Report motion offsets for touchpad swipes
Adds two new axes, AXIS_GESTURE_X_OFFSET and AXIS_GESTURE_Y_OFFSET,
which report the movement of swipe gestures on the touchpad as a
fraction of the touchpad's size.
Bug: 246758376
Test: check axis values come through in a test app
Change-Id: I313410053a8db13273bd05a33d3a6a1f75081dae
diff --git a/include/android/input.h b/include/android/input.h
index d906af6..5d19c5c 100644
--- a/include/android/input.h
+++ b/include/android/input.h
@@ -771,6 +771,21 @@
* The interpretation of a generic axis is device-specific.
*/
AMOTION_EVENT_AXIS_GENERIC_16 = 47,
+ /**
+ * Axis constant: X gesture offset axis of a motion event.
+ *
+ * - For a touch pad, reports the distance that a swipe gesture has moved in the X axis, as a
+ * proportion of the touch pad's size. For example, if a touch pad is 1000 units wide, and a
+ * swipe gesture starts at X = 500 then moves to X = 400, this axis would have a value of
+ * -0.1.
+ */
+ AMOTION_EVENT_AXIS_GESTURE_X_OFFSET = 48,
+ /**
+ * Axis constant: Y gesture offset axis of a motion event.
+ *
+ * The same as {@link AMOTION_EVENT_AXIS_GESTURE_X_OFFSET}, but for the Y axis.
+ */
+ AMOTION_EVENT_AXIS_GESTURE_Y_OFFSET = 49,
/**
* Note: This is not an "Axis constant". It does not represent any axis, nor should it be used
@@ -778,7 +793,7 @@
* to make some computations (like iterating through all possible axes) cleaner.
* Please update the value accordingly if you add a new axis.
*/
- AMOTION_EVENT_MAXIMUM_VALID_AXIS_VALUE = AMOTION_EVENT_AXIS_GENERIC_16,
+ AMOTION_EVENT_MAXIMUM_VALID_AXIS_VALUE = AMOTION_EVENT_AXIS_GESTURE_Y_OFFSET,
// NOTE: If you add a new axis here you must also add it to several other files.
// Refer to frameworks/base/core/java/android/view/MotionEvent.java for the full list.
diff --git a/libs/input/InputEventLabels.cpp b/libs/input/InputEventLabels.cpp
index 163a2fe..b78fae3 100644
--- a/libs/input/InputEventLabels.cpp
+++ b/libs/input/InputEventLabels.cpp
@@ -391,7 +391,9 @@
DEFINE_AXIS(GENERIC_13), \
DEFINE_AXIS(GENERIC_14), \
DEFINE_AXIS(GENERIC_15), \
- DEFINE_AXIS(GENERIC_16)
+ DEFINE_AXIS(GENERIC_16), \
+ DEFINE_AXIS(GESTURE_X_OFFSET), \
+ DEFINE_AXIS(GESTURE_Y_OFFSET)
// NOTE: If you add new LEDs here, you must also add them to Input.h
#define LEDS_SEQUENCE \
diff --git a/services/inputflinger/InputCommonConverter.cpp b/services/inputflinger/InputCommonConverter.cpp
index 23b6f57..6db89d4 100644
--- a/services/inputflinger/InputCommonConverter.cpp
+++ b/services/inputflinger/InputCommonConverter.cpp
@@ -263,8 +263,11 @@
static_assert(static_cast<common::Axis>(AMOTION_EVENT_AXIS_GENERIC_14) == common::Axis::GENERIC_14);
static_assert(static_cast<common::Axis>(AMOTION_EVENT_AXIS_GENERIC_15) == common::Axis::GENERIC_15);
static_assert(static_cast<common::Axis>(AMOTION_EVENT_AXIS_GENERIC_16) == common::Axis::GENERIC_16);
+// TODO(hcutts): add GESTURE_X_OFFSET and GESTURE_Y_OFFSET.
+// If you added a new axis, consider whether this should also be exposed as a HAL axis. Update the
+// static_assert below and add the new axis here, or leave a comment summarizing your decision.
static_assert(static_cast<common::Axis>(AMOTION_EVENT_MAXIMUM_VALID_AXIS_VALUE) ==
- static_cast<common::Axis>(AMOTION_EVENT_AXIS_GENERIC_16));
+ static_cast<common::Axis>(AMOTION_EVENT_AXIS_GESTURE_Y_OFFSET));
static common::VideoFrame getHalVideoFrame(const TouchVideoFrame& frame) {
common::VideoFrame out;
diff --git a/services/inputflinger/reader/mapper/TouchInputMapper.cpp b/services/inputflinger/reader/mapper/TouchInputMapper.cpp
index da58efd..7f6785e 100644
--- a/services/inputflinger/reader/mapper/TouchInputMapper.cpp
+++ b/services/inputflinger/reader/mapper/TouchInputMapper.cpp
@@ -3175,7 +3175,7 @@
mPointerGesture.referenceIdBits = mCurrentCookedState.fingerIdBits;
// Add delta for all fingers and calculate a common movement delta.
- float commonDeltaX = 0, commonDeltaY = 0;
+ int32_t commonDeltaRawX = 0, commonDeltaRawY = 0;
BitSet32 commonIdBits(mLastCookedState.fingerIdBits.value &
mCurrentCookedState.fingerIdBits.value);
for (BitSet32 idBits(commonIdBits); !idBits.isEmpty();) {
@@ -3188,11 +3188,11 @@
delta.dy += cpd.y - lpd.y;
if (first) {
- commonDeltaX = delta.dx;
- commonDeltaY = delta.dy;
+ commonDeltaRawX = delta.dx;
+ commonDeltaRawY = delta.dy;
} else {
- commonDeltaX = calculateCommonVector(commonDeltaX, delta.dx);
- commonDeltaY = calculateCommonVector(commonDeltaY, delta.dy);
+ commonDeltaRawX = calculateCommonVector(commonDeltaRawX, delta.dx);
+ commonDeltaRawY = calculateCommonVector(commonDeltaRawY, delta.dy);
}
}
@@ -3298,7 +3298,7 @@
// Move the reference points based on the overall group motion of the fingers
// except in PRESS mode while waiting for a transition to occur.
if (mPointerGesture.currentGestureMode != PointerGesture::Mode::PRESS &&
- (commonDeltaX || commonDeltaY)) {
+ (commonDeltaRawX || commonDeltaRawY)) {
for (BitSet32 idBits(mPointerGesture.referenceIdBits); !idBits.isEmpty();) {
uint32_t id = idBits.clearFirstMarkedBit();
PointerGesture::Delta& delta = mPointerGesture.referenceDeltas[id];
@@ -3306,11 +3306,11 @@
delta.dy = 0;
}
- mPointerGesture.referenceTouchX += commonDeltaX;
- mPointerGesture.referenceTouchY += commonDeltaY;
+ mPointerGesture.referenceTouchX += commonDeltaRawX;
+ mPointerGesture.referenceTouchY += commonDeltaRawY;
- commonDeltaX *= mPointerXMovementScale;
- commonDeltaY *= mPointerYMovementScale;
+ float commonDeltaX = commonDeltaRawX * mPointerXMovementScale;
+ float commonDeltaY = commonDeltaRawY * mPointerYMovementScale;
rotateDelta(mInputDeviceOrientation, &commonDeltaX, &commonDeltaY);
mPointerVelocityControl.move(when, &commonDeltaX, &commonDeltaY);
@@ -3341,6 +3341,16 @@
mPointerGesture.currentGestureCoords[0].setAxisValue(AMOTION_EVENT_AXIS_Y,
mPointerGesture.referenceGestureY);
mPointerGesture.currentGestureCoords[0].setAxisValue(AMOTION_EVENT_AXIS_PRESSURE, 1.0f);
+ if (mPointerGesture.currentGestureMode == PointerGesture::Mode::SWIPE) {
+ float xOffset = static_cast<float>(commonDeltaRawX) /
+ (mRawPointerAxes.x.maxValue - mRawPointerAxes.x.minValue);
+ float yOffset = static_cast<float>(commonDeltaRawY) /
+ (mRawPointerAxes.y.maxValue - mRawPointerAxes.y.minValue);
+ mPointerGesture.currentGestureCoords[0]
+ .setAxisValue(AMOTION_EVENT_AXIS_GESTURE_X_OFFSET, xOffset);
+ mPointerGesture.currentGestureCoords[0]
+ .setAxisValue(AMOTION_EVENT_AXIS_GESTURE_Y_OFFSET, yOffset);
+ }
} else if (mPointerGesture.currentGestureMode == PointerGesture::Mode::FREEFORM) {
// FREEFORM mode.
ALOGD_IF(DEBUG_GESTURES,
diff --git a/services/inputflinger/tests/InputReader_test.cpp b/services/inputflinger/tests/InputReader_test.cpp
index dded6a1..1e26265 100644
--- a/services/inputflinger/tests/InputReader_test.cpp
+++ b/services/inputflinger/tests/InputReader_test.cpp
@@ -10085,6 +10085,52 @@
0, 0, 0, 0, 0));
}
+TEST_F(MultiTouchPointerModeTest, TwoFingerSwipeOffsets) {
+ preparePointerMode(25 /*xResolution*/, 25 /*yResolution*/);
+ MultiTouchInputMapper& mapper = addMapperAndConfigure<MultiTouchInputMapper>();
+ NotifyMotionArgs motionArgs;
+
+ // Place two fingers down.
+ int32_t x1 = 100, y1 = 125, x2 = 550, y2 = 125;
+
+ processId(mapper, FIRST_TRACKING_ID);
+ processPosition(mapper, x1, y1);
+ processMTSync(mapper);
+ processId(mapper, SECOND_TRACKING_ID);
+ processPosition(mapper, x2, y2);
+ processMTSync(mapper);
+ processSync(mapper);
+
+ ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs));
+ ASSERT_EQ(1U, motionArgs.pointerCount);
+ ASSERT_EQ(AMOTION_EVENT_ACTION_DOWN, motionArgs.action);
+ ASSERT_EQ(MotionClassification::NONE, motionArgs.classification);
+ ASSERT_EQ(0, motionArgs.pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_GESTURE_X_OFFSET));
+ ASSERT_EQ(0, motionArgs.pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_GESTURE_Y_OFFSET));
+
+ // Move the two fingers down and to the left.
+ int32_t movingDistance = 200;
+ x1 -= movingDistance;
+ y1 += movingDistance;
+ x2 -= movingDistance;
+ y2 += movingDistance;
+
+ processId(mapper, FIRST_TRACKING_ID);
+ processPosition(mapper, x1, y1);
+ processMTSync(mapper);
+ processId(mapper, SECOND_TRACKING_ID);
+ processPosition(mapper, x2, y2);
+ processMTSync(mapper);
+ processSync(mapper);
+
+ ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs));
+ ASSERT_EQ(1U, motionArgs.pointerCount);
+ ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action);
+ ASSERT_EQ(MotionClassification::TWO_FINGER_SWIPE, motionArgs.classification);
+ ASSERT_LT(motionArgs.pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_GESTURE_X_OFFSET), 0);
+ ASSERT_GT(motionArgs.pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_GESTURE_Y_OFFSET), 0);
+}
+
// --- JoystickInputMapperTest ---
class JoystickInputMapperTest : public InputMapperTest {