Loading services/inputflinger/PointerChoreographer.cpp +11 −5 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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); Loading Loading @@ -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}; } Loading @@ -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 Loading @@ -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); } } Loading services/inputflinger/tests/PointerChoreographer_test.cpp +103 −0 Original line number Diff line number Diff line Loading @@ -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 Loading
services/inputflinger/PointerChoreographer.cpp +11 −5 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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); Loading Loading @@ -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}; } Loading @@ -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 Loading @@ -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); } } Loading
services/inputflinger/tests/PointerChoreographer_test.cpp +103 −0 Original line number Diff line number Diff line Loading @@ -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