Merge "Dispatch cancel event to the correct target display" into main
diff --git a/services/inputflinger/dispatcher/InputDispatcher.cpp b/services/inputflinger/dispatcher/InputDispatcher.cpp
index b3be89e..9cd1e09 100644
--- a/services/inputflinger/dispatcher/InputDispatcher.cpp
+++ b/services/inputflinger/dispatcher/InputDispatcher.cpp
@@ -3948,8 +3948,13 @@
<< connection->getInputChannelName().c_str() << reason << LOG_ID_EVENTS;
InputTarget target;
- sp<WindowInfoHandle> windowHandle =
- getWindowHandleLocked(connection->inputChannel->getConnectionToken());
+ sp<WindowInfoHandle> windowHandle;
+ if (options.displayId) {
+ windowHandle = getWindowHandleLocked(connection->inputChannel->getConnectionToken(),
+ options.displayId.value());
+ } else {
+ windowHandle = getWindowHandleLocked(connection->inputChannel->getConnectionToken());
+ }
if (windowHandle != nullptr) {
const WindowInfo* windowInfo = windowHandle->getInfo();
target.setDefaultPointerTransform(windowInfo->transform);
diff --git a/services/inputflinger/tests/InputDispatcher_test.cpp b/services/inputflinger/tests/InputDispatcher_test.cpp
index dd003a6..38970f2 100644
--- a/services/inputflinger/tests/InputDispatcher_test.cpp
+++ b/services/inputflinger/tests/InputDispatcher_test.cpp
@@ -4003,6 +4003,60 @@
}
/**
+ * When there are multiple screens, such as screen projection to TV or screen recording, if the
+ * cancel event occurs, the coordinates of the cancel event should be sent to the target screen, and
+ * its coordinates should be converted by the transform of the windows of target screen.
+ */
+TEST_F(InputDispatcherTest, WhenMultiDisplayWindowSameToken_DispatchCancelToTargetDisplay) {
+ // This case will create a window and a spy window on the default display and mirror
+ // window on the second display. cancel event is sent through spy window pilferPointers
+ std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
+
+ sp<FakeWindowHandle> spyWindowDefaultDisplay =
+ sp<FakeWindowHandle>::make(application, mDispatcher, "Spy", ADISPLAY_ID_DEFAULT);
+ spyWindowDefaultDisplay->setTrustedOverlay(true);
+ spyWindowDefaultDisplay->setSpy(true);
+
+ sp<FakeWindowHandle> windowDefaultDisplay =
+ sp<FakeWindowHandle>::make(application, mDispatcher, "DefaultDisplay",
+ ADISPLAY_ID_DEFAULT);
+ windowDefaultDisplay->setWindowTransform(1, 0, 0, 1);
+
+ sp<FakeWindowHandle> windowSecondDisplay = windowDefaultDisplay->clone(SECOND_DISPLAY_ID);
+ windowSecondDisplay->setWindowTransform(2, 0, 0, 2);
+
+ // Add the windows to the dispatcher
+ mDispatcher->onWindowInfosChanged(
+ {{*spyWindowDefaultDisplay->getInfo(), *windowDefaultDisplay->getInfo(),
+ *windowSecondDisplay->getInfo()},
+ {},
+ 0,
+ 0});
+
+ // Send down to ADISPLAY_ID_DEFAULT
+ ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
+ injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
+ {100, 100}))
+ << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
+
+ spyWindowDefaultDisplay->consumeMotionDown();
+ windowDefaultDisplay->consumeMotionDown();
+
+ EXPECT_EQ(OK, mDispatcher->pilferPointers(spyWindowDefaultDisplay->getToken()));
+
+ // windowDefaultDisplay gets cancel
+ MotionEvent* event = windowDefaultDisplay->consumeMotion();
+ EXPECT_EQ(AMOTION_EVENT_ACTION_CANCEL, event->getAction());
+
+ // The cancel event is sent to windowDefaultDisplay of the ADISPLAY_ID_DEFAULT display, so the
+ // coordinates of the cancel are converted by windowDefaultDisplay's transform, the x and y
+ // coordinates are both 100, otherwise if the cancel event is sent to windowSecondDisplay of
+ // SECOND_DISPLAY_ID, the x and y coordinates are 200
+ EXPECT_EQ(100, event->getX(0));
+ EXPECT_EQ(100, event->getY(0));
+}
+
+/**
* Ensure the correct coordinate spaces are used by InputDispatcher.
*
* InputDispatcher works in the display space, so its coordinate system is relative to the display