Merge "Transfer remote animation option from an intercepted activity." into tm-dev
This commit is contained in:
committed by
Android (Google) Code Review
commit
6c937bea00
@@ -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;
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1585,7 +1585,7 @@ class ActivityStarter {
|
||||
}
|
||||
|
||||
if (ActivityManager.isStartResultSuccessful(result)) {
|
||||
mInterceptor.onActivityLaunched(targetTask.getTaskInfo(), r.info);
|
||||
mInterceptor.onActivityLaunched(targetTask.getTaskInfo(), r);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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());
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user