Add tests for WATCH_OUTSIDE_TOUCH and touches outside windows
These tests document the current behavior on InputDispatcher.
Bug: 214087836
Test: atest inputflinger_tests
Change-Id: Icfa3cab08b117073028156f5535d0f2ea8e82e78
diff --git a/services/inputflinger/tests/InputDispatcher_test.cpp b/services/inputflinger/tests/InputDispatcher_test.cpp
index 470d2f6..a324aa0 100644
--- a/services/inputflinger/tests/InputDispatcher_test.cpp
+++ b/services/inputflinger/tests/InputDispatcher_test.cpp
@@ -55,6 +55,8 @@
static constexpr int32_t POINTER_1_DOWN =
AMOTION_EVENT_ACTION_POINTER_DOWN | (1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT);
+static constexpr int32_t POINTER_2_DOWN =
+ AMOTION_EVENT_ACTION_POINTER_DOWN | (2 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT);
static constexpr int32_t POINTER_1_UP =
AMOTION_EVENT_ACTION_POINTER_UP | (1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT);
@@ -2181,6 +2183,53 @@
}
/**
+ * This test documents the behavior of WATCH_OUTSIDE_TOUCH. The window will get ACTION_OUTSIDE when
+ * a another pointer causes ACTION_DOWN to be sent to another window for the first time. Only one
+ * ACTION_OUTSIDE event is sent per gesture.
+ */
+TEST_F(InputDispatcherTest, ActionOutsideSentOnlyWhenAWindowIsTouched) {
+ // There are three windows that do not overlap. `window` wants to WATCH_OUTSIDE_TOUCH.
+ std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
+ sp<FakeWindowHandle> window =
+ new FakeWindowHandle(application, mDispatcher, "First Window", ADISPLAY_ID_DEFAULT);
+ window->setWatchOutsideTouch(true);
+ window->setFrame(Rect{0, 0, 100, 100});
+ sp<FakeWindowHandle> secondWindow =
+ new FakeWindowHandle(application, mDispatcher, "Second Window", ADISPLAY_ID_DEFAULT);
+ secondWindow->setFrame(Rect{100, 100, 200, 200});
+ sp<FakeWindowHandle> thirdWindow =
+ new FakeWindowHandle(application, mDispatcher, "Third Window", ADISPLAY_ID_DEFAULT);
+ thirdWindow->setFrame(Rect{200, 200, 300, 300});
+ mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {window, secondWindow, thirdWindow}}});
+
+ // First pointer lands outside all windows. `window` does not get ACTION_OUTSIDE.
+ NotifyMotionArgs motionArgs =
+ generateMotionArgs(AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN,
+ ADISPLAY_ID_DEFAULT, {PointF{-10, -10}});
+ mDispatcher->notifyMotion(&motionArgs);
+ window->assertNoEvents();
+ secondWindow->assertNoEvents();
+
+ // The second pointer lands inside `secondWindow`, which should receive a DOWN event.
+ // Now, `window` should get ACTION_OUTSIDE.
+ motionArgs = generateMotionArgs(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
+ {PointF{-10, -10}, PointF{105, 105}});
+ mDispatcher->notifyMotion(&motionArgs);
+ window->consumeMotionOutside();
+ secondWindow->consumeMotionDown();
+ thirdWindow->assertNoEvents();
+
+ // The third pointer lands inside `thirdWindow`, which should receive a DOWN event. There is
+ // no ACTION_OUTSIDE sent to `window` because one has already been sent for this gesture.
+ motionArgs = generateMotionArgs(POINTER_2_DOWN, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
+ {PointF{-10, -10}, PointF{105, 105}, PointF{205, 205}});
+ mDispatcher->notifyMotion(&motionArgs);
+ window->assertNoEvents();
+ secondWindow->consumeMotionMove();
+ thirdWindow->consumeMotionDown();
+}
+
+/**
* Ensure the correct coordinate spaces are used by InputDispatcher.
*
* InputDispatcher works in the display space, so its coordinate system is relative to the display
@@ -6570,9 +6619,7 @@
// Third finger goes down outside all windows, so injection should fail.
const MotionEvent thirdFingerDownEvent =
- MotionEventBuilder(AMOTION_EVENT_ACTION_POINTER_DOWN |
- (2 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT),
- AINPUT_SOURCE_TOUCHSCREEN)
+ MotionEventBuilder(POINTER_2_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
.displayId(ADISPLAY_ID_DEFAULT)
.eventTime(systemTime(SYSTEM_TIME_MONOTONIC))
.pointer(PointerBuilder(/* id */ 0, AMOTION_EVENT_TOOL_TYPE_FINGER)