diff options
author | 2025-02-17 17:20:24 +0900 | |
---|---|---|
committer | 2025-02-25 19:24:22 +0900 | |
commit | 96df7be319ce19ea86c53ad4f04f0d964a39e73f (patch) | |
tree | 6ddfd5e5bcd7ebd5c9dfd854c105ac8013ef448b | |
parent | 3c769a4d1ba7f422e5b21d6d5f7e0f6b1ae5b2f0 (diff) |
[CD Cursor] Apply selection logic to change cursor displayId
In connected displays scenario, this tracks the latest display the
cursor is at, within the DisplayTopology. By default, this will be set
to topology primary display, and updated when mouse crossed to another
display.
Note: If associatedDisplay is in different topology, mouse will simply
be on the associatedDisplay, keeping existing behavior
Doc: go/connected-displays-cursor-behavior
Bug: 396568321
Test: atest inputflinger_tests
Test: atest InputTests
Test: atest CtsInputTestCases
Flag: com.android.input.flags.connected_displays_associated_display_cursor_bugfix
Change-Id: I6a68d9cd5a4de06896e0e29104c25b8a4493b852
-rw-r--r-- | include/input/InputFlags.h | 5 | ||||
-rw-r--r-- | libs/input/InputFlags.cpp | 5 | ||||
-rw-r--r-- | services/inputflinger/PointerChoreographer.cpp | 28 | ||||
-rw-r--r-- | services/inputflinger/PointerChoreographer.h | 7 | ||||
-rw-r--r-- | services/inputflinger/tests/PointerChoreographer_test.cpp | 84 |
5 files changed, 120 insertions, 9 deletions
diff --git a/include/input/InputFlags.h b/include/input/InputFlags.h index 0e194eaeb8..4b42f775dd 100644 --- a/include/input/InputFlags.h +++ b/include/input/InputFlags.h @@ -25,6 +25,11 @@ public: * override. */ static bool connectedDisplaysCursorEnabled(); + + /** + * Check if both connectedDisplaysCursor and associatedDisplayCursorBugfix is enabled. + */ + static bool connectedDisplaysCursorAndAssociatedDisplayCursorBugfixEnabled(); }; } // namespace android diff --git a/libs/input/InputFlags.cpp b/libs/input/InputFlags.cpp index 555b1387ba..f866f9b8f0 100644 --- a/libs/input/InputFlags.cpp +++ b/libs/input/InputFlags.cpp @@ -39,4 +39,9 @@ bool InputFlags::connectedDisplaysCursorEnabled() { return com::android::input::flags::connected_displays_cursor(); } +bool InputFlags::connectedDisplaysCursorAndAssociatedDisplayCursorBugfixEnabled() { + return connectedDisplaysCursorEnabled() && + com::android::input::flags::connected_displays_associated_display_cursor_bugfix(); +} + } // namespace android
\ No newline at end of file diff --git a/services/inputflinger/PointerChoreographer.cpp b/services/inputflinger/PointerChoreographer.cpp index e06ff6b9c7..98b514ba73 100644 --- a/services/inputflinger/PointerChoreographer.cpp +++ b/services/inputflinger/PointerChoreographer.cpp @@ -132,7 +132,7 @@ PointerChoreographer::PointerChoreographer( }), mNextListener(listener), mPolicy(policy), - mDefaultMouseDisplayId(ui::LogicalDisplayId::DEFAULT), + mCurrentMouseDisplayId(ui::LogicalDisplayId::INVALID), mNotifiedPointerDisplayId(ui::LogicalDisplayId::INVALID), mShowTouchesEnabled(false), mStylusPointerIconEnabled(false), @@ -361,7 +361,7 @@ void PointerChoreographer::handleUnconsumedDeltaLocked(PointerControllerInterfac LOG(FATAL) << "A cursor already exists on destination display" << destinationViewport.displayId; } - mDefaultMouseDisplayId = destinationViewport.displayId; + mCurrentMouseDisplayId = destinationViewport.displayId; auto pcNode = mMousePointersByDisplay.extract(sourceDisplayId); pcNode.key() = destinationViewport.displayId; mMousePointersByDisplay.insert(std::move(pcNode)); @@ -609,9 +609,9 @@ void PointerChoreographer::setDisplayTopology(const DisplayTopologyGraph& displa // make primary display default mouse display, if it was not set or // the existing display was removed - if (mDefaultMouseDisplayId == ui::LogicalDisplayId::INVALID || - mTopology.graph.find(mDefaultMouseDisplayId) == mTopology.graph.end()) { - mDefaultMouseDisplayId = mTopology.primaryDisplayId; + if (mCurrentMouseDisplayId == ui::LogicalDisplayId::INVALID || + mTopology.graph.find(mCurrentMouseDisplayId) == mTopology.graph.end()) { + mCurrentMouseDisplayId = mTopology.primaryDisplayId; pointerDisplayChange = updatePointerControllersLocked(); } } // release lock @@ -665,7 +665,19 @@ const DisplayViewport* PointerChoreographer::findViewportByIdLocked( ui::LogicalDisplayId PointerChoreographer::getTargetMouseDisplayLocked( ui::LogicalDisplayId associatedDisplayId) const { - return associatedDisplayId.isValid() ? associatedDisplayId : mDefaultMouseDisplayId; + if (!InputFlags::connectedDisplaysCursorAndAssociatedDisplayCursorBugfixEnabled()) { + if (associatedDisplayId.isValid()) { + return associatedDisplayId; + } + return mCurrentMouseDisplayId.isValid() ? mCurrentMouseDisplayId + : ui::LogicalDisplayId::DEFAULT; + } + // Associated display is not included in the topology, return this associated display. + if (associatedDisplayId.isValid() && + mTopology.graph.find(associatedDisplayId) == mTopology.graph.end()) { + return associatedDisplayId; + } + return mCurrentMouseDisplayId.isValid() ? mCurrentMouseDisplayId : mTopology.primaryDisplayId; } std::pair<ui::LogicalDisplayId, PointerControllerInterface&> @@ -774,7 +786,7 @@ PointerChoreographer::PointerDisplayChange PointerChoreographer::calculatePointerDisplayChangeToNotify() { ui::LogicalDisplayId displayIdToNotify = ui::LogicalDisplayId::INVALID; vec2 cursorPosition = {0, 0}; - if (const auto it = mMousePointersByDisplay.find(mDefaultMouseDisplayId); + if (const auto it = mMousePointersByDisplay.find(mCurrentMouseDisplayId); it != mMousePointersByDisplay.end()) { const auto& pointerController = it->second; // Use the displayId from the pointerController, because it accurately reflects whether @@ -800,7 +812,7 @@ void PointerChoreographer::setDefaultMouseDisplayId(ui::LogicalDisplayId display { // acquire lock std::scoped_lock _l(getLock()); - mDefaultMouseDisplayId = displayId; + mCurrentMouseDisplayId = displayId; pointerDisplayChange = updatePointerControllersLocked(); } // release lock diff --git a/services/inputflinger/PointerChoreographer.h b/services/inputflinger/PointerChoreographer.h index 24351256ef..67bdca1bab 100644 --- a/services/inputflinger/PointerChoreographer.h +++ b/services/inputflinger/PointerChoreographer.h @@ -231,7 +231,12 @@ private: std::map<DeviceId, std::shared_ptr<PointerControllerInterface>> mDrawingTabletPointersByDevice GUARDED_BY(getLock()); - ui::LogicalDisplayId mDefaultMouseDisplayId GUARDED_BY(getLock()); + // In connected displays scenario, this tracks the latest display the cursor is at, within the + // DisplayTopology. By default, this will be set to topology primary display, and updated when + // mouse crossed to another display. + // In non-connected displays scenario, this will be treated as the default display cursor + // will be on, when mouse doesn't have associated display. + ui::LogicalDisplayId mCurrentMouseDisplayId GUARDED_BY(getLock()); ui::LogicalDisplayId mNotifiedPointerDisplayId GUARDED_BY(getLock()); std::vector<InputDeviceInfo> mInputDeviceInfos GUARDED_BY(getLock()); std::set<DeviceId> mMouseDevices GUARDED_BY(getLock()); diff --git a/services/inputflinger/tests/PointerChoreographer_test.cpp b/services/inputflinger/tests/PointerChoreographer_test.cpp index 3aad16f533..38d0679095 100644 --- a/services/inputflinger/tests/PointerChoreographer_test.cpp +++ b/services/inputflinger/tests/PointerChoreographer_test.cpp @@ -3072,6 +3072,90 @@ TEST_F(PointerChoreographerDisplayTopologyDefaultMouseDisplayTests, ASSERT_TRUE(pc->isPointerShown()); } +TEST_F(PointerChoreographerDisplayTopologyDefaultMouseDisplayTests, + UsePrimaryDisplayIfAssociatedDisplayIsInTopology) { + SCOPED_FLAG_OVERRIDE(connected_displays_cursor, true); + SCOPED_FLAG_OVERRIDE(connected_displays_associated_display_cursor_bugfix, true); + + // Add two displays + mChoreographer.setDisplayViewports( + {createViewport(FIRST_DISPLAY_ID), createViewport(SECOND_DISPLAY_ID)}); + setDisplayTopologyWithDisplays(/*primaryDisplayId=*/SECOND_DISPLAY_ID, + /*adjacentDisplays=*/{FIRST_DISPLAY_ID}); + + mChoreographer.notifyInputDevicesChanged( + {/*id=*/0, {generateTestDeviceInfo(DEVICE_ID, AINPUT_SOURCE_MOUSE, FIRST_DISPLAY_ID)}}); + + auto pc = assertPointerControllerCreated(ControllerType::MOUSE); + pc->assertViewportSet(SECOND_DISPLAY_ID); + ASSERT_TRUE(pc->isPointerShown()); +} + +TEST_F(PointerChoreographerDisplayTopologyDefaultMouseDisplayTests, + AllowCrossingDisplayEvenWithAssociatedDisplaySet) { + SCOPED_FLAG_OVERRIDE(connected_displays_cursor, true); + SCOPED_FLAG_OVERRIDE(connected_displays_associated_display_cursor_bugfix, true); + + // Add two displays + mChoreographer.setDisplayViewports( + {createViewport(FIRST_DISPLAY_ID), createViewport(SECOND_DISPLAY_ID)}); + setDisplayTopologyWithDisplays(/*primaryDisplayId=*/FIRST_DISPLAY_ID, + /*adjacentDisplays=*/{SECOND_DISPLAY_ID}); + + mChoreographer.notifyInputDevicesChanged( + {/*id=*/0, + {generateTestDeviceInfo(DEVICE_ID, AINPUT_SOURCE_MOUSE, SECOND_DISPLAY_ID)}}); + + auto pc = assertPointerControllerCreated(ControllerType::MOUSE); + pc->assertViewportSet(FIRST_DISPLAY_ID); + ASSERT_TRUE(pc->isPointerShown()); + + // Move cursor to the secondary display + auto pointerBuilder = PointerBuilder(/*id=*/0, ToolType::MOUSE) + .axis(AMOTION_EVENT_AXIS_RELATIVE_X, /*x=*/100) + .axis(AMOTION_EVENT_AXIS_RELATIVE_Y, /*y=*/0); + mChoreographer.notifyMotion( + MotionArgsBuilder(AMOTION_EVENT_ACTION_HOVER_MOVE, AINPUT_SOURCE_MOUSE) + .pointer(pointerBuilder) + .deviceId(DEVICE_ID) + .displayId(ui::LogicalDisplayId::INVALID) + .build()); + + assertPointerControllerNotCreated(); + pc->assertViewportSet(SECOND_DISPLAY_ID); + ASSERT_TRUE(pc->isPointerShown()); +} + +TEST_F(PointerChoreographerDisplayTopologyDefaultMouseDisplayTests, + AddAssociatedDisplayCursorOutsideOfDisplayTopology) { + SCOPED_FLAG_OVERRIDE(connected_displays_cursor, true); + SCOPED_FLAG_OVERRIDE(connected_displays_associated_display_cursor_bugfix, true); + + // Add three displays, with only first and second display in DisplayTopolgoy + mChoreographer.setDisplayViewports({createViewport(FIRST_DISPLAY_ID), + createViewport(SECOND_DISPLAY_ID), + createViewport(THIRD_DISPLAY_ID)}); + setDisplayTopologyWithDisplays(/*primaryDisplayId=*/FIRST_DISPLAY_ID, + /*adjacentDisplays=*/{SECOND_DISPLAY_ID}); + + mChoreographer.notifyInputDevicesChanged( + {/*id=*/0, + {generateTestDeviceInfo(DEVICE_ID, AINPUT_SOURCE_MOUSE, + ui::LogicalDisplayId::INVALID)}}); + + auto pc = assertPointerControllerCreated(ControllerType::MOUSE); + pc->assertViewportSet(FIRST_DISPLAY_ID); + ASSERT_TRUE(pc->isPointerShown()); + + // Adds a new mouse associated with third display + mChoreographer.notifyInputDevicesChanged( + {/*id=*/1, {generateTestDeviceInfo(DEVICE_ID, AINPUT_SOURCE_MOUSE, THIRD_DISPLAY_ID)}}); + + pc = assertPointerControllerCreated(ControllerType::MOUSE); + pc->assertViewportSet(THIRD_DISPLAY_ID); + ASSERT_TRUE(pc->isPointerShown()); +} + class PointerChoreographerWindowInfoListenerTest : public testing::Test {}; TEST_F_WITH_FLAGS( |