diff options
Diffstat (limited to 'PermissionController')
18 files changed, 278 insertions, 36 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/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/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/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 |