Merge "Transfer remote animation option from an intercepted activity." into tm-dev

This commit is contained in:
TreeHugger Robot
2022-03-31 11:28:10 +00:00
committed by Android (Google) Code Review
7 changed files with 58 additions and 37 deletions

View File

@@ -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;

View File

@@ -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

View File

@@ -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;
}
}

View File

@@ -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;
}

View File

@@ -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);
}
}

View File

@@ -1585,7 +1585,7 @@ class ActivityStarter {
}
if (ActivityManager.isStartResultSuccessful(result)) {
mInterceptor.onActivityLaunched(targetTask.getTaskInfo(), r.info);
mInterceptor.onActivityLaunched(targetTask.getTaskInfo(), r);
}
}

View File

@@ -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());
}