TouchpadInputMapper: add dump method

This dumps the state from the gesture converter, and a list of gesture
properties, which is useful for debugging settings.

Bug: 251196347
Test: run dumpsys input with touchpad connected, check output
Change-Id: I036d0251b06489b645b883a239ff345a98448497
diff --git a/include/input/PrintTools.h b/include/input/PrintTools.h
index e24344b..ce87170 100644
--- a/include/input/PrintTools.h
+++ b/include/input/PrintTools.h
@@ -20,6 +20,7 @@
 #include <optional>
 #include <set>
 #include <string>
+#include <vector>
 
 namespace android {
 
@@ -28,6 +29,16 @@
     return std::to_string(v);
 }
 
+template <>
+inline std::string constToString(const bool& value) {
+    return value ? "true" : "false";
+}
+
+template <>
+inline std::string constToString(const std::vector<bool>::reference& value) {
+    return value ? "true" : "false";
+}
+
 inline std::string constToString(const std::string& s) {
     return s;
 }
@@ -70,6 +81,19 @@
     return out;
 }
 
+/**
+ * Convert a vector to a string. The values of the vector should be of a type supported by
+ * constToString.
+ */
+template <typename T>
+std::string dumpVector(std::vector<T> values) {
+    std::string dump = constToString(values[0]);
+    for (size_t i = 1; i < values.size(); i++) {
+        dump += ", " + constToString(values[i]);
+    }
+    return dump;
+}
+
 const char* toString(bool value);
 
 /**
@@ -81,4 +105,4 @@
  */
 std::string addLinePrefix(std::string str, const std::string& prefix);
 
-} // namespace android
\ No newline at end of file
+} // namespace android
diff --git a/services/inputflinger/reader/EventHub.cpp b/services/inputflinger/reader/EventHub.cpp
index 43b67ca..f7b38a1 100644
--- a/services/inputflinger/reader/EventHub.cpp
+++ b/services/inputflinger/reader/EventHub.cpp
@@ -515,6 +515,18 @@
     return deviceClasses & InputDeviceClass::JOYSTICK;
 }
 
+// --- RawAbsoluteAxisInfo ---
+
+std::ostream& operator<<(std::ostream& out, const RawAbsoluteAxisInfo& info) {
+    if (info.valid) {
+        out << "min=" << info.minValue << ", max=" << info.maxValue << ", flat=" << info.flat
+            << ", fuzz=" << info.fuzz << ", resolution=" << info.resolution;
+    } else {
+        out << "unknown range";
+    }
+    return out;
+}
+
 // --- EventHub::Device ---
 
 EventHub::Device::Device(int fd, int32_t id, std::string path, InputDeviceIdentifier identifier,
diff --git a/services/inputflinger/reader/include/EventHub.h b/services/inputflinger/reader/include/EventHub.h
index a3ecf41..86acadb 100644
--- a/services/inputflinger/reader/include/EventHub.h
+++ b/services/inputflinger/reader/include/EventHub.h
@@ -19,6 +19,8 @@
 #include <bitset>
 #include <climits>
 #include <filesystem>
+#include <ostream>
+#include <string>
 #include <unordered_map>
 #include <utility>
 #include <vector>
@@ -77,6 +79,8 @@
     inline void clear() { *this = RawAbsoluteAxisInfo(); }
 };
 
+std::ostream& operator<<(std::ostream& out, const RawAbsoluteAxisInfo& info);
+
 /*
  * Input device classes.
  */
diff --git a/services/inputflinger/reader/mapper/InputMapper.cpp b/services/inputflinger/reader/mapper/InputMapper.cpp
index 8e3539c..ba2ea99 100644
--- a/services/inputflinger/reader/mapper/InputMapper.cpp
+++ b/services/inputflinger/reader/mapper/InputMapper.cpp
@@ -18,6 +18,8 @@
 
 #include "InputMapper.h"
 
+#include <sstream>
+
 #include "InputDevice.h"
 #include "input/PrintTools.h"
 
