summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author nergi <nergi@google.com> 2025-02-17 17:20:24 +0900
committer nergi <nergi@google.com> 2025-02-25 19:24:22 +0900
commit96df7be319ce19ea86c53ad4f04f0d964a39e73f (patch)
tree6ddfd5e5bcd7ebd5c9dfd854c105ac8013ef448b
parent3c769a4d1ba7f422e5b21d6d5f7e0f6b1ae5b2f0 (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.h5
-rw-r--r--libs/input/InputFlags.cpp5
-rw-r--r--services/inputflinger/PointerChoreographer.cpp28
-rw-r--r--services/inputflinger/PointerChoreographer.h7
-rw-r--r--services/inputflinger/tests/PointerChoreographer_test.cpp84
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(