Merge "Fix toggleCapsLock failed for multiple EventHub devices"
diff --git a/services/inputflinger/reader/EventHub.cpp b/services/inputflinger/reader/EventHub.cpp
index 68d5e7c..0f0ad0a 100644
--- a/services/inputflinger/reader/EventHub.cpp
+++ b/services/inputflinger/reader/EventHub.cpp
@@ -1209,6 +1209,15 @@
     return false;
 }
 
+bool EventHub::hasKeyCode(int32_t deviceId, int32_t keyCode) const {
+    std::scoped_lock _l(mLock);
+    Device* device = getDeviceLocked(deviceId);
+    if (device != nullptr) {
+        return device->hasKeycodeLocked(keyCode);
+    }
+    return false;
+}
+
 bool EventHub::hasLed(int32_t deviceId, int32_t led) const {
     std::scoped_lock _l(mLock);
     Device* device = getDeviceLocked(deviceId);
diff --git a/services/inputflinger/reader/InputDevice.cpp b/services/inputflinger/reader/InputDevice.cpp
index 1e9ec54..36344b5 100644
--- a/services/inputflinger/reader/InputDevice.cpp
+++ b/services/inputflinger/reader/InputDevice.cpp
@@ -559,7 +559,13 @@
 }
 
 void InputDevice::updateMetaState(int32_t keyCode) {
-    for_each_mapper([keyCode](InputMapper& mapper) { mapper.updateMetaState(keyCode); });
+    first_in_mappers<bool>([keyCode](InputMapper& mapper) {
+        if (sourcesMatchMask(mapper.getSources(), AINPUT_SOURCE_KEYBOARD) &&
+            mapper.updateMetaState(keyCode)) {
+            return std::make_optional(true);
+        }
+        return std::optional<bool>();
+    });
 }
 
 void InputDevice::bumpGeneration() {
diff --git a/services/inputflinger/reader/InputReader.cpp b/services/inputflinger/reader/InputReader.cpp
index 10c04f6..e71a9e9 100644
--- a/services/inputflinger/reader/InputReader.cpp
+++ b/services/inputflinger/reader/InputReader.cpp
@@ -555,6 +555,7 @@
     }
 
     if (device->isIgnored()) {
+        ALOGW("Ignoring toggleCapsLock for ignored deviceId %" PRId32 ".", deviceId);
         return;
     }
 
diff --git a/services/inputflinger/reader/include/EventHub.h b/services/inputflinger/reader/include/EventHub.h
index 3c3f88e..7a00bac 100644
--- a/services/inputflinger/reader/include/EventHub.h
+++ b/services/inputflinger/reader/include/EventHub.h
@@ -312,6 +312,7 @@
                                        uint8_t* outFlags) const = 0;
 
     virtual bool hasScanCode(int32_t deviceId, int32_t scanCode) const = 0;
+    virtual bool hasKeyCode(int32_t deviceId, int32_t keyCode) const = 0;
 
     /* LED related functions expect Android LED constants, not scan codes or HID usages */
     virtual bool hasLed(int32_t deviceId, int32_t led) const = 0;
@@ -489,6 +490,7 @@
     std::vector<TouchVideoFrame> getVideoFrames(int32_t deviceId) override final;
 
     bool hasScanCode(int32_t deviceId, int32_t scanCode) const override final;
+    bool hasKeyCode(int32_t deviceId, int32_t keyCode) const override final;
     bool hasLed(int32_t deviceId, int32_t led) const override final;
     void setLedState(int32_t deviceId, int32_t led, bool on) override final;
 
diff --git a/services/inputflinger/reader/include/InputDevice.h b/services/inputflinger/reader/include/InputDevice.h
index f32472d..518aaa0 100644
--- a/services/inputflinger/reader/include/InputDevice.h
+++ b/services/inputflinger/reader/include/InputDevice.h
@@ -323,6 +323,7 @@
     inline bool hasScanCode(int32_t scanCode) const {
         return mEventHub->hasScanCode(mId, scanCode);
     }
+    inline bool hasKeyCode(int32_t keyCode) const { return mEventHub->hasKeyCode(mId, keyCode); }
     inline bool hasLed(int32_t led) const { return mEventHub->hasLed(mId, led); }
     inline void setLedState(int32_t led, bool on) { return mEventHub->setLedState(mId, led, on); }
     inline void getVirtualKeyDefinitions(std::vector<VirtualKeyDefinition>& outVirtualKeys) const {
diff --git a/services/inputflinger/reader/mapper/InputMapper.cpp b/services/inputflinger/reader/mapper/InputMapper.cpp
index df1acd4..b9aef54 100644
--- a/services/inputflinger/reader/mapper/InputMapper.cpp
+++ b/services/inputflinger/reader/mapper/InputMapper.cpp
@@ -84,7 +84,9 @@
     return 0;
 }
 
-void InputMapper::updateMetaState(int32_t keyCode) {}
+bool InputMapper::updateMetaState(int32_t keyCode) {
+    return false;
+}
 
 void InputMapper::updateExternalStylusState(const StylusState& state) {}
 