@@ -120,12 +122,9 @@
 
 void InputMapper::dumpRawAbsoluteAxisInfo(std::string& dump, const RawAbsoluteAxisInfo& axis,
                                           const char* name) {
-    if (axis.valid) {
-        dump += StringPrintf(INDENT4 "%s: min=%d, max=%d, flat=%d, fuzz=%d, resolution=%d\n", name,
-                             axis.minValue, axis.maxValue, axis.flat, axis.fuzz, axis.resolution);
-    } else {
-        dump += StringPrintf(INDENT4 "%s: unknown range\n", name);
-    }
+    std::stringstream out;
+    out << INDENT4 << name << ": " << axis << "\n";
+    dump += out.str();
 }
 
 void InputMapper::dumpStylusState(std::string& dump, const StylusState& state) {
diff --git a/services/inputflinger/reader/mapper/TouchpadInputMapper.cpp b/services/inputflinger/reader/mapper/TouchpadInputMapper.cpp
index 89ba07e..b6313a1 100644
--- a/services/inputflinger/reader/mapper/TouchpadInputMapper.cpp
+++ b/services/inputflinger/reader/mapper/TouchpadInputMapper.cpp
@@ -19,6 +19,7 @@
 #include <optional>
 
 #include <android/input.h>
+#include <input/PrintTools.h>
 #include <linux/input-event-codes.h>
 #include <log/log_main.h>
 #include "TouchCursorInputMapperCommon.h"
@@ -124,6 +125,14 @@
     return AINPUT_SOURCE_MOUSE | AINPUT_SOURCE_TOUCHPAD;
 }
 
+void TouchpadInputMapper::dump(std::string& dump) {
+    dump += INDENT2 "Touchpad Input Mapper:\n";
+    dump += INDENT3 "Gesture converter:\n";
+    dump += addLinePrefix(mGestureConverter.dump(), INDENT4);
+    dump += INDENT3 "Gesture properties:\n";
+    dump += addLinePrefix(mPropertyProvider.dump(), INDENT4);
+}
+
 std::list<NotifyArgs> TouchpadInputMapper::configure(nsecs_t when,
                                                      const InputReaderConfiguration* config,
                                                      uint32_t changes) {
diff --git a/services/inputflinger/reader/mapper/TouchpadInputMapper.h b/services/inputflinger/reader/mapper/TouchpadInputMapper.h
index 8ffc8a0..d693bca 100644
--- a/services/inputflinger/reader/mapper/TouchpadInputMapper.h
+++ b/services/inputflinger/reader/mapper/TouchpadInputMapper.h
@@ -41,6 +41,8 @@
     ~TouchpadInputMapper();
 
     uint32_t getSources() const override;
+    void dump(std::string& dump) override;
+
     [[nodiscard]] std::list<NotifyArgs> configure(nsecs_t when,
                                                   const InputReaderConfiguration* config,
                                                   uint32_t changes) override;
diff --git a/services/inputflinger/reader/mapper/gestures/GestureConverter.cpp b/services/inputflinger/reader/mapper/gestures/GestureConverter.cpp
index 11ffd28..561b1f8 100644
--- a/services/inputflinger/reader/mapper/gestures/GestureConverter.cpp
+++ b/services/inputflinger/reader/mapper/gestures/GestureConverter.cpp
@@ -16,7 +16,11 @@
 
 #include "gestures/GestureConverter.h"
 
+#include <sstream>
+
+#include <android-base/stringprintf.h>
 #include <android/input.h>
+#include <ftl/enum.h>
 #include <linux/input-event-codes.h>
 #include <log/log_main.h>
 
@@ -55,6 +59,18 @@
     deviceContext.getAbsoluteAxisInfo(ABS_MT_POSITION_Y, &mYAxisInfo);
 }
 
+std::string GestureConverter::dump() const {
+    std::stringstream out;
+    out << "Orientation: " << ftl::enum_string(mOrientation) << "\n";
+    out << "Axis info:\n";
+    out << "  X: " << mXAxisInfo << "\n";
+    out << "  Y: " << mYAxisInfo << "\n";
+    out << StringPrintf("Button state: 0x%08x\n", mButtonState);
+    out << "Down time: " << mDownTime << "\n";
+    out << "Current classification: " << ftl::enum_string(mCurrentClassification) << "\n";
+    return out.str();
+}
+
 void GestureConverter::reset() {
     mButtonState = 0;
 }
