• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2023 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #include "../Macros.h"
18 
19 #include "gestures/PropertyProvider.h"
20 
21 #include <algorithm>
22 #include <optional>
23 #include <utility>
24 
25 #include <android-base/stringprintf.h>
26 #include <ftl/enum.h>
27 #include <input/PrintTools.h>
28 #include <log/log_main.h>
29 
30 namespace android {
31 
32 namespace {
33 
createInt(void * data,const char * name,int * loc,size_t count,const int * init)34 GesturesProp* createInt(void* data, const char* name, int* loc, size_t count, const int* init) {
35     return static_cast<PropertyProvider*>(data)->createIntArrayProperty(name, loc, count, init);
36 }
37 
createBool(void * data,const char * name,GesturesPropBool * loc,size_t count,const GesturesPropBool * init)38 GesturesProp* createBool(void* data, const char* name, GesturesPropBool* loc, size_t count,
39                          const GesturesPropBool* init) {
40     return static_cast<PropertyProvider*>(data)->createBoolArrayProperty(name, loc, count, init);
41 }
42 
createString(void * data,const char * name,const char ** loc,const char * const init)43 GesturesProp* createString(void* data, const char* name, const char** loc, const char* const init) {
44     return static_cast<PropertyProvider*>(data)->createStringProperty(name, loc, init);
45 }
46 
createReal(void * data,const char * name,double * loc,size_t count,const double * init)47 GesturesProp* createReal(void* data, const char* name, double* loc, size_t count,
48                          const double* init) {
49     return static_cast<PropertyProvider*>(data)->createRealArrayProperty(name, loc, count, init);
50 }
51 
registerHandlers(void * data,GesturesProp * prop,void * handlerData,GesturesPropGetHandler getter,GesturesPropSetHandler setter)52 void registerHandlers(void* data, GesturesProp* prop, void* handlerData,
53                       GesturesPropGetHandler getter, GesturesPropSetHandler setter) {
54     prop->registerHandlers(handlerData, getter, setter);
55 }
56 
freeProperty(void * data,GesturesProp * prop)57 void freeProperty(void* data, GesturesProp* prop) {
58     static_cast<PropertyProvider*>(data)->freeProperty(prop);
59 }
60 
61 } // namespace
62 
63 const GesturesPropProvider gesturePropProvider = {
64         .create_int_fn = createInt,
65         .create_bool_fn = createBool,
66         .create_string_fn = createString,
67         .create_real_fn = createReal,
68         .register_handlers_fn = registerHandlers,
69         .free_fn = freeProperty,
70 };
71 
hasProperty(const std::string & name) const72 bool PropertyProvider::hasProperty(const std::string& name) const {
73     return mProperties.find(name) != mProperties.end();
74 }
75 
getProperty(const std::string & name)76 GesturesProp& PropertyProvider::getProperty(const std::string& name) {
77     return mProperties.at(name);
78 }
79 
dump() const80 std::string PropertyProvider::dump() const {
81     std::string dump;
82     for (const auto& [name, property] : mProperties) {
83         dump += property.dump() + "\n";
84     }
85     return dump;
86 }
87 
loadPropertiesFromIdcFile(const PropertyMap & idcProperties)88 void PropertyProvider::loadPropertiesFromIdcFile(const PropertyMap& idcProperties) {
89     // For compatibility with the configuration file syntax, gesture property names in IDC files are
90     // prefixed with "gestureProp." and have spaces replaced by underscores. So, for example, the
91     // configuration key "gestureProp.Palm_Width" refers to the "Palm Width" property.
92     const std::string gesturePropPrefix = "gestureProp.";
93     for (const std::string& key : idcProperties.getKeysWithPrefix(gesturePropPrefix)) {
94         std::string propertyName = key.substr(gesturePropPrefix.length());
95         for (size_t i = 0; i < propertyName.length(); i++) {
96             if (propertyName[i] == '_') {
97                 propertyName[i] = ' ';
98             }
99         }
100 
101         auto it = mProperties.find(propertyName);
102         if (it != mProperties.end()) {
103             it->second.trySetFromIdcProperty(idcProperties, key);
104         } else {
105             ALOGE("Gesture property \"%s\" specified in IDC file does not exist for this device.",
106                   propertyName.c_str());
107         }
108     }
109 }
110 
createIntArrayProperty(const std::string & name,int * loc,size_t count,const int * init)111 GesturesProp* PropertyProvider::createIntArrayProperty(const std::string& name, int* loc,
112                                                        size_t count, const int* init) {
113     const auto [it, inserted] =
114             mProperties.insert(std::pair{name, GesturesProp(name, loc, count, init)});
115     LOG_ALWAYS_FATAL_IF(!inserted, "Gesture property \"%s\" already exists.", name.c_str());
116     return &it->second;
117 }
118 
createBoolArrayProperty(const std::string & name,GesturesPropBool * loc,size_t count,const GesturesPropBool * init)119 GesturesProp* PropertyProvider::createBoolArrayProperty(const std::string& name,
120                                                         GesturesPropBool* loc, size_t count,
121                                                         const GesturesPropBool* init) {
122     const auto [it, inserted] =
123             mProperties.insert(std::pair{name, GesturesProp(name, loc, count, init)});
124     LOG_ALWAYS_FATAL_IF(!inserted, "Gesture property \"%s\" already exists.", name.c_str());
125     return &it->second;
126 }
127 
createRealArrayProperty(const std::string & name,double * loc,size_t count,const double * init)128 GesturesProp* PropertyProvider::createRealArrayProperty(const std::string& name, double* loc,
129                                                         size_t count, const double* init) {
130     const auto [it, inserted] =
131             mProperties.insert(std::pair{name, GesturesProp(name, loc, count, init)});
132     LOG_ALWAYS_FATAL_IF(!inserted, "Gesture property \"%s\" already exists.", name.c_str());
133     return &it->second;
134 }
135 
createStringProperty(const std::string & name,const char ** loc,const char * const init)136 GesturesProp* PropertyProvider::createStringProperty(const std::string& name, const char** loc,
137                                                      const char* const init) {
138     const auto [it, inserted] = mProperties.insert(std::pair{name, GesturesProp(name, loc, init)});
139     LOG_ALWAYS_FATAL_IF(!inserted, "Gesture property \"%s\" already exists.", name.c_str());
140     return &it->second;
141 }
142 
freeProperty(GesturesProp * prop)143 void PropertyProvider::freeProperty(GesturesProp* prop) {
144     mProperties.erase(prop->getName());
145 }
146 
147 } // namespace android
148 
149 template <typename T>
GesturesProp(std::string name,T * dataPointer,size_t count,const T * initialValues)150 GesturesProp::GesturesProp(std::string name, T* dataPointer, size_t count, const T* initialValues)
151       : mName(name), mCount(count), mDataPointer(dataPointer) {
152     std::copy_n(initialValues, count, dataPointer);
153 }
154 
GesturesProp(std::string name,const char ** dataPointer,const char * const initialValue)155 GesturesProp::GesturesProp(std::string name, const char** dataPointer,
156                            const char* const initialValue)
157       : mName(name), mCount(1), mDataPointer(dataPointer) {
158     *(std::get<const char**>(mDataPointer)) = initialValue;
159 }
160 
dump() const161 std::string GesturesProp::dump() const {
162     using android::base::StringPrintf;
163     std::string type, values;
164     switch (mDataPointer.index()) {
165         case 0:
166             type = "integer";
167             values = android::dumpVector(getIntValues());
168             break;
169         case 1:
170             type = "boolean";
171             values = android::dumpVector(getBoolValues());
172             break;
173         case 2:
174             type = "string";
175             values = getStringValue();
176             break;
177         case 3:
178             type = "real";
179             values = android::dumpVector(getRealValues());
180             break;
181     }
182     std::string typeAndSize = mCount == 1 ? type : std::to_string(mCount) + " " + type + "s";
183     return StringPrintf("%s (%s): %s", mName.c_str(), typeAndSize.c_str(), values.c_str());
184 }
185 
registerHandlers(void * handlerData,GesturesPropGetHandler getter,GesturesPropSetHandler setter)186 void GesturesProp::registerHandlers(void* handlerData, GesturesPropGetHandler getter,
187                                     GesturesPropSetHandler setter) {
188     mHandlerData = handlerData;
189     mGetter = getter;
190     mSetter = setter;
191 }
192 
getIntValues() const193 std::vector<int> GesturesProp::getIntValues() const {
194     LOG_ALWAYS_FATAL_IF(!std::holds_alternative<int*>(mDataPointer),
195                         "Attempt to read ints from \"%s\" gesture property.", mName.c_str());
196     return getValues<int, int>(std::get<int*>(mDataPointer));
197 }
198 
getBoolValues() const199 std::vector<bool> GesturesProp::getBoolValues() const {
200     LOG_ALWAYS_FATAL_IF(!std::holds_alternative<GesturesPropBool*>(mDataPointer),
201                         "Attempt to read bools from \"%s\" gesture property.", mName.c_str());
202     return getValues<bool, GesturesPropBool>(std::get<GesturesPropBool*>(mDataPointer));
203 }
204 
getRealValues() const205 std::vector<double> GesturesProp::getRealValues() const {
206     LOG_ALWAYS_FATAL_IF(!std::holds_alternative<double*>(mDataPointer),
207                         "Attempt to read reals from \"%s\" gesture property.", mName.c_str());
208     return getValues<double, double>(std::get<double*>(mDataPointer));
209 }
210 
getStringValue() const211 std::string GesturesProp::getStringValue() const {
212     LOG_ALWAYS_FATAL_IF(!std::holds_alternative<const char**>(mDataPointer),
213                         "Attempt to read a string from \"%s\" gesture property.", mName.c_str());
214     if (mGetter != nullptr) {
215         mGetter(mHandlerData);
216     }
217     return std::string(*std::get<const char**>(mDataPointer));
218 }
219 
setBoolValues(const std::vector<bool> & values)220 void GesturesProp::setBoolValues(const std::vector<bool>& values) {
221     LOG_ALWAYS_FATAL_IF(!std::holds_alternative<GesturesPropBool*>(mDataPointer),
222                         "Attempt to write bools to \"%s\" gesture property.", mName.c_str());
223     setValues(std::get<GesturesPropBool*>(mDataPointer), values);
224 }
225 
setIntValues(const std::vector<int> & values)226 void GesturesProp::setIntValues(const std::vector<int>& values) {
227     LOG_ALWAYS_FATAL_IF(!std::holds_alternative<int*>(mDataPointer),
228                         "Attempt to write ints to \"%s\" gesture property.", mName.c_str());
229     setValues(std::get<int*>(mDataPointer), values);
230 }
231 
setRealValues(const std::vector<double> & values)232 void GesturesProp::setRealValues(const std::vector<double>& values) {
233     LOG_ALWAYS_FATAL_IF(!std::holds_alternative<double*>(mDataPointer),
234                         "Attempt to write reals to \"%s\" gesture property.", mName.c_str());
235     setValues(std::get<double*>(mDataPointer), values);
236 }
237 
238 namespace {
239 
240 // Helper to std::visit with lambdas.
241 template <typename... V>
242 struct Visitor : V... { using V::operator()...; };
243 // explicit deduction guide (not needed as of C++20)
244 template <typename... V>
245 Visitor(V...) -> Visitor<V...>;
246 
247 } // namespace
248 
trySetFromIdcProperty(const android::PropertyMap & idcProperties,const std::string & propertyName)249 void GesturesProp::trySetFromIdcProperty(const android::PropertyMap& idcProperties,
250                                          const std::string& propertyName) {
251     if (mCount != 1) {
252         ALOGE("Gesture property \"%s\" is an array, and so cannot be set in an IDC file.",
253               mName.c_str());
254         return;
255     }
256     bool parsedSuccessfully = false;
257     Visitor setVisitor{
258             [&](int*) {
259                 if (std::optional<int32_t> value = idcProperties.getInt(propertyName); value) {
260                     parsedSuccessfully = true;
261                     setIntValues({*value});
262                 }
263             },
264             [&](GesturesPropBool*) {
265                 if (std::optional<bool> value = idcProperties.getBool(propertyName); value) {
266                     parsedSuccessfully = true;
267                     setBoolValues({*value});
268                 }
269             },
270             [&](double*) {
271                 if (std::optional<double> value = idcProperties.getDouble(propertyName); value) {
272                     parsedSuccessfully = true;
273                     setRealValues({*value});
274                 }
275             },
276             [&](const char**) {
277                 ALOGE("Gesture property \"%s\" is a string, and so cannot be set in an IDC file.",
278                       mName.c_str());
279                 // We've already reported the type mismatch, so set parsedSuccessfully.
280                 parsedSuccessfully = true;
281             },
282     };
283     std::visit(setVisitor, mDataPointer);
284 
285     ALOGE_IF(!parsedSuccessfully, "Gesture property \"%s\" couldn't be set due to a type mismatch.",
286              mName.c_str());
287 }
288 
289 template <typename T, typename U>
getValues(U * dataPointer) const290 const std::vector<T> GesturesProp::getValues(U* dataPointer) const {
291     if (mGetter != nullptr) {
292         mGetter(mHandlerData);
293     }
294     std::vector<T> values;
295     values.reserve(mCount);
296     for (size_t i = 0; i < mCount; i++) {
297         values.push_back(dataPointer[i]);
298     }
299     return values;
300 }
301 
302 template <typename T, typename U>
setValues(T * dataPointer,const std::vector<U> & values)303 void GesturesProp::setValues(T* dataPointer, const std::vector<U>& values) {
304     LOG_ALWAYS_FATAL_IF(values.size() != mCount,
305                         "Attempt to write %zu values to \"%s\" gesture property, which holds %zu.",
306                         values.size(), mName.c_str(), mCount);
307     std::copy(values.begin(), values.end(), dataPointer);
308     if (mSetter != nullptr) {
309         mSetter(mHandlerData);
310     }
311 }
312