summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--core/java/android/view/ViewGroup.java7
-rw-r--r--core/java/android/view/ViewRootImpl.java2
-rw-r--r--core/java/android/window/WindowOnBackInvokedDispatcher.java24
-rw-r--r--core/java/com/android/internal/policy/DecorView.java4
-rw-r--r--core/tests/coretests/src/android/window/WindowOnBackInvokedDispatcherTest.java35
5 files changed, 51 insertions, 21 deletions
diff --git a/core/java/android/view/ViewGroup.java b/core/java/android/view/ViewGroup.java
index 11ad86c2b95d..ab529e6fe60a 100644
--- a/core/java/android/view/ViewGroup.java
+++ b/core/java/android/view/ViewGroup.java
@@ -2654,9 +2654,10 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager
ViewRootImpl viewRootImpl = getViewRootImpl();
if (actionMasked == MotionEvent.ACTION_DOWN || mFirstTouchTarget != null) {
final boolean disallowIntercept = (mGroupFlags & FLAG_DISALLOW_INTERCEPT) != 0;
- final boolean isDispatchingBack = (viewRootImpl != null
- && viewRootImpl.getOnBackInvokedDispatcher().isDispatching());
- if (!disallowIntercept || isDispatchingBack) { // Allow back to intercept touch
+ final boolean isBackGestureInProgress = (viewRootImpl != null
+ && viewRootImpl.getOnBackInvokedDispatcher().isBackGestureInProgress());
+ if (!disallowIntercept || isBackGestureInProgress) {
+ // Allow back to intercept touch
intercepted = onInterceptTouchEvent(ev);
ev.setAction(action); // restore action in case it was changed
} else {
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index f51d909e9e8b..63121bd8800c 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -7228,7 +7228,7 @@ public final class ViewRootImpl implements ViewParent,
private int doOnBackKeyEvent(KeyEvent keyEvent) {
WindowOnBackInvokedDispatcher dispatcher = getOnBackInvokedDispatcher();
OnBackInvokedCallback topCallback = dispatcher.getTopCallback();
- if (dispatcher.isDispatching()) {
+ if (dispatcher.isBackGestureInProgress()) {
return FINISH_NOT_HANDLED;
}
if (topCallback instanceof OnBackAnimationCallback) {
diff --git a/core/java/android/window/WindowOnBackInvokedDispatcher.java b/core/java/android/window/WindowOnBackInvokedDispatcher.java
index cf0c0159bccd..e351d6ba3e56 100644
--- a/core/java/android/window/WindowOnBackInvokedDispatcher.java
+++ b/core/java/android/window/WindowOnBackInvokedDispatcher.java
@@ -114,7 +114,7 @@ public class WindowOnBackInvokedDispatcher implements OnBackInvokedDispatcher {
/** Updates the dispatcher state on a new {@link MotionEvent}. */
public void onMotionEvent(MotionEvent ev) {
- if (!isDispatching() || ev == null || ev.getAction() != MotionEvent.ACTION_MOVE) {
+ if (!isBackGestureInProgress() || ev == null || ev.getAction() != MotionEvent.ACTION_MOVE) {
return;
}
mTouchTracker.update(ev.getX(), ev.getY(), Float.NaN, Float.NaN);
@@ -246,9 +246,9 @@ public class WindowOnBackInvokedDispatcher implements OnBackInvokedDispatcher {
}
/**
- * Indicates if the dispatcher is actively dispatching to a callback.
+ * Indicates if a user gesture is currently in progress.
*/
- public boolean isDispatching() {
+ public boolean isBackGestureInProgress() {
synchronized (mLock) {
return mTouchTracker.isActive() || mImeDispatchingActive;
}
@@ -475,12 +475,17 @@ public class WindowOnBackInvokedDispatcher implements OnBackInvokedDispatcher {
@Override
public void onBackStarted(BackMotionEvent backEvent) {
mHandler.post(() -> {
+ final OnBackAnimationCallback callback = getBackAnimationCallback();
+
+ // reset progress animator before dispatching onBackStarted to callback. This
+ // ensures that onBackCancelled (of a previous gesture) is always dispatched
+ // before onBackStarted
+ if (callback != null) mProgressAnimator.reset();
mTouchTracker.setState(BackTouchTracker.TouchTrackerState.ACTIVE);
mTouchTracker.setShouldUpdateStartLocation(true);
mTouchTracker.setGestureStartLocation(
backEvent.getTouchX(), backEvent.getTouchY(), backEvent.getSwipeEdge());
- final OnBackAnimationCallback callback = getBackAnimationCallback();
if (callback != null) {
callback.onBackStarted(new BackEvent(
backEvent.getTouchX(),
@@ -499,14 +504,9 @@ public class WindowOnBackInvokedDispatcher implements OnBackInvokedDispatcher {
public void onBackCancelled() {
mHandler.post(() -> {
final OnBackAnimationCallback callback = getBackAnimationCallback();
- if (callback == null) {
- mTouchTracker.reset();
- return;
- }
- mProgressAnimator.onBackCancelled(() -> {
- mTouchTracker.reset();
- callback.onBackCancelled();
- });
+ mTouchTracker.reset();
+ if (callback == null) return;
+ mProgressAnimator.onBackCancelled(callback::onBackCancelled);
});
}
diff --git a/core/java/com/android/internal/policy/DecorView.java b/core/java/com/android/internal/policy/DecorView.java
index f4315e3988ac..74c2325d45a2 100644
--- a/core/java/com/android/internal/policy/DecorView.java
+++ b/core/java/com/android/internal/policy/DecorView.java
@@ -523,8 +523,8 @@ public class DecorView extends FrameLayout implements RootViewSurfaceTaker, Wind
ViewRootImpl viewRootImpl = getViewRootImpl();
if (viewRootImpl != null) {
viewRootImpl.getOnBackInvokedDispatcher().onMotionEvent(event);
- // Intercept touch if back dispatching is active.
- if (viewRootImpl.getOnBackInvokedDispatcher().isDispatching()) {
+ // Intercept touch if back gesture is in progress.
+ if (viewRootImpl.getOnBackInvokedDispatcher().isBackGestureInProgress()) {
return true;
}
}
diff --git a/core/tests/coretests/src/android/window/WindowOnBackInvokedDispatcherTest.java b/core/tests/coretests/src/android/window/WindowOnBackInvokedDispatcherTest.java
index 1a8e75a6554d..d54b862dfd34 100644
--- a/core/tests/coretests/src/android/window/WindowOnBackInvokedDispatcherTest.java
+++ b/core/tests/coretests/src/android/window/WindowOnBackInvokedDispatcherTest.java
@@ -51,6 +51,7 @@ import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
+import org.mockito.InOrder;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.MockitoAnnotations;
@@ -372,6 +373,34 @@ public class WindowOnBackInvokedDispatcherTest {
}
@Test
+ public void onBackCancelled_calledBeforeOnBackStartedOfNewGesture() throws RemoteException {
+ mDispatcher.registerOnBackInvokedCallback(PRIORITY_DEFAULT, mCallback1);
+ OnBackInvokedCallbackInfo callbackInfo = assertSetCallbackInfo();
+
+ callbackInfo.getCallback().onBackStarted(mBackEvent);
+
+ waitForIdle();
+ verify(mCallback1).onBackStarted(any(BackEvent.class));
+ clearInvocations(mCallback1);
+
+ callbackInfo.getCallback().onBackCancelled();
+
+ waitForIdle();
+ // verify onBackCancelled not yet called (since BackProgressAnimator animates
+ // progress to 0 first)
+ verify(mCallback1, never()).onBackCancelled();
+
+ // simulate start of new gesture while cancel animation is still running
+ callbackInfo.getCallback().onBackStarted(mBackEvent);
+ waitForIdle();
+
+ // verify that onBackCancelled is called before onBackStarted
+ InOrder orderVerifier = Mockito.inOrder(mCallback1);
+ orderVerifier.verify(mCallback1).onBackCancelled();
+ orderVerifier.verify(mCallback1).onBackStarted(any(BackEvent.class));
+ }
+
+ @Test
public void onDetachFromWindow_cancelCallbackAndIgnoreOnBackInvoked() throws RemoteException {
mDispatcher.registerOnBackInvokedCallback(PRIORITY_DEFAULT, mCallback1);
@@ -399,11 +428,11 @@ public class WindowOnBackInvokedDispatcherTest {
callbackInfo.getCallback().onBackStarted(mBackEvent);
waitForIdle();
- assertTrue(mDispatcher.isDispatching());
+ assertTrue(mDispatcher.isBackGestureInProgress());
callbackInfo.getCallback().onBackInvoked();
waitForIdle();
- assertFalse(mDispatcher.isDispatching());
+ assertFalse(mDispatcher.isBackGestureInProgress());
}
@Test
@@ -418,7 +447,7 @@ public class WindowOnBackInvokedDispatcherTest {
callbackInfo.getCallback().onBackStarted(mBackEvent);
waitForIdle();
- assertTrue(mDispatcher.isDispatching());
+ assertTrue(mDispatcher.isBackGestureInProgress());
assertTrue(mDispatcher.mTouchTracker.isActive());
main.runWithScissors(() -> mDispatcher.onMotionEvent(mMotionEvent), 100);