summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author omarmt <omarmt@google.com> 2023-05-09 16:01:53 +0000
committer Omar Miatello <omarmt@google.com> 2023-05-12 08:20:33 +0000
commit11fccc4afb99a143a2f84668787102995414976a (patch)
treefdd5d8ccdf1e0479a5df5be468dfbe072669b1a4
parent3e1928ca21cb4ae402874805acc9de128ee6b08a (diff)
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
-rw-r--r--core/java/android/window/BackProgressAnimator.java15
-rw-r--r--core/java/android/window/WindowOnBackInvokedDispatcher.java10
-rw-r--r--core/tests/coretests/src/android/window/WindowOnBackInvokedDispatcherTest.java21
3 files changed, 41 insertions, 5 deletions
diff --git a/core/java/android/window/BackProgressAnimator.java b/core/java/android/window/BackProgressAnimator.java
index 618670a0a2c4..e58c044730ae 100644
--- a/core/java/android/window/BackProgressAnimator.java
+++ b/core/java/android/window/BackProgressAnimator.java
@@ -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(
diff --git a/core/java/android/window/WindowOnBackInvokedDispatcher.java b/core/java/android/window/WindowOnBackInvokedDispatcher.java
index 4d0132e46ba7..22b2ec09c034 100644
--- a/core/java/android/window/WindowOnBackInvokedDispatcher.java
+++ b/core/java/android/window/WindowOnBackInvokedDispatcher.java
@@ -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());
}
}
diff --git a/core/tests/coretests/src/android/window/WindowOnBackInvokedDispatcherTest.java b/core/tests/coretests/src/android/window/WindowOnBackInvokedDispatcherTest.java
index cde100cc20aa..8e772a2d1845 100644
--- a/core/tests/coretests/src/android/window/WindowOnBackInvokedDispatcherTest.java
+++ b/core/tests/coretests/src/android/window/WindowOnBackInvokedDispatcherTest.java
@@ -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);
+ }
}