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