xref: /aosp_15_r20/frameworks/native/libs/input/tests/InputConsumerResampling_test.cpp (revision 38e8c45f13ce32b0dcecb25141ffecaf386fa17f)
1 /*
2  * Copyright (C) 2024 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #include <input/InputConsumerNoResampling.h>
18 
19 #include <chrono>
20 #include <memory>
21 #include <string>
22 #include <vector>
23 
24 #include <TestEventMatchers.h>
25 #include <TestInputChannel.h>
26 #include <attestation/HmacKeyManager.h>
27 #include <gmock/gmock.h>
28 #include <gtest/gtest.h>
29 #include <input/BlockingQueue.h>
30 #include <input/InputEventBuilders.h>
31 #include <input/Resampler.h>
32 #include <utils/Looper.h>
33 #include <utils/StrongPointer.h>
34 
35 namespace android {
36 namespace {
37 
38 using std::chrono::nanoseconds;
39 using namespace std::chrono_literals;
40 
41 const std::chrono::milliseconds RESAMPLE_LATENCY{5};
42 
43 struct Pointer {
44     int32_t id{0};
45     float x{0.0f};
46     float y{0.0f};
47     ToolType toolType{ToolType::FINGER};
48     bool isResampled{false};
49 
asPointerBuilderandroid::__anon1f8bd8530111::Pointer50     PointerBuilder asPointerBuilder() const {
51         return PointerBuilder{id, toolType}.x(x).y(y).isResampled(isResampled);
52     }
53 };
54 
55 struct InputEventEntry {
56     std::chrono::nanoseconds eventTime{0};
57     std::vector<Pointer> pointers{};
58     int32_t action{-1};
59 };
60 
61 } // namespace
62 
63 class InputConsumerResamplingTest : public ::testing::Test, public InputConsumerCallbacks {
64 protected:
InputConsumerResamplingTest()65     InputConsumerResamplingTest()
66           : mClientTestChannel{std::make_shared<TestInputChannel>("TestChannel")},
67             mLooper{sp<Looper>::make(/*allowNonCallbacks=*/false)} {
68         Looper::setForThread(mLooper);
69         mConsumer = std::make_unique<
70                 InputConsumerNoResampling>(mClientTestChannel, mLooper, *this,
__anon1f8bd8530202() 71                                            []() { return std::make_unique<LegacyResampler>(); });
72     }
73 
invokeLooperCallback() const74     void invokeLooperCallback() const {
75         sp<LooperCallback> callback;
76         ASSERT_TRUE(mLooper->getFdStateDebug(mClientTestChannel->getFd(), /*ident=*/nullptr,
77                                              /*events=*/nullptr, &callback, /*data=*/nullptr));
78         ASSERT_NE(callback, nullptr);
79         callback->handleEvent(mClientTestChannel->getFd(), ALOOPER_EVENT_INPUT, /*data=*/nullptr);
80     }
81 
82     InputMessage nextPointerMessage(const InputEventEntry& entry);
83 
84     void assertReceivedMotionEvent(const std::vector<InputEventEntry>& expectedEntries);
85 
86     std::shared_ptr<TestInputChannel> mClientTestChannel;
87     sp<Looper> mLooper;
88     std::unique_ptr<InputConsumerNoResampling> mConsumer;
89 
90     BlockingQueue<std::unique_ptr<KeyEvent>> mKeyEvents;
91     BlockingQueue<std::unique_ptr<MotionEvent>> mMotionEvents;
92     BlockingQueue<std::unique_ptr<FocusEvent>> mFocusEvents;
93     BlockingQueue<std::unique_ptr<CaptureEvent>> mCaptureEvents;
94     BlockingQueue<std::unique_ptr<DragEvent>> mDragEvents;
95     BlockingQueue<std::unique_ptr<TouchModeEvent>> mTouchModeEvents;
96 
97 private:
98     uint32_t mLastSeq{0};
99     size_t mOnBatchedInputEventPendingInvocationCount{0};
100 
101     // InputConsumerCallbacks interface
onKeyEvent(std::unique_ptr<KeyEvent> event,uint32_t seq)102     void onKeyEvent(std::unique_ptr<KeyEvent> event, uint32_t seq) override {
103         mKeyEvents.push(std::move(event));
104         mConsumer->finishInputEvent(seq, true);
105     }
onMotionEvent(std::unique_ptr<MotionEvent> event,uint32_t seq)106     void onMotionEvent(std::unique_ptr<MotionEvent> event, uint32_t seq) override {
107         mMotionEvents.push(std::move(event));
108         mConsumer->finishInputEvent(seq, true);
109     }
onBatchedInputEventPending(int32_t pendingBatchSource)110     void onBatchedInputEventPending(int32_t pendingBatchSource) override {
111         if (!mConsumer->probablyHasInput()) {
112             ADD_FAILURE() << "should deterministically have input because there is a batch";
113         }
114         ++mOnBatchedInputEventPendingInvocationCount;
115     }
onFocusEvent(std::unique_ptr<FocusEvent> event,uint32_t seq)116     void onFocusEvent(std::unique_ptr<FocusEvent> event, uint32_t seq) override {
117         mFocusEvents.push(std::move(event));
118         mConsumer->finishInputEvent(seq, true);
119     }
onCaptureEvent(std::unique_ptr<CaptureEvent> event,uint32_t seq)120     void onCaptureEvent(std::unique_ptr<CaptureEvent> event, uint32_t seq) override {
121         mCaptureEvents.push(std::move(event));
122         mConsumer->finishInputEvent(seq, true);
123     }
onDragEvent(std::unique_ptr<DragEvent> event,uint32_t seq)124     void onDragEvent(std::unique_ptr<DragEvent> event, uint32_t seq) override {
125         mDragEvents.push(std::move(event));
126         mConsumer->finishInputEvent(seq, true);
127     }
onTouchModeEvent(std::unique_ptr<TouchModeEvent> event,uint32_t seq)128     void onTouchModeEvent(std::unique_ptr<TouchModeEvent> event, uint32_t seq) override {
129         mTouchModeEvents.push(std::move(event));
130         mConsumer->finishInputEvent(seq, true);
131     }
132 };
133 
nextPointerMessage(const InputEventEntry & entry)134 InputMessage InputConsumerResamplingTest::nextPointerMessage(const InputEventEntry& entry) {
135     ++mLastSeq;
136     InputMessageBuilder messageBuilder = InputMessageBuilder{InputMessage::Type::MOTION, mLastSeq}
137                                                  .eventTime(entry.eventTime.count())
138                                                  .deviceId(1)
139                                                  .action(entry.action)
140                                                  .downTime(0);
141     for (const Pointer& pointer : entry.pointers) {
142         messageBuilder.pointer(pointer.asPointerBuilder());
143     }
144     return messageBuilder.build();
145 }
146 
assertReceivedMotionEvent(const std::vector<InputEventEntry> & expectedEntries)147 void InputConsumerResamplingTest::assertReceivedMotionEvent(
148         const std::vector<InputEventEntry>& expectedEntries) {
149     std::unique_ptr<MotionEvent> motionEvent = mMotionEvents.pop();
150     ASSERT_NE(motionEvent, nullptr);
151 
152     ASSERT_EQ(motionEvent->getHistorySize() + 1, expectedEntries.size());
153 
154     for (size_t sampleIndex = 0; sampleIndex < expectedEntries.size(); ++sampleIndex) {
155         SCOPED_TRACE("sampleIndex: " + std::to_string(sampleIndex));
156         const InputEventEntry& expectedEntry = expectedEntries[sampleIndex];
157         EXPECT_EQ(motionEvent->getHistoricalEventTime(sampleIndex),
158                   expectedEntry.eventTime.count());
159         EXPECT_EQ(motionEvent->getPointerCount(), expectedEntry.pointers.size());
160         EXPECT_EQ(motionEvent->getAction(), expectedEntry.action);
161 
162         for (size_t pointerIndex = 0; pointerIndex < expectedEntry.pointers.size();
163              ++pointerIndex) {
164             SCOPED_TRACE("pointerIndex: " + std::to_string(pointerIndex));
165             ssize_t eventPointerIndex =
166                     motionEvent->findPointerIndex(expectedEntry.pointers[pointerIndex].id);
167             EXPECT_EQ(motionEvent->getHistoricalRawX(eventPointerIndex, sampleIndex),
168                       expectedEntry.pointers[pointerIndex].x);
169             EXPECT_EQ(motionEvent->getHistoricalRawY(eventPointerIndex, sampleIndex),
170                       expectedEntry.pointers[pointerIndex].y);
171             EXPECT_EQ(motionEvent->getHistoricalX(eventPointerIndex, sampleIndex),
172                       expectedEntry.pointers[pointerIndex].x);
173             EXPECT_EQ(motionEvent->getHistoricalY(eventPointerIndex, sampleIndex),
174                       expectedEntry.pointers[pointerIndex].y);
175             EXPECT_EQ(motionEvent->isResampled(pointerIndex, sampleIndex),
176                       expectedEntry.pointers[pointerIndex].isResampled);
177         }
178     }
179 }
180 
181 /**
182  * Timeline
183  * ---------+------------------+------------------+--------+-----------------+----------------------
184  *          0 ms               10 ms              20 ms    25 ms            35 ms
185  *          ACTION_DOWN       ACTION_MOVE      ACTION_MOVE  ^                ^
186  *                                                          |                |
187  *                                                         resampled value   |
188  *                                                                          frameTime
189  * Typically, the prediction is made for time frameTime - RESAMPLE_LATENCY, or 30 ms in this case,
190  * where RESAMPLE_LATENCY equals 5 milliseconds. However, that would be 10 ms later than the last
191  * real sample (which came in at 20 ms). Therefore, the resampling should happen at 20 ms +
192  * RESAMPLE_MAX_PREDICTION = 28 ms, where RESAMPLE_MAX_PREDICTION equals 8 milliseconds. In this
193  * situation, though, resample time is further limited by taking half of the difference between the
194  * last two real events, which would put this time at: 20 ms + (20 ms - 10 ms) / 2 = 25 ms.
195  */
TEST_F(InputConsumerResamplingTest,EventIsResampled)196 TEST_F(InputConsumerResamplingTest, EventIsResampled) {
197     // Send the initial ACTION_DOWN separately, so that the first consumed event will only return an
198     // InputEvent with a single action.
199     mClientTestChannel->enqueueMessage(nextPointerMessage(
200             {0ms, {Pointer{.id = 0, .x = 10.0f, .y = 20.0f}}, AMOTION_EVENT_ACTION_DOWN}));
201 
202     invokeLooperCallback();
203     assertReceivedMotionEvent({InputEventEntry{0ms,
204                                                {Pointer{.id = 0, .x = 10.0f, .y = 20.0f}},
205                                                AMOTION_EVENT_ACTION_DOWN}});
206 
207     // Two ACTION_MOVE events 10 ms apart that move in X direction and stay still in Y
208     mClientTestChannel->enqueueMessage(nextPointerMessage(
209             {10ms, {Pointer{.id = 0, .x = 20.0f, .y = 30.0f}}, AMOTION_EVENT_ACTION_MOVE}));
210     mClientTestChannel->enqueueMessage(nextPointerMessage(
211             {20ms, {Pointer{.id = 0, .x = 30.0f, .y = 30.0f}}, AMOTION_EVENT_ACTION_MOVE}));
212 
213     invokeLooperCallback();
214     mConsumer->consumeBatchedInputEvents(nanoseconds{35ms}.count());
215     assertReceivedMotionEvent(
216             {InputEventEntry{10ms,
217                              {Pointer{.id = 0, .x = 20.0f, .y = 30.0f}},
218                              AMOTION_EVENT_ACTION_MOVE},
219              InputEventEntry{20ms,
220                              {Pointer{.id = 0, .x = 30.0f, .y = 30.0f}},
221                              AMOTION_EVENT_ACTION_MOVE},
222              InputEventEntry{25ms,
223                              {Pointer{.id = 0, .x = 35.0f, .y = 30.0f, .isResampled = true}},
224                              AMOTION_EVENT_ACTION_MOVE}});
225 
226     mClientTestChannel->assertFinishMessage(/*seq=*/1, /*handled=*/true);
227     mClientTestChannel->assertFinishMessage(/*seq=*/2, /*handled=*/true);
228     mClientTestChannel->assertFinishMessage(/*seq=*/3, /*handled=*/true);
229 }
230 
231 /**
232  * Same as above test, but use pointer id=1 instead of 0 to make sure that system does not
233  * have these hardcoded.
234  */
TEST_F(InputConsumerResamplingTest,EventIsResampledWithDifferentId)235 TEST_F(InputConsumerResamplingTest, EventIsResampledWithDifferentId) {
236     // Send the initial ACTION_DOWN separately, so that the first consumed event will only return an
237     // InputEvent with a single action.
238     mClientTestChannel->enqueueMessage(nextPointerMessage(
239             {0ms, {Pointer{.id = 1, .x = 10.0f, .y = 20.0f}}, AMOTION_EVENT_ACTION_DOWN}));
240 
241     invokeLooperCallback();
242     assertReceivedMotionEvent({InputEventEntry{0ms,
243                                                {Pointer{.id = 1, .x = 10.0f, .y = 20.0f}},
244                                                AMOTION_EVENT_ACTION_DOWN}});
245 
246     // Two ACTION_MOVE events 10 ms apart that move in X direction and stay still in Y
247     mClientTestChannel->enqueueMessage(nextPointerMessage(
248             {10ms, {Pointer{.id = 1, .x = 20.0f, .y = 30.0f}}, AMOTION_EVENT_ACTION_MOVE}));
249     mClientTestChannel->enqueueMessage(nextPointerMessage(
250             {20ms, {Pointer{.id = 1, .x = 30.0f, .y = 30.0f}}, AMOTION_EVENT_ACTION_MOVE}));
251 
252     invokeLooperCallback();
253     mConsumer->consumeBatchedInputEvents(nanoseconds{35ms}.count());
254     assertReceivedMotionEvent(
255             {InputEventEntry{10ms,
256                              {Pointer{.id = 1, .x = 20.0f, .y = 30.0f}},
257                              AMOTION_EVENT_ACTION_MOVE},
258              InputEventEntry{20ms,
259                              {Pointer{.id = 1, .x = 30.0f, .y = 30.0f}},
260                              AMOTION_EVENT_ACTION_MOVE},
261              InputEventEntry{25ms,
262                              {Pointer{.id = 1, .x = 35.0f, .y = 30.0f, .isResampled = true}},
263                              AMOTION_EVENT_ACTION_MOVE}});
264 
265     mClientTestChannel->assertFinishMessage(/*seq=*/1, /*handled=*/true);
266     mClientTestChannel->assertFinishMessage(/*seq=*/2, /*handled=*/true);
267     mClientTestChannel->assertFinishMessage(/*seq=*/3, /*handled=*/true);
268 }
269 
270 /**
271  * Stylus pointer coordinates are resampled.
272  */
TEST_F(InputConsumerResamplingTest,StylusEventIsResampled)273 TEST_F(InputConsumerResamplingTest, StylusEventIsResampled) {
274     // Send the initial ACTION_DOWN separately, so that the first consumed event will only return an
275     // InputEvent with a single action.
276     mClientTestChannel->enqueueMessage(nextPointerMessage(
277             {0ms,
278              {Pointer{.id = 0, .x = 10.0f, .y = 20.0f, .toolType = ToolType::STYLUS}},
279              AMOTION_EVENT_ACTION_DOWN}));
280 
281     invokeLooperCallback();
282     assertReceivedMotionEvent({InputEventEntry{0ms,
283                                                {Pointer{.id = 0,
284                                                         .x = 10.0f,
285                                                         .y = 20.0f,
286                                                         .toolType = ToolType::STYLUS}},
287                                                AMOTION_EVENT_ACTION_DOWN}});
288 
289     // Two ACTION_MOVE events 10 ms apart that move in X direction and stay still in Y
290     mClientTestChannel->enqueueMessage(nextPointerMessage(
291             {10ms,
292              {Pointer{.id = 0, .x = 20.0f, .y = 30.0f, .toolType = ToolType::STYLUS}},
293              AMOTION_EVENT_ACTION_MOVE}));
294     mClientTestChannel->enqueueMessage(nextPointerMessage(
295             {20ms,
296              {Pointer{.id = 0, .x = 30.0f, .y = 30.0f, .toolType = ToolType::STYLUS}},
297              AMOTION_EVENT_ACTION_MOVE}));
298 
299     invokeLooperCallback();
300     mConsumer->consumeBatchedInputEvents(nanoseconds{35ms}.count());
301     assertReceivedMotionEvent({InputEventEntry{10ms,
302                                                {Pointer{.id = 0,
303                                                         .x = 20.0f,
304                                                         .y = 30.0f,
305                                                         .toolType = ToolType::STYLUS}},
306                                                AMOTION_EVENT_ACTION_MOVE},
307                                InputEventEntry{20ms,
308                                                {Pointer{.id = 0,
309                                                         .x = 30.0f,
310                                                         .y = 30.0f,
311                                                         .toolType = ToolType::STYLUS}},
312                                                AMOTION_EVENT_ACTION_MOVE},
313                                InputEventEntry{25ms,
314                                                {Pointer{.id = 0,
315                                                         .x = 35.0f,
316                                                         .y = 30.0f,
317                                                         .toolType = ToolType::STYLUS,
318                                                         .isResampled = true}},
319                                                AMOTION_EVENT_ACTION_MOVE}});
320 
321     mClientTestChannel->assertFinishMessage(/*seq=*/1, /*handled=*/true);
322     mClientTestChannel->assertFinishMessage(/*seq=*/2, /*handled=*/true);
323     mClientTestChannel->assertFinishMessage(/*seq=*/3, /*handled=*/true);
324 }
325 
326 /**
327  * Mouse pointer coordinates are resampled.
328  */
TEST_F(InputConsumerResamplingTest,MouseEventIsResampled)329 TEST_F(InputConsumerResamplingTest, MouseEventIsResampled) {
330     // Send the initial ACTION_DOWN separately, so that the first consumed event will only return an
331     // InputEvent with a single action.
332     mClientTestChannel->enqueueMessage(nextPointerMessage(
333             {0ms,
334              {Pointer{.id = 0, .x = 10.0f, .y = 20.0f, .toolType = ToolType::MOUSE}},
335              AMOTION_EVENT_ACTION_DOWN}));
336 
337     invokeLooperCallback();
338     assertReceivedMotionEvent({InputEventEntry{0ms,
339                                                {Pointer{.id = 0,
340                                                         .x = 10.0f,
341                                                         .y = 20.0f,
342                                                         .toolType = ToolType::MOUSE}},
343                                                AMOTION_EVENT_ACTION_DOWN}});
344 
345     // Two ACTION_MOVE events 10 ms apart that move in X direction and stay still in Y
346     mClientTestChannel->enqueueMessage(nextPointerMessage(
347             {10ms,
348              {Pointer{.id = 0, .x = 20.0f, .y = 30.0f, .toolType = ToolType::MOUSE}},
349              AMOTION_EVENT_ACTION_MOVE}));
350     mClientTestChannel->enqueueMessage(nextPointerMessage(
351             {20ms,
352              {Pointer{.id = 0, .x = 30.0f, .y = 30.0f, .toolType = ToolType::MOUSE}},
353              AMOTION_EVENT_ACTION_MOVE}));
354 
355     invokeLooperCallback();
356     mConsumer->consumeBatchedInputEvents(nanoseconds{35ms}.count());
357     assertReceivedMotionEvent({InputEventEntry{10ms,
358                                                {Pointer{.id = 0,
359                                                         .x = 20.0f,
360                                                         .y = 30.0f,
361                                                         .toolType = ToolType::MOUSE}},
362                                                AMOTION_EVENT_ACTION_MOVE},
363                                InputEventEntry{20ms,
364                                                {Pointer{.id = 0,
365                                                         .x = 30.0f,
366                                                         .y = 30.0f,
367                                                         .toolType = ToolType::MOUSE}},
368                                                AMOTION_EVENT_ACTION_MOVE},
369                                InputEventEntry{25ms,
370                                                {Pointer{.id = 0,
371                                                         .x = 35.0f,
372                                                         .y = 30.0f,
373                                                         .toolType = ToolType::MOUSE,
374                                                         .isResampled = true}},
375                                                AMOTION_EVENT_ACTION_MOVE}});
376 
377     mClientTestChannel->assertFinishMessage(/*seq=*/1, /*handled=*/true);
378     mClientTestChannel->assertFinishMessage(/*seq=*/2, /*handled=*/true);
379     mClientTestChannel->assertFinishMessage(/*seq=*/3, /*handled=*/true);
380 }
381 
382 /**
383  * Motion events with palm tool type are not resampled.
384  */
TEST_F(InputConsumerResamplingTest,PalmEventIsNotResampled)385 TEST_F(InputConsumerResamplingTest, PalmEventIsNotResampled) {
386     // Send the initial ACTION_DOWN separately, so that the first consumed event will only return an
387     // InputEvent with a single action.
388     mClientTestChannel->enqueueMessage(nextPointerMessage(
389             {0ms,
390              {Pointer{.id = 0, .x = 10.0f, .y = 20.0f, .toolType = ToolType::PALM}},
391              AMOTION_EVENT_ACTION_DOWN}));
392 
393     invokeLooperCallback();
394     assertReceivedMotionEvent(
395             {InputEventEntry{0ms,
396                              {Pointer{.id = 0, .x = 10.0f, .y = 20.0f, .toolType = ToolType::PALM}},
397                              AMOTION_EVENT_ACTION_DOWN}});
398 
399     // Two ACTION_MOVE events 10 ms apart that move in X direction and stay still in Y
400     mClientTestChannel->enqueueMessage(nextPointerMessage(
401             {10ms,
402              {Pointer{.id = 0, .x = 20.0f, .y = 30.0f, .toolType = ToolType::PALM}},
403              AMOTION_EVENT_ACTION_MOVE}));
404     mClientTestChannel->enqueueMessage(nextPointerMessage(
405             {20ms,
406              {Pointer{.id = 0, .x = 30.0f, .y = 30.0f, .toolType = ToolType::PALM}},
407              AMOTION_EVENT_ACTION_MOVE}));
408 
409     invokeLooperCallback();
410     mConsumer->consumeBatchedInputEvents(nanoseconds{35ms}.count());
411     assertReceivedMotionEvent(
412             {InputEventEntry{10ms,
413                              {Pointer{.id = 0, .x = 20.0f, .y = 30.0f, .toolType = ToolType::PALM}},
414                              AMOTION_EVENT_ACTION_MOVE},
415              InputEventEntry{20ms,
416                              {Pointer{.id = 0, .x = 30.0f, .y = 30.0f, .toolType = ToolType::PALM}},
417                              AMOTION_EVENT_ACTION_MOVE}});
418 
419     mClientTestChannel->assertFinishMessage(/*seq=*/1, /*handled=*/true);
420     mClientTestChannel->assertFinishMessage(/*seq=*/2, /*handled=*/true);
421     mClientTestChannel->assertFinishMessage(/*seq=*/3, /*handled=*/true);
422 }
423 
424 /**
425  * Event should not be resampled when sample time is equal to event time.
426  */
TEST_F(InputConsumerResamplingTest,SampleTimeEqualsEventTime)427 TEST_F(InputConsumerResamplingTest, SampleTimeEqualsEventTime) {
428     // Send the initial ACTION_DOWN separately, so that the first consumed event will only return an
429     // InputEvent with a single action.
430     mClientTestChannel->enqueueMessage(nextPointerMessage(
431             {0ms, {Pointer{.id = 0, .x = 10.0f, .y = 20.0f}}, AMOTION_EVENT_ACTION_DOWN}));
432 
433     invokeLooperCallback();
434     assertReceivedMotionEvent({InputEventEntry{0ms,
435                                                {Pointer{.id = 0, .x = 10.0f, .y = 20.0f}},
436                                                AMOTION_EVENT_ACTION_DOWN}});
437 
438     // Two ACTION_MOVE events 10 ms apart that move in X direction and stay still in Y
439     mClientTestChannel->enqueueMessage(nextPointerMessage(
440             {10ms, {Pointer{.id = 0, .x = 20.0f, .y = 30.0f}}, AMOTION_EVENT_ACTION_MOVE}));
441     mClientTestChannel->enqueueMessage(nextPointerMessage(
442             {20ms, {Pointer{.id = 0, .x = 30.0f, .y = 30.0f}}, AMOTION_EVENT_ACTION_MOVE}));
443 
444     invokeLooperCallback();
445     mConsumer->consumeBatchedInputEvents(nanoseconds{20ms + RESAMPLE_LATENCY}.count());
446 
447     // MotionEvent should not resampled because the resample time falls exactly on the existing
448     // event time.
449     assertReceivedMotionEvent({InputEventEntry{10ms,
450                                                {Pointer{.id = 0, .x = 20.0f, .y = 30.0f}},
451                                                AMOTION_EVENT_ACTION_MOVE},
452                                InputEventEntry{20ms,
453                                                {Pointer{.id = 0, .x = 30.0f, .y = 30.0f}},
454                                                AMOTION_EVENT_ACTION_MOVE}});
455 
456     mClientTestChannel->assertFinishMessage(/*seq=*/1, /*handled=*/true);
457     mClientTestChannel->assertFinishMessage(/*seq=*/2, /*handled=*/true);
458     mClientTestChannel->assertFinishMessage(/*seq=*/3, /*handled=*/true);
459 }
460 
461 /**
462  * Once we send a resampled value to the app, we should continue to send the last predicted value if
463  * a pointer does not move. Only real values are used to determine if a pointer does not move.
464  */
TEST_F(InputConsumerResamplingTest,ResampledValueIsUsedForIdenticalCoordinates)465 TEST_F(InputConsumerResamplingTest, ResampledValueIsUsedForIdenticalCoordinates) {
466     // Send the initial ACTION_DOWN separately, so that the first consumed event will only return an
467     // InputEvent with a single action.
468     mClientTestChannel->enqueueMessage(nextPointerMessage(
469             {0ms, {Pointer{.id = 0, .x = 10.0f, .y = 20.0f}}, AMOTION_EVENT_ACTION_DOWN}));
470 
471     invokeLooperCallback();
472     assertReceivedMotionEvent({InputEventEntry{0ms,
473                                                {Pointer{.id = 0, .x = 10.0f, .y = 20.0f}},
474                                                AMOTION_EVENT_ACTION_DOWN}});
475 
476     // Two ACTION_MOVE events 10 ms apart that move in X direction and stay still in Y
477     mClientTestChannel->enqueueMessage(nextPointerMessage(
478             {10ms, {Pointer{.id = 0, .x = 20.0f, .y = 30.0f}}, AMOTION_EVENT_ACTION_MOVE}));
479     mClientTestChannel->enqueueMessage(nextPointerMessage(
480             {20ms, {Pointer{.id = 0, .x = 30.0f, .y = 30.0f}}, AMOTION_EVENT_ACTION_MOVE}));
481 
482     invokeLooperCallback();
483     mConsumer->consumeBatchedInputEvents(nanoseconds{35ms}.count());
484     assertReceivedMotionEvent(
485             {InputEventEntry{10ms,
486                              {Pointer{.id = 0, .x = 20.0f, .y = 30.0f}},
487                              AMOTION_EVENT_ACTION_MOVE},
488              InputEventEntry{20ms,
489                              {Pointer{.id = 0, .x = 30.0f, .y = 30.0f}},
490                              AMOTION_EVENT_ACTION_MOVE},
491              InputEventEntry{25ms,
492                              {Pointer{.id = 0, .x = 35.0f, .y = 30.0f, .isResampled = true}},
493                              AMOTION_EVENT_ACTION_MOVE}});
494 
495     // Coordinate value 30 has been resampled to 35. When a new event comes in with value 30 again,
496     // the system should still report 35.
497     mClientTestChannel->enqueueMessage(nextPointerMessage(
498             {40ms, {Pointer{.id = 0, .x = 30.0f, .y = 30.0f}}, AMOTION_EVENT_ACTION_MOVE}));
499 
500     invokeLooperCallback();
501     mConsumer->consumeBatchedInputEvents(nanoseconds{45ms + RESAMPLE_LATENCY}.count());
502     // Original and resampled event should be both overwritten.
503     assertReceivedMotionEvent(
504             {InputEventEntry{40ms,
505                              {Pointer{.id = 0, .x = 35.0f, .y = 30.0f, .isResampled = true}},
506                              AMOTION_EVENT_ACTION_MOVE},
507              InputEventEntry{45ms,
508                              {Pointer{.id = 0, .x = 35.0f, .y = 30.0f, .isResampled = true}},
509                              AMOTION_EVENT_ACTION_MOVE}});
510 
511     mClientTestChannel->assertFinishMessage(/*seq=*/1, /*handled=*/true);
512     mClientTestChannel->assertFinishMessage(/*seq=*/2, /*handled=*/true);
513     mClientTestChannel->assertFinishMessage(/*seq=*/3, /*handled=*/true);
514     mClientTestChannel->assertFinishMessage(/*seq=*/4, /*handled=*/true);
515 }
516 
TEST_F(InputConsumerResamplingTest,OldEventReceivedAfterResampleOccurs)517 TEST_F(InputConsumerResamplingTest, OldEventReceivedAfterResampleOccurs) {
518     // Send the initial ACTION_DOWN separately, so that the first consumed event will only return an
519     // InputEvent with a single action.
520     mClientTestChannel->enqueueMessage(nextPointerMessage(
521             {0ms, {Pointer{.id = 0, .x = 10.0f, .y = 20.0f}}, AMOTION_EVENT_ACTION_DOWN}));
522 
523     invokeLooperCallback();
524     assertReceivedMotionEvent({InputEventEntry{0ms,
525                                                {Pointer{.id = 0, .x = 10.0f, .y = 20.0f}},
526                                                AMOTION_EVENT_ACTION_DOWN}});
527 
528     // Two ACTION_MOVE events 10 ms apart that move in X direction and stay still in Y
529     mClientTestChannel->enqueueMessage(nextPointerMessage(
530             {10ms, {Pointer{.id = 0, .x = 20.0f, .y = 30.0f}}, AMOTION_EVENT_ACTION_MOVE}));
531     mClientTestChannel->enqueueMessage(nextPointerMessage(
532             {20ms, {Pointer{.id = 0, .x = 30.0f, .y = 30.0f}}, AMOTION_EVENT_ACTION_MOVE}));
533 
534     invokeLooperCallback();
535     mConsumer->consumeBatchedInputEvents(nanoseconds{35ms}.count());
536     assertReceivedMotionEvent(
537             {InputEventEntry{10ms,
538                              {Pointer{.id = 0, .x = 20.0f, .y = 30.0f}},
539                              AMOTION_EVENT_ACTION_MOVE},
540              InputEventEntry{20ms,
541                              {Pointer{.id = 0, .x = 30.0f, .y = 30.0f}},
542                              AMOTION_EVENT_ACTION_MOVE},
543              InputEventEntry{25ms,
544                              {Pointer{.id = 0, .x = 35.0f, .y = 30.0f, .isResampled = true}},
545                              AMOTION_EVENT_ACTION_MOVE}});
546 
547     // Above, the resampled event is at 25ms rather than at 30 ms = 35ms - RESAMPLE_LATENCY
548     // because we are further bound by how far we can extrapolate by the "last time delta".
549     // That's 50% of (20 ms - 10ms) => 5ms. So we can't predict more than 5 ms into the future
550     // from the event at 20ms, which is why the resampled event is at t = 25 ms.
551 
552     // We resampled the event to 25 ms. Now, an older 'real' event comes in.
553     mClientTestChannel->enqueueMessage(nextPointerMessage(
554             {24ms, {Pointer{.id = 0, .x = 40.0f, .y = 30.0f}}, AMOTION_EVENT_ACTION_MOVE}));
555 
556     invokeLooperCallback();
557     mConsumer->consumeBatchedInputEvents(nanoseconds{50ms}.count());
558     // Original and resampled event should be both overwritten.
559     assertReceivedMotionEvent(
560             {InputEventEntry{24ms,
561                              {Pointer{.id = 0, .x = 35.0f, .y = 30.0f, .isResampled = true}},
562                              AMOTION_EVENT_ACTION_MOVE},
563              InputEventEntry{26ms,
564                              {Pointer{.id = 0, .x = 45.0f, .y = 30.0f, .isResampled = true}},
565                              AMOTION_EVENT_ACTION_MOVE}});
566 
567     mClientTestChannel->assertFinishMessage(/*seq=*/1, /*handled=*/true);
568     mClientTestChannel->assertFinishMessage(/*seq=*/2, /*handled=*/true);
569     mClientTestChannel->assertFinishMessage(/*seq=*/3, /*handled=*/true);
570     mClientTestChannel->assertFinishMessage(/*seq=*/4, /*handled=*/true);
571 }
572 
TEST_F(InputConsumerResamplingTest,DoNotResampleWhenFrameTimeIsNotAvailable)573 TEST_F(InputConsumerResamplingTest, DoNotResampleWhenFrameTimeIsNotAvailable) {
574     mClientTestChannel->enqueueMessage(nextPointerMessage(
575             {0ms, {Pointer{.id = 0, .x = 10.0f, .y = 20.0f}}, AMOTION_EVENT_ACTION_DOWN}));
576 
577     invokeLooperCallback();
578     assertReceivedMotionEvent({InputEventEntry{0ms,
579                                                {Pointer{.id = 0, .x = 10.0f, .y = 20.0f}},
580                                                AMOTION_EVENT_ACTION_DOWN}});
581 
582     mClientTestChannel->enqueueMessage(nextPointerMessage(
583             {10ms, {Pointer{.id = 0, .x = 20.0f, .y = 30.0f}}, AMOTION_EVENT_ACTION_MOVE}));
584     mClientTestChannel->enqueueMessage(nextPointerMessage(
585             {20ms, {Pointer{.id = 0, .x = 30.0f, .y = 30.0f}}, AMOTION_EVENT_ACTION_MOVE}));
586 
587     invokeLooperCallback();
588     mConsumer->consumeBatchedInputEvents(std::nullopt);
589     assertReceivedMotionEvent({InputEventEntry{10ms,
590                                                {Pointer{.id = 0, .x = 20.0f, .y = 30.0f}},
591                                                AMOTION_EVENT_ACTION_MOVE},
592                                InputEventEntry{20ms,
593                                                {Pointer{.id = 0, .x = 30.0f, .y = 30.0f}},
594                                                AMOTION_EVENT_ACTION_MOVE}});
595 
596     mClientTestChannel->assertFinishMessage(/*seq=*/1, /*handled=*/true);
597     mClientTestChannel->assertFinishMessage(/*seq=*/2, /*handled=*/true);
598     mClientTestChannel->assertFinishMessage(/*seq=*/3, /*handled=*/true);
599 }
600 
TEST_F(InputConsumerResamplingTest,TwoPointersAreResampledIndependently)601 TEST_F(InputConsumerResamplingTest, TwoPointersAreResampledIndependently) {
602     // Full action for when a pointer with index=1 appears (some other pointer must already be
603     // present)
604     const int32_t actionPointer1Down =
605             AMOTION_EVENT_ACTION_POINTER_DOWN + (1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT);
606 
607     // Full action for when a pointer with index=0 disappears (some other pointer must still remain)
608     const int32_t actionPointer0Up =
609             AMOTION_EVENT_ACTION_POINTER_UP + (0 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT);
610 
611     mClientTestChannel->enqueueMessage(nextPointerMessage(
612             {0ms, {Pointer{.id = 0, .x = 100.0f, .y = 100.0f}}, AMOTION_EVENT_ACTION_DOWN}));
613 
614     mClientTestChannel->assertNoSentMessages();
615 
616     invokeLooperCallback();
617     assertReceivedMotionEvent({InputEventEntry{0ms,
618                                                {Pointer{.id = 0, .x = 100.0f, .y = 100.0f}},
619                                                AMOTION_EVENT_ACTION_DOWN}});
620 
621     mClientTestChannel->enqueueMessage(nextPointerMessage(
622             {10ms, {Pointer{.id = 0, .x = 100.0f, .y = 100.0f}}, AMOTION_EVENT_ACTION_MOVE}));
623 
624     invokeLooperCallback();
625     mConsumer->consumeBatchedInputEvents(nanoseconds{10ms + RESAMPLE_LATENCY}.count());
626     // Not resampled value because requestedFrameTime - RESAMPLE_LATENCY == eventTime
627     assertReceivedMotionEvent({InputEventEntry{10ms,
628                                                {Pointer{.id = 0, .x = 100.0f, .y = 100.0f}},
629                                                AMOTION_EVENT_ACTION_MOVE}});
630 
631     // Second pointer id=1 appears
632     mClientTestChannel->enqueueMessage(
633             nextPointerMessage({15ms,
634                                 {Pointer{.id = 0, .x = 100.0f, .y = 100.0f},
635                                  Pointer{.id = 1, .x = 500.0f, .y = 500.0f}},
636                                 actionPointer1Down}));
637 
638     invokeLooperCallback();
639     mConsumer->consumeBatchedInputEvents(nanoseconds{20ms + RESAMPLE_LATENCY}.count());
640     // Not resampled value because requestedFrameTime - RESAMPLE_LATENCY == eventTime.
641     assertReceivedMotionEvent({InputEventEntry{15ms,
642                                                {Pointer{.id = 0, .x = 100.0f, .y = 100.0f},
643                                                 Pointer{.id = 1, .x = 500.0f, .y = 500.0f}},
644                                                actionPointer1Down}});
645 
646     // Both pointers move
647     mClientTestChannel->enqueueMessage(
648             nextPointerMessage({30ms,
649                                 {Pointer{.id = 0, .x = 100.0f, .y = 100.0f},
650                                  Pointer{.id = 1, .x = 500.0f, .y = 500.0f}},
651                                 AMOTION_EVENT_ACTION_MOVE}));
652     mClientTestChannel->enqueueMessage(
653             nextPointerMessage({40ms,
654                                 {Pointer{.id = 0, .x = 120.0f, .y = 120.0f},
655                                  Pointer{.id = 1, .x = 600.0f, .y = 600.0f}},
656                                 AMOTION_EVENT_ACTION_MOVE}));
657 
658     invokeLooperCallback();
659     mConsumer->consumeBatchedInputEvents(nanoseconds{45ms + RESAMPLE_LATENCY}.count());
660     assertReceivedMotionEvent(
661             {InputEventEntry{30ms,
662                              {Pointer{.id = 0, .x = 100.0f, .y = 100.0f},
663                               Pointer{.id = 1, .x = 500.0f, .y = 500.0f}},
664                              AMOTION_EVENT_ACTION_MOVE},
665              InputEventEntry{40ms,
666                              {Pointer{.id = 0, .x = 120.0f, .y = 120.0f},
667                               Pointer{.id = 1, .x = 600.0f, .y = 600.0f}},
668                              AMOTION_EVENT_ACTION_MOVE},
669              InputEventEntry{45ms,
670                              {Pointer{.id = 0, .x = 130.0f, .y = 130.0f, .isResampled = true},
671                               Pointer{.id = 1, .x = 650.0f, .y = 650.0f, .isResampled = true}},
672                              AMOTION_EVENT_ACTION_MOVE}});
673 
674     // Both pointers move again
675     mClientTestChannel->enqueueMessage(
676             nextPointerMessage({60ms,
677                                 {Pointer{.id = 0, .x = 120.0f, .y = 120.0f},
678                                  Pointer{.id = 1, .x = 600.0f, .y = 600.0f}},
679                                 AMOTION_EVENT_ACTION_MOVE}));
680     mClientTestChannel->enqueueMessage(
681             nextPointerMessage({70ms,
682                                 {Pointer{.id = 0, .x = 130.0f, .y = 130.0f},
683                                  Pointer{.id = 1, .x = 700.0f, .y = 700.0f}},
684                                 AMOTION_EVENT_ACTION_MOVE}));
685 
686     invokeLooperCallback();
687     mConsumer->consumeBatchedInputEvents(nanoseconds{75ms + RESAMPLE_LATENCY}.count());
688 
689     /*
690      * The pointer id 0 at t = 60 should not be equal to 120 because the value was received twice,
691      * and resampled to 130. Therefore, if we reported 130, then we should continue to report it as
692      * such. Likewise, with pointer id 1.
693      */
694 
695     // Not 120 because it matches a previous real event.
696     assertReceivedMotionEvent(
697             {InputEventEntry{60ms,
698                              {Pointer{.id = 0, .x = 130.0f, .y = 130.0f, .isResampled = true},
699                               Pointer{.id = 1, .x = 650.0f, .y = 650.0f, .isResampled = true}},
700                              AMOTION_EVENT_ACTION_MOVE},
701              InputEventEntry{70ms,
702                              {Pointer{.id = 0, .x = 130.0f, .y = 130.0f},
703                               Pointer{.id = 1, .x = 700.0f, .y = 700.0f}},
704                              AMOTION_EVENT_ACTION_MOVE},
705              InputEventEntry{75ms,
706                              {Pointer{.id = 0, .x = 135.0f, .y = 135.0f, .isResampled = true},
707                               Pointer{.id = 1, .x = 750.0f, .y = 750.0f, .isResampled = true}},
708                              AMOTION_EVENT_ACTION_MOVE}});
709 
710     // First pointer id=0 leaves the screen
711     mClientTestChannel->enqueueMessage(
712             nextPointerMessage({80ms,
713                                 {Pointer{.id = 0, .x = 120.0f, .y = 120.0f},
714                                  Pointer{.id = 1, .x = 600.0f, .y = 600.0f}},
715                                 actionPointer0Up}));
716 
717     invokeLooperCallback();
718     // Not resampled event for ACTION_POINTER_UP
719     assertReceivedMotionEvent({InputEventEntry{80ms,
720                                                {Pointer{.id = 0, .x = 120.0f, .y = 120.0f},
721                                                 Pointer{.id = 1, .x = 600.0f, .y = 600.0f}},
722                                                actionPointer0Up}});
723 
724     // Remaining pointer id=1 is still present, but doesn't move
725     mClientTestChannel->enqueueMessage(nextPointerMessage(
726             {90ms, {Pointer{.id = 1, .x = 600.0f, .y = 600.0f}}, AMOTION_EVENT_ACTION_MOVE}));
727 
728     invokeLooperCallback();
729     mConsumer->consumeBatchedInputEvents(nanoseconds{100ms}.count());
730 
731     /*
732      * The latest event with ACTION_MOVE was at t = 70 with value = 700. Thus, the resampled value
733      * is 700 + ((95 - 70)/(90 - 70))*(600 - 700) = 575.
734      */
735     assertReceivedMotionEvent(
736             {InputEventEntry{90ms,
737                              {Pointer{.id = 1, .x = 600.0f, .y = 600.0f}},
738                              AMOTION_EVENT_ACTION_MOVE},
739              InputEventEntry{95ms,
740                              {Pointer{.id = 1, .x = 575.0f, .y = 575.0f, .isResampled = true}},
741                              AMOTION_EVENT_ACTION_MOVE}});
742 }
743 
744 } // namespace android
745