Fetch country code information from Device sysfs path
HID devices report the country code via sysfs. Need to read it
and pass it and save it as a member variable to InputDevice
In subsequent CLs will use it to auto-detect a layout for PK.
More information in DD: go/pk_auto_layout_detection
Test: atest inputflinger_tests:InputReaderTest
Bug: 242715614
Change-Id: I73ca7518dbee3e563c41024bb3ed41261c8d7846
diff --git a/include/input/InputDevice.h b/include/input/InputDevice.h
index 3585392..d51d6a7 100644
--- a/include/input/InputDevice.h
+++ b/include/input/InputDevice.h
@@ -23,6 +23,8 @@
#include <unordered_map>
#include <vector>
+#include "android/hardware/input/InputDeviceCountryCode.h"
+
namespace android {
/*
@@ -210,8 +212,10 @@
};
void initialize(int32_t id, int32_t generation, int32_t controllerNumber,
- const InputDeviceIdentifier& identifier, const std::string& alias, bool isExternal,
- bool hasMic);
+ const InputDeviceIdentifier& identifier, const std::string& alias,
+ bool isExternal, bool hasMic,
+ hardware::input::InputDeviceCountryCode countryCode =
+ hardware::input::InputDeviceCountryCode::INVALID);
inline int32_t getId() const { return mId; }
inline int32_t getControllerNumber() const { return mControllerNumber; }
@@ -223,6 +227,7 @@
}
inline bool isExternal() const { return mIsExternal; }
inline bool hasMic() const { return mHasMic; }
+ inline hardware::input::InputDeviceCountryCode getCountryCode() const { return mCountryCode; }
inline uint32_t getSources() const { return mSources; }
const MotionRange* getMotionRange(int32_t axis, uint32_t source) const;
@@ -274,9 +279,11 @@
std::string mAlias;
bool mIsExternal;
bool mHasMic;
+ hardware::input::InputDeviceCountryCode mCountryCode;
uint32_t mSources;
int32_t mKeyboardType;
std::shared_ptr<KeyCharacterMap> mKeyCharacterMap;
+
bool mHasVibrator;
bool mHasBattery;
bool mHasButtonUnderPad;
diff --git a/libs/input/Android.bp b/libs/input/Android.bp
index 5030d60..29e02cf 100644
--- a/libs/input/Android.bp
+++ b/libs/input/Android.bp
@@ -26,6 +26,7 @@
filegroup {
name: "inputconstants_aidl",
srcs: [
+ "android/hardware/input/InputDeviceCountryCode.aidl",
"android/os/IInputConstants.aidl",
"android/os/InputEventInjectionResult.aidl",
"android/os/InputEventInjectionSync.aidl",
diff --git a/libs/input/InputDevice.cpp b/libs/input/InputDevice.cpp
index a908969..3fe03c7 100644
--- a/libs/input/InputDevice.cpp
+++ b/libs/input/InputDevice.cpp
@@ -26,6 +26,7 @@
#include <input/InputEventLabels.h>
using android::base::StringPrintf;
+using android::hardware::input::InputDeviceCountryCode;
namespace android {
@@ -177,6 +178,7 @@
mAlias(other.mAlias),
mIsExternal(other.mIsExternal),
mHasMic(other.mHasMic),
+ mCountryCode(other.mCountryCode),
mSources(other.mSources),
mKeyboardType(other.mKeyboardType),
mKeyCharacterMap(other.mKeyCharacterMap),
@@ -192,8 +194,8 @@
}
void InputDeviceInfo::initialize(int32_t id, int32_t generation, int32_t controllerNumber,
- const InputDeviceIdentifier& identifier, const std::string& alias, bool isExternal,
- bool hasMic) {
+ const InputDeviceIdentifier& identifier, const std::string& alias,
+ bool isExternal, bool hasMic, InputDeviceCountryCode countryCode) {
mId = id;
mGeneration = generation;
mControllerNumber = controllerNumber;
@@ -201,6 +203,7 @@
mAlias = alias;
mIsExternal = isExternal;
mHasMic = hasMic;
+ mCountryCode = countryCode;
mSources = 0;
mKeyboardType = AINPUT_KEYBOARD_TYPE_NONE;
mHasVibrator = false;
diff --git a/libs/input/android/hardware/input/InputDeviceCountryCode.aidl b/libs/input/android/hardware/input/InputDeviceCountryCode.aidl
new file mode 100644
index 0000000..6bb1a60
--- /dev/null
+++ b/libs/input/android/hardware/input/InputDeviceCountryCode.aidl
@@ -0,0 +1,212 @@
+/*
+ * Copyright (C) 2022 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.
+ */
+
+package android.hardware.input;
+
+/**
+ * Constant for HID country code declared by a HID device. These constants are declared as AIDL to
+ * be used by java and native input code.
+ *
+ * @hide
+ */
+@Backing(type="int")
+enum InputDeviceCountryCode {
+ /**
+ * Used as default value where country code is not set in the device HID descriptor
+ */
+ INVALID = -1,
+
+ /**
+ * Used as default value when country code is not supported by the HID device. The HID
+ * descriptor sets "00" as the country code in this case.
+ */
+ NOT_SUPPORTED = 0,
+
+ /**
+ * Arabic
+ */
+ ARABIC = 1,
+
+ /**
+ * Belgian
+ */
+ BELGIAN = 2,
+
+ /**
+ * Canadian (Bilingual)
+ */
+ CANADIAN_BILINGUAL = 3,
+
+ /**
+ * Canadian (French)
+ */
+ CANADIAN_FRENCH = 4,
+
+ /**
+ * Czech Republic
+ */
+ CZECH_REPUBLIC = 5,
+
+ /**
+ * Danish
+ */
+ DANISH = 6,
+
+ /**
+ * Finnish
+ */
+ FINNISH = 7,
+
+ /**
+ * French
+ */
+ FRENCH = 8,
+
+ /**
+ * German
+ */
+ GERMAN = 9,
+
+ /**
+ * Greek
+ */
+ GREEK = 10,
+
+ /**
+ * Hebrew
+ */
+ HEBREW = 11,
+
+ /**
+ * Hungary
+ */
+ HUNGARY = 12,
+
+ /**
+ * International (ISO)
+ */
+ INTERNATIONAL = 13,
+
+ /**
+ * Italian
+ */
+ ITALIAN = 14,
+
+ /**
+ * Japan (Katakana)
+ */
+ JAPAN = 15,
+
+ /**
+ * Korean
+ */
+ KOREAN = 16,
+
+ /**
+ * Latin American
+ */
+ LATIN_AMERICAN = 17,
+
+ /**
+ * Netherlands (Dutch)
+ */
+ DUTCH = 18,
+
+ /**
+ * Norwegian
+ */
+ NORWEGIAN = 19,
+
+ /**
+ * Persian
+ */
+ PERSIAN = 20,
+
+ /**
+ * Poland
+ */
+ POLAND = 21,
+
+ /**
+ * Portuguese
+ */
+ PORTUGUESE = 22,
+
+ /**
+ * Russia
+ */
+ RUSSIA = 23,
+
+ /**
+ * Slovakia
+ */
+ SLOVAKIA = 24,
+
+ /**
+ * Spanish
+ */
+ SPANISH = 25,
+
+ /**
+ * Swedish
+ */
+ SWEDISH = 26,
+
+ /**
+ * Swiss (French)
+ */
+ SWISS_FRENCH = 27,
+
+ /**
+ * Swiss (German)
+ */
+ SWISS_GERMAN = 28,
+
+ /**
+ * Switzerland
+ */
+ SWITZERLAND = 29,
+
+ /**
+ * Taiwan
+ */
+ TAIWAN = 30,
+
+ /**
+ * Turkish_Q
+ */
+ TURKISH_Q = 31,
+
+ /**
+ * UK
+ */
+ UK = 32,
+
+ /**
+ * US
+ */
+ US = 33,
+
+ /**
+ * Yugoslavia
+ */
+ YUGOSLAVIA = 34,
+
+ /**
+ * Turkish_F
+ */
+ TURKISH_F = 35,
+}
\ No newline at end of file
diff --git a/services/inputflinger/reader/EventHub.cpp b/services/inputflinger/reader/EventHub.cpp
index 06a38c8..336763c 100644
--- a/services/inputflinger/reader/EventHub.cpp
+++ b/services/inputflinger/reader/EventHub.cpp
@@ -61,6 +61,7 @@
#define INDENT3 " "
using android::base::StringPrintf;
+using android::hardware::input::InputDeviceCountryCode;
namespace android {
@@ -302,6 +303,24 @@
}
/**
+ * Read country code information exposed through the sysfs path.
+ */
+static InputDeviceCountryCode readCountryCodeLocked(const std::filesystem::path& sysfsRootPath) {
+ // Check the sysfs root path
+ int hidCountryCode = static_cast<int>(InputDeviceCountryCode::INVALID);
+ std::string str;
+ if (base::ReadFileToString(sysfsRootPath / "country", &str)) {
+ hidCountryCode = std::stoi(str, nullptr, 16);
+ LOG_ALWAYS_FATAL_IF(hidCountryCode > 35 || hidCountryCode < 0,
+ "HID country code should be in range [0, 35]. Found country code "
+ "to be %d",
+ hidCountryCode);
+ }
+
+ return static_cast<InputDeviceCountryCode>(hidCountryCode);
+}
+
+/**
* Read information about batteries exposed through the sysfs path.
*/
static std::unordered_map<int32_t /*batteryId*/, RawBatteryInfo> readBatteryConfiguration(
@@ -1238,6 +1257,15 @@
}
}
+InputDeviceCountryCode EventHub::getCountryCode(int32_t deviceId) const {
+ std::scoped_lock _l(mLock);
+ Device* device = getDeviceLocked(deviceId);
+ if (device == nullptr || !device->associatedDevice) {
+ return InputDeviceCountryCode::INVALID;
+ }
+ return device->associatedDevice->countryCode;
+}
+
void EventHub::setExcludedDevices(const std::vector<std::string>& devices) {
std::scoped_lock _l(mLock);
@@ -1384,6 +1412,7 @@
return std::make_shared<AssociatedDevice>(
AssociatedDevice{.sysfsRootPath = path,
+ .countryCode = readCountryCodeLocked(path),
.batteryInfos = readBatteryConfiguration(path),
.lightInfos = readLightsConfiguration(path)});
}
@@ -2553,6 +2582,9 @@
device->keyMap.keyLayoutFile.c_str());
dump += StringPrintf(INDENT3 "KeyCharacterMapFile: %s\n",
device->keyMap.keyCharacterMapFile.c_str());
+ dump += StringPrintf(INDENT3 "CountryCode: %d\n",
+ device->associatedDevice ? device->associatedDevice->countryCode
+ : InputDeviceCountryCode::INVALID);
dump += StringPrintf(INDENT3 "ConfigurationFile: %s\n",
device->configurationFile.c_str());
dump += StringPrintf(INDENT3 "VideoDevice: %s\n",
diff --git a/services/inputflinger/reader/InputDevice.cpp b/services/inputflinger/reader/InputDevice.cpp
index 5c9e63e..8eadcdc 100644
--- a/services/inputflinger/reader/InputDevice.cpp
+++ b/services/inputflinger/reader/InputDevice.cpp
@@ -35,6 +35,8 @@
#include "SwitchInputMapper.h"
#include "VibratorInputMapper.h"
+using android::hardware::input::InputDeviceCountryCode;
+
namespace android {
InputDevice::InputDevice(InputReaderContext* context, int32_t id, int32_t generation,
@@ -240,6 +242,7 @@
mSources = 0;
mClasses = ftl::Flags<InputDeviceClass>(0);
mControllerNumber = 0;
+ mCountryCode = InputDeviceCountryCode::INVALID;
for_each_subdevice([this](InputDeviceContext& context) {
mClasses |= context.getDeviceClasses();
@@ -251,6 +254,16 @@
}
mControllerNumber = controllerNumber;
}
+
+ InputDeviceCountryCode countryCode = context.getCountryCode();
+ if (countryCode != InputDeviceCountryCode::INVALID) {
+ if (mCountryCode != InputDeviceCountryCode::INVALID && mCountryCode != countryCode) {
+ ALOGW("InputDevice::configure(): %s device contains multiple unique country "
+ "codes",
+ getName().c_str());
+ }
+ mCountryCode = countryCode;
+ }
});
mIsExternal = mClasses.test(InputDeviceClass::EXTERNAL);
@@ -422,7 +435,7 @@
InputDeviceInfo InputDevice::getDeviceInfo() {
InputDeviceInfo outDeviceInfo;
outDeviceInfo.initialize(mId, mGeneration, mControllerNumber, mIdentifier, mAlias, mIsExternal,
- mHasMic);
+ mHasMic, mCountryCode);
for_each_mapper(
[&outDeviceInfo](InputMapper& mapper) { mapper.populateDeviceInfo(&outDeviceInfo); });
diff --git a/services/inputflinger/reader/include/EventHub.h b/services/inputflinger/reader/include/EventHub.h
index 8aec367..dfb98f1 100644
--- a/services/inputflinger/reader/include/EventHub.h
+++ b/services/inputflinger/reader/include/EventHub.h
@@ -43,6 +43,7 @@
#include "TouchVideoDevice.h"
#include "VibrationElement.h"
+#include "android/hardware/input/InputDeviceCountryCode.h"
struct inotify_event;
@@ -301,9 +302,9 @@
int32_t deviceId, int32_t lightId) const = 0;
virtual void setLightIntensities(int32_t deviceId, int32_t lightId,
std::unordered_map<LightColor, int32_t> intensities) = 0;
- /*
- * Query current input state.
- */
+ /* Query Country code associated with the input device. */
+ virtual hardware::input::InputDeviceCountryCode getCountryCode(int32_t deviceId) const = 0;
+ /* Query current input state. */
virtual int32_t getScanCodeState(int32_t deviceId, int32_t scanCode) const = 0;
virtual int32_t getKeyCodeState(int32_t deviceId, int32_t keyCode) const = 0;
virtual int32_t getSwitchState(int32_t deviceId, int32_t sw) const = 0;
@@ -483,6 +484,8 @@
void setLightIntensities(int32_t deviceId, int32_t lightId,
std::unordered_map<LightColor, int32_t> intensities) override final;
+ hardware::input::InputDeviceCountryCode getCountryCode(int32_t deviceId) const override final;
+
void setExcludedDevices(const std::vector<std::string>& devices) override final;
int32_t getScanCodeState(int32_t deviceId, int32_t scanCode) const override final;
@@ -544,7 +547,7 @@
struct AssociatedDevice {
// The sysfs root path of the misc device.
std::filesystem::path sysfsRootPath;
-
+ hardware::input::InputDeviceCountryCode countryCode;
std::unordered_map<int32_t /*batteryId*/, RawBatteryInfo> batteryInfos;
std::unordered_map<int32_t /*lightId*/, RawLightInfo> lightInfos;
};
diff --git a/services/inputflinger/reader/include/InputDevice.h b/services/inputflinger/reader/include/InputDevice.h
index 51872ac..141464f 100644
--- a/services/inputflinger/reader/include/InputDevice.h
+++ b/services/inputflinger/reader/include/InputDevice.h
@@ -158,6 +158,7 @@
int32_t mId;
int32_t mGeneration;
int32_t mControllerNumber;
+ hardware::input::InputDeviceCountryCode mCountryCode;
InputDeviceIdentifier mIdentifier;
std::string mAlias;
ftl::Flags<InputDeviceClass> mClasses;
@@ -311,6 +312,9 @@
}
inline std::vector<TouchVideoFrame> getVideoFrames() { return mEventHub->getVideoFrames(mId); }
+ inline hardware::input::InputDeviceCountryCode getCountryCode() const {
+ return mEventHub->getCountryCode(mId);
+ }
inline int32_t getScanCodeState(int32_t scanCode) const {
return mEventHub->getScanCodeState(mId, scanCode);
}
diff --git a/services/inputflinger/tests/InputReader_test.cpp b/services/inputflinger/tests/InputReader_test.cpp
index 9a0c565..ae98415 100644
--- a/services/inputflinger/tests/InputReader_test.cpp
+++ b/services/inputflinger/tests/InputReader_test.cpp
@@ -38,9 +38,12 @@
#include <gtest/gtest.h>
#include <gui/constants.h>
+#include "android/hardware/input/InputDeviceCountryCode.h"
#include "input/DisplayViewport.h"
#include "input/Input.h"
+using android::hardware::input::InputDeviceCountryCode;
+
namespace android {
using namespace ftl::flag_operators;
@@ -455,6 +458,7 @@
BitArray<MSC_MAX> mscBitmask;
std::vector<VirtualKeyDefinition> virtualKeys;
bool enabled;
+ InputDeviceCountryCode countryCode;
status_t enable() {
enabled = true;
@@ -584,6 +588,11 @@
device->keyCodeStates.replaceValueFor(keyCode, state);
}
+ void setCountryCode(int32_t deviceId, InputDeviceCountryCode countryCode) {
+ Device* device = getDevice(deviceId);
+ device->countryCode = countryCode;
+ }
+
void setScanCodeState(int32_t deviceId, int32_t scanCode, int32_t state) {
Device* device = getDevice(deviceId);
device->scanCodeStates.replaceValueFor(scanCode, state);
@@ -845,6 +854,14 @@
return AKEY_STATE_UNKNOWN;
}
+ InputDeviceCountryCode getCountryCode(int32_t deviceId) const override {
+ Device* device = getDevice(deviceId);
+ if (device) {
+ return device->countryCode;
+ }
+ return InputDeviceCountryCode::INVALID;
+ }
+
int32_t getKeyCodeState(int32_t deviceId, int32_t keyCode) const override {
Device* device = getDevice(deviceId);
if (device) {
@@ -2685,6 +2702,17 @@
ASSERT_EQ(ftl::Flags<InputDeviceClass>(0), mDevice->getClasses());
}
+TEST_F(InputDeviceTest, CountryCodeCorrectlyMapped) {
+ mFakeEventHub->setCountryCode(EVENTHUB_ID, InputDeviceCountryCode::INTERNATIONAL);
+
+ // Configuration
+ mDevice->addMapper<FakeInputMapper>(EVENTHUB_ID, AINPUT_SOURCE_KEYBOARD);
+ InputReaderConfiguration config;
+ mDevice->configure(ARBITRARY_TIME, &config, 0);
+
+ ASSERT_EQ(InputDeviceCountryCode::INTERNATIONAL, mDevice->getDeviceInfo().getCountryCode());
+}
+
TEST_F(InputDeviceTest, WhenDeviceCreated_EnabledIsFalse) {
ASSERT_EQ(mDevice->isEnabled(), false);
}