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 
27 using android::base::StringPrintf;
28 
29 namespace android {
30 
31 static const char* CONFIGURATION_FILE_DIR[] = {
32         "idc/",
33         "keylayout/",
34         "keychars/",
35 };
36 
37 static const char* CONFIGURATION_FILE_EXTENSION[] = {
38         ".idc",
39         ".kl",
40         ".kcm",
41 };
42 
isValidNameChar(char ch)43 static bool isValidNameChar(char ch) {
44     return isascii(ch) && (isdigit(ch) || isalpha(ch) || ch == '-' || ch == '_');
45 }
46 
appendInputDeviceConfigurationFileRelativePath(std::string & path,const std::string & name,InputDeviceConfigurationFileType type)47 static void appendInputDeviceConfigurationFileRelativePath(std::string& path,
48         const std::string& name, InputDeviceConfigurationFileType type) {
49     path += CONFIGURATION_FILE_DIR[type];
50     path += name;
51     path += CONFIGURATION_FILE_EXTENSION[type];
52 }
53 
getInputDeviceConfigurationFilePathByDeviceIdentifier(const InputDeviceIdentifier & deviceIdentifier,InputDeviceConfigurationFileType type)54 std::string getInputDeviceConfigurationFilePathByDeviceIdentifier(
55         const InputDeviceIdentifier& deviceIdentifier,
56         InputDeviceConfigurationFileType type) {
57     if (deviceIdentifier.vendor !=0 && deviceIdentifier.product != 0) {
58         if (deviceIdentifier.version != 0) {
59             // Try vendor product version.
60             std::string versionPath = getInputDeviceConfigurationFilePathByName(
61                     StringPrintf("Vendor_%04x_Product_%04x_Version_%04x",
62                             deviceIdentifier.vendor, deviceIdentifier.product,
63                             deviceIdentifier.version),
64                     type);
65             if (!versionPath.empty()) {
66                 return versionPath;
67             }
68         }
69 
70         // Try vendor product.
71         std::string productPath = getInputDeviceConfigurationFilePathByName(
72                 StringPrintf("Vendor_%04x_Product_%04x",
73                         deviceIdentifier.vendor, deviceIdentifier.product),
74                 type);
75         if (!productPath.empty()) {
76             return productPath;
77         }
78     }
79 
80     // Try device name.
81     return getInputDeviceConfigurationFilePathByName(deviceIdentifier.getCanonicalName(), type);
82 }
83 
getInputDeviceConfigurationFilePathByName(const std::string & name,InputDeviceConfigurationFileType type)84 std::string getInputDeviceConfigurationFilePathByName(
85         const std::string& name, InputDeviceConfigurationFileType type) {
86     // Search system repository.
87     std::string path;
88 
89     // Treblized input device config files will be located /odm/usr or /vendor/usr.
90     const char *rootsForPartition[] {"/odm", "/vendor", getenv("ANDROID_ROOT")};
91     for (size_t i = 0; i < size(rootsForPartition); i++) {
92         if (rootsForPartition[i] == nullptr) {
93             continue;
94         }
95         path = rootsForPartition[i];
96         path += "/usr/";
97         appendInputDeviceConfigurationFileRelativePath(path, name, type);
98 #if DEBUG_PROBE
99         ALOGD("Probing for system provided input device configuration file: path='%s'",
100               path.c_str());
101 #endif
102         if (!access(path.c_str(), R_OK)) {
103 #if DEBUG_PROBE
104             ALOGD("Found");
105 #endif
106             return path;
107         }
108     }
109 
110     // Search user repository.
111     // TODO Should only look here if not in safe mode.
112     path = "";
113     char *androidData = getenv("ANDROID_DATA");
114     if (androidData != nullptr) {
115         path += androidData;
116     }
117     path += "/system/devices/";
118     appendInputDeviceConfigurationFileRelativePath(path, name, type);
119 #if DEBUG_PROBE
120     ALOGD("Probing for system user input device configuration file: path='%s'", path.c_str());
121 #endif
122     if (!access(path.c_str(), R_OK)) {
123 #if DEBUG_PROBE
124         ALOGD("Found");
125 #endif
126         return path;
127     }
128 
129     // Not found.
130 #if DEBUG_PROBE
131     ALOGD("Probe failed to find input device configuration file: name='%s', type=%d",
132             name.c_str(), type);
133 #endif
134     return "";
135 }
136 
137 // --- InputDeviceIdentifier
138 
getCanonicalName() const139 std::string InputDeviceIdentifier::getCanonicalName() const {
140     std::string replacedName = name;
141     for (char& ch : replacedName) {
142         if (!isValidNameChar(ch)) {
143             ch = '_';
144         }
145     }
146     return replacedName;
147 }
148 
149 
150 // --- InputDeviceInfo ---
151 
InputDeviceInfo()152 InputDeviceInfo::InputDeviceInfo() {
153     initialize(-1, 0, -1, InputDeviceIdentifier(), "", false, false);
154 }
155 
InputDeviceInfo(const InputDeviceInfo & other)156 InputDeviceInfo::InputDeviceInfo(const InputDeviceInfo& other) :
157         mId(other.mId), mGeneration(other.mGeneration), mControllerNumber(other.mControllerNumber),
158         mIdentifier(other.mIdentifier), mAlias(other.mAlias), mIsExternal(other.mIsExternal),
159         mHasMic(other.mHasMic), mSources(other.mSources),
160         mKeyboardType(other.mKeyboardType), mKeyCharacterMap(other.mKeyCharacterMap),
161         mHasVibrator(other.mHasVibrator), mHasButtonUnderPad(other.mHasButtonUnderPad),
162         mMotionRanges(other.mMotionRanges) {
163 }
164 
~InputDeviceInfo()165 InputDeviceInfo::~InputDeviceInfo() {
166 }
167 
initialize(int32_t id,int32_t generation,int32_t controllerNumber,const InputDeviceIdentifier & identifier,const std::string & alias,bool isExternal,bool hasMic)168 void InputDeviceInfo::initialize(int32_t id, int32_t generation, int32_t controllerNumber,
169         const InputDeviceIdentifier& identifier, const std::string& alias, bool isExternal,
170         bool hasMic) {
171     mId = id;
172     mGeneration = generation;
173     mControllerNumber = controllerNumber;
174     mIdentifier = identifier;
175     mAlias = alias;
176     mIsExternal = isExternal;
177     mHasMic = hasMic;
178     mSources = 0;
179     mKeyboardType = AINPUT_KEYBOARD_TYPE_NONE;
180     mHasVibrator = false;
181     mHasButtonUnderPad = false;
182     mMotionRanges.clear();
183 }
184 
getMotionRange(int32_t axis,uint32_t source) const185 const InputDeviceInfo::MotionRange* InputDeviceInfo::getMotionRange(
186         int32_t axis, uint32_t source) const {
187     size_t numRanges = mMotionRanges.size();
188     for (size_t i = 0; i < numRanges; i++) {
189         const MotionRange& range = mMotionRanges[i];
190         if (range.axis == axis && range.source == source) {
191             return &range;
192         }
193     }
194     return nullptr;
195 }
196 
addSource(uint32_t source)197 void InputDeviceInfo::addSource(uint32_t source) {
198     mSources |= source;
199 }
200 
addMotionRange(int32_t axis,uint32_t source,float min,float max,float flat,float fuzz,float resolution)201 void InputDeviceInfo::addMotionRange(int32_t axis, uint32_t source, float min, float max,
202         float flat, float fuzz, float resolution) {
203     MotionRange range = { axis, source, min, max, flat, fuzz, resolution };
204     mMotionRanges.push_back(range);
205 }
206 
addMotionRange(const MotionRange & range)207 void InputDeviceInfo::addMotionRange(const MotionRange& range) {
208     mMotionRanges.push_back(range);
209 }
210 
211 } // namespace android
212