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

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

Start animations in default handler after start transaction

This was basically posting animation start onto anim executor
which is a different thread. This caused a race where the
animation could start (and apply some surface changes) before
the transition startTransaction which could cause flicker in
the corners (outside the rounded corner) since the animation
background surface wasn't shown yet.

Bug: 265007895
Test: flicker TaskTransitionTest
Change-Id: I717a4a1e8be1ace1bbbed32b358290d2c59650b6
parent 53fb11c1
Loading
Loading
Loading
Loading
+31 −39
Original line number Diff line number Diff line
@@ -445,7 +445,6 @@ public class DefaultTransitionHandler implements Transitions.TransitionHandler {
                backgroundColorForTransition = getTransitionBackgroundColorIfSet(info, change, a,
                        backgroundColorForTransition);

                boolean delayedEdgeExtension = false;
                if (!isTask && a.hasExtension()) {
                    if (!Transitions.isOpeningType(change.getMode())) {
                        // Can screenshot now (before startTransaction is applied)
@@ -455,7 +454,6 @@ public class DefaultTransitionHandler implements Transitions.TransitionHandler {
                        // may not be visible or ready yet.
                        postStartTransactionCallbacks
                                .add(t -> edgeExtendWindow(change, a, t, finishTransaction));
                        delayedEdgeExtension = true;
                    }
                }

@@ -464,19 +462,9 @@ public class DefaultTransitionHandler implements Transitions.TransitionHandler {
                        : new Rect(change.getEndAbsBounds());
                clipRect.offsetTo(0, 0);

                if (delayedEdgeExtension) {
                    // If the edge extension needs to happen after the startTransition has been
                    // applied, then we want to only start the animation after the edge extension
                    // postStartTransaction callback has been run
                    postStartTransactionCallbacks.add(t ->
                            startSurfaceAnimation(animations, a, change.getLeash(), onAnimFinish,
                                    mTransactionPool, mMainExecutor, mAnimExecutor,
                                    change.getEndRelOffset(), cornerRadius, clipRect));
                } else {
                    startSurfaceAnimation(animations, a, change.getLeash(), onAnimFinish,
                            mTransactionPool, mMainExecutor, mAnimExecutor,
                            change.getEndRelOffset(), cornerRadius, clipRect);
                }
                buildSurfaceAnimation(animations, a, change.getLeash(), onAnimFinish,
                        mTransactionPool, mMainExecutor, change.getEndRelOffset(), cornerRadius,
                        clipRect);

                if (info.getAnimationOptions() != null) {
                    attachThumbnail(animations, onAnimFinish, change, info.getAnimationOptions(),
@@ -490,19 +478,25 @@ public class DefaultTransitionHandler implements Transitions.TransitionHandler {
                    startTransaction, finishTransaction);
        }

        if (postStartTransactionCallbacks.size() > 0) {
            // postStartTransactionCallbacks require that the start transaction is already
            // applied to run otherwise they may result in flickers and UI inconsistencies.
        boolean waitForStartTransactionApply = postStartTransactionCallbacks.size() > 0;
        startTransaction.apply(waitForStartTransactionApply);

        // Run tasks that require startTransaction to already be applied
            startTransaction.apply(true /* sync */);
            // startTransaction is empty now, so fill it with the edge-extension setup
            for (Consumer<SurfaceControl.Transaction> postStartTransactionCallback :
                    postStartTransactionCallbacks) {
            final SurfaceControl.Transaction t = mTransactionPool.acquire();
            postStartTransactionCallback.accept(t);
            t.apply();
            mTransactionPool.release(t);
                postStartTransactionCallback.accept(startTransaction);
            }
        }
        startTransaction.apply();

        // now start animations. they are started on another thread, so we have to post them
        // *after* applying the startTransaction
        mAnimExecutor.execute(() -> {
            for (int i = 0; i < animations.size(); ++i) {
                animations.get(i).start();
            }
        });

        mRotator.cleanUp(finishTransaction);
        TransitionMetrics.getInstance().reportAnimationStart(transition);
@@ -539,8 +533,8 @@ public class DefaultTransitionHandler implements Transitions.TransitionHandler {
            animations.removeAll(animGroupStore);
            onAnimFinish.run();
        };
        anim.startAnimation(animGroup, finishCallback, mTransitionAnimationScaleSetting,
                mMainExecutor, mAnimExecutor);
        anim.buildAnimation(animGroup, finishCallback, mTransitionAnimationScaleSetting,
                mMainExecutor);
        for (int i = animGroup.size() - 1; i >= 0; i--) {
            final Animator animator = animGroup.get(i);
            animGroupStore.add(animator);
@@ -633,11 +627,12 @@ public class DefaultTransitionHandler implements Transitions.TransitionHandler {
        return a;
    }

    static void startSurfaceAnimation(@NonNull ArrayList<Animator> animations,
    /** Builds an animator for the surface and adds it to the `animations` list. */
    static void buildSurfaceAnimation(@NonNull ArrayList<Animator> animations,
            @NonNull Animation anim, @NonNull SurfaceControl leash,
            @NonNull Runnable finishCallback, @NonNull TransactionPool pool,
            @NonNull ShellExecutor mainExecutor, @NonNull ShellExecutor animExecutor,
            @Nullable Point position, float cornerRadius, @Nullable Rect clipRect) {
            @NonNull ShellExecutor mainExecutor, @Nullable Point position, float cornerRadius,
            @Nullable Rect clipRect) {
        final SurfaceControl.Transaction transaction = pool.acquire();
        final ValueAnimator va = ValueAnimator.ofFloat(0f, 1f);
        final Transformation transformation = new Transformation();
@@ -691,7 +686,6 @@ public class DefaultTransitionHandler implements Transitions.TransitionHandler {
            }
        });
        animations.add(va);
        animExecutor.execute(va::start);
    }

    private void attachThumbnail(@NonNull ArrayList<Animator> animations,
@@ -745,9 +739,8 @@ public class DefaultTransitionHandler implements Transitions.TransitionHandler {
        };
        a.restrictDuration(MAX_ANIMATION_DURATION);
        a.scaleCurrentDuration(mTransitionAnimationScaleSetting);
        startSurfaceAnimation(animations, a, wt.getSurface(), finisher, mTransactionPool,
                mMainExecutor, mAnimExecutor, change.getEndRelOffset(),
                cornerRadius, change.getEndAbsBounds());
        buildSurfaceAnimation(animations, a, wt.getSurface(), finisher, mTransactionPool,
                mMainExecutor, change.getEndRelOffset(), cornerRadius, change.getEndAbsBounds());
    }

    private void attachThumbnailAnimation(@NonNull ArrayList<Animator> animations,
@@ -770,9 +763,8 @@ public class DefaultTransitionHandler implements Transitions.TransitionHandler {
        };
        a.restrictDuration(MAX_ANIMATION_DURATION);
        a.scaleCurrentDuration(mTransitionAnimationScaleSetting);
        startSurfaceAnimation(animations, a, wt.getSurface(), finisher, mTransactionPool,
                mMainExecutor, mAnimExecutor, change.getEndRelOffset(),
                cornerRadius, change.getEndAbsBounds());
        buildSurfaceAnimation(animations, a, wt.getSurface(), finisher, mTransactionPool,
                mMainExecutor, change.getEndRelOffset(), cornerRadius, change.getEndAbsBounds());
    }

    private static int getWallpaperTransitType(TransitionInfo info) {
+21 −26
Original line number Diff line number Diff line
@@ -21,7 +21,7 @@ import static android.view.WindowManager.LayoutParams.ROTATION_ANIMATION_CROSSFA
import static android.view.WindowManager.LayoutParams.ROTATION_ANIMATION_JUMPCUT;
import static android.view.WindowManagerPolicyConstants.SCREEN_FREEZE_LAYER_BASE;

import static com.android.wm.shell.transition.DefaultTransitionHandler.startSurfaceAnimation;
import static com.android.wm.shell.transition.DefaultTransitionHandler.buildSurfaceAnimation;
import static com.android.wm.shell.transition.Transitions.TAG;

import android.animation.Animator;
@@ -244,11 +244,11 @@ class ScreenRotationAnimation {
    }

    /**
     * Returns true if animating.
     * Returns true if any animations were added to `animations`.
     */
    public boolean startAnimation(@NonNull ArrayList<Animator> animations,
    boolean buildAnimation(@NonNull ArrayList<Animator> animations,
            @NonNull Runnable finishCallback, float animationScale,
            @NonNull ShellExecutor mainExecutor, @NonNull ShellExecutor animExecutor) {
            @NonNull ShellExecutor mainExecutor) {
        if (mScreenshotLayer == null) {
            // Can't do animation.
            return false;
@@ -311,13 +311,11 @@ class ScreenRotationAnimation {
            mRotateAlphaAnimation.restrictDuration(MAX_ANIMATION_DURATION);
            mRotateAlphaAnimation.scaleCurrentDuration(animationScale);

            startScreenshotAlphaAnimation(animations, finishCallback, mainExecutor,
                    animExecutor);
            startDisplayRotation(animations, finishCallback, mainExecutor, animExecutor);
            buildScreenshotAlphaAnimation(animations, finishCallback, mainExecutor);
            startDisplayRotation(animations, finishCallback, mainExecutor);
        } else {
            startDisplayRotation(animations, finishCallback, mainExecutor, animExecutor);
            startScreenshotRotationAnimation(animations, finishCallback, mainExecutor,
                    animExecutor);
            startDisplayRotation(animations, finishCallback, mainExecutor);
            startScreenshotRotationAnimation(animations, finishCallback, mainExecutor);
            //startColorAnimation(mTransaction, animationScale);
        }

@@ -325,27 +323,24 @@ class ScreenRotationAnimation {
    }

    private void startDisplayRotation(@NonNull ArrayList<Animator> animations,
            @NonNull Runnable finishCallback, @NonNull ShellExecutor mainExecutor,
            @NonNull ShellExecutor animExecutor) {
        startSurfaceAnimation(animations, mRotateEnterAnimation, mSurfaceControl, finishCallback,
                mTransactionPool, mainExecutor, animExecutor, null /* position */,
                0 /* cornerRadius */, null /* clipRect */);
            @NonNull Runnable finishCallback, @NonNull ShellExecutor mainExecutor) {
        buildSurfaceAnimation(animations, mRotateEnterAnimation, mSurfaceControl, finishCallback,
                mTransactionPool, mainExecutor, null /* position */, 0 /* cornerRadius */,
                null /* clipRect */);
    }

    private void startScreenshotRotationAnimation(@NonNull ArrayList<Animator> animations,
            @NonNull Runnable finishCallback, @NonNull ShellExecutor mainExecutor,
            @NonNull ShellExecutor animExecutor) {
        startSurfaceAnimation(animations, mRotateExitAnimation, mAnimLeash, finishCallback,
                mTransactionPool, mainExecutor, animExecutor, null /* position */,
                0 /* cornerRadius */, null /* clipRect */);
            @NonNull Runnable finishCallback, @NonNull ShellExecutor mainExecutor) {
        buildSurfaceAnimation(animations, mRotateExitAnimation, mAnimLeash, finishCallback,
                mTransactionPool, mainExecutor, null /* position */, 0 /* cornerRadius */,
                null /* clipRect */);
    }

    private void startScreenshotAlphaAnimation(@NonNull ArrayList<Animator> animations,
            @NonNull Runnable finishCallback, @NonNull ShellExecutor mainExecutor,
            @NonNull ShellExecutor animExecutor) {
        startSurfaceAnimation(animations, mRotateAlphaAnimation, mAnimLeash, finishCallback,
                mTransactionPool, mainExecutor, animExecutor, null /* position */,
                0 /* cornerRadius */, null /* clipRect */);
    private void buildScreenshotAlphaAnimation(@NonNull ArrayList<Animator> animations,
            @NonNull Runnable finishCallback, @NonNull ShellExecutor mainExecutor) {
        buildSurfaceAnimation(animations, mRotateAlphaAnimation, mAnimLeash, finishCallback,
                mTransactionPool, mainExecutor, null /* position */, 0 /* cornerRadius */,
                null /* clipRect */);
    }

    private void startColorAnimation(float animationScale, @NonNull ShellExecutor animExecutor) {