Use TWO_FINGER_SWIPE classification for touchpad scroll events
This allows apps to distinguish the fake finger created for touchpad
scrolling from an actual finger.
Bug: 246758376
Test: add classification to InputDispatcher's outbound event logs and
check the new value is used when scrolling
Change-Id: Ia90f9984e75ad6fde2d0e42628ab42eab371b7a5
diff --git a/include/android/input.h b/include/android/input.h
index 8cd9e95..7080386 100644
--- a/include/android/input.h
+++ b/include/android/input.h
@@ -840,6 +840,12 @@
* This classification type should be used to accelerate the long press behaviour.
*/
AMOTION_EVENT_CLASSIFICATION_DEEP_PRESS = 2,
+ /**
+ * Classification constant: touchpad two-finger swipe.
+ *
+ * The current event stream represents the user swiping with two fingers on a touchpad.
+ */
+ AMOTION_EVENT_CLASSIFICATION_TWO_FINGER_SWIPE = 3,
};
/**
diff --git a/include/input/Input.h b/include/input/Input.h
index 2dd651e..172e5b4 100644
--- a/include/input/Input.h
+++ b/include/input/Input.h
@@ -289,6 +289,10 @@
* The current gesture likely represents a user intentionally exerting force on the touchscreen.
*/
DEEP_PRESS = AMOTION_EVENT_CLASSIFICATION_DEEP_PRESS,
+ /**
+ * The current gesture represents the user swiping with two fingers on a touchpad.
+ */
+ TWO_FINGER_SWIPE = AMOTION_EVENT_CLASSIFICATION_TWO_FINGER_SWIPE,
};
/**
diff --git a/libs/input/Input.cpp b/libs/input/Input.cpp
index 2b7483d..579b28e 100644
--- a/libs/input/Input.cpp
+++ b/libs/input/Input.cpp
@@ -87,6 +87,8 @@
return "AMBIGUOUS_GESTURE";
case MotionClassification::DEEP_PRESS:
return "DEEP_PRESS";
+ case MotionClassification::TWO_FINGER_SWIPE:
+ return "TWO_FINGER_SWIPE";
}
}
diff --git a/services/inputflinger/InputProcessor.cpp b/services/inputflinger/InputProcessor.cpp
index 0749441..126cb33 100644
--- a/services/inputflinger/InputProcessor.cpp
+++ b/services/inputflinger/InputProcessor.cpp
@@ -22,6 +22,7 @@
#include <android-base/stringprintf.h>
#include <android/binder_manager.h>
#include <android/binder_process.h>
+#include <input/Input.h>
#include <inttypes.h>
#include <log/log.h>
#include <algorithm>
@@ -436,7 +437,13 @@
mQueuedListener.notifyMotion(args);
} else {
NotifyMotionArgs newArgs(*args);
- newArgs.classification = mMotionClassifier->classify(newArgs);
+ const MotionClassification newClassification = mMotionClassifier->classify(newArgs);
+ LOG_ALWAYS_FATAL_IF(args->classification != MotionClassification::NONE &&
+ newClassification != MotionClassification::NONE,
+ "Conflicting classifications %s (new) and %s (old)!",
+ motionClassificationToString(newClassification),
+ motionClassificationToString(args->classification));
+ newArgs.classification = newClassification;
mQueuedListener.notifyMotion(&newArgs);
}
} // release lock
diff --git a/services/inputflinger/reader/mapper/TouchInputMapper.cpp b/services/inputflinger/reader/mapper/TouchInputMapper.cpp
index 8c241f2..4cd2cce 100644
--- a/services/inputflinger/reader/mapper/TouchInputMapper.cpp
+++ b/services/inputflinger/reader/mapper/TouchInputMapper.cpp
@@ -1950,7 +1950,8 @@
mCurrentCookedState.cookedPointerData.pointerProperties,
mCurrentCookedState.cookedPointerData.pointerCoords,
mCurrentCookedState.cookedPointerData.idToIndex, currentIdBits, -1,
- mOrientedXPrecision, mOrientedYPrecision, mDownTime);
+ mOrientedXPrecision, mOrientedYPrecision, mDownTime,
+ MotionClassification::NONE);
mCurrentMotionAborted = true;
}
}
@@ -1970,7 +1971,8 @@
mCurrentCookedState.cookedPointerData.pointerProperties,
mCurrentCookedState.cookedPointerData.pointerCoords,
mCurrentCookedState.cookedPointerData.idToIndex, currentIdBits, -1,
- mOrientedXPrecision, mOrientedYPrecision, mDownTime);
+ mOrientedXPrecision, mOrientedYPrecision, mDownTime,
+ MotionClassification::NONE);
}
} else {
// There may be pointers going up and pointers going down and pointers moving
@@ -2005,7 +2007,8 @@
mLastCookedState.cookedPointerData.pointerProperties,
mLastCookedState.cookedPointerData.pointerCoords,
mLastCookedState.cookedPointerData.idToIndex, dispatchedIdBits, upId,
- mOrientedXPrecision, mOrientedYPrecision, mDownTime);
+ mOrientedXPrecision, mOrientedYPrecision, mDownTime,
+ MotionClassification::NONE);
dispatchedIdBits.clearBit(upId);
mCurrentCookedState.cookedPointerData.canceledIdBits.clearBit(upId);
}
@@ -2020,7 +2023,8 @@
mCurrentCookedState.cookedPointerData.pointerProperties,
mCurrentCookedState.cookedPointerData.pointerCoords,
mCurrentCookedState.cookedPointerData.idToIndex, dispatchedIdBits, -1,
- mOrientedXPrecision, mOrientedYPrecision, mDownTime);
+ mOrientedXPrecision, mOrientedYPrecision, mDownTime,
+ MotionClassification::NONE);
}
// Dispatch pointer down events using the new pointer locations.
@@ -2038,7 +2042,8 @@
mCurrentCookedState.cookedPointerData.pointerProperties,
mCurrentCookedState.cookedPointerData.pointerCoords,
mCurrentCookedState.cookedPointerData.idToIndex, dispatchedIdBits,
- downId, mOrientedXPrecision, mOrientedYPrecision, mDownTime);
+ downId, mOrientedXPrecision, mOrientedYPrecision, mDownTime,
+ MotionClassification::NONE);
}
}
}
@@ -2054,7 +2059,7 @@
mLastCookedState.cookedPointerData.pointerCoords,
mLastCookedState.cookedPointerData.idToIndex,
mLastCookedState.cookedPointerData.hoveringIdBits, -1, mOrientedXPrecision,
- mOrientedYPrecision, mDownTime);
+ mOrientedYPrecision, mDownTime, MotionClassification::NONE);
mSentHoverEnter = false;
}
}
@@ -2071,7 +2076,8 @@
mCurrentCookedState.cookedPointerData.pointerCoords,
mCurrentCookedState.cookedPointerData.idToIndex,
mCurrentCookedState.cookedPointerData.hoveringIdBits, -1,
- mOrientedXPrecision, mOrientedYPrecision, mDownTime);
+ mOrientedXPrecision, mOrientedYPrecision, mDownTime,
+ MotionClassification::NONE);
mSentHoverEnter = true;
}
@@ -2081,7 +2087,8 @@
mCurrentCookedState.cookedPointerData.pointerCoords,
mCurrentCookedState.cookedPointerData.idToIndex,
mCurrentCookedState.cookedPointerData.hoveringIdBits, -1,
- mOrientedXPrecision, mOrientedYPrecision, mDownTime);
+ mOrientedXPrecision, mOrientedYPrecision, mDownTime,
+ MotionClassification::NONE);
}
}
@@ -2098,7 +2105,8 @@
mCurrentCookedState.cookedPointerData.pointerProperties,
mCurrentCookedState.cookedPointerData.pointerCoords,
mCurrentCookedState.cookedPointerData.idToIndex, idBits, -1,
- mOrientedXPrecision, mOrientedYPrecision, mDownTime);
+ mOrientedXPrecision, mOrientedYPrecision, mDownTime,
+ MotionClassification::NONE);
}
}
@@ -2115,7 +2123,8 @@
mCurrentCookedState.cookedPointerData.pointerProperties,
mCurrentCookedState.cookedPointerData.pointerCoords,
mCurrentCookedState.cookedPointerData.idToIndex, idBits, -1,
- mOrientedXPrecision, mOrientedYPrecision, mDownTime);
+ mOrientedXPrecision, mOrientedYPrecision, mDownTime,
+ MotionClassification::NONE);
}
}
@@ -2502,6 +2511,10 @@
// Send events!
int32_t metaState = getContext()->getGlobalMetaState();
int32_t buttonState = mCurrentCookedState.buttonState;
+ const MotionClassification classification =
+ mPointerGesture.currentGestureMode == PointerGesture::Mode::SWIPE
+ ? MotionClassification::TWO_FINGER_SWIPE
+ : MotionClassification::NONE;
uint32_t flags = 0;
@@ -2542,7 +2555,7 @@
flags, metaState, buttonState, AMOTION_EVENT_EDGE_FLAG_NONE,
mPointerGesture.lastGestureProperties, mPointerGesture.lastGestureCoords,
mPointerGesture.lastGestureIdToIndex, dispatchedGestureIdBits, -1, 0, 0,
- mPointerGesture.downTime);
+ mPointerGesture.downTime, classification);
dispatchedGestureIdBits.clear();
} else {
@@ -2561,7 +2574,7 @@
AMOTION_EVENT_EDGE_FLAG_NONE, mPointerGesture.lastGestureProperties,
mPointerGesture.lastGestureCoords,
mPointerGesture.lastGestureIdToIndex, dispatchedGestureIdBits, id, 0,
- 0, mPointerGesture.downTime);
+ 0, mPointerGesture.downTime, classification);
dispatchedGestureIdBits.clearBit(id);
}
@@ -2575,7 +2588,7 @@
mPointerGesture.currentGestureProperties,
mPointerGesture.currentGestureCoords,
mPointerGesture.currentGestureIdToIndex, dispatchedGestureIdBits, -1, 0, 0,
- mPointerGesture.downTime);
+ mPointerGesture.downTime, classification);
}
// Send motion events for all pointers that went down.
@@ -2595,7 +2608,7 @@
mPointerGesture.currentGestureProperties,
mPointerGesture.currentGestureCoords,
mPointerGesture.currentGestureIdToIndex, dispatchedGestureIdBits, id, 0,
- 0, mPointerGesture.downTime);
+ 0, mPointerGesture.downTime, classification);
}
}
@@ -2606,7 +2619,8 @@
mPointerGesture.currentGestureProperties,
mPointerGesture.currentGestureCoords,
mPointerGesture.currentGestureIdToIndex,
- mPointerGesture.currentGestureIdBits, -1, 0, 0, mPointerGesture.downTime);
+ mPointerGesture.currentGestureIdBits, -1, 0, 0, mPointerGesture.downTime,
+ MotionClassification::NONE);
} else if (dispatchedGestureIdBits.isEmpty() && !mPointerGesture.lastGestureIdBits.isEmpty()) {
// Synthesize a hover move event after all pointers go up to indicate that
// the pointer is hovering again even if the user is not currently touching
@@ -2653,6 +2667,10 @@
}
void TouchInputMapper::abortPointerGestures(nsecs_t when, nsecs_t readTime, uint32_t policyFlags) {
+ const MotionClassification classification =
+ mPointerGesture.lastGestureMode == PointerGesture::Mode::SWIPE
+ ? MotionClassification::TWO_FINGER_SWIPE
+ : MotionClassification::NONE;
// Cancel previously dispatches pointers.
if (!mPointerGesture.lastGestureIdBits.isEmpty()) {
int32_t metaState = getContext()->getGlobalMetaState();
@@ -2661,7 +2679,7 @@
metaState, buttonState, AMOTION_EVENT_EDGE_FLAG_NONE,
mPointerGesture.lastGestureProperties, mPointerGesture.lastGestureCoords,
mPointerGesture.lastGestureIdToIndex, mPointerGesture.lastGestureIdBits, -1,
- 0, 0, mPointerGesture.downTime);
+ 0, 0, mPointerGesture.downTime, classification);
}
// Reset the current pointer gesture.
@@ -3611,7 +3629,8 @@
int32_t edgeFlags, const PointerProperties* properties,
const PointerCoords* coords, const uint32_t* idToIndex,
BitSet32 idBits, int32_t changedId, float xPrecision,
- float yPrecision, nsecs_t downTime) {
+ float yPrecision, nsecs_t downTime,
+ MotionClassification classification) {
PointerCoords pointerCoords[MAX_POINTERS];
PointerProperties pointerProperties[MAX_POINTERS];
uint32_t pointerCount = 0;
@@ -3659,9 +3678,9 @@
[this](TouchVideoFrame& frame) { frame.rotate(this->mInputDeviceOrientation); });
NotifyMotionArgs args(getContext()->getNextId(), when, readTime, deviceId, source, displayId,
policyFlags, action, actionButton, flags, metaState, buttonState,
- MotionClassification::NONE, edgeFlags, pointerCount, pointerProperties,
- pointerCoords, xPrecision, yPrecision, xCursorPosition, yCursorPosition,
- downTime, std::move(frames));
+ classification, edgeFlags, pointerCount, pointerProperties, pointerCoords,
+ xPrecision, yPrecision, xCursorPosition, yCursorPosition, downTime,
+ std::move(frames));
getListener().notifyMotion(&args);
}
diff --git a/services/inputflinger/reader/mapper/TouchInputMapper.h b/services/inputflinger/reader/mapper/TouchInputMapper.h
index bd4cff6..31806e1 100644
--- a/services/inputflinger/reader/mapper/TouchInputMapper.h
+++ b/services/inputflinger/reader/mapper/TouchInputMapper.h
@@ -779,7 +779,8 @@
int32_t action, int32_t actionButton, int32_t flags, int32_t metaState,
int32_t buttonState, int32_t edgeFlags, const PointerProperties* properties,
const PointerCoords* coords, const uint32_t* idToIndex, BitSet32 idBits,
- int32_t changedId, float xPrecision, float yPrecision, nsecs_t downTime);
+ int32_t changedId, float xPrecision, float yPrecision, nsecs_t downTime,
+ MotionClassification classification);
// Updates pointer coords and properties for pointers with specified ids that have moved.
// Returns true if any of them changed.
diff --git a/services/inputflinger/tests/InputReader_test.cpp b/services/inputflinger/tests/InputReader_test.cpp
index ee6993c..097659b 100644
--- a/services/inputflinger/tests/InputReader_test.cpp
+++ b/services/inputflinger/tests/InputReader_test.cpp
@@ -9751,6 +9751,7 @@
ASSERT_EQ(1U, motionArgs.pointerCount);
ASSERT_EQ(AMOTION_EVENT_ACTION_DOWN, motionArgs.action);
ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[0].toolType);
+ ASSERT_EQ(MotionClassification::NONE, motionArgs.classification);
ASSERT_NO_FATAL_FAILURE(
assertPointerCoords(motionArgs.pointerCoords[0], 0, 0, 1, 0, 0, 0, 0, 0, 0, 0));
@@ -9772,6 +9773,7 @@
ASSERT_EQ(1U, motionArgs.pointerCount);
ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action);
ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[0].toolType);
+ ASSERT_EQ(MotionClassification::TWO_FINGER_SWIPE, motionArgs.classification);
ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0], 0,
movingDistance * mPointerMovementScale, 1, 0, 0, 0,
0, 0, 0, 0));
@@ -9809,6 +9811,7 @@
ASSERT_EQ(1U, motionArgs.pointerCount);
ASSERT_EQ(AMOTION_EVENT_ACTION_DOWN, motionArgs.action);
ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[0].toolType);
+ ASSERT_EQ(MotionClassification::NONE, motionArgs.classification);
ASSERT_NO_FATAL_FAILURE(
assertPointerCoords(motionArgs.pointerCoords[0], 0, 0, 1, 0, 0, 0, 0, 0, 0, 0));
@@ -9830,6 +9833,7 @@
ASSERT_EQ(1U, motionArgs.pointerCount);
ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action);
ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[0].toolType);
+ ASSERT_EQ(MotionClassification::TWO_FINGER_SWIPE, motionArgs.classification);
// New coordinate is the scaled relative coordinate from the initial coordinate.
ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0], 0,
movingDistance * mPointerMovementScale, 1, 0, 0, 0,
@@ -9863,6 +9867,7 @@
ASSERT_EQ(1U, motionArgs.pointerCount);
ASSERT_EQ(AMOTION_EVENT_ACTION_DOWN, motionArgs.action);
ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[0].toolType);
+ ASSERT_EQ(MotionClassification::NONE, motionArgs.classification);
// One pointer for PRESS, and its coordinate is used as the origin for pointer coordinates.
ASSERT_NO_FATAL_FAILURE(
assertPointerCoords(motionArgs.pointerCoords[0], 0, 0, 1, 0, 0, 0, 0, 0, 0, 0));
@@ -9892,9 +9897,11 @@
ASSERT_EQ(AMOTION_EVENT_ACTION_DOWN, motionArgs.action);
ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs));
ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[0].toolType);
+ ASSERT_EQ(MotionClassification::NONE, motionArgs.classification);
ASSERT_EQ(2U, motionArgs.pointerCount);
ASSERT_EQ(AMOTION_EVENT_ACTION_POINTER_DOWN, motionArgs.action & AMOTION_EVENT_ACTION_MASK);
ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[0].toolType);
+ ASSERT_EQ(MotionClassification::NONE, motionArgs.classification);
// Two pointers' scaled relative coordinates from their initial centroid.
// Initial y coordinates are 0 as y1 and y2 have the same value.
float cookedX1 = (x1 - x2) / 2 * mPointerXZoomScale;
@@ -9924,6 +9931,7 @@
ASSERT_EQ(2U, motionArgs.pointerCount);
ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action);
ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[0].toolType);
+ ASSERT_EQ(MotionClassification::NONE, motionArgs.classification);
ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0], cookedX1,
movingDistance * 2 * mPointerMovementScale, 1, 0, 0,
0, 0, 0, 0, 0));