[4/n CD Cursor] Use Pointer's display transform for motion events
We assume window's display id always matches pointer's display which is
no longer true. This can lead to motion events being incorrectly
transformed.
In this CL we update raw transform to use pointer's display instead to
ensure raw coordinates are always in pointer's display coordinate space.
Test: atest inputflinger_tests
Bug: 362719483
Flag: com.android.input.flags.connected_displays_cursor
Change-Id: If450ae1697bfac852b18c46a983ee75183f4c940
diff --git a/services/inputflinger/dispatcher/InputDispatcher.cpp b/services/inputflinger/dispatcher/InputDispatcher.cpp
index f0a627c..a2543b1 100644
--- a/services/inputflinger/dispatcher/InputDispatcher.cpp
+++ b/services/inputflinger/dispatcher/InputDispatcher.cpp
@@ -1491,13 +1491,11 @@
if (info.inputConfig.test(WindowInfo::InputConfig::WATCH_OUTSIDE_TOUCH)) {
std::bitset<MAX_POINTER_ID + 1> pointerIds;
pointerIds.set(pointerId);
- DispatcherTouchState::addPointerWindowTarget(windowHandle,
- InputTarget::DispatchMode::OUTSIDE,
- ftl::Flags<InputTarget::Flags>(),
- pointerIds,
- /*firstDownTimeInTarget=*/std::nullopt,
- connections, windowInfos, dump,
- outsideTargets);
+ addPointerWindowTarget(windowHandle, InputTarget::DispatchMode::OUTSIDE,
+ ftl::Flags<InputTarget::Flags>(), pointerIds,
+ /*firstDownTimeInTarget=*/std::nullopt,
+ /*pointerDisplayId=*/std::nullopt, connections, windowInfos,
+ dump, outsideTargets);
}
}
return outsideTargets;
@@ -2612,12 +2610,12 @@
const TouchedWindow& touchedWindow =
tempTouchState.getTouchedWindow(oldTouchedWindowHandle);
- DispatcherTouchState::
- addPointerWindowTarget(oldTouchedWindowHandle,
- InputTarget::DispatchMode::SLIPPERY_EXIT,
- ftl::Flags<InputTarget::Flags>(), pointerIds,
- touchedWindow.getDownTimeInTarget(entry.deviceId),
- connections, windowInfos, dump, targets);
+ addPointerWindowTarget(oldTouchedWindowHandle,
+ InputTarget::DispatchMode::SLIPPERY_EXIT,
+ ftl::Flags<InputTarget::Flags>(), pointerIds,
+ touchedWindow.getDownTimeInTarget(entry.deviceId),
+ /*pointerDisplayId=*/std::nullopt, connections, windowInfos,
+ dump, targets);
// Make a slippery entrance into the new window.
@@ -2666,12 +2664,11 @@
std::bitset<MAX_POINTER_ID + 1> pointerIds;
pointerIds.set(entry.pointerProperties[0].id);
for (const TouchedWindow& touchedWindow : hoveringWindows) {
- DispatcherTouchState::addPointerWindowTarget(touchedWindow.windowHandle,
- touchedWindow.dispatchMode,
- touchedWindow.targetFlags, pointerIds,
- touchedWindow.getDownTimeInTarget(
- entry.deviceId),
- connections, windowInfos, dump, targets);
+ addPointerWindowTarget(touchedWindow.windowHandle, touchedWindow.dispatchMode,
+ touchedWindow.targetFlags, pointerIds,
+ touchedWindow.getDownTimeInTarget(entry.deviceId),
+ /*pointerDisplayId=*/std::nullopt, connections, windowInfos,
+ dump, targets);
}
}
@@ -2724,13 +2721,11 @@
if (touchingPointers.empty()) {
continue;
}
- DispatcherTouchState::addPointerWindowTarget(touchedWindow.windowHandle,
- touchedWindow.dispatchMode,
- touchedWindow.targetFlags,
- getPointerIds(touchingPointers),
- touchedWindow.getDownTimeInTarget(
- entry.deviceId),
- connections, windowInfos, dump, targets);
+ addPointerWindowTarget(touchedWindow.windowHandle, touchedWindow.dispatchMode,
+ touchedWindow.targetFlags, getPointerIds(touchingPointers),
+ touchedWindow.getDownTimeInTarget(entry.deviceId),
+ /*pointerDisplayId=*/displayId, connections, windowInfos, dump,
+ targets);
}
// During targeted injection, only allow owned targets to receive events
@@ -2933,8 +2928,9 @@
const sp<android::gui::WindowInfoHandle>& windowHandle,
InputTarget::DispatchMode dispatchMode, ftl::Flags<InputTarget::Flags> targetFlags,
std::bitset<MAX_POINTER_ID + 1> pointerIds, std::optional<nsecs_t> firstDownTimeInTarget,
- const ConnectionManager& connections, const DispatcherWindowInfo& windowInfos,
- std::function<void()> dump, std::vector<InputTarget>& inputTargets) {
+ std::optional<ui::LogicalDisplayId> pointerDisplayId, const ConnectionManager& connections,
+ const DispatcherWindowInfo& windowInfos, std::function<void()> dump,
+ std::vector<InputTarget>& inputTargets) {
if (pointerIds.none()) {
for (const auto& target : inputTargets) {
LOG(INFO) << "Target: " << target;
@@ -2969,7 +2965,8 @@
}
inputTargets.push_back(
createInputTarget(connection, windowHandle, dispatchMode, targetFlags,
- windowInfos.getRawTransform(*windowHandle->getInfo()),
+ windowInfos.getRawTransform(*windowHandle->getInfo(),
+ pointerDisplayId),
firstDownTimeInTarget));
it = inputTargets.end() - 1;
}
@@ -4172,8 +4169,9 @@
DispatcherTouchState::
addPointerWindowTarget(window, InputTarget::DispatchMode::AS_IS,
ftl::Flags<InputTarget::Flags>(), pointerIds,
- motionEntry.downTime, mConnectionManager,
- mWindowInfos,
+ motionEntry.downTime,
+ /*pointerDisplayId=*/std::nullopt,
+ mConnectionManager, mWindowInfos,
std::bind_front(&InputDispatcher::
logDispatchStateLocked,
this),
@@ -4259,6 +4257,7 @@
DispatcherTouchState::
addPointerWindowTarget(windowHandle, InputTarget::DispatchMode::AS_IS,
targetFlags, pointerIds, motionEntry.downTime,
+ /*pointerDisplayId=*/std::nullopt,
mConnectionManager, mWindowInfos,
std::bind_front(&InputDispatcher::
logDispatchStateLocked,
@@ -5171,13 +5170,24 @@
}
ui::Transform InputDispatcher::DispatcherWindowInfo::getRawTransform(
- const android::gui::WindowInfo& windowInfo) const {
+ const android::gui::WindowInfo& windowInfo,
+ std::optional<ui::LogicalDisplayId> pointerDisplayId) const {
+ // TODO(b/383092013): Handle TOPOLOGY_AWARE window flag.
+ // For now, we assume all windows are topology-aware and can handle cross-display streams.
+ if (com::android::input::flags::connected_displays_cursor() && pointerDisplayId.has_value() &&
+ *pointerDisplayId != windowInfo.displayId) {
+ // Sending pointer to a different display than the window. This is a
+ // cross-display drag gesture, so always use the new display's transform.
+ return getDisplayTransform(*pointerDisplayId);
+ }
// If the window has a cloneLayerStackTransform, always use it as the transform for the "getRaw"
- // APIs. If not, fall back to using the DisplayInfo transform of the window's display.
- return (input_flags::use_cloned_screen_coordinates_as_raw() &&
- windowInfo.cloneLayerStackTransform)
- ? *windowInfo.cloneLayerStackTransform
- : getDisplayTransform(windowInfo.displayId);
+ // APIs. If not, fall back to using the DisplayInfo transform of the window's display
+ bool useClonedScreenCoordinates = (input_flags::use_cloned_screen_coordinates_as_raw() &&
+ windowInfo.cloneLayerStackTransform);
+ if (useClonedScreenCoordinates) {
+ return *windowInfo.cloneLayerStackTransform;
+ }
+ return getDisplayTransform(windowInfo.displayId);
}
ui::LogicalDisplayId InputDispatcher::DispatcherWindowInfo::getPrimaryDisplayId(
@@ -7100,7 +7110,8 @@
oldTouchedWindow.targetFlags,
getPointerIds(pointers),
oldTouchedWindow.getDownTimeInTarget(deviceId),
- connections, windowInfos, dump, targets);
+ /*pointerDisplayId=*/std::nullopt, connections,
+ windowInfos, dump, targets);
state.removeTouchingPointerFromWindow(deviceId, pointerProperties.id, oldWallpaper);
}
diff --git a/services/inputflinger/dispatcher/InputDispatcher.h b/services/inputflinger/dispatcher/InputDispatcher.h
index d765a86..a949900 100644
--- a/services/inputflinger/dispatcher/InputDispatcher.h
+++ b/services/inputflinger/dispatcher/InputDispatcher.h
@@ -307,8 +307,11 @@
// Get the transform for display, returns Identity-transform if display is missing.
ui::Transform getDisplayTransform(ui::LogicalDisplayId displayId) const;
- // Get the raw transform to use for motion events going to the given window.
- ui::Transform getRawTransform(const android::gui::WindowInfo&) const;
+ // Get the raw transform to use for motion events going to the given window. Optionally a
+ // pointer displayId may be supplied if pointer is on a different display from the window.
+ ui::Transform getRawTransform(
+ const android::gui::WindowInfo& windowInfo,
+ std::optional<ui::LogicalDisplayId> pointerDisplayId = std::nullopt) const;
// Lookup for WindowInfoHandle from token and optionally a display-id. In cases where
// display-id is not provided lookup is done for all displays.
@@ -379,6 +382,7 @@
ftl::Flags<InputTarget::Flags> targetFlags,
std::bitset<MAX_POINTER_ID + 1> pointerIds,
std::optional<nsecs_t> firstDownTimeInTarget,
+ std::optional<ui::LogicalDisplayId> pointerDisplayId,
const ConnectionManager& connections,
const DispatcherWindowInfo& windowInfos,
std::function<void()> dump,
diff --git a/services/inputflinger/tests/InputDispatcher_test.cpp b/services/inputflinger/tests/InputDispatcher_test.cpp
index 0c72d76..7e7d954 100644
--- a/services/inputflinger/tests/InputDispatcher_test.cpp
+++ b/services/inputflinger/tests/InputDispatcher_test.cpp
@@ -15207,7 +15207,17 @@
"Window", DISPLAY_ID);
mWindow->setFrame({0, 0, 100, 100});
- mDispatcher->onWindowInfosChanged({{*mWindow->getInfo()}, {}, 0, 0});
+ gui::DisplayInfo displayInfo1;
+ displayInfo1.displayId = DISPLAY_ID;
+
+ ui::Transform transform(ui::Transform::ROT_270, /*logicalDisplayWidth=*/500,
+ /*logicalDisplayHeight=*/500);
+ gui::DisplayInfo displayInfo2;
+ displayInfo2.displayId = SECOND_DISPLAY_ID;
+ displayInfo2.transform = transform;
+
+ mDispatcher->onWindowInfosChanged(
+ {{*mWindow->getInfo()}, {displayInfo1, displayInfo2}, 0, 0});
}
};
@@ -15250,8 +15260,9 @@
.buttonState(AMOTION_EVENT_BUTTON_PRIMARY)
.pointer(PointerBuilder(0, ToolType::MOUSE).x(70).y(70))
.build());
+ // events should be delivered with the second displayId and in corrosponding coordinate space
mWindow->consumeMotionEvent(AllOf(WithMotionAction(AMOTION_EVENT_ACTION_MOVE),
- WithDisplayId(SECOND_DISPLAY_ID), WithRawCoords(70, 70)));
+ WithDisplayId(SECOND_DISPLAY_ID), WithRawCoords(70, 430)));
// pointer-up
mDispatcher->notifyMotion(
@@ -15262,7 +15273,7 @@
.pointer(PointerBuilder(0, ToolType::MOUSE).x(70).y(70))
.build());
mWindow->consumeMotionEvent(AllOf(WithMotionAction(AMOTION_EVENT_ACTION_BUTTON_RELEASE),
- WithDisplayId(SECOND_DISPLAY_ID), WithRawCoords(70, 70)));
+ WithDisplayId(SECOND_DISPLAY_ID), WithRawCoords(70, 430)));
mDispatcher->notifyMotion(MotionArgsBuilder(AMOTION_EVENT_ACTION_UP, AINPUT_SOURCE_MOUSE)
.displayId(SECOND_DISPLAY_ID)