From 0065703423feca30642afba7606e8484ff7bbdb7 Mon Sep 17 00:00:00 2001 From: Hongwei Wang Date: Tue, 6 Oct 2020 13:56:02 -0700 Subject: [PATCH] Enter PiP directly if the transition is handled in Launcher Added also a AIDL method Launcher would issue when the entering pip animation is completed on Launcher side and WM should update the task surface when doing cleanup. Bug: 143965596 Test: see ag/12838262 Change-Id: I5396f9637b4760df014f63b46543d4f399229bba --- .../view/IRecentsAnimationController.aidl | 10 +++++ data/etc/services.core.protolog.json | 6 +++ .../wm/shell/pip/PipTaskOrganizer.java | 28 +++++++++----- .../RecentsAnimationControllerCompat.java | 16 ++++++++ .../server/wm/RecentsAnimationController.java | 37 ++++++++++++++++++- 5 files changed, 86 insertions(+), 11 deletions(-) diff --git a/core/java/android/view/IRecentsAnimationController.aidl b/core/java/android/view/IRecentsAnimationController.aidl index 983ab2eedf5ce..f209d88ac8252 100644 --- a/core/java/android/view/IRecentsAnimationController.aidl +++ b/core/java/android/view/IRecentsAnimationController.aidl @@ -19,6 +19,7 @@ package android.view; import android.app.ActivityManager; import android.view.IRemoteAnimationFinishedCallback; import android.graphics.GraphicBuffer; +import android.graphics.Rect; /** * Passed to the {@link IRecentsAnimationRunner} in order for the runner to control to let the @@ -36,6 +37,15 @@ interface IRecentsAnimationController { @UnsupportedAppUsage ActivityManager.TaskSnapshot screenshotTask(int taskId); + /** + * Sets the final bounds on a Task. This is used by Launcher to notify the system that + * animating Activity to PiP has completed and the associated task surface should be updated + * accordingly. This should be called before `finish` + * @param taskId for which the leash should be updated + * @param destinationBounds bounds of the final PiP window + */ + void setFinishTaskBounds(int taskId, in Rect destinationBounds); + /** * 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 diff --git a/data/etc/services.core.protolog.json b/data/etc/services.core.protolog.json index 98c33705255a3..a430dcdda2471 100644 --- a/data/etc/services.core.protolog.json +++ b/data/etc/services.core.protolog.json @@ -319,6 +319,12 @@ "group": "WM_DEBUG_ORIENTATION", "at": "com\/android\/server\/wm\/DisplayRotation.java" }, + "-1729340764": { + "message": "setFinishTaskBounds(%d): bounds=%s", + "level": "DEBUG", + "group": "WM_DEBUG_RECENTS_ANIMATIONS", + "at": "com\/android\/server\/wm\/RecentsAnimationController.java" + }, "-1715268616": { "message": "Last window, removing starting window %s", "level": "VERBOSE", diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java index a7bf9aea46bca..a284775746055 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java @@ -68,7 +68,6 @@ import com.android.wm.shell.common.DisplayController; import com.android.wm.shell.pip.phone.PipMenuActivityController; import com.android.wm.shell.pip.phone.PipMotionHelper; import com.android.wm.shell.pip.phone.PipUpdateThread; -import com.android.wm.shell.pip.phone.PipUtils; import com.android.wm.shell.splitscreen.SplitScreen; import java.io.PrintWriter; @@ -339,7 +338,7 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener, public Rect startSwipePipToHome(ComponentName componentName, ActivityInfo activityInfo, PictureInPictureParams pictureInPictureParams) { mShouldIgnoreEnteringPipTransition = true; - mState = State.ENTERING_PIP; + sendOnPipTransitionStarted(componentName, TRANSITION_DIRECTION_TO_PIP); mPipBoundsState.setLastPipComponentName(componentName); mPipBoundsState.setAspectRatio(getAspectRatioOrDefault(pictureInPictureParams)); return mPipBoundsHandler.getDestinationBounds(null /* bounds */, @@ -351,7 +350,10 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener, * Expect {@link #onTaskAppeared(ActivityManager.RunningTaskInfo, SurfaceControl)} afterwards. */ public void stopSwipePipToHome(ComponentName componentName, Rect destinationBounds) { - mPipBoundsState.setBounds(destinationBounds); + // do nothing if there is no startSwipePipToHome being called before + if (mShouldIgnoreEnteringPipTransition) { + mPipBoundsState.setBounds(destinationBounds); + } } /** @@ -494,11 +496,9 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener, } if (mShouldIgnoreEnteringPipTransition) { - // Animation has been finished together with Recents, directly apply the sync - // transaction to PiP here. - applyEnterPipSyncTransaction(mPipBoundsState.getBounds(), () -> { - mState = State.ENTERED_PIP; - }); + // animation is finished in the Launcher and here we directly apply the final touch. + applyEnterPipSyncTransaction(mPipBoundsState.getBounds(), + () -> sendOnPipTransitionFinished(TRANSITION_DIRECTION_TO_PIP)); mShouldIgnoreEnteringPipTransition = false; return; } @@ -589,11 +589,19 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener, private void sendOnPipTransitionStarted( @PipAnimationController.TransitionDirection int direction) { + sendOnPipTransitionStarted(mTaskInfo.baseActivity, direction); + } + + private void sendOnPipTransitionStarted(ComponentName componentName, + @PipAnimationController.TransitionDirection int direction) { + if (direction == TRANSITION_DIRECTION_TO_PIP) { + mState = State.ENTERING_PIP; + } final Rect pipBounds = mPipBoundsState.getBounds(); runOnMainHandler(() -> { for (int i = mPipTransitionCallbacks.size() - 1; i >= 0; i--) { final PipTransitionCallback callback = mPipTransitionCallbacks.get(i); - callback.onPipTransitionStarted(mTaskInfo.baseActivity, direction, pipBounds); + callback.onPipTransitionStarted(componentName, direction, pipBounds); } }); } @@ -703,6 +711,7 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener, return; } mShouldDeferEnteringPip = false; + mShouldIgnoreEnteringPipTransition = false; mPictureInPictureParams = null; mState = State.UNDEFINED; mPipUiEventLoggerLogger.setTaskInfo(null); @@ -1081,7 +1090,6 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener, return WINDOWING_MODE_UNDEFINED; } - private void animateResizePip(Rect currentBounds, Rect destinationBounds, Rect sourceHintRect, @PipAnimationController.TransitionDirection int direction, int durationMs) { if (Looper.myLooper() != mUpdateHandler.getLooper()) { 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 76513c6ff3d53..611c4b766b4e5 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 @@ -17,6 +17,7 @@ package com.android.systemui.shared.system; import android.app.ActivityManager.TaskSnapshot; +import android.graphics.Rect; import android.os.RemoteException; import android.util.Log; import android.view.IRecentsAnimationController; @@ -69,6 +70,21 @@ public class RecentsAnimationControllerCompat { } } + /** + * Sets the final bounds on a Task. This is used by Launcher to notify the system that + * animating Activity to PiP has completed and the associated task surface should be updated + * accordingly. This should be called before `finish` + * @param taskId Task id of the Activity in PiP mode. + * @param destinationBounds Bounds of the PiP window on home. + */ + public void setFinishTaskBounds(int taskId, Rect destinationBounds) { + try { + mAnimationController.setFinishTaskBounds(taskId, destinationBounds); + } catch (RemoteException e) { + Log.d(TAG, "Failed to set finish task bounds", e); + } + } + /** * Finish the current recents animation. * @param toHome Going to home or back to the previous app. diff --git a/services/core/java/com/android/server/wm/RecentsAnimationController.java b/services/core/java/com/android/server/wm/RecentsAnimationController.java index 4ad2575c9490e..1736ac933a80b 100644 --- a/services/core/java/com/android/server/wm/RecentsAnimationController.java +++ b/services/core/java/com/android/server/wm/RecentsAnimationController.java @@ -213,6 +213,26 @@ public class RecentsAnimationController implements DeathRecipient { } } + @Override + public void setFinishTaskBounds(int taskId, Rect destinationBounds) { + ProtoLog.d(WM_DEBUG_RECENTS_ANIMATIONS, + "setFinishTaskBounds(%d): bounds=%s", taskId, destinationBounds); + final long token = Binder.clearCallingIdentity(); + try { + synchronized (mService.getWindowManagerLock()) { + for (int i = mPendingAnimations.size() - 1; i >= 0; i--) { + final TaskAnimationAdapter taskAdapter = mPendingAnimations.get(i); + if (taskAdapter.mTask.mTaskId == taskId) { + taskAdapter.mFinishBounds.set(destinationBounds); + break; + } + } + } + } finally { + Binder.restoreCallingIdentity(token); + } + } + @Override public void finish(boolean moveHomeToTop, boolean sendUserLeaveHint) { ProtoLog.d(WM_DEBUG_RECENTS_ANIMATIONS, @@ -739,6 +759,7 @@ public class RecentsAnimationController implements DeathRecipient { taskAdapter.mTask.dontAnimateDimExit(); } removeAnimation(taskAdapter); + taskAdapter.maybeApplyFinishBounds(); } for (int i = mPendingWallpaperAnimations.size() - 1; i >= 0; i--) { @@ -925,7 +946,9 @@ public class RecentsAnimationController implements DeathRecipient { private RemoteAnimationTarget mTarget; private final Rect mBounds = new Rect(); // The bounds of the target relative to its parent. - private Rect mLocalBounds = new Rect(); + private final Rect mLocalBounds = new Rect(); + // The bounds of the target when animation is finished + private final Rect mFinishBounds = new Rect(); TaskAnimationAdapter(Task task, boolean isRecentTaskInvisible) { mTask = task; @@ -960,6 +983,17 @@ public class RecentsAnimationController implements DeathRecipient { return mTarget; } + void maybeApplyFinishBounds() { + if (!mFinishBounds.isEmpty()) { + final SurfaceControl taskSurface = mTask.getSurfaceControl(); + mTask.getPendingTransaction() + .setPosition(taskSurface, mFinishBounds.left, mFinishBounds.top) + .setWindowCrop(taskSurface, mFinishBounds.width(), mFinishBounds.height()) + .apply(); + mFinishBounds.setEmpty(); + } + } + @Override public boolean getShowWallpaper() { return false; @@ -1005,6 +1039,7 @@ public class RecentsAnimationController implements DeathRecipient { } pw.println("mIsRecentTaskInvisible=" + mIsRecentTaskInvisible); pw.println("mLocalBounds=" + mLocalBounds); + pw.println("mFinishBounds=" + mFinishBounds); pw.println("mBounds=" + mBounds); pw.println("mIsRecentTaskInvisible=" + mIsRecentTaskInvisible); }