• 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 <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 &range;
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