1 /*
2  * Copyright (C) 2012 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 #define LOG_TAG "InputDevice"
18 
19 #include <stdlib.h>
20 #include <unistd.h>
21 #include <ctype.h>
22 
23 #include <android-base/properties.h>
24 #include <android-base/stringprintf.h>
25 #include <ftl/enum.h>
26 #include <input/InputDevice.h>
27 #include <input/InputEventLabels.h>
28 
29 using android::base::GetProperty;
30 using android::base::StringPrintf;
31 
32 namespace android {
33 
34 static const char* CONFIGURATION_FILE_DIR[] = {
35         "idc/",
36         "keylayout/",
37         "keychars/",
38 };
39 
40 static const char* CONFIGURATION_FILE_EXTENSION[] = {
41         ".idc",
42         ".kl",
43         ".kcm",
44 };
45 
isValidNameChar(char ch)46 static bool isValidNameChar(char ch) {
47     return isascii(ch) && (isdigit(ch) || isalpha(ch) || ch == '-' || ch == '_');
48 }
49 
appendInputDeviceConfigurationFileRelativePath(std::string & path,const std::string & name,InputDeviceConfigurationFileType type)50 static void appendInputDeviceConfigurationFileRelativePath(std::string& path,
51         const std::string& name, InputDeviceConfigurationFileType type) {
52     path += CONFIGURATION_FILE_DIR[static_cast<int32_t>(type)];
53     path += name;
54     path += CONFIGURATION_FILE_EXTENSION[static_cast<int32_t>(type)];
55 }
56 
getInputDeviceConfigurationFilePathByDeviceIdentifier(const InputDeviceIdentifier & deviceIdentifier,InputDeviceConfigurationFileType type,const char * suffix)57 std::string getInputDeviceConfigurationFilePathByDeviceIdentifier(
58         const InputDeviceIdentifier& deviceIdentifier, InputDeviceConfigurationFileType type,
59         const char* suffix) {
60     if (deviceIdentifier.vendor !=0 && deviceIdentifier.product != 0) {
61         if (deviceIdentifier.version != 0) {
62             // Try vendor product version.
63             std::string versionPath =
64                     getInputDeviceConfigurationFilePathByName(StringPrintf("Vendor_%04x_Product_%"
65                                                                            "04x_Version_%04x%s",
66                                                                            deviceIdentifier.vendor,
67                                                                            deviceIdentifier.product,
68                                                                            deviceIdentifier.version,
69                                                                            suffix),
70                                                               type);
71             if (!versionPath.empty()) {
72                 return versionPath;
73             }
74         }
75 
76         // Try vendor product.
77         std::string productPath =
78                 getInputDeviceConfigurationFilePathByName(StringPrintf("Vendor_%04x_Product_%04x%s",
79                                                                        deviceIdentifier.vendor,
80                                                                        deviceIdentifier.product,
81                                                                        suffix),
82                                                           type);
83         if (!productPath.empty()) {
84             return productPath;
85         }
86     }
87 
88     // Try device name.
89     return getInputDeviceConfigurationFilePathByName(deviceIdentifier.getCanonicalName() + suffix,
90                                                      type);
91 }
92 
getInputDeviceConfigurationFilePathByName(const std::string & name,InputDeviceConfigurationFileType type)93 std::string getInputDeviceConfigurationFilePathByName(
94         const std::string& name, InputDeviceConfigurationFileType type) {
95     // Search system repository.
96     std::string path;
97 
98     // Treblized input device config files will be located /product/usr, /system_ext/usr,
99     // /odm/usr or /vendor/usr.
100     std::vector<std::string> pathPrefixes{
101             "/product/usr/",
102             "/system_ext/usr/",
103             "/odm/usr/",
104             "/vendor/usr/",
105     };
106     // These files may also be in the APEX pointed by input_device.config_file.apex sysprop.
107     if (auto apex = GetProperty("input_device.config_file.apex", ""); !apex.empty()) {
108         pathPrefixes.push_back("/apex/" + apex + "/etc/usr/");
109     }
110     // ANDROID_ROOT may not be set on host
111     if (auto android_root = getenv("ANDROID_ROOT"); android_root != nullptr) {
112         pathPrefixes.push_back(std::string(android_root) + "/usr/");
113     }
114     for (const auto& prefix : pathPrefixes) {
115         path = prefix;
116         appendInputDeviceConfigurationFileRelativePath(path, name, type);
117 #if DEBUG_PROBE
118         ALOGD("Probing for system provided input device configuration file: path='%s'",
119               path.c_str());
120 #endif
121         if (!access(path.c_str(), R_OK)) {
122 #if DEBUG_PROBE
123             ALOGD("Found");
124 #endif
125             return path;
126         }
127     }
128 
129     // Search user repository.
130     // TODO Should only look here if not in safe mode.
131     path = "";
132     char *androidData = getenv("ANDROID_DATA");
133     if (androidData != nullptr) {
134         path += androidData;
135     }
136     path += "/system/devices/";
137     appendInputDeviceConfigurationFileRelativePath(path, name, type);
138 #if DEBUG_PROBE
139     ALOGD("Probing for system user input device configuration file: path='%s'", path.c_str());
140 #endif
141     if (!access(path.c_str(), R_OK)) {
142 #if DEBUG_PROBE
143         ALOGD("Found");
144 #endif
145         return path;
146     }
147 
148     // Not found.
149 #if DEBUG_PROBE
150     ALOGD("Probe failed to find input device configuration file: name='%s', type=%d",
151             name.c_str(), type);
152 #endif
153     return "";
154 }
155 
156 // --- InputDeviceIdentifier
157 
getCanonicalName() const158 std::string InputDeviceIdentifier::getCanonicalName() const {
159     std::string replacedName = name;
160     for (char& ch : replacedName) {
161         if (!isValidNameChar(ch)) {
162             ch = '_';
163         }
164     }
165     return replacedName;
166 }
167 
168 
169 // --- InputDeviceInfo ---
170 
InputDeviceInfo()171 InputDeviceInfo::InputDeviceInfo() {
172     initialize(-1, 0, -1, InputDeviceIdentifier(), "", false, false, ui::LogicalDisplayId::INVALID);
173 }
174 
InputDeviceInfo(const InputDeviceInfo & other)175 InputDeviceInfo::InputDeviceInfo(const InputDeviceInfo& other)
176       : mId(other.mId),
177         mGeneration(other.mGeneration),
178         mControllerNumber(other.mControllerNumber),
179         mIdentifier(other.mIdentifier),
180         mAlias(other.mAlias),
181         mIsExternal(other.mIsExternal),
182         mHasMic(other.mHasMic),
183         mKeyboardLayoutInfo(other.mKeyboardLayoutInfo),
184         mSources(other.mSources),
185         mKeyboardType(other.mKeyboardType),
186         mKeyCharacterMap(other.mKeyCharacterMap),
187         mUsiVersion(other.mUsiVersion),
188         mAssociatedDisplayId(other.mAssociatedDisplayId),
189         mEnabled(other.mEnabled),
190         mHasVibrator(other.mHasVibrator),
191         mHasBattery(other.mHasBattery),
192         mHasButtonUnderPad(other.mHasButtonUnderPad),
193         mHasSensor(other.mHasSensor),
194         mMotionRanges(other.mMotionRanges),
195         mSensors(other.mSensors),
196         mLights(other.mLights),
197         mViewBehavior(other.mViewBehavior) {}
198 
~InputDeviceInfo()199 InputDeviceInfo::~InputDeviceInfo() {
200 }
201 
initialize(int32_t id,int32_t generation,int32_t controllerNumber,const InputDeviceIdentifier & identifier,const std::string & alias,bool isExternal,bool hasMic,ui::LogicalDisplayId associatedDisplayId,InputDeviceViewBehavior viewBehavior,bool enabled)202 void InputDeviceInfo::initialize(int32_t id, int32_t generation, int32_t controllerNumber,
203                                  const InputDeviceIdentifier& identifier, const std::string& alias,
204                                  bool isExternal, bool hasMic,
205                                  ui::LogicalDisplayId associatedDisplayId,
206                                  InputDeviceViewBehavior viewBehavior, bool enabled) {
207     mId = id;
208     mGeneration = generation;
209     mControllerNumber = controllerNumber;
210     mIdentifier = identifier;
211     mAlias = alias;
212     mIsExternal = isExternal;
213     mHasMic = hasMic;
214     mSources = 0;
215     mKeyboardType = AINPUT_KEYBOARD_TYPE_NONE;
216     mAssociatedDisplayId = associatedDisplayId;
217     mEnabled = enabled;
218     mHasVibrator = false;
219     mHasBattery = false;
220     mHasButtonUnderPad = false;
221     mHasSensor = false;
222     mViewBehavior = viewBehavior;
223     mUsiVersion.reset();
224     mMotionRanges.clear();
225     mSensors.clear();
226     mLights.clear();
227 }
228 
getMotionRange(int32_t axis,uint32_t source) const229 const InputDeviceInfo::MotionRange* InputDeviceInfo::getMotionRange(
230         int32_t axis, uint32_t source) const {
231     for (const MotionRange& range : mMotionRanges) {
232         if (range.axis == axis && isFromSource(range.source, source)) {
233             return &range;
234         }
235     }
236     return nullptr;
237 }
238 
addSource(uint32_t source)239 void InputDeviceInfo::addSource(uint32_t source) {
240     mSources |= source;
241 }
242 
addMotionRange(int32_t axis,uint32_t source,float min,float max,float flat,float fuzz,float resolution)243 void InputDeviceInfo::addMotionRange(int32_t axis, uint32_t source, float min, float max,
244         float flat, float fuzz, float resolution) {
245     MotionRange range = { axis, source, min, max, flat, fuzz, resolution };
246     mMotionRanges.push_back(range);
247 }
248 
addMotionRange(const MotionRange & range)249 void InputDeviceInfo::addMotionRange(const MotionRange& range) {
250     mMotionRanges.push_back(range);
251 }
252 
addSensorInfo(const InputDeviceSensorInfo & info)253 void InputDeviceInfo::addSensorInfo(const InputDeviceSensorInfo& info) {
254     if (mSensors.find(info.type) != mSensors.end()) {
255         ALOGW("Sensor type %s already exists, will be replaced by new sensor added.",
256               ftl::enum_string(info.type).c_str());
257     }
258     mSensors.insert_or_assign(info.type, info);
259 }
260 
addBatteryInfo(const InputDeviceBatteryInfo & info)261 void InputDeviceInfo::addBatteryInfo(const InputDeviceBatteryInfo& info) {
262     if (mBatteries.find(info.id) != mBatteries.end()) {
263         ALOGW("Battery id %d already exists, will be replaced by new battery added.", info.id);
264     }
265     mBatteries.insert_or_assign(info.id, info);
266 }
267 
addLightInfo(const InputDeviceLightInfo & info)268 void InputDeviceInfo::addLightInfo(const InputDeviceLightInfo& info) {
269     if (mLights.find(info.id) != mLights.end()) {
270         ALOGW("Light id %d already exists, will be replaced by new light added.", info.id);
271     }
272     mLights.insert_or_assign(info.id, info);
273 }
274 
setKeyboardType(int32_t keyboardType)275 void InputDeviceInfo::setKeyboardType(int32_t keyboardType) {
276     mKeyboardType = keyboardType;
277 }
278 
setKeyboardLayoutInfo(KeyboardLayoutInfo layoutInfo)279 void InputDeviceInfo::setKeyboardLayoutInfo(KeyboardLayoutInfo layoutInfo) {
280     mKeyboardLayoutInfo = std::move(layoutInfo);
281 }
282 
getSensors()283 std::vector<InputDeviceSensorInfo> InputDeviceInfo::getSensors() {
284     std::vector<InputDeviceSensorInfo> infos;
285     infos.reserve(mSensors.size());
286     for (const auto& [type, info] : mSensors) {
287         infos.push_back(info);
288     }
289     return infos;
290 }
291 
getLights()292 std::vector<InputDeviceLightInfo> InputDeviceInfo::getLights() {
293     std::vector<InputDeviceLightInfo> infos;
294     infos.reserve(mLights.size());
295     for (const auto& [id, info] : mLights) {
296         infos.push_back(info);
297     }
298     return infos;
299 }
300 
301 } // namespace android
302