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

Commit 20f122f9 authored by Treehugger Robot's avatar Treehugger Robot Committed by Android (Google) Code Review
Browse files

Merge "Add test coverage to InputConsumerNoResampling" into main

parents 4c6982e5 79655f21
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -24,7 +24,7 @@ namespace android {
/**
 * An interface to receive batched input events. Even if you don't want batching, you still have to
 * use this interface, and some of the events will be batched if your implementation is slow to
 * handle the incoming input.
 * handle the incoming input. The events received by these callbacks are never null.
 */
class InputConsumerCallbacks {
public:
+124 −1
Original line number Diff line number Diff line
@@ -52,7 +52,7 @@ struct PublishMotionArgs {
    const int32_t action;
    const nsecs_t downTime;
    const uint32_t seq;
    const int32_t eventId;
    int32_t eventId;
    const int32_t deviceId = 1;
    const uint32_t source = AINPUT_SOURCE_TOUCHSCREEN;
    const ui::LogicalDisplayId displayId = ui::LogicalDisplayId::DEFAULT;
@@ -291,6 +291,7 @@ protected:
    void publishAndConsumeKeyEvent();
    void publishAndConsumeMotionStream();
    void publishAndConsumeMotionDown(nsecs_t downTime);
    void publishAndConsumeSinglePointerMultipleSamples(const size_t nSamples);
    void publishAndConsumeBatchedMotionMove(nsecs_t downTime);
    void publishAndConsumeFocusEvent();
    void publishAndConsumeCaptureEvent();
@@ -298,6 +299,7 @@ protected:
    void publishAndConsumeTouchModeEvent();
    void publishAndConsumeMotionEvent(int32_t action, nsecs_t downTime,
                                      const std::vector<Pointer>& pointers);

    void TearDown() override {
        // Destroy the consumer, flushing any of the pending ack's.
        sendMessage(LooperMessage::DESTROY_CONSUMER);
@@ -519,6 +521,123 @@ void InputPublisherAndConsumerNoResamplingTest::publishAndConsumeMotionDown(nsec
                                 {Pointer{.id = 0, .x = 20, .y = 30}});
}

/*
 * Decompose a potential multi-sampled MotionEvent into multiple MotionEvents
 * with a single sample.
 */
std::vector<MotionEvent> splitBatchedMotionEvent(const MotionEvent& batchedMotionEvent) {
    std::vector<MotionEvent> singleMotionEvents;
    const size_t batchSize = batchedMotionEvent.getHistorySize() + 1;
    for (size_t i = 0; i < batchSize; ++i) {
        MotionEvent singleMotionEvent;
        singleMotionEvent
                .initialize(batchedMotionEvent.getId(), batchedMotionEvent.getDeviceId(),
                            batchedMotionEvent.getSource(), batchedMotionEvent.getDisplayId(),
                            batchedMotionEvent.getHmac(), batchedMotionEvent.getAction(),
                            batchedMotionEvent.getActionButton(), batchedMotionEvent.getFlags(),
                            batchedMotionEvent.getEdgeFlags(), batchedMotionEvent.getMetaState(),
                            batchedMotionEvent.getButtonState(),
                            batchedMotionEvent.getClassification(),
                            batchedMotionEvent.getTransform(), batchedMotionEvent.getXPrecision(),
                            batchedMotionEvent.getYPrecision(),
                            batchedMotionEvent.getRawXCursorPosition(),
                            batchedMotionEvent.getRawYCursorPosition(),
                            batchedMotionEvent.getRawTransform(), batchedMotionEvent.getDownTime(),
                            batchedMotionEvent.getHistoricalEventTime(/*historicalIndex=*/i),
                            batchedMotionEvent.getPointerCount(),
                            batchedMotionEvent.getPointerProperties(),
                            (batchedMotionEvent.getSamplePointerCoords() + i));
        singleMotionEvents.push_back(singleMotionEvent);
    }
    return singleMotionEvents;
}

/*
 * Simulates a single pointer touching the screen and leaving it there for a period of time.
 * Publishes a DOWN event and consumes it right away. Then, publishes a sequence of MOVE
 * samples for the same pointer, and waits until it has been consumed. Splits batched MotionEvents
 * into individual samples. Checks the consumed MotionEvents against the published ones.
 * This test is non-deterministic because it depends on the timing of arrival of events to the
 * socket.
 *
 * @param nSamples The number of MOVE samples to publish before attempting consumption.
 */
void InputPublisherAndConsumerNoResamplingTest::publishAndConsumeSinglePointerMultipleSamples(
        const size_t nSamples) {
    const nsecs_t downTime = systemTime(SYSTEM_TIME_MONOTONIC);
    const Pointer pointer(0, 20, 30);

    const PublishMotionArgs argsDown(AMOTION_EVENT_ACTION_DOWN, downTime, {pointer}, mSeq);
    const nsecs_t publishTimeOfDown = systemTime(SYSTEM_TIME_MONOTONIC);
    publishMotionEvent(*mPublisher, argsDown);

    // Consume the DOWN event.
    ASSERT_TRUE(mMotionEvents.popWithTimeout(TIMEOUT).has_value());

    verifyFinishedSignal(*mPublisher, mSeq, publishTimeOfDown);

    std::vector<nsecs_t> publishTimes;
    std::vector<PublishMotionArgs> argsMoves;
    std::queue<uint32_t> publishedSequenceNumbers;

    // Block Looper to increase the chance of batching events
    {
        std::scoped_lock l(mLock);
        mLooperMayProceed = false;
    }
    sendMessage(LooperMessage::BLOCK_LOOPER);
    {
        std::unique_lock l(mLock);
        mNotifyLooperWaiting.wait(l, [this] { return mLooperIsBlocked; });
    }

    uint32_t firstSampleId;
    for (size_t i = 0; i < nSamples; ++i) {
        publishedSequenceNumbers.push(++mSeq);
        PublishMotionArgs argsMove(AMOTION_EVENT_ACTION_MOVE, downTime, {pointer}, mSeq);
        // A batched MotionEvent only has a single event id, currently determined when the
        // MotionEvent is initialized. Therefore, to pass the eventId comparisons inside
        // verifyArgsEqualToEvent, we need to override the event id of the published args to match
        // the event id of the first sample inside the MotionEvent.
        if (i == 0) {
            firstSampleId = argsMove.eventId;
        }
        argsMove.eventId = firstSampleId;
        publishTimes.push_back(systemTime(SYSTEM_TIME_MONOTONIC));
        argsMoves.push_back(argsMove);
        publishMotionEvent(*mPublisher, argsMove);
    }

    std::vector<MotionEvent> singleSampledMotionEvents;

    // Unblock Looper
    {
        std::scoped_lock l(mLock);
        mLooperMayProceed = true;
    }
    mNotifyLooperMayProceed.notify_all();

    // We have no control over the socket behavior, so the consumer can receive
    // the motion as a batched event, or as a sequence of multiple single-sample MotionEvents (or a
    // mix of those)
    while (singleSampledMotionEvents.size() != nSamples) {
        const std::optional<std::unique_ptr<MotionEvent>> batchedMotionEvent =
                mMotionEvents.popWithTimeout(TIMEOUT);
        // The events received by these calls are never null
        std::vector<MotionEvent> splitMotionEvents = splitBatchedMotionEvent(**batchedMotionEvent);
        singleSampledMotionEvents.insert(singleSampledMotionEvents.end(), splitMotionEvents.begin(),
                                         splitMotionEvents.end());
    }

    // Consumer can choose to finish events in any order. For simplicity,
    // we verify the events in sequence (since that is how the test is implemented).
    for (size_t i = 0; i < nSamples; ++i) {
        verifyArgsEqualToEvent(argsMoves[i], singleSampledMotionEvents[i]);
        verifyFinishedSignal(*mPublisher, publishedSequenceNumbers.front(), publishTimes[i]);
        publishedSequenceNumbers.pop();
    }
}

void InputPublisherAndConsumerNoResamplingTest::publishAndConsumeBatchedMotionMove(
        nsecs_t downTime) {
    uint32_t seq = mSeq++;
@@ -814,4 +933,8 @@ TEST_F(InputPublisherAndConsumerNoResamplingTest, PublishMultipleEvents_EndToEnd
    ASSERT_NO_FATAL_FAILURE(publishAndConsumeTouchModeEvent());
}

TEST_F(InputPublisherAndConsumerNoResamplingTest, PublishAndConsumeSinglePointer) {
    publishAndConsumeSinglePointerMultipleSamples(3);
}

} // namespace android