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

Commit f0ff75fd authored by Evan Rosky's avatar Evan Rosky
Browse files

End transitions when receiving merge request

The default behavior (if nothing is done) for a merge request
is to let the animation continue and queue up the incoming animation
to start once the current one has finished.

This is maybe the "smoothest" default; however, it is not
responsive for the user. So, instead, go through and, where
appropriate, make animations "jump-to-end" when they receive
a merge request. This way the user will see the new animation
start immediately after they perform an action. There is
technically a "jump" in the animation, but it seems like the
responsiveness is preferable and the jumps aren't super
noticable anyways. This is also how legacy transitions works
so it's not a behavior change.

Bug: 236309064
Test: interrupt animations with other transitions and observe.
      Example: launch an app and then go "back" before it finishes
      animating.
Change-Id: I4a76e7efe2c610b22f3fe97b0bd3ab692a01be08
parent cb8c65fe
Loading
Loading
Loading
Loading
+15 −0
Original line number Diff line number Diff line
@@ -42,6 +42,7 @@ import static com.android.wm.shell.transition.Transitions.TRANSIT_EXIT_PIP_TO_SP
import static com.android.wm.shell.transition.Transitions.TRANSIT_REMOVE_PIP;
import static com.android.wm.shell.transition.Transitions.isOpeningType;

import android.animation.Animator;
import android.app.ActivityManager;
import android.app.TaskInfo;
import android.content.Context;
@@ -248,6 +249,13 @@ public class PipTransition extends PipTransitionController {
        return false;
    }

    @Override
    public void mergeAnimation(@NonNull IBinder transition, @NonNull TransitionInfo info,
            @NonNull SurfaceControl.Transaction t, @NonNull IBinder mergeTarget,
            @NonNull Transitions.TransitionFinishCallback finishCallback) {
        end();
    }

    /** Helper to identify whether this handler is currently the one playing an animation */
    private boolean isAnimatingLocally() {
        return mFinishTransaction != null;
@@ -282,6 +290,13 @@ public class PipTransition extends PipTransitionController {
        }
    }

    @Override
    public void end() {
        Animator animator = mPipAnimationController.getCurrentAnimator();
        if (animator == null) return;
        animator.end();
    }

    @Override
    public boolean handleRotateDisplay(int startRotation, int endRotation,
            WindowContainerTransaction wct) {
+4 −0
Original line number Diff line number Diff line
@@ -237,6 +237,10 @@ public abstract class PipTransitionController implements Transitions.TransitionH
            @NonNull final Transitions.TransitionFinishCallback finishCallback) {
    }

    /** End the currently-playing PiP animation. */
    public void end() {
    }

    /**
     * Callback interface for PiP transitions (both from and to PiP mode)
     */
