Loading include/input/InputFlags.h +5 −0 Original line number Diff line number Diff line Loading @@ -25,6 +25,11 @@ public: * override. */ static bool connectedDisplaysCursorEnabled(); /** * Check if both connectedDisplaysCursor and associatedDisplayCursorBugfix is enabled. */ static bool connectedDisplaysCursorAndAssociatedDisplayCursorBugfixEnabled(); }; } // namespace android libs/input/InputFlags.cpp +5 −0 Original line number Diff line number Diff line Loading @@ -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 services/inputflinger/PointerChoreographer.cpp +20 −8 Original line number Diff line number Diff line Loading @@ -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), Loading Loading @@ -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)); Loading Loading @@ -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 Loading Loading @@ -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&> Loading Loading @@ -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 Loading @@ -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 Loading services/inputflinger/PointerChoreographer.h +6 −1 Original line number Diff line number Diff line Loading @@ -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()); Loading services/inputflinger/tests/PointerChoreographer_test.cpp +84 −0 Original line number Diff line number Diff line Loading @@ -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( Loading Loading
include/input/InputFlags.h +5 −0 Original line number Diff line number Diff line Loading @@ -25,6 +25,11 @@ public: * override. */ static bool connectedDisplaysCursorEnabled(); /** * Check if both connectedDisplaysCursor and associatedDisplayCursorBugfix is enabled. */ static bool connectedDisplaysCursorAndAssociatedDisplayCursorBugfixEnabled(); }; } // namespace android
libs/input/InputFlags.cpp +5 −0 Original line number Diff line number Diff line Loading @@ -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
services/inputflinger/PointerChoreographer.cpp +20 −8 Original line number Diff line number Diff line Loading @@ -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), Loading Loading @@ -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)); Loading Loading @@ -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 Loading Loading @@ -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&> Loading Loading @@ -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 Loading @@ -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 Loading
services/inputflinger/PointerChoreographer.h +6 −1 Original line number Diff line number Diff line Loading @@ -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()); Loading
services/inputflinger/tests/PointerChoreographer_test.cpp +84 −0 Original line number Diff line number Diff line Loading @@ -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( Loading