Mock InputDevice in the InputMapper unit tests

This makes the InputMapperUnitTest subclasses easier to test, as the
tests will not have to rely on the behavior of actual InputDevice
implementation.

Unfortunately, this means InputDevice must now be a virtual class to
allow its mocked subclass to define its behavior for the methods that we
want to change. In this CL, we take the approach of only marking the
methods that we need to customize as virtual to avoid the overhead of
vtable lookups at runtime.

An alternative approach would be to introduce a type parameter to
InputDeviceContext to allow us to specify a different InputDevice
implementation in the tests. This would eliminate any addtional runtime
overheads resulting from vtable lookups. However, this would mean every
InputMapper class would need to have this new type parameter, adding
verbosity and complextity to the codebase. For this reason, the virtual
member approach was preferred.

Bug: 354270482
Test: atest inputflinger_tests
Flag: EXEMPT refactor
Change-Id: Id7e103e1f04812c92ee8ecfdfe1e75a9949efa9e
diff --git a/services/inputflinger/reader/include/InputDevice.h b/services/inputflinger/reader/include/InputDevice.h
index 086c26f..5eb1acc 100644
--- a/services/inputflinger/reader/include/InputDevice.h
+++ b/services/inputflinger/reader/include/InputDevice.h
@@ -43,7 +43,7 @@
 public:
     InputDevice(InputReaderContext* context, int32_t id, int32_t generation,
                 const InputDeviceIdentifier& identifier);
-    ~InputDevice();
+    virtual ~InputDevice();
 
     inline InputReaderContext* getContext() { return mContext; }
     inline int32_t getId() const { return mId; }
@@ -56,7 +56,7 @@
     }
     inline const std::string getLocation() const { return mIdentifier.location; }
     inline ftl::Flags<InputDeviceClass> getClasses() const { return mClasses; }
-    inline uint32_t getSources() const { return mSources; }
+    inline virtual uint32_t getSources() const { return mSources; }
     inline bool hasEventHubDevices() const { return !mDevices.empty(); }
 
     inline bool isExternal() { return mIsExternal; }
@@ -132,7 +132,7 @@
 
     [[nodiscard]] NotifyDeviceResetArgs notifyReset(nsecs_t when);
 
-    inline const PropertyMap& getConfiguration() { return mConfiguration; }
+    inline virtual const PropertyMap& getConfiguration() const { return mConfiguration; }
     inline EventHubInterface* getEventHub() { return mContext->getEventHub(); }
 
     std::optional<ui::LogicalDisplayId> getAssociatedDisplayId();
diff --git a/services/inputflinger/tests/CursorInputMapper_test.cpp b/services/inputflinger/tests/CursorInputMapper_test.cpp
index 727237f..846eced 100644
--- a/services/inputflinger/tests/CursorInputMapper_test.cpp
+++ b/services/inputflinger/tests/CursorInputMapper_test.cpp
@@ -163,7 +163,6 @@
     }
 
     void createMapper() {
-        createDevice();
         mMapper = createInputMapper<CursorInputMapper>(*mDeviceContext, mReaderConfiguration);
     }
 
@@ -542,7 +541,6 @@
     // need to be rotated.
     mPropertyMap.addProperty("cursor.mode", "navigation");
     mPropertyMap.addProperty("cursor.orientationAware", "1");
-    createDevice();
     ViewportFakingInputDeviceContext deviceContext(*mDevice, EVENTHUB_ID, ui::Rotation::Rotation90);
     mMapper = createInputMapper<CursorInputMapper>(deviceContext, mReaderConfiguration);
 
@@ -560,7 +558,6 @@
     // Since InputReader works in the un-rotated coordinate space, only devices that are not
     // orientation-aware are affected by display rotation.
     mPropertyMap.addProperty("cursor.mode", "navigation");
-    createDevice();
     ViewportFakingInputDeviceContext deviceContext(*mDevice, EVENTHUB_ID, ui::Rotation::Rotation0);
     mMapper = createInputMapper<CursorInputMapper>(deviceContext, mReaderConfiguration);
 
@@ -652,7 +649,6 @@
     mReaderConfiguration.setDisplayViewports({primaryViewport, secondaryViewport});
     // Set up the secondary display as the display on which the pointer should be shown.
     // The InputDevice is not associated with any display.
-    createDevice();
     ViewportFakingInputDeviceContext deviceContext(*mDevice, EVENTHUB_ID, secondaryViewport);
     mMapper = createInputMapper<CursorInputMapper>(deviceContext, mReaderConfiguration);
 
