diff options
5 files changed, 107 insertions, 12 deletions
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/pip/PipDisplayLayoutState.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/pip/PipDisplayLayoutState.java index ed42117a55af..d5e47187dac2 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/pip/PipDisplayLayoutState.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/pip/PipDisplayLayoutState.java @@ -115,6 +115,12 @@ public class PipDisplayLayoutState { mDisplayLayout.rotateTo(mContext.getResources(), targetRotation); } + /** Returns the current display rotation of this layout state. */ + @Surface.Rotation + public int getRotation() { + return mDisplayLayout.rotation(); + } + /** Get the current display id */ public int getDisplayId() { return mDisplayId; 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 3c7713d30714..c7f693d8de50 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 @@ -286,6 +286,12 @@ public class PipTransition extends PipTransitionController { // Entering PIP. if (isEnteringPip(info)) { + if (handleEnteringPipWithDisplayChange(transition, info, startTransaction, + finishTransaction, finishCallback)) { + // The destination position is applied directly and let default transition handler + // run the display change animation. + return true; + } startEnterAnimation(info, startTransaction, finishTransaction, finishCallback); return true; } @@ -300,6 +306,25 @@ public class PipTransition extends PipTransitionController { return false; } + private boolean handleEnteringPipWithDisplayChange(@NonNull IBinder transition, + @NonNull TransitionInfo info, @NonNull SurfaceControl.Transaction startT, + @NonNull SurfaceControl.Transaction finishT, + @NonNull Transitions.TransitionFinishCallback finishCallback) { + if (mFixedRotationState != FIXED_ROTATION_UNDEFINED + || !TransitionUtil.hasDisplayChange(info)) { + return false; + } + final TransitionInfo.Change pipChange = getPipChange(info); + if (pipChange == null) { + return false; + } + ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE, + "%s: handle entering PiP with display change", TAG); + mMixedHandler.animateEnteringPipWithDisplayChange(transition, info, pipChange, + startT, finishT, finishCallback); + return true; + } + @Override public void mergeAnimation(@NonNull IBinder transition, @NonNull TransitionInfo info, @NonNull SurfaceControl.Transaction t, @NonNull IBinder mergeTarget, @@ -882,19 +907,24 @@ public class PipTransition extends PipTransitionController { mEnterAnimationType = type; } - private void startEnterAnimation(@NonNull TransitionInfo info, - @NonNull SurfaceControl.Transaction startTransaction, - @NonNull SurfaceControl.Transaction finishTransaction, - @NonNull Transitions.TransitionFinishCallback finishCallback) { - // Search for an Enter PiP transition - TransitionInfo.Change enterPip = null; + @Nullable + private static TransitionInfo.Change getPipChange(@NonNull TransitionInfo info) { for (int i = info.getChanges().size() - 1; i >= 0; --i) { final TransitionInfo.Change change = info.getChanges().get(i); if (change.getTaskInfo() != null && change.getTaskInfo().getWindowingMode() == WINDOWING_MODE_PINNED) { - enterPip = change; + return change; } } + return null; + } + + private void startEnterAnimation(@NonNull TransitionInfo info, + @NonNull SurfaceControl.Transaction startTransaction, + @NonNull SurfaceControl.Transaction finishTransaction, + @NonNull Transitions.TransitionFinishCallback finishCallback) { + // Search for an Enter PiP transition + final TransitionInfo.Change enterPip = getPipChange(info); if (enterPip == null) { throw new IllegalStateException("Trying to start PiP animation without a pip" + "participant"); @@ -968,8 +998,8 @@ public class PipTransition extends PipTransitionController { Rect sourceHintRect = PipBoundsAlgorithm.getValidSourceHintRect( taskInfo.pictureInPictureParams, currentBounds, destinationBounds); if (rotationDelta != Surface.ROTATION_0 - && mFixedRotationState == FIXED_ROTATION_TRANSITION) { - // Need to get the bounds of new rotation in old rotation for fixed rotation, + && endRotation != mPipDisplayLayoutState.getRotation()) { + // Computes the destination bounds in new rotation. computeEnterPipRotatedBounds(rotationDelta, startRotation, endRotation, taskInfo, destinationBounds, sourceHintRect); } @@ -1061,8 +1091,11 @@ public class PipTransition extends PipTransitionController { final Rect displayBounds = mPipDisplayLayoutState.getDisplayBounds(); outDestinationBounds.set(mPipBoundsAlgorithm.getEntryDestinationBounds()); - // Transform the destination bounds to current display coordinates. - rotateBounds(outDestinationBounds, displayBounds, endRotation, startRotation); + if (mFixedRotationState == FIXED_ROTATION_TRANSITION) { + // Transform the destination bounds to current display coordinates. + // With fixed rotation, the bounds of new rotation shows in old rotation. + rotateBounds(outDestinationBounds, displayBounds, endRotation, startRotation); + } // When entering PiP (from button navigation mode), adjust the source rect hint by // display cutout if applicable. if (outSourceHintRect != null && taskInfo.displayCutoutInsets != null) { 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 7730285c86c8..1d1a4e2be3e4 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 @@ -49,6 +49,7 @@ import com.android.wm.shell.common.pip.PipMenuController; import com.android.wm.shell.common.split.SplitScreenUtils; import com.android.wm.shell.protolog.ShellProtoLogGroup; import com.android.wm.shell.sysui.ShellInit; +import com.android.wm.shell.transition.DefaultMixedHandler; import com.android.wm.shell.transition.Transitions; import java.io.PrintWriter; @@ -67,6 +68,7 @@ public abstract class PipTransitionController implements Transitions.TransitionH protected final Transitions mTransitions; private final List<PipTransitionCallback> mPipTransitionCallbacks = new ArrayList<>(); protected PipTaskOrganizer mPipOrganizer; + protected DefaultMixedHandler mMixedHandler; protected final PipAnimationController.PipAnimationCallback mPipAnimationCallback = new PipAnimationController.PipAnimationCallback() { @@ -168,6 +170,14 @@ public abstract class PipTransitionController implements Transitions.TransitionH mPipOrganizer = pto; } + public void setMixedHandler(DefaultMixedHandler mixedHandler) { + mMixedHandler = mixedHandler; + } + + public void applyTransaction(WindowContainerTransaction wct) { + mShellTaskOrganizer.applyTransaction(wct); + } + /** * Registers {@link PipTransitionCallback} to receive transition callbacks. */ diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultMixedHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultMixedHandler.java index bcacecbd8981..8ee1efa90a30 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultMixedHandler.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultMixedHandler.java @@ -107,6 +107,9 @@ public class DefaultMixedHandler implements MixedTransitionHandler, /** Entering Pip from split, but replace the Pip stage instead of breaking split. */ static final int TYPE_ENTER_PIP_REPLACE_FROM_SPLIT = 10; + /** The display changes when pip is entering. */ + static final int TYPE_ENTER_PIP_WITH_DISPLAY_CHANGE = 11; + /** The default animation for this mixed transition. */ static final int ANIM_TYPE_DEFAULT = 0; @@ -233,6 +236,7 @@ public class DefaultMixedHandler implements MixedTransitionHandler, // Add after dependencies because it is higher priority shellInit.addInitCallback(() -> { mPipHandler = pipTransitionController; + pipTransitionController.setMixedHandler(this); mSplitHandler = splitScreenControllerOptional.get().getTransitionHandler(); mPlayer.addHandler(this); if (mSplitHandler != null) { @@ -550,6 +554,47 @@ public class DefaultMixedHandler implements MixedTransitionHandler, return true; } + /** + * For example: pip is entering in rotation 0, and then the display changes to rotation 90 + * before the pip transition is ready. So the info contains both the entering pip and display + * change. In this case, the pip can go to the end state in new rotation directly, and let the + * display level animation cover all changed participates. + */ + public void animateEnteringPipWithDisplayChange(@NonNull IBinder transition, + @NonNull TransitionInfo info, @NonNull TransitionInfo.Change pipChange, + @NonNull SurfaceControl.Transaction startT, + @NonNull SurfaceControl.Transaction finishT, + @NonNull Transitions.TransitionFinishCallback finishCallback) { + // In order to play display level animation, force the type to CHANGE (it could be PIP). + final TransitionInfo changeInfo = info.getType() != TRANSIT_CHANGE + ? subCopy(info, TRANSIT_CHANGE, true /* withChanges */) : info; + final MixedTransition mixed = createDefaultMixedTransition( + MixedTransition.TYPE_ENTER_PIP_WITH_DISPLAY_CHANGE, transition); + mActiveTransitions.add(mixed); + mixed.mInFlightSubAnimations = 2; + final Transitions.TransitionFinishCallback finishCB = wct -> { + --mixed.mInFlightSubAnimations; + mixed.joinFinishArgs(wct); + if (mixed.mInFlightSubAnimations > 0) return; + mActiveTransitions.remove(mixed); + finishCallback.onTransitionFinished(mixed.mFinishWCT); + }; + // Perform the display animation first. + mixed.mLeftoversHandler = mPlayer.dispatchTransition(mixed.mTransition, changeInfo, + startT, finishT, finishCB, mPipHandler); + // Use a standalone finish transaction for pip because it will apply immediately. + final SurfaceControl.Transaction pipFinishT = new SurfaceControl.Transaction(); + mPipHandler.startEnterAnimation(pipChange, startT, pipFinishT, wct -> { + // Apply immediately to avoid potential flickering by bounds change at the end of + // display animation. + mPipHandler.applyTransaction(wct); + finishCB.onTransitionFinished(null /* wct */); + }); + // Jump to the pip end state directly and make sure the real finishT have the latest state. + mPipHandler.end(); + mPipHandler.syncPipSurfaceState(info, startT, finishT); + } + private static boolean animateKeyguard(@NonNull final MixedTransition mixed, @NonNull TransitionInfo info, @NonNull SurfaceControl.Transaction startTransaction, diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultMixedTransition.java b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultMixedTransition.java index 0ada74937df4..c33fb80fdefc 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultMixedTransition.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultMixedTransition.java @@ -70,7 +70,7 @@ class DefaultMixedTransition extends DefaultMixedHandler.MixedTransition { @NonNull SurfaceControl.Transaction finishTransaction, @NonNull Transitions.TransitionFinishCallback finishCallback) { return switch (mType) { - case TYPE_DISPLAY_AND_SPLIT_CHANGE -> false; + case TYPE_DISPLAY_AND_SPLIT_CHANGE, TYPE_ENTER_PIP_WITH_DISPLAY_CHANGE -> false; case TYPE_ENTER_PIP_FROM_ACTIVITY_EMBEDDING -> animateEnterPipFromActivityEmbedding( info, startTransaction, finishTransaction, finishCallback); @@ -253,6 +253,7 @@ class DefaultMixedTransition extends DefaultMixedHandler.MixedTransition { @NonNull Transitions.TransitionFinishCallback finishCallback) { switch (mType) { case TYPE_DISPLAY_AND_SPLIT_CHANGE: + case TYPE_ENTER_PIP_WITH_DISPLAY_CHANGE: // queue since no actual animation. return; case TYPE_ENTER_PIP_FROM_ACTIVITY_EMBEDDING: |