Query InputState for pointer information when canceling a gesture
When the dispatcher produces a synthetic HOVER_EXIT or ACTION_CANCEL, it
relies on the InputState to get the correct coordinates of this event.
That's because these events should use the same coordinates as the last
dispatched HOVER_MOVE or ACTION_MOVE event, and this data is stored
inside InputState.
Before this CL, this logic was checked by "HoverIntoClone" test. When
this test ran, the dispatcher produced scary messages, saying that it
was canceling events because an inconsistent event was received. Another
test that had these logs was StylusHoverAndDownNoInputChannel. This
could also be easily reproduced by sending a HOVER_ENTER and then a
HOVER_EXIT. The HOVER_EXIT event would get rejected, and the dispatcher
would use InputState to generate its own.
Now with this CL, these messages are gone because the dispatcher is
querying for these coords proactively instead of using the cancellation
mechanism of InputState.
Bug: 317183325
Test: TEST=inputflinger_tests; m $TEST && $ANDROID_HOST_OUT/nativetest64/$TEST/$TEST --gtest_filter="*StylusHoverAndDownNoInputChannel"
Change-Id: I44a2446171ab5d2368d7b7f8d806e45d5bb855c0
diff --git a/services/inputflinger/dispatcher/InputDispatcher.cpp b/services/inputflinger/dispatcher/InputDispatcher.cpp
index 8d0ff4b..fa02a33 100644
--- a/services/inputflinger/dispatcher/InputDispatcher.cpp
+++ b/services/inputflinger/dispatcher/InputDispatcher.cpp
@@ -3389,27 +3389,40 @@
dispatchEntry->resolvedFlags = resolvedFlags;
if (resolvedAction != motionEntry.action) {
+ std::optional<std::vector<PointerProperties>> usingProperties;
+ std::optional<std::vector<PointerCoords>> usingCoords;
+ if (resolvedAction == AMOTION_EVENT_ACTION_HOVER_EXIT ||
+ resolvedAction == AMOTION_EVENT_ACTION_CANCEL) {
+ // This is a HOVER_EXIT or an ACTION_CANCEL event that was synthesized by
+ // the dispatcher, and therefore the coordinates of this event are currently
+ // incorrect. These events should use the coordinates of the last dispatched
+ // ACTION_MOVE or HOVER_MOVE. We need to query InputState to get this data.
+ const bool hovering = resolvedAction == AMOTION_EVENT_ACTION_HOVER_EXIT;
+ std::optional<std::pair<std::vector<PointerProperties>,
+ std::vector<PointerCoords>>>
+ pointerInfo =
+ connection->inputState.getPointersOfLastEvent(motionEntry,
+ hovering);
+ if (pointerInfo) {
+ usingProperties = pointerInfo->first;
+ usingCoords = pointerInfo->second;
+ }
+ }
// Generate a new MotionEntry with a new eventId using the resolved action and
// flags.
- resolvedMotion =
- std::make_shared<MotionEntry>(mIdGenerator.nextId(),
- motionEntry.injectionState,
- motionEntry.eventTime,
- motionEntry.deviceId, motionEntry.source,
- motionEntry.displayId,
- motionEntry.policyFlags, resolvedAction,
- motionEntry.actionButton, resolvedFlags,
- motionEntry.metaState,
- motionEntry.buttonState,
- motionEntry.classification,
- motionEntry.edgeFlags,
- motionEntry.xPrecision,
- motionEntry.yPrecision,
- motionEntry.xCursorPosition,
- motionEntry.yCursorPosition,
- motionEntry.downTime,
- motionEntry.pointerProperties,
- motionEntry.pointerCoords);
+ resolvedMotion = std::make_shared<
+ MotionEntry>(mIdGenerator.nextId(), motionEntry.injectionState,
+ motionEntry.eventTime, motionEntry.deviceId,
+ motionEntry.source, motionEntry.displayId,
+ motionEntry.policyFlags, resolvedAction,
+ motionEntry.actionButton, resolvedFlags,
+ motionEntry.metaState, motionEntry.buttonState,
+ motionEntry.classification, motionEntry.edgeFlags,
+ motionEntry.xPrecision, motionEntry.yPrecision,
+ motionEntry.xCursorPosition, motionEntry.yCursorPosition,
+ motionEntry.downTime,
+ usingProperties.value_or(motionEntry.pointerProperties),
+ usingCoords.value_or(motionEntry.pointerCoords));
if (ATRACE_ENABLED()) {
std::string message = StringPrintf("Transmute MotionEvent(id=0x%" PRIx32
") to MotionEvent(id=0x%" PRIx32 ").",