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