Merge "libgui: Add bq_gl_fence_cleanup flag" into main
diff --git a/include/android/OWNERS b/include/android/OWNERS
index fad8c1b..64d7e54 100644
--- a/include/android/OWNERS
+++ b/include/android/OWNERS
@@ -3,3 +3,6 @@
 # Window manager
 per-file surface_control_input_receiver.h = file:platform/frameworks/base:/services/core/java/com/android/server/wm/OWNERS
 per-file input_transfer_token.h = file:platform/frameworks/base:/services/core/java/com/android/server/wm/OWNERS
+
+# CoGS
+per-file *luts* = file:platform/frameworks/base:/graphics/java/android/graphics/OWNERS
\ No newline at end of file
diff --git a/include/android/performance_hint.h b/include/android/performance_hint.h
index 3486e9b..976c7d6 100644
--- a/include/android/performance_hint.h
+++ b/include/android/performance_hint.h
@@ -19,9 +19,23 @@
  *
  * APerformanceHint allows apps to create performance hint sessions for groups
  * of threads, and provide hints to the system about the workload of those threads,
- * to help the system more accurately allocate power for them. It is the NDK
+ * to help the system more accurately allocate resources for them. It is the NDK
  * counterpart to the Java PerformanceHintManager SDK API.
  *
+ * This API is intended for periodic workloads, such as frame production. Clients are
+ * expected to create an instance of APerformanceHintManager, create a session with
+ * that, and then set a target duration for the session. Then, they can report the actual
+ * work duration at the end of each cycle to inform the framework about how long those
+ * workloads are taking. The framework will then compare the actual durations to the target
+ * duration and attempt to help the client reach a steady state under the target.
+ *
+ * Unlike reportActualWorkDuration, the "notify..." hints are intended to be sent in
+ * advance of large changes in the workload, to prevent them from going over the target
+ * when there is a sudden, unforseen change. Their effects are intended to last for only
+ * one cycle, after which reportActualWorkDuration will have a chance to catch up.
+ * These hints should be used judiciously, only in cases where the workload is changing
+ * substantially. To enforce that, they are tracked using a per-app rate limiter to avoid
+ * excessive hinting and encourage clients to be mindful about when to send them.
  * @{
  */
 
@@ -250,6 +264,54 @@
         AWorkDuration* _Nonnull workDuration) __INTRODUCED_IN(__ANDROID_API_V__);
 
 /**
+ * Informs the framework of an upcoming increase in the workload of a graphics pipeline
+ * bound to this session. The user can specify whether the increase is expected to be
+ * on the CPU, GPU, or both.
+ *
+ * Sending hints for both CPU and GPU counts as two separate hints for the purposes of the
+ * rate limiter.
+ *
+ * @param cpu Indicates if the workload increase is expected to affect the CPU.
+ * @param gpu Indicates if the workload increase is expected to affect the GPU.
+ * @param debugName A required string used to identify this specific hint during
+ *        tracing. This debug string will only be held for the duration of the
+ *        method, and can be safely discarded after.
+ *
+ * @return 0 on success.
+ *         EINVAL if no hints were requested.
+ *         EBUSY if the hint was rate limited.
+ *         EPIPE if communication with the system service has failed.
+ *         ENOTSUP if the hint is not supported.
+ */
+int APerformanceHint_notifyWorkloadIncrease(
+        APerformanceHintSession* _Nonnull session,
+        bool cpu, bool gpu, const char* _Nonnull debugName) __INTRODUCED_IN(36);
+
+/**
+ * Informs the framework of an upcoming reset in the workload of a graphics pipeline
+ * bound to this session, or the imminent start of a new workload. The user can specify
+ * whether the reset is expected to affect the CPU, GPU, or both.
+ *
+ * Sending hints for both CPU and GPU counts as two separate hints for the purposes of the
+ * this load tracking.
+ *
+ * @param cpu Indicates if the workload reset is expected to affect the CPU.
+ * @param gpu Indicates if the workload reset is expected to affect the GPU.
+ * @param debugName A required string used to identify this specific hint during
+ *        tracing. This debug string will only be held for the duration of the
+ *        method, and can be safely discarded after.
+ *
+ * @return 0 on success.
+ *         EINVAL if no hints were requested.
+ *         EBUSY if the hint was rate limited.
+ *         EPIPE if communication with the system service has failed.
+ *         ENOTSUP if the hint is not supported.
+ */
+int APerformanceHint_notifyWorkloadReset(
+        APerformanceHintSession* _Nonnull session,
+        bool cpu, bool gpu, const char* _Nonnull debugName) __INTRODUCED_IN(36);
+
+/**
  * Creates a new AWorkDuration. When the client finishes using {@link AWorkDuration}, it should
  * call {@link AWorkDuration_release()} to destroy {@link AWorkDuration} and release all resources
  * associated with it.
diff --git a/include/private/performance_hint_private.h b/include/private/performance_hint_private.h
index b7308c2..3229e45 100644
--- a/include/private/performance_hint_private.h
+++ b/include/private/performance_hint_private.h
@@ -114,6 +114,18 @@
  */
 void APerformanceHint_setUseFMQForTesting(bool enabled);
 
+/**
+ * Get the rate limiter properties for testing.
+ */
+void APerformanceHint_getRateLimiterPropertiesForTesting(
+        int32_t* maxLoadHintsPerInterval, int64_t* loadHintInterval);
+
+/*
+ * Forces the "new load hint" flag to be disabled for testing.
+ */
+void APerformanceHint_setUseNewLoadHintBehaviorForTesting(bool newBehavior);
+
+
 __END_DECLS
 
 #endif // ANDROID_PRIVATE_NATIVE_PERFORMANCE_HINT_PRIVATE_H
diff --git a/libs/binder/Android.bp b/libs/binder/Android.bp
index 2ef642a..0a61178 100644
--- a/libs/binder/Android.bp
+++ b/libs/binder/Android.bp
@@ -829,6 +829,7 @@
     backend: {
         rust: {
             apex_available: [
+                "//apex_available:platform",
                 "com.android.virt",
             ],
             enabled: true,
@@ -881,7 +882,6 @@
         ":__subpackages__",
         "//packages/modules/Virtualization:__subpackages__",
         "//device/google/cuttlefish/shared/minidroid:__subpackages__",
-        "//system/software_defined_vehicle:__subpackages__",
         "//visibility:any_system_partition",
     ],
 }
diff --git a/libs/binder/rust/rpcbinder/Android.bp b/libs/binder/rust/rpcbinder/Android.bp
index 174fe8a..4036551 100644
--- a/libs/binder/rust/rpcbinder/Android.bp
+++ b/libs/binder/rust/rpcbinder/Android.bp
@@ -27,7 +27,6 @@
     visibility: [
         "//device/google/cuttlefish/shared/minidroid/sample",
         "//packages/modules/Virtualization:__subpackages__",
-        "//system/software_defined_vehicle:__subpackages__",
     ],
     apex_available: [
         "//apex_available:platform",
diff --git a/services/inputflinger/tests/InputReader_test.cpp b/services/inputflinger/tests/InputReader_test.cpp
index ee3b2a2..9d2256f 100644
--- a/services/inputflinger/tests/InputReader_test.cpp
+++ b/services/inputflinger/tests/InputReader_test.cpp
@@ -3031,1048 +3031,6 @@
     mapper.assertProcessWasCalled();
 }
 