@@ -673,7 +669,6 @@
     DisplayViewport secondaryViewport = createSecondaryViewport();
     mReaderConfiguration.setDisplayViewports({primaryViewport, secondaryViewport});
     // Set up the primary display as the display on which the pointer should be shown.
-    createDevice();
     // Associate the InputDevice with the secondary display.
     ViewportFakingInputDeviceContext deviceContext(*mDevice, EVENTHUB_ID, secondaryViewport);
     mMapper = createInputMapper<CursorInputMapper>(deviceContext, mReaderConfiguration);
@@ -1032,7 +1027,6 @@
     mPropertyMap.addProperty("cursor.mode", "pointer");
     DisplayViewport primaryViewport = createPrimaryViewport(ui::Rotation::Rotation0);
     mReaderConfiguration.setDisplayViewports({primaryViewport});
-    createDevice();
     ViewportFakingInputDeviceContext deviceContext(*mDevice, EVENTHUB_ID, primaryViewport);
     mMapper = createInputMapper<CursorInputMapper>(deviceContext, mReaderConfiguration);
 
@@ -1070,7 +1064,6 @@
     mReaderConfiguration.setDisplayViewports({primaryViewport});
     // Disable acceleration for the display.
     mReaderConfiguration.displaysWithMousePointerAccelerationDisabled.emplace(DISPLAY_ID);
