blob: 883ca82fe08294fa419d867610501fc607c1898f [file] [log] [blame]
Paul Ramirez5d59a422024-10-01 15:59:16 +00001/*
2 * Copyright (C) 2024 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#include <input/InputConsumerNoResampling.h>
18
19#include <chrono>
20#include <memory>
21#include <string>
22#include <vector>
23
24#include <TestEventMatchers.h>
25#include <TestInputChannel.h>
26#include <attestation/HmacKeyManager.h>
27#include <gmock/gmock.h>
28#include <gtest/gtest.h>
29#include <input/BlockingQueue.h>
30#include <input/InputEventBuilders.h>
31#include <input/Resampler.h>
32#include <utils/Looper.h>
33#include <utils/StrongPointer.h>
34
35namespace android {
36namespace {
37
38using std::chrono::nanoseconds;
39using namespace std::chrono_literals;
40
41struct Pointer {
42 int32_t id{0};
43 float x{0.0f};
44 float y{0.0f};
45 ToolType toolType{ToolType::FINGER};
46 bool isResampled{false};
47
48 PointerBuilder asPointerBuilder() const {
49 return PointerBuilder{id, toolType}.x(x).y(y).isResampled(isResampled);
50 }
51};
52
53struct InputEventEntry {
54 std::chrono::nanoseconds eventTime{0};
55 std::vector<Pointer> pointers{};
56 int32_t action{-1};
57};
58
59} // namespace
60
61class InputConsumerResamplingTest : public ::testing::Test, public InputConsumerCallbacks {
62protected:
63 InputConsumerResamplingTest()
64 : mClientTestChannel{std::make_shared<TestInputChannel>("TestChannel")},
65 mLooper{sp<Looper>::make(/*allowNonCallbacks=*/false)} {
66 Looper::setForThread(mLooper);
67 mConsumer = std::make_unique<
68 InputConsumerNoResampling>(mClientTestChannel, mLooper, *this,
69 []() { return std::make_unique<LegacyResampler>(); });
70 }
71
72 void invokeLooperCallback() const {
73 sp<LooperCallback> callback;
74 ASSERT_TRUE(mLooper->getFdStateDebug(mClientTestChannel->getFd(), /*ident=*/nullptr,
75 /*events=*/nullptr, &callback, /*data=*/nullptr));
76 ASSERT_NE(callback, nullptr);
77 callback->handleEvent(mClientTestChannel->getFd(), ALOOPER_EVENT_INPUT, /*data=*/nullptr);
78 }
79
80 InputMessage nextPointerMessage(const InputEventEntry& entry);
81
82 void assertReceivedMotionEvent(const std::vector<InputEventEntry>& expectedEntries);
83
84 std::shared_ptr<TestInputChannel> mClientTestChannel;
85 sp<Looper> mLooper;
86 std::unique_ptr<InputConsumerNoResampling> mConsumer;
87
88 BlockingQueue<std::unique_ptr<KeyEvent>> mKeyEvents;
89 BlockingQueue<std::unique_ptr<MotionEvent>> mMotionEvents;
90 BlockingQueue<std::unique_ptr<FocusEvent>> mFocusEvents;
91 BlockingQueue<std::unique_ptr<CaptureEvent>> mCaptureEvents;
92 BlockingQueue<std::unique_ptr<DragEvent>> mDragEvents;
93 BlockingQueue<std::unique_ptr<TouchModeEvent>> mTouchModeEvents;
94
95private:
96 uint32_t mLastSeq{0};
97 size_t mOnBatchedInputEventPendingInvocationCount{0};
98
99 // InputConsumerCallbacks interface
100 void onKeyEvent(std::unique_ptr<KeyEvent> event, uint32_t seq) override {
101 mKeyEvents.push(std::move(event));
102 mConsumer->finishInputEvent(seq, true);
103 }
104 void onMotionEvent(std::unique_ptr<MotionEvent> event, uint32_t seq) override {
105 mMotionEvents.push(std::move(event));
106 mConsumer->finishInputEvent(seq, true);
107 }
108 void onBatchedInputEventPending(int32_t pendingBatchSource) override {
109 if (!mConsumer->probablyHasInput()) {
110 ADD_FAILURE() << "should deterministically have input because there is a batch";
111 }
112 ++mOnBatchedInputEventPendingInvocationCount;
113 }
114 void onFocusEvent(std::unique_ptr<FocusEvent> event, uint32_t seq) override {
115 mFocusEvents.push(std::move(event));
116 mConsumer->finishInputEvent(seq, true);
117 }
118 void onCaptureEvent(std::unique_ptr<CaptureEvent> event, uint32_t seq) override {
119 mCaptureEvents.push(std::move(event));
120 mConsumer->finishInputEvent(seq, true);
121 }
122 void onDragEvent(std::unique_ptr<DragEvent> event, uint32_t seq) override {
123 mDragEvents.push(std::move(event));
124 mConsumer->finishInputEvent(seq, true);
125 }
126 void onTouchModeEvent(std::unique_ptr<TouchModeEvent> event, uint32_t seq) override {
127 mTouchModeEvents.push(std::move(event));
128 mConsumer->finishInputEvent(seq, true);
129 }
130};
131
132InputMessage InputConsumerResamplingTest::nextPointerMessage(const InputEventEntry& entry) {
133 ++mLastSeq;
134 InputMessageBuilder messageBuilder = InputMessageBuilder{InputMessage::Type::MOTION, mLastSeq}
135 .eventTime(entry.eventTime.count())
136 .deviceId(1)
137 .action(entry.action)
138 .downTime(0);
139 for (const Pointer& pointer : entry.pointers) {
140 messageBuilder.pointer(pointer.asPointerBuilder());
141 }
142 return messageBuilder.build();
143}
144
145void InputConsumerResamplingTest::assertReceivedMotionEvent(
146 const std::vector<InputEventEntry>& expectedEntries) {
147 std::unique_ptr<MotionEvent> motionEvent = mMotionEvents.pop();
148 ASSERT_NE(motionEvent, nullptr);
149
150 ASSERT_EQ(motionEvent->getHistorySize() + 1, expectedEntries.size());
151
152 for (size_t sampleIndex = 0; sampleIndex < expectedEntries.size(); ++sampleIndex) {
153 SCOPED_TRACE("sampleIndex: " + std::to_string(sampleIndex));
154 const InputEventEntry& expectedEntry = expectedEntries[sampleIndex];
155 EXPECT_EQ(motionEvent->getHistoricalEventTime(sampleIndex),
156 expectedEntry.eventTime.count());
157 EXPECT_EQ(motionEvent->getPointerCount(), expectedEntry.pointers.size());
158 EXPECT_EQ(motionEvent->getAction(), expectedEntry.action);
159
160 for (size_t pointerIndex = 0; pointerIndex < expectedEntry.pointers.size();
161 ++pointerIndex) {
162 SCOPED_TRACE("pointerIndex: " + std::to_string(pointerIndex));
163 ssize_t eventPointerIndex =
164 motionEvent->findPointerIndex(expectedEntry.pointers[pointerIndex].id);
165 EXPECT_EQ(motionEvent->getHistoricalRawX(eventPointerIndex, sampleIndex),
166 expectedEntry.pointers[pointerIndex].x);
167 EXPECT_EQ(motionEvent->getHistoricalRawY(eventPointerIndex, sampleIndex),
168 expectedEntry.pointers[pointerIndex].y);
169 EXPECT_EQ(motionEvent->getHistoricalX(eventPointerIndex, sampleIndex),
170 expectedEntry.pointers[pointerIndex].x);
171 EXPECT_EQ(motionEvent->getHistoricalY(eventPointerIndex, sampleIndex),
172 expectedEntry.pointers[pointerIndex].y);
173 EXPECT_EQ(motionEvent->isResampled(pointerIndex, sampleIndex),
174 expectedEntry.pointers[pointerIndex].isResampled);
175 }
176 }
177}
178
179/**
180 * Timeline
181 * ---------+------------------+------------------+--------+-----------------+----------------------
182 * 0 ms 10 ms 20 ms 25 ms 35 ms
183 * ACTION_DOWN ACTION_MOVE ACTION_MOVE ^ ^
184 * | |
185 * resampled value |
186 * frameTime
187 * Typically, the prediction is made for time frameTime - RESAMPLE_LATENCY, or 30 ms in this case,
188 * where RESAMPLE_LATENCY equals 5 milliseconds. However, that would be 10 ms later than the last
189 * real sample (which came in at 20 ms). Therefore, the resampling should happen at 20 ms +
190 * RESAMPLE_MAX_PREDICTION = 28 ms, where RESAMPLE_MAX_PREDICTION equals 8 milliseconds. In this
191 * situation, though, resample time is further limited by taking half of the difference between the
192 * last two real events, which would put this time at: 20 ms + (20 ms - 10 ms) / 2 = 25 ms.
193 */
194TEST_F(InputConsumerResamplingTest, EventIsResampled) {
Paul Ramirez7f1efed2024-09-29 23:55:23 +0000195 // Send the initial ACTION_DOWN separately, so that the first consumed event will only return an
Paul Ramirez5d59a422024-10-01 15:59:16 +0000196 // InputEvent with a single action.
197 mClientTestChannel->enqueueMessage(nextPointerMessage(
198 {0ms, {Pointer{.id = 0, .x = 10.0f, .y = 20.0f}}, AMOTION_EVENT_ACTION_DOWN}));
199
Paul Ramirez5d59a422024-10-01 15:59:16 +0000200 invokeLooperCallback();
201 assertReceivedMotionEvent({InputEventEntry{0ms,
202 {Pointer{.id = 0, .x = 10.0f, .y = 20.0f}},
203 AMOTION_EVENT_ACTION_DOWN}});
204
205 // Two ACTION_MOVE events 10 ms apart that move in X direction and stay still in Y
206 mClientTestChannel->enqueueMessage(nextPointerMessage(
207 {10ms, {Pointer{.id = 0, .x = 20.0f, .y = 30.0f}}, AMOTION_EVENT_ACTION_MOVE}));
208 mClientTestChannel->enqueueMessage(nextPointerMessage(
209 {20ms, {Pointer{.id = 0, .x = 30.0f, .y = 30.0f}}, AMOTION_EVENT_ACTION_MOVE}));
210
211 invokeLooperCallback();
212 mConsumer->consumeBatchedInputEvents(nanoseconds{35ms}.count());
213 assertReceivedMotionEvent(
214 {InputEventEntry{10ms,
215 {Pointer{.id = 0, .x = 20.0f, .y = 30.0f}},
216 AMOTION_EVENT_ACTION_MOVE},
217 InputEventEntry{20ms,
218 {Pointer{.id = 0, .x = 30.0f, .y = 30.0f}},
219 AMOTION_EVENT_ACTION_MOVE},
220 InputEventEntry{25ms,
221 {Pointer{.id = 0, .x = 35.0f, .y = 30.0f, .isResampled = true}},
222 AMOTION_EVENT_ACTION_MOVE}});
223
224 mClientTestChannel->assertFinishMessage(/*seq=*/1, /*handled=*/true);
225 mClientTestChannel->assertFinishMessage(/*seq=*/2, /*handled=*/true);
226 mClientTestChannel->assertFinishMessage(/*seq=*/3, /*handled=*/true);
227}
228
229/**
230 * Same as above test, but use pointer id=1 instead of 0 to make sure that system does not
231 * have these hardcoded.
232 */
233TEST_F(InputConsumerResamplingTest, EventIsResampledWithDifferentId) {
Paul Ramirez7f1efed2024-09-29 23:55:23 +0000234 // Send the initial ACTION_DOWN separately, so that the first consumed event will only return an
Paul Ramirez5d59a422024-10-01 15:59:16 +0000235 // InputEvent with a single action.
236 mClientTestChannel->enqueueMessage(nextPointerMessage(
237 {0ms, {Pointer{.id = 1, .x = 10.0f, .y = 20.0f}}, AMOTION_EVENT_ACTION_DOWN}));
238
Paul Ramirez5d59a422024-10-01 15:59:16 +0000239 invokeLooperCallback();
240 assertReceivedMotionEvent({InputEventEntry{0ms,
241 {Pointer{.id = 1, .x = 10.0f, .y = 20.0f}},
242 AMOTION_EVENT_ACTION_DOWN}});
243
244 // Two ACTION_MOVE events 10 ms apart that move in X direction and stay still in Y
245 mClientTestChannel->enqueueMessage(nextPointerMessage(
246 {10ms, {Pointer{.id = 1, .x = 20.0f, .y = 30.0f}}, AMOTION_EVENT_ACTION_MOVE}));
247 mClientTestChannel->enqueueMessage(nextPointerMessage(
248 {20ms, {Pointer{.id = 1, .x = 30.0f, .y = 30.0f}}, AMOTION_EVENT_ACTION_MOVE}));
249
250 invokeLooperCallback();
251 mConsumer->consumeBatchedInputEvents(nanoseconds{35ms}.count());
252 assertReceivedMotionEvent(
253 {InputEventEntry{10ms,
254 {Pointer{.id = 1, .x = 20.0f, .y = 30.0f}},
255 AMOTION_EVENT_ACTION_MOVE},
256 InputEventEntry{20ms,
257 {Pointer{.id = 1, .x = 30.0f, .y = 30.0f}},
258 AMOTION_EVENT_ACTION_MOVE},
259 InputEventEntry{25ms,
260 {Pointer{.id = 1, .x = 35.0f, .y = 30.0f, .isResampled = true}},
261 AMOTION_EVENT_ACTION_MOVE}});
262
263 mClientTestChannel->assertFinishMessage(/*seq=*/1, /*handled=*/true);
264 mClientTestChannel->assertFinishMessage(/*seq=*/2, /*handled=*/true);
265 mClientTestChannel->assertFinishMessage(/*seq=*/3, /*handled=*/true);
266}
267
268/**
269 * Stylus pointer coordinates are resampled.
270 */
271TEST_F(InputConsumerResamplingTest, StylusEventIsResampled) {
Paul Ramirez7f1efed2024-09-29 23:55:23 +0000272 // Send the initial ACTION_DOWN separately, so that the first consumed event will only return an
Paul Ramirez5d59a422024-10-01 15:59:16 +0000273 // InputEvent with a single action.
274 mClientTestChannel->enqueueMessage(nextPointerMessage(
275 {0ms,
276 {Pointer{.id = 0, .x = 10.0f, .y = 20.0f, .toolType = ToolType::STYLUS}},
277 AMOTION_EVENT_ACTION_DOWN}));
278
Paul Ramirez5d59a422024-10-01 15:59:16 +0000279 invokeLooperCallback();
280 assertReceivedMotionEvent({InputEventEntry{0ms,
281 {Pointer{.id = 0,
282 .x = 10.0f,
283 .y = 20.0f,
284 .toolType = ToolType::STYLUS}},
285 AMOTION_EVENT_ACTION_DOWN}});
286
287 // Two ACTION_MOVE events 10 ms apart that move in X direction and stay still in Y
288 mClientTestChannel->enqueueMessage(nextPointerMessage(
289 {10ms,
290 {Pointer{.id = 0, .x = 20.0f, .y = 30.0f, .toolType = ToolType::STYLUS}},
291 AMOTION_EVENT_ACTION_MOVE}));
292 mClientTestChannel->enqueueMessage(nextPointerMessage(
293 {20ms,
294 {Pointer{.id = 0, .x = 30.0f, .y = 30.0f, .toolType = ToolType::STYLUS}},
295 AMOTION_EVENT_ACTION_MOVE}));
296
297 invokeLooperCallback();
298 mConsumer->consumeBatchedInputEvents(nanoseconds{35ms}.count());
299 assertReceivedMotionEvent({InputEventEntry{10ms,
300 {Pointer{.id = 0,
301 .x = 20.0f,
302 .y = 30.0f,
303 .toolType = ToolType::STYLUS}},
304 AMOTION_EVENT_ACTION_MOVE},
305 InputEventEntry{20ms,
306 {Pointer{.id = 0,
307 .x = 30.0f,
308 .y = 30.0f,
309 .toolType = ToolType::STYLUS}},
310 AMOTION_EVENT_ACTION_MOVE},
311 InputEventEntry{25ms,
312 {Pointer{.id = 0,
313 .x = 35.0f,
314 .y = 30.0f,
315 .toolType = ToolType::STYLUS,
316 .isResampled = true}},
317 AMOTION_EVENT_ACTION_MOVE}});
318
319 mClientTestChannel->assertFinishMessage(/*seq=*/1, /*handled=*/true);
320 mClientTestChannel->assertFinishMessage(/*seq=*/2, /*handled=*/true);
321 mClientTestChannel->assertFinishMessage(/*seq=*/3, /*handled=*/true);
322}
323
324/**
325 * Mouse pointer coordinates are resampled.
326 */
327TEST_F(InputConsumerResamplingTest, MouseEventIsResampled) {
Paul Ramirez7f1efed2024-09-29 23:55:23 +0000328 // Send the initial ACTION_DOWN separately, so that the first consumed event will only return an
Paul Ramirez5d59a422024-10-01 15:59:16 +0000329 // InputEvent with a single action.
Paul Ramirez5d59a422024-10-01 15:59:16 +0000330 mClientTestChannel->enqueueMessage(nextPointerMessage(
331 {0ms,
332 {Pointer{.id = 0, .x = 10.0f, .y = 20.0f, .toolType = ToolType::MOUSE}},
333 AMOTION_EVENT_ACTION_DOWN}));
334
Paul Ramirez5d59a422024-10-01 15:59:16 +0000335 invokeLooperCallback();
336 assertReceivedMotionEvent({InputEventEntry{0ms,
337 {Pointer{.id = 0,
338 .x = 10.0f,
339 .y = 20.0f,
340 .toolType = ToolType::MOUSE}},
341 AMOTION_EVENT_ACTION_DOWN}});
342
343 // Two ACTION_MOVE events 10 ms apart that move in X direction and stay still in Y
344 mClientTestChannel->enqueueMessage(nextPointerMessage(
345 {10ms,
346 {Pointer{.id = 0, .x = 20.0f, .y = 30.0f, .toolType = ToolType::MOUSE}},
347 AMOTION_EVENT_ACTION_MOVE}));
348 mClientTestChannel->enqueueMessage(nextPointerMessage(
349 {20ms,
350 {Pointer{.id = 0, .x = 30.0f, .y = 30.0f, .toolType = ToolType::MOUSE}},
351 AMOTION_EVENT_ACTION_MOVE}));
352
353 invokeLooperCallback();
354 mConsumer->consumeBatchedInputEvents(nanoseconds{35ms}.count());
355 assertReceivedMotionEvent({InputEventEntry{10ms,
356 {Pointer{.id = 0,
357 .x = 20.0f,
358 .y = 30.0f,
359 .toolType = ToolType::MOUSE}},
360 AMOTION_EVENT_ACTION_MOVE},
361 InputEventEntry{20ms,
362 {Pointer{.id = 0,
363 .x = 30.0f,
364 .y = 30.0f,
365 .toolType = ToolType::MOUSE}},
366 AMOTION_EVENT_ACTION_MOVE},
367 InputEventEntry{25ms,
368 {Pointer{.id = 0,
369 .x = 35.0f,
370 .y = 30.0f,
371 .toolType = ToolType::MOUSE,
372 .isResampled = true}},
373 AMOTION_EVENT_ACTION_MOVE}});
374
375 mClientTestChannel->assertFinishMessage(/*seq=*/1, /*handled=*/true);
376 mClientTestChannel->assertFinishMessage(/*seq=*/2, /*handled=*/true);
377 mClientTestChannel->assertFinishMessage(/*seq=*/3, /*handled=*/true);
378}
379
380/**
381 * Motion events with palm tool type are not resampled.
382 */
383TEST_F(InputConsumerResamplingTest, PalmEventIsNotResampled) {
Paul Ramirez7f1efed2024-09-29 23:55:23 +0000384 // Send the initial ACTION_DOWN separately, so that the first consumed event will only return an
Paul Ramirez5d59a422024-10-01 15:59:16 +0000385 // InputEvent with a single action.
386 mClientTestChannel->enqueueMessage(nextPointerMessage(
387 {0ms,
388 {Pointer{.id = 0, .x = 10.0f, .y = 20.0f, .toolType = ToolType::PALM}},
389 AMOTION_EVENT_ACTION_DOWN}));
390
Paul Ramirez5d59a422024-10-01 15:59:16 +0000391 invokeLooperCallback();
392 assertReceivedMotionEvent(
393 {InputEventEntry{0ms,
394 {Pointer{.id = 0, .x = 10.0f, .y = 20.0f, .toolType = ToolType::PALM}},
395 AMOTION_EVENT_ACTION_DOWN}});
396
397 // Two ACTION_MOVE events 10 ms apart that move in X direction and stay still in Y
398 mClientTestChannel->enqueueMessage(nextPointerMessage(
399 {10ms,
400 {Pointer{.id = 0, .x = 20.0f, .y = 30.0f, .toolType = ToolType::PALM}},
401 AMOTION_EVENT_ACTION_MOVE}));
402 mClientTestChannel->enqueueMessage(nextPointerMessage(
403 {20ms,
404 {Pointer{.id = 0, .x = 30.0f, .y = 30.0f, .toolType = ToolType::PALM}},
405 AMOTION_EVENT_ACTION_MOVE}));
406
407 invokeLooperCallback();
408 mConsumer->consumeBatchedInputEvents(nanoseconds{35ms}.count());
409 assertReceivedMotionEvent(
410 {InputEventEntry{10ms,
411 {Pointer{.id = 0, .x = 20.0f, .y = 30.0f, .toolType = ToolType::PALM}},
412 AMOTION_EVENT_ACTION_MOVE},
413 InputEventEntry{20ms,
414 {Pointer{.id = 0, .x = 30.0f, .y = 30.0f, .toolType = ToolType::PALM}},
415 AMOTION_EVENT_ACTION_MOVE}});
416
417 mClientTestChannel->assertFinishMessage(/*seq=*/1, /*handled=*/true);
418 mClientTestChannel->assertFinishMessage(/*seq=*/2, /*handled=*/true);
419 mClientTestChannel->assertFinishMessage(/*seq=*/3, /*handled=*/true);
420}
421
Paul Ramirez7f1efed2024-09-29 23:55:23 +0000422/**
423 * Event should not be resampled when sample time is equal to event time.
424 */
425TEST_F(InputConsumerResamplingTest, SampleTimeEqualsEventTime) {
426 // Send the initial ACTION_DOWN separately, so that the first consumed event will only return an
427 // InputEvent with a single action.
428 mClientTestChannel->enqueueMessage(nextPointerMessage(
429 {0ms, {Pointer{.id = 0, .x = 10.0f, .y = 20.0f}}, AMOTION_EVENT_ACTION_DOWN}));
430
Paul Ramirez7f1efed2024-09-29 23:55:23 +0000431 invokeLooperCallback();
432 assertReceivedMotionEvent({InputEventEntry{0ms,
433 {Pointer{.id = 0, .x = 10.0f, .y = 20.0f}},
434 AMOTION_EVENT_ACTION_DOWN}});
435
436 // Two ACTION_MOVE events 10 ms apart that move in X direction and stay still in Y
437 mClientTestChannel->enqueueMessage(nextPointerMessage(
438 {10ms, {Pointer{.id = 0, .x = 20.0f, .y = 30.0f}}, AMOTION_EVENT_ACTION_MOVE}));
439 mClientTestChannel->enqueueMessage(nextPointerMessage(
440 {20ms, {Pointer{.id = 0, .x = 30.0f, .y = 30.0f}}, AMOTION_EVENT_ACTION_MOVE}));
441
442 invokeLooperCallback();
443 mConsumer->consumeBatchedInputEvents(nanoseconds{20ms + 5ms /*RESAMPLE_LATENCY*/}.count());
444
445 // MotionEvent should not resampled because the resample time falls exactly on the existing
446 // event time.
447 assertReceivedMotionEvent({InputEventEntry{10ms,
448 {Pointer{.id = 0, .x = 20.0f, .y = 30.0f}},
449 AMOTION_EVENT_ACTION_MOVE},
450 InputEventEntry{20ms,
451 {Pointer{.id = 0, .x = 30.0f, .y = 30.0f}},
452 AMOTION_EVENT_ACTION_MOVE}});
453
454 mClientTestChannel->assertFinishMessage(/*seq=*/1, /*handled=*/true);
455 mClientTestChannel->assertFinishMessage(/*seq=*/2, /*handled=*/true);
456 mClientTestChannel->assertFinishMessage(/*seq=*/3, /*handled=*/true);
457}
458
Paul Ramirez4d3b03a2024-09-30 01:39:00 +0000459/**
460 * Once we send a resampled value to the app, we should continue to send the last predicted value if
461 * a pointer does not move. Only real values are used to determine if a pointer does not move.
462 */
463TEST_F(InputConsumerResamplingTest, ResampledValueIsUsedForIdenticalCoordinates) {
464 // Send the initial ACTION_DOWN separately, so that the first consumed event will only return an
465 // InputEvent with a single action.
466 mClientTestChannel->enqueueMessage(nextPointerMessage(
467 {0ms, {Pointer{.id = 0, .x = 10.0f, .y = 20.0f}}, AMOTION_EVENT_ACTION_DOWN}));
468
469 invokeLooperCallback();
470 assertReceivedMotionEvent({InputEventEntry{0ms,
471 {Pointer{.id = 0, .x = 10.0f, .y = 20.0f}},
472 AMOTION_EVENT_ACTION_DOWN}});
473
474 // Two ACTION_MOVE events 10 ms apart that move in X direction and stay still in Y
475 mClientTestChannel->enqueueMessage(nextPointerMessage(
476 {10ms, {Pointer{.id = 0, .x = 20.0f, .y = 30.0f}}, AMOTION_EVENT_ACTION_MOVE}));
477 mClientTestChannel->enqueueMessage(nextPointerMessage(
478 {20ms, {Pointer{.id = 0, .x = 30.0f, .y = 30.0f}}, AMOTION_EVENT_ACTION_MOVE}));
479
480 invokeLooperCallback();
481 mConsumer->consumeBatchedInputEvents(nanoseconds{35ms}.count());
482 assertReceivedMotionEvent(
483 {InputEventEntry{10ms,
484 {Pointer{.id = 0, .x = 20.0f, .y = 30.0f}},
485 AMOTION_EVENT_ACTION_MOVE},
486 InputEventEntry{20ms,
487 {Pointer{.id = 0, .x = 30.0f, .y = 30.0f}},
488 AMOTION_EVENT_ACTION_MOVE},
489 InputEventEntry{25ms,
490 {Pointer{.id = 0, .x = 35.0f, .y = 30.0f, .isResampled = true}},
491 AMOTION_EVENT_ACTION_MOVE}});
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 mClientTestChannel->enqueueMessage(nextPointerMessage(
496 {40ms, {Pointer{.id = 0, .x = 30.0f, .y = 30.0f}}, AMOTION_EVENT_ACTION_MOVE}));
497
498 invokeLooperCallback();
499 mConsumer->consumeBatchedInputEvents(nanoseconds{45ms + 5ms /*RESAMPLE_LATENCY*/}.count());
500 assertReceivedMotionEvent(
501 {InputEventEntry{40ms,
502 {Pointer{.id = 0, .x = 35.0f, .y = 30.0f, .isResampled = true}},
503 AMOTION_EVENT_ACTION_MOVE}, // original event, rewritten
504 InputEventEntry{45ms,
505 {Pointer{.id = 0, .x = 35.0f, .y = 30.0f, .isResampled = true}},
506 AMOTION_EVENT_ACTION_MOVE}}); // resampled event, rewritten
507
508 mClientTestChannel->assertFinishMessage(/*seq=*/1, /*handled=*/true);
509 mClientTestChannel->assertFinishMessage(/*seq=*/2, /*handled=*/true);
510 mClientTestChannel->assertFinishMessage(/*seq=*/3, /*handled=*/true);
511 mClientTestChannel->assertFinishMessage(/*seq=*/4, /*handled=*/true);
512}
513
Paul Ramirez4679e552024-10-01 01:17:39 +0000514TEST_F(InputConsumerResamplingTest, OldEventReceivedAfterResampleOccurs) {
515 // Send the initial ACTION_DOWN separately, so that the first consumed event will only return an
516 // InputEvent with a single action.
517 mClientTestChannel->enqueueMessage(nextPointerMessage(
518 {0ms, {Pointer{.id = 0, .x = 10.0f, .y = 20.0f}}, AMOTION_EVENT_ACTION_DOWN}));
519
520 invokeLooperCallback();
521 assertReceivedMotionEvent({InputEventEntry{0ms,
522 {Pointer{.id = 0, .x = 10.0f, .y = 20.0f}},
523 AMOTION_EVENT_ACTION_DOWN}});
524
525 // Two ACTION_MOVE events 10 ms apart that move in X direction and stay still in Y
526 mClientTestChannel->enqueueMessage(nextPointerMessage(
527 {10ms, {Pointer{.id = 0, .x = 20.0f, .y = 30.0f}}, AMOTION_EVENT_ACTION_MOVE}));
528 mClientTestChannel->enqueueMessage(nextPointerMessage(
529 {20ms, {Pointer{.id = 0, .x = 30.0f, .y = 30.0f}}, AMOTION_EVENT_ACTION_MOVE}));
530
531 invokeLooperCallback();
532 mConsumer->consumeBatchedInputEvents(nanoseconds{35ms}.count());
533 assertReceivedMotionEvent(
534 {InputEventEntry{10ms,
535 {Pointer{.id = 0, .x = 20.0f, .y = 30.0f}},
536 AMOTION_EVENT_ACTION_MOVE},
537 InputEventEntry{20ms,
538 {Pointer{.id = 0, .x = 30.0f, .y = 30.0f}},
539 AMOTION_EVENT_ACTION_MOVE},
540 InputEventEntry{25ms,
541 {Pointer{.id = 0, .x = 35.0f, .y = 30.0f, .isResampled = true}},
542 AMOTION_EVENT_ACTION_MOVE}});
543
544 // Above, the resampled event is at 25ms rather than at 30 ms = 35ms - RESAMPLE_LATENCY
545 // because we are further bound by how far we can extrapolate by the "last time delta".
546 // That's 50% of (20 ms - 10ms) => 5ms. So we can't predict more than 5 ms into the future
547 // from the event at 20ms, which is why the resampled event is at t = 25 ms.
548
549 // We resampled the event to 25 ms. Now, an older 'real' event comes in.
550 mClientTestChannel->enqueueMessage(nextPointerMessage(
551 {24ms, {Pointer{.id = 0, .x = 40.0f, .y = 30.0f}}, AMOTION_EVENT_ACTION_MOVE}));
552
553 invokeLooperCallback();
554 mConsumer->consumeBatchedInputEvents(nanoseconds{50ms}.count());
555 assertReceivedMotionEvent(
556 {InputEventEntry{24ms,
557 {Pointer{.id = 0, .x = 35.0f, .y = 30.0f, .isResampled = true}},
558 AMOTION_EVENT_ACTION_MOVE}, // original event, rewritten
559 InputEventEntry{26ms,
560 {Pointer{.id = 0, .x = 45.0f, .y = 30.0f, .isResampled = true}},
561 AMOTION_EVENT_ACTION_MOVE}}); // resampled event, rewritten
562
563 mClientTestChannel->assertFinishMessage(/*seq=*/1, /*handled=*/true);
564 mClientTestChannel->assertFinishMessage(/*seq=*/2, /*handled=*/true);
565 mClientTestChannel->assertFinishMessage(/*seq=*/3, /*handled=*/true);
566 mClientTestChannel->assertFinishMessage(/*seq=*/4, /*handled=*/true);
567}
568
Paul Ramirez5d59a422024-10-01 15:59:16 +0000569} // namespace android