summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--PermissionController/Android.bp1
-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-b+sr+Latn/strings.xml2
-rw-r--r--PermissionController/res/values-de-v35/strings.xml20
-rw-r--r--PermissionController/res/values-el/strings.xml12
-rw-r--r--PermissionController/res/values-es-rUS-v35/strings.xml20
-rw-r--r--PermissionController/res/values-es/strings.xml2
-rw-r--r--PermissionController/res/values-eu/strings.xml2
-rw-r--r--PermissionController/res/values-fa/strings.xml6
-rw-r--r--PermissionController/res/values-fr-v35/strings.xml20
-rw-r--r--PermissionController/res/values-fr/strings.xml2
-rw-r--r--PermissionController/res/values-hi/strings.xml4
-rw-r--r--PermissionController/res/values-in-watch/strings.xml8
-rw-r--r--PermissionController/res/values-in/strings.xml2
-rw-r--r--PermissionController/res/values-it-v35/strings.xml20
-rw-r--r--PermissionController/res/values-iw/strings.xml2
-rw-r--r--PermissionController/res/values-mr/strings.xml2
-rw-r--r--PermissionController/res/values-my/strings.xml2
-rw-r--r--PermissionController/res/values-sr/strings.xml2
-rw-r--r--PermissionController/res/values-sv/strings.xml2
-rw-r--r--PermissionController/res/values-v35/styles.xml216
-rw-r--r--PermissionController/res/values-watch/donottranslate.xml51
-rw-r--r--PermissionController/res/values/bools.xml1
-rw-r--r--PermissionController/res/values/overlayable.xml101
-rw-r--r--PermissionController/res/xml-v35/app_permission.xml (renamed from PermissionController/res/xml/app_permission.xml)32
-rw-r--r--PermissionController/res/xml/roles.xml1
-rw-r--r--PermissionController/role-controller/java/com/android/role/controller/model/AppOp.java4
-rw-r--r--PermissionController/role-controller/java/com/android/role/controller/model/Permissions.java9
-rw-r--r--PermissionController/role-controller/java/com/android/role/controller/model/Role.java29
-rw-r--r--PermissionController/role-controller/java/com/android/role/controller/model/RoleParser.java215
-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/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.java13
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/ui/handheld/v36/PermissionSelectorWithWidgetPreference.kt (renamed from PermissionController/src/com/android/permissioncontroller/permission/ui/handheld/PermissionSelectorWithWidgetPreference.kt)16
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/ui/handheld/v36/PermissionTwoTargetPreference.kt (renamed from PermissionController/src/com/android/permissioncontroller/permission/ui/handheld/PermissionTwoTargetPreference.kt)10
-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/ui/wear/theme/ResourceHelper.kt53
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/ui/wear/theme/WearComposeMaterial3ColorScheme.kt179
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/ui/wear/theme/WearComposeMaterial3Shapes.kt66
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/ui/wear/theme/WearComposeMaterial3TypeScaleTokens.kt109
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/ui/wear/theme/WearComposeMaterial3Typography.kt240
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/ui/wear/theme/WearComposeMaterial3VariableFontTokens.kt186
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/ui/wear/theme/WearOverlayableMaterial3Theme.kt37
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/ui/wear/theme/WearPermissionTheme.kt17
-rw-r--r--PermissionController/src/com/android/permissioncontroller/role/Role.md7
-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--PermissionController/tests/mocking/src/com/android/permissioncontroller/tests/mocking/role/model/RoleParserTest.kt154
-rw-r--r--SafetyCenter/Resources/Android.bp1
-rw-r--r--SafetyCenter/Resources/res/values-ar/strings.xml2
-rw-r--r--flags/Android.bp1
-rw-r--r--flags/flags.aconfig18
-rw-r--r--tests/cts/permissionmultiuser/AndroidTest.xml4
-rw-r--r--tests/cts/permissionmultiuser/src/android/permissionmultiuser/cts/AppDataSharingUpdatesTest.kt4
-rw-r--r--tests/cts/permissionpolicy/res/raw/android_manifest.xml23
-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
78 files changed, 2398 insertions, 1142 deletions
diff --git a/PermissionController/Android.bp b/PermissionController/Android.bp
index 21d6f4774..596b2dbb5 100644
--- a/PermissionController/Android.bp
+++ b/PermissionController/Android.bp
@@ -158,6 +158,7 @@ android_library {
"androidx.compose.runtime_runtime-livedata",
"androidx.compose.ui_ui",
"androidx.wear.compose_compose-material",
+ "androidx.wear.compose_compose-material3",
"android.content.pm.flags-aconfig-java-export",
"android.os.flags-aconfig-java-export",
],
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-b+sr+Latn/strings.xml b/PermissionController/res/values-b+sr+Latn/strings.xml
index 8215737c7..546b3183b 100644
--- a/PermissionController/res/values-b+sr+Latn/strings.xml
+++ b/PermissionController/res/values-b+sr+Latn/strings.xml
@@ -471,7 +471,7 @@
<string name="permgrouprequest_device_aware_storage_isolated" msgid="6463062962458809752">"Dozvoljavate da aplikacija &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; pristupa slikama i medijima na: &lt;b&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequest_contacts" msgid="8391550064551053695">"Želite da dozvolite da &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; pristupa kontaktima?"</string>
<string name="permgrouprequest_device_aware_contacts" msgid="731025863972535928">"Dozvoljavate da aplikacija &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; pristupa kontaktima na: &lt;b&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/b&gt;?"</string>
- <string name="permgrouprequest_location" msgid="6990232580121067883">"Želite da dozvolite da &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; pristupa lokaciji ovog uređaja?"</string>
+ <string name="permgrouprequest_location" msgid="6990232580121067883">"Želite da dozvolite da aplikacija &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; pristupa lokaciji ovog uređaja?"</string>
<string name="permgrouprequest_device_aware_location" msgid="6075412127429878638">"Dozvoljavate da aplikacija &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; pristupa lokaciji uređaja &lt;b&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequestdetail_location" msgid="2635935335778429894">"Aplikacija će imati pristup lokaciji samo dok koristite aplikaciju"</string>
<string name="permgroupbackgroundrequest_location" msgid="1085680897265734809">"Želite da dozvolite da &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; pristupa lokaciji ovog uređaja?"</string>
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/strings.xml b/PermissionController/res/values-el/strings.xml
index a3d62412f..a0982e7a9 100644
--- a/PermissionController/res/values-el/strings.xml
+++ b/PermissionController/res/values-el/strings.xml
@@ -256,7 +256,7 @@
<string name="allowed_storage_scoped" msgid="5383645873719086975">"Επιτρέπεται η πρόσβαση μόνο σε μέσα"</string>
<string name="allowed_storage_full" msgid="5356699280625693530">"Επιτρέπεται η διαχείριση όλων των αρχείων"</string>
<string name="ask_header" msgid="2633816846459944376">"Ερώτηση κάθε φορά"</string>
- <string name="denied_header" msgid="903209608358177654">"Δεν επιτρέπεται"</string>
+ <string name="denied_header" msgid="903209608358177654">"Δεν επιτρέπονται"</string>
<string name="permission_group_name_with_device_name" msgid="8798741850536024820">"<xliff:g id="PERM_GROUP_NAME">%1$s</xliff:g> στη συσκευή <xliff:g id="DEVICE_NAME">%2$s</xliff:g>"</string>
<string name="storage_footer_hyperlink_text" msgid="8873343987957834810">"Δείτε περισσότερες εφαρμογές με πρόσβαση σε όλα τα αρχεία"</string>
<string name="days" msgid="609563020985571393">"{count,plural, =1{1 ημέρα}other{# ημέρες}}"</string>
@@ -471,7 +471,7 @@
<string name="permgrouprequest_device_aware_storage_isolated" msgid="6463062962458809752">"Να επιτρέπεται στην εφαρμογή &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; η πρόσβαση σε φωτογραφίες και μέσα στη συσκευή &lt;b&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/b&gt;;"</string>
<string name="permgrouprequest_contacts" msgid="8391550064551053695">"Να επιτρέπεται στο &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; να έχει πρόσβαση στις επαφές σας;"</string>
<string name="permgrouprequest_device_aware_contacts" msgid="731025863972535928">"Να επιτρέπεται στην εφαρμογή &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; η πρόσβαση στις επαφές σας στη συσκευή &lt;b&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/b&gt;;"</string>
- <string name="permgrouprequest_location" msgid="6990232580121067883">"Να επιτρέπεται στο &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; η πρόσβαση στην τοποθεσία αυτής της συσκευής;"</string>
+ <string name="permgrouprequest_location" msgid="6990232580121067883">"Να επιτρέπεται στην εφαρμογή &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; η πρόσβαση στην τοποθεσία αυτής της συσκευής;"</string>
<string name="permgrouprequest_device_aware_location" msgid="6075412127429878638">"Να επιτρέπεται στην εφαρμογή &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; η πρόσβαση στην τοποθεσία της συσκευής &lt;b&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>’s&lt;/b&gt;;"</string>
<string name="permgrouprequestdetail_location" msgid="2635935335778429894">"Η εφαρμογή θα έχει πρόσβαση στην τοποθεσία μόνο κατά τη διάρκεια χρήσης της εφαρμογής"</string>
<string name="permgroupbackgroundrequest_location" msgid="1085680897265734809">"Να επιτρέπεται στο &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; να έχει πρόσβαση στην τοποθεσία αυτής της συσκευής;"</string>
@@ -503,11 +503,11 @@
<string name="permgrouprequest_device_aware_read_media_visual" msgid="3122576538319059333">"Να επιτρέπεται στην εφαρμογή &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; η πρόσβαση σε φωτογραφίες και σε βίντεο στη συσκευή &lt;b&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/b&gt;;"</string>
<string name="permgrouprequest_more_photos" msgid="128933814654231321">"Να επιτρέπεται στην εφαρμογή &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; η πρόσβαση σε περισσότερες φωτογραφίες και βίντεο αυτής της συσκευής;"</string>
<string name="permgrouprequest_device_aware_more_photos" msgid="1703469013613723053">"Να επιτρέπεται στην εφαρμογή &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; η πρόσβαση σε περισσότερες φωτογραφίες και βίντεο στη συσκευή &lt;b&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/b&gt;;"</string>
- <string name="permgrouprequest_microphone" msgid="2825208549114811299">"Να επιτρέπεται στο &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; η εγγραφή ήχου;"</string>
- <string name="permgrouprequest_device_aware_microphone" msgid="8821701550505437951">"Να επιτρέπεται στην εφαρμογή &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; η εγγραφή ήχου στη συσκευή &lt;b&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/b&gt;;"</string>
+ <string name="permgrouprequest_microphone" msgid="2825208549114811299">"Να επιτρέπεται στο &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; η ηχογράφηση;"</string>
+ <string name="permgrouprequest_device_aware_microphone" msgid="8821701550505437951">"Να επιτρέπεται στην εφαρμογή &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; η ηχογράφηση στη συσκευή &lt;b&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/b&gt;;"</string>
<string name="permgrouprequestdetail_microphone" msgid="8510456971528228861">"Αυτή η εφαρμογή θα μπορεί να εγγράφει ήχο μόνο όταν τη χρησιμοποιείτε"</string>
- <string name="permgroupbackgroundrequest_microphone" msgid="8874462606796368183">"Να επιτρέπεται στο &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; η εγγραφή ήχου;"</string>
- <string name="permgroupbackgroundrequest_device_aware_microphone" msgid="3321823187623762958">"Να επιτρέπεται στην εφαρμογή &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; η εγγραφή ήχου στη συσκευή &lt;b&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/b&gt;;"</string>
+ <string name="permgroupbackgroundrequest_microphone" msgid="8874462606796368183">"Να επιτρέπεται στο &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; η ηχογράφηση;"</string>
+ <string name="permgroupbackgroundrequest_device_aware_microphone" msgid="3321823187623762958">"Να επιτρέπεται στην εφαρμογή &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; η ηχογράφηση στη συσκευή &lt;b&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/b&gt;;"</string>
<string name="permgroupbackgroundrequestdetail_microphone" msgid="553702902263681838">"Αυτή η εφαρμογή ενδέχεται να εγγράφει βίντεο συνεχώς, ακόμη και όταν δεν τη χρησιμοποιείτε. "<annotation id="link">"Έγκριση στις ρυθμίσεις."</annotation></string>
<string name="permgroupupgraderequest_microphone" msgid="1362781696161233341">"Αλλαγή πρόσβασης στο μικρόφωνο για την εφαρμογή &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;;"</string>
<string name="permgroupupgraderequest_device_aware_microphone" msgid="8722411173971679806">"Να γίνει αλλαγή της πρόσβασης μικροφώνου για την εφαρμογή &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; στη συσκευή &lt;b&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/b&gt;;"</string>
diff --git a/PermissionController/res/values-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/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-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/strings.xml b/PermissionController/res/values-fa/strings.xml
index 607745eeb..49f4a86d7 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>
@@ -471,7 +471,7 @@
<string name="permgrouprequest_device_aware_storage_isolated" msgid="6463062962458809752">"به «<xliff:g id="APP_NAME">%1$s</xliff:g>» اجازه می‌دهید به عکس‌ها و رسانه‌های «<xliff:g id="DEVICE_NAME">%2$s</xliff:g>» دسترسی داشته باشد؟"</string>
<string name="permgrouprequest_contacts" msgid="8391550064551053695">"‏به &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; اجازه دسترسی به مخاطبینتان می‌دهید؟"</string>
<string name="permgrouprequest_device_aware_contacts" msgid="731025863972535928">"به «<xliff:g id="APP_NAME">%1$s</xliff:g>» اجازه می‌دهید به مخاطبین شما در «<xliff:g id="DEVICE_NAME">%2$s</xliff:g>» دسترسی داشته باشد؟"</string>
- <string name="permgrouprequest_location" msgid="6990232580121067883">"‏به &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; اجازه دسترسی به مکان این دستگاه می‌دهید؟"</string>
+ <string name="permgrouprequest_location" msgid="6990232580121067883">"‏به &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; اجازه دسترسی به مکان این دستگاه را می‌دهید؟"</string>
<string name="permgrouprequest_device_aware_location" msgid="6075412127429878638">"به «<xliff:g id="APP_NAME">%1$s</xliff:g>» اجازه می‌دهید به مکان «<xliff:g id="DEVICE_NAME">%2$s</xliff:g>» دسترسی داشته باشد؟"</string>
<string name="permgrouprequestdetail_location" msgid="2635935335778429894">"این برنامه فقط وقتی از آن استفاده می‌کنید، به مکان دسترسی خواهد داشت"</string>
<string name="permgroupbackgroundrequest_location" msgid="1085680897265734809">"‏به &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; اجازه داده شود به مکان این دستگاه دسترسی پیدا کند؟"</string>
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-fr/strings.xml b/PermissionController/res/values-fr/strings.xml
index 4f2fc806c..2ea77b4f4 100644
--- a/PermissionController/res/values-fr/strings.xml
+++ b/PermissionController/res/values-fr/strings.xml
@@ -369,7 +369,7 @@
<string name="role_dialer_search_keywords" msgid="3324448983559188087">"clavier"</string>
<string name="role_sms_label" msgid="8456999857547686640">"Appli de SMS par défaut"</string>
<string name="role_sms_short_label" msgid="4371444488034692243">"Appli de SMS"</string>
- <string name="role_sms_description" msgid="3424020199148153513">"Applications qui vous permettent d\'utiliser votre numéro de téléphone pour envoyer et recevoir des SMS, des photos, des vidéos et plus encore"</string>
+ <string name="role_sms_description" msgid="3424020199148153513">"Applications qui vous permettent d\'utiliser votre numéro de téléphone pour envoyer et recevoir des messages, des photos, des vidéos et plus encore"</string>
<string name="role_sms_request_title" msgid="7953552109601185602">"Définir <xliff:g id="APP_NAME">%1$s</xliff:g> comme application par défaut pour les SMS ?"</string>
<string name="role_sms_request_description" msgid="2691004766132144886">"Cette appli aura accès à votre appareil photo, vos contacts, vos fichiers et contenus multimédias, votre micro, votre téléphone et vos SMS"</string>
<string name="role_sms_search_keywords" msgid="8022048144395047352">"SMS, envoyer un SMS, messages, message"</string>
diff --git a/PermissionController/res/values-hi/strings.xml b/PermissionController/res/values-hi/strings.xml
index 134a3d0f7..c612e43f6 100644
--- a/PermissionController/res/values-hi/strings.xml
+++ b/PermissionController/res/values-hi/strings.xml
@@ -74,13 +74,13 @@
<string name="days_ago" msgid="6650359081551335629">"{count,plural, =0{आज}=1{1 दिन पहले}one{# दिन पहले}other{# दिन पहले}}"</string>
<string name="app_disable_dlg_positive" msgid="7418444149981904940">"ऐप्लिकेशन बंद करें"</string>
<string name="app_disable_dlg_text" msgid="3126943217146120240">"अगर आप इस ऐप्लिकेशन को बंद कर देते हैं, तो हो सकता है कि Android और दूसरे ऐप्लिकेशन ठीक से काम न करें. ध्यान रखें कि आप इस ऐप्लिकेशन को मिटा नहीं सकते, क्योंकि यह आपके डिवाइस पर पहले से इंस्टॉल होकर आया है. इसे बंद करने पर ऐप्लिकेशन बंद हो जाएगा और आपके डिवाइस पर नहीं दिखेगा."</string>
- <string name="app_permission_manager" msgid="3903811137630909550">"अनुमतियों को मैनेज करना"</string>
+ <string name="app_permission_manager" msgid="3903811137630909550">"अनुमतियों को मैनेज करें"</string>
<string name="never_ask_again" msgid="4728762438198560329">"दोबारा न पूछें"</string>
<string name="no_permissions" msgid="3881676756371148563">"किसी अनुमति की ज़रूरत नहीं है"</string>
<string name="additional_permissions" msgid="5801285469338873430">"दूसरी अनुमतियां"</string>
<string name="app_permissions_info_button_label" msgid="7633312050729974623">"ऐप्लिकेशन के बारे में जानकारी देखें"</string>
<string name="additional_permissions_more" msgid="5681220714755304407">"{count,plural, =1{# और अनुमति}one{# और अनुमति}other{# और अनुमतियां}}"</string>
- <string name="old_sdk_deny_warning" msgid="2382236998845153919">"यह ऐप्लिकेशन Android के पुराने वर्शन के लिए बनाया गया था. अगर आप अनुमति नहीं देते हैं, तो हो सकता है कि यह ठीक तरह से काम न करे."</string>
+ <string name="old_sdk_deny_warning" msgid="2382236998845153919">"इस ऐप्लिकेशन को Android के पुराने वर्शन के लिए बनाया गया था. अगर अनुमति नहीं दी जाती है, तो हो सकता है कि यह ठीक तरह से काम न करे."</string>
<string name="storage_supergroup_warning_allow" msgid="103093462784523190">"यह ऐप्लिकेशन, Android के पुराने वर्शन के लिए बनाया गया था. यह अनुमति देने पर, ऐप्लिकेशन को आपके डिवाइस में मौजूद सभी फ़ाइलों का ऐक्सेस मिल जाएगा. इसमें फ़ोटो, वीडियो, संगीत, ऑडियो, और दूसरी फ़ाइलें शामिल हैं."</string>
<string name="storage_supergroup_warning_deny" msgid="6420765672683284347">"यह ऐप्लिकेशन, Android के पुराने वर्शन के लिए बनाया गया था. यह अनुमति न देने पर, ऐप्लिकेशन को आपके डिवाइस में मौजूद किसी भी फ़ाइल का ऐक्सेस नहीं मिलेगा. इसमें फ़ोटो, वीडियो, संगीत, ऑडियो, और दूसरी फ़ाइलें शामिल हैं."</string>
<string name="default_permission_description" msgid="4624464917726285203">"ऐसी कार्रवाई करें जिसकी जानकारी नहीं है"</string>
diff --git a/PermissionController/res/values-in-watch/strings.xml b/PermissionController/res/values-in-watch/strings.xml
index c124feda4..4f72c0154 100644
--- a/PermissionController/res/values-in-watch/strings.xml
+++ b/PermissionController/res/values-in-watch/strings.xml
@@ -22,11 +22,11 @@
<string name="permission_summary_enforced_by_policy" msgid="2352478756952948019">"Tidak dapat diubah"</string>
<string name="generic_yes" msgid="2489207724988649846">"Ya"</string>
<string name="generic_cancel" msgid="2631708607129269698">"Batal"</string>
- <string name="permission_access_always" msgid="2107115233573823032">"Semua"</string>
+ <string name="permission_access_always" msgid="2107115233573823032">"Sepanjang waktu"</string>
<string name="permission_access_only_foreground" msgid="4412115020089923986">"Saat menggunakan aplikasi"</string>
- <string name="app_permission_button_allow_always" msgid="4920899432212307102">"Semua"</string>
+ <string name="app_permission_button_allow_always" msgid="4920899432212307102">"Sepanjang waktu"</string>
<string name="app_permission_button_allow_foreground" msgid="7186980598244864830">"Saat menggunakan aplikasi"</string>
- <string name="grant_dialog_button_allow_always" msgid="7130695257254694576">"Semua"</string>
+ <string name="grant_dialog_button_allow_always" msgid="7130695257254694576">"Sepanjang waktu"</string>
<string name="grant_dialog_button_allow_foreground" msgid="8917595344037255090">"Saat menggunakan aplikasi"</string>
- <string name="grant_dialog_button_allow_background" msgid="6104993390936535493">"Semua"</string>
+ <string name="grant_dialog_button_allow_background" msgid="6104993390936535493">"Sepanjang waktu"</string>
</resources>
diff --git a/PermissionController/res/values-in/strings.xml b/PermissionController/res/values-in/strings.xml
index 4604dbaef..e409aabd9 100644
--- a/PermissionController/res/values-in/strings.xml
+++ b/PermissionController/res/values-in/strings.xml
@@ -80,7 +80,7 @@
<string name="additional_permissions" msgid="5801285469338873430">"Izin tambahan"</string>
<string name="app_permissions_info_button_label" msgid="7633312050729974623">"Buka info aplikasi"</string>
<string name="additional_permissions_more" msgid="5681220714755304407">"{count,plural, =1{# lainnya}other{# lainnya}}"</string>
- <string name="old_sdk_deny_warning" msgid="2382236998845153919">"Aplikasi ini dirancang untuk versi lama Android. Menolak izin dapat menyebabkan aplikasi tidak berfungsi lagi sesuai harapan."</string>
+ <string name="old_sdk_deny_warning" msgid="2382236998845153919">"Aplikasi ini dirancang untuk versi lama Android. Menolak izin dapat membuat aplikasi tidak lagi berfungsi sebagaimana mestinya."</string>
<string name="storage_supergroup_warning_allow" msgid="103093462784523190">"Aplikasi ini dirancang untuk versi lama Android. Jika Anda memberikan izin ini, akses ke semua penyimpanan (termasuk foto, video, musik, audio, dan file lainnya) akan diizinkan."</string>
<string name="storage_supergroup_warning_deny" msgid="6420765672683284347">"Aplikasi ini dirancang untuk versi lama Android. Jika Anda menolak izin ini, akses ke semua penyimpanan (termasuk foto, video, musik, audio, dan file lainnya) akan ditolak."</string>
<string name="default_permission_description" msgid="4624464917726285203">"melakukan tindakan yang tidak dikenal"</string>
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/strings.xml b/PermissionController/res/values-iw/strings.xml
index 90536dcc8..a936d3e4e 100644
--- a/PermissionController/res/values-iw/strings.xml
+++ b/PermissionController/res/values-iw/strings.xml
@@ -471,7 +471,7 @@
<string name="permgrouprequest_device_aware_storage_isolated" msgid="6463062962458809752">"‏לתת לאפליקציה &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; הרשאת גישה לתמונות ולמדיה במכשיר &lt;b&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequest_contacts" msgid="8391550064551053695">"‏לתת לאפליקציה &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; הרשאת גישה לאנשי הקשר שלך?"</string>
<string name="permgrouprequest_device_aware_contacts" msgid="731025863972535928">"‏לתת לאפליקציה &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; הרשאת גישה לאנשי הקשר במכשיר &lt;b&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/b&gt;?"</string>
- <string name="permgrouprequest_location" msgid="6990232580121067883">"‏לתת לאפליקציה &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; הרשאת גישה למיקום המכשיר?"</string>
+ <string name="permgrouprequest_location" msgid="6990232580121067883">"‏לתת לאפליקציה \'&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;\' הרשאת גישה למיקום המכשיר?"</string>
<string name="permgrouprequest_device_aware_location" msgid="6075412127429878638">"‏לתת לאפליקציה &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; הרשאת גישה למיקום של &lt;b&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequestdetail_location" msgid="2635935335778429894">"לאפליקציה תהיה גישה אל נתוני המיקום רק בזמן השימוש בה"</string>
<string name="permgroupbackgroundrequest_location" msgid="1085680897265734809">"‏לתת לאפליקציה &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; הרשאת גישה למיקום המכשיר?"</string>
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-my/strings.xml b/PermissionController/res/values-my/strings.xml
index 0bd62801c..b29ee2286 100644
--- a/PermissionController/res/values-my/strings.xml
+++ b/PermissionController/res/values-my/strings.xml
@@ -195,7 +195,7 @@
<string name="app_permission_button_allow_limited_access" msgid="8824410215149764113">"ကန့်သတ်သုံးခြင်းကို ခွင့်ပြုရန်"</string>
<string name="precise_image_description" msgid="6349638632303619872">"နေရာအတိအကျ"</string>
<string name="approximate_image_description" msgid="938803699637069884">"တည်နေရာခန့်မှန်းခြေ"</string>
- <string name="app_permission_location_accuracy" msgid="7166912915040018669">"နေရာအတိအကျကို သုံးခြင်း"</string>
+ <string name="app_permission_location_accuracy" msgid="7166912915040018669">"နေရာအတိအကျ သုံးရန်"</string>
<string name="app_permission_location_accuracy_subtitle" msgid="2654077606404987210">"နေရာအတိအကျကို ပိတ်ထားသည့်အခါ အက်ပ်များက သင်၏တည်နေရာခန့်မှန်းခြေကို သုံးနိုင်သည်"</string>
<string name="app_permission_title" msgid="2090897901051370711">"<xliff:g id="PERM">%1$s</xliff:g> ခွင့်ပြုချက်"</string>
<string name="app_permission_header" msgid="2951363137032603806">"ဤအက်ပ်အတွက် <xliff:g id="PERM">%1$s</xliff:g> အသုံးပြုခွင့်"</string>
diff --git a/PermissionController/res/values-sr/strings.xml b/PermissionController/res/values-sr/strings.xml
index 957c026e6..1f8085a95 100644
--- a/PermissionController/res/values-sr/strings.xml
+++ b/PermissionController/res/values-sr/strings.xml
@@ -471,7 +471,7 @@
<string name="permgrouprequest_device_aware_storage_isolated" msgid="6463062962458809752">"Дозвољавате да апликација &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; приступа сликама и медијима на: &lt;b&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequest_contacts" msgid="8391550064551053695">"Желите да дозволите да &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; приступа контактима?"</string>
<string name="permgrouprequest_device_aware_contacts" msgid="731025863972535928">"Дозвољавате да апликација &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; приступа контактима на: &lt;b&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/b&gt;?"</string>
- <string name="permgrouprequest_location" msgid="6990232580121067883">"Желите да дозволите да &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; приступа локацији овог уређаја?"</string>
+ <string name="permgrouprequest_location" msgid="6990232580121067883">"Желите да дозволите да апликација &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; приступа локацији овог уређаја?"</string>
<string name="permgrouprequest_device_aware_location" msgid="6075412127429878638">"Дозвољавате да апликација &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; приступа локацији уређаја &lt;b&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequestdetail_location" msgid="2635935335778429894">"Апликација ће имати приступ локацији само док користите апликацију"</string>
<string name="permgroupbackgroundrequest_location" msgid="1085680897265734809">"Желите да дозволите да &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; приступа локацији овог уређаја?"</string>
diff --git a/PermissionController/res/values-sv/strings.xml b/PermissionController/res/values-sv/strings.xml
index 67f8b34f8..937a12200 100644
--- a/PermissionController/res/values-sv/strings.xml
+++ b/PermissionController/res/values-sv/strings.xml
@@ -437,7 +437,7 @@
<string name="default_apps_more" msgid="4078194675848858093">"Fler standardappar"</string>
<string name="default_apps_manage_domain_urls" msgid="6775566451561036069">"Öppna länkar"</string>
<string name="default_apps_for_work" msgid="4970308943596201811">"Standardinställning för jobbet"</string>
- <string name="default_apps_for_private_profile" msgid="2022024112144880785">"Standard för privat område"</string>
+ <string name="default_apps_for_private_profile" msgid="2022024112144880785">"Standard för privat utrymme"</string>
<string name="default_app_none" msgid="9084592086808194457">"Ingen"</string>
<string name="default_app_system_default" msgid="6218386768175513760">"(System­standard)"</string>
<string name="default_app_no_apps" msgid="115720991680586885">"Inga appar"</string>
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-watch/donottranslate.xml b/PermissionController/res/values-watch/donottranslate.xml
index c3ab3cbb1..309c51388 100644
--- a/PermissionController/res/values-watch/donottranslate.xml
+++ b/PermissionController/res/values-watch/donottranslate.xml
@@ -28,4 +28,55 @@
<string name="wear_material_compose_caption_1_font_family">font-family-text-medium-device-default</string>
<string name="wear_material_compose_caption_2_font_family">font-family-text-medium-device-default</string>
<string name="wear_material_compose_caption_3_font_family">font-family-text-medium-device-default</string>
+
+ <string name="wear_compose_material3_arc_small_font_family">font-family-flex-device-default</string>
+ <string name="wear_compose_material3_arc_medium_font_family">font-family-flex-device-default</string>
+ <string name="wear_compose_material3_arc_large_font_family">font-family-flex-device-default</string>
+ <string name="wear_compose_material3_body_extra_small_font_family">font-family-flex-device-default</string>
+ <string name="wear_compose_material3_body_small_font_family">font-family-flex-device-default</string>
+ <string name="wear_compose_material3_body_medium_font_family">font-family-flex-device-default</string>
+ <string name="wear_compose_material3_body_large_font_family">font-family-flex-device-default</string>
+ <string name="wear_compose_material3_display_small_font_family">font-family-flex-device-default</string>
+ <string name="wear_compose_material3_display_medium_font_family">font-family-flex-device-default</string>
+ <string name="wear_compose_material3_display_large_font_family">font-family-flex-device-default</string>
+ <string name="wear_compose_material3_label_small_font_family">font-family-flex-device-default</string>
+ <string name="wear_compose_material3_label_medium_font_family">font-family-flex-device-default</string>
+ <string name="wear_compose_material3_label_large_font_family">font-family-flex-device-default</string>
+ <string name="wear_compose_material3_numeral_extra_small_font_family">font-family-flex-device-default</string>
+ <string name="wear_compose_material3_numeral_small_font_family">font-family-flex-device-default</string>
+ <string name="wear_compose_material3_numeral_medium_font_family">font-family-flex-device-default</string>
+ <string name="wear_compose_material3_numeral_large_font_family">font-family-flex-device-default</string>
+ <string name="wear_compose_material3_numeral_extra_large_font_family">font-family-flex-device-default</string>
+ <string name="wear_compose_material3_title_small_font_family">font-family-flex-device-default</string>
+ <string name="wear_compose_material3_title_medium_font_family">font-family-flex-device-default</string>
+ <string name="wear_compose_material3_title_large_font_family">font-family-flex-device-default</string>
+
+ <dimen name="wear_compose_material3_arc_small_font_size">14</dimen>
+ <dimen name="wear_compose_material3_arc_medium_font_size">15</dimen>
+ <dimen name="wear_compose_material3_arc_large_font_size">20</dimen>
+ <dimen name="wear_compose_material3_body_extra_small_font_size">10</dimen>
+ <dimen name="wear_compose_material3_body_small_font_size">12</dimen>
+ <dimen name="wear_compose_material3_body_medium_font_size">14</dimen>
+ <dimen name="wear_compose_material3_body_large_font_size">16</dimen>
+ <dimen name="wear_compose_material3_display_small_font_size">24</dimen>
+ <dimen name="wear_compose_material3_display_medium_font_size">30</dimen>
+ <dimen name="wear_compose_material3_display_large_font_size">40</dimen>
+ <dimen name="wear_compose_material3_label_small_font_size">13</dimen>
+ <dimen name="wear_compose_material3_label_medium_font_size">15</dimen>
+ <dimen name="wear_compose_material3_label_large_font_size">20</dimen>
+ <dimen name="wear_compose_material3_numeral_extra_small_font_size">24</dimen>
+ <dimen name="wear_compose_material3_numeral_small_font_size">30</dimen>
+ <dimen name="wear_compose_material3_numeral_medium_font_size">40</dimen>
+ <dimen name="wear_compose_material3_numeral_large_font_size">50</dimen>
+ <dimen name="wear_compose_material3_numeral_extra_large_font_size">60</dimen>
+ <dimen name="wear_compose_material3_title_small_font_size">14</dimen>
+ <dimen name="wear_compose_material3_title_medium_font_size">16</dimen>
+ <dimen name="wear_compose_material3_title_large_font_size">20</dimen>
+
+ <dimen name="wear_compose_material3_shape_corner_extra_small_size">4</dimen>
+ <dimen name="wear_compose_material3_shape_corner_small_size">8</dimen>
+ <dimen name="wear_compose_material3_shape_corner_medium_size">18</dimen>
+ <dimen name="wear_compose_material3_shape_corner_large_size">26</dimen>
+ <dimen name="wear_compose_material3_shape_corner_extra_large_size">36</dimen>
+
</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..510bb900f 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" />
@@ -431,7 +460,7 @@
<item type="style" name="AppDataSharingUpdateSettingsIcon" />
<!-- END SAFETY LABELS STYLE -->
- <!--START WEAR SPECIFIC FONT STRINGS -->
+ <!--START WEAR SPECIFIC MATERIAL2 FONT STRINGS -->
<item type="string" name="wear_material_compose_display_1_font_family" />
<item type="string" name="wear_material_compose_display_2_font_family" />
<item type="string" name="wear_material_compose_display_3_font_family" />
@@ -444,7 +473,75 @@
<item type="string" name="wear_material_compose_caption_1_font_family" />
<item type="string" name="wear_material_compose_caption_2_font_family" />
<item type="string" name="wear_material_compose_caption_3_font_family" />
- <!--END WEAR SPECIFIC FONT STRINGS -->
+ <!--END WEAR SPECIFIC MATERIAL2 FONT STRINGS -->
+
+ <!--START WEAR SPECIFIC MATERIAL3 FONT FACE TOKENS-->
+ <item type="string" name="wear_compose_material3_arc_small_font_family" />
+ <item type="string" name="wear_compose_material3_arc_medium_font_family" />
+ <item type="string" name="wear_compose_material3_arc_large_font_family" />
+
+ <item type="string" name="wear_compose_material3_body_extra_small_font_family" />
+ <item type="string" name="wear_compose_material3_body_small_font_family" />
+ <item type="string" name="wear_compose_material3_body_medium_font_family" />
+ <item type="string" name="wear_compose_material3_body_large_font_family" />
+
+ <item type="string" name="wear_compose_material3_display_small_font_family" />
+ <item type="string" name="wear_compose_material3_display_medium_font_family" />
+ <item type="string" name="wear_compose_material3_display_large_font_family" />
+
+ <item type="string" name="wear_compose_material3_label_small_font_family" />
+ <item type="string" name="wear_compose_material3_label_medium_font_family" />
+ <item type="string" name="wear_compose_material3_label_large_font_family" />
+
+ <item type="string" name="wear_compose_material3_numeral_extra_small_font_family" />
+ <item type="string" name="wear_compose_material3_numeral_small_font_family" />
+ <item type="string" name="wear_compose_material3_numeral_medium_font_family" />
+ <item type="string" name="wear_compose_material3_numeral_large_font_family" />
+ <item type="string" name="wear_compose_material3_numeral_extra_large_font_family" />
+
+ <item type="string" name="wear_compose_material3_title_small_font_family" />
+ <item type="string" name="wear_compose_material3_title_medium_font_family" />
+ <item type="string" name="wear_compose_material3_title_large_font_family" />
+ <!--END WEAR SPECIFIC MATERIAL3 FONT FACE TOKENS-->
+
+
+ <!--START WEAR SPECIFIC MATERIAL3 FONT SIZE TOKENS-->
+ <item type="dimen" name="wear_compose_material3_arc_small_font_size" />
+ <item type="dimen" name="wear_compose_material3_arc_medium_font_size" />
+ <item type="dimen" name="wear_compose_material3_arc_large_font_size" />
+
+ <item type="dimen" name="wear_compose_material3_body_extra_small_font_size" />
+ <item type="dimen" name="wear_compose_material3_body_small_font_size" />
+ <item type="dimen" name="wear_compose_material3_body_medium_font_size" />
+ <item type="dimen" name="wear_compose_material3_body_large_font_size" />
+
+ <item type="dimen" name="wear_compose_material3_display_small_font_size" />
+ <item type="dimen" name="wear_compose_material3_display_medium_font_size" />
+ <item type="dimen" name="wear_compose_material3_display_large_font_size" />
+
+ <item type="dimen" name="wear_compose_material3_label_small_font_size" />
+ <item type="dimen" name="wear_compose_material3_label_medium_font_size" />
+ <item type="dimen" name="wear_compose_material3_label_large_font_size" />
+
+ <item type="dimen" name="wear_compose_material3_numeral_extra_small_font_size" />
+ <item type="dimen" name="wear_compose_material3_numeral_small_font_size" />
+ <item type="dimen" name="wear_compose_material3_numeral_medium_font_size" />
+ <item type="dimen" name="wear_compose_material3_numeral_large_font_size" />
+ <item type="dimen" name="wear_compose_material3_numeral_extra_large_font_size" />
+
+ <item type="dimen" name="wear_compose_material3_title_small_font_size" />
+ <item type="dimen" name="wear_compose_material3_title_medium_font_size" />
+ <item type="dimen" name="wear_compose_material3_title_large_font_size" />
+ <!--END WEAR SPECIFIC MATERIAL3 FONT SIZE TOKENS-->
+
+ <!--START WEAR SPECIFIC MATERIAL3 SHAPE TOKENS-->
+ <item type="dimen" name="wear_compose_material3_shape_corner_extra_small_size" />
+ <item type="dimen" name="wear_compose_material3_shape_corner_small_size" />
+ <item type="dimen" name="wear_compose_material3_shape_corner_medium_size" />
+ <item type="dimen" name="wear_compose_material3_shape_corner_large_size" />
+ <item type="dimen" name="wear_compose_material3_shape_corner_extra_large_size" />
+ <!--END WEAR SPECIFIC MATERIAL3 SHAPE TOKENS-->
+
<!-- START ENHANCED CONFIRMATION DIALOG -->
<item type="style" name="Theme.EnhancedConfirmationDialog" />
diff --git a/PermissionController/res/xml/app_permission.xml b/PermissionController/res/xml-v35/app_permission.xml
index 5e6857185..87315815d 100644
--- a/PermissionController/res/xml/app_permission.xml
+++ b/PermissionController/res/xml-v35/app_permission.xml
@@ -19,46 +19,46 @@
android:key="app_permission_button_category"
android:title="@string/app_permission_header">
- <com.android.permissioncontroller.permission.ui.handheld.PermissionSelectorWithWidgetPreference
+ <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.PermissionSelectorWithWidgetPreference
+ <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.PermissionSelectorWithWidgetPreference
+ <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.PermissionSelectorWithWidgetPreference
+ <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.PermissionSelectorWithWidgetPreference
+ <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.PermissionSelectorWithWidgetPreference
+ <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.PermissionSelectorWithWidgetPreference
+ <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.PermissionSelectorWithWidgetPreference
+ <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" />
@@ -71,7 +71,7 @@
android:title="@string/app_permission_location_accuracy"
app:isPreferenceVisible="false" />
- <com.android.permissioncontroller.permission.ui.handheld.PermissionTwoTargetPreference
+ <com.android.permissioncontroller.permission.ui.handheld.v36.PermissionTwoTargetPreference
android:key="app_permission_details"
android:selectable="false"
android:summary="@string/permission_summary_enabled_system_fixed"
@@ -79,26 +79,24 @@
app:iconSpaceReserved="true"
app:isPreferenceVisible="false" />
- <com.android.permissioncontroller.permission.ui.handheld.PermissionPreference
+ <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.PermissionPreference
+ <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.PermissionPreference
+ <com.android.permissioncontroller.permission.ui.handheld.PermissionFooterPreference
android:key="app_permission_footer_storage_special_app_access"
android:icon="@drawable/ic_info_outline"
- android:selectable="false"
- android:summary="@string/app_permission_footer_special_file_access"
+ android:title="@string/app_permission_footer_special_file_access"
app:isPreferenceVisible="false" />
- <com.android.permissioncontroller.permission.ui.handheld.PermissionPreference
+ <com.android.permissioncontroller.permission.ui.handheld.PermissionFooterPreference
android:key="app_permission_additional_info"
android:icon="@drawable/ic_info_outline"
- android:selectable="false"
- android:summary="@string/exempt_info_label"
+ android:title="@string/exempt_info_label"
app:isPreferenceVisible="false" />
</PreferenceScreen>
diff --git a/PermissionController/res/xml/roles.xml b/PermissionController/res/xml/roles.xml
index 1d01f8208..ba4e80cf2 100644
--- a/PermissionController/res/xml/roles.xml
+++ b/PermissionController/res/xml/roles.xml
@@ -1281,6 +1281,7 @@
name="android.app.role.SYSTEM_SUPERVISION"
defaultHolders="config_systemSupervision"
exclusive="true"
+ ignoreDisabledSystemPackageWhenGranting="true"
minSdkVersion="33"
static="true"
systemOnly="true"
diff --git a/PermissionController/role-controller/java/com/android/role/controller/model/AppOp.java b/PermissionController/role-controller/java/com/android/role/controller/model/AppOp.java
index 1c71e0c99..56c4944a0 100644
--- a/PermissionController/role-controller/java/com/android/role/controller/model/AppOp.java
+++ b/PermissionController/role-controller/java/com/android/role/controller/model/AppOp.java
@@ -23,6 +23,7 @@ import android.os.UserHandle;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
+import androidx.annotation.VisibleForTesting;
import com.android.modules.utils.build.SdkLevel;
import com.android.role.controller.util.PackageUtils;
@@ -130,7 +131,8 @@ public class AppOp {
return Permissions.setAppOpUidModeAsUser(packageName, mName, defaultMode, user, context);
}
- boolean isAvailableByFeatureFlagAndSdkVersion() {
+ @VisibleForTesting
+ public boolean isAvailableByFeatureFlagAndSdkVersion() {
if (mFeatureFlag != null && !mFeatureFlag.get()) {
return false;
}
diff --git a/PermissionController/role-controller/java/com/android/role/controller/model/Permissions.java b/PermissionController/role-controller/java/com/android/role/controller/model/Permissions.java
index e788fdce1..6de52ca42 100644
--- a/PermissionController/role-controller/java/com/android/role/controller/model/Permissions.java
+++ b/PermissionController/role-controller/java/com/android/role/controller/model/Permissions.java
@@ -86,8 +86,9 @@ public class Permissions {
*
* @param packageName the package name of the application to be granted permissions to
* @param permissions the list of permissions to be granted
- * @param overrideDisabledSystemPackage whether to ignore the permissions of a disabled system
- * package (if this package is an updated system package)
+ * @param ignoreDisabledSystemPackage whether to ignore the requested permissions of a disabled
+ * system package (if this package is an updated system
+ * package)
* @param overrideUserSetAndFixed whether to override user set and fixed flags on the permission
* @param setGrantedByRole whether the permissions will be granted as granted-by-role
* @param setGrantedByDefault whether the permissions will be granted as granted-by-default
@@ -101,7 +102,7 @@ public class Permissions {
* PackageInfo, java.util.Set, boolean, boolean, int)
*/
public static boolean grantAsUser(@NonNull String packageName,
- @NonNull List<String> permissions, boolean overrideDisabledSystemPackage,
+ @NonNull List<String> permissions, boolean ignoreDisabledSystemPackage,
boolean overrideUserSetAndFixed, boolean setGrantedByRole, boolean setGrantedByDefault,
boolean setSystemFixed, @NonNull UserHandle user, @NonNull Context context) {
if (setGrantedByRole == setGrantedByDefault) {
@@ -145,7 +146,7 @@ public class Permissions {
// choice to grant this app the permissions needed to function. For all other
// apps, (default grants on first boot and user creation) we don't grant default
// permissions if the version on the system image does not declare them.
- if (!overrideDisabledSystemPackage && isUpdatedSystemApp(packageInfo)) {
+ if (!ignoreDisabledSystemPackage && isUpdatedSystemApp(packageInfo)) {
PackageInfo disabledSystemPackageInfo = getFactoryPackageInfoAsUser(packageName, user,
context);
if (disabledSystemPackageInfo != null) {
diff --git a/PermissionController/role-controller/java/com/android/role/controller/model/Role.java b/PermissionController/role-controller/java/com/android/role/controller/model/Role.java
index 04fd615e1..942535b0f 100644
--- a/PermissionController/role-controller/java/com/android/role/controller/model/Role.java
+++ b/PermissionController/role-controller/java/com/android/role/controller/model/Role.java
@@ -41,6 +41,7 @@ import android.util.Log;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.StringRes;
+import androidx.annotation.VisibleForTesting;
import com.android.modules.utils.build.SdkLevel;
import com.android.role.controller.util.CollectionUtils;
@@ -125,6 +126,12 @@ public class Role {
private final Supplier<Boolean> mFeatureFlag;
/**
+ * Whether this role should ignore the requested permissions of a disabled system package when
+ * granting.
+ */
+ private final boolean mIgnoreDisabledSystemPackageWhenGranting;
+
+ /**
* The string resource for the label of this role.
*/
@StringRes
@@ -241,7 +248,8 @@ public class Role {
public Role(@NonNull String name, boolean allowBypassingQualification,
@Nullable RoleBehavior behavior, @Nullable String defaultHoldersResourceName,
@StringRes int descriptionResource, boolean exclusive, boolean fallBackToDefaultHolder,
- @Nullable Supplier<Boolean> featureFlag, @StringRes int labelResource,
+ @Nullable Supplier<Boolean> featureFlag,
+ boolean ignoreDisabledSystemPackageWhenGranting, @StringRes int labelResource,
int maxSdkVersion, int minSdkVersion, boolean onlyGrantWhenAdded,
boolean overrideUserWhenGranting, @StringRes int requestDescriptionResource,
@StringRes int requestTitleResource, boolean requestable,
@@ -259,6 +267,7 @@ public class Role {
mExclusive = exclusive;
mFallBackToDefaultHolder = fallBackToDefaultHolder;
mFeatureFlag = featureFlag;
+ mIgnoreDisabledSystemPackageWhenGranting = ignoreDisabledSystemPackageWhenGranting;
mLabelResource = labelResource;
mMaxSdkVersion = maxSdkVersion;
mMinSdkVersion = minSdkVersion;
@@ -305,6 +314,13 @@ public class Role {
return mFeatureFlag;
}
+ /**
+ * @see #mIgnoreDisabledSystemPackageWhenGranting
+ */
+ public boolean shouldIgnoreDisabledSystemPackageWhenGranting() {
+ return mIgnoreDisabledSystemPackageWhenGranting;
+ }
+
@StringRes
public int getLabelResource() {
return mLabelResource;
@@ -355,6 +371,10 @@ public class Role {
return mShowNone;
}
+ public boolean isSystemOnly() {
+ return mSystemOnly;
+ }
+
public boolean isVisible() {
return mVisible;
}
@@ -424,7 +444,8 @@ public class Role {
*
* @return whether this role is available based on SDK version
*/
- boolean isAvailableByFeatureFlagAndSdkVersion() {
+ @VisibleForTesting
+ public boolean isAvailableByFeatureFlagAndSdkVersion() {
if (mFeatureFlag != null && !mFeatureFlag.get()) {
return false;
}
@@ -819,7 +840,7 @@ public class Role {
boolean overrideUser, @NonNull UserHandle user, @NonNull Context context) {
boolean permissionOrAppOpChanged = Permissions.grantAsUser(packageName,
Permissions.filterBySdkVersionAsUser(mPermissions, user, context),
- SdkLevel.isAtLeastS() ? !mSystemOnly : true, overrideUser, true, false, false,
+ mIgnoreDisabledSystemPackageWhenGranting, overrideUser, true, false, false,
user, context);
List<String> appOpPermissionsToGrant =
@@ -1105,6 +1126,8 @@ public class Role {
+ ", mExclusive=" + mExclusive
+ ", mFallBackToDefaultHolder=" + mFallBackToDefaultHolder
+ ", mFeatureFlag=" + mFeatureFlag
+ + ", mIgnoreDisabledSystemPackageWhenGranting="
+ + mIgnoreDisabledSystemPackageWhenGranting
+ ", mLabelResource=" + mLabelResource
+ ", mMaxSdkVersion=" + mMaxSdkVersion
+ ", mMinSdkVersion=" + mMinSdkVersion
diff --git a/PermissionController/role-controller/java/com/android/role/controller/model/RoleParser.java b/PermissionController/role-controller/java/com/android/role/controller/model/RoleParser.java
index f1a275daf..d4e5fa2d6 100644
--- a/PermissionController/role-controller/java/com/android/role/controller/model/RoleParser.java
+++ b/PermissionController/role-controller/java/com/android/role/controller/model/RoleParser.java
@@ -94,6 +94,8 @@ public class RoleParser {
private static final String ATTRIBUTE_EXCLUSIVE = "exclusive";
private static final String ATTRIBUTE_FALL_BACK_TO_DEFAULT_HOLDER = "fallBackToDefaultHolder";
private static final String ATTRIBUTE_FEATURE_FLAG = "featureFlag";
+ private static final String ATTRIBUTE_IGNORE_DISABLED_SYSTEM_PACKAGE_WHEN_GRANTING =
+ "ignoreDisabledSystemPackageWhenGranting";
private static final String ATTRIBUTE_LABEL = "label";
private static final String ATTRIBUTE_MAX_SDK_VERSION = "maxSdkVersion";
private static final String ATTRIBUTE_MIN_SDK_VERSION = "minSdkVersion";
@@ -156,16 +158,16 @@ public class RoleParser {
@NonNull
private final Context mContext;
- private final boolean mValidationEnabled;
+ private final boolean mThrowOnError;
public RoleParser(@NonNull Context context) {
this(context, false);
}
@VisibleForTesting
- public RoleParser(@NonNull Context context, boolean validationEnabled) {
+ public RoleParser(@NonNull Context context, boolean throwOnError) {
mContext = context;
- mValidationEnabled = validationEnabled;
+ mThrowOnError = throwOnError;
}
/**
@@ -175,18 +177,21 @@ public class RoleParser {
*/
@NonNull
public ArrayMap<String, Role> parse() {
+ Pair<ArrayMap<String, PermissionSet>, ArrayMap<String, Role>> xml = parseRolesXml();
+ if (xml == null) {
+ return new ArrayMap<>();
+ }
+ return xml.second;
+ }
+
+ @Nullable
+ @VisibleForTesting
+ public Pair<ArrayMap<String, PermissionSet>, ArrayMap<String, Role>> parseRolesXml() {
try (XmlResourceParser parser = getRolesXml()) {
- Pair<ArrayMap<String, PermissionSet>, ArrayMap<String, Role>> xml = parseXml(parser);
- if (xml == null) {
- return new ArrayMap<>();
- }
- ArrayMap<String, PermissionSet> permissionSets = xml.first;
- ArrayMap<String, Role> roles = xml.second;
- validateResult(permissionSets, roles);
- return roles;
+ return parseXml(parser);
} catch (XmlPullParserException | IOException e) {
throwOrLogMessage("Unable to parse roles.xml", e);
- return new ArrayMap<>();
+ return null;
}
}
@@ -426,6 +431,11 @@ public class RoleParser {
Supplier<Boolean> featureFlag = getAttributeMethodValue(parser, ATTRIBUTE_FEATURE_FLAG,
boolean.class, sFeatureFlagFallback, TAG_ROLE);
+ boolean systemOnly = getAttributeBooleanValue(parser, ATTRIBUTE_SYSTEM_ONLY, false);
+ boolean ignoreDisabledSystemPackageWhenGranting = getAttributeBooleanValue(parser,
+ ATTRIBUTE_IGNORE_DISABLED_SYSTEM_PACKAGE_WHEN_GRANTING,
+ SdkLevel.isAtLeastS() ? !systemOnly : true);
+
int maxSdkVersion = getAttributeIntValue(parser, ATTRIBUTE_MAX_SDK_VERSION,
Build.VERSION_CODES.CUR_DEVELOPMENT);
int minSdkVersion = getAttributeIntValue(parser, ATTRIBUTE_MIN_SDK_VERSION,
@@ -484,8 +494,6 @@ public class RoleParser {
return null;
}
- boolean systemOnly = getAttributeBooleanValue(parser, ATTRIBUTE_SYSTEM_ONLY, false);
-
String uiBehaviorName = getAttributeValue(parser, ATTRIBUTE_UI_BEHAVIOR);
List<RequiredComponent> requiredComponents = null;
@@ -567,8 +575,9 @@ public class RoleParser {
preferredActivities = Collections.emptyList();
}
return new Role(name, allowBypassingQualification, behavior, defaultHoldersResourceName,
- descriptionResource, exclusive, fallBackToDefaultHolder, featureFlag, labelResource,
- maxSdkVersion, minSdkVersion, onlyGrantWhenAdded, overrideUserWhenGranting,
+ descriptionResource, exclusive, fallBackToDefaultHolder, featureFlag,
+ ignoreDisabledSystemPackageWhenGranting, labelResource, maxSdkVersion,
+ minSdkVersion, onlyGrantWhenAdded, overrideUserWhenGranting,
requestDescriptionResource, requestTitleResource, requestable,
searchKeywordsResource, shortLabelResource, showNone, statik, systemOnly, visible,
requiredComponents, permissions, appOpPermissions, appOps, preferredActivities,
@@ -624,7 +633,7 @@ public class RoleParser {
int queryFlags = getAttributeIntValue(parser, ATTRIBUTE_QUERY_FLAGS, 0);
IntentFilterData intentFilterData = null;
List<RequiredMetaData> metaData = new ArrayList<>();
- List<String> validationMetaDataNames = mValidationEnabled ? new ArrayList<>() : null;
+ List<String> validationMetaDataNames = mThrowOnError ? new ArrayList<>() : null;
int type;
int depth;
@@ -651,7 +660,7 @@ public class RoleParser {
if (metaDataName == null) {
continue;
}
- if (mValidationEnabled) {
+ if (mThrowOnError) {
validateNoDuplicateElement(metaDataName, validationMetaDataNames,
"meta data");
}
@@ -668,7 +677,7 @@ public class RoleParser {
RequiredMetaData requiredMetaData = new RequiredMetaData(metaDataName,
metaDataValue, metaDataProhibited);
metaData.add(requiredMetaData);
- if (mValidationEnabled) {
+ if (mThrowOnError) {
validationMetaDataNames.add(metaDataName);
}
break;
@@ -1204,7 +1213,7 @@ public class RoleParser {
}
private void throwOrLogMessage(String message) {
- if (mValidationEnabled) {
+ if (mThrowOnError) {
throw new IllegalArgumentException(message);
} else {
Log.wtf(LOG_TAG, message);
@@ -1212,7 +1221,7 @@ public class RoleParser {
}
private void throwOrLogMessage(String message, Throwable cause) {
- if (mValidationEnabled) {
+ if (mThrowOnError) {
throw new IllegalArgumentException(message, cause);
} else {
Log.wtf(LOG_TAG, message, cause);
@@ -1222,168 +1231,4 @@ public class RoleParser {
private void throwOrLogForUnknownTag(@NonNull XmlResourceParser parser) {
throwOrLogMessage("Unknown tag: " + parser.getName());
}
-
- /**
- * Validates the permission names with {@code PackageManager} and ensures that all app ops with
- * a permission in {@code AppOpsManager} have declared that permission in its role and ensures
- * that all preferred activities are listed in the required components.
- */
- private void validateResult(@NonNull ArrayMap<String, PermissionSet> permissionSets,
- @NonNull ArrayMap<String, Role> roles) {
- if (!mValidationEnabled) {
- return;
- }
-
- int permissionSetsSize = permissionSets.size();
- for (int permissionSetsIndex = 0; permissionSetsIndex < permissionSetsSize;
- permissionSetsIndex++) {
- PermissionSet permissionSet = permissionSets.valueAt(permissionSetsIndex);
-
- List<Permission> permissions = permissionSet.getPermissions();
- int permissionsSize = permissions.size();
- for (int permissionsIndex = 0; permissionsIndex < permissionsSize; permissionsIndex++) {
- Permission permission = permissions.get(permissionsIndex);
-
- validatePermission(permission);
- }
- }
-
- int rolesSize = roles.size();
- for (int rolesIndex = 0; rolesIndex < rolesSize; rolesIndex++) {
- Role role = roles.valueAt(rolesIndex);
-
- if (!role.isAvailableByFeatureFlagAndSdkVersion()) {
- continue;
- }
-
- List<RequiredComponent> requiredComponents = role.getRequiredComponents();
- int requiredComponentsSize = requiredComponents.size();
- for (int requiredComponentsIndex = 0; requiredComponentsIndex < requiredComponentsSize;
- requiredComponentsIndex++) {
- RequiredComponent requiredComponent = requiredComponents.get(
- requiredComponentsIndex);
-
- String permission = requiredComponent.getPermission();
- if (permission != null) {
- validatePermission(permission);
- }
- }
-
- List<Permission> permissions = role.getPermissions();
- int permissionsSize = permissions.size();
- for (int i = 0; i < permissionsSize; i++) {
- Permission permission = permissions.get(i);
-
- validatePermission(permission);
- }
-
- List<AppOp> appOps = role.getAppOps();
- int appOpsSize = appOps.size();
- for (int i = 0; i < appOpsSize; i++) {
- AppOp appOp = appOps.get(i);
-
- validateAppOp(appOp);
- }
-
- List<Permission> appOpPermissions = role.getAppOpPermissions();
- int appOpPermissionsSize = appOpPermissions.size();
- for (int i = 0; i < appOpPermissionsSize; i++) {
- validateAppOpPermission(appOpPermissions.get(i));
- }
-
- List<PreferredActivity> preferredActivities = role.getPreferredActivities();
- int preferredActivitiesSize = preferredActivities.size();
- for (int preferredActivitiesIndex = 0;
- preferredActivitiesIndex < preferredActivitiesSize;
- preferredActivitiesIndex++) {
- PreferredActivity preferredActivity = preferredActivities.get(
- preferredActivitiesIndex);
-
- if (!role.getRequiredComponents().contains(preferredActivity.getActivity())) {
- throw new IllegalArgumentException("<activity> of <preferred-activity> not"
- + " required in <required-components>, role: " + role.getName()
- + ", preferred activity: " + preferredActivity);
- }
- }
- }
- }
-
- private void validatePermission(@NonNull Permission permission) {
- if (!permission.isAvailableAsUser(Process.myUserHandle(), mContext)) {
- return;
- }
- validatePermission(permission.getName(), true);
- }
-
- private void validatePermission(@NonNull String permission) {
- validatePermission(permission, false);
- }
-
- private void validatePermission(@NonNull String permission, boolean enforceIsRuntimeOrRole) {
- PackageManager packageManager = mContext.getPackageManager();
- boolean isAutomotive = packageManager.hasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE);
- // Skip validation for car permissions which may not be available on all build targets.
- if (!isAutomotive && permission.startsWith("android.car")) {
- return;
- }
-
- PermissionInfo permissionInfo;
- try {
- permissionInfo = packageManager.getPermissionInfo(permission, 0);
- } catch (PackageManager.NameNotFoundException e) {
- throw new IllegalArgumentException("Unknown permission: " + permission, e);
- }
-
- if (enforceIsRuntimeOrRole) {
- if (!(permissionInfo.getProtection() == PermissionInfo.PROTECTION_DANGEROUS
- || (permissionInfo.getProtectionFlags() & PermissionInfo.PROTECTION_FLAG_ROLE)
- == PermissionInfo.PROTECTION_FLAG_ROLE)) {
- throw new IllegalArgumentException(
- "Permission is not a runtime or role permission: " + permission);
- }
- }
- }
-
- private void validateAppOpPermission(@NonNull Permission appOpPermission) {
- if (!appOpPermission.isAvailableAsUser(Process.myUserHandle(), mContext)) {
- return;
- }
- validateAppOpPermission(appOpPermission.getName());
- }
-
- private void validateAppOpPermission(@NonNull String appOpPermission) {
- PackageManager packageManager = mContext.getPackageManager();
- PermissionInfo permissionInfo;
- try {
- permissionInfo = packageManager.getPermissionInfo(appOpPermission, 0);
- } catch (PackageManager.NameNotFoundException e) {
- throw new IllegalArgumentException("Unknown app op permission: " + appOpPermission, e);
- }
- if ((permissionInfo.getProtectionFlags() & PermissionInfo.PROTECTION_FLAG_APPOP)
- != PermissionInfo.PROTECTION_FLAG_APPOP) {
- throw new IllegalArgumentException("Permission is not an app op permission: "
- + appOpPermission);
- }
- }
-
- private void validateAppOp(@NonNull AppOp appOp) {
- if (!appOp.isAvailableByFeatureFlagAndSdkVersion()) {
- return;
- }
- // This throws IllegalArgumentException if app op is unknown.
- String permission = AppOpsManager.opToPermission(appOp.getName());
- if (permission != null) {
- PackageManager packageManager = mContext.getPackageManager();
- PermissionInfo permissionInfo;
- try {
- permissionInfo = packageManager.getPermissionInfo(permission, 0);
- } catch (PackageManager.NameNotFoundException e) {
- throw new RuntimeException(e);
- }
- if (permissionInfo.getProtection() == PermissionInfo.PROTECTION_DANGEROUS) {
- throw new IllegalArgumentException("App op has an associated runtime permission: "
- + appOp.getName());
- }
- }
- }
}
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/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 481dc0dac..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
@@ -79,11 +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.PermissionSelectorWithWidgetPreference;
import com.android.permissioncontroller.permission.ui.handheld.PermissionSwitchPreference;
-import com.android.permissioncontroller.permission.ui.handheld.PermissionTwoTargetPreference;
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;
@@ -133,10 +132,10 @@ public class AppPermissionFragment extends SettingsWithLargeHeader
private @NonNull SelectorWithWidgetPreference mDenyForegroundButton;
private @NonNull PermissionSwitchPreference mLocationAccuracySwitch;
private @NonNull PermissionTwoTargetPreference mDetails;
- private @NonNull PermissionPreference mFooterLink1;
- private @NonNull PermissionPreference mFooterLink2;
- private @NonNull PermissionPreference mFooterStorageSpecialAppAccess;
- private @NonNull PermissionPreference mAdditionalInfo;
+ private @NonNull AppPermissionFooterLinkPreference mFooterLink1;
+ private @NonNull AppPermissionFooterLinkPreference mFooterLink2;
+ private @NonNull PermissionFooterPreference mFooterStorageSpecialAppAccess;
+ private @NonNull PermissionFooterPreference mAdditionalInfo;
private @NonNull String mPackageName;
private @NonNull String mPermGroupName;
@@ -268,7 +267,7 @@ public class AppPermissionFragment extends SettingsWithLargeHeader
if (exemptedPackages.contains(mPackageName)) {
int additional_info_label = Utils.isStatusBarIndicatorPermission(mPermGroupName)
? R.string.exempt_mic_camera_info_label : R.string.exempt_info_label;
- mAdditionalInfo.setSummary(context.getString(additional_info_label, mPackageLabel));
+ mAdditionalInfo.setTitle(context.getString(additional_info_label, mPackageLabel));
mAdditionalInfo.setVisible(true);
} else {
mAdditionalInfo.setVisible(false);
diff --git a/PermissionController/src/com/android/permissioncontroller/permission/ui/handheld/PermissionSelectorWithWidgetPreference.kt b/PermissionController/src/com/android/permissioncontroller/permission/ui/handheld/v36/PermissionSelectorWithWidgetPreference.kt
index 9d095c7dc..1574eaba3 100644
--- a/PermissionController/src/com/android/permissioncontroller/permission/ui/handheld/PermissionSelectorWithWidgetPreference.kt
+++ b/PermissionController/src/com/android/permissioncontroller/permission/ui/handheld/v36/PermissionSelectorWithWidgetPreference.kt
@@ -14,14 +14,16 @@
* limitations under the License.
*/
-package com.android.permissioncontroller.permission.ui.handheld
+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
@@ -34,6 +36,7 @@ import com.android.settingslib.widget.SelectorWithWidgetPreference
* - 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)
@@ -46,7 +49,7 @@ class PermissionSelectorWithWidgetPreference : SelectorWithWidgetPreference {
constructor(
context: Context,
attrs: AttributeSet?,
- @AttrRes defStyleAttr: Int
+ @AttrRes defStyleAttr: Int,
) : super(context, attrs, defStyleAttr) {
init(context, attrs)
}
@@ -56,6 +59,8 @@ class PermissionSelectorWithWidgetPreference : SelectorWithWidgetPreference {
}
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)
@@ -69,9 +74,10 @@ class PermissionSelectorWithWidgetPreference : SelectorWithWidgetPreference {
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 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)
diff --git a/PermissionController/src/com/android/permissioncontroller/permission/ui/handheld/PermissionTwoTargetPreference.kt b/PermissionController/src/com/android/permissioncontroller/permission/ui/handheld/v36/PermissionTwoTargetPreference.kt
index 13c9ee7c4..cf6585f4d 100644
--- a/PermissionController/src/com/android/permissioncontroller/permission/ui/handheld/PermissionTwoTargetPreference.kt
+++ b/PermissionController/src/com/android/permissioncontroller/permission/ui/handheld/v36/PermissionTwoTargetPreference.kt
@@ -14,13 +14,15 @@
* limitations under the License.
*/
-package com.android.permissioncontroller.permission.ui.handheld
+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
@@ -32,6 +34,7 @@ import com.android.settingslib.widget.TwoTargetPreference
* - 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)
@@ -44,7 +47,7 @@ class PermissionTwoTargetPreference : TwoTargetPreference {
constructor(
context: Context,
attrs: AttributeSet?,
- @AttrRes defStyleAttr: Int
+ @AttrRes defStyleAttr: Int,
) : super(context, attrs, defStyleAttr) {
init(context, attrs)
}
@@ -53,12 +56,13 @@ class PermissionTwoTargetPreference : TwoTargetPreference {
context: Context,
attrs: AttributeSet?,
@AttrRes defStyleAttr: Int,
- @StyleRes defStyleRes: 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)
}
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/ui/wear/theme/ResourceHelper.kt b/PermissionController/src/com/android/permissioncontroller/permission/ui/wear/theme/ResourceHelper.kt
new file mode 100644
index 000000000..3c2c38578
--- /dev/null
+++ b/PermissionController/src/com/android/permissioncontroller/permission/ui/wear/theme/ResourceHelper.kt
@@ -0,0 +1,53 @@
+/*
+ * 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.wear.theme
+
+import android.content.Context
+import androidx.annotation.ColorRes
+import androidx.annotation.DimenRes
+import androidx.annotation.DoNotInline
+import androidx.annotation.StringRes
+import androidx.compose.ui.graphics.Color
+
+internal object ResourceHelper {
+ @DoNotInline
+ fun getColor(context: Context, @ColorRes id: Int): Color? {
+ return try {
+ val colorInt = context.resources.getColor(id, context.theme)
+ Color(colorInt)
+ } catch (e: Exception) {
+ null
+ }
+ }
+
+ @DoNotInline
+ fun getString(context: Context, @StringRes id: Int): String? {
+ return try {
+ context.resources.getString(id)
+ } catch (e: Exception) {
+ null
+ }
+ }
+
+ @DoNotInline
+ fun getDimen(context: Context, @DimenRes id: Int): Float? {
+ return try {
+ context.resources.getDimension(id)
+ } catch (e: Exception) {
+ null
+ }
+ }
+}
diff --git a/PermissionController/src/com/android/permissioncontroller/permission/ui/wear/theme/WearComposeMaterial3ColorScheme.kt b/PermissionController/src/com/android/permissioncontroller/permission/ui/wear/theme/WearComposeMaterial3ColorScheme.kt
new file mode 100644
index 000000000..6af9a28ec
--- /dev/null
+++ b/PermissionController/src/com/android/permissioncontroller/permission/ui/wear/theme/WearComposeMaterial3ColorScheme.kt
@@ -0,0 +1,179 @@
+/*
+ * 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.wear.theme
+
+import android.content.Context
+import android.os.Build
+import androidx.annotation.ColorRes
+import androidx.annotation.RequiresApi
+import androidx.compose.ui.graphics.Color
+import androidx.wear.compose.material3.ColorScheme
+
+/**
+ * Creates a dynamic color maps that can be overlaid. In wear we only support dark theme for the
+ * time being. If the device supports dynamic color generation these resources are updated with the
+ * generated colors
+ */
+internal object WearComposeMaterial3ColorScheme {
+
+ private fun Color.updatedColor(context: Context, @ColorRes colorRes: Int): Color {
+ return ResourceHelper.getColor(context, colorRes) ?: this
+ }
+
+ @RequiresApi(Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
+ fun dynamicColorScheme(context: Context): ColorScheme {
+ val defaultColorScheme = ColorScheme()
+ return ColorScheme(
+ primary =
+ defaultColorScheme.primary.updatedColor(
+ context,
+ android.R.color.system_primary_fixed,
+ ),
+ primaryDim =
+ defaultColorScheme.primaryDim.updatedColor(
+ context,
+ android.R.color.system_primary_fixed_dim,
+ ),
+ primaryContainer =
+ defaultColorScheme.primaryContainer.updatedColor(
+ context,
+ android.R.color.system_primary_container_dark,
+ ),
+ onPrimary =
+ defaultColorScheme.onPrimary.updatedColor(
+ context,
+ android.R.color.system_on_primary_fixed,
+ ),
+ onPrimaryContainer =
+ defaultColorScheme.onPrimaryContainer.updatedColor(
+ context,
+ android.R.color.system_on_primary_container_dark,
+ ),
+ secondary =
+ defaultColorScheme.secondary.updatedColor(
+ context,
+ android.R.color.system_secondary_fixed,
+ ),
+ secondaryDim =
+ defaultColorScheme.secondaryDim.updatedColor(
+ context,
+ android.R.color.system_secondary_fixed_dim,
+ ),
+ secondaryContainer =
+ defaultColorScheme.secondaryContainer.updatedColor(
+ context,
+ android.R.color.system_secondary_container_dark,
+ ),
+ onSecondary =
+ defaultColorScheme.onSecondary.updatedColor(
+ context,
+ android.R.color.system_on_secondary_fixed,
+ ),
+ onSecondaryContainer =
+ defaultColorScheme.onSecondaryContainer.updatedColor(
+ context,
+ android.R.color.system_on_secondary_container_dark,
+ ),
+ tertiary =
+ defaultColorScheme.tertiary.updatedColor(
+ context,
+ android.R.color.system_tertiary_fixed,
+ ),
+ tertiaryDim =
+ defaultColorScheme.tertiaryDim.updatedColor(
+ context,
+ android.R.color.system_tertiary_fixed_dim,
+ ),
+ tertiaryContainer =
+ defaultColorScheme.tertiaryContainer.updatedColor(
+ context,
+ android.R.color.system_tertiary_container_dark,
+ ),
+ onTertiary =
+ defaultColorScheme.onTertiary.updatedColor(
+ context,
+ android.R.color.system_on_tertiary_fixed,
+ ),
+ onTertiaryContainer =
+ defaultColorScheme.onTertiaryContainer.updatedColor(
+ context,
+ android.R.color.system_on_tertiary_container_dark,
+ ),
+ surfaceContainerLow =
+ defaultColorScheme.surfaceContainerLow.updatedColor(
+ context,
+ android.R.color.system_surface_container_low_dark,
+ ),
+ surfaceContainer =
+ defaultColorScheme.surfaceContainer.updatedColor(
+ context,
+ android.R.color.system_surface_container_dark,
+ ),
+ surfaceContainerHigh =
+ defaultColorScheme.surfaceContainerHigh.updatedColor(
+ context,
+ android.R.color.system_surface_container_high_dark,
+ ),
+ onSurface =
+ defaultColorScheme.onSurface.updatedColor(
+ context,
+ android.R.color.system_on_surface_dark,
+ ),
+ onSurfaceVariant =
+ defaultColorScheme.onSurfaceVariant.updatedColor(
+ context,
+ android.R.color.system_on_surface_variant_dark,
+ ),
+ outline =
+ defaultColorScheme.outline.updatedColor(
+ context,
+ android.R.color.system_outline_dark,
+ ),
+ outlineVariant =
+ defaultColorScheme.outlineVariant.updatedColor(
+ context,
+ android.R.color.system_outline_variant_dark,
+ ),
+ background =
+ defaultColorScheme.background.updatedColor(
+ context,
+ android.R.color.system_background_dark,
+ ),
+ onBackground =
+ defaultColorScheme.onBackground.updatedColor(
+ context,
+ android.R.color.system_on_background_dark,
+ ),
+ error =
+ defaultColorScheme.error.updatedColor(context, android.R.color.system_error_dark),
+ onError =
+ defaultColorScheme.onError.updatedColor(
+ context,
+ android.R.color.system_on_error_dark,
+ ),
+ errorContainer =
+ defaultColorScheme.errorContainer.updatedColor(
+ context,
+ android.R.color.system_error_container_dark,
+ ),
+ onErrorContainer =
+ defaultColorScheme.onErrorContainer.updatedColor(
+ context,
+ android.R.color.system_on_error_container_dark,
+ ),
+ )
+ }
+}
diff --git a/PermissionController/src/com/android/permissioncontroller/permission/ui/wear/theme/WearComposeMaterial3Shapes.kt b/PermissionController/src/com/android/permissioncontroller/permission/ui/wear/theme/WearComposeMaterial3Shapes.kt
new file mode 100644
index 000000000..f81022842
--- /dev/null
+++ b/PermissionController/src/com/android/permissioncontroller/permission/ui/wear/theme/WearComposeMaterial3Shapes.kt
@@ -0,0 +1,66 @@
+/*
+ * 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.wear.theme
+
+import android.content.Context
+import androidx.annotation.DimenRes
+import androidx.compose.foundation.shape.CornerBasedShape
+import androidx.compose.foundation.shape.CornerSize
+import androidx.compose.ui.unit.dp
+import androidx.wear.compose.material3.Shapes
+import com.android.permissioncontroller.R
+
+// TODO(b/324928718): Use system defined symbols.
+internal object WearComposeMaterial3Shapes {
+ private fun CornerBasedShape.updatedShape(
+ context: Context,
+ @DimenRes cornerSizeRes: Int,
+ ): CornerBasedShape {
+ val size = ResourceHelper.getDimen(context, cornerSizeRes)?.dp ?: return this
+ return copy(CornerSize(size))
+ }
+
+ fun dynamicShapes(context: Context): Shapes {
+ val defaultShapes = Shapes()
+ return Shapes(
+ extraLarge =
+ defaultShapes.extraLarge.updatedShape(
+ context,
+ R.dimen.wear_compose_material3_shape_corner_extra_large_size,
+ ),
+ large =
+ defaultShapes.large.updatedShape(
+ context,
+ R.dimen.wear_compose_material3_shape_corner_large_size,
+ ),
+ medium =
+ defaultShapes.medium.updatedShape(
+ context,
+ R.dimen.wear_compose_material3_shape_corner_medium_size,
+ ),
+ small =
+ defaultShapes.small.updatedShape(
+ context,
+ R.dimen.wear_compose_material3_shape_corner_small_size,
+ ),
+ extraSmall =
+ defaultShapes.extraSmall.updatedShape(
+ context,
+ R.dimen.wear_compose_material3_shape_corner_extra_small_size,
+ ),
+ )
+ }
+}
diff --git a/PermissionController/src/com/android/permissioncontroller/permission/ui/wear/theme/WearComposeMaterial3TypeScaleTokens.kt b/PermissionController/src/com/android/permissioncontroller/permission/ui/wear/theme/WearComposeMaterial3TypeScaleTokens.kt
new file mode 100644
index 000000000..a4ec9ee1d
--- /dev/null
+++ b/PermissionController/src/com/android/permissioncontroller/permission/ui/wear/theme/WearComposeMaterial3TypeScaleTokens.kt
@@ -0,0 +1,109 @@
+/*
+ * 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.wear.theme
+
+/*
+ * These values are retrieved from https://carbon.googleplex.com/wear-m3/pages and
+ * modified by UX.
+ * These values are internal to material3 library. We copied them to support flex font families
+ * Do not edit directly. Copy paste from compose material library.
+ */
+
+internal object WearComposeMaterial3TypeScaleTokens {
+ val ArcLargeRoundness = 100.0f
+ val ArcLargeWeight = 600.0f
+ val ArcLargeWidth = 100.0f
+
+ val ArcMediumRoundness = 100.0f
+ val ArcMediumWeight = 600.0f
+ val ArcMediumWidth = 90.0f
+
+ val ArcSmallRoundness = 100.0f
+ val ArcSmallWeight = 550.0f
+ val ArcSmallWidth = 90.0f
+
+ val BodyExtraSmallRoundness = 100.0f
+ val BodyExtraSmallWeight = 500.0f
+ val BodyExtraSmallWidth = 84.0f
+
+ val BodyLargeRoundness = 100.0f
+ val BodyLargeWeight = 450.0f
+ val BodyLargeWidth = 90.0f
+
+ val BodyMediumRoundness = 100.0f
+ val BodyMediumWeight = 450.0f
+ val BodyMediumWidth = 90.0f
+
+ val BodySmallRoundness = 100.0f
+ val BodySmallWeight = 500.0f
+ val BodySmallWidth = 86.0f
+
+ val DisplayLargeRoundness = 100.0f
+ val DisplayLargeWeight = 450.0f
+ val DisplayLargeWidth = 100.0f
+
+ val DisplayMediumRoundness = 100.0f
+ val DisplayMediumWeight = 500.0f
+ val DisplayMediumWidth = 100.0f
+
+ val DisplaySmallRoundness = 100.0f
+ val DisplaySmallWeight = 500.0f
+ val DisplaySmallWidth = 100.0f
+
+ val LabelLargeRoundness = 100.0f
+ val LabelLargeWeight = 500.0f
+ val LabelLargeWidth = 100.0f
+
+ val LabelMediumRoundness = 100.0f
+ val LabelMediumWeight = 500.0f
+ val LabelMediumWidth = 90.0f
+
+ val LabelSmallRoundness = 100.0f
+ val LabelSmallWeight = 500.0f
+ val LabelSmallWidth = 84.0f
+
+ val NumeralExtraLargeRoundness = 100.0f
+ val NumeralExtraLargeWeight = 550.0f
+ val NumeralExtraLargeWidth = 100.0f
+
+ val NumeralExtraSmallRoundness = 100.0f
+ val NumeralExtraSmallWeight = 550.0f
+ val NumeralExtraSmallWidth = 100.0f
+
+ val NumeralLargeRoundness = 100.0f
+ val NumeralLargeWeight = 600.0f
+ val NumeralLargeWidth = 100.0f
+
+ val NumeralMediumRoundness = 100.0f
+ val NumeralMediumWidth = 100.0f
+ val NumeralMediumWeight = 600.0f
+
+ val NumeralSmallRoundness = 100.0f
+ val NumeralSmallWeight = 600.0f
+ val NumeralSmallWidth = 100.0f
+
+ val TitleLargeRoundness = 100.0f
+ val TitleLargeWeight = 500.0f
+ val TitleLargeWidth = 100.0f
+
+ val TitleMediumRoundness = 100.0f
+ val TitleMediumWeight = 550.0f
+ val TitleMediumWidth = 100.0f
+
+ val TitleSmallRoundness = 100.0f
+ val TitleSmallWeight = 550.0f
+ val TitleSmallWidth = 100.0f
+}
diff --git a/PermissionController/src/com/android/permissioncontroller/permission/ui/wear/theme/WearComposeMaterial3Typography.kt b/PermissionController/src/com/android/permissioncontroller/permission/ui/wear/theme/WearComposeMaterial3Typography.kt
new file mode 100644
index 000000000..ceae526a7
--- /dev/null
+++ b/PermissionController/src/com/android/permissioncontroller/permission/ui/wear/theme/WearComposeMaterial3Typography.kt
@@ -0,0 +1,240 @@
+/*
+ * 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.wear.theme
+
+import android.content.Context
+import androidx.annotation.DimenRes
+import androidx.annotation.StringRes
+import androidx.compose.ui.text.TextStyle
+import androidx.compose.ui.text.font.DeviceFontFamilyName
+import androidx.compose.ui.text.font.Font
+import androidx.compose.ui.text.font.FontFamily
+import androidx.compose.ui.text.font.FontVariation
+import androidx.compose.ui.unit.sp
+import androidx.wear.compose.material3.Typography
+import com.android.permissioncontroller.R
+
+internal object WearComposeMaterial3Typography {
+
+ private const val DEVICE_DEFAULT_FLEX_FONT_TYPE = "font-family-flex-device-default"
+
+ fun fontFamily(
+ context: Context,
+ @StringRes id: Int,
+ variationSettings: FontVariation.Settings? = null,
+ ): FontFamily {
+ val typefaceName = ResourceHelper.getString(context, id) ?: DEVICE_DEFAULT_FLEX_FONT_TYPE
+
+ val font =
+ if (variationSettings != null) {
+ Font(
+ familyName = DeviceFontFamilyName(typefaceName),
+ variationSettings = variationSettings,
+ )
+ } else {
+ Font(familyName = DeviceFontFamilyName(typefaceName))
+ }
+ return FontFamily(font)
+ }
+
+ private fun TextStyle.updatedTextStyle(
+ context: Context,
+ @StringRes fontRes: Int,
+ variationSettings: FontVariation.Settings? = null,
+ @DimenRes fontSizeRes: Int,
+ ): TextStyle {
+
+ val fontFamily =
+ fontFamily(context = context, id = fontRes, variationSettings = variationSettings)
+ val fontSize = ResourceHelper.getDimen(context = context, id = fontSizeRes)?.sp ?: fontSize
+
+ return copy(fontFamily = fontFamily, fontSize = fontSize)
+ }
+
+ fun dynamicTypography(context: Context): Typography {
+ val defaultTypography = Typography()
+ return Typography(
+ arcLarge =
+ defaultTypography.arcLarge.updatedTextStyle(
+ context = context,
+ fontRes = R.string.wear_compose_material3_arc_large_font_family,
+ fontSizeRes = R.dimen.wear_compose_material3_arc_large_font_size,
+ variationSettings =
+ WearComposeMaterial3VariableFontTokens.ArcLargeVariationSettings,
+ ),
+ arcMedium =
+ defaultTypography.arcMedium.updatedTextStyle(
+ context = context,
+ fontRes = R.string.wear_compose_material3_arc_medium_font_family,
+ fontSizeRes = R.dimen.wear_compose_material3_arc_medium_font_size,
+ variationSettings =
+ WearComposeMaterial3VariableFontTokens.ArcMediumVariationSettings,
+ ),
+ arcSmall =
+ defaultTypography.arcSmall.updatedTextStyle(
+ context = context,
+ fontRes = R.string.wear_compose_material3_arc_small_font_family,
+ fontSizeRes = R.dimen.wear_compose_material3_arc_small_font_size,
+ variationSettings =
+ WearComposeMaterial3VariableFontTokens.ArcSmallVariationSettings,
+ ),
+ bodyLarge =
+ defaultTypography.bodyLarge.updatedTextStyle(
+ context = context,
+ fontRes = R.string.wear_compose_material3_body_large_font_family,
+ fontSizeRes = R.dimen.wear_compose_material3_body_large_font_size,
+ variationSettings =
+ WearComposeMaterial3VariableFontTokens.BodyLargeVariationSettings,
+ ),
+ bodyMedium =
+ defaultTypography.bodyMedium.updatedTextStyle(
+ context = context,
+ fontRes = R.string.wear_compose_material3_body_medium_font_family,
+ fontSizeRes = R.dimen.wear_compose_material3_body_medium_font_size,
+ variationSettings =
+ WearComposeMaterial3VariableFontTokens.BodyMediumVariationSettings,
+ ),
+ bodySmall =
+ defaultTypography.bodySmall.updatedTextStyle(
+ context = context,
+ fontRes = R.string.wear_compose_material3_body_small_font_family,
+ fontSizeRes = R.dimen.wear_compose_material3_body_small_font_size,
+ variationSettings =
+ WearComposeMaterial3VariableFontTokens.BodySmallVariationSettings,
+ ),
+ bodyExtraSmall =
+ defaultTypography.bodyExtraSmall.updatedTextStyle(
+ context = context,
+ fontRes = R.string.wear_compose_material3_body_extra_small_font_family,
+ fontSizeRes = R.dimen.wear_compose_material3_body_extra_small_font_size,
+ variationSettings =
+ WearComposeMaterial3VariableFontTokens.BodyExtraSmallVariationSettings,
+ ),
+ displayLarge =
+ defaultTypography.displayLarge.updatedTextStyle(
+ context = context,
+ fontRes = R.string.wear_compose_material3_display_large_font_family,
+ fontSizeRes = R.dimen.wear_compose_material3_display_large_font_size,
+ variationSettings =
+ WearComposeMaterial3VariableFontTokens.DisplayLargeVariationSettings,
+ ),
+ displayMedium =
+ defaultTypography.displayMedium.updatedTextStyle(
+ context = context,
+ fontRes = R.string.wear_compose_material3_display_medium_font_family,
+ fontSizeRes = R.dimen.wear_compose_material3_display_medium_font_size,
+ variationSettings =
+ WearComposeMaterial3VariableFontTokens.DisplayMediumVariationSettings,
+ ),
+ displaySmall =
+ defaultTypography.displaySmall.updatedTextStyle(
+ context = context,
+ fontRes = R.string.wear_compose_material3_display_small_font_family,
+ fontSizeRes = R.dimen.wear_compose_material3_display_small_font_size,
+ variationSettings =
+ WearComposeMaterial3VariableFontTokens.DisplaySmallVariationSettings,
+ ),
+ labelLarge =
+ defaultTypography.labelLarge.updatedTextStyle(
+ context = context,
+ fontRes = R.string.wear_compose_material3_label_large_font_family,
+ fontSizeRes = R.dimen.wear_compose_material3_label_large_font_size,
+ variationSettings =
+ WearComposeMaterial3VariableFontTokens.LabelLargeVariationSettings,
+ ),
+ labelMedium =
+ defaultTypography.labelMedium.updatedTextStyle(
+ context = context,
+ fontRes = R.string.wear_compose_material3_label_medium_font_family,
+ fontSizeRes = R.dimen.wear_compose_material3_label_medium_font_size,
+ variationSettings =
+ WearComposeMaterial3VariableFontTokens.LabelMediumVariationSettings,
+ ),
+ labelSmall =
+ defaultTypography.labelSmall.updatedTextStyle(
+ context = context,
+ fontRes = R.string.wear_compose_material3_label_small_font_family,
+ fontSizeRes = R.dimen.wear_compose_material3_label_small_font_size,
+ variationSettings =
+ WearComposeMaterial3VariableFontTokens.LabelSmallVariationSettings,
+ ),
+ numeralExtraLarge =
+ defaultTypography.numeralExtraLarge.updatedTextStyle(
+ context = context,
+ fontRes = R.string.wear_compose_material3_numeral_extra_large_font_family,
+ fontSizeRes = R.dimen.wear_compose_material3_numeral_extra_large_font_size,
+ variationSettings =
+ WearComposeMaterial3VariableFontTokens.NumeralExtraLargeVariationSettings,
+ ),
+ numeralLarge =
+ defaultTypography.numeralLarge.updatedTextStyle(
+ context = context,
+ fontRes = R.string.wear_compose_material3_numeral_large_font_family,
+ fontSizeRes = R.dimen.wear_compose_material3_numeral_large_font_size,
+ variationSettings =
+ WearComposeMaterial3VariableFontTokens.NumeralLargeVariationSettings,
+ ),
+ numeralMedium =
+ defaultTypography.numeralMedium.updatedTextStyle(
+ context = context,
+ fontRes = R.string.wear_compose_material3_numeral_medium_font_family,
+ fontSizeRes = R.dimen.wear_compose_material3_numeral_medium_font_size,
+ variationSettings =
+ WearComposeMaterial3VariableFontTokens.NumeralMediumVariationSettings,
+ ),
+ numeralSmall =
+ defaultTypography.numeralSmall.updatedTextStyle(
+ context = context,
+ fontRes = R.string.wear_compose_material3_numeral_small_font_family,
+ fontSizeRes = R.dimen.wear_compose_material3_numeral_small_font_size,
+ variationSettings =
+ WearComposeMaterial3VariableFontTokens.NumeralSmallVariationSettings,
+ ),
+ numeralExtraSmall =
+ defaultTypography.numeralExtraSmall.updatedTextStyle(
+ context = context,
+ fontRes = R.string.wear_compose_material3_numeral_extra_small_font_family,
+ fontSizeRes = R.dimen.wear_compose_material3_numeral_extra_small_font_size,
+ variationSettings =
+ WearComposeMaterial3VariableFontTokens.NumeralExtraSmallVariationSettings,
+ ),
+ titleLarge =
+ defaultTypography.titleLarge.updatedTextStyle(
+ context = context,
+ fontRes = R.string.wear_compose_material3_title_large_font_family,
+ fontSizeRes = R.dimen.wear_compose_material3_title_large_font_size,
+ variationSettings =
+ WearComposeMaterial3VariableFontTokens.TitleLargeVariationSettings,
+ ),
+ titleMedium =
+ defaultTypography.titleMedium.updatedTextStyle(
+ context = context,
+ fontRes = R.string.wear_compose_material3_title_medium_font_family,
+ fontSizeRes = R.dimen.wear_compose_material3_title_medium_font_size,
+ variationSettings =
+ WearComposeMaterial3VariableFontTokens.TitleMediumVariationSettings,
+ ),
+ titleSmall =
+ defaultTypography.titleSmall.updatedTextStyle(
+ context = context,
+ fontRes = R.string.wear_compose_material3_title_small_font_family,
+ fontSizeRes = R.dimen.wear_compose_material3_title_small_font_size,
+ variationSettings =
+ WearComposeMaterial3VariableFontTokens.TitleSmallVariationSettings,
+ ),
+ )
+ }
+}
diff --git a/PermissionController/src/com/android/permissioncontroller/permission/ui/wear/theme/WearComposeMaterial3VariableFontTokens.kt b/PermissionController/src/com/android/permissioncontroller/permission/ui/wear/theme/WearComposeMaterial3VariableFontTokens.kt
new file mode 100644
index 000000000..1b42a3b05
--- /dev/null
+++ b/PermissionController/src/com/android/permissioncontroller/permission/ui/wear/theme/WearComposeMaterial3VariableFontTokens.kt
@@ -0,0 +1,186 @@
+/*
+ * 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.wear.theme
+
+import androidx.compose.ui.text.font.FontVariation
+
+internal object WearComposeMaterial3VariableFontTokens {
+ val ArcLargeVariationSettings =
+ FontVariation.Settings(
+ FontVariation.Setting("ROND", WearComposeMaterial3TypeScaleTokens.ArcLargeRoundness),
+ FontVariation.Setting("wdth", WearComposeMaterial3TypeScaleTokens.ArcLargeWidth),
+ FontVariation.Setting("wght", WearComposeMaterial3TypeScaleTokens.ArcLargeWeight),
+ )
+ val ArcMediumVariationSettings =
+ FontVariation.Settings(
+ FontVariation.Setting("ROND", WearComposeMaterial3TypeScaleTokens.ArcMediumRoundness),
+ FontVariation.Setting("wdth", WearComposeMaterial3TypeScaleTokens.ArcMediumWidth),
+ FontVariation.Setting("wght", WearComposeMaterial3TypeScaleTokens.ArcMediumWeight),
+ )
+ val ArcSmallVariationSettings =
+ FontVariation.Settings(
+ FontVariation.Setting("ROND", WearComposeMaterial3TypeScaleTokens.ArcSmallRoundness),
+ FontVariation.Setting("wdth", WearComposeMaterial3TypeScaleTokens.ArcSmallWidth),
+ FontVariation.Setting("wght", WearComposeMaterial3TypeScaleTokens.ArcSmallWeight),
+ )
+ val BodyExtraSmallVariationSettings =
+ FontVariation.Settings(
+ FontVariation.Setting(
+ "ROND",
+ WearComposeMaterial3TypeScaleTokens.BodyExtraSmallRoundness,
+ ),
+ FontVariation.Setting("wdth", WearComposeMaterial3TypeScaleTokens.BodyExtraSmallWidth),
+ FontVariation.Setting("wght", WearComposeMaterial3TypeScaleTokens.BodyExtraSmallWeight),
+ )
+ val BodyLargeVariationSettings =
+ FontVariation.Settings(
+ FontVariation.Setting("ROND", WearComposeMaterial3TypeScaleTokens.BodyLargeRoundness),
+ FontVariation.Setting("wdth", WearComposeMaterial3TypeScaleTokens.BodyLargeWidth),
+ FontVariation.Setting("wght", WearComposeMaterial3TypeScaleTokens.BodyLargeWeight),
+ )
+ val BodyMediumVariationSettings =
+ FontVariation.Settings(
+ FontVariation.Setting("ROND", WearComposeMaterial3TypeScaleTokens.BodyMediumRoundness),
+ FontVariation.Setting("wdth", WearComposeMaterial3TypeScaleTokens.BodyMediumWidth),
+ FontVariation.Setting("wght", WearComposeMaterial3TypeScaleTokens.BodyMediumWeight),
+ )
+ val BodySmallVariationSettings =
+ FontVariation.Settings(
+ FontVariation.Setting("ROND", WearComposeMaterial3TypeScaleTokens.BodySmallRoundness),
+ FontVariation.Setting("wdth", WearComposeMaterial3TypeScaleTokens.BodySmallWidth),
+ FontVariation.Setting("wght", WearComposeMaterial3TypeScaleTokens.BodySmallWeight),
+ )
+ val DisplayLargeVariationSettings =
+ FontVariation.Settings(
+ FontVariation.Setting(
+ "ROND",
+ WearComposeMaterial3TypeScaleTokens.DisplayLargeRoundness,
+ ),
+ FontVariation.Setting("wdth", WearComposeMaterial3TypeScaleTokens.DisplayLargeWidth),
+ FontVariation.Setting("wght", WearComposeMaterial3TypeScaleTokens.DisplayLargeWeight),
+ )
+ val DisplayMediumVariationSettings =
+ FontVariation.Settings(
+ FontVariation.Setting(
+ "ROND",
+ WearComposeMaterial3TypeScaleTokens.DisplayMediumRoundness,
+ ),
+ FontVariation.Setting("wdth", WearComposeMaterial3TypeScaleTokens.DisplayMediumWidth),
+ FontVariation.Setting("wght", WearComposeMaterial3TypeScaleTokens.DisplayMediumWeight),
+ )
+ val DisplaySmallVariationSettings =
+ FontVariation.Settings(
+ FontVariation.Setting(
+ "ROND",
+ WearComposeMaterial3TypeScaleTokens.DisplaySmallRoundness,
+ ),
+ FontVariation.Setting("wdth", WearComposeMaterial3TypeScaleTokens.DisplaySmallWidth),
+ FontVariation.Setting("wght", WearComposeMaterial3TypeScaleTokens.DisplaySmallWeight),
+ )
+ val LabelLargeVariationSettings =
+ FontVariation.Settings(
+ FontVariation.Setting("ROND", WearComposeMaterial3TypeScaleTokens.LabelLargeRoundness),
+ FontVariation.Setting("wdth", WearComposeMaterial3TypeScaleTokens.LabelLargeWidth),
+ FontVariation.Setting("wght", WearComposeMaterial3TypeScaleTokens.LabelLargeWeight),
+ )
+ val LabelMediumVariationSettings =
+ FontVariation.Settings(
+ FontVariation.Setting("ROND", WearComposeMaterial3TypeScaleTokens.LabelMediumRoundness),
+ FontVariation.Setting("wdth", WearComposeMaterial3TypeScaleTokens.LabelMediumWidth),
+ FontVariation.Setting("wght", WearComposeMaterial3TypeScaleTokens.LabelMediumWeight),
+ )
+ val LabelSmallVariationSettings =
+ FontVariation.Settings(
+ FontVariation.Setting("ROND", WearComposeMaterial3TypeScaleTokens.LabelSmallRoundness),
+ FontVariation.Setting("wdth", WearComposeMaterial3TypeScaleTokens.LabelSmallWidth),
+ FontVariation.Setting("wght", WearComposeMaterial3TypeScaleTokens.LabelSmallWeight),
+ )
+ val NumeralExtraLargeVariationSettings =
+ FontVariation.Settings(
+ FontVariation.Setting(
+ "ROND",
+ WearComposeMaterial3TypeScaleTokens.NumeralExtraLargeRoundness,
+ ),
+ FontVariation.Setting(
+ "wdth",
+ WearComposeMaterial3TypeScaleTokens.NumeralExtraLargeWidth,
+ ),
+ FontVariation.Setting(
+ "wght",
+ WearComposeMaterial3TypeScaleTokens.NumeralExtraLargeWeight,
+ ),
+ )
+ val NumeralExtraSmallVariationSettings =
+ FontVariation.Settings(
+ FontVariation.Setting(
+ "ROND",
+ WearComposeMaterial3TypeScaleTokens.NumeralExtraSmallRoundness,
+ ),
+ FontVariation.Setting(
+ "wdth",
+ WearComposeMaterial3TypeScaleTokens.NumeralExtraSmallWidth,
+ ),
+ FontVariation.Setting(
+ "wght",
+ WearComposeMaterial3TypeScaleTokens.NumeralExtraSmallWeight,
+ ),
+ )
+ val NumeralLargeVariationSettings =
+ FontVariation.Settings(
+ FontVariation.Setting(
+ "ROND",
+ WearComposeMaterial3TypeScaleTokens.NumeralLargeRoundness,
+ ),
+ FontVariation.Setting("wdth", WearComposeMaterial3TypeScaleTokens.NumeralLargeWidth),
+ FontVariation.Setting("wght", WearComposeMaterial3TypeScaleTokens.NumeralLargeWeight),
+ )
+ val NumeralMediumVariationSettings =
+ FontVariation.Settings(
+ FontVariation.Setting(
+ "ROND",
+ WearComposeMaterial3TypeScaleTokens.NumeralMediumRoundness,
+ ),
+ FontVariation.Setting("wdth", WearComposeMaterial3TypeScaleTokens.NumeralMediumWidth),
+ FontVariation.Setting("wght", WearComposeMaterial3TypeScaleTokens.NumeralMediumWeight),
+ )
+ val NumeralSmallVariationSettings =
+ FontVariation.Settings(
+ FontVariation.Setting(
+ "ROND",
+ WearComposeMaterial3TypeScaleTokens.NumeralSmallRoundness,
+ ),
+ FontVariation.Setting("wdth", WearComposeMaterial3TypeScaleTokens.NumeralSmallWidth),
+ FontVariation.Setting("wght", WearComposeMaterial3TypeScaleTokens.NumeralSmallWeight),
+ )
+ val TitleLargeVariationSettings =
+ FontVariation.Settings(
+ FontVariation.Setting("ROND", WearComposeMaterial3TypeScaleTokens.TitleLargeRoundness),
+ FontVariation.Setting("wdth", WearComposeMaterial3TypeScaleTokens.TitleLargeWidth),
+ FontVariation.Setting("wght", WearComposeMaterial3TypeScaleTokens.TitleLargeWeight),
+ )
+ val TitleMediumVariationSettings =
+ FontVariation.Settings(
+ FontVariation.Setting("ROND", WearComposeMaterial3TypeScaleTokens.TitleMediumRoundness),
+ FontVariation.Setting("wdth", WearComposeMaterial3TypeScaleTokens.TitleMediumWidth),
+ FontVariation.Setting("wght", WearComposeMaterial3TypeScaleTokens.TitleMediumWeight),
+ )
+ val TitleSmallVariationSettings =
+ FontVariation.Settings(
+ FontVariation.Setting("ROND", WearComposeMaterial3TypeScaleTokens.TitleSmallRoundness),
+ FontVariation.Setting("wdth", WearComposeMaterial3TypeScaleTokens.TitleSmallWidth),
+ FontVariation.Setting("wght", WearComposeMaterial3TypeScaleTokens.TitleSmallWeight),
+ )
+}
diff --git a/PermissionController/src/com/android/permissioncontroller/permission/ui/wear/theme/WearOverlayableMaterial3Theme.kt b/PermissionController/src/com/android/permissioncontroller/permission/ui/wear/theme/WearOverlayableMaterial3Theme.kt
new file mode 100644
index 000000000..d2b2324ea
--- /dev/null
+++ b/PermissionController/src/com/android/permissioncontroller/permission/ui/wear/theme/WearOverlayableMaterial3Theme.kt
@@ -0,0 +1,37 @@
+/*
+ * 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.wear.theme
+
+import android.os.Build
+import androidx.compose.runtime.Composable
+import androidx.compose.ui.platform.LocalContext
+import androidx.wear.compose.material3.MaterialTheme
+
+/** The Material 3 Theme Wrapper for Supporting RRO. */
+@Composable
+fun WearOverlayableMaterial3Theme(content: @Composable () -> Unit) {
+ val context = LocalContext.current
+ if (Build.VERSION.SDK_INT >= 36) {
+ MaterialTheme(
+ colorScheme = WearComposeMaterial3ColorScheme.dynamicColorScheme(context),
+ typography = WearComposeMaterial3Typography.dynamicTypography(context),
+ shapes = WearComposeMaterial3Shapes.dynamicShapes(context),
+ content = content,
+ )
+ } else {
+ MaterialTheme(content = content)
+ }
+}
diff --git a/PermissionController/src/com/android/permissioncontroller/permission/ui/wear/theme/WearPermissionTheme.kt b/PermissionController/src/com/android/permissioncontroller/permission/ui/wear/theme/WearPermissionTheme.kt
index 933cf19f9..1d6d25ab1 100644
--- a/PermissionController/src/com/android/permissioncontroller/permission/ui/wear/theme/WearPermissionTheme.kt
+++ b/PermissionController/src/com/android/permissioncontroller/permission/ui/wear/theme/WearPermissionTheme.kt
@@ -1,3 +1,18 @@
+/*
+ * 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.wear.theme
import android.content.Context
@@ -16,7 +31,7 @@ import androidx.wear.compose.material.MaterialTheme
import androidx.wear.compose.material.Typography
import com.android.permissioncontroller.R
-/** The Material 3 Theme Wrapper for Supporting RRO. */
+/** The Material 2.5 Theme Wrapper for Supporting RRO. */
@Composable
fun WearPermissionTheme(content: @Composable () -> Unit) {
val context = LocalContext.current
diff --git a/PermissionController/src/com/android/permissioncontroller/role/Role.md b/PermissionController/src/com/android/permissioncontroller/role/Role.md
index d4a514784..255214495 100644
--- a/PermissionController/src/com/android/permissioncontroller/role/Role.md
+++ b/PermissionController/src/com/android/permissioncontroller/role/Role.md
@@ -62,6 +62,13 @@ is optional and defaults to `false`.
the Java method on the `Flags` class which will be invoked via reflection. Note that any new
aconfig library dependency will need corresponding jarjar rules for PermissionController and the
system service JAR.
+- `ignoreDisabledSystemPackageWhenGranting`: Whether the role should ignore the requested
+permissions of the disabled system package (if any) when granting permissions. If `false`, the
+permission will need to be requested by the disabled system package as well, if there is one. This
+attribute is optional and defaults to the opposite of `systemOnly` on Android S+, or `true` below
+Android S. **Note:** Extra care should be taken when adding a runtime permission to a role with
+this attribute explicitly set to `true`, because that may allow apps to update and silently obtain
+a new runtime permission.
- `label`: The string resource for the label of the role, e.g. `@string/role_sms_label`, which says
"Default SMS app". For default apps, this string will appear in the default app detail page as the
title. This attribute is required if the role is `visible`.
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/PermissionController/tests/mocking/src/com/android/permissioncontroller/tests/mocking/role/model/RoleParserTest.kt b/PermissionController/tests/mocking/src/com/android/permissioncontroller/tests/mocking/role/model/RoleParserTest.kt
index ec6ab4eff..f1accb6e5 100644
--- a/PermissionController/tests/mocking/src/com/android/permissioncontroller/tests/mocking/role/model/RoleParserTest.kt
+++ b/PermissionController/tests/mocking/src/com/android/permissioncontroller/tests/mocking/role/model/RoleParserTest.kt
@@ -16,9 +16,18 @@
package com.android.permissioncontroller.tests.mocking.role.model
+import android.app.AppOpsManager
+import android.content.pm.PackageManager
+import android.content.pm.PermissionInfo
+import android.os.Process
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.platform.app.InstrumentationRegistry
+import com.android.modules.utils.build.SdkLevel
import com.android.permissioncontroller.role.model.RoleParserInitializer
+import com.android.role.controller.model.AppOp
+import com.android.role.controller.model.Permission
+import com.android.role.controller.model.PermissionSet
+import com.android.role.controller.model.Role
import com.android.role.controller.model.RoleParser
import org.junit.BeforeClass
import org.junit.Test
@@ -37,9 +46,10 @@ class RoleParserTest {
private val instrumentation = InstrumentationRegistry.getInstrumentation()
private val uiAutomation = instrumentation.uiAutomation
private val targetContext = instrumentation.targetContext
+ private val packageManager = targetContext.packageManager
@Test
- fun testParseRolesWithValidation() {
+ fun parseRoles() {
// We may need to call privileged APIs to determine availability of things.
uiAutomation.adoptShellPermissionIdentity()
try {
@@ -48,4 +58,146 @@ class RoleParserTest {
uiAutomation.dropShellPermissionIdentity()
}
}
+
+ @Test
+ fun validateRoles() {
+ // We may need to call privileged APIs to determine availability of things.
+ uiAutomation.adoptShellPermissionIdentity()
+ try {
+ val xml = RoleParser(targetContext).parseRolesXml()
+ requireNotNull(xml)
+ validateRoles(xml.first, xml.second)
+ } finally {
+ uiAutomation.dropShellPermissionIdentity()
+ }
+ }
+
+ fun validateRoles(permissionSets: Map<String, PermissionSet>, roles: Map<String, Role>) {
+ for (permissionSet in permissionSets.values) {
+ for (permission in permissionSet.permissions) {
+ validatePermission(permission, false)
+ }
+ }
+
+ for (role in roles.values) {
+ if (!role.isAvailableByFeatureFlagAndSdkVersion) {
+ continue
+ }
+
+ for (requiredComponent in role.requiredComponents) {
+ val permission = requiredComponent.permission
+ if (permission != null) {
+ validatePermission(permission)
+ }
+ }
+
+ for (permission in role.permissions) {
+ // Prevent system-only roles that ignore disabled system packages from
+ // granting runtime permissions for now, since that may allow apps to update and
+ // silently obtain a new runtime permission.
+ val enforceNotRuntime =
+ SdkLevel.isAtLeastS() &&
+ role.isSystemOnly &&
+ role.shouldIgnoreDisabledSystemPackageWhenGranting()
+ validatePermission(permission, enforceNotRuntime)
+ }
+
+ for (appOp in role.appOps) {
+ validateAppOp(appOp)
+ }
+
+ for (appOpPermission in role.appOpPermissions) {
+ validateAppOpPermission(appOpPermission)
+ }
+
+ for (preferredActivity in role.preferredActivities) {
+ require(preferredActivity.activity in role.requiredComponents) {
+ "<activity> of <preferred-activity> not required in <required-components>," +
+ " role: ${role.name}, preferred activity: $preferredActivity"
+ }
+ }
+ }
+ }
+
+ private fun validatePermission(permission: Permission, enforceNotRuntime: Boolean) {
+ if (!permission.isAvailableAsUser(Process.myUserHandle(), targetContext)) {
+ return
+ }
+ validatePermission(permission.name, true, enforceNotRuntime)
+ }
+
+ private fun validatePermission(permissionName: String) {
+ validatePermission(permissionName, false, false)
+ }
+
+ private fun validatePermission(
+ permissionName: String,
+ enforceIsRuntimeOrRole: Boolean,
+ enforceNotRuntime: Boolean,
+ ) {
+ val isAutomotive = packageManager.hasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE)
+ // Skip validation for car permissions which may not be available on all build targets.
+ if (!isAutomotive && permissionName.startsWith("android.car")) {
+ return
+ }
+
+ val permissionInfo =
+ try {
+ packageManager.getPermissionInfo(permissionName, 0)
+ } catch (e: PackageManager.NameNotFoundException) {
+ throw IllegalArgumentException("Unknown permission: $permissionName", e)
+ }
+
+ if (enforceIsRuntimeOrRole) {
+ require(
+ permissionInfo.protection == PermissionInfo.PROTECTION_DANGEROUS ||
+ permissionInfo.protectionFlags and PermissionInfo.PROTECTION_FLAG_ROLE ==
+ PermissionInfo.PROTECTION_FLAG_ROLE
+ ) {
+ "Permission is not a runtime or role permission: $permissionName"
+ }
+ }
+
+ if (enforceNotRuntime) {
+ require(permissionInfo.protection != PermissionInfo.PROTECTION_DANGEROUS) {
+ "Permission is a runtime permission: $permissionName"
+ }
+ }
+ }
+
+ private fun validateAppOpPermission(appOpPermission: Permission) {
+ if (!appOpPermission.isAvailableAsUser(Process.myUserHandle(), targetContext)) {
+ return
+ }
+ validateAppOpPermission(appOpPermission.name)
+ }
+
+ private fun validateAppOpPermission(permissionName: String) {
+ val permissionInfo =
+ try {
+ packageManager.getPermissionInfo(permissionName, 0)
+ } catch (e: PackageManager.NameNotFoundException) {
+ throw IllegalArgumentException("Unknown app op permission: $permissionName", e)
+ }
+ require(
+ permissionInfo.protectionFlags and PermissionInfo.PROTECTION_FLAG_APPOP ==
+ PermissionInfo.PROTECTION_FLAG_APPOP
+ ) {
+ "Permission is not an app op permission: $permissionName"
+ }
+ }
+
+ private fun validateAppOp(appOp: AppOp) {
+ if (!appOp.isAvailableByFeatureFlagAndSdkVersion) {
+ return
+ }
+ // This throws IllegalArgumentException if app op is unknown.
+ val permissionName = AppOpsManager.opToPermission(appOp.name)
+ if (permissionName != null) {
+ val permissionInfo = packageManager.getPermissionInfo(permissionName, 0)
+ require(permissionInfo.protection != PermissionInfo.PROTECTION_DANGEROUS) {
+ "App op has an associated runtime permission: ${appOp.name}"
+ }
+ }
+ }
}
diff --git a/SafetyCenter/Resources/Android.bp b/SafetyCenter/Resources/Android.bp
index a10ea7f1a..f485172f4 100644
--- a/SafetyCenter/Resources/Android.bp
+++ b/SafetyCenter/Resources/Android.bp
@@ -49,6 +49,7 @@ android_app {
static_libs: [
"SafetyCenterResourcesShared",
],
+ updatable: true,
}
android_app_certificate {
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..d130f05e2 100644
--- a/flags/flags.aconfig
+++ b/flags/flags.aconfig
@@ -108,3 +108,21 @@ 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
+}
+
+flag {
+ name: "wear_compose_material3"
+ is_exported: true
+ namespace: "permissions"
+ description: "This flag enables material3 design system for wear ui components (to support BC25)"
+ bug: "370489422"
+ is_fixed_read_only: true
+} \ No newline at end of file
diff --git a/tests/cts/permissionmultiuser/AndroidTest.xml b/tests/cts/permissionmultiuser/AndroidTest.xml
index 10fd4e7a5..f6834036b 100644
--- a/tests/cts/permissionmultiuser/AndroidTest.xml
+++ b/tests/cts/permissionmultiuser/AndroidTest.xml
@@ -63,8 +63,8 @@
<test class="com.android.tradefed.testtype.AndroidJUnitTest" >
<option name="package" value="android.permissionmultiuser.cts" />
- <option name="exclude-annotation" value="com.android.bedstead.harrier.annotations.RequireRunOnWorkProfile" />
- <option name="exclude-annotation" value="com.android.bedstead.harrier.annotations.RequireRunOnSecondaryUser" />
+ <option name="exclude-annotation" value="com.android.bedstead.enterprise.annotations.RequireRunOnWorkProfile" />
+ <option name="exclude-annotation" value="com.android.bedstead.multiuser.annotations.RequireRunOnSecondaryUser" />
<option name="runtime-hint" value="5m" />
</test>
diff --git a/tests/cts/permissionmultiuser/src/android/permissionmultiuser/cts/AppDataSharingUpdatesTest.kt b/tests/cts/permissionmultiuser/src/android/permissionmultiuser/cts/AppDataSharingUpdatesTest.kt
index 2169f0f72..2067dec51 100644
--- a/tests/cts/permissionmultiuser/src/android/permissionmultiuser/cts/AppDataSharingUpdatesTest.kt
+++ b/tests/cts/permissionmultiuser/src/android/permissionmultiuser/cts/AppDataSharingUpdatesTest.kt
@@ -50,15 +50,15 @@ import android.support.test.uiautomator.UiObject2
import android.util.Log
import androidx.test.filters.SdkSuppress
import androidx.test.platform.app.InstrumentationRegistry
+import com.android.bedstead.enterprise.annotations.RequireRunOnWorkProfile
import com.android.bedstead.harrier.BedsteadJUnit4
import com.android.bedstead.harrier.DeviceState
import com.android.bedstead.permissions.annotations.EnsureHasPermission
import com.android.bedstead.harrier.annotations.EnsureSecureSettingSet
import com.android.bedstead.harrier.annotations.RequireDoesNotHaveFeature
import com.android.bedstead.harrier.annotations.RequireNotWatch
-import com.android.bedstead.harrier.annotations.RequireRunOnAdditionalUser
-import com.android.bedstead.harrier.annotations.RequireRunOnWorkProfile
import com.android.bedstead.harrier.annotations.RequireSdkVersion
+import com.android.bedstead.multiuser.annotations.RequireRunOnAdditionalUser
import com.android.bedstead.permissions.CommonPermissions.INTERACT_ACROSS_USERS
import com.android.compatibility.common.util.ApiTest
import com.android.compatibility.common.util.DeviceConfigStateChangerRule
diff --git a/tests/cts/permissionpolicy/res/raw/android_manifest.xml b/tests/cts/permissionpolicy/res/raw/android_manifest.xml
index af96c9a20..f548119b6 100644
--- a/tests/cts/permissionpolicy/res/raw/android_manifest.xml
+++ b/tests/cts/permissionpolicy/res/raw/android_manifest.xml
@@ -8264,6 +8264,29 @@
<permission android:name="android.permission.RESERVED_FOR_TESTING_SIGNATURE"
android:protectionLevel="signature"/>
+ <!-- @SystemApi
+ @FlaggedApi("android.content.pm.verification_service")
+ Allows app to be the verification agent to verify packages.
+ <p>Protection level: signature|privileged
+ @hide
+ -->
+ <permission android:name="android.permission.VERIFICATION_AGENT"
+ android:protectionLevel="signature|privileged"
+ android:featureFlag="android.content.pm.verification_service"/>
+
+ <!-- @SystemApi
+ @FlaggedApi("android.content.pm.verification_service")
+ Must be required by a privileged {@link android.content.pm.verify.pkg.VerifierService}
+ to ensure that only the system can bind to it.
+ This permission should not be held by anything other than the system.
+ <p>Not for use by third-party applications. </p>
+ <p>Protection level: signature
+ @hide
+ -->
+ <permission android:name="android.permission.BIND_VERIFICATION_AGENT"
+ android:protectionLevel="internal"
+ android:featureFlag="android.content.pm.verification_service" />
+
<!-- Attribution for Geofencing service. -->
<attribution android:tag="GeofencingService" android:label="@string/geofencing_service"/>
<!-- Attribution for Country Detector. -->
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