diff --git a/config/hiddenapi-vendor-list.txt b/config/hiddenapi-vendor-list.txt index 61ae6e77cbfd9..3a3a708a20cb1 100644 --- a/config/hiddenapi-vendor-list.txt +++ b/config/hiddenapi-vendor-list.txt @@ -20,7 +20,7 @@ Landroid/app/AppOpsManager$PackageOps;->getOps()Ljava/util/List; Landroid/app/AppOpsManager$PackageOps;->getPackageName()Ljava/lang/String; Landroid/app/AppOpsManager$PackageOps;->getUid()I Landroid/app/IActivityController$Stub;->()V -Landroid/app/IActivityManager;->cancelRecentsAnimation()V +Landroid/app/IActivityManager;->cancelRecentsAnimation(Z)V Landroid/app/IActivityManager;->cancelTaskWindowTransition(I)V Landroid/app/IActivityManager;->closeSystemDialogs(Ljava/lang/String;)V Landroid/app/IActivityManager;->getCurrentUser()Landroid/content/pm/UserInfo; diff --git a/core/java/android/app/IActivityManager.aidl b/core/java/android/app/IActivityManager.aidl index e1a02fa497f73..919f71472d333 100644 --- a/core/java/android/app/IActivityManager.aidl +++ b/core/java/android/app/IActivityManager.aidl @@ -450,7 +450,7 @@ interface IActivityManager { in Intent intent, in String resolvedType, in Bundle options, int userId); void startRecentsActivity(in Intent intent, in IAssistDataReceiver assistDataReceiver, in IRecentsAnimationRunner recentsAnimationRunner); - void cancelRecentsAnimation(); + void cancelRecentsAnimation(boolean restoreHomeStackPosition); int startActivityFromRecents(int taskId, in Bundle options); Bundle getActivityOptions(in IBinder token); List getAppTasks(in String callingPackage); diff --git a/core/java/android/view/IRecentsAnimationController.aidl b/core/java/android/view/IRecentsAnimationController.aidl index 89684ca46003c..c0b40c8ceb3b9 100644 --- a/core/java/android/view/IRecentsAnimationController.aidl +++ b/core/java/android/view/IRecentsAnimationController.aidl @@ -59,4 +59,9 @@ interface IRecentsAnimationController { * taken. */ void setAnimationTargetsBehindSystemBars(boolean behindSystemBars); + + /** + * Informs the system that the primary split-screen stack should be minimized. + */ + void setSplitScreenMinimized(boolean minimized); } diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/ActivityManagerWrapper.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/ActivityManagerWrapper.java index 1aad27f99cdce..6aa27542da9a0 100644 --- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/ActivityManagerWrapper.java +++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/ActivityManagerWrapper.java @@ -258,9 +258,9 @@ public class ActivityManagerWrapper { /** * Cancels the remote recents animation started from {@link #startRecentsActivity}. */ - public void cancelRecentsAnimation() { + public void cancelRecentsAnimation(boolean restoreHomeStackPosition) { try { - ActivityManager.getService().cancelRecentsAnimation(); + ActivityManager.getService().cancelRecentsAnimation(restoreHomeStackPosition); } catch (RemoteException e) { Log.e(TAG, "Failed to cancel recents animation", e); } diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/RecentsAnimationControllerCompat.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/RecentsAnimationControllerCompat.java index 5fa6c79a6e85f..80e226d929cd5 100644 --- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/RecentsAnimationControllerCompat.java +++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/RecentsAnimationControllerCompat.java @@ -61,6 +61,14 @@ public class RecentsAnimationControllerCompat { } } + public void setSplitScreenMinimized(boolean minimized) { + try { + mAnimationController.setSplitScreenMinimized(minimized); + } catch (RemoteException e) { + Log.e(TAG, "Failed to set minimize dock", e); + } + } + public void finish(boolean toHome) { try { mAnimationController.finish(toHome); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyButtonView.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyButtonView.java index 44c27571fa3bf..1c9579d4c4abd 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyButtonView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyButtonView.java @@ -52,6 +52,7 @@ import com.android.systemui.plugins.statusbar.phone.NavBarButtonProvider.ButtonI import com.android.systemui.shared.system.ActivityManagerWrapper; import com.android.systemui.statusbar.VibratorHelper; +import static android.view.KeyEvent.KEYCODE_HOME; import static android.view.accessibility.AccessibilityNodeInfo.ACTION_CLICK; import static android.view.accessibility.AccessibilityNodeInfo.ACTION_LONG_CLICK; @@ -270,8 +271,12 @@ public class KeyButtonView extends ImageView implements ButtonInterface { if (mCode != 0) { if (doIt) { // If there was a pending remote recents animation, then we need to - // cancel the animation now before we handle the button itself - ActivityManagerWrapper.getInstance().cancelRecentsAnimation(); + // cancel the animation now before we handle the button itself. In the case + // where we are going home and the recents animation has already started, + // just cancel the recents animation, leaving the home stack in place + boolean isHomeKey = mCode == KEYCODE_HOME; + ActivityManagerWrapper.getInstance().cancelRecentsAnimation(!isHomeKey); + sendEvent(KeyEvent.ACTION_UP, 0); sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_CLICKED); } else { diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java index f97c6d617a7e6..db52b9700e4ef 100644 --- a/services/core/java/com/android/server/am/ActivityManagerService.java +++ b/services/core/java/com/android/server/am/ActivityManagerService.java @@ -204,6 +204,8 @@ import static android.view.WindowManager.TRANSIT_NONE; import static android.view.WindowManager.TRANSIT_TASK_IN_PLACE; import static android.view.WindowManager.TRANSIT_TASK_OPEN; import static android.view.WindowManager.TRANSIT_TASK_TO_FRONT; +import static com.android.server.wm.RecentsAnimationController.REORDER_MOVE_HOME_TO_ORIGINAL_POSITION; +import static com.android.server.wm.RecentsAnimationController.REORDER_KEEP_HOME_IN_PLACE; import static org.xmlpull.v1.XmlPullParser.END_DOCUMENT; import static org.xmlpull.v1.XmlPullParser.START_TAG; @@ -257,7 +259,6 @@ import android.app.WaitResult; import android.app.WindowConfiguration.ActivityType; import android.app.WindowConfiguration.WindowingMode; import android.app.admin.DevicePolicyCache; -import android.app.admin.DevicePolicyManager; import android.app.assist.AssistContent; import android.app.assist.AssistStructure; import android.app.backup.IBackupManager; @@ -5238,12 +5239,14 @@ public class ActivityManagerService extends IActivityManager.Stub } @Override - public void cancelRecentsAnimation() { + public void cancelRecentsAnimation(boolean restoreHomeStackPosition) { enforceCallerIsRecentsOrHasPermission(MANAGE_ACTIVITY_STACKS, "cancelRecentsAnimation()"); final long origId = Binder.clearCallingIdentity(); try { synchronized (this) { - mWindowManager.cancelRecentsAnimation(); + mWindowManager.cancelRecentsAnimation(restoreHomeStackPosition + ? REORDER_MOVE_HOME_TO_ORIGINAL_POSITION + : REORDER_KEEP_HOME_IN_PLACE); } } finally { Binder.restoreCallingIdentity(origId); diff --git a/services/core/java/com/android/server/am/RecentsAnimation.java b/services/core/java/com/android/server/am/RecentsAnimation.java index 9df321c64c9a8..99337b83d0017 100644 --- a/services/core/java/com/android/server/am/RecentsAnimation.java +++ b/services/core/java/com/android/server/am/RecentsAnimation.java @@ -23,6 +23,8 @@ import static android.content.Intent.FLAG_ACTIVITY_NO_ANIMATION; import static android.os.Trace.TRACE_TAG_ACTIVITY_MANAGER; import static android.view.WindowManager.TRANSIT_NONE; import static com.android.server.am.ActivityStackSupervisor.PRESERVE_WINDOWS; +import static com.android.server.wm.RecentsAnimationController.REORDER_MOVE_HOME_TO_ORIGINAL_POSITION; +import static com.android.server.wm.RecentsAnimationController.REORDER_MOVE_HOME_TO_TOP; import android.app.ActivityOptions; import android.content.ComponentName; @@ -32,6 +34,7 @@ import android.os.RemoteException; import android.os.Trace; import android.util.Slog; import android.view.IRecentsAnimationRunner; +import com.android.server.wm.RecentsAnimationController; import com.android.server.wm.RecentsAnimationController.RecentsAnimationCallbacks; import com.android.server.wm.WindowManagerService; @@ -123,7 +126,7 @@ class RecentsAnimation implements RecentsAnimationCallbacks { // Fetch all the surface controls and pass them to the client to get the animation // started - mWindowManager.cancelRecentsAnimation(); + mWindowManager.cancelRecentsAnimation(REORDER_MOVE_HOME_TO_ORIGINAL_POSITION); mWindowManager.initializeRecentsAnimation(recentsAnimationRunner, this, display.mDisplayId, mStackSupervisor.mRecentTasks.getRecentTaskIds()); @@ -140,7 +143,7 @@ class RecentsAnimation implements RecentsAnimationCallbacks { } @Override - public void onAnimationFinished(boolean moveHomeToTop) { + public void onAnimationFinished(@RecentsAnimationController.ReorderMode int reorderMode) { synchronized (mService) { if (mWindowManager.getRecentsAnimationController() == null) return; @@ -151,9 +154,8 @@ class RecentsAnimation implements RecentsAnimationCallbacks { "RecentsAnimation#onAnimationFinished_inSurfaceTransaction"); mWindowManager.deferSurfaceLayout(); try { - mWindowManager.cleanupRecentsAnimation(moveHomeToTop); + mWindowManager.cleanupRecentsAnimation(reorderMode); - // Move the home stack to the front final ActivityRecord homeActivity = mStackSupervisor.getHomeActivity(); if (homeActivity == null) { return; @@ -162,15 +164,19 @@ class RecentsAnimation implements RecentsAnimationCallbacks { // Restore the launched-behind state homeActivity.mLaunchTaskBehind = false; - if (moveHomeToTop) { + if (reorderMode == REORDER_MOVE_HOME_TO_TOP) { // Bring the home stack to the front final ActivityStack homeStack = homeActivity.getStack(); mStackSupervisor.mNoAnimActivities.add(homeActivity); homeStack.moveToFront("RecentsAnimation.onAnimationFinished()"); - } else { + } else if (reorderMode == REORDER_MOVE_HOME_TO_ORIGINAL_POSITION){ // Restore the home stack to its previous position final ActivityDisplay display = homeActivity.getDisplay(); display.moveHomeStackBehindStack(mRestoreHomeBehindStack); + } else { + // Keep home stack in place, nothing changes, so ignore the transition logic + // below + return; } mWindowManager.prepareAppTransition(TRANSIT_NONE, false); @@ -180,6 +186,11 @@ class RecentsAnimation implements RecentsAnimationCallbacks { // No reason to wait for the pausing activity in this case, as the hiding of // surfaces needs to be done immediately. mWindowManager.executeAppTransition(); + + // After reordering the stacks, reset the minimized state. At this point, either + // home is now top-most and we will stay minimized (if in split-screen), or we + // will have returned to the app, and the minimized state should be reset + mWindowManager.checkSplitScreenMinimizedChanged(true /* animate */); } finally { mWindowManager.continueSurfaceLayout(); Trace.traceEnd(TRACE_TAG_ACTIVITY_MANAGER); diff --git a/services/core/java/com/android/server/wm/BoundsAnimationController.java b/services/core/java/com/android/server/wm/BoundsAnimationController.java index ba67ff6a678ec..112d93c750597 100644 --- a/services/core/java/com/android/server/wm/BoundsAnimationController.java +++ b/services/core/java/com/android/server/wm/BoundsAnimationController.java @@ -161,7 +161,10 @@ public class BoundsAnimationController { // Timeout callback to ensure we continue the animation if waiting for resuming or app // windows drawn fails - private final Runnable mResumeRunnable = () -> resume(); + private final Runnable mResumeRunnable = () -> { + if (DEBUG) Slog.d(TAG, "pause: timed out waiting for windows drawn"); + resume(); + }; BoundsAnimator(BoundsAnimationTarget target, Rect from, Rect to, @SchedulePipModeChangedState int schedulePipModeChangedState, @@ -213,7 +216,7 @@ public class BoundsAnimationController { // When starting an animation from fullscreen, pause here and wait for the // windows-drawn signal before we start the rest of the transition down into PiP. - if (mMoveFromFullscreen) { + if (mMoveFromFullscreen && mTarget.shouldDeferStartOnMoveToFullscreen()) { pause(); } } else if (mPrevSchedulePipModeChangedState == SCHEDULE_PIP_MODE_CHANGED_ON_END && diff --git a/services/core/java/com/android/server/wm/BoundsAnimationTarget.java b/services/core/java/com/android/server/wm/BoundsAnimationTarget.java index 647a2d6deac62..68be4e8420a29 100644 --- a/services/core/java/com/android/server/wm/BoundsAnimationTarget.java +++ b/services/core/java/com/android/server/wm/BoundsAnimationTarget.java @@ -33,6 +33,12 @@ interface BoundsAnimationTarget { */ void onAnimationStart(boolean schedulePipModeChangedCallback, boolean forceUpdate); + /** + * @return Whether the animation should be paused waiting for the windows to draw before + * entering PiP. + */ + boolean shouldDeferStartOnMoveToFullscreen(); + /** * Sets the size of the target (without any intermediate steps, like scheduling animation) * but freezes the bounds of any tasks in the target at taskBounds, to allow for more diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java index c4f2bd4d5f75c..0771b53325c02 100644 --- a/services/core/java/com/android/server/wm/DisplayContent.java +++ b/services/core/java/com/android/server/wm/DisplayContent.java @@ -3568,7 +3568,8 @@ class DisplayContent extends WindowContainer= 0; } - setMinimizedDockedStack(homeVisible, animate); + setMinimizedDockedStack(homeVisible || minimizedForRecentsAnimation, animate); } private boolean isWithinDisplay(Task task) { diff --git a/services/core/java/com/android/server/wm/RecentsAnimationController.java b/services/core/java/com/android/server/wm/RecentsAnimationController.java index 7274aee3c9872..c4f51976fb1bc 100644 --- a/services/core/java/com/android/server/wm/RecentsAnimationController.java +++ b/services/core/java/com/android/server/wm/RecentsAnimationController.java @@ -29,6 +29,7 @@ import static com.android.server.wm.WindowManagerService.H.NOTIFY_APP_TRANSITION import static com.android.server.wm.RemoteAnimationAdapterWrapperProto.TARGET; import static com.android.server.wm.AnimationAdapterProto.REMOTE; +import android.annotation.IntDef; import android.app.ActivityManager.TaskSnapshot; import android.app.WindowConfiguration; import android.graphics.Point; @@ -67,12 +68,25 @@ public class RecentsAnimationController implements DeathRecipient { private static final boolean DEBUG = false; private static final long FAILSAFE_DELAY = 1000; + public static final int REORDER_KEEP_HOME_IN_PLACE = 0; + public static final int REORDER_MOVE_HOME_TO_TOP = 1; + public static final int REORDER_MOVE_HOME_TO_ORIGINAL_POSITION = 2; + + @IntDef(prefix = { "REORDER_MODE_" }, value = { + REORDER_KEEP_HOME_IN_PLACE, + REORDER_MOVE_HOME_TO_TOP, + REORDER_MOVE_HOME_TO_ORIGINAL_POSITION + }) + public @interface ReorderMode {} + private final WindowManagerService mService; private final IRecentsAnimationRunner mRunner; private final RecentsAnimationCallbacks mCallbacks; private final ArrayList mPendingAnimations = new ArrayList<>(); private final int mDisplayId; - private final Runnable mFailsafeRunnable = this::cancelAnimation; + private final Runnable mFailsafeRunnable = () -> { + cancelAnimation(REORDER_MOVE_HOME_TO_ORIGINAL_POSITION); + }; // The recents component app token that is shown behind the visibile tasks private AppWindowToken mHomeAppToken; @@ -84,16 +98,20 @@ public class RecentsAnimationController implements DeathRecipient { private boolean mPendingStart = true; // Set when the animation has been canceled - private boolean mCanceled = false; + private boolean mCanceled; // 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; + // Whether or not the recents animation should cause the primary split-screen stack to be + // minimized + private boolean mSplitScreenMinimized; + private Rect mTmpRect = new Rect(); public interface RecentsAnimationCallbacks { - void onAnimationFinished(boolean moveHomeToTop); + void onAnimationFinished(@ReorderMode int reorderMode); } private final IRecentsAnimationController mController = @@ -102,7 +120,7 @@ public class RecentsAnimationController implements DeathRecipient { @Override public TaskSnapshot screenshotTask(int taskId) { if (DEBUG) Log.d(TAG, "screenshotTask(" + taskId + "): mCanceled=" + mCanceled); - long token = Binder.clearCallingIdentity(); + final long token = Binder.clearCallingIdentity(); try { synchronized (mService.getWindowManagerLock()) { if (mCanceled) { @@ -131,7 +149,7 @@ public class RecentsAnimationController implements DeathRecipient { @Override public void finish(boolean moveHomeToTop) { if (DEBUG) Log.d(TAG, "finish(" + moveHomeToTop + "): mCanceled=" + mCanceled); - long token = Binder.clearCallingIdentity(); + final long token = Binder.clearCallingIdentity(); try { synchronized (mService.getWindowManagerLock()) { if (mCanceled) { @@ -141,7 +159,9 @@ public class RecentsAnimationController implements DeathRecipient { // Note, the callback will handle its own synchronization, do not lock on WM lock // prior to calling the callback - mCallbacks.onAnimationFinished(moveHomeToTop); + mCallbacks.onAnimationFinished(moveHomeToTop + ? REORDER_MOVE_HOME_TO_TOP + : REORDER_MOVE_HOME_TO_ORIGINAL_POSITION); } finally { Binder.restoreCallingIdentity(token); } @@ -150,7 +170,7 @@ public class RecentsAnimationController implements DeathRecipient { @Override public void setAnimationTargetsBehindSystemBars(boolean behindSystemBars) throws RemoteException { - long token = Binder.clearCallingIdentity(); + final long token = Binder.clearCallingIdentity(); try { synchronized (mService.getWindowManagerLock()) { for (int i = mPendingAnimations.size() - 1; i >= 0; i--) { @@ -167,7 +187,7 @@ public class RecentsAnimationController implements DeathRecipient { public void setInputConsumerEnabled(boolean enabled) { if (DEBUG) Log.d(TAG, "setInputConsumerEnabled(" + enabled + "): mCanceled=" + mCanceled); - long token = Binder.clearCallingIdentity(); + final long token = Binder.clearCallingIdentity(); try { synchronized (mService.getWindowManagerLock()) { if (mCanceled) { @@ -182,6 +202,23 @@ public class RecentsAnimationController implements DeathRecipient { Binder.restoreCallingIdentity(token); } } + + @Override + public void setSplitScreenMinimized(boolean minimized) { + final long token = Binder.clearCallingIdentity(); + try { + synchronized (mService.getWindowManagerLock()) { + if (mCanceled) { + return; + } + + mSplitScreenMinimized = minimized; + mService.checkSplitScreenMinimizedChanged(true /* animate */); + } + } finally { + Binder.restoreCallingIdentity(token); + } + } }; /** @@ -222,14 +259,14 @@ public class RecentsAnimationController implements DeathRecipient { // Skip the animation if there is nothing to animate if (mPendingAnimations.isEmpty()) { - cancelAnimation(); + cancelAnimation(REORDER_MOVE_HOME_TO_ORIGINAL_POSITION); return; } try { mRunner.asBinder().linkToDeath(this, 0); } catch (RemoteException e) { - cancelAnimation(); + cancelAnimation(REORDER_MOVE_HOME_TO_ORIGINAL_POSITION); return; } @@ -299,7 +336,7 @@ public class RecentsAnimationController implements DeathRecipient { reasons).sendToTarget(); } - void cancelAnimation() { + void cancelAnimation(@ReorderMode int reorderMode) { if (DEBUG) Log.d(TAG, "cancelAnimation()"); synchronized (mService.getWindowManagerLock()) { if (mCanceled) { @@ -314,18 +351,20 @@ public class RecentsAnimationController implements DeathRecipient { Slog.e(TAG, "Failed to cancel recents animation", e); } } + // Clean up and return to the previous app // Don't hold the WM lock here as it calls back to AM/RecentsAnimation - mCallbacks.onAnimationFinished(false /* moveHomeToTop */); + mCallbacks.onAnimationFinished(reorderMode); } - void cleanupAnimation(boolean moveHomeToTop) { + void cleanupAnimation(@ReorderMode int reorderMode) { 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.mTask.setCanAffectSystemUiFlags(true); - if (moveHomeToTop) { + if (reorderMode == REORDER_MOVE_HOME_TO_TOP + || reorderMode == REORDER_KEEP_HOME_IN_PLACE) { adapter.mTask.dontAnimateDimExit(); } adapter.mCapturedFinishCallback.onAnimationFinished(adapter); @@ -333,7 +372,7 @@ public class RecentsAnimationController implements DeathRecipient { mPendingAnimations.clear(); mRunner.asBinder().unlinkToDeath(this, 0); - + // Clear associated input consumers mService.mInputMonitor.updateInputWindowsLw(true /*force*/); mService.destroyInputConsumer(INPUT_CONSUMER_RECENTS_ANIMATION); } @@ -344,7 +383,7 @@ public class RecentsAnimationController implements DeathRecipient { @Override public void binderDied() { - cancelAnimation(); + cancelAnimation(REORDER_MOVE_HOME_TO_ORIGINAL_POSITION); } void checkAnimationReady(WallpaperController wallpaperController) { @@ -358,6 +397,10 @@ public class RecentsAnimationController implements DeathRecipient { } } + boolean isSplitScreenMinimized() { + return mSplitScreenMinimized; + } + boolean isWallpaperVisible(WindowState w) { return w != null && w.mAppToken != null && mHomeAppToken == w.mAppToken && isHomeAppOverWallpaper(); @@ -389,6 +432,15 @@ public class RecentsAnimationController implements DeathRecipient { return mHomeAppToken.windowsCanBeWallpaperTarget(); } + boolean isAnimatingTask(Task task) { + for (int i = mPendingAnimations.size() - 1; i >= 0; i--) { + if (task == mPendingAnimations.get(i).mTask) { + return true; + } + } + return false; + } + private boolean isAnimatingApp(AppWindowToken appToken) { for (int i = mPendingAnimations.size() - 1; i >= 0; i--) { final Task task = mPendingAnimations.get(i).mTask; @@ -409,18 +461,18 @@ public class RecentsAnimationController implements DeathRecipient { private OnAnimationFinishedCallback mCapturedFinishCallback; private final boolean mIsRecentTaskInvisible; private RemoteAnimationTarget mTarget; + private final Point mPosition = new Point(); + private final Rect mBounds = new Rect(); TaskAnimationAdapter(Task task, boolean isRecentTaskInvisible) { mTask = task; mIsRecentTaskInvisible = isRecentTaskInvisible; + final WindowContainer container = mTask.getParent(); + container.getRelativePosition(mPosition); + container.getBounds(mBounds); } RemoteAnimationTarget createRemoteAnimationApp() { - final Point position = new Point(); - final Rect bounds = new Rect(); - final WindowContainer container = mTask.getParent(); - container.getRelativePosition(position); - container.getBounds(bounds); final WindowState mainWindow = mTask.getTopVisibleAppMainWindow(); if (mainWindow == null) { return null; @@ -429,7 +481,7 @@ public class RecentsAnimationController implements DeathRecipient { InsetUtils.addInsets(insets, mainWindow.mAppToken.getLetterboxInsets()); mTarget = new RemoteAnimationTarget(mTask.mTaskId, MODE_CLOSING, mCapturedLeash, !mTask.fillsParent(), mainWindow.mWinAnimator.mLastClipRect, - insets, mTask.getPrefixOrderIndex(), position, bounds, + insets, mTask.getPrefixOrderIndex(), mPosition, mBounds, mTask.getWindowConfiguration(), mIsRecentTaskInvisible); return mTarget; } @@ -452,13 +504,14 @@ public class RecentsAnimationController implements DeathRecipient { @Override public void startAnimation(SurfaceControl animationLeash, Transaction t, OnAnimationFinishedCallback finishCallback) { + t.setPosition(animationLeash, mPosition.x, mPosition.y); mCapturedLeash = animationLeash; mCapturedFinishCallback = finishCallback; } @Override public void onAnimationCancelled(SurfaceControl animationLeash) { - cancelAnimation(); + cancelAnimation(REORDER_MOVE_HOME_TO_ORIGINAL_POSITION); } @Override diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java index e8d321099f000..95223d84635ad 100644 --- a/services/core/java/com/android/server/wm/Task.java +++ b/services/core/java/com/android/server/wm/Task.java @@ -44,6 +44,7 @@ import android.util.Slog; import android.util.proto.ProtoOutputStream; import android.view.Surface; +import android.view.SurfaceControl; import com.android.internal.annotations.VisibleForTesting; import java.io.PrintWriter; @@ -559,6 +560,23 @@ class Task extends WindowContainer { && !mStack.isAnimatingBoundsToFullscreen() && !mPreserveNonFloatingState; } + @Override + public SurfaceControl getAnimationLeashParent() { + // Reparent to the animation layer so that we aren't clipped by the non-minimized + // stack bounds, currently we only animate the task for the recents animation + return getAppAnimationLayer(false /* boosted */); + } + + boolean isTaskAnimating() { + final RecentsAnimationController recentsAnim = mService.getRecentsAnimationController(); + if (recentsAnim != null) { + if (recentsAnim.isAnimatingTask(this)) { + return true; + } + } + return false; + } + WindowState getTopVisibleAppMainWindow() { final AppWindowToken token = getTopVisibleAppToken(); return token != null ? token.findMainWindow() : null; diff --git a/services/core/java/com/android/server/wm/TaskStack.java b/services/core/java/com/android/server/wm/TaskStack.java index 62754ada7900d..2175c6be5b5f7 100644 --- a/services/core/java/com/android/server/wm/TaskStack.java +++ b/services/core/java/com/android/server/wm/TaskStack.java @@ -33,8 +33,6 @@ import static android.view.WindowManager.DOCKED_LEFT; import static android.view.WindowManager.DOCKED_RIGHT; import static android.view.WindowManager.DOCKED_TOP; import static com.android.server.wm.DragResizeMode.DRAG_RESIZE_MODE_DOCKED_DIVIDER; -import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_TASK_MOVEMENT; -import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM; import static com.android.server.wm.StackProto.ADJUSTED_BOUNDS; import static com.android.server.wm.StackProto.ADJUSTED_FOR_IME; import static com.android.server.wm.StackProto.ADJUST_DIVIDER_AMOUNT; @@ -47,6 +45,8 @@ import static com.android.server.wm.StackProto.ID; import static com.android.server.wm.StackProto.MINIMIZE_AMOUNT; import static com.android.server.wm.StackProto.TASKS; import static com.android.server.wm.StackProto.WINDOW_CONTAINER; +import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_TASK_MOVEMENT; +import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM; import android.annotation.CallSuper; import android.content.res.Configuration; @@ -62,12 +62,10 @@ import android.util.proto.ProtoOutputStream; import android.view.DisplayInfo; import android.view.Surface; import android.view.SurfaceControl; - import com.android.internal.policy.DividerSnapAlgorithm; import com.android.internal.policy.DividerSnapAlgorithm.SnapTarget; import com.android.internal.policy.DockedDividerUtils; import com.android.server.EventLogTags; - import java.io.PrintWriter; public class TaskStack extends WindowContainer implements @@ -1333,6 +1331,20 @@ public class TaskStack extends WindowContainer implements return mMinimizeAmount != 0f; } + /** + * @return {@code true} if we have a {@link Task} that is animating (currently only used for the + * recents animation); {@code false} otherwise. + */ + boolean isTaskAnimating() { + for (int j = mChildren.size() - 1; j >= 0; j--) { + final Task task = mChildren.get(j); + if (task.isTaskAnimating()) { + return true; + } + } + return false; + } + @CallSuper @Override public void writeToProto(ProtoOutputStream proto, long fieldId, boolean trim) { @@ -1687,6 +1699,25 @@ public class TaskStack extends WindowContainer implements } } + @Override + public boolean shouldDeferStartOnMoveToFullscreen() { + // Workaround for the recents animation -- normally we need to wait for the new activity to + // show before starting the PiP animation, but because we start and show the home activity + // early for the recents animation prior to the PiP animation starting, there is no + // subsequent all-drawn signal. In this case, we can skip the pause when the home stack is + // already visible and drawn. + final TaskStack homeStack = mDisplayContent.getHomeStack(); + if (homeStack == null) { + return true; + } + final Task homeTask = homeStack.getTopChild(); + final AppWindowToken homeApp = homeTask.getTopVisibleAppToken(); + if (!homeTask.isVisible() || homeApp == null) { + return true; + } + return !homeApp.allDrawn; + } + /** * @return True if we are currently animating the pinned stack from fullscreen to non-fullscreen * bounds and we have a deferred PiP mode changed callback set with the animation. diff --git a/services/core/java/com/android/server/wm/WallpaperController.java b/services/core/java/com/android/server/wm/WallpaperController.java index c509980e1e9e2..6de1579292438 100644 --- a/services/core/java/com/android/server/wm/WallpaperController.java +++ b/services/core/java/com/android/server/wm/WallpaperController.java @@ -26,6 +26,7 @@ import static android.view.WindowManager.LayoutParams.TYPE_WALLPAPER; import static com.android.server.policy.WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER; import static android.view.WindowManager.TRANSIT_FLAG_KEYGUARD_GOING_AWAY_WITH_WALLPAPER; +import static com.android.server.wm.RecentsAnimationController.REORDER_MOVE_HOME_TO_ORIGINAL_POSITION; import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_APP_TRANSITIONS; import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_SCREENSHOT; import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_WALLPAPER; @@ -618,7 +619,8 @@ class WallpaperController { // If there was a recents animation in progress, cancel that animation if (mService.getRecentsAnimationController() != null) { - mService.getRecentsAnimationController().cancelAnimation(); + mService.getRecentsAnimationController().cancelAnimation( + REORDER_MOVE_HOME_TO_ORIGINAL_POSITION); } return true; } diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java index f1cd46bc16d01..28a57f5a46956 100644 --- a/services/core/java/com/android/server/wm/WindowManagerService.java +++ b/services/core/java/com/android/server/wm/WindowManagerService.java @@ -2687,20 +2687,20 @@ public class WindowManagerService extends IWindowManager.Stub } } - public void cancelRecentsAnimation() { + public void cancelRecentsAnimation(@RecentsAnimationController.ReorderMode int reorderMode) { // Note: Do not hold the WM lock, this will lock appropriately in the call which also // calls through to AM/RecentsAnimation.onAnimationFinished() if (mRecentsAnimationController != null) { // This call will call through to cleanupAnimation() below after the animation is // canceled - mRecentsAnimationController.cancelAnimation(); + mRecentsAnimationController.cancelAnimation(reorderMode); } } - public void cleanupRecentsAnimation(boolean moveHomeToTop) { + public void cleanupRecentsAnimation(@RecentsAnimationController.ReorderMode int reorderMode) { synchronized (mWindowMap) { if (mRecentsAnimationController != null) { - mRecentsAnimationController.cleanupAnimation(moveHomeToTop); + mRecentsAnimationController.cleanupAnimation(reorderMode); mRecentsAnimationController = null; mAppTransition.updateBooster(); } diff --git a/services/tests/servicestests/src/com/android/server/am/RecentTasksTest.java b/services/tests/servicestests/src/com/android/server/am/RecentTasksTest.java index 77653872e5ee8..6290ff191847b 100644 --- a/services/tests/servicestests/src/com/android/server/am/RecentTasksTest.java +++ b/services/tests/servicestests/src/com/android/server/am/RecentTasksTest.java @@ -649,7 +649,7 @@ public class RecentTasksTest extends ActivityTestsBase { assertSecurityException(expectCallable, () -> mService.cancelTaskWindowTransition(0)); assertSecurityException(expectCallable, () -> mService.startRecentsActivity(null, null, null)); - assertSecurityException(expectCallable, () -> mService.cancelRecentsAnimation()); + assertSecurityException(expectCallable, () -> mService.cancelRecentsAnimation(true)); } private void testGetTasksApis(boolean expectCallable) { diff --git a/services/tests/servicestests/src/com/android/server/wm/BoundsAnimationControllerTests.java b/services/tests/servicestests/src/com/android/server/wm/BoundsAnimationControllerTests.java index 2bfe2742d419b..6019958d06501 100644 --- a/services/tests/servicestests/src/com/android/server/wm/BoundsAnimationControllerTests.java +++ b/services/tests/servicestests/src/com/android/server/wm/BoundsAnimationControllerTests.java @@ -158,6 +158,11 @@ public class BoundsAnimationControllerTests extends WindowTestsBase { mForcePipModeChangedCallback = forceUpdate; } + @Override + public boolean shouldDeferStartOnMoveToFullscreen() { + return true; + } + @Override public boolean setPinnedStackSize(Rect stackBounds, Rect taskBounds) { // TODO: Once we break the runs apart, we should fail() here if this is called outside