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

Commit e76e2239 authored by Riddle Hsu's avatar Riddle Hsu
Browse files

Add mixed entering pip transition with display change

The case happens when a pip is entering in previous rotation and then
display updates. The transition type can be either TRANSIT_CHANGE or
TRANSIT_PIP:
 PipTask CHANGE
   sb=Rect(0, 0 - 1080, 2340)
   eb=Rect(0, 0 - 2340, 1080) r=0->3
 Display CHANGE
   sb=Rect(0, 0 - 1080, 2340)
   eb=Rect(0, 0 - 2340, 1080) r=0->3

The destination pip bounds should be calculated from (2340, 1080).
Because a display snapshot should have covered the screen, the pip
should go to the end state immediately and only animate the display
rotation animation.

This also merges [1] and [2].
[1]: I110d1c11f3d3fdcfb83698e5cf1ec4efb062bd10
[2]: Ia9c78105f4a9782c156744e6cb38681f265955a0

Bug: 340367710
Test: Enable auto rotation and home rotation.
      Swipe up (do not release touch) an auto pip activity in portrait.
      Rotate the device to landscape.
      Continue the swipe up to enter pip.
      The display should show a rotation animation and
      the pip can show on correct landscape position,

Merged-In: Ia1e5e8c7edb8c2a078a66b587d5d26a495166de2
Change-Id: Ia1e5e8c7edb8c2a078a66b587d5d26a495166de2
(cherry picked from commit 6373912c)
parent 0753af02
Loading
Loading
Loading
Loading
+6 −0
Original line number Diff line number Diff line
@@ -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;
+49 −13
Original line number Diff line number Diff line
@@ -287,6 +287,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;
        }
@@ -301,6 +307,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,
@@ -825,8 +850,11 @@ public class PipTransition extends PipTransitionController {
            @NonNull Transitions.TransitionFinishCallback finishCallback,
            @NonNull TaskInfo taskInfo) {
        startTransaction.apply();
        finishTransaction.setWindowCrop(info.getChanges().get(0).getLeash(),
                mPipDisplayLayoutState.getDisplayBounds());
        final TransitionInfo.Change pipChange = findCurrentPipTaskChange(info);
        if (pipChange == null) {
            ProtoLog.e(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
                    "removePipImmediately is called without pip change");
        }
        mPipOrganizer.onExitPipFinished(taskInfo);
        finishCallback.onTransitionFinished(null);
    }
@@ -873,19 +901,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");
@@ -959,8 +992,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);
        }
@@ -1052,8 +1085,11 @@ public class PipTransition extends PipTransitionController {

        final Rect displayBounds = mPipDisplayLayoutState.getDisplayBounds();
        outDestinationBounds.set(mPipBoundsAlgorithm.getEntryDestinationBounds());
        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) {
+10 −0
Original line number Diff line number Diff line
@@ -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;
@@ -68,6 +69,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() {
@@ -173,6 +175,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.
     */
+45 −0
Original line number Diff line number Diff line
@@ -106,6 +106,9 @@ public class DefaultMixedHandler implements Transitions.TransitionHandler,
        /** 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;

@@ -232,6 +235,7 @@ public class DefaultMixedHandler implements Transitions.TransitionHandler,
            // 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) {
@@ -549,6 +553,47 @@ public class DefaultMixedHandler implements Transitions.TransitionHandler,
        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,
+2 −1
Original line number Diff line number Diff line
@@ -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:
Loading