diff options
20 files changed, 416 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/xml/roles.xml b/PermissionController/res/xml/roles.xml index b067c41b5..2f9ac3148 100644 --- a/PermissionController/res/xml/roles.xml +++ b/PermissionController/res/xml/roles.xml @@ -107,6 +107,7 @@ defaultHolders="config_defaultAssistant" description="@string/role_assistant_description" exclusive="true" + exclusivity="user" fallBackToDefaultHolder="true" showNone="true" label="@string/role_assistant_label" @@ -173,6 +174,7 @@ defaultHolders="config_defaultBrowser" description="@string/role_browser_description" exclusive="true" + exclusivity="user" label="@string/role_browser_label" overrideUserWhenGranting="true" requestDescription="@string/role_browser_request_description" @@ -216,6 +218,7 @@ defaultHolders="config_defaultDialer" description="@string/role_dialer_description" exclusive="true" + exclusivity="user" fallBackToDefaultHolder="true" label="@string/role_dialer_label" overrideUserWhenGranting="true" @@ -304,6 +307,7 @@ defaultHolders="config_defaultSms" description="@string/role_sms_description" exclusive="true" + exclusivity="user" label="@string/role_sms_label" overrideUserWhenGranting="true" requestDescription="@string/role_sms_request_description" @@ -394,6 +398,7 @@ behavior="EmergencyRoleBehavior" description="@string/role_emergency_description" exclusive="true" + exclusivity="user" label="@string/role_emergency_label" overrideUserWhenGranting="true" requestDescription="@string/role_emergency_request_description" @@ -426,6 +431,7 @@ behavior="HomeRoleBehavior" description="@string/role_home_description" exclusive="true" + exclusivity="user" label="@string/role_home_label" overrideUserWhenGranting="true" requestDescription="@string/role_home_request_description" @@ -472,6 +478,7 @@ defaultHolders="config_defaultCallRedirection" description="@string/role_call_redirection_description" exclusive="true" + exclusivity="user" label="@string/role_call_redirection_label" overrideUserWhenGranting="true" requestDescription="@string/role_call_redirection_request_description" @@ -493,6 +500,7 @@ defaultHolders="config_defaultCallScreening" description="@string/role_call_screening_description" exclusive="true" + exclusivity="user" label="@string/role_call_screening_label" overrideUserWhenGranting="true" requestDescription="@string/role_call_screening_request_description" @@ -518,6 +526,7 @@ name="android.app.role.SYSTEM_GALLERY" defaultHolders="config_systemGallery" exclusive="true" + exclusivity="user" static="true" systemOnly="true" visible="false"> @@ -537,6 +546,7 @@ behavior="v31.AutomotiveRoleBehavior" defaultHolders="config_systemAutomotiveCluster" exclusive="true" + exclusivity="user" minSdkVersion="31" static="true" systemOnly="true" @@ -554,6 +564,7 @@ behavior="v31.CompanionDeviceWatchRoleBehavior" description="@string/role_watch_description" exclusive="false" + exclusivity="none" minSdkVersion="31" systemOnly="false" visible="false"> @@ -582,6 +593,7 @@ name="android.app.role.SYSTEM_AUTOMOTIVE_PROJECTION" defaultHolders="config_systemAutomotiveProjection" exclusive="true" + exclusivity="user" minSdkVersion="31" static="true" systemOnly="true" @@ -619,6 +631,7 @@ behavior="v31.SystemShellRoleBehavior" defaultHolders="config_systemShell" exclusive="true" + exclusivity="user" minSdkVersion="31" static="true" systemOnly="true" @@ -714,6 +727,7 @@ name="android.app.role.SYSTEM_CONTACTS" defaultHolders="config_systemContacts" exclusive="true" + exclusivity="user" minSdkVersion="31" static="true" systemOnly="true" @@ -730,6 +744,7 @@ allowBypassingQualification="true" defaultHolders="config_systemSpeechRecognizer" exclusive="true" + exclusivity="user" minSdkVersion="31" static="true" systemOnly="true" @@ -751,6 +766,7 @@ name="android.app.role.SYSTEM_WIFI_COEX_MANAGER" defaultHolders="config_systemWifiCoexManager" exclusive="true" + exclusivity="user" minSdkVersion="31" static="true" systemOnly="true" @@ -765,6 +781,7 @@ name="android.app.role.SYSTEM_WELLBEING" defaultHolders="config_systemWellbeing" exclusive="true" + exclusivity="user" minSdkVersion="31" static="true" systemOnly="true" @@ -793,6 +810,7 @@ behavior="v31.TelevisionRoleBehavior" defaultHolders="config_systemTelevisionNotificationHandler" exclusive="true" + exclusivity="user" minSdkVersion="31" static="true" systemOnly="true" @@ -811,6 +829,7 @@ name="android.app.role.SYSTEM_COMPANION_DEVICE_PROVIDER" defaultHolders="config_systemCompanionDeviceProvider" exclusive="true" + exclusivity="user" minSdkVersion="31" static="true" systemOnly="true" @@ -846,6 +865,7 @@ name="android.app.role.SYSTEM_UI_INTELLIGENCE" defaultHolders="config_systemUiIntelligence" exclusive="true" + exclusivity="user" minSdkVersion="31" static="true" systemOnly="true" @@ -901,6 +921,7 @@ name="android.app.role.SYSTEM_AMBIENT_AUDIO_INTELLIGENCE" defaultHolders="config_systemAmbientAudioIntelligence" exclusive="true" + exclusivity="user" minSdkVersion="31" static="true" systemOnly="true" @@ -947,6 +968,7 @@ name="android.app.role.SYSTEM_AUDIO_INTELLIGENCE" defaultHolders="config_systemAudioIntelligence" exclusive="true" + exclusivity="user" minSdkVersion="31" static="true" systemOnly="true" @@ -993,6 +1015,7 @@ name="android.app.role.SYSTEM_NOTIFICATION_INTELLIGENCE" defaultHolders="config_systemNotificationIntelligence" exclusive="true" + exclusivity="user" minSdkVersion="31" static="true" systemOnly="true" @@ -1035,6 +1058,7 @@ name="android.app.role.SYSTEM_TEXT_INTELLIGENCE" defaultHolders="config_systemTextIntelligence" exclusive="true" + exclusivity="user" minSdkVersion="31" static="true" systemOnly="true" @@ -1075,6 +1099,7 @@ name="android.app.role.SYSTEM_VISUAL_INTELLIGENCE" defaultHolders="config_systemVisualIntelligence" exclusive="true" + exclusivity="user" minSdkVersion="31" static="true" systemOnly="true" @@ -1100,6 +1125,7 @@ name="android.app.role.SYSTEM_DOCUMENT_MANAGER" behavior="v33.DocumentManagerRoleBehavior" exclusive="true" + exclusivity="user" minSdkVersion="33" static="true" systemOnly="true" @@ -1132,6 +1158,7 @@ allowBypassingQualification="true" defaultHolders="config_systemActivityRecognizer" exclusive="false" + exclusivity="none" static="true" systemOnly="true" visible="false"> @@ -1151,6 +1178,7 @@ name="android.app.role.SYSTEM_UI" defaultHolders="config_systemUi" exclusive="true" + exclusivity="user" minSdkVersion="31" static="true" systemOnly="true" @@ -1177,6 +1205,7 @@ behavior="v31.TelevisionRoleBehavior" defaultHolders="config_systemTelevisionRemoteService" exclusive="true" + exclusivity="user" minSdkVersion="31" static="true" systemOnly="true" @@ -1196,6 +1225,7 @@ behavior="v33.CompanionDeviceAppStreamingRoleBehavior" description="@string/role_app_streaming_description" exclusive="false" + exclusivity="none" minSdkVersion="33" systemOnly="true" visible="false"> @@ -1220,6 +1250,7 @@ behavior="v33.CompanionDeviceComputerRoleBehavior" description="@string/role_companion_device_computer_description" exclusive="false" + exclusivity="none" minSdkVersion="33" systemOnly="true" visible="false"> @@ -1239,6 +1270,7 @@ name="android.app.role.COMPANION_DEVICE_GLASSES" behavior="v34.CompanionDeviceGlassesRoleBehavior" exclusive="false" + exclusivity="none" minSdkVersion="34" systemOnly="false" visible="false"> @@ -1265,6 +1297,7 @@ name="android.app.role.COMPANION_DEVICE_NEARBY_DEVICE_STREAMING" allowBypassingQualification="true" exclusive="false" + exclusivity="none" minSdkVersion="34" systemOnly="true" visible="false"> @@ -1278,6 +1311,7 @@ name="android.app.role.SYSTEM_SUPERVISION" defaultHolders="config_systemSupervision" exclusive="true" + exclusivity="user" minSdkVersion="33" static="true" systemOnly="true" @@ -1300,6 +1334,7 @@ behavior="v33.DevicePolicyManagementRoleBehavior" defaultHolders="config_devicePolicyManagement" exclusive="true" + exclusivity="user" minSdkVersion="33" static="true" systemOnly="false" @@ -1412,6 +1447,7 @@ name="android.app.role.SYSTEM_APP_PROTECTION_SERVICE" defaultHolders="config_systemAppProtectionService" exclusive="true" + exclusivity="user" minSdkVersion="33" static="true" systemOnly="true" @@ -1440,6 +1476,7 @@ behavior="v31.AutomotiveRoleBehavior" defaultHolders="config_systemAutomotiveCalendarSyncManager" exclusive="true" + exclusivity="user" minSdkVersion="33" static="true" systemOnly="true" @@ -1461,6 +1498,7 @@ defaultHolders="config_defaultAutomotiveNavigation" description="@string/role_automotive_navigation_description" exclusive="true" + exclusivity="user" label="@string/role_automotive_navigation_label" minSdkVersion="33" overrideUserWhenGranting="true" @@ -1534,6 +1572,7 @@ name="android.app.role.SYSTEM_SETTINGS_INTELLIGENCE" defaultHolders="config_systemSettingsIntelligence" exclusive="true" + exclusivity="user" minSdkVersion="33" static="true" systemOnly="true" @@ -1551,6 +1590,7 @@ name="android.app.role.SYSTEM_BLUETOOTH_STACK" defaultHolders="config_systemBluetoothStack" exclusive="true" + exclusivity="user" minSdkVersion="33" static="true" systemOnly="true" @@ -1575,6 +1615,7 @@ <role name="android.app.role.FINANCED_DEVICE_KIOSK" exclusive="true" + exclusivity="user" minSdkVersion="34" visible="false"> <permissions> @@ -1590,6 +1631,7 @@ name="android.app.role.SYSTEM_FINANCED_DEVICE_CONTROLLER" defaultHolders="config_systemFinancedDeviceController" exclusive="true" + exclusivity="user" minSdkVersion="34" static="true" systemOnly="true" @@ -1617,6 +1659,7 @@ behavior="v33.SystemWearHealthServiceRoleBehavior" defaultHolders="config_systemWearHealthService" exclusive="true" + exclusivity="user" minSdkVersion="33" static="true" systemOnly="true" @@ -1644,6 +1687,7 @@ defaultHolders="config_defaultNotes" description="@string/role_notes_description" exclusive="true" + exclusivity="user" label="@string/role_notes_label" minSdkVersion="34" overrideUserWhenGranting="true" @@ -1685,6 +1729,7 @@ allowBypassingQualification="true" defaultHolders="config_systemCallStreaming" exclusive="true" + exclusivity="user" minSdkVersion="34" static="true" systemOnly="true" @@ -1707,6 +1752,7 @@ behavior="v35.RetailDemoRoleBehavior" defaultHolders="config_defaultRetailDemo" exclusive="true" + exclusivity="user" minSdkVersion="35" static="true" visible="false"> @@ -1733,6 +1779,7 @@ defaultHolders="config_defaultWallet" description="@string/role_wallet_description" exclusive="true" + exclusivity="user" label="@string/role_wallet_label" minSdkVersion="35" overrideUserWhenGranting="true" @@ -1743,5 +1790,4 @@ shortLabel="@string/role_wallet_short_label" uiBehavior="v35.WalletRoleUiBehavior"/> - </roles> diff --git a/PermissionController/role-controller/Android.bp b/PermissionController/role-controller/Android.bp index 166823b08..612c979b5 100644 --- a/PermissionController/role-controller/Android.bp +++ b/PermissionController/role-controller/Android.bp @@ -17,6 +17,9 @@ package { default_applicable_licenses: ["Android-Apache-2.0"], } +// Any place that role-controller is added as a dependency must also include +// "com.android.permission.flags-aconfig-java" or +// "com.android.permission.flags-aconfig-java-export", java_library { name: "role-controller", srcs: [ @@ -24,6 +27,7 @@ java_library { ], libs: [ "androidx.annotation_annotation", + "com.android.permission.flags-aconfig-java", ], static_libs: [ "modules-utils-build_system", diff --git a/PermissionController/role-controller/java/com/android/role/controller/model/Role.java b/PermissionController/role-controller/java/com/android/role/controller/model/Role.java index 2f2431ece..570ef034a 100644 --- a/PermissionController/role-controller/java/com/android/role/controller/model/Role.java +++ b/PermissionController/role-controller/java/com/android/role/controller/model/Role.java @@ -38,6 +38,7 @@ import android.util.ArrayMap; import android.util.ArraySet; import android.util.Log; +import androidx.annotation.IntDef; import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.annotation.StringRes; @@ -49,6 +50,8 @@ import com.android.role.controller.util.PackageUtils; import com.android.role.controller.util.RoleManagerCompat; import com.android.role.controller.util.UserUtils; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; import java.util.ArrayList; import java.util.Collections; import java.util.List; @@ -83,6 +86,27 @@ public class Role { private static final String CERTIFICATE_SEPARATOR = ":"; + @Retention(RetentionPolicy.SOURCE) + @IntDef({ + EXCLUSIVITY_NONE, + EXCLUSIVITY_USER, + EXCLUSIVITY_PROFILE_GROUP + }) + public @interface Exclusivity {} + + /** + * Does not enforce any exclusivity, which means multiple apps may hold this role in a user. + */ + public static final int EXCLUSIVITY_NONE = 0; + + /** Enforces exclusivity within one user. */ + public static final int EXCLUSIVITY_USER = 1; + + /** + * Enforces exclusivity across all users (including profile users) in the same profile group. + */ + public static final int EXCLUSIVITY_PROFILE_GROUP = 2; + /** * The name of this role. Must be unique. */ @@ -110,9 +134,10 @@ public class Role { private final int mDescriptionResource; /** - * Whether this role is exclusive, i.e. allows at most one holder. + * The exclusivity of this role, i.e. whether this role allows multiple holders, or allows at + * most one holder within a user or a profile group. */ - private final boolean mExclusive; + private final int mExclusivity; /** * Whether this role should fall back to the default holder. @@ -186,8 +211,8 @@ public class Role { /** * Whether the UI for this role will show the "None" item. Only valid if this role is - * {@link #mExclusive exclusive}, and {@link #getFallbackHolder(Context)} should also return - * empty to allow actually selecting "None". + * {@link #isExclusive()}, and {@link #getFallbackHolder(Context)} should + * also return empty to allow actually selecting "None". */ private final boolean mShowNone; @@ -241,14 +266,14 @@ public class Role { public Role(@NonNull String name, boolean allowBypassingQualification, @Nullable RoleBehavior behavior, @Nullable String defaultHoldersResourceName, - @StringRes int descriptionResource, boolean exclusive, boolean fallBackToDefaultHolder, - @Nullable Supplier<Boolean> featureFlag, @StringRes int labelResource, - int maxSdkVersion, int minSdkVersion, boolean onlyGrantWhenAdded, - boolean overrideUserWhenGranting, @StringRes int requestDescriptionResource, - @StringRes int requestTitleResource, boolean requestable, - @StringRes int searchKeywordsResource, @StringRes int shortLabelResource, - boolean showNone, boolean statik, boolean systemOnly, boolean visible, - @NonNull List<RequiredComponent> requiredComponents, + @StringRes int descriptionResource, @Exclusivity int exclusivity, + boolean fallBackToDefaultHolder, @Nullable Supplier<Boolean> featureFlag, + @StringRes int labelResource, int maxSdkVersion, int minSdkVersion, + boolean onlyGrantWhenAdded, boolean overrideUserWhenGranting, + @StringRes int requestDescriptionResource, @StringRes int requestTitleResource, + boolean requestable, @StringRes int searchKeywordsResource, + @StringRes int shortLabelResource, boolean showNone, boolean statik, boolean systemOnly, + boolean visible, @NonNull List<RequiredComponent> requiredComponents, @NonNull List<Permission> permissions, @NonNull List<Permission> appOpPermissions, @NonNull List<AppOp> appOps, @NonNull List<PreferredActivity> preferredActivities, @Nullable String uiBehaviorName) { @@ -257,7 +282,7 @@ public class Role { mBehavior = behavior; mDefaultHoldersResourceName = defaultHoldersResourceName; mDescriptionResource = descriptionResource; - mExclusive = exclusive; + mExclusivity = exclusivity; mFallBackToDefaultHolder = fallBackToDefaultHolder; mFeatureFlag = featureFlag; mLabelResource = labelResource; @@ -298,7 +323,13 @@ public class Role { } public boolean isExclusive() { - return mExclusive; + // TODO(b/373390494): Allow RoleBehavior to override this getExclusivity + return mExclusivity != EXCLUSIVITY_NONE; + } + + public int getExclusivity() { + // TODO(b/373390494): Allow RoleBehavior to override this + return mExclusivity; } @Nullable @@ -353,6 +384,8 @@ public class Role { * @see #mShowNone */ public boolean shouldShowNone() { + // TODO(b/373390494): Ensure RoleBehavior override doesn't conflict with this. + // mShowNone can only be true if isExclusive=true return mShowNone; } @@ -1041,7 +1074,7 @@ public class Role { */ @Nullable public Intent getRestrictionIntentAsUser(@NonNull UserHandle user, @NonNull Context context) { - if (SdkLevel.isAtLeastU() && mExclusive) { + if (SdkLevel.isAtLeastU() && isExclusive()) { UserManager userManager = context.getSystemService(UserManager.class); if (userManager.hasUserRestrictionForUser(UserManager.DISALLOW_CONFIG_DEFAULT_APPS, user)) { @@ -1104,7 +1137,7 @@ public class Role { + ", mBehavior=" + mBehavior + ", mDefaultHoldersResourceName=" + mDefaultHoldersResourceName + ", mDescriptionResource=" + mDescriptionResource - + ", mExclusive=" + mExclusive + + ", mExclusivity=" + mExclusivity + ", mFallBackToDefaultHolder=" + mFallBackToDefaultHolder + ", mFeatureFlag=" + mFeatureFlag + ", mLabelResource=" + mLabelResource 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 a0705cd5e..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 @@ -89,6 +89,7 @@ public class RoleParser { private static final String ATTRIBUTE_DEFAULT_HOLDERS = "defaultHolders"; private static final String ATTRIBUTE_DESCRIPTION = "description"; private static final String ATTRIBUTE_EXCLUSIVE = "exclusive"; + private static final String ATTRIBUTE_EXCLUSIVITY = "exclusivity"; private static final String ATTRIBUTE_FALL_BACK_TO_DEFAULT_HOLDER = "fallBackToDefaultHolder"; private static final String ATTRIBUTE_FEATURE_FLAG = "featureFlag"; private static final String ATTRIBUTE_LABEL = "label"; @@ -135,6 +136,10 @@ public class RoleParser { sModeNameToMode.put(MODE_NAME_FOREGROUND, AppOpsManager.MODE_FOREGROUND); } + private static final String EXCLUSIVITY_NONE = "none"; + private static final String EXCLUSIVITY_USER = "user"; + private static final String EXCLUSIVITY_PROFILE_GROUP = "profileGroup"; + private static final Supplier<Boolean> sFeatureFlagFallback = () -> false; private static final ArrayMap<Class<?>, Class<?>> sPrimitiveToWrapperClass = new ArrayMap<>(); @@ -413,13 +418,45 @@ public class RoleParser { shortLabelResource = 0; } - Boolean exclusive = requireAttributeBooleanValue(parser, ATTRIBUTE_EXCLUSIVE, true, - TAG_ROLE); - if (exclusive == null) { - skipCurrentTag(parser); - return null; + int exclusivity; + if (com.android.permission.flags.Flags.crossUserRoleEnabled()) { + String exclusivityName = requireAttributeValue(parser, ATTRIBUTE_EXCLUSIVITY, TAG_ROLE); + if (exclusivityName == null) { + skipCurrentTag(parser); + return null; + } + switch (exclusivityName) { + case EXCLUSIVITY_NONE: + exclusivity = Role.EXCLUSIVITY_NONE; + break; + case EXCLUSIVITY_USER: + exclusivity = Role.EXCLUSIVITY_USER; + break; + case EXCLUSIVITY_PROFILE_GROUP: + // TODO(b/372743073): change to isAtLeastB once available + // EXCLUSIVITY_PROFILE behavior only available for B+ + // fallback to default of EXCLUSIVITY_USER + exclusivity = SdkLevel.isAtLeastV() + ? Role.EXCLUSIVITY_PROFILE_GROUP + : Role.EXCLUSIVITY_USER; + break; + default: + throwOrLogMessage("Invalid value for \"exclusivity\" on <role>: " + name + + ", exclusivity: " + exclusivityName); + skipCurrentTag(parser); + return null; + } + } else { + Boolean exclusive = + requireAttributeBooleanValue(parser, ATTRIBUTE_EXCLUSIVE, true, TAG_ROLE); + if (exclusive == null) { + skipCurrentTag(parser); + return null; + } + exclusivity = exclusive ? Role.EXCLUSIVITY_USER : Role.EXCLUSIVITY_NONE; } + boolean fallBackToDefaultHolder = getAttributeBooleanValue(parser, ATTRIBUTE_FALL_BACK_TO_DEFAULT_HOLDER, false); @@ -470,7 +507,7 @@ public class RoleParser { 0); boolean showNone = getAttributeBooleanValue(parser, ATTRIBUTE_SHOW_NONE, false); - if (showNone && !exclusive) { + if (showNone && exclusivity == Role.EXCLUSIVITY_NONE) { throwOrLogMessage("showNone=\"true\" is invalid for a non-exclusive role: " + name); skipCurrentTag(parser); return null; @@ -567,12 +604,12 @@ public class RoleParser { preferredActivities = Collections.emptyList(); } return new Role(name, allowBypassingQualification, behavior, defaultHoldersResourceName, - descriptionResource, exclusive, fallBackToDefaultHolder, featureFlag, labelResource, - maxSdkVersion, minSdkVersion, onlyGrantWhenAdded, overrideUserWhenGranting, - requestDescriptionResource, requestTitleResource, requestable, - searchKeywordsResource, shortLabelResource, showNone, statik, systemOnly, visible, - requiredComponents, permissions, appOpPermissions, appOps, preferredActivities, - uiBehaviorName); + descriptionResource, exclusivity, fallBackToDefaultHolder, featureFlag, + labelResource, maxSdkVersion, minSdkVersion, onlyGrantWhenAdded, + overrideUserWhenGranting, requestDescriptionResource, requestTitleResource, + requestable, searchKeywordsResource, shortLabelResource, showNone, statik, + systemOnly, visible, requiredComponents, permissions, appOpPermissions, appOps, + preferredActivities, uiBehaviorName); } @NonNull @@ -1106,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 { @@ -1155,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/ui/wear/elements/material3/WearPermissionButton.kt b/PermissionController/src/com/android/permissioncontroller/permission/ui/wear/elements/material3/WearPermissionButton.kt index 4ed9e92b9..e0adf1265 100644 --- a/PermissionController/src/com/android/permissioncontroller/permission/ui/wear/elements/material3/WearPermissionButton.kt +++ b/PermissionController/src/com/android/permissioncontroller/permission/ui/wear/elements/material3/WearPermissionButton.kt @@ -20,10 +20,13 @@ import androidx.compose.foundation.layout.RowScope import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier +import androidx.compose.ui.text.font.FontWeight +import androidx.compose.ui.text.style.Hyphens import androidx.wear.compose.material3.Button import androidx.wear.compose.material3.ButtonColors import androidx.wear.compose.material3.ButtonDefaults import androidx.wear.compose.material3.LocalTextConfiguration +import androidx.wear.compose.material3.LocalTextStyle import androidx.wear.compose.material3.Text import com.android.permissioncontroller.permission.ui.wear.elements.Chip import com.android.permissioncontroller.permission.ui.wear.theme.WearPermissionMaterialUIVersion @@ -94,6 +97,8 @@ private fun WearPermissionButtonInternal( text = label, modifier = Modifier.fillMaxWidth(), maxLines = labelMaxLines ?: LocalTextConfiguration.current.maxLines, + style = + LocalTextStyle.current.copy(fontWeight = FontWeight.W600, hyphens = Hyphens.Auto), ) } diff --git a/PermissionController/src/com/android/permissioncontroller/permission/ui/wear/elements/material3/WearPermissionButtonStyle.kt b/PermissionController/src/com/android/permissioncontroller/permission/ui/wear/elements/material3/WearPermissionButtonStyle.kt index 5a91ae46c..504c69bb0 100644 --- a/PermissionController/src/com/android/permissioncontroller/permission/ui/wear/elements/material3/WearPermissionButtonStyle.kt +++ b/PermissionController/src/com/android/permissioncontroller/permission/ui/wear/elements/material3/WearPermissionButtonStyle.kt @@ -21,6 +21,7 @@ import androidx.wear.compose.material.ChipColors import androidx.wear.compose.material.ChipDefaults import androidx.wear.compose.material3.ButtonColors import androidx.wear.compose.material3.ButtonDefaults +import com.android.permissioncontroller.permission.ui.wear.elements.chipDefaultColors import com.android.permissioncontroller.permission.ui.wear.elements.chipDisabledColors import com.android.permissioncontroller.permission.ui.wear.elements.material3.WearPermissionButtonStyle.DisabledLike import com.android.permissioncontroller.permission.ui.wear.elements.material3.WearPermissionButtonStyle.Primary @@ -41,7 +42,7 @@ enum class WearPermissionButtonStyle { @Composable internal fun WearPermissionButtonStyle.material2ChipColors(): ChipColors { return when (this) { - Primary -> ChipDefaults.primaryChipColors() + Primary -> chipDefaultColors() Secondary -> ChipDefaults.secondaryChipColors() Transparent -> ChipDefaults.childChipColors() DisabledLike -> chipDisabledColors() diff --git a/PermissionController/src/com/android/permissioncontroller/permission/ui/wear/elements/material3/WearPermissionListFooter.kt b/PermissionController/src/com/android/permissioncontroller/permission/ui/wear/elements/material3/WearPermissionListFooter.kt new file mode 100644 index 000000000..807c93370 --- /dev/null +++ b/PermissionController/src/com/android/permissioncontroller/permission/ui/wear/elements/material3/WearPermissionListFooter.kt @@ -0,0 +1,67 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.permissioncontroller.permission.ui.wear.elements.material3 + +import androidx.compose.foundation.layout.RowScope +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.requiredHeightIn +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import androidx.compose.ui.unit.dp +import androidx.wear.compose.material3.Button +import androidx.wear.compose.material3.ButtonDefaults +import androidx.wear.compose.material3.Text +import com.android.permissioncontroller.permission.ui.wear.elements.ListFooter +import com.android.permissioncontroller.permission.ui.wear.theme.WearPermissionMaterialUIVersion + +@Composable +fun WearPermissionListFooter( + materialUIVersion: WearPermissionMaterialUIVersion, + label: String, + iconBuilder: WearPermissionIconBuilder? = null, + onClick: (() -> Unit) = {}, +) { + if (materialUIVersion == WearPermissionMaterialUIVersion.MATERIAL2_5) { + ListFooter( + description = label, + iconRes = iconBuilder?.let { it.iconResource as Int }, + onClick = onClick, + ) + } else { + WearPermissionListFooterInternal(label, iconBuilder, onClick) + } +} + +@Composable +private fun WearPermissionListFooterInternal( + label: String, + iconBuilder: WearPermissionIconBuilder?, + onClick: () -> Unit, +) { + val footerTextComposable: (@Composable RowScope.() -> Unit) = { + Text(modifier = Modifier.fillMaxWidth(), text = label, maxLines = Int.MAX_VALUE) + } + Button( + icon = { iconBuilder?.build() }, + label = {}, + secondaryLabel = footerTextComposable, + enabled = true, + onClick = onClick, + modifier = Modifier.requiredHeightIn(min = 1.dp).fillMaxWidth(), + colors = ButtonDefaults.childButtonColors(), + ) +} diff --git a/PermissionController/src/com/android/permissioncontroller/permission/ui/wear/theme/WearPermissionTheme.kt b/PermissionController/src/com/android/permissioncontroller/permission/ui/wear/theme/WearPermissionTheme.kt index cfaaa0df9..adf179be6 100644 --- a/PermissionController/src/com/android/permissioncontroller/permission/ui/wear/theme/WearPermissionTheme.kt +++ b/PermissionController/src/com/android/permissioncontroller/permission/ui/wear/theme/WearPermissionTheme.kt @@ -35,15 +35,16 @@ import com.android.permissioncontroller.R import com.android.permissioncontroller.permission.ui.wear.theme.WearPermissionMaterialUIVersion.MATERIAL2_5 import com.android.permissioncontroller.permission.ui.wear.theme.WearPermissionMaterialUIVersion.MATERIAL3 +/** This enum is used to specify the material version used for a specific screen */ enum class WearPermissionMaterialUIVersion { MATERIAL2_5, MATERIAL3, } /** - * Supports both Material 3 and Material 2 theme. default version for permission theme will be - * LEGACY until we migrate enough screens to 3. LEGACY version will use material 3 overlay resources - * by default. + * Supports both Material 3 and Material 2_5 theme. default version for permission theme will be 2_5 + * until we migrate enough screens to 3. 2_5 version will use material 3 overlay resources if we + * enable material3 for even one screen (Permission screens will be migrated in phases). */ @Composable fun WearPermissionTheme( @@ -53,7 +54,9 @@ fun WearPermissionTheme( if (Build.VERSION.SDK_INT < Build.VERSION_CODES.VANILLA_ICE_CREAM) { WearPermissionLegacyTheme(content) } else { + // Whether we are ready to use material3 for any screen. val useBridgedTheme = Flags.wearComposeMaterial3() + // Material3 UI controls are still being used in the screen that the theme is applied if (version == MATERIAL3) { val material3Theme = WearOverlayableMaterial3Theme(LocalContext.current) Material3Theme( @@ -62,7 +65,12 @@ fun WearPermissionTheme( shapes = material3Theme.shapes, content = content, ) - } else if (version == MATERIAL2_5 && useBridgedTheme) { + } + // Material2_5 UI controls are still being used in the screen that the theme is applied, + // But some in-app screens(like permission grant screen) are migrated to material3. + // To avoid having two set of overlay resources, we will use material3 overlay resources to + // support material2_5 UI controls as well. + else if (version == MATERIAL2_5 && useBridgedTheme) { val material3Theme = WearOverlayableMaterial3Theme(LocalContext.current) val bridgedLegacyTheme = WearMaterialBridgedLegacyTheme.createFrom(material3Theme) MaterialTheme( @@ -71,7 +79,9 @@ fun WearPermissionTheme( shapes = bridgedLegacyTheme.shapes, content = content, ) - } else { + } + // We are not ready for material3 yet in any screens. + else { WearPermissionLegacyTheme(content) } } diff --git a/PermissionController/src/com/android/permissioncontroller/role/ui/wear/WearRequestRoleScreen.kt b/PermissionController/src/com/android/permissioncontroller/role/ui/wear/WearRequestRoleScreen.kt index 13a9cb6d6..ee8fe2545 100644 --- a/PermissionController/src/com/android/permissioncontroller/role/ui/wear/WearRequestRoleScreen.kt +++ b/PermissionController/src/com/android/permissioncontroller/role/ui/wear/WearRequestRoleScreen.kt @@ -30,22 +30,26 @@ import androidx.compose.ui.Modifier import androidx.compose.ui.platform.testTag import androidx.compose.ui.res.stringResource import androidx.compose.ui.unit.dp -import androidx.wear.compose.material.ChipDefaults -import androidx.wear.compose.material.MaterialTheme +import com.android.permission.flags.Flags import com.android.permissioncontroller.R -import com.android.permissioncontroller.permission.ui.wear.elements.Chip -import com.android.permissioncontroller.permission.ui.wear.elements.ListFooter import com.android.permissioncontroller.permission.ui.wear.elements.ScrollableScreen -import com.android.permissioncontroller.permission.ui.wear.elements.ToggleChip import com.android.permissioncontroller.permission.ui.wear.elements.ToggleChipToggleControl -import com.android.permissioncontroller.permission.ui.wear.elements.toggleChipBackgroundColors +import com.android.permissioncontroller.permission.ui.wear.elements.material3.WearPermissionButton +import com.android.permissioncontroller.permission.ui.wear.elements.material3.WearPermissionButtonStyle +import com.android.permissioncontroller.permission.ui.wear.elements.material3.WearPermissionIconBuilder +import com.android.permissioncontroller.permission.ui.wear.elements.material3.WearPermissionListFooter +import com.android.permissioncontroller.permission.ui.wear.elements.material3.WearPermissionToggleControl +import com.android.permissioncontroller.permission.ui.wear.elements.material3.WearPermissionToggleControlStyle +import com.android.permissioncontroller.permission.ui.wear.theme.WearPermissionMaterialUIVersion +import com.android.permissioncontroller.permission.ui.wear.theme.WearPermissionMaterialUIVersion.MATERIAL2_5 +import com.android.permissioncontroller.permission.ui.wear.theme.WearPermissionMaterialUIVersion.MATERIAL3 import com.android.permissioncontroller.role.ui.ManageRoleHolderStateLiveData @Composable fun WearRequestRoleScreen( helper: WearRequestRoleHelper, onSetAsDefault: (Boolean, String?) -> Unit, - onCanceled: () -> Unit + onCanceled: () -> Unit, ) { val roleLiveData = helper.viewModel.roleLiveData.observeAsState(emptyList()) val manageRoleHolderState = @@ -75,7 +79,15 @@ fun WearRequestRoleScreen( } } + val useMaterial3Controls = Flags.wearComposeMaterial3() + val materialUIVersion = + if (useMaterial3Controls) { + MATERIAL3 + } else { + MATERIAL2_5 + } WearRequestRoleContent( + materialUIVersion, isLoading, helper, roleLiveData.value, @@ -85,7 +97,7 @@ fun WearRequestRoleScreen( onCheckedChanged, onDontAskAgainCheckedChanged, onSetAsDefault, - onCanceled + onCanceled, ) if (isLoading && roleLiveData.value.isNotEmpty()) { @@ -95,6 +107,7 @@ fun WearRequestRoleScreen( @Composable internal fun WearRequestRoleContent( + materialUIVersion: WearPermissionMaterialUIVersion, isLoading: Boolean, helper: WearRequestRoleHelper, qualifyingApplications: List<Pair<ApplicationInfo, Boolean>>, @@ -104,56 +117,74 @@ internal fun WearRequestRoleContent( onCheckedChanged: (Boolean, String?, Boolean) -> Unit, onDontAskAgainCheckedChanged: (Boolean) -> Unit, onSetAsDefault: (Boolean, String?) -> Unit, - onCanceled: () -> Unit + onCanceled: () -> Unit, ) { ScrollableScreen( + materialUIVersion = materialUIVersion, image = helper.getIcon(), title = helper.getTitle(), showTimeText = false, - isLoading = isLoading + isLoading = isLoading, ) { - helper.getNonePreference(qualifyingApplications, selectedPackageName)?.let { + helper.getNonePreference(qualifyingApplications, selectedPackageName)?.let { pref -> item { - ToggleChip( - label = it.label, - icon = it.icon, - enabled = enabled && it.enabled, - checked = it.checked, + WearPermissionToggleControl( + materialUIVersion = materialUIVersion, + label = pref.label, + iconBuilder = pref.icon?.let { WearPermissionIconBuilder.builder(it) }, + enabled = enabled && pref.enabled, + checked = pref.checked, onCheckedChanged = { checked -> - run { onCheckedChanged(checked, it.packageName, it.isHolder) } + onCheckedChanged(checked, pref.packageName, pref.isHolder) }, toggleControl = ToggleChipToggleControl.Radio, - labelMaxLine = Integer.MAX_VALUE + labelMaxLines = Integer.MAX_VALUE, ) } - it.subTitle?.let { subTitle -> item { ListFooter(description = subTitle) } } + pref.subTitle?.let { subTitle -> + item { + WearPermissionListFooter( + materialUIVersion = materialUIVersion, + label = subTitle, + ) + } + } } for (pref in helper.getPreferences(qualifyingApplications, selectedPackageName)) { item { - ToggleChip( + WearPermissionToggleControl( + materialUIVersion = materialUIVersion, label = pref.label, - icon = pref.icon, + iconBuilder = pref.icon?.let { WearPermissionIconBuilder.builder(it) }, enabled = enabled && pref.enabled, checked = pref.checked, onCheckedChanged = { checked -> - run { onCheckedChanged(checked, pref.packageName, pref.isHolder) } + onCheckedChanged(checked, pref.packageName, pref.isHolder) }, toggleControl = ToggleChipToggleControl.Radio, ) } - pref.subTitle?.let { subTitle -> item { ListFooter(description = subTitle) } } + pref.subTitle?.let { subTitle -> + item { + WearPermissionListFooter( + materialUIVersion = materialUIVersion, + label = subTitle, + ) + } + } } if (helper.showDontAskButton()) { item { - ToggleChip( + WearPermissionToggleControl( + materialUIVersion = materialUIVersion, checked = dontAskAgain, enabled = enabled, onCheckedChanged = { checked -> run { onDontAskAgainCheckedChanged(checked) } }, label = stringResource(R.string.request_role_dont_ask_again), toggleControl = ToggleChipToggleControl.Checkbox, - colors = toggleChipBackgroundColors(), + style = WearPermissionToggleControlStyle.Transparent, modifier = Modifier.testTag("com.android.permissioncontroller:id/dont_ask_again"), ) @@ -163,17 +194,18 @@ internal fun WearRequestRoleContent( item { Spacer(modifier = Modifier.height(14.dp)) } item { - Chip( + WearPermissionButton( + materialUIVersion = materialUIVersion, label = stringResource(R.string.request_role_set_as_default), - textColor = MaterialTheme.colors.background, - colors = ChipDefaults.primaryChipColors(), + style = WearPermissionButtonStyle.Primary, enabled = helper.shouldSetAsDefaultEnabled(enabled), onClick = { onSetAsDefault(dontAskAgain, selectedPackageName) }, modifier = Modifier.testTag("android:id/button1"), ) } item { - Chip( + WearPermissionButton( + materialUIVersion = materialUIVersion, label = stringResource(R.string.cancel), enabled = enabled, onClick = { onCanceled() }, diff --git a/PermissionController/tests/mocking/Android.bp b/PermissionController/tests/mocking/Android.bp index a541f4577..37851b2bb 100644 --- a/PermissionController/tests/mocking/Android.bp +++ b/PermissionController/tests/mocking/Android.bp @@ -86,4 +86,7 @@ android_test { ], kotlincflags: ["-Xjvm-default=all"], + + // TODO(b/313706381): Remove jarjar once flagging lib is fixed + jarjar_rules: ":PermissionController-jarjar-rules", } diff --git a/service/Android.bp b/service/Android.bp index 8efce5ebe..b6e85b0fc 100644 --- a/service/Android.bp +++ b/service/Android.bp @@ -101,6 +101,7 @@ java_sdk_library { "modules-utils-backgroundthread", "modules-utils-build", "modules-utils-os", + // framework-permission-s already includes com.android.permission.flags-aconfig-java "role-controller", "safety-center-config", "safety-center-internal-data", @@ -111,6 +112,7 @@ java_sdk_library { "service-permission-statsd", "permissioncontroller-statsd", "service-permission-proto-stream", + "com.android.permission.flags-aconfig-java", ], errorprone: { javacflags: ["-Xep:GuardedBy:ERROR"], diff --git a/service/jarjar-rules.txt b/service/jarjar-rules.txt index 77e071672..4d4d6e050 100644 --- a/service/jarjar-rules.txt +++ b/service/jarjar-rules.txt @@ -1,5 +1,5 @@ # You may bypass this Gerrit IfThisThenThat Lint if your change doesn't affect -# RoleParser.applyJarjarTransformIfNeeded(), by adding NO_IFTTT=reason to your commit +# RoleParser.applyJarjarTransform(), by adding NO_IFTTT=reason to your commit # message. # LINT.IfChange rule android.app.appfunctions.flags.*FeatureFlags* com.android.permission.jarjar.@0 @@ -37,4 +37,4 @@ rule com.android.safetycenter.resources.** com.android.permission.jarjar.@0 rule com.google.protobuf.** com.android.permission.jarjar.@0 rule kotlin.** com.android.permission.jarjar.@0 rule com.android.permissioncontroller.PermissionControllerStatsLog com.android.permission.jarjar.@0 -# LINT.ThenChange(PermissionController/role-controller/java/com/android/role/controller/model/RoleParser.java:applyJarjarTransformIfNeeded) +# LINT.ThenChange(PermissionController/role-controller/java/com/android/role/controller/model/RoleParser.java:applyJarjarTransform) diff --git a/service/java/com/android/permission/compat/UserHandleCompat.java b/service/java/com/android/permission/compat/UserHandleCompat.java index 1901aa997..1b3ebb8d6 100644 --- a/service/java/com/android/permission/compat/UserHandleCompat.java +++ b/service/java/com/android/permission/compat/UserHandleCompat.java @@ -29,6 +29,13 @@ public final class UserHandleCompat { public static final int USER_ALL = UserHandle.ALL.getIdentifier(); /** + * A user ID to indicate an undefined user of the device. + * + * @see UserHandle#USER_NULL + */ + public static final @UserIdInt int USER_NULL = -10000; + + /** * A user ID to indicate the "system" user of the device. */ public static final int USER_SYSTEM = UserHandle.SYSTEM.getIdentifier(); diff --git a/service/java/com/android/safetycenter/UserProfileGroup.java b/service/java/com/android/safetycenter/UserProfileGroup.java index 3202c3776..a78113b04 100644 --- a/service/java/com/android/safetycenter/UserProfileGroup.java +++ b/service/java/com/android/safetycenter/UserProfileGroup.java @@ -30,6 +30,7 @@ import android.util.Log; import androidx.annotation.Nullable; +import com.android.permission.compat.UserHandleCompat; import com.android.permission.util.UserUtils; import java.lang.annotation.Retention; @@ -49,8 +50,6 @@ import java.util.Objects; public final class UserProfileGroup { private static final String TAG = "UserProfileGroup"; - // UserHandle#USER_NULL is a @TestApi so it cannot be accessed from the mainline module. - public static final @UserIdInt int USER_NULL = -10000; @UserIdInt private final int mProfileParentUserId; private final int[] mManagedProfilesUserIds; @@ -147,7 +146,7 @@ public final class UserProfileGroup { int managedProfilesUserIdsLen = 0; int managedRunningProfilesUserIdsLen = 0; - int privateProfileUserId = USER_NULL; + int privateProfileUserId = UserHandleCompat.USER_NULL; boolean privateProfileRunning = false; for (int i = 0; i < userProfiles.size(); i++) { @@ -228,7 +227,7 @@ public final class UserProfileGroup { /* destPos= */ 1, mManagedProfilesUserIds.length); - if (mPrivateProfileUserId != USER_NULL) { + if (mPrivateProfileUserId != UserHandleCompat.USER_NULL) { allProfileIds[allProfileIds.length - 1] = mPrivateProfileUserId; } @@ -269,7 +268,7 @@ public final class UserProfileGroup { case PROFILE_TYPE_MANAGED: return mManagedProfilesUserIds; case PROFILE_TYPE_PRIVATE: - return mPrivateProfileUserId != USER_NULL + return mPrivateProfileUserId != UserHandleCompat.USER_NULL ? new int[]{mPrivateProfileUserId} : new int[]{}; default: Log.w(TAG, "profiles requested for unexpected profile type " + profileType); @@ -308,7 +307,7 @@ public final class UserProfileGroup { private int getNumProfiles() { return 1 + mManagedProfilesUserIds.length - + (mPrivateProfileUserId == USER_NULL ? 0 : 1); + + (mPrivateProfileUserId == UserHandleCompat.USER_NULL ? 0 : 1); } /** @@ -361,7 +360,8 @@ public final class UserProfileGroup { } } - return USER_NULL != mPrivateProfileUserId && userId == mPrivateProfileUserId; + return UserHandleCompat.USER_NULL != mPrivateProfileUserId + && userId == mPrivateProfileUserId; } @Override diff --git a/tests/cts/permission/src/android/permission/cts/NoWifiStatePermissionTest.java b/tests/cts/permission/src/android/permission/cts/NoWifiStatePermissionTest.java index a0637827c..9fff22747 100644 --- a/tests/cts/permission/src/android/permission/cts/NoWifiStatePermissionTest.java +++ b/tests/cts/permission/src/android/permission/cts/NoWifiStatePermissionTest.java @@ -30,9 +30,6 @@ import androidx.test.ext.junit.runners.AndroidJUnit4; import androidx.test.filters.SmallTest; import androidx.test.platform.app.InstrumentationRegistry; -import com.android.compatibility.common.util.UserHelper; - -import org.junit.Assume; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; @@ -217,11 +214,6 @@ public class NoWifiStatePermissionTest { */ @Test(expected = SecurityException.class) public void testSetWifiEnabled() { - // Skip the test for passenger on Multi-user-multi-display devices for Automotive - UserHelper userHelper = new UserHelper(sContext); - Assume.assumeFalse( - "Skipped for visible background User as wifi is disabled for visible background " - + "user.", userHelper.isVisibleBackgroundUser()); mWifiManager.setWifiEnabled(true); } } diff --git a/tests/cts/permissionpolicy/Android.bp b/tests/cts/permissionpolicy/Android.bp index 4249f3c9d..07fde8bff 100644 --- a/tests/cts/permissionpolicy/Android.bp +++ b/tests/cts/permissionpolicy/Android.bp @@ -37,6 +37,7 @@ android_test { "permission-test-util-lib", "androidx.test.rules", "flag-junit", + "android.app.flags-aconfig", "android.permission.flags-aconfig-java-export", ], srcs: [ diff --git a/tests/cts/permissionpolicy/res/raw/android_manifest.xml b/tests/cts/permissionpolicy/res/raw/android_manifest.xml index 5008bda40..d30931c3f 100644 --- a/tests/cts/permissionpolicy/res/raw/android_manifest.xml +++ b/tests/cts/permissionpolicy/res/raw/android_manifest.xml @@ -2616,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 @@ -4258,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 --> <!-- ================================== --> @@ -4764,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 --> <!-- ========================================= --> 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() + } } |