diff options
| -rw-r--r-- | services/inputflinger/PointerChoreographer.cpp | 130 | ||||
| -rw-r--r-- | services/inputflinger/PointerChoreographer.h | 3 | ||||
| -rw-r--r-- | services/inputflinger/reader/InputDevice.cpp | 7 | ||||
| -rw-r--r-- | services/inputflinger/tests/PointerChoreographer_test.cpp | 351 |
4 files changed, 310 insertions, 181 deletions
diff --git a/services/inputflinger/PointerChoreographer.cpp b/services/inputflinger/PointerChoreographer.cpp index 9db3574389..36e133b375 100644 --- a/services/inputflinger/PointerChoreographer.cpp +++ b/services/inputflinger/PointerChoreographer.cpp @@ -37,6 +37,11 @@ bool isFromTouchpad(const NotifyMotionArgs& args) { args.pointerProperties[0].toolType == ToolType::FINGER; } +bool isFromDrawingTablet(const NotifyMotionArgs& args) { + return isFromSource(args.source, AINPUT_SOURCE_MOUSE | AINPUT_SOURCE_STYLUS) && + isStylusToolType(args.pointerProperties[0].toolType); +} + bool isHoverAction(int32_t action) { return action == AMOTION_EVENT_ACTION_HOVER_ENTER || action == AMOTION_EVENT_ACTION_HOVER_MOVE || action == AMOTION_EVENT_ACTION_HOVER_EXIT; @@ -46,6 +51,13 @@ bool isStylusHoverEvent(const NotifyMotionArgs& args) { return isStylusEvent(args.source, args.pointerProperties) && isHoverAction(args.action); } +bool isMouseOrTouchpad(uint32_t sources) { + // Check if this is a mouse or touchpad, but not a drawing tablet. + return isFromSource(sources, AINPUT_SOURCE_MOUSE_RELATIVE) || + (isFromSource(sources, AINPUT_SOURCE_MOUSE) && + !isFromSource(sources, AINPUT_SOURCE_STYLUS)); +} + inline void notifyPointerDisplayChange(std::optional<std::tuple<int32_t, FloatPoint>> change, PointerChoreographerPolicyInterface& policy) { if (!change) { @@ -55,6 +67,18 @@ inline void notifyPointerDisplayChange(std::optional<std::tuple<int32_t, FloatPo policy.notifyPointerDisplayIdChanged(displayId, cursorPosition); } +void setIconForController(const std::variant<std::unique_ptr<SpriteIcon>, PointerIconStyle>& icon, + PointerControllerInterface& controller) { + if (std::holds_alternative<std::unique_ptr<SpriteIcon>>(icon)) { + if (std::get<std::unique_ptr<SpriteIcon>>(icon) == nullptr) { + LOG(FATAL) << "SpriteIcon should not be null"; + } + controller.setCustomPointerIcon(*std::get<std::unique_ptr<SpriteIcon>>(icon)); + } else { + controller.updatePointerIcon(std::get<PointerIconStyle>(icon)); + } +} + } // namespace // --- PointerChoreographer --- @@ -107,6 +131,8 @@ NotifyMotionArgs PointerChoreographer::processMotion(const NotifyMotionArgs& arg return processMouseEventLocked(args); } else if (isFromTouchpad(args)) { return processTouchpadEventLocked(args); + } else if (isFromDrawingTablet(args)) { + processDrawingTabletEventLocked(args); } else if (mStylusPointerIconEnabled && isStylusHoverEvent(args)) { processStylusHoverEventLocked(args); } else if (isFromSource(args.source, AINPUT_SOURCE_TOUCHSCREEN)) { @@ -178,6 +204,36 @@ NotifyMotionArgs PointerChoreographer::processTouchpadEventLocked(const NotifyMo return newArgs; } +void PointerChoreographer::processDrawingTabletEventLocked(const android::NotifyMotionArgs& args) { + if (args.displayId == ADISPLAY_ID_NONE) { + return; + } + + if (args.getPointerCount() != 1) { + LOG(WARNING) << "Only drawing tablet events with a single pointer are currently supported: " + << args.dump(); + } + + // Use a mouse pointer controller for drawing tablets, or create one if it doesn't exist. + auto [it, _] = mDrawingTabletPointersByDevice.try_emplace(args.deviceId, + getMouseControllerConstructor( + args.displayId)); + + PointerControllerInterface& pc = *it->second; + + const float x = args.pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_X); + const float y = args.pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_Y); + pc.setPosition(x, y); + if (args.action == AMOTION_EVENT_ACTION_HOVER_EXIT) { + // TODO(b/315815559): Do not fade and reset the icon if the hover exit will be followed + // immediately by a DOWN event. + pc.fade(PointerControllerInterface::Transition::IMMEDIATE); + pc.updatePointerIcon(PointerIconStyle::TYPE_NOT_SPECIFIED); + } else if (canUnfadeOnDisplay(args.displayId)) { + pc.unfade(PointerControllerInterface::Transition::IMMEDIATE); + } +} + /** * When screen is touched, fade the mouse pointer on that display. We only call fade for * ACTION_DOWN events.This would allow both mouse and touch to be used at the same time if the @@ -244,6 +300,8 @@ void PointerChoreographer::processStylusHoverEventLocked(const NotifyMotionArgs& const float y = args.pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_Y); pc.setPosition(x, y); if (args.action == AMOTION_EVENT_ACTION_HOVER_EXIT) { + // TODO(b/315815559): Do not fade and reset the icon if the hover exit will be followed + // immediately by a DOWN event. pc.fade(PointerControllerInterface::Transition::IMMEDIATE); pc.updatePointerIcon(PointerIconStyle::TYPE_NOT_SPECIFIED); } else if (canUnfadeOnDisplay(args.displayId)) { @@ -273,6 +331,7 @@ void PointerChoreographer::processDeviceReset(const NotifyDeviceResetArgs& args) std::scoped_lock _l(mLock); mTouchPointersByDevice.erase(args.deviceId); mStylusPointersByDevice.erase(args.deviceId); + mDrawingTabletPointersByDevice.erase(args.deviceId); } void PointerChoreographer::notifyPointerCaptureChanged( @@ -309,6 +368,11 @@ void PointerChoreographer::dump(std::string& dump) { std::string pointerControllerDump = addLinePrefix(stylusPointerController->dump(), INDENT); dump += INDENT + std::to_string(deviceId) + " : " + pointerControllerDump; } + dump += INDENT "DrawingTabletControllers:\n"; + for (const auto& [deviceId, drawingTabletController] : mDrawingTabletPointersByDevice) { + std::string pointerControllerDump = addLinePrefix(drawingTabletController->dump(), INDENT); + dump += INDENT + std::to_string(deviceId) + " : " + pointerControllerDump; + } dump += "\n"; } @@ -350,13 +414,13 @@ PointerChoreographer::PointerDisplayChange PointerChoreographer::updatePointerCo std::set<int32_t /*displayId*/> mouseDisplaysToKeep; std::set<DeviceId> touchDevicesToKeep; std::set<DeviceId> stylusDevicesToKeep; + std::set<DeviceId> drawingTabletDevicesToKeep; // Mark the displayIds or deviceIds of PointerControllers currently needed, and create // new PointerControllers if necessary. for (const auto& info : mInputDeviceInfos) { const uint32_t sources = info.getSources(); - if (isFromSource(sources, AINPUT_SOURCE_MOUSE) || - isFromSource(sources, AINPUT_SOURCE_MOUSE_RELATIVE)) { + if (isMouseOrTouchpad(sources)) { const int32_t displayId = getTargetMouseDisplayLocked(info.getAssociatedDisplayId()); mouseDisplaysToKeep.insert(displayId); // For mice, show the cursor immediately when the device is first connected or @@ -377,6 +441,10 @@ PointerChoreographer::PointerDisplayChange PointerChoreographer::updatePointerCo info.getAssociatedDisplayId() != ADISPLAY_ID_NONE) { stylusDevicesToKeep.insert(info.getId()); } + if (isFromSource(sources, AINPUT_SOURCE_STYLUS | AINPUT_SOURCE_MOUSE) && + info.getAssociatedDisplayId() != ADISPLAY_ID_NONE) { + drawingTabletDevicesToKeep.insert(info.getId()); + } } // Remove PointerControllers no longer needed. @@ -389,6 +457,9 @@ PointerChoreographer::PointerDisplayChange PointerChoreographer::updatePointerCo std::erase_if(mStylusPointersByDevice, [&stylusDevicesToKeep](const auto& pair) { return stylusDevicesToKeep.find(pair.first) == stylusDevicesToKeep.end(); }); + std::erase_if(mDrawingTabletPointersByDevice, [&drawingTabletDevicesToKeep](const auto& pair) { + return drawingTabletDevicesToKeep.find(pair.first) == drawingTabletDevicesToKeep.end(); + }); std::erase_if(mMouseDevices, [&](DeviceId id) REQUIRES(mLock) { return std::find_if(mInputDeviceInfos.begin(), mInputDeviceInfos.end(), [id](const auto& info) { return info.getId() == id; }) == @@ -449,6 +520,12 @@ void PointerChoreographer::setDisplayViewports(const std::vector<DisplayViewport stylusPointerController->setDisplayViewport(viewport); } } + for (const auto& [deviceId, drawingTabletController] : mDrawingTabletPointersByDevice) { + const InputDeviceInfo* info = findInputDeviceLocked(deviceId); + if (info && info->getAssociatedDisplayId() == displayId) { + drawingTabletController->setDisplayViewport(viewport); + } + } } mViewports = viewports; pointerDisplayChange = calculatePointerDisplayChangeToNotify(); @@ -522,42 +599,35 @@ bool PointerChoreographer::setPointerIcon( return false; } const uint32_t sources = info->getSources(); - const auto stylusPointerIt = mStylusPointersByDevice.find(deviceId); - if (isFromSource(sources, AINPUT_SOURCE_STYLUS) && - stylusPointerIt != mStylusPointersByDevice.end()) { - if (std::holds_alternative<std::unique_ptr<SpriteIcon>>(icon)) { - if (std::get<std::unique_ptr<SpriteIcon>>(icon) == nullptr) { - LOG(FATAL) << "SpriteIcon should not be null"; - } - stylusPointerIt->second->setCustomPointerIcon( - *std::get<std::unique_ptr<SpriteIcon>>(icon)); - } else { - stylusPointerIt->second->updatePointerIcon(std::get<PointerIconStyle>(icon)); + if (isFromSource(sources, AINPUT_SOURCE_STYLUS | AINPUT_SOURCE_MOUSE)) { + auto it = mDrawingTabletPointersByDevice.find(deviceId); + if (it != mDrawingTabletPointersByDevice.end()) { + setIconForController(icon, *it->second); + return true; } - } else if (isFromSource(sources, AINPUT_SOURCE_MOUSE)) { - if (const auto mousePointerIt = mMousePointersByDisplay.find(displayId); - mousePointerIt != mMousePointersByDisplay.end()) { - if (std::holds_alternative<std::unique_ptr<SpriteIcon>>(icon)) { - if (std::get<std::unique_ptr<SpriteIcon>>(icon) == nullptr) { - LOG(FATAL) << "SpriteIcon should not be null"; - } - mousePointerIt->second->setCustomPointerIcon( - *std::get<std::unique_ptr<SpriteIcon>>(icon)); - } else { - mousePointerIt->second->updatePointerIcon(std::get<PointerIconStyle>(icon)); - } + } + if (isFromSource(sources, AINPUT_SOURCE_STYLUS)) { + auto it = mStylusPointersByDevice.find(deviceId); + if (it != mStylusPointersByDevice.end()) { + setIconForController(icon, *it->second); + return true; + } + } + if (isFromSource(sources, AINPUT_SOURCE_MOUSE)) { + auto it = mMousePointersByDisplay.find(displayId); + if (it != mMousePointersByDisplay.end()) { + setIconForController(icon, *it->second); + return true; } else { LOG(WARNING) << "No mouse pointer controller found for display " << displayId << ", device " << deviceId << "."; return false; } - } else { - LOG(WARNING) << "Cannot set pointer icon for display " << displayId << ", device " - << deviceId << "."; - return false; } - return true; + LOG(WARNING) << "Cannot set pointer icon for display " << displayId << ", device " << deviceId + << "."; + return false; } void PointerChoreographer::setPointerIconVisibility(int32_t displayId, bool visible) { diff --git a/services/inputflinger/PointerChoreographer.h b/services/inputflinger/PointerChoreographer.h index db1488b546..a3c210e696 100644 --- a/services/inputflinger/PointerChoreographer.h +++ b/services/inputflinger/PointerChoreographer.h @@ -123,6 +123,7 @@ private: NotifyMotionArgs processMotion(const NotifyMotionArgs& args); NotifyMotionArgs processMouseEventLocked(const NotifyMotionArgs& args) REQUIRES(mLock); NotifyMotionArgs processTouchpadEventLocked(const NotifyMotionArgs& args) REQUIRES(mLock); + void processDrawingTabletEventLocked(const NotifyMotionArgs& args) REQUIRES(mLock); void processTouchscreenAndStylusEventLocked(const NotifyMotionArgs& args) REQUIRES(mLock); void processStylusHoverEventLocked(const NotifyMotionArgs& args) REQUIRES(mLock); void processDeviceReset(const NotifyDeviceResetArgs& args); @@ -144,6 +145,8 @@ private: GUARDED_BY(mLock); std::map<DeviceId, std::shared_ptr<PointerControllerInterface>> mStylusPointersByDevice GUARDED_BY(mLock); + std::map<DeviceId, std::shared_ptr<PointerControllerInterface>> mDrawingTabletPointersByDevice + GUARDED_BY(mLock); int32_t mDefaultMouseDisplayId GUARDED_BY(mLock); int32_t mNotifiedPointerDisplayId GUARDED_BY(mLock); diff --git a/services/inputflinger/reader/InputDevice.cpp b/services/inputflinger/reader/InputDevice.cpp index 2baf576903..4d8ffb68bb 100644 --- a/services/inputflinger/reader/InputDevice.cpp +++ b/services/inputflinger/reader/InputDevice.cpp @@ -509,13 +509,8 @@ std::vector<std::unique_ptr<InputMapper>> InputDevice::createMappers( // Touchscreens and touchpad devices. static const bool ENABLE_TOUCHPAD_GESTURES_LIBRARY = sysprop::InputProperties::enable_touchpad_gestures_library().value_or(true); - // TODO(b/272518665): Fix the new touchpad stack for Sony DualShock 4 (5c4, 9cc) touchpads, or - // at least load this setting from the IDC file. - const InputDeviceIdentifier identifier = contextPtr.getDeviceIdentifier(); - const bool isSonyDualShock4Touchpad = identifier.vendor == 0x054c && - (identifier.product == 0x05c4 || identifier.product == 0x09cc); if (ENABLE_TOUCHPAD_GESTURES_LIBRARY && classes.test(InputDeviceClass::TOUCHPAD) && - classes.test(InputDeviceClass::TOUCH_MT) && !isSonyDualShock4Touchpad) { + classes.test(InputDeviceClass::TOUCH_MT)) { mappers.push_back(createInputMapper<TouchpadInputMapper>(contextPtr, readerConfig)); } else if (classes.test(InputDeviceClass::TOUCH_MT)) { mappers.push_back(createInputMapper<MultiTouchInputMapper>(contextPtr, readerConfig)); diff --git a/services/inputflinger/tests/PointerChoreographer_test.cpp b/services/inputflinger/tests/PointerChoreographer_test.cpp index e9e50619ee..b9c685e1ce 100644 --- a/services/inputflinger/tests/PointerChoreographer_test.cpp +++ b/services/inputflinger/tests/PointerChoreographer_test.cpp @@ -46,6 +46,7 @@ constexpr int32_t DISPLAY_ID = 5; constexpr int32_t ANOTHER_DISPLAY_ID = 10; constexpr int32_t DISPLAY_WIDTH = 480; constexpr int32_t DISPLAY_HEIGHT = 800; +constexpr auto DRAWING_TABLET_SOURCE = AINPUT_SOURCE_MOUSE | AINPUT_SOURCE_STYLUS; const auto MOUSE_POINTER = PointerBuilder(/*id=*/0, ToolType::MOUSE) .axis(AMOTION_EVENT_AXIS_RELATIVE_X, 10) @@ -725,12 +726,28 @@ TEST_F(PointerChoreographerTest, WhenTouchDeviceIsResetClearsSpots) { assertPointerControllerRemoved(pc); } -TEST_F(PointerChoreographerTest, - WhenStylusPointerIconEnabledAndDisabledDoesNotCreatePointerController) { +using StylusFixtureParam = + std::tuple</*name*/ std::string_view, /*source*/ uint32_t, ControllerType>; + +class StylusTestFixture : public PointerChoreographerTest, + public ::testing::WithParamInterface<StylusFixtureParam> {}; + +INSTANTIATE_TEST_SUITE_P(PointerChoreographerTest, StylusTestFixture, + ::testing::Values(std::make_tuple("DirectStylus", AINPUT_SOURCE_STYLUS, + ControllerType::STYLUS), + std::make_tuple("DrawingTablet", DRAWING_TABLET_SOURCE, + ControllerType::MOUSE)), + [](const testing::TestParamInfo<StylusFixtureParam>& p) { + return std::string{std::get<0>(p.param)}; + }); + +TEST_P(StylusTestFixture, WhenStylusPointerIconEnabledAndDisabledDoesNotCreatePointerController) { + const auto& [name, source, controllerType] = GetParam(); + // Disable stylus pointer icon and add a stylus device. mChoreographer.setStylusPointerIconEnabled(false); mChoreographer.notifyInputDevicesChanged( - {/*id=*/0, {generateTestDeviceInfo(DEVICE_ID, AINPUT_SOURCE_STYLUS, DISPLAY_ID)}}); + {/*id=*/0, {generateTestDeviceInfo(DEVICE_ID, source, DISPLAY_ID)}}); assertPointerControllerNotCreated(); // Enable stylus pointer icon. PointerController still should not be created. @@ -738,25 +755,25 @@ TEST_F(PointerChoreographerTest, assertPointerControllerNotCreated(); } -TEST_F(PointerChoreographerTest, WhenStylusHoverEventOccursCreatesPointerController) { +TEST_P(StylusTestFixture, WhenStylusHoverEventOccursCreatesPointerController) { + const auto& [name, source, controllerType] = GetParam(); + // Add a stylus device and enable stylus pointer icon. mChoreographer.notifyInputDevicesChanged( - {/*id=*/0, {generateTestDeviceInfo(DEVICE_ID, AINPUT_SOURCE_STYLUS, DISPLAY_ID)}}); + {/*id=*/0, {generateTestDeviceInfo(DEVICE_ID, source, DISPLAY_ID)}}); mChoreographer.setStylusPointerIconEnabled(true); assertPointerControllerNotCreated(); // Emit hover event. Now PointerController should be created. - mChoreographer.notifyMotion( - MotionArgsBuilder(AMOTION_EVENT_ACTION_HOVER_ENTER, AINPUT_SOURCE_STYLUS) - .pointer(STYLUS_POINTER) - .deviceId(DEVICE_ID) - .displayId(DISPLAY_ID) - .build()); - assertPointerControllerCreated(ControllerType::STYLUS); + mChoreographer.notifyMotion(MotionArgsBuilder(AMOTION_EVENT_ACTION_HOVER_ENTER, source) + .pointer(STYLUS_POINTER) + .deviceId(DEVICE_ID) + .displayId(DISPLAY_ID) + .build()); + assertPointerControllerCreated(controllerType); } -TEST_F(PointerChoreographerTest, - WhenStylusPointerIconDisabledAndHoverEventOccursDoesNotCreatePointerController) { +TEST_F(PointerChoreographerTest, StylusHoverEventWhenStylusPointerIconDisabled) { // Add a stylus device and disable stylus pointer icon. mChoreographer.notifyInputDevicesChanged( {/*id=*/0, {generateTestDeviceInfo(DEVICE_ID, AINPUT_SOURCE_STYLUS, DISPLAY_ID)}}); @@ -773,25 +790,43 @@ TEST_F(PointerChoreographerTest, assertPointerControllerNotCreated(); } -TEST_F(PointerChoreographerTest, WhenStylusDeviceIsRemovedRemovesPointerController) { - // Make sure the PointerController is created. +TEST_F(PointerChoreographerTest, DrawingTabletHoverEventWhenStylusPointerIconDisabled) { + // Add a drawing tablet and disable stylus pointer icon. mChoreographer.notifyInputDevicesChanged( - {/*id=*/0, {generateTestDeviceInfo(DEVICE_ID, AINPUT_SOURCE_STYLUS, DISPLAY_ID)}}); - mChoreographer.setStylusPointerIconEnabled(true); + {/*id=*/0, {generateTestDeviceInfo(DEVICE_ID, DRAWING_TABLET_SOURCE, DISPLAY_ID)}}); + mChoreographer.setStylusPointerIconEnabled(false); + assertPointerControllerNotCreated(); + + // Emit hover event. Drawing tablets are not affected by "stylus pointer icon" setting. mChoreographer.notifyMotion( - MotionArgsBuilder(AMOTION_EVENT_ACTION_HOVER_ENTER, AINPUT_SOURCE_STYLUS) + MotionArgsBuilder(AMOTION_EVENT_ACTION_HOVER_ENTER, DRAWING_TABLET_SOURCE) .pointer(STYLUS_POINTER) .deviceId(DEVICE_ID) .displayId(DISPLAY_ID) .build()); - auto pc = assertPointerControllerCreated(ControllerType::STYLUS); + assertPointerControllerCreated(ControllerType::MOUSE); +} + +TEST_P(StylusTestFixture, WhenStylusDeviceIsRemovedRemovesPointerController) { + const auto& [name, source, controllerType] = GetParam(); + + // Make sure the PointerController is created. + mChoreographer.notifyInputDevicesChanged( + {/*id=*/0, {generateTestDeviceInfo(DEVICE_ID, source, DISPLAY_ID)}}); + mChoreographer.setStylusPointerIconEnabled(true); + mChoreographer.notifyMotion(MotionArgsBuilder(AMOTION_EVENT_ACTION_HOVER_ENTER, source) + .pointer(STYLUS_POINTER) + .deviceId(DEVICE_ID) + .displayId(DISPLAY_ID) + .build()); + auto pc = assertPointerControllerCreated(controllerType); // Remove the device. mChoreographer.notifyInputDevicesChanged({/*id=*/1, {}}); assertPointerControllerRemoved(pc); } -TEST_F(PointerChoreographerTest, WhenStylusPointerIconDisabledRemovesPointerController) { +TEST_F(PointerChoreographerTest, StylusPointerIconDisabledRemovesPointerController) { // Make sure the PointerController is created. mChoreographer.notifyInputDevicesChanged( {/*id=*/0, {generateTestDeviceInfo(DEVICE_ID, AINPUT_SOURCE_STYLUS, DISPLAY_ID)}}); @@ -809,38 +844,59 @@ TEST_F(PointerChoreographerTest, WhenStylusPointerIconDisabledRemovesPointerCont assertPointerControllerRemoved(pc); } -TEST_F(PointerChoreographerTest, SetsViewportForStylusPointerController) { - // Set viewport. - mChoreographer.setDisplayViewports(createViewports({DISPLAY_ID})); - +TEST_F(PointerChoreographerTest, + StylusPointerIconDisabledDoesNotRemoveDrawingTabletPointerController) { // Make sure the PointerController is created. mChoreographer.notifyInputDevicesChanged( - {/*id=*/0, {generateTestDeviceInfo(DEVICE_ID, AINPUT_SOURCE_STYLUS, DISPLAY_ID)}}); + {/*id=*/0, {generateTestDeviceInfo(DEVICE_ID, DRAWING_TABLET_SOURCE, DISPLAY_ID)}}); mChoreographer.setStylusPointerIconEnabled(true); mChoreographer.notifyMotion( - MotionArgsBuilder(AMOTION_EVENT_ACTION_HOVER_ENTER, AINPUT_SOURCE_STYLUS) + MotionArgsBuilder(AMOTION_EVENT_ACTION_HOVER_ENTER, DRAWING_TABLET_SOURCE) .pointer(STYLUS_POINTER) .deviceId(DEVICE_ID) .displayId(DISPLAY_ID) .build()); - auto pc = assertPointerControllerCreated(ControllerType::STYLUS); + auto pc = assertPointerControllerCreated(ControllerType::MOUSE); + + // Disable stylus pointer icon. This should not affect drawing tablets. + mChoreographer.setStylusPointerIconEnabled(false); + assertPointerControllerNotRemoved(pc); +} + +TEST_P(StylusTestFixture, SetsViewportForStylusPointerController) { + const auto& [name, source, controllerType] = GetParam(); + + // Set viewport. + mChoreographer.setDisplayViewports(createViewports({DISPLAY_ID})); + + // Make sure the PointerController is created. + mChoreographer.notifyInputDevicesChanged( + {/*id=*/0, {generateTestDeviceInfo(DEVICE_ID, source, DISPLAY_ID)}}); + mChoreographer.setStylusPointerIconEnabled(true); + mChoreographer.notifyMotion(MotionArgsBuilder(AMOTION_EVENT_ACTION_HOVER_ENTER, source) + .pointer(STYLUS_POINTER) + .deviceId(DEVICE_ID) + .displayId(DISPLAY_ID) + .build()); + auto pc = assertPointerControllerCreated(controllerType); // Check that viewport is set for the PointerController. pc->assertViewportSet(DISPLAY_ID); } -TEST_F(PointerChoreographerTest, WhenViewportIsSetLaterSetsViewportForStylusPointerController) { +TEST_P(StylusTestFixture, WhenViewportIsSetLaterSetsViewportForStylusPointerController) { + const auto& [name, source, controllerType] = GetParam(); + // Make sure the PointerController is created. mChoreographer.notifyInputDevicesChanged( - {/*id=*/0, {generateTestDeviceInfo(DEVICE_ID, AINPUT_SOURCE_STYLUS, DISPLAY_ID)}}); + {/*id=*/0, {generateTestDeviceInfo(DEVICE_ID, source, DISPLAY_ID)}}); mChoreographer.setStylusPointerIconEnabled(true); - mChoreographer.notifyMotion( - MotionArgsBuilder(AMOTION_EVENT_ACTION_HOVER_ENTER, AINPUT_SOURCE_STYLUS) - .pointer(STYLUS_POINTER) - .deviceId(DEVICE_ID) - .displayId(DISPLAY_ID) - .build()); - auto pc = assertPointerControllerCreated(ControllerType::STYLUS); + mChoreographer.notifyMotion(MotionArgsBuilder(AMOTION_EVENT_ACTION_HOVER_ENTER, source) + .pointer(STYLUS_POINTER) + .deviceId(DEVICE_ID) + .displayId(DISPLAY_ID) + .build()); + auto pc = assertPointerControllerCreated(controllerType); // Check that viewport is unset. pc->assertViewportNotSet(); @@ -852,19 +908,19 @@ TEST_F(PointerChoreographerTest, WhenViewportIsSetLaterSetsViewportForStylusPoin pc->assertViewportSet(DISPLAY_ID); } -TEST_F(PointerChoreographerTest, - WhenViewportDoesNotMatchDoesNotSetViewportForStylusPointerController) { +TEST_P(StylusTestFixture, WhenViewportDoesNotMatchDoesNotSetViewportForStylusPointerController) { + const auto& [name, source, controllerType] = GetParam(); + // Make sure the PointerController is created. mChoreographer.notifyInputDevicesChanged( - {/*id=*/0, {generateTestDeviceInfo(DEVICE_ID, AINPUT_SOURCE_STYLUS, DISPLAY_ID)}}); + {/*id=*/0, {generateTestDeviceInfo(DEVICE_ID, source, DISPLAY_ID)}}); mChoreographer.setStylusPointerIconEnabled(true); - mChoreographer.notifyMotion( - MotionArgsBuilder(AMOTION_EVENT_ACTION_HOVER_ENTER, AINPUT_SOURCE_STYLUS) - .pointer(STYLUS_POINTER) - .deviceId(DEVICE_ID) - .displayId(DISPLAY_ID) - .build()); - auto pc = assertPointerControllerCreated(ControllerType::STYLUS); + mChoreographer.notifyMotion(MotionArgsBuilder(AMOTION_EVENT_ACTION_HOVER_ENTER, source) + .pointer(STYLUS_POINTER) + .deviceId(DEVICE_ID) + .displayId(DISPLAY_ID) + .build()); + auto pc = assertPointerControllerCreated(controllerType); // Check that viewport is unset. pc->assertViewportNotSet(); @@ -876,24 +932,25 @@ TEST_F(PointerChoreographerTest, pc->assertViewportNotSet(); } -TEST_F(PointerChoreographerTest, StylusHoverManipulatesPointer) { +TEST_P(StylusTestFixture, StylusHoverManipulatesPointer) { + const auto& [name, source, controllerType] = GetParam(); + mChoreographer.setStylusPointerIconEnabled(true); mChoreographer.notifyInputDevicesChanged( - {/*id=*/0, {generateTestDeviceInfo(DEVICE_ID, AINPUT_SOURCE_STYLUS, DISPLAY_ID)}}); + {/*id=*/0, {generateTestDeviceInfo(DEVICE_ID, source, DISPLAY_ID)}}); mChoreographer.setDisplayViewports(createViewports({DISPLAY_ID})); // Emit hover enter event. This is for creating PointerController. - mChoreographer.notifyMotion( - MotionArgsBuilder(AMOTION_EVENT_ACTION_HOVER_ENTER, AINPUT_SOURCE_STYLUS) - .pointer(STYLUS_POINTER) - .deviceId(DEVICE_ID) - .displayId(DISPLAY_ID) - .build()); - auto pc = assertPointerControllerCreated(ControllerType::STYLUS); + mChoreographer.notifyMotion(MotionArgsBuilder(AMOTION_EVENT_ACTION_HOVER_ENTER, source) + .pointer(STYLUS_POINTER) + .deviceId(DEVICE_ID) + .displayId(DISPLAY_ID) + .build()); + auto pc = assertPointerControllerCreated(controllerType); // Emit hover move event. After bounds are set, PointerController will update the position. mChoreographer.notifyMotion( - MotionArgsBuilder(AMOTION_EVENT_ACTION_HOVER_MOVE, AINPUT_SOURCE_STYLUS) + MotionArgsBuilder(AMOTION_EVENT_ACTION_HOVER_MOVE, source) .pointer(PointerBuilder(/*id=*/0, ToolType::STYLUS).x(150).y(250)) .deviceId(DEVICE_ID) .displayId(DISPLAY_ID) @@ -903,7 +960,7 @@ TEST_F(PointerChoreographerTest, StylusHoverManipulatesPointer) { // Emit hover exit event. mChoreographer.notifyMotion( - MotionArgsBuilder(AMOTION_EVENT_ACTION_HOVER_EXIT, AINPUT_SOURCE_STYLUS) + MotionArgsBuilder(AMOTION_EVENT_ACTION_HOVER_EXIT, source) .pointer(PointerBuilder(/*id=*/0, ToolType::STYLUS).x(150).y(250)) .deviceId(DEVICE_ID) .displayId(DISPLAY_ID) @@ -912,38 +969,38 @@ TEST_F(PointerChoreographerTest, StylusHoverManipulatesPointer) { ASSERT_FALSE(pc->isPointerShown()); } -TEST_F(PointerChoreographerTest, StylusHoverManipulatesPointerForTwoDisplays) { +TEST_P(StylusTestFixture, StylusHoverManipulatesPointerForTwoDisplays) { + const auto& [name, source, controllerType] = GetParam(); + mChoreographer.setStylusPointerIconEnabled(true); // Add two stylus devices associated to different displays. mChoreographer.notifyInputDevicesChanged( {/*id=*/0, - {generateTestDeviceInfo(DEVICE_ID, AINPUT_SOURCE_STYLUS, DISPLAY_ID), - generateTestDeviceInfo(SECOND_DEVICE_ID, AINPUT_SOURCE_STYLUS, ANOTHER_DISPLAY_ID)}}); + {generateTestDeviceInfo(DEVICE_ID, source, DISPLAY_ID), + generateTestDeviceInfo(SECOND_DEVICE_ID, source, ANOTHER_DISPLAY_ID)}}); mChoreographer.setDisplayViewports(createViewports({DISPLAY_ID, ANOTHER_DISPLAY_ID})); // Emit hover event with first device. This is for creating PointerController. - mChoreographer.notifyMotion( - MotionArgsBuilder(AMOTION_EVENT_ACTION_HOVER_ENTER, AINPUT_SOURCE_STYLUS) - .pointer(STYLUS_POINTER) - .deviceId(DEVICE_ID) - .displayId(DISPLAY_ID) - .build()); - auto firstDisplayPc = assertPointerControllerCreated(ControllerType::STYLUS); + mChoreographer.notifyMotion(MotionArgsBuilder(AMOTION_EVENT_ACTION_HOVER_ENTER, source) + .pointer(STYLUS_POINTER) + .deviceId(DEVICE_ID) + .displayId(DISPLAY_ID) + .build()); + auto firstDisplayPc = assertPointerControllerCreated(controllerType); // Emit hover event with second device. This is for creating PointerController. - mChoreographer.notifyMotion( - MotionArgsBuilder(AMOTION_EVENT_ACTION_HOVER_ENTER, AINPUT_SOURCE_STYLUS) - .pointer(STYLUS_POINTER) - .deviceId(SECOND_DEVICE_ID) - .displayId(ANOTHER_DISPLAY_ID) - .build()); + mChoreographer.notifyMotion(MotionArgsBuilder(AMOTION_EVENT_ACTION_HOVER_ENTER, source) + .pointer(STYLUS_POINTER) + .deviceId(SECOND_DEVICE_ID) + .displayId(ANOTHER_DISPLAY_ID) + .build()); // There should be another PointerController created. - auto secondDisplayPc = assertPointerControllerCreated(ControllerType::STYLUS); + auto secondDisplayPc = assertPointerControllerCreated(controllerType); // Emit hover event with first device. mChoreographer.notifyMotion( - MotionArgsBuilder(AMOTION_EVENT_ACTION_HOVER_MOVE, AINPUT_SOURCE_STYLUS) + MotionArgsBuilder(AMOTION_EVENT_ACTION_HOVER_MOVE, source) .pointer(PointerBuilder(/*id=*/0, ToolType::STYLUS).x(150).y(250)) .deviceId(DEVICE_ID) .displayId(DISPLAY_ID) @@ -955,7 +1012,7 @@ TEST_F(PointerChoreographerTest, StylusHoverManipulatesPointerForTwoDisplays) { // Emit hover event with second device. mChoreographer.notifyMotion( - MotionArgsBuilder(AMOTION_EVENT_ACTION_HOVER_MOVE, AINPUT_SOURCE_STYLUS) + MotionArgsBuilder(AMOTION_EVENT_ACTION_HOVER_MOVE, source) .pointer(PointerBuilder(/*id=*/0, ToolType::STYLUS).x(250).y(350)) .deviceId(SECOND_DEVICE_ID) .displayId(ANOTHER_DISPLAY_ID) @@ -970,19 +1027,20 @@ TEST_F(PointerChoreographerTest, StylusHoverManipulatesPointerForTwoDisplays) { ASSERT_TRUE(firstDisplayPc->isPointerShown()); } -TEST_F(PointerChoreographerTest, WhenStylusDeviceIsResetRemovesPointer) { +TEST_P(StylusTestFixture, WhenStylusDeviceIsResetRemovesPointer) { + const auto& [name, source, controllerType] = GetParam(); + // Make sure the PointerController is created and there is a pointer. mChoreographer.notifyInputDevicesChanged( - {/*id=*/0, {generateTestDeviceInfo(DEVICE_ID, AINPUT_SOURCE_STYLUS, DISPLAY_ID)}}); + {/*id=*/0, {generateTestDeviceInfo(DEVICE_ID, source, DISPLAY_ID)}}); mChoreographer.setStylusPointerIconEnabled(true); mChoreographer.setDisplayViewports(createViewports({DISPLAY_ID})); - mChoreographer.notifyMotion( - MotionArgsBuilder(AMOTION_EVENT_ACTION_HOVER_ENTER, AINPUT_SOURCE_STYLUS) - .pointer(STYLUS_POINTER) - .deviceId(DEVICE_ID) - .displayId(DISPLAY_ID) - .build()); - auto pc = assertPointerControllerCreated(ControllerType::STYLUS); + mChoreographer.notifyMotion(MotionArgsBuilder(AMOTION_EVENT_ACTION_HOVER_ENTER, source) + .pointer(STYLUS_POINTER) + .deviceId(DEVICE_ID) + .displayId(DISPLAY_ID) + .build()); + auto pc = assertPointerControllerCreated(controllerType); ASSERT_TRUE(pc->isPointerShown()); // Reset the device and see the pointer controller was removed. @@ -1424,19 +1482,20 @@ TEST_F(PointerChoreographerTest, SetsPointerIconForMouseOnTwoDisplays) { firstMousePc->assertPointerIconNotSet(); } -TEST_F(PointerChoreographerTest, SetsPointerIconForStylus) { +TEST_P(StylusTestFixture, SetsPointerIconForStylus) { + const auto& [name, source, controllerType] = GetParam(); + // Make sure there is a PointerController. mChoreographer.notifyInputDevicesChanged( - {/*id=*/0, {generateTestDeviceInfo(DEVICE_ID, AINPUT_SOURCE_STYLUS, DISPLAY_ID)}}); + {/*id=*/0, {generateTestDeviceInfo(DEVICE_ID, source, DISPLAY_ID)}}); mChoreographer.setStylusPointerIconEnabled(true); mChoreographer.setDisplayViewports(createViewports({DISPLAY_ID})); - mChoreographer.notifyMotion( - MotionArgsBuilder(AMOTION_EVENT_ACTION_HOVER_ENTER, AINPUT_SOURCE_STYLUS) - .pointer(STYLUS_POINTER) - .deviceId(DEVICE_ID) - .displayId(DISPLAY_ID) - .build()); - auto pc = assertPointerControllerCreated(ControllerType::STYLUS); + mChoreographer.notifyMotion(MotionArgsBuilder(AMOTION_EVENT_ACTION_HOVER_ENTER, source) + .pointer(STYLUS_POINTER) + .deviceId(DEVICE_ID) + .displayId(DISPLAY_ID) + .build()); + auto pc = assertPointerControllerCreated(controllerType); pc->assertPointerIconNotSet(); // Set pointer icon for the device. @@ -1449,28 +1508,28 @@ TEST_F(PointerChoreographerTest, SetsPointerIconForStylus) { pc->assertPointerIconNotSet(); // The stylus stops hovering. This should cause the icon to be reset. - mChoreographer.notifyMotion( - MotionArgsBuilder(AMOTION_EVENT_ACTION_HOVER_EXIT, AINPUT_SOURCE_STYLUS) - .pointer(STYLUS_POINTER) - .deviceId(DEVICE_ID) - .displayId(DISPLAY_ID) - .build()); + mChoreographer.notifyMotion(MotionArgsBuilder(AMOTION_EVENT_ACTION_HOVER_EXIT, source) + .pointer(STYLUS_POINTER) + .deviceId(DEVICE_ID) + .displayId(DISPLAY_ID) + .build()); pc->assertPointerIconSet(PointerIconStyle::TYPE_NOT_SPECIFIED); } -TEST_F(PointerChoreographerTest, SetsCustomPointerIconForStylus) { +TEST_P(StylusTestFixture, SetsCustomPointerIconForStylus) { + const auto& [name, source, controllerType] = GetParam(); + // Make sure there is a PointerController. mChoreographer.notifyInputDevicesChanged( - {/*id=*/0, {generateTestDeviceInfo(DEVICE_ID, AINPUT_SOURCE_STYLUS, DISPLAY_ID)}}); + {/*id=*/0, {generateTestDeviceInfo(DEVICE_ID, source, DISPLAY_ID)}}); mChoreographer.setStylusPointerIconEnabled(true); mChoreographer.setDisplayViewports(createViewports({DISPLAY_ID})); - mChoreographer.notifyMotion( - MotionArgsBuilder(AMOTION_EVENT_ACTION_HOVER_ENTER, AINPUT_SOURCE_STYLUS) - .pointer(STYLUS_POINTER) - .deviceId(DEVICE_ID) - .displayId(DISPLAY_ID) - .build()); - auto pc = assertPointerControllerCreated(ControllerType::STYLUS); + mChoreographer.notifyMotion(MotionArgsBuilder(AMOTION_EVENT_ACTION_HOVER_ENTER, source) + .pointer(STYLUS_POINTER) + .deviceId(DEVICE_ID) + .displayId(DISPLAY_ID) + .build()); + auto pc = assertPointerControllerCreated(controllerType); pc->assertCustomPointerIconNotSet(); // Set custom pointer icon for the device. @@ -1486,28 +1545,28 @@ TEST_F(PointerChoreographerTest, SetsCustomPointerIconForStylus) { pc->assertCustomPointerIconNotSet(); } -TEST_F(PointerChoreographerTest, SetsPointerIconForTwoStyluses) { +TEST_P(StylusTestFixture, SetsPointerIconForTwoStyluses) { + const auto& [name, source, controllerType] = GetParam(); + // Make sure there are two StylusPointerControllers. They can be on a same display. mChoreographer.setStylusPointerIconEnabled(true); mChoreographer.notifyInputDevicesChanged( {/*id=*/0, - {generateTestDeviceInfo(DEVICE_ID, AINPUT_SOURCE_STYLUS, DISPLAY_ID), - generateTestDeviceInfo(SECOND_DEVICE_ID, AINPUT_SOURCE_STYLUS, DISPLAY_ID)}}); + {generateTestDeviceInfo(DEVICE_ID, source, DISPLAY_ID), + generateTestDeviceInfo(SECOND_DEVICE_ID, source, DISPLAY_ID)}}); mChoreographer.setDisplayViewports(createViewports({DISPLAY_ID})); - mChoreographer.notifyMotion( - MotionArgsBuilder(AMOTION_EVENT_ACTION_HOVER_ENTER, AINPUT_SOURCE_STYLUS) - .pointer(STYLUS_POINTER) - .deviceId(DEVICE_ID) - .displayId(DISPLAY_ID) - .build()); - auto firstStylusPc = assertPointerControllerCreated(ControllerType::STYLUS); - mChoreographer.notifyMotion( - MotionArgsBuilder(AMOTION_EVENT_ACTION_HOVER_ENTER, AINPUT_SOURCE_STYLUS) - .pointer(STYLUS_POINTER) - .deviceId(SECOND_DEVICE_ID) - .displayId(DISPLAY_ID) - .build()); - auto secondStylusPc = assertPointerControllerCreated(ControllerType::STYLUS); + mChoreographer.notifyMotion(MotionArgsBuilder(AMOTION_EVENT_ACTION_HOVER_ENTER, source) + .pointer(STYLUS_POINTER) + .deviceId(DEVICE_ID) + .displayId(DISPLAY_ID) + .build()); + auto firstStylusPc = assertPointerControllerCreated(controllerType); + mChoreographer.notifyMotion(MotionArgsBuilder(AMOTION_EVENT_ACTION_HOVER_ENTER, source) + .pointer(STYLUS_POINTER) + .deviceId(SECOND_DEVICE_ID) + .displayId(DISPLAY_ID) + .build()); + auto secondStylusPc = assertPointerControllerCreated(controllerType); // Set pointer icon for one stylus. ASSERT_TRUE(mChoreographer.setPointerIcon(PointerIconStyle::TYPE_TEXT, DISPLAY_ID, DEVICE_ID)); @@ -1521,14 +1580,16 @@ TEST_F(PointerChoreographerTest, SetsPointerIconForTwoStyluses) { firstStylusPc->assertPointerIconNotSet(); } -TEST_F(PointerChoreographerTest, SetsPointerIconForMouseAndStylus) { +TEST_P(StylusTestFixture, SetsPointerIconForMouseAndStylus) { + const auto& [name, source, controllerType] = GetParam(); + // Make sure there are PointerControllers for a mouse and a stylus. mChoreographer.setStylusPointerIconEnabled(true); mChoreographer.setDefaultMouseDisplayId(DISPLAY_ID); mChoreographer.notifyInputDevicesChanged( {/*id=*/0, {generateTestDeviceInfo(DEVICE_ID, AINPUT_SOURCE_MOUSE, ADISPLAY_ID_NONE), - generateTestDeviceInfo(SECOND_DEVICE_ID, AINPUT_SOURCE_STYLUS, DISPLAY_ID)}}); + generateTestDeviceInfo(SECOND_DEVICE_ID, source, DISPLAY_ID)}}); mChoreographer.setDisplayViewports(createViewports({DISPLAY_ID})); mChoreographer.notifyMotion( MotionArgsBuilder(AMOTION_EVENT_ACTION_HOVER_MOVE, AINPUT_SOURCE_MOUSE) @@ -1537,13 +1598,12 @@ TEST_F(PointerChoreographerTest, SetsPointerIconForMouseAndStylus) { .displayId(ADISPLAY_ID_NONE) .build()); auto mousePc = assertPointerControllerCreated(ControllerType::MOUSE); - mChoreographer.notifyMotion( - MotionArgsBuilder(AMOTION_EVENT_ACTION_HOVER_ENTER, AINPUT_SOURCE_STYLUS) - .pointer(STYLUS_POINTER) - .deviceId(SECOND_DEVICE_ID) - .displayId(DISPLAY_ID) - .build()); - auto stylusPc = assertPointerControllerCreated(ControllerType::STYLUS); + mChoreographer.notifyMotion(MotionArgsBuilder(AMOTION_EVENT_ACTION_HOVER_ENTER, source) + .pointer(STYLUS_POINTER) + .deviceId(SECOND_DEVICE_ID) + .displayId(DISPLAY_ID) + .build()); + auto stylusPc = assertPointerControllerCreated(controllerType); // Set pointer icon for the mouse. ASSERT_TRUE(mChoreographer.setPointerIcon(PointerIconStyle::TYPE_TEXT, DISPLAY_ID, DEVICE_ID)); @@ -1652,7 +1712,9 @@ TEST_F(PointerChoreographerTest, SetPointerIconVisibilityHidesPointerForTouchpad ASSERT_FALSE(touchpadPc->isPointerShown()); } -TEST_F(PointerChoreographerTest, SetPointerIconVisibilityHidesPointerForStylus) { +TEST_P(StylusTestFixture, SetPointerIconVisibilityHidesPointerForStylus) { + const auto& [name, source, controllerType] = GetParam(); + mChoreographer.setDisplayViewports(createViewports({DISPLAY_ID})); mChoreographer.setStylusPointerIconEnabled(true); @@ -1660,15 +1722,14 @@ TEST_F(PointerChoreographerTest, SetPointerIconVisibilityHidesPointerForStylus) mChoreographer.setPointerIconVisibility(DISPLAY_ID, false); mChoreographer.notifyInputDevicesChanged( - {/*id=*/0, {generateTestDeviceInfo(DEVICE_ID, AINPUT_SOURCE_STYLUS, DISPLAY_ID)}}); - mChoreographer.notifyMotion( - MotionArgsBuilder(AMOTION_EVENT_ACTION_HOVER_ENTER, AINPUT_SOURCE_STYLUS) - .pointer(STYLUS_POINTER) - .deviceId(DEVICE_ID) - .displayId(DISPLAY_ID) - .build()); + {/*id=*/0, {generateTestDeviceInfo(DEVICE_ID, source, DISPLAY_ID)}}); + mChoreographer.notifyMotion(MotionArgsBuilder(AMOTION_EVENT_ACTION_HOVER_ENTER, source) + .pointer(STYLUS_POINTER) + .deviceId(DEVICE_ID) + .displayId(DISPLAY_ID) + .build()); ASSERT_TRUE(mChoreographer.setPointerIcon(PointerIconStyle::TYPE_TEXT, DISPLAY_ID, DEVICE_ID)); - auto pc = assertPointerControllerCreated(ControllerType::STYLUS); + auto pc = assertPointerControllerCreated(controllerType); pc->assertPointerIconSet(PointerIconStyle::TYPE_TEXT); // The pointer should not be visible. |