From 51d1d7c1d95dbdf70367b02e49ef37c00e75eb88 Mon Sep 17 00:00:00 2001 From: Ben Lin Date: Fri, 5 Feb 2021 14:57:36 -0800 Subject: [PATCH 1/2] PiP: Implement expand transition. Video: http://recall/-/gu5DjQFZPMFpwgaXdl4cV3/hJhcmBJWGG3IHgn6Vw9Xoa Bug: 165793917 Test: Exit PiP with ENABLE_SHELL_TRANSITIONS flag on Change-Id: I669919d44df2b1954ce3cbce9328faf10c24171f --- .../wm/shell/pip/PipTaskOrganizer.java | 5 +++ .../android/wm/shell/pip/PipTransition.java | 33 +++++++++++++++++++ .../wm/shell/pip/PipTransitionController.java | 10 ++++++ .../wm/shell/transition/Transitions.java | 3 ++ 4 files changed, 51 insertions(+) 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 00494611420d3..ee0a1b3e34877 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 @@ -423,6 +423,11 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener, // Set the exiting state first so if there is fixed rotation later, the running animation // won't be interrupted by alpha animation for existing PiP. mState = State.EXITING_PIP; + + if (Transitions.ENABLE_SHELL_TRANSITIONS) { + mPipTransitionController.startTransition(destinationBounds, wct); + return; + } mSyncTransactionQueue.queue(wct); mSyncTransactionQueue.runInSync(t -> { // Make sure to grab the latest source hint rect as it could have been diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransition.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransition.java index 88ee9c9ef7ed5..7581dfaaa1103 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransition.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransition.java @@ -25,6 +25,7 @@ import static com.android.wm.shell.pip.PipAnimationController.TRANSITION_DIRECTI import static com.android.wm.shell.pip.PipAnimationController.TRANSITION_DIRECTION_TO_PIP; import static com.android.wm.shell.pip.PipAnimationController.isInPipDirection; import static com.android.wm.shell.pip.PipAnimationController.isOutPipDirection; +import static com.android.wm.shell.transition.Transitions.TRANSIT_EXIT_PIP; import android.app.TaskInfo; import android.content.Context; @@ -53,6 +54,7 @@ public class PipTransition extends PipTransitionController { private final int mEnterExitAnimationDuration; private @PipAnimationController.AnimationType int mOneShotAnimationType = ANIM_TYPE_BOUNDS; private Transitions.TransitionFinishCallback mFinishCallback; + private Rect mExitDestinationBounds = new Rect(); public PipTransition(Context context, PipBoundsState pipBoundsState, PipMenuController pipMenuController, @@ -66,12 +68,28 @@ public class PipTransition extends PipTransitionController { .getInteger(R.integer.config_pipResizeAnimationDuration); } + @Override + public void startTransition(Rect destinationBounds, WindowContainerTransaction out) { + mExitDestinationBounds.set(destinationBounds); + mTransitions.startTransition(TRANSIT_EXIT_PIP, out, this); + } + @Override public boolean startAnimation(@android.annotation.NonNull IBinder transition, @android.annotation.NonNull TransitionInfo info, @android.annotation.NonNull SurfaceControl.Transaction startTransaction, @android.annotation.NonNull SurfaceControl.Transaction finishTransaction, @android.annotation.NonNull Transitions.TransitionFinishCallback finishCallback) { + + if (info.getType() == TRANSIT_EXIT_PIP && info.getChanges().size() == 1) { + final TransitionInfo.Change change = info.getChanges().get(0); + mFinishCallback = finishCallback; + boolean success = startExpandAnimation(change.getTaskInfo(), change.getLeash(), + new Rect(mExitDestinationBounds)); + mExitDestinationBounds.setEmpty(); + return success; + } + for (int i = info.getChanges().size() - 1; i >= 0; --i) { final TransitionInfo.Change change = info.getChanges().get(i); if (change.getTaskInfo() != null @@ -109,6 +127,21 @@ public class PipTransition extends PipTransitionController { finishResizeForMenu(destinationBounds); } + private boolean startExpandAnimation(final TaskInfo taskInfo, final SurfaceControl leash, + final Rect destinationBounds) { + PipAnimationController.PipTransitionAnimator animator = + mPipAnimationController.getAnimator(taskInfo, leash, mPipBoundsState.getBounds(), + mPipBoundsState.getBounds(), destinationBounds, null, + TRANSITION_DIRECTION_LEAVE_PIP, 0 /* startingAngle */, Surface.ROTATION_0); + + animator.setTransitionDirection(TRANSITION_DIRECTION_LEAVE_PIP) + .setPipAnimationCallback(mPipAnimationCallback) + .setDuration(mEnterExitAnimationDuration) + .start(); + + return true; + } + private boolean startEnterAnimation(final TaskInfo taskInfo, final SurfaceControl leash, final SurfaceControl.Transaction startTransaction, final SurfaceControl.Transaction finishTransaction) { diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransitionController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransitionController.java index d801c918973a9..bc262560844df 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransitionController.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransitionController.java @@ -29,6 +29,7 @@ import android.graphics.Rect; import android.os.Handler; import android.os.Looper; import android.view.SurfaceControl; +import android.window.WindowContainerTransaction; import com.android.wm.shell.ShellTaskOrganizer; import com.android.wm.shell.transition.Transitions; @@ -46,6 +47,7 @@ public abstract class PipTransitionController implements Transitions.TransitionH protected final PipBoundsState mPipBoundsState; protected final ShellTaskOrganizer mShellTaskOrganizer; protected final PipMenuController mPipMenuController; + protected final Transitions mTransitions; private final Handler mMainHandler; private final List mPipTransitionCallbacks = new ArrayList<>(); @@ -98,6 +100,13 @@ public abstract class PipTransitionController implements Transitions.TransitionH SurfaceControl.Transaction tx) { } + /** + * Called when the Shell wants to starts a transition/animation. + */ + public void startTransition(Rect destinationBounds, WindowContainerTransaction out) { + // Default implementation does nothing. + } + public PipTransitionController(PipBoundsState pipBoundsState, PipMenuController pipMenuController, PipBoundsAlgorithm pipBoundsAlgorithm, PipAnimationController pipAnimationController, Transitions transitions, @@ -107,6 +116,7 @@ public abstract class PipTransitionController implements Transitions.TransitionH mShellTaskOrganizer = shellTaskOrganizer; mPipBoundsAlgorithm = pipBoundsAlgorithm; mPipAnimationController = pipAnimationController; + mTransitions = transitions; mMainHandler = new Handler(Looper.getMainLooper()); if (Transitions.ENABLE_SHELL_TRANSITIONS) { transitions.addHandler(this); diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/Transitions.java b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/Transitions.java index 81309431f3962..64faed2061091 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/Transitions.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/Transitions.java @@ -77,6 +77,9 @@ public class Transitions implements RemoteCallable { /** Transition type for launching 2 tasks simultaneously. */ public static final int TRANSIT_SPLIT_SCREEN_PAIR_OPEN = TRANSIT_FIRST_CUSTOM + 2; + /** Transition type for exiting PIP via the Shell, either via Expand or Dismiss. */ + public static final int TRANSIT_EXIT_PIP = TRANSIT_FIRST_CUSTOM + 3; + private final WindowOrganizer mOrganizer; private final Context mContext; private final ShellExecutor mMainExecutor; From d9e72a7b3409d2a6cb0ceac89b2423e70cc54c7f Mon Sep 17 00:00:00 2001 From: Ben Lin Date: Thu, 20 May 2021 16:35:12 -0700 Subject: [PATCH 2/2] PiP: Show the wallpaper as part of the transition. This is usually taken care by RemoteAnimation, but since PiP takes control of the entire thing that is no longer the case. So let's just handle it. Bug: 165793917 Test: Enter PiP with ENABLE_SHELL_TRANSITIONS flag on Change-Id: I8f0af4472c20016f856f33f903bd9a431cd5ef3a --- .../android/wm/shell/pip/PipTransition.java | 26 +++++++++++++++---- 1 file changed, 21 insertions(+), 5 deletions(-) diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransition.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransition.java index 7581dfaaa1103..9d21e55106c36 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransition.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransition.java @@ -18,6 +18,7 @@ package com.android.wm.shell.pip; import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED; import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED; +import static android.window.TransitionInfo.FLAG_IS_WALLPAPER; import static com.android.wm.shell.pip.PipAnimationController.ANIM_TYPE_ALPHA; import static com.android.wm.shell.pip.PipAnimationController.ANIM_TYPE_BOUNDS; @@ -90,17 +91,32 @@ public class PipTransition extends PipTransitionController { return success; } + // Search for an Enter PiP transition (along with a show wallpaper one) + TransitionInfo.Change enterPip = null; + TransitionInfo.Change wallpaper = null; for (int i = info.getChanges().size() - 1; i >= 0; --i) { final TransitionInfo.Change change = info.getChanges().get(i); if (change.getTaskInfo() != null && change.getTaskInfo().configuration.windowConfiguration.getWindowingMode() == WINDOWING_MODE_PINNED) { - mFinishCallback = finishCallback; - return startEnterAnimation(change.getTaskInfo(), change.getLeash(), - startTransaction, finishTransaction); + enterPip = change; + } else if ((change.getFlags() & FLAG_IS_WALLPAPER) != 0) { + wallpaper = change; } } - return false; + if (enterPip == null) { + return false; + } + + // Show the wallpaper if there is a wallpaper change. + if (wallpaper != null) { + startTransaction.show(wallpaper.getLeash()); + startTransaction.setAlpha(wallpaper.getLeash(), 1.f); + } + + mFinishCallback = finishCallback; + return startEnterAnimation(enterPip.getTaskInfo(), enterPip.getLeash(), + startTransaction, finishTransaction); } @Nullable @@ -160,7 +176,6 @@ public class PipTransition extends PipTransitionController { 0 /* startingAngle */, Surface.ROTATION_0); } else if (mOneShotAnimationType == ANIM_TYPE_ALPHA) { startTransaction.setAlpha(leash, 0f); - startTransaction.apply(); animator = mPipAnimationController.getAnimator(taskInfo, leash, destinationBounds, 0f, 1f); mOneShotAnimationType = ANIM_TYPE_BOUNDS; @@ -168,6 +183,7 @@ public class PipTransition extends PipTransitionController { throw new RuntimeException("Unrecognized animation type: " + mOneShotAnimationType); } + startTransaction.apply(); animator.setTransitionDirection(TRANSITION_DIRECTION_TO_PIP) .setPipAnimationCallback(mPipAnimationCallback) .setDuration(mEnterExitAnimationDuration)