Revert^2 "Support touchpad gesture properties in IDC files"

a53cb97af2b4cbb247094d6be93583712dbee3c4

Change-Id: I5463f938665212362b8780e1c646a4b2bf8ad10a
diff --git a/services/inputflinger/reader/mapper/TouchpadInputMapper.cpp b/services/inputflinger/reader/mapper/TouchpadInputMapper.cpp
index d3af402..3309767 100644
--- a/services/inputflinger/reader/mapper/TouchpadInputMapper.cpp
+++ b/services/inputflinger/reader/mapper/TouchpadInputMapper.cpp
@@ -20,6 +20,7 @@
 #include <optional>
 
 #include <android/input.h>
+#include <ftl/enum.h>
 #include <input/PrintTools.h>
 #include <linux/input-event-codes.h>
 #include <log/log_main.h>
@@ -216,6 +217,11 @@
 std::list<NotifyArgs> TouchpadInputMapper::configure(nsecs_t when,
                                                      const InputReaderConfiguration* config,
                                                      uint32_t changes) {
+    if (!changes) {
+        // First time configuration
+        mPropertyProvider.loadPropertiesFromIdcFile(getDeviceContext().getConfiguration());
+    }
+
     if (!changes || (changes & InputReaderConfiguration::CHANGE_DISPLAY_INFO)) {
         std::optional<int32_t> displayId = mPointerController->getDisplayId();
         ui::Rotation orientation = ui::ROTATION_0;
diff --git a/services/inputflinger/reader/mapper/gestures/PropertyProvider.cpp b/services/inputflinger/reader/mapper/gestures/PropertyProvider.cpp
index 089f45a..3d88338 100644
--- a/services/inputflinger/reader/mapper/gestures/PropertyProvider.cpp
+++ b/services/inputflinger/reader/mapper/gestures/PropertyProvider.cpp
@@ -84,6 +84,29 @@
     return dump;
 }
 
+void PropertyProvider::loadPropertiesFromIdcFile(const PropertyMap& idcProperties) {
+    // For compatibility with the configuration file syntax, gesture property names in IDC files are
+    // prefixed with "gestureProp." and have spaces replaced by underscores. So, for example, the
+    // configuration key "gestureProp.Palm_Width" refers to the "Palm Width" property.
+    const std::string gesturePropPrefix = "gestureProp.";
+    for (const std::string key : idcProperties.getKeysWithPrefix(gesturePropPrefix)) {
+        std::string propertyName = key.substr(gesturePropPrefix.length());
+        for (size_t i = 0; i < propertyName.length(); i++) {
+            if (propertyName[i] == '_') {
+                propertyName[i] = ' ';
+            }
+        }
+
+        auto it = mProperties.find(propertyName);
+        if (it != mProperties.end()) {
+            it->second.trySetFromIdcProperty(idcProperties, key);
+        } else {
+            ALOGE("Gesture property \"%s\" specified in IDC file does not exist for this device.",
+                  propertyName.c_str());
+        }
+    }
+}
+
 GesturesProp* PropertyProvider::createIntArrayProperty(const std::string& name, int* loc,
                                                        size_t count, const int* init) {
     const auto [it, inserted] =
@@ -211,6 +234,59 @@
     setValues(std::get<double*>(mDataPointer), values);
 }
 
+namespace {
+
+// Helper to std::visit with lambdas.
+template <typename... V>
+struct Visitor : V... {};
+// explicit deduction guide (not needed as of C++20)
+template <typename... V>
+Visitor(V...) -> Visitor<V...>;
+
+} // namespace
+
+void GesturesProp::trySetFromIdcProperty(const android::PropertyMap& idcProperties,
+                                         const std::string& propertyName) {
+    if (mCount != 1) {
+        ALOGE("Gesture property \"%s\" is an array, and so cannot be set in an IDC file.",
+              mName.c_str());
+        return;
+    }
+    bool parsedSuccessfully = false;
+    Visitor setVisitor{
+            [&](int*) {
+                int32_t value;
+                parsedSuccessfully = idcProperties.tryGetProperty(propertyName, value);
+                if (parsedSuccessfully) {
+                    setIntValues({value});
+                }
+            },
+            [&](GesturesPropBool*) {
+                bool value;
+                parsedSuccessfully = idcProperties.tryGetProperty(propertyName, value);
+                if (parsedSuccessfully) {
+                    setBoolValues({value});
+                }
+            },
+            [&](double*) {
+                double value;
+                parsedSuccessfully = idcProperties.tryGetProperty(propertyName, value);
+                if (parsedSuccessfully) {
+                    setRealValues({value});
+                }
+            },
+            [&](const char**) {
+                ALOGE("Gesture property \"%s\" is a string, and so cannot be set in an IDC file.",
+                      mName.c_str());
+            },
+    };
+    std::visit(setVisitor, mDataPointer);
+
+    ALOGE_IF(!parsedSuccessfully, "Gesture property \"%s\" could set due to a type mismatch.",
+             mName.c_str());
+    return;
+}
+
 template <typename T, typename U>
 const std::vector<T> GesturesProp::getValues(U* dataPointer) const {
     if (mGetter != nullptr) {
diff --git a/services/inputflinger/reader/mapper/gestures/PropertyProvider.h b/services/inputflinger/reader/mapper/gestures/PropertyProvider.h
index 50451a3..c7e0858 100644
--- a/services/inputflinger/reader/mapper/gestures/PropertyProvider.h
+++ b/services/inputflinger/reader/mapper/gestures/PropertyProvider.h
@@ -22,6 +22,7 @@
 #include <vector>
 
 #include "include/gestures.h"
+#include "input/PropertyMap.h"
 
 namespace android {
 
@@ -35,6 +36,8 @@
     GesturesProp& getProperty(const std::string& name);
     std::string dump() const;
 
+    void loadPropertiesFromIdcFile(const PropertyMap& idcProperties);
+
     // Methods to be called by the gestures library:
     GesturesProp* createIntArrayProperty(const std::string& name, int* loc, size_t count,
                                          const int* init);
@@ -83,6 +86,9 @@
     // Setting string values isn't supported since we don't have a use case yet and the memory
     // management adds additional complexity.
 
+    void trySetFromIdcProperty(const android::PropertyMap& idcProperties,
+                               const std::string& propertyName);
+
 private:
     // Two type parameters are required for these methods, rather than one, due to the gestures
     // library using its own bool type.
diff --git a/services/inputflinger/tests/PropertyProvider_test.cpp b/services/inputflinger/tests/PropertyProvider_test.cpp
index 42a6a9f..8a40e78 100644
--- a/services/inputflinger/tests/PropertyProvider_test.cpp
+++ b/services/inputflinger/tests/PropertyProvider_test.cpp
@@ -18,6 +18,7 @@
 #include <gmock/gmock.h>
 #include <gtest/gtest.h>
 
+#include "TestConstants.h"
 #include "include/gestures.h"
 
 namespace android {
@@ -283,4 +284,68 @@
     EXPECT_FALSE(mProvider.hasProperty("Foo"));
 }
 
+class PropertyProviderIdcLoadingTest : public testing::Test {
+protected:
+    void SetUp() override {
+        int initialInt = 0;
+        GesturesPropBool initialBool = false;
+        double initialReal = 0.0;
+        gesturePropProvider.create_int_fn(&mProvider, "An Integer", &mIntData, 1, &initialInt);
+        gesturePropProvider.create_bool_fn(&mProvider, "A Boolean", &mBoolData, 1, &initialBool);
+        gesturePropProvider.create_real_fn(&mProvider, "A Real", &mRealData, 1, &initialReal);
+    }
+
+    PropertyProvider mProvider;
+
+    int mIntData;
+    GesturesPropBool mBoolData;
+    double mRealData;
+};
+
+TEST_F(PropertyProviderIdcLoadingTest, AllCorrect) {
+    PropertyMap idcProps;
+    idcProps.addProperty("gestureProp.An_Integer", "42");
+    idcProps.addProperty("gestureProp.A_Boolean", "1");
+    idcProps.addProperty("gestureProp.A_Real", "3.14159");
+
+    mProvider.loadPropertiesFromIdcFile(idcProps);
+    EXPECT_THAT(mProvider.getProperty("An Integer").getIntValues(), ElementsAre(42));
+    EXPECT_THAT(mProvider.getProperty("A Boolean").getBoolValues(), ElementsAre(true));
+    EXPECT_NEAR(mProvider.getProperty("A Real").getRealValues()[0], 3.14159, EPSILON);
+}
+
+TEST_F(PropertyProviderIdcLoadingTest, InvalidPropsIgnored) {
+    int intArrayData[2];
+    int initialInts[2] = {0, 1};
+    gesturePropProvider.create_int_fn(&mProvider, "Two Integers", intArrayData, 2, initialInts);
+
+    PropertyMap idcProps;
+    // Wrong type
+    idcProps.addProperty("gestureProp.An_Integer", "37.25");
+    // Wrong size
+    idcProps.addProperty("gestureProp.Two_Integers", "42");
+    // Doesn't exist
+    idcProps.addProperty("gestureProp.Some_Nonexistent_Property", "1");
+    // A valid assignment that should still be applied despite the others being invalid
+    idcProps.addProperty("gestureProp.A_Real", "3.14159");
+
+    mProvider.loadPropertiesFromIdcFile(idcProps);
+    EXPECT_THAT(mProvider.getProperty("An Integer").getIntValues(), ElementsAre(0));
+    EXPECT_THAT(mProvider.getProperty("Two Integers").getIntValues(), ElementsAre(0, 1));
+    EXPECT_FALSE(mProvider.hasProperty("Some Nonexistent Property"));
+    EXPECT_NEAR(mProvider.getProperty("A Real").getRealValues()[0], 3.14159, EPSILON);
+}
+
+TEST_F(PropertyProviderIdcLoadingTest, FunkyName) {
+    int data;
+    int initialData = 0;
+    gesturePropProvider.create_int_fn(&mProvider, "  I lOvE sNAKes ", &data, 1, &initialData);
+
+    PropertyMap idcProps;
+    idcProps.addProperty("gestureProp.__I_lOvE_sNAKes_", "42");
+
+    mProvider.loadPropertiesFromIdcFile(idcProps);
+    EXPECT_THAT(mProvider.getProperty("  I lOvE sNAKes ").getIntValues(), ElementsAre(42));
+}
+
 } // namespace android
diff --git a/services/inputflinger/tests/TestConstants.h b/services/inputflinger/tests/TestConstants.h
index 27881f6..ad48b0f 100644
--- a/services/inputflinger/tests/TestConstants.h
+++ b/services/inputflinger/tests/TestConstants.h
@@ -16,6 +16,10 @@
 
 #pragma once
 
+#include <chrono>
+
+#include <utils/Timers.h>
+
 namespace android {
 
 using std::chrono_literals::operator""ms;