Home | History | Annotate | Download | only in input
      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 
     40 static bool isValidNameChar(char ch) {
     41     return isascii(ch) && (isdigit(ch) || isalpha(ch) || ch == '-' || ch == '_');
     42 }
     43 
     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 
     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 
     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 
    136 InputDeviceInfo::InputDeviceInfo() {
    137     initialize(-1, 0, -1, InputDeviceIdentifier(), String8(), false, false);
    138 }
    139 
    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 
    149 InputDeviceInfo::~InputDeviceInfo() {
    150 }
    151 
    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 
    169 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 
    181 void InputDeviceInfo::addSource(uint32_t source) {
    182     mSources |= source;
    183 }
    184 
    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 
    191 void InputDeviceInfo::addMotionRange(const MotionRange& range) {
    192     mMotionRanges.add(range);
    193 }
    194 
    195 } // namespace android
    196