diff options
author | 2025-01-30 15:12:36 +0000 | |
---|---|---|
committer | 2025-02-14 16:18:40 +0000 | |
commit | def7cb17d6efcda756dc0fd1f7bbc0ace720f757 (patch) | |
tree | 837ac6cbf64920da598e6d84b8404b3c17dedd10 | |
parent | f282c31bd6be19691e4f3bd85f06aaa36014586b (diff) |
[5/n CD Cursor] Enable cross-display drag gesture
Enable content drag and drop gesture to continue across display
bounries.
Bug: 393344208
Test: atest inputflinger_tests
Test: adb shell setprop persist.device_config.aconfig_flags.\
lse_desktop_experience.com.android.input.flags.connected_displays_cursor\
true && atest inputflinger_tests
Flag: com.android.input.flags.connected_displays_cursor
Change-Id: I58a501de1a047a3d363dc3f36a59a782f2d886bb
-rw-r--r-- | services/inputflinger/dispatcher/InputDispatcher.cpp | 11 | ||||
-rw-r--r-- | services/inputflinger/dispatcher/InputDispatcher.h | 3 | ||||
-rw-r--r-- | services/inputflinger/tests/InputDispatcher_test.cpp | 113 |
3 files changed, 100 insertions, 27 deletions
diff --git a/services/inputflinger/dispatcher/InputDispatcher.cpp b/services/inputflinger/dispatcher/InputDispatcher.cpp index a2543b1e8b..ca6b85d083 100644 --- a/services/inputflinger/dispatcher/InputDispatcher.cpp +++ b/services/inputflinger/dispatcher/InputDispatcher.cpp @@ -2808,8 +2808,9 @@ void InputDispatcher::finishDragAndDrop(ui::LogicalDisplayId displayId, float x, } void InputDispatcher::addDragEventLocked(const MotionEntry& entry) { - if (!mDragState || mDragState->dragWindow->getInfo()->displayId != entry.displayId || - mDragState->deviceId != entry.deviceId) { + if (!mDragState || mDragState->deviceId != entry.deviceId || + !mWindowInfos.areDisplaysConnected(mDragState->dragWindow->getInfo()->displayId, + entry.displayId)) { return; } @@ -5198,6 +5199,12 @@ ui::LogicalDisplayId InputDispatcher::DispatcherWindowInfo::getPrimaryDisplayId( return displayId; } +bool InputDispatcher::DispatcherWindowInfo::areDisplaysConnected( + ui::LogicalDisplayId display1, ui::LogicalDisplayId display2) const { + return display1 == display2 || + (mTopology.graph.contains(display1) && mTopology.graph.contains(display2)); +} + std::string InputDispatcher::DispatcherWindowInfo::dumpDisplayAndWindowInfo() const { std::string dump; if (!mWindowHandlesByDisplay.empty()) { diff --git a/services/inputflinger/dispatcher/InputDispatcher.h b/services/inputflinger/dispatcher/InputDispatcher.h index a949900911..7e8e1426a0 100644 --- a/services/inputflinger/dispatcher/InputDispatcher.h +++ b/services/inputflinger/dispatcher/InputDispatcher.h @@ -343,6 +343,9 @@ private: // same displayId. ui::LogicalDisplayId getPrimaryDisplayId(ui::LogicalDisplayId displayId) const; + bool areDisplaysConnected(ui::LogicalDisplayId display1, + ui::LogicalDisplayId display2) const; + std::string dumpDisplayAndWindowInfo() const; private: diff --git a/services/inputflinger/tests/InputDispatcher_test.cpp b/services/inputflinger/tests/InputDispatcher_test.cpp index 7e7d954c36..6c5d94d984 100644 --- a/services/inputflinger/tests/InputDispatcher_test.cpp +++ b/services/inputflinger/tests/InputDispatcher_test.cpp @@ -12374,6 +12374,11 @@ protected: sp<FakeWindowHandle> mSecondWindow; sp<FakeWindowHandle> mDragWindow; sp<FakeWindowHandle> mSpyWindow; + + std::vector<gui::DisplayInfo> mDisplayInfos; + + std::shared_ptr<FakeApplicationHandle> mSecondApplication; + sp<FakeWindowHandle> mWindowOnSecondDisplay; // Mouse would force no-split, set the id as non-zero to verify if drag state could track it. static constexpr int32_t MOUSE_POINTER_ID = 1; @@ -12394,10 +12399,17 @@ protected: mSpyWindow->setTrustedOverlay(true); mSpyWindow->setFrame(Rect(0, 0, 200, 100)); + mSecondApplication = std::make_shared<FakeApplicationHandle>(); + mWindowOnSecondDisplay = + sp<FakeWindowHandle>::make(mSecondApplication, mDispatcher, + "TestWindowOnSecondDisplay", SECOND_DISPLAY_ID); + mWindowOnSecondDisplay->setFrame({0, 0, 100, 100}); + mDispatcher->setFocusedApplication(ui::LogicalDisplayId::DEFAULT, mApp); mDispatcher->onWindowInfosChanged( - {{*mSpyWindow->getInfo(), *mWindow->getInfo(), *mSecondWindow->getInfo()}, - {}, + {{*mSpyWindow->getInfo(), *mWindow->getInfo(), *mSecondWindow->getInfo(), + *mWindowOnSecondDisplay->getInfo()}, + mDisplayInfos, 0, 0}); } @@ -12482,11 +12494,12 @@ protected: mDragWindow = sp<FakeWindowHandle>::make(mApp, mDispatcher, "DragWindow", ui::LogicalDisplayId::DEFAULT); mDragWindow->setTouchableRegion(Region{{0, 0, 0, 0}}); - mDispatcher->onWindowInfosChanged({{*mDragWindow->getInfo(), *mSpyWindow->getInfo(), - *mWindow->getInfo(), *mSecondWindow->getInfo()}, - {}, - 0, - 0}); + mDispatcher->onWindowInfosChanged( + {{*mDragWindow->getInfo(), *mSpyWindow->getInfo(), *mWindow->getInfo(), + *mSecondWindow->getInfo(), *mWindowOnSecondDisplay->getInfo()}, + mDisplayInfos, + 0, + 0}); // Transfer touch focus to the drag window bool transferred = @@ -12499,6 +12512,13 @@ protected: } return transferred; } + + void addDisplay(ui::LogicalDisplayId displayId, ui::Transform transform) { + gui::DisplayInfo displayInfo; + displayInfo.displayId = displayId; + displayInfo.transform = transform; + mDisplayInfos.push_back(displayInfo); + } }; TEST_F(InputDispatcherDragTests, DragEnterAndDragExit) { @@ -15185,7 +15205,7 @@ TEST_P(TransferOrDontTransferFixture, MouseAndTouchTransferSimultaneousMultiDevi INSTANTIATE_TEST_SUITE_P(WithAndWithoutTransfer, TransferOrDontTransferFixture, testing::Bool()); -class InputDispatcherConnectedDisplayTest : public InputDispatcherTest { +class InputDispatcherConnectedDisplayTest : public InputDispatcherDragTests { constexpr static int DENSITY_MEDIUM = 160; const DisplayTopologyGraph @@ -15198,26 +15218,15 @@ class InputDispatcherConnectedDisplayTest : public InputDispatcherTest { {SECOND_DISPLAY_ID, DENSITY_MEDIUM}}}; protected: - sp<FakeWindowHandle> mWindow; - void SetUp() override { - InputDispatcherTest::SetUp(); - mDispatcher->setDisplayTopology(mTopology); - mWindow = sp<FakeWindowHandle>::make(std::make_shared<FakeApplicationHandle>(), mDispatcher, - "Window", DISPLAY_ID); - mWindow->setFrame({0, 0, 100, 100}); - - gui::DisplayInfo displayInfo1; - displayInfo1.displayId = DISPLAY_ID; + addDisplay(DISPLAY_ID, ui::Transform()); + addDisplay(SECOND_DISPLAY_ID, + ui::Transform(ui::Transform::ROT_270, /*logicalDisplayWidth=*/ + 500, /*logicalDisplayHeight=*/500)); - ui::Transform transform(ui::Transform::ROT_270, /*logicalDisplayWidth=*/500, - /*logicalDisplayHeight=*/500); - gui::DisplayInfo displayInfo2; - displayInfo2.displayId = SECOND_DISPLAY_ID; - displayInfo2.transform = transform; + InputDispatcherDragTests::SetUp(); - mDispatcher->onWindowInfosChanged( - {{*mWindow->getInfo()}, {displayInfo1, displayInfo2}, 0, 0}); + mDispatcher->setDisplayTopology(mTopology); } }; @@ -15283,4 +15292,58 @@ TEST_F(InputDispatcherConnectedDisplayTest, MultiDisplayMouseGesture) { mWindow->consumeMotionUp(SECOND_DISPLAY_ID); } +TEST_F(InputDispatcherConnectedDisplayTest, MultiDisplayMouseDragAndDrop) { + SCOPED_FLAG_OVERRIDE(connected_displays_cursor, true); + + startDrag(true, AINPUT_SOURCE_MOUSE); + // Move on window. + mDispatcher->notifyMotion( + MotionArgsBuilder(AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_MOUSE) + .displayId(DISPLAY_ID) + .buttonState(AMOTION_EVENT_BUTTON_PRIMARY) + .pointer(PointerBuilder(MOUSE_POINTER_ID, ToolType::MOUSE).x(50).y(50)) + .build()); + mDragWindow->consumeMotionMove(DISPLAY_ID, AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE); + mWindow->consumeDragEvent(false, 50, 50); + mSecondWindow->assertNoEvents(); + mWindowOnSecondDisplay->assertNoEvents(); + + // Move to another window. + mDispatcher->notifyMotion( + MotionArgsBuilder(AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_MOUSE) + .displayId(DISPLAY_ID) + .buttonState(AMOTION_EVENT_BUTTON_PRIMARY) + .pointer(PointerBuilder(MOUSE_POINTER_ID, ToolType::MOUSE).x(150).y(50)) + .build()); + mDragWindow->consumeMotionMove(DISPLAY_ID, AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE); + mWindow->consumeDragEvent(true, 150, 50); + mSecondWindow->consumeDragEvent(false, 50, 50); + mWindowOnSecondDisplay->assertNoEvents(); + + // Move to window on the second display + mDispatcher->notifyMotion( + MotionArgsBuilder(AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_MOUSE) + .displayId(SECOND_DISPLAY_ID) + .buttonState(AMOTION_EVENT_BUTTON_PRIMARY) + .pointer(PointerBuilder(MOUSE_POINTER_ID, ToolType::MOUSE).x(50).y(50)) + .build()); + mDragWindow->consumeMotionMove(SECOND_DISPLAY_ID, AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE); + mWindow->assertNoEvents(); + mSecondWindow->consumeDragEvent(true, -50, 50); + mWindowOnSecondDisplay->consumeDragEvent(false, 50, 50); + + // drop on the second display + mDispatcher->notifyMotion( + MotionArgsBuilder(AMOTION_EVENT_ACTION_UP, AINPUT_SOURCE_MOUSE) + .displayId(SECOND_DISPLAY_ID) + .buttonState(0) + .pointer(PointerBuilder(MOUSE_POINTER_ID, ToolType::MOUSE).x(50).y(50)) + .build()); + mDragWindow->consumeMotionUp(SECOND_DISPLAY_ID, AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE); + mFakePolicy->assertDropTargetEquals(*mDispatcher, mWindowOnSecondDisplay->getToken()); + mWindow->assertNoEvents(); + mSecondWindow->assertNoEvents(); + mWindowOnSecondDisplay->assertNoEvents(); +} + } // namespace android::inputdispatcher |