diff options
7 files changed, 58 insertions, 37 deletions
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java index 326a5f2582e1..9af5b667fc44 100755 --- a/services/core/java/com/android/server/notification/NotificationManagerService.java +++ b/services/core/java/com/android/server/notification/NotificationManagerService.java @@ -264,7 +264,6 @@ import android.widget.Toast; import com.android.internal.R; import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.VisibleForTesting; -import com.android.internal.app.IAppOpsCallback; import com.android.internal.app.IAppOpsService; import com.android.internal.compat.IPlatformCompat; import com.android.internal.config.sysui.SystemUiDeviceConfigFlags; diff --git a/services/core/java/com/android/server/policy/PermissionPolicyService.java b/services/core/java/com/android/server/policy/PermissionPolicyService.java index 11cb5a7167dc..e8546a768429 100644 --- a/services/core/java/com/android/server/policy/PermissionPolicyService.java +++ b/services/core/java/com/android/server/policy/PermissionPolicyService.java @@ -17,6 +17,7 @@ package com.android.server.policy; import static android.Manifest.permission.POST_NOTIFICATIONS; +import static android.app.ActivityOptions.ANIM_REMOTE_ANIMATION; import static android.app.AppOpsManager.MODE_ALLOWED; import static android.app.AppOpsManager.MODE_FOREGROUND; import static android.app.AppOpsManager.MODE_IGNORED; @@ -58,8 +59,6 @@ import android.content.pm.PackageManagerInternal.PackageListObserver; import android.content.pm.PermissionInfo; import android.os.Build; import android.os.Bundle; -import android.os.Handler; -import android.os.Looper; import android.os.Process; import android.os.RemoteException; import android.os.ServiceManager; @@ -93,6 +92,7 @@ import com.android.server.pm.permission.PermissionManagerServiceInternal; import com.android.server.policy.PermissionPolicyInternal.OnInitializedCallback; import com.android.server.utils.TimingsTraceAndSlog; import com.android.server.wm.ActivityInterceptorCallback; +import com.android.server.wm.ActivityInterceptorCallback.ActivityInterceptorInfo; import com.android.server.wm.ActivityTaskManagerInternal; import java.util.ArrayList; @@ -115,7 +115,6 @@ public final class PermissionPolicyService extends SystemService { private static final String SYSTEM_PKG = "android"; private static final boolean DEBUG = false; private static final long USER_SENSITIVE_UPDATE_DELAY_MS = 60000; - private static final long ACTIVITY_START_DELAY_MS = 200; private final Object mLock = new Object(); @@ -155,8 +154,7 @@ public final class PermissionPolicyService extends SystemService { private List<String> mAppOpPermissions; - private final Context mContext; - private final Handler mHandler; + private Context mContext; private PackageManagerInternal mPackageManagerInternal; private PermissionManagerServiceInternal mPermissionManagerInternal; private NotificationManagerInternal mNotificationManager; @@ -167,7 +165,6 @@ public final class PermissionPolicyService extends SystemService { super(context); mContext = context; - mHandler = new Handler(Looper.getMainLooper()); mPackageManager = context.getPackageManager(); mKeyguardManager = context.getSystemService(KeyguardManager.class); LocalServices.addService(PermissionPolicyInternal.class, new Internal()); @@ -1072,7 +1069,7 @@ public final class PermissionPolicyService extends SystemService { clearNotificationReviewFlagsIfNeeded(activityInfo.packageName, user); } else { showNotificationPromptIfNeeded(activityInfo.packageName, - taskInfo.userId, taskInfo.taskId); + taskInfo.userId, taskInfo.taskId, info); } } }; @@ -1103,15 +1100,21 @@ public final class PermissionPolicyService extends SystemService { return true; } + @Override public void showNotificationPromptIfNeeded(@NonNull String packageName, int userId, int taskId) { + showNotificationPromptIfNeeded(packageName, userId, taskId, null /* info */); + } + + void showNotificationPromptIfNeeded(@NonNull String packageName, int userId, + int taskId, @Nullable ActivityInterceptorInfo info) { UserHandle user = UserHandle.of(userId); if (packageName == null || taskId == ActivityTaskManager.INVALID_TASK_ID || !shouldForceShowNotificationPermissionRequest(packageName, user)) { return; } - launchNotificationPermissionRequestDialog(packageName, user, taskId); + launchNotificationPermissionRequestDialog(packageName, user, taskId, info); } @Override @@ -1180,7 +1183,7 @@ public final class PermissionPolicyService extends SystemService { } private void launchNotificationPermissionRequestDialog(String pkgName, UserHandle user, - int taskId) { + int taskId, @Nullable ActivityInterceptorInfo info) { Intent grantPermission = mPackageManager .buildRequestPermissionsIntent(new String[] { POST_NOTIFICATIONS }); // Prevent the front-most activity entering pip due to overlay activity started on top. @@ -1189,18 +1192,29 @@ public final class PermissionPolicyService extends SystemService { ACTION_REQUEST_PERMISSIONS_FOR_OTHER); grantPermission.putExtra(Intent.EXTRA_PACKAGE_NAME, pkgName); - ActivityOptions options = new ActivityOptions(new Bundle()); + final boolean remoteAnimation = info != null && info.checkedOptions != null + && info.checkedOptions.getAnimationType() == ANIM_REMOTE_ANIMATION + && info.clearOptionsAnimation != null; + ActivityOptions options = remoteAnimation ? ActivityOptions.makeRemoteAnimation( + info.checkedOptions.getRemoteAnimationAdapter(), + info.checkedOptions.getRemoteTransition()) + : new ActivityOptions(new Bundle()); options.setTaskOverlay(true, false); options.setLaunchTaskId(taskId); - mHandler.postDelayed(() -> { - try { - mContext.startActivityAsUser( - grantPermission, options.toBundle(), user); - } catch (Exception e) { - Log.e(LOG_TAG, "couldn't start grant permission dialog" - + "for other package " + pkgName, e); - } - }, ACTIVITY_START_DELAY_MS); + if (remoteAnimation) { + // Remote animation set on the intercepted activity will be handled by the grant + // permission activity, which is launched below. So we need to clear remote + // animation from the intercepted activity and its siblings to prevent duplication. + // This should trigger ActivityRecord#clearOptionsAnimationForSiblings for the + // intercepted activity. + info.clearOptionsAnimation.run(); + } + try { + mContext.startActivityAsUser(grantPermission, options.toBundle(), user); + } catch (Exception e) { + Log.e(LOG_TAG, "couldn't start grant permission dialog" + + "for other package " + pkgName, e); + } } @Override diff --git a/services/core/java/com/android/server/wm/ActivityInterceptorCallback.java b/services/core/java/com/android/server/wm/ActivityInterceptorCallback.java index 1d65cbb70ffe..d2053fa25ad8 100644 --- a/services/core/java/com/android/server/wm/ActivityInterceptorCallback.java +++ b/services/core/java/com/android/server/wm/ActivityInterceptorCallback.java @@ -108,11 +108,13 @@ public abstract class ActivityInterceptorCallback { public final int callingPid; public final int callingUid; public final ActivityOptions checkedOptions; + public final @Nullable Runnable clearOptionsAnimation; public ActivityInterceptorInfo(int realCallingUid, int realCallingPid, int userId, String callingPackage, String callingFeatureId, Intent intent, ResolveInfo rInfo, ActivityInfo aInfo, String resolvedType, int callingPid, - int callingUid, ActivityOptions checkedOptions) { + int callingUid, ActivityOptions checkedOptions, + @Nullable Runnable clearOptionsAnimation) { this.realCallingUid = realCallingUid; this.realCallingPid = realCallingPid; this.userId = userId; @@ -125,6 +127,7 @@ public abstract class ActivityInterceptorCallback { this.callingPid = callingPid; this.callingUid = callingUid; this.checkedOptions = checkedOptions; + this.clearOptionsAnimation = clearOptionsAnimation; } } diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java index 0b52fd643a1c..d8ad2a57afa4 100644 --- a/services/core/java/com/android/server/wm/ActivityRecord.java +++ b/services/core/java/com/android/server/wm/ActivityRecord.java @@ -4592,14 +4592,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A } applyOptionsAnimation(mPendingOptions, intent); } - if (task == null) { - clearOptionsAnimation(); - } else { - // This will clear the options for all the ActivityRecords for this Task. - task.forAllActivities((r) -> { - r.clearOptionsAnimation(); - }); - } + clearOptionsAnimationForSiblings(); } /** @@ -4786,6 +4779,15 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A mPendingRemoteTransition = null; } + void clearOptionsAnimationForSiblings() { + if (task == null) { + clearOptionsAnimation(); + } else { + // This will clear the options for all the ActivityRecords for this Task. + task.forAllActivities(ActivityRecord::clearOptionsAnimation); + } + } + ActivityOptions getOptions() { return mPendingOptions; } diff --git a/services/core/java/com/android/server/wm/ActivityStartInterceptor.java b/services/core/java/com/android/server/wm/ActivityStartInterceptor.java index cdeb86c3ee77..a452013bf42a 100644 --- a/services/core/java/com/android/server/wm/ActivityStartInterceptor.java +++ b/services/core/java/com/android/server/wm/ActivityStartInterceptor.java @@ -188,7 +188,7 @@ class ActivityStartInterceptor { final SparseArray<ActivityInterceptorCallback> callbacks = mService.getActivityInterceptorCallbacks(); final ActivityInterceptorCallback.ActivityInterceptorInfo interceptorInfo = - getInterceptorInfo(); + getInterceptorInfo(null /* clearOptionsAnimation */); for (int i = 0; i < callbacks.size(); i++) { final ActivityInterceptorCallback callback = callbacks.valueAt(i); @@ -406,20 +406,22 @@ class ActivityStartInterceptor { /** * Called when an activity is successfully launched. */ - void onActivityLaunched(TaskInfo taskInfo, ActivityInfo activityInfo) { + void onActivityLaunched(TaskInfo taskInfo, ActivityRecord r) { final SparseArray<ActivityInterceptorCallback> callbacks = mService.getActivityInterceptorCallbacks(); - ActivityInterceptorCallback.ActivityInterceptorInfo info = getInterceptorInfo(); + ActivityInterceptorCallback.ActivityInterceptorInfo info = getInterceptorInfo( + r::clearOptionsAnimationForSiblings); for (int i = 0; i < callbacks.size(); i++) { final ActivityInterceptorCallback callback = callbacks.valueAt(i); - callback.onActivityLaunched(taskInfo, activityInfo, info); + callback.onActivityLaunched(taskInfo, r.info, info); } } - private ActivityInterceptorCallback.ActivityInterceptorInfo getInterceptorInfo() { + private ActivityInterceptorCallback.ActivityInterceptorInfo getInterceptorInfo( + @Nullable Runnable clearOptionsAnimation) { return new ActivityInterceptorCallback.ActivityInterceptorInfo(mRealCallingUid, mRealCallingPid, mUserId, mCallingPackage, mCallingFeatureId, mIntent, mRInfo, mAInfo, mResolvedType, mCallingPid, mCallingUid, - mActivityOptions); + mActivityOptions, clearOptionsAnimation); } } diff --git a/services/core/java/com/android/server/wm/ActivityStarter.java b/services/core/java/com/android/server/wm/ActivityStarter.java index 0b717540a7a6..003268b33cdc 100644 --- a/services/core/java/com/android/server/wm/ActivityStarter.java +++ b/services/core/java/com/android/server/wm/ActivityStarter.java @@ -1585,7 +1585,7 @@ class ActivityStarter { } if (ActivityManager.isStartResultSuccessful(result)) { - mInterceptor.onActivityLaunched(targetTask.getTaskInfo(), r.info); + mInterceptor.onActivityLaunched(targetTask.getTaskInfo(), r); } } diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityStartInterceptorTest.java b/services/tests/wmtests/src/com/android/server/wm/ActivityStartInterceptorTest.java index 24ff3f96100a..73e409abf0c1 100644 --- a/services/tests/wmtests/src/com/android/server/wm/ActivityStartInterceptorTest.java +++ b/services/tests/wmtests/src/com/android/server/wm/ActivityStartInterceptorTest.java @@ -31,6 +31,7 @@ import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.ArgumentMatchers.nullable; +import static org.mockito.Mockito.mock; import android.annotation.Nullable; import android.app.ActivityManagerInternal; @@ -350,7 +351,7 @@ public class ActivityStartInterceptorTest { assertEquals(1, mActivityInterceptorCallbacks.size()); final ActivityInterceptorCallback callback = mActivityInterceptorCallbacks.valueAt(0); spyOn(callback); - mInterceptor.onActivityLaunched(null, null); + mInterceptor.onActivityLaunched(null, mock(ActivityRecord.class)); verify(callback, times(1)).onActivityLaunched(any(), any(), any()); } |