diff options
4 files changed, 370 insertions, 151 deletions
diff --git a/services/inputflinger/PointerChoreographer.cpp b/services/inputflinger/PointerChoreographer.cpp index 21f4f2c3ba..e06ff6b9c7 100644 --- a/services/inputflinger/PointerChoreographer.cpp +++ b/services/inputflinger/PointerChoreographer.cpp @@ -602,15 +602,21 @@ void PointerChoreographer::notifyPointerCaptureChanged( } void PointerChoreographer::setDisplayTopology(const DisplayTopologyGraph& displayTopologyGraph) { - std::scoped_lock _l(getLock()); - mTopology = displayTopologyGraph; + PointerDisplayChange pointerDisplayChange; + { // acquire lock + std::scoped_lock _l(getLock()); + mTopology = displayTopologyGraph; + + // 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; + pointerDisplayChange = updatePointerControllersLocked(); + } + } // release lock - // 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; - } + notifyPointerDisplayChange(pointerDisplayChange, mPolicy); } void PointerChoreographer::dump(std::string& dump) { @@ -785,6 +791,10 @@ PointerChoreographer::calculatePointerDisplayChangeToNotify() { } void PointerChoreographer::setDefaultMouseDisplayId(ui::LogicalDisplayId displayId) { + if (InputFlags::connectedDisplaysCursorEnabled()) { + // In connected displays scenario, default mouse display will only be updated from topology. + return; + } PointerDisplayChange pointerDisplayChange; { // acquire lock diff --git a/services/inputflinger/dispatcher/InputDispatcher.cpp b/services/inputflinger/dispatcher/InputDispatcher.cpp index ba7507133e..ef50fc0036 100644 --- a/services/inputflinger/dispatcher/InputDispatcher.cpp +++ b/services/inputflinger/dispatcher/InputDispatcher.cpp @@ -7553,9 +7553,10 @@ void InputDispatcher::DispatcherTouchState::forTouchAndCursorStatesOnDisplay( return; } - // TODO(b/383092013): This is currently not accounting for the "topology group" concept. - // Proper implementation requires looking tghrough all the displays in the topology group. - const auto cursorStateIt = mCursorStateByDisplay.find(displayId); + // DisplayId for the Cursor state may not be same as supplied displayId if display is part of + // topology. Instead we should to check from the topology's primary display. + const auto cursorStateIt = + mCursorStateByDisplay.find(mWindowInfos.getPrimaryDisplayId(displayId)); if (cursorStateIt != mCursorStateByDisplay.end()) { f(cursorStateIt->second); } diff --git a/services/inputflinger/tests/InputDispatcher_test.cpp b/services/inputflinger/tests/InputDispatcher_test.cpp index 1778f6d508..2b9b470a21 100644 --- a/services/inputflinger/tests/InputDispatcher_test.cpp +++ b/services/inputflinger/tests/InputDispatcher_test.cpp @@ -15403,4 +15403,47 @@ TEST_F(InputDispatcherConnectedDisplayTest, MultiDisplayMouseDragAndDropFromNonP mWindowOnSecondDisplay->assertNoEvents(); } +using InputDispatcherConnectedDisplayPointerInWindowTest = InputDispatcherConnectedDisplayTest; + +TEST_F(InputDispatcherConnectedDisplayPointerInWindowTest, MouseOnWindowOnPrimaryDisplay) { + SCOPED_FLAG_OVERRIDE(connected_displays_cursor, true); + + mDispatcher->notifyMotion( + MotionArgsBuilder(ACTION_HOVER_ENTER, AINPUT_SOURCE_MOUSE) + .pointer(PointerBuilder(/*id=*/0, ToolType::MOUSE).x(50).y(50)) + .build()); + + mWindow->consumeMotionEvent(WithMotionAction(ACTION_HOVER_ENTER)); + mSpyWindow->consumeMotionEvent(WithMotionAction(ACTION_HOVER_ENTER)); + mWindowOnSecondDisplay->assertNoEvents(); + + ASSERT_TRUE(mDispatcher->isPointerInWindow(mWindow->getToken(), DISPLAY_ID, DEVICE_ID, + /*pointerId=*/0)); + ASSERT_TRUE(mDispatcher->isPointerInWindow(mSpyWindow->getToken(), DISPLAY_ID, DEVICE_ID, + /*pointerId=*/0)); + ASSERT_FALSE(mDispatcher->isPointerInWindow(mWindowOnSecondDisplay->getToken(), + SECOND_DISPLAY_ID, DEVICE_ID, /*pointerId=*/0)); +} + +TEST_F(InputDispatcherConnectedDisplayPointerInWindowTest, MouseOnWindowOnNonPrimaryDisplay) { + SCOPED_FLAG_OVERRIDE(connected_displays_cursor, true); + + mDispatcher->notifyMotion( + MotionArgsBuilder(ACTION_HOVER_ENTER, AINPUT_SOURCE_MOUSE) + .displayId(SECOND_DISPLAY_ID) + .pointer(PointerBuilder(/*id=*/0, ToolType::MOUSE).x(50).y(50)) + .build()); + + mWindow->assertNoEvents(); + mSpyWindow->assertNoEvents(); + mWindowOnSecondDisplay->consumeMotionEvent(WithMotionAction(ACTION_HOVER_ENTER)); + + ASSERT_FALSE(mDispatcher->isPointerInWindow(mWindow->getToken(), DISPLAY_ID, DEVICE_ID, + /*pointerId=*/0)); + ASSERT_FALSE(mDispatcher->isPointerInWindow(mSpyWindow->getToken(), DISPLAY_ID, DEVICE_ID, + /*pointerId=*/0)); + ASSERT_TRUE(mDispatcher->isPointerInWindow(mWindowOnSecondDisplay->getToken(), + SECOND_DISPLAY_ID, DEVICE_ID, /*pointerId=*/0)); +} + } // namespace android::inputdispatcher diff --git a/services/inputflinger/tests/PointerChoreographer_test.cpp b/services/inputflinger/tests/PointerChoreographer_test.cpp index 99db8fead7..3aad16f533 100644 --- a/services/inputflinger/tests/PointerChoreographer_test.cpp +++ b/services/inputflinger/tests/PointerChoreographer_test.cpp @@ -24,6 +24,7 @@ #include "FakePointerController.h" #include "InterfaceMocks.h" #include "NotifyArgsBuilders.h" +#include "ScopedFlagOverride.h" #include "TestEventMatchers.h" #include "TestInputListener.h" @@ -114,6 +115,10 @@ TestPointerChoreographer::TestPointerChoreographer( }) {} class PointerChoreographerTest : public testing::Test { +public: + static constexpr int DENSITY_MEDIUM = 160; + static constexpr int DENSITY_HIGH = 320; + protected: TestInputListener mTestListener; sp<gui::WindowInfosListener> mRegisteredWindowInfoListener; @@ -140,6 +145,22 @@ protected: }); } + void setDefaultMouseDisplayId(ui::LogicalDisplayId displayId) { + if (input_flags::connected_displays_cursor()) { + // setDefaultMouseDisplayId is no-op if connected displays are enabled, mouse display is + // set based on primary display of the topology. + // Setting topology with the primary display should have same effect as calling + // setDefaultMouseDisplayId without topology. + // For this reason in tests we mock this behavior by creating topology with a single + // display. + mChoreographer.setDisplayTopology({.primaryDisplayId = displayId, + .graph{{displayId, {}}}, + .displaysDensity = {{displayId, DENSITY_MEDIUM}}}); + } else { + mChoreographer.setDefaultMouseDisplayId(displayId); + } + } + std::shared_ptr<FakePointerController> assertPointerControllerCreated( ControllerType expectedType) { EXPECT_FALSE(mCreatedControllers.empty()) << "No PointerController was created"; @@ -292,7 +313,7 @@ TEST_F(PointerChoreographerTest, WhenViewportSetLaterSetsViewportForAssociatedMo TEST_F(PointerChoreographerTest, SetsDefaultMouseViewportForPointerController) { mChoreographer.setDisplayViewports(createViewports({DISPLAY_ID})); - mChoreographer.setDefaultMouseDisplayId(DISPLAY_ID); + setDefaultMouseDisplayId(DISPLAY_ID); // For a mouse event without a target display, default viewport should be set for // the PointerController. @@ -309,7 +330,7 @@ TEST_F(PointerChoreographerTest, WhenDefaultMouseDisplayChangesSetsDefaultMouseViewportForPointerController) { // Set one display as a default mouse display and emit mouse event to create PointerController. mChoreographer.setDisplayViewports(createViewports({DISPLAY_ID, ANOTHER_DISPLAY_ID})); - mChoreographer.setDefaultMouseDisplayId(DISPLAY_ID); + setDefaultMouseDisplayId(DISPLAY_ID); mChoreographer.notifyInputDevicesChanged( {/*id=*/0, {generateTestDeviceInfo(DEVICE_ID, AINPUT_SOURCE_MOUSE, @@ -320,7 +341,7 @@ TEST_F(PointerChoreographerTest, // Change default mouse display. Existing PointerController should be removed and a new one // should be created. - mChoreographer.setDefaultMouseDisplayId(ANOTHER_DISPLAY_ID); + setDefaultMouseDisplayId(ANOTHER_DISPLAY_ID); assertPointerControllerRemoved(firstDisplayPc); auto secondDisplayPc = assertPointerControllerCreated(ControllerType::MOUSE); @@ -329,7 +350,7 @@ TEST_F(PointerChoreographerTest, } TEST_F(PointerChoreographerTest, CallsNotifyPointerDisplayIdChanged) { - mChoreographer.setDefaultMouseDisplayId(DISPLAY_ID); + setDefaultMouseDisplayId(DISPLAY_ID); mChoreographer.setDisplayViewports(createViewports({DISPLAY_ID})); mChoreographer.notifyInputDevicesChanged( {/*id=*/0, @@ -341,7 +362,7 @@ TEST_F(PointerChoreographerTest, CallsNotifyPointerDisplayIdChanged) { } TEST_F(PointerChoreographerTest, WhenViewportIsSetLaterCallsNotifyPointerDisplayIdChanged) { - mChoreographer.setDefaultMouseDisplayId(DISPLAY_ID); + setDefaultMouseDisplayId(DISPLAY_ID); mChoreographer.notifyInputDevicesChanged( {/*id=*/0, {generateTestDeviceInfo(DEVICE_ID, AINPUT_SOURCE_MOUSE, @@ -354,7 +375,7 @@ TEST_F(PointerChoreographerTest, WhenViewportIsSetLaterCallsNotifyPointerDisplay } TEST_F(PointerChoreographerTest, WhenMouseIsRemovedCallsNotifyPointerDisplayIdChanged) { - mChoreographer.setDefaultMouseDisplayId(DISPLAY_ID); + setDefaultMouseDisplayId(DISPLAY_ID); mChoreographer.setDisplayViewports(createViewports({DISPLAY_ID})); mChoreographer.notifyInputDevicesChanged( {/*id=*/0, @@ -373,7 +394,7 @@ TEST_F(PointerChoreographerTest, WhenDefaultMouseDisplayChangesCallsNotifyPointe mChoreographer.setDisplayViewports(createViewports({DISPLAY_ID, ANOTHER_DISPLAY_ID})); // Set one viewport as a default mouse display ID. - mChoreographer.setDefaultMouseDisplayId(DISPLAY_ID); + setDefaultMouseDisplayId(DISPLAY_ID); mChoreographer.notifyInputDevicesChanged( {/*id=*/0, {generateTestDeviceInfo(DEVICE_ID, AINPUT_SOURCE_MOUSE, @@ -382,7 +403,7 @@ TEST_F(PointerChoreographerTest, WhenDefaultMouseDisplayChangesCallsNotifyPointe assertPointerDisplayIdNotified(DISPLAY_ID); // Set another viewport as a default mouse display ID. The mouse is moved to the other display. - mChoreographer.setDefaultMouseDisplayId(ANOTHER_DISPLAY_ID); + setDefaultMouseDisplayId(ANOTHER_DISPLAY_ID); assertPointerControllerRemoved(firstDisplayPc); assertPointerControllerCreated(ControllerType::MOUSE); @@ -391,7 +412,7 @@ TEST_F(PointerChoreographerTest, WhenDefaultMouseDisplayChangesCallsNotifyPointe TEST_F(PointerChoreographerTest, MouseMovesPointerAndReturnsNewArgs) { mChoreographer.setDisplayViewports(createViewports({DISPLAY_ID})); - mChoreographer.setDefaultMouseDisplayId(DISPLAY_ID); + setDefaultMouseDisplayId(DISPLAY_ID); mChoreographer.notifyInputDevicesChanged( {/*id=*/0, {generateTestDeviceInfo(DEVICE_ID, AINPUT_SOURCE_MOUSE, @@ -421,7 +442,7 @@ TEST_F(PointerChoreographerTest, MouseMovesPointerAndReturnsNewArgs) { TEST_F(PointerChoreographerTest, AbsoluteMouseMovesPointerAndReturnsNewArgs) { mChoreographer.setDisplayViewports(createViewports({DISPLAY_ID})); - mChoreographer.setDefaultMouseDisplayId(DISPLAY_ID); + setDefaultMouseDisplayId(DISPLAY_ID); mChoreographer.notifyInputDevicesChanged( {/*id=*/0, {generateTestDeviceInfo(DEVICE_ID, AINPUT_SOURCE_MOUSE, @@ -457,7 +478,7 @@ TEST_F(PointerChoreographerTest, AssociatedMouseMovesPointerOnAssociatedDisplayAndDoesNotMovePointerOnDefaultDisplay) { // Add two displays and set one to default. mChoreographer.setDisplayViewports(createViewports({DISPLAY_ID, ANOTHER_DISPLAY_ID})); - mChoreographer.setDefaultMouseDisplayId(DISPLAY_ID); + setDefaultMouseDisplayId(DISPLAY_ID); // Add two devices, one unassociated and the other associated with non-default mouse display. mChoreographer.notifyInputDevicesChanged( @@ -496,7 +517,7 @@ TEST_F(PointerChoreographerTest, TEST_F(PointerChoreographerTest, DoesNotMovePointerForMouseRelativeSource) { mChoreographer.setDisplayViewports(createViewports({DISPLAY_ID})); - mChoreographer.setDefaultMouseDisplayId(DISPLAY_ID); + setDefaultMouseDisplayId(DISPLAY_ID); mChoreographer.notifyInputDevicesChanged( {/*id=*/0, {generateTestDeviceInfo(DEVICE_ID, AINPUT_SOURCE_MOUSE, @@ -543,7 +564,7 @@ TEST_F(PointerChoreographerTest, DoesNotMovePointerForMouseRelativeSource) { TEST_F(PointerChoreographerTest, WhenPointerCaptureEnabledHidesPointer) { mChoreographer.setDisplayViewports(createViewports({DISPLAY_ID})); - mChoreographer.setDefaultMouseDisplayId(DISPLAY_ID); + setDefaultMouseDisplayId(DISPLAY_ID); mChoreographer.notifyInputDevicesChanged( {/*id=*/0, {generateTestDeviceInfo(DEVICE_ID, AINPUT_SOURCE_MOUSE, @@ -562,7 +583,7 @@ TEST_F(PointerChoreographerTest, WhenPointerCaptureEnabledHidesPointer) { TEST_F(PointerChoreographerTest, MultipleMiceConnectionAndRemoval) { mChoreographer.setDisplayViewports(createViewports({DISPLAY_ID})); - mChoreographer.setDefaultMouseDisplayId(DISPLAY_ID); + setDefaultMouseDisplayId(DISPLAY_ID); // A mouse is connected, and the pointer is shown. mChoreographer.notifyInputDevicesChanged( @@ -599,7 +620,7 @@ TEST_F(PointerChoreographerTest, MultipleMiceConnectionAndRemoval) { TEST_F(PointerChoreographerTest, UnrelatedChangeDoesNotUnfadePointer) { mChoreographer.setDisplayViewports(createViewports({DISPLAY_ID})); - mChoreographer.setDefaultMouseDisplayId(DISPLAY_ID); + setDefaultMouseDisplayId(DISPLAY_ID); mChoreographer.notifyInputDevicesChanged( {/*id=*/0, {generateTestDeviceInfo(DEVICE_ID, AINPUT_SOURCE_MOUSE, @@ -628,7 +649,7 @@ TEST_F(PointerChoreographerTest, UnrelatedChangeDoesNotUnfadePointer) { TEST_F(PointerChoreographerTest, DisabledMouseConnected) { mChoreographer.setDisplayViewports(createViewports({DISPLAY_ID})); - mChoreographer.setDefaultMouseDisplayId(DISPLAY_ID); + setDefaultMouseDisplayId(DISPLAY_ID); InputDeviceInfo mouseDeviceInfo = generateTestDeviceInfo(DEVICE_ID, AINPUT_SOURCE_MOUSE, ui::LogicalDisplayId::INVALID); // Disable this mouse device. @@ -641,7 +662,7 @@ TEST_F(PointerChoreographerTest, DisabledMouseConnected) { TEST_F(PointerChoreographerTest, MouseDeviceDisableLater) { mChoreographer.setDisplayViewports(createViewports({DISPLAY_ID})); - mChoreographer.setDefaultMouseDisplayId(DISPLAY_ID); + setDefaultMouseDisplayId(DISPLAY_ID); InputDeviceInfo mouseDeviceInfo = generateTestDeviceInfo(DEVICE_ID, AINPUT_SOURCE_MOUSE, ui::LogicalDisplayId::INVALID); @@ -660,7 +681,7 @@ TEST_F(PointerChoreographerTest, MouseDeviceDisableLater) { TEST_F(PointerChoreographerTest, MultipleEnabledAndDisabledMiceConnectionAndRemoval) { mChoreographer.setDisplayViewports(createViewports({DISPLAY_ID})); - mChoreographer.setDefaultMouseDisplayId(DISPLAY_ID); + setDefaultMouseDisplayId(DISPLAY_ID); InputDeviceInfo disabledMouseDeviceInfo = generateTestDeviceInfo(DEVICE_ID, AINPUT_SOURCE_MOUSE, ui::LogicalDisplayId::INVALID); disabledMouseDeviceInfo.setEnabled(false); @@ -1011,7 +1032,7 @@ TEST_F(PointerChoreographerTest, ShowTouchesOverridesUnspecifiedStylusIcon) { TEST_F(PointerChoreographerTest, StylusHoverEnterFadesMouseOnDisplay) { // Make sure there are PointerControllers for a mouse and a stylus. mChoreographer.setStylusPointerIconEnabled(true); - mChoreographer.setDefaultMouseDisplayId(DISPLAY_ID); + setDefaultMouseDisplayId(DISPLAY_ID); mChoreographer.notifyInputDevicesChanged( {/*id=*/0, {generateTestDeviceInfo(DEVICE_ID, AINPUT_SOURCE_MOUSE, ui::LogicalDisplayId::INVALID), @@ -1406,7 +1427,7 @@ TEST_F(PointerChoreographerTest, WhenViewportSetLaterSetsViewportForAssociatedTo TEST_F(PointerChoreographerTest, SetsDefaultTouchpadViewportForPointerController) { mChoreographer.setDisplayViewports(createViewports({DISPLAY_ID})); - mChoreographer.setDefaultMouseDisplayId(DISPLAY_ID); + setDefaultMouseDisplayId(DISPLAY_ID); // For a touchpad event without a target display, default viewport should be set for // the PointerController. @@ -1422,7 +1443,7 @@ TEST_F(PointerChoreographerTest, WhenDefaultTouchpadDisplayChangesSetsDefaultTouchpadViewportForPointerController) { // Set one display as a default touchpad display and create PointerController. mChoreographer.setDisplayViewports(createViewports({DISPLAY_ID, ANOTHER_DISPLAY_ID})); - mChoreographer.setDefaultMouseDisplayId(DISPLAY_ID); + setDefaultMouseDisplayId(DISPLAY_ID); mChoreographer.notifyInputDevicesChanged( {/*id=*/0, {generateTestDeviceInfo(DEVICE_ID, AINPUT_SOURCE_MOUSE | AINPUT_SOURCE_TOUCHPAD, @@ -1431,7 +1452,7 @@ TEST_F(PointerChoreographerTest, firstDisplayPc->assertViewportSet(DISPLAY_ID); // Change default mouse display. Existing PointerController should be removed. - mChoreographer.setDefaultMouseDisplayId(ANOTHER_DISPLAY_ID); + setDefaultMouseDisplayId(ANOTHER_DISPLAY_ID); assertPointerControllerRemoved(firstDisplayPc); auto secondDisplayPc = assertPointerControllerCreated(ControllerType::MOUSE); @@ -1439,7 +1460,7 @@ TEST_F(PointerChoreographerTest, } TEST_F(PointerChoreographerTest, TouchpadCallsNotifyPointerDisplayIdChanged) { - mChoreographer.setDefaultMouseDisplayId(DISPLAY_ID); + setDefaultMouseDisplayId(DISPLAY_ID); mChoreographer.setDisplayViewports(createViewports({DISPLAY_ID})); mChoreographer.notifyInputDevicesChanged( {/*id=*/0, @@ -1451,7 +1472,7 @@ TEST_F(PointerChoreographerTest, TouchpadCallsNotifyPointerDisplayIdChanged) { } TEST_F(PointerChoreographerTest, WhenViewportIsSetLaterTouchpadCallsNotifyPointerDisplayIdChanged) { - mChoreographer.setDefaultMouseDisplayId(DISPLAY_ID); + setDefaultMouseDisplayId(DISPLAY_ID); mChoreographer.notifyInputDevicesChanged( {/*id=*/0, {generateTestDeviceInfo(DEVICE_ID, AINPUT_SOURCE_MOUSE | AINPUT_SOURCE_TOUCHPAD, @@ -1464,7 +1485,7 @@ TEST_F(PointerChoreographerTest, WhenViewportIsSetLaterTouchpadCallsNotifyPointe } TEST_F(PointerChoreographerTest, WhenTouchpadIsRemovedCallsNotifyPointerDisplayIdChanged) { - mChoreographer.setDefaultMouseDisplayId(DISPLAY_ID); + setDefaultMouseDisplayId(DISPLAY_ID); mChoreographer.setDisplayViewports(createViewports({DISPLAY_ID})); mChoreographer.notifyInputDevicesChanged( {/*id=*/0, @@ -1484,7 +1505,7 @@ TEST_F(PointerChoreographerTest, mChoreographer.setDisplayViewports(createViewports({DISPLAY_ID, ANOTHER_DISPLAY_ID})); // Set one viewport as a default mouse display ID. - mChoreographer.setDefaultMouseDisplayId(DISPLAY_ID); + setDefaultMouseDisplayId(DISPLAY_ID); mChoreographer.notifyInputDevicesChanged( {/*id=*/0, {generateTestDeviceInfo(DEVICE_ID, AINPUT_SOURCE_MOUSE | AINPUT_SOURCE_TOUCHPAD, @@ -1494,7 +1515,7 @@ TEST_F(PointerChoreographerTest, // Set another viewport as a default mouse display ID. ui::LogicalDisplayId::INVALID will be // notified before a touchpad event. - mChoreographer.setDefaultMouseDisplayId(ANOTHER_DISPLAY_ID); + setDefaultMouseDisplayId(ANOTHER_DISPLAY_ID); assertPointerControllerRemoved(firstDisplayPc); assertPointerControllerCreated(ControllerType::MOUSE); @@ -1503,7 +1524,7 @@ TEST_F(PointerChoreographerTest, TEST_F(PointerChoreographerTest, TouchpadMovesPointerAndReturnsNewArgs) { mChoreographer.setDisplayViewports(createViewports({DISPLAY_ID})); - mChoreographer.setDefaultMouseDisplayId(DISPLAY_ID); + setDefaultMouseDisplayId(DISPLAY_ID); mChoreographer.notifyInputDevicesChanged( {/*id=*/0, {generateTestDeviceInfo(DEVICE_ID, AINPUT_SOURCE_MOUSE | AINPUT_SOURCE_TOUCHPAD, @@ -1533,7 +1554,7 @@ TEST_F(PointerChoreographerTest, TouchpadMovesPointerAndReturnsNewArgs) { TEST_F(PointerChoreographerTest, TouchpadAddsPointerPositionToTheCoords) { mChoreographer.setDisplayViewports(createViewports({DISPLAY_ID})); - mChoreographer.setDefaultMouseDisplayId(DISPLAY_ID); + setDefaultMouseDisplayId(DISPLAY_ID); mChoreographer.notifyInputDevicesChanged( {/*id=*/0, {generateTestDeviceInfo(DEVICE_ID, AINPUT_SOURCE_MOUSE | AINPUT_SOURCE_TOUCHPAD, @@ -1610,7 +1631,7 @@ TEST_F(PointerChoreographerTest, AssociatedTouchpadMovesPointerOnAssociatedDisplayAndDoesNotMovePointerOnDefaultDisplay) { // Add two displays and set one to default. mChoreographer.setDisplayViewports(createViewports({DISPLAY_ID, ANOTHER_DISPLAY_ID})); - mChoreographer.setDefaultMouseDisplayId(DISPLAY_ID); + setDefaultMouseDisplayId(DISPLAY_ID); // Add two devices, one unassociated and the other associated with non-default mouse display. mChoreographer.notifyInputDevicesChanged( @@ -1651,7 +1672,7 @@ TEST_F(PointerChoreographerTest, TEST_F(PointerChoreographerTest, DoesNotMovePointerForTouchpadSource) { mChoreographer.setDisplayViewports(createViewports({DISPLAY_ID})); - mChoreographer.setDefaultMouseDisplayId(DISPLAY_ID); + setDefaultMouseDisplayId(DISPLAY_ID); mChoreographer.notifyInputDevicesChanged( {/*id=*/0, {generateTestDeviceInfo(DEVICE_ID, AINPUT_SOURCE_MOUSE | AINPUT_SOURCE_TOUCHPAD, @@ -1688,7 +1709,7 @@ TEST_F(PointerChoreographerTest, DoesNotMovePointerForTouchpadSource) { TEST_F(PointerChoreographerTest, WhenPointerCaptureEnabledTouchpadHidesPointer) { mChoreographer.setDisplayViewports(createViewports({DISPLAY_ID})); - mChoreographer.setDefaultMouseDisplayId(DISPLAY_ID); + setDefaultMouseDisplayId(DISPLAY_ID); mChoreographer.notifyInputDevicesChanged( {/*id=*/0, {generateTestDeviceInfo(DEVICE_ID, AINPUT_SOURCE_MOUSE | AINPUT_SOURCE_TOUCHPAD, @@ -1708,7 +1729,7 @@ TEST_F(PointerChoreographerTest, WhenPointerCaptureEnabledTouchpadHidesPointer) TEST_F(PointerChoreographerTest, SetsPointerIconForMouse) { // Make sure there is a PointerController. mChoreographer.setDisplayViewports(createViewports({DISPLAY_ID})); - mChoreographer.setDefaultMouseDisplayId(DISPLAY_ID); + setDefaultMouseDisplayId(DISPLAY_ID); mChoreographer.notifyInputDevicesChanged( {/*id=*/0, {generateTestDeviceInfo(DEVICE_ID, AINPUT_SOURCE_MOUSE, @@ -1724,7 +1745,7 @@ TEST_F(PointerChoreographerTest, SetsPointerIconForMouse) { TEST_F(PointerChoreographerTest, DoesNotSetMousePointerIconForWrongDisplayId) { // Make sure there is a PointerController. mChoreographer.setDisplayViewports(createViewports({DISPLAY_ID})); - mChoreographer.setDefaultMouseDisplayId(DISPLAY_ID); + setDefaultMouseDisplayId(DISPLAY_ID); mChoreographer.notifyInputDevicesChanged( {/*id=*/0, {generateTestDeviceInfo(DEVICE_ID, AINPUT_SOURCE_MOUSE, @@ -1741,7 +1762,7 @@ TEST_F(PointerChoreographerTest, DoesNotSetMousePointerIconForWrongDisplayId) { TEST_F(PointerChoreographerTest, DoesNotSetPointerIconForWrongDeviceId) { // Make sure there is a PointerController. mChoreographer.setDisplayViewports(createViewports({DISPLAY_ID})); - mChoreographer.setDefaultMouseDisplayId(DISPLAY_ID); + setDefaultMouseDisplayId(DISPLAY_ID); mChoreographer.notifyInputDevicesChanged( {/*id=*/0, {generateTestDeviceInfo(DEVICE_ID, AINPUT_SOURCE_MOUSE, @@ -1758,7 +1779,7 @@ TEST_F(PointerChoreographerTest, DoesNotSetPointerIconForWrongDeviceId) { TEST_F(PointerChoreographerTest, SetsCustomPointerIconForMouse) { // Make sure there is a PointerController. mChoreographer.setDisplayViewports(createViewports({DISPLAY_ID})); - mChoreographer.setDefaultMouseDisplayId(DISPLAY_ID); + setDefaultMouseDisplayId(DISPLAY_ID); mChoreographer.notifyInputDevicesChanged( {/*id=*/0, {generateTestDeviceInfo(DEVICE_ID, AINPUT_SOURCE_MOUSE, @@ -1782,7 +1803,7 @@ TEST_F(PointerChoreographerTest, SetsCustomPointerIconForMouse) { TEST_F(PointerChoreographerTest, SetsPointerIconForMouseOnTwoDisplays) { // Make sure there are two PointerControllers on different displays. mChoreographer.setDisplayViewports(createViewports({DISPLAY_ID, ANOTHER_DISPLAY_ID})); - mChoreographer.setDefaultMouseDisplayId(DISPLAY_ID); + setDefaultMouseDisplayId(DISPLAY_ID); mChoreographer.notifyInputDevicesChanged( {/*id=*/0, {generateTestDeviceInfo(DEVICE_ID, AINPUT_SOURCE_MOUSE, ui::LogicalDisplayId::INVALID), @@ -1806,7 +1827,7 @@ TEST_F(PointerChoreographerTest, SetsPointerIconForMouseOnTwoDisplays) { TEST_F(PointerChoreographerTest, A11yPointerMotionFilterMouse) { mChoreographer.setDisplayViewports(createViewports({DISPLAY_ID})); - mChoreographer.setDefaultMouseDisplayId(DISPLAY_ID); + setDefaultMouseDisplayId(DISPLAY_ID); mChoreographer.notifyInputDevicesChanged( {/*id=*/0, {generateTestDeviceInfo(DEVICE_ID, AINPUT_SOURCE_MOUSE, @@ -1840,7 +1861,7 @@ TEST_F(PointerChoreographerTest, A11yPointerMotionFilterMouse) { TEST_F(PointerChoreographerTest, A11yPointerMotionFilterTouchpad) { mChoreographer.setDisplayViewports(createViewports({DISPLAY_ID})); - mChoreographer.setDefaultMouseDisplayId(DISPLAY_ID); + setDefaultMouseDisplayId(DISPLAY_ID); mChoreographer.notifyInputDevicesChanged( {/*id=*/0, {generateTestDeviceInfo(DEVICE_ID, AINPUT_SOURCE_MOUSE | AINPUT_SOURCE_TOUCHPAD, @@ -2238,7 +2259,7 @@ TEST_P(StylusTestFixture, SetsPointerIconForMouseAndStylus) { // Make sure there are PointerControllers for a mouse and a stylus. mChoreographer.setStylusPointerIconEnabled(true); - mChoreographer.setDefaultMouseDisplayId(DISPLAY_ID); + setDefaultMouseDisplayId(DISPLAY_ID); mChoreographer.notifyInputDevicesChanged( {/*id=*/0, {generateTestDeviceInfo(DEVICE_ID, AINPUT_SOURCE_MOUSE, ui::LogicalDisplayId::INVALID), @@ -2273,7 +2294,7 @@ TEST_P(StylusTestFixture, SetsPointerIconForMouseAndStylus) { TEST_F(PointerChoreographerTest, SetPointerIconVisibilityHidesPointerOnDisplay) { // Make sure there are two PointerControllers on different displays. mChoreographer.setDisplayViewports(createViewports({DISPLAY_ID, ANOTHER_DISPLAY_ID})); - mChoreographer.setDefaultMouseDisplayId(DISPLAY_ID); + setDefaultMouseDisplayId(DISPLAY_ID); mChoreographer.notifyInputDevicesChanged( {/*id=*/0, {generateTestDeviceInfo(DEVICE_ID, AINPUT_SOURCE_MOUSE, ui::LogicalDisplayId::INVALID), @@ -2327,7 +2348,7 @@ TEST_F(PointerChoreographerTest, SetPointerIconVisibilityHidesPointerOnDisplay) TEST_F(PointerChoreographerTest, SetPointerIconVisibilityHidesPointerWhenDeviceConnected) { mChoreographer.setDisplayViewports(createViewports({DISPLAY_ID})); - mChoreographer.setDefaultMouseDisplayId(DISPLAY_ID); + setDefaultMouseDisplayId(DISPLAY_ID); // Hide the pointer on the display, and then connect the mouse. mChoreographer.setPointerIconVisibility(DISPLAY_ID, false); @@ -2344,7 +2365,7 @@ TEST_F(PointerChoreographerTest, SetPointerIconVisibilityHidesPointerWhenDeviceC TEST_F(PointerChoreographerTest, SetPointerIconVisibilityHidesPointerForTouchpad) { mChoreographer.setDisplayViewports(createViewports({DISPLAY_ID})); - mChoreographer.setDefaultMouseDisplayId(DISPLAY_ID); + setDefaultMouseDisplayId(DISPLAY_ID); // Hide the pointer on the display. mChoreographer.setPointerIconVisibility(DISPLAY_ID, false); @@ -2393,7 +2414,7 @@ TEST_P(StylusTestFixture, SetPointerIconVisibilityHidesPointerForStylus) { TEST_F(PointerChoreographerTest, DrawingTabletCanReportMouseEvent) { mChoreographer.setDisplayViewports(createViewports({DISPLAY_ID})); - mChoreographer.setDefaultMouseDisplayId(DISPLAY_ID); + setDefaultMouseDisplayId(DISPLAY_ID); mChoreographer.notifyInputDevicesChanged( {/*id=*/0, @@ -2420,7 +2441,7 @@ TEST_F(PointerChoreographerTest, DrawingTabletCanReportMouseEvent) { TEST_F(PointerChoreographerTest, MultipleDrawingTabletsReportMouseEvents) { mChoreographer.setDisplayViewports(createViewports({DISPLAY_ID})); - mChoreographer.setDefaultMouseDisplayId(DISPLAY_ID); + setDefaultMouseDisplayId(DISPLAY_ID); // First drawing tablet is added mChoreographer.notifyInputDevicesChanged( @@ -2468,7 +2489,7 @@ TEST_F(PointerChoreographerTest, MultipleDrawingTabletsReportMouseEvents) { TEST_F(PointerChoreographerTest, MouseAndDrawingTabletReportMouseEvents) { mChoreographer.setDisplayViewports(createViewports({DISPLAY_ID})); - mChoreographer.setDefaultMouseDisplayId(DISPLAY_ID); + setDefaultMouseDisplayId(DISPLAY_ID); // Mouse and drawing tablet connected mChoreographer.notifyInputDevicesChanged( @@ -2712,15 +2733,29 @@ TEST_P(PointerVisibilityAndTouchpadTapStateOnKeyPressTestFixture, TestMetaKeyCom metaKeyCombinationDoesNotHidePointer(*pc, AKEYCODE_A, AKEYCODE_META_RIGHT); } -using PointerChoreographerDisplayTopologyTestFixtureParam = +class PointerChoreographerDisplayTopologyTests : public PointerChoreographerTest { +protected: + DisplayViewport createViewport(ui::LogicalDisplayId displayId, int32_t width, int32_t height, + ui::Rotation orientation) { + DisplayViewport viewport; + viewport.displayId = displayId; + viewport.logicalRight = width; + viewport.logicalBottom = height; + viewport.orientation = orientation; + return viewport; + } +}; + +using PointerChoreographerDisplayTopologyCursorTestFixtureParam = std::tuple<std::string_view /*name*/, int32_t /*source device*/, ControllerType /*PointerController*/, ToolType /*pointer tool type*/, vec2 /*source position*/, vec2 /*hover move X/Y*/, ui::LogicalDisplayId /*destination display*/, vec2 /*destination position*/>; -class PointerChoreographerDisplayTopologyTestFixture - : public PointerChoreographerTest, - public testing::WithParamInterface<PointerChoreographerDisplayTopologyTestFixtureParam> { +class PointerChoreographerDisplayTopologyCursorTestFixture + : public PointerChoreographerDisplayTopologyTests, + public testing::WithParamInterface< + PointerChoreographerDisplayTopologyCursorTestFixtureParam> { public: static constexpr ui::LogicalDisplayId DISPLAY_CENTER_ID = ui::LogicalDisplayId{10}; static constexpr ui::LogicalDisplayId DISPLAY_TOP_ID = ui::LogicalDisplayId{20}; @@ -2730,13 +2765,6 @@ public: static constexpr ui::LogicalDisplayId DISPLAY_TOP_RIGHT_CORNER_ID = ui::LogicalDisplayId{60}; static constexpr ui::LogicalDisplayId DISPLAY_HIGH_DENSITY_ID = ui::LogicalDisplayId{70}; - static constexpr int DENSITY_MEDIUM = 160; - static constexpr int DENSITY_HIGH = 320; - - PointerChoreographerDisplayTopologyTestFixture() { - com::android::input::flags::connected_displays_cursor(true); - } - protected: // Note: viewport size is in pixels and offsets in topology are in dp std::vector<DisplayViewport> mViewports{ @@ -2769,34 +2797,24 @@ protected: {DISPLAY_LEFT_ID, DENSITY_MEDIUM}, {DISPLAY_TOP_RIGHT_CORNER_ID, DENSITY_MEDIUM}, {DISPLAY_HIGH_DENSITY_ID, DENSITY_HIGH}}}; - -private: - DisplayViewport createViewport(ui::LogicalDisplayId displayId, int32_t width, int32_t height, - ui::Rotation orientation) { - DisplayViewport viewport; - viewport.displayId = displayId; - viewport.logicalRight = width; - viewport.logicalBottom = height; - viewport.orientation = orientation; - return viewport; - } }; -TEST_P(PointerChoreographerDisplayTopologyTestFixture, PointerChoreographerDisplayTopologyTest) { +TEST_P(PointerChoreographerDisplayTopologyCursorTestFixture, + PointerChoreographerDisplayTopologyTest) { + SCOPED_FLAG_OVERRIDE(connected_displays_cursor, true); + const auto& [_, device, pointerControllerType, pointerToolType, initialPosition, hoverMove, destinationDisplay, destinationPosition] = GetParam(); mChoreographer.setDisplayViewports(mViewports); - mChoreographer.setDefaultMouseDisplayId( - PointerChoreographerDisplayTopologyTestFixture::DISPLAY_CENTER_ID); + setDefaultMouseDisplayId(DISPLAY_CENTER_ID); mChoreographer.setDisplayTopology(mTopology); mChoreographer.notifyInputDevicesChanged( {/*id=*/0, {generateTestDeviceInfo(DEVICE_ID, device, ui::LogicalDisplayId::INVALID)}}); auto pc = assertPointerControllerCreated(pointerControllerType); - ASSERT_EQ(PointerChoreographerDisplayTopologyTestFixture::DISPLAY_CENTER_ID, - pc->getDisplayId()); + ASSERT_EQ(DISPLAY_CENTER_ID, pc->getDisplayId()); // Set initial position of the PointerController. pc->setPosition(initialPosition.x, initialPosition.y); @@ -2828,84 +2846,231 @@ TEST_P(PointerChoreographerDisplayTopologyTestFixture, PointerChoreographerDispl } INSTANTIATE_TEST_SUITE_P( - PointerChoreographerTest, PointerChoreographerDisplayTopologyTestFixture, + PointerChoreographerTest, PointerChoreographerDisplayTopologyCursorTestFixture, testing::Values( // Note: Upon viewport transition cursor will be positioned at the boundary of the // destination, as we drop any unconsumed delta. - std::make_tuple("PrimaryDisplayIsDefault", AINPUT_SOURCE_MOUSE, - ControllerType::MOUSE, ToolType::MOUSE, - vec2(50, 50) /* initial x/y */, vec2(0, 0) /* delta x/y */, - PointerChoreographerDisplayTopologyTestFixture::DISPLAY_CENTER_ID, - vec2(50, 50) /* destination x/y */), - std::make_tuple("UnchangedDisplay", AINPUT_SOURCE_MOUSE, ControllerType::MOUSE, - ToolType::MOUSE, vec2(50, 50) /* initial x/y */, - vec2(25, 25) /* delta x/y */, - PointerChoreographerDisplayTopologyTestFixture::DISPLAY_CENTER_ID, - vec2(75, 75) /* destination x/y */), - std::make_tuple("TransitionToRightDisplay", AINPUT_SOURCE_MOUSE, - ControllerType::MOUSE, ToolType::MOUSE, - vec2(50, 50) /* initial x/y */, vec2(100, 25) /* delta x/y */, - PointerChoreographerDisplayTopologyTestFixture::DISPLAY_RIGHT_ID, - vec2(0, - 50 + 25 - 10) /* Left edge: (0, source + delta - offset) */), + std::make_tuple( + "PrimaryDisplayIsDefault", AINPUT_SOURCE_MOUSE, ControllerType::MOUSE, + ToolType::MOUSE, vec2(50, 50) /* initial x/y */, vec2(0, 0) /* delta x/y */, + PointerChoreographerDisplayTopologyCursorTestFixture::DISPLAY_CENTER_ID, + vec2(50, 50) /* destination x/y */), + std::make_tuple( + "UnchangedDisplay", AINPUT_SOURCE_MOUSE, ControllerType::MOUSE, + ToolType::MOUSE, vec2(50, 50) /* initial x/y */, + vec2(25, 25) /* delta x/y */, + PointerChoreographerDisplayTopologyCursorTestFixture::DISPLAY_CENTER_ID, + vec2(75, 75) /* destination x/y */), + std::make_tuple( + "TransitionToRightDisplay", AINPUT_SOURCE_MOUSE, ControllerType::MOUSE, + ToolType::MOUSE, vec2(50, 50) /* initial x/y */, + vec2(100, 25) /* delta x/y */, + PointerChoreographerDisplayTopologyCursorTestFixture::DISPLAY_RIGHT_ID, + vec2(0, 50 + 25 - 10) /* Left edge: (0, source + delta - offset) */), std::make_tuple( "TransitionToLeftDisplay", AINPUT_SOURCE_MOUSE, ControllerType::MOUSE, ToolType::MOUSE, vec2(50, 50) /* initial x/y */, vec2(-100, 25) /* delta x/y */, - PointerChoreographerDisplayTopologyTestFixture::DISPLAY_LEFT_ID, + PointerChoreographerDisplayTopologyCursorTestFixture::DISPLAY_LEFT_ID, vec2(90, 50 + 25 - 10) /* Right edge: (width, source + delta - offset*/), - std::make_tuple("TransitionToTopDisplay", - AINPUT_SOURCE_MOUSE | AINPUT_SOURCE_TOUCHPAD, ControllerType::MOUSE, - ToolType::FINGER, vec2(50, 50) /* initial x/y */, - vec2(25, -100) /* delta x/y */, - PointerChoreographerDisplayTopologyTestFixture::DISPLAY_TOP_ID, - vec2(50 + 25 - 50, - 90) /* Bottom edge: (source + delta - offset, height) */), - std::make_tuple("TransitionToBottomDisplay", - AINPUT_SOURCE_MOUSE | AINPUT_SOURCE_TOUCHPAD, ControllerType::MOUSE, - ToolType::FINGER, vec2(50, 50) /* initial x/y */, - vec2(25, 100) /* delta x/y */, - PointerChoreographerDisplayTopologyTestFixture::DISPLAY_BOTTOM_ID, - vec2(50 + 25 - 10, 0) /* Top edge: (source + delta - offset, 0) */), + std::make_tuple( + "TransitionToTopDisplay", AINPUT_SOURCE_MOUSE | AINPUT_SOURCE_TOUCHPAD, + ControllerType::MOUSE, ToolType::FINGER, vec2(50, 50) /* initial x/y */, + vec2(25, -100) /* delta x/y */, + PointerChoreographerDisplayTopologyCursorTestFixture::DISPLAY_TOP_ID, + vec2(50 + 25 - 50, + 90) /* Bottom edge: (source + delta - offset, height) */), + std::make_tuple( + "TransitionToBottomDisplay", AINPUT_SOURCE_MOUSE | AINPUT_SOURCE_TOUCHPAD, + ControllerType::MOUSE, ToolType::FINGER, vec2(50, 50) /* initial x/y */, + vec2(25, 100) /* delta x/y */, + PointerChoreographerDisplayTopologyCursorTestFixture::DISPLAY_BOTTOM_ID, + vec2(50 + 25 - 10, 0) /* Top edge: (source + delta - offset, 0) */), // move towards 25 dp gap between DISPLAY_HIGH_DENSITY_ID and DISPLAY_TOP_ID - std::make_tuple("NoTransitionAtTopOffset", AINPUT_SOURCE_MOUSE, - ControllerType::MOUSE, ToolType::MOUSE, - vec2(35, 50) /* initial x/y */, vec2(0, -100) /* Move Up */, - PointerChoreographerDisplayTopologyTestFixture::DISPLAY_CENTER_ID, - vec2(35, 0) /* Top edge */), - std::make_tuple("NoTransitionAtRightOffset", AINPUT_SOURCE_MOUSE, - ControllerType::MOUSE, ToolType::MOUSE, - vec2(95, 5) /* initial x/y */, vec2(100, 0) /* Move Right */, - PointerChoreographerDisplayTopologyTestFixture::DISPLAY_CENTER_ID, - vec2(99, 5) /* Top edge */), - std::make_tuple("NoTransitionAtBottomOffset", - AINPUT_SOURCE_MOUSE | AINPUT_SOURCE_TOUCHPAD, ControllerType::MOUSE, - ToolType::FINGER, vec2(5, 95) /* initial x/y */, - vec2(0, 100) /* Move Down */, - PointerChoreographerDisplayTopologyTestFixture::DISPLAY_CENTER_ID, - vec2(5, 99) /* Bottom edge */), - std::make_tuple("NoTransitionAtLeftOffset", - AINPUT_SOURCE_MOUSE | AINPUT_SOURCE_TOUCHPAD, ControllerType::MOUSE, - ToolType::FINGER, vec2(5, 5) /* initial x/y */, - vec2(-100, 0) /* Move Left */, - PointerChoreographerDisplayTopologyTestFixture::DISPLAY_CENTER_ID, - vec2(0, 5) /* Left edge */), std::make_tuple( - "TransitionAtTopRightCorner", AINPUT_SOURCE_MOUSE | AINPUT_SOURCE_TOUCHPAD, - ControllerType::MOUSE, ToolType::FINGER, vec2(95, 5) /* initial x/y */, - vec2(10, -10) /* Move diagonally to top right corner */, - PointerChoreographerDisplayTopologyTestFixture::DISPLAY_TOP_RIGHT_CORNER_ID, - vec2(0, 90) /* bottom left corner */), + "NoTransitionAtTopOffset", AINPUT_SOURCE_MOUSE, ControllerType::MOUSE, + ToolType::MOUSE, vec2(35, 50) /* initial x/y */, + vec2(0, -100) /* Move Up */, + PointerChoreographerDisplayTopologyCursorTestFixture::DISPLAY_CENTER_ID, + vec2(35, 0) /* Top edge */), std::make_tuple( - "TransitionToHighDpDisplay", AINPUT_SOURCE_MOUSE | AINPUT_SOURCE_TOUCHPAD, - ControllerType::MOUSE, ToolType::MOUSE, vec2(20, 20) /* initial x/y */, - vec2(0, -50) /* delta x/y */, - PointerChoreographerDisplayTopologyTestFixture::DISPLAY_HIGH_DENSITY_ID, - /* Bottom edge: ((source + delta - offset) * density, height) */ - vec2((20 + 0 + 75) * 2, 200))), - [](const testing::TestParamInfo<PointerChoreographerDisplayTopologyTestFixtureParam>& p) { - return std::string{std::get<0>(p.param)}; - }); + "NoTransitionAtRightOffset", AINPUT_SOURCE_MOUSE, ControllerType::MOUSE, + ToolType::MOUSE, vec2(95, 5) /* initial x/y */, + vec2(100, 0) /* Move Right */, + PointerChoreographerDisplayTopologyCursorTestFixture::DISPLAY_CENTER_ID, + vec2(99, 5) /* Top edge */), + std::make_tuple( + "NoTransitionAtBottomOffset", AINPUT_SOURCE_MOUSE | AINPUT_SOURCE_TOUCHPAD, + ControllerType::MOUSE, ToolType::FINGER, vec2(5, 95) /* initial x/y */, + vec2(0, 100) /* Move Down */, + PointerChoreographerDisplayTopologyCursorTestFixture::DISPLAY_CENTER_ID, + vec2(5, 99) /* Bottom edge */), + std::make_tuple( + "NoTransitionAtLeftOffset", AINPUT_SOURCE_MOUSE | AINPUT_SOURCE_TOUCHPAD, + ControllerType::MOUSE, ToolType::FINGER, vec2(5, 5) /* initial x/y */, + vec2(-100, 0) /* Move Left */, + PointerChoreographerDisplayTopologyCursorTestFixture::DISPLAY_CENTER_ID, + vec2(0, 5) /* Left edge */), + std::make_tuple("TransitionAtTopRightCorner", + AINPUT_SOURCE_MOUSE | AINPUT_SOURCE_TOUCHPAD, ControllerType::MOUSE, + ToolType::FINGER, vec2(95, 5) /* initial x/y */, + vec2(10, -10) /* Move diagonally to top right corner */, + PointerChoreographerDisplayTopologyCursorTestFixture:: + DISPLAY_TOP_RIGHT_CORNER_ID, + vec2(0, 90) /* bottom left corner */), + std::make_tuple("TransitionToHighDpDisplay", + AINPUT_SOURCE_MOUSE | AINPUT_SOURCE_TOUCHPAD, ControllerType::MOUSE, + ToolType::MOUSE, vec2(20, 20) /* initial x/y */, + vec2(0, -50) /* delta x/y */, + PointerChoreographerDisplayTopologyCursorTestFixture:: + DISPLAY_HIGH_DENSITY_ID, + /* Bottom edge: ((source + delta - offset) * density, height) */ + vec2((20 + 0 + 75) * 2, 200))), + [](const testing::TestParamInfo<PointerChoreographerDisplayTopologyCursorTestFixtureParam>& + p) { return std::string{std::get<0>(p.param)}; }); + +class PointerChoreographerDisplayTopologyDefaultMouseDisplayTests + : public PointerChoreographerDisplayTopologyTests { +protected: + static constexpr ui::LogicalDisplayId FIRST_DISPLAY_ID = ui::LogicalDisplayId{10}; + static constexpr ui::LogicalDisplayId SECOND_DISPLAY_ID = ui::LogicalDisplayId{20}; + static constexpr ui::LogicalDisplayId THIRD_DISPLAY_ID = ui::LogicalDisplayId{30}; + + DisplayViewport createViewport(ui::LogicalDisplayId displayId) { + return PointerChoreographerDisplayTopologyTests::createViewport(displayId, /*width=*/100, + /*height=*/100, + ui::ROTATION_0); + } + + void setDisplayTopologyWithDisplays( + ui::LogicalDisplayId primaryDisplayId, + const std::vector<ui::LogicalDisplayId>& adjacentDisplays = {}) { + // Prepare a topology with all display connected from left to right. + ui::LogicalDisplayId previousDisplay = primaryDisplayId; + + std::unordered_map<ui::LogicalDisplayId, std::vector<DisplayTopologyAdjacentDisplay>> + topologyGraph; + topologyGraph[primaryDisplayId] = {}; + + std::unordered_map<ui::LogicalDisplayId, int> displaysDensity; + displaysDensity[primaryDisplayId] = DENSITY_MEDIUM; + + for (ui::LogicalDisplayId adjacentDisplayId : adjacentDisplays) { + topologyGraph[previousDisplay].push_back({.displayId = adjacentDisplayId, + .position = DisplayTopologyPosition::RIGHT, + .offsetDp = 0.0f}); + topologyGraph[adjacentDisplayId].push_back({.displayId = previousDisplay, + .position = DisplayTopologyPosition::LEFT, + .offsetDp = 0.0f}); + + displaysDensity[adjacentDisplayId] = DENSITY_MEDIUM; + } + + mChoreographer.setDisplayTopology({primaryDisplayId, topologyGraph, displaysDensity}); + } +}; + +TEST_F(PointerChoreographerDisplayTopologyDefaultMouseDisplayTests, + UnrelatedTopologyUpdatesDoNotChangeCursorDisplay) { + SCOPED_FLAG_OVERRIDE(connected_displays_cursor, true); + + // Set first display as primary display and emit mouse event to create PointerController. + mChoreographer.setDisplayViewports({createViewport(FIRST_DISPLAY_ID)}); + setDisplayTopologyWithDisplays(/*primaryDisplayId=*/FIRST_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()); + + // Add another display keeping the primary display unchanged + mChoreographer.setDisplayViewports( + {createViewport(FIRST_DISPLAY_ID), createViewport(SECOND_DISPLAY_ID)}); + setDisplayTopologyWithDisplays(/*primaryDisplayId=*/FIRST_DISPLAY_ID, + /*adjacentDisplays=*/{SECOND_DISPLAY_ID}); + + assertPointerControllerNotCreated(); + pc->assertViewportSet(FIRST_DISPLAY_ID); + ASSERT_TRUE(pc->isPointerShown()); + + // Move cursor to second display and add a third 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()); + + mChoreographer.setDisplayViewports({createViewport(FIRST_DISPLAY_ID), + createViewport(SECOND_DISPLAY_ID), + createViewport(THIRD_DISPLAY_ID)}); + setDisplayTopologyWithDisplays(/*primaryDisplayId=*/FIRST_DISPLAY_ID, /*adjacentDisplays=*/ + {SECOND_DISPLAY_ID, THIRD_DISPLAY_ID}); + + assertPointerControllerNotCreated(); + pc->assertViewportSet(SECOND_DISPLAY_ID); + ASSERT_TRUE(pc->isPointerShown()); + + // Change the primary display to the third display + setDisplayTopologyWithDisplays(/*primaryDisplayId=*/THIRD_DISPLAY_ID, /*adjacentDisplays=*/ + {SECOND_DISPLAY_ID, THIRD_DISPLAY_ID}); + + assertPointerControllerNotCreated(); + pc->assertViewportSet(SECOND_DISPLAY_ID); + ASSERT_TRUE(pc->isPointerShown()); +} + +TEST_F(PointerChoreographerDisplayTopologyDefaultMouseDisplayTests, + PrimaryDisplayIsFallbackOnPointerDisplayRemoved) { + SCOPED_FLAG_OVERRIDE(connected_displays_cursor, true); + + // Add two displays and move cursor to the secondary display + 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, + ui::LogicalDisplayId::INVALID)}}); + auto pc = assertPointerControllerCreated(ControllerType::MOUSE); + pc->assertViewportSet(FIRST_DISPLAY_ID); + ASSERT_TRUE(pc->isPointerShown()); + + 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()); + + // Remove the secondary display + mChoreographer.setDisplayViewports({createViewport(FIRST_DISPLAY_ID)}); + setDisplayTopologyWithDisplays(/*primaryDisplayId=*/FIRST_DISPLAY_ID); + + assertPointerControllerRemoved(pc); + pc = assertPointerControllerCreated(ControllerType::MOUSE); + pc->assertViewportSet(FIRST_DISPLAY_ID); + ASSERT_TRUE(pc->isPointerShown()); +} class PointerChoreographerWindowInfoListenerTest : public testing::Test {}; |