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