Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 96df7be3 authored by nergi's avatar nergi
Browse files

[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
parent 3c769a4d
Loading
Loading
Loading
Loading
+5 −0
Original line number Diff line number Diff line
@@ -25,6 +25,11 @@ public:
     * override.
     */
    static bool connectedDisplaysCursorEnabled();

    /**
     * Check if both connectedDisplaysCursor and associatedDisplayCursorBugfix is enabled.
     */
    static bool connectedDisplaysCursorAndAssociatedDisplayCursorBugfixEnabled();
};

} // namespace android
+5 −0
Original line number Diff line number Diff line
@@ -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
+20 −8
Original line number Diff line number Diff line
@@ -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

+6 −1
Original line number Diff line number Diff line
@@ -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());
+84 −0
Original line number Diff line number Diff line
@@ -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(