From c04d04de31c346c1ccfa9f94fed715c07ac42986 Mon Sep 17 00:00:00 2001 From: Prabir Pradhan Date: Thu, 8 Sep 2022 22:03:30 +0000 Subject: Resolve associated display and pointer display in CursorInputMapper An InputDevice can be associated with a display, in which case it should only generate events for that display. A mouse generally generates events for whichever display is currently showing the mouse cursor. In the case where a mouse InputDevice is associated with a display, we need to make sure that it only generates events when the mouse cursor is on the associated display. Additionally, any display-dependent configuration, such as orientation, should depend on whichever display the device is configured for. Bug: 236075874 Test: atest inputflinger_tests Change-Id: I1021c121c1eae768585124d312f5187be90da666 Merged-In: I1021c121c1eae768585124d312f5187be90da666 (cherry picked from commit c13ff081db31e93ee3b0a96bb007704c61d10a02) --- include/input/PrintTools.h | 10 ++ .../reader/mapper/CursorInputMapper.cpp | 60 ++++++----- .../inputflinger/reader/mapper/CursorInputMapper.h | 4 + services/inputflinger/tests/InputReader_test.cpp | 115 +++++++++++++++++---- 4 files changed, 142 insertions(+), 47 deletions(-) diff --git a/include/input/PrintTools.h b/include/input/PrintTools.h index 0a75278494..55f730b287 100644 --- a/include/input/PrintTools.h +++ b/include/input/PrintTools.h @@ -17,6 +17,7 @@ #pragma once #include +#include #include #include @@ -27,6 +28,15 @@ std::string constToString(const T& v) { return std::to_string(v); } +/** + * Convert an optional type to string. + */ +template +std::string toString(const std::optional& optional, + std::string (*toString)(const T&) = constToString) { + return optional ? toString(*optional) : ""; +} + /** * Convert a set of integral types to string. */ diff --git a/services/inputflinger/reader/mapper/CursorInputMapper.cpp b/services/inputflinger/reader/mapper/CursorInputMapper.cpp index 91dc61923b..8233682a32 100644 --- a/services/inputflinger/reader/mapper/CursorInputMapper.cpp +++ b/services/inputflinger/reader/mapper/CursorInputMapper.cpp @@ -25,6 +25,8 @@ #include "PointerControllerInterface.h" #include "TouchCursorInputMapperCommon.h" +#include "input/PrintTools.h" + namespace android { // The default velocity control parameters that has no effect. @@ -113,6 +115,7 @@ void CursorInputMapper::dump(std::string& dump) { toString(mCursorScrollAccumulator.haveRelativeHWheel())); dump += StringPrintf(INDENT3 "VWheelScale: %0.3f\n", mVWheelScale); dump += StringPrintf(INDENT3 "HWheelScale: %0.3f\n", mHWheelScale); + dump += StringPrintf(INDENT3 "DisplayId: %s\n", toString(mDisplayId).c_str()); dump += StringPrintf(INDENT3 "Orientation: %d\n", mOrientation); dump += StringPrintf(INDENT3 "ButtonState: 0x%08x\n", mButtonState); dump += StringPrintf(INDENT3 "Down: %s\n", toString(isPointerDown(mButtonState))); @@ -201,21 +204,34 @@ void CursorInputMapper::configure(nsecs_t when, const InputReaderConfiguration* if (!changes || (changes & InputReaderConfiguration::CHANGE_DISPLAY_INFO) || configurePointerCapture) { + const bool isPointer = mParameters.mode == Parameters::Mode::POINTER; + + mDisplayId = ADISPLAY_ID_NONE; + if (auto viewport = mDeviceContext.getAssociatedViewport(); viewport) { + // This InputDevice is associated with a viewport. + // Only generate events for the associated display. + const bool mismatchedPointerDisplay = + isPointer && (viewport->displayId != mPointerController->getDisplayId()); + mDisplayId = mismatchedPointerDisplay ? std::nullopt + : std::make_optional(viewport->displayId); + } else if (isPointer) { + // The InputDevice is not associated with a viewport, but it controls the mouse pointer. + mDisplayId = mPointerController->getDisplayId(); + } + mOrientation = DISPLAY_ORIENTATION_0; const bool isOrientedDevice = (mParameters.orientationAware && mParameters.hasAssociatedDisplay); - // InputReader works in the un-rotated display coordinate space, so we don't need to do // anything if the device is already orientation-aware. If the device is not // orientation-aware, then we need to apply the inverse rotation of the display so that // when the display rotation is applied later as a part of the per-window transform, we // get the expected screen coordinates. When pointer capture is enabled, we do not apply any // rotations and report values directly from the input device. - if (!isOrientedDevice && mParameters.mode != Parameters::Mode::POINTER_RELATIVE) { - std::optional internalViewport = - config->getDisplayViewportByType(ViewportType::INTERNAL); - if (internalViewport) { - mOrientation = getInverseRotation(internalViewport->orientation); + if (!isOrientedDevice && mDisplayId && + mParameters.mode != Parameters::Mode::POINTER_RELATIVE) { + if (auto viewport = config->getDisplayViewportById(*mDisplayId); viewport) { + mOrientation = getInverseRotation(viewport->orientation); } } @@ -279,6 +295,11 @@ void CursorInputMapper::process(const RawEvent* rawEvent) { } void CursorInputMapper::sync(nsecs_t when, nsecs_t readTime) { + if (!mDisplayId) { + // Ignore events when there is no target display configured. + return; + } + int32_t lastButtonState = mButtonState; int32_t currentButtonState = mCursorButtonAccumulator.getButtonState(); mButtonState = currentButtonState; @@ -324,7 +345,6 @@ void CursorInputMapper::sync(nsecs_t when, nsecs_t readTime) { mPointerVelocityControl.move(when, &deltaX, &deltaY); - int32_t displayId = ADISPLAY_ID_NONE; float xCursorPosition = AMOTION_EVENT_INVALID_CURSOR_POSITION; float yCursorPosition = AMOTION_EVENT_INVALID_CURSOR_POSITION; if (mSource == AINPUT_SOURCE_MOUSE) { @@ -348,7 +368,6 @@ void CursorInputMapper::sync(nsecs_t when, nsecs_t readTime) { pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_Y, yCursorPosition); pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_RELATIVE_X, deltaX); pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_RELATIVE_Y, deltaY); - displayId = mPointerController->getDisplayId(); } else { // Pointer capture and navigation modes pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_X, deltaX); @@ -370,7 +389,7 @@ void CursorInputMapper::sync(nsecs_t when, nsecs_t readTime) { // Synthesize key down from buttons if needed. synthesizeButtonKeys(getContext(), AKEY_EVENT_ACTION_DOWN, when, readTime, getDeviceId(), - mSource, displayId, policyFlags, lastButtonState, currentButtonState); + mSource, *mDisplayId, policyFlags, lastButtonState, currentButtonState); // Send motion event. if (downChanged || moved || scrolled || buttonsChanged) { @@ -391,7 +410,7 @@ void CursorInputMapper::sync(nsecs_t when, nsecs_t readTime) { int32_t actionButton = BitSet32::valueForBit(released.clearFirstMarkedBit()); buttonState &= ~actionButton; NotifyMotionArgs releaseArgs(getContext()->getNextId(), when, readTime, - getDeviceId(), mSource, displayId, policyFlags, + getDeviceId(), mSource, *mDisplayId, policyFlags, AMOTION_EVENT_ACTION_BUTTON_RELEASE, actionButton, 0, metaState, buttonState, MotionClassification::NONE, AMOTION_EVENT_EDGE_FLAG_NONE, 1, &pointerProperties, @@ -403,7 +422,7 @@ void CursorInputMapper::sync(nsecs_t when, nsecs_t readTime) { } NotifyMotionArgs args(getContext()->getNextId(), when, readTime, getDeviceId(), mSource, - displayId, policyFlags, motionEventAction, 0, 0, metaState, + *mDisplayId, policyFlags, motionEventAction, 0, 0, metaState, currentButtonState, MotionClassification::NONE, AMOTION_EVENT_EDGE_FLAG_NONE, 1, &pointerProperties, &pointerCoords, mXPrecision, mYPrecision, xCursorPosition, yCursorPosition, downTime, @@ -416,7 +435,7 @@ void CursorInputMapper::sync(nsecs_t when, nsecs_t readTime) { int32_t actionButton = BitSet32::valueForBit(pressed.clearFirstMarkedBit()); buttonState |= actionButton; NotifyMotionArgs pressArgs(getContext()->getNextId(), when, readTime, getDeviceId(), - mSource, displayId, policyFlags, + mSource, *mDisplayId, policyFlags, AMOTION_EVENT_ACTION_BUTTON_PRESS, actionButton, 0, metaState, buttonState, MotionClassification::NONE, AMOTION_EVENT_EDGE_FLAG_NONE, 1, &pointerProperties, @@ -432,7 +451,7 @@ void CursorInputMapper::sync(nsecs_t when, nsecs_t readTime) { // Send hover move after UP to tell the application that the mouse is hovering now. if (motionEventAction == AMOTION_EVENT_ACTION_UP && (mSource == AINPUT_SOURCE_MOUSE)) { NotifyMotionArgs hoverArgs(getContext()->getNextId(), when, readTime, getDeviceId(), - mSource, displayId, policyFlags, + mSource, *mDisplayId, policyFlags, AMOTION_EVENT_ACTION_HOVER_MOVE, 0, 0, metaState, currentButtonState, MotionClassification::NONE, AMOTION_EVENT_EDGE_FLAG_NONE, 1, &pointerProperties, @@ -447,7 +466,7 @@ void CursorInputMapper::sync(nsecs_t when, nsecs_t readTime) { pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_HSCROLL, hscroll); NotifyMotionArgs scrollArgs(getContext()->getNextId(), when, readTime, getDeviceId(), - mSource, displayId, policyFlags, + mSource, *mDisplayId, policyFlags, AMOTION_EVENT_ACTION_SCROLL, 0, 0, metaState, currentButtonState, MotionClassification::NONE, AMOTION_EVENT_EDGE_FLAG_NONE, 1, &pointerProperties, @@ -459,7 +478,7 @@ void CursorInputMapper::sync(nsecs_t when, nsecs_t readTime) { // Synthesize key up from buttons if needed. synthesizeButtonKeys(getContext(), AKEY_EVENT_ACTION_UP, when, readTime, getDeviceId(), mSource, - displayId, policyFlags, lastButtonState, currentButtonState); + *mDisplayId, policyFlags, lastButtonState, currentButtonState); mCursorMotionAccumulator.finishSync(); mCursorScrollAccumulator.finishSync(); @@ -474,16 +493,7 @@ int32_t CursorInputMapper::getScanCodeState(uint32_t sourceMask, int32_t scanCod } std::optional CursorInputMapper::getAssociatedDisplayId() { - if (mParameters.hasAssociatedDisplay) { - if (mParameters.mode == Parameters::Mode::POINTER) { - return std::make_optional(mPointerController->getDisplayId()); - } else { - // If the device is orientationAware and not a mouse, - // it expects to dispatch events to any display - return std::make_optional(ADISPLAY_ID_NONE); - } - } - return std::nullopt; + return mDisplayId; } } // namespace android diff --git a/services/inputflinger/reader/mapper/CursorInputMapper.h b/services/inputflinger/reader/mapper/CursorInputMapper.h index 75aeffb846..60b3dd9ee0 100644 --- a/services/inputflinger/reader/mapper/CursorInputMapper.h +++ b/services/inputflinger/reader/mapper/CursorInputMapper.h @@ -111,6 +111,10 @@ private: VelocityControl mWheelXVelocityControl; VelocityControl mWheelYVelocityControl; + // The display that events generated by this mapper should target. This can be set to + // ADISPLAY_ID_NONE to target the focused display. If there is no display target (i.e. + // std::nullopt), all events will be ignored. + std::optional mDisplayId; int32_t mOrientation; std::shared_ptr mPointerController; diff --git a/services/inputflinger/tests/InputReader_test.cpp b/services/inputflinger/tests/InputReader_test.cpp index 75b8dd1953..e1befedcff 100644 --- a/services/inputflinger/tests/InputReader_test.cpp +++ b/services/inputflinger/tests/InputReader_test.cpp @@ -56,7 +56,9 @@ static constexpr nsecs_t READ_TIME = 4321; // Arbitrary display properties. static constexpr int32_t DISPLAY_ID = 0; +static const std::string DISPLAY_UNIQUE_ID = "local:1"; static constexpr int32_t SECONDARY_DISPLAY_ID = DISPLAY_ID + 1; +static const std::string SECONDARY_DISPLAY_UNIQUE_ID = "local:2"; static constexpr int32_t DISPLAY_WIDTH = 480; static constexpr int32_t DISPLAY_HEIGHT = 800; static constexpr int32_t VIRTUAL_DISPLAY_ID = 1; @@ -91,6 +93,24 @@ static constexpr int32_t ACTION_POINTER_1_UP = // Error tolerance for floating point assertions. static const float EPSILON = 0.001f; +using ::testing::AllOf; + +MATCHER_P(WithAction, action, "InputEvent with specified action") { + return arg.action == action; +} + +MATCHER_P(WithSource, source, "InputEvent with specified source") { + return arg.source == source; +} + +MATCHER_P(WithDisplayId, displayId, "InputEvent with specified displayId") { + return arg.displayId == displayId; +} + +MATCHER_P2(WithCoords, x, y, "MotionEvent with specified action") { + return arg.pointerCoords[0].getX() == x && arg.pointerCoords[0].getY(); +} + template static inline T min(T a, T b) { return a < b ? a : b; @@ -2872,7 +2892,6 @@ TEST_F(InputDeviceTest, Configure_AssignsDisplayUniqueId) { // Device should be disabled because it is associated with a specific display, but the // corresponding display is not found. - const std::string DISPLAY_UNIQUE_ID = "displayUniqueId"; mFakePolicy->addInputUniqueIdAssociation(DEVICE_LOCATION, DISPLAY_UNIQUE_ID); mDevice->configure(ARBITRARY_TIME, mFakePolicy->getReaderConfiguration(), InputReaderConfiguration::CHANGE_DISPLAY_INFO); @@ -2903,7 +2922,6 @@ TEST_F(InputDeviceTest, Configure_UniqueId_CorrectlyMatches) { mDevice->addMapper(EVENTHUB_ID, AINPUT_SOURCE_KEYBOARD); mDevice->configure(ARBITRARY_TIME, mFakePolicy->getReaderConfiguration(), 0); - const std::string DISPLAY_UNIQUE_ID = "displayUniqueId"; mFakePolicy->addInputUniqueIdAssociation(DEVICE_LOCATION, DISPLAY_UNIQUE_ID); mFakePolicy->addDisplayViewport(SECONDARY_DISPLAY_ID, DISPLAY_WIDTH, DISPLAY_HEIGHT, DISPLAY_ORIENTATION_0, /* isActive= */ true, DISPLAY_UNIQUE_ID, @@ -4188,10 +4206,14 @@ protected: int32_t rotatedX, int32_t rotatedY); void prepareDisplay(int32_t orientation) { - const std::string uniqueId = "local:0"; - const ViewportType viewportType = ViewportType::INTERNAL; - setDisplayInfoAndReconfigure(DISPLAY_ID, DISPLAY_WIDTH, DISPLAY_HEIGHT, - orientation, uniqueId, NO_PORT, viewportType); + setDisplayInfoAndReconfigure(DISPLAY_ID, DISPLAY_WIDTH, DISPLAY_HEIGHT, orientation, + DISPLAY_UNIQUE_ID, NO_PORT, ViewportType::INTERNAL); + } + + void prepareSecondaryDisplay() { + setDisplayInfoAndReconfigure(SECONDARY_DISPLAY_ID, DISPLAY_WIDTH, DISPLAY_HEIGHT, + DISPLAY_ORIENTATION_0, SECONDARY_DISPLAY_UNIQUE_ID, NO_PORT, + ViewportType::EXTERNAL); } static void assertCursorPointerCoords(const PointerCoords& coords, float x, float y, @@ -4468,6 +4490,7 @@ TEST_F(CursorInputMapperTest, Process_ShouldHandleCombinedXYAndButtonUpdates) { } TEST_F(CursorInputMapperTest, Process_WhenOrientationAware_ShouldNotRotateMotions) { + mFakePolicy->addInputUniqueIdAssociation(DEVICE_LOCATION, DISPLAY_UNIQUE_ID); addConfigurationProperty("cursor.mode", "navigation"); // InputReader works in the un-rotated coordinate space, so orientation-aware devices do not // need to be rotated. @@ -4486,11 +4509,13 @@ TEST_F(CursorInputMapperTest, Process_WhenOrientationAware_ShouldNotRotateMotion } TEST_F(CursorInputMapperTest, Process_WhenNotOrientationAware_ShouldRotateMotions) { + mFakePolicy->addInputUniqueIdAssociation(DEVICE_LOCATION, DISPLAY_UNIQUE_ID); addConfigurationProperty("cursor.mode", "navigation"); // Since InputReader works in the un-rotated coordinate space, only devices that are not // orientation-aware are affected by display rotation. CursorInputMapper& mapper = addMapperAndConfigure(); + clearViewports(); prepareDisplay(DISPLAY_ORIENTATION_0); ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, 0, 1, 0, 1)); ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, 1, 1, 1, 1)); @@ -4501,6 +4526,7 @@ TEST_F(CursorInputMapperTest, Process_WhenNotOrientationAware_ShouldRotateMotion ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, -1, 0, -1, 0)); ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, -1, 1, -1, 1)); + clearViewports(); prepareDisplay(DISPLAY_ORIENTATION_90); ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, 0, 1, -1, 0)); ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, 1, 1, -1, 1)); @@ -4511,6 +4537,7 @@ TEST_F(CursorInputMapperTest, Process_WhenNotOrientationAware_ShouldRotateMotion ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, -1, 0, 0, -1)); ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, -1, 1, -1, -1)); + clearViewports(); prepareDisplay(DISPLAY_ORIENTATION_180); ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, 0, 1, 0, -1)); ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, 1, 1, -1, -1)); @@ -4521,6 +4548,7 @@ TEST_F(CursorInputMapperTest, Process_WhenNotOrientationAware_ShouldRotateMotion ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, -1, 0, 1, 0)); ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, -1, 1, 1, -1)); + clearViewports(); prepareDisplay(DISPLAY_ORIENTATION_270); ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, 0, 1, 1, 0)); ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, 1, 1, 1, -1)); @@ -5017,33 +5045,76 @@ TEST_F(CursorInputMapperTest, PointerCaptureDisablesOrientationChanges) { ASSERT_EQ(20, args.pointerCoords[0].getY()); } -TEST_F(CursorInputMapperTest, Process_ShouldHandleDisplayId) { +TEST_F(CursorInputMapperTest, ConfigureDisplayId_NoAssociatedViewport) { CursorInputMapper& mapper = addMapperAndConfigure(); - // Setup for second display. - constexpr int32_t SECOND_DISPLAY_ID = 1; - const std::string SECOND_DISPLAY_UNIQUE_ID = "local:1"; - mFakePolicy->addDisplayViewport(SECOND_DISPLAY_ID, 800, 480, DISPLAY_ORIENTATION_0, - true /*isActive*/, SECOND_DISPLAY_UNIQUE_ID, NO_PORT, - ViewportType::EXTERNAL); - mFakePolicy->setDefaultPointerDisplayId(SECOND_DISPLAY_ID); + // Set up the default display. + prepareDisplay(DISPLAY_ORIENTATION_90); + + // Set up the secondary display as the display on which the pointer should be shown. + // The InputDevice is not associated with any display. + prepareSecondaryDisplay(); + mFakePolicy->setDefaultPointerDisplayId(SECONDARY_DISPLAY_ID); configureDevice(InputReaderConfiguration::CHANGE_DISPLAY_INFO); - mFakePointerController->setBounds(0, 0, 800 - 1, 480 - 1); + mFakePointerController->setBounds(0, 0, DISPLAY_WIDTH - 1, DISPLAY_HEIGHT - 1); mFakePointerController->setPosition(100, 200); mFakePointerController->setButtonState(0); - NotifyMotionArgs args; + // Ensure input events are generated for the secondary display. process(mapper, ARBITRARY_TIME, READ_TIME, EV_REL, REL_X, 10); process(mapper, ARBITRARY_TIME, READ_TIME, EV_REL, REL_Y, 20); process(mapper, ARBITRARY_TIME, READ_TIME, EV_SYN, SYN_REPORT, 0); - ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&args)); - ASSERT_EQ(AINPUT_SOURCE_MOUSE, args.source); - ASSERT_EQ(AMOTION_EVENT_ACTION_HOVER_MOVE, args.action); - ASSERT_NO_FATAL_FAILURE(assertPointerCoords(args.pointerCoords[0], - 110.0f, 220.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f)); + ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled( + AllOf(WithAction(AMOTION_EVENT_ACTION_HOVER_MOVE), WithSource(AINPUT_SOURCE_MOUSE), + WithDisplayId(SECONDARY_DISPLAY_ID), WithCoords(110.0f, 220.0f)))); ASSERT_NO_FATAL_FAILURE(assertPosition(*mFakePointerController, 110.0f, 220.0f)); - ASSERT_EQ(SECOND_DISPLAY_ID, args.displayId); +} + +TEST_F(CursorInputMapperTest, ConfigureDisplayId_WithAssociatedViewport) { + CursorInputMapper& mapper = addMapperAndConfigure(); + + // Set up the default display. + prepareDisplay(DISPLAY_ORIENTATION_90); + + // Set up the secondary display as the display on which the pointer should be shown, + // and associate the InputDevice with the secondary display. + prepareSecondaryDisplay(); + mFakePolicy->setDefaultPointerDisplayId(SECONDARY_DISPLAY_ID); + mFakePolicy->addInputUniqueIdAssociation(DEVICE_LOCATION, SECONDARY_DISPLAY_UNIQUE_ID); + configureDevice(InputReaderConfiguration::CHANGE_DISPLAY_INFO); + + mFakePointerController->setBounds(0, 0, DISPLAY_WIDTH - 1, DISPLAY_HEIGHT - 1); + mFakePointerController->setPosition(100, 200); + mFakePointerController->setButtonState(0); + + process(mapper, ARBITRARY_TIME, READ_TIME, EV_REL, REL_X, 10); + process(mapper, ARBITRARY_TIME, READ_TIME, EV_REL, REL_Y, 20); + process(mapper, ARBITRARY_TIME, READ_TIME, EV_SYN, SYN_REPORT, 0); + ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled( + AllOf(WithAction(AMOTION_EVENT_ACTION_HOVER_MOVE), WithSource(AINPUT_SOURCE_MOUSE), + WithDisplayId(SECONDARY_DISPLAY_ID), WithCoords(110.0f, 220.0f)))); + ASSERT_NO_FATAL_FAILURE(assertPosition(*mFakePointerController, 110.0f, 220.0f)); +} + +TEST_F(CursorInputMapperTest, ConfigureDisplayId_IgnoresEventsForMismatchedPointerDisplay) { + CursorInputMapper& mapper = addMapperAndConfigure(); + + // Set up the default display as the display on which the pointer should be shown. + prepareDisplay(DISPLAY_ORIENTATION_90); + mFakePolicy->setDefaultPointerDisplayId(DISPLAY_ID); + + // Associate the InputDevice with the secondary display. + prepareSecondaryDisplay(); + mFakePolicy->addInputUniqueIdAssociation(DEVICE_LOCATION, SECONDARY_DISPLAY_UNIQUE_ID); + configureDevice(InputReaderConfiguration::CHANGE_DISPLAY_INFO); + + // The mapper should not generate any events because it is associated with a display that is + // different from the pointer display. + process(mapper, ARBITRARY_TIME, READ_TIME, EV_REL, REL_X, 10); + process(mapper, ARBITRARY_TIME, READ_TIME, EV_REL, REL_Y, 20); + process(mapper, ARBITRARY_TIME, READ_TIME, EV_SYN, SYN_REPORT, 0); + ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasNotCalled()); } // --- TouchInputMapperTest --- -- cgit v1.2.3