diff options
34 files changed, 549 insertions, 90 deletions
diff --git a/PermissionController/Android.bp b/PermissionController/Android.bp index 5c238806e..596b2dbb5 100644 --- a/PermissionController/Android.bp +++ b/PermissionController/Android.bp @@ -72,6 +72,11 @@ java_library { ], } +filegroup { + name: "PermissionController-jarjar-rules", + srcs: ["jarjar-rules.txt"], +} + android_library { name: "PermissionController-lib", sdk_version: "system_current", @@ -167,6 +172,9 @@ android_library { "//apex_available:platform", "com.android.permission", ], + + // TODO(b/313706381): Remove jarjar once flagging lib is fixed + jarjar_rules: ":PermissionController-jarjar-rules", } android_app { diff --git a/PermissionController/jarjar-rules.txt b/PermissionController/jarjar-rules.txt new file mode 100644 index 000000000..7bfda1ab1 --- /dev/null +++ b/PermissionController/jarjar-rules.txt @@ -0,0 +1,25 @@ +# You may bypass this Gerrit IfThisThenThat Lint if your change doesn't affect +# RoleParser.applyJarjarTransform(), by adding NO_IFTTT=reason to your commit +# message. +# LINT.IfChange +rule android.app.appfunctions.flags.*FeatureFlags* com.android.permissioncontroller.jarjar.@0 +rule android.app.appfunctions.flags.FeatureFlags* com.android.permissioncontroller.jarjar.@0 +rule android.app.appfunctions.flags.FeatureFlags com.android.permissioncontroller.jarjar.@0 +rule android.app.appfunctions.flags.Flags com.android.permissioncontroller.jarjar.@0 +rule android.companion.virtualdevice.flags.*FeatureFlags* com.android.permissioncontroller.jarjar.@0 +rule android.companion.virtualdevice.flags.FeatureFlags* com.android.permissioncontroller.jarjar.@0 +rule android.companion.virtualdevice.flags.FeatureFlags com.android.permissioncontroller.jarjar.@0 +rule android.companion.virtualdevice.flags.Flags com.android.permissioncontroller.jarjar.@0 +rule android.content.pm.*FeatureFlags* com.android.permissioncontroller.jarjar.@0 +rule android.content.pm.FeatureFlags* com.android.permissioncontroller.jarjar.@0 +rule android.content.pm.FeatureFlags com.android.permissioncontroller.jarjar.@0 +rule android.content.pm.Flags com.android.permissioncontroller.jarjar.@0 +rule android.permission.flags.*FeatureFlags* com.android.permissioncontroller.jarjar.@0 +rule android.permission.flags.FeatureFlags* com.android.permissioncontroller.jarjar.@0 +rule android.permission.flags.FeatureFlags com.android.permissioncontroller.jarjar.@0 +rule android.permission.flags.Flags com.android.permissioncontroller.jarjar.@0 +rule android.os.*FeatureFlags* com.android.permissioncontroller.jarjar.@0 +rule android.os.FeatureFlags* com.android.permissioncontroller.jarjar.@0 +rule android.os.FeatureFlags com.android.permissioncontroller.jarjar.@0 +rule android.os.Flags com.android.permissioncontroller.jarjar.@0 +# LINT.ThenChange(PermissionController/role-controller/java/com/android/role/controller/model/RoleParser.java:applyJarjarTransform) diff --git a/PermissionController/res/values-bs/strings.xml b/PermissionController/res/values-bs/strings.xml index 9dbaca940..fe036961d 100644 --- a/PermissionController/res/values-bs/strings.xml +++ b/PermissionController/res/values-bs/strings.xml @@ -683,7 +683,7 @@ <string name="enhanced_confirmation_dialog_learn_more" msgid="5226619861379095709">"Saznajte više"</string> <string name="enhanced_confirmation_dialog_ok" msgid="8560373821598619924">"Uredu"</string> <string name="permission_grant_dialog_streaming_blocked_title" msgid="8905241017017043649">"Zahtjev za odobrenje je potisnut"</string> - <string name="permission_grant_dialog_streaming_blocked_description" msgid="838165608934085319">"Aplikacija traži dodatna odobrenja, ali se ona ne mogu dati u sesiji prijenosa. Najprije dajte odobrenje na telefonu."</string> + <string name="permission_grant_dialog_streaming_blocked_description" msgid="838165608934085319">"Aplikacija traži dodatna odobrenja, ali se ona ne mogu dati u sesiji prenosa. Najprije dajte odobrenje na telefonu."</string> <string name="privacy_dashboard_emergency_location_enforced_attribution_label" msgid="5702912511473457693">"Za hitni poziv ili poruku"</string> <string name="privacy_dashboard_emergency_location_dialog_title" msgid="849723944428031911">"Lokacija je poslana hitnim službama"</string> <string name="privacy_dashboard_emergency_location_dialog_description" msgid="5815970230573483329">"Ova aplikacija je pristupila lokaciji uređaja tokom poziva ili slanja poruke broju za hitne slučajeve. To se može dogoditi čak i kada aplikacija nema odobrenje za lokaciju ili je lokacija uređaja isključena. "<a href="https://support.google.com/android/answer/9319337">"Saznajte više"</a></string> diff --git a/PermissionController/res/values-el/strings.xml b/PermissionController/res/values-el/strings.xml index e8afe33f3..e000a2ac2 100644 --- a/PermissionController/res/values-el/strings.xml +++ b/PermissionController/res/values-el/strings.xml @@ -499,7 +499,7 @@ <string name="permgrouprequest_storage_pre_q" msgid="168130651144569428">"Να επιτρέπεται στην εφαρμογή <b><xliff:g id="APP_NAME">%1$s</xliff:g></b> η πρόσβαση σε <b>φωτογραφίες, βίντεο, μουσική, ήχο και άλλα αρχεία</b> της συσκευής;"</string> <string name="permgrouprequest_read_media_aural" msgid="2593365397347577812">"Να επιτρέπεται στην εφαρμογή <b><xliff:g id="APP_NAME">%1$s</xliff:g></b> η πρόσβαση στη μουσική και στα αρχεία ήχου αυτής της συσκευής;"</string> <string name="permgrouprequest_device_aware_read_media_aural" msgid="7927884506238101064">"Να επιτρέπεται στην εφαρμογή <b><xliff:g id="APP_NAME">%1$s</xliff:g></b> η πρόσβαση σε μουσική και σε ήχο στη συσκευή <b><xliff:g id="DEVICE_NAME">%2$s</xliff:g></b>;"</string> - <string name="permgrouprequest_read_media_visual" msgid="5548780620779729975">"Να επιτρέπεται στην <b><xliff:g id="APP_NAME">%1$s</xliff:g></b> η πρόσβαση στις φωτογραφίες και τα βίντεο αυτής της συσκευής;"</string> + <string name="permgrouprequest_read_media_visual" msgid="5548780620779729975">"Να επιτρέπεται στην εφαρμογή <b><xliff:g id="APP_NAME">%1$s</xliff:g></b> η πρόσβαση στις φωτογραφίες και τα βίντεο αυτής της συσκευής;"</string> <string name="permgrouprequest_device_aware_read_media_visual" msgid="3122576538319059333">"Να επιτρέπεται στην εφαρμογή <b><xliff:g id="APP_NAME">%1$s</xliff:g></b> η πρόσβαση σε φωτογραφίες και σε βίντεο στη συσκευή <b><xliff:g id="DEVICE_NAME">%2$s</xliff:g></b>;"</string> <string name="permgrouprequest_more_photos" msgid="128933814654231321">"Να επιτρέπεται στην εφαρμογή <b><xliff:g id="APP_NAME">%1$s</xliff:g></b> η πρόσβαση σε περισσότερες φωτογραφίες και βίντεο αυτής της συσκευής;"</string> <string name="permgrouprequest_device_aware_more_photos" msgid="1703469013613723053">"Να επιτρέπεται στην εφαρμογή <b><xliff:g id="APP_NAME">%1$s</xliff:g></b> η πρόσβαση σε περισσότερες φωτογραφίες και βίντεο στη συσκευή <b><xliff:g id="DEVICE_NAME">%2$s</xliff:g></b>;"</string> diff --git a/PermissionController/res/values-eu/strings.xml b/PermissionController/res/values-eu/strings.xml index 7acae1dbc..139f41668 100644 --- a/PermissionController/res/values-eu/strings.xml +++ b/PermissionController/res/values-eu/strings.xml @@ -357,7 +357,7 @@ <string name="role_assistant_short_label" msgid="3369003713187703399">"Laguntzaile digitalaren aplikazioa"</string> <string name="role_assistant_description" msgid="6622458130459922952">"Ikusten ari zaren pantailako informazioaren araberako laguntza eskain diezazukete laguntza-aplikazioek. Zenbait aplikaziok exekutatzeko tresna eta ahots bidezko zerbitzuak onartzen dituzte laguntza integratua eskaintzeko."</string> <string name="role_browser_label" msgid="2877796144554070207">"Arakatzaile lehenetsia"</string> - <string name="role_browser_short_label" msgid="6745009127123292296">"Arakatzaile- aplikazioa"</string> + <string name="role_browser_short_label" msgid="6745009127123292296">"Arakatzaile-apliU+2060kazioa"</string> <string name="role_browser_description" msgid="3465253637499842671">"Interneteko sarbidea ematen dizuten eta sakatzen dituzun estekak bistaratzen dituzten aplikazioak"</string> <string name="role_browser_request_title" msgid="2895200507835937192">"<xliff:g id="APP_NAME">%1$s</xliff:g> ezarri nahi duzu arakatzaile lehenetsi gisa?"</string> <string name="role_browser_request_description" msgid="5888803407905985941">"Ez du behar baimenik"</string> diff --git a/PermissionController/res/values-uk/strings.xml b/PermissionController/res/values-uk/strings.xml index 38490365f..b05fb81e4 100644 --- a/PermissionController/res/values-uk/strings.xml +++ b/PermissionController/res/values-uk/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/role-controller/Android.bp b/PermissionController/role-controller/Android.bp index dfcc83a08..612c979b5 100644 --- a/PermissionController/role-controller/Android.bp +++ b/PermissionController/role-controller/Android.bp @@ -17,6 +17,9 @@ package { default_applicable_licenses: ["Android-Apache-2.0"], } +// Any place that role-controller is added as a dependency must also include +// "com.android.permission.flags-aconfig-java" or +// "com.android.permission.flags-aconfig-java-export", java_library { name: "role-controller", srcs: [ @@ -24,6 +27,7 @@ java_library { ], libs: [ "androidx.annotation_annotation", + "com.android.permission.flags-aconfig-java", ], static_libs: [ "modules-utils-build_system", @@ -31,7 +35,6 @@ java_library { "android.companion.virtualdevice.flags-aconfig-java-export", "android.permission.flags-aconfig-java-export", "android.os.flags-aconfig-java-export", - "com.android.permission.flags-aconfig-java-export", ], apex_available: [ "com.android.permission", 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 3a8c90888..061f351de 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 @@ -1143,7 +1143,7 @@ public class RoleParser { + ">"); return fallbackValue; } - String className = applyJarjarTransformIfNeeded(value.substring(0, lastDotIndex)); + String className = applyJarjarTransform(value.substring(0, lastDotIndex)); String methodName = value.substring(lastDotIndex + 1); Method method; try { @@ -1192,16 +1192,18 @@ public class RoleParser { }; } - // LINT.IfChange(applyJarjarTransformIfNeeded) + // LINT.IfChange(applyJarjarTransform) /** * Simulate the jarjar transform that should happen on the class name. * <p> * Currently this only handles the {@code Flags} classes for feature flagging. */ @NonNull - private String applyJarjarTransformIfNeeded(@NonNull String className) { - if (className.endsWith(".Flags") && Objects.equals(mContext.getPackageName(), "android")) { - return "com.android.permission.jarjar." + className; + private String applyJarjarTransform(@NonNull String className) { + if (className.endsWith(".Flags")) { + String jarjarPrefix = Objects.equals(mContext.getPackageName(), "android") + ? "com.android.permission.jarjar." : "com.android.permissioncontroller.jarjar."; + return jarjarPrefix + className; } return className; } diff --git a/PermissionController/src/com/android/permissioncontroller/permission/data/AppPermGroupUiInfoLiveData.kt b/PermissionController/src/com/android/permissioncontroller/permission/data/AppPermGroupUiInfoLiveData.kt index b17098a13..394cb3eb7 100644 --- a/PermissionController/src/com/android/permissioncontroller/permission/data/AppPermGroupUiInfoLiveData.kt +++ b/PermissionController/src/com/android/permissioncontroller/permission/data/AppPermGroupUiInfoLiveData.kt @@ -233,8 +233,8 @@ private constructor( * user */ private fun isUserSet(permissionState: Map<String, PermState>): Boolean { - val flagMask = - PackageManager.FLAG_PERMISSION_USER_SET or PackageManager.FLAG_PERMISSION_USER_FIXED + val flagMask = PackageManager.FLAG_PERMISSION_USER_SET or + PackageManager.FLAG_PERMISSION_USER_FIXED or PackageManager.FLAG_PERMISSION_ONE_TIME return permissionState.any { (it.value.permFlags and flagMask) != 0 } } diff --git a/PermissionController/src/com/android/permissioncontroller/permission/service/BackupHelper.java b/PermissionController/src/com/android/permissioncontroller/permission/service/BackupHelper.java index 24aab174c..2fa809c6d 100644 --- a/PermissionController/src/com/android/permissioncontroller/permission/service/BackupHelper.java +++ b/PermissionController/src/com/android/permissioncontroller/permission/service/BackupHelper.java @@ -96,6 +96,7 @@ public class BackupHelper { private static final String ATTR_USER_SET = "set"; private static final String ATTR_USER_FIXED = "fixed"; private static final String ATTR_WAS_REVIEWED = "was-reviewed"; + private static final String ATTR_ONE_TIME = "one-time"; /** Flags of permissions to <u>not</u> back up */ private static final int SYSTEM_RUNTIME_GRANT_MASK = FLAG_PERMISSION_POLICY_FIXED @@ -452,19 +453,21 @@ public class BackupHelper { private final boolean mIsUserSet; private final boolean mIsUserFixed; private final boolean mWasReviewed; + private final boolean mIsOneTime; // Not persisted, used during parsing so explicitly defined state takes precedence private final boolean mIsAddedFromSplit; private BackupPermissionState(@NonNull String permissionName, boolean isGranted, boolean isUserSet, boolean isUserFixed, boolean wasReviewed, - boolean isAddedFromSplit) { + boolean isOneTime, boolean isAddedFromSplit) { mPermissionName = permissionName; mIsGranted = isGranted; mIsUserSet = isUserSet; mIsUserFixed = isUserFixed; mWasReviewed = wasReviewed; mIsAddedFromSplit = isAddedFromSplit; + mIsOneTime = isOneTime; } /** @@ -512,6 +515,7 @@ public class BackupHelper { "true".equals(parser.getAttributeValue(null, ATTR_USER_SET)), "true".equals(parser.getAttributeValue(null, ATTR_USER_FIXED)), "true".equals(parser.getAttributeValue(null, ATTR_WAS_REVIEWED)), + "true".equals(parser.getAttributeValue(null, ATTR_ONE_TIME)), /* isAddedFromSplit */ i > 0)); } @@ -519,7 +523,8 @@ public class BackupHelper { } /** - * Is the permission granted, also considering the app-op. + * Is the permission granted, also considering the app-op. Don't consider one time grant + * as a permission grant for backup/restore. * * <p>This does not consider the review-required state of the permission. * @@ -528,7 +533,8 @@ public class BackupHelper { * @return {@code true} iff the permission and app-op is granted */ private static boolean isPermGrantedIncludingAppOp(@NonNull Permission perm) { - return perm.isGranted() && (!perm.affectsAppOp() || perm.isAppOpAllowed()); + return perm.isGranted() && (!perm.affectsAppOp() || perm.isAppOpAllowed()) + && !perm.isOneTime(); } /** @@ -549,7 +555,7 @@ public class BackupHelper { return null; } - if (!perm.isUserSet() && perm.isGrantedByDefault()) { + if (!perm.isUserSet() && !perm.isOneTime() && perm.isGrantedByDefault()) { return null; } @@ -564,10 +570,10 @@ public class BackupHelper { } if (isNotInDefaultGrantState || perm.isUserSet() || perm.isUserFixed() - || permissionWasReviewed) { + || perm.isOneTime() || permissionWasReviewed) { return new BackupPermissionState(perm.getName(), isPermGrantedIncludingAppOp(perm), perm.isUserSet(), perm.isUserFixed(), permissionWasReviewed, - /* isAddedFromSplit */ false); + perm.isOneTime(), /* isAddedFromSplit */ false); } else { return null; } @@ -628,6 +634,10 @@ public class BackupHelper { serializer.attribute(null, ATTR_WAS_REVIEWED, "true"); } + if (mIsOneTime) { + serializer.attribute(null, ATTR_ONE_TIME, "true"); + } + serializer.endTag(null, TAG_PERMISSION); } @@ -671,6 +681,10 @@ public class BackupHelper { perm.setUserSet(mIsUserSet); } + + if (!perm.isOneTime()) { + perm.setOneTime(mIsOneTime); + } } } diff --git a/PermissionController/src/com/android/permissioncontroller/permission/ui/handheld/ManageCustomPermissionsFragment.java b/PermissionController/src/com/android/permissioncontroller/permission/ui/handheld/ManageCustomPermissionsFragment.java index 35236b8de..dd460aa2f 100644 --- a/PermissionController/src/com/android/permissioncontroller/permission/ui/handheld/ManageCustomPermissionsFragment.java +++ b/PermissionController/src/com/android/permissioncontroller/permission/ui/handheld/ManageCustomPermissionsFragment.java @@ -24,6 +24,8 @@ import android.view.MenuItem; import androidx.lifecycle.ViewModelProvider; +import com.android.permission.flags.Flags; +import com.android.permissioncontroller.permission.data.PermGroupsPackagesUiInfoLiveData; import com.android.permissioncontroller.permission.ui.model.ManageCustomPermissionsViewModel; import com.android.permissioncontroller.permission.ui.model.ManageCustomPermissionsViewModelFactory; @@ -48,6 +50,14 @@ public class ManageCustomPermissionsFragment extends ManagePermissionsFragment { return arguments; } + private PermGroupsPackagesUiInfoLiveData getPermGroupsLiveData() { + if (Flags.declutteredPermissionManagerEnabled()) { + return mViewModel.getAdditionaPermGroupsUiInfo(); + } else { + return mViewModel.getUiDataLiveData(); + } + } + @Override public void onCreate(Bundle icicle) { super.onCreate(icicle); @@ -56,9 +66,9 @@ public class ManageCustomPermissionsFragment extends ManagePermissionsFragment { new ManageCustomPermissionsViewModelFactory(getActivity().getApplication()); mViewModel = new ViewModelProvider(this, factory) .get(ManageCustomPermissionsViewModel.class); - mPermissionGroups = mViewModel.getUiDataLiveData().getValue(); + mPermissionGroups = getPermGroupsLiveData().getValue(); - mViewModel.getUiDataLiveData().observe(this, permissionGroups -> { + getPermGroupsLiveData().observe(this, permissionGroups -> { if (permissionGroups == null) { mPermissionGroups = new HashMap<>(); } else { diff --git a/PermissionController/src/com/android/permissioncontroller/permission/ui/handheld/ManageStandardPermissionsFragment.java b/PermissionController/src/com/android/permissioncontroller/permission/ui/handheld/ManageStandardPermissionsFragment.java index bf99b7134..51c0906a2 100644 --- a/PermissionController/src/com/android/permissioncontroller/permission/ui/handheld/ManageStandardPermissionsFragment.java +++ b/PermissionController/src/com/android/permissioncontroller/permission/ui/handheld/ManageStandardPermissionsFragment.java @@ -31,7 +31,9 @@ import androidx.preference.Preference; import androidx.preference.PreferenceScreen; import com.android.modules.utils.build.SdkLevel; +import com.android.permission.flags.Flags; import com.android.permissioncontroller.R; +import com.android.permissioncontroller.permission.data.PermGroupsPackagesUiInfoLiveData; import com.android.permissioncontroller.permission.ui.UnusedAppsFragment; import com.android.permissioncontroller.permission.ui.model.ManageStandardPermissionsViewModel; import com.android.permissioncontroller.permission.utils.StringUtils; @@ -58,6 +60,14 @@ public final class ManageStandardPermissionsFragment extends ManagePermissionsFr return arguments; } + private PermGroupsPackagesUiInfoLiveData getPermGroupsLiveData() { + if (Flags.declutteredPermissionManagerEnabled()) { + return mViewModel.getUsedStandardPermGroupsUiInfo(); + } else { + return mViewModel.getUiDataLiveData(); + } + } + @Override public void onCreate(Bundle icicle) { super.onCreate(icicle); @@ -65,12 +75,12 @@ public final class ManageStandardPermissionsFragment extends ManagePermissionsFr final Application application = getActivity().getApplication(); mViewModel = new ViewModelProvider(this, AndroidViewModelFactory.getInstance(application)) .get(ManageStandardPermissionsViewModel.class); - mPermissionGroups = mViewModel.getUiDataLiveData().getValue(); + mPermissionGroups = getPermGroupsLiveData().getValue(); - mViewModel.getUiDataLiveData().observe(this, permissionGroups -> { + getPermGroupsLiveData().observe(this, permissionGroups -> { // Once we have loaded data for the first time, further loads should be staggered, // for performance reasons. - mViewModel.getUiDataLiveData().setLoadStaggered(true); + getPermGroupsLiveData().setLoadStaggered(true); if (permissionGroups != null) { mPermissionGroups = permissionGroups; updatePermissionsUi(); @@ -80,13 +90,18 @@ public final class ManageStandardPermissionsFragment extends ManagePermissionsFr } // If we've loaded all LiveDatas, no need to prioritize loading any particular one - if (!mViewModel.getUiDataLiveData().isStale()) { - mViewModel.getUiDataLiveData().setFirstLoadGroup(null); + if (!getPermGroupsLiveData().isStale()) { + getPermGroupsLiveData().setFirstLoadGroup(null); } }); mViewModel.getNumCustomPermGroups().observe(this, permNames -> updatePermissionsUi()); mViewModel.getNumAutoRevoked().observe(this, show -> updatePermissionsUi()); + if (Flags.declutteredPermissionManagerEnabled()) { + mViewModel.getNumUnusedStandardPermGroups().observe( + this, show -> updatePermissionsUi() + ); + } } @Override @@ -118,6 +133,14 @@ public final class ManageStandardPermissionsFragment extends ManagePermissionsFr if (mViewModel.getNumCustomPermGroups().getValue() != null) { numExtraPermissions = mViewModel.getNumCustomPermGroups().getValue(); } + if (Flags.declutteredPermissionManagerEnabled()) { + if (mViewModel.getNumUnusedStandardPermGroups().getValue() != null) { + // When decluttered permission manager is enabled, unused + // permission groups will also be displayed in the additional + // permissions screen. + numExtraPermissions += mViewModel.getNumUnusedStandardPermGroups().getValue(); + } + } Preference additionalPermissionsPreference = screen.findPreference(EXTRA_PREFS_KEY); if (numExtraPermissions == 0) { @@ -198,7 +221,7 @@ public final class ManageStandardPermissionsFragment extends ManagePermissionsFr public void showPermissionApps(String permissionGroupName) { // If we return to this page within a reasonable time, prioritize loading data from the // permission group whose page we are going to, as that is group most likely to have changed - mViewModel.getUiDataLiveData().setFirstLoadGroup(permissionGroupName); + getPermGroupsLiveData().setFirstLoadGroup(permissionGroupName); mViewModel.showPermissionApps(this, PermissionAppsFragment.createArgs( permissionGroupName, getArguments().getLong(EXTRA_SESSION_ID))); } diff --git a/PermissionController/src/com/android/permissioncontroller/permission/ui/model/ManageCustomPermissionsViewModel.kt b/PermissionController/src/com/android/permissioncontroller/permission/ui/model/ManageCustomPermissionsViewModel.kt index bd80a88cd..429799157 100644 --- a/PermissionController/src/com/android/permissioncontroller/permission/ui/model/ManageCustomPermissionsViewModel.kt +++ b/PermissionController/src/com/android/permissioncontroller/permission/ui/model/ManageCustomPermissionsViewModel.kt @@ -16,17 +16,23 @@ package com.android.permissioncontroller.permission.ui.model +import android.Manifest import android.app.Application +import android.content.Intent +import android.health.connect.HealthPermissions.HEALTH_PERMISSION_GROUP import android.os.Bundle import androidx.fragment.app.Fragment import androidx.lifecycle.AndroidViewModel +import androidx.lifecycle.MutableLiveData import androidx.lifecycle.ViewModel import androidx.lifecycle.ViewModelProvider import androidx.navigation.fragment.findNavController +import com.android.permission.flags.Flags import com.android.permissioncontroller.R import com.android.permissioncontroller.permission.data.PermGroupsPackagesLiveData import com.android.permissioncontroller.permission.data.PermGroupsPackagesUiInfoLiveData import com.android.permissioncontroller.permission.data.SmartUpdateMediatorLiveData +import com.android.permissioncontroller.permission.utils.Utils import com.android.permissioncontroller.permission.utils.navigateSafe /** @@ -38,6 +44,12 @@ import com.android.permissioncontroller.permission.utils.navigateSafe class ManageCustomPermissionsViewModel(private val app: Application) : AndroidViewModel(app) { val uiDataLiveData = PermGroupsPackagesUiInfoLiveData(app, UsedCustomPermGroupNamesLiveData()) + val additionaPermGroupsUiInfo = + PermGroupsPackagesUiInfoLiveData( + app, + if (Flags.declutteredPermissionManagerEnabled()) AdditionalPermGroupNamesLiveData(app) + else MutableLiveData<List<String>>(), + ) /** * Navigate to a Permission Apps fragment @@ -46,6 +58,15 @@ class ManageCustomPermissionsViewModel(private val app: Application) : AndroidVi * @param args The args to pass to the new fragment */ fun showPermissionApps(fragment: Fragment, args: Bundle) { + val groupName = args.getString(Intent.EXTRA_PERMISSION_GROUP_NAME) + if (groupName == Manifest.permission_group.NOTIFICATIONS) { + Utils.navigateToNotificationSettings(fragment.context!!) + return + } + if (Utils.isHealthPermissionUiEnabled() && groupName == HEALTH_PERMISSION_GROUP) { + Utils.navigateToHealthConnectSettings(fragment.context!!) + return + } fragment.findNavController().navigateSafe(R.id.manage_to_perm_apps, args) } } @@ -58,7 +79,8 @@ class ManageCustomPermissionsViewModel(private val app: Application) : AndroidVi class ManageCustomPermissionsViewModelFactory(private val app: Application) : ViewModelProvider.Factory { override fun <T : ViewModel> create(modelClass: Class<T>): T { - @Suppress("UNCHECKED_CAST") return ManageCustomPermissionsViewModel(app) as T + @Suppress("UNCHECKED_CAST") + return ManageCustomPermissionsViewModel(app) as T } } @@ -77,3 +99,32 @@ class UsedCustomPermGroupNamesLiveData : SmartUpdateMediatorLiveData<List<String /* No op override */ } } + +/** + * A LiveData that is the union of LiveData UsedCustomPermGroupNamesLiveData and + * UnusedStandardPermGroupNamesLiveData. + * + * @param app The current application of the fragment + */ +class AdditionalPermGroupNamesLiveData(private val app: Application) : + SmartUpdateMediatorLiveData<List<String>>() { + + val usedCustomGroupNames = UsedCustomPermGroupNamesLiveData() + val unusedStandardGroupNames = UnusedStandardPermGroupNamesLiveData(app) + + init { + addSource(usedCustomGroupNames) { update() } + addSource(unusedStandardGroupNames) { update() } + } + + private fun combineGroupNames( + groupNames1: List<String>?, + groupNames2: List<String>?, + ): List<String> { + return (groupNames1 ?: emptyList()) + (groupNames2 ?: emptyList()) + } + + override fun onUpdate() { + value = combineGroupNames(usedCustomGroupNames.value, unusedStandardGroupNames.value) + } +} diff --git a/PermissionController/src/com/android/permissioncontroller/permission/ui/model/ManageStandardPermissionsViewModel.kt b/PermissionController/src/com/android/permissioncontroller/permission/ui/model/ManageStandardPermissionsViewModel.kt index aeab0aa89..f94999626 100644 --- a/PermissionController/src/com/android/permissioncontroller/permission/ui/model/ManageStandardPermissionsViewModel.kt +++ b/PermissionController/src/com/android/permissioncontroller/permission/ui/model/ManageStandardPermissionsViewModel.kt @@ -23,8 +23,11 @@ import android.health.connect.HealthPermissions.HEALTH_PERMISSION_GROUP import android.os.Bundle import androidx.fragment.app.Fragment import androidx.lifecycle.AndroidViewModel +import androidx.lifecycle.MediatorLiveData +import androidx.lifecycle.MutableLiveData import androidx.lifecycle.map import androidx.navigation.fragment.findNavController +import com.android.permission.flags.Flags import com.android.permissioncontroller.R import com.android.permissioncontroller.permission.data.PermGroupsPackagesLiveData import com.android.permissioncontroller.permission.data.PermGroupsPackagesUiInfoLiveData @@ -45,7 +48,21 @@ import com.android.permissioncontroller.permission.utils.navigateSafe class ManageStandardPermissionsViewModel(private val app: Application) : AndroidViewModel(app) { val uiDataLiveData = PermGroupsPackagesUiInfoLiveData(app, StandardPermGroupNamesLiveData) + val usedStandardPermGroupsUiInfo = + PermGroupsPackagesUiInfoLiveData( + app, + if (Flags.declutteredPermissionManagerEnabled()) UsedStandardPermGroupNamesLiveData(app) + else MutableLiveData<List<String>>(), + ) val numCustomPermGroups = NumCustomPermGroupsWithPackagesLiveData() + val numUnusedStandardPermGroups = + MediatorLiveData<Int>().apply { + if (Flags.declutteredPermissionManagerEnabled()) { + addSource(UnusedStandardPermGroupNamesLiveData(app)) { groupNames -> + value = groupNames.size + } + } + } val numAutoRevoked = unusedAutoRevokePackagesLiveData.map { it?.size ?: 0 } /** @@ -98,3 +115,55 @@ class NumCustomPermGroupsWithPackagesLiveData() : SmartUpdateMediatorLiveData<In value = customPermGroupPackages.value?.size ?: 0 } } + +/** + * A LiveData that tracks the names of the platform-defined permission groups, such that at least + * one of the permissions in the group has been requested at runtime by at least one non-system + * application or has been pregranted to a non-system application. + * + * @param app The current application of the fragment + */ +class UsedStandardPermGroupNamesLiveData(private val app: Application) : + SmartUpdateMediatorLiveData<List<String>>() { + init { + addSource(PermGroupsPackagesUiInfoLiveData(app, StandardPermGroupNamesLiveData)) { + permGroups -> + if (permGroups.values.any { it != null }) { + value = + permGroups + .filterValues { it != null && it.nonSystemUserSetOrPreGranted > 0 } + .keys + .toList() + } + } + } + + override fun onUpdate() { + /* No op override */ + } +} + +/** + * A LiveData that tracks the names of the platform-defined permission groups, such that none of the + * the permissions in the group has been requested at runtime by any non-system application nor has + * been pregranted to any non-system application. + * + * @param app The current application of the fragment + */ +class UnusedStandardPermGroupNamesLiveData(private val app: Application) : + SmartUpdateMediatorLiveData<List<String>>() { + init { + addSource(PermGroupsPackagesUiInfoLiveData(app, StandardPermGroupNamesLiveData)) { + permGroups -> + value = + permGroups + .filterValues { it != null && it.nonSystemUserSetOrPreGranted == 0 } + .keys + .toList() + } + } + + override fun onUpdate() { + /* No op override */ + } +} diff --git a/PermissionController/src/com/android/permissioncontroller/permission/ui/wear/WearAppPermissionGroupsHelper.kt b/PermissionController/src/com/android/permissioncontroller/permission/ui/wear/WearAppPermissionGroupsHelper.kt index 078eefe3b..2933d6fda 100644 --- a/PermissionController/src/com/android/permissioncontroller/permission/ui/wear/WearAppPermissionGroupsHelper.kt +++ b/PermissionController/src/com/android/permissioncontroller/permission/ui/wear/WearAppPermissionGroupsHelper.kt @@ -19,6 +19,7 @@ package com.android.permissioncontroller.permission.ui.wear import android.content.Context import android.content.pm.PackageManager import android.content.pm.PermissionInfo +import android.health.connect.HealthPermissions.HEALTH_PERMISSION_GROUP import android.os.Build import android.os.UserHandle import android.util.ArraySet @@ -319,6 +320,10 @@ class WearAppPermissionGroupsHelper( ) { // Redirect to location controller extra package settings. LocationUtils.startLocationControllerExtraPackageSettings(context, user) + } else if (permGroupName.equals(HEALTH_PERMISSION_GROUP) + && android.permission.flags.Flags.replaceBodySensorPermissionEnabled()) { + // Redirect to Health&Fitness UI + Utils.navigateToAppHealthConnectSettings(fragment.requireContext(), packageName, user) } else { val args = WearAppPermissionFragment.createArgs( diff --git a/PermissionController/src/com/android/permissioncontroller/permission/ui/wear/WearManageStandardPermissionScreen.kt b/PermissionController/src/com/android/permissioncontroller/permission/ui/wear/WearManageStandardPermissionScreen.kt index bd1946759..9aacd65d3 100644 --- a/PermissionController/src/com/android/permissioncontroller/permission/ui/wear/WearManageStandardPermissionScreen.kt +++ b/PermissionController/src/com/android/permissioncontroller/permission/ui/wear/WearManageStandardPermissionScreen.kt @@ -17,6 +17,7 @@ package com.android.permissioncontroller.permission.ui.wear import android.graphics.drawable.Drawable +import android.permission.flags.Flags import androidx.compose.runtime.Composable import androidx.compose.runtime.getValue import androidx.compose.runtime.livedata.observeAsState @@ -77,7 +78,13 @@ internal fun getPermGroupChipParams( } return permissionGroups // Removing Health Connect from the list of permissions to fix b/331260850 - .filterNot { Utils.isHealthPermissionGroup(it.key) } + .let { + if (Flags.replaceBodySensorPermissionEnabled()) { + it + } else { + it.filterNot { Utils.isHealthPermissionGroup(it.key) } + } + } .mapNotNull { val uiInfo = it.value ?: return@mapNotNull null PermGroupChipParam( diff --git a/PermissionController/src/com/android/permissioncontroller/permission/ui/wear/elements/material3/WearPermissionButton.kt b/PermissionController/src/com/android/permissioncontroller/permission/ui/wear/elements/material3/WearPermissionButton.kt index 4ed9e92b9..e0adf1265 100644 --- a/PermissionController/src/com/android/permissioncontroller/permission/ui/wear/elements/material3/WearPermissionButton.kt +++ b/PermissionController/src/com/android/permissioncontroller/permission/ui/wear/elements/material3/WearPermissionButton.kt @@ -20,10 +20,13 @@ import androidx.compose.foundation.layout.RowScope import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier +import androidx.compose.ui.text.font.FontWeight +import androidx.compose.ui.text.style.Hyphens import androidx.wear.compose.material3.Button import androidx.wear.compose.material3.ButtonColors import androidx.wear.compose.material3.ButtonDefaults import androidx.wear.compose.material3.LocalTextConfiguration +import androidx.wear.compose.material3.LocalTextStyle import androidx.wear.compose.material3.Text import com.android.permissioncontroller.permission.ui.wear.elements.Chip import com.android.permissioncontroller.permission.ui.wear.theme.WearPermissionMaterialUIVersion @@ -94,6 +97,8 @@ private fun WearPermissionButtonInternal( text = label, modifier = Modifier.fillMaxWidth(), maxLines = labelMaxLines ?: LocalTextConfiguration.current.maxLines, + style = + LocalTextStyle.current.copy(fontWeight = FontWeight.W600, hyphens = Hyphens.Auto), ) } diff --git a/PermissionController/src/com/android/permissioncontroller/permission/ui/wear/elements/material3/WearPermissionButtonStyle.kt b/PermissionController/src/com/android/permissioncontroller/permission/ui/wear/elements/material3/WearPermissionButtonStyle.kt index 5a91ae46c..504c69bb0 100644 --- a/PermissionController/src/com/android/permissioncontroller/permission/ui/wear/elements/material3/WearPermissionButtonStyle.kt +++ b/PermissionController/src/com/android/permissioncontroller/permission/ui/wear/elements/material3/WearPermissionButtonStyle.kt @@ -21,6 +21,7 @@ import androidx.wear.compose.material.ChipColors import androidx.wear.compose.material.ChipDefaults import androidx.wear.compose.material3.ButtonColors import androidx.wear.compose.material3.ButtonDefaults +import com.android.permissioncontroller.permission.ui.wear.elements.chipDefaultColors import com.android.permissioncontroller.permission.ui.wear.elements.chipDisabledColors import com.android.permissioncontroller.permission.ui.wear.elements.material3.WearPermissionButtonStyle.DisabledLike import com.android.permissioncontroller.permission.ui.wear.elements.material3.WearPermissionButtonStyle.Primary @@ -41,7 +42,7 @@ enum class WearPermissionButtonStyle { @Composable internal fun WearPermissionButtonStyle.material2ChipColors(): ChipColors { return when (this) { - Primary -> ChipDefaults.primaryChipColors() + Primary -> chipDefaultColors() Secondary -> ChipDefaults.secondaryChipColors() Transparent -> ChipDefaults.childChipColors() DisabledLike -> chipDisabledColors() diff --git a/PermissionController/src/com/android/permissioncontroller/permission/ui/wear/elements/material3/WearPermissionListFooter.kt b/PermissionController/src/com/android/permissioncontroller/permission/ui/wear/elements/material3/WearPermissionListFooter.kt new file mode 100644 index 000000000..807c93370 --- /dev/null +++ b/PermissionController/src/com/android/permissioncontroller/permission/ui/wear/elements/material3/WearPermissionListFooter.kt @@ -0,0 +1,67 @@ +/* + * 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.elements.material3 + +import androidx.compose.foundation.layout.RowScope +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.requiredHeightIn +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import androidx.compose.ui.unit.dp +import androidx.wear.compose.material3.Button +import androidx.wear.compose.material3.ButtonDefaults +import androidx.wear.compose.material3.Text +import com.android.permissioncontroller.permission.ui.wear.elements.ListFooter +import com.android.permissioncontroller.permission.ui.wear.theme.WearPermissionMaterialUIVersion + +@Composable +fun WearPermissionListFooter( + materialUIVersion: WearPermissionMaterialUIVersion, + label: String, + iconBuilder: WearPermissionIconBuilder? = null, + onClick: (() -> Unit) = {}, +) { + if (materialUIVersion == WearPermissionMaterialUIVersion.MATERIAL2_5) { + ListFooter( + description = label, + iconRes = iconBuilder?.let { it.iconResource as Int }, + onClick = onClick, + ) + } else { + WearPermissionListFooterInternal(label, iconBuilder, onClick) + } +} + +@Composable +private fun WearPermissionListFooterInternal( + label: String, + iconBuilder: WearPermissionIconBuilder?, + onClick: () -> Unit, +) { + val footerTextComposable: (@Composable RowScope.() -> Unit) = { + Text(modifier = Modifier.fillMaxWidth(), text = label, maxLines = Int.MAX_VALUE) + } + Button( + icon = { iconBuilder?.build() }, + label = {}, + secondaryLabel = footerTextComposable, + enabled = true, + onClick = onClick, + modifier = Modifier.requiredHeightIn(min = 1.dp).fillMaxWidth(), + colors = ButtonDefaults.childButtonColors(), + ) +} 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 cfaaa0df9..adf179be6 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 @@ -35,15 +35,16 @@ import com.android.permissioncontroller.R import com.android.permissioncontroller.permission.ui.wear.theme.WearPermissionMaterialUIVersion.MATERIAL2_5 import com.android.permissioncontroller.permission.ui.wear.theme.WearPermissionMaterialUIVersion.MATERIAL3 +/** This enum is used to specify the material version used for a specific screen */ enum class WearPermissionMaterialUIVersion { MATERIAL2_5, MATERIAL3, } /** - * Supports both Material 3 and Material 2 theme. default version for permission theme will be - * LEGACY until we migrate enough screens to 3. LEGACY version will use material 3 overlay resources - * by default. + * Supports both Material 3 and Material 2_5 theme. default version for permission theme will be 2_5 + * until we migrate enough screens to 3. 2_5 version will use material 3 overlay resources if we + * enable material3 for even one screen (Permission screens will be migrated in phases). */ @Composable fun WearPermissionTheme( @@ -53,7 +54,9 @@ fun WearPermissionTheme( if (Build.VERSION.SDK_INT < Build.VERSION_CODES.VANILLA_ICE_CREAM) { WearPermissionLegacyTheme(content) } else { + // Whether we are ready to use material3 for any screen. val useBridgedTheme = Flags.wearComposeMaterial3() + // Material3 UI controls are still being used in the screen that the theme is applied if (version == MATERIAL3) { val material3Theme = WearOverlayableMaterial3Theme(LocalContext.current) Material3Theme( @@ -62,7 +65,12 @@ fun WearPermissionTheme( shapes = material3Theme.shapes, content = content, ) - } else if (version == MATERIAL2_5 && useBridgedTheme) { + } + // Material2_5 UI controls are still being used in the screen that the theme is applied, + // But some in-app screens(like permission grant screen) are migrated to material3. + // To avoid having two set of overlay resources, we will use material3 overlay resources to + // support material2_5 UI controls as well. + else if (version == MATERIAL2_5 && useBridgedTheme) { val material3Theme = WearOverlayableMaterial3Theme(LocalContext.current) val bridgedLegacyTheme = WearMaterialBridgedLegacyTheme.createFrom(material3Theme) MaterialTheme( @@ -71,7 +79,9 @@ fun WearPermissionTheme( shapes = bridgedLegacyTheme.shapes, content = content, ) - } else { + } + // We are not ready for material3 yet in any screens. + else { WearPermissionLegacyTheme(content) } } diff --git a/PermissionController/src/com/android/permissioncontroller/permission/utils/PermissionMapping.kt b/PermissionController/src/com/android/permissioncontroller/permission/utils/PermissionMapping.kt index 3198a4c09..a3446f802 100644 --- a/PermissionController/src/com/android/permissioncontroller/permission/utils/PermissionMapping.kt +++ b/PermissionController/src/com/android/permissioncontroller/permission/utils/PermissionMapping.kt @@ -139,6 +139,12 @@ object PermissionMapping { PLATFORM_PERMISSIONS[Manifest.permission.NEARBY_WIFI_DEVICES] = Manifest.permission_group.NEARBY_DEVICES } + // Ranging permission will be supported from Android B+, update this when isAtLeastB() + // is available. + if (SdkLevel.isAtLeastV() && Flags.rangingPermissionEnabled()) { + PLATFORM_PERMISSIONS[Manifest.permission.RANGING] = + Manifest.permission_group.NEARBY_DEVICES + } // Any updates to the permissions for the CALL_LOG permission group must also be made in // Permissions {@link com.android.role.controller.model.Permissions} in the role diff --git a/PermissionController/src/com/android/permissioncontroller/role/ui/wear/WearRequestRoleScreen.kt b/PermissionController/src/com/android/permissioncontroller/role/ui/wear/WearRequestRoleScreen.kt index 13a9cb6d6..ee8fe2545 100644 --- a/PermissionController/src/com/android/permissioncontroller/role/ui/wear/WearRequestRoleScreen.kt +++ b/PermissionController/src/com/android/permissioncontroller/role/ui/wear/WearRequestRoleScreen.kt @@ -30,22 +30,26 @@ import androidx.compose.ui.Modifier import androidx.compose.ui.platform.testTag import androidx.compose.ui.res.stringResource import androidx.compose.ui.unit.dp -import androidx.wear.compose.material.ChipDefaults -import androidx.wear.compose.material.MaterialTheme +import com.android.permission.flags.Flags import com.android.permissioncontroller.R -import com.android.permissioncontroller.permission.ui.wear.elements.Chip -import com.android.permissioncontroller.permission.ui.wear.elements.ListFooter import com.android.permissioncontroller.permission.ui.wear.elements.ScrollableScreen -import com.android.permissioncontroller.permission.ui.wear.elements.ToggleChip import com.android.permissioncontroller.permission.ui.wear.elements.ToggleChipToggleControl -import com.android.permissioncontroller.permission.ui.wear.elements.toggleChipBackgroundColors +import com.android.permissioncontroller.permission.ui.wear.elements.material3.WearPermissionButton +import com.android.permissioncontroller.permission.ui.wear.elements.material3.WearPermissionButtonStyle +import com.android.permissioncontroller.permission.ui.wear.elements.material3.WearPermissionIconBuilder +import com.android.permissioncontroller.permission.ui.wear.elements.material3.WearPermissionListFooter +import com.android.permissioncontroller.permission.ui.wear.elements.material3.WearPermissionToggleControl +import com.android.permissioncontroller.permission.ui.wear.elements.material3.WearPermissionToggleControlStyle +import com.android.permissioncontroller.permission.ui.wear.theme.WearPermissionMaterialUIVersion +import com.android.permissioncontroller.permission.ui.wear.theme.WearPermissionMaterialUIVersion.MATERIAL2_5 +import com.android.permissioncontroller.permission.ui.wear.theme.WearPermissionMaterialUIVersion.MATERIAL3 import com.android.permissioncontroller.role.ui.ManageRoleHolderStateLiveData @Composable fun WearRequestRoleScreen( helper: WearRequestRoleHelper, onSetAsDefault: (Boolean, String?) -> Unit, - onCanceled: () -> Unit + onCanceled: () -> Unit, ) { val roleLiveData = helper.viewModel.roleLiveData.observeAsState(emptyList()) val manageRoleHolderState = @@ -75,7 +79,15 @@ fun WearRequestRoleScreen( } } + val useMaterial3Controls = Flags.wearComposeMaterial3() + val materialUIVersion = + if (useMaterial3Controls) { + MATERIAL3 + } else { + MATERIAL2_5 + } WearRequestRoleContent( + materialUIVersion, isLoading, helper, roleLiveData.value, @@ -85,7 +97,7 @@ fun WearRequestRoleScreen( onCheckedChanged, onDontAskAgainCheckedChanged, onSetAsDefault, - onCanceled + onCanceled, ) if (isLoading && roleLiveData.value.isNotEmpty()) { @@ -95,6 +107,7 @@ fun WearRequestRoleScreen( @Composable internal fun WearRequestRoleContent( + materialUIVersion: WearPermissionMaterialUIVersion, isLoading: Boolean, helper: WearRequestRoleHelper, qualifyingApplications: List<Pair<ApplicationInfo, Boolean>>, @@ -104,56 +117,74 @@ internal fun WearRequestRoleContent( onCheckedChanged: (Boolean, String?, Boolean) -> Unit, onDontAskAgainCheckedChanged: (Boolean) -> Unit, onSetAsDefault: (Boolean, String?) -> Unit, - onCanceled: () -> Unit + onCanceled: () -> Unit, ) { ScrollableScreen( + materialUIVersion = materialUIVersion, image = helper.getIcon(), title = helper.getTitle(), showTimeText = false, - isLoading = isLoading + isLoading = isLoading, ) { - helper.getNonePreference(qualifyingApplications, selectedPackageName)?.let { + helper.getNonePreference(qualifyingApplications, selectedPackageName)?.let { pref -> item { - ToggleChip( - label = it.label, - icon = it.icon, - enabled = enabled && it.enabled, - checked = it.checked, + WearPermissionToggleControl( + materialUIVersion = materialUIVersion, + label = pref.label, + iconBuilder = pref.icon?.let { WearPermissionIconBuilder.builder(it) }, + enabled = enabled && pref.enabled, + checked = pref.checked, onCheckedChanged = { checked -> - run { onCheckedChanged(checked, it.packageName, it.isHolder) } + onCheckedChanged(checked, pref.packageName, pref.isHolder) }, toggleControl = ToggleChipToggleControl.Radio, - labelMaxLine = Integer.MAX_VALUE + labelMaxLines = Integer.MAX_VALUE, ) } - it.subTitle?.let { subTitle -> item { ListFooter(description = subTitle) } } + pref.subTitle?.let { subTitle -> + item { + WearPermissionListFooter( + materialUIVersion = materialUIVersion, + label = subTitle, + ) + } + } } for (pref in helper.getPreferences(qualifyingApplications, selectedPackageName)) { item { - ToggleChip( + WearPermissionToggleControl( + materialUIVersion = materialUIVersion, label = pref.label, - icon = pref.icon, + iconBuilder = pref.icon?.let { WearPermissionIconBuilder.builder(it) }, enabled = enabled && pref.enabled, checked = pref.checked, onCheckedChanged = { checked -> - run { onCheckedChanged(checked, pref.packageName, pref.isHolder) } + onCheckedChanged(checked, pref.packageName, pref.isHolder) }, toggleControl = ToggleChipToggleControl.Radio, ) } - pref.subTitle?.let { subTitle -> item { ListFooter(description = subTitle) } } + pref.subTitle?.let { subTitle -> + item { + WearPermissionListFooter( + materialUIVersion = materialUIVersion, + label = subTitle, + ) + } + } } if (helper.showDontAskButton()) { item { - ToggleChip( + WearPermissionToggleControl( + materialUIVersion = materialUIVersion, checked = dontAskAgain, enabled = enabled, onCheckedChanged = { checked -> run { onDontAskAgainCheckedChanged(checked) } }, label = stringResource(R.string.request_role_dont_ask_again), toggleControl = ToggleChipToggleControl.Checkbox, - colors = toggleChipBackgroundColors(), + style = WearPermissionToggleControlStyle.Transparent, modifier = Modifier.testTag("com.android.permissioncontroller:id/dont_ask_again"), ) @@ -163,17 +194,18 @@ internal fun WearRequestRoleContent( item { Spacer(modifier = Modifier.height(14.dp)) } item { - Chip( + WearPermissionButton( + materialUIVersion = materialUIVersion, label = stringResource(R.string.request_role_set_as_default), - textColor = MaterialTheme.colors.background, - colors = ChipDefaults.primaryChipColors(), + style = WearPermissionButtonStyle.Primary, enabled = helper.shouldSetAsDefaultEnabled(enabled), onClick = { onSetAsDefault(dontAskAgain, selectedPackageName) }, modifier = Modifier.testTag("android:id/button1"), ) } item { - Chip( + WearPermissionButton( + materialUIVersion = materialUIVersion, label = stringResource(R.string.cancel), enabled = enabled, onClick = { onCanceled() }, diff --git a/PermissionController/tests/mocking/Android.bp b/PermissionController/tests/mocking/Android.bp index a541f4577..37851b2bb 100644 --- a/PermissionController/tests/mocking/Android.bp +++ b/PermissionController/tests/mocking/Android.bp @@ -86,4 +86,7 @@ android_test { ], kotlincflags: ["-Xjvm-default=all"], + + // TODO(b/313706381): Remove jarjar once flagging lib is fixed + jarjar_rules: ":PermissionController-jarjar-rules", } diff --git a/PermissionController/tests/permissionui/src/com/android/permissioncontroller/permissionui/ui/handheld/ManageCustomPermissionsFragmentTest.kt b/PermissionController/tests/permissionui/src/com/android/permissioncontroller/permissionui/ui/handheld/ManageCustomPermissionsFragmentTest.kt index eb7be564b..b38f5f40a 100644 --- a/PermissionController/tests/permissionui/src/com/android/permissioncontroller/permissionui/ui/handheld/ManageCustomPermissionsFragmentTest.kt +++ b/PermissionController/tests/permissionui/src/com/android/permissioncontroller/permissionui/ui/handheld/ManageCustomPermissionsFragmentTest.kt @@ -26,10 +26,12 @@ import androidx.test.uiautomator.By import com.android.compatibility.common.util.SystemUtil.eventually import com.android.compatibility.common.util.SystemUtil.runWithShellPermissionIdentity import com.android.compatibility.common.util.UiAutomatorUtils2.waitFindObject +import com.android.compatibility.common.util.UiAutomatorUtils2.waitFindObjectOrNull import com.android.permissioncontroller.permissionui.getUsageCountsFromUi import com.android.permissioncontroller.permissionui.wakeUpScreen import com.google.common.truth.Truth.assertThat import org.junit.After +import org.junit.Assert.assertNotNull import org.junit.Before import org.junit.Test import org.junit.runner.RunWith @@ -47,6 +49,7 @@ class ManageCustomPermissionsFragmentTest : BaseHandheldPermissionUiTest() { private val PERM_LABEL = "Permission A" private val PERM = "com.android.permissioncontroller.tests.A" private val ADDITIONAL_PERMISSIONS_LABEL = "Additional permissions" + private val BODY_SENSORS_LABEL = "Body sensors" @Before fun setup() { @@ -92,6 +95,14 @@ class ManageCustomPermissionsFragmentTest : BaseHandheldPermissionUiTest() { eventually { assertThat(getUsageCountsFromUi(PERM_LABEL)).isEqualTo(original) } } + @Test + fun bodySensorsEitherDisplayedInMainPageOrInAdditional() { + if (waitFindObjectOrNull(By.textContains(BODY_SENSORS_LABEL)) == null) { + waitFindObject(By.textContains(ADDITIONAL_PERMISSIONS_LABEL)).click() + assertNotNull(waitFindObjectOrNull(By.textContains(BODY_SENSORS_LABEL))) + } + } + @After fun tearDown() { uninstallApp(DEFINER_PKG) diff --git a/PermissionController/tests/permissionui/src/com/android/permissioncontroller/permissionui/ui/handheld/ManageStandardPermissionsFragmentTest.kt b/PermissionController/tests/permissionui/src/com/android/permissioncontroller/permissionui/ui/handheld/ManageStandardPermissionsFragmentTest.kt index 1ad876245..fcce09450 100644 --- a/PermissionController/tests/permissionui/src/com/android/permissioncontroller/permissionui/ui/handheld/ManageStandardPermissionsFragmentTest.kt +++ b/PermissionController/tests/permissionui/src/com/android/permissioncontroller/permissionui/ui/handheld/ManageStandardPermissionsFragmentTest.kt @@ -23,6 +23,8 @@ import android.permission.cts.PermissionUtils.grantPermission import android.permission.cts.PermissionUtils.install import android.permission.cts.PermissionUtils.revokePermission import android.permission.cts.PermissionUtils.uninstallApp +import android.platform.test.annotations.RequiresFlagsEnabled +import android.platform.test.flag.junit.DeviceFlagsValueProvider import android.util.Log import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.uiautomator.By @@ -30,17 +32,23 @@ import com.android.compatibility.common.util.SystemUtil.eventually import com.android.compatibility.common.util.SystemUtil.getEventually import com.android.compatibility.common.util.SystemUtil.runWithShellPermissionIdentity import com.android.compatibility.common.util.UiAutomatorUtils2.waitFindObjectOrNull +import com.android.permission.flags.Flags import com.android.permissioncontroller.permissionui.getUsageCountsFromUi import com.android.permissioncontroller.permissionui.wakeUpScreen import com.google.common.truth.Truth.assertThat import org.junit.After +import org.junit.Assert.assertNull import org.junit.Before +import org.junit.Rule import org.junit.Test import org.junit.runner.RunWith /** Simple tests for {@link ManageStandardPermissionsFragment} */ @RunWith(AndroidJUnit4::class) class ManageStandardPermissionsFragmentTest : BaseHandheldPermissionUiTest() { + + @JvmField @Rule val checkFlagsRule = DeviceFlagsValueProvider.createCheckFlagsRule() + @Before fun setup() { wakeUpScreen() @@ -117,7 +125,7 @@ class ManageStandardPermissionsFragmentTest : BaseHandheldPermissionUiTest() { assertThat(afterInstall.granted).isEqualTo(original.granted) assertThat(afterInstall.total).isEqualTo(original.total + 1) }, - TIMEOUT + TIMEOUT, ) } @@ -127,13 +135,13 @@ class ManageStandardPermissionsFragmentTest : BaseHandheldPermissionUiTest() { install(LOCATION_USER_APK) eventually( { assertThat(getUsageCountsFromUi(LOCATION_GROUP_LABEL)).isNotEqualTo(original) }, - TIMEOUT + TIMEOUT, ) uninstallApp(LOCATION_USER_PKG) eventually( { assertThat(getUsageCountsFromUi(LOCATION_GROUP_LABEL)).isEqualTo(original) }, - TIMEOUT + TIMEOUT, ) } @@ -147,7 +155,7 @@ class ManageStandardPermissionsFragmentTest : BaseHandheldPermissionUiTest() { assertThat(getUsageCountsFromUi(LOCATION_GROUP_LABEL).total) .isEqualTo(original.total + 1) }, - TIMEOUT + TIMEOUT, ) grantPermission(LOCATION_USER_PKG, ACCESS_COARSE_LOCATION) @@ -170,7 +178,7 @@ class ManageStandardPermissionsFragmentTest : BaseHandheldPermissionUiTest() { assertThat(getUsageCountsFromUi(LOCATION_GROUP_LABEL).granted) .isNotEqualTo(original.granted) }, - TIMEOUT + TIMEOUT, ) revokePermission(LOCATION_USER_PKG, ACCESS_COARSE_LOCATION) @@ -190,7 +198,7 @@ class ManageStandardPermissionsFragmentTest : BaseHandheldPermissionUiTest() { { assertThat(getAdditionalPermissionCount()).isEqualTo(additionalPermissionBefore + 1) }, - TIMEOUT + TIMEOUT, ) } @@ -202,13 +210,13 @@ class ManageStandardPermissionsFragmentTest : BaseHandheldPermissionUiTest() { install(ADDITIONAL_USER_APK) eventually( { assertThat(getAdditionalPermissionCount()).isNotEqualTo(additionalPermissionBefore) }, - TIMEOUT + TIMEOUT, ) uninstallApp(ADDITIONAL_USER_PKG) eventually( { assertThat(getAdditionalPermissionCount()).isEqualTo(additionalPermissionBefore) }, - TIMEOUT + TIMEOUT, ) } @@ -220,16 +228,23 @@ class ManageStandardPermissionsFragmentTest : BaseHandheldPermissionUiTest() { install(ADDITIONAL_USER_APK) eventually( { assertThat(getAdditionalPermissionCount()).isNotEqualTo(additionalPermissionBefore) }, - TIMEOUT + TIMEOUT, ) uninstallApp(ADDITIONAL_DEFINER_PKG) eventually( { assertThat(getAdditionalPermissionCount()).isEqualTo(additionalPermissionBefore) }, - TIMEOUT + TIMEOUT, ) } + @Test + @RequiresFlagsEnabled(Flags.FLAG_DECLUTTERED_PERMISSION_MANAGER_ENABLED) + fun noUnusedPermissionGroupDisplayedInTheMainPage() { + eventually { assertNull(waitFindObjectOrNull(By.hasChild(By.textStartsWith("0 of 0")))) } + eventually { assertNull(waitFindObjectOrNull(By.hasChild(By.textStartsWith("0/0")))) } + } + companion object { private val LOG_TAG = ManageStandardPermissionsFragmentTest::class.java.simpleName diff --git a/service/Android.bp b/service/Android.bp index 8efce5ebe..b6e85b0fc 100644 --- a/service/Android.bp +++ b/service/Android.bp @@ -101,6 +101,7 @@ java_sdk_library { "modules-utils-backgroundthread", "modules-utils-build", "modules-utils-os", + // framework-permission-s already includes com.android.permission.flags-aconfig-java "role-controller", "safety-center-config", "safety-center-internal-data", @@ -111,6 +112,7 @@ java_sdk_library { "service-permission-statsd", "permissioncontroller-statsd", "service-permission-proto-stream", + "com.android.permission.flags-aconfig-java", ], errorprone: { javacflags: ["-Xep:GuardedBy:ERROR"], diff --git a/service/jarjar-rules.txt b/service/jarjar-rules.txt index 77e071672..4d4d6e050 100644 --- a/service/jarjar-rules.txt +++ b/service/jarjar-rules.txt @@ -1,5 +1,5 @@ # You may bypass this Gerrit IfThisThenThat Lint if your change doesn't affect -# RoleParser.applyJarjarTransformIfNeeded(), by adding NO_IFTTT=reason to your commit +# RoleParser.applyJarjarTransform(), by adding NO_IFTTT=reason to your commit # message. # LINT.IfChange rule android.app.appfunctions.flags.*FeatureFlags* com.android.permission.jarjar.@0 @@ -37,4 +37,4 @@ rule com.android.safetycenter.resources.** com.android.permission.jarjar.@0 rule com.google.protobuf.** com.android.permission.jarjar.@0 rule kotlin.** com.android.permission.jarjar.@0 rule com.android.permissioncontroller.PermissionControllerStatsLog com.android.permission.jarjar.@0 -# LINT.ThenChange(PermissionController/role-controller/java/com/android/role/controller/model/RoleParser.java:applyJarjarTransformIfNeeded) +# LINT.ThenChange(PermissionController/role-controller/java/com/android/role/controller/model/RoleParser.java:applyJarjarTransform) diff --git a/service/java/com/android/permission/compat/UserHandleCompat.java b/service/java/com/android/permission/compat/UserHandleCompat.java index 1901aa997..1b3ebb8d6 100644 --- a/service/java/com/android/permission/compat/UserHandleCompat.java +++ b/service/java/com/android/permission/compat/UserHandleCompat.java @@ -29,6 +29,13 @@ public final class UserHandleCompat { public static final int USER_ALL = UserHandle.ALL.getIdentifier(); /** + * A user ID to indicate an undefined user of the device. + * + * @see UserHandle#USER_NULL + */ + public static final @UserIdInt int USER_NULL = -10000; + + /** * A user ID to indicate the "system" user of the device. */ public static final int USER_SYSTEM = UserHandle.SYSTEM.getIdentifier(); diff --git a/service/java/com/android/safetycenter/UserProfileGroup.java b/service/java/com/android/safetycenter/UserProfileGroup.java index 3202c3776..a78113b04 100644 --- a/service/java/com/android/safetycenter/UserProfileGroup.java +++ b/service/java/com/android/safetycenter/UserProfileGroup.java @@ -30,6 +30,7 @@ import android.util.Log; import androidx.annotation.Nullable; +import com.android.permission.compat.UserHandleCompat; import com.android.permission.util.UserUtils; import java.lang.annotation.Retention; @@ -49,8 +50,6 @@ import java.util.Objects; public final class UserProfileGroup { private static final String TAG = "UserProfileGroup"; - // UserHandle#USER_NULL is a @TestApi so it cannot be accessed from the mainline module. - public static final @UserIdInt int USER_NULL = -10000; @UserIdInt private final int mProfileParentUserId; private final int[] mManagedProfilesUserIds; @@ -147,7 +146,7 @@ public final class UserProfileGroup { int managedProfilesUserIdsLen = 0; int managedRunningProfilesUserIdsLen = 0; - int privateProfileUserId = USER_NULL; + int privateProfileUserId = UserHandleCompat.USER_NULL; boolean privateProfileRunning = false; for (int i = 0; i < userProfiles.size(); i++) { @@ -228,7 +227,7 @@ public final class UserProfileGroup { /* destPos= */ 1, mManagedProfilesUserIds.length); - if (mPrivateProfileUserId != USER_NULL) { + if (mPrivateProfileUserId != UserHandleCompat.USER_NULL) { allProfileIds[allProfileIds.length - 1] = mPrivateProfileUserId; } @@ -269,7 +268,7 @@ public final class UserProfileGroup { case PROFILE_TYPE_MANAGED: return mManagedProfilesUserIds; case PROFILE_TYPE_PRIVATE: - return mPrivateProfileUserId != USER_NULL + return mPrivateProfileUserId != UserHandleCompat.USER_NULL ? new int[]{mPrivateProfileUserId} : new int[]{}; default: Log.w(TAG, "profiles requested for unexpected profile type " + profileType); @@ -308,7 +307,7 @@ public final class UserProfileGroup { private int getNumProfiles() { return 1 + mManagedProfilesUserIds.length - + (mPrivateProfileUserId == USER_NULL ? 0 : 1); + + (mPrivateProfileUserId == UserHandleCompat.USER_NULL ? 0 : 1); } /** @@ -361,7 +360,8 @@ public final class UserProfileGroup { } } - return USER_NULL != mPrivateProfileUserId && userId == mPrivateProfileUserId; + return UserHandleCompat.USER_NULL != mPrivateProfileUserId + && userId == mPrivateProfileUserId; } @Override diff --git a/tests/cts/permission/src/android/permission/cts/NoWifiStatePermissionTest.java b/tests/cts/permission/src/android/permission/cts/NoWifiStatePermissionTest.java index a0637827c..9fff22747 100644 --- a/tests/cts/permission/src/android/permission/cts/NoWifiStatePermissionTest.java +++ b/tests/cts/permission/src/android/permission/cts/NoWifiStatePermissionTest.java @@ -30,9 +30,6 @@ import androidx.test.ext.junit.runners.AndroidJUnit4; import androidx.test.filters.SmallTest; import androidx.test.platform.app.InstrumentationRegistry; -import com.android.compatibility.common.util.UserHelper; - -import org.junit.Assume; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; @@ -217,11 +214,6 @@ public class NoWifiStatePermissionTest { */ @Test(expected = SecurityException.class) public void testSetWifiEnabled() { - // Skip the test for passenger on Multi-user-multi-display devices for Automotive - UserHelper userHelper = new UserHelper(sContext); - Assume.assumeFalse( - "Skipped for visible background User as wifi is disabled for visible background " - + "user.", userHelper.isVisibleBackgroundUser()); mWifiManager.setWifiEnabled(true); } } diff --git a/tests/cts/permissionpolicy/Android.bp b/tests/cts/permissionpolicy/Android.bp index e6041eea2..07fde8bff 100644 --- a/tests/cts/permissionpolicy/Android.bp +++ b/tests/cts/permissionpolicy/Android.bp @@ -37,6 +37,8 @@ android_test { "permission-test-util-lib", "androidx.test.rules", "flag-junit", + "android.app.flags-aconfig", + "android.permission.flags-aconfig-java-export", ], srcs: [ "src/**/*.java", diff --git a/tests/cts/permissionpolicy/res/raw/android_manifest.xml b/tests/cts/permissionpolicy/res/raw/android_manifest.xml index 94493ecf7..d30931c3f 100644 --- a/tests/cts/permissionpolicy/res/raw/android_manifest.xml +++ b/tests/cts/permissionpolicy/res/raw/android_manifest.xml @@ -2396,6 +2396,16 @@ android:label="@string/permlab_nearby_wifi_devices" android:protectionLevel="dangerous" /> + <!-- Required to be able to range to devices using any ranging technology. + @FlaggedApi("android.permission.flags.ranging_permission_enabled") + <p>Protection level: dangerous --> + <permission android:name="android.permission.RANGING" + android:permissionGroup="android.permission-group.UNDEFINED" + android:description="@string/permdesc_ranging" + android:label="@string/permlab_ranging" + android:protectionLevel="dangerous" + android:featureFlag="android.permission.flags.ranging_permission_enabled" /> + <!-- @SystemApi @TestApi Allows an application to suspend other apps, which will prevent the user from using them until they are unsuspended. @hide @@ -2606,12 +2616,22 @@ <!-- @SystemApi Allows access to perform vendor effects in the vibrator. <p>Protection level: signature + @FlaggedApi("android.os.vibrator.vendor_vibration_effects") @hide --> <permission android:name="android.permission.VIBRATE_VENDOR_EFFECTS" android:protectionLevel="signature|privileged" android:featureFlag="android.os.vibrator.vendor_vibration_effects" /> + <!-- @SystemApi Allows access to start a vendor vibration session. + <p>Protection level: signature + @FlaggedApi("android.os.vibrator.vendor_vibration_effects") + @hide + --> + <permission android:name="android.permission.START_VIBRATION_SESSIONS" + android:protectionLevel="signature|privileged" + android:featureFlag="android.os.vibrator.vendor_vibration_effects" /> + <!-- @SystemApi Allows access to the vibrator state. <p>Protection level: signature @hide @@ -4248,6 +4268,18 @@ android:description="@string/permdesc_hideOverlayWindows" android:protectionLevel="normal" /> + <!-- Allows an app to enter Picture-in-Picture mode when the user is not explicitly requesting + it. This includes using {@link PictureInPictureParams.Builder#setAutoEnterEnabled} as well + as lifecycle methods such as {@link Activity#onUserLeaveHint} and {@link Activity#onPause} + to enter PiP when the user leaves the app. + This permission should only be used for certain PiP + <a href="{@docRoot}training/tv/get-started/multitasking#usage-types">usage types</a>. + @FlaggedApi("android.app.enable_tv_implicit_enter_pip_restriction") + --> + <permission android:name="android.permission.TV_IMPLICIT_ENTER_PIP" + android:protectionLevel="normal" + android:featureFlag="android.app.enable_tv_implicit_enter_pip_restriction" /> + <!-- ================================== --> <!-- Permissions affecting the system wallpaper --> <!-- ================================== --> @@ -4754,6 +4786,27 @@ <permission android:name="android.permission.PROVIDE_REMOTE_CREDENTIALS" android:protectionLevel="signature|privileged|role" /> + <!-- @FlaggedApi(com.android.settingslib.flags.Flags.FLAG_SETTINGS_CATALYST) + Allows an application to access the Settings Preference services to read settings exposed + by the system Settings app and system apps that contribute settings surfaced by the + Settings app. + <p>This allows the calling application to read settings values through the host + application, agnostic of underlying storage. --> + <permission android:name="android.permission.READ_SYSTEM_PREFERENCES" + android:protectionLevel="signature|privileged|role" + android:featureFlag="com.android.settingslib.flags.settings_catalyst" /> + + <!-- @FlaggedApi(com.android.settingslib.flags.Flags.FLAG_SETTINGS_CATALYST) + Allows an application to access the Settings Preference services to write settings + values exposed by the system Settings app and system apps that contribute settings surfaced + in the Settings app. + <p>This allows the calling application to write settings values + through the host application, agnostic of underlying storage. + <p>Protection Level: signature|privileged|appop - appop to be added in followup --> + <permission android:name="android.permission.WRITE_SYSTEM_PREFERENCES" + android:protectionLevel="signature|privileged" + android:featureFlag="com.android.settingslib.flags.settings_catalyst" /> + <!-- ========================================= --> <!-- Permissions for special development tools --> <!-- ========================================= --> @@ -8343,6 +8396,22 @@ android:protectionLevel="signature|privileged|vendorPrivileged" android:featureFlag="android.media.tv.flags.kids_mode_tvdb_sharing"/> + <!-- + This permission allows the system to receive PACKAGE_CHANGED broadcasts when the component + state of a non-exported component has been changed. + <p>Not for use by third-party applications. </p> + <p>Protection level: internal + @hide + --> + <permission + android:name="android.permission.INTERNAL_RECEIVE_PACKAGE_CHANGED_BROADCAST_ON_COMPONENT_STATE_CHANGED" + android:protectionLevel="internal" + android:featureFlag="android.content.pm.reduce_broadcasts_for_component_state_changes"/> + + <uses-permission + android:name="android.permission.INTERNAL_RECEIVE_PACKAGE_CHANGED_BROADCAST_ON_COMPONENT_STATE_CHANGED" + android:featureFlag="android.content.pm.reduce_broadcasts_for_component_state_changes"/> + <!-- Attribution for Geofencing service. --> <attribution android:tag="GeofencingService" android:label="@string/geofencing_service"/> <!-- Attribution for Country Detector. --> diff --git a/tests/cts/permissionpolicy/src/android/permissionpolicy/cts/RuntimePermissionProperties.kt b/tests/cts/permissionpolicy/src/android/permissionpolicy/cts/RuntimePermissionProperties.kt index 6b3ae5f2e..70832b6ba 100644 --- a/tests/cts/permissionpolicy/src/android/permissionpolicy/cts/RuntimePermissionProperties.kt +++ b/tests/cts/permissionpolicy/src/android/permissionpolicy/cts/RuntimePermissionProperties.kt @@ -33,6 +33,7 @@ import android.Manifest.permission.NEARBY_WIFI_DEVICES import android.Manifest.permission.PACKAGE_USAGE_STATS import android.Manifest.permission.POST_NOTIFICATIONS import android.Manifest.permission.PROCESS_OUTGOING_CALLS +import android.Manifest.permission.RANGING import android.Manifest.permission.READ_CALENDAR import android.Manifest.permission.READ_CALL_LOG import android.Manifest.permission.READ_CELL_BROADCASTS @@ -59,6 +60,7 @@ import android.content.pm.PackageManager.GET_PERMISSIONS import android.content.pm.PermissionInfo.PROTECTION_DANGEROUS import android.content.pm.PermissionInfo.PROTECTION_FLAG_APPOP import android.os.Build +import android.permission.flags.Flags import android.permission.PermissionManager import androidx.test.platform.app.InstrumentationRegistry import androidx.test.runner.AndroidJUnit4 @@ -187,6 +189,12 @@ class RuntimePermissionProperties { // runtime permission expectedPerms.add(READ_MEDIA_VISUAL_USER_SELECTED) + // Add runtime permissions added in B which were _not_ split from a previously existing + // runtime permission + if (Flags.rangingPermissionEnabled()) { + expectedPerms.add(RANGING) + } + assertThat(expectedPerms).containsExactlyElementsIn(platformRuntimePerms.map { it.name }) } } diff --git a/tests/cts/permissionui/src/android/permissionui/cts/CameraMicIndicatorsPermissionTest.kt b/tests/cts/permissionui/src/android/permissionui/cts/CameraMicIndicatorsPermissionTest.kt index e3197599c..19b67e729 100644 --- a/tests/cts/permissionui/src/android/permissionui/cts/CameraMicIndicatorsPermissionTest.kt +++ b/tests/cts/permissionui/src/android/permissionui/cts/CameraMicIndicatorsPermissionTest.kt @@ -28,6 +28,7 @@ import android.os.Build import android.os.Process import android.os.SystemClock import android.os.SystemProperties +import android.os.UserManager import android.permission.PermissionManager import android.permission.cts.MtsIgnore import android.platform.test.annotations.AsbSecurityTest @@ -161,6 +162,8 @@ class CameraMicIndicatorsPermissionTest : StsExtraBusinessLogicTestCase { @Before fun setUp() { + // Camera and Mic are not supported for secondary user visible as a background user. + assumeFalse(isAutomotiveWithVisibleBackgroundUser()) runWithShellPermissionIdentity { screenTimeoutBeforeTest = Settings.System.getLong(context.contentResolver, Settings.System.SCREEN_OFF_TIMEOUT) @@ -209,6 +212,9 @@ class CameraMicIndicatorsPermissionTest : StsExtraBusinessLogicTestCase { @After fun tearDown() { + if (isAutomotiveWithVisibleBackgroundUser()) { + return + } uninstall() if (isCar) { // Deselect the indicator since it persists otherwise @@ -775,4 +781,10 @@ class CameraMicIndicatorsPermissionTest : StsExtraBusinessLogicTestCase { private fun byOneOfText(vararg textValues: String) = By.text(Pattern.compile(textValues.joinToString(separator = "|") { Pattern.quote(it) })) + + fun isAutomotiveWithVisibleBackgroundUser(): Boolean { + val userManager = context.getSystemService(UserManager::class.java) + return packageManager.hasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE) && + userManager.isVisibleBackgroundUsersSupported() + } } |