blob: 0ac2f0f7e6d0aa52da7a26b310c3c078abedc69d [file] [log] [blame]
Prabir Pradhanc5340732024-03-20 22:53:52 +00001/*
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 "FakeWindows.h"
18
19#include <gtest/gtest.h>
20
21namespace android {
22
23// --- FakeInputReceiver ---
24
25FakeInputReceiver::FakeInputReceiver(std::unique_ptr<InputChannel> clientChannel,
26 const std::string name)
27 : mConsumer(std::move(clientChannel)), mName(name) {}
28
29std::unique_ptr<InputEvent> FakeInputReceiver::consume(std::chrono::milliseconds timeout,
30 bool handled) {
31 auto [consumeSeq, event] = receiveEvent(timeout);
32 if (!consumeSeq) {
33 return nullptr;
34 }
35 finishEvent(*consumeSeq, handled);
36 return std::move(event);
37}
38
39std::pair<std::optional<uint32_t>, std::unique_ptr<InputEvent>> FakeInputReceiver::receiveEvent(
40 std::chrono::milliseconds timeout) {
41 uint32_t consumeSeq;
42 std::unique_ptr<InputEvent> event;
43
44 std::chrono::time_point start = std::chrono::steady_clock::now();
45 status_t status = WOULD_BLOCK;
46 while (status == WOULD_BLOCK) {
47 InputEvent* rawEventPtr = nullptr;
48 status = mConsumer.consume(&mEventFactory, /*consumeBatches=*/true, -1, &consumeSeq,
49 &rawEventPtr);
50 event = std::unique_ptr<InputEvent>(rawEventPtr);
51 std::chrono::duration elapsed = std::chrono::steady_clock::now() - start;
52 if (elapsed > timeout) {
53 break;
54 }
55 }
56
57 if (status == WOULD_BLOCK) {
58 // Just means there's no event available.
59 return std::make_pair(std::nullopt, nullptr);
60 }
61
62 if (status != OK) {
63 ADD_FAILURE() << mName.c_str() << ": consumer consume should return OK.";
64 return std::make_pair(std::nullopt, nullptr);
65 }
66 if (event == nullptr) {
67 ADD_FAILURE() << "Consumed correctly, but received NULL event from consumer";
68 }
69 return std::make_pair(consumeSeq, std::move(event));
70}
71
72void FakeInputReceiver::finishEvent(uint32_t consumeSeq, bool handled) {
73 const status_t status = mConsumer.sendFinishedSignal(consumeSeq, handled);
74 ASSERT_EQ(OK, status) << mName.c_str() << ": consumer sendFinishedSignal should return OK.";
75}
76
77void FakeInputReceiver::sendTimeline(int32_t inputEventId,
78 std::array<nsecs_t, GraphicsTimeline::SIZE> timeline) {
79 const status_t status = mConsumer.sendTimeline(inputEventId, timeline);
80 ASSERT_EQ(OK, status);
81}
82
83void FakeInputReceiver::consumeEvent(InputEventType expectedEventType, int32_t expectedAction,
84 std::optional<int32_t> expectedDisplayId,
85 std::optional<int32_t> expectedFlags) {
86 std::unique_ptr<InputEvent> event = consume(CONSUME_TIMEOUT_EVENT_EXPECTED);
87
88 ASSERT_NE(nullptr, event) << mName.c_str() << ": consumer should have returned non-NULL event.";
89 ASSERT_EQ(expectedEventType, event->getType())
90 << mName.c_str() << " expected " << ftl::enum_string(expectedEventType)
91 << " event, got " << *event;
92
93 if (expectedDisplayId.has_value()) {
94 EXPECT_EQ(expectedDisplayId, event->getDisplayId());
95 }
96
97 switch (expectedEventType) {
98 case InputEventType::KEY: {
99 const KeyEvent& keyEvent = static_cast<const KeyEvent&>(*event);
100 ASSERT_THAT(keyEvent, WithKeyAction(expectedAction));
101 if (expectedFlags.has_value()) {
102 EXPECT_EQ(expectedFlags.value(), keyEvent.getFlags());
103 }
104 break;
105 }
106 case InputEventType::MOTION: {
107 const MotionEvent& motionEvent = static_cast<const MotionEvent&>(*event);
108 ASSERT_THAT(motionEvent, WithMotionAction(expectedAction));
109 if (expectedFlags.has_value()) {
110 EXPECT_EQ(expectedFlags.value(), motionEvent.getFlags());
111 }
112 break;
113 }
114 case InputEventType::FOCUS: {
115 FAIL() << "Use 'consumeFocusEvent' for FOCUS events";
116 }
117 case InputEventType::CAPTURE: {
118 FAIL() << "Use 'consumeCaptureEvent' for CAPTURE events";
119 }
120 case InputEventType::TOUCH_MODE: {
121 FAIL() << "Use 'consumeTouchModeEvent' for TOUCH_MODE events";
122 }
123 case InputEventType::DRAG: {
124 FAIL() << "Use 'consumeDragEvent' for DRAG events";
125 }
126 }
127}
128
129std::unique_ptr<MotionEvent> FakeInputReceiver::consumeMotion() {
130 std::unique_ptr<InputEvent> event = consume(CONSUME_TIMEOUT_EVENT_EXPECTED);
131
132 if (event == nullptr) {
133 ADD_FAILURE() << mName << ": expected a MotionEvent, but didn't get one.";
134 return nullptr;
135 }
136
137 if (event->getType() != InputEventType::MOTION) {
138 ADD_FAILURE() << mName << " expected a MotionEvent, got " << *event;
139 return nullptr;
140 }
141 return std::unique_ptr<MotionEvent>(static_cast<MotionEvent*>(event.release()));
142}
143
144void FakeInputReceiver::consumeMotionEvent(const ::testing::Matcher<MotionEvent>& matcher) {
145 std::unique_ptr<MotionEvent> motionEvent = consumeMotion();
146 ASSERT_NE(nullptr, motionEvent) << "Did not get a motion event, but expected " << matcher;
147 ASSERT_THAT(*motionEvent, matcher);
148}
149
150void FakeInputReceiver::consumeFocusEvent(bool hasFocus, bool inTouchMode) {
151 std::unique_ptr<InputEvent> event = consume(CONSUME_TIMEOUT_EVENT_EXPECTED);
152 ASSERT_NE(nullptr, event) << mName.c_str() << ": consumer should have returned non-NULL event.";
153 ASSERT_EQ(InputEventType::FOCUS, event->getType()) << "Instead of FocusEvent, got " << *event;
154
155 ASSERT_EQ(ADISPLAY_ID_NONE, event->getDisplayId())
156 << mName.c_str() << ": event displayId should always be NONE.";
157
158 FocusEvent& focusEvent = static_cast<FocusEvent&>(*event);
159 EXPECT_EQ(hasFocus, focusEvent.getHasFocus());
160}
161
162void FakeInputReceiver::consumeCaptureEvent(bool hasCapture) {
163 std::unique_ptr<InputEvent> event = consume(CONSUME_TIMEOUT_EVENT_EXPECTED);
164 ASSERT_NE(nullptr, event) << mName.c_str() << ": consumer should have returned non-NULL event.";
165 ASSERT_EQ(InputEventType::CAPTURE, event->getType())
166 << "Instead of CaptureEvent, got " << *event;
167
168 ASSERT_EQ(ADISPLAY_ID_NONE, event->getDisplayId())
169 << mName.c_str() << ": event displayId should always be NONE.";
170
171 const auto& captureEvent = static_cast<const CaptureEvent&>(*event);
172 EXPECT_EQ(hasCapture, captureEvent.getPointerCaptureEnabled());
173}
174
175void FakeInputReceiver::consumeDragEvent(bool isExiting, float x, float y) {
176 std::unique_ptr<InputEvent> event = consume(CONSUME_TIMEOUT_EVENT_EXPECTED);
177 ASSERT_NE(nullptr, event) << mName.c_str() << ": consumer should have returned non-NULL event.";
178 ASSERT_EQ(InputEventType::DRAG, event->getType()) << "Instead of DragEvent, got " << *event;
179
180 EXPECT_EQ(ADISPLAY_ID_NONE, event->getDisplayId())
181 << mName.c_str() << ": event displayId should always be NONE.";
182
183 const auto& dragEvent = static_cast<const DragEvent&>(*event);
184 EXPECT_EQ(isExiting, dragEvent.isExiting());
185 EXPECT_EQ(x, dragEvent.getX());
186 EXPECT_EQ(y, dragEvent.getY());
187}
188
189void FakeInputReceiver::consumeTouchModeEvent(bool inTouchMode) {
190 std::unique_ptr<InputEvent> event = consume(CONSUME_TIMEOUT_EVENT_EXPECTED);
191 ASSERT_NE(nullptr, event) << mName.c_str() << ": consumer should have returned non-NULL event.";
192 ASSERT_EQ(InputEventType::TOUCH_MODE, event->getType())
193 << "Instead of TouchModeEvent, got " << *event;
194
195 ASSERT_EQ(ADISPLAY_ID_NONE, event->getDisplayId())
196 << mName.c_str() << ": event displayId should always be NONE.";
197 const auto& touchModeEvent = static_cast<const TouchModeEvent&>(*event);
198 EXPECT_EQ(inTouchMode, touchModeEvent.isInTouchMode());
199}
200
201void FakeInputReceiver::assertNoEvents(std::chrono::milliseconds timeout) {
202 std::unique_ptr<InputEvent> event = consume(timeout);
203 if (event == nullptr) {
204 return;
205 }
206 if (event->getType() == InputEventType::KEY) {
207 KeyEvent& keyEvent = static_cast<KeyEvent&>(*event);
208 ADD_FAILURE() << "Received key event " << keyEvent;
209 } else if (event->getType() == InputEventType::MOTION) {
210 MotionEvent& motionEvent = static_cast<MotionEvent&>(*event);
211 ADD_FAILURE() << "Received motion event " << motionEvent;
212 } else if (event->getType() == InputEventType::FOCUS) {
213 FocusEvent& focusEvent = static_cast<FocusEvent&>(*event);
214 ADD_FAILURE() << "Received focus event, hasFocus = "
215 << (focusEvent.getHasFocus() ? "true" : "false");
216 } else if (event->getType() == InputEventType::CAPTURE) {
217 const auto& captureEvent = static_cast<CaptureEvent&>(*event);
218 ADD_FAILURE() << "Received capture event, pointerCaptureEnabled = "
219 << (captureEvent.getPointerCaptureEnabled() ? "true" : "false");
220 } else if (event->getType() == InputEventType::TOUCH_MODE) {
221 const auto& touchModeEvent = static_cast<TouchModeEvent&>(*event);
222 ADD_FAILURE() << "Received touch mode event, inTouchMode = "
223 << (touchModeEvent.isInTouchMode() ? "true" : "false");
224 }
225 FAIL() << mName.c_str()
226 << ": should not have received any events, so consume() should return NULL";
227}
228
229sp<IBinder> FakeInputReceiver::getToken() {
230 return mConsumer.getChannel()->getConnectionToken();
231}
232
233int FakeInputReceiver::getChannelFd() {
234 return mConsumer.getChannel()->getFd();
235}
236
237// --- FakeWindowHandle ---
238
239std::function<void(const std::unique_ptr<InputEvent>&, const gui::WindowInfo&)>
240 FakeWindowHandle::sOnEventReceivedCallback{};
241
242std::atomic<int32_t> FakeWindowHandle::sId{1};
243
244FakeWindowHandle::FakeWindowHandle(
245 const std::shared_ptr<InputApplicationHandle>& inputApplicationHandle,
246 const std::unique_ptr<inputdispatcher::InputDispatcher>& dispatcher, const std::string name,
247 int32_t displayId, bool createInputChannel)
248 : mName(name) {
249 sp<IBinder> token;
250 if (createInputChannel) {
251 base::Result<std::unique_ptr<InputChannel>> channel = dispatcher->createInputChannel(name);
252 token = (*channel)->getConnectionToken();
253 mInputReceiver = std::make_unique<FakeInputReceiver>(std::move(*channel), name);
254 }
255
256 inputApplicationHandle->updateInfo();
257 mInfo.applicationInfo = *inputApplicationHandle->getInfo();
258
259 mInfo.token = token;
260 mInfo.id = sId++;
261 mInfo.name = name;
262 mInfo.dispatchingTimeout = DISPATCHING_TIMEOUT;
263 mInfo.alpha = 1.0;
264 mInfo.frame = Rect(0, 0, WIDTH, HEIGHT);
265 mInfo.transform.set(0, 0);
266 mInfo.globalScaleFactor = 1.0;
267 mInfo.touchableRegion.clear();
268 mInfo.addTouchableRegion(Rect(0, 0, WIDTH, HEIGHT));
269 mInfo.ownerPid = WINDOW_PID;
270 mInfo.ownerUid = WINDOW_UID;
271 mInfo.displayId = displayId;
272 mInfo.inputConfig = InputConfig::DEFAULT;
273}
274
275sp<FakeWindowHandle> FakeWindowHandle::clone(int32_t displayId) {
276 sp<FakeWindowHandle> handle = sp<FakeWindowHandle>::make(mInfo.name + "(Mirror)");
277 handle->mInfo = mInfo;
278 handle->mInfo.displayId = displayId;
279 handle->mInfo.id = sId++;
280 handle->mInputReceiver = mInputReceiver;
281 return handle;
282}
283
284std::unique_ptr<KeyEvent> FakeWindowHandle::consumeKey(bool handled) {
285 std::unique_ptr<InputEvent> event = consume(CONSUME_TIMEOUT_EVENT_EXPECTED, handled);
286 if (event == nullptr) {
287 ADD_FAILURE() << "No event";
288 return nullptr;
289 }
290 if (event->getType() != InputEventType::KEY) {
291 ADD_FAILURE() << "Instead of key event, got " << event;
292 return nullptr;
293 }
294 return std::unique_ptr<KeyEvent>(static_cast<KeyEvent*>(event.release()));
295}
296
297std::unique_ptr<MotionEvent> FakeWindowHandle::consumeMotionEvent(
298 const ::testing::Matcher<MotionEvent>& matcher) {
299 std::unique_ptr<InputEvent> event = consume(CONSUME_TIMEOUT_EVENT_EXPECTED);
300 if (event == nullptr) {
301 ADD_FAILURE() << "No event";
302 return nullptr;
303 }
304 if (event->getType() != InputEventType::MOTION) {
305 ADD_FAILURE() << "Instead of motion event, got " << *event;
306 return nullptr;
307 }
308 std::unique_ptr<MotionEvent> motionEvent =
309 std::unique_ptr<MotionEvent>(static_cast<MotionEvent*>(event.release()));
310 EXPECT_THAT(*motionEvent, matcher);
311 return motionEvent;
312}
313
314void FakeWindowHandle::assertNoEvents(std::optional<std::chrono::milliseconds> timeout) {
315 if (mInputReceiver == nullptr && mInfo.inputConfig.test(InputConfig::NO_INPUT_CHANNEL)) {
316 return; // Can't receive events if the window does not have input channel
317 }
318 ASSERT_NE(nullptr, mInputReceiver)
319 << "Window without InputReceiver must specify feature NO_INPUT_CHANNEL";
320 mInputReceiver->assertNoEvents(timeout.value_or(CONSUME_TIMEOUT_NO_EVENT_EXPECTED));
321}
322
323std::unique_ptr<InputEvent> FakeWindowHandle::consume(std::chrono::milliseconds timeout,
324 bool handled) {
325 if (mInputReceiver == nullptr) {
326 LOG(FATAL) << "Cannot consume event from a window with no input event receiver";
327 }
328 std::unique_ptr<InputEvent> event = mInputReceiver->consume(timeout, handled);
329 if (event == nullptr) {
330 ADD_FAILURE() << "Consume failed: no event";
331 }
332
333 if (sOnEventReceivedCallback != nullptr) {
334 sOnEventReceivedCallback(event, mInfo);
335 }
336 return event;
337}
338
339std::pair<std::optional<uint32_t /*seq*/>, std::unique_ptr<InputEvent>>
340FakeWindowHandle::receive() {
341 if (mInputReceiver == nullptr) {
342 ADD_FAILURE() << "Invalid receive event on window with no receiver";
343 return std::make_pair(std::nullopt, nullptr);
344 }
345 auto out = mInputReceiver->receiveEvent(CONSUME_TIMEOUT_EVENT_EXPECTED);
346 const auto& [_, event] = out;
347
348 if (sOnEventReceivedCallback != nullptr) {
349 sOnEventReceivedCallback(event, mInfo);
350 }
351 return out;
352}
353
354} // namespace android