Add tests that activity can receive ACTION_CANCEL after onBackStarted
Add tests for
1. Activity not opt-in predictive back
2. Activity opt-in predictive back and
- with default onBackInvokedCallback
- register it's own onBackInvokedCallback
The activity should receive ACTION_CANCEL in above conditions once the
back gesture across the threshold.
Flag: com.android.window.flags.intercept_motion_from_move_to_cancel
Bug: 404173501
Test: atest OnBackInvokedCallbackGestureTest
Change-Id: Ia63d4f886e02206c32094791ae5badd0b65e658a
diff --git a/tests/framework/base/windowmanager/AndroidManifest.xml b/tests/framework/base/windowmanager/AndroidManifest.xml
index dd74b12..ad4e14d 100644
--- a/tests/framework/base/windowmanager/AndroidManifest.xml
+++ b/tests/framework/base/windowmanager/AndroidManifest.xml
@@ -628,6 +628,9 @@
<activity android:name="android.server.wm.backnavigation.BackNavigationActivity"
android:enableOnBackInvokedCallback="true"
android:exported="true"/>
+ <activity android:name="android.server.wm.backnavigation.OptOutBackNavigationActivity"
+ android:enableOnBackInvokedCallback="false"
+ android:exported="true"/>
<activity android:name="android.server.wm.other.PinnedStackTests$TestActivity"
android:exported="true"/>
<activity android:name="android.server.wm.taskfragment.TaskFragmentTrustedModeTest$TranslucentActivity"
diff --git a/tests/framework/base/windowmanager/src/android/server/wm/backnavigation/BackNavigationActivity.java b/tests/framework/base/windowmanager/src/android/server/wm/backnavigation/BackNavigationActivity.java
index 97b6e25..444afa3 100644
--- a/tests/framework/base/windowmanager/src/android/server/wm/backnavigation/BackNavigationActivity.java
+++ b/tests/framework/base/windowmanager/src/android/server/wm/backnavigation/BackNavigationActivity.java
@@ -18,17 +18,22 @@
import android.app.Activity;
import android.os.Bundle;
+import android.view.MotionEvent;
import androidx.annotation.Nullable;
+import java.util.concurrent.CountDownLatch;
+
public class BackNavigationActivity extends Activity {
boolean mOnBackPressedCalled;
boolean mOnUserInteractionCalled;
+ CountDownLatch mReceiveMotionCancel;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
+ mReceiveMotionCancel = new CountDownLatch(1);
}
@Override
@@ -42,4 +47,12 @@
mOnUserInteractionCalled = true;
super.onUserInteraction();
}
+
+ @Override
+ public boolean onTouchEvent(MotionEvent event) {
+ if (event.getAction() == MotionEvent.ACTION_CANCEL) {
+ mReceiveMotionCancel.countDown();
+ }
+ return super.onTouchEvent(event);
+ }
}
diff --git a/tests/framework/base/windowmanager/src/android/server/wm/backnavigation/OnBackInvokedCallbackGestureTest.java b/tests/framework/base/windowmanager/src/android/server/wm/backnavigation/OnBackInvokedCallbackGestureTest.java
index 3532c7d..45d14b6 100644
--- a/tests/framework/base/windowmanager/src/android/server/wm/backnavigation/OnBackInvokedCallbackGestureTest.java
+++ b/tests/framework/base/windowmanager/src/android/server/wm/backnavigation/OnBackInvokedCallbackGestureTest.java
@@ -21,6 +21,7 @@
import static android.window.OnBackInvokedDispatcher.PRIORITY_DEFAULT;
import static android.window.OnBackInvokedDispatcher.PRIORITY_SYSTEM_NAVIGATION_OBSERVER;
+import static com.android.window.flags.Flags.FLAG_INTERCEPT_MOTION_FROM_MOVE_TO_CANCEL;
import static com.android.window.flags.Flags.FLAG_PREDICTIVE_BACK_PRIORITY_SYSTEM_NAVIGATION_OBSERVER;
import static com.android.window.flags.Flags.FLAG_PREDICTIVE_BACK_SWIPE_EDGE_NONE_API;
import static com.android.window.flags.Flags.FLAG_PREDICTIVE_BACK_SYSTEM_OVERRIDE_CALLBACK;
@@ -377,6 +378,75 @@
}
@Test
+ @RequiresFlagsEnabled(FLAG_INTERCEPT_MOTION_FROM_MOVE_TO_CANCEL)
+ public void testReceiveCancelEvent_default_cancel() throws InterruptedException {
+ testReceivedCancelEvent(mActivity, false, false);
+ }
+
+ @Test
+ @RequiresFlagsEnabled(FLAG_INTERCEPT_MOTION_FROM_MOVE_TO_CANCEL)
+ public void testReceiveCancelEvent_default_finish() throws InterruptedException {
+ testReceivedCancelEvent(mActivity, false, true);
+ }
+
+ @Test
+ @RequiresFlagsEnabled(FLAG_INTERCEPT_MOTION_FROM_MOVE_TO_CANCEL)
+ public void testReceiveCancelEvent_override_cancel() throws InterruptedException {
+ testReceivedCancelEvent(mActivity, true, false);
+ }
+
+ @Test
+ @RequiresFlagsEnabled(FLAG_INTERCEPT_MOTION_FROM_MOVE_TO_CANCEL)
+ public void testReceiveCancelEvent_override_finish() throws InterruptedException {
+ testReceivedCancelEvent(mActivity, true, true);
+ }
+
+ @Test
+ @RequiresFlagsEnabled(FLAG_INTERCEPT_MOTION_FROM_MOVE_TO_CANCEL)
+ public void testOptOutActivityReceiveCancelEvent_cancel() throws InterruptedException {
+ try (TestActivitySession<OptOutBackNavigationActivity> activitySession =
+ createManagedTestActivitySession()) {
+ activitySession.launchTestActivityOnDisplaySync(
+ OptOutBackNavigationActivity.class, DEFAULT_DISPLAY);
+ mWmState.waitForAppTransitionIdleOnDisplay(DEFAULT_DISPLAY);
+ final OptOutBackNavigationActivity activity = activitySession.getActivity();
+ testReceivedCancelEvent(activity, false, false);
+ }
+ }
+
+ @Test
+ @RequiresFlagsEnabled(FLAG_INTERCEPT_MOTION_FROM_MOVE_TO_CANCEL)
+ public void testOptOutActivityReceiveCancelEvent_finish() throws InterruptedException {
+ try (TestActivitySession<OptOutBackNavigationActivity> activitySession =
+ createManagedTestActivitySession()) {
+ activitySession.launchTestActivityOnDisplaySync(
+ OptOutBackNavigationActivity.class, DEFAULT_DISPLAY);
+ mWmState.waitForAppTransitionIdleOnDisplay(DEFAULT_DISPLAY);
+ final OptOutBackNavigationActivity activity = activitySession.getActivity();
+ testReceivedCancelEvent(activity, false, true);
+ }
+ }
+
+ private void testReceivedCancelEvent(
+ BackNavigationActivity activity, boolean registerCallback, boolean finishGesture)
+ throws InterruptedException {
+ if (registerCallback) {
+ registerBackCallback(activity, mAnimationCallback, PRIORITY_DEFAULT);
+ }
+ int midHeight = mUiDevice.getDisplayHeight() / 2;
+ int midWidth = mUiDevice.getDisplayWidth() / 2;
+
+ mTouchSwipeSession.beginSwipe(0, midHeight);
+ mTouchSwipeSession.continueSwipe(midWidth, midHeight, PROGRESS_SWIPE_STEPS);
+ if (finishGesture) {
+ mTouchSwipeSession.finishSwipe();
+ } else {
+ mTouchSwipeSession.cancelSwipe();
+ }
+ assertInvoked(activity.mReceiveMotionCancel);
+ }
+
+ @Test
public void ignoresKeyCodeBackDuringDispatch() throws InterruptedException {
registerBackCallback(mActivity, mAnimationCallback, PRIORITY_DEFAULT);
int midHeight = mUiDevice.getDisplayHeight() / 2;
diff --git a/tests/framework/base/windowmanager/src/android/server/wm/backnavigation/OptOutBackNavigationActivity.java b/tests/framework/base/windowmanager/src/android/server/wm/backnavigation/OptOutBackNavigationActivity.java
new file mode 100644
index 0000000..76e82f1
--- /dev/null
+++ b/tests/framework/base/windowmanager/src/android/server/wm/backnavigation/OptOutBackNavigationActivity.java
@@ -0,0 +1,19 @@
+/*
+ * Copyright (C) 2025 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.server.wm.backnavigation;
+
+public class OptOutBackNavigationActivity extends BackNavigationActivity {}