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

Commit 11fccc4a authored by omarmt's avatar omarmt Committed by Omar Miatello
Browse files

Call onBackCancelled() when an active callback is removed from the WindowOnBackInvokedDispatcher

When an OnBackInvokedCallback is unregistered from a WindowOnBackInvokedDispatcher, it is important to check if the callback is the current top one and if the back animation is in progress. If it is, we should call onBackCancelled() on the callback as a final step.

Test: atest WindowOnBackInvokedDispatcherTest
Bug: 276816667
Change-Id: Icaf98899c474c4e8d89d4a9c77acc309d37e9582
parent 3e1928ca
Loading
Loading
Loading
Loading
+10 −5
Original line number Diff line number Diff line
@@ -43,7 +43,7 @@ public class BackProgressAnimator {
    private ProgressCallback mCallback;
    private float mProgress = 0;
    private BackMotionEvent mLastBackEvent;
    private boolean mStarted = false;
    private boolean mBackAnimationInProgress = false;

    private void setProgress(float progress) {
        mProgress = progress;
@@ -87,7 +87,7 @@ public class BackProgressAnimator {
     * @param event the {@link BackMotionEvent} containing the latest target progress.
     */
    public void onBackProgressed(BackMotionEvent event) {
        if (!mStarted) {
        if (!mBackAnimationInProgress) {
            return;
        }
        mLastBackEvent = event;
@@ -108,7 +108,7 @@ public class BackProgressAnimator {
        reset();
        mLastBackEvent = event;
        mCallback = callback;
        mStarted = true;
        mBackAnimationInProgress = true;
    }

    /**
@@ -122,7 +122,7 @@ public class BackProgressAnimator {
            // Should never happen.
            mSpring.cancel();
        }
        mStarted = false;
        mBackAnimationInProgress = false;
        mLastBackEvent = null;
        mCallback = null;
        mProgress = 0;
@@ -149,8 +149,13 @@ public class BackProgressAnimator {
        mSpring.animateToFinalPosition(0);
    }

    /** Returns true if the back animation is in progress. */
    boolean isBackAnimationInProgress() {
        return mBackAnimationInProgress;
    }

    private void updateProgressValue(float progress) {
        if (mLastBackEvent == null || mCallback == null || !mStarted) {
        if (mLastBackEvent == null || mCallback == null || !mBackAnimationInProgress) {
            return;
        }
        mCallback.onProgressUpdate(
+10 −0
Original line number Diff line number Diff line
@@ -158,6 +158,16 @@ public class WindowOnBackInvokedDispatcher implements OnBackInvokedDispatcher {
        mAllCallbacks.remove(callback);
        // Re-populate the top callback to WM if the removed callback was previously the top one.
        if (previousTopCallback == callback) {
            // We should call onBackCancelled() when an active callback is removed from dispatcher.
            if (mProgressAnimator.isBackAnimationInProgress()
                    && callback instanceof OnBackAnimationCallback) {
                // The ProgressAnimator will handle the new topCallback, so we don't want to call
                // onBackCancelled() on it. We call immediately the callback instead.
                OnBackAnimationCallback animatedCallback = (OnBackAnimationCallback) callback;
                animatedCallback.onBackCancelled();
                Log.d(TAG, "The callback was removed while a back animation was in progress, "
                        + "an onBackCancelled() was dispatched.");
            }
            setTopOnBackInvokedCallback(getTopCallback());
        }
    }
+21 −0
Original line number Diff line number Diff line
@@ -173,4 +173,25 @@ public class WindowOnBackInvokedDispatcherTest {
        waitForIdle();
        verify(mCallback2).onBackStarted(any(BackEvent.class));
    }

    @Test
    public void onUnregisterWhileBackInProgress_callOnBackCancelled() throws RemoteException {
        ArgumentCaptor<OnBackInvokedCallbackInfo> captor =
                ArgumentCaptor.forClass(OnBackInvokedCallbackInfo.class);

        mDispatcher.registerOnBackInvokedCallback(
                OnBackInvokedDispatcher.PRIORITY_DEFAULT, mCallback1);

        verify(mWindowSession).setOnBackInvokedCallbackInfo(
                Mockito.eq(mWindow),
                captor.capture());
        IOnBackInvokedCallback iOnBackInvokedCallback = captor.getValue().getCallback();
        iOnBackInvokedCallback.onBackStarted(mBackEvent);
        waitForIdle();
        verify(mCallback1).onBackStarted(any(BackEvent.class));

        mDispatcher.unregisterOnBackInvokedCallback(mCallback1);
        verify(mCallback1).onBackCancelled();
        verifyNoMoreInteractions(mCallback1);
    }
}