Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit e9ef6bc8 authored by Siarhei Vishniakou's avatar Siarhei Vishniakou
Browse files

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
parent e0cafbac
Loading
Loading
Loading
Loading
+32 −19
Original line number Diff line number Diff line
@@ -3389,27 +3389,40 @@ void InputDispatcher::enqueueDispatchEntryLocked(const std::shared_ptr<Connectio

                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,
                    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.metaState, motionEntry.buttonState,
                                         motionEntry.classification, motionEntry.edgeFlags,
                                         motionEntry.xPrecision, motionEntry.yPrecision,
                                         motionEntry.xCursorPosition, motionEntry.yCursorPosition,
                                         motionEntry.downTime,
                                                          motionEntry.pointerProperties,
                                                          motionEntry.pointerCoords);
                                         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 ").",
+10 −10
Original line number Diff line number Diff line
@@ -195,6 +195,16 @@ bool InputState::trackMotion(const MotionEntry& entry, int32_t flags) {
    }
}

std::optional<std::pair<std::vector<PointerProperties>, std::vector<PointerCoords>>>
InputState::getPointersOfLastEvent(const MotionEntry& entry, bool hovering) const {
    ssize_t index = findMotionMemento(entry, hovering);
    if (index == -1) {
        return std::nullopt;
    }
    return std::make_pair(mMotionMementos[index].pointerProperties,
                          mMotionMementos[index].pointerCoords);
}

ssize_t InputState::findKeyMemento(const KeyEntry& entry) const {
    for (size_t i = 0; i < mKeyMementos.size(); i++) {
        const KeyMemento& memento = mKeyMementos[i];
@@ -311,16 +321,6 @@ bool InputState::shouldCancelPreviousStream(const MotionEntry& motionEntry) cons
            return true;
        }

        // Use the previous stream cancellation logic to generate all HOVER_EXIT events.
        // If this hover event was generated as a result of the pointer leaving the window,
        // the HOVER_EXIT event should have the same coordinates as the previous
        // HOVER_MOVE event in this stream. Ensure that all HOVER_EXITs have the same
        // coordinates as the previous event by cancelling the stream here. With this approach, the
        // HOVER_EXIT event is generated from the previous event.
        if (actionMasked == AMOTION_EVENT_ACTION_HOVER_EXIT && lastMemento.hovering) {
            return true;
        }

        // If the stream changes its source, just cancel the current gesture to be safe. It's
        // possible that the app isn't handling source changes properly
        if (motionEntry.source != lastMemento.source) {
+9 −0
Original line number Diff line number Diff line
@@ -48,6 +48,15 @@ public:
    // and should be skipped.
    bool trackMotion(const MotionEntry& entry, int32_t flags);

    /**
     * Return the PointerProperties and the PointerCoords for the last event, if found. Return
     * std::nullopt if not found. We should not return std::vector<PointerCoords> in isolation,
     * because the pointers can technically be stored in the vector in any order, so the
     * PointerProperties are needed to specify the order in which the pointer coords are stored.
     */
    std::optional<std::pair<std::vector<PointerProperties>, std::vector<PointerCoords>>>
    getPointersOfLastEvent(const MotionEntry& entry, bool hovering) const;

    // Create cancel events for the previous stream if the current motionEntry requires it.
    std::unique_ptr<EventEntry> cancelConflictingInputStream(const MotionEntry& motionEntry);