Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit ff41b63e authored by Prabir Pradhan's avatar Prabir Pradhan Committed by Android (Google) Code Review
Browse files

Merge "Resolve associated display and pointer display in CursorInputMapper" into tm-qpr-dev

parents 4bce2e19 c04d04de
Loading
Loading
Loading
Loading
+10 −0
Original line number Original line Diff line number Diff line
@@ -17,6 +17,7 @@
#pragma once
#pragma once


#include <map>
#include <map>
#include <optional>
#include <set>
#include <set>
#include <string>
#include <string>


@@ -27,6 +28,15 @@ std::string constToString(const T& v) {
    return std::to_string(v);
    return std::to_string(v);
}
}


/**
 * Convert an optional type to string.
 */
template <typename T>
std::string toString(const std::optional<T>& optional,
                     std::string (*toString)(const T&) = constToString) {
    return optional ? toString(*optional) : "<not set>";
}

/**
/**
 * Convert a set of integral types to string.
 * Convert a set of integral types to string.
 */
 */
+35 −25
Original line number Original line Diff line number Diff line
@@ -25,6 +25,8 @@
#include "PointerControllerInterface.h"
#include "PointerControllerInterface.h"
#include "TouchCursorInputMapperCommon.h"
#include "TouchCursorInputMapperCommon.h"


#include "input/PrintTools.h"

