Ensure stylus buttons generate events consistently
Add tests to verify that a touchscreen stylus and fused/unfused external
styluses generate button events consistently.
Make changes in TouchInputMapper to enforce consistentcy for external
stylus buttons. In particular, we allow the external stylus's button
state to be applied to the touches even when there is no fusion in
progress.
Bug: 246394583
Test: atest inputflinger_tests
Change-Id: I645481db18e1bec8b61d8309aa4f02afcf1a5383
diff --git a/services/inputflinger/reader/mapper/TouchInputMapper.cpp b/services/inputflinger/reader/mapper/TouchInputMapper.cpp
index 286e1f5..5e81ff8 100644
--- a/services/inputflinger/reader/mapper/TouchInputMapper.cpp
+++ b/services/inputflinger/reader/mapper/TouchInputMapper.cpp
@@ -254,6 +254,8 @@
dump += StringPrintf(INDENT4 "External Stylus ID: %" PRId64 "\n", mExternalStylusId);
dump += StringPrintf(INDENT4 "External Stylus Data Timeout: %" PRId64 "\n",
mExternalStylusFusionTimeout);
+ dump += StringPrintf(INDENT4 " External Stylus Buttons Applied: 0x%08x",
+ mExternalStylusButtonsApplied);
dump += INDENT3 "External Stylus State:\n";
dumpStylusState(dump, mExternalStylusState);
@@ -1413,6 +1415,7 @@
mExternalStylusId = -1;
mExternalStylusFusionTimeout = LLONG_MAX;
mExternalStylusDataPending = false;
+ mExternalStylusButtonsApplied = 0;
}
void TouchInputMapper::clearStylusDataPendingFlags() {
@@ -1683,8 +1686,17 @@
}
void TouchInputMapper::applyExternalStylusButtonState(nsecs_t when) {
- if (mDeviceMode == DeviceMode::DIRECT && hasExternalStylus() && mExternalStylusId != -1) {
- mCurrentRawState.buttonState |= mExternalStylusState.buttons;
+ 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 releasedButtons =
+ mExternalStylusButtonsApplied & ~mExternalStylusState.buttons;
+
+ mCurrentRawState.buttonState |= pressedButtons;
+ mCurrentRawState.buttonState &= ~releasedButtons;
+
+ mExternalStylusButtonsApplied |= pressedButtons;
+ mExternalStylusButtonsApplied &= ~releasedButtons;
}
}
@@ -1722,7 +1734,8 @@
mExternalStylusId = state.rawPointerData.touchingIdBits.firstMarkedBit();
} else if (timeout) {
ALOGD_IF(DEBUG_STYLUS_FUSION, "Timeout expired, assuming touch is not a stylus.");
- resetExternalStylus();
+ mExternalStylusId = -1;
+ mExternalStylusFusionTimeout = LLONG_MAX;
} else {
if (mExternalStylusFusionTimeout == LLONG_MAX) {
mExternalStylusFusionTimeout = state.when + EXTERNAL_STYLUS_DATA_TIMEOUT;
@@ -1764,11 +1777,14 @@
std::list<NotifyArgs> TouchInputMapper::updateExternalStylusState(const StylusState& state) {
std::list<NotifyArgs> out;
+ const bool buttonsChanged = mExternalStylusState.buttons != state.buttons;
mExternalStylusState.copyFrom(state);
- if (mExternalStylusId != -1 || mExternalStylusFusionTimeout != LLONG_MAX) {
- // We're either in the middle of a fused stream of data or we're waiting on data before
- // dispatching the initial down, so go ahead and dispatch now that we have fresh stylus
- // data.
+ if (mExternalStylusId != -1 || mExternalStylusFusionTimeout != LLONG_MAX || buttonsChanged) {
+ // The following three cases are handled here:
+ // - We're in the middle of a fused stream of data;
+ // - We're waiting on external stylus data before dispatching the initial down; or
+ // - Only the button state, which is not reported through a specific pointer, has changed.
+ // Go ahead and dispatch now that we have fresh stylus data.
mExternalStylusDataPending = true;
out += processRawTouches(false /*timeout*/);
}
diff --git a/services/inputflinger/reader/mapper/TouchInputMapper.h b/services/inputflinger/reader/mapper/TouchInputMapper.h
index 34cecf9..efbe885 100644
--- a/services/inputflinger/reader/mapper/TouchInputMapper.h
+++ b/services/inputflinger/reader/mapper/TouchInputMapper.h
@@ -365,6 +365,8 @@
int64_t mExternalStylusId;
nsecs_t mExternalStylusFusionTimeout;
bool mExternalStylusDataPending;
+ // A subset of the buttons in mCurrentRawState that came from an external stylus.
+ int32_t mExternalStylusButtonsApplied;
// True if we sent a HOVER_ENTER event.
bool mSentHoverEnter;