Ignore touchpad contacts that are marked as palms

Some touchpads detect palms in their firmware but continue to report
them, just marking them as palms (e.g. with MT_TOOL_PALM). Since the
Gestures library has no mechanism for marking incoming touches as
pre-detected palms, for now just completely ignore palms reported by the
touchpad.

Bug: 270041770
Test: atest inputflinger_tests:HardwareStateConverterTest
Test: limited manual testing
Change-Id: I7d898889d4bf4e8068194d22150c02a69b59c435
diff --git a/services/inputflinger/reader/mapper/gestures/HardwareStateConverter.cpp b/services/inputflinger/reader/mapper/gestures/HardwareStateConverter.cpp
index 2e175b8..c091a51 100644
--- a/services/inputflinger/reader/mapper/gestures/HardwareStateConverter.cpp
+++ b/services/inputflinger/reader/mapper/gestures/HardwareStateConverter.cpp
@@ -80,18 +80,32 @@
     schs.fingers.clear();
     for (size_t i = 0; i < mMotionAccumulator.getSlotCount(); i++) {
         MultiTouchMotionAccumulator::Slot slot = mMotionAccumulator.getSlot(i);
-        if (slot.isInUse()) {
-            FingerState& fingerState = schs.fingers.emplace_back();
-            fingerState = {};
-            fingerState.touch_major = slot.getTouchMajor();
-            fingerState.touch_minor = slot.getTouchMinor();
-            fingerState.width_major = slot.getToolMajor();
-            fingerState.width_minor = slot.getToolMinor();
-            fingerState.pressure = slot.getPressure();
-            fingerState.orientation = slot.getOrientation();
-            fingerState.position_x = slot.getX();
-            fingerState.position_y = slot.getY();
-            fingerState.tracking_id = slot.getTrackingId();
+        if (!slot.isInUse()) {
+            continue;
+        }
+        // Some touchpads continue to report contacts even after they've identified them as palms.
+        // We want to exclude these contacts from the HardwareStates, but still need to report a
+        // tracking ID of -1 if a finger turns into a palm.
+        const bool isPalm = slot.getToolType() == AMOTION_EVENT_TOOL_TYPE_PALM;
+        if (isPalm && mFingerSlots.find(i) == mFingerSlots.end()) {
+            continue;
+        }
+
+        FingerState& fingerState = schs.fingers.emplace_back();
+        fingerState = {};
+        fingerState.touch_major = slot.getTouchMajor();
+        fingerState.touch_minor = slot.getTouchMinor();
+        fingerState.width_major = slot.getToolMajor();
+        fingerState.width_minor = slot.getToolMinor();
+        fingerState.pressure = slot.getPressure();
+        fingerState.orientation = slot.getOrientation();
+        fingerState.position_x = slot.getX();
+        fingerState.position_y = slot.getY();
+        fingerState.tracking_id = isPalm ? -1 : slot.getTrackingId();
+        if (fingerState.tracking_id == -1) {
+            mFingerSlots.erase(i);
+        } else {
+            mFingerSlots.insert(i);
         }
     }
     schs.state.fingers = schs.fingers.data();
@@ -103,6 +117,7 @@
 void HardwareStateConverter::reset() {
     mCursorButtonAccumulator.reset(mDeviceContext);
     mTouchButtonAccumulator.reset();
+    mFingerSlots.clear();
     mMscTimestamp = 0;
 }
 
diff --git a/services/inputflinger/reader/mapper/gestures/HardwareStateConverter.h b/services/inputflinger/reader/mapper/gestures/HardwareStateConverter.h
index 8831299..d6787b7 100644
--- a/services/inputflinger/reader/mapper/gestures/HardwareStateConverter.h
+++ b/services/inputflinger/reader/mapper/gestures/HardwareStateConverter.h
@@ -17,6 +17,7 @@
 #pragma once
 
 #include <optional>
+#include <set>
 
 #include <utils/Timers.h>
 
@@ -53,6 +54,7 @@
     MultiTouchMotionAccumulator mMotionAccumulator;
     TouchButtonAccumulator mTouchButtonAccumulator;
     int32_t mMscTimestamp = 0;
+    std::set<size_t> mFingerSlots;
 };
 
 } // namespace android
