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