diff --git a/services/inputflinger/reader/mapper/InputMapper.h b/services/inputflinger/reader/mapper/InputMapper.h
index 15cff1c..d9adc0f 100644
--- a/services/inputflinger/reader/mapper/InputMapper.h
+++ b/services/inputflinger/reader/mapper/InputMapper.h
@@ -83,7 +83,11 @@
     virtual std::optional<int32_t> getLightPlayerId(int32_t lightId) { return std::nullopt; }
 
     virtual int32_t getMetaState();
-    virtual void updateMetaState(int32_t keyCode);
+    /**
+     * Process the meta key and update the global meta state when changed.
+     * Return true if the meta key could be handled by the InputMapper.
+     */
+    virtual bool updateMetaState(int32_t keyCode);
 
     virtual void updateExternalStylusState(const StylusState& state);
 
diff --git a/services/inputflinger/reader/mapper/KeyboardInputMapper.cpp b/services/inputflinger/reader/mapper/KeyboardInputMapper.cpp
index 104d087..52af38d 100644
--- a/services/inputflinger/reader/mapper/KeyboardInputMapper.cpp
+++ b/services/inputflinger/reader/mapper/KeyboardInputMapper.cpp
@@ -384,8 +384,13 @@
     return mMetaState;
 }
 
-void KeyboardInputMapper::updateMetaState(int32_t keyCode) {
+bool KeyboardInputMapper::updateMetaState(int32_t keyCode) {
+    if (!android::isMetaKey(keyCode) || !getDeviceContext().hasKeyCode(keyCode)) {
+        return false;
+    }
+
     updateMetaStateIfNeeded(keyCode, false);
+    return true;
 }
 
 bool KeyboardInputMapper::updateMetaStateIfNeeded(int32_t keyCode, bool down) {
diff --git a/services/inputflinger/reader/mapper/KeyboardInputMapper.h b/services/inputflinger/reader/mapper/KeyboardInputMapper.h
index ca41712..fc92320 100644
--- a/services/inputflinger/reader/mapper/KeyboardInputMapper.h
+++ b/services/inputflinger/reader/mapper/KeyboardInputMapper.h
@@ -40,7 +40,7 @@
                                        const int32_t* keyCodes, uint8_t* outFlags) override;
 
     virtual int32_t getMetaState() override;
-    virtual void updateMetaState(int32_t keyCode) override;
+    virtual bool updateMetaState(int32_t keyCode) override;
     virtual std::optional<int32_t> getAssociatedDisplayId() override;
     virtual void updateLedState(bool reset);
 
diff --git a/services/inputflinger/tests/InputReader_test.cpp b/services/inputflinger/tests/InputReader_test.cpp
index 23649a9..c76ed38 100644
--- a/services/inputflinger/tests/InputReader_test.cpp
+++ b/services/inputflinger/tests/InputReader_test.cpp
@@ -871,6 +871,24 @@
         return false;
     }
 
+    bool hasKeyCode(int32_t deviceId, int32_t keyCode) const override {
+        Device* device = getDevice(deviceId);
+        if (!device) {
+            return false;
+        }
+        for (size_t i = 0; i < device->keysByScanCode.size(); i++) {
+            if (keyCode == device->keysByScanCode.valueAt(i).keyCode) {
+                return true;
+            }
+        }
+        for (size_t j = 0; j < device->keysByUsageCode.size(); j++) {
+            if (keyCode == device->keysByUsageCode.valueAt(j).keyCode) {
+                return true;
+            }
+        }
+        return false;
+    }
+
     bool hasLed(int32_t deviceId, int32_t led) const override {
         Device* device = getDevice(deviceId);
         return device && device->leds.indexOfKey(led) >= 0;
@@ -3734,6 +3752,25 @@
               mapper2.getMetaState());
 }
 
+TEST_F(KeyboardInputMapperTest, Process_toggleCapsLockState) {
+    mFakeEventHub->addKey(EVENTHUB_ID, KEY_CAPSLOCK, 0, AKEYCODE_CAPS_LOCK, 0);
+    mFakeEventHub->addKey(EVENTHUB_ID, KEY_NUMLOCK, 0, AKEYCODE_NUM_LOCK, 0);
+    mFakeEventHub->addKey(EVENTHUB_ID, KEY_SCROLLLOCK, 0, AKEYCODE_SCROLL_LOCK, 0);
+
+    // Suppose we have two mappers. (DPAD + KEYBOARD)
+    addMapperAndConfigure<KeyboardInputMapper>(AINPUT_SOURCE_DPAD,
+                                               AINPUT_KEYBOARD_TYPE_NON_ALPHABETIC);
+    KeyboardInputMapper& mapper =
+            addMapperAndConfigure<KeyboardInputMapper>(AINPUT_SOURCE_KEYBOARD,
+                                                       AINPUT_KEYBOARD_TYPE_ALPHABETIC);
+    // Initialize metastate to AMETA_NUM_LOCK_ON.
+    ASSERT_EQ(AMETA_NUM_LOCK_ON, mapper.getMetaState());
+    mapper.updateMetaState(AKEYCODE_NUM_LOCK);
+
+    mReader->toggleCapsLockState(DEVICE_ID);
+    ASSERT_EQ(AMETA_CAPS_LOCK_ON, mapper.getMetaState());
+}
+
 // --- KeyboardInputMapperTest_ExternalDevice ---
 
 class KeyboardInputMapperTest_ExternalDevice : public InputMapperTest {