-// --- KeyboardInputMapperTest ---
-
-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);
-
-    void testDPadKeyRotation(KeyboardInputMapper& mapper, int32_t originalScanCode,
-                             int32_t originalKeyCode, int32_t rotatedKeyCode,
-                             ui::LogicalDisplayId displayId = ui::LogicalDisplayId::INVALID);
-};
-
-/* Similar to setDisplayInfoAndReconfigure, but pre-populates all parameters except for the
- * orientation.
- */
-void KeyboardInputMapperTest::prepareDisplay(ui::Rotation orientation) {
-    setDisplayInfoAndReconfigure(DISPLAY_ID, DISPLAY_WIDTH, DISPLAY_HEIGHT, orientation, UNIQUE_ID,
-                                 NO_PORT, ViewportType::INTERNAL);
-}
-
-void KeyboardInputMapperTest::testDPadKeyRotation(KeyboardInputMapper& mapper,
-                                                  int32_t originalScanCode, int32_t originalKeyCode,
-                                                  int32_t rotatedKeyCode,
-                                                  ui::LogicalDisplayId displayId) {
-    NotifyKeyArgs args;
-
-    process(mapper, ARBITRARY_TIME, READ_TIME, EV_KEY, originalScanCode, 1);
-    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyKeyWasCalled(&args));
-    ASSERT_EQ(AKEY_EVENT_ACTION_DOWN, args.action);
-    ASSERT_EQ(originalScanCode, args.scanCode);
-    ASSERT_EQ(rotatedKeyCode, args.keyCode);
-    ASSERT_EQ(displayId, args.displayId);
-
-    process(mapper, ARBITRARY_TIME, READ_TIME, EV_KEY, originalScanCode, 0);
-    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyKeyWasCalled(&args));
-    ASSERT_EQ(AKEY_EVENT_ACTION_UP, args.action);
-    ASSERT_EQ(originalScanCode, args.scanCode);
-    ASSERT_EQ(rotatedKeyCode, args.keyCode);
-    ASSERT_EQ(displayId, args.displayId);
-}
-
-TEST_F(KeyboardInputMapperTest, GetSources) {
-    KeyboardInputMapper& mapper =
-            constructAndAddMapper<KeyboardInputMapper>(AINPUT_SOURCE_KEYBOARD);
-
-    ASSERT_EQ(AINPUT_SOURCE_KEYBOARD, mapper.getSources());
-}
-
-TEST_F(KeyboardInputMapperTest, Process_SimpleKeyPress) {
-    const int32_t USAGE_A = 0x070004;
-    const int32_t USAGE_UNKNOWN = 0x07ffff;
-    mFakeEventHub->addKey(EVENTHUB_ID, KEY_HOME, 0, AKEYCODE_HOME, POLICY_FLAG_WAKE);
-    mFakeEventHub->addKey(EVENTHUB_ID, 0, USAGE_A, AKEYCODE_A, POLICY_FLAG_WAKE);
-    mFakeEventHub->addKey(EVENTHUB_ID, 0, KEY_NUMLOCK, AKEYCODE_NUM_LOCK, POLICY_FLAG_WAKE);
-    mFakeEventHub->addKey(EVENTHUB_ID, 0, KEY_CAPSLOCK, AKEYCODE_CAPS_LOCK, POLICY_FLAG_WAKE);
-    mFakeEventHub->addKey(EVENTHUB_ID, 0, KEY_SCROLLLOCK, AKEYCODE_SCROLL_LOCK, POLICY_FLAG_WAKE);
-
-    KeyboardInputMapper& mapper =
-            constructAndAddMapper<KeyboardInputMapper>(AINPUT_SOURCE_KEYBOARD);
-    // Initial metastate is AMETA_NONE.
-    ASSERT_EQ(AMETA_NONE, mapper.getMetaState());
-
-    // Key down by scan code.
-    process(mapper, ARBITRARY_TIME, READ_TIME, EV_KEY, KEY_HOME, 1);
-    NotifyKeyArgs args;
-    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyKeyWasCalled(&args));
-    ASSERT_EQ(DEVICE_ID, args.deviceId);
-    ASSERT_EQ(AINPUT_SOURCE_KEYBOARD, args.source);
-    ASSERT_EQ(ARBITRARY_TIME, args.eventTime);
-    ASSERT_EQ(AKEY_EVENT_ACTION_DOWN, args.action);
-    ASSERT_EQ(AKEYCODE_HOME, args.keyCode);
-    ASSERT_EQ(KEY_HOME, args.scanCode);
-    ASSERT_EQ(AMETA_NONE, args.metaState);
-    ASSERT_EQ(AKEY_EVENT_FLAG_FROM_SYSTEM, args.flags);
-    ASSERT_EQ(POLICY_FLAG_WAKE, args.policyFlags);
-    ASSERT_EQ(ARBITRARY_TIME, args.downTime);
-
-    // Key up by scan code.
-    process(mapper, ARBITRARY_TIME + 1, READ_TIME, EV_KEY, KEY_HOME, 0);
-    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyKeyWasCalled(&args));
-    ASSERT_EQ(DEVICE_ID, args.deviceId);
-    ASSERT_EQ(AINPUT_SOURCE_KEYBOARD, args.source);
-    ASSERT_EQ(ARBITRARY_TIME + 1, args.eventTime);
-    ASSERT_EQ(AKEY_EVENT_ACTION_UP, args.action);
-    ASSERT_EQ(AKEYCODE_HOME, args.keyCode);
-    ASSERT_EQ(KEY_HOME, args.scanCode);
-    ASSERT_EQ(AMETA_NONE, args.metaState);
-    ASSERT_EQ(AKEY_EVENT_FLAG_FROM_SYSTEM, args.flags);
-    ASSERT_EQ(POLICY_FLAG_WAKE, args.policyFlags);
-    ASSERT_EQ(ARBITRARY_TIME, args.downTime);
-
-    // Key down by usage code.
-    process(mapper, ARBITRARY_TIME, READ_TIME, EV_MSC, MSC_SCAN, USAGE_A);
-    process(mapper, ARBITRARY_TIME, READ_TIME, EV_KEY, 0, 1);
-    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyKeyWasCalled(&args));
-    ASSERT_EQ(DEVICE_ID, args.deviceId);
-    ASSERT_EQ(AINPUT_SOURCE_KEYBOARD, args.source);
-    ASSERT_EQ(ARBITRARY_TIME, args.eventTime);
-    ASSERT_EQ(AKEY_EVENT_ACTION_DOWN, args.action);
-    ASSERT_EQ(AKEYCODE_A, args.keyCode);
-    ASSERT_EQ(0, args.scanCode);
-    ASSERT_EQ(AMETA_NONE, args.metaState);
-    ASSERT_EQ(AKEY_EVENT_FLAG_FROM_SYSTEM, args.flags);
-    ASSERT_EQ(POLICY_FLAG_WAKE, args.policyFlags);
-    ASSERT_EQ(ARBITRARY_TIME, args.downTime);
-
-    // Key up by usage code.
-    process(mapper, ARBITRARY_TIME, READ_TIME, EV_MSC, MSC_SCAN, USAGE_A);
-    process(mapper, ARBITRARY_TIME + 1, READ_TIME, EV_KEY, 0, 0);
-    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyKeyWasCalled(&args));
-    ASSERT_EQ(DEVICE_ID, args.deviceId);
-    ASSERT_EQ(AINPUT_SOURCE_KEYBOARD, args.source);
-    ASSERT_EQ(ARBITRARY_TIME + 1, args.eventTime);
-    ASSERT_EQ(AKEY_EVENT_ACTION_UP, args.action);
-    ASSERT_EQ(AKEYCODE_A, args.keyCode);
-    ASSERT_EQ(0, args.scanCode);
-    ASSERT_EQ(AMETA_NONE, args.metaState);
-    ASSERT_EQ(AKEY_EVENT_FLAG_FROM_SYSTEM, args.flags);
-    ASSERT_EQ(POLICY_FLAG_WAKE, args.policyFlags);
-    ASSERT_EQ(ARBITRARY_TIME, args.downTime);
-
-    // Key down with unknown scan code or usage code.
-    process(mapper, ARBITRARY_TIME, READ_TIME, EV_MSC, MSC_SCAN, USAGE_UNKNOWN);
-    process(mapper, ARBITRARY_TIME, READ_TIME, EV_KEY, KEY_UNKNOWN, 1);
-    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyKeyWasCalled(&args));
-    ASSERT_EQ(DEVICE_ID, args.deviceId);
-    ASSERT_EQ(AINPUT_SOURCE_KEYBOARD, args.source);
-    ASSERT_EQ(ARBITRARY_TIME, args.eventTime);
-    ASSERT_EQ(AKEY_EVENT_ACTION_DOWN, args.action);
-    ASSERT_EQ(0, args.keyCode);
-    ASSERT_EQ(KEY_UNKNOWN, args.scanCode);
-    ASSERT_EQ(AMETA_NONE, args.metaState);
-    ASSERT_EQ(AKEY_EVENT_FLAG_FROM_SYSTEM, args.flags);
-    ASSERT_EQ(0U, args.policyFlags);
-    ASSERT_EQ(ARBITRARY_TIME, args.downTime);
-
-    // Key up with unknown scan code or usage code.
-    process(mapper, ARBITRARY_TIME, READ_TIME, EV_MSC, MSC_SCAN, USAGE_UNKNOWN);
-    process(mapper, ARBITRARY_TIME + 1, READ_TIME, EV_KEY, KEY_UNKNOWN, 0);
-    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyKeyWasCalled(&args));
-    ASSERT_EQ(DEVICE_ID, args.deviceId);
-    ASSERT_EQ(AINPUT_SOURCE_KEYBOARD, args.source);
-    ASSERT_EQ(ARBITRARY_TIME + 1, args.eventTime);
-    ASSERT_EQ(AKEY_EVENT_ACTION_UP, args.action);
-    ASSERT_EQ(0, args.keyCode);
-    ASSERT_EQ(KEY_UNKNOWN, args.scanCode);
-    ASSERT_EQ(AMETA_NONE, args.metaState);
-    ASSERT_EQ(AKEY_EVENT_FLAG_FROM_SYSTEM, args.flags);
-    ASSERT_EQ(0U, args.policyFlags);
-    ASSERT_EQ(ARBITRARY_TIME, args.downTime);
-}
-
-TEST_F(KeyboardInputMapperTest, Process_KeyRemapping) {
-    mFakeEventHub->addKey(EVENTHUB_ID, KEY_A, 0, AKEYCODE_A, 0);
-    mFakeEventHub->addKey(EVENTHUB_ID, KEY_B, 0, AKEYCODE_B, 0);
-
-    KeyboardInputMapper& mapper =
-            constructAndAddMapper<KeyboardInputMapper>(AINPUT_SOURCE_KEYBOARD);
-
-    mFakeEventHub->setKeyRemapping(EVENTHUB_ID, {{AKEYCODE_A, AKEYCODE_B}});
-    // Key down by scan code.
-    process(mapper, ARBITRARY_TIME, READ_TIME, EV_KEY, KEY_A, 1);
-    NotifyKeyArgs args;
-    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyKeyWasCalled(&args));
-    ASSERT_EQ(AKEYCODE_B, args.keyCode);
-
-    // Key up by scan code.
-    process(mapper, ARBITRARY_TIME + 1, READ_TIME, EV_KEY, KEY_A, 0);
-    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyKeyWasCalled(&args));
-    ASSERT_EQ(AKEYCODE_B, args.keyCode);
-}
-
-/**
- * Ensure that the readTime is set to the time when the EV_KEY is received.
- */
-TEST_F(KeyboardInputMapperTest, Process_SendsReadTime) {
-    mFakeEventHub->addKey(EVENTHUB_ID, KEY_HOME, 0, AKEYCODE_HOME, POLICY_FLAG_WAKE);
-
-    KeyboardInputMapper& mapper =
-            constructAndAddMapper<KeyboardInputMapper>(AINPUT_SOURCE_KEYBOARD);
-    NotifyKeyArgs args;
-
-    // Key down
-    process(mapper, ARBITRARY_TIME, /*readTime=*/12, EV_KEY, KEY_HOME, 1);
-    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyKeyWasCalled(&args));
-    ASSERT_EQ(12, args.readTime);
-
-    // Key up
-    process(mapper, ARBITRARY_TIME, /*readTime=*/15, EV_KEY, KEY_HOME, 1);
-    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyKeyWasCalled(&args));
-    ASSERT_EQ(15, args.readTime);
-}
-
-TEST_F(KeyboardInputMapperTest, Process_ShouldUpdateMetaState) {
-    mFakeEventHub->addKey(EVENTHUB_ID, KEY_LEFTSHIFT, 0, AKEYCODE_SHIFT_LEFT, 0);
-    mFakeEventHub->addKey(EVENTHUB_ID, KEY_A, 0, AKEYCODE_A, 0);
-    mFakeEventHub->addKey(EVENTHUB_ID, 0, KEY_NUMLOCK, AKEYCODE_NUM_LOCK, 0);
-    mFakeEventHub->addKey(EVENTHUB_ID, 0, KEY_CAPSLOCK, AKEYCODE_CAPS_LOCK, 0);
-    mFakeEventHub->addKey(EVENTHUB_ID, 0, KEY_SCROLLLOCK, AKEYCODE_SCROLL_LOCK, 0);
-
-    KeyboardInputMapper& mapper =
-            constructAndAddMapper<KeyboardInputMapper>(AINPUT_SOURCE_KEYBOARD);
-
-    // Initial metastate is AMETA_NONE.
-    ASSERT_EQ(AMETA_NONE, mapper.getMetaState());
-
-    // Metakey down.
-    process(mapper, ARBITRARY_TIME, READ_TIME, EV_KEY, KEY_LEFTSHIFT, 1);
-    NotifyKeyArgs args;
-    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyKeyWasCalled(&args));
-    ASSERT_EQ(AMETA_SHIFT_LEFT_ON | AMETA_SHIFT_ON, args.metaState);
-    ASSERT_EQ(AMETA_SHIFT_LEFT_ON | AMETA_SHIFT_ON, mapper.getMetaState());
-    ASSERT_NO_FATAL_FAILURE(mReader->getContext()->assertUpdateGlobalMetaStateWasCalled());
-
-    // Key down.
-    process(mapper, ARBITRARY_TIME + 1, READ_TIME, EV_KEY, KEY_A, 1);
-    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyKeyWasCalled(&args));
-    ASSERT_EQ(AMETA_SHIFT_LEFT_ON | AMETA_SHIFT_ON, args.metaState);
-    ASSERT_EQ(AMETA_SHIFT_LEFT_ON | AMETA_SHIFT_ON, mapper.getMetaState());
-
-    // Key up.
-    process(mapper, ARBITRARY_TIME + 2, READ_TIME, EV_KEY, KEY_A, 0);
-    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyKeyWasCalled(&args));
-    ASSERT_EQ(AMETA_SHIFT_LEFT_ON | AMETA_SHIFT_ON, args.metaState);
-    ASSERT_EQ(AMETA_SHIFT_LEFT_ON | AMETA_SHIFT_ON, mapper.getMetaState());
-
-    // Metakey up.
-    process(mapper, ARBITRARY_TIME + 3, READ_TIME, EV_KEY, KEY_LEFTSHIFT, 0);
-    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyKeyWasCalled(&args));
-    ASSERT_EQ(AMETA_NONE, args.metaState);
-    ASSERT_EQ(AMETA_NONE, mapper.getMetaState());
-    ASSERT_NO_FATAL_FAILURE(mReader->getContext()->assertUpdateGlobalMetaStateWasCalled());
-}
-
-TEST_F(KeyboardInputMapperTest, Process_WhenNotOrientationAware_ShouldNotRotateDPad) {
-    mFakeEventHub->addKey(EVENTHUB_ID, KEY_UP, 0, AKEYCODE_DPAD_UP, 0);
-    mFakeEventHub->addKey(EVENTHUB_ID, KEY_RIGHT, 0, AKEYCODE_DPAD_RIGHT, 0);
-    mFakeEventHub->addKey(EVENTHUB_ID, KEY_DOWN, 0, AKEYCODE_DPAD_DOWN, 0);
-    mFakeEventHub->addKey(EVENTHUB_ID, KEY_LEFT, 0, AKEYCODE_DPAD_LEFT, 0);
-
-    KeyboardInputMapper& mapper =
-            constructAndAddMapper<KeyboardInputMapper>(AINPUT_SOURCE_KEYBOARD);
-
-    prepareDisplay(ui::ROTATION_90);
-    ASSERT_NO_FATAL_FAILURE(testDPadKeyRotation(mapper,
-            KEY_UP, AKEYCODE_DPAD_UP, AKEYCODE_DPAD_UP));
-    ASSERT_NO_FATAL_FAILURE(testDPadKeyRotation(mapper,
-            KEY_RIGHT, AKEYCODE_DPAD_RIGHT, AKEYCODE_DPAD_RIGHT));
-    ASSERT_NO_FATAL_FAILURE(testDPadKeyRotation(mapper,
-            KEY_DOWN, AKEYCODE_DPAD_DOWN, AKEYCODE_DPAD_DOWN));
-    ASSERT_NO_FATAL_FAILURE(testDPadKeyRotation(mapper,
-            KEY_LEFT, AKEYCODE_DPAD_LEFT, AKEYCODE_DPAD_LEFT));
-}
-
-TEST_F(KeyboardInputMapperTest, Process_WhenOrientationAware_ShouldRotateDPad) {
-    mFakeEventHub->addKey(EVENTHUB_ID, KEY_UP, 0, AKEYCODE_DPAD_UP, 0);
-    mFakeEventHub->addKey(EVENTHUB_ID, KEY_RIGHT, 0, AKEYCODE_DPAD_RIGHT, 0);
-    mFakeEventHub->addKey(EVENTHUB_ID, KEY_DOWN, 0, AKEYCODE_DPAD_DOWN, 0);
-    mFakeEventHub->addKey(EVENTHUB_ID, KEY_LEFT, 0, AKEYCODE_DPAD_LEFT, 0);
-
-    addConfigurationProperty("keyboard.orientationAware", "1");
-    KeyboardInputMapper& mapper =
-            constructAndAddMapper<KeyboardInputMapper>(AINPUT_SOURCE_KEYBOARD);
-
-    prepareDisplay(ui::ROTATION_0);
-    ASSERT_NO_FATAL_FAILURE(
-            testDPadKeyRotation(mapper, KEY_UP, AKEYCODE_DPAD_UP, AKEYCODE_DPAD_UP, DISPLAY_ID));
-    ASSERT_NO_FATAL_FAILURE(testDPadKeyRotation(mapper, KEY_RIGHT, AKEYCODE_DPAD_RIGHT,
-                                                AKEYCODE_DPAD_RIGHT, DISPLAY_ID));
-    ASSERT_NO_FATAL_FAILURE(testDPadKeyRotation(mapper, KEY_DOWN, AKEYCODE_DPAD_DOWN,
-                                                AKEYCODE_DPAD_DOWN, DISPLAY_ID));
-    ASSERT_NO_FATAL_FAILURE(testDPadKeyRotation(mapper, KEY_LEFT, AKEYCODE_DPAD_LEFT,
-                                                AKEYCODE_DPAD_LEFT, DISPLAY_ID));
-
-    clearViewports();
-    prepareDisplay(ui::ROTATION_90);
-    ASSERT_NO_FATAL_FAILURE(
-            testDPadKeyRotation(mapper, KEY_UP, AKEYCODE_DPAD_UP, AKEYCODE_DPAD_LEFT, DISPLAY_ID));
-    ASSERT_NO_FATAL_FAILURE(testDPadKeyRotation(mapper, KEY_RIGHT, AKEYCODE_DPAD_RIGHT,
-                                                AKEYCODE_DPAD_UP, DISPLAY_ID));
-    ASSERT_NO_FATAL_FAILURE(testDPadKeyRotation(mapper, KEY_DOWN, AKEYCODE_DPAD_DOWN,
-                                                AKEYCODE_DPAD_RIGHT, DISPLAY_ID));
-    ASSERT_NO_FATAL_FAILURE(testDPadKeyRotation(mapper, KEY_LEFT, AKEYCODE_DPAD_LEFT,
-                                                AKEYCODE_DPAD_DOWN, DISPLAY_ID));
-
-    clearViewports();
-    prepareDisplay(ui::ROTATION_180);
-    ASSERT_NO_FATAL_FAILURE(
-            testDPadKeyRotation(mapper, KEY_UP, AKEYCODE_DPAD_UP, AKEYCODE_DPAD_DOWN, DISPLAY_ID));
-    ASSERT_NO_FATAL_FAILURE(testDPadKeyRotation(mapper, KEY_RIGHT, AKEYCODE_DPAD_RIGHT,
-                                                AKEYCODE_DPAD_LEFT, DISPLAY_ID));
-    ASSERT_NO_FATAL_FAILURE(testDPadKeyRotation(mapper, KEY_DOWN, AKEYCODE_DPAD_DOWN,
-                                                AKEYCODE_DPAD_UP, DISPLAY_ID));
-    ASSERT_NO_FATAL_FAILURE(testDPadKeyRotation(mapper, KEY_LEFT, AKEYCODE_DPAD_LEFT,
-                                                AKEYCODE_DPAD_RIGHT, DISPLAY_ID));
-
-    clearViewports();
-    prepareDisplay(ui::ROTATION_270);
-    ASSERT_NO_FATAL_FAILURE(
-            testDPadKeyRotation(mapper, KEY_UP, AKEYCODE_DPAD_UP, AKEYCODE_DPAD_RIGHT, DISPLAY_ID));
-    ASSERT_NO_FATAL_FAILURE(testDPadKeyRotation(mapper, KEY_RIGHT, AKEYCODE_DPAD_RIGHT,
-                                                AKEYCODE_DPAD_DOWN, DISPLAY_ID));
-    ASSERT_NO_FATAL_FAILURE(testDPadKeyRotation(mapper, KEY_DOWN, AKEYCODE_DPAD_DOWN,
-                                                AKEYCODE_DPAD_LEFT, DISPLAY_ID));
-    ASSERT_NO_FATAL_FAILURE(testDPadKeyRotation(mapper, KEY_LEFT, AKEYCODE_DPAD_LEFT,
-                                                AKEYCODE_DPAD_UP, DISPLAY_ID));
-
-    // Special case: if orientation changes while key is down, we still emit the same keycode
-    // in the key up as we did in the key down.
-    NotifyKeyArgs args;
-    clearViewports();
-    prepareDisplay(ui::ROTATION_270);
-    process(mapper, ARBITRARY_TIME, READ_TIME, EV_KEY, KEY_UP, 1);
-    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyKeyWasCalled(&args));
-    ASSERT_EQ(AKEY_EVENT_ACTION_DOWN, args.action);
-    ASSERT_EQ(KEY_UP, args.scanCode);
-    ASSERT_EQ(AKEYCODE_DPAD_RIGHT, args.keyCode);
-
-    clearViewports();
-    prepareDisplay(ui::ROTATION_180);
-    process(mapper, ARBITRARY_TIME, READ_TIME, EV_KEY, KEY_UP, 0);
-    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyKeyWasCalled(&args));
-    ASSERT_EQ(AKEY_EVENT_ACTION_UP, args.action);
-    ASSERT_EQ(KEY_UP, args.scanCode);
-    ASSERT_EQ(AKEYCODE_DPAD_RIGHT, args.keyCode);
-}
-
-TEST_F(KeyboardInputMapperTest, DisplayIdConfigurationChange_NotOrientationAware) {
-    // If the keyboard is not orientation aware,
-    // key events should not be associated with a specific display id
-    mFakeEventHub->addKey(EVENTHUB_ID, KEY_UP, 0, AKEYCODE_DPAD_UP, 0);
-
-    KeyboardInputMapper& mapper =
-            constructAndAddMapper<KeyboardInputMapper>(AINPUT_SOURCE_KEYBOARD);
-    NotifyKeyArgs args;
-
-    // Display id should be LogicalDisplayId::INVALID without any display configuration.
-    process(mapper, ARBITRARY_TIME, READ_TIME, EV_KEY, KEY_UP, 1);
-    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyKeyWasCalled(&args));
-    process(mapper, ARBITRARY_TIME, READ_TIME, EV_KEY, KEY_UP, 0);
-    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyKeyWasCalled(&args));
-    ASSERT_EQ(ui::LogicalDisplayId::INVALID, args.displayId);
-
-    prepareDisplay(ui::ROTATION_0);
-    process(mapper, ARBITRARY_TIME, READ_TIME, EV_KEY, KEY_UP, 1);
-    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyKeyWasCalled(&args));
-    process(mapper, ARBITRARY_TIME, READ_TIME, EV_KEY, KEY_UP, 0);
-    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyKeyWasCalled(&args));
-    ASSERT_EQ(ui::LogicalDisplayId::INVALID, args.displayId);
-}
-
-TEST_F(KeyboardInputMapperTest, DisplayIdConfigurationChange_OrientationAware) {
-    // If the keyboard is orientation aware,
-    // key events should be associated with the internal viewport
-    mFakeEventHub->addKey(EVENTHUB_ID, KEY_UP, 0, AKEYCODE_DPAD_UP, 0);
-
-    addConfigurationProperty("keyboard.orientationAware", "1");
-    KeyboardInputMapper& mapper =
-            constructAndAddMapper<KeyboardInputMapper>(AINPUT_SOURCE_KEYBOARD);
-    NotifyKeyArgs args;
-
-    // Display id should be LogicalDisplayId::INVALID without any display configuration.
-    // ^--- already checked by the previous test
-
-    setDisplayInfoAndReconfigure(DISPLAY_ID, DISPLAY_WIDTH, DISPLAY_HEIGHT, ui::ROTATION_0,
-                                 UNIQUE_ID, NO_PORT, ViewportType::INTERNAL);
-    process(mapper, ARBITRARY_TIME, READ_TIME, EV_KEY, KEY_UP, 1);
-    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyKeyWasCalled(&args));
-    process(mapper, ARBITRARY_TIME, READ_TIME, EV_KEY, KEY_UP, 0);
-    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyKeyWasCalled(&args));
-    ASSERT_EQ(DISPLAY_ID, args.displayId);
-
-    constexpr ui::LogicalDisplayId newDisplayId = ui::LogicalDisplayId{2};
-    clearViewports();
-    setDisplayInfoAndReconfigure(newDisplayId, DISPLAY_WIDTH, DISPLAY_HEIGHT, ui::ROTATION_0,
-                                 UNIQUE_ID, NO_PORT, ViewportType::INTERNAL);
-    process(mapper, ARBITRARY_TIME, READ_TIME, EV_KEY, KEY_UP, 1);
-    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyKeyWasCalled(&args));
-    process(mapper, ARBITRARY_TIME, READ_TIME, EV_KEY, KEY_UP, 0);
-    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyKeyWasCalled(&args));
-    ASSERT_EQ(newDisplayId, args.displayId);
-}
-
-TEST_F(KeyboardInputMapperTest, GetKeyCodeState) {
-    KeyboardInputMapper& mapper =
-            constructAndAddMapper<KeyboardInputMapper>(AINPUT_SOURCE_KEYBOARD);
-
-    mFakeEventHub->setKeyCodeState(EVENTHUB_ID, AKEYCODE_A, 1);
-    ASSERT_EQ(1, mapper.getKeyCodeState(AINPUT_SOURCE_ANY, AKEYCODE_A));
-
-    mFakeEventHub->setKeyCodeState(EVENTHUB_ID, AKEYCODE_A, 0);
-    ASSERT_EQ(0, mapper.getKeyCodeState(AINPUT_SOURCE_ANY, AKEYCODE_A));
-}
-
-TEST_F(KeyboardInputMapperTest, GetKeyCodeForKeyLocation) {
-    KeyboardInputMapper& mapper =
-            constructAndAddMapper<KeyboardInputMapper>(AINPUT_SOURCE_KEYBOARD);
-
-    mFakeEventHub->addKeyCodeMapping(EVENTHUB_ID, AKEYCODE_Y, AKEYCODE_Z);
-    ASSERT_EQ(AKEYCODE_Z, mapper.getKeyCodeForKeyLocation(AKEYCODE_Y))
-            << "If a mapping is available, the result is equal to the mapping";
-
-    ASSERT_EQ(AKEYCODE_A, mapper.getKeyCodeForKeyLocation(AKEYCODE_A))
-            << "If no mapping is available, the result is the key location";
-}
-
-TEST_F(KeyboardInputMapperTest, GetScanCodeState) {
-    KeyboardInputMapper& mapper =
-            constructAndAddMapper<KeyboardInputMapper>(AINPUT_SOURCE_KEYBOARD);
-
-    mFakeEventHub->setScanCodeState(EVENTHUB_ID, KEY_A, 1);
-    ASSERT_EQ(1, mapper.getScanCodeState(AINPUT_SOURCE_ANY, KEY_A));
-
-    mFakeEventHub->setScanCodeState(EVENTHUB_ID, KEY_A, 0);
-    ASSERT_EQ(0, mapper.getScanCodeState(AINPUT_SOURCE_ANY, KEY_A));
-}
-
-TEST_F(KeyboardInputMapperTest, MarkSupportedKeyCodes) {
-    KeyboardInputMapper& mapper =
-            constructAndAddMapper<KeyboardInputMapper>(AINPUT_SOURCE_KEYBOARD);
-
-    mFakeEventHub->addKey(EVENTHUB_ID, KEY_A, 0, AKEYCODE_A, 0);
-
-    uint8_t flags[2] = { 0, 0 };
-    ASSERT_TRUE(mapper.markSupportedKeyCodes(AINPUT_SOURCE_ANY, {AKEYCODE_A, AKEYCODE_B}, flags));
-    ASSERT_TRUE(flags[0]);
-    ASSERT_FALSE(flags[1]);
-}
-
-TEST_F(KeyboardInputMapperTest, Process_LockedKeysShouldToggleMetaStateAndLeds) {
-    mFakeEventHub->addLed(EVENTHUB_ID, LED_CAPSL, true /*initially on*/);
-    mFakeEventHub->addLed(EVENTHUB_ID, LED_NUML, false /*initially off*/);
-    mFakeEventHub->addLed(EVENTHUB_ID, LED_SCROLLL, false /*initially off*/);
-    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);
-
-    KeyboardInputMapper& mapper =
-            constructAndAddMapper<KeyboardInputMapper>(AINPUT_SOURCE_KEYBOARD);
-    // Initial metastate is AMETA_NONE.
-    ASSERT_EQ(AMETA_NONE, mapper.getMetaState());
-
-    // Initialization should have turned all of the lights off.
-    ASSERT_FALSE(mFakeEventHub->getLedState(EVENTHUB_ID, LED_CAPSL));
-    ASSERT_FALSE(mFakeEventHub->getLedState(EVENTHUB_ID, LED_NUML));
-    ASSERT_FALSE(mFakeEventHub->getLedState(EVENTHUB_ID, LED_SCROLLL));
-
-    // Toggle caps lock on.
-    process(mapper, ARBITRARY_TIME, READ_TIME, EV_KEY, KEY_CAPSLOCK, 1);
-    process(mapper, ARBITRARY_TIME, READ_TIME, EV_KEY, KEY_CAPSLOCK, 0);
-    ASSERT_TRUE(mFakeEventHub->getLedState(EVENTHUB_ID, LED_CAPSL));
-    ASSERT_FALSE(mFakeEventHub->getLedState(EVENTHUB_ID, LED_NUML));
-    ASSERT_FALSE(mFakeEventHub->getLedState(EVENTHUB_ID, LED_SCROLLL));
-    ASSERT_EQ(AMETA_CAPS_LOCK_ON, mapper.getMetaState());
-
-    // Toggle num lock on.
-    process(mapper, ARBITRARY_TIME, READ_TIME, EV_KEY, KEY_NUMLOCK, 1);
-    process(mapper, ARBITRARY_TIME, READ_TIME, EV_KEY, KEY_NUMLOCK, 0);
-    ASSERT_TRUE(mFakeEventHub->getLedState(EVENTHUB_ID, LED_CAPSL));
-    ASSERT_TRUE(mFakeEventHub->getLedState(EVENTHUB_ID, LED_NUML));
-    ASSERT_FALSE(mFakeEventHub->getLedState(EVENTHUB_ID, LED_SCROLLL));
-    ASSERT_EQ(AMETA_CAPS_LOCK_ON | AMETA_NUM_LOCK_ON, mapper.getMetaState());
-
-    // Toggle caps lock off.
-    process(mapper, ARBITRARY_TIME, READ_TIME, EV_KEY, KEY_CAPSLOCK, 1);
-    process(mapper, ARBITRARY_TIME, READ_TIME, EV_KEY, KEY_CAPSLOCK, 0);
-    ASSERT_FALSE(mFakeEventHub->getLedState(EVENTHUB_ID, LED_CAPSL));
-    ASSERT_TRUE(mFakeEventHub->getLedState(EVENTHUB_ID, LED_NUML));
-    ASSERT_FALSE(mFakeEventHub->getLedState(EVENTHUB_ID, LED_SCROLLL));
-    ASSERT_EQ(AMETA_NUM_LOCK_ON, mapper.getMetaState());
-
-    // Toggle scroll lock on.
-    process(mapper, ARBITRARY_TIME, READ_TIME, EV_KEY, KEY_SCROLLLOCK, 1);
-    process(mapper, ARBITRARY_TIME, READ_TIME, EV_KEY, KEY_SCROLLLOCK, 0);
-    ASSERT_FALSE(mFakeEventHub->getLedState(EVENTHUB_ID, LED_CAPSL));
-    ASSERT_TRUE(mFakeEventHub->getLedState(EVENTHUB_ID, LED_NUML));
-    ASSERT_TRUE(mFakeEventHub->getLedState(EVENTHUB_ID, LED_SCROLLL));
-    ASSERT_EQ(AMETA_NUM_LOCK_ON | AMETA_SCROLL_LOCK_ON, mapper.getMetaState());
-
-    // Toggle num lock off.
-    process(mapper, ARBITRARY_TIME, READ_TIME, EV_KEY, KEY_NUMLOCK, 1);
-    process(mapper, ARBITRARY_TIME, READ_TIME, EV_KEY, KEY_NUMLOCK, 0);
-    ASSERT_FALSE(mFakeEventHub->getLedState(EVENTHUB_ID, LED_CAPSL));
-    ASSERT_FALSE(mFakeEventHub->getLedState(EVENTHUB_ID, LED_NUML));
-    ASSERT_TRUE(mFakeEventHub->getLedState(EVENTHUB_ID, LED_SCROLLL));
-    ASSERT_EQ(AMETA_SCROLL_LOCK_ON, mapper.getMetaState());
-
-    // Toggle scroll lock off.
-    process(mapper, ARBITRARY_TIME, READ_TIME, EV_KEY, KEY_SCROLLLOCK, 1);
-    process(mapper, ARBITRARY_TIME, READ_TIME, EV_KEY, KEY_SCROLLLOCK, 0);
-    ASSERT_FALSE(mFakeEventHub->getLedState(EVENTHUB_ID, LED_CAPSL));
-    ASSERT_FALSE(mFakeEventHub->getLedState(EVENTHUB_ID, LED_NUML));
-    ASSERT_FALSE(mFakeEventHub->getLedState(EVENTHUB_ID, LED_SCROLLL));
-    ASSERT_EQ(AMETA_NONE, mapper.getMetaState());
-}
-
-TEST_F(KeyboardInputMapperTest, Configure_AssignsDisplayPort) {
-    // keyboard 1.
-    mFakeEventHub->addKey(EVENTHUB_ID, KEY_UP, 0, AKEYCODE_DPAD_UP, 0);
-    mFakeEventHub->addKey(EVENTHUB_ID, KEY_RIGHT, 0, AKEYCODE_DPAD_RIGHT, 0);
-    mFakeEventHub->addKey(EVENTHUB_ID, KEY_DOWN, 0, AKEYCODE_DPAD_DOWN, 0);
-    mFakeEventHub->addKey(EVENTHUB_ID, KEY_LEFT, 0, AKEYCODE_DPAD_LEFT, 0);
-
-    // keyboard 2.
-    const std::string USB2 = "USB2";
-    const std::string DEVICE_NAME2 = "KEYBOARD2";
-    constexpr int32_t SECOND_DEVICE_ID = DEVICE_ID + 1;
-    constexpr int32_t SECOND_EVENTHUB_ID = EVENTHUB_ID + 1;
-    std::shared_ptr<InputDevice> device2 =
-            newDevice(SECOND_DEVICE_ID, DEVICE_NAME2, USB2, SECOND_EVENTHUB_ID,
-                      ftl::Flags<InputDeviceClass>(0));
-
-    mFakeEventHub->addKey(SECOND_EVENTHUB_ID, KEY_UP, 0, AKEYCODE_DPAD_UP, 0);
-    mFakeEventHub->addKey(SECOND_EVENTHUB_ID, KEY_RIGHT, 0, AKEYCODE_DPAD_RIGHT, 0);
-    mFakeEventHub->addKey(SECOND_EVENTHUB_ID, KEY_DOWN, 0, AKEYCODE_DPAD_DOWN, 0);
-    mFakeEventHub->addKey(SECOND_EVENTHUB_ID, KEY_LEFT, 0, AKEYCODE_DPAD_LEFT, 0);
-
-    KeyboardInputMapper& mapper =
-            constructAndAddMapper<KeyboardInputMapper>(AINPUT_SOURCE_KEYBOARD);
-
-    device2->addEmptyEventHubDevice(SECOND_EVENTHUB_ID);
-    KeyboardInputMapper& mapper2 =
-            device2->constructAndAddMapper<KeyboardInputMapper>(SECOND_EVENTHUB_ID,
-                                                                mFakePolicy
-                                                                        ->getReaderConfiguration(),
-                                                                AINPUT_SOURCE_KEYBOARD);
-    std::list<NotifyArgs> unused =
-            device2->configure(ARBITRARY_TIME, mFakePolicy->getReaderConfiguration(),
-                               /*changes=*/{});
-    unused += device2->reset(ARBITRARY_TIME);
-
-    // Prepared displays and associated info.
-    constexpr uint8_t hdmi1 = 0;
-    constexpr uint8_t hdmi2 = 1;
-    const std::string SECONDARY_UNIQUE_ID = "local:1";
-
-    mFakePolicy->addInputPortAssociation(DEVICE_LOCATION, hdmi1);
-    mFakePolicy->addInputPortAssociation(USB2, hdmi2);
-
-    // No associated display viewport found, should disable the device.
-    unused += device2->configure(ARBITRARY_TIME, mFakePolicy->getReaderConfiguration(),
-                                 InputReaderConfiguration::Change::DISPLAY_INFO);
-    ASSERT_FALSE(device2->isEnabled());
-
-    // Prepare second display.
-    constexpr ui::LogicalDisplayId newDisplayId = ui::LogicalDisplayId{2};
-    setDisplayInfoAndReconfigure(DISPLAY_ID, DISPLAY_WIDTH, DISPLAY_HEIGHT, ui::ROTATION_0,
-                                 UNIQUE_ID, hdmi1, ViewportType::INTERNAL);
-    setDisplayInfoAndReconfigure(newDisplayId, DISPLAY_WIDTH, DISPLAY_HEIGHT, ui::ROTATION_0,
-                                 SECONDARY_UNIQUE_ID, hdmi2, ViewportType::EXTERNAL);
-    // Default device will reconfigure above, need additional reconfiguration for another device.
-    unused += device2->configure(ARBITRARY_TIME, mFakePolicy->getReaderConfiguration(),
-                                 InputReaderConfiguration::Change::DISPLAY_INFO);
-
-    // Device should be enabled after the associated display is found.
-    ASSERT_TRUE(mDevice->isEnabled());
-    ASSERT_TRUE(device2->isEnabled());
-
-    // Test pad key events
-    ASSERT_NO_FATAL_FAILURE(
-            testDPadKeyRotation(mapper, KEY_UP, AKEYCODE_DPAD_UP, AKEYCODE_DPAD_UP, DISPLAY_ID));
-    ASSERT_NO_FATAL_FAILURE(testDPadKeyRotation(mapper, KEY_RIGHT, AKEYCODE_DPAD_RIGHT,
-                                                AKEYCODE_DPAD_RIGHT, DISPLAY_ID));
-    ASSERT_NO_FATAL_FAILURE(testDPadKeyRotation(mapper, KEY_DOWN, AKEYCODE_DPAD_DOWN,
-                                                AKEYCODE_DPAD_DOWN, DISPLAY_ID));
-    ASSERT_NO_FATAL_FAILURE(testDPadKeyRotation(mapper, KEY_LEFT, AKEYCODE_DPAD_LEFT,
-                                                AKEYCODE_DPAD_LEFT, DISPLAY_ID));
-
-    ASSERT_NO_FATAL_FAILURE(
-            testDPadKeyRotation(mapper2, KEY_UP, AKEYCODE_DPAD_UP, AKEYCODE_DPAD_UP, newDisplayId));
-    ASSERT_NO_FATAL_FAILURE(testDPadKeyRotation(mapper2, KEY_RIGHT, AKEYCODE_DPAD_RIGHT,
-                                                AKEYCODE_DPAD_RIGHT, newDisplayId));
-    ASSERT_NO_FATAL_FAILURE(testDPadKeyRotation(mapper2, KEY_DOWN, AKEYCODE_DPAD_DOWN,
-                                                AKEYCODE_DPAD_DOWN, newDisplayId));
-    ASSERT_NO_FATAL_FAILURE(testDPadKeyRotation(mapper2, KEY_LEFT, AKEYCODE_DPAD_LEFT,
-                                                AKEYCODE_DPAD_LEFT, newDisplayId));
-}
-
-TEST_F(KeyboardInputMapperTest, Process_LockedKeysShouldToggleAfterReattach) {
-    mFakeEventHub->addLed(EVENTHUB_ID, LED_CAPSL, true /*initially on*/);
-    mFakeEventHub->addLed(EVENTHUB_ID, LED_NUML, false /*initially off*/);
-    mFakeEventHub->addLed(EVENTHUB_ID, LED_SCROLLL, false /*initially off*/);
-    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);
-
-    KeyboardInputMapper& mapper =
-            constructAndAddMapper<KeyboardInputMapper>(AINPUT_SOURCE_KEYBOARD);
-    // Initial metastate is AMETA_NONE.
-    ASSERT_EQ(AMETA_NONE, mapper.getMetaState());
-
-    // Initialization should have turned all of the lights off.
-    ASSERT_FALSE(mFakeEventHub->getLedState(EVENTHUB_ID, LED_CAPSL));
-    ASSERT_FALSE(mFakeEventHub->getLedState(EVENTHUB_ID, LED_NUML));
-    ASSERT_FALSE(mFakeEventHub->getLedState(EVENTHUB_ID, LED_SCROLLL));
-
-    // Toggle caps lock on.
-    process(mapper, ARBITRARY_TIME, READ_TIME, EV_KEY, KEY_CAPSLOCK, 1);
-    process(mapper, ARBITRARY_TIME, READ_TIME, EV_KEY, KEY_CAPSLOCK, 0);
-    ASSERT_TRUE(mFakeEventHub->getLedState(EVENTHUB_ID, LED_CAPSL));
-    ASSERT_EQ(AMETA_CAPS_LOCK_ON, mapper.getMetaState());
-
-    // Toggle num lock on.
-    process(mapper, ARBITRARY_TIME, READ_TIME, EV_KEY, KEY_NUMLOCK, 1);
-    process(mapper, ARBITRARY_TIME, READ_TIME, EV_KEY, KEY_NUMLOCK, 0);
-    ASSERT_TRUE(mFakeEventHub->getLedState(EVENTHUB_ID, LED_NUML));
-    ASSERT_EQ(AMETA_CAPS_LOCK_ON | AMETA_NUM_LOCK_ON, mapper.getMetaState());
-
-    // Toggle scroll lock on.
-    process(mapper, ARBITRARY_TIME, READ_TIME, EV_KEY, KEY_SCROLLLOCK, 1);
-    process(mapper, ARBITRARY_TIME, READ_TIME, EV_KEY, KEY_SCROLLLOCK, 0);
-    ASSERT_TRUE(mFakeEventHub->getLedState(EVENTHUB_ID, LED_SCROLLL));
-    ASSERT_EQ(AMETA_CAPS_LOCK_ON | AMETA_NUM_LOCK_ON | AMETA_SCROLL_LOCK_ON, mapper.getMetaState());
-
-    mFakeEventHub->removeDevice(EVENTHUB_ID);
-    mReader->loopOnce();
-
-    // keyboard 2 should default toggle keys.
-    const std::string USB2 = "USB2";
-    const std::string DEVICE_NAME2 = "KEYBOARD2";
-    constexpr int32_t SECOND_DEVICE_ID = DEVICE_ID + 1;
-    constexpr int32_t SECOND_EVENTHUB_ID = EVENTHUB_ID + 1;
-    std::shared_ptr<InputDevice> device2 =
-            newDevice(SECOND_DEVICE_ID, DEVICE_NAME2, USB2, SECOND_EVENTHUB_ID,
-                      ftl::Flags<InputDeviceClass>(0));
-    mFakeEventHub->addLed(SECOND_EVENTHUB_ID, LED_CAPSL, true /*initially on*/);
-    mFakeEventHub->addLed(SECOND_EVENTHUB_ID, LED_NUML, false /*initially off*/);
-    mFakeEventHub->addLed(SECOND_EVENTHUB_ID, LED_SCROLLL, false /*initially off*/);
-    mFakeEventHub->addKey(SECOND_EVENTHUB_ID, KEY_CAPSLOCK, 0, AKEYCODE_CAPS_LOCK, 0);
-    mFakeEventHub->addKey(SECOND_EVENTHUB_ID, KEY_NUMLOCK, 0, AKEYCODE_NUM_LOCK, 0);
-    mFakeEventHub->addKey(SECOND_EVENTHUB_ID, KEY_SCROLLLOCK, 0, AKEYCODE_SCROLL_LOCK, 0);
-
-    device2->addEmptyEventHubDevice(SECOND_EVENTHUB_ID);
-    KeyboardInputMapper& mapper2 =
-            device2->constructAndAddMapper<KeyboardInputMapper>(SECOND_EVENTHUB_ID,
-                                                                mFakePolicy
-                                                                        ->getReaderConfiguration(),
-                                                                AINPUT_SOURCE_KEYBOARD);
-    std::list<NotifyArgs> unused =
-            device2->configure(ARBITRARY_TIME, mFakePolicy->getReaderConfiguration(),
-                               /*changes=*/{});
-    unused += device2->reset(ARBITRARY_TIME);
-
-    ASSERT_TRUE(mFakeEventHub->getLedState(SECOND_EVENTHUB_ID, LED_CAPSL));
-    ASSERT_TRUE(mFakeEventHub->getLedState(SECOND_EVENTHUB_ID, LED_NUML));
-    ASSERT_TRUE(mFakeEventHub->getLedState(SECOND_EVENTHUB_ID, LED_SCROLLL));
-    ASSERT_EQ(AMETA_CAPS_LOCK_ON | AMETA_NUM_LOCK_ON | AMETA_SCROLL_LOCK_ON,
-              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)
-    constructAndAddMapper<KeyboardInputMapper>(AINPUT_SOURCE_DPAD);
-    KeyboardInputMapper& mapper =
-            constructAndAddMapper<KeyboardInputMapper>(AINPUT_SOURCE_KEYBOARD);
-    // Initial metastate is AMETA_NONE.
-    ASSERT_EQ(AMETA_NONE, mapper.getMetaState());
-
-    mReader->toggleCapsLockState(DEVICE_ID);
-    ASSERT_EQ(AMETA_CAPS_LOCK_ON, mapper.getMetaState());
-}
-
-TEST_F(KeyboardInputMapperTest, Process_LockedKeysShouldToggleInMultiDevices) {
-    // keyboard 1.
-    mFakeEventHub->addLed(EVENTHUB_ID, LED_CAPSL, true /*initially on*/);
-    mFakeEventHub->addLed(EVENTHUB_ID, LED_NUML, false /*initially off*/);
-    mFakeEventHub->addLed(EVENTHUB_ID, LED_SCROLLL, false /*initially off*/);
-    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);
-
-    KeyboardInputMapper& mapper1 =
-            constructAndAddMapper<KeyboardInputMapper>(AINPUT_SOURCE_KEYBOARD);
-
-    // keyboard 2.
-    const std::string USB2 = "USB2";
-    const std::string DEVICE_NAME2 = "KEYBOARD2";
-    constexpr int32_t SECOND_DEVICE_ID = DEVICE_ID + 1;
-    constexpr int32_t SECOND_EVENTHUB_ID = EVENTHUB_ID + 1;
-    std::shared_ptr<InputDevice> device2 =
-            newDevice(SECOND_DEVICE_ID, DEVICE_NAME2, USB2, SECOND_EVENTHUB_ID,
-                      ftl::Flags<InputDeviceClass>(0));
-    mFakeEventHub->addLed(SECOND_EVENTHUB_ID, LED_CAPSL, true /*initially on*/);
-    mFakeEventHub->addLed(SECOND_EVENTHUB_ID, LED_NUML, false /*initially off*/);
-    mFakeEventHub->addLed(SECOND_EVENTHUB_ID, LED_SCROLLL, false /*initially off*/);
-    mFakeEventHub->addKey(SECOND_EVENTHUB_ID, KEY_CAPSLOCK, 0, AKEYCODE_CAPS_LOCK, 0);
-    mFakeEventHub->addKey(SECOND_EVENTHUB_ID, KEY_NUMLOCK, 0, AKEYCODE_NUM_LOCK, 0);
-    mFakeEventHub->addKey(SECOND_EVENTHUB_ID, KEY_SCROLLLOCK, 0, AKEYCODE_SCROLL_LOCK, 0);
-
-    device2->addEmptyEventHubDevice(SECOND_EVENTHUB_ID);
-    KeyboardInputMapper& mapper2 =
-            device2->constructAndAddMapper<KeyboardInputMapper>(SECOND_EVENTHUB_ID,
-                                                                mFakePolicy
-                                                                        ->getReaderConfiguration(),
-                                                                AINPUT_SOURCE_KEYBOARD);
-    std::list<NotifyArgs> unused =
-            device2->configure(ARBITRARY_TIME, mFakePolicy->getReaderConfiguration(),
-                               /*changes=*/{});
-    unused += device2->reset(ARBITRARY_TIME);
-
-    // Initial metastate is AMETA_NONE.
-    ASSERT_EQ(AMETA_NONE, mapper1.getMetaState());
-    ASSERT_EQ(AMETA_NONE, mapper2.getMetaState());
-
-    // Toggle num lock on and off.
-    process(mapper1, ARBITRARY_TIME, READ_TIME, EV_KEY, KEY_NUMLOCK, 1);
-    process(mapper1, ARBITRARY_TIME, READ_TIME, EV_KEY, KEY_NUMLOCK, 0);
-    ASSERT_TRUE(mFakeEventHub->getLedState(EVENTHUB_ID, LED_NUML));
-    ASSERT_EQ(AMETA_NUM_LOCK_ON, mapper1.getMetaState());
-    ASSERT_EQ(AMETA_NUM_LOCK_ON, mapper2.getMetaState());
-
-    process(mapper1, ARBITRARY_TIME, READ_TIME, EV_KEY, KEY_NUMLOCK, 1);
-    process(mapper1, ARBITRARY_TIME, READ_TIME, EV_KEY, KEY_NUMLOCK, 0);
-    ASSERT_FALSE(mFakeEventHub->getLedState(EVENTHUB_ID, LED_NUML));
-    ASSERT_EQ(AMETA_NONE, mapper1.getMetaState());
-    ASSERT_EQ(AMETA_NONE, mapper2.getMetaState());
-
-    // Toggle caps lock on and off.
-    process(mapper1, ARBITRARY_TIME, READ_TIME, EV_KEY, KEY_CAPSLOCK, 1);
-    process(mapper1, ARBITRARY_TIME, READ_TIME, EV_KEY, KEY_CAPSLOCK, 0);
-    ASSERT_TRUE(mFakeEventHub->getLedState(EVENTHUB_ID, LED_CAPSL));
-    ASSERT_EQ(AMETA_CAPS_LOCK_ON, mapper1.getMetaState());
-    ASSERT_EQ(AMETA_CAPS_LOCK_ON, mapper2.getMetaState());
-
-    process(mapper1, ARBITRARY_TIME, READ_TIME, EV_KEY, KEY_CAPSLOCK, 1);
-    process(mapper1, ARBITRARY_TIME, READ_TIME, EV_KEY, KEY_CAPSLOCK, 0);
-    ASSERT_FALSE(mFakeEventHub->getLedState(EVENTHUB_ID, LED_CAPSL));
-    ASSERT_EQ(AMETA_NONE, mapper1.getMetaState());
-    ASSERT_EQ(AMETA_NONE, mapper2.getMetaState());
-
-    // Toggle scroll lock on and off.
-    process(mapper1, ARBITRARY_TIME, READ_TIME, EV_KEY, KEY_SCROLLLOCK, 1);
-    process(mapper1, ARBITRARY_TIME, READ_TIME, EV_KEY, KEY_SCROLLLOCK, 0);
-    ASSERT_TRUE(mFakeEventHub->getLedState(EVENTHUB_ID, LED_SCROLLL));
-    ASSERT_EQ(AMETA_SCROLL_LOCK_ON, mapper1.getMetaState());
-    ASSERT_EQ(AMETA_SCROLL_LOCK_ON, mapper2.getMetaState());
-
-    process(mapper1, ARBITRARY_TIME, READ_TIME, EV_KEY, KEY_SCROLLLOCK, 1);
-    process(mapper1, ARBITRARY_TIME, READ_TIME, EV_KEY, KEY_SCROLLLOCK, 0);
-    ASSERT_FALSE(mFakeEventHub->getLedState(EVENTHUB_ID, LED_SCROLLL));
-    ASSERT_EQ(AMETA_NONE, mapper1.getMetaState());
-    ASSERT_EQ(AMETA_NONE, mapper2.getMetaState());
-}
-
-TEST_F(KeyboardInputMapperTest, Process_DisabledDevice) {
-    const int32_t USAGE_A = 0x070004;
-    mFakeEventHub->addKey(EVENTHUB_ID, KEY_HOME, 0, AKEYCODE_HOME, POLICY_FLAG_WAKE);
-    mFakeEventHub->addKey(EVENTHUB_ID, 0, USAGE_A, AKEYCODE_A, POLICY_FLAG_WAKE);
-
-    KeyboardInputMapper& mapper =
-            constructAndAddMapper<KeyboardInputMapper>(AINPUT_SOURCE_KEYBOARD);
-    // Key down by scan code.
-    process(mapper, ARBITRARY_TIME, READ_TIME, EV_KEY, KEY_HOME, 1);
-    NotifyKeyArgs args;
-    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyKeyWasCalled(&args));
-    ASSERT_EQ(DEVICE_ID, args.deviceId);
-    ASSERT_EQ(AINPUT_SOURCE_KEYBOARD, args.source);
-    ASSERT_EQ(ARBITRARY_TIME, args.eventTime);
-    ASSERT_EQ(AKEY_EVENT_ACTION_DOWN, args.action);
-    ASSERT_EQ(AKEYCODE_HOME, args.keyCode);
-    ASSERT_EQ(KEY_HOME, args.scanCode);
-    ASSERT_EQ(AKEY_EVENT_FLAG_FROM_SYSTEM, args.flags);
-
-    // Disable device, it should synthesize cancellation events for down events.
-    mFakePolicy->addDisabledDevice(DEVICE_ID);
-    configureDevice(InputReaderConfiguration::Change::ENABLED_STATE);
-
-    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyKeyWasCalled(&args));
-    ASSERT_EQ(AKEY_EVENT_ACTION_UP, args.action);
-    ASSERT_EQ(AKEYCODE_HOME, args.keyCode);
-    ASSERT_EQ(KEY_HOME, args.scanCode);
-    ASSERT_EQ(AKEY_EVENT_FLAG_FROM_SYSTEM | AKEY_EVENT_FLAG_CANCELED, args.flags);
-}
-
-TEST_F(KeyboardInputMapperTest, Configure_AssignKeyboardLayoutInfo) {
-    constructAndAddMapper<KeyboardInputMapper>(AINPUT_SOURCE_KEYBOARD);
-    std::list<NotifyArgs> unused =
-            mDevice->configure(ARBITRARY_TIME, mFakePolicy->getReaderConfiguration(),
-                               /*changes=*/{});
-
-    uint32_t generation = mReader->getContext()->getGeneration();
-    mFakePolicy->addKeyboardLayoutAssociation(DEVICE_LOCATION, DEVICE_KEYBOARD_LAYOUT_INFO);
-
-    unused += mDevice->configure(ARBITRARY_TIME, mFakePolicy->getReaderConfiguration(),
-                                 InputReaderConfiguration::Change::KEYBOARD_LAYOUT_ASSOCIATION);
-
-    InputDeviceInfo deviceInfo = mDevice->getDeviceInfo();
-    ASSERT_EQ(DEVICE_KEYBOARD_LAYOUT_INFO.languageTag,
-              deviceInfo.getKeyboardLayoutInfo()->languageTag);
-    ASSERT_EQ(DEVICE_KEYBOARD_LAYOUT_INFO.layoutType,
-              deviceInfo.getKeyboardLayoutInfo()->layoutType);
-    ASSERT_TRUE(mReader->getContext()->getGeneration() != generation);
-
-    // Call change layout association with the same values: Generation shouldn't change
-    generation = mReader->getContext()->getGeneration();
-    mFakePolicy->addKeyboardLayoutAssociation(DEVICE_LOCATION, DEVICE_KEYBOARD_LAYOUT_INFO);
-    unused += mDevice->configure(ARBITRARY_TIME, mFakePolicy->getReaderConfiguration(),
-                                 InputReaderConfiguration::Change::KEYBOARD_LAYOUT_ASSOCIATION);
-    ASSERT_TRUE(mReader->getContext()->getGeneration() == generation);
-}
-
-TEST_F(KeyboardInputMapperTest, LayoutInfoCorrectlyMapped) {
-    mFakeEventHub->setRawLayoutInfo(EVENTHUB_ID,
-                                    RawLayoutInfo{.languageTag = "en", .layoutType = "extended"});
-
-    // Configuration
-    constructAndAddMapper<KeyboardInputMapper>(AINPUT_SOURCE_KEYBOARD);
-    InputReaderConfiguration config;
-    std::list<NotifyArgs> unused = mDevice->configure(ARBITRARY_TIME, config, /*changes=*/{});
-
-    ASSERT_EQ("en", mDevice->getDeviceInfo().getKeyboardLayoutInfo()->languageTag);
-    ASSERT_EQ("extended", mDevice->getDeviceInfo().getKeyboardLayoutInfo()->layoutType);
-}
-
-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);
-    NotifyKeyArgs args;
-
-    // Key down
-    process(mapper, ARBITRARY_TIME, READ_TIME, EV_KEY, KEY_LEFT, 1);
-    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyKeyWasCalled(&args));
-    ASSERT_EQ(AKEY_EVENT_FLAG_FROM_SYSTEM | AKEY_EVENT_FLAG_KEEP_TOUCH_MODE, args.flags);
-}
-
-TEST_F_WITH_FLAGS(KeyboardInputMapperTest, WakeBehavior_AlphabeticKeyboard,
-                  REQUIRES_FLAGS_ENABLED(ACONFIG_FLAG(com::android::input::flags,
-                                                      enable_alphabetic_keyboard_wake))) {
-    // For internal alphabetic devices, keys will trigger wake on key down.
-
-    mFakeEventHub->addKey(EVENTHUB_ID, KEY_A, 0, AKEYCODE_A, 0);
-    mFakeEventHub->addKey(EVENTHUB_ID, KEY_HOME, 0, AKEYCODE_HOME, 0);
-    mFakeEventHub->addKey(EVENTHUB_ID, KEY_PLAYPAUSE, 0, AKEYCODE_MEDIA_PLAY_PAUSE, 0);
-
-    KeyboardInputMapper& mapper =
-            constructAndAddMapper<KeyboardInputMapper>(AINPUT_SOURCE_KEYBOARD);
-
-    process(mapper, ARBITRARY_TIME, READ_TIME, EV_KEY, KEY_A, 1);
-    NotifyKeyArgs args;
-    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyKeyWasCalled(&args));
-    ASSERT_EQ(POLICY_FLAG_WAKE, args.policyFlags);
-
-    process(mapper, ARBITRARY_TIME + 1, READ_TIME, EV_KEY, KEY_A, 0);
-    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyKeyWasCalled(&args));
-    ASSERT_EQ(uint32_t(0), args.policyFlags);
-
-    process(mapper, ARBITRARY_TIME, READ_TIME, EV_KEY, KEY_HOME, 1);
-    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyKeyWasCalled(&args));
-    ASSERT_EQ(POLICY_FLAG_WAKE, args.policyFlags);
-
-    process(mapper, ARBITRARY_TIME + 1, READ_TIME, EV_KEY, KEY_HOME, 0);
-    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyKeyWasCalled(&args));
-    ASSERT_EQ(uint32_t(0), args.policyFlags);
-
-    process(mapper, ARBITRARY_TIME, READ_TIME, EV_KEY, KEY_PLAYPAUSE, 1);
-    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyKeyWasCalled(&args));
-    ASSERT_EQ(POLICY_FLAG_WAKE, args.policyFlags);
-
-    process(mapper, ARBITRARY_TIME + 1, READ_TIME, EV_KEY, KEY_PLAYPAUSE, 0);
-    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyKeyWasCalled(&args));
-    ASSERT_EQ(uint32_t(0), args.policyFlags);
-}
-
-/**
- * When there is more than one KeyboardInputMapper for an InputDevice, each mapper should produce
- * events that use the shared keyboard source across all mappers. This is to ensure that each
- * input device generates key events in a consistent manner, regardless of which mapper produces
- * the event.
- */
-TEST_F(KeyboardInputMapperTest, UsesSharedKeyboardSource) {
-    mFakeEventHub->addKey(EVENTHUB_ID, KEY_HOME, 0, AKEYCODE_HOME, POLICY_FLAG_WAKE);
-
-    // Add a mapper with SOURCE_KEYBOARD
-    KeyboardInputMapper& keyboardMapper =
-            constructAndAddMapper<KeyboardInputMapper>(AINPUT_SOURCE_KEYBOARD);
-
-    process(keyboardMapper, ARBITRARY_TIME, 0, EV_KEY, KEY_HOME, 1);
-    ASSERT_NO_FATAL_FAILURE(
-            mFakeListener->assertNotifyKeyWasCalled(WithSource(AINPUT_SOURCE_KEYBOARD)));
-    process(keyboardMapper, ARBITRARY_TIME, 0, EV_KEY, KEY_HOME, 0);
-    ASSERT_NO_FATAL_FAILURE(
-            mFakeListener->assertNotifyKeyWasCalled(WithSource(AINPUT_SOURCE_KEYBOARD)));
-
-    // Add a mapper with SOURCE_DPAD
-    KeyboardInputMapper& dpadMapper =
-            constructAndAddMapper<KeyboardInputMapper>(AINPUT_SOURCE_DPAD);
-    for (auto* mapper : {&keyboardMapper, &dpadMapper}) {
-        process(*mapper, ARBITRARY_TIME, 0, EV_KEY, KEY_HOME, 1);
-        ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyKeyWasCalled(
-                WithSource(AINPUT_SOURCE_KEYBOARD | AINPUT_SOURCE_DPAD)));
-        process(*mapper, ARBITRARY_TIME, 0, EV_KEY, KEY_HOME, 0);
-        ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyKeyWasCalled(
-                WithSource(AINPUT_SOURCE_KEYBOARD | AINPUT_SOURCE_DPAD)));
-    }
-
-    // Add a mapper with SOURCE_GAMEPAD
-    KeyboardInputMapper& gamepadMapper =
-            constructAndAddMapper<KeyboardInputMapper>(AINPUT_SOURCE_GAMEPAD);
-    for (auto* mapper : {&keyboardMapper, &dpadMapper, &gamepadMapper}) {
-        process(*mapper, ARBITRARY_TIME, 0, EV_KEY, KEY_HOME, 1);
-        ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyKeyWasCalled(
-                WithSource(AINPUT_SOURCE_KEYBOARD | AINPUT_SOURCE_DPAD | AINPUT_SOURCE_GAMEPAD)));
-        process(*mapper, ARBITRARY_TIME, 0, EV_KEY, KEY_HOME, 0);
-        ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyKeyWasCalled(
-                WithSource(AINPUT_SOURCE_KEYBOARD | AINPUT_SOURCE_DPAD | AINPUT_SOURCE_GAMEPAD)));
-    }
-}
-
-// --- KeyboardInputMapperTest_ExternalAlphabeticDevice ---
-
-class KeyboardInputMapperTest_ExternalAlphabeticDevice : public InputMapperTest {
-protected:
-    void SetUp() override {
-        InputMapperTest::SetUp(DEVICE_CLASSES | InputDeviceClass::KEYBOARD |
-                               InputDeviceClass::ALPHAKEY | InputDeviceClass::EXTERNAL);
-    }
-};
-
-// --- 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.
-
-    mFakeEventHub->addKey(EVENTHUB_ID, KEY_HOME, 0, AKEYCODE_HOME, 0);
-    mFakeEventHub->addKey(EVENTHUB_ID, KEY_PLAY, 0, AKEYCODE_MEDIA_PLAY, 0);
-    mFakeEventHub->addKey(EVENTHUB_ID, KEY_PLAYPAUSE, 0, AKEYCODE_MEDIA_PLAY_PAUSE,
-                          POLICY_FLAG_WAKE);
-
-    KeyboardInputMapper& mapper =
-            constructAndAddMapper<KeyboardInputMapper>(AINPUT_SOURCE_KEYBOARD);
-
-    process(mapper, ARBITRARY_TIME, READ_TIME, EV_KEY, KEY_HOME, 1);
-    NotifyKeyArgs args;
-    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyKeyWasCalled(&args));
-    ASSERT_EQ(POLICY_FLAG_WAKE, args.policyFlags);
-
-    process(mapper, ARBITRARY_TIME + 1, READ_TIME, EV_KEY, KEY_HOME, 0);
-    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyKeyWasCalled(&args));
-    ASSERT_EQ(uint32_t(0), args.policyFlags);
-
-    process(mapper, ARBITRARY_TIME, READ_TIME, EV_KEY, KEY_PLAY, 1);
-    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyKeyWasCalled(&args));
-    ASSERT_EQ(POLICY_FLAG_WAKE, args.policyFlags);
-
-    process(mapper, ARBITRARY_TIME + 1, READ_TIME, EV_KEY, KEY_PLAY, 0);
-    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyKeyWasCalled(&args));
-    ASSERT_EQ(uint32_t(0), args.policyFlags);
-
-    process(mapper, ARBITRARY_TIME, READ_TIME, EV_KEY, KEY_PLAYPAUSE, 1);
-    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyKeyWasCalled(&args));
-    ASSERT_EQ(POLICY_FLAG_WAKE, args.policyFlags);
-
-    process(mapper, ARBITRARY_TIME + 1, READ_TIME, EV_KEY, KEY_PLAYPAUSE, 0);
-    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyKeyWasCalled(&args));
-    ASSERT_EQ(POLICY_FLAG_WAKE, args.policyFlags);
-}
-
-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).
-
-    mFakeEventHub->addKey(EVENTHUB_ID, KEY_PLAY, 0, AKEYCODE_MEDIA_PLAY, 0);
-    mFakeEventHub->addKey(EVENTHUB_ID, KEY_PLAYPAUSE, 0, AKEYCODE_MEDIA_PLAY_PAUSE,
-                          POLICY_FLAG_WAKE);
-
-    KeyboardInputMapper& mapper =
-            constructAndAddMapper<KeyboardInputMapper>(AINPUT_SOURCE_KEYBOARD);
-
-    process(mapper, ARBITRARY_TIME, READ_TIME, EV_KEY, KEY_PLAY, 1);
-    NotifyKeyArgs args;
-    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyKeyWasCalled(&args));
-    ASSERT_EQ(uint32_t(0), args.policyFlags);
-
-    process(mapper, ARBITRARY_TIME + 1, READ_TIME, EV_KEY, KEY_PLAY, 0);
-    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyKeyWasCalled(&args));
-    ASSERT_EQ(uint32_t(0), args.policyFlags);
-
-    process(mapper, ARBITRARY_TIME, READ_TIME, EV_KEY, KEY_PLAYPAUSE, 1);
-    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyKeyWasCalled(&args));
-    ASSERT_EQ(POLICY_FLAG_WAKE, args.policyFlags);
-
-    process(mapper, ARBITRARY_TIME + 1, READ_TIME, EV_KEY, KEY_PLAYPAUSE, 0);
-    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyKeyWasCalled(&args));
-    ASSERT_EQ(POLICY_FLAG_WAKE, args.policyFlags);
-}
-
-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);
-    mFakeEventHub->addKey(EVENTHUB_ID, KEY_DOWN, 0, AKEYCODE_DPAD_DOWN, 0);
-    mFakeEventHub->addKey(EVENTHUB_ID, KEY_PLAY, 0, AKEYCODE_MEDIA_PLAY, POLICY_FLAG_WAKE);
-
-    addConfigurationProperty("keyboard.doNotWakeByDefault", "1");
-    KeyboardInputMapper& mapper =
-            constructAndAddMapper<KeyboardInputMapper>(AINPUT_SOURCE_KEYBOARD);
-
-    process(mapper, ARBITRARY_TIME, READ_TIME, EV_KEY, KEY_HOME, 1);
-    NotifyKeyArgs args;
-    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyKeyWasCalled(&args));
-    ASSERT_EQ(POLICY_FLAG_WAKE, args.policyFlags);
-
-    process(mapper, ARBITRARY_TIME + 1, READ_TIME, EV_KEY, KEY_HOME, 0);
-    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyKeyWasCalled(&args));
-    ASSERT_EQ(POLICY_FLAG_WAKE, args.policyFlags);
-
-    process(mapper, ARBITRARY_TIME, READ_TIME, EV_KEY, KEY_DOWN, 1);
-    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyKeyWasCalled(&args));
-    ASSERT_EQ(uint32_t(0), args.policyFlags);
-
-    process(mapper, ARBITRARY_TIME + 1, READ_TIME, EV_KEY, KEY_DOWN, 0);
-    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyKeyWasCalled(&args));
-    ASSERT_EQ(uint32_t(0), args.policyFlags);
-
-    process(mapper, ARBITRARY_TIME, READ_TIME, EV_KEY, KEY_PLAY, 1);
-    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyKeyWasCalled(&args));
-    ASSERT_EQ(POLICY_FLAG_WAKE, args.policyFlags);
-
-    process(mapper, ARBITRARY_TIME + 1, READ_TIME, EV_KEY, KEY_PLAY, 0);
-    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyKeyWasCalled(&args));
-    ASSERT_EQ(POLICY_FLAG_WAKE, args.policyFlags);
-}
-
 // --- TouchInputMapperTest ---
 
 class TouchInputMapperTest : public InputMapperTest {
diff --git a/services/inputflinger/tests/KeyboardInputMapper_test.cpp b/services/inputflinger/tests/KeyboardInputMapper_test.cpp
index bcc6062..7474b2d 100644
--- a/services/inputflinger/tests/KeyboardInputMapper_test.cpp
+++ b/services/inputflinger/tests/KeyboardInputMapper_test.cpp
@@ -16,10 +16,29 @@
 
 #include "KeyboardInputMapper.h"
 
-#include <gtest/gtest.h>
+#include <cstdint>
+#include <list>
+#include <memory>
+#include <optional>
+#include <string>
 
+#include <android/input.h>
+#include <android/keycodes.h>
+#include <com_android_input_flags.h>
+#include <flag_macros.h>
+#include <ftl/flags.h>
+#include <gtest/gtest.h>
+#include <input/DisplayViewport.h>
+#include <input/Input.h>
+#include <input/InputDevice.h>
+#include <ui/LogicalDisplayId.h>
+#include <ui/Rotation.h>
+
+#include "EventHub.h"
 #include "InputMapperTest.h"
 #include "InterfaceMocks.h"
+#include "NotifyArgs.h"
+#include "TestConstants.h"
 #include "TestEventMatchers.h"
 
 #define TAG "KeyboardInputMapper_test"
@@ -34,6 +53,16 @@
 using testing::SetArgPointee;
 using testing::VariantWith;
 
+namespace {
+
+// Arbitrary display properties.
+constexpr ui::LogicalDisplayId DISPLAY_ID = ui::LogicalDisplayId::DEFAULT;
+constexpr int32_t DISPLAY_WIDTH = 480;
+constexpr int32_t DISPLAY_HEIGHT = 800;
+constexpr std::optional<uint8_t> NO_PORT = std::nullopt; // no physical port is specified
+
+} // namespace
+
 /**
  * Unit tests for KeyboardInputMapper.
  */
@@ -109,4 +138,1048 @@
                                                              WithScanCode(KEY_0)))));
 }
 
