diff options
| -rw-r--r-- | services/inputflinger/PointerChoreographer.cpp | 16 | ||||
| -rw-r--r-- | services/inputflinger/tests/PointerChoreographer_test.cpp | 103 |
2 files changed, 114 insertions, 5 deletions
diff --git a/services/inputflinger/PointerChoreographer.cpp b/services/inputflinger/PointerChoreographer.cpp index 1aa1077d54..10efea538c 100644 --- a/services/inputflinger/PointerChoreographer.cpp +++ b/services/inputflinger/PointerChoreographer.cpp @@ -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); } } diff --git a/services/inputflinger/tests/PointerChoreographer_test.cpp b/services/inputflinger/tests/PointerChoreographer_test.cpp index 3b2565e973..7d1b23cf9f 100644 --- a/services/inputflinger/tests/PointerChoreographer_test.cpp +++ b/services/inputflinger/tests/PointerChoreographer_test.cpp @@ -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 |