Implement KeyboardClassifier interface in rust

DD: go/project-imposter-android
This CL includes:
- Rust interface setup

Next CL to include:
- Basic categorization into alphabetic and non-alphabetic
- Updating categorization based on key presses

Test: atest --host libinput_rust_test
Test: atest inputflinger_tests
Bug: 263559234
Flag: com.android.input.flags.enable_keyboard_classifier_rust_impl
Change-Id: I52773be992ddd8efaa9546e0af8b0a78515d931c
diff --git a/services/inputflinger/reader/InputDevice.cpp b/services/inputflinger/reader/InputDevice.cpp
index b807b27..2b33403 100644
--- a/services/inputflinger/reader/InputDevice.cpp
+++ b/services/inputflinger/reader/InputDevice.cpp
@@ -237,6 +237,12 @@
     mIsExternal = mClasses.test(InputDeviceClass::EXTERNAL);
     mHasMic = mClasses.test(InputDeviceClass::MIC);
 
+    // Update keyboard type
+    if (mClasses.test(InputDeviceClass::KEYBOARD)) {
+        mContext->getKeyboardClassifier().notifyKeyboardChanged(mId, mIdentifier, mClasses.get());
+        mKeyboardType = mContext->getKeyboardClassifier().getKeyboardType(mId);
+    }
+
     using Change = InputReaderConfiguration::Change;
 
     if (!changes.any() || !isIgnored()) {
@@ -445,6 +451,7 @@
                              mHasMic,
                              getAssociatedDisplayId().value_or(ui::LogicalDisplayId::INVALID),
                              {mShouldSmoothScroll}, isEnabled());
+    outDeviceInfo.setKeyboardType(static_cast<int32_t>(mKeyboardType));
 
     for_each_mapper(
             [&outDeviceInfo](InputMapper& mapper) { mapper.populateDeviceInfo(outDeviceInfo); });
@@ -517,13 +524,9 @@
 
     // Keyboard-like devices.
     uint32_t keyboardSource = 0;
-    int32_t keyboardType = AINPUT_KEYBOARD_TYPE_NON_ALPHABETIC;
     if (classes.test(InputDeviceClass::KEYBOARD)) {
         keyboardSource |= AINPUT_SOURCE_KEYBOARD;
     }
-    if (classes.test(InputDeviceClass::ALPHAKEY)) {
-        keyboardType = AINPUT_KEYBOARD_TYPE_ALPHABETIC;
-    }
     if (classes.test(InputDeviceClass::DPAD)) {
         keyboardSource |= AINPUT_SOURCE_DPAD;
     }
@@ -532,8 +535,8 @@
     }
 
     if (keyboardSource != 0) {
-        mappers.push_back(createInputMapper<KeyboardInputMapper>(contextPtr, readerConfig,
-                                                                 keyboardSource, keyboardType));
+        mappers.push_back(
+                createInputMapper<KeyboardInputMapper>(contextPtr, readerConfig, keyboardSource));
     }
 
     // Cursor-like devices.
@@ -730,6 +733,13 @@
     return mController ? std::make_optional(mController->getEventHubId()) : std::nullopt;
 }
 
+void InputDevice::setKeyboardType(KeyboardType keyboardType) {
+    if (mKeyboardType != keyboardType) {
+        mKeyboardType = keyboardType;
+        bumpGeneration();
+    }
+}
+
 InputDeviceContext::InputDeviceContext(InputDevice& device, int32_t eventHubId)
       : mDevice(device),
         mContext(device.getContext()),
diff --git a/services/inputflinger/reader/InputReader.cpp b/services/inputflinger/reader/InputReader.cpp
index b9523ef..ab13ad4 100644
--- a/services/inputflinger/reader/InputReader.cpp
+++ b/services/inputflinger/reader/InputReader.cpp
@@ -102,6 +102,7 @@
         mEventHub(eventHub),
         mPolicy(policy),
         mNextListener(listener),
+        mKeyboardClassifier(std::make_unique<KeyboardClassifier>()),
         mGlobalMetaState(AMETA_NONE),
         mLedMetaState(AMETA_NONE),
         mGeneration(1),
@@ -1076,4 +1077,8 @@
     return mIdGenerator.nextId();
 }
 
+KeyboardClassifier& InputReader::ContextImpl::getKeyboardClassifier() {
+    return *mReader->mKeyboardClassifier;
+}
+
 } // namespace android