+// TODO(b/283812079): convert the tests below to use InputMapperUnitTest.
+
+// --- KeyboardInputMapperTest ---
+
+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);
+
+    void testDPadKeyRotation(KeyboardInputMapper& mapper, int32_t originalScanCode,
+                             int32_t originalKeyCode, int32_t rotatedKeyCode,
+                             ui::LogicalDisplayId displayId = ui::LogicalDisplayId::INVALID);
+};
+
+/* Similar to setDisplayInfoAndReconfigure, but pre-populates all parameters except for the
+ * orientation.
+ */
+void KeyboardInputMapperTest::prepareDisplay(ui::Rotation orientation) {
+    setDisplayInfoAndReconfigure(DISPLAY_ID, DISPLAY_WIDTH, DISPLAY_HEIGHT, orientation, UNIQUE_ID,
+                                 NO_PORT, ViewportType::INTERNAL);
+}
+
+void KeyboardInputMapperTest::testDPadKeyRotation(KeyboardInputMapper& mapper,
+                                                  int32_t originalScanCode, int32_t originalKeyCode,
+                                                  int32_t rotatedKeyCode,
+                                                  ui::LogicalDisplayId displayId) {
+    NotifyKeyArgs args;
+
+    process(mapper, ARBITRARY_TIME, READ_TIME, EV_KEY, originalScanCode, 1);
+    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyKeyWasCalled(&args));
+    ASSERT_EQ(AKEY_EVENT_ACTION_DOWN, args.action);
+    ASSERT_EQ(originalScanCode, args.scanCode);
+    ASSERT_EQ(rotatedKeyCode, args.keyCode);
+    ASSERT_EQ(displayId, args.displayId);
+
+    process(mapper, ARBITRARY_TIME, READ_TIME, EV_KEY, originalScanCode, 0);
+    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyKeyWasCalled(&args));
+    ASSERT_EQ(AKEY_EVENT_ACTION_UP, args.action);
+    ASSERT_EQ(originalScanCode, args.scanCode);
+    ASSERT_EQ(rotatedKeyCode, args.keyCode);
+    ASSERT_EQ(displayId, args.displayId);
+}
+
+TEST_F(KeyboardInputMapperTest, GetSources) {
+    KeyboardInputMapper& mapper =
+            constructAndAddMapper<KeyboardInputMapper>(AINPUT_SOURCE_KEYBOARD);
+
+    ASSERT_EQ(AINPUT_SOURCE_KEYBOARD, mapper.getSources());
+}
+
+TEST_F(KeyboardInputMapperTest, Process_SimpleKeyPress) {
+    const int32_t USAGE_A = 0x070004;
+    const int32_t USAGE_UNKNOWN = 0x07ffff;
+    mFakeEventHub->addKey(EVENTHUB_ID, KEY_HOME, 0, AKEYCODE_HOME, POLICY_FLAG_WAKE);
+    mFakeEventHub->addKey(EVENTHUB_ID, 0, USAGE_A, AKEYCODE_A, POLICY_FLAG_WAKE);
+    mFakeEventHub->addKey(EVENTHUB_ID, 0, KEY_NUMLOCK, AKEYCODE_NUM_LOCK, POLICY_FLAG_WAKE);
+    mFakeEventHub->addKey(EVENTHUB_ID, 0, KEY_CAPSLOCK, AKEYCODE_CAPS_LOCK, POLICY_FLAG_WAKE);
+    mFakeEventHub->addKey(EVENTHUB_ID, 0, KEY_SCROLLLOCK, AKEYCODE_SCROLL_LOCK, POLICY_FLAG_WAKE);
+
+    KeyboardInputMapper& mapper =
+            constructAndAddMapper<KeyboardInputMapper>(AINPUT_SOURCE_KEYBOARD);
+    // Initial metastate is AMETA_NONE.
+    ASSERT_EQ(AMETA_NONE, mapper.getMetaState());
+
+    // Key down by scan code.
+    process(mapper, ARBITRARY_TIME, READ_TIME, EV_KEY, KEY_HOME, 1);
+    NotifyKeyArgs args;
+    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyKeyWasCalled(&args));
+    ASSERT_EQ(DEVICE_ID, args.deviceId);
+    ASSERT_EQ(AINPUT_SOURCE_KEYBOARD, args.source);
+    ASSERT_EQ(ARBITRARY_TIME, args.eventTime);
+    ASSERT_EQ(AKEY_EVENT_ACTION_DOWN, args.action);
+    ASSERT_EQ(AKEYCODE_HOME, args.keyCode);
+    ASSERT_EQ(KEY_HOME, args.scanCode);
+    ASSERT_EQ(AMETA_NONE, args.metaState);
+    ASSERT_EQ(AKEY_EVENT_FLAG_FROM_SYSTEM, args.flags);
+    ASSERT_EQ(POLICY_FLAG_WAKE, args.policyFlags);
+    ASSERT_EQ(ARBITRARY_TIME, args.downTime);
+
+    // Key up by scan code.
+    process(mapper, ARBITRARY_TIME + 1, READ_TIME, EV_KEY, KEY_HOME, 0);
+    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyKeyWasCalled(&args));
+    ASSERT_EQ(DEVICE_ID, args.deviceId);
+    ASSERT_EQ(AINPUT_SOURCE_KEYBOARD, args.source);
+    ASSERT_EQ(ARBITRARY_TIME + 1, args.eventTime);
+    ASSERT_EQ(AKEY_EVENT_ACTION_UP, args.action);
+    ASSERT_EQ(AKEYCODE_HOME, args.keyCode);
+    ASSERT_EQ(KEY_HOME, args.scanCode);
+    ASSERT_EQ(AMETA_NONE, args.metaState);
+    ASSERT_EQ(AKEY_EVENT_FLAG_FROM_SYSTEM, args.flags);
+    ASSERT_EQ(POLICY_FLAG_WAKE, args.policyFlags);
+    ASSERT_EQ(ARBITRARY_TIME, args.downTime);
+
+    // Key down by usage code.
+    process(mapper, ARBITRARY_TIME, READ_TIME, EV_MSC, MSC_SCAN, USAGE_A);
+    process(mapper, ARBITRARY_TIME, READ_TIME, EV_KEY, 0, 1);
+    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyKeyWasCalled(&args));
+    ASSERT_EQ(DEVICE_ID, args.deviceId);
+    ASSERT_EQ(AINPUT_SOURCE_KEYBOARD, args.source);
+    ASSERT_EQ(ARBITRARY_TIME, args.eventTime);
+    ASSERT_EQ(AKEY_EVENT_ACTION_DOWN, args.action);
+    ASSERT_EQ(AKEYCODE_A, args.keyCode);
+    ASSERT_EQ(0, args.scanCode);
+    ASSERT_EQ(AMETA_NONE, args.metaState);
+    ASSERT_EQ(AKEY_EVENT_FLAG_FROM_SYSTEM, args.flags);
+    ASSERT_EQ(POLICY_FLAG_WAKE, args.policyFlags);
+    ASSERT_EQ(ARBITRARY_TIME, args.downTime);
+
+    // Key up by usage code.
+    process(mapper, ARBITRARY_TIME, READ_TIME, EV_MSC, MSC_SCAN, USAGE_A);
+    process(mapper, ARBITRARY_TIME + 1, READ_TIME, EV_KEY, 0, 0);
+    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyKeyWasCalled(&args));
+    ASSERT_EQ(DEVICE_ID, args.deviceId);
+    ASSERT_EQ(AINPUT_SOURCE_KEYBOARD, args.source);
+    ASSERT_EQ(ARBITRARY_TIME + 1, args.eventTime);
+    ASSERT_EQ(AKEY_EVENT_ACTION_UP, args.action);
+    ASSERT_EQ(AKEYCODE_A, args.keyCode);
+    ASSERT_EQ(0, args.scanCode);
+    ASSERT_EQ(AMETA_NONE, args.metaState);
+    ASSERT_EQ(AKEY_EVENT_FLAG_FROM_SYSTEM, args.flags);
+    ASSERT_EQ(POLICY_FLAG_WAKE, args.policyFlags);
+    ASSERT_EQ(ARBITRARY_TIME, args.downTime);
+
+    // Key down with unknown scan code or usage code.
+    process(mapper, ARBITRARY_TIME, READ_TIME, EV_MSC, MSC_SCAN, USAGE_UNKNOWN);
+    process(mapper, ARBITRARY_TIME, READ_TIME, EV_KEY, KEY_UNKNOWN, 1);
+    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyKeyWasCalled(&args));
+    ASSERT_EQ(DEVICE_ID, args.deviceId);
+    ASSERT_EQ(AINPUT_SOURCE_KEYBOARD, args.source);
+    ASSERT_EQ(ARBITRARY_TIME, args.eventTime);
+    ASSERT_EQ(AKEY_EVENT_ACTION_DOWN, args.action);
+    ASSERT_EQ(0, args.keyCode);
+    ASSERT_EQ(KEY_UNKNOWN, args.scanCode);
+    ASSERT_EQ(AMETA_NONE, args.metaState);
+    ASSERT_EQ(AKEY_EVENT_FLAG_FROM_SYSTEM, args.flags);
+    ASSERT_EQ(0U, args.policyFlags);
+    ASSERT_EQ(ARBITRARY_TIME, args.downTime);
+
+    // Key up with unknown scan code or usage code.
+    process(mapper, ARBITRARY_TIME, READ_TIME, EV_MSC, MSC_SCAN, USAGE_UNKNOWN);
+    process(mapper, ARBITRARY_TIME + 1, READ_TIME, EV_KEY, KEY_UNKNOWN, 0);
+    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyKeyWasCalled(&args));
+    ASSERT_EQ(DEVICE_ID, args.deviceId);
+    ASSERT_EQ(AINPUT_SOURCE_KEYBOARD, args.source);
+    ASSERT_EQ(ARBITRARY_TIME + 1, args.eventTime);
+    ASSERT_EQ(AKEY_EVENT_ACTION_UP, args.action);
+    ASSERT_EQ(0, args.keyCode);
+    ASSERT_EQ(KEY_UNKNOWN, args.scanCode);
+    ASSERT_EQ(AMETA_NONE, args.metaState);
+    ASSERT_EQ(AKEY_EVENT_FLAG_FROM_SYSTEM, args.flags);
+    ASSERT_EQ(0U, args.policyFlags);
+    ASSERT_EQ(ARBITRARY_TIME, args.downTime);
+}
+
+TEST_F(KeyboardInputMapperTest, Process_KeyRemapping) {
+    mFakeEventHub->addKey(EVENTHUB_ID, KEY_A, 0, AKEYCODE_A, 0);
+    mFakeEventHub->addKey(EVENTHUB_ID, KEY_B, 0, AKEYCODE_B, 0);
+
+    KeyboardInputMapper& mapper =
+            constructAndAddMapper<KeyboardInputMapper>(AINPUT_SOURCE_KEYBOARD);
+
+    mFakeEventHub->setKeyRemapping(EVENTHUB_ID, {{AKEYCODE_A, AKEYCODE_B}});
+    // Key down by scan code.
+    process(mapper, ARBITRARY_TIME, READ_TIME, EV_KEY, KEY_A, 1);
+    NotifyKeyArgs args;
+    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyKeyWasCalled(&args));
+    ASSERT_EQ(AKEYCODE_B, args.keyCode);
+
+    // Key up by scan code.
+    process(mapper, ARBITRARY_TIME + 1, READ_TIME, EV_KEY, KEY_A, 0);
+    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyKeyWasCalled(&args));
+    ASSERT_EQ(AKEYCODE_B, args.keyCode);
+}
+
+/**
+ * Ensure that the readTime is set to the time when the EV_KEY is received.
+ */
+TEST_F(KeyboardInputMapperTest, Process_SendsReadTime) {
+    mFakeEventHub->addKey(EVENTHUB_ID, KEY_HOME, 0, AKEYCODE_HOME, POLICY_FLAG_WAKE);
+
+    KeyboardInputMapper& mapper =
+            constructAndAddMapper<KeyboardInputMapper>(AINPUT_SOURCE_KEYBOARD);
+    NotifyKeyArgs args;
+
+    // Key down
+    process(mapper, ARBITRARY_TIME, /*readTime=*/12, EV_KEY, KEY_HOME, 1);
+    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyKeyWasCalled(&args));
+    ASSERT_EQ(12, args.readTime);
+
+    // Key up
+    process(mapper, ARBITRARY_TIME, /*readTime=*/15, EV_KEY, KEY_HOME, 1);
+    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyKeyWasCalled(&args));
+    ASSERT_EQ(15, args.readTime);
+}
+
+TEST_F(KeyboardInputMapperTest, Process_ShouldUpdateMetaState) {
+    mFakeEventHub->addKey(EVENTHUB_ID, KEY_LEFTSHIFT, 0, AKEYCODE_SHIFT_LEFT, 0);
+    mFakeEventHub->addKey(EVENTHUB_ID, KEY_A, 0, AKEYCODE_A, 0);
+    mFakeEventHub->addKey(EVENTHUB_ID, 0, KEY_NUMLOCK, AKEYCODE_NUM_LOCK, 0);
+    mFakeEventHub->addKey(EVENTHUB_ID, 0, KEY_CAPSLOCK, AKEYCODE_CAPS_LOCK, 0);
+    mFakeEventHub->addKey(EVENTHUB_ID, 0, KEY_SCROLLLOCK, AKEYCODE_SCROLL_LOCK, 0);
+
+    KeyboardInputMapper& mapper =
+            constructAndAddMapper<KeyboardInputMapper>(AINPUT_SOURCE_KEYBOARD);
+
+    // Initial metastate is AMETA_NONE.
+    ASSERT_EQ(AMETA_NONE, mapper.getMetaState());
+
+    // Metakey down.
+    process(mapper, ARBITRARY_TIME, READ_TIME, EV_KEY, KEY_LEFTSHIFT, 1);
+    NotifyKeyArgs args;
+    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyKeyWasCalled(&args));
+    ASSERT_EQ(AMETA_SHIFT_LEFT_ON | AMETA_SHIFT_ON, args.metaState);
+    ASSERT_EQ(AMETA_SHIFT_LEFT_ON | AMETA_SHIFT_ON, mapper.getMetaState());
+    ASSERT_NO_FATAL_FAILURE(mReader->getContext()->assertUpdateGlobalMetaStateWasCalled());
+
+    // Key down.
+    process(mapper, ARBITRARY_TIME + 1, READ_TIME, EV_KEY, KEY_A, 1);
+    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyKeyWasCalled(&args));
+    ASSERT_EQ(AMETA_SHIFT_LEFT_ON | AMETA_SHIFT_ON, args.metaState);
+    ASSERT_EQ(AMETA_SHIFT_LEFT_ON | AMETA_SHIFT_ON, mapper.getMetaState());
+
+    // Key up.
+    process(mapper, ARBITRARY_TIME + 2, READ_TIME, EV_KEY, KEY_A, 0);
+    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyKeyWasCalled(&args));
+    ASSERT_EQ(AMETA_SHIFT_LEFT_ON | AMETA_SHIFT_ON, args.metaState);
+    ASSERT_EQ(AMETA_SHIFT_LEFT_ON | AMETA_SHIFT_ON, mapper.getMetaState());
+
+    // Metakey up.
+    process(mapper, ARBITRARY_TIME + 3, READ_TIME, EV_KEY, KEY_LEFTSHIFT, 0);
+    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyKeyWasCalled(&args));
+    ASSERT_EQ(AMETA_NONE, args.metaState);
+    ASSERT_EQ(AMETA_NONE, mapper.getMetaState());
+    ASSERT_NO_FATAL_FAILURE(mReader->getContext()->assertUpdateGlobalMetaStateWasCalled());
+}
+
+TEST_F(KeyboardInputMapperTest, Process_WhenNotOrientationAware_ShouldNotRotateDPad) {
+    mFakeEventHub->addKey(EVENTHUB_ID, KEY_UP, 0, AKEYCODE_DPAD_UP, 0);
+    mFakeEventHub->addKey(EVENTHUB_ID, KEY_RIGHT, 0, AKEYCODE_DPAD_RIGHT, 0);
+    mFakeEventHub->addKey(EVENTHUB_ID, KEY_DOWN, 0, AKEYCODE_DPAD_DOWN, 0);
+    mFakeEventHub->addKey(EVENTHUB_ID, KEY_LEFT, 0, AKEYCODE_DPAD_LEFT, 0);
+
+    KeyboardInputMapper& mapper =
+            constructAndAddMapper<KeyboardInputMapper>(AINPUT_SOURCE_KEYBOARD);
+
+    prepareDisplay(ui::ROTATION_90);
+    ASSERT_NO_FATAL_FAILURE(testDPadKeyRotation(mapper,
+                                                KEY_UP, AKEYCODE_DPAD_UP, AKEYCODE_DPAD_UP));
+    ASSERT_NO_FATAL_FAILURE(testDPadKeyRotation(mapper,
+                                                KEY_RIGHT, AKEYCODE_DPAD_RIGHT, AKEYCODE_DPAD_RIGHT));
+    ASSERT_NO_FATAL_FAILURE(testDPadKeyRotation(mapper,
+                                                KEY_DOWN, AKEYCODE_DPAD_DOWN, AKEYCODE_DPAD_DOWN));
+    ASSERT_NO_FATAL_FAILURE(testDPadKeyRotation(mapper,
+                                                KEY_LEFT, AKEYCODE_DPAD_LEFT, AKEYCODE_DPAD_LEFT));
+}
+
+TEST_F(KeyboardInputMapperTest, Process_WhenOrientationAware_ShouldRotateDPad) {
+    mFakeEventHub->addKey(EVENTHUB_ID, KEY_UP, 0, AKEYCODE_DPAD_UP, 0);
+    mFakeEventHub->addKey(EVENTHUB_ID, KEY_RIGHT, 0, AKEYCODE_DPAD_RIGHT, 0);
+    mFakeEventHub->addKey(EVENTHUB_ID, KEY_DOWN, 0, AKEYCODE_DPAD_DOWN, 0);
+    mFakeEventHub->addKey(EVENTHUB_ID, KEY_LEFT, 0, AKEYCODE_DPAD_LEFT, 0);
+
+    addConfigurationProperty("keyboard.orientationAware", "1");
+    KeyboardInputMapper& mapper =
+            constructAndAddMapper<KeyboardInputMapper>(AINPUT_SOURCE_KEYBOARD);
+
+    prepareDisplay(ui::ROTATION_0);
+    ASSERT_NO_FATAL_FAILURE(
+            testDPadKeyRotation(mapper, KEY_UP, AKEYCODE_DPAD_UP, AKEYCODE_DPAD_UP, DISPLAY_ID));
+    ASSERT_NO_FATAL_FAILURE(testDPadKeyRotation(mapper, KEY_RIGHT, AKEYCODE_DPAD_RIGHT,
+                                                AKEYCODE_DPAD_RIGHT, DISPLAY_ID));
+    ASSERT_NO_FATAL_FAILURE(testDPadKeyRotation(mapper, KEY_DOWN, AKEYCODE_DPAD_DOWN,
+                                                AKEYCODE_DPAD_DOWN, DISPLAY_ID));
+    ASSERT_NO_FATAL_FAILURE(testDPadKeyRotation(mapper, KEY_LEFT, AKEYCODE_DPAD_LEFT,
+                                                AKEYCODE_DPAD_LEFT, DISPLAY_ID));
+
+    clearViewports();
+    prepareDisplay(ui::ROTATION_90);
+    ASSERT_NO_FATAL_FAILURE(
+            testDPadKeyRotation(mapper, KEY_UP, AKEYCODE_DPAD_UP, AKEYCODE_DPAD_LEFT, DISPLAY_ID));
+    ASSERT_NO_FATAL_FAILURE(testDPadKeyRotation(mapper, KEY_RIGHT, AKEYCODE_DPAD_RIGHT,
+                                                AKEYCODE_DPAD_UP, DISPLAY_ID));
+    ASSERT_NO_FATAL_FAILURE(testDPadKeyRotation(mapper, KEY_DOWN, AKEYCODE_DPAD_DOWN,
+                                                AKEYCODE_DPAD_RIGHT, DISPLAY_ID));
+    ASSERT_NO_FATAL_FAILURE(testDPadKeyRotation(mapper, KEY_LEFT, AKEYCODE_DPAD_LEFT,
+                                                AKEYCODE_DPAD_DOWN, DISPLAY_ID));
+
+    clearViewports();
+    prepareDisplay(ui::ROTATION_180);
+    ASSERT_NO_FATAL_FAILURE(
+            testDPadKeyRotation(mapper, KEY_UP, AKEYCODE_DPAD_UP, AKEYCODE_DPAD_DOWN, DISPLAY_ID));
+    ASSERT_NO_FATAL_FAILURE(testDPadKeyRotation(mapper, KEY_RIGHT, AKEYCODE_DPAD_RIGHT,
+                                                AKEYCODE_DPAD_LEFT, DISPLAY_ID));
+    ASSERT_NO_FATAL_FAILURE(testDPadKeyRotation(mapper, KEY_DOWN, AKEYCODE_DPAD_DOWN,
+                                                AKEYCODE_DPAD_UP, DISPLAY_ID));
+    ASSERT_NO_FATAL_FAILURE(testDPadKeyRotation(mapper, KEY_LEFT, AKEYCODE_DPAD_LEFT,
+                                                AKEYCODE_DPAD_RIGHT, DISPLAY_ID));
+
+    clearViewports();
+    prepareDisplay(ui::ROTATION_270);
+    ASSERT_NO_FATAL_FAILURE(
+            testDPadKeyRotation(mapper, KEY_UP, AKEYCODE_DPAD_UP, AKEYCODE_DPAD_RIGHT, DISPLAY_ID));
+    ASSERT_NO_FATAL_FAILURE(testDPadKeyRotation(mapper, KEY_RIGHT, AKEYCODE_DPAD_RIGHT,
+                                                AKEYCODE_DPAD_DOWN, DISPLAY_ID));
+    ASSERT_NO_FATAL_FAILURE(testDPadKeyRotation(mapper, KEY_DOWN, AKEYCODE_DPAD_DOWN,
+                                                AKEYCODE_DPAD_LEFT, DISPLAY_ID));
+    ASSERT_NO_FATAL_FAILURE(testDPadKeyRotation(mapper, KEY_LEFT, AKEYCODE_DPAD_LEFT,
+                                                AKEYCODE_DPAD_UP, DISPLAY_ID));
+
+    // Special case: if orientation changes while key is down, we still emit the same keycode
+    // in the key up as we did in the key down.
+    NotifyKeyArgs args;
+    clearViewports();
+    prepareDisplay(ui::ROTATION_270);
+    process(mapper, ARBITRARY_TIME, READ_TIME, EV_KEY, KEY_UP, 1);
+    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyKeyWasCalled(&args));
+    ASSERT_EQ(AKEY_EVENT_ACTION_DOWN, args.action);
+    ASSERT_EQ(KEY_UP, args.scanCode);
+    ASSERT_EQ(AKEYCODE_DPAD_RIGHT, args.keyCode);
+
+    clearViewports();
+    prepareDisplay(ui::ROTATION_180);
+    process(mapper, ARBITRARY_TIME, READ_TIME, EV_KEY, KEY_UP, 0);
+    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyKeyWasCalled(&args));
+    ASSERT_EQ(AKEY_EVENT_ACTION_UP, args.action);
+    ASSERT_EQ(KEY_UP, args.scanCode);
+    ASSERT_EQ(AKEYCODE_DPAD_RIGHT, args.keyCode);
+}
+
+TEST_F(KeyboardInputMapperTest, DisplayIdConfigurationChange_NotOrientationAware) {
+    // If the keyboard is not orientation aware,
+    // key events should not be associated with a specific display id
+    mFakeEventHub->addKey(EVENTHUB_ID, KEY_UP, 0, AKEYCODE_DPAD_UP, 0);
+
+    KeyboardInputMapper& mapper =
+            constructAndAddMapper<KeyboardInputMapper>(AINPUT_SOURCE_KEYBOARD);
+    NotifyKeyArgs args;
+
+    // Display id should be LogicalDisplayId::INVALID without any display configuration.
+    process(mapper, ARBITRARY_TIME, READ_TIME, EV_KEY, KEY_UP, 1);
+    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyKeyWasCalled(&args));
+    process(mapper, ARBITRARY_TIME, READ_TIME, EV_KEY, KEY_UP, 0);
+    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyKeyWasCalled(&args));
+    ASSERT_EQ(ui::LogicalDisplayId::INVALID, args.displayId);
+
+    prepareDisplay(ui::ROTATION_0);
+    process(mapper, ARBITRARY_TIME, READ_TIME, EV_KEY, KEY_UP, 1);
+    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyKeyWasCalled(&args));
+    process(mapper, ARBITRARY_TIME, READ_TIME, EV_KEY, KEY_UP, 0);
+    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyKeyWasCalled(&args));
+    ASSERT_EQ(ui::LogicalDisplayId::INVALID, args.displayId);
+}
+
+TEST_F(KeyboardInputMapperTest, DisplayIdConfigurationChange_OrientationAware) {
+    // If the keyboard is orientation aware,
+    // key events should be associated with the internal viewport
+    mFakeEventHub->addKey(EVENTHUB_ID, KEY_UP, 0, AKEYCODE_DPAD_UP, 0);
+
+    addConfigurationProperty("keyboard.orientationAware", "1");
+    KeyboardInputMapper& mapper =
+            constructAndAddMapper<KeyboardInputMapper>(AINPUT_SOURCE_KEYBOARD);
+    NotifyKeyArgs args;
+
+    // Display id should be LogicalDisplayId::INVALID without any display configuration.
+    // ^--- already checked by the previous test
+
+    setDisplayInfoAndReconfigure(DISPLAY_ID, DISPLAY_WIDTH, DISPLAY_HEIGHT, ui::ROTATION_0,
+                                 UNIQUE_ID, NO_PORT, ViewportType::INTERNAL);
+    process(mapper, ARBITRARY_TIME, READ_TIME, EV_KEY, KEY_UP, 1);
+    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyKeyWasCalled(&args));
+    process(mapper, ARBITRARY_TIME, READ_TIME, EV_KEY, KEY_UP, 0);
+    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyKeyWasCalled(&args));
+    ASSERT_EQ(DISPLAY_ID, args.displayId);
+
+    constexpr ui::LogicalDisplayId newDisplayId = ui::LogicalDisplayId{2};
+    clearViewports();
+    setDisplayInfoAndReconfigure(newDisplayId, DISPLAY_WIDTH, DISPLAY_HEIGHT, ui::ROTATION_0,
+                                 UNIQUE_ID, NO_PORT, ViewportType::INTERNAL);
+    process(mapper, ARBITRARY_TIME, READ_TIME, EV_KEY, KEY_UP, 1);
+    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyKeyWasCalled(&args));
+    process(mapper, ARBITRARY_TIME, READ_TIME, EV_KEY, KEY_UP, 0);
+    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyKeyWasCalled(&args));
+    ASSERT_EQ(newDisplayId, args.displayId);
+}
+
+TEST_F(KeyboardInputMapperTest, GetKeyCodeState) {
+    KeyboardInputMapper& mapper =
+            constructAndAddMapper<KeyboardInputMapper>(AINPUT_SOURCE_KEYBOARD);
+
+    mFakeEventHub->setKeyCodeState(EVENTHUB_ID, AKEYCODE_A, 1);
+    ASSERT_EQ(1, mapper.getKeyCodeState(AINPUT_SOURCE_ANY, AKEYCODE_A));
+
+    mFakeEventHub->setKeyCodeState(EVENTHUB_ID, AKEYCODE_A, 0);
+    ASSERT_EQ(0, mapper.getKeyCodeState(AINPUT_SOURCE_ANY, AKEYCODE_A));
+}
+
+TEST_F(KeyboardInputMapperTest, GetKeyCodeForKeyLocation) {
+    KeyboardInputMapper& mapper =
+            constructAndAddMapper<KeyboardInputMapper>(AINPUT_SOURCE_KEYBOARD);
+
+    mFakeEventHub->addKeyCodeMapping(EVENTHUB_ID, AKEYCODE_Y, AKEYCODE_Z);
+    ASSERT_EQ(AKEYCODE_Z, mapper.getKeyCodeForKeyLocation(AKEYCODE_Y))
+                                << "If a mapping is available, the result is equal to the mapping";
+
+    ASSERT_EQ(AKEYCODE_A, mapper.getKeyCodeForKeyLocation(AKEYCODE_A))
+                                << "If no mapping is available, the result is the key location";
+}
+
+TEST_F(KeyboardInputMapperTest, GetScanCodeState) {
+    KeyboardInputMapper& mapper =
+            constructAndAddMapper<KeyboardInputMapper>(AINPUT_SOURCE_KEYBOARD);
+
+    mFakeEventHub->setScanCodeState(EVENTHUB_ID, KEY_A, 1);
+    ASSERT_EQ(1, mapper.getScanCodeState(AINPUT_SOURCE_ANY, KEY_A));
+
+    mFakeEventHub->setScanCodeState(EVENTHUB_ID, KEY_A, 0);
+    ASSERT_EQ(0, mapper.getScanCodeState(AINPUT_SOURCE_ANY, KEY_A));
+}
+
+TEST_F(KeyboardInputMapperTest, MarkSupportedKeyCodes) {
+    KeyboardInputMapper& mapper =
+            constructAndAddMapper<KeyboardInputMapper>(AINPUT_SOURCE_KEYBOARD);
+
+    mFakeEventHub->addKey(EVENTHUB_ID, KEY_A, 0, AKEYCODE_A, 0);
+
+    uint8_t flags[2] = { 0, 0 };
+    ASSERT_TRUE(mapper.markSupportedKeyCodes(AINPUT_SOURCE_ANY, {AKEYCODE_A, AKEYCODE_B}, flags));
+    ASSERT_TRUE(flags[0]);
+    ASSERT_FALSE(flags[1]);
+}
+
+TEST_F(KeyboardInputMapperTest, Process_LockedKeysShouldToggleMetaStateAndLeds) {
+    mFakeEventHub->addLed(EVENTHUB_ID, LED_CAPSL, true /*initially on*/);
+    mFakeEventHub->addLed(EVENTHUB_ID, LED_NUML, false /*initially off*/);
+    mFakeEventHub->addLed(EVENTHUB_ID, LED_SCROLLL, false /*initially off*/);
+    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);
+
+    KeyboardInputMapper& mapper =
+            constructAndAddMapper<KeyboardInputMapper>(AINPUT_SOURCE_KEYBOARD);
+    // Initial metastate is AMETA_NONE.
+    ASSERT_EQ(AMETA_NONE, mapper.getMetaState());
+
+    // Initialization should have turned all of the lights off.
+    ASSERT_FALSE(mFakeEventHub->getLedState(EVENTHUB_ID, LED_CAPSL));
+    ASSERT_FALSE(mFakeEventHub->getLedState(EVENTHUB_ID, LED_NUML));
+    ASSERT_FALSE(mFakeEventHub->getLedState(EVENTHUB_ID, LED_SCROLLL));
+
+    // Toggle caps lock on.
+    process(mapper, ARBITRARY_TIME, READ_TIME, EV_KEY, KEY_CAPSLOCK, 1);
+    process(mapper, ARBITRARY_TIME, READ_TIME, EV_KEY, KEY_CAPSLOCK, 0);
+    ASSERT_TRUE(mFakeEventHub->getLedState(EVENTHUB_ID, LED_CAPSL));
+    ASSERT_FALSE(mFakeEventHub->getLedState(EVENTHUB_ID, LED_NUML));
+    ASSERT_FALSE(mFakeEventHub->getLedState(EVENTHUB_ID, LED_SCROLLL));
+    ASSERT_EQ(AMETA_CAPS_LOCK_ON, mapper.getMetaState());
+
+    // Toggle num lock on.
+    process(mapper, ARBITRARY_TIME, READ_TIME, EV_KEY, KEY_NUMLOCK, 1);
+    process(mapper, ARBITRARY_TIME, READ_TIME, EV_KEY, KEY_NUMLOCK, 0);
+    ASSERT_TRUE(mFakeEventHub->getLedState(EVENTHUB_ID, LED_CAPSL));
+    ASSERT_TRUE(mFakeEventHub->getLedState(EVENTHUB_ID, LED_NUML));
+    ASSERT_FALSE(mFakeEventHub->getLedState(EVENTHUB_ID, LED_SCROLLL));
+    ASSERT_EQ(AMETA_CAPS_LOCK_ON | AMETA_NUM_LOCK_ON, mapper.getMetaState());
+
+    // Toggle caps lock off.
+    process(mapper, ARBITRARY_TIME, READ_TIME, EV_KEY, KEY_CAPSLOCK, 1);
+    process(mapper, ARBITRARY_TIME, READ_TIME, EV_KEY, KEY_CAPSLOCK, 0);
+    ASSERT_FALSE(mFakeEventHub->getLedState(EVENTHUB_ID, LED_CAPSL));
+    ASSERT_TRUE(mFakeEventHub->getLedState(EVENTHUB_ID, LED_NUML));
+    ASSERT_FALSE(mFakeEventHub->getLedState(EVENTHUB_ID, LED_SCROLLL));
+    ASSERT_EQ(AMETA_NUM_LOCK_ON, mapper.getMetaState());
+
+    // Toggle scroll lock on.
+    process(mapper, ARBITRARY_TIME, READ_TIME, EV_KEY, KEY_SCROLLLOCK, 1);
+    process(mapper, ARBITRARY_TIME, READ_TIME, EV_KEY, KEY_SCROLLLOCK, 0);
+    ASSERT_FALSE(mFakeEventHub->getLedState(EVENTHUB_ID, LED_CAPSL));
+    ASSERT_TRUE(mFakeEventHub->getLedState(EVENTHUB_ID, LED_NUML));
+    ASSERT_TRUE(mFakeEventHub->getLedState(EVENTHUB_ID, LED_SCROLLL));
+    ASSERT_EQ(AMETA_NUM_LOCK_ON | AMETA_SCROLL_LOCK_ON, mapper.getMetaState());
+
+    // Toggle num lock off.
+    process(mapper, ARBITRARY_TIME, READ_TIME, EV_KEY, KEY_NUMLOCK, 1);
+    process(mapper, ARBITRARY_TIME, READ_TIME, EV_KEY, KEY_NUMLOCK, 0);
+    ASSERT_FALSE(mFakeEventHub->getLedState(EVENTHUB_ID, LED_CAPSL));
+    ASSERT_FALSE(mFakeEventHub->getLedState(EVENTHUB_ID, LED_NUML));
+    ASSERT_TRUE(mFakeEventHub->getLedState(EVENTHUB_ID, LED_SCROLLL));
+    ASSERT_EQ(AMETA_SCROLL_LOCK_ON, mapper.getMetaState());
+
+    // Toggle scroll lock off.
+    process(mapper, ARBITRARY_TIME, READ_TIME, EV_KEY, KEY_SCROLLLOCK, 1);
+    process(mapper, ARBITRARY_TIME, READ_TIME, EV_KEY, KEY_SCROLLLOCK, 0);
+    ASSERT_FALSE(mFakeEventHub->getLedState(EVENTHUB_ID, LED_CAPSL));
+    ASSERT_FALSE(mFakeEventHub->getLedState(EVENTHUB_ID, LED_NUML));
+    ASSERT_FALSE(mFakeEventHub->getLedState(EVENTHUB_ID, LED_SCROLLL));
+    ASSERT_EQ(AMETA_NONE, mapper.getMetaState());
+}
+
+TEST_F(KeyboardInputMapperTest, Configure_AssignsDisplayPort) {
+    // keyboard 1.
+    mFakeEventHub->addKey(EVENTHUB_ID, KEY_UP, 0, AKEYCODE_DPAD_UP, 0);
+    mFakeEventHub->addKey(EVENTHUB_ID, KEY_RIGHT, 0, AKEYCODE_DPAD_RIGHT, 0);
+    mFakeEventHub->addKey(EVENTHUB_ID, KEY_DOWN, 0, AKEYCODE_DPAD_DOWN, 0);
+    mFakeEventHub->addKey(EVENTHUB_ID, KEY_LEFT, 0, AKEYCODE_DPAD_LEFT, 0);
+
+    // keyboard 2.
+    const std::string USB2 = "USB2";
+    const std::string DEVICE_NAME2 = "KEYBOARD2";
+    constexpr int32_t SECOND_DEVICE_ID = DEVICE_ID + 1;
+    constexpr int32_t SECOND_EVENTHUB_ID = EVENTHUB_ID + 1;
+    std::shared_ptr<InputDevice> device2 =
+            newDevice(SECOND_DEVICE_ID, DEVICE_NAME2, USB2, SECOND_EVENTHUB_ID,
+                      ftl::Flags<InputDeviceClass>(0));
+
+    mFakeEventHub->addKey(SECOND_EVENTHUB_ID, KEY_UP, 0, AKEYCODE_DPAD_UP, 0);
+    mFakeEventHub->addKey(SECOND_EVENTHUB_ID, KEY_RIGHT, 0, AKEYCODE_DPAD_RIGHT, 0);
+    mFakeEventHub->addKey(SECOND_EVENTHUB_ID, KEY_DOWN, 0, AKEYCODE_DPAD_DOWN, 0);
+    mFakeEventHub->addKey(SECOND_EVENTHUB_ID, KEY_LEFT, 0, AKEYCODE_DPAD_LEFT, 0);
+
+    KeyboardInputMapper& mapper =
+            constructAndAddMapper<KeyboardInputMapper>(AINPUT_SOURCE_KEYBOARD);
+
+    device2->addEmptyEventHubDevice(SECOND_EVENTHUB_ID);
+    KeyboardInputMapper& mapper2 =
+            device2->constructAndAddMapper<KeyboardInputMapper>(SECOND_EVENTHUB_ID,
+                                                                mFakePolicy
+                                                                        ->getReaderConfiguration(),
+                                                                AINPUT_SOURCE_KEYBOARD);
+    std::list<NotifyArgs> unused =
+            device2->configure(ARBITRARY_TIME, mFakePolicy->getReaderConfiguration(),
+                    /*changes=*/{});
+    unused += device2->reset(ARBITRARY_TIME);
+
+    // Prepared displays and associated info.
+    constexpr uint8_t hdmi1 = 0;
+    constexpr uint8_t hdmi2 = 1;
+    const std::string SECONDARY_UNIQUE_ID = "local:1";
+
+    mFakePolicy->addInputPortAssociation(DEVICE_LOCATION, hdmi1);
+    mFakePolicy->addInputPortAssociation(USB2, hdmi2);
+
+    // No associated display viewport found, should disable the device.
+    unused += device2->configure(ARBITRARY_TIME, mFakePolicy->getReaderConfiguration(),
+                                 InputReaderConfiguration::Change::DISPLAY_INFO);
+    ASSERT_FALSE(device2->isEnabled());
+
+    // Prepare second display.
+    constexpr ui::LogicalDisplayId newDisplayId = ui::LogicalDisplayId{2};
+    setDisplayInfoAndReconfigure(DISPLAY_ID, DISPLAY_WIDTH, DISPLAY_HEIGHT, ui::ROTATION_0,
+                                 UNIQUE_ID, hdmi1, ViewportType::INTERNAL);
+    setDisplayInfoAndReconfigure(newDisplayId, DISPLAY_WIDTH, DISPLAY_HEIGHT, ui::ROTATION_0,
+                                 SECONDARY_UNIQUE_ID, hdmi2, ViewportType::EXTERNAL);
+    // Default device will reconfigure above, need additional reconfiguration for another device.
+    unused += device2->configure(ARBITRARY_TIME, mFakePolicy->getReaderConfiguration(),
+                                 InputReaderConfiguration::Change::DISPLAY_INFO);
+
+    // Device should be enabled after the associated display is found.
+    ASSERT_TRUE(mDevice->isEnabled());
+    ASSERT_TRUE(device2->isEnabled());
+
+    // Test pad key events
+    ASSERT_NO_FATAL_FAILURE(
+            testDPadKeyRotation(mapper, KEY_UP, AKEYCODE_DPAD_UP, AKEYCODE_DPAD_UP, DISPLAY_ID));
+    ASSERT_NO_FATAL_FAILURE(testDPadKeyRotation(mapper, KEY_RIGHT, AKEYCODE_DPAD_RIGHT,
+                                                AKEYCODE_DPAD_RIGHT, DISPLAY_ID));
+    ASSERT_NO_FATAL_FAILURE(testDPadKeyRotation(mapper, KEY_DOWN, AKEYCODE_DPAD_DOWN,
+                                                AKEYCODE_DPAD_DOWN, DISPLAY_ID));
+    ASSERT_NO_FATAL_FAILURE(testDPadKeyRotation(mapper, KEY_LEFT, AKEYCODE_DPAD_LEFT,
+                                                AKEYCODE_DPAD_LEFT, DISPLAY_ID));
+
+    ASSERT_NO_FATAL_FAILURE(
+            testDPadKeyRotation(mapper2, KEY_UP, AKEYCODE_DPAD_UP, AKEYCODE_DPAD_UP, newDisplayId));
+    ASSERT_NO_FATAL_FAILURE(testDPadKeyRotation(mapper2, KEY_RIGHT, AKEYCODE_DPAD_RIGHT,
+                                                AKEYCODE_DPAD_RIGHT, newDisplayId));
+    ASSERT_NO_FATAL_FAILURE(testDPadKeyRotation(mapper2, KEY_DOWN, AKEYCODE_DPAD_DOWN,
+                                                AKEYCODE_DPAD_DOWN, newDisplayId));
+    ASSERT_NO_FATAL_FAILURE(testDPadKeyRotation(mapper2, KEY_LEFT, AKEYCODE_DPAD_LEFT,
+                                                AKEYCODE_DPAD_LEFT, newDisplayId));
+}
+
+TEST_F(KeyboardInputMapperTest, Process_LockedKeysShouldToggleAfterReattach) {
+    mFakeEventHub->addLed(EVENTHUB_ID, LED_CAPSL, true /*initially on*/);
+    mFakeEventHub->addLed(EVENTHUB_ID, LED_NUML, false /*initially off*/);
+    mFakeEventHub->addLed(EVENTHUB_ID, LED_SCROLLL, false /*initially off*/);
+    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);
+
+    KeyboardInputMapper& mapper =
+            constructAndAddMapper<KeyboardInputMapper>(AINPUT_SOURCE_KEYBOARD);
+    // Initial metastate is AMETA_NONE.
+    ASSERT_EQ(AMETA_NONE, mapper.getMetaState());
+
+    // Initialization should have turned all of the lights off.
+    ASSERT_FALSE(mFakeEventHub->getLedState(EVENTHUB_ID, LED_CAPSL));
+    ASSERT_FALSE(mFakeEventHub->getLedState(EVENTHUB_ID, LED_NUML));
+    ASSERT_FALSE(mFakeEventHub->getLedState(EVENTHUB_ID, LED_SCROLLL));
+
+    // Toggle caps lock on.
+    process(mapper, ARBITRARY_TIME, READ_TIME, EV_KEY, KEY_CAPSLOCK, 1);
+    process(mapper, ARBITRARY_TIME, READ_TIME, EV_KEY, KEY_CAPSLOCK, 0);
+    ASSERT_TRUE(mFakeEventHub->getLedState(EVENTHUB_ID, LED_CAPSL));
+    ASSERT_EQ(AMETA_CAPS_LOCK_ON, mapper.getMetaState());
+
+    // Toggle num lock on.
+    process(mapper, ARBITRARY_TIME, READ_TIME, EV_KEY, KEY_NUMLOCK, 1);
+    process(mapper, ARBITRARY_TIME, READ_TIME, EV_KEY, KEY_NUMLOCK, 0);
+    ASSERT_TRUE(mFakeEventHub->getLedState(EVENTHUB_ID, LED_NUML));
+    ASSERT_EQ(AMETA_CAPS_LOCK_ON | AMETA_NUM_LOCK_ON, mapper.getMetaState());
+
+    // Toggle scroll lock on.
+    process(mapper, ARBITRARY_TIME, READ_TIME, EV_KEY, KEY_SCROLLLOCK, 1);
+    process(mapper, ARBITRARY_TIME, READ_TIME, EV_KEY, KEY_SCROLLLOCK, 0);
+    ASSERT_TRUE(mFakeEventHub->getLedState(EVENTHUB_ID, LED_SCROLLL));
+    ASSERT_EQ(AMETA_CAPS_LOCK_ON | AMETA_NUM_LOCK_ON | AMETA_SCROLL_LOCK_ON, mapper.getMetaState());
+
+    mFakeEventHub->removeDevice(EVENTHUB_ID);
+    mReader->loopOnce();
+
+    // keyboard 2 should default toggle keys.
+    const std::string USB2 = "USB2";
+    const std::string DEVICE_NAME2 = "KEYBOARD2";
+    constexpr int32_t SECOND_DEVICE_ID = DEVICE_ID + 1;
+    constexpr int32_t SECOND_EVENTHUB_ID = EVENTHUB_ID + 1;
+    std::shared_ptr<InputDevice> device2 =
+            newDevice(SECOND_DEVICE_ID, DEVICE_NAME2, USB2, SECOND_EVENTHUB_ID,
+                      ftl::Flags<InputDeviceClass>(0));
+    mFakeEventHub->addLed(SECOND_EVENTHUB_ID, LED_CAPSL, true /*initially on*/);
+    mFakeEventHub->addLed(SECOND_EVENTHUB_ID, LED_NUML, false /*initially off*/);
+    mFakeEventHub->addLed(SECOND_EVENTHUB_ID, LED_SCROLLL, false /*initially off*/);
+    mFakeEventHub->addKey(SECOND_EVENTHUB_ID, KEY_CAPSLOCK, 0, AKEYCODE_CAPS_LOCK, 0);
+    mFakeEventHub->addKey(SECOND_EVENTHUB_ID, KEY_NUMLOCK, 0, AKEYCODE_NUM_LOCK, 0);
+    mFakeEventHub->addKey(SECOND_EVENTHUB_ID, KEY_SCROLLLOCK, 0, AKEYCODE_SCROLL_LOCK, 0);
+
+    device2->addEmptyEventHubDevice(SECOND_EVENTHUB_ID);
+    KeyboardInputMapper& mapper2 =
+            device2->constructAndAddMapper<KeyboardInputMapper>(SECOND_EVENTHUB_ID,
+                                                                mFakePolicy
+                                                                        ->getReaderConfiguration(),
+                                                                AINPUT_SOURCE_KEYBOARD);
+    std::list<NotifyArgs> unused =
+            device2->configure(ARBITRARY_TIME, mFakePolicy->getReaderConfiguration(),
+                    /*changes=*/{});
+    unused += device2->reset(ARBITRARY_TIME);
+
+    ASSERT_TRUE(mFakeEventHub->getLedState(SECOND_EVENTHUB_ID, LED_CAPSL));
+    ASSERT_TRUE(mFakeEventHub->getLedState(SECOND_EVENTHUB_ID, LED_NUML));
+    ASSERT_TRUE(mFakeEventHub->getLedState(SECOND_EVENTHUB_ID, LED_SCROLLL));
+    ASSERT_EQ(AMETA_CAPS_LOCK_ON | AMETA_NUM_LOCK_ON | AMETA_SCROLL_LOCK_ON,
+              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)
+    constructAndAddMapper<KeyboardInputMapper>(AINPUT_SOURCE_DPAD);
+    KeyboardInputMapper& mapper =
+            constructAndAddMapper<KeyboardInputMapper>(AINPUT_SOURCE_KEYBOARD);
+    // Initial metastate is AMETA_NONE.
+    ASSERT_EQ(AMETA_NONE, mapper.getMetaState());
+
+    mReader->toggleCapsLockState(DEVICE_ID);
+    ASSERT_EQ(AMETA_CAPS_LOCK_ON, mapper.getMetaState());
+}
+
+TEST_F(KeyboardInputMapperTest, Process_LockedKeysShouldToggleInMultiDevices) {
+    // keyboard 1.
+    mFakeEventHub->addLed(EVENTHUB_ID, LED_CAPSL, true /*initially on*/);
+    mFakeEventHub->addLed(EVENTHUB_ID, LED_NUML, false /*initially off*/);
+    mFakeEventHub->addLed(EVENTHUB_ID, LED_SCROLLL, false /*initially off*/);
+    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);
+
+    KeyboardInputMapper& mapper1 =
+            constructAndAddMapper<KeyboardInputMapper>(AINPUT_SOURCE_KEYBOARD);
+
+    // keyboard 2.
+    const std::string USB2 = "USB2";
+    const std::string DEVICE_NAME2 = "KEYBOARD2";
+    constexpr int32_t SECOND_DEVICE_ID = DEVICE_ID + 1;
+    constexpr int32_t SECOND_EVENTHUB_ID = EVENTHUB_ID + 1;
+    std::shared_ptr<InputDevice> device2 =
+            newDevice(SECOND_DEVICE_ID, DEVICE_NAME2, USB2, SECOND_EVENTHUB_ID,
+                      ftl::Flags<InputDeviceClass>(0));
+    mFakeEventHub->addLed(SECOND_EVENTHUB_ID, LED_CAPSL, true /*initially on*/);
+    mFakeEventHub->addLed(SECOND_EVENTHUB_ID, LED_NUML, false /*initially off*/);
+    mFakeEventHub->addLed(SECOND_EVENTHUB_ID, LED_SCROLLL, false /*initially off*/);
+    mFakeEventHub->addKey(SECOND_EVENTHUB_ID, KEY_CAPSLOCK, 0, AKEYCODE_CAPS_LOCK, 0);
+    mFakeEventHub->addKey(SECOND_EVENTHUB_ID, KEY_NUMLOCK, 0, AKEYCODE_NUM_LOCK, 0);
+    mFakeEventHub->addKey(SECOND_EVENTHUB_ID, KEY_SCROLLLOCK, 0, AKEYCODE_SCROLL_LOCK, 0);
+
+    device2->addEmptyEventHubDevice(SECOND_EVENTHUB_ID);
+    KeyboardInputMapper& mapper2 =
+            device2->constructAndAddMapper<KeyboardInputMapper>(SECOND_EVENTHUB_ID,
+                                                                mFakePolicy
+                                                                        ->getReaderConfiguration(),
+                                                                AINPUT_SOURCE_KEYBOARD);
+    std::list<NotifyArgs> unused =
+            device2->configure(ARBITRARY_TIME, mFakePolicy->getReaderConfiguration(),
+                    /*changes=*/{});
+    unused += device2->reset(ARBITRARY_TIME);
+
+    // Initial metastate is AMETA_NONE.
+    ASSERT_EQ(AMETA_NONE, mapper1.getMetaState());
+    ASSERT_EQ(AMETA_NONE, mapper2.getMetaState());
+
+    // Toggle num lock on and off.
+    process(mapper1, ARBITRARY_TIME, READ_TIME, EV_KEY, KEY_NUMLOCK, 1);
+    process(mapper1, ARBITRARY_TIME, READ_TIME, EV_KEY, KEY_NUMLOCK, 0);
+    ASSERT_TRUE(mFakeEventHub->getLedState(EVENTHUB_ID, LED_NUML));
+    ASSERT_EQ(AMETA_NUM_LOCK_ON, mapper1.getMetaState());
+    ASSERT_EQ(AMETA_NUM_LOCK_ON, mapper2.getMetaState());
+
+    process(mapper1, ARBITRARY_TIME, READ_TIME, EV_KEY, KEY_NUMLOCK, 1);
+    process(mapper1, ARBITRARY_TIME, READ_TIME, EV_KEY, KEY_NUMLOCK, 0);
+    ASSERT_FALSE(mFakeEventHub->getLedState(EVENTHUB_ID, LED_NUML));
+    ASSERT_EQ(AMETA_NONE, mapper1.getMetaState());
+    ASSERT_EQ(AMETA_NONE, mapper2.getMetaState());
+
+    // Toggle caps lock on and off.
+    process(mapper1, ARBITRARY_TIME, READ_TIME, EV_KEY, KEY_CAPSLOCK, 1);
+    process(mapper1, ARBITRARY_TIME, READ_TIME, EV_KEY, KEY_CAPSLOCK, 0);
+    ASSERT_TRUE(mFakeEventHub->getLedState(EVENTHUB_ID, LED_CAPSL));
+    ASSERT_EQ(AMETA_CAPS_LOCK_ON, mapper1.getMetaState());
+    ASSERT_EQ(AMETA_CAPS_LOCK_ON, mapper2.getMetaState());
+
+    process(mapper1, ARBITRARY_TIME, READ_TIME, EV_KEY, KEY_CAPSLOCK, 1);
+    process(mapper1, ARBITRARY_TIME, READ_TIME, EV_KEY, KEY_CAPSLOCK, 0);
+    ASSERT_FALSE(mFakeEventHub->getLedState(EVENTHUB_ID, LED_CAPSL));
+    ASSERT_EQ(AMETA_NONE, mapper1.getMetaState());
+    ASSERT_EQ(AMETA_NONE, mapper2.getMetaState());
+
+    // Toggle scroll lock on and off.
+    process(mapper1, ARBITRARY_TIME, READ_TIME, EV_KEY, KEY_SCROLLLOCK, 1);
+    process(mapper1, ARBITRARY_TIME, READ_TIME, EV_KEY, KEY_SCROLLLOCK, 0);
+    ASSERT_TRUE(mFakeEventHub->getLedState(EVENTHUB_ID, LED_SCROLLL));
+    ASSERT_EQ(AMETA_SCROLL_LOCK_ON, mapper1.getMetaState());
+    ASSERT_EQ(AMETA_SCROLL_LOCK_ON, mapper2.getMetaState());
+
+    process(mapper1, ARBITRARY_TIME, READ_TIME, EV_KEY, KEY_SCROLLLOCK, 1);
+    process(mapper1, ARBITRARY_TIME, READ_TIME, EV_KEY, KEY_SCROLLLOCK, 0);
+    ASSERT_FALSE(mFakeEventHub->getLedState(EVENTHUB_ID, LED_SCROLLL));
+    ASSERT_EQ(AMETA_NONE, mapper1.getMetaState());
+    ASSERT_EQ(AMETA_NONE, mapper2.getMetaState());
+}
+
+TEST_F(KeyboardInputMapperTest, Process_DisabledDevice) {
+    const int32_t USAGE_A = 0x070004;
+    mFakeEventHub->addKey(EVENTHUB_ID, KEY_HOME, 0, AKEYCODE_HOME, POLICY_FLAG_WAKE);
+    mFakeEventHub->addKey(EVENTHUB_ID, 0, USAGE_A, AKEYCODE_A, POLICY_FLAG_WAKE);
+
+    KeyboardInputMapper& mapper =
+            constructAndAddMapper<KeyboardInputMapper>(AINPUT_SOURCE_KEYBOARD);
+    // Key down by scan code.
+    process(mapper, ARBITRARY_TIME, READ_TIME, EV_KEY, KEY_HOME, 1);
+    NotifyKeyArgs args;
+    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyKeyWasCalled(&args));
+    ASSERT_EQ(DEVICE_ID, args.deviceId);
+    ASSERT_EQ(AINPUT_SOURCE_KEYBOARD, args.source);
+    ASSERT_EQ(ARBITRARY_TIME, args.eventTime);
+    ASSERT_EQ(AKEY_EVENT_ACTION_DOWN, args.action);
+    ASSERT_EQ(AKEYCODE_HOME, args.keyCode);
+    ASSERT_EQ(KEY_HOME, args.scanCode);
+    ASSERT_EQ(AKEY_EVENT_FLAG_FROM_SYSTEM, args.flags);
+
+    // Disable device, it should synthesize cancellation events for down events.
+    mFakePolicy->addDisabledDevice(DEVICE_ID);
+    configureDevice(InputReaderConfiguration::Change::ENABLED_STATE);
+
+    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyKeyWasCalled(&args));
+    ASSERT_EQ(AKEY_EVENT_ACTION_UP, args.action);
+    ASSERT_EQ(AKEYCODE_HOME, args.keyCode);
+    ASSERT_EQ(KEY_HOME, args.scanCode);
+    ASSERT_EQ(AKEY_EVENT_FLAG_FROM_SYSTEM | AKEY_EVENT_FLAG_CANCELED, args.flags);
+}
+
+TEST_F(KeyboardInputMapperTest, Configure_AssignKeyboardLayoutInfo) {
+    constructAndAddMapper<KeyboardInputMapper>(AINPUT_SOURCE_KEYBOARD);
+    std::list<NotifyArgs> unused =
+            mDevice->configure(ARBITRARY_TIME, mFakePolicy->getReaderConfiguration(),
+                    /*changes=*/{});
+
+    uint32_t generation = mReader->getContext()->getGeneration();
+    mFakePolicy->addKeyboardLayoutAssociation(DEVICE_LOCATION, DEVICE_KEYBOARD_LAYOUT_INFO);
+
+    unused += mDevice->configure(ARBITRARY_TIME, mFakePolicy->getReaderConfiguration(),
+                                 InputReaderConfiguration::Change::KEYBOARD_LAYOUT_ASSOCIATION);
+
+    InputDeviceInfo deviceInfo = mDevice->getDeviceInfo();
+    ASSERT_EQ(DEVICE_KEYBOARD_LAYOUT_INFO.languageTag,
+              deviceInfo.getKeyboardLayoutInfo()->languageTag);
+    ASSERT_EQ(DEVICE_KEYBOARD_LAYOUT_INFO.layoutType,
+              deviceInfo.getKeyboardLayoutInfo()->layoutType);
+    ASSERT_TRUE(mReader->getContext()->getGeneration() != generation);
+
+    // Call change layout association with the same values: Generation shouldn't change
+    generation = mReader->getContext()->getGeneration();
+    mFakePolicy->addKeyboardLayoutAssociation(DEVICE_LOCATION, DEVICE_KEYBOARD_LAYOUT_INFO);
+    unused += mDevice->configure(ARBITRARY_TIME, mFakePolicy->getReaderConfiguration(),
+                                 InputReaderConfiguration::Change::KEYBOARD_LAYOUT_ASSOCIATION);
+    ASSERT_TRUE(mReader->getContext()->getGeneration() == generation);
+}
+
+TEST_F(KeyboardInputMapperTest, LayoutInfoCorrectlyMapped) {
+    mFakeEventHub->setRawLayoutInfo(EVENTHUB_ID,
+                                    RawLayoutInfo{.languageTag = "en", .layoutType = "extended"});
+
+    // Configuration
+    constructAndAddMapper<KeyboardInputMapper>(AINPUT_SOURCE_KEYBOARD);
+    InputReaderConfiguration config;
+    std::list<NotifyArgs> unused = mDevice->configure(ARBITRARY_TIME, config, /*changes=*/{});
+
+    ASSERT_EQ("en", mDevice->getDeviceInfo().getKeyboardLayoutInfo()->languageTag);
+    ASSERT_EQ("extended", mDevice->getDeviceInfo().getKeyboardLayoutInfo()->layoutType);
+}
+
+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);
+    NotifyKeyArgs args;
+
+    // Key down
+    process(mapper, ARBITRARY_TIME, READ_TIME, EV_KEY, KEY_LEFT, 1);
+    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyKeyWasCalled(&args));
+    ASSERT_EQ(AKEY_EVENT_FLAG_FROM_SYSTEM | AKEY_EVENT_FLAG_KEEP_TOUCH_MODE, args.flags);
+}
+
+TEST_F_WITH_FLAGS(KeyboardInputMapperTest, WakeBehavior_AlphabeticKeyboard,
+        REQUIRES_FLAGS_ENABLED(ACONFIG_FLAG(com::android::input::flags,
+                                            enable_alphabetic_keyboard_wake))) {
+    // For internal alphabetic devices, keys will trigger wake on key down.
+
+    mFakeEventHub->addKey(EVENTHUB_ID, KEY_A, 0, AKEYCODE_A, 0);
+    mFakeEventHub->addKey(EVENTHUB_ID, KEY_HOME, 0, AKEYCODE_HOME, 0);
+    mFakeEventHub->addKey(EVENTHUB_ID, KEY_PLAYPAUSE, 0, AKEYCODE_MEDIA_PLAY_PAUSE, 0);
+
+    KeyboardInputMapper& mapper =
+            constructAndAddMapper<KeyboardInputMapper>(AINPUT_SOURCE_KEYBOARD);
+
+    process(mapper, ARBITRARY_TIME, READ_TIME, EV_KEY, KEY_A, 1);
+    NotifyKeyArgs args;
+    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyKeyWasCalled(&args));
+    ASSERT_EQ(POLICY_FLAG_WAKE, args.policyFlags);
+
+    process(mapper, ARBITRARY_TIME + 1, READ_TIME, EV_KEY, KEY_A, 0);
+    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyKeyWasCalled(&args));
+    ASSERT_EQ(uint32_t(0), args.policyFlags);
+
+    process(mapper, ARBITRARY_TIME, READ_TIME, EV_KEY, KEY_HOME, 1);
+    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyKeyWasCalled(&args));
+    ASSERT_EQ(POLICY_FLAG_WAKE, args.policyFlags);
+
+    process(mapper, ARBITRARY_TIME + 1, READ_TIME, EV_KEY, KEY_HOME, 0);
+    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyKeyWasCalled(&args));
+    ASSERT_EQ(uint32_t(0), args.policyFlags);
+
+    process(mapper, ARBITRARY_TIME, READ_TIME, EV_KEY, KEY_PLAYPAUSE, 1);
+    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyKeyWasCalled(&args));
+    ASSERT_EQ(POLICY_FLAG_WAKE, args.policyFlags);
+
+    process(mapper, ARBITRARY_TIME + 1, READ_TIME, EV_KEY, KEY_PLAYPAUSE, 0);
+    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyKeyWasCalled(&args));
+    ASSERT_EQ(uint32_t(0), args.policyFlags);
+}
+
+/**
+ * When there is more than one KeyboardInputMapper for an InputDevice, each mapper should produce
+ * events that use the shared keyboard source across all mappers. This is to ensure that each
+ * input device generates key events in a consistent manner, regardless of which mapper produces
+ * the event.
+ */
+TEST_F(KeyboardInputMapperTest, UsesSharedKeyboardSource) {
+    mFakeEventHub->addKey(EVENTHUB_ID, KEY_HOME, 0, AKEYCODE_HOME, POLICY_FLAG_WAKE);
+
+    // Add a mapper with SOURCE_KEYBOARD
+    KeyboardInputMapper& keyboardMapper =
+            constructAndAddMapper<KeyboardInputMapper>(AINPUT_SOURCE_KEYBOARD);
+
+    process(keyboardMapper, ARBITRARY_TIME, 0, EV_KEY, KEY_HOME, 1);
+    ASSERT_NO_FATAL_FAILURE(
+            mFakeListener->assertNotifyKeyWasCalled(WithSource(AINPUT_SOURCE_KEYBOARD)));
+    process(keyboardMapper, ARBITRARY_TIME, 0, EV_KEY, KEY_HOME, 0);
+    ASSERT_NO_FATAL_FAILURE(
+            mFakeListener->assertNotifyKeyWasCalled(WithSource(AINPUT_SOURCE_KEYBOARD)));
+
+    // Add a mapper with SOURCE_DPAD
+    KeyboardInputMapper& dpadMapper =
+            constructAndAddMapper<KeyboardInputMapper>(AINPUT_SOURCE_DPAD);
+    for (auto* mapper : {&keyboardMapper, &dpadMapper}) {
+        process(*mapper, ARBITRARY_TIME, 0, EV_KEY, KEY_HOME, 1);
+        ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyKeyWasCalled(
+                WithSource(AINPUT_SOURCE_KEYBOARD | AINPUT_SOURCE_DPAD)));
+        process(*mapper, ARBITRARY_TIME, 0, EV_KEY, KEY_HOME, 0);
+        ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyKeyWasCalled(
+                WithSource(AINPUT_SOURCE_KEYBOARD | AINPUT_SOURCE_DPAD)));
+    }
+
+    // Add a mapper with SOURCE_GAMEPAD
+    KeyboardInputMapper& gamepadMapper =
+            constructAndAddMapper<KeyboardInputMapper>(AINPUT_SOURCE_GAMEPAD);
+    for (auto* mapper : {&keyboardMapper, &dpadMapper, &gamepadMapper}) {
+        process(*mapper, ARBITRARY_TIME, 0, EV_KEY, KEY_HOME, 1);
+        ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyKeyWasCalled(
+                WithSource(AINPUT_SOURCE_KEYBOARD | AINPUT_SOURCE_DPAD | AINPUT_SOURCE_GAMEPAD)));
+        process(*mapper, ARBITRARY_TIME, 0, EV_KEY, KEY_HOME, 0);
+        ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyKeyWasCalled(
+                WithSource(AINPUT_SOURCE_KEYBOARD | AINPUT_SOURCE_DPAD | AINPUT_SOURCE_GAMEPAD)));
+    }
+}
+
+// --- KeyboardInputMapperTest_ExternalAlphabeticDevice ---
+
+class KeyboardInputMapperTest_ExternalAlphabeticDevice : public InputMapperTest {
+protected:
+    void SetUp() override {
+        InputMapperTest::SetUp(DEVICE_CLASSES | InputDeviceClass::KEYBOARD |
+                               InputDeviceClass::ALPHAKEY | InputDeviceClass::EXTERNAL);
+    }
+};
+
+// --- 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.
+
+    mFakeEventHub->addKey(EVENTHUB_ID, KEY_HOME, 0, AKEYCODE_HOME, 0);
+    mFakeEventHub->addKey(EVENTHUB_ID, KEY_PLAY, 0, AKEYCODE_MEDIA_PLAY, 0);
+    mFakeEventHub->addKey(EVENTHUB_ID, KEY_PLAYPAUSE, 0, AKEYCODE_MEDIA_PLAY_PAUSE,
+                          POLICY_FLAG_WAKE);
+
+    KeyboardInputMapper& mapper =
+            constructAndAddMapper<KeyboardInputMapper>(AINPUT_SOURCE_KEYBOARD);
+
+    process(mapper, ARBITRARY_TIME, READ_TIME, EV_KEY, KEY_HOME, 1);
+    NotifyKeyArgs args;
+    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyKeyWasCalled(&args));
+    ASSERT_EQ(POLICY_FLAG_WAKE, args.policyFlags);
+
+    process(mapper, ARBITRARY_TIME + 1, READ_TIME, EV_KEY, KEY_HOME, 0);
+    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyKeyWasCalled(&args));
+    ASSERT_EQ(uint32_t(0), args.policyFlags);
+
+    process(mapper, ARBITRARY_TIME, READ_TIME, EV_KEY, KEY_PLAY, 1);
+    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyKeyWasCalled(&args));
+    ASSERT_EQ(POLICY_FLAG_WAKE, args.policyFlags);
+
+    process(mapper, ARBITRARY_TIME + 1, READ_TIME, EV_KEY, KEY_PLAY, 0);
+    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyKeyWasCalled(&args));
+    ASSERT_EQ(uint32_t(0), args.policyFlags);
+
+    process(mapper, ARBITRARY_TIME, READ_TIME, EV_KEY, KEY_PLAYPAUSE, 1);
+    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyKeyWasCalled(&args));
+    ASSERT_EQ(POLICY_FLAG_WAKE, args.policyFlags);
+
+    process(mapper, ARBITRARY_TIME + 1, READ_TIME, EV_KEY, KEY_PLAYPAUSE, 0);
+    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyKeyWasCalled(&args));
+    ASSERT_EQ(POLICY_FLAG_WAKE, args.policyFlags);
+}
+
+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).
+
+    mFakeEventHub->addKey(EVENTHUB_ID, KEY_PLAY, 0, AKEYCODE_MEDIA_PLAY, 0);
+    mFakeEventHub->addKey(EVENTHUB_ID, KEY_PLAYPAUSE, 0, AKEYCODE_MEDIA_PLAY_PAUSE,
+                          POLICY_FLAG_WAKE);
+
+    KeyboardInputMapper& mapper =
+            constructAndAddMapper<KeyboardInputMapper>(AINPUT_SOURCE_KEYBOARD);
+
+    process(mapper, ARBITRARY_TIME, READ_TIME, EV_KEY, KEY_PLAY, 1);
+    NotifyKeyArgs args;
+    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyKeyWasCalled(&args));
+    ASSERT_EQ(uint32_t(0), args.policyFlags);
+
+    process(mapper, ARBITRARY_TIME + 1, READ_TIME, EV_KEY, KEY_PLAY, 0);
+    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyKeyWasCalled(&args));
+    ASSERT_EQ(uint32_t(0), args.policyFlags);
+
+    process(mapper, ARBITRARY_TIME, READ_TIME, EV_KEY, KEY_PLAYPAUSE, 1);
+    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyKeyWasCalled(&args));
+    ASSERT_EQ(POLICY_FLAG_WAKE, args.policyFlags);
+
+    process(mapper, ARBITRARY_TIME + 1, READ_TIME, EV_KEY, KEY_PLAYPAUSE, 0);
+    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyKeyWasCalled(&args));
+    ASSERT_EQ(POLICY_FLAG_WAKE, args.policyFlags);
+}
+
+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);
+    mFakeEventHub->addKey(EVENTHUB_ID, KEY_DOWN, 0, AKEYCODE_DPAD_DOWN, 0);
+    mFakeEventHub->addKey(EVENTHUB_ID, KEY_PLAY, 0, AKEYCODE_MEDIA_PLAY, POLICY_FLAG_WAKE);
+
+    addConfigurationProperty("keyboard.doNotWakeByDefault", "1");
+    KeyboardInputMapper& mapper =
+            constructAndAddMapper<KeyboardInputMapper>(AINPUT_SOURCE_KEYBOARD);
+
+    process(mapper, ARBITRARY_TIME, READ_TIME, EV_KEY, KEY_HOME, 1);
+    NotifyKeyArgs args;
+    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyKeyWasCalled(&args));
+    ASSERT_EQ(POLICY_FLAG_WAKE, args.policyFlags);
+
+    process(mapper, ARBITRARY_TIME + 1, READ_TIME, EV_KEY, KEY_HOME, 0);
+    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyKeyWasCalled(&args));
+    ASSERT_EQ(POLICY_FLAG_WAKE, args.policyFlags);
+
+    process(mapper, ARBITRARY_TIME, READ_TIME, EV_KEY, KEY_DOWN, 1);
+    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyKeyWasCalled(&args));
+    ASSERT_EQ(uint32_t(0), args.policyFlags);
+
+    process(mapper, ARBITRARY_TIME + 1, READ_TIME, EV_KEY, KEY_DOWN, 0);
+    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyKeyWasCalled(&args));
+    ASSERT_EQ(uint32_t(0), args.policyFlags);
+
+    process(mapper, ARBITRARY_TIME, READ_TIME, EV_KEY, KEY_PLAY, 1);
+    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyKeyWasCalled(&args));
+    ASSERT_EQ(POLICY_FLAG_WAKE, args.policyFlags);
+
+    process(mapper, ARBITRARY_TIME + 1, READ_TIME, EV_KEY, KEY_PLAY, 0);
+    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyKeyWasCalled(&args));
+    ASSERT_EQ(POLICY_FLAG_WAKE, args.policyFlags);
+}
+
 } // namespace android
