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

Commit 17ab0a3f authored by Tony Huang's avatar Tony Huang Committed by Automerger Merge Worker
Browse files

Merge "Implement resize enter animation" into udc-dev am: 460be670

parents ec301ae7 460be670
Loading
Loading
Loading
Loading
+3 −1
Original line number Diff line number Diff line
@@ -22,6 +22,8 @@ import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_NO_MOVE_ANIMA
import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_TRUSTED_OVERLAY;
import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;

import static com.android.wm.shell.common.split.SplitScreenConstants.FADE_DURATION;

import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.ValueAnimator;
@@ -60,7 +62,6 @@ public class SplitDecorManager extends WindowlessWindowManager {
    private static final String TAG = SplitDecorManager.class.getSimpleName();
    private static final String RESIZING_BACKGROUND_SURFACE_NAME = "ResizingBackground";
    private static final String GAP_BACKGROUND_SURFACE_NAME = "GapBackground";
    private static final long FADE_DURATION = 133;

    private final IconProvider mIconProvider;
    private final SurfaceSession mSurfaceSession;
@@ -263,6 +264,7 @@ public class SplitDecorManager extends WindowlessWindowManager {

            final SurfaceControl.Transaction animT = new SurfaceControl.Transaction();
            mScreenshotAnimator = ValueAnimator.ofFloat(1, 0);
            mScreenshotAnimator.setDuration(FADE_DURATION);
            mScreenshotAnimator.addUpdateListener(valueAnimator -> {
                final float progress = (float) valueAnimator.getAnimatedValue();
                animT.setAlpha(mScreenshot, progress);
+5 −0
Original line number Diff line number Diff line
@@ -43,6 +43,11 @@ public class SplitScreenConstants {
     */
    public static final int SPLIT_POSITION_BOTTOM_OR_RIGHT = 1;

    /**
     * Duration used for every split fade-in or fade-out.
     */
    public static final int FADE_DURATION = 133;

    @IntDef(prefix = {"SPLIT_POSITION_"}, value = {
            SPLIT_POSITION_UNDEFINED,
            SPLIT_POSITION_TOP_OR_LEFT,
+65 −79
Original line number Diff line number Diff line
@@ -22,6 +22,7 @@ import static android.view.WindowManager.TRANSIT_OPEN;
import static android.view.WindowManager.TRANSIT_TO_BACK;
import static android.view.WindowManager.TRANSIT_TO_FRONT;

import static com.android.wm.shell.common.split.SplitScreenConstants.FADE_DURATION;
import static com.android.wm.shell.common.split.SplitScreenConstants.FLAG_IS_DIVIDER_BAR;
import static com.android.wm.shell.splitscreen.SplitScreen.stageTypeToString;
import static com.android.wm.shell.splitscreen.SplitScreenController.EXIT_REASON_DRAG_DIVIDER;
@@ -34,7 +35,6 @@ import android.animation.AnimatorListenerAdapter;
import android.animation.ValueAnimator;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.graphics.Rect;
import android.os.IBinder;
import android.view.SurfaceControl;
import android.view.WindowManager;
@@ -63,7 +63,7 @@ class SplitScreenTransitions {
    private final Runnable mOnFinish;

    DismissSession mPendingDismiss = null;
    TransitSession mPendingEnter = null;
    EnterSession mPendingEnter = null;
    TransitSession mPendingResize = null;

    private IBinder mAnimatingTransition = null;
@@ -120,6 +120,7 @@ class SplitScreenTransitions {
            @NonNull SurfaceControl.Transaction t, @NonNull WindowContainerToken mainRoot,
            @NonNull WindowContainerToken sideRoot, @NonNull WindowContainerToken topRoot) {
        // Play some place-holder fade animations
        final boolean isEnter = isPendingEnter(transition);
        for (int i = info.getChanges().size() - 1; i >= 0; --i) {
            final TransitionInfo.Change change = info.getChanges().get(i);
            final SurfaceControl leash = change.getLeash();
@@ -142,17 +143,23 @@ class SplitScreenTransitions {
                            change.getEndRelOffset().x, change.getEndRelOffset().y);
                }
            }
            boolean isRootOrSplitSideRoot = change.getParent() == null
                    || topRoot.equals(change.getParent());
            boolean isDivider = change.getFlags() == FLAG_IS_DIVIDER_BAR;
            // For enter or exit, we only want to animate side roots and the divider but not the
            // top-root.
            if (!isRootOrSplitSideRoot || topRoot.equals(change.getContainer()) || isDivider) {
                continue;
            }

            if (isPendingEnter(transition) && (mainRoot.equals(change.getContainer())
                    || sideRoot.equals(change.getContainer()))) {
            final boolean isTopRoot = topRoot.equals(change.getContainer());
            final boolean isMainRoot = mainRoot.equals(change.getContainer());
            final boolean isSideRoot = sideRoot.equals(change.getContainer());
            final boolean isDivider = change.getFlags() == FLAG_IS_DIVIDER_BAR;
            final boolean isMainChild = mainRoot.equals(change.getParent());
            final boolean isSideChild = sideRoot.equals(change.getParent());
            if (isEnter && (isMainChild || isSideChild)) {
                // Reset child tasks bounds on finish.
                mFinishTransaction.setPosition(leash,
                        change.getEndRelOffset().x, change.getEndRelOffset().y);
                mFinishTransaction.setCrop(leash, null);
            } else if (isEnter && isTopRoot) {
                // Ensure top root is visible at start.
                t.setAlpha(leash, 1.f);
                t.show(leash);
            } else if (isEnter && isMainRoot || isSideRoot) {
                t.setPosition(leash, change.getEndAbsBounds().left, change.getEndAbsBounds().top);
                t.setWindowCrop(leash, change.getEndAbsBounds().width(),
                        change.getEndAbsBounds().height());
@@ -161,10 +168,24 @@ class SplitScreenTransitions {
                t.setLayer(leash, Integer.MAX_VALUE);
                t.show(leash);
            }
            // These container changes we don't want to animate them.
            // We should only animate stage root, divider and child tasks are not under stage root.
            if (isTopRoot || isMainChild || isSideChild || change.getTaskInfo() == null) {
                continue;
            }

            if (isEnter && mPendingEnter.mResizeAnim) {
                // We will run animation in next transition so skip anim here
                continue;
            } else if (isEnter && isMainRoot) {
                // Main stage already on top so skip fade in animation to reduce flicker.
                continue;
            }

            boolean isOpening = TransitionUtil.isOpeningType(info.getType());
            if (isOpening && (mode == TRANSIT_OPEN || mode == TRANSIT_TO_FRONT)) {
                // fade in
                startExampleAnimation(leash, true /* show */);
                startFadeAnimation(leash, true /* show */);
            } else if (!isOpening && (mode == TRANSIT_CLOSE || mode == TRANSIT_TO_BACK)) {
                // fade out
                if (info.getType() == TRANSIT_SPLIT_DISMISS_SNAP) {
@@ -173,7 +194,7 @@ class SplitScreenTransitions {
                    // and don't animate it so it doesn't pop-in when reparented.
                    t.setAlpha(leash, 0.f);
                } else {
                    startExampleAnimation(leash, false /* show */);
                    startFadeAnimation(leash, false /* show */);
                }
            }
        }
@@ -267,7 +288,7 @@ class SplitScreenTransitions {
            Transitions.TransitionHandler handler,
            @Nullable TransitionConsumedCallback consumedCallback,
            @Nullable TransitionFinishedCallback finishedCallback,
            int extraTransitType) {
            int extraTransitType, boolean resizeAnim) {
        if (mPendingEnter != null) {
            ProtoLog.v(ShellProtoLogGroup.WM_SHELL_TRANSITIONS, "  splitTransition "
                    + " skip to start enter split transition since it already exist. ");
@@ -275,7 +296,7 @@ class SplitScreenTransitions {
        }
        final IBinder transition = mTransitions.startTransition(transitType, wct, handler);
        setEnterTransition(transition, remoteTransition, consumedCallback, finishedCallback,
                extraTransitType);
                extraTransitType, resizeAnim);
        return transition;
    }

@@ -284,9 +305,10 @@ class SplitScreenTransitions {
            @Nullable RemoteTransition remoteTransition,
            @Nullable TransitionConsumedCallback consumedCallback,
            @Nullable TransitionFinishedCallback finishedCallback,
            int extraTransitType) {
        mPendingEnter = new TransitSession(
                transition, consumedCallback, finishedCallback, remoteTransition, extraTransitType);
            int extraTransitType, boolean resizeAnim) {
        mPendingEnter = new EnterSession(
                transition, consumedCallback, finishedCallback, remoteTransition, extraTransitType,
                resizeAnim);

        ProtoLog.v(ShellProtoLogGroup.WM_SHELL_TRANSITIONS, "  splitTransition "
                + " deduced Enter split screen");
@@ -409,78 +431,27 @@ class SplitScreenTransitions {
        }
    }

    // TODO(shell-transitions): real animations
    private void startExampleAnimation(@NonNull SurfaceControl leash, boolean show) {
    private void startFadeAnimation(@NonNull SurfaceControl leash, boolean show) {
        final float end = show ? 1.f : 0.f;
        final float start = 1.f - end;
        final SurfaceControl.Transaction transaction = mTransactionPool.acquire();
        final ValueAnimator va = ValueAnimator.ofFloat(start, end);
        va.setDuration(500);
        va.setDuration(FADE_DURATION);
        va.addUpdateListener(animation -> {
            float fraction = animation.getAnimatedFraction();
            transaction.setAlpha(leash, start * (1.f - fraction) + end * fraction);
            transaction.apply();
        });
        final Runnable finisher = () -> {
            transaction.setAlpha(leash, end);
            transaction.apply();
            mTransactionPool.release(transaction);
            mTransitions.getMainExecutor().execute(() -> {
                mAnimations.remove(va);
                onFinish(null /* wct */, null /* wctCB */);
            });
        };
        va.addListener(new AnimatorListenerAdapter() {
            @Override
            public void onAnimationEnd(Animator animation) {
                finisher.run();
            }

            @Override
            public void onAnimationCancel(Animator animation) {
                finisher.run();
            }
        });
        mAnimations.add(va);
        mTransitions.getAnimExecutor().execute(va::start);
    }

    // TODO(shell-transitions): real animations
    private void startExampleResizeAnimation(@NonNull SurfaceControl leash,
            @NonNull Rect startBounds, @NonNull Rect endBounds) {
        final SurfaceControl.Transaction transaction = mTransactionPool.acquire();
        final ValueAnimator va = ValueAnimator.ofFloat(0.f, 1.f);
        va.setDuration(500);
        va.addUpdateListener(animation -> {
            float fraction = animation.getAnimatedFraction();
            transaction.setWindowCrop(leash,
                    (int) (startBounds.width() * (1.f - fraction) + endBounds.width() * fraction),
                    (int) (startBounds.height() * (1.f - fraction)
                            + endBounds.height() * fraction));
            transaction.setPosition(leash,
                    startBounds.left * (1.f - fraction) + endBounds.left * fraction,
                    startBounds.top * (1.f - fraction) + endBounds.top * fraction);
            transaction.apply();
        });
        final Runnable finisher = () -> {
            transaction.setWindowCrop(leash, 0, 0);
            transaction.setPosition(leash, endBounds.left, endBounds.top);
                transaction.setAlpha(leash, end);
                transaction.apply();
                mTransactionPool.release(transaction);
                mTransitions.getMainExecutor().execute(() -> {
                    mAnimations.remove(va);
                    onFinish(null /* wct */, null /* wctCB */);
                });
        };
        va.addListener(new AnimatorListenerAdapter() {
            @Override
            public void onAnimationEnd(Animator animation) {
                finisher.run();
            }

            @Override
            public void onAnimationCancel(Animator animation) {
                finisher.run();
            }
        });
        mAnimations.add(va);
@@ -569,6 +540,21 @@ class SplitScreenTransitions {
        }
    }

    /** Bundled information of enter transition. */
    class EnterSession extends TransitSession {
        final boolean mResizeAnim;

        EnterSession(IBinder transition,
                @Nullable TransitionConsumedCallback consumedCallback,
                @Nullable TransitionFinishedCallback finishedCallback,
                @Nullable RemoteTransition remoteTransition,
                int extraTransitType, boolean resizeAnim) {
            super(transition, consumedCallback, finishedCallback, remoteTransition,
                    extraTransitType);
            this.mResizeAnim = resizeAnim;
        }
    }

    /** Bundled information of dismiss transition. */
    class DismissSession extends TransitSession {
        final int mReason;
+32 −45
Original line number Diff line number Diff line
@@ -395,7 +395,8 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler,
            mSplitTransitions.startEnterTransition(TRANSIT_TO_FRONT, wct,
                    null, this, null /* consumedCallback */, null /* finishedCallback */,
                    isSplitScreenVisible()
                            ? TRANSIT_SPLIT_SCREEN_OPEN_TO_SIDE : TRANSIT_SPLIT_SCREEN_PAIR_OPEN);
                            ? TRANSIT_SPLIT_SCREEN_OPEN_TO_SIDE : TRANSIT_SPLIT_SCREEN_PAIR_OPEN,
                    !mIsDropEntering);
        } else {
            mSyncQueue.queue(wct);
            mSyncQueue.runInSync(t -> {
@@ -503,7 +504,8 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler,
        prepareEnterSplitScreen(wct, null /* taskInfo */, position);

        mSplitTransitions.startEnterTransition(TRANSIT_TO_FRONT, wct, null, this,
                null /* consumedCallback */, null /* finishedCallback */, extraTransitType);
                null /* consumedCallback */, null /* finishedCallback */, extraTransitType,
                !mIsDropEntering);
    }

    /** Launches an activity into split by legacy transition. */
@@ -661,7 +663,7 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler,

        mSplitTransitions.startEnterTransition(
                TRANSIT_TO_FRONT, wct, remoteTransition, this, null, null,
                TRANSIT_SPLIT_SCREEN_PAIR_OPEN);
                TRANSIT_SPLIT_SCREEN_PAIR_OPEN, false);
        setEnterInstanceId(instanceId);
    }

@@ -713,7 +715,7 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler,

        mSplitTransitions.startEnterTransition(
                TRANSIT_TO_FRONT, wct, remoteTransition, this, null, null,
                TRANSIT_SPLIT_SCREEN_PAIR_OPEN);
                TRANSIT_SPLIT_SCREEN_PAIR_OPEN, false);
        setEnterInstanceId(instanceId);
    }

@@ -1494,14 +1496,6 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler,

    private void prepareBringSplit(WindowContainerTransaction wct,
            @Nullable ActivityManager.RunningTaskInfo taskInfo, @SplitPosition int startPosition) {
        StageTaskListener targetStage;
        if (isSplitScreenVisible()) {
            // If the split screen is foreground, retrieves target stage based on position.
            targetStage = startPosition == mSideStagePosition ? mSideStage : mMainStage;
        } else {
            targetStage = mSideStage;
        }

        if (taskInfo != null) {
            wct.startTask(taskInfo.taskId,
                    resolveStartStage(STAGE_TYPE_UNDEFINED, startPosition, null, wct));
@@ -1510,13 +1504,8 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler,
        // and evict all tasks current under its.
        if (!isSplitScreenVisible()) {
            // Recreate so we need to reset position rather than keep position of background split.
            mSplitLayout.resetDividerPosition();
            updateWindowBounds(mSplitLayout, wct);
            final StageTaskListener anotherStage = targetStage == mMainStage
                    ? mSideStage : mMainStage;
            anotherStage.reparentTopTask(wct);
            wct.reorder(mRootTaskInfo.token, true);
            setRootForceTranslucent(false, wct);
            mMainStage.reparentTopTask(wct);
            prepareSplitLayout(wct);
        }
    }

@@ -1532,8 +1521,22 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler,
            mSideStage.addTask(taskInfo, wct);
        }
        mMainStage.activate(wct, true /* includingTopTask */);
        prepareSplitLayout(wct);
    }

    private void prepareSplitLayout(WindowContainerTransaction wct) {
        if (mIsDropEntering) {
            mSplitLayout.resetDividerPosition();
        } else {
            mSplitLayout.setDividerAtBorder(mSideStagePosition == SPLIT_POSITION_TOP_OR_LEFT);
        }
        updateWindowBounds(mSplitLayout, wct);
        if (!mIsDropEntering) {
            // Reset its smallest width dp to avoid is change layout before it actually resized to
            // split bounds.
            wct.setSmallestScreenWidthDp(mMainStage.mRootTaskInfo.token,
                    SMALLEST_SCREEN_WIDTH_DP_UNDEFINED);
        }
        wct.reorder(mRootTaskInfo.token, true);
        setRootForceTranslucent(false, wct);
    }
@@ -1548,6 +1551,7 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler,
        updateSurfaceBounds(mSplitLayout, t, false /* applyResizingOffset */);
        t.show(mRootTaskLeash);
        setSplitsVisible(true);
        mIsDropEntering = false;
        updateRecentTasksSplitPair();
        if (!mLogger.hasStartedSession()) {
            mLogger.logEnter(mSplitLayout.getDividerPositionAsFraction(),
@@ -1777,18 +1781,10 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler,
        // Handle entering split screen while there is a split pair running in the background.
        if (stageListener == mSideStageListener && !isSplitScreenVisible() && isSplitActive()
                && mSplitRequest == null) {
            if (mIsDropEntering) {
                mSplitLayout.resetDividerPosition();
            } else {
                mSplitLayout.setDividerAtBorder(mSideStagePosition == SPLIT_POSITION_TOP_OR_LEFT);
            }
            final WindowContainerTransaction wct = new WindowContainerTransaction();
            mMainStage.reparentTopTask(wct);
            prepareEnterSplitScreen(wct);
            mMainStage.evictAllChildren(wct);
            mSideStage.evictOtherChildren(wct, taskId);
            updateWindowBounds(mSplitLayout, wct);
            wct.reorder(mRootTaskInfo.token, true);
            setRootForceTranslucent(false, wct);

            mSyncQueue.queue(wct);
            mSyncQueue.runInSync(t -> {
@@ -1983,20 +1979,8 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler,
                exitSplitScreen(null /* childrenToTop */, EXIT_REASON_APP_FINISHED);
            }
        } else if (isSideStage && hasChildren && !mMainStage.isActive()) {
            mSplitLayout.init();

            final WindowContainerTransaction wct = new WindowContainerTransaction();
            if (mIsDropEntering) {
            prepareEnterSplitScreen(wct);
            } else {
                // TODO (b/238697912) : Add the validation to prevent entering non-recovered status
                onSplitScreenEnter();
                mSplitLayout.setDividerAtBorder(mSideStagePosition == SPLIT_POSITION_TOP_OR_LEFT);
                mMainStage.activate(wct, true /* includingTopTask */);
                updateWindowBounds(mSplitLayout, wct);
                wct.reorder(mRootTaskInfo.token, true);
                setRootForceTranslucent(false, wct);
            }

            mSyncQueue.queue(wct);
            mSyncQueue.runInSync(t -> {
@@ -2353,7 +2337,7 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler,
                prepareEnterSplitScreen(out);
                mSplitTransitions.setEnterTransition(transition, request.getRemoteTransition(),
                        null /* consumedCallback */, null /* finishedCallback */,
                        0 /* extraTransitType */);
                        0 /* extraTransitType */, !mIsDropEntering);
            }
        }
        return out;
@@ -2596,7 +2580,7 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler,
    }

    private boolean startPendingEnterAnimation(
            @NonNull SplitScreenTransitions.TransitSession enterTransition,
            @NonNull SplitScreenTransitions.EnterSession enterTransition,
            @NonNull TransitionInfo info, @NonNull SurfaceControl.Transaction t,
            @NonNull SurfaceControl.Transaction finishT) {
        // First, verify that we actually have opened apps in both splits.
@@ -2654,7 +2638,6 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler,
                    + " to have been called with " + sideChild.getTaskInfo().taskId
                    + " before startAnimation().");
        }

        final TransitionInfo.Change finalMainChild = mainChild;
        final TransitionInfo.Change finalSideChild = sideChild;
        enterTransition.setFinishedCallback((callbackWct, callbackT) -> {
@@ -2664,6 +2647,10 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler,
            if (finalSideChild != null) {
                mSideStage.evictOtherChildren(callbackWct, finalSideChild.getTaskInfo().taskId);
            }
            if (enterTransition.mResizeAnim) {
                mShowDecorImmediately = true;
                mSplitLayout.flingDividerToCenter();
            }
        });

        finishEnterSplitScreen(finishT);
+2 −2
Original line number Diff line number Diff line
@@ -182,7 +182,7 @@ public class SplitTransitionTests extends ShellTestCase {
        IBinder transition = mSplitScreenTransitions.startEnterTransition(
                TRANSIT_OPEN, new WindowContainerTransaction(),
                new RemoteTransition(testRemote, "Test"), mStageCoordinator, null, null,
                TRANSIT_SPLIT_SCREEN_PAIR_OPEN);
                TRANSIT_SPLIT_SCREEN_PAIR_OPEN, false);
        mMainStage.onTaskAppeared(mMainChild, createMockSurface());
        mSideStage.onTaskAppeared(mSideChild, createMockSurface());
        boolean accepted = mStageCoordinator.startAnimation(transition, info,
@@ -408,7 +408,7 @@ public class SplitTransitionTests extends ShellTestCase {
        IBinder enterTransit = mSplitScreenTransitions.startEnterTransition(
                TRANSIT_OPEN, new WindowContainerTransaction(),
                new RemoteTransition(new TestRemoteTransition(), "Test"),
                mStageCoordinator, null, null, TRANSIT_SPLIT_SCREEN_PAIR_OPEN);
                mStageCoordinator, null, null, TRANSIT_SPLIT_SCREEN_PAIR_OPEN, false);
        mMainStage.onTaskAppeared(mMainChild, createMockSurface());
        mSideStage.onTaskAppeared(mSideChild, createMockSurface());
        mStageCoordinator.startAnimation(enterTransit, enterInfo,
Loading