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