19f25b7fdf216c9ef0bd2322cd223eeaf0d60f77fJeff Brown/*
29f25b7fdf216c9ef0bd2322cd223eeaf0d60f77fJeff Brown * Copyright (C) 2012 The Android Open Source Project
39f25b7fdf216c9ef0bd2322cd223eeaf0d60f77fJeff Brown *
49f25b7fdf216c9ef0bd2322cd223eeaf0d60f77fJeff Brown * Licensed under the Apache License, Version 2.0 (the "License");
59f25b7fdf216c9ef0bd2322cd223eeaf0d60f77fJeff Brown * you may not use this file except in compliance with the License.
69f25b7fdf216c9ef0bd2322cd223eeaf0d60f77fJeff Brown * You may obtain a copy of the License at
79f25b7fdf216c9ef0bd2322cd223eeaf0d60f77fJeff Brown *
89f25b7fdf216c9ef0bd2322cd223eeaf0d60f77fJeff Brown *      http://www.apache.org/licenses/LICENSE-2.0
99f25b7fdf216c9ef0bd2322cd223eeaf0d60f77fJeff Brown *
109f25b7fdf216c9ef0bd2322cd223eeaf0d60f77fJeff Brown * Unless required by applicable law or agreed to in writing, software
119f25b7fdf216c9ef0bd2322cd223eeaf0d60f77fJeff Brown * distributed under the License is distributed on an "AS IS" BASIS,
129f25b7fdf216c9ef0bd2322cd223eeaf0d60f77fJeff Brown * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
139f25b7fdf216c9ef0bd2322cd223eeaf0d60f77fJeff Brown * See the License for the specific language governing permissions and
149f25b7fdf216c9ef0bd2322cd223eeaf0d60f77fJeff Brown * limitations under the License.
159f25b7fdf216c9ef0bd2322cd223eeaf0d60f77fJeff Brown */
169f25b7fdf216c9ef0bd2322cd223eeaf0d60f77fJeff Brown
179f25b7fdf216c9ef0bd2322cd223eeaf0d60f77fJeff Brown#define LOG_TAG "InputDevice"
189f25b7fdf216c9ef0bd2322cd223eeaf0d60f77fJeff Brown
199f25b7fdf216c9ef0bd2322cd223eeaf0d60f77fJeff Brown#include <stdlib.h>
209f25b7fdf216c9ef0bd2322cd223eeaf0d60f77fJeff Brown#include <unistd.h>
219f25b7fdf216c9ef0bd2322cd223eeaf0d60f77fJeff Brown#include <ctype.h>
229f25b7fdf216c9ef0bd2322cd223eeaf0d60f77fJeff Brown
239f25b7fdf216c9ef0bd2322cd223eeaf0d60f77fJeff Brown#include <androidfw/InputDevice.h>
249f25b7fdf216c9ef0bd2322cd223eeaf0d60f77fJeff Brown
259f25b7fdf216c9ef0bd2322cd223eeaf0d60f77fJeff Brownnamespace android {
269f25b7fdf216c9ef0bd2322cd223eeaf0d60f77fJeff Brown
279f25b7fdf216c9ef0bd2322cd223eeaf0d60f77fJeff Brownstatic const char* CONFIGURATION_FILE_DIR[] = {
289f25b7fdf216c9ef0bd2322cd223eeaf0d60f77fJeff Brown        "idc/",
299f25b7fdf216c9ef0bd2322cd223eeaf0d60f77fJeff Brown        "keylayout/",
309f25b7fdf216c9ef0bd2322cd223eeaf0d60f77fJeff Brown        "keychars/",
319f25b7fdf216c9ef0bd2322cd223eeaf0d60f77fJeff Brown};
329f25b7fdf216c9ef0bd2322cd223eeaf0d60f77fJeff Brown
339f25b7fdf216c9ef0bd2322cd223eeaf0d60f77fJeff Brownstatic const char* CONFIGURATION_FILE_EXTENSION[] = {
349f25b7fdf216c9ef0bd2322cd223eeaf0d60f77fJeff Brown        ".idc",
359f25b7fdf216c9ef0bd2322cd223eeaf0d60f77fJeff Brown        ".kl",
369f25b7fdf216c9ef0bd2322cd223eeaf0d60f77fJeff Brown        ".kcm",
379f25b7fdf216c9ef0bd2322cd223eeaf0d60f77fJeff Brown};
389f25b7fdf216c9ef0bd2322cd223eeaf0d60f77fJeff Brown
399f25b7fdf216c9ef0bd2322cd223eeaf0d60f77fJeff Brownstatic bool isValidNameChar(char ch) {
409f25b7fdf216c9ef0bd2322cd223eeaf0d60f77fJeff Brown    return isascii(ch) && (isdigit(ch) || isalpha(ch) || ch == '-' || ch == '_');
419f25b7fdf216c9ef0bd2322cd223eeaf0d60f77fJeff Brown}
429f25b7fdf216c9ef0bd2322cd223eeaf0d60f77fJeff Brown
439f25b7fdf216c9ef0bd2322cd223eeaf0d60f77fJeff Brownstatic void appendInputDeviceConfigurationFileRelativePath(String8& path,
449f25b7fdf216c9ef0bd2322cd223eeaf0d60f77fJeff Brown        const String8& name, InputDeviceConfigurationFileType type) {
459f25b7fdf216c9ef0bd2322cd223eeaf0d60f77fJeff Brown    path.append(CONFIGURATION_FILE_DIR[type]);
469f25b7fdf216c9ef0bd2322cd223eeaf0d60f77fJeff Brown    for (size_t i = 0; i < name.length(); i++) {
479f25b7fdf216c9ef0bd2322cd223eeaf0d60f77fJeff Brown        char ch = name[i];
489f25b7fdf216c9ef0bd2322cd223eeaf0d60f77fJeff Brown        if (!isValidNameChar(ch)) {
499f25b7fdf216c9ef0bd2322cd223eeaf0d60f77fJeff Brown            ch = '_';
509f25b7fdf216c9ef0bd2322cd223eeaf0d60f77fJeff Brown        }
519f25b7fdf216c9ef0bd2322cd223eeaf0d60f77fJeff Brown        path.append(&ch, 1);
529f25b7fdf216c9ef0bd2322cd223eeaf0d60f77fJeff Brown    }
539f25b7fdf216c9ef0bd2322cd223eeaf0d60f77fJeff Brown    path.append(CONFIGURATION_FILE_EXTENSION[type]);
549f25b7fdf216c9ef0bd2322cd223eeaf0d60f77fJeff Brown}
559f25b7fdf216c9ef0bd2322cd223eeaf0d60f77fJeff Brown
569f25b7fdf216c9ef0bd2322cd223eeaf0d60f77fJeff BrownString8 getInputDeviceConfigurationFilePathByDeviceIdentifier(
579f25b7fdf216c9ef0bd2322cd223eeaf0d60f77fJeff Brown        const InputDeviceIdentifier& deviceIdentifier,
589f25b7fdf216c9ef0bd2322cd223eeaf0d60f77fJeff Brown        InputDeviceConfigurationFileType type) {
599f25b7fdf216c9ef0bd2322cd223eeaf0d60f77fJeff Brown    if (deviceIdentifier.vendor !=0 && deviceIdentifier.product != 0) {
609f25b7fdf216c9ef0bd2322cd223eeaf0d60f77fJeff Brown        if (deviceIdentifier.version != 0) {
619f25b7fdf216c9ef0bd2322cd223eeaf0d60f77fJeff Brown            // Try vendor product version.
629f25b7fdf216c9ef0bd2322cd223eeaf0d60f77fJeff Brown            String8 versionPath(getInputDeviceConfigurationFilePathByName(
639f25b7fdf216c9ef0bd2322cd223eeaf0d60f77fJeff Brown                    String8::format("Vendor_%04x_Product_%04x_Version_%04x",
649f25b7fdf216c9ef0bd2322cd223eeaf0d60f77fJeff Brown                            deviceIdentifier.vendor, deviceIdentifier.product,
659f25b7fdf216c9ef0bd2322cd223eeaf0d60f77fJeff Brown                            deviceIdentifier.version),
669f25b7fdf216c9ef0bd2322cd223eeaf0d60f77fJeff Brown                    type));
679f25b7fdf216c9ef0bd2322cd223eeaf0d60f77fJeff Brown            if (!versionPath.isEmpty()) {
689f25b7fdf216c9ef0bd2322cd223eeaf0d60f77fJeff Brown                return versionPath;
699f25b7fdf216c9ef0bd2322cd223eeaf0d60f77fJeff Brown            }
709f25b7fdf216c9ef0bd2322cd223eeaf0d60f77fJeff Brown        }
719f25b7fdf216c9ef0bd2322cd223eeaf0d60f77fJeff Brown
729f25b7fdf216c9ef0bd2322cd223eeaf0d60f77fJeff Brown        // Try vendor product.
739f25b7fdf216c9ef0bd2322cd223eeaf0d60f77fJeff Brown        String8 productPath(getInputDeviceConfigurationFilePathByName(
749f25b7fdf216c9ef0bd2322cd223eeaf0d60f77fJeff Brown                String8::format("Vendor_%04x_Product_%04x",
759f25b7fdf216c9ef0bd2322cd223eeaf0d60f77fJeff Brown                        deviceIdentifier.vendor, deviceIdentifier.product),
769f25b7fdf216c9ef0bd2322cd223eeaf0d60f77fJeff Brown                type));
779f25b7fdf216c9ef0bd2322cd223eeaf0d60f77fJeff Brown        if (!productPath.isEmpty()) {
789f25b7fdf216c9ef0bd2322cd223eeaf0d60f77fJeff Brown            return productPath;
799f25b7fdf216c9ef0bd2322cd223eeaf0d60f77fJeff Brown        }
809f25b7fdf216c9ef0bd2322cd223eeaf0d60f77fJeff Brown    }
819f25b7fdf216c9ef0bd2322cd223eeaf0d60f77fJeff Brown
829f25b7fdf216c9ef0bd2322cd223eeaf0d60f77fJeff Brown    // Try device name.
839f25b7fdf216c9ef0bd2322cd223eeaf0d60f77fJeff Brown    return getInputDeviceConfigurationFilePathByName(deviceIdentifier.name, type);
849f25b7fdf216c9ef0bd2322cd223eeaf0d60f77fJeff Brown}
859f25b7fdf216c9ef0bd2322cd223eeaf0d60f77fJeff Brown
869f25b7fdf216c9ef0bd2322cd223eeaf0d60f77fJeff BrownString8 getInputDeviceConfigurationFilePathByName(
879f25b7fdf216c9ef0bd2322cd223eeaf0d60f77fJeff Brown        const String8& name, InputDeviceConfigurationFileType type) {
889f25b7fdf216c9ef0bd2322cd223eeaf0d60f77fJeff Brown    // Search system repository.
899f25b7fdf216c9ef0bd2322cd223eeaf0d60f77fJeff Brown    String8 path;
909f25b7fdf216c9ef0bd2322cd223eeaf0d60f77fJeff Brown    path.setTo(getenv("ANDROID_ROOT"));
919f25b7fdf216c9ef0bd2322cd223eeaf0d60f77fJeff Brown    path.append("/usr/");
929f25b7fdf216c9ef0bd2322cd223eeaf0d60f77fJeff Brown    appendInputDeviceConfigurationFileRelativePath(path, name, type);
939f25b7fdf216c9ef0bd2322cd223eeaf0d60f77fJeff Brown#if DEBUG_PROBE
949f25b7fdf216c9ef0bd2322cd223eeaf0d60f77fJeff Brown    ALOGD("Probing for system provided input device configuration file: path='%s'", path.string());
959f25b7fdf216c9ef0bd2322cd223eeaf0d60f77fJeff Brown#endif
969f25b7fdf216c9ef0bd2322cd223eeaf0d60f77fJeff Brown    if (!access(path.string(), R_OK)) {
979f25b7fdf216c9ef0bd2322cd223eeaf0d60f77fJeff Brown#if DEBUG_PROBE
989f25b7fdf216c9ef0bd2322cd223eeaf0d60f77fJeff Brown        ALOGD("Found");
999f25b7fdf216c9ef0bd2322cd223eeaf0d60f77fJeff Brown#endif
1009f25b7fdf216c9ef0bd2322cd223eeaf0d60f77fJeff Brown        return path;
1019f25b7fdf216c9ef0bd2322cd223eeaf0d60f77fJeff Brown    }
1029f25b7fdf216c9ef0bd2322cd223eeaf0d60f77fJeff Brown
1039f25b7fdf216c9ef0bd2322cd223eeaf0d60f77fJeff Brown    // Search user repository.
1049f25b7fdf216c9ef0bd2322cd223eeaf0d60f77fJeff Brown    // TODO Should only look here if not in safe mode.
1059f25b7fdf216c9ef0bd2322cd223eeaf0d60f77fJeff Brown    path.setTo(getenv("ANDROID_DATA"));
1069f25b7fdf216c9ef0bd2322cd223eeaf0d60f77fJeff Brown    path.append("/system/devices/");
1079f25b7fdf216c9ef0bd2322cd223eeaf0d60f77fJeff Brown    appendInputDeviceConfigurationFileRelativePath(path, name, type);
1089f25b7fdf216c9ef0bd2322cd223eeaf0d60f77fJeff Brown#if DEBUG_PROBE
1099f25b7fdf216c9ef0bd2322cd223eeaf0d60f77fJeff Brown    ALOGD("Probing for system user input device configuration file: path='%s'", path.string());
1109f25b7fdf216c9ef0bd2322cd223eeaf0d60f77fJeff Brown#endif
1119f25b7fdf216c9ef0bd2322cd223eeaf0d60f77fJeff Brown    if (!access(path.string(), R_OK)) {
1129f25b7fdf216c9ef0bd2322cd223eeaf0d60f77fJeff Brown#if DEBUG_PROBE
1139f25b7fdf216c9ef0bd2322cd223eeaf0d60f77fJeff Brown        ALOGD("Found");
1149f25b7fdf216c9ef0bd2322cd223eeaf0d60f77fJeff Brown#endif
1159f25b7fdf216c9ef0bd2322cd223eeaf0d60f77fJeff Brown        return path;
1169f25b7fdf216c9ef0bd2322cd223eeaf0d60f77fJeff Brown    }
1179f25b7fdf216c9ef0bd2322cd223eeaf0d60f77fJeff Brown
1189f25b7fdf216c9ef0bd2322cd223eeaf0d60f77fJeff Brown    // Not found.
1199f25b7fdf216c9ef0bd2322cd223eeaf0d60f77fJeff Brown#if DEBUG_PROBE
1209f25b7fdf216c9ef0bd2322cd223eeaf0d60f77fJeff Brown    ALOGD("Probe failed to find input device configuration file: name='%s', type=%d",
1219f25b7fdf216c9ef0bd2322cd223eeaf0d60f77fJeff Brown            name.string(), type);
1229f25b7fdf216c9ef0bd2322cd223eeaf0d60f77fJeff Brown#endif
1239f25b7fdf216c9ef0bd2322cd223eeaf0d60f77fJeff Brown    return String8();
1249f25b7fdf216c9ef0bd2322cd223eeaf0d60f77fJeff Brown}
1259f25b7fdf216c9ef0bd2322cd223eeaf0d60f77fJeff Brown
1269f25b7fdf216c9ef0bd2322cd223eeaf0d60f77fJeff Brown
1279f25b7fdf216c9ef0bd2322cd223eeaf0d60f77fJeff Brown// --- InputDeviceInfo ---
1289f25b7fdf216c9ef0bd2322cd223eeaf0d60f77fJeff Brown
1299f25b7fdf216c9ef0bd2322cd223eeaf0d60f77fJeff BrownInputDeviceInfo::InputDeviceInfo() {
130daa3753a04699724d2cfe824ac1f5a266d643a05Jeff Brown    initialize(-1, -1, InputDeviceIdentifier(), String8(), false);
1319f25b7fdf216c9ef0bd2322cd223eeaf0d60f77fJeff Brown}
1329f25b7fdf216c9ef0bd2322cd223eeaf0d60f77fJeff Brown
1339f25b7fdf216c9ef0bd2322cd223eeaf0d60f77fJeff BrownInputDeviceInfo::InputDeviceInfo(const InputDeviceInfo& other) :
1345bbd4b4f5fc19302fa017ad6afee6eb2d489d91aJeff Brown        mId(other.mId), mGeneration(other.mGeneration), mIdentifier(other.mIdentifier),
135daa3753a04699724d2cfe824ac1f5a266d643a05Jeff Brown        mAlias(other.mAlias), mIsExternal(other.mIsExternal), mSources(other.mSources),
1369f25b7fdf216c9ef0bd2322cd223eeaf0d60f77fJeff Brown        mKeyboardType(other.mKeyboardType),
1379f25b7fdf216c9ef0bd2322cd223eeaf0d60f77fJeff Brown        mKeyCharacterMap(other.mKeyCharacterMap),
138a47425a13c19f95057df78b8bb65bb25657e8753Jeff Brown        mHasVibrator(other.mHasVibrator),
1399f25b7fdf216c9ef0bd2322cd223eeaf0d60f77fJeff Brown        mMotionRanges(other.mMotionRanges) {
1409f25b7fdf216c9ef0bd2322cd223eeaf0d60f77fJeff Brown}
1419f25b7fdf216c9ef0bd2322cd223eeaf0d60f77fJeff Brown
1429f25b7fdf216c9ef0bd2322cd223eeaf0d60f77fJeff BrownInputDeviceInfo::~InputDeviceInfo() {
1439f25b7fdf216c9ef0bd2322cd223eeaf0d60f77fJeff Brown}
1449f25b7fdf216c9ef0bd2322cd223eeaf0d60f77fJeff Brown
145af9e8d38184c6ba4d2d3eb5bde7014a66dd8a78bJeff Brownvoid InputDeviceInfo::initialize(int32_t id, int32_t generation,
146daa3753a04699724d2cfe824ac1f5a266d643a05Jeff Brown        const InputDeviceIdentifier& identifier, const String8& alias, bool isExternal) {
1479f25b7fdf216c9ef0bd2322cd223eeaf0d60f77fJeff Brown    mId = id;
148af9e8d38184c6ba4d2d3eb5bde7014a66dd8a78bJeff Brown    mGeneration = generation;
1495bbd4b4f5fc19302fa017ad6afee6eb2d489d91aJeff Brown    mIdentifier = identifier;
1505bbd4b4f5fc19302fa017ad6afee6eb2d489d91aJeff Brown    mAlias = alias;
151daa3753a04699724d2cfe824ac1f5a266d643a05Jeff Brown    mIsExternal = isExternal;
1529f25b7fdf216c9ef0bd2322cd223eeaf0d60f77fJeff Brown    mSources = 0;
1539f25b7fdf216c9ef0bd2322cd223eeaf0d60f77fJeff Brown    mKeyboardType = AINPUT_KEYBOARD_TYPE_NONE;
154a47425a13c19f95057df78b8bb65bb25657e8753Jeff Brown    mHasVibrator = false;
1559f25b7fdf216c9ef0bd2322cd223eeaf0d60f77fJeff Brown    mMotionRanges.clear();
1569f25b7fdf216c9ef0bd2322cd223eeaf0d60f77fJeff Brown}
1579f25b7fdf216c9ef0bd2322cd223eeaf0d60f77fJeff Brown
1589f25b7fdf216c9ef0bd2322cd223eeaf0d60f77fJeff Brownconst InputDeviceInfo::MotionRange* InputDeviceInfo::getMotionRange(
1599f25b7fdf216c9ef0bd2322cd223eeaf0d60f77fJeff Brown        int32_t axis, uint32_t source) const {
1609f25b7fdf216c9ef0bd2322cd223eeaf0d60f77fJeff Brown    size_t numRanges = mMotionRanges.size();
1619f25b7fdf216c9ef0bd2322cd223eeaf0d60f77fJeff Brown    for (size_t i = 0; i < numRanges; i++) {
1629f25b7fdf216c9ef0bd2322cd223eeaf0d60f77fJeff Brown        const MotionRange& range = mMotionRanges.itemAt(i);
1639f25b7fdf216c9ef0bd2322cd223eeaf0d60f77fJeff Brown        if (range.axis == axis && range.source == source) {
1649f25b7fdf216c9ef0bd2322cd223eeaf0d60f77fJeff Brown            return &range;
1659f25b7fdf216c9ef0bd2322cd223eeaf0d60f77fJeff Brown        }
1669f25b7fdf216c9ef0bd2322cd223eeaf0d60f77fJeff Brown    }
1679f25b7fdf216c9ef0bd2322cd223eeaf0d60f77fJeff Brown    return NULL;
1689f25b7fdf216c9ef0bd2322cd223eeaf0d60f77fJeff Brown}
1699f25b7fdf216c9ef0bd2322cd223eeaf0d60f77fJeff Brown
1709f25b7fdf216c9ef0bd2322cd223eeaf0d60f77fJeff Brownvoid InputDeviceInfo::addSource(uint32_t source) {
1719f25b7fdf216c9ef0bd2322cd223eeaf0d60f77fJeff Brown    mSources |= source;
1729f25b7fdf216c9ef0bd2322cd223eeaf0d60f77fJeff Brown}
1739f25b7fdf216c9ef0bd2322cd223eeaf0d60f77fJeff Brown
1749f25b7fdf216c9ef0bd2322cd223eeaf0d60f77fJeff Brownvoid InputDeviceInfo::addMotionRange(int32_t axis, uint32_t source, float min, float max,
1759f25b7fdf216c9ef0bd2322cd223eeaf0d60f77fJeff Brown        float flat, float fuzz) {
1769f25b7fdf216c9ef0bd2322cd223eeaf0d60f77fJeff Brown    MotionRange range = { axis, source, min, max, flat, fuzz };
1779f25b7fdf216c9ef0bd2322cd223eeaf0d60f77fJeff Brown    mMotionRanges.add(range);
1789f25b7fdf216c9ef0bd2322cd223eeaf0d60f77fJeff Brown}
1799f25b7fdf216c9ef0bd2322cd223eeaf0d60f77fJeff Brown
1809f25b7fdf216c9ef0bd2322cd223eeaf0d60f77fJeff Brownvoid InputDeviceInfo::addMotionRange(const MotionRange& range) {
1819f25b7fdf216c9ef0bd2322cd223eeaf0d60f77fJeff Brown    mMotionRanges.add(range);
1829f25b7fdf216c9ef0bd2322cd223eeaf0d60f77fJeff Brown}
1839f25b7fdf216c9ef0bd2322cd223eeaf0d60f77fJeff Brown
1849f25b7fdf216c9ef0bd2322cd223eeaf0d60f77fJeff Brown} // namespace android
185