Expose flag to report palm detected by firmware to gestures-lib

We currently don't report palms detected by firmware to gestures-lib,
this leads to situations where gesture lib consideres a touch to be
lifted if  its reported as palm by firmware. This can also cause
unintended tap-to-click, and prevent bottom-right click from working as
intended.

BUG=b:302505955
TEST=atest libchrome-gestures_test

Change-Id: I172af6b3d46997bfefe68b4bede5c80d522bad3d
Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/gestures/+/4974106
Code-Coverage: Zoss <zoss-cl-coverage@prod.google.com>
Reviewed-by: Harry Cutts <hcutts@chromium.org>
Tested-by: Arpit Singh <arpitks@google.com>
Reviewed-by: Sean O'Brien <seobrien@chromium.org>
Commit-Queue: Harry Cutts <hcutts@chromium.org>
diff --git a/include/gestures.h b/include/gestures.h
index 83924cd..1a0a9b3 100644
--- a/include/gestures.h
+++ b/include/gestures.h
@@ -165,6 +165,10 @@
 // Describes a single contact on a touch surface. Generally, the fields have the
 // same meaning as the equivalent ABS_MT_... axis in the Linux evdev protocol.
 struct FingerState {
+  enum class ToolType {
+    kFinger = 0,
+    kPalm,
+  };
   // The large and small radii of the ellipse of the finger touching the pad.
   float touch_major, touch_minor;
 
@@ -188,6 +192,8 @@
   // A bit field of flags that are used internally by the library. (See the
   // GESTURES_FINGER_* constants.) Should be set to 0 on incoming FingerStates.
   unsigned flags;
+
+  ToolType tool_type = ToolType::kFinger;
 #ifdef __cplusplus
   bool NonFlagsEquals(const FingerState& that) const {
     return touch_major == that.touch_major &&
diff --git a/include/palm_classifying_filter_interpreter.h b/include/palm_classifying_filter_interpreter.h
index 4ef88bd..53fcafe 100644
--- a/include/palm_classifying_filter_interpreter.h
+++ b/include/palm_classifying_filter_interpreter.h
@@ -25,6 +25,7 @@
 // bottom area of the pad.
 
 class PalmClassifyingFilterInterpreter : public FilterInterpreter {
+  FRIEND_TEST(PalmClassifyingFilterInterpreterTest, ExternallyMarkedPalmTest);
   FRIEND_TEST(PalmClassifyingFilterInterpreterTest, PalmAtEdgeTest);
   FRIEND_TEST(PalmClassifyingFilterInterpreterTest, PalmReevaluateTest);
   FRIEND_TEST(PalmClassifyingFilterInterpreterTest, PalmTest);
diff --git a/src/palm_classifying_filter_interpreter.cc b/src/palm_classifying_filter_interpreter.cc
index 2dfe58e..1551f94 100644
--- a/src/palm_classifying_filter_interpreter.cc
+++ b/src/palm_classifying_filter_interpreter.cc
@@ -191,6 +191,11 @@
       pointing_.erase(fs.tracking_id);
       continue;
     }
+    // Mark externally reported palms
+    if(fs.tool_type == FingerState::ToolType::kPalm){
+      palm_.insert(fs.tracking_id);
+      pointing_.erase(fs.tracking_id);
+    }
   }
 
   if (hwstate.finger_cnt == 1 &&
diff --git a/src/palm_classifying_filter_interpreter_unittest.cc b/src/palm_classifying_filter_interpreter_unittest.cc
index b0a2ca6..6d667ad 100644
--- a/src/palm_classifying_filter_interpreter_unittest.cc
+++ b/src/palm_classifying_filter_interpreter_unittest.cc
@@ -12,6 +12,7 @@
 
 #include "include/gestures.h"
 #include "include/palm_classifying_filter_interpreter.h"
+#include "include/string_util.h"
 #include "include/unittest_util.h"
 #include "include/util.h"
 
@@ -119,6 +120,68 @@
   }
 }
 
+TEST(PalmClassifyingFilterInterpreterTest, ExternallyMarkedPalmTest) {
+  PalmClassifyingFilterInterpreterTestInterpreter* base_interpreter =
+    new PalmClassifyingFilterInterpreterTestInterpreter;
+  PalmClassifyingFilterInterpreter pci(nullptr, base_interpreter, nullptr);
+  HardwareProperties hwprops = {
+    .right = 1000,
+    .bottom = 1000,
+    .res_x = 500,
+    .res_y = 500,
+    .orientation_minimum = -1,
+    .orientation_maximum = 2,
+    .max_finger_cnt = 2,
+    .max_touch_cnt = 5,
+    .supports_t5r2 = 0,
+    .support_semi_mt = 0,
+    .is_button_pad = 1,
+    .has_wheel = 0,
+    .wheel_is_hi_res = 0,
+    .is_haptic_pad = 0,
+  };
+
+  TestInterpreterWrapper wrapper(&pci, &hwprops);
+
+  const float kPr = pci.palm_pressure_.val_ / 2;
+
+  FingerState finger_states[] = {
+    // TM, Tm, WM, Wm, Press, Orientation, X, Y, TrID, flags, ToolType
+    {0, 0, 0, 0, kPr, 0, 600, 500, 1, 0},
+    {0, 0, 0, 0, kPr, 0, 600, 500, 1, 0},
+    // mark the touch as palm
+    {0, 0, 0, 0, kPr, 0, 600, 500, 1, 0, FingerState::ToolType::kPalm},
+    {0, 0, 0, 0, kPr, 0, 600, 500, 1, 0, FingerState::ToolType::kPalm},
+  };
+  HardwareState hardware_state[] = {
+    // time, buttons, finger count, touch count, finger states pointer
+    make_hwstate(0.00, 0, 1, 1, &finger_states[0]),
+    make_hwstate(4.00, 0, 1, 1, &finger_states[1]),
+    make_hwstate(5.00, 0, 1, 1, &finger_states[2]),
+    make_hwstate(5.01, 0, 1, 1, &finger_states[3]),
+  };
+
+  for (size_t i = 0; i < arraysize(hardware_state); ++i) {
+    SCOPED_TRACE(StringPrintf("i = %zu", i));
+    if(i > 1) {
+      base_interpreter->expected_flags_ = GESTURES_FINGER_PALM;
+    }
+    else {
+      base_interpreter->expected_flags_ = 0;
+    }
+    wrapper.SyncInterpret(hardware_state[i], nullptr);
+    if (i > 1) {
+      // After the second frame finger is marked as palm
+      EXPECT_FALSE(SetContainsValue(pci.pointing_, 1));
+      EXPECT_TRUE(SetContainsValue(pci.palm_, 1));
+    }
+    else {
+      EXPECT_TRUE(SetContainsValue(pci.pointing_, 1));
+      EXPECT_FALSE(SetContainsValue(pci.palm_, 1));
+    }
+  }
+}
+
 TEST(PalmClassifyingFilterInterpreterTest, StationaryPalmTest) {
   PalmClassifyingFilterInterpreter pci(nullptr, nullptr, nullptr);
   HardwareProperties hwprops = {