Skip to content

Commit 96df7be

Browse files
author
nergi
committed
[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
1 parent 3c769a4 commit 96df7be

5 files changed

Lines changed: 120 additions & 9 deletions

File tree

include/input/InputFlags.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,11 @@ class InputFlags {
2525
* override.
2626
*/
2727
static bool connectedDisplaysCursorEnabled();
28+
29+
/**
30+
* Check if both connectedDisplaysCursor and associatedDisplayCursorBugfix is enabled.
31+
*/
32+
static bool connectedDisplaysCursorAndAssociatedDisplayCursorBugfixEnabled();
2833
};
2934

3035
} // namespace android

libs/input/InputFlags.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,4 +39,9 @@ bool InputFlags::connectedDisplaysCursorEnabled() {
3939
return com::android::input::flags::connected_displays_cursor();
4040
}
4141

42+
bool InputFlags::connectedDisplaysCursorAndAssociatedDisplayCursorBugfixEnabled() {
43+
return connectedDisplaysCursorEnabled() &&
44+
com::android::input::flags::connected_displays_associated_display_cursor_bugfix();
45+
}
46+
4247
} // namespace android

services/inputflinger/PointerChoreographer.cpp

Lines changed: 20 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -132,7 +132,7 @@ PointerChoreographer::PointerChoreographer(
132132
}),
133133
mNextListener(listener),
134134
mPolicy(policy),
135-
mDefaultMouseDisplayId(ui::LogicalDisplayId::DEFAULT),
135+
mCurrentMouseDisplayId(ui::LogicalDisplayId::INVALID),
136136
mNotifiedPointerDisplayId(ui::LogicalDisplayId::INVALID),
137137
mShowTouchesEnabled(false),
138138
mStylusPointerIconEnabled(false),
@@ -361,7 +361,7 @@ void PointerChoreographer::handleUnconsumedDeltaLocked(PointerControllerInterfac
361361
LOG(FATAL) << "A cursor already exists on destination display"
362362
<< destinationViewport.displayId;
363363
}
364-
mDefaultMouseDisplayId = destinationViewport.displayId;
364+
mCurrentMouseDisplayId = destinationViewport.displayId;
365365
auto pcNode = mMousePointersByDisplay.extract(sourceDisplayId);
366366
pcNode.key() = destinationViewport.displayId;
367367
mMousePointersByDisplay.insert(std::move(pcNode));
@@ -609,9 +609,9 @@ void PointerChoreographer::setDisplayTopology(const DisplayTopologyGraph& displa
609609

610610
// make primary display default mouse display, if it was not set or
611611
// the existing display was removed
612-
if (mDefaultMouseDisplayId == ui::LogicalDisplayId::INVALID ||
613-
mTopology.graph.find(mDefaultMouseDisplayId) == mTopology.graph.end()) {
614-
mDefaultMouseDisplayId = mTopology.primaryDisplayId;
612+
if (mCurrentMouseDisplayId == ui::LogicalDisplayId::INVALID ||
613+
mTopology.graph.find(mCurrentMouseDisplayId) == mTopology.graph.end()) {
614+
mCurrentMouseDisplayId = mTopology.primaryDisplayId;
615615
pointerDisplayChange = updatePointerControllersLocked();
616616
}
617617
} // release lock
@@ -665,7 +665,19 @@ const DisplayViewport* PointerChoreographer::findViewportByIdLocked(
665665

666666
ui::LogicalDisplayId PointerChoreographer::getTargetMouseDisplayLocked(
667667
ui::LogicalDisplayId associatedDisplayId) const {
668-
return associatedDisplayId.isValid() ? associatedDisplayId : mDefaultMouseDisplayId;
668+
if (!InputFlags::connectedDisplaysCursorAndAssociatedDisplayCursorBugfixEnabled()) {
669+
if (associatedDisplayId.isValid()) {
670+
return associatedDisplayId;
671+
}
672+
return mCurrentMouseDisplayId.isValid() ? mCurrentMouseDisplayId
673+
: ui::LogicalDisplayId::DEFAULT;
674+
}
675+
// Associated display is not included in the topology, return this associated display.
676+
if (associatedDisplayId.isValid() &&
677+
mTopology.graph.find(associatedDisplayId) == mTopology.graph.end()) {
678+
return associatedDisplayId;
679+
}
680+
return mCurrentMouseDisplayId.isValid() ? mCurrentMouseDisplayId : mTopology.primaryDisplayId;
669681
}
670682

671683
std::pair<ui::LogicalDisplayId, PointerControllerInterface&>
@@ -774,7 +786,7 @@ PointerChoreographer::PointerDisplayChange
774786
PointerChoreographer::calculatePointerDisplayChangeToNotify() {
775787
ui::LogicalDisplayId displayIdToNotify = ui::LogicalDisplayId::INVALID;
776788
vec2 cursorPosition = {0, 0};
777-
if (const auto it = mMousePointersByDisplay.find(mDefaultMouseDisplayId);
789+
if (const auto it = mMousePointersByDisplay.find(mCurrentMouseDisplayId);
778790
it != mMousePointersByDisplay.end()) {
779791
const auto& pointerController = it->second;
780792
// Use the displayId from the pointerController, because it accurately reflects whether
@@ -800,7 +812,7 @@ void PointerChoreographer::setDefaultMouseDisplayId(ui::LogicalDisplayId display
800812
{ // acquire lock
801813
std::scoped_lock _l(getLock());
802814

803-
mDefaultMouseDisplayId = displayId;
815+
mCurrentMouseDisplayId = displayId;
804816
pointerDisplayChange = updatePointerControllersLocked();
805817
} // release lock
806818

services/inputflinger/PointerChoreographer.h

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -231,7 +231,12 @@ class PointerChoreographer : public PointerChoreographerInterface {
231231
std::map<DeviceId, std::shared_ptr<PointerControllerInterface>> mDrawingTabletPointersByDevice
232232
GUARDED_BY(getLock());
233233

234-
ui::LogicalDisplayId mDefaultMouseDisplayId GUARDED_BY(getLock());
234+
// In connected displays scenario, this tracks the latest display the cursor is at, within the
235+
// DisplayTopology. By default, this will be set to topology primary display, and updated when
236+
// mouse crossed to another display.
237+
// In non-connected displays scenario, this will be treated as the default display cursor
238+
// will be on, when mouse doesn't have associated display.
239+
ui::LogicalDisplayId mCurrentMouseDisplayId GUARDED_BY(getLock());
235240
ui::LogicalDisplayId mNotifiedPointerDisplayId GUARDED_BY(getLock());
236241
std::vector<InputDeviceInfo> mInputDeviceInfos GUARDED_BY(getLock());
237242
std::set<DeviceId> mMouseDevices GUARDED_BY(getLock());

services/inputflinger/tests/PointerChoreographer_test.cpp

Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3072,6 +3072,90 @@ TEST_F(PointerChoreographerDisplayTopologyDefaultMouseDisplayTests,
30723072
ASSERT_TRUE(pc->isPointerShown());
30733073
}
30743074

3075+
TEST_F(PointerChoreographerDisplayTopologyDefaultMouseDisplayTests,
3076+
UsePrimaryDisplayIfAssociatedDisplayIsInTopology) {
3077+
SCOPED_FLAG_OVERRIDE(connected_displays_cursor, true);
3078+
SCOPED_FLAG_OVERRIDE(connected_displays_associated_display_cursor_bugfix, true);
3079+
3080+
// Add two displays
3081+
mChoreographer.setDisplayViewports(
3082+
{createViewport(FIRST_DISPLAY_ID), createViewport(SECOND_DISPLAY_ID)});
3083+
setDisplayTopologyWithDisplays(/*primaryDisplayId=*/SECOND_DISPLAY_ID,
3084+
/*adjacentDisplays=*/{FIRST_DISPLAY_ID});
3085+
3086+
mChoreographer.notifyInputDevicesChanged(
3087+
{/*id=*/0, {generateTestDeviceInfo(DEVICE_ID, AINPUT_SOURCE_MOUSE, FIRST_DISPLAY_ID)}});
3088+
3089+
auto pc = assertPointerControllerCreated(ControllerType::MOUSE);
3090+
pc->assertViewportSet(SECOND_DISPLAY_ID);
3091+
ASSERT_TRUE(pc->isPointerShown());
3092+
}
3093+
3094+
TEST_F(PointerChoreographerDisplayTopologyDefaultMouseDisplayTests,
3095+
AllowCrossingDisplayEvenWithAssociatedDisplaySet) {
3096+
SCOPED_FLAG_OVERRIDE(connected_displays_cursor, true);
3097+
SCOPED_FLAG_OVERRIDE(connected_displays_associated_display_cursor_bugfix, true);
3098+
3099+
// Add two displays
3100+
mChoreographer.setDisplayViewports(
3101+
{createViewport(FIRST_DISPLAY_ID), createViewport(SECOND_DISPLAY_ID)});
3102+
setDisplayTopologyWithDisplays(/*primaryDisplayId=*/FIRST_DISPLAY_ID,
3103+
/*adjacentDisplays=*/{SECOND_DISPLAY_ID});
3104+
3105+
mChoreographer.notifyInputDevicesChanged(
3106+
{/*id=*/0,
3107+
{generateTestDeviceInfo(DEVICE_ID, AINPUT_SOURCE_MOUSE, SECOND_DISPLAY_ID)}});
3108+
3109+
auto pc = assertPointerControllerCreated(ControllerType::MOUSE);
3110+
pc->assertViewportSet(FIRST_DISPLAY_ID);
3111+
ASSERT_TRUE(pc->isPointerShown());
3112+
3113+
// Move cursor to the secondary display
3114+
auto pointerBuilder = PointerBuilder(/*id=*/0, ToolType::MOUSE)
3115+
.axis(AMOTION_EVENT_AXIS_RELATIVE_X, /*x=*/100)
3116+
.axis(AMOTION_EVENT_AXIS_RELATIVE_Y, /*y=*/0);
3117+
mChoreographer.notifyMotion(
3118+
MotionArgsBuilder(AMOTION_EVENT_ACTION_HOVER_MOVE, AINPUT_SOURCE_MOUSE)
3119+
.pointer(pointerBuilder)
3120+
.deviceId(DEVICE_ID)
3121+
.displayId(ui::LogicalDisplayId::INVALID)
3122+
.build());
3123+
3124+
assertPointerControllerNotCreated();
3125+
pc->assertViewportSet(SECOND_DISPLAY_ID);
3126+
ASSERT_TRUE(pc->isPointerShown());
3127+
}
3128+
3129+
TEST_F(PointerChoreographerDisplayTopologyDefaultMouseDisplayTests,
3130+
AddAssociatedDisplayCursorOutsideOfDisplayTopology) {
3131+
SCOPED_FLAG_OVERRIDE(connected_displays_cursor, true);
3132+
SCOPED_FLAG_OVERRIDE(connected_displays_associated_display_cursor_bugfix, true);
3133+
3134+
// Add three displays, with only first and second display in DisplayTopolgoy
3135+
mChoreographer.setDisplayViewports({createViewport(FIRST_DISPLAY_ID),
3136+
createViewport(SECOND_DISPLAY_ID),
3137+
createViewport(THIRD_DISPLAY_ID)});
3138+
setDisplayTopologyWithDisplays(/*primaryDisplayId=*/FIRST_DISPLAY_ID,
3139+
/*adjacentDisplays=*/{SECOND_DISPLAY_ID});
3140+
3141+
mChoreographer.notifyInputDevicesChanged(
3142+
{/*id=*/0,
3143+
{generateTestDeviceInfo(DEVICE_ID, AINPUT_SOURCE_MOUSE,
3144+
ui::LogicalDisplayId::INVALID)}});
3145+
3146+
auto pc = assertPointerControllerCreated(ControllerType::MOUSE);
3147+
pc->assertViewportSet(FIRST_DISPLAY_ID);
3148+
ASSERT_TRUE(pc->isPointerShown());
3149+
3150+
// Adds a new mouse associated with third display
3151+
mChoreographer.notifyInputDevicesChanged(
3152+
{/*id=*/1, {generateTestDeviceInfo(DEVICE_ID, AINPUT_SOURCE_MOUSE, THIRD_DISPLAY_ID)}});
3153+
3154+
pc = assertPointerControllerCreated(ControllerType::MOUSE);
3155+
pc->assertViewportSet(THIRD_DISPLAY_ID);
3156+
ASSERT_TRUE(pc->isPointerShown());
3157+
}
3158+
30753159
class PointerChoreographerWindowInfoListenerTest : public testing::Test {};
30763160

30773161
TEST_F_WITH_FLAGS(

0 commit comments

Comments
 (0)