namespace android {
namespace android {


// The default velocity control parameters that has no effect.
// The default velocity control parameters that has no effect.
@@ -113,6 +115,7 @@ void CursorInputMapper::dump(std::string& dump) {
                         toString(mCursorScrollAccumulator.haveRelativeHWheel()));
                         toString(mCursorScrollAccumulator.haveRelativeHWheel()));
    dump += StringPrintf(INDENT3 "VWheelScale: %0.3f\n", mVWheelScale);
    dump += StringPrintf(INDENT3 "VWheelScale: %0.3f\n", mVWheelScale);
    dump += StringPrintf(INDENT3 "HWheelScale: %0.3f\n", mHWheelScale);
    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 "Orientation: %d\n", mOrientation);
    dump += StringPrintf(INDENT3 "ButtonState: 0x%08x\n", mButtonState);
    dump += StringPrintf(INDENT3 "ButtonState: 0x%08x\n", mButtonState);
    dump += StringPrintf(INDENT3 "Down: %s\n", toString(isPointerDown(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) ||
    if (!changes || (changes & InputReaderConfiguration::CHANGE_DISPLAY_INFO) ||
        configurePointerCapture) {
        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;
        mOrientation = DISPLAY_ORIENTATION_0;
        const bool isOrientedDevice =
        const bool isOrientedDevice =
                (mParameters.orientationAware && mParameters.hasAssociatedDisplay);
                (mParameters.orientationAware && mParameters.hasAssociatedDisplay);

        // InputReader works in the un-rotated display coordinate space, so we don't need to do
        // 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
        // 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
        // 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
        // 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
        // get the expected screen coordinates. When pointer capture is enabled, we do not apply any
        // rotations and report values directly from the input device.
        // rotations and report values directly from the input device.
        if (!isOrientedDevice && mParameters.mode != Parameters::Mode::POINTER_RELATIVE) {
        if (!isOrientedDevice && mDisplayId &&
            std::optional<DisplayViewport> internalViewport =
            mParameters.mode != Parameters::Mode::POINTER_RELATIVE) {
                    config->getDisplayViewportByType(ViewportType::INTERNAL);
            if (auto viewport = config->getDisplayViewportById(*mDisplayId); viewport) {
            if (internalViewport) {
                mOrientation = getInverseRotation(viewport->orientation);
                mOrientation = getInverseRotation(internalViewport->orientation);
            }
            }
        }
        }


@@ -279,6 +295,11 @@ void CursorInputMapper::process(const RawEvent* rawEvent) {
}
}


void CursorInputMapper::sync(nsecs_t when, nsecs_t readTime) {
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 lastButtonState = mButtonState;
    int32_t currentButtonState = mCursorButtonAccumulator.getButtonState();
    int32_t currentButtonState = mCursorButtonAccumulator.getButtonState();
    mButtonState = currentButtonState;
    mButtonState = currentButtonState;
@@ -324,7 +345,6 @@ void CursorInputMapper::sync(nsecs_t when, nsecs_t readTime) {


    mPointerVelocityControl.move(when, &deltaX, &deltaY);
    mPointerVelocityControl.move(when, &deltaX, &deltaY);


    int32_t displayId = ADISPLAY_ID_NONE;
    float xCursorPosition = AMOTION_EVENT_INVALID_CURSOR_POSITION;
    float xCursorPosition = AMOTION_EVENT_INVALID_CURSOR_POSITION;
    float yCursorPosition = AMOTION_EVENT_INVALID_CURSOR_POSITION;
    float yCursorPosition = AMOTION_EVENT_INVALID_CURSOR_POSITION;
    if (mSource == AINPUT_SOURCE_MOUSE) {
    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_Y, yCursorPosition);
        pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_RELATIVE_X, deltaX);
        pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_RELATIVE_X, deltaX);
        pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_RELATIVE_Y, deltaY);
        pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_RELATIVE_Y, deltaY);
        displayId = mPointerController->getDisplayId();
    } else {
    } else {
        // Pointer capture and navigation modes
        // Pointer capture and navigation modes
        pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_X, deltaX);
        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.
    // Synthesize key down from buttons if needed.
    synthesizeButtonKeys(getContext(), AKEY_EVENT_ACTION_DOWN, when, readTime, getDeviceId(),
    synthesizeButtonKeys(getContext(), AKEY_EVENT_ACTION_DOWN, when, readTime, getDeviceId(),
                         mSource, displayId, policyFlags, lastButtonState, currentButtonState);
                         mSource, *mDisplayId, policyFlags, lastButtonState, currentButtonState);


    // Send motion event.
    // Send motion event.
    if (downChanged || moved || scrolled || buttonsChanged) {
    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());
                int32_t actionButton = BitSet32::valueForBit(released.clearFirstMarkedBit());
                buttonState &= ~actionButton;
                buttonState &= ~actionButton;
                NotifyMotionArgs releaseArgs(getContext()->getNextId(), when, readTime,
                NotifyMotionArgs releaseArgs(getContext()->getNextId(), when, readTime,
                                             getDeviceId(), mSource, displayId, policyFlags,
                                             getDeviceId(), mSource, *mDisplayId, policyFlags,
                                             AMOTION_EVENT_ACTION_BUTTON_RELEASE, actionButton, 0,
                                             AMOTION_EVENT_ACTION_BUTTON_RELEASE, actionButton, 0,
                                             metaState, buttonState, MotionClassification::NONE,
                                             metaState, buttonState, MotionClassification::NONE,
                                             AMOTION_EVENT_EDGE_FLAG_NONE, 1, &pointerProperties,
                                             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,
        NotifyMotionArgs args(getContext()->getNextId(), when, readTime, getDeviceId(), mSource,
                              displayId, policyFlags, motionEventAction, 0, 0, metaState,
                              *mDisplayId, policyFlags, motionEventAction, 0, 0, metaState,
                              currentButtonState, MotionClassification::NONE,
                              currentButtonState, MotionClassification::NONE,
                              AMOTION_EVENT_EDGE_FLAG_NONE, 1, &pointerProperties, &pointerCoords,
                              AMOTION_EVENT_EDGE_FLAG_NONE, 1, &pointerProperties, &pointerCoords,
                              mXPrecision, mYPrecision, xCursorPosition, yCursorPosition, downTime,
                              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());
                int32_t actionButton = BitSet32::valueForBit(pressed.clearFirstMarkedBit());
                buttonState |= actionButton;
                buttonState |= actionButton;
                NotifyMotionArgs pressArgs(getContext()->getNextId(), when, readTime, getDeviceId(),
                NotifyMotionArgs pressArgs(getContext()->getNextId(), when, readTime, getDeviceId(),
                                           mSource, displayId, policyFlags,
                                           mSource, *mDisplayId, policyFlags,
                                           AMOTION_EVENT_ACTION_BUTTON_PRESS, actionButton, 0,
                                           AMOTION_EVENT_ACTION_BUTTON_PRESS, actionButton, 0,
                                           metaState, buttonState, MotionClassification::NONE,
                                           metaState, buttonState, MotionClassification::NONE,
                                           AMOTION_EVENT_EDGE_FLAG_NONE, 1, &pointerProperties,
                                           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.
        // 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)) {
        if (motionEventAction == AMOTION_EVENT_ACTION_UP && (mSource == AINPUT_SOURCE_MOUSE)) {
            NotifyMotionArgs hoverArgs(getContext()->getNextId(), when, readTime, getDeviceId(),
            NotifyMotionArgs hoverArgs(getContext()->getNextId(), when, readTime, getDeviceId(),
                                       mSource, displayId, policyFlags,
                                       mSource, *mDisplayId, policyFlags,
                                       AMOTION_EVENT_ACTION_HOVER_MOVE, 0, 0, metaState,
                                       AMOTION_EVENT_ACTION_HOVER_MOVE, 0, 0, metaState,
                                       currentButtonState, MotionClassification::NONE,
                                       currentButtonState, MotionClassification::NONE,
                                       AMOTION_EVENT_EDGE_FLAG_NONE, 1, &pointerProperties,
                                       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);
            pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_HSCROLL, hscroll);


            NotifyMotionArgs scrollArgs(getContext()->getNextId(), when, readTime, getDeviceId(),
            NotifyMotionArgs scrollArgs(getContext()->getNextId(), when, readTime, getDeviceId(),
                                        mSource, displayId, policyFlags,
                                        mSource, *mDisplayId, policyFlags,
                                        AMOTION_EVENT_ACTION_SCROLL, 0, 0, metaState,
                                        AMOTION_EVENT_ACTION_SCROLL, 0, 0, metaState,
                                        currentButtonState, MotionClassification::NONE,
                                        currentButtonState, MotionClassification::NONE,
                                        AMOTION_EVENT_EDGE_FLAG_NONE, 1, &pointerProperties,
                                        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.
    // Synthesize key up from buttons if needed.
    synthesizeButtonKeys(getContext(), AKEY_EVENT_ACTION_UP, when, readTime, getDeviceId(), mSource,
    synthesizeButtonKeys(getContext(), AKEY_EVENT_ACTION_UP, when, readTime, getDeviceId(), mSource,
                         displayId, policyFlags, lastButtonState, currentButtonState);
                         *mDisplayId, policyFlags, lastButtonState, currentButtonState);


    mCursorMotionAccumulator.finishSync();
    mCursorMotionAccumulator.finishSync();
    mCursorScrollAccumulator.finishSync();
    mCursorScrollAccumulator.finishSync();
@@ -474,16 +493,7 @@ int32_t CursorInputMapper::getScanCodeState(uint32_t sourceMask, int32_t scanCod
}
}


std::optional<int32_t> CursorInputMapper::getAssociatedDisplayId() {
std::optional<int32_t> CursorInputMapper::getAssociatedDisplayId() {
    if (mParameters.hasAssociatedDisplay) {
    return mDisplayId;
        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;
}
}


} // namespace android
} // namespace android
+4 −0
Original line number Original line Diff line number Diff line
@@ -111,6 +111,10 @@ private:
    VelocityControl mWheelXVelocityControl;
    VelocityControl mWheelXVelocityControl;
    VelocityControl mWheelYVelocityControl;
    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<int32_t> mDisplayId;
    int32_t mOrientation;
    int32_t mOrientation;


    std::shared_ptr<PointerControllerInterface> mPointerController;
    std::shared_ptr<PointerControllerInterface> mPointerController;
+93 −22
Original line number Original line Diff line number Diff line
@@ -56,7 +56,9 @@ static constexpr nsecs_t READ_TIME = 4321;


// Arbitrary display properties.
// Arbitrary display properties.
static constexpr int32_t DISPLAY_ID = 0;
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 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_WIDTH = 480;
static constexpr int32_t DISPLAY_HEIGHT = 800;
static constexpr int32_t DISPLAY_HEIGHT = 800;
static constexpr int32_t VIRTUAL_DISPLAY_ID = 1;
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.
// Error tolerance for floating point assertions.
static const float EPSILON = 0.001f;
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<typename T>
template<typename T>
static inline T min(T a, T b) {
static inline T min(T a, T b) {
    return a < b ? a : 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
    // Device should be disabled because it is associated with a specific display, but the
    // corresponding display is not found.
    // corresponding display is not found.
    const std::string DISPLAY_UNIQUE_ID = "displayUniqueId";
    mFakePolicy->addInputUniqueIdAssociation(DEVICE_LOCATION, DISPLAY_UNIQUE_ID);
    mFakePolicy->addInputUniqueIdAssociation(DEVICE_LOCATION, DISPLAY_UNIQUE_ID);
    mDevice->configure(ARBITRARY_TIME, mFakePolicy->getReaderConfiguration(),
    mDevice->configure(ARBITRARY_TIME, mFakePolicy->getReaderConfiguration(),
                       InputReaderConfiguration::CHANGE_DISPLAY_INFO);
                       InputReaderConfiguration::CHANGE_DISPLAY_INFO);
@@ -2903,7 +2922,6 @@ TEST_F(InputDeviceTest, Configure_UniqueId_CorrectlyMatches) {
    mDevice->addMapper<FakeInputMapper>(EVENTHUB_ID, AINPUT_SOURCE_KEYBOARD);
    mDevice->addMapper<FakeInputMapper>(EVENTHUB_ID, AINPUT_SOURCE_KEYBOARD);
    mDevice->configure(ARBITRARY_TIME, mFakePolicy->getReaderConfiguration(), 0);
    mDevice->configure(ARBITRARY_TIME, mFakePolicy->getReaderConfiguration(), 0);


    const std::string DISPLAY_UNIQUE_ID = "displayUniqueId";
    mFakePolicy->addInputUniqueIdAssociation(DEVICE_LOCATION, DISPLAY_UNIQUE_ID);
    mFakePolicy->addInputUniqueIdAssociation(DEVICE_LOCATION, DISPLAY_UNIQUE_ID);
    mFakePolicy->addDisplayViewport(SECONDARY_DISPLAY_ID, DISPLAY_WIDTH, DISPLAY_HEIGHT,
    mFakePolicy->addDisplayViewport(SECONDARY_DISPLAY_ID, DISPLAY_WIDTH, DISPLAY_HEIGHT,
                                    DISPLAY_ORIENTATION_0, /* isActive= */ true, DISPLAY_UNIQUE_ID,
                                    DISPLAY_ORIENTATION_0, /* isActive= */ true, DISPLAY_UNIQUE_ID,
@@ -4188,10 +4206,14 @@ protected:
                            int32_t rotatedX, int32_t rotatedY);
                            int32_t rotatedX, int32_t rotatedY);


    void prepareDisplay(int32_t orientation) {
    void prepareDisplay(int32_t orientation) {
        const std::string uniqueId = "local:0";
        setDisplayInfoAndReconfigure(DISPLAY_ID, DISPLAY_WIDTH, DISPLAY_HEIGHT, orientation,
        const ViewportType viewportType = ViewportType::INTERNAL;
                                     DISPLAY_UNIQUE_ID, NO_PORT, ViewportType::INTERNAL);
        setDisplayInfoAndReconfigure(DISPLAY_ID, DISPLAY_WIDTH, DISPLAY_HEIGHT,
    }
                orientation, uniqueId, NO_PORT, viewportType);

    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,
    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) {
TEST_F(CursorInputMapperTest, Process_WhenOrientationAware_ShouldNotRotateMotions) {
    mFakePolicy->addInputUniqueIdAssociation(DEVICE_LOCATION, DISPLAY_UNIQUE_ID);
    addConfigurationProperty("cursor.mode", "navigation");
    addConfigurationProperty("cursor.mode", "navigation");
    // InputReader works in the un-rotated coordinate space, so orientation-aware devices do not
    // InputReader works in the un-rotated coordinate space, so orientation-aware devices do not
    // need to be rotated.
    // need to be rotated.
@@ -4486,11 +4509,13 @@ TEST_F(CursorInputMapperTest, Process_WhenOrientationAware_ShouldNotRotateMotion
}
}


TEST_F(CursorInputMapperTest, Process_WhenNotOrientationAware_ShouldRotateMotions) {
TEST_F(CursorInputMapperTest, Process_WhenNotOrientationAware_ShouldRotateMotions) {
    mFakePolicy->addInputUniqueIdAssociation(DEVICE_LOCATION, DISPLAY_UNIQUE_ID);
    addConfigurationProperty("cursor.mode", "navigation");
    addConfigurationProperty("cursor.mode", "navigation");
    // Since InputReader works in the un-rotated coordinate space, only devices that are not
    // Since InputReader works in the un-rotated coordinate space, only devices that are not
    // orientation-aware are affected by display rotation.
    // orientation-aware are affected by display rotation.
    CursorInputMapper& mapper = addMapperAndConfigure<CursorInputMapper>();
    CursorInputMapper& mapper = addMapperAndConfigure<CursorInputMapper>();


    clearViewports();
    prepareDisplay(DISPLAY_ORIENTATION_0);
    prepareDisplay(DISPLAY_ORIENTATION_0);
    ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper,  0,  1,  0,  1));
    ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper,  0,  1,  0,  1));
    ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper,  1,  1,  1,  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,  0, -1,  0));
    ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, -1,  1, -1,  1));
    ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, -1,  1, -1,  1));


    clearViewports();
    prepareDisplay(DISPLAY_ORIENTATION_90);
    prepareDisplay(DISPLAY_ORIENTATION_90);
    ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper,  0,  1, -1,  0));
    ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper,  0,  1, -1,  0));
    ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper,  1,  1, -1,  1));
    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,  0,  0, -1));
    ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, -1,  1, -1, -1));
    ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, -1,  1, -1, -1));


    clearViewports();
    prepareDisplay(DISPLAY_ORIENTATION_180);
    prepareDisplay(DISPLAY_ORIENTATION_180);
    ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper,  0,  1,  0, -1));
    ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper,  0,  1,  0, -1));
    ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper,  1,  1, -1, -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,  0,  1,  0));
    ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, -1,  1,  1, -1));
    ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, -1,  1,  1, -1));


    clearViewports();
    prepareDisplay(DISPLAY_ORIENTATION_270);
    prepareDisplay(DISPLAY_ORIENTATION_270);
    ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper,  0,  1,  1,  0));
    ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper,  0,  1,  1,  0));
    ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper,  1,  1,  1, -1));
    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());
    ASSERT_EQ(20, args.pointerCoords[0].getY());
}
}


