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