blob: 70529bbd39526196458e36c7cd0557f9ccc91708 [file] [log] [blame]
Siarhei Vishniakou2b920272024-02-27 19:49:51 -08001/*
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 <android-base/logging.h>
18#include <attestation/HmacKeyManager.h>
19#include <ftl/enum.h>
20#include <gtest/gtest.h>
Siarhei Vishniakou2b920272024-02-27 19:49:51 -080021#include <input/BlockingQueue.h>
22#include <input/InputConsumerNoResampling.h>
23#include <input/InputTransport.h>
24
25using android::base::Result;
26
27namespace android {
28
29namespace {
30
31static constexpr float EPSILON = MotionEvent::ROUNDING_PRECISION;
32static constexpr int32_t ACTION_MOVE = AMOTION_EVENT_ACTION_MOVE;
33static constexpr int32_t POINTER_1_DOWN =
34 AMOTION_EVENT_ACTION_POINTER_DOWN | (1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT);
35static constexpr int32_t POINTER_2_DOWN =
36 AMOTION_EVENT_ACTION_POINTER_DOWN | (2 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT);
37
38static auto constexpr TIMEOUT = 5s;
39
40struct Pointer {
41 int32_t id;
42 float x;
43 float y;
44 bool isResampled = false;
45};
46
47// A collection of arguments to be sent as publishMotionEvent(). The saved members of this struct
48// allow to check the expectations against the event acquired from the InputConsumerCallbacks. To
49// help simplify expectation checking it carries members not present in MotionEvent, like
50// |rawXScale|.
51struct PublishMotionArgs {
52 const int32_t action;
53 const nsecs_t downTime;
54 const uint32_t seq;
55 const int32_t eventId;
56 const int32_t deviceId = 1;
57 const uint32_t source = AINPUT_SOURCE_TOUCHSCREEN;
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -070058 const ui::LogicalDisplayId displayId = ui::LogicalDisplayId::DEFAULT;
Siarhei Vishniakou2b920272024-02-27 19:49:51 -080059 const int32_t actionButton = 0;
60 const int32_t edgeFlags = AMOTION_EVENT_EDGE_FLAG_TOP;
61 const int32_t metaState = AMETA_ALT_LEFT_ON | AMETA_ALT_ON;
62 const int32_t buttonState = AMOTION_EVENT_BUTTON_PRIMARY;
63 const MotionClassification classification = MotionClassification::AMBIGUOUS_GESTURE;
64 const float xScale = 2;
65 const float yScale = 3;
66 const float xOffset = -10;
67 const float yOffset = -20;
68 const float rawXScale = 4;
69 const float rawYScale = -5;
70 const float rawXOffset = -11;
71 const float rawYOffset = 42;
72 const float xPrecision = 0.25;
73 const float yPrecision = 0.5;
74 const float xCursorPosition = 1.3;
75 const float yCursorPosition = 50.6;
76 std::array<uint8_t, 32> hmac;
77 int32_t flags;
78 ui::Transform transform;
79 ui::Transform rawTransform;
80 const nsecs_t eventTime;
81 size_t pointerCount;
82 std::vector<PointerProperties> pointerProperties;
83 std::vector<PointerCoords> pointerCoords;
84
85 PublishMotionArgs(int32_t action, nsecs_t downTime, const std::vector<Pointer>& pointers,
86 const uint32_t seq);
87};
88
89PublishMotionArgs::PublishMotionArgs(int32_t inAction, nsecs_t inDownTime,
90 const std::vector<Pointer>& pointers, const uint32_t inSeq)
91 : action(inAction),
92 downTime(inDownTime),
93 seq(inSeq),
94 eventId(InputEvent::nextId()),
95 eventTime(systemTime(SYSTEM_TIME_MONOTONIC)) {
96 hmac = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
97 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31};
98
99 flags = AMOTION_EVENT_FLAG_WINDOW_IS_OBSCURED;
100 if (action == AMOTION_EVENT_ACTION_CANCEL) {
101 flags |= AMOTION_EVENT_FLAG_CANCELED;
102 }
103 pointerCount = pointers.size();
104 for (size_t i = 0; i < pointerCount; i++) {
105 pointerProperties.push_back({});
106 pointerProperties[i].clear();
107 pointerProperties[i].id = pointers[i].id;
108 pointerProperties[i].toolType = ToolType::FINGER;
109
110 pointerCoords.push_back({});
111 pointerCoords[i].clear();
112 pointerCoords[i].isResampled = pointers[i].isResampled;
113 pointerCoords[i].setAxisValue(AMOTION_EVENT_AXIS_X, pointers[i].x);
114 pointerCoords[i].setAxisValue(AMOTION_EVENT_AXIS_Y, pointers[i].y);
115 pointerCoords[i].setAxisValue(AMOTION_EVENT_AXIS_PRESSURE, 0.5 * i);
116 pointerCoords[i].setAxisValue(AMOTION_EVENT_AXIS_SIZE, 0.7 * i);
117 pointerCoords[i].setAxisValue(AMOTION_EVENT_AXIS_TOUCH_MAJOR, 1.5 * i);
118 pointerCoords[i].setAxisValue(AMOTION_EVENT_AXIS_TOUCH_MINOR, 1.7 * i);
119 pointerCoords[i].setAxisValue(AMOTION_EVENT_AXIS_TOOL_MAJOR, 2.5 * i);
120 pointerCoords[i].setAxisValue(AMOTION_EVENT_AXIS_TOOL_MAJOR, 2.7 * i);
121 pointerCoords[i].setAxisValue(AMOTION_EVENT_AXIS_ORIENTATION, 3.5 * i);
122 }
123 transform.set({xScale, 0, xOffset, 0, yScale, yOffset, 0, 0, 1});
124 rawTransform.set({rawXScale, 0, rawXOffset, 0, rawYScale, rawYOffset, 0, 0, 1});
125}
126
127// Checks expectations against |motionEvent| acquired from an InputConsumer. Floating point
128// comparisons limit precision to EPSILON.
129void verifyArgsEqualToEvent(const PublishMotionArgs& args, const MotionEvent& motionEvent) {
130 EXPECT_EQ(args.eventId, motionEvent.getId());
131 EXPECT_EQ(args.deviceId, motionEvent.getDeviceId());
132 EXPECT_EQ(args.source, motionEvent.getSource());
133 EXPECT_EQ(args.displayId, motionEvent.getDisplayId());
134 EXPECT_EQ(args.hmac, motionEvent.getHmac());
135 EXPECT_EQ(args.action, motionEvent.getAction());
136 EXPECT_EQ(args.downTime, motionEvent.getDownTime());
137 EXPECT_EQ(args.flags, motionEvent.getFlags());
138 EXPECT_EQ(args.edgeFlags, motionEvent.getEdgeFlags());
139 EXPECT_EQ(args.metaState, motionEvent.getMetaState());
140 EXPECT_EQ(args.buttonState, motionEvent.getButtonState());
141 EXPECT_EQ(args.classification, motionEvent.getClassification());
142 EXPECT_EQ(args.transform, motionEvent.getTransform());
143 EXPECT_NEAR((-args.rawXOffset / args.rawXScale) * args.xScale + args.xOffset,
144 motionEvent.getRawXOffset(), EPSILON);
145 EXPECT_NEAR((-args.rawYOffset / args.rawYScale) * args.yScale + args.yOffset,
146 motionEvent.getRawYOffset(), EPSILON);
147 EXPECT_EQ(args.xPrecision, motionEvent.getXPrecision());
148 EXPECT_EQ(args.yPrecision, motionEvent.getYPrecision());
149 EXPECT_NEAR(args.xCursorPosition, motionEvent.getRawXCursorPosition(), EPSILON);
150 EXPECT_NEAR(args.yCursorPosition, motionEvent.getRawYCursorPosition(), EPSILON);
151 EXPECT_NEAR(args.xCursorPosition * args.xScale + args.xOffset, motionEvent.getXCursorPosition(),
152 EPSILON);
153 EXPECT_NEAR(args.yCursorPosition * args.yScale + args.yOffset, motionEvent.getYCursorPosition(),
154 EPSILON);
155 EXPECT_EQ(args.rawTransform, motionEvent.getRawTransform());
156 EXPECT_EQ(args.eventTime, motionEvent.getEventTime());
157 EXPECT_EQ(args.pointerCount, motionEvent.getPointerCount());
158 EXPECT_EQ(0U, motionEvent.getHistorySize());
159
160 for (size_t i = 0; i < args.pointerCount; i++) {
161 SCOPED_TRACE(i);
162 EXPECT_EQ(args.pointerProperties[i].id, motionEvent.getPointerId(i));
163 EXPECT_EQ(args.pointerProperties[i].toolType, motionEvent.getToolType(i));
164
165 const auto& pc = args.pointerCoords[i];
166 EXPECT_EQ(pc, motionEvent.getSamplePointerCoords()[i]);
167
168 EXPECT_NEAR(pc.getX() * args.rawXScale + args.rawXOffset, motionEvent.getRawX(i), EPSILON);
169 EXPECT_NEAR(pc.getY() * args.rawYScale + args.rawYOffset, motionEvent.getRawY(i), EPSILON);
170 EXPECT_NEAR(pc.getX() * args.xScale + args.xOffset, motionEvent.getX(i), EPSILON);
171 EXPECT_NEAR(pc.getY() * args.yScale + args.yOffset, motionEvent.getY(i), EPSILON);
172 EXPECT_EQ(pc.getAxisValue(AMOTION_EVENT_AXIS_PRESSURE), motionEvent.getPressure(i));
173 EXPECT_EQ(pc.getAxisValue(AMOTION_EVENT_AXIS_SIZE), motionEvent.getSize(i));
174 EXPECT_EQ(pc.getAxisValue(AMOTION_EVENT_AXIS_TOUCH_MAJOR), motionEvent.getTouchMajor(i));
175 EXPECT_EQ(pc.getAxisValue(AMOTION_EVENT_AXIS_TOUCH_MINOR), motionEvent.getTouchMinor(i));
176 EXPECT_EQ(pc.getAxisValue(AMOTION_EVENT_AXIS_TOOL_MAJOR), motionEvent.getToolMajor(i));
177 EXPECT_EQ(pc.getAxisValue(AMOTION_EVENT_AXIS_TOOL_MINOR), motionEvent.getToolMinor(i));
178
179 // Calculate the orientation after scaling, keeping in mind that an orientation of 0 is
180 // "up", and the positive y direction is "down".
181 const float unscaledOrientation = pc.getAxisValue(AMOTION_EVENT_AXIS_ORIENTATION);
182 const float x = sinf(unscaledOrientation) * args.xScale;
183 const float y = -cosf(unscaledOrientation) * args.yScale;
184 EXPECT_EQ(atan2f(x, -y), motionEvent.getOrientation(i));
185 }
186}
187
188void publishMotionEvent(InputPublisher& publisher, const PublishMotionArgs& a) {
189 status_t status =
190 publisher.publishMotionEvent(a.seq, a.eventId, a.deviceId, a.source, a.displayId,
191 a.hmac, a.action, a.actionButton, a.flags, a.edgeFlags,
192 a.metaState, a.buttonState, a.classification, a.transform,
193 a.xPrecision, a.yPrecision, a.xCursorPosition,
194 a.yCursorPosition, a.rawTransform, a.downTime, a.eventTime,
195 a.pointerCount, a.pointerProperties.data(),
196 a.pointerCoords.data());
197 ASSERT_EQ(OK, status) << "publisher publishMotionEvent should return OK";
198}
199
200Result<InputPublisher::ConsumerResponse> receiveConsumerResponse(
201 InputPublisher& publisher, std::chrono::milliseconds timeout) {
202 const std::chrono::time_point start = std::chrono::steady_clock::now();
203
204 while (true) {
205 Result<InputPublisher::ConsumerResponse> result = publisher.receiveConsumerResponse();
206 if (result.ok()) {
207 return result;
208 }
209 const std::chrono::duration waited = std::chrono::steady_clock::now() - start;
210 if (waited > timeout) {
211 return result;
212 }
213 }
214}
215
216void verifyFinishedSignal(InputPublisher& publisher, uint32_t seq, nsecs_t publishTime) {
217 Result<InputPublisher::ConsumerResponse> result = receiveConsumerResponse(publisher, TIMEOUT);
218 ASSERT_TRUE(result.ok()) << "receiveConsumerResponse returned " << result.error().message();
219 ASSERT_TRUE(std::holds_alternative<InputPublisher::Finished>(*result));
220 const InputPublisher::Finished& finish = std::get<InputPublisher::Finished>(*result);
221 ASSERT_EQ(seq, finish.seq)
222 << "receiveConsumerResponse should have returned the original sequence number";
223 ASSERT_TRUE(finish.handled)
224 << "receiveConsumerResponse should have set handled to consumer's reply";
225 ASSERT_GE(finish.consumeTime, publishTime)
226 << "finished signal's consume time should be greater than publish time";
227}
228
229} // namespace
230
231class InputConsumerMessageHandler : public MessageHandler {
232public:
233 InputConsumerMessageHandler(std::function<void(const Message&)> function)
234 : mFunction(function) {}
235
236private:
237 void handleMessage(const Message& message) override { mFunction(message); }
238
239 std::function<void(const Message&)> mFunction;
240};
241
242class InputPublisherAndConsumerNoResamplingTest : public testing::Test,
243 public InputConsumerCallbacks {
244protected:
245 std::unique_ptr<InputChannel> mClientChannel;
246 std::unique_ptr<InputPublisher> mPublisher;
247 std::unique_ptr<InputConsumerNoResampling> mConsumer;
248
249 std::thread mLooperThread;
250 sp<Looper> mLooper = sp<Looper>::make(/*allowNonCallbacks=*/false);
251
252 // LOOPER CONTROL
253 // Set to false when you want the looper to exit
254 std::atomic<bool> mExitLooper = false;
255 std::mutex mLock;
256
257 // Used by test to notify looper that the value of "mLooperMayProceed" has changed
258 std::condition_variable mNotifyLooperMayProceed;
259 bool mLooperMayProceed GUARDED_BY(mLock){true};
260 // Used by looper to notify the test that it's about to block on "mLooperMayProceed" -> true
261 std::condition_variable mNotifyLooperWaiting;
262 bool mLooperIsBlocked GUARDED_BY(mLock){false};
263
264 std::condition_variable mNotifyConsumerDestroyed;
265 bool mConsumerDestroyed GUARDED_BY(mLock){false};
266
267 void runLooper() {
268 static constexpr int LOOP_INDEFINITELY = -1;
269 Looper::setForThread(mLooper);
270 // Loop forever -- this thread is dedicated to servicing the looper callbacks.
271 while (!mExitLooper) {
272 mLooper->pollOnce(/*timeoutMillis=*/LOOP_INDEFINITELY);
273 }
274 }
275
276 void SetUp() override {
277 std::unique_ptr<InputChannel> serverChannel;
278 status_t result =
279 InputChannel::openInputChannelPair("channel name", serverChannel, mClientChannel);
280 ASSERT_EQ(OK, result);
281
282 mPublisher = std::make_unique<InputPublisher>(std::move(serverChannel));
283 mMessageHandler = sp<InputConsumerMessageHandler>::make(
284 [this](const Message& message) { handleMessage(message); });
285 mLooperThread = std::thread([this] { runLooper(); });
286 sendMessage(LooperMessage::CREATE_CONSUMER);
287 }
288
289 void publishAndConsumeKeyEvent();
290 void publishAndConsumeMotionStream();
291 void publishAndConsumeMotionDown(nsecs_t downTime);
292 void publishAndConsumeBatchedMotionMove(nsecs_t downTime);
293 void publishAndConsumeFocusEvent();
294 void publishAndConsumeCaptureEvent();
295 void publishAndConsumeDragEvent();
296 void publishAndConsumeTouchModeEvent();
297 void publishAndConsumeMotionEvent(int32_t action, nsecs_t downTime,
298 const std::vector<Pointer>& pointers);
299 void TearDown() override {
300 // Destroy the consumer, flushing any of the pending ack's.
301 sendMessage(LooperMessage::DESTROY_CONSUMER);
302 {
303 std::unique_lock lock(mLock);
304 base::ScopedLockAssertion assumeLocked(mLock);
305 mNotifyConsumerDestroyed.wait(lock, [this] { return mConsumerDestroyed; });
306 }
307 // Stop the looper thread so that we can destroy the object.
308 mExitLooper = true;
309 mLooper->wake();
310 mLooperThread.join();
311 }
312
313protected:
314 // Interaction with the looper thread
315 enum class LooperMessage : int {
316 CALL_PROBABLY_HAS_INPUT,
317 CREATE_CONSUMER,
318 DESTROY_CONSUMER,
319 CALL_REPORT_TIMELINE,
320 BLOCK_LOOPER,
321 };
322 void sendMessage(LooperMessage message);
323 struct ReportTimelineArgs {
324 int32_t inputEventId;
325 nsecs_t gpuCompletedTime;
326 nsecs_t presentTime;
327 };
328 // The input to the function "InputConsumer::reportTimeline". Populated on the test thread and
329 // accessed on the looper thread.
330 BlockingQueue<ReportTimelineArgs> mReportTimelineArgs;
331 // The output of calling "InputConsumer::probablyHasInput()". Populated on the looper thread and
332 // accessed on the test thread.
333 BlockingQueue<bool> mProbablyHasInputResponses;
334
335private:
336 sp<MessageHandler> mMessageHandler;
337 void handleMessage(const Message& message);
338
339 static auto constexpr NO_EVENT_TIMEOUT = 10ms;
340 // The sequence number to use when publishing the next event
341 uint32_t mSeq = 1;
342
Siarhei Vishniakou3891ec92024-03-15 13:29:57 -0700343 BlockingQueue<std::unique_ptr<KeyEvent>> mKeyEvents;
344 BlockingQueue<std::unique_ptr<MotionEvent>> mMotionEvents;
345 BlockingQueue<std::unique_ptr<FocusEvent>> mFocusEvents;
346 BlockingQueue<std::unique_ptr<CaptureEvent>> mCaptureEvents;
347 BlockingQueue<std::unique_ptr<DragEvent>> mDragEvents;
348 BlockingQueue<std::unique_ptr<TouchModeEvent>> mTouchModeEvents;
Siarhei Vishniakou2b920272024-02-27 19:49:51 -0800349
350 // InputConsumerCallbacks interface
Siarhei Vishniakou3891ec92024-03-15 13:29:57 -0700351 void onKeyEvent(std::unique_ptr<KeyEvent> event, uint32_t seq) override {
Siarhei Vishniakou2b920272024-02-27 19:49:51 -0800352 mKeyEvents.push(std::move(event));
353 mConsumer->finishInputEvent(seq, true);
354 }
Siarhei Vishniakou3891ec92024-03-15 13:29:57 -0700355 void onMotionEvent(std::unique_ptr<MotionEvent> event, uint32_t seq) override {
Siarhei Vishniakou2b920272024-02-27 19:49:51 -0800356 mMotionEvents.push(std::move(event));
357 mConsumer->finishInputEvent(seq, true);
358 }
359 void onBatchedInputEventPending(int32_t pendingBatchSource) override {
360 if (!mConsumer->probablyHasInput()) {
361 ADD_FAILURE() << "should deterministically have input because there is a batch";
362 }
363 mConsumer->consumeBatchedInputEvents(std::nullopt);
364 };
Siarhei Vishniakou3891ec92024-03-15 13:29:57 -0700365 void onFocusEvent(std::unique_ptr<FocusEvent> event, uint32_t seq) override {
Siarhei Vishniakou2b920272024-02-27 19:49:51 -0800366 mFocusEvents.push(std::move(event));
367 mConsumer->finishInputEvent(seq, true);
368 };
Siarhei Vishniakou3891ec92024-03-15 13:29:57 -0700369 void onCaptureEvent(std::unique_ptr<CaptureEvent> event, uint32_t seq) override {
Siarhei Vishniakou2b920272024-02-27 19:49:51 -0800370 mCaptureEvents.push(std::move(event));
371 mConsumer->finishInputEvent(seq, true);
372 };
Siarhei Vishniakou3891ec92024-03-15 13:29:57 -0700373 void onDragEvent(std::unique_ptr<DragEvent> event, uint32_t seq) override {
Siarhei Vishniakou2b920272024-02-27 19:49:51 -0800374 mDragEvents.push(std::move(event));
375 mConsumer->finishInputEvent(seq, true);
376 }
Siarhei Vishniakou3891ec92024-03-15 13:29:57 -0700377 void onTouchModeEvent(std::unique_ptr<TouchModeEvent> event, uint32_t seq) override {
Siarhei Vishniakou2b920272024-02-27 19:49:51 -0800378 mTouchModeEvents.push(std::move(event));
379 mConsumer->finishInputEvent(seq, true);
380 };
381};
382
383void InputPublisherAndConsumerNoResamplingTest::sendMessage(LooperMessage message) {
384 Message msg{ftl::to_underlying(message)};
385 mLooper->sendMessage(mMessageHandler, msg);
386}
387
388void InputPublisherAndConsumerNoResamplingTest::handleMessage(const Message& message) {
389 switch (static_cast<LooperMessage>(message.what)) {
390 case LooperMessage::CALL_PROBABLY_HAS_INPUT: {
391 mProbablyHasInputResponses.push(mConsumer->probablyHasInput());
392 break;
393 }
394 case LooperMessage::CREATE_CONSUMER: {
395 mConsumer = std::make_unique<InputConsumerNoResampling>(std::move(mClientChannel),
396 mLooper, *this);
397 break;
398 }
399 case LooperMessage::DESTROY_CONSUMER: {
400 mConsumer = nullptr;
401 {
402 std::unique_lock lock(mLock);
403 mConsumerDestroyed = true;
404 }
405 mNotifyConsumerDestroyed.notify_all();
406 break;
407 }
408 case LooperMessage::CALL_REPORT_TIMELINE: {
409 std::optional<ReportTimelineArgs> args = mReportTimelineArgs.pop();
410 if (!args.has_value()) {
411 ADD_FAILURE() << "Couldn't get the 'reportTimeline' args in time";
412 return;
413 }
414 mConsumer->reportTimeline(args->inputEventId, args->gpuCompletedTime,
415 args->presentTime);
416 break;
417 }
418 case LooperMessage::BLOCK_LOOPER: {
419 {
420 std::unique_lock lock(mLock);
421 mLooperIsBlocked = true;
422 }
423 mNotifyLooperWaiting.notify_all();
424
425 {
426 std::unique_lock lock(mLock);
427 base::ScopedLockAssertion assumeLocked(mLock);
428 mNotifyLooperMayProceed.wait(lock, [this] { return mLooperMayProceed; });
429 }
430
431 {
432 std::unique_lock lock(mLock);
433 mLooperIsBlocked = false;
434 }
435 mNotifyLooperWaiting.notify_all();
436 break;
437 }
438 }
439}
440
441void InputPublisherAndConsumerNoResamplingTest::publishAndConsumeKeyEvent() {
442 status_t status;
443
444 const uint32_t seq = mSeq++;
445 int32_t eventId = InputEvent::nextId();
446 constexpr int32_t deviceId = 1;
447 constexpr uint32_t source = AINPUT_SOURCE_KEYBOARD;
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -0700448 constexpr ui::LogicalDisplayId displayId = ui::LogicalDisplayId::DEFAULT;
Siarhei Vishniakou2b920272024-02-27 19:49:51 -0800449 constexpr std::array<uint8_t, 32> hmac = {31, 30, 29, 28, 27, 26, 25, 24, 23, 22, 21,
450 20, 19, 18, 17, 16, 15, 14, 13, 12, 11, 10,
451 9, 8, 7, 6, 5, 4, 3, 2, 1, 0};
452 constexpr int32_t action = AKEY_EVENT_ACTION_DOWN;
453 constexpr int32_t flags = AKEY_EVENT_FLAG_FROM_SYSTEM;
454 constexpr int32_t keyCode = AKEYCODE_ENTER;
455 constexpr int32_t scanCode = 13;
456 constexpr int32_t metaState = AMETA_ALT_LEFT_ON | AMETA_ALT_ON;
457 constexpr int32_t repeatCount = 1;
458 constexpr nsecs_t downTime = 3;
459 constexpr nsecs_t eventTime = 4;
460 const nsecs_t publishTime = systemTime(SYSTEM_TIME_MONOTONIC);
461
462 status = mPublisher->publishKeyEvent(seq, eventId, deviceId, source, displayId, hmac, action,
463 flags, keyCode, scanCode, metaState, repeatCount, downTime,
464 eventTime);
465 ASSERT_EQ(OK, status) << "publisher publishKeyEvent should return OK";
466
Siarhei Vishniakou3891ec92024-03-15 13:29:57 -0700467 std::optional<std::unique_ptr<KeyEvent>> optKeyEvent = mKeyEvents.popWithTimeout(TIMEOUT);
468 ASSERT_TRUE(optKeyEvent.has_value()) << "consumer should have returned non-NULL event";
469 std::unique_ptr<KeyEvent> keyEvent = std::move(*optKeyEvent);
Siarhei Vishniakou2b920272024-02-27 19:49:51 -0800470
471 sendMessage(LooperMessage::CALL_PROBABLY_HAS_INPUT);
472 std::optional<bool> probablyHasInput = mProbablyHasInputResponses.popWithTimeout(TIMEOUT);
473 ASSERT_TRUE(probablyHasInput.has_value());
474 ASSERT_FALSE(probablyHasInput.value()) << "no events should be waiting after being consumed";
475
Siarhei Vishniakou2b920272024-02-27 19:49:51 -0800476 EXPECT_EQ(eventId, keyEvent->getId());
477 EXPECT_EQ(deviceId, keyEvent->getDeviceId());
478 EXPECT_EQ(source, keyEvent->getSource());
479 EXPECT_EQ(displayId, keyEvent->getDisplayId());
480 EXPECT_EQ(hmac, keyEvent->getHmac());
481 EXPECT_EQ(action, keyEvent->getAction());
482 EXPECT_EQ(flags, keyEvent->getFlags());
483 EXPECT_EQ(keyCode, keyEvent->getKeyCode());
484 EXPECT_EQ(scanCode, keyEvent->getScanCode());
485 EXPECT_EQ(metaState, keyEvent->getMetaState());
486 EXPECT_EQ(repeatCount, keyEvent->getRepeatCount());
487 EXPECT_EQ(downTime, keyEvent->getDownTime());
488 EXPECT_EQ(eventTime, keyEvent->getEventTime());
489
490 verifyFinishedSignal(*mPublisher, seq, publishTime);
491}
492
493void InputPublisherAndConsumerNoResamplingTest::publishAndConsumeMotionStream() {
494 const nsecs_t downTime = systemTime(SYSTEM_TIME_MONOTONIC);
495
496 publishAndConsumeMotionEvent(AMOTION_EVENT_ACTION_DOWN, downTime,
497 {Pointer{.id = 0, .x = 20, .y = 30}});
498
499 publishAndConsumeMotionEvent(POINTER_1_DOWN, downTime,
500 {Pointer{.id = 0, .x = 20, .y = 30},
501 Pointer{.id = 1, .x = 200, .y = 300}});
502
503 publishAndConsumeMotionEvent(POINTER_2_DOWN, downTime,
504 {Pointer{.id = 0, .x = 20, .y = 30},
505 Pointer{.id = 1, .x = 200, .y = 300},
506 Pointer{.id = 2, .x = 300, .y = 400}});
507
508 // Provide a consistent input stream - cancel the gesture that was started above
509 publishAndConsumeMotionEvent(AMOTION_EVENT_ACTION_CANCEL, downTime,
510 {Pointer{.id = 0, .x = 20, .y = 30},
511 Pointer{.id = 1, .x = 200, .y = 300},
512 Pointer{.id = 2, .x = 300, .y = 400}});
513}
514
515void InputPublisherAndConsumerNoResamplingTest::publishAndConsumeMotionDown(nsecs_t downTime) {
516 publishAndConsumeMotionEvent(AMOTION_EVENT_ACTION_DOWN, downTime,
517 {Pointer{.id = 0, .x = 20, .y = 30}});
518}
519
520void InputPublisherAndConsumerNoResamplingTest::publishAndConsumeBatchedMotionMove(
521 nsecs_t downTime) {
522 uint32_t seq = mSeq++;
523 const std::vector<Pointer> pointers = {Pointer{.id = 0, .x = 20, .y = 30}};
524 PublishMotionArgs args(AMOTION_EVENT_ACTION_MOVE, downTime, pointers, seq);
525 const nsecs_t publishTime = systemTime(SYSTEM_TIME_MONOTONIC);
526
527 // Block the looper thread, preventing it from being able to service any of the fd callbacks.
528
529 {
530 std::scoped_lock lock(mLock);
531 mLooperMayProceed = false;
532 }
533 sendMessage(LooperMessage::BLOCK_LOOPER);
534 {
535 std::unique_lock lock(mLock);
536 mNotifyLooperWaiting.wait(lock, [this] { return mLooperIsBlocked; });
537 }
538
539 publishMotionEvent(*mPublisher, args);
540
541 // Ensure no event arrives because the UI thread is blocked
Siarhei Vishniakou3891ec92024-03-15 13:29:57 -0700542 std::optional<std::unique_ptr<MotionEvent>> noEvent =
543 mMotionEvents.popWithTimeout(NO_EVENT_TIMEOUT);
Siarhei Vishniakou2b920272024-02-27 19:49:51 -0800544 ASSERT_FALSE(noEvent.has_value()) << "Got unexpected event: " << *noEvent;
545
546 Result<InputPublisher::ConsumerResponse> result = mPublisher->receiveConsumerResponse();
547 ASSERT_FALSE(result.ok());
548 ASSERT_EQ(WOULD_BLOCK, result.error().code());
549
550 // We shouldn't be calling mConsumer on the UI thread, but in this situation, the looper
551 // thread is locked, so this should be safe to do.
552 ASSERT_TRUE(mConsumer->probablyHasInput())
553 << "should deterministically have input because there is a batch";
554
555 // Now, unblock the looper thread, so that the event can arrive.
556 {
557 std::scoped_lock lock(mLock);
558 mLooperMayProceed = true;
559 }
560 mNotifyLooperMayProceed.notify_all();
561
Siarhei Vishniakou3891ec92024-03-15 13:29:57 -0700562 std::optional<std::unique_ptr<MotionEvent>> optMotion = mMotionEvents.popWithTimeout(TIMEOUT);
563 ASSERT_TRUE(optMotion.has_value());
564 std::unique_ptr<MotionEvent> motion = std::move(*optMotion);
Siarhei Vishniakou2b920272024-02-27 19:49:51 -0800565 ASSERT_EQ(ACTION_MOVE, motion->getAction());
566
567 verifyFinishedSignal(*mPublisher, seq, publishTime);
568}
569
570void InputPublisherAndConsumerNoResamplingTest::publishAndConsumeMotionEvent(
571 int32_t action, nsecs_t downTime, const std::vector<Pointer>& pointers) {
572 uint32_t seq = mSeq++;
573 PublishMotionArgs args(action, downTime, pointers, seq);
574 nsecs_t publishTime = systemTime(SYSTEM_TIME_MONOTONIC);
575 publishMotionEvent(*mPublisher, args);
576
Siarhei Vishniakou3891ec92024-03-15 13:29:57 -0700577 std::optional<std::unique_ptr<MotionEvent>> optMotion = mMotionEvents.popWithTimeout(TIMEOUT);
578 ASSERT_TRUE(optMotion.has_value());
579 std::unique_ptr<MotionEvent> event = std::move(*optMotion);
Siarhei Vishniakou2b920272024-02-27 19:49:51 -0800580
581 verifyArgsEqualToEvent(args, *event);
582
583 verifyFinishedSignal(*mPublisher, seq, publishTime);
584}
585
586void InputPublisherAndConsumerNoResamplingTest::publishAndConsumeFocusEvent() {
587 status_t status;
588
589 constexpr uint32_t seq = 15;
590 int32_t eventId = InputEvent::nextId();
591 constexpr bool hasFocus = true;
592 const nsecs_t publishTime = systemTime(SYSTEM_TIME_MONOTONIC);
593
594 status = mPublisher->publishFocusEvent(seq, eventId, hasFocus);
595 ASSERT_EQ(OK, status) << "publisher publishFocusEvent should return OK";
596
Siarhei Vishniakou3891ec92024-03-15 13:29:57 -0700597 std::optional<std::unique_ptr<FocusEvent>> optFocusEvent = mFocusEvents.popWithTimeout(TIMEOUT);
598 ASSERT_TRUE(optFocusEvent.has_value()) << "consumer should have returned non-NULL event";
599 std::unique_ptr<FocusEvent> focusEvent = std::move(*optFocusEvent);
Siarhei Vishniakou2b920272024-02-27 19:49:51 -0800600 EXPECT_EQ(eventId, focusEvent->getId());
601 EXPECT_EQ(hasFocus, focusEvent->getHasFocus());
602
603 verifyFinishedSignal(*mPublisher, seq, publishTime);
604}
605
606void InputPublisherAndConsumerNoResamplingTest::publishAndConsumeCaptureEvent() {
607 status_t status;
608
609 constexpr uint32_t seq = 42;
610 int32_t eventId = InputEvent::nextId();
611 constexpr bool captureEnabled = true;
612 const nsecs_t publishTime = systemTime(SYSTEM_TIME_MONOTONIC);
613
614 status = mPublisher->publishCaptureEvent(seq, eventId, captureEnabled);
615 ASSERT_EQ(OK, status) << "publisher publishCaptureEvent should return OK";
616
Siarhei Vishniakou3891ec92024-03-15 13:29:57 -0700617 std::optional<std::unique_ptr<CaptureEvent>> optEvent = mCaptureEvents.popWithTimeout(TIMEOUT);
618 ASSERT_TRUE(optEvent.has_value()) << "consumer should have returned non-NULL event";
619 std::unique_ptr<CaptureEvent> event = std::move(*optEvent);
Siarhei Vishniakou2b920272024-02-27 19:49:51 -0800620
621 const CaptureEvent& captureEvent = *event;
622 EXPECT_EQ(eventId, captureEvent.getId());
623 EXPECT_EQ(captureEnabled, captureEvent.getPointerCaptureEnabled());
624
625 verifyFinishedSignal(*mPublisher, seq, publishTime);
626}
627
628void InputPublisherAndConsumerNoResamplingTest::publishAndConsumeDragEvent() {
629 status_t status;
630
631 constexpr uint32_t seq = 15;
632 int32_t eventId = InputEvent::nextId();
633 constexpr bool isExiting = false;
634 constexpr float x = 10;
635 constexpr float y = 15;
636 const nsecs_t publishTime = systemTime(SYSTEM_TIME_MONOTONIC);
637
638 status = mPublisher->publishDragEvent(seq, eventId, x, y, isExiting);
639 ASSERT_EQ(OK, status) << "publisher publishDragEvent should return OK";
640
Siarhei Vishniakou3891ec92024-03-15 13:29:57 -0700641 std::optional<std::unique_ptr<DragEvent>> optEvent = mDragEvents.popWithTimeout(TIMEOUT);
642 ASSERT_TRUE(optEvent.has_value()) << "consumer should have returned non-NULL event";
643 std::unique_ptr<DragEvent> event = std::move(*optEvent);
Siarhei Vishniakou2b920272024-02-27 19:49:51 -0800644
645 const DragEvent& dragEvent = *event;
646 EXPECT_EQ(eventId, dragEvent.getId());
647 EXPECT_EQ(isExiting, dragEvent.isExiting());
648 EXPECT_EQ(x, dragEvent.getX());
649 EXPECT_EQ(y, dragEvent.getY());
650
651 verifyFinishedSignal(*mPublisher, seq, publishTime);
652}
653
654void InputPublisherAndConsumerNoResamplingTest::publishAndConsumeTouchModeEvent() {
655 status_t status;
656
657 constexpr uint32_t seq = 15;
658 int32_t eventId = InputEvent::nextId();
659 constexpr bool touchModeEnabled = true;
660 const nsecs_t publishTime = systemTime(SYSTEM_TIME_MONOTONIC);
661
662 status = mPublisher->publishTouchModeEvent(seq, eventId, touchModeEnabled);
663 ASSERT_EQ(OK, status) << "publisher publishTouchModeEvent should return OK";
664
Siarhei Vishniakou3891ec92024-03-15 13:29:57 -0700665 std::optional<std::unique_ptr<TouchModeEvent>> optEvent =
666 mTouchModeEvents.popWithTimeout(TIMEOUT);
667 ASSERT_TRUE(optEvent.has_value());
668 std::unique_ptr<TouchModeEvent> event = std::move(*optEvent);
Siarhei Vishniakou2b920272024-02-27 19:49:51 -0800669
670 const TouchModeEvent& touchModeEvent = *event;
671 EXPECT_EQ(eventId, touchModeEvent.getId());
672 EXPECT_EQ(touchModeEnabled, touchModeEvent.isInTouchMode());
673
674 verifyFinishedSignal(*mPublisher, seq, publishTime);
675}
676
677TEST_F(InputPublisherAndConsumerNoResamplingTest, SendTimeline) {
678 const int32_t inputEventId = 20;
679 const nsecs_t gpuCompletedTime = 30;
680 const nsecs_t presentTime = 40;
681
682 mReportTimelineArgs.emplace(inputEventId, gpuCompletedTime, presentTime);
683 sendMessage(LooperMessage::CALL_REPORT_TIMELINE);
684
685 Result<InputPublisher::ConsumerResponse> result = receiveConsumerResponse(*mPublisher, TIMEOUT);
686 ASSERT_TRUE(result.ok()) << "receiveConsumerResponse should return OK";
687 ASSERT_TRUE(std::holds_alternative<InputPublisher::Timeline>(*result));
688 const InputPublisher::Timeline& timeline = std::get<InputPublisher::Timeline>(*result);
689 ASSERT_EQ(inputEventId, timeline.inputEventId);
690 ASSERT_EQ(gpuCompletedTime, timeline.graphicsTimeline[GraphicsTimeline::GPU_COMPLETED_TIME]);
691 ASSERT_EQ(presentTime, timeline.graphicsTimeline[GraphicsTimeline::PRESENT_TIME]);
692}
693
694TEST_F(InputPublisherAndConsumerNoResamplingTest, PublishKeyEvent_EndToEnd) {
695 ASSERT_NO_FATAL_FAILURE(publishAndConsumeKeyEvent());
696}
697
698TEST_F(InputPublisherAndConsumerNoResamplingTest, PublishMotionEvent_EndToEnd) {
699 ASSERT_NO_FATAL_FAILURE(publishAndConsumeMotionStream());
700}
701
702TEST_F(InputPublisherAndConsumerNoResamplingTest, PublishMotionMoveEvent_EndToEnd) {
703 // Publish a DOWN event before MOVE to pass the InputVerifier checks.
704 const nsecs_t downTime = systemTime(SYSTEM_TIME_MONOTONIC);
705 ASSERT_NO_FATAL_FAILURE(publishAndConsumeMotionDown(downTime));
706
707 // Publish the MOVE event and check expectations.
708 ASSERT_NO_FATAL_FAILURE(publishAndConsumeBatchedMotionMove(downTime));
709}
710
711TEST_F(InputPublisherAndConsumerNoResamplingTest, PublishFocusEvent_EndToEnd) {
712 ASSERT_NO_FATAL_FAILURE(publishAndConsumeFocusEvent());
713}
714
715TEST_F(InputPublisherAndConsumerNoResamplingTest, PublishCaptureEvent_EndToEnd) {
716 ASSERT_NO_FATAL_FAILURE(publishAndConsumeCaptureEvent());
717}
718
719TEST_F(InputPublisherAndConsumerNoResamplingTest, PublishDragEvent_EndToEnd) {
720 ASSERT_NO_FATAL_FAILURE(publishAndConsumeDragEvent());
721}
722
723TEST_F(InputPublisherAndConsumerNoResamplingTest, PublishTouchModeEvent_EndToEnd) {
724 ASSERT_NO_FATAL_FAILURE(publishAndConsumeTouchModeEvent());
725}
726
727TEST_F(InputPublisherAndConsumerNoResamplingTest,
728 PublishMotionEvent_WhenSequenceNumberIsZero_ReturnsError) {
729 status_t status;
730 const size_t pointerCount = 1;
731 PointerProperties pointerProperties[pointerCount];
732 PointerCoords pointerCoords[pointerCount];
733 for (size_t i = 0; i < pointerCount; i++) {
734 pointerProperties[i].clear();
735 pointerCoords[i].clear();
736 }
737
738 ui::Transform identityTransform;
739 status =
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -0700740 mPublisher->publishMotionEvent(0, InputEvent::nextId(), 0, 0,
741 ui::LogicalDisplayId::DEFAULT, INVALID_HMAC, 0, 0, 0, 0,
742 0, 0, MotionClassification::NONE, identityTransform, 0,
743 0, AMOTION_EVENT_INVALID_CURSOR_POSITION,
Siarhei Vishniakou2b920272024-02-27 19:49:51 -0800744 AMOTION_EVENT_INVALID_CURSOR_POSITION, identityTransform,
745 0, 0, pointerCount, pointerProperties, pointerCoords);
746 ASSERT_EQ(BAD_VALUE, status) << "publisher publishMotionEvent should return BAD_VALUE";
747}
748
749TEST_F(InputPublisherAndConsumerNoResamplingTest,
750 PublishMotionEvent_WhenPointerCountLessThan1_ReturnsError) {
751 status_t status;
752 const size_t pointerCount = 0;
753 PointerProperties pointerProperties[pointerCount];
754 PointerCoords pointerCoords[pointerCount];
755
756 ui::Transform identityTransform;
757 status =
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -0700758 mPublisher->publishMotionEvent(1, InputEvent::nextId(), 0, 0,
759 ui::LogicalDisplayId::DEFAULT, INVALID_HMAC, 0, 0, 0, 0,
760 0, 0, MotionClassification::NONE, identityTransform, 0,
761 0, AMOTION_EVENT_INVALID_CURSOR_POSITION,
Siarhei Vishniakou2b920272024-02-27 19:49:51 -0800762 AMOTION_EVENT_INVALID_CURSOR_POSITION, identityTransform,
763 0, 0, pointerCount, pointerProperties, pointerCoords);
764 ASSERT_EQ(BAD_VALUE, status) << "publisher publishMotionEvent should return BAD_VALUE";
765}
766
767TEST_F(InputPublisherAndConsumerNoResamplingTest,
768 PublishMotionEvent_WhenPointerCountGreaterThanMax_ReturnsError) {
769 status_t status;
770 const size_t pointerCount = MAX_POINTERS + 1;
771 PointerProperties pointerProperties[pointerCount];
772 PointerCoords pointerCoords[pointerCount];
773 for (size_t i = 0; i < pointerCount; i++) {
774 pointerProperties[i].clear();
775 pointerCoords[i].clear();
776 }
777
778 ui::Transform identityTransform;
779 status =
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -0700780 mPublisher->publishMotionEvent(1, InputEvent::nextId(), 0, 0,
781 ui::LogicalDisplayId::DEFAULT, INVALID_HMAC, 0, 0, 0, 0,
782 0, 0, MotionClassification::NONE, identityTransform, 0,
783 0, AMOTION_EVENT_INVALID_CURSOR_POSITION,
Siarhei Vishniakou2b920272024-02-27 19:49:51 -0800784 AMOTION_EVENT_INVALID_CURSOR_POSITION, identityTransform,
785 0, 0, pointerCount, pointerProperties, pointerCoords);
786 ASSERT_EQ(BAD_VALUE, status) << "publisher publishMotionEvent should return BAD_VALUE";
787}
788
789TEST_F(InputPublisherAndConsumerNoResamplingTest, PublishMultipleEvents_EndToEnd) {
790 const nsecs_t downTime = systemTime(SYSTEM_TIME_MONOTONIC);
791
792 publishAndConsumeMotionEvent(AMOTION_EVENT_ACTION_DOWN, downTime,
793 {Pointer{.id = 0, .x = 20, .y = 30}});
794 ASSERT_NO_FATAL_FAILURE(publishAndConsumeKeyEvent());
795 publishAndConsumeMotionEvent(POINTER_1_DOWN, downTime,
796 {Pointer{.id = 0, .x = 20, .y = 30},
797 Pointer{.id = 1, .x = 200, .y = 300}});
798 ASSERT_NO_FATAL_FAILURE(publishAndConsumeFocusEvent());
799 publishAndConsumeMotionEvent(POINTER_2_DOWN, downTime,
800 {Pointer{.id = 0, .x = 20, .y = 30},
801 Pointer{.id = 1, .x = 200, .y = 300},
802 Pointer{.id = 2, .x = 200, .y = 300}});
803 ASSERT_NO_FATAL_FAILURE(publishAndConsumeKeyEvent());
804 ASSERT_NO_FATAL_FAILURE(publishAndConsumeCaptureEvent());
805 ASSERT_NO_FATAL_FAILURE(publishAndConsumeDragEvent());
806 // Provide a consistent input stream - cancel the gesture that was started above
807 publishAndConsumeMotionEvent(AMOTION_EVENT_ACTION_CANCEL, downTime,
808 {Pointer{.id = 0, .x = 20, .y = 30},
809 Pointer{.id = 1, .x = 200, .y = 300},
810 Pointer{.id = 2, .x = 200, .y = 300}});
811 ASSERT_NO_FATAL_FAILURE(publishAndConsumeKeyEvent());
812 ASSERT_NO_FATAL_FAILURE(publishAndConsumeTouchModeEvent());
813}
814
815} // namespace android