Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit eb8ca0d7 authored by Chris Li's avatar Chris Li
Browse files

Fixed rotation for entering PIP with Shell transition

Entering PIP rotation with orientation is changed to use fixed rotation,
so we need to update the animation as well.

Will update exiting PIP and swipe to enter in next cl

Bug: 219411429
Test: manual test enter PIP from different orientation
Change-Id: Id30f15c72b7d59ae63012d9f62e829d73ec4f335
parent fe197a7d
Loading
Loading
Loading
Loading
+23 −3
Original line number Original line Diff line number Diff line
@@ -364,8 +364,13 @@ public final class TransitionInfo implements Parcelable {
        private final Point mEndRelOffset = new Point();
        private final Point mEndRelOffset = new Point();
        private ActivityManager.RunningTaskInfo mTaskInfo = null;
        private ActivityManager.RunningTaskInfo mTaskInfo = null;
        private boolean mAllowEnterPip;
        private boolean mAllowEnterPip;
        private int mStartRotation = ROTATION_UNDEFINED;
        private @Surface.Rotation int mStartRotation = ROTATION_UNDEFINED;
        private int mEndRotation = ROTATION_UNDEFINED;
        private @Surface.Rotation int mEndRotation = ROTATION_UNDEFINED;
        /**
         * The end rotation of the top activity after fixed rotation is finished. If the top
         * activity is not in fixed rotation, it will be {@link ROTATION_UNDEFINED}.
         */
        private @Surface.Rotation int mEndFixedRotation = ROTATION_UNDEFINED;
        private int mRotationAnimation = ROTATION_ANIMATION_UNSPECIFIED;
        private int mRotationAnimation = ROTATION_ANIMATION_UNSPECIFIED;
        private @ColorInt int mBackgroundColor;
        private @ColorInt int mBackgroundColor;


@@ -388,6 +393,7 @@ public final class TransitionInfo implements Parcelable {
            mAllowEnterPip = in.readBoolean();
            mAllowEnterPip = in.readBoolean();
            mStartRotation = in.readInt();
            mStartRotation = in.readInt();
            mEndRotation = in.readInt();
            mEndRotation = in.readInt();
            mEndFixedRotation = in.readInt();
            mRotationAnimation = in.readInt();
            mRotationAnimation = in.readInt();
            mBackgroundColor = in.readInt();
            mBackgroundColor = in.readInt();
        }
        }
@@ -441,6 +447,11 @@ public final class TransitionInfo implements Parcelable {
            mEndRotation = end;
            mEndRotation = end;
        }
        }


        /** Sets end rotation that top activity will be launched to after fixed rotation. */
        public void setEndFixedRotation(@Surface.Rotation int endFixedRotation) {
            mEndFixedRotation = endFixedRotation;
        }

        /**
        /**
         * Sets the app-requested animation type for rotation. Will be one of the
         * Sets the app-requested animation type for rotation. Will be one of the
         * ROTATION_ANIMATION_ values in {@link android.view.WindowManager.LayoutParams};
         * ROTATION_ANIMATION_ values in {@link android.view.WindowManager.LayoutParams};
@@ -521,14 +532,21 @@ public final class TransitionInfo implements Parcelable {
            return mAllowEnterPip;
            return mAllowEnterPip;
        }
        }


        @Surface.Rotation
        public int getStartRotation() {
        public int getStartRotation() {
            return mStartRotation;
            return mStartRotation;
        }
        }


        @Surface.Rotation
        public int getEndRotation() {
        public int getEndRotation() {
            return mEndRotation;
            return mEndRotation;
        }
        }


        @Surface.Rotation
        public int getEndFixedRotation() {
            return mEndFixedRotation;
        }

        /** @return the rotation animation. */
        /** @return the rotation animation. */
        public int getRotationAnimation() {
        public int getRotationAnimation() {
            return mRotationAnimation;
            return mRotationAnimation;
@@ -555,6 +573,7 @@ public final class TransitionInfo implements Parcelable {
            dest.writeBoolean(mAllowEnterPip);
            dest.writeBoolean(mAllowEnterPip);
            dest.writeInt(mStartRotation);
            dest.writeInt(mStartRotation);
            dest.writeInt(mEndRotation);
            dest.writeInt(mEndRotation);
            dest.writeInt(mEndFixedRotation);
            dest.writeInt(mRotationAnimation);
            dest.writeInt(mRotationAnimation);
            dest.writeInt(mBackgroundColor);
            dest.writeInt(mBackgroundColor);
        }
        }
@@ -584,7 +603,8 @@ public final class TransitionInfo implements Parcelable {
            return "{" + mContainer + "(" + mParent + ") leash=" + mLeash
            return "{" + mContainer + "(" + mParent + ") leash=" + mLeash
                    + " m=" + modeToString(mMode) + " f=" + flagsToString(mFlags) + " sb="
                    + " m=" + modeToString(mMode) + " f=" + flagsToString(mFlags) + " sb="
                    + mStartAbsBounds + " eb=" + mEndAbsBounds + " eo=" + mEndRelOffset + " r="
                    + mStartAbsBounds + " eb=" + mEndAbsBounds + " eo=" + mEndRelOffset + " r="
                    + mStartRotation + "->" + mEndRotation + ":" + mRotationAnimation + "}";
                    + mStartRotation + "->" + mEndRotation + ":" + mRotationAnimation
                    + " endFixedRotation=" + mEndFixedRotation + "}";
        }
        }
    }
    }


