diff options
author | 2024-10-01 01:17:39 +0000 | |
---|---|---|
committer | 2024-10-09 00:58:10 +0000 | |
commit | 4679e55027a36e63cfdc642de313cb2c46c58c54 (patch) | |
tree | 91aca7153c9f7d2c1ef305717efa259488eae757 | |
parent | 4d3b03adfa3543158c982546f3d6daec7eed06e8 (diff) |
Add logic to overwrite pointer coordinates if event time is too old
Included OldEventReceivedAfterResampleOccurs from
TouchResampling_test.cpp, and added the missing logic in LegacyResampler
to pass the test. The CL wrongly assumes pointer information guarantees
between motion events, that is, pointer IDs can appear in different
order between samples. This issue is fixed in the second to last CL in
the relation chain by using an associative array as a data structure to
store and access pointer properties and coordinates.
Bug: 297226446
Flag: EXEMPT refactor
Test: TEST=libinput_tests; m $TEST && $ANDROID_HOST_OUT/nativetest64/$TEST/$TEST --gtest_filter="InputConsumerResamplingTest*"
Change-Id: I41cb79eaba965cfdfe7db68c388cb5d0ffa406f3
-rw-r--r-- | include/input/Resampler.h | 6 | ||||
-rw-r--r-- | libs/input/Resampler.cpp | 19 | ||||
-rw-r--r-- | libs/input/tests/InputConsumerResampling_test.cpp | 55 |
3 files changed, 80 insertions, 0 deletions
diff --git a/include/input/Resampler.h b/include/input/Resampler.h index f04dfde995..47519c2cfd 100644 --- a/include/input/Resampler.h +++ b/include/input/Resampler.h @@ -166,6 +166,12 @@ private: */ void overwriteStillPointers(MotionEvent& motionEvent, size_t sampleIndex) const; + /** + * Overwrites the pointer coordinates of a sample with event time older than + * that of mPreviousPrediction. + */ + void overwriteOldPointers(MotionEvent& motionEvent, size_t sampleIndex) const; + inline static void addSampleToMotionEvent(const Sample& sample, MotionEvent& motionEvent); }; } // namespace android diff --git a/libs/input/Resampler.cpp b/libs/input/Resampler.cpp index 8fe904f9a4..e2cc6fb174 100644 --- a/libs/input/Resampler.cpp +++ b/libs/input/Resampler.cpp @@ -271,6 +271,7 @@ void LegacyResampler::overwriteMotionEventSamples(MotionEvent& motionEvent) cons const size_t numSamples = motionEvent.getHistorySize() + 1; for (size_t sampleIndex = 0; sampleIndex < numSamples; ++sampleIndex) { overwriteStillPointers(motionEvent, sampleIndex); + overwriteOldPointers(motionEvent, sampleIndex); } } @@ -289,6 +290,24 @@ void LegacyResampler::overwriteStillPointers(MotionEvent& motionEvent, size_t sa } } +void LegacyResampler::overwriteOldPointers(MotionEvent& motionEvent, size_t sampleIndex) const { + if (!mPreviousPrediction.has_value()) { + return; + } + if (nanoseconds{motionEvent.getHistoricalEventTime(sampleIndex)} < + mPreviousPrediction->eventTime) { + LOG_IF(INFO, debugResampling()) + << "Motion event sample older than predicted sample. Overwriting event time from " + << motionEvent.getHistoricalEventTime(sampleIndex) << "ns to " + << mPreviousPrediction->eventTime.count() << "ns."; + for (size_t pointerIndex = 0; pointerIndex < motionEvent.getPointerCount(); + ++pointerIndex) { + setMotionEventPointerCoords(motionEvent, sampleIndex, pointerIndex, + mPreviousPrediction->pointers[pointerIndex].coords); + } + } +} + void LegacyResampler::resampleMotionEvent(nanoseconds frameTime, MotionEvent& motionEvent, const InputMessage* futureSample) { const nanoseconds resampleTime = frameTime - RESAMPLE_LATENCY; diff --git a/libs/input/tests/InputConsumerResampling_test.cpp b/libs/input/tests/InputConsumerResampling_test.cpp index 85311afea9..883ca82fe0 100644 --- a/libs/input/tests/InputConsumerResampling_test.cpp +++ b/libs/input/tests/InputConsumerResampling_test.cpp @@ -511,4 +511,59 @@ TEST_F(InputConsumerResamplingTest, ResampledValueIsUsedForIdenticalCoordinates) mClientTestChannel->assertFinishMessage(/*seq=*/4, /*handled=*/true); } +TEST_F(InputConsumerResamplingTest, OldEventReceivedAfterResampleOccurs) { + // Send the initial ACTION_DOWN separately, so that the first consumed event will only return an + // InputEvent with a single action. + mClientTestChannel->enqueueMessage(nextPointerMessage( + {0ms, {Pointer{.id = 0, .x = 10.0f, .y = 20.0f}}, AMOTION_EVENT_ACTION_DOWN})); + + invokeLooperCallback(); + assertReceivedMotionEvent({InputEventEntry{0ms, + {Pointer{.id = 0, .x = 10.0f, .y = 20.0f}}, + AMOTION_EVENT_ACTION_DOWN}}); + + // Two ACTION_MOVE events 10 ms apart that move in X direction and stay still in Y + mClientTestChannel->enqueueMessage(nextPointerMessage( + {10ms, {Pointer{.id = 0, .x = 20.0f, .y = 30.0f}}, AMOTION_EVENT_ACTION_MOVE})); + mClientTestChannel->enqueueMessage(nextPointerMessage( + {20ms, {Pointer{.id = 0, .x = 30.0f, .y = 30.0f}}, AMOTION_EVENT_ACTION_MOVE})); + + invokeLooperCallback(); + mConsumer->consumeBatchedInputEvents(nanoseconds{35ms}.count()); + assertReceivedMotionEvent( + {InputEventEntry{10ms, + {Pointer{.id = 0, .x = 20.0f, .y = 30.0f}}, + AMOTION_EVENT_ACTION_MOVE}, + InputEventEntry{20ms, + {Pointer{.id = 0, .x = 30.0f, .y = 30.0f}}, + AMOTION_EVENT_ACTION_MOVE}, + InputEventEntry{25ms, + {Pointer{.id = 0, .x = 35.0f, .y = 30.0f, .isResampled = true}}, + AMOTION_EVENT_ACTION_MOVE}}); + + // Above, the resampled event is at 25ms rather than at 30 ms = 35ms - RESAMPLE_LATENCY + // because we are further bound by how far we can extrapolate by the "last time delta". + // That's 50% of (20 ms - 10ms) => 5ms. So we can't predict more than 5 ms into the future + // from the event at 20ms, which is why the resampled event is at t = 25 ms. + + // We resampled the event to 25 ms. Now, an older 'real' event comes in. + mClientTestChannel->enqueueMessage(nextPointerMessage( + {24ms, {Pointer{.id = 0, .x = 40.0f, .y = 30.0f}}, AMOTION_EVENT_ACTION_MOVE})); + + invokeLooperCallback(); + mConsumer->consumeBatchedInputEvents(nanoseconds{50ms}.count()); + assertReceivedMotionEvent( + {InputEventEntry{24ms, + {Pointer{.id = 0, .x = 35.0f, .y = 30.0f, .isResampled = true}}, + AMOTION_EVENT_ACTION_MOVE}, // original event, rewritten + InputEventEntry{26ms, + {Pointer{.id = 0, .x = 45.0f, .y = 30.0f, .isResampled = true}}, + AMOTION_EVENT_ACTION_MOVE}}); // resampled event, rewritten + + mClientTestChannel->assertFinishMessage(/*seq=*/1, /*handled=*/true); + mClientTestChannel->assertFinishMessage(/*seq=*/2, /*handled=*/true); + mClientTestChannel->assertFinishMessage(/*seq=*/3, /*handled=*/true); + mClientTestChannel->assertFinishMessage(/*seq=*/4, /*handled=*/true); +} + } // namespace android |