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

Commit 2a2da1d8 authored by Prabir Pradhan's avatar Prabir Pradhan
Browse files

InputDispatcher: Establish 1:1 relation between eventId and EventEntry

Previously, one event could be dispatched as events with different
actions and flags to different windows. For example, a HOVER_MOVE
event can technically be dispatched as HOVER_ENTER, HOVER_MOVE, or
HOVER_EXIT. We achieved this by "overriding" the action and flags
in the EventEntry using the DispatchEntry. This was further complicated
by the fact that we wanted to generate a new eventId in some cases
and not in others.

To simplify this logic, we will establish a 1:1 relationship between
eventId and EventEntry, so that eventIds will never be overridden
during dispatch. We will also simplify things further by using a new
eventId (therefore also creating a new EventEntry) whenever the action
of an event is to change. There will no longer be an action override
in DispatchEntry either.

Even after this change, there are still fields that will need to be
modified for each DispatchEntry, namely the flags and coordinates
that take the window/display transforms into account, so this change
is not intended to create a 1:1 relation between eventId and outbound
events from InputDispatcher.

Bug: 210460522
Test: atest inputflinger_tests
Change-Id: I158267081814d856d7fedf05c02c284717533d6c
parent 24047542
Loading
Loading
Loading
Loading
+1 −22
Original line number Diff line number Diff line
@@ -287,21 +287,15 @@ DispatchEntry::DispatchEntry(std::shared_ptr<const EventEntry> eventEntry,
        rawTransform(rawTransform),
        globalScaleFactor(globalScaleFactor),
        deliveryTime(0),
        resolvedAction(0),
        resolvedFlags(0) {
    switch (this->eventEntry->type) {
        case EventEntry::Type::KEY: {
            const KeyEntry& keyEntry = static_cast<const KeyEntry&>(*this->eventEntry);
            resolvedEventId = keyEntry.id;
            resolvedAction = keyEntry.action;
            resolvedFlags = keyEntry.flags;

            break;
        }
        case EventEntry::Type::MOTION: {
            const MotionEntry& motionEntry = static_cast<const MotionEntry&>(*this->eventEntry);
            resolvedEventId = motionEntry.id;
            resolvedAction = motionEntry.action;
            resolvedFlags = motionEntry.flags;
            break;
        }
@@ -321,24 +315,9 @@ uint32_t DispatchEntry::nextSeq() {
}

std::ostream& operator<<(std::ostream& out, const DispatchEntry& entry) {
    out << "DispatchEntry{resolvedAction=";
    switch (entry.eventEntry->type) {
        case EventEntry::Type::KEY: {
            out << KeyEvent::actionToString(entry.resolvedAction);
            break;
        }
        case EventEntry::Type::MOTION: {
            out << MotionEvent::actionToString(entry.resolvedAction);
            break;
        }
        default: {
            out << "<invalid, not a key or a motion>";
            break;
        }
    }
    std::string transform;
    entry.transform.dump(transform, "transform");
    out << ", resolvedFlags=" << entry.resolvedFlags
    out << "DispatchEntry{resolvedFlags=" << entry.resolvedFlags
        << ", targetFlags=" << entry.targetFlags.string() << ", transform=" << transform
        << "} original: " << entry.eventEntry->getDescription();
    return out;
+0 −3
Original line number Diff line number Diff line
@@ -220,9 +220,6 @@ struct DispatchEntry {
    // An ANR will be triggered if a response for this entry is not received by timeoutTime
    nsecs_t timeoutTime;

    // Set to the resolved ID, action and flags when the event is enqueued.
    int32_t resolvedEventId;
    int32_t resolvedAction;
    int32_t resolvedFlags;

    DispatchEntry(std::shared_ptr<const EventEntry> eventEntry,
+106 −94
Original line number Diff line number Diff line
@@ -295,9 +295,8 @@ std::string dumpQueue(const std::deque<std::unique_ptr<DispatchEntry>>& queue,
        }
        dump.append(INDENT4);
        dump += entry.eventEntry->getDescription();
        dump += StringPrintf(", seq=%" PRIu32 ", targetFlags=%s, resolvedAction=%d, age=%" PRId64
                             "ms",
                             entry.seq, entry.targetFlags.string().c_str(), entry.resolvedAction,
        dump += StringPrintf(", seq=%" PRIu32 ", targetFlags=%s, age=%" PRId64 "ms", entry.seq,
                             entry.targetFlags.string().c_str(),
                             ns2ms(currentTime - entry.eventEntry->eventTime));
        if (entry.deliveryTime != 0) {
            // This entry was delivered, so add information on how long we've been waiting
@@ -455,10 +454,6 @@ bool shouldReportMetricsForConnection(const Connection& connection) {
bool shouldReportFinishedEvent(const DispatchEntry& dispatchEntry, const Connection& connection) {
    const EventEntry& eventEntry = *dispatchEntry.eventEntry;
    const int32_t& inputEventId = eventEntry.id;
    if (inputEventId != dispatchEntry.resolvedEventId) {
        // Event was transmuted
        return false;
    }
    if (inputEventId == android::os::IInputConstants::INVALID_INPUT_EVENT_ID) {
        return false;
    }
@@ -3333,13 +3328,12 @@ void InputDispatcher::enqueueDispatchEntryLocked(const std::shared_ptr<Connectio

    // Use the eventEntry from dispatchEntry since the entry may have changed and can now be a
    // different EventEntry than what was passed in.
    const EventEntry& newEntry = *(dispatchEntry->eventEntry);
    eventEntry = dispatchEntry->eventEntry;
    // Apply target flags and update the connection's input state.
    switch (newEntry.type) {
    switch (eventEntry->type) {
        case EventEntry::Type::KEY: {
            const KeyEntry& keyEntry = static_cast<const KeyEntry&>(newEntry);
            if (!connection->inputState.trackKey(keyEntry, dispatchEntry->resolvedAction,
                                                 dispatchEntry->resolvedFlags)) {
            const KeyEntry& keyEntry = static_cast<const KeyEntry&>(*eventEntry);
            if (!connection->inputState.trackKey(keyEntry, keyEntry.flags)) {
                LOG(WARNING) << "channel " << connection->getInputChannelName()
                             << "~ dropping inconsistent event: " << *dispatchEntry;
                return; // skip the inconsistent event
@@ -3348,58 +3342,90 @@ void InputDispatcher::enqueueDispatchEntryLocked(const std::shared_ptr<Connectio
        }

        case EventEntry::Type::MOTION: {
            const MotionEntry& motionEntry = static_cast<const MotionEntry&>(newEntry);
            // Assign a default value to dispatchEntry that will never be generated by InputReader,
            // and assign a InputDispatcher value if it doesn't change in the if-else chain below.
            constexpr int32_t DEFAULT_RESOLVED_EVENT_ID =
                    static_cast<int32_t>(IdGenerator::Source::OTHER);
            dispatchEntry->resolvedEventId = DEFAULT_RESOLVED_EVENT_ID;
            std::shared_ptr<const MotionEntry> resolvedMotion =
                    std::static_pointer_cast<const MotionEntry>(eventEntry);
            {
                // Determine the resolved motion entry.
                const MotionEntry& motionEntry = static_cast<const MotionEntry&>(*eventEntry);
                int32_t resolvedAction = motionEntry.action;
                int32_t resolvedFlags = motionEntry.flags;

                if (dispatchMode.test(InputTarget::Flags::DISPATCH_AS_OUTSIDE)) {
                dispatchEntry->resolvedAction = AMOTION_EVENT_ACTION_OUTSIDE;
                    resolvedAction = AMOTION_EVENT_ACTION_OUTSIDE;
                } else if (dispatchMode.test(InputTarget::Flags::DISPATCH_AS_HOVER_EXIT)) {
                dispatchEntry->resolvedAction = AMOTION_EVENT_ACTION_HOVER_EXIT;
                    resolvedAction = AMOTION_EVENT_ACTION_HOVER_EXIT;
                } else if (dispatchMode.test(InputTarget::Flags::DISPATCH_AS_HOVER_ENTER)) {
                dispatchEntry->resolvedAction = AMOTION_EVENT_ACTION_HOVER_ENTER;
                    resolvedAction = AMOTION_EVENT_ACTION_HOVER_ENTER;
                } else if (dispatchMode.test(InputTarget::Flags::DISPATCH_AS_SLIPPERY_EXIT)) {
                dispatchEntry->resolvedAction = AMOTION_EVENT_ACTION_CANCEL;
                    resolvedAction = AMOTION_EVENT_ACTION_CANCEL;
                } else if (dispatchMode.test(InputTarget::Flags::DISPATCH_AS_SLIPPERY_ENTER)) {
                dispatchEntry->resolvedAction = AMOTION_EVENT_ACTION_DOWN;
            } else {
                dispatchEntry->resolvedEventId = motionEntry.id;
                    resolvedAction = AMOTION_EVENT_ACTION_DOWN;
                }
            if (dispatchEntry->resolvedAction == AMOTION_EVENT_ACTION_HOVER_MOVE &&
                if (resolvedAction == AMOTION_EVENT_ACTION_HOVER_MOVE &&
                    !connection->inputState.isHovering(motionEntry.deviceId, motionEntry.source,
                                                       motionEntry.displayId)) {
                    if (DEBUG_DISPATCH_CYCLE) {
                    ALOGD("channel '%s' ~ enqueueDispatchEntryLocked: filling in missing hover "
                          "enter event",
                          connection->getInputChannelName().c_str());
                        LOG(DEBUG) << "channel '" << connection->getInputChannelName().c_str()
                                   << "' ~ enqueueDispatchEntryLocked: filling in missing hover "
                                      "enter event";
                    }
                // We keep the 'resolvedEventId' here equal to the original 'motionEntry.id' because
                // this is a one-to-one event conversion.
                dispatchEntry->resolvedAction = AMOTION_EVENT_ACTION_HOVER_ENTER;
                    resolvedAction = AMOTION_EVENT_ACTION_HOVER_ENTER;
                }

            if (dispatchEntry->resolvedAction == AMOTION_EVENT_ACTION_CANCEL) {
                dispatchEntry->resolvedFlags |= AMOTION_EVENT_FLAG_CANCELED;
                if (resolvedAction == AMOTION_EVENT_ACTION_CANCEL) {
                    resolvedFlags |= AMOTION_EVENT_FLAG_CANCELED;
                }
                if (dispatchEntry->targetFlags.test(InputTarget::Flags::WINDOW_IS_OBSCURED)) {
                dispatchEntry->resolvedFlags |= AMOTION_EVENT_FLAG_WINDOW_IS_OBSCURED;
                    resolvedFlags |= AMOTION_EVENT_FLAG_WINDOW_IS_OBSCURED;
                }
                if (dispatchEntry->targetFlags.test(
                            InputTarget::Flags::WINDOW_IS_PARTIALLY_OBSCURED)) {
                    resolvedFlags |= AMOTION_EVENT_FLAG_WINDOW_IS_PARTIALLY_OBSCURED;
                }

                dispatchEntry->resolvedFlags = resolvedFlags;
                if (resolvedAction != motionEntry.action) {
                    // 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);
                    if (ATRACE_ENABLED()) {
                        std::string message = StringPrintf("Transmute MotionEvent(id=0x%" PRIx32
                                                           ") to MotionEvent(id=0x%" PRIx32 ").",
                                                           motionEntry.id, resolvedMotion->id);
                        ATRACE_NAME(message.c_str());
                    }

                    // Set the resolved motion entry in the DispatchEntry.
                    dispatchEntry->eventEntry = resolvedMotion;
                    eventEntry = resolvedMotion;
                }
            if (dispatchEntry->targetFlags.test(InputTarget::Flags::WINDOW_IS_PARTIALLY_OBSCURED)) {
                dispatchEntry->resolvedFlags |= AMOTION_EVENT_FLAG_WINDOW_IS_PARTIALLY_OBSCURED;
            }

            // Check if we need to cancel any of the ongoing gestures. We don't support multiple
            // devices being active at the same time in the same window, so if a new device is
            // active, cancel the gesture from the old device.

            std::unique_ptr<EventEntry> cancelEvent =
                    connection->inputState
                            .cancelConflictingInputStream(motionEntry,
                                                          dispatchEntry->resolvedAction);
                    connection->inputState.cancelConflictingInputStream(*resolvedMotion);
            if (cancelEvent != nullptr) {
                LOG(INFO) << "Canceling pointers for device " << motionEntry.deviceId << " in "
                LOG(INFO) << "Canceling pointers for device " << resolvedMotion->deviceId << " in "
                          << connection->getInputChannelName() << " with event "
                          << cancelEvent->getDescription();
                std::unique_ptr<DispatchEntry> cancelDispatchEntry =
@@ -3411,31 +3437,20 @@ void InputDispatcher::enqueueDispatchEntryLocked(const std::shared_ptr<Connectio
                connection->outboundQueue.emplace_back(std::move(cancelDispatchEntry));
            }

            if (!connection->inputState.trackMotion(motionEntry, dispatchEntry->resolvedAction,
            if (!connection->inputState.trackMotion(*resolvedMotion,
                                                    dispatchEntry->resolvedFlags)) {
                LOG(WARNING) << "channel " << connection->getInputChannelName()
                             << "~ dropping inconsistent event: " << *dispatchEntry;
                return; // skip the inconsistent event
            }

            dispatchEntry->resolvedEventId =
                    dispatchEntry->resolvedEventId == DEFAULT_RESOLVED_EVENT_ID
                    ? mIdGenerator.nextId()
                    : motionEntry.id;
            if (ATRACE_ENABLED() && dispatchEntry->resolvedEventId != motionEntry.id) {
                std::string message = StringPrintf("Transmute MotionEvent(id=0x%" PRIx32
                                                   ") to MotionEvent(id=0x%" PRIx32 ").",
                                                   motionEntry.id, dispatchEntry->resolvedEventId);
                ATRACE_NAME(message.c_str());
            }

            if ((motionEntry.flags & AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE) &&
                (motionEntry.policyFlags & POLICY_FLAG_TRUSTED)) {
            if ((resolvedMotion->flags & AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE) &&
                (resolvedMotion->policyFlags & POLICY_FLAG_TRUSTED)) {
                // Skip reporting pointer down outside focus to the policy.
                break;
            }

            dispatchPointerDownOutsideFocus(motionEntry.source, dispatchEntry->resolvedAction,
            dispatchPointerDownOutsideFocus(resolvedMotion->source, resolvedMotion->action,
                                            inputTarget.inputChannel->getConnectionToken());

            break;
@@ -3453,14 +3468,14 @@ void InputDispatcher::enqueueDispatchEntryLocked(const std::shared_ptr<Connectio
        case EventEntry::Type::CONFIGURATION_CHANGED:
        case EventEntry::Type::DEVICE_RESET: {
            LOG_ALWAYS_FATAL("%s events should not go to apps",
                             ftl::enum_string(newEntry.type).c_str());
                             ftl::enum_string(eventEntry->type).c_str());
            break;
        }
    }

    // Remember that we are waiting for this dispatch to complete.
    if (dispatchEntry->hasForegroundTarget()) {
        incrementPendingForegroundDispatches(newEntry);
        incrementPendingForegroundDispatches(*eventEntry);
    }

    // Enqueue the dispatch entry.
@@ -3609,18 +3624,17 @@ status_t InputDispatcher::publishMotionEvent(Connection& connection,

    // Publish the motion event.
    return connection.inputPublisher
            .publishMotionEvent(dispatchEntry.seq, dispatchEntry.resolvedEventId,
                                motionEntry.deviceId, motionEntry.source, motionEntry.displayId,
                                std::move(hmac), dispatchEntry.resolvedAction,
                                motionEntry.actionButton, dispatchEntry.resolvedFlags,
                                motionEntry.edgeFlags, motionEntry.metaState,
                                motionEntry.buttonState, motionEntry.classification,
                                dispatchEntry.transform, motionEntry.xPrecision,
                                motionEntry.yPrecision, motionEntry.xCursorPosition,
                                motionEntry.yCursorPosition, dispatchEntry.rawTransform,
                                motionEntry.downTime, motionEntry.eventTime,
                                motionEntry.getPointerCount(), motionEntry.pointerProperties.data(),
                                usingCoords);
            .publishMotionEvent(dispatchEntry.seq, motionEntry.id, motionEntry.deviceId,
                                motionEntry.source, motionEntry.displayId, std::move(hmac),
                                motionEntry.action, motionEntry.actionButton,
                                dispatchEntry.resolvedFlags, motionEntry.edgeFlags,
                                motionEntry.metaState, motionEntry.buttonState,
                                motionEntry.classification, dispatchEntry.transform,
                                motionEntry.xPrecision, motionEntry.yPrecision,
                                motionEntry.xCursorPosition, motionEntry.yCursorPosition,
                                dispatchEntry.rawTransform, motionEntry.downTime,
                                motionEntry.eventTime, motionEntry.getPointerCount(),
                                motionEntry.pointerProperties.data(), usingCoords);
}

void InputDispatcher::startDispatchCycleLocked(nsecs_t currentTime,
@@ -3652,14 +3666,13 @@ void InputDispatcher::startDispatchCycleLocked(nsecs_t currentTime,

                // Publish the key event.
                status = connection->inputPublisher
                                 .publishKeyEvent(dispatchEntry->seq,
                                                  dispatchEntry->resolvedEventId, keyEntry.deviceId,
                                                  keyEntry.source, keyEntry.displayId,
                                                  std::move(hmac), dispatchEntry->resolvedAction,
                                                  dispatchEntry->resolvedFlags, keyEntry.keyCode,
                                                  keyEntry.scanCode, keyEntry.metaState,
                                                  keyEntry.repeatCount, keyEntry.downTime,
                                                  keyEntry.eventTime);
                                 .publishKeyEvent(dispatchEntry->seq, keyEntry.id,
                                                  keyEntry.deviceId, keyEntry.source,
                                                  keyEntry.displayId, std::move(hmac),
                                                  keyEntry.action, dispatchEntry->resolvedFlags,
                                                  keyEntry.keyCode, keyEntry.scanCode,
                                                  keyEntry.metaState, keyEntry.repeatCount,
                                                  keyEntry.downTime, keyEntry.eventTime);
                break;
            }

@@ -3777,7 +3790,7 @@ std::array<uint8_t, 32> InputDispatcher::sign(const VerifiedInputEvent& event) c

const std::array<uint8_t, 32> InputDispatcher::getSignature(
        const MotionEntry& motionEntry, const DispatchEntry& dispatchEntry) const {
    const int32_t actionMasked = MotionEvent::getActionMasked(dispatchEntry.resolvedAction);
    const int32_t actionMasked = MotionEvent::getActionMasked(motionEntry.action);
    if (actionMasked != AMOTION_EVENT_ACTION_UP && actionMasked != AMOTION_EVENT_ACTION_DOWN) {
        // Only sign events up and down events as the purely move events
        // are tied to their up/down counterparts so signing would be redundant.
@@ -3795,7 +3808,6 @@ const std::array<uint8_t, 32> InputDispatcher::getSignature(
        const KeyEntry& keyEntry, const DispatchEntry& dispatchEntry) const {
    VerifiedKeyEvent verifiedEvent = verifiedKeyEventFromKeyEntry(keyEntry);
    verifiedEvent.flags = dispatchEntry.resolvedFlags & VERIFIED_KEY_EVENT_FLAGS;
    verifiedEvent.action = dispatchEntry.resolvedAction;
    return sign(verifiedEvent);
}

+10 −11
Original line number Diff line number Diff line
@@ -38,8 +38,8 @@ bool InputState::isHovering(DeviceId deviceId, uint32_t source, int32_t displayI
    return false;
}

bool InputState::trackKey(const KeyEntry& entry, int32_t action, int32_t flags) {
    switch (action) {
bool InputState::trackKey(const KeyEntry& entry, int32_t flags) {
    switch (entry.action) {
        case AKEY_EVENT_ACTION_UP: {
            if (entry.flags & AKEY_EVENT_FLAG_FALLBACK) {
                std::erase_if(mFallbackKeys,
@@ -88,7 +88,7 @@ bool InputState::trackKey(const KeyEntry& entry, int32_t action, int32_t flags)
 *  true if the incoming event was correctly tracked,
 *  false if the incoming event should be dropped.
 */
bool InputState::trackMotion(const MotionEntry& entry, int32_t action, int32_t flags) {
bool InputState::trackMotion(const MotionEntry& entry, int32_t flags) {
    // Don't track non-pointer events
    if (!isFromSource(entry.source, AINPUT_SOURCE_CLASS_POINTER)) {
        // This is a focus-dispatched event; we don't track its state.
@@ -104,7 +104,7 @@ bool InputState::trackMotion(const MotionEntry& entry, int32_t action, int32_t f
        }
    }

    int32_t actionMasked = action & AMOTION_EVENT_ACTION_MASK;
    int32_t actionMasked = entry.action & AMOTION_EVENT_ACTION_MASK;
    switch (actionMasked) {
        case AMOTION_EVENT_ACTION_UP:
        case AMOTION_EVENT_ACTION_CANCEL: {
@@ -281,8 +281,7 @@ size_t InputState::MotionMemento::getPointerCount() const {
    return pointerProperties.size();
}

bool InputState::shouldCancelPreviousStream(const MotionEntry& motionEntry,
                                            int32_t resolvedAction) const {
bool InputState::shouldCancelPreviousStream(const MotionEntry& motionEntry) const {
    if (!isFromSource(motionEntry.source, AINPUT_SOURCE_CLASS_POINTER)) {
        // This is a focus-dispatched event that should not affect the previous stream.
        return false;
@@ -300,7 +299,7 @@ bool InputState::shouldCancelPreviousStream(const MotionEntry& motionEntry,
    }

    const MotionMemento& lastMemento = mMotionMementos.back();
    const int32_t actionMasked = MotionEvent::getActionMasked(resolvedAction);
    const int32_t actionMasked = MotionEvent::getActionMasked(motionEntry.action);

    // For compatibility, only one input device can be active at a time in the same window.
    if (lastMemento.deviceId == motionEntry.deviceId) {
@@ -369,9 +368,9 @@ bool InputState::shouldCancelPreviousStream(const MotionEntry& motionEntry,
    return false;
}

std::unique_ptr<EventEntry> InputState::cancelConflictingInputStream(const MotionEntry& motionEntry,
                                                                     int32_t resolvedAction) {
    if (!shouldCancelPreviousStream(motionEntry, resolvedAction)) {
std::unique_ptr<EventEntry> InputState::cancelConflictingInputStream(
        const MotionEntry& motionEntry) {
    if (!shouldCancelPreviousStream(motionEntry)) {
        return {};
    }

@@ -381,7 +380,7 @@ std::unique_ptr<EventEntry> InputState::cancelConflictingInputStream(const Motio
    std::unique_ptr<MotionEntry> cancelEntry =
            createCancelEntryForMemento(memento, motionEntry.eventTime);

    if (!trackMotion(*cancelEntry, cancelEntry->action, cancelEntry->flags)) {
    if (!trackMotion(*cancelEntry, cancelEntry->flags)) {
        LOG(FATAL) << "Generated inconsistent cancel event!";
    }
    return cancelEntry;
+4 −5
Original line number Diff line number Diff line
@@ -41,16 +41,15 @@ public:
    // Records tracking information for a key event that has just been published.
    // Returns true if the event should be delivered, false if it is inconsistent
    // and should be skipped.
    bool trackKey(const KeyEntry& entry, int32_t action, int32_t flags);
    bool trackKey(const KeyEntry& entry, int32_t flags);

    // Records tracking information for a motion event that has just been published.
    // Returns true if the event should be delivered, false if it is inconsistent
    // and should be skipped.
    bool trackMotion(const MotionEntry& entry, int32_t action, int32_t flags);
    bool trackMotion(const MotionEntry& entry, int32_t flags);

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

    // Synthesizes cancelation events for the current state and resets the tracked state.
    std::vector<std::unique_ptr<EventEntry>> synthesizeCancelationEvents(
@@ -127,7 +126,7 @@ private:

    static bool shouldCancelKey(const KeyMemento& memento, const CancelationOptions& options);
    static bool shouldCancelMotion(const MotionMemento& memento, const CancelationOptions& options);
    bool shouldCancelPreviousStream(const MotionEntry& motionEntry, int32_t resolvedAction) const;
    bool shouldCancelPreviousStream(const MotionEntry& motionEntry) const;
    std::unique_ptr<MotionEntry> createCancelEntryForMemento(const MotionMemento& memento,
                                                             nsecs_t eventTime) const;