summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--PermissionController/Android.bp8
-rw-r--r--PermissionController/jarjar-rules.txt25
-rw-r--r--PermissionController/res/values-bs/strings.xml2
-rw-r--r--PermissionController/res/values-el/strings.xml2
-rw-r--r--PermissionController/res/values-eu/strings.xml2
-rw-r--r--PermissionController/res/values-uk/strings.xml2
-rw-r--r--PermissionController/role-controller/java/com/android/role/controller/model/RoleParser.java12
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/data/AppPermGroupUiInfoLiveData.kt4
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/service/BackupHelper.java26
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/ui/handheld/ManageCustomPermissionsFragment.java14
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/ui/handheld/ManageStandardPermissionsFragment.java35
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/ui/model/ManageCustomPermissionsViewModel.kt53
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/ui/model/ManageStandardPermissionsViewModel.kt69
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/ui/wear/WearAppPermissionGroupsHelper.kt5
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/utils/PermissionMapping.kt6
-rw-r--r--PermissionController/tests/mocking/Android.bp3
-rw-r--r--PermissionController/tests/permissionui/src/com/android/permissioncontroller/permissionui/ui/handheld/ManageCustomPermissionsFragmentTest.kt11
-rw-r--r--PermissionController/tests/permissionui/src/com/android/permissioncontroller/permissionui/ui/handheld/ManageStandardPermissionsFragmentTest.kt35
-rw-r--r--service/Android.bp1
-rw-r--r--service/jarjar-rules.txt4
-rw-r--r--service/java/com/android/permission/util/UserUtils.java40
-rw-r--r--service/java/com/android/safetycenter/UserProfileGroup.java42
-rw-r--r--tests/cts/permission/src/android/permission/cts/NoWifiStatePermissionTest.java8
-rw-r--r--tests/cts/permissionpolicy/Android.bp2
-rw-r--r--tests/cts/permissionpolicy/res/raw/android_manifest.xml69
-rw-r--r--tests/cts/permissionpolicy/src/android/permissionpolicy/cts/RuntimePermissionProperties.kt8
-rw-r--r--tests/cts/permissionui/src/android/permissionui/cts/CameraMicIndicatorsPermissionTest.kt12
27 files changed, 414 insertions, 86 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">"Να επιτρέπεται στην εφαρμογή &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; η πρόσβαση σε &lt;b&gt;φωτογραφίες, βίντεο, μουσική, ήχο και άλλα αρχεία&lt;/b&gt; της συσκευής;"</string>
<string name="permgrouprequest_read_media_aural" msgid="2593365397347577812">"Να επιτρέπεται στην εφαρμογή &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; η πρόσβαση στη μουσική και στα αρχεία ήχου αυτής της συσκευής;"</string>
<string name="permgrouprequest_device_aware_read_media_aural" msgid="7927884506238101064">"Να επιτρέπεται στην εφαρμογή &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; η πρόσβαση σε μουσική και σε ήχο στη συσκευή &lt;b&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/b&gt;;"</string>
- <string name="permgrouprequest_read_media_visual" msgid="5548780620779729975">"Να επιτρέπεται στην &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; η πρόσβαση στις φωτογραφίες και τα βίντεο αυτής της συσκευής;"</string>
+ <string name="permgrouprequest_read_media_visual" msgid="5548780620779729975">"Να επιτρέπεται στην εφαρμογή &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; η πρόσβαση στις φωτογραφίες και τα βίντεο αυτής της συσκευής;"</string>
<string name="permgrouprequest_device_aware_read_media_visual" msgid="3122576538319059333">"Να επιτρέπεται στην εφαρμογή &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; η πρόσβαση σε φωτογραφίες και σε βίντεο στη συσκευή &lt;b&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/b&gt;;"</string>
<string name="permgrouprequest_more_photos" msgid="128933814654231321">"Να επιτρέπεται στην εφαρμογή &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; η πρόσβαση σε περισσότερες φωτογραφίες και βίντεο αυτής της συσκευής;"</string>
<string name="permgrouprequest_device_aware_more_photos" msgid="1703469013613723053">"Να επιτρέπεται στην εφαρμογή &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; η πρόσβαση σε περισσότερες φωτογραφίες και βίντεο στη συσκευή &lt;b&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/b&gt;;"</string>
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
diff --git a/service/Android.bp b/service/Android.bp
index 58b6c7ba7..b6e85b0fc 100644
--- a/service/Android.bp
+++ b/service/Android.bp
@@ -112,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/util/UserUtils.java b/service/java/com/android/permission/util/UserUtils.java
index 33389a88f..639c7aacb 100644
--- a/service/java/com/android/permission/util/UserUtils.java
+++ b/service/java/com/android/permission/util/UserUtils.java
@@ -19,6 +19,7 @@ package com.android.permission.util;
import android.annotation.NonNull;
import android.annotation.UserIdInt;
import android.content.Context;
+import android.content.pm.PackageManager;
import android.os.Binder;
import android.os.Process;
import android.os.UserHandle;
@@ -30,6 +31,7 @@ import com.android.permission.compat.UserHandleCompat;
import com.android.permission.flags.Flags;
import java.util.List;
+import java.util.Objects;
/** Utility class to deal with Android users. */
public final class UserUtils {
@@ -81,6 +83,32 @@ public final class UserUtils {
}
}
+ /** Returns all the enabled user profiles on the device. */
+ @NonNull
+ public static List<UserHandle> getUserProfiles(@NonNull Context context) {
+ UserManager userManager = context.getSystemService(UserManager.class);
+ // This call requires the QUERY_USERS permission.
+ final long identity = Binder.clearCallingIdentity();
+ try {
+ return userManager.getUserProfiles();
+ } finally {
+ Binder.restoreCallingIdentity(identity);
+ }
+ }
+
+ /** Returns the parent of a given user. */
+ public static UserHandle getProfileParent(@UserIdInt int userId, @NonNull Context context) {
+ Context userContext = getUserContext(userId, context);
+ UserManager userManager = userContext.getSystemService(UserManager.class);
+ // This call requires the INTERACT_ACROSS_USERS permission.
+ final long identity = Binder.clearCallingIdentity();
+ try {
+ return userManager.getProfileParent(UserHandle.of(userId));
+ } finally {
+ Binder.restoreCallingIdentity(identity);
+ }
+ }
+
/** Returns whether a given {@code userId} corresponds to a managed profile. */
public static boolean isManagedProfile(@UserIdInt int userId, @NonNull Context context) {
UserManager userManager = context.getSystemService(UserManager.class);
@@ -107,8 +135,7 @@ public final class UserUtils {
// MANAGE_USERS, QUERY_USERS, or INTERACT_ACROSS_USERS.
final long identity = Binder.clearCallingIdentity();
try {
- Context userContext = context
- .createContextAsUser(UserHandle.of(userId), /* flags= */ 0);
+ Context userContext = getUserContext(userId, context);
UserManager userManager = userContext.getSystemService(UserManager.class);
return userManager != null && userManager.isPrivateProfile();
} finally {
@@ -141,4 +168,13 @@ public final class UserUtils {
Binder.restoreCallingIdentity(identity);
}
}
+
+ @NonNull
+ public static Context getUserContext(@UserIdInt int userId, @NonNull Context context) {
+ if (SdkLevel.isAtLeastS() && context.getUser().getIdentifier() == userId) {
+ return context;
+ } else {
+ return context.createContextAsUser(UserHandle.of(userId), 0);
+ }
+ }
}
diff --git a/service/java/com/android/safetycenter/UserProfileGroup.java b/service/java/com/android/safetycenter/UserProfileGroup.java
index 46a440bf7..3202c3776 100644
--- a/service/java/com/android/safetycenter/UserProfileGroup.java
+++ b/service/java/com/android/safetycenter/UserProfileGroup.java
@@ -134,9 +134,9 @@ public final class UserProfileGroup {
* is disabled.
*/
public static UserProfileGroup fromUser(Context context, @UserIdInt int userId) {
- UserManager userManager = getUserManagerForUser(userId, context);
- List<UserHandle> userProfiles = getEnabledUserProfiles(userManager);
- UserHandle profileParent = getProfileParent(userManager, userId);
+ Context userContext = UserUtils.getUserContext(userId, context);
+ List<UserHandle> userProfiles = UserUtils.getUserProfiles(userContext);
+ UserHandle profileParent = UserUtils.getProfileParent(userId, userContext);
int profileParentUserId = userId;
if (profileParent != null) {
profileParentUserId = profileParent.getIdentifier();
@@ -192,23 +192,10 @@ public final class UserProfileGroup {
}
private static UserManager getUserManagerForUser(@UserIdInt int userId, Context context) {
- Context userContext = getUserContext(context, UserHandle.of(userId));
+ Context userContext = UserUtils.getUserContext(userId, context);
return requireNonNull(userContext.getSystemService(UserManager.class));
}
- private static Context getUserContext(Context context, UserHandle userHandle) {
- if (Process.myUserHandle().equals(userHandle)) {
- return context;
- } else {
- try {
- return context.createPackageContextAsUser(
- context.getPackageName(), /* flags= */ 0, userHandle);
- } catch (PackageManager.NameNotFoundException doesNotHappen) {
- throw new IllegalStateException(doesNotHappen);
- }
- }
- }
-
private static boolean isProfile(@UserIdInt int userId, Context context) {
// This call requires the INTERACT_ACROSS_USERS permission.
final long callingId = Binder.clearCallingIdentity();
@@ -220,27 +207,6 @@ public final class UserProfileGroup {
}
}
- private static List<UserHandle> getEnabledUserProfiles(UserManager userManager) {
- // This call requires the QUERY_USERS permission.
- final long callingId = Binder.clearCallingIdentity();
- try {
- return userManager.getUserProfiles();
- } finally {
- Binder.restoreCallingIdentity(callingId);
- }
- }
-
- @Nullable
- private static UserHandle getProfileParent(UserManager userManager, @UserIdInt int userId) {
- // This call requires the INTERACT_ACROSS_USERS permission.
- final long callingId = Binder.clearCallingIdentity();
- try {
- return userManager.getProfileParent(UserHandle.of(userId));
- } finally {
- Binder.restoreCallingIdentity(callingId);
- }
- }
-
/** Returns the profile parent user id of the {@link UserProfileGroup}. */
public int getProfileParentUserId() {
return mProfileParentUserId;
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()
+ }
}