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

Commit 87370813 authored by Shan Huang's avatar Shan Huang Committed by Automerger Merge Worker
Browse files

Merge "Fix broken animation on two consecutive swipes." into tm-dev am: 8a91edd4 am: 1d578488

parents 6910411d 1d578488
Loading
Loading
Loading
Loading
+39 −2
Original line number Diff line number Diff line
@@ -67,8 +67,12 @@ public class BackAnimationController implements RemoteCallable<BackAnimationCont
                    SETTING_VALUE_ON) != SETTING_VALUE_OFF;
    private static final int PROGRESS_THRESHOLD = SystemProperties
            .getInt(PREDICTIVE_BACK_PROGRESS_THRESHOLD_PROP, -1);

    private final AtomicBoolean mEnableAnimations = new AtomicBoolean(false);
    /**
     * Max duration to wait for a transition to finish before accepting another gesture start
     * request.
     */
    private static final long MAX_TRANSITION_DURATION = 2000;

    /**
     * Location of the initial touch event of the back gesture.
@@ -84,6 +88,8 @@ public class BackAnimationController implements RemoteCallable<BackAnimationCont
    /** True when a back gesture is ongoing */
    private boolean mBackGestureStarted = false;

    /** Tracks if an uninterruptible transition is in progress */
    private boolean mTransitionInProgress = false;
    /** @see #setTriggerBack(boolean) */
    private boolean mTriggerBack;

@@ -96,6 +102,10 @@ public class BackAnimationController implements RemoteCallable<BackAnimationCont
    private IOnBackInvokedCallback mBackToLauncherCallback;
    private float mTriggerThreshold;
    private float mProgressThreshold;
    private final Runnable mResetTransitionRunnable = () -> {
        finishAnimation();
        mTransitionInProgress = false;
    };

    public BackAnimationController(
            @NonNull @ShellMainThread ShellExecutor shellExecutor,
@@ -229,7 +239,8 @@ public class BackAnimationController implements RemoteCallable<BackAnimationCont
        mBackToLauncherCallback = null;
    }

    private void onBackToLauncherAnimationFinished() {
    @VisibleForTesting
    void onBackToLauncherAnimationFinished() {
        if (mBackNavigationInfo != null) {
            IOnBackInvokedCallback callback = mBackNavigationInfo.getOnBackInvokedCallback();
            if (mTriggerBack) {
@@ -246,6 +257,9 @@ public class BackAnimationController implements RemoteCallable<BackAnimationCont
     * {@link BackAnimationController}
     */
    public void onMotionEvent(MotionEvent event, int action, @BackEvent.SwipeEdge int swipeEdge) {
        if (mTransitionInProgress) {
            return;
        }
        if (action == MotionEvent.ACTION_MOVE) {
            if (!mBackGestureStarted) {
                // Let the animation initialized here to make sure the onPointerDownOutsideFocus
@@ -370,6 +384,9 @@ public class BackAnimationController implements RemoteCallable<BackAnimationCont
        IOnBackInvokedCallback targetCallback = shouldDispatchToLauncher
                ? mBackToLauncherCallback
                : mBackNavigationInfo.getOnBackInvokedCallback();
        if (shouldDispatchToLauncher) {
            startTransition();
        }
        if (mTriggerBack) {
            dispatchOnBackInvoked(targetCallback);
        } else {
@@ -436,6 +453,9 @@ public class BackAnimationController implements RemoteCallable<BackAnimationCont
     * Sets to true when the back gesture has passed the triggering threshold, false otherwise.
     */
    public void setTriggerBack(boolean triggerBack) {
        if (mTransitionInProgress) {
            return;
        }
        mTriggerBack = triggerBack;
    }

@@ -467,6 +487,23 @@ public class BackAnimationController implements RemoteCallable<BackAnimationCont
            mTransaction.remove(screenshotSurface);
        }
        mTransaction.apply();
        stopTransition();
        backNavigationInfo.onBackNavigationFinished(triggerBack);
    }

    private void startTransition() {
        if (mTransitionInProgress) {
            return;
        }
        mTransitionInProgress = true;
        mShellExecutor.executeDelayed(mResetTransitionRunnable, MAX_TRANSITION_DURATION);
    }

    private void stopTransition() {
        if (!mTransitionInProgress) {
            return;
        }
        mShellExecutor.removeCallbacks(mResetTransitionRunnable);
        mTransitionInProgress = false;
    }
}
+44 −1
Original line number Diff line number Diff line
@@ -26,8 +26,10 @@ import static org.mockito.Mockito.atLeastOnce;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.reset;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyNoMoreInteractions;

import android.app.IActivityTaskManager;
import android.app.WindowConfiguration;
@@ -180,7 +182,8 @@ public class BackAnimationControllerTest {
        // b/207481538, we check that the surface is not moved for now, we can re-enable this once
        // we implement the animation
        verify(mTransaction, never()).setScale(eq(screenshotSurface), anyInt(), anyInt());
        verify(mTransaction, never()).setPosition(animationTarget.leash, 100, 100);
        verify(mTransaction, never()).setPosition(
                animationTarget.leash, 100, 100);
        verify(mTransaction, atLeastOnce()).apply();
    }

@@ -251,6 +254,46 @@ public class BackAnimationControllerTest {
        verify(mIOnBackInvokedCallback, never()).onBackInvoked();
    }

    public void ignoresGesture_transitionInProgress() throws RemoteException {
        mController.setBackToLauncherCallback(mIOnBackInvokedCallback);
        RemoteAnimationTarget animationTarget = createAnimationTarget();
        createNavigationInfo(animationTarget, null, null,
                BackNavigationInfo.TYPE_RETURN_TO_HOME, null);

        triggerBackGesture();
        // Check that back invocation is dispatched.
        verify(mIOnBackInvokedCallback).onBackInvoked();

        reset(mIOnBackInvokedCallback);
        // Verify that we prevent animation from restarting if another gestures happens before
        // the previous transition is finished.
        doMotionEvent(MotionEvent.ACTION_DOWN, 0);
        verifyNoMoreInteractions(mIOnBackInvokedCallback);

        // Verify that we start accepting gestures again once transition finishes.
        mController.onBackToLauncherAnimationFinished();
        doMotionEvent(MotionEvent.ACTION_DOWN, 0);
        doMotionEvent(MotionEvent.ACTION_MOVE, 100);
        verify(mIOnBackInvokedCallback).onBackStarted();
    }

    @Test
    public void acceptsGesture_transitionTimeout() throws RemoteException {
        mController.setBackToLauncherCallback(mIOnBackInvokedCallback);
        RemoteAnimationTarget animationTarget = createAnimationTarget();
        createNavigationInfo(animationTarget, null, null,
                BackNavigationInfo.TYPE_RETURN_TO_HOME, null);

        triggerBackGesture();
        reset(mIOnBackInvokedCallback);

        // Simulate transition timeout.
        mShellExecutor.flushAll();
        doMotionEvent(MotionEvent.ACTION_DOWN, 0);
        doMotionEvent(MotionEvent.ACTION_MOVE, 100);
        verify(mIOnBackInvokedCallback).onBackStarted();
    }

    private void doMotionEvent(int actionDown, int coordinate) {
        mController.onMotionEvent(
                MotionEvent.obtain(0, mEventTime, actionDown, coordinate, coordinate, 0),