Loading services/inputflinger/reader/mapper/TouchInputMapper.cpp +57 −49 Original line number Diff line number Diff line Loading @@ -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), Loading Loading @@ -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; Loading @@ -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; Loading Loading @@ -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; Loading @@ -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; Loading @@ -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; Loading @@ -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) { Loading Loading @@ -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; Loading @@ -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; Loading @@ -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 Loading Loading @@ -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); Loading Loading @@ -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); } Loading Loading @@ -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; Loading @@ -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; Loading @@ -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; Loading @@ -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; Loading @@ -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); Loading Loading @@ -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) { Loading services/inputflinger/reader/mapper/TouchInputMapper.h +6 −2 Original line number Diff line number Diff line Loading @@ -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. Loading services/inputflinger/tests/InputReader_test.cpp +126 −44 Original line number Diff line number Diff line Loading @@ -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"); Loading Loading @@ -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 Loading
services/inputflinger/reader/mapper/TouchInputMapper.cpp +57 −49 Original line number Diff line number Diff line Loading @@ -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), Loading Loading @@ -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; Loading @@ -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; Loading Loading @@ -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; Loading @@ -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; Loading @@ -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; Loading @@ -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) { Loading Loading @@ -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; Loading @@ -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; Loading @@ -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 Loading Loading @@ -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); Loading Loading @@ -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); } Loading Loading @@ -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; Loading @@ -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; Loading @@ -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; Loading @@ -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; Loading @@ -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); Loading Loading @@ -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) { Loading
services/inputflinger/reader/mapper/TouchInputMapper.h +6 −2 Original line number Diff line number Diff line Loading @@ -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. Loading
services/inputflinger/tests/InputReader_test.cpp +126 −44 Original line number Diff line number Diff line Loading @@ -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"); Loading Loading @@ -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