diff --git a/services/inputflinger/reader/mapper/gestures/GestureConverter.h b/services/inputflinger/reader/mapper/gestures/GestureConverter.h
index 8e8e3d9..2ec5841 100644
--- a/services/inputflinger/reader/mapper/gestures/GestureConverter.h
+++ b/services/inputflinger/reader/mapper/gestures/GestureConverter.h
@@ -40,6 +40,8 @@
     GestureConverter(InputReaderContext& readerContext, const InputDeviceContext& deviceContext,
                      int32_t deviceId);
 
+    std::string dump() const;
+
     void setOrientation(ui::Rotation orientation) { mOrientation = orientation; }
     void reset();
 
diff --git a/services/inputflinger/reader/mapper/gestures/PropertyProvider.cpp b/services/inputflinger/reader/mapper/gestures/PropertyProvider.cpp
index 2e12854..cd18cd3 100644
--- a/services/inputflinger/reader/mapper/gestures/PropertyProvider.cpp
+++ b/services/inputflinger/reader/mapper/gestures/PropertyProvider.cpp
@@ -21,7 +21,9 @@
 #include <algorithm>
 #include <utility>
 
+#include <android-base/stringprintf.h>
 #include <ftl/enum.h>
+#include <input/PrintTools.h>
 #include <log/log_main.h>
 
 namespace android {
@@ -74,6 +76,14 @@
     return mProperties.at(name);
 }
 
+std::string PropertyProvider::dump() const {
+    std::string dump;
+    for (const auto& [name, property] : mProperties) {
+        dump += property.dump() + "\n";
+    }
+    return dump;
+}
+
 GesturesProp* PropertyProvider::createIntArrayProperty(const std::string name, int* loc,
                                                        size_t count, const int* init) {
     const auto [it, inserted] =
@@ -124,6 +134,31 @@
     *(std::get<const char**>(mDataPointer)) = initialValue;
 }
 
+std::string GesturesProp::dump() const {
+    using android::base::StringPrintf;
+    std::string type, values;
+    switch (mDataPointer.index()) {
+        case 0:
+            type = "integer";
+            values = android::dumpVector(getIntValues());
+            break;
+        case 1:
+            type = "boolean";
+            values = android::dumpVector(getBoolValues());
+            break;
+        case 2:
+            type = "string";
+            values = getStringValue();
+            break;
+        case 3:
+            type = "real";
+            values = android::dumpVector(getRealValues());
+            break;
+    }
+    std::string typeAndSize = mCount == 1 ? type : std::to_string(mCount) + " " + type + "s";
+    return StringPrintf("%s (%s): %s", mName.c_str(), typeAndSize.c_str(), values.c_str());
+}
+
 void GesturesProp::registerHandlers(void* handlerData, GesturesPropGetHandler getter,
                                     GesturesPropSetHandler setter) {
     mHandlerData = handlerData;
diff --git a/services/inputflinger/reader/mapper/gestures/PropertyProvider.h b/services/inputflinger/reader/mapper/gestures/PropertyProvider.h
index 4bebd46..c21260f 100644
--- a/services/inputflinger/reader/mapper/gestures/PropertyProvider.h
+++ b/services/inputflinger/reader/mapper/gestures/PropertyProvider.h
@@ -33,6 +33,7 @@
 public:
     bool hasProperty(const std::string name) const;
     GesturesProp& getProperty(const std::string name);
+    std::string dump() const;
 
     // Methods to be called by the gestures library:
     GesturesProp* createIntArrayProperty(const std::string name, int* loc, size_t count,
@@ -62,6 +63,8 @@
     GesturesProp(std::string name, T* dataPointer, size_t count, const T* initialValues);
     GesturesProp(std::string name, const char** dataPointer, const char* const initialValue);
 
+    std::string dump() const;
+
     std::string getName() const { return mName; }
 
     size_t getCount() const { return mCount; }