diff options
author | 2023-03-13 11:32:06 +0000 | |
---|---|---|
committer | 2023-03-13 11:32:29 +0000 | |
commit | 2b67ff1bda2323353b52c2762f0f0296b68c04bf (patch) | |
tree | 639f89ca49253a63fb01a227e1a48129ff7c6d4a | |
parent | a53cb97af2b4cbb247094d6be93583712dbee3c4 (diff) |
Revert^2 "Support touchpad gesture properties in IDC files"
a53cb97af2b4cbb247094d6be93583712dbee3c4
Change-Id: I5463f938665212362b8780e1c646a4b2bf8ad10a
-rw-r--r-- | include/input/PropertyMap.h | 7 | ||||
-rw-r--r-- | libs/input/Android.bp | 1 | ||||
-rw-r--r-- | libs/input/PropertyMap.cpp | 29 | ||||
-rw-r--r-- | services/inputflinger/reader/mapper/TouchpadInputMapper.cpp | 6 | ||||
-rw-r--r-- | services/inputflinger/reader/mapper/gestures/PropertyProvider.cpp | 76 | ||||
-rw-r--r-- | services/inputflinger/reader/mapper/gestures/PropertyProvider.h | 6 | ||||
-rw-r--r-- | services/inputflinger/tests/PropertyProvider_test.cpp | 65 | ||||
-rw-r--r-- | services/inputflinger/tests/TestConstants.h | 4 |
8 files changed, 194 insertions, 0 deletions
diff --git a/include/input/PropertyMap.h b/include/input/PropertyMap.h index 28e4816afe..18ce16df36 100644 --- a/include/input/PropertyMap.h +++ b/include/input/PropertyMap.h @@ -18,7 +18,10 @@ #include <android-base/result.h> #include <utils/Tokenizer.h> + +#include <string> #include <unordered_map> +#include <unordered_set> namespace android { @@ -57,6 +60,9 @@ public: */ void addProperty(const std::string& key, const std::string& value); + /* Returns a set of all property keys starting with the given prefix. */ + std::unordered_set<std::string> getKeysWithPrefix(const std::string& prefix) const; + /* Gets the value of a property and parses it. * Returns true and sets outValue if the key was found and its value was parsed successfully. * Otherwise returns false and does not modify outValue. (Also logs a warning.) @@ -65,6 +71,7 @@ public: bool tryGetProperty(const std::string& key, bool& outValue) const; bool tryGetProperty(const std::string& key, int32_t& outValue) const; bool tryGetProperty(const std::string& key, float& outValue) const; + bool tryGetProperty(const std::string& key, double& outValue) const; /* Adds all values from the specified property map. */ void addAll(const PropertyMap* map); diff --git a/libs/input/Android.bp b/libs/input/Android.bp index f38dd98428..869458c407 100644 --- a/libs/input/Android.bp +++ b/libs/input/Android.bp @@ -167,6 +167,7 @@ cc_library { cc_defaults { name: "libinput_fuzz_defaults", + cpp_std: "c++20", host_supported: true, shared_libs: [ "libutils", diff --git a/libs/input/PropertyMap.cpp b/libs/input/PropertyMap.cpp index ed9ac9fc72..9a4f10b21d 100644 --- a/libs/input/PropertyMap.cpp +++ b/libs/input/PropertyMap.cpp @@ -16,6 +16,8 @@ #define LOG_TAG "PropertyMap" +#include <cstdlib> + #include <input/PropertyMap.h> #include <log/log.h> @@ -44,6 +46,16 @@ void PropertyMap::addProperty(const std::string& key, const std::string& value) mProperties.emplace(key, value); } +std::unordered_set<std::string> PropertyMap::getKeysWithPrefix(const std::string& prefix) const { + std::unordered_set<std::string> keys; + for (const auto& [key, _] : mProperties) { + if (key.starts_with(prefix)) { + keys.insert(key); + } + } + return keys; +} + bool PropertyMap::hasProperty(const std::string& key) const { return mProperties.find(key) != mProperties.end(); } @@ -102,6 +114,23 @@ bool PropertyMap::tryGetProperty(const std::string& key, float& outValue) const return true; } +bool PropertyMap::tryGetProperty(const std::string& key, double& outValue) const { + std::string stringValue; + if (!tryGetProperty(key, stringValue) || stringValue.length() == 0) { + return false; + } + + char* end; + double value = strtod(stringValue.c_str(), &end); + if (*end != '\0') { + ALOGW("Property key '%s' has invalid value '%s'. Expected a double.", key.c_str(), + stringValue.c_str()); + return false; + } + outValue = value; + return true; +} + void PropertyMap::addAll(const PropertyMap* map) { for (const auto& [key, value] : map->mProperties) { mProperties.emplace(key, value); diff --git a/services/inputflinger/reader/mapper/TouchpadInputMapper.cpp b/services/inputflinger/reader/mapper/TouchpadInputMapper.cpp index d3af402153..330976719d 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 @@ void TouchpadInputMapper::dump(std::string& dump) { 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 089f45a4e6..3d883389c9 100644 --- a/services/inputflinger/reader/mapper/gestures/PropertyProvider.cpp +++ b/services/inputflinger/reader/mapper/gestures/PropertyProvider.cpp @@ -84,6 +84,29 @@ std::string PropertyProvider::dump() const { 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 @@ void GesturesProp::setRealValues(const std::vector<double>& values) { 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 50451a3929..c7e0858c6d 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 @@ public: 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 @@ public: // 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 42a6a9f4b9..8a40e78b89 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 @@ TEST_F(PropertyProviderTest, Free) { 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 27881f6f49..ad48b0fbe0 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; |