Skip processing repeat EV_KEY events for keyboards

Key repeat is handled by Android internally so we should not use the
kernel level key repeat.

Android attempts to disable key repeat by sending a EVIOCSREP ioctl
call, however this does not work on all keyboards (namely any that use
the atkbd driver) as [0, 0] are considered invalid configuration values
for the driver.

This functions in a similar way to the original intention in that it
will discard all kernel level repeat EV_KEY events to allow the system
level key-repeat to function correctly.

Bug: b/374209729
Test: Manually with offending device
Flag: EXEMPT bugfix
Change-Id: I5219edcddfc2fdb420e5c3ef7ecc9b5c557e5c6a
diff --git a/services/inputflinger/reader/mapper/KeyboardInputMapper.cpp b/services/inputflinger/reader/mapper/KeyboardInputMapper.cpp
index 567a3e2..852ed08 100644
--- a/services/inputflinger/reader/mapper/KeyboardInputMapper.cpp
+++ b/services/inputflinger/reader/mapper/KeyboardInputMapper.cpp
@@ -241,11 +241,16 @@
     mHidUsageAccumulator.process(rawEvent);
     switch (rawEvent.type) {
         case EV_KEY: {
-            int32_t scanCode = rawEvent.code;
+            // Skip processing repeated keys (value == 2) since auto repeat is handled by Android
+            // internally.
+            if (rawEvent.value == 2) {
+                break;
+            }
 
+            const int32_t scanCode = rawEvent.code;
             if (isSupportedScanCode(scanCode)) {
-                out += processKey(rawEvent.when, rawEvent.readTime, rawEvent.value != 0,
-                                  scanCode, mHidUsageAccumulator.consumeCurrentHidUsage());
+                out += processKey(rawEvent.when, rawEvent.readTime, rawEvent.value != 0, scanCode,
+                                  mHidUsageAccumulator.consumeCurrentHidUsage());
             }
             break;
         }
diff --git a/services/inputflinger/tests/KeyboardInputMapper_test.cpp b/services/inputflinger/tests/KeyboardInputMapper_test.cpp
index 88c25d3..bcc6062 100644
--- a/services/inputflinger/tests/KeyboardInputMapper_test.cpp
+++ b/services/inputflinger/tests/KeyboardInputMapper_test.cpp
@@ -20,16 +20,19 @@
 
 #include "InputMapperTest.h"
 #include "InterfaceMocks.h"
+#include "TestEventMatchers.h"
 
 #define TAG "KeyboardInputMapper_test"
 
 namespace android {
 
 using testing::_;
+using testing::AllOf;
 using testing::Args;
 using testing::DoAll;
 using testing::Return;
 using testing::SetArgPointee;
+using testing::VariantWith;
 
 /**
  * Unit tests for KeyboardInputMapper.
@@ -86,4 +89,24 @@
     }
 }
 
+TEST_F(KeyboardInputMapperUnitTest, RepeatEventsDiscarded) {
+    std::list<NotifyArgs> args;
+    args += process(ARBITRARY_TIME, EV_KEY, KEY_0, 1);
+    args += process(ARBITRARY_TIME, EV_SYN, SYN_REPORT, 0);
+
+    args += process(ARBITRARY_TIME, EV_KEY, KEY_0, 2);
+    args += process(ARBITRARY_TIME, EV_SYN, SYN_REPORT, 0);
+
+    args += process(ARBITRARY_TIME, EV_KEY, KEY_0, 0);
+    args += process(ARBITRARY_TIME, EV_SYN, SYN_REPORT, 0);
+
+    EXPECT_THAT(args,
+                ElementsAre(VariantWith<NotifyKeyArgs>(AllOf(WithKeyAction(AKEY_EVENT_ACTION_DOWN),
+                                                             WithKeyCode(AKEYCODE_0),
+                                                             WithScanCode(KEY_0))),
+                            VariantWith<NotifyKeyArgs>(AllOf(WithKeyAction(AKEY_EVENT_ACTION_UP),
+                                                             WithKeyCode(AKEYCODE_0),
+                                                             WithScanCode(KEY_0)))));
+}
+
 } // namespace android
diff --git a/services/inputflinger/tests/TestEventMatchers.h b/services/inputflinger/tests/TestEventMatchers.h
index 6fa3365..f58d8fd 100644
--- a/services/inputflinger/tests/TestEventMatchers.h
+++ b/services/inputflinger/tests/TestEventMatchers.h
@@ -540,6 +540,34 @@
     return WithKeyCodeMatcher(keyCode);
 }
 
+/// Scan code
+class WithScanCodeMatcher {
+public:
+    using is_gtest_matcher = void;
+    explicit WithScanCodeMatcher(int32_t scanCode) : mScanCode(scanCode) {}
+
+    bool MatchAndExplain(const NotifyKeyArgs& args, std::ostream*) const {
+        return mScanCode == args.scanCode;
+    }
+
+    bool MatchAndExplain(const KeyEvent& event, std::ostream*) const {
+        return mScanCode == event.getKeyCode();
+    }
+
+    void DescribeTo(std::ostream* os) const {
+        *os << "with scan code " << KeyEvent::getLabel(mScanCode);
+    }
+
+    void DescribeNegationTo(std::ostream* os) const { *os << "wrong scan code"; }
+
+private:
+    const int32_t mScanCode;
+};
+
+inline WithScanCodeMatcher WithScanCode(int32_t scanCode) {
+    return WithScanCodeMatcher(scanCode);
+}
+
 /// EventId
 class WithEventIdMatcher {
 public: