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

Commit 6de3b57a authored by TreeHugger Robot's avatar TreeHugger Robot Committed by Automerger Merge Worker
Browse files

Merge "Fix tap is wrong in landscape with cutout disabled" into rvc-dev am:...

Merge "Fix tap is wrong in landscape with cutout disabled" into rvc-dev am: e983bd43 am: 15cf6453 am: 8d5c1ef5 am: 6dcff03c

Change-Id: Id0e8ca942955ef963cd2498cab92eeb5f47217af
parents 3a6586be 6dcff03c
Loading
Loading
Loading
Loading
+57 −49
Original line number Diff line number Diff line
@@ -160,8 +160,8 @@ TouchInputMapper::TouchInputMapper(InputDeviceContext& deviceContext)
      : InputMapper(deviceContext),
        mSource(0),
        mDeviceMode(DEVICE_MODE_DISABLED),
        mSurfaceWidth(-1),
        mSurfaceHeight(-1),
        mRawSurfaceWidth(-1),
        mRawSurfaceHeight(-1),
        mSurfaceLeft(0),
        mSurfaceTop(0),
        mPhysicalWidth(-1),
@@ -680,7 +680,7 @@ void TouchInputMapper::configureSurface(nsecs_t when, bool* outResetNeeded) {
                    naturalLogicalHeight = mViewport.logicalRight - mViewport.logicalLeft;
                    naturalPhysicalWidth = mViewport.physicalBottom - mViewport.physicalTop;
                    naturalPhysicalHeight = mViewport.physicalRight - mViewport.physicalLeft;
                    naturalPhysicalLeft = mViewport.deviceHeight - naturalPhysicalWidth;
                    naturalPhysicalLeft = mViewport.deviceHeight - mViewport.physicalBottom;
                    naturalPhysicalTop = mViewport.physicalLeft;
                    naturalDeviceWidth = mViewport.deviceHeight;
                    naturalDeviceHeight = mViewport.deviceWidth;
@@ -701,7 +701,7 @@ void TouchInputMapper::configureSurface(nsecs_t when, bool* outResetNeeded) {
                    naturalPhysicalWidth = mViewport.physicalBottom - mViewport.physicalTop;
                    naturalPhysicalHeight = mViewport.physicalRight - mViewport.physicalLeft;
                    naturalPhysicalLeft = mViewport.physicalTop;
                    naturalPhysicalTop = mViewport.deviceWidth - naturalPhysicalHeight;
                    naturalPhysicalTop = mViewport.deviceWidth - mViewport.physicalRight;
                    naturalDeviceWidth = mViewport.deviceHeight;
                    naturalDeviceHeight = mViewport.deviceWidth;
                    break;
@@ -729,10 +729,12 @@ void TouchInputMapper::configureSurface(nsecs_t when, bool* outResetNeeded) {
            mPhysicalLeft = naturalPhysicalLeft;
            mPhysicalTop = naturalPhysicalTop;

            mSurfaceWidth = naturalLogicalWidth * naturalDeviceWidth / naturalPhysicalWidth;
            mSurfaceHeight = naturalLogicalHeight * naturalDeviceHeight / naturalPhysicalHeight;
            mRawSurfaceWidth = naturalLogicalWidth * naturalDeviceWidth / naturalPhysicalWidth;
            mRawSurfaceHeight = naturalLogicalHeight * naturalDeviceHeight / naturalPhysicalHeight;
            mSurfaceLeft = naturalPhysicalLeft * naturalLogicalWidth / naturalPhysicalWidth;
            mSurfaceTop = naturalPhysicalTop * naturalLogicalHeight / naturalPhysicalHeight;
            mSurfaceRight = mSurfaceLeft + naturalLogicalWidth;
            mSurfaceBottom = mSurfaceTop + naturalLogicalHeight;

            mSurfaceOrientation =
                    mParameters.orientationAware ? mViewport.orientation : DISPLAY_ORIENTATION_0;
@@ -742,8 +744,8 @@ void TouchInputMapper::configureSurface(nsecs_t when, bool* outResetNeeded) {
            mPhysicalLeft = 0;
            mPhysicalTop = 0;

            mSurfaceWidth = rawWidth;
            mSurfaceHeight = rawHeight;
            mRawSurfaceWidth = rawWidth;
            mRawSurfaceHeight = rawHeight;
            mSurfaceLeft = 0;
            mSurfaceTop = 0;
            mSurfaceOrientation = DISPLAY_ORIENTATION_0;
@@ -769,12 +771,12 @@ void TouchInputMapper::configureSurface(nsecs_t when, bool* outResetNeeded) {
    if (viewportChanged || deviceModeChanged) {
        ALOGI("Device reconfigured: id=%d, name='%s', size %dx%d, orientation %d, mode %d, "
              "display id %d",
              getDeviceId(), getDeviceName().c_str(), mSurfaceWidth, mSurfaceHeight,
              getDeviceId(), getDeviceName().c_str(), mRawSurfaceWidth, mRawSurfaceHeight,
              mSurfaceOrientation, mDeviceMode, mViewport.displayId);

        // Configure X and Y factors.
        mXScale = float(mSurfaceWidth) / rawWidth;
        mYScale = float(mSurfaceHeight) / rawHeight;
        mXScale = float(mRawSurfaceWidth) / rawWidth;
        mYScale = float(mRawSurfaceHeight) / rawHeight;
        mXTranslate = -mSurfaceLeft;
        mYTranslate = -mSurfaceTop;
        mXPrecision = 1.0f / mXScale;
@@ -793,7 +795,7 @@ void TouchInputMapper::configureSurface(nsecs_t when, bool* outResetNeeded) {
        mGeometricScale = avg(mXScale, mYScale);

        // Size of diagonal axis.
        float diagonalSize = hypotf(mSurfaceWidth, mSurfaceHeight);
        float diagonalSize = hypotf(mRawSurfaceWidth, mRawSurfaceHeight);

        // Size factors.
        if (mCalibration.sizeCalibration != Calibration::SIZE_CALIBRATION_NONE) {
@@ -956,13 +958,13 @@ void TouchInputMapper::configureSurface(nsecs_t when, bool* outResetNeeded) {
                mOrientedYPrecision = mXPrecision;

                mOrientedRanges.x.min = mYTranslate;
                mOrientedRanges.x.max = mSurfaceHeight + mYTranslate - 1;
                mOrientedRanges.x.max = mRawSurfaceHeight + mYTranslate - 1;
                mOrientedRanges.x.flat = 0;
                mOrientedRanges.x.fuzz = 0;
                mOrientedRanges.x.resolution = mRawPointerAxes.y.resolution * mYScale;

                mOrientedRanges.y.min = mXTranslate;
                mOrientedRanges.y.max = mSurfaceWidth + mXTranslate - 1;
                mOrientedRanges.y.max = mRawSurfaceWidth + mXTranslate - 1;
                mOrientedRanges.y.flat = 0;
                mOrientedRanges.y.fuzz = 0;
                mOrientedRanges.y.resolution = mRawPointerAxes.x.resolution * mXScale;
@@ -973,13 +975,13 @@ void TouchInputMapper::configureSurface(nsecs_t when, bool* outResetNeeded) {
                mOrientedYPrecision = mYPrecision;

                mOrientedRanges.x.min = mXTranslate;
                mOrientedRanges.x.max = mSurfaceWidth + mXTranslate - 1;
                mOrientedRanges.x.max = mRawSurfaceWidth + mXTranslate - 1;
                mOrientedRanges.x.flat = 0;
                mOrientedRanges.x.fuzz = 0;
                mOrientedRanges.x.resolution = mRawPointerAxes.x.resolution * mXScale;

                mOrientedRanges.y.min = mYTranslate;
                mOrientedRanges.y.max = mSurfaceHeight + mYTranslate - 1;
                mOrientedRanges.y.max = mRawSurfaceHeight + mYTranslate - 1;
                mOrientedRanges.y.flat = 0;
                mOrientedRanges.y.fuzz = 0;
                mOrientedRanges.y.resolution = mRawPointerAxes.y.resolution * mYScale;
@@ -992,7 +994,7 @@ void TouchInputMapper::configureSurface(nsecs_t when, bool* outResetNeeded) {
        if (mDeviceMode == DEVICE_MODE_POINTER) {
            // Compute pointer gesture detection parameters.
            float rawDiagonal = hypotf(rawWidth, rawHeight);
            float displayDiagonal = hypotf(mSurfaceWidth, mSurfaceHeight);
            float displayDiagonal = hypotf(mRawSurfaceWidth, mRawSurfaceHeight);

            // Scale movements such that one whole swipe of the touch pad covers a
            // given area relative to the diagonal size of the display when no acceleration
@@ -1027,10 +1029,12 @@ void TouchInputMapper::configureSurface(nsecs_t when, bool* outResetNeeded) {

void TouchInputMapper::dumpSurface(std::string& dump) {
    dump += StringPrintf(INDENT3 "%s\n", mViewport.toString().c_str());
    dump += StringPrintf(INDENT3 "SurfaceWidth: %dpx\n", mSurfaceWidth);
    dump += StringPrintf(INDENT3 "SurfaceHeight: %dpx\n", mSurfaceHeight);
    dump += StringPrintf(INDENT3 "RawSurfaceWidth: %dpx\n", mRawSurfaceWidth);
    dump += StringPrintf(INDENT3 "RawSurfaceHeight: %dpx\n", mRawSurfaceHeight);
    dump += StringPrintf(INDENT3 "SurfaceLeft: %d\n", mSurfaceLeft);
    dump += StringPrintf(INDENT3 "SurfaceTop: %d\n", mSurfaceTop);
    dump += StringPrintf(INDENT3 "SurfaceRight: %d\n", mSurfaceRight);
    dump += StringPrintf(INDENT3 "SurfaceBottom: %d\n", mSurfaceBottom);
    dump += StringPrintf(INDENT3 "PhysicalWidth: %dpx\n", mPhysicalWidth);
    dump += StringPrintf(INDENT3 "PhysicalHeight: %dpx\n", mPhysicalHeight);
    dump += StringPrintf(INDENT3 "PhysicalLeft: %d\n", mPhysicalLeft);
@@ -1074,16 +1078,16 @@ void TouchInputMapper::configureVirtualKeys() {
        int32_t halfHeight = virtualKeyDefinition.height / 2;

        virtualKey.hitLeft =
                (virtualKeyDefinition.centerX - halfWidth) * touchScreenWidth / mSurfaceWidth +
                (virtualKeyDefinition.centerX - halfWidth) * touchScreenWidth / mRawSurfaceWidth +
                touchScreenLeft;
        virtualKey.hitRight =
                (virtualKeyDefinition.centerX + halfWidth) * touchScreenWidth / mSurfaceWidth +
                (virtualKeyDefinition.centerX + halfWidth) * touchScreenWidth / mRawSurfaceWidth +
                touchScreenLeft;
        virtualKey.hitTop =
                (virtualKeyDefinition.centerY - halfHeight) * touchScreenHeight / mSurfaceHeight +
        virtualKey.hitTop = (virtualKeyDefinition.centerY - halfHeight) * touchScreenHeight /
                        mRawSurfaceHeight +
                touchScreenTop;
        virtualKey.hitBottom =
                (virtualKeyDefinition.centerY + halfHeight) * touchScreenHeight / mSurfaceHeight +
        virtualKey.hitBottom = (virtualKeyDefinition.centerY + halfHeight) * touchScreenHeight /
                        mRawSurfaceHeight +
                touchScreenTop;
        mVirtualKeys.push_back(virtualKey);
    }
@@ -2188,13 +2192,10 @@ void TouchInputMapper::cookPointerData() {
        rotateAndScale(xTransformed, yTransformed);

        // Adjust X, Y, and coverage coords for surface orientation.
        float x, y;
        float left, top, right, bottom;

        switch (mSurfaceOrientation) {
            case DISPLAY_ORIENTATION_90:
                x = yTransformed + mYTranslate;
                y = xTransformed + mXTranslate;
                left = float(rawTop - mRawPointerAxes.y.minValue) * mYScale + mYTranslate;
                right = float(rawBottom - mRawPointerAxes.y.minValue) * mYScale + mYTranslate;
                bottom = float(mRawPointerAxes.x.maxValue - rawLeft) * mXScale + mXTranslate;
@@ -2207,8 +2208,6 @@ void TouchInputMapper::cookPointerData() {
                }
                break;
            case DISPLAY_ORIENTATION_180:
                x = xTransformed + mXTranslate;
                y = yTransformed + mYTranslate;
                left = float(mRawPointerAxes.x.maxValue - rawRight) * mXScale;
                right = float(mRawPointerAxes.x.maxValue - rawLeft) * mXScale;
                bottom = float(mRawPointerAxes.y.maxValue - rawTop) * mYScale + mYTranslate;
@@ -2221,8 +2220,6 @@ void TouchInputMapper::cookPointerData() {
                }
                break;
            case DISPLAY_ORIENTATION_270:
                x = yTransformed + mYTranslate;
                y = xTransformed + mXTranslate;
                left = float(mRawPointerAxes.y.maxValue - rawBottom) * mYScale;
                right = float(mRawPointerAxes.y.maxValue - rawTop) * mYScale;
                bottom = float(rawRight - mRawPointerAxes.x.minValue) * mXScale + mXTranslate;
@@ -2235,8 +2232,6 @@ void TouchInputMapper::cookPointerData() {
                }
                break;
            default:
                x = xTransformed + mXTranslate;
                y = yTransformed + mYTranslate;
                left = float(rawLeft - mRawPointerAxes.x.minValue) * mXScale + mXTranslate;
                right = float(rawRight - mRawPointerAxes.x.minValue) * mXScale + mXTranslate;
                bottom = float(rawBottom - mRawPointerAxes.y.minValue) * mYScale + mYTranslate;
@@ -2247,8 +2242,8 @@ void TouchInputMapper::cookPointerData() {
        // Write output coords.
        PointerCoords& out = mCurrentCookedState.cookedPointerData.pointerCoords[i];
        out.clear();
        out.setAxisValue(AMOTION_EVENT_AXIS_X, x);
        out.setAxisValue(AMOTION_EVENT_AXIS_Y, y);
        out.setAxisValue(AMOTION_EVENT_AXIS_X, xTransformed);
        out.setAxisValue(AMOTION_EVENT_AXIS_Y, yTransformed);
        out.setAxisValue(AMOTION_EVENT_AXIS_PRESSURE, pressure);
        out.setAxisValue(AMOTION_EVENT_AXIS_SIZE, size);
        out.setAxisValue(AMOTION_EVENT_AXIS_TOUCH_MAJOR, touchMajor);
@@ -3624,34 +3619,47 @@ void TouchInputMapper::cancelTouch(nsecs_t when) {
    abortTouches(when, 0 /* policyFlags*/);
}

// Transform raw coordinate to surface coordinate
void TouchInputMapper::rotateAndScale(float& x, float& y) {
    // Scale to surface coordinate.
    const float xScaled = float(x - mRawPointerAxes.x.minValue) * mXScale;
    const float yScaled = float(y - mRawPointerAxes.y.minValue) * mYScale;

    // Rotate to surface coordinate.
    // 0 - no swap and reverse.
    // 90 - swap x/y and reverse y.
    // 180 - reverse x, y.
    // 270 - swap x/y and reverse x.
    switch (mSurfaceOrientation) {
        case DISPLAY_ORIENTATION_0:
            x = xScaled + mXTranslate;
            y = yScaled + mYTranslate;
            break;
        case DISPLAY_ORIENTATION_90:
            x = float(mRawPointerAxes.x.maxValue - x) * mXScale;
            y = float(y - mRawPointerAxes.y.minValue) * mYScale;
            y = mSurfaceRight - xScaled;
            x = yScaled + mYTranslate;
            break;
        case DISPLAY_ORIENTATION_180:
            x = float(mRawPointerAxes.x.maxValue - x) * mXScale;
            y = float(mRawPointerAxes.y.maxValue - y) * mYScale;
            x = mSurfaceRight - xScaled;
            y = mSurfaceBottom - yScaled;
            break;
        case DISPLAY_ORIENTATION_270:
            x = float(x - mRawPointerAxes.x.minValue) * mXScale;
            y = float(mRawPointerAxes.y.maxValue - y) * mYScale;
            y = xScaled + mXTranslate;
            x = mSurfaceBottom - yScaled;
            break;
        default:
            x = float(x - mRawPointerAxes.x.minValue) * mXScale;
            y = float(y - mRawPointerAxes.y.minValue) * mYScale;
            break;
            assert(false);
    }
}

bool TouchInputMapper::isPointInsideSurface(int32_t x, int32_t y) {
    float xTransformed = x, yTransformed = y;
    rotateAndScale(xTransformed, yTransformed);
    const float xScaled = (x - mRawPointerAxes.x.minValue) * mXScale;
    const float yScaled = (y - mRawPointerAxes.y.minValue) * mYScale;

    return x >= mRawPointerAxes.x.minValue && x <= mRawPointerAxes.x.maxValue &&
            xTransformed >= mSurfaceLeft && xTransformed <= mSurfaceLeft + mSurfaceWidth &&
            xScaled >= mSurfaceLeft && xScaled <= mSurfaceRight &&
            y >= mRawPointerAxes.y.minValue && y <= mRawPointerAxes.y.maxValue &&
            yTransformed >= mSurfaceTop && yTransformed <= mSurfaceTop + mSurfaceHeight;
            yScaled >= mSurfaceTop && yScaled <= mSurfaceBottom;
}

const TouchInputMapper::VirtualKey* TouchInputMapper::findVirtualKeyHit(int32_t x, int32_t y) {
+6 −2
Original line number Diff line number Diff line
@@ -407,12 +407,16 @@ private:
    // The surface orientation, width and height set by configureSurface().
    // The width and height are derived from the viewport but are specified
    // in the natural orientation.
    // They could be used for calculating diagonal, scaling factors, and virtual keys.
    int32_t mRawSurfaceWidth;
    int32_t mRawSurfaceHeight;

    // The surface origin specifies how the surface coordinates should be translated
    // to align with the logical display coordinate space.
    int32_t mSurfaceWidth;
    int32_t mSurfaceHeight;
    int32_t mSurfaceLeft;
    int32_t mSurfaceTop;
    int32_t mSurfaceRight;
    int32_t mSurfaceBottom;

    // Similar to the surface coordinates, but in the raw display coordinate space rather than in
    // the logical coordinate space.
+126 −44
Original line number Diff line number Diff line
@@ -6990,51 +6990,7 @@ TEST_F(MultiTouchInputMapperTest, Configure_EnabledForAssociatedDisplay) {
    ASSERT_EQ(SECONDARY_DISPLAY_ID, args.displayId);
}

/**
 * Test touch should not work if outside of surface.
 */
TEST_F(MultiTouchInputMapperTest, Viewports_SurfaceRange) {
    addConfigurationProperty("touch.deviceType", "touchScreen");
    prepareDisplay(DISPLAY_ORIENTATION_0);
    prepareAxes(POSITION);
    MultiTouchInputMapper& mapper = addMapperAndConfigure<MultiTouchInputMapper>();

    // Touch on left-top area should work.
    int32_t rawX = DISPLAY_WIDTH / 2 - 1;
    int32_t rawY = DISPLAY_HEIGHT / 2 - 1;
    processPosition(mapper, rawX, rawY);
    processSync(mapper);

    NotifyMotionArgs args;
    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&args));

    // Reset.
    mapper.reset(ARBITRARY_TIME);

    // Let logical display be different to physical display and rotate 90-degrees.
    std::optional<DisplayViewport> internalViewport =
            mFakePolicy->getDisplayViewportByType(ViewportType::VIEWPORT_INTERNAL);
    internalViewport->orientation = DISPLAY_ORIENTATION_90;
    internalViewport->logicalLeft = 0;
    internalViewport->logicalTop = 0;
    internalViewport->logicalRight = DISPLAY_HEIGHT;
    internalViewport->logicalBottom = DISPLAY_WIDTH / 2;

    internalViewport->physicalLeft = DISPLAY_HEIGHT;
    internalViewport->physicalTop = DISPLAY_WIDTH / 2;
    internalViewport->physicalRight = DISPLAY_HEIGHT;
    internalViewport->physicalBottom = DISPLAY_WIDTH;

    internalViewport->deviceWidth = DISPLAY_HEIGHT;
    internalViewport->deviceHeight = DISPLAY_WIDTH;
    mFakePolicy->updateViewport(internalViewport.value());
    configureDevice(InputReaderConfiguration::CHANGE_DISPLAY_INFO);

    // Display align to right-top after rotate 90-degrees, touch on left-top area should not work.
    processPosition(mapper, rawX, rawY);
    processSync(mapper);
    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasNotCalled());
}

TEST_F(MultiTouchInputMapperTest, Process_ShouldHandleSingleTouch) {
    addConfigurationProperty("touch.deviceType", "touchScreen");
@@ -7161,4 +7117,130 @@ TEST_F(MultiTouchInputMapperTest_ExternalDevice, Viewports_Fallback) {
    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs));
    ASSERT_EQ(SECONDARY_DISPLAY_ID, motionArgs.displayId);
}

/**
 * Test touch should not work if outside of surface.
 */
class MultiTouchInputMapperTest_SurfaceRange : public MultiTouchInputMapperTest {
protected:
    void halfDisplayToCenterHorizontal(int32_t orientation) {
        std::optional<DisplayViewport> internalViewport =
                mFakePolicy->getDisplayViewportByType(ViewportType::VIEWPORT_INTERNAL);

        // Half display to (width/4, 0, width * 3/4, height) to make display has offset.
        internalViewport->orientation = orientation;
        if (orientation == DISPLAY_ORIENTATION_90 || orientation == DISPLAY_ORIENTATION_270) {
            internalViewport->logicalLeft = 0;
            internalViewport->logicalTop = 0;
            internalViewport->logicalRight = DISPLAY_HEIGHT;
            internalViewport->logicalBottom = DISPLAY_WIDTH / 2;

            internalViewport->physicalLeft = 0;
            internalViewport->physicalTop = DISPLAY_WIDTH / 4;
            internalViewport->physicalRight = DISPLAY_HEIGHT;
            internalViewport->physicalBottom = DISPLAY_WIDTH * 3 / 4;

            internalViewport->deviceWidth = DISPLAY_HEIGHT;
            internalViewport->deviceHeight = DISPLAY_WIDTH;
        } else {
            internalViewport->logicalLeft = 0;
            internalViewport->logicalTop = 0;
            internalViewport->logicalRight = DISPLAY_WIDTH / 2;
            internalViewport->logicalBottom = DISPLAY_HEIGHT;

            internalViewport->physicalLeft = DISPLAY_WIDTH / 4;
            internalViewport->physicalTop = 0;
            internalViewport->physicalRight = DISPLAY_WIDTH * 3 / 4;
            internalViewport->physicalBottom = DISPLAY_HEIGHT;

            internalViewport->deviceWidth = DISPLAY_WIDTH;
            internalViewport->deviceHeight = DISPLAY_HEIGHT;
        }

        mFakePolicy->updateViewport(internalViewport.value());
        configureDevice(InputReaderConfiguration::CHANGE_DISPLAY_INFO);
    }

    void processPositionAndVerify(MultiTouchInputMapper& mapper, int32_t xInside, int32_t yInside,
                                  int32_t xOutside, int32_t yOutside, int32_t xExpected,
                                  int32_t yExpected) {
        // touch on outside area should not work.
        processPosition(mapper, toRawX(xOutside), toRawY(yOutside));
        processSync(mapper);
        ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasNotCalled());

        // touch on inside area should receive the event.
        NotifyMotionArgs args;
        processPosition(mapper, toRawX(xInside), toRawY(yInside));
        processSync(mapper);
        ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&args));
        ASSERT_NEAR(xExpected, args.pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_X), 1);
        ASSERT_NEAR(yExpected, args.pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_Y), 1);

        // Reset.
        mapper.reset(ARBITRARY_TIME);
    }
};

TEST_F(MultiTouchInputMapperTest_SurfaceRange, Viewports_SurfaceRange) {
    addConfigurationProperty("touch.deviceType", "touchScreen");
    prepareDisplay(DISPLAY_ORIENTATION_0);
    prepareAxes(POSITION);
    MultiTouchInputMapper& mapper = addMapperAndConfigure<MultiTouchInputMapper>();

    // Touch on center of normal display should work.
    const int32_t x = DISPLAY_WIDTH / 4;
    const int32_t y = DISPLAY_HEIGHT / 2;
    processPosition(mapper, toRawX(x), toRawY(y));
    processSync(mapper);
    NotifyMotionArgs args;
    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&args));
    ASSERT_NO_FATAL_FAILURE(assertPointerCoords(args.pointerCoords[0], x, y, 1.0f, 0.0f, 0.0f, 0.0f,
                                                0.0f, 0.0f, 0.0f, 0.0f));
    // Reset.
    mapper.reset(ARBITRARY_TIME);

    // Let physical display be different to device, and make surface and physical could be 1:1.
    halfDisplayToCenterHorizontal(DISPLAY_ORIENTATION_0);

    const int32_t xExpected = (x + 1) - (DISPLAY_WIDTH / 4);
    const int32_t yExpected = y;
    processPositionAndVerify(mapper, x - 1, y, x + 1, y, xExpected, yExpected);
}

TEST_F(MultiTouchInputMapperTest_SurfaceRange, Viewports_SurfaceRange_90) {
    addConfigurationProperty("touch.deviceType", "touchScreen");
    prepareDisplay(DISPLAY_ORIENTATION_0);
    prepareAxes(POSITION);
    MultiTouchInputMapper& mapper = addMapperAndConfigure<MultiTouchInputMapper>();

    // Half display to (width/4, 0, width * 3/4, height) and rotate 90-degrees.
    halfDisplayToCenterHorizontal(DISPLAY_ORIENTATION_90);

    const int32_t x = DISPLAY_WIDTH / 4;
    const int32_t y = DISPLAY_HEIGHT / 2;

    // expect x/y = swap x/y then reverse y.
    const int32_t xExpected = y;
    const int32_t yExpected = (DISPLAY_WIDTH * 3 / 4) - (x + 1);
    processPositionAndVerify(mapper, x - 1, y, x + 1, y, xExpected, yExpected);
}

TEST_F(MultiTouchInputMapperTest_SurfaceRange, Viewports_SurfaceRange_270) {
    addConfigurationProperty("touch.deviceType", "touchScreen");
    prepareDisplay(DISPLAY_ORIENTATION_0);
    prepareAxes(POSITION);
    MultiTouchInputMapper& mapper = addMapperAndConfigure<MultiTouchInputMapper>();

    // Half display to (width/4, 0, width * 3/4, height) and rotate 270-degrees.
    halfDisplayToCenterHorizontal(DISPLAY_ORIENTATION_270);

    const int32_t x = DISPLAY_WIDTH / 4;
    const int32_t y = DISPLAY_HEIGHT / 2;

    // expect x/y = swap x/y then reverse x.
    constexpr int32_t xExpected = DISPLAY_HEIGHT - y;
    constexpr int32_t yExpected = (x + 1) - DISPLAY_WIDTH / 4;
    processPositionAndVerify(mapper, x - 1, y, x + 1, y, xExpected, yExpected);
}
} // namespace android