Preserve multi-touch slot state when resetting input mappers

The existing pattern in InputReader is that when a mapper is reset, all
of its state is cleared and state of the buttons/axes is
queried through EventHub to rebuild the current state of the mapper.

This approach does not work for multi-touch devices, since there is no
way to query the current state of the contacts through the evdev
multi-touch protocol.

Since we cannot fully rebuild the current state of a multi-touch device,
we work around this limitation by never clearing the multi-touch state.

Bug: 248506674
Test: atest inputflinger_tests
Change-Id: Ic59d9fcb4e13fe262c422825c2485185004b719b
diff --git a/services/inputflinger/reader/mapper/MultiTouchInputMapper.cpp b/services/inputflinger/reader/mapper/MultiTouchInputMapper.cpp
index 8f5dc9b..047f068 100644
--- a/services/inputflinger/reader/mapper/MultiTouchInputMapper.cpp
+++ b/services/inputflinger/reader/mapper/MultiTouchInputMapper.cpp
@@ -38,13 +38,9 @@
                                             bool usingSlotsProtocol) {
     mUsingSlotsProtocol = usingSlotsProtocol;
     mHaveStylus = deviceContext.hasAbsoluteAxis(ABS_MT_TOOL_TYPE);
-
     mSlots = std::vector<Slot>(slotCount);
-}
 
-void MultiTouchMotionAccumulator::reset(InputDeviceContext& deviceContext) {
-    // Unfortunately there is no way to read the initial contents of the slots.
-    // So when we reset the accumulator, we must assume they are all zeroes.
+    mCurrentSlot = -1;
     if (mUsingSlotsProtocol) {
         // Query the driver for the current slot index and use it as the initial slot
         // before we start reading events from the device.  It is possible that the
@@ -56,22 +52,20 @@
         // This can cause the touch point to "jump", but at least there will be
         // no stuck touches.
         int32_t initialSlot;
-        status_t status = deviceContext.getAbsoluteAxisValue(ABS_MT_SLOT, &initialSlot);
-        if (status) {
-            ALOGD("Could not retrieve current multitouch slot index.  status=%d", status);
-            initialSlot = -1;
+        if (const auto status = deviceContext.getAbsoluteAxisValue(ABS_MT_SLOT, &initialSlot);
+            status == OK) {
+            mCurrentSlot = initialSlot;
+        } else {
+            ALOGD("Could not retrieve current multi-touch slot index. status=%d", status);
         }
-        clearSlots(initialSlot);
-    } else {
-        clearSlots(-1);
     }
 }
 
-void MultiTouchMotionAccumulator::clearSlots(int32_t initialSlot) {
+void MultiTouchMotionAccumulator::resetSlots() {
     for (Slot& slot : mSlots) {
         slot.clear();
     }
-    mCurrentSlot = initialSlot;
+    mCurrentSlot = -1;
 }
 
 void MultiTouchMotionAccumulator::process(const RawEvent* rawEvent) {
@@ -159,7 +153,7 @@
 
 void MultiTouchMotionAccumulator::finishSync() {
     if (!mUsingSlotsProtocol) {
-        clearSlots(-1);
+        resetSlots();
     }
 }
 
@@ -198,10 +192,12 @@
 MultiTouchInputMapper::~MultiTouchInputMapper() {}
 
 void MultiTouchInputMapper::reset(nsecs_t when) {
-    mMultiTouchMotionAccumulator.reset(getDeviceContext());
-
-    mPointerIdBits.clear();
-
+    // The evdev multi-touch protocol does not allow userspace applications to query the initial or
+    // current state of the pointers at any time. This means if we clear our accumulated state when
+    // resetting the input mapper, there's no way to rebuild the full initial state of the pointers.
+    // We can only wait for updates to all the pointers and axes. Rather than clearing the state and
+    // rebuilding the state from scratch, we work around this kernel API limitation by never
+    // fully clearing any state specific to the multi-touch protocol.
     TouchInputMapper::reset(when);
 }