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