diff --git a/services/inputflinger/reader/include/EventHub.h b/services/inputflinger/reader/include/EventHub.h
index 39d2f5b..7cf584d 100644
--- a/services/inputflinger/reader/include/EventHub.h
+++ b/services/inputflinger/reader/include/EventHub.h
@@ -85,64 +85,67 @@
 
 /*
  * Input device classes.
+ *
+ * These classes are duplicated in rust side here: /frameworks/native/libs/input/rust/input.rs.
+ * If any new classes are added, we need to add them in rust input side too.
  */
 enum class InputDeviceClass : uint32_t {
     /* The input device is a keyboard or has buttons. */
-    KEYBOARD = 0x00000001,
+    KEYBOARD = android::os::IInputConstants::DEVICE_CLASS_KEYBOARD,
 
     /* The input device is an alpha-numeric keyboard (not just a dial pad). */
-    ALPHAKEY = 0x00000002,
+    ALPHAKEY = android::os::IInputConstants::DEVICE_CLASS_ALPHAKEY,
 
     /* The input device is a touchscreen or a touchpad (either single-touch or multi-touch). */
-    TOUCH = 0x00000004,
+    TOUCH = android::os::IInputConstants::DEVICE_CLASS_TOUCH,
 
     /* The input device is a cursor device such as a trackball or mouse. */
-    CURSOR = 0x00000008,
+    CURSOR = android::os::IInputConstants::DEVICE_CLASS_CURSOR,
 
     /* The input device is a multi-touch touchscreen or touchpad. */
-    TOUCH_MT = 0x00000010,
+    TOUCH_MT = android::os::IInputConstants::DEVICE_CLASS_TOUCH_MT,
 
     /* The input device is a directional pad (implies keyboard, has DPAD keys). */
-    DPAD = 0x00000020,
+    DPAD = android::os::IInputConstants::DEVICE_CLASS_DPAD,
 
     /* The input device is a gamepad (implies keyboard, has BUTTON keys). */
-    GAMEPAD = 0x00000040,
+    GAMEPAD = android::os::IInputConstants::DEVICE_CLASS_GAMEPAD,
 
     /* The input device has switches. */
-    SWITCH = 0x00000080,
+    SWITCH = android::os::IInputConstants::DEVICE_CLASS_SWITCH,
 
     /* The input device is a joystick (implies gamepad, has joystick absolute axes). */
-    JOYSTICK = 0x00000100,
+    JOYSTICK = android::os::IInputConstants::DEVICE_CLASS_JOYSTICK,
 
     /* The input device has a vibrator (supports FF_RUMBLE). */
-    VIBRATOR = 0x00000200,
+    VIBRATOR = android::os::IInputConstants::DEVICE_CLASS_VIBRATOR,
 
     /* The input device has a microphone. */
-    MIC = 0x00000400,
+    MIC = android::os::IInputConstants::DEVICE_CLASS_MIC,
 
     /* The input device is an external stylus (has data we want to fuse with touch data). */
-    EXTERNAL_STYLUS = 0x00000800,
+    EXTERNAL_STYLUS = android::os::IInputConstants::DEVICE_CLASS_EXTERNAL_STYLUS,
 
     /* The input device has a rotary encoder */
-    ROTARY_ENCODER = 0x00001000,
+    ROTARY_ENCODER = android::os::IInputConstants::DEVICE_CLASS_ROTARY_ENCODER,
 
     /* The input device has a sensor like accelerometer, gyro, etc */
-    SENSOR = 0x00002000,
+    SENSOR = android::os::IInputConstants::DEVICE_CLASS_SENSOR,
 
     /* The input device has a battery */
-    BATTERY = 0x00004000,
+    BATTERY = android::os::IInputConstants::DEVICE_CLASS_BATTERY,
 
     /* The input device has sysfs controllable lights */
-    LIGHT = 0x00008000,
+    LIGHT = android::os::IInputConstants::DEVICE_CLASS_LIGHT,
 
     /* The input device is a touchpad, requiring an on-screen cursor. */
-    TOUCHPAD = 0x00010000,
+    TOUCHPAD = android::os::IInputConstants::DEVICE_CLASS_TOUCHPAD,
 
     /* The input device is virtual (not a real device, not part of UI configuration). */
-    VIRTUAL = 0x40000000,
+    VIRTUAL = android::os::IInputConstants::DEVICE_CLASS_VIRTUAL,
 
     /* The input device is external (not built-in). */
-    EXTERNAL = 0x80000000,
+    EXTERNAL = android::os::IInputConstants::DEVICE_CLASS_EXTERNAL,
 };
 
 enum class SysfsClass : uint32_t {
diff --git a/services/inputflinger/reader/include/InputDevice.h b/services/inputflinger/reader/include/InputDevice.h
index 4c9af2e..2a7e262 100644
--- a/services/inputflinger/reader/include/InputDevice.h
+++ b/services/inputflinger/reader/include/InputDevice.h
@@ -79,6 +79,8 @@
 
     inline bool isIgnored() { return !getMapperCount() && !mController; }
 
+    inline KeyboardType getKeyboardType() const { return mKeyboardType; }
+
     bool isEnabled();
 
     void dump(std::string& dump, const std::string& eventHubDevStr);
@@ -124,6 +126,8 @@
 
     void addKeyRemapping(int32_t fromKeyCode, int32_t toKeyCode);
 
+    void setKeyboardType(KeyboardType keyboardType);
+
     void bumpGeneration();
 
     [[nodiscard]] NotifyDeviceResetArgs notifyReset(nsecs_t when);
@@ -196,6 +200,7 @@
     uint32_t mSources;
     bool mIsWaking;
     bool mIsExternal;
+    KeyboardType mKeyboardType = KeyboardType::NONE;
     std::optional<uint8_t> mAssociatedDisplayPort;
     std::optional<std::string> mAssociatedDisplayUniqueIdByPort;
     std::optional<std::string> mAssociatedDisplayUniqueIdByDescriptor;
@@ -470,6 +475,10 @@
     }
     inline void bumpGeneration() { mDevice.bumpGeneration(); }
     inline const PropertyMap& getConfiguration() const { return mDevice.getConfiguration(); }
+    inline KeyboardType getKeyboardType() const { return mDevice.getKeyboardType(); }
+    inline void setKeyboardType(KeyboardType keyboardType) {
+        return mDevice.setKeyboardType(keyboardType);
+    }
 
 private:
     InputDevice& mDevice;
diff --git a/services/inputflinger/reader/include/InputReader.h b/services/inputflinger/reader/include/InputReader.h
index 7e701c5..6f8c289 100644
--- a/services/inputflinger/reader/include/InputReader.h
+++ b/services/inputflinger/reader/include/InputReader.h
@@ -157,6 +157,7 @@
         void setLastKeyDownTimestamp(nsecs_t when) REQUIRES(mReader->mLock)
                 REQUIRES(mLock) override;
         nsecs_t getLastKeyDownTimestamp() REQUIRES(mReader->mLock) REQUIRES(mLock) override;
+        KeyboardClassifier& getKeyboardClassifier() override;
     } mContext;
 
     friend class ContextImpl;