diff --git a/services/surfaceflinger/Scheduler/RefreshRateSelector.cpp b/services/surfaceflinger/Scheduler/RefreshRateSelector.cpp
index 84fa139..e4069dd 100644
--- a/services/surfaceflinger/Scheduler/RefreshRateSelector.cpp
+++ b/services/surfaceflinger/Scheduler/RefreshRateSelector.cpp
@@ -770,17 +770,13 @@
             const bool inPrimaryPhysicalRange =
                     policy->primaryRanges.physical.includes(modePtr->getPeakFps());
             const bool inPrimaryRenderRange = policy->primaryRanges.render.includes(fps);
-            if (!mIsVrrDevice.load() &&
-                ((policy->primaryRangeIsSingleRate() && !inPrimaryPhysicalRange) ||
+            if (((policy->primaryRangeIsSingleRate() && !inPrimaryPhysicalRange) ||
                  !inPrimaryRenderRange) &&
                 !(layer.focused &&
                   (layer.vote == LayerVoteType::ExplicitDefault ||
                    layer.vote == LayerVoteType::ExplicitExact))) {
                 // Only focused layers with ExplicitDefault frame rate settings are allowed to score
                 // refresh rates outside the primary range.
-                ALOGV("%s ignores %s (primaryRangeIsSingleRate). Current mode = %s",
-                      formatLayerInfo(layer, weight).c_str(), to_string(*modePtr).c_str(),
-                      to_string(activeMode).c_str());
                 continue;
             }
 
@@ -904,8 +900,7 @@
                                    to_string(descending.front().frameRateMode.fps).c_str());
             return {descending, kNoSignals};
         } else {
-            ALOGV("%s (primaryRangeIsSingleRate)",
-                  to_string(ranking.front().frameRateMode.fps).c_str());
+            ALOGV("primaryRangeIsSingleRate");
             SFTRACE_FORMAT_INSTANT("%s (primaryRangeIsSingleRate)",
                                    to_string(ranking.front().frameRateMode.fps).c_str());
             return {ranking, kNoSignals};
@@ -1041,14 +1036,12 @@
 
         // Layers with ExplicitExactOrMultiple expect touch boost
         if (globalSignals.touch && hasExplicitExactOrMultiple) {
-            ALOGV("%s: Skipping for touch (input signal): uid=%d", __func__, uid);
             continue;
         }
 
         // Mirrors getRankedFrameRates. If there is no ExplicitDefault, expect touch boost and
         // skip frame rate override.
         if (hasHighHint && !hasExplicitDefault) {
-            ALOGV("%s: Skipping for touch (HighHint): uid=%d", __func__, uid);
             continue;
         }
 
@@ -1072,9 +1065,6 @@
                 constexpr bool isSeamlessSwitch = true;
                 const auto layerScore = calculateLayerScoreLocked(*layer, fps, isSeamlessSwitch);
                 score += layer->weight * layerScore;
-                ALOGV("%s: %s gives %s fps score of %.4f", __func__,
-                      formatLayerInfo(*layer, layer->weight).c_str(), to_string(fps).c_str(),
-                      layerScore);
             }
         }
 
