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