Revert "Revert "2/ Add support for remote Recents animation""
This reverts commit 9f8518e532e41ba57916afc49bba72bc23ad3eda. Reason for revert: Testing relanding changes with ag/3515280 Change-Id: I410bd752c815a5b998a719453def01e00a9d47c8
This commit is contained in:
parent
59a47deda3
commit
e2d721781f
@ -331,6 +331,8 @@ java_library {
|
||||
"core/java/android/view/IPinnedStackController.aidl",
|
||||
"core/java/android/view/IPinnedStackListener.aidl",
|
||||
"core/java/android/view/IRemoteAnimationRunner.aidl",
|
||||
"core/java/android/view/IRecentsAnimationController.aidl",
|
||||
"core/java/android/view/IRecentsAnimationRunner.aidl",
|
||||
"core/java/android/view/IRemoteAnimationFinishedCallback.aidl",
|
||||
"core/java/android/view/IRotationWatcher.aidl",
|
||||
"core/java/android/view/IWallpaperVisibilityListener.aidl",
|
||||
|
@ -206,6 +206,12 @@ public class ActivityOptions {
|
||||
private static final String KEY_TASK_OVERLAY_CAN_RESUME =
|
||||
"android.activity.taskOverlayCanResume";
|
||||
|
||||
/**
|
||||
* See {@link #setAvoidMoveToFront()}.
|
||||
* @hide
|
||||
*/
|
||||
private static final String KEY_AVOID_MOVE_TO_FRONT = "android.activity.avoidMoveToFront";
|
||||
|
||||
/**
|
||||
* Where the split-screen-primary stack should be positioned.
|
||||
* @hide
|
||||
@ -307,6 +313,7 @@ public class ActivityOptions {
|
||||
private boolean mDisallowEnterPictureInPictureWhileLaunching;
|
||||
private boolean mTaskOverlay;
|
||||
private boolean mTaskOverlayCanResume;
|
||||
private boolean mAvoidMoveToFront;
|
||||
private AppTransitionAnimationSpec mAnimSpecs[];
|
||||
private int mRotationAnimationHint = -1;
|
||||
private Bundle mAppVerificationBundle;
|
||||
@ -923,6 +930,7 @@ public class ActivityOptions {
|
||||
mLaunchTaskId = opts.getInt(KEY_LAUNCH_TASK_ID, -1);
|
||||
mTaskOverlay = opts.getBoolean(KEY_TASK_OVERLAY, false);
|
||||
mTaskOverlayCanResume = opts.getBoolean(KEY_TASK_OVERLAY_CAN_RESUME, false);
|
||||
mAvoidMoveToFront = opts.getBoolean(KEY_AVOID_MOVE_TO_FRONT, false);
|
||||
mSplitScreenCreateMode = opts.getInt(KEY_SPLIT_SCREEN_CREATE_MODE,
|
||||
SPLIT_SCREEN_CREATE_MODE_TOP_OR_LEFT);
|
||||
mDisallowEnterPictureInPictureWhileLaunching = opts.getBoolean(
|
||||
@ -1239,6 +1247,25 @@ public class ActivityOptions {
|
||||
return mTaskOverlayCanResume;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets whether the activity launched should not cause the activity stack it is contained in to
|
||||
* be moved to the front as a part of launching.
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
public void setAvoidMoveToFront() {
|
||||
mAvoidMoveToFront = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return whether the activity launch should prevent moving the associated activity stack to
|
||||
* the front.
|
||||
* @hide
|
||||
*/
|
||||
public boolean getAvoidMoveToFront() {
|
||||
return mAvoidMoveToFront;
|
||||
}
|
||||
|
||||
/** @hide */
|
||||
public int getSplitScreenCreateMode() {
|
||||
return mSplitScreenCreateMode;
|
||||
@ -1416,6 +1443,7 @@ public class ActivityOptions {
|
||||
b.putInt(KEY_LAUNCH_TASK_ID, mLaunchTaskId);
|
||||
b.putBoolean(KEY_TASK_OVERLAY, mTaskOverlay);
|
||||
b.putBoolean(KEY_TASK_OVERLAY_CAN_RESUME, mTaskOverlayCanResume);
|
||||
b.putBoolean(KEY_AVOID_MOVE_TO_FRONT, mAvoidMoveToFront);
|
||||
b.putInt(KEY_SPLIT_SCREEN_CREATE_MODE, mSplitScreenCreateMode);
|
||||
b.putBoolean(KEY_DISALLOW_ENTER_PICTURE_IN_PICTURE_WHILE_LAUNCHING,
|
||||
mDisallowEnterPictureInPictureWhileLaunching);
|
||||
|
@ -66,6 +66,7 @@ import android.os.PersistableBundle;
|
||||
import android.os.StrictMode;
|
||||
import android.os.WorkSource;
|
||||
import android.service.voice.IVoiceInteractionSession;
|
||||
import android.view.IRecentsAnimationRunner;
|
||||
import android.view.RemoteAnimationDefinition;
|
||||
import com.android.internal.app.IVoiceInteractor;
|
||||
import com.android.internal.os.IResultReceiver;
|
||||
@ -442,8 +443,9 @@ interface IActivityManager {
|
||||
in Bundle options, int userId);
|
||||
int startAssistantActivity(in String callingPackage, int callingPid, int callingUid,
|
||||
in Intent intent, in String resolvedType, in Bundle options, int userId);
|
||||
int startRecentsActivity(in IAssistDataReceiver assistDataReceiver, in Bundle options,
|
||||
in Bundle activityOptions, int userId);
|
||||
void startRecentsActivity(in Intent intent, in IAssistDataReceiver assistDataReceiver,
|
||||
in IRecentsAnimationRunner recentsAnimationRunner);
|
||||
void cancelRecentsAnimation();
|
||||
int startActivityFromRecents(int taskId, in Bundle options);
|
||||
Bundle getActivityOptions(in IBinder token);
|
||||
List<IBinder> getAppTasks(in String callingPackage);
|
||||
|
54
core/java/android/view/IRecentsAnimationController.aidl
Normal file
54
core/java/android/view/IRecentsAnimationController.aidl
Normal file
@ -0,0 +1,54 @@
|
||||
/*
|
||||
* Copyright (C) 2018 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package android.view;
|
||||
|
||||
import android.app.ActivityManager;
|
||||
import android.view.IRemoteAnimationFinishedCallback;
|
||||
import android.graphics.GraphicBuffer;
|
||||
|
||||
/**
|
||||
* Passed to the {@link IRecentsAnimationRunner} in order for the runner to control to let the
|
||||
* runner control certain aspects of the recents animation, and to notify window manager when the
|
||||
* animation has completed.
|
||||
*
|
||||
* {@hide}
|
||||
*/
|
||||
interface IRecentsAnimationController {
|
||||
|
||||
/**
|
||||
* Takes a screenshot of the task associated with the given {@param taskId}. Only valid for the
|
||||
* current set of task ids provided to the handler.
|
||||
*/
|
||||
ActivityManager.TaskSnapshot screenshotTask(int taskId);
|
||||
|
||||
/**
|
||||
* Notifies to the system that the animation into Recents should end, and all leashes associated
|
||||
* with remote animation targets should be relinquished. If {@param moveHomeToTop} is true, then
|
||||
* the home activity should be moved to the top. Otherwise, the home activity is hidden and the
|
||||
* user is returned to the app.
|
||||
*/
|
||||
void finish(boolean moveHomeToTop);
|
||||
|
||||
/**
|
||||
* Called by the handler to indicate that the recents animation input consumer should be
|
||||
* enabled. This is currently used to work around an issue where registering an input consumer
|
||||
* mid-animation causes the existing motion event chain to be canceled. Instead, the caller
|
||||
* may register the recents animation input consumer prior to starting the recents animation
|
||||
* and then enable it mid-animation to start receiving touch events.
|
||||
*/
|
||||
void setInputConsumerEnabled(boolean enabled);
|
||||
}
|
42
core/java/android/view/IRecentsAnimationRunner.aidl
Normal file
42
core/java/android/view/IRecentsAnimationRunner.aidl
Normal file
@ -0,0 +1,42 @@
|
||||
/*
|
||||
* Copyright (C) 2018 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package android.view;
|
||||
|
||||
import android.view.RemoteAnimationTarget;
|
||||
import android.view.IRecentsAnimationController;
|
||||
|
||||
/**
|
||||
* Interface that is used to callback from window manager to the process that runs a recents
|
||||
* animation to start or cancel it.
|
||||
*
|
||||
* {@hide}
|
||||
*/
|
||||
oneway interface IRecentsAnimationRunner {
|
||||
|
||||
/**
|
||||
* Called when the system is ready for the handler to start animating all the visible tasks.
|
||||
*/
|
||||
void onAnimationStart(in IRecentsAnimationController controller,
|
||||
in RemoteAnimationTarget[] apps);
|
||||
|
||||
/**
|
||||
* Called when the system needs to cancel the current animation. This can be due to the
|
||||
* wallpaper not drawing in time, or the handler not finishing the animation within a predefined
|
||||
* amount of time.
|
||||
*/
|
||||
void onAnimationCanceled();
|
||||
}
|
@ -17,6 +17,7 @@
|
||||
package android.view;
|
||||
|
||||
import android.annotation.IntDef;
|
||||
import android.app.WindowConfiguration;
|
||||
import android.graphics.Point;
|
||||
import android.graphics.Rect;
|
||||
import android.os.Parcel;
|
||||
@ -98,8 +99,14 @@ public class RemoteAnimationTarget implements Parcelable {
|
||||
*/
|
||||
public final Rect sourceContainerBounds;
|
||||
|
||||
/**
|
||||
* The window configuration for the target.
|
||||
*/
|
||||
public final WindowConfiguration windowConfiguration;
|
||||
|
||||
public RemoteAnimationTarget(int taskId, int mode, SurfaceControl leash, boolean isTranslucent,
|
||||
Rect clipRect, int prefixOrderIndex, Point position, Rect sourceContainerBounds) {
|
||||
Rect clipRect, int prefixOrderIndex, Point position, Rect sourceContainerBounds,
|
||||
WindowConfiguration windowConfig) {
|
||||
this.mode = mode;
|
||||
this.taskId = taskId;
|
||||
this.leash = leash;
|
||||
@ -108,6 +115,7 @@ public class RemoteAnimationTarget implements Parcelable {
|
||||
this.prefixOrderIndex = prefixOrderIndex;
|
||||
this.position = new Point(position);
|
||||
this.sourceContainerBounds = new Rect(sourceContainerBounds);
|
||||
this.windowConfiguration = windowConfig;
|
||||
}
|
||||
|
||||
public RemoteAnimationTarget(Parcel in) {
|
||||
@ -119,6 +127,7 @@ public class RemoteAnimationTarget implements Parcelable {
|
||||
prefixOrderIndex = in.readInt();
|
||||
position = in.readParcelable(null);
|
||||
sourceContainerBounds = in.readParcelable(null);
|
||||
windowConfiguration = in.readParcelable(null);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -136,6 +145,7 @@ public class RemoteAnimationTarget implements Parcelable {
|
||||
dest.writeInt(prefixOrderIndex);
|
||||
dest.writeParcelable(position, 0 /* flags */);
|
||||
dest.writeParcelable(sourceContainerBounds, 0 /* flags */);
|
||||
dest.writeParcelable(windowConfiguration, 0 /* flags */);
|
||||
}
|
||||
|
||||
public static final Creator<RemoteAnimationTarget> CREATOR
|
||||
|
@ -16,6 +16,7 @@
|
||||
|
||||
package com.android.server.am;
|
||||
|
||||
import static android.app.ActivityManager.StackId.INVALID_STACK_ID;
|
||||
import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME;
|
||||
import static android.app.WindowConfiguration.ACTIVITY_TYPE_RECENTS;
|
||||
import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
|
||||
@ -664,6 +665,64 @@ class ActivityDisplay extends ConfigurationContainer<ActivityStack>
|
||||
&& (mSupervisor.mService.mRunningVoice == null);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the stack currently above the home stack. Can be null if there is no home stack, or
|
||||
* the home stack is already on top.
|
||||
*/
|
||||
ActivityStack getStackAboveHome() {
|
||||
if (mHomeStack == null) {
|
||||
// Skip if there is no home stack
|
||||
return null;
|
||||
}
|
||||
|
||||
final int stackIndex = mStacks.indexOf(mHomeStack) + 1;
|
||||
return (stackIndex < mStacks.size()) ? mStacks.get(stackIndex) : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adjusts the home stack behind the last visible stack in the display if necessary. Generally
|
||||
* used in conjunction with {@link #moveHomeStackBehindStack}.
|
||||
*/
|
||||
void moveHomeStackBehindBottomMostVisibleStack() {
|
||||
if (mHomeStack == null) {
|
||||
// Skip if there is no home stack
|
||||
return;
|
||||
}
|
||||
|
||||
// Move the home stack to the bottom to not affect the following visibility checks
|
||||
positionChildAtBottom(mHomeStack);
|
||||
|
||||
// Find the next position where the homes stack should be placed
|
||||
final int numStacks = mStacks.size();
|
||||
for (int stackNdx = 0; stackNdx < numStacks; stackNdx++) {
|
||||
final ActivityStack stack = mStacks.get(stackNdx);
|
||||
if (stack == mHomeStack) {
|
||||
continue;
|
||||
}
|
||||
final int winMode = stack.getWindowingMode();
|
||||
final boolean isValidWindowingMode = winMode == WINDOWING_MODE_FULLSCREEN ||
|
||||
winMode == WINDOWING_MODE_SPLIT_SCREEN_SECONDARY;
|
||||
if (stack.shouldBeVisible(null) && isValidWindowingMode) {
|
||||
// Move the home stack to behind this stack
|
||||
positionChildAt(mHomeStack, Math.max(0, stackNdx - 1));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Moves the home stack behind the given {@param stack} if possible. If {@param stack} is not
|
||||
* currently in the display, then then the home stack is moved to the back. Generally used in
|
||||
* conjunction with {@link #moveHomeStackBehindBottomMostVisibleStack}.
|
||||
*/
|
||||
void moveHomeStackBehindStack(ActivityStack behindStack) {
|
||||
if (behindStack == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
positionChildAt(mHomeStack, Math.max(0, mStacks.indexOf(behindStack) - 1));
|
||||
}
|
||||
|
||||
boolean isSleeping() {
|
||||
return mSleeping;
|
||||
}
|
||||
|
@ -39,6 +39,7 @@ import static android.app.ActivityManagerInternal.ASSIST_KEY_STRUCTURE;
|
||||
import static android.app.ActivityThread.PROC_START_SEQ_IDENT;
|
||||
import static android.app.AppOpsManager.OP_ASSIST_STRUCTURE;
|
||||
import static android.app.AppOpsManager.OP_NONE;
|
||||
import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME;
|
||||
import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
|
||||
import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED;
|
||||
import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
|
||||
@ -377,6 +378,7 @@ import android.util.Xml;
|
||||
import android.util.proto.ProtoOutputStream;
|
||||
import android.util.proto.ProtoUtils;
|
||||
import android.view.Gravity;
|
||||
import android.view.IRecentsAnimationRunner;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.RemoteAnimationDefinition;
|
||||
import android.view.View;
|
||||
@ -450,6 +452,7 @@ import com.android.server.pm.Installer.InstallerException;
|
||||
import com.android.server.utils.PriorityDump;
|
||||
import com.android.server.vr.VrManagerInternal;
|
||||
import com.android.server.wm.PinnedStackWindowController;
|
||||
import com.android.server.wm.RecentsAnimationController;
|
||||
import com.android.server.wm.WindowManagerService;
|
||||
|
||||
import dalvik.system.VMRuntime;
|
||||
@ -5096,23 +5099,16 @@ public class ActivityManagerService extends IActivityManager.Stub
|
||||
}
|
||||
|
||||
@Override
|
||||
public int startRecentsActivity(IAssistDataReceiver assistDataReceiver, Bundle options,
|
||||
Bundle activityOptions, int userId) {
|
||||
if (!mRecentTasks.isCallerRecents(Binder.getCallingUid())) {
|
||||
String msg = "Permission Denial: startRecentsActivity() from pid="
|
||||
+ Binder.getCallingPid() + ", uid=" + Binder.getCallingUid()
|
||||
+ " not recent tasks package";
|
||||
Slog.w(TAG, msg);
|
||||
throw new SecurityException(msg);
|
||||
}
|
||||
|
||||
final SafeActivityOptions safeOptions = SafeActivityOptions.fromBundle(options);
|
||||
final int recentsUid = mRecentTasks.getRecentsComponentUid();
|
||||
final ComponentName recentsComponent = mRecentTasks.getRecentsComponent();
|
||||
final String recentsPackage = recentsComponent.getPackageName();
|
||||
public void startRecentsActivity(Intent intent, IAssistDataReceiver assistDataReceiver,
|
||||
IRecentsAnimationRunner recentsAnimationRunner) {
|
||||
enforceCallerIsRecentsOrHasPermission(MANAGE_ACTIVITY_STACKS, "startRecentsActivity()");
|
||||
final long origId = Binder.clearCallingIdentity();
|
||||
try {
|
||||
synchronized (this) {
|
||||
final int recentsUid = mRecentTasks.getRecentsComponentUid();
|
||||
final ComponentName recentsComponent = mRecentTasks.getRecentsComponent();
|
||||
final String recentsPackage = recentsComponent.getPackageName();
|
||||
|
||||
// If provided, kick off the request for the assist data in the background before
|
||||
// starting the activity
|
||||
if (assistDataReceiver != null) {
|
||||
@ -5129,17 +5125,24 @@ public class ActivityManagerService extends IActivityManager.Stub
|
||||
recentsUid, recentsPackage);
|
||||
}
|
||||
|
||||
final Intent intent = new Intent();
|
||||
intent.setFlags(FLAG_ACTIVITY_NEW_TASK);
|
||||
intent.setComponent(recentsComponent);
|
||||
intent.putExtras(options);
|
||||
// Start a new recents animation
|
||||
final RecentsAnimation anim = new RecentsAnimation(this, mStackSupervisor,
|
||||
mActivityStartController, mWindowManager, mUserController);
|
||||
anim.startRecentsActivity(intent, recentsAnimationRunner, recentsComponent,
|
||||
recentsUid);
|
||||
}
|
||||
} finally {
|
||||
Binder.restoreCallingIdentity(origId);
|
||||
}
|
||||
}
|
||||
|
||||
return mActivityStartController.obtainStarter(intent, "startRecentsActivity")
|
||||
.setCallingUid(recentsUid)
|
||||
.setCallingPackage(recentsPackage)
|
||||
.setActivityOptions(safeOptions)
|
||||
.setMayWait(userId)
|
||||
.execute();
|
||||
@Override
|
||||
public void cancelRecentsAnimation() {
|
||||
enforceCallerIsRecentsOrHasPermission(MANAGE_ACTIVITY_STACKS, "cancelRecentsAnimation()");
|
||||
final long origId = Binder.clearCallingIdentity();
|
||||
try {
|
||||
synchronized (this) {
|
||||
mWindowManager.cancelRecentsAnimation();
|
||||
}
|
||||
} finally {
|
||||
Binder.restoreCallingIdentity(origId);
|
||||
|
@ -297,6 +297,7 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D
|
||||
private RunningTasks mRunningTasks;
|
||||
|
||||
final ActivityStackSupervisorHandler mHandler;
|
||||
final Looper mLooper;
|
||||
|
||||
/** Short cut */
|
||||
WindowManagerService mWindowManager;
|
||||
@ -581,6 +582,7 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D
|
||||
|
||||
public ActivityStackSupervisor(ActivityManagerService service, Looper looper) {
|
||||
mService = service;
|
||||
mLooper = looper;
|
||||
mHandler = new ActivityStackSupervisorHandler(looper);
|
||||
}
|
||||
|
||||
|
@ -302,6 +302,7 @@ class ActivityStarter {
|
||||
SafeActivityOptions activityOptions;
|
||||
boolean ignoreTargetSecurity;
|
||||
boolean componentSpecified;
|
||||
boolean avoidMoveToFront;
|
||||
ActivityRecord[] outActivity;
|
||||
TaskRecord inTask;
|
||||
String reason;
|
||||
@ -356,6 +357,7 @@ class ActivityStarter {
|
||||
userId = 0;
|
||||
waitResult = null;
|
||||
mayWait = false;
|
||||
avoidMoveToFront = false;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -390,6 +392,7 @@ class ActivityStarter {
|
||||
userId = request.userId;
|
||||
waitResult = request.waitResult;
|
||||
mayWait = request.mayWait;
|
||||
avoidMoveToFront = request.avoidMoveToFront;
|
||||
}
|
||||
}
|
||||
|
||||
@ -1485,19 +1488,23 @@ class ActivityStarter {
|
||||
mDoResume = false;
|
||||
}
|
||||
|
||||
if (mOptions != null && mOptions.getLaunchTaskId() != -1
|
||||
&& mOptions.getTaskOverlay()) {
|
||||
r.mTaskOverlay = true;
|
||||
if (!mOptions.canTaskOverlayResume()) {
|
||||
final TaskRecord task = mSupervisor.anyTaskForIdLocked(mOptions.getLaunchTaskId());
|
||||
final ActivityRecord top = task != null ? task.getTopActivity() : null;
|
||||
if (top != null && top.state != RESUMED) {
|
||||
if (mOptions != null) {
|
||||
if (mOptions.getLaunchTaskId() != -1 && mOptions.getTaskOverlay()) {
|
||||
r.mTaskOverlay = true;
|
||||
if (!mOptions.canTaskOverlayResume()) {
|
||||
final TaskRecord task = mSupervisor.anyTaskForIdLocked(
|
||||
mOptions.getLaunchTaskId());
|
||||
final ActivityRecord top = task != null ? task.getTopActivity() : null;
|
||||
if (top != null && top.state != RESUMED) {
|
||||
|
||||
// The caller specifies that we'd like to be avoided to be moved to the front,
|
||||
// so be it!
|
||||
mDoResume = false;
|
||||
mAvoidMoveToFront = true;
|
||||
// The caller specifies that we'd like to be avoided to be moved to the
|
||||
// front, so be it!
|
||||
mDoResume = false;
|
||||
mAvoidMoveToFront = true;
|
||||
}
|
||||
}
|
||||
} else if (mOptions.getAvoidMoveToFront()) {
|
||||
mAvoidMoveToFront = true;
|
||||
}
|
||||
}
|
||||
|
||||
@ -1838,7 +1845,7 @@ class ActivityStarter {
|
||||
// Need to update mTargetStack because if task was moved out of it, the original stack may
|
||||
// be destroyed.
|
||||
mTargetStack = intentActivity.getStack();
|
||||
if (!mMovedToFront && mDoResume) {
|
||||
if (!mAvoidMoveToFront && !mMovedToFront && mDoResume) {
|
||||
if (DEBUG_TASKS) Slog.d(TAG_TASKS, "Bring to front target: " + mTargetStack
|
||||
+ " from " + intentActivity);
|
||||
mTargetStack.moveToFront("intentActivityFound");
|
||||
|
159
services/core/java/com/android/server/am/RecentsAnimation.java
Normal file
159
services/core/java/com/android/server/am/RecentsAnimation.java
Normal file
@ -0,0 +1,159 @@
|
||||
/*
|
||||
* Copyright (C) 2018 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.server.am;
|
||||
|
||||
import static android.app.ActivityManager.StackId.INVALID_STACK_ID;
|
||||
import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME;
|
||||
import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK;
|
||||
import static android.content.Intent.FLAG_ACTIVITY_NO_ANIMATION;
|
||||
import static android.view.WindowManager.TRANSIT_NONE;
|
||||
import static com.android.server.am.ActivityStackSupervisor.PRESERVE_WINDOWS;
|
||||
|
||||
import android.app.ActivityOptions;
|
||||
import android.content.ComponentName;
|
||||
import android.content.Intent;
|
||||
import android.os.Handler;
|
||||
import android.view.IRecentsAnimationRunner;
|
||||
import com.android.server.wm.RecentsAnimationController.RecentsAnimationCallbacks;
|
||||
import com.android.server.wm.WindowManagerService;
|
||||
|
||||
/**
|
||||
* Manages the recents animation, including the reordering of the stacks for the transition and
|
||||
* cleanup. See {@link com.android.server.wm.RecentsAnimationController}.
|
||||
*/
|
||||
class RecentsAnimation implements RecentsAnimationCallbacks {
|
||||
private static final String TAG = RecentsAnimation.class.getSimpleName();
|
||||
|
||||
private static final int RECENTS_ANIMATION_TIMEOUT = 10 * 1000;
|
||||
|
||||
private final ActivityManagerService mService;
|
||||
private final ActivityStackSupervisor mStackSupervisor;
|
||||
private final ActivityStartController mActivityStartController;
|
||||
private final WindowManagerService mWindowManager;
|
||||
private final UserController mUserController;
|
||||
private final Handler mHandler;
|
||||
|
||||
private final Runnable mCancelAnimationRunnable;
|
||||
|
||||
// The stack to restore the home stack behind when the animation is finished
|
||||
private ActivityStack mRestoreHomeBehindStack;
|
||||
|
||||
RecentsAnimation(ActivityManagerService am, ActivityStackSupervisor stackSupervisor,
|
||||
ActivityStartController activityStartController, WindowManagerService wm,
|
||||
UserController userController) {
|
||||
mService = am;
|
||||
mStackSupervisor = stackSupervisor;
|
||||
mActivityStartController = activityStartController;
|
||||
mHandler = new Handler(mStackSupervisor.mLooper);
|
||||
mWindowManager = wm;
|
||||
mUserController = userController;
|
||||
mCancelAnimationRunnable = () -> {
|
||||
// The caller has not finished the animation in a predefined amount of time, so
|
||||
// force-cancel the animation
|
||||
mWindowManager.cancelRecentsAnimation();
|
||||
};
|
||||
}
|
||||
|
||||
void startRecentsActivity(Intent intent, IRecentsAnimationRunner recentsAnimationRunner,
|
||||
ComponentName recentsComponent, int recentsUid) {
|
||||
|
||||
// Cancel the previous recents animation if necessary
|
||||
mWindowManager.cancelRecentsAnimation();
|
||||
|
||||
final boolean hasExistingHomeActivity = mStackSupervisor.getHomeActivity() != null;
|
||||
if (!hasExistingHomeActivity) {
|
||||
// No home activity
|
||||
final ActivityOptions opts = ActivityOptions.makeBasic();
|
||||
opts.setLaunchActivityType(ACTIVITY_TYPE_HOME);
|
||||
opts.setAvoidMoveToFront();
|
||||
intent.addFlags(FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_NO_ANIMATION);
|
||||
|
||||
mActivityStartController.obtainStarter(intent, "startRecentsActivity_noHomeActivity")
|
||||
.setCallingUid(recentsUid)
|
||||
.setCallingPackage(recentsComponent.getPackageName())
|
||||
.setActivityOptions(SafeActivityOptions.fromBundle(opts.toBundle()))
|
||||
.setMayWait(mUserController.getCurrentUserId())
|
||||
.execute();
|
||||
mWindowManager.prepareAppTransition(TRANSIT_NONE, false);
|
||||
|
||||
// TODO: Maybe wait for app to draw in this particular case?
|
||||
}
|
||||
|
||||
final ActivityRecord homeActivity = mStackSupervisor.getHomeActivity();
|
||||
final ActivityDisplay display = homeActivity.getDisplay();
|
||||
|
||||
// Save the initial position of the home activity stack to be restored to after the
|
||||
// animation completes
|
||||
mRestoreHomeBehindStack = hasExistingHomeActivity
|
||||
? display.getStackAboveHome()
|
||||
: null;
|
||||
|
||||
// Move the home activity into place for the animation
|
||||
display.moveHomeStackBehindBottomMostVisibleStack();
|
||||
|
||||
// Mark the home activity as launch-behind to bump its visibility for the
|
||||
// duration of the gesture that is driven by the recents component
|
||||
homeActivity.mLaunchTaskBehind = true;
|
||||
|
||||
// Fetch all the surface controls and pass them to the client to get the animation
|
||||
// started
|
||||
mWindowManager.initializeRecentsAnimation(recentsAnimationRunner, this, display.mDisplayId);
|
||||
|
||||
// If we updated the launch-behind state, update the visibility of the activities after we
|
||||
// fetch the visible tasks to be controlled by the animation
|
||||
mStackSupervisor.ensureActivitiesVisibleLocked(null, 0, PRESERVE_WINDOWS);
|
||||
|
||||
// Post a timeout for the animation
|
||||
mHandler.postDelayed(mCancelAnimationRunnable, RECENTS_ANIMATION_TIMEOUT);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAnimationFinished(boolean moveHomeToTop) {
|
||||
mHandler.removeCallbacks(mCancelAnimationRunnable);
|
||||
synchronized (mService) {
|
||||
if (mWindowManager.getRecentsAnimationController() == null) return;
|
||||
|
||||
mWindowManager.inSurfaceTransaction(() -> {
|
||||
mWindowManager.cleanupRecentsAnimation();
|
||||
|
||||
// Move the home stack to the front
|
||||
final ActivityRecord homeActivity = mStackSupervisor.getHomeActivity();
|
||||
if (homeActivity == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Restore the launched-behind state
|
||||
homeActivity.mLaunchTaskBehind = false;
|
||||
|
||||
if (moveHomeToTop) {
|
||||
// Bring the home stack to the front
|
||||
final ActivityStack homeStack = homeActivity.getStack();
|
||||
homeStack.mNoAnimActivities.add(homeActivity);
|
||||
homeStack.moveToFront("RecentsAnimation.onAnimationFinished()");
|
||||
} else {
|
||||
// Restore the home stack to its previous position
|
||||
final ActivityDisplay display = homeActivity.getDisplay();
|
||||
display.moveHomeStackBehindStack(mRestoreHomeBehindStack);
|
||||
}
|
||||
|
||||
mWindowManager.prepareAppTransition(TRANSIT_NONE, false);
|
||||
mStackSupervisor.ensureActivitiesVisibleLocked(null, 0, false);
|
||||
mStackSupervisor.resumeFocusedStackTopActivityLocked();
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
@ -1508,6 +1508,10 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo
|
||||
return mTaskStackContainers.getTopStack();
|
||||
}
|
||||
|
||||
ArrayList<Task> getVisibleTasks() {
|
||||
return mTaskStackContainers.getVisibleTasks();
|
||||
}
|
||||
|
||||
void onStackWindowingModeChanged(TaskStack stack) {
|
||||
mTaskStackContainers.onStackWindowingModeChanged(stack);
|
||||
}
|
||||
@ -3260,6 +3264,16 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo
|
||||
return mSplitScreenPrimaryStack;
|
||||
}
|
||||
|
||||
ArrayList<Task> getVisibleTasks() {
|
||||
final ArrayList<Task> visibleTasks = new ArrayList<>();
|
||||
forAllTasks(task -> {
|
||||
if (task.isVisible()) {
|
||||
visibleTasks.add(task);
|
||||
}
|
||||
});
|
||||
return visibleTasks;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds the stack to this container.
|
||||
* @see DisplayContent#createStack(int, boolean, StackWindowController)
|
||||
|
@ -0,0 +1,373 @@
|
||||
/*
|
||||
* Copyright (C) 2017 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License
|
||||
*/
|
||||
|
||||
package com.android.server.wm;
|
||||
|
||||
import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME;
|
||||
import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY;
|
||||
import static android.view.RemoteAnimationTarget.MODE_CLOSING;
|
||||
import static com.android.server.policy.WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER;
|
||||
import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME;
|
||||
import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
|
||||
|
||||
import android.app.ActivityManager;
|
||||
import android.app.ActivityManager.TaskSnapshot;
|
||||
import android.app.WindowConfiguration;
|
||||
import android.graphics.GraphicBuffer;
|
||||
import android.graphics.Point;
|
||||
import android.graphics.Rect;
|
||||
import android.os.Binder;
|
||||
import android.os.RemoteException;
|
||||
import android.os.SystemClock;
|
||||
import android.util.Log;
|
||||
import android.util.Slog;
|
||||
import android.view.IRecentsAnimationController;
|
||||
import android.view.IRecentsAnimationRunner;
|
||||
import android.view.RemoteAnimationTarget;
|
||||
import android.view.SurfaceControl;
|
||||
import android.view.SurfaceControl.Transaction;
|
||||
import com.android.server.wm.SurfaceAnimator.OnAnimationFinishedCallback;
|
||||
import java.io.PrintWriter;
|
||||
import java.util.ArrayList;
|
||||
|
||||
/**
|
||||
* Controls a single instance of the remote driven recents animation. In particular, this allows
|
||||
* the calling SystemUI to animate the visible task windows as a part of the transition. The remote
|
||||
* runner is provided an animation controller which allows it to take screenshots and to notify
|
||||
* window manager when the animation is completed. In addition, window manager may also notify the
|
||||
* app if it requires the animation to be canceled at any time (ie. due to timeout, etc.)
|
||||
*/
|
||||
public class RecentsAnimationController {
|
||||
private static final String TAG = TAG_WITH_CLASS_NAME ? "RecentsAnimationController" : TAG_WM;
|
||||
private static final boolean DEBUG = false;
|
||||
|
||||
private final WindowManagerService mService;
|
||||
private final IRecentsAnimationRunner mRunner;
|
||||
private final RecentsAnimationCallbacks mCallbacks;
|
||||
private final ArrayList<TaskAnimationAdapter> mPendingAnimations = new ArrayList<>();
|
||||
|
||||
// The recents component app token that is shown behind the visibile tasks
|
||||
private AppWindowToken mHomeAppToken;
|
||||
|
||||
// We start the RecentsAnimationController in a pending-start state since we need to wait for
|
||||
// the wallpaper/activity to draw before we can give control to the handler to start animating
|
||||
// the visible task surfaces
|
||||
private boolean mPendingStart = true;
|
||||
|
||||
// Set when the animation has been canceled
|
||||
private boolean mCanceled = false;
|
||||
|
||||
// Whether or not the input consumer is enabled. The input consumer must be both registered and
|
||||
// enabled for it to start intercepting touch events.
|
||||
private boolean mInputConsumerEnabled;
|
||||
|
||||
public interface RecentsAnimationCallbacks {
|
||||
void onAnimationFinished(boolean moveHomeToTop);
|
||||
}
|
||||
|
||||
private final IRecentsAnimationController mController =
|
||||
new IRecentsAnimationController.Stub() {
|
||||
|
||||
@Override
|
||||
public TaskSnapshot screenshotTask(int taskId) {
|
||||
if (DEBUG) Log.d(TAG, "screenshotTask(" + taskId + "): mCanceled=" + mCanceled);
|
||||
long token = Binder.clearCallingIdentity();
|
||||
try {
|
||||
synchronized (mService.getWindowManagerLock()) {
|
||||
if (mCanceled) {
|
||||
return null;
|
||||
}
|
||||
for (int i = mPendingAnimations.size() - 1; i >= 0; i--) {
|
||||
final TaskAnimationAdapter adapter = mPendingAnimations.get(i);
|
||||
final Task task = adapter.mTask;
|
||||
if (task.mTaskId == taskId) {
|
||||
// TODO: Save this screenshot as the task snapshot?
|
||||
final Rect taskFrame = new Rect();
|
||||
task.getBounds(taskFrame);
|
||||
final GraphicBuffer buffer = SurfaceControl.captureLayers(
|
||||
task.getSurfaceControl().getHandle(), taskFrame, 1f);
|
||||
final AppWindowToken topChild = task.getTopChild();
|
||||
final WindowState mainWindow = topChild.findMainWindow();
|
||||
return new TaskSnapshot(buffer, topChild.getConfiguration().orientation,
|
||||
mainWindow.mStableInsets,
|
||||
ActivityManager.isLowRamDeviceStatic() /* reduced */,
|
||||
1.0f /* scale */);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
} finally {
|
||||
Binder.restoreCallingIdentity(token);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void finish(boolean moveHomeToTop) {
|
||||
if (DEBUG) Log.d(TAG, "finish(" + moveHomeToTop + "): mCanceled=" + mCanceled);
|
||||
long token = Binder.clearCallingIdentity();
|
||||
try {
|
||||
synchronized (mService.getWindowManagerLock()) {
|
||||
if (mCanceled) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Note, the callback will handle its own synchronization, do not lock on WM lock
|
||||
// prior to calling the callback
|
||||
mCallbacks.onAnimationFinished(moveHomeToTop);
|
||||
} finally {
|
||||
Binder.restoreCallingIdentity(token);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setInputConsumerEnabled(boolean enabled) {
|
||||
if (DEBUG) Log.d(TAG, "setInputConsumerEnabled(" + enabled + "): mCanceled="
|
||||
+ mCanceled);
|
||||
long token = Binder.clearCallingIdentity();
|
||||
try {
|
||||
synchronized (mService.getWindowManagerLock()) {
|
||||
if (mCanceled) {
|
||||
return;
|
||||
}
|
||||
|
||||
mInputConsumerEnabled = enabled;
|
||||
mService.mInputMonitor.updateInputWindowsLw(true /*force*/);
|
||||
mService.scheduleAnimationLocked();
|
||||
}
|
||||
} finally {
|
||||
Binder.restoreCallingIdentity(token);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Initializes a new RecentsAnimationController.
|
||||
*
|
||||
* @param remoteAnimationRunner The remote runner which should be notified when the animation is
|
||||
* ready to start or has been canceled
|
||||
* @param callbacks Callbacks to be made when the animation finishes
|
||||
* @param restoreHomeBehindStackId The stack id to restore the home stack behind once the
|
||||
* animation is complete. Will be passed to the callback.
|
||||
*/
|
||||
RecentsAnimationController(WindowManagerService service,
|
||||
IRecentsAnimationRunner remoteAnimationRunner, RecentsAnimationCallbacks callbacks,
|
||||
int displayId) {
|
||||
mService = service;
|
||||
mRunner = remoteAnimationRunner;
|
||||
mCallbacks = callbacks;
|
||||
|
||||
final DisplayContent dc = mService.mRoot.getDisplayContent(displayId);
|
||||
final ArrayList<Task> visibleTasks = dc.getVisibleTasks();
|
||||
if (visibleTasks.isEmpty()) {
|
||||
cancelAnimation();
|
||||
return;
|
||||
}
|
||||
|
||||
// Make leashes for each of the visible tasks and add it to the recents animation to be
|
||||
// started
|
||||
final int taskCount = visibleTasks.size();
|
||||
for (int i = 0; i < taskCount; i++) {
|
||||
final Task task = visibleTasks.get(i);
|
||||
final WindowConfiguration config = task.getWindowConfiguration();
|
||||
if (config.tasksAreFloating()
|
||||
|| config.getWindowingMode() == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY
|
||||
|| config.getActivityType() == ACTIVITY_TYPE_HOME) {
|
||||
continue;
|
||||
}
|
||||
addAnimation(task);
|
||||
}
|
||||
|
||||
// Adjust the wallpaper visibility for the showing home activity
|
||||
final AppWindowToken recentsComponentAppToken =
|
||||
dc.getHomeStack().getTopChild().getTopFullscreenAppToken();
|
||||
if (recentsComponentAppToken != null) {
|
||||
if (DEBUG) Log.d(TAG, "setHomeApp(" + recentsComponentAppToken.getName() + ")");
|
||||
mHomeAppToken = recentsComponentAppToken;
|
||||
final WallpaperController wc = dc.mWallpaperController;
|
||||
if (recentsComponentAppToken.windowsCanBeWallpaperTarget()) {
|
||||
dc.pendingLayoutChanges |= FINISH_LAYOUT_REDO_WALLPAPER;
|
||||
dc.setLayoutNeeded();
|
||||
}
|
||||
}
|
||||
|
||||
mService.mWindowPlacerLocked.performSurfacePlacement();
|
||||
}
|
||||
|
||||
private void addAnimation(Task task) {
|
||||
if (DEBUG) Log.d(TAG, "addAnimation(" + task.getName() + ")");
|
||||
final SurfaceAnimator anim = new SurfaceAnimator(task, null /* animationFinishedCallback */,
|
||||
mService.mAnimator::addAfterPrepareSurfacesRunnable, mService);
|
||||
final TaskAnimationAdapter taskAdapter = new TaskAnimationAdapter(task);
|
||||
anim.startAnimation(task.getPendingTransaction(), taskAdapter, false /* hidden */);
|
||||
task.commitPendingTransaction();
|
||||
mPendingAnimations.add(taskAdapter);
|
||||
}
|
||||
|
||||
void startAnimation() {
|
||||
if (DEBUG) Log.d(TAG, "startAnimation(): mPendingStart=" + mPendingStart);
|
||||
if (!mPendingStart) {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
final RemoteAnimationTarget[] appAnimations =
|
||||
new RemoteAnimationTarget[mPendingAnimations.size()];
|
||||
for (int i = mPendingAnimations.size() - 1; i >= 0; i--) {
|
||||
appAnimations[i] = mPendingAnimations.get(i).createRemoteAnimationApp();
|
||||
}
|
||||
mPendingStart = false;
|
||||
mRunner.onAnimationStart(mController, appAnimations);
|
||||
} catch (RemoteException e) {
|
||||
Slog.e(TAG, "Failed to start recents animation", e);
|
||||
}
|
||||
}
|
||||
|
||||
void cancelAnimation() {
|
||||
if (DEBUG) Log.d(TAG, "cancelAnimation()");
|
||||
if (mCanceled) {
|
||||
// We've already canceled the animation
|
||||
return;
|
||||
}
|
||||
mCanceled = true;
|
||||
try {
|
||||
mRunner.onAnimationCanceled();
|
||||
} catch (RemoteException e) {
|
||||
Slog.e(TAG, "Failed to cancel recents animation", e);
|
||||
}
|
||||
|
||||
// Clean up and return to the previous app
|
||||
mCallbacks.onAnimationFinished(false /* moveHomeToTop */);
|
||||
}
|
||||
|
||||
void cleanupAnimation() {
|
||||
if (DEBUG) Log.d(TAG, "cleanupAnimation(): mPendingAnimations="
|
||||
+ mPendingAnimations.size());
|
||||
for (int i = mPendingAnimations.size() - 1; i >= 0; i--) {
|
||||
final TaskAnimationAdapter adapter = mPendingAnimations.get(i);
|
||||
adapter.mCapturedFinishCallback.onAnimationFinished(adapter);
|
||||
}
|
||||
mPendingAnimations.clear();
|
||||
|
||||
mService.mInputMonitor.updateInputWindowsLw(true /*force*/);
|
||||
mService.scheduleAnimationLocked();
|
||||
}
|
||||
|
||||
void checkAnimationReady(WallpaperController wallpaperController) {
|
||||
if (mPendingStart) {
|
||||
final boolean wallpaperReady = !isHomeAppOverWallpaper()
|
||||
|| (wallpaperController.getWallpaperTarget() != null
|
||||
&& wallpaperController.wallpaperTransitionReady());
|
||||
if (wallpaperReady) {
|
||||
mService.getRecentsAnimationController().startAnimation();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
boolean isWallpaperVisible(WindowState w) {
|
||||
return w != null && w.mAppToken != null && mHomeAppToken == w.mAppToken
|
||||
&& isHomeAppOverWallpaper();
|
||||
}
|
||||
|
||||
boolean isHomeAppOverWallpaper() {
|
||||
if (mHomeAppToken == null) {
|
||||
return false;
|
||||
}
|
||||
return mHomeAppToken.windowsCanBeWallpaperTarget();
|
||||
}
|
||||
|
||||
WindowState getHomeAppMainWindow() {
|
||||
if (mHomeAppToken == null) {
|
||||
return null;
|
||||
}
|
||||
return mHomeAppToken.findMainWindow();
|
||||
}
|
||||
|
||||
boolean isAnimatingApp(AppWindowToken appToken) {
|
||||
for (int i = mPendingAnimations.size() - 1; i >= 0; i--) {
|
||||
final Task task = mPendingAnimations.get(i).mTask;
|
||||
for (int j = task.getChildCount() - 1; j >= 0; j--) {
|
||||
final AppWindowToken app = task.getChildAt(j);
|
||||
if (app == appToken) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
boolean isInputConsumerEnabled() {
|
||||
return mInputConsumerEnabled;
|
||||
}
|
||||
|
||||
private class TaskAnimationAdapter implements AnimationAdapter {
|
||||
|
||||
private Task mTask;
|
||||
private SurfaceControl mCapturedLeash;
|
||||
private OnAnimationFinishedCallback mCapturedFinishCallback;
|
||||
|
||||
TaskAnimationAdapter(Task task) {
|
||||
mTask = task;
|
||||
}
|
||||
|
||||
RemoteAnimationTarget createRemoteAnimationApp() {
|
||||
// TODO: Do we need position and stack bounds?
|
||||
return new RemoteAnimationTarget(mTask.mTaskId, MODE_CLOSING, mCapturedLeash,
|
||||
!mTask.fillsParent(),
|
||||
mTask.getTopVisibleAppMainWindow().mWinAnimator.mLastClipRect,
|
||||
mTask.getPrefixOrderIndex(), new Point(), new Rect(),
|
||||
mTask.getWindowConfiguration());
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean getDetachWallpaper() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getBackgroundColor() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void startAnimation(SurfaceControl animationLeash, Transaction t,
|
||||
OnAnimationFinishedCallback finishCallback) {
|
||||
mCapturedLeash = animationLeash;
|
||||
mCapturedFinishCallback = finishCallback;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAnimationCancelled(SurfaceControl animationLeash) {
|
||||
cancelAnimation();
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getDurationHint() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getStatusBarTransitionsStartTime() {
|
||||
return SystemClock.uptimeMillis();
|
||||
}
|
||||
}
|
||||
|
||||
public void dump(PrintWriter pw, String prefix) {
|
||||
final String innerPrefix = prefix + " ";
|
||||
pw.print(prefix); pw.println(RecentsAnimationController.class.getSimpleName() + ":");
|
||||
pw.print(innerPrefix); pw.println("mPendingStart=" + mPendingStart);
|
||||
pw.print(innerPrefix); pw.println("mHomeAppToken=" + mHomeAppToken);
|
||||
}
|
||||
}
|
@ -160,7 +160,8 @@ class RemoteAnimationController {
|
||||
return new RemoteAnimationTarget(task.mTaskId, getMode(),
|
||||
mCapturedLeash, !mAppWindowToken.fillsParent(),
|
||||
mainWindow.mWinAnimator.mLastClipRect,
|
||||
mAppWindowToken.getPrefixOrderIndex(), mPosition, mStackBounds);
|
||||
mAppWindowToken.getPrefixOrderIndex(), mPosition, mStackBounds,
|
||||
task.getWindowConfiguration());
|
||||
}
|
||||
|
||||
private int getMode() {
|
||||
|
@ -623,6 +623,13 @@ class RootWindowContainer extends WindowContainer<DisplayContent> {
|
||||
defaultDisplay.pendingLayoutChanges);
|
||||
}
|
||||
|
||||
// Defer starting the recents animation until the wallpaper has drawn
|
||||
final RecentsAnimationController recentsAnimationController =
|
||||
mService.getRecentsAnimationController();
|
||||
if (recentsAnimationController != null) {
|
||||
recentsAnimationController.checkAnimationReady(mWallpaperController);
|
||||
}
|
||||
|
||||
if (mWallpaperForceHidingChanged && defaultDisplay.pendingLayoutChanges == 0
|
||||
&& !mService.mAppTransition.isReady()) {
|
||||
// At this point, there was a window with a wallpaper that was force hiding other
|
||||
|
@ -62,7 +62,7 @@ class SurfaceAnimator {
|
||||
* @param addAfterPrepareSurfaces Consumer that takes a runnable and executes it after preparing
|
||||
* surfaces in WM. Can be implemented differently during testing.
|
||||
*/
|
||||
SurfaceAnimator(Animatable animatable, Runnable animationFinishedCallback,
|
||||
SurfaceAnimator(Animatable animatable, @Nullable Runnable animationFinishedCallback,
|
||||
Consumer<Runnable> addAfterPrepareSurfaces, WindowManagerService service) {
|
||||
mAnimatable = animatable;
|
||||
mService = service;
|
||||
@ -71,7 +71,8 @@ class SurfaceAnimator {
|
||||
addAfterPrepareSurfaces);
|
||||
}
|
||||
|
||||
private OnAnimationFinishedCallback getFinishedCallback(Runnable animationFinishedCallback,
|
||||
private OnAnimationFinishedCallback getFinishedCallback(
|
||||
@Nullable Runnable animationFinishedCallback,
|
||||
Consumer<Runnable> addAfterPrepareSurfaces) {
|
||||
return anim -> {
|
||||
synchronized (mService.mWindowMap) {
|
||||
@ -97,7 +98,9 @@ class SurfaceAnimator {
|
||||
SurfaceControl.openTransaction();
|
||||
try {
|
||||
reset(t, true /* destroyLeash */);
|
||||
animationFinishedCallback.run();
|
||||
if (animationFinishedCallback != null) {
|
||||
animationFinishedCallback.run();
|
||||
}
|
||||
} finally {
|
||||
SurfaceControl.mergeToGlobalTransaction(t);
|
||||
SurfaceControl.closeTransaction();
|
||||
|
@ -149,8 +149,17 @@ class WallpaperController {
|
||||
mFindResults.setUseTopWallpaperAsTarget(true);
|
||||
}
|
||||
|
||||
final RecentsAnimationController recentsAnimationController =
|
||||
mService.getRecentsAnimationController();
|
||||
final boolean hasWallpaper = (w.mAttrs.flags & FLAG_SHOW_WALLPAPER) != 0;
|
||||
if (hasWallpaper && w.isOnScreen() && (mWallpaperTarget == w || w.isDrawFinishedLw())) {
|
||||
final boolean isRecentsTransitionTarget = (recentsAnimationController != null
|
||||
&& recentsAnimationController.isWallpaperVisible(w));
|
||||
if (isRecentsTransitionTarget) {
|
||||
if (DEBUG_WALLPAPER) Slog.v(TAG, "Found recents animation wallpaper target: " + w);
|
||||
mFindResults.setWallpaperTarget(w);
|
||||
return true;
|
||||
} else if (hasWallpaper && w.isOnScreen()
|
||||
&& (mWallpaperTarget == w || w.isDrawFinishedLw())) {
|
||||
if (DEBUG_WALLPAPER) Slog.v(TAG, "Found wallpaper target: " + w);
|
||||
mFindResults.setWallpaperTarget(w);
|
||||
if (w == mWallpaperTarget && w.mWinAnimator.isAnimationSet()) {
|
||||
@ -199,15 +208,22 @@ class WallpaperController {
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isWallpaperVisible(WindowState wallpaperTarget) {
|
||||
private final boolean isWallpaperVisible(WindowState wallpaperTarget) {
|
||||
final RecentsAnimationController recentsAnimationController =
|
||||
mService.getRecentsAnimationController();
|
||||
boolean isAnimatingWithRecentsComponent = recentsAnimationController != null
|
||||
&& recentsAnimationController.isWallpaperVisible(wallpaperTarget);
|
||||
if (DEBUG_WALLPAPER) Slog.v(TAG, "Wallpaper vis: target " + wallpaperTarget + ", obscured="
|
||||
+ (wallpaperTarget != null ? Boolean.toString(wallpaperTarget.mObscured) : "??")
|
||||
+ " animating=" + ((wallpaperTarget != null && wallpaperTarget.mAppToken != null)
|
||||
? wallpaperTarget.mAppToken.isSelfAnimating() : null)
|
||||
+ " prev=" + mPrevWallpaperTarget);
|
||||
+ " prev=" + mPrevWallpaperTarget
|
||||
+ " recentsAnimationWallpaperVisible=" + isAnimatingWithRecentsComponent);
|
||||
return (wallpaperTarget != null
|
||||
&& (!wallpaperTarget.mObscured || (wallpaperTarget.mAppToken != null
|
||||
&& wallpaperTarget.mAppToken.isSelfAnimating())))
|
||||
&& (!wallpaperTarget.mObscured
|
||||
|| isAnimatingWithRecentsComponent
|
||||
|| (wallpaperTarget.mAppToken != null
|
||||
&& wallpaperTarget.mAppToken.isSelfAnimating())))
|
||||
|| mPrevWallpaperTarget != null;
|
||||
}
|
||||
|
||||
@ -587,6 +603,11 @@ class WallpaperController {
|
||||
mWallpaperDrawState = WALLPAPER_DRAW_TIMEOUT;
|
||||
if (DEBUG_APP_TRANSITIONS || DEBUG_WALLPAPER) Slog.v(TAG,
|
||||
"*** WALLPAPER DRAW TIMEOUT");
|
||||
|
||||
// If there was a recents animation in progress, cancel that animation
|
||||
if (mService.getRecentsAnimationController() != null) {
|
||||
mService.getRecentsAnimationController().cancelAnimation();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
|
@ -337,9 +337,9 @@ class WindowContainer<E extends WindowContainer> extends ConfigurationContainer<
|
||||
}
|
||||
|
||||
/** Returns true if this window container has the input child. */
|
||||
boolean hasChild(WindowContainer child) {
|
||||
boolean hasChild(E child) {
|
||||
for (int i = mChildren.size() - 1; i >= 0; --i) {
|
||||
final WindowContainer current = mChildren.get(i);
|
||||
final E current = mChildren.get(i);
|
||||
if (current == child || current.hasChild(child)) {
|
||||
return true;
|
||||
}
|
||||
|
@ -24,6 +24,8 @@ import static android.Manifest.permission.RESTRICTED_VR_ACCESS;
|
||||
import static android.app.ActivityManager.SPLIT_SCREEN_CREATE_MODE_TOP_OR_LEFT;
|
||||
import static android.app.AppOpsManager.OP_SYSTEM_ALERT_WINDOW;
|
||||
import static android.app.StatusBarManager.DISABLE_MASK;
|
||||
import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME;
|
||||
import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY;
|
||||
import static android.app.admin.DevicePolicyManager.ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED;
|
||||
import static android.content.Intent.ACTION_USER_REMOVED;
|
||||
import static android.content.Intent.EXTRA_USER_HANDLE;
|
||||
@ -123,6 +125,7 @@ import android.app.ActivityThread;
|
||||
import android.app.AppOpsManager;
|
||||
import android.app.IActivityManager;
|
||||
import android.app.IAssistDataReceiver;
|
||||
import android.app.WindowConfiguration;
|
||||
import android.content.BroadcastReceiver;
|
||||
import android.content.ContentResolver;
|
||||
import android.content.Context;
|
||||
@ -196,6 +199,7 @@ import android.view.IDockedStackListener;
|
||||
import android.view.IInputFilter;
|
||||
import android.view.IOnKeyguardExitResult;
|
||||
import android.view.IPinnedStackListener;
|
||||
import android.view.IRecentsAnimationRunner;
|
||||
import android.view.IRotationWatcher;
|
||||
import android.view.IWallpaperVisibilityListener;
|
||||
import android.view.IWindow;
|
||||
@ -528,6 +532,7 @@ public class WindowManagerService extends IWindowManager.Stub
|
||||
IInputMethodManager mInputMethodManager;
|
||||
|
||||
AccessibilityController mAccessibilityController;
|
||||
private RecentsAnimationController mRecentsAnimationController;
|
||||
|
||||
Watermark mWatermark;
|
||||
StrictModeFlash mStrictModeFlash;
|
||||
@ -2670,6 +2675,39 @@ public class WindowManagerService extends IWindowManager.Stub
|
||||
}
|
||||
}
|
||||
|
||||
public void initializeRecentsAnimation(
|
||||
IRecentsAnimationRunner recentsAnimationRunner,
|
||||
RecentsAnimationController.RecentsAnimationCallbacks callbacks, int displayId) {
|
||||
synchronized (mWindowMap) {
|
||||
cancelRecentsAnimation();
|
||||
mRecentsAnimationController = new RecentsAnimationController(this,
|
||||
recentsAnimationRunner, callbacks, displayId);
|
||||
}
|
||||
}
|
||||
|
||||
public RecentsAnimationController getRecentsAnimationController() {
|
||||
return mRecentsAnimationController;
|
||||
}
|
||||
|
||||
public void cancelRecentsAnimation() {
|
||||
synchronized (mWindowMap) {
|
||||
if (mRecentsAnimationController != null) {
|
||||
// This call will call through to cleanupAnimation() below after the animation is
|
||||
// canceled
|
||||
mRecentsAnimationController.cancelAnimation();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void cleanupRecentsAnimation() {
|
||||
synchronized (mWindowMap) {
|
||||
if (mRecentsAnimationController != null) {
|
||||
mRecentsAnimationController.cleanupAnimation();
|
||||
mRecentsAnimationController = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void setAppFullscreen(IBinder token, boolean toOpaque) {
|
||||
synchronized (mWindowMap) {
|
||||
final AppWindowToken atoken = mRoot.getAppWindowToken(token);
|
||||
@ -6327,6 +6365,10 @@ public class WindowManagerService extends IWindowManager.Stub
|
||||
pw.print(" mSkipAppTransitionAnimation=");pw.println(mSkipAppTransitionAnimation);
|
||||
pw.println(" mLayoutToAnim:");
|
||||
mAppTransition.dump(pw, " ");
|
||||
if (mRecentsAnimationController != null) {
|
||||
pw.print(" mRecentsAnimationController="); pw.println(mRecentsAnimationController);
|
||||
mRecentsAnimationController.dump(pw, " ");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -573,7 +573,8 @@ public class RecentTasksTest extends ActivityTestsBase {
|
||||
assertSecurityException(expectCallable, () -> mService.getTaskDescription(0));
|
||||
assertSecurityException(expectCallable, () -> mService.cancelTaskWindowTransition(0));
|
||||
assertSecurityException(expectCallable, () -> mService.startRecentsActivity(null, null,
|
||||
null, 0));
|
||||
null));
|
||||
assertSecurityException(expectCallable, () -> mService.cancelRecentsAnimation());
|
||||
}
|
||||
|
||||
private void testGetTasksApis(boolean expectCallable) {
|
||||
|
Loading…
x
Reference in New Issue
Block a user