@@ -1329,8 +1319,6 @@
     LOG_ALWAYS_FATAL_IF(!activeModeOpt);
     mActiveModeOpt = FrameRateMode{activeModeOpt->get()->getPeakFps(),
                                    ftl::as_non_null(activeModeOpt->get())};
-    mIsVrrDevice = FlagManager::getInstance().vrr_config() &&
-            activeModeOpt->get()->getVrrConfig().has_value();
 
     const auto sortedModes = sortByRefreshRate(mDisplayModes);
     mMinRefreshRateModeIt = sortedModes.front();
diff --git a/services/surfaceflinger/tests/unittests/RefreshRateSelectorTest.cpp b/services/surfaceflinger/tests/unittests/RefreshRateSelectorTest.cpp
index b5be8db..80b2b8d 100644
--- a/services/surfaceflinger/tests/unittests/RefreshRateSelectorTest.cpp
+++ b/services/surfaceflinger/tests/unittests/RefreshRateSelectorTest.cpp
@@ -308,42 +308,6 @@
                     << " category=" << ftl::enum_string(testCase.frameRateCategory);
         }
     }
-
-    template <class T>
-    std::vector<LayerRequirement> createLayers(const std::initializer_list<T>& surfaceVotes) {
-        std::vector<LayerRequirement> layers;
-        for (auto surfaceVote : surfaceVotes) {
-            ALOGI("**** %s: Adding layers for %s: (desiredFrameRate=%s, voteType=%s), "
-                  "(frameRateCategory=%s)",
-                  __func__, surfaceVote.name.c_str(),
-                  to_string(surfaceVote.desiredFrameRate).c_str(),
-                  ftl::enum_string(surfaceVote.voteType).c_str(),
-                  ftl::enum_string(surfaceVote.frameRateCategory).c_str());
-
-            if (surfaceVote.desiredFrameRate.isValid()) {
-                std::stringstream ss;
-                ss << surfaceVote.name << " (" << surfaceVote.weight << "): ExplicitDefault ("
-                   << to_string(surfaceVote.desiredFrameRate) << ")";
-                LayerRequirement layer = {.name = ss.str(),
-                                          .vote = surfaceVote.voteType,
-                                          .desiredRefreshRate = surfaceVote.desiredFrameRate,
-                                          .weight = surfaceVote.weight};
-                layers.push_back(layer);
-            }
-
-            if (surfaceVote.frameRateCategory != FrameRateCategory::Default) {
-                std::stringstream ss;
-                ss << surfaceVote.name << " (" << surfaceVote.weight << "): ExplicitCategory ("
-                   << ftl::enum_string(surfaceVote.frameRateCategory) << ")";
-                LayerRequirement layer = {.name = ss.str(),
-                                          .vote = LayerVoteType::ExplicitCategory,
-                                          .frameRateCategory = surfaceVote.frameRateCategory,
-                                          .weight = surfaceVote.weight};
-                layers.push_back(layer);
-            }
-        }
-        return layers;
-    }
 };
 
 RefreshRateSelectorTest::RefreshRateSelectorTest() {
@@ -1812,98 +1776,6 @@
             selector);
 }
 