+21 −9
Original line number Original line Diff line number Diff line
@@ -563,6 +563,13 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener,
            Log.d(TAG, "Alpha animation is expired. Use bounds animation.");
            Log.d(TAG, "Alpha animation is expired. Use bounds animation.");
            mOneShotAnimationType = ANIM_TYPE_BOUNDS;
            mOneShotAnimationType = ANIM_TYPE_BOUNDS;
        }
        }

        if (Transitions.ENABLE_SHELL_TRANSITIONS) {
            // For Shell transition, we will animate the window in PipTransition#startAnimation
            // instead of #onTaskAppeared.
            return;
        }

        if (mWaitForFixedRotation) {
        if (mWaitForFixedRotation) {
            onTaskAppearedWithFixedRotation();
            onTaskAppearedWithFixedRotation();
            return;
            return;
@@ -572,15 +579,6 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener,
        Objects.requireNonNull(destinationBounds, "Missing destination bounds");
        Objects.requireNonNull(destinationBounds, "Missing destination bounds");
        final Rect currentBounds = mTaskInfo.configuration.windowConfiguration.getBounds();
        final Rect currentBounds = mTaskInfo.configuration.windowConfiguration.getBounds();


        if (Transitions.ENABLE_SHELL_TRANSITIONS) {
            if (mOneShotAnimationType == ANIM_TYPE_BOUNDS) {
                mPipMenuController.attach(mLeash);
            } else if (mOneShotAnimationType == ANIM_TYPE_ALPHA) {
                mOneShotAnimationType = ANIM_TYPE_BOUNDS;
            }
            return;
        }

        if (mOneShotAnimationType == ANIM_TYPE_BOUNDS) {
        if (mOneShotAnimationType == ANIM_TYPE_BOUNDS) {
            mPipMenuController.attach(mLeash);
            mPipMenuController.attach(mLeash);
            final Rect sourceHintRect = PipBoundsAlgorithm.getValidSourceHintRect(
            final Rect sourceHintRect = PipBoundsAlgorithm.getValidSourceHintRect(
@@ -813,6 +811,16 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener,
        mNextRotation = newRotation;
        mNextRotation = newRotation;
        mWaitForFixedRotation = true;
        mWaitForFixedRotation = true;


        if (Transitions.ENABLE_SHELL_TRANSITIONS) {
            // The fixed rotation will also be included in the transition info. However, if it is
            // not a PIP transition (such as open another app to different orientation),
            // PIP transition handler may not be aware of the fixed rotation start.
            // Notify the PIP transition handler so that it can fade out the PIP window early for
            // fixed transition of other windows.
            mPipTransitionController.onFixedRotationStarted();
            return;
        }

        if (mPipTransitionState.isInPip()) {
        if (mPipTransitionState.isInPip()) {
            // Fade out the existing PiP to avoid jump cut during seamless rotation.
            // Fade out the existing PiP to avoid jump cut during seamless rotation.
            fadeExistingPip(false /* show */);
            fadeExistingPip(false /* show */);
@@ -824,6 +832,10 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener,
        if (!mWaitForFixedRotation) {
        if (!mWaitForFixedRotation) {
            return;
            return;
        }
        }
        if (Transitions.ENABLE_SHELL_TRANSITIONS) {
            clearWaitForFixedRotation();
            return;
        }
        if (mPipTransitionState.getTransitionState() == PipTransitionState.TASK_APPEARED) {
        if (mPipTransitionState.getTransitionState() == PipTransitionState.TASK_APPEARED) {
            if (mPipTransitionState.getInSwipePipToHomeTransition()) {
            if (mPipTransitionState.getInSwipePipToHomeTransition()) {
                onEndOfSwipePipToHomeTransition();
                onEndOfSwipePipToHomeTransition();
+150 −25
Original line number Original line Diff line number Diff line
@@ -16,6 +16,7 @@


package com.android.wm.shell.pip;
package com.android.wm.shell.pip;


import static android.app.WindowConfiguration.ROTATION_UNDEFINED;
import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
import static android.util.RotationUtils.deltaRotation;
import static android.util.RotationUtils.deltaRotation;
@@ -32,9 +33,11 @@ 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_ALPHA;
import static com.android.wm.shell.pip.PipAnimationController.ANIM_TYPE_BOUNDS;
import static com.android.wm.shell.pip.PipAnimationController.ANIM_TYPE_BOUNDS;
import static com.android.wm.shell.pip.PipAnimationController.TRANSITION_DIRECTION_LEAVE_PIP;
import static com.android.wm.shell.pip.PipAnimationController.TRANSITION_DIRECTION_LEAVE_PIP;
import static com.android.wm.shell.pip.PipAnimationController.TRANSITION_DIRECTION_SAME;
import static com.android.wm.shell.pip.PipAnimationController.TRANSITION_DIRECTION_TO_PIP;
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.isInPipDirection;
import static com.android.wm.shell.pip.PipAnimationController.isOutPipDirection;
import static com.android.wm.shell.pip.PipAnimationController.isOutPipDirection;
import static com.android.wm.shell.pip.PipTransitionState.ENTERED_PIP;
import static com.android.wm.shell.transition.Transitions.TRANSIT_EXIT_PIP;
import static com.android.wm.shell.transition.Transitions.TRANSIT_EXIT_PIP;
import static com.android.wm.shell.transition.Transitions.TRANSIT_EXIT_PIP_TO_SPLIT;
import static com.android.wm.shell.transition.Transitions.TRANSIT_EXIT_PIP_TO_SPLIT;
import static com.android.wm.shell.transition.Transitions.TRANSIT_REMOVE_PIP;
import static com.android.wm.shell.transition.Transitions.TRANSIT_REMOVE_PIP;
@@ -47,6 +50,7 @@ import android.graphics.Matrix;
import android.graphics.Point;
import android.graphics.Point;
import android.graphics.Rect;
import android.graphics.Rect;
import android.os.IBinder;
import android.os.IBinder;
import android.util.Log;
import android.view.Surface;
import android.view.Surface;
import android.view.SurfaceControl;
import android.view.SurfaceControl;
import android.window.TransitionInfo;
import android.window.TransitionInfo;
@@ -86,6 +90,16 @@ public class PipTransition extends PipTransitionController {
    /** The Task window that is currently in PIP windowing mode. */
    /** The Task window that is currently in PIP windowing mode. */
    @Nullable
    @Nullable
    private WindowContainerToken mCurrentPipTaskToken;
    private WindowContainerToken mCurrentPipTaskToken;
    /** Whether display is in fixed rotation. */
    private boolean mInFixedRotation;
    /**
     * The rotation that the display will apply after expanding PiP to fullscreen. This is only
     * meaningful if {@link #mInFixedRotation} is true.
     */
    @Surface.Rotation
    private int mFixedRotation;
    /** Whether the PIP window has fade out for fixed rotation. */
    private boolean mHasFadeOut;


    public PipTransition(Context context,
    public PipTransition(Context context,
            PipBoundsState pipBoundsState,
            PipBoundsState pipBoundsState,
@@ -136,35 +150,41 @@ public class PipTransition extends PipTransitionController {
            @NonNull SurfaceControl.Transaction startTransaction,
            @NonNull SurfaceControl.Transaction startTransaction,
            @NonNull SurfaceControl.Transaction finishTransaction,
            @NonNull SurfaceControl.Transaction finishTransaction,
            @NonNull Transitions.TransitionFinishCallback finishCallback) {
            @NonNull Transitions.TransitionFinishCallback finishCallback) {
        final TransitionInfo.Change currentPipChange = findCurrentPipChange(info);
        final TransitionInfo.Change fixedRotationChange = findFixedRotationChange(info);
        mInFixedRotation = fixedRotationChange != null;
        mFixedRotation = mInFixedRotation
                ? fixedRotationChange.getEndFixedRotation()
                : ROTATION_UNDEFINED;

        // Exiting PIP.
        // Exiting PIP.
        final int type = info.getType();
        final int type = info.getType();
        if (transition.equals(mExitTransition)) {
        if (transition.equals(mExitTransition)) {
            mExitDestinationBounds.setEmpty();
            mExitDestinationBounds.setEmpty();
            mExitTransition = null;
            mExitTransition = null;

            mHasFadeOut = false;
            if (mFinishCallback != null) {
            if (mFinishCallback != null) {
                mFinishCallback.onTransitionFinished(null, null);
                mFinishCallback.onTransitionFinished(null, null);
                mFinishCallback = null;
                mFinishCallback = null;
                throw new RuntimeException("Previous callback not called, aborting exit PIP.");
                throw new RuntimeException("Previous callback not called, aborting exit PIP.");
            }
            }


            final TransitionInfo.Change exitPipChange = findCurrentPipChange(info);
            if (currentPipChange == null) {
            if (exitPipChange == null) {
                throw new RuntimeException("Cannot find the pip window for exit-pip transition.");
                throw new RuntimeException("Cannot find the pip window for exit-pip transition.");
            }
            }


            switch (type) {
            switch (type) {
                case TRANSIT_EXIT_PIP:
                case TRANSIT_EXIT_PIP:
                    startExitAnimation(info, startTransaction, finishTransaction, finishCallback,
                    startExitAnimation(info, startTransaction, finishTransaction, finishCallback,
                            exitPipChange);
                            currentPipChange);
                    break;
                    break;
                case TRANSIT_EXIT_PIP_TO_SPLIT:
                case TRANSIT_EXIT_PIP_TO_SPLIT:
                    startExitToSplitAnimation(info, startTransaction, finishTransaction,
                    startExitToSplitAnimation(info, startTransaction, finishTransaction,
                            finishCallback, exitPipChange);
                            finishCallback, currentPipChange);
                    break;
                    break;
                case TRANSIT_REMOVE_PIP:
                case TRANSIT_REMOVE_PIP:
                    removePipImmediately(info, startTransaction, finishTransaction, finishCallback,
                    removePipImmediately(info, startTransaction, finishTransaction, finishCallback,
                            exitPipChange);
                            currentPipChange);
                    break;
                    break;
                default:
                default:
                    throw new IllegalStateException("mExitTransition with unexpected transit type="
                    throw new IllegalStateException("mExitTransition with unexpected transit type="
@@ -177,7 +197,6 @@ public class PipTransition extends PipTransitionController {
        // The previous PIP Task is no longer in PIP, but this is not an exit transition (This can
        // The previous PIP Task is no longer in PIP, but this is not an exit transition (This can
        // happen when a new activity requests enter PIP). In this case, we just show this Task in
        // happen when a new activity requests enter PIP). In this case, we just show this Task in
        // its end state, and play other animation as normal.
        // its end state, and play other animation as normal.
        final TransitionInfo.Change currentPipChange = findCurrentPipChange(info);
        if (currentPipChange != null
        if (currentPipChange != null
                && currentPipChange.getTaskInfo().getWindowingMode() != WINDOWING_MODE_PINNED) {
                && currentPipChange.getTaskInfo().getWindowingMode() != WINDOWING_MODE_PINNED) {
            resetPrevPip(currentPipChange, startTransaction);
            resetPrevPip(currentPipChange, startTransaction);
@@ -193,6 +212,12 @@ public class PipTransition extends PipTransitionController {
        if (currentPipChange != null) {
        if (currentPipChange != null) {
            updatePipForUnhandledTransition(currentPipChange, startTransaction, finishTransaction);
            updatePipForUnhandledTransition(currentPipChange, startTransaction, finishTransaction);
        }
        }

        // Fade in the fadeout PIP when the fixed rotation is finished.
        if (mPipTransitionState.isInPip() && !mInFixedRotation && mHasFadeOut) {
            fadeExistingPip(true /* show */);
        }

        return false;
        return false;
    }
    }


@@ -242,9 +267,8 @@ public class PipTransition extends PipTransitionController {
    public void onFinishResize(TaskInfo taskInfo, Rect destinationBounds,
    public void onFinishResize(TaskInfo taskInfo, Rect destinationBounds,
            @PipAnimationController.TransitionDirection int direction,
            @PipAnimationController.TransitionDirection int direction,
            @Nullable SurfaceControl.Transaction tx) {
            @Nullable SurfaceControl.Transaction tx) {

        if (isInPipDirection(direction)) {
        if (isInPipDirection(direction)) {
            mPipTransitionState.setTransitionState(PipTransitionState.ENTERED_PIP);
            mPipTransitionState.setTransitionState(ENTERED_PIP);
        }
        }
        // If there is an expected exit transition, then the exit will be "merged" into this
        // If there is an expected exit transition, then the exit will be "merged" into this
        // transition so don't fire the finish-callback in that case.
        // transition so don't fire the finish-callback in that case.
@@ -268,6 +292,16 @@ public class PipTransition extends PipTransitionController {
        mFinishCallback = null;
        mFinishCallback = null;
    }
    }


    @Override
    public void onFixedRotationStarted() {
        // The transition with this fixed rotation may be handled by other handler before reaching
        // PipTransition, so we cannot do this in #startAnimation.
        if (mPipTransitionState.getTransitionState() == ENTERED_PIP && !mHasFadeOut) {
            // Fade out the existing PiP to avoid jump cut during seamless rotation.
            fadeExistingPip(false /* show */);
        }
    }

    @Nullable
    @Nullable
    private TransitionInfo.Change findCurrentPipChange(@NonNull TransitionInfo info) {
    private TransitionInfo.Change findCurrentPipChange(@NonNull TransitionInfo info) {
        if (mCurrentPipTaskToken == null) {
        if (mCurrentPipTaskToken == null) {
@@ -282,6 +316,17 @@ public class PipTransition extends PipTransitionController {
        return null;
        return null;
    }
    }


    @Nullable
    private TransitionInfo.Change findFixedRotationChange(@NonNull TransitionInfo info) {
        for (int i = info.getChanges().size() - 1; i >= 0; --i) {
            final TransitionInfo.Change change = info.getChanges().get(i);
            if (change.getEndFixedRotation() != ROTATION_UNDEFINED) {
                return change;
            }
        }
        return null;
    }

    private void startExitAnimation(@NonNull TransitionInfo info,
    private void startExitAnimation(@NonNull TransitionInfo info,
            @NonNull SurfaceControl.Transaction startTransaction,
            @NonNull SurfaceControl.Transaction startTransaction,
            @NonNull SurfaceControl.Transaction finishTransaction,
            @NonNull SurfaceControl.Transaction finishTransaction,
@@ -453,6 +498,7 @@ public class PipTransition extends PipTransitionController {
        }
        }
        // Keep track of the PIP task.
        // Keep track of the PIP task.
        mCurrentPipTaskToken = enterPip.getContainer();
        mCurrentPipTaskToken = enterPip.getContainer();
        mHasFadeOut = false;


        if (mFinishCallback != null) {
        if (mFinishCallback != null) {
            mFinishCallback.onTransitionFinished(null /* wct */, null /* callback */);
            mFinishCallback.onTransitionFinished(null /* wct */, null /* callback */);
@@ -465,12 +511,25 @@ public class PipTransition extends PipTransitionController {
            startTransaction.show(wallpaper.getLeash());
            startTransaction.show(wallpaper.getLeash());
            startTransaction.setAlpha(wallpaper.getLeash(), 1.f);
            startTransaction.setAlpha(wallpaper.getLeash(), 1.f);
        }
        }
        // Make sure other open changes are visible as entering PIP. Some may be hidden in
        // Transitions#setupStartState because the transition type is OPEN (such as auto-enter).
        for (int i = info.getChanges().size() - 1; i >= 0; --i) {
            final TransitionInfo.Change change = info.getChanges().get(i);
            if (change == enterPip || change == wallpaper) {
                continue;
            }
            if (isOpeningType(change.getMode())) {
                final SurfaceControl leash = change.getLeash();
                startTransaction.show(leash).setAlpha(leash, 1.f);
            }
        }


        mPipTransitionState.setTransitionState(PipTransitionState.ENTERING_PIP);
        mPipTransitionState.setTransitionState(PipTransitionState.ENTERING_PIP);
        mFinishCallback = finishCallback;
        mFinishCallback = finishCallback;
        final int endRotation = mInFixedRotation ? mFixedRotation : enterPip.getEndRotation();
        return startEnterAnimation(enterPip.getTaskInfo(), enterPip.getLeash(),
        return startEnterAnimation(enterPip.getTaskInfo(), enterPip.getLeash(),
                startTransaction, finishTransaction, enterPip.getStartRotation(),
                startTransaction, finishTransaction, enterPip.getStartRotation(),
                enterPip.getEndRotation());
                endRotation);
    }
    }


    private boolean startEnterAnimation(final TaskInfo taskInfo, final SurfaceControl leash,
    private boolean startEnterAnimation(final TaskInfo taskInfo, final SurfaceControl leash,
@@ -481,25 +540,36 @@ public class PipTransition extends PipTransitionController {
                taskInfo.topActivityInfo);
                taskInfo.topActivityInfo);
        final Rect destinationBounds = mPipBoundsAlgorithm.getEntryDestinationBounds();
        final Rect destinationBounds = mPipBoundsAlgorithm.getEntryDestinationBounds();
        final Rect currentBounds = taskInfo.configuration.windowConfiguration.getBounds();
        final Rect currentBounds = taskInfo.configuration.windowConfiguration.getBounds();
        int rotationDelta = deltaRotation(startRotation, endRotation);
        Rect sourceHintRect = PipBoundsAlgorithm.getValidSourceHintRect(
                taskInfo.pictureInPictureParams, currentBounds);
        if (rotationDelta != Surface.ROTATION_0 && mInFixedRotation) {
            // Need to get the bounds of new rotation in old rotation for fixed rotation,
            sourceHintRect = computeRotatedBounds(rotationDelta, startRotation, endRotation,
                    taskInfo, TRANSITION_DIRECTION_TO_PIP, destinationBounds, sourceHintRect);
        }
        PipAnimationController.PipTransitionAnimator animator;
        PipAnimationController.PipTransitionAnimator animator;
        // Set corner radius for entering pip.
        // Set corner radius for entering pip.
        mSurfaceTransactionHelper
        mSurfaceTransactionHelper
                .crop(finishTransaction, leash, destinationBounds)
                .crop(finishTransaction, leash, destinationBounds)
                .round(finishTransaction, leash, true /* applyCornerRadius */);
                .round(finishTransaction, leash, true /* applyCornerRadius */);
        mPipMenuController.attach(leash);

        if (taskInfo.pictureInPictureParams != null
        if (taskInfo.pictureInPictureParams != null
                && taskInfo.pictureInPictureParams.isAutoEnterEnabled()
                && taskInfo.pictureInPictureParams.isAutoEnterEnabled()
                && mPipTransitionState.getInSwipePipToHomeTransition()) {
                && mPipTransitionState.getInSwipePipToHomeTransition()) {
            mOneShotAnimationType = ANIM_TYPE_BOUNDS;
            mOneShotAnimationType = ANIM_TYPE_BOUNDS;

            // PiP menu is attached late in the process here to avoid any artifacts on the leash
            // caused by addShellRoot when in gesture navigation mode.
            mPipMenuController.attach(leash);
            SurfaceControl.Transaction tx = new SurfaceControl.Transaction();
            SurfaceControl.Transaction tx = new SurfaceControl.Transaction();
            tx.setMatrix(leash, Matrix.IDENTITY_MATRIX, new float[9])
            tx.setMatrix(leash, Matrix.IDENTITY_MATRIX, new float[9])
                    .setPosition(leash, destinationBounds.left, destinationBounds.top)
                    .setPosition(leash, destinationBounds.left, destinationBounds.top)
                    .setWindowCrop(leash, destinationBounds.width(), destinationBounds.height());
                    .setWindowCrop(leash, destinationBounds.width(), destinationBounds.height());
            startTransaction.merge(tx);
            startTransaction.merge(tx);
            startTransaction.apply();
            startTransaction.apply();
            if (rotationDelta != Surface.ROTATION_0 && mInFixedRotation) {
                // For fixed rotation, set the destination bounds to the new rotation coordinates
                // at the end.
                destinationBounds.set(mPipBoundsAlgorithm.getEntryDestinationBounds());
            }
            mPipBoundsState.setBounds(destinationBounds);
            mPipBoundsState.setBounds(destinationBounds);
            onFinishResize(taskInfo, destinationBounds, TRANSITION_DIRECTION_TO_PIP, null /* tx */);
            onFinishResize(taskInfo, destinationBounds, TRANSITION_DIRECTION_TO_PIP, null /* tx */);
            sendOnPipTransitionFinished(TRANSITION_DIRECTION_TO_PIP);
            sendOnPipTransitionFinished(TRANSITION_DIRECTION_TO_PIP);
@@ -507,17 +577,14 @@ public class PipTransition extends PipTransitionController {
            return true;
            return true;
        }
        }


        int rotationDelta = deltaRotation(endRotation, startRotation);
        if (rotationDelta != Surface.ROTATION_0) {
        if (rotationDelta != Surface.ROTATION_0) {
            Matrix tmpTransform = new Matrix();
            Matrix tmpTransform = new Matrix();
            tmpTransform.postRotate(rotationDelta == Surface.ROTATION_90
            tmpTransform.postRotate(rotationDelta);
                    ? Surface.ROTATION_270 : Surface.ROTATION_90);
            startTransaction.setMatrix(leash, tmpTransform, new float[9]);
            startTransaction.setMatrix(leash, tmpTransform, new float[9]);
        }
        }
        if (mOneShotAnimationType == ANIM_TYPE_BOUNDS) {
        if (mOneShotAnimationType == ANIM_TYPE_BOUNDS) {
            final Rect sourceHintRect =
            // Reverse the rotation for Shell transition animation.
                    PipBoundsAlgorithm.getValidSourceHintRect(
            rotationDelta = deltaRotation(rotationDelta, 0);
                            taskInfo.pictureInPictureParams, currentBounds);
            animator = mPipAnimationController.getAnimator(taskInfo, leash, currentBounds,
            animator = mPipAnimationController.getAnimator(taskInfo, leash, currentBounds,
                    currentBounds, destinationBounds, sourceHintRect, TRANSITION_DIRECTION_TO_PIP,
                    currentBounds, destinationBounds, sourceHintRect, TRANSITION_DIRECTION_TO_PIP,
                    0 /* startingAngle */, rotationDelta);
                    0 /* startingAngle */, rotationDelta);
@@ -528,9 +595,6 @@ public class PipTransition extends PipTransitionController {
            }
            }
        } else if (mOneShotAnimationType == ANIM_TYPE_ALPHA) {
        } else if (mOneShotAnimationType == ANIM_TYPE_ALPHA) {
            startTransaction.setAlpha(leash, 0f);
            startTransaction.setAlpha(leash, 0f);
            // PiP menu is attached late in the process here to avoid any artifacts on the leash
            // caused by addShellRoot when in gesture navigation mode.
            mPipMenuController.attach(leash);
            animator = mPipAnimationController.getAnimator(taskInfo, leash, destinationBounds,
            animator = mPipAnimationController.getAnimator(taskInfo, leash, destinationBounds,
                    0f, 1f);
                    0f, 1f);
            mOneShotAnimationType = ANIM_TYPE_BOUNDS;
            mOneShotAnimationType = ANIM_TYPE_BOUNDS;
@@ -541,12 +605,47 @@ public class PipTransition extends PipTransitionController {
        startTransaction.apply();
        startTransaction.apply();
        animator.setTransitionDirection(TRANSITION_DIRECTION_TO_PIP)
        animator.setTransitionDirection(TRANSITION_DIRECTION_TO_PIP)
                .setPipAnimationCallback(mPipAnimationCallback)
                .setPipAnimationCallback(mPipAnimationCallback)
                .setDuration(mEnterExitAnimationDuration)
                .setDuration(mEnterExitAnimationDuration);
                .start();
        if (rotationDelta != Surface.ROTATION_0 && mInFixedRotation) {
            // For fixed rotation, the animation destination bounds is in old rotation coordinates.
            // Set the destination bounds to new coordinates after the animation is finished.
            // ComputeRotatedBounds has changed the DisplayLayout without affecting the animation.
            animator.setDestinationBounds(mPipBoundsAlgorithm.getEntryDestinationBounds());
        }
        animator.start();


        return true;
        return true;
    }
    }


    /** Computes destination bounds in old rotation and returns source hint rect if available. */
    @Nullable
    private Rect computeRotatedBounds(int rotationDelta, int startRotation, int endRotation,
            TaskInfo taskInfo, int direction, Rect outDestinationBounds,
            @Nullable Rect sourceHintRect) {
        if (direction == TRANSITION_DIRECTION_TO_PIP) {
            mPipBoundsState.getDisplayLayout().rotateTo(mContext.getResources(), endRotation);
            final Rect displayBounds = mPipBoundsState.getDisplayBounds();
            outDestinationBounds.set(mPipBoundsAlgorithm.getEntryDestinationBounds());
            // Transform the destination bounds to current display coordinates.
            rotateBounds(outDestinationBounds, displayBounds, endRotation, startRotation);
            // When entering PiP (from button navigation mode), adjust the source rect hint by
            // display cutout if applicable.
            if (sourceHintRect != null && taskInfo.displayCutoutInsets != null) {
                if (rotationDelta == Surface.ROTATION_270) {
                    sourceHintRect.offset(taskInfo.displayCutoutInsets.left,
                            taskInfo.displayCutoutInsets.top);
                }
            }
        } else if (direction == TRANSITION_DIRECTION_LEAVE_PIP) {
            final Rect rotatedDestinationBounds = new Rect(outDestinationBounds);
            rotateBounds(rotatedDestinationBounds, mPipBoundsState.getDisplayBounds(),
                    rotationDelta);
            return PipBoundsAlgorithm.getValidSourceHintRect(taskInfo.pictureInPictureParams,
                    rotatedDestinationBounds);
        }
        return sourceHintRect;
    }

    private void startExitToSplitAnimation(TransitionInfo info,
    private void startExitToSplitAnimation(TransitionInfo info,
            SurfaceControl.Transaction startTransaction,
            SurfaceControl.Transaction startTransaction,
            SurfaceControl.Transaction finishTransaction,
            SurfaceControl.Transaction finishTransaction,
@@ -595,6 +694,13 @@ public class PipTransition extends PipTransitionController {
        startTransaction.setCornerRadius(leash, 0);
        startTransaction.setCornerRadius(leash, 0);
        startTransaction.setPosition(leash, bounds.left, bounds.top);
        startTransaction.setPosition(leash, bounds.left, bounds.top);


        if (mHasFadeOut && prevPipChange.getTaskInfo().isVisible()) {
            if (mPipAnimationController.getCurrentAnimator() != null) {
                mPipAnimationController.getCurrentAnimator().cancel();
            }
            startTransaction.setAlpha(leash, 1);
        }
        mHasFadeOut = false;
        mCurrentPipTaskToken = null;
        mCurrentPipTaskToken = null;
        mPipOrganizer.onExitPipFinished(prevPipChange.getTaskInfo());
        mPipOrganizer.onExitPipFinished(prevPipChange.getTaskInfo());
    }
    }
@@ -615,6 +721,25 @@ public class PipTransition extends PipTransitionController {
                .round(finishTransaction, leash, isInPip);
                .round(finishTransaction, leash, isInPip);
    }
    }


    /** Hides and shows the existing PIP during fixed rotation transition of other activities. */
    private void fadeExistingPip(boolean show) {
        final SurfaceControl leash = mPipOrganizer.getSurfaceControl();
        final TaskInfo taskInfo = mPipOrganizer.getTaskInfo();
        if (leash == null || !leash.isValid() || taskInfo == null) {
            Log.w(TAG, "Invalid leash on fadeExistingPip: " + leash);
            return;
        }
        final float alphaStart = show ? 0 : 1;
        final float alphaEnd = show ? 1 : 0;
        mPipAnimationController
                .getAnimator(taskInfo, leash, mPipBoundsState.getBounds(), alphaStart, alphaEnd)
                .setTransitionDirection(TRANSITION_DIRECTION_SAME)
                .setPipAnimationCallback(mPipAnimationCallback)
                .setDuration(mEnterExitAnimationDuration)
                .start();
        mHasFadeOut = !show;
    }

    private void finishResizeForMenu(Rect destinationBounds) {
    private void finishResizeForMenu(Rect destinationBounds) {
        mPipMenuController.movePipMenu(null, null, destinationBounds);
        mPipMenuController.movePipMenu(null, null, destinationBounds);
        mPipMenuController.updateMenuBounds(destinationBounds);
        mPipMenuController.updateMenuBounds(destinationBounds);
+4 −0
Original line number Original line Diff line number Diff line
@@ -123,6 +123,10 @@ public abstract class PipTransitionController implements Transitions.TransitionH
    public void forceFinishTransition() {
    public void forceFinishTransition() {
    }
    }


    /** Called when the fixed rotation started. */
    public void onFixedRotationStarted() {
    }

    public PipTransitionController(PipBoundsState pipBoundsState,
    public PipTransitionController(PipBoundsState pipBoundsState,
            PipMenuController pipMenuController, PipBoundsAlgorithm pipBoundsAlgorithm,
            PipMenuController pipMenuController, PipBoundsAlgorithm pipBoundsAlgorithm,
            PipAnimationController pipAnimationController, Transitions transitions,
            PipAnimationController pipAnimationController, Transitions transitions,
+11 −0
Original line number Original line Diff line number Diff line
@@ -1251,6 +1251,17 @@ class Transition extends Binder implements BLASTSyncEngine.TransactionReadyListe
                final ActivityRecord topMostActivity = task.getTopMostActivity();
                final ActivityRecord topMostActivity = task.getTopMostActivity();
                change.setAllowEnterPip(topMostActivity != null
                change.setAllowEnterPip(topMostActivity != null
                        && topMostActivity.checkEnterPictureInPictureAppOpsState());
                        && topMostActivity.checkEnterPictureInPictureAppOpsState());
                final ActivityRecord topRunningActivity = task.topRunningActivity();
                if (topRunningActivity != null && task.mDisplayContent != null) {
                    // If Activity is in fixed rotation, its will be applied with the next rotation,
                    // when the Task is still in the previous rotation.
                    final int taskRotation = task.getWindowConfiguration().getDisplayRotation();
                    final int activityRotation = topRunningActivity.getWindowConfiguration()
                            .getDisplayRotation();
                    if (taskRotation != activityRotation) {
                        change.setEndFixedRotation(activityRotation);
                    }
                }
            } else if ((info.mFlags & ChangeInfo.FLAG_SEAMLESS_ROTATION) != 0) {
            } else if ((info.mFlags & ChangeInfo.FLAG_SEAMLESS_ROTATION) != 0) {
                change.setRotationAnimation(ROTATION_ANIMATION_SEAMLESS);
                change.setRotationAnimation(ROTATION_ANIMATION_SEAMLESS);
            }
            }