: InputMapper(deviceContext),
mSource(0),
mDeviceMode(DEVICE_MODE_DISABLED),
- mSurfaceWidth(-1),
- mSurfaceHeight(-1),
+ mRawSurfaceWidth(-1),
+ mRawSurfaceHeight(-1),
mSurfaceLeft(0),
mSurfaceTop(0),
mPhysicalWidth(-1),
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;
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;
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;
mPhysicalLeft = 0;
mPhysicalTop = 0;
- mSurfaceWidth = rawWidth;
- mSurfaceHeight = rawHeight;
+ mRawSurfaceWidth = rawWidth;
+ mRawSurfaceHeight = rawHeight;
mSurfaceLeft = 0;
mSurfaceTop = 0;
mSurfaceOrientation = DISPLAY_ORIENTATION_0;
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;
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) {
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;
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;
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
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);
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);
}
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;
}
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;
}
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;
}
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;
// 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);
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) {
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");
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