-TEST_P(RefreshRateSelectorTest, getBestFrameRateMode_multiSurface_arr) {
-    if (GetParam() != Config::FrameRateOverride::Enabled) {
-        return;
-    }
-
-    SET_FLAG_FOR_TEST(flags::vrr_config, true);
-
-    auto selector = createSelector(kVrrMode_120, kModeId120);
-
-    // Switch the policy to be more like an ARR device (primary range is a single rate).
-    constexpr FpsRange k120_120Hz = {120_Hz, 120_Hz};
-    constexpr FpsRange k0_120Hz = {0_Hz, 120_Hz};
-    constexpr FpsRanges kPrimaryRanges = {/*physical*/ k120_120Hz,
-                                          /*render*/ k120_120Hz};
-    constexpr FpsRanges kAppRequestRanges = {/*physical*/ k120_120Hz,
-                                             /*render*/ k0_120Hz};
-    EXPECT_EQ(SetPolicyResult::Changed,
-              selector.setDisplayManagerPolicy(
-                      {/*defaultMode*/ kModeId120, kPrimaryRanges, kAppRequestRanges}));
-
-    // Surface can translate to multiple layers in SF  scheduler due to category and frame rate
-    // value.
-    struct SurfaceVote {
-        // Params
-        std::string name = "";
-        Fps desiredFrameRate = 0_Hz;
-        LayerVoteType voteType = LayerVoteType::ExplicitDefault;
-        FrameRateCategory frameRateCategory = FrameRateCategory::Default;
-        float weight = 1.f;
-    };
-
-    auto layers = createLayers(
-            std::initializer_list<SurfaceVote>{{.name = "60 fixed source",
-                                                .desiredFrameRate = 60_Hz,
-                                                .voteType = LayerVoteType::ExplicitExactOrMultiple,
-                                                .weight = 0.27f},
-                                               {.name = "1 fixed source + NoPreference",
-                                                .desiredFrameRate = 1_Hz,
-                                                .voteType = LayerVoteType::ExplicitExactOrMultiple,
-                                                .frameRateCategory =
-                                                        FrameRateCategory::NoPreference}});
-    auto actualRankedFrameRates = selector.getRankedFrameRates(layers);
-    EXPECT_EQ(60_Hz, actualRankedFrameRates.ranking.front().frameRateMode.fps);
-
-    layers = createLayers(
-            std::initializer_list<SurfaceVote>{{.name = "60 fixed source",
-                                                .desiredFrameRate = 60_Hz,
-                                                .voteType = LayerVoteType::ExplicitExactOrMultiple,
-                                                .weight = 0.27f},
-                                               {.name = "1 fixed source + Normal",
-                                                .desiredFrameRate = 1_Hz,
-                                                .voteType = LayerVoteType::ExplicitExactOrMultiple,
-                                                .frameRateCategory = FrameRateCategory::Normal}});
-    actualRankedFrameRates = selector.getRankedFrameRates(layers);
-    EXPECT_EQ(60_Hz, actualRankedFrameRates.ranking.front().frameRateMode.fps);
-
-    layers = createLayers(std::initializer_list<SurfaceVote>{
-            {.name = "30 fixed source + NoPreference",
-             .desiredFrameRate = 30_Hz,
-             .voteType = LayerVoteType::ExplicitExactOrMultiple,
-             .frameRateCategory = FrameRateCategory::NoPreference}});
-    actualRankedFrameRates = selector.getRankedFrameRates(layers);
-    EXPECT_EQ(30_Hz, actualRankedFrameRates.ranking.front().frameRateMode.fps);
-
-    layers = createLayers(std::initializer_list<SurfaceVote>{
-            {.name = "1 fixed source + NoPreference",
-             .desiredFrameRate = 1_Hz,
-             .voteType = LayerVoteType::ExplicitExactOrMultiple,
-             .frameRateCategory = FrameRateCategory::NoPreference}});
-    actualRankedFrameRates = selector.getRankedFrameRates(layers);
-    // Result affected by RefreshRateSelector.kMinSupportedFrameRate.
-    EXPECT_EQ(20_Hz, actualRankedFrameRates.ranking.front().frameRateMode.fps);
-
-    layers = createLayers(std::initializer_list<SurfaceVote>{
-            {.name = "24 fixed source + NoPreference",
-             .desiredFrameRate = 24_Hz,
-             .voteType = LayerVoteType::ExplicitExactOrMultiple,
-             .frameRateCategory = FrameRateCategory::NoPreference}});
-    actualRankedFrameRates = selector.getRankedFrameRates(layers);
-    EXPECT_EQ(24_Hz, actualRankedFrameRates.ranking.front().frameRateMode.fps);
-
-    layers = createLayers(std::initializer_list<SurfaceVote>{
-            {.name = "23.976 fixed source + NoPreference",
-             .desiredFrameRate = 23.976_Hz,
-             .voteType = LayerVoteType::ExplicitExactOrMultiple,
-             .frameRateCategory = FrameRateCategory::NoPreference}});
-    actualRankedFrameRates = selector.getRankedFrameRates(layers);
-    // Chooses 120 unless certain threshold is set, see tests test23976Chooses120 and
-    // test23976Chooses60IfThresholdIs120.
-    EXPECT_EQ(120_Hz, actualRankedFrameRates.ranking.front().frameRateMode.fps);
-}
-
 TEST_P(RefreshRateSelectorTest, getBestFrameRateMode_withFrameRateCategory_60_120) {
     auto selector = createSelector(makeModes(kMode60, kMode120), kModeId60);
 
diff --git a/vulkan/libvulkan/libvulkan_flags.aconfig b/vulkan/libvulkan/libvulkan_flags.aconfig
index 891bc02..dae5b52 100644
--- a/vulkan/libvulkan/libvulkan_flags.aconfig
+++ b/vulkan/libvulkan/libvulkan_flags.aconfig
@@ -8,3 +8,11 @@
   bug: "341978292"
   is_fixed_read_only: true
 }
+
+flag {
+  name: "vulkan_1_4_instance_api"
+  namespace: "core_graphics"
+  description: "Enable support for the Vulkan 1.4 instance API"
+  bug: "370568136"
+  is_fixed_read_only: true
+}