Loading services/inputflinger/PointerChoreographer.cpp +37 −5 Original line number Diff line number Diff line Loading @@ -109,7 +109,9 @@ NotifyMotionArgs PointerChoreographer::processMouseEventLocked(const NotifyMotio const float deltaX = args.pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_RELATIVE_X); const float deltaY = args.pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_RELATIVE_Y); pc.move(deltaX, deltaY); if (canUnfadeOnDisplay(displayId)) { pc.unfade(PointerControllerInterface::Transition::IMMEDIATE); } const auto [x, y] = pc.getPosition(); NotifyMotionArgs newArgs(args); Loading @@ -131,7 +133,9 @@ NotifyMotionArgs PointerChoreographer::processTouchpadEventLocked(const NotifyMo const float deltaX = args.pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_RELATIVE_X); const float deltaY = args.pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_RELATIVE_Y); pc.move(deltaX, deltaY); if (canUnfadeOnDisplay(displayId)) { pc.unfade(PointerControllerInterface::Transition::IMMEDIATE); } const auto [x, y] = pc.getPosition(); newArgs.pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_X, x); Loading @@ -140,7 +144,9 @@ NotifyMotionArgs PointerChoreographer::processTouchpadEventLocked(const NotifyMo newArgs.yCursorPosition = y; } else { // This is a trackpad gesture with fake finger(s) that should not move the mouse pointer. if (canUnfadeOnDisplay(displayId)) { pc.unfade(PointerControllerInterface::Transition::IMMEDIATE); } const auto [x, y] = pc.getPosition(); for (uint32_t i = 0; i < newArgs.getPointerCount(); i++) { Loading Loading @@ -223,7 +229,7 @@ void PointerChoreographer::processStylusHoverEventLocked(const NotifyMotionArgs& if (args.action == AMOTION_EVENT_ACTION_HOVER_EXIT) { pc.fade(PointerControllerInterface::Transition::IMMEDIATE); pc.updatePointerIcon(PointerIconStyle::TYPE_NOT_SPECIFIED); } else { } else if (canUnfadeOnDisplay(args.displayId)) { pc.unfade(PointerControllerInterface::Transition::IMMEDIATE); } } Loading Loading @@ -323,6 +329,10 @@ InputDeviceInfo* PointerChoreographer::findInputDeviceLocked(DeviceId deviceId) return it != mInputDeviceInfos.end() ? &(*it) : nullptr; } bool PointerChoreographer::canUnfadeOnDisplay(int32_t displayId) { return mDisplaysWithPointersHidden.find(displayId) == mDisplaysWithPointersHidden.end(); } void PointerChoreographer::updatePointerControllersLocked() { std::set<int32_t /*displayId*/> mouseDisplaysToKeep; std::set<DeviceId> touchDevicesToKeep; Loading @@ -342,7 +352,7 @@ void PointerChoreographer::updatePointerControllersLocked() { mMousePointersByDisplay.try_emplace(displayId, getMouseControllerConstructor(displayId)); auto [_, isNewMouseDevice] = mMouseDevices.emplace(info.getId()); if (isNewMouseDevice || isNewMousePointer) { if ((isNewMouseDevice || isNewMousePointer) && canUnfadeOnDisplay(displayId)) { mousePointerIt->second->unfade(PointerControllerInterface::Transition::IMMEDIATE); } } Loading Loading @@ -513,6 +523,28 @@ bool PointerChoreographer::setPointerIcon( return true; } void PointerChoreographer::setPointerIconVisibility(int32_t displayId, bool visible) { std::scoped_lock lock(mLock); if (visible) { mDisplaysWithPointersHidden.erase(displayId); // We do not unfade the icons here, because we don't know when the last event happened. return; } mDisplaysWithPointersHidden.emplace(displayId); // Hide any icons that are currently visible on the display. if (auto it = mMousePointersByDisplay.find(displayId); it != mMousePointersByDisplay.end()) { const auto& [_, controller] = *it; controller->fade(PointerControllerInterface::Transition::IMMEDIATE); } for (const auto& [_, controller] : mStylusPointersByDevice) { if (controller->getDisplayId() == displayId) { controller->fade(PointerControllerInterface::Transition::IMMEDIATE); } } } PointerChoreographer::ControllerConstructor PointerChoreographer::getMouseControllerConstructor( int32_t displayId) { std::function<std::shared_ptr<PointerControllerInterface>()> ctor = Loading services/inputflinger/PointerChoreographer.h +8 −0 Original line number Diff line number Diff line Loading @@ -67,6 +67,11 @@ public: */ virtual bool setPointerIcon(std::variant<std::unique_ptr<SpriteIcon>, PointerIconStyle> icon, int32_t displayId, DeviceId deviceId) = 0; /** * Set whether pointer icons for mice, touchpads, and styluses should be visible on the * given display. */ virtual void setPointerIconVisibility(int32_t displayId, bool visible) = 0; /** * This method may be called on any thread (usually by the input manager on a binder thread). Loading @@ -89,6 +94,7 @@ public: void setStylusPointerIconEnabled(bool enabled) override; bool setPointerIcon(std::variant<std::unique_ptr<SpriteIcon>, PointerIconStyle> icon, int32_t displayId, DeviceId deviceId) override; void setPointerIconVisibility(int32_t displayId, bool visible) override; void notifyInputDevicesChanged(const NotifyInputDevicesChangedArgs& args) override; void notifyConfigurationChanged(const NotifyConfigurationChangedArgs& args) override; Loading @@ -110,6 +116,7 @@ private: std::pair<int32_t, PointerControllerInterface&> getDisplayIdAndMouseControllerLocked( int32_t associatedDisplayId) REQUIRES(mLock); InputDeviceInfo* findInputDeviceLocked(DeviceId deviceId) REQUIRES(mLock); bool canUnfadeOnDisplay(int32_t displayId) REQUIRES(mLock); NotifyMotionArgs processMotion(const NotifyMotionArgs& args); NotifyMotionArgs processMouseEventLocked(const NotifyMotionArgs& args) REQUIRES(mLock); Loading Loading @@ -143,6 +150,7 @@ private: std::vector<DisplayViewport> mViewports GUARDED_BY(mLock); bool mShowTouchesEnabled GUARDED_BY(mLock); bool mStylusPointerIconEnabled GUARDED_BY(mLock); std::set<int32_t /*displayId*/> mDisplaysWithPointersHidden; }; } // namespace android services/inputflinger/tests/PointerChoreographer_test.cpp +118 −0 Original line number Diff line number Diff line Loading @@ -1557,4 +1557,122 @@ TEST_F(PointerChoreographerTest, SetsPointerIconForMouseAndStylus) { mousePc->assertPointerIconNotSet(); } TEST_F(PointerChoreographerTest, SetPointerIconVisibilityHidesPointerOnDisplay) { // Make sure there are two PointerControllers on different displays. mChoreographer.setDisplayViewports(createViewports({DISPLAY_ID, ANOTHER_DISPLAY_ID})); mChoreographer.setDefaultMouseDisplayId(DISPLAY_ID); mChoreographer.notifyInputDevicesChanged( {/*id=*/0, {generateTestDeviceInfo(DEVICE_ID, AINPUT_SOURCE_MOUSE, ADISPLAY_ID_NONE), generateTestDeviceInfo(SECOND_DEVICE_ID, AINPUT_SOURCE_MOUSE, ANOTHER_DISPLAY_ID)}}); auto firstMousePc = assertPointerControllerCreated(ControllerType::MOUSE); ASSERT_EQ(DISPLAY_ID, firstMousePc->getDisplayId()); auto secondMousePc = assertPointerControllerCreated(ControllerType::MOUSE); ASSERT_EQ(ANOTHER_DISPLAY_ID, secondMousePc->getDisplayId()); // Both pointers should be visible. ASSERT_TRUE(firstMousePc->isPointerShown()); ASSERT_TRUE(secondMousePc->isPointerShown()); // Hide the icon on the second display. mChoreographer.setPointerIconVisibility(ANOTHER_DISPLAY_ID, false); ASSERT_TRUE(firstMousePc->isPointerShown()); ASSERT_FALSE(secondMousePc->isPointerShown()); // Move and set pointer icons for both mice. The second pointer should still be hidden. mChoreographer.notifyMotion( MotionArgsBuilder(AMOTION_EVENT_ACTION_HOVER_ENTER, AINPUT_SOURCE_MOUSE) .pointer(MOUSE_POINTER) .deviceId(DEVICE_ID) .displayId(DISPLAY_ID) .build()); mChoreographer.notifyMotion( MotionArgsBuilder(AMOTION_EVENT_ACTION_HOVER_ENTER, AINPUT_SOURCE_MOUSE) .pointer(MOUSE_POINTER) .deviceId(SECOND_DEVICE_ID) .displayId(ANOTHER_DISPLAY_ID) .build()); ASSERT_TRUE(mChoreographer.setPointerIcon(PointerIconStyle::TYPE_TEXT, DISPLAY_ID, DEVICE_ID)); ASSERT_TRUE(mChoreographer.setPointerIcon(PointerIconStyle::TYPE_TEXT, ANOTHER_DISPLAY_ID, SECOND_DEVICE_ID)); firstMousePc->assertPointerIconSet(PointerIconStyle::TYPE_TEXT); secondMousePc->assertPointerIconSet(PointerIconStyle::TYPE_TEXT); ASSERT_TRUE(firstMousePc->isPointerShown()); ASSERT_FALSE(secondMousePc->isPointerShown()); // Allow the icon to be visible on the second display, and move the mouse. mChoreographer.setPointerIconVisibility(ANOTHER_DISPLAY_ID, true); mChoreographer.notifyMotion( MotionArgsBuilder(AMOTION_EVENT_ACTION_HOVER_ENTER, AINPUT_SOURCE_MOUSE) .pointer(MOUSE_POINTER) .deviceId(SECOND_DEVICE_ID) .displayId(ANOTHER_DISPLAY_ID) .build()); ASSERT_TRUE(firstMousePc->isPointerShown()); ASSERT_TRUE(secondMousePc->isPointerShown()); } TEST_F(PointerChoreographerTest, SetPointerIconVisibilityHidesPointerWhenDeviceConnected) { mChoreographer.setDisplayViewports(createViewports({DISPLAY_ID})); mChoreographer.setDefaultMouseDisplayId(DISPLAY_ID); // Hide the pointer on the display, and then connect the mouse. mChoreographer.setPointerIconVisibility(DISPLAY_ID, false); mChoreographer.notifyInputDevicesChanged( {/*id=*/0, {generateTestDeviceInfo(DEVICE_ID, AINPUT_SOURCE_MOUSE, ADISPLAY_ID_NONE)}}); auto mousePc = assertPointerControllerCreated(ControllerType::MOUSE); ASSERT_EQ(DISPLAY_ID, mousePc->getDisplayId()); // The pointer should not be visible. ASSERT_FALSE(mousePc->isPointerShown()); } TEST_F(PointerChoreographerTest, SetPointerIconVisibilityHidesPointerForTouchpad) { mChoreographer.setDisplayViewports(createViewports({DISPLAY_ID})); mChoreographer.setDefaultMouseDisplayId(DISPLAY_ID); // Hide the pointer on the display. mChoreographer.setPointerIconVisibility(DISPLAY_ID, false); mChoreographer.notifyInputDevicesChanged( {/*id=*/0, {generateTestDeviceInfo(DEVICE_ID, AINPUT_SOURCE_MOUSE | AINPUT_SOURCE_TOUCHPAD, ADISPLAY_ID_NONE)}}); auto touchpadPc = assertPointerControllerCreated(ControllerType::MOUSE); ASSERT_EQ(DISPLAY_ID, touchpadPc->getDisplayId()); mChoreographer.notifyMotion(MotionArgsBuilder(AMOTION_EVENT_ACTION_HOVER_ENTER, AINPUT_SOURCE_MOUSE | AINPUT_SOURCE_TOUCHPAD) .pointer(TOUCHPAD_POINTER) .deviceId(DEVICE_ID) .displayId(DISPLAY_ID) .build()); // The pointer should not be visible. ASSERT_FALSE(touchpadPc->isPointerShown()); } TEST_F(PointerChoreographerTest, SetPointerIconVisibilityHidesPointerForStylus) { mChoreographer.setDisplayViewports(createViewports({DISPLAY_ID})); mChoreographer.setStylusPointerIconEnabled(true); // Hide the pointer on the display. 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()); ASSERT_TRUE(mChoreographer.setPointerIcon(PointerIconStyle::TYPE_TEXT, DISPLAY_ID, DEVICE_ID)); auto pc = assertPointerControllerCreated(ControllerType::STYLUS); pc->assertPointerIconSet(PointerIconStyle::TYPE_TEXT); // The pointer should not be visible. ASSERT_FALSE(pc->isPointerShown()); } } // namespace android Loading
services/inputflinger/PointerChoreographer.cpp +37 −5 Original line number Diff line number Diff line Loading @@ -109,7 +109,9 @@ NotifyMotionArgs PointerChoreographer::processMouseEventLocked(const NotifyMotio const float deltaX = args.pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_RELATIVE_X); const float deltaY = args.pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_RELATIVE_Y); pc.move(deltaX, deltaY); if (canUnfadeOnDisplay(displayId)) { pc.unfade(PointerControllerInterface::Transition::IMMEDIATE); } const auto [x, y] = pc.getPosition(); NotifyMotionArgs newArgs(args); Loading @@ -131,7 +133,9 @@ NotifyMotionArgs PointerChoreographer::processTouchpadEventLocked(const NotifyMo const float deltaX = args.pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_RELATIVE_X); const float deltaY = args.pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_RELATIVE_Y); pc.move(deltaX, deltaY); if (canUnfadeOnDisplay(displayId)) { pc.unfade(PointerControllerInterface::Transition::IMMEDIATE); } const auto [x, y] = pc.getPosition(); newArgs.pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_X, x); Loading @@ -140,7 +144,9 @@ NotifyMotionArgs PointerChoreographer::processTouchpadEventLocked(const NotifyMo newArgs.yCursorPosition = y; } else { // This is a trackpad gesture with fake finger(s) that should not move the mouse pointer. if (canUnfadeOnDisplay(displayId)) { pc.unfade(PointerControllerInterface::Transition::IMMEDIATE); } const auto [x, y] = pc.getPosition(); for (uint32_t i = 0; i < newArgs.getPointerCount(); i++) { Loading Loading @@ -223,7 +229,7 @@ void PointerChoreographer::processStylusHoverEventLocked(const NotifyMotionArgs& if (args.action == AMOTION_EVENT_ACTION_HOVER_EXIT) { pc.fade(PointerControllerInterface::Transition::IMMEDIATE); pc.updatePointerIcon(PointerIconStyle::TYPE_NOT_SPECIFIED); } else { } else if (canUnfadeOnDisplay(args.displayId)) { pc.unfade(PointerControllerInterface::Transition::IMMEDIATE); } } Loading Loading @@ -323,6 +329,10 @@ InputDeviceInfo* PointerChoreographer::findInputDeviceLocked(DeviceId deviceId) return it != mInputDeviceInfos.end() ? &(*it) : nullptr; } bool PointerChoreographer::canUnfadeOnDisplay(int32_t displayId) { return mDisplaysWithPointersHidden.find(displayId) == mDisplaysWithPointersHidden.end(); } void PointerChoreographer::updatePointerControllersLocked() { std::set<int32_t /*displayId*/> mouseDisplaysToKeep; std::set<DeviceId> touchDevicesToKeep; Loading @@ -342,7 +352,7 @@ void PointerChoreographer::updatePointerControllersLocked() { mMousePointersByDisplay.try_emplace(displayId, getMouseControllerConstructor(displayId)); auto [_, isNewMouseDevice] = mMouseDevices.emplace(info.getId()); if (isNewMouseDevice || isNewMousePointer) { if ((isNewMouseDevice || isNewMousePointer) && canUnfadeOnDisplay(displayId)) { mousePointerIt->second->unfade(PointerControllerInterface::Transition::IMMEDIATE); } } Loading Loading @@ -513,6 +523,28 @@ bool PointerChoreographer::setPointerIcon( return true; } void PointerChoreographer::setPointerIconVisibility(int32_t displayId, bool visible) { std::scoped_lock lock(mLock); if (visible) { mDisplaysWithPointersHidden.erase(displayId); // We do not unfade the icons here, because we don't know when the last event happened. return; } mDisplaysWithPointersHidden.emplace(displayId); // Hide any icons that are currently visible on the display. if (auto it = mMousePointersByDisplay.find(displayId); it != mMousePointersByDisplay.end()) { const auto& [_, controller] = *it; controller->fade(PointerControllerInterface::Transition::IMMEDIATE); } for (const auto& [_, controller] : mStylusPointersByDevice) { if (controller->getDisplayId() == displayId) { controller->fade(PointerControllerInterface::Transition::IMMEDIATE); } } } PointerChoreographer::ControllerConstructor PointerChoreographer::getMouseControllerConstructor( int32_t displayId) { std::function<std::shared_ptr<PointerControllerInterface>()> ctor = Loading
services/inputflinger/PointerChoreographer.h +8 −0 Original line number Diff line number Diff line Loading @@ -67,6 +67,11 @@ public: */ virtual bool setPointerIcon(std::variant<std::unique_ptr<SpriteIcon>, PointerIconStyle> icon, int32_t displayId, DeviceId deviceId) = 0; /** * Set whether pointer icons for mice, touchpads, and styluses should be visible on the * given display. */ virtual void setPointerIconVisibility(int32_t displayId, bool visible) = 0; /** * This method may be called on any thread (usually by the input manager on a binder thread). Loading @@ -89,6 +94,7 @@ public: void setStylusPointerIconEnabled(bool enabled) override; bool setPointerIcon(std::variant<std::unique_ptr<SpriteIcon>, PointerIconStyle> icon, int32_t displayId, DeviceId deviceId) override; void setPointerIconVisibility(int32_t displayId, bool visible) override; void notifyInputDevicesChanged(const NotifyInputDevicesChangedArgs& args) override; void notifyConfigurationChanged(const NotifyConfigurationChangedArgs& args) override; Loading @@ -110,6 +116,7 @@ private: std::pair<int32_t, PointerControllerInterface&> getDisplayIdAndMouseControllerLocked( int32_t associatedDisplayId) REQUIRES(mLock); InputDeviceInfo* findInputDeviceLocked(DeviceId deviceId) REQUIRES(mLock); bool canUnfadeOnDisplay(int32_t displayId) REQUIRES(mLock); NotifyMotionArgs processMotion(const NotifyMotionArgs& args); NotifyMotionArgs processMouseEventLocked(const NotifyMotionArgs& args) REQUIRES(mLock); Loading Loading @@ -143,6 +150,7 @@ private: std::vector<DisplayViewport> mViewports GUARDED_BY(mLock); bool mShowTouchesEnabled GUARDED_BY(mLock); bool mStylusPointerIconEnabled GUARDED_BY(mLock); std::set<int32_t /*displayId*/> mDisplaysWithPointersHidden; }; } // namespace android
services/inputflinger/tests/PointerChoreographer_test.cpp +118 −0 Original line number Diff line number Diff line Loading @@ -1557,4 +1557,122 @@ TEST_F(PointerChoreographerTest, SetsPointerIconForMouseAndStylus) { mousePc->assertPointerIconNotSet(); } TEST_F(PointerChoreographerTest, SetPointerIconVisibilityHidesPointerOnDisplay) { // Make sure there are two PointerControllers on different displays. mChoreographer.setDisplayViewports(createViewports({DISPLAY_ID, ANOTHER_DISPLAY_ID})); mChoreographer.setDefaultMouseDisplayId(DISPLAY_ID); mChoreographer.notifyInputDevicesChanged( {/*id=*/0, {generateTestDeviceInfo(DEVICE_ID, AINPUT_SOURCE_MOUSE, ADISPLAY_ID_NONE), generateTestDeviceInfo(SECOND_DEVICE_ID, AINPUT_SOURCE_MOUSE, ANOTHER_DISPLAY_ID)}}); auto firstMousePc = assertPointerControllerCreated(ControllerType::MOUSE); ASSERT_EQ(DISPLAY_ID, firstMousePc->getDisplayId()); auto secondMousePc = assertPointerControllerCreated(ControllerType::MOUSE); ASSERT_EQ(ANOTHER_DISPLAY_ID, secondMousePc->getDisplayId()); // Both pointers should be visible. ASSERT_TRUE(firstMousePc->isPointerShown()); ASSERT_TRUE(secondMousePc->isPointerShown()); // Hide the icon on the second display. mChoreographer.setPointerIconVisibility(ANOTHER_DISPLAY_ID, false); ASSERT_TRUE(firstMousePc->isPointerShown()); ASSERT_FALSE(secondMousePc->isPointerShown()); // Move and set pointer icons for both mice. The second pointer should still be hidden. mChoreographer.notifyMotion( MotionArgsBuilder(AMOTION_EVENT_ACTION_HOVER_ENTER, AINPUT_SOURCE_MOUSE) .pointer(MOUSE_POINTER) .deviceId(DEVICE_ID) .displayId(DISPLAY_ID) .build()); mChoreographer.notifyMotion( MotionArgsBuilder(AMOTION_EVENT_ACTION_HOVER_ENTER, AINPUT_SOURCE_MOUSE) .pointer(MOUSE_POINTER) .deviceId(SECOND_DEVICE_ID) .displayId(ANOTHER_DISPLAY_ID) .build()); ASSERT_TRUE(mChoreographer.setPointerIcon(PointerIconStyle::TYPE_TEXT, DISPLAY_ID, DEVICE_ID)); ASSERT_TRUE(mChoreographer.setPointerIcon(PointerIconStyle::TYPE_TEXT, ANOTHER_DISPLAY_ID, SECOND_DEVICE_ID)); firstMousePc->assertPointerIconSet(PointerIconStyle::TYPE_TEXT); secondMousePc->assertPointerIconSet(PointerIconStyle::TYPE_TEXT); ASSERT_TRUE(firstMousePc->isPointerShown()); ASSERT_FALSE(secondMousePc->isPointerShown()); // Allow the icon to be visible on the second display, and move the mouse. mChoreographer.setPointerIconVisibility(ANOTHER_DISPLAY_ID, true); mChoreographer.notifyMotion( MotionArgsBuilder(AMOTION_EVENT_ACTION_HOVER_ENTER, AINPUT_SOURCE_MOUSE) .pointer(MOUSE_POINTER) .deviceId(SECOND_DEVICE_ID) .displayId(ANOTHER_DISPLAY_ID) .build()); ASSERT_TRUE(firstMousePc->isPointerShown()); ASSERT_TRUE(secondMousePc->isPointerShown()); } TEST_F(PointerChoreographerTest, SetPointerIconVisibilityHidesPointerWhenDeviceConnected) { mChoreographer.setDisplayViewports(createViewports({DISPLAY_ID})); mChoreographer.setDefaultMouseDisplayId(DISPLAY_ID); // Hide the pointer on the display, and then connect the mouse. mChoreographer.setPointerIconVisibility(DISPLAY_ID, false); mChoreographer.notifyInputDevicesChanged( {/*id=*/0, {generateTestDeviceInfo(DEVICE_ID, AINPUT_SOURCE_MOUSE, ADISPLAY_ID_NONE)}}); auto mousePc = assertPointerControllerCreated(ControllerType::MOUSE); ASSERT_EQ(DISPLAY_ID, mousePc->getDisplayId()); // The pointer should not be visible. ASSERT_FALSE(mousePc->isPointerShown()); } TEST_F(PointerChoreographerTest, SetPointerIconVisibilityHidesPointerForTouchpad) { mChoreographer.setDisplayViewports(createViewports({DISPLAY_ID})); mChoreographer.setDefaultMouseDisplayId(DISPLAY_ID); // Hide the pointer on the display. mChoreographer.setPointerIconVisibility(DISPLAY_ID, false); mChoreographer.notifyInputDevicesChanged( {/*id=*/0, {generateTestDeviceInfo(DEVICE_ID, AINPUT_SOURCE_MOUSE | AINPUT_SOURCE_TOUCHPAD, ADISPLAY_ID_NONE)}}); auto touchpadPc = assertPointerControllerCreated(ControllerType::MOUSE); ASSERT_EQ(DISPLAY_ID, touchpadPc->getDisplayId()); mChoreographer.notifyMotion(MotionArgsBuilder(AMOTION_EVENT_ACTION_HOVER_ENTER, AINPUT_SOURCE_MOUSE | AINPUT_SOURCE_TOUCHPAD) .pointer(TOUCHPAD_POINTER) .deviceId(DEVICE_ID) .displayId(DISPLAY_ID) .build()); // The pointer should not be visible. ASSERT_FALSE(touchpadPc->isPointerShown()); } TEST_F(PointerChoreographerTest, SetPointerIconVisibilityHidesPointerForStylus) { mChoreographer.setDisplayViewports(createViewports({DISPLAY_ID})); mChoreographer.setStylusPointerIconEnabled(true); // Hide the pointer on the display. 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()); ASSERT_TRUE(mChoreographer.setPointerIcon(PointerIconStyle::TYPE_TEXT, DISPLAY_ID, DEVICE_ID)); auto pc = assertPointerControllerCreated(ControllerType::STYLUS); pc->assertPointerIconSet(PointerIconStyle::TYPE_TEXT); // The pointer should not be visible. ASSERT_FALSE(pc->isPointerShown()); } } // namespace android