TEST_F(CursorInputMapperTest, Process_ShouldHandleDisplayId) {
TEST_F(CursorInputMapperTest, ConfigureDisplayId_NoAssociatedViewport) {
    CursorInputMapper& mapper = addMapperAndConfigure<CursorInputMapper>();
    CursorInputMapper& mapper = addMapperAndConfigure<CursorInputMapper>();


    // Setup for second display.
    // Set up the default display.
    constexpr int32_t SECOND_DISPLAY_ID = 1;
    prepareDisplay(DISPLAY_ORIENTATION_90);
    const std::string SECOND_DISPLAY_UNIQUE_ID = "local:1";

    mFakePolicy->addDisplayViewport(SECOND_DISPLAY_ID, 800, 480, DISPLAY_ORIENTATION_0,
    // Set up the secondary display as the display on which the pointer should be shown.
                                    true /*isActive*/, SECOND_DISPLAY_UNIQUE_ID, NO_PORT,
    // The InputDevice is not associated with any display.
                                    ViewportType::EXTERNAL);
    prepareSecondaryDisplay();
    mFakePolicy->setDefaultPointerDisplayId(SECOND_DISPLAY_ID);
    mFakePolicy->setDefaultPointerDisplayId(SECONDARY_DISPLAY_ID);
    configureDevice(InputReaderConfiguration::CHANGE_DISPLAY_INFO);
    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->setPosition(100, 200);
    mFakePointerController->setButtonState(0);
    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_X, 10);
    process(mapper, ARBITRARY_TIME, READ_TIME, EV_REL, REL_Y, 20);
    process(mapper, ARBITRARY_TIME, READ_TIME, EV_REL, REL_Y, 20);
    process(mapper, ARBITRARY_TIME, READ_TIME, EV_SYN, SYN_REPORT, 0);
    process(mapper, ARBITRARY_TIME, READ_TIME, EV_SYN, SYN_REPORT, 0);
    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&args));
    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(
    ASSERT_EQ(AINPUT_SOURCE_MOUSE, args.source);
            AllOf(WithAction(AMOTION_EVENT_ACTION_HOVER_MOVE), WithSource(AINPUT_SOURCE_MOUSE),
    ASSERT_EQ(AMOTION_EVENT_ACTION_HOVER_MOVE, args.action);
                  WithDisplayId(SECONDARY_DISPLAY_ID), WithCoords(110.0f, 220.0f))));
    ASSERT_NO_FATAL_FAILURE(assertPointerCoords(args.pointerCoords[0],
    ASSERT_NO_FATAL_FAILURE(assertPosition(*mFakePointerController, 110.0f, 220.0f));
            110.0f, 220.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f));
}

TEST_F(CursorInputMapperTest, ConfigureDisplayId_WithAssociatedViewport) {
    CursorInputMapper& mapper = addMapperAndConfigure<CursorInputMapper>();

    // 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));
    ASSERT_NO_FATAL_FAILURE(assertPosition(*mFakePointerController, 110.0f, 220.0f));
    ASSERT_EQ(SECOND_DISPLAY_ID, args.displayId);
}

TEST_F(CursorInputMapperTest, ConfigureDisplayId_IgnoresEventsForMismatchedPointerDisplay) {
    CursorInputMapper& mapper = addMapperAndConfigure<CursorInputMapper>();

    // 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 ---
// --- TouchInputMapperTest ---