1 /*
2 * Copyright (C) 2010 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 "../dispatcher/InputDispatcher.h"
18 #include "FakeApplicationHandle.h"
19 #include "FakeInputDispatcherPolicy.h"
20 #include "FakeInputTracingBackend.h"
21 #include "FakeWindows.h"
22 #include "TestEventMatchers.h"
23
24 #include <NotifyArgsBuilders.h>
25 #include <android-base/logging.h>
26 #include <android-base/properties.h>
27 #include <android-base/silent_death_test.h>
28 #include <android-base/stringprintf.h>
29 #include <android-base/thread_annotations.h>
30 #include <binder/Binder.h>
31 #include <com_android_input_flags.h>
32 #include <fcntl.h>
33 #include <flag_macros.h>
34 #include <gmock/gmock.h>
35 #include <gtest/gtest.h>
36 #include <input/BlockingQueue.h>
37 #include <input/Input.h>
38 #include <input/InputConsumer.h>
39 #include <input/PrintTools.h>
40 #include <linux/input.h>
41 #include <sys/epoll.h>
42
43 #include <cinttypes>
44 #include <compare>
45 #include <thread>
46 #include <unordered_set>
47 #include <vector>
48
49 using android::base::StringPrintf;
50 using android::gui::FocusRequest;
51 using android::gui::TouchOcclusionMode;
52 using android::gui::WindowInfo;
53 using android::gui::WindowInfoHandle;
54 using android::os::InputEventInjectionResult;
55 using android::os::InputEventInjectionSync;
56
57 namespace android::inputdispatcher {
58
59 using namespace ftl::flag_operators;
60 using testing::AllOf;
61 using testing::Not;
62 using testing::Pointee;
63 using testing::UnorderedElementsAre;
64
65 namespace {
66
67 // An arbitrary time value.
68 static constexpr nsecs_t ARBITRARY_TIME = 1234;
69
70 // An arbitrary device id.
71 static constexpr int32_t DEVICE_ID = DEFAULT_DEVICE_ID;
72 static constexpr int32_t SECOND_DEVICE_ID = 2;
73
74 // An arbitrary display id.
75 constexpr ui::LogicalDisplayId DISPLAY_ID = ui::LogicalDisplayId::DEFAULT;
76 constexpr ui::LogicalDisplayId SECOND_DISPLAY_ID = ui::LogicalDisplayId{1};
77
78 // Ensure common actions are interchangeable between keys and motions for convenience.
79 static_assert(AMOTION_EVENT_ACTION_DOWN == AKEY_EVENT_ACTION_DOWN);
80 static_assert(AMOTION_EVENT_ACTION_UP == AKEY_EVENT_ACTION_UP);
81 static constexpr int32_t ACTION_DOWN = AMOTION_EVENT_ACTION_DOWN;
82 static constexpr int32_t ACTION_MOVE = AMOTION_EVENT_ACTION_MOVE;
83 static constexpr int32_t ACTION_UP = AMOTION_EVENT_ACTION_UP;
84 static constexpr int32_t ACTION_HOVER_ENTER = AMOTION_EVENT_ACTION_HOVER_ENTER;
85 static constexpr int32_t ACTION_HOVER_MOVE = AMOTION_EVENT_ACTION_HOVER_MOVE;
86 static constexpr int32_t ACTION_HOVER_EXIT = AMOTION_EVENT_ACTION_HOVER_EXIT;
87 static constexpr int32_t ACTION_SCROLL = AMOTION_EVENT_ACTION_SCROLL;
88 static constexpr int32_t ACTION_OUTSIDE = AMOTION_EVENT_ACTION_OUTSIDE;
89 static constexpr int32_t ACTION_CANCEL = AMOTION_EVENT_ACTION_CANCEL;
90 /**
91 * The POINTER_DOWN(0) is an unusual, but valid, action. It just means that the new pointer in the
92 * MotionEvent is at the index 0 rather than 1 (or later). That is, the pointer id=0 (which is at
93 * index 0) is the new pointer going down. The same pointer could have been placed at a different
94 * index, and the action would become POINTER_1_DOWN, 2, etc..; these would all be valid. In
95 * general, we try to place pointer id = 0 at the index 0. Of course, this is not possible if
96 * pointer id=0 leaves but the pointer id=1 remains.
97 */
98 static constexpr int32_t POINTER_0_DOWN =
99 AMOTION_EVENT_ACTION_POINTER_DOWN | (0 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT);
100 static constexpr int32_t POINTER_1_DOWN =
101 AMOTION_EVENT_ACTION_POINTER_DOWN | (1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT);
102 static constexpr int32_t POINTER_2_DOWN =
103 AMOTION_EVENT_ACTION_POINTER_DOWN | (2 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT);
104 static constexpr int32_t POINTER_3_DOWN =
105 AMOTION_EVENT_ACTION_POINTER_DOWN | (3 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT);
106 static constexpr int32_t POINTER_0_UP =
107 AMOTION_EVENT_ACTION_POINTER_UP | (0 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT);
108 static constexpr int32_t POINTER_1_UP =
109 AMOTION_EVENT_ACTION_POINTER_UP | (1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT);
110 static constexpr int32_t POINTER_2_UP =
111 AMOTION_EVENT_ACTION_POINTER_UP | (2 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT);
112
113 // The default pid and uid for the windows created on the secondary display by the test.
114 static constexpr gui::Pid SECONDARY_WINDOW_PID{1010};
115 static constexpr gui::Uid SECONDARY_WINDOW_UID{1012};
116
117 // An arbitrary pid of the gesture monitor window
118 static constexpr gui::Pid MONITOR_PID{2001};
119
120 static constexpr int EXPECTED_WALLPAPER_FLAGS =
121 AMOTION_EVENT_FLAG_WINDOW_IS_OBSCURED | AMOTION_EVENT_FLAG_WINDOW_IS_PARTIALLY_OBSCURED;
122
123 using ReservedInputDeviceId::VIRTUAL_KEYBOARD_ID;
124
125 /**
126 * Return a DOWN key event with KEYCODE_A.
127 */
getTestKeyEvent()128 static KeyEvent getTestKeyEvent() {
129 KeyEvent event;
130
131 event.initialize(InputEvent::nextId(), DEVICE_ID, AINPUT_SOURCE_KEYBOARD,
132 ui::LogicalDisplayId::INVALID, INVALID_HMAC, AKEY_EVENT_ACTION_DOWN, 0,
133 AKEYCODE_A, KEY_A, AMETA_NONE, 0, ARBITRARY_TIME, ARBITRARY_TIME);
134 return event;
135 }
136
137 /**
138 * Provide a local override for a flag value. The value is restored when the object of this class
139 * goes out of scope.
140 * This class is not intended to be used directly, because its usage is cumbersome.
141 * Instead, a wrapper macro SCOPED_FLAG_OVERRIDE is provided.
142 */
143 class ScopedFlagOverride {
144 public:
ScopedFlagOverride(std::function<bool ()> read,std::function<void (bool)> write,bool value)145 ScopedFlagOverride(std::function<bool()> read, std::function<void(bool)> write, bool value)
146 : mInitialValue(read()), mWriteValue(write) {
147 mWriteValue(value);
148 }
~ScopedFlagOverride()149 ~ScopedFlagOverride() { mWriteValue(mInitialValue); }
150
151 private:
152 const bool mInitialValue;
153 std::function<void(bool)> mWriteValue;
154 };
155
156 typedef bool (*readFlagValueFunction)();
157 typedef void (*writeFlagValueFunction)(bool);
158
159 /**
160 * Use this macro to locally override a flag value.
161 * Example usage:
162 * SCOPED_FLAG_OVERRIDE(enable_multi_device_same_window_stream, false);
163 * Note: this works by creating a local variable in your current scope. Don't call this twice for
164 * the same flag, because the variable names will clash!
165 */
166 #define SCOPED_FLAG_OVERRIDE(NAME, VALUE) \
167 readFlagValueFunction read##NAME = com::android::input::flags::NAME; \
168 writeFlagValueFunction write##NAME = com::android::input::flags::NAME; \
169 ScopedFlagOverride override##NAME(read##NAME, write##NAME, (VALUE))
170
171 } // namespace
172
173 // --- InputDispatcherTest ---
174
175 class InputDispatcherTest : public testing::Test {
176 protected:
177 std::unique_ptr<FakeInputDispatcherPolicy> mFakePolicy;
178 std::unique_ptr<InputDispatcher> mDispatcher;
179 std::shared_ptr<VerifyingTrace> mVerifyingTrace;
180
SetUp()181 void SetUp() override {
182 mVerifyingTrace = std::make_shared<VerifyingTrace>();
183 FakeWindowHandle::sOnEventReceivedCallback = [this](const auto& _1, const auto& _2) {
184 handleEventReceivedByWindow(_1, _2);
185 };
186
187 mFakePolicy = std::make_unique<FakeInputDispatcherPolicy>();
188 mDispatcher = std::make_unique<InputDispatcher>(*mFakePolicy,
189 std::make_unique<FakeInputTracingBackend>(
190 mVerifyingTrace));
191
192 mDispatcher->setInputDispatchMode(/*enabled=*/true, /*frozen=*/false);
193 // Start InputDispatcher thread
194 ASSERT_EQ(OK, mDispatcher->start());
195 }
196
TearDown()197 void TearDown() override {
198 ASSERT_NO_FATAL_FAILURE(mVerifyingTrace->verifyExpectedEventsTraced());
199 FakeWindowHandle::sOnEventReceivedCallback = nullptr;
200
201 ASSERT_EQ(OK, mDispatcher->stop());
202 mFakePolicy.reset();
203 mDispatcher.reset();
204 }
205
handleEventReceivedByWindow(const std::unique_ptr<InputEvent> & event,const gui::WindowInfo & info)206 void handleEventReceivedByWindow(const std::unique_ptr<InputEvent>& event,
207 const gui::WindowInfo& info) {
208 if (!event) {
209 return;
210 }
211
212 switch (event->getType()) {
213 case InputEventType::KEY: {
214 mVerifyingTrace->expectKeyDispatchTraced(static_cast<KeyEvent&>(*event), info.id);
215 break;
216 }
217 case InputEventType::MOTION: {
218 mVerifyingTrace->expectMotionDispatchTraced(static_cast<MotionEvent&>(*event),
219 info.id);
220 break;
221 }
222 default:
223 break;
224 }
225 }
226
227 /**
228 * Used for debugging when writing the test
229 */
dumpDispatcherState()230 void dumpDispatcherState() {
231 std::string dump;
232 mDispatcher->dump(dump);
233 std::stringstream ss(dump);
234 std::string to;
235
236 while (std::getline(ss, to, '\n')) {
237 ALOGE("%s", to.c_str());
238 }
239 }
240
setFocusedWindow(const sp<WindowInfoHandle> & window)241 void setFocusedWindow(const sp<WindowInfoHandle>& window) {
242 FocusRequest request;
243 request.token = window->getToken();
244 request.windowName = window->getName();
245 request.timestamp = systemTime(SYSTEM_TIME_MONOTONIC);
246 request.displayId = window->getInfo()->displayId.val();
247 mDispatcher->setFocusedWindow(request);
248 }
249 };
250
TEST_F(InputDispatcherTest,InjectInputEvent_ValidatesKeyEvents)251 TEST_F(InputDispatcherTest, InjectInputEvent_ValidatesKeyEvents) {
252 KeyEvent event;
253
254 // Rejects undefined key actions.
255 event.initialize(InputEvent::nextId(), DEVICE_ID, AINPUT_SOURCE_KEYBOARD,
256 ui::LogicalDisplayId::INVALID, INVALID_HMAC,
257 /*action=*/-1, 0, AKEYCODE_A, KEY_A, AMETA_NONE, 0, ARBITRARY_TIME,
258 ARBITRARY_TIME);
259 ASSERT_EQ(InputEventInjectionResult::FAILED,
260 mDispatcher->injectInputEvent(&event, /*targetUid=*/{}, InputEventInjectionSync::NONE,
261 0ms, 0))
262 << "Should reject key events with undefined action.";
263
264 // Rejects ACTION_MULTIPLE since it is not supported despite being defined in the API.
265 event.initialize(InputEvent::nextId(), DEVICE_ID, AINPUT_SOURCE_KEYBOARD,
266 ui::LogicalDisplayId::INVALID, INVALID_HMAC, AKEY_EVENT_ACTION_MULTIPLE, 0,
267 AKEYCODE_A, KEY_A, AMETA_NONE, 0, ARBITRARY_TIME, ARBITRARY_TIME);
268 ASSERT_EQ(InputEventInjectionResult::FAILED,
269 mDispatcher->injectInputEvent(&event, /*targetUid=*/{}, InputEventInjectionSync::NONE,
270 0ms, 0))
271 << "Should reject key events with ACTION_MULTIPLE.";
272 }
273
TEST_F(InputDispatcherTest,InjectInputEvent_ValidatesMotionEvents)274 TEST_F(InputDispatcherTest, InjectInputEvent_ValidatesMotionEvents) {
275 MotionEvent event;
276 PointerProperties pointerProperties[MAX_POINTERS + 1];
277 PointerCoords pointerCoords[MAX_POINTERS + 1];
278 for (size_t i = 0; i <= MAX_POINTERS; i++) {
279 pointerProperties[i].clear();
280 pointerProperties[i].id = i;
281 pointerCoords[i].clear();
282 }
283
284 // Some constants commonly used below
285 constexpr int32_t source = AINPUT_SOURCE_TOUCHSCREEN;
286 constexpr int32_t edgeFlags = AMOTION_EVENT_EDGE_FLAG_NONE;
287 constexpr int32_t metaState = AMETA_NONE;
288 constexpr MotionClassification classification = MotionClassification::NONE;
289
290 ui::Transform identityTransform;
291 // Rejects undefined motion actions.
292 event.initialize(InputEvent::nextId(), DEVICE_ID, source, DISPLAY_ID, INVALID_HMAC,
293 /*action=*/-1, 0, 0, edgeFlags, metaState, 0, classification,
294 identityTransform, 0, 0, AMOTION_EVENT_INVALID_CURSOR_POSITION,
295 AMOTION_EVENT_INVALID_CURSOR_POSITION, identityTransform, ARBITRARY_TIME,
296 ARBITRARY_TIME,
297 /*pointerCount=*/1, pointerProperties, pointerCoords);
298 ASSERT_EQ(InputEventInjectionResult::FAILED,
299 mDispatcher->injectInputEvent(&event, /*targetUid=*/{}, InputEventInjectionSync::NONE,
300 0ms, 0))
301 << "Should reject motion events with undefined action.";
302
303 // Rejects pointer down with invalid index.
304 event.initialize(InputEvent::nextId(), DEVICE_ID, source, DISPLAY_ID, INVALID_HMAC,
305 POINTER_1_DOWN, 0, 0, edgeFlags, metaState, 0, classification,
306 identityTransform, 0, 0, AMOTION_EVENT_INVALID_CURSOR_POSITION,
307 AMOTION_EVENT_INVALID_CURSOR_POSITION, identityTransform, ARBITRARY_TIME,
308 ARBITRARY_TIME,
309 /*pointerCount=*/1, pointerProperties, pointerCoords);
310 ASSERT_EQ(InputEventInjectionResult::FAILED,
311 mDispatcher->injectInputEvent(&event, /*targetUid=*/{}, InputEventInjectionSync::NONE,
312 0ms, 0))
313 << "Should reject motion events with pointer down index too large.";
314
315 event.initialize(InputEvent::nextId(), DEVICE_ID, source, DISPLAY_ID, INVALID_HMAC,
316 AMOTION_EVENT_ACTION_POINTER_DOWN |
317 (~0U << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT),
318 0, 0, edgeFlags, metaState, 0, classification, identityTransform, 0, 0,
319 AMOTION_EVENT_INVALID_CURSOR_POSITION, AMOTION_EVENT_INVALID_CURSOR_POSITION,
320 identityTransform, ARBITRARY_TIME, ARBITRARY_TIME,
321 /*pointerCount=*/1, pointerProperties, pointerCoords);
322 ASSERT_EQ(InputEventInjectionResult::FAILED,
323 mDispatcher->injectInputEvent(&event, /*targetUid=*/{}, InputEventInjectionSync::NONE,
324 0ms, 0))
325 << "Should reject motion events with pointer down index too small.";
326
327 // Rejects pointer up with invalid index.
328 event.initialize(InputEvent::nextId(), DEVICE_ID, source, DISPLAY_ID, INVALID_HMAC,
329 POINTER_1_UP, 0, 0, edgeFlags, metaState, 0, classification, identityTransform,
330 0, 0, AMOTION_EVENT_INVALID_CURSOR_POSITION,
331 AMOTION_EVENT_INVALID_CURSOR_POSITION, identityTransform, ARBITRARY_TIME,
332 ARBITRARY_TIME,
333 /*pointerCount=*/1, pointerProperties, pointerCoords);
334 ASSERT_EQ(InputEventInjectionResult::FAILED,
335 mDispatcher->injectInputEvent(&event, /*targetUid=*/{}, InputEventInjectionSync::NONE,
336 0ms, 0))
337 << "Should reject motion events with pointer up index too large.";
338
339 event.initialize(InputEvent::nextId(), DEVICE_ID, source, DISPLAY_ID, INVALID_HMAC,
340 AMOTION_EVENT_ACTION_POINTER_UP |
341 (~0U << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT),
342 0, 0, edgeFlags, metaState, 0, classification, identityTransform, 0, 0,
343 AMOTION_EVENT_INVALID_CURSOR_POSITION, AMOTION_EVENT_INVALID_CURSOR_POSITION,
344 identityTransform, ARBITRARY_TIME, ARBITRARY_TIME,
345 /*pointerCount=*/1, pointerProperties, pointerCoords);
346 ASSERT_EQ(InputEventInjectionResult::FAILED,
347 mDispatcher->injectInputEvent(&event, /*targetUid=*/{}, InputEventInjectionSync::NONE,
348 0ms, 0))
349 << "Should reject motion events with pointer up index too small.";
350
351 // Rejects motion events with invalid number of pointers.
352 event.initialize(InputEvent::nextId(), DEVICE_ID, source, DISPLAY_ID, INVALID_HMAC,
353 AMOTION_EVENT_ACTION_DOWN, 0, 0, edgeFlags, metaState, 0, classification,
354 identityTransform, 0, 0, AMOTION_EVENT_INVALID_CURSOR_POSITION,
355 AMOTION_EVENT_INVALID_CURSOR_POSITION, identityTransform, ARBITRARY_TIME,
356 ARBITRARY_TIME,
357 /*pointerCount=*/0, pointerProperties, pointerCoords);
358 ASSERT_EQ(InputEventInjectionResult::FAILED,
359 mDispatcher->injectInputEvent(&event, /*targetUid=*/{}, InputEventInjectionSync::NONE,
360 0ms, 0))
361 << "Should reject motion events with 0 pointers.";
362
363 event.initialize(InputEvent::nextId(), DEVICE_ID, source, DISPLAY_ID, INVALID_HMAC,
364 AMOTION_EVENT_ACTION_DOWN, 0, 0, edgeFlags, metaState, 0, classification,
365 identityTransform, 0, 0, AMOTION_EVENT_INVALID_CURSOR_POSITION,
366 AMOTION_EVENT_INVALID_CURSOR_POSITION, identityTransform, ARBITRARY_TIME,
367 ARBITRARY_TIME,
368 /*pointerCount=*/MAX_POINTERS + 1, pointerProperties, pointerCoords);
369 ASSERT_EQ(InputEventInjectionResult::FAILED,
370 mDispatcher->injectInputEvent(&event, /*targetUid=*/{}, InputEventInjectionSync::NONE,
371 0ms, 0))
372 << "Should reject motion events with more than MAX_POINTERS pointers.";
373
374 // Rejects motion events with invalid pointer ids.
375 pointerProperties[0].id = -1;
376 event.initialize(InputEvent::nextId(), DEVICE_ID, source, DISPLAY_ID, INVALID_HMAC,
377 AMOTION_EVENT_ACTION_DOWN, 0, 0, edgeFlags, metaState, 0, classification,
378 identityTransform, 0, 0, AMOTION_EVENT_INVALID_CURSOR_POSITION,
379 AMOTION_EVENT_INVALID_CURSOR_POSITION, identityTransform, ARBITRARY_TIME,
380 ARBITRARY_TIME,
381 /*pointerCount=*/1, pointerProperties, pointerCoords);
382 ASSERT_EQ(InputEventInjectionResult::FAILED,
383 mDispatcher->injectInputEvent(&event, /*targetUid=*/{}, InputEventInjectionSync::NONE,
384 0ms, 0))
385 << "Should reject motion events with pointer ids less than 0.";
386
387 pointerProperties[0].id = MAX_POINTER_ID + 1;
388 event.initialize(InputEvent::nextId(), DEVICE_ID, source, DISPLAY_ID, INVALID_HMAC,
389 AMOTION_EVENT_ACTION_DOWN, 0, 0, edgeFlags, metaState, 0, classification,
390 identityTransform, 0, 0, AMOTION_EVENT_INVALID_CURSOR_POSITION,
391 AMOTION_EVENT_INVALID_CURSOR_POSITION, identityTransform, ARBITRARY_TIME,
392 ARBITRARY_TIME,
393 /*pointerCount=*/1, pointerProperties, pointerCoords);
394 ASSERT_EQ(InputEventInjectionResult::FAILED,
395 mDispatcher->injectInputEvent(&event, /*targetUid=*/{}, InputEventInjectionSync::NONE,
396 0ms, 0))
397 << "Should reject motion events with pointer ids greater than MAX_POINTER_ID.";
398
399 // Rejects motion events with duplicate pointer ids.
400 pointerProperties[0].id = 1;
401 pointerProperties[1].id = 1;
402 event.initialize(InputEvent::nextId(), DEVICE_ID, source, DISPLAY_ID, INVALID_HMAC,
403 AMOTION_EVENT_ACTION_DOWN, 0, 0, edgeFlags, metaState, 0, classification,
404 identityTransform, 0, 0, AMOTION_EVENT_INVALID_CURSOR_POSITION,
405 AMOTION_EVENT_INVALID_CURSOR_POSITION, identityTransform, ARBITRARY_TIME,
406 ARBITRARY_TIME,
407 /*pointerCount=*/2, pointerProperties, pointerCoords);
408 ASSERT_EQ(InputEventInjectionResult::FAILED,
409 mDispatcher->injectInputEvent(&event, /*targetUid=*/{}, InputEventInjectionSync::NONE,
410 0ms, 0))
411 << "Should reject motion events with duplicate pointer ids.";
412 }
413
TEST_F(InputDispatcherTest,NotifySwitch_CallsPolicy)414 TEST_F(InputDispatcherTest, NotifySwitch_CallsPolicy) {
415 NotifySwitchArgs args(InputEvent::nextId(), /*eventTime=*/20, /*policyFlags=*/0,
416 /*switchValues=*/1,
417 /*switchMask=*/2);
418 mDispatcher->notifySwitch(args);
419
420 // InputDispatcher adds POLICY_FLAG_TRUSTED because the event went through InputListener
421 args.policyFlags |= POLICY_FLAG_TRUSTED;
422 mFakePolicy->assertNotifySwitchWasCalled(args);
423 }
424
425 namespace {
426
427 static constexpr std::chrono::duration INJECT_EVENT_TIMEOUT = 500ms;
428
429 class FakeMonitorReceiver {
430 public:
FakeMonitorReceiver(InputDispatcher & dispatcher,const std::string name,ui::LogicalDisplayId displayId)431 FakeMonitorReceiver(InputDispatcher& dispatcher, const std::string name,
432 ui::LogicalDisplayId displayId)
433 : mInputReceiver(*dispatcher.createInputMonitor(displayId, name, MONITOR_PID), name) {}
434
getToken()435 sp<IBinder> getToken() { return mInputReceiver.getToken(); }
436
consumeKeyDown(ui::LogicalDisplayId expectedDisplayId,int32_t expectedFlags=0)437 void consumeKeyDown(ui::LogicalDisplayId expectedDisplayId, int32_t expectedFlags = 0) {
438 mInputReceiver.consumeEvent(InputEventType::KEY, AKEY_EVENT_ACTION_DOWN, expectedDisplayId,
439 expectedFlags);
440 }
441
receiveEvent()442 std::optional<int32_t> receiveEvent() {
443 const auto [sequenceNum, _] = mInputReceiver.receiveEvent(CONSUME_TIMEOUT_EVENT_EXPECTED);
444 return sequenceNum;
445 }
446
finishEvent(uint32_t consumeSeq)447 void finishEvent(uint32_t consumeSeq) { return mInputReceiver.finishEvent(consumeSeq); }
448
consumeMotionDown(ui::LogicalDisplayId expectedDisplayId,int32_t expectedFlags=0)449 void consumeMotionDown(ui::LogicalDisplayId expectedDisplayId, int32_t expectedFlags = 0) {
450 mInputReceiver.consumeEvent(InputEventType::MOTION, AMOTION_EVENT_ACTION_DOWN,
451 expectedDisplayId, expectedFlags);
452 }
453
consumeMotionMove(ui::LogicalDisplayId expectedDisplayId,int32_t expectedFlags=0)454 void consumeMotionMove(ui::LogicalDisplayId expectedDisplayId, int32_t expectedFlags = 0) {
455 mInputReceiver.consumeEvent(InputEventType::MOTION, AMOTION_EVENT_ACTION_MOVE,
456 expectedDisplayId, expectedFlags);
457 }
458
consumeMotionUp(ui::LogicalDisplayId expectedDisplayId,int32_t expectedFlags=0)459 void consumeMotionUp(ui::LogicalDisplayId expectedDisplayId, int32_t expectedFlags = 0) {
460 mInputReceiver.consumeEvent(InputEventType::MOTION, AMOTION_EVENT_ACTION_UP,
461 expectedDisplayId, expectedFlags);
462 }
463
consumeMotionCancel(ui::LogicalDisplayId expectedDisplayId,int32_t expectedFlags=0)464 void consumeMotionCancel(ui::LogicalDisplayId expectedDisplayId, int32_t expectedFlags = 0) {
465 mInputReceiver.consumeMotionEvent(
466 AllOf(WithMotionAction(AMOTION_EVENT_ACTION_CANCEL),
467 WithDisplayId(expectedDisplayId),
468 WithFlags(expectedFlags | AMOTION_EVENT_FLAG_CANCELED)));
469 }
470
consumeMotionPointerDown(int32_t pointerIdx)471 void consumeMotionPointerDown(int32_t pointerIdx) {
472 int32_t action = AMOTION_EVENT_ACTION_POINTER_DOWN |
473 (pointerIdx << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT);
474 mInputReceiver.consumeEvent(InputEventType::MOTION, action, ui::LogicalDisplayId::DEFAULT,
475 /*expectedFlags=*/0);
476 }
477
consumeMotionEvent(const::testing::Matcher<MotionEvent> & matcher)478 void consumeMotionEvent(const ::testing::Matcher<MotionEvent>& matcher) {
479 mInputReceiver.consumeMotionEvent(matcher);
480 }
481
consumeMotion()482 std::unique_ptr<MotionEvent> consumeMotion() { return mInputReceiver.consumeMotion(); }
483
assertNoEvents()484 void assertNoEvents() { mInputReceiver.assertNoEvents(CONSUME_TIMEOUT_NO_EVENT_EXPECTED); }
485
486 private:
487 FakeInputReceiver mInputReceiver;
488 };
489
injectKey(InputDispatcher & dispatcher,int32_t action,int32_t repeatCount,ui::LogicalDisplayId displayId=ui::LogicalDisplayId::INVALID,InputEventInjectionSync syncMode=InputEventInjectionSync::WAIT_FOR_RESULT,std::chrono::milliseconds injectionTimeout=INJECT_EVENT_TIMEOUT,bool allowKeyRepeat=true,std::optional<gui::Uid> targetUid={},uint32_t policyFlags=DEFAULT_POLICY_FLAGS)490 static InputEventInjectionResult injectKey(
491 InputDispatcher& dispatcher, int32_t action, int32_t repeatCount,
492 ui::LogicalDisplayId displayId = ui::LogicalDisplayId::INVALID,
493 InputEventInjectionSync syncMode = InputEventInjectionSync::WAIT_FOR_RESULT,
494 std::chrono::milliseconds injectionTimeout = INJECT_EVENT_TIMEOUT,
495 bool allowKeyRepeat = true, std::optional<gui::Uid> targetUid = {},
496 uint32_t policyFlags = DEFAULT_POLICY_FLAGS) {
497 KeyEvent event;
498 nsecs_t currentTime = systemTime(SYSTEM_TIME_MONOTONIC);
499
500 // Define a valid key down event.
501 event.initialize(InputEvent::nextId(), DEVICE_ID, AINPUT_SOURCE_KEYBOARD, displayId,
502 INVALID_HMAC, action, /*flags=*/0, AKEYCODE_A, KEY_A, AMETA_NONE, repeatCount,
503 currentTime, currentTime);
504
505 if (!allowKeyRepeat) {
506 policyFlags |= POLICY_FLAG_DISABLE_KEY_REPEAT;
507 }
508 // Inject event until dispatch out.
509 return dispatcher.injectInputEvent(&event, targetUid, syncMode, injectionTimeout, policyFlags);
510 }
511
assertInjectedKeyTimesOut(InputDispatcher & dispatcher)512 static void assertInjectedKeyTimesOut(InputDispatcher& dispatcher) {
513 InputEventInjectionResult result =
514 injectKey(dispatcher, AKEY_EVENT_ACTION_DOWN, /*repeatCount=*/0,
515 ui::LogicalDisplayId::INVALID, InputEventInjectionSync::WAIT_FOR_RESULT,
516 CONSUME_TIMEOUT_NO_EVENT_EXPECTED);
517 if (result != InputEventInjectionResult::TIMED_OUT) {
518 FAIL() << "Injection should have timed out, but got " << ftl::enum_string(result);
519 }
520 }
521
injectKeyDown(InputDispatcher & dispatcher,ui::LogicalDisplayId displayId=ui::LogicalDisplayId::INVALID)522 static InputEventInjectionResult injectKeyDown(
523 InputDispatcher& dispatcher,
524 ui::LogicalDisplayId displayId = ui::LogicalDisplayId::INVALID) {
525 return injectKey(dispatcher, AKEY_EVENT_ACTION_DOWN, /*repeatCount=*/0, displayId);
526 }
527
528 // Inject a down event that has key repeat disabled. This allows InputDispatcher to idle without
529 // sending a subsequent key up. When key repeat is enabled, the dispatcher cannot idle because it
530 // has to be woken up to process the repeating key.
injectKeyDownNoRepeat(InputDispatcher & dispatcher,ui::LogicalDisplayId displayId=ui::LogicalDisplayId::INVALID)531 static InputEventInjectionResult injectKeyDownNoRepeat(
532 InputDispatcher& dispatcher,
533 ui::LogicalDisplayId displayId = ui::LogicalDisplayId::INVALID) {
534 return injectKey(dispatcher, AKEY_EVENT_ACTION_DOWN, /*repeatCount=*/0, displayId,
535 InputEventInjectionSync::WAIT_FOR_RESULT, INJECT_EVENT_TIMEOUT,
536 /*allowKeyRepeat=*/false);
537 }
538
injectKeyUp(InputDispatcher & dispatcher,ui::LogicalDisplayId displayId=ui::LogicalDisplayId::INVALID)539 static InputEventInjectionResult injectKeyUp(
540 InputDispatcher& dispatcher,
541 ui::LogicalDisplayId displayId = ui::LogicalDisplayId::INVALID) {
542 return injectKey(dispatcher, AKEY_EVENT_ACTION_UP, /*repeatCount=*/0, displayId);
543 }
544
injectMotionEvent(InputDispatcher & dispatcher,const MotionEvent & event,std::chrono::milliseconds injectionTimeout=INJECT_EVENT_TIMEOUT,InputEventInjectionSync injectionMode=InputEventInjectionSync::WAIT_FOR_RESULT,std::optional<gui::Uid> targetUid={},uint32_t policyFlags=DEFAULT_POLICY_FLAGS)545 static InputEventInjectionResult injectMotionEvent(
546 InputDispatcher& dispatcher, const MotionEvent& event,
547 std::chrono::milliseconds injectionTimeout = INJECT_EVENT_TIMEOUT,
548 InputEventInjectionSync injectionMode = InputEventInjectionSync::WAIT_FOR_RESULT,
549 std::optional<gui::Uid> targetUid = {}, uint32_t policyFlags = DEFAULT_POLICY_FLAGS) {
550 return dispatcher.injectInputEvent(&event, targetUid, injectionMode, injectionTimeout,
551 policyFlags);
552 }
553
injectMotionEvent(InputDispatcher & dispatcher,int32_t action,int32_t source,ui::LogicalDisplayId displayId,const PointF & position={100, 200},const PointF & cursorPosition={AMOTION_EVENT_INVALID_CURSOR_POSITION, AMOTION_EVENT_INVALID_CURSOR_POSITION},std::chrono::milliseconds injectionTimeout=INJECT_EVENT_TIMEOUT,InputEventInjectionSync injectionMode=InputEventInjectionSync::WAIT_FOR_RESULT,nsecs_t eventTime=systemTime (SYSTEM_TIME_MONOTONIC),std::optional<gui::Uid> targetUid={},uint32_t policyFlags=DEFAULT_POLICY_FLAGS)554 static InputEventInjectionResult injectMotionEvent(
555 InputDispatcher& dispatcher, int32_t action, int32_t source, ui::LogicalDisplayId displayId,
556 const PointF& position = {100, 200},
557 const PointF& cursorPosition = {AMOTION_EVENT_INVALID_CURSOR_POSITION,
558 AMOTION_EVENT_INVALID_CURSOR_POSITION},
559 std::chrono::milliseconds injectionTimeout = INJECT_EVENT_TIMEOUT,
560 InputEventInjectionSync injectionMode = InputEventInjectionSync::WAIT_FOR_RESULT,
561 nsecs_t eventTime = systemTime(SYSTEM_TIME_MONOTONIC),
562 std::optional<gui::Uid> targetUid = {}, uint32_t policyFlags = DEFAULT_POLICY_FLAGS) {
563 MotionEventBuilder motionBuilder =
564 MotionEventBuilder(action, source)
565 .displayId(displayId)
566 .eventTime(eventTime)
567 .rawXCursorPosition(cursorPosition.x)
568 .rawYCursorPosition(cursorPosition.y)
569 .pointer(
570 PointerBuilder(/*id=*/0, ToolType::FINGER).x(position.x).y(position.y));
571 if (MotionEvent::getActionMasked(action) == ACTION_DOWN) {
572 motionBuilder.downTime(eventTime);
573 }
574
575 // Inject event until dispatch out.
576 return injectMotionEvent(dispatcher, motionBuilder.build(), injectionTimeout, injectionMode,
577 targetUid, policyFlags);
578 }
579
injectMotionDown(InputDispatcher & dispatcher,int32_t source,ui::LogicalDisplayId displayId,const PointF & location={100, 200})580 static InputEventInjectionResult injectMotionDown(InputDispatcher& dispatcher, int32_t source,
581 ui::LogicalDisplayId displayId,
582 const PointF& location = {100, 200}) {
583 return injectMotionEvent(dispatcher, AMOTION_EVENT_ACTION_DOWN, source, displayId, location);
584 }
585
injectMotionUp(InputDispatcher & dispatcher,int32_t source,ui::LogicalDisplayId displayId,const PointF & location={100, 200})586 static InputEventInjectionResult injectMotionUp(InputDispatcher& dispatcher, int32_t source,
587 ui::LogicalDisplayId displayId,
588 const PointF& location = {100, 200}) {
589 return injectMotionEvent(dispatcher, AMOTION_EVENT_ACTION_UP, source, displayId, location);
590 }
591
generateKeyArgs(int32_t action,ui::LogicalDisplayId displayId=ui::LogicalDisplayId::INVALID)592 static NotifyKeyArgs generateKeyArgs(
593 int32_t action, ui::LogicalDisplayId displayId = ui::LogicalDisplayId::INVALID) {
594 nsecs_t currentTime = systemTime(SYSTEM_TIME_MONOTONIC);
595 // Define a valid key event.
596 NotifyKeyArgs args(InputEvent::nextId(), currentTime, /*readTime=*/0, DEVICE_ID,
597 AINPUT_SOURCE_KEYBOARD, displayId, POLICY_FLAG_PASS_TO_USER, action,
598 /*flags=*/0, AKEYCODE_A, KEY_A, AMETA_NONE, currentTime);
599
600 return args;
601 }
602
generateMotionArgs(int32_t action,int32_t source,ui::LogicalDisplayId displayId,const std::vector<PointF> & points)603 [[nodiscard]] static NotifyMotionArgs generateMotionArgs(int32_t action, int32_t source,
604 ui::LogicalDisplayId displayId,
605 const std::vector<PointF>& points) {
606 size_t pointerCount = points.size();
607 if (action == AMOTION_EVENT_ACTION_DOWN || action == AMOTION_EVENT_ACTION_UP) {
608 EXPECT_EQ(1U, pointerCount) << "Actions DOWN and UP can only contain a single pointer";
609 }
610
611 PointerProperties pointerProperties[pointerCount];
612 PointerCoords pointerCoords[pointerCount];
613
614 for (size_t i = 0; i < pointerCount; i++) {
615 pointerProperties[i].clear();
616 pointerProperties[i].id = i;
617 pointerProperties[i].toolType = ToolType::FINGER;
618
619 pointerCoords[i].clear();
620 pointerCoords[i].setAxisValue(AMOTION_EVENT_AXIS_X, points[i].x);
621 pointerCoords[i].setAxisValue(AMOTION_EVENT_AXIS_Y, points[i].y);
622 }
623
624 nsecs_t currentTime = systemTime(SYSTEM_TIME_MONOTONIC);
625 // Define a valid motion event.
626 NotifyMotionArgs args(InputEvent::nextId(), currentTime, /*readTime=*/0, DEVICE_ID, source,
627 displayId, POLICY_FLAG_PASS_TO_USER, action, /*actionButton=*/0,
628 /*flags=*/0, AMETA_NONE, /*buttonState=*/0, MotionClassification::NONE,
629 AMOTION_EVENT_EDGE_FLAG_NONE, pointerCount, pointerProperties,
630 pointerCoords, /*xPrecision=*/0, /*yPrecision=*/0,
631 AMOTION_EVENT_INVALID_CURSOR_POSITION,
632 AMOTION_EVENT_INVALID_CURSOR_POSITION, currentTime, /*videoFrames=*/{});
633
634 return args;
635 }
636
generateTouchArgs(int32_t action,const std::vector<PointF> & points)637 static NotifyMotionArgs generateTouchArgs(int32_t action, const std::vector<PointF>& points) {
638 return generateMotionArgs(action, AINPUT_SOURCE_TOUCHSCREEN, DISPLAY_ID, points);
639 }
640
generateMotionArgs(int32_t action,int32_t source,ui::LogicalDisplayId displayId)641 static NotifyMotionArgs generateMotionArgs(int32_t action, int32_t source,
642 ui::LogicalDisplayId displayId) {
643 return generateMotionArgs(action, source, displayId, {PointF{100, 200}});
644 }
645
generatePointerCaptureChangedArgs(const PointerCaptureRequest & request)646 static NotifyPointerCaptureChangedArgs generatePointerCaptureChangedArgs(
647 const PointerCaptureRequest& request) {
648 return NotifyPointerCaptureChangedArgs(InputEvent::nextId(), systemTime(SYSTEM_TIME_MONOTONIC),
649 request);
650 }
651
652 } // namespace
653
654 /**
655 * When a window unexpectedly disposes of its input channel, policy should be notified about the
656 * broken channel.
657 */
TEST_F(InputDispatcherTest,WhenInputChannelBreaks_PolicyIsNotified)658 TEST_F(InputDispatcherTest, WhenInputChannelBreaks_PolicyIsNotified) {
659 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
660 sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher,
661 "Window that breaks its input channel",
662 ui::LogicalDisplayId::DEFAULT);
663
664 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
665
666 // Window closes its channel, but the window remains.
667 window->destroyReceiver();
668 mFakePolicy->assertNotifyInputChannelBrokenWasCalled(window->getInfo()->token);
669 }
670
TEST_F(InputDispatcherTest,SetInputWindow_SingleWindowTouch)671 TEST_F(InputDispatcherTest, SetInputWindow_SingleWindowTouch) {
672 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
673 sp<FakeWindowHandle> window =
674 sp<FakeWindowHandle>::make(application, mDispatcher, "Fake Window",
675 ui::LogicalDisplayId::DEFAULT);
676
677 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
678 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
679 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN,
680 ui::LogicalDisplayId::DEFAULT))
681 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
682
683 // Window should receive motion event.
684 window->consumeMotionDown(ui::LogicalDisplayId::DEFAULT);
685 }
686
687 using InputDispatcherDeathTest = InputDispatcherTest;
688
689 /**
690 * When 'onWindowInfosChanged' arguments contain a duplicate entry for the same window, dispatcher
691 * should crash.
692 */
TEST_F(InputDispatcherDeathTest,DuplicateWindowInfosAbortDispatcher)693 TEST_F(InputDispatcherDeathTest, DuplicateWindowInfosAbortDispatcher) {
694 testing::GTEST_FLAG(death_test_style) = "threadsafe";
695 ScopedSilentDeath _silentDeath;
696
697 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
698 sp<FakeWindowHandle> window =
699 sp<FakeWindowHandle>::make(application, mDispatcher, "Fake Window",
700 ui::LogicalDisplayId::DEFAULT);
701 ASSERT_DEATH(mDispatcher->onWindowInfosChanged(
702 {{*window->getInfo(), *window->getInfo()}, {}, 0, 0}),
703 "Incorrect WindowInfosUpdate provided");
704 }
705
TEST_F(InputDispatcherTest,WhenDisplayNotSpecified_InjectMotionToDefaultDisplay)706 TEST_F(InputDispatcherTest, WhenDisplayNotSpecified_InjectMotionToDefaultDisplay) {
707 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
708 sp<FakeWindowHandle> window =
709 sp<FakeWindowHandle>::make(application, mDispatcher, "Fake Window",
710 ui::LogicalDisplayId::DEFAULT);
711
712 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
713 // Inject a MotionEvent to an unknown display.
714 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
715 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN,
716 ui::LogicalDisplayId::INVALID))
717 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
718
719 // Window should receive motion event.
720 window->consumeMotionDown(ui::LogicalDisplayId::DEFAULT);
721 }
722
723 /**
724 * Calling onWindowInfosChanged once should not cause any issues.
725 * This test serves as a sanity check for the next test, where onWindowInfosChanged is
726 * called twice.
727 */
TEST_F(InputDispatcherTest,SetInputWindowOnceWithSingleTouchWindow)728 TEST_F(InputDispatcherTest, SetInputWindowOnceWithSingleTouchWindow) {
729 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
730 sp<FakeWindowHandle> window =
731 sp<FakeWindowHandle>::make(application, mDispatcher, "Fake Window",
732 ui::LogicalDisplayId::DEFAULT);
733 window->setFrame(Rect(0, 0, 100, 100));
734
735 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
736 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
737 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN,
738 ui::LogicalDisplayId::DEFAULT, {50, 50}))
739 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
740
741 // Window should receive motion event.
742 window->consumeMotionDown(ui::LogicalDisplayId::DEFAULT);
743 }
744
745 /**
746 * Calling onWindowInfosChanged twice, with the same info, should not cause any issues.
747 */
TEST_F(InputDispatcherTest,SetInputWindowTwice_SingleWindowTouch)748 TEST_F(InputDispatcherTest, SetInputWindowTwice_SingleWindowTouch) {
749 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
750 sp<FakeWindowHandle> window =
751 sp<FakeWindowHandle>::make(application, mDispatcher, "Fake Window",
752 ui::LogicalDisplayId::DEFAULT);
753 window->setFrame(Rect(0, 0, 100, 100));
754
755 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
756 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
757 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
758 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN,
759 ui::LogicalDisplayId::DEFAULT, {50, 50}))
760 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
761
762 // Window should receive motion event.
763 window->consumeMotionDown(ui::LogicalDisplayId::DEFAULT);
764 }
765
766 // The foreground window should receive the first touch down event.
TEST_F(InputDispatcherTest,SetInputWindow_MultiWindowsTouch)767 TEST_F(InputDispatcherTest, SetInputWindow_MultiWindowsTouch) {
768 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
769 sp<FakeWindowHandle> windowTop = sp<FakeWindowHandle>::make(application, mDispatcher, "Top",
770 ui::LogicalDisplayId::DEFAULT);
771 sp<FakeWindowHandle> windowSecond =
772 sp<FakeWindowHandle>::make(application, mDispatcher, "Second",
773 ui::LogicalDisplayId::DEFAULT);
774
775 mDispatcher->onWindowInfosChanged(
776 {{*windowTop->getInfo(), *windowSecond->getInfo()}, {}, 0, 0});
777 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
778 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN,
779 ui::LogicalDisplayId::DEFAULT))
780 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
781
782 // Top window should receive the touch down event. Second window should not receive anything.
783 windowTop->consumeMotionDown(ui::LogicalDisplayId::DEFAULT);
784 windowSecond->assertNoEvents();
785 }
786
787 /**
788 * Two windows: A top window, and a wallpaper behind the window.
789 * Touch goes to the top window, and then top window disappears. Ensure that wallpaper window
790 * gets ACTION_CANCEL.
791 * 1. foregroundWindow <-- dup touch to wallpaper
792 * 2. wallpaperWindow <-- is wallpaper
793 */
TEST_F(InputDispatcherTest,WhenForegroundWindowDisappears_WallpaperTouchIsCanceled)794 TEST_F(InputDispatcherTest, WhenForegroundWindowDisappears_WallpaperTouchIsCanceled) {
795 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
796 sp<FakeWindowHandle> foregroundWindow =
797 sp<FakeWindowHandle>::make(application, mDispatcher, "Foreground",
798 ui::LogicalDisplayId::DEFAULT);
799 foregroundWindow->setDupTouchToWallpaper(true);
800 sp<FakeWindowHandle> wallpaperWindow =
801 sp<FakeWindowHandle>::make(application, mDispatcher, "Wallpaper",
802 ui::LogicalDisplayId::DEFAULT);
803 wallpaperWindow->setIsWallpaper(true);
804
805 mDispatcher->onWindowInfosChanged(
806 {{*foregroundWindow->getInfo(), *wallpaperWindow->getInfo()}, {}, 0, 0});
807 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
808 injectMotionEvent(*mDispatcher,
809 MotionEventBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
810 .pointer(PointerBuilder(0, ToolType::FINGER).x(100).y(200))
811 .build()))
812 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
813
814 // Both foreground window and its wallpaper should receive the touch down
815 foregroundWindow->consumeMotionDown();
816 wallpaperWindow->consumeMotionDown(ui::LogicalDisplayId::DEFAULT, EXPECTED_WALLPAPER_FLAGS);
817
818 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
819 injectMotionEvent(*mDispatcher,
820 MotionEventBuilder(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN)
821 .pointer(PointerBuilder(0, ToolType::FINGER).x(110).y(200))
822 .build()))
823 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
824
825 foregroundWindow->consumeMotionEvent(WithMotionAction(ACTION_MOVE));
826 wallpaperWindow->consumeMotionMove(ui::LogicalDisplayId::DEFAULT, EXPECTED_WALLPAPER_FLAGS);
827
828 // Now the foreground window goes away, but the wallpaper stays
829 mDispatcher->onWindowInfosChanged({{*wallpaperWindow->getInfo()}, {}, 0, 0});
830 foregroundWindow->consumeMotionCancel();
831 // Since the "parent" window of the wallpaper is gone, wallpaper should receive cancel, too.
832 wallpaperWindow->consumeMotionCancel(ui::LogicalDisplayId::DEFAULT, EXPECTED_WALLPAPER_FLAGS);
833 }
834
835 /**
836 * Two fingers down on the window, and lift off the first finger.
837 * Next, cancel the gesture to the window by removing the window. Make sure that the CANCEL event
838 * contains a single pointer.
839 */
TEST_F(InputDispatcherTest,CancelAfterPointer0Up)840 TEST_F(InputDispatcherTest, CancelAfterPointer0Up) {
841 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
842 sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher, "Window",
843 ui::LogicalDisplayId::DEFAULT);
844
845 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
846 // First touch pointer down on right window
847 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
848 .pointer(PointerBuilder(0, ToolType::FINGER).x(100).y(100))
849 .build());
850 // Second touch pointer down
851 mDispatcher->notifyMotion(MotionArgsBuilder(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
852 .pointer(PointerBuilder(0, ToolType::FINGER).x(100).y(100))
853 .pointer(PointerBuilder(1, ToolType::FINGER).x(110).y(100))
854 .build());
855 // First touch pointer lifts. The second one remains down
856 mDispatcher->notifyMotion(MotionArgsBuilder(POINTER_0_UP, AINPUT_SOURCE_TOUCHSCREEN)
857 .pointer(PointerBuilder(0, ToolType::FINGER).x(100).y(100))
858 .pointer(PointerBuilder(1, ToolType::FINGER).x(110).y(100))
859 .build());
860 window->consumeMotionEvent(WithMotionAction(ACTION_DOWN));
861 window->consumeMotionEvent(WithMotionAction(POINTER_1_DOWN));
862 window->consumeMotionEvent(WithMotionAction(POINTER_0_UP));
863
864 // Remove the window. The gesture should be canceled
865 mDispatcher->onWindowInfosChanged({{}, {}, 0, 0});
866 const std::map<int32_t, PointF> expectedPointers{{1, PointF{110, 100}}};
867 window->consumeMotionEvent(
868 AllOf(WithMotionAction(ACTION_CANCEL), WithPointers(expectedPointers)));
869 }
870
871 /**
872 * Same test as WhenForegroundWindowDisappears_WallpaperTouchIsCanceled above,
873 * with the following differences:
874 * After ACTION_DOWN, Wallpaper window hangs up its channel, which forces the dispatcher to
875 * clean up the connection.
876 * This later may crash dispatcher during ACTION_CANCEL synthesis, if the dispatcher is not careful.
877 * Ensure that there's no crash in the dispatcher.
878 */
TEST_F(InputDispatcherTest,WhenWallpaperDisappears_NoCrash)879 TEST_F(InputDispatcherTest, WhenWallpaperDisappears_NoCrash) {
880 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
881 sp<FakeWindowHandle> foregroundWindow =
882 sp<FakeWindowHandle>::make(application, mDispatcher, "Foreground",
883 ui::LogicalDisplayId::DEFAULT);
884 foregroundWindow->setDupTouchToWallpaper(true);
885 sp<FakeWindowHandle> wallpaperWindow =
886 sp<FakeWindowHandle>::make(application, mDispatcher, "Wallpaper",
887 ui::LogicalDisplayId::DEFAULT);
888 wallpaperWindow->setIsWallpaper(true);
889
890 mDispatcher->onWindowInfosChanged(
891 {{*foregroundWindow->getInfo(), *wallpaperWindow->getInfo()}, {}, 0, 0});
892 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
893 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN,
894 ui::LogicalDisplayId::DEFAULT, {100, 200}))
895 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
896
897 // Both foreground window and its wallpaper should receive the touch down
898 foregroundWindow->consumeMotionDown();
899 wallpaperWindow->consumeMotionDown(ui::LogicalDisplayId::DEFAULT, EXPECTED_WALLPAPER_FLAGS);
900
901 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
902 injectMotionEvent(*mDispatcher, AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN,
903 ui::LogicalDisplayId::DEFAULT, {110, 200}))
904 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
905
906 foregroundWindow->consumeMotionMove();
907 wallpaperWindow->consumeMotionMove(ui::LogicalDisplayId::DEFAULT, EXPECTED_WALLPAPER_FLAGS);
908
909 // Wallpaper closes its channel, but the window remains.
910 wallpaperWindow->destroyReceiver();
911 mFakePolicy->assertNotifyInputChannelBrokenWasCalled(wallpaperWindow->getInfo()->token);
912
913 // Now the foreground window goes away, but the wallpaper stays, even though its channel
914 // is no longer valid.
915 mDispatcher->onWindowInfosChanged({{*wallpaperWindow->getInfo()}, {}, 0, 0});
916 foregroundWindow->consumeMotionCancel();
917 }
918
919 /**
920 * Two windows: left and right, and a separate wallpaper window underneath each. Device A sends a
921 * down event to the left window. Device B sends a down event to the right window. Next, the right
922 * window disappears. Both the right window and its wallpaper window should receive cancel event.
923 * The left window and its wallpaper window should not receive any events.
924 */
TEST_F(InputDispatcherTest,MultiDeviceDisappearingWindowWithWallpaperWindows)925 TEST_F(InputDispatcherTest, MultiDeviceDisappearingWindowWithWallpaperWindows) {
926 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
927 sp<FakeWindowHandle> leftForegroundWindow =
928 sp<FakeWindowHandle>::make(application, mDispatcher, "Left foreground window",
929 ui::LogicalDisplayId::DEFAULT);
930 leftForegroundWindow->setFrame(Rect(0, 0, 100, 100));
931 leftForegroundWindow->setDupTouchToWallpaper(true);
932 sp<FakeWindowHandle> leftWallpaperWindow =
933 sp<FakeWindowHandle>::make(application, mDispatcher, "Left wallpaper window",
934 ui::LogicalDisplayId::DEFAULT);
935 leftWallpaperWindow->setFrame(Rect(0, 0, 100, 100));
936 leftWallpaperWindow->setIsWallpaper(true);
937
938 sp<FakeWindowHandle> rightForegroundWindow =
939 sp<FakeWindowHandle>::make(application, mDispatcher, "Right foreground window",
940 ui::LogicalDisplayId::DEFAULT);
941 rightForegroundWindow->setFrame(Rect(100, 0, 200, 100));
942 rightForegroundWindow->setDupTouchToWallpaper(true);
943 sp<FakeWindowHandle> rightWallpaperWindow =
944 sp<FakeWindowHandle>::make(application, mDispatcher, "Right wallpaper window",
945 ui::LogicalDisplayId::DEFAULT);
946 rightWallpaperWindow->setFrame(Rect(100, 0, 200, 100));
947 rightWallpaperWindow->setIsWallpaper(true);
948
949 mDispatcher->onWindowInfosChanged(
950 {{*leftForegroundWindow->getInfo(), *leftWallpaperWindow->getInfo(),
951 *rightForegroundWindow->getInfo(), *rightWallpaperWindow->getInfo()},
952 {},
953 0,
954 0});
955
956 const DeviceId deviceA = 9;
957 const DeviceId deviceB = 3;
958 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
959 .pointer(PointerBuilder(0, ToolType::FINGER).x(50).y(50))
960 .deviceId(deviceA)
961 .build());
962 leftForegroundWindow->consumeMotionEvent(
963 AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(deviceA)));
964 leftWallpaperWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN),
965 WithDeviceId(deviceA),
966 WithFlags(EXPECTED_WALLPAPER_FLAGS)));
967
968 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
969 .pointer(PointerBuilder(0, ToolType::FINGER).x(150).y(50))
970 .deviceId(deviceB)
971 .build());
972 rightForegroundWindow->consumeMotionEvent(
973 AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(deviceB)));
974 rightWallpaperWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN),
975 WithDeviceId(deviceB),
976 WithFlags(EXPECTED_WALLPAPER_FLAGS)));
977
978 // Now right foreground window disappears, but right wallpaper window remains.
979 mDispatcher->onWindowInfosChanged(
980 {{*leftForegroundWindow->getInfo(), *leftWallpaperWindow->getInfo(),
981 *rightWallpaperWindow->getInfo()},
982 {},
983 0,
984 0});
985
986 // Left foreground window and left wallpaper window still exist, and should not receive any
987 // events.
988 leftForegroundWindow->assertNoEvents();
989 leftWallpaperWindow->assertNoEvents();
990 // Since right foreground window disappeared, right wallpaper window and right foreground window
991 // should receive cancel events.
992 rightForegroundWindow->consumeMotionEvent(
993 AllOf(WithMotionAction(ACTION_CANCEL), WithDeviceId(deviceB)));
994 rightWallpaperWindow->consumeMotionEvent(
995 AllOf(WithMotionAction(ACTION_CANCEL), WithDeviceId(deviceB),
996 WithFlags(EXPECTED_WALLPAPER_FLAGS | AMOTION_EVENT_FLAG_CANCELED)));
997 }
998
999 /**
1000 * Three windows arranged horizontally and without any overlap. Every window has a
1001 * wallpaper window underneath. The middle window also has SLIPPERY flag.
1002 * Device A sends a down event to the left window. Device B sends a down event to the middle window.
1003 * Next, device B sends move event to the right window. Touch for device B should slip from the
1004 * middle window to the right window. Also, the right wallpaper window should receive a down event.
1005 * The middle window and its wallpaper window should receive a cancel event. The left window should
1006 * not receive any events. If device B continues to report events, the right window and its
1007 * wallpaper window should receive remaining events.
1008 */
TEST_F(InputDispatcherTest,MultiDeviceSlipperyTouchWithWallpaperWindow)1009 TEST_F(InputDispatcherTest, MultiDeviceSlipperyTouchWithWallpaperWindow) {
1010 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
1011 sp<FakeWindowHandle> leftForegroundWindow =
1012 sp<FakeWindowHandle>::make(application, mDispatcher, "Left foreground window",
1013 ui::LogicalDisplayId::DEFAULT);
1014 leftForegroundWindow->setFrame(Rect(0, 0, 100, 100));
1015 leftForegroundWindow->setDupTouchToWallpaper(true);
1016 sp<FakeWindowHandle> leftWallpaperWindow =
1017 sp<FakeWindowHandle>::make(application, mDispatcher, "Left wallpaper window",
1018 ui::LogicalDisplayId::DEFAULT);
1019 leftWallpaperWindow->setFrame(Rect(0, 0, 100, 100));
1020 leftWallpaperWindow->setIsWallpaper(true);
1021
1022 sp<FakeWindowHandle> middleForegroundWindow =
1023 sp<FakeWindowHandle>::make(application, mDispatcher, "Middle foreground window",
1024 ui::LogicalDisplayId::DEFAULT);
1025 middleForegroundWindow->setFrame(Rect(100, 0, 200, 100));
1026 middleForegroundWindow->setDupTouchToWallpaper(true);
1027 middleForegroundWindow->setSlippery(true);
1028 sp<FakeWindowHandle> middleWallpaperWindow =
1029 sp<FakeWindowHandle>::make(application, mDispatcher, "Middle wallpaper window",
1030 ui::LogicalDisplayId::DEFAULT);
1031 middleWallpaperWindow->setFrame(Rect(100, 0, 200, 100));
1032 middleWallpaperWindow->setIsWallpaper(true);
1033
1034 sp<FakeWindowHandle> rightForegroundWindow =
1035 sp<FakeWindowHandle>::make(application, mDispatcher, "Right foreground window",
1036 ui::LogicalDisplayId::DEFAULT);
1037 rightForegroundWindow->setFrame(Rect(200, 0, 300, 100));
1038 rightForegroundWindow->setDupTouchToWallpaper(true);
1039 sp<FakeWindowHandle> rightWallpaperWindow =
1040 sp<FakeWindowHandle>::make(application, mDispatcher, "Right wallpaper window",
1041 ui::LogicalDisplayId::DEFAULT);
1042 rightWallpaperWindow->setFrame(Rect(200, 0, 300, 100));
1043 rightWallpaperWindow->setIsWallpaper(true);
1044
1045 mDispatcher->onWindowInfosChanged(
1046 {{*leftForegroundWindow->getInfo(), *leftWallpaperWindow->getInfo(),
1047 *middleForegroundWindow->getInfo(), *middleWallpaperWindow->getInfo(),
1048 *rightForegroundWindow->getInfo(), *rightWallpaperWindow->getInfo()},
1049 {},
1050 0,
1051 0});
1052
1053 const DeviceId deviceA = 9;
1054 const DeviceId deviceB = 3;
1055 // Device A sends a DOWN event to the left window
1056 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
1057 .pointer(PointerBuilder(0, ToolType::FINGER).x(50).y(50))
1058 .deviceId(deviceA)
1059 .build());
1060 leftForegroundWindow->consumeMotionEvent(
1061 AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(deviceA)));
1062 leftWallpaperWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN),
1063 WithDeviceId(deviceA),
1064 WithFlags(EXPECTED_WALLPAPER_FLAGS)));
1065 // Device B sends a DOWN event to the middle window
1066 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
1067 .pointer(PointerBuilder(0, ToolType::FINGER).x(150).y(50))
1068 .deviceId(deviceB)
1069 .build());
1070 middleForegroundWindow->consumeMotionEvent(
1071 AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(deviceB)));
1072 middleWallpaperWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN),
1073 WithDeviceId(deviceB),
1074 WithFlags(EXPECTED_WALLPAPER_FLAGS)));
1075 // Move the events of device B to the top of the right window.
1076 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN)
1077 .pointer(PointerBuilder(0, ToolType::FINGER).x(250).y(50))
1078 .deviceId(deviceB)
1079 .build());
1080 middleForegroundWindow->consumeMotionEvent(
1081 AllOf(WithMotionAction(ACTION_CANCEL), WithDeviceId(deviceB)));
1082 middleWallpaperWindow->consumeMotionEvent(
1083 AllOf(WithMotionAction(ACTION_CANCEL), WithDeviceId(deviceB),
1084 WithFlags(EXPECTED_WALLPAPER_FLAGS | AMOTION_EVENT_FLAG_CANCELED)));
1085 rightForegroundWindow->consumeMotionEvent(
1086 AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(deviceB)));
1087 rightWallpaperWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN),
1088 WithDeviceId(deviceB),
1089 WithFlags(EXPECTED_WALLPAPER_FLAGS)));
1090 // Make sure the window on the right can receive the remaining events.
1091 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN)
1092 .pointer(PointerBuilder(0, ToolType::FINGER).x(251).y(51))
1093 .deviceId(deviceB)
1094 .build());
1095 leftForegroundWindow->assertNoEvents();
1096 leftWallpaperWindow->assertNoEvents();
1097 middleForegroundWindow->assertNoEvents();
1098 middleWallpaperWindow->assertNoEvents();
1099 rightForegroundWindow->consumeMotionEvent(
1100 AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(deviceB)));
1101 rightWallpaperWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_MOVE),
1102 WithDeviceId(deviceB),
1103 WithFlags(EXPECTED_WALLPAPER_FLAGS)));
1104 }
1105
1106 /**
1107 * Similar to the test above, we have three windows, they are arranged horizontally and without any
1108 * overlap, and every window has a wallpaper window. The middle window is a simple window, without
1109 * any special flags. Device A reports a down event that lands in left window. Device B sends a down
1110 * event to the middle window and then touch is transferred from the middle window to the right
1111 * window. The right window and its wallpaper window should receive a down event. The middle window
1112 * and its wallpaper window should receive a cancel event. The left window should not receive any
1113 * events. Subsequent events reported by device B should go to the right window and its wallpaper.
1114 */
TEST_F(InputDispatcherTest,MultiDeviceTouchTransferWithWallpaperWindows)1115 TEST_F(InputDispatcherTest, MultiDeviceTouchTransferWithWallpaperWindows) {
1116 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
1117 sp<FakeWindowHandle> leftForegroundWindow =
1118 sp<FakeWindowHandle>::make(application, mDispatcher, "Left foreground window",
1119 ui::LogicalDisplayId::DEFAULT);
1120 leftForegroundWindow->setFrame(Rect(0, 0, 100, 100));
1121 leftForegroundWindow->setDupTouchToWallpaper(true);
1122 sp<FakeWindowHandle> leftWallpaperWindow =
1123 sp<FakeWindowHandle>::make(application, mDispatcher, "Left wallpaper window",
1124 ui::LogicalDisplayId::DEFAULT);
1125 leftWallpaperWindow->setFrame(Rect(0, 0, 100, 100));
1126 leftWallpaperWindow->setIsWallpaper(true);
1127
1128 sp<FakeWindowHandle> middleForegroundWindow =
1129 sp<FakeWindowHandle>::make(application, mDispatcher, "Middle foreground window",
1130 ui::LogicalDisplayId::DEFAULT);
1131 middleForegroundWindow->setFrame(Rect(100, 0, 200, 100));
1132 middleForegroundWindow->setDupTouchToWallpaper(true);
1133 sp<FakeWindowHandle> middleWallpaperWindow =
1134 sp<FakeWindowHandle>::make(application, mDispatcher, "Middle wallpaper window",
1135 ui::LogicalDisplayId::DEFAULT);
1136 middleWallpaperWindow->setFrame(Rect(100, 0, 200, 100));
1137 middleWallpaperWindow->setIsWallpaper(true);
1138
1139 sp<FakeWindowHandle> rightForegroundWindow =
1140 sp<FakeWindowHandle>::make(application, mDispatcher, "Right foreground window",
1141 ui::LogicalDisplayId::DEFAULT);
1142 rightForegroundWindow->setFrame(Rect(200, 0, 300, 100));
1143 rightForegroundWindow->setDupTouchToWallpaper(true);
1144 sp<FakeWindowHandle> rightWallpaperWindow =
1145 sp<FakeWindowHandle>::make(application, mDispatcher, "Right wallpaper window",
1146 ui::LogicalDisplayId::DEFAULT);
1147 rightWallpaperWindow->setFrame(Rect(200, 0, 300, 100));
1148 rightWallpaperWindow->setIsWallpaper(true);
1149
1150 mDispatcher->onWindowInfosChanged(
1151 {{*leftForegroundWindow->getInfo(), *leftWallpaperWindow->getInfo(),
1152 *middleForegroundWindow->getInfo(), *middleWallpaperWindow->getInfo(),
1153 *rightForegroundWindow->getInfo(), *rightWallpaperWindow->getInfo()},
1154 {},
1155 0,
1156 0});
1157
1158 const DeviceId deviceA = 9;
1159 const DeviceId deviceB = 3;
1160 // Device A touch down on the left window
1161 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
1162 .pointer(PointerBuilder(0, ToolType::FINGER).x(50).y(50))
1163 .deviceId(deviceA)
1164 .build());
1165 leftForegroundWindow->consumeMotionEvent(
1166 AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(deviceA)));
1167 leftWallpaperWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN),
1168 WithDeviceId(deviceA),
1169 WithFlags(EXPECTED_WALLPAPER_FLAGS)));
1170 // Device B touch down on the middle window
1171 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
1172 .pointer(PointerBuilder(0, ToolType::FINGER).x(150).y(50))
1173 .deviceId(deviceB)
1174 .build());
1175 middleForegroundWindow->consumeMotionEvent(
1176 AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(deviceB)));
1177 middleWallpaperWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN),
1178 WithDeviceId(deviceB),
1179 WithFlags(EXPECTED_WALLPAPER_FLAGS)));
1180
1181 // Transfer touch from the middle window to the right window.
1182 ASSERT_TRUE(mDispatcher->transferTouchGesture(middleForegroundWindow->getToken(),
1183 rightForegroundWindow->getToken()));
1184
1185 middleForegroundWindow->consumeMotionEvent(
1186 AllOf(WithMotionAction(ACTION_CANCEL), WithDeviceId(deviceB)));
1187 middleWallpaperWindow->consumeMotionEvent(
1188 AllOf(WithMotionAction(ACTION_CANCEL), WithDeviceId(deviceB),
1189 WithFlags(EXPECTED_WALLPAPER_FLAGS | AMOTION_EVENT_FLAG_CANCELED)));
1190 rightForegroundWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN),
1191 WithDeviceId(deviceB),
1192 WithFlags(AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE)));
1193 rightWallpaperWindow->consumeMotionEvent(
1194 AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(deviceB),
1195 WithFlags(EXPECTED_WALLPAPER_FLAGS | AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE)));
1196
1197 // Make sure the right window can receive the remaining events.
1198 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN)
1199 .pointer(PointerBuilder(0, ToolType::FINGER).x(251).y(51))
1200 .deviceId(deviceB)
1201 .build());
1202 leftForegroundWindow->assertNoEvents();
1203 leftWallpaperWindow->assertNoEvents();
1204 middleForegroundWindow->assertNoEvents();
1205 middleWallpaperWindow->assertNoEvents();
1206 rightForegroundWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_MOVE),
1207 WithDeviceId(deviceB),
1208 WithFlags(AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE)));
1209 rightWallpaperWindow->consumeMotionEvent(
1210 AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(deviceB),
1211 WithFlags(EXPECTED_WALLPAPER_FLAGS | AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE)));
1212 }
1213
1214 class ShouldSplitTouchFixture : public InputDispatcherTest,
1215 public ::testing::WithParamInterface<bool> {};
1216 INSTANTIATE_TEST_SUITE_P(InputDispatcherTest, ShouldSplitTouchFixture,
1217 ::testing::Values(true, false));
1218 /**
1219 * A single window that receives touch (on top), and a wallpaper window underneath it.
1220 * The top window gets a multitouch gesture.
1221 * Ensure that wallpaper gets the same gesture.
1222 */
TEST_P(ShouldSplitTouchFixture,WallpaperWindowReceivesMultiTouch)1223 TEST_P(ShouldSplitTouchFixture, WallpaperWindowReceivesMultiTouch) {
1224 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
1225 sp<FakeWindowHandle> foregroundWindow =
1226 sp<FakeWindowHandle>::make(application, mDispatcher, "Foreground",
1227 ui::LogicalDisplayId::DEFAULT);
1228 foregroundWindow->setDupTouchToWallpaper(true);
1229 foregroundWindow->setPreventSplitting(GetParam());
1230
1231 sp<FakeWindowHandle> wallpaperWindow =
1232 sp<FakeWindowHandle>::make(application, mDispatcher, "Wallpaper",
1233 ui::LogicalDisplayId::DEFAULT);
1234 wallpaperWindow->setIsWallpaper(true);
1235
1236 mDispatcher->onWindowInfosChanged(
1237 {{*foregroundWindow->getInfo(), *wallpaperWindow->getInfo()}, {}, 0, 0});
1238
1239 // Touch down on top window
1240 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
1241 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN,
1242 ui::LogicalDisplayId::DEFAULT, {100, 100}))
1243 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
1244
1245 // Both top window and its wallpaper should receive the touch down
1246 foregroundWindow->consumeMotionDown();
1247 wallpaperWindow->consumeMotionDown(ui::LogicalDisplayId::DEFAULT, EXPECTED_WALLPAPER_FLAGS);
1248
1249 // Second finger down on the top window
1250 const MotionEvent secondFingerDownEvent =
1251 MotionEventBuilder(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
1252 .eventTime(systemTime(SYSTEM_TIME_MONOTONIC))
1253 .pointer(PointerBuilder(/*id=*/0, ToolType::FINGER).x(100).y(100))
1254 .pointer(PointerBuilder(/*id=*/1, ToolType::FINGER).x(150).y(150))
1255 .build();
1256 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
1257 injectMotionEvent(*mDispatcher, secondFingerDownEvent, INJECT_EVENT_TIMEOUT,
1258 InputEventInjectionSync::WAIT_FOR_RESULT))
1259 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
1260 foregroundWindow->consumeMotionPointerDown(/*pointerIndex=*/1);
1261 wallpaperWindow->consumeMotionPointerDown(/*pointerIndex=*/1, ui::LogicalDisplayId::DEFAULT,
1262 EXPECTED_WALLPAPER_FLAGS);
1263
1264 const MotionEvent secondFingerUpEvent =
1265 MotionEventBuilder(POINTER_0_UP, AINPUT_SOURCE_TOUCHSCREEN)
1266 .displayId(ui::LogicalDisplayId::DEFAULT)
1267 .eventTime(systemTime(SYSTEM_TIME_MONOTONIC))
1268 .pointer(PointerBuilder(/*id=*/0, ToolType::FINGER).x(100).y(100))
1269 .pointer(PointerBuilder(/*id=*/1, ToolType::FINGER).x(150).y(150))
1270 .build();
1271 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
1272 injectMotionEvent(*mDispatcher, secondFingerUpEvent, INJECT_EVENT_TIMEOUT,
1273 InputEventInjectionSync::WAIT_FOR_RESULT))
1274 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
1275 foregroundWindow->consumeMotionPointerUp(/*pointerIdx=*/0,
1276 WithDisplayId(ui::LogicalDisplayId::DEFAULT));
1277 wallpaperWindow->consumeMotionPointerUp(/*pointerIdx=*/0,
1278 AllOf(WithDisplayId(ui::LogicalDisplayId::DEFAULT),
1279 WithFlags(EXPECTED_WALLPAPER_FLAGS)));
1280
1281 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
1282 injectMotionEvent(*mDispatcher,
1283 MotionEventBuilder(AMOTION_EVENT_ACTION_UP,
1284 AINPUT_SOURCE_TOUCHSCREEN)
1285 .displayId(ui::LogicalDisplayId::DEFAULT)
1286 .eventTime(systemTime(SYSTEM_TIME_MONOTONIC))
1287 .pointer(PointerBuilder(/*id=*/1, ToolType::FINGER)
1288 .x(100)
1289 .y(100))
1290 .build(),
1291 INJECT_EVENT_TIMEOUT, InputEventInjectionSync::WAIT_FOR_RESULT))
1292 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
1293 foregroundWindow->consumeMotionUp(ui::LogicalDisplayId::DEFAULT);
1294 wallpaperWindow->consumeMotionUp(ui::LogicalDisplayId::DEFAULT, EXPECTED_WALLPAPER_FLAGS);
1295 }
1296
1297 /**
1298 * Two windows: a window on the left and window on the right.
1299 * A third window, wallpaper, is behind both windows, and spans both top windows.
1300 * The first touch down goes to the left window. A second pointer touches down on the right window.
1301 * The touch is split, so both left and right windows should receive ACTION_DOWN.
1302 * The wallpaper will get the full event, so it should receive ACTION_DOWN followed by
1303 * ACTION_POINTER_DOWN(1).
1304 */
TEST_F(InputDispatcherTest,TwoWindows_SplitWallpaperTouch)1305 TEST_F(InputDispatcherTest, TwoWindows_SplitWallpaperTouch) {
1306 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
1307 sp<FakeWindowHandle> leftWindow = sp<FakeWindowHandle>::make(application, mDispatcher, "Left",
1308 ui::LogicalDisplayId::DEFAULT);
1309 leftWindow->setFrame(Rect(0, 0, 200, 200));
1310 leftWindow->setDupTouchToWallpaper(true);
1311
1312 sp<FakeWindowHandle> rightWindow = sp<FakeWindowHandle>::make(application, mDispatcher, "Right",
1313 ui::LogicalDisplayId::DEFAULT);
1314 rightWindow->setFrame(Rect(200, 0, 400, 200));
1315 rightWindow->setDupTouchToWallpaper(true);
1316
1317 sp<FakeWindowHandle> wallpaperWindow =
1318 sp<FakeWindowHandle>::make(application, mDispatcher, "Wallpaper",
1319 ui::LogicalDisplayId::DEFAULT);
1320 wallpaperWindow->setFrame(Rect(0, 0, 400, 200));
1321 wallpaperWindow->setIsWallpaper(true);
1322
1323 mDispatcher->onWindowInfosChanged(
1324 {{*leftWindow->getInfo(), *rightWindow->getInfo(), *wallpaperWindow->getInfo()},
1325 {},
1326 0,
1327 0});
1328
1329 // Touch down on left window
1330 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
1331 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN,
1332 ui::LogicalDisplayId::DEFAULT, {100, 100}))
1333 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
1334
1335 // Both foreground window and its wallpaper should receive the touch down
1336 leftWindow->consumeMotionDown();
1337 wallpaperWindow->consumeMotionDown(ui::LogicalDisplayId::DEFAULT, EXPECTED_WALLPAPER_FLAGS);
1338
1339 // Second finger down on the right window
1340 const MotionEvent secondFingerDownEvent =
1341 MotionEventBuilder(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
1342 .eventTime(systemTime(SYSTEM_TIME_MONOTONIC))
1343 .pointer(PointerBuilder(/*id=*/0, ToolType::FINGER).x(100).y(100))
1344 .pointer(PointerBuilder(/*id=*/1, ToolType::FINGER).x(300).y(100))
1345 .build();
1346 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
1347 injectMotionEvent(*mDispatcher, secondFingerDownEvent, INJECT_EVENT_TIMEOUT,
1348 InputEventInjectionSync::WAIT_FOR_RESULT))
1349 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
1350
1351 leftWindow->consumeMotionMove();
1352 // Since the touch is split, right window gets ACTION_DOWN
1353 rightWindow->consumeMotionDown(ui::LogicalDisplayId::DEFAULT);
1354 wallpaperWindow->consumeMotionPointerDown(/*pointerIndex=*/1, ui::LogicalDisplayId::DEFAULT,
1355 EXPECTED_WALLPAPER_FLAGS);
1356
1357 // Now, leftWindow, which received the first finger, disappears.
1358 mDispatcher->onWindowInfosChanged(
1359 {{*rightWindow->getInfo(), *wallpaperWindow->getInfo()}, {}, 0, 0});
1360 leftWindow->consumeMotionCancel();
1361 // Since a "parent" window of the wallpaper is gone, wallpaper should receive cancel, too.
1362 wallpaperWindow->consumeMotionCancel(ui::LogicalDisplayId::DEFAULT, EXPECTED_WALLPAPER_FLAGS);
1363
1364 // The pointer that's still down on the right window moves, and goes to the right window only.
1365 // As far as the dispatcher's concerned though, both pointers are still present.
1366 const MotionEvent secondFingerMoveEvent =
1367 MotionEventBuilder(AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN)
1368 .eventTime(systemTime(SYSTEM_TIME_MONOTONIC))
1369 .pointer(PointerBuilder(/*id=*/0, ToolType::FINGER).x(100).y(100))
1370 .pointer(PointerBuilder(/*id=*/1, ToolType::FINGER).x(310).y(110))
1371 .build();
1372 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
1373 injectMotionEvent(*mDispatcher, secondFingerMoveEvent, INJECT_EVENT_TIMEOUT,
1374 InputEventInjectionSync::WAIT_FOR_RESULT));
1375 rightWindow->consumeMotionMove();
1376
1377 leftWindow->assertNoEvents();
1378 rightWindow->assertNoEvents();
1379 wallpaperWindow->assertNoEvents();
1380 }
1381
1382 /**
1383 * Two windows: a window on the left with dup touch to wallpaper and window on the right without it.
1384 * The touch slips to the right window. so left window and wallpaper should receive ACTION_CANCEL
1385 * The right window should receive ACTION_DOWN.
1386 */
TEST_F(InputDispatcherTest,WallpaperWindowWhenSlippery)1387 TEST_F(InputDispatcherTest, WallpaperWindowWhenSlippery) {
1388 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
1389 sp<FakeWindowHandle> leftWindow = sp<FakeWindowHandle>::make(application, mDispatcher, "Left",
1390 ui::LogicalDisplayId::DEFAULT);
1391 leftWindow->setFrame(Rect(0, 0, 200, 200));
1392 leftWindow->setDupTouchToWallpaper(true);
1393 leftWindow->setSlippery(true);
1394
1395 sp<FakeWindowHandle> rightWindow = sp<FakeWindowHandle>::make(application, mDispatcher, "Right",
1396 ui::LogicalDisplayId::DEFAULT);
1397 rightWindow->setFrame(Rect(200, 0, 400, 200));
1398
1399 sp<FakeWindowHandle> wallpaperWindow =
1400 sp<FakeWindowHandle>::make(application, mDispatcher, "Wallpaper",
1401 ui::LogicalDisplayId::DEFAULT);
1402 wallpaperWindow->setIsWallpaper(true);
1403
1404 mDispatcher->onWindowInfosChanged(
1405 {{*leftWindow->getInfo(), *rightWindow->getInfo(), *wallpaperWindow->getInfo()},
1406 {},
1407 0,
1408 0});
1409
1410 // Touch down on left window
1411 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
1412 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN,
1413 ui::LogicalDisplayId::DEFAULT, {100, 100}))
1414 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
1415
1416 // Both foreground window and its wallpaper should receive the touch down
1417 leftWindow->consumeMotionDown();
1418 wallpaperWindow->consumeMotionDown(ui::LogicalDisplayId::DEFAULT, EXPECTED_WALLPAPER_FLAGS);
1419
1420 // Move to right window, the left window should receive cancel.
1421 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
1422 injectMotionEvent(*mDispatcher, AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN,
1423 ui::LogicalDisplayId::DEFAULT, {201, 100}))
1424 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
1425
1426 leftWindow->consumeMotionCancel();
1427 rightWindow->consumeMotionDown(ui::LogicalDisplayId::DEFAULT);
1428 wallpaperWindow->consumeMotionCancel(ui::LogicalDisplayId::DEFAULT, EXPECTED_WALLPAPER_FLAGS);
1429 }
1430
1431 /**
1432 * The policy typically sets POLICY_FLAG_PASS_TO_USER to the events. But when the display is not
1433 * interactive, it might stop sending this flag.
1434 * In this test, we check that if the policy stops sending this flag mid-gesture, we still ensure
1435 * to have a consistent input stream.
1436 *
1437 * Test procedure:
1438 * DOWN -> POINTER_DOWN -> (stop sending POLICY_FLAG_PASS_TO_USER) -> CANCEL.
1439 * DOWN (new gesture).
1440 *
1441 * In the bad implementation, we could potentially drop the CANCEL event, and get an inconsistent
1442 * state in the dispatcher. This would cause the final DOWN event to not be delivered to the app.
1443 *
1444 * We technically just need a single window here, but we are using two windows (spy on top and a
1445 * regular window below) to emulate the actual situation where it happens on the device.
1446 */
TEST_F(InputDispatcherTest,TwoPointerCancelInconsistentPolicy)1447 TEST_F(InputDispatcherTest, TwoPointerCancelInconsistentPolicy) {
1448 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
1449 sp<FakeWindowHandle> spyWindow = sp<FakeWindowHandle>::make(application, mDispatcher, "Spy",
1450 ui::LogicalDisplayId::DEFAULT);
1451 spyWindow->setFrame(Rect(0, 0, 200, 200));
1452 spyWindow->setTrustedOverlay(true);
1453 spyWindow->setSpy(true);
1454
1455 sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher, "Window",
1456 ui::LogicalDisplayId::DEFAULT);
1457 window->setFrame(Rect(0, 0, 200, 200));
1458
1459 mDispatcher->onWindowInfosChanged({{*spyWindow->getInfo(), *window->getInfo()}, {}, 0, 0});
1460 const int32_t touchDeviceId = 4;
1461
1462 // Two pointers down
1463 mDispatcher->notifyMotion(
1464 MotionArgsBuilder(AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
1465 .deviceId(touchDeviceId)
1466 .policyFlags(DEFAULT_POLICY_FLAGS)
1467 .pointer(PointerBuilder(0, ToolType::FINGER).x(100).y(100))
1468 .build());
1469
1470 mDispatcher->notifyMotion(MotionArgsBuilder(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
1471 .deviceId(touchDeviceId)
1472 .policyFlags(DEFAULT_POLICY_FLAGS)
1473 .pointer(PointerBuilder(0, ToolType::FINGER).x(100).y(100))
1474 .pointer(PointerBuilder(1, ToolType::FINGER).x(120).y(120))
1475 .build());
1476 spyWindow->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_DOWN));
1477 spyWindow->consumeMotionEvent(WithMotionAction(POINTER_1_DOWN));
1478 window->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_DOWN));
1479 window->consumeMotionEvent(WithMotionAction(POINTER_1_DOWN));
1480
1481 // Cancel the current gesture. Send the cancel without the default policy flags.
1482 mDispatcher->notifyMotion(
1483 MotionArgsBuilder(AMOTION_EVENT_ACTION_CANCEL, AINPUT_SOURCE_TOUCHSCREEN)
1484 .deviceId(touchDeviceId)
1485 .policyFlags(0)
1486 .pointer(PointerBuilder(0, ToolType::FINGER).x(100).y(100))
1487 .pointer(PointerBuilder(1, ToolType::FINGER).x(120).y(120))
1488 .build());
1489 spyWindow->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_CANCEL));
1490 window->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_CANCEL));
1491
1492 // We don't need to reset the device to reproduce the issue, but the reset event typically
1493 // follows, so we keep it here to model the actual listener behaviour more closely.
1494 mDispatcher->notifyDeviceReset({/*id=*/1, systemTime(SYSTEM_TIME_MONOTONIC), touchDeviceId});
1495
1496 // Start new gesture
1497 mDispatcher->notifyMotion(
1498 MotionArgsBuilder(AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
1499 .deviceId(touchDeviceId)
1500 .policyFlags(DEFAULT_POLICY_FLAGS)
1501 .pointer(PointerBuilder(0, ToolType::FINGER).x(100).y(100))
1502 .build());
1503 spyWindow->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_DOWN));
1504 window->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_DOWN));
1505
1506 // No more events
1507 spyWindow->assertNoEvents();
1508 window->assertNoEvents();
1509 }
1510
1511 /**
1512 * Same as the above 'TwoPointerCancelInconsistentPolicy' test, but for hovers.
1513 * The policy typically sets POLICY_FLAG_PASS_TO_USER to the events. But when the display is not
1514 * interactive, it might stop sending this flag.
1515 * We've already ensured the consistency of the touch event in this case, and we should also ensure
1516 * the consistency of the hover event in this case.
1517 *
1518 * Test procedure:
1519 * HOVER_ENTER -> HOVER_MOVE -> (stop sending POLICY_FLAG_PASS_TO_USER) -> HOVER_EXIT
1520 * HOVER_ENTER -> HOVER_MOVE -> HOVER_EXIT
1521 *
1522 * We expect to receive two full streams of hover events.
1523 */
TEST_F(InputDispatcherTest,HoverEventInconsistentPolicy)1524 TEST_F(InputDispatcherTest, HoverEventInconsistentPolicy) {
1525 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
1526
1527 sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher, "Window",
1528 ui::LogicalDisplayId::DEFAULT);
1529 window->setFrame(Rect(0, 0, 300, 300));
1530
1531 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
1532
1533 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_ENTER, AINPUT_SOURCE_STYLUS)
1534 .policyFlags(DEFAULT_POLICY_FLAGS)
1535 .pointer(PointerBuilder(0, ToolType::STYLUS).x(100).y(101))
1536 .build());
1537 window->consumeMotionEvent(WithMotionAction(ACTION_HOVER_ENTER));
1538
1539 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_MOVE, AINPUT_SOURCE_STYLUS)
1540 .policyFlags(DEFAULT_POLICY_FLAGS)
1541 .pointer(PointerBuilder(0, ToolType::STYLUS).x(101).y(102))
1542 .build());
1543 window->consumeMotionEvent(WithMotionAction(ACTION_HOVER_MOVE));
1544
1545 // Send hover exit without the default policy flags.
1546 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_EXIT, AINPUT_SOURCE_STYLUS)
1547 .policyFlags(0)
1548 .pointer(PointerBuilder(0, ToolType::STYLUS).x(101).y(102))
1549 .build());
1550
1551 window->consumeMotionEvent(WithMotionAction(ACTION_HOVER_EXIT));
1552
1553 // Send a simple hover event stream, ensure dispatcher not crashed and window can receive
1554 // right event.
1555 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_ENTER, AINPUT_SOURCE_STYLUS)
1556 .policyFlags(DEFAULT_POLICY_FLAGS)
1557 .pointer(PointerBuilder(0, ToolType::STYLUS).x(200).y(201))
1558 .build());
1559 window->consumeMotionEvent(WithMotionAction(ACTION_HOVER_ENTER));
1560
1561 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_MOVE, AINPUT_SOURCE_STYLUS)
1562 .policyFlags(DEFAULT_POLICY_FLAGS)
1563 .pointer(PointerBuilder(0, ToolType::STYLUS).x(201).y(202))
1564 .build());
1565 window->consumeMotionEvent(WithMotionAction(ACTION_HOVER_MOVE));
1566
1567 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_EXIT, AINPUT_SOURCE_STYLUS)
1568 .policyFlags(DEFAULT_POLICY_FLAGS)
1569 .pointer(PointerBuilder(0, ToolType::STYLUS).x(201).y(202))
1570 .build());
1571 window->consumeMotionEvent(WithMotionAction(ACTION_HOVER_EXIT));
1572 }
1573
1574 /**
1575 * Two windows: a window on the left and a window on the right.
1576 * Mouse is hovered from the right window into the left window.
1577 * Next, we tap on the left window, where the cursor was last seen.
1578 * The second tap is done onto the right window.
1579 * The mouse and tap are from two different devices.
1580 * We technically don't need to set the downtime / eventtime for these events, but setting these
1581 * explicitly helps during debugging.
1582 * This test reproduces a crash where there is a mismatch between the downTime and eventTime.
1583 * In the buggy implementation, a tap on the right window would cause a crash.
1584 */
TEST_F(InputDispatcherTest,HoverFromLeftToRightAndTap_legacy)1585 TEST_F(InputDispatcherTest, HoverFromLeftToRightAndTap_legacy) {
1586 SCOPED_FLAG_OVERRIDE(enable_multi_device_same_window_stream, false);
1587
1588 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
1589 sp<FakeWindowHandle> leftWindow = sp<FakeWindowHandle>::make(application, mDispatcher, "Left",
1590 ui::LogicalDisplayId::DEFAULT);
1591 leftWindow->setFrame(Rect(0, 0, 200, 200));
1592
1593 sp<FakeWindowHandle> rightWindow = sp<FakeWindowHandle>::make(application, mDispatcher, "Right",
1594 ui::LogicalDisplayId::DEFAULT);
1595 rightWindow->setFrame(Rect(200, 0, 400, 200));
1596
1597 mDispatcher->onWindowInfosChanged(
1598 {{*leftWindow->getInfo(), *rightWindow->getInfo()}, {}, 0, 0});
1599 // All times need to start at the current time, otherwise the dispatcher will drop the events as
1600 // stale.
1601 const nsecs_t baseTime = systemTime(SYSTEM_TIME_MONOTONIC);
1602 const int32_t mouseDeviceId = 6;
1603 const int32_t touchDeviceId = 4;
1604 // Move the cursor from right
1605 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
1606 injectMotionEvent(*mDispatcher,
1607 MotionEventBuilder(AMOTION_EVENT_ACTION_HOVER_MOVE,
1608 AINPUT_SOURCE_MOUSE)
1609 .deviceId(mouseDeviceId)
1610 .downTime(baseTime + 10)
1611 .eventTime(baseTime + 20)
1612 .pointer(PointerBuilder(0, ToolType::MOUSE).x(300).y(100))
1613 .build()));
1614 rightWindow->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_ENTER));
1615
1616 // .. to the left window
1617 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
1618 injectMotionEvent(*mDispatcher,
1619 MotionEventBuilder(AMOTION_EVENT_ACTION_HOVER_MOVE,
1620 AINPUT_SOURCE_MOUSE)
1621 .deviceId(mouseDeviceId)
1622 .downTime(baseTime + 10)
1623 .eventTime(baseTime + 30)
1624 .pointer(PointerBuilder(0, ToolType::MOUSE).x(110).y(100))
1625 .build()));
1626 rightWindow->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_EXIT));
1627 leftWindow->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_ENTER));
1628 // Now tap the left window
1629 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
1630 injectMotionEvent(*mDispatcher,
1631 MotionEventBuilder(AMOTION_EVENT_ACTION_DOWN,
1632 AINPUT_SOURCE_TOUCHSCREEN)
1633 .deviceId(touchDeviceId)
1634 .downTime(baseTime + 40)
1635 .eventTime(baseTime + 40)
1636 .pointer(PointerBuilder(0, ToolType::FINGER).x(100).y(100))
1637 .build()));
1638 leftWindow->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_EXIT));
1639 leftWindow->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_DOWN));
1640
1641 // release tap
1642 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
1643 injectMotionEvent(*mDispatcher,
1644 MotionEventBuilder(AMOTION_EVENT_ACTION_UP,
1645 AINPUT_SOURCE_TOUCHSCREEN)
1646 .deviceId(touchDeviceId)
1647 .downTime(baseTime + 40)
1648 .eventTime(baseTime + 50)
1649 .pointer(PointerBuilder(0, ToolType::FINGER).x(100).y(100))
1650 .build()));
1651 leftWindow->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_UP));
1652
1653 // Tap the window on the right
1654 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
1655 injectMotionEvent(*mDispatcher,
1656 MotionEventBuilder(AMOTION_EVENT_ACTION_DOWN,
1657 AINPUT_SOURCE_TOUCHSCREEN)
1658 .deviceId(touchDeviceId)
1659 .downTime(baseTime + 60)
1660 .eventTime(baseTime + 60)
1661 .pointer(PointerBuilder(0, ToolType::FINGER).x(300).y(100))
1662 .build()));
1663 rightWindow->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_DOWN));
1664
1665 // release tap
1666 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
1667 injectMotionEvent(*mDispatcher,
1668 MotionEventBuilder(AMOTION_EVENT_ACTION_UP,
1669 AINPUT_SOURCE_TOUCHSCREEN)
1670 .deviceId(touchDeviceId)
1671 .downTime(baseTime + 60)
1672 .eventTime(baseTime + 70)
1673 .pointer(PointerBuilder(0, ToolType::FINGER).x(300).y(100))
1674 .build()));
1675 rightWindow->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_UP));
1676
1677 // No more events
1678 leftWindow->assertNoEvents();
1679 rightWindow->assertNoEvents();
1680 }
1681
1682 /**
1683 * Two windows: a window on the left and a window on the right.
1684 * Mouse is hovered from the right window into the left window.
1685 * Next, we tap on the left window, where the cursor was last seen.
1686 * The second tap is done onto the right window.
1687 * The mouse and tap are from two different devices.
1688 * We technically don't need to set the downtime / eventtime for these events, but setting these
1689 * explicitly helps during debugging.
1690 * This test reproduces a crash where there is a mismatch between the downTime and eventTime.
1691 * In the buggy implementation, a tap on the right window would cause a crash.
1692 */
TEST_F(InputDispatcherTest,HoverFromLeftToRightAndTap)1693 TEST_F(InputDispatcherTest, HoverFromLeftToRightAndTap) {
1694 SCOPED_FLAG_OVERRIDE(enable_multi_device_same_window_stream, true);
1695
1696 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
1697 sp<FakeWindowHandle> leftWindow = sp<FakeWindowHandle>::make(application, mDispatcher, "Left",
1698 ui::LogicalDisplayId::DEFAULT);
1699 leftWindow->setFrame(Rect(0, 0, 200, 200));
1700
1701 sp<FakeWindowHandle> rightWindow = sp<FakeWindowHandle>::make(application, mDispatcher, "Right",
1702 ui::LogicalDisplayId::DEFAULT);
1703 rightWindow->setFrame(Rect(200, 0, 400, 200));
1704
1705 mDispatcher->onWindowInfosChanged(
1706 {{*leftWindow->getInfo(), *rightWindow->getInfo()}, {}, 0, 0});
1707 // All times need to start at the current time, otherwise the dispatcher will drop the events as
1708 // stale.
1709 const nsecs_t baseTime = systemTime(SYSTEM_TIME_MONOTONIC);
1710 const int32_t mouseDeviceId = 6;
1711 const int32_t touchDeviceId = 4;
1712 // Move the cursor from right
1713 mDispatcher->notifyMotion(
1714 MotionArgsBuilder(AMOTION_EVENT_ACTION_HOVER_MOVE, AINPUT_SOURCE_MOUSE)
1715 .deviceId(mouseDeviceId)
1716 .downTime(baseTime + 10)
1717 .eventTime(baseTime + 20)
1718 .pointer(PointerBuilder(0, ToolType::MOUSE).x(300).y(100))
1719 .build());
1720 rightWindow->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_ENTER));
1721
1722 // .. to the left window
1723 mDispatcher->notifyMotion(
1724 MotionArgsBuilder(AMOTION_EVENT_ACTION_HOVER_MOVE, AINPUT_SOURCE_MOUSE)
1725 .deviceId(mouseDeviceId)
1726 .downTime(baseTime + 10)
1727 .eventTime(baseTime + 30)
1728 .pointer(PointerBuilder(0, ToolType::MOUSE).x(110).y(100))
1729 .build());
1730 rightWindow->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_EXIT));
1731 leftWindow->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_ENTER));
1732 // Now tap the left window
1733 mDispatcher->notifyMotion(
1734 MotionArgsBuilder(AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
1735 .deviceId(touchDeviceId)
1736 .downTime(baseTime + 40)
1737 .eventTime(baseTime + 40)
1738 .pointer(PointerBuilder(0, ToolType::FINGER).x(100).y(100))
1739 .build());
1740 leftWindow->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_DOWN));
1741
1742 // release tap
1743 mDispatcher->notifyMotion(MotionArgsBuilder(AMOTION_EVENT_ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN)
1744 .deviceId(touchDeviceId)
1745 .downTime(baseTime + 40)
1746 .eventTime(baseTime + 50)
1747 .pointer(PointerBuilder(0, ToolType::FINGER).x(100).y(100))
1748 .build());
1749 leftWindow->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_UP));
1750
1751 // Tap the window on the right
1752 mDispatcher->notifyMotion(
1753 MotionArgsBuilder(AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
1754 .deviceId(touchDeviceId)
1755 .downTime(baseTime + 60)
1756 .eventTime(baseTime + 60)
1757 .pointer(PointerBuilder(0, ToolType::FINGER).x(300).y(100))
1758 .build());
1759 rightWindow->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_DOWN));
1760
1761 // release tap
1762 mDispatcher->notifyMotion(MotionArgsBuilder(AMOTION_EVENT_ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN)
1763 .deviceId(touchDeviceId)
1764 .downTime(baseTime + 60)
1765 .eventTime(baseTime + 70)
1766 .pointer(PointerBuilder(0, ToolType::FINGER).x(300).y(100))
1767 .build());
1768 rightWindow->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_UP));
1769
1770 // No more events
1771 leftWindow->assertNoEvents();
1772 rightWindow->assertNoEvents();
1773 }
1774
1775 /**
1776 * Start hovering in a window. While this hover is still active, make another window appear on top.
1777 * The top, obstructing window has no input channel, so it's not supposed to receive input.
1778 * While the top window is present, the hovering is stopped.
1779 * Later, hovering gets resumed again.
1780 * Ensure that new hover gesture is handled correctly.
1781 * This test reproduces a crash where the HOVER_EXIT event wasn't getting dispatched correctly
1782 * to the window that's currently being hovered over.
1783 */
TEST_F(InputDispatcherTest,HoverWhileWindowAppears)1784 TEST_F(InputDispatcherTest, HoverWhileWindowAppears) {
1785 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
1786 sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher, "Window",
1787 ui::LogicalDisplayId::DEFAULT);
1788 window->setFrame(Rect(0, 0, 200, 200));
1789
1790 // Only a single window is present at first
1791 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
1792
1793 // Start hovering in the window
1794 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_ENTER, AINPUT_SOURCE_STYLUS)
1795 .pointer(PointerBuilder(0, ToolType::STYLUS).x(100).y(100))
1796 .build());
1797 window->consumeMotionEvent(WithMotionAction(ACTION_HOVER_ENTER));
1798
1799 // Now, an obscuring window appears!
1800 sp<FakeWindowHandle> obscuringWindow =
1801 sp<FakeWindowHandle>::make(application, mDispatcher, "Obscuring window",
1802 ui::LogicalDisplayId::DEFAULT,
1803 /*createInputChannel=*/false);
1804 obscuringWindow->setFrame(Rect(0, 0, 200, 200));
1805 obscuringWindow->setTouchOcclusionMode(TouchOcclusionMode::BLOCK_UNTRUSTED);
1806 obscuringWindow->setOwnerInfo(SECONDARY_WINDOW_PID, SECONDARY_WINDOW_UID);
1807 obscuringWindow->setNoInputChannel(true);
1808 obscuringWindow->setFocusable(false);
1809 obscuringWindow->setAlpha(1.0);
1810 mDispatcher->onWindowInfosChanged(
1811 {{*obscuringWindow->getInfo(), *window->getInfo()}, {}, 0, 0});
1812
1813 // While this new obscuring window is present, the hovering is stopped
1814 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_EXIT, AINPUT_SOURCE_STYLUS)
1815 .pointer(PointerBuilder(0, ToolType::STYLUS).x(100).y(100))
1816 .build());
1817 window->consumeMotionEvent(WithMotionAction(ACTION_HOVER_EXIT));
1818
1819 // Now the obscuring window goes away.
1820 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
1821
1822 // And a new hover gesture starts.
1823 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_ENTER, AINPUT_SOURCE_STYLUS)
1824 .pointer(PointerBuilder(0, ToolType::STYLUS).x(100).y(100))
1825 .build());
1826 window->consumeMotionEvent(WithMotionAction(ACTION_HOVER_ENTER));
1827 }
1828
1829 /**
1830 * Same test as 'HoverWhileWindowAppears' above, but here, we also send some HOVER_MOVE events to
1831 * the obscuring window.
1832 */
TEST_F(InputDispatcherTest,HoverMoveWhileWindowAppears)1833 TEST_F(InputDispatcherTest, HoverMoveWhileWindowAppears) {
1834 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
1835 sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher, "Window",
1836 ui::LogicalDisplayId::DEFAULT);
1837 window->setFrame(Rect(0, 0, 200, 200));
1838
1839 // Only a single window is present at first
1840 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
1841
1842 // Start hovering in the window
1843 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_ENTER, AINPUT_SOURCE_STYLUS)
1844 .pointer(PointerBuilder(0, ToolType::STYLUS).x(100).y(100))
1845 .build());
1846 window->consumeMotionEvent(WithMotionAction(ACTION_HOVER_ENTER));
1847
1848 // Now, an obscuring window appears!
1849 sp<FakeWindowHandle> obscuringWindow =
1850 sp<FakeWindowHandle>::make(application, mDispatcher, "Obscuring window",
1851 ui::LogicalDisplayId::DEFAULT,
1852 /*createInputChannel=*/false);
1853 obscuringWindow->setFrame(Rect(0, 0, 200, 200));
1854 obscuringWindow->setTouchOcclusionMode(TouchOcclusionMode::BLOCK_UNTRUSTED);
1855 obscuringWindow->setOwnerInfo(SECONDARY_WINDOW_PID, SECONDARY_WINDOW_UID);
1856 obscuringWindow->setNoInputChannel(true);
1857 obscuringWindow->setFocusable(false);
1858 obscuringWindow->setAlpha(1.0);
1859 mDispatcher->onWindowInfosChanged(
1860 {{*obscuringWindow->getInfo(), *window->getInfo()}, {}, 0, 0});
1861
1862 // While this new obscuring window is present, the hovering continues. The event can't go to the
1863 // bottom window due to obstructed touches, so it should generate HOVER_EXIT for that window.
1864 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_MOVE, AINPUT_SOURCE_STYLUS)
1865 .pointer(PointerBuilder(0, ToolType::STYLUS).x(100).y(100))
1866 .build());
1867 obscuringWindow->assertNoEvents();
1868 window->consumeMotionEvent(WithMotionAction(ACTION_HOVER_EXIT));
1869
1870 // Now the obscuring window goes away.
1871 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
1872
1873 // Hovering continues in the same position. The hovering pointer re-enters the bottom window,
1874 // so it should generate a HOVER_ENTER
1875 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_MOVE, AINPUT_SOURCE_STYLUS)
1876 .pointer(PointerBuilder(0, ToolType::STYLUS).x(100).y(100))
1877 .build());
1878 window->consumeMotionEvent(WithMotionAction(ACTION_HOVER_ENTER));
1879
1880 // Now the MOVE should be getting dispatched normally
1881 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_MOVE, AINPUT_SOURCE_STYLUS)
1882 .pointer(PointerBuilder(0, ToolType::STYLUS).x(110).y(110))
1883 .build());
1884 window->consumeMotionEvent(WithMotionAction(ACTION_HOVER_MOVE));
1885 }
1886
1887 /**
1888 * Hover mouse over a window, and then send ACTION_SCROLL. Ensure both the hover and the scroll
1889 * events are delivered to the window.
1890 */
TEST_F(InputDispatcherTest,HoverMoveAndScroll)1891 TEST_F(InputDispatcherTest, HoverMoveAndScroll) {
1892 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
1893 sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher, "Window",
1894 ui::LogicalDisplayId::DEFAULT);
1895 window->setFrame(Rect(0, 0, 200, 200));
1896 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
1897
1898 // Start hovering in the window
1899 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_ENTER, AINPUT_SOURCE_MOUSE)
1900 .pointer(PointerBuilder(0, ToolType::MOUSE).x(100).y(110))
1901 .build());
1902 window->consumeMotionEvent(WithMotionAction(ACTION_HOVER_ENTER));
1903
1904 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_MOVE, AINPUT_SOURCE_MOUSE)
1905 .pointer(PointerBuilder(0, ToolType::MOUSE).x(110).y(120))
1906 .build());
1907 window->consumeMotionEvent(WithMotionAction(ACTION_HOVER_MOVE));
1908
1909 // Scroll with the mouse
1910 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_SCROLL, AINPUT_SOURCE_MOUSE)
1911 .pointer(PointerBuilder(0, ToolType::MOUSE).x(110).y(120))
1912 .build());
1913 window->consumeMotionEvent(WithMotionAction(ACTION_SCROLL));
1914 }
1915
1916 /**
1917 * Two windows: a trusted overlay and a regular window underneath. Both windows are visible.
1918 * Mouse is hovered, and the hover event should only go to the overlay.
1919 * However, next, the touchable region of the trusted overlay shrinks. The mouse position hasn't
1920 * changed, but the cursor would now end up hovering above the regular window underneatch.
1921 * If the mouse is now clicked, this would generate an ACTION_DOWN event, which would go to the
1922 * regular window. However, the trusted overlay is also watching for outside touch.
1923 * The trusted overlay should get two events:
1924 * 1) The ACTION_OUTSIDE event, since the click is now not inside its touchable region
1925 * 2) The HOVER_EXIT event, since the mouse pointer is no longer hovering inside this window
1926 *
1927 * This test reproduces a crash where there is an overlap between dispatch modes for the trusted
1928 * overlay touch target, since the event is causing both an ACTION_OUTSIDE, and as a HOVER_EXIT.
1929 */
TEST_F(InputDispatcherTest,MouseClickUnderShrinkingTrustedOverlay)1930 TEST_F(InputDispatcherTest, MouseClickUnderShrinkingTrustedOverlay) {
1931 std::shared_ptr<FakeApplicationHandle> app = std::make_shared<FakeApplicationHandle>();
1932 sp<FakeWindowHandle> overlay = sp<FakeWindowHandle>::make(app, mDispatcher, "Trusted overlay",
1933 ui::LogicalDisplayId::DEFAULT);
1934 overlay->setTrustedOverlay(true);
1935 overlay->setWatchOutsideTouch(true);
1936 overlay->setFrame(Rect(0, 0, 200, 200));
1937
1938 sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(app, mDispatcher, "Regular window",
1939 ui::LogicalDisplayId::DEFAULT);
1940 window->setFrame(Rect(0, 0, 200, 200));
1941
1942 mDispatcher->onWindowInfosChanged({{*overlay->getInfo(), *window->getInfo()}, {}, 0, 0});
1943 // Hover the mouse into the overlay
1944 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_MOVE, AINPUT_SOURCE_MOUSE)
1945 .pointer(PointerBuilder(0, ToolType::MOUSE).x(100).y(110))
1946 .build());
1947 overlay->consumeMotionEvent(WithMotionAction(ACTION_HOVER_ENTER));
1948
1949 // Now, shrink the touchable region of the overlay! This will cause the cursor to suddenly have
1950 // the regular window as the touch target
1951 overlay->setTouchableRegion(Region({0, 0, 0, 0}));
1952 mDispatcher->onWindowInfosChanged({{*overlay->getInfo(), *window->getInfo()}, {}, 0, 0});
1953
1954 // Now we can click with the mouse. The click should go into the regular window
1955 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_MOUSE)
1956 .pointer(PointerBuilder(0, ToolType::MOUSE).x(100).y(110))
1957 .build());
1958 overlay->consumeMotionEvent(WithMotionAction(ACTION_HOVER_EXIT));
1959 overlay->consumeMotionEvent(WithMotionAction(ACTION_OUTSIDE));
1960 window->consumeMotionEvent(WithMotionAction(ACTION_DOWN));
1961 }
1962
1963 /**
1964 * Similar to above, but also has a spy on top that also catches the HOVER
1965 * events. Also, instead of ACTION_DOWN, we are continuing to send the hovering
1966 * stream to ensure that the spy receives hover events correctly.
1967 */
TEST_F(InputDispatcherTest,MouseClickUnderShrinkingTrustedOverlayWithSpy)1968 TEST_F(InputDispatcherTest, MouseClickUnderShrinkingTrustedOverlayWithSpy) {
1969 std::shared_ptr<FakeApplicationHandle> app = std::make_shared<FakeApplicationHandle>();
1970 sp<FakeWindowHandle> spyWindow =
1971 sp<FakeWindowHandle>::make(app, mDispatcher, "Spy", ui::LogicalDisplayId::DEFAULT);
1972 spyWindow->setFrame(Rect(0, 0, 200, 200));
1973 spyWindow->setTrustedOverlay(true);
1974 spyWindow->setSpy(true);
1975 sp<FakeWindowHandle> overlay = sp<FakeWindowHandle>::make(app, mDispatcher, "Trusted overlay",
1976 ui::LogicalDisplayId::DEFAULT);
1977 overlay->setTrustedOverlay(true);
1978 overlay->setWatchOutsideTouch(true);
1979 overlay->setFrame(Rect(0, 0, 200, 200));
1980
1981 sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(app, mDispatcher, "Regular window",
1982 ui::LogicalDisplayId::DEFAULT);
1983 window->setFrame(Rect(0, 0, 200, 200));
1984
1985 mDispatcher->onWindowInfosChanged(
1986 {{*spyWindow->getInfo(), *overlay->getInfo(), *window->getInfo()}, {}, 0, 0});
1987 // Hover the mouse into the overlay
1988 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_MOVE, AINPUT_SOURCE_MOUSE)
1989 .pointer(PointerBuilder(0, ToolType::MOUSE).x(100).y(110))
1990 .build());
1991 spyWindow->consumeMotionEvent(WithMotionAction(ACTION_HOVER_ENTER));
1992 overlay->consumeMotionEvent(WithMotionAction(ACTION_HOVER_ENTER));
1993
1994 // Now, shrink the touchable region of the overlay! This will cause the cursor to suddenly have
1995 // the regular window as the touch target
1996 overlay->setTouchableRegion(Region({0, 0, 0, 0}));
1997 mDispatcher->onWindowInfosChanged(
1998 {{*spyWindow->getInfo(), *overlay->getInfo(), *window->getInfo()}, {}, 0, 0});
1999
2000 // Now we can click with the mouse. The click should go into the regular window
2001 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_MOVE, AINPUT_SOURCE_MOUSE)
2002 .pointer(PointerBuilder(0, ToolType::MOUSE).x(110).y(110))
2003 .build());
2004 spyWindow->consumeMotionEvent(WithMotionAction(ACTION_HOVER_MOVE));
2005 overlay->consumeMotionEvent(WithMotionAction(ACTION_HOVER_EXIT));
2006 window->consumeMotionEvent(WithMotionAction(ACTION_HOVER_ENTER));
2007 }
2008
2009 using InputDispatcherMultiDeviceTest = InputDispatcherTest;
2010
2011 /**
2012 * One window. Stylus down on the window. Next, touch from another device goes down. Ensure that
2013 * touch is dropped, because stylus should be preferred over touch.
2014 */
TEST_F(InputDispatcherMultiDeviceTest,StylusDownBlocksTouchDown)2015 TEST_F(InputDispatcherMultiDeviceTest, StylusDownBlocksTouchDown) {
2016 SCOPED_FLAG_OVERRIDE(enable_multi_device_same_window_stream, false);
2017 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
2018 sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher, "Window",
2019 ui::LogicalDisplayId::DEFAULT);
2020 window->setFrame(Rect(0, 0, 200, 200));
2021
2022 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
2023
2024 constexpr int32_t touchDeviceId = 4;
2025 constexpr int32_t stylusDeviceId = 2;
2026
2027 // Stylus down
2028 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_STYLUS)
2029 .deviceId(stylusDeviceId)
2030 .pointer(PointerBuilder(0, ToolType::STYLUS).x(100).y(110))
2031 .build());
2032 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(stylusDeviceId)));
2033
2034 // Touch down
2035 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
2036 .deviceId(touchDeviceId)
2037 .pointer(PointerBuilder(0, ToolType::FINGER).x(140).y(145))
2038 .build());
2039
2040 // Touch move
2041 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN)
2042 .deviceId(touchDeviceId)
2043 .pointer(PointerBuilder(0, ToolType::FINGER).x(141).y(146))
2044 .build());
2045 // Touch is ignored because stylus is already down
2046
2047 // Subsequent stylus movements are delivered correctly
2048 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_STYLUS)
2049 .deviceId(stylusDeviceId)
2050 .pointer(PointerBuilder(0, ToolType::STYLUS).x(101).y(111))
2051 .build());
2052 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(stylusDeviceId),
2053 WithCoords(101, 111)));
2054
2055 window->assertNoEvents();
2056 }
2057
2058 /**
2059 * One window. Stylus down on the window. Next, touch from another device goes down. Ensure that
2060 * touch is not dropped, because multiple devices are allowed to be active in the same window.
2061 */
TEST_F(InputDispatcherMultiDeviceTest,StylusDownDoesNotBlockTouchDown)2062 TEST_F(InputDispatcherMultiDeviceTest, StylusDownDoesNotBlockTouchDown) {
2063 SCOPED_FLAG_OVERRIDE(enable_multi_device_same_window_stream, true);
2064 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
2065 sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher, "Window",
2066 ui::LogicalDisplayId::DEFAULT);
2067 window->setFrame(Rect(0, 0, 200, 200));
2068
2069 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
2070
2071 constexpr int32_t touchDeviceId = 4;
2072 constexpr int32_t stylusDeviceId = 2;
2073
2074 // Stylus down
2075 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_STYLUS)
2076 .deviceId(stylusDeviceId)
2077 .pointer(PointerBuilder(0, ToolType::STYLUS).x(100).y(110))
2078 .build());
2079 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(stylusDeviceId)));
2080
2081 // Touch down
2082 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
2083 .deviceId(touchDeviceId)
2084 .pointer(PointerBuilder(0, ToolType::FINGER).x(140).y(145))
2085 .build());
2086 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(touchDeviceId)));
2087
2088 // Touch move
2089 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN)
2090 .deviceId(touchDeviceId)
2091 .pointer(PointerBuilder(0, ToolType::FINGER).x(141).y(146))
2092 .build());
2093 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(touchDeviceId)));
2094
2095 // Stylus move
2096 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_STYLUS)
2097 .deviceId(stylusDeviceId)
2098 .pointer(PointerBuilder(0, ToolType::STYLUS).x(101).y(111))
2099 .build());
2100 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(stylusDeviceId),
2101 WithCoords(101, 111)));
2102
2103 window->assertNoEvents();
2104 }
2105
2106 /**
2107 * One window and one spy window. Stylus down on the window. Next, touch from another device goes
2108 * down. Ensure that touch is dropped, because stylus should be preferred over touch.
2109 * Similar test as above, but with added SPY window.
2110 */
TEST_F(InputDispatcherMultiDeviceTest,StylusDownWithSpyBlocksTouchDown)2111 TEST_F(InputDispatcherMultiDeviceTest, StylusDownWithSpyBlocksTouchDown) {
2112 SCOPED_FLAG_OVERRIDE(enable_multi_device_same_window_stream, false);
2113 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
2114 sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher, "Window",
2115 ui::LogicalDisplayId::DEFAULT);
2116 sp<FakeWindowHandle> spyWindow = sp<FakeWindowHandle>::make(application, mDispatcher, "Spy",
2117 ui::LogicalDisplayId::DEFAULT);
2118 spyWindow->setFrame(Rect(0, 0, 200, 200));
2119 spyWindow->setTrustedOverlay(true);
2120 spyWindow->setSpy(true);
2121 window->setFrame(Rect(0, 0, 200, 200));
2122
2123 mDispatcher->onWindowInfosChanged({{*spyWindow->getInfo(), *window->getInfo()}, {}, 0, 0});
2124
2125 constexpr int32_t touchDeviceId = 4;
2126 constexpr int32_t stylusDeviceId = 2;
2127
2128 // Stylus down
2129 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_STYLUS)
2130 .deviceId(stylusDeviceId)
2131 .pointer(PointerBuilder(0, ToolType::STYLUS).x(100).y(110))
2132 .build());
2133 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(stylusDeviceId)));
2134 spyWindow->consumeMotionEvent(
2135 AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(stylusDeviceId)));
2136
2137 // Touch down
2138 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
2139 .deviceId(touchDeviceId)
2140 .pointer(PointerBuilder(0, ToolType::FINGER).x(140).y(145))
2141 .build());
2142
2143 // Touch move
2144 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN)
2145 .deviceId(touchDeviceId)
2146 .pointer(PointerBuilder(0, ToolType::FINGER).x(141).y(146))
2147 .build());
2148
2149 // Touch is ignored because stylus is already down
2150
2151 // Subsequent stylus movements are delivered correctly
2152 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_STYLUS)
2153 .deviceId(stylusDeviceId)
2154 .pointer(PointerBuilder(0, ToolType::STYLUS).x(101).y(111))
2155 .build());
2156 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(stylusDeviceId),
2157 WithCoords(101, 111)));
2158 spyWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(stylusDeviceId),
2159 WithCoords(101, 111)));
2160
2161 window->assertNoEvents();
2162 spyWindow->assertNoEvents();
2163 }
2164
2165 /**
2166 * One window and one spy window. Stylus down on the window. Next, touch from another device goes
2167 * down. Ensure that touch is not dropped, because multiple devices can be active at the same time.
2168 * Similar test as above, but with added SPY window.
2169 */
TEST_F(InputDispatcherMultiDeviceTest,StylusDownWithSpyDoesNotBlockTouchDown)2170 TEST_F(InputDispatcherMultiDeviceTest, StylusDownWithSpyDoesNotBlockTouchDown) {
2171 SCOPED_FLAG_OVERRIDE(enable_multi_device_same_window_stream, true);
2172 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
2173 sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher, "Window",
2174 ui::LogicalDisplayId::DEFAULT);
2175 sp<FakeWindowHandle> spyWindow = sp<FakeWindowHandle>::make(application, mDispatcher, "Spy",
2176 ui::LogicalDisplayId::DEFAULT);
2177 spyWindow->setFrame(Rect(0, 0, 200, 200));
2178 spyWindow->setTrustedOverlay(true);
2179 spyWindow->setSpy(true);
2180 window->setFrame(Rect(0, 0, 200, 200));
2181
2182 mDispatcher->onWindowInfosChanged({{*spyWindow->getInfo(), *window->getInfo()}, {}, 0, 0});
2183
2184 constexpr int32_t touchDeviceId = 4;
2185 constexpr int32_t stylusDeviceId = 2;
2186
2187 // Stylus down
2188 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_STYLUS)
2189 .deviceId(stylusDeviceId)
2190 .pointer(PointerBuilder(0, ToolType::STYLUS).x(100).y(110))
2191 .build());
2192 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(stylusDeviceId)));
2193 spyWindow->consumeMotionEvent(
2194 AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(stylusDeviceId)));
2195
2196 // Touch down
2197 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
2198 .deviceId(touchDeviceId)
2199 .pointer(PointerBuilder(0, ToolType::FINGER).x(140).y(145))
2200 .build());
2201 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(touchDeviceId)));
2202 spyWindow->consumeMotionEvent(
2203 AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(touchDeviceId)));
2204
2205 // Touch move
2206 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN)
2207 .deviceId(touchDeviceId)
2208 .pointer(PointerBuilder(0, ToolType::FINGER).x(141).y(146))
2209 .build());
2210 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(touchDeviceId)));
2211 spyWindow->consumeMotionEvent(
2212 AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(touchDeviceId)));
2213
2214 // Subsequent stylus movements are delivered correctly
2215 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_STYLUS)
2216 .deviceId(stylusDeviceId)
2217 .pointer(PointerBuilder(0, ToolType::STYLUS).x(101).y(111))
2218 .build());
2219 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(stylusDeviceId),
2220 WithCoords(101, 111)));
2221 spyWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(stylusDeviceId),
2222 WithCoords(101, 111)));
2223
2224 window->assertNoEvents();
2225 spyWindow->assertNoEvents();
2226 }
2227
2228 /**
2229 * One window. Stylus hover on the window. Next, touch from another device goes down. Ensure that
2230 * touch is dropped, because stylus hover takes precedence.
2231 */
TEST_F(InputDispatcherMultiDeviceTest,StylusHoverBlocksTouchDown)2232 TEST_F(InputDispatcherMultiDeviceTest, StylusHoverBlocksTouchDown) {
2233 SCOPED_FLAG_OVERRIDE(enable_multi_device_same_window_stream, false);
2234 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
2235 sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher, "Window",
2236 ui::LogicalDisplayId::DEFAULT);
2237 window->setFrame(Rect(0, 0, 200, 200));
2238
2239 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
2240
2241 constexpr int32_t touchDeviceId = 4;
2242 constexpr int32_t stylusDeviceId = 2;
2243
2244 // Stylus down on the window
2245 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_ENTER, AINPUT_SOURCE_STYLUS)
2246 .deviceId(stylusDeviceId)
2247 .pointer(PointerBuilder(0, ToolType::STYLUS).x(100).y(110))
2248 .build());
2249 window->consumeMotionEvent(
2250 AllOf(WithMotionAction(ACTION_HOVER_ENTER), WithDeviceId(stylusDeviceId)));
2251
2252 // Touch down on window
2253 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
2254 .deviceId(touchDeviceId)
2255 .pointer(PointerBuilder(0, ToolType::FINGER).x(140).y(145))
2256 .build());
2257 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN)
2258 .deviceId(touchDeviceId)
2259 .pointer(PointerBuilder(0, ToolType::FINGER).x(141).y(146))
2260 .build());
2261
2262 // Touch is ignored because stylus is hovering
2263
2264 // Subsequent stylus movements are delivered correctly
2265 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_MOVE, AINPUT_SOURCE_STYLUS)
2266 .deviceId(stylusDeviceId)
2267 .pointer(PointerBuilder(0, ToolType::STYLUS).x(101).y(111))
2268 .build());
2269 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_HOVER_MOVE),
2270 WithDeviceId(stylusDeviceId), WithCoords(101, 111)));
2271
2272 // and subsequent touches continue to be ignored
2273 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN)
2274 .deviceId(touchDeviceId)
2275 .pointer(PointerBuilder(0, ToolType::FINGER).x(142).y(147))
2276 .build());
2277 window->assertNoEvents();
2278 }
2279
2280 /**
2281 * One window. Stylus hover on the window. Next, touch from another device goes down. Ensure that
2282 * touch is not dropped, because stylus hover and touch can be both active at the same time.
2283 */
TEST_F(InputDispatcherMultiDeviceTest,StylusHoverDoesNotBlockTouchDown)2284 TEST_F(InputDispatcherMultiDeviceTest, StylusHoverDoesNotBlockTouchDown) {
2285 SCOPED_FLAG_OVERRIDE(enable_multi_device_same_window_stream, true);
2286 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
2287 sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher, "Window",
2288 ui::LogicalDisplayId::DEFAULT);
2289 window->setFrame(Rect(0, 0, 200, 200));
2290
2291 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
2292
2293 constexpr int32_t touchDeviceId = 4;
2294 constexpr int32_t stylusDeviceId = 2;
2295
2296 // Stylus down on the window
2297 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_ENTER, AINPUT_SOURCE_STYLUS)
2298 .deviceId(stylusDeviceId)
2299 .pointer(PointerBuilder(0, ToolType::STYLUS).x(100).y(110))
2300 .build());
2301 window->consumeMotionEvent(
2302 AllOf(WithMotionAction(ACTION_HOVER_ENTER), WithDeviceId(stylusDeviceId)));
2303
2304 // Touch down on window
2305 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
2306 .deviceId(touchDeviceId)
2307 .pointer(PointerBuilder(0, ToolType::FINGER).x(140).y(145))
2308 .build());
2309 // Touch move on window
2310 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(touchDeviceId)));
2311 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN)
2312 .deviceId(touchDeviceId)
2313 .pointer(PointerBuilder(0, ToolType::FINGER).x(141).y(146))
2314 .build());
2315 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(touchDeviceId)));
2316
2317 // Subsequent stylus movements are delivered correctly
2318 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_MOVE, AINPUT_SOURCE_STYLUS)
2319 .deviceId(stylusDeviceId)
2320 .pointer(PointerBuilder(0, ToolType::STYLUS).x(101).y(111))
2321 .build());
2322 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_HOVER_MOVE),
2323 WithDeviceId(stylusDeviceId), WithCoords(101, 111)));
2324
2325 // and subsequent touches continue to work
2326 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN)
2327 .deviceId(touchDeviceId)
2328 .pointer(PointerBuilder(0, ToolType::FINGER).x(142).y(147))
2329 .build());
2330 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(touchDeviceId)));
2331 window->assertNoEvents();
2332 }
2333
2334 /**
2335 * One window. Touch down on the window. Then, stylus hover on the window from another device.
2336 * Ensure that touch is canceled, because stylus hover should take precedence.
2337 */
TEST_F(InputDispatcherMultiDeviceTest,TouchIsCanceledByStylusHover)2338 TEST_F(InputDispatcherMultiDeviceTest, TouchIsCanceledByStylusHover) {
2339 SCOPED_FLAG_OVERRIDE(enable_multi_device_same_window_stream, false);
2340 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
2341 sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher, "Window",
2342 ui::LogicalDisplayId::DEFAULT);
2343 window->setFrame(Rect(0, 0, 200, 200));
2344
2345 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
2346
2347 constexpr int32_t touchDeviceId = 4;
2348 constexpr int32_t stylusDeviceId = 2;
2349
2350 // Touch down on window
2351 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
2352 .deviceId(touchDeviceId)
2353 .pointer(PointerBuilder(0, ToolType::FINGER).x(140).y(145))
2354 .build());
2355 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN)
2356 .deviceId(touchDeviceId)
2357 .pointer(PointerBuilder(0, ToolType::FINGER).x(141).y(146))
2358 .build());
2359 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(touchDeviceId)));
2360 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(touchDeviceId)));
2361
2362 // Stylus hover on the window
2363 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_ENTER, AINPUT_SOURCE_STYLUS)
2364 .deviceId(stylusDeviceId)
2365 .pointer(PointerBuilder(0, ToolType::STYLUS).x(100).y(110))
2366 .build());
2367 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_MOVE, AINPUT_SOURCE_STYLUS)
2368 .deviceId(stylusDeviceId)
2369 .pointer(PointerBuilder(0, ToolType::STYLUS).x(101).y(111))
2370 .build());
2371 // Stylus hover movement causes touch to be canceled
2372 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_CANCEL), WithDeviceId(touchDeviceId),
2373 WithCoords(141, 146)));
2374 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_HOVER_ENTER),
2375 WithDeviceId(stylusDeviceId), WithCoords(100, 110)));
2376 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_HOVER_MOVE),
2377 WithDeviceId(stylusDeviceId), WithCoords(101, 111)));
2378
2379 // Subsequent touch movements are ignored
2380 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN)
2381 .deviceId(touchDeviceId)
2382 .pointer(PointerBuilder(0, ToolType::FINGER).x(142).y(147))
2383 .build());
2384
2385 window->assertNoEvents();
2386 }
2387
2388 /**
2389 * One window. Touch down on the window. Then, stylus hover on the window from another device.
2390 * Ensure that touch is not canceled, because stylus hover can be active at the same time as touch.
2391 */
TEST_F(InputDispatcherMultiDeviceTest,TouchIsNotCanceledByStylusHover)2392 TEST_F(InputDispatcherMultiDeviceTest, TouchIsNotCanceledByStylusHover) {
2393 SCOPED_FLAG_OVERRIDE(enable_multi_device_same_window_stream, true);
2394 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
2395 sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher, "Window",
2396 ui::LogicalDisplayId::DEFAULT);
2397 window->setFrame(Rect(0, 0, 200, 200));
2398
2399 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
2400
2401 constexpr int32_t touchDeviceId = 4;
2402 constexpr int32_t stylusDeviceId = 2;
2403
2404 // Touch down on window
2405 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
2406 .deviceId(touchDeviceId)
2407 .pointer(PointerBuilder(0, ToolType::FINGER).x(140).y(145))
2408 .build());
2409 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN)
2410 .deviceId(touchDeviceId)
2411 .pointer(PointerBuilder(0, ToolType::FINGER).x(141).y(146))
2412 .build());
2413 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(touchDeviceId)));
2414 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(touchDeviceId)));
2415
2416 // Stylus hover on the window
2417 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_ENTER, AINPUT_SOURCE_STYLUS)
2418 .deviceId(stylusDeviceId)
2419 .pointer(PointerBuilder(0, ToolType::STYLUS).x(100).y(110))
2420 .build());
2421 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_MOVE, AINPUT_SOURCE_STYLUS)
2422 .deviceId(stylusDeviceId)
2423 .pointer(PointerBuilder(0, ToolType::STYLUS).x(101).y(111))
2424 .build());
2425 // Stylus hover movement is received normally
2426 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_HOVER_ENTER),
2427 WithDeviceId(stylusDeviceId), WithCoords(100, 110)));
2428 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_HOVER_MOVE),
2429 WithDeviceId(stylusDeviceId), WithCoords(101, 111)));
2430
2431 // Subsequent touch movements also work
2432 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN)
2433 .deviceId(touchDeviceId)
2434 .pointer(PointerBuilder(0, ToolType::FINGER).x(142).y(147))
2435 .build());
2436 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(touchDeviceId),
2437 WithCoords(142, 147)));
2438
2439 window->assertNoEvents();
2440 }
2441
2442 /**
2443 * One window. Stylus down on the window. Then, stylus from another device goes down. Ensure that
2444 * the latest stylus takes over. That is, old stylus should be canceled and the new stylus should
2445 * become active.
2446 */
TEST_F(InputDispatcherMultiDeviceTest,LatestStylusWins)2447 TEST_F(InputDispatcherMultiDeviceTest, LatestStylusWins) {
2448 SCOPED_FLAG_OVERRIDE(enable_multi_device_same_window_stream, false);
2449 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
2450 sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher, "Window",
2451 ui::LogicalDisplayId::DEFAULT);
2452 window->setFrame(Rect(0, 0, 200, 200));
2453
2454 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
2455
2456 constexpr int32_t stylusDeviceId1 = 3;
2457 constexpr int32_t stylusDeviceId2 = 5;
2458
2459 // Touch down on window
2460 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_STYLUS)
2461 .deviceId(stylusDeviceId1)
2462 .pointer(PointerBuilder(0, ToolType::STYLUS).x(99).y(100))
2463 .build());
2464 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_STYLUS)
2465 .deviceId(stylusDeviceId1)
2466 .pointer(PointerBuilder(0, ToolType::STYLUS).x(100).y(101))
2467 .build());
2468 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(stylusDeviceId1)));
2469 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(stylusDeviceId1)));
2470
2471 // Second stylus down
2472 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_STYLUS)
2473 .deviceId(stylusDeviceId2)
2474 .pointer(PointerBuilder(0, ToolType::STYLUS).x(9).y(10))
2475 .build());
2476 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_STYLUS)
2477 .deviceId(stylusDeviceId2)
2478 .pointer(PointerBuilder(0, ToolType::STYLUS).x(10).y(11))
2479 .build());
2480
2481 // First stylus is canceled, second one takes over.
2482 window->consumeMotionEvent(
2483 AllOf(WithMotionAction(ACTION_CANCEL), WithDeviceId(stylusDeviceId1)));
2484 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(stylusDeviceId2)));
2485 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(stylusDeviceId2)));
2486
2487 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_STYLUS)
2488 .deviceId(stylusDeviceId1)
2489 .pointer(PointerBuilder(0, ToolType::STYLUS).x(101).y(102))
2490 .build());
2491 // Subsequent stylus movements are delivered correctly
2492 window->assertNoEvents();
2493 }
2494
2495 /**
2496 * One window. Stylus down on the window. Then, stylus from another device goes down. Ensure that
2497 * both stylus devices can function simultaneously.
2498 */
TEST_F(InputDispatcherMultiDeviceTest,TwoStylusDevicesActiveAtTheSameTime)2499 TEST_F(InputDispatcherMultiDeviceTest, TwoStylusDevicesActiveAtTheSameTime) {
2500 SCOPED_FLAG_OVERRIDE(enable_multi_device_same_window_stream, true);
2501 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
2502 sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher, "Window",
2503 ui::LogicalDisplayId::DEFAULT);
2504 window->setFrame(Rect(0, 0, 200, 200));
2505
2506 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
2507
2508 constexpr int32_t stylusDeviceId1 = 3;
2509 constexpr int32_t stylusDeviceId2 = 5;
2510
2511 // Touch down on window
2512 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_STYLUS)
2513 .deviceId(stylusDeviceId1)
2514 .pointer(PointerBuilder(0, ToolType::STYLUS).x(99).y(100))
2515 .build());
2516 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_STYLUS)
2517 .deviceId(stylusDeviceId1)
2518 .pointer(PointerBuilder(0, ToolType::STYLUS).x(100).y(101))
2519 .build());
2520 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(stylusDeviceId1)));
2521 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(stylusDeviceId1)));
2522
2523 // Second stylus down
2524 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_STYLUS)
2525 .deviceId(stylusDeviceId2)
2526 .pointer(PointerBuilder(0, ToolType::STYLUS).x(9).y(10))
2527 .build());
2528 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_STYLUS)
2529 .deviceId(stylusDeviceId2)
2530 .pointer(PointerBuilder(0, ToolType::STYLUS).x(10).y(11))
2531 .build());
2532 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(stylusDeviceId2)));
2533 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(stylusDeviceId2)));
2534
2535 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_STYLUS)
2536 .deviceId(stylusDeviceId1)
2537 .pointer(PointerBuilder(0, ToolType::STYLUS).x(101).y(102))
2538 .build());
2539 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(stylusDeviceId1)));
2540 window->assertNoEvents();
2541 }
2542
2543 /**
2544 * One window. Touch down on the window. Then, stylus down on the window from another device.
2545 * Ensure that is canceled, because stylus down should be preferred over touch.
2546 */
TEST_F(InputDispatcherMultiDeviceTest,TouchIsCanceledByStylusDown)2547 TEST_F(InputDispatcherMultiDeviceTest, TouchIsCanceledByStylusDown) {
2548 SCOPED_FLAG_OVERRIDE(enable_multi_device_same_window_stream, false);
2549 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
2550 sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher, "Window",
2551 ui::LogicalDisplayId::DEFAULT);
2552 window->setFrame(Rect(0, 0, 200, 200));
2553
2554 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
2555
2556 constexpr int32_t touchDeviceId = 4;
2557 constexpr int32_t stylusDeviceId = 2;
2558
2559 // Touch down on window
2560 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
2561 .deviceId(touchDeviceId)
2562 .pointer(PointerBuilder(0, ToolType::FINGER).x(140).y(145))
2563 .build());
2564 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN)
2565 .deviceId(touchDeviceId)
2566 .pointer(PointerBuilder(0, ToolType::FINGER).x(141).y(146))
2567 .build());
2568 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(touchDeviceId)));
2569 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(touchDeviceId)));
2570
2571 // Stylus down on the window
2572 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_STYLUS)
2573 .deviceId(stylusDeviceId)
2574 .pointer(PointerBuilder(0, ToolType::STYLUS).x(100).y(110))
2575 .build());
2576 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_CANCEL), WithDeviceId(touchDeviceId)));
2577 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(stylusDeviceId)));
2578
2579 // Subsequent stylus movements are delivered correctly
2580 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_STYLUS)
2581 .deviceId(stylusDeviceId)
2582 .pointer(PointerBuilder(0, ToolType::STYLUS).x(101).y(111))
2583 .build());
2584 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(stylusDeviceId),
2585 WithCoords(101, 111)));
2586 }
2587
2588 /**
2589 * One window. Touch down on the window. Then, stylus down on the window from another device.
2590 * Ensure that both touch and stylus are functioning independently.
2591 */
TEST_F(InputDispatcherMultiDeviceTest,TouchIsNotCanceledByStylusDown)2592 TEST_F(InputDispatcherMultiDeviceTest, TouchIsNotCanceledByStylusDown) {
2593 SCOPED_FLAG_OVERRIDE(enable_multi_device_same_window_stream, true);
2594 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
2595 sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher, "Window",
2596 ui::LogicalDisplayId::DEFAULT);
2597 window->setFrame(Rect(0, 0, 200, 200));
2598
2599 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
2600
2601 constexpr int32_t touchDeviceId = 4;
2602 constexpr int32_t stylusDeviceId = 2;
2603
2604 // Touch down on window
2605 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
2606 .deviceId(touchDeviceId)
2607 .pointer(PointerBuilder(0, ToolType::FINGER).x(140).y(145))
2608 .build());
2609 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN)
2610 .deviceId(touchDeviceId)
2611 .pointer(PointerBuilder(0, ToolType::FINGER).x(141).y(146))
2612 .build());
2613 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(touchDeviceId)));
2614 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(touchDeviceId)));
2615
2616 // Stylus down on the window
2617 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_STYLUS)
2618 .deviceId(stylusDeviceId)
2619 .pointer(PointerBuilder(0, ToolType::STYLUS).x(100).y(110))
2620 .build());
2621 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(stylusDeviceId)));
2622
2623 // Subsequent stylus movements are delivered correctly
2624 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_STYLUS)
2625 .deviceId(stylusDeviceId)
2626 .pointer(PointerBuilder(0, ToolType::STYLUS).x(101).y(111))
2627 .build());
2628 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(stylusDeviceId),
2629 WithCoords(101, 111)));
2630
2631 // Touch continues to work too
2632 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN)
2633 .deviceId(touchDeviceId)
2634 .pointer(PointerBuilder(0, ToolType::FINGER).x(148).y(149))
2635 .build());
2636 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(touchDeviceId)));
2637 }
2638
2639 /**
2640 * Two windows: a window on the left and a window on the right.
2641 * Mouse is clicked on the left window and remains down. Touch is touched on the right and remains
2642 * down. Then, on the left window, also place second touch pointer down.
2643 * This test tries to reproduce a crash.
2644 * In the buggy implementation, second pointer down on the left window would cause a crash.
2645 */
TEST_F(InputDispatcherMultiDeviceTest,MultiDeviceSplitTouch_legacy)2646 TEST_F(InputDispatcherMultiDeviceTest, MultiDeviceSplitTouch_legacy) {
2647 SCOPED_FLAG_OVERRIDE(enable_multi_device_same_window_stream, false);
2648 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
2649 sp<FakeWindowHandle> leftWindow = sp<FakeWindowHandle>::make(application, mDispatcher, "Left",
2650 ui::LogicalDisplayId::DEFAULT);
2651 leftWindow->setFrame(Rect(0, 0, 200, 200));
2652
2653 sp<FakeWindowHandle> rightWindow = sp<FakeWindowHandle>::make(application, mDispatcher, "Right",
2654 ui::LogicalDisplayId::DEFAULT);
2655 rightWindow->setFrame(Rect(200, 0, 400, 200));
2656
2657 mDispatcher->onWindowInfosChanged(
2658 {{*leftWindow->getInfo(), *rightWindow->getInfo()}, {}, 0, 0});
2659
2660 const int32_t touchDeviceId = 4;
2661 const int32_t mouseDeviceId = 6;
2662
2663 // Start hovering over the left window
2664 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_ENTER, AINPUT_SOURCE_MOUSE)
2665 .deviceId(mouseDeviceId)
2666 .pointer(PointerBuilder(0, ToolType::MOUSE).x(100).y(100))
2667 .build());
2668 leftWindow->consumeMotionEvent(
2669 AllOf(WithMotionAction(ACTION_HOVER_ENTER), WithDeviceId(mouseDeviceId)));
2670
2671 // Mouse down on left window
2672 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_MOUSE)
2673 .deviceId(mouseDeviceId)
2674 .buttonState(AMOTION_EVENT_BUTTON_PRIMARY)
2675 .pointer(PointerBuilder(0, ToolType::MOUSE).x(100).y(100))
2676 .build());
2677
2678 leftWindow->consumeMotionEvent(
2679 AllOf(WithMotionAction(ACTION_HOVER_EXIT), WithDeviceId(mouseDeviceId)));
2680 leftWindow->consumeMotionEvent(
2681 AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(mouseDeviceId)));
2682
2683 mDispatcher->notifyMotion(
2684 MotionArgsBuilder(AMOTION_EVENT_ACTION_BUTTON_PRESS, AINPUT_SOURCE_MOUSE)
2685 .deviceId(mouseDeviceId)
2686 .buttonState(AMOTION_EVENT_BUTTON_PRIMARY)
2687 .actionButton(AMOTION_EVENT_BUTTON_PRIMARY)
2688 .pointer(PointerBuilder(0, ToolType::MOUSE).x(100).y(100))
2689 .build());
2690 leftWindow->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_BUTTON_PRESS));
2691
2692 // First touch pointer down on right window
2693 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
2694 .deviceId(touchDeviceId)
2695 .pointer(PointerBuilder(0, ToolType::FINGER).x(300).y(100))
2696 .build());
2697 leftWindow->assertNoEvents();
2698
2699 rightWindow->consumeMotionEvent(WithMotionAction(ACTION_DOWN));
2700
2701 // Second touch pointer down on left window
2702 mDispatcher->notifyMotion(MotionArgsBuilder(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
2703 .deviceId(touchDeviceId)
2704 .pointer(PointerBuilder(0, ToolType::FINGER).x(300).y(100))
2705 .pointer(PointerBuilder(1, ToolType::FINGER).x(100).y(100))
2706 .build());
2707 // Since this is now a new splittable pointer going down on the left window, and it's coming
2708 // from a different device, the current gesture in the left window (pointer down) should first
2709 // be canceled.
2710 leftWindow->consumeMotionEvent(
2711 AllOf(WithMotionAction(ACTION_CANCEL), WithDeviceId(mouseDeviceId)));
2712 leftWindow->consumeMotionEvent(
2713 AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(touchDeviceId)));
2714 // This MOVE event is not necessary (doesn't carry any new information), but it's there in the
2715 // current implementation.
2716 const std::map<int32_t, PointF> expectedPointers{{0, PointF{100, 100}}};
2717 rightWindow->consumeMotionEvent(
2718 AllOf(WithMotionAction(ACTION_MOVE), WithPointers(expectedPointers)));
2719
2720 leftWindow->assertNoEvents();
2721 rightWindow->assertNoEvents();
2722 }
2723
2724 /**
2725 * Two windows: a window on the left and a window on the right.
2726 * Mouse is clicked on the left window and remains down. Touch is touched on the right and remains
2727 * down. Then, on the left window, also place second touch pointer down.
2728 * This test tries to reproduce a crash.
2729 * In the buggy implementation, second pointer down on the left window would cause a crash.
2730 */
TEST_F(InputDispatcherMultiDeviceTest,MultiDeviceSplitTouch)2731 TEST_F(InputDispatcherMultiDeviceTest, MultiDeviceSplitTouch) {
2732 SCOPED_FLAG_OVERRIDE(enable_multi_device_same_window_stream, true);
2733 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
2734 sp<FakeWindowHandle> leftWindow = sp<FakeWindowHandle>::make(application, mDispatcher, "Left",
2735 ui::LogicalDisplayId::DEFAULT);
2736 leftWindow->setFrame(Rect(0, 0, 200, 200));
2737
2738 sp<FakeWindowHandle> rightWindow = sp<FakeWindowHandle>::make(application, mDispatcher, "Right",
2739 ui::LogicalDisplayId::DEFAULT);
2740 rightWindow->setFrame(Rect(200, 0, 400, 200));
2741
2742 mDispatcher->onWindowInfosChanged(
2743 {{*leftWindow->getInfo(), *rightWindow->getInfo()}, {}, 0, 0});
2744
2745 const int32_t touchDeviceId = 4;
2746 const int32_t mouseDeviceId = 6;
2747
2748 // Start hovering over the left window
2749 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_ENTER, AINPUT_SOURCE_MOUSE)
2750 .deviceId(mouseDeviceId)
2751 .pointer(PointerBuilder(0, ToolType::MOUSE).x(100).y(100))
2752 .build());
2753 leftWindow->consumeMotionEvent(
2754 AllOf(WithMotionAction(ACTION_HOVER_ENTER), WithDeviceId(mouseDeviceId)));
2755
2756 // Mouse down on left window
2757 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_MOUSE)
2758 .deviceId(mouseDeviceId)
2759 .buttonState(AMOTION_EVENT_BUTTON_PRIMARY)
2760 .pointer(PointerBuilder(0, ToolType::MOUSE).x(100).y(100))
2761 .build());
2762
2763 leftWindow->consumeMotionEvent(
2764 AllOf(WithMotionAction(ACTION_HOVER_EXIT), WithDeviceId(mouseDeviceId)));
2765 leftWindow->consumeMotionEvent(
2766 AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(mouseDeviceId)));
2767
2768 mDispatcher->notifyMotion(
2769 MotionArgsBuilder(AMOTION_EVENT_ACTION_BUTTON_PRESS, AINPUT_SOURCE_MOUSE)
2770 .deviceId(mouseDeviceId)
2771 .buttonState(AMOTION_EVENT_BUTTON_PRIMARY)
2772 .actionButton(AMOTION_EVENT_BUTTON_PRIMARY)
2773 .pointer(PointerBuilder(0, ToolType::MOUSE).x(100).y(100))
2774 .build());
2775 leftWindow->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_BUTTON_PRESS));
2776
2777 // First touch pointer down on right window
2778 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
2779 .deviceId(touchDeviceId)
2780 .pointer(PointerBuilder(0, ToolType::FINGER).x(300).y(100))
2781 .build());
2782 leftWindow->assertNoEvents();
2783
2784 rightWindow->consumeMotionEvent(WithMotionAction(ACTION_DOWN));
2785
2786 // Second touch pointer down on left window
2787 mDispatcher->notifyMotion(MotionArgsBuilder(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
2788 .deviceId(touchDeviceId)
2789 .pointer(PointerBuilder(0, ToolType::FINGER).x(300).y(100))
2790 .pointer(PointerBuilder(1, ToolType::FINGER).x(100).y(100))
2791 .build());
2792 // Since this is now a new splittable pointer going down on the left window, and it's coming
2793 // from a different device, it will be split and delivered to left window separately.
2794 leftWindow->consumeMotionEvent(
2795 AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(touchDeviceId)));
2796 // This MOVE event is not necessary (doesn't carry any new information), but it's there in the
2797 // current implementation.
2798 const std::map<int32_t, PointF> expectedPointers{{0, PointF{100, 100}}};
2799 rightWindow->consumeMotionEvent(
2800 AllOf(WithMotionAction(ACTION_MOVE), WithPointers(expectedPointers)));
2801
2802 leftWindow->assertNoEvents();
2803 rightWindow->assertNoEvents();
2804 }
2805
2806 /**
2807 * Two windows: a window on the left and a window on the right.
2808 * Mouse is hovered on the left window and stylus is hovered on the right window.
2809 */
TEST_F(InputDispatcherMultiDeviceTest,MultiDeviceHover)2810 TEST_F(InputDispatcherMultiDeviceTest, MultiDeviceHover) {
2811 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
2812 sp<FakeWindowHandle> leftWindow = sp<FakeWindowHandle>::make(application, mDispatcher, "Left",
2813 ui::LogicalDisplayId::DEFAULT);
2814 leftWindow->setFrame(Rect(0, 0, 200, 200));
2815
2816 sp<FakeWindowHandle> rightWindow = sp<FakeWindowHandle>::make(application, mDispatcher, "Right",
2817 ui::LogicalDisplayId::DEFAULT);
2818 rightWindow->setFrame(Rect(200, 0, 400, 200));
2819
2820 mDispatcher->onWindowInfosChanged(
2821 {{*leftWindow->getInfo(), *rightWindow->getInfo()}, {}, 0, 0});
2822
2823 const int32_t stylusDeviceId = 3;
2824 const int32_t mouseDeviceId = 6;
2825
2826 // Start hovering over the left window
2827 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_ENTER, AINPUT_SOURCE_MOUSE)
2828 .deviceId(mouseDeviceId)
2829 .pointer(PointerBuilder(0, ToolType::MOUSE).x(100).y(110))
2830 .build());
2831 leftWindow->consumeMotionEvent(
2832 AllOf(WithMotionAction(ACTION_HOVER_ENTER), WithDeviceId(mouseDeviceId)));
2833
2834 // Stylus hovered on right window
2835 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_ENTER, AINPUT_SOURCE_STYLUS)
2836 .deviceId(stylusDeviceId)
2837 .pointer(PointerBuilder(0, ToolType::STYLUS).x(300).y(100))
2838 .build());
2839 rightWindow->consumeMotionEvent(
2840 AllOf(WithMotionAction(ACTION_HOVER_ENTER), WithDeviceId(stylusDeviceId)));
2841
2842 // Subsequent HOVER_MOVE events are dispatched correctly.
2843 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_MOVE, AINPUT_SOURCE_MOUSE)
2844 .deviceId(mouseDeviceId)
2845 .pointer(PointerBuilder(0, ToolType::MOUSE).x(110).y(120))
2846 .build());
2847 leftWindow->consumeMotionEvent(
2848 AllOf(WithMotionAction(ACTION_HOVER_MOVE), WithDeviceId(mouseDeviceId)));
2849
2850 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_MOVE, AINPUT_SOURCE_STYLUS)
2851 .deviceId(stylusDeviceId)
2852 .pointer(PointerBuilder(0, ToolType::STYLUS).x(310).y(110))
2853 .build());
2854 rightWindow->consumeMotionEvent(
2855 AllOf(WithMotionAction(ACTION_HOVER_MOVE), WithDeviceId(stylusDeviceId)));
2856
2857 leftWindow->assertNoEvents();
2858 rightWindow->assertNoEvents();
2859 }
2860
2861 /**
2862 * Three windows: a window on the left and a window on the right.
2863 * And a spy window that's positioned above all of them.
2864 * Stylus down on the left window and remains down. Touch goes down on the right and remains down.
2865 * Check the stream that's received by the spy.
2866 */
TEST_F(InputDispatcherMultiDeviceTest,MultiDeviceWithSpy_legacy)2867 TEST_F(InputDispatcherMultiDeviceTest, MultiDeviceWithSpy_legacy) {
2868 SCOPED_FLAG_OVERRIDE(enable_multi_device_same_window_stream, false);
2869 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
2870
2871 sp<FakeWindowHandle> spyWindow = sp<FakeWindowHandle>::make(application, mDispatcher, "Spy",
2872 ui::LogicalDisplayId::DEFAULT);
2873 spyWindow->setFrame(Rect(0, 0, 400, 400));
2874 spyWindow->setTrustedOverlay(true);
2875 spyWindow->setSpy(true);
2876
2877 sp<FakeWindowHandle> leftWindow = sp<FakeWindowHandle>::make(application, mDispatcher, "Left",
2878 ui::LogicalDisplayId::DEFAULT);
2879 leftWindow->setFrame(Rect(0, 0, 200, 200));
2880
2881 sp<FakeWindowHandle> rightWindow = sp<FakeWindowHandle>::make(application, mDispatcher, "Right",
2882 ui::LogicalDisplayId::DEFAULT);
2883
2884 rightWindow->setFrame(Rect(200, 0, 400, 200));
2885
2886 mDispatcher->onWindowInfosChanged(
2887 {{*spyWindow->getInfo(), *leftWindow->getInfo(), *rightWindow->getInfo()}, {}, 0, 0});
2888
2889 const int32_t stylusDeviceId = 1;
2890 const int32_t touchDeviceId = 2;
2891
2892 // Stylus down on the left window
2893 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_STYLUS)
2894 .deviceId(stylusDeviceId)
2895 .pointer(PointerBuilder(0, ToolType::STYLUS).x(100).y(100))
2896 .build());
2897 leftWindow->consumeMotionEvent(
2898 AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(stylusDeviceId)));
2899 spyWindow->consumeMotionEvent(
2900 AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(stylusDeviceId)));
2901
2902 // Touch down on the right window
2903 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
2904 .deviceId(touchDeviceId)
2905 .pointer(PointerBuilder(0, ToolType::FINGER).x(300).y(100))
2906 .build());
2907 leftWindow->assertNoEvents();
2908 rightWindow->consumeMotionEvent(
2909 AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(touchDeviceId)));
2910
2911 // Spy window does not receive touch events, because stylus events take precedence, and it
2912 // already has an active stylus gesture.
2913
2914 // Stylus movements continue. They should be delivered to the left window and to the spy window
2915 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_STYLUS)
2916 .deviceId(stylusDeviceId)
2917 .pointer(PointerBuilder(0, ToolType::STYLUS).x(110).y(110))
2918 .build());
2919 leftWindow->consumeMotionEvent(
2920 AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(stylusDeviceId)));
2921 spyWindow->consumeMotionEvent(
2922 AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(stylusDeviceId)));
2923
2924 // Further MOVE events keep going to the right window only
2925 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN)
2926 .deviceId(touchDeviceId)
2927 .pointer(PointerBuilder(0, ToolType::FINGER).x(310).y(110))
2928 .build());
2929 rightWindow->consumeMotionEvent(
2930 AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(touchDeviceId)));
2931
2932 spyWindow->assertNoEvents();
2933 leftWindow->assertNoEvents();
2934 rightWindow->assertNoEvents();
2935 }
2936
2937 /**
2938 * Three windows: a window on the left and a window on the right.
2939 * And a spy window that's positioned above all of them.
2940 * Stylus down on the left window and remains down. Touch goes down on the right and remains down.
2941 * Check the stream that's received by the spy.
2942 */
TEST_F(InputDispatcherMultiDeviceTest,MultiDeviceWithSpy)2943 TEST_F(InputDispatcherMultiDeviceTest, MultiDeviceWithSpy) {
2944 SCOPED_FLAG_OVERRIDE(enable_multi_device_same_window_stream, true);
2945 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
2946
2947 sp<FakeWindowHandle> spyWindow = sp<FakeWindowHandle>::make(application, mDispatcher, "Spy",
2948 ui::LogicalDisplayId::DEFAULT);
2949 spyWindow->setFrame(Rect(0, 0, 400, 400));
2950 spyWindow->setTrustedOverlay(true);
2951 spyWindow->setSpy(true);
2952
2953 sp<FakeWindowHandle> leftWindow = sp<FakeWindowHandle>::make(application, mDispatcher, "Left",
2954 ui::LogicalDisplayId::DEFAULT);
2955 leftWindow->setFrame(Rect(0, 0, 200, 200));
2956
2957 sp<FakeWindowHandle> rightWindow = sp<FakeWindowHandle>::make(application, mDispatcher, "Right",
2958 ui::LogicalDisplayId::DEFAULT);
2959
2960 rightWindow->setFrame(Rect(200, 0, 400, 200));
2961
2962 mDispatcher->onWindowInfosChanged(
2963 {{*spyWindow->getInfo(), *leftWindow->getInfo(), *rightWindow->getInfo()}, {}, 0, 0});
2964
2965 const int32_t stylusDeviceId = 1;
2966 const int32_t touchDeviceId = 2;
2967
2968 // Stylus down on the left window
2969 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_STYLUS)
2970 .deviceId(stylusDeviceId)
2971 .pointer(PointerBuilder(0, ToolType::STYLUS).x(100).y(100))
2972 .build());
2973 leftWindow->consumeMotionEvent(
2974 AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(stylusDeviceId)));
2975 spyWindow->consumeMotionEvent(
2976 AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(stylusDeviceId)));
2977
2978 // Touch down on the right window
2979 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
2980 .deviceId(touchDeviceId)
2981 .pointer(PointerBuilder(0, ToolType::FINGER).x(300).y(100))
2982 .build());
2983 leftWindow->assertNoEvents();
2984 rightWindow->consumeMotionEvent(
2985 AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(touchDeviceId)));
2986 spyWindow->consumeMotionEvent(
2987 AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(touchDeviceId)));
2988
2989 // Stylus movements continue. They should be delivered to the left window and to the spy window
2990 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_STYLUS)
2991 .deviceId(stylusDeviceId)
2992 .pointer(PointerBuilder(0, ToolType::STYLUS).x(110).y(110))
2993 .build());
2994 leftWindow->consumeMotionEvent(
2995 AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(stylusDeviceId)));
2996 spyWindow->consumeMotionEvent(
2997 AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(stylusDeviceId)));
2998
2999 // Further touch MOVE events keep going to the right window and to the spy
3000 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN)
3001 .deviceId(touchDeviceId)
3002 .pointer(PointerBuilder(0, ToolType::FINGER).x(310).y(110))
3003 .build());
3004 rightWindow->consumeMotionEvent(
3005 AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(touchDeviceId)));
3006 spyWindow->consumeMotionEvent(
3007 AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(touchDeviceId)));
3008
3009 spyWindow->assertNoEvents();
3010 leftWindow->assertNoEvents();
3011 rightWindow->assertNoEvents();
3012 }
3013
3014 /**
3015 * Three windows: a window on the left, a window on the right, and a spy window positioned above
3016 * both.
3017 * Check hover in left window and touch down in the right window.
3018 * At first, spy should receive hover. Spy shouldn't receive touch while stylus is hovering.
3019 * At the same time, left and right should be getting independent streams of hovering and touch,
3020 * respectively.
3021 */
TEST_F(InputDispatcherMultiDeviceTest,MultiDeviceHoverBlocksTouchWithSpy)3022 TEST_F(InputDispatcherMultiDeviceTest, MultiDeviceHoverBlocksTouchWithSpy) {
3023 SCOPED_FLAG_OVERRIDE(enable_multi_device_same_window_stream, false);
3024 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
3025
3026 sp<FakeWindowHandle> spyWindow = sp<FakeWindowHandle>::make(application, mDispatcher, "Spy",
3027 ui::LogicalDisplayId::DEFAULT);
3028 spyWindow->setFrame(Rect(0, 0, 400, 400));
3029 spyWindow->setTrustedOverlay(true);
3030 spyWindow->setSpy(true);
3031
3032 sp<FakeWindowHandle> leftWindow = sp<FakeWindowHandle>::make(application, mDispatcher, "Left",
3033 ui::LogicalDisplayId::DEFAULT);
3034 leftWindow->setFrame(Rect(0, 0, 200, 200));
3035
3036 sp<FakeWindowHandle> rightWindow = sp<FakeWindowHandle>::make(application, mDispatcher, "Right",
3037 ui::LogicalDisplayId::DEFAULT);
3038 rightWindow->setFrame(Rect(200, 0, 400, 200));
3039
3040 mDispatcher->onWindowInfosChanged(
3041 {{*spyWindow->getInfo(), *leftWindow->getInfo(), *rightWindow->getInfo()}, {}, 0, 0});
3042
3043 const int32_t stylusDeviceId = 1;
3044 const int32_t touchDeviceId = 2;
3045
3046 // Stylus hover on the left window
3047 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_ENTER, AINPUT_SOURCE_STYLUS)
3048 .deviceId(stylusDeviceId)
3049 .pointer(PointerBuilder(0, ToolType::STYLUS).x(100).y(100))
3050 .build());
3051 leftWindow->consumeMotionEvent(
3052 AllOf(WithMotionAction(ACTION_HOVER_ENTER), WithDeviceId(stylusDeviceId)));
3053 spyWindow->consumeMotionEvent(
3054 AllOf(WithMotionAction(ACTION_HOVER_ENTER), WithDeviceId(stylusDeviceId)));
3055
3056 // Touch down on the right window. Spy doesn't receive this touch because it already has
3057 // stylus hovering there.
3058 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
3059 .deviceId(touchDeviceId)
3060 .pointer(PointerBuilder(0, ToolType::FINGER).x(300).y(100))
3061 .build());
3062 leftWindow->assertNoEvents();
3063 spyWindow->assertNoEvents();
3064 rightWindow->consumeMotionEvent(
3065 AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(touchDeviceId)));
3066
3067 // Stylus movements continue. They should be delivered to the left window and the spy.
3068 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_MOVE, AINPUT_SOURCE_STYLUS)
3069 .deviceId(stylusDeviceId)
3070 .pointer(PointerBuilder(0, ToolType::STYLUS).x(110).y(110))
3071 .build());
3072 leftWindow->consumeMotionEvent(
3073 AllOf(WithMotionAction(ACTION_HOVER_MOVE), WithDeviceId(stylusDeviceId)));
3074 spyWindow->consumeMotionEvent(
3075 AllOf(WithMotionAction(ACTION_HOVER_MOVE), WithDeviceId(stylusDeviceId)));
3076
3077 // Touch movements continue. They should be delivered to the right window only
3078 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN)
3079 .deviceId(touchDeviceId)
3080 .pointer(PointerBuilder(0, ToolType::FINGER).x(301).y(101))
3081 .build());
3082 rightWindow->consumeMotionEvent(
3083 AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(touchDeviceId)));
3084
3085 spyWindow->assertNoEvents();
3086 leftWindow->assertNoEvents();
3087 rightWindow->assertNoEvents();
3088 }
3089
3090 /**
3091 * Three windows: a window on the left, a window on the right, and a spy window positioned above
3092 * both.
3093 * Check hover in left window and touch down in the right window.
3094 * At first, spy should receive hover. Next, spy should receive touch.
3095 * At the same time, left and right should be getting independent streams of hovering and touch,
3096 * respectively.
3097 */
TEST_F(InputDispatcherMultiDeviceTest,MultiDeviceHoverDoesNotBlockTouchWithSpy)3098 TEST_F(InputDispatcherMultiDeviceTest, MultiDeviceHoverDoesNotBlockTouchWithSpy) {
3099 SCOPED_FLAG_OVERRIDE(enable_multi_device_same_window_stream, true);
3100 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
3101
3102 sp<FakeWindowHandle> spyWindow = sp<FakeWindowHandle>::make(application, mDispatcher, "Spy",
3103 ui::LogicalDisplayId::DEFAULT);
3104 spyWindow->setFrame(Rect(0, 0, 400, 400));
3105 spyWindow->setTrustedOverlay(true);
3106 spyWindow->setSpy(true);
3107
3108 sp<FakeWindowHandle> leftWindow = sp<FakeWindowHandle>::make(application, mDispatcher, "Left",
3109 ui::LogicalDisplayId::DEFAULT);
3110 leftWindow->setFrame(Rect(0, 0, 200, 200));
3111
3112 sp<FakeWindowHandle> rightWindow = sp<FakeWindowHandle>::make(application, mDispatcher, "Right",
3113 ui::LogicalDisplayId::DEFAULT);
3114 rightWindow->setFrame(Rect(200, 0, 400, 200));
3115
3116 mDispatcher->onWindowInfosChanged(
3117 {{*spyWindow->getInfo(), *leftWindow->getInfo(), *rightWindow->getInfo()}, {}, 0, 0});
3118
3119 const int32_t stylusDeviceId = 1;
3120 const int32_t touchDeviceId = 2;
3121
3122 // Stylus hover on the left window
3123 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_ENTER, AINPUT_SOURCE_STYLUS)
3124 .deviceId(stylusDeviceId)
3125 .pointer(PointerBuilder(0, ToolType::STYLUS).x(100).y(100))
3126 .build());
3127 leftWindow->consumeMotionEvent(
3128 AllOf(WithMotionAction(ACTION_HOVER_ENTER), WithDeviceId(stylusDeviceId)));
3129 spyWindow->consumeMotionEvent(
3130 AllOf(WithMotionAction(ACTION_HOVER_ENTER), WithDeviceId(stylusDeviceId)));
3131
3132 // Touch down on the right window.
3133 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
3134 .deviceId(touchDeviceId)
3135 .pointer(PointerBuilder(0, ToolType::FINGER).x(300).y(100))
3136 .build());
3137 leftWindow->assertNoEvents();
3138 spyWindow->consumeMotionEvent(
3139 AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(touchDeviceId)));
3140 rightWindow->consumeMotionEvent(
3141 AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(touchDeviceId)));
3142
3143 // Stylus movements continue. They should be delivered to the left window and the spy.
3144 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_MOVE, AINPUT_SOURCE_STYLUS)
3145 .deviceId(stylusDeviceId)
3146 .pointer(PointerBuilder(0, ToolType::STYLUS).x(110).y(110))
3147 .build());
3148 leftWindow->consumeMotionEvent(
3149 AllOf(WithMotionAction(ACTION_HOVER_MOVE), WithDeviceId(stylusDeviceId)));
3150 spyWindow->consumeMotionEvent(
3151 AllOf(WithMotionAction(ACTION_HOVER_MOVE), WithDeviceId(stylusDeviceId)));
3152
3153 // Touch movements continue. They should be delivered to the right window and the spy
3154 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN)
3155 .deviceId(touchDeviceId)
3156 .pointer(PointerBuilder(0, ToolType::FINGER).x(301).y(101))
3157 .build());
3158 rightWindow->consumeMotionEvent(
3159 AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(touchDeviceId)));
3160 spyWindow->consumeMotionEvent(
3161 AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(touchDeviceId)));
3162
3163 spyWindow->assertNoEvents();
3164 leftWindow->assertNoEvents();
3165 rightWindow->assertNoEvents();
3166 }
3167
3168 /**
3169 * On a single window, use two different devices: mouse and touch.
3170 * Touch happens first, with two pointers going down, and then the first pointer leaving.
3171 * Mouse is clicked next, which causes the touch stream to be aborted with ACTION_CANCEL.
3172 * Finally, a second touch pointer goes down again. Ensure the second touch pointer is ignored,
3173 * because the mouse is currently down, and a POINTER_DOWN event from the touchscreen does not
3174 * represent a new gesture.
3175 */
TEST_F(InputDispatcherMultiDeviceTest,MixedTouchAndMouseWithPointerDown_legacy)3176 TEST_F(InputDispatcherMultiDeviceTest, MixedTouchAndMouseWithPointerDown_legacy) {
3177 SCOPED_FLAG_OVERRIDE(enable_multi_device_same_window_stream, false);
3178 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
3179 sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher, "Window",
3180 ui::LogicalDisplayId::DEFAULT);
3181 window->setFrame(Rect(0, 0, 400, 400));
3182
3183 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
3184
3185 const int32_t touchDeviceId = 4;
3186 const int32_t mouseDeviceId = 6;
3187
3188 // First touch pointer down
3189 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
3190 .deviceId(touchDeviceId)
3191 .pointer(PointerBuilder(0, ToolType::FINGER).x(300).y(100))
3192 .build());
3193 // Second touch pointer down
3194 mDispatcher->notifyMotion(MotionArgsBuilder(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
3195 .deviceId(touchDeviceId)
3196 .pointer(PointerBuilder(0, ToolType::FINGER).x(300).y(100))
3197 .pointer(PointerBuilder(1, ToolType::FINGER).x(350).y(100))
3198 .build());
3199 // First touch pointer lifts. The second one remains down
3200 mDispatcher->notifyMotion(MotionArgsBuilder(POINTER_0_UP, AINPUT_SOURCE_TOUCHSCREEN)
3201 .deviceId(touchDeviceId)
3202 .pointer(PointerBuilder(0, ToolType::FINGER).x(300).y(100))
3203 .pointer(PointerBuilder(1, ToolType::FINGER).x(350).y(100))
3204 .build());
3205 window->consumeMotionEvent(WithMotionAction(ACTION_DOWN));
3206 window->consumeMotionEvent(WithMotionAction(POINTER_1_DOWN));
3207 window->consumeMotionEvent(WithMotionAction(POINTER_0_UP));
3208
3209 // Mouse down. The touch should be canceled
3210 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_MOUSE)
3211 .deviceId(mouseDeviceId)
3212 .buttonState(AMOTION_EVENT_BUTTON_PRIMARY)
3213 .pointer(PointerBuilder(0, ToolType::MOUSE).x(320).y(100))
3214 .build());
3215
3216 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_CANCEL), WithDeviceId(touchDeviceId),
3217 WithPointerCount(1u)));
3218 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(mouseDeviceId)));
3219
3220 mDispatcher->notifyMotion(
3221 MotionArgsBuilder(AMOTION_EVENT_ACTION_BUTTON_PRESS, AINPUT_SOURCE_MOUSE)
3222 .deviceId(mouseDeviceId)
3223 .buttonState(AMOTION_EVENT_BUTTON_PRIMARY)
3224 .actionButton(AMOTION_EVENT_BUTTON_PRIMARY)
3225 .pointer(PointerBuilder(0, ToolType::MOUSE).x(320).y(100))
3226 .build());
3227 window->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_BUTTON_PRESS));
3228
3229 // Second touch pointer down.
3230 mDispatcher->notifyMotion(MotionArgsBuilder(POINTER_0_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
3231 .deviceId(touchDeviceId)
3232 .pointer(PointerBuilder(0, ToolType::FINGER).x(300).y(100))
3233 .pointer(PointerBuilder(1, ToolType::FINGER).x(350).y(100))
3234 .build());
3235 // Since we already canceled this touch gesture, it will be ignored until a completely new
3236 // gesture is started. This is easier to implement than trying to keep track of the new pointer
3237 // and generating an ACTION_DOWN instead of ACTION_POINTER_DOWN.
3238 // However, mouse movements should continue to work.
3239 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_MOUSE)
3240 .deviceId(mouseDeviceId)
3241 .buttonState(AMOTION_EVENT_BUTTON_PRIMARY)
3242 .pointer(PointerBuilder(0, ToolType::MOUSE).x(330).y(110))
3243 .build());
3244 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(mouseDeviceId)));
3245
3246 window->assertNoEvents();
3247 }
3248
3249 /**
3250 * On a single window, use two different devices: mouse and touch.
3251 * Touch happens first, with two pointers going down, and then the first pointer leaving.
3252 * Mouse is clicked next, which should not interfere with the touch stream.
3253 * Finally, a second touch pointer goes down again. Ensure the second touch pointer is also
3254 * delivered correctly.
3255 */
TEST_F(InputDispatcherMultiDeviceTest,MixedTouchAndMouseWithPointerDown)3256 TEST_F(InputDispatcherMultiDeviceTest, MixedTouchAndMouseWithPointerDown) {
3257 SCOPED_FLAG_OVERRIDE(enable_multi_device_same_window_stream, true);
3258 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
3259 sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher, "Window",
3260 ui::LogicalDisplayId::DEFAULT);
3261 window->setFrame(Rect(0, 0, 400, 400));
3262
3263 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
3264
3265 const int32_t touchDeviceId = 4;
3266 const int32_t mouseDeviceId = 6;
3267
3268 // First touch pointer down
3269 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
3270 .deviceId(touchDeviceId)
3271 .pointer(PointerBuilder(0, ToolType::FINGER).x(300).y(100))
3272 .build());
3273 // Second touch pointer down
3274 mDispatcher->notifyMotion(MotionArgsBuilder(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
3275 .deviceId(touchDeviceId)
3276 .pointer(PointerBuilder(0, ToolType::FINGER).x(300).y(100))
3277 .pointer(PointerBuilder(1, ToolType::FINGER).x(350).y(100))
3278 .build());
3279 // First touch pointer lifts. The second one remains down
3280 mDispatcher->notifyMotion(MotionArgsBuilder(POINTER_0_UP, AINPUT_SOURCE_TOUCHSCREEN)
3281 .deviceId(touchDeviceId)
3282 .pointer(PointerBuilder(0, ToolType::FINGER).x(300).y(100))
3283 .pointer(PointerBuilder(1, ToolType::FINGER).x(350).y(100))
3284 .build());
3285 window->consumeMotionEvent(WithMotionAction(ACTION_DOWN));
3286 window->consumeMotionEvent(WithMotionAction(POINTER_1_DOWN));
3287 window->consumeMotionEvent(WithMotionAction(POINTER_0_UP));
3288
3289 // Mouse down
3290 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_MOUSE)
3291 .deviceId(mouseDeviceId)
3292 .buttonState(AMOTION_EVENT_BUTTON_PRIMARY)
3293 .pointer(PointerBuilder(0, ToolType::MOUSE).x(320).y(100))
3294 .build());
3295
3296 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(mouseDeviceId)));
3297
3298 mDispatcher->notifyMotion(
3299 MotionArgsBuilder(AMOTION_EVENT_ACTION_BUTTON_PRESS, AINPUT_SOURCE_MOUSE)
3300 .deviceId(mouseDeviceId)
3301 .buttonState(AMOTION_EVENT_BUTTON_PRIMARY)
3302 .actionButton(AMOTION_EVENT_BUTTON_PRIMARY)
3303 .pointer(PointerBuilder(0, ToolType::MOUSE).x(320).y(100))
3304 .build());
3305 window->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_BUTTON_PRESS));
3306
3307 // Second touch pointer down.
3308 mDispatcher->notifyMotion(MotionArgsBuilder(POINTER_0_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
3309 .deviceId(touchDeviceId)
3310 .pointer(PointerBuilder(0, ToolType::FINGER).x(300).y(100))
3311 .pointer(PointerBuilder(1, ToolType::FINGER).x(350).y(100))
3312 .build());
3313 window->consumeMotionEvent(AllOf(WithMotionAction(POINTER_0_DOWN), WithDeviceId(touchDeviceId),
3314 WithPointerCount(2u)));
3315
3316 // Mouse movements should continue to work
3317 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_MOUSE)
3318 .deviceId(mouseDeviceId)
3319 .buttonState(AMOTION_EVENT_BUTTON_PRIMARY)
3320 .pointer(PointerBuilder(0, ToolType::MOUSE).x(330).y(110))
3321 .build());
3322 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(mouseDeviceId)));
3323
3324 window->assertNoEvents();
3325 }
3326
3327 /**
3328 * Inject a touch down and then send a new event via 'notifyMotion'. Ensure the new event cancels
3329 * the injected event.
3330 */
TEST_F(InputDispatcherMultiDeviceTest,UnfinishedInjectedEvent_legacy)3331 TEST_F(InputDispatcherMultiDeviceTest, UnfinishedInjectedEvent_legacy) {
3332 SCOPED_FLAG_OVERRIDE(enable_multi_device_same_window_stream, false);
3333 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
3334 sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher, "Window",
3335 ui::LogicalDisplayId::DEFAULT);
3336 window->setFrame(Rect(0, 0, 400, 400));
3337
3338 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
3339
3340 const int32_t touchDeviceId = 4;
3341 // Pretend a test injects an ACTION_DOWN mouse event, but forgets to lift up the touch after
3342 // completion.
3343 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
3344 injectMotionEvent(*mDispatcher,
3345 MotionEventBuilder(ACTION_DOWN, AINPUT_SOURCE_MOUSE)
3346 .deviceId(ReservedInputDeviceId::VIRTUAL_KEYBOARD_ID)
3347 .pointer(PointerBuilder(0, ToolType::MOUSE).x(50).y(50))
3348 .build()));
3349 window->consumeMotionEvent(
3350 AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(VIRTUAL_KEYBOARD_ID)));
3351
3352 // Now a real touch comes. Rather than crashing or dropping the real event, the injected pointer
3353 // should be canceled and the new gesture should take over.
3354 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
3355 .deviceId(touchDeviceId)
3356 .pointer(PointerBuilder(0, ToolType::FINGER).x(300).y(100))
3357 .build());
3358
3359 window->consumeMotionEvent(
3360 AllOf(WithMotionAction(ACTION_CANCEL), WithDeviceId(VIRTUAL_KEYBOARD_ID)));
3361 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(touchDeviceId)));
3362 }
3363
3364 /**
3365 * Inject a touch down and then send a new event via 'notifyMotion'. Ensure the new event runs
3366 * parallel to the injected event.
3367 */
TEST_F(InputDispatcherMultiDeviceTest,UnfinishedInjectedEvent)3368 TEST_F(InputDispatcherMultiDeviceTest, UnfinishedInjectedEvent) {
3369 SCOPED_FLAG_OVERRIDE(enable_multi_device_same_window_stream, true);
3370 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
3371 sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher, "Window",
3372 ui::LogicalDisplayId::DEFAULT);
3373 window->setFrame(Rect(0, 0, 400, 400));
3374
3375 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
3376
3377 const int32_t touchDeviceId = 4;
3378 // Pretend a test injects an ACTION_DOWN mouse event, but forgets to lift up the touch after
3379 // completion.
3380 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
3381 injectMotionEvent(*mDispatcher,
3382 MotionEventBuilder(ACTION_DOWN, AINPUT_SOURCE_MOUSE)
3383 .deviceId(ReservedInputDeviceId::VIRTUAL_KEYBOARD_ID)
3384 .pointer(PointerBuilder(0, ToolType::MOUSE).x(50).y(50))
3385 .build()));
3386 window->consumeMotionEvent(
3387 AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(VIRTUAL_KEYBOARD_ID)));
3388
3389 // Now a real touch comes. The injected pointer will remain, and the new gesture will also be
3390 // allowed through.
3391 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
3392 .deviceId(touchDeviceId)
3393 .pointer(PointerBuilder(0, ToolType::FINGER).x(300).y(100))
3394 .build());
3395 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(touchDeviceId)));
3396 }
3397
3398 /**
3399 * This test is similar to the test above, but the sequence of injected events is different.
3400 *
3401 * Two windows: a window on the left and a window on the right.
3402 * Mouse is hovered over the left window.
3403 * Next, we tap on the left window, where the cursor was last seen.
3404 *
3405 * After that, we inject one finger down onto the right window, and then a second finger down onto
3406 * the left window.
3407 * The touch is split, so this last gesture should cause 2 ACTION_DOWN events, one in the right
3408 * window (first), and then another on the left window (second).
3409 * This test reproduces a crash where there is a mismatch between the downTime and eventTime.
3410 * In the buggy implementation, second finger down on the left window would cause a crash.
3411 */
TEST_F(InputDispatcherMultiDeviceTest,HoverTapAndSplitTouch_legacy)3412 TEST_F(InputDispatcherMultiDeviceTest, HoverTapAndSplitTouch_legacy) {
3413 SCOPED_FLAG_OVERRIDE(enable_multi_device_same_window_stream, false);
3414 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
3415 sp<FakeWindowHandle> leftWindow = sp<FakeWindowHandle>::make(application, mDispatcher, "Left",
3416 ui::LogicalDisplayId::DEFAULT);
3417 leftWindow->setFrame(Rect(0, 0, 200, 200));
3418
3419 sp<FakeWindowHandle> rightWindow = sp<FakeWindowHandle>::make(application, mDispatcher, "Right",
3420 ui::LogicalDisplayId::DEFAULT);
3421 rightWindow->setFrame(Rect(200, 0, 400, 200));
3422
3423 mDispatcher->onWindowInfosChanged(
3424 {{*leftWindow->getInfo(), *rightWindow->getInfo()}, {}, 0, 0});
3425
3426 const int32_t mouseDeviceId = 6;
3427 const int32_t touchDeviceId = 4;
3428 // Hover over the left window. Keep the cursor there.
3429 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
3430 injectMotionEvent(*mDispatcher,
3431 MotionEventBuilder(AMOTION_EVENT_ACTION_HOVER_ENTER,
3432 AINPUT_SOURCE_MOUSE)
3433 .deviceId(mouseDeviceId)
3434 .pointer(PointerBuilder(0, ToolType::MOUSE).x(50).y(50))
3435 .build()));
3436 leftWindow->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_ENTER));
3437
3438 // Tap on left window
3439 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
3440 injectMotionEvent(*mDispatcher,
3441 MotionEventBuilder(AMOTION_EVENT_ACTION_DOWN,
3442 AINPUT_SOURCE_TOUCHSCREEN)
3443 .deviceId(touchDeviceId)
3444 .pointer(PointerBuilder(0, ToolType::FINGER).x(100).y(100))
3445 .build()));
3446
3447 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
3448 injectMotionEvent(*mDispatcher,
3449 MotionEventBuilder(AMOTION_EVENT_ACTION_UP,
3450 AINPUT_SOURCE_TOUCHSCREEN)
3451 .deviceId(touchDeviceId)
3452 .pointer(PointerBuilder(0, ToolType::FINGER).x(100).y(100))
3453 .build()));
3454 leftWindow->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_EXIT));
3455 leftWindow->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_DOWN));
3456 leftWindow->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_UP));
3457
3458 // First finger down on right window
3459 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
3460 injectMotionEvent(*mDispatcher,
3461 MotionEventBuilder(AMOTION_EVENT_ACTION_DOWN,
3462 AINPUT_SOURCE_TOUCHSCREEN)
3463 .deviceId(touchDeviceId)
3464 .pointer(PointerBuilder(0, ToolType::FINGER).x(300).y(100))
3465 .build()));
3466 rightWindow->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_DOWN));
3467
3468 // Second finger down on the left window
3469 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
3470 injectMotionEvent(*mDispatcher,
3471 MotionEventBuilder(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
3472 .deviceId(touchDeviceId)
3473 .pointer(PointerBuilder(0, ToolType::FINGER).x(300).y(100))
3474 .pointer(PointerBuilder(1, ToolType::FINGER).x(100).y(100))
3475 .build()));
3476 leftWindow->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_DOWN));
3477 rightWindow->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_MOVE));
3478
3479 // No more events
3480 leftWindow->assertNoEvents();
3481 rightWindow->assertNoEvents();
3482 }
3483
3484 /**
3485 * This test is similar to the test above, but the sequence of injected events is different.
3486 *
3487 * Two windows: a window on the left and a window on the right.
3488 * Mouse is hovered over the left window.
3489 * Next, we tap on the left window, where the cursor was last seen.
3490 *
3491 * After that, we send one finger down onto the right window, and then a second finger down onto
3492 * the left window.
3493 * The touch is split, so this last gesture should cause 2 ACTION_DOWN events, one in the right
3494 * window (first), and then another on the left window (second).
3495 * This test reproduces a crash where there is a mismatch between the downTime and eventTime.
3496 * In the buggy implementation, second finger down on the left window would cause a crash.
3497 */
TEST_F(InputDispatcherMultiDeviceTest,HoverTapAndSplitTouch)3498 TEST_F(InputDispatcherMultiDeviceTest, HoverTapAndSplitTouch) {
3499 SCOPED_FLAG_OVERRIDE(enable_multi_device_same_window_stream, true);
3500 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
3501 sp<FakeWindowHandle> leftWindow = sp<FakeWindowHandle>::make(application, mDispatcher, "Left",
3502 ui::LogicalDisplayId::DEFAULT);
3503 leftWindow->setFrame(Rect(0, 0, 200, 200));
3504
3505 sp<FakeWindowHandle> rightWindow = sp<FakeWindowHandle>::make(application, mDispatcher, "Right",
3506 ui::LogicalDisplayId::DEFAULT);
3507 rightWindow->setFrame(Rect(200, 0, 400, 200));
3508
3509 mDispatcher->onWindowInfosChanged(
3510 {{*leftWindow->getInfo(), *rightWindow->getInfo()}, {}, 0, 0});
3511
3512 const int32_t mouseDeviceId = 6;
3513 const int32_t touchDeviceId = 4;
3514 // Hover over the left window. Keep the cursor there.
3515 mDispatcher->notifyMotion(
3516 MotionArgsBuilder(AMOTION_EVENT_ACTION_HOVER_ENTER, AINPUT_SOURCE_MOUSE)
3517 .deviceId(mouseDeviceId)
3518 .pointer(PointerBuilder(0, ToolType::MOUSE).x(50).y(50))
3519 .build());
3520 leftWindow->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_ENTER));
3521
3522 // Tap on left window
3523 mDispatcher->notifyMotion(
3524 MotionArgsBuilder(AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
3525 .deviceId(touchDeviceId)
3526 .pointer(PointerBuilder(0, ToolType::FINGER).x(100).y(100))
3527 .build());
3528
3529 mDispatcher->notifyMotion(MotionArgsBuilder(AMOTION_EVENT_ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN)
3530 .deviceId(touchDeviceId)
3531 .pointer(PointerBuilder(0, ToolType::FINGER).x(100).y(100))
3532 .build());
3533 leftWindow->consumeMotionEvent(
3534 AllOf(WithMotionAction(AMOTION_EVENT_ACTION_DOWN), WithDeviceId(touchDeviceId)));
3535 leftWindow->consumeMotionEvent(
3536 AllOf(WithMotionAction(AMOTION_EVENT_ACTION_UP), WithDeviceId(touchDeviceId)));
3537
3538 // First finger down on right window
3539 mDispatcher->notifyMotion(
3540 MotionArgsBuilder(AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
3541 .deviceId(touchDeviceId)
3542 .pointer(PointerBuilder(0, ToolType::FINGER).x(300).y(100))
3543 .build());
3544 rightWindow->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_DOWN));
3545
3546 // Second finger down on the left window
3547 mDispatcher->notifyMotion(MotionArgsBuilder(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
3548 .deviceId(touchDeviceId)
3549 .pointer(PointerBuilder(0, ToolType::FINGER).x(300).y(100))
3550 .pointer(PointerBuilder(1, ToolType::FINGER).x(100).y(100))
3551 .build());
3552 leftWindow->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_DOWN));
3553 rightWindow->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_MOVE));
3554
3555 // No more events
3556 leftWindow->assertNoEvents();
3557 rightWindow->assertNoEvents();
3558 }
3559
3560 /**
3561 * Start hovering with a stylus device, and then tap with a touch device. Ensure no crash occurs.
3562 * While the touch is down, new hover events from the stylus device should be ignored. After the
3563 * touch is gone, stylus hovering should start working again.
3564 */
TEST_F(InputDispatcherMultiDeviceTest,StylusHoverIgnoresTouchTap)3565 TEST_F(InputDispatcherMultiDeviceTest, StylusHoverIgnoresTouchTap) {
3566 SCOPED_FLAG_OVERRIDE(enable_multi_device_same_window_stream, false);
3567 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
3568 sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher, "Window",
3569 ui::LogicalDisplayId::DEFAULT);
3570 window->setFrame(Rect(0, 0, 200, 200));
3571
3572 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
3573
3574 const int32_t stylusDeviceId = 5;
3575 const int32_t touchDeviceId = 4;
3576 // Start hovering with stylus
3577 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
3578 injectMotionEvent(*mDispatcher,
3579 MotionEventBuilder(ACTION_HOVER_ENTER, AINPUT_SOURCE_STYLUS)
3580 .deviceId(stylusDeviceId)
3581 .pointer(PointerBuilder(0, ToolType::STYLUS).x(50).y(50))
3582 .build()));
3583 window->consumeMotionEvent(WithMotionAction(ACTION_HOVER_ENTER));
3584
3585 // Finger down on the window
3586 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
3587 injectMotionEvent(*mDispatcher,
3588 MotionEventBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
3589 .deviceId(touchDeviceId)
3590 .pointer(PointerBuilder(0, ToolType::FINGER).x(100).y(100))
3591 .build()));
3592 // The touch device should be ignored!
3593
3594 // Continue hovering with stylus.
3595 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
3596 injectMotionEvent(*mDispatcher,
3597 MotionEventBuilder(AMOTION_EVENT_ACTION_HOVER_MOVE,
3598 AINPUT_SOURCE_STYLUS)
3599 .deviceId(stylusDeviceId)
3600 .pointer(PointerBuilder(0, ToolType::STYLUS).x(60).y(60))
3601 .build()));
3602 // Hovers continue to work
3603 window->consumeMotionEvent(
3604 AllOf(WithMotionAction(ACTION_HOVER_MOVE), WithDeviceId(stylusDeviceId)));
3605
3606 // Lift up the finger
3607 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
3608 injectMotionEvent(*mDispatcher,
3609 MotionEventBuilder(AMOTION_EVENT_ACTION_UP,
3610 AINPUT_SOURCE_TOUCHSCREEN)
3611 .deviceId(touchDeviceId)
3612 .pointer(PointerBuilder(0, ToolType::FINGER).x(100).y(100))
3613 .build()));
3614
3615 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
3616 injectMotionEvent(*mDispatcher,
3617 MotionEventBuilder(AMOTION_EVENT_ACTION_HOVER_MOVE,
3618 AINPUT_SOURCE_STYLUS)
3619 .deviceId(stylusDeviceId)
3620 .pointer(PointerBuilder(0, ToolType::STYLUS).x(70).y(70))
3621 .build()));
3622 window->consumeMotionEvent(
3623 AllOf(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_MOVE), WithDeviceId(stylusDeviceId)));
3624 window->assertNoEvents();
3625 }
3626
3627 /**
3628 * Start hovering with a stylus device, and then tap with a touch device. Ensure no crash occurs.
3629 * While the touch is down, hovering from the stylus is not affected. After the touch is gone,
3630 * check that the stylus hovering continues to work.
3631 */
TEST_F(InputDispatcherMultiDeviceTest,StylusHoverWithTouchTap)3632 TEST_F(InputDispatcherMultiDeviceTest, StylusHoverWithTouchTap) {
3633 SCOPED_FLAG_OVERRIDE(enable_multi_device_same_window_stream, true);
3634 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
3635 sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher, "Window",
3636 ui::LogicalDisplayId::DEFAULT);
3637 window->setFrame(Rect(0, 0, 200, 200));
3638
3639 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
3640
3641 const int32_t stylusDeviceId = 5;
3642 const int32_t touchDeviceId = 4;
3643 // Start hovering with stylus
3644 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_ENTER, AINPUT_SOURCE_STYLUS)
3645 .deviceId(stylusDeviceId)
3646 .pointer(PointerBuilder(0, ToolType::STYLUS).x(50).y(50))
3647 .build());
3648 window->consumeMotionEvent(WithMotionAction(ACTION_HOVER_ENTER));
3649
3650 // Finger down on the window
3651 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
3652 .deviceId(touchDeviceId)
3653 .pointer(PointerBuilder(0, ToolType::FINGER).x(100).y(100))
3654 .build());
3655 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(touchDeviceId)));
3656
3657 // Continue hovering with stylus.
3658 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_MOVE, AINPUT_SOURCE_STYLUS)
3659 .deviceId(stylusDeviceId)
3660 .pointer(PointerBuilder(0, ToolType::STYLUS).x(60).y(60))
3661 .build());
3662 // Hovers continue to work
3663 window->consumeMotionEvent(
3664 AllOf(WithMotionAction(ACTION_HOVER_MOVE), WithDeviceId(stylusDeviceId)));
3665
3666 // Lift up the finger
3667 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN)
3668 .deviceId(touchDeviceId)
3669 .pointer(PointerBuilder(0, ToolType::FINGER).x(100).y(100))
3670 .build());
3671 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_UP), WithDeviceId(touchDeviceId)));
3672
3673 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_MOVE, AINPUT_SOURCE_STYLUS)
3674 .deviceId(stylusDeviceId)
3675 .pointer(PointerBuilder(0, ToolType::STYLUS).x(70).y(70))
3676 .build());
3677 window->consumeMotionEvent(
3678 AllOf(WithMotionAction(ACTION_HOVER_MOVE), WithDeviceId(stylusDeviceId)));
3679 window->assertNoEvents();
3680 }
3681
3682 /**
3683 * If stylus is down anywhere on the screen, then touches should not be delivered to windows that
3684 * have InputConfig::GLOBAL_STYLUS_BLOCKS_TOUCH.
3685 *
3686 * Two windows: one on the left and one on the right.
3687 * The window on the right has GLOBAL_STYLUS_BLOCKS_TOUCH config.
3688 * Stylus down on the left window, and then touch down on the right window.
3689 * Check that the right window doesn't get touches while the stylus is down on the left window.
3690 */
TEST_F(InputDispatcherMultiDeviceTest,GlobalStylusDownBlocksTouch)3691 TEST_F(InputDispatcherMultiDeviceTest, GlobalStylusDownBlocksTouch) {
3692 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
3693 sp<FakeWindowHandle> leftWindow =
3694 sp<FakeWindowHandle>::make(application, mDispatcher, "Left window",
3695 ui::LogicalDisplayId::DEFAULT);
3696 leftWindow->setFrame(Rect(0, 0, 100, 100));
3697
3698 sp<FakeWindowHandle> sbtRightWindow =
3699 sp<FakeWindowHandle>::make(application, mDispatcher,
3700 "Stylus blocks touch (right) window",
3701 ui::LogicalDisplayId::DEFAULT);
3702 sbtRightWindow->setFrame(Rect(100, 100, 200, 200));
3703 sbtRightWindow->setGlobalStylusBlocksTouch(true);
3704
3705 mDispatcher->onWindowInfosChanged(
3706 {{*leftWindow->getInfo(), *sbtRightWindow->getInfo()}, {}, 0, 0});
3707
3708 const int32_t stylusDeviceId = 5;
3709 const int32_t touchDeviceId = 4;
3710
3711 // Stylus down in the left window
3712 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_STYLUS)
3713 .pointer(PointerBuilder(0, ToolType::STYLUS).x(50).y(52))
3714 .deviceId(stylusDeviceId)
3715 .build());
3716 leftWindow->consumeMotionEvent(
3717 AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(stylusDeviceId)));
3718
3719 // Finger tap on the right window
3720 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
3721 .pointer(PointerBuilder(0, ToolType::FINGER).x(150).y(151))
3722 .deviceId(touchDeviceId)
3723 .build());
3724 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN)
3725 .pointer(PointerBuilder(0, ToolType::FINGER).x(150).y(151))
3726 .deviceId(touchDeviceId)
3727 .build());
3728
3729 // The touch should be blocked, because stylus is down somewhere else on screen!
3730 sbtRightWindow->assertNoEvents();
3731
3732 // Continue stylus motion, and ensure it's not impacted.
3733 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_STYLUS)
3734 .pointer(PointerBuilder(0, ToolType::STYLUS).x(51).y(53))
3735 .deviceId(stylusDeviceId)
3736 .build());
3737 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_UP, AINPUT_SOURCE_STYLUS)
3738 .pointer(PointerBuilder(0, ToolType::STYLUS).x(51).y(53))
3739 .deviceId(stylusDeviceId)
3740 .build());
3741 leftWindow->consumeMotionEvent(
3742 AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(stylusDeviceId)));
3743 leftWindow->consumeMotionEvent(
3744 AllOf(WithMotionAction(ACTION_UP), WithDeviceId(stylusDeviceId)));
3745
3746 // Now that the stylus gesture is done, touches should be getting delivered correctly.
3747 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
3748 .pointer(PointerBuilder(0, ToolType::FINGER).x(151).y(153))
3749 .deviceId(touchDeviceId)
3750 .build());
3751 sbtRightWindow->consumeMotionEvent(
3752 AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(touchDeviceId)));
3753 }
3754
3755 /**
3756 * If stylus is hovering anywhere on the screen, then touches should not be delivered to windows
3757 * that have InputConfig::GLOBAL_STYLUS_BLOCKS_TOUCH.
3758 *
3759 * Two windows: one on the left and one on the right.
3760 * The window on the right has GLOBAL_STYLUS_BLOCKS_TOUCH config.
3761 * Stylus hover on the left window, and then touch down on the right window.
3762 * Check that the right window doesn't get touches while the stylus is hovering on the left window.
3763 */
TEST_F(InputDispatcherMultiDeviceTest,GlobalStylusHoverBlocksTouch)3764 TEST_F(InputDispatcherMultiDeviceTest, GlobalStylusHoverBlocksTouch) {
3765 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
3766 sp<FakeWindowHandle> leftWindow =
3767 sp<FakeWindowHandle>::make(application, mDispatcher, "Left window",
3768 ui::LogicalDisplayId::DEFAULT);
3769 leftWindow->setFrame(Rect(0, 0, 100, 100));
3770
3771 sp<FakeWindowHandle> sbtRightWindow =
3772 sp<FakeWindowHandle>::make(application, mDispatcher,
3773 "Stylus blocks touch (right) window",
3774 ui::LogicalDisplayId::DEFAULT);
3775 sbtRightWindow->setFrame(Rect(100, 100, 200, 200));
3776 sbtRightWindow->setGlobalStylusBlocksTouch(true);
3777
3778 mDispatcher->onWindowInfosChanged(
3779 {{*leftWindow->getInfo(), *sbtRightWindow->getInfo()}, {}, 0, 0});
3780
3781 const int32_t stylusDeviceId = 5;
3782 const int32_t touchDeviceId = 4;
3783
3784 // Stylus hover in the left window
3785 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_ENTER, AINPUT_SOURCE_STYLUS)
3786 .pointer(PointerBuilder(0, ToolType::STYLUS).x(50).y(52))
3787 .deviceId(stylusDeviceId)
3788 .build());
3789 leftWindow->consumeMotionEvent(
3790 AllOf(WithMotionAction(ACTION_HOVER_ENTER), WithDeviceId(stylusDeviceId)));
3791
3792 // Finger tap on the right window
3793 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
3794 .pointer(PointerBuilder(0, ToolType::FINGER).x(150).y(151))
3795 .deviceId(touchDeviceId)
3796 .build());
3797 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN)
3798 .pointer(PointerBuilder(0, ToolType::FINGER).x(150).y(151))
3799 .deviceId(touchDeviceId)
3800 .build());
3801
3802 // The touch should be blocked, because stylus is hovering somewhere else on screen!
3803 sbtRightWindow->assertNoEvents();
3804
3805 // Continue stylus motion, and ensure it's not impacted.
3806 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_MOVE, AINPUT_SOURCE_STYLUS)
3807 .pointer(PointerBuilder(0, ToolType::STYLUS).x(51).y(53))
3808 .deviceId(stylusDeviceId)
3809 .build());
3810 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_EXIT, AINPUT_SOURCE_STYLUS)
3811 .pointer(PointerBuilder(0, ToolType::STYLUS).x(51).y(53))
3812 .deviceId(stylusDeviceId)
3813 .build());
3814 leftWindow->consumeMotionEvent(
3815 AllOf(WithMotionAction(ACTION_HOVER_MOVE), WithDeviceId(stylusDeviceId)));
3816 leftWindow->consumeMotionEvent(
3817 AllOf(WithMotionAction(ACTION_HOVER_EXIT), WithDeviceId(stylusDeviceId)));
3818
3819 // Now that the stylus gesture is done, touches should be getting delivered correctly.
3820 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
3821 .pointer(PointerBuilder(0, ToolType::FINGER).x(151).y(153))
3822 .deviceId(touchDeviceId)
3823 .build());
3824 sbtRightWindow->consumeMotionEvent(
3825 AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(touchDeviceId)));
3826 }
3827
3828 /**
3829 * A spy window above a window with no input channel.
3830 * Start hovering with a stylus device, and then tap with it.
3831 * Ensure spy window receives the entire sequence.
3832 */
TEST_F(InputDispatcherTest,StylusHoverAndDownNoInputChannel)3833 TEST_F(InputDispatcherTest, StylusHoverAndDownNoInputChannel) {
3834 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
3835 sp<FakeWindowHandle> spyWindow = sp<FakeWindowHandle>::make(application, mDispatcher, "Spy",
3836 ui::LogicalDisplayId::DEFAULT);
3837 spyWindow->setFrame(Rect(0, 0, 200, 200));
3838 spyWindow->setTrustedOverlay(true);
3839 spyWindow->setSpy(true);
3840 sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher, "Window",
3841 ui::LogicalDisplayId::DEFAULT);
3842 window->setNoInputChannel(true);
3843 window->setFrame(Rect(0, 0, 200, 200));
3844
3845 mDispatcher->onWindowInfosChanged({{*spyWindow->getInfo(), *window->getInfo()}, {}, 0, 0});
3846
3847 // Start hovering with stylus
3848 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_ENTER, AINPUT_SOURCE_STYLUS)
3849 .pointer(PointerBuilder(0, ToolType::STYLUS).x(50).y(50))
3850 .build());
3851 spyWindow->consumeMotionEvent(WithMotionAction(ACTION_HOVER_ENTER));
3852 // Stop hovering
3853 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_EXIT, AINPUT_SOURCE_STYLUS)
3854 .pointer(PointerBuilder(0, ToolType::STYLUS).x(50).y(50))
3855 .build());
3856 spyWindow->consumeMotionEvent(WithMotionAction(ACTION_HOVER_EXIT));
3857
3858 // Stylus touches down
3859 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_STYLUS)
3860 .pointer(PointerBuilder(0, ToolType::STYLUS).x(50).y(50))
3861 .build());
3862 spyWindow->consumeMotionEvent(WithMotionAction(ACTION_DOWN));
3863
3864 // Stylus goes up
3865 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_UP, AINPUT_SOURCE_STYLUS)
3866 .pointer(PointerBuilder(0, ToolType::STYLUS).x(50).y(50))
3867 .build());
3868 spyWindow->consumeMotionEvent(WithMotionAction(ACTION_UP));
3869
3870 // Again hover
3871 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_ENTER, AINPUT_SOURCE_STYLUS)
3872 .pointer(PointerBuilder(0, ToolType::STYLUS).x(50).y(50))
3873 .build());
3874 spyWindow->consumeMotionEvent(WithMotionAction(ACTION_HOVER_ENTER));
3875 // Stop hovering
3876 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_EXIT, AINPUT_SOURCE_STYLUS)
3877 .pointer(PointerBuilder(0, ToolType::STYLUS).x(50).y(50))
3878 .build());
3879 spyWindow->consumeMotionEvent(WithMotionAction(ACTION_HOVER_EXIT));
3880
3881 // No more events
3882 spyWindow->assertNoEvents();
3883 window->assertNoEvents();
3884 }
3885
3886 /**
3887 * A stale stylus HOVER_EXIT event is injected. Since it's a stale event, it should generally be
3888 * rejected. But since we already have an ongoing gesture, this event should be processed.
3889 * This prevents inconsistent events being handled inside the dispatcher.
3890 */
TEST_F(InputDispatcherTest,StaleStylusHoverGestureIsComplete)3891 TEST_F(InputDispatcherTest, StaleStylusHoverGestureIsComplete) {
3892 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
3893
3894 sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher, "Window",
3895 ui::LogicalDisplayId::DEFAULT);
3896 window->setFrame(Rect(0, 0, 200, 200));
3897
3898 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
3899
3900 // Start hovering with stylus
3901 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_ENTER, AINPUT_SOURCE_STYLUS)
3902 .pointer(PointerBuilder(0, ToolType::STYLUS).x(50).y(50))
3903 .build());
3904 window->consumeMotionEvent(WithMotionAction(ACTION_HOVER_ENTER));
3905
3906 NotifyMotionArgs hoverExit = MotionArgsBuilder(ACTION_HOVER_EXIT, AINPUT_SOURCE_STYLUS)
3907 .pointer(PointerBuilder(0, ToolType::STYLUS).x(50).y(50))
3908 .build();
3909 // Make this 'hoverExit' event stale
3910 mFakePolicy->setStaleEventTimeout(100ms);
3911 std::this_thread::sleep_for(100ms);
3912
3913 // It shouldn't be dropped by the dispatcher, even though it's stale.
3914 mDispatcher->notifyMotion(hoverExit);
3915 window->consumeMotionEvent(WithMotionAction(ACTION_HOVER_EXIT));
3916
3917 // Stylus starts hovering again! There should be no crash.
3918 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_ENTER, AINPUT_SOURCE_STYLUS)
3919 .pointer(PointerBuilder(0, ToolType::STYLUS).x(51).y(51))
3920 .build());
3921 window->consumeMotionEvent(WithMotionAction(ACTION_HOVER_ENTER));
3922 }
3923
3924 /**
3925 * Start hovering with a mouse, and then tap with a touch device. Pilfer the touch stream.
3926 * Next, click with the mouse device. Both windows (spy and regular) should receive the new mouse
3927 * ACTION_DOWN event because that's a new gesture, and pilfering should no longer be active.
3928 * While the mouse is down, new move events from the touch device should be ignored.
3929 */
TEST_F(InputDispatcherTest,TouchPilferAndMouseMove_legacy)3930 TEST_F(InputDispatcherTest, TouchPilferAndMouseMove_legacy) {
3931 SCOPED_FLAG_OVERRIDE(enable_multi_device_same_window_stream, false);
3932 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
3933 sp<FakeWindowHandle> spyWindow = sp<FakeWindowHandle>::make(application, mDispatcher, "Spy",
3934 ui::LogicalDisplayId::DEFAULT);
3935 spyWindow->setFrame(Rect(0, 0, 200, 200));
3936 spyWindow->setTrustedOverlay(true);
3937 spyWindow->setSpy(true);
3938 sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher, "Window",
3939 ui::LogicalDisplayId::DEFAULT);
3940 window->setFrame(Rect(0, 0, 200, 200));
3941
3942 mDispatcher->onWindowInfosChanged({{*spyWindow->getInfo(), *window->getInfo()}, {}, 0, 0});
3943
3944 const int32_t mouseDeviceId = 7;
3945 const int32_t touchDeviceId = 4;
3946
3947 // Hover a bit with mouse first
3948 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_ENTER, AINPUT_SOURCE_MOUSE)
3949 .deviceId(mouseDeviceId)
3950 .pointer(PointerBuilder(0, ToolType::MOUSE).x(100).y(100))
3951 .build());
3952 spyWindow->consumeMotionEvent(
3953 AllOf(WithMotionAction(ACTION_HOVER_ENTER), WithDeviceId(mouseDeviceId)));
3954 window->consumeMotionEvent(
3955 AllOf(WithMotionAction(ACTION_HOVER_ENTER), WithDeviceId(mouseDeviceId)));
3956
3957 // Start touching
3958 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
3959 .deviceId(touchDeviceId)
3960 .pointer(PointerBuilder(0, ToolType::FINGER).x(50).y(50))
3961 .build());
3962 spyWindow->consumeMotionEvent(WithMotionAction(ACTION_HOVER_EXIT));
3963 window->consumeMotionEvent(WithMotionAction(ACTION_HOVER_EXIT));
3964 spyWindow->consumeMotionEvent(WithMotionAction(ACTION_DOWN));
3965 window->consumeMotionEvent(WithMotionAction(ACTION_DOWN));
3966
3967 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN)
3968 .deviceId(touchDeviceId)
3969 .pointer(PointerBuilder(0, ToolType::FINGER).x(55).y(55))
3970 .build());
3971 spyWindow->consumeMotionEvent(WithMotionAction(ACTION_MOVE));
3972 window->consumeMotionEvent(WithMotionAction(ACTION_MOVE));
3973
3974 // Pilfer the stream
3975 EXPECT_EQ(OK, mDispatcher->pilferPointers(spyWindow->getToken()));
3976 window->consumeMotionEvent(WithMotionAction(ACTION_CANCEL));
3977
3978 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN)
3979 .deviceId(touchDeviceId)
3980 .pointer(PointerBuilder(0, ToolType::FINGER).x(60).y(60))
3981 .build());
3982 spyWindow->consumeMotionEvent(WithMotionAction(ACTION_MOVE));
3983
3984 // Mouse down
3985 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_MOUSE)
3986 .deviceId(mouseDeviceId)
3987 .buttonState(AMOTION_EVENT_BUTTON_PRIMARY)
3988 .pointer(PointerBuilder(0, ToolType::MOUSE).x(100).y(100))
3989 .build());
3990
3991 spyWindow->consumeMotionEvent(
3992 AllOf(WithMotionAction(ACTION_CANCEL), WithDeviceId(touchDeviceId)));
3993 spyWindow->consumeMotionEvent(
3994 AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(mouseDeviceId)));
3995 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(mouseDeviceId)));
3996
3997 mDispatcher->notifyMotion(
3998 MotionArgsBuilder(AMOTION_EVENT_ACTION_BUTTON_PRESS, AINPUT_SOURCE_MOUSE)
3999 .deviceId(mouseDeviceId)
4000 .buttonState(AMOTION_EVENT_BUTTON_PRIMARY)
4001 .actionButton(AMOTION_EVENT_BUTTON_PRIMARY)
4002 .pointer(PointerBuilder(0, ToolType::MOUSE).x(100).y(100))
4003 .build());
4004 spyWindow->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_BUTTON_PRESS));
4005 window->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_BUTTON_PRESS));
4006
4007 // Mouse move!
4008 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_MOUSE)
4009 .deviceId(mouseDeviceId)
4010 .buttonState(AMOTION_EVENT_BUTTON_PRIMARY)
4011 .pointer(PointerBuilder(0, ToolType::MOUSE).x(110).y(110))
4012 .build());
4013 spyWindow->consumeMotionEvent(WithMotionAction(ACTION_MOVE));
4014 window->consumeMotionEvent(WithMotionAction(ACTION_MOVE));
4015
4016 // Touch move!
4017 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN)
4018 .deviceId(touchDeviceId)
4019 .pointer(PointerBuilder(0, ToolType::FINGER).x(65).y(65))
4020 .build());
4021
4022 // No more events
4023 spyWindow->assertNoEvents();
4024 window->assertNoEvents();
4025 }
4026
4027 /**
4028 * Start hovering with a mouse, and then tap with a touch device. Pilfer the touch stream.
4029 * Next, click with the mouse device. Both windows (spy and regular) should receive the new mouse
4030 * ACTION_DOWN event because that's a new gesture, and pilfering should no longer be active.
4031 * While the mouse is down, new move events from the touch device should continue to work.
4032 */
TEST_F(InputDispatcherTest,TouchPilferAndMouseMove)4033 TEST_F(InputDispatcherTest, TouchPilferAndMouseMove) {
4034 SCOPED_FLAG_OVERRIDE(enable_multi_device_same_window_stream, true);
4035 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
4036 sp<FakeWindowHandle> spyWindow = sp<FakeWindowHandle>::make(application, mDispatcher, "Spy",
4037 ui::LogicalDisplayId::DEFAULT);
4038 spyWindow->setFrame(Rect(0, 0, 200, 200));
4039 spyWindow->setTrustedOverlay(true);
4040 spyWindow->setSpy(true);
4041 sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher, "Window",
4042 ui::LogicalDisplayId::DEFAULT);
4043 window->setFrame(Rect(0, 0, 200, 200));
4044
4045 mDispatcher->onWindowInfosChanged({{*spyWindow->getInfo(), *window->getInfo()}, {}, 0, 0});
4046
4047 const int32_t mouseDeviceId = 7;
4048 const int32_t touchDeviceId = 4;
4049
4050 // Hover a bit with mouse first
4051 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_ENTER, AINPUT_SOURCE_MOUSE)
4052 .deviceId(mouseDeviceId)
4053 .pointer(PointerBuilder(0, ToolType::MOUSE).x(100).y(100))
4054 .build());
4055 spyWindow->consumeMotionEvent(
4056 AllOf(WithMotionAction(ACTION_HOVER_ENTER), WithDeviceId(mouseDeviceId)));
4057 window->consumeMotionEvent(
4058 AllOf(WithMotionAction(ACTION_HOVER_ENTER), WithDeviceId(mouseDeviceId)));
4059
4060 // Start touching
4061 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
4062 .deviceId(touchDeviceId)
4063 .pointer(PointerBuilder(0, ToolType::FINGER).x(50).y(50))
4064 .build());
4065
4066 spyWindow->consumeMotionEvent(WithMotionAction(ACTION_DOWN));
4067 window->consumeMotionEvent(WithMotionAction(ACTION_DOWN));
4068
4069 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN)
4070 .deviceId(touchDeviceId)
4071 .pointer(PointerBuilder(0, ToolType::FINGER).x(55).y(55))
4072 .build());
4073 spyWindow->consumeMotionEvent(WithMotionAction(ACTION_MOVE));
4074 window->consumeMotionEvent(WithMotionAction(ACTION_MOVE));
4075
4076 // Pilfer the stream
4077 EXPECT_EQ(OK, mDispatcher->pilferPointers(spyWindow->getToken()));
4078 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_CANCEL), WithDeviceId(touchDeviceId)));
4079 // Hover is not pilfered! Only touch.
4080
4081 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN)
4082 .deviceId(touchDeviceId)
4083 .pointer(PointerBuilder(0, ToolType::FINGER).x(60).y(60))
4084 .build());
4085 spyWindow->consumeMotionEvent(WithMotionAction(ACTION_MOVE));
4086
4087 // Mouse down
4088 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_MOUSE)
4089 .deviceId(mouseDeviceId)
4090 .buttonState(AMOTION_EVENT_BUTTON_PRIMARY)
4091 .pointer(PointerBuilder(0, ToolType::MOUSE).x(100).y(100))
4092 .build());
4093
4094 spyWindow->consumeMotionEvent(
4095 AllOf(WithMotionAction(ACTION_HOVER_EXIT), WithDeviceId(mouseDeviceId)));
4096 spyWindow->consumeMotionEvent(
4097 AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(mouseDeviceId)));
4098 window->consumeMotionEvent(
4099 AllOf(WithMotionAction(ACTION_HOVER_EXIT), WithDeviceId(mouseDeviceId)));
4100 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(mouseDeviceId)));
4101
4102 mDispatcher->notifyMotion(
4103 MotionArgsBuilder(AMOTION_EVENT_ACTION_BUTTON_PRESS, AINPUT_SOURCE_MOUSE)
4104 .deviceId(mouseDeviceId)
4105 .buttonState(AMOTION_EVENT_BUTTON_PRIMARY)
4106 .actionButton(AMOTION_EVENT_BUTTON_PRIMARY)
4107 .pointer(PointerBuilder(0, ToolType::MOUSE).x(100).y(100))
4108 .build());
4109 spyWindow->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_BUTTON_PRESS));
4110 window->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_BUTTON_PRESS));
4111
4112 // Mouse move!
4113 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_MOUSE)
4114 .deviceId(mouseDeviceId)
4115 .buttonState(AMOTION_EVENT_BUTTON_PRIMARY)
4116 .pointer(PointerBuilder(0, ToolType::MOUSE).x(110).y(110))
4117 .build());
4118 spyWindow->consumeMotionEvent(
4119 AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(mouseDeviceId)));
4120 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(mouseDeviceId)));
4121
4122 // Touch move!
4123 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN)
4124 .deviceId(touchDeviceId)
4125 .pointer(PointerBuilder(0, ToolType::FINGER).x(65).y(65))
4126 .build());
4127 spyWindow->consumeMotionEvent(
4128 AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(touchDeviceId)));
4129
4130 // No more events
4131 spyWindow->assertNoEvents();
4132 window->assertNoEvents();
4133 }
4134
4135 /**
4136 * On the display, have a single window, and also an area where there's no window.
4137 * First pointer touches the "no window" area of the screen. Second pointer touches the window.
4138 * Make sure that the window receives the second pointer, and first pointer is simply ignored.
4139 */
TEST_F(InputDispatcherTest,SplitWorksWhenEmptyAreaIsTouched)4140 TEST_F(InputDispatcherTest, SplitWorksWhenEmptyAreaIsTouched) {
4141 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
4142 sp<FakeWindowHandle> window =
4143 sp<FakeWindowHandle>::make(application, mDispatcher, "Window", DISPLAY_ID);
4144
4145 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
4146
4147 // Touch down on the empty space
4148 mDispatcher->notifyMotion(generateTouchArgs(AMOTION_EVENT_ACTION_DOWN, {{-1, -1}}));
4149
4150 mDispatcher->waitForIdle();
4151 window->assertNoEvents();
4152
4153 // Now touch down on the window with another pointer
4154 mDispatcher->notifyMotion(generateTouchArgs(POINTER_1_DOWN, {{-1, -1}, {10, 10}}));
4155 mDispatcher->waitForIdle();
4156 window->consumeMotionDown();
4157 }
4158
4159 /**
4160 * Same test as above, but instead of touching the empty space, the first touch goes to
4161 * non-touchable window.
4162 */
TEST_F(InputDispatcherTest,SplitWorksWhenNonTouchableWindowIsTouched)4163 TEST_F(InputDispatcherTest, SplitWorksWhenNonTouchableWindowIsTouched) {
4164 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
4165 sp<FakeWindowHandle> window1 =
4166 sp<FakeWindowHandle>::make(application, mDispatcher, "Window1", DISPLAY_ID);
4167 window1->setTouchableRegion(Region{{0, 0, 100, 100}});
4168 window1->setTouchable(false);
4169 sp<FakeWindowHandle> window2 =
4170 sp<FakeWindowHandle>::make(application, mDispatcher, "Window2", DISPLAY_ID);
4171 window2->setTouchableRegion(Region{{100, 0, 200, 100}});
4172
4173 mDispatcher->onWindowInfosChanged({{*window1->getInfo(), *window2->getInfo()}, {}, 0, 0});
4174
4175 // Touch down on the non-touchable window
4176 mDispatcher->notifyMotion(generateTouchArgs(AMOTION_EVENT_ACTION_DOWN, {{50, 50}}));
4177
4178 mDispatcher->waitForIdle();
4179 window1->assertNoEvents();
4180 window2->assertNoEvents();
4181
4182 // Now touch down on the window with another pointer
4183 mDispatcher->notifyMotion(generateTouchArgs(POINTER_1_DOWN, {{50, 50}, {150, 50}}));
4184 mDispatcher->waitForIdle();
4185 window2->consumeMotionDown();
4186 }
4187
4188 /**
4189 * When splitting touch events the downTime should be adjusted such that the downTime corresponds
4190 * to the event time of the first ACTION_DOWN sent to the particular window.
4191 */
TEST_F(InputDispatcherTest,SplitTouchesSendCorrectActionDownTime)4192 TEST_F(InputDispatcherTest, SplitTouchesSendCorrectActionDownTime) {
4193 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
4194 sp<FakeWindowHandle> window1 =
4195 sp<FakeWindowHandle>::make(application, mDispatcher, "Window1", DISPLAY_ID);
4196 window1->setTouchableRegion(Region{{0, 0, 100, 100}});
4197 sp<FakeWindowHandle> window2 =
4198 sp<FakeWindowHandle>::make(application, mDispatcher, "Window2", DISPLAY_ID);
4199 window2->setTouchableRegion(Region{{100, 0, 200, 100}});
4200
4201 mDispatcher->onWindowInfosChanged({{*window1->getInfo(), *window2->getInfo()}, {}, 0, 0});
4202
4203 // Touch down on the first window
4204 mDispatcher->notifyMotion(generateTouchArgs(AMOTION_EVENT_ACTION_DOWN, {{50, 50}}));
4205 mDispatcher->waitForIdle();
4206
4207 const std::unique_ptr<MotionEvent> firstDown =
4208 window1->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN)));
4209 ASSERT_EQ(firstDown->getDownTime(), firstDown->getEventTime());
4210 window2->assertNoEvents();
4211
4212 // Now touch down on the window with another pointer
4213 mDispatcher->notifyMotion(generateTouchArgs(POINTER_1_DOWN, {{50, 50}, {150, 50}}));
4214 mDispatcher->waitForIdle();
4215
4216 const std::unique_ptr<MotionEvent> secondDown =
4217 window2->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN)));
4218 ASSERT_EQ(secondDown->getDownTime(), secondDown->getEventTime());
4219 ASSERT_NE(firstDown->getDownTime(), secondDown->getDownTime());
4220 // We currently send MOVE events to all windows receiving a split touch when there is any change
4221 // in the touch state, even when none of the pointers in the split window actually moved.
4222 // Document this behavior in the test.
4223 window1->consumeMotionMove();
4224
4225 // Now move the pointer on the second window
4226 mDispatcher->notifyMotion(generateTouchArgs(AMOTION_EVENT_ACTION_MOVE, {{50, 50}, {151, 51}}));
4227 mDispatcher->waitForIdle();
4228
4229 window2->consumeMotionEvent(WithDownTime(secondDown->getDownTime()));
4230 window1->consumeMotionEvent(WithDownTime(firstDown->getDownTime()));
4231
4232 // Now add new touch down on the second window
4233 mDispatcher->notifyMotion(generateTouchArgs(POINTER_2_DOWN, {{50, 50}, {151, 51}, {150, 50}}));
4234 mDispatcher->waitForIdle();
4235
4236 window2->consumeMotionEvent(
4237 AllOf(WithMotionAction(POINTER_1_DOWN), WithDownTime(secondDown->getDownTime())));
4238 window1->consumeMotionEvent(WithDownTime(firstDown->getDownTime()));
4239
4240 // Now move the pointer on the first window
4241 mDispatcher->notifyMotion(
4242 generateTouchArgs(AMOTION_EVENT_ACTION_MOVE, {{51, 51}, {151, 51}, {150, 50}}));
4243 mDispatcher->waitForIdle();
4244
4245 window1->consumeMotionEvent(WithDownTime(firstDown->getDownTime()));
4246 window2->consumeMotionEvent(WithDownTime(secondDown->getDownTime()));
4247
4248 // Now add new touch down on the first window
4249 mDispatcher->notifyMotion(
4250 generateTouchArgs(POINTER_3_DOWN, {{51, 51}, {151, 51}, {150, 50}, {50, 50}}));
4251 mDispatcher->waitForIdle();
4252
4253 window1->consumeMotionEvent(
4254 AllOf(WithMotionAction(POINTER_1_DOWN), WithDownTime(firstDown->getDownTime())));
4255 window2->consumeMotionEvent(WithDownTime(secondDown->getDownTime()));
4256 }
4257
4258 /**
4259 * When events are not split, the downTime should be adjusted such that the downTime corresponds
4260 * to the event time of the first ACTION_DOWN. If a new window appears, it should not affect
4261 * the event routing because the first window prevents splitting.
4262 */
TEST_F(InputDispatcherTest,SplitTouchesSendCorrectActionDownTimeForNewWindow)4263 TEST_F(InputDispatcherTest, SplitTouchesSendCorrectActionDownTimeForNewWindow) {
4264 SCOPED_FLAG_OVERRIDE(split_all_touches, false);
4265 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
4266 sp<FakeWindowHandle> window1 =
4267 sp<FakeWindowHandle>::make(application, mDispatcher, "Window1", DISPLAY_ID);
4268 window1->setTouchableRegion(Region{{0, 0, 100, 100}});
4269 window1->setPreventSplitting(true);
4270
4271 sp<FakeWindowHandle> window2 =
4272 sp<FakeWindowHandle>::make(application, mDispatcher, "Window2", DISPLAY_ID);
4273 window2->setTouchableRegion(Region{{100, 0, 200, 100}});
4274
4275 mDispatcher->onWindowInfosChanged({{*window1->getInfo()}, {}, 0, 0});
4276
4277 // Touch down on the first window
4278 NotifyMotionArgs downArgs = MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
4279 .pointer(PointerBuilder(0, ToolType::FINGER).x(50).y(50))
4280 .build();
4281 mDispatcher->notifyMotion(downArgs);
4282
4283 window1->consumeMotionEvent(
4284 AllOf(WithMotionAction(ACTION_DOWN), WithDownTime(downArgs.downTime)));
4285
4286 // Second window is added
4287 mDispatcher->onWindowInfosChanged({{*window1->getInfo(), *window2->getInfo()}, {}, 0, 0});
4288
4289 // Now touch down on the window with another pointer
4290 mDispatcher->notifyMotion(MotionArgsBuilder(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
4291 .pointer(PointerBuilder(0, ToolType::FINGER).x(50).y(50))
4292 .pointer(PointerBuilder(1, ToolType::FINGER).x(150).y(50))
4293 .downTime(downArgs.downTime)
4294 .build());
4295 window1->consumeMotionPointerDown(1, AllOf(WithDownTime(downArgs.downTime)));
4296
4297 // Finish the gesture
4298 mDispatcher->notifyMotion(MotionArgsBuilder(POINTER_1_UP, AINPUT_SOURCE_TOUCHSCREEN)
4299 .pointer(PointerBuilder(0, ToolType::FINGER).x(50).y(50))
4300 .pointer(PointerBuilder(1, ToolType::FINGER).x(150).y(50))
4301 .downTime(downArgs.downTime)
4302 .build());
4303 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN)
4304 .pointer(PointerBuilder(0, ToolType::FINGER).x(50).y(50))
4305 .downTime(downArgs.downTime)
4306 .build());
4307 window1->consumeMotionPointerUp(1, AllOf(WithDownTime(downArgs.downTime)));
4308 window1->consumeMotionEvent(
4309 AllOf(WithMotionAction(ACTION_UP), WithDownTime(downArgs.downTime)));
4310 window2->assertNoEvents();
4311 }
4312
4313 /**
4314 * When splitting touch events, the downTime should be adjusted such that the downTime corresponds
4315 * to the event time of the first ACTION_DOWN sent to the new window.
4316 * If a new window that does not support split appears on the screen and gets touched with the
4317 * second finger, it should not get any events because it doesn't want split touches. At the same
4318 * time, the first window should not get the pointer_down event because it supports split touches
4319 * (and the touch occurred outside of the bounds of window1).
4320 */
TEST_F(InputDispatcherTest,SplitTouchesDropsEventForNonSplittableSecondWindow)4321 TEST_F(InputDispatcherTest, SplitTouchesDropsEventForNonSplittableSecondWindow) {
4322 SCOPED_FLAG_OVERRIDE(split_all_touches, false);
4323 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
4324 sp<FakeWindowHandle> window1 =
4325 sp<FakeWindowHandle>::make(application, mDispatcher, "Window1", DISPLAY_ID);
4326 window1->setTouchableRegion(Region{{0, 0, 100, 100}});
4327
4328 sp<FakeWindowHandle> window2 =
4329 sp<FakeWindowHandle>::make(application, mDispatcher, "Window2", DISPLAY_ID);
4330 window2->setTouchableRegion(Region{{100, 0, 200, 100}});
4331
4332 mDispatcher->onWindowInfosChanged({{*window1->getInfo()}, {}, 0, 0});
4333
4334 // Touch down on the first window
4335 NotifyMotionArgs downArgs = MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
4336 .pointer(PointerBuilder(0, ToolType::FINGER).x(50).y(50))
4337 .build();
4338 mDispatcher->notifyMotion(downArgs);
4339
4340 window1->consumeMotionEvent(
4341 AllOf(WithMotionAction(ACTION_DOWN), WithDownTime(downArgs.downTime)));
4342
4343 // Second window is added
4344 window2->setPreventSplitting(true);
4345 mDispatcher->onWindowInfosChanged({{*window1->getInfo(), *window2->getInfo()}, {}, 0, 0});
4346
4347 // Now touch down on the window with another pointer
4348 mDispatcher->notifyMotion(MotionArgsBuilder(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
4349 .pointer(PointerBuilder(0, ToolType::FINGER).x(50).y(50))
4350 .pointer(PointerBuilder(1, ToolType::FINGER).x(150).y(50))
4351 .downTime(downArgs.downTime)
4352 .build());
4353 // Event is dropped because window2 doesn't support split touch, and window1 does.
4354
4355 // Complete the gesture
4356 mDispatcher->notifyMotion(MotionArgsBuilder(POINTER_1_UP, AINPUT_SOURCE_TOUCHSCREEN)
4357 .pointer(PointerBuilder(0, ToolType::FINGER).x(50).y(50))
4358 .pointer(PointerBuilder(1, ToolType::FINGER).x(150).y(50))
4359 .downTime(downArgs.downTime)
4360 .build());
4361 // A redundant MOVE event is generated that doesn't carry any new information
4362 window1->consumeMotionEvent(
4363 AllOf(WithMotionAction(ACTION_MOVE), WithDownTime(downArgs.downTime)));
4364 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN)
4365 .pointer(PointerBuilder(0, ToolType::FINGER).x(50).y(50))
4366 .downTime(downArgs.downTime)
4367 .build());
4368
4369 window1->consumeMotionEvent(
4370 AllOf(WithMotionAction(ACTION_UP), WithDownTime(downArgs.downTime)));
4371 window1->assertNoEvents();
4372 window2->assertNoEvents();
4373 }
4374
TEST_F(InputDispatcherTest,HoverMoveEnterMouseClickAndHoverMoveExit)4375 TEST_F(InputDispatcherTest, HoverMoveEnterMouseClickAndHoverMoveExit) {
4376 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
4377 sp<FakeWindowHandle> windowLeft = sp<FakeWindowHandle>::make(application, mDispatcher, "Left",
4378 ui::LogicalDisplayId::DEFAULT);
4379 windowLeft->setFrame(Rect(0, 0, 600, 800));
4380 sp<FakeWindowHandle> windowRight = sp<FakeWindowHandle>::make(application, mDispatcher, "Right",
4381 ui::LogicalDisplayId::DEFAULT);
4382 windowRight->setFrame(Rect(600, 0, 1200, 800));
4383
4384 mDispatcher->setFocusedApplication(ui::LogicalDisplayId::DEFAULT, application);
4385
4386 mDispatcher->onWindowInfosChanged(
4387 {{*windowLeft->getInfo(), *windowRight->getInfo()}, {}, 0, 0});
4388
4389 // Start cursor position in right window so that we can move the cursor to left window.
4390 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
4391 injectMotionEvent(*mDispatcher,
4392 MotionEventBuilder(AMOTION_EVENT_ACTION_HOVER_MOVE,
4393 AINPUT_SOURCE_MOUSE)
4394 .pointer(PointerBuilder(0, ToolType::MOUSE).x(900).y(400))
4395 .build()));
4396 windowRight->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_ENTER));
4397
4398 // Move cursor into left window
4399 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
4400 injectMotionEvent(*mDispatcher,
4401 MotionEventBuilder(AMOTION_EVENT_ACTION_HOVER_MOVE,
4402 AINPUT_SOURCE_MOUSE)
4403 .pointer(PointerBuilder(0, ToolType::MOUSE).x(300).y(400))
4404 .build()));
4405 windowRight->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_EXIT));
4406 windowLeft->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_ENTER));
4407
4408 // Inject a series of mouse events for a mouse click
4409 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
4410 injectMotionEvent(*mDispatcher,
4411 MotionEventBuilder(AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_MOUSE)
4412 .buttonState(AMOTION_EVENT_BUTTON_PRIMARY)
4413 .pointer(PointerBuilder(0, ToolType::MOUSE).x(300).y(400))
4414 .build()));
4415 windowLeft->consumeMotionEvent(WithMotionAction(ACTION_HOVER_EXIT));
4416 windowLeft->consumeMotionEvent(WithMotionAction(ACTION_DOWN));
4417
4418 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
4419 injectMotionEvent(*mDispatcher,
4420 MotionEventBuilder(AMOTION_EVENT_ACTION_BUTTON_PRESS,
4421 AINPUT_SOURCE_MOUSE)
4422 .buttonState(AMOTION_EVENT_BUTTON_PRIMARY)
4423 .actionButton(AMOTION_EVENT_BUTTON_PRIMARY)
4424 .pointer(PointerBuilder(0, ToolType::MOUSE).x(300).y(400))
4425 .build()));
4426 windowLeft->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_BUTTON_PRESS));
4427
4428 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
4429 injectMotionEvent(*mDispatcher,
4430 MotionEventBuilder(AMOTION_EVENT_ACTION_BUTTON_RELEASE,
4431 AINPUT_SOURCE_MOUSE)
4432 .buttonState(0)
4433 .actionButton(AMOTION_EVENT_BUTTON_PRIMARY)
4434 .pointer(PointerBuilder(0, ToolType::MOUSE).x(300).y(400))
4435 .build()));
4436 windowLeft->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_BUTTON_RELEASE));
4437
4438 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
4439 injectMotionEvent(*mDispatcher,
4440 MotionEventBuilder(AMOTION_EVENT_ACTION_UP, AINPUT_SOURCE_MOUSE)
4441 .buttonState(0)
4442 .pointer(PointerBuilder(0, ToolType::MOUSE).x(300).y(400))
4443 .build()));
4444 windowLeft->consumeMotionUp(ui::LogicalDisplayId::DEFAULT);
4445
4446 // Move mouse cursor back to right window
4447 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
4448 injectMotionEvent(*mDispatcher,
4449 MotionEventBuilder(AMOTION_EVENT_ACTION_HOVER_MOVE,
4450 AINPUT_SOURCE_MOUSE)
4451 .pointer(PointerBuilder(0, ToolType::MOUSE).x(900).y(400))
4452 .build()));
4453 windowRight->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_ENTER));
4454
4455 // No more events
4456 windowLeft->assertNoEvents();
4457 windowRight->assertNoEvents();
4458 }
4459
4460 /**
4461 * Put two fingers down (and don't release them) and click the mouse button.
4462 * The clicking of mouse is a new ACTION_DOWN event. Since it's from a different device, the
4463 * currently active gesture should be canceled, and the new one should proceed.
4464 */
TEST_F(InputDispatcherTest,TwoPointersDownMouseClick_legacy)4465 TEST_F(InputDispatcherTest, TwoPointersDownMouseClick_legacy) {
4466 SCOPED_FLAG_OVERRIDE(enable_multi_device_same_window_stream, false);
4467 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
4468 sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher, "Window",
4469 ui::LogicalDisplayId::DEFAULT);
4470 window->setFrame(Rect(0, 0, 600, 800));
4471
4472 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
4473
4474 const int32_t touchDeviceId = 4;
4475 const int32_t mouseDeviceId = 6;
4476
4477 // Two pointers down
4478 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
4479 .deviceId(touchDeviceId)
4480 .pointer(PointerBuilder(0, ToolType::FINGER).x(100).y(100))
4481 .build());
4482
4483 mDispatcher->notifyMotion(MotionArgsBuilder(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
4484 .deviceId(touchDeviceId)
4485 .pointer(PointerBuilder(0, ToolType::FINGER).x(100).y(100))
4486 .pointer(PointerBuilder(1, ToolType::FINGER).x(120).y(120))
4487 .build());
4488 window->consumeMotionEvent(WithMotionAction(ACTION_DOWN));
4489 window->consumeMotionEvent(WithMotionAction(POINTER_1_DOWN));
4490
4491 // Inject a series of mouse events for a mouse click
4492 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_MOUSE)
4493 .deviceId(mouseDeviceId)
4494 .buttonState(AMOTION_EVENT_BUTTON_PRIMARY)
4495 .pointer(PointerBuilder(0, ToolType::MOUSE).x(300).y(400))
4496 .build());
4497 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_CANCEL), WithDeviceId(touchDeviceId),
4498 WithPointerCount(2u)));
4499 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(mouseDeviceId)));
4500
4501 mDispatcher->notifyMotion(
4502 MotionArgsBuilder(AMOTION_EVENT_ACTION_BUTTON_PRESS, AINPUT_SOURCE_MOUSE)
4503 .deviceId(mouseDeviceId)
4504 .buttonState(AMOTION_EVENT_BUTTON_PRIMARY)
4505 .actionButton(AMOTION_EVENT_BUTTON_PRIMARY)
4506 .pointer(PointerBuilder(0, ToolType::MOUSE).x(300).y(400))
4507 .build());
4508 window->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_BUTTON_PRESS));
4509
4510 // Try to send more touch events while the mouse is down. Since it's a continuation of an
4511 // already canceled gesture, it should be ignored.
4512 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN)
4513 .deviceId(touchDeviceId)
4514 .pointer(PointerBuilder(0, ToolType::FINGER).x(101).y(101))
4515 .pointer(PointerBuilder(1, ToolType::FINGER).x(121).y(121))
4516 .build());
4517 window->assertNoEvents();
4518 }
4519
4520 /**
4521 * Put two fingers down (and don't release them) and click the mouse button.
4522 * The clicking of mouse is a new ACTION_DOWN event. Since it's from a different device, the
4523 * currently active gesture should not be canceled, and the new one should proceed in parallel.
4524 */
TEST_F(InputDispatcherTest,TwoPointersDownMouseClick)4525 TEST_F(InputDispatcherTest, TwoPointersDownMouseClick) {
4526 SCOPED_FLAG_OVERRIDE(enable_multi_device_same_window_stream, true);
4527 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
4528 sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher, "Window",
4529 ui::LogicalDisplayId::DEFAULT);
4530 window->setFrame(Rect(0, 0, 600, 800));
4531
4532 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
4533
4534 const int32_t touchDeviceId = 4;
4535 const int32_t mouseDeviceId = 6;
4536
4537 // Two pointers down
4538 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
4539 .deviceId(touchDeviceId)
4540 .pointer(PointerBuilder(0, ToolType::FINGER).x(100).y(100))
4541 .build());
4542
4543 mDispatcher->notifyMotion(MotionArgsBuilder(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
4544 .deviceId(touchDeviceId)
4545 .pointer(PointerBuilder(0, ToolType::FINGER).x(100).y(100))
4546 .pointer(PointerBuilder(1, ToolType::FINGER).x(120).y(120))
4547 .build());
4548 window->consumeMotionEvent(WithMotionAction(ACTION_DOWN));
4549 window->consumeMotionEvent(WithMotionAction(POINTER_1_DOWN));
4550
4551 // Send a series of mouse events for a mouse click
4552 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_MOUSE)
4553 .deviceId(mouseDeviceId)
4554 .buttonState(AMOTION_EVENT_BUTTON_PRIMARY)
4555 .pointer(PointerBuilder(0, ToolType::MOUSE).x(300).y(400))
4556 .build());
4557 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(mouseDeviceId)));
4558
4559 mDispatcher->notifyMotion(
4560 MotionArgsBuilder(AMOTION_EVENT_ACTION_BUTTON_PRESS, AINPUT_SOURCE_MOUSE)
4561 .deviceId(mouseDeviceId)
4562 .buttonState(AMOTION_EVENT_BUTTON_PRIMARY)
4563 .actionButton(AMOTION_EVENT_BUTTON_PRIMARY)
4564 .pointer(PointerBuilder(0, ToolType::MOUSE).x(300).y(400))
4565 .build());
4566 window->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_BUTTON_PRESS));
4567
4568 // Try to send more touch events while the mouse is down. Since it's a continuation of an
4569 // already active gesture, it should be sent normally.
4570 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN)
4571 .deviceId(touchDeviceId)
4572 .pointer(PointerBuilder(0, ToolType::FINGER).x(101).y(101))
4573 .pointer(PointerBuilder(1, ToolType::FINGER).x(121).y(121))
4574 .build());
4575 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(touchDeviceId)));
4576 window->assertNoEvents();
4577 }
4578
4579 /**
4580 * A spy window sits above a window with NO_INPUT_CHANNEL. Ensure that the spy receives events even
4581 * though the window underneath should not get any events.
4582 */
TEST_F(InputDispatcherTest,NonSplittableSpyAboveNoInputChannelWindowSinglePointer)4583 TEST_F(InputDispatcherTest, NonSplittableSpyAboveNoInputChannelWindowSinglePointer) {
4584 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
4585
4586 sp<FakeWindowHandle> spyWindow = sp<FakeWindowHandle>::make(application, mDispatcher, "Spy",
4587 ui::LogicalDisplayId::DEFAULT);
4588 spyWindow->setFrame(Rect(0, 0, 100, 100));
4589 spyWindow->setTrustedOverlay(true);
4590 spyWindow->setPreventSplitting(true);
4591 spyWindow->setSpy(true);
4592 // Another window below spy that has both NO_INPUT_CHANNEL and PREVENT_SPLITTING
4593 sp<FakeWindowHandle> inputSinkWindow =
4594 sp<FakeWindowHandle>::make(application, mDispatcher, "Input sink below spy",
4595 ui::LogicalDisplayId::DEFAULT);
4596 inputSinkWindow->setFrame(Rect(0, 0, 100, 100));
4597 inputSinkWindow->setTrustedOverlay(true);
4598 inputSinkWindow->setPreventSplitting(true);
4599 inputSinkWindow->setNoInputChannel(true);
4600
4601 mDispatcher->onWindowInfosChanged(
4602 {{*spyWindow->getInfo(), *inputSinkWindow->getInfo()}, {}, 0, 0});
4603
4604 // Tap the spy window
4605 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
4606 .pointer(PointerBuilder(0, ToolType::FINGER).x(50).y(51))
4607 .build());
4608 mDispatcher->notifyMotion(
4609 MotionArgsBuilder(ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN)
4610 .pointer(PointerBuilder(/*id=*/0, ToolType::FINGER).x(50).y(51))
4611 .build());
4612
4613 spyWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN)));
4614 spyWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_UP)));
4615 inputSinkWindow->assertNoEvents();
4616 }
4617
4618 /**
4619 * A spy window sits above a window with NO_INPUT_CHANNEL. Ensure that the spy receives events even
4620 * though the window underneath should not get any events.
4621 * Same test as above, but with two pointers touching instead of one.
4622 */
TEST_F(InputDispatcherTest,NonSplittableSpyAboveNoInputChannelWindowTwoPointers)4623 TEST_F(InputDispatcherTest, NonSplittableSpyAboveNoInputChannelWindowTwoPointers) {
4624 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
4625
4626 sp<FakeWindowHandle> spyWindow = sp<FakeWindowHandle>::make(application, mDispatcher, "Spy",
4627 ui::LogicalDisplayId::DEFAULT);
4628 spyWindow->setFrame(Rect(0, 0, 100, 100));
4629 spyWindow->setTrustedOverlay(true);
4630 spyWindow->setPreventSplitting(true);
4631 spyWindow->setSpy(true);
4632 // Another window below spy that would have both NO_INPUT_CHANNEL and PREVENT_SPLITTING
4633 sp<FakeWindowHandle> inputSinkWindow =
4634 sp<FakeWindowHandle>::make(application, mDispatcher, "Input sink below spy",
4635 ui::LogicalDisplayId::DEFAULT);
4636 inputSinkWindow->setFrame(Rect(0, 0, 100, 100));
4637 inputSinkWindow->setTrustedOverlay(true);
4638 inputSinkWindow->setPreventSplitting(true);
4639 inputSinkWindow->setNoInputChannel(true);
4640
4641 mDispatcher->onWindowInfosChanged(
4642 {{*spyWindow->getInfo(), *inputSinkWindow->getInfo()}, {}, 0, 0});
4643
4644 // Both fingers land into the spy window
4645 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
4646 .pointer(PointerBuilder(0, ToolType::FINGER).x(50).y(51))
4647 .build());
4648 mDispatcher->notifyMotion(
4649 MotionArgsBuilder(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
4650 .pointer(PointerBuilder(/*id=*/0, ToolType::FINGER).x(50).y(51))
4651 .pointer(PointerBuilder(/*id=*/1, ToolType::FINGER).x(10).y(11))
4652 .build());
4653 mDispatcher->notifyMotion(
4654 MotionArgsBuilder(POINTER_1_UP, AINPUT_SOURCE_TOUCHSCREEN)
4655 .pointer(PointerBuilder(/*id=*/0, ToolType::FINGER).x(50).y(51))
4656 .pointer(PointerBuilder(/*id=*/1, ToolType::FINGER).x(10).y(11))
4657 .build());
4658 mDispatcher->notifyMotion(
4659 MotionArgsBuilder(ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN)
4660 .pointer(PointerBuilder(/*id=*/0, ToolType::FINGER).x(50).y(51))
4661 .build());
4662
4663 spyWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN)));
4664 spyWindow->consumeMotionPointerDown(1, WithPointerCount(2));
4665 spyWindow->consumeMotionPointerUp(1, WithPointerCount(2));
4666 spyWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_UP)));
4667 inputSinkWindow->assertNoEvents();
4668 }
4669
4670 /** Check the behaviour for cases where input sink prevents or doesn't prevent splitting. */
4671 class SpyThatPreventsSplittingWithApplicationFixture : public InputDispatcherTest,
4672 public ::testing::WithParamInterface<bool> {
4673 };
4674
4675 /**
4676 * Three windows:
4677 * - An application window (app window)
4678 * - A spy window that does not overlap the app window. Has PREVENT_SPLITTING flag
4679 * - A window below the spy that has NO_INPUT_CHANNEL (call it 'inputSink')
4680 *
4681 * The spy window is side-by-side with the app window. The inputSink is below the spy.
4682 * We first touch the area outside of the appWindow, but inside spyWindow.
4683 * Only the SPY window should get the DOWN event.
4684 * The spy pilfers after receiving the first DOWN event.
4685 * Next, we touch the app window.
4686 * The spy should receive POINTER_DOWN(1) (since spy is preventing splits).
4687 * Also, since the spy is already pilfering the first pointer, it will be sent the remaining new
4688 * pointers automatically, as well.
4689 * Next, the first pointer (from the spy) is lifted.
4690 * Spy should get POINTER_UP(0).
4691 * This event should not go to the app because the app never received this pointer to begin with.
4692 * Now, lift the remaining pointer and check that the spy receives UP event.
4693 *
4694 * Finally, send a new ACTION_DOWN event to the spy and check that it's received.
4695 * This test attempts to reproduce a crash in the dispatcher.
4696 */
TEST_P(SpyThatPreventsSplittingWithApplicationFixture,SpyThatPreventsSplittingWithApplication)4697 TEST_P(SpyThatPreventsSplittingWithApplicationFixture, SpyThatPreventsSplittingWithApplication) {
4698 SCOPED_FLAG_OVERRIDE(split_all_touches, false);
4699 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
4700
4701 sp<FakeWindowHandle> spyWindow = sp<FakeWindowHandle>::make(application, mDispatcher, "Spy",
4702 ui::LogicalDisplayId::DEFAULT);
4703 spyWindow->setFrame(Rect(100, 100, 200, 200));
4704 spyWindow->setTrustedOverlay(true);
4705 spyWindow->setPreventSplitting(true);
4706 spyWindow->setSpy(true);
4707 // Another window below spy that has both NO_INPUT_CHANNEL and PREVENT_SPLITTING
4708 sp<FakeWindowHandle> inputSinkWindow =
4709 sp<FakeWindowHandle>::make(application, mDispatcher, "Input sink below spy",
4710 ui::LogicalDisplayId::DEFAULT);
4711 inputSinkWindow->setFrame(Rect(100, 100, 200, 200)); // directly below the spy
4712 inputSinkWindow->setTrustedOverlay(true);
4713 inputSinkWindow->setPreventSplitting(GetParam());
4714 inputSinkWindow->setNoInputChannel(true);
4715
4716 sp<FakeWindowHandle> appWindow = sp<FakeWindowHandle>::make(application, mDispatcher, "App",
4717 ui::LogicalDisplayId::DEFAULT);
4718 appWindow->setFrame(Rect(0, 0, 100, 100));
4719
4720 mDispatcher->setFocusedApplication(ui::LogicalDisplayId::DEFAULT, application);
4721 mDispatcher->onWindowInfosChanged(
4722 {{*spyWindow->getInfo(), *inputSinkWindow->getInfo(), *appWindow->getInfo()},
4723 {},
4724 0,
4725 0});
4726
4727 // First finger lands outside of the appWindow, but inside of the spy window
4728 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
4729 .pointer(PointerBuilder(0, ToolType::FINGER).x(150).y(150))
4730 .build());
4731 spyWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN)));
4732
4733 mDispatcher->pilferPointers(spyWindow->getToken());
4734
4735 // Second finger lands in the app, and goes to the spy window. It doesn't go to the app because
4736 // the spy is already pilfering the first pointer, and this automatically grants the remaining
4737 // new pointers to the spy, as well.
4738 mDispatcher->notifyMotion(
4739 MotionArgsBuilder(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
4740 .pointer(PointerBuilder(/*id=*/0, ToolType::FINGER).x(150).y(150))
4741 .pointer(PointerBuilder(/*id=*/1, ToolType::FINGER).x(50).y(50))
4742 .build());
4743
4744 spyWindow->consumeMotionPointerDown(1, WithPointerCount(2));
4745
4746 // Now lift up the first pointer
4747 mDispatcher->notifyMotion(
4748 MotionArgsBuilder(POINTER_0_UP, AINPUT_SOURCE_TOUCHSCREEN)
4749 .pointer(PointerBuilder(/*id=*/0, ToolType::FINGER).x(150).y(150))
4750 .pointer(PointerBuilder(/*id=*/1, ToolType::FINGER).x(50).y(50))
4751 .build());
4752 spyWindow->consumeMotionPointerUp(0, WithPointerCount(2));
4753
4754 // And lift the remaining pointer!
4755 mDispatcher->notifyMotion(
4756 MotionArgsBuilder(ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN)
4757 .pointer(PointerBuilder(/*id=*/1, ToolType::FINGER).x(50).y(50))
4758 .build());
4759 spyWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_UP), WithPointerCount(1)));
4760
4761 // Now send a new DOWN, which should again go to spy.
4762 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
4763 .pointer(PointerBuilder(0, ToolType::FINGER).x(150).y(150))
4764 .build());
4765 spyWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN)));
4766 // The app window doesn't get any events this entire time because the spy received the events
4767 // first and pilfered, which makes all new pointers go to it as well.
4768 appWindow->assertNoEvents();
4769 }
4770
4771 // Behaviour should be the same regardless of whether inputSink supports splitting.
4772 INSTANTIATE_TEST_SUITE_P(SpyThatPreventsSplittingWithApplication,
4773 SpyThatPreventsSplittingWithApplicationFixture, testing::Bool());
4774
TEST_F(InputDispatcherTest,HoverWithSpyWindows)4775 TEST_F(InputDispatcherTest, HoverWithSpyWindows) {
4776 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
4777
4778 sp<FakeWindowHandle> spyWindow = sp<FakeWindowHandle>::make(application, mDispatcher, "Spy",
4779 ui::LogicalDisplayId::DEFAULT);
4780 spyWindow->setFrame(Rect(0, 0, 600, 800));
4781 spyWindow->setTrustedOverlay(true);
4782 spyWindow->setSpy(true);
4783 sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher, "Window",
4784 ui::LogicalDisplayId::DEFAULT);
4785 window->setFrame(Rect(0, 0, 600, 800));
4786
4787 mDispatcher->setFocusedApplication(ui::LogicalDisplayId::DEFAULT, application);
4788 mDispatcher->onWindowInfosChanged({{*spyWindow->getInfo(), *window->getInfo()}, {}, 0, 0});
4789
4790 // Send mouse cursor to the window
4791 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
4792 injectMotionEvent(*mDispatcher,
4793 MotionEventBuilder(AMOTION_EVENT_ACTION_HOVER_ENTER,
4794 AINPUT_SOURCE_MOUSE)
4795 .pointer(PointerBuilder(0, ToolType::MOUSE).x(100).y(100))
4796 .build()));
4797
4798 window->consumeMotionEvent(AllOf(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_ENTER),
4799 WithSource(AINPUT_SOURCE_MOUSE)));
4800 spyWindow->consumeMotionEvent(AllOf(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_ENTER),
4801 WithSource(AINPUT_SOURCE_MOUSE)));
4802
4803 window->assertNoEvents();
4804 spyWindow->assertNoEvents();
4805 }
4806
TEST_F(InputDispatcherTest,MouseAndTouchWithSpyWindows_legacy)4807 TEST_F(InputDispatcherTest, MouseAndTouchWithSpyWindows_legacy) {
4808 SCOPED_FLAG_OVERRIDE(enable_multi_device_same_window_stream, false);
4809 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
4810
4811 sp<FakeWindowHandle> spyWindow = sp<FakeWindowHandle>::make(application, mDispatcher, "Spy",
4812 ui::LogicalDisplayId::DEFAULT);
4813 spyWindow->setFrame(Rect(0, 0, 600, 800));
4814 spyWindow->setTrustedOverlay(true);
4815 spyWindow->setSpy(true);
4816 sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher, "Window",
4817 ui::LogicalDisplayId::DEFAULT);
4818 window->setFrame(Rect(0, 0, 600, 800));
4819
4820 mDispatcher->setFocusedApplication(ui::LogicalDisplayId::DEFAULT, application);
4821 mDispatcher->onWindowInfosChanged({{*spyWindow->getInfo(), *window->getInfo()}, {}, 0, 0});
4822
4823 // Send mouse cursor to the window
4824 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
4825 injectMotionEvent(*mDispatcher,
4826 MotionEventBuilder(AMOTION_EVENT_ACTION_HOVER_ENTER,
4827 AINPUT_SOURCE_MOUSE)
4828 .pointer(PointerBuilder(0, ToolType::MOUSE).x(100).y(100))
4829 .build()));
4830
4831 // Move mouse cursor
4832 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
4833 injectMotionEvent(*mDispatcher,
4834 MotionEventBuilder(AMOTION_EVENT_ACTION_HOVER_MOVE,
4835 AINPUT_SOURCE_MOUSE)
4836 .pointer(PointerBuilder(0, ToolType::MOUSE).x(110).y(110))
4837 .build()));
4838
4839 window->consumeMotionEvent(AllOf(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_ENTER),
4840 WithSource(AINPUT_SOURCE_MOUSE)));
4841 spyWindow->consumeMotionEvent(AllOf(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_ENTER),
4842 WithSource(AINPUT_SOURCE_MOUSE)));
4843 window->consumeMotionEvent(AllOf(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_MOVE),
4844 WithSource(AINPUT_SOURCE_MOUSE)));
4845 spyWindow->consumeMotionEvent(AllOf(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_MOVE),
4846 WithSource(AINPUT_SOURCE_MOUSE)));
4847 // Touch down on the window
4848 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
4849 injectMotionEvent(*mDispatcher,
4850 MotionEventBuilder(AMOTION_EVENT_ACTION_DOWN,
4851 AINPUT_SOURCE_TOUCHSCREEN)
4852 .deviceId(SECOND_DEVICE_ID)
4853 .pointer(PointerBuilder(0, ToolType::FINGER).x(200).y(200))
4854 .build()));
4855 window->consumeMotionEvent(AllOf(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_EXIT),
4856 WithSource(AINPUT_SOURCE_MOUSE)));
4857 spyWindow->consumeMotionEvent(AllOf(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_EXIT),
4858 WithSource(AINPUT_SOURCE_MOUSE)));
4859 window->consumeMotionEvent(AllOf(WithMotionAction(AMOTION_EVENT_ACTION_DOWN),
4860 WithSource(AINPUT_SOURCE_TOUCHSCREEN)));
4861 spyWindow->consumeMotionEvent(AllOf(WithMotionAction(AMOTION_EVENT_ACTION_DOWN),
4862 WithSource(AINPUT_SOURCE_TOUCHSCREEN)));
4863
4864 // pilfer the motion, retaining the gesture on the spy window.
4865 EXPECT_EQ(OK, mDispatcher->pilferPointers(spyWindow->getToken()));
4866 window->consumeMotionEvent(AllOf(WithMotionAction(AMOTION_EVENT_ACTION_CANCEL),
4867 WithSource(AINPUT_SOURCE_TOUCHSCREEN)));
4868
4869 // Touch UP on the window
4870 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
4871 injectMotionEvent(*mDispatcher,
4872 MotionEventBuilder(AMOTION_EVENT_ACTION_UP,
4873 AINPUT_SOURCE_TOUCHSCREEN)
4874 .deviceId(SECOND_DEVICE_ID)
4875 .pointer(PointerBuilder(0, ToolType::FINGER).x(200).y(200))
4876 .build()));
4877 spyWindow->consumeMotionEvent(AllOf(WithMotionAction(AMOTION_EVENT_ACTION_UP),
4878 WithSource(AINPUT_SOURCE_TOUCHSCREEN)));
4879
4880 // Previously, a touch was pilfered. However, that gesture was just finished. Now, we are going
4881 // to send a new gesture. It should again go to both windows (spy and the window below), just
4882 // like the first gesture did, before pilfering. The window configuration has not changed.
4883
4884 // One more tap - DOWN
4885 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
4886 injectMotionEvent(*mDispatcher,
4887 MotionEventBuilder(AMOTION_EVENT_ACTION_DOWN,
4888 AINPUT_SOURCE_TOUCHSCREEN)
4889 .deviceId(SECOND_DEVICE_ID)
4890 .pointer(PointerBuilder(0, ToolType::FINGER).x(250).y(250))
4891 .build()));
4892 window->consumeMotionEvent(AllOf(WithMotionAction(AMOTION_EVENT_ACTION_DOWN),
4893 WithSource(AINPUT_SOURCE_TOUCHSCREEN)));
4894 spyWindow->consumeMotionEvent(AllOf(WithMotionAction(AMOTION_EVENT_ACTION_DOWN),
4895 WithSource(AINPUT_SOURCE_TOUCHSCREEN)));
4896
4897 // Touch UP on the window
4898 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
4899 injectMotionEvent(*mDispatcher,
4900 MotionEventBuilder(AMOTION_EVENT_ACTION_UP,
4901 AINPUT_SOURCE_TOUCHSCREEN)
4902 .deviceId(SECOND_DEVICE_ID)
4903 .pointer(PointerBuilder(0, ToolType::FINGER).x(250).y(250))
4904 .build()));
4905 window->consumeMotionEvent(AllOf(WithMotionAction(AMOTION_EVENT_ACTION_UP),
4906 WithSource(AINPUT_SOURCE_TOUCHSCREEN)));
4907 spyWindow->consumeMotionEvent(AllOf(WithMotionAction(AMOTION_EVENT_ACTION_UP),
4908 WithSource(AINPUT_SOURCE_TOUCHSCREEN)));
4909
4910 window->assertNoEvents();
4911 spyWindow->assertNoEvents();
4912 }
4913
TEST_F(InputDispatcherTest,MouseAndTouchWithSpyWindows)4914 TEST_F(InputDispatcherTest, MouseAndTouchWithSpyWindows) {
4915 SCOPED_FLAG_OVERRIDE(enable_multi_device_same_window_stream, true);
4916 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
4917
4918 sp<FakeWindowHandle> spyWindow = sp<FakeWindowHandle>::make(application, mDispatcher, "Spy",
4919 ui::LogicalDisplayId::DEFAULT);
4920 spyWindow->setFrame(Rect(0, 0, 600, 800));
4921 spyWindow->setTrustedOverlay(true);
4922 spyWindow->setSpy(true);
4923 sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher, "Window",
4924 ui::LogicalDisplayId::DEFAULT);
4925 window->setFrame(Rect(0, 0, 600, 800));
4926
4927 mDispatcher->setFocusedApplication(ui::LogicalDisplayId::DEFAULT, application);
4928 mDispatcher->onWindowInfosChanged({{*spyWindow->getInfo(), *window->getInfo()}, {}, 0, 0});
4929
4930 // Send mouse cursor to the window
4931 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_ENTER, AINPUT_SOURCE_MOUSE)
4932 .pointer(PointerBuilder(0, ToolType::MOUSE).x(100).y(100))
4933 .build());
4934
4935 // Move mouse cursor
4936 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_MOVE, AINPUT_SOURCE_MOUSE)
4937 .pointer(PointerBuilder(0, ToolType::MOUSE).x(110).y(110))
4938 .build());
4939
4940 window->consumeMotionEvent(
4941 AllOf(WithMotionAction(ACTION_HOVER_ENTER), WithSource(AINPUT_SOURCE_MOUSE)));
4942 spyWindow->consumeMotionEvent(
4943 AllOf(WithMotionAction(ACTION_HOVER_ENTER), WithSource(AINPUT_SOURCE_MOUSE)));
4944 window->consumeMotionEvent(
4945 AllOf(WithMotionAction(ACTION_HOVER_MOVE), WithSource(AINPUT_SOURCE_MOUSE)));
4946 spyWindow->consumeMotionEvent(
4947 AllOf(WithMotionAction(ACTION_HOVER_MOVE), WithSource(AINPUT_SOURCE_MOUSE)));
4948 // Touch down on the window
4949 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
4950 .deviceId(SECOND_DEVICE_ID)
4951 .pointer(PointerBuilder(0, ToolType::FINGER).x(200).y(200))
4952 .build());
4953 window->consumeMotionEvent(
4954 AllOf(WithMotionAction(ACTION_DOWN), WithSource(AINPUT_SOURCE_TOUCHSCREEN)));
4955 spyWindow->consumeMotionEvent(
4956 AllOf(WithMotionAction(ACTION_DOWN), WithSource(AINPUT_SOURCE_TOUCHSCREEN)));
4957
4958 // pilfer the motion, retaining the gesture on the spy window.
4959 EXPECT_EQ(OK, mDispatcher->pilferPointers(spyWindow->getToken()));
4960 window->consumeMotionEvent(
4961 AllOf(WithMotionAction(ACTION_CANCEL), WithSource(AINPUT_SOURCE_TOUCHSCREEN)));
4962 // Mouse hover is not pilfered
4963
4964 // Touch UP on the window
4965 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN)
4966 .deviceId(SECOND_DEVICE_ID)
4967 .pointer(PointerBuilder(0, ToolType::FINGER).x(200).y(200))
4968 .build());
4969 spyWindow->consumeMotionEvent(
4970 AllOf(WithMotionAction(ACTION_UP), WithSource(AINPUT_SOURCE_TOUCHSCREEN)));
4971
4972 // Previously, a touch was pilfered. However, that gesture was just finished. Now, we are going
4973 // to send a new gesture. It should again go to both windows (spy and the window below), just
4974 // like the first gesture did, before pilfering. The window configuration has not changed.
4975
4976 // One more tap - DOWN
4977 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
4978 .deviceId(SECOND_DEVICE_ID)
4979 .pointer(PointerBuilder(0, ToolType::FINGER).x(250).y(250))
4980 .build());
4981 window->consumeMotionEvent(
4982 AllOf(WithMotionAction(ACTION_DOWN), WithSource(AINPUT_SOURCE_TOUCHSCREEN)));
4983 spyWindow->consumeMotionEvent(
4984 AllOf(WithMotionAction(ACTION_DOWN), WithSource(AINPUT_SOURCE_TOUCHSCREEN)));
4985
4986 // Touch UP on the window
4987 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN)
4988 .deviceId(SECOND_DEVICE_ID)
4989 .pointer(PointerBuilder(0, ToolType::FINGER).x(250).y(250))
4990 .build());
4991 window->consumeMotionEvent(
4992 AllOf(WithMotionAction(ACTION_UP), WithSource(AINPUT_SOURCE_TOUCHSCREEN)));
4993 spyWindow->consumeMotionEvent(
4994 AllOf(WithMotionAction(ACTION_UP), WithSource(AINPUT_SOURCE_TOUCHSCREEN)));
4995
4996 // Mouse movement continues normally as well
4997 // Move mouse cursor
4998 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_MOVE, AINPUT_SOURCE_MOUSE)
4999 .pointer(PointerBuilder(0, ToolType::MOUSE).x(120).y(130))
5000 .build());
5001 window->consumeMotionEvent(
5002 AllOf(WithMotionAction(ACTION_HOVER_MOVE), WithSource(AINPUT_SOURCE_MOUSE)));
5003 spyWindow->consumeMotionEvent(
5004 AllOf(WithMotionAction(ACTION_HOVER_MOVE), WithSource(AINPUT_SOURCE_MOUSE)));
5005
5006 window->assertNoEvents();
5007 spyWindow->assertNoEvents();
5008 }
5009
5010 // This test is different from the test above that HOVER_ENTER and HOVER_EXIT events are injected
5011 // directly in this test.
TEST_F(InputDispatcherTest,HoverEnterMouseClickAndHoverExit)5012 TEST_F(InputDispatcherTest, HoverEnterMouseClickAndHoverExit) {
5013 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
5014 sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher, "Window",
5015 ui::LogicalDisplayId::DEFAULT);
5016 window->setFrame(Rect(0, 0, 1200, 800));
5017
5018 mDispatcher->setFocusedApplication(ui::LogicalDisplayId::DEFAULT, application);
5019
5020 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
5021
5022 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
5023 injectMotionEvent(*mDispatcher,
5024 MotionEventBuilder(AMOTION_EVENT_ACTION_HOVER_ENTER,
5025 AINPUT_SOURCE_MOUSE)
5026 .pointer(PointerBuilder(0, ToolType::MOUSE).x(300).y(400))
5027 .build()));
5028 window->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_ENTER));
5029 // Inject a series of mouse events for a mouse click
5030 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
5031 injectMotionEvent(*mDispatcher,
5032 MotionEventBuilder(AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_MOUSE)
5033 .buttonState(AMOTION_EVENT_BUTTON_PRIMARY)
5034 .pointer(PointerBuilder(0, ToolType::MOUSE).x(300).y(400))
5035 .build()));
5036 window->consumeMotionEvent(WithMotionAction(ACTION_HOVER_EXIT));
5037 window->consumeMotionEvent(WithMotionAction(ACTION_DOWN));
5038
5039 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
5040 injectMotionEvent(*mDispatcher,
5041 MotionEventBuilder(AMOTION_EVENT_ACTION_BUTTON_PRESS,
5042 AINPUT_SOURCE_MOUSE)
5043 .buttonState(AMOTION_EVENT_BUTTON_PRIMARY)
5044 .actionButton(AMOTION_EVENT_BUTTON_PRIMARY)
5045 .pointer(PointerBuilder(0, ToolType::MOUSE).x(300).y(400))
5046 .build()));
5047 window->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_BUTTON_PRESS));
5048
5049 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
5050 injectMotionEvent(*mDispatcher,
5051 MotionEventBuilder(AMOTION_EVENT_ACTION_BUTTON_RELEASE,
5052 AINPUT_SOURCE_MOUSE)
5053 .buttonState(0)
5054 .actionButton(AMOTION_EVENT_BUTTON_PRIMARY)
5055 .pointer(PointerBuilder(0, ToolType::MOUSE).x(300).y(400))
5056 .build()));
5057 window->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_BUTTON_RELEASE));
5058
5059 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
5060 injectMotionEvent(*mDispatcher,
5061 MotionEventBuilder(AMOTION_EVENT_ACTION_UP, AINPUT_SOURCE_MOUSE)
5062 .buttonState(0)
5063 .pointer(PointerBuilder(0, ToolType::MOUSE).x(300).y(400))
5064 .build()));
5065 window->consumeMotionUp(ui::LogicalDisplayId::DEFAULT);
5066
5067 // We already canceled the hovering implicitly by injecting the "DOWN" event without lifting the
5068 // hover first. Therefore, injection of HOVER_EXIT is inconsistent, and should fail.
5069 ASSERT_EQ(InputEventInjectionResult::FAILED,
5070 injectMotionEvent(*mDispatcher,
5071 MotionEventBuilder(AMOTION_EVENT_ACTION_HOVER_EXIT,
5072 AINPUT_SOURCE_MOUSE)
5073 .pointer(PointerBuilder(0, ToolType::MOUSE).x(300).y(400))
5074 .build()));
5075 window->assertNoEvents();
5076 }
5077
5078 /**
5079 * Hover over a window, and then remove that window. Make sure that HOVER_EXIT for that event
5080 * is generated.
5081 */
TEST_F(InputDispatcherTest,HoverExitIsSentToRemovedWindow)5082 TEST_F(InputDispatcherTest, HoverExitIsSentToRemovedWindow) {
5083 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
5084 sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher, "Window",
5085 ui::LogicalDisplayId::DEFAULT);
5086 window->setFrame(Rect(0, 0, 1200, 800));
5087
5088 mDispatcher->setFocusedApplication(ui::LogicalDisplayId::DEFAULT, application);
5089
5090 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
5091
5092 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
5093 injectMotionEvent(*mDispatcher,
5094 MotionEventBuilder(AMOTION_EVENT_ACTION_HOVER_ENTER,
5095 AINPUT_SOURCE_MOUSE)
5096 .pointer(PointerBuilder(0, ToolType::MOUSE).x(300).y(400))
5097 .build()));
5098 window->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_ENTER));
5099
5100 // Remove the window, but keep the channel.
5101 mDispatcher->onWindowInfosChanged({{}, {}, 0, 0});
5102 window->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_EXIT));
5103 }
5104
5105 /**
5106 * Test that invalid HOVER events sent by accessibility do not cause a fatal crash.
5107 */
TEST_F(InputDispatcherTest,InvalidA11yHoverStreamDoesNotCrash)5108 TEST_F(InputDispatcherTest, InvalidA11yHoverStreamDoesNotCrash) {
5109 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
5110 sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher, "Window",
5111 ui::LogicalDisplayId::DEFAULT);
5112 window->setFrame(Rect(0, 0, 1200, 800));
5113
5114 mDispatcher->setFocusedApplication(ui::LogicalDisplayId::DEFAULT, application);
5115
5116 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
5117
5118 MotionEventBuilder hoverEnterBuilder =
5119 MotionEventBuilder(AMOTION_EVENT_ACTION_HOVER_ENTER, AINPUT_SOURCE_MOUSE)
5120 .pointer(PointerBuilder(0, ToolType::MOUSE).x(300).y(400))
5121 .addFlag(AMOTION_EVENT_FLAG_IS_ACCESSIBILITY_EVENT);
5122 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
5123 injectMotionEvent(*mDispatcher, hoverEnterBuilder.build()));
5124 window->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_ENTER));
5125 // Another HOVER_ENTER would be inconsistent, and should therefore fail to
5126 // get injected.
5127 ASSERT_EQ(InputEventInjectionResult::FAILED,
5128 injectMotionEvent(*mDispatcher, hoverEnterBuilder.build()));
5129 }
5130
5131 /**
5132 * Invalid events injected by input filter are rejected.
5133 */
TEST_F(InputDispatcherTest,InvalidA11yEventsGetRejected)5134 TEST_F(InputDispatcherTest, InvalidA11yEventsGetRejected) {
5135 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
5136 sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher, "Window",
5137 ui::LogicalDisplayId::DEFAULT);
5138
5139 mDispatcher->setFocusedApplication(ui::LogicalDisplayId::DEFAULT, application);
5140
5141 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
5142
5143 // a11y sets 'POLICY_FLAG_INJECTED_FROM_ACCESSIBILITY' policy flag during injection, so define
5144 // a custom injection function here for convenience.
5145 auto injectFromAccessibility = [&](int32_t action, float x, float y) {
5146 MotionEvent event = MotionEventBuilder(action, AINPUT_SOURCE_TOUCHSCREEN)
5147 .pointer(PointerBuilder(0, ToolType::FINGER).x(x).y(y))
5148 .addFlag(AMOTION_EVENT_FLAG_IS_ACCESSIBILITY_EVENT)
5149 .build();
5150 return injectMotionEvent(*mDispatcher, event, 100ms,
5151 InputEventInjectionSync::WAIT_FOR_RESULT, /*targetUid=*/{},
5152 POLICY_FLAG_PASS_TO_USER | POLICY_FLAG_FILTERED |
5153 POLICY_FLAG_INJECTED_FROM_ACCESSIBILITY);
5154 };
5155
5156 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
5157 injectFromAccessibility(ACTION_DOWN, /*x=*/300, /*y=*/400));
5158 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
5159 injectFromAccessibility(ACTION_MOVE, /*x=*/310, /*y=*/420));
5160 window->consumeMotionEvent(WithMotionAction(ACTION_DOWN));
5161 window->consumeMotionEvent(WithMotionAction(ACTION_MOVE));
5162 // finger is still down, so a new DOWN event should be rejected!
5163 ASSERT_EQ(InputEventInjectionResult::FAILED,
5164 injectFromAccessibility(ACTION_DOWN, /*x=*/340, /*y=*/410));
5165
5166 // if the gesture is correctly finished, new down event will succeed
5167 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
5168 injectFromAccessibility(ACTION_MOVE, /*x=*/320, /*y=*/430));
5169 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
5170 injectFromAccessibility(ACTION_UP, /*x=*/320, /*y=*/430));
5171 window->consumeMotionEvent(WithMotionAction(ACTION_MOVE));
5172 window->consumeMotionEvent(WithMotionAction(ACTION_UP));
5173
5174 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
5175 injectFromAccessibility(ACTION_DOWN, /*x=*/350, /*y=*/460));
5176 window->consumeMotionEvent(WithMotionAction(ACTION_DOWN));
5177 }
5178
5179 /**
5180 * If mouse is hovering when the touch goes down, the hovering should be stopped via HOVER_EXIT.
5181 */
TEST_F(InputDispatcherTest,TouchDownAfterMouseHover_legacy)5182 TEST_F(InputDispatcherTest, TouchDownAfterMouseHover_legacy) {
5183 SCOPED_FLAG_OVERRIDE(enable_multi_device_same_window_stream, false);
5184 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
5185 sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher, "Window",
5186 ui::LogicalDisplayId::DEFAULT);
5187 window->setFrame(Rect(0, 0, 100, 100));
5188
5189 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
5190
5191 const int32_t mouseDeviceId = 7;
5192 const int32_t touchDeviceId = 4;
5193
5194 // Start hovering with the mouse
5195 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_ENTER, AINPUT_SOURCE_MOUSE)
5196 .deviceId(mouseDeviceId)
5197 .pointer(PointerBuilder(0, ToolType::MOUSE).x(10).y(10))
5198 .build());
5199 window->consumeMotionEvent(
5200 AllOf(WithMotionAction(ACTION_HOVER_ENTER), WithDeviceId(mouseDeviceId)));
5201
5202 // Touch goes down
5203 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
5204 .deviceId(touchDeviceId)
5205 .pointer(PointerBuilder(0, ToolType::FINGER).x(50).y(50))
5206 .build());
5207
5208 window->consumeMotionEvent(
5209 AllOf(WithMotionAction(ACTION_HOVER_EXIT), WithDeviceId(mouseDeviceId)));
5210 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(touchDeviceId)));
5211 }
5212
5213 /**
5214 * If mouse is hovering when the touch goes down, the hovering should not be stopped.
5215 */
TEST_F(InputDispatcherTest,TouchDownAfterMouseHover)5216 TEST_F(InputDispatcherTest, TouchDownAfterMouseHover) {
5217 SCOPED_FLAG_OVERRIDE(enable_multi_device_same_window_stream, true);
5218 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
5219 sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher, "Window",
5220 ui::LogicalDisplayId::DEFAULT);
5221 window->setFrame(Rect(0, 0, 100, 100));
5222
5223 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
5224
5225 const int32_t mouseDeviceId = 7;
5226 const int32_t touchDeviceId = 4;
5227
5228 // Start hovering with the mouse
5229 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_ENTER, AINPUT_SOURCE_MOUSE)
5230 .deviceId(mouseDeviceId)
5231 .pointer(PointerBuilder(0, ToolType::MOUSE).x(10).y(10))
5232 .build());
5233 window->consumeMotionEvent(
5234 AllOf(WithMotionAction(ACTION_HOVER_ENTER), WithDeviceId(mouseDeviceId)));
5235
5236 // Touch goes down
5237 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
5238 .deviceId(touchDeviceId)
5239 .pointer(PointerBuilder(0, ToolType::FINGER).x(50).y(50))
5240 .build());
5241 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(touchDeviceId)));
5242 }
5243
5244 /**
5245 * Inject a mouse hover event followed by a tap from touchscreen.
5246 * The tap causes a HOVER_EXIT event to be generated because the current event
5247 * stream's source has been switched.
5248 */
TEST_F(InputDispatcherTest,MouseHoverAndTouchTap_legacy)5249 TEST_F(InputDispatcherTest, MouseHoverAndTouchTap_legacy) {
5250 SCOPED_FLAG_OVERRIDE(enable_multi_device_same_window_stream, false);
5251 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
5252 sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher, "Window",
5253 ui::LogicalDisplayId::DEFAULT);
5254 window->setFrame(Rect(0, 0, 100, 100));
5255
5256 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
5257 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_MOVE, AINPUT_SOURCE_MOUSE)
5258 .pointer(PointerBuilder(0, ToolType::MOUSE).x(50).y(50))
5259 .build());
5260 ASSERT_NO_FATAL_FAILURE(
5261 window->consumeMotionEvent(AllOf(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_ENTER),
5262 WithSource(AINPUT_SOURCE_MOUSE))));
5263
5264 // Tap on the window
5265 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
5266 .pointer(PointerBuilder(0, ToolType::FINGER).x(10).y(10))
5267 .build());
5268 ASSERT_NO_FATAL_FAILURE(
5269 window->consumeMotionEvent(AllOf(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_EXIT),
5270 WithSource(AINPUT_SOURCE_MOUSE))));
5271
5272 ASSERT_NO_FATAL_FAILURE(
5273 window->consumeMotionEvent(AllOf(WithMotionAction(AMOTION_EVENT_ACTION_DOWN),
5274 WithSource(AINPUT_SOURCE_TOUCHSCREEN))));
5275
5276 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN)
5277 .pointer(PointerBuilder(0, ToolType::FINGER).x(10).y(10))
5278 .build());
5279 ASSERT_NO_FATAL_FAILURE(
5280 window->consumeMotionEvent(AllOf(WithMotionAction(AMOTION_EVENT_ACTION_UP),
5281 WithSource(AINPUT_SOURCE_TOUCHSCREEN))));
5282 }
5283
5284 /**
5285 * Send a mouse hover event followed by a tap from touchscreen.
5286 * The tap causes a HOVER_EXIT event to be generated because the current event
5287 * stream's source has been switched.
5288 */
TEST_F(InputDispatcherTest,MouseHoverAndTouchTap)5289 TEST_F(InputDispatcherTest, MouseHoverAndTouchTap) {
5290 SCOPED_FLAG_OVERRIDE(enable_multi_device_same_window_stream, true);
5291 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
5292 sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher, "Window",
5293 ui::LogicalDisplayId::DEFAULT);
5294 window->setFrame(Rect(0, 0, 100, 100));
5295
5296 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
5297 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_MOVE, AINPUT_SOURCE_MOUSE)
5298 .pointer(PointerBuilder(0, ToolType::MOUSE).x(50).y(50))
5299 .build());
5300
5301 window->consumeMotionEvent(AllOf(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_ENTER),
5302 WithSource(AINPUT_SOURCE_MOUSE)));
5303
5304 // Tap on the window
5305 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
5306 .pointer(PointerBuilder(0, ToolType::FINGER).x(10).y(10))
5307 .build());
5308
5309 window->consumeMotionEvent(AllOf(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_EXIT),
5310 WithSource(AINPUT_SOURCE_MOUSE)));
5311
5312 window->consumeMotionEvent(AllOf(WithMotionAction(AMOTION_EVENT_ACTION_DOWN),
5313 WithSource(AINPUT_SOURCE_TOUCHSCREEN)));
5314
5315 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN)
5316 .pointer(PointerBuilder(0, ToolType::FINGER).x(10).y(10))
5317 .build());
5318
5319 window->consumeMotionEvent(AllOf(WithMotionAction(AMOTION_EVENT_ACTION_UP),
5320 WithSource(AINPUT_SOURCE_TOUCHSCREEN)));
5321 }
5322
TEST_F(InputDispatcherTest,HoverEnterMoveRemoveWindowsInSecondDisplay)5323 TEST_F(InputDispatcherTest, HoverEnterMoveRemoveWindowsInSecondDisplay) {
5324 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
5325 sp<FakeWindowHandle> windowDefaultDisplay =
5326 sp<FakeWindowHandle>::make(application, mDispatcher, "DefaultDisplay",
5327 ui::LogicalDisplayId::DEFAULT);
5328 windowDefaultDisplay->setFrame(Rect(0, 0, 600, 800));
5329 sp<FakeWindowHandle> windowSecondDisplay =
5330 sp<FakeWindowHandle>::make(application, mDispatcher, "SecondDisplay",
5331 SECOND_DISPLAY_ID);
5332 windowSecondDisplay->setFrame(Rect(0, 0, 600, 800));
5333
5334 mDispatcher->onWindowInfosChanged(
5335 {{*windowDefaultDisplay->getInfo(), *windowSecondDisplay->getInfo()}, {}, 0, 0});
5336
5337 // Set cursor position in window in default display and check that hover enter and move
5338 // events are generated.
5339 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
5340 injectMotionEvent(*mDispatcher,
5341 MotionEventBuilder(AMOTION_EVENT_ACTION_HOVER_MOVE,
5342 AINPUT_SOURCE_MOUSE)
5343 .displayId(ui::LogicalDisplayId::DEFAULT)
5344 .pointer(PointerBuilder(0, ToolType::MOUSE).x(300).y(600))
5345 .build()));
5346 windowDefaultDisplay->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_ENTER));
5347
5348 // Remove all windows in secondary display and check that no event happens on window in
5349 // primary display.
5350 mDispatcher->onWindowInfosChanged({{*windowDefaultDisplay->getInfo()}, {}, 0, 0});
5351
5352 windowDefaultDisplay->assertNoEvents();
5353
5354 // Move cursor position in window in default display and check that only hover move
5355 // event is generated and not hover enter event.
5356 mDispatcher->onWindowInfosChanged(
5357 {{*windowDefaultDisplay->getInfo(), *windowSecondDisplay->getInfo()}, {}, 0, 0});
5358 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
5359 injectMotionEvent(*mDispatcher,
5360 MotionEventBuilder(AMOTION_EVENT_ACTION_HOVER_MOVE,
5361 AINPUT_SOURCE_MOUSE)
5362 .displayId(ui::LogicalDisplayId::DEFAULT)
5363 .pointer(PointerBuilder(0, ToolType::MOUSE).x(400).y(700))
5364 .build()));
5365 windowDefaultDisplay->consumeMotionEvent(
5366 AllOf(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_MOVE),
5367 WithSource(AINPUT_SOURCE_MOUSE)));
5368 windowDefaultDisplay->assertNoEvents();
5369 }
5370
TEST_F(InputDispatcherTest,DispatchMouseEventsUnderCursor)5371 TEST_F(InputDispatcherTest, DispatchMouseEventsUnderCursor) {
5372 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
5373
5374 sp<FakeWindowHandle> windowLeft = sp<FakeWindowHandle>::make(application, mDispatcher, "Left",
5375 ui::LogicalDisplayId::DEFAULT);
5376 windowLeft->setFrame(Rect(0, 0, 600, 800));
5377 sp<FakeWindowHandle> windowRight = sp<FakeWindowHandle>::make(application, mDispatcher, "Right",
5378 ui::LogicalDisplayId::DEFAULT);
5379 windowRight->setFrame(Rect(600, 0, 1200, 800));
5380
5381 mDispatcher->setFocusedApplication(ui::LogicalDisplayId::DEFAULT, application);
5382
5383 mDispatcher->onWindowInfosChanged(
5384 {{*windowLeft->getInfo(), *windowRight->getInfo()}, {}, 0, 0});
5385
5386 // Inject an event with coordinate in the area of right window, with mouse cursor in the area of
5387 // left window. This event should be dispatched to the left window.
5388 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
5389 injectMotionEvent(*mDispatcher, AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_MOUSE,
5390 ui::LogicalDisplayId::DEFAULT, {610, 400}, {599, 400}));
5391 windowLeft->consumeMotionDown(ui::LogicalDisplayId::DEFAULT);
5392 windowRight->assertNoEvents();
5393 }
5394
TEST_F(InputDispatcherTest,NotifyDeviceReset_CancelsKeyStream)5395 TEST_F(InputDispatcherTest, NotifyDeviceReset_CancelsKeyStream) {
5396 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
5397 sp<FakeWindowHandle> window =
5398 sp<FakeWindowHandle>::make(application, mDispatcher, "Fake Window",
5399 ui::LogicalDisplayId::DEFAULT);
5400 window->setFocusable(true);
5401
5402 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
5403 setFocusedWindow(window);
5404
5405 window->consumeFocusEvent(true);
5406
5407 mDispatcher->notifyKey(generateKeyArgs(AKEY_EVENT_ACTION_DOWN, ui::LogicalDisplayId::DEFAULT));
5408
5409 // Window should receive key down event.
5410 window->consumeKeyDown(ui::LogicalDisplayId::DEFAULT);
5411
5412 // When device reset happens, that key stream should be terminated with FLAG_CANCELED
5413 // on the app side.
5414 mDispatcher->notifyDeviceReset({/*id=*/10, /*eventTime=*/20, DEVICE_ID});
5415 window->consumeKeyUp(ui::LogicalDisplayId::DEFAULT, AKEY_EVENT_FLAG_CANCELED);
5416 }
5417
TEST_F(InputDispatcherTest,NotifyDeviceReset_CancelsMotionStream)5418 TEST_F(InputDispatcherTest, NotifyDeviceReset_CancelsMotionStream) {
5419 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
5420 sp<FakeWindowHandle> window =
5421 sp<FakeWindowHandle>::make(application, mDispatcher, "Fake Window",
5422 ui::LogicalDisplayId::DEFAULT);
5423
5424 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
5425
5426 mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_DOWN,
5427 AINPUT_SOURCE_TOUCHSCREEN,
5428 ui::LogicalDisplayId::DEFAULT));
5429
5430 // Window should receive motion down event.
5431 window->consumeMotionDown(ui::LogicalDisplayId::DEFAULT);
5432
5433 // When device reset happens, that motion stream should be terminated with ACTION_CANCEL
5434 // on the app side.
5435 mDispatcher->notifyDeviceReset({/*id=*/10, /*eventTime=*/20, DEVICE_ID});
5436 window->consumeMotionEvent(
5437 AllOf(WithMotionAction(ACTION_CANCEL), WithDisplayId(ui::LogicalDisplayId::DEFAULT)));
5438 }
5439
TEST_F(InputDispatcherTest,NotifyDeviceResetCancelsHoveringStream)5440 TEST_F(InputDispatcherTest, NotifyDeviceResetCancelsHoveringStream) {
5441 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
5442 sp<FakeWindowHandle> window =
5443 sp<FakeWindowHandle>::make(application, mDispatcher, "Fake Window",
5444 ui::LogicalDisplayId::DEFAULT);
5445
5446 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
5447
5448 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_ENTER, AINPUT_SOURCE_STYLUS)
5449 .pointer(PointerBuilder(0, ToolType::STYLUS).x(10).y(10))
5450 .build());
5451
5452 window->consumeMotionEvent(WithMotionAction(ACTION_HOVER_ENTER));
5453
5454 // When device reset happens, that hover stream should be terminated with ACTION_HOVER_EXIT
5455 mDispatcher->notifyDeviceReset({/*id=*/10, /*eventTime=*/20, DEVICE_ID});
5456 window->consumeMotionEvent(WithMotionAction(ACTION_HOVER_EXIT));
5457
5458 // After the device has been reset, a new hovering stream can be sent to the window
5459 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_ENTER, AINPUT_SOURCE_STYLUS)
5460 .pointer(PointerBuilder(0, ToolType::STYLUS).x(15).y(15))
5461 .build());
5462 window->consumeMotionEvent(WithMotionAction(ACTION_HOVER_ENTER));
5463 }
5464
TEST_F(InputDispatcherTest,InterceptKeyByPolicy)5465 TEST_F(InputDispatcherTest, InterceptKeyByPolicy) {
5466 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
5467 sp<FakeWindowHandle> window =
5468 sp<FakeWindowHandle>::make(application, mDispatcher, "Fake Window",
5469 ui::LogicalDisplayId::DEFAULT);
5470 window->setFocusable(true);
5471
5472 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
5473 setFocusedWindow(window);
5474
5475 window->consumeFocusEvent(true);
5476
5477 const NotifyKeyArgs keyArgs =
5478 generateKeyArgs(AKEY_EVENT_ACTION_DOWN, ui::LogicalDisplayId::DEFAULT);
5479 const std::chrono::milliseconds interceptKeyTimeout = 50ms;
5480 const nsecs_t injectTime = keyArgs.eventTime;
5481 mFakePolicy->setInterceptKeyTimeout(interceptKeyTimeout);
5482 mDispatcher->notifyKey(keyArgs);
5483 // The dispatching time should be always greater than or equal to intercept key timeout.
5484 window->consumeKeyDown(ui::LogicalDisplayId::DEFAULT);
5485 ASSERT_TRUE((systemTime(SYSTEM_TIME_MONOTONIC) - injectTime) >=
5486 std::chrono::nanoseconds(interceptKeyTimeout).count());
5487 }
5488
5489 /**
5490 * Keys with ACTION_UP are delivered immediately, even if a long 'intercept key timeout' is set.
5491 */
TEST_F(InputDispatcherTest,InterceptKeyIfKeyUp)5492 TEST_F(InputDispatcherTest, InterceptKeyIfKeyUp) {
5493 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
5494 sp<FakeWindowHandle> window =
5495 sp<FakeWindowHandle>::make(application, mDispatcher, "Fake Window",
5496 ui::LogicalDisplayId::DEFAULT);
5497 window->setFocusable(true);
5498
5499 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
5500 setFocusedWindow(window);
5501
5502 window->consumeFocusEvent(true);
5503
5504 mDispatcher->notifyKey(generateKeyArgs(AKEY_EVENT_ACTION_DOWN, ui::LogicalDisplayId::DEFAULT));
5505 window->consumeKeyDown(ui::LogicalDisplayId::DEFAULT);
5506
5507 // Set a value that's significantly larger than the default consumption timeout. If the
5508 // implementation is correct, the actual value doesn't matter; it won't slow down the test.
5509 mFakePolicy->setInterceptKeyTimeout(600ms);
5510 mDispatcher->notifyKey(generateKeyArgs(AKEY_EVENT_ACTION_UP, ui::LogicalDisplayId::DEFAULT));
5511 // Window should receive key event immediately when same key up.
5512 window->consumeKeyUp(ui::LogicalDisplayId::DEFAULT);
5513 }
5514
5515 /**
5516 * Two windows. First is a regular window. Second does not overlap with the first, and has
5517 * WATCH_OUTSIDE_TOUCH.
5518 * Both windows are owned by the same UID.
5519 * Tap first window. Make sure that the second window receives ACTION_OUTSIDE with correct, non-zero
5520 * coordinates. The coordinates are not zeroed out because both windows are owned by the same UID.
5521 */
TEST_F(InputDispatcherTest,ActionOutsideForOwnedWindowHasValidCoordinates)5522 TEST_F(InputDispatcherTest, ActionOutsideForOwnedWindowHasValidCoordinates) {
5523 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
5524 sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher, "Window",
5525 ui::LogicalDisplayId::DEFAULT);
5526 window->setFrame(Rect{0, 0, 100, 100});
5527
5528 sp<FakeWindowHandle> outsideWindow =
5529 sp<FakeWindowHandle>::make(application, mDispatcher, "Outside Window",
5530 ui::LogicalDisplayId::DEFAULT);
5531 outsideWindow->setFrame(Rect{100, 100, 200, 200});
5532 outsideWindow->setWatchOutsideTouch(true);
5533 // outsideWindow must be above 'window' to receive ACTION_OUTSIDE events when 'window' is tapped
5534 mDispatcher->onWindowInfosChanged({{*outsideWindow->getInfo(), *window->getInfo()}, {}, 0, 0});
5535
5536 // Tap on first window.
5537 mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_DOWN,
5538 AINPUT_SOURCE_TOUCHSCREEN,
5539 ui::LogicalDisplayId::DEFAULT, {PointF{50, 50}}));
5540 window->consumeMotionDown();
5541 // The coordinates of the tap in 'outsideWindow' are relative to its top left corner.
5542 // Therefore, we should offset them by (100, 100) relative to the screen's top left corner.
5543 outsideWindow->consumeMotionEvent(
5544 AllOf(WithMotionAction(ACTION_OUTSIDE), WithCoords(-50, -50)));
5545
5546 // Ensure outsideWindow doesn't get any more events for the gesture.
5547 mDispatcher->notifyMotion(generateMotionArgs(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN,
5548 ui::LogicalDisplayId::DEFAULT, {PointF{51, 51}}));
5549 window->consumeMotionMove();
5550 outsideWindow->assertNoEvents();
5551 }
5552
5553 /**
5554 * Three windows:
5555 * - Left window
5556 * - Right window
5557 * - Outside window(watch for ACTION_OUTSIDE events)
5558 * The windows "left" and "outside" share the same owner, the window "right" has a different owner,
5559 * In order to allow the outside window can receive the ACTION_OUTSIDE events, the outside window is
5560 * positioned above the "left" and "right" windows, and it doesn't overlap with them.
5561 *
5562 * First, device A report a down event landed in the right window, the outside window can receive
5563 * an ACTION_OUTSIDE event that with zeroed coordinates, the device B report a down event landed
5564 * in the left window, the outside window can receive an ACTION_OUTSIDE event the with valid
5565 * coordinates, after these, device A and device B continue report MOVE event, the right and left
5566 * window can receive it, but outside window event can't receive it.
5567 */
TEST_F(InputDispatcherTest,ActionOutsideForOwnedWindowHasValidCoordinatesWhenMultiDevice)5568 TEST_F(InputDispatcherTest, ActionOutsideForOwnedWindowHasValidCoordinatesWhenMultiDevice) {
5569 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
5570 sp<FakeWindowHandle> leftWindow =
5571 sp<FakeWindowHandle>::make(application, mDispatcher, "Left Window",
5572 ui::LogicalDisplayId::DEFAULT);
5573 leftWindow->setFrame(Rect{0, 0, 100, 100});
5574 leftWindow->setOwnerInfo(gui::Pid{1}, gui::Uid{101});
5575
5576 sp<FakeWindowHandle> outsideWindow =
5577 sp<FakeWindowHandle>::make(application, mDispatcher, "Outside Window",
5578 ui::LogicalDisplayId::DEFAULT);
5579 outsideWindow->setFrame(Rect{100, 100, 200, 200});
5580 outsideWindow->setOwnerInfo(gui::Pid{1}, gui::Uid{101});
5581 outsideWindow->setWatchOutsideTouch(true);
5582
5583 std::shared_ptr<FakeApplicationHandle> anotherApplication =
5584 std::make_shared<FakeApplicationHandle>();
5585 sp<FakeWindowHandle> rightWindow =
5586 sp<FakeWindowHandle>::make(anotherApplication, mDispatcher, "Right Window",
5587 ui::LogicalDisplayId::DEFAULT);
5588 rightWindow->setFrame(Rect{100, 0, 200, 100});
5589 rightWindow->setOwnerInfo(gui::Pid{2}, gui::Uid{202});
5590
5591 // OutsideWindow must be above left window and right window to receive ACTION_OUTSIDE events
5592 // when left window or right window is tapped
5593 mDispatcher->onWindowInfosChanged(
5594 {{*outsideWindow->getInfo(), *leftWindow->getInfo(), *rightWindow->getInfo()},
5595 {},
5596 0,
5597 0});
5598
5599 const DeviceId deviceA = 9;
5600 const DeviceId deviceB = 3;
5601
5602 // Tap on right window use device A
5603 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
5604 .pointer(PointerBuilder(0, ToolType::FINGER).x(150).y(50))
5605 .deviceId(deviceA)
5606 .build());
5607 leftWindow->assertNoEvents();
5608 rightWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(deviceA)));
5609 // Right window is belonged to another owner, so outsideWindow should receive ACTION_OUTSIDE
5610 // with zeroed coords.
5611 outsideWindow->consumeMotionEvent(
5612 AllOf(WithMotionAction(ACTION_OUTSIDE), WithDeviceId(deviceA), WithCoords(0, 0)));
5613
5614 // Tap on left window use device B
5615 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
5616 .pointer(PointerBuilder(0, ToolType::FINGER).x(50).y(50))
5617 .deviceId(deviceB)
5618 .build());
5619 leftWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(deviceB)));
5620 rightWindow->assertNoEvents();
5621 // Because new gesture down on the left window that has the same owner with outside Window, the
5622 // outside Window should receive the ACTION_OUTSIDE with coords.
5623 outsideWindow->consumeMotionEvent(
5624 AllOf(WithMotionAction(ACTION_OUTSIDE), WithDeviceId(deviceB), WithCoords(-50, -50)));
5625
5626 // Ensure that windows that can only accept outside do not receive remaining gestures
5627 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN)
5628 .pointer(PointerBuilder(0, ToolType::FINGER).x(151).y(51))
5629 .deviceId(deviceA)
5630 .build());
5631 leftWindow->assertNoEvents();
5632 rightWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(deviceA)));
5633
5634 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN)
5635 .pointer(PointerBuilder(0, ToolType::FINGER).x(51).y(51))
5636 .deviceId(deviceB)
5637 .build());
5638 leftWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(deviceB)));
5639 rightWindow->assertNoEvents();
5640 outsideWindow->assertNoEvents();
5641 }
5642
5643 /**
5644 * This test documents the behavior of WATCH_OUTSIDE_TOUCH. The window will get ACTION_OUTSIDE when
5645 * a another pointer causes ACTION_DOWN to be sent to another window for the first time. Only one
5646 * ACTION_OUTSIDE event is sent per gesture.
5647 */
TEST_F(InputDispatcherTest,ActionOutsideSentOnlyWhenAWindowIsTouched)5648 TEST_F(InputDispatcherTest, ActionOutsideSentOnlyWhenAWindowIsTouched) {
5649 // There are three windows that do not overlap. `window` wants to WATCH_OUTSIDE_TOUCH.
5650 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
5651 sp<FakeWindowHandle> window =
5652 sp<FakeWindowHandle>::make(application, mDispatcher, "First Window",
5653 ui::LogicalDisplayId::DEFAULT);
5654 window->setWatchOutsideTouch(true);
5655 window->setFrame(Rect{0, 0, 100, 100});
5656 sp<FakeWindowHandle> secondWindow =
5657 sp<FakeWindowHandle>::make(application, mDispatcher, "Second Window",
5658 ui::LogicalDisplayId::DEFAULT);
5659 secondWindow->setFrame(Rect{100, 100, 200, 200});
5660 sp<FakeWindowHandle> thirdWindow =
5661 sp<FakeWindowHandle>::make(application, mDispatcher, "Third Window",
5662 ui::LogicalDisplayId::DEFAULT);
5663 thirdWindow->setFrame(Rect{200, 200, 300, 300});
5664 mDispatcher->onWindowInfosChanged(
5665 {{*window->getInfo(), *secondWindow->getInfo(), *thirdWindow->getInfo()}, {}, 0, 0});
5666
5667 // First pointer lands outside all windows. `window` does not get ACTION_OUTSIDE.
5668 mDispatcher->notifyMotion(
5669 generateMotionArgs(AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN,
5670 ui::LogicalDisplayId::DEFAULT, {PointF{-10, -10}}));
5671 window->assertNoEvents();
5672 secondWindow->assertNoEvents();
5673
5674 // The second pointer lands inside `secondWindow`, which should receive a DOWN event.
5675 // Now, `window` should get ACTION_OUTSIDE.
5676 mDispatcher->notifyMotion(generateMotionArgs(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN,
5677 ui::LogicalDisplayId::DEFAULT,
5678 {PointF{-10, -10}, PointF{105, 105}}));
5679 const std::map<int32_t, PointF> expectedPointers{{0, PointF{-10, -10}}, {1, PointF{105, 105}}};
5680 window->consumeMotionEvent(
5681 AllOf(WithMotionAction(ACTION_OUTSIDE), WithPointers(expectedPointers)));
5682 secondWindow->consumeMotionDown();
5683 thirdWindow->assertNoEvents();
5684
5685 // The third pointer lands inside `thirdWindow`, which should receive a DOWN event. There is
5686 // no ACTION_OUTSIDE sent to `window` because one has already been sent for this gesture.
5687 mDispatcher->notifyMotion(
5688 generateMotionArgs(POINTER_2_DOWN, AINPUT_SOURCE_TOUCHSCREEN,
5689 ui::LogicalDisplayId::DEFAULT,
5690 {PointF{-10, -10}, PointF{105, 105}, PointF{205, 205}}));
5691 window->assertNoEvents();
5692 secondWindow->consumeMotionMove();
5693 thirdWindow->consumeMotionDown();
5694 }
5695
TEST_F(InputDispatcherTest,OnWindowInfosChanged_RemoveAllWindowsOnDisplay)5696 TEST_F(InputDispatcherTest, OnWindowInfosChanged_RemoveAllWindowsOnDisplay) {
5697 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
5698 sp<FakeWindowHandle> window =
5699 sp<FakeWindowHandle>::make(application, mDispatcher, "Fake Window",
5700 ui::LogicalDisplayId::DEFAULT);
5701 window->setFocusable(true);
5702
5703 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
5704 setFocusedWindow(window);
5705
5706 window->consumeFocusEvent(true);
5707
5708 const NotifyKeyArgs keyDown =
5709 generateKeyArgs(AKEY_EVENT_ACTION_DOWN, ui::LogicalDisplayId::DEFAULT);
5710 const NotifyKeyArgs keyUp =
5711 generateKeyArgs(AKEY_EVENT_ACTION_UP, ui::LogicalDisplayId::DEFAULT);
5712 mDispatcher->notifyKey(keyDown);
5713 mDispatcher->notifyKey(keyUp);
5714
5715 window->consumeKeyDown(ui::LogicalDisplayId::DEFAULT);
5716 window->consumeKeyUp(ui::LogicalDisplayId::DEFAULT);
5717
5718 // All windows are removed from the display. Ensure that we can no longer dispatch to it.
5719 mDispatcher->onWindowInfosChanged({{}, {}, 0, 0});
5720
5721 window->consumeFocusEvent(false);
5722
5723 mDispatcher->notifyKey(keyDown);
5724 mDispatcher->notifyKey(keyUp);
5725 window->assertNoEvents();
5726 }
5727
TEST_F(InputDispatcherTest,NonSplitTouchableWindowReceivesMultiTouch)5728 TEST_F(InputDispatcherTest, NonSplitTouchableWindowReceivesMultiTouch) {
5729 SCOPED_FLAG_OVERRIDE(split_all_touches, false);
5730 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
5731 sp<FakeWindowHandle> window =
5732 sp<FakeWindowHandle>::make(application, mDispatcher, "Fake Window",
5733 ui::LogicalDisplayId::DEFAULT);
5734 // Ensure window is non-split and have some transform.
5735 window->setPreventSplitting(true);
5736 window->setWindowOffset(20, 40);
5737 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
5738
5739 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
5740 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN,
5741 ui::LogicalDisplayId::DEFAULT, {50, 50}))
5742 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
5743 window->consumeMotionDown(ui::LogicalDisplayId::DEFAULT);
5744
5745 const MotionEvent secondFingerDownEvent =
5746 MotionEventBuilder(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
5747 .displayId(ui::LogicalDisplayId::DEFAULT)
5748 .eventTime(systemTime(SYSTEM_TIME_MONOTONIC))
5749 .pointer(PointerBuilder(/*id=*/0, ToolType::FINGER).x(50).y(50))
5750 .pointer(PointerBuilder(/*id=*/1, ToolType::FINGER).x(-30).y(-50))
5751 .build();
5752 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
5753 injectMotionEvent(*mDispatcher, secondFingerDownEvent, INJECT_EVENT_TIMEOUT,
5754 InputEventInjectionSync::WAIT_FOR_RESULT))
5755 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
5756
5757 std::unique_ptr<MotionEvent> event = window->consumeMotionEvent();
5758 ASSERT_NE(nullptr, event);
5759 EXPECT_EQ(POINTER_1_DOWN, event->getAction());
5760 EXPECT_EQ(70, event->getX(0)); // 50 + 20
5761 EXPECT_EQ(90, event->getY(0)); // 50 + 40
5762 EXPECT_EQ(-10, event->getX(1)); // -30 + 20
5763 EXPECT_EQ(-10, event->getY(1)); // -50 + 40
5764 }
5765
5766 /**
5767 * Two windows: a splittable and a non-splittable.
5768 * The non-splittable window shouldn't receive any "incomplete" gestures.
5769 * Send the first pointer to the splittable window, and then touch the non-splittable window.
5770 * The second pointer should be dropped because the initial window is splittable, so it won't get
5771 * any pointers outside of it, and the second window is non-splittable, so it shouldn't get any
5772 * "incomplete" gestures.
5773 */
TEST_F(InputDispatcherTest,SplittableAndNonSplittableWindows)5774 TEST_F(InputDispatcherTest, SplittableAndNonSplittableWindows) {
5775 SCOPED_FLAG_OVERRIDE(split_all_touches, false);
5776 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
5777 sp<FakeWindowHandle> leftWindow =
5778 sp<FakeWindowHandle>::make(application, mDispatcher, "Left splittable Window",
5779 ui::LogicalDisplayId::DEFAULT);
5780 leftWindow->setPreventSplitting(false);
5781 leftWindow->setFrame(Rect(0, 0, 100, 100));
5782 sp<FakeWindowHandle> rightWindow =
5783 sp<FakeWindowHandle>::make(application, mDispatcher, "Right non-splittable Window",
5784 ui::LogicalDisplayId::DEFAULT);
5785 rightWindow->setPreventSplitting(true);
5786 rightWindow->setFrame(Rect(100, 100, 200, 200));
5787 mDispatcher->onWindowInfosChanged(
5788 {{*leftWindow->getInfo(), *rightWindow->getInfo()}, {}, 0, 0});
5789
5790 // Touch down on left, splittable window
5791 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
5792 .pointer(PointerBuilder(0, ToolType::FINGER).x(50).y(50))
5793 .build());
5794 leftWindow->consumeMotionEvent(WithMotionAction(ACTION_DOWN));
5795
5796 mDispatcher->notifyMotion(
5797 MotionArgsBuilder(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
5798 .pointer(PointerBuilder(/*id=*/0, ToolType::FINGER).x(50).y(50))
5799 .pointer(PointerBuilder(/*id=*/1, ToolType::FINGER).x(150).y(150))
5800 .build());
5801 leftWindow->assertNoEvents();
5802 rightWindow->assertNoEvents();
5803 }
5804
5805 /**
5806 * Three windows:
5807 * 1) A window on the left, with flag dup_to_wallpaper
5808 * 2) A window on the right, with flag slippery
5809 * 3) A wallpaper window under the left window
5810 * When touch slips from right window to left, the wallpaper should receive a similar slippery
5811 * enter event. Later on, when another device becomes active, the wallpaper should receive
5812 * consistent streams from the new device, and also from the old device.
5813 * This test attempts to reproduce a crash in the dispatcher where the wallpaper target's downTime
5814 * was not getting set during slippery entrance.
5815 */
TEST_F(InputDispatcherTest,WallpaperWindowWhenSlipperyAndMultiWindowMultiTouch)5816 TEST_F(InputDispatcherTest, WallpaperWindowWhenSlipperyAndMultiWindowMultiTouch) {
5817 SCOPED_FLAG_OVERRIDE(enable_multi_device_same_window_stream, true);
5818 std::shared_ptr<FakeApplicationHandle> application1 = std::make_shared<FakeApplicationHandle>();
5819 std::shared_ptr<FakeApplicationHandle> application2 = std::make_shared<FakeApplicationHandle>();
5820 std::shared_ptr<FakeApplicationHandle> application3 = std::make_shared<FakeApplicationHandle>();
5821 sp<FakeWindowHandle> wallpaper =
5822 sp<FakeWindowHandle>::make(application1, mDispatcher, "wallpaper",
5823 ui::LogicalDisplayId::DEFAULT);
5824 wallpaper->setIsWallpaper(true);
5825 wallpaper->setPreventSplitting(true);
5826 wallpaper->setTouchable(false);
5827
5828 sp<FakeWindowHandle> leftWindow = sp<FakeWindowHandle>::make(application2, mDispatcher, "Left",
5829 ui::LogicalDisplayId::DEFAULT);
5830 leftWindow->setTouchableRegion(Region{{0, 0, 100, 100}});
5831 leftWindow->setDupTouchToWallpaper(true);
5832
5833 sp<FakeWindowHandle> rightWindow =
5834 sp<FakeWindowHandle>::make(application3, mDispatcher, "Right",
5835 ui::LogicalDisplayId::DEFAULT);
5836 rightWindow->setTouchableRegion(Region{{100, 0, 200, 100}});
5837 rightWindow->setSlippery(true);
5838 rightWindow->setWatchOutsideTouch(true);
5839 rightWindow->setTrustedOverlay(true);
5840
5841 mDispatcher->onWindowInfosChanged(
5842 {{*rightWindow->getInfo(), *leftWindow->getInfo(), *wallpaper->getInfo()}, {}, 0, 0});
5843
5844 const DeviceId deviceA = 3;
5845 const DeviceId deviceB = 9;
5846
5847 // First finger from device A into right window
5848 NotifyMotionArgs deviceADownArgs =
5849 MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
5850 .pointer(PointerBuilder(0, ToolType::FINGER).x(150).y(50))
5851 .deviceId(deviceA)
5852 .build();
5853
5854 mDispatcher->notifyMotion(deviceADownArgs);
5855 rightWindow->consumeMotionEvent(WithMotionAction(ACTION_DOWN));
5856
5857 // Move the finger of device A from right window into left window. It should slip.
5858 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN)
5859 .pointer(PointerBuilder(0, ToolType::FINGER).x(80).y(50))
5860 .deviceId(deviceA)
5861 .downTime(deviceADownArgs.downTime)
5862 .build());
5863
5864 leftWindow->consumeMotionEvent(WithMotionAction(ACTION_DOWN));
5865 rightWindow->consumeMotionEvent(WithMotionAction(ACTION_CANCEL));
5866 wallpaper->consumeMotionEvent(WithMotionAction(ACTION_DOWN));
5867
5868 // Finger from device B down into left window
5869 NotifyMotionArgs deviceBDownArgs =
5870 MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
5871 .pointer(PointerBuilder(0, ToolType::FINGER).x(40).y(40))
5872 .deviceId(deviceB)
5873 .build();
5874 mDispatcher->notifyMotion(deviceBDownArgs);
5875 leftWindow->consumeMotionEvent(AllOf(WithDeviceId(deviceB), WithMotionAction(ACTION_DOWN)));
5876 wallpaper->consumeMotionEvent(AllOf(WithDeviceId(deviceB), WithMotionAction(ACTION_DOWN)));
5877
5878 rightWindow->consumeMotionEvent(AllOf(WithDeviceId(deviceB), WithMotionAction(ACTION_OUTSIDE)));
5879
5880 // Move finger from device B, still keeping it in the left window
5881 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN)
5882 .pointer(PointerBuilder(0, ToolType::FINGER).x(40).y(50))
5883 .deviceId(deviceB)
5884 .downTime(deviceBDownArgs.downTime)
5885 .build());
5886 leftWindow->consumeMotionEvent(AllOf(WithDeviceId(deviceB), WithMotionAction(ACTION_MOVE)));
5887 wallpaper->consumeMotionEvent(AllOf(WithDeviceId(deviceB), WithMotionAction(ACTION_MOVE)));
5888
5889 // Lift the finger from device B
5890 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN)
5891 .pointer(PointerBuilder(0, ToolType::FINGER).x(40).y(50))
5892 .deviceId(deviceB)
5893 .downTime(deviceBDownArgs.downTime)
5894 .build());
5895 leftWindow->consumeMotionEvent(AllOf(WithDeviceId(deviceB), WithMotionAction(ACTION_UP)));
5896 wallpaper->consumeMotionEvent(AllOf(WithDeviceId(deviceB), WithMotionAction(ACTION_UP)));
5897
5898 // Move the finger of device A, keeping it in the left window
5899 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN)
5900 .pointer(PointerBuilder(0, ToolType::FINGER).x(70).y(50))
5901 .deviceId(deviceA)
5902 .downTime(deviceADownArgs.downTime)
5903 .build());
5904
5905 leftWindow->consumeMotionEvent(AllOf(WithDeviceId(deviceA), WithMotionAction(ACTION_MOVE)));
5906 wallpaper->consumeMotionEvent(AllOf(WithDeviceId(deviceA), WithMotionAction(ACTION_MOVE)));
5907
5908 // Second finger down from device A, into the right window. It should be split into:
5909 // MOVE for the left window (due to existing implementation) + a DOWN into the right window
5910 // Wallpaper will not receive this new pointer, and it will only get the MOVE event.
5911 mDispatcher->notifyMotion(MotionArgsBuilder(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
5912 .pointer(PointerBuilder(0, ToolType::FINGER).x(70).y(50))
5913 .pointer(PointerBuilder(1, ToolType::FINGER).x(140).y(50))
5914 .deviceId(deviceA)
5915 .downTime(deviceADownArgs.downTime)
5916 .build());
5917 auto firstFingerMoveFromDeviceA = AllOf(WithDeviceId(deviceA), WithMotionAction(ACTION_MOVE),
5918 WithPointerCount(1), WithPointerId(0, 0));
5919 leftWindow->consumeMotionEvent(firstFingerMoveFromDeviceA);
5920 wallpaper->consumeMotionEvent(firstFingerMoveFromDeviceA);
5921 rightWindow->consumeMotionEvent(
5922 AllOf(WithDeviceId(deviceA), WithMotionAction(ACTION_DOWN), WithPointerId(0, 1)));
5923
5924 // Lift up the second finger.
5925 mDispatcher->notifyMotion(MotionArgsBuilder(POINTER_1_UP, AINPUT_SOURCE_TOUCHSCREEN)
5926 .pointer(PointerBuilder(0, ToolType::FINGER).x(70).y(50))
5927 .pointer(PointerBuilder(1, ToolType::FINGER).x(140).y(50))
5928 .deviceId(deviceA)
5929 .downTime(deviceADownArgs.downTime)
5930 .build());
5931
5932 rightWindow->consumeMotionEvent(AllOf(WithDeviceId(deviceA), WithMotionAction(ACTION_UP)));
5933 leftWindow->consumeMotionEvent(firstFingerMoveFromDeviceA);
5934 wallpaper->consumeMotionEvent(firstFingerMoveFromDeviceA);
5935
5936 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN)
5937 .pointer(PointerBuilder(0, ToolType::FINGER).x(70).y(50))
5938 .deviceId(deviceA)
5939 .downTime(deviceADownArgs.downTime)
5940 .build());
5941
5942 leftWindow->consumeMotionEvent(AllOf(WithDeviceId(deviceA), WithMotionAction(ACTION_UP)));
5943 wallpaper->consumeMotionEvent(AllOf(WithDeviceId(deviceA), WithMotionAction(ACTION_UP)));
5944 rightWindow->assertNoEvents();
5945 }
5946
5947 /**
5948 * Same test as above, but with enable_multi_device_same_window_stream flag set to false.
5949 */
TEST_F(InputDispatcherTest,WallpaperWindowWhenSlipperyAndMultiWindowMultiTouch_legacy)5950 TEST_F(InputDispatcherTest, WallpaperWindowWhenSlipperyAndMultiWindowMultiTouch_legacy) {
5951 SCOPED_FLAG_OVERRIDE(enable_multi_device_same_window_stream, false);
5952 std::shared_ptr<FakeApplicationHandle> application1 = std::make_shared<FakeApplicationHandle>();
5953 std::shared_ptr<FakeApplicationHandle> application2 = std::make_shared<FakeApplicationHandle>();
5954 std::shared_ptr<FakeApplicationHandle> application3 = std::make_shared<FakeApplicationHandle>();
5955 sp<FakeWindowHandle> wallpaper =
5956 sp<FakeWindowHandle>::make(application1, mDispatcher, "wallpaper",
5957 ui::LogicalDisplayId::DEFAULT);
5958 wallpaper->setIsWallpaper(true);
5959 wallpaper->setPreventSplitting(true);
5960 wallpaper->setTouchable(false);
5961
5962 sp<FakeWindowHandle> leftWindow = sp<FakeWindowHandle>::make(application2, mDispatcher, "Left",
5963 ui::LogicalDisplayId::DEFAULT);
5964 leftWindow->setTouchableRegion(Region{{0, 0, 100, 100}});
5965 leftWindow->setDupTouchToWallpaper(true);
5966
5967 sp<FakeWindowHandle> rightWindow =
5968 sp<FakeWindowHandle>::make(application3, mDispatcher, "Right",
5969 ui::LogicalDisplayId::DEFAULT);
5970 rightWindow->setTouchableRegion(Region{{100, 0, 200, 100}});
5971 rightWindow->setSlippery(true);
5972 rightWindow->setWatchOutsideTouch(true);
5973 rightWindow->setTrustedOverlay(true);
5974
5975 mDispatcher->onWindowInfosChanged(
5976 {{*rightWindow->getInfo(), *leftWindow->getInfo(), *wallpaper->getInfo()}, {}, 0, 0});
5977
5978 const DeviceId deviceA = 3;
5979 const DeviceId deviceB = 9;
5980
5981 // First finger from device A into right window
5982 NotifyMotionArgs deviceADownArgs =
5983 MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
5984 .pointer(PointerBuilder(0, ToolType::FINGER).x(150).y(50))
5985 .deviceId(deviceA)
5986 .build();
5987
5988 mDispatcher->notifyMotion(deviceADownArgs);
5989 rightWindow->consumeMotionEvent(WithMotionAction(ACTION_DOWN));
5990
5991 // Move the finger of device A from right window into left window. It should slip.
5992 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN)
5993 .pointer(PointerBuilder(0, ToolType::FINGER).x(80).y(50))
5994 .deviceId(deviceA)
5995 .downTime(deviceADownArgs.downTime)
5996 .build());
5997
5998 leftWindow->consumeMotionEvent(WithMotionAction(ACTION_DOWN));
5999 rightWindow->consumeMotionEvent(WithMotionAction(ACTION_CANCEL));
6000 wallpaper->consumeMotionEvent(WithMotionAction(ACTION_DOWN));
6001
6002 // Finger from device B down into left window
6003 NotifyMotionArgs deviceBDownArgs =
6004 MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
6005 .pointer(PointerBuilder(0, ToolType::FINGER).x(40).y(40))
6006 .deviceId(deviceB)
6007 .build();
6008 mDispatcher->notifyMotion(deviceBDownArgs);
6009 leftWindow->consumeMotionEvent(AllOf(WithDeviceId(deviceA), WithMotionAction(ACTION_CANCEL)));
6010 leftWindow->consumeMotionEvent(AllOf(WithDeviceId(deviceB), WithMotionAction(ACTION_DOWN)));
6011 wallpaper->consumeMotionEvent(AllOf(WithDeviceId(deviceA), WithMotionAction(ACTION_CANCEL)));
6012 wallpaper->consumeMotionEvent(AllOf(WithDeviceId(deviceB), WithMotionAction(ACTION_DOWN)));
6013
6014 rightWindow->consumeMotionEvent(AllOf(WithDeviceId(deviceB), WithMotionAction(ACTION_OUTSIDE)));
6015
6016 // Move finger from device B, still keeping it in the left window
6017 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN)
6018 .pointer(PointerBuilder(0, ToolType::FINGER).x(40).y(50))
6019 .deviceId(deviceB)
6020 .downTime(deviceBDownArgs.downTime)
6021 .build());
6022 leftWindow->consumeMotionEvent(AllOf(WithDeviceId(deviceB), WithMotionAction(ACTION_MOVE)));
6023 wallpaper->consumeMotionEvent(AllOf(WithDeviceId(deviceB), WithMotionAction(ACTION_MOVE)));
6024
6025 // Lift the finger from device B
6026 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN)
6027 .pointer(PointerBuilder(0, ToolType::FINGER).x(40).y(50))
6028 .deviceId(deviceB)
6029 .downTime(deviceBDownArgs.downTime)
6030 .build());
6031 leftWindow->consumeMotionEvent(AllOf(WithDeviceId(deviceB), WithMotionAction(ACTION_UP)));
6032 wallpaper->consumeMotionEvent(AllOf(WithDeviceId(deviceB), WithMotionAction(ACTION_UP)));
6033
6034 // Move the finger of device A, keeping it in the left window
6035 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN)
6036 .pointer(PointerBuilder(0, ToolType::FINGER).x(70).y(50))
6037 .deviceId(deviceA)
6038 .downTime(deviceADownArgs.downTime)
6039 .build());
6040 // This device was already canceled, so MOVE events will not be arriving to the windows from it.
6041
6042 // Second finger down from device A, into the right window. It should be split into:
6043 // MOVE for the left window (due to existing implementation) + a DOWN into the right window
6044 // Wallpaper will not receive this new pointer, and it will only get the MOVE event.
6045 mDispatcher->notifyMotion(MotionArgsBuilder(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
6046 .pointer(PointerBuilder(0, ToolType::FINGER).x(70).y(50))
6047 .pointer(PointerBuilder(1, ToolType::FINGER).x(140).y(50))
6048 .deviceId(deviceA)
6049 .downTime(deviceADownArgs.downTime)
6050 .build());
6051 rightWindow->consumeMotionEvent(
6052 AllOf(WithDeviceId(deviceA), WithMotionAction(ACTION_DOWN), WithPointerId(0, 1)));
6053
6054 // Lift up the second finger.
6055 mDispatcher->notifyMotion(MotionArgsBuilder(POINTER_1_UP, AINPUT_SOURCE_TOUCHSCREEN)
6056 .pointer(PointerBuilder(0, ToolType::FINGER).x(70).y(50))
6057 .pointer(PointerBuilder(1, ToolType::FINGER).x(140).y(50))
6058 .deviceId(deviceA)
6059 .downTime(deviceADownArgs.downTime)
6060 .build());
6061
6062 rightWindow->consumeMotionEvent(AllOf(WithDeviceId(deviceA), WithMotionAction(ACTION_UP)));
6063
6064 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN)
6065 .pointer(PointerBuilder(0, ToolType::FINGER).x(70).y(50))
6066 .deviceId(deviceA)
6067 .downTime(deviceADownArgs.downTime)
6068 .build());
6069 rightWindow->assertNoEvents();
6070 }
6071
6072 /**
6073 * Two windows: left and right. The left window has PREVENT_SPLITTING input config. Device A sends a
6074 * down event to the right window. Device B sends a down event to the left window, and then a
6075 * POINTER_DOWN event to the right window. However, since the left window prevents splitting, the
6076 * POINTER_DOWN event should only go to the left window, and not to the right window.
6077 * This test attempts to reproduce a crash.
6078 */
TEST_F(InputDispatcherTest,MultiDeviceTwoWindowsPreventSplitting)6079 TEST_F(InputDispatcherTest, MultiDeviceTwoWindowsPreventSplitting) {
6080 SCOPED_FLAG_OVERRIDE(split_all_touches, false);
6081 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
6082 sp<FakeWindowHandle> leftWindow =
6083 sp<FakeWindowHandle>::make(application, mDispatcher, "Left window (prevent splitting)",
6084 ui::LogicalDisplayId::DEFAULT);
6085 leftWindow->setFrame(Rect(0, 0, 100, 100));
6086 leftWindow->setPreventSplitting(true);
6087
6088 sp<FakeWindowHandle> rightWindow =
6089 sp<FakeWindowHandle>::make(application, mDispatcher, "Right window",
6090 ui::LogicalDisplayId::DEFAULT);
6091 rightWindow->setFrame(Rect(100, 0, 200, 100));
6092
6093 mDispatcher->onWindowInfosChanged(
6094 {{*leftWindow->getInfo(), *rightWindow->getInfo()}, {}, 0, 0});
6095
6096 const DeviceId deviceA = 9;
6097 const DeviceId deviceB = 3;
6098 // Touch the right window with device A
6099 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
6100 .pointer(PointerBuilder(0, ToolType::FINGER).x(150).y(50))
6101 .deviceId(deviceA)
6102 .build());
6103 rightWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(deviceA)));
6104 // Touch the left window with device B
6105 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
6106 .pointer(PointerBuilder(0, ToolType::FINGER).x(50).y(50))
6107 .deviceId(deviceB)
6108 .build());
6109 leftWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(deviceB)));
6110 // Send a second pointer from device B to the right window. It shouldn't go to the right window
6111 // because the left window prevents splitting.
6112 mDispatcher->notifyMotion(MotionArgsBuilder(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
6113 .deviceId(deviceB)
6114 .pointer(PointerBuilder(0, ToolType::FINGER).x(50).y(50))
6115 .pointer(PointerBuilder(1, ToolType::FINGER).x(120).y(120))
6116 .build());
6117 leftWindow->consumeMotionPointerDown(1, WithDeviceId(deviceB));
6118
6119 // Finish the gesture for both devices
6120 mDispatcher->notifyMotion(MotionArgsBuilder(POINTER_1_UP, AINPUT_SOURCE_TOUCHSCREEN)
6121 .deviceId(deviceB)
6122 .pointer(PointerBuilder(0, ToolType::FINGER).x(50).y(50))
6123 .pointer(PointerBuilder(1, ToolType::FINGER).x(120).y(120))
6124 .build());
6125 leftWindow->consumeMotionPointerUp(1, WithDeviceId(deviceB));
6126 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN)
6127 .pointer(PointerBuilder(0, ToolType::FINGER).x(50).y(50))
6128 .deviceId(deviceB)
6129 .build());
6130 leftWindow->consumeMotionEvent(
6131 AllOf(WithMotionAction(ACTION_UP), WithDeviceId(deviceB), WithPointerId(0, 0)));
6132 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN)
6133 .pointer(PointerBuilder(0, ToolType::FINGER).x(150).y(50))
6134 .deviceId(deviceA)
6135 .build());
6136 rightWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_UP), WithDeviceId(deviceA)));
6137 }
6138
TEST_F(InputDispatcherTest,TouchpadThreeFingerSwipeOnlySentToTrustedOverlays)6139 TEST_F(InputDispatcherTest, TouchpadThreeFingerSwipeOnlySentToTrustedOverlays) {
6140 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
6141 sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher, "Window",
6142 ui::LogicalDisplayId::DEFAULT);
6143 window->setFrame(Rect(0, 0, 400, 400));
6144 sp<FakeWindowHandle> trustedOverlay =
6145 sp<FakeWindowHandle>::make(application, mDispatcher, "Trusted Overlay",
6146 ui::LogicalDisplayId::DEFAULT);
6147 trustedOverlay->setSpy(true);
6148 trustedOverlay->setTrustedOverlay(true);
6149
6150 mDispatcher->onWindowInfosChanged({{*trustedOverlay->getInfo(), *window->getInfo()}, {}, 0, 0});
6151
6152 // Start a three-finger touchpad swipe
6153 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_MOUSE)
6154 .pointer(PointerBuilder(0, ToolType::FINGER).x(200).y(100))
6155 .classification(MotionClassification::MULTI_FINGER_SWIPE)
6156 .build());
6157 mDispatcher->notifyMotion(MotionArgsBuilder(POINTER_1_DOWN, AINPUT_SOURCE_MOUSE)
6158 .pointer(PointerBuilder(0, ToolType::FINGER).x(200).y(100))
6159 .pointer(PointerBuilder(1, ToolType::FINGER).x(250).y(100))
6160 .classification(MotionClassification::MULTI_FINGER_SWIPE)
6161 .build());
6162 mDispatcher->notifyMotion(MotionArgsBuilder(POINTER_2_DOWN, AINPUT_SOURCE_MOUSE)
6163 .pointer(PointerBuilder(0, ToolType::FINGER).x(200).y(100))
6164 .pointer(PointerBuilder(1, ToolType::FINGER).x(250).y(100))
6165 .pointer(PointerBuilder(2, ToolType::FINGER).x(300).y(100))
6166 .classification(MotionClassification::MULTI_FINGER_SWIPE)
6167 .build());
6168
6169 trustedOverlay->consumeMotionEvent(WithMotionAction(ACTION_DOWN));
6170 trustedOverlay->consumeMotionEvent(WithMotionAction(POINTER_1_DOWN));
6171 trustedOverlay->consumeMotionEvent(WithMotionAction(POINTER_2_DOWN));
6172
6173 // Move the swipe a bit
6174 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_MOUSE)
6175 .pointer(PointerBuilder(0, ToolType::FINGER).x(200).y(105))
6176 .pointer(PointerBuilder(1, ToolType::FINGER).x(250).y(105))
6177 .pointer(PointerBuilder(2, ToolType::FINGER).x(300).y(105))
6178 .classification(MotionClassification::MULTI_FINGER_SWIPE)
6179 .build());
6180
6181 trustedOverlay->consumeMotionEvent(WithMotionAction(ACTION_MOVE));
6182
6183 // End the swipe
6184 mDispatcher->notifyMotion(MotionArgsBuilder(POINTER_2_UP, AINPUT_SOURCE_MOUSE)
6185 .pointer(PointerBuilder(0, ToolType::FINGER).x(200).y(105))
6186 .pointer(PointerBuilder(1, ToolType::FINGER).x(250).y(105))
6187 .pointer(PointerBuilder(2, ToolType::FINGER).x(300).y(105))
6188 .classification(MotionClassification::MULTI_FINGER_SWIPE)
6189 .build());
6190 mDispatcher->notifyMotion(MotionArgsBuilder(POINTER_1_UP, AINPUT_SOURCE_MOUSE)
6191 .pointer(PointerBuilder(0, ToolType::FINGER).x(200).y(105))
6192 .pointer(PointerBuilder(1, ToolType::FINGER).x(250).y(105))
6193 .classification(MotionClassification::MULTI_FINGER_SWIPE)
6194 .build());
6195 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_UP, AINPUT_SOURCE_MOUSE)
6196 .pointer(PointerBuilder(0, ToolType::FINGER).x(200).y(105))
6197 .classification(MotionClassification::MULTI_FINGER_SWIPE)
6198 .build());
6199
6200 trustedOverlay->consumeMotionEvent(WithMotionAction(POINTER_2_UP));
6201 trustedOverlay->consumeMotionEvent(WithMotionAction(POINTER_1_UP));
6202 trustedOverlay->consumeMotionEvent(WithMotionAction(ACTION_UP));
6203
6204 window->assertNoEvents();
6205 }
6206
TEST_F(InputDispatcherTest,TouchpadThreeFingerSwipeNotSentToSingleWindow)6207 TEST_F(InputDispatcherTest, TouchpadThreeFingerSwipeNotSentToSingleWindow) {
6208 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
6209 sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher, "Window",
6210 ui::LogicalDisplayId::DEFAULT);
6211 window->setFrame(Rect(0, 0, 400, 400));
6212 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
6213
6214 // Start a three-finger touchpad swipe
6215 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_MOUSE)
6216 .pointer(PointerBuilder(0, ToolType::FINGER).x(200).y(100))
6217 .classification(MotionClassification::MULTI_FINGER_SWIPE)
6218 .build());
6219 mDispatcher->notifyMotion(MotionArgsBuilder(POINTER_1_DOWN, AINPUT_SOURCE_MOUSE)
6220 .pointer(PointerBuilder(0, ToolType::FINGER).x(200).y(100))
6221 .pointer(PointerBuilder(1, ToolType::FINGER).x(250).y(100))
6222 .classification(MotionClassification::MULTI_FINGER_SWIPE)
6223 .build());
6224 mDispatcher->notifyMotion(MotionArgsBuilder(POINTER_2_DOWN, AINPUT_SOURCE_MOUSE)
6225 .pointer(PointerBuilder(0, ToolType::FINGER).x(200).y(100))
6226 .pointer(PointerBuilder(1, ToolType::FINGER).x(250).y(100))
6227 .pointer(PointerBuilder(2, ToolType::FINGER).x(300).y(100))
6228 .classification(MotionClassification::MULTI_FINGER_SWIPE)
6229 .build());
6230
6231 // Move the swipe a bit
6232 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_MOUSE)
6233 .pointer(PointerBuilder(0, ToolType::FINGER).x(200).y(105))
6234 .pointer(PointerBuilder(1, ToolType::FINGER).x(250).y(105))
6235 .pointer(PointerBuilder(2, ToolType::FINGER).x(300).y(105))
6236 .classification(MotionClassification::MULTI_FINGER_SWIPE)
6237 .build());
6238
6239 // End the swipe
6240 mDispatcher->notifyMotion(MotionArgsBuilder(POINTER_2_UP, AINPUT_SOURCE_MOUSE)
6241 .pointer(PointerBuilder(0, ToolType::FINGER).x(200).y(105))
6242 .pointer(PointerBuilder(1, ToolType::FINGER).x(250).y(105))
6243 .pointer(PointerBuilder(2, ToolType::FINGER).x(300).y(105))
6244 .classification(MotionClassification::MULTI_FINGER_SWIPE)
6245 .build());
6246 mDispatcher->notifyMotion(MotionArgsBuilder(POINTER_1_UP, AINPUT_SOURCE_MOUSE)
6247 .pointer(PointerBuilder(0, ToolType::FINGER).x(200).y(105))
6248 .pointer(PointerBuilder(1, ToolType::FINGER).x(250).y(105))
6249 .classification(MotionClassification::MULTI_FINGER_SWIPE)
6250 .build());
6251 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_UP, AINPUT_SOURCE_MOUSE)
6252 .pointer(PointerBuilder(0, ToolType::FINGER).x(200).y(105))
6253 .classification(MotionClassification::MULTI_FINGER_SWIPE)
6254 .build());
6255
6256 window->assertNoEvents();
6257 }
6258
6259 /**
6260 * Send a two-pointer gesture to a single window. The window's orientation changes in response to
6261 * the first pointer.
6262 * Ensure that the second pointer and the subsequent gesture is correctly delivered to the window.
6263 */
TEST_F(InputDispatcherTest,MultiplePointersWithRotatingWindow)6264 TEST_F(InputDispatcherTest, MultiplePointersWithRotatingWindow) {
6265 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
6266 sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher, "Window",
6267 ui::LogicalDisplayId::DEFAULT);
6268 window->setFrame(Rect(0, 0, 400, 400));
6269 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
6270
6271 const nsecs_t baseTime = systemTime(SYSTEM_TIME_MONOTONIC);
6272 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
6273 .downTime(baseTime + 10)
6274 .eventTime(baseTime + 10)
6275 .pointer(PointerBuilder(0, ToolType::FINGER).x(100).y(100))
6276 .build());
6277
6278 window->consumeMotionEvent(WithMotionAction(ACTION_DOWN));
6279
6280 // Change the transform so that the orientation is now different from original.
6281 window->setWindowTransform(0, -1, 1, 0);
6282
6283 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
6284
6285 mDispatcher->notifyMotion(MotionArgsBuilder(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
6286 .downTime(baseTime + 10)
6287 .eventTime(baseTime + 30)
6288 .pointer(PointerBuilder(0, ToolType::FINGER).x(100).y(100))
6289 .pointer(PointerBuilder(1, ToolType::FINGER).x(200).y(200))
6290 .build());
6291
6292 window->consumeMotionEvent(WithMotionAction(POINTER_1_DOWN));
6293
6294 // Finish the gesture and start a new one. Ensure all events are sent to the window.
6295 mDispatcher->notifyMotion(MotionArgsBuilder(POINTER_1_UP, AINPUT_SOURCE_TOUCHSCREEN)
6296 .downTime(baseTime + 10)
6297 .eventTime(baseTime + 40)
6298 .pointer(PointerBuilder(0, ToolType::FINGER).x(100).y(100))
6299 .pointer(PointerBuilder(1, ToolType::FINGER).x(200).y(200))
6300 .build());
6301
6302 window->consumeMotionEvent(WithMotionAction(POINTER_1_UP));
6303
6304 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN)
6305 .downTime(baseTime + 10)
6306 .eventTime(baseTime + 50)
6307 .pointer(PointerBuilder(0, ToolType::FINGER).x(100).y(100))
6308 .build());
6309
6310 window->consumeMotionEvent(WithMotionAction(ACTION_UP));
6311
6312 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
6313 .downTime(baseTime + 60)
6314 .eventTime(baseTime + 60)
6315 .pointer(PointerBuilder(0, ToolType::FINGER).x(40).y(40))
6316 .build());
6317
6318 window->consumeMotionEvent(WithMotionAction(ACTION_DOWN));
6319 }
6320
6321 /**
6322 * When there are multiple screens, such as screen projection to TV or screen recording, if the
6323 * cancel event occurs, the coordinates of the cancel event should be sent to the target screen, and
6324 * its coordinates should be converted by the transform of the windows of target screen.
6325 */
TEST_F(InputDispatcherTest,WhenMultiDisplayWindowSameToken_DispatchCancelToTargetDisplay)6326 TEST_F(InputDispatcherTest, WhenMultiDisplayWindowSameToken_DispatchCancelToTargetDisplay) {
6327 // This case will create a window and a spy window on the default display and mirror
6328 // window on the second display. cancel event is sent through spy window pilferPointers
6329 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
6330
6331 sp<FakeWindowHandle> spyWindowDefaultDisplay =
6332 sp<FakeWindowHandle>::make(application, mDispatcher, "Spy",
6333 ui::LogicalDisplayId::DEFAULT);
6334 spyWindowDefaultDisplay->setTrustedOverlay(true);
6335 spyWindowDefaultDisplay->setSpy(true);
6336
6337 sp<FakeWindowHandle> windowDefaultDisplay =
6338 sp<FakeWindowHandle>::make(application, mDispatcher, "DefaultDisplay",
6339 ui::LogicalDisplayId::DEFAULT);
6340 windowDefaultDisplay->setWindowTransform(1, 0, 0, 1);
6341
6342 sp<FakeWindowHandle> windowSecondDisplay = windowDefaultDisplay->clone(SECOND_DISPLAY_ID);
6343 windowSecondDisplay->setWindowTransform(2, 0, 0, 2);
6344
6345 // Add the windows to the dispatcher
6346 mDispatcher->onWindowInfosChanged(
6347 {{*spyWindowDefaultDisplay->getInfo(), *windowDefaultDisplay->getInfo(),
6348 *windowSecondDisplay->getInfo()},
6349 {},
6350 0,
6351 0});
6352
6353 // Send down to ui::LogicalDisplayId::DEFAULT
6354 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
6355 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN,
6356 ui::LogicalDisplayId::DEFAULT, {100, 100}))
6357 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
6358
6359 spyWindowDefaultDisplay->consumeMotionDown();
6360 windowDefaultDisplay->consumeMotionDown();
6361
6362 EXPECT_EQ(OK, mDispatcher->pilferPointers(spyWindowDefaultDisplay->getToken()));
6363
6364 // windowDefaultDisplay gets cancel
6365 std::unique_ptr<MotionEvent> event = windowDefaultDisplay->consumeMotionEvent();
6366 ASSERT_NE(nullptr, event);
6367 EXPECT_EQ(AMOTION_EVENT_ACTION_CANCEL, event->getAction());
6368
6369 // The cancel event is sent to windowDefaultDisplay of the ui::LogicalDisplayId::DEFAULT
6370 // display, so the coordinates of the cancel are converted by windowDefaultDisplay's transform,
6371 // the x and y coordinates are both 100, otherwise if the cancel event is sent to
6372 // windowSecondDisplay of SECOND_DISPLAY_ID, the x and y coordinates are 200
6373 EXPECT_EQ(100, event->getX(0));
6374 EXPECT_EQ(100, event->getY(0));
6375 }
6376
6377 /**
6378 * Ensure the correct coordinate spaces are used by InputDispatcher.
6379 *
6380 * InputDispatcher works in the display space, so its coordinate system is relative to the display
6381 * panel. Windows get events in the window space, and get raw coordinates in the logical display
6382 * space.
6383 */
6384 class InputDispatcherDisplayProjectionTest : public InputDispatcherTest {
6385 public:
SetUp()6386 void SetUp() override {
6387 InputDispatcherTest::SetUp();
6388 removeAllWindowsAndDisplays();
6389 }
6390
addDisplayInfo(ui::LogicalDisplayId displayId,const ui::Transform & transform)6391 void addDisplayInfo(ui::LogicalDisplayId displayId, const ui::Transform& transform) {
6392 gui::DisplayInfo info;
6393 info.displayId = displayId;
6394 info.transform = transform;
6395 mDisplayInfos.push_back(std::move(info));
6396 mDispatcher->onWindowInfosChanged({mWindowInfos, mDisplayInfos, 0, 0});
6397 }
6398
addWindow(const sp<WindowInfoHandle> & windowHandle)6399 void addWindow(const sp<WindowInfoHandle>& windowHandle) {
6400 mWindowInfos.push_back(*windowHandle->getInfo());
6401 mDispatcher->onWindowInfosChanged({mWindowInfos, mDisplayInfos, 0, 0});
6402 }
6403
removeAllWindowsAndDisplays()6404 void removeAllWindowsAndDisplays() {
6405 mDisplayInfos.clear();
6406 mWindowInfos.clear();
6407 }
6408
6409 // Set up a test scenario where the display has a scaled projection and there are two windows
6410 // on the display.
setupScaledDisplayScenario()6411 std::pair<sp<FakeWindowHandle>, sp<FakeWindowHandle>> setupScaledDisplayScenario() {
6412 // The display has a projection that has a scale factor of 2 and 4 in the x and y directions
6413 // respectively.
6414 ui::Transform displayTransform;
6415 displayTransform.set(2, 0, 0, 4);
6416 addDisplayInfo(ui::LogicalDisplayId::DEFAULT, displayTransform);
6417
6418 std::shared_ptr<FakeApplicationHandle> application =
6419 std::make_shared<FakeApplicationHandle>();
6420
6421 // Add two windows to the display. Their frames are represented in the display space.
6422 sp<FakeWindowHandle> firstWindow =
6423 sp<FakeWindowHandle>::make(application, mDispatcher, "First Window",
6424 ui::LogicalDisplayId::DEFAULT);
6425 firstWindow->setFrame(Rect(0, 0, 100, 200), displayTransform);
6426 addWindow(firstWindow);
6427
6428 sp<FakeWindowHandle> secondWindow =
6429 sp<FakeWindowHandle>::make(application, mDispatcher, "Second Window",
6430 ui::LogicalDisplayId::DEFAULT);
6431 secondWindow->setFrame(Rect(100, 200, 200, 400), displayTransform);
6432 addWindow(secondWindow);
6433 return {std::move(firstWindow), std::move(secondWindow)};
6434 }
6435
6436 private:
6437 std::vector<gui::DisplayInfo> mDisplayInfos;
6438 std::vector<gui::WindowInfo> mWindowInfos;
6439 };
6440
TEST_F(InputDispatcherDisplayProjectionTest,HitTestCoordinateSpaceConsistency)6441 TEST_F(InputDispatcherDisplayProjectionTest, HitTestCoordinateSpaceConsistency) {
6442 auto [firstWindow, secondWindow] = setupScaledDisplayScenario();
6443 // Send down to the first window. The point is represented in the display space. The point is
6444 // selected so that if the hit test was performed with the point and the bounds being in
6445 // different coordinate spaces, the event would end up in the incorrect window.
6446 mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_DOWN,
6447 AINPUT_SOURCE_TOUCHSCREEN,
6448 ui::LogicalDisplayId::DEFAULT, {PointF{75, 55}}));
6449
6450 firstWindow->consumeMotionDown();
6451 secondWindow->assertNoEvents();
6452 }
6453
6454 // Ensure that when a MotionEvent is injected through the InputDispatcher::injectInputEvent() API,
6455 // the event should be treated as being in the logical display space.
TEST_F(InputDispatcherDisplayProjectionTest,InjectionInLogicalDisplaySpace)6456 TEST_F(InputDispatcherDisplayProjectionTest, InjectionInLogicalDisplaySpace) {
6457 auto [firstWindow, secondWindow] = setupScaledDisplayScenario();
6458 // Send down to the first window. The point is represented in the logical display space. The
6459 // point is selected so that if the hit test was done in logical display space, then it would
6460 // end up in the incorrect window.
6461 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ui::LogicalDisplayId::DEFAULT,
6462 PointF{75 * 2, 55 * 4});
6463
6464 firstWindow->consumeMotionDown();
6465 secondWindow->assertNoEvents();
6466 }
6467
6468 // Ensure that when a MotionEvent that has a custom transform is injected, the post-transformed
6469 // event should be treated as being in the logical display space.
TEST_F(InputDispatcherDisplayProjectionTest,InjectionWithTransformInLogicalDisplaySpace)6470 TEST_F(InputDispatcherDisplayProjectionTest, InjectionWithTransformInLogicalDisplaySpace) {
6471 auto [firstWindow, secondWindow] = setupScaledDisplayScenario();
6472
6473 const std::array<float, 9> matrix = {1.1, 2.2, 3.3, 4.4, 5.5, 6.6, 0.0, 0.0, 1.0};
6474 ui::Transform injectedEventTransform;
6475 injectedEventTransform.set(matrix);
6476 const vec2 expectedPoint{75, 55}; // The injected point in the logical display space.
6477 const vec2 untransformedPoint = injectedEventTransform.inverse().transform(expectedPoint);
6478
6479 MotionEvent event = MotionEventBuilder(AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
6480 .displayId(ui::LogicalDisplayId::DEFAULT)
6481 .eventTime(systemTime(SYSTEM_TIME_MONOTONIC))
6482 .pointer(PointerBuilder(/*id=*/0, ToolType::FINGER)
6483 .x(untransformedPoint.x)
6484 .y(untransformedPoint.y))
6485 .build();
6486 event.transform(matrix);
6487
6488 injectMotionEvent(*mDispatcher, event, INJECT_EVENT_TIMEOUT,
6489 InputEventInjectionSync::WAIT_FOR_RESULT);
6490
6491 firstWindow->consumeMotionDown();
6492 secondWindow->assertNoEvents();
6493 }
6494
TEST_F(InputDispatcherDisplayProjectionTest,WindowGetsEventsInCorrectCoordinateSpace)6495 TEST_F(InputDispatcherDisplayProjectionTest, WindowGetsEventsInCorrectCoordinateSpace) {
6496 auto [firstWindow, secondWindow] = setupScaledDisplayScenario();
6497
6498 // Send down to the second window.
6499 mDispatcher->notifyMotion(
6500 generateMotionArgs(AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN,
6501 ui::LogicalDisplayId::DEFAULT, {PointF{150, 220}}));
6502
6503 firstWindow->assertNoEvents();
6504 std::unique_ptr<MotionEvent> event = secondWindow->consumeMotionEvent();
6505 ASSERT_NE(nullptr, event);
6506 EXPECT_EQ(AMOTION_EVENT_ACTION_DOWN, event->getAction());
6507
6508 // Ensure that the events from the "getRaw" API are in logical display coordinates.
6509 EXPECT_EQ(300, event->getRawX(0));
6510 EXPECT_EQ(880, event->getRawY(0));
6511
6512 // Ensure that the x and y values are in the window's coordinate space.
6513 // The left-top of the second window is at (100, 200) in display space, which is (200, 800) in
6514 // the logical display space. This will be the origin of the window space.
6515 EXPECT_EQ(100, event->getX(0));
6516 EXPECT_EQ(80, event->getY(0));
6517 }
6518
TEST_F(InputDispatcherDisplayProjectionTest,CancelMotionWithCorrectCoordinates)6519 TEST_F(InputDispatcherDisplayProjectionTest, CancelMotionWithCorrectCoordinates) {
6520 auto [firstWindow, secondWindow] = setupScaledDisplayScenario();
6521 // The monitor will always receive events in the logical display's coordinate space, because
6522 // it does not have a window.
6523 FakeMonitorReceiver monitor{*mDispatcher, "Monitor", ui::LogicalDisplayId::DEFAULT};
6524
6525 // Send down to the first window.
6526 mDispatcher->notifyMotion(generateMotionArgs(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN,
6527 ui::LogicalDisplayId::DEFAULT, {PointF{50, 100}}));
6528 firstWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithCoords(100, 400)));
6529 monitor.consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithCoords(100, 400)));
6530
6531 // Second pointer goes down on second window.
6532 mDispatcher->notifyMotion(generateMotionArgs(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN,
6533 ui::LogicalDisplayId::DEFAULT,
6534 {PointF{50, 100}, PointF{150, 220}}));
6535 secondWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithCoords(100, 80)));
6536 const std::map<int32_t, PointF> expectedMonitorPointers{{0, PointF{100, 400}},
6537 {1, PointF{300, 880}}};
6538 monitor.consumeMotionEvent(
6539 AllOf(WithMotionAction(POINTER_1_DOWN), WithPointers(expectedMonitorPointers)));
6540
6541 mDispatcher->cancelCurrentTouch();
6542
6543 firstWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_CANCEL), WithCoords(100, 400)));
6544 secondWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_CANCEL), WithCoords(100, 80)));
6545 monitor.consumeMotionEvent(
6546 AllOf(WithMotionAction(ACTION_CANCEL), WithPointers(expectedMonitorPointers)));
6547 }
6548
TEST_F(InputDispatcherDisplayProjectionTest,SynthesizeDownWithCorrectCoordinates)6549 TEST_F(InputDispatcherDisplayProjectionTest, SynthesizeDownWithCorrectCoordinates) {
6550 auto [firstWindow, secondWindow] = setupScaledDisplayScenario();
6551
6552 // Send down to the first window.
6553 mDispatcher->notifyMotion(generateMotionArgs(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN,
6554 ui::LogicalDisplayId::DEFAULT, {PointF{50, 100}}));
6555 firstWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithCoords(100, 400)));
6556
6557 // The pointer is transferred to the second window, and the second window receives it in the
6558 // correct coordinate space.
6559 mDispatcher->transferTouchGesture(firstWindow->getToken(), secondWindow->getToken());
6560 firstWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_CANCEL), WithCoords(100, 400)));
6561 secondWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithCoords(-100, -400)));
6562 }
6563
TEST_F(InputDispatcherDisplayProjectionTest,SynthesizeHoverEnterExitWithCorrectCoordinates)6564 TEST_F(InputDispatcherDisplayProjectionTest, SynthesizeHoverEnterExitWithCorrectCoordinates) {
6565 auto [firstWindow, secondWindow] = setupScaledDisplayScenario();
6566
6567 // Send hover move to the second window, and ensure it shows up as hover enter.
6568 mDispatcher->notifyMotion(generateMotionArgs(ACTION_HOVER_MOVE, AINPUT_SOURCE_STYLUS,
6569 ui::LogicalDisplayId::DEFAULT,
6570 {PointF{150, 220}}));
6571 secondWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_HOVER_ENTER),
6572 WithCoords(100, 80), WithRawCoords(300, 880)));
6573
6574 // Touch down at the same location and ensure a hover exit is synthesized.
6575 mDispatcher->notifyMotion(generateMotionArgs(ACTION_DOWN, AINPUT_SOURCE_STYLUS,
6576 ui::LogicalDisplayId::DEFAULT,
6577 {PointF{150, 220}}));
6578 secondWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_HOVER_EXIT), WithCoords(100, 80),
6579 WithRawCoords(300, 880)));
6580 secondWindow->consumeMotionEvent(
6581 AllOf(WithMotionAction(ACTION_DOWN), WithCoords(100, 80), WithRawCoords(300, 880)));
6582 secondWindow->assertNoEvents();
6583 firstWindow->assertNoEvents();
6584 }
6585
6586 // Same as above, but while the window is being mirrored.
TEST_F(InputDispatcherDisplayProjectionTest,SynthesizeHoverEnterExitWithCorrectCoordinatesWhenMirrored)6587 TEST_F(InputDispatcherDisplayProjectionTest,
6588 SynthesizeHoverEnterExitWithCorrectCoordinatesWhenMirrored) {
6589 auto [firstWindow, secondWindow] = setupScaledDisplayScenario();
6590
6591 const std::array<float, 9> matrix = {1.1, 2.2, 3.3, 4.4, 5.5, 6.6, 0.0, 0.0, 1.0};
6592 ui::Transform secondDisplayTransform;
6593 secondDisplayTransform.set(matrix);
6594 addDisplayInfo(SECOND_DISPLAY_ID, secondDisplayTransform);
6595
6596 sp<FakeWindowHandle> secondWindowClone = secondWindow->clone(SECOND_DISPLAY_ID);
6597 secondWindowClone->setWindowTransform(1.1, 2.2, 3.3, 4.4);
6598 addWindow(secondWindowClone);
6599
6600 // Send hover move to the second window, and ensure it shows up as hover enter.
6601 mDispatcher->notifyMotion(generateMotionArgs(ACTION_HOVER_MOVE, AINPUT_SOURCE_STYLUS,
6602 ui::LogicalDisplayId::DEFAULT,
6603 {PointF{150, 220}}));
6604 secondWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_HOVER_ENTER),
6605 WithCoords(100, 80), WithRawCoords(300, 880)));
6606
6607 // Touch down at the same location and ensure a hover exit is synthesized for the correct
6608 // display.
6609 mDispatcher->notifyMotion(generateMotionArgs(ACTION_DOWN, AINPUT_SOURCE_STYLUS,
6610 ui::LogicalDisplayId::DEFAULT,
6611 {PointF{150, 220}}));
6612 secondWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_HOVER_EXIT), WithCoords(100, 80),
6613 WithRawCoords(300, 880)));
6614 secondWindow->consumeMotionEvent(
6615 AllOf(WithMotionAction(ACTION_DOWN), WithCoords(100, 80), WithRawCoords(300, 880)));
6616 secondWindow->assertNoEvents();
6617 firstWindow->assertNoEvents();
6618 }
6619
TEST_F(InputDispatcherDisplayProjectionTest,SynthesizeHoverCancelationWithCorrectCoordinates)6620 TEST_F(InputDispatcherDisplayProjectionTest, SynthesizeHoverCancelationWithCorrectCoordinates) {
6621 auto [firstWindow, secondWindow] = setupScaledDisplayScenario();
6622
6623 // Send hover enter to second window
6624 mDispatcher->notifyMotion(generateMotionArgs(ACTION_HOVER_ENTER, AINPUT_SOURCE_STYLUS,
6625 ui::LogicalDisplayId::DEFAULT,
6626 {PointF{150, 220}}));
6627 secondWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_HOVER_ENTER),
6628 WithCoords(100, 80), WithRawCoords(300, 880)));
6629
6630 mDispatcher->cancelCurrentTouch();
6631
6632 secondWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_HOVER_EXIT), WithCoords(100, 80),
6633 WithRawCoords(300, 880)));
6634 secondWindow->assertNoEvents();
6635 firstWindow->assertNoEvents();
6636 }
6637
6638 // Same as above, but while the window is being mirrored.
TEST_F(InputDispatcherDisplayProjectionTest,SynthesizeHoverCancelationWithCorrectCoordinatesWhenMirrored)6639 TEST_F(InputDispatcherDisplayProjectionTest,
6640 SynthesizeHoverCancelationWithCorrectCoordinatesWhenMirrored) {
6641 auto [firstWindow, secondWindow] = setupScaledDisplayScenario();
6642
6643 const std::array<float, 9> matrix = {1.1, 2.2, 3.3, 4.4, 5.5, 6.6, 0.0, 0.0, 1.0};
6644 ui::Transform secondDisplayTransform;
6645 secondDisplayTransform.set(matrix);
6646 addDisplayInfo(SECOND_DISPLAY_ID, secondDisplayTransform);
6647
6648 sp<FakeWindowHandle> secondWindowClone = secondWindow->clone(SECOND_DISPLAY_ID);
6649 secondWindowClone->setWindowTransform(1.1, 2.2, 3.3, 4.4);
6650 addWindow(secondWindowClone);
6651
6652 // Send hover enter to second window
6653 mDispatcher->notifyMotion(generateMotionArgs(ACTION_HOVER_ENTER, AINPUT_SOURCE_STYLUS,
6654 ui::LogicalDisplayId::DEFAULT,
6655 {PointF{150, 220}}));
6656 secondWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_HOVER_ENTER),
6657 WithCoords(100, 80), WithRawCoords(300, 880),
6658 WithDisplayId(ui::LogicalDisplayId::DEFAULT)));
6659
6660 mDispatcher->cancelCurrentTouch();
6661
6662 // Ensure the cancelation happens with the correct displayId and the correct coordinates.
6663 secondWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_HOVER_EXIT), WithCoords(100, 80),
6664 WithRawCoords(300, 880),
6665 WithDisplayId(ui::LogicalDisplayId::DEFAULT)));
6666 secondWindow->assertNoEvents();
6667 firstWindow->assertNoEvents();
6668 }
6669
6670 /** Ensure consistent behavior of InputDispatcher in all orientations. */
6671 class InputDispatcherDisplayOrientationFixture
6672 : public InputDispatcherDisplayProjectionTest,
6673 public ::testing::WithParamInterface<ui::Rotation> {};
6674
6675 // This test verifies the touchable region of a window for all rotations of the display by tapping
6676 // in different locations on the display, specifically points close to the four corners of a
6677 // window.
TEST_P(InputDispatcherDisplayOrientationFixture,HitTestInDifferentOrientations)6678 TEST_P(InputDispatcherDisplayOrientationFixture, HitTestInDifferentOrientations) {
6679 constexpr static int32_t displayWidth = 400;
6680 constexpr static int32_t displayHeight = 800;
6681
6682 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
6683
6684 const auto rotation = GetParam();
6685
6686 // Set up the display with the specified rotation.
6687 const bool isRotated = rotation == ui::ROTATION_90 || rotation == ui::ROTATION_270;
6688 const int32_t logicalDisplayWidth = isRotated ? displayHeight : displayWidth;
6689 const int32_t logicalDisplayHeight = isRotated ? displayWidth : displayHeight;
6690 const ui::Transform displayTransform(ui::Transform::toRotationFlags(rotation),
6691 logicalDisplayWidth, logicalDisplayHeight);
6692 addDisplayInfo(ui::LogicalDisplayId::DEFAULT, displayTransform);
6693
6694 // Create a window with its bounds determined in the logical display.
6695 const Rect frameInLogicalDisplay(100, 100, 200, 300);
6696 const Rect frameInDisplay = displayTransform.inverse().transform(frameInLogicalDisplay);
6697 sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher, "Window",
6698 ui::LogicalDisplayId::DEFAULT);
6699 window->setFrame(frameInDisplay, displayTransform);
6700 addWindow(window);
6701
6702 // The following points in logical display space should be inside the window.
6703 static const std::array<vec2, 4> insidePoints{
6704 {{100, 100}, {199.99, 100}, {100, 299.99}, {199.99, 299.99}}};
6705 for (const auto pointInsideWindow : insidePoints) {
6706 const vec2 p = displayTransform.inverse().transform(pointInsideWindow);
6707 const PointF pointInDisplaySpace{p.x, p.y};
6708 mDispatcher->notifyMotion(
6709 generateMotionArgs(AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN,
6710 ui::LogicalDisplayId::DEFAULT, {pointInDisplaySpace}));
6711 window->consumeMotionDown();
6712
6713 mDispatcher->notifyMotion(
6714 generateMotionArgs(AMOTION_EVENT_ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN,
6715 ui::LogicalDisplayId::DEFAULT, {pointInDisplaySpace}));
6716 window->consumeMotionUp();
6717 }
6718
6719 // The following points in logical display space should be outside the window.
6720 static const std::array<vec2, 5> outsidePoints{
6721 {{200, 100}, {100, 300}, {200, 300}, {100, 99.99}, {99.99, 100}}};
6722 for (const auto pointOutsideWindow : outsidePoints) {
6723 const vec2 p = displayTransform.inverse().transform(pointOutsideWindow);
6724 const PointF pointInDisplaySpace{p.x, p.y};
6725 mDispatcher->notifyMotion(
6726 generateMotionArgs(AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN,
6727 ui::LogicalDisplayId::DEFAULT, {pointInDisplaySpace}));
6728
6729 mDispatcher->notifyMotion(
6730 generateMotionArgs(AMOTION_EVENT_ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN,
6731 ui::LogicalDisplayId::DEFAULT, {pointInDisplaySpace}));
6732 }
6733 window->assertNoEvents();
6734 }
6735
6736 // This test verifies the occlusion detection for all rotations of the display by tapping
6737 // in different locations on the display, specifically points close to the four corners of a
6738 // window.
TEST_P(InputDispatcherDisplayOrientationFixture,BlockUntrustClickInDifferentOrientations)6739 TEST_P(InputDispatcherDisplayOrientationFixture, BlockUntrustClickInDifferentOrientations) {
6740 constexpr static int32_t displayWidth = 400;
6741 constexpr static int32_t displayHeight = 800;
6742
6743 std::shared_ptr<FakeApplicationHandle> untrustedWindowApplication =
6744 std::make_shared<FakeApplicationHandle>();
6745 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
6746
6747 const auto rotation = GetParam();
6748
6749 // Set up the display with the specified rotation.
6750 const bool isRotated = rotation == ui::ROTATION_90 || rotation == ui::ROTATION_270;
6751 const int32_t logicalDisplayWidth = isRotated ? displayHeight : displayWidth;
6752 const int32_t logicalDisplayHeight = isRotated ? displayWidth : displayHeight;
6753 const ui::Transform displayTransform(ui::Transform::toRotationFlags(rotation),
6754 logicalDisplayWidth, logicalDisplayHeight);
6755 addDisplayInfo(ui::LogicalDisplayId::DEFAULT, displayTransform);
6756
6757 // Create a window that not trusted.
6758 const Rect untrustedWindowFrameInLogicalDisplay(100, 100, 200, 300);
6759
6760 const Rect untrustedWindowFrameInDisplay =
6761 displayTransform.inverse().transform(untrustedWindowFrameInLogicalDisplay);
6762
6763 sp<FakeWindowHandle> untrustedWindow =
6764 sp<FakeWindowHandle>::make(untrustedWindowApplication, mDispatcher, "UntrustedWindow",
6765 ui::LogicalDisplayId::DEFAULT);
6766 untrustedWindow->setFrame(untrustedWindowFrameInDisplay, displayTransform);
6767 untrustedWindow->setTrustedOverlay(false);
6768 untrustedWindow->setTouchOcclusionMode(TouchOcclusionMode::BLOCK_UNTRUSTED);
6769 untrustedWindow->setTouchable(false);
6770 untrustedWindow->setAlpha(1.0f);
6771 untrustedWindow->setOwnerInfo(gui::Pid{1}, gui::Uid{101});
6772 addWindow(untrustedWindow);
6773
6774 // Create a simple app window below the untrusted window.
6775 const Rect simpleAppWindowFrameInLogicalDisplay(0, 0, 300, 600);
6776 const Rect simpleAppWindowFrameInDisplay =
6777 displayTransform.inverse().transform(simpleAppWindowFrameInLogicalDisplay);
6778
6779 sp<FakeWindowHandle> simpleAppWindow =
6780 sp<FakeWindowHandle>::make(application, mDispatcher, "SimpleAppWindow",
6781 ui::LogicalDisplayId::DEFAULT);
6782 simpleAppWindow->setFrame(simpleAppWindowFrameInDisplay, displayTransform);
6783 simpleAppWindow->setOwnerInfo(gui::Pid{2}, gui::Uid{202});
6784 addWindow(simpleAppWindow);
6785
6786 // The following points in logical display space should be inside the untrusted window, so
6787 // the simple window could not receive events that coordinate is these point.
6788 static const std::array<vec2, 4> untrustedPoints{
6789 {{100, 100}, {199.99, 100}, {100, 299.99}, {199.99, 299.99}}};
6790
6791 for (const auto untrustedPoint : untrustedPoints) {
6792 const vec2 p = displayTransform.inverse().transform(untrustedPoint);
6793 const PointF pointInDisplaySpace{p.x, p.y};
6794 mDispatcher->notifyMotion(
6795 generateMotionArgs(AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN,
6796 ui::LogicalDisplayId::DEFAULT, {pointInDisplaySpace}));
6797 mDispatcher->notifyMotion(
6798 generateMotionArgs(AMOTION_EVENT_ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN,
6799 ui::LogicalDisplayId::DEFAULT, {pointInDisplaySpace}));
6800 }
6801 untrustedWindow->assertNoEvents();
6802 simpleAppWindow->assertNoEvents();
6803 // The following points in logical display space should be outside the untrusted window, so
6804 // the simple window should receive events that coordinate is these point.
6805 static const std::array<vec2, 5> trustedPoints{
6806 {{200, 100}, {100, 300}, {200, 300}, {100, 99.99}, {99.99, 100}}};
6807 for (const auto trustedPoint : trustedPoints) {
6808 const vec2 p = displayTransform.inverse().transform(trustedPoint);
6809 const PointF pointInDisplaySpace{p.x, p.y};
6810 mDispatcher->notifyMotion(
6811 generateMotionArgs(AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN,
6812 ui::LogicalDisplayId::DEFAULT, {pointInDisplaySpace}));
6813 simpleAppWindow->consumeMotionDown(ui::LogicalDisplayId::DEFAULT,
6814 AMOTION_EVENT_FLAG_WINDOW_IS_PARTIALLY_OBSCURED);
6815 mDispatcher->notifyMotion(
6816 generateMotionArgs(AMOTION_EVENT_ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN,
6817 ui::LogicalDisplayId::DEFAULT, {pointInDisplaySpace}));
6818 simpleAppWindow->consumeMotionUp(ui::LogicalDisplayId::DEFAULT,
6819 AMOTION_EVENT_FLAG_WINDOW_IS_PARTIALLY_OBSCURED);
6820 }
6821 untrustedWindow->assertNoEvents();
6822 }
6823
6824 // Run the precision tests for all rotations.
6825 INSTANTIATE_TEST_SUITE_P(InputDispatcherDisplayOrientationTests,
6826 InputDispatcherDisplayOrientationFixture,
6827 ::testing::Values(ui::ROTATION_0, ui::ROTATION_90, ui::ROTATION_180,
6828 ui::ROTATION_270),
__anon345ef8bd0502(const testing::TestParamInfo<ui::Rotation>& testParamInfo) 6829 [](const testing::TestParamInfo<ui::Rotation>& testParamInfo) {
6830 return ftl::enum_string(testParamInfo.param);
6831 });
6832
6833 using TransferFunction = std::function<bool(const std::unique_ptr<InputDispatcher>& dispatcher,
6834 sp<IBinder>, sp<IBinder>)>;
6835
6836 class TransferTouchFixture : public InputDispatcherTest,
6837 public ::testing::WithParamInterface<TransferFunction> {};
6838
TEST_P(TransferTouchFixture,TransferTouch_OnePointer)6839 TEST_P(TransferTouchFixture, TransferTouch_OnePointer) {
6840 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
6841
6842 // Create a couple of windows
6843 sp<FakeWindowHandle> firstWindow =
6844 sp<FakeWindowHandle>::make(application, mDispatcher, "First Window",
6845 ui::LogicalDisplayId::DEFAULT);
6846 firstWindow->setDupTouchToWallpaper(true);
6847 sp<FakeWindowHandle> secondWindow =
6848 sp<FakeWindowHandle>::make(application, mDispatcher, "Second Window",
6849 ui::LogicalDisplayId::DEFAULT);
6850 sp<FakeWindowHandle> wallpaper =
6851 sp<FakeWindowHandle>::make(application, mDispatcher, "Wallpaper",
6852 ui::LogicalDisplayId::DEFAULT);
6853 wallpaper->setIsWallpaper(true);
6854 // Add the windows to the dispatcher, and ensure the first window is focused
6855 mDispatcher->onWindowInfosChanged(
6856 {{*firstWindow->getInfo(), *secondWindow->getInfo(), *wallpaper->getInfo()}, {}, 0, 0});
6857 setFocusedWindow(firstWindow);
6858 firstWindow->consumeFocusEvent(true);
6859
6860 // Send down to the first window
6861 mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_DOWN,
6862 AINPUT_SOURCE_TOUCHSCREEN,
6863 ui::LogicalDisplayId::DEFAULT));
6864
6865 // Only the first window should get the down event
6866 firstWindow->consumeMotionDown();
6867 secondWindow->assertNoEvents();
6868 wallpaper->consumeMotionDown(ui::LogicalDisplayId::DEFAULT, EXPECTED_WALLPAPER_FLAGS);
6869 // Dispatcher reports pointer down outside focus for the wallpaper
6870 mFakePolicy->assertOnPointerDownEquals(wallpaper->getToken());
6871
6872 // Transfer touch to the second window
6873 TransferFunction f = GetParam();
6874 const bool success = f(mDispatcher, firstWindow->getToken(), secondWindow->getToken());
6875 ASSERT_TRUE(success);
6876 // The first window gets cancel and the second gets down
6877 firstWindow->consumeMotionCancel();
6878 secondWindow->consumeMotionDown(ui::LogicalDisplayId::DEFAULT,
6879 AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
6880 wallpaper->consumeMotionCancel(ui::LogicalDisplayId::DEFAULT, EXPECTED_WALLPAPER_FLAGS);
6881 // There should not be any changes to the focused window when transferring touch
6882 ASSERT_NO_FATAL_FAILURE(mFakePolicy->assertOnPointerDownWasNotCalled());
6883
6884 // Send up event to the second window
6885 mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN,
6886 ui::LogicalDisplayId::DEFAULT));
6887 // The first window gets no events and the second gets up
6888 firstWindow->assertNoEvents();
6889 secondWindow->consumeMotionUp(ui::LogicalDisplayId::DEFAULT,
6890 AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
6891 wallpaper->assertNoEvents();
6892 }
6893
6894 /**
6895 * When 'transferTouchGesture' API is invoked, dispatcher needs to find the "best" window to take
6896 * touch from. When we have spy windows, there are several windows to choose from: either spy, or
6897 * the 'real' (non-spy) window. Always prefer the 'real' window because that's what would be most
6898 * natural to the user.
6899 * In this test, we are sending a pointer to both spy window and first window. We then try to
6900 * transfer touch to the second window. The dispatcher should identify the first window as the
6901 * one that should lose the gesture, and therefore the action should be to move the gesture from
6902 * the first window to the second.
6903 * The main goal here is to test the behaviour of 'transferTouchGesture' API, but it's still valid
6904 * to test the other API, as well.
6905 */
TEST_P(TransferTouchFixture,TransferTouch_MultipleWindowsWithSpy)6906 TEST_P(TransferTouchFixture, TransferTouch_MultipleWindowsWithSpy) {
6907 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
6908
6909 // Create a couple of windows + a spy window
6910 sp<FakeWindowHandle> spyWindow = sp<FakeWindowHandle>::make(application, mDispatcher, "Spy",
6911 ui::LogicalDisplayId::DEFAULT);
6912 spyWindow->setTrustedOverlay(true);
6913 spyWindow->setSpy(true);
6914 sp<FakeWindowHandle> firstWindow = sp<FakeWindowHandle>::make(application, mDispatcher, "First",
6915 ui::LogicalDisplayId::DEFAULT);
6916 sp<FakeWindowHandle> secondWindow =
6917 sp<FakeWindowHandle>::make(application, mDispatcher, "Second",
6918 ui::LogicalDisplayId::DEFAULT);
6919
6920 // Add the windows to the dispatcher
6921 mDispatcher->onWindowInfosChanged(
6922 {{*spyWindow->getInfo(), *firstWindow->getInfo(), *secondWindow->getInfo()}, {}, 0, 0});
6923
6924 // Send down to the first window
6925 mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_DOWN,
6926 AINPUT_SOURCE_TOUCHSCREEN,
6927 ui::LogicalDisplayId::DEFAULT));
6928 // Only the first window and spy should get the down event
6929 spyWindow->consumeMotionDown();
6930 firstWindow->consumeMotionDown();
6931
6932 // Transfer touch to the second window. Non-spy window should be preferred over the spy window
6933 // if f === 'transferTouchGesture'.
6934 TransferFunction f = GetParam();
6935 const bool success = f(mDispatcher, firstWindow->getToken(), secondWindow->getToken());
6936 ASSERT_TRUE(success);
6937 // The first window gets cancel and the second gets down
6938 firstWindow->consumeMotionCancel();
6939 secondWindow->consumeMotionDown(ui::LogicalDisplayId::DEFAULT,
6940 AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
6941
6942 // Send up event to the second window
6943 mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN,
6944 ui::LogicalDisplayId::DEFAULT));
6945 // The first window gets no events and the second+spy get up
6946 firstWindow->assertNoEvents();
6947 spyWindow->consumeMotionUp();
6948 secondWindow->consumeMotionUp(ui::LogicalDisplayId::DEFAULT,
6949 AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
6950 }
6951
TEST_P(TransferTouchFixture,TransferTouch_TwoPointersNonSplitTouch)6952 TEST_P(TransferTouchFixture, TransferTouch_TwoPointersNonSplitTouch) {
6953 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
6954
6955 PointF touchPoint = {10, 10};
6956
6957 // Create a couple of windows
6958 sp<FakeWindowHandle> firstWindow =
6959 sp<FakeWindowHandle>::make(application, mDispatcher, "First Window",
6960 ui::LogicalDisplayId::DEFAULT);
6961 firstWindow->setPreventSplitting(true);
6962 sp<FakeWindowHandle> secondWindow =
6963 sp<FakeWindowHandle>::make(application, mDispatcher, "Second Window",
6964 ui::LogicalDisplayId::DEFAULT);
6965 secondWindow->setPreventSplitting(true);
6966
6967 // Add the windows to the dispatcher
6968 mDispatcher->onWindowInfosChanged(
6969 {{*firstWindow->getInfo(), *secondWindow->getInfo()}, {}, 0, 0});
6970
6971 // Send down to the first window
6972 mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_DOWN,
6973 AINPUT_SOURCE_TOUCHSCREEN,
6974 ui::LogicalDisplayId::DEFAULT, {touchPoint}));
6975 // Only the first window should get the down event
6976 firstWindow->consumeMotionDown();
6977 secondWindow->assertNoEvents();
6978
6979 // Send pointer down to the first window
6980 mDispatcher->notifyMotion(generateMotionArgs(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN,
6981 ui::LogicalDisplayId::DEFAULT,
6982 {touchPoint, touchPoint}));
6983 // Only the first window should get the pointer down event
6984 firstWindow->consumeMotionPointerDown(1);
6985 secondWindow->assertNoEvents();
6986
6987 // Transfer touch focus to the second window
6988 TransferFunction f = GetParam();
6989 bool success = f(mDispatcher, firstWindow->getToken(), secondWindow->getToken());
6990 ASSERT_TRUE(success);
6991 // The first window gets cancel and the second gets down and pointer down
6992 firstWindow->consumeMotionCancel();
6993 secondWindow->consumeMotionDown(ui::LogicalDisplayId::DEFAULT,
6994 AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
6995 secondWindow->consumeMotionPointerDown(1, ui::LogicalDisplayId::DEFAULT,
6996 AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
6997
6998 // Send pointer up to the second window
6999 mDispatcher->notifyMotion(generateMotionArgs(POINTER_1_UP, AINPUT_SOURCE_TOUCHSCREEN,
7000 ui::LogicalDisplayId::DEFAULT,
7001 {touchPoint, touchPoint}));
7002 // The first window gets nothing and the second gets pointer up
7003 firstWindow->assertNoEvents();
7004 secondWindow->consumeMotionPointerUp(/*pointerIdx=*/1,
7005 AllOf(WithDisplayId(ui::LogicalDisplayId::DEFAULT),
7006 WithFlags(AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE),
7007 WithPointerCount(2)));
7008
7009 // Send up event to the second window
7010 mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN,
7011 ui::LogicalDisplayId::DEFAULT));
7012 // The first window gets nothing and the second gets up
7013 firstWindow->assertNoEvents();
7014 secondWindow->consumeMotionUp(ui::LogicalDisplayId::DEFAULT,
7015 AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
7016 }
7017
TEST_P(TransferTouchFixture,TransferTouch_MultipleWallpapers)7018 TEST_P(TransferTouchFixture, TransferTouch_MultipleWallpapers) {
7019 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
7020
7021 // Create a couple of windows
7022 sp<FakeWindowHandle> firstWindow =
7023 sp<FakeWindowHandle>::make(application, mDispatcher, "First Window",
7024 ui::LogicalDisplayId::DEFAULT);
7025 firstWindow->setDupTouchToWallpaper(true);
7026 sp<FakeWindowHandle> secondWindow =
7027 sp<FakeWindowHandle>::make(application, mDispatcher, "Second Window",
7028 ui::LogicalDisplayId::DEFAULT);
7029 secondWindow->setDupTouchToWallpaper(true);
7030
7031 sp<FakeWindowHandle> wallpaper1 =
7032 sp<FakeWindowHandle>::make(application, mDispatcher, "Wallpaper1",
7033 ui::LogicalDisplayId::DEFAULT);
7034 wallpaper1->setIsWallpaper(true);
7035
7036 sp<FakeWindowHandle> wallpaper2 =
7037 sp<FakeWindowHandle>::make(application, mDispatcher, "Wallpaper2",
7038 ui::LogicalDisplayId::DEFAULT);
7039 wallpaper2->setIsWallpaper(true);
7040 // Add the windows to the dispatcher
7041 mDispatcher->onWindowInfosChanged({{*firstWindow->getInfo(), *wallpaper1->getInfo(),
7042 *secondWindow->getInfo(), *wallpaper2->getInfo()},
7043 {},
7044 0,
7045 0});
7046
7047 // Send down to the first window
7048 mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_DOWN,
7049 AINPUT_SOURCE_TOUCHSCREEN,
7050 ui::LogicalDisplayId::DEFAULT));
7051
7052 // Only the first window should get the down event
7053 firstWindow->consumeMotionDown();
7054 secondWindow->assertNoEvents();
7055 wallpaper1->consumeMotionDown(ui::LogicalDisplayId::DEFAULT, EXPECTED_WALLPAPER_FLAGS);
7056 wallpaper2->assertNoEvents();
7057
7058 // Transfer touch focus to the second window
7059 TransferFunction f = GetParam();
7060 bool success = f(mDispatcher, firstWindow->getToken(), secondWindow->getToken());
7061 ASSERT_TRUE(success);
7062
7063 // The first window gets cancel and the second gets down
7064 firstWindow->consumeMotionCancel();
7065 secondWindow->consumeMotionDown(ui::LogicalDisplayId::DEFAULT,
7066 AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
7067 wallpaper1->consumeMotionCancel(ui::LogicalDisplayId::DEFAULT, EXPECTED_WALLPAPER_FLAGS);
7068 wallpaper2->consumeMotionDown(ui::LogicalDisplayId::DEFAULT,
7069 EXPECTED_WALLPAPER_FLAGS | AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
7070
7071 // Send up event to the second window
7072 mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN,
7073 ui::LogicalDisplayId::DEFAULT));
7074 // The first window gets no events and the second gets up
7075 firstWindow->assertNoEvents();
7076 secondWindow->consumeMotionUp(ui::LogicalDisplayId::DEFAULT,
7077 AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
7078 wallpaper1->assertNoEvents();
7079 wallpaper2->consumeMotionUp(ui::LogicalDisplayId::DEFAULT,
7080 EXPECTED_WALLPAPER_FLAGS | AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
7081 }
7082
7083 // For the cases of single pointer touch and two pointers non-split touch, the api's
7084 // 'transferTouchGesture' and 'transferTouchOnDisplay' are equivalent in behaviour. They only differ
7085 // for the case where there are multiple pointers split across several windows.
7086 INSTANTIATE_TEST_SUITE_P(
7087 InputDispatcherTransferFunctionTests, TransferTouchFixture,
7088 ::testing::Values(
7089 [&](const std::unique_ptr<InputDispatcher>& dispatcher, sp<IBinder> /*ignored*/,
__anon345ef8bd0602(const std::unique_ptr<InputDispatcher>& dispatcher, sp<IBinder> , sp<IBinder> destChannelToken) 7090 sp<IBinder> destChannelToken) {
7091 return dispatcher->transferTouchOnDisplay(destChannelToken,
7092 ui::LogicalDisplayId::DEFAULT);
7093 },
7094 [&](const std::unique_ptr<InputDispatcher>& dispatcher, sp<IBinder> from,
__anon345ef8bd0702(const std::unique_ptr<InputDispatcher>& dispatcher, sp<IBinder> from, sp<IBinder> to) 7095 sp<IBinder> to) {
7096 return dispatcher->transferTouchGesture(from, to,
7097 /*isDragAndDrop=*/false);
7098 }));
7099
TEST_F(InputDispatcherTest,TransferTouch_TwoPointersSplitTouch)7100 TEST_F(InputDispatcherTest, TransferTouch_TwoPointersSplitTouch) {
7101 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
7102
7103 sp<FakeWindowHandle> firstWindow =
7104 sp<FakeWindowHandle>::make(application, mDispatcher, "First Window",
7105 ui::LogicalDisplayId::DEFAULT);
7106 firstWindow->setFrame(Rect(0, 0, 600, 400));
7107
7108 sp<FakeWindowHandle> secondWindow =
7109 sp<FakeWindowHandle>::make(application, mDispatcher, "Second Window",
7110 ui::LogicalDisplayId::DEFAULT);
7111 secondWindow->setFrame(Rect(0, 400, 600, 800));
7112
7113 // Add the windows to the dispatcher
7114 mDispatcher->onWindowInfosChanged(
7115 {{*firstWindow->getInfo(), *secondWindow->getInfo()}, {}, 0, 0});
7116
7117 PointF pointInFirst = {300, 200};
7118 PointF pointInSecond = {300, 600};
7119
7120 // Send down to the first window
7121 mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_DOWN,
7122 AINPUT_SOURCE_TOUCHSCREEN,
7123 ui::LogicalDisplayId::DEFAULT, {pointInFirst}));
7124 // Only the first window should get the down event
7125 firstWindow->consumeMotionDown();
7126 secondWindow->assertNoEvents();
7127
7128 // Send down to the second window
7129 mDispatcher->notifyMotion(generateMotionArgs(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN,
7130 ui::LogicalDisplayId::DEFAULT,
7131 {pointInFirst, pointInSecond}));
7132 // The first window gets a move and the second a down
7133 firstWindow->consumeMotionMove();
7134 secondWindow->consumeMotionDown();
7135
7136 // Transfer touch to the second window
7137 mDispatcher->transferTouchGesture(firstWindow->getToken(), secondWindow->getToken());
7138 // The first window gets cancel and the new gets pointer down (it already saw down)
7139 firstWindow->consumeMotionCancel();
7140 secondWindow->consumeMotionPointerDown(1, ui::LogicalDisplayId::DEFAULT,
7141 AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
7142
7143 // Send pointer up to the second window
7144 mDispatcher->notifyMotion(generateMotionArgs(POINTER_1_UP, AINPUT_SOURCE_TOUCHSCREEN,
7145 ui::LogicalDisplayId::DEFAULT,
7146 {pointInFirst, pointInSecond}));
7147 // The first window gets nothing and the second gets pointer up
7148 firstWindow->assertNoEvents();
7149 secondWindow->consumeMotionPointerUp(/*pointerIdx=*/1,
7150 AllOf(WithDisplayId(ui::LogicalDisplayId::DEFAULT),
7151 WithFlags(AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE),
7152 WithPointerCount(2)));
7153
7154 // Send up event to the second window
7155 mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN,
7156 ui::LogicalDisplayId::DEFAULT));
7157 // The first window gets nothing and the second gets up
7158 firstWindow->assertNoEvents();
7159 secondWindow->consumeMotionUp(ui::LogicalDisplayId::DEFAULT,
7160 AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
7161 }
7162
7163 // Same as TransferTouch_TwoPointersSplitTouch, but using 'transferTouchOnDisplay' api.
7164 // Unlike 'transferTouchGesture', calling 'transferTouchOnDisplay' when there are two windows
7165 // receiving touch is not supported, so the touch should continue on those windows and the
7166 // transferred-to window should get nothing.
TEST_F(InputDispatcherTest,TransferTouchOnDisplay_TwoPointersSplitTouch)7167 TEST_F(InputDispatcherTest, TransferTouchOnDisplay_TwoPointersSplitTouch) {
7168 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
7169
7170 sp<FakeWindowHandle> firstWindow =
7171 sp<FakeWindowHandle>::make(application, mDispatcher, "First Window",
7172 ui::LogicalDisplayId::DEFAULT);
7173 firstWindow->setFrame(Rect(0, 0, 600, 400));
7174
7175 sp<FakeWindowHandle> secondWindow =
7176 sp<FakeWindowHandle>::make(application, mDispatcher, "Second Window",
7177 ui::LogicalDisplayId::DEFAULT);
7178 secondWindow->setFrame(Rect(0, 400, 600, 800));
7179
7180 // Add the windows to the dispatcher
7181 mDispatcher->onWindowInfosChanged(
7182 {{*firstWindow->getInfo(), *secondWindow->getInfo()}, {}, 0, 0});
7183
7184 PointF pointInFirst = {300, 200};
7185 PointF pointInSecond = {300, 600};
7186
7187 // Send down to the first window
7188 mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_DOWN,
7189 AINPUT_SOURCE_TOUCHSCREEN,
7190 ui::LogicalDisplayId::DEFAULT, {pointInFirst}));
7191 // Only the first window should get the down event
7192 firstWindow->consumeMotionDown();
7193 secondWindow->assertNoEvents();
7194
7195 // Send down to the second window
7196 mDispatcher->notifyMotion(generateMotionArgs(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN,
7197 ui::LogicalDisplayId::DEFAULT,
7198 {pointInFirst, pointInSecond}));
7199 // The first window gets a move and the second a down
7200 firstWindow->consumeMotionMove();
7201 secondWindow->consumeMotionDown();
7202
7203 // Transfer touch focus to the second window
7204 const bool transferred = mDispatcher->transferTouchOnDisplay(secondWindow->getToken(),
7205 ui::LogicalDisplayId::DEFAULT);
7206 // The 'transferTouchOnDisplay' call should not succeed, because there are 2 touched windows
7207 ASSERT_FALSE(transferred);
7208 firstWindow->assertNoEvents();
7209 secondWindow->assertNoEvents();
7210
7211 // The rest of the dispatch should proceed as normal
7212 // Send pointer up to the second window
7213 mDispatcher->notifyMotion(generateMotionArgs(POINTER_1_UP, AINPUT_SOURCE_TOUCHSCREEN,
7214 ui::LogicalDisplayId::DEFAULT,
7215 {pointInFirst, pointInSecond}));
7216 // The first window gets MOVE and the second gets pointer up
7217 firstWindow->consumeMotionMove();
7218 secondWindow->consumeMotionUp();
7219
7220 // Send up event to the first window
7221 mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN,
7222 ui::LogicalDisplayId::DEFAULT));
7223 // The first window gets nothing and the second gets up
7224 firstWindow->consumeMotionUp();
7225 secondWindow->assertNoEvents();
7226 }
7227
7228 // This case will create two windows and one mirrored window on the default display and mirror
7229 // two windows on the second display. It will test if 'transferTouchGesture' works fine if we put
7230 // the windows info of second display before default display.
TEST_F(InputDispatcherTest,TransferTouch_CloneSurface)7231 TEST_F(InputDispatcherTest, TransferTouch_CloneSurface) {
7232 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
7233 sp<FakeWindowHandle> firstWindowInPrimary =
7234 sp<FakeWindowHandle>::make(application, mDispatcher, "D_1_W1",
7235 ui::LogicalDisplayId::DEFAULT);
7236 firstWindowInPrimary->setFrame(Rect(0, 0, 100, 100));
7237 sp<FakeWindowHandle> secondWindowInPrimary =
7238 sp<FakeWindowHandle>::make(application, mDispatcher, "D_1_W2",
7239 ui::LogicalDisplayId::DEFAULT);
7240 secondWindowInPrimary->setFrame(Rect(100, 0, 200, 100));
7241
7242 sp<FakeWindowHandle> mirrorWindowInPrimary =
7243 firstWindowInPrimary->clone(ui::LogicalDisplayId::DEFAULT);
7244 mirrorWindowInPrimary->setFrame(Rect(0, 100, 100, 200));
7245
7246 sp<FakeWindowHandle> firstWindowInSecondary = firstWindowInPrimary->clone(SECOND_DISPLAY_ID);
7247 firstWindowInSecondary->setFrame(Rect(0, 0, 100, 100));
7248
7249 sp<FakeWindowHandle> secondWindowInSecondary = secondWindowInPrimary->clone(SECOND_DISPLAY_ID);
7250 secondWindowInPrimary->setFrame(Rect(100, 0, 200, 100));
7251
7252 // Update window info, let it find window handle of second display first.
7253 mDispatcher->onWindowInfosChanged(
7254 {{*firstWindowInSecondary->getInfo(), *secondWindowInSecondary->getInfo(),
7255 *mirrorWindowInPrimary->getInfo(), *firstWindowInPrimary->getInfo(),
7256 *secondWindowInPrimary->getInfo()},
7257 {},
7258 0,
7259 0});
7260
7261 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
7262 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN,
7263 ui::LogicalDisplayId::DEFAULT, {50, 50}))
7264 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
7265
7266 // Window should receive motion event.
7267 firstWindowInPrimary->consumeMotionDown(ui::LogicalDisplayId::DEFAULT);
7268
7269 // Transfer touch
7270 ASSERT_TRUE(mDispatcher->transferTouchGesture(firstWindowInPrimary->getToken(),
7271 secondWindowInPrimary->getToken()));
7272 // The first window gets cancel.
7273 firstWindowInPrimary->consumeMotionCancel();
7274 secondWindowInPrimary->consumeMotionDown(ui::LogicalDisplayId::DEFAULT,
7275 AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
7276
7277 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
7278 injectMotionEvent(*mDispatcher, AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN,
7279 ui::LogicalDisplayId::DEFAULT, {150, 50}))
7280 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
7281 firstWindowInPrimary->assertNoEvents();
7282 secondWindowInPrimary->consumeMotionMove(ui::LogicalDisplayId::DEFAULT,
7283 AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
7284
7285 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
7286 injectMotionUp(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ui::LogicalDisplayId::DEFAULT,
7287 {150, 50}))
7288 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
7289 firstWindowInPrimary->assertNoEvents();
7290 secondWindowInPrimary->consumeMotionUp(ui::LogicalDisplayId::DEFAULT,
7291 AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
7292 }
7293
7294 // Same as TransferTouch_CloneSurface, but this touch on the secondary display and use
7295 // 'transferTouchOnDisplay' api.
TEST_F(InputDispatcherTest,TransferTouchOnDisplay_CloneSurface)7296 TEST_F(InputDispatcherTest, TransferTouchOnDisplay_CloneSurface) {
7297 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
7298 sp<FakeWindowHandle> firstWindowInPrimary =
7299 sp<FakeWindowHandle>::make(application, mDispatcher, "D_1_W1",
7300 ui::LogicalDisplayId::DEFAULT);
7301 firstWindowInPrimary->setFrame(Rect(0, 0, 100, 100));
7302 sp<FakeWindowHandle> secondWindowInPrimary =
7303 sp<FakeWindowHandle>::make(application, mDispatcher, "D_1_W2",
7304 ui::LogicalDisplayId::DEFAULT);
7305 secondWindowInPrimary->setFrame(Rect(100, 0, 200, 100));
7306
7307 sp<FakeWindowHandle> mirrorWindowInPrimary =
7308 firstWindowInPrimary->clone(ui::LogicalDisplayId::DEFAULT);
7309 mirrorWindowInPrimary->setFrame(Rect(0, 100, 100, 200));
7310
7311 sp<FakeWindowHandle> firstWindowInSecondary = firstWindowInPrimary->clone(SECOND_DISPLAY_ID);
7312 firstWindowInSecondary->setFrame(Rect(0, 0, 100, 100));
7313
7314 sp<FakeWindowHandle> secondWindowInSecondary = secondWindowInPrimary->clone(SECOND_DISPLAY_ID);
7315 secondWindowInPrimary->setFrame(Rect(100, 0, 200, 100));
7316
7317 // Update window info, let it find window handle of second display first.
7318 mDispatcher->onWindowInfosChanged(
7319 {{*firstWindowInSecondary->getInfo(), *secondWindowInSecondary->getInfo(),
7320 *mirrorWindowInPrimary->getInfo(), *firstWindowInPrimary->getInfo(),
7321 *secondWindowInPrimary->getInfo()},
7322 {},
7323 0,
7324 0});
7325
7326 // Touch on second display.
7327 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
7328 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, SECOND_DISPLAY_ID,
7329 {50, 50}))
7330 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
7331
7332 // Window should receive motion event.
7333 firstWindowInSecondary->consumeMotionDown(SECOND_DISPLAY_ID);
7334
7335 // Transfer touch focus
7336 ASSERT_TRUE(mDispatcher->transferTouchOnDisplay(secondWindowInSecondary->getToken(),
7337 SECOND_DISPLAY_ID));
7338
7339 // The first window gets cancel.
7340 firstWindowInSecondary->consumeMotionCancel(SECOND_DISPLAY_ID);
7341 secondWindowInSecondary->consumeMotionDown(SECOND_DISPLAY_ID,
7342 AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
7343
7344 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
7345 injectMotionEvent(*mDispatcher, AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN,
7346 SECOND_DISPLAY_ID, {150, 50}))
7347 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
7348 firstWindowInSecondary->assertNoEvents();
7349 secondWindowInSecondary->consumeMotionMove(SECOND_DISPLAY_ID,
7350 AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
7351
7352 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
7353 injectMotionUp(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, SECOND_DISPLAY_ID, {150, 50}))
7354 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
7355 firstWindowInSecondary->assertNoEvents();
7356 secondWindowInSecondary->consumeMotionUp(SECOND_DISPLAY_ID, AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
7357 }
7358
TEST_F(InputDispatcherTest,FocusedWindow_ReceivesFocusEventAndKeyEvent)7359 TEST_F(InputDispatcherTest, FocusedWindow_ReceivesFocusEventAndKeyEvent) {
7360 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
7361 sp<FakeWindowHandle> window =
7362 sp<FakeWindowHandle>::make(application, mDispatcher, "Fake Window",
7363 ui::LogicalDisplayId::DEFAULT);
7364
7365 window->setFocusable(true);
7366 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
7367 setFocusedWindow(window);
7368
7369 window->consumeFocusEvent(true);
7370
7371 mDispatcher->notifyKey(generateKeyArgs(AKEY_EVENT_ACTION_DOWN, ui::LogicalDisplayId::DEFAULT));
7372
7373 // Window should receive key down event.
7374 window->consumeKeyDown(ui::LogicalDisplayId::DEFAULT);
7375
7376 // Should have poked user activity
7377 mDispatcher->waitForIdle();
7378 mFakePolicy->assertUserActivityPoked();
7379 }
7380
TEST_F(InputDispatcherTest,FocusedWindow_DisableUserActivity)7381 TEST_F(InputDispatcherTest, FocusedWindow_DisableUserActivity) {
7382 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
7383 sp<FakeWindowHandle> window =
7384 sp<FakeWindowHandle>::make(application, mDispatcher, "Fake Window",
7385 ui::LogicalDisplayId::DEFAULT);
7386
7387 window->setDisableUserActivity(true);
7388 window->setFocusable(true);
7389 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
7390 setFocusedWindow(window);
7391
7392 window->consumeFocusEvent(true);
7393
7394 mDispatcher->notifyKey(
7395 KeyArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_KEYBOARD).keyCode(AKEYCODE_A).build());
7396
7397 // Window should receive key down event.
7398 window->consumeKeyDown(ui::LogicalDisplayId::DEFAULT);
7399
7400 // Should have not poked user activity
7401 mDispatcher->waitForIdle();
7402 mFakePolicy->assertUserActivityNotPoked();
7403 }
7404
TEST_F(InputDispatcherTest,FocusedWindow_DoesNotReceivePolicyConsumedKey)7405 TEST_F(InputDispatcherTest, FocusedWindow_DoesNotReceivePolicyConsumedKey) {
7406 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
7407 sp<FakeWindowHandle> window =
7408 sp<FakeWindowHandle>::make(application, mDispatcher, "Fake Window",
7409 ui::LogicalDisplayId::DEFAULT);
7410
7411 window->setFocusable(true);
7412 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
7413 setFocusedWindow(window);
7414
7415 window->consumeFocusEvent(true);
7416
7417 mFakePolicy->setConsumeKeyBeforeDispatching(true);
7418
7419 mDispatcher->notifyKey(
7420 KeyArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_KEYBOARD).keyCode(AKEYCODE_A).build());
7421 mDispatcher->waitForIdle();
7422
7423 // Key is not passed down
7424 window->assertNoEvents();
7425
7426 // Should have poked user activity
7427 mFakePolicy->assertUserActivityPoked();
7428 }
7429
TEST_F(InputDispatcherTest,FocusedWindow_PolicyConsumedKeyIgnoresDisableUserActivity)7430 TEST_F(InputDispatcherTest, FocusedWindow_PolicyConsumedKeyIgnoresDisableUserActivity) {
7431 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
7432 sp<FakeWindowHandle> window =
7433 sp<FakeWindowHandle>::make(application, mDispatcher, "Fake Window",
7434 ui::LogicalDisplayId::DEFAULT);
7435
7436 window->setDisableUserActivity(true);
7437 window->setFocusable(true);
7438 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
7439 setFocusedWindow(window);
7440
7441 window->consumeFocusEvent(true);
7442
7443 mFakePolicy->setConsumeKeyBeforeDispatching(true);
7444
7445 mDispatcher->notifyKey(
7446 KeyArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_KEYBOARD).keyCode(AKEYCODE_A).build());
7447 mDispatcher->waitForIdle();
7448
7449 // System key is not passed down
7450 window->assertNoEvents();
7451
7452 // Should have poked user activity
7453 mFakePolicy->assertUserActivityPoked();
7454 }
7455
7456 class DisableUserActivityInputDispatcherTest : public InputDispatcherTest,
7457 public ::testing::WithParamInterface<bool> {};
7458
TEST_P(DisableUserActivityInputDispatcherTest,NotPassedToUserUserActivity)7459 TEST_P(DisableUserActivityInputDispatcherTest, NotPassedToUserUserActivity) {
7460 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
7461 sp<FakeWindowHandle> window =
7462 sp<FakeWindowHandle>::make(application, mDispatcher, "Fake Window",
7463 ui::LogicalDisplayId::DEFAULT);
7464
7465 window->setDisableUserActivity(GetParam());
7466
7467 window->setFocusable(true);
7468 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
7469 setFocusedWindow(window);
7470
7471 window->consumeFocusEvent(true);
7472
7473 mDispatcher->notifyKey(KeyArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_KEYBOARD)
7474 .keyCode(AKEYCODE_A)
7475 .policyFlags(0)
7476 .build());
7477 mDispatcher->waitForIdle();
7478
7479 // Key is not passed down
7480 window->assertNoEvents();
7481
7482 // Should not have poked user activity
7483 mFakePolicy->assertUserActivityNotPoked();
7484 }
7485
7486 INSTANTIATE_TEST_CASE_P(DisableUserActivity, DisableUserActivityInputDispatcherTest,
7487 ::testing::Bool());
7488
TEST_F(InputDispatcherTest,InjectedTouchesPokeUserActivity)7489 TEST_F(InputDispatcherTest, InjectedTouchesPokeUserActivity) {
7490 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
7491 sp<FakeWindowHandle> window =
7492 sp<FakeWindowHandle>::make(application, mDispatcher, "Fake Window",
7493 ui::LogicalDisplayId::DEFAULT);
7494
7495 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
7496
7497 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
7498 injectMotionEvent(*mDispatcher, AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN,
7499 ui::LogicalDisplayId::DEFAULT, {100, 100}))
7500 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
7501
7502 window->consumeMotionEvent(
7503 AllOf(WithMotionAction(ACTION_DOWN), WithDisplayId(ui::LogicalDisplayId::DEFAULT)));
7504
7505 // Should have poked user activity
7506 mDispatcher->waitForIdle();
7507 mFakePolicy->assertUserActivityPoked();
7508 }
7509
TEST_F(InputDispatcherTest,UnfocusedWindow_DoesNotReceiveFocusEventOrKeyEvent)7510 TEST_F(InputDispatcherTest, UnfocusedWindow_DoesNotReceiveFocusEventOrKeyEvent) {
7511 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
7512 sp<FakeWindowHandle> window =
7513 sp<FakeWindowHandle>::make(application, mDispatcher, "Fake Window",
7514 ui::LogicalDisplayId::DEFAULT);
7515
7516 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
7517
7518 mDispatcher->notifyKey(generateKeyArgs(AKEY_EVENT_ACTION_DOWN, ui::LogicalDisplayId::DEFAULT));
7519 mDispatcher->waitForIdle();
7520
7521 window->assertNoEvents();
7522 }
7523
7524 // If a window is touchable, but does not have focus, it should receive motion events, but not keys
TEST_F(InputDispatcherTest,UnfocusedWindow_ReceivesMotionsButNotKeys)7525 TEST_F(InputDispatcherTest, UnfocusedWindow_ReceivesMotionsButNotKeys) {
7526 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
7527 sp<FakeWindowHandle> window =
7528 sp<FakeWindowHandle>::make(application, mDispatcher, "Fake Window",
7529 ui::LogicalDisplayId::DEFAULT);
7530
7531 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
7532
7533 // Send key
7534 mDispatcher->notifyKey(generateKeyArgs(AKEY_EVENT_ACTION_DOWN, ui::LogicalDisplayId::DEFAULT));
7535 // Send motion
7536 mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_DOWN,
7537 AINPUT_SOURCE_TOUCHSCREEN,
7538 ui::LogicalDisplayId::DEFAULT));
7539
7540 // Window should receive only the motion event
7541 window->consumeMotionDown(ui::LogicalDisplayId::DEFAULT);
7542 window->assertNoEvents(); // Key event or focus event will not be received
7543 }
7544
TEST_F(InputDispatcherTest,PointerCancel_SendCancelWhenSplitTouch)7545 TEST_F(InputDispatcherTest, PointerCancel_SendCancelWhenSplitTouch) {
7546 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
7547
7548 sp<FakeWindowHandle> firstWindow =
7549 sp<FakeWindowHandle>::make(application, mDispatcher, "First Window",
7550 ui::LogicalDisplayId::DEFAULT);
7551 firstWindow->setFrame(Rect(0, 0, 600, 400));
7552
7553 sp<FakeWindowHandle> secondWindow =
7554 sp<FakeWindowHandle>::make(application, mDispatcher, "Second Window",
7555 ui::LogicalDisplayId::DEFAULT);
7556 secondWindow->setFrame(Rect(0, 400, 600, 800));
7557
7558 // Add the windows to the dispatcher
7559 mDispatcher->onWindowInfosChanged(
7560 {{*firstWindow->getInfo(), *secondWindow->getInfo()}, {}, 0, 0});
7561
7562 PointF pointInFirst = {300, 200};
7563 PointF pointInSecond = {300, 600};
7564
7565 // Send down to the first window
7566 mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_DOWN,
7567 AINPUT_SOURCE_TOUCHSCREEN,
7568 ui::LogicalDisplayId::DEFAULT, {pointInFirst}));
7569 // Only the first window should get the down event
7570 firstWindow->consumeMotionDown();
7571 secondWindow->assertNoEvents();
7572
7573 // Send down to the second window
7574 mDispatcher->notifyMotion(generateMotionArgs(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN,
7575 ui::LogicalDisplayId::DEFAULT,
7576 {pointInFirst, pointInSecond}));
7577 // The first window gets a move and the second a down
7578 firstWindow->consumeMotionMove();
7579 secondWindow->consumeMotionDown();
7580
7581 // Send pointer cancel to the second window
7582 NotifyMotionArgs pointerUpMotionArgs =
7583 generateMotionArgs(POINTER_1_UP, AINPUT_SOURCE_TOUCHSCREEN,
7584 ui::LogicalDisplayId::DEFAULT, {pointInFirst, pointInSecond});
7585 pointerUpMotionArgs.flags |= AMOTION_EVENT_FLAG_CANCELED;
7586 mDispatcher->notifyMotion(pointerUpMotionArgs);
7587 // The first window gets move and the second gets cancel.
7588 firstWindow->consumeMotionMove(ui::LogicalDisplayId::DEFAULT, AMOTION_EVENT_FLAG_CANCELED);
7589 secondWindow->consumeMotionCancel(ui::LogicalDisplayId::DEFAULT, AMOTION_EVENT_FLAG_CANCELED);
7590
7591 // Send up event.
7592 mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN,
7593 ui::LogicalDisplayId::DEFAULT));
7594 // The first window gets up and the second gets nothing.
7595 firstWindow->consumeMotionUp();
7596 secondWindow->assertNoEvents();
7597 }
7598
TEST_F(InputDispatcherTest,SendTimeline_DoesNotCrashDispatcher)7599 TEST_F(InputDispatcherTest, SendTimeline_DoesNotCrashDispatcher) {
7600 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
7601
7602 sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher, "Window",
7603 ui::LogicalDisplayId::DEFAULT);
7604 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
7605 std::array<nsecs_t, GraphicsTimeline::SIZE> graphicsTimeline;
7606 graphicsTimeline[GraphicsTimeline::GPU_COMPLETED_TIME] = 2;
7607 graphicsTimeline[GraphicsTimeline::PRESENT_TIME] = 3;
7608
7609 window->sendTimeline(/*inputEventId=*/1, graphicsTimeline);
7610 window->assertNoEvents();
7611 mDispatcher->waitForIdle();
7612 }
7613
7614 using InputDispatcherMonitorTest = InputDispatcherTest;
7615
7616 /**
7617 * Two entities that receive touch: A window, and a global monitor.
7618 * The touch goes to the window, and then the window disappears.
7619 * The monitor does not get cancel right away. But if more events come in, the touch gets canceled
7620 * for the monitor, as well.
7621 * 1. foregroundWindow
7622 * 2. monitor <-- global monitor (doesn't observe z order, receives all events)
7623 */
TEST_F(InputDispatcherMonitorTest,MonitorTouchIsCanceledWhenForegroundWindowDisappears)7624 TEST_F(InputDispatcherMonitorTest, MonitorTouchIsCanceledWhenForegroundWindowDisappears) {
7625 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
7626 sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher, "Foreground",
7627 ui::LogicalDisplayId::DEFAULT);
7628
7629 FakeMonitorReceiver monitor =
7630 FakeMonitorReceiver(*mDispatcher, "M_1", ui::LogicalDisplayId::DEFAULT);
7631
7632 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
7633 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
7634 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN,
7635 ui::LogicalDisplayId::DEFAULT, {100, 200}))
7636 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
7637
7638 // Both the foreground window and the global monitor should receive the touch down
7639 window->consumeMotionDown();
7640 monitor.consumeMotionDown(ui::LogicalDisplayId::DEFAULT);
7641
7642 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
7643 injectMotionEvent(*mDispatcher, AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN,
7644 ui::LogicalDisplayId::DEFAULT, {110, 200}))
7645 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
7646
7647 window->consumeMotionMove();
7648 monitor.consumeMotionMove(ui::LogicalDisplayId::DEFAULT);
7649
7650 // Now the foreground window goes away
7651 mDispatcher->onWindowInfosChanged({{}, {}, 0, 0});
7652 window->consumeMotionCancel();
7653 monitor.assertNoEvents(); // Global monitor does not get a cancel yet
7654
7655 // If more events come in, there will be no more foreground window to send them to. This will
7656 // cause a cancel for the monitor, as well.
7657 ASSERT_EQ(InputEventInjectionResult::FAILED,
7658 injectMotionEvent(*mDispatcher, AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN,
7659 ui::LogicalDisplayId::DEFAULT, {120, 200}))
7660 << "Injection should fail because the window was removed";
7661 window->assertNoEvents();
7662 // Global monitor now gets the cancel
7663 monitor.consumeMotionCancel(ui::LogicalDisplayId::DEFAULT);
7664 }
7665
TEST_F(InputDispatcherMonitorTest,ReceivesMotionEvents)7666 TEST_F(InputDispatcherMonitorTest, ReceivesMotionEvents) {
7667 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
7668 sp<FakeWindowHandle> window =
7669 sp<FakeWindowHandle>::make(application, mDispatcher, "Fake Window",
7670 ui::LogicalDisplayId::DEFAULT);
7671 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
7672
7673 FakeMonitorReceiver monitor =
7674 FakeMonitorReceiver(*mDispatcher, "M_1", ui::LogicalDisplayId::DEFAULT);
7675
7676 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
7677 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN,
7678 ui::LogicalDisplayId::DEFAULT))
7679 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
7680 window->consumeMotionDown(ui::LogicalDisplayId::DEFAULT);
7681 monitor.consumeMotionDown(ui::LogicalDisplayId::DEFAULT);
7682 }
7683
TEST_F(InputDispatcherMonitorTest,MonitorCannotPilferPointers)7684 TEST_F(InputDispatcherMonitorTest, MonitorCannotPilferPointers) {
7685 FakeMonitorReceiver monitor =
7686 FakeMonitorReceiver(*mDispatcher, "M_1", ui::LogicalDisplayId::DEFAULT);
7687
7688 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
7689 sp<FakeWindowHandle> window =
7690 sp<FakeWindowHandle>::make(application, mDispatcher, "Fake Window",
7691 ui::LogicalDisplayId::DEFAULT);
7692 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
7693
7694 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
7695 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN,
7696 ui::LogicalDisplayId::DEFAULT))
7697 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
7698 monitor.consumeMotionDown(ui::LogicalDisplayId::DEFAULT);
7699 window->consumeMotionDown(ui::LogicalDisplayId::DEFAULT);
7700
7701 // Pilfer pointers from the monitor.
7702 // This should not do anything and the window should continue to receive events.
7703 EXPECT_NE(OK, mDispatcher->pilferPointers(monitor.getToken()));
7704
7705 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
7706 injectMotionEvent(*mDispatcher, AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN,
7707 ui::LogicalDisplayId::DEFAULT))
7708 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
7709
7710 monitor.consumeMotionMove(ui::LogicalDisplayId::DEFAULT);
7711 window->consumeMotionMove(ui::LogicalDisplayId::DEFAULT);
7712 }
7713
TEST_F(InputDispatcherMonitorTest,NoWindowTransform)7714 TEST_F(InputDispatcherMonitorTest, NoWindowTransform) {
7715 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
7716 sp<FakeWindowHandle> window =
7717 sp<FakeWindowHandle>::make(application, mDispatcher, "Fake Window",
7718 ui::LogicalDisplayId::DEFAULT);
7719 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
7720 window->setWindowOffset(20, 40);
7721 window->setWindowTransform(0, 1, -1, 0);
7722
7723 FakeMonitorReceiver monitor =
7724 FakeMonitorReceiver(*mDispatcher, "M_1", ui::LogicalDisplayId::DEFAULT);
7725
7726 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
7727 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN,
7728 ui::LogicalDisplayId::DEFAULT))
7729 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
7730 window->consumeMotionDown(ui::LogicalDisplayId::DEFAULT);
7731 std::unique_ptr<MotionEvent> event = monitor.consumeMotion();
7732 ASSERT_NE(nullptr, event);
7733 // Even though window has transform, gesture monitor must not.
7734 ASSERT_EQ(ui::Transform(), event->getTransform());
7735 }
7736
TEST_F(InputDispatcherMonitorTest,InjectionFailsWithNoWindow)7737 TEST_F(InputDispatcherMonitorTest, InjectionFailsWithNoWindow) {
7738 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
7739 FakeMonitorReceiver monitor =
7740 FakeMonitorReceiver(*mDispatcher, "M_1", ui::LogicalDisplayId::DEFAULT);
7741
7742 ASSERT_EQ(InputEventInjectionResult::FAILED,
7743 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN,
7744 ui::LogicalDisplayId::DEFAULT))
7745 << "Injection should fail if there is a monitor, but no touchable window";
7746 monitor.assertNoEvents();
7747 }
7748
7749 /**
7750 * Two displays
7751 * The first monitor has a foreground window, a monitor
7752 * The second window has only one monitor.
7753 * We first inject a Down event into the first display, this injection should succeed and both
7754 * the foreground window and monitor should receive a down event, then inject a Down event into
7755 * the second display as well, this injection should fail, at this point, the first display
7756 * window and monitor should not receive a cancel or any other event.
7757 * Continue to inject Move and UP events to the first display, the events should be received
7758 * normally by the foreground window and monitor.
7759 */
TEST_F(InputDispatcherMonitorTest,MonitorTouchIsNotCanceledWhenAnotherEmptyDisplayReceiveEvents)7760 TEST_F(InputDispatcherMonitorTest, MonitorTouchIsNotCanceledWhenAnotherEmptyDisplayReceiveEvents) {
7761 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
7762 sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher, "Foreground",
7763 ui::LogicalDisplayId::DEFAULT);
7764
7765 FakeMonitorReceiver monitor =
7766 FakeMonitorReceiver(*mDispatcher, "M_1", ui::LogicalDisplayId::DEFAULT);
7767 FakeMonitorReceiver secondMonitor = FakeMonitorReceiver(*mDispatcher, "M_2", SECOND_DISPLAY_ID);
7768
7769 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
7770 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
7771 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN,
7772 ui::LogicalDisplayId::DEFAULT, {100, 200}))
7773 << "The down event injected into the first display should succeed";
7774
7775 window->consumeMotionDown();
7776 monitor.consumeMotionDown(ui::LogicalDisplayId::DEFAULT);
7777
7778 ASSERT_EQ(InputEventInjectionResult::FAILED,
7779 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, SECOND_DISPLAY_ID,
7780 {100, 200}))
7781 << "The down event injected into the second display should fail since there's no "
7782 "touchable window";
7783
7784 // Continue to inject event to first display.
7785 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
7786 injectMotionEvent(*mDispatcher, AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN,
7787 ui::LogicalDisplayId::DEFAULT, {110, 220}))
7788 << "The move event injected into the first display should succeed";
7789
7790 window->consumeMotionMove();
7791 monitor.consumeMotionMove(ui::LogicalDisplayId::DEFAULT);
7792
7793 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
7794 injectMotionUp(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ui::LogicalDisplayId::DEFAULT,
7795 {110, 220}))
7796 << "The up event injected into the first display should succeed";
7797
7798 window->consumeMotionUp();
7799 monitor.consumeMotionUp(ui::LogicalDisplayId::DEFAULT);
7800
7801 window->assertNoEvents();
7802 monitor.assertNoEvents();
7803 secondMonitor.assertNoEvents();
7804 }
7805
7806 /**
7807 * Two displays
7808 * There is a monitor and foreground window on each display.
7809 * First, we inject down events into each of the two displays, at this point, the foreground windows
7810 * and monitors on both displays should receive down events.
7811 * At this point, the foreground window of the second display goes away, the gone window should
7812 * receive the cancel event, and the other windows and monitors should not receive any events.
7813 * Inject a move event into the second display. At this point, the injection should fail because
7814 * the second display no longer has a foreground window. At this point, the monitor on the second
7815 * display should receive a cancel event, and any windows or monitors on the first display should
7816 * not receive any events, and any subsequent injection of events into the second display should
7817 * also fail.
7818 * Continue to inject events into the first display, and the events should all be injected
7819 * successfully and received normally.
7820 */
TEST_F(InputDispatcherMonitorTest,MonitorTouchIsNotCancelWhenAnotherDisplayMonitorTouchCanceled)7821 TEST_F(InputDispatcherMonitorTest, MonitorTouchIsNotCancelWhenAnotherDisplayMonitorTouchCanceled) {
7822 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
7823 sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher, "Foreground",
7824 ui::LogicalDisplayId::DEFAULT);
7825 sp<FakeWindowHandle> secondWindow =
7826 sp<FakeWindowHandle>::make(application, mDispatcher, "SecondForeground",
7827 SECOND_DISPLAY_ID);
7828
7829 FakeMonitorReceiver monitor =
7830 FakeMonitorReceiver(*mDispatcher, "M_1", ui::LogicalDisplayId::DEFAULT);
7831 FakeMonitorReceiver secondMonitor = FakeMonitorReceiver(*mDispatcher, "M_2", SECOND_DISPLAY_ID);
7832
7833 // There is a foreground window on both displays.
7834 mDispatcher->onWindowInfosChanged({{*window->getInfo(), *secondWindow->getInfo()}, {}, 0, 0});
7835 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
7836 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN,
7837 ui::LogicalDisplayId::DEFAULT, {100, 200}))
7838 << "The down event injected into the first display should succeed";
7839
7840 window->consumeMotionDown(ui::LogicalDisplayId::DEFAULT);
7841 monitor.consumeMotionDown(ui::LogicalDisplayId::DEFAULT);
7842
7843 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
7844 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, SECOND_DISPLAY_ID,
7845 {100, 200}))
7846 << "The down event injected into the second display should succeed";
7847
7848 secondWindow->consumeMotionDown(SECOND_DISPLAY_ID);
7849 secondMonitor.consumeMotionDown(SECOND_DISPLAY_ID);
7850
7851 // Now second window is gone away.
7852 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
7853
7854 // The gone window should receive a cancel, and the monitor on the second display should not
7855 // receive any events.
7856 secondWindow->consumeMotionCancel(SECOND_DISPLAY_ID);
7857 secondMonitor.assertNoEvents();
7858
7859 ASSERT_EQ(InputEventInjectionResult::FAILED,
7860 injectMotionEvent(*mDispatcher, AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN,
7861 SECOND_DISPLAY_ID, {110, 220}))
7862 << "The move event injected into the second display should fail because there's no "
7863 "touchable window";
7864 // Now the monitor on the second display should receive a cancel event.
7865 secondMonitor.consumeMotionCancel(SECOND_DISPLAY_ID);
7866
7867 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
7868 injectMotionEvent(*mDispatcher, AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN,
7869 ui::LogicalDisplayId::DEFAULT, {110, 200}))
7870 << "The move event injected into the first display should succeed";
7871
7872 window->consumeMotionMove();
7873 monitor.consumeMotionMove(ui::LogicalDisplayId::DEFAULT);
7874
7875 ASSERT_EQ(InputEventInjectionResult::FAILED,
7876 injectMotionUp(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, SECOND_DISPLAY_ID,
7877 {110, 220}))
7878 << "The up event injected into the second display should fail because there's no "
7879 "touchable window";
7880
7881 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
7882 injectMotionUp(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ui::LogicalDisplayId::DEFAULT,
7883 {110, 220}))
7884 << "The up event injected into the first display should succeed";
7885
7886 window->consumeMotionUp(ui::LogicalDisplayId::DEFAULT);
7887 monitor.consumeMotionUp(ui::LogicalDisplayId::DEFAULT);
7888
7889 window->assertNoEvents();
7890 monitor.assertNoEvents();
7891 secondWindow->assertNoEvents();
7892 secondMonitor.assertNoEvents();
7893 }
7894
7895 /**
7896 * One display with transform
7897 * There is a foreground window and a monitor on the display
7898 * Inject down event and move event sequentially, the foreground window and monitor can receive down
7899 * event and move event, then let the foreground window go away, the foreground window receives
7900 * cancel event, inject move event again, the monitor receives cancel event, all the events received
7901 * by the monitor should be with the same transform as the display
7902 */
TEST_F(InputDispatcherMonitorTest,MonitorTouchCancelEventWithDisplayTransform)7903 TEST_F(InputDispatcherMonitorTest, MonitorTouchCancelEventWithDisplayTransform) {
7904 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
7905 sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher, "Foreground",
7906 ui::LogicalDisplayId::DEFAULT);
7907 FakeMonitorReceiver monitor =
7908 FakeMonitorReceiver(*mDispatcher, "M_1", ui::LogicalDisplayId::DEFAULT);
7909
7910 ui::Transform transform;
7911 transform.set({1.1, 2.2, 3.3, 4.4, 5.5, 6.6, 0, 0, 1});
7912
7913 gui::DisplayInfo displayInfo;
7914 displayInfo.displayId = ui::LogicalDisplayId::DEFAULT;
7915 displayInfo.transform = transform;
7916
7917 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {displayInfo}, 0, 0});
7918
7919 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
7920 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN,
7921 ui::LogicalDisplayId::DEFAULT, {100, 200}))
7922 << "The down event injected should succeed";
7923
7924 window->consumeMotionDown();
7925 std::unique_ptr<MotionEvent> downMotionEvent = monitor.consumeMotion();
7926 EXPECT_EQ(transform, downMotionEvent->getTransform());
7927 EXPECT_EQ(AMOTION_EVENT_ACTION_DOWN, downMotionEvent->getAction());
7928
7929 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
7930 injectMotionEvent(*mDispatcher, AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN,
7931 ui::LogicalDisplayId::DEFAULT, {110, 220}))
7932 << "The move event injected should succeed";
7933
7934 window->consumeMotionMove();
7935 std::unique_ptr<MotionEvent> moveMotionEvent = monitor.consumeMotion();
7936 EXPECT_EQ(transform, moveMotionEvent->getTransform());
7937 EXPECT_EQ(AMOTION_EVENT_ACTION_MOVE, moveMotionEvent->getAction());
7938
7939 // Let foreground window gone
7940 mDispatcher->onWindowInfosChanged({{}, {displayInfo}, 0, 0});
7941
7942 // Foreground window should receive a cancel event, but not the monitor.
7943 window->consumeMotionCancel();
7944
7945 ASSERT_EQ(InputEventInjectionResult::FAILED,
7946 injectMotionEvent(*mDispatcher, AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN,
7947 ui::LogicalDisplayId::DEFAULT, {110, 220}))
7948 << "The move event injected should failed";
7949 // Now foreground should not receive any events, but monitor should receive a cancel event
7950 // with transform that same as display's display.
7951 std::unique_ptr<MotionEvent> cancelMotionEvent = monitor.consumeMotion();
7952 EXPECT_EQ(transform, cancelMotionEvent->getTransform());
7953 EXPECT_EQ(ui::LogicalDisplayId::DEFAULT, cancelMotionEvent->getDisplayId());
7954 EXPECT_EQ(AMOTION_EVENT_ACTION_CANCEL, cancelMotionEvent->getAction());
7955
7956 // Other event inject to this display should fail.
7957 ASSERT_EQ(InputEventInjectionResult::FAILED,
7958 injectMotionEvent(*mDispatcher, AMOTION_EVENT_ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN,
7959 ui::LogicalDisplayId::DEFAULT, {110, 220}))
7960 << "The up event injected should fail because the touched window was removed";
7961 window->assertNoEvents();
7962 monitor.assertNoEvents();
7963 }
7964
TEST_F(InputDispatcherTest,TestMoveEvent)7965 TEST_F(InputDispatcherTest, TestMoveEvent) {
7966 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
7967 sp<FakeWindowHandle> window =
7968 sp<FakeWindowHandle>::make(application, mDispatcher, "Fake Window",
7969 ui::LogicalDisplayId::DEFAULT);
7970
7971 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
7972
7973 NotifyMotionArgs motionArgs =
7974 generateMotionArgs(AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN,
7975 ui::LogicalDisplayId::DEFAULT);
7976
7977 mDispatcher->notifyMotion(motionArgs);
7978 // Window should receive motion down event.
7979 window->consumeMotionDown(ui::LogicalDisplayId::DEFAULT);
7980
7981 motionArgs.action = AMOTION_EVENT_ACTION_MOVE;
7982 motionArgs.id += 1;
7983 motionArgs.eventTime = systemTime(SYSTEM_TIME_MONOTONIC);
7984 motionArgs.pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_X,
7985 motionArgs.pointerCoords[0].getX() - 10);
7986
7987 mDispatcher->notifyMotion(motionArgs);
7988 window->consumeMotionMove(ui::LogicalDisplayId::DEFAULT, /*expectedFlags=*/0);
7989 }
7990
7991 /**
7992 * Dispatcher has touch mode enabled by default. Typically, the policy overrides that value to
7993 * the device default right away. In the test scenario, we check both the default value,
7994 * and the action of enabling / disabling.
7995 */
TEST_F(InputDispatcherTest,TouchModeState_IsSentToApps)7996 TEST_F(InputDispatcherTest, TouchModeState_IsSentToApps) {
7997 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
7998 sp<FakeWindowHandle> window =
7999 sp<FakeWindowHandle>::make(application, mDispatcher, "Test window",
8000 ui::LogicalDisplayId::DEFAULT);
8001 const WindowInfo& windowInfo = *window->getInfo();
8002
8003 // Set focused application.
8004 mDispatcher->setFocusedApplication(ui::LogicalDisplayId::DEFAULT, application);
8005 window->setFocusable(true);
8006
8007 SCOPED_TRACE("Check default value of touch mode");
8008 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
8009 setFocusedWindow(window);
8010 window->consumeFocusEvent(/*hasFocus=*/true, /*inTouchMode=*/true);
8011
8012 SCOPED_TRACE("Remove the window to trigger focus loss");
8013 window->setFocusable(false);
8014 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
8015 window->consumeFocusEvent(/*hasFocus=*/false, /*inTouchMode=*/true);
8016
8017 SCOPED_TRACE("Disable touch mode");
8018 mDispatcher->setInTouchMode(false, windowInfo.ownerPid, windowInfo.ownerUid,
8019 /*hasPermission=*/true, ui::LogicalDisplayId::DEFAULT);
8020 window->consumeTouchModeEvent(false);
8021 window->setFocusable(true);
8022 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
8023 setFocusedWindow(window);
8024 window->consumeFocusEvent(/*hasFocus=*/true, /*inTouchMode=*/false);
8025
8026 SCOPED_TRACE("Remove the window to trigger focus loss");
8027 window->setFocusable(false);
8028 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
8029 window->consumeFocusEvent(/*hasFocus=*/false, /*inTouchMode=*/false);
8030
8031 SCOPED_TRACE("Enable touch mode again");
8032 mDispatcher->setInTouchMode(true, windowInfo.ownerPid, windowInfo.ownerUid,
8033 /*hasPermission=*/true, ui::LogicalDisplayId::DEFAULT);
8034 window->consumeTouchModeEvent(true);
8035 window->setFocusable(true);
8036 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
8037 setFocusedWindow(window);
8038 window->consumeFocusEvent(/*hasFocus=*/true, /*inTouchMode=*/true);
8039
8040 window->assertNoEvents();
8041 }
8042
TEST_F(InputDispatcherTest,VerifyInputEvent_KeyEvent)8043 TEST_F(InputDispatcherTest, VerifyInputEvent_KeyEvent) {
8044 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
8045 sp<FakeWindowHandle> window =
8046 sp<FakeWindowHandle>::make(application, mDispatcher, "Test window",
8047 ui::LogicalDisplayId::DEFAULT);
8048
8049 mDispatcher->setFocusedApplication(ui::LogicalDisplayId::DEFAULT, application);
8050 window->setFocusable(true);
8051
8052 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
8053 setFocusedWindow(window);
8054
8055 window->consumeFocusEvent(/*hasFocus=*/true, /*inTouchMode=*/true);
8056
8057 const NotifyKeyArgs keyArgs = generateKeyArgs(AKEY_EVENT_ACTION_DOWN);
8058 mDispatcher->notifyKey(keyArgs);
8059
8060 std::unique_ptr<KeyEvent> event = window->consumeKey();
8061 ASSERT_NE(event, nullptr);
8062 std::unique_ptr<VerifiedInputEvent> verified = mDispatcher->verifyInputEvent(*event);
8063 ASSERT_NE(verified, nullptr);
8064 ASSERT_EQ(verified->type, VerifiedInputEvent::Type::KEY);
8065
8066 ASSERT_EQ(keyArgs.eventTime, verified->eventTimeNanos);
8067 ASSERT_EQ(keyArgs.deviceId, verified->deviceId);
8068 ASSERT_EQ(keyArgs.source, verified->source);
8069 ASSERT_EQ(keyArgs.displayId, verified->displayId);
8070
8071 const VerifiedKeyEvent& verifiedKey = static_cast<const VerifiedKeyEvent&>(*verified);
8072
8073 ASSERT_EQ(keyArgs.action, verifiedKey.action);
8074 ASSERT_EQ(keyArgs.flags & VERIFIED_KEY_EVENT_FLAGS, verifiedKey.flags);
8075 ASSERT_EQ(keyArgs.downTime, verifiedKey.downTimeNanos);
8076 ASSERT_EQ(keyArgs.keyCode, verifiedKey.keyCode);
8077 ASSERT_EQ(keyArgs.scanCode, verifiedKey.scanCode);
8078 ASSERT_EQ(keyArgs.metaState, verifiedKey.metaState);
8079 ASSERT_EQ(0, verifiedKey.repeatCount);
8080 }
8081
TEST_F(InputDispatcherTest,VerifyInputEvent_MotionEvent)8082 TEST_F(InputDispatcherTest, VerifyInputEvent_MotionEvent) {
8083 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
8084 sp<FakeWindowHandle> window =
8085 sp<FakeWindowHandle>::make(application, mDispatcher, "Test window",
8086 ui::LogicalDisplayId::DEFAULT);
8087
8088 mDispatcher->setFocusedApplication(ui::LogicalDisplayId::DEFAULT, application);
8089
8090 ui::Transform transform;
8091 transform.set({1.1, 2.2, 3.3, 4.4, 5.5, 6.6, 0, 0, 1});
8092
8093 gui::DisplayInfo displayInfo;
8094 displayInfo.displayId = ui::LogicalDisplayId::DEFAULT;
8095 displayInfo.transform = transform;
8096
8097 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {displayInfo}, 0, 0});
8098
8099 const NotifyMotionArgs motionArgs =
8100 generateMotionArgs(AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN,
8101 ui::LogicalDisplayId::DEFAULT);
8102 mDispatcher->notifyMotion(motionArgs);
8103
8104 std::unique_ptr<MotionEvent> event = window->consumeMotionEvent();
8105 ASSERT_NE(nullptr, event);
8106 std::unique_ptr<VerifiedInputEvent> verified = mDispatcher->verifyInputEvent(*event);
8107 ASSERT_NE(verified, nullptr);
8108 ASSERT_EQ(verified->type, VerifiedInputEvent::Type::MOTION);
8109
8110 EXPECT_EQ(motionArgs.eventTime, verified->eventTimeNanos);
8111 EXPECT_EQ(motionArgs.deviceId, verified->deviceId);
8112 EXPECT_EQ(motionArgs.source, verified->source);
8113 EXPECT_EQ(motionArgs.displayId, verified->displayId);
8114
8115 const VerifiedMotionEvent& verifiedMotion = static_cast<const VerifiedMotionEvent&>(*verified);
8116
8117 const vec2 rawXY =
8118 MotionEvent::calculateTransformedXY(motionArgs.source, transform,
8119 motionArgs.pointerCoords[0].getXYValue());
8120 EXPECT_EQ(rawXY.x, verifiedMotion.rawX);
8121 EXPECT_EQ(rawXY.y, verifiedMotion.rawY);
8122 EXPECT_EQ(motionArgs.action & AMOTION_EVENT_ACTION_MASK, verifiedMotion.actionMasked);
8123 EXPECT_EQ(motionArgs.flags & VERIFIED_MOTION_EVENT_FLAGS, verifiedMotion.flags);
8124 EXPECT_EQ(motionArgs.downTime, verifiedMotion.downTimeNanos);
8125 EXPECT_EQ(motionArgs.metaState, verifiedMotion.metaState);
8126 EXPECT_EQ(motionArgs.buttonState, verifiedMotion.buttonState);
8127 }
8128
8129 /**
8130 * Ensure that separate calls to sign the same data are generating the same key.
8131 * We avoid asserting against INVALID_HMAC. Since the key is random, there is a non-zero chance
8132 * that a specific key and data combination would produce INVALID_HMAC, which would cause flaky
8133 * tests.
8134 */
TEST_F(InputDispatcherTest,GeneratedHmac_IsConsistent)8135 TEST_F(InputDispatcherTest, GeneratedHmac_IsConsistent) {
8136 KeyEvent event = getTestKeyEvent();
8137 VerifiedKeyEvent verifiedEvent = verifiedKeyEventFromKeyEvent(event);
8138
8139 std::array<uint8_t, 32> hmac1 = mDispatcher->sign(verifiedEvent);
8140 std::array<uint8_t, 32> hmac2 = mDispatcher->sign(verifiedEvent);
8141 ASSERT_EQ(hmac1, hmac2);
8142 }
8143
8144 /**
8145 * Ensure that changes in VerifiedKeyEvent produce a different hmac.
8146 */
TEST_F(InputDispatcherTest,GeneratedHmac_ChangesWhenFieldsChange)8147 TEST_F(InputDispatcherTest, GeneratedHmac_ChangesWhenFieldsChange) {
8148 KeyEvent event = getTestKeyEvent();
8149 VerifiedKeyEvent verifiedEvent = verifiedKeyEventFromKeyEvent(event);
8150 std::array<uint8_t, 32> initialHmac = mDispatcher->sign(verifiedEvent);
8151
8152 verifiedEvent.deviceId += 1;
8153 ASSERT_NE(initialHmac, mDispatcher->sign(verifiedEvent));
8154
8155 verifiedEvent.source += 1;
8156 ASSERT_NE(initialHmac, mDispatcher->sign(verifiedEvent));
8157
8158 verifiedEvent.eventTimeNanos += 1;
8159 ASSERT_NE(initialHmac, mDispatcher->sign(verifiedEvent));
8160
8161 verifiedEvent.displayId = ui::LogicalDisplayId{verifiedEvent.displayId.val() + 1};
8162 ASSERT_NE(initialHmac, mDispatcher->sign(verifiedEvent));
8163
8164 verifiedEvent.action += 1;
8165 ASSERT_NE(initialHmac, mDispatcher->sign(verifiedEvent));
8166
8167 verifiedEvent.downTimeNanos += 1;
8168 ASSERT_NE(initialHmac, mDispatcher->sign(verifiedEvent));
8169
8170 verifiedEvent.flags += 1;
8171 ASSERT_NE(initialHmac, mDispatcher->sign(verifiedEvent));
8172
8173 verifiedEvent.keyCode += 1;
8174 ASSERT_NE(initialHmac, mDispatcher->sign(verifiedEvent));
8175
8176 verifiedEvent.scanCode += 1;
8177 ASSERT_NE(initialHmac, mDispatcher->sign(verifiedEvent));
8178
8179 verifiedEvent.metaState += 1;
8180 ASSERT_NE(initialHmac, mDispatcher->sign(verifiedEvent));
8181
8182 verifiedEvent.repeatCount += 1;
8183 ASSERT_NE(initialHmac, mDispatcher->sign(verifiedEvent));
8184 }
8185
TEST_F(InputDispatcherTest,SetFocusedWindow)8186 TEST_F(InputDispatcherTest, SetFocusedWindow) {
8187 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
8188 sp<FakeWindowHandle> windowTop = sp<FakeWindowHandle>::make(application, mDispatcher, "Top",
8189 ui::LogicalDisplayId::DEFAULT);
8190 sp<FakeWindowHandle> windowSecond =
8191 sp<FakeWindowHandle>::make(application, mDispatcher, "Second",
8192 ui::LogicalDisplayId::DEFAULT);
8193 mDispatcher->setFocusedApplication(ui::LogicalDisplayId::DEFAULT, application);
8194
8195 // Top window is also focusable but is not granted focus.
8196 windowTop->setFocusable(true);
8197 windowSecond->setFocusable(true);
8198 mDispatcher->onWindowInfosChanged(
8199 {{*windowTop->getInfo(), *windowSecond->getInfo()}, {}, 0, 0});
8200 setFocusedWindow(windowSecond);
8201
8202 windowSecond->consumeFocusEvent(true);
8203 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectKeyDown(*mDispatcher))
8204 << "Inject key event should return InputEventInjectionResult::SUCCEEDED";
8205
8206 // Focused window should receive event.
8207 windowSecond->consumeKeyDown(ui::LogicalDisplayId::INVALID);
8208 windowTop->assertNoEvents();
8209 }
8210
TEST_F(InputDispatcherTest,SetFocusedWindow_DropRequestInvalidChannel)8211 TEST_F(InputDispatcherTest, SetFocusedWindow_DropRequestInvalidChannel) {
8212 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
8213 sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher, "TestWindow",
8214 ui::LogicalDisplayId::DEFAULT);
8215 mDispatcher->setFocusedApplication(ui::LogicalDisplayId::DEFAULT, application);
8216
8217 window->setFocusable(true);
8218 // Release channel for window is no longer valid.
8219 window->releaseChannel();
8220 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
8221 setFocusedWindow(window);
8222
8223 // Test inject a key down, should timeout.
8224 ASSERT_NO_FATAL_FAILURE(assertInjectedKeyTimesOut(*mDispatcher));
8225
8226 // window channel is invalid, so it should not receive any input event.
8227 window->assertNoEvents();
8228 }
8229
TEST_F(InputDispatcherTest,SetFocusedWindow_DropRequestNoFocusableWindow)8230 TEST_F(InputDispatcherTest, SetFocusedWindow_DropRequestNoFocusableWindow) {
8231 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
8232 sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher, "TestWindow",
8233 ui::LogicalDisplayId::DEFAULT);
8234 window->setFocusable(false);
8235 mDispatcher->setFocusedApplication(ui::LogicalDisplayId::DEFAULT, application);
8236
8237 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
8238 setFocusedWindow(window);
8239
8240 // Test inject a key down, should timeout.
8241 ASSERT_NO_FATAL_FAILURE(assertInjectedKeyTimesOut(*mDispatcher));
8242
8243 // window is not focusable, so it should not receive any input event.
8244 window->assertNoEvents();
8245 }
8246
TEST_F(InputDispatcherTest,SetFocusedWindow_CheckFocusedToken)8247 TEST_F(InputDispatcherTest, SetFocusedWindow_CheckFocusedToken) {
8248 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
8249 sp<FakeWindowHandle> windowTop = sp<FakeWindowHandle>::make(application, mDispatcher, "Top",
8250 ui::LogicalDisplayId::DEFAULT);
8251 sp<FakeWindowHandle> windowSecond =
8252 sp<FakeWindowHandle>::make(application, mDispatcher, "Second",
8253 ui::LogicalDisplayId::DEFAULT);
8254 mDispatcher->setFocusedApplication(ui::LogicalDisplayId::DEFAULT, application);
8255
8256 windowTop->setFocusable(true);
8257 windowSecond->setFocusable(true);
8258 mDispatcher->onWindowInfosChanged(
8259 {{*windowTop->getInfo(), *windowSecond->getInfo()}, {}, 0, 0});
8260 setFocusedWindow(windowTop);
8261 windowTop->consumeFocusEvent(true);
8262
8263 windowTop->editInfo()->focusTransferTarget = windowSecond->getToken();
8264 mDispatcher->onWindowInfosChanged(
8265 {{*windowTop->getInfo(), *windowSecond->getInfo()}, {}, 0, 0});
8266 windowSecond->consumeFocusEvent(true);
8267 windowTop->consumeFocusEvent(false);
8268
8269 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectKeyDown(*mDispatcher))
8270 << "Inject key event should return InputEventInjectionResult::SUCCEEDED";
8271
8272 // Focused window should receive event.
8273 windowSecond->consumeKeyDown(ui::LogicalDisplayId::INVALID);
8274 }
8275
TEST_F(InputDispatcherTest,SetFocusedWindow_TransferFocusTokenNotFocusable)8276 TEST_F(InputDispatcherTest, SetFocusedWindow_TransferFocusTokenNotFocusable) {
8277 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
8278 sp<FakeWindowHandle> windowTop = sp<FakeWindowHandle>::make(application, mDispatcher, "Top",
8279 ui::LogicalDisplayId::DEFAULT);
8280 sp<FakeWindowHandle> windowSecond =
8281 sp<FakeWindowHandle>::make(application, mDispatcher, "Second",
8282 ui::LogicalDisplayId::DEFAULT);
8283 mDispatcher->setFocusedApplication(ui::LogicalDisplayId::DEFAULT, application);
8284
8285 windowTop->setFocusable(true);
8286 windowSecond->setFocusable(false);
8287 windowTop->editInfo()->focusTransferTarget = windowSecond->getToken();
8288 mDispatcher->onWindowInfosChanged(
8289 {{*windowTop->getInfo(), *windowSecond->getInfo()}, {}, 0, 0});
8290 setFocusedWindow(windowTop);
8291 windowTop->consumeFocusEvent(true);
8292
8293 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectKeyDown(*mDispatcher))
8294 << "Inject key event should return InputEventInjectionResult::SUCCEEDED";
8295
8296 // Event should be dropped.
8297 windowTop->consumeKeyDown(ui::LogicalDisplayId::INVALID);
8298 windowSecond->assertNoEvents();
8299 }
8300
TEST_F(InputDispatcherTest,SetFocusedWindow_DeferInvisibleWindow)8301 TEST_F(InputDispatcherTest, SetFocusedWindow_DeferInvisibleWindow) {
8302 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
8303 sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher, "TestWindow",
8304 ui::LogicalDisplayId::DEFAULT);
8305 sp<FakeWindowHandle> previousFocusedWindow =
8306 sp<FakeWindowHandle>::make(application, mDispatcher, "previousFocusedWindow",
8307 ui::LogicalDisplayId::DEFAULT);
8308 mDispatcher->setFocusedApplication(ui::LogicalDisplayId::DEFAULT, application);
8309
8310 window->setFocusable(true);
8311 previousFocusedWindow->setFocusable(true);
8312 window->setVisible(false);
8313 mDispatcher->onWindowInfosChanged(
8314 {{*window->getInfo(), *previousFocusedWindow->getInfo()}, {}, 0, 0});
8315 setFocusedWindow(previousFocusedWindow);
8316 previousFocusedWindow->consumeFocusEvent(true);
8317
8318 // Requesting focus on invisible window takes focus from currently focused window.
8319 setFocusedWindow(window);
8320 previousFocusedWindow->consumeFocusEvent(false);
8321
8322 // Injected key goes to pending queue.
8323 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
8324 injectKey(*mDispatcher, AKEY_EVENT_ACTION_DOWN, /*repeatCount=*/0,
8325 ui::LogicalDisplayId::DEFAULT, InputEventInjectionSync::NONE));
8326
8327 // Window does not get focus event or key down.
8328 window->assertNoEvents();
8329
8330 // Window becomes visible.
8331 window->setVisible(true);
8332 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
8333
8334 // Window receives focus event.
8335 window->consumeFocusEvent(true);
8336 // Focused window receives key down.
8337 window->consumeKeyDown(ui::LogicalDisplayId::DEFAULT);
8338 }
8339
TEST_F(InputDispatcherTest,DisplayRemoved)8340 TEST_F(InputDispatcherTest, DisplayRemoved) {
8341 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
8342 sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher, "window",
8343 ui::LogicalDisplayId::DEFAULT);
8344 mDispatcher->setFocusedApplication(ui::LogicalDisplayId::DEFAULT, application);
8345
8346 // window is granted focus.
8347 window->setFocusable(true);
8348 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
8349 setFocusedWindow(window);
8350 window->consumeFocusEvent(true);
8351
8352 // When a display is removed window loses focus.
8353 mDispatcher->displayRemoved(ui::LogicalDisplayId::DEFAULT);
8354 window->consumeFocusEvent(false);
8355 }
8356
8357 /**
8358 * Launch two windows, with different owners. One window (slipperyExitWindow) has Flag::SLIPPERY,
8359 * and overlaps the other window, slipperyEnterWindow. The window 'slipperyExitWindow' is on top
8360 * of the 'slipperyEnterWindow'.
8361 *
8362 * Inject touch down into the top window. Upon receipt of the DOWN event, move the window in such
8363 * a way so that the touched location is no longer covered by the top window.
8364 *
8365 * Next, inject a MOVE event. Because the top window already moved earlier, this event is now
8366 * positioned over the bottom (slipperyEnterWindow) only. And because the top window had
8367 * Flag::SLIPPERY, this will cause the top window to lose the touch event (it will receive
8368 * ACTION_CANCEL instead), and the bottom window will receive a newly generated gesture (starting
8369 * with ACTION_DOWN).
8370 * Thus, the touch has been transferred from the top window into the bottom window, because the top
8371 * window moved itself away from the touched location and had Flag::SLIPPERY.
8372 *
8373 * Even though the top window moved away from the touched location, it is still obscuring the bottom
8374 * window. It's just not obscuring it at the touched location. That means, FLAG_WINDOW_IS_PARTIALLY_
8375 * OBSCURED should be set for the MotionEvent that reaches the bottom window.
8376 *
8377 * In this test, we ensure that the event received by the bottom window has
8378 * FLAG_WINDOW_IS_PARTIALLY_OBSCURED.
8379 */
TEST_F(InputDispatcherTest,SlipperyWindow_SetsFlagPartiallyObscured)8380 TEST_F(InputDispatcherTest, SlipperyWindow_SetsFlagPartiallyObscured) {
8381 constexpr gui::Pid SLIPPERY_PID{WINDOW_PID.val() + 1};
8382 constexpr gui::Uid SLIPPERY_UID{WINDOW_UID.val() + 1};
8383
8384 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
8385 mDispatcher->setFocusedApplication(ui::LogicalDisplayId::DEFAULT, application);
8386
8387 sp<FakeWindowHandle> slipperyExitWindow =
8388 sp<FakeWindowHandle>::make(application, mDispatcher, "Top",
8389 ui::LogicalDisplayId::DEFAULT);
8390 slipperyExitWindow->setSlippery(true);
8391 // Make sure this one overlaps the bottom window
8392 slipperyExitWindow->setFrame(Rect(25, 25, 75, 75));
8393 // Change the owner uid/pid of the window so that it is considered to be occluding the bottom
8394 // one. Windows with the same owner are not considered to be occluding each other.
8395 slipperyExitWindow->setOwnerInfo(SLIPPERY_PID, SLIPPERY_UID);
8396
8397 sp<FakeWindowHandle> slipperyEnterWindow =
8398 sp<FakeWindowHandle>::make(application, mDispatcher, "Second",
8399 ui::LogicalDisplayId::DEFAULT);
8400 slipperyExitWindow->setFrame(Rect(0, 0, 100, 100));
8401
8402 mDispatcher->onWindowInfosChanged(
8403 {{*slipperyExitWindow->getInfo(), *slipperyEnterWindow->getInfo()}, {}, 0, 0});
8404
8405 // Use notifyMotion instead of injecting to avoid dealing with injection permissions
8406 mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_DOWN,
8407 AINPUT_SOURCE_TOUCHSCREEN,
8408 ui::LogicalDisplayId::DEFAULT, {{50, 50}}));
8409 slipperyExitWindow->consumeMotionDown();
8410 slipperyExitWindow->setFrame(Rect(70, 70, 100, 100));
8411 mDispatcher->onWindowInfosChanged(
8412 {{*slipperyExitWindow->getInfo(), *slipperyEnterWindow->getInfo()}, {}, 0, 0});
8413
8414 mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_MOVE,
8415 AINPUT_SOURCE_TOUCHSCREEN,
8416 ui::LogicalDisplayId::DEFAULT, {{51, 51}}));
8417
8418 slipperyExitWindow->consumeMotionCancel();
8419
8420 slipperyEnterWindow->consumeMotionDown(ui::LogicalDisplayId::DEFAULT,
8421 AMOTION_EVENT_FLAG_WINDOW_IS_PARTIALLY_OBSCURED);
8422 }
8423
8424 /**
8425 * Two windows, one on the left and another on the right. The left window is slippery. The right
8426 * window isn't eligible to receive touch because it specifies InputConfig::DROP_INPUT. When the
8427 * touch moves from the left window into the right window, the gesture should continue to go to the
8428 * left window. Touch shouldn't slip because the right window can't receive touches. This test
8429 * reproduces a crash.
8430 */
TEST_F(InputDispatcherTest,TouchSlippingIntoWindowThatDropsTouches)8431 TEST_F(InputDispatcherTest, TouchSlippingIntoWindowThatDropsTouches) {
8432 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
8433
8434 sp<FakeWindowHandle> leftSlipperyWindow =
8435 sp<FakeWindowHandle>::make(application, mDispatcher, "Left",
8436 ui::LogicalDisplayId::DEFAULT);
8437 leftSlipperyWindow->setSlippery(true);
8438 leftSlipperyWindow->setFrame(Rect(0, 0, 100, 100));
8439
8440 sp<FakeWindowHandle> rightDropTouchesWindow =
8441 sp<FakeWindowHandle>::make(application, mDispatcher, "Right",
8442 ui::LogicalDisplayId::DEFAULT);
8443 rightDropTouchesWindow->setFrame(Rect(100, 0, 200, 100));
8444 rightDropTouchesWindow->setDropInput(true);
8445
8446 mDispatcher->onWindowInfosChanged(
8447 {{*leftSlipperyWindow->getInfo(), *rightDropTouchesWindow->getInfo()}, {}, 0, 0});
8448
8449 // Start touch in the left window
8450 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
8451 .pointer(PointerBuilder(0, ToolType::FINGER).x(50).y(50))
8452 .build());
8453 leftSlipperyWindow->consumeMotionDown();
8454
8455 // And move it into the right window
8456 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN)
8457 .pointer(PointerBuilder(0, ToolType::FINGER).x(150).y(50))
8458 .build());
8459
8460 // Since the right window isn't eligible to receive input, touch does not slip.
8461 // The left window continues to receive the gesture.
8462 leftSlipperyWindow->consumeMotionEvent(WithMotionAction(ACTION_MOVE));
8463 rightDropTouchesWindow->assertNoEvents();
8464 }
8465
8466 /**
8467 * A single window is on screen first. Touch is injected into that window. Next, a second window
8468 * appears. Since the first window is slippery, touch will move from the first window to the second.
8469 */
TEST_F(InputDispatcherTest,InjectedTouchSlips)8470 TEST_F(InputDispatcherTest, InjectedTouchSlips) {
8471 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
8472 sp<FakeWindowHandle> originalWindow =
8473 sp<FakeWindowHandle>::make(application, mDispatcher, "Original",
8474 ui::LogicalDisplayId::DEFAULT);
8475 originalWindow->setFrame(Rect(0, 0, 200, 200));
8476 originalWindow->setSlippery(true);
8477
8478 sp<FakeWindowHandle> appearingWindow =
8479 sp<FakeWindowHandle>::make(application, mDispatcher, "Appearing",
8480 ui::LogicalDisplayId::DEFAULT);
8481 appearingWindow->setFrame(Rect(0, 0, 200, 200));
8482
8483 mDispatcher->onWindowInfosChanged({{*originalWindow->getInfo()}, {}, 0, 0});
8484
8485 // Touch down on the original window
8486 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
8487 injectMotionEvent(*mDispatcher,
8488 MotionEventBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
8489 .pointer(PointerBuilder(1, ToolType::FINGER).x(100).y(100))
8490 .build()));
8491 originalWindow->consumeMotionEvent(WithMotionAction(ACTION_DOWN));
8492
8493 // Now, a new window appears. This could be, for example, a notification shade that appears
8494 // after user starts to drag down on the launcher window.
8495 mDispatcher->onWindowInfosChanged(
8496 {{*appearingWindow->getInfo(), *originalWindow->getInfo()}, {}, 0, 0});
8497 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
8498 injectMotionEvent(*mDispatcher,
8499 MotionEventBuilder(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN)
8500 .pointer(PointerBuilder(1, ToolType::FINGER).x(110).y(110))
8501 .build()));
8502 originalWindow->consumeMotionEvent(WithMotionAction(ACTION_CANCEL));
8503 appearingWindow->consumeMotionEvent(WithMotionAction(ACTION_DOWN));
8504 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
8505 injectMotionEvent(*mDispatcher,
8506 MotionEventBuilder(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN)
8507 .pointer(PointerBuilder(1, ToolType::FINGER).x(120).y(120))
8508 .build()));
8509 appearingWindow->consumeMotionEvent(WithMotionAction(ACTION_MOVE));
8510
8511 originalWindow->assertNoEvents();
8512 appearingWindow->assertNoEvents();
8513 }
8514
8515 /**
8516 * Three windows:
8517 * - left window, which has FLAG_SLIPPERY, so it supports slippery exit
8518 * - right window
8519 * - spy window
8520 * The three windows do not overlap.
8521 *
8522 * We have two devices reporting events:
8523 * - Device A reports ACTION_DOWN, which lands in the left window
8524 * - Device B reports ACTION_DOWN, which lands in the spy window.
8525 * - Now, device B reports ACTION_MOVE events which move to the right window.
8526 *
8527 * The right window should not receive any events because the spy window is not a foreground window,
8528 * and also it does not support slippery touches.
8529 */
TEST_F(InputDispatcherTest,MultiDeviceSpyWindowSlipTest)8530 TEST_F(InputDispatcherTest, MultiDeviceSpyWindowSlipTest) {
8531 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
8532 sp<FakeWindowHandle> leftWindow =
8533 sp<FakeWindowHandle>::make(application, mDispatcher, "Left window",
8534 ui::LogicalDisplayId::DEFAULT);
8535 leftWindow->setFrame(Rect(0, 0, 100, 100));
8536 leftWindow->setSlippery(true);
8537
8538 sp<FakeWindowHandle> rightWindow =
8539 sp<FakeWindowHandle>::make(application, mDispatcher, "Right window",
8540 ui::LogicalDisplayId::DEFAULT);
8541 rightWindow->setFrame(Rect(100, 0, 200, 100));
8542
8543 sp<FakeWindowHandle> spyWindow =
8544 sp<FakeWindowHandle>::make(application, mDispatcher, "Spy Window",
8545 ui::LogicalDisplayId::DEFAULT);
8546 spyWindow->setFrame(Rect(200, 0, 300, 100));
8547 spyWindow->setSpy(true);
8548 spyWindow->setTrustedOverlay(true);
8549
8550 mDispatcher->onWindowInfosChanged(
8551 {{*leftWindow->getInfo(), *rightWindow->getInfo(), *spyWindow->getInfo()}, {}, 0, 0});
8552
8553 const DeviceId deviceA = 9;
8554 const DeviceId deviceB = 3;
8555
8556 // Tap on left window with device A
8557 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
8558 .pointer(PointerBuilder(0, ToolType::FINGER).x(50).y(50))
8559 .deviceId(deviceA)
8560 .build());
8561 leftWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(deviceA)));
8562
8563 // Tap on spy window with device B
8564 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
8565 .pointer(PointerBuilder(0, ToolType::FINGER).x(250).y(50))
8566 .deviceId(deviceB)
8567 .build());
8568 spyWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(deviceB)));
8569
8570 // Move to right window with device B. Touches should not slip to the right window, because spy
8571 // window is not a foreground window, and it does not have FLAG_SLIPPERY
8572 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN)
8573 .pointer(PointerBuilder(0, ToolType::FINGER).x(150).y(50))
8574 .deviceId(deviceB)
8575 .build());
8576 leftWindow->assertNoEvents();
8577 rightWindow->assertNoEvents();
8578 spyWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(deviceB)));
8579 }
8580
8581 /**
8582 * Three windows arranged horizontally and without any overlap.
8583 * The left and right windows have FLAG_SLIPPERY. The middle window does not have any special flags.
8584 *
8585 * We have two devices reporting events:
8586 * - Device A reports ACTION_DOWN which lands in the left window
8587 * - Device B reports ACTION_DOWN which lands in the right window
8588 * - Device B reports ACTION_MOVE that shifts to the middle window.
8589 * This should cause touches for Device B to slip from the right window to the middle window.
8590 * The right window should receive ACTION_CANCEL for device B and the
8591 * middle window should receive down event for Device B.
8592 * If device B reports more ACTION_MOVE events, the middle window should receive remaining events.
8593 */
TEST_F(InputDispatcherTest,MultiDeviceSlipperyWindowTest)8594 TEST_F(InputDispatcherTest, MultiDeviceSlipperyWindowTest) {
8595 SCOPED_FLAG_OVERRIDE(enable_multi_device_same_window_stream, true);
8596 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
8597 sp<FakeWindowHandle> leftWindow =
8598 sp<FakeWindowHandle>::make(application, mDispatcher, "Left window",
8599 ui::LogicalDisplayId::DEFAULT);
8600 leftWindow->setFrame(Rect(0, 0, 100, 100));
8601 leftWindow->setSlippery(true);
8602
8603 sp<FakeWindowHandle> middleWindow =
8604 sp<FakeWindowHandle>::make(application, mDispatcher, "middle window",
8605 ui::LogicalDisplayId::DEFAULT);
8606 middleWindow->setFrame(Rect(100, 0, 200, 100));
8607
8608 sp<FakeWindowHandle> rightWindow =
8609 sp<FakeWindowHandle>::make(application, mDispatcher, "Right window",
8610 ui::LogicalDisplayId::DEFAULT);
8611 rightWindow->setFrame(Rect(200, 0, 300, 100));
8612 rightWindow->setSlippery(true);
8613
8614 mDispatcher->onWindowInfosChanged(
8615 {{*leftWindow->getInfo(), *middleWindow->getInfo(), *rightWindow->getInfo()},
8616 {},
8617 0,
8618 0});
8619
8620 const DeviceId deviceA = 9;
8621 const DeviceId deviceB = 3;
8622
8623 // Tap on left window with device A
8624 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
8625 .pointer(PointerBuilder(0, ToolType::FINGER).x(50).y(50))
8626 .deviceId(deviceA)
8627 .build());
8628 leftWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(deviceA)));
8629
8630 // Tap on right window with device B
8631 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
8632 .pointer(PointerBuilder(0, ToolType::FINGER).x(250).y(50))
8633 .deviceId(deviceB)
8634 .build());
8635 rightWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(deviceB)));
8636
8637 // Move to middle window with device B. Touches should slip to middle window, because right
8638 // window is a foreground window that's associated with device B and has FLAG_SLIPPERY.
8639 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN)
8640 .pointer(PointerBuilder(0, ToolType::FINGER).x(150).y(50))
8641 .deviceId(deviceB)
8642 .build());
8643 rightWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_CANCEL), WithDeviceId(deviceB)));
8644 middleWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(deviceB)));
8645
8646 // Move to middle window with device A. Touches should slip to middle window, because left
8647 // window is a foreground window that's associated with device A and has FLAG_SLIPPERY.
8648 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN)
8649 .pointer(PointerBuilder(0, ToolType::FINGER).x(150).y(50))
8650 .deviceId(deviceA)
8651 .build());
8652 leftWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_CANCEL), WithDeviceId(deviceA)));
8653 middleWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(deviceA)));
8654
8655 // Ensure that middle window can receive the remaining move events.
8656 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN)
8657 .pointer(PointerBuilder(0, ToolType::FINGER).x(151).y(51))
8658 .deviceId(deviceB)
8659 .build());
8660 leftWindow->assertNoEvents();
8661 middleWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(deviceB)));
8662 rightWindow->assertNoEvents();
8663 }
8664
TEST_F(InputDispatcherTest,NotifiesDeviceInteractionsWithMotions)8665 TEST_F(InputDispatcherTest, NotifiesDeviceInteractionsWithMotions) {
8666 using Uid = gui::Uid;
8667 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
8668
8669 sp<FakeWindowHandle> leftWindow = sp<FakeWindowHandle>::make(application, mDispatcher, "Left",
8670 ui::LogicalDisplayId::DEFAULT);
8671 leftWindow->setFrame(Rect(0, 0, 100, 100));
8672 leftWindow->setOwnerInfo(gui::Pid{1}, Uid{101});
8673
8674 sp<FakeWindowHandle> rightSpy =
8675 sp<FakeWindowHandle>::make(application, mDispatcher, "Right spy",
8676 ui::LogicalDisplayId::DEFAULT);
8677 rightSpy->setFrame(Rect(100, 0, 200, 100));
8678 rightSpy->setOwnerInfo(gui::Pid{2}, Uid{102});
8679 rightSpy->setSpy(true);
8680 rightSpy->setTrustedOverlay(true);
8681
8682 sp<FakeWindowHandle> rightWindow = sp<FakeWindowHandle>::make(application, mDispatcher, "Right",
8683 ui::LogicalDisplayId::DEFAULT);
8684 rightWindow->setFrame(Rect(100, 0, 200, 100));
8685 rightWindow->setOwnerInfo(gui::Pid{3}, Uid{103});
8686
8687 mDispatcher->onWindowInfosChanged(
8688 {{*rightSpy->getInfo(), *rightWindow->getInfo(), *leftWindow->getInfo()}, {}, 0, 0});
8689
8690 // Touch in the left window
8691 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
8692 .pointer(PointerBuilder(0, ToolType::FINGER).x(50).y(50))
8693 .build());
8694 ASSERT_NO_FATAL_FAILURE(leftWindow->consumeMotionDown());
8695 mDispatcher->waitForIdle();
8696 ASSERT_NO_FATAL_FAILURE(
8697 mFakePolicy->assertNotifyDeviceInteractionWasCalled(DEVICE_ID, {Uid{101}}));
8698
8699 // Touch another finger over the right windows
8700 mDispatcher->notifyMotion(MotionArgsBuilder(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
8701 .pointer(PointerBuilder(0, ToolType::FINGER).x(50).y(50))
8702 .pointer(PointerBuilder(1, ToolType::FINGER).x(150).y(50))
8703 .build());
8704 ASSERT_NO_FATAL_FAILURE(rightSpy->consumeMotionDown());
8705 ASSERT_NO_FATAL_FAILURE(rightWindow->consumeMotionDown());
8706 ASSERT_NO_FATAL_FAILURE(leftWindow->consumeMotionMove());
8707 mDispatcher->waitForIdle();
8708 ASSERT_NO_FATAL_FAILURE(
8709 mFakePolicy->assertNotifyDeviceInteractionWasCalled(DEVICE_ID,
8710 {Uid{101}, Uid{102}, Uid{103}}));
8711
8712 // Release finger over left window. The UP actions are not treated as device interaction.
8713 // The windows that did not receive the UP pointer will receive MOVE events, but since this
8714 // is part of the UP action, we do not treat this as device interaction.
8715 mDispatcher->notifyMotion(MotionArgsBuilder(POINTER_0_UP, AINPUT_SOURCE_TOUCHSCREEN)
8716 .pointer(PointerBuilder(0, ToolType::FINGER).x(50).y(50))
8717 .pointer(PointerBuilder(1, ToolType::FINGER).x(150).y(50))
8718 .build());
8719 ASSERT_NO_FATAL_FAILURE(leftWindow->consumeMotionUp());
8720 ASSERT_NO_FATAL_FAILURE(rightSpy->consumeMotionMove());
8721 ASSERT_NO_FATAL_FAILURE(rightWindow->consumeMotionMove());
8722 mDispatcher->waitForIdle();
8723 ASSERT_NO_FATAL_FAILURE(mFakePolicy->assertNotifyDeviceInteractionWasNotCalled());
8724
8725 // Move remaining finger
8726 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN)
8727 .pointer(PointerBuilder(1, ToolType::FINGER).x(150).y(50))
8728 .build());
8729 ASSERT_NO_FATAL_FAILURE(rightSpy->consumeMotionMove());
8730 ASSERT_NO_FATAL_FAILURE(rightWindow->consumeMotionMove());
8731 mDispatcher->waitForIdle();
8732 ASSERT_NO_FATAL_FAILURE(
8733 mFakePolicy->assertNotifyDeviceInteractionWasCalled(DEVICE_ID, {Uid{102}, Uid{103}}));
8734
8735 // Release all fingers
8736 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN)
8737 .pointer(PointerBuilder(1, ToolType::FINGER).x(150).y(50))
8738 .build());
8739 ASSERT_NO_FATAL_FAILURE(rightSpy->consumeMotionUp());
8740 ASSERT_NO_FATAL_FAILURE(rightWindow->consumeMotionUp());
8741 mDispatcher->waitForIdle();
8742 ASSERT_NO_FATAL_FAILURE(mFakePolicy->assertNotifyDeviceInteractionWasNotCalled());
8743 }
8744
TEST_F(InputDispatcherTest,NotifiesDeviceInteractionsWithKeys)8745 TEST_F(InputDispatcherTest, NotifiesDeviceInteractionsWithKeys) {
8746 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
8747
8748 sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher, "Window",
8749 ui::LogicalDisplayId::DEFAULT);
8750 window->setFrame(Rect(0, 0, 100, 100));
8751 window->setOwnerInfo(gui::Pid{1}, gui::Uid{101});
8752
8753 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
8754 setFocusedWindow(window);
8755 ASSERT_NO_FATAL_FAILURE(window->consumeFocusEvent(true));
8756
8757 mDispatcher->notifyKey(KeyArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_KEYBOARD).build());
8758 ASSERT_NO_FATAL_FAILURE(window->consumeKeyDown(ui::LogicalDisplayId::DEFAULT));
8759 mDispatcher->waitForIdle();
8760 ASSERT_NO_FATAL_FAILURE(
8761 mFakePolicy->assertNotifyDeviceInteractionWasCalled(DEVICE_ID, {gui::Uid{101}}));
8762
8763 // The UP actions are not treated as device interaction.
8764 mDispatcher->notifyKey(KeyArgsBuilder(ACTION_UP, AINPUT_SOURCE_KEYBOARD).build());
8765 ASSERT_NO_FATAL_FAILURE(window->consumeKeyUp(ui::LogicalDisplayId::DEFAULT));
8766 mDispatcher->waitForIdle();
8767 ASSERT_NO_FATAL_FAILURE(mFakePolicy->assertNotifyDeviceInteractionWasNotCalled());
8768 }
8769
TEST_F(InputDispatcherTest,HoverEnterExitSynthesisUsesNewEventId)8770 TEST_F(InputDispatcherTest, HoverEnterExitSynthesisUsesNewEventId) {
8771 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
8772
8773 sp<FakeWindowHandle> left = sp<FakeWindowHandle>::make(application, mDispatcher, "Left Window",
8774 ui::LogicalDisplayId::DEFAULT);
8775 left->setFrame(Rect(0, 0, 100, 100));
8776 sp<FakeWindowHandle> right =
8777 sp<FakeWindowHandle>::make(application, mDispatcher, "Right Window",
8778 ui::LogicalDisplayId::DEFAULT);
8779 right->setFrame(Rect(100, 0, 200, 100));
8780 sp<FakeWindowHandle> spy = sp<FakeWindowHandle>::make(application, mDispatcher, "Spy Window",
8781 ui::LogicalDisplayId::DEFAULT);
8782 spy->setFrame(Rect(0, 0, 200, 100));
8783 spy->setTrustedOverlay(true);
8784 spy->setSpy(true);
8785
8786 mDispatcher->onWindowInfosChanged(
8787 {{*spy->getInfo(), *left->getInfo(), *right->getInfo()}, {}, 0, 0});
8788
8789 // Send hover move to the left window, and ensure hover enter is synthesized with a new eventId.
8790 NotifyMotionArgs notifyArgs =
8791 generateMotionArgs(ACTION_HOVER_MOVE, AINPUT_SOURCE_STYLUS,
8792 ui::LogicalDisplayId::DEFAULT, {PointF{50, 50}});
8793 mDispatcher->notifyMotion(notifyArgs);
8794
8795 std::unique_ptr<MotionEvent> leftEnter = left->consumeMotionEvent(
8796 AllOf(WithMotionAction(ACTION_HOVER_ENTER), Not(WithEventId(notifyArgs.id)),
8797 WithEventIdSource(IdGenerator::Source::INPUT_DISPATCHER)));
8798 ASSERT_NE(nullptr, leftEnter);
8799 spy->consumeMotionEvent(AllOf(WithMotionAction(ACTION_HOVER_ENTER),
8800 Not(WithEventId(notifyArgs.id)),
8801 Not(WithEventId(leftEnter->getId())),
8802 WithEventIdSource(IdGenerator::Source::INPUT_DISPATCHER)));
8803
8804 // Send move to the right window, and ensure hover exit and enter are synthesized with new ids.
8805 notifyArgs = generateMotionArgs(ACTION_HOVER_MOVE, AINPUT_SOURCE_STYLUS,
8806 ui::LogicalDisplayId::DEFAULT, {PointF{150, 50}});
8807 mDispatcher->notifyMotion(notifyArgs);
8808
8809 std::unique_ptr<MotionEvent> leftExit = left->consumeMotionEvent(
8810 AllOf(WithMotionAction(ACTION_HOVER_EXIT), Not(WithEventId(notifyArgs.id)),
8811 WithEventIdSource(IdGenerator::Source::INPUT_DISPATCHER)));
8812 ASSERT_NE(nullptr, leftExit);
8813 right->consumeMotionEvent(AllOf(WithMotionAction(ACTION_HOVER_ENTER),
8814 Not(WithEventId(notifyArgs.id)),
8815 Not(WithEventId(leftExit->getId())),
8816 WithEventIdSource(IdGenerator::Source::INPUT_DISPATCHER)));
8817
8818 spy->consumeMotionEvent(AllOf(WithMotionAction(ACTION_HOVER_MOVE), WithEventId(notifyArgs.id)));
8819 }
8820
8821 /**
8822 * When a device reports a DOWN event, which lands in a window that supports splits, and then the
8823 * device then reports a POINTER_DOWN, which lands in the location of a non-existing window, then
8824 * the previous window should receive this event and not be dropped.
8825 */
TEST_F(InputDispatcherMultiDeviceTest,SingleDevicePointerDownEventRetentionWithoutWindowTarget)8826 TEST_F(InputDispatcherMultiDeviceTest, SingleDevicePointerDownEventRetentionWithoutWindowTarget) {
8827 SCOPED_FLAG_OVERRIDE(split_all_touches, false);
8828 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
8829 sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher, "Window",
8830 ui::LogicalDisplayId::DEFAULT);
8831 window->setFrame(Rect(0, 0, 100, 100));
8832 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
8833
8834 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
8835 .pointer(PointerBuilder(0, ToolType::FINGER).x(50).y(50))
8836 .build());
8837
8838 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN)));
8839
8840 mDispatcher->notifyMotion(MotionArgsBuilder(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
8841 .pointer(PointerBuilder(0, ToolType::FINGER).x(50).y(50))
8842 .pointer(PointerBuilder(1, ToolType::FINGER).x(200).y(200))
8843 .build());
8844
8845 window->consumeMotionEvent(AllOf(WithMotionAction(POINTER_1_DOWN)));
8846 }
8847
8848 /**
8849 * When deviceA reports a DOWN event, which lands in a window that supports splits, and then deviceB
8850 * also reports a DOWN event, which lands in the location of a non-existing window, then the
8851 * previous window should receive deviceB's event and it should be dropped.
8852 */
TEST_F(InputDispatcherMultiDeviceTest,SecondDeviceDownEventDroppedWithoutWindowTarget)8853 TEST_F(InputDispatcherMultiDeviceTest, SecondDeviceDownEventDroppedWithoutWindowTarget) {
8854 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
8855 sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher, "Window",
8856 ui::LogicalDisplayId::DEFAULT);
8857 window->setFrame(Rect(0, 0, 100, 100));
8858 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
8859
8860 const DeviceId deviceA = 9;
8861 const DeviceId deviceB = 3;
8862
8863 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
8864 .pointer(PointerBuilder(0, ToolType::FINGER).x(50).y(50))
8865 .deviceId(deviceA)
8866 .build());
8867 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(deviceA)));
8868
8869 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
8870 .pointer(PointerBuilder(0, ToolType::FINGER).x(200).y(200))
8871 .deviceId(deviceB)
8872 .build());
8873 window->assertNoEvents();
8874 }
8875
8876 class InputDispatcherFallbackKeyTest : public InputDispatcherTest {
8877 protected:
8878 std::shared_ptr<FakeApplicationHandle> mApp;
8879 sp<FakeWindowHandle> mWindow;
8880
SetUp()8881 virtual void SetUp() override {
8882 InputDispatcherTest::SetUp();
8883
8884 mApp = std::make_shared<FakeApplicationHandle>();
8885
8886 mWindow = sp<FakeWindowHandle>::make(mApp, mDispatcher, "Window",
8887 ui::LogicalDisplayId::DEFAULT);
8888 mWindow->setFrame(Rect(0, 0, 100, 100));
8889
8890 mDispatcher->onWindowInfosChanged({{*mWindow->getInfo()}, {}, 0, 0});
8891 setFocusedWindow(mWindow);
8892 ASSERT_NO_FATAL_FAILURE(mWindow->consumeFocusEvent(/*hasFocus=*/true));
8893 }
8894
setFallback(int32_t keycode)8895 void setFallback(int32_t keycode) {
8896 mFakePolicy->setUnhandledKeyHandler([keycode](const KeyEvent& event) {
8897 return KeyEventBuilder(event).keyCode(keycode).build();
8898 });
8899 }
8900
consumeKey(bool handled,const::testing::Matcher<KeyEvent> & matcher)8901 void consumeKey(bool handled, const ::testing::Matcher<KeyEvent>& matcher) {
8902 std::unique_ptr<KeyEvent> event = mWindow->consumeKey(handled);
8903 ASSERT_NE(nullptr, event);
8904 ASSERT_THAT(*event, matcher);
8905 }
8906 };
8907
TEST_F(InputDispatcherFallbackKeyTest,PolicyNotNotifiedForHandledKey)8908 TEST_F(InputDispatcherFallbackKeyTest, PolicyNotNotifiedForHandledKey) {
8909 mDispatcher->notifyKey(
8910 KeyArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_KEYBOARD).keyCode(AKEYCODE_A).build());
8911 consumeKey(/*handled=*/true, AllOf(WithKeyAction(ACTION_DOWN), WithKeyCode(AKEYCODE_A)));
8912 ASSERT_NO_FATAL_FAILURE(mFakePolicy->assertUnhandledKeyNotReported());
8913 }
8914
TEST_F(InputDispatcherFallbackKeyTest,PolicyNotifiedForUnhandledKey)8915 TEST_F(InputDispatcherFallbackKeyTest, PolicyNotifiedForUnhandledKey) {
8916 mDispatcher->notifyKey(
8917 KeyArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_KEYBOARD).keyCode(AKEYCODE_A).build());
8918 consumeKey(/*handled=*/false, AllOf(WithKeyAction(ACTION_DOWN), WithKeyCode(AKEYCODE_A)));
8919 ASSERT_NO_FATAL_FAILURE(mFakePolicy->assertUnhandledKeyReported(AKEYCODE_A));
8920 }
8921
TEST_F(InputDispatcherFallbackKeyTest,NoFallbackRequestedByPolicy)8922 TEST_F(InputDispatcherFallbackKeyTest, NoFallbackRequestedByPolicy) {
8923 mDispatcher->notifyKey(
8924 KeyArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_KEYBOARD).keyCode(AKEYCODE_A).build());
8925
8926 // Do not handle this key event.
8927 consumeKey(/*handled=*/false,
8928 AllOf(WithKeyAction(ACTION_DOWN), WithKeyCode(AKEYCODE_A), WithFlags(0)));
8929 ASSERT_NO_FATAL_FAILURE(mFakePolicy->assertUnhandledKeyReported(AKEYCODE_A));
8930
8931 // Since the policy did not request any fallback to be generated, ensure there are no events.
8932 ASSERT_NO_FATAL_FAILURE(mFakePolicy->assertUnhandledKeyNotReported());
8933 }
8934
TEST_F(InputDispatcherFallbackKeyTest,FallbackDispatchForUnhandledKey)8935 TEST_F(InputDispatcherFallbackKeyTest, FallbackDispatchForUnhandledKey) {
8936 setFallback(AKEYCODE_B);
8937 mDispatcher->notifyKey(
8938 KeyArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_KEYBOARD).keyCode(AKEYCODE_A).build());
8939
8940 // Do not handle this key event.
8941 consumeKey(/*handled=*/false,
8942 AllOf(WithKeyAction(ACTION_DOWN), WithKeyCode(AKEYCODE_A), WithFlags(0)));
8943
8944 // Since the key was not handled, ensure the fallback event was dispatched instead.
8945 ASSERT_NO_FATAL_FAILURE(mFakePolicy->assertUnhandledKeyReported(AKEYCODE_A));
8946 consumeKey(/*handled=*/true,
8947 AllOf(WithKeyAction(ACTION_DOWN), WithKeyCode(AKEYCODE_B),
8948 WithFlags(AKEY_EVENT_FLAG_FALLBACK)));
8949
8950 // Release the original key, and ensure the fallback key is also released.
8951 mDispatcher->notifyKey(
8952 KeyArgsBuilder(ACTION_UP, AINPUT_SOURCE_KEYBOARD).keyCode(AKEYCODE_A).build());
8953 consumeKey(/*handled=*/false,
8954 AllOf(WithKeyAction(ACTION_UP), WithKeyCode(AKEYCODE_A), WithFlags(0)));
8955 ASSERT_NO_FATAL_FAILURE(mFakePolicy->assertUnhandledKeyReported(AKEYCODE_A));
8956 consumeKey(/*handled=*/true,
8957 AllOf(WithKeyAction(ACTION_UP), WithKeyCode(AKEYCODE_B),
8958 WithFlags(AKEY_EVENT_FLAG_FALLBACK)));
8959
8960 ASSERT_NO_FATAL_FAILURE(mFakePolicy->assertUnhandledKeyNotReported());
8961 mWindow->assertNoEvents();
8962 }
8963
TEST_F(InputDispatcherFallbackKeyTest,AppHandlesPreviouslyUnhandledKey)8964 TEST_F(InputDispatcherFallbackKeyTest, AppHandlesPreviouslyUnhandledKey) {
8965 setFallback(AKEYCODE_B);
8966 mDispatcher->notifyKey(
8967 KeyArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_KEYBOARD).keyCode(AKEYCODE_A).build());
8968
8969 // Do not handle this key event, but handle the fallback.
8970 consumeKey(/*handled=*/false,
8971 AllOf(WithKeyAction(ACTION_DOWN), WithKeyCode(AKEYCODE_A), WithFlags(0)));
8972 ASSERT_NO_FATAL_FAILURE(mFakePolicy->assertUnhandledKeyReported(AKEYCODE_A));
8973 consumeKey(/*handled=*/true,
8974 AllOf(WithKeyAction(ACTION_DOWN), WithKeyCode(AKEYCODE_B),
8975 WithFlags(AKEY_EVENT_FLAG_FALLBACK)));
8976
8977 // Release the original key, and ensure the fallback key is also released.
8978 mDispatcher->notifyKey(
8979 KeyArgsBuilder(ACTION_UP, AINPUT_SOURCE_KEYBOARD).keyCode(AKEYCODE_A).build());
8980 // But this time, the app handles the original key.
8981 consumeKey(/*handled=*/true,
8982 AllOf(WithKeyAction(ACTION_UP), WithKeyCode(AKEYCODE_A), WithFlags(0)));
8983 ASSERT_NO_FATAL_FAILURE(mFakePolicy->assertUnhandledKeyReported(AKEYCODE_A));
8984 // Ensure the fallback key is canceled.
8985 consumeKey(/*handled=*/true,
8986 AllOf(WithKeyAction(ACTION_UP), WithKeyCode(AKEYCODE_B),
8987 WithFlags(AKEY_EVENT_FLAG_FALLBACK | AKEY_EVENT_FLAG_CANCELED)));
8988
8989 ASSERT_NO_FATAL_FAILURE(mFakePolicy->assertUnhandledKeyNotReported());
8990 mWindow->assertNoEvents();
8991 }
8992
TEST_F(InputDispatcherFallbackKeyTest,AppDoesNotHandleFallback)8993 TEST_F(InputDispatcherFallbackKeyTest, AppDoesNotHandleFallback) {
8994 setFallback(AKEYCODE_B);
8995 mDispatcher->notifyKey(
8996 KeyArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_KEYBOARD).keyCode(AKEYCODE_A).build());
8997
8998 // Do not handle this key event.
8999 consumeKey(/*handled=*/false,
9000 AllOf(WithKeyAction(ACTION_DOWN), WithKeyCode(AKEYCODE_A), WithFlags(0)));
9001 ASSERT_NO_FATAL_FAILURE(mFakePolicy->assertUnhandledKeyReported(AKEYCODE_A));
9002 // App does not handle the fallback either, so ensure another fallback is not generated.
9003 setFallback(AKEYCODE_C);
9004 consumeKey(/*handled=*/false,
9005 AllOf(WithKeyAction(ACTION_DOWN), WithKeyCode(AKEYCODE_B),
9006 WithFlags(AKEY_EVENT_FLAG_FALLBACK)));
9007
9008 // Release the original key, and ensure the fallback key is also released.
9009 setFallback(AKEYCODE_B);
9010 mDispatcher->notifyKey(
9011 KeyArgsBuilder(ACTION_UP, AINPUT_SOURCE_KEYBOARD).keyCode(AKEYCODE_A).build());
9012 consumeKey(/*handled=*/false,
9013 AllOf(WithKeyAction(ACTION_UP), WithKeyCode(AKEYCODE_A), WithFlags(0)));
9014 ASSERT_NO_FATAL_FAILURE(mFakePolicy->assertUnhandledKeyReported(AKEYCODE_A));
9015 consumeKey(/*handled=*/false,
9016 AllOf(WithKeyAction(ACTION_UP), WithKeyCode(AKEYCODE_B),
9017 WithFlags(AKEY_EVENT_FLAG_FALLBACK)));
9018
9019 ASSERT_NO_FATAL_FAILURE(mFakePolicy->assertUnhandledKeyNotReported());
9020 mWindow->assertNoEvents();
9021 }
9022
TEST_F(InputDispatcherFallbackKeyTest,InconsistentPolicyCancelsFallback)9023 TEST_F(InputDispatcherFallbackKeyTest, InconsistentPolicyCancelsFallback) {
9024 setFallback(AKEYCODE_B);
9025 mDispatcher->notifyKey(
9026 KeyArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_KEYBOARD).keyCode(AKEYCODE_A).build());
9027
9028 // Do not handle this key event, so fallback is generated.
9029 consumeKey(/*handled=*/false,
9030 AllOf(WithKeyAction(ACTION_DOWN), WithKeyCode(AKEYCODE_A), WithFlags(0)));
9031 ASSERT_NO_FATAL_FAILURE(mFakePolicy->assertUnhandledKeyReported(AKEYCODE_A));
9032 consumeKey(/*handled=*/true,
9033 AllOf(WithKeyAction(ACTION_DOWN), WithKeyCode(AKEYCODE_B),
9034 WithFlags(AKEY_EVENT_FLAG_FALLBACK)));
9035
9036 // Release the original key, but assume the policy is misbehaving and it
9037 // generates an inconsistent fallback to the one from the DOWN event.
9038 setFallback(AKEYCODE_C);
9039 mDispatcher->notifyKey(
9040 KeyArgsBuilder(ACTION_UP, AINPUT_SOURCE_KEYBOARD).keyCode(AKEYCODE_A).build());
9041 consumeKey(/*handled=*/false,
9042 AllOf(WithKeyAction(ACTION_UP), WithKeyCode(AKEYCODE_A), WithFlags(0)));
9043 ASSERT_NO_FATAL_FAILURE(mFakePolicy->assertUnhandledKeyReported(AKEYCODE_A));
9044 // Ensure the fallback key reported before as DOWN is canceled due to the inconsistency.
9045 consumeKey(/*handled=*/true,
9046 AllOf(WithKeyAction(ACTION_UP), WithKeyCode(AKEYCODE_B),
9047 WithFlags(AKEY_EVENT_FLAG_FALLBACK | AKEY_EVENT_FLAG_CANCELED)));
9048
9049 ASSERT_NO_FATAL_FAILURE(mFakePolicy->assertUnhandledKeyNotReported());
9050 mWindow->assertNoEvents();
9051 }
9052
TEST_F(InputDispatcherFallbackKeyTest,CanceledKeyCancelsFallback)9053 TEST_F(InputDispatcherFallbackKeyTest, CanceledKeyCancelsFallback) {
9054 setFallback(AKEYCODE_B);
9055 mDispatcher->notifyKey(
9056 KeyArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_KEYBOARD).keyCode(AKEYCODE_A).build());
9057
9058 // Do not handle this key event, so fallback is generated.
9059 consumeKey(/*handled=*/false,
9060 AllOf(WithKeyAction(ACTION_DOWN), WithKeyCode(AKEYCODE_A), WithFlags(0)));
9061 ASSERT_NO_FATAL_FAILURE(mFakePolicy->assertUnhandledKeyReported(AKEYCODE_A));
9062 consumeKey(/*handled=*/true,
9063 AllOf(WithKeyAction(ACTION_DOWN), WithKeyCode(AKEYCODE_B),
9064 WithFlags(AKEY_EVENT_FLAG_FALLBACK)));
9065
9066 // The original key is canceled.
9067 mDispatcher->notifyKey(KeyArgsBuilder(ACTION_UP, AINPUT_SOURCE_KEYBOARD)
9068 .keyCode(AKEYCODE_A)
9069 .addFlag(AKEY_EVENT_FLAG_CANCELED)
9070 .build());
9071 consumeKey(/*handled=*/false,
9072 AllOf(WithKeyAction(ACTION_UP), WithKeyCode(AKEYCODE_A),
9073 WithFlags(AKEY_EVENT_FLAG_CANCELED)));
9074 ASSERT_NO_FATAL_FAILURE(mFakePolicy->assertUnhandledKeyReported(AKEYCODE_A));
9075 // Ensure the fallback key is also canceled due to the original key being canceled.
9076 consumeKey(/*handled=*/true,
9077 AllOf(WithKeyAction(ACTION_UP), WithKeyCode(AKEYCODE_B),
9078 WithFlags(AKEY_EVENT_FLAG_FALLBACK | AKEY_EVENT_FLAG_CANCELED)));
9079
9080 ASSERT_NO_FATAL_FAILURE(mFakePolicy->assertUnhandledKeyNotReported());
9081 mWindow->assertNoEvents();
9082 }
9083
TEST_F(InputDispatcherFallbackKeyTest,InputChannelRemovedDuringPolicyCall)9084 TEST_F(InputDispatcherFallbackKeyTest, InputChannelRemovedDuringPolicyCall) {
9085 setFallback(AKEYCODE_B);
9086 mDispatcher->notifyKey(
9087 KeyArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_KEYBOARD).keyCode(AKEYCODE_A).build());
9088
9089 // Do not handle this key event.
9090 consumeKey(/*handled=*/false,
9091 AllOf(WithKeyAction(ACTION_DOWN), WithKeyCode(AKEYCODE_A), WithFlags(0)));
9092 ASSERT_NO_FATAL_FAILURE(mFakePolicy->assertUnhandledKeyReported(AKEYCODE_A));
9093 consumeKey(/*handled=*/true,
9094 AllOf(WithKeyAction(ACTION_DOWN), WithKeyCode(AKEYCODE_B),
9095 WithFlags(AKEY_EVENT_FLAG_FALLBACK)));
9096
9097 mFakePolicy->setUnhandledKeyHandler([&](const KeyEvent& event) {
9098 // When the unhandled key is reported to the policy next, remove the input channel.
9099 mDispatcher->removeInputChannel(mWindow->getToken());
9100 return KeyEventBuilder(event).keyCode(AKEYCODE_B).build();
9101 });
9102 // Release the original key, and let the app now handle the previously unhandled key.
9103 // This should result in the previously generated fallback key to be cancelled.
9104 // Since the policy was notified of the unhandled DOWN event earlier, it will also be notified
9105 // of the UP event for consistency. The Dispatcher calls into the policy from its own thread
9106 // without holding the lock, because it need to synchronously fetch the fallback key. While in
9107 // the policy call, we will now remove the input channel. Once the policy call returns, the
9108 // Dispatcher will no longer have a channel to send cancellation events to. Ensure this does
9109 // not cause any crashes.
9110 mDispatcher->notifyKey(
9111 KeyArgsBuilder(ACTION_UP, AINPUT_SOURCE_KEYBOARD).keyCode(AKEYCODE_A).build());
9112 consumeKey(/*handled=*/true,
9113 AllOf(WithKeyAction(ACTION_UP), WithKeyCode(AKEYCODE_A), WithFlags(0)));
9114 ASSERT_NO_FATAL_FAILURE(mFakePolicy->assertUnhandledKeyReported(AKEYCODE_A));
9115 }
9116
TEST_F(InputDispatcherFallbackKeyTest,WindowRemovedDuringPolicyCall)9117 TEST_F(InputDispatcherFallbackKeyTest, WindowRemovedDuringPolicyCall) {
9118 setFallback(AKEYCODE_B);
9119 mDispatcher->notifyKey(
9120 KeyArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_KEYBOARD).keyCode(AKEYCODE_A).build());
9121
9122 // Do not handle this key event.
9123 consumeKey(/*handled=*/false,
9124 AllOf(WithKeyAction(ACTION_DOWN), WithKeyCode(AKEYCODE_A), WithFlags(0)));
9125 ASSERT_NO_FATAL_FAILURE(mFakePolicy->assertUnhandledKeyReported(AKEYCODE_A));
9126 consumeKey(/*handled=*/true,
9127 AllOf(WithKeyAction(ACTION_DOWN), WithKeyCode(AKEYCODE_B),
9128 WithFlags(AKEY_EVENT_FLAG_FALLBACK)));
9129
9130 mFakePolicy->setUnhandledKeyHandler([&](const KeyEvent& event) {
9131 // When the unhandled key is reported to the policy next, remove the window.
9132 mDispatcher->onWindowInfosChanged({{}, {}, 0, 0});
9133 return KeyEventBuilder(event).keyCode(AKEYCODE_B).build();
9134 });
9135 // Release the original key, which the app will not handle. When this unhandled key is reported
9136 // to the policy, the window will be removed.
9137 mDispatcher->notifyKey(
9138 KeyArgsBuilder(ACTION_UP, AINPUT_SOURCE_KEYBOARD).keyCode(AKEYCODE_A).build());
9139 consumeKey(/*handled=*/false,
9140 AllOf(WithKeyAction(ACTION_UP), WithKeyCode(AKEYCODE_A), WithFlags(0)));
9141 ASSERT_NO_FATAL_FAILURE(mFakePolicy->assertUnhandledKeyReported(AKEYCODE_A));
9142
9143 // Since the window was removed, it loses focus, and the channel state will be reset.
9144 consumeKey(/*handled=*/true,
9145 AllOf(WithKeyAction(ACTION_UP), WithKeyCode(AKEYCODE_B),
9146 WithFlags(AKEY_EVENT_FLAG_FALLBACK | AKEY_EVENT_FLAG_CANCELED)));
9147 mWindow->consumeFocusEvent(false);
9148 mWindow->assertNoEvents();
9149 }
9150
TEST_F(InputDispatcherFallbackKeyTest,WindowRemovedWhileAwaitingFinishedSignal)9151 TEST_F(InputDispatcherFallbackKeyTest, WindowRemovedWhileAwaitingFinishedSignal) {
9152 setFallback(AKEYCODE_B);
9153 mDispatcher->notifyKey(
9154 KeyArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_KEYBOARD).keyCode(AKEYCODE_A).build());
9155
9156 // Do not handle this key event.
9157 consumeKey(/*handled=*/false,
9158 AllOf(WithKeyAction(ACTION_DOWN), WithKeyCode(AKEYCODE_A), WithFlags(0)));
9159 ASSERT_NO_FATAL_FAILURE(mFakePolicy->assertUnhandledKeyReported(AKEYCODE_A));
9160 const auto [seq, event] = mWindow->receiveEvent();
9161 ASSERT_TRUE(seq.has_value() && event != nullptr) << "Failed to receive fallback event";
9162 ASSERT_EQ(event->getType(), InputEventType::KEY);
9163 ASSERT_THAT(static_cast<const KeyEvent&>(*event),
9164 AllOf(WithKeyAction(ACTION_DOWN), WithKeyCode(AKEYCODE_B),
9165 WithFlags(AKEY_EVENT_FLAG_FALLBACK)));
9166
9167 // Remove the window now, which should generate a cancellations and make the window lose focus.
9168 mDispatcher->onWindowInfosChanged({{}, {}, 0, 0});
9169 consumeKey(/*handled=*/true,
9170 AllOf(WithKeyAction(ACTION_UP), WithKeyCode(AKEYCODE_A),
9171 WithFlags(AKEY_EVENT_FLAG_CANCELED)));
9172 consumeKey(/*handled=*/true,
9173 AllOf(WithKeyAction(ACTION_UP), WithKeyCode(AKEYCODE_B),
9174 WithFlags(AKEY_EVENT_FLAG_FALLBACK | AKEY_EVENT_FLAG_CANCELED)));
9175 mWindow->consumeFocusEvent(false);
9176
9177 // Finish the event by reporting it as handled.
9178 mWindow->finishEvent(*seq);
9179 mWindow->assertNoEvents();
9180 }
9181
9182 class InputDispatcherKeyRepeatTest : public InputDispatcherTest {
9183 protected:
9184 static constexpr std::chrono::nanoseconds KEY_REPEAT_TIMEOUT = 40ms;
9185 static constexpr std::chrono::nanoseconds KEY_REPEAT_DELAY = 40ms;
9186 static constexpr bool KEY_REPEAT_ENABLED = true;
9187
9188 std::shared_ptr<FakeApplicationHandle> mApp;
9189 sp<FakeWindowHandle> mWindow;
9190
SetUp()9191 virtual void SetUp() override {
9192 InputDispatcherTest::SetUp();
9193
9194 mDispatcher->setKeyRepeatConfiguration(KEY_REPEAT_TIMEOUT, KEY_REPEAT_DELAY,
9195 KEY_REPEAT_ENABLED);
9196 setUpWindow();
9197 }
9198
setUpWindow()9199 void setUpWindow() {
9200 mApp = std::make_shared<FakeApplicationHandle>();
9201 mWindow = sp<FakeWindowHandle>::make(mApp, mDispatcher, "Fake Window",
9202 ui::LogicalDisplayId::DEFAULT);
9203
9204 mWindow->setFocusable(true);
9205 mDispatcher->onWindowInfosChanged({{*mWindow->getInfo()}, {}, 0, 0});
9206 setFocusedWindow(mWindow);
9207 mWindow->consumeFocusEvent(true);
9208 }
9209
sendAndConsumeKeyDown(int32_t deviceId)9210 void sendAndConsumeKeyDown(int32_t deviceId) {
9211 NotifyKeyArgs keyArgs =
9212 generateKeyArgs(AKEY_EVENT_ACTION_DOWN, ui::LogicalDisplayId::DEFAULT);
9213 keyArgs.deviceId = deviceId;
9214 keyArgs.policyFlags |= POLICY_FLAG_TRUSTED; // Otherwise it won't generate repeat event
9215 mDispatcher->notifyKey(keyArgs);
9216
9217 // Window should receive key down event.
9218 mWindow->consumeKeyDown(ui::LogicalDisplayId::DEFAULT);
9219 }
9220
expectKeyRepeatOnce(int32_t repeatCount)9221 void expectKeyRepeatOnce(int32_t repeatCount) {
9222 SCOPED_TRACE(StringPrintf("Checking event with repeat count %" PRId32, repeatCount));
9223 mWindow->consumeKeyEvent(
9224 AllOf(WithKeyAction(AKEY_EVENT_ACTION_DOWN), WithRepeatCount(repeatCount)));
9225 }
9226
sendAndConsumeKeyUp(int32_t deviceId)9227 void sendAndConsumeKeyUp(int32_t deviceId) {
9228 NotifyKeyArgs keyArgs =
9229 generateKeyArgs(AKEY_EVENT_ACTION_UP, ui::LogicalDisplayId::DEFAULT);
9230 keyArgs.deviceId = deviceId;
9231 keyArgs.policyFlags |= POLICY_FLAG_TRUSTED; // Unless it won't generate repeat event
9232 mDispatcher->notifyKey(keyArgs);
9233
9234 // Window should receive key down event.
9235 mWindow->consumeKeyUp(ui::LogicalDisplayId::DEFAULT,
9236 /*expectedFlags=*/0);
9237 }
9238
injectKeyRepeat(int32_t repeatCount)9239 void injectKeyRepeat(int32_t repeatCount) {
9240 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
9241 injectKey(*mDispatcher, AKEY_EVENT_ACTION_DOWN, repeatCount,
9242 ui::LogicalDisplayId::DEFAULT))
9243 << "Inject key event should return InputEventInjectionResult::SUCCEEDED";
9244 }
9245 };
9246
TEST_F(InputDispatcherKeyRepeatTest,FocusedWindow_ReceivesKeyRepeat)9247 TEST_F(InputDispatcherKeyRepeatTest, FocusedWindow_ReceivesKeyRepeat) {
9248 sendAndConsumeKeyDown(/*deviceId=*/1);
9249 for (int32_t repeatCount = 1; repeatCount <= 10; ++repeatCount) {
9250 expectKeyRepeatOnce(repeatCount);
9251 }
9252 }
9253
TEST_F(InputDispatcherKeyRepeatTest,FocusedWindow_ReceivesKeyRepeatFromTwoDevices)9254 TEST_F(InputDispatcherKeyRepeatTest, FocusedWindow_ReceivesKeyRepeatFromTwoDevices) {
9255 sendAndConsumeKeyDown(/*deviceId=*/1);
9256 for (int32_t repeatCount = 1; repeatCount <= 10; ++repeatCount) {
9257 expectKeyRepeatOnce(repeatCount);
9258 }
9259 sendAndConsumeKeyDown(/*deviceId=*/2);
9260 /* repeatCount will start from 1 for deviceId 2 */
9261 for (int32_t repeatCount = 1; repeatCount <= 10; ++repeatCount) {
9262 expectKeyRepeatOnce(repeatCount);
9263 }
9264 }
9265
TEST_F(InputDispatcherKeyRepeatTest,FocusedWindow_StopsKeyRepeatAfterUp)9266 TEST_F(InputDispatcherKeyRepeatTest, FocusedWindow_StopsKeyRepeatAfterUp) {
9267 sendAndConsumeKeyDown(/*deviceId=*/1);
9268 expectKeyRepeatOnce(/*repeatCount=*/1);
9269 sendAndConsumeKeyUp(/*deviceId=*/1);
9270 mWindow->assertNoEvents();
9271 }
9272
TEST_F(InputDispatcherKeyRepeatTest,FocusedWindow_KeyRepeatAfterStaleDeviceKeyUp)9273 TEST_F(InputDispatcherKeyRepeatTest, FocusedWindow_KeyRepeatAfterStaleDeviceKeyUp) {
9274 sendAndConsumeKeyDown(/*deviceId=*/1);
9275 expectKeyRepeatOnce(/*repeatCount=*/1);
9276 sendAndConsumeKeyDown(/*deviceId=*/2);
9277 expectKeyRepeatOnce(/*repeatCount=*/1);
9278 // Stale key up from device 1.
9279 sendAndConsumeKeyUp(/*deviceId=*/1);
9280 // Device 2 is still down, keep repeating
9281 expectKeyRepeatOnce(/*repeatCount=*/2);
9282 expectKeyRepeatOnce(/*repeatCount=*/3);
9283 // Device 2 key up
9284 sendAndConsumeKeyUp(/*deviceId=*/2);
9285 mWindow->assertNoEvents();
9286 }
9287
TEST_F(InputDispatcherKeyRepeatTest,FocusedWindow_KeyRepeatStopsAfterRepeatingKeyUp)9288 TEST_F(InputDispatcherKeyRepeatTest, FocusedWindow_KeyRepeatStopsAfterRepeatingKeyUp) {
9289 sendAndConsumeKeyDown(/*deviceId=*/1);
9290 expectKeyRepeatOnce(/*repeatCount=*/1);
9291 sendAndConsumeKeyDown(/*deviceId=*/2);
9292 expectKeyRepeatOnce(/*repeatCount=*/1);
9293 // Device 2 which holds the key repeating goes up, expect the repeating to stop.
9294 sendAndConsumeKeyUp(/*deviceId=*/2);
9295 // Device 1 still holds key down, but the repeating was already stopped
9296 mWindow->assertNoEvents();
9297 }
9298
TEST_F(InputDispatcherKeyRepeatTest,FocusedWindow_StopsKeyRepeatAfterDisableInputDevice)9299 TEST_F(InputDispatcherKeyRepeatTest, FocusedWindow_StopsKeyRepeatAfterDisableInputDevice) {
9300 sendAndConsumeKeyDown(DEVICE_ID);
9301 expectKeyRepeatOnce(/*repeatCount=*/1);
9302 mDispatcher->notifyDeviceReset({/*id=*/10, /*eventTime=*/20, DEVICE_ID});
9303 mWindow->consumeKeyUp(ui::LogicalDisplayId::DEFAULT,
9304 AKEY_EVENT_FLAG_CANCELED | AKEY_EVENT_FLAG_LONG_PRESS);
9305 mWindow->assertNoEvents();
9306 }
9307
TEST_F(InputDispatcherKeyRepeatTest,FocusedWindow_RepeatKeyEventsUseEventIdFromInputDispatcher)9308 TEST_F(InputDispatcherKeyRepeatTest, FocusedWindow_RepeatKeyEventsUseEventIdFromInputDispatcher) {
9309 GTEST_SKIP() << "Flaky test (b/270393106)";
9310 sendAndConsumeKeyDown(/*deviceId=*/1);
9311 for (int32_t repeatCount = 1; repeatCount <= 10; ++repeatCount) {
9312 std::unique_ptr<KeyEvent> repeatEvent = mWindow->consumeKey();
9313 ASSERT_NE(nullptr, repeatEvent);
9314 EXPECT_EQ(IdGenerator::Source::INPUT_DISPATCHER,
9315 IdGenerator::getSource(repeatEvent->getId()));
9316 }
9317 }
9318
TEST_F(InputDispatcherKeyRepeatTest,FocusedWindow_RepeatKeyEventsUseUniqueEventId)9319 TEST_F(InputDispatcherKeyRepeatTest, FocusedWindow_RepeatKeyEventsUseUniqueEventId) {
9320 GTEST_SKIP() << "Flaky test (b/270393106)";
9321 sendAndConsumeKeyDown(/*deviceId=*/1);
9322
9323 std::unordered_set<int32_t> idSet;
9324 for (int32_t repeatCount = 1; repeatCount <= 10; ++repeatCount) {
9325 std::unique_ptr<KeyEvent> repeatEvent = mWindow->consumeKey();
9326 ASSERT_NE(nullptr, repeatEvent);
9327 int32_t id = repeatEvent->getId();
9328 EXPECT_EQ(idSet.end(), idSet.find(id));
9329 idSet.insert(id);
9330 }
9331 }
9332
TEST_F(InputDispatcherKeyRepeatTest,FocusedWindow_CorrectRepeatCountWhenInjectKeyRepeat)9333 TEST_F(InputDispatcherKeyRepeatTest, FocusedWindow_CorrectRepeatCountWhenInjectKeyRepeat) {
9334 injectKeyRepeat(0);
9335 mWindow->consumeKeyDown(ui::LogicalDisplayId::DEFAULT);
9336 for (int32_t repeatCount = 1; repeatCount <= 2; ++repeatCount) {
9337 expectKeyRepeatOnce(repeatCount);
9338 }
9339 injectKeyRepeat(1);
9340 // Expect repeatCount to be 3 instead of 1
9341 expectKeyRepeatOnce(3);
9342 }
9343
TEST_F(InputDispatcherKeyRepeatTest,FocusedWindow_NoRepeatWhenKeyRepeatDisabled)9344 TEST_F(InputDispatcherKeyRepeatTest, FocusedWindow_NoRepeatWhenKeyRepeatDisabled) {
9345 SCOPED_FLAG_OVERRIDE(keyboard_repeat_keys, true);
9346 static constexpr std::chrono::milliseconds KEY_NO_REPEAT_ASSERTION_TIMEOUT = 100ms;
9347
9348 mDispatcher->setKeyRepeatConfiguration(KEY_REPEAT_TIMEOUT, KEY_REPEAT_DELAY,
9349 /*repeatKeyEnabled=*/false);
9350 sendAndConsumeKeyDown(/*deviceId=*/1);
9351
9352 ASSERT_GT(KEY_NO_REPEAT_ASSERTION_TIMEOUT, KEY_REPEAT_TIMEOUT)
9353 << "Ensure the check for no key repeats extends beyond the repeat timeout duration.";
9354 ASSERT_GT(KEY_NO_REPEAT_ASSERTION_TIMEOUT, KEY_REPEAT_DELAY)
9355 << "Ensure the check for no key repeats extends beyond the repeat delay duration.";
9356
9357 // No events should be returned if key repeat is turned off.
9358 // Wait for KEY_NO_REPEAT_ASSERTION_TIMEOUT to return no events to ensure key repeat disabled.
9359 mWindow->assertNoEvents(KEY_NO_REPEAT_ASSERTION_TIMEOUT);
9360 }
9361
9362 /* Test InputDispatcher for MultiDisplay */
9363 class InputDispatcherFocusOnTwoDisplaysTest : public InputDispatcherTest {
9364 public:
SetUp()9365 virtual void SetUp() override {
9366 InputDispatcherTest::SetUp();
9367
9368 application1 = std::make_shared<FakeApplicationHandle>();
9369 windowInPrimary = sp<FakeWindowHandle>::make(application1, mDispatcher, "D_1",
9370 ui::LogicalDisplayId::DEFAULT);
9371
9372 // Set focus window for primary display, but focused display would be second one.
9373 mDispatcher->setFocusedApplication(ui::LogicalDisplayId::DEFAULT, application1);
9374 windowInPrimary->setFocusable(true);
9375 mDispatcher->onWindowInfosChanged({{*windowInPrimary->getInfo()}, {}, 0, 0});
9376
9377 setFocusedWindow(windowInPrimary);
9378 windowInPrimary->consumeFocusEvent(true);
9379
9380 application2 = std::make_shared<FakeApplicationHandle>();
9381 windowInSecondary =
9382 sp<FakeWindowHandle>::make(application2, mDispatcher, "D_2", SECOND_DISPLAY_ID);
9383 // Set focus to second display window.
9384 // Set focus display to second one.
9385 mDispatcher->setFocusedDisplay(SECOND_DISPLAY_ID);
9386 mFakePolicy->assertFocusedDisplayNotified(SECOND_DISPLAY_ID);
9387
9388 // Set focus window for second display.
9389 mDispatcher->setFocusedApplication(SECOND_DISPLAY_ID, application2);
9390 windowInSecondary->setFocusable(true);
9391 mDispatcher->onWindowInfosChanged(
9392 {{*windowInPrimary->getInfo(), *windowInSecondary->getInfo()}, {}, 0, 0});
9393 setFocusedWindow(windowInSecondary);
9394 windowInSecondary->consumeFocusEvent(true);
9395 }
9396
TearDown()9397 virtual void TearDown() override {
9398 InputDispatcherTest::TearDown();
9399
9400 application1.reset();
9401 windowInPrimary.clear();
9402 application2.reset();
9403 windowInSecondary.clear();
9404 }
9405
9406 protected:
9407 std::shared_ptr<FakeApplicationHandle> application1;
9408 sp<FakeWindowHandle> windowInPrimary;
9409 std::shared_ptr<FakeApplicationHandle> application2;
9410 sp<FakeWindowHandle> windowInSecondary;
9411 };
9412
TEST_F(InputDispatcherFocusOnTwoDisplaysTest,SetInputWindow_MultiDisplayTouch)9413 TEST_F(InputDispatcherFocusOnTwoDisplaysTest, SetInputWindow_MultiDisplayTouch) {
9414 // Test touch down on primary display.
9415 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
9416 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN,
9417 ui::LogicalDisplayId::DEFAULT))
9418 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
9419 windowInPrimary->consumeMotionDown(ui::LogicalDisplayId::DEFAULT);
9420 windowInSecondary->assertNoEvents();
9421
9422 // Test touch down on second display.
9423 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
9424 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, SECOND_DISPLAY_ID))
9425 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
9426 windowInPrimary->assertNoEvents();
9427 windowInSecondary->consumeMotionDown(SECOND_DISPLAY_ID);
9428 }
9429
TEST_F(InputDispatcherFocusOnTwoDisplaysTest,SetInputWindow_MultiDisplayFocus)9430 TEST_F(InputDispatcherFocusOnTwoDisplaysTest, SetInputWindow_MultiDisplayFocus) {
9431 // Test inject a key down with display id specified.
9432 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
9433 injectKeyDownNoRepeat(*mDispatcher, ui::LogicalDisplayId::DEFAULT))
9434 << "Inject key event should return InputEventInjectionResult::SUCCEEDED";
9435 windowInPrimary->consumeKeyDown(ui::LogicalDisplayId::DEFAULT);
9436 windowInSecondary->assertNoEvents();
9437
9438 // Test inject a key down without display id specified.
9439 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectKeyDownNoRepeat(*mDispatcher))
9440 << "Inject key event should return InputEventInjectionResult::SUCCEEDED";
9441 windowInPrimary->assertNoEvents();
9442 windowInSecondary->consumeKeyDown(ui::LogicalDisplayId::INVALID);
9443
9444 // Remove all windows in secondary display.
9445 mDispatcher->onWindowInfosChanged({{*windowInPrimary->getInfo()}, {}, 0, 0});
9446
9447 // Old focus should receive a cancel event.
9448 windowInSecondary->consumeKeyUp(ui::LogicalDisplayId::INVALID, AKEY_EVENT_FLAG_CANCELED);
9449
9450 // Test inject a key down, should timeout because of no target window.
9451 ASSERT_NO_FATAL_FAILURE(assertInjectedKeyTimesOut(*mDispatcher));
9452 windowInPrimary->assertNoEvents();
9453 windowInSecondary->consumeFocusEvent(false);
9454 windowInSecondary->assertNoEvents();
9455 }
9456
9457 // Test per-display input monitors for motion event.
TEST_F(InputDispatcherFocusOnTwoDisplaysTest,MonitorMotionEvent_MultiDisplay)9458 TEST_F(InputDispatcherFocusOnTwoDisplaysTest, MonitorMotionEvent_MultiDisplay) {
9459 FakeMonitorReceiver monitorInPrimary =
9460 FakeMonitorReceiver(*mDispatcher, "M_1", ui::LogicalDisplayId::DEFAULT);
9461 FakeMonitorReceiver monitorInSecondary =
9462 FakeMonitorReceiver(*mDispatcher, "M_2", SECOND_DISPLAY_ID);
9463
9464 // Test touch down on primary display.
9465 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
9466 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN,
9467 ui::LogicalDisplayId::DEFAULT))
9468 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
9469 windowInPrimary->consumeMotionDown(ui::LogicalDisplayId::DEFAULT);
9470 monitorInPrimary.consumeMotionDown(ui::LogicalDisplayId::DEFAULT);
9471 windowInSecondary->assertNoEvents();
9472 monitorInSecondary.assertNoEvents();
9473
9474 // Test touch down on second display.
9475 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
9476 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, SECOND_DISPLAY_ID))
9477 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
9478 windowInPrimary->assertNoEvents();
9479 monitorInPrimary.assertNoEvents();
9480 windowInSecondary->consumeMotionDown(SECOND_DISPLAY_ID);
9481 monitorInSecondary.consumeMotionDown(SECOND_DISPLAY_ID);
9482
9483 // Lift up the touch from the second display
9484 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
9485 injectMotionUp(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, SECOND_DISPLAY_ID))
9486 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
9487 windowInSecondary->consumeMotionUp(SECOND_DISPLAY_ID);
9488 monitorInSecondary.consumeMotionUp(SECOND_DISPLAY_ID);
9489
9490 // Test inject a non-pointer motion event.
9491 // If specific a display, it will dispatch to the focused window of particular display,
9492 // or it will dispatch to the focused window of focused display.
9493 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
9494 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TRACKBALL,
9495 ui::LogicalDisplayId::INVALID))
9496 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
9497 windowInPrimary->assertNoEvents();
9498 monitorInPrimary.assertNoEvents();
9499 windowInSecondary->consumeMotionDown(ui::LogicalDisplayId::INVALID);
9500 monitorInSecondary.consumeMotionDown(ui::LogicalDisplayId::INVALID);
9501 }
9502
9503 // Test per-display input monitors for key event.
TEST_F(InputDispatcherFocusOnTwoDisplaysTest,MonitorKeyEvent_MultiDisplay)9504 TEST_F(InputDispatcherFocusOnTwoDisplaysTest, MonitorKeyEvent_MultiDisplay) {
9505 // Input monitor per display.
9506 FakeMonitorReceiver monitorInPrimary =
9507 FakeMonitorReceiver(*mDispatcher, "M_1", ui::LogicalDisplayId::DEFAULT);
9508 FakeMonitorReceiver monitorInSecondary =
9509 FakeMonitorReceiver(*mDispatcher, "M_2", SECOND_DISPLAY_ID);
9510
9511 // Test inject a key down.
9512 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectKeyDown(*mDispatcher))
9513 << "Inject key event should return InputEventInjectionResult::SUCCEEDED";
9514 windowInPrimary->assertNoEvents();
9515 monitorInPrimary.assertNoEvents();
9516 windowInSecondary->consumeKeyDown(ui::LogicalDisplayId::INVALID);
9517 monitorInSecondary.consumeKeyDown(ui::LogicalDisplayId::INVALID);
9518 }
9519
TEST_F(InputDispatcherFocusOnTwoDisplaysTest,CanFocusWindowOnUnfocusedDisplay)9520 TEST_F(InputDispatcherFocusOnTwoDisplaysTest, CanFocusWindowOnUnfocusedDisplay) {
9521 sp<FakeWindowHandle> secondWindowInPrimary =
9522 sp<FakeWindowHandle>::make(application1, mDispatcher, "D_1_W2",
9523 ui::LogicalDisplayId::DEFAULT);
9524 secondWindowInPrimary->setFocusable(true);
9525 mDispatcher->onWindowInfosChanged(
9526 {{*windowInPrimary->getInfo(), *secondWindowInPrimary->getInfo(),
9527 *windowInSecondary->getInfo()},
9528 {},
9529 0,
9530 0});
9531 setFocusedWindow(secondWindowInPrimary);
9532 windowInPrimary->consumeFocusEvent(false);
9533 secondWindowInPrimary->consumeFocusEvent(true);
9534
9535 // Test inject a key down.
9536 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
9537 injectKeyDown(*mDispatcher, ui::LogicalDisplayId::DEFAULT))
9538 << "Inject key event should return InputEventInjectionResult::SUCCEEDED";
9539 windowInPrimary->assertNoEvents();
9540 windowInSecondary->assertNoEvents();
9541 secondWindowInPrimary->consumeKeyDown(ui::LogicalDisplayId::DEFAULT);
9542 }
9543
TEST_F(InputDispatcherFocusOnTwoDisplaysTest,CancelTouch_MultiDisplay)9544 TEST_F(InputDispatcherFocusOnTwoDisplaysTest, CancelTouch_MultiDisplay) {
9545 FakeMonitorReceiver monitorInPrimary =
9546 FakeMonitorReceiver(*mDispatcher, "M_1", ui::LogicalDisplayId::DEFAULT);
9547 FakeMonitorReceiver monitorInSecondary =
9548 FakeMonitorReceiver(*mDispatcher, "M_2", SECOND_DISPLAY_ID);
9549
9550 // Test touch down on primary display.
9551 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
9552 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN,
9553 ui::LogicalDisplayId::DEFAULT))
9554 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
9555 windowInPrimary->consumeMotionDown(ui::LogicalDisplayId::DEFAULT);
9556 monitorInPrimary.consumeMotionDown(ui::LogicalDisplayId::DEFAULT);
9557
9558 // Test touch down on second display.
9559 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
9560 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, SECOND_DISPLAY_ID))
9561 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
9562 windowInSecondary->consumeMotionDown(SECOND_DISPLAY_ID);
9563 monitorInSecondary.consumeMotionDown(SECOND_DISPLAY_ID);
9564
9565 // Trigger cancel touch.
9566 mDispatcher->cancelCurrentTouch();
9567 windowInPrimary->consumeMotionCancel(ui::LogicalDisplayId::DEFAULT);
9568 monitorInPrimary.consumeMotionCancel(ui::LogicalDisplayId::DEFAULT);
9569 windowInSecondary->consumeMotionCancel(SECOND_DISPLAY_ID);
9570 monitorInSecondary.consumeMotionCancel(SECOND_DISPLAY_ID);
9571
9572 // Test inject a move motion event, no window/monitor should receive the event.
9573 ASSERT_EQ(InputEventInjectionResult::FAILED,
9574 injectMotionEvent(*mDispatcher, AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN,
9575 ui::LogicalDisplayId::DEFAULT, {110, 200}))
9576 << "Inject motion event should return InputEventInjectionResult::FAILED";
9577 windowInPrimary->assertNoEvents();
9578 monitorInPrimary.assertNoEvents();
9579
9580 ASSERT_EQ(InputEventInjectionResult::FAILED,
9581 injectMotionEvent(*mDispatcher, AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN,
9582 SECOND_DISPLAY_ID, {110, 200}))
9583 << "Inject motion event should return InputEventInjectionResult::FAILED";
9584 windowInSecondary->assertNoEvents();
9585 monitorInSecondary.assertNoEvents();
9586 }
9587
9588 /**
9589 * Send a key to the primary display and to the secondary display.
9590 * Then cause the key on the primary display to be canceled by sending in a stale key.
9591 * Ensure that the key on the primary display is canceled, and that the key on the secondary display
9592 * does not get canceled.
9593 */
TEST_F(InputDispatcherFocusOnTwoDisplaysTest,WhenDropKeyEvent_OnlyCancelCorrespondingKeyGesture)9594 TEST_F(InputDispatcherFocusOnTwoDisplaysTest, WhenDropKeyEvent_OnlyCancelCorrespondingKeyGesture) {
9595 // Send a key down on primary display
9596 mDispatcher->notifyKey(
9597 KeyArgsBuilder(AKEY_EVENT_ACTION_DOWN, AINPUT_SOURCE_KEYBOARD)
9598 .displayId(ui::LogicalDisplayId::DEFAULT)
9599 .policyFlags(DEFAULT_POLICY_FLAGS | POLICY_FLAG_DISABLE_KEY_REPEAT)
9600 .build());
9601 windowInPrimary->consumeKeyEvent(AllOf(WithKeyAction(AKEY_EVENT_ACTION_DOWN),
9602 WithDisplayId(ui::LogicalDisplayId::DEFAULT)));
9603 windowInSecondary->assertNoEvents();
9604
9605 // Send a key down on second display
9606 mDispatcher->notifyKey(
9607 KeyArgsBuilder(AKEY_EVENT_ACTION_DOWN, AINPUT_SOURCE_KEYBOARD)
9608 .displayId(SECOND_DISPLAY_ID)
9609 .policyFlags(DEFAULT_POLICY_FLAGS | POLICY_FLAG_DISABLE_KEY_REPEAT)
9610 .build());
9611 windowInSecondary->consumeKeyEvent(
9612 AllOf(WithKeyAction(AKEY_EVENT_ACTION_DOWN), WithDisplayId(SECOND_DISPLAY_ID)));
9613 windowInPrimary->assertNoEvents();
9614
9615 // Send a valid key up event on primary display that will be dropped because it is stale
9616 NotifyKeyArgs staleKeyUp =
9617 KeyArgsBuilder(AKEY_EVENT_ACTION_UP, AINPUT_SOURCE_KEYBOARD)
9618 .displayId(ui::LogicalDisplayId::DEFAULT)
9619 .policyFlags(DEFAULT_POLICY_FLAGS | POLICY_FLAG_DISABLE_KEY_REPEAT)
9620 .build();
9621 static constexpr std::chrono::duration STALE_EVENT_TIMEOUT = 10ms;
9622 mFakePolicy->setStaleEventTimeout(STALE_EVENT_TIMEOUT);
9623 std::this_thread::sleep_for(STALE_EVENT_TIMEOUT);
9624 mDispatcher->notifyKey(staleKeyUp);
9625
9626 // Only the key gesture corresponding to the dropped event should receive the cancel event.
9627 // Therefore, windowInPrimary should get the cancel event and windowInSecondary should not
9628 // receive any events.
9629 windowInPrimary->consumeKeyEvent(AllOf(WithKeyAction(AKEY_EVENT_ACTION_UP),
9630 WithDisplayId(ui::LogicalDisplayId::DEFAULT),
9631 WithFlags(AKEY_EVENT_FLAG_CANCELED)));
9632 windowInSecondary->assertNoEvents();
9633 }
9634
9635 /**
9636 * Similar to 'WhenDropKeyEvent_OnlyCancelCorrespondingKeyGesture' but for motion events.
9637 */
TEST_F(InputDispatcherFocusOnTwoDisplaysTest,WhenDropMotionEvent_OnlyCancelCorrespondingGesture)9638 TEST_F(InputDispatcherFocusOnTwoDisplaysTest, WhenDropMotionEvent_OnlyCancelCorrespondingGesture) {
9639 // Send touch down on primary display.
9640 mDispatcher->notifyMotion(
9641 MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
9642 .pointer(PointerBuilder(/*id=*/0, ToolType::FINGER).x(100).y(200))
9643 .displayId(ui::LogicalDisplayId::DEFAULT)
9644 .build());
9645 windowInPrimary->consumeMotionEvent(
9646 AllOf(WithMotionAction(ACTION_DOWN), WithDisplayId(ui::LogicalDisplayId::DEFAULT)));
9647 windowInSecondary->assertNoEvents();
9648
9649 // Send touch down on second display.
9650 mDispatcher->notifyMotion(
9651 MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
9652 .pointer(PointerBuilder(/*id=*/0, ToolType::FINGER).x(100).y(200))
9653 .displayId(SECOND_DISPLAY_ID)
9654 .build());
9655 windowInPrimary->assertNoEvents();
9656 windowInSecondary->consumeMotionEvent(
9657 AllOf(WithMotionAction(ACTION_DOWN), WithDisplayId(SECOND_DISPLAY_ID)));
9658
9659 // inject a valid MotionEvent on primary display that will be stale when it arrives.
9660 NotifyMotionArgs staleMotionUp =
9661 MotionArgsBuilder(ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN)
9662 .displayId(ui::LogicalDisplayId::DEFAULT)
9663 .pointer(PointerBuilder(/*id=*/0, ToolType::FINGER).x(100).y(200))
9664 .build();
9665 static constexpr std::chrono::duration STALE_EVENT_TIMEOUT = 10ms;
9666 mFakePolicy->setStaleEventTimeout(STALE_EVENT_TIMEOUT);
9667 std::this_thread::sleep_for(STALE_EVENT_TIMEOUT);
9668 mDispatcher->notifyMotion(staleMotionUp);
9669
9670 // For stale motion events, we let the gesture to complete. This behaviour is different from key
9671 // events, where we would cancel the current keys instead.
9672 windowInPrimary->consumeMotionEvent(WithMotionAction(ACTION_UP));
9673 windowInSecondary->assertNoEvents();
9674 }
9675
9676 class InputFilterTest : public InputDispatcherTest {
9677 protected:
testNotifyMotion(ui::LogicalDisplayId displayId,bool expectToBeFiltered,const ui::Transform & transform=ui::Transform ())9678 void testNotifyMotion(ui::LogicalDisplayId displayId, bool expectToBeFiltered,
9679 const ui::Transform& transform = ui::Transform()) {
9680 NotifyMotionArgs motionArgs;
9681
9682 motionArgs =
9683 generateMotionArgs(AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN, displayId);
9684 mDispatcher->notifyMotion(motionArgs);
9685 motionArgs =
9686 generateMotionArgs(AMOTION_EVENT_ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN, displayId);
9687 mDispatcher->notifyMotion(motionArgs);
9688 ASSERT_TRUE(mDispatcher->waitForIdle());
9689 if (expectToBeFiltered) {
9690 const auto xy = transform.transform(motionArgs.pointerCoords[0].getXYValue());
9691 mFakePolicy->assertFilterInputEventWasCalled(motionArgs, xy);
9692 } else {
9693 mFakePolicy->assertFilterInputEventWasNotCalled();
9694 }
9695 }
9696
testNotifyKey(bool expectToBeFiltered)9697 void testNotifyKey(bool expectToBeFiltered) {
9698 NotifyKeyArgs keyArgs;
9699
9700 keyArgs = generateKeyArgs(AKEY_EVENT_ACTION_DOWN);
9701 mDispatcher->notifyKey(keyArgs);
9702 keyArgs = generateKeyArgs(AKEY_EVENT_ACTION_UP);
9703 mDispatcher->notifyKey(keyArgs);
9704 ASSERT_TRUE(mDispatcher->waitForIdle());
9705
9706 if (expectToBeFiltered) {
9707 mFakePolicy->assertFilterInputEventWasCalled(keyArgs);
9708 } else {
9709 mFakePolicy->assertFilterInputEventWasNotCalled();
9710 }
9711 }
9712 };
9713
9714 // Test InputFilter for MotionEvent
TEST_F(InputFilterTest,MotionEvent_InputFilter)9715 TEST_F(InputFilterTest, MotionEvent_InputFilter) {
9716 // Since the InputFilter is disabled by default, check if touch events aren't filtered.
9717 testNotifyMotion(ui::LogicalDisplayId::DEFAULT, /*expectToBeFiltered=*/false);
9718 testNotifyMotion(SECOND_DISPLAY_ID, /*expectToBeFiltered=*/false);
9719
9720 // Enable InputFilter
9721 mDispatcher->setInputFilterEnabled(true);
9722 // Test touch on both primary and second display, and check if both events are filtered.
9723 testNotifyMotion(ui::LogicalDisplayId::DEFAULT, /*expectToBeFiltered=*/true);
9724 testNotifyMotion(SECOND_DISPLAY_ID, /*expectToBeFiltered=*/true);
9725
9726 // Disable InputFilter
9727 mDispatcher->setInputFilterEnabled(false);
9728 // Test touch on both primary and second display, and check if both events aren't filtered.
9729 testNotifyMotion(ui::LogicalDisplayId::DEFAULT, /*expectToBeFiltered=*/false);
9730 testNotifyMotion(SECOND_DISPLAY_ID, /*expectToBeFiltered=*/false);
9731 }
9732
9733 // Test InputFilter for KeyEvent
TEST_F(InputFilterTest,KeyEvent_InputFilter)9734 TEST_F(InputFilterTest, KeyEvent_InputFilter) {
9735 // Since the InputFilter is disabled by default, check if key event aren't filtered.
9736 testNotifyKey(/*expectToBeFiltered=*/false);
9737
9738 // Enable InputFilter
9739 mDispatcher->setInputFilterEnabled(true);
9740 // Send a key event, and check if it is filtered.
9741 testNotifyKey(/*expectToBeFiltered=*/true);
9742
9743 // Disable InputFilter
9744 mDispatcher->setInputFilterEnabled(false);
9745 // Send a key event, and check if it isn't filtered.
9746 testNotifyKey(/*expectToBeFiltered=*/false);
9747 }
9748
9749 // Ensure that MotionEvents sent to the InputFilter through InputListener are converted to the
9750 // logical display coordinate space.
TEST_F(InputFilterTest,MotionEvent_UsesLogicalDisplayCoordinates_notifyMotion)9751 TEST_F(InputFilterTest, MotionEvent_UsesLogicalDisplayCoordinates_notifyMotion) {
9752 ui::Transform firstDisplayTransform;
9753 firstDisplayTransform.set({1.1, 2.2, 3.3, 4.4, 5.5, 6.6, 0, 0, 1});
9754 ui::Transform secondDisplayTransform;
9755 secondDisplayTransform.set({-6.6, -5.5, -4.4, -3.3, -2.2, -1.1, 0, 0, 1});
9756
9757 std::vector<gui::DisplayInfo> displayInfos(2);
9758 displayInfos[0].displayId = ui::LogicalDisplayId::DEFAULT;
9759 displayInfos[0].transform = firstDisplayTransform;
9760 displayInfos[1].displayId = SECOND_DISPLAY_ID;
9761 displayInfos[1].transform = secondDisplayTransform;
9762
9763 mDispatcher->onWindowInfosChanged({{}, displayInfos, 0, 0});
9764
9765 // Enable InputFilter
9766 mDispatcher->setInputFilterEnabled(true);
9767
9768 // Ensure the correct transforms are used for the displays.
9769 testNotifyMotion(ui::LogicalDisplayId::DEFAULT, /*expectToBeFiltered=*/true,
9770 firstDisplayTransform);
9771 testNotifyMotion(SECOND_DISPLAY_ID, /*expectToBeFiltered=*/true, secondDisplayTransform);
9772 }
9773
9774 class InputFilterInjectionPolicyTest : public InputDispatcherTest {
9775 protected:
SetUp()9776 virtual void SetUp() override {
9777 InputDispatcherTest::SetUp();
9778
9779 /**
9780 * We don't need to enable input filter to test the injected event policy, but we enabled it
9781 * here to make the tests more realistic, since this policy only matters when inputfilter is
9782 * on.
9783 */
9784 mDispatcher->setInputFilterEnabled(true);
9785
9786 std::shared_ptr<InputApplicationHandle> application =
9787 std::make_shared<FakeApplicationHandle>();
9788 mWindow = sp<FakeWindowHandle>::make(application, mDispatcher, "Test Window",
9789 ui::LogicalDisplayId::DEFAULT);
9790
9791 mDispatcher->setFocusedApplication(ui::LogicalDisplayId::DEFAULT, application);
9792 mWindow->setFocusable(true);
9793 mDispatcher->onWindowInfosChanged({{*mWindow->getInfo()}, {}, 0, 0});
9794 setFocusedWindow(mWindow);
9795 mWindow->consumeFocusEvent(true);
9796 }
9797
testInjectedKey(int32_t policyFlags,int32_t injectedDeviceId,int32_t resolvedDeviceId,int32_t flags)9798 void testInjectedKey(int32_t policyFlags, int32_t injectedDeviceId, int32_t resolvedDeviceId,
9799 int32_t flags) {
9800 KeyEvent event;
9801
9802 const nsecs_t eventTime = systemTime(SYSTEM_TIME_MONOTONIC);
9803 event.initialize(InputEvent::nextId(), injectedDeviceId, AINPUT_SOURCE_KEYBOARD,
9804 ui::LogicalDisplayId::INVALID, INVALID_HMAC, AKEY_EVENT_ACTION_DOWN, 0,
9805 AKEYCODE_A, KEY_A, AMETA_NONE, /*repeatCount=*/0, eventTime, eventTime);
9806 const int32_t additionalPolicyFlags =
9807 POLICY_FLAG_PASS_TO_USER | POLICY_FLAG_DISABLE_KEY_REPEAT;
9808 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
9809 mDispatcher->injectInputEvent(&event, /*targetUid=*/{},
9810 InputEventInjectionSync::WAIT_FOR_RESULT, 100ms,
9811 policyFlags | additionalPolicyFlags));
9812
9813 mWindow->consumeKeyEvent(AllOf(WithDeviceId(resolvedDeviceId), WithFlags(flags)));
9814 }
9815
testInjectedMotion(int32_t policyFlags,int32_t injectedDeviceId,int32_t resolvedDeviceId,int32_t flags)9816 void testInjectedMotion(int32_t policyFlags, int32_t injectedDeviceId, int32_t resolvedDeviceId,
9817 int32_t flags) {
9818 MotionEvent event;
9819 PointerProperties pointerProperties[1];
9820 PointerCoords pointerCoords[1];
9821 pointerProperties[0].clear();
9822 pointerProperties[0].id = 0;
9823 pointerCoords[0].clear();
9824 pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_X, 300);
9825 pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_Y, 400);
9826
9827 ui::Transform identityTransform;
9828 const nsecs_t eventTime = systemTime(SYSTEM_TIME_MONOTONIC);
9829 event.initialize(InputEvent::nextId(), injectedDeviceId, AINPUT_SOURCE_TOUCHSCREEN,
9830 DISPLAY_ID, INVALID_HMAC, AMOTION_EVENT_ACTION_DOWN, 0, 0,
9831 AMOTION_EVENT_EDGE_FLAG_NONE, AMETA_NONE, 0, MotionClassification::NONE,
9832 identityTransform, 0, 0, AMOTION_EVENT_INVALID_CURSOR_POSITION,
9833 AMOTION_EVENT_INVALID_CURSOR_POSITION, identityTransform, eventTime,
9834 eventTime,
9835 /*pointerCount=*/1, pointerProperties, pointerCoords);
9836
9837 const int32_t additionalPolicyFlags = POLICY_FLAG_PASS_TO_USER;
9838 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
9839 mDispatcher->injectInputEvent(&event, /*targetUid=*/{},
9840 InputEventInjectionSync::WAIT_FOR_RESULT, 100ms,
9841 policyFlags | additionalPolicyFlags));
9842
9843 mWindow->consumeMotionEvent(AllOf(WithFlags(flags), WithDeviceId(resolvedDeviceId)));
9844 }
9845
9846 private:
9847 sp<FakeWindowHandle> mWindow;
9848 };
9849
TEST_F(InputFilterInjectionPolicyTest,TrustedFilteredEvents_KeepOriginalDeviceId)9850 TEST_F(InputFilterInjectionPolicyTest, TrustedFilteredEvents_KeepOriginalDeviceId) {
9851 // Must have POLICY_FLAG_FILTERED here to indicate that the event has gone through the input
9852 // filter. Without it, the event will no different from a regularly injected event, and the
9853 // injected device id will be overwritten.
9854 testInjectedKey(POLICY_FLAG_FILTERED, /*injectedDeviceId=*/3, /*resolvedDeviceId=*/3,
9855 /*flags=*/0);
9856 }
9857
TEST_F(InputFilterInjectionPolicyTest,KeyEventsInjectedFromAccessibility_HaveAccessibilityFlag)9858 TEST_F(InputFilterInjectionPolicyTest, KeyEventsInjectedFromAccessibility_HaveAccessibilityFlag) {
9859 testInjectedKey(POLICY_FLAG_FILTERED | POLICY_FLAG_INJECTED_FROM_ACCESSIBILITY,
9860 /*injectedDeviceId=*/3, /*resolvedDeviceId=*/3,
9861 AKEY_EVENT_FLAG_IS_ACCESSIBILITY_EVENT);
9862 }
9863
TEST_F(InputFilterInjectionPolicyTest,MotionEventsInjectedFromAccessibility_HaveAccessibilityFlag)9864 TEST_F(InputFilterInjectionPolicyTest,
9865 MotionEventsInjectedFromAccessibility_HaveAccessibilityFlag) {
9866 testInjectedMotion(POLICY_FLAG_FILTERED | POLICY_FLAG_INJECTED_FROM_ACCESSIBILITY,
9867 /*injectedDeviceId=*/3, /*resolvedDeviceId=*/3,
9868 AMOTION_EVENT_FLAG_IS_ACCESSIBILITY_EVENT);
9869 }
9870
TEST_F(InputFilterInjectionPolicyTest,RegularInjectedEvents_ReceiveVirtualDeviceId)9871 TEST_F(InputFilterInjectionPolicyTest, RegularInjectedEvents_ReceiveVirtualDeviceId) {
9872 testInjectedKey(/*policyFlags=*/0, /*injectedDeviceId=*/3,
9873 /*resolvedDeviceId=*/VIRTUAL_KEYBOARD_ID, /*flags=*/0);
9874 }
9875
9876 class InputDispatcherUserActivityPokeTests : public InputDispatcherTest {
9877 protected:
SetUp()9878 virtual void SetUp() override {
9879 InputDispatcherTest::SetUp();
9880
9881 std::shared_ptr<FakeApplicationHandle> application =
9882 std::make_shared<FakeApplicationHandle>();
9883 application->setDispatchingTimeout(100ms);
9884 mWindow = sp<FakeWindowHandle>::make(application, mDispatcher, "TestWindow",
9885 ui::LogicalDisplayId::DEFAULT);
9886 mWindow->setFrame(Rect(0, 0, 100, 100));
9887 mWindow->setDispatchingTimeout(100ms);
9888 mWindow->setFocusable(true);
9889
9890 // Set focused application.
9891 mDispatcher->setFocusedApplication(ui::LogicalDisplayId::DEFAULT, application);
9892
9893 mDispatcher->onWindowInfosChanged({{*mWindow->getInfo()}, {}, 0, 0});
9894 setFocusedWindow(mWindow);
9895 mWindow->consumeFocusEvent(true);
9896 }
9897
notifyAndConsumeMotion(int32_t action,uint32_t source,ui::LogicalDisplayId displayId,nsecs_t eventTime)9898 void notifyAndConsumeMotion(int32_t action, uint32_t source, ui::LogicalDisplayId displayId,
9899 nsecs_t eventTime) {
9900 mDispatcher->notifyMotion(MotionArgsBuilder(action, source)
9901 .displayId(displayId)
9902 .eventTime(eventTime)
9903 .pointer(PointerBuilder(0, ToolType::FINGER).x(50).y(50))
9904 .build());
9905 mWindow->consumeMotionEvent(WithMotionAction(action));
9906 }
9907
9908 private:
9909 sp<FakeWindowHandle> mWindow;
9910 };
9911
TEST_F_WITH_FLAGS(InputDispatcherUserActivityPokeTests,MinPokeTimeObserved,REQUIRES_FLAGS_ENABLED (ACONFIG_FLAG (com::android::input::flags,rate_limit_user_activity_poke_in_dispatcher)))9912 TEST_F_WITH_FLAGS(
9913 InputDispatcherUserActivityPokeTests, MinPokeTimeObserved,
9914 REQUIRES_FLAGS_ENABLED(ACONFIG_FLAG(com::android::input::flags,
9915 rate_limit_user_activity_poke_in_dispatcher))) {
9916 mDispatcher->setMinTimeBetweenUserActivityPokes(50ms);
9917
9918 // First event of type TOUCH. Should poke.
9919 notifyAndConsumeMotion(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN, ui::LogicalDisplayId::DEFAULT,
9920 milliseconds_to_nanoseconds(50));
9921 mFakePolicy->assertUserActivityPoked(
9922 {{milliseconds_to_nanoseconds(50), USER_ACTIVITY_EVENT_TOUCH,
9923 ui::LogicalDisplayId::DEFAULT}});
9924
9925 // 80ns > 50ns has passed since previous TOUCH event. Should poke.
9926 notifyAndConsumeMotion(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN, ui::LogicalDisplayId::DEFAULT,
9927 milliseconds_to_nanoseconds(130));
9928 mFakePolicy->assertUserActivityPoked(
9929 {{milliseconds_to_nanoseconds(130), USER_ACTIVITY_EVENT_TOUCH,
9930 ui::LogicalDisplayId::DEFAULT}});
9931
9932 // First event of type OTHER. Should poke (despite being within 50ns of previous TOUCH event).
9933 notifyAndConsumeMotion(ACTION_SCROLL, AINPUT_SOURCE_ROTARY_ENCODER,
9934 ui::LogicalDisplayId::DEFAULT, milliseconds_to_nanoseconds(135));
9935 mFakePolicy->assertUserActivityPoked(
9936 {{milliseconds_to_nanoseconds(135), USER_ACTIVITY_EVENT_OTHER,
9937 ui::LogicalDisplayId::DEFAULT}});
9938
9939 // Within 50ns of previous TOUCH event. Should NOT poke.
9940 notifyAndConsumeMotion(ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN, ui::LogicalDisplayId::DEFAULT,
9941 milliseconds_to_nanoseconds(140));
9942 mFakePolicy->assertUserActivityNotPoked();
9943
9944 // Within 50ns of previous OTHER event. Should NOT poke.
9945 notifyAndConsumeMotion(ACTION_SCROLL, AINPUT_SOURCE_ROTARY_ENCODER,
9946 ui::LogicalDisplayId::DEFAULT, milliseconds_to_nanoseconds(150));
9947 mFakePolicy->assertUserActivityNotPoked();
9948
9949 // Within 50ns of previous TOUCH event (which was at time 130). Should NOT poke.
9950 // Note that STYLUS is mapped to TOUCH user activity, since it's a pointer-type source.
9951 notifyAndConsumeMotion(ACTION_DOWN, AINPUT_SOURCE_STYLUS, ui::LogicalDisplayId::DEFAULT,
9952 milliseconds_to_nanoseconds(160));
9953 mFakePolicy->assertUserActivityNotPoked();
9954
9955 // 65ns > 50ns has passed since previous OTHER event. Should poke.
9956 notifyAndConsumeMotion(ACTION_SCROLL, AINPUT_SOURCE_ROTARY_ENCODER,
9957 ui::LogicalDisplayId::DEFAULT, milliseconds_to_nanoseconds(200));
9958 mFakePolicy->assertUserActivityPoked(
9959 {{milliseconds_to_nanoseconds(200), USER_ACTIVITY_EVENT_OTHER,
9960 ui::LogicalDisplayId::DEFAULT}});
9961
9962 // 170ns > 50ns has passed since previous TOUCH event. Should poke.
9963 notifyAndConsumeMotion(ACTION_UP, AINPUT_SOURCE_STYLUS, ui::LogicalDisplayId::DEFAULT,
9964 milliseconds_to_nanoseconds(300));
9965 mFakePolicy->assertUserActivityPoked(
9966 {{milliseconds_to_nanoseconds(300), USER_ACTIVITY_EVENT_TOUCH,
9967 ui::LogicalDisplayId::DEFAULT}});
9968
9969 // Assert that there's no more user activity poke event.
9970 mFakePolicy->assertUserActivityNotPoked();
9971 }
9972
TEST_F_WITH_FLAGS(InputDispatcherUserActivityPokeTests,DefaultMinPokeTimeOf100MsUsed,REQUIRES_FLAGS_ENABLED (ACONFIG_FLAG (com::android::input::flags,rate_limit_user_activity_poke_in_dispatcher)))9973 TEST_F_WITH_FLAGS(
9974 InputDispatcherUserActivityPokeTests, DefaultMinPokeTimeOf100MsUsed,
9975 REQUIRES_FLAGS_ENABLED(ACONFIG_FLAG(com::android::input::flags,
9976 rate_limit_user_activity_poke_in_dispatcher))) {
9977 notifyAndConsumeMotion(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN, ui::LogicalDisplayId::DEFAULT,
9978 milliseconds_to_nanoseconds(200));
9979 mFakePolicy->assertUserActivityPoked(
9980 {{milliseconds_to_nanoseconds(200), USER_ACTIVITY_EVENT_TOUCH,
9981 ui::LogicalDisplayId::DEFAULT}});
9982
9983 notifyAndConsumeMotion(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN, ui::LogicalDisplayId::DEFAULT,
9984 milliseconds_to_nanoseconds(280));
9985 mFakePolicy->assertUserActivityNotPoked();
9986
9987 notifyAndConsumeMotion(ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN, ui::LogicalDisplayId::DEFAULT,
9988 milliseconds_to_nanoseconds(340));
9989 mFakePolicy->assertUserActivityPoked(
9990 {{milliseconds_to_nanoseconds(340), USER_ACTIVITY_EVENT_TOUCH,
9991 ui::LogicalDisplayId::DEFAULT}});
9992 }
9993
TEST_F_WITH_FLAGS(InputDispatcherUserActivityPokeTests,ZeroMinPokeTimeDisablesRateLimiting,REQUIRES_FLAGS_ENABLED (ACONFIG_FLAG (com::android::input::flags,rate_limit_user_activity_poke_in_dispatcher)))9994 TEST_F_WITH_FLAGS(
9995 InputDispatcherUserActivityPokeTests, ZeroMinPokeTimeDisablesRateLimiting,
9996 REQUIRES_FLAGS_ENABLED(ACONFIG_FLAG(com::android::input::flags,
9997 rate_limit_user_activity_poke_in_dispatcher))) {
9998 mDispatcher->setMinTimeBetweenUserActivityPokes(0ms);
9999
10000 notifyAndConsumeMotion(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN, ui::LogicalDisplayId::DEFAULT,
10001 20);
10002 mFakePolicy->assertUserActivityPoked();
10003
10004 notifyAndConsumeMotion(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN, ui::LogicalDisplayId::DEFAULT,
10005 30);
10006 mFakePolicy->assertUserActivityPoked();
10007 }
10008
10009 class InputDispatcherOnPointerDownOutsideFocus : public InputDispatcherTest {
SetUp()10010 virtual void SetUp() override {
10011 InputDispatcherTest::SetUp();
10012
10013 std::shared_ptr<FakeApplicationHandle> application =
10014 std::make_shared<FakeApplicationHandle>();
10015 mUnfocusedWindow = sp<FakeWindowHandle>::make(application, mDispatcher, "Top",
10016 ui::LogicalDisplayId::DEFAULT);
10017 mUnfocusedWindow->setFrame(Rect(0, 0, 30, 30));
10018
10019 mFocusedWindow = sp<FakeWindowHandle>::make(application, mDispatcher, "Second",
10020 ui::LogicalDisplayId::DEFAULT);
10021 mFocusedWindow->setFrame(Rect(50, 50, 100, 100));
10022
10023 // Set focused application.
10024 mDispatcher->setFocusedApplication(ui::LogicalDisplayId::DEFAULT, application);
10025 mFocusedWindow->setFocusable(true);
10026
10027 // Expect one focus window exist in display.
10028 mDispatcher->onWindowInfosChanged(
10029 {{*mUnfocusedWindow->getInfo(), *mFocusedWindow->getInfo()}, {}, 0, 0});
10030 setFocusedWindow(mFocusedWindow);
10031 mFocusedWindow->consumeFocusEvent(true);
10032 }
10033
TearDown()10034 virtual void TearDown() override {
10035 InputDispatcherTest::TearDown();
10036
10037 mUnfocusedWindow.clear();
10038 mFocusedWindow.clear();
10039 }
10040
10041 protected:
10042 sp<FakeWindowHandle> mUnfocusedWindow;
10043 sp<FakeWindowHandle> mFocusedWindow;
10044 static constexpr PointF FOCUSED_WINDOW_TOUCH_POINT = {60, 60};
10045 };
10046
10047 // Have two windows, one with focus. Inject MotionEvent with source TOUCHSCREEN and action
10048 // DOWN on the window that doesn't have focus. Ensure the window that didn't have focus received
10049 // the onPointerDownOutsideFocus callback.
TEST_F(InputDispatcherOnPointerDownOutsideFocus,OnPointerDownOutsideFocus_Success)10050 TEST_F(InputDispatcherOnPointerDownOutsideFocus, OnPointerDownOutsideFocus_Success) {
10051 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
10052 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN,
10053 ui::LogicalDisplayId::DEFAULT, {20, 20}))
10054 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
10055 mUnfocusedWindow->consumeMotionDown();
10056
10057 ASSERT_TRUE(mDispatcher->waitForIdle());
10058 mFakePolicy->assertOnPointerDownEquals(mUnfocusedWindow->getToken());
10059 }
10060
10061 // Have two windows, one with focus. Inject MotionEvent with source TRACKBALL and action
10062 // DOWN on the window that doesn't have focus. Ensure no window received the
10063 // onPointerDownOutsideFocus callback.
TEST_F(InputDispatcherOnPointerDownOutsideFocus,OnPointerDownOutsideFocus_NonPointerSource)10064 TEST_F(InputDispatcherOnPointerDownOutsideFocus, OnPointerDownOutsideFocus_NonPointerSource) {
10065 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
10066 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TRACKBALL, ui::LogicalDisplayId::DEFAULT,
10067 {20, 20}))
10068 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
10069 mFocusedWindow->consumeMotionDown();
10070
10071 ASSERT_TRUE(mDispatcher->waitForIdle());
10072 mFakePolicy->assertOnPointerDownWasNotCalled();
10073 }
10074
10075 // Have two windows, one with focus. Inject KeyEvent with action DOWN on the window that doesn't
10076 // have focus. Ensure no window received the onPointerDownOutsideFocus callback.
TEST_F(InputDispatcherOnPointerDownOutsideFocus,OnPointerDownOutsideFocus_NonMotionFailure)10077 TEST_F(InputDispatcherOnPointerDownOutsideFocus, OnPointerDownOutsideFocus_NonMotionFailure) {
10078 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
10079 injectKeyDownNoRepeat(*mDispatcher, ui::LogicalDisplayId::DEFAULT))
10080 << "Inject key event should return InputEventInjectionResult::SUCCEEDED";
10081 mFocusedWindow->consumeKeyDown(ui::LogicalDisplayId::DEFAULT);
10082
10083 ASSERT_TRUE(mDispatcher->waitForIdle());
10084 mFakePolicy->assertOnPointerDownWasNotCalled();
10085 }
10086
10087 // Have two windows, one with focus. Inject MotionEvent with source TOUCHSCREEN and action
10088 // DOWN on the window that already has focus. Ensure no window received the
10089 // onPointerDownOutsideFocus callback.
TEST_F(InputDispatcherOnPointerDownOutsideFocus,OnPointerDownOutsideFocus_OnAlreadyFocusedWindow)10090 TEST_F(InputDispatcherOnPointerDownOutsideFocus, OnPointerDownOutsideFocus_OnAlreadyFocusedWindow) {
10091 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
10092 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN,
10093 ui::LogicalDisplayId::DEFAULT, FOCUSED_WINDOW_TOUCH_POINT))
10094 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
10095 mFocusedWindow->consumeMotionDown();
10096
10097 ASSERT_TRUE(mDispatcher->waitForIdle());
10098 mFakePolicy->assertOnPointerDownWasNotCalled();
10099 }
10100
10101 // Have two windows, one with focus. Injecting a trusted DOWN MotionEvent with the flag
10102 // NO_FOCUS_CHANGE on the unfocused window should not call the onPointerDownOutsideFocus callback.
TEST_F(InputDispatcherOnPointerDownOutsideFocus,NoFocusChangeFlag)10103 TEST_F(InputDispatcherOnPointerDownOutsideFocus, NoFocusChangeFlag) {
10104 const MotionEvent event =
10105 MotionEventBuilder(AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_MOUSE)
10106 .eventTime(systemTime(SYSTEM_TIME_MONOTONIC))
10107 .pointer(PointerBuilder(/*id=*/0, ToolType::FINGER).x(20).y(20))
10108 .addFlag(AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE)
10109 .build();
10110 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectMotionEvent(*mDispatcher, event))
10111 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
10112 mUnfocusedWindow->consumeAnyMotionDown(ui::LogicalDisplayId::DEFAULT,
10113 AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
10114
10115 ASSERT_TRUE(mDispatcher->waitForIdle());
10116 mFakePolicy->assertOnPointerDownWasNotCalled();
10117 // Ensure that the unfocused window did not receive any FOCUS events.
10118 mUnfocusedWindow->assertNoEvents();
10119 }
10120
10121 // These tests ensures we can send touch events to a single client when there are multiple input
10122 // windows that point to the same client token.
10123 class InputDispatcherMultiWindowSameTokenTests : public InputDispatcherTest {
SetUp()10124 virtual void SetUp() override {
10125 InputDispatcherTest::SetUp();
10126
10127 std::shared_ptr<FakeApplicationHandle> application =
10128 std::make_shared<FakeApplicationHandle>();
10129 mWindow1 = sp<FakeWindowHandle>::make(application, mDispatcher, "Fake Window 1",
10130 ui::LogicalDisplayId::DEFAULT);
10131 mWindow1->setFrame(Rect(0, 0, 100, 100));
10132
10133 mWindow2 = mWindow1->clone(ui::LogicalDisplayId::DEFAULT);
10134 mWindow2->setFrame(Rect(100, 100, 200, 200));
10135
10136 mDispatcher->onWindowInfosChanged({{*mWindow1->getInfo(), *mWindow2->getInfo()}, {}, 0, 0});
10137 }
10138
10139 protected:
10140 sp<FakeWindowHandle> mWindow1;
10141 sp<FakeWindowHandle> mWindow2;
10142
10143 // Helper function to convert the point from screen coordinates into the window's space
getPointInWindow(const WindowInfo * windowInfo,const PointF & point)10144 static PointF getPointInWindow(const WindowInfo* windowInfo, const PointF& point) {
10145 vec2 vals = windowInfo->transform.transform(point.x, point.y);
10146 return {vals.x, vals.y};
10147 }
10148
consumeMotionEvent(const sp<FakeWindowHandle> & window,int32_t expectedAction,const std::vector<PointF> & points)10149 void consumeMotionEvent(const sp<FakeWindowHandle>& window, int32_t expectedAction,
10150 const std::vector<PointF>& points) {
10151 const std::string name = window->getName();
10152 std::unique_ptr<MotionEvent> motionEvent =
10153 window->consumeMotionEvent(WithMotionAction(expectedAction));
10154 ASSERT_NE(nullptr, motionEvent);
10155 ASSERT_EQ(points.size(), motionEvent->getPointerCount());
10156
10157 for (size_t i = 0; i < points.size(); i++) {
10158 float expectedX = points[i].x;
10159 float expectedY = points[i].y;
10160
10161 EXPECT_EQ(expectedX, motionEvent->getX(i))
10162 << "expected " << expectedX << " for x[" << i << "] coord of " << name.c_str()
10163 << ", got " << motionEvent->getX(i);
10164 EXPECT_EQ(expectedY, motionEvent->getY(i))
10165 << "expected " << expectedY << " for y[" << i << "] coord of " << name.c_str()
10166 << ", got " << motionEvent->getY(i);
10167 }
10168 }
10169
touchAndAssertPositions(sp<FakeWindowHandle> touchedWindow,int32_t action,const std::vector<PointF> & touchedPoints,std::vector<PointF> expectedPoints)10170 void touchAndAssertPositions(sp<FakeWindowHandle> touchedWindow, int32_t action,
10171 const std::vector<PointF>& touchedPoints,
10172 std::vector<PointF> expectedPoints) {
10173 mDispatcher->notifyMotion(generateMotionArgs(action, AINPUT_SOURCE_TOUCHSCREEN,
10174 ui::LogicalDisplayId::DEFAULT, touchedPoints));
10175
10176 consumeMotionEvent(touchedWindow, action, expectedPoints);
10177 }
10178 };
10179
TEST_F(InputDispatcherMultiWindowSameTokenTests,SingleTouchSameScale)10180 TEST_F(InputDispatcherMultiWindowSameTokenTests, SingleTouchSameScale) {
10181 // Touch Window 1
10182 PointF touchedPoint = {10, 10};
10183 PointF expectedPoint = getPointInWindow(mWindow1->getInfo(), touchedPoint);
10184 touchAndAssertPositions(mWindow1, AMOTION_EVENT_ACTION_DOWN, {touchedPoint}, {expectedPoint});
10185
10186 // Release touch on Window 1
10187 touchAndAssertPositions(mWindow1, AMOTION_EVENT_ACTION_UP, {touchedPoint}, {expectedPoint});
10188
10189 // Touch Window 2
10190 touchedPoint = {150, 150};
10191 expectedPoint = getPointInWindow(mWindow2->getInfo(), touchedPoint);
10192 touchAndAssertPositions(mWindow2, AMOTION_EVENT_ACTION_DOWN, {touchedPoint}, {expectedPoint});
10193 }
10194
TEST_F(InputDispatcherMultiWindowSameTokenTests,SingleTouchDifferentTransform)10195 TEST_F(InputDispatcherMultiWindowSameTokenTests, SingleTouchDifferentTransform) {
10196 // Set scale value for window2
10197 mWindow2->setWindowScale(0.5f, 0.5f);
10198 mDispatcher->onWindowInfosChanged({{*mWindow1->getInfo(), *mWindow2->getInfo()}, {}, 0, 0});
10199
10200 // Touch Window 1
10201 PointF touchedPoint = {10, 10};
10202 PointF expectedPoint = getPointInWindow(mWindow1->getInfo(), touchedPoint);
10203 touchAndAssertPositions(mWindow1, AMOTION_EVENT_ACTION_DOWN, {touchedPoint}, {expectedPoint});
10204 // Release touch on Window 1
10205 touchAndAssertPositions(mWindow1, AMOTION_EVENT_ACTION_UP, {touchedPoint}, {expectedPoint});
10206
10207 // Touch Window 2
10208 touchedPoint = {150, 150};
10209 expectedPoint = getPointInWindow(mWindow2->getInfo(), touchedPoint);
10210 touchAndAssertPositions(mWindow2, AMOTION_EVENT_ACTION_DOWN, {touchedPoint}, {expectedPoint});
10211 touchAndAssertPositions(mWindow2, AMOTION_EVENT_ACTION_UP, {touchedPoint}, {expectedPoint});
10212
10213 // Update the transform so rotation is set
10214 mWindow2->setWindowTransform(0, -1, 1, 0);
10215 mDispatcher->onWindowInfosChanged({{*mWindow1->getInfo(), *mWindow2->getInfo()}, {}, 0, 0});
10216 expectedPoint = getPointInWindow(mWindow2->getInfo(), touchedPoint);
10217 touchAndAssertPositions(mWindow2, AMOTION_EVENT_ACTION_DOWN, {touchedPoint}, {expectedPoint});
10218 }
10219
TEST_F(InputDispatcherMultiWindowSameTokenTests,MultipleTouchDifferentTransform)10220 TEST_F(InputDispatcherMultiWindowSameTokenTests, MultipleTouchDifferentTransform) {
10221 mWindow2->setWindowScale(0.5f, 0.5f);
10222 mDispatcher->onWindowInfosChanged({{*mWindow1->getInfo(), *mWindow2->getInfo()}, {}, 0, 0});
10223
10224 // Touch Window 1
10225 std::vector<PointF> touchedPoints = {PointF{10, 10}};
10226 std::vector<PointF> expectedPoints = {getPointInWindow(mWindow1->getInfo(), touchedPoints[0])};
10227 touchAndAssertPositions(mWindow1, AMOTION_EVENT_ACTION_DOWN, touchedPoints, expectedPoints);
10228
10229 // Touch Window 2
10230 // Since this is part of the same touch gesture that has already been dispatched to Window 1,
10231 // the touch stream from Window 2 will be merged with the stream in Window 1. The merged stream
10232 // will continue to be dispatched through Window 1.
10233 touchedPoints.push_back(PointF{150, 150});
10234 expectedPoints.push_back(getPointInWindow(mWindow2->getInfo(), touchedPoints[1]));
10235 touchAndAssertPositions(mWindow1, POINTER_1_DOWN, touchedPoints, expectedPoints);
10236
10237 // Release Window 2
10238 touchAndAssertPositions(mWindow1, POINTER_1_UP, touchedPoints, expectedPoints);
10239 expectedPoints.pop_back();
10240
10241 // Update the transform so rotation is set for Window 2
10242 mWindow2->setWindowTransform(0, -1, 1, 0);
10243 mDispatcher->onWindowInfosChanged({{*mWindow1->getInfo(), *mWindow2->getInfo()}, {}, 0, 0});
10244 expectedPoints.push_back(getPointInWindow(mWindow2->getInfo(), touchedPoints[1]));
10245 touchAndAssertPositions(mWindow1, POINTER_1_DOWN, touchedPoints, expectedPoints);
10246 }
10247
TEST_F(InputDispatcherMultiWindowSameTokenTests,MultipleTouchMoveDifferentTransform)10248 TEST_F(InputDispatcherMultiWindowSameTokenTests, MultipleTouchMoveDifferentTransform) {
10249 mWindow2->setWindowScale(0.5f, 0.5f);
10250 mDispatcher->onWindowInfosChanged({{*mWindow1->getInfo(), *mWindow2->getInfo()}, {}, 0, 0});
10251
10252 // Touch Window 1
10253 std::vector<PointF> touchedPoints = {PointF{10, 10}};
10254 std::vector<PointF> expectedPoints = {getPointInWindow(mWindow1->getInfo(), touchedPoints[0])};
10255 touchAndAssertPositions(mWindow1, AMOTION_EVENT_ACTION_DOWN, touchedPoints, expectedPoints);
10256
10257 // Touch Window 2
10258 touchedPoints.push_back(PointF{150, 150});
10259 expectedPoints.push_back(getPointInWindow(mWindow2->getInfo(), touchedPoints[1]));
10260
10261 touchAndAssertPositions(mWindow1, POINTER_1_DOWN, touchedPoints, expectedPoints);
10262
10263 // Move both windows
10264 touchedPoints = {{20, 20}, {175, 175}};
10265 expectedPoints = {getPointInWindow(mWindow1->getInfo(), touchedPoints[0]),
10266 getPointInWindow(mWindow2->getInfo(), touchedPoints[1])};
10267
10268 touchAndAssertPositions(mWindow1, AMOTION_EVENT_ACTION_MOVE, touchedPoints, expectedPoints);
10269
10270 // Release Window 2
10271 touchAndAssertPositions(mWindow1, POINTER_1_UP, touchedPoints, expectedPoints);
10272 expectedPoints.pop_back();
10273
10274 // Touch Window 2
10275 mWindow2->setWindowTransform(0, -1, 1, 0);
10276 mDispatcher->onWindowInfosChanged({{*mWindow1->getInfo(), *mWindow2->getInfo()}, {}, 0, 0});
10277 expectedPoints.push_back(getPointInWindow(mWindow2->getInfo(), touchedPoints[1]));
10278 touchAndAssertPositions(mWindow1, POINTER_1_DOWN, touchedPoints, expectedPoints);
10279
10280 // Move both windows
10281 touchedPoints = {{20, 20}, {175, 175}};
10282 expectedPoints = {getPointInWindow(mWindow1->getInfo(), touchedPoints[0]),
10283 getPointInWindow(mWindow2->getInfo(), touchedPoints[1])};
10284
10285 touchAndAssertPositions(mWindow1, AMOTION_EVENT_ACTION_MOVE, touchedPoints, expectedPoints);
10286 }
10287
TEST_F(InputDispatcherMultiWindowSameTokenTests,MultipleWindowsFirstTouchWithScale)10288 TEST_F(InputDispatcherMultiWindowSameTokenTests, MultipleWindowsFirstTouchWithScale) {
10289 mWindow1->setWindowScale(0.5f, 0.5f);
10290 mDispatcher->onWindowInfosChanged({{*mWindow1->getInfo(), *mWindow2->getInfo()}, {}, 0, 0});
10291
10292 // Touch Window 1
10293 std::vector<PointF> touchedPoints = {PointF{10, 10}};
10294 std::vector<PointF> expectedPoints = {getPointInWindow(mWindow1->getInfo(), touchedPoints[0])};
10295 touchAndAssertPositions(mWindow1, AMOTION_EVENT_ACTION_DOWN, touchedPoints, expectedPoints);
10296
10297 // Touch Window 2
10298 touchedPoints.push_back(PointF{150, 150});
10299 expectedPoints.push_back(getPointInWindow(mWindow2->getInfo(), touchedPoints[1]));
10300
10301 touchAndAssertPositions(mWindow1, POINTER_1_DOWN, touchedPoints, expectedPoints);
10302
10303 // Move both windows
10304 touchedPoints = {{20, 20}, {175, 175}};
10305 expectedPoints = {getPointInWindow(mWindow1->getInfo(), touchedPoints[0]),
10306 getPointInWindow(mWindow2->getInfo(), touchedPoints[1])};
10307
10308 touchAndAssertPositions(mWindow1, AMOTION_EVENT_ACTION_MOVE, touchedPoints, expectedPoints);
10309 }
10310
10311 /**
10312 * When one of the windows is slippery, the touch should not slip into the other window with the
10313 * same input channel.
10314 */
TEST_F(InputDispatcherMultiWindowSameTokenTests,TouchDoesNotSlipEvenIfSlippery)10315 TEST_F(InputDispatcherMultiWindowSameTokenTests, TouchDoesNotSlipEvenIfSlippery) {
10316 mWindow1->setSlippery(true);
10317 mDispatcher->onWindowInfosChanged({{*mWindow1->getInfo(), *mWindow2->getInfo()}, {}, 0, 0});
10318
10319 // Touch down in window 1
10320 mDispatcher->notifyMotion(generateMotionArgs(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN,
10321 ui::LogicalDisplayId::DEFAULT, {{50, 50}}));
10322 consumeMotionEvent(mWindow1, ACTION_DOWN, {{50, 50}});
10323
10324 // Move touch to be above window 2. Even though window 1 is slippery, touch should not slip.
10325 // That means the gesture should continue normally, without any ACTION_CANCEL or ACTION_DOWN
10326 // getting generated.
10327 mDispatcher->notifyMotion(generateMotionArgs(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN,
10328 ui::LogicalDisplayId::DEFAULT, {{150, 150}}));
10329
10330 consumeMotionEvent(mWindow1, ACTION_MOVE, {{150, 150}});
10331 }
10332
10333 /**
10334 * When hover starts in one window and continues into the other, there should be a HOVER_EXIT and
10335 * a HOVER_ENTER generated, even if the windows have the same token. This is because the new window
10336 * that the pointer is hovering over may have a different transform.
10337 */
TEST_F(InputDispatcherMultiWindowSameTokenTests,HoverIntoClone)10338 TEST_F(InputDispatcherMultiWindowSameTokenTests, HoverIntoClone) {
10339 mDispatcher->onWindowInfosChanged({{*mWindow1->getInfo(), *mWindow2->getInfo()}, {}, 0, 0});
10340
10341 // Start hover in window 1
10342 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_ENTER, AINPUT_SOURCE_TOUCHSCREEN)
10343 .pointer(PointerBuilder(0, ToolType::FINGER).x(50).y(50))
10344 .build());
10345 consumeMotionEvent(mWindow1, ACTION_HOVER_ENTER,
10346 {getPointInWindow(mWindow1->getInfo(), PointF{50, 50})});
10347 // Move hover to window 2.
10348 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_MOVE, AINPUT_SOURCE_TOUCHSCREEN)
10349 .pointer(PointerBuilder(0, ToolType::FINGER).x(150).y(150))
10350 .build());
10351 consumeMotionEvent(mWindow1, ACTION_HOVER_EXIT, {{50, 50}});
10352 consumeMotionEvent(mWindow2, ACTION_HOVER_ENTER,
10353 {getPointInWindow(mWindow2->getInfo(), PointF{150, 150})});
10354 }
10355
10356 class InputDispatcherSingleWindowAnr : public InputDispatcherTest {
SetUp()10357 virtual void SetUp() override {
10358 InputDispatcherTest::SetUp();
10359
10360 mApplication = std::make_shared<FakeApplicationHandle>();
10361 mApplication->setDispatchingTimeout(100ms);
10362 mWindow = sp<FakeWindowHandle>::make(mApplication, mDispatcher, "TestWindow",
10363 ui::LogicalDisplayId::DEFAULT);
10364 mWindow->setFrame(Rect(0, 0, 30, 30));
10365 mWindow->setDispatchingTimeout(100ms);
10366 mWindow->setFocusable(true);
10367
10368 // Set focused application.
10369 mDispatcher->setFocusedApplication(ui::LogicalDisplayId::DEFAULT, mApplication);
10370
10371 mDispatcher->onWindowInfosChanged({{*mWindow->getInfo()}, {}, 0, 0});
10372 setFocusedWindow(mWindow);
10373 mWindow->consumeFocusEvent(true);
10374 }
10375
TearDown()10376 virtual void TearDown() override {
10377 InputDispatcherTest::TearDown();
10378 mWindow.clear();
10379 }
10380
10381 protected:
10382 static constexpr std::chrono::duration SPY_TIMEOUT = 200ms;
10383 std::shared_ptr<FakeApplicationHandle> mApplication;
10384 sp<FakeWindowHandle> mWindow;
10385 static constexpr PointF WINDOW_LOCATION = {20, 20};
10386
tapOnWindow()10387 void tapOnWindow() {
10388 const auto touchingPointer = PointerBuilder(/*id=*/0, ToolType::FINGER)
10389 .x(WINDOW_LOCATION.x)
10390 .y(WINDOW_LOCATION.y);
10391 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
10392 .pointer(touchingPointer)
10393 .build());
10394 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN)
10395 .pointer(touchingPointer)
10396 .build());
10397 }
10398
addSpyWindow()10399 sp<FakeWindowHandle> addSpyWindow() {
10400 sp<FakeWindowHandle> spy = sp<FakeWindowHandle>::make(mApplication, mDispatcher, "Spy",
10401 ui::LogicalDisplayId::DEFAULT);
10402 spy->setTrustedOverlay(true);
10403 spy->setFocusable(false);
10404 spy->setSpy(true);
10405 spy->setDispatchingTimeout(SPY_TIMEOUT);
10406 mDispatcher->onWindowInfosChanged({{*spy->getInfo(), *mWindow->getInfo()}, {}, 0, 0});
10407 return spy;
10408 }
10409 };
10410
10411 // Send a tap and respond, which should not cause an ANR.
TEST_F(InputDispatcherSingleWindowAnr,WhenTouchIsConsumed_NoAnr)10412 TEST_F(InputDispatcherSingleWindowAnr, WhenTouchIsConsumed_NoAnr) {
10413 tapOnWindow();
10414 mWindow->consumeMotionDown();
10415 mWindow->consumeMotionUp();
10416 ASSERT_TRUE(mDispatcher->waitForIdle());
10417 mFakePolicy->assertNotifyAnrWasNotCalled();
10418 }
10419
10420 // Send a regular key and respond, which should not cause an ANR.
TEST_F(InputDispatcherSingleWindowAnr,WhenKeyIsConsumed_NoAnr)10421 TEST_F(InputDispatcherSingleWindowAnr, WhenKeyIsConsumed_NoAnr) {
10422 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectKeyDownNoRepeat(*mDispatcher));
10423 mWindow->consumeKeyDown(ui::LogicalDisplayId::INVALID);
10424 ASSERT_TRUE(mDispatcher->waitForIdle());
10425 mFakePolicy->assertNotifyAnrWasNotCalled();
10426 }
10427
TEST_F(InputDispatcherSingleWindowAnr,WhenFocusedApplicationChanges_NoAnr)10428 TEST_F(InputDispatcherSingleWindowAnr, WhenFocusedApplicationChanges_NoAnr) {
10429 mWindow->setFocusable(false);
10430 mDispatcher->onWindowInfosChanged({{*mWindow->getInfo()}, {}, 0, 0});
10431 mWindow->consumeFocusEvent(false);
10432
10433 InputEventInjectionResult result =
10434 injectKey(*mDispatcher, AKEY_EVENT_ACTION_DOWN, /*repeatCount=*/0,
10435 ui::LogicalDisplayId::DEFAULT, InputEventInjectionSync::NONE,
10436 CONSUME_TIMEOUT_EVENT_EXPECTED,
10437 /*allowKeyRepeat=*/false);
10438 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, result);
10439 // Key will not go to window because we have no focused window.
10440 // The 'no focused window' ANR timer should start instead.
10441
10442 // Now, the focused application goes away.
10443 mDispatcher->setFocusedApplication(ui::LogicalDisplayId::DEFAULT, nullptr);
10444 // The key should get dropped and there should be no ANR.
10445
10446 ASSERT_TRUE(mDispatcher->waitForIdle());
10447 mFakePolicy->assertNotifyAnrWasNotCalled();
10448 }
10449
10450 // Send an event to the app and have the app not respond right away.
10451 // When ANR is raised, policy will tell the dispatcher to cancel the events for that window.
10452 // So InputDispatcher will enqueue ACTION_CANCEL event as well.
TEST_F(InputDispatcherSingleWindowAnr,OnPointerDown_BasicAnr)10453 TEST_F(InputDispatcherSingleWindowAnr, OnPointerDown_BasicAnr) {
10454 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
10455 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN,
10456 ui::LogicalDisplayId::DEFAULT, WINDOW_LOCATION));
10457
10458 const auto [sequenceNum, _] = mWindow->receiveEvent(); // ACTION_DOWN
10459 ASSERT_TRUE(sequenceNum);
10460 const std::chrono::duration timeout = mWindow->getDispatchingTimeout(DISPATCHING_TIMEOUT);
10461 mFakePolicy->assertNotifyWindowUnresponsiveWasCalled(timeout, mWindow);
10462
10463 mWindow->finishEvent(*sequenceNum);
10464 mWindow->consumeMotionEvent(
10465 AllOf(WithMotionAction(ACTION_CANCEL), WithDisplayId(ui::LogicalDisplayId::DEFAULT)));
10466 ASSERT_TRUE(mDispatcher->waitForIdle());
10467 mFakePolicy->assertNotifyWindowResponsiveWasCalled(mWindow->getToken(), mWindow->getPid());
10468 }
10469
10470 // Send a key to the app and have the app not respond right away.
TEST_F(InputDispatcherSingleWindowAnr,OnKeyDown_BasicAnr)10471 TEST_F(InputDispatcherSingleWindowAnr, OnKeyDown_BasicAnr) {
10472 // Inject a key, and don't respond - expect that ANR is called.
10473 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectKeyDownNoRepeat(*mDispatcher));
10474 const auto [sequenceNum, _] = mWindow->receiveEvent();
10475 ASSERT_TRUE(sequenceNum);
10476 const std::chrono::duration timeout = mWindow->getDispatchingTimeout(DISPATCHING_TIMEOUT);
10477 mFakePolicy->assertNotifyWindowUnresponsiveWasCalled(timeout, mWindow);
10478 ASSERT_TRUE(mDispatcher->waitForIdle());
10479 }
10480
10481 // We have a focused application, but no focused window
TEST_F(InputDispatcherSingleWindowAnr,FocusedApplication_NoFocusedWindow)10482 TEST_F(InputDispatcherSingleWindowAnr, FocusedApplication_NoFocusedWindow) {
10483 mWindow->setFocusable(false);
10484 mDispatcher->onWindowInfosChanged({{*mWindow->getInfo()}, {}, 0, 0});
10485 mWindow->consumeFocusEvent(false);
10486
10487 // taps on the window work as normal
10488 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
10489 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN,
10490 ui::LogicalDisplayId::DEFAULT, WINDOW_LOCATION));
10491 ASSERT_NO_FATAL_FAILURE(mWindow->consumeMotionDown());
10492 mDispatcher->waitForIdle();
10493 mFakePolicy->assertNotifyAnrWasNotCalled();
10494
10495 // Once a focused event arrives, we get an ANR for this application
10496 // We specify the injection timeout to be smaller than the application timeout, to ensure that
10497 // injection times out (instead of failing).
10498 const InputEventInjectionResult result =
10499 injectKey(*mDispatcher, AKEY_EVENT_ACTION_DOWN, /*repeatCount=*/0,
10500 ui::LogicalDisplayId::DEFAULT, InputEventInjectionSync::WAIT_FOR_RESULT, 50ms,
10501 /*allowKeyRepeat=*/false);
10502 ASSERT_EQ(InputEventInjectionResult::TIMED_OUT, result);
10503 const std::chrono::duration timeout = mApplication->getDispatchingTimeout(DISPATCHING_TIMEOUT);
10504 mFakePolicy->assertNotifyNoFocusedWindowAnrWasCalled(timeout, mApplication);
10505 ASSERT_TRUE(mDispatcher->waitForIdle());
10506 }
10507
10508 /**
10509 * Make sure the stale key is dropped before causing an ANR. So even if there's no focused window,
10510 * there will not be an ANR.
10511 */
TEST_F(InputDispatcherSingleWindowAnr,StaleKeyEventDoesNotAnr)10512 TEST_F(InputDispatcherSingleWindowAnr, StaleKeyEventDoesNotAnr) {
10513 mWindow->setFocusable(false);
10514 mDispatcher->onWindowInfosChanged({{*mWindow->getInfo()}, {}, 0, 0});
10515 mWindow->consumeFocusEvent(false);
10516
10517 KeyEvent event;
10518 static constexpr std::chrono::duration STALE_EVENT_TIMEOUT = 1000ms;
10519 mFakePolicy->setStaleEventTimeout(STALE_EVENT_TIMEOUT);
10520 const nsecs_t eventTime = systemTime(SYSTEM_TIME_MONOTONIC) -
10521 std::chrono::nanoseconds(STALE_EVENT_TIMEOUT).count();
10522
10523 // Define a valid key down event that is stale (too old).
10524 event.initialize(InputEvent::nextId(), DEVICE_ID, AINPUT_SOURCE_KEYBOARD,
10525 ui::LogicalDisplayId::INVALID, INVALID_HMAC, AKEY_EVENT_ACTION_DOWN,
10526 /*flags=*/0, AKEYCODE_A, KEY_A, AMETA_NONE, /*repeatCount=*/0, eventTime,
10527 eventTime);
10528
10529 const int32_t policyFlags =
10530 POLICY_FLAG_FILTERED | POLICY_FLAG_PASS_TO_USER | POLICY_FLAG_DISABLE_KEY_REPEAT;
10531
10532 InputEventInjectionResult result =
10533 mDispatcher->injectInputEvent(&event, /*targetUid=*/{},
10534 InputEventInjectionSync::WAIT_FOR_RESULT,
10535 INJECT_EVENT_TIMEOUT, policyFlags);
10536 ASSERT_EQ(InputEventInjectionResult::FAILED, result)
10537 << "Injection should fail because the event is stale";
10538
10539 ASSERT_TRUE(mDispatcher->waitForIdle());
10540 mFakePolicy->assertNotifyAnrWasNotCalled();
10541 mWindow->assertNoEvents();
10542 }
10543
10544 // We have a focused application, but no focused window
10545 // Make sure that we don't notify policy twice about the same ANR.
TEST_F(InputDispatcherSingleWindowAnr,NoFocusedWindow_DoesNotSendDuplicateAnr)10546 TEST_F(InputDispatcherSingleWindowAnr, NoFocusedWindow_DoesNotSendDuplicateAnr) {
10547 const std::chrono::duration appTimeout = 400ms;
10548 mApplication->setDispatchingTimeout(appTimeout);
10549 mDispatcher->setFocusedApplication(ui::LogicalDisplayId::DEFAULT, mApplication);
10550
10551 mWindow->setFocusable(false);
10552 mDispatcher->onWindowInfosChanged({{*mWindow->getInfo()}, {}, 0, 0});
10553 mWindow->consumeFocusEvent(false);
10554
10555 // Once a focused event arrives, we get an ANR for this application
10556 // We specify the injection timeout to be smaller than the application timeout, to ensure that
10557 // injection times out (instead of failing).
10558 const std::chrono::duration eventInjectionTimeout = 100ms;
10559 ASSERT_LT(eventInjectionTimeout, appTimeout);
10560 const InputEventInjectionResult result =
10561 injectKey(*mDispatcher, AKEY_EVENT_ACTION_DOWN, /*repeatCount=*/0,
10562 ui::LogicalDisplayId::DEFAULT, InputEventInjectionSync::WAIT_FOR_RESULT,
10563 eventInjectionTimeout,
10564 /*allowKeyRepeat=*/false);
10565 ASSERT_EQ(InputEventInjectionResult::TIMED_OUT, result)
10566 << "result=" << ftl::enum_string(result);
10567 // We already waited for 'eventInjectionTimeout`, because the countdown started when the event
10568 // was first injected. So now we have (appTimeout - eventInjectionTimeout) left to wait.
10569 std::chrono::duration remainingWaitTime = appTimeout - eventInjectionTimeout;
10570 mFakePolicy->assertNotifyNoFocusedWindowAnrWasCalled(remainingWaitTime, mApplication);
10571
10572 std::this_thread::sleep_for(appTimeout);
10573 // ANR should not be raised again. It is up to policy to do that if it desires.
10574 mFakePolicy->assertNotifyAnrWasNotCalled();
10575
10576 // If we now get a focused window, the ANR should stop, but the policy handles that via
10577 // 'notifyFocusChanged' callback. This is implemented in the policy so we can't test it here.
10578 ASSERT_TRUE(mDispatcher->waitForIdle());
10579 }
10580
10581 // We have a focused application, but no focused window
TEST_F(InputDispatcherSingleWindowAnr,NoFocusedWindow_DropsFocusedEvents)10582 TEST_F(InputDispatcherSingleWindowAnr, NoFocusedWindow_DropsFocusedEvents) {
10583 mWindow->setFocusable(false);
10584 mDispatcher->onWindowInfosChanged({{*mWindow->getInfo()}, {}, 0, 0});
10585 mWindow->consumeFocusEvent(false);
10586
10587 // Once a focused event arrives, we get an ANR for this application
10588 ASSERT_NO_FATAL_FAILURE(assertInjectedKeyTimesOut(*mDispatcher));
10589
10590 const std::chrono::duration timeout = mApplication->getDispatchingTimeout(DISPATCHING_TIMEOUT);
10591 mFakePolicy->assertNotifyNoFocusedWindowAnrWasCalled(timeout, mApplication);
10592
10593 // Future focused events get dropped right away
10594 ASSERT_EQ(InputEventInjectionResult::FAILED, injectKeyDown(*mDispatcher));
10595 ASSERT_TRUE(mDispatcher->waitForIdle());
10596 mWindow->assertNoEvents();
10597 }
10598
10599 /**
10600 * Ensure that the implementation is valid. Since we are using multiset to keep track of the
10601 * ANR timeouts, we are allowing entries with identical timestamps in the same connection.
10602 * If we process 1 of the events, but ANR on the second event with the same timestamp,
10603 * the ANR mechanism should still work.
10604 *
10605 * In this test, we are injecting DOWN and UP events with the same timestamps, and acknowledging the
10606 * DOWN event, while not responding on the second one.
10607 */
TEST_F(InputDispatcherSingleWindowAnr,Anr_HandlesEventsWithIdenticalTimestamps)10608 TEST_F(InputDispatcherSingleWindowAnr, Anr_HandlesEventsWithIdenticalTimestamps) {
10609 nsecs_t currentTime = systemTime(SYSTEM_TIME_MONOTONIC);
10610 injectMotionEvent(*mDispatcher, AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN,
10611 ui::LogicalDisplayId::DEFAULT, WINDOW_LOCATION,
10612 {AMOTION_EVENT_INVALID_CURSOR_POSITION,
10613 AMOTION_EVENT_INVALID_CURSOR_POSITION},
10614 500ms, InputEventInjectionSync::WAIT_FOR_RESULT, currentTime);
10615
10616 // Now send ACTION_UP, with identical timestamp
10617 injectMotionEvent(*mDispatcher, AMOTION_EVENT_ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN,
10618 ui::LogicalDisplayId::DEFAULT, WINDOW_LOCATION,
10619 {AMOTION_EVENT_INVALID_CURSOR_POSITION,
10620 AMOTION_EVENT_INVALID_CURSOR_POSITION},
10621 500ms, InputEventInjectionSync::WAIT_FOR_RESULT, currentTime);
10622
10623 // We have now sent down and up. Let's consume first event and then ANR on the second.
10624 mWindow->consumeMotionDown(ui::LogicalDisplayId::DEFAULT);
10625 const std::chrono::duration timeout = mWindow->getDispatchingTimeout(DISPATCHING_TIMEOUT);
10626 mFakePolicy->assertNotifyWindowUnresponsiveWasCalled(timeout, mWindow);
10627 }
10628
10629 // A spy window can receive an ANR
TEST_F(InputDispatcherSingleWindowAnr,SpyWindowAnr)10630 TEST_F(InputDispatcherSingleWindowAnr, SpyWindowAnr) {
10631 sp<FakeWindowHandle> spy = addSpyWindow();
10632
10633 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
10634 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN,
10635 ui::LogicalDisplayId::DEFAULT, WINDOW_LOCATION));
10636 mWindow->consumeMotionDown();
10637
10638 const auto [sequenceNum, _] = spy->receiveEvent(); // ACTION_DOWN
10639 ASSERT_TRUE(sequenceNum);
10640 const std::chrono::duration timeout = spy->getDispatchingTimeout(DISPATCHING_TIMEOUT);
10641 mFakePolicy->assertNotifyWindowUnresponsiveWasCalled(timeout, spy);
10642
10643 spy->finishEvent(*sequenceNum);
10644 spy->consumeMotionEvent(
10645 AllOf(WithMotionAction(ACTION_CANCEL), WithDisplayId(ui::LogicalDisplayId::DEFAULT)));
10646 ASSERT_TRUE(mDispatcher->waitForIdle());
10647 mFakePolicy->assertNotifyWindowResponsiveWasCalled(spy->getToken(), mWindow->getPid());
10648 }
10649
10650 // If an app is not responding to a key event, spy windows should continue to receive
10651 // new motion events
TEST_F(InputDispatcherSingleWindowAnr,SpyWindowReceivesEventsDuringAppAnrOnKey)10652 TEST_F(InputDispatcherSingleWindowAnr, SpyWindowReceivesEventsDuringAppAnrOnKey) {
10653 sp<FakeWindowHandle> spy = addSpyWindow();
10654
10655 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
10656 injectKeyDown(*mDispatcher, ui::LogicalDisplayId::DEFAULT));
10657 mWindow->consumeKeyDown(ui::LogicalDisplayId::DEFAULT);
10658 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
10659 injectKeyUp(*mDispatcher, ui::LogicalDisplayId::DEFAULT));
10660
10661 // Stuck on the ACTION_UP
10662 const std::chrono::duration timeout = mWindow->getDispatchingTimeout(DISPATCHING_TIMEOUT);
10663 mFakePolicy->assertNotifyWindowUnresponsiveWasCalled(timeout, mWindow);
10664
10665 // New tap will go to the spy window, but not to the window
10666 tapOnWindow();
10667 spy->consumeMotionDown(ui::LogicalDisplayId::DEFAULT);
10668 spy->consumeMotionUp(ui::LogicalDisplayId::DEFAULT);
10669
10670 mWindow->consumeKeyUp(ui::LogicalDisplayId::DEFAULT); // still the previous motion
10671 mDispatcher->waitForIdle();
10672 mFakePolicy->assertNotifyWindowResponsiveWasCalled(mWindow->getToken(), mWindow->getPid());
10673 mWindow->assertNoEvents();
10674 spy->assertNoEvents();
10675 }
10676
10677 // If an app is not responding to a motion event, spy windows should continue to receive
10678 // new motion events
TEST_F(InputDispatcherSingleWindowAnr,SpyWindowReceivesEventsDuringAppAnrOnMotion)10679 TEST_F(InputDispatcherSingleWindowAnr, SpyWindowReceivesEventsDuringAppAnrOnMotion) {
10680 sp<FakeWindowHandle> spy = addSpyWindow();
10681
10682 tapOnWindow();
10683 spy->consumeMotionDown(ui::LogicalDisplayId::DEFAULT);
10684 spy->consumeMotionUp(ui::LogicalDisplayId::DEFAULT);
10685
10686 mWindow->consumeMotionDown();
10687 // Stuck on the ACTION_UP
10688 const std::chrono::duration timeout = mWindow->getDispatchingTimeout(DISPATCHING_TIMEOUT);
10689 mFakePolicy->assertNotifyWindowUnresponsiveWasCalled(timeout, mWindow);
10690
10691 // New tap will go to the spy window, but not to the window
10692 tapOnWindow();
10693 spy->consumeMotionDown(ui::LogicalDisplayId::DEFAULT);
10694 spy->consumeMotionUp(ui::LogicalDisplayId::DEFAULT);
10695
10696 mWindow->consumeMotionUp(ui::LogicalDisplayId::DEFAULT); // still the previous motion
10697 mDispatcher->waitForIdle();
10698 mFakePolicy->assertNotifyWindowResponsiveWasCalled(mWindow->getToken(), mWindow->getPid());
10699 mWindow->assertNoEvents();
10700 spy->assertNoEvents();
10701 }
10702
TEST_F(InputDispatcherSingleWindowAnr,UnresponsiveMonitorAnr)10703 TEST_F(InputDispatcherSingleWindowAnr, UnresponsiveMonitorAnr) {
10704 mDispatcher->setMonitorDispatchingTimeoutForTest(SPY_TIMEOUT);
10705
10706 FakeMonitorReceiver monitor =
10707 FakeMonitorReceiver(*mDispatcher, "M_1", ui::LogicalDisplayId::DEFAULT);
10708
10709 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
10710 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN,
10711 ui::LogicalDisplayId::DEFAULT, WINDOW_LOCATION));
10712
10713 mWindow->consumeMotionDown(ui::LogicalDisplayId::DEFAULT);
10714 const std::optional<uint32_t> consumeSeq = monitor.receiveEvent();
10715 ASSERT_TRUE(consumeSeq);
10716
10717 mFakePolicy->assertNotifyWindowUnresponsiveWasCalled(SPY_TIMEOUT, monitor.getToken(),
10718 MONITOR_PID);
10719
10720 monitor.finishEvent(*consumeSeq);
10721 monitor.consumeMotionCancel(ui::LogicalDisplayId::DEFAULT);
10722
10723 ASSERT_TRUE(mDispatcher->waitForIdle());
10724 mFakePolicy->assertNotifyWindowResponsiveWasCalled(monitor.getToken(), MONITOR_PID);
10725 }
10726
10727 // If a window is unresponsive, then you get anr. if the window later catches up and starts to
10728 // process events, you don't get an anr. When the window later becomes unresponsive again, you
10729 // get an ANR again.
10730 // 1. tap -> block on ACTION_UP -> receive ANR
10731 // 2. consume all pending events (= queue becomes healthy again)
10732 // 3. tap again -> block on ACTION_UP again -> receive ANR second time
TEST_F(InputDispatcherSingleWindowAnr,SameWindow_CanReceiveAnrTwice)10733 TEST_F(InputDispatcherSingleWindowAnr, SameWindow_CanReceiveAnrTwice) {
10734 tapOnWindow();
10735
10736 mWindow->consumeMotionDown();
10737 // Block on ACTION_UP
10738 const std::chrono::duration timeout = mWindow->getDispatchingTimeout(DISPATCHING_TIMEOUT);
10739 mFakePolicy->assertNotifyWindowUnresponsiveWasCalled(timeout, mWindow);
10740 mWindow->consumeMotionUp(); // Now the connection should be healthy again
10741 mDispatcher->waitForIdle();
10742 mFakePolicy->assertNotifyWindowResponsiveWasCalled(mWindow->getToken(), mWindow->getPid());
10743 mWindow->assertNoEvents();
10744
10745 tapOnWindow();
10746 mWindow->consumeMotionDown();
10747 mFakePolicy->assertNotifyWindowUnresponsiveWasCalled(timeout, mWindow);
10748 mWindow->consumeMotionUp();
10749
10750 mDispatcher->waitForIdle();
10751 mFakePolicy->assertNotifyWindowResponsiveWasCalled(mWindow->getToken(), mWindow->getPid());
10752 mFakePolicy->assertNotifyAnrWasNotCalled();
10753 mWindow->assertNoEvents();
10754 }
10755
10756 // If a connection remains unresponsive for a while, make sure policy is only notified once about
10757 // it.
TEST_F(InputDispatcherSingleWindowAnr,Policy_DoesNotGetDuplicateAnr)10758 TEST_F(InputDispatcherSingleWindowAnr, Policy_DoesNotGetDuplicateAnr) {
10759 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
10760 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN,
10761 ui::LogicalDisplayId::DEFAULT, WINDOW_LOCATION));
10762
10763 const std::chrono::duration windowTimeout = mWindow->getDispatchingTimeout(DISPATCHING_TIMEOUT);
10764 mFakePolicy->assertNotifyWindowUnresponsiveWasCalled(windowTimeout, mWindow);
10765 std::this_thread::sleep_for(windowTimeout);
10766 // 'notifyConnectionUnresponsive' should only be called once per connection
10767 mFakePolicy->assertNotifyAnrWasNotCalled();
10768 // When the ANR happened, dispatcher should abort the current event stream via ACTION_CANCEL
10769 mWindow->consumeMotionDown();
10770 mWindow->consumeMotionEvent(
10771 AllOf(WithMotionAction(ACTION_CANCEL), WithDisplayId(ui::LogicalDisplayId::DEFAULT)));
10772 mWindow->assertNoEvents();
10773 mDispatcher->waitForIdle();
10774 mFakePolicy->assertNotifyWindowResponsiveWasCalled(mWindow->getToken(), mWindow->getPid());
10775 mFakePolicy->assertNotifyAnrWasNotCalled();
10776 }
10777
10778 /**
10779 * If a window is processing a motion event, and then a key event comes in, the key event should
10780 * not get delivered to the focused window until the motion is processed.
10781 */
TEST_F(InputDispatcherSingleWindowAnr,Key_StaysPendingWhileMotionIsProcessed)10782 TEST_F(InputDispatcherSingleWindowAnr, Key_StaysPendingWhileMotionIsProcessed) {
10783 // The timeouts in this test are established by relying on the fact that the "key waiting for
10784 // events timeout" is equal to 500ms.
10785 ASSERT_EQ(mFakePolicy->getKeyWaitingForEventsTimeout(), 500ms);
10786 mWindow->setDispatchingTimeout(2s); // Set a long ANR timeout to prevent it from triggering
10787 mDispatcher->onWindowInfosChanged({{*mWindow->getInfo()}, {}, 0, 0});
10788
10789 tapOnWindow();
10790 const auto& [downSequenceNum, downEvent] = mWindow->receiveEvent();
10791 ASSERT_TRUE(downSequenceNum);
10792 const auto& [upSequenceNum, upEvent] = mWindow->receiveEvent();
10793 ASSERT_TRUE(upSequenceNum);
10794
10795 // Don't finish the events yet, and send a key
10796 mDispatcher->notifyKey(
10797 KeyArgsBuilder(AKEY_EVENT_ACTION_DOWN, AINPUT_SOURCE_KEYBOARD)
10798 .policyFlags(DEFAULT_POLICY_FLAGS | POLICY_FLAG_DISABLE_KEY_REPEAT)
10799 .build());
10800 // Key will not be sent to the window, yet, because the window is still processing events
10801 // and the key remains pending, waiting for the touch events to be processed
10802 // Make sure that `assertNoEvents` doesn't wait too long, because it could cause an ANR.
10803 mWindow->assertNoEvents(100ms);
10804
10805 std::this_thread::sleep_for(400ms);
10806 // if we wait long enough though, dispatcher will give up, and still send the key
10807 // to the focused window, even though we have not yet finished the motion event
10808 mWindow->consumeKeyDown(ui::LogicalDisplayId::DEFAULT);
10809 mWindow->finishEvent(*downSequenceNum);
10810 mWindow->finishEvent(*upSequenceNum);
10811 }
10812
10813 /**
10814 * If a window is processing a motion event, and then a key event comes in, the key event should
10815 * not go to the focused window until the motion is processed.
10816 * If then a new motion comes in, then the pending key event should be going to the currently
10817 * focused window right away.
10818 */
TEST_F(InputDispatcherSingleWindowAnr,PendingKey_IsDeliveredWhileMotionIsProcessingAndNewTouchComesIn)10819 TEST_F(InputDispatcherSingleWindowAnr,
10820 PendingKey_IsDeliveredWhileMotionIsProcessingAndNewTouchComesIn) {
10821 // The timeouts in this test are established by relying on the fact that the "key waiting for
10822 // events timeout" is equal to 500ms.
10823 ASSERT_EQ(mFakePolicy->getKeyWaitingForEventsTimeout(), 500ms);
10824 mWindow->setDispatchingTimeout(2s); // Set a long ANR timeout to prevent it from triggering
10825 mDispatcher->onWindowInfosChanged({{*mWindow->getInfo()}, {}, 0, 0});
10826
10827 tapOnWindow();
10828 const auto& [downSequenceNum, _] = mWindow->receiveEvent();
10829 ASSERT_TRUE(downSequenceNum);
10830 const auto& [upSequenceNum, upEvent] = mWindow->receiveEvent();
10831 ASSERT_TRUE(upSequenceNum);
10832 // Don't finish the events yet, and send a key
10833 mDispatcher->notifyKey(
10834 KeyArgsBuilder(AKEY_EVENT_ACTION_DOWN, AINPUT_SOURCE_KEYBOARD)
10835 .policyFlags(DEFAULT_POLICY_FLAGS | POLICY_FLAG_DISABLE_KEY_REPEAT)
10836 .build());
10837 // At this point, key is still pending, and should not be sent to the application yet.
10838 mWindow->assertNoEvents(100ms);
10839
10840 // Now tap down again. It should cause the pending key to go to the focused window right away.
10841 tapOnWindow();
10842 // Now that we tapped, we should receive the key immediately.
10843 // Since there's still room for slowness, we use 200ms, which is much less than
10844 // the "key waiting for events' timeout of 500ms minus the already waited 100ms duration.
10845 std::unique_ptr<InputEvent> keyEvent = mWindow->consume(200ms);
10846 ASSERT_NE(nullptr, keyEvent);
10847 ASSERT_EQ(InputEventType::KEY, keyEvent->getType());
10848 ASSERT_THAT(static_cast<KeyEvent&>(*keyEvent), WithKeyAction(AKEY_EVENT_ACTION_DOWN));
10849 // it doesn't matter that we haven't ack'd the other events yet. We can finish events in any
10850 // order.
10851 mWindow->finishEvent(*downSequenceNum); // first tap's ACTION_DOWN
10852 mWindow->finishEvent(*upSequenceNum); // first tap's ACTION_UP
10853 mWindow->consumeMotionEvent(WithMotionAction(ACTION_DOWN));
10854 mWindow->consumeMotionEvent(WithMotionAction(ACTION_UP));
10855 mWindow->assertNoEvents();
10856 }
10857
10858 /**
10859 * Send an event to the app and have the app not respond right away.
10860 * When ANR is raised, policy will tell the dispatcher to cancel the events for that window.
10861 * So InputDispatcher will enqueue ACTION_CANCEL event as well.
10862 * At some point, the window becomes responsive again.
10863 * Ensure that subsequent events get dropped, and the next gesture is delivered.
10864 */
TEST_F(InputDispatcherSingleWindowAnr,TwoGesturesWithAnr)10865 TEST_F(InputDispatcherSingleWindowAnr, TwoGesturesWithAnr) {
10866 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
10867 .pointer(PointerBuilder(0, ToolType::FINGER).x(10).y(10))
10868 .build());
10869
10870 const auto [sequenceNum, _] = mWindow->receiveEvent(); // ACTION_DOWN
10871 ASSERT_TRUE(sequenceNum);
10872 const std::chrono::duration timeout = mWindow->getDispatchingTimeout(DISPATCHING_TIMEOUT);
10873 mFakePolicy->assertNotifyWindowUnresponsiveWasCalled(timeout, mWindow);
10874
10875 mWindow->finishEvent(*sequenceNum);
10876 mWindow->consumeMotionEvent(WithMotionAction(ACTION_CANCEL));
10877 ASSERT_TRUE(mDispatcher->waitForIdle());
10878 mFakePolicy->assertNotifyWindowResponsiveWasCalled(mWindow->getToken(), mWindow->getPid());
10879
10880 // Now that the window is responsive, let's continue the gesture.
10881 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN)
10882 .pointer(PointerBuilder(0, ToolType::FINGER).x(11).y(11))
10883 .build());
10884
10885 mDispatcher->notifyMotion(MotionArgsBuilder(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
10886 .pointer(PointerBuilder(0, ToolType::FINGER).x(11).y(11))
10887 .pointer(PointerBuilder(1, ToolType::FINGER).x(3).y(3))
10888 .build());
10889
10890 mDispatcher->notifyMotion(MotionArgsBuilder(POINTER_1_UP, AINPUT_SOURCE_TOUCHSCREEN)
10891 .pointer(PointerBuilder(0, ToolType::FINGER).x(11).y(11))
10892 .pointer(PointerBuilder(1, ToolType::FINGER).x(3).y(3))
10893 .build());
10894 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN)
10895 .pointer(PointerBuilder(0, ToolType::FINGER).x(11).y(11))
10896 .build());
10897 // We already canceled this pointer, so the window shouldn't get any new events.
10898 mWindow->assertNoEvents();
10899
10900 // Start another one.
10901 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
10902 .pointer(PointerBuilder(0, ToolType::FINGER).x(15).y(15))
10903 .build());
10904 mWindow->consumeMotionEvent(WithMotionAction(ACTION_DOWN));
10905 }
10906
10907 // Send an event to the app and have the app not respond right away. Then remove the app window.
10908 // When the window is removed, the dispatcher will cancel the events for that window.
10909 // So InputDispatcher will enqueue ACTION_CANCEL event as well.
TEST_F(InputDispatcherSingleWindowAnr,AnrAfterWindowRemoval)10910 TEST_F(InputDispatcherSingleWindowAnr, AnrAfterWindowRemoval) {
10911 mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_DOWN,
10912 AINPUT_SOURCE_TOUCHSCREEN,
10913 ui::LogicalDisplayId::DEFAULT, {WINDOW_LOCATION}));
10914
10915 const auto [sequenceNum, _] = mWindow->receiveEvent(); // ACTION_DOWN
10916 ASSERT_TRUE(sequenceNum);
10917
10918 // Remove the window, but the input channel should remain alive.
10919 mDispatcher->onWindowInfosChanged({{}, {}, 0, 0});
10920
10921 const std::chrono::duration timeout = mWindow->getDispatchingTimeout(DISPATCHING_TIMEOUT);
10922 // Since the window was removed, Dispatcher does not know the PID associated with the window
10923 // anymore, so the policy is notified without the PID.
10924 mFakePolicy->assertNotifyWindowUnresponsiveWasCalled(timeout, mWindow->getToken(),
10925 /*pid=*/std::nullopt);
10926
10927 mWindow->finishEvent(*sequenceNum);
10928 // The cancellation was generated when the window was removed, along with the focus event.
10929 mWindow->consumeMotionEvent(
10930 AllOf(WithMotionAction(ACTION_CANCEL), WithDisplayId(ui::LogicalDisplayId::DEFAULT)));
10931 mWindow->consumeFocusEvent(false);
10932 ASSERT_TRUE(mDispatcher->waitForIdle());
10933 mFakePolicy->assertNotifyWindowResponsiveWasCalled(mWindow->getToken(), /*pid=*/std::nullopt);
10934 }
10935
10936 // Send an event to the app and have the app not respond right away. Wait for the policy to be
10937 // notified of the unresponsive window, then remove the app window.
TEST_F(InputDispatcherSingleWindowAnr,AnrFollowedByWindowRemoval)10938 TEST_F(InputDispatcherSingleWindowAnr, AnrFollowedByWindowRemoval) {
10939 mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_DOWN,
10940 AINPUT_SOURCE_TOUCHSCREEN,
10941 ui::LogicalDisplayId::DEFAULT, {WINDOW_LOCATION}));
10942
10943 const auto [sequenceNum, _] = mWindow->receiveEvent(); // ACTION_DOWN
10944 ASSERT_TRUE(sequenceNum);
10945 const std::chrono::duration timeout = mWindow->getDispatchingTimeout(DISPATCHING_TIMEOUT);
10946 mFakePolicy->assertNotifyWindowUnresponsiveWasCalled(timeout, mWindow);
10947
10948 // Remove the window, but the input channel should remain alive.
10949 mDispatcher->onWindowInfosChanged({{}, {}, 0, 0});
10950
10951 mWindow->finishEvent(*sequenceNum);
10952 // The cancellation was generated during the ANR, and the window lost focus when it was removed.
10953 mWindow->consumeMotionEvent(
10954 AllOf(WithMotionAction(ACTION_CANCEL), WithDisplayId(ui::LogicalDisplayId::DEFAULT)));
10955 mWindow->consumeFocusEvent(false);
10956 ASSERT_TRUE(mDispatcher->waitForIdle());
10957 // Since the window was removed, Dispatcher does not know the PID associated with the window
10958 // becoming responsive, so the policy is notified without the PID.
10959 mFakePolicy->assertNotifyWindowResponsiveWasCalled(mWindow->getToken(), /*pid=*/std::nullopt);
10960 }
10961
10962 class InputDispatcherMultiWindowAnr : public InputDispatcherTest {
SetUp()10963 virtual void SetUp() override {
10964 InputDispatcherTest::SetUp();
10965
10966 mApplication = std::make_shared<FakeApplicationHandle>();
10967 mApplication->setDispatchingTimeout(100ms);
10968 mUnfocusedWindow = sp<FakeWindowHandle>::make(mApplication, mDispatcher, "Unfocused",
10969 ui::LogicalDisplayId::DEFAULT);
10970 mUnfocusedWindow->setFrame(Rect(0, 0, 30, 30));
10971 // Adding FLAG_WATCH_OUTSIDE_TOUCH to receive ACTION_OUTSIDE when another window is tapped
10972 mUnfocusedWindow->setWatchOutsideTouch(true);
10973
10974 mFocusedWindow = sp<FakeWindowHandle>::make(mApplication, mDispatcher, "Focused",
10975 ui::LogicalDisplayId::DEFAULT);
10976 mFocusedWindow->setDispatchingTimeout(100ms);
10977 mFocusedWindow->setFrame(Rect(50, 50, 100, 100));
10978
10979 // Set focused application.
10980 mDispatcher->setFocusedApplication(ui::LogicalDisplayId::DEFAULT, mApplication);
10981 mFocusedWindow->setFocusable(true);
10982
10983 // Expect one focus window exist in display.
10984 mDispatcher->onWindowInfosChanged(
10985 {{*mUnfocusedWindow->getInfo(), *mFocusedWindow->getInfo()}, {}, 0, 0});
10986 setFocusedWindow(mFocusedWindow);
10987 mFocusedWindow->consumeFocusEvent(true);
10988 }
10989
TearDown()10990 virtual void TearDown() override {
10991 InputDispatcherTest::TearDown();
10992
10993 mUnfocusedWindow.clear();
10994 mFocusedWindow.clear();
10995 }
10996
10997 protected:
10998 std::shared_ptr<FakeApplicationHandle> mApplication;
10999 sp<FakeWindowHandle> mUnfocusedWindow;
11000 sp<FakeWindowHandle> mFocusedWindow;
11001 static constexpr PointF UNFOCUSED_WINDOW_LOCATION = {20, 20};
11002 static constexpr PointF FOCUSED_WINDOW_LOCATION = {75, 75};
11003 static constexpr PointF LOCATION_OUTSIDE_ALL_WINDOWS = {40, 40};
11004
tapOnFocusedWindow()11005 void tapOnFocusedWindow() { tap(FOCUSED_WINDOW_LOCATION); }
11006
tapOnUnfocusedWindow()11007 void tapOnUnfocusedWindow() { tap(UNFOCUSED_WINDOW_LOCATION); }
11008
11009 private:
tap(const PointF & location)11010 void tap(const PointF& location) {
11011 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
11012 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN,
11013 ui::LogicalDisplayId::DEFAULT, location));
11014 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
11015 injectMotionUp(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN,
11016 ui::LogicalDisplayId::DEFAULT, location));
11017 }
11018 };
11019
11020 // If we have 2 windows that are both unresponsive, the one with the shortest timeout
11021 // should be ANR'd first.
TEST_F(InputDispatcherMultiWindowAnr,TwoWindows_BothUnresponsive)11022 TEST_F(InputDispatcherMultiWindowAnr, TwoWindows_BothUnresponsive) {
11023 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
11024 injectMotionEvent(*mDispatcher,
11025 MotionEventBuilder(AMOTION_EVENT_ACTION_DOWN,
11026 AINPUT_SOURCE_TOUCHSCREEN)
11027 .pointer(PointerBuilder(0, ToolType::FINGER)
11028 .x(FOCUSED_WINDOW_LOCATION.x)
11029 .y(FOCUSED_WINDOW_LOCATION.y))
11030 .build()));
11031 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
11032 injectMotionEvent(*mDispatcher,
11033 MotionEventBuilder(AMOTION_EVENT_ACTION_UP,
11034 AINPUT_SOURCE_TOUCHSCREEN)
11035 .pointer(PointerBuilder(0, ToolType::FINGER)
11036 .x(FOCUSED_WINDOW_LOCATION.x)
11037 .y(FOCUSED_WINDOW_LOCATION.y))
11038 .build()));
11039 mFocusedWindow->consumeMotionDown();
11040 mFocusedWindow->consumeMotionUp();
11041 mUnfocusedWindow->consumeMotionOutside(ui::LogicalDisplayId::DEFAULT, /*flags=*/0);
11042 // We consumed all events, so no ANR
11043 ASSERT_TRUE(mDispatcher->waitForIdle());
11044 mFakePolicy->assertNotifyAnrWasNotCalled();
11045
11046 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
11047 injectMotionEvent(*mDispatcher,
11048 MotionEventBuilder(AMOTION_EVENT_ACTION_DOWN,
11049 AINPUT_SOURCE_TOUCHSCREEN)
11050 .pointer(PointerBuilder(0, ToolType::FINGER)
11051 .x(FOCUSED_WINDOW_LOCATION.x)
11052 .y(FOCUSED_WINDOW_LOCATION.y))
11053 .build()));
11054 const auto [unfocusedSequenceNum, _] = mUnfocusedWindow->receiveEvent();
11055 ASSERT_TRUE(unfocusedSequenceNum);
11056
11057 const std::chrono::duration timeout =
11058 mFocusedWindow->getDispatchingTimeout(DISPATCHING_TIMEOUT);
11059 mFakePolicy->assertNotifyWindowUnresponsiveWasCalled(timeout, mFocusedWindow);
11060
11061 mUnfocusedWindow->finishEvent(*unfocusedSequenceNum);
11062 mFocusedWindow->consumeMotionDown();
11063 // This cancel is generated because the connection was unresponsive
11064 mFocusedWindow->consumeMotionCancel();
11065 mFocusedWindow->assertNoEvents();
11066 mUnfocusedWindow->assertNoEvents();
11067 ASSERT_TRUE(mDispatcher->waitForIdle());
11068 mFakePolicy->assertNotifyWindowResponsiveWasCalled(mFocusedWindow->getToken(),
11069 mFocusedWindow->getPid());
11070 mFakePolicy->assertNotifyAnrWasNotCalled();
11071 }
11072
11073 // If we have 2 windows with identical timeouts that are both unresponsive,
11074 // it doesn't matter which order they should have ANR.
11075 // But we should receive ANR for both.
TEST_F(InputDispatcherMultiWindowAnr,TwoWindows_BothUnresponsiveWithSameTimeout)11076 TEST_F(InputDispatcherMultiWindowAnr, TwoWindows_BothUnresponsiveWithSameTimeout) {
11077 // Set the timeout for unfocused window to match the focused window
11078 mUnfocusedWindow->setDispatchingTimeout(
11079 mFocusedWindow->getDispatchingTimeout(DISPATCHING_TIMEOUT));
11080 mDispatcher->onWindowInfosChanged(
11081 {{*mUnfocusedWindow->getInfo(), *mFocusedWindow->getInfo()}, {}, 0, 0});
11082
11083 tapOnFocusedWindow();
11084 // we should have ACTION_DOWN/ACTION_UP on focused window and ACTION_OUTSIDE on unfocused window
11085 // We don't know which window will ANR first. But both of them should happen eventually.
11086 std::array<sp<IBinder>, 2> anrConnectionTokens = {mFakePolicy->getUnresponsiveWindowToken(
11087 mFocusedWindow->getDispatchingTimeout(
11088 DISPATCHING_TIMEOUT)),
11089 mFakePolicy->getUnresponsiveWindowToken(0ms)};
11090
11091 ASSERT_THAT(anrConnectionTokens,
11092 ::testing::UnorderedElementsAre(testing::Eq(mFocusedWindow->getToken()),
11093 testing::Eq(mUnfocusedWindow->getToken())));
11094
11095 ASSERT_TRUE(mDispatcher->waitForIdle());
11096 mFakePolicy->assertNotifyAnrWasNotCalled();
11097
11098 mFocusedWindow->consumeMotionDown();
11099 mFocusedWindow->consumeMotionUp();
11100 mUnfocusedWindow->consumeMotionOutside();
11101
11102 std::array<sp<IBinder>, 2> responsiveTokens = {mFakePolicy->getResponsiveWindowToken(),
11103 mFakePolicy->getResponsiveWindowToken()};
11104
11105 // Both applications should be marked as responsive, in any order
11106 ASSERT_THAT(responsiveTokens,
11107 ::testing::UnorderedElementsAre(testing::Eq(mFocusedWindow->getToken()),
11108 testing::Eq(mUnfocusedWindow->getToken())));
11109 mFakePolicy->assertNotifyAnrWasNotCalled();
11110 }
11111
11112 // If a window is already not responding, the second tap on the same window should be ignored.
11113 // We should also log an error to account for the dropped event (not tested here).
11114 // At the same time, FLAG_WATCH_OUTSIDE_TOUCH targets should not receive any events.
TEST_F(InputDispatcherMultiWindowAnr,DuringAnr_SecondTapIsIgnored)11115 TEST_F(InputDispatcherMultiWindowAnr, DuringAnr_SecondTapIsIgnored) {
11116 tapOnFocusedWindow();
11117 mUnfocusedWindow->consumeMotionOutside(ui::LogicalDisplayId::DEFAULT, /*flags=*/0);
11118 // Receive the events, but don't respond
11119 const auto [downEventSequenceNum, downEvent] = mFocusedWindow->receiveEvent(); // ACTION_DOWN
11120 ASSERT_TRUE(downEventSequenceNum);
11121 const auto [upEventSequenceNum, upEvent] = mFocusedWindow->receiveEvent(); // ACTION_UP
11122 ASSERT_TRUE(upEventSequenceNum);
11123 const std::chrono::duration timeout =
11124 mFocusedWindow->getDispatchingTimeout(DISPATCHING_TIMEOUT);
11125 mFakePolicy->assertNotifyWindowUnresponsiveWasCalled(timeout, mFocusedWindow);
11126
11127 // Tap once again
11128 // We cannot use "tapOnFocusedWindow" because it asserts the injection result to be success
11129 ASSERT_EQ(InputEventInjectionResult::FAILED,
11130 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN,
11131 ui::LogicalDisplayId::DEFAULT, FOCUSED_WINDOW_LOCATION));
11132 ASSERT_EQ(InputEventInjectionResult::FAILED,
11133 injectMotionUp(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ui::LogicalDisplayId::DEFAULT,
11134 FOCUSED_WINDOW_LOCATION));
11135 // Unfocused window does not receive ACTION_OUTSIDE because the tapped window is not a
11136 // valid touch target
11137 mUnfocusedWindow->assertNoEvents();
11138
11139 // Consume the first tap
11140 mFocusedWindow->finishEvent(*downEventSequenceNum);
11141 mFocusedWindow->finishEvent(*upEventSequenceNum);
11142 ASSERT_TRUE(mDispatcher->waitForIdle());
11143 // The second tap did not go to the focused window
11144 mFocusedWindow->assertNoEvents();
11145 // Since all events are finished, connection should be deemed healthy again
11146 mFakePolicy->assertNotifyWindowResponsiveWasCalled(mFocusedWindow->getToken(),
11147 mFocusedWindow->getPid());
11148 mFakePolicy->assertNotifyAnrWasNotCalled();
11149 }
11150
11151 // If you tap outside of all windows, there will not be ANR
TEST_F(InputDispatcherMultiWindowAnr,TapOutsideAllWindows_DoesNotAnr)11152 TEST_F(InputDispatcherMultiWindowAnr, TapOutsideAllWindows_DoesNotAnr) {
11153 ASSERT_EQ(InputEventInjectionResult::FAILED,
11154 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN,
11155 ui::LogicalDisplayId::DEFAULT, LOCATION_OUTSIDE_ALL_WINDOWS));
11156 ASSERT_TRUE(mDispatcher->waitForIdle());
11157 mFakePolicy->assertNotifyAnrWasNotCalled();
11158 }
11159
11160 // Since the focused window is paused, tapping on it should not produce any events
TEST_F(InputDispatcherMultiWindowAnr,Window_CanBePaused)11161 TEST_F(InputDispatcherMultiWindowAnr, Window_CanBePaused) {
11162 mFocusedWindow->setPaused(true);
11163 mDispatcher->onWindowInfosChanged(
11164 {{*mUnfocusedWindow->getInfo(), *mFocusedWindow->getInfo()}, {}, 0, 0});
11165
11166 ASSERT_EQ(InputEventInjectionResult::FAILED,
11167 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN,
11168 ui::LogicalDisplayId::DEFAULT, FOCUSED_WINDOW_LOCATION));
11169
11170 std::this_thread::sleep_for(mFocusedWindow->getDispatchingTimeout(DISPATCHING_TIMEOUT));
11171 ASSERT_TRUE(mDispatcher->waitForIdle());
11172 // Should not ANR because the window is paused, and touches shouldn't go to it
11173 mFakePolicy->assertNotifyAnrWasNotCalled();
11174
11175 mFocusedWindow->assertNoEvents();
11176 mUnfocusedWindow->assertNoEvents();
11177 }
11178
11179 /**
11180 * If a window is processing a motion event, and then a key event comes in, the key event should
11181 * not get delivered to the focused window until the motion is processed.
11182 * If a different window becomes focused at this time, the key should go to that window instead.
11183 *
11184 * Warning!!!
11185 * This test depends on the value of android::inputdispatcher::KEY_WAITING_FOR_MOTION_TIMEOUT
11186 * and the injection timeout that we specify when injecting the key.
11187 * We must have the injection timeout (100ms) be smaller than
11188 * KEY_WAITING_FOR_MOTION_TIMEOUT (currently 500ms).
11189 *
11190 * If that value changes, this test should also change.
11191 */
TEST_F(InputDispatcherMultiWindowAnr,PendingKey_GoesToNewlyFocusedWindow)11192 TEST_F(InputDispatcherMultiWindowAnr, PendingKey_GoesToNewlyFocusedWindow) {
11193 // Set a long ANR timeout to prevent it from triggering
11194 mFocusedWindow->setDispatchingTimeout(2s);
11195 mDispatcher->onWindowInfosChanged(
11196 {{*mFocusedWindow->getInfo(), *mUnfocusedWindow->getInfo()}, {}, 0, 0});
11197
11198 tapOnUnfocusedWindow();
11199 const auto [downSequenceNum, downEvent] = mUnfocusedWindow->receiveEvent();
11200 ASSERT_TRUE(downSequenceNum);
11201 const auto [upSequenceNum, upEvent] = mUnfocusedWindow->receiveEvent();
11202 ASSERT_TRUE(upSequenceNum);
11203 // Don't finish the events yet, and send a key
11204 // Injection will succeed because we will eventually give up and send the key to the focused
11205 // window even if motions are still being processed.
11206
11207 InputEventInjectionResult result =
11208 injectKey(*mDispatcher, AKEY_EVENT_ACTION_DOWN, /*repeatCount=*/0,
11209 ui::LogicalDisplayId::DEFAULT, InputEventInjectionSync::NONE,
11210 /*injectionTimeout=*/100ms);
11211 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, result);
11212 // Key will not be sent to the window, yet, because the window is still processing events
11213 // and the key remains pending, waiting for the touch events to be processed.
11214 // Make sure `assertNoEvents` doesn't take too long. It uses CONSUME_TIMEOUT_NO_EVENT_EXPECTED
11215 // under the hood.
11216 static_assert(CONSUME_TIMEOUT_NO_EVENT_EXPECTED < 100ms);
11217 mFocusedWindow->assertNoEvents();
11218
11219 // Switch the focus to the "unfocused" window that we tapped. Expect the key to go there
11220 mFocusedWindow->setFocusable(false);
11221 mUnfocusedWindow->setFocusable(true);
11222 mDispatcher->onWindowInfosChanged(
11223 {{*mFocusedWindow->getInfo(), *mUnfocusedWindow->getInfo()}, {}, 0, 0});
11224 setFocusedWindow(mUnfocusedWindow);
11225
11226 // Focus events should precede the key events
11227 mUnfocusedWindow->consumeFocusEvent(true);
11228 mFocusedWindow->consumeFocusEvent(false);
11229
11230 // Finish the tap events, which should unblock dispatcher
11231 mUnfocusedWindow->finishEvent(*downSequenceNum);
11232 mUnfocusedWindow->finishEvent(*upSequenceNum);
11233
11234 // Now that all queues are cleared and no backlog in the connections, the key event
11235 // can finally go to the newly focused "mUnfocusedWindow".
11236 mUnfocusedWindow->consumeKeyDown(ui::LogicalDisplayId::DEFAULT);
11237 mFocusedWindow->assertNoEvents();
11238 mUnfocusedWindow->assertNoEvents();
11239 mFakePolicy->assertNotifyAnrWasNotCalled();
11240 }
11241
11242 // When the touch stream is split across 2 windows, and one of them does not respond,
11243 // then ANR should be raised and the touch should be canceled for the unresponsive window.
11244 // The other window should not be affected by that.
TEST_F(InputDispatcherMultiWindowAnr,SplitTouch_SingleWindowAnr)11245 TEST_F(InputDispatcherMultiWindowAnr, SplitTouch_SingleWindowAnr) {
11246 // Touch Window 1
11247 mDispatcher->notifyMotion(
11248 generateMotionArgs(AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN,
11249 ui::LogicalDisplayId::DEFAULT, {FOCUSED_WINDOW_LOCATION}));
11250 mUnfocusedWindow->consumeMotionOutside(ui::LogicalDisplayId::DEFAULT, /*flags=*/0);
11251
11252 // Touch Window 2
11253 mDispatcher->notifyMotion(
11254 generateMotionArgs(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN,
11255 ui::LogicalDisplayId::DEFAULT,
11256 {FOCUSED_WINDOW_LOCATION, UNFOCUSED_WINDOW_LOCATION}));
11257
11258 const std::chrono::duration timeout =
11259 mFocusedWindow->getDispatchingTimeout(DISPATCHING_TIMEOUT);
11260 mFakePolicy->assertNotifyWindowUnresponsiveWasCalled(timeout, mFocusedWindow);
11261
11262 mUnfocusedWindow->consumeMotionDown();
11263 mFocusedWindow->consumeMotionDown();
11264 // Focused window may or may not receive ACTION_MOVE
11265 // But it should definitely receive ACTION_CANCEL due to the ANR
11266 const auto [moveOrCancelSequenceNum, event] = mFocusedWindow->receiveEvent();
11267 ASSERT_TRUE(moveOrCancelSequenceNum);
11268 mFocusedWindow->finishEvent(*moveOrCancelSequenceNum);
11269 ASSERT_NE(nullptr, event);
11270 ASSERT_EQ(event->getType(), InputEventType::MOTION);
11271 MotionEvent& motionEvent = static_cast<MotionEvent&>(*event);
11272 if (motionEvent.getAction() == AMOTION_EVENT_ACTION_MOVE) {
11273 mFocusedWindow->consumeMotionCancel();
11274 } else {
11275 ASSERT_EQ(AMOTION_EVENT_ACTION_CANCEL, motionEvent.getAction());
11276 }
11277 ASSERT_TRUE(mDispatcher->waitForIdle());
11278 mFakePolicy->assertNotifyWindowResponsiveWasCalled(mFocusedWindow->getToken(),
11279 mFocusedWindow->getPid());
11280
11281 mUnfocusedWindow->assertNoEvents();
11282 mFocusedWindow->assertNoEvents();
11283 mFakePolicy->assertNotifyAnrWasNotCalled();
11284 }
11285
11286 /**
11287 * If we have no focused window, and a key comes in, we start the ANR timer.
11288 * The focused application should add a focused window before the timer runs out to prevent ANR.
11289 *
11290 * If the user touches another application during this time, the key should be dropped.
11291 * Next, if a new focused window comes in, without toggling the focused application,
11292 * then no ANR should occur.
11293 *
11294 * Normally, we would expect the new focused window to be accompanied by 'setFocusedApplication',
11295 * but in some cases the policy may not update the focused application.
11296 */
TEST_F(InputDispatcherMultiWindowAnr,FocusedWindowWithoutSetFocusedApplication_NoAnr)11297 TEST_F(InputDispatcherMultiWindowAnr, FocusedWindowWithoutSetFocusedApplication_NoAnr) {
11298 std::shared_ptr<FakeApplicationHandle> focusedApplication =
11299 std::make_shared<FakeApplicationHandle>();
11300 focusedApplication->setDispatchingTimeout(300ms);
11301 mDispatcher->setFocusedApplication(ui::LogicalDisplayId::DEFAULT, focusedApplication);
11302 // The application that owns 'mFocusedWindow' and 'mUnfocusedWindow' is not focused.
11303 mFocusedWindow->setFocusable(false);
11304
11305 mDispatcher->onWindowInfosChanged(
11306 {{*mFocusedWindow->getInfo(), *mUnfocusedWindow->getInfo()}, {}, 0, 0});
11307 mFocusedWindow->consumeFocusEvent(false);
11308
11309 // Send a key. The ANR timer should start because there is no focused window.
11310 // 'focusedApplication' will get blamed if this timer completes.
11311 // Key will not be sent anywhere because we have no focused window. It will remain pending.
11312 InputEventInjectionResult result =
11313 injectKey(*mDispatcher, AKEY_EVENT_ACTION_DOWN, /*repeatCount=*/0,
11314 ui::LogicalDisplayId::DEFAULT, InputEventInjectionSync::NONE,
11315 /*injectionTimeout=*/100ms,
11316 /*allowKeyRepeat=*/false);
11317 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, result);
11318
11319 // Wait until dispatcher starts the "no focused window" timer. If we don't wait here,
11320 // then the injected touches won't cause the focused event to get dropped.
11321 // The dispatcher only checks for whether the queue should be pruned upon queueing.
11322 // If we inject the touch right away and the ANR timer hasn't started, the touch event would
11323 // simply be added to the queue without 'shouldPruneInboundQueueLocked' returning 'true'.
11324 // For this test, it means that the key would get delivered to the window once it becomes
11325 // focused.
11326 std::this_thread::sleep_for(100ms);
11327
11328 // Touch unfocused window. This should force the pending key to get dropped.
11329 mDispatcher->notifyMotion(
11330 generateMotionArgs(AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN,
11331 ui::LogicalDisplayId::DEFAULT, {UNFOCUSED_WINDOW_LOCATION}));
11332
11333 // We do not consume the motion right away, because that would require dispatcher to first
11334 // process (== drop) the key event, and by that time, ANR will be raised.
11335 // Set the focused window first.
11336 mFocusedWindow->setFocusable(true);
11337 mDispatcher->onWindowInfosChanged(
11338 {{*mFocusedWindow->getInfo(), *mUnfocusedWindow->getInfo()}, {}, 0, 0});
11339 setFocusedWindow(mFocusedWindow);
11340 mFocusedWindow->consumeFocusEvent(true);
11341 // We do not call "setFocusedApplication" here, even though the newly focused window belongs
11342 // to another application. This could be a bug / behaviour in the policy.
11343
11344 mUnfocusedWindow->consumeMotionDown();
11345
11346 ASSERT_TRUE(mDispatcher->waitForIdle());
11347 // Should not ANR because we actually have a focused window. It was just added too slowly.
11348 ASSERT_NO_FATAL_FAILURE(mFakePolicy->assertNotifyAnrWasNotCalled());
11349 }
11350
11351 /**
11352 * If we are pruning input queue, we should never drop pointer events. Otherwise, we risk having
11353 * an inconsistent event stream inside the dispatcher. In this test, we make sure that the
11354 * dispatcher doesn't prune pointer events incorrectly.
11355 *
11356 * This test reproduces a crash in InputDispatcher.
11357 * To reproduce the crash, we need to simulate the conditions for "pruning input queue" to occur.
11358 *
11359 * Keep the currently focused application (mApplication), and have no focused window.
11360 * We set up two additional windows:
11361 * 1) The navigation bar window. This simulates the system "NavigationBar", which is used in the
11362 * 3-button navigation mode. This window injects a BACK button when it's touched. 2) The application
11363 * window. This window is not focusable, but is touchable.
11364 *
11365 * We first touch the navigation bar, which causes it to inject a key. Since there's no focused
11366 * window, the dispatcher doesn't process this key, and all other events inside dispatcher are now
11367 * blocked. The dispatcher is waiting for 'mApplication' to add a focused window.
11368 *
11369 * Now, we touch "Another window". This window is owned by a different application than
11370 * 'mApplication'. This causes the dispatcher to stop waiting for 'mApplication' to add a focused
11371 * window. Now, the "pruning input queue" behaviour should kick in, and the dispatcher should start
11372 * dropping the events from its queue. Ensure that no crash occurs.
11373 *
11374 * In this test, we are setting long timeouts to prevent ANRs and events dropped due to being stale.
11375 * This does not affect the test running time.
11376 */
TEST_F(InputDispatcherMultiWindowAnr,PruningInputQueueShouldNotDropPointerEvents)11377 TEST_F(InputDispatcherMultiWindowAnr, PruningInputQueueShouldNotDropPointerEvents) {
11378 std::shared_ptr<FakeApplicationHandle> systemUiApplication =
11379 std::make_shared<FakeApplicationHandle>();
11380 systemUiApplication->setDispatchingTimeout(3000ms);
11381 mFakePolicy->setStaleEventTimeout(3000ms);
11382 sp<FakeWindowHandle> navigationBar =
11383 sp<FakeWindowHandle>::make(systemUiApplication, mDispatcher, "NavigationBar",
11384 ui::LogicalDisplayId::DEFAULT);
11385 navigationBar->setFocusable(false);
11386 navigationBar->setWatchOutsideTouch(true);
11387 navigationBar->setFrame(Rect(0, 0, 100, 100));
11388
11389 mApplication->setDispatchingTimeout(3000ms);
11390 // 'mApplication' is already focused, but we call it again here to make it explicit.
11391 mDispatcher->setFocusedApplication(ui::LogicalDisplayId::DEFAULT, mApplication);
11392
11393 std::shared_ptr<FakeApplicationHandle> anotherApplication =
11394 std::make_shared<FakeApplicationHandle>();
11395 sp<FakeWindowHandle> appWindow =
11396 sp<FakeWindowHandle>::make(anotherApplication, mDispatcher, "Another window",
11397 ui::LogicalDisplayId::DEFAULT);
11398 appWindow->setFocusable(false);
11399 appWindow->setFrame(Rect(100, 100, 200, 200));
11400
11401 mDispatcher->onWindowInfosChanged(
11402 {{*navigationBar->getInfo(), *appWindow->getInfo()}, {}, 0, 0});
11403 // 'mFocusedWindow' is no longer in the dispatcher window list, and therefore loses focus
11404 mFocusedWindow->consumeFocusEvent(false);
11405
11406 // Touch down the navigation bar. It consumes the touch and injects a key into the dispatcher
11407 // in response.
11408 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
11409 .pointer(PointerBuilder(0, ToolType::FINGER).x(50).y(50))
11410 .build());
11411 navigationBar->consumeMotionEvent(WithMotionAction(ACTION_DOWN));
11412
11413 // Key will not be sent anywhere because we have no focused window. It will remain pending.
11414 // Pretend we are injecting KEYCODE_BACK, but it doesn't actually matter what key it is.
11415 InputEventInjectionResult result =
11416 injectKey(*mDispatcher, AKEY_EVENT_ACTION_DOWN, /*repeatCount=*/0,
11417 ui::LogicalDisplayId::DEFAULT, InputEventInjectionSync::NONE,
11418 /*injectionTimeout=*/100ms,
11419 /*allowKeyRepeat=*/false);
11420 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, result);
11421
11422 // Finish the gesture - lift up finger and inject ACTION_UP key event
11423 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN)
11424 .pointer(PointerBuilder(0, ToolType::FINGER).x(50).y(50))
11425 .build());
11426 result = injectKey(*mDispatcher, AKEY_EVENT_ACTION_UP, /*repeatCount=*/0,
11427 ui::LogicalDisplayId::DEFAULT, InputEventInjectionSync::NONE,
11428 /*injectionTimeout=*/100ms,
11429 /*allowKeyRepeat=*/false);
11430 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, result);
11431 // The key that was injected is blocking the dispatcher, so the navigation bar shouldn't be
11432 // getting any events yet.
11433 navigationBar->assertNoEvents();
11434
11435 // Now touch "Another window". This touch is going to a different application than the one we
11436 // are waiting for (which is 'mApplication').
11437 // This should cause the dispatcher to drop the pending focus-dispatched events (like the key
11438 // trying to be injected) and to continue processing the rest of the events in the original
11439 // order.
11440 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
11441 .pointer(PointerBuilder(0, ToolType::FINGER).x(150).y(150))
11442 .build());
11443 navigationBar->consumeMotionEvent(WithMotionAction(ACTION_UP));
11444 navigationBar->consumeMotionEvent(WithMotionAction(ACTION_OUTSIDE));
11445 appWindow->consumeMotionEvent(WithMotionAction(ACTION_DOWN));
11446
11447 appWindow->assertNoEvents();
11448 navigationBar->assertNoEvents();
11449 }
11450
11451 // These tests ensure we cannot send touch events to a window that's positioned behind a window
11452 // that has feature NO_INPUT_CHANNEL.
11453 // Layout:
11454 // Top (closest to user)
11455 // mNoInputWindow (above all windows)
11456 // mBottomWindow
11457 // Bottom (furthest from user)
11458 class InputDispatcherMultiWindowOcclusionTests : public InputDispatcherTest {
SetUp()11459 virtual void SetUp() override {
11460 InputDispatcherTest::SetUp();
11461
11462 mApplication = std::make_shared<FakeApplicationHandle>();
11463 mNoInputWindow = sp<FakeWindowHandle>::make(mApplication, mDispatcher,
11464 "Window without input channel",
11465 ui::LogicalDisplayId::DEFAULT,
11466 /*createInputChannel=*/false);
11467 mNoInputWindow->setNoInputChannel(true);
11468 mNoInputWindow->setFrame(Rect(0, 0, 100, 100));
11469 // It's perfectly valid for this window to not have an associated input channel
11470
11471 mBottomWindow = sp<FakeWindowHandle>::make(mApplication, mDispatcher, "Bottom window",
11472 ui::LogicalDisplayId::DEFAULT);
11473 mBottomWindow->setFrame(Rect(0, 0, 100, 100));
11474
11475 mDispatcher->onWindowInfosChanged(
11476 {{*mNoInputWindow->getInfo(), *mBottomWindow->getInfo()}, {}, 0, 0});
11477 }
11478
11479 protected:
11480 std::shared_ptr<FakeApplicationHandle> mApplication;
11481 sp<FakeWindowHandle> mNoInputWindow;
11482 sp<FakeWindowHandle> mBottomWindow;
11483 };
11484
TEST_F(InputDispatcherMultiWindowOcclusionTests,NoInputChannelFeature_DropsTouches)11485 TEST_F(InputDispatcherMultiWindowOcclusionTests, NoInputChannelFeature_DropsTouches) {
11486 PointF touchedPoint = {10, 10};
11487
11488 mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_DOWN,
11489 AINPUT_SOURCE_TOUCHSCREEN,
11490 ui::LogicalDisplayId::DEFAULT, {touchedPoint}));
11491
11492 mNoInputWindow->assertNoEvents();
11493 // Even though the window 'mNoInputWindow' positioned above 'mBottomWindow' does not have
11494 // an input channel, it is not marked as FLAG_NOT_TOUCHABLE,
11495 // and therefore should prevent mBottomWindow from receiving touches
11496 mBottomWindow->assertNoEvents();
11497 }
11498
11499 /**
11500 * If a window has feature NO_INPUT_CHANNEL, and somehow (by mistake) still has an input channel,
11501 * ensure that this window does not receive any touches, and blocks touches to windows underneath.
11502 */
TEST_F(InputDispatcherMultiWindowOcclusionTests,NoInputChannelFeature_DropsTouchesWithValidChannel)11503 TEST_F(InputDispatcherMultiWindowOcclusionTests,
11504 NoInputChannelFeature_DropsTouchesWithValidChannel) {
11505 mNoInputWindow = sp<FakeWindowHandle>::make(mApplication, mDispatcher,
11506 "Window with input channel and NO_INPUT_CHANNEL",
11507 ui::LogicalDisplayId::DEFAULT);
11508
11509 mNoInputWindow->setNoInputChannel(true);
11510 mNoInputWindow->setFrame(Rect(0, 0, 100, 100));
11511 mDispatcher->onWindowInfosChanged(
11512 {{*mNoInputWindow->getInfo(), *mBottomWindow->getInfo()}, {}, 0, 0});
11513
11514 PointF touchedPoint = {10, 10};
11515
11516 mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_DOWN,
11517 AINPUT_SOURCE_TOUCHSCREEN,
11518 ui::LogicalDisplayId::DEFAULT, {touchedPoint}));
11519
11520 mNoInputWindow->assertNoEvents();
11521 mBottomWindow->assertNoEvents();
11522 }
11523
11524 class InputDispatcherMirrorWindowFocusTests : public InputDispatcherTest {
11525 protected:
11526 std::shared_ptr<FakeApplicationHandle> mApp;
11527 sp<FakeWindowHandle> mWindow;
11528 sp<FakeWindowHandle> mMirror;
11529
SetUp()11530 virtual void SetUp() override {
11531 InputDispatcherTest::SetUp();
11532 mApp = std::make_shared<FakeApplicationHandle>();
11533 mWindow = sp<FakeWindowHandle>::make(mApp, mDispatcher, "TestWindow",
11534 ui::LogicalDisplayId::DEFAULT);
11535 mMirror = mWindow->clone(ui::LogicalDisplayId::DEFAULT);
11536 mDispatcher->setFocusedApplication(ui::LogicalDisplayId::DEFAULT, mApp);
11537 mWindow->setFocusable(true);
11538 mMirror->setFocusable(true);
11539 mDispatcher->onWindowInfosChanged({{*mWindow->getInfo(), *mMirror->getInfo()}, {}, 0, 0});
11540 }
11541 };
11542
TEST_F(InputDispatcherMirrorWindowFocusTests,CanGetFocus)11543 TEST_F(InputDispatcherMirrorWindowFocusTests, CanGetFocus) {
11544 // Request focus on a mirrored window
11545 setFocusedWindow(mMirror);
11546
11547 // window gets focused
11548 mWindow->consumeFocusEvent(true);
11549 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectKeyDown(*mDispatcher))
11550 << "Inject key event should return InputEventInjectionResult::SUCCEEDED";
11551 mWindow->consumeKeyDown(ui::LogicalDisplayId::INVALID);
11552 }
11553
11554 // A focused & mirrored window remains focused only if the window and its mirror are both
11555 // focusable.
TEST_F(InputDispatcherMirrorWindowFocusTests,FocusedIfAllWindowsFocusable)11556 TEST_F(InputDispatcherMirrorWindowFocusTests, FocusedIfAllWindowsFocusable) {
11557 setFocusedWindow(mMirror);
11558
11559 // window gets focused because it is above the mirror
11560 mWindow->consumeFocusEvent(true);
11561 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectKeyDown(*mDispatcher))
11562 << "Inject key event should return InputEventInjectionResult::SUCCEEDED";
11563 mWindow->consumeKeyDown(ui::LogicalDisplayId::INVALID);
11564 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectKeyUp(*mDispatcher))
11565 << "Inject key event should return InputEventInjectionResult::SUCCEEDED";
11566 mWindow->consumeKeyUp(ui::LogicalDisplayId::INVALID);
11567
11568 mMirror->setFocusable(false);
11569 mDispatcher->onWindowInfosChanged({{*mWindow->getInfo(), *mMirror->getInfo()}, {}, 0, 0});
11570
11571 // window loses focus since one of the windows associated with the token in not focusable
11572 mWindow->consumeFocusEvent(false);
11573
11574 ASSERT_EQ(InputEventInjectionResult::TIMED_OUT, injectKeyDown(*mDispatcher))
11575 << "Inject key event should return InputEventInjectionResult::TIMED_OUT";
11576 mWindow->assertNoEvents();
11577 }
11578
11579 // A focused & mirrored window remains focused until the window and its mirror both become
11580 // invisible.
TEST_F(InputDispatcherMirrorWindowFocusTests,FocusedIfAnyWindowVisible)11581 TEST_F(InputDispatcherMirrorWindowFocusTests, FocusedIfAnyWindowVisible) {
11582 setFocusedWindow(mMirror);
11583
11584 // window gets focused
11585 mWindow->consumeFocusEvent(true);
11586 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectKeyDown(*mDispatcher))
11587 << "Inject key event should return InputEventInjectionResult::SUCCEEDED";
11588 mWindow->consumeKeyDown(ui::LogicalDisplayId::INVALID);
11589 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectKeyUp(*mDispatcher))
11590 << "Inject key event should return InputEventInjectionResult::SUCCEEDED";
11591 mWindow->consumeKeyUp(ui::LogicalDisplayId::INVALID);
11592
11593 mMirror->setVisible(false);
11594 mDispatcher->onWindowInfosChanged({{*mWindow->getInfo(), *mMirror->getInfo()}, {}, 0, 0});
11595
11596 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectKeyDown(*mDispatcher))
11597 << "Inject key event should return InputEventInjectionResult::SUCCEEDED";
11598 mWindow->consumeKeyDown(ui::LogicalDisplayId::INVALID);
11599 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectKeyUp(*mDispatcher))
11600 << "Inject key event should return InputEventInjectionResult::SUCCEEDED";
11601 mWindow->consumeKeyUp(ui::LogicalDisplayId::INVALID);
11602
11603 mWindow->setVisible(false);
11604 mDispatcher->onWindowInfosChanged({{*mWindow->getInfo(), *mMirror->getInfo()}, {}, 0, 0});
11605
11606 // window loses focus only after all windows associated with the token become invisible.
11607 mWindow->consumeFocusEvent(false);
11608
11609 ASSERT_EQ(InputEventInjectionResult::TIMED_OUT, injectKeyDown(*mDispatcher))
11610 << "Inject key event should return InputEventInjectionResult::TIMED_OUT";
11611 mWindow->assertNoEvents();
11612 }
11613
11614 // A focused & mirrored window remains focused until both windows are removed.
TEST_F(InputDispatcherMirrorWindowFocusTests,FocusedWhileWindowsAlive)11615 TEST_F(InputDispatcherMirrorWindowFocusTests, FocusedWhileWindowsAlive) {
11616 setFocusedWindow(mMirror);
11617
11618 // window gets focused
11619 mWindow->consumeFocusEvent(true);
11620 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectKeyDown(*mDispatcher))
11621 << "Inject key event should return InputEventInjectionResult::SUCCEEDED";
11622 mWindow->consumeKeyDown(ui::LogicalDisplayId::INVALID);
11623 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectKeyUp(*mDispatcher))
11624 << "Inject key event should return InputEventInjectionResult::SUCCEEDED";
11625 mWindow->consumeKeyUp(ui::LogicalDisplayId::INVALID);
11626
11627 // single window is removed but the window token remains focused
11628 mDispatcher->onWindowInfosChanged({{*mMirror->getInfo()}, {}, 0, 0});
11629
11630 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectKeyDown(*mDispatcher))
11631 << "Inject key event should return InputEventInjectionResult::SUCCEEDED";
11632 mMirror->consumeKeyDown(ui::LogicalDisplayId::INVALID);
11633 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectKeyUp(*mDispatcher))
11634 << "Inject key event should return InputEventInjectionResult::SUCCEEDED";
11635 mMirror->consumeKeyUp(ui::LogicalDisplayId::INVALID);
11636
11637 // Both windows are removed
11638 mDispatcher->onWindowInfosChanged({{}, {}, 0, 0});
11639 mWindow->consumeFocusEvent(false);
11640
11641 ASSERT_EQ(InputEventInjectionResult::TIMED_OUT, injectKeyDown(*mDispatcher))
11642 << "Inject key event should return InputEventInjectionResult::TIMED_OUT";
11643 mWindow->assertNoEvents();
11644 }
11645
11646 // Focus request can be pending until one window becomes visible.
TEST_F(InputDispatcherMirrorWindowFocusTests,DeferFocusWhenInvisible)11647 TEST_F(InputDispatcherMirrorWindowFocusTests, DeferFocusWhenInvisible) {
11648 // Request focus on an invisible mirror.
11649 mWindow->setVisible(false);
11650 mMirror->setVisible(false);
11651 mDispatcher->onWindowInfosChanged({{*mWindow->getInfo(), *mMirror->getInfo()}, {}, 0, 0});
11652 setFocusedWindow(mMirror);
11653
11654 // Injected key goes to pending queue.
11655 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
11656 injectKey(*mDispatcher, AKEY_EVENT_ACTION_DOWN, /*repeatCount=*/0,
11657 ui::LogicalDisplayId::DEFAULT, InputEventInjectionSync::NONE));
11658
11659 mMirror->setVisible(true);
11660 mDispatcher->onWindowInfosChanged({{*mWindow->getInfo(), *mMirror->getInfo()}, {}, 0, 0});
11661
11662 // window gets focused
11663 mWindow->consumeFocusEvent(true);
11664 // window gets the pending key event
11665 mWindow->consumeKeyDown(ui::LogicalDisplayId::DEFAULT);
11666 }
11667
11668 class InputDispatcherPointerCaptureTests : public InputDispatcherTest {
11669 protected:
11670 std::shared_ptr<FakeApplicationHandle> mApp;
11671 sp<FakeWindowHandle> mWindow;
11672 sp<FakeWindowHandle> mSecondWindow;
11673
SetUp()11674 void SetUp() override {
11675 InputDispatcherTest::SetUp();
11676 mApp = std::make_shared<FakeApplicationHandle>();
11677 mWindow = sp<FakeWindowHandle>::make(mApp, mDispatcher, "TestWindow",
11678 ui::LogicalDisplayId::DEFAULT);
11679 mWindow->setFocusable(true);
11680 mSecondWindow = sp<FakeWindowHandle>::make(mApp, mDispatcher, "TestWindow2",
11681 ui::LogicalDisplayId::DEFAULT);
11682 mSecondWindow->setFocusable(true);
11683
11684 mDispatcher->setFocusedApplication(ui::LogicalDisplayId::DEFAULT, mApp);
11685 mDispatcher->onWindowInfosChanged(
11686 {{*mWindow->getInfo(), *mSecondWindow->getInfo()}, {}, 0, 0});
11687
11688 setFocusedWindow(mWindow);
11689 mWindow->consumeFocusEvent(true);
11690 }
11691
notifyPointerCaptureChanged(const PointerCaptureRequest & request)11692 void notifyPointerCaptureChanged(const PointerCaptureRequest& request) {
11693 mDispatcher->notifyPointerCaptureChanged(generatePointerCaptureChangedArgs(request));
11694 }
11695
requestAndVerifyPointerCapture(const sp<FakeWindowHandle> & window,bool enabled)11696 PointerCaptureRequest requestAndVerifyPointerCapture(const sp<FakeWindowHandle>& window,
11697 bool enabled) {
11698 mDispatcher->requestPointerCapture(window->getToken(), enabled);
11699 auto request = mFakePolicy->assertSetPointerCaptureCalled(window, enabled);
11700 notifyPointerCaptureChanged(request);
11701 window->consumeCaptureEvent(enabled);
11702 return request;
11703 }
11704 };
11705
TEST_F(InputDispatcherPointerCaptureTests,EnablePointerCaptureWhenFocused)11706 TEST_F(InputDispatcherPointerCaptureTests, EnablePointerCaptureWhenFocused) {
11707 // Ensure that capture cannot be obtained for unfocused windows.
11708 mDispatcher->requestPointerCapture(mSecondWindow->getToken(), true);
11709 mFakePolicy->assertSetPointerCaptureNotCalled();
11710 mSecondWindow->assertNoEvents();
11711
11712 // Ensure that capture can be enabled from the focus window.
11713 requestAndVerifyPointerCapture(mWindow, true);
11714
11715 // Ensure that capture cannot be disabled from a window that does not have capture.
11716 mDispatcher->requestPointerCapture(mSecondWindow->getToken(), false);
11717 mFakePolicy->assertSetPointerCaptureNotCalled();
11718
11719 // Ensure that capture can be disabled from the window with capture.
11720 requestAndVerifyPointerCapture(mWindow, false);
11721 }
11722
TEST_F(InputDispatcherPointerCaptureTests,DisablesPointerCaptureAfterWindowLosesFocus)11723 TEST_F(InputDispatcherPointerCaptureTests, DisablesPointerCaptureAfterWindowLosesFocus) {
11724 auto request = requestAndVerifyPointerCapture(mWindow, true);
11725
11726 setFocusedWindow(mSecondWindow);
11727
11728 // Ensure that the capture disabled event was sent first.
11729 mWindow->consumeCaptureEvent(false);
11730 mWindow->consumeFocusEvent(false);
11731 mSecondWindow->consumeFocusEvent(true);
11732 mFakePolicy->assertSetPointerCaptureCalled(mWindow, false);
11733
11734 // Ensure that additional state changes from InputReader are not sent to the window.
11735 notifyPointerCaptureChanged({});
11736 notifyPointerCaptureChanged(request);
11737 notifyPointerCaptureChanged({});
11738 mWindow->assertNoEvents();
11739 mSecondWindow->assertNoEvents();
11740 mFakePolicy->assertSetPointerCaptureNotCalled();
11741 }
11742
TEST_F(InputDispatcherPointerCaptureTests,UnexpectedStateChangeDisablesPointerCapture)11743 TEST_F(InputDispatcherPointerCaptureTests, UnexpectedStateChangeDisablesPointerCapture) {
11744 auto request = requestAndVerifyPointerCapture(mWindow, true);
11745
11746 // InputReader unexpectedly disables and enables pointer capture.
11747 notifyPointerCaptureChanged({});
11748 notifyPointerCaptureChanged(request);
11749
11750 // Ensure that Pointer Capture is disabled.
11751 mFakePolicy->assertSetPointerCaptureCalled(mWindow, false);
11752 mWindow->consumeCaptureEvent(false);
11753 mWindow->assertNoEvents();
11754 }
11755
TEST_F(InputDispatcherPointerCaptureTests,OutOfOrderRequests)11756 TEST_F(InputDispatcherPointerCaptureTests, OutOfOrderRequests) {
11757 requestAndVerifyPointerCapture(mWindow, true);
11758
11759 // The first window loses focus.
11760 setFocusedWindow(mSecondWindow);
11761 mFakePolicy->assertSetPointerCaptureCalled(mWindow, false);
11762 mWindow->consumeCaptureEvent(false);
11763
11764 // Request Pointer Capture from the second window before the notification from InputReader
11765 // arrives.
11766 mDispatcher->requestPointerCapture(mSecondWindow->getToken(), true);
11767 auto request = mFakePolicy->assertSetPointerCaptureCalled(mSecondWindow, true);
11768
11769 // InputReader notifies Pointer Capture was disabled (because of the focus change).
11770 notifyPointerCaptureChanged({});
11771
11772 // InputReader notifies Pointer Capture was enabled (because of mSecondWindow's request).
11773 notifyPointerCaptureChanged(request);
11774
11775 mSecondWindow->consumeFocusEvent(true);
11776 mSecondWindow->consumeCaptureEvent(true);
11777 }
11778
TEST_F(InputDispatcherPointerCaptureTests,EnableRequestFollowsSequenceNumbers)11779 TEST_F(InputDispatcherPointerCaptureTests, EnableRequestFollowsSequenceNumbers) {
11780 // App repeatedly enables and disables capture.
11781 mDispatcher->requestPointerCapture(mWindow->getToken(), true);
11782 auto firstRequest = mFakePolicy->assertSetPointerCaptureCalled(mWindow, true);
11783 mDispatcher->requestPointerCapture(mWindow->getToken(), false);
11784 mFakePolicy->assertSetPointerCaptureCalled(mWindow, false);
11785 mDispatcher->requestPointerCapture(mWindow->getToken(), true);
11786 auto secondRequest = mFakePolicy->assertSetPointerCaptureCalled(mWindow, true);
11787
11788 // InputReader notifies that PointerCapture has been enabled for the first request. Since the
11789 // first request is now stale, this should do nothing.
11790 notifyPointerCaptureChanged(firstRequest);
11791 mWindow->assertNoEvents();
11792
11793 // InputReader notifies that the second request was enabled.
11794 notifyPointerCaptureChanged(secondRequest);
11795 mWindow->consumeCaptureEvent(true);
11796 }
11797
TEST_F(InputDispatcherPointerCaptureTests,RapidToggleRequests)11798 TEST_F(InputDispatcherPointerCaptureTests, RapidToggleRequests) {
11799 requestAndVerifyPointerCapture(mWindow, true);
11800
11801 // App toggles pointer capture off and on.
11802 mDispatcher->requestPointerCapture(mWindow->getToken(), false);
11803 mFakePolicy->assertSetPointerCaptureCalled(mWindow, false);
11804
11805 mDispatcher->requestPointerCapture(mWindow->getToken(), true);
11806 auto enableRequest = mFakePolicy->assertSetPointerCaptureCalled(mWindow, true);
11807
11808 // InputReader notifies that the latest "enable" request was processed, while skipping over the
11809 // preceding "disable" request.
11810 notifyPointerCaptureChanged(enableRequest);
11811
11812 // Since pointer capture was never disabled during the rapid toggle, the window does not receive
11813 // any notifications.
11814 mWindow->assertNoEvents();
11815 }
11816
11817 /**
11818 * One window. Hover mouse in the window, and then start capture. Make sure that the relative
11819 * mouse movements don't affect the previous mouse hovering state.
11820 * When pointer capture is enabled, the incoming events are always ACTION_MOVE (there are no
11821 * HOVER_MOVE events).
11822 */
TEST_F(InputDispatcherPointerCaptureTests,MouseHoverAndPointerCapture)11823 TEST_F(InputDispatcherPointerCaptureTests, MouseHoverAndPointerCapture) {
11824 // Mouse hover on the window
11825 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_ENTER, AINPUT_SOURCE_MOUSE)
11826 .pointer(PointerBuilder(0, ToolType::MOUSE).x(100).y(110))
11827 .build());
11828 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_MOVE, AINPUT_SOURCE_MOUSE)
11829 .pointer(PointerBuilder(0, ToolType::MOUSE).x(100).y(110))
11830 .build());
11831
11832 mWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_HOVER_ENTER)));
11833 mWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_HOVER_MOVE)));
11834
11835 // Start pointer capture
11836 requestAndVerifyPointerCapture(mWindow, true);
11837
11838 // Send some relative mouse movements and receive them in the window.
11839 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_MOUSE_RELATIVE)
11840 .pointer(PointerBuilder(0, ToolType::MOUSE).x(10).y(11))
11841 .build());
11842 mWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_MOVE), WithCoords(10, 11),
11843 WithSource(AINPUT_SOURCE_MOUSE_RELATIVE)));
11844
11845 // Stop pointer capture
11846 requestAndVerifyPointerCapture(mWindow, false);
11847
11848 // Continue hovering on the window
11849 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_MOVE, AINPUT_SOURCE_MOUSE)
11850 .pointer(PointerBuilder(0, ToolType::MOUSE).x(105).y(115))
11851 .build());
11852 mWindow->consumeMotionEvent(
11853 AllOf(WithMotionAction(ACTION_HOVER_MOVE), WithSource(AINPUT_SOURCE_MOUSE)));
11854
11855 mWindow->assertNoEvents();
11856 }
11857
TEST_F(InputDispatcherPointerCaptureTests,MultiDisplayPointerCapture)11858 TEST_F(InputDispatcherPointerCaptureTests, MultiDisplayPointerCapture) {
11859 // The default display is the focused display to begin with.
11860 requestAndVerifyPointerCapture(mWindow, true);
11861
11862 // Move the second window to a second display, make it the focused window on that display.
11863 mSecondWindow->editInfo()->displayId = SECOND_DISPLAY_ID;
11864 mDispatcher->onWindowInfosChanged({{*mWindow->getInfo(), *mSecondWindow->getInfo()}, {}, 0, 0});
11865 setFocusedWindow(mSecondWindow);
11866 mSecondWindow->consumeFocusEvent(true);
11867
11868 mWindow->assertNoEvents();
11869
11870 // The second window cannot gain capture because it is not on the focused display.
11871 mDispatcher->requestPointerCapture(mSecondWindow->getToken(), true);
11872 mFakePolicy->assertSetPointerCaptureNotCalled();
11873 mSecondWindow->assertNoEvents();
11874
11875 // Make the second display the focused display.
11876 mDispatcher->setFocusedDisplay(SECOND_DISPLAY_ID);
11877 mFakePolicy->assertFocusedDisplayNotified(SECOND_DISPLAY_ID);
11878
11879 // This causes the first window to lose pointer capture, and it's unable to request capture.
11880 mWindow->consumeCaptureEvent(false);
11881 mFakePolicy->assertSetPointerCaptureCalled(mWindow, false);
11882
11883 mDispatcher->requestPointerCapture(mWindow->getToken(), true);
11884 mFakePolicy->assertSetPointerCaptureNotCalled();
11885
11886 // The second window is now able to gain pointer capture successfully.
11887 requestAndVerifyPointerCapture(mSecondWindow, true);
11888 }
11889
11890 using InputDispatcherPointerCaptureDeathTest = InputDispatcherPointerCaptureTests;
11891
TEST_F(InputDispatcherPointerCaptureDeathTest,NotifyPointerCaptureChangedWithWrongTokenAbortsDispatcher)11892 TEST_F(InputDispatcherPointerCaptureDeathTest,
11893 NotifyPointerCaptureChangedWithWrongTokenAbortsDispatcher) {
11894 testing::GTEST_FLAG(death_test_style) = "threadsafe";
11895 ScopedSilentDeath _silentDeath;
11896
11897 mDispatcher->requestPointerCapture(mWindow->getToken(), true);
11898 auto request = mFakePolicy->assertSetPointerCaptureCalled(mWindow, true);
11899
11900 // Dispatch a pointer changed event with a wrong token.
11901 request.window = mSecondWindow->getToken();
11902 ASSERT_DEATH(
11903 {
11904 notifyPointerCaptureChanged(request);
11905 mSecondWindow->consumeCaptureEvent(true);
11906 },
11907 "Unexpected requested window for Pointer Capture.");
11908 }
11909
11910 class InputDispatcherUntrustedTouchesTest : public InputDispatcherTest {
11911 protected:
11912 constexpr static const float MAXIMUM_OBSCURING_OPACITY = 0.8;
11913
11914 constexpr static const float OPACITY_ABOVE_THRESHOLD = 0.9;
11915 static_assert(OPACITY_ABOVE_THRESHOLD > MAXIMUM_OBSCURING_OPACITY);
11916
11917 constexpr static const float OPACITY_BELOW_THRESHOLD = 0.7;
11918 static_assert(OPACITY_BELOW_THRESHOLD < MAXIMUM_OBSCURING_OPACITY);
11919
11920 // When combined twice, ie 1 - (1 - 0.5)*(1 - 0.5) = 0.75 < 8, is still below the threshold
11921 constexpr static const float OPACITY_FAR_BELOW_THRESHOLD = 0.5;
11922 static_assert(OPACITY_FAR_BELOW_THRESHOLD < MAXIMUM_OBSCURING_OPACITY);
11923 static_assert(1 - (1 - OPACITY_FAR_BELOW_THRESHOLD) * (1 - OPACITY_FAR_BELOW_THRESHOLD) <
11924 MAXIMUM_OBSCURING_OPACITY);
11925
11926 static constexpr gui::Uid TOUCHED_APP_UID{10001};
11927 static constexpr gui::Uid APP_B_UID{10002};
11928 static constexpr gui::Uid APP_C_UID{10003};
11929
11930 sp<FakeWindowHandle> mTouchWindow;
11931
SetUp()11932 virtual void SetUp() override {
11933 InputDispatcherTest::SetUp();
11934 mTouchWindow = getWindow(TOUCHED_APP_UID, "Touched");
11935 mDispatcher->setMaximumObscuringOpacityForTouch(MAXIMUM_OBSCURING_OPACITY);
11936 }
11937
TearDown()11938 virtual void TearDown() override {
11939 InputDispatcherTest::TearDown();
11940 mTouchWindow.clear();
11941 }
11942
getOccludingWindow(gui::Uid uid,std::string name,TouchOcclusionMode mode,float alpha=1.0f)11943 sp<FakeWindowHandle> getOccludingWindow(gui::Uid uid, std::string name, TouchOcclusionMode mode,
11944 float alpha = 1.0f) {
11945 sp<FakeWindowHandle> window = getWindow(uid, name);
11946 window->setTouchable(false);
11947 window->setTouchOcclusionMode(mode);
11948 window->setAlpha(alpha);
11949 return window;
11950 }
11951
getWindow(gui::Uid uid,std::string name)11952 sp<FakeWindowHandle> getWindow(gui::Uid uid, std::string name) {
11953 std::shared_ptr<FakeApplicationHandle> app = std::make_shared<FakeApplicationHandle>();
11954 sp<FakeWindowHandle> window =
11955 sp<FakeWindowHandle>::make(app, mDispatcher, name, ui::LogicalDisplayId::DEFAULT);
11956 // Generate an arbitrary PID based on the UID
11957 window->setOwnerInfo(gui::Pid{static_cast<pid_t>(1777 + (uid.val() % 10000))}, uid);
11958 return window;
11959 }
11960
touch(const std::vector<PointF> & points={PointF{100, 200}})11961 void touch(const std::vector<PointF>& points = {PointF{100, 200}}) {
11962 mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_DOWN,
11963 AINPUT_SOURCE_TOUCHSCREEN,
11964 ui::LogicalDisplayId::DEFAULT, points));
11965 }
11966 };
11967
TEST_F(InputDispatcherUntrustedTouchesTest,WindowWithBlockUntrustedOcclusionMode_BlocksTouch)11968 TEST_F(InputDispatcherUntrustedTouchesTest, WindowWithBlockUntrustedOcclusionMode_BlocksTouch) {
11969 const sp<FakeWindowHandle>& w =
11970 getOccludingWindow(APP_B_UID, "B", TouchOcclusionMode::BLOCK_UNTRUSTED);
11971 mDispatcher->onWindowInfosChanged({{*w->getInfo(), *mTouchWindow->getInfo()}, {}, 0, 0});
11972
11973 touch();
11974
11975 mTouchWindow->assertNoEvents();
11976 }
11977
TEST_F(InputDispatcherUntrustedTouchesTest,WindowWithBlockUntrustedOcclusionModeWithOpacityBelowThreshold_BlocksTouch)11978 TEST_F(InputDispatcherUntrustedTouchesTest,
11979 WindowWithBlockUntrustedOcclusionModeWithOpacityBelowThreshold_BlocksTouch) {
11980 const sp<FakeWindowHandle>& w =
11981 getOccludingWindow(APP_B_UID, "B", TouchOcclusionMode::BLOCK_UNTRUSTED, 0.7f);
11982 mDispatcher->onWindowInfosChanged({{*w->getInfo(), *mTouchWindow->getInfo()}, {}, 0, 0});
11983
11984 touch();
11985
11986 mTouchWindow->assertNoEvents();
11987 }
11988
TEST_F(InputDispatcherUntrustedTouchesTest,WindowWithBlockUntrustedOcclusionMode_DoesNotReceiveTouch)11989 TEST_F(InputDispatcherUntrustedTouchesTest,
11990 WindowWithBlockUntrustedOcclusionMode_DoesNotReceiveTouch) {
11991 const sp<FakeWindowHandle>& w =
11992 getOccludingWindow(APP_B_UID, "B", TouchOcclusionMode::BLOCK_UNTRUSTED);
11993 mDispatcher->onWindowInfosChanged({{*w->getInfo(), *mTouchWindow->getInfo()}, {}, 0, 0});
11994
11995 touch();
11996
11997 w->assertNoEvents();
11998 }
11999
TEST_F(InputDispatcherUntrustedTouchesTest,WindowWithAllowOcclusionMode_AllowsTouch)12000 TEST_F(InputDispatcherUntrustedTouchesTest, WindowWithAllowOcclusionMode_AllowsTouch) {
12001 const sp<FakeWindowHandle>& w = getOccludingWindow(APP_B_UID, "B", TouchOcclusionMode::ALLOW);
12002 mDispatcher->onWindowInfosChanged({{*w->getInfo(), *mTouchWindow->getInfo()}, {}, 0, 0});
12003
12004 touch();
12005
12006 mTouchWindow->consumeAnyMotionDown();
12007 }
12008
TEST_F(InputDispatcherUntrustedTouchesTest,TouchOutsideOccludingWindow_AllowsTouch)12009 TEST_F(InputDispatcherUntrustedTouchesTest, TouchOutsideOccludingWindow_AllowsTouch) {
12010 const sp<FakeWindowHandle>& w =
12011 getOccludingWindow(APP_B_UID, "B", TouchOcclusionMode::BLOCK_UNTRUSTED);
12012 w->setFrame(Rect(0, 0, 50, 50));
12013 mDispatcher->onWindowInfosChanged({{*w->getInfo(), *mTouchWindow->getInfo()}, {}, 0, 0});
12014
12015 touch({PointF{100, 100}});
12016
12017 mTouchWindow->consumeAnyMotionDown();
12018 }
12019
TEST_F(InputDispatcherUntrustedTouchesTest,WindowFromSameUid_AllowsTouch)12020 TEST_F(InputDispatcherUntrustedTouchesTest, WindowFromSameUid_AllowsTouch) {
12021 const sp<FakeWindowHandle>& w =
12022 getOccludingWindow(TOUCHED_APP_UID, "A", TouchOcclusionMode::BLOCK_UNTRUSTED);
12023 mDispatcher->onWindowInfosChanged({{*w->getInfo(), *mTouchWindow->getInfo()}, {}, 0, 0});
12024
12025 touch();
12026
12027 mTouchWindow->consumeAnyMotionDown();
12028 }
12029
TEST_F(InputDispatcherUntrustedTouchesTest,WindowWithZeroOpacity_AllowsTouch)12030 TEST_F(InputDispatcherUntrustedTouchesTest, WindowWithZeroOpacity_AllowsTouch) {
12031 const sp<FakeWindowHandle>& w =
12032 getOccludingWindow(APP_B_UID, "B", TouchOcclusionMode::BLOCK_UNTRUSTED, 0.0f);
12033 mDispatcher->onWindowInfosChanged({{*w->getInfo(), *mTouchWindow->getInfo()}, {}, 0, 0});
12034
12035 touch();
12036
12037 mTouchWindow->consumeAnyMotionDown();
12038 }
12039
TEST_F(InputDispatcherUntrustedTouchesTest,WindowWithZeroOpacity_DoesNotReceiveTouch)12040 TEST_F(InputDispatcherUntrustedTouchesTest, WindowWithZeroOpacity_DoesNotReceiveTouch) {
12041 const sp<FakeWindowHandle>& w =
12042 getOccludingWindow(APP_B_UID, "B", TouchOcclusionMode::BLOCK_UNTRUSTED, 0.0f);
12043 mDispatcher->onWindowInfosChanged({{*w->getInfo(), *mTouchWindow->getInfo()}, {}, 0, 0});
12044
12045 touch();
12046
12047 w->assertNoEvents();
12048 }
12049
12050 /**
12051 * This is important to make sure apps can't indirectly learn the position of touches (outside vs
12052 * inside) while letting them pass-through. Note that even though touch passes through the occluding
12053 * window, the occluding window will still receive ACTION_OUTSIDE event.
12054 */
TEST_F(InputDispatcherUntrustedTouchesTest,WindowWithZeroOpacityAndWatchOutside_ReceivesOutsideEvent)12055 TEST_F(InputDispatcherUntrustedTouchesTest,
12056 WindowWithZeroOpacityAndWatchOutside_ReceivesOutsideEvent) {
12057 const sp<FakeWindowHandle>& w =
12058 getOccludingWindow(APP_B_UID, "B", TouchOcclusionMode::BLOCK_UNTRUSTED, 0.0f);
12059 w->setWatchOutsideTouch(true);
12060 mDispatcher->onWindowInfosChanged({{*w->getInfo(), *mTouchWindow->getInfo()}, {}, 0, 0});
12061
12062 touch();
12063
12064 w->consumeMotionOutside();
12065 }
12066
TEST_F(InputDispatcherUntrustedTouchesTest,OutsideEvent_HasZeroCoordinates)12067 TEST_F(InputDispatcherUntrustedTouchesTest, OutsideEvent_HasZeroCoordinates) {
12068 const sp<FakeWindowHandle>& w =
12069 getOccludingWindow(APP_B_UID, "B", TouchOcclusionMode::BLOCK_UNTRUSTED, 0.0f);
12070 w->setWatchOutsideTouch(true);
12071 mDispatcher->onWindowInfosChanged({{*w->getInfo(), *mTouchWindow->getInfo()}, {}, 0, 0});
12072
12073 touch();
12074
12075 w->consumeMotionOutsideWithZeroedCoords();
12076 }
12077
TEST_F(InputDispatcherUntrustedTouchesTest,WindowWithOpacityBelowThreshold_AllowsTouch)12078 TEST_F(InputDispatcherUntrustedTouchesTest, WindowWithOpacityBelowThreshold_AllowsTouch) {
12079 const sp<FakeWindowHandle>& w =
12080 getOccludingWindow(APP_B_UID, "B", TouchOcclusionMode::USE_OPACITY,
12081 OPACITY_BELOW_THRESHOLD);
12082 mDispatcher->onWindowInfosChanged({{*w->getInfo(), *mTouchWindow->getInfo()}, {}, 0, 0});
12083
12084 touch();
12085
12086 mTouchWindow->consumeAnyMotionDown();
12087 }
12088
TEST_F(InputDispatcherUntrustedTouchesTest,WindowWithOpacityAtThreshold_AllowsTouch)12089 TEST_F(InputDispatcherUntrustedTouchesTest, WindowWithOpacityAtThreshold_AllowsTouch) {
12090 const sp<FakeWindowHandle>& w =
12091 getOccludingWindow(APP_B_UID, "B", TouchOcclusionMode::USE_OPACITY,
12092 MAXIMUM_OBSCURING_OPACITY);
12093 mDispatcher->onWindowInfosChanged({{*w->getInfo(), *mTouchWindow->getInfo()}, {}, 0, 0});
12094
12095 touch();
12096
12097 mTouchWindow->consumeAnyMotionDown();
12098 }
12099
TEST_F(InputDispatcherUntrustedTouchesTest,WindowWithOpacityAboveThreshold_BlocksTouch)12100 TEST_F(InputDispatcherUntrustedTouchesTest, WindowWithOpacityAboveThreshold_BlocksTouch) {
12101 const sp<FakeWindowHandle>& w =
12102 getOccludingWindow(APP_B_UID, "B", TouchOcclusionMode::USE_OPACITY,
12103 OPACITY_ABOVE_THRESHOLD);
12104 mDispatcher->onWindowInfosChanged({{*w->getInfo(), *mTouchWindow->getInfo()}, {}, 0, 0});
12105
12106 touch();
12107
12108 mTouchWindow->assertNoEvents();
12109 }
12110
TEST_F(InputDispatcherUntrustedTouchesTest,WindowsWithCombinedOpacityAboveThreshold_BlocksTouch)12111 TEST_F(InputDispatcherUntrustedTouchesTest, WindowsWithCombinedOpacityAboveThreshold_BlocksTouch) {
12112 // Resulting opacity = 1 - (1 - 0.7)*(1 - 0.7) = .91
12113 const sp<FakeWindowHandle>& w1 =
12114 getOccludingWindow(APP_B_UID, "B1", TouchOcclusionMode::USE_OPACITY,
12115 OPACITY_BELOW_THRESHOLD);
12116 const sp<FakeWindowHandle>& w2 =
12117 getOccludingWindow(APP_B_UID, "B2", TouchOcclusionMode::USE_OPACITY,
12118 OPACITY_BELOW_THRESHOLD);
12119 mDispatcher->onWindowInfosChanged(
12120 {{*w1->getInfo(), *w2->getInfo(), *mTouchWindow->getInfo()}, {}, 0, 0});
12121
12122 touch();
12123
12124 mTouchWindow->assertNoEvents();
12125 }
12126
TEST_F(InputDispatcherUntrustedTouchesTest,WindowsWithCombinedOpacityBelowThreshold_AllowsTouch)12127 TEST_F(InputDispatcherUntrustedTouchesTest, WindowsWithCombinedOpacityBelowThreshold_AllowsTouch) {
12128 // Resulting opacity = 1 - (1 - 0.5)*(1 - 0.5) = .75
12129 const sp<FakeWindowHandle>& w1 =
12130 getOccludingWindow(APP_B_UID, "B1", TouchOcclusionMode::USE_OPACITY,
12131 OPACITY_FAR_BELOW_THRESHOLD);
12132 const sp<FakeWindowHandle>& w2 =
12133 getOccludingWindow(APP_B_UID, "B2", TouchOcclusionMode::USE_OPACITY,
12134 OPACITY_FAR_BELOW_THRESHOLD);
12135 mDispatcher->onWindowInfosChanged(
12136 {{*w1->getInfo(), *w2->getInfo(), *mTouchWindow->getInfo()}, {}, 0, 0});
12137
12138 touch();
12139
12140 mTouchWindow->consumeAnyMotionDown();
12141 }
12142
TEST_F(InputDispatcherUntrustedTouchesTest,WindowsFromDifferentAppsEachBelowThreshold_AllowsTouch)12143 TEST_F(InputDispatcherUntrustedTouchesTest,
12144 WindowsFromDifferentAppsEachBelowThreshold_AllowsTouch) {
12145 const sp<FakeWindowHandle>& wB =
12146 getOccludingWindow(APP_B_UID, "B", TouchOcclusionMode::USE_OPACITY,
12147 OPACITY_BELOW_THRESHOLD);
12148 const sp<FakeWindowHandle>& wC =
12149 getOccludingWindow(APP_C_UID, "C", TouchOcclusionMode::USE_OPACITY,
12150 OPACITY_BELOW_THRESHOLD);
12151 mDispatcher->onWindowInfosChanged(
12152 {{*wB->getInfo(), *wC->getInfo(), *mTouchWindow->getInfo()}, {}, 0, 0});
12153
12154 touch();
12155
12156 mTouchWindow->consumeAnyMotionDown();
12157 }
12158
TEST_F(InputDispatcherUntrustedTouchesTest,WindowsFromDifferentAppsOneAboveThreshold_BlocksTouch)12159 TEST_F(InputDispatcherUntrustedTouchesTest, WindowsFromDifferentAppsOneAboveThreshold_BlocksTouch) {
12160 const sp<FakeWindowHandle>& wB =
12161 getOccludingWindow(APP_B_UID, "B", TouchOcclusionMode::USE_OPACITY,
12162 OPACITY_BELOW_THRESHOLD);
12163 const sp<FakeWindowHandle>& wC =
12164 getOccludingWindow(APP_C_UID, "C", TouchOcclusionMode::USE_OPACITY,
12165 OPACITY_ABOVE_THRESHOLD);
12166 mDispatcher->onWindowInfosChanged(
12167 {{*wB->getInfo(), *wC->getInfo(), *mTouchWindow->getInfo()}, {}, 0, 0});
12168
12169 touch();
12170
12171 mTouchWindow->assertNoEvents();
12172 }
12173
TEST_F(InputDispatcherUntrustedTouchesTest,WindowWithOpacityAboveThresholdAndSelfWindow_BlocksTouch)12174 TEST_F(InputDispatcherUntrustedTouchesTest,
12175 WindowWithOpacityAboveThresholdAndSelfWindow_BlocksTouch) {
12176 const sp<FakeWindowHandle>& wA =
12177 getOccludingWindow(TOUCHED_APP_UID, "T", TouchOcclusionMode::USE_OPACITY,
12178 OPACITY_BELOW_THRESHOLD);
12179 const sp<FakeWindowHandle>& wB =
12180 getOccludingWindow(APP_B_UID, "B", TouchOcclusionMode::USE_OPACITY,
12181 OPACITY_ABOVE_THRESHOLD);
12182 mDispatcher->onWindowInfosChanged(
12183 {{*wA->getInfo(), *wB->getInfo(), *mTouchWindow->getInfo()}, {}, 0, 0});
12184
12185 touch();
12186
12187 mTouchWindow->assertNoEvents();
12188 }
12189
TEST_F(InputDispatcherUntrustedTouchesTest,WindowWithOpacityBelowThresholdAndSelfWindow_AllowsTouch)12190 TEST_F(InputDispatcherUntrustedTouchesTest,
12191 WindowWithOpacityBelowThresholdAndSelfWindow_AllowsTouch) {
12192 const sp<FakeWindowHandle>& wA =
12193 getOccludingWindow(TOUCHED_APP_UID, "T", TouchOcclusionMode::USE_OPACITY,
12194 OPACITY_ABOVE_THRESHOLD);
12195 const sp<FakeWindowHandle>& wB =
12196 getOccludingWindow(APP_B_UID, "B", TouchOcclusionMode::USE_OPACITY,
12197 OPACITY_BELOW_THRESHOLD);
12198 mDispatcher->onWindowInfosChanged(
12199 {{*wA->getInfo(), *wB->getInfo(), *mTouchWindow->getInfo()}, {}, 0, 0});
12200
12201 touch();
12202
12203 mTouchWindow->consumeAnyMotionDown();
12204 }
12205
TEST_F(InputDispatcherUntrustedTouchesTest,SelfWindowWithOpacityAboveThreshold_AllowsTouch)12206 TEST_F(InputDispatcherUntrustedTouchesTest, SelfWindowWithOpacityAboveThreshold_AllowsTouch) {
12207 const sp<FakeWindowHandle>& w =
12208 getOccludingWindow(TOUCHED_APP_UID, "T", TouchOcclusionMode::USE_OPACITY,
12209 OPACITY_ABOVE_THRESHOLD);
12210 mDispatcher->onWindowInfosChanged({{*w->getInfo(), *mTouchWindow->getInfo()}, {}, 0, 0});
12211
12212 touch();
12213
12214 mTouchWindow->consumeAnyMotionDown();
12215 }
12216
TEST_F(InputDispatcherUntrustedTouchesTest,SelfWindowWithBlockUntrustedMode_AllowsTouch)12217 TEST_F(InputDispatcherUntrustedTouchesTest, SelfWindowWithBlockUntrustedMode_AllowsTouch) {
12218 const sp<FakeWindowHandle>& w =
12219 getOccludingWindow(TOUCHED_APP_UID, "T", TouchOcclusionMode::BLOCK_UNTRUSTED);
12220 mDispatcher->onWindowInfosChanged({{*w->getInfo(), *mTouchWindow->getInfo()}, {}, 0, 0});
12221
12222 touch();
12223
12224 mTouchWindow->consumeAnyMotionDown();
12225 }
12226
TEST_F(InputDispatcherUntrustedTouchesTest,OpacityThresholdIs0AndWindowAboveThreshold_BlocksTouch)12227 TEST_F(InputDispatcherUntrustedTouchesTest,
12228 OpacityThresholdIs0AndWindowAboveThreshold_BlocksTouch) {
12229 mDispatcher->setMaximumObscuringOpacityForTouch(0.0f);
12230 const sp<FakeWindowHandle>& w =
12231 getOccludingWindow(APP_B_UID, "B", TouchOcclusionMode::USE_OPACITY, 0.1f);
12232 mDispatcher->onWindowInfosChanged({{*w->getInfo(), *mTouchWindow->getInfo()}, {}, 0, 0});
12233
12234 touch();
12235
12236 mTouchWindow->assertNoEvents();
12237 }
12238
TEST_F(InputDispatcherUntrustedTouchesTest,OpacityThresholdIs0AndWindowAtThreshold_AllowsTouch)12239 TEST_F(InputDispatcherUntrustedTouchesTest, OpacityThresholdIs0AndWindowAtThreshold_AllowsTouch) {
12240 mDispatcher->setMaximumObscuringOpacityForTouch(0.0f);
12241 const sp<FakeWindowHandle>& w =
12242 getOccludingWindow(APP_B_UID, "B", TouchOcclusionMode::USE_OPACITY, 0.0f);
12243 mDispatcher->onWindowInfosChanged({{*w->getInfo(), *mTouchWindow->getInfo()}, {}, 0, 0});
12244
12245 touch();
12246
12247 mTouchWindow->consumeAnyMotionDown();
12248 }
12249
TEST_F(InputDispatcherUntrustedTouchesTest,OpacityThresholdIs1AndWindowBelowThreshold_AllowsTouch)12250 TEST_F(InputDispatcherUntrustedTouchesTest,
12251 OpacityThresholdIs1AndWindowBelowThreshold_AllowsTouch) {
12252 mDispatcher->setMaximumObscuringOpacityForTouch(1.0f);
12253 const sp<FakeWindowHandle>& w =
12254 getOccludingWindow(APP_B_UID, "B", TouchOcclusionMode::USE_OPACITY,
12255 OPACITY_ABOVE_THRESHOLD);
12256 mDispatcher->onWindowInfosChanged({{*w->getInfo(), *mTouchWindow->getInfo()}, {}, 0, 0});
12257
12258 touch();
12259
12260 mTouchWindow->consumeAnyMotionDown();
12261 }
12262
TEST_F(InputDispatcherUntrustedTouchesTest,WindowWithBlockUntrustedModeAndWindowWithOpacityBelowFromSameApp_BlocksTouch)12263 TEST_F(InputDispatcherUntrustedTouchesTest,
12264 WindowWithBlockUntrustedModeAndWindowWithOpacityBelowFromSameApp_BlocksTouch) {
12265 const sp<FakeWindowHandle>& w1 =
12266 getOccludingWindow(APP_B_UID, "B", TouchOcclusionMode::BLOCK_UNTRUSTED,
12267 OPACITY_BELOW_THRESHOLD);
12268 const sp<FakeWindowHandle>& w2 =
12269 getOccludingWindow(APP_B_UID, "B", TouchOcclusionMode::USE_OPACITY,
12270 OPACITY_BELOW_THRESHOLD);
12271 mDispatcher->onWindowInfosChanged(
12272 {{*w1->getInfo(), *w2->getInfo(), *mTouchWindow->getInfo()}, {}, 0, 0});
12273
12274 touch();
12275
12276 mTouchWindow->assertNoEvents();
12277 }
12278
12279 /**
12280 * Window B of BLOCK_UNTRUSTED occlusion mode is enough to block the touch, we're testing that the
12281 * addition of another window (C) of USE_OPACITY occlusion mode and opacity below the threshold
12282 * (which alone would result in allowing touches) does not affect the blocking behavior.
12283 */
TEST_F(InputDispatcherUntrustedTouchesTest,WindowWithBlockUntrustedModeAndWindowWithOpacityBelowFromDifferentApps_BlocksTouch)12284 TEST_F(InputDispatcherUntrustedTouchesTest,
12285 WindowWithBlockUntrustedModeAndWindowWithOpacityBelowFromDifferentApps_BlocksTouch) {
12286 const sp<FakeWindowHandle>& wB =
12287 getOccludingWindow(APP_B_UID, "B", TouchOcclusionMode::BLOCK_UNTRUSTED,
12288 OPACITY_BELOW_THRESHOLD);
12289 const sp<FakeWindowHandle>& wC =
12290 getOccludingWindow(APP_C_UID, "C", TouchOcclusionMode::USE_OPACITY,
12291 OPACITY_BELOW_THRESHOLD);
12292 mDispatcher->onWindowInfosChanged(
12293 {{*wB->getInfo(), *wC->getInfo(), *mTouchWindow->getInfo()}, {}, 0, 0});
12294
12295 touch();
12296
12297 mTouchWindow->assertNoEvents();
12298 }
12299
12300 /**
12301 * This test is testing that a window from a different UID but with same application token doesn't
12302 * block the touch. Apps can share the application token for close UI collaboration for example.
12303 */
TEST_F(InputDispatcherUntrustedTouchesTest,WindowWithSameApplicationTokenFromDifferentApp_AllowsTouch)12304 TEST_F(InputDispatcherUntrustedTouchesTest,
12305 WindowWithSameApplicationTokenFromDifferentApp_AllowsTouch) {
12306 const sp<FakeWindowHandle>& w =
12307 getOccludingWindow(APP_B_UID, "B", TouchOcclusionMode::BLOCK_UNTRUSTED);
12308 w->setApplicationToken(mTouchWindow->getApplicationToken());
12309 mDispatcher->onWindowInfosChanged({{*w->getInfo(), *mTouchWindow->getInfo()}, {}, 0, 0});
12310
12311 touch();
12312
12313 mTouchWindow->consumeAnyMotionDown();
12314 }
12315
12316 class InputDispatcherDragTests : public InputDispatcherTest {
12317 protected:
12318 std::shared_ptr<FakeApplicationHandle> mApp;
12319 sp<FakeWindowHandle> mWindow;
12320 sp<FakeWindowHandle> mSecondWindow;
12321 sp<FakeWindowHandle> mDragWindow;
12322 sp<FakeWindowHandle> mSpyWindow;
12323 // Mouse would force no-split, set the id as non-zero to verify if drag state could track it.
12324 static constexpr int32_t MOUSE_POINTER_ID = 1;
12325
SetUp()12326 void SetUp() override {
12327 InputDispatcherTest::SetUp();
12328 mApp = std::make_shared<FakeApplicationHandle>();
12329 mWindow = sp<FakeWindowHandle>::make(mApp, mDispatcher, "TestWindow",
12330 ui::LogicalDisplayId::DEFAULT);
12331 mWindow->setFrame(Rect(0, 0, 100, 100));
12332
12333 mSecondWindow = sp<FakeWindowHandle>::make(mApp, mDispatcher, "TestWindow2",
12334 ui::LogicalDisplayId::DEFAULT);
12335 mSecondWindow->setFrame(Rect(100, 0, 200, 100));
12336
12337 mSpyWindow = sp<FakeWindowHandle>::make(mApp, mDispatcher, "SpyWindow",
12338 ui::LogicalDisplayId::DEFAULT);
12339 mSpyWindow->setSpy(true);
12340 mSpyWindow->setTrustedOverlay(true);
12341 mSpyWindow->setFrame(Rect(0, 0, 200, 100));
12342
12343 mDispatcher->setFocusedApplication(ui::LogicalDisplayId::DEFAULT, mApp);
12344 mDispatcher->onWindowInfosChanged(
12345 {{*mSpyWindow->getInfo(), *mWindow->getInfo(), *mSecondWindow->getInfo()},
12346 {},
12347 0,
12348 0});
12349 }
12350
injectDown(int fromSource=AINPUT_SOURCE_TOUCHSCREEN)12351 void injectDown(int fromSource = AINPUT_SOURCE_TOUCHSCREEN) {
12352 switch (fromSource) {
12353 case AINPUT_SOURCE_TOUCHSCREEN:
12354 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
12355 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN,
12356 ui::LogicalDisplayId::DEFAULT, {50, 50}))
12357 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
12358 break;
12359 case AINPUT_SOURCE_STYLUS:
12360 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
12361 injectMotionEvent(*mDispatcher,
12362 MotionEventBuilder(AMOTION_EVENT_ACTION_DOWN,
12363 AINPUT_SOURCE_STYLUS)
12364 .buttonState(
12365 AMOTION_EVENT_BUTTON_STYLUS_PRIMARY)
12366 .pointer(PointerBuilder(0, ToolType::STYLUS)
12367 .x(50)
12368 .y(50))
12369 .build()));
12370 break;
12371 case AINPUT_SOURCE_MOUSE:
12372 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
12373 injectMotionEvent(*mDispatcher,
12374 MotionEventBuilder(AMOTION_EVENT_ACTION_DOWN,
12375 AINPUT_SOURCE_MOUSE)
12376 .buttonState(AMOTION_EVENT_BUTTON_PRIMARY)
12377 .pointer(PointerBuilder(MOUSE_POINTER_ID,
12378 ToolType::MOUSE)
12379 .x(50)
12380 .y(50))
12381 .build()));
12382 break;
12383 default:
12384 FAIL() << "Source " << fromSource << " doesn't support drag and drop";
12385 }
12386
12387 // Window should receive motion event.
12388 mWindow->consumeMotionDown(ui::LogicalDisplayId::DEFAULT);
12389 // Spy window should also receive motion event
12390 mSpyWindow->consumeMotionDown(ui::LogicalDisplayId::DEFAULT);
12391 }
12392
12393 // Start performing drag, we will create a drag window and transfer touch to it.
12394 // @param sendDown : if true, send a motion down on first window before perform drag and drop.
12395 // Returns true on success.
startDrag(bool sendDown=true,int fromSource=AINPUT_SOURCE_TOUCHSCREEN)12396 bool startDrag(bool sendDown = true, int fromSource = AINPUT_SOURCE_TOUCHSCREEN) {
12397 if (sendDown) {
12398 injectDown(fromSource);
12399 }
12400
12401 // The drag window covers the entire display
12402 mDragWindow = sp<FakeWindowHandle>::make(mApp, mDispatcher, "DragWindow",
12403 ui::LogicalDisplayId::DEFAULT);
12404 mDragWindow->setTouchableRegion(Region{{0, 0, 0, 0}});
12405 mDispatcher->onWindowInfosChanged({{*mDragWindow->getInfo(), *mSpyWindow->getInfo(),
12406 *mWindow->getInfo(), *mSecondWindow->getInfo()},
12407 {},
12408 0,
12409 0});
12410
12411 // Transfer touch focus to the drag window
12412 bool transferred =
12413 mDispatcher->transferTouchGesture(mWindow->getToken(), mDragWindow->getToken(),
12414 /*isDragDrop=*/true);
12415 if (transferred) {
12416 mWindow->consumeMotionCancel();
12417 mDragWindow->consumeMotionDown(ui::LogicalDisplayId::DEFAULT,
12418 AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
12419 }
12420 return transferred;
12421 }
12422 };
12423
TEST_F(InputDispatcherDragTests,DragEnterAndDragExit)12424 TEST_F(InputDispatcherDragTests, DragEnterAndDragExit) {
12425 startDrag();
12426
12427 // Move on window.
12428 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
12429 injectMotionEvent(*mDispatcher, AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN,
12430 ui::LogicalDisplayId::DEFAULT, {50, 50}))
12431 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
12432 mDragWindow->consumeMotionMove(ui::LogicalDisplayId::DEFAULT,
12433 AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
12434 mWindow->consumeDragEvent(false, 50, 50);
12435 mSecondWindow->assertNoEvents();
12436
12437 // Move to another window.
12438 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
12439 injectMotionEvent(*mDispatcher, AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN,
12440 ui::LogicalDisplayId::DEFAULT, {150, 50}))
12441 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
12442 mDragWindow->consumeMotionMove(ui::LogicalDisplayId::DEFAULT,
12443 AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
12444 mWindow->consumeDragEvent(true, 150, 50);
12445 mSecondWindow->consumeDragEvent(false, 50, 50);
12446
12447 // Move back to original window.
12448 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
12449 injectMotionEvent(*mDispatcher, AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN,
12450 ui::LogicalDisplayId::DEFAULT, {50, 50}))
12451 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
12452 mDragWindow->consumeMotionMove(ui::LogicalDisplayId::DEFAULT,
12453 AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
12454 mWindow->consumeDragEvent(false, 50, 50);
12455 mSecondWindow->consumeDragEvent(true, -50, 50);
12456
12457 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
12458 injectMotionUp(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ui::LogicalDisplayId::DEFAULT,
12459 {50, 50}))
12460 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
12461 mDragWindow->consumeMotionUp(ui::LogicalDisplayId::DEFAULT, AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
12462 mWindow->assertNoEvents();
12463 mSecondWindow->assertNoEvents();
12464 }
12465
TEST_F(InputDispatcherDragTests,DragEnterAndPointerDownPilfersPointers)12466 TEST_F(InputDispatcherDragTests, DragEnterAndPointerDownPilfersPointers) {
12467 startDrag();
12468
12469 // No cancel event after drag start
12470 mSpyWindow->assertNoEvents();
12471
12472 const MotionEvent secondFingerDownEvent =
12473 MotionEventBuilder(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
12474 .eventTime(systemTime(SYSTEM_TIME_MONOTONIC))
12475 .pointer(PointerBuilder(/*id=*/0, ToolType::FINGER).x(50).y(50))
12476 .pointer(PointerBuilder(/*id=*/1, ToolType::FINGER).x(60).y(60))
12477 .build();
12478 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
12479 injectMotionEvent(*mDispatcher, secondFingerDownEvent, INJECT_EVENT_TIMEOUT,
12480 InputEventInjectionSync::WAIT_FOR_RESULT))
12481 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
12482
12483 // Receives cancel for first pointer after next pointer down
12484 mSpyWindow->consumeMotionCancel();
12485 mSpyWindow->consumeMotionDown();
12486
12487 mSpyWindow->assertNoEvents();
12488 }
12489
TEST_F(InputDispatcherDragTests,DragAndDrop)12490 TEST_F(InputDispatcherDragTests, DragAndDrop) {
12491 startDrag();
12492
12493 // Move on window.
12494 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
12495 injectMotionEvent(*mDispatcher, AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN,
12496 ui::LogicalDisplayId::DEFAULT, {50, 50}))
12497 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
12498 mDragWindow->consumeMotionMove(ui::LogicalDisplayId::DEFAULT,
12499 AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
12500 mWindow->consumeDragEvent(false, 50, 50);
12501 mSecondWindow->assertNoEvents();
12502
12503 // Move to another window.
12504 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
12505 injectMotionEvent(*mDispatcher, AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN,
12506 ui::LogicalDisplayId::DEFAULT, {150, 50}))
12507 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
12508 mDragWindow->consumeMotionMove(ui::LogicalDisplayId::DEFAULT,
12509 AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
12510 mWindow->consumeDragEvent(true, 150, 50);
12511 mSecondWindow->consumeDragEvent(false, 50, 50);
12512
12513 // drop to another window.
12514 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
12515 injectMotionUp(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ui::LogicalDisplayId::DEFAULT,
12516 {150, 50}))
12517 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
12518 mDragWindow->consumeMotionUp(ui::LogicalDisplayId::DEFAULT, AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
12519 mFakePolicy->assertDropTargetEquals(*mDispatcher, mSecondWindow->getToken());
12520 mWindow->assertNoEvents();
12521 mSecondWindow->assertNoEvents();
12522 }
12523
TEST_F(InputDispatcherDragTests,DragAndDropNotCancelledIfSomeOtherPointerIsPilfered)12524 TEST_F(InputDispatcherDragTests, DragAndDropNotCancelledIfSomeOtherPointerIsPilfered) {
12525 startDrag();
12526
12527 // No cancel event after drag start
12528 mSpyWindow->assertNoEvents();
12529
12530 const MotionEvent secondFingerDownEvent =
12531 MotionEventBuilder(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
12532 .eventTime(systemTime(SYSTEM_TIME_MONOTONIC))
12533 .pointer(PointerBuilder(/*id=*/0, ToolType::FINGER).x(50).y(50))
12534 .pointer(PointerBuilder(/*id=*/1, ToolType::FINGER).x(60).y(60))
12535 .build();
12536 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
12537 injectMotionEvent(*mDispatcher, secondFingerDownEvent, INJECT_EVENT_TIMEOUT,
12538 InputEventInjectionSync::WAIT_FOR_RESULT))
12539 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
12540
12541 // Receives cancel for first pointer after next pointer down
12542 mSpyWindow->consumeMotionEvent(WithMotionAction(ACTION_CANCEL));
12543 mSpyWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithPointerIds({1})));
12544 mDragWindow->consumeMotionEvent(WithMotionAction(ACTION_MOVE));
12545
12546 mSpyWindow->assertNoEvents();
12547
12548 // Spy window calls pilfer pointers
12549 EXPECT_EQ(OK, mDispatcher->pilferPointers(mSpyWindow->getToken()));
12550 mDragWindow->assertNoEvents();
12551
12552 const MotionEvent firstFingerMoveEvent =
12553 MotionEventBuilder(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN)
12554 .eventTime(systemTime(SYSTEM_TIME_MONOTONIC))
12555 .pointer(PointerBuilder(/*id=*/0, ToolType::FINGER).x(60).y(60))
12556 .pointer(PointerBuilder(/*id=*/1, ToolType::FINGER).x(60).y(60))
12557 .build();
12558 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
12559 injectMotionEvent(*mDispatcher, firstFingerMoveEvent, INJECT_EVENT_TIMEOUT,
12560 InputEventInjectionSync::WAIT_FOR_RESULT))
12561 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
12562
12563 // Drag window should still receive the new event
12564 mDragWindow->consumeMotionEvent(
12565 AllOf(WithMotionAction(ACTION_MOVE), WithFlags(AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE)));
12566 mDragWindow->assertNoEvents();
12567 }
12568
TEST_F(InputDispatcherDragTests,StylusDragAndDrop)12569 TEST_F(InputDispatcherDragTests, StylusDragAndDrop) {
12570 startDrag(true, AINPUT_SOURCE_STYLUS);
12571
12572 // Move on window and keep button pressed.
12573 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
12574 injectMotionEvent(*mDispatcher,
12575 MotionEventBuilder(AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_STYLUS)
12576 .buttonState(AMOTION_EVENT_BUTTON_STYLUS_PRIMARY)
12577 .pointer(PointerBuilder(0, ToolType::STYLUS).x(50).y(50))
12578 .build()))
12579 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
12580 mDragWindow->consumeMotionMove(ui::LogicalDisplayId::DEFAULT,
12581 AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
12582 mWindow->consumeDragEvent(false, 50, 50);
12583 mSecondWindow->assertNoEvents();
12584
12585 // Move to another window and release button, expect to drop item.
12586 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
12587 injectMotionEvent(*mDispatcher,
12588 MotionEventBuilder(AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_STYLUS)
12589 .buttonState(0)
12590 .pointer(PointerBuilder(0, ToolType::STYLUS).x(150).y(50))
12591 .build()))
12592 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
12593 mDragWindow->consumeMotionMove(ui::LogicalDisplayId::DEFAULT,
12594 AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
12595 mWindow->assertNoEvents();
12596 mSecondWindow->assertNoEvents();
12597 mFakePolicy->assertDropTargetEquals(*mDispatcher, mSecondWindow->getToken());
12598
12599 // nothing to the window.
12600 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
12601 injectMotionEvent(*mDispatcher,
12602 MotionEventBuilder(AMOTION_EVENT_ACTION_UP, AINPUT_SOURCE_STYLUS)
12603 .buttonState(0)
12604 .pointer(PointerBuilder(0, ToolType::STYLUS).x(150).y(50))
12605 .build()))
12606 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
12607 mDragWindow->consumeMotionUp(ui::LogicalDisplayId::DEFAULT, AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
12608 mWindow->assertNoEvents();
12609 mSecondWindow->assertNoEvents();
12610 }
12611
TEST_F(InputDispatcherDragTests,DragAndDropOnInvalidWindow)12612 TEST_F(InputDispatcherDragTests, DragAndDropOnInvalidWindow) {
12613 startDrag();
12614
12615 // Set second window invisible.
12616 mSecondWindow->setVisible(false);
12617 mDispatcher->onWindowInfosChanged(
12618 {{*mDragWindow->getInfo(), *mWindow->getInfo(), *mSecondWindow->getInfo()}, {}, 0, 0});
12619
12620 // Move on window.
12621 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
12622 injectMotionEvent(*mDispatcher, AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN,
12623 ui::LogicalDisplayId::DEFAULT, {50, 50}))
12624 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
12625 mDragWindow->consumeMotionMove(ui::LogicalDisplayId::DEFAULT,
12626 AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
12627 mWindow->consumeDragEvent(false, 50, 50);
12628 mSecondWindow->assertNoEvents();
12629
12630 // Move to another window.
12631 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
12632 injectMotionEvent(*mDispatcher, AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN,
12633 ui::LogicalDisplayId::DEFAULT, {150, 50}))
12634 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
12635 mDragWindow->consumeMotionMove(ui::LogicalDisplayId::DEFAULT,
12636 AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
12637 mWindow->consumeDragEvent(true, 150, 50);
12638 mSecondWindow->assertNoEvents();
12639
12640 // drop to another window.
12641 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
12642 injectMotionUp(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ui::LogicalDisplayId::DEFAULT,
12643 {150, 50}))
12644 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
12645 mDragWindow->consumeMotionUp(ui::LogicalDisplayId::DEFAULT, AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
12646 mFakePolicy->assertDropTargetEquals(*mDispatcher, nullptr);
12647 mWindow->assertNoEvents();
12648 mSecondWindow->assertNoEvents();
12649 }
12650
TEST_F(InputDispatcherDragTests,NoDragAndDropWhenMultiFingers)12651 TEST_F(InputDispatcherDragTests, NoDragAndDropWhenMultiFingers) {
12652 // Ensure window could track pointerIds if it didn't support split touch.
12653 mWindow->setPreventSplitting(true);
12654
12655 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
12656 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN,
12657 ui::LogicalDisplayId::DEFAULT, {50, 50}))
12658 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
12659 mWindow->consumeMotionDown(ui::LogicalDisplayId::DEFAULT);
12660
12661 const MotionEvent secondFingerDownEvent =
12662 MotionEventBuilder(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
12663 .displayId(ui::LogicalDisplayId::DEFAULT)
12664 .eventTime(systemTime(SYSTEM_TIME_MONOTONIC))
12665 .pointer(PointerBuilder(/*id=*/0, ToolType::FINGER).x(50).y(50))
12666 .pointer(PointerBuilder(/*id=*/1, ToolType::FINGER).x(75).y(50))
12667 .build();
12668 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
12669 injectMotionEvent(*mDispatcher, secondFingerDownEvent, INJECT_EVENT_TIMEOUT,
12670 InputEventInjectionSync::WAIT_FOR_RESULT))
12671 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
12672 mWindow->consumeMotionPointerDown(/*pointerIndex=*/1);
12673
12674 // Should not perform drag and drop when window has multi fingers.
12675 ASSERT_FALSE(startDrag(false));
12676 }
12677
TEST_F(InputDispatcherDragTests,DragAndDropWhenSplitTouch)12678 TEST_F(InputDispatcherDragTests, DragAndDropWhenSplitTouch) {
12679 // First down on second window.
12680 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
12681 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN,
12682 ui::LogicalDisplayId::DEFAULT, {150, 50}))
12683 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
12684
12685 mSecondWindow->consumeMotionDown(ui::LogicalDisplayId::DEFAULT);
12686
12687 // Second down on first window.
12688 const MotionEvent secondFingerDownEvent =
12689 MotionEventBuilder(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
12690 .displayId(ui::LogicalDisplayId::DEFAULT)
12691 .eventTime(systemTime(SYSTEM_TIME_MONOTONIC))
12692 .pointer(PointerBuilder(/*id=*/0, ToolType::FINGER).x(150).y(50))
12693 .pointer(PointerBuilder(/*id=*/1, ToolType::FINGER).x(50).y(50))
12694 .build();
12695 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
12696 injectMotionEvent(*mDispatcher, secondFingerDownEvent, INJECT_EVENT_TIMEOUT,
12697 InputEventInjectionSync::WAIT_FOR_RESULT))
12698 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
12699 mWindow->consumeMotionDown(ui::LogicalDisplayId::DEFAULT);
12700 mSecondWindow->consumeMotionMove(ui::LogicalDisplayId::DEFAULT);
12701
12702 // Perform drag and drop from first window.
12703 ASSERT_TRUE(startDrag(false));
12704
12705 // Move on window.
12706 const MotionEvent secondFingerMoveEvent =
12707 MotionEventBuilder(AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN)
12708 .eventTime(systemTime(SYSTEM_TIME_MONOTONIC))
12709 .pointer(PointerBuilder(/*id=*/0, ToolType::FINGER).x(150).y(50))
12710 .pointer(PointerBuilder(/*id=*/1, ToolType::FINGER).x(50).y(50))
12711 .build();
12712 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
12713 injectMotionEvent(*mDispatcher, secondFingerMoveEvent, INJECT_EVENT_TIMEOUT,
12714 InputEventInjectionSync::WAIT_FOR_RESULT));
12715 mDragWindow->consumeMotionMove(ui::LogicalDisplayId::DEFAULT,
12716 AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
12717 mWindow->consumeDragEvent(false, 50, 50);
12718 mSecondWindow->consumeMotionMove();
12719
12720 // Release the drag pointer should perform drop.
12721 const MotionEvent secondFingerUpEvent =
12722 MotionEventBuilder(POINTER_1_UP, AINPUT_SOURCE_TOUCHSCREEN)
12723 .eventTime(systemTime(SYSTEM_TIME_MONOTONIC))
12724 .pointer(PointerBuilder(/*id=*/0, ToolType::FINGER).x(150).y(50))
12725 .pointer(PointerBuilder(/*id=*/1, ToolType::FINGER).x(50).y(50))
12726 .build();
12727 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
12728 injectMotionEvent(*mDispatcher, secondFingerUpEvent, INJECT_EVENT_TIMEOUT,
12729 InputEventInjectionSync::WAIT_FOR_RESULT));
12730 mDragWindow->consumeMotionUp(ui::LogicalDisplayId::DEFAULT, AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
12731 mFakePolicy->assertDropTargetEquals(*mDispatcher, mWindow->getToken());
12732 mWindow->assertNoEvents();
12733 mSecondWindow->consumeMotionMove();
12734 }
12735
TEST_F(InputDispatcherDragTests,DragAndDropWhenMultiDisplays)12736 TEST_F(InputDispatcherDragTests, DragAndDropWhenMultiDisplays) {
12737 startDrag();
12738
12739 // Update window of second display.
12740 sp<FakeWindowHandle> windowInSecondary =
12741 sp<FakeWindowHandle>::make(mApp, mDispatcher, "D_2", SECOND_DISPLAY_ID);
12742 mDispatcher->onWindowInfosChanged(
12743 {{*mDragWindow->getInfo(), *mSpyWindow->getInfo(), *mWindow->getInfo(),
12744 *mSecondWindow->getInfo(), *windowInSecondary->getInfo()},
12745 {},
12746 0,
12747 0});
12748
12749 // Let second display has a touch state.
12750 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
12751 injectMotionEvent(*mDispatcher,
12752 MotionEventBuilder(AMOTION_EVENT_ACTION_DOWN,
12753 AINPUT_SOURCE_TOUCHSCREEN)
12754 .displayId(SECOND_DISPLAY_ID)
12755 .pointer(PointerBuilder(0, ToolType::FINGER).x(100).y(100))
12756 .build()));
12757 windowInSecondary->consumeMotionDown(SECOND_DISPLAY_ID, /*expectedFlag=*/0);
12758 // Update window again.
12759 mDispatcher->onWindowInfosChanged(
12760 {{*mDragWindow->getInfo(), *mSpyWindow->getInfo(), *mWindow->getInfo(),
12761 *mSecondWindow->getInfo(), *windowInSecondary->getInfo()},
12762 {},
12763 0,
12764 0});
12765
12766 // Move on window.
12767 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
12768 injectMotionEvent(*mDispatcher, AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN,
12769 ui::LogicalDisplayId::DEFAULT, {50, 50}))
12770 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
12771 mDragWindow->consumeMotionMove(ui::LogicalDisplayId::DEFAULT,
12772 AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
12773 mWindow->consumeDragEvent(false, 50, 50);
12774 mSecondWindow->assertNoEvents();
12775
12776 // Move to another window.
12777 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
12778 injectMotionEvent(*mDispatcher, AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN,
12779 ui::LogicalDisplayId::DEFAULT, {150, 50}))
12780 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
12781 mDragWindow->consumeMotionMove(ui::LogicalDisplayId::DEFAULT,
12782 AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
12783 mWindow->consumeDragEvent(true, 150, 50);
12784 mSecondWindow->consumeDragEvent(false, 50, 50);
12785
12786 // drop to another window.
12787 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
12788 injectMotionUp(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ui::LogicalDisplayId::DEFAULT,
12789 {150, 50}))
12790 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
12791 mDragWindow->consumeMotionUp(ui::LogicalDisplayId::DEFAULT, AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
12792 mFakePolicy->assertDropTargetEquals(*mDispatcher, mSecondWindow->getToken());
12793 mWindow->assertNoEvents();
12794 mSecondWindow->assertNoEvents();
12795 }
12796
TEST_F(InputDispatcherDragTests,MouseDragAndDrop)12797 TEST_F(InputDispatcherDragTests, MouseDragAndDrop) {
12798 startDrag(true, AINPUT_SOURCE_MOUSE);
12799 // Move on window.
12800 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
12801 injectMotionEvent(*mDispatcher,
12802 MotionEventBuilder(AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_MOUSE)
12803 .buttonState(AMOTION_EVENT_BUTTON_PRIMARY)
12804 .pointer(PointerBuilder(MOUSE_POINTER_ID, ToolType::MOUSE)
12805 .x(50)
12806 .y(50))
12807 .build()))
12808 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
12809 mDragWindow->consumeMotionMove(ui::LogicalDisplayId::DEFAULT,
12810 AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
12811 mWindow->consumeDragEvent(false, 50, 50);
12812 mSecondWindow->assertNoEvents();
12813
12814 // Move to another window.
12815 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
12816 injectMotionEvent(*mDispatcher,
12817 MotionEventBuilder(AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_MOUSE)
12818 .buttonState(AMOTION_EVENT_BUTTON_PRIMARY)
12819 .pointer(PointerBuilder(MOUSE_POINTER_ID, ToolType::MOUSE)
12820 .x(150)
12821 .y(50))
12822 .build()))
12823 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
12824 mDragWindow->consumeMotionMove(ui::LogicalDisplayId::DEFAULT,
12825 AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
12826 mWindow->consumeDragEvent(true, 150, 50);
12827 mSecondWindow->consumeDragEvent(false, 50, 50);
12828
12829 // drop to another window.
12830 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
12831 injectMotionEvent(*mDispatcher,
12832 MotionEventBuilder(AMOTION_EVENT_ACTION_UP, AINPUT_SOURCE_MOUSE)
12833 .buttonState(0)
12834 .pointer(PointerBuilder(MOUSE_POINTER_ID, ToolType::MOUSE)
12835 .x(150)
12836 .y(50))
12837 .build()))
12838 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
12839 mDragWindow->consumeMotionUp(ui::LogicalDisplayId::DEFAULT, AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
12840 mFakePolicy->assertDropTargetEquals(*mDispatcher, mSecondWindow->getToken());
12841 mWindow->assertNoEvents();
12842 mSecondWindow->assertNoEvents();
12843 }
12844
12845 /**
12846 * Start drag and drop with a pointer whose id is not 0, cancel the current touch, and ensure drag
12847 * and drop is also canceled. Then inject a simple gesture, and ensure dispatcher does not crash.
12848 */
TEST_F(InputDispatcherDragTests,DragAndDropFinishedWhenCancelCurrentTouch)12849 TEST_F(InputDispatcherDragTests, DragAndDropFinishedWhenCancelCurrentTouch) {
12850 // Down on second window
12851 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
12852 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN,
12853 ui::LogicalDisplayId::DEFAULT, {150, 50}))
12854 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
12855
12856 ASSERT_NO_FATAL_FAILURE(mSecondWindow->consumeMotionDown());
12857 ASSERT_NO_FATAL_FAILURE(mSpyWindow->consumeMotionDown());
12858
12859 // Down on first window
12860 const MotionEvent secondFingerDownEvent =
12861 MotionEventBuilder(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
12862 .displayId(ui::LogicalDisplayId::DEFAULT)
12863 .pointer(PointerBuilder(/*id=*/0, ToolType::FINGER).x(150).y(50))
12864 .pointer(PointerBuilder(/*id=*/1, ToolType::FINGER).x(50).y(50))
12865 .build();
12866 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
12867 injectMotionEvent(*mDispatcher, secondFingerDownEvent, INJECT_EVENT_TIMEOUT,
12868 InputEventInjectionSync::WAIT_FOR_RESULT))
12869 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
12870 ASSERT_NO_FATAL_FAILURE(mWindow->consumeMotionDown());
12871 ASSERT_NO_FATAL_FAILURE(mSecondWindow->consumeMotionMove());
12872 ASSERT_NO_FATAL_FAILURE(mSpyWindow->consumeMotionPointerDown(1));
12873
12874 // Start drag on first window
12875 ASSERT_TRUE(startDrag(/*sendDown=*/false, AINPUT_SOURCE_TOUCHSCREEN));
12876
12877 // Trigger cancel
12878 mDispatcher->cancelCurrentTouch();
12879 ASSERT_NO_FATAL_FAILURE(mSecondWindow->consumeMotionCancel());
12880 ASSERT_NO_FATAL_FAILURE(mDragWindow->consumeMotionCancel(ui::LogicalDisplayId::DEFAULT,
12881 AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE));
12882 ASSERT_NO_FATAL_FAILURE(mSpyWindow->consumeMotionCancel());
12883
12884 ASSERT_TRUE(mDispatcher->waitForIdle());
12885 // The D&D finished with nullptr
12886 mFakePolicy->assertDropTargetEquals(*mDispatcher, nullptr);
12887
12888 // Remove drag window
12889 mDispatcher->onWindowInfosChanged({{*mWindow->getInfo(), *mSecondWindow->getInfo()}, {}, 0, 0});
12890
12891 // Complete the first event stream, even though the injection will fail because there aren't any
12892 // valid targets to dispatch this event to. This is still needed to make the input stream
12893 // consistent
12894 ASSERT_EQ(InputEventInjectionResult::FAILED,
12895 injectMotionEvent(*mDispatcher,
12896 MotionEventBuilder(ACTION_CANCEL, AINPUT_SOURCE_TOUCHSCREEN)
12897 .displayId(ui::LogicalDisplayId::DEFAULT)
12898 .pointer(PointerBuilder(/*id=*/0, ToolType::FINGER)
12899 .x(150)
12900 .y(50))
12901 .pointer(PointerBuilder(/*id=*/1, ToolType::FINGER)
12902 .x(50)
12903 .y(50))
12904 .build(),
12905 INJECT_EVENT_TIMEOUT, InputEventInjectionSync::WAIT_FOR_RESULT));
12906
12907 // Inject a simple gesture, ensure dispatcher not crashed
12908 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
12909 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN,
12910 ui::LogicalDisplayId::DEFAULT, PointF{50, 50}))
12911 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
12912 ASSERT_NO_FATAL_FAILURE(mWindow->consumeMotionDown());
12913
12914 const MotionEvent moveEvent =
12915 MotionEventBuilder(AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN)
12916 .displayId(ui::LogicalDisplayId::DEFAULT)
12917 .pointer(PointerBuilder(/*id=*/0, ToolType::FINGER).x(50).y(50))
12918 .build();
12919 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
12920 injectMotionEvent(*mDispatcher, moveEvent, INJECT_EVENT_TIMEOUT,
12921 InputEventInjectionSync::WAIT_FOR_RESULT))
12922 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
12923 ASSERT_NO_FATAL_FAILURE(mWindow->consumeMotionMove());
12924
12925 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
12926 injectMotionUp(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ui::LogicalDisplayId::DEFAULT,
12927 {50, 50}))
12928 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
12929 ASSERT_NO_FATAL_FAILURE(mWindow->consumeMotionUp());
12930 }
12931
TEST_F(InputDispatcherDragTests,NoDragAndDropWithHoveringPointer)12932 TEST_F(InputDispatcherDragTests, NoDragAndDropWithHoveringPointer) {
12933 // Start hovering over the window.
12934 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
12935 injectMotionEvent(*mDispatcher, ACTION_HOVER_ENTER, AINPUT_SOURCE_MOUSE,
12936 ui::LogicalDisplayId::DEFAULT, {50, 50}));
12937
12938 ASSERT_NO_FATAL_FAILURE(mWindow->consumeMotionEvent(WithMotionAction(ACTION_HOVER_ENTER)));
12939 ASSERT_NO_FATAL_FAILURE(mSpyWindow->consumeMotionEvent(WithMotionAction(ACTION_HOVER_ENTER)));
12940
12941 ASSERT_FALSE(startDrag(/*sendDown=*/false))
12942 << "Drag and drop should not work with a hovering pointer";
12943 }
12944
12945 /**
12946 * Two devices, we use the second pointer of Device A to start the drag, during the drag process, if
12947 * we perform a click using Device B, the dispatcher should work well.
12948 */
TEST_F(InputDispatcherDragTests,DragAndDropWhenSplitTouchAndMultiDevice)12949 TEST_F(InputDispatcherDragTests, DragAndDropWhenSplitTouchAndMultiDevice) {
12950 const DeviceId deviceA = 1;
12951 const DeviceId deviceB = 2;
12952 // First down on second window with deviceA.
12953 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
12954 .deviceId(deviceA)
12955 .pointer(PointerBuilder(0, ToolType::FINGER).x(150).y(50))
12956 .build());
12957 mSecondWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(deviceA),
12958 WithDisplayId(ui::LogicalDisplayId::DEFAULT)));
12959
12960 // Second down on first window with deviceA
12961 mDispatcher->notifyMotion(MotionArgsBuilder(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
12962 .deviceId(deviceA)
12963 .pointer(PointerBuilder(0, ToolType::FINGER).x(150).y(50))
12964 .pointer(PointerBuilder(1, ToolType::FINGER).x(50).y(50))
12965 .build());
12966 mWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(deviceA),
12967 WithDisplayId(ui::LogicalDisplayId::DEFAULT)));
12968 mSecondWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(deviceA),
12969 WithDisplayId(ui::LogicalDisplayId::DEFAULT)));
12970
12971 // Perform drag and drop from first window.
12972 ASSERT_TRUE(startDrag(/*sendDown=*/false));
12973
12974 // Click first window with device B, we should ensure dispatcher work well.
12975 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_MOUSE)
12976 .deviceId(deviceB)
12977 .pointer(PointerBuilder(0, ToolType::FINGER).x(50).y(50))
12978 .build());
12979 mWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(deviceB),
12980 WithDisplayId(ui::LogicalDisplayId::DEFAULT)));
12981
12982 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_UP, AINPUT_SOURCE_MOUSE)
12983 .deviceId(deviceB)
12984 .pointer(PointerBuilder(0, ToolType::FINGER).x(50).y(50))
12985 .build());
12986 mWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_UP), WithDeviceId(deviceB),
12987 WithDisplayId(ui::LogicalDisplayId::DEFAULT)));
12988
12989 // Move with device A.
12990 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN)
12991 .deviceId(deviceA)
12992 .pointer(PointerBuilder(0, ToolType::FINGER).x(151).y(51))
12993 .pointer(PointerBuilder(1, ToolType::FINGER).x(51).y(51))
12994 .build());
12995
12996 mDragWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(deviceA),
12997 WithDisplayId(ui::LogicalDisplayId::DEFAULT),
12998 WithFlags(AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE)));
12999 mWindow->consumeDragEvent(false, 51, 51);
13000 mSecondWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(deviceA),
13001 WithDisplayId(ui::LogicalDisplayId::DEFAULT)));
13002
13003 // Releasing the drag pointer should cause drop.
13004 mDispatcher->notifyMotion(MotionArgsBuilder(POINTER_1_UP, AINPUT_SOURCE_TOUCHSCREEN)
13005 .deviceId(deviceA)
13006 .pointer(PointerBuilder(0, ToolType::FINGER).x(151).y(51))
13007 .pointer(PointerBuilder(1, ToolType::FINGER).x(51).y(51))
13008 .build());
13009 mDragWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_UP), WithDeviceId(deviceA),
13010 WithDisplayId(ui::LogicalDisplayId::DEFAULT),
13011 WithFlags(AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE)));
13012 mFakePolicy->assertDropTargetEquals(*mDispatcher, mWindow->getToken());
13013 mSecondWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(deviceA),
13014 WithDisplayId(ui::LogicalDisplayId::DEFAULT)));
13015
13016 // Release all pointers.
13017 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN)
13018 .deviceId(deviceA)
13019 .pointer(PointerBuilder(0, ToolType::FINGER).x(151).y(51))
13020 .build());
13021 mSecondWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_UP), WithDeviceId(deviceA),
13022 WithDisplayId(ui::LogicalDisplayId::DEFAULT)));
13023 mWindow->assertNoEvents();
13024 }
13025
13026 class InputDispatcherDropInputFeatureTest : public InputDispatcherTest {};
13027
TEST_F(InputDispatcherDropInputFeatureTest,WindowDropsInput)13028 TEST_F(InputDispatcherDropInputFeatureTest, WindowDropsInput) {
13029 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
13030 sp<FakeWindowHandle> window =
13031 sp<FakeWindowHandle>::make(application, mDispatcher, "Test window",
13032 ui::LogicalDisplayId::DEFAULT);
13033 window->setDropInput(true);
13034 mDispatcher->setFocusedApplication(ui::LogicalDisplayId::DEFAULT, application);
13035 window->setFocusable(true);
13036 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
13037 setFocusedWindow(window);
13038 window->consumeFocusEvent(/*hasFocus=*/true, /*inTouchMode=*/true);
13039
13040 // With the flag set, window should not get any input
13041 mDispatcher->notifyKey(generateKeyArgs(AKEY_EVENT_ACTION_DOWN, ui::LogicalDisplayId::DEFAULT));
13042 window->assertNoEvents();
13043
13044 mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_DOWN,
13045 AINPUT_SOURCE_TOUCHSCREEN,
13046 ui::LogicalDisplayId::DEFAULT));
13047 mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN,
13048 ui::LogicalDisplayId::DEFAULT));
13049 mDispatcher->waitForIdle();
13050 window->assertNoEvents();
13051
13052 // With the flag cleared, the window should get input
13053 window->setDropInput(false);
13054 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
13055
13056 mDispatcher->notifyKey(generateKeyArgs(AKEY_EVENT_ACTION_UP, ui::LogicalDisplayId::DEFAULT));
13057 window->consumeKeyUp(ui::LogicalDisplayId::DEFAULT);
13058
13059 mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_DOWN,
13060 AINPUT_SOURCE_TOUCHSCREEN,
13061 ui::LogicalDisplayId::DEFAULT));
13062 window->consumeMotionDown(ui::LogicalDisplayId::DEFAULT);
13063 window->assertNoEvents();
13064 }
13065
TEST_F(InputDispatcherDropInputFeatureTest,ObscuredWindowDropsInput)13066 TEST_F(InputDispatcherDropInputFeatureTest, ObscuredWindowDropsInput) {
13067 std::shared_ptr<FakeApplicationHandle> obscuringApplication =
13068 std::make_shared<FakeApplicationHandle>();
13069 sp<FakeWindowHandle> obscuringWindow =
13070 sp<FakeWindowHandle>::make(obscuringApplication, mDispatcher, "obscuringWindow",
13071 ui::LogicalDisplayId::DEFAULT);
13072 obscuringWindow->setFrame(Rect(0, 0, 50, 50));
13073 obscuringWindow->setOwnerInfo(gui::Pid{111}, gui::Uid{111});
13074 obscuringWindow->setTouchable(false);
13075 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
13076 sp<FakeWindowHandle> window =
13077 sp<FakeWindowHandle>::make(application, mDispatcher, "Test window",
13078 ui::LogicalDisplayId::DEFAULT);
13079 window->setDropInputIfObscured(true);
13080 window->setOwnerInfo(gui::Pid{222}, gui::Uid{222});
13081 mDispatcher->setFocusedApplication(ui::LogicalDisplayId::DEFAULT, application);
13082 window->setFocusable(true);
13083 mDispatcher->onWindowInfosChanged(
13084 {{*obscuringWindow->getInfo(), *window->getInfo()}, {}, 0, 0});
13085 setFocusedWindow(window);
13086 window->consumeFocusEvent(/*hasFocus=*/true, /*inTouchMode=*/true);
13087
13088 // With the flag set, window should not get any input
13089 mDispatcher->notifyKey(generateKeyArgs(AKEY_EVENT_ACTION_DOWN, ui::LogicalDisplayId::DEFAULT));
13090 window->assertNoEvents();
13091
13092 mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_DOWN,
13093 AINPUT_SOURCE_TOUCHSCREEN,
13094 ui::LogicalDisplayId::DEFAULT));
13095 mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN,
13096 ui::LogicalDisplayId::DEFAULT));
13097 window->assertNoEvents();
13098
13099 // With the flag cleared, the window should get input
13100 window->setDropInputIfObscured(false);
13101 mDispatcher->onWindowInfosChanged(
13102 {{*obscuringWindow->getInfo(), *window->getInfo()}, {}, 0, 0});
13103
13104 mDispatcher->notifyKey(generateKeyArgs(AKEY_EVENT_ACTION_UP, ui::LogicalDisplayId::DEFAULT));
13105 window->consumeKeyUp(ui::LogicalDisplayId::DEFAULT);
13106
13107 mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_DOWN,
13108 AINPUT_SOURCE_TOUCHSCREEN,
13109 ui::LogicalDisplayId::DEFAULT));
13110 window->consumeMotionDown(ui::LogicalDisplayId::DEFAULT,
13111 AMOTION_EVENT_FLAG_WINDOW_IS_PARTIALLY_OBSCURED);
13112 window->assertNoEvents();
13113 }
13114
TEST_F(InputDispatcherDropInputFeatureTest,UnobscuredWindowGetsInput)13115 TEST_F(InputDispatcherDropInputFeatureTest, UnobscuredWindowGetsInput) {
13116 std::shared_ptr<FakeApplicationHandle> obscuringApplication =
13117 std::make_shared<FakeApplicationHandle>();
13118 sp<FakeWindowHandle> obscuringWindow =
13119 sp<FakeWindowHandle>::make(obscuringApplication, mDispatcher, "obscuringWindow",
13120 ui::LogicalDisplayId::DEFAULT);
13121 obscuringWindow->setFrame(Rect(0, 0, 50, 50));
13122 obscuringWindow->setOwnerInfo(gui::Pid{111}, gui::Uid{111});
13123 obscuringWindow->setTouchable(false);
13124 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
13125 sp<FakeWindowHandle> window =
13126 sp<FakeWindowHandle>::make(application, mDispatcher, "Test window",
13127 ui::LogicalDisplayId::DEFAULT);
13128 window->setDropInputIfObscured(true);
13129 window->setOwnerInfo(gui::Pid{222}, gui::Uid{222});
13130 mDispatcher->setFocusedApplication(ui::LogicalDisplayId::DEFAULT, application);
13131 window->setFocusable(true);
13132 mDispatcher->onWindowInfosChanged(
13133 {{*obscuringWindow->getInfo(), *window->getInfo()}, {}, 0, 0});
13134 setFocusedWindow(window);
13135 window->consumeFocusEvent(/*hasFocus=*/true, /*inTouchMode=*/true);
13136
13137 // With the flag set, window should not get any input
13138 mDispatcher->notifyKey(generateKeyArgs(AKEY_EVENT_ACTION_DOWN, ui::LogicalDisplayId::DEFAULT));
13139 window->assertNoEvents();
13140
13141 mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_DOWN,
13142 AINPUT_SOURCE_TOUCHSCREEN,
13143 ui::LogicalDisplayId::DEFAULT));
13144 mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN,
13145 ui::LogicalDisplayId::DEFAULT));
13146 window->assertNoEvents();
13147
13148 // When the window is no longer obscured because it went on top, it should get input
13149 mDispatcher->onWindowInfosChanged(
13150 {{*window->getInfo(), *obscuringWindow->getInfo()}, {}, 0, 0});
13151
13152 mDispatcher->notifyKey(generateKeyArgs(AKEY_EVENT_ACTION_UP, ui::LogicalDisplayId::DEFAULT));
13153 window->consumeKeyUp(ui::LogicalDisplayId::DEFAULT);
13154
13155 mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_DOWN,
13156 AINPUT_SOURCE_TOUCHSCREEN,
13157 ui::LogicalDisplayId::DEFAULT));
13158 window->consumeMotionDown(ui::LogicalDisplayId::DEFAULT);
13159 window->assertNoEvents();
13160 }
13161
13162 class InputDispatcherTouchModeChangedTests : public InputDispatcherTest {
13163 protected:
13164 std::shared_ptr<FakeApplicationHandle> mApp;
13165 std::shared_ptr<FakeApplicationHandle> mSecondaryApp;
13166 sp<FakeWindowHandle> mWindow;
13167 sp<FakeWindowHandle> mSecondWindow;
13168 sp<FakeWindowHandle> mThirdWindow;
13169
SetUp()13170 void SetUp() override {
13171 InputDispatcherTest::SetUp();
13172
13173 mApp = std::make_shared<FakeApplicationHandle>();
13174 mSecondaryApp = std::make_shared<FakeApplicationHandle>();
13175 mWindow = sp<FakeWindowHandle>::make(mApp, mDispatcher, "TestWindow",
13176 ui::LogicalDisplayId::DEFAULT);
13177 mWindow->setFocusable(true);
13178 setFocusedWindow(mWindow);
13179 mSecondWindow = sp<FakeWindowHandle>::make(mApp, mDispatcher, "TestWindow2",
13180 ui::LogicalDisplayId::DEFAULT);
13181 mSecondWindow->setFocusable(true);
13182 mThirdWindow =
13183 sp<FakeWindowHandle>::make(mSecondaryApp, mDispatcher,
13184 "TestWindow3_SecondaryDisplay", SECOND_DISPLAY_ID);
13185 mThirdWindow->setFocusable(true);
13186
13187 mDispatcher->setFocusedApplication(ui::LogicalDisplayId::DEFAULT, mApp);
13188 mDispatcher->onWindowInfosChanged(
13189 {{*mWindow->getInfo(), *mSecondWindow->getInfo(), *mThirdWindow->getInfo()},
13190 {},
13191 0,
13192 0});
13193 mThirdWindow->setOwnerInfo(SECONDARY_WINDOW_PID, SECONDARY_WINDOW_UID);
13194 mWindow->consumeFocusEvent(true);
13195
13196 // Set main display initial touch mode to InputDispatcher::kDefaultInTouchMode.
13197 if (mDispatcher->setInTouchMode(InputDispatcher::kDefaultInTouchMode, WINDOW_PID,
13198 WINDOW_UID, /*hasPermission=*/true,
13199 ui::LogicalDisplayId::DEFAULT)) {
13200 mWindow->consumeTouchModeEvent(InputDispatcher::kDefaultInTouchMode);
13201 mSecondWindow->consumeTouchModeEvent(InputDispatcher::kDefaultInTouchMode);
13202 mThirdWindow->assertNoEvents();
13203 }
13204
13205 // Set secondary display initial touch mode to InputDispatcher::kDefaultInTouchMode.
13206 if (mDispatcher->setInTouchMode(InputDispatcher::kDefaultInTouchMode, SECONDARY_WINDOW_PID,
13207 SECONDARY_WINDOW_UID, /*hasPermission=*/true,
13208 SECOND_DISPLAY_ID)) {
13209 mWindow->assertNoEvents();
13210 mSecondWindow->assertNoEvents();
13211 mThirdWindow->consumeTouchModeEvent(InputDispatcher::kDefaultInTouchMode);
13212 }
13213 }
13214
changeAndVerifyTouchModeInMainDisplayOnly(bool inTouchMode,gui::Pid pid,gui::Uid uid,bool hasPermission)13215 void changeAndVerifyTouchModeInMainDisplayOnly(bool inTouchMode, gui::Pid pid, gui::Uid uid,
13216 bool hasPermission) {
13217 ASSERT_TRUE(mDispatcher->setInTouchMode(inTouchMode, pid, uid, hasPermission,
13218 ui::LogicalDisplayId::DEFAULT));
13219 mWindow->consumeTouchModeEvent(inTouchMode);
13220 mSecondWindow->consumeTouchModeEvent(inTouchMode);
13221 mThirdWindow->assertNoEvents();
13222 }
13223 };
13224
TEST_F(InputDispatcherTouchModeChangedTests,FocusedWindowCanChangeTouchMode)13225 TEST_F(InputDispatcherTouchModeChangedTests, FocusedWindowCanChangeTouchMode) {
13226 const WindowInfo& windowInfo = *mWindow->getInfo();
13227 changeAndVerifyTouchModeInMainDisplayOnly(!InputDispatcher::kDefaultInTouchMode,
13228 windowInfo.ownerPid, windowInfo.ownerUid,
13229 /* hasPermission=*/false);
13230 }
13231
TEST_F(InputDispatcherTouchModeChangedTests,NonFocusedWindowOwnerCannotChangeTouchMode)13232 TEST_F(InputDispatcherTouchModeChangedTests, NonFocusedWindowOwnerCannotChangeTouchMode) {
13233 const WindowInfo& windowInfo = *mWindow->getInfo();
13234 gui::Pid ownerPid = windowInfo.ownerPid;
13235 gui::Uid ownerUid = windowInfo.ownerUid;
13236 mWindow->setOwnerInfo(gui::Pid::INVALID, gui::Uid::INVALID);
13237 ASSERT_FALSE(mDispatcher->setInTouchMode(InputDispatcher::kDefaultInTouchMode, ownerPid,
13238 ownerUid, /*hasPermission=*/false,
13239 ui::LogicalDisplayId::DEFAULT));
13240 mWindow->assertNoEvents();
13241 mSecondWindow->assertNoEvents();
13242 }
13243
TEST_F(InputDispatcherTouchModeChangedTests,NonWindowOwnerMayChangeTouchModeOnPermissionGranted)13244 TEST_F(InputDispatcherTouchModeChangedTests, NonWindowOwnerMayChangeTouchModeOnPermissionGranted) {
13245 const WindowInfo& windowInfo = *mWindow->getInfo();
13246 gui::Pid ownerPid = windowInfo.ownerPid;
13247 gui::Uid ownerUid = windowInfo.ownerUid;
13248 mWindow->setOwnerInfo(gui::Pid::INVALID, gui::Uid::INVALID);
13249 changeAndVerifyTouchModeInMainDisplayOnly(!InputDispatcher::kDefaultInTouchMode, ownerPid,
13250 ownerUid, /*hasPermission=*/true);
13251 }
13252
TEST_F(InputDispatcherTouchModeChangedTests,EventIsNotGeneratedIfNotChangingTouchMode)13253 TEST_F(InputDispatcherTouchModeChangedTests, EventIsNotGeneratedIfNotChangingTouchMode) {
13254 const WindowInfo& windowInfo = *mWindow->getInfo();
13255 ASSERT_FALSE(mDispatcher->setInTouchMode(InputDispatcher::kDefaultInTouchMode,
13256 windowInfo.ownerPid, windowInfo.ownerUid,
13257 /*hasPermission=*/true,
13258 ui::LogicalDisplayId::DEFAULT));
13259 mWindow->assertNoEvents();
13260 mSecondWindow->assertNoEvents();
13261 }
13262
TEST_F(InputDispatcherTouchModeChangedTests,ChangeTouchOnSecondaryDisplayOnly)13263 TEST_F(InputDispatcherTouchModeChangedTests, ChangeTouchOnSecondaryDisplayOnly) {
13264 const WindowInfo& windowInfo = *mThirdWindow->getInfo();
13265 ASSERT_TRUE(mDispatcher->setInTouchMode(!InputDispatcher::kDefaultInTouchMode,
13266 windowInfo.ownerPid, windowInfo.ownerUid,
13267 /*hasPermission=*/true, SECOND_DISPLAY_ID));
13268 mWindow->assertNoEvents();
13269 mSecondWindow->assertNoEvents();
13270 mThirdWindow->consumeTouchModeEvent(!InputDispatcher::kDefaultInTouchMode);
13271 }
13272
TEST_F(InputDispatcherTouchModeChangedTests,CanChangeTouchModeWhenOwningLastInteractedWindow)13273 TEST_F(InputDispatcherTouchModeChangedTests, CanChangeTouchModeWhenOwningLastInteractedWindow) {
13274 // Interact with the window first.
13275 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
13276 injectKeyDown(*mDispatcher, ui::LogicalDisplayId::DEFAULT))
13277 << "Inject key event should return InputEventInjectionResult::SUCCEEDED";
13278 mWindow->consumeKeyDown(ui::LogicalDisplayId::DEFAULT);
13279
13280 // Then remove focus.
13281 mWindow->setFocusable(false);
13282 mDispatcher->onWindowInfosChanged({{*mWindow->getInfo()}, {}, 0, 0});
13283
13284 // Assert that caller can switch touch mode by owning one of the last interacted window.
13285 const WindowInfo& windowInfo = *mWindow->getInfo();
13286 ASSERT_TRUE(mDispatcher->setInTouchMode(!InputDispatcher::kDefaultInTouchMode,
13287 windowInfo.ownerPid, windowInfo.ownerUid,
13288 /*hasPermission=*/false,
13289 ui::LogicalDisplayId::DEFAULT));
13290 }
13291
13292 class InputDispatcherSpyWindowTest : public InputDispatcherTest {
13293 public:
createSpy()13294 sp<FakeWindowHandle> createSpy() {
13295 std::shared_ptr<FakeApplicationHandle> application =
13296 std::make_shared<FakeApplicationHandle>();
13297 std::string name = "Fake Spy ";
13298 name += std::to_string(mSpyCount++);
13299 sp<FakeWindowHandle> spy =
13300 sp<FakeWindowHandle>::make(application, mDispatcher, name.c_str(),
13301 ui::LogicalDisplayId::DEFAULT);
13302 spy->setSpy(true);
13303 spy->setTrustedOverlay(true);
13304 return spy;
13305 }
13306
createForeground()13307 sp<FakeWindowHandle> createForeground() {
13308 std::shared_ptr<FakeApplicationHandle> application =
13309 std::make_shared<FakeApplicationHandle>();
13310 sp<FakeWindowHandle> window =
13311 sp<FakeWindowHandle>::make(application, mDispatcher, "Fake Window",
13312 ui::LogicalDisplayId::DEFAULT);
13313 window->setFocusable(true);
13314 return window;
13315 }
13316
13317 private:
13318 int mSpyCount{0};
13319 };
13320
13321 using InputDispatcherSpyWindowDeathTest = InputDispatcherSpyWindowTest;
13322 /**
13323 * Adding a spy window that is not a trusted overlay causes Dispatcher to abort.
13324 */
TEST_F(InputDispatcherSpyWindowDeathTest,UntrustedSpy_AbortsDispatcher)13325 TEST_F(InputDispatcherSpyWindowDeathTest, UntrustedSpy_AbortsDispatcher) {
13326 testing::GTEST_FLAG(death_test_style) = "threadsafe";
13327 ScopedSilentDeath _silentDeath;
13328
13329 auto spy = createSpy();
13330 spy->setTrustedOverlay(false);
13331 ASSERT_DEATH(mDispatcher->onWindowInfosChanged({{*spy->getInfo()}, {}, 0, 0}),
13332 ".* not a trusted overlay");
13333 }
13334
13335 /**
13336 * Input injection into a display with a spy window but no foreground windows should succeed.
13337 */
TEST_F(InputDispatcherSpyWindowTest,NoForegroundWindow)13338 TEST_F(InputDispatcherSpyWindowTest, NoForegroundWindow) {
13339 auto spy = createSpy();
13340 mDispatcher->onWindowInfosChanged({{*spy->getInfo()}, {}, 0, 0});
13341
13342 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
13343 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN,
13344 ui::LogicalDisplayId::DEFAULT))
13345 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
13346 spy->consumeMotionDown(ui::LogicalDisplayId::DEFAULT);
13347 }
13348
13349 /**
13350 * Verify the order in which different input windows receive events. The touched foreground window
13351 * (if there is one) should always receive the event first. When there are multiple spy windows, the
13352 * spy windows will receive the event according to their Z-order, where the top-most spy window will
13353 * receive events before ones belows it.
13354 *
13355 * Here, we set up a scenario with four windows in the following Z order from the top:
13356 * spy1, spy2, window, spy3.
13357 * We then inject an event and verify that the foreground "window" receives it first, followed by
13358 * "spy1" and "spy2". The "spy3" does not receive the event because it is underneath the foreground
13359 * window.
13360 */
TEST_F(InputDispatcherSpyWindowTest,ReceivesInputInOrder)13361 TEST_F(InputDispatcherSpyWindowTest, ReceivesInputInOrder) {
13362 auto window = createForeground();
13363 auto spy1 = createSpy();
13364 auto spy2 = createSpy();
13365 auto spy3 = createSpy();
13366 mDispatcher->onWindowInfosChanged(
13367 {{*spy1->getInfo(), *spy2->getInfo(), *window->getInfo(), *spy3->getInfo()}, {}, 0, 0});
13368 const std::vector<sp<FakeWindowHandle>> channels{spy1, spy2, window, spy3};
13369 const size_t numChannels = channels.size();
13370
13371 base::unique_fd epollFd(epoll_create1(EPOLL_CLOEXEC));
13372 if (!epollFd.ok()) {
13373 FAIL() << "Failed to create epoll fd";
13374 }
13375
13376 for (size_t i = 0; i < numChannels; i++) {
13377 struct epoll_event event = {.events = EPOLLIN, .data.u64 = i};
13378 if (epoll_ctl(epollFd.get(), EPOLL_CTL_ADD, channels[i]->getChannelFd(), &event) < 0) {
13379 FAIL() << "Failed to add fd to epoll";
13380 }
13381 }
13382
13383 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
13384 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN,
13385 ui::LogicalDisplayId::DEFAULT))
13386 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
13387
13388 std::vector<size_t> eventOrder;
13389 std::vector<struct epoll_event> events(numChannels);
13390 for (;;) {
13391 const int nFds = epoll_wait(epollFd.get(), events.data(), static_cast<int>(numChannels),
13392 (100ms).count());
13393 if (nFds < 0) {
13394 FAIL() << "Failed to call epoll_wait";
13395 }
13396 if (nFds == 0) {
13397 break; // epoll_wait timed out
13398 }
13399 for (int i = 0; i < nFds; i++) {
13400 ASSERT_EQ(static_cast<uint32_t>(EPOLLIN), events[i].events);
13401 eventOrder.push_back(static_cast<size_t>(events[i].data.u64));
13402 channels[i]->consumeMotionDown();
13403 }
13404 }
13405
13406 // Verify the order in which the events were received.
13407 EXPECT_EQ(3u, eventOrder.size());
13408 EXPECT_EQ(2u, eventOrder[0]); // index 2: window
13409 EXPECT_EQ(0u, eventOrder[1]); // index 0: spy1
13410 EXPECT_EQ(1u, eventOrder[2]); // index 1: spy2
13411 }
13412
13413 /**
13414 * A spy window using the NOT_TOUCHABLE flag does not receive events.
13415 */
TEST_F(InputDispatcherSpyWindowTest,NotTouchable)13416 TEST_F(InputDispatcherSpyWindowTest, NotTouchable) {
13417 auto window = createForeground();
13418 auto spy = createSpy();
13419 spy->setTouchable(false);
13420 mDispatcher->onWindowInfosChanged({{*spy->getInfo(), *window->getInfo()}, {}, 0, 0});
13421
13422 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
13423 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN,
13424 ui::LogicalDisplayId::DEFAULT))
13425 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
13426 window->consumeMotionDown(ui::LogicalDisplayId::DEFAULT);
13427 spy->assertNoEvents();
13428 }
13429
13430 /**
13431 * A spy window will only receive gestures that originate within its touchable region. Gestures that
13432 * have their ACTION_DOWN outside of the touchable region of the spy window will not be dispatched
13433 * to the window.
13434 */
TEST_F(InputDispatcherSpyWindowTest,TouchableRegion)13435 TEST_F(InputDispatcherSpyWindowTest, TouchableRegion) {
13436 auto window = createForeground();
13437 auto spy = createSpy();
13438 spy->setTouchableRegion(Region{{0, 0, 20, 20}});
13439 mDispatcher->onWindowInfosChanged({{*spy->getInfo(), *window->getInfo()}, {}, 0, 0});
13440
13441 // Inject an event outside the spy window's touchable region.
13442 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
13443 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN,
13444 ui::LogicalDisplayId::DEFAULT))
13445 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
13446 window->consumeMotionDown();
13447 spy->assertNoEvents();
13448 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
13449 injectMotionUp(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN,
13450 ui::LogicalDisplayId::DEFAULT))
13451 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
13452 window->consumeMotionUp();
13453 spy->assertNoEvents();
13454
13455 // Inject an event inside the spy window's touchable region.
13456 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
13457 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN,
13458 ui::LogicalDisplayId::DEFAULT, {5, 10}))
13459 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
13460 window->consumeMotionDown();
13461 spy->consumeMotionDown();
13462 }
13463
13464 /**
13465 * A spy window can listen for touches outside its touchable region using the WATCH_OUTSIDE_TOUCHES
13466 * flag, but it will get zero-ed out coordinates if the foreground has a different owner.
13467 */
TEST_F(InputDispatcherSpyWindowTest,WatchOutsideTouches)13468 TEST_F(InputDispatcherSpyWindowTest, WatchOutsideTouches) {
13469 auto window = createForeground();
13470 window->setOwnerInfo(gui::Pid{12}, gui::Uid{34});
13471 auto spy = createSpy();
13472 spy->setWatchOutsideTouch(true);
13473 spy->setOwnerInfo(gui::Pid{56}, gui::Uid{78});
13474 spy->setFrame(Rect{0, 0, 20, 20});
13475 mDispatcher->onWindowInfosChanged({{*spy->getInfo(), *window->getInfo()}, {}, 0, 0});
13476
13477 // Inject an event outside the spy window's frame and touchable region.
13478 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
13479 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN,
13480 ui::LogicalDisplayId::DEFAULT, {100, 200}))
13481 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
13482 window->consumeMotionDown();
13483 spy->consumeMotionOutsideWithZeroedCoords();
13484 }
13485
13486 /**
13487 * Even when a spy window spans over multiple foreground windows, the spy should receive all
13488 * pointers that are down within its bounds.
13489 */
TEST_F(InputDispatcherSpyWindowTest,ReceivesMultiplePointers)13490 TEST_F(InputDispatcherSpyWindowTest, ReceivesMultiplePointers) {
13491 auto windowLeft = createForeground();
13492 windowLeft->setFrame({0, 0, 100, 200});
13493 auto windowRight = createForeground();
13494 windowRight->setFrame({100, 0, 200, 200});
13495 auto spy = createSpy();
13496 spy->setFrame({0, 0, 200, 200});
13497 mDispatcher->onWindowInfosChanged(
13498 {{*spy->getInfo(), *windowLeft->getInfo(), *windowRight->getInfo()}, {}, 0, 0});
13499
13500 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
13501 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN,
13502 ui::LogicalDisplayId::DEFAULT, {50, 50}))
13503 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
13504 windowLeft->consumeMotionDown();
13505 spy->consumeMotionDown();
13506
13507 const MotionEvent secondFingerDownEvent =
13508 MotionEventBuilder(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
13509 .eventTime(systemTime(SYSTEM_TIME_MONOTONIC))
13510 .pointer(PointerBuilder(/*id=*/0, ToolType::FINGER).x(50).y(50))
13511 .pointer(PointerBuilder(/*id=*/1, ToolType::FINGER).x(150).y(50))
13512 .build();
13513 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
13514 injectMotionEvent(*mDispatcher, secondFingerDownEvent, INJECT_EVENT_TIMEOUT,
13515 InputEventInjectionSync::WAIT_FOR_RESULT))
13516 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
13517 windowRight->consumeMotionDown();
13518 spy->consumeMotionPointerDown(/*pointerIndex=*/1);
13519 }
13520
13521 /**
13522 * When the first pointer lands outside the spy window and the second pointer lands inside it, the
13523 * the spy should receive the second pointer with ACTION_DOWN.
13524 */
TEST_F(InputDispatcherSpyWindowTest,ReceivesSecondPointerAsDown)13525 TEST_F(InputDispatcherSpyWindowTest, ReceivesSecondPointerAsDown) {
13526 auto window = createForeground();
13527 window->setFrame({0, 0, 200, 200});
13528 auto spyRight = createSpy();
13529 spyRight->setFrame({100, 0, 200, 200});
13530 mDispatcher->onWindowInfosChanged({{*spyRight->getInfo(), *window->getInfo()}, {}, 0, 0});
13531
13532 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
13533 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN,
13534 ui::LogicalDisplayId::DEFAULT, {50, 50}))
13535 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
13536 window->consumeMotionDown();
13537 spyRight->assertNoEvents();
13538
13539 const MotionEvent secondFingerDownEvent =
13540 MotionEventBuilder(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
13541 .eventTime(systemTime(SYSTEM_TIME_MONOTONIC))
13542 .pointer(PointerBuilder(/*id=*/0, ToolType::FINGER).x(50).y(50))
13543 .pointer(PointerBuilder(/*id=*/1, ToolType::FINGER).x(150).y(50))
13544 .build();
13545 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
13546 injectMotionEvent(*mDispatcher, secondFingerDownEvent, INJECT_EVENT_TIMEOUT,
13547 InputEventInjectionSync::WAIT_FOR_RESULT))
13548 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
13549 window->consumeMotionPointerDown(/*pointerIndex=*/1);
13550 spyRight->consumeMotionDown();
13551 }
13552
13553 /**
13554 * The spy window should not be able to affect whether or not touches are split. Only the foreground
13555 * windows should be allowed to control split touch.
13556 */
TEST_F(InputDispatcherSpyWindowTest,SplitIfNoForegroundWindowTouched)13557 TEST_F(InputDispatcherSpyWindowTest, SplitIfNoForegroundWindowTouched) {
13558 // This spy window prevents touch splitting. However, we still expect to split touches
13559 // because a foreground window has not disabled splitting.
13560 auto spy = createSpy();
13561 spy->setPreventSplitting(true);
13562
13563 auto window = createForeground();
13564 window->setFrame(Rect(0, 0, 100, 100));
13565
13566 mDispatcher->onWindowInfosChanged({{*spy->getInfo(), *window->getInfo()}, {}, 0, 0});
13567
13568 // First finger down, no window touched.
13569 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
13570 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN,
13571 ui::LogicalDisplayId::DEFAULT, {100, 200}))
13572 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
13573 spy->consumeMotionDown(ui::LogicalDisplayId::DEFAULT);
13574 window->assertNoEvents();
13575
13576 // Second finger down on window, the window should receive touch down.
13577 const MotionEvent secondFingerDownEvent =
13578 MotionEventBuilder(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
13579 .displayId(ui::LogicalDisplayId::DEFAULT)
13580 .eventTime(systemTime(SYSTEM_TIME_MONOTONIC))
13581 .pointer(PointerBuilder(/*id=*/0, ToolType::FINGER).x(100).y(200))
13582 .pointer(PointerBuilder(/*id=*/1, ToolType::FINGER).x(50).y(50))
13583 .build();
13584 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
13585 injectMotionEvent(*mDispatcher, secondFingerDownEvent, INJECT_EVENT_TIMEOUT,
13586 InputEventInjectionSync::WAIT_FOR_RESULT))
13587 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
13588
13589 window->consumeMotionDown(ui::LogicalDisplayId::DEFAULT);
13590 spy->consumeMotionPointerDown(/*pointerIndex=*/1);
13591 }
13592
13593 /**
13594 * A spy window will usually be implemented as an un-focusable window. Verify that these windows
13595 * do not receive key events.
13596 */
TEST_F(InputDispatcherSpyWindowTest,UnfocusableSpyDoesNotReceiveKeyEvents)13597 TEST_F(InputDispatcherSpyWindowTest, UnfocusableSpyDoesNotReceiveKeyEvents) {
13598 auto spy = createSpy();
13599 spy->setFocusable(false);
13600
13601 auto window = createForeground();
13602 mDispatcher->onWindowInfosChanged({{*spy->getInfo(), *window->getInfo()}, {}, 0, 0});
13603 setFocusedWindow(window);
13604 window->consumeFocusEvent(true);
13605
13606 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectKeyDown(*mDispatcher))
13607 << "Inject key event should return InputEventInjectionResult::SUCCEEDED";
13608 window->consumeKeyDown(ui::LogicalDisplayId::INVALID);
13609
13610 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectKeyUp(*mDispatcher))
13611 << "Inject key event should return InputEventInjectionResult::SUCCEEDED";
13612 window->consumeKeyUp(ui::LogicalDisplayId::INVALID);
13613
13614 spy->assertNoEvents();
13615 }
13616
13617 using InputDispatcherPilferPointersTest = InputDispatcherSpyWindowTest;
13618
13619 /**
13620 * A spy window can pilfer pointers. When this happens, touch gestures used by the spy window that
13621 * are currently sent to any other windows - including other spy windows - will also be cancelled.
13622 */
TEST_F(InputDispatcherPilferPointersTest,PilferPointers)13623 TEST_F(InputDispatcherPilferPointersTest, PilferPointers) {
13624 auto window = createForeground();
13625 auto spy1 = createSpy();
13626 auto spy2 = createSpy();
13627 mDispatcher->onWindowInfosChanged(
13628 {{*spy1->getInfo(), *spy2->getInfo(), *window->getInfo()}, {}, 0, 0});
13629
13630 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
13631 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN,
13632 ui::LogicalDisplayId::DEFAULT))
13633 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
13634 window->consumeMotionDown();
13635 spy1->consumeMotionDown();
13636 spy2->consumeMotionDown();
13637
13638 // Pilfer pointers from the second spy window.
13639 EXPECT_EQ(OK, mDispatcher->pilferPointers(spy2->getToken()));
13640 spy2->assertNoEvents();
13641 spy1->consumeMotionCancel();
13642 window->consumeMotionCancel();
13643
13644 // The rest of the gesture should only be sent to the second spy window.
13645 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
13646 injectMotionEvent(*mDispatcher, AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN,
13647 ui::LogicalDisplayId::DEFAULT))
13648 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
13649 spy2->consumeMotionMove();
13650 spy1->assertNoEvents();
13651 window->assertNoEvents();
13652 }
13653
13654 /**
13655 * A spy window can pilfer pointers for a gesture even after the foreground window has been removed
13656 * in the middle of the gesture.
13657 */
TEST_F(InputDispatcherPilferPointersTest,CanPilferAfterWindowIsRemovedMidStream)13658 TEST_F(InputDispatcherPilferPointersTest, CanPilferAfterWindowIsRemovedMidStream) {
13659 auto window = createForeground();
13660 auto spy = createSpy();
13661 mDispatcher->onWindowInfosChanged({{*spy->getInfo(), *window->getInfo()}, {}, 0, 0});
13662
13663 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
13664 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN,
13665 ui::LogicalDisplayId::DEFAULT))
13666 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
13667 window->consumeMotionDown(ui::LogicalDisplayId::DEFAULT);
13668 spy->consumeMotionDown(ui::LogicalDisplayId::DEFAULT);
13669
13670 window->releaseChannel();
13671
13672 EXPECT_EQ(OK, mDispatcher->pilferPointers(spy->getToken()));
13673
13674 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
13675 injectMotionUp(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN,
13676 ui::LogicalDisplayId::DEFAULT))
13677 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
13678 spy->consumeMotionUp(ui::LogicalDisplayId::DEFAULT);
13679 }
13680
13681 /**
13682 * After a spy window pilfers pointers, new pointers that go down in its bounds should be sent to
13683 * the spy, but not to any other windows.
13684 */
TEST_F(InputDispatcherPilferPointersTest,ContinuesToReceiveGestureAfterPilfer)13685 TEST_F(InputDispatcherPilferPointersTest, ContinuesToReceiveGestureAfterPilfer) {
13686 auto spy = createSpy();
13687 auto window = createForeground();
13688
13689 mDispatcher->onWindowInfosChanged({{*spy->getInfo(), *window->getInfo()}, {}, 0, 0});
13690
13691 // First finger down on the window and the spy.
13692 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
13693 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN,
13694 ui::LogicalDisplayId::DEFAULT, {100, 200}))
13695 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
13696 spy->consumeMotionDown();
13697 window->consumeMotionDown();
13698
13699 // Spy window pilfers the pointers.
13700 EXPECT_EQ(OK, mDispatcher->pilferPointers(spy->getToken()));
13701 window->consumeMotionCancel();
13702
13703 // Second finger down on the window and spy, but the window should not receive the pointer down.
13704 const MotionEvent secondFingerDownEvent =
13705 MotionEventBuilder(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
13706 .displayId(ui::LogicalDisplayId::DEFAULT)
13707 .eventTime(systemTime(SYSTEM_TIME_MONOTONIC))
13708 .pointer(PointerBuilder(/*id=*/0, ToolType::FINGER).x(100).y(200))
13709 .pointer(PointerBuilder(/*id=*/1, ToolType::FINGER).x(50).y(50))
13710 .build();
13711 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
13712 injectMotionEvent(*mDispatcher, secondFingerDownEvent, INJECT_EVENT_TIMEOUT,
13713 InputEventInjectionSync::WAIT_FOR_RESULT))
13714 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
13715
13716 spy->consumeMotionPointerDown(/*pointerIndex=*/1);
13717
13718 // Third finger goes down outside all windows, so injection should fail.
13719 const MotionEvent thirdFingerDownEvent =
13720 MotionEventBuilder(POINTER_2_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
13721 .displayId(ui::LogicalDisplayId::DEFAULT)
13722 .eventTime(systemTime(SYSTEM_TIME_MONOTONIC))
13723 .pointer(PointerBuilder(/*id=*/0, ToolType::FINGER).x(100).y(200))
13724 .pointer(PointerBuilder(/*id=*/1, ToolType::FINGER).x(50).y(50))
13725 .pointer(PointerBuilder(/*id=*/2, ToolType::FINGER).x(-5).y(-5))
13726 .build();
13727 ASSERT_EQ(InputEventInjectionResult::FAILED,
13728 injectMotionEvent(*mDispatcher, thirdFingerDownEvent, INJECT_EVENT_TIMEOUT,
13729 InputEventInjectionSync::WAIT_FOR_RESULT))
13730 << "Inject motion event should return InputEventInjectionResult::FAILED";
13731
13732 spy->assertNoEvents();
13733 window->assertNoEvents();
13734 }
13735
13736 /**
13737 * After a spy window pilfers pointers, only the pointers used by the spy should be canceled
13738 */
TEST_F(InputDispatcherPilferPointersTest,PartiallyPilferRequiredPointers)13739 TEST_F(InputDispatcherPilferPointersTest, PartiallyPilferRequiredPointers) {
13740 auto spy = createSpy();
13741 spy->setFrame(Rect(0, 0, 100, 100));
13742 auto window = createForeground();
13743 window->setFrame(Rect(0, 0, 200, 200));
13744
13745 mDispatcher->onWindowInfosChanged({{*spy->getInfo(), *window->getInfo()}, {}, 0, 0});
13746
13747 // First finger down on the window only
13748 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
13749 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN,
13750 ui::LogicalDisplayId::DEFAULT, {150, 150}))
13751 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
13752 window->consumeMotionDown();
13753
13754 // Second finger down on the spy and window
13755 const MotionEvent secondFingerDownEvent =
13756 MotionEventBuilder(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
13757 .displayId(ui::LogicalDisplayId::DEFAULT)
13758 .eventTime(systemTime(SYSTEM_TIME_MONOTONIC))
13759 .pointer(PointerBuilder(/*id=*/0, ToolType::FINGER).x(150).y(150))
13760 .pointer(PointerBuilder(/*id=*/1, ToolType::FINGER).x(10).y(10))
13761 .build();
13762 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
13763 injectMotionEvent(*mDispatcher, secondFingerDownEvent, INJECT_EVENT_TIMEOUT,
13764 InputEventInjectionSync::WAIT_FOR_RESULT))
13765 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
13766 spy->consumeMotionDown();
13767 window->consumeMotionPointerDown(1);
13768
13769 // Third finger down on the spy and window
13770 const MotionEvent thirdFingerDownEvent =
13771 MotionEventBuilder(POINTER_2_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
13772 .displayId(ui::LogicalDisplayId::DEFAULT)
13773 .eventTime(systemTime(SYSTEM_TIME_MONOTONIC))
13774 .pointer(PointerBuilder(/*id=*/0, ToolType::FINGER).x(150).y(150))
13775 .pointer(PointerBuilder(/*id=*/1, ToolType::FINGER).x(10).y(10))
13776 .pointer(PointerBuilder(/*id=*/2, ToolType::FINGER).x(50).y(50))
13777 .build();
13778 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
13779 injectMotionEvent(*mDispatcher, thirdFingerDownEvent, INJECT_EVENT_TIMEOUT,
13780 InputEventInjectionSync::WAIT_FOR_RESULT))
13781 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
13782 spy->consumeMotionPointerDown(1);
13783 window->consumeMotionPointerDown(2);
13784
13785 // Spy window pilfers the pointers.
13786 EXPECT_EQ(OK, mDispatcher->pilferPointers(spy->getToken()));
13787 window->consumeMotionPointerUp(/*pointerIdx=*/2,
13788 AllOf(WithDisplayId(ui::LogicalDisplayId::DEFAULT),
13789 WithFlags(AMOTION_EVENT_FLAG_CANCELED),
13790 WithPointerCount(3)));
13791 window->consumeMotionPointerUp(/*pointerIdx=*/1,
13792 AllOf(WithDisplayId(ui::LogicalDisplayId::DEFAULT),
13793 WithFlags(AMOTION_EVENT_FLAG_CANCELED),
13794 WithPointerCount(2)));
13795
13796 spy->assertNoEvents();
13797 window->assertNoEvents();
13798 }
13799
13800 /**
13801 * After a spy window pilfers pointers, all pilfered pointers that have already been dispatched to
13802 * other windows should be canceled. If this results in the cancellation of all pointers for some
13803 * window, then that window should receive ACTION_CANCEL.
13804 */
TEST_F(InputDispatcherPilferPointersTest,PilferAllRequiredPointers)13805 TEST_F(InputDispatcherPilferPointersTest, PilferAllRequiredPointers) {
13806 auto spy = createSpy();
13807 spy->setFrame(Rect(0, 0, 100, 100));
13808 auto window = createForeground();
13809 window->setFrame(Rect(0, 0, 200, 200));
13810
13811 mDispatcher->onWindowInfosChanged({{*spy->getInfo(), *window->getInfo()}, {}, 0, 0});
13812
13813 // First finger down on both spy and window
13814 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
13815 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN,
13816 ui::LogicalDisplayId::DEFAULT, {10, 10}))
13817 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
13818 window->consumeMotionDown();
13819 spy->consumeMotionDown();
13820
13821 // Second finger down on the spy and window
13822 const MotionEvent secondFingerDownEvent =
13823 MotionEventBuilder(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
13824 .displayId(ui::LogicalDisplayId::DEFAULT)
13825 .eventTime(systemTime(SYSTEM_TIME_MONOTONIC))
13826 .pointer(PointerBuilder(/*id=*/0, ToolType::FINGER).x(10).y(10))
13827 .pointer(PointerBuilder(/*id=*/1, ToolType::FINGER).x(50).y(50))
13828 .build();
13829 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
13830 injectMotionEvent(*mDispatcher, secondFingerDownEvent, INJECT_EVENT_TIMEOUT,
13831 InputEventInjectionSync::WAIT_FOR_RESULT))
13832 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
13833 spy->consumeMotionPointerDown(1);
13834 window->consumeMotionPointerDown(1);
13835
13836 // Spy window pilfers the pointers.
13837 EXPECT_EQ(OK, mDispatcher->pilferPointers(spy->getToken()));
13838 window->consumeMotionCancel();
13839
13840 spy->assertNoEvents();
13841 window->assertNoEvents();
13842 }
13843
13844 /**
13845 * After a spy window pilfers pointers, new pointers that are not touching the spy window can still
13846 * be sent to other windows
13847 */
TEST_F(InputDispatcherPilferPointersTest,CanReceivePointersAfterPilfer)13848 TEST_F(InputDispatcherPilferPointersTest, CanReceivePointersAfterPilfer) {
13849 auto spy = createSpy();
13850 spy->setFrame(Rect(0, 0, 100, 100));
13851 auto window = createForeground();
13852 window->setFrame(Rect(0, 0, 200, 200));
13853
13854 mDispatcher->onWindowInfosChanged({{*spy->getInfo(), *window->getInfo()}, {}, 0, 0});
13855
13856 // First finger down on both window and spy
13857 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
13858 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN,
13859 ui::LogicalDisplayId::DEFAULT, {10, 10}))
13860 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
13861 window->consumeMotionDown();
13862 spy->consumeMotionDown();
13863
13864 // Spy window pilfers the pointers.
13865 EXPECT_EQ(OK, mDispatcher->pilferPointers(spy->getToken()));
13866 window->consumeMotionCancel();
13867
13868 // Second finger down on the window only
13869 const MotionEvent secondFingerDownEvent =
13870 MotionEventBuilder(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
13871 .displayId(ui::LogicalDisplayId::DEFAULT)
13872 .eventTime(systemTime(SYSTEM_TIME_MONOTONIC))
13873 .pointer(PointerBuilder(/*id=*/0, ToolType::FINGER).x(10).y(10))
13874 .pointer(PointerBuilder(/*id=*/1, ToolType::FINGER).x(150).y(150))
13875 .build();
13876 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
13877 injectMotionEvent(*mDispatcher, secondFingerDownEvent, INJECT_EVENT_TIMEOUT,
13878 InputEventInjectionSync::WAIT_FOR_RESULT))
13879 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
13880 window->consumeMotionDown();
13881 window->assertNoEvents();
13882
13883 // TODO(b/232530217): do not send the unnecessary MOVE event and delete the next line
13884 spy->consumeMotionMove();
13885 spy->assertNoEvents();
13886 }
13887
13888 /**
13889 * A window on the left and a window on the right. Also, a spy window that's above all of the
13890 * windows, and spanning both left and right windows.
13891 * Send simultaneous motion streams from two different devices, one to the left window, and another
13892 * to the right window.
13893 * Pilfer from spy window.
13894 * Check that the pilfering only affects the pointers that are actually being received by the spy.
13895 */
TEST_F(InputDispatcherPilferPointersTest,MultiDevicePilfer_legacy)13896 TEST_F(InputDispatcherPilferPointersTest, MultiDevicePilfer_legacy) {
13897 SCOPED_FLAG_OVERRIDE(enable_multi_device_same_window_stream, false);
13898 sp<FakeWindowHandle> spy = createSpy();
13899 spy->setFrame(Rect(0, 0, 200, 200));
13900 sp<FakeWindowHandle> leftWindow = createForeground();
13901 leftWindow->setFrame(Rect(0, 0, 100, 100));
13902
13903 sp<FakeWindowHandle> rightWindow = createForeground();
13904 rightWindow->setFrame(Rect(100, 0, 200, 100));
13905
13906 constexpr int32_t stylusDeviceId = 1;
13907 constexpr int32_t touchDeviceId = 2;
13908
13909 mDispatcher->onWindowInfosChanged(
13910 {{*spy->getInfo(), *leftWindow->getInfo(), *rightWindow->getInfo()}, {}, 0, 0});
13911
13912 // Stylus down on left window and spy
13913 mDispatcher->notifyMotion(MotionArgsBuilder(AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_STYLUS)
13914 .deviceId(stylusDeviceId)
13915 .pointer(PointerBuilder(0, ToolType::STYLUS).x(50).y(50))
13916 .build());
13917 leftWindow->consumeMotionEvent(
13918 AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(stylusDeviceId)));
13919 spy->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(stylusDeviceId)));
13920
13921 // Finger down on right window and spy - but spy already has stylus
13922 mDispatcher->notifyMotion(
13923 MotionArgsBuilder(AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
13924 .deviceId(touchDeviceId)
13925 .pointer(PointerBuilder(0, ToolType::FINGER).x(150).y(50))
13926 .build());
13927 rightWindow->consumeMotionEvent(
13928 AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(touchDeviceId)));
13929 spy->assertNoEvents();
13930
13931 // Act: pilfer from spy. Spy is currently receiving touch events.
13932 EXPECT_EQ(OK, mDispatcher->pilferPointers(spy->getToken()));
13933 leftWindow->consumeMotionEvent(
13934 AllOf(WithMotionAction(ACTION_CANCEL), WithDeviceId(stylusDeviceId)));
13935 rightWindow->consumeMotionEvent(
13936 AllOf(WithMotionAction(ACTION_CANCEL), WithDeviceId(touchDeviceId)));
13937
13938 // Continue movements from both stylus and touch. Touch will be delivered to spy, but not stylus
13939 mDispatcher->notifyMotion(MotionArgsBuilder(AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_STYLUS)
13940 .deviceId(stylusDeviceId)
13941 .pointer(PointerBuilder(0, ToolType::STYLUS).x(51).y(52))
13942 .build());
13943 mDispatcher->notifyMotion(
13944 MotionArgsBuilder(AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN)
13945 .deviceId(touchDeviceId)
13946 .pointer(PointerBuilder(0, ToolType::FINGER).x(151).y(52))
13947 .build());
13948 spy->consumeMotionEvent(AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(stylusDeviceId)));
13949
13950 spy->assertNoEvents();
13951 leftWindow->assertNoEvents();
13952 rightWindow->assertNoEvents();
13953 }
13954
13955 /**
13956 * A window on the left and a window on the right. Also, a spy window that's above all of the
13957 * windows, and spanning both left and right windows.
13958 * Send simultaneous motion streams from two different devices, one to the left window, and another
13959 * to the right window.
13960 * Pilfer from spy window.
13961 * Check that the pilfering affects all of the pointers that are actually being received by the spy.
13962 * The spy should receive both the touch and the stylus events after pilfer.
13963 */
TEST_F(InputDispatcherPilferPointersTest,MultiDevicePilfer)13964 TEST_F(InputDispatcherPilferPointersTest, MultiDevicePilfer) {
13965 SCOPED_FLAG_OVERRIDE(enable_multi_device_same_window_stream, true);
13966 sp<FakeWindowHandle> spy = createSpy();
13967 spy->setFrame(Rect(0, 0, 200, 200));
13968 sp<FakeWindowHandle> leftWindow = createForeground();
13969 leftWindow->setFrame(Rect(0, 0, 100, 100));
13970
13971 sp<FakeWindowHandle> rightWindow = createForeground();
13972 rightWindow->setFrame(Rect(100, 0, 200, 100));
13973
13974 constexpr int32_t stylusDeviceId = 1;
13975 constexpr int32_t touchDeviceId = 2;
13976
13977 mDispatcher->onWindowInfosChanged(
13978 {{*spy->getInfo(), *leftWindow->getInfo(), *rightWindow->getInfo()}, {}, 0, 0});
13979
13980 // Stylus down on left window and spy
13981 mDispatcher->notifyMotion(MotionArgsBuilder(AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_STYLUS)
13982 .deviceId(stylusDeviceId)
13983 .pointer(PointerBuilder(0, ToolType::STYLUS).x(50).y(50))
13984 .build());
13985 leftWindow->consumeMotionEvent(
13986 AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(stylusDeviceId)));
13987 spy->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(stylusDeviceId)));
13988
13989 // Finger down on right window and spy
13990 mDispatcher->notifyMotion(
13991 MotionArgsBuilder(AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
13992 .deviceId(touchDeviceId)
13993 .pointer(PointerBuilder(0, ToolType::FINGER).x(150).y(50))
13994 .build());
13995 rightWindow->consumeMotionEvent(
13996 AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(touchDeviceId)));
13997 spy->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(touchDeviceId)));
13998
13999 // Act: pilfer from spy. Spy is currently receiving touch events.
14000 EXPECT_EQ(OK, mDispatcher->pilferPointers(spy->getToken()));
14001 leftWindow->consumeMotionEvent(
14002 AllOf(WithMotionAction(ACTION_CANCEL), WithDeviceId(stylusDeviceId)));
14003 rightWindow->consumeMotionEvent(
14004 AllOf(WithMotionAction(ACTION_CANCEL), WithDeviceId(touchDeviceId)));
14005
14006 // Continue movements from both stylus and touch. Touch and stylus will be delivered to spy
14007 // Instead of sending the two MOVE events for each input device together, and then receiving
14008 // them both, process them one at at time. InputConsumer is always in the batching mode, which
14009 // means that the two MOVE events will be initially put into a batch. Once the events are
14010 // batched, the 'consume' call may result in any of the MOVE events to be sent first (depending
14011 // on the implementation of InputConsumer), which would mean that the order of the received
14012 // events could be different depending on whether there are 1 or 2 events pending in the
14013 // InputChannel at the time the test calls 'consume'. To make assertions simpler here, and to
14014 // avoid this confusing behaviour, send and receive each MOVE event separately.
14015 mDispatcher->notifyMotion(MotionArgsBuilder(AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_STYLUS)
14016 .deviceId(stylusDeviceId)
14017 .pointer(PointerBuilder(0, ToolType::STYLUS).x(51).y(52))
14018 .build());
14019 spy->consumeMotionEvent(AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(stylusDeviceId)));
14020 mDispatcher->notifyMotion(
14021 MotionArgsBuilder(AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN)
14022 .deviceId(touchDeviceId)
14023 .pointer(PointerBuilder(0, ToolType::FINGER).x(151).y(52))
14024 .build());
14025 spy->consumeMotionEvent(AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(touchDeviceId)));
14026
14027 spy->assertNoEvents();
14028 leftWindow->assertNoEvents();
14029 rightWindow->assertNoEvents();
14030 }
14031
TEST_F(InputDispatcherPilferPointersTest,NoPilferingWithHoveringPointers)14032 TEST_F(InputDispatcherPilferPointersTest, NoPilferingWithHoveringPointers) {
14033 auto window = createForeground();
14034 auto spy = createSpy();
14035 mDispatcher->onWindowInfosChanged({{*spy->getInfo(), *window->getInfo()}, {}, 0, 0});
14036
14037 mDispatcher->notifyMotion(
14038 MotionArgsBuilder(ACTION_HOVER_ENTER, AINPUT_SOURCE_MOUSE)
14039 .deviceId(1)
14040 .pointer(PointerBuilder(/*id=*/0, ToolType::MOUSE).x(100).y(200))
14041 .build());
14042 window->consumeMotionEvent(WithMotionAction(ACTION_HOVER_ENTER));
14043 spy->consumeMotionEvent(WithMotionAction(ACTION_HOVER_ENTER));
14044
14045 // Pilfer pointers from the spy window should fail.
14046 EXPECT_NE(OK, mDispatcher->pilferPointers(spy->getToken()));
14047 spy->assertNoEvents();
14048 window->assertNoEvents();
14049 }
14050
14051 class InputDispatcherStylusInterceptorTest : public InputDispatcherTest {
14052 public:
setupStylusOverlayScenario()14053 std::pair<sp<FakeWindowHandle>, sp<FakeWindowHandle>> setupStylusOverlayScenario() {
14054 std::shared_ptr<FakeApplicationHandle> overlayApplication =
14055 std::make_shared<FakeApplicationHandle>();
14056 sp<FakeWindowHandle> overlay = sp<FakeWindowHandle>::make(overlayApplication, mDispatcher,
14057 "Stylus interceptor window",
14058 ui::LogicalDisplayId::DEFAULT);
14059 overlay->setFocusable(false);
14060 overlay->setOwnerInfo(gui::Pid{111}, gui::Uid{111});
14061 overlay->setTouchable(false);
14062 overlay->setInterceptsStylus(true);
14063 overlay->setTrustedOverlay(true);
14064
14065 std::shared_ptr<FakeApplicationHandle> application =
14066 std::make_shared<FakeApplicationHandle>();
14067 sp<FakeWindowHandle> window =
14068 sp<FakeWindowHandle>::make(application, mDispatcher, "Application window",
14069 ui::LogicalDisplayId::DEFAULT);
14070 window->setFocusable(true);
14071 window->setOwnerInfo(gui::Pid{222}, gui::Uid{222});
14072
14073 mDispatcher->setFocusedApplication(ui::LogicalDisplayId::DEFAULT, application);
14074 mDispatcher->onWindowInfosChanged({{*overlay->getInfo(), *window->getInfo()}, {}, 0, 0});
14075 setFocusedWindow(window);
14076 window->consumeFocusEvent(/*hasFocus=*/true, /*inTouchMode=*/true);
14077 return {std::move(overlay), std::move(window)};
14078 }
14079
sendFingerEvent(int32_t action)14080 void sendFingerEvent(int32_t action) {
14081 mDispatcher->notifyMotion(
14082 generateMotionArgs(action, AINPUT_SOURCE_TOUCHSCREEN | AINPUT_SOURCE_STYLUS,
14083 ui::LogicalDisplayId::DEFAULT, {PointF{20, 20}}));
14084 }
14085
sendStylusEvent(int32_t action)14086 void sendStylusEvent(int32_t action) {
14087 NotifyMotionArgs motionArgs =
14088 generateMotionArgs(action, AINPUT_SOURCE_TOUCHSCREEN | AINPUT_SOURCE_STYLUS,
14089 ui::LogicalDisplayId::DEFAULT, {PointF{30, 40}});
14090 motionArgs.pointerProperties[0].toolType = ToolType::STYLUS;
14091 mDispatcher->notifyMotion(motionArgs);
14092 }
14093 };
14094
14095 using InputDispatcherStylusInterceptorDeathTest = InputDispatcherStylusInterceptorTest;
14096
TEST_F(InputDispatcherStylusInterceptorDeathTest,UntrustedOverlay_AbortsDispatcher)14097 TEST_F(InputDispatcherStylusInterceptorDeathTest, UntrustedOverlay_AbortsDispatcher) {
14098 testing::GTEST_FLAG(death_test_style) = "threadsafe";
14099 ScopedSilentDeath _silentDeath;
14100
14101 auto [overlay, window] = setupStylusOverlayScenario();
14102 overlay->setTrustedOverlay(false);
14103 // Configuring an untrusted overlay as a stylus interceptor should cause Dispatcher to abort.
14104 ASSERT_DEATH(mDispatcher->onWindowInfosChanged(
14105 {{*overlay->getInfo(), *window->getInfo()}, {}, 0, 0}),
14106 ".* not a trusted overlay");
14107 }
14108
TEST_F(InputDispatcherStylusInterceptorTest,ConsmesOnlyStylusEvents)14109 TEST_F(InputDispatcherStylusInterceptorTest, ConsmesOnlyStylusEvents) {
14110 auto [overlay, window] = setupStylusOverlayScenario();
14111 mDispatcher->onWindowInfosChanged({{*overlay->getInfo(), *window->getInfo()}, {}, 0, 0});
14112
14113 sendStylusEvent(AMOTION_EVENT_ACTION_DOWN);
14114 overlay->consumeMotionDown();
14115 sendStylusEvent(AMOTION_EVENT_ACTION_UP);
14116 overlay->consumeMotionUp();
14117
14118 sendFingerEvent(AMOTION_EVENT_ACTION_DOWN);
14119 window->consumeMotionDown();
14120 sendFingerEvent(AMOTION_EVENT_ACTION_UP);
14121 window->consumeMotionUp();
14122
14123 overlay->assertNoEvents();
14124 window->assertNoEvents();
14125 }
14126
TEST_F(InputDispatcherStylusInterceptorTest,SpyWindowStylusInterceptor)14127 TEST_F(InputDispatcherStylusInterceptorTest, SpyWindowStylusInterceptor) {
14128 auto [overlay, window] = setupStylusOverlayScenario();
14129 overlay->setSpy(true);
14130 mDispatcher->onWindowInfosChanged({{*overlay->getInfo(), *window->getInfo()}, {}, 0, 0});
14131
14132 sendStylusEvent(AMOTION_EVENT_ACTION_DOWN);
14133 overlay->consumeMotionDown();
14134 window->consumeMotionDown();
14135 sendStylusEvent(AMOTION_EVENT_ACTION_UP);
14136 overlay->consumeMotionUp();
14137 window->consumeMotionUp();
14138
14139 sendFingerEvent(AMOTION_EVENT_ACTION_DOWN);
14140 window->consumeMotionDown();
14141 sendFingerEvent(AMOTION_EVENT_ACTION_UP);
14142 window->consumeMotionUp();
14143
14144 overlay->assertNoEvents();
14145 window->assertNoEvents();
14146 }
14147
14148 /**
14149 * Set up a scenario to test the behavior used by the stylus handwriting detection feature.
14150 * The scenario is as follows:
14151 * - The stylus interceptor overlay is configured as a spy window.
14152 * - The stylus interceptor spy receives the start of a new stylus gesture.
14153 * - It pilfers pointers and then configures itself to no longer be a spy.
14154 * - The stylus interceptor continues to receive the rest of the gesture.
14155 */
TEST_F(InputDispatcherStylusInterceptorTest,StylusHandwritingScenario)14156 TEST_F(InputDispatcherStylusInterceptorTest, StylusHandwritingScenario) {
14157 auto [overlay, window] = setupStylusOverlayScenario();
14158 overlay->setSpy(true);
14159 mDispatcher->onWindowInfosChanged({{*overlay->getInfo(), *window->getInfo()}, {}, 0, 0});
14160
14161 sendStylusEvent(AMOTION_EVENT_ACTION_DOWN);
14162 overlay->consumeMotionDown();
14163 window->consumeMotionDown();
14164
14165 // The interceptor pilfers the pointers.
14166 EXPECT_EQ(OK, mDispatcher->pilferPointers(overlay->getToken()));
14167 window->consumeMotionCancel();
14168
14169 // The interceptor configures itself so that it is no longer a spy.
14170 overlay->setSpy(false);
14171 mDispatcher->onWindowInfosChanged({{*overlay->getInfo(), *window->getInfo()}, {}, 0, 0});
14172
14173 // It continues to receive the rest of the stylus gesture.
14174 sendStylusEvent(AMOTION_EVENT_ACTION_MOVE);
14175 overlay->consumeMotionMove();
14176 sendStylusEvent(AMOTION_EVENT_ACTION_UP);
14177 overlay->consumeMotionUp();
14178
14179 window->assertNoEvents();
14180 }
14181
14182 struct User {
14183 gui::Pid mPid;
14184 gui::Uid mUid;
14185 uint32_t mPolicyFlags{DEFAULT_POLICY_FLAGS};
14186 std::unique_ptr<InputDispatcher>& mDispatcher;
14187
Userandroid::inputdispatcher::User14188 User(std::unique_ptr<InputDispatcher>& dispatcher, gui::Pid pid, gui::Uid uid)
14189 : mPid(pid), mUid(uid), mDispatcher(dispatcher) {}
14190
injectTargetedMotionandroid::inputdispatcher::User14191 InputEventInjectionResult injectTargetedMotion(int32_t action) const {
14192 return injectMotionEvent(*mDispatcher, action, AINPUT_SOURCE_TOUCHSCREEN,
14193 ui::LogicalDisplayId::DEFAULT, {100, 200},
14194 {AMOTION_EVENT_INVALID_CURSOR_POSITION,
14195 AMOTION_EVENT_INVALID_CURSOR_POSITION},
14196 INJECT_EVENT_TIMEOUT, InputEventInjectionSync::WAIT_FOR_RESULT,
14197 systemTime(SYSTEM_TIME_MONOTONIC), {mUid}, mPolicyFlags);
14198 }
14199
injectTargetedKeyandroid::inputdispatcher::User14200 InputEventInjectionResult injectTargetedKey(int32_t action) const {
14201 return inputdispatcher::injectKey(*mDispatcher, action, /*repeatCount=*/0,
14202 ui::LogicalDisplayId::INVALID,
14203 InputEventInjectionSync::WAIT_FOR_RESULT,
14204 INJECT_EVENT_TIMEOUT, /*allowKeyRepeat=*/false, {mUid},
14205 mPolicyFlags);
14206 }
14207
createWindowandroid::inputdispatcher::User14208 sp<FakeWindowHandle> createWindow(const char* name) const {
14209 std::shared_ptr<FakeApplicationHandle> overlayApplication =
14210 std::make_shared<FakeApplicationHandle>();
14211 sp<FakeWindowHandle> window =
14212 sp<FakeWindowHandle>::make(overlayApplication, mDispatcher, name,
14213 ui::LogicalDisplayId::DEFAULT);
14214 window->setOwnerInfo(mPid, mUid);
14215 return window;
14216 }
14217 };
14218
14219 using InputDispatcherTargetedInjectionTest = InputDispatcherTest;
14220
TEST_F(InputDispatcherTargetedInjectionTest,CanInjectIntoOwnedWindow)14221 TEST_F(InputDispatcherTargetedInjectionTest, CanInjectIntoOwnedWindow) {
14222 auto owner = User(mDispatcher, gui::Pid{10}, gui::Uid{11});
14223 auto window = owner.createWindow("Owned window");
14224 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
14225
14226 EXPECT_EQ(InputEventInjectionResult::SUCCEEDED,
14227 owner.injectTargetedMotion(AMOTION_EVENT_ACTION_DOWN));
14228 window->consumeMotionDown();
14229
14230 setFocusedWindow(window);
14231 window->consumeFocusEvent(true);
14232
14233 EXPECT_EQ(InputEventInjectionResult::SUCCEEDED,
14234 owner.injectTargetedKey(AKEY_EVENT_ACTION_DOWN));
14235 window->consumeKeyDown(ui::LogicalDisplayId::INVALID);
14236 }
14237
TEST_F(InputDispatcherTargetedInjectionTest,CannotInjectIntoUnownedWindow)14238 TEST_F(InputDispatcherTargetedInjectionTest, CannotInjectIntoUnownedWindow) {
14239 auto owner = User(mDispatcher, gui::Pid{10}, gui::Uid{11});
14240 auto window = owner.createWindow("Owned window");
14241 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
14242
14243 auto rando = User(mDispatcher, gui::Pid{20}, gui::Uid{21});
14244 EXPECT_EQ(InputEventInjectionResult::TARGET_MISMATCH,
14245 rando.injectTargetedMotion(AMOTION_EVENT_ACTION_DOWN));
14246
14247 setFocusedWindow(window);
14248 window->consumeFocusEvent(true);
14249
14250 EXPECT_EQ(InputEventInjectionResult::TARGET_MISMATCH,
14251 rando.injectTargetedKey(AKEY_EVENT_ACTION_DOWN));
14252 window->assertNoEvents();
14253 }
14254
TEST_F(InputDispatcherTargetedInjectionTest,CanInjectIntoOwnedSpyWindow)14255 TEST_F(InputDispatcherTargetedInjectionTest, CanInjectIntoOwnedSpyWindow) {
14256 auto owner = User(mDispatcher, gui::Pid{10}, gui::Uid{11});
14257 auto window = owner.createWindow("Owned window");
14258 auto spy = owner.createWindow("Owned spy");
14259 spy->setSpy(true);
14260 spy->setTrustedOverlay(true);
14261 mDispatcher->onWindowInfosChanged({{*spy->getInfo(), *window->getInfo()}, {}, 0, 0});
14262
14263 EXPECT_EQ(InputEventInjectionResult::SUCCEEDED,
14264 owner.injectTargetedMotion(AMOTION_EVENT_ACTION_DOWN));
14265 spy->consumeMotionDown();
14266 window->consumeMotionDown();
14267 }
14268
TEST_F(InputDispatcherTargetedInjectionTest,CannotInjectIntoUnownedSpyWindow)14269 TEST_F(InputDispatcherTargetedInjectionTest, CannotInjectIntoUnownedSpyWindow) {
14270 auto owner = User(mDispatcher, gui::Pid{10}, gui::Uid{11});
14271 auto window = owner.createWindow("Owned window");
14272
14273 auto rando = User(mDispatcher, gui::Pid{20}, gui::Uid{21});
14274 auto randosSpy = rando.createWindow("Rando's spy");
14275 randosSpy->setSpy(true);
14276 randosSpy->setTrustedOverlay(true);
14277 mDispatcher->onWindowInfosChanged({{*randosSpy->getInfo(), *window->getInfo()}, {}, 0, 0});
14278
14279 // The event is targeted at owner's window, so injection should succeed, but the spy should
14280 // not receive the event.
14281 EXPECT_EQ(InputEventInjectionResult::SUCCEEDED,
14282 owner.injectTargetedMotion(AMOTION_EVENT_ACTION_DOWN));
14283 randosSpy->assertNoEvents();
14284 window->consumeMotionDown();
14285 }
14286
TEST_F(InputDispatcherTargetedInjectionTest,CanInjectIntoAnyWindowWhenNotTargeting)14287 TEST_F(InputDispatcherTargetedInjectionTest, CanInjectIntoAnyWindowWhenNotTargeting) {
14288 auto owner = User(mDispatcher, gui::Pid{10}, gui::Uid{11});
14289 auto window = owner.createWindow("Owned window");
14290
14291 auto rando = User(mDispatcher, gui::Pid{20}, gui::Uid{21});
14292 auto randosSpy = rando.createWindow("Rando's spy");
14293 randosSpy->setSpy(true);
14294 randosSpy->setTrustedOverlay(true);
14295 mDispatcher->onWindowInfosChanged({{*randosSpy->getInfo(), *window->getInfo()}, {}, 0, 0});
14296
14297 // A user that has injection permission can inject into any window.
14298 EXPECT_EQ(InputEventInjectionResult::SUCCEEDED,
14299 injectMotionEvent(*mDispatcher, AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN,
14300 ui::LogicalDisplayId::DEFAULT));
14301 randosSpy->consumeMotionDown();
14302 window->consumeMotionDown();
14303
14304 setFocusedWindow(randosSpy);
14305 randosSpy->consumeFocusEvent(true);
14306
14307 EXPECT_EQ(InputEventInjectionResult::SUCCEEDED, injectKeyDown(*mDispatcher));
14308 randosSpy->consumeKeyDown(ui::LogicalDisplayId::INVALID);
14309 window->assertNoEvents();
14310 }
14311
TEST_F(InputDispatcherTargetedInjectionTest,CannotGenerateActionOutsideToOtherUids)14312 TEST_F(InputDispatcherTargetedInjectionTest, CannotGenerateActionOutsideToOtherUids) {
14313 auto owner = User(mDispatcher, gui::Pid{10}, gui::Uid{11});
14314 auto window = owner.createWindow("Owned window");
14315
14316 auto rando = User(mDispatcher, gui::Pid{20}, gui::Uid{21});
14317 auto randosWindow = rando.createWindow("Rando's window");
14318 randosWindow->setFrame(Rect{-10, -10, -5, -5});
14319 randosWindow->setWatchOutsideTouch(true);
14320 mDispatcher->onWindowInfosChanged({{*randosWindow->getInfo(), *window->getInfo()}, {}, 0, 0});
14321
14322 // Do not allow generation of ACTION_OUTSIDE events into windows owned by different uids.
14323 EXPECT_EQ(InputEventInjectionResult::SUCCEEDED,
14324 owner.injectTargetedMotion(AMOTION_EVENT_ACTION_DOWN));
14325 window->consumeMotionDown();
14326 randosWindow->assertNoEvents();
14327 }
14328
14329 using InputDispatcherPointerInWindowTest = InputDispatcherTest;
14330
TEST_F(InputDispatcherPointerInWindowTest,PointerInWindowWhenHovering)14331 TEST_F(InputDispatcherPointerInWindowTest, PointerInWindowWhenHovering) {
14332 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
14333
14334 sp<FakeWindowHandle> left = sp<FakeWindowHandle>::make(application, mDispatcher, "Left Window",
14335 ui::LogicalDisplayId::DEFAULT);
14336 left->setFrame(Rect(0, 0, 100, 100));
14337 sp<FakeWindowHandle> right =
14338 sp<FakeWindowHandle>::make(application, mDispatcher, "Right Window",
14339 ui::LogicalDisplayId::DEFAULT);
14340 right->setFrame(Rect(100, 0, 200, 100));
14341 sp<FakeWindowHandle> spy = sp<FakeWindowHandle>::make(application, mDispatcher, "Spy Window",
14342 ui::LogicalDisplayId::DEFAULT);
14343 spy->setFrame(Rect(0, 0, 200, 100));
14344 spy->setTrustedOverlay(true);
14345 spy->setSpy(true);
14346
14347 mDispatcher->onWindowInfosChanged(
14348 {{*spy->getInfo(), *left->getInfo(), *right->getInfo()}, {}, 0, 0});
14349
14350 // Hover into the left window.
14351 mDispatcher->notifyMotion(
14352 MotionArgsBuilder(ACTION_HOVER_ENTER, AINPUT_SOURCE_STYLUS)
14353 .pointer(PointerBuilder(/*id=*/0, ToolType::STYLUS).x(50).y(50))
14354 .build());
14355
14356 left->consumeMotionEvent(WithMotionAction(ACTION_HOVER_ENTER));
14357 spy->consumeMotionEvent(WithMotionAction(ACTION_HOVER_ENTER));
14358
14359 ASSERT_TRUE(mDispatcher->isPointerInWindow(left->getToken(), ui::LogicalDisplayId::DEFAULT,
14360 DEVICE_ID,
14361 /*pointerId=*/0));
14362 ASSERT_TRUE(mDispatcher->isPointerInWindow(spy->getToken(), ui::LogicalDisplayId::DEFAULT,
14363 DEVICE_ID,
14364 /*pointerId=*/0));
14365 ASSERT_FALSE(mDispatcher->isPointerInWindow(right->getToken(), ui::LogicalDisplayId::DEFAULT,
14366 DEVICE_ID,
14367 /*pointerId=*/0));
14368
14369 // Hover move to the right window.
14370 mDispatcher->notifyMotion(
14371 MotionArgsBuilder(ACTION_HOVER_MOVE, AINPUT_SOURCE_STYLUS)
14372 .pointer(PointerBuilder(/*id=*/0, ToolType::STYLUS).x(150).y(50))
14373 .build());
14374
14375 left->consumeMotionEvent(WithMotionAction(ACTION_HOVER_EXIT));
14376 right->consumeMotionEvent(WithMotionAction(ACTION_HOVER_ENTER));
14377 spy->consumeMotionEvent(WithMotionAction(ACTION_HOVER_MOVE));
14378
14379 ASSERT_FALSE(mDispatcher->isPointerInWindow(left->getToken(), ui::LogicalDisplayId::DEFAULT,
14380 DEVICE_ID,
14381 /*pointerId=*/0));
14382 ASSERT_TRUE(mDispatcher->isPointerInWindow(spy->getToken(), ui::LogicalDisplayId::DEFAULT,
14383 DEVICE_ID,
14384 /*pointerId=*/0));
14385 ASSERT_TRUE(mDispatcher->isPointerInWindow(right->getToken(), ui::LogicalDisplayId::DEFAULT,
14386 DEVICE_ID,
14387 /*pointerId=*/0));
14388
14389 // Stop hovering.
14390 mDispatcher->notifyMotion(
14391 MotionArgsBuilder(ACTION_HOVER_EXIT, AINPUT_SOURCE_STYLUS)
14392 .pointer(PointerBuilder(/*id=*/0, ToolType::STYLUS).x(150).y(50))
14393 .build());
14394
14395 right->consumeMotionEvent(WithMotionAction(ACTION_HOVER_EXIT));
14396 spy->consumeMotionEvent(WithMotionAction(ACTION_HOVER_EXIT));
14397
14398 ASSERT_FALSE(mDispatcher->isPointerInWindow(left->getToken(), ui::LogicalDisplayId::DEFAULT,
14399 DEVICE_ID,
14400 /*pointerId=*/0));
14401 ASSERT_FALSE(mDispatcher->isPointerInWindow(spy->getToken(), ui::LogicalDisplayId::DEFAULT,
14402 DEVICE_ID,
14403 /*pointerId=*/0));
14404 ASSERT_FALSE(mDispatcher->isPointerInWindow(right->getToken(), ui::LogicalDisplayId::DEFAULT,
14405 DEVICE_ID,
14406 /*pointerId=*/0));
14407 }
14408
TEST_F(InputDispatcherPointerInWindowTest,PointerInWindowWithSplitTouch)14409 TEST_F(InputDispatcherPointerInWindowTest, PointerInWindowWithSplitTouch) {
14410 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
14411
14412 sp<FakeWindowHandle> left = sp<FakeWindowHandle>::make(application, mDispatcher, "Left Window",
14413 ui::LogicalDisplayId::DEFAULT);
14414 left->setFrame(Rect(0, 0, 100, 100));
14415 sp<FakeWindowHandle> right =
14416 sp<FakeWindowHandle>::make(application, mDispatcher, "Right Window",
14417 ui::LogicalDisplayId::DEFAULT);
14418 right->setFrame(Rect(100, 0, 200, 100));
14419 sp<FakeWindowHandle> spy = sp<FakeWindowHandle>::make(application, mDispatcher, "Spy Window",
14420 ui::LogicalDisplayId::DEFAULT);
14421 spy->setFrame(Rect(0, 0, 200, 100));
14422 spy->setTrustedOverlay(true);
14423 spy->setSpy(true);
14424
14425 mDispatcher->onWindowInfosChanged(
14426 {{*spy->getInfo(), *left->getInfo(), *right->getInfo()}, {}, 0, 0});
14427
14428 // First pointer down on left window.
14429 mDispatcher->notifyMotion(
14430 MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
14431 .pointer(PointerBuilder(/*id=*/0, ToolType::FINGER).x(50).y(50))
14432 .build());
14433
14434 left->consumeMotionDown();
14435 spy->consumeMotionDown();
14436
14437 ASSERT_TRUE(mDispatcher->isPointerInWindow(left->getToken(), ui::LogicalDisplayId::DEFAULT,
14438 DEVICE_ID,
14439 /*pointerId=*/0));
14440 ASSERT_TRUE(mDispatcher->isPointerInWindow(spy->getToken(), ui::LogicalDisplayId::DEFAULT,
14441 DEVICE_ID,
14442 /*pointerId=*/0));
14443 ASSERT_FALSE(mDispatcher->isPointerInWindow(right->getToken(), ui::LogicalDisplayId::DEFAULT,
14444 DEVICE_ID,
14445 /*pointerId=*/0));
14446
14447 // Second pointer down on right window.
14448 mDispatcher->notifyMotion(
14449 MotionArgsBuilder(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
14450 .pointer(PointerBuilder(/*id=*/0, ToolType::FINGER).x(50).y(50))
14451 .pointer(PointerBuilder(/*id=*/1, ToolType::FINGER).x(150).y(50))
14452 .build());
14453
14454 left->consumeMotionMove();
14455 right->consumeMotionDown();
14456 spy->consumeMotionEvent(WithMotionAction(POINTER_1_DOWN));
14457
14458 ASSERT_TRUE(mDispatcher->isPointerInWindow(left->getToken(), ui::LogicalDisplayId::DEFAULT,
14459 DEVICE_ID,
14460 /*pointerId=*/0));
14461 ASSERT_TRUE(mDispatcher->isPointerInWindow(spy->getToken(), ui::LogicalDisplayId::DEFAULT,
14462 DEVICE_ID,
14463 /*pointerId=*/0));
14464 ASSERT_FALSE(mDispatcher->isPointerInWindow(right->getToken(), ui::LogicalDisplayId::DEFAULT,
14465 DEVICE_ID,
14466 /*pointerId=*/0));
14467 ASSERT_FALSE(mDispatcher->isPointerInWindow(left->getToken(), ui::LogicalDisplayId::DEFAULT,
14468 DEVICE_ID,
14469 /*pointerId=*/1));
14470 ASSERT_TRUE(mDispatcher->isPointerInWindow(spy->getToken(), ui::LogicalDisplayId::DEFAULT,
14471 DEVICE_ID,
14472 /*pointerId=*/1));
14473 ASSERT_TRUE(mDispatcher->isPointerInWindow(right->getToken(), ui::LogicalDisplayId::DEFAULT,
14474 DEVICE_ID,
14475 /*pointerId=*/1));
14476
14477 // Second pointer up.
14478 mDispatcher->notifyMotion(
14479 MotionArgsBuilder(POINTER_1_UP, AINPUT_SOURCE_TOUCHSCREEN)
14480 .pointer(PointerBuilder(/*id=*/0, ToolType::FINGER).x(50).y(50))
14481 .pointer(PointerBuilder(/*id=*/1, ToolType::FINGER).x(150).y(50))
14482 .build());
14483
14484 left->consumeMotionMove();
14485 right->consumeMotionUp();
14486 spy->consumeMotionEvent(WithMotionAction(POINTER_1_UP));
14487
14488 ASSERT_TRUE(mDispatcher->isPointerInWindow(left->getToken(), ui::LogicalDisplayId::DEFAULT,
14489 DEVICE_ID,
14490 /*pointerId=*/0));
14491 ASSERT_TRUE(mDispatcher->isPointerInWindow(spy->getToken(), ui::LogicalDisplayId::DEFAULT,
14492 DEVICE_ID,
14493 /*pointerId=*/0));
14494 ASSERT_FALSE(mDispatcher->isPointerInWindow(right->getToken(), ui::LogicalDisplayId::DEFAULT,
14495 DEVICE_ID,
14496 /*pointerId=*/0));
14497 ASSERT_FALSE(mDispatcher->isPointerInWindow(left->getToken(), ui::LogicalDisplayId::DEFAULT,
14498 DEVICE_ID,
14499 /*pointerId=*/1));
14500 ASSERT_FALSE(mDispatcher->isPointerInWindow(spy->getToken(), ui::LogicalDisplayId::DEFAULT,
14501 DEVICE_ID,
14502 /*pointerId=*/1));
14503 ASSERT_FALSE(mDispatcher->isPointerInWindow(right->getToken(), ui::LogicalDisplayId::DEFAULT,
14504 DEVICE_ID,
14505 /*pointerId=*/1));
14506
14507 // First pointer up.
14508 mDispatcher->notifyMotion(
14509 MotionArgsBuilder(ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN)
14510 .pointer(PointerBuilder(/*id=*/0, ToolType::FINGER).x(50).y(50))
14511 .build());
14512
14513 left->consumeMotionUp();
14514 spy->consumeMotionUp();
14515
14516 ASSERT_FALSE(mDispatcher->isPointerInWindow(left->getToken(), ui::LogicalDisplayId::DEFAULT,
14517 DEVICE_ID,
14518 /*pointerId=*/0));
14519 ASSERT_FALSE(mDispatcher->isPointerInWindow(spy->getToken(), ui::LogicalDisplayId::DEFAULT,
14520 DEVICE_ID,
14521 /*pointerId=*/0));
14522 ASSERT_FALSE(mDispatcher->isPointerInWindow(right->getToken(), ui::LogicalDisplayId::DEFAULT,
14523 DEVICE_ID,
14524 /*pointerId=*/0));
14525 }
14526
TEST_F(InputDispatcherPointerInWindowTest,MultipleDevicesControllingOneMouse_legacy)14527 TEST_F(InputDispatcherPointerInWindowTest, MultipleDevicesControllingOneMouse_legacy) {
14528 SCOPED_FLAG_OVERRIDE(enable_multi_device_same_window_stream, false);
14529 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
14530
14531 sp<FakeWindowHandle> left = sp<FakeWindowHandle>::make(application, mDispatcher, "Left Window",
14532 ui::LogicalDisplayId::DEFAULT);
14533 left->setFrame(Rect(0, 0, 100, 100));
14534 sp<FakeWindowHandle> right =
14535 sp<FakeWindowHandle>::make(application, mDispatcher, "Right Window",
14536 ui::LogicalDisplayId::DEFAULT);
14537 right->setFrame(Rect(100, 0, 200, 100));
14538
14539 mDispatcher->onWindowInfosChanged({{*left->getInfo(), *right->getInfo()}, {}, 0, 0});
14540
14541 ASSERT_FALSE(mDispatcher->isPointerInWindow(left->getToken(), ui::LogicalDisplayId::DEFAULT,
14542 DEVICE_ID,
14543 /*pointerId=*/0));
14544 ASSERT_FALSE(mDispatcher->isPointerInWindow(right->getToken(), ui::LogicalDisplayId::DEFAULT,
14545 DEVICE_ID,
14546 /*pointerId=*/0));
14547
14548 // Hover move into the window.
14549 mDispatcher->notifyMotion(
14550 MotionArgsBuilder(ACTION_HOVER_MOVE, AINPUT_SOURCE_MOUSE)
14551 .pointer(PointerBuilder(/*id=*/0, ToolType::MOUSE).x(50).y(50))
14552 .rawXCursorPosition(50)
14553 .rawYCursorPosition(50)
14554 .deviceId(DEVICE_ID)
14555 .build());
14556
14557 left->consumeMotionEvent(WithMotionAction(ACTION_HOVER_ENTER));
14558
14559 ASSERT_TRUE(mDispatcher->isPointerInWindow(left->getToken(), ui::LogicalDisplayId::DEFAULT,
14560 DEVICE_ID,
14561 /*pointerId=*/0));
14562
14563 // Move the mouse with another device. This cancels the hovering pointer from the first device.
14564 mDispatcher->notifyMotion(
14565 MotionArgsBuilder(ACTION_HOVER_MOVE, AINPUT_SOURCE_MOUSE)
14566 .pointer(PointerBuilder(/*id=*/0, ToolType::MOUSE).x(51).y(50))
14567 .rawXCursorPosition(51)
14568 .rawYCursorPosition(50)
14569 .deviceId(SECOND_DEVICE_ID)
14570 .build());
14571
14572 left->consumeMotionEvent(WithMotionAction(ACTION_HOVER_EXIT));
14573 left->consumeMotionEvent(WithMotionAction(ACTION_HOVER_ENTER));
14574
14575 // TODO(b/313689709): InputDispatcher's touch state is not updated, even though the window gets
14576 // a HOVER_EXIT from the first device.
14577 ASSERT_TRUE(mDispatcher->isPointerInWindow(left->getToken(), ui::LogicalDisplayId::DEFAULT,
14578 DEVICE_ID,
14579 /*pointerId=*/0));
14580 ASSERT_TRUE(mDispatcher->isPointerInWindow(left->getToken(), ui::LogicalDisplayId::DEFAULT,
14581 SECOND_DEVICE_ID,
14582 /*pointerId=*/0));
14583
14584 // Move the mouse outside the window. Document the current behavior, where the window does not
14585 // receive HOVER_EXIT even though the mouse left the window.
14586 mDispatcher->notifyMotion(
14587 MotionArgsBuilder(ACTION_HOVER_MOVE, AINPUT_SOURCE_MOUSE)
14588 .pointer(PointerBuilder(/*id=*/0, ToolType::MOUSE).x(150).y(50))
14589 .rawXCursorPosition(150)
14590 .rawYCursorPosition(50)
14591 .deviceId(SECOND_DEVICE_ID)
14592 .build());
14593
14594 left->consumeMotionEvent(WithMotionAction(ACTION_HOVER_EXIT));
14595 right->consumeMotionEvent(WithMotionAction(ACTION_HOVER_ENTER));
14596 ASSERT_TRUE(mDispatcher->isPointerInWindow(left->getToken(), ui::LogicalDisplayId::DEFAULT,
14597 DEVICE_ID,
14598 /*pointerId=*/0));
14599 ASSERT_FALSE(mDispatcher->isPointerInWindow(left->getToken(), ui::LogicalDisplayId::DEFAULT,
14600 SECOND_DEVICE_ID,
14601 /*pointerId=*/0));
14602 }
14603
14604 /**
14605 * TODO(b/313689709) - correctly support multiple mouse devices, because they should be controlling
14606 * the same cursor, and therefore have a shared motion event stream.
14607 */
TEST_F(InputDispatcherPointerInWindowTest,MultipleDevicesControllingOneMouse)14608 TEST_F(InputDispatcherPointerInWindowTest, MultipleDevicesControllingOneMouse) {
14609 SCOPED_FLAG_OVERRIDE(enable_multi_device_same_window_stream, true);
14610 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
14611
14612 sp<FakeWindowHandle> left = sp<FakeWindowHandle>::make(application, mDispatcher, "Left Window",
14613 ui::LogicalDisplayId::DEFAULT);
14614 left->setFrame(Rect(0, 0, 100, 100));
14615 sp<FakeWindowHandle> right =
14616 sp<FakeWindowHandle>::make(application, mDispatcher, "Right Window",
14617 ui::LogicalDisplayId::DEFAULT);
14618 right->setFrame(Rect(100, 0, 200, 100));
14619
14620 mDispatcher->onWindowInfosChanged({{*left->getInfo(), *right->getInfo()}, {}, 0, 0});
14621
14622 ASSERT_FALSE(mDispatcher->isPointerInWindow(left->getToken(), ui::LogicalDisplayId::DEFAULT,
14623 DEVICE_ID,
14624 /*pointerId=*/0));
14625 ASSERT_FALSE(mDispatcher->isPointerInWindow(right->getToken(), ui::LogicalDisplayId::DEFAULT,
14626 DEVICE_ID,
14627 /*pointerId=*/0));
14628
14629 // Hover move into the window.
14630 mDispatcher->notifyMotion(
14631 MotionArgsBuilder(ACTION_HOVER_MOVE, AINPUT_SOURCE_MOUSE)
14632 .pointer(PointerBuilder(/*id=*/0, ToolType::MOUSE).x(50).y(50))
14633 .rawXCursorPosition(50)
14634 .rawYCursorPosition(50)
14635 .deviceId(DEVICE_ID)
14636 .build());
14637
14638 left->consumeMotionEvent(WithMotionAction(ACTION_HOVER_ENTER));
14639
14640 ASSERT_TRUE(mDispatcher->isPointerInWindow(left->getToken(), ui::LogicalDisplayId::DEFAULT,
14641 DEVICE_ID,
14642 /*pointerId=*/0));
14643
14644 // Move the mouse with another device
14645 mDispatcher->notifyMotion(
14646 MotionArgsBuilder(ACTION_HOVER_MOVE, AINPUT_SOURCE_MOUSE)
14647 .pointer(PointerBuilder(/*id=*/0, ToolType::MOUSE).x(51).y(50))
14648 .rawXCursorPosition(51)
14649 .rawYCursorPosition(50)
14650 .deviceId(SECOND_DEVICE_ID)
14651 .build());
14652 left->consumeMotionEvent(WithMotionAction(ACTION_HOVER_ENTER));
14653
14654 // TODO(b/313689709): InputDispatcher's touch state is not updated, even though the window gets
14655 // a HOVER_EXIT from the first device.
14656 ASSERT_TRUE(mDispatcher->isPointerInWindow(left->getToken(), ui::LogicalDisplayId::DEFAULT,
14657 DEVICE_ID,
14658 /*pointerId=*/0));
14659 ASSERT_TRUE(mDispatcher->isPointerInWindow(left->getToken(), ui::LogicalDisplayId::DEFAULT,
14660 SECOND_DEVICE_ID,
14661 /*pointerId=*/0));
14662
14663 // Move the mouse outside the window. Document the current behavior, where the window does not
14664 // receive HOVER_EXIT even though the mouse left the window.
14665 mDispatcher->notifyMotion(
14666 MotionArgsBuilder(ACTION_HOVER_MOVE, AINPUT_SOURCE_MOUSE)
14667 .pointer(PointerBuilder(/*id=*/0, ToolType::MOUSE).x(150).y(50))
14668 .rawXCursorPosition(150)
14669 .rawYCursorPosition(50)
14670 .deviceId(SECOND_DEVICE_ID)
14671 .build());
14672
14673 right->consumeMotionEvent(WithMotionAction(ACTION_HOVER_ENTER));
14674 ASSERT_TRUE(mDispatcher->isPointerInWindow(left->getToken(), ui::LogicalDisplayId::DEFAULT,
14675 DEVICE_ID,
14676 /*pointerId=*/0));
14677 ASSERT_FALSE(mDispatcher->isPointerInWindow(left->getToken(), ui::LogicalDisplayId::DEFAULT,
14678 SECOND_DEVICE_ID,
14679 /*pointerId=*/0));
14680 }
14681
TEST_F(InputDispatcherTest,FocusedDisplayChangeIsNotified)14682 TEST_F(InputDispatcherTest, FocusedDisplayChangeIsNotified) {
14683 mDispatcher->setFocusedDisplay(SECOND_DISPLAY_ID);
14684 mFakePolicy->assertFocusedDisplayNotified(SECOND_DISPLAY_ID);
14685 }
14686
14687 } // namespace android::inputdispatcher
14688