InputDispatcher: Do not drop ongoing gesture if a window is no longer a spy
The old InputDispatcher policy was that for all touch events, there had
to be at least one touched foreground window or spy window. If not, we
dropped the event.
This caused events to be dropped if a handwriting interceptor spy window
changed its configuration mid-gesture to no longer be a spy. To get
around this, we define non-touchable and spy windows as windows that
"cannot be foreground", and require at least one touched foreground
window or at least one touched window that cannot be foreground.
Bug: 221908983
Test: atest inputflinger_tests
Test: manual: ensure Scribe works
Change-Id: If5fcbf6f4f784184377434f71f1ac121517b023a
diff --git a/services/inputflinger/tests/InputDispatcher_test.cpp b/services/inputflinger/tests/InputDispatcher_test.cpp
index 838e6aa..bf58705 100644
--- a/services/inputflinger/tests/InputDispatcher_test.cpp
+++ b/services/inputflinger/tests/InputDispatcher_test.cpp
@@ -6915,4 +6915,38 @@
window->assertNoEvents();
}
+/**
+ * Set up a scenario to test the behavior used by the stylus handwriting detection feature.
+ * The scenario is as follows:
+ * - The stylus interceptor overlay is configured as a spy window.
+ * - The stylus interceptor spy receives the start of a new stylus gesture.
+ * - It pilfers pointers and then configures itself to no longer be a spy.
+ * - The stylus interceptor continues to receive the rest of the gesture.
+ */
+TEST_F(InputDispatcherStylusInterceptorTest, StylusHandwritingScenario) {
+ auto [overlay, window] = setupStylusOverlayScenario();
+ overlay->setSpy(true);
+ mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {overlay, window}}});
+
+ sendStylusEvent(AMOTION_EVENT_ACTION_DOWN);
+ overlay->consumeMotionDown();
+ window->consumeMotionDown();
+
+ // The interceptor pilfers the pointers.
+ EXPECT_EQ(OK, mDispatcher->pilferPointers(overlay->getToken()));
+ window->consumeMotionCancel();
+
+ // The interceptor configures itself so that it is no longer a spy.
+ overlay->setSpy(false);
+ mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {overlay, window}}});
+
+ // It continues to receive the rest of the stylus gesture.
+ sendStylusEvent(AMOTION_EVENT_ACTION_MOVE);
+ overlay->consumeMotionMove();
+ sendStylusEvent(AMOTION_EVENT_ACTION_UP);
+ overlay->consumeMotionUp();
+
+ window->assertNoEvents();
+}
+
} // namespace android::inputdispatcher