Loading core/api/test-current.txt +2 −0 Original line number Diff line number Diff line Loading @@ -155,8 +155,10 @@ package android.app { public class ActivityOptions { method @NonNull public static android.app.ActivityOptions fromBundle(@NonNull android.os.Bundle); method public boolean isEligibleForLegacyPermissionPrompt(); method @NonNull public static android.app.ActivityOptions makeCustomAnimation(@NonNull android.content.Context, int, int, int, @Nullable android.os.Handler, @Nullable android.app.ActivityOptions.OnAnimationStartedListener, @Nullable android.app.ActivityOptions.OnAnimationFinishedListener); method @NonNull @RequiresPermission(android.Manifest.permission.START_TASKS_FROM_RECENTS) public static android.app.ActivityOptions makeCustomTaskAnimation(@NonNull android.content.Context, int, int, @Nullable android.os.Handler, @Nullable android.app.ActivityOptions.OnAnimationStartedListener, @Nullable android.app.ActivityOptions.OnAnimationFinishedListener); method public void setEligibleForLegacyPermissionPrompt(boolean); method public static void setExitTransitionTimeout(long); method public void setLaunchActivityType(int); method public void setLaunchWindowingMode(int); Loading core/java/android/app/ActivityOptions.java +33 −0 Original line number Diff line number Diff line Loading @@ -173,6 +173,13 @@ public class ActivityOptions extends ComponentOptions { */ public static final String KEY_SPLASH_SCREEN_THEME = "android.activity.splashScreenTheme"; /** * Indicates that this activity launch is eligible to show a legacy permission prompt * @hide */ public static final String KEY_LEGACY_PERMISSION_PROMPT_ELIGIBLE = "android:activity.legacyPermissionPromptEligible"; /** * Callback for when the last frame of the animation is played. * @hide Loading Loading @@ -445,6 +452,7 @@ public class ActivityOptions extends ComponentOptions { private String mSplashScreenThemeResName; @SplashScreen.SplashScreenStyle private int mSplashScreenStyle = SplashScreen.SPLASH_SCREEN_STYLE_UNDEFINED; private boolean mIsEligibleForLegacyPermissionPrompt; private boolean mRemoveWithTaskOrganizer; private boolean mLaunchedFromBubble; private boolean mTransientLaunch; Loading Loading @@ -1243,6 +1251,8 @@ public class ActivityOptions extends ComponentOptions { mTransientLaunch = opts.getBoolean(KEY_TRANSIENT_LAUNCH); mSplashScreenStyle = opts.getInt(KEY_SPLASH_SCREEN_STYLE); mLaunchIntoPipParams = opts.getParcelable(KEY_LAUNCH_INTO_PIP_PARAMS); mIsEligibleForLegacyPermissionPrompt = opts.getBoolean(KEY_LEGACY_PERMISSION_PROMPT_ELIGIBLE); } /** Loading Loading @@ -1473,6 +1483,24 @@ public class ActivityOptions extends ComponentOptions { return this; } /** * Whether the activity is eligible to show a legacy permission prompt * @hide */ @TestApi public boolean isEligibleForLegacyPermissionPrompt() { return mIsEligibleForLegacyPermissionPrompt; } /** * Sets whether the activity is eligible to show a legacy permission prompt * @hide */ @TestApi public void setEligibleForLegacyPermissionPrompt(boolean eligible) { mIsEligibleForLegacyPermissionPrompt = eligible; } /** * Sets whether the activity is to be launched into LockTask mode. * Loading Loading @@ -1909,6 +1937,7 @@ public class ActivityOptions extends ComponentOptions { mSpecsFuture = otherOptions.mSpecsFuture; mRemoteAnimationAdapter = otherOptions.mRemoteAnimationAdapter; mLaunchIntoPipParams = otherOptions.mLaunchIntoPipParams; mIsEligibleForLegacyPermissionPrompt = otherOptions.mIsEligibleForLegacyPermissionPrompt; } /** Loading Loading @@ -2084,6 +2113,10 @@ public class ActivityOptions extends ComponentOptions { if (mLaunchIntoPipParams != null) { b.putParcelable(KEY_LAUNCH_INTO_PIP_PARAMS, mLaunchIntoPipParams); } if (mIsEligibleForLegacyPermissionPrompt) { b.putBoolean(KEY_LEGACY_PERMISSION_PROMPT_ELIGIBLE, mIsEligibleForLegacyPermissionPrompt); } return b; } Loading packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfaces.java +8 −2 Original line number Diff line number Diff line Loading @@ -3972,8 +3972,14 @@ public class CentralSurfaces extends CoreStartable implements mActivityLaunchAnimator.startPendingIntentWithAnimation( controller, animate, intent.getCreatorPackage(), (animationAdapter) -> intent.sendAndReturnResult(null, 0, null, null, null, null, getActivityOptions(mDisplayId, animationAdapter))); (animationAdapter) -> { ActivityOptions options = new ActivityOptions( getActivityOptions(mDisplayId, animationAdapter)); // TODO b/221255671: restrict this to only be set for notifications options.setEligibleForLegacyPermissionPrompt(true); return intent.sendAndReturnResult(null, 0, null, null, null, null, options.toBundle()); }); } catch (PendingIntent.CanceledException e) { // the stack trace isn't very helpful here. // Just log the exception message. Loading services/core/java/com/android/server/policy/PermissionPolicyService.java +42 −12 Original line number Diff line number Diff line Loading @@ -34,6 +34,7 @@ import android.app.ActivityOptions; import android.app.ActivityTaskManager; import android.app.AppOpsManager; import android.app.AppOpsManagerInternal; import android.app.KeyguardManager; import android.app.TaskInfo; import android.app.compat.CompatChanges; import android.compat.annotation.ChangeId; Loading Loading @@ -150,6 +151,7 @@ public final class PermissionPolicyService extends SystemService { private Context mContext; private PackageManagerInternal mPackageManagerInternal; private NotificationManagerInternal mNotificationManager; private final KeyguardManager mKeyguardManager; private final PackageManager mPackageManager; public PermissionPolicyService(@NonNull Context context) { Loading @@ -157,6 +159,7 @@ public final class PermissionPolicyService extends SystemService { mContext = context; mPackageManager = context.getPackageManager(); mKeyguardManager = context.getSystemService(KeyguardManager.class); LocalServices.addService(PermissionPolicyInternal.class, new Internal()); } Loading Loading @@ -1046,13 +1049,22 @@ public final class PermissionPolicyService extends SystemService { } @Override public void onActivityLaunched(TaskInfo taskInfo, ActivityInfo activityInfo) { super.onActivityLaunched(taskInfo, activityInfo); clearNotificationReviewFlagsIfNeeded(activityInfo.packageName, UserHandle.of(taskInfo.userId)); public void onActivityLaunched(TaskInfo taskInfo, ActivityInfo activityInfo, ActivityInterceptorInfo info) { super.onActivityLaunched(taskInfo, activityInfo, info); if (!shouldShowNotificationDialogOrClearFlags(info.intent, info.checkedOptions)) { return; } UserHandle user = UserHandle.of(taskInfo.userId); if (CompatChanges.isChangeEnabled(NOTIFICATION_PERM_CHANGE_ID, activityInfo.packageName, user)) { clearNotificationReviewFlagsIfNeeded(activityInfo.packageName, user); } else { showNotificationPromptIfNeeded(activityInfo.packageName, taskInfo.userId, taskInfo.taskId); } } }; private void onActivityManagerReady() { Loading Loading @@ -1092,10 +1104,28 @@ public final class PermissionPolicyService extends SystemService { launchNotificationPermissionRequestDialog(packageName, user, taskId); } /** * Determine if we should show a notification dialog, or clear the REVIEW_REQUIRED flag, * from a particular package for a particular intent. Returns true if: * 1. The isEligibleForLegacyPermissionPrompt ActivityOption is set, or * 2. The intent is a launcher intent (action is ACTION_MAIN, category is LAUNCHER) */ private boolean shouldShowNotificationDialogOrClearFlags(Intent intent, ActivityOptions options) { if ((options != null && options.isEligibleForLegacyPermissionPrompt())) { return true; } return Intent.ACTION_MAIN.equals(intent.getAction()) && intent.getCategories() != null && (intent.getCategories().contains(Intent.CATEGORY_LAUNCHER) || intent.getCategories().contains(Intent.CATEGORY_LEANBACK_LAUNCHER) || intent.getCategories().contains(Intent.CATEGORY_CAR_LAUNCHER)); } private void clearNotificationReviewFlagsIfNeeded(String packageName, UserHandle user) { if (!CompatChanges.isChangeEnabled(NOTIFICATION_PERM_CHANGE_ID, packageName, user) || ((mPackageManager.getPermissionFlags(POST_NOTIFICATIONS, packageName, user) & FLAG_PERMISSION_REVIEW_REQUIRED) == 0)) { if ((mPackageManager.getPermissionFlags(POST_NOTIFICATIONS, packageName, user) & FLAG_PERMISSION_REVIEW_REQUIRED) == 0) { return; } try { Loading Loading @@ -1210,8 +1240,8 @@ public final class PermissionPolicyService extends SystemService { } if (!pkg.getRequestedPermissions().contains(POST_NOTIFICATIONS) || CompatChanges.isChangeEnabled(NOTIFICATION_PERM_CHANGE_ID, pkg.getPackageName(), user)) { || CompatChanges.isChangeEnabled(NOTIFICATION_PERM_CHANGE_ID, pkgName, user) || mKeyguardManager.isKeyguardLocked()) { return false; } Loading @@ -1220,7 +1250,7 @@ public final class PermissionPolicyService extends SystemService { mNotificationManager = LocalServices.getService(NotificationManagerInternal.class); } boolean hasCreatedNotificationChannels = mNotificationManager .getNumNotificationChannelsForPackage(pkg.getPackageName(), uid, true) > 0; .getNumNotificationChannelsForPackage(pkgName, uid, true) > 0; int flags = mPackageManager.getPermissionFlags(POST_NOTIFICATIONS, pkgName, user); boolean explicitlySet = (flags & PermissionManager.EXPLICIT_SET_FLAGS) != 0; boolean needsReview = (flags & FLAG_PERMISSION_REVIEW_REQUIRED) != 0; Loading services/core/java/com/android/server/wm/ActivityInterceptorCallback.java +6 −2 Original line number Diff line number Diff line Loading @@ -43,9 +43,13 @@ public abstract class ActivityInterceptorCallback { public abstract @Nullable ActivityInterceptResult intercept(ActivityInterceptorInfo info); /** * Called when an activity is successfully launched. * Called when an activity is successfully launched. The intent included in the * ActivityInterceptorInfo may have changed from the one sent in * {@link #intercept(ActivityInterceptorInfo)}, due to the return from * {@link #intercept(ActivityInterceptorInfo)}. */ public void onActivityLaunched(TaskInfo taskInfo, ActivityInfo activityInfo) { public void onActivityLaunched(TaskInfo taskInfo, ActivityInfo activityInfo, ActivityInterceptorInfo info) { } /** Loading Loading
core/api/test-current.txt +2 −0 Original line number Diff line number Diff line Loading @@ -155,8 +155,10 @@ package android.app { public class ActivityOptions { method @NonNull public static android.app.ActivityOptions fromBundle(@NonNull android.os.Bundle); method public boolean isEligibleForLegacyPermissionPrompt(); method @NonNull public static android.app.ActivityOptions makeCustomAnimation(@NonNull android.content.Context, int, int, int, @Nullable android.os.Handler, @Nullable android.app.ActivityOptions.OnAnimationStartedListener, @Nullable android.app.ActivityOptions.OnAnimationFinishedListener); method @NonNull @RequiresPermission(android.Manifest.permission.START_TASKS_FROM_RECENTS) public static android.app.ActivityOptions makeCustomTaskAnimation(@NonNull android.content.Context, int, int, @Nullable android.os.Handler, @Nullable android.app.ActivityOptions.OnAnimationStartedListener, @Nullable android.app.ActivityOptions.OnAnimationFinishedListener); method public void setEligibleForLegacyPermissionPrompt(boolean); method public static void setExitTransitionTimeout(long); method public void setLaunchActivityType(int); method public void setLaunchWindowingMode(int); Loading
core/java/android/app/ActivityOptions.java +33 −0 Original line number Diff line number Diff line Loading @@ -173,6 +173,13 @@ public class ActivityOptions extends ComponentOptions { */ public static final String KEY_SPLASH_SCREEN_THEME = "android.activity.splashScreenTheme"; /** * Indicates that this activity launch is eligible to show a legacy permission prompt * @hide */ public static final String KEY_LEGACY_PERMISSION_PROMPT_ELIGIBLE = "android:activity.legacyPermissionPromptEligible"; /** * Callback for when the last frame of the animation is played. * @hide Loading Loading @@ -445,6 +452,7 @@ public class ActivityOptions extends ComponentOptions { private String mSplashScreenThemeResName; @SplashScreen.SplashScreenStyle private int mSplashScreenStyle = SplashScreen.SPLASH_SCREEN_STYLE_UNDEFINED; private boolean mIsEligibleForLegacyPermissionPrompt; private boolean mRemoveWithTaskOrganizer; private boolean mLaunchedFromBubble; private boolean mTransientLaunch; Loading Loading @@ -1243,6 +1251,8 @@ public class ActivityOptions extends ComponentOptions { mTransientLaunch = opts.getBoolean(KEY_TRANSIENT_LAUNCH); mSplashScreenStyle = opts.getInt(KEY_SPLASH_SCREEN_STYLE); mLaunchIntoPipParams = opts.getParcelable(KEY_LAUNCH_INTO_PIP_PARAMS); mIsEligibleForLegacyPermissionPrompt = opts.getBoolean(KEY_LEGACY_PERMISSION_PROMPT_ELIGIBLE); } /** Loading Loading @@ -1473,6 +1483,24 @@ public class ActivityOptions extends ComponentOptions { return this; } /** * Whether the activity is eligible to show a legacy permission prompt * @hide */ @TestApi public boolean isEligibleForLegacyPermissionPrompt() { return mIsEligibleForLegacyPermissionPrompt; } /** * Sets whether the activity is eligible to show a legacy permission prompt * @hide */ @TestApi public void setEligibleForLegacyPermissionPrompt(boolean eligible) { mIsEligibleForLegacyPermissionPrompt = eligible; } /** * Sets whether the activity is to be launched into LockTask mode. * Loading Loading @@ -1909,6 +1937,7 @@ public class ActivityOptions extends ComponentOptions { mSpecsFuture = otherOptions.mSpecsFuture; mRemoteAnimationAdapter = otherOptions.mRemoteAnimationAdapter; mLaunchIntoPipParams = otherOptions.mLaunchIntoPipParams; mIsEligibleForLegacyPermissionPrompt = otherOptions.mIsEligibleForLegacyPermissionPrompt; } /** Loading Loading @@ -2084,6 +2113,10 @@ public class ActivityOptions extends ComponentOptions { if (mLaunchIntoPipParams != null) { b.putParcelable(KEY_LAUNCH_INTO_PIP_PARAMS, mLaunchIntoPipParams); } if (mIsEligibleForLegacyPermissionPrompt) { b.putBoolean(KEY_LEGACY_PERMISSION_PROMPT_ELIGIBLE, mIsEligibleForLegacyPermissionPrompt); } return b; } Loading
packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfaces.java +8 −2 Original line number Diff line number Diff line Loading @@ -3972,8 +3972,14 @@ public class CentralSurfaces extends CoreStartable implements mActivityLaunchAnimator.startPendingIntentWithAnimation( controller, animate, intent.getCreatorPackage(), (animationAdapter) -> intent.sendAndReturnResult(null, 0, null, null, null, null, getActivityOptions(mDisplayId, animationAdapter))); (animationAdapter) -> { ActivityOptions options = new ActivityOptions( getActivityOptions(mDisplayId, animationAdapter)); // TODO b/221255671: restrict this to only be set for notifications options.setEligibleForLegacyPermissionPrompt(true); return intent.sendAndReturnResult(null, 0, null, null, null, null, options.toBundle()); }); } catch (PendingIntent.CanceledException e) { // the stack trace isn't very helpful here. // Just log the exception message. Loading
services/core/java/com/android/server/policy/PermissionPolicyService.java +42 −12 Original line number Diff line number Diff line Loading @@ -34,6 +34,7 @@ import android.app.ActivityOptions; import android.app.ActivityTaskManager; import android.app.AppOpsManager; import android.app.AppOpsManagerInternal; import android.app.KeyguardManager; import android.app.TaskInfo; import android.app.compat.CompatChanges; import android.compat.annotation.ChangeId; Loading Loading @@ -150,6 +151,7 @@ public final class PermissionPolicyService extends SystemService { private Context mContext; private PackageManagerInternal mPackageManagerInternal; private NotificationManagerInternal mNotificationManager; private final KeyguardManager mKeyguardManager; private final PackageManager mPackageManager; public PermissionPolicyService(@NonNull Context context) { Loading @@ -157,6 +159,7 @@ public final class PermissionPolicyService extends SystemService { mContext = context; mPackageManager = context.getPackageManager(); mKeyguardManager = context.getSystemService(KeyguardManager.class); LocalServices.addService(PermissionPolicyInternal.class, new Internal()); } Loading Loading @@ -1046,13 +1049,22 @@ public final class PermissionPolicyService extends SystemService { } @Override public void onActivityLaunched(TaskInfo taskInfo, ActivityInfo activityInfo) { super.onActivityLaunched(taskInfo, activityInfo); clearNotificationReviewFlagsIfNeeded(activityInfo.packageName, UserHandle.of(taskInfo.userId)); public void onActivityLaunched(TaskInfo taskInfo, ActivityInfo activityInfo, ActivityInterceptorInfo info) { super.onActivityLaunched(taskInfo, activityInfo, info); if (!shouldShowNotificationDialogOrClearFlags(info.intent, info.checkedOptions)) { return; } UserHandle user = UserHandle.of(taskInfo.userId); if (CompatChanges.isChangeEnabled(NOTIFICATION_PERM_CHANGE_ID, activityInfo.packageName, user)) { clearNotificationReviewFlagsIfNeeded(activityInfo.packageName, user); } else { showNotificationPromptIfNeeded(activityInfo.packageName, taskInfo.userId, taskInfo.taskId); } } }; private void onActivityManagerReady() { Loading Loading @@ -1092,10 +1104,28 @@ public final class PermissionPolicyService extends SystemService { launchNotificationPermissionRequestDialog(packageName, user, taskId); } /** * Determine if we should show a notification dialog, or clear the REVIEW_REQUIRED flag, * from a particular package for a particular intent. Returns true if: * 1. The isEligibleForLegacyPermissionPrompt ActivityOption is set, or * 2. The intent is a launcher intent (action is ACTION_MAIN, category is LAUNCHER) */ private boolean shouldShowNotificationDialogOrClearFlags(Intent intent, ActivityOptions options) { if ((options != null && options.isEligibleForLegacyPermissionPrompt())) { return true; } return Intent.ACTION_MAIN.equals(intent.getAction()) && intent.getCategories() != null && (intent.getCategories().contains(Intent.CATEGORY_LAUNCHER) || intent.getCategories().contains(Intent.CATEGORY_LEANBACK_LAUNCHER) || intent.getCategories().contains(Intent.CATEGORY_CAR_LAUNCHER)); } private void clearNotificationReviewFlagsIfNeeded(String packageName, UserHandle user) { if (!CompatChanges.isChangeEnabled(NOTIFICATION_PERM_CHANGE_ID, packageName, user) || ((mPackageManager.getPermissionFlags(POST_NOTIFICATIONS, packageName, user) & FLAG_PERMISSION_REVIEW_REQUIRED) == 0)) { if ((mPackageManager.getPermissionFlags(POST_NOTIFICATIONS, packageName, user) & FLAG_PERMISSION_REVIEW_REQUIRED) == 0) { return; } try { Loading Loading @@ -1210,8 +1240,8 @@ public final class PermissionPolicyService extends SystemService { } if (!pkg.getRequestedPermissions().contains(POST_NOTIFICATIONS) || CompatChanges.isChangeEnabled(NOTIFICATION_PERM_CHANGE_ID, pkg.getPackageName(), user)) { || CompatChanges.isChangeEnabled(NOTIFICATION_PERM_CHANGE_ID, pkgName, user) || mKeyguardManager.isKeyguardLocked()) { return false; } Loading @@ -1220,7 +1250,7 @@ public final class PermissionPolicyService extends SystemService { mNotificationManager = LocalServices.getService(NotificationManagerInternal.class); } boolean hasCreatedNotificationChannels = mNotificationManager .getNumNotificationChannelsForPackage(pkg.getPackageName(), uid, true) > 0; .getNumNotificationChannelsForPackage(pkgName, uid, true) > 0; int flags = mPackageManager.getPermissionFlags(POST_NOTIFICATIONS, pkgName, user); boolean explicitlySet = (flags & PermissionManager.EXPLICIT_SET_FLAGS) != 0; boolean needsReview = (flags & FLAG_PERMISSION_REVIEW_REQUIRED) != 0; Loading
services/core/java/com/android/server/wm/ActivityInterceptorCallback.java +6 −2 Original line number Diff line number Diff line Loading @@ -43,9 +43,13 @@ public abstract class ActivityInterceptorCallback { public abstract @Nullable ActivityInterceptResult intercept(ActivityInterceptorInfo info); /** * Called when an activity is successfully launched. * Called when an activity is successfully launched. The intent included in the * ActivityInterceptorInfo may have changed from the one sent in * {@link #intercept(ActivityInterceptorInfo)}, due to the return from * {@link #intercept(ActivityInterceptorInfo)}. */ public void onActivityLaunched(TaskInfo taskInfo, ActivityInfo activityInfo) { public void onActivityLaunched(TaskInfo taskInfo, ActivityInfo activityInfo, ActivityInterceptorInfo info) { } /** Loading