diff --git a/services/inputflinger/tests/HardwareStateConverter_test.cpp b/services/inputflinger/tests/HardwareStateConverter_test.cpp
index 7921881..36b9bab 100644
--- a/services/inputflinger/tests/HardwareStateConverter_test.cpp
+++ b/services/inputflinger/tests/HardwareStateConverter_test.cpp
@@ -191,6 +191,68 @@
     EXPECT_EQ(0u, finger2.flags);
 }
 
+TEST_F(HardwareStateConverterTest, OnePalm) {
+    const nsecs_t time = ARBITRARY_TIME;
+    InputDeviceContext deviceContext(*mDevice, EVENTHUB_ID);
+    HardwareStateConverter conv(deviceContext);
+
+    processAxis(conv, time, EV_ABS, ABS_MT_SLOT, 0);
+    processAxis(conv, time, EV_ABS, ABS_MT_TOOL_TYPE, MT_TOOL_PALM);
+    processAxis(conv, time, EV_ABS, ABS_MT_TRACKING_ID, 123);
+    processAxis(conv, time, EV_ABS, ABS_MT_POSITION_X, 50);
+    processAxis(conv, time, EV_ABS, ABS_MT_POSITION_Y, 100);
+
+    processAxis(conv, time, EV_KEY, BTN_TOUCH, 1);
+    std::optional<SelfContainedHardwareState> schs = processSync(conv, time);
+    ASSERT_TRUE(schs.has_value());
+    EXPECT_EQ(0, schs->state.finger_cnt);
+}
+
+TEST_F(HardwareStateConverterTest, OneFingerTurningIntoAPalm) {
+    const nsecs_t time = ARBITRARY_TIME;
+    InputDeviceContext deviceContext(*mDevice, EVENTHUB_ID);
+    HardwareStateConverter conv(deviceContext);
+
+    processAxis(conv, time, EV_ABS, ABS_MT_SLOT, 0);
+    processAxis(conv, time, EV_ABS, ABS_MT_TOOL_TYPE, MT_TOOL_FINGER);
+    processAxis(conv, time, EV_ABS, ABS_MT_TRACKING_ID, 123);
+    processAxis(conv, time, EV_ABS, ABS_MT_POSITION_X, 50);
+    processAxis(conv, time, EV_ABS, ABS_MT_POSITION_Y, 100);
+
+    processAxis(conv, time, EV_KEY, BTN_TOUCH, 1);
+
+    std::optional<SelfContainedHardwareState> schs = processSync(conv, time);
+    ASSERT_TRUE(schs.has_value());
+    EXPECT_EQ(1, schs->state.finger_cnt);
+
+    processAxis(conv, time, EV_ABS, ABS_MT_TOOL_TYPE, MT_TOOL_PALM);
+    processAxis(conv, time, EV_ABS, ABS_MT_POSITION_X, 51);
+    processAxis(conv, time, EV_ABS, ABS_MT_POSITION_Y, 99);
+
+    schs = processSync(conv, time);
+    ASSERT_TRUE(schs.has_value());
+    ASSERT_EQ(1, schs->state.finger_cnt);
+    EXPECT_EQ(-1, schs->state.fingers[0].tracking_id);
+
+    processAxis(conv, time, EV_ABS, ABS_MT_POSITION_X, 53);
+    processAxis(conv, time, EV_ABS, ABS_MT_POSITION_Y, 97);
+
+    schs = processSync(conv, time);
+    ASSERT_TRUE(schs.has_value());
+    EXPECT_EQ(0, schs->state.finger_cnt);
+
+    processAxis(conv, time, EV_ABS, ABS_MT_TOOL_TYPE, MT_TOOL_FINGER);
+    processAxis(conv, time, EV_ABS, ABS_MT_POSITION_X, 55);
+    processAxis(conv, time, EV_ABS, ABS_MT_POSITION_Y, 95);
+    schs = processSync(conv, time);
+    ASSERT_TRUE(schs.has_value());
+    ASSERT_EQ(1, schs->state.finger_cnt);
+    const FingerState& newFinger = schs->state.fingers[0];
+    EXPECT_EQ(123, newFinger.tracking_id);
+    EXPECT_NEAR(55, newFinger.position_x, EPSILON);
+    EXPECT_NEAR(95, newFinger.position_y, EPSILON);
+}
+
 TEST_F(HardwareStateConverterTest, ButtonPressed) {
     const nsecs_t time = ARBITRARY_TIME;
     InputDeviceContext deviceContext(*mDevice, EVENTHUB_ID);