Add check to not resample when resample time equals motion event time
Included SampleTimeEqualsEventTime from TouchResampling_test.cpp into
InputConsumerResampling_test.cpp, and added the missing logic in
LegacyResampler to pass the test.
Bug: 297226446
Flag: EXEMPT refactor
Test: TEST=libinput_tests; m $TEST && $ANDROID_HOST_OUT/nativetest64/$TEST/$TEST --gtest_filter="InputConsumerResamplingTest*"
Change-Id: I8ff9a263ea79eed1b814d2b1ce0b7efb5ade584e
diff --git a/include/input/Resampler.h b/include/input/Resampler.h
index 4aaeddd..da0c5b2 100644
--- a/include/input/Resampler.h
+++ b/include/input/Resampler.h
@@ -65,7 +65,8 @@
* extrapolation takes place and `resampleTime` is too far in the future. If `futureSample` is
* not null, interpolation will occur. If `futureSample` is null and there is enough historical
* data, LegacyResampler will extrapolate. Otherwise, no resampling takes place and
- * `motionEvent` is unmodified.
+ * `motionEvent` is unmodified. Furthermore, motionEvent is not resampled if resampleTime equals
+ * the last sample eventTime of motionEvent.
*/
void resampleMotionEvent(std::chrono::nanoseconds frameTime, MotionEvent& motionEvent,
const InputMessage* futureSample) override;
diff --git a/libs/input/Resampler.cpp b/libs/input/Resampler.cpp
index 328fa68..1adff7b 100644
--- a/libs/input/Resampler.cpp
+++ b/libs/input/Resampler.cpp
@@ -249,6 +249,11 @@
const InputMessage* futureSample) {
const nanoseconds resampleTime = frameTime - RESAMPLE_LATENCY;
+ if (resampleTime.count() == motionEvent.getEventTime()) {
+ LOG_IF(INFO, debugResampling()) << "Not resampled. Resample time equals motion event time.";
+ return;
+ }
+
updateLatestSamples(motionEvent);
const std::optional<Sample> sample = (futureSample != nullptr)
diff --git a/libs/input/tests/InputConsumerResampling_test.cpp b/libs/input/tests/InputConsumerResampling_test.cpp
index 61a0a98..b139e87 100644
--- a/libs/input/tests/InputConsumerResampling_test.cpp
+++ b/libs/input/tests/InputConsumerResampling_test.cpp
@@ -1,4 +1,3 @@
-
/*
* Copyright (C) 2024 The Android Open Source Project
*
@@ -193,7 +192,7 @@
* last two real events, which would put this time at: 20 ms + (20 ms - 10 ms) / 2 = 25 ms.
*/
TEST_F(InputConsumerResamplingTest, EventIsResampled) {
- // Initial ACTION_DOWN should be separate, because the first consume event will only return
+ // 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}));
@@ -234,7 +233,7 @@
* have these hardcoded.
*/
TEST_F(InputConsumerResamplingTest, EventIsResampledWithDifferentId) {
- // Initial ACTION_DOWN should be separate, because the first consume event will only return
+ // 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 = 1, .x = 10.0f, .y = 20.0f}}, AMOTION_EVENT_ACTION_DOWN}));
@@ -274,7 +273,7 @@
* Stylus pointer coordinates are resampled.
*/
TEST_F(InputConsumerResamplingTest, StylusEventIsResampled) {
- // Initial ACTION_DOWN should be separate, because the first consume event will only return
+ // 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,
@@ -332,9 +331,8 @@
* Mouse pointer coordinates are resampled.
*/
TEST_F(InputConsumerResamplingTest, MouseEventIsResampled) {
- // Initial ACTION_DOWN should be separate, because the first consume event will only return
+ // 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, .toolType = ToolType::MOUSE}},
@@ -391,7 +389,7 @@
* Motion events with palm tool type are not resampled.
*/
TEST_F(InputConsumerResamplingTest, PalmEventIsNotResampled) {
- // Initial ACTION_DOWN should be separate, because the first consume event will only return
+ // 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,
@@ -431,4 +429,43 @@
mClientTestChannel->assertFinishMessage(/*seq=*/3, /*handled=*/true);
}
+/**
+ * Event should not be resampled when sample time is equal to event time.
+ */
+TEST_F(InputConsumerResamplingTest, SampleTimeEqualsEventTime) {
+ // 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}));
+
+ mClientTestChannel->assertNoSentMessages();
+
+ 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{20ms + 5ms /*RESAMPLE_LATENCY*/}.count());
+
+ // MotionEvent should not resampled because the resample time falls exactly on the existing
+ // event time.
+ 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}});
+
+ mClientTestChannel->assertFinishMessage(/*seq=*/1, /*handled=*/true);
+ mClientTestChannel->assertFinishMessage(/*seq=*/2, /*handled=*/true);
+ mClientTestChannel->assertFinishMessage(/*seq=*/3, /*handled=*/true);
+}
+
} // namespace android