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

Commit 86d68513 authored by Treehugger Robot's avatar Treehugger Robot Committed by Android (Google) Code Review
Browse files

Merge "PointerChoreographer: Support drawing tablets that report mouse events" into main

parents 7547e070 5a31d3c9
Loading
Loading
Loading
Loading
+11 −5
Original line number Diff line number Diff line
@@ -147,6 +147,7 @@ NotifyMotionArgs PointerChoreographer::processMouseEventLocked(const NotifyMotio
                   << args.dump();
    }

    mMouseDevices.emplace(args.deviceId);
    auto [displayId, pc] = ensureMouseControllerLocked(args.displayId);
    NotifyMotionArgs newArgs(args);
    newArgs.displayId = displayId;
@@ -178,6 +179,7 @@ NotifyMotionArgs PointerChoreographer::processMouseEventLocked(const NotifyMotio
}

NotifyMotionArgs PointerChoreographer::processTouchpadEventLocked(const NotifyMotionArgs& args) {
    mMouseDevices.emplace(args.deviceId);
    auto [displayId, pc] = ensureMouseControllerLocked(args.displayId);

    NotifyMotionArgs newArgs(args);
@@ -405,8 +407,10 @@ std::pair<int32_t, PointerControllerInterface&> PointerChoreographer::ensureMous
    const int32_t displayId = getTargetMouseDisplayLocked(associatedDisplayId);

    auto it = mMousePointersByDisplay.find(displayId);
    LOG_ALWAYS_FATAL_IF(it == mMousePointersByDisplay.end(),
                        "There is no mouse controller created for display %d", displayId);
    if (it == mMousePointersByDisplay.end()) {
        it = mMousePointersByDisplay.emplace(displayId, getMouseControllerConstructor(displayId))
                     .first;
    }

    return {displayId, *it->second};
}
@@ -431,7 +435,9 @@ PointerChoreographer::PointerDisplayChange PointerChoreographer::updatePointerCo
    // new PointerControllers if necessary.
    for (const auto& info : mInputDeviceInfos) {
        const uint32_t sources = info.getSources();
        if (isMouseOrTouchpad(sources)) {
        const bool isKnownMouse = mMouseDevices.count(info.getId()) != 0;

        if (isMouseOrTouchpad(sources) || isKnownMouse) {
            const int32_t displayId = getTargetMouseDisplayLocked(info.getAssociatedDisplayId());
            mouseDisplaysToKeep.insert(displayId);
            // For mice, show the cursor immediately when the device is first connected or
@@ -439,8 +445,8 @@ PointerChoreographer::PointerDisplayChange PointerChoreographer::updatePointerCo
            auto [mousePointerIt, isNewMousePointer] =
                    mMousePointersByDisplay.try_emplace(displayId,
                                                        getMouseControllerConstructor(displayId));
            auto [_, isNewMouseDevice] = mMouseDevices.emplace(info.getId());
            if ((isNewMouseDevice || isNewMousePointer) && canUnfadeOnDisplay(displayId)) {
            mMouseDevices.emplace(info.getId());
            if ((!isKnownMouse || isNewMousePointer) && canUnfadeOnDisplay(displayId)) {
                mousePointerIt->second->unfade(PointerControllerInterface::Transition::IMMEDIATE);
            }
        }
+103 −0
Original line number Diff line number Diff line
@@ -1772,4 +1772,107 @@ TEST_P(StylusTestFixture, SetPointerIconVisibilityHidesPointerForStylus) {
    ASSERT_FALSE(pc->isPointerShown());
}

TEST_F(PointerChoreographerTest, DrawingTabletCanReportMouseEvent) {
    mChoreographer.setDisplayViewports(createViewports({DISPLAY_ID}));
    mChoreographer.setDefaultMouseDisplayId(DISPLAY_ID);

    mChoreographer.notifyInputDevicesChanged(
            {/*id=*/0,
             {generateTestDeviceInfo(DEVICE_ID, DRAWING_TABLET_SOURCE, ADISPLAY_ID_NONE)}});
    // There should be no controller created when a drawing tablet is connected
    assertPointerControllerNotCreated();

    // But if it ends up reporting a mouse event, then the mouse controller will be created
    // dynamically.
    mChoreographer.notifyMotion(
            MotionArgsBuilder(AMOTION_EVENT_ACTION_HOVER_ENTER, AINPUT_SOURCE_MOUSE)
                    .pointer(MOUSE_POINTER)
                    .deviceId(DEVICE_ID)
                    .displayId(DISPLAY_ID)
                    .build());
    auto pc = assertPointerControllerCreated(ControllerType::MOUSE);
    ASSERT_TRUE(pc->isPointerShown());

    // The controller is removed when the drawing tablet is removed
    mChoreographer.notifyInputDevicesChanged({/*id=*/0, {}});
    assertPointerControllerRemoved(pc);
}

TEST_F(PointerChoreographerTest, MultipleDrawingTabletsReportMouseEvents) {
    mChoreographer.setDisplayViewports(createViewports({DISPLAY_ID}));
    mChoreographer.setDefaultMouseDisplayId(DISPLAY_ID);

    // First drawing tablet is added
    mChoreographer.notifyInputDevicesChanged(
            {/*id=*/0,
             {generateTestDeviceInfo(DEVICE_ID, DRAWING_TABLET_SOURCE, ADISPLAY_ID_NONE)}});
    assertPointerControllerNotCreated();

    mChoreographer.notifyMotion(
            MotionArgsBuilder(AMOTION_EVENT_ACTION_HOVER_ENTER, AINPUT_SOURCE_MOUSE)
                    .pointer(MOUSE_POINTER)
                    .deviceId(DEVICE_ID)
                    .displayId(DISPLAY_ID)
                    .build());
    auto pc = assertPointerControllerCreated(ControllerType::MOUSE);
    ASSERT_TRUE(pc->isPointerShown());

    // Second drawing tablet is added
    mChoreographer.notifyInputDevicesChanged(
            {/*id=*/0,
             {generateTestDeviceInfo(DEVICE_ID, DRAWING_TABLET_SOURCE, ADISPLAY_ID_NONE),
              generateTestDeviceInfo(SECOND_DEVICE_ID, DRAWING_TABLET_SOURCE, ADISPLAY_ID_NONE)}});
    assertPointerControllerNotRemoved(pc);

    mChoreographer.notifyMotion(
            MotionArgsBuilder(AMOTION_EVENT_ACTION_HOVER_ENTER, AINPUT_SOURCE_MOUSE)
                    .pointer(MOUSE_POINTER)
                    .deviceId(SECOND_DEVICE_ID)
                    .displayId(DISPLAY_ID)
                    .build());

    // First drawing tablet is removed
    mChoreographer.notifyInputDevicesChanged(
            {/*id=*/0,
             {generateTestDeviceInfo(DEVICE_ID, DRAWING_TABLET_SOURCE, ADISPLAY_ID_NONE)}});
    assertPointerControllerNotRemoved(pc);

    // Second drawing tablet is removed
    mChoreographer.notifyInputDevicesChanged({/*id=*/0, {}});
    assertPointerControllerRemoved(pc);
}

TEST_F(PointerChoreographerTest, MouseAndDrawingTabletReportMouseEvents) {
    mChoreographer.setDisplayViewports(createViewports({DISPLAY_ID}));
    mChoreographer.setDefaultMouseDisplayId(DISPLAY_ID);

    // Mouse and drawing tablet connected
    mChoreographer.notifyInputDevicesChanged(
            {/*id=*/0,
             {generateTestDeviceInfo(DEVICE_ID, DRAWING_TABLET_SOURCE, ADISPLAY_ID_NONE),
              generateTestDeviceInfo(SECOND_DEVICE_ID, AINPUT_SOURCE_MOUSE, ADISPLAY_ID_NONE)}});
    auto pc = assertPointerControllerCreated(ControllerType::MOUSE);
    ASSERT_TRUE(pc->isPointerShown());

    // Drawing tablet reports a mouse event
    mChoreographer.notifyMotion(
            MotionArgsBuilder(AMOTION_EVENT_ACTION_HOVER_ENTER, DRAWING_TABLET_SOURCE)
                    .pointer(MOUSE_POINTER)
                    .deviceId(DEVICE_ID)
                    .displayId(DISPLAY_ID)
                    .build());

    // Remove the mouse device
    mChoreographer.notifyInputDevicesChanged(
            {/*id=*/0,
             {generateTestDeviceInfo(DEVICE_ID, DRAWING_TABLET_SOURCE, ADISPLAY_ID_NONE)}});

    // The mouse controller should not be removed, because the drawing tablet has produced a
    // mouse event, so we are treating it as a mouse too.
    assertPointerControllerNotRemoved(pc);

    mChoreographer.notifyInputDevicesChanged({/*id=*/0, {}});
    assertPointerControllerRemoved(pc);
}

} // namespace android