diff options
author | 2024-07-01 21:55:48 +0000 | |
---|---|---|
committer | 2024-07-09 00:14:47 +0000 | |
commit | 79655f217cb475a591ae53ec1eb260c1487261af (patch) | |
tree | d0bc2ad13e8731901c5c252573ec8b46c3ea6abc | |
parent | 0c25e864701a6c408b90709493dd30de9b929e2e (diff) |
Add test coverage to InputConsumerNoResampling
Implemented tests that check for multiple samples in a single
batch
Bug: 297226446
Flag: TEST_ONLY
Test: TEST=libinput_tests; m $TEST &&
$ANDROID_HOST_OUT/nativetest64/$TEST/$TEST
--gtest_filter="*InputPublisherAndConsumerNoResamplingTest*"
Change-Id: Ib34010048225f4f66e6380d05fd4df75fa7fa810
-rw-r--r-- | include/input/InputConsumerNoResampling.h | 2 | ||||
-rw-r--r-- | libs/input/tests/InputPublisherAndConsumerNoResampling_test.cpp | 125 |
2 files changed, 125 insertions, 2 deletions
diff --git a/include/input/InputConsumerNoResampling.h b/include/input/InputConsumerNoResampling.h index 9e48b0872d..c7b1970149 100644 --- a/include/input/InputConsumerNoResampling.h +++ b/include/input/InputConsumerNoResampling.h @@ -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: diff --git a/libs/input/tests/InputPublisherAndConsumerNoResampling_test.cpp b/libs/input/tests/InputPublisherAndConsumerNoResampling_test.cpp index f49469ccca..e7106135fd 100644 --- a/libs/input/tests/InputPublisherAndConsumerNoResampling_test.cpp +++ b/libs/input/tests/InputPublisherAndConsumerNoResampling_test.cpp @@ -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 |