Skip to content

Commit 204b3bc

Browse files
Treehugger RobotAndroid (Google) Code Review
authored andcommitted
Merge "[CD Cursor] Enable gesture transfer across connected displays" into main
2 parents da713fe + 105a3fc commit 204b3bc

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)