Skip to content

Commit 105a3fc

Browse files
author
Arpit Singh
committed
[CD Cursor] Enable gesture transfer across connected displays
In case of a mouse touchState's displayId may not be same as touched window's displayId. This causes the gesture transfer for drag and drop to fail. To prevent this we should lookup for transfer target on all connected displays. Test: atest inputflinger_tests Bug: 393344208 Flag: com.android.input.flags.connected_displays_cursor Change-Id: Ib193f108c54655f2170585ae02228cda969977ea
1 parent 43a1d49 commit 105a3fc

3 files changed

Lines changed: 128 additions & 23 deletions

File tree

services/inputflinger/dispatcher/InputDispatcher.cpp

Lines changed: 40 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5067,8 +5067,19 @@ sp<WindowInfoHandle> InputDispatcher::DispatcherWindowInfo::findWindowHandle(
50675067
}
50685068

50695069
// Only look through the requested display.
5070-
for (const sp<WindowInfoHandle>& windowHandle : getWindowHandlesForDisplay(*displayId)) {
5071-
if (windowHandle->getToken() == windowHandleToken) {
5070+
return findWindowHandleOnDisplay(windowHandleToken, *displayId);
5071+
}
5072+
5073+
sp<WindowInfoHandle> InputDispatcher::DispatcherWindowInfo::findWindowHandleOnConnectedDisplays(
5074+
const sp<IBinder>& windowHandleToken, ui::LogicalDisplayId displayId) const {
5075+
if (windowHandleToken == nullptr) {
5076+
return nullptr;
5077+
}
5078+
5079+
sp<WindowInfoHandle> windowHandle;
5080+
for (ui::LogicalDisplayId connectedDisplayId : getConnectedDisplays(displayId)) {
5081+
windowHandle = findWindowHandleOnDisplay(windowHandleToken, connectedDisplayId);
5082+
if (windowHandle != nullptr) {
50725083
return windowHandle;
50735084
}
50745085
}
@@ -5214,6 +5225,29 @@ std::string InputDispatcher::DispatcherWindowInfo::dumpDisplayAndWindowInfo() co
52145225
return dump;
52155226
}
52165227

5228+
std::vector<ui::LogicalDisplayId> InputDispatcher::DispatcherWindowInfo::getConnectedDisplays(
5229+
ui::LogicalDisplayId displayId) const {
5230+
if (!mTopology.graph.contains(displayId)) {
5231+
return {displayId};
5232+
}
5233+
5234+
std::vector<ui::LogicalDisplayId> connectedDisplays;
5235+
for (auto it : mTopology.graph) {
5236+
connectedDisplays.push_back(it.first);
5237+
}
5238+
return connectedDisplays;
5239+
}
5240+
5241+
sp<WindowInfoHandle> InputDispatcher::DispatcherWindowInfo::findWindowHandleOnDisplay(
5242+
const sp<IBinder>& windowHandleToken, ui::LogicalDisplayId displayId) const {
5243+
for (const sp<WindowInfoHandle>& windowHandle : getWindowHandlesForDisplay(displayId)) {
5244+
if (windowHandle->getToken() == windowHandleToken) {
5245+
return windowHandle;
5246+
}
5247+
}
5248+
return nullptr;
5249+
}
5250+
52175251
bool InputDispatcher::DispatcherTouchState::canWindowReceiveMotion(
52185252
const sp<android::gui::WindowInfoHandle>& window,
52195253
const android::inputdispatcher::MotionEntry& motionEntry) const {
@@ -5806,7 +5840,10 @@ InputDispatcher::DispatcherTouchState::transferTouchGesture(const sp<android::IB
58065840
const DeviceId deviceId = *deviceIds.begin();
58075841

58085842
const sp<WindowInfoHandle> fromWindowHandle = touchedWindow.windowHandle;
5809-
const sp<WindowInfoHandle> toWindowHandle = mWindowInfos.findWindowHandle(toToken, displayId);
5843+
// TouchState displayId may not be same as window displayId, we need to lookup for toToken on
5844+
// all connected displays.
5845+
const sp<WindowInfoHandle> toWindowHandle =
5846+
mWindowInfos.findWindowHandleOnConnectedDisplays(toToken, displayId);
58105847
if (!toWindowHandle) {
58115848
ALOGW("Cannot transfer touch because the transfer target window was not found.");
58125849
return std::nullopt;

services/inputflinger/dispatcher/InputDispatcher.h

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -319,6 +319,11 @@ class InputDispatcher : public android::InputDispatcherInterface {
319319
const sp<IBinder>& windowHandleToken,
320320
std::optional<ui::LogicalDisplayId> displayId = {}) const;
321321

322+
// Lookup for WindowInfoHandle from token and a display-id. Lookup is done for all connected
323+
// displays in the topology of the queried display.
324+
sp<android::gui::WindowInfoHandle> findWindowHandleOnConnectedDisplays(
325+
const sp<IBinder>& windowHandleToken, ui::LogicalDisplayId displayId) const;
326+
322327
bool isWindowPresent(const sp<android::gui::WindowInfoHandle>& windowHandle) const;
323328

324329
// Returns the touched window at the given location, excluding the ignoreWindow if provided.
@@ -349,6 +354,12 @@ class InputDispatcher : public android::InputDispatcherInterface {
349354
std::string dumpDisplayAndWindowInfo() const;
350355

351356
private:
357+
std::vector<ui::LogicalDisplayId> getConnectedDisplays(
358+
ui::LogicalDisplayId displayId) const;
359+
360+
sp<android::gui::WindowInfoHandle> findWindowHandleOnDisplay(
361+
const sp<IBinder>& windowHandleToken, ui::LogicalDisplayId displayId) const;
362+
352363
std::unordered_map<ui::LogicalDisplayId /*displayId*/,
353364
std::vector<sp<android::gui::WindowInfoHandle>>>
354365
mWindowHandlesByDisplay;

services/inputflinger/tests/InputDispatcher_test.cpp

Lines changed: 77 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -12414,18 +12414,22 @@ class InputDispatcherDragTests : public InputDispatcherTest {
1241412414
0});
1241512415
}
1241612416

12417-
void injectDown(int fromSource = AINPUT_SOURCE_TOUCHSCREEN) {
12417+
void injectDown(int fromSource = AINPUT_SOURCE_TOUCHSCREEN,
12418+
ui::LogicalDisplayId displayId = ui::LogicalDisplayId::DEFAULT) {
1241812419
bool consumeButtonPress = false;
12420+
const PointF location =
12421+
displayId == ui::LogicalDisplayId::DEFAULT ? PointF(50, 50) : PointF(50, 450);
1241912422
switch (fromSource) {
1242012423
case AINPUT_SOURCE_TOUCHSCREEN: {
1242112424
ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
12422-
injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN,
12423-
ui::LogicalDisplayId::DEFAULT, {50, 50}))
12425+
injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, displayId,
12426+
location))
1242412427
<< "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
1242512428
break;
1242612429
}
1242712430
case AINPUT_SOURCE_STYLUS: {
12428-
PointerBuilder pointer = PointerBuilder(0, ToolType::STYLUS).x(50).y(50);
12431+
PointerBuilder pointer =
12432+
PointerBuilder(0, ToolType::STYLUS).x(location.x).y(location.y);
1242912433
ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
1243012434
injectMotionEvent(*mDispatcher,
1243112435
MotionEventBuilder(AMOTION_EVENT_ACTION_DOWN,
@@ -12448,19 +12452,22 @@ class InputDispatcherDragTests : public InputDispatcherTest {
1244812452
break;
1244912453
}
1245012454
case AINPUT_SOURCE_MOUSE: {
12451-
PointerBuilder pointer =
12452-
PointerBuilder(MOUSE_POINTER_ID, ToolType::MOUSE).x(50).y(50);
12455+
PointerBuilder pointer = PointerBuilder(MOUSE_POINTER_ID, ToolType::MOUSE)
12456+
.x(location.x)
12457+
.y(location.y);
1245312458
ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
1245412459
injectMotionEvent(*mDispatcher,
1245512460
MotionEventBuilder(AMOTION_EVENT_ACTION_DOWN,
1245612461
AINPUT_SOURCE_MOUSE)
12462+
.displayId(displayId)
1245712463
.buttonState(AMOTION_EVENT_BUTTON_PRIMARY)
1245812464
.pointer(pointer)
1245912465
.build()));
1246012466
ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
1246112467
injectMotionEvent(*mDispatcher,
1246212468
MotionEventBuilder(AMOTION_EVENT_ACTION_BUTTON_PRESS,
1246312469
AINPUT_SOURCE_MOUSE)
12470+
.displayId(displayId)
1246412471
.actionButton(AMOTION_EVENT_BUTTON_PRIMARY)
1246512472
.buttonState(AMOTION_EVENT_BUTTON_PRIMARY)
1246612473
.pointer(pointer)
@@ -12474,25 +12481,30 @@ class InputDispatcherDragTests : public InputDispatcherTest {
1247412481
}
1247512482

1247612483
// Window should receive motion event.
12477-
mWindow->consumeMotionDown(ui::LogicalDisplayId::DEFAULT);
12484+
sp<FakeWindowHandle>& targetWindow =
12485+
displayId == ui::LogicalDisplayId::DEFAULT ? mWindow : mWindowOnSecondDisplay;
12486+
targetWindow->consumeMotionDown(displayId);
1247812487
if (consumeButtonPress) {
12479-
mWindow->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_BUTTON_PRESS));
12488+
targetWindow->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_BUTTON_PRESS));
12489+
}
12490+
12491+
// Spy window should also receive motion event if event is on the same display.
12492+
if (displayId == ui::LogicalDisplayId::DEFAULT) {
12493+
mSpyWindow->consumeMotionDown(ui::LogicalDisplayId::DEFAULT);
1248012494
}
12481-
// Spy window should also receive motion event
12482-
mSpyWindow->consumeMotionDown(ui::LogicalDisplayId::DEFAULT);
1248312495
}
1248412496

1248512497
// Start performing drag, we will create a drag window and transfer touch to it.
1248612498
// @param sendDown : if true, send a motion down on first window before perform drag and drop.
1248712499
// Returns true on success.
12488-
bool startDrag(bool sendDown = true, int fromSource = AINPUT_SOURCE_TOUCHSCREEN) {
12500+
bool startDrag(bool sendDown = true, int fromSource = AINPUT_SOURCE_TOUCHSCREEN,
12501+
ui::LogicalDisplayId dragStartDisplay = ui::LogicalDisplayId::DEFAULT) {
1248912502
if (sendDown) {
12490-
injectDown(fromSource);
12503+
injectDown(fromSource, dragStartDisplay);
1249112504
}
1249212505

1249312506
// The drag window covers the entire display
12494-
mDragWindow = sp<FakeWindowHandle>::make(mApp, mDispatcher, "DragWindow",
12495-
ui::LogicalDisplayId::DEFAULT);
12507+
mDragWindow = sp<FakeWindowHandle>::make(mApp, mDispatcher, "DragWindow", dragStartDisplay);
1249612508
mDragWindow->setTouchableRegion(Region{{0, 0, 0, 0}});
1249712509
mDispatcher->onWindowInfosChanged(
1249812510
{{*mDragWindow->getInfo(), *mSpyWindow->getInfo(), *mWindow->getInfo(),
@@ -12501,14 +12513,17 @@ class InputDispatcherDragTests : public InputDispatcherTest {
1250112513
0,
1250212514
0});
1250312515

12516+
sp<FakeWindowHandle>& targetWindow = dragStartDisplay == ui::LogicalDisplayId::DEFAULT
12517+
? mWindow
12518+
: mWindowOnSecondDisplay;
12519+
1250412520
// Transfer touch focus to the drag window
1250512521
bool transferred =
12506-
mDispatcher->transferTouchGesture(mWindow->getToken(), mDragWindow->getToken(),
12522+
mDispatcher->transferTouchGesture(targetWindow->getToken(), mDragWindow->getToken(),
1250712523
/*isDragDrop=*/true);
1250812524
if (transferred) {
12509-
mWindow->consumeMotionCancel();
12510-
mDragWindow->consumeMotionDown(ui::LogicalDisplayId::DEFAULT,
12511-
AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
12525+
targetWindow->consumeMotionCancel(dragStartDisplay);
12526+
mDragWindow->consumeMotionDown(dragStartDisplay, AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
1251212527
}
1251312528
return transferred;
1251412529
}
@@ -15292,10 +15307,10 @@ TEST_F(InputDispatcherConnectedDisplayTest, MultiDisplayMouseGesture) {
1529215307
mWindow->consumeMotionUp(SECOND_DISPLAY_ID);
1529315308
}
1529415309

15295-
TEST_F(InputDispatcherConnectedDisplayTest, MultiDisplayMouseDragAndDrop) {
15310+
TEST_F(InputDispatcherConnectedDisplayTest, MultiDisplayMouseDragAndDropFromPrimaryDisplay) {
1529615311
SCOPED_FLAG_OVERRIDE(connected_displays_cursor, true);
1529715312

15298-
startDrag(true, AINPUT_SOURCE_MOUSE);
15313+
EXPECT_TRUE(startDrag(true, AINPUT_SOURCE_MOUSE));
1529915314
// Move on window.
1530015315
mDispatcher->notifyMotion(
1530115316
MotionArgsBuilder(AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_MOUSE)
@@ -15346,4 +15361,46 @@ TEST_F(InputDispatcherConnectedDisplayTest, MultiDisplayMouseDragAndDrop) {
1534615361
mWindowOnSecondDisplay->assertNoEvents();
1534715362
}
1534815363

15364+
TEST_F(InputDispatcherConnectedDisplayTest, MultiDisplayMouseDragAndDropFromNonPrimaryDisplay) {
15365+
SCOPED_FLAG_OVERRIDE(connected_displays_cursor, true);
15366+
15367+
EXPECT_TRUE(startDrag(true, AINPUT_SOURCE_MOUSE, SECOND_DISPLAY_ID));
15368+
// Move on window.
15369+
mDispatcher->notifyMotion(
15370+
MotionArgsBuilder(AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_MOUSE)
15371+
.displayId(SECOND_DISPLAY_ID)
15372+
.buttonState(AMOTION_EVENT_BUTTON_PRIMARY)
15373+
.pointer(PointerBuilder(MOUSE_POINTER_ID, ToolType::MOUSE).x(50).y(50))
15374+
.build());
15375+
mDragWindow->consumeMotionMove(SECOND_DISPLAY_ID, AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
15376+
mWindow->assertNoEvents();
15377+
mSecondWindow->assertNoEvents();
15378+
mWindowOnSecondDisplay->consumeDragEvent(false, 50, 50);
15379+
15380+
// Move to window on the primary display
15381+
mDispatcher->notifyMotion(
15382+
MotionArgsBuilder(AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_MOUSE)
15383+
.displayId(DISPLAY_ID)
15384+
.buttonState(AMOTION_EVENT_BUTTON_PRIMARY)
15385+
.pointer(PointerBuilder(MOUSE_POINTER_ID, ToolType::MOUSE).x(50).y(50))
15386+
.build());
15387+
mDragWindow->consumeMotionMove(DISPLAY_ID, AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
15388+
mWindow->consumeDragEvent(false, 50, 50);
15389+
mSecondWindow->assertNoEvents();
15390+
mWindowOnSecondDisplay->consumeDragEvent(true, 50, 50);
15391+
15392+
// drop on the primary display
15393+
mDispatcher->notifyMotion(
15394+
MotionArgsBuilder(AMOTION_EVENT_ACTION_UP, AINPUT_SOURCE_MOUSE)
15395+
.displayId(DISPLAY_ID)
15396+
.buttonState(0)
15397+
.pointer(PointerBuilder(MOUSE_POINTER_ID, ToolType::MOUSE).x(50).y(50))
15398+
.build());
15399+
mDragWindow->consumeMotionUp(DISPLAY_ID, AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
15400+
mFakePolicy->assertDropTargetEquals(*mDispatcher, mWindow->getToken());
15401+
mWindow->assertNoEvents();
15402+
mSecondWindow->assertNoEvents();
15403+
mWindowOnSecondDisplay->assertNoEvents();
15404+
}
15405+
1534915406
} // namespace android::inputdispatcher

0 commit comments

Comments
 (0)