@@ -176,6 +177,10 @@
 
     // The next stage that should receive the events generated inside InputReader.
     InputListenerInterface& mNextListener;
+
+    // Classifier for keyboard/keyboard-like devices
+    std::unique_ptr<KeyboardClassifier> mKeyboardClassifier;
+
     // As various events are generated inside InputReader, they are stored inside this list. The
     // list can only be accessed with the lock, so the events inside it are well-ordered.
     // Once the reader is done working, these events will be swapped into a temporary storage and
diff --git a/services/inputflinger/reader/include/InputReaderContext.h b/services/inputflinger/reader/include/InputReaderContext.h
index 907a49f..e0e0ac2 100644
--- a/services/inputflinger/reader/include/InputReaderContext.h
+++ b/services/inputflinger/reader/include/InputReaderContext.h
@@ -17,6 +17,7 @@
 #pragma once
 
 #include <input/InputDevice.h>
+#include <input/KeyboardClassifier.h>
 #include "NotifyArgs.h"
 
 #include <vector>
@@ -64,6 +65,8 @@
 
     virtual void setLastKeyDownTimestamp(nsecs_t when) = 0;
     virtual nsecs_t getLastKeyDownTimestamp() = 0;
+
+    virtual KeyboardClassifier& getKeyboardClassifier() = 0;
 };
 
 } // namespace android
diff --git a/services/inputflinger/reader/mapper/KeyboardInputMapper.cpp b/services/inputflinger/reader/mapper/KeyboardInputMapper.cpp
index 2124555..2e32380 100644
--- a/services/inputflinger/reader/mapper/KeyboardInputMapper.cpp
+++ b/services/inputflinger/reader/mapper/KeyboardInputMapper.cpp
@@ -21,6 +21,7 @@
 #include "KeyboardInputMapper.h"
 
 #include <ftl/enum.h>
+#include <input/KeyboardClassifier.h>
 #include <ui/Rotation.h>
 
 namespace android {
@@ -96,8 +97,8 @@
 
 KeyboardInputMapper::KeyboardInputMapper(InputDeviceContext& deviceContext,
                                          const InputReaderConfiguration& readerConfig,
-                                         uint32_t source, int32_t keyboardType)
-      : InputMapper(deviceContext, readerConfig), mSource(source), mKeyboardType(keyboardType) {}
+                                         uint32_t source)
+      : InputMapper(deviceContext, readerConfig), mSource(source) {}
 
 uint32_t KeyboardInputMapper::getSources() const {
     return mSource;
@@ -131,7 +132,6 @@
 void KeyboardInputMapper::populateDeviceInfo(InputDeviceInfo& info) {
     InputMapper::populateDeviceInfo(info);
 
-    info.setKeyboardType(mKeyboardType);
     info.setKeyCharacterMap(getDeviceContext().getKeyCharacterMap());
 
     std::optional keyboardLayoutInfo = getKeyboardLayoutInfo();
@@ -143,7 +143,6 @@
 void KeyboardInputMapper::dump(std::string& dump) {
     dump += INDENT2 "Keyboard Input Mapper:\n";
     dumpParameters(dump);
-    dump += StringPrintf(INDENT3 "KeyboardType: %d\n", mKeyboardType);
     dump += StringPrintf(INDENT3 "Orientation: %s\n", ftl::enum_string(getOrientation()).c_str());
     dump += StringPrintf(INDENT3 "KeyDowns: %zu keys currently down\n", mKeyDowns.size());
     dump += StringPrintf(INDENT3 "MetaState: 0x%0x\n", mMetaState);
@@ -327,13 +326,24 @@
         keyMetaState = mMetaState;
     }
 
+    DeviceId deviceId = getDeviceId();
+
+    // On first down: Process key for keyboard classification (will send reconfiguration if the
+    // keyboard type change)
+    if (down && !keyDownIndex) {
+        KeyboardClassifier& classifier = getDeviceContext().getContext()->getKeyboardClassifier();
+        classifier.processKey(deviceId, scanCode, keyMetaState);
+        getDeviceContext().setKeyboardType(classifier.getKeyboardType(deviceId));
+    }
+
+    KeyboardType keyboardType = getDeviceContext().getKeyboardType();
     // Any key down on an external keyboard should wake the device.
     // We don't do this for internal keyboards to prevent them from waking up in your pocket.
     // For internal keyboards and devices for which the default wake behavior is explicitly
     // prevented (e.g. TV remotes), the key layout file should specify the policy flags for each
     // wake key individually.
     if (down && getDeviceContext().isExternal() && !mParameters.doNotWakeByDefault &&
-        !(mKeyboardType != AINPUT_KEYBOARD_TYPE_ALPHABETIC && isMediaKey(keyCode))) {
+        !(keyboardType != KeyboardType::ALPHABETIC && isMediaKey(keyCode))) {
         policyFlags |= POLICY_FLAG_WAKE;
     }
 
@@ -341,8 +351,8 @@
         policyFlags |= POLICY_FLAG_DISABLE_KEY_REPEAT;
     }
 
-    out.emplace_back(NotifyKeyArgs(getContext()->getNextId(), when, readTime, getDeviceId(),
-                                   mSource, getDisplayId(), policyFlags,
+    out.emplace_back(NotifyKeyArgs(getContext()->getNextId(), when, readTime, deviceId, mSource,
+                                   getDisplayId(), policyFlags,
                                    down ? AKEY_EVENT_ACTION_DOWN : AKEY_EVENT_ACTION_UP, flags,
                                    keyCode, scanCode, keyMetaState, downTime));
     return out;
diff --git a/services/inputflinger/reader/mapper/KeyboardInputMapper.h b/services/inputflinger/reader/mapper/KeyboardInputMapper.h
index f2d3f4d..bee2a99 100644
--- a/services/inputflinger/reader/mapper/KeyboardInputMapper.h
+++ b/services/inputflinger/reader/mapper/KeyboardInputMapper.h
@@ -61,7 +61,6 @@
     };
 
     uint32_t mSource{};
-    int32_t mKeyboardType{};
     std::optional<KeyboardLayoutInfo> mKeyboardLayoutInfo;
 
     std::vector<KeyDown> mKeyDowns{}; // keys that are down
@@ -85,8 +84,7 @@
     } mParameters{};
 
     KeyboardInputMapper(InputDeviceContext& deviceContext,
-                        const InputReaderConfiguration& readerConfig, uint32_t source,
-                        int32_t keyboardType);
+                        const InputReaderConfiguration& readerConfig, uint32_t source);
     void configureParameters();
     void dumpParameters(std::string& dump) const;
 
