xref: /aosp_15_r20/frameworks/native/libs/input/tests/Resampler_test.cpp (revision 38e8c45f13ce32b0dcecb25141ffecaf386fa17f)
1 /**
2  * Copyright 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/Resampler.h>
18 
19 #include <gtest/gtest.h>
20 
21 #include <chrono>
22 #include <memory>
23 #include <vector>
24 
25 #include <input/Input.h>
26 #include <input/InputEventBuilders.h>
27 #include <input/InputTransport.h>
28 #include <utils/Timers.h>
29 
30 namespace android {
31 
32 namespace {
33 
34 using namespace std::literals::chrono_literals;
35 
36 constexpr float EPSILON = MotionEvent::ROUNDING_PRECISION;
37 
38 struct Pointer {
39     int32_t id{0};
40     ToolType toolType{ToolType::FINGER};
41     float x{0.0f};
42     float y{0.0f};
43     bool isResampled{false};
44     /**
45      * Converts from Pointer to PointerCoords. Enables calling LegacyResampler methods and
46      * assertions only with the relevant data for tests.
47      */
48     operator PointerCoords() const;
49 };
50 
operator PointerCoords() const51 Pointer::operator PointerCoords() const {
52     PointerCoords pointerCoords;
53     pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_X, x);
54     pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_Y, y);
55     pointerCoords.isResampled = isResampled;
56     return pointerCoords;
57 }
58 
59 struct InputSample {
60     std::chrono::milliseconds eventTime{0};
61     std::vector<Pointer> pointers{};
62 
InputSampleandroid::__anon666b95500111::InputSample63     explicit InputSample(std::chrono::milliseconds eventTime, const std::vector<Pointer>& pointers)
64           : eventTime{eventTime}, pointers{pointers} {}
65     /**
66      * Converts from InputSample to InputMessage. Enables calling LegacyResampler methods only with
67      * the relevant data for tests.
68      */
69     operator InputMessage() const;
70 };
71 
operator InputMessage() const72 InputSample::operator InputMessage() const {
73     InputMessageBuilder messageBuilder =
74             InputMessageBuilder{InputMessage::Type::MOTION, /*seq=*/0}
75                     .eventTime(std::chrono::nanoseconds{eventTime}.count())
76                     .source(AINPUT_SOURCE_TOUCHSCREEN)
77                     .downTime(0);
78 
79     for (const Pointer& pointer : pointers) {
80         messageBuilder.pointer(
81                 PointerBuilder{pointer.id, pointer.toolType}.x(pointer.x).y(pointer.y).isResampled(
82                         pointer.isResampled));
83     }
84     return messageBuilder.build();
85 }
86 
87 struct InputStream {
88     std::vector<InputSample> samples{};
89     int32_t action{0};
90     /**
91      * Converts from InputStream to MotionEvent. Enables calling LegacyResampler methods only with
92      * the relevant data for tests.
93      */
94     operator MotionEvent() const;
95 };
96 
operator MotionEvent() const97 InputStream::operator MotionEvent() const {
98     const InputSample& firstSample{*samples.begin()};
99     MotionEventBuilder motionEventBuilder =
100             MotionEventBuilder(action, AINPUT_SOURCE_CLASS_POINTER)
101                     .downTime(0)
102                     .eventTime(
103                             static_cast<std::chrono::nanoseconds>(firstSample.eventTime).count());
104     for (const Pointer& pointer : firstSample.pointers) {
105         const PointerBuilder pointerBuilder =
106                 PointerBuilder(pointer.id, pointer.toolType).x(pointer.x).y(pointer.y);
107         motionEventBuilder.pointer(pointerBuilder);
108     }
109     MotionEvent motionEvent = motionEventBuilder.build();
110     const size_t numSamples = samples.size();
111     for (size_t i = 1; i < numSamples; ++i) {
112         std::vector<PointerCoords> pointersCoords{samples[i].pointers.begin(),
113                                                   samples[i].pointers.end()};
114         motionEvent.addSample(static_cast<std::chrono::nanoseconds>(samples[i].eventTime).count(),
115                               pointersCoords.data(), motionEvent.getId());
116     }
117     return motionEvent;
118 }
119 
120 } // namespace
121 
122 /**
123  * The testing setup assumes an input rate of 200 Hz and a display rate of 60 Hz. This implies that
124  * input events are received every 5 milliseconds, while the display consumes batched events every
125  * ~16 milliseconds. The resampler's RESAMPLE_LATENCY constant determines the resample time, which
126  * is calculated as frameTime - RESAMPLE_LATENCY. resampleTime specifies the time used for
127  * resampling. For example, if the desired frame time consumption is ~16 milliseconds, the resample
128  * time would be ~11 milliseconds. Consequenly, the last added sample to the motion event has an
129  * event time of ~11 milliseconds. Note that there are specific scenarios where resampleMotionEvent
130  * is not called with a multiple of ~16 milliseconds. These cases are primarily for data addition
131  * or to test other functionalities of the resampler.
132  *
133  * Coordinates are calculated using linear interpolation (lerp) based on the last two available
134  * samples. Linear interpolation is defined as (a + alpha*(b - a)). Let t_b and t_a be the
135  * timestamps of samples a and b, respectively. The interpolation factor alpha is calculated as
136  * (resampleTime - t_a) / (t_b - t_a). The value of alpha determines whether the resampled
137  * coordinates are interpolated or extrapolated. If alpha falls within the semi-closed interval [0,
138  * 1), the coordinates are interpolated. If alpha is greater than or equal to 1, the coordinates are
139  * extrapolated.
140  *
141  * The timeline below depics an interpolation scenario
142  * -----------------------------------|---------|---------|---------|----------
143  *                                   10ms      11ms      15ms      16ms
144  *                                   MOVE       |        MOVE       |
145  *                                         resampleTime         frameTime
146  * Based on the timeline alpha is (11 - 10)/(15 - 10) = 1/5. Thus, coordinates are interpolated.
147  *
148  * The following timeline portrays an extrapolation scenario
149  * -------------------------|---------|---------|-------------------|----------
150  *                          5ms      10ms      11ms                16ms
151  *                          MOVE     MOVE       |                   |
152  *                                         resampleTime         frameTime
153  * Likewise, alpha = (11 - 5)/(10 - 5) = 6/5. Hence, coordinates are extrapolated.
154  *
155  * If a motion event was resampled, the tests will check that the following conditions are satisfied
156  * to guarantee resampling correctness:
157  * - The motion event metadata must not change.
158  * - The number of samples in the motion event must only increment by 1.
159  * - The resampled values must be at the end of motion event coordinates.
160  * - The rasamples values must be near the hand calculations.
161  * - The resampled time must be the most recent one in motion event.
162  */
163 class ResamplerTest : public testing::Test {
164 protected:
ResamplerTest()165     ResamplerTest() : mResampler(std::make_unique<LegacyResampler>()) {}
166 
~ResamplerTest()167     ~ResamplerTest() override {}
168 
SetUp()169     void SetUp() override {}
170 
TearDown()171     void TearDown() override {}
172 
173     std::unique_ptr<Resampler> mResampler;
174 
175     /**
176      * Checks that beforeCall and afterCall are equal except for the mutated attributes by addSample
177      * member function.
178      * @param beforeCall MotionEvent before passing it to resampleMotionEvent
179      * @param afterCall MotionEvent after passing it to resampleMotionEvent
180      */
181     void assertMotionEventMetaDataDidNotMutate(const MotionEvent& beforeCall,
182                                                const MotionEvent& afterCall);
183 
184     /**
185      * Asserts the MotionEvent is resampled by checking an increment in history size and that the
186      * resampled coordinates are near the expected ones.
187      */
188     void assertMotionEventIsResampledAndCoordsNear(
189             const MotionEvent& original, const MotionEvent& resampled,
190             const std::vector<PointerCoords>& expectedCoords);
191 
192     void assertMotionEventIsNotResampled(const MotionEvent& original,
193                                          const MotionEvent& notResampled);
194 };
195 
assertMotionEventMetaDataDidNotMutate(const MotionEvent & beforeCall,const MotionEvent & afterCall)196 void ResamplerTest::assertMotionEventMetaDataDidNotMutate(const MotionEvent& beforeCall,
197                                                           const MotionEvent& afterCall) {
198     EXPECT_EQ(beforeCall.getDeviceId(), afterCall.getDeviceId());
199     EXPECT_EQ(beforeCall.getAction(), afterCall.getAction());
200     EXPECT_EQ(beforeCall.getActionButton(), afterCall.getActionButton());
201     EXPECT_EQ(beforeCall.getButtonState(), afterCall.getButtonState());
202     EXPECT_EQ(beforeCall.getFlags(), afterCall.getFlags());
203     EXPECT_EQ(beforeCall.getEdgeFlags(), afterCall.getEdgeFlags());
204     EXPECT_EQ(beforeCall.getClassification(), afterCall.getClassification());
205     EXPECT_EQ(beforeCall.getPointerCount(), afterCall.getPointerCount());
206     EXPECT_EQ(beforeCall.getMetaState(), afterCall.getMetaState());
207     EXPECT_EQ(beforeCall.getSource(), afterCall.getSource());
208     EXPECT_EQ(beforeCall.getXPrecision(), afterCall.getXPrecision());
209     EXPECT_EQ(beforeCall.getYPrecision(), afterCall.getYPrecision());
210     EXPECT_EQ(beforeCall.getDownTime(), afterCall.getDownTime());
211     EXPECT_EQ(beforeCall.getDisplayId(), afterCall.getDisplayId());
212 }
213 
assertMotionEventIsResampledAndCoordsNear(const MotionEvent & original,const MotionEvent & resampled,const std::vector<PointerCoords> & expectedCoords)214 void ResamplerTest::assertMotionEventIsResampledAndCoordsNear(
215         const MotionEvent& original, const MotionEvent& resampled,
216         const std::vector<PointerCoords>& expectedCoords) {
217     assertMotionEventMetaDataDidNotMutate(original, resampled);
218 
219     const size_t originalSampleSize = original.getHistorySize() + 1;
220     const size_t resampledSampleSize = resampled.getHistorySize() + 1;
221     EXPECT_EQ(originalSampleSize + 1, resampledSampleSize);
222 
223     const size_t numPointers = resampled.getPointerCount();
224     const size_t beginLatestSample = resampledSampleSize - 1;
225     for (size_t i = 0; i < numPointers; ++i) {
226         SCOPED_TRACE(i);
227         EXPECT_EQ(original.getPointerId(i), resampled.getPointerId(i));
228         EXPECT_EQ(original.getToolType(i), resampled.getToolType(i));
229 
230         const PointerCoords& resampledCoords =
231                 resampled.getSamplePointerCoords()[beginLatestSample * numPointers + i];
232 
233         EXPECT_TRUE(resampledCoords.isResampled);
234         EXPECT_NEAR(expectedCoords[i].getX(), resampledCoords.getX(), EPSILON);
235         EXPECT_NEAR(expectedCoords[i].getY(), resampledCoords.getY(), EPSILON);
236     }
237 }
238 
assertMotionEventIsNotResampled(const MotionEvent & original,const MotionEvent & notResampled)239 void ResamplerTest::assertMotionEventIsNotResampled(const MotionEvent& original,
240                                                     const MotionEvent& notResampled) {
241     assertMotionEventMetaDataDidNotMutate(original, notResampled);
242     const size_t originalSampleSize = original.getHistorySize() + 1;
243     const size_t notResampledSampleSize = notResampled.getHistorySize() + 1;
244     EXPECT_EQ(originalSampleSize, notResampledSampleSize);
245 }
246 
TEST_F(ResamplerTest,NonResampledAxesArePreserved)247 TEST_F(ResamplerTest, NonResampledAxesArePreserved) {
248     constexpr float TOUCH_MAJOR_VALUE = 1.0f;
249 
250     MotionEvent motionEvent =
251             InputStream{{InputSample{5ms, {{.id = 0, .x = 1.0f, .y = 1.0f, .isResampled = false}}}},
252                         AMOTION_EVENT_ACTION_MOVE};
253 
254     constexpr std::chrono::nanoseconds eventTime{10ms};
255     PointerCoords pointerCoords{};
256     pointerCoords.isResampled = false;
257     pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_X, 2.0f);
258     pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_Y, 2.0f);
259     pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_TOUCH_MAJOR, TOUCH_MAJOR_VALUE);
260 
261     motionEvent.addSample(eventTime.count(), &pointerCoords, motionEvent.getId());
262 
263     const InputMessage futureSample =
264             InputSample{15ms, {{.id = 0, .x = 3.0f, .y = 4.0f, .isResampled = false}}};
265 
266     const MotionEvent originalMotionEvent = motionEvent;
267 
268     mResampler->resampleMotionEvent(16ms, motionEvent, &futureSample);
269 
270     EXPECT_EQ(motionEvent.getTouchMajor(0), TOUCH_MAJOR_VALUE);
271 
272     assertMotionEventIsResampledAndCoordsNear(originalMotionEvent, motionEvent,
273                                               {Pointer{.id = 0,
274                                                        .x = 2.2f,
275                                                        .y = 2.4f,
276                                                        .isResampled = true}});
277 }
278 
TEST_F(ResamplerTest,SinglePointerNotEnoughDataToResample)279 TEST_F(ResamplerTest, SinglePointerNotEnoughDataToResample) {
280     MotionEvent motionEvent =
281             InputStream{{InputSample{5ms, {{.id = 0, .x = 1.0f, .y = 1.0f, .isResampled = false}}}},
282                         AMOTION_EVENT_ACTION_MOVE};
283 
284     const MotionEvent originalMotionEvent = motionEvent;
285 
286     mResampler->resampleMotionEvent(16ms, motionEvent, /*futureSample=*/nullptr);
287 
288     assertMotionEventIsNotResampled(originalMotionEvent, motionEvent);
289 }
290 
TEST_F(ResamplerTest,SinglePointerSingleSampleInterpolation)291 TEST_F(ResamplerTest, SinglePointerSingleSampleInterpolation) {
292     MotionEvent motionEvent =
293             InputStream{{InputSample{10ms,
294                                      {{.id = 0, .x = 1.0f, .y = 2.0f, .isResampled = false}}}},
295                         AMOTION_EVENT_ACTION_MOVE};
296     const InputMessage futureSample =
297             InputSample{15ms, {{.id = 0, .x = 2.0f, .y = 4.0f, .isResampled = false}}};
298 
299     const MotionEvent originalMotionEvent = motionEvent;
300 
301     mResampler->resampleMotionEvent(16ms, motionEvent, &futureSample);
302 
303     assertMotionEventIsResampledAndCoordsNear(originalMotionEvent, motionEvent,
304                                               {Pointer{.id = 0,
305                                                        .x = 1.2f,
306                                                        .y = 2.4f,
307                                                        .isResampled = true}});
308 }
309 
TEST_F(ResamplerTest,SinglePointerDeltaTooSmallInterpolation)310 TEST_F(ResamplerTest, SinglePointerDeltaTooSmallInterpolation) {
311     MotionEvent motionEvent =
312             InputStream{{InputSample{10ms,
313                                      {{.id = 0, .x = 1.0f, .y = 2.0f, .isResampled = false}}}},
314                         AMOTION_EVENT_ACTION_MOVE};
315     const InputMessage futureSample =
316             InputSample{11ms, {{.id = 0, .x = 2.0f, .y = 4.0f, .isResampled = false}}};
317 
318     const MotionEvent originalMotionEvent = motionEvent;
319 
320     mResampler->resampleMotionEvent(10'500'000ns, motionEvent, &futureSample);
321 
322     assertMotionEventIsNotResampled(originalMotionEvent, motionEvent);
323 }
324 
325 /**
326  * Tests extrapolation given two MotionEvents with a single sample.
327  */
TEST_F(ResamplerTest,SinglePointerSingleSampleExtrapolation)328 TEST_F(ResamplerTest, SinglePointerSingleSampleExtrapolation) {
329     MotionEvent firstMotionEvent =
330             InputStream{{InputSample{5ms, {{.id = 0, .x = 1.0f, .y = 2.0f, .isResampled = false}}}},
331                         AMOTION_EVENT_ACTION_MOVE};
332 
333     mResampler->resampleMotionEvent(9ms, firstMotionEvent, nullptr);
334 
335     MotionEvent secondMotionEvent =
336             InputStream{{InputSample{10ms,
337                                      {{.id = 0, .x = 2.0f, .y = 4.0f, .isResampled = false}}}},
338                         AMOTION_EVENT_ACTION_MOVE};
339 
340     const MotionEvent originalMotionEvent = secondMotionEvent;
341 
342     mResampler->resampleMotionEvent(16ms, secondMotionEvent, nullptr);
343 
344     assertMotionEventIsResampledAndCoordsNear(originalMotionEvent, secondMotionEvent,
345                                               {Pointer{.id = 0,
346                                                        .x = 2.2f,
347                                                        .y = 4.4f,
348                                                        .isResampled = true}});
349 }
350 
TEST_F(ResamplerTest,SinglePointerMultipleSampleInterpolation)351 TEST_F(ResamplerTest, SinglePointerMultipleSampleInterpolation) {
352     MotionEvent motionEvent =
353             InputStream{{InputSample{5ms, {{.id = 0, .x = 1.0f, .y = 2.0f, .isResampled = false}}},
354                          InputSample{10ms,
355                                      {{.id = 0, .x = 2.0f, .y = 3.0f, .isResampled = false}}}},
356                         AMOTION_EVENT_ACTION_MOVE};
357 
358     const InputMessage futureSample =
359             InputSample{15ms, {{.id = 0, .x = 3.0f, .y = 5.0f, .isResampled = false}}};
360 
361     const MotionEvent originalMotionEvent = motionEvent;
362 
363     mResampler->resampleMotionEvent(16ms, motionEvent, &futureSample);
364 
365     assertMotionEventIsResampledAndCoordsNear(originalMotionEvent, motionEvent,
366                                               {Pointer{.id = 0,
367                                                        .x = 2.2f,
368                                                        .y = 3.4f,
369                                                        .isResampled = true}});
370 }
371 
TEST_F(ResamplerTest,SinglePointerMultipleSampleExtrapolation)372 TEST_F(ResamplerTest, SinglePointerMultipleSampleExtrapolation) {
373     MotionEvent motionEvent =
374             InputStream{{InputSample{5ms, {{.id = 0, .x = 1.0f, .y = 2.0f, .isResampled = false}}},
375                          InputSample{10ms,
376                                      {{.id = 0, .x = 2.0f, .y = 4.0f, .isResampled = false}}}},
377                         AMOTION_EVENT_ACTION_MOVE};
378 
379     const MotionEvent originalMotionEvent = motionEvent;
380 
381     mResampler->resampleMotionEvent(16ms, motionEvent, nullptr);
382 
383     assertMotionEventIsResampledAndCoordsNear(originalMotionEvent, motionEvent,
384                                               {Pointer{.id = 0,
385                                                        .x = 2.2f,
386                                                        .y = 4.4f,
387                                                        .isResampled = true}});
388 }
389 
TEST_F(ResamplerTest,SinglePointerDeltaTooSmallExtrapolation)390 TEST_F(ResamplerTest, SinglePointerDeltaTooSmallExtrapolation) {
391     MotionEvent motionEvent =
392             InputStream{{InputSample{9ms, {{.id = 0, .x = 1.0f, .y = 2.0f, .isResampled = false}}},
393                          InputSample{10ms,
394                                      {{.id = 0, .x = 2.0f, .y = 4.0f, .isResampled = false}}}},
395                         AMOTION_EVENT_ACTION_MOVE};
396 
397     const MotionEvent originalMotionEvent = motionEvent;
398 
399     mResampler->resampleMotionEvent(16ms, motionEvent, nullptr);
400 
401     assertMotionEventIsNotResampled(originalMotionEvent, motionEvent);
402 }
403 
TEST_F(ResamplerTest,SinglePointerDeltaTooLargeExtrapolation)404 TEST_F(ResamplerTest, SinglePointerDeltaTooLargeExtrapolation) {
405     MotionEvent motionEvent =
406             InputStream{{InputSample{5ms, {{.id = 0, .x = 1.0f, .y = 2.0f, .isResampled = false}}},
407                          InputSample{26ms,
408                                      {{.id = 0, .x = 2.0f, .y = 4.0f, .isResampled = false}}}},
409                         AMOTION_EVENT_ACTION_MOVE};
410 
411     const MotionEvent originalMotionEvent = motionEvent;
412 
413     mResampler->resampleMotionEvent(32ms, motionEvent, nullptr);
414 
415     assertMotionEventIsNotResampled(originalMotionEvent, motionEvent);
416 }
417 
TEST_F(ResamplerTest,SinglePointerResampleTimeTooFarExtrapolation)418 TEST_F(ResamplerTest, SinglePointerResampleTimeTooFarExtrapolation) {
419     MotionEvent motionEvent =
420             InputStream{{InputSample{5ms, {{.id = 0, .x = 1.0f, .y = 2.0f, .isResampled = false}}},
421                          InputSample{25ms,
422                                      {{.id = 0, .x = 2.0f, .y = 4.0f, .isResampled = false}}}},
423                         AMOTION_EVENT_ACTION_MOVE};
424 
425     const MotionEvent originalMotionEvent = motionEvent;
426 
427     mResampler->resampleMotionEvent(48ms, motionEvent, nullptr);
428 
429     assertMotionEventIsResampledAndCoordsNear(originalMotionEvent, motionEvent,
430                                               {Pointer{.id = 0,
431                                                        .x = 2.4f,
432                                                        .y = 4.8f,
433                                                        .isResampled = true}});
434 }
435 
TEST_F(ResamplerTest,MultiplePointerSingleSampleInterpolation)436 TEST_F(ResamplerTest, MultiplePointerSingleSampleInterpolation) {
437     MotionEvent motionEvent =
438             InputStream{{InputSample{5ms,
439                                      {{.id = 0, .x = 1.0f, .y = 1.0f, .isResampled = false},
440                                       {.id = 1, .x = 2.0f, .y = 2.0f, .isResampled = false}}}},
441                         AMOTION_EVENT_ACTION_MOVE};
442 
443     const InputMessage futureSample =
444             InputSample{15ms,
445                         {{.id = 0, .x = 3.0f, .y = 3.0f, .isResampled = false},
446                          {.id = 1, .x = 4.0f, .y = 4.0f, .isResampled = false}}};
447 
448     const MotionEvent originalMotionEvent = motionEvent;
449 
450     mResampler->resampleMotionEvent(16ms, motionEvent, &futureSample);
451 
452     assertMotionEventIsResampledAndCoordsNear(originalMotionEvent, motionEvent,
453                                               {Pointer{.x = 2.2f, .y = 2.2f, .isResampled = true},
454                                                Pointer{.x = 3.2f, .y = 3.2f, .isResampled = true}});
455 }
456 
TEST_F(ResamplerTest,MultiplePointerSingleSampleExtrapolation)457 TEST_F(ResamplerTest, MultiplePointerSingleSampleExtrapolation) {
458     MotionEvent firstMotionEvent =
459             InputStream{{InputSample{5ms,
460                                      {{.id = 0, .x = 1.0f, .y = 1.0f, .isResampled = false},
461                                       {.id = 1, .x = 2.0f, .y = 2.0f, .isResampled = false}}}},
462                         AMOTION_EVENT_ACTION_MOVE};
463 
464     mResampler->resampleMotionEvent(9ms, firstMotionEvent, /*futureSample=*/nullptr);
465 
466     MotionEvent secondMotionEvent =
467             InputStream{{InputSample{10ms,
468                                      {{.id = 0, .x = 3.0f, .y = 3.0f, .isResampled = false},
469                                       {.id = 1, .x = 4.0f, .y = 4.0f, .isResampled = false}}}},
470                         AMOTION_EVENT_ACTION_MOVE};
471 
472     const MotionEvent originalMotionEvent = secondMotionEvent;
473 
474     mResampler->resampleMotionEvent(16ms, secondMotionEvent, /*futureSample=*/nullptr);
475 
476     assertMotionEventIsResampledAndCoordsNear(originalMotionEvent, secondMotionEvent,
477                                               {Pointer{.x = 3.4f, .y = 3.4f, .isResampled = true},
478                                                Pointer{.x = 4.4f, .y = 4.4f, .isResampled = true}});
479 }
480 
TEST_F(ResamplerTest,MultiplePointerMultipleSampleInterpolation)481 TEST_F(ResamplerTest, MultiplePointerMultipleSampleInterpolation) {
482     MotionEvent motionEvent =
483             InputStream{{InputSample{5ms,
484                                      {{.id = 0, .x = 1.0f, .y = 1.0f, .isResampled = false},
485                                       {.id = 1, .x = 2.0f, .y = 2.0f, .isResampled = false}}},
486                          InputSample{10ms,
487                                      {{.id = 0, .x = 3.0f, .y = 3.0f, .isResampled = false},
488                                       {.id = 1, .x = 4.0f, .y = 4.0f, .isResampled = false}}}},
489                         AMOTION_EVENT_ACTION_MOVE};
490     const InputMessage futureSample =
491             InputSample{15ms,
492                         {{.id = 0, .x = 5.0f, .y = 5.0f, .isResampled = false},
493                          {.id = 1, .x = 6.0f, .y = 6.0f, .isResampled = false}}};
494 
495     const MotionEvent originalMotionEvent = motionEvent;
496 
497     mResampler->resampleMotionEvent(16ms, motionEvent, &futureSample);
498 
499     assertMotionEventIsResampledAndCoordsNear(originalMotionEvent, motionEvent,
500                                               {Pointer{.x = 3.4f, .y = 3.4f, .isResampled = true},
501                                                Pointer{.x = 4.4f, .y = 4.4f, .isResampled = true}});
502 }
503 
TEST_F(ResamplerTest,MultiplePointerMultipleSampleExtrapolation)504 TEST_F(ResamplerTest, MultiplePointerMultipleSampleExtrapolation) {
505     MotionEvent motionEvent =
506             InputStream{{InputSample{5ms,
507                                      {{.id = 0, .x = 1.0f, .y = 1.0f, .isResampled = false},
508                                       {.id = 1, .x = 2.0f, .y = 2.0f, .isResampled = false}}},
509                          InputSample{10ms,
510                                      {{.id = 0, .x = 3.0f, .y = 3.0f, .isResampled = false},
511                                       {.id = 1, .x = 4.0f, .y = 4.0f, .isResampled = false}}}},
512                         AMOTION_EVENT_ACTION_MOVE};
513 
514     const MotionEvent originalMotionEvent = motionEvent;
515 
516     mResampler->resampleMotionEvent(16ms, motionEvent, /*futureSample=*/nullptr);
517 
518     assertMotionEventIsResampledAndCoordsNear(originalMotionEvent, motionEvent,
519                                               {Pointer{.x = 3.4f, .y = 3.4f, .isResampled = true},
520                                                Pointer{.x = 4.4f, .y = 4.4f, .isResampled = true}});
521 }
522 
TEST_F(ResamplerTest,MultiplePointerIncreaseNumPointersInterpolation)523 TEST_F(ResamplerTest, MultiplePointerIncreaseNumPointersInterpolation) {
524     MotionEvent motionEvent =
525             InputStream{{InputSample{10ms,
526                                      {{.id = 0, .x = 1.0f, .y = 1.0f, .isResampled = false},
527                                       {.id = 1, .x = 2.0f, .y = 2.0f, .isResampled = false}}}},
528                         AMOTION_EVENT_ACTION_MOVE};
529 
530     const InputMessage futureSample =
531             InputSample{15ms,
532                         {{.id = 0, .x = 3.0f, .y = 3.0f, .isResampled = false},
533                          {.id = 1, .x = 4.0f, .y = 4.0f, .isResampled = false},
534                          {.id = 2, .x = 5.0f, .y = 5.0f, .isResampled = false}}};
535 
536     const MotionEvent originalMotionEvent = motionEvent;
537 
538     mResampler->resampleMotionEvent(16ms, motionEvent, &futureSample);
539 
540     assertMotionEventIsResampledAndCoordsNear(originalMotionEvent, motionEvent,
541                                               {Pointer{.x = 1.4f, .y = 1.4f, .isResampled = true},
542                                                Pointer{.x = 2.4f, .y = 2.4f, .isResampled = true}});
543 
544     MotionEvent secondMotionEvent =
545             InputStream{{InputSample{25ms,
546                                      {{.id = 0, .x = 3.0f, .y = 3.0f, .isResampled = false},
547                                       {.id = 1, .x = 4.0f, .y = 4.0f, .isResampled = false},
548                                       {.id = 2, .x = 5.0f, .y = 5.0f, .isResampled = false}}}},
549                         AMOTION_EVENT_ACTION_MOVE};
550 
551     const InputMessage secondFutureSample =
552             InputSample{30ms,
553                         {{.id = 0, .x = 5.0f, .y = 5.0f, .isResampled = false},
554                          {.id = 1, .x = 6.0f, .y = 6.0f, .isResampled = false},
555                          {.id = 2, .x = 7.0f, .y = 7.0f, .isResampled = false}}};
556 
557     const MotionEvent originalSecondMotionEvent = secondMotionEvent;
558 
559     mResampler->resampleMotionEvent(32ms, secondMotionEvent, &secondFutureSample);
560 
561     assertMotionEventIsResampledAndCoordsNear(originalSecondMotionEvent, secondMotionEvent,
562                                               {Pointer{.x = 3.8f, .y = 3.8f, .isResampled = true},
563                                                Pointer{.x = 4.8f, .y = 4.8f, .isResampled = true},
564                                                Pointer{.x = 5.8f, .y = 5.8f, .isResampled = true}});
565 }
566 
TEST_F(ResamplerTest,MultiplePointerIncreaseNumPointersExtrapolation)567 TEST_F(ResamplerTest, MultiplePointerIncreaseNumPointersExtrapolation) {
568     MotionEvent firstMotionEvent =
569             InputStream{{InputSample{5ms,
570                                      {{.id = 0, .x = 1.0f, .y = 1.0f, .isResampled = false},
571                                       {.id = 1, .x = 2.0f, .y = 2.0f, .isResampled = false}}}},
572                         AMOTION_EVENT_ACTION_MOVE};
573 
574     mResampler->resampleMotionEvent(9ms, firstMotionEvent, /*futureSample=*/nullptr);
575 
576     MotionEvent secondMotionEvent =
577             InputStream{{InputSample{10ms,
578                                      {{.id = 0, .x = 3.0f, .y = 3.0f, .isResampled = false},
579                                       {.id = 1, .x = 4.0f, .y = 4.0f, .isResampled = false},
580                                       {.id = 2, .x = 5.0f, .y = 5.0f, .isResampled = false}}}},
581                         AMOTION_EVENT_ACTION_MOVE};
582 
583     const MotionEvent secondOriginalMotionEvent = secondMotionEvent;
584 
585     mResampler->resampleMotionEvent(16ms, secondMotionEvent, /*futureSample=*/nullptr);
586 
587     assertMotionEventIsNotResampled(secondOriginalMotionEvent, secondMotionEvent);
588 }
589 
TEST_F(ResamplerTest,MultiplePointerDecreaseNumPointersInterpolation)590 TEST_F(ResamplerTest, MultiplePointerDecreaseNumPointersInterpolation) {
591     MotionEvent motionEvent =
592             InputStream{{InputSample{10ms,
593                                      {{.id = 0, .x = 3.0f, .y = 3.0f, .isResampled = false},
594                                       {.id = 1, .x = 4.0f, .y = 4.0f, .isResampled = false},
595                                       {.id = 2, .x = 5.0f, .y = 5.0f, .isResampled = false}}}},
596                         AMOTION_EVENT_ACTION_MOVE};
597 
598     const InputMessage futureSample =
599             InputSample{15ms,
600                         {{.id = 0, .x = 4.0f, .y = 4.0f, .isResampled = false},
601                          {.id = 1, .x = 5.0f, .y = 5.0f, .isResampled = false}}};
602 
603     const MotionEvent originalMotionEvent = motionEvent;
604 
605     mResampler->resampleMotionEvent(16ms, motionEvent, &futureSample);
606 
607     assertMotionEventIsNotResampled(originalMotionEvent, motionEvent);
608 }
609 
TEST_F(ResamplerTest,MultiplePointerDecreaseNumPointersExtrapolation)610 TEST_F(ResamplerTest, MultiplePointerDecreaseNumPointersExtrapolation) {
611     MotionEvent firstMotionEvent =
612             InputStream{{InputSample{5ms,
613                                      {{.id = 0, .x = 1.0f, .y = 1.0f, .isResampled = false},
614                                       {.id = 1, .x = 2.0f, .y = 2.0f, .isResampled = false},
615                                       {.id = 2, .x = 3.0f, .y = 3.0f, .isResampled = false}}}},
616                         AMOTION_EVENT_ACTION_MOVE};
617 
618     mResampler->resampleMotionEvent(9ms, firstMotionEvent, /*futureSample=*/nullptr);
619 
620     MotionEvent secondMotionEvent =
621             InputStream{{InputSample{10ms,
622                                      {{.id = 0, .x = 3.0f, .y = 3.0f, .isResampled = false},
623                                       {.id = 1, .x = 4.0f, .y = 4.0f, .isResampled = false}}}},
624                         AMOTION_EVENT_ACTION_MOVE};
625 
626     const MotionEvent secondOriginalMotionEvent = secondMotionEvent;
627 
628     mResampler->resampleMotionEvent(16ms, secondMotionEvent, /*futureSample=*/nullptr);
629 
630     assertMotionEventIsResampledAndCoordsNear(secondOriginalMotionEvent, secondMotionEvent,
631                                               {Pointer{.x = 3.4f, .y = 3.4f, .isResampled = true},
632                                                Pointer{.x = 4.4f, .y = 4.4f, .isResampled = true}});
633 }
634 
TEST_F(ResamplerTest,MultiplePointerDifferentIdOrderInterpolation)635 TEST_F(ResamplerTest, MultiplePointerDifferentIdOrderInterpolation) {
636     MotionEvent motionEvent =
637             InputStream{{InputSample{10ms,
638                                      {{.id = 0, .x = 1.0f, .y = 1.0f, .isResampled = false},
639                                       {.id = 1, .x = 2.0f, .y = 2.0f, .isResampled = false}}}},
640                         AMOTION_EVENT_ACTION_MOVE};
641 
642     const InputMessage futureSample =
643             InputSample{15ms,
644                         {{.id = 1, .x = 4.0f, .y = 4.0f, .isResampled = false},
645                          {.id = 0, .x = 3.0f, .y = 3.0f, .isResampled = false}}};
646 
647     const MotionEvent originalMotionEvent = motionEvent;
648 
649     mResampler->resampleMotionEvent(16ms, motionEvent, &futureSample);
650 
651     assertMotionEventIsResampledAndCoordsNear(originalMotionEvent, motionEvent,
652                                               {Pointer{.id = 0,
653                                                        .x = 1.4f,
654                                                        .y = 1.4f,
655                                                        .isResampled = true},
656                                                Pointer{.id = 1,
657                                                        .x = 2.4f,
658                                                        .y = 2.4f,
659                                                        .isResampled = true}});
660 }
661 
TEST_F(ResamplerTest,MultiplePointerDifferentIdOrderExtrapolation)662 TEST_F(ResamplerTest, MultiplePointerDifferentIdOrderExtrapolation) {
663     MotionEvent firstMotionEvent =
664             InputStream{{InputSample{5ms,
665                                      {{.id = 0, .x = 1.0f, .y = 1.0f, .isResampled = false},
666                                       {.id = 1, .x = 2.0f, .y = 2.0f, .isResampled = false}}}},
667                         AMOTION_EVENT_ACTION_MOVE};
668 
669     mResampler->resampleMotionEvent(9ms, firstMotionEvent, /*futureSample=*/nullptr);
670 
671     MotionEvent secondMotionEvent =
672             InputStream{{InputSample{10ms,
673                                      {{.id = 1, .x = 4.0f, .y = 4.0f, .isResampled = false},
674                                       {.id = 0, .x = 3.0f, .y = 3.0f, .isResampled = false}}}},
675                         AMOTION_EVENT_ACTION_MOVE};
676 
677     const MotionEvent secondOriginalMotionEvent = secondMotionEvent;
678 
679     mResampler->resampleMotionEvent(16ms, secondMotionEvent, /*futureSample=*/nullptr);
680 
681     assertMotionEventIsResampledAndCoordsNear(secondOriginalMotionEvent, secondMotionEvent,
682                                               {Pointer{.id = 1,
683                                                        .x = 4.4f,
684                                                        .y = 4.4f,
685                                                        .isResampled = true},
686                                                Pointer{.id = 0,
687                                                        .x = 3.4f,
688                                                        .y = 3.4f,
689                                                        .isResampled = true}});
690 }
691 
TEST_F(ResamplerTest,MultiplePointerDifferentIdsInterpolation)692 TEST_F(ResamplerTest, MultiplePointerDifferentIdsInterpolation) {
693     MotionEvent motionEvent =
694             InputStream{{InputSample{10ms,
695                                      {{.id = 0, .x = 1.0f, .y = 1.0f, .isResampled = false},
696                                       {.id = 1, .x = 2.0f, .y = 2.0f, .isResampled = false}}}},
697                         AMOTION_EVENT_ACTION_MOVE};
698 
699     const InputMessage futureSample =
700             InputSample{15ms,
701                         {{.id = 1, .x = 4.0f, .y = 4.0f, .isResampled = false},
702                          {.id = 2, .x = 3.0f, .y = 3.0f, .isResampled = false}}};
703 
704     const MotionEvent originalMotionEvent = motionEvent;
705 
706     mResampler->resampleMotionEvent(16ms, motionEvent, &futureSample);
707 
708     assertMotionEventIsNotResampled(originalMotionEvent, motionEvent);
709 }
710 
TEST_F(ResamplerTest,MultiplePointerDifferentIdsExtrapolation)711 TEST_F(ResamplerTest, MultiplePointerDifferentIdsExtrapolation) {
712     MotionEvent firstMotionEvent =
713             InputStream{{InputSample{5ms,
714                                      {{.id = 0, .x = 1.0f, .y = 1.0f, .isResampled = false},
715                                       {.id = 1, .x = 2.0f, .y = 2.0f, .isResampled = false}}}},
716                         AMOTION_EVENT_ACTION_MOVE};
717 
718     mResampler->resampleMotionEvent(9ms, firstMotionEvent, /*futureSample=*/nullptr);
719 
720     MotionEvent secondMotionEvent =
721             InputStream{{InputSample{10ms,
722                                      {{.id = 1, .x = 4.0f, .y = 4.0f, .isResampled = false},
723                                       {.id = 2, .x = 3.0f, .y = 3.0f, .isResampled = false}}}},
724                         AMOTION_EVENT_ACTION_MOVE};
725 
726     const MotionEvent secondOriginalMotionEvent = secondMotionEvent;
727 
728     mResampler->resampleMotionEvent(16ms, secondMotionEvent, /*futureSample=*/nullptr);
729 
730     assertMotionEventIsNotResampled(secondOriginalMotionEvent, secondMotionEvent);
731 }
732 
TEST_F(ResamplerTest,MultiplePointerDifferentToolTypeInterpolation)733 TEST_F(ResamplerTest, MultiplePointerDifferentToolTypeInterpolation) {
734     MotionEvent motionEvent = InputStream{{InputSample{10ms,
735                                                        {{.id = 0,
736                                                          .toolType = ToolType::FINGER,
737                                                          .x = 1.0f,
738                                                          .y = 1.0f,
739                                                          .isResampled = false},
740                                                         {.id = 1,
741                                                          .toolType = ToolType::FINGER,
742                                                          .x = 2.0f,
743                                                          .y = 2.0f,
744                                                          .isResampled = false}}}},
745                                           AMOTION_EVENT_ACTION_MOVE};
746 
747     const InputMessage futureSample = InputSample{15ms,
748                                                   {{.id = 0,
749                                                     .toolType = ToolType::FINGER,
750                                                     .x = 3.0,
751                                                     .y = 3.0,
752                                                     .isResampled = false},
753                                                    {.id = 1,
754                                                     .toolType = ToolType::STYLUS,
755                                                     .x = 4.0,
756                                                     .y = 4.0,
757                                                     .isResampled = false}}};
758 
759     const MotionEvent originalMotionEvent = motionEvent;
760 
761     mResampler->resampleMotionEvent(16ms, motionEvent, &futureSample);
762 
763     assertMotionEventIsNotResampled(originalMotionEvent, motionEvent);
764 }
765 
TEST_F(ResamplerTest,MultiplePointerDifferentToolTypeExtrapolation)766 TEST_F(ResamplerTest, MultiplePointerDifferentToolTypeExtrapolation) {
767     MotionEvent firstMotionEvent = InputStream{{InputSample{5ms,
768                                                             {{.id = 0,
769                                                               .toolType = ToolType::FINGER,
770                                                               .x = 1.0f,
771                                                               .y = 1.0f,
772                                                               .isResampled = false},
773                                                              {.id = 1,
774                                                               .toolType = ToolType::FINGER,
775                                                               .x = 2.0f,
776                                                               .y = 2.0f,
777                                                               .isResampled = false}}}},
778                                                AMOTION_EVENT_ACTION_MOVE};
779 
780     mResampler->resampleMotionEvent(9ms, firstMotionEvent, /*futureSample=*/nullptr);
781 
782     MotionEvent secondMotionEvent = InputStream{{InputSample{10ms,
783                                                              {{.id = 0,
784                                                                .toolType = ToolType::FINGER,
785                                                                .x = 1.0f,
786                                                                .y = 1.0f,
787                                                                .isResampled = false},
788                                                               {.id = 1,
789                                                                .toolType = ToolType::STYLUS,
790                                                                .x = 2.0f,
791                                                                .y = 2.0f,
792                                                                .isResampled = false}}}},
793                                                 AMOTION_EVENT_ACTION_MOVE};
794 
795     const MotionEvent secondOriginalMotionEvent = secondMotionEvent;
796 
797     mResampler->resampleMotionEvent(16ms, secondMotionEvent, /*futureSample=*/nullptr);
798 
799     assertMotionEventIsNotResampled(secondOriginalMotionEvent, secondMotionEvent);
800 }
801 
TEST_F(ResamplerTest,MultiplePointerShouldNotResampleToolTypeInterpolation)802 TEST_F(ResamplerTest, MultiplePointerShouldNotResampleToolTypeInterpolation) {
803     MotionEvent motionEvent = InputStream{{InputSample{10ms,
804                                                        {{.id = 0,
805                                                          .toolType = ToolType::PALM,
806                                                          .x = 1.0f,
807                                                          .y = 1.0f,
808                                                          .isResampled = false},
809                                                         {.id = 1,
810                                                          .toolType = ToolType::PALM,
811                                                          .x = 2.0f,
812                                                          .y = 2.0f,
813                                                          .isResampled = false}}}},
814                                           AMOTION_EVENT_ACTION_MOVE};
815 
816     const InputMessage futureSample = InputSample{15ms,
817                                                   {{.id = 0,
818                                                     .toolType = ToolType::PALM,
819                                                     .x = 3.0,
820                                                     .y = 3.0,
821                                                     .isResampled = false},
822                                                    {.id = 1,
823                                                     .toolType = ToolType::PALM,
824                                                     .x = 4.0,
825                                                     .y = 4.0,
826                                                     .isResampled = false}}};
827 
828     const MotionEvent originalMotionEvent = motionEvent;
829 
830     mResampler->resampleMotionEvent(16ms, motionEvent, /*futureSample=*/nullptr);
831 
832     assertMotionEventIsNotResampled(originalMotionEvent, motionEvent);
833 }
834 
TEST_F(ResamplerTest,MultiplePointerShouldNotResampleToolTypeExtrapolation)835 TEST_F(ResamplerTest, MultiplePointerShouldNotResampleToolTypeExtrapolation) {
836     MotionEvent motionEvent = InputStream{{InputSample{5ms,
837                                                        {{.id = 0,
838                                                          .toolType = ToolType::PALM,
839                                                          .x = 1.0f,
840                                                          .y = 1.0f,
841                                                          .isResampled = false},
842                                                         {.id = 1,
843                                                          .toolType = ToolType::PALM,
844                                                          .x = 2.0f,
845                                                          .y = 2.0f,
846                                                          .isResampled = false}}},
847                                            InputSample{10ms,
848                                                        {{.id = 0,
849                                                          .toolType = ToolType::PALM,
850                                                          .x = 3.0f,
851                                                          .y = 3.0f,
852                                                          .isResampled = false},
853                                                         {.id = 1,
854                                                          .toolType = ToolType::PALM,
855                                                          .x = 4.0f,
856                                                          .y = 4.0f,
857                                                          .isResampled = false}}}},
858                                           AMOTION_EVENT_ACTION_MOVE};
859 
860     const MotionEvent originalMotionEvent = motionEvent;
861 
862     mResampler->resampleMotionEvent(16ms, motionEvent, /*futureSample=*/nullptr);
863 
864     assertMotionEventIsNotResampled(originalMotionEvent, motionEvent);
865 }
866 } // namespace android
867