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 ⦥
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