diff --git a/services/inputflinger/tests/InputReader_test.cpp b/services/inputflinger/tests/InputReader_test.cpp
index 8536ff0..07fa59f 100644
--- a/services/inputflinger/tests/InputReader_test.cpp
+++ b/services/inputflinger/tests/InputReader_test.cpp
@@ -3314,6 +3314,10 @@
 
 class KeyboardInputMapperTest : public InputMapperTest {
 protected:
+    void SetUp() override {
+        InputMapperTest::SetUp(DEVICE_CLASSES | InputDeviceClass::KEYBOARD |
+                               InputDeviceClass::ALPHAKEY);
+    }
     const std::string UNIQUE_ID = "local:0";
     const KeyboardLayoutInfo DEVICE_KEYBOARD_LAYOUT_INFO = KeyboardLayoutInfo("en-US", "qwerty");
     void prepareDisplay(ui::Rotation orientation);
@@ -3354,8 +3358,7 @@
 
 TEST_F(KeyboardInputMapperTest, GetSources) {
     KeyboardInputMapper& mapper =
-            constructAndAddMapper<KeyboardInputMapper>(AINPUT_SOURCE_KEYBOARD,
-                                                       AINPUT_KEYBOARD_TYPE_ALPHABETIC);
+            constructAndAddMapper<KeyboardInputMapper>(AINPUT_SOURCE_KEYBOARD);
 
     ASSERT_EQ(AINPUT_SOURCE_KEYBOARD, mapper.getSources());
 }
@@ -3370,8 +3373,7 @@
     mFakeEventHub->addKey(EVENTHUB_ID, 0, KEY_SCROLLLOCK, AKEYCODE_SCROLL_LOCK, POLICY_FLAG_WAKE);
 
     KeyboardInputMapper& mapper =
-            constructAndAddMapper<KeyboardInputMapper>(AINPUT_SOURCE_KEYBOARD,
-                                                       AINPUT_KEYBOARD_TYPE_ALPHABETIC);
+            constructAndAddMapper<KeyboardInputMapper>(AINPUT_SOURCE_KEYBOARD);
     // Initial metastate is AMETA_NONE.
     ASSERT_EQ(AMETA_NONE, mapper.getMetaState());
 
@@ -3471,8 +3473,7 @@
     mFakeEventHub->addKeyRemapping(EVENTHUB_ID, AKEYCODE_A, AKEYCODE_B);
 
     KeyboardInputMapper& mapper =
-            constructAndAddMapper<KeyboardInputMapper>(AINPUT_SOURCE_KEYBOARD,
-                                                       AINPUT_KEYBOARD_TYPE_ALPHABETIC);
+            constructAndAddMapper<KeyboardInputMapper>(AINPUT_SOURCE_KEYBOARD);
 
     // Key down by scan code.
     process(mapper, ARBITRARY_TIME, READ_TIME, EV_KEY, KEY_A, 1);
@@ -3493,8 +3494,7 @@
     mFakeEventHub->addKey(EVENTHUB_ID, KEY_HOME, 0, AKEYCODE_HOME, POLICY_FLAG_WAKE);
 
     KeyboardInputMapper& mapper =
-            constructAndAddMapper<KeyboardInputMapper>(AINPUT_SOURCE_KEYBOARD,
-                                                       AINPUT_KEYBOARD_TYPE_ALPHABETIC);
+            constructAndAddMapper<KeyboardInputMapper>(AINPUT_SOURCE_KEYBOARD);
     NotifyKeyArgs args;
 
     // Key down
@@ -3516,8 +3516,7 @@
     mFakeEventHub->addKey(EVENTHUB_ID, 0, KEY_SCROLLLOCK, AKEYCODE_SCROLL_LOCK, 0);
 
     KeyboardInputMapper& mapper =
-            constructAndAddMapper<KeyboardInputMapper>(AINPUT_SOURCE_KEYBOARD,
-                                                       AINPUT_KEYBOARD_TYPE_ALPHABETIC);
+            constructAndAddMapper<KeyboardInputMapper>(AINPUT_SOURCE_KEYBOARD);
 
     // Initial metastate is AMETA_NONE.
     ASSERT_EQ(AMETA_NONE, mapper.getMetaState());
@@ -3557,8 +3556,7 @@
     mFakeEventHub->addKey(EVENTHUB_ID, KEY_LEFT, 0, AKEYCODE_DPAD_LEFT, 0);
 
     KeyboardInputMapper& mapper =
-            constructAndAddMapper<KeyboardInputMapper>(AINPUT_SOURCE_KEYBOARD,
-                                                       AINPUT_KEYBOARD_TYPE_ALPHABETIC);
+            constructAndAddMapper<KeyboardInputMapper>(AINPUT_SOURCE_KEYBOARD);
 
     prepareDisplay(ui::ROTATION_90);
     ASSERT_NO_FATAL_FAILURE(testDPadKeyRotation(mapper,
@@ -3579,8 +3577,7 @@
 
     addConfigurationProperty("keyboard.orientationAware", "1");
     KeyboardInputMapper& mapper =
-            constructAndAddMapper<KeyboardInputMapper>(AINPUT_SOURCE_KEYBOARD,
-                                                       AINPUT_KEYBOARD_TYPE_ALPHABETIC);
+            constructAndAddMapper<KeyboardInputMapper>(AINPUT_SOURCE_KEYBOARD);
 
     prepareDisplay(ui::ROTATION_0);
     ASSERT_NO_FATAL_FAILURE(
@@ -3651,8 +3648,7 @@
     mFakeEventHub->addKey(EVENTHUB_ID, KEY_UP, 0, AKEYCODE_DPAD_UP, 0);
 
     KeyboardInputMapper& mapper =
-            constructAndAddMapper<KeyboardInputMapper>(AINPUT_SOURCE_KEYBOARD,
-                                                       AINPUT_KEYBOARD_TYPE_ALPHABETIC);
+            constructAndAddMapper<KeyboardInputMapper>(AINPUT_SOURCE_KEYBOARD);
     NotifyKeyArgs args;
 
     // Display id should be LogicalDisplayId::INVALID without any display configuration.
@@ -3677,8 +3673,7 @@
 
     addConfigurationProperty("keyboard.orientationAware", "1");
     KeyboardInputMapper& mapper =
-            constructAndAddMapper<KeyboardInputMapper>(AINPUT_SOURCE_KEYBOARD,
-                                                       AINPUT_KEYBOARD_TYPE_ALPHABETIC);
+            constructAndAddMapper<KeyboardInputMapper>(AINPUT_SOURCE_KEYBOARD);
     NotifyKeyArgs args;
 
     // Display id should be LogicalDisplayId::INVALID without any display configuration.
@@ -3705,8 +3700,7 @@
 
 TEST_F(KeyboardInputMapperTest, GetKeyCodeState) {
     KeyboardInputMapper& mapper =
-            constructAndAddMapper<KeyboardInputMapper>(AINPUT_SOURCE_KEYBOARD,
-                                                       AINPUT_KEYBOARD_TYPE_ALPHABETIC);
+            constructAndAddMapper<KeyboardInputMapper>(AINPUT_SOURCE_KEYBOARD);
 
     mFakeEventHub->setKeyCodeState(EVENTHUB_ID, AKEYCODE_A, 1);
     ASSERT_EQ(1, mapper.getKeyCodeState(AINPUT_SOURCE_ANY, AKEYCODE_A));
@@ -3717,8 +3711,7 @@
 
 TEST_F(KeyboardInputMapperTest, GetKeyCodeForKeyLocation) {
     KeyboardInputMapper& mapper =
-            constructAndAddMapper<KeyboardInputMapper>(AINPUT_SOURCE_KEYBOARD,
-                                                       AINPUT_KEYBOARD_TYPE_ALPHABETIC);
+            constructAndAddMapper<KeyboardInputMapper>(AINPUT_SOURCE_KEYBOARD);
 
     mFakeEventHub->addKeyCodeMapping(EVENTHUB_ID, AKEYCODE_Y, AKEYCODE_Z);
     ASSERT_EQ(AKEYCODE_Z, mapper.getKeyCodeForKeyLocation(AKEYCODE_Y))
@@ -3730,8 +3723,7 @@
 
 TEST_F(KeyboardInputMapperTest, GetScanCodeState) {
     KeyboardInputMapper& mapper =
-            constructAndAddMapper<KeyboardInputMapper>(AINPUT_SOURCE_KEYBOARD,
-                                                       AINPUT_KEYBOARD_TYPE_ALPHABETIC);
+            constructAndAddMapper<KeyboardInputMapper>(AINPUT_SOURCE_KEYBOARD);
 
     mFakeEventHub->setScanCodeState(EVENTHUB_ID, KEY_A, 1);
     ASSERT_EQ(1, mapper.getScanCodeState(AINPUT_SOURCE_ANY, KEY_A));
@@ -3742,8 +3734,7 @@
 
 TEST_F(KeyboardInputMapperTest, MarkSupportedKeyCodes) {
     KeyboardInputMapper& mapper =
-            constructAndAddMapper<KeyboardInputMapper>(AINPUT_SOURCE_KEYBOARD,
-                                                       AINPUT_KEYBOARD_TYPE_ALPHABETIC);
+            constructAndAddMapper<KeyboardInputMapper>(AINPUT_SOURCE_KEYBOARD);
 
     mFakeEventHub->addKey(EVENTHUB_ID, KEY_A, 0, AKEYCODE_A, 0);
 
@@ -3762,8 +3753,7 @@
     mFakeEventHub->addKey(EVENTHUB_ID, KEY_SCROLLLOCK, 0, AKEYCODE_SCROLL_LOCK, 0);
 
     KeyboardInputMapper& mapper =
-            constructAndAddMapper<KeyboardInputMapper>(AINPUT_SOURCE_KEYBOARD,
-                                                       AINPUT_KEYBOARD_TYPE_ALPHABETIC);
+            constructAndAddMapper<KeyboardInputMapper>(AINPUT_SOURCE_KEYBOARD);
     // Initial metastate is AMETA_NONE.
     ASSERT_EQ(AMETA_NONE, mapper.getMetaState());
 
@@ -3828,8 +3818,7 @@
     mFakeEventHub->addKey(EVENTHUB_ID, BTN_Y, 0, AKEYCODE_BUTTON_Y, 0);
 
     KeyboardInputMapper& mapper =
-            constructAndAddMapper<KeyboardInputMapper>(AINPUT_SOURCE_KEYBOARD,
-                                                       AINPUT_KEYBOARD_TYPE_NON_ALPHABETIC);
+            constructAndAddMapper<KeyboardInputMapper>(AINPUT_SOURCE_KEYBOARD);
 
     // Meta state should be AMETA_NONE after reset
     std::list<NotifyArgs> unused = mapper.reset(ARBITRARY_TIME);
@@ -3878,16 +3867,14 @@
     mFakeEventHub->addKey(SECOND_EVENTHUB_ID, KEY_LEFT, 0, AKEYCODE_DPAD_LEFT, 0);
 
     KeyboardInputMapper& mapper =
-            constructAndAddMapper<KeyboardInputMapper>(AINPUT_SOURCE_KEYBOARD,
-                                                       AINPUT_KEYBOARD_TYPE_ALPHABETIC);
+            constructAndAddMapper<KeyboardInputMapper>(AINPUT_SOURCE_KEYBOARD);
 
     device2->addEmptyEventHubDevice(SECOND_EVENTHUB_ID);
     KeyboardInputMapper& mapper2 =
             device2->constructAndAddMapper<KeyboardInputMapper>(SECOND_EVENTHUB_ID,
                                                                 mFakePolicy
                                                                         ->getReaderConfiguration(),
-                                                                AINPUT_SOURCE_KEYBOARD,
-                                                                AINPUT_KEYBOARD_TYPE_ALPHABETIC);
+                                                                AINPUT_SOURCE_KEYBOARD);
     std::list<NotifyArgs> unused =
             device2->configure(ARBITRARY_TIME, mFakePolicy->getReaderConfiguration(),
                                /*changes=*/{});
@@ -3949,8 +3936,7 @@
     mFakeEventHub->addKey(EVENTHUB_ID, KEY_SCROLLLOCK, 0, AKEYCODE_SCROLL_LOCK, 0);
 
     KeyboardInputMapper& mapper =
-            constructAndAddMapper<KeyboardInputMapper>(AINPUT_SOURCE_KEYBOARD,
-                                                       AINPUT_KEYBOARD_TYPE_ALPHABETIC);
+            constructAndAddMapper<KeyboardInputMapper>(AINPUT_SOURCE_KEYBOARD);
     // Initial metastate is AMETA_NONE.
     ASSERT_EQ(AMETA_NONE, mapper.getMetaState());
 
@@ -4000,8 +3986,7 @@
             device2->constructAndAddMapper<KeyboardInputMapper>(SECOND_EVENTHUB_ID,
                                                                 mFakePolicy
                                                                         ->getReaderConfiguration(),
-                                                                AINPUT_SOURCE_KEYBOARD,
-                                                                AINPUT_KEYBOARD_TYPE_ALPHABETIC);
+                                                                AINPUT_SOURCE_KEYBOARD);
     std::list<NotifyArgs> unused =
             device2->configure(ARBITRARY_TIME, mFakePolicy->getReaderConfiguration(),
                                /*changes=*/{});
@@ -4020,11 +4005,9 @@
     mFakeEventHub->addKey(EVENTHUB_ID, KEY_SCROLLLOCK, 0, AKEYCODE_SCROLL_LOCK, 0);
 
     // Suppose we have two mappers. (DPAD + KEYBOARD)
-    constructAndAddMapper<KeyboardInputMapper>(AINPUT_SOURCE_DPAD,
-                                               AINPUT_KEYBOARD_TYPE_NON_ALPHABETIC);
+    constructAndAddMapper<KeyboardInputMapper>(AINPUT_SOURCE_DPAD);
     KeyboardInputMapper& mapper =
-            constructAndAddMapper<KeyboardInputMapper>(AINPUT_SOURCE_KEYBOARD,
-                                                       AINPUT_KEYBOARD_TYPE_ALPHABETIC);
+            constructAndAddMapper<KeyboardInputMapper>(AINPUT_SOURCE_KEYBOARD);
     // Initial metastate is AMETA_NONE.
     ASSERT_EQ(AMETA_NONE, mapper.getMetaState());
 
@@ -4042,8 +4025,7 @@
     mFakeEventHub->addKey(EVENTHUB_ID, KEY_SCROLLLOCK, 0, AKEYCODE_SCROLL_LOCK, 0);
 
     KeyboardInputMapper& mapper1 =
-            constructAndAddMapper<KeyboardInputMapper>(AINPUT_SOURCE_KEYBOARD,
-                                                       AINPUT_KEYBOARD_TYPE_ALPHABETIC);
+            constructAndAddMapper<KeyboardInputMapper>(AINPUT_SOURCE_KEYBOARD);
 
     // keyboard 2.
     const std::string USB2 = "USB2";
@@ -4065,8 +4047,7 @@
             device2->constructAndAddMapper<KeyboardInputMapper>(SECOND_EVENTHUB_ID,
                                                                 mFakePolicy
                                                                         ->getReaderConfiguration(),
-                                                                AINPUT_SOURCE_KEYBOARD,
-                                                                AINPUT_KEYBOARD_TYPE_ALPHABETIC);
+                                                                AINPUT_SOURCE_KEYBOARD);
     std::list<NotifyArgs> unused =
             device2->configure(ARBITRARY_TIME, mFakePolicy->getReaderConfiguration(),
                                /*changes=*/{});
@@ -4122,8 +4103,7 @@
     mFakeEventHub->addKey(EVENTHUB_ID, 0, USAGE_A, AKEYCODE_A, POLICY_FLAG_WAKE);
 
     KeyboardInputMapper& mapper =
-            constructAndAddMapper<KeyboardInputMapper>(AINPUT_SOURCE_KEYBOARD,
-                                                       AINPUT_KEYBOARD_TYPE_ALPHABETIC);
+            constructAndAddMapper<KeyboardInputMapper>(AINPUT_SOURCE_KEYBOARD);
     // Key down by scan code.
     process(mapper, ARBITRARY_TIME, READ_TIME, EV_KEY, KEY_HOME, 1);
     NotifyKeyArgs args;
@@ -4148,8 +4128,7 @@
 }
 
 TEST_F(KeyboardInputMapperTest, Configure_AssignKeyboardLayoutInfo) {
-    constructAndAddMapper<KeyboardInputMapper>(AINPUT_SOURCE_KEYBOARD,
-                                               AINPUT_KEYBOARD_TYPE_ALPHABETIC);
+    constructAndAddMapper<KeyboardInputMapper>(AINPUT_SOURCE_KEYBOARD);
     std::list<NotifyArgs> unused =
             mDevice->configure(ARBITRARY_TIME, mFakePolicy->getReaderConfiguration(),
                                /*changes=*/{});
@@ -4180,8 +4159,7 @@
                                     RawLayoutInfo{.languageTag = "en", .layoutType = "extended"});
 
     // Configuration
-    constructAndAddMapper<KeyboardInputMapper>(AINPUT_SOURCE_KEYBOARD,
-                                               AINPUT_KEYBOARD_TYPE_ALPHABETIC);
+    constructAndAddMapper<KeyboardInputMapper>(AINPUT_SOURCE_KEYBOARD);
     InputReaderConfiguration config;
     std::list<NotifyArgs> unused = mDevice->configure(ARBITRARY_TIME, config, /*changes=*/{});
 
@@ -4192,8 +4170,7 @@
 TEST_F(KeyboardInputMapperTest, Process_GesureEventToSetFlagKeepTouchMode) {
     mFakeEventHub->addKey(EVENTHUB_ID, KEY_LEFT, 0, AKEYCODE_DPAD_LEFT, POLICY_FLAG_GESTURE);
     KeyboardInputMapper& mapper =
-            constructAndAddMapper<KeyboardInputMapper>(AINPUT_SOURCE_KEYBOARD,
-                                                       AINPUT_KEYBOARD_TYPE_ALPHABETIC);
+            constructAndAddMapper<KeyboardInputMapper>(AINPUT_SOURCE_KEYBOARD);
     NotifyKeyArgs args;
 
     // Key down
@@ -4202,14 +4179,27 @@
     ASSERT_EQ(AKEY_EVENT_FLAG_FROM_SYSTEM | AKEY_EVENT_FLAG_KEEP_TOUCH_MODE, args.flags);
 }
 
-// --- KeyboardInputMapperTest_ExternalDevice ---
+// --- KeyboardInputMapperTest_ExternalAlphabeticDevice ---
 
-class KeyboardInputMapperTest_ExternalDevice : public InputMapperTest {
+class KeyboardInputMapperTest_ExternalAlphabeticDevice : public InputMapperTest {
 protected:
-    void SetUp() override { InputMapperTest::SetUp(DEVICE_CLASSES | InputDeviceClass::EXTERNAL); }
+    void SetUp() override {
+        InputMapperTest::SetUp(DEVICE_CLASSES | InputDeviceClass::KEYBOARD |
+                               InputDeviceClass::ALPHAKEY | InputDeviceClass::EXTERNAL);
+    }
 };
 
-TEST_F(KeyboardInputMapperTest_ExternalDevice, WakeBehavior_AlphabeticKeyboard) {
+// --- KeyboardInputMapperTest_ExternalNonAlphabeticDevice ---
+
+class KeyboardInputMapperTest_ExternalNonAlphabeticDevice : public InputMapperTest {
+protected:
+    void SetUp() override {
+        InputMapperTest::SetUp(DEVICE_CLASSES | InputDeviceClass::KEYBOARD |
+                               InputDeviceClass::EXTERNAL);
+    }
+};
+
+TEST_F(KeyboardInputMapperTest_ExternalAlphabeticDevice, WakeBehavior_AlphabeticKeyboard) {
     // For external devices, keys will trigger wake on key down. Media keys should also trigger
     // wake if triggered from external devices.
 
@@ -4219,8 +4209,7 @@
                           POLICY_FLAG_WAKE);
 
     KeyboardInputMapper& mapper =
-            constructAndAddMapper<KeyboardInputMapper>(AINPUT_SOURCE_KEYBOARD,
-                                                       AINPUT_KEYBOARD_TYPE_ALPHABETIC);
+            constructAndAddMapper<KeyboardInputMapper>(AINPUT_SOURCE_KEYBOARD);
 
     process(mapper, ARBITRARY_TIME, READ_TIME, EV_KEY, KEY_HOME, 1);
     NotifyKeyArgs args;
@@ -4248,7 +4237,7 @@
     ASSERT_EQ(POLICY_FLAG_WAKE, args.policyFlags);
 }
 
-TEST_F(KeyboardInputMapperTest_ExternalDevice, WakeBehavior_NoneAlphabeticKeyboard) {
+TEST_F(KeyboardInputMapperTest_ExternalNonAlphabeticDevice, WakeBehavior_NonAlphabeticKeyboard) {
     // For external devices, keys will trigger wake on key down. Media keys should not trigger
     // wake if triggered from external non-alphaebtic keyboard (e.g. headsets).
 
@@ -4257,8 +4246,7 @@
                           POLICY_FLAG_WAKE);
 
     KeyboardInputMapper& mapper =
-            constructAndAddMapper<KeyboardInputMapper>(AINPUT_SOURCE_KEYBOARD,
-                                                       AINPUT_KEYBOARD_TYPE_NON_ALPHABETIC);
+            constructAndAddMapper<KeyboardInputMapper>(AINPUT_SOURCE_KEYBOARD);
 
     process(mapper, ARBITRARY_TIME, READ_TIME, EV_KEY, KEY_PLAY, 1);
     NotifyKeyArgs args;
@@ -4278,7 +4266,7 @@
     ASSERT_EQ(POLICY_FLAG_WAKE, args.policyFlags);
 }
 
-TEST_F(KeyboardInputMapperTest_ExternalDevice, DoNotWakeByDefaultBehavior) {
+TEST_F(KeyboardInputMapperTest_ExternalAlphabeticDevice, DoNotWakeByDefaultBehavior) {
     // Tv Remote key's wake behavior is prescribed by the keylayout file.
 
     mFakeEventHub->addKey(EVENTHUB_ID, KEY_HOME, 0, AKEYCODE_HOME, POLICY_FLAG_WAKE);
@@ -4287,8 +4275,7 @@
 
     addConfigurationProperty("keyboard.doNotWakeByDefault", "1");
     KeyboardInputMapper& mapper =
-            constructAndAddMapper<KeyboardInputMapper>(AINPUT_SOURCE_KEYBOARD,
-                                                       AINPUT_KEYBOARD_TYPE_ALPHABETIC);
+            constructAndAddMapper<KeyboardInputMapper>(AINPUT_SOURCE_KEYBOARD);
 
     process(mapper, ARBITRARY_TIME, READ_TIME, EV_KEY, KEY_HOME, 1);
     NotifyKeyArgs args;
diff --git a/services/inputflinger/tests/InterfaceMocks.h b/services/inputflinger/tests/InterfaceMocks.h
index 6389cdc..2d4e917 100644
--- a/services/inputflinger/tests/InterfaceMocks.h
+++ b/services/inputflinger/tests/InterfaceMocks.h
@@ -36,6 +36,7 @@
 #include <input/InputDevice.h>
 #include <input/KeyCharacterMap.h>
 #include <input/KeyLayoutMap.h>
+#include <input/KeyboardClassifier.h>
 #include <input/PropertyMap.h>
 #include <input/TouchVideoFrame.h>
 #include <input/VirtualKeyMap.h>
@@ -75,8 +76,11 @@
     MOCK_METHOD(void, setLastKeyDownTimestamp, (nsecs_t when));
     MOCK_METHOD(nsecs_t, getLastKeyDownTimestamp, ());
 
+    KeyboardClassifier& getKeyboardClassifier() override { return *mClassifier; };
+
 private:
     int32_t mGeneration = 0;
+    std::unique_ptr<KeyboardClassifier> mClassifier = std::make_unique<KeyboardClassifier>();
 };
 
 class MockEventHubInterface : public EventHubInterface {
diff --git a/services/inputflinger/tests/KeyboardInputMapper_test.cpp b/services/inputflinger/tests/KeyboardInputMapper_test.cpp
index 031b77d..ada841d 100644
--- a/services/inputflinger/tests/KeyboardInputMapper_test.cpp
+++ b/services/inputflinger/tests/KeyboardInputMapper_test.cpp
@@ -67,8 +67,7 @@
         EXPECT_CALL(mMockInputReaderContext, getPolicy).WillRepeatedly(Return(mFakePolicy.get()));
 
         mMapper = createInputMapper<KeyboardInputMapper>(*mDeviceContext, mReaderConfiguration,
-                                                         AINPUT_SOURCE_KEYBOARD,
-                                                         AINPUT_KEYBOARD_TYPE_ALPHABETIC);
+                                                         AINPUT_SOURCE_KEYBOARD);
     }
 
     void testPointerVisibilityForKeys(const std::vector<int32_t>& keyCodes, bool expectVisible) {
diff --git a/services/inputflinger/tests/fuzzers/KeyboardInputFuzzer.cpp b/services/inputflinger/tests/fuzzers/KeyboardInputFuzzer.cpp
index 922cbdf..3b3f8d2 100644
--- a/services/inputflinger/tests/fuzzers/KeyboardInputFuzzer.cpp
+++ b/services/inputflinger/tests/fuzzers/KeyboardInputFuzzer.cpp
@@ -50,11 +50,10 @@
     FuzzInputReaderContext context(eventHub, fdp);
     InputDevice device = getFuzzedInputDevice(*fdp, &context);
 
-    KeyboardInputMapper& mapper = getMapperForDevice<
-            ThreadSafeFuzzedDataProvider,
-            KeyboardInputMapper>(*fdp.get(), device, InputReaderConfiguration{},
-                                 /*source=*/fdp->ConsumeIntegral<uint32_t>(),
-                                 /*keyboardType=*/fdp->ConsumeIntegral<int32_t>());
+    KeyboardInputMapper& mapper =
+            getMapperForDevice<ThreadSafeFuzzedDataProvider,
+                               KeyboardInputMapper>(*fdp.get(), device, InputReaderConfiguration{},
+                                                    /*source=*/fdp->ConsumeIntegral<uint32_t>());
 
     // Loop through mapper operations until randomness is exhausted.
     while (fdp->remaining_bytes() > 0) {
diff --git a/services/inputflinger/tests/fuzzers/MapperHelpers.h b/services/inputflinger/tests/fuzzers/MapperHelpers.h
index 25f2f2e..ff425dd 100644
--- a/services/inputflinger/tests/fuzzers/MapperHelpers.h
+++ b/services/inputflinger/tests/fuzzers/MapperHelpers.h
@@ -338,9 +338,11 @@
 
     void setLastKeyDownTimestamp(nsecs_t when) { mLastKeyDownTimestamp = when; };
     nsecs_t getLastKeyDownTimestamp() { return mLastKeyDownTimestamp; };
+    KeyboardClassifier& getKeyboardClassifier() override { return *mClassifier; }
 
 private:
     nsecs_t mLastKeyDownTimestamp;
+    std::unique_ptr<KeyboardClassifier> mClassifier = std::make_unique<KeyboardClassifier>();
 };
 
 template <class Fdp>