Loading services/inputflinger/include/InputReaderBase.h +9 −1 Original line number Diff line number Diff line Loading @@ -197,6 +197,9 @@ struct InputReaderConfiguration { // The keyboard layout association has changed. CHANGE_KEYBOARD_LAYOUT_ASSOCIATION = 1 << 11, // The stylus button reporting configurations has changed. CHANGE_STYLUS_BUTTON_REPORTING = 1 << 12, // All devices must be reopened. CHANGE_MUST_REOPEN = 1 << 31, }; Loading Loading @@ -309,6 +312,10 @@ struct InputReaderConfiguration { // The set of currently disabled input devices. std::set<int32_t> disabledDevices; // True if stylus button reporting through motion events should be enabled, in which case // stylus button state changes are reported through motion events. bool stylusButtonMotionEventsEnabled; InputReaderConfiguration() : virtualKeyQuietTime(0), pointerVelocityControlParameters(1.0f, 500.0f, 3000.0f, Loading @@ -329,7 +336,8 @@ struct InputReaderConfiguration { pointerGestureMovementSpeedRatio(0.8f), pointerGestureZoomSpeedRatio(0.3f), showTouches(false), pointerCaptureRequest() {} pointerCaptureRequest(), stylusButtonMotionEventsEnabled(true) {} static std::string changesToString(uint32_t changes); Loading services/inputflinger/reader/mapper/TouchInputMapper.cpp +14 −3 Original line number Diff line number Diff line Loading @@ -88,6 +88,14 @@ static ui::Size getNaturalDisplaySize(const DisplayViewport& viewport) { return rotatedDisplaySize; } static int32_t filterButtonState(InputReaderConfiguration& config, int32_t buttonState) { if (!config.stylusButtonMotionEventsEnabled) { buttonState &= ~(AMOTION_EVENT_BUTTON_STYLUS_PRIMARY | AMOTION_EVENT_BUTTON_STYLUS_SECONDARY); } return buttonState; } // --- RawPointerData --- void RawPointerData::getCentroidOfTouchingPointers(float* outX, float* outY) const { Loading Loading @@ -1400,8 +1408,9 @@ std::list<NotifyArgs> TouchInputMapper::sync(nsecs_t when, nsecs_t readTime) { next.readTime = readTime; // Sync button state. next.buttonState = mTouchButtonAccumulator.getButtonState() | mCursorButtonAccumulator.getButtonState(); next.buttonState = filterButtonState(mConfig, mTouchButtonAccumulator.getButtonState() | mCursorButtonAccumulator.getButtonState()); // Sync scroll next.rawVScroll = mCursorScrollAccumulator.getRelativeVWheel(); Loading Loading @@ -1640,7 +1649,9 @@ bool TouchInputMapper::isTouchScreen() { void TouchInputMapper::applyExternalStylusButtonState(nsecs_t when) { if (mDeviceMode == DeviceMode::DIRECT && hasExternalStylus()) { // If any of the external buttons are already pressed by the touch device, ignore them. const int32_t pressedButtons = ~mCurrentRawState.buttonState & mExternalStylusState.buttons; const int32_t pressedButtons = filterButtonState(mConfig, ~mCurrentRawState.buttonState & mExternalStylusState.buttons); const int32_t releasedButtons = mExternalStylusButtonsApplied & ~mExternalStylusState.buttons; Loading services/inputflinger/tests/FakeInputReaderPolicy.cpp +4 −0 Original line number Diff line number Diff line Loading @@ -201,6 +201,10 @@ void FakeInputReaderPolicy::setVelocityControlParams(const VelocityControlParame mConfig.wheelVelocityControlParameters = params; } void FakeInputReaderPolicy::setStylusButtonMotionEventsEnabled(bool enabled) { mConfig.stylusButtonMotionEventsEnabled = enabled; } void FakeInputReaderPolicy::getReaderConfiguration(InputReaderConfiguration* outConfig) { *outConfig = mConfig; } Loading services/inputflinger/tests/FakeInputReaderPolicy.h +1 −0 Original line number Diff line number Diff line Loading @@ -75,6 +75,7 @@ public: float getPointerGestureMovementSpeedRatio(); float getPointerGestureZoomSpeedRatio(); void setVelocityControlParams(const VelocityControlParameters& params); void setStylusButtonMotionEventsEnabled(bool enabled); private: void getReaderConfiguration(InputReaderConfiguration* outConfig) override; Loading services/inputflinger/tests/InputReader_test.cpp +90 −0 Original line number Diff line number Diff line Loading @@ -2020,6 +2020,56 @@ TYPED_TEST(StylusButtonIntegrationTest, StylusButtonsWithinTouchGesture) { WithDeviceId(touchscreenId)))); } TYPED_TEST(StylusButtonIntegrationTest, StylusButtonMotionEventsDisabled) { TestFixture::mFakePolicy->setStylusButtonMotionEventsEnabled(false); TestFixture::mReader->requestRefreshConfiguration( InputReaderConfiguration::CHANGE_STYLUS_BUTTON_REPORTING); const Point centerPoint = TestFixture::mTouchscreen->getCenterPoint(); const auto touchscreenId = TestFixture::mTouchscreenInfo.getId(); const auto stylusId = TestFixture::mStylusInfo.getId(); // Start a stylus gesture. By the time this event is processed, the configuration change that // was requested is guaranteed to be completed. TestFixture::mTouchscreen->sendSlot(FIRST_SLOT); TestFixture::mTouchscreen->sendTrackingId(FIRST_TRACKING_ID); TestFixture::mTouchscreen->sendToolType(MT_TOOL_PEN); TestFixture::mTouchscreen->sendDown(centerPoint); TestFixture::mTouchscreen->sendSync(); ASSERT_NO_FATAL_FAILURE(TestFixture::mTestListener->assertNotifyMotionWasCalled( AllOf(WithMotionAction(AMOTION_EVENT_ACTION_DOWN), WithToolType(AMOTION_EVENT_TOOL_TYPE_STYLUS), WithButtonState(0), WithDeviceId(touchscreenId)))); // Press and release a stylus button. Each change only generates a MOVE motion event. // Key events are unaffected. TestFixture::mStylus->pressKey(BTN_STYLUS); ASSERT_NO_FATAL_FAILURE(TestFixture::mTestListener->assertNotifyKeyWasCalled( AllOf(WithKeyAction(AKEY_EVENT_ACTION_DOWN), WithSource(AINPUT_SOURCE_KEYBOARD), WithKeyCode(AKEYCODE_STYLUS_BUTTON_PRIMARY), WithDeviceId(stylusId)))); ASSERT_NO_FATAL_FAILURE(TestFixture::mTestListener->assertNotifyMotionWasCalled( AllOf(WithMotionAction(AMOTION_EVENT_ACTION_MOVE), WithToolType(AMOTION_EVENT_TOOL_TYPE_STYLUS), WithButtonState(0), WithDeviceId(touchscreenId)))); TestFixture::mStylus->releaseKey(BTN_STYLUS); ASSERT_NO_FATAL_FAILURE(TestFixture::mTestListener->assertNotifyKeyWasCalled( AllOf(WithKeyAction(AKEY_EVENT_ACTION_UP), WithSource(AINPUT_SOURCE_KEYBOARD), WithKeyCode(AKEYCODE_STYLUS_BUTTON_PRIMARY), WithDeviceId(stylusId)))); ASSERT_NO_FATAL_FAILURE(TestFixture::mTestListener->assertNotifyMotionWasCalled( AllOf(WithMotionAction(AMOTION_EVENT_ACTION_MOVE), WithToolType(AMOTION_EVENT_TOOL_TYPE_STYLUS), WithButtonState(0), WithDeviceId(touchscreenId)))); // Finish the stylus gesture. TestFixture::mTouchscreen->sendTrackingId(INVALID_TRACKING_ID); TestFixture::mTouchscreen->sendSync(); ASSERT_NO_FATAL_FAILURE(TestFixture::mTestListener->assertNotifyMotionWasCalled( AllOf(WithMotionAction(AMOTION_EVENT_ACTION_UP), WithToolType(AMOTION_EVENT_TOOL_TYPE_STYLUS), WithButtonState(0), WithDeviceId(touchscreenId)))); } // --- ExternalStylusIntegrationTest --- // Verify the behavior of an external stylus. An external stylus can report pressure or button Loading Loading @@ -6577,6 +6627,46 @@ TEST_F(SingleTouchInputMapperTest, ButtonIsReleasedOnTouchUp) { WithCoords(toDisplayX(100), toDisplayY(200)), WithButtonState(0)))); } TEST_F(SingleTouchInputMapperTest, StylusButtonMotionEventsDisabled) { addConfigurationProperty("touch.deviceType", "touchScreen"); prepareDisplay(ui::ROTATION_0); prepareButtons(); prepareAxes(POSITION); mFakePolicy->setStylusButtonMotionEventsEnabled(false); SingleTouchInputMapper& mapper = addMapperAndConfigure<SingleTouchInputMapper>(); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyDeviceResetWasCalled()); // Press a stylus button. processKey(mapper, BTN_STYLUS, 1); processSync(mapper); // Start a touch gesture and ensure that the stylus button is not reported. processDown(mapper, 100, 200); processSync(mapper); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled( AllOf(WithMotionAction(AMOTION_EVENT_ACTION_DOWN), WithButtonState(0)))); // Release and press the stylus button again. processKey(mapper, BTN_STYLUS, 0); processSync(mapper); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled( AllOf(WithMotionAction(AMOTION_EVENT_ACTION_MOVE), WithButtonState(0)))); processKey(mapper, BTN_STYLUS, 1); processSync(mapper); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled( AllOf(WithMotionAction(AMOTION_EVENT_ACTION_MOVE), WithButtonState(0)))); // Release the touch gesture. processUp(mapper); processSync(mapper); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled( AllOf(WithMotionAction(AMOTION_EVENT_ACTION_UP), WithButtonState(0)))); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasNotCalled()); } TEST_F(SingleTouchInputMapperTest, WhenDeviceTypeIsSetToTouchNavigation_setsCorrectType) { mFakePolicy->addDeviceTypeAssociation(DEVICE_LOCATION, "touchNavigation"); prepareDisplay(ui::ROTATION_0); Loading Loading
services/inputflinger/include/InputReaderBase.h +9 −1 Original line number Diff line number Diff line Loading @@ -197,6 +197,9 @@ struct InputReaderConfiguration { // The keyboard layout association has changed. CHANGE_KEYBOARD_LAYOUT_ASSOCIATION = 1 << 11, // The stylus button reporting configurations has changed. CHANGE_STYLUS_BUTTON_REPORTING = 1 << 12, // All devices must be reopened. CHANGE_MUST_REOPEN = 1 << 31, }; Loading Loading @@ -309,6 +312,10 @@ struct InputReaderConfiguration { // The set of currently disabled input devices. std::set<int32_t> disabledDevices; // True if stylus button reporting through motion events should be enabled, in which case // stylus button state changes are reported through motion events. bool stylusButtonMotionEventsEnabled; InputReaderConfiguration() : virtualKeyQuietTime(0), pointerVelocityControlParameters(1.0f, 500.0f, 3000.0f, Loading @@ -329,7 +336,8 @@ struct InputReaderConfiguration { pointerGestureMovementSpeedRatio(0.8f), pointerGestureZoomSpeedRatio(0.3f), showTouches(false), pointerCaptureRequest() {} pointerCaptureRequest(), stylusButtonMotionEventsEnabled(true) {} static std::string changesToString(uint32_t changes); Loading
services/inputflinger/reader/mapper/TouchInputMapper.cpp +14 −3 Original line number Diff line number Diff line Loading @@ -88,6 +88,14 @@ static ui::Size getNaturalDisplaySize(const DisplayViewport& viewport) { return rotatedDisplaySize; } static int32_t filterButtonState(InputReaderConfiguration& config, int32_t buttonState) { if (!config.stylusButtonMotionEventsEnabled) { buttonState &= ~(AMOTION_EVENT_BUTTON_STYLUS_PRIMARY | AMOTION_EVENT_BUTTON_STYLUS_SECONDARY); } return buttonState; } // --- RawPointerData --- void RawPointerData::getCentroidOfTouchingPointers(float* outX, float* outY) const { Loading Loading @@ -1400,8 +1408,9 @@ std::list<NotifyArgs> TouchInputMapper::sync(nsecs_t when, nsecs_t readTime) { next.readTime = readTime; // Sync button state. next.buttonState = mTouchButtonAccumulator.getButtonState() | mCursorButtonAccumulator.getButtonState(); next.buttonState = filterButtonState(mConfig, mTouchButtonAccumulator.getButtonState() | mCursorButtonAccumulator.getButtonState()); // Sync scroll next.rawVScroll = mCursorScrollAccumulator.getRelativeVWheel(); Loading Loading @@ -1640,7 +1649,9 @@ bool TouchInputMapper::isTouchScreen() { void TouchInputMapper::applyExternalStylusButtonState(nsecs_t when) { if (mDeviceMode == DeviceMode::DIRECT && hasExternalStylus()) { // If any of the external buttons are already pressed by the touch device, ignore them. const int32_t pressedButtons = ~mCurrentRawState.buttonState & mExternalStylusState.buttons; const int32_t pressedButtons = filterButtonState(mConfig, ~mCurrentRawState.buttonState & mExternalStylusState.buttons); const int32_t releasedButtons = mExternalStylusButtonsApplied & ~mExternalStylusState.buttons; Loading
services/inputflinger/tests/FakeInputReaderPolicy.cpp +4 −0 Original line number Diff line number Diff line Loading @@ -201,6 +201,10 @@ void FakeInputReaderPolicy::setVelocityControlParams(const VelocityControlParame mConfig.wheelVelocityControlParameters = params; } void FakeInputReaderPolicy::setStylusButtonMotionEventsEnabled(bool enabled) { mConfig.stylusButtonMotionEventsEnabled = enabled; } void FakeInputReaderPolicy::getReaderConfiguration(InputReaderConfiguration* outConfig) { *outConfig = mConfig; } Loading
services/inputflinger/tests/FakeInputReaderPolicy.h +1 −0 Original line number Diff line number Diff line Loading @@ -75,6 +75,7 @@ public: float getPointerGestureMovementSpeedRatio(); float getPointerGestureZoomSpeedRatio(); void setVelocityControlParams(const VelocityControlParameters& params); void setStylusButtonMotionEventsEnabled(bool enabled); private: void getReaderConfiguration(InputReaderConfiguration* outConfig) override; Loading
services/inputflinger/tests/InputReader_test.cpp +90 −0 Original line number Diff line number Diff line Loading @@ -2020,6 +2020,56 @@ TYPED_TEST(StylusButtonIntegrationTest, StylusButtonsWithinTouchGesture) { WithDeviceId(touchscreenId)))); } TYPED_TEST(StylusButtonIntegrationTest, StylusButtonMotionEventsDisabled) { TestFixture::mFakePolicy->setStylusButtonMotionEventsEnabled(false); TestFixture::mReader->requestRefreshConfiguration( InputReaderConfiguration::CHANGE_STYLUS_BUTTON_REPORTING); const Point centerPoint = TestFixture::mTouchscreen->getCenterPoint(); const auto touchscreenId = TestFixture::mTouchscreenInfo.getId(); const auto stylusId = TestFixture::mStylusInfo.getId(); // Start a stylus gesture. By the time this event is processed, the configuration change that // was requested is guaranteed to be completed. TestFixture::mTouchscreen->sendSlot(FIRST_SLOT); TestFixture::mTouchscreen->sendTrackingId(FIRST_TRACKING_ID); TestFixture::mTouchscreen->sendToolType(MT_TOOL_PEN); TestFixture::mTouchscreen->sendDown(centerPoint); TestFixture::mTouchscreen->sendSync(); ASSERT_NO_FATAL_FAILURE(TestFixture::mTestListener->assertNotifyMotionWasCalled( AllOf(WithMotionAction(AMOTION_EVENT_ACTION_DOWN), WithToolType(AMOTION_EVENT_TOOL_TYPE_STYLUS), WithButtonState(0), WithDeviceId(touchscreenId)))); // Press and release a stylus button. Each change only generates a MOVE motion event. // Key events are unaffected. TestFixture::mStylus->pressKey(BTN_STYLUS); ASSERT_NO_FATAL_FAILURE(TestFixture::mTestListener->assertNotifyKeyWasCalled( AllOf(WithKeyAction(AKEY_EVENT_ACTION_DOWN), WithSource(AINPUT_SOURCE_KEYBOARD), WithKeyCode(AKEYCODE_STYLUS_BUTTON_PRIMARY), WithDeviceId(stylusId)))); ASSERT_NO_FATAL_FAILURE(TestFixture::mTestListener->assertNotifyMotionWasCalled( AllOf(WithMotionAction(AMOTION_EVENT_ACTION_MOVE), WithToolType(AMOTION_EVENT_TOOL_TYPE_STYLUS), WithButtonState(0), WithDeviceId(touchscreenId)))); TestFixture::mStylus->releaseKey(BTN_STYLUS); ASSERT_NO_FATAL_FAILURE(TestFixture::mTestListener->assertNotifyKeyWasCalled( AllOf(WithKeyAction(AKEY_EVENT_ACTION_UP), WithSource(AINPUT_SOURCE_KEYBOARD), WithKeyCode(AKEYCODE_STYLUS_BUTTON_PRIMARY), WithDeviceId(stylusId)))); ASSERT_NO_FATAL_FAILURE(TestFixture::mTestListener->assertNotifyMotionWasCalled( AllOf(WithMotionAction(AMOTION_EVENT_ACTION_MOVE), WithToolType(AMOTION_EVENT_TOOL_TYPE_STYLUS), WithButtonState(0), WithDeviceId(touchscreenId)))); // Finish the stylus gesture. TestFixture::mTouchscreen->sendTrackingId(INVALID_TRACKING_ID); TestFixture::mTouchscreen->sendSync(); ASSERT_NO_FATAL_FAILURE(TestFixture::mTestListener->assertNotifyMotionWasCalled( AllOf(WithMotionAction(AMOTION_EVENT_ACTION_UP), WithToolType(AMOTION_EVENT_TOOL_TYPE_STYLUS), WithButtonState(0), WithDeviceId(touchscreenId)))); } // --- ExternalStylusIntegrationTest --- // Verify the behavior of an external stylus. An external stylus can report pressure or button Loading Loading @@ -6577,6 +6627,46 @@ TEST_F(SingleTouchInputMapperTest, ButtonIsReleasedOnTouchUp) { WithCoords(toDisplayX(100), toDisplayY(200)), WithButtonState(0)))); } TEST_F(SingleTouchInputMapperTest, StylusButtonMotionEventsDisabled) { addConfigurationProperty("touch.deviceType", "touchScreen"); prepareDisplay(ui::ROTATION_0); prepareButtons(); prepareAxes(POSITION); mFakePolicy->setStylusButtonMotionEventsEnabled(false); SingleTouchInputMapper& mapper = addMapperAndConfigure<SingleTouchInputMapper>(); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyDeviceResetWasCalled()); // Press a stylus button. processKey(mapper, BTN_STYLUS, 1); processSync(mapper); // Start a touch gesture and ensure that the stylus button is not reported. processDown(mapper, 100, 200); processSync(mapper); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled( AllOf(WithMotionAction(AMOTION_EVENT_ACTION_DOWN), WithButtonState(0)))); // Release and press the stylus button again. processKey(mapper, BTN_STYLUS, 0); processSync(mapper); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled( AllOf(WithMotionAction(AMOTION_EVENT_ACTION_MOVE), WithButtonState(0)))); processKey(mapper, BTN_STYLUS, 1); processSync(mapper); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled( AllOf(WithMotionAction(AMOTION_EVENT_ACTION_MOVE), WithButtonState(0)))); // Release the touch gesture. processUp(mapper); processSync(mapper); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled( AllOf(WithMotionAction(AMOTION_EVENT_ACTION_UP), WithButtonState(0)))); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasNotCalled()); } TEST_F(SingleTouchInputMapperTest, WhenDeviceTypeIsSetToTouchNavigation_setsCorrectType) { mFakePolicy->addDeviceTypeAssociation(DEVICE_LOCATION, "touchNavigation"); prepareDisplay(ui::ROTATION_0); Loading