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 <input/InputDevice.h>
25 #include <input/InputEventLabels.h>
26 #include <input/NamedEnum.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)55 std::string getInputDeviceConfigurationFilePathByDeviceIdentifier(
56 const InputDeviceIdentifier& deviceIdentifier,
57 InputDeviceConfigurationFileType type) {
58 if (deviceIdentifier.vendor !=0 && deviceIdentifier.product != 0) {
59 if (deviceIdentifier.version != 0) {
60 // Try vendor product version.
61 std::string versionPath = getInputDeviceConfigurationFilePathByName(
62 StringPrintf("Vendor_%04x_Product_%04x_Version_%04x",
63 deviceIdentifier.vendor, deviceIdentifier.product,
64 deviceIdentifier.version),
65 type);
66 if (!versionPath.empty()) {
67 return versionPath;
68 }
69 }
70
71 // Try vendor product.
72 std::string productPath = getInputDeviceConfigurationFilePathByName(
73 StringPrintf("Vendor_%04x_Product_%04x",
74 deviceIdentifier.vendor, deviceIdentifier.product),
75 type);
76 if (!productPath.empty()) {
77 return productPath;
78 }
79 }
80
81 // Try device name.
82 return getInputDeviceConfigurationFilePathByName(deviceIdentifier.getCanonicalName(), type);
83 }
84
getInputDeviceConfigurationFilePathByName(const std::string & name,InputDeviceConfigurationFileType type)85 std::string getInputDeviceConfigurationFilePathByName(
86 const std::string& name, InputDeviceConfigurationFileType type) {
87 // Search system repository.
88 std::string path;
89
90 // Treblized input device config files will be located /product/usr, /system_ext/usr,
91 // /odm/usr or /vendor/usr.
92 const char* rootsForPartition[]{"/product", "/system_ext", "/odm", "/vendor",
93 getenv("ANDROID_ROOT")};
94 for (size_t i = 0; i < size(rootsForPartition); i++) {
95 if (rootsForPartition[i] == nullptr) {
96 continue;
97 }
98 path = rootsForPartition[i];
99 path += "/usr/";
100 appendInputDeviceConfigurationFileRelativePath(path, name, type);
101 #if DEBUG_PROBE
102 ALOGD("Probing for system provided input device configuration file: path='%s'",
103 path.c_str());
104 #endif
105 if (!access(path.c_str(), R_OK)) {
106 #if DEBUG_PROBE
107 ALOGD("Found");
108 #endif
109 return path;
110 }
111 }
112
113 // Search user repository.
114 // TODO Should only look here if not in safe mode.
115 path = "";
116 char *androidData = getenv("ANDROID_DATA");
117 if (androidData != nullptr) {
118 path += androidData;
119 }
120 path += "/system/devices/";
121 appendInputDeviceConfigurationFileRelativePath(path, name, type);
122 #if DEBUG_PROBE
123 ALOGD("Probing for system user input device configuration file: path='%s'", path.c_str());
124 #endif
125 if (!access(path.c_str(), R_OK)) {
126 #if DEBUG_PROBE
127 ALOGD("Found");
128 #endif
129 return path;
130 }
131
132 // Not found.
133 #if DEBUG_PROBE
134 ALOGD("Probe failed to find input device configuration file: name='%s', type=%d",
135 name.c_str(), type);
136 #endif
137 return "";
138 }
139
140 // --- InputDeviceIdentifier
141
getCanonicalName() const142 std::string InputDeviceIdentifier::getCanonicalName() const {
143 std::string replacedName = name;
144 for (char& ch : replacedName) {
145 if (!isValidNameChar(ch)) {
146 ch = '_';
147 }
148 }
149 return replacedName;
150 }
151
152
153 // --- InputDeviceInfo ---
154
InputDeviceInfo()155 InputDeviceInfo::InputDeviceInfo() {
156 initialize(-1, 0, -1, InputDeviceIdentifier(), "", false, false);
157 }
158
InputDeviceInfo(const InputDeviceInfo & other)159 InputDeviceInfo::InputDeviceInfo(const InputDeviceInfo& other)
160 : mId(other.mId),
161 mGeneration(other.mGeneration),
162 mControllerNumber(other.mControllerNumber),
163 mIdentifier(other.mIdentifier),
164 mAlias(other.mAlias),
165 mIsExternal(other.mIsExternal),
166 mHasMic(other.mHasMic),
167 mSources(other.mSources),
168 mKeyboardType(other.mKeyboardType),
169 mKeyCharacterMap(other.mKeyCharacterMap),
170 mHasVibrator(other.mHasVibrator),
171 mHasBattery(other.mHasBattery),
172 mHasButtonUnderPad(other.mHasButtonUnderPad),
173 mHasSensor(other.mHasSensor),
174 mMotionRanges(other.mMotionRanges),
175 mSensors(other.mSensors),
176 mLights(other.mLights) {}
177
~InputDeviceInfo()178 InputDeviceInfo::~InputDeviceInfo() {
179 }
180
initialize(int32_t id,int32_t generation,int32_t controllerNumber,const InputDeviceIdentifier & identifier,const std::string & alias,bool isExternal,bool hasMic)181 void InputDeviceInfo::initialize(int32_t id, int32_t generation, int32_t controllerNumber,
182 const InputDeviceIdentifier& identifier, const std::string& alias, bool isExternal,
183 bool hasMic) {
184 mId = id;
185 mGeneration = generation;
186 mControllerNumber = controllerNumber;
187 mIdentifier = identifier;
188 mAlias = alias;
189 mIsExternal = isExternal;
190 mHasMic = hasMic;
191 mSources = 0;
192 mKeyboardType = AINPUT_KEYBOARD_TYPE_NONE;
193 mHasVibrator = false;
194 mHasBattery = false;
195 mHasButtonUnderPad = false;
196 mHasSensor = false;
197 mMotionRanges.clear();
198 mSensors.clear();
199 mLights.clear();
200 }
201
getMotionRange(int32_t axis,uint32_t source) const202 const InputDeviceInfo::MotionRange* InputDeviceInfo::getMotionRange(
203 int32_t axis, uint32_t source) const {
204 size_t numRanges = mMotionRanges.size();
205 for (size_t i = 0; i < numRanges; i++) {
206 const MotionRange& range = mMotionRanges[i];
207 if (range.axis == axis && range.source == source) {
208 return ⦥
209 }
210 }
211 return nullptr;
212 }
213
addSource(uint32_t source)214 void InputDeviceInfo::addSource(uint32_t source) {
215 mSources |= source;
216 }
217
addMotionRange(int32_t axis,uint32_t source,float min,float max,float flat,float fuzz,float resolution)218 void InputDeviceInfo::addMotionRange(int32_t axis, uint32_t source, float min, float max,
219 float flat, float fuzz, float resolution) {
220 MotionRange range = { axis, source, min, max, flat, fuzz, resolution };
221 mMotionRanges.push_back(range);
222 }
223
addMotionRange(const MotionRange & range)224 void InputDeviceInfo::addMotionRange(const MotionRange& range) {
225 mMotionRanges.push_back(range);
226 }
227
addSensorInfo(const InputDeviceSensorInfo & info)228 void InputDeviceInfo::addSensorInfo(const InputDeviceSensorInfo& info) {
229 if (mSensors.find(info.type) != mSensors.end()) {
230 ALOGW("Sensor type %s already exists, will be replaced by new sensor added.",
231 NamedEnum::string(info.type).c_str());
232 }
233 mSensors.insert_or_assign(info.type, info);
234 }
235
addBatteryInfo(const InputDeviceBatteryInfo & info)236 void InputDeviceInfo::addBatteryInfo(const InputDeviceBatteryInfo& info) {
237 if (mBatteries.find(info.id) != mBatteries.end()) {
238 ALOGW("Battery id %d already exists, will be replaced by new battery added.", info.id);
239 }
240 mBatteries.insert_or_assign(info.id, info);
241 }
242
addLightInfo(const InputDeviceLightInfo & info)243 void InputDeviceInfo::addLightInfo(const InputDeviceLightInfo& info) {
244 if (mLights.find(info.id) != mLights.end()) {
245 ALOGW("Light id %d already exists, will be replaced by new light added.", info.id);
246 }
247 mLights.insert_or_assign(info.id, info);
248 }
249
getSensors()250 std::vector<InputDeviceSensorInfo> InputDeviceInfo::getSensors() {
251 std::vector<InputDeviceSensorInfo> infos;
252 infos.reserve(mSensors.size());
253 for (const auto& [type, info] : mSensors) {
254 infos.push_back(info);
255 }
256 return infos;
257 }
258
getLights()259 std::vector<InputDeviceLightInfo> InputDeviceInfo::getLights() {
260 std::vector<InputDeviceLightInfo> infos;
261 infos.reserve(mLights.size());
262 for (const auto& [id, info] : mLights) {
263 infos.push_back(info);
264 }
265 return infos;
266 }
267
268 } // namespace android
269