• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2022 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 <chrono>
18 #include <vector>
19 
20 #include <attestation/HmacKeyManager.h>
21 #include <gtest/gtest.h>
22 #include <input/InputConsumer.h>
23 #include <input/InputTransport.h>
24 
25 using namespace std::chrono_literals;
26 
27 namespace android {
28 
29 namespace {
30 
31 struct Pointer {
32     int32_t id;
33     float x;
34     float y;
35     ToolType toolType = ToolType::FINGER;
36     bool isResampled = false;
37 };
38 
39 struct InputEventEntry {
40     std::chrono::nanoseconds eventTime;
41     std::vector<Pointer> pointers;
42     int32_t action;
43 };
44 
45 } // namespace
46 
47 class TouchResamplingTest : public testing::Test {
48 protected:
49     std::unique_ptr<InputPublisher> mPublisher;
50     std::unique_ptr<InputConsumer> mConsumer;
51     PreallocatedInputEventFactory mEventFactory;
52 
53     uint32_t mSeq = 1;
54 
SetUp()55     void SetUp() override {
56         std::unique_ptr<InputChannel> serverChannel, clientChannel;
57         status_t result =
58                 InputChannel::openInputChannelPair("channel name", serverChannel, clientChannel);
59         ASSERT_EQ(OK, result);
60 
61         mPublisher = std::make_unique<InputPublisher>(std::move(serverChannel));
62         mConsumer = std::make_unique<InputConsumer>(std::move(clientChannel),
63                                                     /*enableTouchResampling=*/true);
64     }
65 
66     status_t publishSimpleMotionEventWithCoords(int32_t action, nsecs_t eventTime,
67                                                 const std::vector<PointerProperties>& properties,
68                                                 const std::vector<PointerCoords>& coords);
69     void publishSimpleMotionEvent(int32_t action, nsecs_t eventTime,
70                                   const std::vector<Pointer>& pointers);
71     void publishInputEventEntries(const std::vector<InputEventEntry>& entries);
72     void consumeInputEventEntries(const std::vector<InputEventEntry>& entries,
73                                   std::chrono::nanoseconds frameTime);
74     void receiveResponseUntilSequence(uint32_t seq);
75 };
76 
publishSimpleMotionEventWithCoords(int32_t action,nsecs_t eventTime,const std::vector<PointerProperties> & properties,const std::vector<PointerCoords> & coords)77 status_t TouchResamplingTest::publishSimpleMotionEventWithCoords(
78         int32_t action, nsecs_t eventTime, const std::vector<PointerProperties>& properties,
79         const std::vector<PointerCoords>& coords) {
80     const ui::Transform identityTransform;
81     const nsecs_t downTime = 0;
82 
83     if (action == AMOTION_EVENT_ACTION_DOWN && eventTime != 0) {
84         ADD_FAILURE() << "Downtime should be equal to 0 (hardcoded for convenience)";
85     }
86     return mPublisher->publishMotionEvent(mSeq++, InputEvent::nextId(), /*deviceId=*/1,
87                                           AINPUT_SOURCE_TOUCHSCREEN, ui::LogicalDisplayId::DEFAULT,
88                                           INVALID_HMAC, action, /*actionButton=*/0, /*flags=*/0,
89                                           /*edgeFlags=*/0, AMETA_NONE, /*buttonState=*/0,
90                                           MotionClassification::NONE, identityTransform,
91                                           /*xPrecision=*/0, /*yPrecision=*/0,
92                                           AMOTION_EVENT_INVALID_CURSOR_POSITION,
93                                           AMOTION_EVENT_INVALID_CURSOR_POSITION, identityTransform,
94                                           downTime, eventTime, properties.size(), properties.data(),
95                                           coords.data());
96 }
97 
publishSimpleMotionEvent(int32_t action,nsecs_t eventTime,const std::vector<Pointer> & pointers)98 void TouchResamplingTest::publishSimpleMotionEvent(int32_t action, nsecs_t eventTime,
99                                                    const std::vector<Pointer>& pointers) {
100     std::vector<PointerProperties> properties;
101     std::vector<PointerCoords> coords;
102 
103     for (const Pointer& pointer : pointers) {
104         properties.push_back({});
105         properties.back().clear();
106         properties.back().id = pointer.id;
107         properties.back().toolType = pointer.toolType;
108 
109         coords.push_back({});
110         coords.back().clear();
111         coords.back().setAxisValue(AMOTION_EVENT_AXIS_X, pointer.x);
112         coords.back().setAxisValue(AMOTION_EVENT_AXIS_Y, pointer.y);
113     }
114 
115     status_t result = publishSimpleMotionEventWithCoords(action, eventTime, properties, coords);
116     ASSERT_EQ(OK, result);
117 }
118 
119 /**
120  * Each entry is published separately, one entry at a time. As a result, action is used here
121  * on a per-entry basis.
122  */
publishInputEventEntries(const std::vector<InputEventEntry> & entries)123 void TouchResamplingTest::publishInputEventEntries(const std::vector<InputEventEntry>& entries) {
124     for (const InputEventEntry& entry : entries) {
125         publishSimpleMotionEvent(entry.action, entry.eventTime.count(), entry.pointers);
126     }
127 }
128 
129 /**
130  * Inside the publisher, read responses repeatedly until the desired sequence number is returned.
131  *
132  * Sometimes, when you call 'sendFinishedSignal', you would be finishing a batch which is comprised
133  * of several input events. As a result, consumer will generate multiple 'finish' signals on your
134  * behalf.
135  *
136  * In this function, we call 'receiveConsumerResponse' in a loop until the desired sequence number
137  * is returned.
138  */
receiveResponseUntilSequence(uint32_t seq)139 void TouchResamplingTest::receiveResponseUntilSequence(uint32_t seq) {
140     size_t consumedEvents = 0;
141     while (consumedEvents < 100) {
142         android::base::Result<InputPublisher::ConsumerResponse> response =
143                 mPublisher->receiveConsumerResponse();
144         ASSERT_TRUE(response.ok());
145         ASSERT_TRUE(std::holds_alternative<InputPublisher::Finished>(*response));
146         const InputPublisher::Finished& finish = std::get<InputPublisher::Finished>(*response);
147         ASSERT_TRUE(finish.handled)
148                 << "publisher receiveFinishedSignal should have set handled to consumer's reply";
149         if (finish.seq == seq) {
150             return;
151         }
152         consumedEvents++;
153     }
154     FAIL() << "Got " << consumedEvents << "events, but still no event with seq=" << seq;
155 }
156 
157 /**
158  * All entries are compared against a single MotionEvent, but the same data structure
159  * InputEventEntry is used here for simpler code. As a result, the entire array of InputEventEntry
160  * must contain identical values for the action field.
161  */
consumeInputEventEntries(const std::vector<InputEventEntry> & entries,std::chrono::nanoseconds frameTime)162 void TouchResamplingTest::consumeInputEventEntries(const std::vector<InputEventEntry>& entries,
163                                                    std::chrono::nanoseconds frameTime) {
164     ASSERT_GE(entries.size(), 1U) << "Must have at least 1 InputEventEntry to compare against";
165 
166     uint32_t consumeSeq;
167     InputEvent* event;
168 
169     status_t status = mConsumer->consume(&mEventFactory, /*consumeBatches=*/true, frameTime.count(),
170                                          &consumeSeq, &event);
171     ASSERT_EQ(OK, status);
172     MotionEvent* motionEvent = static_cast<MotionEvent*>(event);
173 
174     ASSERT_EQ(entries.size() - 1, motionEvent->getHistorySize());
175     for (size_t i = 0; i < entries.size(); i++) { // most recent sample is last
176         SCOPED_TRACE(i);
177         const InputEventEntry& entry = entries[i];
178         ASSERT_EQ(entry.action, motionEvent->getAction());
179         ASSERT_EQ(entry.eventTime.count(), motionEvent->getHistoricalEventTime(i));
180         ASSERT_EQ(entry.pointers.size(), motionEvent->getPointerCount());
181 
182         for (size_t p = 0; p < motionEvent->getPointerCount(); p++) {
183             SCOPED_TRACE(p);
184             // The pointers can be in any order, both in MotionEvent as well as InputEventEntry
185             ssize_t motionEventPointerIndex = motionEvent->findPointerIndex(entry.pointers[p].id);
186             ASSERT_GE(motionEventPointerIndex, 0) << "Pointer must be present in MotionEvent";
187             ASSERT_EQ(entry.pointers[p].x,
188                       motionEvent->getHistoricalAxisValue(AMOTION_EVENT_AXIS_X,
189                                                           motionEventPointerIndex, i));
190             ASSERT_EQ(entry.pointers[p].x,
191                       motionEvent->getHistoricalRawAxisValue(AMOTION_EVENT_AXIS_X,
192                                                              motionEventPointerIndex, i));
193             ASSERT_EQ(entry.pointers[p].y,
194                       motionEvent->getHistoricalAxisValue(AMOTION_EVENT_AXIS_Y,
195                                                           motionEventPointerIndex, i));
196             ASSERT_EQ(entry.pointers[p].y,
197                       motionEvent->getHistoricalRawAxisValue(AMOTION_EVENT_AXIS_Y,
198                                                              motionEventPointerIndex, i));
199             ASSERT_EQ(entry.pointers[p].isResampled,
200                       motionEvent->isResampled(motionEventPointerIndex, i));
201         }
202     }
203 
204     status = mConsumer->sendFinishedSignal(consumeSeq, true);
205     ASSERT_EQ(OK, status);
206 
207     receiveResponseUntilSequence(consumeSeq);
208 }
209 
210 /**
211  * Timeline
212  * ---------+------------------+------------------+--------+-----------------+----------------------
213  *          0 ms               10 ms              20 ms    25 ms            35 ms
214  *          ACTION_DOWN       ACTION_MOVE      ACTION_MOVE  ^                ^
215  *                                                          |                |
216  *                                                         resampled value   |
217  *                                                                          frameTime
218  * Typically, the prediction is made for time frameTime - RESAMPLE_LATENCY, or 30 ms in this case
219  * However, that would be 10 ms later than the last real sample (which came in at 20 ms).
220  * Therefore, the resampling should happen at 20 ms + RESAMPLE_MAX_PREDICTION = 28 ms.
221  * In this situation, though, resample time is further limited by taking half of the difference
222  * between the last two real events, which would put this time at:
223  * 20 ms + (20 ms - 10 ms) / 2 = 25 ms.
224  */
TEST_F(TouchResamplingTest,EventIsResampled)225 TEST_F(TouchResamplingTest, EventIsResampled) {
226     std::chrono::nanoseconds frameTime;
227     std::vector<InputEventEntry> entries, expectedEntries;
228 
229     // Initial ACTION_DOWN should be separate, because the first consume event will only return
230     // InputEvent with a single action.
231     entries = {
232             //      id  x   y
233             {0ms, {{0, 10, 20}}, AMOTION_EVENT_ACTION_DOWN},
234     };
235     publishInputEventEntries(entries);
236     frameTime = 5ms;
237     expectedEntries = {
238             //      id  x   y
239             {0ms, {{0, 10, 20}}, AMOTION_EVENT_ACTION_DOWN},
240     };
241     consumeInputEventEntries(expectedEntries, frameTime);
242 
243     // Two ACTION_MOVE events 10 ms apart that move in X direction and stay still in Y
244     entries = {
245             //      id  x   y
246             {10ms, {{0, 20, 30}}, AMOTION_EVENT_ACTION_MOVE},
247             {20ms, {{0, 30, 30}}, AMOTION_EVENT_ACTION_MOVE},
248     };
249     publishInputEventEntries(entries);
250     frameTime = 35ms;
251     expectedEntries = {
252             //      id  x   y
253             {10ms, {{0, 20, 30}}, AMOTION_EVENT_ACTION_MOVE},
254             {20ms, {{0, 30, 30}}, AMOTION_EVENT_ACTION_MOVE},
255             {25ms, {{0, 35, 30, .isResampled = true}}, AMOTION_EVENT_ACTION_MOVE},
256     };
257     consumeInputEventEntries(expectedEntries, frameTime);
258 }
259 
260 /**
261  * Same as above test, but use pointer id=1 instead of 0 to make sure that system does not
262  * have these hardcoded.
263  */
TEST_F(TouchResamplingTest,EventIsResampledWithDifferentId)264 TEST_F(TouchResamplingTest, EventIsResampledWithDifferentId) {
265     std::chrono::nanoseconds frameTime;
266     std::vector<InputEventEntry> entries, expectedEntries;
267 
268     // Initial ACTION_DOWN should be separate, because the first consume event will only return
269     // InputEvent with a single action.
270     entries = {
271             //      id  x   y
272             {0ms, {{1, 10, 20}}, AMOTION_EVENT_ACTION_DOWN},
273     };
274     publishInputEventEntries(entries);
275     frameTime = 5ms;
276     expectedEntries = {
277             //      id  x   y
278             {0ms, {{1, 10, 20}}, AMOTION_EVENT_ACTION_DOWN},
279     };
280     consumeInputEventEntries(expectedEntries, frameTime);
281 
282     // Two ACTION_MOVE events 10 ms apart that move in X direction and stay still in Y
283     entries = {
284             //      id  x   y
285             {10ms, {{1, 20, 30}}, AMOTION_EVENT_ACTION_MOVE},
286             {20ms, {{1, 30, 30}}, AMOTION_EVENT_ACTION_MOVE},
287     };
288     publishInputEventEntries(entries);
289     frameTime = 35ms;
290     expectedEntries = {
291             //      id  x   y
292             {10ms, {{1, 20, 30}}, AMOTION_EVENT_ACTION_MOVE},
293             {20ms, {{1, 30, 30}}, AMOTION_EVENT_ACTION_MOVE},
294             {25ms, {{1, 35, 30, .isResampled = true}}, AMOTION_EVENT_ACTION_MOVE},
295     };
296     consumeInputEventEntries(expectedEntries, frameTime);
297 }
298 
299 /**
300  * Stylus pointer coordinates are resampled.
301  */
TEST_F(TouchResamplingTest,StylusEventIsResampled)302 TEST_F(TouchResamplingTest, StylusEventIsResampled) {
303     std::chrono::nanoseconds frameTime;
304     std::vector<InputEventEntry> entries, expectedEntries;
305 
306     // Initial ACTION_DOWN should be separate, because the first consume event will only return
307     // InputEvent with a single action.
308     entries = {
309             //      id  x   y
310             {0ms, {{0, 10, 20, .toolType = ToolType::STYLUS}}, AMOTION_EVENT_ACTION_DOWN},
311     };
312     publishInputEventEntries(entries);
313     frameTime = 5ms;
314     expectedEntries = {
315             //      id  x   y
316             {0ms, {{0, 10, 20, .toolType = ToolType::STYLUS}}, AMOTION_EVENT_ACTION_DOWN},
317     };
318     consumeInputEventEntries(expectedEntries, frameTime);
319 
320     // Two ACTION_MOVE events 10 ms apart that move in X direction and stay still in Y
321     entries = {
322             //      id  x   y
323             {10ms, {{0, 20, 30, .toolType = ToolType::STYLUS}}, AMOTION_EVENT_ACTION_MOVE},
324             {20ms, {{0, 30, 30, .toolType = ToolType::STYLUS}}, AMOTION_EVENT_ACTION_MOVE},
325     };
326     publishInputEventEntries(entries);
327     frameTime = 35ms;
328     expectedEntries = {
329             //      id  x   y
330             {10ms, {{0, 20, 30, .toolType = ToolType::STYLUS}}, AMOTION_EVENT_ACTION_MOVE},
331             {20ms, {{0, 30, 30, .toolType = ToolType::STYLUS}}, AMOTION_EVENT_ACTION_MOVE},
332             {25ms,
333              {{0, 35, 30, .toolType = ToolType::STYLUS, .isResampled = true}},
334              AMOTION_EVENT_ACTION_MOVE},
335     };
336     consumeInputEventEntries(expectedEntries, frameTime);
337 }
338 
339 /**
340  * Mouse pointer coordinates are resampled.
341  */
TEST_F(TouchResamplingTest,MouseEventIsResampled)342 TEST_F(TouchResamplingTest, MouseEventIsResampled) {
343     std::chrono::nanoseconds frameTime;
344     std::vector<InputEventEntry> entries, expectedEntries;
345 
346     // Initial ACTION_DOWN should be separate, because the first consume event will only return
347     // InputEvent with a single action.
348     entries = {
349             //      id  x   y
350             {0ms, {{0, 10, 20, .toolType = ToolType::MOUSE}}, AMOTION_EVENT_ACTION_DOWN},
351     };
352     publishInputEventEntries(entries);
353     frameTime = 5ms;
354     expectedEntries = {
355             //      id  x   y
356             {0ms, {{0, 10, 20, .toolType = ToolType::MOUSE}}, AMOTION_EVENT_ACTION_DOWN},
357     };
358     consumeInputEventEntries(expectedEntries, frameTime);
359 
360     // Two ACTION_MOVE events 10 ms apart that move in X direction and stay still in Y
361     entries = {
362             //      id  x   y
363             {10ms, {{0, 20, 30, .toolType = ToolType::MOUSE}}, AMOTION_EVENT_ACTION_MOVE},
364             {20ms, {{0, 30, 30, .toolType = ToolType::MOUSE}}, AMOTION_EVENT_ACTION_MOVE},
365     };
366     publishInputEventEntries(entries);
367     frameTime = 35ms;
368     expectedEntries = {
369             //      id  x   y
370             {10ms, {{0, 20, 30, .toolType = ToolType::MOUSE}}, AMOTION_EVENT_ACTION_MOVE},
371             {20ms, {{0, 30, 30, .toolType = ToolType::MOUSE}}, AMOTION_EVENT_ACTION_MOVE},
372             {25ms,
373              {{0, 35, 30, .toolType = ToolType::MOUSE, .isResampled = true}},
374              AMOTION_EVENT_ACTION_MOVE},
375     };
376     consumeInputEventEntries(expectedEntries, frameTime);
377 }
378 
379 /**
380  * Motion events with palm tool type are not resampled.
381  */
TEST_F(TouchResamplingTest,PalmEventIsNotResampled)382 TEST_F(TouchResamplingTest, PalmEventIsNotResampled) {
383     std::chrono::nanoseconds frameTime;
384     std::vector<InputEventEntry> entries, expectedEntries;
385 
386     // Initial ACTION_DOWN should be separate, because the first consume event will only return
387     // InputEvent with a single action.
388     entries = {
389             //      id  x   y
390             {0ms, {{0, 10, 20, .toolType = ToolType::PALM}}, AMOTION_EVENT_ACTION_DOWN},
391     };
392     publishInputEventEntries(entries);
393     frameTime = 5ms;
394     expectedEntries = {
395             //      id  x   y
396             {0ms, {{0, 10, 20, .toolType = ToolType::PALM}}, AMOTION_EVENT_ACTION_DOWN},
397     };
398     consumeInputEventEntries(expectedEntries, frameTime);
399 
400     // Two ACTION_MOVE events 10 ms apart that move in X direction and stay still in Y
401     entries = {
402             //      id  x   y
403             {10ms, {{0, 20, 30, .toolType = ToolType::PALM}}, AMOTION_EVENT_ACTION_MOVE},
404             {20ms, {{0, 30, 30, .toolType = ToolType::PALM}}, AMOTION_EVENT_ACTION_MOVE},
405     };
406     publishInputEventEntries(entries);
407     frameTime = 35ms;
408     expectedEntries = {
409             //      id  x   y
410             {10ms, {{0, 20, 30, .toolType = ToolType::PALM}}, AMOTION_EVENT_ACTION_MOVE},
411             {20ms, {{0, 30, 30, .toolType = ToolType::PALM}}, AMOTION_EVENT_ACTION_MOVE},
412     };
413     consumeInputEventEntries(expectedEntries, frameTime);
414 }
415 
416 /**
417  * Event should not be resampled when sample time is equal to event time.
418  */
TEST_F(TouchResamplingTest,SampleTimeEqualsEventTime)419 TEST_F(TouchResamplingTest, SampleTimeEqualsEventTime) {
420     std::chrono::nanoseconds frameTime;
421     std::vector<InputEventEntry> entries, expectedEntries;
422 
423     // Initial ACTION_DOWN should be separate, because the first consume event will only return
424     // InputEvent with a single action.
425     entries = {
426             //      id  x   y
427             {0ms, {{0, 10, 20}}, AMOTION_EVENT_ACTION_DOWN},
428     };
429     publishInputEventEntries(entries);
430     frameTime = 5ms;
431     expectedEntries = {
432             //      id  x   y
433             {0ms, {{0, 10, 20}}, AMOTION_EVENT_ACTION_DOWN},
434     };
435     consumeInputEventEntries(expectedEntries, frameTime);
436 
437     // Two ACTION_MOVE events 10 ms apart that move in X direction and stay still in Y
438     entries = {
439             //      id  x   y
440             {10ms, {{0, 20, 30}}, AMOTION_EVENT_ACTION_MOVE},
441             {20ms, {{0, 30, 30}}, AMOTION_EVENT_ACTION_MOVE},
442     };
443     publishInputEventEntries(entries);
444     frameTime = 20ms + 5ms /*RESAMPLE_LATENCY*/;
445     expectedEntries = {
446             //      id  x   y
447             {10ms, {{0, 20, 30}}, AMOTION_EVENT_ACTION_MOVE},
448             {20ms, {{0, 30, 30}}, AMOTION_EVENT_ACTION_MOVE},
449             // no resampled event because the time of resample falls exactly on the existing event
450     };
451     consumeInputEventEntries(expectedEntries, frameTime);
452 }
453 
454 /**
455  * Once we send a resampled value to the app, we should continue to "lie" if the pointer
456  * does not move. So, if the pointer keeps the same coordinates, resampled value should continue
457  * to be used.
458  */
TEST_F(TouchResamplingTest,ResampledValueIsUsedForIdenticalCoordinates)459 TEST_F(TouchResamplingTest, ResampledValueIsUsedForIdenticalCoordinates) {
460     std::chrono::nanoseconds frameTime;
461     std::vector<InputEventEntry> entries, expectedEntries;
462 
463     // Initial ACTION_DOWN should be separate, because the first consume event will only return
464     // InputEvent with a single action.
465     entries = {
466             //      id  x   y
467             {0ms, {{0, 10, 20}}, AMOTION_EVENT_ACTION_DOWN},
468     };
469     publishInputEventEntries(entries);
470     frameTime = 5ms;
471     expectedEntries = {
472             //      id  x   y
473             {0ms, {{0, 10, 20}}, AMOTION_EVENT_ACTION_DOWN},
474     };
475     consumeInputEventEntries(expectedEntries, frameTime);
476 
477     // Two ACTION_MOVE events 10 ms apart that move in X direction and stay still in Y
478     entries = {
479             //      id  x   y
480             {10ms, {{0, 20, 30}}, AMOTION_EVENT_ACTION_MOVE},
481             {20ms, {{0, 30, 30}}, AMOTION_EVENT_ACTION_MOVE},
482     };
483     publishInputEventEntries(entries);
484     frameTime = 35ms;
485     expectedEntries = {
486             //      id  x   y
487             {10ms, {{0, 20, 30}}, AMOTION_EVENT_ACTION_MOVE},
488             {20ms, {{0, 30, 30}}, AMOTION_EVENT_ACTION_MOVE},
489             {25ms, {{0, 35, 30, .isResampled = true}}, AMOTION_EVENT_ACTION_MOVE},
490     };
491     consumeInputEventEntries(expectedEntries, frameTime);
492 
493     // Coordinate value 30 has been resampled to 35. When a new event comes in with value 30 again,
494     // the system should still report 35.
495     entries = {
496             //      id  x   y
497             {40ms, {{0, 30, 30}}, AMOTION_EVENT_ACTION_MOVE},
498     };
499     publishInputEventEntries(entries);
500     frameTime = 45ms + 5ms /*RESAMPLE_LATENCY*/;
501     expectedEntries = {
502             //      id  x   y
503             {40ms,
504              {{0, 35, 30, .isResampled = true}},
505              AMOTION_EVENT_ACTION_MOVE}, // original event, rewritten
506             {45ms,
507              {{0, 35, 30, .isResampled = true}},
508              AMOTION_EVENT_ACTION_MOVE}, // resampled event, rewritten
509     };
510     consumeInputEventEntries(expectedEntries, frameTime);
511 }
512 
TEST_F(TouchResamplingTest,OldEventReceivedAfterResampleOccurs)513 TEST_F(TouchResamplingTest, OldEventReceivedAfterResampleOccurs) {
514     std::chrono::nanoseconds frameTime;
515     std::vector<InputEventEntry> entries, expectedEntries;
516 
517     // Initial ACTION_DOWN should be separate, because the first consume event will only return
518     // InputEvent with a single action.
519     entries = {
520             //      id  x   y
521             {0ms, {{0, 10, 20}}, AMOTION_EVENT_ACTION_DOWN},
522     };
523     publishInputEventEntries(entries);
524     frameTime = 5ms;
525     expectedEntries = {
526             //      id  x   y
527             {0ms, {{0, 10, 20}}, AMOTION_EVENT_ACTION_DOWN},
528     };
529     consumeInputEventEntries(expectedEntries, frameTime);
530 
531     // Two ACTION_MOVE events 10 ms apart that move in X direction and stay still in Y
532     entries = {
533             //      id  x   y
534             {10ms, {{0, 20, 30}}, AMOTION_EVENT_ACTION_MOVE},
535             {20ms, {{0, 30, 30}}, AMOTION_EVENT_ACTION_MOVE},
536     };
537     publishInputEventEntries(entries);
538     frameTime = 35ms;
539     expectedEntries = {
540             //      id  x   y
541             {10ms, {{0, 20, 30}}, AMOTION_EVENT_ACTION_MOVE},
542             {20ms, {{0, 30, 30}}, AMOTION_EVENT_ACTION_MOVE},
543             {25ms, {{0, 35, 30, .isResampled = true}}, AMOTION_EVENT_ACTION_MOVE},
544     };
545     consumeInputEventEntries(expectedEntries, frameTime);
546     // Above, the resampled event is at 25ms rather than at 30 ms = 35ms - RESAMPLE_LATENCY
547     // because we are further bound by how far we can extrapolate by the "last time delta".
548     // That's 50% of (20 ms - 10ms) => 5ms. So we can't predict more than 5 ms into the future
549     // from the event at 20ms, which is why the resampled event is at t = 25 ms.
550 
551     // We resampled the event to 25 ms. Now, an older 'real' event comes in.
552     entries = {
553             //      id  x   y
554             {24ms, {{0, 40, 30}}, AMOTION_EVENT_ACTION_MOVE},
555     };
556     publishInputEventEntries(entries);
557     frameTime = 50ms;
558     expectedEntries = {
559             //      id  x   y
560             {24ms,
561              {{0, 35, 30, .isResampled = true}},
562              AMOTION_EVENT_ACTION_MOVE}, // original event, rewritten
563             {26ms,
564              {{0, 45, 30, .isResampled = true}},
565              AMOTION_EVENT_ACTION_MOVE}, // resampled event, rewritten
566     };
567     consumeInputEventEntries(expectedEntries, frameTime);
568 }
569 
TEST_F(TouchResamplingTest,TwoPointersAreResampledIndependently)570 TEST_F(TouchResamplingTest, TwoPointersAreResampledIndependently) {
571     std::chrono::nanoseconds frameTime;
572     std::vector<InputEventEntry> entries, expectedEntries;
573 
574     // full action for when a pointer with id=1 appears (some other pointer must already be present)
575     constexpr int32_t actionPointer1Down =
576             AMOTION_EVENT_ACTION_POINTER_DOWN + (1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT);
577 
578     // full action for when a pointer with id=0 disappears (some other pointer must still remain)
579     constexpr int32_t actionPointer0Up =
580             AMOTION_EVENT_ACTION_POINTER_UP + (0 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT);
581 
582     // Initial ACTION_DOWN should be separate, because the first consume event will only return
583     // InputEvent with a single action.
584     entries = {
585             //      id  x   y
586             {0ms, {{0, 100, 100}}, AMOTION_EVENT_ACTION_DOWN},
587     };
588     publishInputEventEntries(entries);
589     frameTime = 5ms;
590     expectedEntries = {
591             //      id  x   y
592             {0ms, {{0, 100, 100}}, AMOTION_EVENT_ACTION_DOWN},
593     };
594     consumeInputEventEntries(expectedEntries, frameTime);
595 
596     entries = {
597             //       id  x   y
598             {10ms, {{0, 100, 100}}, AMOTION_EVENT_ACTION_MOVE},
599     };
600     publishInputEventEntries(entries);
601     frameTime = 10ms + 5ms /*RESAMPLE_LATENCY*/;
602     expectedEntries = {
603             //       id  x   y
604             {10ms, {{0, 100, 100}}, AMOTION_EVENT_ACTION_MOVE},
605             // no resampled value because frameTime - RESAMPLE_LATENCY == eventTime
606     };
607     consumeInputEventEntries(expectedEntries, frameTime);
608 
609     // Second pointer id=1 appears
610     entries = {
611             //      id  x    y
612             {15ms, {{0, 100, 100}, {1, 500, 500}}, actionPointer1Down},
613     };
614     publishInputEventEntries(entries);
615     frameTime = 20ms + 5ms /*RESAMPLE_LATENCY*/;
616     expectedEntries = {
617             //      id  x    y
618             {15ms, {{0, 100, 100}, {1, 500, 500}}, actionPointer1Down},
619             // no resampled value because frameTime - RESAMPLE_LATENCY == eventTime
620     };
621     consumeInputEventEntries(expectedEntries, frameTime);
622 
623     // Both pointers move
624     entries = {
625             //      id  x    y
626             {30ms, {{0, 100, 100}, {1, 500, 500}}, AMOTION_EVENT_ACTION_MOVE},
627             {40ms, {{0, 120, 120}, {1, 600, 600}}, AMOTION_EVENT_ACTION_MOVE},
628     };
629     publishInputEventEntries(entries);
630     frameTime = 45ms + 5ms /*RESAMPLE_LATENCY*/;
631     expectedEntries = {
632             //      id  x    y
633             {30ms, {{0, 100, 100}, {1, 500, 500}}, AMOTION_EVENT_ACTION_MOVE},
634             {40ms, {{0, 120, 120}, {1, 600, 600}}, AMOTION_EVENT_ACTION_MOVE},
635             {45ms,
636              {{0, 130, 130, .isResampled = true}, {1, 650, 650, .isResampled = true}},
637              AMOTION_EVENT_ACTION_MOVE},
638     };
639     consumeInputEventEntries(expectedEntries, frameTime);
640 
641     // Both pointers move again
642     entries = {
643             //      id  x    y
644             {60ms, {{0, 120, 120}, {1, 600, 600}}, AMOTION_EVENT_ACTION_MOVE},
645             {70ms, {{0, 130, 130}, {1, 700, 700}}, AMOTION_EVENT_ACTION_MOVE},
646     };
647     publishInputEventEntries(entries);
648     frameTime = 75ms + 5ms /*RESAMPLE_LATENCY*/;
649     /**
650      * The sample at t = 60, pointer id 0 is not equal to 120, because this value of 120 was
651      * received twice, and resampled to 130. So if we already reported it as "130", we continue
652      * to report it as such. Similar with pointer id 1.
653      */
654     expectedEntries = {
655             {60ms,
656              {{0, 130, 130, .isResampled = true}, // not 120! because it matches previous real event
657               {1, 650, 650, .isResampled = true}},
658              AMOTION_EVENT_ACTION_MOVE},
659             {70ms, {{0, 130, 130}, {1, 700, 700}}, AMOTION_EVENT_ACTION_MOVE},
660             {75ms,
661              {{0, 135, 135, .isResampled = true}, {1, 750, 750, .isResampled = true}},
662              AMOTION_EVENT_ACTION_MOVE},
663     };
664     consumeInputEventEntries(expectedEntries, frameTime);
665 
666     // First pointer id=0 leaves the screen
667     entries = {
668             //      id  x    y
669             {80ms, {{0, 120, 120}, {1, 600, 600}}, actionPointer0Up},
670     };
671     publishInputEventEntries(entries);
672     frameTime = 90ms;
673     expectedEntries = {
674             //      id  x    y
675             {80ms, {{0, 120, 120}, {1, 600, 600}}, actionPointer0Up},
676             // no resampled event for ACTION_POINTER_UP
677     };
678     consumeInputEventEntries(expectedEntries, frameTime);
679 
680     // Remaining pointer id=1 is still present, but doesn't move
681     entries = {
682             //      id  x    y
683             {90ms, {{1, 600, 600}}, AMOTION_EVENT_ACTION_MOVE},
684     };
685     publishInputEventEntries(entries);
686     frameTime = 100ms;
687     expectedEntries = {
688             //      id  x    y
689             {90ms, {{1, 600, 600}}, AMOTION_EVENT_ACTION_MOVE},
690             /**
691              * The latest event with ACTION_MOVE was at t = 70, coord = 700.
692              * Use that value for resampling here: (600 - 700) / (90 - 70) * 5 + 600
693              */
694             {95ms, {{1, 575, 575, .isResampled = true}}, AMOTION_EVENT_ACTION_MOVE},
695     };
696     consumeInputEventEntries(expectedEntries, frameTime);
697 }
698 
699 } // namespace android
700