summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--PermissionController/res/drawable/ic_shield_exclamation_outline_24dp.xml28
-rw-r--r--PermissionController/res/layout-v35/app_permission_footer_link_preference.xml34
-rw-r--r--PermissionController/res/layout-v35/permission_preference_selector_with_widget.xml69
-rw-r--r--PermissionController/res/layout-v35/permission_preference_two_target.xml60
-rw-r--r--PermissionController/res/layout-v35/permission_preference_widget_radiobutton.xml24
-rw-r--r--PermissionController/res/values-af-v35/strings.xml20
-rw-r--r--PermissionController/res/values-am-v35/strings.xml20
-rw-r--r--PermissionController/res/values-ar-v35/strings.xml20
-rw-r--r--PermissionController/res/values-as-v35/strings.xml20
-rw-r--r--PermissionController/res/values-az-v35/strings.xml20
-rw-r--r--PermissionController/res/values-b+sr+Latn-v35/strings.xml20
-rw-r--r--PermissionController/res/values-be-v35/strings.xml20
-rw-r--r--PermissionController/res/values-bg-v35/strings.xml20
-rw-r--r--PermissionController/res/values-bn-v35/strings.xml20
-rw-r--r--PermissionController/res/values-bs-v35/strings.xml20
-rw-r--r--PermissionController/res/values-ca-v35/strings.xml20
-rw-r--r--PermissionController/res/values-cs-v35/strings.xml20
-rw-r--r--PermissionController/res/values-da-v35/strings.xml20
-rw-r--r--PermissionController/res/values-de-v35/strings.xml20
-rw-r--r--PermissionController/res/values-el-v35/strings.xml20
-rw-r--r--PermissionController/res/values-en-rAU-v35/strings.xml20
-rw-r--r--PermissionController/res/values-en-rGB-v35/strings.xml20
-rw-r--r--PermissionController/res/values-en-rIN-v35/strings.xml20
-rw-r--r--PermissionController/res/values-es-rUS-v35/strings.xml20
-rw-r--r--PermissionController/res/values-es-v35/strings.xml20
-rw-r--r--PermissionController/res/values-es/strings.xml2
-rw-r--r--PermissionController/res/values-et-v35/strings.xml20
-rw-r--r--PermissionController/res/values-eu-v35/strings.xml20
-rw-r--r--PermissionController/res/values-eu/strings.xml2
-rw-r--r--PermissionController/res/values-fa-v35/strings.xml20
-rw-r--r--PermissionController/res/values-fa/strings.xml4
-rw-r--r--PermissionController/res/values-fi-v35/strings.xml20
-rw-r--r--PermissionController/res/values-fr-rCA-v35/strings.xml20
-rw-r--r--PermissionController/res/values-fr-v35/strings.xml20
-rw-r--r--PermissionController/res/values-gl-v35/strings.xml20
-rw-r--r--PermissionController/res/values-gu-v35/strings.xml20
-rw-r--r--PermissionController/res/values-hi-v35/strings.xml20
-rw-r--r--PermissionController/res/values-hr-v35/strings.xml20
-rw-r--r--PermissionController/res/values-hu-v35/strings.xml20
-rw-r--r--PermissionController/res/values-hy-v35/strings.xml20
-rw-r--r--PermissionController/res/values-in-v35/strings.xml20
-rw-r--r--PermissionController/res/values-is-v35/strings.xml20
-rw-r--r--PermissionController/res/values-it-v35/strings.xml20
-rw-r--r--PermissionController/res/values-iw-v35/strings.xml20
-rw-r--r--PermissionController/res/values-ja-v35/strings.xml20
-rw-r--r--PermissionController/res/values-ka-v35/strings.xml20
-rw-r--r--PermissionController/res/values-kk-v35/strings.xml20
-rw-r--r--PermissionController/res/values-km-v35/strings.xml20
-rw-r--r--PermissionController/res/values-kn-v35/strings.xml20
-rw-r--r--PermissionController/res/values-ko-v35/strings.xml20
-rw-r--r--PermissionController/res/values-ky-v35/strings.xml20
-rw-r--r--PermissionController/res/values-lo-v35/strings.xml20
-rw-r--r--PermissionController/res/values-lt-v35/strings.xml20
-rw-r--r--PermissionController/res/values-lv-v35/strings.xml20
-rw-r--r--PermissionController/res/values-mk-v35/strings.xml20
-rw-r--r--PermissionController/res/values-ml-v35/strings.xml20
-rw-r--r--PermissionController/res/values-mn-v35/strings.xml20
-rw-r--r--PermissionController/res/values-mr-v35/strings.xml20
-rw-r--r--PermissionController/res/values-mr/strings.xml2
-rw-r--r--PermissionController/res/values-ms-v35/strings.xml20
-rw-r--r--PermissionController/res/values-my-v35/strings.xml20
-rw-r--r--PermissionController/res/values-nb-v35/strings.xml20
-rw-r--r--PermissionController/res/values-ne-v35/strings.xml20
-rw-r--r--PermissionController/res/values-nl-v35/strings.xml20
-rw-r--r--PermissionController/res/values-or-v35/strings.xml20
-rw-r--r--PermissionController/res/values-pa-v35/strings.xml20
-rw-r--r--PermissionController/res/values-pl-v35/strings.xml20
-rw-r--r--PermissionController/res/values-pt-rBR-v35/strings.xml20
-rw-r--r--PermissionController/res/values-pt-rPT-v35/strings.xml20
-rw-r--r--PermissionController/res/values-pt-v35/strings.xml20
-rw-r--r--PermissionController/res/values-ro-v35/strings.xml20
-rw-r--r--PermissionController/res/values-ru-v35/strings.xml20
-rw-r--r--PermissionController/res/values-si-v35/strings.xml20
-rw-r--r--PermissionController/res/values-sk-v35/strings.xml20
-rw-r--r--PermissionController/res/values-sl-v35/strings.xml20
-rw-r--r--PermissionController/res/values-sq-v35/strings.xml20
-rw-r--r--PermissionController/res/values-sr-v35/strings.xml20
-rw-r--r--PermissionController/res/values-sv-v35/strings.xml20
-rw-r--r--PermissionController/res/values-sw-v35/strings.xml20
-rw-r--r--PermissionController/res/values-ta-v35/strings.xml20
-rw-r--r--PermissionController/res/values-te-v35/strings.xml20
-rw-r--r--PermissionController/res/values-th-v35/strings.xml20
-rw-r--r--PermissionController/res/values-tl-v35/strings.xml20
-rw-r--r--PermissionController/res/values-tr-v35/strings.xml20
-rw-r--r--PermissionController/res/values-uk-v35/strings.xml20
-rw-r--r--PermissionController/res/values-ur-v35/strings.xml20
-rw-r--r--PermissionController/res/values-uz-v35/strings.xml20
-rw-r--r--PermissionController/res/values-v35/styles.xml216
-rw-r--r--PermissionController/res/values-vi-v35/strings.xml20
-rw-r--r--PermissionController/res/values-zh-rCN-v35/strings.xml20
-rw-r--r--PermissionController/res/values-zh-rHK-v35/strings.xml20
-rw-r--r--PermissionController/res/values-zh-rTW-v35/strings.xml20
-rw-r--r--PermissionController/res/values-zu-v35/strings.xml20
-rw-r--r--PermissionController/res/values/attrs.xml5
-rw-r--r--PermissionController/res/values/bools.xml1
-rw-r--r--PermissionController/res/values/overlayable.xml29
-rw-r--r--PermissionController/res/xml-v35/app_permission.xml102
-rw-r--r--PermissionController/role-controller/java/com/android/role/controller/behavior/v34/NotesRoleBehavior.java7
-rw-r--r--PermissionController/src/com/android/permissioncontroller/hibernation/HibernationPolicy.kt31
-rw-r--r--PermissionController/src/com/android/permissioncontroller/hibernation/TEST_MAPPING10
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/compat/AppPermissionFragmentCompat.java8
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/domain/usecase/v31/GetPermissionGroupUsageDetailsUseCase.kt88
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/ui/auto/dashboard/AutoPermissionHistoryPreference.kt16
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/ui/auto/dashboard/AutoPermissionUsageDetailsFragment.kt127
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/ui/auto/dashboard/AutoPermissionUsageFragment.kt12
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/ui/handheld/AppPermissionWrapperFragment.java2
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/ui/handheld/PermissionFooterPreference.kt9
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/ui/handheld/PermissionPreference.kt19
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/ui/handheld/PermissionPreferenceCategory.kt19
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/ui/handheld/max35/LegacyAppPermissionFragment.java1
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/ui/handheld/v31/PermissionHistoryPreference.java1
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/ui/handheld/v35/SectionPreferenceGroupAdapter.kt6
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/ui/handheld/v36/AppPermissionFooterLinkPreference.kt50
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/ui/handheld/v36/AppPermissionFragment.java365
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/ui/handheld/v36/PermissionSelectorWithWidgetPreference.kt103
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/ui/handheld/v36/PermissionTwoTargetPreference.kt105
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/ui/legacy/PermissionUsageDetailsViewModelLegacy.kt596
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/ui/wear/elements/AnnotatedText.kt57
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/ui/wear/elements/ScrollableScreen.kt1
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/utils/ResourceUtils.kt26
-rw-r--r--PermissionController/tests/mocking/src/com/android/permissioncontroller/tests/mocking/hibernation/HibernationPolicyTest.kt60
-rw-r--r--PermissionController/tests/mocking/src/com/android/permissioncontroller/tests/mocking/permission/domain/usecase/GetPermissionGroupUsageDetailsUseCaseTest.kt206
-rw-r--r--SafetyCenter/Resources/res/values-ar/strings.xml2
-rw-r--r--flags/Android.bp1
-rw-r--r--flags/flags.aconfig9
-rw-r--r--tests/apex/Android.bp1
-rw-r--r--tests/apex/java/com/android/role/RoleUserStateTest.kt94
-rw-r--r--tests/cts/permissionmultidevice/src/android/permissionmultidevice/cts/AppPermissionsTest.kt5
-rw-r--r--tests/cts/permissionui/src/android/permissionui/cts/AppPermissionTest.kt5
-rw-r--r--tests/cts/permissionui/src/android/permissionui/cts/BaseUsePermissionTest.kt13
-rw-r--r--tests/cts/permissionui/src/android/permissionui/cts/PermissionReviewTapjackingTest.kt2
-rw-r--r--tests/cts/role/Android.bp2
-rw-r--r--tests/cts/role/AndroidTest.xml2
-rw-r--r--tests/cts/role/CtsRoleTestAppClone/Android.bp (renamed from tests/cts/role/CtsRoleTestAppForProfile/Android.bp)2
-rw-r--r--tests/cts/role/CtsRoleTestAppClone/AndroidManifest.xml (renamed from tests/cts/role/CtsRoleTestAppForProfile/AndroidManifest.xml)4
-rw-r--r--tests/cts/role/src/android/app/role/cts/RoleManagerTest.java52
-rw-r--r--tests/cts/role/src/android/app/role/cts/RoleShellCommandTest.kt36
-rw-r--r--tests/functional/safetycenter/multiusers/src/android/safetycenter/functional/multiusers/SafetyCenterMultiUsersTest.kt8
138 files changed, 3286 insertions, 1115 deletions
diff --git a/PermissionController/res/drawable/ic_shield_exclamation_outline_24dp.xml b/PermissionController/res/drawable/ic_shield_exclamation_outline_24dp.xml
new file mode 100644
index 000000000..6bbf7a174
--- /dev/null
+++ b/PermissionController/res/drawable/ic_shield_exclamation_outline_24dp.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2024 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT 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="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/layout-v35/app_permission_footer_link_preference.xml b/PermissionController/res/layout-v35/app_permission_footer_link_preference.xml
new file mode 100644
index 000000000..75381e762
--- /dev/null
+++ b/PermissionController/res/layout-v35/app_permission_footer_link_preference.xml
@@ -0,0 +1,34 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2024 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT 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 copy of PermissionPreference, with custom styles for some elements
+ -->
+<com.android.permissioncontroller.permission.ui.handheld.v35.DrawableStateLinearLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ style="@style/AppPermissionFooterLinkPreferenceRootLayoutStyle">
+
+ <RelativeLayout
+ style="@style/AppPermissionFooterLinkPreferenceTextLayoutStyle">
+
+ <TextView
+ android:id="@android:id/summary"
+ style="@style/AppPermissionFooterLinkPreferenceSummaryStyle"/>
+
+ </RelativeLayout>
+
+</com.android.permissioncontroller.permission.ui.handheld.v35.DrawableStateLinearLayout>
diff --git a/PermissionController/res/layout-v35/permission_preference_selector_with_widget.xml b/PermissionController/res/layout-v35/permission_preference_selector_with_widget.xml
new file mode 100644
index 000000000..230e51fc3
--- /dev/null
+++ b/PermissionController/res/layout-v35/permission_preference_selector_with_widget.xml
@@ -0,0 +1,69 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2024 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT 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 direct copy of the following layout, but with overlayable styles:
+ ~ SettingsLib/SelectorWithWidgetPreference/res/layout-v33/preference_selector_with_widget.xml
+ -->
+<com.android.permissioncontroller.permission.ui.handheld.v35.DrawableStateLinearLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ style="@style/PermissionSelectorWithWidgetPreferenceRootLayoutStyle">
+
+ <LinearLayout
+ android:id="@android:id/widget_frame"
+ style="@style/PermissionSelectorWithWidgetPreferenceWidgetFrameStyle" />
+
+ <LinearLayout
+ android:id="@+id/icon_frame"
+ style="@style/PermissionSelectorWithWidgetPreferenceIconFrameStyle">
+
+ <androidx.preference.internal.PreferenceImageView
+ android:id="@android:id/icon"
+ style="@style/PermissionSelectorWithWidgetPreferenceIconStyle" />
+ </LinearLayout>
+
+ <LinearLayout style="@style/PermissionSelectorWithWidgetPreferenceTextContainerStyle">
+
+ <TextView
+ android:id="@android:id/title"
+ style="@style/PermissionSelectorWithWidgetPreferenceTitleStyle" />
+
+ <LinearLayout
+ android:id="@+id/summary_container"
+ style="@style/PermissionSelectorWithWidgetPreferenceSummaryContainerStyle">
+
+ <TextView
+ android:id="@android:id/summary"
+ style="@style/PermissionSelectorWithWidgetPreferenceSummaryStyle" />
+
+ <TextView
+ android:id="@+id/appendix"
+ style="@style/PermissionSelectorWithWidgetPreferenceAppendixStyle" />
+ </LinearLayout>
+ </LinearLayout>
+
+ <LinearLayout
+ android:id="@+id/selector_extra_widget_container"
+ style="@style/PermissionSelectorWithWidgetPreferenceExtraWidgetContainerStyle">
+
+ <View style="@style/PermissionSelectorWithWidgetPreferenceExtraWidgetDividerStyle" />
+
+ <ImageView
+ android:id="@+id/selector_extra_widget"
+ android:contentDescription="@string/settings_label"
+ style="@style/PermissionSelectorWithWidgetPreferenceExtraWidgetImageStyle" />
+ </LinearLayout>
+</com.android.permissioncontroller.permission.ui.handheld.v35.DrawableStateLinearLayout>
diff --git a/PermissionController/res/layout-v35/permission_preference_two_target.xml b/PermissionController/res/layout-v35/permission_preference_two_target.xml
new file mode 100644
index 000000000..906393b3c
--- /dev/null
+++ b/PermissionController/res/layout-v35/permission_preference_two_target.xml
@@ -0,0 +1,60 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2024 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT 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 direct copy of the following layout, but with overlayable styles:
+ ~ SettingsLib/TwoTargetPreference/res/layout-v33/preference_two_target.xml
+ -->
+
+<!-- Based off preference_material_settings.xml except that ripple on only on the left side. -->
+<com.android.permissioncontroller.permission.ui.handheld.v35.DrawableStateLinearLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ style="@style/PermissionTwoTargetPreferenceRootLayoutStyle">
+
+ <LinearLayout
+ android:id="@+id/icon_frame"
+ style="@style/PermissionTwoTargetPreferenceIconFrameStyle">
+
+ <androidx.preference.internal.PreferenceImageView
+ android:id="@android:id/icon"
+ style="@style/PermissionTwoTargetPreferenceIconStyle"/>
+
+ </LinearLayout>
+
+ <RelativeLayout style="@style/PermissionTwoTargetPreferenceTextContainerStyle">
+
+ <TextView
+ android:id="@android:id/title"
+ style="@style/PermissionTwoTargetPreferenceTitleStyle"/>
+
+ <TextView
+ android:id="@android:id/summary"
+ style="@style/PermissionTwoTargetPreferenceSummaryStyle"/>
+
+ </RelativeLayout>
+
+ <LinearLayout
+ android:id="@+id/two_target_divider"
+ style="@style/PermissionTwoTargetPreferenceDividerContainerStyle">
+ <View style="@style/PermissionTwoTargetPreferenceDividerStyle" />
+ </LinearLayout>
+
+ <!-- Preference should place its actual preference widget here. -->
+ <LinearLayout
+ android:id="@android:id/widget_frame"
+ style="@style/PermissionTwoTargetPreferenceWidgetFrameStyle" />
+
+</com.android.permissioncontroller.permission.ui.handheld.v35.DrawableStateLinearLayout>
diff --git a/PermissionController/res/layout-v35/permission_preference_widget_radiobutton.xml b/PermissionController/res/layout-v35/permission_preference_widget_radiobutton.xml
new file mode 100644
index 000000000..10e311110
--- /dev/null
+++ b/PermissionController/res/layout-v35/permission_preference_widget_radiobutton.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2024 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT 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 direct copy of the following layout, but with overlayable styles:
+ ~ SettingsLib/SelectorWithWidgetPreference/res/layout/preference_widget_radiobutton.xml
+ -->
+<RadioButton
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@android:id/checkbox"
+ style="@style/PermissionSelectorWithWidgetPreferenceWidgetRadioButton" />
diff --git a/PermissionController/res/values-af-v35/strings.xml b/PermissionController/res/values-af-v35/strings.xml
new file mode 100644
index 000000000..ae1626d6d
--- /dev/null
+++ b/PermissionController/res/values-af-v35/strings.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2024 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="safety_center_entries_category_title" msgid="4413287601344137909">"Sekuriteit"</string>
+</resources>
diff --git a/PermissionController/res/values-am-v35/strings.xml b/PermissionController/res/values-am-v35/strings.xml
new file mode 100644
index 000000000..3d2bdc7e9
--- /dev/null
+++ b/PermissionController/res/values-am-v35/strings.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2024 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="safety_center_entries_category_title" msgid="4413287601344137909">"ደህንነት"</string>
+</resources>
diff --git a/PermissionController/res/values-ar-v35/strings.xml b/PermissionController/res/values-ar-v35/strings.xml
new file mode 100644
index 000000000..6042920c0
--- /dev/null
+++ b/PermissionController/res/values-ar-v35/strings.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2024 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="safety_center_entries_category_title" msgid="4413287601344137909">"الأمان"</string>
+</resources>
diff --git a/PermissionController/res/values-as-v35/strings.xml b/PermissionController/res/values-as-v35/strings.xml
new file mode 100644
index 000000000..37ac47117
--- /dev/null
+++ b/PermissionController/res/values-as-v35/strings.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2024 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="safety_center_entries_category_title" msgid="4413287601344137909">"সুৰক্ষা"</string>
+</resources>
diff --git a/PermissionController/res/values-az-v35/strings.xml b/PermissionController/res/values-az-v35/strings.xml
new file mode 100644
index 000000000..7ffd58cc1
--- /dev/null
+++ b/PermissionController/res/values-az-v35/strings.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2024 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="safety_center_entries_category_title" msgid="4413287601344137909">"Güvənlik"</string>
+</resources>
diff --git a/PermissionController/res/values-b+sr+Latn-v35/strings.xml b/PermissionController/res/values-b+sr+Latn-v35/strings.xml
new file mode 100644
index 000000000..9ad2d24c7
--- /dev/null
+++ b/PermissionController/res/values-b+sr+Latn-v35/strings.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2024 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="safety_center_entries_category_title" msgid="4413287601344137909">"Bezbednost"</string>
+</resources>
diff --git a/PermissionController/res/values-be-v35/strings.xml b/PermissionController/res/values-be-v35/strings.xml
new file mode 100644
index 000000000..39f076e77
--- /dev/null
+++ b/PermissionController/res/values-be-v35/strings.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2024 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="safety_center_entries_category_title" msgid="4413287601344137909">"Бяспека"</string>
+</resources>
diff --git a/PermissionController/res/values-bg-v35/strings.xml b/PermissionController/res/values-bg-v35/strings.xml
new file mode 100644
index 000000000..72f4a8562
--- /dev/null
+++ b/PermissionController/res/values-bg-v35/strings.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2024 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="safety_center_entries_category_title" msgid="4413287601344137909">"Сигурност"</string>
+</resources>
diff --git a/PermissionController/res/values-bn-v35/strings.xml b/PermissionController/res/values-bn-v35/strings.xml
new file mode 100644
index 000000000..066c4ad5a
--- /dev/null
+++ b/PermissionController/res/values-bn-v35/strings.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2024 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="safety_center_entries_category_title" msgid="4413287601344137909">"সুরক্ষা"</string>
+</resources>
diff --git a/PermissionController/res/values-bs-v35/strings.xml b/PermissionController/res/values-bs-v35/strings.xml
new file mode 100644
index 000000000..71b83b6c9
--- /dev/null
+++ b/PermissionController/res/values-bs-v35/strings.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2024 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="safety_center_entries_category_title" msgid="4413287601344137909">"Sigurnost"</string>
+</resources>
diff --git a/PermissionController/res/values-ca-v35/strings.xml b/PermissionController/res/values-ca-v35/strings.xml
new file mode 100644
index 000000000..10bff4b9c
--- /dev/null
+++ b/PermissionController/res/values-ca-v35/strings.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2024 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="safety_center_entries_category_title" msgid="4413287601344137909">"Seguretat"</string>
+</resources>
diff --git a/PermissionController/res/values-cs-v35/strings.xml b/PermissionController/res/values-cs-v35/strings.xml
new file mode 100644
index 000000000..95aa40cc4
--- /dev/null
+++ b/PermissionController/res/values-cs-v35/strings.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2024 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="safety_center_entries_category_title" msgid="4413287601344137909">"Zabezpečení"</string>
+</resources>
diff --git a/PermissionController/res/values-da-v35/strings.xml b/PermissionController/res/values-da-v35/strings.xml
new file mode 100644
index 000000000..911941e5b
--- /dev/null
+++ b/PermissionController/res/values-da-v35/strings.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2024 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="safety_center_entries_category_title" msgid="4413287601344137909">"Sikkerhed"</string>
+</resources>
diff --git a/PermissionController/res/values-de-v35/strings.xml b/PermissionController/res/values-de-v35/strings.xml
new file mode 100644
index 000000000..7f04a8b8c
--- /dev/null
+++ b/PermissionController/res/values-de-v35/strings.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2024 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="safety_center_entries_category_title" msgid="4413287601344137909">"Sicherheit"</string>
+</resources>
diff --git a/PermissionController/res/values-el-v35/strings.xml b/PermissionController/res/values-el-v35/strings.xml
new file mode 100644
index 000000000..fa7c62da3
--- /dev/null
+++ b/PermissionController/res/values-el-v35/strings.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2024 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="safety_center_entries_category_title" msgid="4413287601344137909">"Ασφάλεια"</string>
+</resources>
diff --git a/PermissionController/res/values-en-rAU-v35/strings.xml b/PermissionController/res/values-en-rAU-v35/strings.xml
new file mode 100644
index 000000000..c4b7df49d
--- /dev/null
+++ b/PermissionController/res/values-en-rAU-v35/strings.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2024 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="safety_center_entries_category_title" msgid="4413287601344137909">"Security"</string>
+</resources>
diff --git a/PermissionController/res/values-en-rGB-v35/strings.xml b/PermissionController/res/values-en-rGB-v35/strings.xml
new file mode 100644
index 000000000..c4b7df49d
--- /dev/null
+++ b/PermissionController/res/values-en-rGB-v35/strings.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2024 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="safety_center_entries_category_title" msgid="4413287601344137909">"Security"</string>
+</resources>
diff --git a/PermissionController/res/values-en-rIN-v35/strings.xml b/PermissionController/res/values-en-rIN-v35/strings.xml
new file mode 100644
index 000000000..c4b7df49d
--- /dev/null
+++ b/PermissionController/res/values-en-rIN-v35/strings.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2024 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="safety_center_entries_category_title" msgid="4413287601344137909">"Security"</string>
+</resources>
diff --git a/PermissionController/res/values-es-rUS-v35/strings.xml b/PermissionController/res/values-es-rUS-v35/strings.xml
new file mode 100644
index 000000000..ecd01df78
--- /dev/null
+++ b/PermissionController/res/values-es-rUS-v35/strings.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2024 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="safety_center_entries_category_title" msgid="4413287601344137909">"Seguridad"</string>
+</resources>
diff --git a/PermissionController/res/values-es-v35/strings.xml b/PermissionController/res/values-es-v35/strings.xml
new file mode 100644
index 000000000..ecd01df78
--- /dev/null
+++ b/PermissionController/res/values-es-v35/strings.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2024 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="safety_center_entries_category_title" msgid="4413287601344137909">"Seguridad"</string>
+</resources>
diff --git a/PermissionController/res/values-es/strings.xml b/PermissionController/res/values-es/strings.xml
index e22e3f1e1..402bd5214 100644
--- a/PermissionController/res/values-es/strings.xml
+++ b/PermissionController/res/values-es/strings.xml
@@ -584,7 +584,7 @@
<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="microphone_toggle_label_qs" msgid="8132912469813396552">"Acceso a micro"</string>
<string name="permissions_removed_qs" msgid="8957319130625294572">"Permiso retirado"</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>
diff --git a/PermissionController/res/values-et-v35/strings.xml b/PermissionController/res/values-et-v35/strings.xml
new file mode 100644
index 000000000..3723766d0
--- /dev/null
+++ b/PermissionController/res/values-et-v35/strings.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2024 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="safety_center_entries_category_title" msgid="4413287601344137909">"Turvalisus"</string>
+</resources>
diff --git a/PermissionController/res/values-eu-v35/strings.xml b/PermissionController/res/values-eu-v35/strings.xml
new file mode 100644
index 000000000..63e64934c
--- /dev/null
+++ b/PermissionController/res/values-eu-v35/strings.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2024 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="safety_center_entries_category_title" msgid="4413287601344137909">"Segurtasuna"</string>
+</resources>
diff --git a/PermissionController/res/values-eu/strings.xml b/PermissionController/res/values-eu/strings.xml
index a718def46..8160770ea 100644
--- a/PermissionController/res/values-eu/strings.xml
+++ b/PermissionController/res/values-eu/strings.xml
@@ -250,7 +250,7 @@
<string name="app_permission_most_recent_denied_summary" msgid="7659497197737708112">"Une honetan ukatuta / Azken sarbide-data: <xliff:g id="TIME_DATE">%1$s</xliff:g>"</string>
<string name="app_permission_never_accessed_summary" msgid="401346181461975090">"Ez da erabili inoiz"</string>
<string name="app_permission_never_accessed_denied_summary" msgid="6596000497490905146">"Ukatuta / Ez da erabili inoiz"</string>
- <string name="allowed_header" msgid="7769277978004790414">"Baimenduta"</string>
+ <string name="allowed_header" msgid="7769277978004790414">"Baimendutakoak"</string>
<string name="allowed_always_header" msgid="6455903312589013545">"Beti baimendutakoak"</string>
<string name="allowed_foreground_header" msgid="6845655788447833353">"Erabili bitartean soilik baimendutakoak"</string>
<string name="allowed_storage_scoped" msgid="5383645873719086975">"Multimedia-fitx. soilik erabiltzeko baimena dutenak"</string>
diff --git a/PermissionController/res/values-fa-v35/strings.xml b/PermissionController/res/values-fa-v35/strings.xml
new file mode 100644
index 000000000..5bc65a09d
--- /dev/null
+++ b/PermissionController/res/values-fa-v35/strings.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2024 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="safety_center_entries_category_title" msgid="4413287601344137909">"امنیت"</string>
+</resources>
diff --git a/PermissionController/res/values-fa/strings.xml b/PermissionController/res/values-fa/strings.xml
index 607745eeb..4ed186f3e 100644
--- a/PermissionController/res/values-fa/strings.xml
+++ b/PermissionController/res/values-fa/strings.xml
@@ -250,7 +250,7 @@
<string name="app_permission_most_recent_denied_summary" msgid="7659497197737708112">"درحال‌حاضر رد شده است / آخرین دسترسی: <xliff:g id="TIME_DATE">%1$s</xliff:g>"</string>
<string name="app_permission_never_accessed_summary" msgid="401346181461975090">"هرگز دسترسی نداشته است"</string>
<string name="app_permission_never_accessed_denied_summary" msgid="6596000497490905146">"غیرمجاز / هرگز دسترسی نداشته است"</string>
- <string name="allowed_header" msgid="7769277978004790414">"مجاز است"</string>
+ <string name="allowed_header" msgid="7769277978004790414">"مجاز بودن"</string>
<string name="allowed_always_header" msgid="6455903312589013545">"همیشه مجاز بودن"</string>
<string name="allowed_foreground_header" msgid="6845655788447833353">"مجاز فقط هنگام استفاده"</string>
<string name="allowed_storage_scoped" msgid="5383645873719086975">"مجاز فقط برای دسترسی به رسانه‌ها"</string>
@@ -346,7 +346,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>
diff --git a/PermissionController/res/values-fi-v35/strings.xml b/PermissionController/res/values-fi-v35/strings.xml
new file mode 100644
index 000000000..a1c8d62d4
--- /dev/null
+++ b/PermissionController/res/values-fi-v35/strings.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2024 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="safety_center_entries_category_title" msgid="4413287601344137909">"Suojaus"</string>
+</resources>
diff --git a/PermissionController/res/values-fr-rCA-v35/strings.xml b/PermissionController/res/values-fr-rCA-v35/strings.xml
new file mode 100644
index 000000000..9a88205ed
--- /dev/null
+++ b/PermissionController/res/values-fr-rCA-v35/strings.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2024 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="safety_center_entries_category_title" msgid="4413287601344137909">"Sécurité"</string>
+</resources>
diff --git a/PermissionController/res/values-fr-v35/strings.xml b/PermissionController/res/values-fr-v35/strings.xml
new file mode 100644
index 000000000..9a88205ed
--- /dev/null
+++ b/PermissionController/res/values-fr-v35/strings.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2024 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="safety_center_entries_category_title" msgid="4413287601344137909">"Sécurité"</string>
+</resources>
diff --git a/PermissionController/res/values-gl-v35/strings.xml b/PermissionController/res/values-gl-v35/strings.xml
new file mode 100644
index 000000000..54a03138f
--- /dev/null
+++ b/PermissionController/res/values-gl-v35/strings.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2024 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="safety_center_entries_category_title" msgid="4413287601344137909">"Seguranza"</string>
+</resources>
diff --git a/PermissionController/res/values-gu-v35/strings.xml b/PermissionController/res/values-gu-v35/strings.xml
new file mode 100644
index 000000000..60eb21111
--- /dev/null
+++ b/PermissionController/res/values-gu-v35/strings.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2024 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="safety_center_entries_category_title" msgid="4413287601344137909">"સુરક્ષા"</string>
+</resources>
diff --git a/PermissionController/res/values-hi-v35/strings.xml b/PermissionController/res/values-hi-v35/strings.xml
new file mode 100644
index 000000000..3d8a7dedf
--- /dev/null
+++ b/PermissionController/res/values-hi-v35/strings.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2024 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="safety_center_entries_category_title" msgid="4413287601344137909">"सुरक्षा"</string>
+</resources>
diff --git a/PermissionController/res/values-hr-v35/strings.xml b/PermissionController/res/values-hr-v35/strings.xml
new file mode 100644
index 000000000..71b83b6c9
--- /dev/null
+++ b/PermissionController/res/values-hr-v35/strings.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2024 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="safety_center_entries_category_title" msgid="4413287601344137909">"Sigurnost"</string>
+</resources>
diff --git a/PermissionController/res/values-hu-v35/strings.xml b/PermissionController/res/values-hu-v35/strings.xml
new file mode 100644
index 000000000..b0ef5cfc4
--- /dev/null
+++ b/PermissionController/res/values-hu-v35/strings.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2024 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="safety_center_entries_category_title" msgid="4413287601344137909">"Biztonság"</string>
+</resources>
diff --git a/PermissionController/res/values-hy-v35/strings.xml b/PermissionController/res/values-hy-v35/strings.xml
new file mode 100644
index 000000000..3cbb6bd04
--- /dev/null
+++ b/PermissionController/res/values-hy-v35/strings.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2024 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="safety_center_entries_category_title" msgid="4413287601344137909">"Անվտանգություն"</string>
+</resources>
diff --git a/PermissionController/res/values-in-v35/strings.xml b/PermissionController/res/values-in-v35/strings.xml
new file mode 100644
index 000000000..18a74e175
--- /dev/null
+++ b/PermissionController/res/values-in-v35/strings.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2024 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="safety_center_entries_category_title" msgid="4413287601344137909">"Keamanan"</string>
+</resources>
diff --git a/PermissionController/res/values-is-v35/strings.xml b/PermissionController/res/values-is-v35/strings.xml
new file mode 100644
index 000000000..4463df957
--- /dev/null
+++ b/PermissionController/res/values-is-v35/strings.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2024 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="safety_center_entries_category_title" msgid="4413287601344137909">"Öryggi"</string>
+</resources>
diff --git a/PermissionController/res/values-it-v35/strings.xml b/PermissionController/res/values-it-v35/strings.xml
new file mode 100644
index 000000000..61a64698f
--- /dev/null
+++ b/PermissionController/res/values-it-v35/strings.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2024 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="safety_center_entries_category_title" msgid="4413287601344137909">"Sicurezza"</string>
+</resources>
diff --git a/PermissionController/res/values-iw-v35/strings.xml b/PermissionController/res/values-iw-v35/strings.xml
new file mode 100644
index 000000000..b9ebf0891
--- /dev/null
+++ b/PermissionController/res/values-iw-v35/strings.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2024 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="safety_center_entries_category_title" msgid="4413287601344137909">"אבטחה"</string>
+</resources>
diff --git a/PermissionController/res/values-ja-v35/strings.xml b/PermissionController/res/values-ja-v35/strings.xml
new file mode 100644
index 000000000..301dec443
--- /dev/null
+++ b/PermissionController/res/values-ja-v35/strings.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2024 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="safety_center_entries_category_title" msgid="4413287601344137909">"セキュリティ"</string>
+</resources>
diff --git a/PermissionController/res/values-ka-v35/strings.xml b/PermissionController/res/values-ka-v35/strings.xml
new file mode 100644
index 000000000..fb932751b
--- /dev/null
+++ b/PermissionController/res/values-ka-v35/strings.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2024 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="safety_center_entries_category_title" msgid="4413287601344137909">"უსაფრთხოება"</string>
+</resources>
diff --git a/PermissionController/res/values-kk-v35/strings.xml b/PermissionController/res/values-kk-v35/strings.xml
new file mode 100644
index 000000000..6c5e61d14
--- /dev/null
+++ b/PermissionController/res/values-kk-v35/strings.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2024 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="safety_center_entries_category_title" msgid="4413287601344137909">"Қауіпсіздік"</string>
+</resources>
diff --git a/PermissionController/res/values-km-v35/strings.xml b/PermissionController/res/values-km-v35/strings.xml
new file mode 100644
index 000000000..e461c54d5
--- /dev/null
+++ b/PermissionController/res/values-km-v35/strings.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2024 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="safety_center_entries_category_title" msgid="4413287601344137909">"សន្តិសុខ"</string>
+</resources>
diff --git a/PermissionController/res/values-kn-v35/strings.xml b/PermissionController/res/values-kn-v35/strings.xml
new file mode 100644
index 000000000..7205ee7fe
--- /dev/null
+++ b/PermissionController/res/values-kn-v35/strings.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2024 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="safety_center_entries_category_title" msgid="4413287601344137909">"ಭದ್ರತೆ"</string>
+</resources>
diff --git a/PermissionController/res/values-ko-v35/strings.xml b/PermissionController/res/values-ko-v35/strings.xml
new file mode 100644
index 000000000..99de87a25
--- /dev/null
+++ b/PermissionController/res/values-ko-v35/strings.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2024 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="safety_center_entries_category_title" msgid="4413287601344137909">"보안"</string>
+</resources>
diff --git a/PermissionController/res/values-ky-v35/strings.xml b/PermissionController/res/values-ky-v35/strings.xml
new file mode 100644
index 000000000..844abd6f0
--- /dev/null
+++ b/PermissionController/res/values-ky-v35/strings.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2024 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="safety_center_entries_category_title" msgid="4413287601344137909">"Коопсуздук"</string>
+</resources>
diff --git a/PermissionController/res/values-lo-v35/strings.xml b/PermissionController/res/values-lo-v35/strings.xml
new file mode 100644
index 000000000..08a6e9920
--- /dev/null
+++ b/PermissionController/res/values-lo-v35/strings.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2024 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="safety_center_entries_category_title" msgid="4413287601344137909">"ຄວາມປອດໄພ"</string>
+</resources>
diff --git a/PermissionController/res/values-lt-v35/strings.xml b/PermissionController/res/values-lt-v35/strings.xml
new file mode 100644
index 000000000..b53fe3513
--- /dev/null
+++ b/PermissionController/res/values-lt-v35/strings.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2024 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="safety_center_entries_category_title" msgid="4413287601344137909">"Sauga"</string>
+</resources>
diff --git a/PermissionController/res/values-lv-v35/strings.xml b/PermissionController/res/values-lv-v35/strings.xml
new file mode 100644
index 000000000..98ae9a138
--- /dev/null
+++ b/PermissionController/res/values-lv-v35/strings.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2024 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="safety_center_entries_category_title" msgid="4413287601344137909">"Drošība"</string>
+</resources>
diff --git a/PermissionController/res/values-mk-v35/strings.xml b/PermissionController/res/values-mk-v35/strings.xml
new file mode 100644
index 000000000..3690e7e0e
--- /dev/null
+++ b/PermissionController/res/values-mk-v35/strings.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2024 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="safety_center_entries_category_title" msgid="4413287601344137909">"Безбедност"</string>
+</resources>
diff --git a/PermissionController/res/values-ml-v35/strings.xml b/PermissionController/res/values-ml-v35/strings.xml
new file mode 100644
index 000000000..7d3552e5f
--- /dev/null
+++ b/PermissionController/res/values-ml-v35/strings.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2024 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="safety_center_entries_category_title" msgid="4413287601344137909">"സുരക്ഷ"</string>
+</resources>
diff --git a/PermissionController/res/values-mn-v35/strings.xml b/PermissionController/res/values-mn-v35/strings.xml
new file mode 100644
index 000000000..cb9e18162
--- /dev/null
+++ b/PermissionController/res/values-mn-v35/strings.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2024 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="safety_center_entries_category_title" msgid="4413287601344137909">"Аюулгүй байдал"</string>
+</resources>
diff --git a/PermissionController/res/values-mr-v35/strings.xml b/PermissionController/res/values-mr-v35/strings.xml
new file mode 100644
index 000000000..3d8a7dedf
--- /dev/null
+++ b/PermissionController/res/values-mr-v35/strings.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2024 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="safety_center_entries_category_title" msgid="4413287601344137909">"सुरक्षा"</string>
+</resources>
diff --git a/PermissionController/res/values-mr/strings.xml b/PermissionController/res/values-mr/strings.xml
index 53de5e31c..72f121d1c 100644
--- a/PermissionController/res/values-mr/strings.xml
+++ b/PermissionController/res/values-mr/strings.xml
@@ -87,7 +87,7 @@
<string name="app_permissions_group_summary" msgid="8788419008958284002">"<xliff:g id="COUNT_1">%2$d</xliff:g> पैकी <xliff:g id="COUNT_0">%1$d</xliff:g> अ‍ॅप्सना परवानगी दिली"</string>
<string name="app_permissions_group_summary2" msgid="4329922444840521150">"<xliff:g id="COUNT_0">%1$d</xliff:g>/<xliff:g id="COUNT_1">%2$d</xliff:g> अ‍ॅप्सना अनुमती आहे"</string>
<string name="menu_show_system" msgid="4254021607027872504">"सिस्टीम दाखवा"</string>
- <string name="menu_hide_system" msgid="3855390843744028465">"सिस्टम लपवा"</string>
+ <string name="menu_hide_system" msgid="3855390843744028465">"सिस्टीम लपवा"</string>
<string name="menu_show_7_days_data" msgid="8979611198508523706">"सात दिवस दाखवा"</string>
<string name="menu_show_24_hours_data" msgid="8228054833323380780">"२४ तास दाखवा"</string>
<string name="manage_permission" msgid="2895385393037061964">"परवानगी व्यवस्थापित करा"</string>
diff --git a/PermissionController/res/values-ms-v35/strings.xml b/PermissionController/res/values-ms-v35/strings.xml
new file mode 100644
index 000000000..f09b6ea0e
--- /dev/null
+++ b/PermissionController/res/values-ms-v35/strings.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2024 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="safety_center_entries_category_title" msgid="4413287601344137909">"Keselamatan"</string>
+</resources>
diff --git a/PermissionController/res/values-my-v35/strings.xml b/PermissionController/res/values-my-v35/strings.xml
new file mode 100644
index 000000000..ef994e0a4
--- /dev/null
+++ b/PermissionController/res/values-my-v35/strings.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2024 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="safety_center_entries_category_title" msgid="4413287601344137909">"လုံခြုံရေး"</string>
+</resources>
diff --git a/PermissionController/res/values-nb-v35/strings.xml b/PermissionController/res/values-nb-v35/strings.xml
new file mode 100644
index 000000000..0e03b1f53
--- /dev/null
+++ b/PermissionController/res/values-nb-v35/strings.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2024 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="safety_center_entries_category_title" msgid="4413287601344137909">"Sikkerhet"</string>
+</resources>
diff --git a/PermissionController/res/values-ne-v35/strings.xml b/PermissionController/res/values-ne-v35/strings.xml
new file mode 100644
index 000000000..3d8a7dedf
--- /dev/null
+++ b/PermissionController/res/values-ne-v35/strings.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2024 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="safety_center_entries_category_title" msgid="4413287601344137909">"सुरक्षा"</string>
+</resources>
diff --git a/PermissionController/res/values-nl-v35/strings.xml b/PermissionController/res/values-nl-v35/strings.xml
new file mode 100644
index 000000000..f38159c4d
--- /dev/null
+++ b/PermissionController/res/values-nl-v35/strings.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2024 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="safety_center_entries_category_title" msgid="4413287601344137909">"Beveiliging"</string>
+</resources>
diff --git a/PermissionController/res/values-or-v35/strings.xml b/PermissionController/res/values-or-v35/strings.xml
new file mode 100644
index 000000000..56dc78f79
--- /dev/null
+++ b/PermissionController/res/values-or-v35/strings.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2024 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="safety_center_entries_category_title" msgid="4413287601344137909">"ସୁରକ୍ଷା"</string>
+</resources>
diff --git a/PermissionController/res/values-pa-v35/strings.xml b/PermissionController/res/values-pa-v35/strings.xml
new file mode 100644
index 000000000..f6cd2ad56
--- /dev/null
+++ b/PermissionController/res/values-pa-v35/strings.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2024 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="safety_center_entries_category_title" msgid="4413287601344137909">"ਸੁਰੱਖਿਆ"</string>
+</resources>
diff --git a/PermissionController/res/values-pl-v35/strings.xml b/PermissionController/res/values-pl-v35/strings.xml
new file mode 100644
index 000000000..441703f88
--- /dev/null
+++ b/PermissionController/res/values-pl-v35/strings.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2024 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="safety_center_entries_category_title" msgid="4413287601344137909">"Bezpieczeństwo"</string>
+</resources>
diff --git a/PermissionController/res/values-pt-rBR-v35/strings.xml b/PermissionController/res/values-pt-rBR-v35/strings.xml
new file mode 100644
index 000000000..96603658a
--- /dev/null
+++ b/PermissionController/res/values-pt-rBR-v35/strings.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2024 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="safety_center_entries_category_title" msgid="4413287601344137909">"Segurança"</string>
+</resources>
diff --git a/PermissionController/res/values-pt-rPT-v35/strings.xml b/PermissionController/res/values-pt-rPT-v35/strings.xml
new file mode 100644
index 000000000..96603658a
--- /dev/null
+++ b/PermissionController/res/values-pt-rPT-v35/strings.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2024 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="safety_center_entries_category_title" msgid="4413287601344137909">"Segurança"</string>
+</resources>
diff --git a/PermissionController/res/values-pt-v35/strings.xml b/PermissionController/res/values-pt-v35/strings.xml
new file mode 100644
index 000000000..96603658a
--- /dev/null
+++ b/PermissionController/res/values-pt-v35/strings.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2024 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="safety_center_entries_category_title" msgid="4413287601344137909">"Segurança"</string>
+</resources>
diff --git a/PermissionController/res/values-ro-v35/strings.xml b/PermissionController/res/values-ro-v35/strings.xml
new file mode 100644
index 000000000..856c75c82
--- /dev/null
+++ b/PermissionController/res/values-ro-v35/strings.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2024 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="safety_center_entries_category_title" msgid="4413287601344137909">"Securitate"</string>
+</resources>
diff --git a/PermissionController/res/values-ru-v35/strings.xml b/PermissionController/res/values-ru-v35/strings.xml
new file mode 100644
index 000000000..c6fa35d68
--- /dev/null
+++ b/PermissionController/res/values-ru-v35/strings.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2024 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="safety_center_entries_category_title" msgid="4413287601344137909">"Безопасность"</string>
+</resources>
diff --git a/PermissionController/res/values-si-v35/strings.xml b/PermissionController/res/values-si-v35/strings.xml
new file mode 100644
index 000000000..dd5c408ae
--- /dev/null
+++ b/PermissionController/res/values-si-v35/strings.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2024 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="safety_center_entries_category_title" msgid="4413287601344137909">"ආරක්ෂාව"</string>
+</resources>
diff --git a/PermissionController/res/values-sk-v35/strings.xml b/PermissionController/res/values-sk-v35/strings.xml
new file mode 100644
index 000000000..6bd3cb05c
--- /dev/null
+++ b/PermissionController/res/values-sk-v35/strings.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2024 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="safety_center_entries_category_title" msgid="4413287601344137909">"Zabezpečenie"</string>
+</resources>
diff --git a/PermissionController/res/values-sl-v35/strings.xml b/PermissionController/res/values-sl-v35/strings.xml
new file mode 100644
index 000000000..e20a0e57b
--- /dev/null
+++ b/PermissionController/res/values-sl-v35/strings.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2024 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="safety_center_entries_category_title" msgid="4413287601344137909">"Varnost"</string>
+</resources>
diff --git a/PermissionController/res/values-sq-v35/strings.xml b/PermissionController/res/values-sq-v35/strings.xml
new file mode 100644
index 000000000..ef8b1c486
--- /dev/null
+++ b/PermissionController/res/values-sq-v35/strings.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2024 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="safety_center_entries_category_title" msgid="4413287601344137909">"Siguria"</string>
+</resources>
diff --git a/PermissionController/res/values-sr-v35/strings.xml b/PermissionController/res/values-sr-v35/strings.xml
new file mode 100644
index 000000000..3690e7e0e
--- /dev/null
+++ b/PermissionController/res/values-sr-v35/strings.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2024 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="safety_center_entries_category_title" msgid="4413287601344137909">"Безбедност"</string>
+</resources>
diff --git a/PermissionController/res/values-sv-v35/strings.xml b/PermissionController/res/values-sv-v35/strings.xml
new file mode 100644
index 000000000..c3d1b1b1c
--- /dev/null
+++ b/PermissionController/res/values-sv-v35/strings.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2024 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="safety_center_entries_category_title" msgid="4413287601344137909">"Säkerhet"</string>
+</resources>
diff --git a/PermissionController/res/values-sw-v35/strings.xml b/PermissionController/res/values-sw-v35/strings.xml
new file mode 100644
index 000000000..6234b97ec
--- /dev/null
+++ b/PermissionController/res/values-sw-v35/strings.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2024 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="safety_center_entries_category_title" msgid="4413287601344137909">"Usalama"</string>
+</resources>
diff --git a/PermissionController/res/values-ta-v35/strings.xml b/PermissionController/res/values-ta-v35/strings.xml
new file mode 100644
index 000000000..6c6adaf80
--- /dev/null
+++ b/PermissionController/res/values-ta-v35/strings.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2024 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="safety_center_entries_category_title" msgid="4413287601344137909">"பாதுகாப்பு"</string>
+</resources>
diff --git a/PermissionController/res/values-te-v35/strings.xml b/PermissionController/res/values-te-v35/strings.xml
new file mode 100644
index 000000000..7285aa987
--- /dev/null
+++ b/PermissionController/res/values-te-v35/strings.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2024 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="safety_center_entries_category_title" msgid="4413287601344137909">"సెక్యూరిటీ"</string>
+</resources>
diff --git a/PermissionController/res/values-th-v35/strings.xml b/PermissionController/res/values-th-v35/strings.xml
new file mode 100644
index 000000000..cf819a8ce
--- /dev/null
+++ b/PermissionController/res/values-th-v35/strings.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2024 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="safety_center_entries_category_title" msgid="4413287601344137909">"ความปลอดภัย"</string>
+</resources>
diff --git a/PermissionController/res/values-tl-v35/strings.xml b/PermissionController/res/values-tl-v35/strings.xml
new file mode 100644
index 000000000..ecd01df78
--- /dev/null
+++ b/PermissionController/res/values-tl-v35/strings.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2024 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="safety_center_entries_category_title" msgid="4413287601344137909">"Seguridad"</string>
+</resources>
diff --git a/PermissionController/res/values-tr-v35/strings.xml b/PermissionController/res/values-tr-v35/strings.xml
new file mode 100644
index 000000000..ed8a1bf04
--- /dev/null
+++ b/PermissionController/res/values-tr-v35/strings.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2024 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="safety_center_entries_category_title" msgid="4413287601344137909">"Güvenlik"</string>
+</resources>
diff --git a/PermissionController/res/values-uk-v35/strings.xml b/PermissionController/res/values-uk-v35/strings.xml
new file mode 100644
index 000000000..d6eeae9b5
--- /dev/null
+++ b/PermissionController/res/values-uk-v35/strings.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2024 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="safety_center_entries_category_title" msgid="4413287601344137909">"Безпека"</string>
+</resources>
diff --git a/PermissionController/res/values-ur-v35/strings.xml b/PermissionController/res/values-ur-v35/strings.xml
new file mode 100644
index 000000000..d06432a1e
--- /dev/null
+++ b/PermissionController/res/values-ur-v35/strings.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2024 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="safety_center_entries_category_title" msgid="4413287601344137909">"سیکیورٹی"</string>
+</resources>
diff --git a/PermissionController/res/values-uz-v35/strings.xml b/PermissionController/res/values-uz-v35/strings.xml
new file mode 100644
index 000000000..965903b10
--- /dev/null
+++ b/PermissionController/res/values-uz-v35/strings.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2024 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="safety_center_entries_category_title" msgid="4413287601344137909">"Xavfsizlik"</string>
+</resources>
diff --git a/PermissionController/res/values-v35/styles.xml b/PermissionController/res/values-v35/styles.xml
index 612125fb1..513754bb8 100644
--- a/PermissionController/res/values-v35/styles.xml
+++ b/PermissionController/res/values-v35/styles.xml
@@ -197,5 +197,221 @@
<item name="android:visibility">gone</item>
</style>
+ <style name="PermissionSelectorWithWidgetPreferenceRootLayoutStyle">
+ <item name="android:layout_width">match_parent</item>
+ <item name="android:layout_height">wrap_content</item>
+ <item name="android:background">?android:attr/selectableItemBackground</item>
+ <item name="android:gravity">center_vertical</item>
+ <item name="android:minHeight">?android:attr/listPreferredItemHeightSmall</item>
+ <item name="android:paddingEnd">?android:attr/listPreferredItemPaddingEnd</item>
+ </style>
+
+ <style name="PermissionSelectorWithWidgetPreferenceWidgetFrameStyle">
+ <item name="android:layout_width">wrap_content</item>
+ <item name="android:layout_height">match_parent</item>
+ <item name="android:paddingHorizontal">20dp</item>
+ <item name="android:gravity">center</item>
+ <item name="android:minWidth">56dp</item>
+ <item name="android:orientation">vertical</item>
+ </style>
+
+ <style name="PermissionSelectorWithWidgetPreferenceIconFrameStyle">
+ <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:minWidth">32dp</item>
+ <item name="android:orientation">horizontal</item>
+ <item name="android:layout_marginEnd">16dp</item>
+ <item name="android:paddingTop">4dp</item>
+ <item name="android:paddingBottom">4dp</item>
+ </style>
+
+ <style name="PermissionSelectorWithWidgetPreferenceIconStyle">
+ <item name="android:layout_width">wrap_content</item>
+ <item name="android:layout_height">wrap_content</item>
+ <item name="maxWidth">@dimen/secondary_app_icon_size</item>
+ <item name="maxHeight">@dimen/secondary_app_icon_size</item>
+ </style>
+
+ <style name="PermissionSelectorWithWidgetPreferenceTextContainerStyle">
+ <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:orientation">vertical</item>
+ <item name="android:paddingTop">16dp</item>
+ <item name="android:paddingBottom">16dp</item>
+ <item name="android:paddingEnd">?android:attr/listPreferredItemPaddingEnd</item>
+ </style>
+
+ <style name="PermissionSelectorWithWidgetPreferenceTitleStyle">
+ <item name="android:layout_width">wrap_content</item>
+ <item name="android:layout_height">wrap_content</item>
+ <item name="android:maxLines">2</item>
+ <item name="android:ellipsize">end</item>
+ <item name="android:hyphenationFrequency">normalFast</item>
+ <item name="android:lineBreakWordStyle">phrase</item>
+ <item name="android:textAppearance">?android:attr/textAppearanceListItem</item>
+ </style>
+
+ <style name="PermissionSelectorWithWidgetPreferenceSummaryContainerStyle">
+ <item name="android:layout_width">match_parent</item>
+ <item name="android:layout_height">wrap_content</item>
+ <item name="android:visibility">gone</item>
+ </style>
+
+ <style name="PermissionSelectorWithWidgetPreferenceSummaryStyle">
+ <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:textAppearance">?android:attr/textAppearanceSmall</item>
+ <item name="android:textAlignment">viewStart</item>
+ <item name="android:hyphenationFrequency">normalFast</item>
+ <item name="android:lineBreakWordStyle">phrase</item>
+ <item name="android:textColor">?android:attr/textColorSecondary</item>
+ </style>
+
+ <style name="PermissionSelectorWithWidgetPreferenceAppendixStyle">
+ <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:textAppearance">?android:attr/textAppearanceSmall</item>
+ <item name="android:textAlignment">viewEnd</item>
+ <item name="android:textColor">?android:attr/textColorSecondary</item>
+ <item name="android:maxLines">1</item>
+ <item name="android:visibility">gone</item>
+ <item name="android:ellipsize">end</item>
+ </style>
+
+ <style name="PermissionSelectorWithWidgetPreferenceExtraWidgetContainerStyle">
+ <item name="android:layout_width">wrap_content</item>
+ <item name="android:layout_height">match_parent</item>
+ <item name="android:orientation">horizontal</item>
+ <item name="android:gravity">center_vertical</item>
+ </style>
+
+ <style name="PermissionSelectorWithWidgetPreferenceExtraWidgetDividerStyle">
+ <item name="android:layout_width">.75dp</item>
+ <item name="android:layout_height">32dp</item>
+ <item name="android:layout_marginTop">16dp</item>
+ <item name="android:layout_marginBottom">16dp</item>
+ <item name="android:background">?android:attr/dividerVertical</item>
+ </style>
+
+ <style name="PermissionSelectorWithWidgetPreferenceExtraWidgetImageStyle">
+ <item name="android:layout_width">match_parent</item>
+ <item name="android:minWidth">@dimen/two_target_min_width</item>
+ <item name="android:layout_height">fill_parent</item>
+ <item name="android:src">@drawable/ic_settings_accent</item>
+ <item name="android:paddingStart">24dp</item>
+ <item name="android:paddingEnd">24dp</item>
+ <item name="android:layout_gravity">center</item>
+ <item name="android:background">?android:attr/selectableItemBackground</item>
+ </style>
+
+ <style name="PermissionSelectorWithWidgetPreferenceWidgetRadioButton">
+ <item name="android:layout_width">wrap_content</item>
+ <item name="android:layout_height">wrap_content</item>
+ <item name="android:layout_gravity">center</item>
+ <item name="android:background">@null</item>
+ <item name="android:focusable">false</item>
+ <item name="android:clickable">false</item>
+ </style>
+
+ <style name="PermissionTwoTargetPreferenceRootLayoutStyle">
+ <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:background">?android:attr/selectableItemBackground</item>
+ <item name="android:paddingStart">?android:attr/listPreferredItemPaddingStart</item>
+ <item name="android:paddingEnd">?android:attr/listPreferredItemPaddingEnd</item>
+ <item name="android:clipToPadding">false</item>
+ </style>
+
+ <style name="PermissionTwoTargetPreferenceTextContainerStyle">
+ <item name="android:layout_width">wrap_content</item>
+ <item name="android:layout_height">wrap_content</item>
+ <item name="android:layout_weight">1</item>
+ <item name="android:paddingTop">16dp</item>
+ <item name="android:paddingBottom">16dp</item>
+ </style>
+
+ <style name="PermissionTwoTargetPreferenceTitleStyle">
+ <item name="android:layout_width">wrap_content</item>
+ <item name="android:layout_height">wrap_content</item>
+ <item name="android:maxLines">2</item>
+ <item name="android:hyphenationFrequency">normalFast</item>
+ <item name="android:lineBreakWordStyle">phrase</item>
+ <item name="android:textAppearance">?android:attr/textAppearanceListItem</item>
+ <item name="android:ellipsize">marquee</item>
+ </style>
+
+ <style name="PermissionTwoTargetPreferenceSummaryStyle">
+ <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:hyphenationFrequency">normalFast</item>
+ <item name="android:lineBreakWordStyle">phrase</item>
+ <item name="android:maxLines">10</item>
+ </style>
+
+ <style name="PermissionTwoTargetPreferenceWidgetFrameStyle">
+ <item name="android:layout_width">wrap_content</item>
+ <item name="android:layout_height">match_parent</item>
+ <item name="android:minWidth">@dimen/two_target_min_width</item>
+ <item name="android:gravity">center</item>
+ <item name="android:orientation">vertical</item>
+ </style>
+
+ <style name="PermissionTwoTargetPreferenceIconFrameStyle">
+ <item name="android:layout_width">wrap_content</item>
+ <item name="android:layout_height">wrap_content</item>
+ <item name="android:minWidth">48dp</item>
+ <item name="android:gravity">start|center_vertical</item>
+ <item name="android:orientation">horizontal</item>
+ <item name="android:paddingLeft">0dp</item>
+ <item name="android:paddingStart">0dp</item>
+ <item name="android:paddingRight">8dp</item>
+ <item name="android:paddingEnd">8dp</item>
+ <item name="android:paddingTop">4dp</item>
+ <item name="android:paddingBottom">4dp</item>
+ </style>
+
+ <style name="PermissionTwoTargetPreferenceIconStyle">
+ <item name="android:layout_width">wrap_content</item>
+ <item name="android:layout_height">wrap_content</item>
+ <item name="maxWidth">48dp</item>
+ <item name="maxHeight">48dp</item>
+ </style>
+
+ <style name="PermissionTwoTargetPreferenceDividerContainerStyle">
+ <item name="android:layout_width">wrap_content</item>
+ <item name="android:layout_height">match_parent</item>
+ <item name="android:gravity">start|center_vertical</item>
+ <item name="android:orientation">horizontal</item>
+ <item name="android:paddingStart">?android:attr/listPreferredItemPaddingEnd</item>
+ <item name="android:paddingLeft">?android:attr/listPreferredItemPaddingEnd</item>
+ <item name="android:paddingTop">16dp</item>
+ <item name="android:paddingBottom">16dp</item>
+ </style>
+
+ <style name="PermissionTwoTargetPreferenceDividerStyle">
+ <item name="android:layout_width">1dp</item>
+ <item name="android:layout_height">32dp</item>
+ <item name="android:background">?android:attr/listDivider</item>
+ </style>
+
+ <style name="AppPermissionFooterLinkPreferenceRootLayoutStyle"
+ parent="PermissionPreferenceRootLayoutStyle" />
+
+ <style name="AppPermissionFooterLinkPreferenceTextLayoutStyle"
+ parent="PermissionPreferenceTextRelativeLayoutStyle" />
+
+ <style name="AppPermissionFooterLinkPreferenceSummaryStyle"
+ parent="PermissionPreferenceSummaryTextStyle" />
+
<!-- END PREFERENCE STYLES -->
</resources> \ No newline at end of file
diff --git a/PermissionController/res/values-vi-v35/strings.xml b/PermissionController/res/values-vi-v35/strings.xml
new file mode 100644
index 000000000..56c9bd351
--- /dev/null
+++ b/PermissionController/res/values-vi-v35/strings.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2024 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="safety_center_entries_category_title" msgid="4413287601344137909">"Bảo mật"</string>
+</resources>
diff --git a/PermissionController/res/values-zh-rCN-v35/strings.xml b/PermissionController/res/values-zh-rCN-v35/strings.xml
new file mode 100644
index 000000000..c9da7729f
--- /dev/null
+++ b/PermissionController/res/values-zh-rCN-v35/strings.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2024 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="safety_center_entries_category_title" msgid="4413287601344137909">"安全"</string>
+</resources>
diff --git a/PermissionController/res/values-zh-rHK-v35/strings.xml b/PermissionController/res/values-zh-rHK-v35/strings.xml
new file mode 100644
index 000000000..15c4d9bff
--- /dev/null
+++ b/PermissionController/res/values-zh-rHK-v35/strings.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2024 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="safety_center_entries_category_title" msgid="4413287601344137909">"安全性"</string>
+</resources>
diff --git a/PermissionController/res/values-zh-rTW-v35/strings.xml b/PermissionController/res/values-zh-rTW-v35/strings.xml
new file mode 100644
index 000000000..15c4d9bff
--- /dev/null
+++ b/PermissionController/res/values-zh-rTW-v35/strings.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2024 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="safety_center_entries_category_title" msgid="4413287601344137909">"安全性"</string>
+</resources>
diff --git a/PermissionController/res/values-zu-v35/strings.xml b/PermissionController/res/values-zu-v35/strings.xml
new file mode 100644
index 000000000..39381b3ce
--- /dev/null
+++ b/PermissionController/res/values-zu-v35/strings.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2024 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="safety_center_entries_category_title" msgid="4413287601344137909">"Ukuvikeleka"</string>
+</resources>
diff --git a/PermissionController/res/values/attrs.xml b/PermissionController/res/values/attrs.xml
index cc93effde..0634ab5f1 100644
--- a/PermissionController/res/values/attrs.xml
+++ b/PermissionController/res/values/attrs.xml
@@ -37,4 +37,9 @@
<attr name="carDividerColor" format="color"/>
<!-- END: Car Settings Preferences -->
+ <!-- START: AppPermissionFragment -->
+ <attr name="extraWidgetId" format="reference" />
+ <attr name="extraWidgetIcon" format="reference" />
+ <attr name="checkboxId" format="reference" />
+ <!-- END: AppPermissionFragment -->
</resources>
diff --git a/PermissionController/res/values/bools.xml b/PermissionController/res/values/bools.xml
index b5f33b081..4cfed5e79 100644
--- a/PermissionController/res/values/bools.xml
+++ b/PermissionController/res/values/bools.xml
@@ -20,4 +20,5 @@
<bool name="is_at_least_t">false</bool>
<bool name="is_at_least_u">false</bool>
<bool name="is_at_least_v">false</bool>
+ <bool name="config_usePreferenceForAppPermissionSettings">false</bool>
</resources>
diff --git a/PermissionController/res/values/overlayable.xml b/PermissionController/res/values/overlayable.xml
index 9075fa67c..31f3355e4 100644
--- a/PermissionController/res/values/overlayable.xml
+++ b/PermissionController/res/values/overlayable.xml
@@ -48,6 +48,35 @@
<item type="style" name="PermissionFooterPreferenceTitleTextStyle" />
<item type="style" name="PermissionFooterPreferenceLearnMoreTextStyle" />
+ <item type="style" name="PermissionSelectorWithWidgetPreferenceRootLayoutStyle" />
+ <item type="style" name="PermissionSelectorWithWidgetPreferenceWidgetFrameStyle" />
+ <item type="style" name="PermissionSelectorWithWidgetPreferenceIconFrameStyle" />
+ <item type="style" name="PermissionSelectorWithWidgetPreferenceIconStyle" />
+ <item type="style" name="PermissionSelectorWithWidgetPreferenceTextContainerStyle" />
+ <item type="style" name="PermissionSelectorWithWidgetPreferenceTitleStyle" />
+ <item type="style" name="PermissionSelectorWithWidgetPreferenceSummaryContainerStyle" />
+ <item type="style" name="PermissionSelectorWithWidgetPreferenceSummaryStyle" />
+ <item type="style" name="PermissionSelectorWithWidgetPreferenceAppendixStyle" />
+ <item type="style" name="PermissionSelectorWithWidgetPreferenceExtraWidgetContainerStyle" />
+ <item type="style" name="PermissionSelectorWithWidgetPreferenceExtraWidgetDividerStyle" />
+ <item type="style" name="PermissionSelectorWithWidgetPreferenceExtraWidgetImageStyle" />
+ <item type="style" name="PermissionSelectorWithWidgetPreferenceWidgetRadioButton" />
+
+ <item type="style" name="PermissionTwoTargetPreferenceRootLayoutStyle" />
+ <item type="style" name="PermissionTwoTargetPreferenceTextContainerStyle" />
+ <item type="style" name="PermissionTwoTargetPreferenceTitleStyle" />
+ <item type="style" name="PermissionTwoTargetPreferenceSummaryStyle" />
+ <item type="style" name="PermissionTwoTargetPreferenceWidgetFrameStyle" />
+ <item type="style" name="PermissionTwoTargetPreferenceIconFrameStyle" />
+ <item type="style" name="PermissionTwoTargetPreferenceIconStyle" />
+ <item type="style" name="PermissionTwoTargetPreferenceDividerContainerStyle" />
+ <item type="style" name="PermissionTwoTargetPreferenceDividerStyle" />
+
+ <item type="style" name="AppPermissionFooterLinkPreferenceRootLayoutStyle" />
+ <item type="style" name="AppPermissionFooterLinkPreferenceTextLayoutStyle" />
+ <item type="style" name="AppPermissionFooterLinkPreferenceSummaryStyle" />
+
+ <item type="bool" name="config_usePreferenceForAppPermissionSettings" />
<item type="bool" name="config_permissionFooterPreferenceIconVisible" />
<item type="dimen" name="permission_preference_app_icon_size" />
<item type="dimen" name="permission_preference_permission_group_icon_size" />
diff --git a/PermissionController/res/xml-v35/app_permission.xml b/PermissionController/res/xml-v35/app_permission.xml
new file mode 100644
index 000000000..87315815d
--- /dev/null
+++ b/PermissionController/res/xml-v35/app_permission.xml
@@ -0,0 +1,102 @@
+<PreferenceScreen
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:app="http://schemas.android.com/apk/res-auto">
+
+ <com.android.permissioncontroller.permission.ui.handheld.PermissionPreferenceCategory
+ android:key="app_permission_rationale_container"
+ android:title="@string/app_permission_rationale_message"
+ app:isPreferenceVisible="false">
+
+ <com.android.permissioncontroller.permission.ui.handheld.PermissionPreference
+ android:key="app_permission_rationale"
+ android:icon="@drawable/ic_shield_exclamation_outline_24dp"
+ android:summary="@string/app_location_permission_rationale_subtitle"
+ android:title="@string/app_location_permission_rationale_title" />
+
+ </com.android.permissioncontroller.permission.ui.handheld.PermissionPreferenceCategory>
+
+ <com.android.permissioncontroller.permission.ui.handheld.PermissionPreferenceCategory
+ android:key="app_permission_button_category"
+ android:title="@string/app_permission_header">
+
+ <com.android.permissioncontroller.permission.ui.handheld.v36.PermissionSelectorWithWidgetPreference
+ android:key="app_permission_allow_radio_button"
+ android:title="@string/app_permission_button_allow"
+ app:checkboxId="@+id/allow_radio_button" />
+
+ <com.android.permissioncontroller.permission.ui.handheld.v36.PermissionSelectorWithWidgetPreference
+ android:key="app_permission_allow_always_radio_button"
+ android:title="@string/app_permission_button_allow_always"
+ app:checkboxId="@+id/allow_always_radio_button"
+ app:isPreferenceVisible="false" />
+
+ <com.android.permissioncontroller.permission.ui.handheld.v36.PermissionSelectorWithWidgetPreference
+ android:key="app_permission_allow_foreground_only_radio_button"
+ android:title="@string/app_permission_button_allow_foreground"
+ app:checkboxId="@+id/allow_foreground_only_radio_button" />
+
+ <com.android.permissioncontroller.permission.ui.handheld.v36.PermissionSelectorWithWidgetPreference
+ android:key="app_permission_select_photos_radio_button"
+ android:title="@string/app_permission_button_allow_limited_access"
+ app:checkboxId="@+id/select_radio_button"
+ app:extraWidgetIcon="@drawable/ic_edit"
+ app:extraWidgetId="@+id/edit_selected_button" />
+
+ <com.android.permissioncontroller.permission.ui.handheld.v36.PermissionSelectorWithWidgetPreference
+ android:key="app_permission_ask_one_time_radio_button"
+ android:title="@string/app_permission_button_ask"
+ app:checkboxId="@+id/ask_one_time_radio_button" />
+
+ <com.android.permissioncontroller.permission.ui.handheld.v36.PermissionSelectorWithWidgetPreference
+ android:key="app_permission_ask_radio_button"
+ android:text="@string/app_permission_button_ask"
+ android:title="@string/app_permission_button_ask"
+ app:checkboxId="@+id/ask_radio_button" />
+
+ <com.android.permissioncontroller.permission.ui.handheld.v36.PermissionSelectorWithWidgetPreference
+ android:key="app_permission_deny_radio_button"
+ android:title="@string/app_permission_button_deny"
+ app:checkboxId="@+id/deny_radio_button" />
+
+ <com.android.permissioncontroller.permission.ui.handheld.v36.PermissionSelectorWithWidgetPreference
+ android:key="app_permission_deny_foreground_radio_button"
+ android:title="@string/app_permission_button_deny"
+ app:checkboxId="@+id/deny_foreground_radio_button" />
+
+ </com.android.permissioncontroller.permission.ui.handheld.PermissionPreferenceCategory>
+
+ <com.android.permissioncontroller.permission.ui.handheld.PermissionSwitchPreference
+ android:key="app_permission_location_accuracy_switch"
+ android:summary="@string/app_permission_location_accuracy_subtitle"
+ android:title="@string/app_permission_location_accuracy"
+ app:isPreferenceVisible="false" />
+
+ <com.android.permissioncontroller.permission.ui.handheld.v36.PermissionTwoTargetPreference
+ android:key="app_permission_details"
+ android:selectable="false"
+ android:summary="@string/permission_summary_enabled_system_fixed"
+ app:extraWidgetIcon="@drawable/ic_settings"
+ app:iconSpaceReserved="true"
+ app:isPreferenceVisible="false" />
+
+ <com.android.permissioncontroller.permission.ui.handheld.v36.AppPermissionFooterLinkPreference
+ android:key="app_permission_footer_link_1"
+ android:summary="@string/app_permission_footer_app_permissions_link" />
+
+ <com.android.permissioncontroller.permission.ui.handheld.v36.AppPermissionFooterLinkPreference
+ android:key="app_permission_footer_link_2"
+ android:summary="@string/app_permission_footer_permission_apps_link" />
+
+ <com.android.permissioncontroller.permission.ui.handheld.PermissionFooterPreference
+ android:key="app_permission_footer_storage_special_app_access"
+ android:icon="@drawable/ic_info_outline"
+ android:title="@string/app_permission_footer_special_file_access"
+ app:isPreferenceVisible="false" />
+
+ <com.android.permissioncontroller.permission.ui.handheld.PermissionFooterPreference
+ android:key="app_permission_additional_info"
+ android:icon="@drawable/ic_info_outline"
+ android:title="@string/exempt_info_label"
+ app:isPreferenceVisible="false" />
+
+</PreferenceScreen>
diff --git a/PermissionController/role-controller/java/com/android/role/controller/behavior/v34/NotesRoleBehavior.java b/PermissionController/role-controller/java/com/android/role/controller/behavior/v34/NotesRoleBehavior.java
index 71f7795f7..382a03d5f 100644
--- a/PermissionController/role-controller/java/com/android/role/controller/behavior/v34/NotesRoleBehavior.java
+++ b/PermissionController/role-controller/java/com/android/role/controller/behavior/v34/NotesRoleBehavior.java
@@ -46,17 +46,12 @@ public class NotesRoleBehavior implements RoleBehavior {
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;
+ return !UserUtils.isProfile(user, context);
}
/**
diff --git a/PermissionController/src/com/android/permissioncontroller/hibernation/HibernationPolicy.kt b/PermissionController/src/com/android/permissioncontroller/hibernation/HibernationPolicy.kt
index d23225ed3..8b11036e8 100644
--- a/PermissionController/src/com/android/permissioncontroller/hibernation/HibernationPolicy.kt
+++ b/PermissionController/src/com/android/permissioncontroller/hibernation/HibernationPolicy.kt
@@ -73,6 +73,7 @@ import android.service.dreams.DreamService
import android.service.notification.NotificationListenerService
import android.service.voice.VoiceInteractionService
import android.service.wallpaper.WallpaperService
+import android.telecom.TelecomManager
import android.telephony.TelephonyManager.CARRIER_PRIVILEGE_STATUS_HAS_ACCESS
import android.telephony.TelephonyManager.CARRIER_PRIVILEGE_STATUS_NO_ACCESS
import android.util.Log
@@ -658,6 +659,36 @@ suspend fun isPackageHibernationExemptBySystem(
return true
}
+ // Note that it's fine to check permissions instead of app ops as all these permissions were
+ // introduced before auto-revoke / hibernation in R.
+ val hasCallRelatedPermissions =
+ context.checkPermission(Manifest.permission.MANAGE_OWN_CALLS, -1 /* pid */, pkg.uid) ==
+ PERMISSION_GRANTED
+ && context.checkPermission(Manifest.permission.RECORD_AUDIO, -1 /* pid */, pkg.uid) ==
+ PERMISSION_GRANTED
+ && context.checkPermission(Manifest.permission.WRITE_CALL_LOG, -1 /* pid */, pkg.uid) ==
+ PERMISSION_GRANTED
+ if (hasCallRelatedPermissions) {
+ val phoneAccounts = context.getSystemService(TelecomManager::class.java)!!
+ .selfManagedPhoneAccounts
+ var hasRegisteredPhoneAccount = false
+ for (phoneAccount in phoneAccounts) {
+ if (pkg.packageName == phoneAccount.componentName.packageName) {
+ hasRegisteredPhoneAccount = true
+ break
+ }
+ }
+ if (hasRegisteredPhoneAccount) {
+ if (DEBUG_HIBERNATION_POLICY) {
+ DumpableLog.i(
+ LOG_TAG,
+ "Exempted ${pkg.packageName} - caller app"
+ )
+ }
+ return true
+ }
+ }
+
if (SdkLevel.isAtLeastS()) {
val hasInstallOrUpdatePermissions =
context.checkPermission(Manifest.permission.INSTALL_PACKAGES, -1 /* pid */, pkg.uid) ==
diff --git a/PermissionController/src/com/android/permissioncontroller/hibernation/TEST_MAPPING b/PermissionController/src/com/android/permissioncontroller/hibernation/TEST_MAPPING
index 69a8f74be..038b2f992 100644
--- a/PermissionController/src/com/android/permissioncontroller/hibernation/TEST_MAPPING
+++ b/PermissionController/src/com/android/permissioncontroller/hibernation/TEST_MAPPING
@@ -11,5 +11,15 @@
}
]
}
+ ],
+ "postsubmit": [
+ {
+ "name": "PermissionControllerMockingTests",
+ "options": [
+ {
+ "include-filter": "com.android.permissioncontroller.tests.mocking.hibernation"
+ }
+ ]
+ }
]
}
diff --git a/PermissionController/src/com/android/permissioncontroller/permission/compat/AppPermissionFragmentCompat.java b/PermissionController/src/com/android/permissioncontroller/permission/compat/AppPermissionFragmentCompat.java
index 188e3a9d0..de7404ead 100644
--- a/PermissionController/src/com/android/permissioncontroller/permission/compat/AppPermissionFragmentCompat.java
+++ b/PermissionController/src/com/android/permissioncontroller/permission/compat/AppPermissionFragmentCompat.java
@@ -19,6 +19,7 @@ package com.android.permissioncontroller.permission.compat;
import static com.android.permissioncontroller.Constants.EXTRA_SESSION_ID;
import static com.android.permissioncontroller.permission.ui.ManagePermissionsActivity.EXTRA_CALLER_NAME;
+import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.os.UserHandle;
@@ -29,6 +30,7 @@ import androidx.preference.PreferenceFragmentCompat;
import com.android.modules.utils.build.SdkLevel;
import com.android.permission.flags.Flags;
+import com.android.permissioncontroller.R;
import com.android.permissioncontroller.permission.ui.handheld.max35.LegacyAppPermissionFragment;
import com.android.permissioncontroller.permission.ui.handheld.v36.AppPermissionFragment;
@@ -41,8 +43,10 @@ public class AppPermissionFragmentCompat {
* Create an instance of this fragment
*/
@NonNull
- public static PreferenceFragmentCompat createFragment() {
- if (SdkLevel.isAtLeastV() && Flags.appPermissionFragmentUsesPreferences()) {
+ public static PreferenceFragmentCompat createFragment(@NonNull Context context) {
+ if (SdkLevel.isAtLeastV() && (Flags.appPermissionFragmentUsesPreferences()
+ || context.getResources().getBoolean(
+ R.bool.config_usePreferenceForAppPermissionSettings))) {
return new AppPermissionFragment();
} else {
return new LegacyAppPermissionFragment();
diff --git a/PermissionController/src/com/android/permissioncontroller/permission/domain/usecase/v31/GetPermissionGroupUsageDetailsUseCase.kt b/PermissionController/src/com/android/permissioncontroller/permission/domain/usecase/v31/GetPermissionGroupUsageDetailsUseCase.kt
index 16eaaf6f2..edf6e22e5 100644
--- a/PermissionController/src/com/android/permissioncontroller/permission/domain/usecase/v31/GetPermissionGroupUsageDetailsUseCase.kt
+++ b/PermissionController/src/com/android/permissioncontroller/permission/domain/usecase/v31/GetPermissionGroupUsageDetailsUseCase.kt
@@ -21,6 +21,7 @@ import android.app.AppOpsManager
import android.os.UserHandle
import android.permission.flags.Flags
import com.android.modules.utils.build.SdkLevel
+import com.android.permissioncontroller.PermissionControllerApplication
import com.android.permissioncontroller.appops.data.model.v31.DiscretePackageOpsModel
import com.android.permissioncontroller.appops.data.model.v31.DiscretePackageOpsModel.DiscreteOpModel
import com.android.permissioncontroller.appops.data.repository.v31.AppOpRepository
@@ -29,6 +30,7 @@ import com.android.permissioncontroller.permission.domain.model.v31.PermissionTi
import com.android.permissioncontroller.permission.domain.model.v31.PermissionTimelineUsageModelWrapper
import com.android.permissioncontroller.permission.ui.model.v31.PermissionUsageDetailsViewModel.Companion.CLUSTER_SPACING_MINUTES
import com.android.permissioncontroller.permission.ui.model.v31.PermissionUsageDetailsViewModel.Companion.ONE_MINUTE_MS
+import com.android.permissioncontroller.permission.utils.LocationUtils
import com.android.permissioncontroller.permission.utils.PermissionMapping
import com.android.permissioncontroller.pm.data.repository.v31.PackageRepository
import com.android.permissioncontroller.role.data.repository.v31.RoleRepository
@@ -72,7 +74,7 @@ class GetPermissionGroupUsageDetailsUseCase(
permissionGroup,
packageOps.userId,
permissionRepository,
- packageRepository
+ packageRepository,
)
packageOps
}
@@ -86,43 +88,61 @@ class GetPermissionGroupUsageDetailsUseCase(
}
}
+ // show attribution on T+ for location provider only..
+ private fun shouldShowAttributionLabel(packageName: String): Boolean {
+ return if (com.android.permission.flags.Flags.permissionTimelineAttributionLabelFix()) {
+ SdkLevel.isAtLeastT() &&
+ LocationUtils.isLocationProvider(PermissionControllerApplication.get(), packageName)
+ } else true
+ }
+
/** Group app op accesses by attribution label if it is available and user visible. */
private suspend fun List<DiscretePackageOpsModel>.groupByAttributionLabelIfNeeded() =
map { packageOps ->
- val attributionInfo =
- packageRepository.getPackageAttributionInfo(
- packageOps.packageName,
- UserHandle.of(packageOps.userId)
- )
- if (attributionInfo != null) {
- if (attributionInfo.areUserVisible && attributionInfo.tagResourceMap != null) {
- val attributionLabelOpsMap: Map<String?, List<DiscreteOpModel>> =
- packageOps.appOpAccesses
- .map { appOpEntry ->
- val resourceId =
- attributionInfo.tagResourceMap[appOpEntry.attributionTag]
- val label = attributionInfo.resourceLabelMap?.get(resourceId)
- label to appOpEntry
- }
- .groupBy { labelAppOpEntryPair -> labelAppOpEntryPair.first }
- .mapValues { (_, values) ->
- values.map { labelAppOpEntryPair -> labelAppOpEntryPair.second }
- }
+ if (!shouldShowAttributionLabel(packageOps.packageName)) {
+ listOf(packageOps)
+ } else {
+ val attributionInfo =
+ packageRepository.getPackageAttributionInfo(
+ packageOps.packageName,
+ UserHandle.of(packageOps.userId),
+ )
+ if (attributionInfo != null) {
+ if (
+ attributionInfo.areUserVisible && attributionInfo.tagResourceMap != null
+ ) {
+ val attributionLabelOpsMap: Map<String?, List<DiscreteOpModel>> =
+ packageOps.appOpAccesses
+ .map { appOpEntry ->
+ val resourceId =
+ attributionInfo.tagResourceMap[
+ appOpEntry.attributionTag]
+ val label =
+ attributionInfo.resourceLabelMap?.get(resourceId)
+ label to appOpEntry
+ }
+ .groupBy { labelAppOpEntryPair -> labelAppOpEntryPair.first }
+ .mapValues { (_, values) ->
+ values.map { labelAppOpEntryPair ->
+ labelAppOpEntryPair.second
+ }
+ }
- attributionLabelOpsMap.map { labelAppOpsEntry ->
- DiscretePackageOpsModel(
- packageOps.packageName,
- packageOps.userId,
- appOpAccesses = labelAppOpsEntry.value,
- attributionLabel = labelAppOpsEntry.key,
- isUserSensitive = packageOps.isUserSensitive,
- )
+ attributionLabelOpsMap.map { labelAppOpsEntry ->
+ DiscretePackageOpsModel(
+ packageOps.packageName,
+ packageOps.userId,
+ appOpAccesses = labelAppOpsEntry.value,
+ attributionLabel = labelAppOpsEntry.key,
+ isUserSensitive = packageOps.isUserSensitive,
+ )
+ }
+ } else {
+ listOf(packageOps)
}
} else {
listOf(packageOps)
}
- } else {
- listOf(packageOps)
}
}
.flatten()
@@ -147,7 +167,7 @@ class GetPermissionGroupUsageDetailsUseCase(
packageOps.userId,
currentCluster.toMutableList(),
packageOps.attributionLabel,
- packageOps.isUserSensitive
+ packageOps.isUserSensitive,
)
)
currentCluster.clear()
@@ -164,7 +184,7 @@ class GetPermissionGroupUsageDetailsUseCase(
packageOps.userId,
currentCluster.toMutableList(),
packageOps.attributionLabel,
- packageOps.isUserSensitive
+ packageOps.isUserSensitive,
)
)
}
@@ -220,7 +240,7 @@ class GetPermissionGroupUsageDetailsUseCase(
private fun canAccessBeAddedToCluster(
currentAccess: DiscreteOpModel,
- clusteredAccesses: List<DiscreteOpModel>
+ clusteredAccesses: List<DiscreteOpModel>,
): Boolean {
val clusterOp = clusteredAccesses.last().opName
if (
@@ -282,7 +302,7 @@ class GetPermissionGroupUsageDetailsUseCase(
listOf(
Manifest.permission_group.CAMERA,
Manifest.permission_group.LOCATION,
- Manifest.permission_group.MICROPHONE
+ Manifest.permission_group.MICROPHONE,
)
permissionGroups.forEach { permissionGroup ->
val opNames =
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 2d14260a2..36597a3a3 100644
--- a/PermissionController/src/com/android/permissioncontroller/permission/ui/auto/dashboard/AutoPermissionHistoryPreference.kt
+++ b/PermissionController/src/com/android/permissioncontroller/permission/ui/auto/dashboard/AutoPermissionHistoryPreference.kt
@@ -23,30 +23,30 @@ import androidx.annotation.RequiresApi
import androidx.preference.Preference.OnPreferenceClickListener
import com.android.car.ui.preference.CarUiPreference
import com.android.permissioncontroller.R
-import com.android.permissioncontroller.permission.ui.legacy.PermissionUsageDetailsViewModelLegacy
import com.android.permissioncontroller.permission.ui.model.v31.PermissionUsageDetailsViewModel
+import com.android.permissioncontroller.permission.ui.model.v31.PermissionUsageDetailsViewModel.AppPermissionAccessUiInfo
/** Preference that displays a permission usage for an app. */
@RequiresApi(Build.VERSION_CODES.S)
class AutoPermissionHistoryPreference(
context: Context,
- historyPreferenceData: PermissionUsageDetailsViewModelLegacy.HistoryPreferenceData
+ historyPreferenceData: AppPermissionAccessUiInfo,
) : CarUiPreference(context) {
init {
- title = historyPreferenceData.preferenceTitle
+ title = historyPreferenceData.packageLabel
summary =
if (historyPreferenceData.summaryText != null) {
context.getString(
R.string.auto_permission_usage_timeline_summary,
DateFormat.getTimeFormat(context).format(historyPreferenceData.accessEndTime),
- historyPreferenceData.summaryText
+ historyPreferenceData.summaryText,
)
} else {
DateFormat.getTimeFormat(context).format(historyPreferenceData.accessEndTime)
}
- if (historyPreferenceData.appIcon != null) {
- icon = historyPreferenceData.appIcon
+ if (historyPreferenceData.badgedPackageIcon != null) {
+ icon = historyPreferenceData.badgedPackageIcon
}
onPreferenceClickListener = OnPreferenceClickListener {
@@ -56,12 +56,12 @@ class AutoPermissionHistoryPreference(
PermissionUsageDetailsViewModel.createHistoryPreferenceClickIntent(
context = context,
userHandle = historyPreferenceData.userHandle,
- packageName = historyPreferenceData.pkgName,
+ packageName = historyPreferenceData.packageName,
permissionGroup = historyPreferenceData.permissionGroup,
accessEndTime = historyPreferenceData.accessEndTime,
accessStartTime = historyPreferenceData.accessStartTime,
showingAttribution = historyPreferenceData.showingAttribution,
- attributionTags = historyPreferenceData.attributionTags.toSet()
+ attributionTags = historyPreferenceData.attributionTags.toSet(),
)
)
true
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 481543eb6..8edd39913 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
@@ -13,11 +13,8 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-@file:Suppress("DEPRECATION")
-
package com.android.permissioncontroller.permission.ui.auto.dashboard
-import android.app.role.RoleManager
import android.content.Intent
import android.os.Build
import android.os.Bundle
@@ -36,16 +33,12 @@ 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.ui.ManagePermissionsActivity
import com.android.permissioncontroller.permission.ui.auto.AutoDividerPreference
-import com.android.permissioncontroller.permission.ui.legacy.PermissionUsageDetailsViewModelFactoryLegacy
-import com.android.permissioncontroller.permission.ui.legacy.PermissionUsageDetailsViewModelLegacy
+import com.android.permissioncontroller.permission.ui.model.v31.BasePermissionUsageDetailsViewModel
+import com.android.permissioncontroller.permission.ui.model.v31.PermissionUsageDetailsViewModel
+import com.android.permissioncontroller.permission.ui.model.v31.PermissionUsageDetailsViewModel.AppPermissionAccessUiInfo
import com.android.permissioncontroller.permission.utils.KotlinUtils.getPermGroupLabel
-import com.android.permissioncontroller.permission.utils.Utils
import java.time.Clock
import java.time.Instant
import java.time.ZoneId
@@ -54,9 +47,7 @@ import java.time.temporal.ChronoUnit
import java.util.concurrent.atomic.AtomicReference
@RequiresApi(Build.VERSION_CODES.S)
-class AutoPermissionUsageDetailsFragment :
- AutoSettingsFrameFragment(), PermissionsUsagesChangeCallback {
-
+class AutoPermissionUsageDetailsFragment : AutoSettingsFrameFragment() {
companion object {
private const val LOG_TAG = "AutoPermissionUsageDetailsFragment"
private const val KEY_SESSION_ID = "_session_id"
@@ -70,14 +61,11 @@ class AutoPermissionUsageDetailsFragment :
.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]. */
fun newInstance(
groupName: String?,
showSystem: Boolean,
- sessionId: Long
+ sessionId: Long,
): AutoPermissionUsageDetailsFragment {
return AutoPermissionUsageDetailsFragment().apply {
arguments =
@@ -92,14 +80,10 @@ class AutoPermissionUsageDetailsFragment :
private val SESSION_ID_KEY = (AutoPermissionUsageFragment::class.java.name + KEY_SESSION_ID)
- private lateinit var permissionUsages: PermissionUsages
- private lateinit var usageViewModel: PermissionUsageDetailsViewModelLegacy
+ private lateinit var usageViewModel: BasePermissionUsageDetailsViewModel
private lateinit var filterGroup: String
- private lateinit var roleManager: RoleManager
- private var appPermissionUsages: List<AppPermissionUsage> = listOf()
private var showSystem = false
- private var finishedInitialLoad = false
private var hasSystemApps = false
/** Unique Id of a request */
@@ -116,7 +100,7 @@ class AutoPermissionUsageDetailsFragment :
!requireArguments().containsKey(Intent.EXTRA_PERMISSION_GROUP_NAME) or
(requireArguments().getString(Intent.EXTRA_PERMISSION_GROUP_NAME) == null)
) {
- DumpableLog.e(LOG_TAG, "Missing argument ${Intent.EXTRA_USER}")
+ DumpableLog.e(LOG_TAG, "Missing argument ${Intent.EXTRA_PERMISSION_GROUP_NAME}")
activity?.finish()
return
}
@@ -130,28 +114,21 @@ class AutoPermissionUsageDetailsFragment :
headerLabel =
resources.getString(
R.string.permission_group_usage_title,
- getPermGroupLabel(requireContext(), filterGroup)
+ getPermGroupLabel(requireContext(), filterGroup),
)
-
- val context = preferenceManager.getContext()
- permissionUsages = PermissionUsages(context)
- roleManager = Utils.getSystemServiceSafe(context, RoleManager::class.java)
- val usageViewModelFactory =
- PermissionUsageDetailsViewModelFactoryLegacy(
+ val factory =
+ PermissionUsageDetailsViewModel.PermissionUsageDetailsViewModelFactory(
PermissionControllerApplication.get(),
- roleManager,
+ this,
filterGroup,
- sessionId
)
usageViewModel =
- ViewModelProvider(this, usageViewModelFactory)[
- PermissionUsageDetailsViewModelLegacy::class.java]
-
- reloadData()
+ ViewModelProvider(this, factory)[BasePermissionUsageDetailsViewModel::class.java]
+ usageViewModel.getPermissionUsagesDetailsInfoUiLiveData().observe(this, this::updateUI)
}
override fun onCreatePreferences(bundlle: Bundle?, s: String?) {
- preferenceScreen = preferenceManager.createPreferenceScreen(context!!)
+ preferenceScreen = preferenceManager.createPreferenceScreen(requireContext())
}
private fun setupHeaderPreferences() {
@@ -161,38 +138,16 @@ class AutoPermissionUsageDetailsFragment :
preferenceScreen.addPreference(AutoDividerPreference(context))
}
- /** Reloads the data to show. */
- private fun reloadData() {
- usageViewModel.loadPermissionUsages(
- requireActivity().getLoaderManager(),
- permissionUsages,
- this,
- FILTER_24_HOURS
- )
- if (finishedInitialLoad) {
- setLoading(true)
- }
- }
-
- override fun onPermissionUsagesChanged() {
- if (permissionUsages.usages.isEmpty()) {
- return
- }
- appPermissionUsages = ArrayList(permissionUsages.usages)
- updateUI()
- }
-
private fun updateSystemToggle() {
if (!showSystem) {
PermissionControllerStatsLog.write(
PERMISSION_USAGE_FRAGMENT_INTERACTION,
sessionId,
- PERMISSION_USAGE_FRAGMENT_INTERACTION__ACTION__SHOW_SYSTEM_CLICKED
+ PERMISSION_USAGE_FRAGMENT_INTERACTION__ACTION__SHOW_SYSTEM_CLICKED,
)
}
showSystem = !showSystem
updateAction()
- updateUI()
}
private fun updateAction() {
@@ -206,47 +161,36 @@ class AutoPermissionUsageDetailsFragment :
} else {
getString(R.string.menu_show_system)
}
- setAction(label) { updateSystemToggle() }
+ setAction(label) {
+ usageViewModel.updateShowSystemAppsToggle(!showSystem)
+ updateSystemToggle()
+ }
}
- private fun updateUI() {
- if (appPermissionUsages.isEmpty()) {
+ private fun updateUI(uiInfo: PermissionUsageDetailsViewModel.PermissionUsageDetailsUiState) {
+ if (
+ activity == null ||
+ uiInfo is PermissionUsageDetailsViewModel.PermissionUsageDetailsUiState.Loading
+ ) {
return
}
preferenceScreen.removeAll()
setupHeaderPreferences()
-
- val uiData =
- usageViewModel.buildPermissionUsageDetailsUiData(
- appPermissionUsages,
- showSystem,
- SHOW_7_DAYS
- )
-
- if (hasSystemApps != uiData.shouldDisplayShowSystemToggle) {
- hasSystemApps = uiData.shouldDisplayShowSystemToggle
+ val uiData = uiInfo as PermissionUsageDetailsViewModel.PermissionUsageDetailsUiState.Success
+ if (hasSystemApps != uiData.containsSystemAppUsage) {
+ hasSystemApps = uiData.containsSystemAppUsage
updateAction()
}
-
val category = AtomicReference(PreferenceCategory(requireContext()))
preferenceScreen.addPreference(category.get())
- AppDataLoader(context) {
- renderHistoryPreferences(
- uiData.getHistoryPreferenceDataList(),
- category,
- preferenceScreen
- )
+ renderHistoryPreferences(uiData.appPermissionAccessUiInfoList, category, preferenceScreen)
- setLoading(false)
- finishedInitialLoad = true
- permissionUsages.stopLoader(requireActivity().getLoaderManager())
- }
- .execute(*uiData.permissionApps.toTypedArray())
+ setLoading(false)
}
fun createPermissionHistoryPreference(
- historyPreferenceData: PermissionUsageDetailsViewModelLegacy.HistoryPreferenceData
+ historyPreferenceData: AppPermissionAccessUiInfo
): Preference {
return AutoPermissionHistoryPreference(requireContext(), historyPreferenceData)
}
@@ -257,7 +201,7 @@ class AutoPermissionUsageDetailsFragment :
summary =
getString(
R.string.permission_group_usage_subtitle_24h,
- getPermGroupLabel(requireContext(), filterGroup)
+ getPermGroupLabel(requireContext(), filterGroup),
)
isSelectable = false
}
@@ -271,7 +215,7 @@ class AutoPermissionUsageDetailsFragment :
summary =
getString(
R.string.manage_permission_summary,
- getPermGroupLabel(requireContext(), filterGroup)
+ getPermGroupLabel(requireContext(), filterGroup),
)
onPreferenceClickListener =
Preference.OnPreferenceClickListener {
@@ -287,9 +231,8 @@ class AutoPermissionUsageDetailsFragment :
}
/** Render the provided [historyPreferenceDataList] into the [preferenceScreen] UI. */
- fun renderHistoryPreferences(
- historyPreferenceDataList:
- List<PermissionUsageDetailsViewModelLegacy.HistoryPreferenceData>,
+ private fun renderHistoryPreferences(
+ historyPreferenceDataList: List<AppPermissionAccessUiInfo>,
category: AtomicReference<PreferenceCategory>,
preferenceScreen: PreferenceScreen,
) {
@@ -299,7 +242,7 @@ class AutoPermissionUsageDetailsFragment :
val currentDateMs =
ZonedDateTime.ofInstant(
Instant.ofEpochMilli(usageTimestamp),
- Clock.system(ZoneId.systemDefault()).zone
+ Clock.system(ZoneId.systemDefault()).zone,
)
.truncatedTo(ChronoUnit.DAYS)
.toEpochSecond() * 1000L
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 9f39bd785..36d867b11 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
@@ -46,7 +46,7 @@ class AutoPermissionUsageFragment : AutoSettingsFrameFragment() {
Manifest.permission_group.CAMERA,
1,
Manifest.permission_group.MICROPHONE,
- 2
+ 2,
)
private const val DEFAULT_ORDER: Int = 3
}
@@ -54,7 +54,6 @@ class AutoPermissionUsageFragment : AutoSettingsFrameFragment() {
private val SESSION_ID_KEY = (AutoPermissionUsageFragment::class.java.name + KEY_SESSION_ID)
private var showSystem = false
- private var finishedInitialLoad = false
private var hasSystemApps = false
/** Unique Id of a request */
@@ -89,7 +88,7 @@ class AutoPermissionUsageFragment : AutoSettingsFrameFragment() {
PermissionControllerStatsLog.write(
PERMISSION_USAGE_FRAGMENT_INTERACTION,
sessionId,
- PERMISSION_USAGE_FRAGMENT_INTERACTION__ACTION__SHOW_SYSTEM_CLICKED
+ PERMISSION_USAGE_FRAGMENT_INTERACTION__ACTION__SHOW_SYSTEM_CLICKED,
)
}
showSystem = !showSystem
@@ -133,13 +132,13 @@ class AutoPermissionUsageFragment : AutoSettingsFrameFragment() {
Comparator.comparing { permissionGroupWithUsageCount: Map.Entry<String, Int> ->
PERMISSION_GROUP_ORDER.getOrDefault(
permissionGroupWithUsageCount.key,
- DEFAULT_ORDER
+ DEFAULT_ORDER,
)
}
.thenComparing { permissionGroupWithUsageCount: Map.Entry<String, Int> ->
mViewModel.getPermissionGroupLabel(
requireContext(),
- permissionGroupWithUsageCount.key
+ permissionGroupWithUsageCount.key,
)
}
)
@@ -153,11 +152,10 @@ class AutoPermissionUsageFragment : AutoSettingsFrameFragment() {
permissionGroupWithUsageCountsEntries[i].value,
showSystem,
sessionId,
- false
+ false,
)
getPreferenceScreen().addPreference(permissionUsagePreference)
}
- finishedInitialLoad = true
setLoading(false)
}
}
diff --git a/PermissionController/src/com/android/permissioncontroller/permission/ui/handheld/AppPermissionWrapperFragment.java b/PermissionController/src/com/android/permissioncontroller/permission/ui/handheld/AppPermissionWrapperFragment.java
index 8650d99fc..080c7cfdc 100644
--- a/PermissionController/src/com/android/permissioncontroller/permission/ui/handheld/AppPermissionWrapperFragment.java
+++ b/PermissionController/src/com/android/permissioncontroller/permission/ui/handheld/AppPermissionWrapperFragment.java
@@ -29,7 +29,7 @@ public class AppPermissionWrapperFragment extends PermissionsCollapsingToolbarBa
@NonNull
@Override
public PreferenceFragmentCompat createPreferenceFragment() {
- return AppPermissionFragmentCompat.createFragment();
+ return AppPermissionFragmentCompat.createFragment(getContext());
}
@Override
diff --git a/PermissionController/src/com/android/permissioncontroller/permission/ui/handheld/PermissionFooterPreference.kt b/PermissionController/src/com/android/permissioncontroller/permission/ui/handheld/PermissionFooterPreference.kt
index 1cd4ed23a..e7749d827 100644
--- a/PermissionController/src/com/android/permissioncontroller/permission/ui/handheld/PermissionFooterPreference.kt
+++ b/PermissionController/src/com/android/permissioncontroller/permission/ui/handheld/PermissionFooterPreference.kt
@@ -17,16 +17,21 @@
package com.android.permissioncontroller.permission.ui.handheld
import android.content.Context
+import android.util.AttributeSet
import android.view.View
import com.android.modules.utils.build.SdkLevel
import com.android.permissioncontroller.R
import com.android.settingslib.widget.FooterPreference
-class PermissionFooterPreference(c: Context) : FooterPreference(c) {
+class PermissionFooterPreference : FooterPreference {
+ constructor(context: Context) : super(context)
+
+ constructor(context: Context, attrs: AttributeSet?) : super(context, attrs)
+
init {
if (SdkLevel.isAtLeastV()) {
layoutResource = R.layout.permission_footer_preference
- if (c.resources.getBoolean(R.bool.config_permissionFooterPreferenceIconVisible)) {
+ if (context.resources.getBoolean(R.bool.config_permissionFooterPreferenceIconVisible)) {
setIconVisibility(View.VISIBLE)
} else {
setIconVisibility(View.GONE)
diff --git a/PermissionController/src/com/android/permissioncontroller/permission/ui/handheld/PermissionPreference.kt b/PermissionController/src/com/android/permissioncontroller/permission/ui/handheld/PermissionPreference.kt
index 5e30183ec..010ca28a7 100644
--- a/PermissionController/src/com/android/permissioncontroller/permission/ui/handheld/PermissionPreference.kt
+++ b/PermissionController/src/com/android/permissioncontroller/permission/ui/handheld/PermissionPreference.kt
@@ -18,15 +18,30 @@ package com.android.permissioncontroller.permission.ui.handheld
import android.content.Context
import android.util.AttributeSet
+import androidx.annotation.AttrRes
+import androidx.annotation.StyleRes
import androidx.preference.Preference
import com.android.modules.utils.build.SdkLevel
import com.android.permissioncontroller.DeviceUtils
import com.android.permissioncontroller.R
open class PermissionPreference : Preference {
- constructor(c: Context) : super(c)
+ constructor(context: Context) : super(context)
- constructor(c: Context, a: AttributeSet) : super(c, a)
+ constructor(context: Context, attrs: AttributeSet?) : super(context, attrs)
+
+ constructor(
+ context: Context,
+ attrs: AttributeSet?,
+ @AttrRes defStyleAttr: Int,
+ ) : super(context, attrs, defStyleAttr)
+
+ constructor(
+ context: Context,
+ attrs: AttributeSet?,
+ @AttrRes defStyleAttr: Int,
+ @StyleRes defStyleRes: Int,
+ ) : super(context, attrs, defStyleAttr, defStyleRes)
init {
if (SdkLevel.isAtLeastV() && DeviceUtils.isHandheld(context)) {
diff --git a/PermissionController/src/com/android/permissioncontroller/permission/ui/handheld/PermissionPreferenceCategory.kt b/PermissionController/src/com/android/permissioncontroller/permission/ui/handheld/PermissionPreferenceCategory.kt
index ef1752530..ef95c6c5c 100644
--- a/PermissionController/src/com/android/permissioncontroller/permission/ui/handheld/PermissionPreferenceCategory.kt
+++ b/PermissionController/src/com/android/permissioncontroller/permission/ui/handheld/PermissionPreferenceCategory.kt
@@ -18,15 +18,30 @@ package com.android.permissioncontroller.permission.ui.handheld
import android.content.Context
import android.util.AttributeSet
+import androidx.annotation.AttrRes
+import androidx.annotation.StyleRes
import androidx.preference.PreferenceCategory
import com.android.modules.utils.build.SdkLevel
import com.android.permissioncontroller.DeviceUtils
import com.android.permissioncontroller.R
open class PermissionPreferenceCategory : PreferenceCategory {
- constructor(c: Context) : super(c)
+ constructor(context: Context) : super(context)
- constructor(c: Context, a: AttributeSet) : super(c, a)
+ constructor(context: Context, attrs: AttributeSet?) : super(context, attrs)
+
+ constructor(
+ context: Context,
+ attrs: AttributeSet?,
+ @AttrRes defStyleAttr: Int,
+ ) : super(context, attrs, defStyleAttr)
+
+ constructor(
+ context: Context,
+ attrs: AttributeSet?,
+ @AttrRes defStyleAttr: Int,
+ @StyleRes defStyleRes: Int,
+ ) : super(context, attrs, defStyleAttr, defStyleRes)
init {
if (SdkLevel.isAtLeastV() && DeviceUtils.isHandheld(context)) {
diff --git a/PermissionController/src/com/android/permissioncontroller/permission/ui/handheld/max35/LegacyAppPermissionFragment.java b/PermissionController/src/com/android/permissioncontroller/permission/ui/handheld/max35/LegacyAppPermissionFragment.java
index e8ad9aae6..35650defb 100644
--- a/PermissionController/src/com/android/permissioncontroller/permission/ui/handheld/max35/LegacyAppPermissionFragment.java
+++ b/PermissionController/src/com/android/permissioncontroller/permission/ui/handheld/max35/LegacyAppPermissionFragment.java
@@ -105,7 +105,6 @@ import java.util.Objects;
import java.util.Optional;
import java.util.Set;
-
/**
* Show and manage a single permission group for an app.
*
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 4f8d69e5e..933911bff 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
@@ -160,7 +160,6 @@ public class PermissionHistoryPreference extends Preference {
mPermissionGroup,
mPackageName,
PERMISSION_DETAILS_INTERACTION__ACTION__TIMELINE_ROW_CLICKED);
- mContext.startActivityAsUser(intent, mUserHandle);
AlertDialog.Builder dialogBuilder = new AlertDialog.Builder(mContext)
.setTitle(R.string.privacy_dashboard_emergency_location_dialog_title)
.setMessage(
diff --git a/PermissionController/src/com/android/permissioncontroller/permission/ui/handheld/v35/SectionPreferenceGroupAdapter.kt b/PermissionController/src/com/android/permissioncontroller/permission/ui/handheld/v35/SectionPreferenceGroupAdapter.kt
index 72e066777..e5dce40b0 100644
--- a/PermissionController/src/com/android/permissioncontroller/permission/ui/handheld/v35/SectionPreferenceGroupAdapter.kt
+++ b/PermissionController/src/com/android/permissioncontroller/permission/ui/handheld/v35/SectionPreferenceGroupAdapter.kt
@@ -25,6 +25,7 @@ import androidx.preference.PreferenceGroup
import androidx.preference.PreferenceGroupAdapter
import androidx.preference.PreferenceViewHolder
import com.android.permissioncontroller.R
+import com.android.permissioncontroller.permission.ui.handheld.v36.AppPermissionFooterLinkPreference
import com.android.settingslib.widget.FooterPreference
/**
@@ -106,7 +107,10 @@ class SectionPreferenceGroupAdapter(preferenceGroup: PreferenceGroup) :
}
private val Preference.isSectionDivider: Boolean
- get() = this is PreferenceCategory || this is FooterPreference
+ get() =
+ this is PreferenceCategory ||
+ this is FooterPreference ||
+ this is AppPermissionFooterLinkPreference
override fun onBindViewHolder(holder: PreferenceViewHolder, position: Int) {
super.onBindViewHolder(holder, position)
diff --git a/PermissionController/src/com/android/permissioncontroller/permission/ui/handheld/v36/AppPermissionFooterLinkPreference.kt b/PermissionController/src/com/android/permissioncontroller/permission/ui/handheld/v36/AppPermissionFooterLinkPreference.kt
new file mode 100644
index 000000000..f5f511253
--- /dev/null
+++ b/PermissionController/src/com/android/permissioncontroller/permission/ui/handheld/v36/AppPermissionFooterLinkPreference.kt
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS 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.v36
+
+import android.content.Context
+import android.os.Build
+import android.util.AttributeSet
+import androidx.annotation.AttrRes
+import androidx.annotation.RequiresApi
+import androidx.annotation.StyleRes
+import com.android.permissioncontroller.R
+import com.android.permissioncontroller.permission.ui.handheld.PermissionPreference
+
+@RequiresApi(Build.VERSION_CODES.VANILLA_ICE_CREAM)
+class AppPermissionFooterLinkPreference : PermissionPreference {
+ constructor(context: Context) : super(context)
+
+ constructor(context: Context, attrs: AttributeSet?) : super(context, attrs)
+
+ constructor(
+ context: Context,
+ attrs: AttributeSet?,
+ @AttrRes defStyleAttr: Int,
+ ) : super(context, attrs, defStyleAttr)
+
+ constructor(
+ context: Context,
+ attrs: AttributeSet?,
+ @AttrRes defStyleAttr: Int,
+ @StyleRes defStyleRes: Int,
+ ) : super(context, attrs, defStyleAttr, defStyleRes)
+
+ init {
+ layoutResource = R.layout.app_permission_footer_link_preference
+ }
+}
diff --git a/PermissionController/src/com/android/permissioncontroller/permission/ui/handheld/v36/AppPermissionFragment.java b/PermissionController/src/com/android/permissioncontroller/permission/ui/handheld/v36/AppPermissionFragment.java
index 02a811bdd..4fde26c9d 100644
--- a/PermissionController/src/com/android/permissioncontroller/permission/ui/handheld/v36/AppPermissionFragment.java
+++ b/PermissionController/src/com/android/permissioncontroller/permission/ui/handheld/v36/AppPermissionFragment.java
@@ -62,20 +62,15 @@ import android.view.LayoutInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
-import android.widget.CompoundButton;
-import android.widget.FrameLayout;
-import android.widget.ImageView;
-import android.widget.RadioButton;
-import android.widget.Switch;
-import android.widget.TextView;
import android.widget.Toast;
import androidx.annotation.NonNull;
import androidx.annotation.RequiresApi;
import androidx.annotation.StringRes;
-import androidx.core.widget.NestedScrollView;
import androidx.fragment.app.DialogFragment;
import androidx.lifecycle.ViewModelProvider;
+import androidx.preference.Preference;
+import androidx.preference.TwoStatePreference;
import com.android.modules.utils.build.SdkLevel;
import com.android.permissioncontroller.R;
@@ -84,6 +79,10 @@ import com.android.permissioncontroller.permission.ui.GrantPermissionsViewHandle
import com.android.permissioncontroller.permission.ui.handheld.AllAppPermissionsFragment;
import com.android.permissioncontroller.permission.ui.handheld.AppPermissionGroupsFragment;
import com.android.permissioncontroller.permission.ui.handheld.PermissionAppsFragment;
+import com.android.permissioncontroller.permission.ui.handheld.PermissionFooterPreference;
+import com.android.permissioncontroller.permission.ui.handheld.PermissionPreference;
+import com.android.permissioncontroller.permission.ui.handheld.PermissionPreferenceCategory;
+import com.android.permissioncontroller.permission.ui.handheld.PermissionSwitchPreference;
import com.android.permissioncontroller.permission.ui.handheld.SettingsWithLargeHeader;
import com.android.permissioncontroller.permission.ui.model.AppPermissionViewModel;
import com.android.permissioncontroller.permission.ui.model.AppPermissionViewModel.ButtonState;
@@ -96,13 +95,12 @@ import com.android.permissioncontroller.permission.utils.Utils;
import com.android.permissioncontroller.permission.utils.v35.MultiDeviceUtils;
import com.android.settingslib.RestrictedLockUtils;
import com.android.settingslib.RestrictedLockUtils.EnforcedAdmin;
-import com.android.settingslib.widget.ActionBarShadowController;
+import com.android.settingslib.widget.SelectorWithWidgetPreference;
import kotlin.Pair;
import java.util.Map;
import java.util.Objects;
-import java.util.Optional;
import java.util.Set;
/**
@@ -120,26 +118,25 @@ public class AppPermissionFragment extends SettingsWithLargeHeader
private static final long EDIT_PHOTOS_BUTTON_ANIMATION_LENGTH_MS = 200L;
private @NonNull AppPermissionViewModel mViewModel;
- private @NonNull ViewGroup mAppPermissionRationaleContainer;
- private @NonNull ViewGroup mAppPermissionRationaleContent;
- private @NonNull FrameLayout mAllowButtonFrame;
- private @NonNull RadioButton mAllowButton;
- private @NonNull RadioButton mAllowAlwaysButton;
- private @NonNull RadioButton mAllowForegroundButton;
- private @NonNull RadioButton mAskOneTimeButton;
- private @NonNull RadioButton mAskButton;
- private @NonNull RadioButton mSelectButton;
- private @NonNull RadioButton mDenyButton;
- private @NonNull RadioButton mDenyForegroundButton;
- private @NonNull ImageView mEditSelectedPhotosButton;
- private @NonNull View mAllowLimitedPhotosLayout;
- private @NonNull View mSelectPhotosDivider;
- private @NonNull View mLocationAccuracy;
- private @NonNull Switch mLocationAccuracySwitch;
- private @NonNull View mDivider;
- private @NonNull ViewGroup mWidgetFrame;
- private @NonNull TextView mPermissionDetails;
- private @NonNull NestedScrollView mNestedScrollView;
+
+ private @NonNull PermissionPreferenceCategory mAppPermissionRationaleContainer;
+ private @NonNull PermissionPreference mAppPermissionRationaleContent;
+ private @NonNull PermissionPreferenceCategory mButtonCategory;
+ private @NonNull PermissionSelectorWithWidgetPreference mAllowButton;
+ private @NonNull SelectorWithWidgetPreference mAllowAlwaysButton;
+ private @NonNull SelectorWithWidgetPreference mAllowForegroundButton;
+ private @NonNull PermissionSelectorWithWidgetPreference mSelectButton;
+ private @NonNull SelectorWithWidgetPreference mAskOneTimeButton;
+ private @NonNull SelectorWithWidgetPreference mAskButton;
+ private @NonNull SelectorWithWidgetPreference mDenyButton;
+ private @NonNull SelectorWithWidgetPreference mDenyForegroundButton;
+ private @NonNull PermissionSwitchPreference mLocationAccuracySwitch;
+ private @NonNull PermissionTwoTargetPreference mDetails;
+ private @NonNull AppPermissionFooterLinkPreference mFooterLink1;
+ private @NonNull AppPermissionFooterLinkPreference mFooterLink2;
+ private @NonNull PermissionFooterPreference mFooterStorageSpecialAppAccess;
+ private @NonNull PermissionFooterPreference mAdditionalInfo;
+
private @NonNull String mPackageName;
private @NonNull String mPermGroupName;
private @NonNull UserHandle mUser;
@@ -202,20 +199,52 @@ public class AppPermissionFragment extends SettingsWithLargeHeader
if (mIsStorageGroup) {
mViewModel.getFullStorageStateLiveData().observe(this, this::setSpecialStorageState);
}
+ mViewModel.getShowPermissionRationaleLiveData().observe(this,
+ this::showPermissionRationaleDialog);
mRoleManager = Utils.getSystemServiceSafe(getContext(), RoleManager.class);
}
@Override
+ public void onCreatePreferences(Bundle bundle, String s) {
+ super.onCreatePreferences(bundle, s);
+ addPreferencesFromResource(R.xml.app_permission);
+
+ mAppPermissionRationaleContainer = requirePreference("app_permission_rationale_container");
+ mAppPermissionRationaleContent = requirePreference("app_permission_rationale");
+ mButtonCategory = requirePreference("app_permission_button_category");
+ mAllowButton = requirePreference("app_permission_allow_radio_button");
+ mAllowAlwaysButton = requirePreference("app_permission_allow_always_radio_button");
+ mAllowForegroundButton =
+ requirePreference("app_permission_allow_foreground_only_radio_button");
+ mSelectButton = requirePreference("app_permission_select_photos_radio_button");
+ mAskOneTimeButton = requirePreference("app_permission_ask_one_time_radio_button");
+ mAskButton = requirePreference("app_permission_ask_radio_button");
+ mDenyButton = requirePreference("app_permission_deny_radio_button");
+ mDenyForegroundButton = requirePreference("app_permission_deny_foreground_radio_button");
+ mLocationAccuracySwitch = requirePreference("app_permission_location_accuracy_switch");
+ mDetails = requirePreference("app_permission_details");
+ mFooterLink1 = requirePreference("app_permission_footer_link_1");
+ mFooterLink2 = requirePreference("app_permission_footer_link_2");
+ mFooterStorageSpecialAppAccess =
+ requirePreference("app_permission_footer_storage_special_app_access");
+ mAdditionalInfo = requirePreference("app_permission_additional_info");
+ }
+
+ @SuppressWarnings("TypeParameterUnusedInFormals")
+ private <T extends Preference> @NonNull T requirePreference(@NonNull CharSequence key) {
+ return Objects.requireNonNull(findPreference(key),
+ "Failed to find preference '" + key + "'");
+ }
+
+ @Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
Context context = getContext();
- ViewGroup root = (ViewGroup) inflater.inflate(R.layout.app_permission, container, false);
mIsInitialLoad = true;
setHeader(mPackageIcon, mPackageLabel, null, null, false);
- updateHeader(root.requireViewById(R.id.large_header));
String text = null;
if (MultiDeviceUtils.isDefaultDeviceId(mPersistentDeviceId)) {
@@ -225,87 +254,54 @@ public class AppPermissionFragment extends SettingsWithLargeHeader
text = context.getString(R.string.app_permission_header_with_device_name,
mPermGroupLabel, deviceName);
}
- ((TextView) root.requireViewById(R.id.permission_message)).setText(text);
+ mButtonCategory.setTitle(text);
+ mFooterLink1.setSummary(context.getString(
+ R.string.app_permission_footer_app_permissions_link, mPackageLabel));
String caller = getArguments().getString(EXTRA_CALLER_NAME);
+ setBottomLinkState(mFooterLink1, caller, Intent.ACTION_MANAGE_APP_PERMISSIONS);
- TextView footer1Link = root.requireViewById(R.id.footer_link_1);
- footer1Link.setText(context.getString(R.string.app_permission_footer_app_permissions_link,
- mPackageLabel));
- setBottomLinkState(footer1Link, caller, Intent.ACTION_MANAGE_APP_PERMISSIONS);
-
- TextView footer2Link = root.requireViewById(R.id.footer_link_2);
- footer2Link.setText(context.getString(R.string.app_permission_footer_permission_apps_link));
- setBottomLinkState(footer2Link, caller, Intent.ACTION_MANAGE_PERMISSION_APPS);
+ setBottomLinkState(mFooterLink2, caller, Intent.ACTION_MANAGE_PERMISSION_APPS);
Set<String> exemptedPackages = Utils.getExemptedPackages(mRoleManager);
- ImageView footerInfoIcon = root.requireViewById(R.id.app_additional_info_icon);
- TextView footerInfoText = root.requireViewById(R.id.app_additional_info_text);
if (exemptedPackages.contains(mPackageName)) {
int additional_info_label = Utils.isStatusBarIndicatorPermission(mPermGroupName)
? R.string.exempt_mic_camera_info_label : R.string.exempt_info_label;
- footerInfoText.setText(context.getString(additional_info_label, mPackageLabel));
- footerInfoIcon.setVisibility(View.VISIBLE);
- footerInfoText.setVisibility(View.VISIBLE);
+ mAdditionalInfo.setTitle(context.getString(additional_info_label, mPackageLabel));
+ mAdditionalInfo.setVisible(true);
} else {
- footerInfoIcon.setVisibility(View.GONE);
- footerInfoText.setVisibility(View.GONE);
+ mAdditionalInfo.setVisible(false);
}
- mAllowButtonFrame = root.requireViewById(R.id.allow_radio_button_frame);
- mAllowButton = root.requireViewById(R.id.allow_radio_button);
- mAllowAlwaysButton = root.requireViewById(R.id.allow_always_radio_button);
- 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);
- mSelectButton = root.requireViewById(R.id.select_radio_button);
- mDenyButton = root.requireViewById(R.id.deny_radio_button);
- mDenyForegroundButton = root.requireViewById(R.id.deny_foreground_radio_button);
-
- mDivider = root.requireViewById(R.id.two_target_divider);
- mWidgetFrame = root.requireViewById(R.id.widget_frame);
- mPermissionDetails = root.requireViewById(R.id.permission_details);
- mLocationAccuracy = root.requireViewById(R.id.location_accuracy);
- mLocationAccuracySwitch = root.requireViewById(R.id.location_accuracy_switch);
- mAllowLimitedPhotosLayout = root.requireViewById(R.id.radio_select_layout);
- mEditSelectedPhotosButton = root.requireViewById(R.id.edit_selected_button);
- mSelectPhotosDivider = root.requireViewById(R.id.edit_photos_divider);
- mNestedScrollView = root.requireViewById(R.id.nested_scroll_view);
-
if (mViewModel.getButtonStateLiveData().getValue() != null) {
setRadioButtonsState(mViewModel.getButtonStateLiveData().getValue());
} else {
- mAllowButton.setVisibility(View.GONE);
- mAllowAlwaysButton.setVisibility(View.GONE);
- mAllowForegroundButton.setVisibility(View.GONE);
- mAskOneTimeButton.setVisibility(View.GONE);
- mAskButton.setVisibility(View.GONE);
- mDenyButton.setVisibility(View.GONE);
- mDenyForegroundButton.setVisibility(View.GONE);
- mLocationAccuracy.setVisibility(View.GONE);
- mAllowLimitedPhotosLayout.setVisibility(View.GONE);
- mSelectPhotosDivider.setAlpha(0f);
- mEditSelectedPhotosButton.setAlpha(0f);
+ mAllowButton.setVisible(false);
+ mAllowAlwaysButton.setVisible(false);
+ mAllowForegroundButton.setVisible(false);
+ mAskOneTimeButton.setVisible(false);
+ mAskButton.setVisible(false);
+ mDenyButton.setVisible(false);
+ mDenyForegroundButton.setVisible(false);
+ mLocationAccuracySwitch.setVisible(false);
+ mSelectButton.setVisible(false);
+ mSelectButton.setExtraWidgetOnClickListener(null);
}
if (mViewModel.getFullStorageStateLiveData().isInitialized() && mIsStorageGroup) {
- setSpecialStorageState(mViewModel.getFullStorageStateLiveData().getValue(), root);
+ setSpecialStorageState(mViewModel.getFullStorageStateLiveData().getValue());
} else {
- TextView storageFooter = root.requireViewById(R.id.footer_storage_special_app_access);
- storageFooter.setVisibility(View.GONE);
+ mFooterStorageSpecialAppAccess.setVisible(false);
}
- 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));
- });
+
+ // Avoid an animation by showing this Preference immediately
+ showPermissionRationaleDialog(mViewModel.getShowPermissionRationaleLiveData().getValue());
getActivity().setTitle(
getPreferenceManager().getContext().getString(R.string.app_permission_title,
mPermGroupLabel));
- return root;
+
+ return super.onCreateView(inflater, container, savedInstanceState);
}
public void onResume() {
@@ -314,28 +310,32 @@ public class AppPermissionFragment extends SettingsWithLargeHeader
mPhotoPickerTriggered = false;
}
+ private void showPermissionRationaleDialog(Boolean showPermissionRationale) {
+ showPermissionRationaleDialog(showPermissionRationale == Boolean.TRUE);
+ }
+
private void showPermissionRationaleDialog(boolean showPermissionRationale) {
if (!showPermissionRationale) {
- mAppPermissionRationaleContainer.setVisibility(View.GONE);
+ mAppPermissionRationaleContainer.setVisible(false);
} else {
- mAppPermissionRationaleContainer.setVisibility(View.VISIBLE);
- mAppPermissionRationaleContent.setOnClickListener((v) -> {
- if (!SdkLevel.isAtLeastU()) {
- return;
+ mAppPermissionRationaleContainer.setVisible(true);
+ mAppPermissionRationaleContent.setOnPreferenceClickListener((v) -> {
+ if (SdkLevel.isAtLeastU()) {
+ mViewModel.showPermissionRationaleActivity(getActivity(), mPermGroupName);
}
- mViewModel.showPermissionRationaleActivity(getActivity(), mPermGroupName);
+ return true;
});
}
}
- private void setBottomLinkState(TextView view, String caller, String action) {
+ private void setBottomLinkState(Preference preference, String caller, String action) {
if ((Objects.equals(caller, AppPermissionGroupsFragment.class.getName())
&& action.equals(Intent.ACTION_MANAGE_APP_PERMISSIONS))
|| (Objects.equals(caller, PermissionAppsFragment.class.getName())
&& action.equals(Intent.ACTION_MANAGE_PERMISSION_APPS))) {
- view.setVisibility(View.GONE);
+ preference.setVisible(false);
} else {
- view.setOnClickListener((v) -> {
+ preference.setOnPreferenceClickListener((v) -> {
Bundle args;
if (action.equals(Intent.ACTION_MANAGE_APP_PERMISSIONS)) {
args = AppPermissionGroupsFragment.createArgs(mPackageName, mUser,
@@ -344,26 +344,11 @@ public class AppPermissionFragment extends SettingsWithLargeHeader
args = PermissionAppsFragment.createArgs(mPermGroupName, mSessionId);
}
mViewModel.showBottomLinkPage(this, action, args);
+ return true;
});
}
}
- private void setSpecialStorageState(FullStoragePackageState storageState) {
- setSpecialStorageState(storageState, getView());
- }
-
- @Override
- public void onStart() {
- super.onStart();
-
- ActionBar ab = getActivity().getActionBar();
- if (ab != null) {
- ab.setElevation(0);
- }
-
- ActionBarShadowController.attachToView(getActivity(), getLifecycle(), mNestedScrollView);
- }
-
@Override
public boolean onOptionsItemSelected(MenuItem item) {
if (item.getItemId() == android.R.id.home) {
@@ -384,7 +369,13 @@ public class AppPermissionFragment extends SettingsWithLargeHeader
} else if (states == null) {
return;
}
- mAllowButtonFrame.setOnClickListener((v) -> allowButtonFrameClickListener());
+
+ mAllowButton.setOnClickListener((v) -> {
+ allowButtonFrameClickListener();
+ });
+ mAllowButton.setOnDisabledClickListener((v) -> {
+ allowButtonFrameClickListener();
+ });
mAllowAlwaysButton.setOnClickListener((v) -> {
markSingleButtonAsChecked(ButtonType.ALLOW_ALWAYS);
if (mIsStorageGroup) {
@@ -426,13 +417,21 @@ public class AppPermissionFragment extends SettingsWithLargeHeader
mViewModel.requestChange(false, this, this, ChangeRequest.PHOTOS_SELECTED,
buttonPressed);
});
- mEditSelectedPhotosButton.setOnClickListener((v) -> {
- ButtonState selectState = states.get(ButtonType.SELECT_PHOTOS);
- if (selectState != null && selectState.isChecked() && !mPhotoPickerTriggered) {
- mPhotoPickerTriggered = true;
- mViewModel.openPhotoPicker(this);
- }
- });
+
+ if (isButtonChecked(states, ButtonType.SELECT_PHOTOS)) {
+ // Show the clickable extra widget
+ // TODO(b/366269715): make the widget show/hide via animation
+ mSelectButton.setExtraWidgetOnClickListener((v) -> {
+ if (isButtonChecked(states, ButtonType.SELECT_PHOTOS) && !mPhotoPickerTriggered) {
+ mPhotoPickerTriggered = true;
+ mViewModel.openPhotoPicker(this);
+ }
+ });
+ } else {
+ // Hide the clickable extra widget
+ mSelectButton.setExtraWidgetOnClickListener(null);
+ }
+
mDenyButton.setOnClickListener((v) -> {
markSingleButtonAsChecked(ButtonType.DENY);
if (mViewModel.getFullStorageStateLiveData().getValue() != null
@@ -454,15 +453,17 @@ public class AppPermissionFragment extends SettingsWithLargeHeader
APP_PERMISSION_FRAGMENT_ACTION_REPORTED__BUTTON_PRESSED__GRANT_FINE_LOCATION;
int revokeFineLocation =
APP_PERMISSION_FRAGMENT_ACTION_REPORTED__BUTTON_PRESSED__REVOKE_FINE_LOCATION;
- mLocationAccuracy.setOnClickListener((v) -> {
- mLocationAccuracySwitch.performClick();
- if (mLocationAccuracySwitch.isChecked()) {
+
+ mLocationAccuracySwitch.setOnPreferenceChangeListener((pref, newValue) -> {
+ if ((Boolean) newValue) {
mViewModel.requestChange(false, this, this, ChangeRequest.GRANT_FINE_LOCATION,
grantFineLocation);
} else {
mViewModel.requestChange(false, this, this, ChangeRequest.REVOKE_FINE_LOCATION,
revokeFineLocation);
}
+ // Don't actually toggle the switch yet. (Allow livedata observer to do so.)
+ return false;
});
setButtonState(mAllowButton, states.get(ButtonType.ALLOW));
@@ -473,23 +474,13 @@ public class AppPermissionFragment extends SettingsWithLargeHeader
setButtonState(mDenyButton, states.get(ButtonType.DENY));
setButtonState(mDenyForegroundButton, states.get(ButtonType.DENY_FOREGROUND));
setButtonState(mSelectButton, states.get(ButtonType.SELECT_PHOTOS));
- if (mSelectButton.getVisibility() == View.VISIBLE) {
- mAllowButton.setText(R.string.app_permission_button_always_allow_all);
+ if (mSelectButton.isVisible()) {
+ mAllowButton.setTitle(R.string.app_permission_button_always_allow_all);
} else {
- mAllowButton.setText(R.string.app_permission_button_allow);
+ mAllowButton.setTitle(R.string.app_permission_button_allow);
}
- ButtonState locationAccuracyState = states.get(ButtonType.LOCATION_ACCURACY);
- if (!locationAccuracyState.isShown()) {
- mLocationAccuracy.setVisibility(View.GONE);
- } else {
- mLocationAccuracy.setVisibility(View.VISIBLE);
- }
- mLocationAccuracySwitch.setChecked(locationAccuracyState.isChecked());
- if (!locationAccuracyState.isEnabled()) {
- mLocationAccuracy.setEnabled(false);
- mLocationAccuracySwitch.setEnabled(false);
- }
+ setButtonState(mLocationAccuracySwitch, states.get(ButtonType.LOCATION_ACCURACY));
mIsInitialLoad = false;
@@ -509,60 +500,38 @@ public class AppPermissionFragment extends SettingsWithLargeHeader
}
}
- private void setButtonState(CompoundButton button, AppPermissionViewModel.ButtonState state) {
- int visible = state.isShown() ? View.VISIBLE : View.GONE;
- button.setVisibility(visible);
- if (state.isShown()) {
- button.setChecked(state.isChecked());
- button.setEnabled(state.isEnabled());
- }
- if (mIsInitialLoad) {
- button.jumpDrawablesToCurrentState();
- }
-
- if (button == mSelectButton) {
- mAllowLimitedPhotosLayout.setVisibility(visible);
- float endOpacity = state.isChecked() ? 1f : 0f;
- // On initial load, do not show the fade in/out animation
- if (mIsInitialLoad) {
- mSelectPhotosDivider.setAlpha(endOpacity);
- mEditSelectedPhotosButton.setAlpha(endOpacity);
- return;
- }
- mEditSelectedPhotosButton.animate().alpha(endOpacity)
- .setDuration(EDIT_PHOTOS_BUTTON_ANIMATION_LENGTH_MS);
- mSelectPhotosDivider.animate().alpha(endOpacity)
- .setDuration(EDIT_PHOTOS_BUTTON_ANIMATION_LENGTH_MS);
- }
+ private void setButtonState(TwoStatePreference button,
+ AppPermissionViewModel.ButtonState state) {
+ button.setVisible(state.isShown());
+ button.setChecked(state.isChecked());
+ button.setEnabled(state.isEnabled());
}
- private void setSpecialStorageState(FullStoragePackageState storageState, View v) {
- if (v == null) {
- return;
- }
+ private boolean isButtonChecked(Map<ButtonType, ButtonState> state, ButtonType button) {
+ return state.containsKey(button) && state.get(button).isChecked();
+ }
- TextView textView = v.requireViewById(R.id.footer_storage_special_app_access);
- if (mAllowButton == null || !mIsStorageGroup) {
- textView.setVisibility(View.GONE);
+ private void setSpecialStorageState(FullStoragePackageState storageState) {
+ if (!mAllowButton.isVisible() || !mIsStorageGroup) {
+ mFooterStorageSpecialAppAccess.setVisible(false);
return;
}
- mAllowAlwaysButton.setText(R.string.app_permission_button_allow_all_files);
- mAllowForegroundButton.setText(R.string.app_permission_button_allow_media_only);
+ mAllowAlwaysButton.setTitle(R.string.app_permission_button_allow_all_files);
+ mAllowForegroundButton.setTitle(R.string.app_permission_button_allow_media_only);
if (storageState == null) {
- textView.setVisibility(View.GONE);
+ mFooterStorageSpecialAppAccess.setVisible(false);
return;
}
if (storageState.isLegacy()) {
- mAllowButton.setText(R.string.app_permission_button_allow_all_files);
- textView.setVisibility(View.GONE);
+ mAllowButton.setTitle(R.string.app_permission_button_allow_all_files);
+ mFooterStorageSpecialAppAccess.setVisible(false);
return;
}
- textView.setText(R.string.app_permission_footer_special_file_access);
- textView.setVisibility(View.VISIBLE);
+ mFooterStorageSpecialAppAccess.setVisible(true);
}
private void setResult(@GrantPermissionsViewHandler.Result int result) {
@@ -578,53 +547,37 @@ public class AppPermissionFragment extends SettingsWithLargeHeader
private void setDetail(Pair<Integer, Integer> detailResIds) {
if (detailResIds == null) {
- mWidgetFrame.setVisibility(View.GONE);
- mDivider.setVisibility(View.GONE);
+ mDetails.setOnSecondTargetClickListener(null);
return;
}
- mWidgetFrame.setVisibility(View.VISIBLE);
if (detailResIds.getSecond() != null) {
// If the permissions are individually controlled, also show a link to the page that
// lets you control them.
- mDivider.setVisibility(View.VISIBLE);
- showRightIcon(R.drawable.ic_settings);
+ mDetails.setExtraWidgetIconRes(R.drawable.ic_settings);
Bundle args = AllAppPermissionsFragment.createArgs(mPackageName, mPermGroupName, mUser);
- mWidgetFrame.setOnClickListener(v -> mViewModel.showAllPermissions(this, args));
- mPermissionDetails.setText(getPreferenceManager().getContext().getString(
+ mDetails.setOnSecondTargetClickListener((v) ->
+ mViewModel.showAllPermissions(this, args));
+ mDetails.setSummary(getPreferenceManager().getContext().getString(
detailResIds.getFirst(), detailResIds.getSecond()));
} else {
- mPermissionDetails.setText(getPreferenceManager().getContext().getString(
+ mDetails.setOnSecondTargetClickListener(null);
+ mDetails.setSummary(getPreferenceManager().getContext().getString(
detailResIds.getFirst()));
}
- mPermissionDetails.setVisibility(View.VISIBLE);
-
+ mDetails.setVisible(true);
}
private void setAdminSupportDetail(EnforcedAdmin admin) {
if (admin != null) {
- showRightIcon(R.drawable.ic_info);
- mWidgetFrame.setOnClickListener(v ->
- RestrictedLockUtils.sendShowAdminSupportDetailsIntent(getContext(), admin)
- );
+ mDetails.setExtraWidgetIconRes(R.drawable.ic_info_outline);
+ mDetails.setOnSecondTargetClickListener((v) ->
+ RestrictedLockUtils.sendShowAdminSupportDetailsIntent(getContext(), admin));
} else {
- mWidgetFrame.removeAllViews();
+ mDetails.setOnSecondTargetClickListener(null);
}
}
/**
- * Show the given icon on the right of the first radio button.
- *
- * @param iconId the resourceId of the drawable to use.
- */
- private void showRightIcon(int iconId) {
- mWidgetFrame.removeAllViews();
- ImageView imageView = new ImageView(getPreferenceManager().getContext());
- imageView.setImageResource(iconId);
- mWidgetFrame.addView(imageView);
- mWidgetFrame.setVisibility(View.VISIBLE);
- }
-
- /**
* Show a dialog that warns the users that they are about to revoke permissions that were
* granted by default, or that they are about to grant full file access to an app.
*
diff --git a/PermissionController/src/com/android/permissioncontroller/permission/ui/handheld/v36/PermissionSelectorWithWidgetPreference.kt b/PermissionController/src/com/android/permissioncontroller/permission/ui/handheld/v36/PermissionSelectorWithWidgetPreference.kt
new file mode 100644
index 000000000..1574eaba3
--- /dev/null
+++ b/PermissionController/src/com/android/permissioncontroller/permission/ui/handheld/v36/PermissionSelectorWithWidgetPreference.kt
@@ -0,0 +1,103 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS 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.v36
+
+import android.content.Context
+import android.os.Build
+import android.util.AttributeSet
+import android.widget.ImageView
+import androidx.annotation.AttrRes
+import androidx.annotation.DrawableRes
+import androidx.annotation.IdRes
+import androidx.annotation.RequiresApi
+import androidx.preference.PreferenceViewHolder
+import com.android.permissioncontroller.R
+import com.android.permissioncontroller.permission.utils.ResourceUtils
+import com.android.settingslib.widget.SelectorWithWidgetPreference
+
+/**
+ * A `SelectorWithWidgetPreference` with additional features:
+ * - Propagates the supplied `app:extraWidgetIcon` drawable to the extraWidget
+ * - Propagates the supplied `app:extraWidgetId` id to the extraWidget (the icon on the right)
+ * - Propagates the supplied `app:checkboxId` id to the checkbox (or radio button, on the left)
+ * - Allows defining a "disabled click listener" handler that handles clicks when disabled
+ */
+@RequiresApi(Build.VERSION_CODES.VANILLA_ICE_CREAM)
+class PermissionSelectorWithWidgetPreference : SelectorWithWidgetPreference {
+ constructor(context: Context) : super(context) {
+ init(context, null)
+ }
+
+ constructor(context: Context, attrs: AttributeSet?) : super(context, attrs) {
+ init(context, attrs)
+ }
+
+ constructor(
+ context: Context,
+ attrs: AttributeSet?,
+ @AttrRes defStyleAttr: Int,
+ ) : super(context, attrs, defStyleAttr) {
+ init(context, attrs)
+ }
+
+ constructor(context: Context, isCheckbox: Boolean) : super(context, isCheckbox) {
+ init(context, null)
+ }
+
+ private fun init(context: Context, attrs: AttributeSet?) {
+ layoutResource = R.layout.permission_preference_selector_with_widget
+ widgetLayoutResource = R.layout.permission_preference_widget_radiobutton
+ extraWidgetIconRes =
+ ResourceUtils.getResourceIdByAttr(context, attrs, R.attr.extraWidgetIcon)
+ extraWidgetIdRes = ResourceUtils.getResourceIdByAttr(context, attrs, R.attr.extraWidgetId)
+ checkboxIdRes = ResourceUtils.getResourceIdByAttr(context, attrs, R.attr.checkboxId)
+ }
+
+ @DrawableRes private var extraWidgetIconRes = 0
+ @IdRes private var extraWidgetIdRes = 0
+ @IdRes private var checkboxIdRes = 0
+ private var onDisabledClickListener: OnClickListener? = null
+
+ override fun onBindViewHolder(holder: PreferenceViewHolder) {
+ super.onBindViewHolder(holder)
+ val extraWidget =
+ holder.findViewById(
+ com.android.settingslib.widget.preference.selector.R.id.selector_extra_widget
+ ) as? ImageView
+ val checkbox = holder.findViewById(android.R.id.checkbox)
+ if (extraWidgetIconRes != 0) {
+ extraWidget?.setImageResource(extraWidgetIconRes)
+ }
+ if (extraWidgetIdRes != 0) {
+ extraWidget?.id = extraWidgetIdRes
+ }
+ if (checkboxIdRes != 0) {
+ checkbox?.id = checkboxIdRes
+ }
+ if (onDisabledClickListener != null) {
+ holder.itemView.isEnabled = true
+ holder.itemView.setOnClickListener {
+ onDisabledClickListener?.onRadioButtonClicked(this)
+ }
+ }
+ }
+
+ fun setOnDisabledClickListener(onClickListener: OnClickListener?) {
+ onDisabledClickListener = onClickListener
+ notifyChanged()
+ }
+}
diff --git a/PermissionController/src/com/android/permissioncontroller/permission/ui/handheld/v36/PermissionTwoTargetPreference.kt b/PermissionController/src/com/android/permissioncontroller/permission/ui/handheld/v36/PermissionTwoTargetPreference.kt
new file mode 100644
index 000000000..cf6585f4d
--- /dev/null
+++ b/PermissionController/src/com/android/permissioncontroller/permission/ui/handheld/v36/PermissionTwoTargetPreference.kt
@@ -0,0 +1,105 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS 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.v36
+
+import android.content.Context
+import android.os.Build
+import android.util.AttributeSet
+import android.widget.ImageView
+import androidx.annotation.AttrRes
+import androidx.annotation.DrawableRes
+import androidx.annotation.RequiresApi
+import androidx.annotation.StyleRes
+import androidx.preference.PreferenceViewHolder
+import com.android.permissioncontroller.R
+import com.android.permissioncontroller.permission.utils.ResourceUtils
+import com.android.settingslib.widget.TwoTargetPreference
+
+/**
+ * A `TwoTargetPreference` with additional features:
+ * - Propagates the supplied `app:extraWidgetIcon` drawable to the second target
+ * - Allows defining a click listener on the second target (the icon on the right)
+ */
+@RequiresApi(Build.VERSION_CODES.VANILLA_ICE_CREAM)
+class PermissionTwoTargetPreference : TwoTargetPreference {
+ constructor(context: Context) : super(context) {
+ init(context, null)
+ }
+
+ constructor(context: Context, attrs: AttributeSet?) : super(context, attrs) {
+ init(context, attrs)
+ }
+
+ constructor(
+ context: Context,
+ attrs: AttributeSet?,
+ @AttrRes defStyleAttr: Int,
+ ) : super(context, attrs, defStyleAttr) {
+ init(context, attrs)
+ }
+
+ constructor(
+ context: Context,
+ attrs: AttributeSet?,
+ @AttrRes defStyleAttr: Int,
+ @StyleRes defStyleRes: Int,
+ ) : super(context, attrs, defStyleAttr, defStyleRes) {
+ init(context, attrs)
+ }
+
+ private fun init(context: Context, attrs: AttributeSet?) {
+ layoutResource = R.layout.permission_preference_two_target
+ extraWidgetIconRes =
+ ResourceUtils.getResourceIdByAttr(context, attrs, R.attr.extraWidgetIcon)
+ }
+
+ @DrawableRes private var extraWidgetIconRes = 0
+ private var secondTargetClickListener: OnSecondTargetClickListener? = null
+
+ override fun onBindViewHolder(holder: PreferenceViewHolder) {
+ super.onBindViewHolder(holder)
+ val settingsButton = holder.findViewById(R.id.settings_button) as ImageView
+ if (extraWidgetIconRes != 0) {
+ settingsButton.setImageResource(extraWidgetIconRes)
+ }
+ if (secondTargetClickListener != null) {
+ settingsButton.setOnClickListener {
+ secondTargetClickListener!!.onSecondTargetClick(this)
+ }
+ } else {
+ settingsButton.setOnClickListener(null)
+ }
+ }
+
+ override fun getSecondTargetResId() = R.layout.settings_button_preference_widget
+
+ override fun shouldHideSecondTarget() = secondTargetClickListener == null
+
+ fun setOnSecondTargetClickListener(listener: OnSecondTargetClickListener?) {
+ secondTargetClickListener = listener
+ notifyChanged()
+ }
+
+ fun setExtraWidgetIconRes(@DrawableRes extraWidgetIconRes: Int) {
+ this.extraWidgetIconRes = extraWidgetIconRes
+ notifyChanged()
+ }
+
+ interface OnSecondTargetClickListener {
+ fun onSecondTargetClick(preference: TwoTargetPreference)
+ }
+}
diff --git a/PermissionController/src/com/android/permissioncontroller/permission/ui/legacy/PermissionUsageDetailsViewModelLegacy.kt b/PermissionController/src/com/android/permissioncontroller/permission/ui/legacy/PermissionUsageDetailsViewModelLegacy.kt
deleted file mode 100644
index 1369bfdaa..000000000
--- a/PermissionController/src/com/android/permissioncontroller/permission/ui/legacy/PermissionUsageDetailsViewModelLegacy.kt
+++ /dev/null
@@ -1,596 +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.
- */
-@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.getPackageLabel
-import com.android.permissioncontroller.permission.utils.PermissionMapping
-import com.android.permissioncontroller.permission.utils.StringUtils
-import com.android.permissioncontroller.permission.utils.Utils
-import com.android.permissioncontroller.permission.utils.v31.SubattributionUtils
-import java.time.Instant
-import java.util.concurrent.TimeUnit
-import java.util.concurrent.TimeUnit.DAYS
-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 (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> {
- val exemptedPackages = Utils.getExemptedPackages(roleManager)
- return appPermissionUsages
- .filter { !exemptedPackages.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/wear/elements/AnnotatedText.kt b/PermissionController/src/com/android/permissioncontroller/permission/ui/wear/elements/AnnotatedText.kt
index bcdf3b661..34c7cee9a 100644
--- a/PermissionController/src/com/android/permissioncontroller/permission/ui/wear/elements/AnnotatedText.kt
+++ b/PermissionController/src/com/android/permissioncontroller/permission/ui/wear/elements/AnnotatedText.kt
@@ -32,47 +32,70 @@ import androidx.compose.ui.text.TextStyle
import androidx.compose.ui.text.buildAnnotatedString
import androidx.compose.ui.text.style.TextDecoration
import androidx.wear.compose.material.MaterialTheme
+import com.android.permissioncontroller.permission.ui.wear.WearUtils.capitalize
const val CLICKABLE_SPAN_TAG = "CLICKABLE_SPAN_TAG"
@Composable
-fun AnnotatedText(text: CharSequence, style: TextStyle, modifier: Modifier = Modifier) {
+fun AnnotatedText(
+ text: CharSequence,
+ style: TextStyle,
+ modifier: Modifier = Modifier,
+ shouldCapitalize: Boolean
+) {
val onClickCallbacks = mutableMapOf<String, (View) -> Unit>()
val context = LocalContext.current
val listener = LinkInteractionListener {
if (it is LinkAnnotation.Clickable) {
- onClickCallbacks.get(it.tag)?.invoke(View(context))
+ onClickCallbacks[it.tag]?.invoke(View(context))
}
}
val annotatedString =
- spannableStringToAnnotatedString(text, onClickCallbacks, listener = listener)
+ spannableStringToAnnotatedString(
+ text,
+ shouldCapitalize,
+ onClickCallbacks,
+ listener = listener
+ )
BasicText(text = annotatedString, style = style, modifier = modifier)
}
@Composable
private fun spannableStringToAnnotatedString(
text: CharSequence,
+ shouldCapitalize: Boolean,
onClickCallbacks: MutableMap<String, (View) -> Unit>,
spanColor: Color = MaterialTheme.colors.primary,
listener: LinkInteractionListener
-) =
- if (text is Spanned) {
- buildAnnotatedString {
- append((text.toString()))
- for (span in text.getSpans(0, text.length, Any::class.java)) {
- val start = text.getSpanStart(span)
- val end = text.getSpanEnd(span)
- when (span) {
- is ClickableSpan ->
- addClickableSpan(span, spanColor, start, end, onClickCallbacks, listener)
- else -> addStyle(SpanStyle(), start, end)
+): AnnotatedString {
+ val finalString = if (shouldCapitalize) text.toString().capitalize() else text.toString()
+ val annotatedString =
+ if (text is Spanned) {
+ buildAnnotatedString {
+ append(finalString)
+ for (span in text.getSpans(0, text.length, Any::class.java)) {
+ val start = text.getSpanStart(span)
+ val end = text.getSpanEnd(span)
+ when (span) {
+ is ClickableSpan ->
+ addClickableSpan(
+ span,
+ spanColor,
+ start,
+ end,
+ onClickCallbacks,
+ listener
+ )
+ else -> addStyle(SpanStyle(), start, end)
+ }
}
}
+ } else {
+ AnnotatedString(text.toString())
}
- } else {
- AnnotatedString(text.toString())
- }
+ return annotatedString
+}
private fun AnnotatedString.Builder.addClickableSpan(
span: ClickableSpan,
diff --git a/PermissionController/src/com/android/permissioncontroller/permission/ui/wear/elements/ScrollableScreen.kt b/PermissionController/src/com/android/permissioncontroller/permission/ui/wear/elements/ScrollableScreen.kt
index 53013def7..d8f340a7b 100644
--- a/PermissionController/src/com/android/permissioncontroller/permission/ui/wear/elements/ScrollableScreen.kt
+++ b/PermissionController/src/com/android/permissioncontroller/permission/ui/wear/elements/ScrollableScreen.kt
@@ -282,6 +282,7 @@ internal fun Scaffold(
color = MaterialTheme.colors.onSurfaceVariant
),
modifier = modifier,
+ shouldCapitalize = true
)
}
}
diff --git a/PermissionController/src/com/android/permissioncontroller/permission/utils/ResourceUtils.kt b/PermissionController/src/com/android/permissioncontroller/permission/utils/ResourceUtils.kt
new file mode 100644
index 000000000..efe3361b1
--- /dev/null
+++ b/PermissionController/src/com/android/permissioncontroller/permission/utils/ResourceUtils.kt
@@ -0,0 +1,26 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.permissioncontroller.permission.utils
+import android.content.Context
+import android.util.AttributeSet
+import androidx.annotation.AttrRes
+import androidx.core.content.res.use
+
+object ResourceUtils {
+ fun getResourceIdByAttr(context: Context, attrs: AttributeSet?, @AttrRes attr: Int) =
+ context.obtainStyledAttributes(attrs, intArrayOf(attr)).use { it.getResourceId(0, 0) }
+}
diff --git a/PermissionController/tests/mocking/src/com/android/permissioncontroller/tests/mocking/hibernation/HibernationPolicyTest.kt b/PermissionController/tests/mocking/src/com/android/permissioncontroller/tests/mocking/hibernation/HibernationPolicyTest.kt
index 99aa4baa9..0d89e0501 100644
--- a/PermissionController/tests/mocking/src/com/android/permissioncontroller/tests/mocking/hibernation/HibernationPolicyTest.kt
+++ b/PermissionController/tests/mocking/src/com/android/permissioncontroller/tests/mocking/hibernation/HibernationPolicyTest.kt
@@ -16,19 +16,27 @@
package com.android.permissioncontroller.tests.mocking.hibernation
+import android.Manifest
import android.app.job.JobScheduler
+import android.content.ComponentName
import android.content.ContentResolver
import android.content.Context
import android.content.Intent
import android.content.SharedPreferences
+import android.content.pm.PackageManager
+import android.content.pm.PackageManager.PERMISSION_GRANTED
import android.database.ContentObserver
import android.net.Uri
+import android.os.Binder
import android.os.Build
import android.os.SystemClock
+import android.os.UserHandle
import android.os.UserManager
import android.preference.PreferenceManager
import android.provider.DeviceConfig
import android.provider.Settings
+import android.telecom.PhoneAccountHandle
+import android.telecom.TelecomManager
import androidx.test.core.app.ApplicationProvider
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SdkSuppress
@@ -37,12 +45,16 @@ 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_SYSTEM_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.PREF_KEY_SYSTEM_TIME_SNAPSHOT
import com.android.permissioncontroller.hibernation.SNAPSHOT_UNINITIALIZED
import com.android.permissioncontroller.hibernation.getStartTimeOfUnusedAppTracking
+import com.android.permissioncontroller.hibernation.isPackageHibernationExemptBySystem
+import com.android.permissioncontroller.permission.model.livedatatypes.LightPackageInfo
+import com.android.permissioncontroller.permission.utils.ContextCompat
import com.google.common.truth.Truth.assertThat
+import kotlinx.coroutines.runBlocking
import org.junit.After
import org.junit.Before
import org.junit.Test
@@ -71,11 +83,14 @@ class HibernationPolicyTest {
private val application = Mockito.mock(PermissionControllerApplication::class.java)
private const val USER_SETUP_INCOMPLETE = 0
private const val USER_SETUP_COMPLETE = 1
+ private const val TEST_PKG_NAME = "test.package"
}
@Mock lateinit var jobScheduler: JobScheduler
@Mock lateinit var context: Context
@Mock lateinit var userManager: UserManager
+ @Mock lateinit var packageManager: PackageManager
+ @Mock lateinit var telecomManager: TelecomManager
@Mock lateinit var contentResolver: ContentResolver
private lateinit var realContext: Context
@@ -83,6 +98,7 @@ class HibernationPolicyTest {
private lateinit var sharedPreferences: SharedPreferences
private lateinit var mockitoSession: MockitoSession
private lateinit var filesDir: File
+ private lateinit var userHandle: UserHandle
@Before
fun setup() {
@@ -100,11 +116,15 @@ class HibernationPolicyTest {
`when`(Settings.Secure.getUriFor(any())).thenReturn(Mockito.mock(Uri::class.java))
realContext = ApplicationProvider.getApplicationContext()
+ userHandle = UserHandle.getUserHandleForUid(Binder.getCallingUid())
sharedPreferences =
PreferenceManager.getDefaultSharedPreferences(realContext.applicationContext)
`when`(context.getSharedPreferences(anyString(), anyInt())).thenReturn(sharedPreferences)
`when`(context.getSystemService(UserManager::class.java)).thenReturn(userManager)
+ `when`(application.getSystemService(TelecomManager::class.java)).thenReturn(telecomManager)
+ `when`(application.packageManager).thenReturn(packageManager)
+ `when`(application.applicationContext).thenReturn(context)
filesDir = realContext.cacheDir
`when`(application.filesDir).thenReturn(filesDir)
@@ -207,6 +227,25 @@ class HibernationPolicyTest {
.isNotEqualTo(systemTimeSnapshot)
}
+ @Test
+ fun isPackageExemptBySystem_isCallingApp_returnsTrue() = runBlocking<Unit> {
+ val pkgInfo = makePackageInfo(TEST_PKG_NAME)
+
+ `when`(context.checkPermission(
+ eq(Manifest.permission.MANAGE_OWN_CALLS), anyInt(), eq(pkgInfo.uid)))
+ .thenReturn(PERMISSION_GRANTED)
+ `when`(context.checkPermission(
+ eq(Manifest.permission.RECORD_AUDIO), anyInt(), eq(pkgInfo.uid)))
+ .thenReturn(PERMISSION_GRANTED)
+ `when`(context.checkPermission(
+ eq(Manifest.permission.WRITE_CALL_LOG), anyInt(), eq(pkgInfo.uid)))
+ .thenReturn(PERMISSION_GRANTED)
+ `when`(telecomManager.selfManagedPhoneAccounts).thenReturn(
+ listOf(PhoneAccountHandle(ComponentName(TEST_PKG_NAME, "Service"), "id")))
+
+ assertThat(isPackageHibernationExemptBySystem(pkgInfo, userHandle)).isTrue()
+ }
+
private fun assertAdjustedTime(systemTimeSnapshot: Long, realtimeSnapshot: Long) {
val newStartTimeOfUnusedAppTracking =
sharedPreferences.getLong(
@@ -223,4 +262,23 @@ class HibernationPolicyTest {
assertThat(newRealtimeSnapshot).isNotEqualTo(SNAPSHOT_UNINITIALIZED)
assertThat(newRealtimeSnapshot).isAtLeast(realtimeSnapshot)
}
+
+ private fun makePackageInfo(packageName: String): LightPackageInfo {
+ return LightPackageInfo(
+ packageName,
+ emptyList(),
+ emptyList(),
+ emptyList(),
+ 0 /* uid */,
+ Build.VERSION_CODES.CUR_DEVELOPMENT,
+ false /* isInstantApp */,
+ true /* enabled */,
+ 0 /* appFlags */,
+ 0 /* firstInstallTime */,
+ 0 /* lastUpdateTime */,
+ false /* areAttributionsUserVisible */,
+ emptyMap() /* attributionTagsToLabels */,
+ ContextCompat.DEVICE_ID_DEFAULT
+ )
+ }
}
diff --git a/PermissionController/tests/mocking/src/com/android/permissioncontroller/tests/mocking/permission/domain/usecase/GetPermissionGroupUsageDetailsUseCaseTest.kt b/PermissionController/tests/mocking/src/com/android/permissioncontroller/tests/mocking/permission/domain/usecase/GetPermissionGroupUsageDetailsUseCaseTest.kt
index da2d05f63..c2040f76b 100644
--- a/PermissionController/tests/mocking/src/com/android/permissioncontroller/tests/mocking/permission/domain/usecase/GetPermissionGroupUsageDetailsUseCaseTest.kt
+++ b/PermissionController/tests/mocking/src/com/android/permissioncontroller/tests/mocking/permission/domain/usecase/GetPermissionGroupUsageDetailsUseCaseTest.kt
@@ -34,6 +34,7 @@ import com.android.permissioncontroller.permission.domain.model.v31.PermissionTi
import com.android.permissioncontroller.permission.domain.model.v31.PermissionTimelineUsageModelWrapper
import com.android.permissioncontroller.permission.domain.usecase.v31.GetPermissionGroupUsageDetailsUseCase
import com.android.permissioncontroller.permission.domain.usecase.v31.TELECOM_PACKAGE
+import com.android.permissioncontroller.permission.utils.LocationUtils
import com.android.permissioncontroller.pm.data.model.v31.PackageAttributionModel
import com.android.permissioncontroller.pm.data.model.v31.PackageInfoModel
import com.android.permissioncontroller.pm.data.repository.v31.PackageRepository
@@ -56,9 +57,11 @@ import kotlinx.coroutines.test.runTest
import org.junit.After
import org.junit.Assume
import org.junit.Before
+import org.junit.Ignore
import org.junit.Test
import org.junit.runner.RunWith
import org.mockito.Mock
+import org.mockito.Mockito
import org.mockito.Mockito.`when` as whenever
import org.mockito.MockitoAnnotations
import org.mockito.MockitoSession
@@ -88,11 +91,13 @@ class GetPermissionGroupUsageDetailsUseCaseTest {
mockitoSession =
ExtendedMockito.mockitoSession()
.mockStatic(PermissionControllerApplication::class.java)
+ .mockStatic(LocationUtils::class.java)
.strictness(Strictness.LENIENT)
.startMocking()
whenever(PermissionControllerApplication.get()).thenReturn(application)
whenever(application.applicationContext).thenReturn(context)
+ whenever(LocationUtils.isLocationProvider(Mockito.any(), Mockito.any())).thenReturn(false)
packageInfos =
mapOf(
@@ -102,7 +107,7 @@ class GetPermissionGroupUsageDetailsUseCaseTest {
systemPackageName to
getPackageInfoModel(
systemPackageName,
- applicationFlags = ApplicationInfo.FLAG_SYSTEM
+ applicationFlags = ApplicationInfo.FLAG_SYSTEM,
),
)
.toMutableMap()
@@ -124,7 +129,7 @@ class GetPermissionGroupUsageDetailsUseCaseTest {
emit(
listOf(
DiscretePackageOpsModel(testPackageName, currentUser.identifier, appOpEvents),
- DiscretePackageOpsModel(guestUserPkgName, guestUser.identifier, appOpEvents)
+ DiscretePackageOpsModel(guestUserPkgName, guestUser.identifier, appOpEvents),
)
)
}
@@ -150,11 +155,7 @@ class GetPermissionGroupUsageDetailsUseCaseTest {
emit(
listOf(
DiscretePackageOpsModel(testPackageName, currentUser.identifier, appOpEvents),
- DiscretePackageOpsModel(
- testPackageName,
- privateProfile.identifier,
- appOpEvents
- ),
+ DiscretePackageOpsModel(testPackageName, privateProfile.identifier, appOpEvents),
)
)
}
@@ -168,8 +169,8 @@ class GetPermissionGroupUsageDetailsUseCaseTest {
currentUserProfiles =
listOf(currentUser.identifier, privateProfile.identifier),
quietUserProfiles = listOf(privateProfile.identifier),
- showInQuiteModeProfiles = listOf(privateProfile.identifier)
- )
+ showInQuiteModeProfiles = listOf(privateProfile.identifier),
+ ),
)
val permissionTimelineUsages = getResult(underTest, this)
@@ -190,11 +191,7 @@ class GetPermissionGroupUsageDetailsUseCaseTest {
emit(
listOf(
DiscretePackageOpsModel(testPackageName, currentUser.identifier, appOpEvents),
- DiscretePackageOpsModel(
- testPackageName,
- privateProfile.identifier,
- appOpEvents
- ),
+ DiscretePackageOpsModel(testPackageName, privateProfile.identifier, appOpEvents),
)
)
}
@@ -208,7 +205,7 @@ class GetPermissionGroupUsageDetailsUseCaseTest {
currentUserProfiles =
listOf(currentUser.identifier, privateProfile.identifier),
quietUserProfiles = listOf(privateProfile.identifier),
- )
+ ),
)
val permissionTimelineUsages = getResult(underTest, this)
@@ -254,7 +251,7 @@ class GetPermissionGroupUsageDetailsUseCaseTest {
val discretePackageOps = flow {
emit(
listOf(
- DiscretePackageOpsModel(testPackageName, currentUser.identifier, appOpEvents),
+ DiscretePackageOpsModel(testPackageName, currentUser.identifier, appOpEvents)
)
)
}
@@ -280,7 +277,7 @@ class GetPermissionGroupUsageDetailsUseCaseTest {
val discretePackageOps = flow {
emit(
listOf(
- DiscretePackageOpsModel(testPackageName, currentUser.identifier, appOpEvents),
+ DiscretePackageOpsModel(testPackageName, currentUser.identifier, appOpEvents)
)
)
}
@@ -303,23 +300,23 @@ class GetPermissionGroupUsageDetailsUseCaseTest {
DiscreteOpModel(
AppOpsManager.OPSTR_CAMERA,
MINUTES.toMillis(1),
- MINUTES.toMillis(1)
+ MINUTES.toMillis(1),
),
DiscreteOpModel(
AppOpsManager.OPSTR_CAMERA,
MINUTES.toMillis(2),
- MINUTES.toMillis(1)
+ MINUTES.toMillis(1),
),
DiscreteOpModel(
AppOpsManager.OPSTR_CAMERA,
MINUTES.toMillis(3),
- MINUTES.toMillis(2)
+ MINUTES.toMillis(2),
),
)
val discretePackageOps = flow {
emit(
listOf(
- DiscretePackageOpsModel(testPackageName, currentUser.identifier, appOpEvents),
+ DiscretePackageOpsModel(testPackageName, currentUser.identifier, appOpEvents)
)
)
}
@@ -344,23 +341,19 @@ class GetPermissionGroupUsageDetailsUseCaseTest {
DiscreteOpModel(
AppOpsManager.OPSTR_FINE_LOCATION,
hours3 + MINUTES.toMillis(59),
- -1
+ -1,
),
DiscreteOpModel(
AppOpsManager.OPSTR_FINE_LOCATION,
hours4 + MINUTES.toMillis(0),
- -1
- ),
- DiscreteOpModel(
- AppOpsManager.OPSTR_FINE_LOCATION,
- hours4 + MINUTES.toMillis(1),
- -1
+ -1,
),
+ DiscreteOpModel(AppOpsManager.OPSTR_FINE_LOCATION, hours4 + MINUTES.toMillis(1), -1),
)
val discretePackageOps = flow {
emit(
listOf(
- DiscretePackageOpsModel(testPackageName, currentUser.identifier, appOpEvents),
+ DiscretePackageOpsModel(testPackageName, currentUser.identifier, appOpEvents)
)
)
}
@@ -383,18 +376,18 @@ class GetPermissionGroupUsageDetailsUseCaseTest {
DiscreteOpModel(
AppOpsManager.OPSTR_CAMERA,
MINUTES.toMillis(1),
- MINUTES.toMillis(3)
+ MINUTES.toMillis(3),
),
DiscreteOpModel(
AppOpsManager.OPSTR_CAMERA,
MINUTES.toMillis(3),
- MINUTES.toMillis(2)
+ MINUTES.toMillis(2),
),
)
val discretePackageOps = flow {
emit(
listOf(
- DiscretePackageOpsModel(testPackageName, currentUser.identifier, appOpEvents),
+ DiscretePackageOpsModel(testPackageName, currentUser.identifier, appOpEvents)
)
)
}
@@ -420,7 +413,7 @@ class GetPermissionGroupUsageDetailsUseCaseTest {
val discretePackageOps = flow {
emit(
listOf(
- DiscretePackageOpsModel(testPackageName, currentUser.identifier, appOpEvents),
+ DiscretePackageOpsModel(testPackageName, currentUser.identifier, appOpEvents)
)
)
}
@@ -448,18 +441,18 @@ class GetPermissionGroupUsageDetailsUseCaseTest {
DiscreteOpModel(
AppOpsManager.OPSTR_CAMERA,
MINUTES.toMillis(1),
- MINUTES.toMillis(3)
+ MINUTES.toMillis(3),
),
DiscreteOpModel(
AppOpsManager.OPSTR_CAMERA,
MINUTES.toMillis(5),
- MINUTES.toMillis(5)
+ MINUTES.toMillis(5),
),
)
val discretePackageOps = flow {
emit(
listOf(
- DiscretePackageOpsModel(testPackageName, currentUser.identifier, appOpEvents),
+ DiscretePackageOpsModel(testPackageName, currentUser.identifier, appOpEvents)
)
)
}
@@ -483,13 +476,11 @@ class GetPermissionGroupUsageDetailsUseCaseTest {
@Test
fun singleDiscreteAccess() = runTest {
val appOpEvents =
- listOf(
- DiscreteOpModel(AppOpsManager.OPSTR_FINE_LOCATION, MINUTES.toMillis(1), -1),
- )
+ listOf(DiscreteOpModel(AppOpsManager.OPSTR_FINE_LOCATION, MINUTES.toMillis(1), -1))
val discretePackageOps = flow {
emit(
listOf(
- DiscretePackageOpsModel(testPackageName, currentUser.identifier, appOpEvents),
+ DiscretePackageOpsModel(testPackageName, currentUser.identifier, appOpEvents)
)
)
}
@@ -512,13 +503,13 @@ class GetPermissionGroupUsageDetailsUseCaseTest {
DiscreteOpModel(
AppOpsManager.OPSTR_CAMERA,
MINUTES.toMillis(1),
- MINUTES.toMillis(3)
- ),
+ MINUTES.toMillis(3),
+ )
)
val discretePackageOps = flow {
emit(
listOf(
- DiscretePackageOpsModel(testPackageName, currentUser.identifier, appOpEvents),
+ DiscretePackageOpsModel(testPackageName, currentUser.identifier, appOpEvents)
)
)
}
@@ -541,29 +532,29 @@ class GetPermissionGroupUsageDetailsUseCaseTest {
DiscreteOpModel(
AppOpsManager.OPSTR_CAMERA,
MINUTES.toMillis(1),
- MINUTES.toMillis(2)
+ MINUTES.toMillis(2),
),
// This entry says the camera was accessed for 15 minutes starting at minute 3
DiscreteOpModel(
AppOpsManager.OPSTR_CAMERA,
MINUTES.toMillis(3),
- MINUTES.toMillis(15)
+ MINUTES.toMillis(15),
),
DiscreteOpModel(
AppOpsManager.OPSTR_CAMERA,
MINUTES.toMillis(4),
- MINUTES.toMillis(1)
+ MINUTES.toMillis(1),
),
DiscreteOpModel(
AppOpsManager.OPSTR_CAMERA,
MINUTES.toMillis(6),
- MINUTES.toMillis(1)
+ MINUTES.toMillis(1),
),
)
val discretePackageOps = flow {
emit(
listOf(
- DiscretePackageOpsModel(testPackageName, currentUser.identifier, appOpEvents),
+ DiscretePackageOpsModel(testPackageName, currentUser.identifier, appOpEvents)
)
)
}
@@ -582,9 +573,7 @@ class GetPermissionGroupUsageDetailsUseCaseTest {
@Test
fun verifyUserSensitiveFlags() = runTest {
val appOpEvents =
- listOf(
- DiscreteOpModel(AppOpsManager.OPSTR_COARSE_LOCATION, MINUTES.toMillis(1), -1),
- )
+ listOf(DiscreteOpModel(AppOpsManager.OPSTR_COARSE_LOCATION, MINUTES.toMillis(1), -1))
val discretePackageOps = flow {
emit(
listOf(
@@ -620,13 +609,11 @@ class GetPermissionGroupUsageDetailsUseCaseTest {
@Test
fun verifyNotUserSensitiveFlagsForSystemPackage() = runTest {
val appOpEvents =
- listOf(
- DiscreteOpModel(AppOpsManager.OPSTR_COARSE_LOCATION, MINUTES.toMillis(1), -1),
- )
+ listOf(DiscreteOpModel(AppOpsManager.OPSTR_COARSE_LOCATION, MINUTES.toMillis(1), -1))
val discretePackageOps = flow {
emit(
listOf(
- DiscretePackageOpsModel(systemPackageName, currentUser.identifier, appOpEvents),
+ DiscretePackageOpsModel(systemPackageName, currentUser.identifier, appOpEvents)
)
)
}
@@ -651,14 +638,12 @@ class GetPermissionGroupUsageDetailsUseCaseTest {
@Test
fun verifyCameraUserSensitiveFlagsForTelecomPackage() = runTest {
val appOpEvents =
- listOf(
- DiscreteOpModel(AppOpsManager.OPSTR_CAMERA, MINUTES.toMillis(1), -1),
- )
+ listOf(DiscreteOpModel(AppOpsManager.OPSTR_CAMERA, MINUTES.toMillis(1), -1))
packageInfos[TELECOM_PACKAGE] = getPackageInfoModel(TELECOM_PACKAGE)
val discretePackageOps = flow {
emit(
listOf(
- DiscretePackageOpsModel(TELECOM_PACKAGE, currentUser.identifier, appOpEvents),
+ DiscretePackageOpsModel(TELECOM_PACKAGE, currentUser.identifier, appOpEvents)
)
)
}
@@ -683,14 +668,12 @@ class GetPermissionGroupUsageDetailsUseCaseTest {
@Test
fun verifyLocationUserSensitiveFlagsForTelecomPackage() = runTest {
val appOpEvents =
- listOf(
- DiscreteOpModel(AppOpsManager.OPSTR_COARSE_LOCATION, MINUTES.toMillis(1), -1),
- )
+ listOf(DiscreteOpModel(AppOpsManager.OPSTR_COARSE_LOCATION, MINUTES.toMillis(1), -1))
packageInfos[TELECOM_PACKAGE] = getPackageInfoModel(TELECOM_PACKAGE)
val discretePackageOps = flow {
emit(
listOf(
- DiscretePackageOpsModel(TELECOM_PACKAGE, currentUser.identifier, appOpEvents),
+ DiscretePackageOpsModel(TELECOM_PACKAGE, currentUser.identifier, appOpEvents)
)
)
}
@@ -714,7 +697,74 @@ class GetPermissionGroupUsageDetailsUseCaseTest {
}
@Test
- fun verifyAttributionTagsAreGroupedAndClustered() = runTest {
+ @RequiresFlagsEnabled(
+ com.android.permission.flags.Flags.FLAG_PERMISSION_TIMELINE_ATTRIBUTION_LABEL_FIX
+ )
+ @Ignore("b/365004787")
+ fun verifyAccessIsNotGroupedByAttributionLabelAndClustered() = runTest {
+ // The package is not a location provider.
+ val appOpEvents =
+ listOf(
+ // These entries should be clustered even though they have
+ // different attribution labels.
+ DiscreteOpModel(
+ AppOpsManager.OPSTR_COARSE_LOCATION,
+ MINUTES.toMillis(1),
+ -1,
+ "tag1",
+ ),
+ DiscreteOpModel(
+ AppOpsManager.OPSTR_COARSE_LOCATION,
+ MINUTES.toMillis(2),
+ -1,
+ "tag1",
+ ),
+ DiscreteOpModel(
+ AppOpsManager.OPSTR_COARSE_LOCATION,
+ MINUTES.toMillis(3),
+ -1,
+ "tag3",
+ ),
+ DiscreteOpModel(
+ AppOpsManager.OPSTR_COARSE_LOCATION,
+ MINUTES.toMillis(4),
+ -1,
+ "tag2",
+ ),
+ )
+ val discretePackageOps = flow {
+ emit(
+ listOf(
+ DiscretePackageOpsModel(testPackageName, currentUser.identifier, appOpEvents)
+ )
+ )
+ }
+ val packageAttributions = mutableMapOf<String, PackageAttributionModel>()
+ // tag1 and tag3 refers to same attribution label.
+ val attributionTagToLabelRes = mapOf("tag1" to 100, "tag2" to 200, "tag3" to 100)
+ val attributionsMap = mapOf(100 to "Tag1 Label", 200 to "Tag2 Label")
+ packageAttributions[testPackageName] =
+ PackageAttributionModel(
+ testPackageName,
+ true,
+ attributionTagToLabelRes,
+ attributionsMap,
+ )
+
+ val underTest =
+ getPermissionGroupUsageDetailsUseCase(
+ LOCATION_PERMISSION_GROUP,
+ discretePackageOps,
+ packageRepository = FakePackageRepository(packageInfos, packageAttributions),
+ )
+ val permissionTimelineUsages = getResult(underTest, this)
+
+ Truth.assertThat(permissionTimelineUsages.size).isEqualTo(1)
+ }
+
+ @Test
+ fun verifyAccessIsGroupedByAttributionLabelAndClustered() = runTest {
+ whenever(LocationUtils.isLocationProvider(Mockito.any(), Mockito.any())).thenReturn(true)
val appOpEvents =
listOf(
// These 3 entries should be grouped and clustered.
@@ -722,38 +772,38 @@ class GetPermissionGroupUsageDetailsUseCaseTest {
AppOpsManager.OPSTR_COARSE_LOCATION,
MINUTES.toMillis(1),
-1,
- "tag1"
+ "tag1",
),
DiscreteOpModel(
AppOpsManager.OPSTR_COARSE_LOCATION,
MINUTES.toMillis(2),
-1,
- "tag1"
+ "tag1",
),
DiscreteOpModel(
AppOpsManager.OPSTR_COARSE_LOCATION,
MINUTES.toMillis(3),
-1,
- "tag3"
+ "tag3",
),
// The access at minute 4 should not be grouped or clustered.
DiscreteOpModel(
AppOpsManager.OPSTR_COARSE_LOCATION,
MINUTES.toMillis(4),
-1,
- "tag2"
+ "tag2",
),
DiscreteOpModel(
AppOpsManager.OPSTR_COARSE_LOCATION,
MINUTES.toMillis(8),
-1,
- "tag2"
+ "tag2",
),
)
val discretePackageOps = flow {
emit(
listOf(
- DiscretePackageOpsModel(testPackageName, currentUser.identifier, appOpEvents),
+ DiscretePackageOpsModel(testPackageName, currentUser.identifier, appOpEvents)
)
)
}
@@ -766,14 +816,14 @@ class GetPermissionGroupUsageDetailsUseCaseTest {
testPackageName,
true,
attributionTagToLabelRes,
- attributionsMap
+ attributionsMap,
)
val underTest =
getPermissionGroupUsageDetailsUseCase(
LOCATION_PERMISSION_GROUP,
discretePackageOps,
- packageRepository = FakePackageRepository(packageInfos, packageAttributions)
+ packageRepository = FakePackageRepository(packageInfos, packageAttributions),
)
val permissionTimelineUsages = getResult(underTest, this)
@@ -805,7 +855,7 @@ class GetPermissionGroupUsageDetailsUseCaseTest {
val discretePackageOps = flow {
emit(
listOf(
- DiscretePackageOpsModel(testPackageName, currentUser.identifier, appOpEvents),
+ DiscretePackageOpsModel(testPackageName, currentUser.identifier, appOpEvents)
)
)
}
@@ -829,7 +879,7 @@ class GetPermissionGroupUsageDetailsUseCaseTest {
val discretePackageOps = flow {
emit(
listOf(
- DiscretePackageOpsModel(testPackageName, currentUser.identifier, appOpEvents),
+ DiscretePackageOpsModel(testPackageName, currentUser.identifier, appOpEvents)
)
)
}
@@ -843,7 +893,7 @@ class GetPermissionGroupUsageDetailsUseCaseTest {
private fun TestScope.getResult(
useCase: GetPermissionGroupUsageDetailsUseCase,
- coroutineScope: CoroutineScope
+ coroutineScope: CoroutineScope,
): List<PermissionTimelineUsageModel> {
val usages by collectLastValue(useCase(coroutineScope))
return (usages as PermissionTimelineUsageModelWrapper.Success).timelineUsageModels
@@ -854,7 +904,7 @@ class GetPermissionGroupUsageDetailsUseCaseTest {
discreteUsageFlow: Flow<List<DiscretePackageOpsModel>>,
permissionFlags: Map<String, Int> = emptyMap(),
userRepository: UserRepository = FakeUserRepository(listOf(currentUser.identifier)),
- packageRepository: PackageRepository = FakePackageRepository(packageInfos)
+ packageRepository: PackageRepository = FakePackageRepository(packageInfos),
): GetPermissionGroupUsageDetailsUseCase {
val permissionRepository = FakePermissionRepository(permissionFlags)
val appOpUsageRepository = FakeAppOpRepository(emptyFlow(), discreteUsageFlow)
@@ -865,7 +915,7 @@ class GetPermissionGroupUsageDetailsUseCaseTest {
permissionRepository,
appOpUsageRepository,
roleRepository,
- userRepository
+ userRepository,
)
}
@@ -877,7 +927,7 @@ class GetPermissionGroupUsageDetailsUseCaseTest {
listOf(
PackageInfo.REQUESTED_PERMISSION_GRANTED,
PackageInfo.REQUESTED_PERMISSION_GRANTED,
- PackageInfo.REQUESTED_PERMISSION_GRANTED
+ PackageInfo.REQUESTED_PERMISSION_GRANTED,
),
applicationFlags: Int = 0,
) = PackageInfoModel(packageName, requestedPermissions, permissionsFlags, applicationFlags)
diff --git a/SafetyCenter/Resources/res/values-ar/strings.xml b/SafetyCenter/Resources/res/values-ar/strings.xml
index 14ec20a51..0fc5079db 100644
--- a/SafetyCenter/Resources/res/values-ar/strings.xml
+++ b/SafetyCenter/Resources/res/values-ar/strings.xml
@@ -36,7 +36,7 @@
<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_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>
diff --git a/flags/Android.bp b/flags/Android.bp
index aba1e44a9..d22da26c3 100644
--- a/flags/Android.bp
+++ b/flags/Android.bp
@@ -36,6 +36,7 @@ java_aconfig_library {
libs: ["framework-configinfrastructure.stubs.module_lib"],
visibility: [
"//packages/modules/Permission:__subpackages__",
+ "//vendor:__subpackages__",
],
apex_available: [
"com.android.permission",
diff --git a/flags/flags.aconfig b/flags/flags.aconfig
index c94614654..5f3d1cc93 100644
--- a/flags/flags.aconfig
+++ b/flags/flags.aconfig
@@ -108,3 +108,12 @@ flag {
bug: "349675008"
is_fixed_read_only: true
}
+
+flag {
+ name: "permission_timeline_attribution_label_fix"
+ is_exported: true
+ namespace: "permissions"
+ description: "This flag is used for the attribution label fix on permission timeline page"
+ bug: "369606734"
+ is_fixed_read_only: true
+}
diff --git a/tests/apex/Android.bp b/tests/apex/Android.bp
index 83bf4e252..18f1bea75 100644
--- a/tests/apex/Android.bp
+++ b/tests/apex/Android.bp
@@ -27,6 +27,7 @@ android_test {
],
static_libs: [
"service-permission.impl",
+ "services.core",
"androidx.test.rules",
"androidx.test.ext.junit",
"androidx.test.ext.truth",
diff --git a/tests/apex/java/com/android/role/RoleUserStateTest.kt b/tests/apex/java/com/android/role/RoleUserStateTest.kt
new file mode 100644
index 000000000..8b0c51174
--- /dev/null
+++ b/tests/apex/java/com/android/role/RoleUserStateTest.kt
@@ -0,0 +1,94 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.role
+
+import android.os.UserHandle
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import com.android.server.role.RoleServicePlatformHelper
+import com.google.common.truth.Truth.assertWithMessage
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.Mockito.mock
+
+@RunWith(AndroidJUnit4::class)
+class RoleUserStateTest {
+ private var roleServicePlatformHelper = mock(RoleServicePlatformHelper::class.java)
+ private var roleUserStateCallback = mock(RoleUserState.Callback::class.java)
+
+ private val userId = UserHandle.myUserId()
+ private val roleUserState =
+ RoleUserState(userId, roleServicePlatformHelper, roleUserStateCallback, false)
+
+ @Before
+ fun setUp() {
+ setUpRole(ROLE_NAME_1, true)
+ setUpRole(ROLE_NAME_2, false)
+ }
+
+ private fun setUpRole(roleName: String, fallbackEnabled: Boolean) {
+ roleUserState.addRoleName(roleName)
+ roleUserState.setFallbackEnabled(roleName, fallbackEnabled)
+ }
+
+ @Test
+ fun testUpgradeVersion_upgradeNotNeeded_remainsUnchanged() {
+ roleUserState.version = RoleUserState.VERSION_FALLBACK_STATE_MIGRATED
+ val legacyFallbackDisabledRoles = listOf(ROLE_NAME_1, ROLE_NAME_2)
+
+ roleUserState.upgradeVersion(legacyFallbackDisabledRoles)
+
+ assertRoleFallbackState(ROLE_NAME_1, roleUserState.isFallbackEnabled(ROLE_NAME_1), true)
+ assertRoleFallbackState(ROLE_NAME_2, roleUserState.isFallbackEnabled(ROLE_NAME_2), false)
+ }
+
+ @Test
+ fun testUpgradeVersion_upgradeNeeded_disabledFallbackStateMigrated() {
+ roleUserState.version = RoleUserState.VERSION_UNDEFINED
+ val legacyFallbackDisabledRoles = listOf(ROLE_NAME_1, ROLE_NAME_2)
+
+ roleUserState.upgradeVersion(legacyFallbackDisabledRoles)
+
+ assertRoleFallbackState(ROLE_NAME_1, roleUserState.isFallbackEnabled(ROLE_NAME_1), false)
+ assertRoleFallbackState(ROLE_NAME_2, roleUserState.isFallbackEnabled(ROLE_NAME_2), false)
+ }
+
+ @Test
+ fun testUpgradeVersion_upgradeNeeded_enabledFallbackStateMigrated() {
+ roleUserState.version = RoleUserState.VERSION_UNDEFINED
+ val legacyFallbackDisabledRoles = emptyList<String>()
+
+ roleUserState.upgradeVersion(legacyFallbackDisabledRoles)
+
+ assertRoleFallbackState(ROLE_NAME_1, roleUserState.isFallbackEnabled(ROLE_NAME_1), true)
+ assertRoleFallbackState(ROLE_NAME_2, roleUserState.isFallbackEnabled(ROLE_NAME_2), true)
+ }
+
+ private fun assertRoleFallbackState(roleName: String, actual: Boolean, expected: Boolean) {
+ assertWithMessage(
+ "Fallback enabled state for role: $roleName is $actual while" +
+ " is expected to be $expected"
+ )
+ .that(actual)
+ .isEqualTo(expected)
+ }
+
+ companion object {
+ private const val ROLE_NAME_1 = "ROLE_NAME_1"
+ private const val ROLE_NAME_2 = "ROLE_NAME_2"
+ }
+}
diff --git a/tests/cts/permissionmultidevice/src/android/permissionmultidevice/cts/AppPermissionsTest.kt b/tests/cts/permissionmultidevice/src/android/permissionmultidevice/cts/AppPermissionsTest.kt
index 7ecc51ded..4d166939a 100644
--- a/tests/cts/permissionmultidevice/src/android/permissionmultidevice/cts/AppPermissionsTest.kt
+++ b/tests/cts/permissionmultidevice/src/android/permissionmultidevice/cts/AppPermissionsTest.kt
@@ -320,8 +320,7 @@ class AppPermissionsTest {
}
private fun verifyPermissionMessage() {
- val actualText = UiAutomatorUtils2.waitFindObject(By.res(PERMISSION_MESSAGE_ID)).text
- assertEquals(permissionMessage, actualText)
+ UiAutomatorUtils2.waitFindObject(By.text(permissionMessage))
}
private fun getGrantInfoMap(): Map<String, List<String>> {
@@ -441,8 +440,6 @@ class AppPermissionsTest {
"com.android.permissioncontroller:id/deny_radio_button"
private const val TITLE = "android:id/title"
private const val RECYCLER_VIEW = "com.android.permissioncontroller:id/recycler_view"
- private const val PERMISSION_MESSAGE_ID =
- "com.android.permissioncontroller:id/permission_message"
private const val NEW_WINDOW_TIMEOUT_MILLIS: Long = 20_000
}
}
diff --git a/tests/cts/permissionui/src/android/permissionui/cts/AppPermissionTest.kt b/tests/cts/permissionui/src/android/permissionui/cts/AppPermissionTest.kt
index 4ada5717e..f0c12171c 100644
--- a/tests/cts/permissionui/src/android/permissionui/cts/AppPermissionTest.kt
+++ b/tests/cts/permissionui/src/android/permissionui/cts/AppPermissionTest.kt
@@ -335,7 +335,10 @@ class AppPermissionTest : BaseUsePermissionTest() {
}
private fun assertAppPermissionRationaleContainerIsVisible(expected: Boolean) {
- findView(By.res(APP_PERMISSION_RATIONALE_CONTAINER_VIEW), expected)
+ findView(
+ By.text(getPermissionControllerString(APP_PERMISSION_RATIONALE_TITLE_TEXT)),
+ expected
+ )
}
companion object {
diff --git a/tests/cts/permissionui/src/android/permissionui/cts/BaseUsePermissionTest.kt b/tests/cts/permissionui/src/android/permissionui/cts/BaseUsePermissionTest.kt
index cbb8abc0a..2332ff0c7 100644
--- a/tests/cts/permissionui/src/android/permissionui/cts/BaseUsePermissionTest.kt
+++ b/tests/cts/permissionui/src/android/permissionui/cts/BaseUsePermissionTest.kt
@@ -122,8 +122,6 @@ abstract class BaseUsePermissionTest : BasePermissionTest() {
const val ALLOW_ALWAYS_RADIO_BUTTON =
"com.android.permissioncontroller:id/allow_always_radio_button"
- const val ALLOW_RADIO_BUTTON_FRAME =
- "com.android.permissioncontroller:id/allow_radio_button_frame"
const val ALLOW_RADIO_BUTTON = "com.android.permissioncontroller:id/allow_radio_button"
const val ALLOW_FOREGROUND_RADIO_BUTTON =
"com.android.permissioncontroller:id/allow_foreground_only_radio_button"
@@ -147,10 +145,9 @@ abstract class BaseUsePermissionTest : BasePermissionTest() {
const val ECM_ALERT_DIALOG_OK_BUTTON_TEXT = "enhanced_confirmation_dialog_ok"
const val ALERT_DIALOG_MESSAGE = "android:id/message"
const val ALERT_DIALOG_OK_BUTTON = "android:id/button1"
- const val APP_PERMISSION_RATIONALE_CONTAINER_VIEW =
- "com.android.permissioncontroller:id/app_permission_rationale_container"
- const val APP_PERMISSION_RATIONALE_CONTENT_VIEW =
- "com.android.permissioncontroller:id/app_permission_rationale_content"
+ const val APP_PERMISSION_RATIONALE_TITLE_TEXT = "app_location_permission_rationale_title"
+ const val APP_PERMISSION_RATIONALE_SUBTITLE_TEXT =
+ "app_location_permission_rationale_subtitle"
const val GRANT_DIALOG_PERMISSION_RATIONALE_CONTAINER_VIEW =
"com.android.permissioncontroller:id/permission_rationale_container"
const val PERMISSION_RATIONALE_ACTIVITY_TITLE_VIEW =
@@ -994,7 +991,9 @@ abstract class BaseUsePermissionTest : BasePermissionTest() {
}
protected fun clickPermissionRationaleContentInAppPermission() {
- clickAndWaitForWindowTransition(By.res(APP_PERMISSION_RATIONALE_CONTENT_VIEW))
+ clickAndWaitForWindowTransition(
+ By.text(getPermissionControllerString(APP_PERMISSION_RATIONALE_SUBTITLE_TEXT))
+ )
}
protected fun clickPermissionRationaleViewInGrantDialog() {
diff --git a/tests/cts/permissionui/src/android/permissionui/cts/PermissionReviewTapjackingTest.kt b/tests/cts/permissionui/src/android/permissionui/cts/PermissionReviewTapjackingTest.kt
index ae08ffa10..14901eb2a 100644
--- a/tests/cts/permissionui/src/android/permissionui/cts/PermissionReviewTapjackingTest.kt
+++ b/tests/cts/permissionui/src/android/permissionui/cts/PermissionReviewTapjackingTest.kt
@@ -44,6 +44,8 @@ class PermissionReviewTapjackingTest : BaseUsePermissionTest() {
installPackage(APP_APK_PATH_22)
installPackage(HELPER_APP_OVERLAY)
+ Thread.sleep(1000)
+
SystemUtil.runShellCommandOrThrow(
"appops set $HELPER_PACKAGE_NAME android:system_alert_window allow"
)
diff --git a/tests/cts/role/Android.bp b/tests/cts/role/Android.bp
index e392109db..f0095b7dd 100644
--- a/tests/cts/role/Android.bp
+++ b/tests/cts/role/Android.bp
@@ -48,6 +48,6 @@ android_test {
":CtsRoleTestApp",
":CtsRoleTestApp28",
":CtsRoleTestApp33WithoutInCallService",
- ":CtsRoleTestAppForProfile",
+ ":CtsRoleTestAppClone",
],
}
diff --git a/tests/cts/role/AndroidTest.xml b/tests/cts/role/AndroidTest.xml
index a53fa62d0..bfdcf2829 100644
--- a/tests/cts/role/AndroidTest.xml
+++ b/tests/cts/role/AndroidTest.xml
@@ -42,7 +42,7 @@
<option name="push" value="CtsRoleTestApp.apk->/data/local/tmp/cts-role/CtsRoleTestApp.apk" />
<option name="push" value="CtsRoleTestApp28.apk->/data/local/tmp/cts-role/CtsRoleTestApp28.apk" />
<option name="push" value="CtsRoleTestApp33WithoutInCallService.apk->/data/local/tmp/cts-role/CtsRoleTestApp33WithoutInCallService.apk" />
- <option name="push" value="CtsRoleTestAppForProfile.apk->/data/local/tmp/cts-role/CtsRoleTestAppForProfile.apk" />
+ <option name="push" value="CtsRoleTestAppClone.apk->/data/local/tmp/cts-role/CtsRoleTestAppClone.apk" />
</target_preparer>
<test class="com.android.tradefed.testtype.AndroidJUnitTest" >
diff --git a/tests/cts/role/CtsRoleTestAppForProfile/Android.bp b/tests/cts/role/CtsRoleTestAppClone/Android.bp
index 1d9a1e6e8..0ac48da8b 100644
--- a/tests/cts/role/CtsRoleTestAppForProfile/Android.bp
+++ b/tests/cts/role/CtsRoleTestAppClone/Android.bp
@@ -17,7 +17,7 @@ package {
}
android_test_helper_app {
- name: "CtsRoleTestAppForProfile",
+ name: "CtsRoleTestAppClone",
defaults: ["mts-target-sdk-version-current"],
min_sdk_version: "30",
}
diff --git a/tests/cts/role/CtsRoleTestAppForProfile/AndroidManifest.xml b/tests/cts/role/CtsRoleTestAppClone/AndroidManifest.xml
index 05413e55f..f45ab359b 100644
--- a/tests/cts/role/CtsRoleTestAppForProfile/AndroidManifest.xml
+++ b/tests/cts/role/CtsRoleTestAppClone/AndroidManifest.xml
@@ -18,9 +18,9 @@
<manifest
xmlns:android="http://schemas.android.com/apk/res/android"
- package="android.app.role.cts.appForProfile">
+ package="android.app.role.cts.appClone">
- <application android:label="CtsRoleTestAppForProfile">
+ <application android:label="CtsRoleTestAppClone">
<!-- Browser -->
<activity
android:name=".BrowserActivity"
diff --git a/tests/cts/role/src/android/app/role/cts/RoleManagerTest.java b/tests/cts/role/src/android/app/role/cts/RoleManagerTest.java
index b64de5665..4ba8b33e7 100644
--- a/tests/cts/role/src/android/app/role/cts/RoleManagerTest.java
+++ b/tests/cts/role/src/android/app/role/cts/RoleManagerTest.java
@@ -66,7 +66,7 @@ import androidx.test.uiautomator.Until;
import com.android.bedstead.harrier.BedsteadJUnit4;
import com.android.bedstead.harrier.DeviceState;
-import com.android.bedstead.harrier.annotations.EnsureHasPrivateProfile;
+import com.android.bedstead.multiuser.annotations.EnsureHasPrivateProfile;
import com.android.bedstead.nene.types.OptionalBoolean;
import com.android.compatibility.common.util.DisableAnimationRule;
import com.android.compatibility.common.util.FreezeRotationRule;
@@ -108,10 +108,10 @@ public class RoleManagerTest {
private static final String APP_APK_PATH = "/data/local/tmp/cts-role/CtsRoleTestApp.apk";
private static final String APP_PACKAGE_NAME = "android.app.role.cts.app";
private static final String APP_LABEL = "CtsRoleTestApp";
- private static final String APP_FOR_PROFILE_APK_PATH =
- "/data/local/tmp/cts-role/CtsRoleTestAppForProfile.apk";
- private static final String APP_FOR_PROFILE_PACKAGE_NAME = "android.app.role.cts.appForProfile";
- private static final String APP_FOR_PROFILE = "CtsRoleTestAppForProfile";
+ private static final String APP_CLONE_APK_PATH =
+ "/data/local/tmp/cts-role/CtsRoleTestAppClone.apk";
+ private static final String APP_CLONE_PACKAGE_NAME = "android.app.role.cts.appClone";
+ private static final String APP_CLONE = "CtsRoleTestAppClone";
private static final String APP_IS_ROLE_HELD_ACTIVITY_NAME = APP_PACKAGE_NAME
+ ".IsRoleHeldActivity";
private static final String APP_IS_ROLE_HELD_EXTRA_IS_ROLE_HELD = APP_PACKAGE_NAME
@@ -183,7 +183,20 @@ public class RoleManagerTest {
private String mRoleHolder;
@Before
- public void saveRoleHolder() throws Exception {
+ public void setUp() throws Exception {
+ saveRoleHolder();
+ installApp();
+ wakeUpScreen();
+ closeNotificationShade();
+ }
+
+ @After
+ public void tearDown() throws Exception {
+ uninstallApp();
+ restoreRoleHolder();
+ }
+
+ private void saveRoleHolder() throws Exception {
List<String> roleHolders = getRoleHolders(ROLE_NAME);
mRoleHolder = !roleHolders.isEmpty() ? roleHolders.get(0) : null;
@@ -193,8 +206,7 @@ public class RoleManagerTest {
}
}
- @After
- public void restoreRoleHolder() throws Exception {
+ private void restoreRoleHolder() throws Exception {
removeRoleHolder(ROLE_NAME, APP_PACKAGE_NAME);
if (mRoleHolder != null) {
@@ -204,27 +216,27 @@ public class RoleManagerTest {
assertIsRoleHolder(ROLE_NAME, APP_PACKAGE_NAME, false);
}
- @Before
- public void installApp() throws Exception {
+ private void installApp() throws Exception {
installPackage(APP_APK_PATH);
installPackage(APP_28_APK_PATH);
installPackage(APP_33_WITHOUT_INCALLSERVICE_APK_PATH);
+ // Install CtsRoleTestAppClone as default role holder for browser role
+ // in case no browser is installed on system
+ installPackage(APP_CLONE_APK_PATH);
}
- @After
- public void uninstallApp() throws Exception {
+ private void uninstallApp() throws Exception {
uninstallPackage(APP_PACKAGE_NAME);
uninstallPackage(APP_28_PACKAGE_NAME);
uninstallPackage(APP_33_WITHOUT_INCALLSERVICE_PACKAGE_NAME);
+ uninstallPackage(APP_CLONE_PACKAGE_NAME);
}
- @Before
- public void wakeUpScreen() throws IOException {
+ private void wakeUpScreen() throws IOException {
runShellCommand(sInstrumentation, "input keyevent KEYCODE_WAKEUP");
}
- @Before
- public void closeNotificationShade() {
+ private void closeNotificationShade() {
sContext.sendBroadcast(new Intent(Intent.ACTION_CLOSE_SYSTEM_DIALOGS));
}
@@ -855,15 +867,15 @@ public class RoleManagerTest {
UserHandle privateProfile = sDeviceState.privateProfile().userHandle();
assertThat(privateProfile).isNotNull();
installPackage(APP_APK_PATH, privateProfile);
- installPackage(APP_FOR_PROFILE_APK_PATH, privateProfile);
- addRoleHolderAsUser(ROLE_NAME, APP_FOR_PROFILE_PACKAGE_NAME, privateProfile);
+ installPackage(APP_CLONE_APK_PATH, privateProfile);
+ addRoleHolderAsUser(ROLE_NAME, APP_CLONE_PACKAGE_NAME, privateProfile);
sContext.startActivity(new Intent(Settings.ACTION_MANAGE_DEFAULT_APPS_SETTINGS)
.addCategory(Intent.CATEGORY_DEFAULT)
.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK));
waitForIdle();
- waitFindObject(By.hasDescendant(By.text(APP_FOR_PROFILE))).click();
+ waitFindObject(By.hasDescendant(By.text(APP_CLONE))).click();
waitForIdle();
waitFindObject(By.clickable(true).hasDescendant(By.checkable(true).checked(false))
@@ -877,7 +889,7 @@ public class RoleManagerTest {
pressBack();
uninstallPackage(APP_PACKAGE_NAME, privateProfile);
- uninstallPackage(APP_FOR_PROFILE_APK_PATH, privateProfile);
+ uninstallPackage(APP_CLONE_PACKAGE_NAME, privateProfile);
}
@Test
diff --git a/tests/cts/role/src/android/app/role/cts/RoleShellCommandTest.kt b/tests/cts/role/src/android/app/role/cts/RoleShellCommandTest.kt
index 7e58e1848..83d4f78ad 100644
--- a/tests/cts/role/src/android/app/role/cts/RoleShellCommandTest.kt
+++ b/tests/cts/role/src/android/app/role/cts/RoleShellCommandTest.kt
@@ -44,7 +44,20 @@ class RoleShellCommandTest {
private var wasBypassingRoleQualification: Boolean = false
@Before
- fun saveRoleHolder() {
+ public fun setUp() {
+ saveRoleHolder()
+ saveBypassingRoleQualification()
+ installApp()
+ }
+
+ @After
+ public fun tearDown() {
+ uninstallApp()
+ restoreBypassingRoleQualification()
+ restoreRoleHolder()
+ }
+
+ private fun saveRoleHolder() {
roleHolder = getRoleHolders().firstOrNull()
if (roleHolder == APP_PACKAGE_NAME) {
removeRoleHolder()
@@ -52,31 +65,30 @@ class RoleShellCommandTest {
}
}
- @Before
- fun saveBypassingRoleQualification() {
+ private fun saveBypassingRoleQualification() {
wasBypassingRoleQualification = isBypassingRoleQualification()
}
- @After
- fun restoreRoleHolder() {
+ private fun restoreRoleHolder() {
removeRoleHolder()
roleHolder?.let { addRoleHolder(it) }
assertIsRoleHolder(false)
}
- @After
- fun restoreBypassingRoleQualification() {
+ private fun restoreBypassingRoleQualification() {
setBypassingRoleQualification(wasBypassingRoleQualification)
}
- @Before
- fun installApp() {
+ private fun installApp() {
installPackage(APP_APK_PATH)
+ // Install CtsRoleTestAppClone as default role holder for browser role
+ // in case no browser is installed on system
+ installPackage(APP_CLONE_APK_PATH)
}
- @After
- fun uninstallApp() {
+ private fun uninstallApp() {
uninstallPackage(APP_PACKAGE_NAME)
+ uninstallPackage(APP_CLONE_PACKAGE_NAME)
}
@Test
@@ -196,5 +208,7 @@ class RoleShellCommandTest {
private const val ROLE_NAME = RoleManager.ROLE_BROWSER
private const val APP_APK_PATH = "/data/local/tmp/cts-role/CtsRoleTestApp.apk"
private const val APP_PACKAGE_NAME = "android.app.role.cts.app"
+ private const val APP_CLONE_APK_PATH = "/data/local/tmp/cts-role/CtsRoleTestAppClone.apk"
+ private const val APP_CLONE_PACKAGE_NAME = "android.app.role.cts.appClone"
}
}
diff --git a/tests/functional/safetycenter/multiusers/src/android/safetycenter/functional/multiusers/SafetyCenterMultiUsersTest.kt b/tests/functional/safetycenter/multiusers/src/android/safetycenter/functional/multiusers/SafetyCenterMultiUsersTest.kt
index ff5dcc1f6..7c2062e8d 100644
--- a/tests/functional/safetycenter/multiusers/src/android/safetycenter/functional/multiusers/SafetyCenterMultiUsersTest.kt
+++ b/tests/functional/safetycenter/multiusers/src/android/safetycenter/functional/multiusers/SafetyCenterMultiUsersTest.kt
@@ -43,11 +43,11 @@ import androidx.test.core.app.ApplicationProvider
import androidx.test.filters.LargeTest
import com.android.bedstead.harrier.BedsteadJUnit4
import com.android.bedstead.harrier.DeviceState
-import com.android.bedstead.harrier.annotations.EnsureHasAdditionalUser
-import com.android.bedstead.harrier.annotations.EnsureHasCloneProfile
+import com.android.bedstead.multiuser.annotations.EnsureHasAdditionalUser
+import com.android.bedstead.multiuser.annotations.EnsureHasCloneProfile
import com.android.bedstead.enterprise.annotations.EnsureHasNoWorkProfile
-import com.android.bedstead.harrier.annotations.EnsureHasPrivateProfile
-import com.android.bedstead.harrier.annotations.EnsureHasNoPrivateProfile
+import com.android.bedstead.multiuser.annotations.EnsureHasPrivateProfile
+import com.android.bedstead.multiuser.annotations.EnsureHasNoPrivateProfile
import com.android.bedstead.enterprise.annotations.EnsureHasWorkProfile
import com.android.bedstead.enterprise.annotations.EnsureHasDeviceOwner
import com.android.bedstead.enterprise.annotations.EnsureHasNoDeviceOwner