Add configuration for disabling stylus button motion events
This adds an option for disabling stylus buttons from being reported as
part of a motion gesture. When disabled, all reported motion events'
button state will not include any stylus buttons. Key events are
unaffected.
Bug: 263256832
Test: atest inputflinger_tests
Change-Id: If9ac98c77e980e6b45cfc012ed04b5541e350ebc
diff --git a/services/inputflinger/include/InputReaderBase.h b/services/inputflinger/include/InputReaderBase.h
index d2c940f..d55ab28 100644
--- a/services/inputflinger/include/InputReaderBase.h
+++ b/services/inputflinger/include/InputReaderBase.h
@@ -197,6 +197,9 @@
// 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,
};
@@ -309,6 +312,10 @@
// 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,
@@ -329,7 +336,8 @@
pointerGestureMovementSpeedRatio(0.8f),
pointerGestureZoomSpeedRatio(0.3f),
showTouches(false),
- pointerCaptureRequest() {}
+ pointerCaptureRequest(),
+ stylusButtonMotionEventsEnabled(true) {}
static std::string changesToString(uint32_t changes);
diff --git a/services/inputflinger/reader/mapper/TouchInputMapper.cpp b/services/inputflinger/reader/mapper/TouchInputMapper.cpp
index 9a7af40..4d51aee 100644
--- a/services/inputflinger/reader/mapper/TouchInputMapper.cpp
+++ b/services/inputflinger/reader/mapper/TouchInputMapper.cpp
@@ -88,6 +88,14 @@
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 {
@@ -1400,8 +1408,9 @@
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();
@@ -1640,7 +1649,9 @@
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;
diff --git a/services/inputflinger/tests/FakeInputReaderPolicy.cpp b/services/inputflinger/tests/FakeInputReaderPolicy.cpp
index f755356..bb8a30e 100644
--- a/services/inputflinger/tests/FakeInputReaderPolicy.cpp
+++ b/services/inputflinger/tests/FakeInputReaderPolicy.cpp
@@ -201,6 +201,10 @@
mConfig.wheelVelocityControlParameters = params;
}
+void FakeInputReaderPolicy::setStylusButtonMotionEventsEnabled(bool enabled) {
+ mConfig.stylusButtonMotionEventsEnabled = enabled;
+}
+
void FakeInputReaderPolicy::getReaderConfiguration(InputReaderConfiguration* outConfig) {
*outConfig = mConfig;
}
diff --git a/services/inputflinger/tests/FakeInputReaderPolicy.h b/services/inputflinger/tests/FakeInputReaderPolicy.h
index 862ff0b..9ec3217 100644
--- a/services/inputflinger/tests/FakeInputReaderPolicy.h
+++ b/services/inputflinger/tests/FakeInputReaderPolicy.h
@@ -75,6 +75,7 @@
float getPointerGestureMovementSpeedRatio();
float getPointerGestureZoomSpeedRatio();
void setVelocityControlParams(const VelocityControlParameters& params);
+ void setStylusButtonMotionEventsEnabled(bool enabled);
private:
void getReaderConfiguration(InputReaderConfiguration* outConfig) override;
diff --git a/services/inputflinger/tests/InputReader_test.cpp b/services/inputflinger/tests/InputReader_test.cpp
index 96d27b8..3bb2bde 100644
--- a/services/inputflinger/tests/InputReader_test.cpp
+++ b/services/inputflinger/tests/InputReader_test.cpp
@@ -2023,6 +2023,56 @@
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
@@ -6577,6 +6627,46 @@
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);