/* * Copyright (C) 2012 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #define LOG_TAG "InputDevice" #include #include #include #include #include #include #include #include #include using android::base::GetProperty; using android::base::StringPrintf; namespace android { // Set to true to log detailed debugging messages about IDC file probing. static constexpr bool DEBUG_PROBE = false; static const char* CONFIGURATION_FILE_DIR[] = { "idc/", "keylayout/", "keychars/", }; static const char* CONFIGURATION_FILE_EXTENSION[] = { ".idc", ".kl", ".kcm", }; static bool isValidNameChar(char ch) { return isascii(ch) && (isdigit(ch) || isalpha(ch) || ch == '-' || ch == '_'); } static void appendInputDeviceConfigurationFileRelativePath(std::string& path, const std::string& name, InputDeviceConfigurationFileType type) { path += CONFIGURATION_FILE_DIR[static_cast(type)]; path += name; path += CONFIGURATION_FILE_EXTENSION[static_cast(type)]; } std::string getInputDeviceConfigurationFilePathByDeviceIdentifier( const InputDeviceIdentifier& deviceIdentifier, InputDeviceConfigurationFileType type, const char* suffix) { if (deviceIdentifier.vendor !=0 && deviceIdentifier.product != 0) { if (deviceIdentifier.version != 0) { // Try vendor product version. std::string versionPath = getInputDeviceConfigurationFilePathByName(StringPrintf("Vendor_%04x_Product_%" "04x_Version_%04x%s", deviceIdentifier.vendor, deviceIdentifier.product, deviceIdentifier.version, suffix), type); if (!versionPath.empty()) { return versionPath; } } // Try vendor product. std::string productPath = getInputDeviceConfigurationFilePathByName(StringPrintf("Vendor_%04x_Product_%04x%s", deviceIdentifier.vendor, deviceIdentifier.product, suffix), type); if (!productPath.empty()) { return productPath; } } // Try device name. return getInputDeviceConfigurationFilePathByName(deviceIdentifier.getCanonicalName() + suffix, type); } std::string getInputDeviceConfigurationFilePathByName( const std::string& name, InputDeviceConfigurationFileType type) { // Search system repository. std::string path; // Treblized input device config files will be located /product/usr, /system_ext/usr, // /odm/usr or /vendor/usr. std::vector pathPrefixes{ "/product/usr/", "/system_ext/usr/", "/odm/usr/", "/vendor/usr/", }; // These files may also be in the APEX pointed by input_device.config_file.apex sysprop. if (auto apex = GetProperty("input_device.config_file.apex", ""); !apex.empty()) { pathPrefixes.push_back("/apex/" + apex + "/etc/usr/"); } // ANDROID_ROOT may not be set on host if (auto android_root = getenv("ANDROID_ROOT"); android_root != nullptr) { pathPrefixes.push_back(std::string(android_root) + "/usr/"); } for (const auto& prefix : pathPrefixes) { path = prefix; appendInputDeviceConfigurationFileRelativePath(path, name, type); if (!access(path.c_str(), R_OK)) { LOG_IF(INFO, DEBUG_PROBE) << "Found system-provided input device configuration file at " << path; return path; } else if (errno != ENOENT) { LOG(WARNING) << "Couldn't find a system-provided input device configuration file at " << path << " due to error " << errno << " (" << strerror(errno) << "); there may be an IDC file there that cannot be loaded."; } else { LOG_IF(ERROR, DEBUG_PROBE) << "Didn't find system-provided input device configuration file at " << path << ": " << strerror(errno); } } // Search user repository. // TODO Should only look here if not in safe mode. path = ""; char *androidData = getenv("ANDROID_DATA"); if (androidData != nullptr) { path += androidData; } path += "/system/devices/"; appendInputDeviceConfigurationFileRelativePath(path, name, type); if (!access(path.c_str(), R_OK)) { LOG_IF(INFO, DEBUG_PROBE) << "Found system user input device configuration file at " << path; return path; } else if (errno != ENOENT) { LOG(WARNING) << "Couldn't find a system user input device configuration file at " << path << " due to error " << errno << " (" << strerror(errno) << "); there may be an IDC file there that cannot be loaded."; } else { LOG_IF(ERROR, DEBUG_PROBE) << "Didn't find system user input device configuration file at " << path << ": " << strerror(errno); } // Not found. LOG_IF(INFO, DEBUG_PROBE) << "Probe failed to find input device configuration file with name '" << name << "' and type " << ftl::enum_string(type); return ""; } // --- InputDeviceIdentifier std::string InputDeviceIdentifier::getCanonicalName() const { std::string replacedName = name; for (char& ch : replacedName) { if (!isValidNameChar(ch)) { ch = '_'; } } return replacedName; } // --- InputDeviceInfo --- InputDeviceInfo::InputDeviceInfo() { initialize(-1, 0, -1, InputDeviceIdentifier(), "", false, false, ui::LogicalDisplayId::INVALID); } InputDeviceInfo::InputDeviceInfo(const InputDeviceInfo& other) : mId(other.mId), mGeneration(other.mGeneration), mControllerNumber(other.mControllerNumber), mIdentifier(other.mIdentifier), mAlias(other.mAlias), mIsExternal(other.mIsExternal), mHasMic(other.mHasMic), mKeyboardLayoutInfo(other.mKeyboardLayoutInfo), mSources(other.mSources), mKeyboardType(other.mKeyboardType), mKeyCharacterMap(other.mKeyCharacterMap ? std::make_unique(*other.mKeyCharacterMap) : nullptr), mUsiVersion(other.mUsiVersion), mAssociatedDisplayId(other.mAssociatedDisplayId), mEnabled(other.mEnabled), mHasVibrator(other.mHasVibrator), mHasBattery(other.mHasBattery), mHasButtonUnderPad(other.mHasButtonUnderPad), mHasSensor(other.mHasSensor), mMotionRanges(other.mMotionRanges), mSensors(other.mSensors), mLights(other.mLights), mViewBehavior(other.mViewBehavior) {} InputDeviceInfo& InputDeviceInfo::operator=(const InputDeviceInfo& other) { mId = other.mId; mGeneration = other.mGeneration; mControllerNumber = other.mControllerNumber; mIdentifier = other.mIdentifier; mAlias = other.mAlias; mIsExternal = other.mIsExternal; mHasMic = other.mHasMic; mKeyboardLayoutInfo = other.mKeyboardLayoutInfo; mSources = other.mSources; mKeyboardType = other.mKeyboardType; mKeyCharacterMap = other.mKeyCharacterMap ? std::make_unique(*other.mKeyCharacterMap) : nullptr; mUsiVersion = other.mUsiVersion; mAssociatedDisplayId = other.mAssociatedDisplayId; mEnabled = other.mEnabled; mHasVibrator = other.mHasVibrator; mHasBattery = other.mHasBattery; mHasButtonUnderPad = other.mHasButtonUnderPad; mHasSensor = other.mHasSensor; mMotionRanges = other.mMotionRanges; mSensors = other.mSensors; mLights = other.mLights; mViewBehavior = other.mViewBehavior; return *this; } InputDeviceInfo::~InputDeviceInfo() { } void InputDeviceInfo::initialize(int32_t id, int32_t generation, int32_t controllerNumber, const InputDeviceIdentifier& identifier, const std::string& alias, bool isExternal, bool hasMic, ui::LogicalDisplayId associatedDisplayId, InputDeviceViewBehavior viewBehavior, bool enabled) { mId = id; mGeneration = generation; mControllerNumber = controllerNumber; mIdentifier = identifier; mAlias = alias; mIsExternal = isExternal; mHasMic = hasMic; mSources = 0; mKeyboardType = AINPUT_KEYBOARD_TYPE_NONE; mAssociatedDisplayId = associatedDisplayId; mEnabled = enabled; mHasVibrator = false; mHasBattery = false; mHasButtonUnderPad = false; mHasSensor = false; mViewBehavior = viewBehavior; mUsiVersion.reset(); mMotionRanges.clear(); mSensors.clear(); mLights.clear(); } const InputDeviceInfo::MotionRange* InputDeviceInfo::getMotionRange( int32_t axis, uint32_t source) const { for (const MotionRange& range : mMotionRanges) { if (range.axis == axis && isFromSource(range.source, source)) { return ⦥ } } return nullptr; } void InputDeviceInfo::addSource(uint32_t source) { mSources |= source; } void InputDeviceInfo::addMotionRange(int32_t axis, uint32_t source, float min, float max, float flat, float fuzz, float resolution) { MotionRange range = { axis, source, min, max, flat, fuzz, resolution }; mMotionRanges.push_back(range); } void InputDeviceInfo::addMotionRange(const MotionRange& range) { mMotionRanges.push_back(range); } void InputDeviceInfo::addSensorInfo(const InputDeviceSensorInfo& info) { if (mSensors.find(info.type) != mSensors.end()) { ALOGW("Sensor type %s already exists, will be replaced by new sensor added.", ftl::enum_string(info.type).c_str()); } mSensors.insert_or_assign(info.type, info); } void InputDeviceInfo::addBatteryInfo(const InputDeviceBatteryInfo& info) { if (mBatteries.find(info.id) != mBatteries.end()) { ALOGW("Battery id %d already exists, will be replaced by new battery added.", info.id); } mBatteries.insert_or_assign(info.id, info); } void InputDeviceInfo::addLightInfo(const InputDeviceLightInfo& info) { if (mLights.find(info.id) != mLights.end()) { ALOGW("Light id %d already exists, will be replaced by new light added.", info.id); } mLights.insert_or_assign(info.id, info); } void InputDeviceInfo::setKeyboardType(int32_t keyboardType) { mKeyboardType = keyboardType; } void InputDeviceInfo::setKeyboardLayoutInfo(KeyboardLayoutInfo layoutInfo) { mKeyboardLayoutInfo = std::move(layoutInfo); } std::vector InputDeviceInfo::getSensors() { std::vector infos; infos.reserve(mSensors.size()); for (const auto& [type, info] : mSensors) { infos.push_back(info); } return infos; } std::vector InputDeviceInfo::getLights() { std::vector infos; infos.reserve(mLights.size()); for (const auto& [id, info] : mLights) { infos.push_back(info); } return infos; } } // namespace android