+17 −1
Original line number Diff line number Diff line
@@ -225,9 +225,25 @@ class SplitScreenTransitions {

    void mergeAnimation(IBinder transition, TransitionInfo info, SurfaceControl.Transaction t,
            IBinder mergeTarget, Transitions.TransitionFinishCallback finishCallback) {
        if (mergeTarget == mAnimatingTransition && mActiveRemoteHandler != null) {
        if (mergeTarget != mAnimatingTransition) return;
        if (mActiveRemoteHandler != null) {
            mActiveRemoteHandler.mergeAnimation(transition, info, t, mergeTarget, finishCallback);
        } else {
            for (int i = mAnimations.size() - 1; i >= 0; --i) {
                final Animator anim = mAnimations.get(i);
                mTransitions.getAnimExecutor().execute(anim::end);
            }
        }
    }

    boolean end() {
        // If its remote, there's nothing we can do right now.
        if (mActiveRemoteHandler != null) return false;
        for (int i = mAnimations.size() - 1; i >= 0; --i) {
            final Animator anim = mAnimations.get(i);
            mTransitions.getAnimExecutor().execute(anim::end);
        }
        return true;
    }

    void onTransitionMerged(@NonNull IBinder transition) {
+5 −0
Original line number Diff line number Diff line
@@ -1521,6 +1521,11 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler,
        mSplitTransitions.mergeAnimation(transition, info, t, mergeTarget, finishCallback);
    }

    /** Jump the current transition animation to the end. */
    public boolean end() {
        return mSplitTransitions.end();
    }

    @Override
    public void onTransitionMerged(@NonNull IBinder transition) {
        mSplitTransitions.onTransitionMerged(transition);
+39 −3
Original line number Diff line number Diff line
@@ -53,10 +53,18 @@ public class DefaultMixedHandler implements Transitions.TransitionHandler {
    private static class MixedTransition {
        static final int TYPE_ENTER_PIP_FROM_SPLIT = 1;

        /** The default animation for this mixed transition. */
        static final int ANIM_TYPE_DEFAULT = 0;

        /** For ENTER_PIP_FROM_SPLIT, indicates that this is a to-home animation. */
        static final int ANIM_TYPE_GOING_HOME = 1;

        final int mType;
        int mAnimType = 0;
        final IBinder mTransition;

        Transitions.TransitionFinishCallback mFinishCallback = null;
        Transitions.TransitionHandler mLeftoversHandler = null;

        /**
         * Mixed transitions are made up of multiple "parts". This keeps track of how many
@@ -128,7 +136,7 @@ public class DefaultMixedHandler implements Transitions.TransitionHandler {
        MixedTransition mixed = null;
        for (int i = mActiveTransitions.size() - 1; i >= 0; --i) {
            if (mActiveTransitions.get(i).mTransition != transition) continue;
            mixed = mActiveTransitions.remove(i);
            mixed = mActiveTransitions.get(i);
            break;
        }
        if (mixed == null) return false;
@@ -137,6 +145,7 @@ public class DefaultMixedHandler implements Transitions.TransitionHandler {
            return animateEnterPipFromSplit(mixed, info, startTransaction, finishTransaction,
                    finishCallback);
        } else {
            mActiveTransitions.remove(mixed);
            throw new IllegalStateException("Starting mixed animation without a known mixed type? "
                    + mixed.mType);
        }
@@ -178,6 +187,7 @@ public class DefaultMixedHandler implements Transitions.TransitionHandler {
        Transitions.TransitionFinishCallback finishCB = (wct, wctCB) -> {
            --mixed.mInFlightSubAnimations;
            if (mixed.mInFlightSubAnimations > 0) return;
            mActiveTransitions.remove(mixed);
            if (isGoingHome) {
                mSplitHandler.onTransitionAnimationComplete();
            }
@@ -216,8 +226,8 @@ public class DefaultMixedHandler implements Transitions.TransitionHandler {
                    finishCB);
            // Dispatch the rest of the transition normally. This will most-likely be taken by
            // recents or default handler.
            mPlayer.dispatchTransition(mixed.mTransition, everythingElse, otherStartT,
                    finishTransaction, finishCB, this);
            mixed.mLeftoversHandler = mPlayer.dispatchTransition(mixed.mTransition, everythingElse,
                    otherStartT, finishTransaction, finishCB, this);
        } else {
            ProtoLog.v(ShellProtoLogGroup.WM_SHELL_TRANSITIONS, "  Not leaving split, so just "
                    + "forward animation to Pip-Handler.");
@@ -235,6 +245,32 @@ public class DefaultMixedHandler implements Transitions.TransitionHandler {
    public void mergeAnimation(@NonNull IBinder transition, @NonNull TransitionInfo info,
            @NonNull SurfaceControl.Transaction t, @NonNull IBinder mergeTarget,
            @NonNull Transitions.TransitionFinishCallback finishCallback) {
        for (int i = 0; i < mActiveTransitions.size(); ++i) {
            if (mActiveTransitions.get(i) != mergeTarget) continue;
            MixedTransition mixed = mActiveTransitions.get(i);
            if (mixed.mInFlightSubAnimations <= 0) {
                // Already done, so no need to end it.
                return;
            }
            if (mixed.mType == MixedTransition.TYPE_ENTER_PIP_FROM_SPLIT) {
                if (mixed.mAnimType == MixedTransition.ANIM_TYPE_GOING_HOME) {
                    boolean ended = mSplitHandler.end();
                    // If split couldn't end (because it is remote), then don't end everything else
                    // since we have to play out the animation anyways.
                    if (!ended) return;
                    mPipHandler.end();
                    if (mixed.mLeftoversHandler != null) {
                        mixed.mLeftoversHandler.mergeAnimation(transition, info, t, mergeTarget,
                                finishCallback);
                    }
                } else {
                    mPipHandler.end();
                }
            } else {
                throw new IllegalStateException("Playing a mixed transition with unknown type? "
                        + mixed.mType);
            }
        }
    }

    @Override
Loading