CapturedTouchpadEventConverter: filter out palms
When a touchpad marks a touch as a palm, we don't want to pass it on to
apps that have captured the touchpad. In future, we could pass these
through if we wanted by removing @hide from MotionEvent.TOOL_TYPE_PALM
and using that to denote palm touches.
Bug: b/259547750
Test: atest inputflinger_tests
Test: on a suitable touchpad captured by a test app, move a palm around.
Check it's not reported at all when the pad identifies it straight
away, and that it's cancelled when identified after touching down.
(`getevent -l | grep TOOL_TYPE` is useful to tell when the pad
changes its classification of the touch)
Change-Id: Iefe84120321246f3661a4d2d06e0ec01ba9fe52b
diff --git a/services/inputflinger/reader/mapper/CapturedTouchpadEventConverter.cpp b/services/inputflinger/reader/mapper/CapturedTouchpadEventConverter.cpp
index 023372a..dab4661 100644
--- a/services/inputflinger/reader/mapper/CapturedTouchpadEventConverter.cpp
+++ b/services/inputflinger/reader/mapper/CapturedTouchpadEventConverter.cpp
@@ -162,7 +162,6 @@
}
std::list<NotifyArgs> CapturedTouchpadEventConverter::sync(nsecs_t when, nsecs_t readTime) {
- // TODO(b/259547750): filter out touches marked as palms (using MT_TOOL_PALM).
std::list<NotifyArgs> out;
std::vector<PointerCoords> coords;
std::vector<PointerProperties> properties;
@@ -187,7 +186,11 @@
std::vector<size_t> upSlots, downSlots;
for (size_t i = 0; i < mMotionAccumulator.getSlotCount(); i++) {
- const bool isInUse = mMotionAccumulator.getSlot(i).isInUse();
+ const MultiTouchMotionAccumulator::Slot& slot = mMotionAccumulator.getSlot(i);
+ // Some touchpads continue to report contacts even after they've identified them as palms.
+ // We don't currently have a way to mark these as palms when reporting to apps, so don't
+ // report them at all.
+ const bool isInUse = slot.isInUse() && slot.getToolType() != ToolType::PALM;
const bool wasInUse = mPointerIdForSlotNumber.find(i) != mPointerIdForSlotNumber.end();
if (isInUse && !wasInUse) {
downSlots.push_back(i);
@@ -199,10 +202,15 @@
// For any touches that were lifted, send UP or POINTER_UP events.
for (size_t slotNumber : upSlots) {
const size_t indexToRemove = coordsIndexForSlotNumber.at(slotNumber);
- const int32_t action = coords.size() == 1
- ? AMOTION_EVENT_ACTION_UP
- : actionWithIndex(AMOTION_EVENT_ACTION_POINTER_UP, indexToRemove);
- out.push_back(makeMotionArgs(when, readTime, action, coords, properties));
+ const bool cancel = mMotionAccumulator.getSlot(slotNumber).getToolType() == ToolType::PALM;
+ int32_t action;
+ if (coords.size() == 1) {
+ action = cancel ? AMOTION_EVENT_ACTION_CANCEL : AMOTION_EVENT_ACTION_UP;
+ } else {
+ action = actionWithIndex(AMOTION_EVENT_ACTION_POINTER_UP, indexToRemove);
+ }
+ out.push_back(makeMotionArgs(when, readTime, action, coords, properties, /*actionButton=*/0,
+ /*flags=*/cancel ? AMOTION_EVENT_FLAG_CANCELED : 0));
freePointerIdForSlot(slotNumber);
coords.erase(coords.begin() + indexToRemove);
@@ -249,12 +257,12 @@
NotifyMotionArgs CapturedTouchpadEventConverter::makeMotionArgs(
nsecs_t when, nsecs_t readTime, int32_t action, const std::vector<PointerCoords>& coords,
- const std::vector<PointerProperties>& properties, int32_t actionButton) {
+ const std::vector<PointerProperties>& properties, int32_t actionButton, int32_t flags) {
LOG_ALWAYS_FATAL_IF(coords.size() != properties.size(),
"Mismatched coords and properties arrays.");
return NotifyMotionArgs(mReaderContext.getNextId(), when, readTime, mDeviceId, SOURCE,
ADISPLAY_ID_NONE, /*policyFlags=*/POLICY_FLAG_WAKE, action,
- /*actionButton=*/actionButton, /*flags=*/0,
+ /*actionButton=*/actionButton, flags,
mReaderContext.getGlobalMetaState(), mButtonState,
MotionClassification::NONE, AMOTION_EVENT_EDGE_FLAG_NONE, coords.size(),
properties.data(), coords.data(), /*xPrecision=*/1.0f,
diff --git a/services/inputflinger/reader/mapper/CapturedTouchpadEventConverter.h b/services/inputflinger/reader/mapper/CapturedTouchpadEventConverter.h
index d81692d..9b6df7a 100644
--- a/services/inputflinger/reader/mapper/CapturedTouchpadEventConverter.h
+++ b/services/inputflinger/reader/mapper/CapturedTouchpadEventConverter.h
@@ -53,7 +53,7 @@
[[nodiscard]] NotifyMotionArgs makeMotionArgs(nsecs_t when, nsecs_t readTime, int32_t action,
const std::vector<PointerCoords>& coords,
const std::vector<PointerProperties>& properties,
- int32_t actionButton = 0);
+ int32_t actionButton = 0, int32_t flags = 0);
PointerCoords makePointerCoordsForSlot(const MultiTouchMotionAccumulator::Slot& slot) const;
int32_t allocatePointerIdToSlot(size_t slotNumber);
void freePointerIdForSlot(size_t slotNumber);
diff --git a/services/inputflinger/tests/CapturedTouchpadEventConverter_test.cpp b/services/inputflinger/tests/CapturedTouchpadEventConverter_test.cpp
index 694641c..3dc5152 100644
--- a/services/inputflinger/tests/CapturedTouchpadEventConverter_test.cpp
+++ b/services/inputflinger/tests/CapturedTouchpadEventConverter_test.cpp
@@ -22,6 +22,7 @@
#include <EventHub.h>
#include <gtest/gtest.h>
#include <linux/input-event-codes.h>
+#include <linux/input.h>
#include <utils/StrongPointer.h>
#include "FakeEventHub.h"
@@ -415,6 +416,233 @@
EPSILON);
}
+TEST_F(CapturedTouchpadEventConverterTest, OnePalm_neverReported) {
+ addBasicAxesToEventHub();
+ mFakeEventHub->addAbsoluteAxis(EVENTHUB_ID, ABS_MT_TOOL_TYPE, 0, MT_TOOL_PALM, 0, 0, 0);
+ CapturedTouchpadEventConverter conv(*mReader.getContext(), mDeviceContext, mAccumulator,
+ DEVICE_ID);
+
+ processAxis(conv, EV_ABS, ABS_MT_SLOT, 0);
+ processAxis(conv, EV_ABS, ABS_MT_TRACKING_ID, 1);
+ processAxis(conv, EV_ABS, ABS_MT_POSITION_X, 50);
+ processAxis(conv, EV_ABS, ABS_MT_POSITION_Y, 100);
+ processAxis(conv, EV_ABS, ABS_MT_TOOL_TYPE, MT_TOOL_PALM);
+ processAxis(conv, EV_KEY, BTN_TOUCH, 1);
+ processAxis(conv, EV_KEY, BTN_TOOL_FINGER, 1);
+
+ EXPECT_EQ(0u, processSync(conv).size());
+
+ processAxis(conv, EV_ABS, ABS_MT_POSITION_X, 51);
+
+ EXPECT_EQ(0u, processSync(conv).size());
+
+ processAxis(conv, EV_ABS, ABS_MT_TRACKING_ID, -1);
+ processAxis(conv, EV_KEY, BTN_TOUCH, 0);
+ processAxis(conv, EV_KEY, BTN_TOOL_FINGER, 0);
+
+ EXPECT_EQ(0u, processSync(conv).size());
+}
+
+TEST_F(CapturedTouchpadEventConverterTest, FingerTurningIntoPalm_cancelled) {
+ addBasicAxesToEventHub();
+ mFakeEventHub->addAbsoluteAxis(EVENTHUB_ID, ABS_MT_TOOL_TYPE, 0, MT_TOOL_PALM, 0, 0, 0);
+ CapturedTouchpadEventConverter conv(*mReader.getContext(), mDeviceContext, mAccumulator,
+ DEVICE_ID);
+
+ processAxis(conv, EV_ABS, ABS_MT_SLOT, 0);
+ processAxis(conv, EV_ABS, ABS_MT_TRACKING_ID, 1);
+ processAxis(conv, EV_ABS, ABS_MT_POSITION_X, 50);
+ processAxis(conv, EV_ABS, ABS_MT_POSITION_Y, 100);
+ processAxis(conv, EV_ABS, ABS_MT_TOOL_TYPE, MT_TOOL_FINGER);
+ processAxis(conv, EV_KEY, BTN_TOUCH, 1);
+ processAxis(conv, EV_KEY, BTN_TOOL_FINGER, 1);
+
+ EXPECT_THAT(processSyncAndExpectSingleMotionArg(conv),
+ AllOf(WithMotionAction(AMOTION_EVENT_ACTION_DOWN), WithToolType(ToolType::FINGER),
+ WithPointerCount(1u)));
+
+ processAxis(conv, EV_ABS, ABS_MT_POSITION_X, 51);
+ processAxis(conv, EV_ABS, ABS_MT_TOOL_TYPE, MT_TOOL_PALM);
+
+ std::list<NotifyArgs> args = processSync(conv);
+ ASSERT_EQ(2u, args.size());
+ EXPECT_THAT(std::get<NotifyMotionArgs>(args.front()),
+ AllOf(WithMotionAction(AMOTION_EVENT_ACTION_MOVE), WithPointerCount(1u)));
+ args.pop_front();
+ EXPECT_THAT(std::get<NotifyMotionArgs>(args.front()),
+ AllOf(WithMotionAction(AMOTION_EVENT_ACTION_CANCEL), WithPointerCount(1u)));
+
+ processAxis(conv, EV_ABS, ABS_MT_POSITION_X, 52);
+
+ EXPECT_EQ(0u, processSync(conv).size());
+
+ processAxis(conv, EV_ABS, ABS_MT_TRACKING_ID, -1);
+ processAxis(conv, EV_KEY, BTN_TOUCH, 0);
+ processAxis(conv, EV_KEY, BTN_TOOL_FINGER, 0);
+
+ EXPECT_EQ(0u, processSync(conv).size());
+}
+
+TEST_F(CapturedTouchpadEventConverterTest, PalmTurningIntoFinger_reported) {
+ addBasicAxesToEventHub();
+ mFakeEventHub->addAbsoluteAxis(EVENTHUB_ID, ABS_MT_TOOL_TYPE, 0, MT_TOOL_PALM, 0, 0, 0);
+ CapturedTouchpadEventConverter conv(*mReader.getContext(), mDeviceContext, mAccumulator,
+ DEVICE_ID);
+
+ processAxis(conv, EV_ABS, ABS_MT_SLOT, 0);
+ processAxis(conv, EV_ABS, ABS_MT_TRACKING_ID, 1);
+ processAxis(conv, EV_ABS, ABS_MT_POSITION_X, 50);
+ processAxis(conv, EV_ABS, ABS_MT_POSITION_Y, 100);
+ processAxis(conv, EV_ABS, ABS_MT_TOOL_TYPE, MT_TOOL_PALM);
+ processAxis(conv, EV_KEY, BTN_TOUCH, 1);
+ processAxis(conv, EV_KEY, BTN_TOOL_FINGER, 1);
+
+ EXPECT_EQ(0u, processSync(conv).size());
+
+ processAxis(conv, EV_ABS, ABS_MT_POSITION_X, 51);
+ processAxis(conv, EV_ABS, ABS_MT_TOOL_TYPE, MT_TOOL_FINGER);
+
+ EXPECT_THAT(processSyncAndExpectSingleMotionArg(conv),
+ AllOf(WithMotionAction(AMOTION_EVENT_ACTION_DOWN), WithPointerCount(1u),
+ WithCoords(51, 100)));
+
+ processAxis(conv, EV_ABS, ABS_MT_POSITION_X, 52);
+
+ EXPECT_THAT(processSyncAndExpectSingleMotionArg(conv),
+ AllOf(WithMotionAction(AMOTION_EVENT_ACTION_MOVE), WithPointerCount(1u),
+ WithCoords(52, 100)));
+}
+
+TEST_F(CapturedTouchpadEventConverterTest, FingerArrivingAfterPalm_onlyFingerReported) {
+ addBasicAxesToEventHub();
+ mFakeEventHub->addAbsoluteAxis(EVENTHUB_ID, ABS_MT_TOOL_TYPE, 0, MT_TOOL_PALM, 0, 0, 0);
+ CapturedTouchpadEventConverter conv(*mReader.getContext(), mDeviceContext, mAccumulator,
+ DEVICE_ID);
+
+ processAxis(conv, EV_ABS, ABS_MT_SLOT, 0);
+ processAxis(conv, EV_ABS, ABS_MT_TRACKING_ID, 1);
+ processAxis(conv, EV_ABS, ABS_MT_POSITION_X, 50);
+ processAxis(conv, EV_ABS, ABS_MT_POSITION_Y, 100);
+ processAxis(conv, EV_ABS, ABS_MT_TOOL_TYPE, MT_TOOL_PALM);
+ processAxis(conv, EV_KEY, BTN_TOUCH, 1);
+ processAxis(conv, EV_KEY, BTN_TOOL_FINGER, 1);
+
+ EXPECT_EQ(0u, processSync(conv).size());
+
+ processAxis(conv, EV_ABS, ABS_MT_SLOT, 1);
+ processAxis(conv, EV_ABS, ABS_MT_TRACKING_ID, 2);
+ processAxis(conv, EV_ABS, ABS_MT_POSITION_X, 100);
+ processAxis(conv, EV_ABS, ABS_MT_POSITION_Y, 150);
+ processAxis(conv, EV_ABS, ABS_MT_TOOL_TYPE, MT_TOOL_FINGER);
+ processAxis(conv, EV_KEY, BTN_TOOL_FINGER, 0);
+ processAxis(conv, EV_KEY, BTN_TOOL_DOUBLETAP, 1);
+
+ EXPECT_THAT(processSyncAndExpectSingleMotionArg(conv),
+ AllOf(WithMotionAction(AMOTION_EVENT_ACTION_DOWN), WithPointerCount(1u),
+ WithCoords(100, 150)));
+
+ processAxis(conv, EV_ABS, ABS_MT_SLOT, 0);
+ processAxis(conv, EV_ABS, ABS_MT_POSITION_X, 52);
+ processAxis(conv, EV_ABS, ABS_MT_POSITION_Y, 102);
+ processAxis(conv, EV_ABS, ABS_MT_SLOT, 1);
+ processAxis(conv, EV_ABS, ABS_MT_POSITION_X, 98);
+ processAxis(conv, EV_ABS, ABS_MT_POSITION_Y, 148);
+
+ EXPECT_THAT(processSyncAndExpectSingleMotionArg(conv),
+ AllOf(WithMotionAction(AMOTION_EVENT_ACTION_MOVE), WithPointerCount(1u),
+ WithCoords(98, 148)));
+}
+
+TEST_F(CapturedTouchpadEventConverterTest, FingerAndFingerTurningIntoPalm_partiallyCancelled) {
+ addBasicAxesToEventHub();
+ mFakeEventHub->addAbsoluteAxis(EVENTHUB_ID, ABS_MT_TOOL_TYPE, 0, MT_TOOL_PALM, 0, 0, 0);
+ CapturedTouchpadEventConverter conv(*mReader.getContext(), mDeviceContext, mAccumulator,
+ DEVICE_ID);
+
+ processAxis(conv, EV_ABS, ABS_MT_SLOT, 0);
+ processAxis(conv, EV_ABS, ABS_MT_TRACKING_ID, 1);
+ processAxis(conv, EV_ABS, ABS_MT_POSITION_X, 50);
+ processAxis(conv, EV_ABS, ABS_MT_TOOL_TYPE, MT_TOOL_FINGER);
+
+ processAxis(conv, EV_ABS, ABS_MT_SLOT, 1);
+ processAxis(conv, EV_ABS, ABS_MT_TRACKING_ID, 2);
+ processAxis(conv, EV_ABS, ABS_MT_POSITION_X, 250);
+ processAxis(conv, EV_ABS, ABS_MT_TOOL_TYPE, MT_TOOL_FINGER);
+
+ processAxis(conv, EV_KEY, BTN_TOUCH, 1);
+ processAxis(conv, EV_KEY, BTN_TOOL_DOUBLETAP, 1);
+
+ std::list<NotifyArgs> args = processSync(conv);
+ ASSERT_EQ(2u, args.size());
+ EXPECT_THAT(std::get<NotifyMotionArgs>(args.front()),
+ AllOf(WithMotionAction(AMOTION_EVENT_ACTION_DOWN), WithPointerCount(1u),
+ WithToolType(ToolType::FINGER)));
+ args.pop_front();
+ EXPECT_THAT(std::get<NotifyMotionArgs>(args.front()),
+ AllOf(WithMotionAction(AMOTION_EVENT_ACTION_POINTER_DOWN |
+ 1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT),
+ WithPointerCount(2u), WithPointerToolType(0, ToolType::FINGER),
+ WithPointerToolType(1, ToolType::FINGER)));
+
+ processAxis(conv, EV_ABS, ABS_MT_SLOT, 0);
+ processAxis(conv, EV_ABS, ABS_MT_POSITION_X, 51);
+
+ processAxis(conv, EV_ABS, ABS_MT_SLOT, 1);
+ processAxis(conv, EV_ABS, ABS_MT_POSITION_X, 251);
+ processAxis(conv, EV_ABS, ABS_MT_TOOL_TYPE, MT_TOOL_PALM);
+
+ args = processSync(conv);
+ ASSERT_EQ(2u, args.size());
+ EXPECT_THAT(std::get<NotifyMotionArgs>(args.front()),
+ AllOf(WithMotionAction(AMOTION_EVENT_ACTION_MOVE), WithPointerCount(2u)));
+ args.pop_front();
+ EXPECT_THAT(std::get<NotifyMotionArgs>(args.front()),
+ AllOf(WithMotionAction(AMOTION_EVENT_ACTION_POINTER_UP |
+ 1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT),
+ WithFlags(AMOTION_EVENT_FLAG_CANCELED), WithPointerCount(2u)));
+}
+
+TEST_F(CapturedTouchpadEventConverterTest, FingerAndPalmTurningIntoFinger_reported) {
+ addBasicAxesToEventHub();
+ mFakeEventHub->addAbsoluteAxis(EVENTHUB_ID, ABS_MT_TOOL_TYPE, 0, MT_TOOL_PALM, 0, 0, 0);
+ CapturedTouchpadEventConverter conv(*mReader.getContext(), mDeviceContext, mAccumulator,
+ DEVICE_ID);
+
+ processAxis(conv, EV_ABS, ABS_MT_SLOT, 0);
+ processAxis(conv, EV_ABS, ABS_MT_TRACKING_ID, 1);
+ processAxis(conv, EV_ABS, ABS_MT_POSITION_X, 50);
+ processAxis(conv, EV_ABS, ABS_MT_TOOL_TYPE, MT_TOOL_FINGER);
+
+ processAxis(conv, EV_ABS, ABS_MT_SLOT, 1);
+ processAxis(conv, EV_ABS, ABS_MT_TRACKING_ID, 2);
+ processAxis(conv, EV_ABS, ABS_MT_POSITION_X, 250);
+ processAxis(conv, EV_ABS, ABS_MT_TOOL_TYPE, MT_TOOL_PALM);
+
+ processAxis(conv, EV_KEY, BTN_TOUCH, 1);
+ processAxis(conv, EV_KEY, BTN_TOOL_DOUBLETAP, 1);
+
+ EXPECT_THAT(processSyncAndExpectSingleMotionArg(conv),
+ AllOf(WithMotionAction(AMOTION_EVENT_ACTION_DOWN), WithPointerCount(1u),
+ WithToolType(ToolType::FINGER)));
+
+ processAxis(conv, EV_ABS, ABS_MT_SLOT, 0);
+ processAxis(conv, EV_ABS, ABS_MT_POSITION_X, 51);
+
+ processAxis(conv, EV_ABS, ABS_MT_SLOT, 1);
+ processAxis(conv, EV_ABS, ABS_MT_POSITION_X, 251);
+ processAxis(conv, EV_ABS, ABS_MT_TOOL_TYPE, MT_TOOL_FINGER);
+
+ std::list<NotifyArgs> args = processSync(conv);
+ ASSERT_EQ(2u, args.size());
+ EXPECT_THAT(std::get<NotifyMotionArgs>(args.front()),
+ AllOf(WithMotionAction(AMOTION_EVENT_ACTION_MOVE), WithPointerCount(1u)));
+ args.pop_front();
+ EXPECT_THAT(std::get<NotifyMotionArgs>(args.front()),
+ AllOf(WithMotionAction(AMOTION_EVENT_ACTION_POINTER_DOWN |
+ 1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT),
+ WithPointerCount(2u)));
+}
+
TEST_F(CapturedTouchpadEventConverterTest, TwoFingers_motionReportedCorrectly) {
CapturedTouchpadEventConverter conv = createConverter();