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

Commit 104a5f5c authored by Tony Huang's avatar Tony Huang
Browse files

Implement split resize shell transition

For reduce jank or flicker when resize ActivityEmbedding in split
case, we should apply shell transition to resize case too.

Fix: 247678744
Test: manual
Test: pass existing tests
Change-Id: I8a1aa500d5928284ca7955042dffb617be15635a
parent b60de628
Loading
Loading
Loading
Loading
+55 −22
Original line number Original line Diff line number Diff line
@@ -51,8 +51,6 @@ import com.android.wm.shell.R;
import com.android.wm.shell.common.ScreenshotUtils;
import com.android.wm.shell.common.ScreenshotUtils;
import com.android.wm.shell.common.SurfaceUtils;
import com.android.wm.shell.common.SurfaceUtils;


import java.util.function.Consumer;

/**
/**
 * Handles split decor like showing resizing hint for a specific split.
 * Handles split decor like showing resizing hint for a specific split.
 */
 */
@@ -72,17 +70,18 @@ public class SplitDecorManager extends WindowlessWindowManager {
    private SurfaceControl mIconLeash;
    private SurfaceControl mIconLeash;
    private SurfaceControl mBackgroundLeash;
    private SurfaceControl mBackgroundLeash;
    private SurfaceControl mGapBackgroundLeash;
    private SurfaceControl mGapBackgroundLeash;
    private SurfaceControl mScreenshot;


    private boolean mShown;
    private boolean mShown;
    private boolean mIsResizing;
    private boolean mIsResizing;
    private final Rect mBounds = new Rect();
    private final Rect mBounds = new Rect();
    private final Rect mResizingBounds = new Rect();
    private final Rect mTempRect = new Rect();
    private final Rect mTempRect = new Rect();
    private ValueAnimator mFadeAnimator;
    private ValueAnimator mFadeAnimator;


    private int mIconSize;
    private int mIconSize;
    private int mOffsetX;
    private int mOffsetX;
    private int mOffsetY;
    private int mOffsetY;
    private int mRunningAnimationCount = 0;


    public SplitDecorManager(Configuration configuration, IconProvider iconProvider,
    public SplitDecorManager(Configuration configuration, IconProvider iconProvider,
            SurfaceSession surfaceSession) {
            SurfaceSession surfaceSession) {
@@ -173,7 +172,6 @@ public class SplitDecorManager extends WindowlessWindowManager {
            mIsResizing = true;
            mIsResizing = true;
            mBounds.set(newBounds);
            mBounds.set(newBounds);
        }
        }
        mResizingBounds.set(newBounds);
        mOffsetX = offsetX;
        mOffsetX = offsetX;
        mOffsetY = offsetY;
        mOffsetY = offsetY;


@@ -227,33 +225,41 @@ public class SplitDecorManager extends WindowlessWindowManager {
                t.setVisibility(mBackgroundLeash, show);
                t.setVisibility(mBackgroundLeash, show);
                t.setVisibility(mIconLeash, show);
                t.setVisibility(mIconLeash, show);
            } else {
            } else {
                startFadeAnimation(show, null /* finishedConsumer */);
                startFadeAnimation(show, false, null);
            }
            }
            mShown = show;
            mShown = show;
        }
        }
    }
    }


    /** Stops showing resizing hint. */
    /** Stops showing resizing hint. */
    public void onResized(SurfaceControl.Transaction t) {
    public void onResized(SurfaceControl.Transaction t, Runnable animFinishedCallback) {
        if (!mShown && mIsResizing) {
        if (mScreenshot != null) {
            mTempRect.set(mResizingBounds);
            t.setPosition(mScreenshot, mOffsetX, mOffsetY);
            mTempRect.offsetTo(-mOffsetX, -mOffsetY);
            final SurfaceControl screenshot = ScreenshotUtils.takeScreenshot(t,
                    mHostLeash, mTempRect, Integer.MAX_VALUE - 1);


            final SurfaceControl.Transaction animT = new SurfaceControl.Transaction();
            final SurfaceControl.Transaction animT = new SurfaceControl.Transaction();
            final ValueAnimator va = ValueAnimator.ofFloat(1, 0);
            final ValueAnimator va = ValueAnimator.ofFloat(1, 0);
            va.addUpdateListener(valueAnimator -> {
            va.addUpdateListener(valueAnimator -> {
                final float progress = (float) valueAnimator.getAnimatedValue();
                final float progress = (float) valueAnimator.getAnimatedValue();
                animT.setAlpha(screenshot, progress);
                animT.setAlpha(mScreenshot, progress);
                animT.apply();
                animT.apply();
            });
            });
            va.addListener(new AnimatorListenerAdapter() {
            va.addListener(new AnimatorListenerAdapter() {
                @Override
                public void onAnimationStart(Animator animation) {
                    mRunningAnimationCount++;
                }

                @Override
                @Override
                public void onAnimationEnd(@androidx.annotation.NonNull Animator animation) {
                public void onAnimationEnd(@androidx.annotation.NonNull Animator animation) {
                    animT.remove(screenshot);
                    mRunningAnimationCount--;
                    animT.remove(mScreenshot);
                    animT.apply();
                    animT.apply();
                    animT.close();
                    animT.close();
                    mScreenshot = null;

                    if (mRunningAnimationCount == 0 && animFinishedCallback != null) {
                        animFinishedCallback.run();
                    }
                }
                }
            });
            });
            va.start();
            va.start();
@@ -285,10 +291,34 @@ public class SplitDecorManager extends WindowlessWindowManager {
            mFadeAnimator.cancel();
            mFadeAnimator.cancel();
        }
        }
        if (mShown) {
        if (mShown) {
            fadeOutDecor(null /* finishedCallback */);
            fadeOutDecor(animFinishedCallback);
        } else {
        } else {
            // Decor surface is hidden so release it directly.
            // Decor surface is hidden so release it directly.
            releaseDecor(t);
            releaseDecor(t);
            if (mRunningAnimationCount == 0 && animFinishedCallback != null) {
                animFinishedCallback.run();
            }
        }
    }

    /** Screenshot host leash and attach on it if meet some conditions */
    public void screenshotIfNeeded(SurfaceControl.Transaction t) {
        if (!mShown && mIsResizing) {
            mTempRect.set(mBounds);
            mTempRect.offsetTo(0, 0);
            mScreenshot = ScreenshotUtils.takeScreenshot(t, mHostLeash, mTempRect,
                    Integer.MAX_VALUE - 1);
        }
    }

    /** Set screenshot and attach on host leash it if meet some conditions */
    public void setScreenshotIfNeeded(SurfaceControl screenshot, SurfaceControl.Transaction t) {
        if (screenshot == null || !screenshot.isValid()) return;

        if (!mShown && mIsResizing) {
            mScreenshot = screenshot;
            t.reparent(screenshot, mHostLeash);
            t.setLayer(screenshot, Integer.MAX_VALUE - 1);
        }
        }
    }
    }


@@ -296,18 +326,15 @@ public class SplitDecorManager extends WindowlessWindowManager {
     * directly. */
     * directly. */
    public void fadeOutDecor(Runnable finishedCallback) {
    public void fadeOutDecor(Runnable finishedCallback) {
        if (mShown) {
        if (mShown) {
            startFadeAnimation(false /* show */, transaction -> {
            startFadeAnimation(false /* show */, true, finishedCallback);
                releaseDecor(transaction);
                if (finishedCallback != null) finishedCallback.run();
            });
            mShown = false;
            mShown = false;
        } else {
        } else {
            if (finishedCallback != null) finishedCallback.run();
            if (finishedCallback != null) finishedCallback.run();
        }
        }
    }
    }


    private void startFadeAnimation(boolean show,
    private void startFadeAnimation(boolean show, boolean releaseSurface,
            Consumer<SurfaceControl.Transaction> finishedConsumer) {
            Runnable finishedCallback) {
        final SurfaceControl.Transaction animT = new SurfaceControl.Transaction();
        final SurfaceControl.Transaction animT = new SurfaceControl.Transaction();
        mFadeAnimator = ValueAnimator.ofFloat(0f, 1f);
        mFadeAnimator = ValueAnimator.ofFloat(0f, 1f);
        mFadeAnimator.setDuration(FADE_DURATION);
        mFadeAnimator.setDuration(FADE_DURATION);
@@ -324,6 +351,7 @@ public class SplitDecorManager extends WindowlessWindowManager {
        mFadeAnimator.addListener(new AnimatorListenerAdapter() {
        mFadeAnimator.addListener(new AnimatorListenerAdapter() {
            @Override
            @Override
            public void onAnimationStart(@NonNull Animator animation) {
            public void onAnimationStart(@NonNull Animator animation) {
                mRunningAnimationCount++;
                if (show) {
                if (show) {
                    animT.show(mBackgroundLeash).show(mIconLeash);
                    animT.show(mBackgroundLeash).show(mIconLeash);
                }
                }
@@ -335,6 +363,7 @@ public class SplitDecorManager extends WindowlessWindowManager {


            @Override
            @Override
            public void onAnimationEnd(@NonNull Animator animation) {
            public void onAnimationEnd(@NonNull Animator animation) {
                mRunningAnimationCount--;
                if (!show) {
                if (!show) {
                    if (mBackgroundLeash != null) {
                    if (mBackgroundLeash != null) {
                        animT.hide(mBackgroundLeash);
                        animT.hide(mBackgroundLeash);
@@ -343,11 +372,15 @@ public class SplitDecorManager extends WindowlessWindowManager {
                        animT.hide(mIconLeash);
                        animT.hide(mIconLeash);
                    }
                    }
                }
                }
                if (finishedConsumer != null) {
                if (releaseSurface) {
                    finishedConsumer.accept(animT);
                    releaseDecor(animT);
                }
                }
                animT.apply();
                animT.apply();
                animT.close();
                animT.close();

                if (mRunningAnimationCount == 0 && finishedCallback != null) {
                    finishedCallback.run();
                }
            }
            }
        });
        });
        mFadeAnimator.start();
        mFadeAnimator.start();
+67 −0
Original line number Original line Diff line number Diff line
@@ -47,6 +47,7 @@ import android.window.WindowContainerTransactionCallback;


import com.android.internal.protolog.common.ProtoLog;
import com.android.internal.protolog.common.ProtoLog;
import com.android.wm.shell.common.TransactionPool;
import com.android.wm.shell.common.TransactionPool;
import com.android.wm.shell.common.split.SplitDecorManager;
import com.android.wm.shell.protolog.ShellProtoLogGroup;
import com.android.wm.shell.protolog.ShellProtoLogGroup;
import com.android.wm.shell.transition.OneShotRemoteHandler;
import com.android.wm.shell.transition.OneShotRemoteHandler;
import com.android.wm.shell.transition.Transitions;
import com.android.wm.shell.transition.Transitions;
@@ -64,6 +65,7 @@ class SplitScreenTransitions {
    DismissTransition mPendingDismiss = null;
    DismissTransition mPendingDismiss = null;
    TransitSession mPendingEnter = null;
    TransitSession mPendingEnter = null;
    TransitSession mPendingRecent = null;
    TransitSession mPendingRecent = null;
    TransitSession mPendingResize = null;


    private IBinder mAnimatingTransition = null;
    private IBinder mAnimatingTransition = null;
    OneShotRemoteHandler mPendingRemoteHandler = null;
    OneShotRemoteHandler mPendingRemoteHandler = null;
@@ -177,6 +179,43 @@ class SplitScreenTransitions {
        onFinish(null /* wct */, null /* wctCB */);
        onFinish(null /* wct */, null /* wctCB */);
    }
    }


    void applyResizeTransition(@NonNull IBinder transition, @NonNull TransitionInfo info,
            @NonNull SurfaceControl.Transaction startTransaction,
            @NonNull SurfaceControl.Transaction finishTransaction,
            @NonNull Transitions.TransitionFinishCallback finishCallback,
            @NonNull WindowContainerToken mainRoot, @NonNull WindowContainerToken sideRoot,
            @NonNull SplitDecorManager mainDecor, @NonNull SplitDecorManager sideDecor) {
        mFinishCallback = finishCallback;
        mAnimatingTransition = transition;
        mFinishTransaction = finishTransaction;

        for (int i = info.getChanges().size() - 1; i >= 0; --i) {
            final TransitionInfo.Change change = info.getChanges().get(i);
            if (mainRoot.equals(change.getContainer()) || sideRoot.equals(change.getContainer())) {
                final SurfaceControl leash = change.getLeash();
                startTransaction.setPosition(leash, change.getEndAbsBounds().left,
                        change.getEndAbsBounds().top);
                startTransaction.setWindowCrop(leash, change.getEndAbsBounds().width(),
                        change.getEndAbsBounds().height());

                SplitDecorManager decor = mainRoot.equals(change.getContainer())
                        ? mainDecor : sideDecor;
                ValueAnimator va = new ValueAnimator();
                mAnimations.add(va);
                decor.setScreenshotIfNeeded(change.getSnapshot(), startTransaction);
                decor.onResized(startTransaction, () -> {
                    mTransitions.getMainExecutor().execute(() -> {
                        mAnimations.remove(va);
                        onFinish(null /* wct */, null /* wctCB */);
                    });
                });
            }
        }

        startTransaction.apply();
        onFinish(null /* wct */, null /* wctCB */);
    }

    boolean isPendingTransition(IBinder transition) {
    boolean isPendingTransition(IBinder transition) {
        return getPendingTransition(transition) != null;
        return getPendingTransition(transition) != null;
    }
    }
@@ -193,6 +232,10 @@ class SplitScreenTransitions {
        return mPendingDismiss != null && mPendingDismiss.mTransition == transition;
        return mPendingDismiss != null && mPendingDismiss.mTransition == transition;
    }
    }


    boolean isPendingResize(IBinder transition) {
        return mPendingResize != null && mPendingResize.mTransition == transition;
    }

    @Nullable
    @Nullable
    private TransitSession getPendingTransition(IBinder transition) {
    private TransitSession getPendingTransition(IBinder transition) {
        if (isPendingEnter(transition)) {
        if (isPendingEnter(transition)) {
@@ -201,11 +244,14 @@ class SplitScreenTransitions {
            return mPendingRecent;
            return mPendingRecent;
        } else if (isPendingDismiss(transition)) {
        } else if (isPendingDismiss(transition)) {
            return mPendingDismiss;
            return mPendingDismiss;
        } else if (isPendingResize(transition)) {
            return mPendingResize;
        }
        }


        return null;
        return null;
    }
    }



    /** Starts a transition to enter split with a remote transition animator. */
    /** Starts a transition to enter split with a remote transition animator. */
    IBinder startEnterTransition(
    IBinder startEnterTransition(
            @WindowManager.TransitionType int transitType,
            @WindowManager.TransitionType int transitType,
@@ -258,6 +304,21 @@ class SplitScreenTransitions {
                exitReasonToString(reason), stageTypeToString(dismissTop));
                exitReasonToString(reason), stageTypeToString(dismissTop));
    }
    }


    IBinder startResizeTransition(WindowContainerTransaction wct,
            Transitions.TransitionHandler handler,
            @Nullable TransitionFinishedCallback finishCallback) {
        IBinder transition = mTransitions.startTransition(TRANSIT_CHANGE, wct, handler);
        setResizeTransition(transition, finishCallback);
        return transition;
    }

    void setResizeTransition(@NonNull IBinder transition,
            @Nullable TransitionFinishedCallback finishCallback) {
        mPendingResize = new TransitSession(transition, null /* consumedCb */, finishCallback);
        ProtoLog.v(ShellProtoLogGroup.WM_SHELL_TRANSITIONS, "  splitTransition "
                + " deduced Resize split screen");
    }

    void setRecentTransition(@NonNull IBinder transition,
    void setRecentTransition(@NonNull IBinder transition,
            @Nullable RemoteTransition remoteTransition,
            @Nullable RemoteTransition remoteTransition,
            @Nullable TransitionFinishedCallback finishCallback) {
            @Nullable TransitionFinishedCallback finishCallback) {
@@ -324,6 +385,9 @@ class SplitScreenTransitions {
            mPendingRecent.onConsumed(aborted);
            mPendingRecent.onConsumed(aborted);
            mPendingRecent = null;
            mPendingRecent = null;
            mPendingRemoteHandler = null;
            mPendingRemoteHandler = null;
        } else if (isPendingResize(transition)) {
            mPendingResize.onConsumed(aborted);
            mPendingResize = null;
        }
        }
    }
    }


@@ -340,6 +404,9 @@ class SplitScreenTransitions {
        } else if (isPendingDismiss(mAnimatingTransition)) {
        } else if (isPendingDismiss(mAnimatingTransition)) {
            mPendingDismiss.onFinished(wct, mFinishTransaction);
            mPendingDismiss.onFinished(wct, mFinishTransaction);
            mPendingDismiss = null;
            mPendingDismiss = null;
        } else if (isPendingResize(mAnimatingTransition)) {
            mPendingResize.onFinished(wct, mFinishTransaction);
            mPendingResize = null;
        }
        }


        mPendingRemoteHandler = null;
        mPendingRemoteHandler = null;
+26 −6
Original line number Original line Diff line number Diff line
@@ -1670,15 +1670,29 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler,
    public void onLayoutSizeChanged(SplitLayout layout) {
    public void onLayoutSizeChanged(SplitLayout layout) {
        // Reset this flag every time onLayoutSizeChanged.
        // Reset this flag every time onLayoutSizeChanged.
        mShowDecorImmediately = false;
        mShowDecorImmediately = false;

        if (!ENABLE_SHELL_TRANSITIONS) {
            // Only need screenshot for legacy case because shell transition should screenshot
            // itself during transition.
            final SurfaceControl.Transaction startT = mTransactionPool.acquire();
            mMainStage.screenshotIfNeeded(startT);
            mSideStage.screenshotIfNeeded(startT);
            mTransactionPool.release(startT);
        }

        final WindowContainerTransaction wct = new WindowContainerTransaction();
        final WindowContainerTransaction wct = new WindowContainerTransaction();
        updateWindowBounds(layout, wct);
        updateWindowBounds(layout, wct);
        sendOnBoundsChanged();
        sendOnBoundsChanged();
        if (ENABLE_SHELL_TRANSITIONS) {
            mSplitTransitions.startResizeTransition(wct, this, null /* callback */);
        } else {
            mSyncQueue.queue(wct);
            mSyncQueue.queue(wct);
            mSyncQueue.runInSync(t -> {
            mSyncQueue.runInSync(t -> {
                updateSurfaceBounds(layout, t, false /* applyResizingOffset */);
                updateSurfaceBounds(layout, t, false /* applyResizingOffset */);
                mMainStage.onResized(t);
                mMainStage.onResized(t);
                mSideStage.onResized(t);
                mSideStage.onResized(t);
            });
            });
        }
        mLogger.logResize(mSplitLayout.getDividerPositionAsFraction());
        mLogger.logResize(mSplitLayout.getDividerPositionAsFraction());
    }
    }


@@ -2032,6 +2046,12 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler,
        } else if (mSplitTransitions.isPendingDismiss(transition)) {
        } else if (mSplitTransitions.isPendingDismiss(transition)) {
            shouldAnimate = startPendingDismissAnimation(
            shouldAnimate = startPendingDismissAnimation(
                    mSplitTransitions.mPendingDismiss, info, startTransaction, finishTransaction);
                    mSplitTransitions.mPendingDismiss, info, startTransaction, finishTransaction);
        } else if (mSplitTransitions.isPendingResize(transition)) {
            mSplitTransitions.applyResizeTransition(transition, info, startTransaction,
                    finishTransaction, finishCallback, mMainStage.mRootTaskInfo.token,
                    mSideStage.mRootTaskInfo.token, mMainStage.getSplitDecorManager(),
                    mSideStage.getSplitDecorManager());
            return true;
        }
        }
        if (!shouldAnimate) return false;
        if (!shouldAnimate) return false;


+11 −1
Original line number Original line Diff line number Diff line
@@ -292,7 +292,13 @@ class StageTaskListener implements ShellTaskOrganizer.TaskListener {


    void onResized(SurfaceControl.Transaction t) {
    void onResized(SurfaceControl.Transaction t) {
        if (mSplitDecorManager != null) {
        if (mSplitDecorManager != null) {
            mSplitDecorManager.onResized(t);
            mSplitDecorManager.onResized(t, null);
        }
    }

    void screenshotIfNeeded(SurfaceControl.Transaction t) {
        if (mSplitDecorManager != null) {
            mSplitDecorManager.screenshotIfNeeded(t);
        }
        }
    }
    }


@@ -304,6 +310,10 @@ class StageTaskListener implements ShellTaskOrganizer.TaskListener {
        }
        }
    }
    }


    SplitDecorManager getSplitDecorManager() {
        return mSplitDecorManager;
    }

    void addTask(ActivityManager.RunningTaskInfo task, WindowContainerTransaction wct) {
    void addTask(ActivityManager.RunningTaskInfo task, WindowContainerTransaction wct) {
        // Clear overridden bounds and windowing mode to make sure the child task can inherit
        // Clear overridden bounds and windowing mode to make sure the child task can inherit
        // windowing mode and bounds from split root.
        // windowing mode and bounds from split root.
+1 −1
Original line number Original line Diff line number Diff line
@@ -2177,7 +2177,7 @@ class Task extends TaskFragment {
    }
    }


    private boolean shouldStartChangeTransition(int prevWinMode, @NonNull Rect prevBounds) {
    private boolean shouldStartChangeTransition(int prevWinMode, @NonNull Rect prevBounds) {
        if (!isLeafTask() || !canStartChangeTransition()) {
        if (!(isLeafTask() || mCreatedByOrganizer) || !canStartChangeTransition()) {
            return false;
            return false;
        }
        }
        final int newWinMode = getWindowingMode();
        final int newWinMode = getWindowingMode();