summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Issei Suzuki <issei@google.com> 2022-03-22 18:13:34 +0100
committer Issei Suzuki <issei@google.com> 2022-03-29 12:36:59 +0200
commit5705da8f7dcdf35f77e47fd9090b164968f4dfc8 (patch)
treeb155ae402d8c3eb9772f5d13c7602326eea4d2be
parentcf4afcdd955cfdb74f7b9b4bed1cf9923d9f8eb0 (diff)
Transfer remote animation option from an intercepted activity.
While an activity starts, ActivityStartIntercepter may intercept it and launch another activity. If this happens, we don't have chance to apply pending remote animation of the intercepted activity. The pending remote animation originally came from ActivityOption, so we extract the remote animation from an ActivityOption of the intercepted activity, and pipe it through to the activity being launched by the ActivityStartIntercepter. This also reverts commit a17263ae782e35aa086f6a6e5d76104d8fd145ea. Bug: 222757698 Test: manual. Start YouTube app from the launcher and check animation. Change-Id: Ice62f4ee3453a06362e3acf820ef22235656845c
-rwxr-xr-xservices/core/java/com/android/server/notification/NotificationManagerService.java1
-rw-r--r--services/core/java/com/android/server/policy/PermissionPolicyService.java52
-rw-r--r--services/core/java/com/android/server/wm/ActivityInterceptorCallback.java5
-rw-r--r--services/core/java/com/android/server/wm/ActivityRecord.java18
-rw-r--r--services/core/java/com/android/server/wm/ActivityStartInterceptor.java14
-rw-r--r--services/core/java/com/android/server/wm/ActivityStarter.java2
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/ActivityStartInterceptorTest.java3
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());
}