-    createDevice();
 
     // Don't associate the device with the display yet.
     ViewportFakingInputDeviceContext deviceContext(*mDevice, EVENTHUB_ID,
diff --git a/services/inputflinger/tests/InputMapperTest.cpp b/services/inputflinger/tests/InputMapperTest.cpp
index 7e96d5f..af1f377 100644
--- a/services/inputflinger/tests/InputMapperTest.cpp
+++ b/services/inputflinger/tests/InputMapperTest.cpp
@@ -26,7 +26,9 @@
 namespace android {
 
 using testing::_;
+using testing::NiceMock;
 using testing::Return;
+using testing::ReturnRef;
 
 void InputMapperUnitTest::SetUpWithBus(int bus) {
     mFakePolicy = sp<FakeInputReaderPolicy>::make();
@@ -43,16 +45,11 @@
     EXPECT_CALL(mMockEventHub, getConfiguration(EVENTHUB_ID)).WillRepeatedly([&](int32_t) {
         return mPropertyMap;
     });
-}
 
-void InputMapperUnitTest::createDevice() {
-    mDevice = std::make_unique<InputDevice>(&mMockInputReaderContext, DEVICE_ID,
-                                            /*generation=*/2, mIdentifier);
-    mDevice->addEmptyEventHubDevice(EVENTHUB_ID);
+    mDevice = std::make_unique<NiceMock<MockInputDevice>>(&mMockInputReaderContext, DEVICE_ID,
+                                                          /*generation=*/2, mIdentifier);
+    ON_CALL((*mDevice), getConfiguration).WillByDefault(ReturnRef(mPropertyMap));
     mDeviceContext = std::make_unique<InputDeviceContext>(*mDevice, EVENTHUB_ID);
-    std::list<NotifyArgs> args =
-            mDevice->configure(systemTime(), mReaderConfiguration, /*changes=*/{});
-    ASSERT_THAT(args, testing::ElementsAre(testing::VariantWith<NotifyDeviceResetArgs>(_)));
 }
 
 void InputMapperUnitTest::setupAxis(int axis, bool valid, int32_t min, int32_t max,
diff --git a/services/inputflinger/tests/InputMapperTest.h b/services/inputflinger/tests/InputMapperTest.h
index 88057dc..9353f8c 100644
--- a/services/inputflinger/tests/InputMapperTest.h
+++ b/services/inputflinger/tests/InputMapperTest.h
@@ -43,13 +43,6 @@
     virtual void SetUp() override { SetUpWithBus(0); }
     virtual void SetUpWithBus(int bus);
 
-    /**
-     * Initializes mDevice and mDeviceContext. When this happens, mDevice takes a copy of
-     * mPropertyMap, so tests that need to set configuration properties should do so before calling
-     * this. Others will most likely want to call it in their SetUp method.
-     */
-    void createDevice();
-
     void setupAxis(int axis, bool valid, int32_t min, int32_t max, int32_t resolution);
 
     void expectScanCodes(bool present, std::set<int> scanCodes);
@@ -67,7 +60,7 @@
     MockEventHubInterface mMockEventHub;
     sp<FakeInputReaderPolicy> mFakePolicy;
     MockInputReaderContext mMockInputReaderContext;
-    std::unique_ptr<InputDevice> mDevice;
+    std::unique_ptr<MockInputDevice> mDevice;
 
     std::unique_ptr<InputDeviceContext> mDeviceContext;
     InputReaderConfiguration mReaderConfiguration;
diff --git a/services/inputflinger/tests/InterfaceMocks.h b/services/inputflinger/tests/InterfaceMocks.h
index 48e0b4f..d51c708 100644
--- a/services/inputflinger/tests/InterfaceMocks.h
+++ b/services/inputflinger/tests/InterfaceMocks.h
@@ -26,6 +26,7 @@
 #include <vector>
 
 #include <EventHub.h>
+#include <InputDevice.h>
 #include <InputReaderBase.h>
 #include <InputReaderContext.h>
 #include <NotifyArgs.h>
@@ -59,7 +60,7 @@
     MOCK_METHOD(void, requestTimeoutAtTime, (nsecs_t when), (override));
     int32_t bumpGeneration() override { return ++mGeneration; }
 
-    MOCK_METHOD(void, getExternalStylusDevices, (std::vector<InputDeviceInfo> & outDevices),
+    MOCK_METHOD(void, getExternalStylusDevices, (std::vector<InputDeviceInfo>& outDevices),
                 (override));
     MOCK_METHOD(std::list<NotifyArgs>, dispatchExternalStylusState, (const StylusState& outState),
                 (override));
@@ -172,7 +173,7 @@
     MOCK_METHOD(void, requestReopenDevices, (), (override));
     MOCK_METHOD(void, wake, (), (override));
 
-    MOCK_METHOD(void, dump, (std::string & dump), (const, override));
+    MOCK_METHOD(void, dump, (std::string& dump), (const, override));
     MOCK_METHOD(void, monitor, (), (const, override));
     MOCK_METHOD(bool, isDeviceEnabled, (int32_t deviceId), (const, override));
     MOCK_METHOD(status_t, enableDevice, (int32_t deviceId), (override));
@@ -190,4 +191,75 @@
     MOCK_METHOD(void, notifyMouseCursorFadedOnTyping, (), (override));
 };
 
+class MockInputDevice : public InputDevice {
+public:
+    MockInputDevice(InputReaderContext* context, int32_t id, int32_t generation,
+                    const InputDeviceIdentifier& identifier)
+          : InputDevice(context, id, generation, identifier) {}
+
+    MOCK_METHOD(uint32_t, getSources, (), (const, override));
+    MOCK_METHOD(bool, isEnabled, (), ());
+
+    MOCK_METHOD(void, dump, (std::string& dump, const std::string& eventHubDevStr), ());
+    MOCK_METHOD(void, addEmptyEventHubDevice, (int32_t eventHubId), ());
+    MOCK_METHOD(std::list<NotifyArgs>, addEventHubDevice,
+                (nsecs_t when, int32_t eventHubId, const InputReaderConfiguration& readerConfig),
+                ());
+    MOCK_METHOD(void, removeEventHubDevice, (int32_t eventHubId), ());
+    MOCK_METHOD(std::list<NotifyArgs>, configure,
+                (nsecs_t when, const InputReaderConfiguration& readerConfig,
+                 ConfigurationChanges changes),
+                ());
+    MOCK_METHOD(std::list<NotifyArgs>, reset, (nsecs_t when), ());
+    MOCK_METHOD(std::list<NotifyArgs>, process, (const RawEvent* rawEvents, size_t count), ());
+    MOCK_METHOD(std::list<NotifyArgs>, timeoutExpired, (nsecs_t when), ());
+    MOCK_METHOD(std::list<NotifyArgs>, updateExternalStylusState, (const StylusState& state), ());
+
+    MOCK_METHOD(InputDeviceInfo, getDeviceInfo, (), ());
+    MOCK_METHOD(int32_t, getKeyCodeState, (uint32_t sourceMask, int32_t keyCode), ());
+    MOCK_METHOD(int32_t, getScanCodeState, (uint32_t sourceMask, int32_t scanCode), ());
+    MOCK_METHOD(int32_t, getSwitchState, (uint32_t sourceMask, int32_t switchCode), ());
+    MOCK_METHOD(int32_t, getKeyCodeForKeyLocation, (int32_t locationKeyCode), (const));
+    MOCK_METHOD(bool, markSupportedKeyCodes,
+                (uint32_t sourceMask, const std::vector<int32_t>& keyCodes, uint8_t* outFlags), ());
+    MOCK_METHOD(std::list<NotifyArgs>, vibrate,
+                (const VibrationSequence& sequence, ssize_t repeat, int32_t token), ());
+    MOCK_METHOD(std::list<NotifyArgs>, cancelVibrate, (int32_t token), ());
+    MOCK_METHOD(bool, isVibrating, (), ());
+    MOCK_METHOD(std::vector<int32_t>, getVibratorIds, (), ());
+    MOCK_METHOD(std::list<NotifyArgs>, cancelTouch, (nsecs_t when, nsecs_t readTime), ());
+    MOCK_METHOD(bool, enableSensor,
+                (InputDeviceSensorType sensorType, std::chrono::microseconds samplingPeriod,
+                 std::chrono::microseconds maxBatchReportLatency),
+                ());
+
+    MOCK_METHOD(void, disableSensor, (InputDeviceSensorType sensorType), ());
+    MOCK_METHOD(void, flushSensor, (InputDeviceSensorType sensorType), ());
+
+    MOCK_METHOD(std::optional<int32_t>, getBatteryEventHubId, (), (const));
+
+    MOCK_METHOD(bool, setLightColor, (int32_t lightId, int32_t color), ());
+    MOCK_METHOD(bool, setLightPlayerId, (int32_t lightId, int32_t playerId), ());
+    MOCK_METHOD(std::optional<int32_t>, getLightColor, (int32_t lightId), ());
+    MOCK_METHOD(std::optional<int32_t>, getLightPlayerId, (int32_t lightId), ());
+
+    MOCK_METHOD(int32_t, getMetaState, (), ());
+    MOCK_METHOD(void, updateMetaState, (int32_t keyCode), ());
+
+    MOCK_METHOD(void, addKeyRemapping, (int32_t fromKeyCode, int32_t toKeyCode), ());
+
+    MOCK_METHOD(void, setKeyboardType, (KeyboardType keyboardType), ());
+
+    MOCK_METHOD(void, bumpGeneration, (), ());
+
+    MOCK_METHOD(const PropertyMap&, getConfiguration, (), (const, override));
+
+    MOCK_METHOD(NotifyDeviceResetArgs, notifyReset, (nsecs_t when), ());
+
+    MOCK_METHOD(std::optional<ui::LogicalDisplayId>, getAssociatedDisplayId, (), ());
+
+    MOCK_METHOD(void, updateLedState, (bool reset), ());
+
+    MOCK_METHOD(size_t, getMapperCount, (), ());
+};
 } // namespace android
diff --git a/services/inputflinger/tests/KeyboardInputMapper_test.cpp b/services/inputflinger/tests/KeyboardInputMapper_test.cpp
index d3e8dee..aa71e07 100644
--- a/services/inputflinger/tests/KeyboardInputMapper_test.cpp
+++ b/services/inputflinger/tests/KeyboardInputMapper_test.cpp
@@ -55,7 +55,6 @@
 
     void SetUp() override {
         InputMapperUnitTest::SetUp();
-        createDevice();
 
         // set key-codes expected in tests
         for (const auto& [scanCode, outKeycode] : mKeyCodeMap) {
diff --git a/services/inputflinger/tests/MultiTouchInputMapper_test.cpp b/services/inputflinger/tests/MultiTouchInputMapper_test.cpp
index d4d3c38..9a6b266 100644
--- a/services/inputflinger/tests/MultiTouchInputMapper_test.cpp
+++ b/services/inputflinger/tests/MultiTouchInputMapper_test.cpp
@@ -109,7 +109,6 @@
         mFakePolicy->addDisplayViewport(DISPLAY_ID, DISPLAY_WIDTH, DISPLAY_HEIGHT, ui::ROTATION_0,
                                         /*isActive=*/true, "local:0", NO_PORT,
                                         ViewportType::INTERNAL);
-        createDevice();
         mMapper = createInputMapper<MultiTouchInputMapper>(*mDeviceContext,
                                                            mFakePolicy->getReaderConfiguration());
     }
diff --git a/services/inputflinger/tests/MultiTouchMotionAccumulator_test.cpp b/services/inputflinger/tests/MultiTouchMotionAccumulator_test.cpp
index b441a23..9ddb8c1 100644
--- a/services/inputflinger/tests/MultiTouchMotionAccumulator_test.cpp
+++ b/services/inputflinger/tests/MultiTouchMotionAccumulator_test.cpp
@@ -23,10 +23,7 @@
 protected:
     static constexpr size_t SLOT_COUNT = 8;
 
-    void SetUp() override {
-        InputMapperUnitTest::SetUp();
-        createDevice();
-    }
+    void SetUp() override { InputMapperUnitTest::SetUp(); }
 
     MultiTouchMotionAccumulator mMotionAccumulator;
 
diff --git a/services/inputflinger/tests/RotaryEncoderInputMapper_test.cpp b/services/inputflinger/tests/RotaryEncoderInputMapper_test.cpp
index 366b3dc..a796c49 100644
--- a/services/inputflinger/tests/RotaryEncoderInputMapper_test.cpp
+++ b/services/inputflinger/tests/RotaryEncoderInputMapper_test.cpp
@@ -138,7 +138,6 @@
     mReaderConfiguration.setDisplayViewports({primaryViewport, secondaryViewport});
 
     // Set up the secondary display as the associated viewport of the mapper.
-    createDevice();
     ViewportFakingInputDeviceContext deviceContext(*mDevice, EVENTHUB_ID, secondaryViewport);
     mMapper = createInputMapper<RotaryEncoderInputMapper>(deviceContext, mReaderConfiguration);
 
@@ -159,7 +158,6 @@
     mFakePolicy->addDisplayViewport(createPrimaryViewport());
 
     // Set up the mapper with no associated viewport.
-    createDevice();
     mMapper = createInputMapper<RotaryEncoderInputMapper>(*mDeviceContext, mReaderConfiguration);
 
     // Ensure input events are generated without display ID
@@ -174,7 +172,6 @@
 }
 
 TEST_F(RotaryEncoderInputMapperTest, ProcessRegularScroll) {
-    createDevice();
     mMapper = createInputMapper<RotaryEncoderInputMapper>(*mDeviceContext, mReaderConfiguration);
 
     std::list<NotifyArgs> args;
@@ -191,7 +188,6 @@
     vd_flags::high_resolution_scroll(true);
     EXPECT_CALL(mMockEventHub, hasRelativeAxis(EVENTHUB_ID, REL_WHEEL_HI_RES))
             .WillRepeatedly(Return(true));
-    createDevice();
     mMapper = createInputMapper<RotaryEncoderInputMapper>(*mDeviceContext, mReaderConfiguration);
 
     std::list<NotifyArgs> args;
@@ -208,7 +204,6 @@
     vd_flags::high_resolution_scroll(true);
     EXPECT_CALL(mMockEventHub, hasRelativeAxis(EVENTHUB_ID, REL_WHEEL_HI_RES))
             .WillRepeatedly(Return(true));
-    createDevice();
     mMapper = createInputMapper<RotaryEncoderInputMapper>(*mDeviceContext, mReaderConfiguration);
 
     std::list<NotifyArgs> args;
diff --git a/services/inputflinger/tests/SwitchInputMapper_test.cpp b/services/inputflinger/tests/SwitchInputMapper_test.cpp
index 4020e78..ebbf10b 100644
--- a/services/inputflinger/tests/SwitchInputMapper_test.cpp
+++ b/services/inputflinger/tests/SwitchInputMapper_test.cpp
@@ -33,7 +33,6 @@
 protected:
     void SetUp() override {
         InputMapperUnitTest::SetUp();
-        createDevice();
         mMapper = createInputMapper<SwitchInputMapper>(*mDeviceContext,
                                                        mFakePolicy->getReaderConfiguration());
     }
diff --git a/services/inputflinger/tests/TouchpadInputMapper_test.cpp b/services/inputflinger/tests/TouchpadInputMapper_test.cpp
index 1afb4f0..fc8a7da 100644
--- a/services/inputflinger/tests/TouchpadInputMapper_test.cpp
+++ b/services/inputflinger/tests/TouchpadInputMapper_test.cpp
@@ -109,7 +109,6 @@
                 .WillRepeatedly([]() -> base::Result<std::vector<int32_t>> {
                     return base::ResultError("Axis not supported", NAME_NOT_FOUND);
                 });
-        createDevice();
         mMapper = createInputMapper<TouchpadInputMapper>(*mDeviceContext, mReaderConfiguration);
     }
 };
diff --git a/services/inputflinger/tests/VibratorInputMapper_test.cpp b/services/inputflinger/tests/VibratorInputMapper_test.cpp
index aa4a6bb..6e3344c 100644
--- a/services/inputflinger/tests/VibratorInputMapper_test.cpp
+++ b/services/inputflinger/tests/VibratorInputMapper_test.cpp
@@ -36,7 +36,6 @@
 protected:
     void SetUp() override {
         InputMapperUnitTest::SetUp();
-        createDevice();
         EXPECT_CALL(mMockEventHub, getDeviceClasses(EVENTHUB_ID))
                 .WillRepeatedly(testing::Return(InputDeviceClass::VIBRATOR));
         EXPECT_CALL(mMockEventHub, getVibratorIds(EVENTHUB_ID))