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
This commit is contained in:
@@ -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(
|
||||
|
||||
@@ -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());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user