blob: 4bb64fc9e1b01d7bf531d59b1f8fd6d786aa2b1c [file] [log] [blame]
Michael Wrightd02c5b62014-02-10 15:10:22 -08001/*
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
Garfield Tan0fc2fa72019-08-29 17:22:15 -070017#include "../dispatcher/InputDispatcher.h"
Siarhei Vishniakou2defec02023-06-08 17:24:44 -070018#include "FakeApplicationHandle.h"
Prabir Pradhan81e89fe2024-03-20 21:17:09 +000019#include "FakeInputDispatcherPolicy.h"
Prabir Pradhandc3a2ad2024-02-05 19:03:51 +000020#include "FakeInputTracingBackend.h"
Prabir Pradhanc5340732024-03-20 22:53:52 +000021#include "FakeWindows.h"
Prabir Pradhane3b28dd2023-10-06 04:19:29 +000022#include "TestEventMatchers.h"
Michael Wrightd02c5b62014-02-10 15:10:22 -080023
Cody Heiner166a5af2023-07-07 12:25:00 -070024#include <NotifyArgsBuilders.h>
Prabir Pradhan5893d362023-11-17 04:30:40 +000025#include <android-base/logging.h>
Siarhei Vishniakou1c494c52021-08-11 20:25:01 -070026#include <android-base/properties.h>
Prabir Pradhana3ab87a2022-01-27 10:00:21 -080027#include <android-base/silent_death_test.h>
Garfield Tan1c7bc862020-01-28 13:24:04 -080028#include <android-base/stringprintf.h>
Siarhei Vishniakou4cb50ca2020-05-26 21:43:02 -070029#include <android-base/thread_annotations.h>
Robert Carr803535b2018-08-02 16:38:15 -070030#include <binder/Binder.h>
Ameer Armalycff4fa52023-10-04 23:45:11 +000031#include <com_android_input_flags.h>
Michael Wright8e9a8562022-02-09 13:44:29 +000032#include <fcntl.h>
Ameer Armalycff4fa52023-10-04 23:45:11 +000033#include <flag_macros.h>
Siarhei Vishniakou0b0374d2022-11-17 17:40:53 -080034#include <gmock/gmock.h>
Michael Wrightd02c5b62014-02-10 15:10:22 -080035#include <gtest/gtest.h>
Siarhei Vishniakou3782af62024-03-07 21:56:39 -080036#include <input/BlockingQueue.h>
Siarhei Vishniakou870ecec2020-12-09 08:07:46 -100037#include <input/Input.h>
Siarhei Vishniakou0438ca82024-03-12 14:27:25 -070038#include <input/InputConsumer.h>
Siarhei Vishniakouf4043212023-09-18 19:33:03 -070039#include <input/PrintTools.h>
Michael Wrightd02c5b62014-02-10 15:10:22 -080040#include <linux/input.h>
Prabir Pradhan07e05b62021-11-19 03:57:24 -080041#include <sys/epoll.h>
Siarhei Vishniakou870ecec2020-12-09 08:07:46 -100042
Garfield Tan1c7bc862020-01-28 13:24:04 -080043#include <cinttypes>
Siarhei Vishniakou487c49b2022-12-02 15:48:57 -080044#include <compare>
Siarhei Vishniakou4cb50ca2020-05-26 21:43:02 -070045#include <thread>
Garfield Tan1c7bc862020-01-28 13:24:04 -080046#include <unordered_set>
chaviwd1c23182019-12-20 18:44:56 -080047#include <vector>
Michael Wrightd02c5b62014-02-10 15:10:22 -080048
Garfield Tan1c7bc862020-01-28 13:24:04 -080049using android::base::StringPrintf;
chaviw3277faf2021-05-19 16:45:23 -050050using android::gui::FocusRequest;
51using android::gui::TouchOcclusionMode;
52using android::gui::WindowInfo;
53using android::gui::WindowInfoHandle;
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -080054using android::os::InputEventInjectionResult;
55using android::os::InputEventInjectionSync;
Garfield Tan1c7bc862020-01-28 13:24:04 -080056
Garfield Tane84e6f92019-08-29 17:28:41 -070057namespace android::inputdispatcher {
Michael Wrightd02c5b62014-02-10 15:10:22 -080058
Dominik Laskowski2f01d772022-03-23 16:01:29 -070059using namespace ftl::flag_operators;
Siarhei Vishniakou0b0374d2022-11-17 17:40:53 -080060using testing::AllOf;
Prabir Pradhan5893d362023-11-17 04:30:40 +000061using testing::Not;
Dominik Laskowski2f01d772022-03-23 16:01:29 -070062
Siarhei Vishniakouf4043212023-09-18 19:33:03 -070063namespace {
64
Michael Wrightd02c5b62014-02-10 15:10:22 -080065// An arbitrary time value.
Prabir Pradhan5735a322022-04-11 17:23:34 +000066static constexpr nsecs_t ARBITRARY_TIME = 1234;
Michael Wrightd02c5b62014-02-10 15:10:22 -080067
68// An arbitrary device id.
Prabir Pradhan9205e422023-05-16 20:06:13 +000069static constexpr int32_t DEVICE_ID = DEFAULT_DEVICE_ID;
Siarhei Vishniakou060f82b2023-01-27 06:39:14 -080070static constexpr int32_t SECOND_DEVICE_ID = 2;
Michael Wrightd02c5b62014-02-10 15:10:22 -080071
Jeff Brownf086ddb2014-02-11 14:28:48 -080072// An arbitrary display id.
Arthur Hungabbb9d82021-09-01 14:52:30 +000073static constexpr int32_t DISPLAY_ID = ADISPLAY_ID_DEFAULT;
74static constexpr int32_t SECOND_DISPLAY_ID = 1;
Jeff Brownf086ddb2014-02-11 14:28:48 -080075
Prabir Pradhan8ede1d12023-05-08 19:37:44 +000076// Ensure common actions are interchangeable between keys and motions for convenience.
77static_assert(AMOTION_EVENT_ACTION_DOWN == AKEY_EVENT_ACTION_DOWN);
78static_assert(AMOTION_EVENT_ACTION_UP == AKEY_EVENT_ACTION_UP);
Siarhei Vishniakouf372b812023-02-14 18:06:51 -080079static constexpr int32_t ACTION_DOWN = AMOTION_EVENT_ACTION_DOWN;
80static constexpr int32_t ACTION_MOVE = AMOTION_EVENT_ACTION_MOVE;
81static constexpr int32_t ACTION_UP = AMOTION_EVENT_ACTION_UP;
82static constexpr int32_t ACTION_HOVER_ENTER = AMOTION_EVENT_ACTION_HOVER_ENTER;
Siarhei Vishniakoua235c042023-05-02 09:59:09 -070083static constexpr int32_t ACTION_HOVER_MOVE = AMOTION_EVENT_ACTION_HOVER_MOVE;
Siarhei Vishniakouf372b812023-02-14 18:06:51 -080084static constexpr int32_t ACTION_HOVER_EXIT = AMOTION_EVENT_ACTION_HOVER_EXIT;
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -070085static constexpr int32_t ACTION_SCROLL = AMOTION_EVENT_ACTION_SCROLL;
Siarhei Vishniakou487c49b2022-12-02 15:48:57 -080086static constexpr int32_t ACTION_OUTSIDE = AMOTION_EVENT_ACTION_OUTSIDE;
Siarhei Vishniakou1ae72f12023-01-29 12:55:30 -080087static constexpr int32_t ACTION_CANCEL = AMOTION_EVENT_ACTION_CANCEL;
Siarhei Vishniakouf372b812023-02-14 18:06:51 -080088/**
89 * The POINTER_DOWN(0) is an unusual, but valid, action. It just means that the new pointer in the
90 * MotionEvent is at the index 0 rather than 1 (or later). That is, the pointer id=0 (which is at
91 * index 0) is the new pointer going down. The same pointer could have been placed at a different
92 * index, and the action would become POINTER_1_DOWN, 2, etc..; these would all be valid. In
93 * general, we try to place pointer id = 0 at the index 0. Of course, this is not possible if
94 * pointer id=0 leaves but the pointer id=1 remains.
95 */
96static constexpr int32_t POINTER_0_DOWN =
97 AMOTION_EVENT_ACTION_POINTER_DOWN | (0 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT);
Siarhei Vishniakoua16e3a22022-03-02 15:26:40 -080098static constexpr int32_t POINTER_1_DOWN =
99 AMOTION_EVENT_ACTION_POINTER_DOWN | (1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT);
Prabir Pradhanb60b1dc2022-03-15 14:02:35 +0000100static constexpr int32_t POINTER_2_DOWN =
101 AMOTION_EVENT_ACTION_POINTER_DOWN | (2 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT);
Vaibhav Devmurari882bd9b2022-06-23 14:54:54 +0000102static constexpr int32_t POINTER_3_DOWN =
103 AMOTION_EVENT_ACTION_POINTER_DOWN | (3 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT);
Arthur Hungc539dbb2022-12-08 07:45:36 +0000104static constexpr int32_t POINTER_0_UP =
105 AMOTION_EVENT_ACTION_POINTER_UP | (0 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT);
Siarhei Vishniakoua16e3a22022-03-02 15:26:40 -0800106static constexpr int32_t POINTER_1_UP =
107 AMOTION_EVENT_ACTION_POINTER_UP | (1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT);
Harry Cuttsb166c002023-05-09 13:06:05 +0000108static constexpr int32_t POINTER_2_UP =
109 AMOTION_EVENT_ACTION_POINTER_UP | (2 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT);
Siarhei Vishniakoua16e3a22022-03-02 15:26:40 -0800110
Antonio Kantek15beb512022-06-13 22:35:41 +0000111// The default pid and uid for the windows created on the secondary display by the test.
Prabir Pradhanaeebeb42023-06-13 19:53:03 +0000112static constexpr gui::Pid SECONDARY_WINDOW_PID{1010};
Prabir Pradhan8a5c41d2023-06-08 19:13:46 +0000113static constexpr gui::Uid SECONDARY_WINDOW_UID{1012};
Antonio Kantek15beb512022-06-13 22:35:41 +0000114
Siarhei Vishniakou58cfc602020-12-14 23:21:30 +0000115// An arbitrary pid of the gesture monitor window
Prabir Pradhanaeebeb42023-06-13 19:53:03 +0000116static constexpr gui::Pid MONITOR_PID{2001};
Siarhei Vishniakou58cfc602020-12-14 23:21:30 +0000117
Arthur Hungc539dbb2022-12-08 07:45:36 +0000118static constexpr int expectedWallpaperFlags =
119 AMOTION_EVENT_FLAG_WINDOW_IS_OBSCURED | AMOTION_EVENT_FLAG_WINDOW_IS_PARTIALLY_OBSCURED;
120
Siarhei Vishniakou56e79092023-02-21 19:13:16 -0800121using ReservedInputDeviceId::VIRTUAL_KEYBOARD_ID;
122
Gang Wang342c9272020-01-13 13:15:04 -0500123/**
124 * Return a DOWN key event with KEYCODE_A.
125 */
126static KeyEvent getTestKeyEvent() {
127 KeyEvent event;
128
Garfield Tanfbe732e2020-01-24 11:26:14 -0800129 event.initialize(InputEvent::nextId(), DEVICE_ID, AINPUT_SOURCE_KEYBOARD, ADISPLAY_ID_NONE,
130 INVALID_HMAC, AKEY_EVENT_ACTION_DOWN, 0, AKEYCODE_A, KEY_A, AMETA_NONE, 0,
131 ARBITRARY_TIME, ARBITRARY_TIME);
Gang Wang342c9272020-01-13 13:15:04 -0500132 return event;
133}
134
Siarhei Vishniakouf4043212023-09-18 19:33:03 -0700135} // namespace
Michael Wrightd02c5b62014-02-10 15:10:22 -0800136
Michael Wrightd02c5b62014-02-10 15:10:22 -0800137// --- InputDispatcherTest ---
138
139class InputDispatcherTest : public testing::Test {
140protected:
Prabir Pradhana41d2442023-04-20 21:30:40 +0000141 std::unique_ptr<FakeInputDispatcherPolicy> mFakePolicy;
Siarhei Vishniakou18050092021-09-01 13:32:49 -0700142 std::unique_ptr<InputDispatcher> mDispatcher;
Prabir Pradhanc5340732024-03-20 22:53:52 +0000143 std::shared_ptr<VerifyingTrace> mVerifyingTrace;
Michael Wrightd02c5b62014-02-10 15:10:22 -0800144
Siarhei Vishniakouf2652122021-03-05 21:39:46 +0000145 void SetUp() override {
Prabir Pradhanc5340732024-03-20 22:53:52 +0000146 mVerifyingTrace = std::make_shared<VerifyingTrace>();
147 FakeWindowHandle::sOnEventReceivedCallback = [this](const auto& _1, const auto& _2) {
148 handleEventReceivedByWindow(_1, _2);
149 };
150
Prabir Pradhana41d2442023-04-20 21:30:40 +0000151 mFakePolicy = std::make_unique<FakeInputDispatcherPolicy>();
Prabir Pradhandc3a2ad2024-02-05 19:03:51 +0000152 mDispatcher = std::make_unique<InputDispatcher>(*mFakePolicy,
153 std::make_unique<FakeInputTracingBackend>(
Prabir Pradhanc5340732024-03-20 22:53:52 +0000154 mVerifyingTrace));
Siarhei Vishniakoua7333112023-10-27 13:33:29 -0700155
Harry Cutts101ee9b2023-07-06 18:04:14 +0000156 mDispatcher->setInputDispatchMode(/*enabled=*/true, /*frozen=*/false);
Siarhei Vishniakou870ecec2020-12-09 08:07:46 -1000157 // Start InputDispatcher thread
Prabir Pradhan3608aad2019-10-02 17:08:26 -0700158 ASSERT_EQ(OK, mDispatcher->start());
Michael Wrightd02c5b62014-02-10 15:10:22 -0800159 }
160
Siarhei Vishniakouf2652122021-03-05 21:39:46 +0000161 void TearDown() override {
Prabir Pradhanc5340732024-03-20 22:53:52 +0000162 ASSERT_NO_FATAL_FAILURE(mVerifyingTrace->verifyExpectedEventsTraced());
163 FakeWindowHandle::sOnEventReceivedCallback = nullptr;
164
Prabir Pradhan3608aad2019-10-02 17:08:26 -0700165 ASSERT_EQ(OK, mDispatcher->stop());
Prabir Pradhana41d2442023-04-20 21:30:40 +0000166 mFakePolicy.reset();
Siarhei Vishniakou18050092021-09-01 13:32:49 -0700167 mDispatcher.reset();
Michael Wrightd02c5b62014-02-10 15:10:22 -0800168 }
Siarhei Vishniakou4cb50ca2020-05-26 21:43:02 -0700169
Prabir Pradhanc5340732024-03-20 22:53:52 +0000170 void handleEventReceivedByWindow(const std::unique_ptr<InputEvent>& event,
171 const gui::WindowInfo& info) {
172 if (!event) {
173 return;
174 }
175
176 switch (event->getType()) {
177 case InputEventType::KEY: {
178 mVerifyingTrace->expectKeyDispatchTraced(static_cast<KeyEvent&>(*event), info.id);
179 break;
180 }
181 case InputEventType::MOTION: {
182 mVerifyingTrace->expectMotionDispatchTraced(static_cast<MotionEvent&>(*event),
183 info.id);
184 break;
185 }
186 default:
187 break;
188 }
189 }
190
Siarhei Vishniakou4cb50ca2020-05-26 21:43:02 -0700191 /**
192 * Used for debugging when writing the test
193 */
194 void dumpDispatcherState() {
195 std::string dump;
196 mDispatcher->dump(dump);
197 std::stringstream ss(dump);
198 std::string to;
199
200 while (std::getline(ss, to, '\n')) {
201 ALOGE("%s", to.c_str());
202 }
203 }
Vishnu Nair958da932020-08-21 17:12:37 -0700204
Chavi Weingarten847e8512023-03-29 00:26:09 +0000205 void setFocusedWindow(const sp<WindowInfoHandle>& window) {
Vishnu Nair958da932020-08-21 17:12:37 -0700206 FocusRequest request;
207 request.token = window->getToken();
Siarhei Vishniakou5d552c42021-05-21 05:02:22 +0000208 request.windowName = window->getName();
Vishnu Nair958da932020-08-21 17:12:37 -0700209 request.timestamp = systemTime(SYSTEM_TIME_MONOTONIC);
210 request.displayId = window->getInfo()->displayId;
211 mDispatcher->setFocusedWindow(request);
212 }
Michael Wrightd02c5b62014-02-10 15:10:22 -0800213};
214
Michael Wrightd02c5b62014-02-10 15:10:22 -0800215TEST_F(InputDispatcherTest, InjectInputEvent_ValidatesKeyEvents) {
216 KeyEvent event;
217
218 // Rejects undefined key actions.
Garfield Tanfbe732e2020-01-24 11:26:14 -0800219 event.initialize(InputEvent::nextId(), DEVICE_ID, AINPUT_SOURCE_KEYBOARD, ADISPLAY_ID_NONE,
220 INVALID_HMAC,
Harry Cutts101ee9b2023-07-06 18:04:14 +0000221 /*action=*/-1, 0, AKEYCODE_A, KEY_A, AMETA_NONE, 0, ARBITRARY_TIME,
Siarhei Vishniakou9c858ac2020-01-23 14:20:11 -0600222 ARBITRARY_TIME);
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -0800223 ASSERT_EQ(InputEventInjectionResult::FAILED,
Harry Cutts33476232023-01-30 19:57:29 +0000224 mDispatcher->injectInputEvent(&event, /*targetUid=*/{}, InputEventInjectionSync::NONE,
Prabir Pradhan5735a322022-04-11 17:23:34 +0000225 0ms, 0))
Michael Wrightd02c5b62014-02-10 15:10:22 -0800226 << "Should reject key events with undefined action.";
227
228 // Rejects ACTION_MULTIPLE since it is not supported despite being defined in the API.
Garfield Tanfbe732e2020-01-24 11:26:14 -0800229 event.initialize(InputEvent::nextId(), DEVICE_ID, AINPUT_SOURCE_KEYBOARD, ADISPLAY_ID_NONE,
230 INVALID_HMAC, AKEY_EVENT_ACTION_MULTIPLE, 0, AKEYCODE_A, KEY_A, AMETA_NONE, 0,
Siarhei Vishniakou9c858ac2020-01-23 14:20:11 -0600231 ARBITRARY_TIME, ARBITRARY_TIME);
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -0800232 ASSERT_EQ(InputEventInjectionResult::FAILED,
Harry Cutts33476232023-01-30 19:57:29 +0000233 mDispatcher->injectInputEvent(&event, /*targetUid=*/{}, InputEventInjectionSync::NONE,
Prabir Pradhan5735a322022-04-11 17:23:34 +0000234 0ms, 0))
Michael Wrightd02c5b62014-02-10 15:10:22 -0800235 << "Should reject key events with ACTION_MULTIPLE.";
236}
237
238TEST_F(InputDispatcherTest, InjectInputEvent_ValidatesMotionEvents) {
239 MotionEvent event;
240 PointerProperties pointerProperties[MAX_POINTERS + 1];
241 PointerCoords pointerCoords[MAX_POINTERS + 1];
Siarhei Vishniakou01747382022-01-20 13:23:27 -0800242 for (size_t i = 0; i <= MAX_POINTERS; i++) {
Michael Wrightd02c5b62014-02-10 15:10:22 -0800243 pointerProperties[i].clear();
244 pointerProperties[i].id = i;
245 pointerCoords[i].clear();
246 }
247
Siarhei Vishniakou49e59222018-12-28 18:17:15 -0800248 // Some constants commonly used below
249 constexpr int32_t source = AINPUT_SOURCE_TOUCHSCREEN;
250 constexpr int32_t edgeFlags = AMOTION_EVENT_EDGE_FLAG_NONE;
251 constexpr int32_t metaState = AMETA_NONE;
252 constexpr MotionClassification classification = MotionClassification::NONE;
253
chaviw9eaa22c2020-07-01 16:21:27 -0700254 ui::Transform identityTransform;
Michael Wrightd02c5b62014-02-10 15:10:22 -0800255 // Rejects undefined motion actions.
Garfield Tanfbe732e2020-01-24 11:26:14 -0800256 event.initialize(InputEvent::nextId(), DEVICE_ID, source, DISPLAY_ID, INVALID_HMAC,
Harry Cutts101ee9b2023-07-06 18:04:14 +0000257 /*action=*/-1, 0, 0, edgeFlags, metaState, 0, classification,
chaviw9eaa22c2020-07-01 16:21:27 -0700258 identityTransform, 0, 0, AMOTION_EVENT_INVALID_CURSOR_POSITION,
Prabir Pradhanb9b18502021-08-26 12:30:32 -0700259 AMOTION_EVENT_INVALID_CURSOR_POSITION, identityTransform, ARBITRARY_TIME,
260 ARBITRARY_TIME,
Harry Cutts101ee9b2023-07-06 18:04:14 +0000261 /*pointerCount=*/1, pointerProperties, pointerCoords);
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -0800262 ASSERT_EQ(InputEventInjectionResult::FAILED,
Harry Cutts33476232023-01-30 19:57:29 +0000263 mDispatcher->injectInputEvent(&event, /*targetUid=*/{}, InputEventInjectionSync::NONE,
Prabir Pradhan5735a322022-04-11 17:23:34 +0000264 0ms, 0))
Michael Wrightd02c5b62014-02-10 15:10:22 -0800265 << "Should reject motion events with undefined action.";
266
267 // Rejects pointer down with invalid index.
Garfield Tanfbe732e2020-01-24 11:26:14 -0800268 event.initialize(InputEvent::nextId(), DEVICE_ID, source, DISPLAY_ID, INVALID_HMAC,
Siarhei Vishniakoua16e3a22022-03-02 15:26:40 -0800269 POINTER_1_DOWN, 0, 0, edgeFlags, metaState, 0, classification,
270 identityTransform, 0, 0, AMOTION_EVENT_INVALID_CURSOR_POSITION,
271 AMOTION_EVENT_INVALID_CURSOR_POSITION, identityTransform, ARBITRARY_TIME,
272 ARBITRARY_TIME,
Harry Cutts101ee9b2023-07-06 18:04:14 +0000273 /*pointerCount=*/1, pointerProperties, pointerCoords);
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -0800274 ASSERT_EQ(InputEventInjectionResult::FAILED,
Harry Cutts33476232023-01-30 19:57:29 +0000275 mDispatcher->injectInputEvent(&event, /*targetUid=*/{}, InputEventInjectionSync::NONE,
Prabir Pradhan5735a322022-04-11 17:23:34 +0000276 0ms, 0))
Michael Wrightd02c5b62014-02-10 15:10:22 -0800277 << "Should reject motion events with pointer down index too large.";
278
Garfield Tanfbe732e2020-01-24 11:26:14 -0800279 event.initialize(InputEvent::nextId(), DEVICE_ID, source, DISPLAY_ID, INVALID_HMAC,
Garfield Tan00f511d2019-06-12 16:55:40 -0700280 AMOTION_EVENT_ACTION_POINTER_DOWN |
281 (~0U << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT),
chaviw9eaa22c2020-07-01 16:21:27 -0700282 0, 0, edgeFlags, metaState, 0, classification, identityTransform, 0, 0,
283 AMOTION_EVENT_INVALID_CURSOR_POSITION, AMOTION_EVENT_INVALID_CURSOR_POSITION,
Prabir Pradhanb9b18502021-08-26 12:30:32 -0700284 identityTransform, ARBITRARY_TIME, ARBITRARY_TIME,
Harry Cutts101ee9b2023-07-06 18:04:14 +0000285 /*pointerCount=*/1, pointerProperties, pointerCoords);
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -0800286 ASSERT_EQ(InputEventInjectionResult::FAILED,
Harry Cutts33476232023-01-30 19:57:29 +0000287 mDispatcher->injectInputEvent(&event, /*targetUid=*/{}, InputEventInjectionSync::NONE,
Prabir Pradhan5735a322022-04-11 17:23:34 +0000288 0ms, 0))
Michael Wrightd02c5b62014-02-10 15:10:22 -0800289 << "Should reject motion events with pointer down index too small.";
290
291 // Rejects pointer up with invalid index.
Garfield Tanfbe732e2020-01-24 11:26:14 -0800292 event.initialize(InputEvent::nextId(), DEVICE_ID, source, DISPLAY_ID, INVALID_HMAC,
Siarhei Vishniakoua16e3a22022-03-02 15:26:40 -0800293 POINTER_1_UP, 0, 0, edgeFlags, metaState, 0, classification, identityTransform,
294 0, 0, AMOTION_EVENT_INVALID_CURSOR_POSITION,
295 AMOTION_EVENT_INVALID_CURSOR_POSITION, identityTransform, ARBITRARY_TIME,
296 ARBITRARY_TIME,
Harry Cutts101ee9b2023-07-06 18:04:14 +0000297 /*pointerCount=*/1, pointerProperties, pointerCoords);
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -0800298 ASSERT_EQ(InputEventInjectionResult::FAILED,
Harry Cutts33476232023-01-30 19:57:29 +0000299 mDispatcher->injectInputEvent(&event, /*targetUid=*/{}, InputEventInjectionSync::NONE,
Prabir Pradhan5735a322022-04-11 17:23:34 +0000300 0ms, 0))
Michael Wrightd02c5b62014-02-10 15:10:22 -0800301 << "Should reject motion events with pointer up index too large.";
302
Garfield Tanfbe732e2020-01-24 11:26:14 -0800303 event.initialize(InputEvent::nextId(), DEVICE_ID, source, DISPLAY_ID, INVALID_HMAC,
Garfield Tan00f511d2019-06-12 16:55:40 -0700304 AMOTION_EVENT_ACTION_POINTER_UP |
305 (~0U << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT),
chaviw9eaa22c2020-07-01 16:21:27 -0700306 0, 0, edgeFlags, metaState, 0, classification, identityTransform, 0, 0,
307 AMOTION_EVENT_INVALID_CURSOR_POSITION, AMOTION_EVENT_INVALID_CURSOR_POSITION,
Prabir Pradhanb9b18502021-08-26 12:30:32 -0700308 identityTransform, ARBITRARY_TIME, ARBITRARY_TIME,
Harry Cutts101ee9b2023-07-06 18:04:14 +0000309 /*pointerCount=*/1, pointerProperties, pointerCoords);
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -0800310 ASSERT_EQ(InputEventInjectionResult::FAILED,
Harry Cutts33476232023-01-30 19:57:29 +0000311 mDispatcher->injectInputEvent(&event, /*targetUid=*/{}, InputEventInjectionSync::NONE,
Prabir Pradhan5735a322022-04-11 17:23:34 +0000312 0ms, 0))
Michael Wrightd02c5b62014-02-10 15:10:22 -0800313 << "Should reject motion events with pointer up index too small.";
314
315 // Rejects motion events with invalid number of pointers.
Garfield Tanfbe732e2020-01-24 11:26:14 -0800316 event.initialize(InputEvent::nextId(), DEVICE_ID, source, DISPLAY_ID, INVALID_HMAC,
317 AMOTION_EVENT_ACTION_DOWN, 0, 0, edgeFlags, metaState, 0, classification,
chaviw9eaa22c2020-07-01 16:21:27 -0700318 identityTransform, 0, 0, AMOTION_EVENT_INVALID_CURSOR_POSITION,
Prabir Pradhanb9b18502021-08-26 12:30:32 -0700319 AMOTION_EVENT_INVALID_CURSOR_POSITION, identityTransform, ARBITRARY_TIME,
320 ARBITRARY_TIME,
Harry Cutts101ee9b2023-07-06 18:04:14 +0000321 /*pointerCount=*/0, pointerProperties, pointerCoords);
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -0800322 ASSERT_EQ(InputEventInjectionResult::FAILED,
Harry Cutts33476232023-01-30 19:57:29 +0000323 mDispatcher->injectInputEvent(&event, /*targetUid=*/{}, InputEventInjectionSync::NONE,
Prabir Pradhan5735a322022-04-11 17:23:34 +0000324 0ms, 0))
Michael Wrightd02c5b62014-02-10 15:10:22 -0800325 << "Should reject motion events with 0 pointers.";
326
Garfield Tanfbe732e2020-01-24 11:26:14 -0800327 event.initialize(InputEvent::nextId(), DEVICE_ID, source, DISPLAY_ID, INVALID_HMAC,
328 AMOTION_EVENT_ACTION_DOWN, 0, 0, edgeFlags, metaState, 0, classification,
chaviw9eaa22c2020-07-01 16:21:27 -0700329 identityTransform, 0, 0, AMOTION_EVENT_INVALID_CURSOR_POSITION,
Prabir Pradhanb9b18502021-08-26 12:30:32 -0700330 AMOTION_EVENT_INVALID_CURSOR_POSITION, identityTransform, ARBITRARY_TIME,
331 ARBITRARY_TIME,
Harry Cutts101ee9b2023-07-06 18:04:14 +0000332 /*pointerCount=*/MAX_POINTERS + 1, pointerProperties, pointerCoords);
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -0800333 ASSERT_EQ(InputEventInjectionResult::FAILED,
Harry Cutts33476232023-01-30 19:57:29 +0000334 mDispatcher->injectInputEvent(&event, /*targetUid=*/{}, InputEventInjectionSync::NONE,
Prabir Pradhan5735a322022-04-11 17:23:34 +0000335 0ms, 0))
Michael Wrightd02c5b62014-02-10 15:10:22 -0800336 << "Should reject motion events with more than MAX_POINTERS pointers.";
337
338 // Rejects motion events with invalid pointer ids.
339 pointerProperties[0].id = -1;
Garfield Tanfbe732e2020-01-24 11:26:14 -0800340 event.initialize(InputEvent::nextId(), DEVICE_ID, source, DISPLAY_ID, INVALID_HMAC,
341 AMOTION_EVENT_ACTION_DOWN, 0, 0, edgeFlags, metaState, 0, classification,
chaviw9eaa22c2020-07-01 16:21:27 -0700342 identityTransform, 0, 0, AMOTION_EVENT_INVALID_CURSOR_POSITION,
Prabir Pradhanb9b18502021-08-26 12:30:32 -0700343 AMOTION_EVENT_INVALID_CURSOR_POSITION, identityTransform, ARBITRARY_TIME,
344 ARBITRARY_TIME,
Harry Cutts101ee9b2023-07-06 18:04:14 +0000345 /*pointerCount=*/1, pointerProperties, pointerCoords);
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -0800346 ASSERT_EQ(InputEventInjectionResult::FAILED,
Harry Cutts33476232023-01-30 19:57:29 +0000347 mDispatcher->injectInputEvent(&event, /*targetUid=*/{}, InputEventInjectionSync::NONE,
Prabir Pradhan5735a322022-04-11 17:23:34 +0000348 0ms, 0))
Michael Wrightd02c5b62014-02-10 15:10:22 -0800349 << "Should reject motion events with pointer ids less than 0.";
350
351 pointerProperties[0].id = MAX_POINTER_ID + 1;
Garfield Tanfbe732e2020-01-24 11:26:14 -0800352 event.initialize(InputEvent::nextId(), DEVICE_ID, source, DISPLAY_ID, INVALID_HMAC,
353 AMOTION_EVENT_ACTION_DOWN, 0, 0, edgeFlags, metaState, 0, classification,
chaviw9eaa22c2020-07-01 16:21:27 -0700354 identityTransform, 0, 0, AMOTION_EVENT_INVALID_CURSOR_POSITION,
Prabir Pradhanb9b18502021-08-26 12:30:32 -0700355 AMOTION_EVENT_INVALID_CURSOR_POSITION, identityTransform, ARBITRARY_TIME,
356 ARBITRARY_TIME,
Harry Cutts101ee9b2023-07-06 18:04:14 +0000357 /*pointerCount=*/1, pointerProperties, pointerCoords);
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -0800358 ASSERT_EQ(InputEventInjectionResult::FAILED,
Harry Cutts33476232023-01-30 19:57:29 +0000359 mDispatcher->injectInputEvent(&event, /*targetUid=*/{}, InputEventInjectionSync::NONE,
Prabir Pradhan5735a322022-04-11 17:23:34 +0000360 0ms, 0))
Michael Wrightd02c5b62014-02-10 15:10:22 -0800361 << "Should reject motion events with pointer ids greater than MAX_POINTER_ID.";
362
363 // Rejects motion events with duplicate pointer ids.
364 pointerProperties[0].id = 1;
365 pointerProperties[1].id = 1;
Garfield Tanfbe732e2020-01-24 11:26:14 -0800366 event.initialize(InputEvent::nextId(), DEVICE_ID, source, DISPLAY_ID, INVALID_HMAC,
367 AMOTION_EVENT_ACTION_DOWN, 0, 0, edgeFlags, metaState, 0, classification,
chaviw9eaa22c2020-07-01 16:21:27 -0700368 identityTransform, 0, 0, AMOTION_EVENT_INVALID_CURSOR_POSITION,
Prabir Pradhanb9b18502021-08-26 12:30:32 -0700369 AMOTION_EVENT_INVALID_CURSOR_POSITION, identityTransform, ARBITRARY_TIME,
370 ARBITRARY_TIME,
Harry Cutts101ee9b2023-07-06 18:04:14 +0000371 /*pointerCount=*/2, pointerProperties, pointerCoords);
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -0800372 ASSERT_EQ(InputEventInjectionResult::FAILED,
Harry Cutts33476232023-01-30 19:57:29 +0000373 mDispatcher->injectInputEvent(&event, /*targetUid=*/{}, InputEventInjectionSync::NONE,
Prabir Pradhan5735a322022-04-11 17:23:34 +0000374 0ms, 0))
Michael Wrightd02c5b62014-02-10 15:10:22 -0800375 << "Should reject motion events with duplicate pointer ids.";
376}
377
Siarhei Vishniakou2bfa9052019-11-21 18:10:54 -0800378/* Test InputDispatcher for notifyConfigurationChanged and notifySwitch events */
379
380TEST_F(InputDispatcherTest, NotifyConfigurationChanged_CallsPolicy) {
381 constexpr nsecs_t eventTime = 20;
Prabir Pradhan678438e2023-04-13 19:32:51 +0000382 mDispatcher->notifyConfigurationChanged({/*id=*/10, eventTime});
Siarhei Vishniakou2bfa9052019-11-21 18:10:54 -0800383 ASSERT_TRUE(mDispatcher->waitForIdle());
384
385 mFakePolicy->assertNotifyConfigurationChangedWasCalled(eventTime);
386}
387
388TEST_F(InputDispatcherTest, NotifySwitch_CallsPolicy) {
Prabir Pradhana8fe7c52023-12-14 22:07:23 +0000389 NotifySwitchArgs args(InputEvent::nextId(), /*eventTime=*/20, /*policyFlags=*/0,
390 /*switchValues=*/1,
Harry Cutts33476232023-01-30 19:57:29 +0000391 /*switchMask=*/2);
Prabir Pradhan678438e2023-04-13 19:32:51 +0000392 mDispatcher->notifySwitch(args);
Siarhei Vishniakou2bfa9052019-11-21 18:10:54 -0800393
394 // InputDispatcher adds POLICY_FLAG_TRUSTED because the event went through InputListener
395 args.policyFlags |= POLICY_FLAG_TRUSTED;
396 mFakePolicy->assertNotifySwitchWasCalled(args);
397}
398
Siarhei Vishniakouadeb6fa2023-05-26 09:11:06 -0700399namespace {
400
Siarhei Vishniakou097c3db2020-05-06 14:18:38 -0700401static constexpr std::chrono::duration INJECT_EVENT_TIMEOUT = 500ms;
Siarhei Vishniakou540dbae2020-05-05 18:17:17 -0700402
Prabir Pradhan112b1ad2023-09-21 09:53:53 +0000403class FakeMonitorReceiver {
404public:
Siarhei Vishniakou2defec02023-06-08 17:24:44 -0700405 FakeMonitorReceiver(InputDispatcher& dispatcher, const std::string name, int32_t displayId)
406 : mInputReceiver(*dispatcher.createInputMonitor(displayId, name, MONITOR_PID), name) {}
Prabir Pradhan112b1ad2023-09-21 09:53:53 +0000407
Siarhei Vishniakou2defec02023-06-08 17:24:44 -0700408 sp<IBinder> getToken() { return mInputReceiver.getToken(); }
Prabir Pradhan112b1ad2023-09-21 09:53:53 +0000409
410 void consumeKeyDown(int32_t expectedDisplayId, int32_t expectedFlags = 0) {
Siarhei Vishniakou2defec02023-06-08 17:24:44 -0700411 mInputReceiver.consumeEvent(InputEventType::KEY, AKEY_EVENT_ACTION_DOWN, expectedDisplayId,
412 expectedFlags);
Prabir Pradhan112b1ad2023-09-21 09:53:53 +0000413 }
414
415 std::optional<int32_t> receiveEvent() {
Siarhei Vishniakoud3061ab2023-12-18 20:41:08 -0800416 const auto [sequenceNum, _] = mInputReceiver.receiveEvent(CONSUME_TIMEOUT_EVENT_EXPECTED);
417 return sequenceNum;
Prabir Pradhan112b1ad2023-09-21 09:53:53 +0000418 }
419
Siarhei Vishniakou2defec02023-06-08 17:24:44 -0700420 void finishEvent(uint32_t consumeSeq) { return mInputReceiver.finishEvent(consumeSeq); }
Prabir Pradhan112b1ad2023-09-21 09:53:53 +0000421
422 void consumeMotionDown(int32_t expectedDisplayId, int32_t expectedFlags = 0) {
Siarhei Vishniakou2defec02023-06-08 17:24:44 -0700423 mInputReceiver.consumeEvent(InputEventType::MOTION, AMOTION_EVENT_ACTION_DOWN,
424 expectedDisplayId, expectedFlags);
Prabir Pradhan112b1ad2023-09-21 09:53:53 +0000425 }
426
427 void consumeMotionMove(int32_t expectedDisplayId, int32_t expectedFlags = 0) {
Siarhei Vishniakou2defec02023-06-08 17:24:44 -0700428 mInputReceiver.consumeEvent(InputEventType::MOTION, AMOTION_EVENT_ACTION_MOVE,
429 expectedDisplayId, expectedFlags);
Prabir Pradhan112b1ad2023-09-21 09:53:53 +0000430 }
431
432 void consumeMotionUp(int32_t expectedDisplayId, int32_t expectedFlags = 0) {
Siarhei Vishniakou2defec02023-06-08 17:24:44 -0700433 mInputReceiver.consumeEvent(InputEventType::MOTION, AMOTION_EVENT_ACTION_UP,
434 expectedDisplayId, expectedFlags);
Prabir Pradhan112b1ad2023-09-21 09:53:53 +0000435 }
436
437 void consumeMotionCancel(int32_t expectedDisplayId, int32_t expectedFlags = 0) {
Siarhei Vishniakou2defec02023-06-08 17:24:44 -0700438 mInputReceiver.consumeMotionEvent(
Prabir Pradhan112b1ad2023-09-21 09:53:53 +0000439 AllOf(WithMotionAction(AMOTION_EVENT_ACTION_CANCEL),
440 WithDisplayId(expectedDisplayId),
441 WithFlags(expectedFlags | AMOTION_EVENT_FLAG_CANCELED)));
442 }
443
444 void consumeMotionPointerDown(int32_t pointerIdx) {
445 int32_t action = AMOTION_EVENT_ACTION_POINTER_DOWN |
446 (pointerIdx << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT);
Siarhei Vishniakou2defec02023-06-08 17:24:44 -0700447 mInputReceiver.consumeEvent(InputEventType::MOTION, action, ADISPLAY_ID_DEFAULT,
448 /*expectedFlags=*/0);
Prabir Pradhan112b1ad2023-09-21 09:53:53 +0000449 }
450
451 void consumeMotionEvent(const ::testing::Matcher<MotionEvent>& matcher) {
Siarhei Vishniakou2defec02023-06-08 17:24:44 -0700452 mInputReceiver.consumeMotionEvent(matcher);
Prabir Pradhan112b1ad2023-09-21 09:53:53 +0000453 }
454
Siarhei Vishniakoud3061ab2023-12-18 20:41:08 -0800455 std::unique_ptr<MotionEvent> consumeMotion() { return mInputReceiver.consumeMotion(); }
Prabir Pradhan112b1ad2023-09-21 09:53:53 +0000456
Siarhei Vishniakouef2b4502023-12-28 11:51:47 -0800457 void assertNoEvents() { mInputReceiver.assertNoEvents(CONSUME_TIMEOUT_NO_EVENT_EXPECTED); }
Prabir Pradhan112b1ad2023-09-21 09:53:53 +0000458
459private:
Siarhei Vishniakou2defec02023-06-08 17:24:44 -0700460 FakeInputReceiver mInputReceiver;
Prabir Pradhan112b1ad2023-09-21 09:53:53 +0000461};
462
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -0800463static InputEventInjectionResult injectKey(
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -0700464 InputDispatcher& dispatcher, int32_t action, int32_t repeatCount,
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -0800465 int32_t displayId = ADISPLAY_ID_NONE,
466 InputEventInjectionSync syncMode = InputEventInjectionSync::WAIT_FOR_RESULT,
Prabir Pradhan93f342c2021-03-11 15:05:30 -0800467 std::chrono::milliseconds injectionTimeout = INJECT_EVENT_TIMEOUT,
Prabir Pradhan8a5c41d2023-06-08 19:13:46 +0000468 bool allowKeyRepeat = true, std::optional<gui::Uid> targetUid = {},
Prabir Pradhan5735a322022-04-11 17:23:34 +0000469 uint32_t policyFlags = DEFAULT_POLICY_FLAGS) {
Arthur Hungb92218b2018-08-14 12:00:21 +0800470 KeyEvent event;
471 nsecs_t currentTime = systemTime(SYSTEM_TIME_MONOTONIC);
472
473 // Define a valid key down event.
Garfield Tanfbe732e2020-01-24 11:26:14 -0800474 event.initialize(InputEvent::nextId(), DEVICE_ID, AINPUT_SOURCE_KEYBOARD, displayId,
Harry Cutts33476232023-01-30 19:57:29 +0000475 INVALID_HMAC, action, /*flags=*/0, AKEYCODE_A, KEY_A, AMETA_NONE, repeatCount,
476 currentTime, currentTime);
Arthur Hungb92218b2018-08-14 12:00:21 +0800477
Prabir Pradhan93f342c2021-03-11 15:05:30 -0800478 if (!allowKeyRepeat) {
479 policyFlags |= POLICY_FLAG_DISABLE_KEY_REPEAT;
480 }
Arthur Hungb92218b2018-08-14 12:00:21 +0800481 // Inject event until dispatch out.
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -0700482 return dispatcher.injectInputEvent(&event, targetUid, syncMode, injectionTimeout, policyFlags);
Arthur Hungb92218b2018-08-14 12:00:21 +0800483}
484
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -0700485static void assertInjectedKeyTimesOut(InputDispatcher& dispatcher) {
486 InputEventInjectionResult result =
487 injectKey(dispatcher, AKEY_EVENT_ACTION_DOWN, /*repeatCount=*/0, ADISPLAY_ID_NONE,
488 InputEventInjectionSync::WAIT_FOR_RESULT, CONSUME_TIMEOUT_NO_EVENT_EXPECTED);
489 if (result != InputEventInjectionResult::TIMED_OUT) {
490 FAIL() << "Injection should have timed out, but got " << ftl::enum_string(result);
491 }
492}
493
494static InputEventInjectionResult injectKeyDown(InputDispatcher& dispatcher,
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -0800495 int32_t displayId = ADISPLAY_ID_NONE) {
Harry Cutts33476232023-01-30 19:57:29 +0000496 return injectKey(dispatcher, AKEY_EVENT_ACTION_DOWN, /*repeatCount=*/0, displayId);
Siarhei Vishniakou4cb50ca2020-05-26 21:43:02 -0700497}
498
Prabir Pradhan93f342c2021-03-11 15:05:30 -0800499// Inject a down event that has key repeat disabled. This allows InputDispatcher to idle without
500// sending a subsequent key up. When key repeat is enabled, the dispatcher cannot idle because it
501// has to be woken up to process the repeating key.
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -0700502static InputEventInjectionResult injectKeyDownNoRepeat(InputDispatcher& dispatcher,
503 int32_t displayId = ADISPLAY_ID_NONE) {
Harry Cutts33476232023-01-30 19:57:29 +0000504 return injectKey(dispatcher, AKEY_EVENT_ACTION_DOWN, /*repeatCount=*/0, displayId,
Prabir Pradhan93f342c2021-03-11 15:05:30 -0800505 InputEventInjectionSync::WAIT_FOR_RESULT, INJECT_EVENT_TIMEOUT,
Harry Cutts33476232023-01-30 19:57:29 +0000506 /*allowKeyRepeat=*/false);
Prabir Pradhan93f342c2021-03-11 15:05:30 -0800507}
508
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -0700509static InputEventInjectionResult injectKeyUp(InputDispatcher& dispatcher,
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -0800510 int32_t displayId = ADISPLAY_ID_NONE) {
Harry Cutts33476232023-01-30 19:57:29 +0000511 return injectKey(dispatcher, AKEY_EVENT_ACTION_UP, /*repeatCount=*/0, displayId);
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -0700512}
513
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -0800514static InputEventInjectionResult injectMotionEvent(
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -0700515 InputDispatcher& dispatcher, const MotionEvent& event,
Garfield Tandf26e862020-07-01 20:18:19 -0700516 std::chrono::milliseconds injectionTimeout = INJECT_EVENT_TIMEOUT,
Prabir Pradhan5735a322022-04-11 17:23:34 +0000517 InputEventInjectionSync injectionMode = InputEventInjectionSync::WAIT_FOR_RESULT,
Prabir Pradhan8a5c41d2023-06-08 19:13:46 +0000518 std::optional<gui::Uid> targetUid = {}, uint32_t policyFlags = DEFAULT_POLICY_FLAGS) {
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -0700519 return dispatcher.injectInputEvent(&event, targetUid, injectionMode, injectionTimeout,
520 policyFlags);
Garfield Tandf26e862020-07-01 20:18:19 -0700521}
522
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -0800523static InputEventInjectionResult injectMotionEvent(
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -0700524 InputDispatcher& dispatcher, int32_t action, int32_t source, int32_t displayId,
525 const PointF& position = {100, 200},
Siarhei Vishniakou4cb50ca2020-05-26 21:43:02 -0700526 const PointF& cursorPosition = {AMOTION_EVENT_INVALID_CURSOR_POSITION,
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -0700527 AMOTION_EVENT_INVALID_CURSOR_POSITION},
528 std::chrono::milliseconds injectionTimeout = INJECT_EVENT_TIMEOUT,
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -0800529 InputEventInjectionSync injectionMode = InputEventInjectionSync::WAIT_FOR_RESULT,
Prabir Pradhan5735a322022-04-11 17:23:34 +0000530 nsecs_t eventTime = systemTime(SYSTEM_TIME_MONOTONIC),
Prabir Pradhan8a5c41d2023-06-08 19:13:46 +0000531 std::optional<gui::Uid> targetUid = {}, uint32_t policyFlags = DEFAULT_POLICY_FLAGS) {
Siarhei Vishniakou90ee4782023-05-08 11:57:24 -0700532 MotionEventBuilder motionBuilder =
533 MotionEventBuilder(action, source)
534 .displayId(displayId)
535 .eventTime(eventTime)
536 .rawXCursorPosition(cursorPosition.x)
537 .rawYCursorPosition(cursorPosition.y)
538 .pointer(
539 PointerBuilder(/*id=*/0, ToolType::FINGER).x(position.x).y(position.y));
540 if (MotionEvent::getActionMasked(action) == ACTION_DOWN) {
541 motionBuilder.downTime(eventTime);
542 }
Arthur Hungb92218b2018-08-14 12:00:21 +0800543
544 // Inject event until dispatch out.
Siarhei Vishniakou90ee4782023-05-08 11:57:24 -0700545 return injectMotionEvent(dispatcher, motionBuilder.build(), injectionTimeout, injectionMode,
546 targetUid, policyFlags);
Arthur Hungb92218b2018-08-14 12:00:21 +0800547}
548
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -0700549static InputEventInjectionResult injectMotionDown(InputDispatcher& dispatcher, int32_t source,
550 int32_t displayId,
551 const PointF& location = {100, 200}) {
Siarhei Vishniakou4cb50ca2020-05-26 21:43:02 -0700552 return injectMotionEvent(dispatcher, AMOTION_EVENT_ACTION_DOWN, source, displayId, location);
Garfield Tan00f511d2019-06-12 16:55:40 -0700553}
554
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -0700555static InputEventInjectionResult injectMotionUp(InputDispatcher& dispatcher, int32_t source,
556 int32_t displayId,
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -0800557 const PointF& location = {100, 200}) {
Siarhei Vishniakou4cb50ca2020-05-26 21:43:02 -0700558 return injectMotionEvent(dispatcher, AMOTION_EVENT_ACTION_UP, source, displayId, location);
Michael Wright3a240c42019-12-10 20:53:41 +0000559}
560
Jackal Guof9696682018-10-05 12:23:23 +0800561static NotifyKeyArgs generateKeyArgs(int32_t action, int32_t displayId = ADISPLAY_ID_NONE) {
562 nsecs_t currentTime = systemTime(SYSTEM_TIME_MONOTONIC);
563 // Define a valid key event.
Prabir Pradhana8fe7c52023-12-14 22:07:23 +0000564 NotifyKeyArgs args(InputEvent::nextId(), currentTime, /*readTime=*/0, DEVICE_ID,
565 AINPUT_SOURCE_KEYBOARD, displayId, POLICY_FLAG_PASS_TO_USER, action,
566 /*flags=*/0, AKEYCODE_A, KEY_A, AMETA_NONE, currentTime);
Jackal Guof9696682018-10-05 12:23:23 +0800567
568 return args;
569}
570
Josep del Riob3981622023-04-18 15:49:45 +0000571static NotifyKeyArgs generateSystemShortcutArgs(int32_t action,
572 int32_t displayId = ADISPLAY_ID_NONE) {
573 nsecs_t currentTime = systemTime(SYSTEM_TIME_MONOTONIC);
574 // Define a valid key event.
Prabir Pradhana8fe7c52023-12-14 22:07:23 +0000575 NotifyKeyArgs args(InputEvent::nextId(), currentTime, /*readTime=*/0, DEVICE_ID,
576 AINPUT_SOURCE_KEYBOARD, displayId, 0, action, /*flags=*/0, AKEYCODE_C, KEY_C,
577 AMETA_META_ON, currentTime);
Josep del Riob3981622023-04-18 15:49:45 +0000578
579 return args;
580}
581
582static NotifyKeyArgs generateAssistantKeyArgs(int32_t action,
583 int32_t displayId = ADISPLAY_ID_NONE) {
584 nsecs_t currentTime = systemTime(SYSTEM_TIME_MONOTONIC);
585 // Define a valid key event.
Prabir Pradhana8fe7c52023-12-14 22:07:23 +0000586 NotifyKeyArgs args(InputEvent::nextId(), currentTime, /*readTime=*/0, DEVICE_ID,
587 AINPUT_SOURCE_KEYBOARD, displayId, 0, action, /*flags=*/0, AKEYCODE_ASSIST,
588 KEY_ASSISTANT, AMETA_NONE, currentTime);
Josep del Riob3981622023-04-18 15:49:45 +0000589
590 return args;
591}
592
Prabir Pradhan678438e2023-04-13 19:32:51 +0000593[[nodiscard]] static NotifyMotionArgs generateMotionArgs(int32_t action, int32_t source,
594 int32_t displayId,
595 const std::vector<PointF>& points) {
chaviwd1c23182019-12-20 18:44:56 -0800596 size_t pointerCount = points.size();
chaviwaf87b3e2019-10-01 16:59:28 -0700597 if (action == AMOTION_EVENT_ACTION_DOWN || action == AMOTION_EVENT_ACTION_UP) {
598 EXPECT_EQ(1U, pointerCount) << "Actions DOWN and UP can only contain a single pointer";
599 }
600
chaviwd1c23182019-12-20 18:44:56 -0800601 PointerProperties pointerProperties[pointerCount];
602 PointerCoords pointerCoords[pointerCount];
Jackal Guof9696682018-10-05 12:23:23 +0800603
chaviwd1c23182019-12-20 18:44:56 -0800604 for (size_t i = 0; i < pointerCount; i++) {
605 pointerProperties[i].clear();
606 pointerProperties[i].id = i;
Siarhei Vishniakou6d73f832022-07-21 17:27:03 -0700607 pointerProperties[i].toolType = ToolType::FINGER;
Jackal Guof9696682018-10-05 12:23:23 +0800608
chaviwd1c23182019-12-20 18:44:56 -0800609 pointerCoords[i].clear();
610 pointerCoords[i].setAxisValue(AMOTION_EVENT_AXIS_X, points[i].x);
611 pointerCoords[i].setAxisValue(AMOTION_EVENT_AXIS_Y, points[i].y);
612 }
Jackal Guof9696682018-10-05 12:23:23 +0800613
614 nsecs_t currentTime = systemTime(SYSTEM_TIME_MONOTONIC);
615 // Define a valid motion event.
Prabir Pradhana8fe7c52023-12-14 22:07:23 +0000616 NotifyMotionArgs args(InputEvent::nextId(), currentTime, /*readTime=*/0, DEVICE_ID, source,
617 displayId, POLICY_FLAG_PASS_TO_USER, action, /*actionButton=*/0,
618 /*flags=*/0, AMETA_NONE, /*buttonState=*/0, MotionClassification::NONE,
chaviwd1c23182019-12-20 18:44:56 -0800619 AMOTION_EVENT_EDGE_FLAG_NONE, pointerCount, pointerProperties,
Harry Cutts101ee9b2023-07-06 18:04:14 +0000620 pointerCoords, /*xPrecision=*/0, /*yPrecision=*/0,
Garfield Tan00f511d2019-06-12 16:55:40 -0700621 AMOTION_EVENT_INVALID_CURSOR_POSITION,
Harry Cutts101ee9b2023-07-06 18:04:14 +0000622 AMOTION_EVENT_INVALID_CURSOR_POSITION, currentTime, /*videoFrames=*/{});
Jackal Guof9696682018-10-05 12:23:23 +0800623
624 return args;
625}
626
Siarhei Vishniakoua16e3a22022-03-02 15:26:40 -0800627static NotifyMotionArgs generateTouchArgs(int32_t action, const std::vector<PointF>& points) {
628 return generateMotionArgs(action, AINPUT_SOURCE_TOUCHSCREEN, DISPLAY_ID, points);
629}
630
chaviwd1c23182019-12-20 18:44:56 -0800631static NotifyMotionArgs generateMotionArgs(int32_t action, int32_t source, int32_t displayId) {
632 return generateMotionArgs(action, source, displayId, {PointF{100, 200}});
633}
634
Prabir Pradhan5cc1a692021-08-06 14:01:18 +0000635static NotifyPointerCaptureChangedArgs generatePointerCaptureChangedArgs(
636 const PointerCaptureRequest& request) {
Prabir Pradhana8fe7c52023-12-14 22:07:23 +0000637 return NotifyPointerCaptureChangedArgs(InputEvent::nextId(), systemTime(SYSTEM_TIME_MONOTONIC),
638 request);
Prabir Pradhan99987712020-11-10 18:43:05 -0800639}
640
Siarhei Vishniakouadeb6fa2023-05-26 09:11:06 -0700641} // namespace
642
Siarhei Vishniakou7aa3e942021-11-18 09:49:11 -0800643/**
644 * When a window unexpectedly disposes of its input channel, policy should be notified about the
645 * broken channel.
646 */
647TEST_F(InputDispatcherTest, WhenInputChannelBreaks_PolicyIsNotified) {
648 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
649 sp<FakeWindowHandle> window =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -0700650 sp<FakeWindowHandle>::make(application, mDispatcher,
651 "Window that breaks its input channel", ADISPLAY_ID_DEFAULT);
Siarhei Vishniakou7aa3e942021-11-18 09:49:11 -0800652
Siarhei Vishniakouc41de372023-07-20 13:14:26 -0700653 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Siarhei Vishniakou7aa3e942021-11-18 09:49:11 -0800654
655 // Window closes its channel, but the window remains.
656 window->destroyReceiver();
657 mFakePolicy->assertNotifyInputChannelBrokenWasCalled(window->getInfo()->token);
658}
659
Arthur Hungb92218b2018-08-14 12:00:21 +0800660TEST_F(InputDispatcherTest, SetInputWindow_SingleWindowTouch) {
Chris Yea209fde2020-07-22 13:54:51 -0700661 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -0700662 sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher,
663 "Fake Window", ADISPLAY_ID_DEFAULT);
Arthur Hungb92218b2018-08-14 12:00:21 +0800664
Siarhei Vishniakouc41de372023-07-20 13:14:26 -0700665 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -0800666 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -0700667 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT))
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -0800668 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
Arthur Hungb92218b2018-08-14 12:00:21 +0800669
670 // Window should receive motion event.
Siarhei Vishniakouc5ca85c2019-11-15 17:20:00 -0800671 window->consumeMotionDown(ADISPLAY_ID_DEFAULT);
Arthur Hungb92218b2018-08-14 12:00:21 +0800672}
673
Siarhei Vishniakouaeed0da2024-01-09 08:57:13 -0800674using InputDispatcherDeathTest = InputDispatcherTest;
675
676/**
677 * When 'onWindowInfosChanged' arguments contain a duplicate entry for the same window, dispatcher
678 * should crash.
679 */
680TEST_F(InputDispatcherDeathTest, DuplicateWindowInfosAbortDispatcher) {
681 testing::GTEST_FLAG(death_test_style) = "threadsafe";
682 ScopedSilentDeath _silentDeath;
683
684 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
685 sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher,
686 "Fake Window", ADISPLAY_ID_DEFAULT);
687 ASSERT_DEATH(mDispatcher->onWindowInfosChanged(
688 {{*window->getInfo(), *window->getInfo()}, {}, 0, 0}),
689 "Incorrect WindowInfosUpdate provided");
690}
691
Prabir Pradhanc44ce4d2021-10-05 05:26:29 -0700692TEST_F(InputDispatcherTest, WhenDisplayNotSpecified_InjectMotionToDefaultDisplay) {
693 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -0700694 sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher,
695 "Fake Window", ADISPLAY_ID_DEFAULT);
Prabir Pradhanc44ce4d2021-10-05 05:26:29 -0700696
Siarhei Vishniakouc41de372023-07-20 13:14:26 -0700697 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Prabir Pradhanc44ce4d2021-10-05 05:26:29 -0700698 // Inject a MotionEvent to an unknown display.
699 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -0700700 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_NONE))
Prabir Pradhanc44ce4d2021-10-05 05:26:29 -0700701 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
702
703 // Window should receive motion event.
704 window->consumeMotionDown(ADISPLAY_ID_DEFAULT);
705}
706
Siarhei Vishniakoufb9fcda2020-05-04 14:59:19 -0700707/**
Siarhei Vishniakouc41de372023-07-20 13:14:26 -0700708 * Calling onWindowInfosChanged once should not cause any issues.
709 * This test serves as a sanity check for the next test, where onWindowInfosChanged is
Siarhei Vishniakoufb9fcda2020-05-04 14:59:19 -0700710 * called twice.
711 */
Prabir Pradhan76bdecb2022-01-31 11:14:15 -0800712TEST_F(InputDispatcherTest, SetInputWindowOnceWithSingleTouchWindow) {
Chris Yea209fde2020-07-22 13:54:51 -0700713 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -0700714 sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher,
715 "Fake Window", ADISPLAY_ID_DEFAULT);
Siarhei Vishniakoufb9fcda2020-05-04 14:59:19 -0700716 window->setFrame(Rect(0, 0, 100, 100));
Siarhei Vishniakoufb9fcda2020-05-04 14:59:19 -0700717
Siarhei Vishniakouc41de372023-07-20 13:14:26 -0700718 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -0800719 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -0700720 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
Siarhei Vishniakoufb9fcda2020-05-04 14:59:19 -0700721 {50, 50}))
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -0800722 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
Siarhei Vishniakoufb9fcda2020-05-04 14:59:19 -0700723
724 // Window should receive motion event.
725 window->consumeMotionDown(ADISPLAY_ID_DEFAULT);
726}
727
728/**
Siarhei Vishniakouc41de372023-07-20 13:14:26 -0700729 * Calling onWindowInfosChanged twice, with the same info, should not cause any issues.
Siarhei Vishniakoufb9fcda2020-05-04 14:59:19 -0700730 */
731TEST_F(InputDispatcherTest, SetInputWindowTwice_SingleWindowTouch) {
Chris Yea209fde2020-07-22 13:54:51 -0700732 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -0700733 sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher,
734 "Fake Window", ADISPLAY_ID_DEFAULT);
Siarhei Vishniakoufb9fcda2020-05-04 14:59:19 -0700735 window->setFrame(Rect(0, 0, 100, 100));
Siarhei Vishniakoufb9fcda2020-05-04 14:59:19 -0700736
Siarhei Vishniakouc41de372023-07-20 13:14:26 -0700737 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
738 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -0800739 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -0700740 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
Siarhei Vishniakoufb9fcda2020-05-04 14:59:19 -0700741 {50, 50}))
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -0800742 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
Siarhei Vishniakoufb9fcda2020-05-04 14:59:19 -0700743
744 // Window should receive motion event.
745 window->consumeMotionDown(ADISPLAY_ID_DEFAULT);
746}
747
Arthur Hungb92218b2018-08-14 12:00:21 +0800748// The foreground window should receive the first touch down event.
749TEST_F(InputDispatcherTest, SetInputWindow_MultiWindowsTouch) {
Chris Yea209fde2020-07-22 13:54:51 -0700750 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
Siarhei Vishniakou870ecec2020-12-09 08:07:46 -1000751 sp<FakeWindowHandle> windowTop =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -0700752 sp<FakeWindowHandle>::make(application, mDispatcher, "Top", ADISPLAY_ID_DEFAULT);
Siarhei Vishniakou870ecec2020-12-09 08:07:46 -1000753 sp<FakeWindowHandle> windowSecond =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -0700754 sp<FakeWindowHandle>::make(application, mDispatcher, "Second", ADISPLAY_ID_DEFAULT);
Arthur Hungb92218b2018-08-14 12:00:21 +0800755
Siarhei Vishniakouc41de372023-07-20 13:14:26 -0700756 mDispatcher->onWindowInfosChanged(
757 {{*windowTop->getInfo(), *windowSecond->getInfo()}, {}, 0, 0});
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -0800758 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -0700759 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT))
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -0800760 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
Arthur Hungb92218b2018-08-14 12:00:21 +0800761
762 // Top window should receive the touch down event. Second window should not receive anything.
Siarhei Vishniakouc5ca85c2019-11-15 17:20:00 -0800763 windowTop->consumeMotionDown(ADISPLAY_ID_DEFAULT);
Arthur Hungb92218b2018-08-14 12:00:21 +0800764 windowSecond->assertNoEvents();
765}
766
Siarhei Vishniakouca205502021-07-16 21:31:58 +0000767/**
768 * Two windows: A top window, and a wallpaper behind the window.
769 * Touch goes to the top window, and then top window disappears. Ensure that wallpaper window
770 * gets ACTION_CANCEL.
Prabir Pradhan4d5c52f2022-01-31 08:52:10 -0800771 * 1. foregroundWindow <-- dup touch to wallpaper
772 * 2. wallpaperWindow <-- is wallpaper
Siarhei Vishniakouca205502021-07-16 21:31:58 +0000773 */
774TEST_F(InputDispatcherTest, WhenForegroundWindowDisappears_WallpaperTouchIsCanceled) {
775 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
776 sp<FakeWindowHandle> foregroundWindow =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -0700777 sp<FakeWindowHandle>::make(application, mDispatcher, "Foreground", ADISPLAY_ID_DEFAULT);
Prabir Pradhan4d5c52f2022-01-31 08:52:10 -0800778 foregroundWindow->setDupTouchToWallpaper(true);
Siarhei Vishniakouca205502021-07-16 21:31:58 +0000779 sp<FakeWindowHandle> wallpaperWindow =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -0700780 sp<FakeWindowHandle>::make(application, mDispatcher, "Wallpaper", ADISPLAY_ID_DEFAULT);
Prabir Pradhan4d5c52f2022-01-31 08:52:10 -0800781 wallpaperWindow->setIsWallpaper(true);
Siarhei Vishniakouca205502021-07-16 21:31:58 +0000782
Siarhei Vishniakouc41de372023-07-20 13:14:26 -0700783 mDispatcher->onWindowInfosChanged(
784 {{*foregroundWindow->getInfo(), *wallpaperWindow->getInfo()}, {}, 0, 0});
Siarhei Vishniakouca205502021-07-16 21:31:58 +0000785 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoud908f5a2023-11-16 10:25:12 -0800786 injectMotionEvent(*mDispatcher,
787 MotionEventBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
788 .pointer(PointerBuilder(0, ToolType::FINGER).x(100).y(200))
789 .build()))
Siarhei Vishniakouca205502021-07-16 21:31:58 +0000790 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
791
792 // Both foreground window and its wallpaper should receive the touch down
793 foregroundWindow->consumeMotionDown();
794 wallpaperWindow->consumeMotionDown(ADISPLAY_ID_DEFAULT, expectedWallpaperFlags);
795
796 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoud908f5a2023-11-16 10:25:12 -0800797 injectMotionEvent(*mDispatcher,
798 MotionEventBuilder(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN)
799 .pointer(PointerBuilder(0, ToolType::FINGER).x(110).y(200))
800 .build()))
Siarhei Vishniakouca205502021-07-16 21:31:58 +0000801 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
802
Siarhei Vishniakoud908f5a2023-11-16 10:25:12 -0800803 foregroundWindow->consumeMotionEvent(WithMotionAction(ACTION_MOVE));
Siarhei Vishniakouca205502021-07-16 21:31:58 +0000804 wallpaperWindow->consumeMotionMove(ADISPLAY_ID_DEFAULT, expectedWallpaperFlags);
805
806 // Now the foreground window goes away, but the wallpaper stays
Siarhei Vishniakouc41de372023-07-20 13:14:26 -0700807 mDispatcher->onWindowInfosChanged({{*wallpaperWindow->getInfo()}, {}, 0, 0});
Siarhei Vishniakouca205502021-07-16 21:31:58 +0000808 foregroundWindow->consumeMotionCancel();
809 // Since the "parent" window of the wallpaper is gone, wallpaper should receive cancel, too.
810 wallpaperWindow->consumeMotionCancel(ADISPLAY_ID_DEFAULT, expectedWallpaperFlags);
811}
812
813/**
Siarhei Vishniakou82dc0422023-02-17 23:12:52 -0800814 * Two fingers down on the window, and lift off the first finger.
815 * Next, cancel the gesture to the window by removing the window. Make sure that the CANCEL event
816 * contains a single pointer.
817 */
818TEST_F(InputDispatcherTest, CancelAfterPointer0Up) {
819 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
820 sp<FakeWindowHandle> window =
821 sp<FakeWindowHandle>::make(application, mDispatcher, "Window", ADISPLAY_ID_DEFAULT);
822
Siarhei Vishniakouc41de372023-07-20 13:14:26 -0700823 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Siarhei Vishniakou82dc0422023-02-17 23:12:52 -0800824 // First touch pointer down on right window
Prabir Pradhan678438e2023-04-13 19:32:51 +0000825 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
826 .pointer(PointerBuilder(0, ToolType::FINGER).x(100).y(100))
827 .build());
Siarhei Vishniakou82dc0422023-02-17 23:12:52 -0800828 // Second touch pointer down
Prabir Pradhan678438e2023-04-13 19:32:51 +0000829 mDispatcher->notifyMotion(MotionArgsBuilder(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
830 .pointer(PointerBuilder(0, ToolType::FINGER).x(100).y(100))
831 .pointer(PointerBuilder(1, ToolType::FINGER).x(110).y(100))
832 .build());
Siarhei Vishniakou82dc0422023-02-17 23:12:52 -0800833 // First touch pointer lifts. The second one remains down
Prabir Pradhan678438e2023-04-13 19:32:51 +0000834 mDispatcher->notifyMotion(MotionArgsBuilder(POINTER_0_UP, AINPUT_SOURCE_TOUCHSCREEN)
835 .pointer(PointerBuilder(0, ToolType::FINGER).x(100).y(100))
836 .pointer(PointerBuilder(1, ToolType::FINGER).x(110).y(100))
837 .build());
Siarhei Vishniakou82dc0422023-02-17 23:12:52 -0800838 window->consumeMotionEvent(WithMotionAction(ACTION_DOWN));
839 window->consumeMotionEvent(WithMotionAction(POINTER_1_DOWN));
840 window->consumeMotionEvent(WithMotionAction(POINTER_0_UP));
841
842 // Remove the window. The gesture should be canceled
Siarhei Vishniakouc41de372023-07-20 13:14:26 -0700843 mDispatcher->onWindowInfosChanged({{}, {}, 0, 0});
Siarhei Vishniakou82dc0422023-02-17 23:12:52 -0800844 const std::map<int32_t, PointF> expectedPointers{{1, PointF{110, 100}}};
845 window->consumeMotionEvent(
846 AllOf(WithMotionAction(ACTION_CANCEL), WithPointers(expectedPointers)));
847}
848
849/**
Siarhei Vishniakou2b030972021-11-18 10:01:27 -0800850 * Same test as WhenForegroundWindowDisappears_WallpaperTouchIsCanceled above,
851 * with the following differences:
852 * After ACTION_DOWN, Wallpaper window hangs up its channel, which forces the dispatcher to
853 * clean up the connection.
854 * This later may crash dispatcher during ACTION_CANCEL synthesis, if the dispatcher is not careful.
855 * Ensure that there's no crash in the dispatcher.
856 */
857TEST_F(InputDispatcherTest, WhenWallpaperDisappears_NoCrash) {
858 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
859 sp<FakeWindowHandle> foregroundWindow =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -0700860 sp<FakeWindowHandle>::make(application, mDispatcher, "Foreground", ADISPLAY_ID_DEFAULT);
Prabir Pradhan4d5c52f2022-01-31 08:52:10 -0800861 foregroundWindow->setDupTouchToWallpaper(true);
Siarhei Vishniakou2b030972021-11-18 10:01:27 -0800862 sp<FakeWindowHandle> wallpaperWindow =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -0700863 sp<FakeWindowHandle>::make(application, mDispatcher, "Wallpaper", ADISPLAY_ID_DEFAULT);
Prabir Pradhan4d5c52f2022-01-31 08:52:10 -0800864 wallpaperWindow->setIsWallpaper(true);
Siarhei Vishniakou2b030972021-11-18 10:01:27 -0800865
Siarhei Vishniakouc41de372023-07-20 13:14:26 -0700866 mDispatcher->onWindowInfosChanged(
867 {{*foregroundWindow->getInfo(), *wallpaperWindow->getInfo()}, {}, 0, 0});
Siarhei Vishniakou2b030972021-11-18 10:01:27 -0800868 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -0700869 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
Siarhei Vishniakou2b030972021-11-18 10:01:27 -0800870 {100, 200}))
871 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
872
873 // Both foreground window and its wallpaper should receive the touch down
874 foregroundWindow->consumeMotionDown();
875 wallpaperWindow->consumeMotionDown(ADISPLAY_ID_DEFAULT, expectedWallpaperFlags);
876
877 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -0700878 injectMotionEvent(*mDispatcher, AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN,
Siarhei Vishniakou2b030972021-11-18 10:01:27 -0800879 ADISPLAY_ID_DEFAULT, {110, 200}))
880 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
881
882 foregroundWindow->consumeMotionMove();
883 wallpaperWindow->consumeMotionMove(ADISPLAY_ID_DEFAULT, expectedWallpaperFlags);
884
885 // Wallpaper closes its channel, but the window remains.
886 wallpaperWindow->destroyReceiver();
887 mFakePolicy->assertNotifyInputChannelBrokenWasCalled(wallpaperWindow->getInfo()->token);
888
889 // Now the foreground window goes away, but the wallpaper stays, even though its channel
890 // is no longer valid.
Siarhei Vishniakouc41de372023-07-20 13:14:26 -0700891 mDispatcher->onWindowInfosChanged({{*wallpaperWindow->getInfo()}, {}, 0, 0});
Siarhei Vishniakou2b030972021-11-18 10:01:27 -0800892 foregroundWindow->consumeMotionCancel();
893}
894
Arthur Hungc539dbb2022-12-08 07:45:36 +0000895class ShouldSplitTouchFixture : public InputDispatcherTest,
896 public ::testing::WithParamInterface<bool> {};
897INSTANTIATE_TEST_SUITE_P(InputDispatcherTest, ShouldSplitTouchFixture,
898 ::testing::Values(true, false));
Siarhei Vishniakou2b030972021-11-18 10:01:27 -0800899/**
Siarhei Vishniakouca205502021-07-16 21:31:58 +0000900 * A single window that receives touch (on top), and a wallpaper window underneath it.
901 * The top window gets a multitouch gesture.
902 * Ensure that wallpaper gets the same gesture.
903 */
Arthur Hungc539dbb2022-12-08 07:45:36 +0000904TEST_P(ShouldSplitTouchFixture, WallpaperWindowReceivesMultiTouch) {
Siarhei Vishniakouca205502021-07-16 21:31:58 +0000905 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
Arthur Hungc539dbb2022-12-08 07:45:36 +0000906 sp<FakeWindowHandle> foregroundWindow =
907 sp<FakeWindowHandle>::make(application, mDispatcher, "Foreground", ADISPLAY_ID_DEFAULT);
908 foregroundWindow->setDupTouchToWallpaper(true);
909 foregroundWindow->setPreventSplitting(GetParam());
Siarhei Vishniakouca205502021-07-16 21:31:58 +0000910
911 sp<FakeWindowHandle> wallpaperWindow =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -0700912 sp<FakeWindowHandle>::make(application, mDispatcher, "Wallpaper", ADISPLAY_ID_DEFAULT);
Prabir Pradhan4d5c52f2022-01-31 08:52:10 -0800913 wallpaperWindow->setIsWallpaper(true);
Siarhei Vishniakouca205502021-07-16 21:31:58 +0000914
Siarhei Vishniakouc41de372023-07-20 13:14:26 -0700915 mDispatcher->onWindowInfosChanged(
916 {{*foregroundWindow->getInfo(), *wallpaperWindow->getInfo()}, {}, 0, 0});
Siarhei Vishniakouca205502021-07-16 21:31:58 +0000917
918 // Touch down on top window
919 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -0700920 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
Siarhei Vishniakouca205502021-07-16 21:31:58 +0000921 {100, 100}))
922 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
923
924 // Both top window and its wallpaper should receive the touch down
Arthur Hungc539dbb2022-12-08 07:45:36 +0000925 foregroundWindow->consumeMotionDown();
Siarhei Vishniakouca205502021-07-16 21:31:58 +0000926 wallpaperWindow->consumeMotionDown(ADISPLAY_ID_DEFAULT, expectedWallpaperFlags);
927
928 // Second finger down on the top window
929 const MotionEvent secondFingerDownEvent =
Siarhei Vishniakoua16e3a22022-03-02 15:26:40 -0800930 MotionEventBuilder(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
Siarhei Vishniakouca205502021-07-16 21:31:58 +0000931 .eventTime(systemTime(SYSTEM_TIME_MONOTONIC))
Siarhei Vishniakou6d73f832022-07-21 17:27:03 -0700932 .pointer(PointerBuilder(/*id=*/0, ToolType::FINGER).x(100).y(100))
933 .pointer(PointerBuilder(/*id=*/1, ToolType::FINGER).x(150).y(150))
Siarhei Vishniakouca205502021-07-16 21:31:58 +0000934 .build();
935 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -0700936 injectMotionEvent(*mDispatcher, secondFingerDownEvent, INJECT_EVENT_TIMEOUT,
Siarhei Vishniakouca205502021-07-16 21:31:58 +0000937 InputEventInjectionSync::WAIT_FOR_RESULT))
938 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
939
Harry Cutts33476232023-01-30 19:57:29 +0000940 foregroundWindow->consumeMotionPointerDown(/*pointerIndex=*/1);
941 wallpaperWindow->consumeMotionPointerDown(/*pointerIndex=*/1, ADISPLAY_ID_DEFAULT,
Siarhei Vishniakouca205502021-07-16 21:31:58 +0000942 expectedWallpaperFlags);
Arthur Hungc539dbb2022-12-08 07:45:36 +0000943
944 const MotionEvent secondFingerUpEvent =
945 MotionEventBuilder(POINTER_0_UP, AINPUT_SOURCE_TOUCHSCREEN)
946 .displayId(ADISPLAY_ID_DEFAULT)
947 .eventTime(systemTime(SYSTEM_TIME_MONOTONIC))
Siarhei Vishniakou6d73f832022-07-21 17:27:03 -0700948 .pointer(PointerBuilder(/*id=*/0, ToolType::FINGER).x(100).y(100))
949 .pointer(PointerBuilder(/*id=*/1, ToolType::FINGER).x(150).y(150))
Arthur Hungc539dbb2022-12-08 07:45:36 +0000950 .build();
951 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -0700952 injectMotionEvent(*mDispatcher, secondFingerUpEvent, INJECT_EVENT_TIMEOUT,
Arthur Hungc539dbb2022-12-08 07:45:36 +0000953 InputEventInjectionSync::WAIT_FOR_RESULT))
954 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
955 foregroundWindow->consumeMotionPointerUp(0);
956 wallpaperWindow->consumeMotionPointerUp(0, ADISPLAY_ID_DEFAULT, expectedWallpaperFlags);
957
958 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -0700959 injectMotionEvent(*mDispatcher,
Siarhei Vishniakou92c8fd52023-01-29 14:57:43 -0800960 MotionEventBuilder(AMOTION_EVENT_ACTION_UP,
961 AINPUT_SOURCE_TOUCHSCREEN)
962 .displayId(ADISPLAY_ID_DEFAULT)
963 .eventTime(systemTime(SYSTEM_TIME_MONOTONIC))
Harry Cutts101ee9b2023-07-06 18:04:14 +0000964 .pointer(PointerBuilder(/*id=*/1, ToolType::FINGER)
Siarhei Vishniakou92c8fd52023-01-29 14:57:43 -0800965 .x(100)
966 .y(100))
967 .build(),
968 INJECT_EVENT_TIMEOUT, InputEventInjectionSync::WAIT_FOR_RESULT))
Arthur Hungc539dbb2022-12-08 07:45:36 +0000969 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
970 foregroundWindow->consumeMotionUp(ADISPLAY_ID_DEFAULT);
971 wallpaperWindow->consumeMotionUp(ADISPLAY_ID_DEFAULT, expectedWallpaperFlags);
Siarhei Vishniakouca205502021-07-16 21:31:58 +0000972}
973
974/**
975 * Two windows: a window on the left and window on the right.
976 * A third window, wallpaper, is behind both windows, and spans both top windows.
977 * The first touch down goes to the left window. A second pointer touches down on the right window.
978 * The touch is split, so both left and right windows should receive ACTION_DOWN.
979 * The wallpaper will get the full event, so it should receive ACTION_DOWN followed by
980 * ACTION_POINTER_DOWN(1).
981 */
982TEST_F(InputDispatcherTest, TwoWindows_SplitWallpaperTouch) {
983 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
984 sp<FakeWindowHandle> leftWindow =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -0700985 sp<FakeWindowHandle>::make(application, mDispatcher, "Left", ADISPLAY_ID_DEFAULT);
Siarhei Vishniakouca205502021-07-16 21:31:58 +0000986 leftWindow->setFrame(Rect(0, 0, 200, 200));
Prabir Pradhan4d5c52f2022-01-31 08:52:10 -0800987 leftWindow->setDupTouchToWallpaper(true);
Siarhei Vishniakouca205502021-07-16 21:31:58 +0000988
989 sp<FakeWindowHandle> rightWindow =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -0700990 sp<FakeWindowHandle>::make(application, mDispatcher, "Right", ADISPLAY_ID_DEFAULT);
Siarhei Vishniakouca205502021-07-16 21:31:58 +0000991 rightWindow->setFrame(Rect(200, 0, 400, 200));
Prabir Pradhan4d5c52f2022-01-31 08:52:10 -0800992 rightWindow->setDupTouchToWallpaper(true);
Siarhei Vishniakouca205502021-07-16 21:31:58 +0000993
994 sp<FakeWindowHandle> wallpaperWindow =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -0700995 sp<FakeWindowHandle>::make(application, mDispatcher, "Wallpaper", ADISPLAY_ID_DEFAULT);
Siarhei Vishniakouca205502021-07-16 21:31:58 +0000996 wallpaperWindow->setFrame(Rect(0, 0, 400, 200));
Prabir Pradhan4d5c52f2022-01-31 08:52:10 -0800997 wallpaperWindow->setIsWallpaper(true);
Siarhei Vishniakouca205502021-07-16 21:31:58 +0000998
Siarhei Vishniakouc41de372023-07-20 13:14:26 -0700999 mDispatcher->onWindowInfosChanged(
1000 {{*leftWindow->getInfo(), *rightWindow->getInfo(), *wallpaperWindow->getInfo()},
1001 {},
1002 0,
1003 0});
Siarhei Vishniakouca205502021-07-16 21:31:58 +00001004
1005 // Touch down on left window
1006 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07001007 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
Siarhei Vishniakouca205502021-07-16 21:31:58 +00001008 {100, 100}))
1009 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
1010
1011 // Both foreground window and its wallpaper should receive the touch down
1012 leftWindow->consumeMotionDown();
1013 wallpaperWindow->consumeMotionDown(ADISPLAY_ID_DEFAULT, expectedWallpaperFlags);
1014
1015 // Second finger down on the right window
1016 const MotionEvent secondFingerDownEvent =
Siarhei Vishniakoua16e3a22022-03-02 15:26:40 -08001017 MotionEventBuilder(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
Siarhei Vishniakouca205502021-07-16 21:31:58 +00001018 .eventTime(systemTime(SYSTEM_TIME_MONOTONIC))
Siarhei Vishniakou6d73f832022-07-21 17:27:03 -07001019 .pointer(PointerBuilder(/*id=*/0, ToolType::FINGER).x(100).y(100))
1020 .pointer(PointerBuilder(/*id=*/1, ToolType::FINGER).x(300).y(100))
Siarhei Vishniakouca205502021-07-16 21:31:58 +00001021 .build();
1022 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07001023 injectMotionEvent(*mDispatcher, secondFingerDownEvent, INJECT_EVENT_TIMEOUT,
Siarhei Vishniakouca205502021-07-16 21:31:58 +00001024 InputEventInjectionSync::WAIT_FOR_RESULT))
1025 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
1026
1027 leftWindow->consumeMotionMove();
1028 // Since the touch is split, right window gets ACTION_DOWN
1029 rightWindow->consumeMotionDown(ADISPLAY_ID_DEFAULT);
Harry Cutts33476232023-01-30 19:57:29 +00001030 wallpaperWindow->consumeMotionPointerDown(/*pointerIndex=*/1, ADISPLAY_ID_DEFAULT,
Siarhei Vishniakouca205502021-07-16 21:31:58 +00001031 expectedWallpaperFlags);
1032
1033 // Now, leftWindow, which received the first finger, disappears.
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07001034 mDispatcher->onWindowInfosChanged(
1035 {{*rightWindow->getInfo(), *wallpaperWindow->getInfo()}, {}, 0, 0});
Siarhei Vishniakouca205502021-07-16 21:31:58 +00001036 leftWindow->consumeMotionCancel();
1037 // Since a "parent" window of the wallpaper is gone, wallpaper should receive cancel, too.
1038 wallpaperWindow->consumeMotionCancel(ADISPLAY_ID_DEFAULT, expectedWallpaperFlags);
1039
1040 // The pointer that's still down on the right window moves, and goes to the right window only.
1041 // As far as the dispatcher's concerned though, both pointers are still present.
1042 const MotionEvent secondFingerMoveEvent =
1043 MotionEventBuilder(AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN)
1044 .eventTime(systemTime(SYSTEM_TIME_MONOTONIC))
Siarhei Vishniakou6d73f832022-07-21 17:27:03 -07001045 .pointer(PointerBuilder(/*id=*/0, ToolType::FINGER).x(100).y(100))
1046 .pointer(PointerBuilder(/*id=*/1, ToolType::FINGER).x(310).y(110))
Siarhei Vishniakouca205502021-07-16 21:31:58 +00001047 .build();
1048 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07001049 injectMotionEvent(*mDispatcher, secondFingerMoveEvent, INJECT_EVENT_TIMEOUT,
Siarhei Vishniakouca205502021-07-16 21:31:58 +00001050 InputEventInjectionSync::WAIT_FOR_RESULT));
1051 rightWindow->consumeMotionMove();
1052
1053 leftWindow->assertNoEvents();
1054 rightWindow->assertNoEvents();
1055 wallpaperWindow->assertNoEvents();
1056}
1057
Arthur Hungc539dbb2022-12-08 07:45:36 +00001058/**
1059 * Two windows: a window on the left with dup touch to wallpaper and window on the right without it.
1060 * The touch slips to the right window. so left window and wallpaper should receive ACTION_CANCEL
1061 * The right window should receive ACTION_DOWN.
1062 */
1063TEST_F(InputDispatcherTest, WallpaperWindowWhenSlippery) {
Arthur Hung74c248d2022-11-23 07:09:59 +00001064 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
Arthur Hungc539dbb2022-12-08 07:45:36 +00001065 sp<FakeWindowHandle> leftWindow =
1066 sp<FakeWindowHandle>::make(application, mDispatcher, "Left", ADISPLAY_ID_DEFAULT);
1067 leftWindow->setFrame(Rect(0, 0, 200, 200));
1068 leftWindow->setDupTouchToWallpaper(true);
1069 leftWindow->setSlippery(true);
1070
1071 sp<FakeWindowHandle> rightWindow =
1072 sp<FakeWindowHandle>::make(application, mDispatcher, "Right", ADISPLAY_ID_DEFAULT);
1073 rightWindow->setFrame(Rect(200, 0, 400, 200));
Arthur Hung74c248d2022-11-23 07:09:59 +00001074
1075 sp<FakeWindowHandle> wallpaperWindow =
1076 sp<FakeWindowHandle>::make(application, mDispatcher, "Wallpaper", ADISPLAY_ID_DEFAULT);
1077 wallpaperWindow->setIsWallpaper(true);
Arthur Hung74c248d2022-11-23 07:09:59 +00001078
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07001079 mDispatcher->onWindowInfosChanged(
1080 {{*leftWindow->getInfo(), *rightWindow->getInfo(), *wallpaperWindow->getInfo()},
1081 {},
1082 0,
1083 0});
Arthur Hung74c248d2022-11-23 07:09:59 +00001084
Arthur Hungc539dbb2022-12-08 07:45:36 +00001085 // Touch down on left window
Arthur Hung74c248d2022-11-23 07:09:59 +00001086 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07001087 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
Arthur Hungc539dbb2022-12-08 07:45:36 +00001088 {100, 100}))
Arthur Hung74c248d2022-11-23 07:09:59 +00001089 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
Arthur Hungc539dbb2022-12-08 07:45:36 +00001090
1091 // Both foreground window and its wallpaper should receive the touch down
1092 leftWindow->consumeMotionDown();
Arthur Hung74c248d2022-11-23 07:09:59 +00001093 wallpaperWindow->consumeMotionDown(ADISPLAY_ID_DEFAULT, expectedWallpaperFlags);
1094
Arthur Hungc539dbb2022-12-08 07:45:36 +00001095 // Move to right window, the left window should receive cancel.
Arthur Hung74c248d2022-11-23 07:09:59 +00001096 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07001097 injectMotionEvent(*mDispatcher, AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN,
Arthur Hungc539dbb2022-12-08 07:45:36 +00001098 ADISPLAY_ID_DEFAULT, {201, 100}))
Arthur Hung74c248d2022-11-23 07:09:59 +00001099 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
1100
Arthur Hungc539dbb2022-12-08 07:45:36 +00001101 leftWindow->consumeMotionCancel();
1102 rightWindow->consumeMotionDown(ADISPLAY_ID_DEFAULT);
1103 wallpaperWindow->consumeMotionCancel(ADISPLAY_ID_DEFAULT, expectedWallpaperFlags);
Arthur Hung74c248d2022-11-23 07:09:59 +00001104}
1105
Siarhei Vishniakoua16e3a22022-03-02 15:26:40 -08001106/**
Siarhei Vishniakou5bf25d92023-02-08 15:43:38 -08001107 * The policy typically sets POLICY_FLAG_PASS_TO_USER to the events. But when the display is not
1108 * interactive, it might stop sending this flag.
1109 * In this test, we check that if the policy stops sending this flag mid-gesture, we still ensure
1110 * to have a consistent input stream.
1111 *
1112 * Test procedure:
1113 * DOWN -> POINTER_DOWN -> (stop sending POLICY_FLAG_PASS_TO_USER) -> CANCEL.
1114 * DOWN (new gesture).
1115 *
1116 * In the bad implementation, we could potentially drop the CANCEL event, and get an inconsistent
1117 * state in the dispatcher. This would cause the final DOWN event to not be delivered to the app.
1118 *
1119 * We technically just need a single window here, but we are using two windows (spy on top and a
1120 * regular window below) to emulate the actual situation where it happens on the device.
1121 */
1122TEST_F(InputDispatcherTest, TwoPointerCancelInconsistentPolicy) {
1123 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
1124 sp<FakeWindowHandle> spyWindow =
1125 sp<FakeWindowHandle>::make(application, mDispatcher, "Spy", ADISPLAY_ID_DEFAULT);
1126 spyWindow->setFrame(Rect(0, 0, 200, 200));
1127 spyWindow->setTrustedOverlay(true);
1128 spyWindow->setSpy(true);
1129
1130 sp<FakeWindowHandle> window =
1131 sp<FakeWindowHandle>::make(application, mDispatcher, "Window", ADISPLAY_ID_DEFAULT);
1132 window->setFrame(Rect(0, 0, 200, 200));
1133
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07001134 mDispatcher->onWindowInfosChanged({{*spyWindow->getInfo(), *window->getInfo()}, {}, 0, 0});
Siarhei Vishniakou5bf25d92023-02-08 15:43:38 -08001135 const int32_t touchDeviceId = 4;
Siarhei Vishniakou5bf25d92023-02-08 15:43:38 -08001136
1137 // Two pointers down
Prabir Pradhan678438e2023-04-13 19:32:51 +00001138 mDispatcher->notifyMotion(
1139 MotionArgsBuilder(AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
1140 .deviceId(touchDeviceId)
1141 .policyFlags(DEFAULT_POLICY_FLAGS)
1142 .pointer(PointerBuilder(0, ToolType::FINGER).x(100).y(100))
1143 .build());
Siarhei Vishniakou5bf25d92023-02-08 15:43:38 -08001144
Prabir Pradhan678438e2023-04-13 19:32:51 +00001145 mDispatcher->notifyMotion(MotionArgsBuilder(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
1146 .deviceId(touchDeviceId)
1147 .policyFlags(DEFAULT_POLICY_FLAGS)
1148 .pointer(PointerBuilder(0, ToolType::FINGER).x(100).y(100))
1149 .pointer(PointerBuilder(1, ToolType::FINGER).x(120).y(120))
1150 .build());
Siarhei Vishniakou5bf25d92023-02-08 15:43:38 -08001151 spyWindow->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_DOWN));
1152 spyWindow->consumeMotionEvent(WithMotionAction(POINTER_1_DOWN));
1153 window->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_DOWN));
1154 window->consumeMotionEvent(WithMotionAction(POINTER_1_DOWN));
1155
1156 // Cancel the current gesture. Send the cancel without the default policy flags.
Prabir Pradhan678438e2023-04-13 19:32:51 +00001157 mDispatcher->notifyMotion(
1158 MotionArgsBuilder(AMOTION_EVENT_ACTION_CANCEL, AINPUT_SOURCE_TOUCHSCREEN)
1159 .deviceId(touchDeviceId)
1160 .policyFlags(0)
1161 .pointer(PointerBuilder(0, ToolType::FINGER).x(100).y(100))
1162 .pointer(PointerBuilder(1, ToolType::FINGER).x(120).y(120))
1163 .build());
Siarhei Vishniakou5bf25d92023-02-08 15:43:38 -08001164 spyWindow->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_CANCEL));
1165 window->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_CANCEL));
1166
1167 // We don't need to reset the device to reproduce the issue, but the reset event typically
1168 // follows, so we keep it here to model the actual listener behaviour more closely.
Prabir Pradhan678438e2023-04-13 19:32:51 +00001169 mDispatcher->notifyDeviceReset({/*id=*/1, systemTime(SYSTEM_TIME_MONOTONIC), touchDeviceId});
Siarhei Vishniakou5bf25d92023-02-08 15:43:38 -08001170
1171 // Start new gesture
Prabir Pradhan678438e2023-04-13 19:32:51 +00001172 mDispatcher->notifyMotion(
1173 MotionArgsBuilder(AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
1174 .deviceId(touchDeviceId)
1175 .policyFlags(DEFAULT_POLICY_FLAGS)
1176 .pointer(PointerBuilder(0, ToolType::FINGER).x(100).y(100))
1177 .build());
Siarhei Vishniakou5bf25d92023-02-08 15:43:38 -08001178 spyWindow->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_DOWN));
1179 window->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_DOWN));
1180
1181 // No more events
1182 spyWindow->assertNoEvents();
1183 window->assertNoEvents();
1184}
1185
1186/**
Linnan Li907ae732023-09-05 17:14:21 +08001187 * Same as the above 'TwoPointerCancelInconsistentPolicy' test, but for hovers.
1188 * The policy typically sets POLICY_FLAG_PASS_TO_USER to the events. But when the display is not
1189 * interactive, it might stop sending this flag.
1190 * We've already ensured the consistency of the touch event in this case, and we should also ensure
1191 * the consistency of the hover event in this case.
1192 *
1193 * Test procedure:
1194 * HOVER_ENTER -> HOVER_MOVE -> (stop sending POLICY_FLAG_PASS_TO_USER) -> HOVER_EXIT
1195 * HOVER_ENTER -> HOVER_MOVE -> HOVER_EXIT
1196 *
1197 * We expect to receive two full streams of hover events.
1198 */
1199TEST_F(InputDispatcherTest, HoverEventInconsistentPolicy) {
1200 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
1201
1202 sp<FakeWindowHandle> window =
1203 sp<FakeWindowHandle>::make(application, mDispatcher, "Window", ADISPLAY_ID_DEFAULT);
1204 window->setFrame(Rect(0, 0, 300, 300));
1205
1206 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
1207
1208 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_ENTER, AINPUT_SOURCE_STYLUS)
1209 .policyFlags(DEFAULT_POLICY_FLAGS)
1210 .pointer(PointerBuilder(0, ToolType::STYLUS).x(100).y(101))
1211 .build());
1212 window->consumeMotionEvent(WithMotionAction(ACTION_HOVER_ENTER));
1213
1214 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_MOVE, AINPUT_SOURCE_STYLUS)
1215 .policyFlags(DEFAULT_POLICY_FLAGS)
1216 .pointer(PointerBuilder(0, ToolType::STYLUS).x(101).y(102))
1217 .build());
1218 window->consumeMotionEvent(WithMotionAction(ACTION_HOVER_MOVE));
1219
1220 // Send hover exit without the default policy flags.
1221 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_EXIT, AINPUT_SOURCE_STYLUS)
1222 .policyFlags(0)
1223 .pointer(PointerBuilder(0, ToolType::STYLUS).x(101).y(102))
1224 .build());
1225
1226 window->consumeMotionEvent(WithMotionAction(ACTION_HOVER_EXIT));
1227
1228 // Send a simple hover event stream, ensure dispatcher not crashed and window can receive
1229 // right event.
1230 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_ENTER, AINPUT_SOURCE_STYLUS)
1231 .policyFlags(DEFAULT_POLICY_FLAGS)
1232 .pointer(PointerBuilder(0, ToolType::STYLUS).x(200).y(201))
1233 .build());
1234 window->consumeMotionEvent(WithMotionAction(ACTION_HOVER_ENTER));
1235
1236 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_MOVE, AINPUT_SOURCE_STYLUS)
1237 .policyFlags(DEFAULT_POLICY_FLAGS)
1238 .pointer(PointerBuilder(0, ToolType::STYLUS).x(201).y(202))
1239 .build());
1240 window->consumeMotionEvent(WithMotionAction(ACTION_HOVER_MOVE));
1241
1242 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_EXIT, AINPUT_SOURCE_STYLUS)
1243 .policyFlags(DEFAULT_POLICY_FLAGS)
1244 .pointer(PointerBuilder(0, ToolType::STYLUS).x(201).y(202))
1245 .build());
1246 window->consumeMotionEvent(WithMotionAction(ACTION_HOVER_EXIT));
1247}
1248
1249/**
Siarhei Vishniakoue0431e42023-01-28 17:01:39 -08001250 * Two windows: a window on the left and a window on the right.
1251 * Mouse is hovered from the right window into the left window.
1252 * Next, we tap on the left window, where the cursor was last seen.
1253 * The second tap is done onto the right window.
1254 * The mouse and tap are from two different devices.
1255 * We technically don't need to set the downtime / eventtime for these events, but setting these
1256 * explicitly helps during debugging.
1257 * This test reproduces a crash where there is a mismatch between the downTime and eventTime.
1258 * In the buggy implementation, a tap on the right window would cause a crash.
1259 */
1260TEST_F(InputDispatcherTest, HoverFromLeftToRightAndTap) {
1261 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
1262 sp<FakeWindowHandle> leftWindow =
1263 sp<FakeWindowHandle>::make(application, mDispatcher, "Left", ADISPLAY_ID_DEFAULT);
1264 leftWindow->setFrame(Rect(0, 0, 200, 200));
1265
1266 sp<FakeWindowHandle> rightWindow =
1267 sp<FakeWindowHandle>::make(application, mDispatcher, "Right", ADISPLAY_ID_DEFAULT);
1268 rightWindow->setFrame(Rect(200, 0, 400, 200));
1269
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07001270 mDispatcher->onWindowInfosChanged(
1271 {{*leftWindow->getInfo(), *rightWindow->getInfo()}, {}, 0, 0});
Siarhei Vishniakoue0431e42023-01-28 17:01:39 -08001272 // All times need to start at the current time, otherwise the dispatcher will drop the events as
1273 // stale.
1274 const nsecs_t baseTime = systemTime(SYSTEM_TIME_MONOTONIC);
1275 const int32_t mouseDeviceId = 6;
1276 const int32_t touchDeviceId = 4;
1277 // Move the cursor from right
1278 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07001279 injectMotionEvent(*mDispatcher,
Siarhei Vishniakoue0431e42023-01-28 17:01:39 -08001280 MotionEventBuilder(AMOTION_EVENT_ACTION_HOVER_MOVE,
1281 AINPUT_SOURCE_MOUSE)
1282 .deviceId(mouseDeviceId)
1283 .downTime(baseTime + 10)
1284 .eventTime(baseTime + 20)
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07001285 .pointer(PointerBuilder(0, ToolType::MOUSE).x(300).y(100))
Siarhei Vishniakoue0431e42023-01-28 17:01:39 -08001286 .build()));
1287 rightWindow->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_ENTER));
1288
1289 // .. to the left window
1290 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07001291 injectMotionEvent(*mDispatcher,
Siarhei Vishniakoue0431e42023-01-28 17:01:39 -08001292 MotionEventBuilder(AMOTION_EVENT_ACTION_HOVER_MOVE,
1293 AINPUT_SOURCE_MOUSE)
1294 .deviceId(mouseDeviceId)
1295 .downTime(baseTime + 10)
1296 .eventTime(baseTime + 30)
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07001297 .pointer(PointerBuilder(0, ToolType::MOUSE).x(110).y(100))
Siarhei Vishniakoue0431e42023-01-28 17:01:39 -08001298 .build()));
1299 rightWindow->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_EXIT));
1300 leftWindow->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_ENTER));
1301 // Now tap the left window
1302 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07001303 injectMotionEvent(*mDispatcher,
Siarhei Vishniakoue0431e42023-01-28 17:01:39 -08001304 MotionEventBuilder(AMOTION_EVENT_ACTION_DOWN,
1305 AINPUT_SOURCE_TOUCHSCREEN)
1306 .deviceId(touchDeviceId)
1307 .downTime(baseTime + 40)
1308 .eventTime(baseTime + 40)
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07001309 .pointer(PointerBuilder(0, ToolType::FINGER).x(100).y(100))
Siarhei Vishniakoue0431e42023-01-28 17:01:39 -08001310 .build()));
1311 leftWindow->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_EXIT));
1312 leftWindow->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_DOWN));
1313
1314 // release tap
1315 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07001316 injectMotionEvent(*mDispatcher,
Siarhei Vishniakoue0431e42023-01-28 17:01:39 -08001317 MotionEventBuilder(AMOTION_EVENT_ACTION_UP,
1318 AINPUT_SOURCE_TOUCHSCREEN)
1319 .deviceId(touchDeviceId)
1320 .downTime(baseTime + 40)
1321 .eventTime(baseTime + 50)
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07001322 .pointer(PointerBuilder(0, ToolType::FINGER).x(100).y(100))
Siarhei Vishniakoue0431e42023-01-28 17:01:39 -08001323 .build()));
1324 leftWindow->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_UP));
1325
1326 // Tap the window on the right
1327 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07001328 injectMotionEvent(*mDispatcher,
Siarhei Vishniakoue0431e42023-01-28 17:01:39 -08001329 MotionEventBuilder(AMOTION_EVENT_ACTION_DOWN,
1330 AINPUT_SOURCE_TOUCHSCREEN)
1331 .deviceId(touchDeviceId)
1332 .downTime(baseTime + 60)
1333 .eventTime(baseTime + 60)
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07001334 .pointer(PointerBuilder(0, ToolType::FINGER).x(300).y(100))
Siarhei Vishniakoue0431e42023-01-28 17:01:39 -08001335 .build()));
1336 rightWindow->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_DOWN));
1337
1338 // release tap
1339 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07001340 injectMotionEvent(*mDispatcher,
Siarhei Vishniakoue0431e42023-01-28 17:01:39 -08001341 MotionEventBuilder(AMOTION_EVENT_ACTION_UP,
1342 AINPUT_SOURCE_TOUCHSCREEN)
1343 .deviceId(touchDeviceId)
1344 .downTime(baseTime + 60)
1345 .eventTime(baseTime + 70)
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07001346 .pointer(PointerBuilder(0, ToolType::FINGER).x(300).y(100))
Siarhei Vishniakoue0431e42023-01-28 17:01:39 -08001347 .build()));
1348 rightWindow->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_UP));
1349
1350 // No more events
1351 leftWindow->assertNoEvents();
1352 rightWindow->assertNoEvents();
1353}
1354
1355/**
Siarhei Vishniakoua235c042023-05-02 09:59:09 -07001356 * Start hovering in a window. While this hover is still active, make another window appear on top.
1357 * The top, obstructing window has no input channel, so it's not supposed to receive input.
1358 * While the top window is present, the hovering is stopped.
1359 * Later, hovering gets resumed again.
1360 * Ensure that new hover gesture is handled correctly.
1361 * This test reproduces a crash where the HOVER_EXIT event wasn't getting dispatched correctly
1362 * to the window that's currently being hovered over.
1363 */
1364TEST_F(InputDispatcherTest, HoverWhileWindowAppears) {
1365 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
1366 sp<FakeWindowHandle> window =
1367 sp<FakeWindowHandle>::make(application, mDispatcher, "Window", ADISPLAY_ID_DEFAULT);
1368 window->setFrame(Rect(0, 0, 200, 200));
1369
1370 // Only a single window is present at first
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07001371 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Siarhei Vishniakoua235c042023-05-02 09:59:09 -07001372
1373 // Start hovering in the window
1374 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_ENTER, AINPUT_SOURCE_STYLUS)
1375 .pointer(PointerBuilder(0, ToolType::STYLUS).x(100).y(100))
1376 .build());
1377 window->consumeMotionEvent(WithMotionAction(ACTION_HOVER_ENTER));
1378
1379 // Now, an obscuring window appears!
1380 sp<FakeWindowHandle> obscuringWindow =
1381 sp<FakeWindowHandle>::make(application, mDispatcher, "Obscuring window",
1382 ADISPLAY_ID_DEFAULT,
Prabir Pradhane7cc69c2024-01-05 21:35:28 +00001383 /*createInputChannel=*/false);
Siarhei Vishniakoua235c042023-05-02 09:59:09 -07001384 obscuringWindow->setFrame(Rect(0, 0, 200, 200));
1385 obscuringWindow->setTouchOcclusionMode(TouchOcclusionMode::BLOCK_UNTRUSTED);
1386 obscuringWindow->setOwnerInfo(SECONDARY_WINDOW_PID, SECONDARY_WINDOW_UID);
1387 obscuringWindow->setNoInputChannel(true);
1388 obscuringWindow->setFocusable(false);
1389 obscuringWindow->setAlpha(1.0);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07001390 mDispatcher->onWindowInfosChanged(
1391 {{*obscuringWindow->getInfo(), *window->getInfo()}, {}, 0, 0});
Siarhei Vishniakoua235c042023-05-02 09:59:09 -07001392
1393 // While this new obscuring window is present, the hovering is stopped
1394 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_EXIT, AINPUT_SOURCE_STYLUS)
1395 .pointer(PointerBuilder(0, ToolType::STYLUS).x(100).y(100))
1396 .build());
1397 window->consumeMotionEvent(WithMotionAction(ACTION_HOVER_EXIT));
1398
1399 // Now the obscuring window goes away.
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07001400 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Siarhei Vishniakoua235c042023-05-02 09:59:09 -07001401
1402 // And a new hover gesture starts.
1403 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_ENTER, AINPUT_SOURCE_STYLUS)
1404 .pointer(PointerBuilder(0, ToolType::STYLUS).x(100).y(100))
1405 .build());
1406 window->consumeMotionEvent(WithMotionAction(ACTION_HOVER_ENTER));
1407}
1408
1409/**
1410 * Same test as 'HoverWhileWindowAppears' above, but here, we also send some HOVER_MOVE events to
1411 * the obscuring window.
1412 */
1413TEST_F(InputDispatcherTest, HoverMoveWhileWindowAppears) {
1414 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
1415 sp<FakeWindowHandle> window =
1416 sp<FakeWindowHandle>::make(application, mDispatcher, "Window", ADISPLAY_ID_DEFAULT);
1417 window->setFrame(Rect(0, 0, 200, 200));
1418
1419 // Only a single window is present at first
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07001420 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Siarhei Vishniakoua235c042023-05-02 09:59:09 -07001421
1422 // Start hovering in the window
1423 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_ENTER, AINPUT_SOURCE_STYLUS)
1424 .pointer(PointerBuilder(0, ToolType::STYLUS).x(100).y(100))
1425 .build());
1426 window->consumeMotionEvent(WithMotionAction(ACTION_HOVER_ENTER));
1427
1428 // Now, an obscuring window appears!
1429 sp<FakeWindowHandle> obscuringWindow =
1430 sp<FakeWindowHandle>::make(application, mDispatcher, "Obscuring window",
1431 ADISPLAY_ID_DEFAULT,
Prabir Pradhane7cc69c2024-01-05 21:35:28 +00001432 /*createInputChannel=*/false);
Siarhei Vishniakoua235c042023-05-02 09:59:09 -07001433 obscuringWindow->setFrame(Rect(0, 0, 200, 200));
1434 obscuringWindow->setTouchOcclusionMode(TouchOcclusionMode::BLOCK_UNTRUSTED);
1435 obscuringWindow->setOwnerInfo(SECONDARY_WINDOW_PID, SECONDARY_WINDOW_UID);
1436 obscuringWindow->setNoInputChannel(true);
1437 obscuringWindow->setFocusable(false);
1438 obscuringWindow->setAlpha(1.0);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07001439 mDispatcher->onWindowInfosChanged(
1440 {{*obscuringWindow->getInfo(), *window->getInfo()}, {}, 0, 0});
Siarhei Vishniakoua235c042023-05-02 09:59:09 -07001441
1442 // While this new obscuring window is present, the hovering continues. The event can't go to the
1443 // bottom window due to obstructed touches, so it should generate HOVER_EXIT for that window.
1444 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_MOVE, AINPUT_SOURCE_STYLUS)
1445 .pointer(PointerBuilder(0, ToolType::STYLUS).x(100).y(100))
1446 .build());
1447 obscuringWindow->assertNoEvents();
1448 window->consumeMotionEvent(WithMotionAction(ACTION_HOVER_EXIT));
1449
1450 // Now the obscuring window goes away.
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07001451 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Siarhei Vishniakoua235c042023-05-02 09:59:09 -07001452
1453 // Hovering continues in the same position. The hovering pointer re-enters the bottom window,
1454 // so it should generate a HOVER_ENTER
1455 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_MOVE, AINPUT_SOURCE_STYLUS)
1456 .pointer(PointerBuilder(0, ToolType::STYLUS).x(100).y(100))
1457 .build());
1458 window->consumeMotionEvent(WithMotionAction(ACTION_HOVER_ENTER));
1459
1460 // Now the MOVE should be getting dispatched normally
1461 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_MOVE, AINPUT_SOURCE_STYLUS)
1462 .pointer(PointerBuilder(0, ToolType::STYLUS).x(110).y(110))
1463 .build());
1464 window->consumeMotionEvent(WithMotionAction(ACTION_HOVER_MOVE));
1465}
1466
1467/**
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -07001468 * Hover mouse over a window, and then send ACTION_SCROLL. Ensure both the hover and the scroll
1469 * events are delivered to the window.
1470 */
1471TEST_F(InputDispatcherTest, HoverMoveAndScroll) {
1472 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
1473 sp<FakeWindowHandle> window =
1474 sp<FakeWindowHandle>::make(application, mDispatcher, "Window", ADISPLAY_ID_DEFAULT);
1475 window->setFrame(Rect(0, 0, 200, 200));
1476 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
1477
1478 // Start hovering in the window
1479 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_ENTER, AINPUT_SOURCE_MOUSE)
1480 .pointer(PointerBuilder(0, ToolType::MOUSE).x(100).y(110))
1481 .build());
1482 window->consumeMotionEvent(WithMotionAction(ACTION_HOVER_ENTER));
1483
1484 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_MOVE, AINPUT_SOURCE_MOUSE)
1485 .pointer(PointerBuilder(0, ToolType::MOUSE).x(110).y(120))
1486 .build());
1487 window->consumeMotionEvent(WithMotionAction(ACTION_HOVER_MOVE));
1488
1489 // Scroll with the mouse
1490 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_SCROLL, AINPUT_SOURCE_MOUSE)
1491 .pointer(PointerBuilder(0, ToolType::MOUSE).x(110).y(120))
1492 .build());
1493 window->consumeMotionEvent(WithMotionAction(ACTION_SCROLL));
1494}
1495
1496using InputDispatcherMultiDeviceTest = InputDispatcherTest;
1497
1498/**
Siarhei Vishniakou2899c552023-07-10 18:20:46 -07001499 * One window. Stylus down on the window. Next, touch from another device goes down. Ensure that
1500 * touch is dropped, because stylus should be preferred over touch.
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -07001501 */
Siarhei Vishniakou2899c552023-07-10 18:20:46 -07001502TEST_F(InputDispatcherMultiDeviceTest, StylusDownBlocksTouchDown) {
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -07001503 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
1504 sp<FakeWindowHandle> window =
1505 sp<FakeWindowHandle>::make(application, mDispatcher, "Window", ADISPLAY_ID_DEFAULT);
1506 window->setFrame(Rect(0, 0, 200, 200));
1507
1508 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
1509
1510 constexpr int32_t touchDeviceId = 4;
1511 constexpr int32_t stylusDeviceId = 2;
1512
1513 // Stylus down
1514 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_STYLUS)
1515 .deviceId(stylusDeviceId)
1516 .pointer(PointerBuilder(0, ToolType::STYLUS).x(100).y(110))
1517 .build());
1518 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(stylusDeviceId)));
1519
1520 // Touch down
1521 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
1522 .deviceId(touchDeviceId)
1523 .pointer(PointerBuilder(0, ToolType::FINGER).x(140).y(145))
1524 .build());
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -07001525
1526 // Touch move
1527 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN)
1528 .deviceId(touchDeviceId)
1529 .pointer(PointerBuilder(0, ToolType::FINGER).x(141).y(146))
1530 .build());
Siarhei Vishniakou2899c552023-07-10 18:20:46 -07001531 // Touch is ignored because stylus is already down
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -07001532
Siarhei Vishniakou2899c552023-07-10 18:20:46 -07001533 // Subsequent stylus movements are delivered correctly
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -07001534 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_STYLUS)
1535 .deviceId(stylusDeviceId)
1536 .pointer(PointerBuilder(0, ToolType::STYLUS).x(101).y(111))
1537 .build());
Siarhei Vishniakou2899c552023-07-10 18:20:46 -07001538 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(stylusDeviceId),
1539 WithCoords(101, 111)));
1540
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -07001541 window->assertNoEvents();
1542}
1543
1544/**
1545 * One window and one spy window. Stylus down on the window. Next, touch from another device goes
Siarhei Vishniakou2899c552023-07-10 18:20:46 -07001546 * down. Ensure that touch is dropped, because stylus should be preferred over touch.
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -07001547 * Similar test as above, but with added SPY window.
1548 */
Siarhei Vishniakou2899c552023-07-10 18:20:46 -07001549TEST_F(InputDispatcherMultiDeviceTest, StylusDownWithSpyBlocksTouchDown) {
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -07001550 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
1551 sp<FakeWindowHandle> window =
1552 sp<FakeWindowHandle>::make(application, mDispatcher, "Window", ADISPLAY_ID_DEFAULT);
1553 sp<FakeWindowHandle> spyWindow =
1554 sp<FakeWindowHandle>::make(application, mDispatcher, "Spy", ADISPLAY_ID_DEFAULT);
1555 spyWindow->setFrame(Rect(0, 0, 200, 200));
1556 spyWindow->setTrustedOverlay(true);
1557 spyWindow->setSpy(true);
1558 window->setFrame(Rect(0, 0, 200, 200));
1559
1560 mDispatcher->onWindowInfosChanged({{*spyWindow->getInfo(), *window->getInfo()}, {}, 0, 0});
1561
1562 constexpr int32_t touchDeviceId = 4;
1563 constexpr int32_t stylusDeviceId = 2;
1564
1565 // Stylus down
1566 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_STYLUS)
1567 .deviceId(stylusDeviceId)
1568 .pointer(PointerBuilder(0, ToolType::STYLUS).x(100).y(110))
1569 .build());
1570 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(stylusDeviceId)));
1571 spyWindow->consumeMotionEvent(
1572 AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(stylusDeviceId)));
1573
1574 // Touch down
1575 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
1576 .deviceId(touchDeviceId)
1577 .pointer(PointerBuilder(0, ToolType::FINGER).x(140).y(145))
1578 .build());
1579
1580 // Touch move
1581 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN)
1582 .deviceId(touchDeviceId)
1583 .pointer(PointerBuilder(0, ToolType::FINGER).x(141).y(146))
1584 .build());
Siarhei Vishniakou2899c552023-07-10 18:20:46 -07001585
1586 // Touch is ignored because stylus is already down
1587
1588 // Subsequent stylus movements are delivered correctly
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -07001589 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_STYLUS)
1590 .deviceId(stylusDeviceId)
1591 .pointer(PointerBuilder(0, ToolType::STYLUS).x(101).y(111))
1592 .build());
Siarhei Vishniakou2899c552023-07-10 18:20:46 -07001593 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(stylusDeviceId),
1594 WithCoords(101, 111)));
1595 spyWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(stylusDeviceId),
1596 WithCoords(101, 111)));
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -07001597
1598 window->assertNoEvents();
1599 spyWindow->assertNoEvents();
1600}
1601
1602/**
Siarhei Vishniakou2899c552023-07-10 18:20:46 -07001603 * One window. Stylus hover on the window. Next, touch from another device goes down. Ensure that
Siarhei Vishniakou3ad54f52023-11-02 16:54:40 -07001604 * touch is dropped, because stylus hover takes precedence.
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -07001605 */
Siarhei Vishniakou3ad54f52023-11-02 16:54:40 -07001606TEST_F(InputDispatcherMultiDeviceTest, StylusHoverBlocksTouchDown) {
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -07001607 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
1608 sp<FakeWindowHandle> window =
1609 sp<FakeWindowHandle>::make(application, mDispatcher, "Window", ADISPLAY_ID_DEFAULT);
1610 window->setFrame(Rect(0, 0, 200, 200));
1611
1612 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
1613
1614 constexpr int32_t touchDeviceId = 4;
1615 constexpr int32_t stylusDeviceId = 2;
1616
1617 // Stylus down on the window
1618 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_ENTER, AINPUT_SOURCE_STYLUS)
1619 .deviceId(stylusDeviceId)
1620 .pointer(PointerBuilder(0, ToolType::STYLUS).x(100).y(110))
1621 .build());
1622 window->consumeMotionEvent(
1623 AllOf(WithMotionAction(ACTION_HOVER_ENTER), WithDeviceId(stylusDeviceId)));
1624
1625 // Touch down on window
1626 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
1627 .deviceId(touchDeviceId)
1628 .pointer(PointerBuilder(0, ToolType::FINGER).x(140).y(145))
1629 .build());
1630 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN)
1631 .deviceId(touchDeviceId)
1632 .pointer(PointerBuilder(0, ToolType::FINGER).x(141).y(146))
1633 .build());
Siarhei Vishniakou2899c552023-07-10 18:20:46 -07001634
Siarhei Vishniakou3ad54f52023-11-02 16:54:40 -07001635 // Touch is ignored because stylus is hovering
Siarhei Vishniakou2899c552023-07-10 18:20:46 -07001636
Siarhei Vishniakou3ad54f52023-11-02 16:54:40 -07001637 // Subsequent stylus movements are delivered correctly
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -07001638 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_MOVE, AINPUT_SOURCE_STYLUS)
1639 .deviceId(stylusDeviceId)
1640 .pointer(PointerBuilder(0, ToolType::STYLUS).x(101).y(111))
1641 .build());
Siarhei Vishniakou3ad54f52023-11-02 16:54:40 -07001642 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_HOVER_MOVE),
1643 WithDeviceId(stylusDeviceId), WithCoords(101, 111)));
Siarhei Vishniakou2899c552023-07-10 18:20:46 -07001644
Siarhei Vishniakou3ad54f52023-11-02 16:54:40 -07001645 // and subsequent touches continue to be ignored
Siarhei Vishniakou2899c552023-07-10 18:20:46 -07001646 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN)
1647 .deviceId(touchDeviceId)
1648 .pointer(PointerBuilder(0, ToolType::FINGER).x(142).y(147))
1649 .build());
Siarhei Vishniakou3ad54f52023-11-02 16:54:40 -07001650 window->assertNoEvents();
Siarhei Vishniakou2899c552023-07-10 18:20:46 -07001651}
1652
1653/**
1654 * One window. Touch down on the window. Then, stylus hover on the window from another device.
Siarhei Vishniakou3ad54f52023-11-02 16:54:40 -07001655 * Ensure that touch is canceled, because stylus hover should take precedence.
Siarhei Vishniakou2899c552023-07-10 18:20:46 -07001656 */
Siarhei Vishniakou3ad54f52023-11-02 16:54:40 -07001657TEST_F(InputDispatcherMultiDeviceTest, TouchIsCanceledByStylusHover) {
Siarhei Vishniakou2899c552023-07-10 18:20:46 -07001658 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
1659 sp<FakeWindowHandle> window =
1660 sp<FakeWindowHandle>::make(application, mDispatcher, "Window", ADISPLAY_ID_DEFAULT);
1661 window->setFrame(Rect(0, 0, 200, 200));
1662
1663 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
1664
1665 constexpr int32_t touchDeviceId = 4;
1666 constexpr int32_t stylusDeviceId = 2;
1667
1668 // Touch down on window
1669 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
1670 .deviceId(touchDeviceId)
1671 .pointer(PointerBuilder(0, ToolType::FINGER).x(140).y(145))
1672 .build());
1673 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN)
1674 .deviceId(touchDeviceId)
1675 .pointer(PointerBuilder(0, ToolType::FINGER).x(141).y(146))
1676 .build());
1677 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(touchDeviceId)));
1678 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(touchDeviceId)));
1679
1680 // Stylus hover on the window
1681 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_ENTER, AINPUT_SOURCE_STYLUS)
1682 .deviceId(stylusDeviceId)
1683 .pointer(PointerBuilder(0, ToolType::STYLUS).x(100).y(110))
1684 .build());
1685 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_MOVE, AINPUT_SOURCE_STYLUS)
1686 .deviceId(stylusDeviceId)
1687 .pointer(PointerBuilder(0, ToolType::STYLUS).x(101).y(111))
1688 .build());
Siarhei Vishniakou3ad54f52023-11-02 16:54:40 -07001689 // Stylus hover movement causes touch to be canceled
1690 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_CANCEL), WithDeviceId(touchDeviceId),
1691 WithCoords(141, 146)));
1692 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_HOVER_ENTER),
1693 WithDeviceId(stylusDeviceId), WithCoords(100, 110)));
1694 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_HOVER_MOVE),
1695 WithDeviceId(stylusDeviceId), WithCoords(101, 111)));
Siarhei Vishniakou2899c552023-07-10 18:20:46 -07001696
Siarhei Vishniakou3ad54f52023-11-02 16:54:40 -07001697 // Subsequent touch movements are ignored
Siarhei Vishniakou2899c552023-07-10 18:20:46 -07001698 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN)
1699 .deviceId(touchDeviceId)
1700 .pointer(PointerBuilder(0, ToolType::FINGER).x(142).y(147))
1701 .build());
Siarhei Vishniakou3ad54f52023-11-02 16:54:40 -07001702
1703 window->assertNoEvents();
Siarhei Vishniakou2899c552023-07-10 18:20:46 -07001704}
1705
1706/**
1707 * One window. Stylus down on the window. Then, stylus from another device goes down. Ensure that
1708 * the latest stylus takes over. That is, old stylus should be canceled and the new stylus should
1709 * become active.
1710 */
1711TEST_F(InputDispatcherMultiDeviceTest, LatestStylusWins) {
1712 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
1713 sp<FakeWindowHandle> window =
1714 sp<FakeWindowHandle>::make(application, mDispatcher, "Window", ADISPLAY_ID_DEFAULT);
1715 window->setFrame(Rect(0, 0, 200, 200));
1716
1717 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
1718
1719 constexpr int32_t stylusDeviceId1 = 3;
1720 constexpr int32_t stylusDeviceId2 = 5;
1721
1722 // Touch down on window
1723 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_STYLUS)
1724 .deviceId(stylusDeviceId1)
1725 .pointer(PointerBuilder(0, ToolType::STYLUS).x(99).y(100))
1726 .build());
1727 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_STYLUS)
1728 .deviceId(stylusDeviceId1)
1729 .pointer(PointerBuilder(0, ToolType::STYLUS).x(100).y(101))
1730 .build());
1731 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(stylusDeviceId1)));
1732 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(stylusDeviceId1)));
1733
1734 // Second stylus down
1735 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_STYLUS)
1736 .deviceId(stylusDeviceId2)
1737 .pointer(PointerBuilder(0, ToolType::STYLUS).x(9).y(10))
1738 .build());
1739 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_STYLUS)
1740 .deviceId(stylusDeviceId2)
1741 .pointer(PointerBuilder(0, ToolType::STYLUS).x(10).y(11))
1742 .build());
1743
1744 // First stylus is canceled, second one takes over.
1745 window->consumeMotionEvent(
1746 AllOf(WithMotionAction(ACTION_CANCEL), WithDeviceId(stylusDeviceId1)));
1747 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(stylusDeviceId2)));
1748 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(stylusDeviceId2)));
1749
1750 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_STYLUS)
1751 .deviceId(stylusDeviceId1)
1752 .pointer(PointerBuilder(0, ToolType::STYLUS).x(101).y(102))
1753 .build());
1754 // Subsequent stylus movements are delivered correctly
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -07001755 window->assertNoEvents();
1756}
1757
1758/**
Siarhei Vishniakou2899c552023-07-10 18:20:46 -07001759 * One window. Touch down on the window. Then, stylus down on the window from another device.
1760 * Ensure that is canceled, because stylus down should be preferred over touch.
1761 */
1762TEST_F(InputDispatcherMultiDeviceTest, TouchIsCanceledByStylusDown) {
1763 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
1764 sp<FakeWindowHandle> window =
1765 sp<FakeWindowHandle>::make(application, mDispatcher, "Window", ADISPLAY_ID_DEFAULT);
1766 window->setFrame(Rect(0, 0, 200, 200));
1767
1768 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
1769
1770 constexpr int32_t touchDeviceId = 4;
1771 constexpr int32_t stylusDeviceId = 2;
1772
1773 // Touch down on window
1774 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
1775 .deviceId(touchDeviceId)
1776 .pointer(PointerBuilder(0, ToolType::FINGER).x(140).y(145))
1777 .build());
1778 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN)
1779 .deviceId(touchDeviceId)
1780 .pointer(PointerBuilder(0, ToolType::FINGER).x(141).y(146))
1781 .build());
1782 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(touchDeviceId)));
1783 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(touchDeviceId)));
1784
1785 // Stylus down on the window
1786 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_STYLUS)
1787 .deviceId(stylusDeviceId)
1788 .pointer(PointerBuilder(0, ToolType::STYLUS).x(100).y(110))
1789 .build());
1790 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_CANCEL), WithDeviceId(touchDeviceId)));
1791 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(stylusDeviceId)));
1792
1793 // Subsequent stylus movements are delivered correctly
1794 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_STYLUS)
1795 .deviceId(stylusDeviceId)
1796 .pointer(PointerBuilder(0, ToolType::STYLUS).x(101).y(111))
1797 .build());
1798 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(stylusDeviceId),
1799 WithCoords(101, 111)));
1800}
1801
1802/**
Siarhei Vishniakouf372b812023-02-14 18:06:51 -08001803 * Two windows: a window on the left and a window on the right.
1804 * Mouse is clicked on the left window and remains down. Touch is touched on the right and remains
1805 * down. Then, on the left window, also place second touch pointer down.
1806 * This test tries to reproduce a crash.
1807 * In the buggy implementation, second pointer down on the left window would cause a crash.
1808 */
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -07001809TEST_F(InputDispatcherMultiDeviceTest, MultiDeviceSplitTouch) {
Siarhei Vishniakouf372b812023-02-14 18:06:51 -08001810 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
1811 sp<FakeWindowHandle> leftWindow =
1812 sp<FakeWindowHandle>::make(application, mDispatcher, "Left", ADISPLAY_ID_DEFAULT);
1813 leftWindow->setFrame(Rect(0, 0, 200, 200));
1814
1815 sp<FakeWindowHandle> rightWindow =
1816 sp<FakeWindowHandle>::make(application, mDispatcher, "Right", ADISPLAY_ID_DEFAULT);
1817 rightWindow->setFrame(Rect(200, 0, 400, 200));
1818
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07001819 mDispatcher->onWindowInfosChanged(
1820 {{*leftWindow->getInfo(), *rightWindow->getInfo()}, {}, 0, 0});
Siarhei Vishniakouf372b812023-02-14 18:06:51 -08001821
1822 const int32_t touchDeviceId = 4;
1823 const int32_t mouseDeviceId = 6;
Siarhei Vishniakouf372b812023-02-14 18:06:51 -08001824
1825 // Start hovering over the left window
Prabir Pradhan678438e2023-04-13 19:32:51 +00001826 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_ENTER, AINPUT_SOURCE_MOUSE)
1827 .deviceId(mouseDeviceId)
1828 .pointer(PointerBuilder(0, ToolType::MOUSE).x(100).y(100))
1829 .build());
Siarhei Vishniakouf372b812023-02-14 18:06:51 -08001830 leftWindow->consumeMotionEvent(
1831 AllOf(WithMotionAction(ACTION_HOVER_ENTER), WithDeviceId(mouseDeviceId)));
1832
1833 // Mouse down on left window
Prabir Pradhan678438e2023-04-13 19:32:51 +00001834 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_MOUSE)
1835 .deviceId(mouseDeviceId)
1836 .buttonState(AMOTION_EVENT_BUTTON_PRIMARY)
1837 .pointer(PointerBuilder(0, ToolType::MOUSE).x(100).y(100))
1838 .build());
Siarhei Vishniakouf372b812023-02-14 18:06:51 -08001839
1840 leftWindow->consumeMotionEvent(
1841 AllOf(WithMotionAction(ACTION_HOVER_EXIT), WithDeviceId(mouseDeviceId)));
1842 leftWindow->consumeMotionEvent(
1843 AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(mouseDeviceId)));
1844
Prabir Pradhan678438e2023-04-13 19:32:51 +00001845 mDispatcher->notifyMotion(
1846 MotionArgsBuilder(AMOTION_EVENT_ACTION_BUTTON_PRESS, AINPUT_SOURCE_MOUSE)
1847 .deviceId(mouseDeviceId)
1848 .buttonState(AMOTION_EVENT_BUTTON_PRIMARY)
1849 .actionButton(AMOTION_EVENT_BUTTON_PRIMARY)
1850 .pointer(PointerBuilder(0, ToolType::MOUSE).x(100).y(100))
1851 .build());
Siarhei Vishniakouf372b812023-02-14 18:06:51 -08001852 leftWindow->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_BUTTON_PRESS));
1853
1854 // First touch pointer down on right window
Prabir Pradhan678438e2023-04-13 19:32:51 +00001855 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
1856 .deviceId(touchDeviceId)
1857 .pointer(PointerBuilder(0, ToolType::FINGER).x(300).y(100))
1858 .build());
Siarhei Vishniakou2899c552023-07-10 18:20:46 -07001859 leftWindow->assertNoEvents();
1860
Siarhei Vishniakouf372b812023-02-14 18:06:51 -08001861 rightWindow->consumeMotionEvent(WithMotionAction(ACTION_DOWN));
1862
1863 // Second touch pointer down on left window
Prabir Pradhan678438e2023-04-13 19:32:51 +00001864 mDispatcher->notifyMotion(MotionArgsBuilder(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
1865 .deviceId(touchDeviceId)
1866 .pointer(PointerBuilder(0, ToolType::FINGER).x(300).y(100))
1867 .pointer(PointerBuilder(1, ToolType::FINGER).x(100).y(100))
1868 .build());
Siarhei Vishniakou2899c552023-07-10 18:20:46 -07001869 // Since this is now a new splittable pointer going down on the left window, and it's coming
1870 // from a different device, the current gesture in the left window (pointer down) should first
1871 // be canceled.
1872 leftWindow->consumeMotionEvent(
1873 AllOf(WithMotionAction(ACTION_CANCEL), WithDeviceId(mouseDeviceId)));
Siarhei Vishniakouf372b812023-02-14 18:06:51 -08001874 leftWindow->consumeMotionEvent(
1875 AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(touchDeviceId)));
1876 // This MOVE event is not necessary (doesn't carry any new information), but it's there in the
1877 // current implementation.
1878 const std::map<int32_t, PointF> expectedPointers{{0, PointF{100, 100}}};
1879 rightWindow->consumeMotionEvent(
1880 AllOf(WithMotionAction(ACTION_MOVE), WithPointers(expectedPointers)));
1881
1882 leftWindow->assertNoEvents();
1883 rightWindow->assertNoEvents();
1884}
1885
1886/**
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -07001887 * Two windows: a window on the left and a window on the right.
1888 * Mouse is hovered on the left window and stylus is hovered on the right window.
1889 */
1890TEST_F(InputDispatcherMultiDeviceTest, MultiDeviceHover) {
1891 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
1892 sp<FakeWindowHandle> leftWindow =
1893 sp<FakeWindowHandle>::make(application, mDispatcher, "Left", ADISPLAY_ID_DEFAULT);
1894 leftWindow->setFrame(Rect(0, 0, 200, 200));
1895
1896 sp<FakeWindowHandle> rightWindow =
1897 sp<FakeWindowHandle>::make(application, mDispatcher, "Right", ADISPLAY_ID_DEFAULT);
1898 rightWindow->setFrame(Rect(200, 0, 400, 200));
1899
1900 mDispatcher->onWindowInfosChanged(
1901 {{*leftWindow->getInfo(), *rightWindow->getInfo()}, {}, 0, 0});
1902
1903 const int32_t stylusDeviceId = 3;
1904 const int32_t mouseDeviceId = 6;
1905
1906 // Start hovering over the left window
1907 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_ENTER, AINPUT_SOURCE_MOUSE)
1908 .deviceId(mouseDeviceId)
1909 .pointer(PointerBuilder(0, ToolType::MOUSE).x(100).y(110))
1910 .build());
1911 leftWindow->consumeMotionEvent(
1912 AllOf(WithMotionAction(ACTION_HOVER_ENTER), WithDeviceId(mouseDeviceId)));
1913
1914 // Stylus hovered on right window
1915 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_ENTER, AINPUT_SOURCE_STYLUS)
1916 .deviceId(stylusDeviceId)
1917 .pointer(PointerBuilder(0, ToolType::STYLUS).x(300).y(100))
1918 .build());
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -07001919 rightWindow->consumeMotionEvent(
1920 AllOf(WithMotionAction(ACTION_HOVER_ENTER), WithDeviceId(stylusDeviceId)));
1921
1922 // Subsequent HOVER_MOVE events are dispatched correctly.
1923 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_MOVE, AINPUT_SOURCE_MOUSE)
1924 .deviceId(mouseDeviceId)
1925 .pointer(PointerBuilder(0, ToolType::MOUSE).x(110).y(120))
1926 .build());
1927 leftWindow->consumeMotionEvent(
Siarhei Vishniakou2899c552023-07-10 18:20:46 -07001928 AllOf(WithMotionAction(ACTION_HOVER_MOVE), WithDeviceId(mouseDeviceId)));
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -07001929
1930 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_MOVE, AINPUT_SOURCE_STYLUS)
1931 .deviceId(stylusDeviceId)
1932 .pointer(PointerBuilder(0, ToolType::STYLUS).x(310).y(110))
1933 .build());
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -07001934 rightWindow->consumeMotionEvent(
Siarhei Vishniakou2899c552023-07-10 18:20:46 -07001935 AllOf(WithMotionAction(ACTION_HOVER_MOVE), WithDeviceId(stylusDeviceId)));
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -07001936
1937 leftWindow->assertNoEvents();
1938 rightWindow->assertNoEvents();
1939}
1940
1941/**
1942 * Three windows: a window on the left and a window on the right.
1943 * And a spy window that's positioned above all of them.
1944 * Stylus down on the left window and remains down. Touch goes down on the right and remains down.
1945 * Check the stream that's received by the spy.
1946 */
1947TEST_F(InputDispatcherMultiDeviceTest, MultiDeviceWithSpy) {
1948 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
1949
1950 sp<FakeWindowHandle> spyWindow =
1951 sp<FakeWindowHandle>::make(application, mDispatcher, "Spy", ADISPLAY_ID_DEFAULT);
1952 spyWindow->setFrame(Rect(0, 0, 400, 400));
1953 spyWindow->setTrustedOverlay(true);
1954 spyWindow->setSpy(true);
1955
1956 sp<FakeWindowHandle> leftWindow =
1957 sp<FakeWindowHandle>::make(application, mDispatcher, "Left", ADISPLAY_ID_DEFAULT);
1958 leftWindow->setFrame(Rect(0, 0, 200, 200));
1959
1960 sp<FakeWindowHandle> rightWindow =
1961 sp<FakeWindowHandle>::make(application, mDispatcher, "Right", ADISPLAY_ID_DEFAULT);
1962
1963 rightWindow->setFrame(Rect(200, 0, 400, 200));
1964
1965 mDispatcher->onWindowInfosChanged(
1966 {{*spyWindow->getInfo(), *leftWindow->getInfo(), *rightWindow->getInfo()}, {}, 0, 0});
1967
1968 const int32_t stylusDeviceId = 1;
1969 const int32_t touchDeviceId = 2;
1970
1971 // Stylus down on the left window
1972 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_STYLUS)
1973 .deviceId(stylusDeviceId)
1974 .pointer(PointerBuilder(0, ToolType::STYLUS).x(100).y(100))
1975 .build());
1976 leftWindow->consumeMotionEvent(
1977 AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(stylusDeviceId)));
1978 spyWindow->consumeMotionEvent(
1979 AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(stylusDeviceId)));
1980
1981 // Touch down on the right window
1982 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
1983 .deviceId(touchDeviceId)
1984 .pointer(PointerBuilder(0, ToolType::FINGER).x(300).y(100))
1985 .build());
Siarhei Vishniakou2899c552023-07-10 18:20:46 -07001986 leftWindow->assertNoEvents();
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -07001987 rightWindow->consumeMotionEvent(
1988 AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(touchDeviceId)));
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -07001989
Siarhei Vishniakou2899c552023-07-10 18:20:46 -07001990 // Spy window does not receive touch events, because stylus events take precedence, and it
1991 // already has an active stylus gesture.
1992
1993 // Stylus movements continue. They should be delivered to the left window and to the spy window
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -07001994 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_STYLUS)
1995 .deviceId(stylusDeviceId)
1996 .pointer(PointerBuilder(0, ToolType::STYLUS).x(110).y(110))
1997 .build());
Siarhei Vishniakou2899c552023-07-10 18:20:46 -07001998 leftWindow->consumeMotionEvent(
1999 AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(stylusDeviceId)));
2000 spyWindow->consumeMotionEvent(
2001 AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(stylusDeviceId)));
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -07002002
Siarhei Vishniakou2899c552023-07-10 18:20:46 -07002003 // Further MOVE events keep going to the right window only
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -07002004 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN)
2005 .deviceId(touchDeviceId)
2006 .pointer(PointerBuilder(0, ToolType::FINGER).x(310).y(110))
2007 .build());
2008 rightWindow->consumeMotionEvent(
2009 AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(touchDeviceId)));
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -07002010
2011 spyWindow->assertNoEvents();
2012 leftWindow->assertNoEvents();
2013 rightWindow->assertNoEvents();
2014}
2015
2016/**
2017 * Three windows: a window on the left, a window on the right, and a spy window positioned above
2018 * both.
2019 * Check hover in left window and touch down in the right window.
Siarhei Vishniakou3ad54f52023-11-02 16:54:40 -07002020 * At first, spy should receive hover. Spy shouldn't receive touch while stylus is hovering.
Siarhei Vishniakou2899c552023-07-10 18:20:46 -07002021 * At the same time, left and right should be getting independent streams of hovering and touch,
2022 * respectively.
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -07002023 */
Siarhei Vishniakou3ad54f52023-11-02 16:54:40 -07002024TEST_F(InputDispatcherMultiDeviceTest, MultiDeviceHoverBlocksTouchWithSpy) {
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -07002025 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
2026
2027 sp<FakeWindowHandle> spyWindow =
2028 sp<FakeWindowHandle>::make(application, mDispatcher, "Spy", ADISPLAY_ID_DEFAULT);
2029 spyWindow->setFrame(Rect(0, 0, 400, 400));
2030 spyWindow->setTrustedOverlay(true);
2031 spyWindow->setSpy(true);
2032
2033 sp<FakeWindowHandle> leftWindow =
2034 sp<FakeWindowHandle>::make(application, mDispatcher, "Left", ADISPLAY_ID_DEFAULT);
2035 leftWindow->setFrame(Rect(0, 0, 200, 200));
2036
2037 sp<FakeWindowHandle> rightWindow =
2038 sp<FakeWindowHandle>::make(application, mDispatcher, "Right", ADISPLAY_ID_DEFAULT);
2039 rightWindow->setFrame(Rect(200, 0, 400, 200));
2040
2041 mDispatcher->onWindowInfosChanged(
2042 {{*spyWindow->getInfo(), *leftWindow->getInfo(), *rightWindow->getInfo()}, {}, 0, 0});
2043
2044 const int32_t stylusDeviceId = 1;
2045 const int32_t touchDeviceId = 2;
2046
2047 // Stylus hover on the left window
2048 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_ENTER, AINPUT_SOURCE_STYLUS)
2049 .deviceId(stylusDeviceId)
2050 .pointer(PointerBuilder(0, ToolType::STYLUS).x(100).y(100))
2051 .build());
2052 leftWindow->consumeMotionEvent(
2053 AllOf(WithMotionAction(ACTION_HOVER_ENTER), WithDeviceId(stylusDeviceId)));
2054 spyWindow->consumeMotionEvent(
2055 AllOf(WithMotionAction(ACTION_HOVER_ENTER), WithDeviceId(stylusDeviceId)));
2056
Siarhei Vishniakou2899c552023-07-10 18:20:46 -07002057 // Touch down on the right window. Spy doesn't receive this touch because it already has
2058 // stylus hovering there.
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -07002059 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
2060 .deviceId(touchDeviceId)
2061 .pointer(PointerBuilder(0, ToolType::FINGER).x(300).y(100))
2062 .build());
Siarhei Vishniakou2899c552023-07-10 18:20:46 -07002063 leftWindow->assertNoEvents();
Siarhei Vishniakou3ad54f52023-11-02 16:54:40 -07002064 spyWindow->assertNoEvents();
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -07002065 rightWindow->consumeMotionEvent(
2066 AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(touchDeviceId)));
2067
Siarhei Vishniakou3ad54f52023-11-02 16:54:40 -07002068 // Stylus movements continue. They should be delivered to the left window and the spy.
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -07002069 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_MOVE, AINPUT_SOURCE_STYLUS)
2070 .deviceId(stylusDeviceId)
2071 .pointer(PointerBuilder(0, ToolType::STYLUS).x(110).y(110))
2072 .build());
Siarhei Vishniakou2899c552023-07-10 18:20:46 -07002073 leftWindow->consumeMotionEvent(
2074 AllOf(WithMotionAction(ACTION_HOVER_MOVE), WithDeviceId(stylusDeviceId)));
Siarhei Vishniakou3ad54f52023-11-02 16:54:40 -07002075 spyWindow->consumeMotionEvent(
2076 AllOf(WithMotionAction(ACTION_HOVER_MOVE), WithDeviceId(stylusDeviceId)));
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -07002077
Siarhei Vishniakou3ad54f52023-11-02 16:54:40 -07002078 // Touch movements continue. They should be delivered to the right window only
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -07002079 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN)
2080 .deviceId(touchDeviceId)
2081 .pointer(PointerBuilder(0, ToolType::FINGER).x(301).y(101))
2082 .build());
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -07002083 rightWindow->consumeMotionEvent(
2084 AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(touchDeviceId)));
2085
2086 spyWindow->assertNoEvents();
2087 leftWindow->assertNoEvents();
2088 rightWindow->assertNoEvents();
2089}
2090
2091/**
Siarhei Vishniakouf372b812023-02-14 18:06:51 -08002092 * On a single window, use two different devices: mouse and touch.
2093 * Touch happens first, with two pointers going down, and then the first pointer leaving.
2094 * Mouse is clicked next, which causes the touch stream to be aborted with ACTION_CANCEL.
2095 * Finally, a second touch pointer goes down again. Ensure the second touch pointer is ignored,
2096 * because the mouse is currently down, and a POINTER_DOWN event from the touchscreen does not
2097 * represent a new gesture.
2098 */
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -07002099TEST_F(InputDispatcherMultiDeviceTest, MixedTouchAndMouseWithPointerDown) {
Siarhei Vishniakouf372b812023-02-14 18:06:51 -08002100 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
2101 sp<FakeWindowHandle> window =
2102 sp<FakeWindowHandle>::make(application, mDispatcher, "Window", ADISPLAY_ID_DEFAULT);
2103 window->setFrame(Rect(0, 0, 400, 400));
2104
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07002105 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Siarhei Vishniakouf372b812023-02-14 18:06:51 -08002106
2107 const int32_t touchDeviceId = 4;
2108 const int32_t mouseDeviceId = 6;
Siarhei Vishniakouf372b812023-02-14 18:06:51 -08002109
Siarhei Vishniakou4e1ffa52023-02-21 11:50:34 -08002110 // First touch pointer down
Prabir Pradhan678438e2023-04-13 19:32:51 +00002111 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
2112 .deviceId(touchDeviceId)
2113 .pointer(PointerBuilder(0, ToolType::FINGER).x(300).y(100))
2114 .build());
Siarhei Vishniakouf372b812023-02-14 18:06:51 -08002115 // Second touch pointer down
Prabir Pradhan678438e2023-04-13 19:32:51 +00002116 mDispatcher->notifyMotion(MotionArgsBuilder(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
2117 .deviceId(touchDeviceId)
2118 .pointer(PointerBuilder(0, ToolType::FINGER).x(300).y(100))
2119 .pointer(PointerBuilder(1, ToolType::FINGER).x(350).y(100))
2120 .build());
Siarhei Vishniakouf372b812023-02-14 18:06:51 -08002121 // First touch pointer lifts. The second one remains down
Prabir Pradhan678438e2023-04-13 19:32:51 +00002122 mDispatcher->notifyMotion(MotionArgsBuilder(POINTER_0_UP, AINPUT_SOURCE_TOUCHSCREEN)
2123 .deviceId(touchDeviceId)
2124 .pointer(PointerBuilder(0, ToolType::FINGER).x(300).y(100))
2125 .pointer(PointerBuilder(1, ToolType::FINGER).x(350).y(100))
2126 .build());
Siarhei Vishniakouf372b812023-02-14 18:06:51 -08002127 window->consumeMotionEvent(WithMotionAction(ACTION_DOWN));
2128 window->consumeMotionEvent(WithMotionAction(POINTER_1_DOWN));
2129 window->consumeMotionEvent(WithMotionAction(POINTER_0_UP));
2130
2131 // Mouse down. The touch should be canceled
Prabir Pradhan678438e2023-04-13 19:32:51 +00002132 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_MOUSE)
2133 .deviceId(mouseDeviceId)
2134 .buttonState(AMOTION_EVENT_BUTTON_PRIMARY)
2135 .pointer(PointerBuilder(0, ToolType::MOUSE).x(320).y(100))
2136 .build());
Siarhei Vishniakouf372b812023-02-14 18:06:51 -08002137
2138 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_CANCEL), WithDeviceId(touchDeviceId),
Siarhei Vishniakou82dc0422023-02-17 23:12:52 -08002139 WithPointerCount(1u)));
Siarhei Vishniakouf372b812023-02-14 18:06:51 -08002140 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(mouseDeviceId)));
2141
Prabir Pradhan678438e2023-04-13 19:32:51 +00002142 mDispatcher->notifyMotion(
2143 MotionArgsBuilder(AMOTION_EVENT_ACTION_BUTTON_PRESS, AINPUT_SOURCE_MOUSE)
2144 .deviceId(mouseDeviceId)
2145 .buttonState(AMOTION_EVENT_BUTTON_PRIMARY)
2146 .actionButton(AMOTION_EVENT_BUTTON_PRIMARY)
2147 .pointer(PointerBuilder(0, ToolType::MOUSE).x(320).y(100))
2148 .build());
Siarhei Vishniakouf372b812023-02-14 18:06:51 -08002149 window->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_BUTTON_PRESS));
2150
2151 // Second touch pointer down.
Prabir Pradhan678438e2023-04-13 19:32:51 +00002152 mDispatcher->notifyMotion(MotionArgsBuilder(POINTER_0_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
2153 .deviceId(touchDeviceId)
2154 .pointer(PointerBuilder(0, ToolType::FINGER).x(300).y(100))
2155 .pointer(PointerBuilder(1, ToolType::FINGER).x(350).y(100))
2156 .build());
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -07002157 // Since we already canceled this touch gesture, it will be ignored until a completely new
2158 // gesture is started. This is easier to implement than trying to keep track of the new pointer
2159 // and generating an ACTION_DOWN instead of ACTION_POINTER_DOWN.
2160 // However, mouse movements should continue to work.
2161 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_MOUSE)
2162 .deviceId(mouseDeviceId)
2163 .buttonState(AMOTION_EVENT_BUTTON_PRIMARY)
2164 .pointer(PointerBuilder(0, ToolType::MOUSE).x(330).y(110))
2165 .build());
2166 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(mouseDeviceId)));
2167
Siarhei Vishniakouf372b812023-02-14 18:06:51 -08002168 window->assertNoEvents();
2169}
2170
2171/**
Siarhei Vishniakou56e79092023-02-21 19:13:16 -08002172 * Inject a touch down and then send a new event via 'notifyMotion'. Ensure the new event cancels
2173 * the injected event.
2174 */
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -07002175TEST_F(InputDispatcherMultiDeviceTest, UnfinishedInjectedEvent) {
Siarhei Vishniakou56e79092023-02-21 19:13:16 -08002176 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
2177 sp<FakeWindowHandle> window =
2178 sp<FakeWindowHandle>::make(application, mDispatcher, "Window", ADISPLAY_ID_DEFAULT);
2179 window->setFrame(Rect(0, 0, 400, 400));
2180
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07002181 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Siarhei Vishniakou56e79092023-02-21 19:13:16 -08002182
2183 const int32_t touchDeviceId = 4;
Siarhei Vishniakou56e79092023-02-21 19:13:16 -08002184 // Pretend a test injects an ACTION_DOWN mouse event, but forgets to lift up the touch after
2185 // completion.
2186 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07002187 injectMotionEvent(*mDispatcher,
Siarhei Vishniakou56e79092023-02-21 19:13:16 -08002188 MotionEventBuilder(ACTION_DOWN, AINPUT_SOURCE_MOUSE)
2189 .deviceId(ReservedInputDeviceId::VIRTUAL_KEYBOARD_ID)
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07002190 .pointer(PointerBuilder(0, ToolType::MOUSE).x(50).y(50))
Siarhei Vishniakou56e79092023-02-21 19:13:16 -08002191 .build()));
2192 window->consumeMotionEvent(
2193 AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(VIRTUAL_KEYBOARD_ID)));
2194
2195 // Now a real touch comes. Rather than crashing or dropping the real event, the injected pointer
2196 // should be canceled and the new gesture should take over.
Prabir Pradhan678438e2023-04-13 19:32:51 +00002197 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
2198 .deviceId(touchDeviceId)
2199 .pointer(PointerBuilder(0, ToolType::FINGER).x(300).y(100))
2200 .build());
Siarhei Vishniakou56e79092023-02-21 19:13:16 -08002201
2202 window->consumeMotionEvent(
2203 AllOf(WithMotionAction(ACTION_CANCEL), WithDeviceId(VIRTUAL_KEYBOARD_ID)));
2204 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(touchDeviceId)));
2205}
2206
2207/**
Siarhei Vishniakou6464e462023-02-06 18:57:59 -08002208 * This test is similar to the test above, but the sequence of injected events is different.
2209 *
2210 * Two windows: a window on the left and a window on the right.
2211 * Mouse is hovered over the left window.
2212 * Next, we tap on the left window, where the cursor was last seen.
2213 *
2214 * After that, we inject one finger down onto the right window, and then a second finger down onto
2215 * the left window.
2216 * The touch is split, so this last gesture should cause 2 ACTION_DOWN events, one in the right
2217 * window (first), and then another on the left window (second).
2218 * This test reproduces a crash where there is a mismatch between the downTime and eventTime.
2219 * In the buggy implementation, second finger down on the left window would cause a crash.
2220 */
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -07002221TEST_F(InputDispatcherMultiDeviceTest, HoverTapAndSplitTouch) {
Siarhei Vishniakou6464e462023-02-06 18:57:59 -08002222 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
2223 sp<FakeWindowHandle> leftWindow =
2224 sp<FakeWindowHandle>::make(application, mDispatcher, "Left", ADISPLAY_ID_DEFAULT);
2225 leftWindow->setFrame(Rect(0, 0, 200, 200));
2226
2227 sp<FakeWindowHandle> rightWindow =
2228 sp<FakeWindowHandle>::make(application, mDispatcher, "Right", ADISPLAY_ID_DEFAULT);
2229 rightWindow->setFrame(Rect(200, 0, 400, 200));
2230
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07002231 mDispatcher->onWindowInfosChanged(
2232 {{*leftWindow->getInfo(), *rightWindow->getInfo()}, {}, 0, 0});
Siarhei Vishniakou6464e462023-02-06 18:57:59 -08002233
2234 const int32_t mouseDeviceId = 6;
2235 const int32_t touchDeviceId = 4;
2236 // Hover over the left window. Keep the cursor there.
2237 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07002238 injectMotionEvent(*mDispatcher,
Siarhei Vishniakou6464e462023-02-06 18:57:59 -08002239 MotionEventBuilder(AMOTION_EVENT_ACTION_HOVER_ENTER,
2240 AINPUT_SOURCE_MOUSE)
2241 .deviceId(mouseDeviceId)
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07002242 .pointer(PointerBuilder(0, ToolType::MOUSE).x(50).y(50))
Siarhei Vishniakou6464e462023-02-06 18:57:59 -08002243 .build()));
2244 leftWindow->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_ENTER));
2245
2246 // Tap on left window
2247 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07002248 injectMotionEvent(*mDispatcher,
Siarhei Vishniakou6464e462023-02-06 18:57:59 -08002249 MotionEventBuilder(AMOTION_EVENT_ACTION_DOWN,
2250 AINPUT_SOURCE_TOUCHSCREEN)
2251 .deviceId(touchDeviceId)
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07002252 .pointer(PointerBuilder(0, ToolType::FINGER).x(100).y(100))
Siarhei Vishniakou6464e462023-02-06 18:57:59 -08002253 .build()));
2254
2255 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07002256 injectMotionEvent(*mDispatcher,
Siarhei Vishniakou6464e462023-02-06 18:57:59 -08002257 MotionEventBuilder(AMOTION_EVENT_ACTION_UP,
2258 AINPUT_SOURCE_TOUCHSCREEN)
2259 .deviceId(touchDeviceId)
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07002260 .pointer(PointerBuilder(0, ToolType::FINGER).x(100).y(100))
Siarhei Vishniakou6464e462023-02-06 18:57:59 -08002261 .build()));
2262 leftWindow->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_EXIT));
2263 leftWindow->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_DOWN));
2264 leftWindow->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_UP));
2265
2266 // First finger down on right window
2267 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07002268 injectMotionEvent(*mDispatcher,
Siarhei Vishniakou6464e462023-02-06 18:57:59 -08002269 MotionEventBuilder(AMOTION_EVENT_ACTION_DOWN,
2270 AINPUT_SOURCE_TOUCHSCREEN)
2271 .deviceId(touchDeviceId)
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07002272 .pointer(PointerBuilder(0, ToolType::FINGER).x(300).y(100))
Siarhei Vishniakou6464e462023-02-06 18:57:59 -08002273 .build()));
2274 rightWindow->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_DOWN));
2275
2276 // Second finger down on the left window
2277 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07002278 injectMotionEvent(*mDispatcher,
Siarhei Vishniakou6464e462023-02-06 18:57:59 -08002279 MotionEventBuilder(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
2280 .deviceId(touchDeviceId)
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07002281 .pointer(PointerBuilder(0, ToolType::FINGER).x(300).y(100))
2282 .pointer(PointerBuilder(1, ToolType::FINGER).x(100).y(100))
Siarhei Vishniakou6464e462023-02-06 18:57:59 -08002283 .build()));
2284 leftWindow->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_DOWN));
2285 rightWindow->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_MOVE));
2286
2287 // No more events
2288 leftWindow->assertNoEvents();
2289 rightWindow->assertNoEvents();
2290}
2291
2292/**
Siarhei Vishniakou2e3e4432023-02-09 18:34:11 -08002293 * Start hovering with a stylus device, and then tap with a touch device. Ensure no crash occurs.
2294 * While the touch is down, new hover events from the stylus device should be ignored. After the
2295 * touch is gone, stylus hovering should start working again.
2296 */
Siarhei Vishniakou3ad54f52023-11-02 16:54:40 -07002297TEST_F(InputDispatcherMultiDeviceTest, StylusHoverIgnoresTouchTap) {
Siarhei Vishniakou2e3e4432023-02-09 18:34:11 -08002298 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
2299 sp<FakeWindowHandle> window =
2300 sp<FakeWindowHandle>::make(application, mDispatcher, "Window", ADISPLAY_ID_DEFAULT);
2301 window->setFrame(Rect(0, 0, 200, 200));
2302
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07002303 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Siarhei Vishniakou2e3e4432023-02-09 18:34:11 -08002304
2305 const int32_t stylusDeviceId = 5;
2306 const int32_t touchDeviceId = 4;
2307 // Start hovering with stylus
2308 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07002309 injectMotionEvent(*mDispatcher,
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -07002310 MotionEventBuilder(ACTION_HOVER_ENTER, AINPUT_SOURCE_STYLUS)
Siarhei Vishniakou2e3e4432023-02-09 18:34:11 -08002311 .deviceId(stylusDeviceId)
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07002312 .pointer(PointerBuilder(0, ToolType::STYLUS).x(50).y(50))
Siarhei Vishniakou2e3e4432023-02-09 18:34:11 -08002313 .build()));
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -07002314 window->consumeMotionEvent(WithMotionAction(ACTION_HOVER_ENTER));
Siarhei Vishniakou2e3e4432023-02-09 18:34:11 -08002315
2316 // Finger down on the window
2317 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07002318 injectMotionEvent(*mDispatcher,
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -07002319 MotionEventBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
Siarhei Vishniakou2e3e4432023-02-09 18:34:11 -08002320 .deviceId(touchDeviceId)
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07002321 .pointer(PointerBuilder(0, ToolType::FINGER).x(100).y(100))
Siarhei Vishniakou2e3e4432023-02-09 18:34:11 -08002322 .build()));
Siarhei Vishniakou3ad54f52023-11-02 16:54:40 -07002323 // The touch device should be ignored!
Siarhei Vishniakou2e3e4432023-02-09 18:34:11 -08002324
Siarhei Vishniakou2899c552023-07-10 18:20:46 -07002325 // Continue hovering with stylus.
2326 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07002327 injectMotionEvent(*mDispatcher,
Siarhei Vishniakou2e3e4432023-02-09 18:34:11 -08002328 MotionEventBuilder(AMOTION_EVENT_ACTION_HOVER_MOVE,
2329 AINPUT_SOURCE_STYLUS)
2330 .deviceId(stylusDeviceId)
Siarhei Vishniakou25537f82023-07-18 14:35:47 -07002331 .pointer(PointerBuilder(0, ToolType::STYLUS).x(60).y(60))
Siarhei Vishniakou2e3e4432023-02-09 18:34:11 -08002332 .build()));
Siarhei Vishniakou3ad54f52023-11-02 16:54:40 -07002333 // Hovers continue to work
2334 window->consumeMotionEvent(
2335 AllOf(WithMotionAction(ACTION_HOVER_MOVE), WithDeviceId(stylusDeviceId)));
Siarhei Vishniakou2e3e4432023-02-09 18:34:11 -08002336
2337 // Lift up the finger
2338 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07002339 injectMotionEvent(*mDispatcher,
Siarhei Vishniakou2e3e4432023-02-09 18:34:11 -08002340 MotionEventBuilder(AMOTION_EVENT_ACTION_UP,
2341 AINPUT_SOURCE_TOUCHSCREEN)
2342 .deviceId(touchDeviceId)
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07002343 .pointer(PointerBuilder(0, ToolType::FINGER).x(100).y(100))
Siarhei Vishniakou2e3e4432023-02-09 18:34:11 -08002344 .build()));
Siarhei Vishniakou2e3e4432023-02-09 18:34:11 -08002345
Siarhei Vishniakou2e3e4432023-02-09 18:34:11 -08002346 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07002347 injectMotionEvent(*mDispatcher,
Siarhei Vishniakou2e3e4432023-02-09 18:34:11 -08002348 MotionEventBuilder(AMOTION_EVENT_ACTION_HOVER_MOVE,
2349 AINPUT_SOURCE_STYLUS)
2350 .deviceId(stylusDeviceId)
Siarhei Vishniakou25537f82023-07-18 14:35:47 -07002351 .pointer(PointerBuilder(0, ToolType::STYLUS).x(70).y(70))
Siarhei Vishniakou2e3e4432023-02-09 18:34:11 -08002352 .build()));
Siarhei Vishniakou3ad54f52023-11-02 16:54:40 -07002353 window->consumeMotionEvent(
2354 AllOf(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_MOVE), WithDeviceId(stylusDeviceId)));
Siarhei Vishniakou2e3e4432023-02-09 18:34:11 -08002355 window->assertNoEvents();
2356}
2357
2358/**
Siarhei Vishniakouf77f60a2023-10-23 17:26:05 -07002359 * If stylus is down anywhere on the screen, then touches should not be delivered to windows that
2360 * have InputConfig::GLOBAL_STYLUS_BLOCKS_TOUCH.
2361 *
2362 * Two windows: one on the left and one on the right.
2363 * The window on the right has GLOBAL_STYLUS_BLOCKS_TOUCH config.
2364 * Stylus down on the left window, and then touch down on the right window.
2365 * Check that the right window doesn't get touches while the stylus is down on the left window.
2366 */
2367TEST_F(InputDispatcherMultiDeviceTest, GlobalStylusDownBlocksTouch) {
2368 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
2369 sp<FakeWindowHandle> leftWindow =
2370 sp<FakeWindowHandle>::make(application, mDispatcher, "Left window",
2371 ADISPLAY_ID_DEFAULT);
2372 leftWindow->setFrame(Rect(0, 0, 100, 100));
2373
2374 sp<FakeWindowHandle> sbtRightWindow =
2375 sp<FakeWindowHandle>::make(application, mDispatcher,
2376 "Stylus blocks touch (right) window", ADISPLAY_ID_DEFAULT);
2377 sbtRightWindow->setFrame(Rect(100, 100, 200, 200));
2378 sbtRightWindow->setGlobalStylusBlocksTouch(true);
2379
2380 mDispatcher->onWindowInfosChanged(
2381 {{*leftWindow->getInfo(), *sbtRightWindow->getInfo()}, {}, 0, 0});
2382
2383 const int32_t stylusDeviceId = 5;
2384 const int32_t touchDeviceId = 4;
2385
2386 // Stylus down in the left window
2387 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_STYLUS)
2388 .pointer(PointerBuilder(0, ToolType::STYLUS).x(50).y(52))
2389 .deviceId(stylusDeviceId)
2390 .build());
2391 leftWindow->consumeMotionEvent(
2392 AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(stylusDeviceId)));
2393
2394 // Finger tap on the right window
2395 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
2396 .pointer(PointerBuilder(0, ToolType::FINGER).x(150).y(151))
2397 .deviceId(touchDeviceId)
2398 .build());
2399 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN)
2400 .pointer(PointerBuilder(0, ToolType::FINGER).x(150).y(151))
2401 .deviceId(touchDeviceId)
2402 .build());
2403
2404 // The touch should be blocked, because stylus is down somewhere else on screen!
2405 sbtRightWindow->assertNoEvents();
2406
2407 // Continue stylus motion, and ensure it's not impacted.
2408 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_STYLUS)
2409 .pointer(PointerBuilder(0, ToolType::STYLUS).x(51).y(53))
2410 .deviceId(stylusDeviceId)
2411 .build());
2412 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_UP, AINPUT_SOURCE_STYLUS)
2413 .pointer(PointerBuilder(0, ToolType::STYLUS).x(51).y(53))
2414 .deviceId(stylusDeviceId)
2415 .build());
2416 leftWindow->consumeMotionEvent(
2417 AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(stylusDeviceId)));
2418 leftWindow->consumeMotionEvent(
2419 AllOf(WithMotionAction(ACTION_UP), WithDeviceId(stylusDeviceId)));
2420
2421 // Now that the stylus gesture is done, touches should be getting delivered correctly.
2422 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
2423 .pointer(PointerBuilder(0, ToolType::FINGER).x(151).y(153))
2424 .deviceId(touchDeviceId)
2425 .build());
2426 sbtRightWindow->consumeMotionEvent(
2427 AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(touchDeviceId)));
2428}
2429
2430/**
2431 * If stylus is hovering anywhere on the screen, then touches should not be delivered to windows
2432 * that have InputConfig::GLOBAL_STYLUS_BLOCKS_TOUCH.
2433 *
2434 * Two windows: one on the left and one on the right.
2435 * The window on the right has GLOBAL_STYLUS_BLOCKS_TOUCH config.
2436 * Stylus hover on the left window, and then touch down on the right window.
2437 * Check that the right window doesn't get touches while the stylus is hovering on the left window.
2438 */
2439TEST_F(InputDispatcherMultiDeviceTest, GlobalStylusHoverBlocksTouch) {
2440 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
2441 sp<FakeWindowHandle> leftWindow =
2442 sp<FakeWindowHandle>::make(application, mDispatcher, "Left window",
2443 ADISPLAY_ID_DEFAULT);
2444 leftWindow->setFrame(Rect(0, 0, 100, 100));
2445
2446 sp<FakeWindowHandle> sbtRightWindow =
2447 sp<FakeWindowHandle>::make(application, mDispatcher,
2448 "Stylus blocks touch (right) window", ADISPLAY_ID_DEFAULT);
2449 sbtRightWindow->setFrame(Rect(100, 100, 200, 200));
2450 sbtRightWindow->setGlobalStylusBlocksTouch(true);
2451
2452 mDispatcher->onWindowInfosChanged(
2453 {{*leftWindow->getInfo(), *sbtRightWindow->getInfo()}, {}, 0, 0});
2454
2455 const int32_t stylusDeviceId = 5;
2456 const int32_t touchDeviceId = 4;
2457
2458 // Stylus hover in the left window
2459 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_ENTER, AINPUT_SOURCE_STYLUS)
2460 .pointer(PointerBuilder(0, ToolType::STYLUS).x(50).y(52))
2461 .deviceId(stylusDeviceId)
2462 .build());
2463 leftWindow->consumeMotionEvent(
2464 AllOf(WithMotionAction(ACTION_HOVER_ENTER), WithDeviceId(stylusDeviceId)));
2465
2466 // Finger tap on the right window
2467 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
2468 .pointer(PointerBuilder(0, ToolType::FINGER).x(150).y(151))
2469 .deviceId(touchDeviceId)
2470 .build());
2471 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN)
2472 .pointer(PointerBuilder(0, ToolType::FINGER).x(150).y(151))
2473 .deviceId(touchDeviceId)
2474 .build());
2475
2476 // The touch should be blocked, because stylus is hovering somewhere else on screen!
2477 sbtRightWindow->assertNoEvents();
2478
2479 // Continue stylus motion, and ensure it's not impacted.
2480 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_MOVE, AINPUT_SOURCE_STYLUS)
2481 .pointer(PointerBuilder(0, ToolType::STYLUS).x(51).y(53))
2482 .deviceId(stylusDeviceId)
2483 .build());
2484 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_EXIT, AINPUT_SOURCE_STYLUS)
2485 .pointer(PointerBuilder(0, ToolType::STYLUS).x(51).y(53))
2486 .deviceId(stylusDeviceId)
2487 .build());
2488 leftWindow->consumeMotionEvent(
2489 AllOf(WithMotionAction(ACTION_HOVER_MOVE), WithDeviceId(stylusDeviceId)));
2490 leftWindow->consumeMotionEvent(
2491 AllOf(WithMotionAction(ACTION_HOVER_EXIT), WithDeviceId(stylusDeviceId)));
2492
2493 // Now that the stylus gesture is done, touches should be getting delivered correctly.
2494 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
2495 .pointer(PointerBuilder(0, ToolType::FINGER).x(151).y(153))
2496 .deviceId(touchDeviceId)
2497 .build());
2498 sbtRightWindow->consumeMotionEvent(
2499 AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(touchDeviceId)));
2500}
2501
2502/**
Siarhei Vishniakouf372b812023-02-14 18:06:51 -08002503 * A spy window above a window with no input channel.
2504 * Start hovering with a stylus device, and then tap with it.
2505 * Ensure spy window receives the entire sequence.
2506 */
2507TEST_F(InputDispatcherTest, StylusHoverAndDownNoInputChannel) {
2508 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
2509 sp<FakeWindowHandle> spyWindow =
2510 sp<FakeWindowHandle>::make(application, mDispatcher, "Spy", ADISPLAY_ID_DEFAULT);
2511 spyWindow->setFrame(Rect(0, 0, 200, 200));
2512 spyWindow->setTrustedOverlay(true);
2513 spyWindow->setSpy(true);
2514 sp<FakeWindowHandle> window =
2515 sp<FakeWindowHandle>::make(application, mDispatcher, "Window", ADISPLAY_ID_DEFAULT);
2516 window->setNoInputChannel(true);
2517 window->setFrame(Rect(0, 0, 200, 200));
2518
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07002519 mDispatcher->onWindowInfosChanged({{*spyWindow->getInfo(), *window->getInfo()}, {}, 0, 0});
Siarhei Vishniakouf372b812023-02-14 18:06:51 -08002520
Siarhei Vishniakouf372b812023-02-14 18:06:51 -08002521 // Start hovering with stylus
Prabir Pradhan678438e2023-04-13 19:32:51 +00002522 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_ENTER, AINPUT_SOURCE_STYLUS)
2523 .pointer(PointerBuilder(0, ToolType::STYLUS).x(50).y(50))
2524 .build());
Siarhei Vishniakouf372b812023-02-14 18:06:51 -08002525 spyWindow->consumeMotionEvent(WithMotionAction(ACTION_HOVER_ENTER));
2526 // Stop hovering
Prabir Pradhan678438e2023-04-13 19:32:51 +00002527 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_EXIT, AINPUT_SOURCE_STYLUS)
2528 .pointer(PointerBuilder(0, ToolType::STYLUS).x(50).y(50))
2529 .build());
Siarhei Vishniakouf372b812023-02-14 18:06:51 -08002530 spyWindow->consumeMotionEvent(WithMotionAction(ACTION_HOVER_EXIT));
2531
2532 // Stylus touches down
Prabir Pradhan678438e2023-04-13 19:32:51 +00002533 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_STYLUS)
2534 .pointer(PointerBuilder(0, ToolType::STYLUS).x(50).y(50))
2535 .build());
Siarhei Vishniakouf372b812023-02-14 18:06:51 -08002536 spyWindow->consumeMotionEvent(WithMotionAction(ACTION_DOWN));
2537
2538 // Stylus goes up
Prabir Pradhan678438e2023-04-13 19:32:51 +00002539 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_UP, AINPUT_SOURCE_STYLUS)
2540 .pointer(PointerBuilder(0, ToolType::STYLUS).x(50).y(50))
2541 .build());
Siarhei Vishniakouf372b812023-02-14 18:06:51 -08002542 spyWindow->consumeMotionEvent(WithMotionAction(ACTION_UP));
2543
2544 // Again hover
Prabir Pradhan678438e2023-04-13 19:32:51 +00002545 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_ENTER, AINPUT_SOURCE_STYLUS)
2546 .pointer(PointerBuilder(0, ToolType::STYLUS).x(50).y(50))
2547 .build());
Siarhei Vishniakouf372b812023-02-14 18:06:51 -08002548 spyWindow->consumeMotionEvent(WithMotionAction(ACTION_HOVER_ENTER));
2549 // Stop hovering
Prabir Pradhan678438e2023-04-13 19:32:51 +00002550 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_EXIT, AINPUT_SOURCE_STYLUS)
2551 .pointer(PointerBuilder(0, ToolType::STYLUS).x(50).y(50))
2552 .build());
Siarhei Vishniakouf372b812023-02-14 18:06:51 -08002553 spyWindow->consumeMotionEvent(WithMotionAction(ACTION_HOVER_EXIT));
2554
2555 // No more events
2556 spyWindow->assertNoEvents();
2557 window->assertNoEvents();
2558}
2559
2560/**
Siarhei Vishniakou6b71b632023-10-27 21:34:46 -07002561 * A stale stylus HOVER_EXIT event is injected. Since it's a stale event, it should generally be
2562 * rejected. But since we already have an ongoing gesture, this event should be processed.
2563 * This prevents inconsistent events being handled inside the dispatcher.
2564 */
2565TEST_F(InputDispatcherTest, StaleStylusHoverGestureIsComplete) {
2566 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
2567
2568 sp<FakeWindowHandle> window =
2569 sp<FakeWindowHandle>::make(application, mDispatcher, "Window", ADISPLAY_ID_DEFAULT);
2570 window->setFrame(Rect(0, 0, 200, 200));
2571
2572 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
2573
2574 // Start hovering with stylus
2575 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_ENTER, AINPUT_SOURCE_STYLUS)
2576 .pointer(PointerBuilder(0, ToolType::STYLUS).x(50).y(50))
2577 .build());
2578 window->consumeMotionEvent(WithMotionAction(ACTION_HOVER_ENTER));
2579
2580 NotifyMotionArgs hoverExit = MotionArgsBuilder(ACTION_HOVER_EXIT, AINPUT_SOURCE_STYLUS)
2581 .pointer(PointerBuilder(0, ToolType::STYLUS).x(50).y(50))
2582 .build();
2583 // Make this 'hoverExit' event stale
2584 mFakePolicy->setStaleEventTimeout(100ms);
2585 std::this_thread::sleep_for(100ms);
2586
2587 // It shouldn't be dropped by the dispatcher, even though it's stale.
2588 mDispatcher->notifyMotion(hoverExit);
2589 window->consumeMotionEvent(WithMotionAction(ACTION_HOVER_EXIT));
2590
2591 // Stylus starts hovering again! There should be no crash.
2592 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_ENTER, AINPUT_SOURCE_STYLUS)
2593 .pointer(PointerBuilder(0, ToolType::STYLUS).x(51).y(51))
2594 .build());
2595 window->consumeMotionEvent(WithMotionAction(ACTION_HOVER_ENTER));
2596}
2597
2598/**
Siarhei Vishniakouf372b812023-02-14 18:06:51 -08002599 * Start hovering with a mouse, and then tap with a touch device. Pilfer the touch stream.
2600 * Next, click with the mouse device. Both windows (spy and regular) should receive the new mouse
2601 * ACTION_DOWN event because that's a new gesture, and pilfering should no longer be active.
2602 * While the mouse is down, new move events from the touch device should be ignored.
2603 */
2604TEST_F(InputDispatcherTest, TouchPilferAndMouseMove) {
2605 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
2606 sp<FakeWindowHandle> spyWindow =
2607 sp<FakeWindowHandle>::make(application, mDispatcher, "Spy", ADISPLAY_ID_DEFAULT);
2608 spyWindow->setFrame(Rect(0, 0, 200, 200));
2609 spyWindow->setTrustedOverlay(true);
2610 spyWindow->setSpy(true);
2611 sp<FakeWindowHandle> window =
2612 sp<FakeWindowHandle>::make(application, mDispatcher, "Window", ADISPLAY_ID_DEFAULT);
2613 window->setFrame(Rect(0, 0, 200, 200));
2614
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07002615 mDispatcher->onWindowInfosChanged({{*spyWindow->getInfo(), *window->getInfo()}, {}, 0, 0});
Siarhei Vishniakouf372b812023-02-14 18:06:51 -08002616
2617 const int32_t mouseDeviceId = 7;
2618 const int32_t touchDeviceId = 4;
Siarhei Vishniakouf372b812023-02-14 18:06:51 -08002619
2620 // Hover a bit with mouse first
Prabir Pradhan678438e2023-04-13 19:32:51 +00002621 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_ENTER, AINPUT_SOURCE_MOUSE)
2622 .deviceId(mouseDeviceId)
2623 .pointer(PointerBuilder(0, ToolType::MOUSE).x(100).y(100))
2624 .build());
Siarhei Vishniakouf372b812023-02-14 18:06:51 -08002625 spyWindow->consumeMotionEvent(
2626 AllOf(WithMotionAction(ACTION_HOVER_ENTER), WithDeviceId(mouseDeviceId)));
2627 window->consumeMotionEvent(
2628 AllOf(WithMotionAction(ACTION_HOVER_ENTER), WithDeviceId(mouseDeviceId)));
2629
2630 // Start touching
Prabir Pradhan678438e2023-04-13 19:32:51 +00002631 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
2632 .deviceId(touchDeviceId)
2633 .pointer(PointerBuilder(0, ToolType::FINGER).x(50).y(50))
2634 .build());
Siarhei Vishniakouf372b812023-02-14 18:06:51 -08002635 spyWindow->consumeMotionEvent(WithMotionAction(ACTION_HOVER_EXIT));
2636 window->consumeMotionEvent(WithMotionAction(ACTION_HOVER_EXIT));
2637 spyWindow->consumeMotionEvent(WithMotionAction(ACTION_DOWN));
2638 window->consumeMotionEvent(WithMotionAction(ACTION_DOWN));
2639
Prabir Pradhan678438e2023-04-13 19:32:51 +00002640 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN)
2641 .deviceId(touchDeviceId)
2642 .pointer(PointerBuilder(0, ToolType::FINGER).x(55).y(55))
2643 .build());
Siarhei Vishniakouf372b812023-02-14 18:06:51 -08002644 spyWindow->consumeMotionEvent(WithMotionAction(ACTION_MOVE));
2645 window->consumeMotionEvent(WithMotionAction(ACTION_MOVE));
2646
2647 // Pilfer the stream
2648 EXPECT_EQ(OK, mDispatcher->pilferPointers(spyWindow->getToken()));
2649 window->consumeMotionEvent(WithMotionAction(ACTION_CANCEL));
2650
Prabir Pradhan678438e2023-04-13 19:32:51 +00002651 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN)
2652 .deviceId(touchDeviceId)
2653 .pointer(PointerBuilder(0, ToolType::FINGER).x(60).y(60))
2654 .build());
Siarhei Vishniakouf372b812023-02-14 18:06:51 -08002655 spyWindow->consumeMotionEvent(WithMotionAction(ACTION_MOVE));
2656
2657 // Mouse down
Prabir Pradhan678438e2023-04-13 19:32:51 +00002658 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_MOUSE)
2659 .deviceId(mouseDeviceId)
2660 .buttonState(AMOTION_EVENT_BUTTON_PRIMARY)
2661 .pointer(PointerBuilder(0, ToolType::MOUSE).x(100).y(100))
2662 .build());
Siarhei Vishniakouf372b812023-02-14 18:06:51 -08002663
2664 spyWindow->consumeMotionEvent(
2665 AllOf(WithMotionAction(ACTION_CANCEL), WithDeviceId(touchDeviceId)));
2666 spyWindow->consumeMotionEvent(
2667 AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(mouseDeviceId)));
2668 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(mouseDeviceId)));
2669
Prabir Pradhan678438e2023-04-13 19:32:51 +00002670 mDispatcher->notifyMotion(
2671 MotionArgsBuilder(AMOTION_EVENT_ACTION_BUTTON_PRESS, AINPUT_SOURCE_MOUSE)
2672 .deviceId(mouseDeviceId)
2673 .buttonState(AMOTION_EVENT_BUTTON_PRIMARY)
2674 .actionButton(AMOTION_EVENT_BUTTON_PRIMARY)
2675 .pointer(PointerBuilder(0, ToolType::MOUSE).x(100).y(100))
2676 .build());
Siarhei Vishniakouf372b812023-02-14 18:06:51 -08002677 spyWindow->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_BUTTON_PRESS));
2678 window->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_BUTTON_PRESS));
2679
2680 // Mouse move!
Prabir Pradhan678438e2023-04-13 19:32:51 +00002681 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_MOUSE)
2682 .deviceId(mouseDeviceId)
2683 .buttonState(AMOTION_EVENT_BUTTON_PRIMARY)
2684 .pointer(PointerBuilder(0, ToolType::MOUSE).x(110).y(110))
2685 .build());
Siarhei Vishniakouf372b812023-02-14 18:06:51 -08002686 spyWindow->consumeMotionEvent(WithMotionAction(ACTION_MOVE));
2687 window->consumeMotionEvent(WithMotionAction(ACTION_MOVE));
2688
2689 // Touch move!
Prabir Pradhan678438e2023-04-13 19:32:51 +00002690 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN)
2691 .deviceId(touchDeviceId)
2692 .pointer(PointerBuilder(0, ToolType::FINGER).x(65).y(65))
2693 .build());
Siarhei Vishniakouf372b812023-02-14 18:06:51 -08002694
2695 // No more events
2696 spyWindow->assertNoEvents();
2697 window->assertNoEvents();
2698}
2699
2700/**
Siarhei Vishniakoua16e3a22022-03-02 15:26:40 -08002701 * On the display, have a single window, and also an area where there's no window.
2702 * First pointer touches the "no window" area of the screen. Second pointer touches the window.
2703 * Make sure that the window receives the second pointer, and first pointer is simply ignored.
2704 */
2705TEST_F(InputDispatcherTest, SplitWorksWhenEmptyAreaIsTouched) {
2706 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
2707 sp<FakeWindowHandle> window =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07002708 sp<FakeWindowHandle>::make(application, mDispatcher, "Window", DISPLAY_ID);
Siarhei Vishniakoua16e3a22022-03-02 15:26:40 -08002709
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07002710 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Siarhei Vishniakoua16e3a22022-03-02 15:26:40 -08002711
2712 // Touch down on the empty space
Prabir Pradhan678438e2023-04-13 19:32:51 +00002713 mDispatcher->notifyMotion(generateTouchArgs(AMOTION_EVENT_ACTION_DOWN, {{-1, -1}}));
Siarhei Vishniakoua16e3a22022-03-02 15:26:40 -08002714
2715 mDispatcher->waitForIdle();
2716 window->assertNoEvents();
2717
2718 // Now touch down on the window with another pointer
Prabir Pradhan678438e2023-04-13 19:32:51 +00002719 mDispatcher->notifyMotion(generateTouchArgs(POINTER_1_DOWN, {{-1, -1}, {10, 10}}));
Siarhei Vishniakoua16e3a22022-03-02 15:26:40 -08002720 mDispatcher->waitForIdle();
2721 window->consumeMotionDown();
2722}
2723
2724/**
2725 * Same test as above, but instead of touching the empty space, the first touch goes to
2726 * non-touchable window.
2727 */
2728TEST_F(InputDispatcherTest, SplitWorksWhenNonTouchableWindowIsTouched) {
2729 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
2730 sp<FakeWindowHandle> window1 =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07002731 sp<FakeWindowHandle>::make(application, mDispatcher, "Window1", DISPLAY_ID);
Siarhei Vishniakoua16e3a22022-03-02 15:26:40 -08002732 window1->setTouchableRegion(Region{{0, 0, 100, 100}});
2733 window1->setTouchable(false);
2734 sp<FakeWindowHandle> window2 =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07002735 sp<FakeWindowHandle>::make(application, mDispatcher, "Window2", DISPLAY_ID);
Siarhei Vishniakoua16e3a22022-03-02 15:26:40 -08002736 window2->setTouchableRegion(Region{{100, 0, 200, 100}});
2737
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07002738 mDispatcher->onWindowInfosChanged({{*window1->getInfo(), *window2->getInfo()}, {}, 0, 0});
Siarhei Vishniakoua16e3a22022-03-02 15:26:40 -08002739
Siarhei Vishniakoua16e3a22022-03-02 15:26:40 -08002740 // Touch down on the non-touchable window
Prabir Pradhan678438e2023-04-13 19:32:51 +00002741 mDispatcher->notifyMotion(generateTouchArgs(AMOTION_EVENT_ACTION_DOWN, {{50, 50}}));
Siarhei Vishniakoua16e3a22022-03-02 15:26:40 -08002742
2743 mDispatcher->waitForIdle();
2744 window1->assertNoEvents();
2745 window2->assertNoEvents();
2746
2747 // Now touch down on the window with another pointer
Prabir Pradhan678438e2023-04-13 19:32:51 +00002748 mDispatcher->notifyMotion(generateTouchArgs(POINTER_1_DOWN, {{50, 50}, {150, 50}}));
Siarhei Vishniakoua16e3a22022-03-02 15:26:40 -08002749 mDispatcher->waitForIdle();
2750 window2->consumeMotionDown();
2751}
2752
Vaibhav Devmurari882bd9b2022-06-23 14:54:54 +00002753/**
2754 * When splitting touch events the downTime should be adjusted such that the downTime corresponds
2755 * to the event time of the first ACTION_DOWN sent to the particular window.
2756 */
2757TEST_F(InputDispatcherTest, SplitTouchesSendCorrectActionDownTime) {
2758 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
2759 sp<FakeWindowHandle> window1 =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07002760 sp<FakeWindowHandle>::make(application, mDispatcher, "Window1", DISPLAY_ID);
Vaibhav Devmurari882bd9b2022-06-23 14:54:54 +00002761 window1->setTouchableRegion(Region{{0, 0, 100, 100}});
2762 sp<FakeWindowHandle> window2 =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07002763 sp<FakeWindowHandle>::make(application, mDispatcher, "Window2", DISPLAY_ID);
Vaibhav Devmurari882bd9b2022-06-23 14:54:54 +00002764 window2->setTouchableRegion(Region{{100, 0, 200, 100}});
2765
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07002766 mDispatcher->onWindowInfosChanged({{*window1->getInfo(), *window2->getInfo()}, {}, 0, 0});
Vaibhav Devmurari882bd9b2022-06-23 14:54:54 +00002767
Vaibhav Devmurari882bd9b2022-06-23 14:54:54 +00002768 // Touch down on the first window
Prabir Pradhan678438e2023-04-13 19:32:51 +00002769 mDispatcher->notifyMotion(generateTouchArgs(AMOTION_EVENT_ACTION_DOWN, {{50, 50}}));
Vaibhav Devmurari882bd9b2022-06-23 14:54:54 +00002770 mDispatcher->waitForIdle();
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07002771
Prabir Pradhan9d5f9ce2024-01-24 00:03:41 +00002772 const std::unique_ptr<MotionEvent> firstDown =
2773 window1->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN)));
2774 ASSERT_EQ(firstDown->getDownTime(), firstDown->getEventTime());
Vaibhav Devmurari882bd9b2022-06-23 14:54:54 +00002775 window2->assertNoEvents();
Vaibhav Devmurari882bd9b2022-06-23 14:54:54 +00002776
2777 // Now touch down on the window with another pointer
Prabir Pradhan678438e2023-04-13 19:32:51 +00002778 mDispatcher->notifyMotion(generateTouchArgs(POINTER_1_DOWN, {{50, 50}, {150, 50}}));
Vaibhav Devmurari882bd9b2022-06-23 14:54:54 +00002779 mDispatcher->waitForIdle();
Prabir Pradhan9d5f9ce2024-01-24 00:03:41 +00002780
2781 const std::unique_ptr<MotionEvent> secondDown =
2782 window2->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN)));
2783 ASSERT_EQ(secondDown->getDownTime(), secondDown->getEventTime());
2784 ASSERT_NE(firstDown->getDownTime(), secondDown->getDownTime());
2785 // We currently send MOVE events to all windows receiving a split touch when there is any change
2786 // in the touch state, even when none of the pointers in the split window actually moved.
2787 // Document this behavior in the test.
2788 window1->consumeMotionMove();
Vaibhav Devmurari882bd9b2022-06-23 14:54:54 +00002789
2790 // Now move the pointer on the second window
Prabir Pradhan678438e2023-04-13 19:32:51 +00002791 mDispatcher->notifyMotion(generateTouchArgs(AMOTION_EVENT_ACTION_MOVE, {{50, 50}, {151, 51}}));
Vaibhav Devmurari882bd9b2022-06-23 14:54:54 +00002792 mDispatcher->waitForIdle();
Prabir Pradhan9d5f9ce2024-01-24 00:03:41 +00002793
2794 window2->consumeMotionEvent(WithDownTime(secondDown->getDownTime()));
2795 window1->consumeMotionEvent(WithDownTime(firstDown->getDownTime()));
Vaibhav Devmurari882bd9b2022-06-23 14:54:54 +00002796
2797 // Now add new touch down on the second window
Prabir Pradhan678438e2023-04-13 19:32:51 +00002798 mDispatcher->notifyMotion(generateTouchArgs(POINTER_2_DOWN, {{50, 50}, {151, 51}, {150, 50}}));
Vaibhav Devmurari882bd9b2022-06-23 14:54:54 +00002799 mDispatcher->waitForIdle();
Vaibhav Devmurari882bd9b2022-06-23 14:54:54 +00002800
Prabir Pradhan9d5f9ce2024-01-24 00:03:41 +00002801 window2->consumeMotionEvent(
2802 AllOf(WithMotionAction(POINTER_1_DOWN), WithDownTime(secondDown->getDownTime())));
2803 window1->consumeMotionEvent(WithDownTime(firstDown->getDownTime()));
Vaibhav Devmurari882bd9b2022-06-23 14:54:54 +00002804
2805 // Now move the pointer on the first window
Prabir Pradhan678438e2023-04-13 19:32:51 +00002806 mDispatcher->notifyMotion(
2807 generateTouchArgs(AMOTION_EVENT_ACTION_MOVE, {{51, 51}, {151, 51}, {150, 50}}));
Vaibhav Devmurari882bd9b2022-06-23 14:54:54 +00002808 mDispatcher->waitForIdle();
Vaibhav Devmurari882bd9b2022-06-23 14:54:54 +00002809
Prabir Pradhan9d5f9ce2024-01-24 00:03:41 +00002810 window1->consumeMotionEvent(WithDownTime(firstDown->getDownTime()));
2811 window2->consumeMotionEvent(WithDownTime(secondDown->getDownTime()));
2812
2813 // Now add new touch down on the first window
Prabir Pradhan678438e2023-04-13 19:32:51 +00002814 mDispatcher->notifyMotion(
2815 generateTouchArgs(POINTER_3_DOWN, {{51, 51}, {151, 51}, {150, 50}, {50, 50}}));
Vaibhav Devmurari882bd9b2022-06-23 14:54:54 +00002816 mDispatcher->waitForIdle();
Prabir Pradhan9d5f9ce2024-01-24 00:03:41 +00002817
2818 window1->consumeMotionEvent(
2819 AllOf(WithMotionAction(POINTER_1_DOWN), WithDownTime(firstDown->getDownTime())));
2820 window2->consumeMotionEvent(WithDownTime(secondDown->getDownTime()));
Vaibhav Devmurari882bd9b2022-06-23 14:54:54 +00002821}
2822
Garfield Tandf26e862020-07-01 20:18:19 -07002823TEST_F(InputDispatcherTest, HoverMoveEnterMouseClickAndHoverMoveExit) {
Chris Yea209fde2020-07-22 13:54:51 -07002824 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
Garfield Tandf26e862020-07-01 20:18:19 -07002825 sp<FakeWindowHandle> windowLeft =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07002826 sp<FakeWindowHandle>::make(application, mDispatcher, "Left", ADISPLAY_ID_DEFAULT);
Garfield Tandf26e862020-07-01 20:18:19 -07002827 windowLeft->setFrame(Rect(0, 0, 600, 800));
Garfield Tandf26e862020-07-01 20:18:19 -07002828 sp<FakeWindowHandle> windowRight =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07002829 sp<FakeWindowHandle>::make(application, mDispatcher, "Right", ADISPLAY_ID_DEFAULT);
Garfield Tandf26e862020-07-01 20:18:19 -07002830 windowRight->setFrame(Rect(600, 0, 1200, 800));
Garfield Tandf26e862020-07-01 20:18:19 -07002831
2832 mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application);
2833
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07002834 mDispatcher->onWindowInfosChanged(
2835 {{*windowLeft->getInfo(), *windowRight->getInfo()}, {}, 0, 0});
Garfield Tandf26e862020-07-01 20:18:19 -07002836
2837 // Start cursor position in right window so that we can move the cursor to left window.
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08002838 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07002839 injectMotionEvent(*mDispatcher,
Garfield Tandf26e862020-07-01 20:18:19 -07002840 MotionEventBuilder(AMOTION_EVENT_ACTION_HOVER_MOVE,
2841 AINPUT_SOURCE_MOUSE)
Siarhei Vishniakou6d73f832022-07-21 17:27:03 -07002842 .pointer(PointerBuilder(0, ToolType::MOUSE).x(900).y(400))
Garfield Tandf26e862020-07-01 20:18:19 -07002843 .build()));
Siarhei Vishniakou5cee1e32022-11-29 12:35:39 -08002844 windowRight->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_ENTER));
Garfield Tandf26e862020-07-01 20:18:19 -07002845
2846 // Move cursor into left window
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08002847 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07002848 injectMotionEvent(*mDispatcher,
Garfield Tandf26e862020-07-01 20:18:19 -07002849 MotionEventBuilder(AMOTION_EVENT_ACTION_HOVER_MOVE,
2850 AINPUT_SOURCE_MOUSE)
Siarhei Vishniakou6d73f832022-07-21 17:27:03 -07002851 .pointer(PointerBuilder(0, ToolType::MOUSE).x(300).y(400))
Garfield Tandf26e862020-07-01 20:18:19 -07002852 .build()));
Siarhei Vishniakou5cee1e32022-11-29 12:35:39 -08002853 windowRight->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_EXIT));
2854 windowLeft->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_ENTER));
Garfield Tandf26e862020-07-01 20:18:19 -07002855
2856 // Inject a series of mouse events for a mouse click
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08002857 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07002858 injectMotionEvent(*mDispatcher,
Garfield Tandf26e862020-07-01 20:18:19 -07002859 MotionEventBuilder(AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_MOUSE)
2860 .buttonState(AMOTION_EVENT_BUTTON_PRIMARY)
Siarhei Vishniakou6d73f832022-07-21 17:27:03 -07002861 .pointer(PointerBuilder(0, ToolType::MOUSE).x(300).y(400))
Garfield Tandf26e862020-07-01 20:18:19 -07002862 .build()));
Siarhei Vishniakouf372b812023-02-14 18:06:51 -08002863 windowLeft->consumeMotionEvent(WithMotionAction(ACTION_HOVER_EXIT));
2864 windowLeft->consumeMotionEvent(WithMotionAction(ACTION_DOWN));
Garfield Tandf26e862020-07-01 20:18:19 -07002865
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08002866 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07002867 injectMotionEvent(*mDispatcher,
Garfield Tandf26e862020-07-01 20:18:19 -07002868 MotionEventBuilder(AMOTION_EVENT_ACTION_BUTTON_PRESS,
2869 AINPUT_SOURCE_MOUSE)
2870 .buttonState(AMOTION_EVENT_BUTTON_PRIMARY)
2871 .actionButton(AMOTION_EVENT_BUTTON_PRIMARY)
Siarhei Vishniakou6d73f832022-07-21 17:27:03 -07002872 .pointer(PointerBuilder(0, ToolType::MOUSE).x(300).y(400))
Garfield Tandf26e862020-07-01 20:18:19 -07002873 .build()));
Siarhei Vishniakou5cee1e32022-11-29 12:35:39 -08002874 windowLeft->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_BUTTON_PRESS));
Garfield Tandf26e862020-07-01 20:18:19 -07002875
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08002876 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07002877 injectMotionEvent(*mDispatcher,
Garfield Tandf26e862020-07-01 20:18:19 -07002878 MotionEventBuilder(AMOTION_EVENT_ACTION_BUTTON_RELEASE,
2879 AINPUT_SOURCE_MOUSE)
2880 .buttonState(0)
2881 .actionButton(AMOTION_EVENT_BUTTON_PRIMARY)
Siarhei Vishniakou6d73f832022-07-21 17:27:03 -07002882 .pointer(PointerBuilder(0, ToolType::MOUSE).x(300).y(400))
Garfield Tandf26e862020-07-01 20:18:19 -07002883 .build()));
Siarhei Vishniakou5cee1e32022-11-29 12:35:39 -08002884 windowLeft->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_BUTTON_RELEASE));
Garfield Tandf26e862020-07-01 20:18:19 -07002885
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08002886 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07002887 injectMotionEvent(*mDispatcher,
Garfield Tandf26e862020-07-01 20:18:19 -07002888 MotionEventBuilder(AMOTION_EVENT_ACTION_UP, AINPUT_SOURCE_MOUSE)
2889 .buttonState(0)
Siarhei Vishniakou6d73f832022-07-21 17:27:03 -07002890 .pointer(PointerBuilder(0, ToolType::MOUSE).x(300).y(400))
Garfield Tandf26e862020-07-01 20:18:19 -07002891 .build()));
2892 windowLeft->consumeMotionUp(ADISPLAY_ID_DEFAULT);
2893
2894 // Move mouse cursor back to right window
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08002895 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07002896 injectMotionEvent(*mDispatcher,
Garfield Tandf26e862020-07-01 20:18:19 -07002897 MotionEventBuilder(AMOTION_EVENT_ACTION_HOVER_MOVE,
2898 AINPUT_SOURCE_MOUSE)
Siarhei Vishniakou6d73f832022-07-21 17:27:03 -07002899 .pointer(PointerBuilder(0, ToolType::MOUSE).x(900).y(400))
Garfield Tandf26e862020-07-01 20:18:19 -07002900 .build()));
Siarhei Vishniakou5cee1e32022-11-29 12:35:39 -08002901 windowRight->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_ENTER));
Siarhei Vishniakou5cee1e32022-11-29 12:35:39 -08002902
2903 // No more events
2904 windowLeft->assertNoEvents();
2905 windowRight->assertNoEvents();
2906}
2907
Siarhei Vishniakouf372b812023-02-14 18:06:51 -08002908/**
2909 * Put two fingers down (and don't release them) and click the mouse button.
2910 * The clicking of mouse is a new ACTION_DOWN event. Since it's from a different device, the
2911 * currently active gesture should be canceled, and the new one should proceed.
2912 */
2913TEST_F(InputDispatcherTest, TwoPointersDownMouseClick) {
2914 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
2915 sp<FakeWindowHandle> window =
2916 sp<FakeWindowHandle>::make(application, mDispatcher, "Window", ADISPLAY_ID_DEFAULT);
2917 window->setFrame(Rect(0, 0, 600, 800));
2918
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07002919 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Siarhei Vishniakouf372b812023-02-14 18:06:51 -08002920
2921 const int32_t touchDeviceId = 4;
2922 const int32_t mouseDeviceId = 6;
Siarhei Vishniakouf372b812023-02-14 18:06:51 -08002923
2924 // Two pointers down
Prabir Pradhan678438e2023-04-13 19:32:51 +00002925 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
2926 .deviceId(touchDeviceId)
2927 .pointer(PointerBuilder(0, ToolType::FINGER).x(100).y(100))
2928 .build());
Siarhei Vishniakouf372b812023-02-14 18:06:51 -08002929
Prabir Pradhan678438e2023-04-13 19:32:51 +00002930 mDispatcher->notifyMotion(MotionArgsBuilder(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
2931 .deviceId(touchDeviceId)
2932 .pointer(PointerBuilder(0, ToolType::FINGER).x(100).y(100))
2933 .pointer(PointerBuilder(1, ToolType::FINGER).x(120).y(120))
2934 .build());
Siarhei Vishniakouf372b812023-02-14 18:06:51 -08002935 window->consumeMotionEvent(WithMotionAction(ACTION_DOWN));
2936 window->consumeMotionEvent(WithMotionAction(POINTER_1_DOWN));
2937
2938 // Inject a series of mouse events for a mouse click
Prabir Pradhan678438e2023-04-13 19:32:51 +00002939 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_MOUSE)
2940 .deviceId(mouseDeviceId)
2941 .buttonState(AMOTION_EVENT_BUTTON_PRIMARY)
2942 .pointer(PointerBuilder(0, ToolType::MOUSE).x(300).y(400))
2943 .build());
Siarhei Vishniakouf372b812023-02-14 18:06:51 -08002944 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_CANCEL), WithDeviceId(touchDeviceId),
2945 WithPointerCount(2u)));
2946 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(mouseDeviceId)));
2947
Prabir Pradhan678438e2023-04-13 19:32:51 +00002948 mDispatcher->notifyMotion(
2949 MotionArgsBuilder(AMOTION_EVENT_ACTION_BUTTON_PRESS, AINPUT_SOURCE_MOUSE)
2950 .deviceId(mouseDeviceId)
2951 .buttonState(AMOTION_EVENT_BUTTON_PRIMARY)
2952 .actionButton(AMOTION_EVENT_BUTTON_PRIMARY)
2953 .pointer(PointerBuilder(0, ToolType::MOUSE).x(300).y(400))
2954 .build());
Siarhei Vishniakouf372b812023-02-14 18:06:51 -08002955 window->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_BUTTON_PRESS));
2956
2957 // Try to send more touch events while the mouse is down. Since it's a continuation of an
2958 // already canceled gesture, it should be ignored.
Prabir Pradhan678438e2023-04-13 19:32:51 +00002959 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN)
2960 .deviceId(touchDeviceId)
2961 .pointer(PointerBuilder(0, ToolType::FINGER).x(101).y(101))
2962 .pointer(PointerBuilder(1, ToolType::FINGER).x(121).y(121))
2963 .build());
Siarhei Vishniakouf372b812023-02-14 18:06:51 -08002964 window->assertNoEvents();
2965}
2966
Siarhei Vishniakou5cee1e32022-11-29 12:35:39 -08002967TEST_F(InputDispatcherTest, HoverWithSpyWindows) {
2968 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
2969
2970 sp<FakeWindowHandle> spyWindow =
2971 sp<FakeWindowHandle>::make(application, mDispatcher, "Spy", ADISPLAY_ID_DEFAULT);
2972 spyWindow->setFrame(Rect(0, 0, 600, 800));
2973 spyWindow->setTrustedOverlay(true);
2974 spyWindow->setSpy(true);
2975 sp<FakeWindowHandle> window =
2976 sp<FakeWindowHandle>::make(application, mDispatcher, "Window", ADISPLAY_ID_DEFAULT);
2977 window->setFrame(Rect(0, 0, 600, 800));
2978
2979 mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07002980 mDispatcher->onWindowInfosChanged({{*spyWindow->getInfo(), *window->getInfo()}, {}, 0, 0});
Siarhei Vishniakou5cee1e32022-11-29 12:35:39 -08002981
2982 // Send mouse cursor to the window
2983 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07002984 injectMotionEvent(*mDispatcher,
Siarhei Vishniakou5cee1e32022-11-29 12:35:39 -08002985 MotionEventBuilder(AMOTION_EVENT_ACTION_HOVER_ENTER,
2986 AINPUT_SOURCE_MOUSE)
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07002987 .pointer(PointerBuilder(0, ToolType::MOUSE).x(100).y(100))
Siarhei Vishniakou5cee1e32022-11-29 12:35:39 -08002988 .build()));
2989
2990 window->consumeMotionEvent(AllOf(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_ENTER),
2991 WithSource(AINPUT_SOURCE_MOUSE)));
2992 spyWindow->consumeMotionEvent(AllOf(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_ENTER),
2993 WithSource(AINPUT_SOURCE_MOUSE)));
2994
2995 window->assertNoEvents();
2996 spyWindow->assertNoEvents();
Garfield Tandf26e862020-07-01 20:18:19 -07002997}
2998
Siarhei Vishniakou060f82b2023-01-27 06:39:14 -08002999TEST_F(InputDispatcherTest, MouseAndTouchWithSpyWindows) {
3000 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
3001
3002 sp<FakeWindowHandle> spyWindow =
3003 sp<FakeWindowHandle>::make(application, mDispatcher, "Spy", ADISPLAY_ID_DEFAULT);
3004 spyWindow->setFrame(Rect(0, 0, 600, 800));
3005 spyWindow->setTrustedOverlay(true);
3006 spyWindow->setSpy(true);
3007 sp<FakeWindowHandle> window =
3008 sp<FakeWindowHandle>::make(application, mDispatcher, "Window", ADISPLAY_ID_DEFAULT);
3009 window->setFrame(Rect(0, 0, 600, 800));
3010
3011 mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07003012 mDispatcher->onWindowInfosChanged({{*spyWindow->getInfo(), *window->getInfo()}, {}, 0, 0});
Siarhei Vishniakou060f82b2023-01-27 06:39:14 -08003013
3014 // Send mouse cursor to the window
3015 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07003016 injectMotionEvent(*mDispatcher,
Siarhei Vishniakou060f82b2023-01-27 06:39:14 -08003017 MotionEventBuilder(AMOTION_EVENT_ACTION_HOVER_ENTER,
3018 AINPUT_SOURCE_MOUSE)
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07003019 .pointer(PointerBuilder(0, ToolType::MOUSE).x(100).y(100))
Siarhei Vishniakou060f82b2023-01-27 06:39:14 -08003020 .build()));
3021
3022 // Move mouse cursor
3023 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07003024 injectMotionEvent(*mDispatcher,
Siarhei Vishniakou060f82b2023-01-27 06:39:14 -08003025 MotionEventBuilder(AMOTION_EVENT_ACTION_HOVER_MOVE,
3026 AINPUT_SOURCE_MOUSE)
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07003027 .pointer(PointerBuilder(0, ToolType::MOUSE).x(110).y(110))
Siarhei Vishniakou060f82b2023-01-27 06:39:14 -08003028 .build()));
3029
3030 window->consumeMotionEvent(AllOf(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_ENTER),
3031 WithSource(AINPUT_SOURCE_MOUSE)));
3032 spyWindow->consumeMotionEvent(AllOf(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_ENTER),
3033 WithSource(AINPUT_SOURCE_MOUSE)));
3034 window->consumeMotionEvent(AllOf(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_MOVE),
3035 WithSource(AINPUT_SOURCE_MOUSE)));
3036 spyWindow->consumeMotionEvent(AllOf(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_MOVE),
3037 WithSource(AINPUT_SOURCE_MOUSE)));
3038 // Touch down on the window
3039 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07003040 injectMotionEvent(*mDispatcher,
Siarhei Vishniakou060f82b2023-01-27 06:39:14 -08003041 MotionEventBuilder(AMOTION_EVENT_ACTION_DOWN,
3042 AINPUT_SOURCE_TOUCHSCREEN)
3043 .deviceId(SECOND_DEVICE_ID)
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07003044 .pointer(PointerBuilder(0, ToolType::FINGER).x(200).y(200))
Siarhei Vishniakou060f82b2023-01-27 06:39:14 -08003045 .build()));
3046 window->consumeMotionEvent(AllOf(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_EXIT),
3047 WithSource(AINPUT_SOURCE_MOUSE)));
3048 spyWindow->consumeMotionEvent(AllOf(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_EXIT),
3049 WithSource(AINPUT_SOURCE_MOUSE)));
3050 window->consumeMotionEvent(AllOf(WithMotionAction(AMOTION_EVENT_ACTION_DOWN),
3051 WithSource(AINPUT_SOURCE_TOUCHSCREEN)));
3052 spyWindow->consumeMotionEvent(AllOf(WithMotionAction(AMOTION_EVENT_ACTION_DOWN),
3053 WithSource(AINPUT_SOURCE_TOUCHSCREEN)));
3054
3055 // pilfer the motion, retaining the gesture on the spy window.
3056 EXPECT_EQ(OK, mDispatcher->pilferPointers(spyWindow->getToken()));
3057 window->consumeMotionEvent(AllOf(WithMotionAction(AMOTION_EVENT_ACTION_CANCEL),
3058 WithSource(AINPUT_SOURCE_TOUCHSCREEN)));
3059
3060 // Touch UP on the window
3061 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07003062 injectMotionEvent(*mDispatcher,
Siarhei Vishniakou060f82b2023-01-27 06:39:14 -08003063 MotionEventBuilder(AMOTION_EVENT_ACTION_UP,
3064 AINPUT_SOURCE_TOUCHSCREEN)
3065 .deviceId(SECOND_DEVICE_ID)
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07003066 .pointer(PointerBuilder(0, ToolType::FINGER).x(200).y(200))
Siarhei Vishniakou060f82b2023-01-27 06:39:14 -08003067 .build()));
3068 spyWindow->consumeMotionEvent(AllOf(WithMotionAction(AMOTION_EVENT_ACTION_UP),
3069 WithSource(AINPUT_SOURCE_TOUCHSCREEN)));
3070
3071 // Previously, a touch was pilfered. However, that gesture was just finished. Now, we are going
3072 // to send a new gesture. It should again go to both windows (spy and the window below), just
3073 // like the first gesture did, before pilfering. The window configuration has not changed.
3074
3075 // One more tap - DOWN
3076 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07003077 injectMotionEvent(*mDispatcher,
Siarhei Vishniakou060f82b2023-01-27 06:39:14 -08003078 MotionEventBuilder(AMOTION_EVENT_ACTION_DOWN,
3079 AINPUT_SOURCE_TOUCHSCREEN)
3080 .deviceId(SECOND_DEVICE_ID)
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07003081 .pointer(PointerBuilder(0, ToolType::FINGER).x(250).y(250))
Siarhei Vishniakou060f82b2023-01-27 06:39:14 -08003082 .build()));
3083 window->consumeMotionEvent(AllOf(WithMotionAction(AMOTION_EVENT_ACTION_DOWN),
3084 WithSource(AINPUT_SOURCE_TOUCHSCREEN)));
3085 spyWindow->consumeMotionEvent(AllOf(WithMotionAction(AMOTION_EVENT_ACTION_DOWN),
3086 WithSource(AINPUT_SOURCE_TOUCHSCREEN)));
3087
3088 // Touch UP on the window
3089 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07003090 injectMotionEvent(*mDispatcher,
Siarhei Vishniakou060f82b2023-01-27 06:39:14 -08003091 MotionEventBuilder(AMOTION_EVENT_ACTION_UP,
3092 AINPUT_SOURCE_TOUCHSCREEN)
3093 .deviceId(SECOND_DEVICE_ID)
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07003094 .pointer(PointerBuilder(0, ToolType::FINGER).x(250).y(250))
Siarhei Vishniakou060f82b2023-01-27 06:39:14 -08003095 .build()));
3096 window->consumeMotionEvent(AllOf(WithMotionAction(AMOTION_EVENT_ACTION_UP),
3097 WithSource(AINPUT_SOURCE_TOUCHSCREEN)));
3098 spyWindow->consumeMotionEvent(AllOf(WithMotionAction(AMOTION_EVENT_ACTION_UP),
3099 WithSource(AINPUT_SOURCE_TOUCHSCREEN)));
3100
3101 window->assertNoEvents();
3102 spyWindow->assertNoEvents();
3103}
3104
Garfield Tandf26e862020-07-01 20:18:19 -07003105// This test is different from the test above that HOVER_ENTER and HOVER_EXIT events are injected
3106// directly in this test.
3107TEST_F(InputDispatcherTest, HoverEnterMouseClickAndHoverExit) {
Chris Yea209fde2020-07-22 13:54:51 -07003108 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
Garfield Tandf26e862020-07-01 20:18:19 -07003109 sp<FakeWindowHandle> window =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07003110 sp<FakeWindowHandle>::make(application, mDispatcher, "Window", ADISPLAY_ID_DEFAULT);
Garfield Tandf26e862020-07-01 20:18:19 -07003111 window->setFrame(Rect(0, 0, 1200, 800));
Garfield Tandf26e862020-07-01 20:18:19 -07003112
3113 mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application);
3114
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07003115 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Garfield Tandf26e862020-07-01 20:18:19 -07003116
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08003117 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07003118 injectMotionEvent(*mDispatcher,
Garfield Tandf26e862020-07-01 20:18:19 -07003119 MotionEventBuilder(AMOTION_EVENT_ACTION_HOVER_ENTER,
3120 AINPUT_SOURCE_MOUSE)
Siarhei Vishniakou6d73f832022-07-21 17:27:03 -07003121 .pointer(PointerBuilder(0, ToolType::MOUSE).x(300).y(400))
Garfield Tandf26e862020-07-01 20:18:19 -07003122 .build()));
Siarhei Vishniakou5cee1e32022-11-29 12:35:39 -08003123 window->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_ENTER));
Garfield Tandf26e862020-07-01 20:18:19 -07003124 // Inject a series of mouse events for a mouse click
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08003125 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07003126 injectMotionEvent(*mDispatcher,
Garfield Tandf26e862020-07-01 20:18:19 -07003127 MotionEventBuilder(AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_MOUSE)
3128 .buttonState(AMOTION_EVENT_BUTTON_PRIMARY)
Siarhei Vishniakou6d73f832022-07-21 17:27:03 -07003129 .pointer(PointerBuilder(0, ToolType::MOUSE).x(300).y(400))
Garfield Tandf26e862020-07-01 20:18:19 -07003130 .build()));
Siarhei Vishniakouf372b812023-02-14 18:06:51 -08003131 window->consumeMotionEvent(WithMotionAction(ACTION_HOVER_EXIT));
3132 window->consumeMotionEvent(WithMotionAction(ACTION_DOWN));
Garfield Tandf26e862020-07-01 20:18:19 -07003133
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08003134 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07003135 injectMotionEvent(*mDispatcher,
Garfield Tandf26e862020-07-01 20:18:19 -07003136 MotionEventBuilder(AMOTION_EVENT_ACTION_BUTTON_PRESS,
3137 AINPUT_SOURCE_MOUSE)
3138 .buttonState(AMOTION_EVENT_BUTTON_PRIMARY)
3139 .actionButton(AMOTION_EVENT_BUTTON_PRIMARY)
Siarhei Vishniakou6d73f832022-07-21 17:27:03 -07003140 .pointer(PointerBuilder(0, ToolType::MOUSE).x(300).y(400))
Garfield Tandf26e862020-07-01 20:18:19 -07003141 .build()));
Siarhei Vishniakou5cee1e32022-11-29 12:35:39 -08003142 window->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_BUTTON_PRESS));
Garfield Tandf26e862020-07-01 20:18:19 -07003143
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08003144 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07003145 injectMotionEvent(*mDispatcher,
Garfield Tandf26e862020-07-01 20:18:19 -07003146 MotionEventBuilder(AMOTION_EVENT_ACTION_BUTTON_RELEASE,
3147 AINPUT_SOURCE_MOUSE)
3148 .buttonState(0)
3149 .actionButton(AMOTION_EVENT_BUTTON_PRIMARY)
Siarhei Vishniakou6d73f832022-07-21 17:27:03 -07003150 .pointer(PointerBuilder(0, ToolType::MOUSE).x(300).y(400))
Garfield Tandf26e862020-07-01 20:18:19 -07003151 .build()));
Siarhei Vishniakou5cee1e32022-11-29 12:35:39 -08003152 window->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_BUTTON_RELEASE));
Garfield Tandf26e862020-07-01 20:18:19 -07003153
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08003154 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07003155 injectMotionEvent(*mDispatcher,
Garfield Tandf26e862020-07-01 20:18:19 -07003156 MotionEventBuilder(AMOTION_EVENT_ACTION_UP, AINPUT_SOURCE_MOUSE)
3157 .buttonState(0)
Siarhei Vishniakou6d73f832022-07-21 17:27:03 -07003158 .pointer(PointerBuilder(0, ToolType::MOUSE).x(300).y(400))
Garfield Tandf26e862020-07-01 20:18:19 -07003159 .build()));
3160 window->consumeMotionUp(ADISPLAY_ID_DEFAULT);
3161
Siarhei Vishniakoua235c042023-05-02 09:59:09 -07003162 // We already canceled the hovering implicitly by injecting the "DOWN" event without lifting the
3163 // hover first. Therefore, injection of HOVER_EXIT is inconsistent, and should fail.
3164 ASSERT_EQ(InputEventInjectionResult::FAILED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07003165 injectMotionEvent(*mDispatcher,
Garfield Tandf26e862020-07-01 20:18:19 -07003166 MotionEventBuilder(AMOTION_EVENT_ACTION_HOVER_EXIT,
3167 AINPUT_SOURCE_MOUSE)
Siarhei Vishniakou6d73f832022-07-21 17:27:03 -07003168 .pointer(PointerBuilder(0, ToolType::MOUSE).x(300).y(400))
Garfield Tandf26e862020-07-01 20:18:19 -07003169 .build()));
Siarhei Vishniakouf372b812023-02-14 18:06:51 -08003170 window->assertNoEvents();
Garfield Tandf26e862020-07-01 20:18:19 -07003171}
3172
Siarhei Vishniakou0b0374d2022-11-17 17:40:53 -08003173/**
Siarhei Vishniakoub581f7f2022-12-07 20:23:06 +00003174 * Hover over a window, and then remove that window. Make sure that HOVER_EXIT for that event
3175 * is generated.
3176 */
3177TEST_F(InputDispatcherTest, HoverExitIsSentToRemovedWindow) {
3178 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
3179 sp<FakeWindowHandle> window =
3180 sp<FakeWindowHandle>::make(application, mDispatcher, "Window", ADISPLAY_ID_DEFAULT);
3181 window->setFrame(Rect(0, 0, 1200, 800));
3182
3183 mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application);
3184
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07003185 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Siarhei Vishniakoub581f7f2022-12-07 20:23:06 +00003186
3187 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07003188 injectMotionEvent(*mDispatcher,
Siarhei Vishniakoub581f7f2022-12-07 20:23:06 +00003189 MotionEventBuilder(AMOTION_EVENT_ACTION_HOVER_ENTER,
3190 AINPUT_SOURCE_MOUSE)
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07003191 .pointer(PointerBuilder(0, ToolType::MOUSE).x(300).y(400))
Siarhei Vishniakoub581f7f2022-12-07 20:23:06 +00003192 .build()));
3193 window->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_ENTER));
3194
3195 // Remove the window, but keep the channel.
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07003196 mDispatcher->onWindowInfosChanged({{}, {}, 0, 0});
Siarhei Vishniakoub581f7f2022-12-07 20:23:06 +00003197 window->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_EXIT));
3198}
3199
3200/**
Daniel Norman7487dfa2023-08-02 16:39:45 -07003201 * Test that invalid HOVER events sent by accessibility do not cause a fatal crash.
3202 */
Ameer Armalycff4fa52023-10-04 23:45:11 +00003203TEST_F_WITH_FLAGS(InputDispatcherTest, InvalidA11yHoverStreamDoesNotCrash,
3204 REQUIRES_FLAGS_DISABLED(ACONFIG_FLAG(com::android::input::flags,
3205 a11y_crash_on_inconsistent_event_stream))) {
Daniel Norman7487dfa2023-08-02 16:39:45 -07003206 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
3207 sp<FakeWindowHandle> window =
3208 sp<FakeWindowHandle>::make(application, mDispatcher, "Window", ADISPLAY_ID_DEFAULT);
3209 window->setFrame(Rect(0, 0, 1200, 800));
3210
3211 mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application);
3212
3213 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
3214
3215 MotionEventBuilder hoverEnterBuilder =
3216 MotionEventBuilder(AMOTION_EVENT_ACTION_HOVER_ENTER, AINPUT_SOURCE_MOUSE)
3217 .pointer(PointerBuilder(0, ToolType::MOUSE).x(300).y(400))
3218 .addFlag(AMOTION_EVENT_FLAG_IS_ACCESSIBILITY_EVENT);
3219 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
3220 injectMotionEvent(*mDispatcher, hoverEnterBuilder.build()));
3221 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
3222 injectMotionEvent(*mDispatcher, hoverEnterBuilder.build()));
3223 window->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_ENTER));
3224 window->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_ENTER));
3225}
3226
3227/**
Siarhei Vishniakou4e1ffa52023-02-21 11:50:34 -08003228 * If mouse is hovering when the touch goes down, the hovering should be stopped via HOVER_EXIT.
3229 */
3230TEST_F(InputDispatcherTest, TouchDownAfterMouseHover) {
3231 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
3232 sp<FakeWindowHandle> window =
3233 sp<FakeWindowHandle>::make(application, mDispatcher, "Window", ADISPLAY_ID_DEFAULT);
3234 window->setFrame(Rect(0, 0, 100, 100));
3235
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07003236 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Siarhei Vishniakou4e1ffa52023-02-21 11:50:34 -08003237
3238 const int32_t mouseDeviceId = 7;
3239 const int32_t touchDeviceId = 4;
Siarhei Vishniakou4e1ffa52023-02-21 11:50:34 -08003240
3241 // Start hovering with the mouse
Prabir Pradhan678438e2023-04-13 19:32:51 +00003242 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_ENTER, AINPUT_SOURCE_MOUSE)
3243 .deviceId(mouseDeviceId)
3244 .pointer(PointerBuilder(0, ToolType::MOUSE).x(10).y(10))
3245 .build());
Siarhei Vishniakou4e1ffa52023-02-21 11:50:34 -08003246 window->consumeMotionEvent(
3247 AllOf(WithMotionAction(ACTION_HOVER_ENTER), WithDeviceId(mouseDeviceId)));
3248
3249 // Touch goes down
Prabir Pradhan678438e2023-04-13 19:32:51 +00003250 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
3251 .deviceId(touchDeviceId)
3252 .pointer(PointerBuilder(0, ToolType::FINGER).x(50).y(50))
3253 .build());
Siarhei Vishniakou4e1ffa52023-02-21 11:50:34 -08003254
3255 window->consumeMotionEvent(
3256 AllOf(WithMotionAction(ACTION_HOVER_EXIT), WithDeviceId(mouseDeviceId)));
3257 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(touchDeviceId)));
3258}
3259
3260/**
Siarhei Vishniakou0b0374d2022-11-17 17:40:53 -08003261 * Inject a mouse hover event followed by a tap from touchscreen.
Siarhei Vishniakoub581f7f2022-12-07 20:23:06 +00003262 * The tap causes a HOVER_EXIT event to be generated because the current event
3263 * stream's source has been switched.
Siarhei Vishniakou0b0374d2022-11-17 17:40:53 -08003264 */
3265TEST_F(InputDispatcherTest, MouseHoverAndTouchTap) {
3266 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
3267 sp<FakeWindowHandle> window =
3268 sp<FakeWindowHandle>::make(application, mDispatcher, "Window", ADISPLAY_ID_DEFAULT);
3269 window->setFrame(Rect(0, 0, 100, 100));
3270
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07003271 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -07003272 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_MOVE, AINPUT_SOURCE_MOUSE)
3273 .pointer(PointerBuilder(0, ToolType::MOUSE).x(50).y(50))
3274 .build());
Siarhei Vishniakou0b0374d2022-11-17 17:40:53 -08003275 ASSERT_NO_FATAL_FAILURE(
3276 window->consumeMotionEvent(AllOf(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_ENTER),
3277 WithSource(AINPUT_SOURCE_MOUSE))));
Siarhei Vishniakou0b0374d2022-11-17 17:40:53 -08003278
3279 // Tap on the window
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -07003280 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
3281 .pointer(PointerBuilder(0, ToolType::FINGER).x(10).y(10))
3282 .build());
Siarhei Vishniakou0b0374d2022-11-17 17:40:53 -08003283 ASSERT_NO_FATAL_FAILURE(
Siarhei Vishniakoub581f7f2022-12-07 20:23:06 +00003284 window->consumeMotionEvent(AllOf(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_EXIT),
3285 WithSource(AINPUT_SOURCE_MOUSE))));
3286
3287 ASSERT_NO_FATAL_FAILURE(
Siarhei Vishniakou0b0374d2022-11-17 17:40:53 -08003288 window->consumeMotionEvent(AllOf(WithMotionAction(AMOTION_EVENT_ACTION_DOWN),
3289 WithSource(AINPUT_SOURCE_TOUCHSCREEN))));
3290
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -07003291 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN)
3292 .pointer(PointerBuilder(0, ToolType::FINGER).x(10).y(10))
3293 .build());
Siarhei Vishniakou0b0374d2022-11-17 17:40:53 -08003294 ASSERT_NO_FATAL_FAILURE(
3295 window->consumeMotionEvent(AllOf(WithMotionAction(AMOTION_EVENT_ACTION_UP),
3296 WithSource(AINPUT_SOURCE_TOUCHSCREEN))));
3297}
3298
Tommy Nordgrendae9dfc2022-10-13 11:25:57 +02003299TEST_F(InputDispatcherTest, HoverEnterMoveRemoveWindowsInSecondDisplay) {
3300 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
3301 sp<FakeWindowHandle> windowDefaultDisplay =
3302 sp<FakeWindowHandle>::make(application, mDispatcher, "DefaultDisplay",
3303 ADISPLAY_ID_DEFAULT);
3304 windowDefaultDisplay->setFrame(Rect(0, 0, 600, 800));
3305 sp<FakeWindowHandle> windowSecondDisplay =
3306 sp<FakeWindowHandle>::make(application, mDispatcher, "SecondDisplay",
3307 SECOND_DISPLAY_ID);
3308 windowSecondDisplay->setFrame(Rect(0, 0, 600, 800));
3309
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07003310 mDispatcher->onWindowInfosChanged(
3311 {{*windowDefaultDisplay->getInfo(), *windowSecondDisplay->getInfo()}, {}, 0, 0});
Tommy Nordgrendae9dfc2022-10-13 11:25:57 +02003312
3313 // Set cursor position in window in default display and check that hover enter and move
3314 // events are generated.
3315 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07003316 injectMotionEvent(*mDispatcher,
Tommy Nordgrendae9dfc2022-10-13 11:25:57 +02003317 MotionEventBuilder(AMOTION_EVENT_ACTION_HOVER_MOVE,
3318 AINPUT_SOURCE_MOUSE)
3319 .displayId(ADISPLAY_ID_DEFAULT)
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07003320 .pointer(PointerBuilder(0, ToolType::MOUSE).x(300).y(600))
Tommy Nordgrendae9dfc2022-10-13 11:25:57 +02003321 .build()));
Siarhei Vishniakou5cee1e32022-11-29 12:35:39 -08003322 windowDefaultDisplay->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_ENTER));
Tommy Nordgrendae9dfc2022-10-13 11:25:57 +02003323
3324 // Remove all windows in secondary display and check that no event happens on window in
3325 // primary display.
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07003326 mDispatcher->onWindowInfosChanged({{*windowDefaultDisplay->getInfo()}, {}, 0, 0});
3327
Tommy Nordgrendae9dfc2022-10-13 11:25:57 +02003328 windowDefaultDisplay->assertNoEvents();
3329
3330 // Move cursor position in window in default display and check that only hover move
3331 // event is generated and not hover enter event.
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07003332 mDispatcher->onWindowInfosChanged(
3333 {{*windowDefaultDisplay->getInfo(), *windowSecondDisplay->getInfo()}, {}, 0, 0});
Tommy Nordgrendae9dfc2022-10-13 11:25:57 +02003334 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07003335 injectMotionEvent(*mDispatcher,
Tommy Nordgrendae9dfc2022-10-13 11:25:57 +02003336 MotionEventBuilder(AMOTION_EVENT_ACTION_HOVER_MOVE,
3337 AINPUT_SOURCE_MOUSE)
3338 .displayId(ADISPLAY_ID_DEFAULT)
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07003339 .pointer(PointerBuilder(0, ToolType::MOUSE).x(400).y(700))
Tommy Nordgrendae9dfc2022-10-13 11:25:57 +02003340 .build()));
Siarhei Vishniakou5cee1e32022-11-29 12:35:39 -08003341 windowDefaultDisplay->consumeMotionEvent(
3342 AllOf(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_MOVE),
3343 WithSource(AINPUT_SOURCE_MOUSE)));
Tommy Nordgrendae9dfc2022-10-13 11:25:57 +02003344 windowDefaultDisplay->assertNoEvents();
3345}
3346
Garfield Tan00f511d2019-06-12 16:55:40 -07003347TEST_F(InputDispatcherTest, DispatchMouseEventsUnderCursor) {
Chris Yea209fde2020-07-22 13:54:51 -07003348 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
Garfield Tan00f511d2019-06-12 16:55:40 -07003349
3350 sp<FakeWindowHandle> windowLeft =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07003351 sp<FakeWindowHandle>::make(application, mDispatcher, "Left", ADISPLAY_ID_DEFAULT);
Garfield Tan00f511d2019-06-12 16:55:40 -07003352 windowLeft->setFrame(Rect(0, 0, 600, 800));
Garfield Tan00f511d2019-06-12 16:55:40 -07003353 sp<FakeWindowHandle> windowRight =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07003354 sp<FakeWindowHandle>::make(application, mDispatcher, "Right", ADISPLAY_ID_DEFAULT);
Garfield Tan00f511d2019-06-12 16:55:40 -07003355 windowRight->setFrame(Rect(600, 0, 1200, 800));
Garfield Tan00f511d2019-06-12 16:55:40 -07003356
3357 mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application);
3358
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07003359 mDispatcher->onWindowInfosChanged(
3360 {{*windowLeft->getInfo(), *windowRight->getInfo()}, {}, 0, 0});
Garfield Tan00f511d2019-06-12 16:55:40 -07003361
3362 // Inject an event with coordinate in the area of right window, with mouse cursor in the area of
3363 // left window. This event should be dispatched to the left window.
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08003364 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07003365 injectMotionEvent(*mDispatcher, AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_MOUSE,
Siarhei Vishniakou4cb50ca2020-05-26 21:43:02 -07003366 ADISPLAY_ID_DEFAULT, {610, 400}, {599, 400}));
Siarhei Vishniakouc5ca85c2019-11-15 17:20:00 -08003367 windowLeft->consumeMotionDown(ADISPLAY_ID_DEFAULT);
Garfield Tan00f511d2019-06-12 16:55:40 -07003368 windowRight->assertNoEvents();
3369}
3370
Siarhei Vishniakou2bfa9052019-11-21 18:10:54 -08003371TEST_F(InputDispatcherTest, NotifyDeviceReset_CancelsKeyStream) {
Chris Yea209fde2020-07-22 13:54:51 -07003372 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07003373 sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher,
3374 "Fake Window", ADISPLAY_ID_DEFAULT);
Vishnu Nair47074b82020-08-14 11:54:47 -07003375 window->setFocusable(true);
Siarhei Vishniakou2bfa9052019-11-21 18:10:54 -08003376
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07003377 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Vishnu Nair958da932020-08-21 17:12:37 -07003378 setFocusedWindow(window);
3379
Siarhei Vishniakouf1035d42019-09-20 16:32:01 +01003380 window->consumeFocusEvent(true);
Siarhei Vishniakou2bfa9052019-11-21 18:10:54 -08003381
Prabir Pradhan678438e2023-04-13 19:32:51 +00003382 mDispatcher->notifyKey(generateKeyArgs(AKEY_EVENT_ACTION_DOWN, ADISPLAY_ID_DEFAULT));
Siarhei Vishniakou2bfa9052019-11-21 18:10:54 -08003383
3384 // Window should receive key down event.
3385 window->consumeKeyDown(ADISPLAY_ID_DEFAULT);
3386
3387 // When device reset happens, that key stream should be terminated with FLAG_CANCELED
3388 // on the app side.
Prabir Pradhan678438e2023-04-13 19:32:51 +00003389 mDispatcher->notifyDeviceReset({/*id=*/10, /*eventTime=*/20, DEVICE_ID});
Prabir Pradhan7662a8d2023-12-15 01:58:14 +00003390 window->consumeKeyUp(ADISPLAY_ID_DEFAULT, AKEY_EVENT_FLAG_CANCELED);
Siarhei Vishniakou2bfa9052019-11-21 18:10:54 -08003391}
3392
3393TEST_F(InputDispatcherTest, NotifyDeviceReset_CancelsMotionStream) {
Chris Yea209fde2020-07-22 13:54:51 -07003394 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07003395 sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher,
3396 "Fake Window", ADISPLAY_ID_DEFAULT);
Siarhei Vishniakou2bfa9052019-11-21 18:10:54 -08003397
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07003398 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Siarhei Vishniakou2bfa9052019-11-21 18:10:54 -08003399
Prabir Pradhan678438e2023-04-13 19:32:51 +00003400 mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_DOWN,
3401 AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT));
Siarhei Vishniakou2bfa9052019-11-21 18:10:54 -08003402
3403 // Window should receive motion down event.
3404 window->consumeMotionDown(ADISPLAY_ID_DEFAULT);
3405
3406 // When device reset happens, that motion stream should be terminated with ACTION_CANCEL
3407 // on the app side.
Prabir Pradhan678438e2023-04-13 19:32:51 +00003408 mDispatcher->notifyDeviceReset({/*id=*/10, /*eventTime=*/20, DEVICE_ID});
Siarhei Vishniakou1ae72f12023-01-29 12:55:30 -08003409 window->consumeMotionEvent(
3410 AllOf(WithMotionAction(ACTION_CANCEL), WithDisplayId(ADISPLAY_ID_DEFAULT)));
Siarhei Vishniakou2bfa9052019-11-21 18:10:54 -08003411}
3412
Siarhei Vishniakou0686f0c2023-05-02 11:56:15 -07003413TEST_F(InputDispatcherTest, NotifyDeviceResetCancelsHoveringStream) {
3414 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
3415 sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher,
3416 "Fake Window", ADISPLAY_ID_DEFAULT);
3417
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07003418 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Siarhei Vishniakou0686f0c2023-05-02 11:56:15 -07003419
3420 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_ENTER, AINPUT_SOURCE_STYLUS)
3421 .pointer(PointerBuilder(0, ToolType::STYLUS).x(10).y(10))
3422 .build());
3423
3424 window->consumeMotionEvent(WithMotionAction(ACTION_HOVER_ENTER));
3425
3426 // When device reset happens, that hover stream should be terminated with ACTION_HOVER_EXIT
3427 mDispatcher->notifyDeviceReset({/*id=*/10, /*eventTime=*/20, DEVICE_ID});
3428 window->consumeMotionEvent(WithMotionAction(ACTION_HOVER_EXIT));
3429
3430 // After the device has been reset, a new hovering stream can be sent to the window
3431 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_ENTER, AINPUT_SOURCE_STYLUS)
3432 .pointer(PointerBuilder(0, ToolType::STYLUS).x(15).y(15))
3433 .build());
3434 window->consumeMotionEvent(WithMotionAction(ACTION_HOVER_ENTER));
3435}
3436
Arthur Hung2ee6d0b2022-03-03 20:19:38 +08003437TEST_F(InputDispatcherTest, InterceptKeyByPolicy) {
3438 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07003439 sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher,
3440 "Fake Window", ADISPLAY_ID_DEFAULT);
Arthur Hung2ee6d0b2022-03-03 20:19:38 +08003441 window->setFocusable(true);
3442
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07003443 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Arthur Hung2ee6d0b2022-03-03 20:19:38 +08003444 setFocusedWindow(window);
3445
3446 window->consumeFocusEvent(true);
3447
Prabir Pradhan678438e2023-04-13 19:32:51 +00003448 const NotifyKeyArgs keyArgs = generateKeyArgs(AKEY_EVENT_ACTION_DOWN, ADISPLAY_ID_DEFAULT);
Arthur Hung2ee6d0b2022-03-03 20:19:38 +08003449 const std::chrono::milliseconds interceptKeyTimeout = 50ms;
3450 const nsecs_t injectTime = keyArgs.eventTime;
3451 mFakePolicy->setInterceptKeyTimeout(interceptKeyTimeout);
Prabir Pradhan678438e2023-04-13 19:32:51 +00003452 mDispatcher->notifyKey(keyArgs);
Arthur Hung2ee6d0b2022-03-03 20:19:38 +08003453 // The dispatching time should be always greater than or equal to intercept key timeout.
3454 window->consumeKeyDown(ADISPLAY_ID_DEFAULT);
3455 ASSERT_TRUE((systemTime(SYSTEM_TIME_MONOTONIC) - injectTime) >=
3456 std::chrono::nanoseconds(interceptKeyTimeout).count());
3457}
3458
Siarhei Vishniakouf54d2ab2023-06-09 13:23:53 -07003459/**
3460 * Keys with ACTION_UP are delivered immediately, even if a long 'intercept key timeout' is set.
3461 */
Arthur Hung2ee6d0b2022-03-03 20:19:38 +08003462TEST_F(InputDispatcherTest, InterceptKeyIfKeyUp) {
3463 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07003464 sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher,
3465 "Fake Window", ADISPLAY_ID_DEFAULT);
Arthur Hung2ee6d0b2022-03-03 20:19:38 +08003466 window->setFocusable(true);
3467
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07003468 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Arthur Hung2ee6d0b2022-03-03 20:19:38 +08003469 setFocusedWindow(window);
3470
3471 window->consumeFocusEvent(true);
3472
Prabir Pradhan678438e2023-04-13 19:32:51 +00003473 mDispatcher->notifyKey(generateKeyArgs(AKEY_EVENT_ACTION_DOWN, ADISPLAY_ID_DEFAULT));
Arthur Hung2ee6d0b2022-03-03 20:19:38 +08003474 window->consumeKeyDown(ADISPLAY_ID_DEFAULT);
Siarhei Vishniakouf54d2ab2023-06-09 13:23:53 -07003475
3476 // Set a value that's significantly larger than the default consumption timeout. If the
3477 // implementation is correct, the actual value doesn't matter; it won't slow down the test.
3478 mFakePolicy->setInterceptKeyTimeout(600ms);
3479 mDispatcher->notifyKey(generateKeyArgs(AKEY_EVENT_ACTION_UP, ADISPLAY_ID_DEFAULT));
3480 // Window should receive key event immediately when same key up.
Arthur Hung2ee6d0b2022-03-03 20:19:38 +08003481 window->consumeKeyUp(ADISPLAY_ID_DEFAULT);
3482}
3483
Prabir Pradhanc44ce4d2021-10-05 05:26:29 -07003484/**
Siarhei Vishniakou487c49b2022-12-02 15:48:57 -08003485 * Two windows. First is a regular window. Second does not overlap with the first, and has
3486 * WATCH_OUTSIDE_TOUCH.
3487 * Both windows are owned by the same UID.
3488 * Tap first window. Make sure that the second window receives ACTION_OUTSIDE with correct, non-zero
3489 * coordinates. The coordinates are not zeroed out because both windows are owned by the same UID.
3490 */
3491TEST_F(InputDispatcherTest, ActionOutsideForOwnedWindowHasValidCoordinates) {
3492 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -07003493 sp<FakeWindowHandle> window =
3494 sp<FakeWindowHandle>::make(application, mDispatcher, "Window", ADISPLAY_ID_DEFAULT);
Siarhei Vishniakou487c49b2022-12-02 15:48:57 -08003495 window->setFrame(Rect{0, 0, 100, 100});
3496
3497 sp<FakeWindowHandle> outsideWindow =
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -07003498 sp<FakeWindowHandle>::make(application, mDispatcher, "Outside Window",
Siarhei Vishniakou487c49b2022-12-02 15:48:57 -08003499 ADISPLAY_ID_DEFAULT);
3500 outsideWindow->setFrame(Rect{100, 100, 200, 200});
3501 outsideWindow->setWatchOutsideTouch(true);
3502 // outsideWindow must be above 'window' to receive ACTION_OUTSIDE events when 'window' is tapped
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07003503 mDispatcher->onWindowInfosChanged({{*outsideWindow->getInfo(), *window->getInfo()}, {}, 0, 0});
Siarhei Vishniakou487c49b2022-12-02 15:48:57 -08003504
3505 // Tap on first window.
Prabir Pradhan678438e2023-04-13 19:32:51 +00003506 mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_DOWN,
3507 AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
3508 {PointF{50, 50}}));
Siarhei Vishniakou487c49b2022-12-02 15:48:57 -08003509 window->consumeMotionDown();
3510 // The coordinates of the tap in 'outsideWindow' are relative to its top left corner.
3511 // Therefore, we should offset them by (100, 100) relative to the screen's top left corner.
3512 outsideWindow->consumeMotionEvent(
3513 AllOf(WithMotionAction(ACTION_OUTSIDE), WithCoords(-50, -50)));
Prabir Pradhan502a7252023-12-01 16:11:24 +00003514
3515 // Ensure outsideWindow doesn't get any more events for the gesture.
3516 mDispatcher->notifyMotion(generateMotionArgs(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN,
3517 ADISPLAY_ID_DEFAULT, {PointF{51, 51}}));
3518 window->consumeMotionMove();
3519 outsideWindow->assertNoEvents();
Siarhei Vishniakou487c49b2022-12-02 15:48:57 -08003520}
3521
3522/**
Prabir Pradhanb60b1dc2022-03-15 14:02:35 +00003523 * This test documents the behavior of WATCH_OUTSIDE_TOUCH. The window will get ACTION_OUTSIDE when
3524 * a another pointer causes ACTION_DOWN to be sent to another window for the first time. Only one
3525 * ACTION_OUTSIDE event is sent per gesture.
3526 */
3527TEST_F(InputDispatcherTest, ActionOutsideSentOnlyWhenAWindowIsTouched) {
3528 // There are three windows that do not overlap. `window` wants to WATCH_OUTSIDE_TOUCH.
3529 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07003530 sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher,
3531 "First Window", ADISPLAY_ID_DEFAULT);
Prabir Pradhanb60b1dc2022-03-15 14:02:35 +00003532 window->setWatchOutsideTouch(true);
3533 window->setFrame(Rect{0, 0, 100, 100});
3534 sp<FakeWindowHandle> secondWindow =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07003535 sp<FakeWindowHandle>::make(application, mDispatcher, "Second Window",
3536 ADISPLAY_ID_DEFAULT);
Prabir Pradhanb60b1dc2022-03-15 14:02:35 +00003537 secondWindow->setFrame(Rect{100, 100, 200, 200});
3538 sp<FakeWindowHandle> thirdWindow =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07003539 sp<FakeWindowHandle>::make(application, mDispatcher, "Third Window",
3540 ADISPLAY_ID_DEFAULT);
Prabir Pradhanb60b1dc2022-03-15 14:02:35 +00003541 thirdWindow->setFrame(Rect{200, 200, 300, 300});
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07003542 mDispatcher->onWindowInfosChanged(
3543 {{*window->getInfo(), *secondWindow->getInfo(), *thirdWindow->getInfo()}, {}, 0, 0});
Prabir Pradhanb60b1dc2022-03-15 14:02:35 +00003544
3545 // First pointer lands outside all windows. `window` does not get ACTION_OUTSIDE.
Prabir Pradhan678438e2023-04-13 19:32:51 +00003546 mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_DOWN,
3547 AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
3548 {PointF{-10, -10}}));
Prabir Pradhanb60b1dc2022-03-15 14:02:35 +00003549 window->assertNoEvents();
3550 secondWindow->assertNoEvents();
3551
3552 // The second pointer lands inside `secondWindow`, which should receive a DOWN event.
3553 // Now, `window` should get ACTION_OUTSIDE.
Prabir Pradhan678438e2023-04-13 19:32:51 +00003554 mDispatcher->notifyMotion(generateMotionArgs(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN,
3555 ADISPLAY_ID_DEFAULT,
3556 {PointF{-10, -10}, PointF{105, 105}}));
Siarhei Vishniakou487c49b2022-12-02 15:48:57 -08003557 const std::map<int32_t, PointF> expectedPointers{{0, PointF{-10, -10}}, {1, PointF{105, 105}}};
3558 window->consumeMotionEvent(
3559 AllOf(WithMotionAction(ACTION_OUTSIDE), WithPointers(expectedPointers)));
Prabir Pradhanb60b1dc2022-03-15 14:02:35 +00003560 secondWindow->consumeMotionDown();
3561 thirdWindow->assertNoEvents();
3562
3563 // The third pointer lands inside `thirdWindow`, which should receive a DOWN event. There is
3564 // no ACTION_OUTSIDE sent to `window` because one has already been sent for this gesture.
Prabir Pradhan678438e2023-04-13 19:32:51 +00003565 mDispatcher->notifyMotion(
3566 generateMotionArgs(POINTER_2_DOWN, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
3567 {PointF{-10, -10}, PointF{105, 105}, PointF{205, 205}}));
Prabir Pradhanb60b1dc2022-03-15 14:02:35 +00003568 window->assertNoEvents();
3569 secondWindow->consumeMotionMove();
3570 thirdWindow->consumeMotionDown();
3571}
3572
Prabir Pradhan814fe082022-07-22 20:22:18 +00003573TEST_F(InputDispatcherTest, OnWindowInfosChanged_RemoveAllWindowsOnDisplay) {
3574 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07003575 sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher,
3576 "Fake Window", ADISPLAY_ID_DEFAULT);
Prabir Pradhan814fe082022-07-22 20:22:18 +00003577 window->setFocusable(true);
3578
Patrick Williamsd828f302023-04-28 17:52:08 -05003579 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Prabir Pradhan814fe082022-07-22 20:22:18 +00003580 setFocusedWindow(window);
3581
3582 window->consumeFocusEvent(true);
3583
Prabir Pradhan678438e2023-04-13 19:32:51 +00003584 const NotifyKeyArgs keyDown = generateKeyArgs(AKEY_EVENT_ACTION_DOWN, ADISPLAY_ID_DEFAULT);
3585 const NotifyKeyArgs keyUp = generateKeyArgs(AKEY_EVENT_ACTION_UP, ADISPLAY_ID_DEFAULT);
3586 mDispatcher->notifyKey(keyDown);
3587 mDispatcher->notifyKey(keyUp);
Prabir Pradhan814fe082022-07-22 20:22:18 +00003588
3589 window->consumeKeyDown(ADISPLAY_ID_DEFAULT);
3590 window->consumeKeyUp(ADISPLAY_ID_DEFAULT);
3591
3592 // All windows are removed from the display. Ensure that we can no longer dispatch to it.
Patrick Williamsd828f302023-04-28 17:52:08 -05003593 mDispatcher->onWindowInfosChanged({{}, {}, 0, 0});
Prabir Pradhan814fe082022-07-22 20:22:18 +00003594
3595 window->consumeFocusEvent(false);
3596
Prabir Pradhan678438e2023-04-13 19:32:51 +00003597 mDispatcher->notifyKey(keyDown);
3598 mDispatcher->notifyKey(keyUp);
Prabir Pradhan814fe082022-07-22 20:22:18 +00003599 window->assertNoEvents();
3600}
3601
Arthur Hung96483742022-11-15 03:30:48 +00003602TEST_F(InputDispatcherTest, NonSplitTouchableWindowReceivesMultiTouch) {
3603 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
3604 sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher,
3605 "Fake Window", ADISPLAY_ID_DEFAULT);
3606 // Ensure window is non-split and have some transform.
3607 window->setPreventSplitting(true);
3608 window->setWindowOffset(20, 40);
Patrick Williamsd828f302023-04-28 17:52:08 -05003609 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Arthur Hung96483742022-11-15 03:30:48 +00003610
3611 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07003612 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
Arthur Hung96483742022-11-15 03:30:48 +00003613 {50, 50}))
3614 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
3615 window->consumeMotionDown(ADISPLAY_ID_DEFAULT);
3616
3617 const MotionEvent secondFingerDownEvent =
3618 MotionEventBuilder(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
3619 .displayId(ADISPLAY_ID_DEFAULT)
3620 .eventTime(systemTime(SYSTEM_TIME_MONOTONIC))
Siarhei Vishniakou6d73f832022-07-21 17:27:03 -07003621 .pointer(PointerBuilder(/*id=*/0, ToolType::FINGER).x(50).y(50))
3622 .pointer(PointerBuilder(/*id=*/1, ToolType::FINGER).x(-30).y(-50))
Arthur Hung96483742022-11-15 03:30:48 +00003623 .build();
3624 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07003625 injectMotionEvent(*mDispatcher, secondFingerDownEvent, INJECT_EVENT_TIMEOUT,
Arthur Hung96483742022-11-15 03:30:48 +00003626 InputEventInjectionSync::WAIT_FOR_RESULT))
3627 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
3628
Siarhei Vishniakoud3061ab2023-12-18 20:41:08 -08003629 std::unique_ptr<MotionEvent> event = window->consumeMotionEvent();
3630 ASSERT_NE(nullptr, event);
3631 EXPECT_EQ(POINTER_1_DOWN, event->getAction());
3632 EXPECT_EQ(70, event->getX(0)); // 50 + 20
3633 EXPECT_EQ(90, event->getY(0)); // 50 + 40
3634 EXPECT_EQ(-10, event->getX(1)); // -30 + 20
3635 EXPECT_EQ(-10, event->getY(1)); // -50 + 40
Arthur Hung96483742022-11-15 03:30:48 +00003636}
3637
Siarhei Vishniakou25537f82023-07-18 14:35:47 -07003638/**
3639 * Two windows: a splittable and a non-splittable.
3640 * The non-splittable window shouldn't receive any "incomplete" gestures.
3641 * Send the first pointer to the splittable window, and then touch the non-splittable window.
3642 * The second pointer should be dropped because the initial window is splittable, so it won't get
3643 * any pointers outside of it, and the second window is non-splittable, so it shouldn't get any
3644 * "incomplete" gestures.
3645 */
3646TEST_F(InputDispatcherTest, SplittableAndNonSplittableWindows) {
3647 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
3648 sp<FakeWindowHandle> leftWindow =
3649 sp<FakeWindowHandle>::make(application, mDispatcher, "Left splittable Window",
3650 ADISPLAY_ID_DEFAULT);
3651 leftWindow->setPreventSplitting(false);
3652 leftWindow->setFrame(Rect(0, 0, 100, 100));
3653 sp<FakeWindowHandle> rightWindow =
3654 sp<FakeWindowHandle>::make(application, mDispatcher, "Right non-splittable Window",
3655 ADISPLAY_ID_DEFAULT);
3656 rightWindow->setPreventSplitting(true);
3657 rightWindow->setFrame(Rect(100, 100, 200, 200));
3658 mDispatcher->onWindowInfosChanged(
3659 {{*leftWindow->getInfo(), *rightWindow->getInfo()}, {}, 0, 0});
3660
3661 // Touch down on left, splittable window
3662 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
3663 .pointer(PointerBuilder(0, ToolType::FINGER).x(50).y(50))
3664 .build());
3665 leftWindow->consumeMotionEvent(WithMotionAction(ACTION_DOWN));
3666
3667 mDispatcher->notifyMotion(
3668 MotionArgsBuilder(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
3669 .pointer(PointerBuilder(/*id=*/0, ToolType::FINGER).x(50).y(50))
3670 .pointer(PointerBuilder(/*id=*/1, ToolType::FINGER).x(150).y(150))
3671 .build());
3672 leftWindow->assertNoEvents();
3673 rightWindow->assertNoEvents();
3674}
3675
Harry Cuttsb166c002023-05-09 13:06:05 +00003676TEST_F(InputDispatcherTest, TouchpadThreeFingerSwipeOnlySentToTrustedOverlays) {
3677 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
3678 sp<FakeWindowHandle> window =
3679 sp<FakeWindowHandle>::make(application, mDispatcher, "Window", ADISPLAY_ID_DEFAULT);
3680 window->setFrame(Rect(0, 0, 400, 400));
3681 sp<FakeWindowHandle> trustedOverlay =
3682 sp<FakeWindowHandle>::make(application, mDispatcher, "Trusted Overlay",
3683 ADISPLAY_ID_DEFAULT);
3684 trustedOverlay->setSpy(true);
3685 trustedOverlay->setTrustedOverlay(true);
3686
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07003687 mDispatcher->onWindowInfosChanged({{*trustedOverlay->getInfo(), *window->getInfo()}, {}, 0, 0});
Harry Cuttsb166c002023-05-09 13:06:05 +00003688
3689 // Start a three-finger touchpad swipe
3690 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_MOUSE)
3691 .pointer(PointerBuilder(0, ToolType::FINGER).x(200).y(100))
3692 .classification(MotionClassification::MULTI_FINGER_SWIPE)
3693 .build());
3694 mDispatcher->notifyMotion(MotionArgsBuilder(POINTER_1_DOWN, AINPUT_SOURCE_MOUSE)
3695 .pointer(PointerBuilder(0, ToolType::FINGER).x(200).y(100))
3696 .pointer(PointerBuilder(1, ToolType::FINGER).x(250).y(100))
3697 .classification(MotionClassification::MULTI_FINGER_SWIPE)
3698 .build());
3699 mDispatcher->notifyMotion(MotionArgsBuilder(POINTER_2_DOWN, AINPUT_SOURCE_MOUSE)
3700 .pointer(PointerBuilder(0, ToolType::FINGER).x(200).y(100))
3701 .pointer(PointerBuilder(1, ToolType::FINGER).x(250).y(100))
3702 .pointer(PointerBuilder(2, ToolType::FINGER).x(300).y(100))
3703 .classification(MotionClassification::MULTI_FINGER_SWIPE)
3704 .build());
3705
3706 trustedOverlay->consumeMotionEvent(WithMotionAction(ACTION_DOWN));
3707 trustedOverlay->consumeMotionEvent(WithMotionAction(POINTER_1_DOWN));
3708 trustedOverlay->consumeMotionEvent(WithMotionAction(POINTER_2_DOWN));
3709
3710 // Move the swipe a bit
3711 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_MOUSE)
3712 .pointer(PointerBuilder(0, ToolType::FINGER).x(200).y(105))
3713 .pointer(PointerBuilder(1, ToolType::FINGER).x(250).y(105))
3714 .pointer(PointerBuilder(2, ToolType::FINGER).x(300).y(105))
3715 .classification(MotionClassification::MULTI_FINGER_SWIPE)
3716 .build());
3717
3718 trustedOverlay->consumeMotionEvent(WithMotionAction(ACTION_MOVE));
3719
3720 // End the swipe
3721 mDispatcher->notifyMotion(MotionArgsBuilder(POINTER_2_UP, AINPUT_SOURCE_MOUSE)
3722 .pointer(PointerBuilder(0, ToolType::FINGER).x(200).y(105))
3723 .pointer(PointerBuilder(1, ToolType::FINGER).x(250).y(105))
3724 .pointer(PointerBuilder(2, ToolType::FINGER).x(300).y(105))
3725 .classification(MotionClassification::MULTI_FINGER_SWIPE)
3726 .build());
3727 mDispatcher->notifyMotion(MotionArgsBuilder(POINTER_1_UP, AINPUT_SOURCE_MOUSE)
3728 .pointer(PointerBuilder(0, ToolType::FINGER).x(200).y(105))
3729 .pointer(PointerBuilder(1, ToolType::FINGER).x(250).y(105))
3730 .classification(MotionClassification::MULTI_FINGER_SWIPE)
3731 .build());
3732 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_UP, AINPUT_SOURCE_MOUSE)
3733 .pointer(PointerBuilder(0, ToolType::FINGER).x(200).y(105))
3734 .classification(MotionClassification::MULTI_FINGER_SWIPE)
3735 .build());
3736
3737 trustedOverlay->consumeMotionEvent(WithMotionAction(POINTER_2_UP));
3738 trustedOverlay->consumeMotionEvent(WithMotionAction(POINTER_1_UP));
3739 trustedOverlay->consumeMotionEvent(WithMotionAction(ACTION_UP));
3740
3741 window->assertNoEvents();
3742}
3743
3744TEST_F(InputDispatcherTest, TouchpadThreeFingerSwipeNotSentToSingleWindow) {
3745 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
3746 sp<FakeWindowHandle> window =
3747 sp<FakeWindowHandle>::make(application, mDispatcher, "Window", ADISPLAY_ID_DEFAULT);
3748 window->setFrame(Rect(0, 0, 400, 400));
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07003749 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Harry Cuttsb166c002023-05-09 13:06:05 +00003750
3751 // Start a three-finger touchpad swipe
3752 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_MOUSE)
3753 .pointer(PointerBuilder(0, ToolType::FINGER).x(200).y(100))
3754 .classification(MotionClassification::MULTI_FINGER_SWIPE)
3755 .build());
3756 mDispatcher->notifyMotion(MotionArgsBuilder(POINTER_1_DOWN, AINPUT_SOURCE_MOUSE)
3757 .pointer(PointerBuilder(0, ToolType::FINGER).x(200).y(100))
3758 .pointer(PointerBuilder(1, ToolType::FINGER).x(250).y(100))
3759 .classification(MotionClassification::MULTI_FINGER_SWIPE)
3760 .build());
3761 mDispatcher->notifyMotion(MotionArgsBuilder(POINTER_2_DOWN, AINPUT_SOURCE_MOUSE)
3762 .pointer(PointerBuilder(0, ToolType::FINGER).x(200).y(100))
3763 .pointer(PointerBuilder(1, ToolType::FINGER).x(250).y(100))
3764 .pointer(PointerBuilder(2, ToolType::FINGER).x(300).y(100))
3765 .classification(MotionClassification::MULTI_FINGER_SWIPE)
3766 .build());
3767
3768 // Move the swipe a bit
3769 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_MOUSE)
3770 .pointer(PointerBuilder(0, ToolType::FINGER).x(200).y(105))
3771 .pointer(PointerBuilder(1, ToolType::FINGER).x(250).y(105))
3772 .pointer(PointerBuilder(2, ToolType::FINGER).x(300).y(105))
3773 .classification(MotionClassification::MULTI_FINGER_SWIPE)
3774 .build());
3775
3776 // End the swipe
3777 mDispatcher->notifyMotion(MotionArgsBuilder(POINTER_2_UP, AINPUT_SOURCE_MOUSE)
3778 .pointer(PointerBuilder(0, ToolType::FINGER).x(200).y(105))
3779 .pointer(PointerBuilder(1, ToolType::FINGER).x(250).y(105))
3780 .pointer(PointerBuilder(2, ToolType::FINGER).x(300).y(105))
3781 .classification(MotionClassification::MULTI_FINGER_SWIPE)
3782 .build());
3783 mDispatcher->notifyMotion(MotionArgsBuilder(POINTER_1_UP, AINPUT_SOURCE_MOUSE)
3784 .pointer(PointerBuilder(0, ToolType::FINGER).x(200).y(105))
3785 .pointer(PointerBuilder(1, ToolType::FINGER).x(250).y(105))
3786 .classification(MotionClassification::MULTI_FINGER_SWIPE)
3787 .build());
3788 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_UP, AINPUT_SOURCE_MOUSE)
3789 .pointer(PointerBuilder(0, ToolType::FINGER).x(200).y(105))
3790 .classification(MotionClassification::MULTI_FINGER_SWIPE)
3791 .build());
3792
3793 window->assertNoEvents();
3794}
3795
Prabir Pradhanb60b1dc2022-03-15 14:02:35 +00003796/**
Siarhei Vishniakouadb9fc92023-05-26 10:46:09 -07003797 * Send a two-pointer gesture to a single window. The window's orientation changes in response to
3798 * the first pointer.
Prabir Pradhan69d00bf2023-06-23 19:55:18 +00003799 * Ensure that the second pointer and the subsequent gesture is correctly delivered to the window.
Siarhei Vishniakouadb9fc92023-05-26 10:46:09 -07003800 */
3801TEST_F(InputDispatcherTest, MultiplePointersWithRotatingWindow) {
3802 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
3803 sp<FakeWindowHandle> window =
3804 sp<FakeWindowHandle>::make(application, mDispatcher, "Window", ADISPLAY_ID_DEFAULT);
3805 window->setFrame(Rect(0, 0, 400, 400));
Siarhei Vishniakou700424c2023-07-18 17:18:42 -07003806 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Siarhei Vishniakouadb9fc92023-05-26 10:46:09 -07003807
3808 const nsecs_t baseTime = systemTime(SYSTEM_TIME_MONOTONIC);
3809 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
3810 .downTime(baseTime + 10)
3811 .eventTime(baseTime + 10)
3812 .pointer(PointerBuilder(0, ToolType::FINGER).x(100).y(100))
3813 .build());
3814
3815 window->consumeMotionEvent(WithMotionAction(ACTION_DOWN));
3816
Siarhei Vishniakouadb9fc92023-05-26 10:46:09 -07003817 // Change the transform so that the orientation is now different from original.
Siarhei Vishniakou700424c2023-07-18 17:18:42 -07003818 window->setWindowTransform(0, -1, 1, 0);
Siarhei Vishniakouadb9fc92023-05-26 10:46:09 -07003819
Siarhei Vishniakou700424c2023-07-18 17:18:42 -07003820 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Siarhei Vishniakouadb9fc92023-05-26 10:46:09 -07003821
Siarhei Vishniakouadb9fc92023-05-26 10:46:09 -07003822 mDispatcher->notifyMotion(MotionArgsBuilder(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
3823 .downTime(baseTime + 10)
3824 .eventTime(baseTime + 30)
3825 .pointer(PointerBuilder(0, ToolType::FINGER).x(100).y(100))
3826 .pointer(PointerBuilder(1, ToolType::FINGER).x(200).y(200))
3827 .build());
3828
Prabir Pradhan69d00bf2023-06-23 19:55:18 +00003829 window->consumeMotionEvent(WithMotionAction(POINTER_1_DOWN));
3830
3831 // Finish the gesture and start a new one. Ensure all events are sent to the window.
Siarhei Vishniakouadb9fc92023-05-26 10:46:09 -07003832 mDispatcher->notifyMotion(MotionArgsBuilder(POINTER_1_UP, AINPUT_SOURCE_TOUCHSCREEN)
3833 .downTime(baseTime + 10)
3834 .eventTime(baseTime + 40)
3835 .pointer(PointerBuilder(0, ToolType::FINGER).x(100).y(100))
3836 .pointer(PointerBuilder(1, ToolType::FINGER).x(200).y(200))
3837 .build());
Prabir Pradhan69d00bf2023-06-23 19:55:18 +00003838
3839 window->consumeMotionEvent(WithMotionAction(POINTER_1_UP));
3840
Siarhei Vishniakouadb9fc92023-05-26 10:46:09 -07003841 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN)
3842 .downTime(baseTime + 10)
3843 .eventTime(baseTime + 50)
3844 .pointer(PointerBuilder(0, ToolType::FINGER).x(100).y(100))
3845 .build());
3846
Prabir Pradhan69d00bf2023-06-23 19:55:18 +00003847 window->consumeMotionEvent(WithMotionAction(ACTION_UP));
3848
Siarhei Vishniakouadb9fc92023-05-26 10:46:09 -07003849 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
3850 .downTime(baseTime + 60)
3851 .eventTime(baseTime + 60)
3852 .pointer(PointerBuilder(0, ToolType::FINGER).x(40).y(40))
3853 .build());
3854
Siarhei Vishniakou700424c2023-07-18 17:18:42 -07003855 window->consumeMotionEvent(WithMotionAction(ACTION_DOWN));
Siarhei Vishniakouadb9fc92023-05-26 10:46:09 -07003856}
3857
3858/**
Hu Guo771a7692023-09-17 20:51:08 +08003859 * When there are multiple screens, such as screen projection to TV or screen recording, if the
3860 * cancel event occurs, the coordinates of the cancel event should be sent to the target screen, and
3861 * its coordinates should be converted by the transform of the windows of target screen.
3862 */
3863TEST_F(InputDispatcherTest, WhenMultiDisplayWindowSameToken_DispatchCancelToTargetDisplay) {
3864 // This case will create a window and a spy window on the default display and mirror
3865 // window on the second display. cancel event is sent through spy window pilferPointers
3866 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
3867
3868 sp<FakeWindowHandle> spyWindowDefaultDisplay =
3869 sp<FakeWindowHandle>::make(application, mDispatcher, "Spy", ADISPLAY_ID_DEFAULT);
3870 spyWindowDefaultDisplay->setTrustedOverlay(true);
3871 spyWindowDefaultDisplay->setSpy(true);
3872
3873 sp<FakeWindowHandle> windowDefaultDisplay =
3874 sp<FakeWindowHandle>::make(application, mDispatcher, "DefaultDisplay",
3875 ADISPLAY_ID_DEFAULT);
3876 windowDefaultDisplay->setWindowTransform(1, 0, 0, 1);
3877
3878 sp<FakeWindowHandle> windowSecondDisplay = windowDefaultDisplay->clone(SECOND_DISPLAY_ID);
3879 windowSecondDisplay->setWindowTransform(2, 0, 0, 2);
3880
3881 // Add the windows to the dispatcher
3882 mDispatcher->onWindowInfosChanged(
3883 {{*spyWindowDefaultDisplay->getInfo(), *windowDefaultDisplay->getInfo(),
3884 *windowSecondDisplay->getInfo()},
3885 {},
3886 0,
3887 0});
3888
3889 // Send down to ADISPLAY_ID_DEFAULT
3890 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
3891 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
3892 {100, 100}))
3893 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
3894
3895 spyWindowDefaultDisplay->consumeMotionDown();
3896 windowDefaultDisplay->consumeMotionDown();
3897
3898 EXPECT_EQ(OK, mDispatcher->pilferPointers(spyWindowDefaultDisplay->getToken()));
3899
3900 // windowDefaultDisplay gets cancel
Siarhei Vishniakoud3061ab2023-12-18 20:41:08 -08003901 std::unique_ptr<MotionEvent> event = windowDefaultDisplay->consumeMotionEvent();
3902 ASSERT_NE(nullptr, event);
3903 EXPECT_EQ(AMOTION_EVENT_ACTION_CANCEL, event->getAction());
Hu Guo771a7692023-09-17 20:51:08 +08003904
3905 // The cancel event is sent to windowDefaultDisplay of the ADISPLAY_ID_DEFAULT display, so the
3906 // coordinates of the cancel are converted by windowDefaultDisplay's transform, the x and y
3907 // coordinates are both 100, otherwise if the cancel event is sent to windowSecondDisplay of
3908 // SECOND_DISPLAY_ID, the x and y coordinates are 200
Siarhei Vishniakoud3061ab2023-12-18 20:41:08 -08003909 EXPECT_EQ(100, event->getX(0));
3910 EXPECT_EQ(100, event->getY(0));
Hu Guo771a7692023-09-17 20:51:08 +08003911}
3912
3913/**
Prabir Pradhanc44ce4d2021-10-05 05:26:29 -07003914 * Ensure the correct coordinate spaces are used by InputDispatcher.
3915 *
3916 * InputDispatcher works in the display space, so its coordinate system is relative to the display
3917 * panel. Windows get events in the window space, and get raw coordinates in the logical display
3918 * space.
3919 */
3920class InputDispatcherDisplayProjectionTest : public InputDispatcherTest {
3921public:
3922 void SetUp() override {
3923 InputDispatcherTest::SetUp();
Prabir Pradhan33e3baa2022-12-06 20:30:22 +00003924 removeAllWindowsAndDisplays();
Prabir Pradhanc44ce4d2021-10-05 05:26:29 -07003925 }
3926
3927 void addDisplayInfo(int displayId, const ui::Transform& transform) {
3928 gui::DisplayInfo info;
3929 info.displayId = displayId;
3930 info.transform = transform;
3931 mDisplayInfos.push_back(std::move(info));
Patrick Williamsd828f302023-04-28 17:52:08 -05003932 mDispatcher->onWindowInfosChanged({mWindowInfos, mDisplayInfos, 0, 0});
Prabir Pradhanc44ce4d2021-10-05 05:26:29 -07003933 }
3934
3935 void addWindow(const sp<WindowInfoHandle>& windowHandle) {
3936 mWindowInfos.push_back(*windowHandle->getInfo());
Patrick Williamsd828f302023-04-28 17:52:08 -05003937 mDispatcher->onWindowInfosChanged({mWindowInfos, mDisplayInfos, 0, 0});
Prabir Pradhanc44ce4d2021-10-05 05:26:29 -07003938 }
3939
Prabir Pradhan33e3baa2022-12-06 20:30:22 +00003940 void removeAllWindowsAndDisplays() {
3941 mDisplayInfos.clear();
3942 mWindowInfos.clear();
3943 }
3944
Prabir Pradhanc44ce4d2021-10-05 05:26:29 -07003945 // Set up a test scenario where the display has a scaled projection and there are two windows
3946 // on the display.
3947 std::pair<sp<FakeWindowHandle>, sp<FakeWindowHandle>> setupScaledDisplayScenario() {
3948 // The display has a projection that has a scale factor of 2 and 4 in the x and y directions
3949 // respectively.
3950 ui::Transform displayTransform;
3951 displayTransform.set(2, 0, 0, 4);
3952 addDisplayInfo(ADISPLAY_ID_DEFAULT, displayTransform);
3953
3954 std::shared_ptr<FakeApplicationHandle> application =
3955 std::make_shared<FakeApplicationHandle>();
3956
3957 // Add two windows to the display. Their frames are represented in the display space.
3958 sp<FakeWindowHandle> firstWindow =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07003959 sp<FakeWindowHandle>::make(application, mDispatcher, "First Window",
3960 ADISPLAY_ID_DEFAULT);
Prabir Pradhanc44ce4d2021-10-05 05:26:29 -07003961 firstWindow->setFrame(Rect(0, 0, 100, 200), displayTransform);
3962 addWindow(firstWindow);
3963
3964 sp<FakeWindowHandle> secondWindow =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07003965 sp<FakeWindowHandle>::make(application, mDispatcher, "Second Window",
3966 ADISPLAY_ID_DEFAULT);
Prabir Pradhanc44ce4d2021-10-05 05:26:29 -07003967 secondWindow->setFrame(Rect(100, 200, 200, 400), displayTransform);
3968 addWindow(secondWindow);
3969 return {std::move(firstWindow), std::move(secondWindow)};
3970 }
3971
3972private:
3973 std::vector<gui::DisplayInfo> mDisplayInfos;
3974 std::vector<gui::WindowInfo> mWindowInfos;
3975};
3976
Prabir Pradhan33e3baa2022-12-06 20:30:22 +00003977TEST_F(InputDispatcherDisplayProjectionTest, HitTestCoordinateSpaceConsistency) {
Prabir Pradhanc44ce4d2021-10-05 05:26:29 -07003978 auto [firstWindow, secondWindow] = setupScaledDisplayScenario();
3979 // Send down to the first window. The point is represented in the display space. The point is
Prabir Pradhan33e3baa2022-12-06 20:30:22 +00003980 // selected so that if the hit test was performed with the point and the bounds being in
3981 // different coordinate spaces, the event would end up in the incorrect window.
Prabir Pradhan678438e2023-04-13 19:32:51 +00003982 mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_DOWN,
3983 AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
3984 {PointF{75, 55}}));
Prabir Pradhanc44ce4d2021-10-05 05:26:29 -07003985
3986 firstWindow->consumeMotionDown();
3987 secondWindow->assertNoEvents();
3988}
3989
3990// Ensure that when a MotionEvent is injected through the InputDispatcher::injectInputEvent() API,
3991// the event should be treated as being in the logical display space.
3992TEST_F(InputDispatcherDisplayProjectionTest, InjectionInLogicalDisplaySpace) {
3993 auto [firstWindow, secondWindow] = setupScaledDisplayScenario();
3994 // Send down to the first window. The point is represented in the logical display space. The
3995 // point is selected so that if the hit test was done in logical display space, then it would
3996 // end up in the incorrect window.
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07003997 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
Prabir Pradhanc44ce4d2021-10-05 05:26:29 -07003998 PointF{75 * 2, 55 * 4});
3999
4000 firstWindow->consumeMotionDown();
4001 secondWindow->assertNoEvents();
4002}
4003
Prabir Pradhandaa2f142021-12-10 09:30:08 +00004004// Ensure that when a MotionEvent that has a custom transform is injected, the post-transformed
4005// event should be treated as being in the logical display space.
4006TEST_F(InputDispatcherDisplayProjectionTest, InjectionWithTransformInLogicalDisplaySpace) {
4007 auto [firstWindow, secondWindow] = setupScaledDisplayScenario();
4008
4009 const std::array<float, 9> matrix = {1.1, 2.2, 3.3, 4.4, 5.5, 6.6, 0.0, 0.0, 1.0};
4010 ui::Transform injectedEventTransform;
4011 injectedEventTransform.set(matrix);
4012 const vec2 expectedPoint{75, 55}; // The injected point in the logical display space.
4013 const vec2 untransformedPoint = injectedEventTransform.inverse().transform(expectedPoint);
4014
4015 MotionEvent event = MotionEventBuilder(AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
4016 .displayId(ADISPLAY_ID_DEFAULT)
4017 .eventTime(systemTime(SYSTEM_TIME_MONOTONIC))
Siarhei Vishniakou6d73f832022-07-21 17:27:03 -07004018 .pointer(PointerBuilder(/*id=*/0, ToolType::FINGER)
Prabir Pradhandaa2f142021-12-10 09:30:08 +00004019 .x(untransformedPoint.x)
4020 .y(untransformedPoint.y))
4021 .build();
4022 event.transform(matrix);
4023
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07004024 injectMotionEvent(*mDispatcher, event, INJECT_EVENT_TIMEOUT,
Prabir Pradhandaa2f142021-12-10 09:30:08 +00004025 InputEventInjectionSync::WAIT_FOR_RESULT);
4026
4027 firstWindow->consumeMotionDown();
4028 secondWindow->assertNoEvents();
4029}
4030
Prabir Pradhanc44ce4d2021-10-05 05:26:29 -07004031TEST_F(InputDispatcherDisplayProjectionTest, WindowGetsEventsInCorrectCoordinateSpace) {
4032 auto [firstWindow, secondWindow] = setupScaledDisplayScenario();
4033
4034 // Send down to the second window.
Prabir Pradhan678438e2023-04-13 19:32:51 +00004035 mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_DOWN,
4036 AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
4037 {PointF{150, 220}}));
Prabir Pradhanc44ce4d2021-10-05 05:26:29 -07004038
4039 firstWindow->assertNoEvents();
Siarhei Vishniakoud3061ab2023-12-18 20:41:08 -08004040 std::unique_ptr<MotionEvent> event = secondWindow->consumeMotionEvent();
4041 ASSERT_NE(nullptr, event);
4042 EXPECT_EQ(AMOTION_EVENT_ACTION_DOWN, event->getAction());
Prabir Pradhanc44ce4d2021-10-05 05:26:29 -07004043
4044 // Ensure that the events from the "getRaw" API are in logical display coordinates.
Siarhei Vishniakoud3061ab2023-12-18 20:41:08 -08004045 EXPECT_EQ(300, event->getRawX(0));
4046 EXPECT_EQ(880, event->getRawY(0));
Prabir Pradhanc44ce4d2021-10-05 05:26:29 -07004047
4048 // Ensure that the x and y values are in the window's coordinate space.
4049 // The left-top of the second window is at (100, 200) in display space, which is (200, 800) in
4050 // the logical display space. This will be the origin of the window space.
Siarhei Vishniakoud3061ab2023-12-18 20:41:08 -08004051 EXPECT_EQ(100, event->getX(0));
4052 EXPECT_EQ(80, event->getY(0));
Prabir Pradhanc44ce4d2021-10-05 05:26:29 -07004053}
4054
Prabir Pradhan112b1ad2023-09-21 09:53:53 +00004055TEST_F(InputDispatcherDisplayProjectionTest, CancelMotionWithCorrectCoordinates) {
4056 auto [firstWindow, secondWindow] = setupScaledDisplayScenario();
4057 // The monitor will always receive events in the logical display's coordinate space, because
4058 // it does not have a window.
Prabir Pradhanfb549072023-10-05 19:17:36 +00004059 FakeMonitorReceiver monitor{*mDispatcher, "Monitor", ADISPLAY_ID_DEFAULT};
Prabir Pradhan112b1ad2023-09-21 09:53:53 +00004060
4061 // Send down to the first window.
4062 mDispatcher->notifyMotion(generateMotionArgs(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN,
4063 ADISPLAY_ID_DEFAULT, {PointF{50, 100}}));
4064 firstWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithCoords(100, 400)));
4065 monitor.consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithCoords(100, 400)));
4066
4067 // Second pointer goes down on second window.
4068 mDispatcher->notifyMotion(generateMotionArgs(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN,
4069 ADISPLAY_ID_DEFAULT,
4070 {PointF{50, 100}, PointF{150, 220}}));
4071 secondWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithCoords(100, 80)));
4072 const std::map<int32_t, PointF> expectedMonitorPointers{{0, PointF{100, 400}},
4073 {1, PointF{300, 880}}};
4074 monitor.consumeMotionEvent(
4075 AllOf(WithMotionAction(POINTER_1_DOWN), WithPointers(expectedMonitorPointers)));
4076
4077 mDispatcher->cancelCurrentTouch();
4078
4079 firstWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_CANCEL), WithCoords(100, 400)));
4080 secondWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_CANCEL), WithCoords(100, 80)));
4081 monitor.consumeMotionEvent(
4082 AllOf(WithMotionAction(ACTION_CANCEL), WithPointers(expectedMonitorPointers)));
4083}
4084
Prabir Pradhan1c29a092023-09-21 10:29:29 +00004085TEST_F(InputDispatcherDisplayProjectionTest, SynthesizeDownWithCorrectCoordinates) {
4086 auto [firstWindow, secondWindow] = setupScaledDisplayScenario();
4087
4088 // Send down to the first window.
4089 mDispatcher->notifyMotion(generateMotionArgs(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN,
4090 ADISPLAY_ID_DEFAULT, {PointF{50, 100}}));
4091 firstWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithCoords(100, 400)));
4092
4093 // The pointer is transferred to the second window, and the second window receives it in the
4094 // correct coordinate space.
Prabir Pradhan367f3432024-02-13 23:05:58 +00004095 mDispatcher->transferTouchGesture(firstWindow->getToken(), secondWindow->getToken());
Prabir Pradhan1c29a092023-09-21 10:29:29 +00004096 firstWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_CANCEL), WithCoords(100, 400)));
4097 secondWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithCoords(-100, -400)));
4098}
4099
Prabir Pradhan0dfcac72023-10-05 20:04:21 +00004100TEST_F(InputDispatcherDisplayProjectionTest, SynthesizeHoverEnterExitWithCorrectCoordinates) {
4101 auto [firstWindow, secondWindow] = setupScaledDisplayScenario();
4102
4103 // Send hover move to the second window, and ensure it shows up as hover enter.
4104 mDispatcher->notifyMotion(generateMotionArgs(ACTION_HOVER_MOVE, AINPUT_SOURCE_STYLUS,
4105 ADISPLAY_ID_DEFAULT, {PointF{150, 220}}));
4106 secondWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_HOVER_ENTER),
4107 WithCoords(100, 80), WithRawCoords(300, 880)));
4108
4109 // Touch down at the same location and ensure a hover exit is synthesized.
4110 mDispatcher->notifyMotion(generateMotionArgs(ACTION_DOWN, AINPUT_SOURCE_STYLUS,
4111 ADISPLAY_ID_DEFAULT, {PointF{150, 220}}));
4112 secondWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_HOVER_EXIT), WithCoords(100, 80),
4113 WithRawCoords(300, 880)));
4114 secondWindow->consumeMotionEvent(
4115 AllOf(WithMotionAction(ACTION_DOWN), WithCoords(100, 80), WithRawCoords(300, 880)));
4116 secondWindow->assertNoEvents();
4117 firstWindow->assertNoEvents();
4118}
4119
Prabir Pradhan453ae732023-10-13 14:30:14 +00004120// Same as above, but while the window is being mirrored.
4121TEST_F(InputDispatcherDisplayProjectionTest,
4122 SynthesizeHoverEnterExitWithCorrectCoordinatesWhenMirrored) {
4123 auto [firstWindow, secondWindow] = setupScaledDisplayScenario();
4124
4125 const std::array<float, 9> matrix = {1.1, 2.2, 3.3, 4.4, 5.5, 6.6, 0.0, 0.0, 1.0};
4126 ui::Transform secondDisplayTransform;
4127 secondDisplayTransform.set(matrix);
4128 addDisplayInfo(SECOND_DISPLAY_ID, secondDisplayTransform);
4129
4130 sp<FakeWindowHandle> secondWindowClone = secondWindow->clone(SECOND_DISPLAY_ID);
4131 secondWindowClone->setWindowTransform(1.1, 2.2, 3.3, 4.4);
4132 addWindow(secondWindowClone);
4133
4134 // Send hover move to the second window, and ensure it shows up as hover enter.
4135 mDispatcher->notifyMotion(generateMotionArgs(ACTION_HOVER_MOVE, AINPUT_SOURCE_STYLUS,
4136 ADISPLAY_ID_DEFAULT, {PointF{150, 220}}));
4137 secondWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_HOVER_ENTER),
4138 WithCoords(100, 80), WithRawCoords(300, 880)));
4139
4140 // Touch down at the same location and ensure a hover exit is synthesized for the correct
4141 // display.
4142 mDispatcher->notifyMotion(generateMotionArgs(ACTION_DOWN, AINPUT_SOURCE_STYLUS,
4143 ADISPLAY_ID_DEFAULT, {PointF{150, 220}}));
4144 secondWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_HOVER_EXIT), WithCoords(100, 80),
4145 WithRawCoords(300, 880)));
4146 secondWindow->consumeMotionEvent(
4147 AllOf(WithMotionAction(ACTION_DOWN), WithCoords(100, 80), WithRawCoords(300, 880)));
4148 secondWindow->assertNoEvents();
4149 firstWindow->assertNoEvents();
4150}
4151
Prabir Pradhan0dfcac72023-10-05 20:04:21 +00004152TEST_F(InputDispatcherDisplayProjectionTest, SynthesizeHoverCancelationWithCorrectCoordinates) {
4153 auto [firstWindow, secondWindow] = setupScaledDisplayScenario();
4154
4155 // Send hover enter to second window
4156 mDispatcher->notifyMotion(generateMotionArgs(ACTION_HOVER_ENTER, AINPUT_SOURCE_STYLUS,
4157 ADISPLAY_ID_DEFAULT, {PointF{150, 220}}));
4158 secondWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_HOVER_ENTER),
4159 WithCoords(100, 80), WithRawCoords(300, 880)));
4160
4161 mDispatcher->cancelCurrentTouch();
4162
4163 secondWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_HOVER_EXIT), WithCoords(100, 80),
4164 WithRawCoords(300, 880)));
4165 secondWindow->assertNoEvents();
4166 firstWindow->assertNoEvents();
4167}
4168
Prabir Pradhan453ae732023-10-13 14:30:14 +00004169// Same as above, but while the window is being mirrored.
Prabir Pradhan16463382023-10-12 23:03:19 +00004170TEST_F(InputDispatcherDisplayProjectionTest,
4171 SynthesizeHoverCancelationWithCorrectCoordinatesWhenMirrored) {
4172 auto [firstWindow, secondWindow] = setupScaledDisplayScenario();
4173
4174 const std::array<float, 9> matrix = {1.1, 2.2, 3.3, 4.4, 5.5, 6.6, 0.0, 0.0, 1.0};
4175 ui::Transform secondDisplayTransform;
4176 secondDisplayTransform.set(matrix);
4177 addDisplayInfo(SECOND_DISPLAY_ID, secondDisplayTransform);
4178
4179 sp<FakeWindowHandle> secondWindowClone = secondWindow->clone(SECOND_DISPLAY_ID);
4180 secondWindowClone->setWindowTransform(1.1, 2.2, 3.3, 4.4);
4181 addWindow(secondWindowClone);
4182
4183 // Send hover enter to second window
4184 mDispatcher->notifyMotion(generateMotionArgs(ACTION_HOVER_ENTER, AINPUT_SOURCE_STYLUS,
4185 ADISPLAY_ID_DEFAULT, {PointF{150, 220}}));
4186 secondWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_HOVER_ENTER),
4187 WithCoords(100, 80), WithRawCoords(300, 880),
4188 WithDisplayId(ADISPLAY_ID_DEFAULT)));
4189
4190 mDispatcher->cancelCurrentTouch();
4191
4192 // Ensure the cancelation happens with the correct displayId and the correct coordinates.
4193 secondWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_HOVER_EXIT), WithCoords(100, 80),
4194 WithRawCoords(300, 880),
4195 WithDisplayId(ADISPLAY_ID_DEFAULT)));
4196 secondWindow->assertNoEvents();
4197 firstWindow->assertNoEvents();
4198}
4199
Prabir Pradhan33e3baa2022-12-06 20:30:22 +00004200/** Ensure consistent behavior of InputDispatcher in all orientations. */
4201class InputDispatcherDisplayOrientationFixture
4202 : public InputDispatcherDisplayProjectionTest,
4203 public ::testing::WithParamInterface<ui::Rotation> {};
4204
4205// This test verifies the touchable region of a window for all rotations of the display by tapping
4206// in different locations on the display, specifically points close to the four corners of a
4207// window.
4208TEST_P(InputDispatcherDisplayOrientationFixture, HitTestInDifferentOrientations) {
4209 constexpr static int32_t displayWidth = 400;
4210 constexpr static int32_t displayHeight = 800;
4211
4212 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
4213
4214 const auto rotation = GetParam();
4215
4216 // Set up the display with the specified rotation.
4217 const bool isRotated = rotation == ui::ROTATION_90 || rotation == ui::ROTATION_270;
4218 const int32_t logicalDisplayWidth = isRotated ? displayHeight : displayWidth;
4219 const int32_t logicalDisplayHeight = isRotated ? displayWidth : displayHeight;
4220 const ui::Transform displayTransform(ui::Transform::toRotationFlags(rotation),
4221 logicalDisplayWidth, logicalDisplayHeight);
4222 addDisplayInfo(ADISPLAY_ID_DEFAULT, displayTransform);
4223
4224 // Create a window with its bounds determined in the logical display.
4225 const Rect frameInLogicalDisplay(100, 100, 200, 300);
4226 const Rect frameInDisplay = displayTransform.inverse().transform(frameInLogicalDisplay);
4227 sp<FakeWindowHandle> window =
4228 sp<FakeWindowHandle>::make(application, mDispatcher, "Window", ADISPLAY_ID_DEFAULT);
4229 window->setFrame(frameInDisplay, displayTransform);
4230 addWindow(window);
4231
4232 // The following points in logical display space should be inside the window.
4233 static const std::array<vec2, 4> insidePoints{
4234 {{100, 100}, {199.99, 100}, {100, 299.99}, {199.99, 299.99}}};
4235 for (const auto pointInsideWindow : insidePoints) {
4236 const vec2 p = displayTransform.inverse().transform(pointInsideWindow);
4237 const PointF pointInDisplaySpace{p.x, p.y};
Prabir Pradhan678438e2023-04-13 19:32:51 +00004238 mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_DOWN,
4239 AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
4240 {pointInDisplaySpace}));
Prabir Pradhan33e3baa2022-12-06 20:30:22 +00004241 window->consumeMotionDown();
4242
Prabir Pradhan678438e2023-04-13 19:32:51 +00004243 mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_UP,
4244 AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
4245 {pointInDisplaySpace}));
Prabir Pradhan33e3baa2022-12-06 20:30:22 +00004246 window->consumeMotionUp();
4247 }
4248
4249 // The following points in logical display space should be outside the window.
4250 static const std::array<vec2, 5> outsidePoints{
4251 {{200, 100}, {100, 300}, {200, 300}, {100, 99.99}, {99.99, 100}}};
4252 for (const auto pointOutsideWindow : outsidePoints) {
4253 const vec2 p = displayTransform.inverse().transform(pointOutsideWindow);
4254 const PointF pointInDisplaySpace{p.x, p.y};
Prabir Pradhan678438e2023-04-13 19:32:51 +00004255 mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_DOWN,
4256 AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
4257 {pointInDisplaySpace}));
Prabir Pradhan33e3baa2022-12-06 20:30:22 +00004258
Prabir Pradhan678438e2023-04-13 19:32:51 +00004259 mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_UP,
4260 AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
4261 {pointInDisplaySpace}));
Prabir Pradhan33e3baa2022-12-06 20:30:22 +00004262 }
4263 window->assertNoEvents();
4264}
4265
Linnan Li5e5645e2024-03-05 14:43:05 +00004266// This test verifies the occlusion detection for all rotations of the display by tapping
4267// in different locations on the display, specifically points close to the four corners of a
4268// window.
4269TEST_P(InputDispatcherDisplayOrientationFixture, BlockUntrustClickInDifferentOrientations) {
4270 constexpr static int32_t displayWidth = 400;
4271 constexpr static int32_t displayHeight = 800;
4272
4273 std::shared_ptr<FakeApplicationHandle> untrustedWindowApplication =
4274 std::make_shared<FakeApplicationHandle>();
4275 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
4276
4277 const auto rotation = GetParam();
4278
4279 // Set up the display with the specified rotation.
4280 const bool isRotated = rotation == ui::ROTATION_90 || rotation == ui::ROTATION_270;
4281 const int32_t logicalDisplayWidth = isRotated ? displayHeight : displayWidth;
4282 const int32_t logicalDisplayHeight = isRotated ? displayWidth : displayHeight;
4283 const ui::Transform displayTransform(ui::Transform::toRotationFlags(rotation),
4284 logicalDisplayWidth, logicalDisplayHeight);
4285 addDisplayInfo(ADISPLAY_ID_DEFAULT, displayTransform);
4286
4287 // Create a window that not trusted.
4288 const Rect untrustedWindowFrameInLogicalDisplay(100, 100, 200, 300);
4289
4290 const Rect untrustedWindowFrameInDisplay =
4291 displayTransform.inverse().transform(untrustedWindowFrameInLogicalDisplay);
4292
4293 sp<FakeWindowHandle> untrustedWindow =
4294 sp<FakeWindowHandle>::make(untrustedWindowApplication, mDispatcher, "UntrustedWindow",
4295 ADISPLAY_ID_DEFAULT);
4296 untrustedWindow->setFrame(untrustedWindowFrameInDisplay, displayTransform);
4297 untrustedWindow->setTrustedOverlay(false);
4298 untrustedWindow->setTouchOcclusionMode(TouchOcclusionMode::BLOCK_UNTRUSTED);
4299 untrustedWindow->setTouchable(false);
4300 untrustedWindow->setAlpha(1.0f);
4301 untrustedWindow->setOwnerInfo(gui::Pid{1}, gui::Uid{101});
4302 addWindow(untrustedWindow);
4303
4304 // Create a simple app window below the untrusted window.
4305 const Rect simpleAppWindowFrameInLogicalDisplay(0, 0, 300, 600);
4306 const Rect simpleAppWindowFrameInDisplay =
4307 displayTransform.inverse().transform(simpleAppWindowFrameInLogicalDisplay);
4308
4309 sp<FakeWindowHandle> simpleAppWindow =
4310 sp<FakeWindowHandle>::make(application, mDispatcher, "SimpleAppWindow",
4311 ADISPLAY_ID_DEFAULT);
4312 simpleAppWindow->setFrame(simpleAppWindowFrameInDisplay, displayTransform);
4313 simpleAppWindow->setOwnerInfo(gui::Pid{2}, gui::Uid{202});
4314 addWindow(simpleAppWindow);
4315
4316 // The following points in logical display space should be inside the untrusted window, so
4317 // the simple window could not receive events that coordinate is these point.
4318 static const std::array<vec2, 4> untrustedPoints{
4319 {{100, 100}, {199.99, 100}, {100, 299.99}, {199.99, 299.99}}};
4320
4321 for (const auto untrustedPoint : untrustedPoints) {
4322 const vec2 p = displayTransform.inverse().transform(untrustedPoint);
4323 const PointF pointInDisplaySpace{p.x, p.y};
4324 mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_DOWN,
4325 AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
4326 {pointInDisplaySpace}));
4327 mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_UP,
4328 AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
4329 {pointInDisplaySpace}));
4330 }
4331 untrustedWindow->assertNoEvents();
4332 simpleAppWindow->assertNoEvents();
4333 // The following points in logical display space should be outside the untrusted window, so
4334 // the simple window should receive events that coordinate is these point.
4335 static const std::array<vec2, 5> trustedPoints{
4336 {{200, 100}, {100, 300}, {200, 300}, {100, 99.99}, {99.99, 100}}};
4337 for (const auto trustedPoint : trustedPoints) {
4338 const vec2 p = displayTransform.inverse().transform(trustedPoint);
4339 const PointF pointInDisplaySpace{p.x, p.y};
4340 mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_DOWN,
4341 AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
4342 {pointInDisplaySpace}));
4343 simpleAppWindow->consumeMotionDown(ADISPLAY_ID_DEFAULT,
4344 AMOTION_EVENT_FLAG_WINDOW_IS_PARTIALLY_OBSCURED);
4345 mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_UP,
4346 AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
4347 {pointInDisplaySpace}));
4348 simpleAppWindow->consumeMotionUp(ADISPLAY_ID_DEFAULT,
4349 AMOTION_EVENT_FLAG_WINDOW_IS_PARTIALLY_OBSCURED);
4350 }
4351 untrustedWindow->assertNoEvents();
4352}
4353
Prabir Pradhan33e3baa2022-12-06 20:30:22 +00004354// Run the precision tests for all rotations.
4355INSTANTIATE_TEST_SUITE_P(InputDispatcherDisplayOrientationTests,
4356 InputDispatcherDisplayOrientationFixture,
4357 ::testing::Values(ui::ROTATION_0, ui::ROTATION_90, ui::ROTATION_180,
4358 ui::ROTATION_270),
4359 [](const testing::TestParamInfo<ui::Rotation>& testParamInfo) {
4360 return ftl::enum_string(testParamInfo.param);
4361 });
4362
Siarhei Vishniakou18050092021-09-01 13:32:49 -07004363using TransferFunction = std::function<bool(const std::unique_ptr<InputDispatcher>& dispatcher,
4364 sp<IBinder>, sp<IBinder>)>;
Siarhei Vishniakoud0c6bc82021-03-13 03:14:52 +00004365
4366class TransferTouchFixture : public InputDispatcherTest,
4367 public ::testing::WithParamInterface<TransferFunction> {};
4368
4369TEST_P(TransferTouchFixture, TransferTouch_OnePointer) {
Chris Yea209fde2020-07-22 13:54:51 -07004370 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
Svet Ganov5d3bc372020-01-26 23:11:07 -08004371
4372 // Create a couple of windows
Siarhei Vishniakou870ecec2020-12-09 08:07:46 -10004373 sp<FakeWindowHandle> firstWindow =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07004374 sp<FakeWindowHandle>::make(application, mDispatcher, "First Window",
4375 ADISPLAY_ID_DEFAULT);
Arthur Hungc539dbb2022-12-08 07:45:36 +00004376 firstWindow->setDupTouchToWallpaper(true);
Siarhei Vishniakou870ecec2020-12-09 08:07:46 -10004377 sp<FakeWindowHandle> secondWindow =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07004378 sp<FakeWindowHandle>::make(application, mDispatcher, "Second Window",
4379 ADISPLAY_ID_DEFAULT);
Arthur Hungc539dbb2022-12-08 07:45:36 +00004380 sp<FakeWindowHandle> wallpaper =
4381 sp<FakeWindowHandle>::make(application, mDispatcher, "Wallpaper", ADISPLAY_ID_DEFAULT);
4382 wallpaper->setIsWallpaper(true);
Prabir Pradhan65455c72024-02-13 21:46:41 +00004383 // Add the windows to the dispatcher, and ensure the first window is focused
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07004384 mDispatcher->onWindowInfosChanged(
4385 {{*firstWindow->getInfo(), *secondWindow->getInfo(), *wallpaper->getInfo()}, {}, 0, 0});
Prabir Pradhan65455c72024-02-13 21:46:41 +00004386 setFocusedWindow(firstWindow);
4387 firstWindow->consumeFocusEvent(true);
Svet Ganov5d3bc372020-01-26 23:11:07 -08004388
4389 // Send down to the first window
Prabir Pradhan678438e2023-04-13 19:32:51 +00004390 mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_DOWN,
4391 AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT));
Arthur Hungc539dbb2022-12-08 07:45:36 +00004392
Svet Ganov5d3bc372020-01-26 23:11:07 -08004393 // Only the first window should get the down event
4394 firstWindow->consumeMotionDown();
4395 secondWindow->assertNoEvents();
Arthur Hungc539dbb2022-12-08 07:45:36 +00004396 wallpaper->consumeMotionDown(ADISPLAY_ID_DEFAULT, expectedWallpaperFlags);
Prabir Pradhan65455c72024-02-13 21:46:41 +00004397 // Dispatcher reports pointer down outside focus for the wallpaper
4398 mFakePolicy->assertOnPointerDownEquals(wallpaper->getToken());
Svet Ganov5d3bc372020-01-26 23:11:07 -08004399
Siarhei Vishniakoud0c6bc82021-03-13 03:14:52 +00004400 // Transfer touch to the second window
4401 TransferFunction f = GetParam();
4402 const bool success = f(mDispatcher, firstWindow->getToken(), secondWindow->getToken());
4403 ASSERT_TRUE(success);
Svet Ganov5d3bc372020-01-26 23:11:07 -08004404 // The first window gets cancel and the second gets down
4405 firstWindow->consumeMotionCancel();
Prabir Pradhan65455c72024-02-13 21:46:41 +00004406 secondWindow->consumeMotionDown(ADISPLAY_ID_DEFAULT, AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
Arthur Hungc539dbb2022-12-08 07:45:36 +00004407 wallpaper->consumeMotionCancel(ADISPLAY_ID_DEFAULT, expectedWallpaperFlags);
Prabir Pradhan65455c72024-02-13 21:46:41 +00004408 // There should not be any changes to the focused window when transferring touch
4409 ASSERT_NO_FATAL_FAILURE(mFakePolicy->assertOnPointerDownWasNotCalled());
Svet Ganov5d3bc372020-01-26 23:11:07 -08004410
4411 // Send up event to the second window
Prabir Pradhan678438e2023-04-13 19:32:51 +00004412 mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN,
4413 ADISPLAY_ID_DEFAULT));
Prabir Pradhan65455c72024-02-13 21:46:41 +00004414 // The first window gets no events and the second gets up
Svet Ganov5d3bc372020-01-26 23:11:07 -08004415 firstWindow->assertNoEvents();
Prabir Pradhan65455c72024-02-13 21:46:41 +00004416 secondWindow->consumeMotionUp(ADISPLAY_ID_DEFAULT, AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
Arthur Hungc539dbb2022-12-08 07:45:36 +00004417 wallpaper->assertNoEvents();
Svet Ganov5d3bc372020-01-26 23:11:07 -08004418}
4419
Siarhei Vishniakou7ae7afd2022-03-31 15:26:13 -07004420/**
Prabir Pradhan367f3432024-02-13 23:05:58 +00004421 * When 'transferTouchGesture' API is invoked, dispatcher needs to find the "best" window to take
4422 * touch from. When we have spy windows, there are several windows to choose from: either spy, or
4423 * the 'real' (non-spy) window. Always prefer the 'real' window because that's what would be most
Siarhei Vishniakou7ae7afd2022-03-31 15:26:13 -07004424 * natural to the user.
4425 * In this test, we are sending a pointer to both spy window and first window. We then try to
4426 * transfer touch to the second window. The dispatcher should identify the first window as the
4427 * one that should lose the gesture, and therefore the action should be to move the gesture from
4428 * the first window to the second.
Prabir Pradhan367f3432024-02-13 23:05:58 +00004429 * The main goal here is to test the behaviour of 'transferTouchGesture' API, but it's still valid
4430 * to test the other API, as well.
Siarhei Vishniakou7ae7afd2022-03-31 15:26:13 -07004431 */
4432TEST_P(TransferTouchFixture, TransferTouch_MultipleWindowsWithSpy) {
4433 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
4434
4435 // Create a couple of windows + a spy window
4436 sp<FakeWindowHandle> spyWindow =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07004437 sp<FakeWindowHandle>::make(application, mDispatcher, "Spy", ADISPLAY_ID_DEFAULT);
Siarhei Vishniakou7ae7afd2022-03-31 15:26:13 -07004438 spyWindow->setTrustedOverlay(true);
4439 spyWindow->setSpy(true);
4440 sp<FakeWindowHandle> firstWindow =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07004441 sp<FakeWindowHandle>::make(application, mDispatcher, "First", ADISPLAY_ID_DEFAULT);
Siarhei Vishniakou7ae7afd2022-03-31 15:26:13 -07004442 sp<FakeWindowHandle> secondWindow =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07004443 sp<FakeWindowHandle>::make(application, mDispatcher, "Second", ADISPLAY_ID_DEFAULT);
Siarhei Vishniakou7ae7afd2022-03-31 15:26:13 -07004444
4445 // Add the windows to the dispatcher
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07004446 mDispatcher->onWindowInfosChanged(
4447 {{*spyWindow->getInfo(), *firstWindow->getInfo(), *secondWindow->getInfo()}, {}, 0, 0});
Siarhei Vishniakou7ae7afd2022-03-31 15:26:13 -07004448
4449 // Send down to the first window
Prabir Pradhan678438e2023-04-13 19:32:51 +00004450 mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_DOWN,
4451 AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT));
Siarhei Vishniakou7ae7afd2022-03-31 15:26:13 -07004452 // Only the first window and spy should get the down event
4453 spyWindow->consumeMotionDown();
4454 firstWindow->consumeMotionDown();
4455
4456 // Transfer touch to the second window. Non-spy window should be preferred over the spy window
Prabir Pradhan367f3432024-02-13 23:05:58 +00004457 // if f === 'transferTouchGesture'.
Siarhei Vishniakou7ae7afd2022-03-31 15:26:13 -07004458 TransferFunction f = GetParam();
4459 const bool success = f(mDispatcher, firstWindow->getToken(), secondWindow->getToken());
4460 ASSERT_TRUE(success);
4461 // The first window gets cancel and the second gets down
4462 firstWindow->consumeMotionCancel();
Prabir Pradhan65455c72024-02-13 21:46:41 +00004463 secondWindow->consumeMotionDown(ADISPLAY_ID_DEFAULT, AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
Siarhei Vishniakou7ae7afd2022-03-31 15:26:13 -07004464
4465 // Send up event to the second window
Prabir Pradhan678438e2023-04-13 19:32:51 +00004466 mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN,
4467 ADISPLAY_ID_DEFAULT));
Siarhei Vishniakou7ae7afd2022-03-31 15:26:13 -07004468 // The first window gets no events and the second+spy get up
4469 firstWindow->assertNoEvents();
4470 spyWindow->consumeMotionUp();
Prabir Pradhan65455c72024-02-13 21:46:41 +00004471 secondWindow->consumeMotionUp(ADISPLAY_ID_DEFAULT, AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
Siarhei Vishniakou7ae7afd2022-03-31 15:26:13 -07004472}
4473
Siarhei Vishniakoud0c6bc82021-03-13 03:14:52 +00004474TEST_P(TransferTouchFixture, TransferTouch_TwoPointersNonSplitTouch) {
Chris Yea209fde2020-07-22 13:54:51 -07004475 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
Svet Ganov5d3bc372020-01-26 23:11:07 -08004476
4477 PointF touchPoint = {10, 10};
4478
4479 // Create a couple of windows
Siarhei Vishniakou870ecec2020-12-09 08:07:46 -10004480 sp<FakeWindowHandle> firstWindow =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07004481 sp<FakeWindowHandle>::make(application, mDispatcher, "First Window",
4482 ADISPLAY_ID_DEFAULT);
Prabir Pradhan76bdecb2022-01-31 11:14:15 -08004483 firstWindow->setPreventSplitting(true);
Siarhei Vishniakou870ecec2020-12-09 08:07:46 -10004484 sp<FakeWindowHandle> secondWindow =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07004485 sp<FakeWindowHandle>::make(application, mDispatcher, "Second Window",
4486 ADISPLAY_ID_DEFAULT);
Prabir Pradhan76bdecb2022-01-31 11:14:15 -08004487 secondWindow->setPreventSplitting(true);
Svet Ganov5d3bc372020-01-26 23:11:07 -08004488
4489 // Add the windows to the dispatcher
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07004490 mDispatcher->onWindowInfosChanged(
4491 {{*firstWindow->getInfo(), *secondWindow->getInfo()}, {}, 0, 0});
Svet Ganov5d3bc372020-01-26 23:11:07 -08004492
4493 // Send down to the first window
Prabir Pradhan678438e2023-04-13 19:32:51 +00004494 mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_DOWN,
4495 AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
4496 {touchPoint}));
Svet Ganov5d3bc372020-01-26 23:11:07 -08004497 // Only the first window should get the down event
4498 firstWindow->consumeMotionDown();
4499 secondWindow->assertNoEvents();
4500
4501 // Send pointer down to the first window
Prabir Pradhan678438e2023-04-13 19:32:51 +00004502 mDispatcher->notifyMotion(generateMotionArgs(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN,
4503 ADISPLAY_ID_DEFAULT, {touchPoint, touchPoint}));
Svet Ganov5d3bc372020-01-26 23:11:07 -08004504 // Only the first window should get the pointer down event
4505 firstWindow->consumeMotionPointerDown(1);
4506 secondWindow->assertNoEvents();
4507
4508 // Transfer touch focus to the second window
Siarhei Vishniakoud0c6bc82021-03-13 03:14:52 +00004509 TransferFunction f = GetParam();
4510 bool success = f(mDispatcher, firstWindow->getToken(), secondWindow->getToken());
4511 ASSERT_TRUE(success);
Svet Ganov5d3bc372020-01-26 23:11:07 -08004512 // The first window gets cancel and the second gets down and pointer down
4513 firstWindow->consumeMotionCancel();
Prabir Pradhan65455c72024-02-13 21:46:41 +00004514 secondWindow->consumeMotionDown(ADISPLAY_ID_DEFAULT, AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
4515 secondWindow->consumeMotionPointerDown(1, ADISPLAY_ID_DEFAULT,
4516 AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
Svet Ganov5d3bc372020-01-26 23:11:07 -08004517
4518 // Send pointer up to the second window
Prabir Pradhan678438e2023-04-13 19:32:51 +00004519 mDispatcher->notifyMotion(generateMotionArgs(POINTER_1_UP, AINPUT_SOURCE_TOUCHSCREEN,
4520 ADISPLAY_ID_DEFAULT, {touchPoint, touchPoint}));
Svet Ganov5d3bc372020-01-26 23:11:07 -08004521 // The first window gets nothing and the second gets pointer up
4522 firstWindow->assertNoEvents();
Prabir Pradhan65455c72024-02-13 21:46:41 +00004523 secondWindow->consumeMotionPointerUp(1, ADISPLAY_ID_DEFAULT,
4524 AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
Svet Ganov5d3bc372020-01-26 23:11:07 -08004525
4526 // Send up event to the second window
Prabir Pradhan678438e2023-04-13 19:32:51 +00004527 mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN,
4528 ADISPLAY_ID_DEFAULT));
Svet Ganov5d3bc372020-01-26 23:11:07 -08004529 // The first window gets nothing and the second gets up
4530 firstWindow->assertNoEvents();
Prabir Pradhan65455c72024-02-13 21:46:41 +00004531 secondWindow->consumeMotionUp(ADISPLAY_ID_DEFAULT, AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
Svet Ganov5d3bc372020-01-26 23:11:07 -08004532}
4533
Arthur Hungc539dbb2022-12-08 07:45:36 +00004534TEST_P(TransferTouchFixture, TransferTouch_MultipleWallpapers) {
4535 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
4536
4537 // Create a couple of windows
4538 sp<FakeWindowHandle> firstWindow =
4539 sp<FakeWindowHandle>::make(application, mDispatcher, "First Window",
4540 ADISPLAY_ID_DEFAULT);
4541 firstWindow->setDupTouchToWallpaper(true);
4542 sp<FakeWindowHandle> secondWindow =
4543 sp<FakeWindowHandle>::make(application, mDispatcher, "Second Window",
4544 ADISPLAY_ID_DEFAULT);
4545 secondWindow->setDupTouchToWallpaper(true);
4546
4547 sp<FakeWindowHandle> wallpaper1 =
4548 sp<FakeWindowHandle>::make(application, mDispatcher, "Wallpaper1", ADISPLAY_ID_DEFAULT);
4549 wallpaper1->setIsWallpaper(true);
4550
4551 sp<FakeWindowHandle> wallpaper2 =
4552 sp<FakeWindowHandle>::make(application, mDispatcher, "Wallpaper2", ADISPLAY_ID_DEFAULT);
4553 wallpaper2->setIsWallpaper(true);
4554 // Add the windows to the dispatcher
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07004555 mDispatcher->onWindowInfosChanged({{*firstWindow->getInfo(), *wallpaper1->getInfo(),
4556 *secondWindow->getInfo(), *wallpaper2->getInfo()},
4557 {},
4558 0,
4559 0});
Arthur Hungc539dbb2022-12-08 07:45:36 +00004560
4561 // Send down to the first window
Prabir Pradhan678438e2023-04-13 19:32:51 +00004562 mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_DOWN,
4563 AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT));
Arthur Hungc539dbb2022-12-08 07:45:36 +00004564
4565 // Only the first window should get the down event
4566 firstWindow->consumeMotionDown();
4567 secondWindow->assertNoEvents();
4568 wallpaper1->consumeMotionDown(ADISPLAY_ID_DEFAULT, expectedWallpaperFlags);
4569 wallpaper2->assertNoEvents();
4570
4571 // Transfer touch focus to the second window
4572 TransferFunction f = GetParam();
4573 bool success = f(mDispatcher, firstWindow->getToken(), secondWindow->getToken());
4574 ASSERT_TRUE(success);
4575
4576 // The first window gets cancel and the second gets down
4577 firstWindow->consumeMotionCancel();
Prabir Pradhan65455c72024-02-13 21:46:41 +00004578 secondWindow->consumeMotionDown(ADISPLAY_ID_DEFAULT, AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
Arthur Hungc539dbb2022-12-08 07:45:36 +00004579 wallpaper1->consumeMotionCancel(ADISPLAY_ID_DEFAULT, expectedWallpaperFlags);
Prabir Pradhan65455c72024-02-13 21:46:41 +00004580 wallpaper2->consumeMotionDown(ADISPLAY_ID_DEFAULT,
4581 expectedWallpaperFlags | AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
Arthur Hungc539dbb2022-12-08 07:45:36 +00004582
4583 // Send up event to the second window
Prabir Pradhan678438e2023-04-13 19:32:51 +00004584 mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN,
4585 ADISPLAY_ID_DEFAULT));
Arthur Hungc539dbb2022-12-08 07:45:36 +00004586 // The first window gets no events and the second gets up
4587 firstWindow->assertNoEvents();
Prabir Pradhan65455c72024-02-13 21:46:41 +00004588 secondWindow->consumeMotionUp(ADISPLAY_ID_DEFAULT, AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
Arthur Hungc539dbb2022-12-08 07:45:36 +00004589 wallpaper1->assertNoEvents();
Prabir Pradhan65455c72024-02-13 21:46:41 +00004590 wallpaper2->consumeMotionUp(ADISPLAY_ID_DEFAULT,
4591 expectedWallpaperFlags | AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
Arthur Hungc539dbb2022-12-08 07:45:36 +00004592}
4593
Siarhei Vishniakoud0c6bc82021-03-13 03:14:52 +00004594// For the cases of single pointer touch and two pointers non-split touch, the api's
Prabir Pradhan367f3432024-02-13 23:05:58 +00004595// 'transferTouchGesture' and 'transferTouchOnDisplay' are equivalent in behaviour. They only differ
Siarhei Vishniakoud0c6bc82021-03-13 03:14:52 +00004596// for the case where there are multiple pointers split across several windows.
Prabir Pradhan367f3432024-02-13 23:05:58 +00004597INSTANTIATE_TEST_SUITE_P(
4598 InputDispatcherTransferFunctionTests, TransferTouchFixture,
4599 ::testing::Values(
4600 [&](const std::unique_ptr<InputDispatcher>& dispatcher, sp<IBinder> /*ignored*/,
4601 sp<IBinder> destChannelToken) {
4602 return dispatcher->transferTouchOnDisplay(destChannelToken,
4603 ADISPLAY_ID_DEFAULT);
4604 },
4605 [&](const std::unique_ptr<InputDispatcher>& dispatcher, sp<IBinder> from,
4606 sp<IBinder> to) {
4607 return dispatcher->transferTouchGesture(from, to,
4608 /*isDragAndDrop=*/false);
4609 }));
Siarhei Vishniakoud0c6bc82021-03-13 03:14:52 +00004610
Prabir Pradhan367f3432024-02-13 23:05:58 +00004611TEST_F(InputDispatcherTest, TransferTouch_TwoPointersSplitTouch) {
Chris Yea209fde2020-07-22 13:54:51 -07004612 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
Svet Ganov5d3bc372020-01-26 23:11:07 -08004613
Siarhei Vishniakou870ecec2020-12-09 08:07:46 -10004614 sp<FakeWindowHandle> firstWindow =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07004615 sp<FakeWindowHandle>::make(application, mDispatcher, "First Window",
4616 ADISPLAY_ID_DEFAULT);
Svet Ganov5d3bc372020-01-26 23:11:07 -08004617 firstWindow->setFrame(Rect(0, 0, 600, 400));
Svet Ganov5d3bc372020-01-26 23:11:07 -08004618
Siarhei Vishniakou870ecec2020-12-09 08:07:46 -10004619 sp<FakeWindowHandle> secondWindow =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07004620 sp<FakeWindowHandle>::make(application, mDispatcher, "Second Window",
4621 ADISPLAY_ID_DEFAULT);
Svet Ganov5d3bc372020-01-26 23:11:07 -08004622 secondWindow->setFrame(Rect(0, 400, 600, 800));
Svet Ganov5d3bc372020-01-26 23:11:07 -08004623
4624 // Add the windows to the dispatcher
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07004625 mDispatcher->onWindowInfosChanged(
4626 {{*firstWindow->getInfo(), *secondWindow->getInfo()}, {}, 0, 0});
Svet Ganov5d3bc372020-01-26 23:11:07 -08004627
4628 PointF pointInFirst = {300, 200};
4629 PointF pointInSecond = {300, 600};
4630
4631 // Send down to the first window
Prabir Pradhan678438e2023-04-13 19:32:51 +00004632 mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_DOWN,
4633 AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
4634 {pointInFirst}));
Svet Ganov5d3bc372020-01-26 23:11:07 -08004635 // Only the first window should get the down event
4636 firstWindow->consumeMotionDown();
4637 secondWindow->assertNoEvents();
4638
4639 // Send down to the second window
Prabir Pradhan678438e2023-04-13 19:32:51 +00004640 mDispatcher->notifyMotion(generateMotionArgs(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN,
4641 ADISPLAY_ID_DEFAULT,
4642 {pointInFirst, pointInSecond}));
Svet Ganov5d3bc372020-01-26 23:11:07 -08004643 // The first window gets a move and the second a down
4644 firstWindow->consumeMotionMove();
4645 secondWindow->consumeMotionDown();
4646
Prabir Pradhan367f3432024-02-13 23:05:58 +00004647 // Transfer touch to the second window
4648 mDispatcher->transferTouchGesture(firstWindow->getToken(), secondWindow->getToken());
Svet Ganov5d3bc372020-01-26 23:11:07 -08004649 // The first window gets cancel and the new gets pointer down (it already saw down)
4650 firstWindow->consumeMotionCancel();
Prabir Pradhan65455c72024-02-13 21:46:41 +00004651 secondWindow->consumeMotionPointerDown(1, ADISPLAY_ID_DEFAULT,
4652 AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
Svet Ganov5d3bc372020-01-26 23:11:07 -08004653
4654 // Send pointer up to the second window
Prabir Pradhan678438e2023-04-13 19:32:51 +00004655 mDispatcher->notifyMotion(generateMotionArgs(POINTER_1_UP, AINPUT_SOURCE_TOUCHSCREEN,
4656 ADISPLAY_ID_DEFAULT,
4657 {pointInFirst, pointInSecond}));
Svet Ganov5d3bc372020-01-26 23:11:07 -08004658 // The first window gets nothing and the second gets pointer up
4659 firstWindow->assertNoEvents();
Prabir Pradhan65455c72024-02-13 21:46:41 +00004660 secondWindow->consumeMotionPointerUp(1, ADISPLAY_ID_DEFAULT,
4661 AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
Svet Ganov5d3bc372020-01-26 23:11:07 -08004662
4663 // Send up event to the second window
Prabir Pradhan678438e2023-04-13 19:32:51 +00004664 mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN,
4665 ADISPLAY_ID_DEFAULT));
Svet Ganov5d3bc372020-01-26 23:11:07 -08004666 // The first window gets nothing and the second gets up
4667 firstWindow->assertNoEvents();
Prabir Pradhan65455c72024-02-13 21:46:41 +00004668 secondWindow->consumeMotionUp(ADISPLAY_ID_DEFAULT, AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
Svet Ganov5d3bc372020-01-26 23:11:07 -08004669}
4670
Prabir Pradhan367f3432024-02-13 23:05:58 +00004671// Same as TransferTouch_TwoPointersSplitTouch, but using 'transferTouchOnDisplay' api.
4672// Unlike 'transferTouchGesture', calling 'transferTouchOnDisplay' when there are two windows
4673// receiving touch is not supported, so the touch should continue on those windows and the
4674// transferred-to window should get nothing.
4675TEST_F(InputDispatcherTest, TransferTouchOnDisplay_TwoPointersSplitTouch) {
Siarhei Vishniakoud0c6bc82021-03-13 03:14:52 +00004676 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
4677
Siarhei Vishniakoud0c6bc82021-03-13 03:14:52 +00004678 sp<FakeWindowHandle> firstWindow =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07004679 sp<FakeWindowHandle>::make(application, mDispatcher, "First Window",
4680 ADISPLAY_ID_DEFAULT);
Siarhei Vishniakoud0c6bc82021-03-13 03:14:52 +00004681 firstWindow->setFrame(Rect(0, 0, 600, 400));
Siarhei Vishniakoud0c6bc82021-03-13 03:14:52 +00004682
Siarhei Vishniakoud0c6bc82021-03-13 03:14:52 +00004683 sp<FakeWindowHandle> secondWindow =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07004684 sp<FakeWindowHandle>::make(application, mDispatcher, "Second Window",
4685 ADISPLAY_ID_DEFAULT);
Siarhei Vishniakoud0c6bc82021-03-13 03:14:52 +00004686 secondWindow->setFrame(Rect(0, 400, 600, 800));
Siarhei Vishniakoud0c6bc82021-03-13 03:14:52 +00004687
4688 // Add the windows to the dispatcher
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07004689 mDispatcher->onWindowInfosChanged(
4690 {{*firstWindow->getInfo(), *secondWindow->getInfo()}, {}, 0, 0});
Siarhei Vishniakoud0c6bc82021-03-13 03:14:52 +00004691
4692 PointF pointInFirst = {300, 200};
4693 PointF pointInSecond = {300, 600};
4694
4695 // Send down to the first window
Prabir Pradhan678438e2023-04-13 19:32:51 +00004696 mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_DOWN,
4697 AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
4698 {pointInFirst}));
Siarhei Vishniakoud0c6bc82021-03-13 03:14:52 +00004699 // Only the first window should get the down event
4700 firstWindow->consumeMotionDown();
4701 secondWindow->assertNoEvents();
4702
4703 // Send down to the second window
Prabir Pradhan678438e2023-04-13 19:32:51 +00004704 mDispatcher->notifyMotion(generateMotionArgs(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN,
4705 ADISPLAY_ID_DEFAULT,
4706 {pointInFirst, pointInSecond}));
Siarhei Vishniakoud0c6bc82021-03-13 03:14:52 +00004707 // The first window gets a move and the second a down
4708 firstWindow->consumeMotionMove();
4709 secondWindow->consumeMotionDown();
4710
4711 // Transfer touch focus to the second window
Siarhei Vishniakou7ae7afd2022-03-31 15:26:13 -07004712 const bool transferred =
Prabir Pradhan367f3432024-02-13 23:05:58 +00004713 mDispatcher->transferTouchOnDisplay(secondWindow->getToken(), ADISPLAY_ID_DEFAULT);
4714 // The 'transferTouchOnDisplay' call should not succeed, because there are 2 touched windows
Siarhei Vishniakoud0c6bc82021-03-13 03:14:52 +00004715 ASSERT_FALSE(transferred);
4716 firstWindow->assertNoEvents();
4717 secondWindow->assertNoEvents();
4718
4719 // The rest of the dispatch should proceed as normal
4720 // Send pointer up to the second window
Prabir Pradhan678438e2023-04-13 19:32:51 +00004721 mDispatcher->notifyMotion(generateMotionArgs(POINTER_1_UP, AINPUT_SOURCE_TOUCHSCREEN,
4722 ADISPLAY_ID_DEFAULT,
4723 {pointInFirst, pointInSecond}));
Siarhei Vishniakoud0c6bc82021-03-13 03:14:52 +00004724 // The first window gets MOVE and the second gets pointer up
4725 firstWindow->consumeMotionMove();
4726 secondWindow->consumeMotionUp();
4727
4728 // Send up event to the first window
Prabir Pradhan678438e2023-04-13 19:32:51 +00004729 mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN,
4730 ADISPLAY_ID_DEFAULT));
Siarhei Vishniakoud0c6bc82021-03-13 03:14:52 +00004731 // The first window gets nothing and the second gets up
4732 firstWindow->consumeMotionUp();
4733 secondWindow->assertNoEvents();
4734}
4735
Arthur Hungabbb9d82021-09-01 14:52:30 +00004736// This case will create two windows and one mirrored window on the default display and mirror
Prabir Pradhan367f3432024-02-13 23:05:58 +00004737// two windows on the second display. It will test if 'transferTouchGesture' works fine if we put
Arthur Hungabbb9d82021-09-01 14:52:30 +00004738// the windows info of second display before default display.
Prabir Pradhan367f3432024-02-13 23:05:58 +00004739TEST_F(InputDispatcherTest, TransferTouch_CloneSurface) {
Arthur Hungabbb9d82021-09-01 14:52:30 +00004740 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
4741 sp<FakeWindowHandle> firstWindowInPrimary =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07004742 sp<FakeWindowHandle>::make(application, mDispatcher, "D_1_W1", ADISPLAY_ID_DEFAULT);
Arthur Hungabbb9d82021-09-01 14:52:30 +00004743 firstWindowInPrimary->setFrame(Rect(0, 0, 100, 100));
Arthur Hungabbb9d82021-09-01 14:52:30 +00004744 sp<FakeWindowHandle> secondWindowInPrimary =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07004745 sp<FakeWindowHandle>::make(application, mDispatcher, "D_1_W2", ADISPLAY_ID_DEFAULT);
Arthur Hungabbb9d82021-09-01 14:52:30 +00004746 secondWindowInPrimary->setFrame(Rect(100, 0, 200, 100));
Arthur Hungabbb9d82021-09-01 14:52:30 +00004747
Siarhei Vishniakouadb9fc92023-05-26 10:46:09 -07004748 sp<FakeWindowHandle> mirrorWindowInPrimary = firstWindowInPrimary->clone(ADISPLAY_ID_DEFAULT);
Arthur Hungabbb9d82021-09-01 14:52:30 +00004749 mirrorWindowInPrimary->setFrame(Rect(0, 100, 100, 200));
Arthur Hungabbb9d82021-09-01 14:52:30 +00004750
Siarhei Vishniakouadb9fc92023-05-26 10:46:09 -07004751 sp<FakeWindowHandle> firstWindowInSecondary = firstWindowInPrimary->clone(SECOND_DISPLAY_ID);
Arthur Hungabbb9d82021-09-01 14:52:30 +00004752 firstWindowInSecondary->setFrame(Rect(0, 0, 100, 100));
Arthur Hungabbb9d82021-09-01 14:52:30 +00004753
Siarhei Vishniakouadb9fc92023-05-26 10:46:09 -07004754 sp<FakeWindowHandle> secondWindowInSecondary = secondWindowInPrimary->clone(SECOND_DISPLAY_ID);
Arthur Hungabbb9d82021-09-01 14:52:30 +00004755 secondWindowInPrimary->setFrame(Rect(100, 0, 200, 100));
Arthur Hungabbb9d82021-09-01 14:52:30 +00004756
4757 // Update window info, let it find window handle of second display first.
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07004758 mDispatcher->onWindowInfosChanged(
4759 {{*firstWindowInSecondary->getInfo(), *secondWindowInSecondary->getInfo(),
4760 *mirrorWindowInPrimary->getInfo(), *firstWindowInPrimary->getInfo(),
4761 *secondWindowInPrimary->getInfo()},
4762 {},
4763 0,
4764 0});
Arthur Hungabbb9d82021-09-01 14:52:30 +00004765
4766 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07004767 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
Arthur Hungabbb9d82021-09-01 14:52:30 +00004768 {50, 50}))
4769 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
4770
4771 // Window should receive motion event.
4772 firstWindowInPrimary->consumeMotionDown(ADISPLAY_ID_DEFAULT);
4773
Prabir Pradhan367f3432024-02-13 23:05:58 +00004774 // Transfer touch
4775 ASSERT_TRUE(mDispatcher->transferTouchGesture(firstWindowInPrimary->getToken(),
4776 secondWindowInPrimary->getToken()));
Arthur Hungabbb9d82021-09-01 14:52:30 +00004777 // The first window gets cancel.
4778 firstWindowInPrimary->consumeMotionCancel();
Prabir Pradhan65455c72024-02-13 21:46:41 +00004779 secondWindowInPrimary->consumeMotionDown(ADISPLAY_ID_DEFAULT,
4780 AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
Arthur Hungabbb9d82021-09-01 14:52:30 +00004781
4782 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07004783 injectMotionEvent(*mDispatcher, AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN,
Arthur Hungabbb9d82021-09-01 14:52:30 +00004784 ADISPLAY_ID_DEFAULT, {150, 50}))
4785 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
4786 firstWindowInPrimary->assertNoEvents();
Prabir Pradhan65455c72024-02-13 21:46:41 +00004787 secondWindowInPrimary->consumeMotionMove(ADISPLAY_ID_DEFAULT,
4788 AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
Arthur Hungabbb9d82021-09-01 14:52:30 +00004789
4790 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07004791 injectMotionUp(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
Arthur Hungabbb9d82021-09-01 14:52:30 +00004792 {150, 50}))
4793 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
4794 firstWindowInPrimary->assertNoEvents();
Prabir Pradhan65455c72024-02-13 21:46:41 +00004795 secondWindowInPrimary->consumeMotionUp(ADISPLAY_ID_DEFAULT, AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
Arthur Hungabbb9d82021-09-01 14:52:30 +00004796}
4797
Prabir Pradhan367f3432024-02-13 23:05:58 +00004798// Same as TransferTouch_CloneSurface, but this touch on the secondary display and use
4799// 'transferTouchOnDisplay' api.
4800TEST_F(InputDispatcherTest, TransferTouchOnDisplay_CloneSurface) {
Arthur Hungabbb9d82021-09-01 14:52:30 +00004801 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
4802 sp<FakeWindowHandle> firstWindowInPrimary =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07004803 sp<FakeWindowHandle>::make(application, mDispatcher, "D_1_W1", ADISPLAY_ID_DEFAULT);
Arthur Hungabbb9d82021-09-01 14:52:30 +00004804 firstWindowInPrimary->setFrame(Rect(0, 0, 100, 100));
Arthur Hungabbb9d82021-09-01 14:52:30 +00004805 sp<FakeWindowHandle> secondWindowInPrimary =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07004806 sp<FakeWindowHandle>::make(application, mDispatcher, "D_1_W2", ADISPLAY_ID_DEFAULT);
Arthur Hungabbb9d82021-09-01 14:52:30 +00004807 secondWindowInPrimary->setFrame(Rect(100, 0, 200, 100));
Arthur Hungabbb9d82021-09-01 14:52:30 +00004808
Siarhei Vishniakouadb9fc92023-05-26 10:46:09 -07004809 sp<FakeWindowHandle> mirrorWindowInPrimary = firstWindowInPrimary->clone(ADISPLAY_ID_DEFAULT);
Arthur Hungabbb9d82021-09-01 14:52:30 +00004810 mirrorWindowInPrimary->setFrame(Rect(0, 100, 100, 200));
Arthur Hungabbb9d82021-09-01 14:52:30 +00004811
Siarhei Vishniakouadb9fc92023-05-26 10:46:09 -07004812 sp<FakeWindowHandle> firstWindowInSecondary = firstWindowInPrimary->clone(SECOND_DISPLAY_ID);
Arthur Hungabbb9d82021-09-01 14:52:30 +00004813 firstWindowInSecondary->setFrame(Rect(0, 0, 100, 100));
Arthur Hungabbb9d82021-09-01 14:52:30 +00004814
Siarhei Vishniakouadb9fc92023-05-26 10:46:09 -07004815 sp<FakeWindowHandle> secondWindowInSecondary = secondWindowInPrimary->clone(SECOND_DISPLAY_ID);
Arthur Hungabbb9d82021-09-01 14:52:30 +00004816 secondWindowInPrimary->setFrame(Rect(100, 0, 200, 100));
Arthur Hungabbb9d82021-09-01 14:52:30 +00004817
4818 // Update window info, let it find window handle of second display first.
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07004819 mDispatcher->onWindowInfosChanged(
4820 {{*firstWindowInSecondary->getInfo(), *secondWindowInSecondary->getInfo(),
4821 *mirrorWindowInPrimary->getInfo(), *firstWindowInPrimary->getInfo(),
4822 *secondWindowInPrimary->getInfo()},
4823 {},
4824 0,
4825 0});
Arthur Hungabbb9d82021-09-01 14:52:30 +00004826
4827 // Touch on second display.
4828 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07004829 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, SECOND_DISPLAY_ID,
4830 {50, 50}))
Arthur Hungabbb9d82021-09-01 14:52:30 +00004831 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
4832
4833 // Window should receive motion event.
Prabir Pradhanbb3f1c02024-01-04 20:17:14 +00004834 firstWindowInSecondary->consumeMotionDown(SECOND_DISPLAY_ID);
Arthur Hungabbb9d82021-09-01 14:52:30 +00004835
4836 // Transfer touch focus
Prabir Pradhan367f3432024-02-13 23:05:58 +00004837 ASSERT_TRUE(mDispatcher->transferTouchOnDisplay(secondWindowInSecondary->getToken(),
4838 SECOND_DISPLAY_ID));
Arthur Hungabbb9d82021-09-01 14:52:30 +00004839
4840 // The first window gets cancel.
Prabir Pradhanbb3f1c02024-01-04 20:17:14 +00004841 firstWindowInSecondary->consumeMotionCancel(SECOND_DISPLAY_ID);
Prabir Pradhan65455c72024-02-13 21:46:41 +00004842 secondWindowInSecondary->consumeMotionDown(SECOND_DISPLAY_ID,
4843 AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
Arthur Hungabbb9d82021-09-01 14:52:30 +00004844
4845 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07004846 injectMotionEvent(*mDispatcher, AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN,
Arthur Hungabbb9d82021-09-01 14:52:30 +00004847 SECOND_DISPLAY_ID, {150, 50}))
4848 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
Prabir Pradhanbb3f1c02024-01-04 20:17:14 +00004849 firstWindowInSecondary->assertNoEvents();
Prabir Pradhan65455c72024-02-13 21:46:41 +00004850 secondWindowInSecondary->consumeMotionMove(SECOND_DISPLAY_ID,
4851 AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
Arthur Hungabbb9d82021-09-01 14:52:30 +00004852
4853 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07004854 injectMotionUp(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, SECOND_DISPLAY_ID, {150, 50}))
Arthur Hungabbb9d82021-09-01 14:52:30 +00004855 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
Prabir Pradhanbb3f1c02024-01-04 20:17:14 +00004856 firstWindowInSecondary->assertNoEvents();
Prabir Pradhan65455c72024-02-13 21:46:41 +00004857 secondWindowInSecondary->consumeMotionUp(SECOND_DISPLAY_ID, AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
Arthur Hungabbb9d82021-09-01 14:52:30 +00004858}
4859
Siarhei Vishniakouf1035d42019-09-20 16:32:01 +01004860TEST_F(InputDispatcherTest, FocusedWindow_ReceivesFocusEventAndKeyEvent) {
Chris Yea209fde2020-07-22 13:54:51 -07004861 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07004862 sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher,
4863 "Fake Window", ADISPLAY_ID_DEFAULT);
Siarhei Vishniakouf1035d42019-09-20 16:32:01 +01004864
Vishnu Nair47074b82020-08-14 11:54:47 -07004865 window->setFocusable(true);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07004866 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Vishnu Nair958da932020-08-21 17:12:37 -07004867 setFocusedWindow(window);
Siarhei Vishniakouf1035d42019-09-20 16:32:01 +01004868
4869 window->consumeFocusEvent(true);
4870
Prabir Pradhan678438e2023-04-13 19:32:51 +00004871 mDispatcher->notifyKey(generateKeyArgs(AKEY_EVENT_ACTION_DOWN, ADISPLAY_ID_DEFAULT));
Siarhei Vishniakouf1035d42019-09-20 16:32:01 +01004872
4873 // Window should receive key down event.
4874 window->consumeKeyDown(ADISPLAY_ID_DEFAULT);
Josep del Riob3981622023-04-18 15:49:45 +00004875
4876 // Should have poked user activity
Siarhei Vishniakou4fd86732023-05-24 17:33:01 +00004877 mDispatcher->waitForIdle();
Josep del Riob3981622023-04-18 15:49:45 +00004878 mFakePolicy->assertUserActivityPoked();
4879}
4880
4881TEST_F(InputDispatcherTest, FocusedWindow_DisableUserActivity) {
4882 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
4883 sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher,
4884 "Fake Window", ADISPLAY_ID_DEFAULT);
4885
4886 window->setDisableUserActivity(true);
4887 window->setFocusable(true);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07004888 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Josep del Riob3981622023-04-18 15:49:45 +00004889 setFocusedWindow(window);
4890
4891 window->consumeFocusEvent(true);
4892
4893 mDispatcher->notifyKey(generateKeyArgs(AKEY_EVENT_ACTION_DOWN, ADISPLAY_ID_DEFAULT));
4894
4895 // Window should receive key down event.
4896 window->consumeKeyDown(ADISPLAY_ID_DEFAULT);
4897
4898 // Should have poked user activity
Siarhei Vishniakou4fd86732023-05-24 17:33:01 +00004899 mDispatcher->waitForIdle();
Josep del Riob3981622023-04-18 15:49:45 +00004900 mFakePolicy->assertUserActivityNotPoked();
4901}
4902
4903TEST_F(InputDispatcherTest, FocusedWindow_DoesNotReceiveSystemShortcut) {
4904 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
4905 sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher,
4906 "Fake Window", ADISPLAY_ID_DEFAULT);
4907
4908 window->setFocusable(true);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07004909 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Josep del Riob3981622023-04-18 15:49:45 +00004910 setFocusedWindow(window);
4911
4912 window->consumeFocusEvent(true);
4913
4914 mDispatcher->notifyKey(generateSystemShortcutArgs(AKEY_EVENT_ACTION_DOWN, ADISPLAY_ID_DEFAULT));
4915 mDispatcher->waitForIdle();
4916
4917 // System key is not passed down
4918 window->assertNoEvents();
4919
4920 // Should have poked user activity
4921 mFakePolicy->assertUserActivityPoked();
4922}
4923
4924TEST_F(InputDispatcherTest, FocusedWindow_DoesNotReceiveAssistantKey) {
4925 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
4926 sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher,
4927 "Fake Window", ADISPLAY_ID_DEFAULT);
4928
4929 window->setFocusable(true);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07004930 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Josep del Riob3981622023-04-18 15:49:45 +00004931 setFocusedWindow(window);
4932
4933 window->consumeFocusEvent(true);
4934
4935 mDispatcher->notifyKey(generateAssistantKeyArgs(AKEY_EVENT_ACTION_DOWN, ADISPLAY_ID_DEFAULT));
4936 mDispatcher->waitForIdle();
4937
4938 // System key is not passed down
4939 window->assertNoEvents();
4940
4941 // Should have poked user activity
4942 mFakePolicy->assertUserActivityPoked();
4943}
4944
4945TEST_F(InputDispatcherTest, FocusedWindow_SystemKeyIgnoresDisableUserActivity) {
4946 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
4947 sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher,
4948 "Fake Window", ADISPLAY_ID_DEFAULT);
4949
4950 window->setDisableUserActivity(true);
4951 window->setFocusable(true);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07004952 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Josep del Riob3981622023-04-18 15:49:45 +00004953 setFocusedWindow(window);
4954
4955 window->consumeFocusEvent(true);
4956
4957 mDispatcher->notifyKey(generateSystemShortcutArgs(AKEY_EVENT_ACTION_DOWN, ADISPLAY_ID_DEFAULT));
4958 mDispatcher->waitForIdle();
4959
4960 // System key is not passed down
4961 window->assertNoEvents();
4962
4963 // Should have poked user activity
4964 mFakePolicy->assertUserActivityPoked();
Siarhei Vishniakouf1035d42019-09-20 16:32:01 +01004965}
4966
Siarhei Vishniakou90ee4782023-05-08 11:57:24 -07004967TEST_F(InputDispatcherTest, InjectedTouchesPokeUserActivity) {
4968 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
4969 sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher,
4970 "Fake Window", ADISPLAY_ID_DEFAULT);
4971
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07004972 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Siarhei Vishniakou90ee4782023-05-08 11:57:24 -07004973
4974 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07004975 injectMotionEvent(*mDispatcher, AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN,
Siarhei Vishniakou90ee4782023-05-08 11:57:24 -07004976 ADISPLAY_ID_DEFAULT, {100, 100}))
4977 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
4978
4979 window->consumeMotionEvent(
4980 AllOf(WithMotionAction(ACTION_DOWN), WithDisplayId(ADISPLAY_ID_DEFAULT)));
4981
4982 // Should have poked user activity
Siarhei Vishniakou4fd86732023-05-24 17:33:01 +00004983 mDispatcher->waitForIdle();
Siarhei Vishniakou90ee4782023-05-08 11:57:24 -07004984 mFakePolicy->assertUserActivityPoked();
4985}
4986
Siarhei Vishniakouf1035d42019-09-20 16:32:01 +01004987TEST_F(InputDispatcherTest, UnfocusedWindow_DoesNotReceiveFocusEventOrKeyEvent) {
Chris Yea209fde2020-07-22 13:54:51 -07004988 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07004989 sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher,
4990 "Fake Window", ADISPLAY_ID_DEFAULT);
Siarhei Vishniakouf1035d42019-09-20 16:32:01 +01004991
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07004992 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Siarhei Vishniakouf1035d42019-09-20 16:32:01 +01004993
Prabir Pradhan678438e2023-04-13 19:32:51 +00004994 mDispatcher->notifyKey(generateKeyArgs(AKEY_EVENT_ACTION_DOWN, ADISPLAY_ID_DEFAULT));
Siarhei Vishniakouf1035d42019-09-20 16:32:01 +01004995 mDispatcher->waitForIdle();
4996
4997 window->assertNoEvents();
4998}
4999
5000// If a window is touchable, but does not have focus, it should receive motion events, but not keys
5001TEST_F(InputDispatcherTest, UnfocusedWindow_ReceivesMotionsButNotKeys) {
Chris Yea209fde2020-07-22 13:54:51 -07005002 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07005003 sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher,
5004 "Fake Window", ADISPLAY_ID_DEFAULT);
Siarhei Vishniakouf1035d42019-09-20 16:32:01 +01005005
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07005006 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Siarhei Vishniakouf1035d42019-09-20 16:32:01 +01005007
5008 // Send key
Prabir Pradhan678438e2023-04-13 19:32:51 +00005009 mDispatcher->notifyKey(generateKeyArgs(AKEY_EVENT_ACTION_DOWN, ADISPLAY_ID_DEFAULT));
Siarhei Vishniakouf1035d42019-09-20 16:32:01 +01005010 // Send motion
Prabir Pradhan678438e2023-04-13 19:32:51 +00005011 mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_DOWN,
5012 AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT));
Siarhei Vishniakouf1035d42019-09-20 16:32:01 +01005013
5014 // Window should receive only the motion event
5015 window->consumeMotionDown(ADISPLAY_ID_DEFAULT);
5016 window->assertNoEvents(); // Key event or focus event will not be received
5017}
5018
arthurhungea3f4fc2020-12-21 23:18:53 +08005019TEST_F(InputDispatcherTest, PointerCancel_SendCancelWhenSplitTouch) {
5020 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
5021
arthurhungea3f4fc2020-12-21 23:18:53 +08005022 sp<FakeWindowHandle> firstWindow =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07005023 sp<FakeWindowHandle>::make(application, mDispatcher, "First Window",
5024 ADISPLAY_ID_DEFAULT);
arthurhungea3f4fc2020-12-21 23:18:53 +08005025 firstWindow->setFrame(Rect(0, 0, 600, 400));
arthurhungea3f4fc2020-12-21 23:18:53 +08005026
arthurhungea3f4fc2020-12-21 23:18:53 +08005027 sp<FakeWindowHandle> secondWindow =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07005028 sp<FakeWindowHandle>::make(application, mDispatcher, "Second Window",
5029 ADISPLAY_ID_DEFAULT);
arthurhungea3f4fc2020-12-21 23:18:53 +08005030 secondWindow->setFrame(Rect(0, 400, 600, 800));
arthurhungea3f4fc2020-12-21 23:18:53 +08005031
5032 // Add the windows to the dispatcher
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07005033 mDispatcher->onWindowInfosChanged(
5034 {{*firstWindow->getInfo(), *secondWindow->getInfo()}, {}, 0, 0});
arthurhungea3f4fc2020-12-21 23:18:53 +08005035
5036 PointF pointInFirst = {300, 200};
5037 PointF pointInSecond = {300, 600};
5038
5039 // Send down to the first window
Prabir Pradhan678438e2023-04-13 19:32:51 +00005040 mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_DOWN,
5041 AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
5042 {pointInFirst}));
arthurhungea3f4fc2020-12-21 23:18:53 +08005043 // Only the first window should get the down event
5044 firstWindow->consumeMotionDown();
5045 secondWindow->assertNoEvents();
5046
5047 // Send down to the second window
Prabir Pradhan678438e2023-04-13 19:32:51 +00005048 mDispatcher->notifyMotion(generateMotionArgs(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN,
5049 ADISPLAY_ID_DEFAULT,
5050 {pointInFirst, pointInSecond}));
arthurhungea3f4fc2020-12-21 23:18:53 +08005051 // The first window gets a move and the second a down
5052 firstWindow->consumeMotionMove();
5053 secondWindow->consumeMotionDown();
5054
5055 // Send pointer cancel to the second window
5056 NotifyMotionArgs pointerUpMotionArgs =
Siarhei Vishniakoua16e3a22022-03-02 15:26:40 -08005057 generateMotionArgs(POINTER_1_UP, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
arthurhungea3f4fc2020-12-21 23:18:53 +08005058 {pointInFirst, pointInSecond});
5059 pointerUpMotionArgs.flags |= AMOTION_EVENT_FLAG_CANCELED;
Prabir Pradhan678438e2023-04-13 19:32:51 +00005060 mDispatcher->notifyMotion(pointerUpMotionArgs);
arthurhungea3f4fc2020-12-21 23:18:53 +08005061 // The first window gets move and the second gets cancel.
5062 firstWindow->consumeMotionMove(ADISPLAY_ID_DEFAULT, AMOTION_EVENT_FLAG_CANCELED);
5063 secondWindow->consumeMotionCancel(ADISPLAY_ID_DEFAULT, AMOTION_EVENT_FLAG_CANCELED);
5064
5065 // Send up event.
Prabir Pradhan678438e2023-04-13 19:32:51 +00005066 mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN,
5067 ADISPLAY_ID_DEFAULT));
arthurhungea3f4fc2020-12-21 23:18:53 +08005068 // The first window gets up and the second gets nothing.
5069 firstWindow->consumeMotionUp();
5070 secondWindow->assertNoEvents();
5071}
5072
Siarhei Vishniakouf94ae022021-02-04 01:23:17 +00005073TEST_F(InputDispatcherTest, SendTimeline_DoesNotCrashDispatcher) {
5074 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
5075
5076 sp<FakeWindowHandle> window =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07005077 sp<FakeWindowHandle>::make(application, mDispatcher, "Window", ADISPLAY_ID_DEFAULT);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07005078 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Siarhei Vishniakouf94ae022021-02-04 01:23:17 +00005079 std::array<nsecs_t, GraphicsTimeline::SIZE> graphicsTimeline;
5080 graphicsTimeline[GraphicsTimeline::GPU_COMPLETED_TIME] = 2;
5081 graphicsTimeline[GraphicsTimeline::PRESENT_TIME] = 3;
5082
Harry Cutts33476232023-01-30 19:57:29 +00005083 window->sendTimeline(/*inputEventId=*/1, graphicsTimeline);
Siarhei Vishniakouf94ae022021-02-04 01:23:17 +00005084 window->assertNoEvents();
5085 mDispatcher->waitForIdle();
5086}
5087
Prabir Pradhan1376fcd2022-01-21 09:56:35 -08005088using InputDispatcherMonitorTest = InputDispatcherTest;
5089
Siarhei Vishniakouca205502021-07-16 21:31:58 +00005090/**
5091 * Two entities that receive touch: A window, and a global monitor.
5092 * The touch goes to the window, and then the window disappears.
5093 * The monitor does not get cancel right away. But if more events come in, the touch gets canceled
5094 * for the monitor, as well.
5095 * 1. foregroundWindow
5096 * 2. monitor <-- global monitor (doesn't observe z order, receives all events)
5097 */
Prabir Pradhan1376fcd2022-01-21 09:56:35 -08005098TEST_F(InputDispatcherMonitorTest, MonitorTouchIsCanceledWhenForegroundWindowDisappears) {
Siarhei Vishniakouca205502021-07-16 21:31:58 +00005099 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
5100 sp<FakeWindowHandle> window =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07005101 sp<FakeWindowHandle>::make(application, mDispatcher, "Foreground", ADISPLAY_ID_DEFAULT);
Siarhei Vishniakouca205502021-07-16 21:31:58 +00005102
Prabir Pradhanfb549072023-10-05 19:17:36 +00005103 FakeMonitorReceiver monitor = FakeMonitorReceiver(*mDispatcher, "M_1", ADISPLAY_ID_DEFAULT);
Siarhei Vishniakouca205502021-07-16 21:31:58 +00005104
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07005105 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Siarhei Vishniakouca205502021-07-16 21:31:58 +00005106 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07005107 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
Siarhei Vishniakouca205502021-07-16 21:31:58 +00005108 {100, 200}))
5109 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
5110
5111 // Both the foreground window and the global monitor should receive the touch down
5112 window->consumeMotionDown();
5113 monitor.consumeMotionDown(ADISPLAY_ID_DEFAULT);
5114
5115 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07005116 injectMotionEvent(*mDispatcher, AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN,
Siarhei Vishniakouca205502021-07-16 21:31:58 +00005117 ADISPLAY_ID_DEFAULT, {110, 200}))
5118 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
5119
5120 window->consumeMotionMove();
5121 monitor.consumeMotionMove(ADISPLAY_ID_DEFAULT);
5122
5123 // Now the foreground window goes away
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07005124 mDispatcher->onWindowInfosChanged({{}, {}, 0, 0});
Siarhei Vishniakouca205502021-07-16 21:31:58 +00005125 window->consumeMotionCancel();
5126 monitor.assertNoEvents(); // Global monitor does not get a cancel yet
5127
5128 // If more events come in, there will be no more foreground window to send them to. This will
5129 // cause a cancel for the monitor, as well.
5130 ASSERT_EQ(InputEventInjectionResult::FAILED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07005131 injectMotionEvent(*mDispatcher, AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN,
Siarhei Vishniakouca205502021-07-16 21:31:58 +00005132 ADISPLAY_ID_DEFAULT, {120, 200}))
5133 << "Injection should fail because the window was removed";
5134 window->assertNoEvents();
5135 // Global monitor now gets the cancel
5136 monitor.consumeMotionCancel(ADISPLAY_ID_DEFAULT);
5137}
5138
Prabir Pradhan1376fcd2022-01-21 09:56:35 -08005139TEST_F(InputDispatcherMonitorTest, ReceivesMotionEvents) {
Chris Yea209fde2020-07-22 13:54:51 -07005140 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07005141 sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher,
5142 "Fake Window", ADISPLAY_ID_DEFAULT);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07005143 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Michael Wright3a240c42019-12-10 20:53:41 +00005144
Prabir Pradhanfb549072023-10-05 19:17:36 +00005145 FakeMonitorReceiver monitor = FakeMonitorReceiver(*mDispatcher, "M_1", ADISPLAY_ID_DEFAULT);
Michael Wright3a240c42019-12-10 20:53:41 +00005146
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08005147 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07005148 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT))
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08005149 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
Michael Wright3a240c42019-12-10 20:53:41 +00005150 window->consumeMotionDown(ADISPLAY_ID_DEFAULT);
chaviwd1c23182019-12-20 18:44:56 -08005151 monitor.consumeMotionDown(ADISPLAY_ID_DEFAULT);
Michael Wright3a240c42019-12-10 20:53:41 +00005152}
5153
Prabir Pradhan1376fcd2022-01-21 09:56:35 -08005154TEST_F(InputDispatcherMonitorTest, MonitorCannotPilferPointers) {
Prabir Pradhanfb549072023-10-05 19:17:36 +00005155 FakeMonitorReceiver monitor = FakeMonitorReceiver(*mDispatcher, "M_1", ADISPLAY_ID_DEFAULT);
Michael Wright3a240c42019-12-10 20:53:41 +00005156
Chris Yea209fde2020-07-22 13:54:51 -07005157 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07005158 sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher,
5159 "Fake Window", ADISPLAY_ID_DEFAULT);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07005160 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Michael Wright3a240c42019-12-10 20:53:41 +00005161
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08005162 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07005163 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT))
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08005164 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
chaviwd1c23182019-12-20 18:44:56 -08005165 monitor.consumeMotionDown(ADISPLAY_ID_DEFAULT);
Prabir Pradhan1376fcd2022-01-21 09:56:35 -08005166 window->consumeMotionDown(ADISPLAY_ID_DEFAULT);
Michael Wright3a240c42019-12-10 20:53:41 +00005167
Prabir Pradhan1376fcd2022-01-21 09:56:35 -08005168 // Pilfer pointers from the monitor.
5169 // This should not do anything and the window should continue to receive events.
5170 EXPECT_NE(OK, mDispatcher->pilferPointers(monitor.getToken()));
Michael Wright3a240c42019-12-10 20:53:41 +00005171
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08005172 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07005173 injectMotionEvent(*mDispatcher, AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN,
Prabir Pradhan1376fcd2022-01-21 09:56:35 -08005174 ADISPLAY_ID_DEFAULT))
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08005175 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
Prabir Pradhan1376fcd2022-01-21 09:56:35 -08005176
5177 monitor.consumeMotionMove(ADISPLAY_ID_DEFAULT);
5178 window->consumeMotionMove(ADISPLAY_ID_DEFAULT);
Michael Wright3a240c42019-12-10 20:53:41 +00005179}
5180
Prabir Pradhan1376fcd2022-01-21 09:56:35 -08005181TEST_F(InputDispatcherMonitorTest, NoWindowTransform) {
Evan Rosky84f07f02021-04-16 10:42:42 -07005182 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07005183 sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher,
5184 "Fake Window", ADISPLAY_ID_DEFAULT);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07005185 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Evan Rosky84f07f02021-04-16 10:42:42 -07005186 window->setWindowOffset(20, 40);
5187 window->setWindowTransform(0, 1, -1, 0);
5188
Prabir Pradhanfb549072023-10-05 19:17:36 +00005189 FakeMonitorReceiver monitor = FakeMonitorReceiver(*mDispatcher, "M_1", ADISPLAY_ID_DEFAULT);
Evan Rosky84f07f02021-04-16 10:42:42 -07005190
5191 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07005192 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT))
Evan Rosky84f07f02021-04-16 10:42:42 -07005193 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
5194 window->consumeMotionDown(ADISPLAY_ID_DEFAULT);
Siarhei Vishniakoud3061ab2023-12-18 20:41:08 -08005195 std::unique_ptr<MotionEvent> event = monitor.consumeMotion();
5196 ASSERT_NE(nullptr, event);
Evan Rosky84f07f02021-04-16 10:42:42 -07005197 // Even though window has transform, gesture monitor must not.
5198 ASSERT_EQ(ui::Transform(), event->getTransform());
5199}
5200
Prabir Pradhan1376fcd2022-01-21 09:56:35 -08005201TEST_F(InputDispatcherMonitorTest, InjectionFailsWithNoWindow) {
Arthur Hungb3307ee2021-10-14 10:57:37 +00005202 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
Prabir Pradhanfb549072023-10-05 19:17:36 +00005203 FakeMonitorReceiver monitor = FakeMonitorReceiver(*mDispatcher, "M_1", ADISPLAY_ID_DEFAULT);
Arthur Hungb3307ee2021-10-14 10:57:37 +00005204
Prabir Pradhan1376fcd2022-01-21 09:56:35 -08005205 ASSERT_EQ(InputEventInjectionResult::FAILED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07005206 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT))
Prabir Pradhan1376fcd2022-01-21 09:56:35 -08005207 << "Injection should fail if there is a monitor, but no touchable window";
5208 monitor.assertNoEvents();
Arthur Hungb3307ee2021-10-14 10:57:37 +00005209}
5210
Linnan Lid8150952024-01-26 18:07:17 +00005211/**
5212 * Two displays
5213 * The first monitor has a foreground window, a monitor
5214 * The second window has only one monitor.
5215 * We first inject a Down event into the first display, this injection should succeed and both
5216 * the foreground window and monitor should receive a down event, then inject a Down event into
5217 * the second display as well, this injection should fail, at this point, the first display
5218 * window and monitor should not receive a cancel or any other event.
5219 * Continue to inject Move and UP events to the first display, the events should be received
5220 * normally by the foreground window and monitor.
5221 */
5222TEST_F(InputDispatcherMonitorTest, MonitorTouchIsNotCanceledWhenAnotherEmptyDisplayReceiveEvents) {
5223 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
5224 sp<FakeWindowHandle> window =
5225 sp<FakeWindowHandle>::make(application, mDispatcher, "Foreground", ADISPLAY_ID_DEFAULT);
5226
5227 FakeMonitorReceiver monitor = FakeMonitorReceiver(*mDispatcher, "M_1", ADISPLAY_ID_DEFAULT);
5228 FakeMonitorReceiver secondMonitor = FakeMonitorReceiver(*mDispatcher, "M_2", SECOND_DISPLAY_ID);
5229
5230 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
5231 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
5232 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
5233 {100, 200}))
5234 << "The down event injected into the first display should succeed";
5235
5236 window->consumeMotionDown();
5237 monitor.consumeMotionDown(ADISPLAY_ID_DEFAULT);
Linnan Lid8150952024-01-26 18:07:17 +00005238
5239 ASSERT_EQ(InputEventInjectionResult::FAILED,
5240 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, SECOND_DISPLAY_ID,
5241 {100, 200}))
Prabir Pradhana0d43d42024-01-30 00:27:08 +00005242 << "The down event injected into the second display should fail since there's no "
5243 "touchable window";
Linnan Lid8150952024-01-26 18:07:17 +00005244
5245 // Continue to inject event to first display.
5246 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
5247 injectMotionEvent(*mDispatcher, AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN,
5248 ADISPLAY_ID_DEFAULT, {110, 220}))
5249 << "The move event injected into the first display should succeed";
5250
5251 window->consumeMotionMove();
5252 monitor.consumeMotionMove(ADISPLAY_ID_DEFAULT);
Linnan Lid8150952024-01-26 18:07:17 +00005253
5254 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
5255 injectMotionUp(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
5256 {110, 220}))
5257 << "The up event injected into the first display should succeed";
5258
5259 window->consumeMotionUp();
5260 monitor.consumeMotionUp(ADISPLAY_ID_DEFAULT);
Prabir Pradhana0d43d42024-01-30 00:27:08 +00005261
5262 window->assertNoEvents();
5263 monitor.assertNoEvents();
Linnan Lid8150952024-01-26 18:07:17 +00005264 secondMonitor.assertNoEvents();
5265}
5266
5267/**
5268 * Two displays
5269 * There is a monitor and foreground window on each display.
5270 * First, we inject down events into each of the two displays, at this point, the foreground windows
5271 * and monitors on both displays should receive down events.
5272 * At this point, the foreground window of the second display goes away, the gone window should
5273 * receive the cancel event, and the other windows and monitors should not receive any events.
5274 * Inject a move event into the second display. At this point, the injection should fail because
5275 * the second display no longer has a foreground window. At this point, the monitor on the second
5276 * display should receive a cancel event, and any windows or monitors on the first display should
5277 * not receive any events, and any subsequent injection of events into the second display should
5278 * also fail.
5279 * Continue to inject events into the first display, and the events should all be injected
5280 * successfully and received normally.
5281 */
5282TEST_F(InputDispatcherMonitorTest, MonitorTouchIsNotCancelWhenAnotherDisplayMonitorTouchCanceled) {
5283 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
5284 sp<FakeWindowHandle> window =
5285 sp<FakeWindowHandle>::make(application, mDispatcher, "Foreground", ADISPLAY_ID_DEFAULT);
5286 sp<FakeWindowHandle> secondWindow =
5287 sp<FakeWindowHandle>::make(application, mDispatcher, "SecondForeground",
5288 SECOND_DISPLAY_ID);
5289
5290 FakeMonitorReceiver monitor = FakeMonitorReceiver(*mDispatcher, "M_1", ADISPLAY_ID_DEFAULT);
5291 FakeMonitorReceiver secondMonitor = FakeMonitorReceiver(*mDispatcher, "M_2", SECOND_DISPLAY_ID);
5292
5293 // There is a foreground window on both displays.
5294 mDispatcher->onWindowInfosChanged({{*window->getInfo(), *secondWindow->getInfo()}, {}, 0, 0});
5295 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
5296 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
5297 {100, 200}))
5298 << "The down event injected into the first display should succeed";
5299
5300 window->consumeMotionDown(ADISPLAY_ID_DEFAULT);
5301 monitor.consumeMotionDown(ADISPLAY_ID_DEFAULT);
Linnan Lid8150952024-01-26 18:07:17 +00005302
5303 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
5304 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, SECOND_DISPLAY_ID,
5305 {100, 200}))
5306 << "The down event injected into the second display should succeed";
5307
Linnan Lid8150952024-01-26 18:07:17 +00005308 secondWindow->consumeMotionDown(SECOND_DISPLAY_ID);
5309 secondMonitor.consumeMotionDown(SECOND_DISPLAY_ID);
5310
5311 // Now second window is gone away.
5312 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
5313
5314 // The gone window should receive a cancel, and the monitor on the second display should not
5315 // receive any events.
Linnan Lid8150952024-01-26 18:07:17 +00005316 secondWindow->consumeMotionCancel(SECOND_DISPLAY_ID);
5317 secondMonitor.assertNoEvents();
5318
5319 ASSERT_EQ(InputEventInjectionResult::FAILED,
5320 injectMotionEvent(*mDispatcher, AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN,
5321 SECOND_DISPLAY_ID, {110, 220}))
Prabir Pradhana0d43d42024-01-30 00:27:08 +00005322 << "The move event injected into the second display should fail because there's no "
5323 "touchable window";
Linnan Lid8150952024-01-26 18:07:17 +00005324 // Now the monitor on the second display should receive a cancel event.
5325 secondMonitor.consumeMotionCancel(SECOND_DISPLAY_ID);
Linnan Lid8150952024-01-26 18:07:17 +00005326
5327 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
5328 injectMotionEvent(*mDispatcher, AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN,
5329 ADISPLAY_ID_DEFAULT, {110, 200}))
5330 << "The move event injected into the first display should succeed";
5331
5332 window->consumeMotionMove();
5333 monitor.consumeMotionMove(ADISPLAY_ID_DEFAULT);
Linnan Lid8150952024-01-26 18:07:17 +00005334
5335 ASSERT_EQ(InputEventInjectionResult::FAILED,
Prabir Pradhana0d43d42024-01-30 00:27:08 +00005336 injectMotionUp(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, SECOND_DISPLAY_ID,
5337 {110, 220}))
5338 << "The up event injected into the second display should fail because there's no "
5339 "touchable window";
Linnan Lid8150952024-01-26 18:07:17 +00005340
5341 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
5342 injectMotionUp(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
5343 {110, 220}))
5344 << "The up event injected into the first display should succeed";
5345
5346 window->consumeMotionUp(ADISPLAY_ID_DEFAULT);
5347 monitor.consumeMotionUp(ADISPLAY_ID_DEFAULT);
Prabir Pradhana0d43d42024-01-30 00:27:08 +00005348
Linnan Lid8150952024-01-26 18:07:17 +00005349 window->assertNoEvents();
5350 monitor.assertNoEvents();
Prabir Pradhana0d43d42024-01-30 00:27:08 +00005351 secondWindow->assertNoEvents();
5352 secondMonitor.assertNoEvents();
Linnan Lid8150952024-01-26 18:07:17 +00005353}
5354
5355/**
5356 * One display with transform
5357 * There is a foreground window and a monitor on the display
5358 * Inject down event and move event sequentially, the foreground window and monitor can receive down
5359 * event and move event, then let the foreground window go away, the foreground window receives
5360 * cancel event, inject move event again, the monitor receives cancel event, all the events received
5361 * by the monitor should be with the same transform as the display
5362 */
5363TEST_F(InputDispatcherMonitorTest, MonitorTouchCancelEventWithDisplayTransform) {
5364 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
5365 sp<FakeWindowHandle> window =
5366 sp<FakeWindowHandle>::make(application, mDispatcher, "Foreground", ADISPLAY_ID_DEFAULT);
5367 FakeMonitorReceiver monitor = FakeMonitorReceiver(*mDispatcher, "M_1", ADISPLAY_ID_DEFAULT);
5368
5369 ui::Transform transform;
5370 transform.set({1.1, 2.2, 3.3, 4.4, 5.5, 6.6, 0, 0, 1});
5371
5372 gui::DisplayInfo displayInfo;
5373 displayInfo.displayId = ADISPLAY_ID_DEFAULT;
5374 displayInfo.transform = transform;
5375
5376 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {displayInfo}, 0, 0});
5377
5378 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
5379 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
5380 {100, 200}))
5381 << "The down event injected should succeed";
5382
5383 window->consumeMotionDown();
5384 std::unique_ptr<MotionEvent> downMotionEvent = monitor.consumeMotion();
5385 EXPECT_EQ(transform, downMotionEvent->getTransform());
5386 EXPECT_EQ(AMOTION_EVENT_ACTION_DOWN, downMotionEvent->getAction());
5387
5388 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
5389 injectMotionEvent(*mDispatcher, AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN,
5390 ADISPLAY_ID_DEFAULT, {110, 220}))
5391 << "The move event injected should succeed";
5392
5393 window->consumeMotionMove();
5394 std::unique_ptr<MotionEvent> moveMotionEvent = monitor.consumeMotion();
5395 EXPECT_EQ(transform, moveMotionEvent->getTransform());
5396 EXPECT_EQ(AMOTION_EVENT_ACTION_MOVE, moveMotionEvent->getAction());
5397
5398 // Let foreground window gone
5399 mDispatcher->onWindowInfosChanged({{}, {displayInfo}, 0, 0});
5400
Prabir Pradhana0d43d42024-01-30 00:27:08 +00005401 // Foreground window should receive a cancel event, but not the monitor.
Linnan Lid8150952024-01-26 18:07:17 +00005402 window->consumeMotionCancel();
Linnan Lid8150952024-01-26 18:07:17 +00005403
5404 ASSERT_EQ(InputEventInjectionResult::FAILED,
5405 injectMotionEvent(*mDispatcher, AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN,
5406 ADISPLAY_ID_DEFAULT, {110, 220}))
5407 << "The move event injected should failed";
5408 // Now foreground should not receive any events, but monitor should receive a cancel event
5409 // with transform that same as display's display.
Linnan Lid8150952024-01-26 18:07:17 +00005410 std::unique_ptr<MotionEvent> cancelMotionEvent = monitor.consumeMotion();
5411 EXPECT_EQ(transform, cancelMotionEvent->getTransform());
5412 EXPECT_EQ(ADISPLAY_ID_DEFAULT, cancelMotionEvent->getDisplayId());
5413 EXPECT_EQ(AMOTION_EVENT_ACTION_CANCEL, cancelMotionEvent->getAction());
5414
5415 // Other event inject to this display should fail.
5416 ASSERT_EQ(InputEventInjectionResult::FAILED,
5417 injectMotionEvent(*mDispatcher, AMOTION_EVENT_ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN,
5418 ADISPLAY_ID_DEFAULT, {110, 220}))
Prabir Pradhana0d43d42024-01-30 00:27:08 +00005419 << "The up event injected should fail because the touched window was removed";
Linnan Lid8150952024-01-26 18:07:17 +00005420 window->assertNoEvents();
5421 monitor.assertNoEvents();
5422}
5423
chaviw81e2bb92019-12-18 15:03:51 -08005424TEST_F(InputDispatcherTest, TestMoveEvent) {
Chris Yea209fde2020-07-22 13:54:51 -07005425 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07005426 sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher,
5427 "Fake Window", ADISPLAY_ID_DEFAULT);
chaviw81e2bb92019-12-18 15:03:51 -08005428
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07005429 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
chaviw81e2bb92019-12-18 15:03:51 -08005430
5431 NotifyMotionArgs motionArgs =
5432 generateMotionArgs(AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN,
5433 ADISPLAY_ID_DEFAULT);
5434
Prabir Pradhan678438e2023-04-13 19:32:51 +00005435 mDispatcher->notifyMotion(motionArgs);
chaviw81e2bb92019-12-18 15:03:51 -08005436 // Window should receive motion down event.
5437 window->consumeMotionDown(ADISPLAY_ID_DEFAULT);
5438
5439 motionArgs.action = AMOTION_EVENT_ACTION_MOVE;
Garfield Tanc51d1ba2020-01-28 13:24:04 -08005440 motionArgs.id += 1;
chaviw81e2bb92019-12-18 15:03:51 -08005441 motionArgs.eventTime = systemTime(SYSTEM_TIME_MONOTONIC);
5442 motionArgs.pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_X,
5443 motionArgs.pointerCoords[0].getX() - 10);
5444
Prabir Pradhan678438e2023-04-13 19:32:51 +00005445 mDispatcher->notifyMotion(motionArgs);
Prabir Pradhan7662a8d2023-12-15 01:58:14 +00005446 window->consumeMotionMove(ADISPLAY_ID_DEFAULT, /*expectedFlags=*/0);
chaviw81e2bb92019-12-18 15:03:51 -08005447}
5448
Siarhei Vishniakouf1035d42019-09-20 16:32:01 +01005449/**
5450 * Dispatcher has touch mode enabled by default. Typically, the policy overrides that value to
5451 * the device default right away. In the test scenario, we check both the default value,
5452 * and the action of enabling / disabling.
5453 */
5454TEST_F(InputDispatcherTest, TouchModeState_IsSentToApps) {
Chris Yea209fde2020-07-22 13:54:51 -07005455 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07005456 sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher,
5457 "Test window", ADISPLAY_ID_DEFAULT);
Antonio Kantekea47acb2021-12-23 12:41:25 -08005458 const WindowInfo& windowInfo = *window->getInfo();
Siarhei Vishniakouf1035d42019-09-20 16:32:01 +01005459
5460 // Set focused application.
5461 mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application);
Vishnu Nair47074b82020-08-14 11:54:47 -07005462 window->setFocusable(true);
Siarhei Vishniakouf1035d42019-09-20 16:32:01 +01005463
5464 SCOPED_TRACE("Check default value of touch mode");
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07005465 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Vishnu Nair958da932020-08-21 17:12:37 -07005466 setFocusedWindow(window);
Harry Cutts33476232023-01-30 19:57:29 +00005467 window->consumeFocusEvent(/*hasFocus=*/true, /*inTouchMode=*/true);
Siarhei Vishniakouf1035d42019-09-20 16:32:01 +01005468
5469 SCOPED_TRACE("Remove the window to trigger focus loss");
Vishnu Nair47074b82020-08-14 11:54:47 -07005470 window->setFocusable(false);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07005471 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Harry Cutts33476232023-01-30 19:57:29 +00005472 window->consumeFocusEvent(/*hasFocus=*/false, /*inTouchMode=*/true);
Siarhei Vishniakouf1035d42019-09-20 16:32:01 +01005473
5474 SCOPED_TRACE("Disable touch mode");
Antonio Kantekea47acb2021-12-23 12:41:25 -08005475 mDispatcher->setInTouchMode(false, windowInfo.ownerPid, windowInfo.ownerUid,
Harry Cutts33476232023-01-30 19:57:29 +00005476 /*hasPermission=*/true, ADISPLAY_ID_DEFAULT);
Antonio Kantekf16f2832021-09-28 04:39:20 +00005477 window->consumeTouchModeEvent(false);
Vishnu Nair47074b82020-08-14 11:54:47 -07005478 window->setFocusable(true);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07005479 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Vishnu Nair958da932020-08-21 17:12:37 -07005480 setFocusedWindow(window);
Harry Cutts33476232023-01-30 19:57:29 +00005481 window->consumeFocusEvent(/*hasFocus=*/true, /*inTouchMode=*/false);
Siarhei Vishniakouf1035d42019-09-20 16:32:01 +01005482
5483 SCOPED_TRACE("Remove the window to trigger focus loss");
Vishnu Nair47074b82020-08-14 11:54:47 -07005484 window->setFocusable(false);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07005485 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Harry Cutts33476232023-01-30 19:57:29 +00005486 window->consumeFocusEvent(/*hasFocus=*/false, /*inTouchMode=*/false);
Siarhei Vishniakouf1035d42019-09-20 16:32:01 +01005487
5488 SCOPED_TRACE("Enable touch mode again");
Antonio Kantekea47acb2021-12-23 12:41:25 -08005489 mDispatcher->setInTouchMode(true, windowInfo.ownerPid, windowInfo.ownerUid,
Harry Cutts33476232023-01-30 19:57:29 +00005490 /*hasPermission=*/true, ADISPLAY_ID_DEFAULT);
Antonio Kantekf16f2832021-09-28 04:39:20 +00005491 window->consumeTouchModeEvent(true);
Vishnu Nair47074b82020-08-14 11:54:47 -07005492 window->setFocusable(true);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07005493 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Vishnu Nair958da932020-08-21 17:12:37 -07005494 setFocusedWindow(window);
Harry Cutts33476232023-01-30 19:57:29 +00005495 window->consumeFocusEvent(/*hasFocus=*/true, /*inTouchMode=*/true);
Siarhei Vishniakouf1035d42019-09-20 16:32:01 +01005496
5497 window->assertNoEvents();
5498}
5499
Gang Wange9087892020-01-07 12:17:14 -05005500TEST_F(InputDispatcherTest, VerifyInputEvent_KeyEvent) {
Chris Yea209fde2020-07-22 13:54:51 -07005501 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07005502 sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher,
5503 "Test window", ADISPLAY_ID_DEFAULT);
Gang Wange9087892020-01-07 12:17:14 -05005504
5505 mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application);
Vishnu Nair47074b82020-08-14 11:54:47 -07005506 window->setFocusable(true);
Gang Wange9087892020-01-07 12:17:14 -05005507
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07005508 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Vishnu Nair958da932020-08-21 17:12:37 -07005509 setFocusedWindow(window);
5510
Harry Cutts33476232023-01-30 19:57:29 +00005511 window->consumeFocusEvent(/*hasFocus=*/true, /*inTouchMode=*/true);
Gang Wange9087892020-01-07 12:17:14 -05005512
Prabir Pradhan678438e2023-04-13 19:32:51 +00005513 const NotifyKeyArgs keyArgs = generateKeyArgs(AKEY_EVENT_ACTION_DOWN);
5514 mDispatcher->notifyKey(keyArgs);
Gang Wange9087892020-01-07 12:17:14 -05005515
Siarhei Vishniakoud3061ab2023-12-18 20:41:08 -08005516 std::unique_ptr<KeyEvent> event = window->consumeKey();
5517 ASSERT_NE(event, nullptr);
5518 std::unique_ptr<VerifiedInputEvent> verified = mDispatcher->verifyInputEvent(*event);
Gang Wange9087892020-01-07 12:17:14 -05005519 ASSERT_NE(verified, nullptr);
5520 ASSERT_EQ(verified->type, VerifiedInputEvent::Type::KEY);
5521
5522 ASSERT_EQ(keyArgs.eventTime, verified->eventTimeNanos);
5523 ASSERT_EQ(keyArgs.deviceId, verified->deviceId);
5524 ASSERT_EQ(keyArgs.source, verified->source);
5525 ASSERT_EQ(keyArgs.displayId, verified->displayId);
5526
5527 const VerifiedKeyEvent& verifiedKey = static_cast<const VerifiedKeyEvent&>(*verified);
5528
5529 ASSERT_EQ(keyArgs.action, verifiedKey.action);
Gang Wange9087892020-01-07 12:17:14 -05005530 ASSERT_EQ(keyArgs.flags & VERIFIED_KEY_EVENT_FLAGS, verifiedKey.flags);
Siarhei Vishniakouf355bf92021-12-09 10:43:21 -08005531 ASSERT_EQ(keyArgs.downTime, verifiedKey.downTimeNanos);
Gang Wange9087892020-01-07 12:17:14 -05005532 ASSERT_EQ(keyArgs.keyCode, verifiedKey.keyCode);
5533 ASSERT_EQ(keyArgs.scanCode, verifiedKey.scanCode);
5534 ASSERT_EQ(keyArgs.metaState, verifiedKey.metaState);
5535 ASSERT_EQ(0, verifiedKey.repeatCount);
5536}
5537
Siarhei Vishniakou47040bf2020-02-28 15:03:13 -08005538TEST_F(InputDispatcherTest, VerifyInputEvent_MotionEvent) {
Chris Yea209fde2020-07-22 13:54:51 -07005539 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07005540 sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher,
5541 "Test window", ADISPLAY_ID_DEFAULT);
Siarhei Vishniakou47040bf2020-02-28 15:03:13 -08005542
5543 mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application);
5544
Prabir Pradhanb5cb9572021-09-24 06:35:16 -07005545 ui::Transform transform;
5546 transform.set({1.1, 2.2, 3.3, 4.4, 5.5, 6.6, 0, 0, 1});
5547
5548 gui::DisplayInfo displayInfo;
5549 displayInfo.displayId = ADISPLAY_ID_DEFAULT;
5550 displayInfo.transform = transform;
5551
Patrick Williamsd828f302023-04-28 17:52:08 -05005552 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {displayInfo}, 0, 0});
Siarhei Vishniakou47040bf2020-02-28 15:03:13 -08005553
Prabir Pradhan678438e2023-04-13 19:32:51 +00005554 const NotifyMotionArgs motionArgs =
Siarhei Vishniakou47040bf2020-02-28 15:03:13 -08005555 generateMotionArgs(AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN,
5556 ADISPLAY_ID_DEFAULT);
Prabir Pradhan678438e2023-04-13 19:32:51 +00005557 mDispatcher->notifyMotion(motionArgs);
Siarhei Vishniakou47040bf2020-02-28 15:03:13 -08005558
Siarhei Vishniakoud3061ab2023-12-18 20:41:08 -08005559 std::unique_ptr<MotionEvent> event = window->consumeMotionEvent();
5560 ASSERT_NE(nullptr, event);
5561 std::unique_ptr<VerifiedInputEvent> verified = mDispatcher->verifyInputEvent(*event);
Siarhei Vishniakou47040bf2020-02-28 15:03:13 -08005562 ASSERT_NE(verified, nullptr);
5563 ASSERT_EQ(verified->type, VerifiedInputEvent::Type::MOTION);
5564
5565 EXPECT_EQ(motionArgs.eventTime, verified->eventTimeNanos);
5566 EXPECT_EQ(motionArgs.deviceId, verified->deviceId);
5567 EXPECT_EQ(motionArgs.source, verified->source);
5568 EXPECT_EQ(motionArgs.displayId, verified->displayId);
5569
5570 const VerifiedMotionEvent& verifiedMotion = static_cast<const VerifiedMotionEvent&>(*verified);
5571
Prabir Pradhanb5cb9572021-09-24 06:35:16 -07005572 const vec2 rawXY =
5573 MotionEvent::calculateTransformedXY(motionArgs.source, transform,
5574 motionArgs.pointerCoords[0].getXYValue());
5575 EXPECT_EQ(rawXY.x, verifiedMotion.rawX);
5576 EXPECT_EQ(rawXY.y, verifiedMotion.rawY);
Siarhei Vishniakou47040bf2020-02-28 15:03:13 -08005577 EXPECT_EQ(motionArgs.action & AMOTION_EVENT_ACTION_MASK, verifiedMotion.actionMasked);
Siarhei Vishniakou47040bf2020-02-28 15:03:13 -08005578 EXPECT_EQ(motionArgs.flags & VERIFIED_MOTION_EVENT_FLAGS, verifiedMotion.flags);
Siarhei Vishniakouf355bf92021-12-09 10:43:21 -08005579 EXPECT_EQ(motionArgs.downTime, verifiedMotion.downTimeNanos);
Siarhei Vishniakou47040bf2020-02-28 15:03:13 -08005580 EXPECT_EQ(motionArgs.metaState, verifiedMotion.metaState);
5581 EXPECT_EQ(motionArgs.buttonState, verifiedMotion.buttonState);
5582}
5583
chaviw09c8d2d2020-08-24 15:48:26 -07005584/**
5585 * Ensure that separate calls to sign the same data are generating the same key.
5586 * We avoid asserting against INVALID_HMAC. Since the key is random, there is a non-zero chance
5587 * that a specific key and data combination would produce INVALID_HMAC, which would cause flaky
5588 * tests.
5589 */
5590TEST_F(InputDispatcherTest, GeneratedHmac_IsConsistent) {
5591 KeyEvent event = getTestKeyEvent();
5592 VerifiedKeyEvent verifiedEvent = verifiedKeyEventFromKeyEvent(event);
5593
5594 std::array<uint8_t, 32> hmac1 = mDispatcher->sign(verifiedEvent);
5595 std::array<uint8_t, 32> hmac2 = mDispatcher->sign(verifiedEvent);
5596 ASSERT_EQ(hmac1, hmac2);
5597}
5598
5599/**
5600 * Ensure that changes in VerifiedKeyEvent produce a different hmac.
5601 */
5602TEST_F(InputDispatcherTest, GeneratedHmac_ChangesWhenFieldsChange) {
5603 KeyEvent event = getTestKeyEvent();
5604 VerifiedKeyEvent verifiedEvent = verifiedKeyEventFromKeyEvent(event);
5605 std::array<uint8_t, 32> initialHmac = mDispatcher->sign(verifiedEvent);
5606
5607 verifiedEvent.deviceId += 1;
5608 ASSERT_NE(initialHmac, mDispatcher->sign(verifiedEvent));
5609
5610 verifiedEvent.source += 1;
5611 ASSERT_NE(initialHmac, mDispatcher->sign(verifiedEvent));
5612
5613 verifiedEvent.eventTimeNanos += 1;
5614 ASSERT_NE(initialHmac, mDispatcher->sign(verifiedEvent));
5615
5616 verifiedEvent.displayId += 1;
5617 ASSERT_NE(initialHmac, mDispatcher->sign(verifiedEvent));
5618
5619 verifiedEvent.action += 1;
5620 ASSERT_NE(initialHmac, mDispatcher->sign(verifiedEvent));
5621
5622 verifiedEvent.downTimeNanos += 1;
5623 ASSERT_NE(initialHmac, mDispatcher->sign(verifiedEvent));
5624
5625 verifiedEvent.flags += 1;
5626 ASSERT_NE(initialHmac, mDispatcher->sign(verifiedEvent));
5627
5628 verifiedEvent.keyCode += 1;
5629 ASSERT_NE(initialHmac, mDispatcher->sign(verifiedEvent));
5630
5631 verifiedEvent.scanCode += 1;
5632 ASSERT_NE(initialHmac, mDispatcher->sign(verifiedEvent));
5633
5634 verifiedEvent.metaState += 1;
5635 ASSERT_NE(initialHmac, mDispatcher->sign(verifiedEvent));
5636
5637 verifiedEvent.repeatCount += 1;
5638 ASSERT_NE(initialHmac, mDispatcher->sign(verifiedEvent));
5639}
5640
Vishnu Nair958da932020-08-21 17:12:37 -07005641TEST_F(InputDispatcherTest, SetFocusedWindow) {
5642 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
5643 sp<FakeWindowHandle> windowTop =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07005644 sp<FakeWindowHandle>::make(application, mDispatcher, "Top", ADISPLAY_ID_DEFAULT);
Vishnu Nair958da932020-08-21 17:12:37 -07005645 sp<FakeWindowHandle> windowSecond =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07005646 sp<FakeWindowHandle>::make(application, mDispatcher, "Second", ADISPLAY_ID_DEFAULT);
Vishnu Nair958da932020-08-21 17:12:37 -07005647 mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application);
5648
5649 // Top window is also focusable but is not granted focus.
5650 windowTop->setFocusable(true);
5651 windowSecond->setFocusable(true);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07005652 mDispatcher->onWindowInfosChanged(
5653 {{*windowTop->getInfo(), *windowSecond->getInfo()}, {}, 0, 0});
Vishnu Nair958da932020-08-21 17:12:37 -07005654 setFocusedWindow(windowSecond);
5655
5656 windowSecond->consumeFocusEvent(true);
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07005657 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectKeyDown(*mDispatcher))
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08005658 << "Inject key event should return InputEventInjectionResult::SUCCEEDED";
Vishnu Nair958da932020-08-21 17:12:37 -07005659
5660 // Focused window should receive event.
5661 windowSecond->consumeKeyDown(ADISPLAY_ID_NONE);
5662 windowTop->assertNoEvents();
5663}
5664
5665TEST_F(InputDispatcherTest, SetFocusedWindow_DropRequestInvalidChannel) {
5666 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
5667 sp<FakeWindowHandle> window =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07005668 sp<FakeWindowHandle>::make(application, mDispatcher, "TestWindow", ADISPLAY_ID_DEFAULT);
Vishnu Nair958da932020-08-21 17:12:37 -07005669 mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application);
5670
5671 window->setFocusable(true);
5672 // Release channel for window is no longer valid.
5673 window->releaseChannel();
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07005674 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Vishnu Nair958da932020-08-21 17:12:37 -07005675 setFocusedWindow(window);
5676
5677 // Test inject a key down, should timeout.
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07005678 ASSERT_NO_FATAL_FAILURE(assertInjectedKeyTimesOut(*mDispatcher));
Vishnu Nair958da932020-08-21 17:12:37 -07005679
5680 // window channel is invalid, so it should not receive any input event.
5681 window->assertNoEvents();
5682}
5683
5684TEST_F(InputDispatcherTest, SetFocusedWindow_DropRequestNoFocusableWindow) {
5685 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
5686 sp<FakeWindowHandle> window =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07005687 sp<FakeWindowHandle>::make(application, mDispatcher, "TestWindow", ADISPLAY_ID_DEFAULT);
Prabir Pradhan76bdecb2022-01-31 11:14:15 -08005688 window->setFocusable(false);
Vishnu Nair958da932020-08-21 17:12:37 -07005689 mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application);
5690
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07005691 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Vishnu Nair958da932020-08-21 17:12:37 -07005692 setFocusedWindow(window);
5693
5694 // Test inject a key down, should timeout.
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07005695 ASSERT_NO_FATAL_FAILURE(assertInjectedKeyTimesOut(*mDispatcher));
Vishnu Nair958da932020-08-21 17:12:37 -07005696
Prabir Pradhan76bdecb2022-01-31 11:14:15 -08005697 // window is not focusable, so it should not receive any input event.
Vishnu Nair958da932020-08-21 17:12:37 -07005698 window->assertNoEvents();
5699}
5700
5701TEST_F(InputDispatcherTest, SetFocusedWindow_CheckFocusedToken) {
5702 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
5703 sp<FakeWindowHandle> windowTop =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07005704 sp<FakeWindowHandle>::make(application, mDispatcher, "Top", ADISPLAY_ID_DEFAULT);
Vishnu Nair958da932020-08-21 17:12:37 -07005705 sp<FakeWindowHandle> windowSecond =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07005706 sp<FakeWindowHandle>::make(application, mDispatcher, "Second", ADISPLAY_ID_DEFAULT);
Vishnu Nair958da932020-08-21 17:12:37 -07005707 mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application);
5708
5709 windowTop->setFocusable(true);
5710 windowSecond->setFocusable(true);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07005711 mDispatcher->onWindowInfosChanged(
5712 {{*windowTop->getInfo(), *windowSecond->getInfo()}, {}, 0, 0});
Vishnu Nair958da932020-08-21 17:12:37 -07005713 setFocusedWindow(windowTop);
5714 windowTop->consumeFocusEvent(true);
5715
Chavi Weingarten847e8512023-03-29 00:26:09 +00005716 windowTop->editInfo()->focusTransferTarget = windowSecond->getToken();
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07005717 mDispatcher->onWindowInfosChanged(
5718 {{*windowTop->getInfo(), *windowSecond->getInfo()}, {}, 0, 0});
Vishnu Nair958da932020-08-21 17:12:37 -07005719 windowSecond->consumeFocusEvent(true);
5720 windowTop->consumeFocusEvent(false);
5721
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07005722 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectKeyDown(*mDispatcher))
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08005723 << "Inject key event should return InputEventInjectionResult::SUCCEEDED";
Vishnu Nair958da932020-08-21 17:12:37 -07005724
5725 // Focused window should receive event.
5726 windowSecond->consumeKeyDown(ADISPLAY_ID_NONE);
5727}
5728
Chavi Weingarten847e8512023-03-29 00:26:09 +00005729TEST_F(InputDispatcherTest, SetFocusedWindow_TransferFocusTokenNotFocusable) {
Vishnu Nair958da932020-08-21 17:12:37 -07005730 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
5731 sp<FakeWindowHandle> windowTop =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07005732 sp<FakeWindowHandle>::make(application, mDispatcher, "Top", ADISPLAY_ID_DEFAULT);
Vishnu Nair958da932020-08-21 17:12:37 -07005733 sp<FakeWindowHandle> windowSecond =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07005734 sp<FakeWindowHandle>::make(application, mDispatcher, "Second", ADISPLAY_ID_DEFAULT);
Vishnu Nair958da932020-08-21 17:12:37 -07005735 mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application);
5736
5737 windowTop->setFocusable(true);
Chavi Weingarten847e8512023-03-29 00:26:09 +00005738 windowSecond->setFocusable(false);
5739 windowTop->editInfo()->focusTransferTarget = windowSecond->getToken();
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07005740 mDispatcher->onWindowInfosChanged(
5741 {{*windowTop->getInfo(), *windowSecond->getInfo()}, {}, 0, 0});
Chavi Weingarten847e8512023-03-29 00:26:09 +00005742 setFocusedWindow(windowTop);
5743 windowTop->consumeFocusEvent(true);
Vishnu Nair958da932020-08-21 17:12:37 -07005744
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07005745 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectKeyDown(*mDispatcher))
Chavi Weingarten847e8512023-03-29 00:26:09 +00005746 << "Inject key event should return InputEventInjectionResult::SUCCEEDED";
Vishnu Nair958da932020-08-21 17:12:37 -07005747
5748 // Event should be dropped.
Chavi Weingarten847e8512023-03-29 00:26:09 +00005749 windowTop->consumeKeyDown(ADISPLAY_ID_NONE);
Vishnu Nair958da932020-08-21 17:12:37 -07005750 windowSecond->assertNoEvents();
5751}
5752
5753TEST_F(InputDispatcherTest, SetFocusedWindow_DeferInvisibleWindow) {
5754 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
5755 sp<FakeWindowHandle> window =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07005756 sp<FakeWindowHandle>::make(application, mDispatcher, "TestWindow", ADISPLAY_ID_DEFAULT);
Vishnu Nair958da932020-08-21 17:12:37 -07005757 sp<FakeWindowHandle> previousFocusedWindow =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07005758 sp<FakeWindowHandle>::make(application, mDispatcher, "previousFocusedWindow",
5759 ADISPLAY_ID_DEFAULT);
Vishnu Nair958da932020-08-21 17:12:37 -07005760 mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application);
5761
5762 window->setFocusable(true);
5763 previousFocusedWindow->setFocusable(true);
5764 window->setVisible(false);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07005765 mDispatcher->onWindowInfosChanged(
5766 {{*window->getInfo(), *previousFocusedWindow->getInfo()}, {}, 0, 0});
Vishnu Nair958da932020-08-21 17:12:37 -07005767 setFocusedWindow(previousFocusedWindow);
5768 previousFocusedWindow->consumeFocusEvent(true);
5769
5770 // Requesting focus on invisible window takes focus from currently focused window.
5771 setFocusedWindow(window);
5772 previousFocusedWindow->consumeFocusEvent(false);
5773
5774 // Injected key goes to pending queue.
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08005775 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07005776 injectKey(*mDispatcher, AKEY_EVENT_ACTION_DOWN, /*repeatCount=*/0,
5777 ADISPLAY_ID_DEFAULT, InputEventInjectionSync::NONE));
Vishnu Nair958da932020-08-21 17:12:37 -07005778
5779 // Window does not get focus event or key down.
5780 window->assertNoEvents();
5781
5782 // Window becomes visible.
5783 window->setVisible(true);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07005784 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Vishnu Nair958da932020-08-21 17:12:37 -07005785
5786 // Window receives focus event.
5787 window->consumeFocusEvent(true);
5788 // Focused window receives key down.
5789 window->consumeKeyDown(ADISPLAY_ID_DEFAULT);
5790}
5791
Vishnu Nair599f1412021-06-21 10:39:58 -07005792TEST_F(InputDispatcherTest, DisplayRemoved) {
5793 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
5794 sp<FakeWindowHandle> window =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07005795 sp<FakeWindowHandle>::make(application, mDispatcher, "window", ADISPLAY_ID_DEFAULT);
Vishnu Nair599f1412021-06-21 10:39:58 -07005796 mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application);
5797
5798 // window is granted focus.
5799 window->setFocusable(true);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07005800 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Vishnu Nair599f1412021-06-21 10:39:58 -07005801 setFocusedWindow(window);
5802 window->consumeFocusEvent(true);
5803
5804 // When a display is removed window loses focus.
5805 mDispatcher->displayRemoved(ADISPLAY_ID_DEFAULT);
5806 window->consumeFocusEvent(false);
5807}
5808
Siarhei Vishniakou870ecec2020-12-09 08:07:46 -10005809/**
5810 * Launch two windows, with different owners. One window (slipperyExitWindow) has Flag::SLIPPERY,
5811 * and overlaps the other window, slipperyEnterWindow. The window 'slipperyExitWindow' is on top
5812 * of the 'slipperyEnterWindow'.
5813 *
5814 * Inject touch down into the top window. Upon receipt of the DOWN event, move the window in such
5815 * a way so that the touched location is no longer covered by the top window.
5816 *
5817 * Next, inject a MOVE event. Because the top window already moved earlier, this event is now
5818 * positioned over the bottom (slipperyEnterWindow) only. And because the top window had
5819 * Flag::SLIPPERY, this will cause the top window to lose the touch event (it will receive
5820 * ACTION_CANCEL instead), and the bottom window will receive a newly generated gesture (starting
5821 * with ACTION_DOWN).
5822 * Thus, the touch has been transferred from the top window into the bottom window, because the top
5823 * window moved itself away from the touched location and had Flag::SLIPPERY.
5824 *
5825 * Even though the top window moved away from the touched location, it is still obscuring the bottom
5826 * window. It's just not obscuring it at the touched location. That means, FLAG_WINDOW_IS_PARTIALLY_
5827 * OBSCURED should be set for the MotionEvent that reaches the bottom window.
5828 *
5829 * In this test, we ensure that the event received by the bottom window has
5830 * FLAG_WINDOW_IS_PARTIALLY_OBSCURED.
5831 */
5832TEST_F(InputDispatcherTest, SlipperyWindow_SetsFlagPartiallyObscured) {
Prabir Pradhanaeebeb42023-06-13 19:53:03 +00005833 constexpr gui::Pid SLIPPERY_PID{WINDOW_PID.val() + 1};
Prabir Pradhan8a5c41d2023-06-08 19:13:46 +00005834 constexpr gui::Uid SLIPPERY_UID{WINDOW_UID.val() + 1};
Siarhei Vishniakou870ecec2020-12-09 08:07:46 -10005835
5836 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
5837 mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application);
5838
5839 sp<FakeWindowHandle> slipperyExitWindow =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07005840 sp<FakeWindowHandle>::make(application, mDispatcher, "Top", ADISPLAY_ID_DEFAULT);
Prabir Pradhan4d5c52f2022-01-31 08:52:10 -08005841 slipperyExitWindow->setSlippery(true);
Siarhei Vishniakou870ecec2020-12-09 08:07:46 -10005842 // Make sure this one overlaps the bottom window
5843 slipperyExitWindow->setFrame(Rect(25, 25, 75, 75));
5844 // Change the owner uid/pid of the window so that it is considered to be occluding the bottom
5845 // one. Windows with the same owner are not considered to be occluding each other.
5846 slipperyExitWindow->setOwnerInfo(SLIPPERY_PID, SLIPPERY_UID);
5847
5848 sp<FakeWindowHandle> slipperyEnterWindow =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07005849 sp<FakeWindowHandle>::make(application, mDispatcher, "Second", ADISPLAY_ID_DEFAULT);
Siarhei Vishniakou870ecec2020-12-09 08:07:46 -10005850 slipperyExitWindow->setFrame(Rect(0, 0, 100, 100));
5851
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07005852 mDispatcher->onWindowInfosChanged(
5853 {{*slipperyExitWindow->getInfo(), *slipperyEnterWindow->getInfo()}, {}, 0, 0});
Siarhei Vishniakou870ecec2020-12-09 08:07:46 -10005854
5855 // Use notifyMotion instead of injecting to avoid dealing with injection permissions
Prabir Pradhan678438e2023-04-13 19:32:51 +00005856 mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_DOWN,
5857 AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
5858 {{50, 50}}));
Siarhei Vishniakou870ecec2020-12-09 08:07:46 -10005859 slipperyExitWindow->consumeMotionDown();
5860 slipperyExitWindow->setFrame(Rect(70, 70, 100, 100));
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07005861 mDispatcher->onWindowInfosChanged(
5862 {{*slipperyExitWindow->getInfo(), *slipperyEnterWindow->getInfo()}, {}, 0, 0});
Siarhei Vishniakou870ecec2020-12-09 08:07:46 -10005863
Prabir Pradhan678438e2023-04-13 19:32:51 +00005864 mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_MOVE,
5865 AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
5866 {{51, 51}}));
Siarhei Vishniakou870ecec2020-12-09 08:07:46 -10005867
5868 slipperyExitWindow->consumeMotionCancel();
5869
5870 slipperyEnterWindow->consumeMotionDown(ADISPLAY_ID_DEFAULT,
5871 AMOTION_EVENT_FLAG_WINDOW_IS_PARTIALLY_OBSCURED);
5872}
5873
Siarhei Vishniakouafa08cc2023-05-08 22:35:50 -07005874/**
5875 * Two windows, one on the left and another on the right. The left window is slippery. The right
5876 * window isn't eligible to receive touch because it specifies InputConfig::DROP_INPUT. When the
5877 * touch moves from the left window into the right window, the gesture should continue to go to the
5878 * left window. Touch shouldn't slip because the right window can't receive touches. This test
5879 * reproduces a crash.
5880 */
5881TEST_F(InputDispatcherTest, TouchSlippingIntoWindowThatDropsTouches) {
5882 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
5883
5884 sp<FakeWindowHandle> leftSlipperyWindow =
5885 sp<FakeWindowHandle>::make(application, mDispatcher, "Left", ADISPLAY_ID_DEFAULT);
5886 leftSlipperyWindow->setSlippery(true);
5887 leftSlipperyWindow->setFrame(Rect(0, 0, 100, 100));
5888
5889 sp<FakeWindowHandle> rightDropTouchesWindow =
5890 sp<FakeWindowHandle>::make(application, mDispatcher, "Right", ADISPLAY_ID_DEFAULT);
5891 rightDropTouchesWindow->setFrame(Rect(100, 0, 200, 100));
5892 rightDropTouchesWindow->setDropInput(true);
5893
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07005894 mDispatcher->onWindowInfosChanged(
5895 {{*leftSlipperyWindow->getInfo(), *rightDropTouchesWindow->getInfo()}, {}, 0, 0});
Siarhei Vishniakouafa08cc2023-05-08 22:35:50 -07005896
5897 // Start touch in the left window
5898 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
5899 .pointer(PointerBuilder(0, ToolType::FINGER).x(50).y(50))
5900 .build());
5901 leftSlipperyWindow->consumeMotionDown();
5902
5903 // And move it into the right window
5904 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN)
5905 .pointer(PointerBuilder(0, ToolType::FINGER).x(150).y(50))
5906 .build());
5907
5908 // Since the right window isn't eligible to receive input, touch does not slip.
5909 // The left window continues to receive the gesture.
5910 leftSlipperyWindow->consumeMotionEvent(WithMotionAction(ACTION_MOVE));
5911 rightDropTouchesWindow->assertNoEvents();
5912}
5913
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -07005914/**
5915 * A single window is on screen first. Touch is injected into that window. Next, a second window
5916 * appears. Since the first window is slippery, touch will move from the first window to the second.
5917 */
5918TEST_F(InputDispatcherTest, InjectedTouchSlips) {
5919 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
5920 sp<FakeWindowHandle> originalWindow =
5921 sp<FakeWindowHandle>::make(application, mDispatcher, "Original", ADISPLAY_ID_DEFAULT);
5922 originalWindow->setFrame(Rect(0, 0, 200, 200));
5923 originalWindow->setSlippery(true);
5924
5925 sp<FakeWindowHandle> appearingWindow =
5926 sp<FakeWindowHandle>::make(application, mDispatcher, "Appearing", ADISPLAY_ID_DEFAULT);
5927 appearingWindow->setFrame(Rect(0, 0, 200, 200));
5928
5929 mDispatcher->onWindowInfosChanged({{*originalWindow->getInfo()}, {}, 0, 0});
5930
5931 // Touch down on the original window
5932 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
5933 injectMotionEvent(*mDispatcher,
5934 MotionEventBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
5935 .pointer(PointerBuilder(1, ToolType::FINGER).x(100).y(100))
5936 .build()));
5937 originalWindow->consumeMotionEvent(WithMotionAction(ACTION_DOWN));
5938
5939 // Now, a new window appears. This could be, for example, a notification shade that appears
5940 // after user starts to drag down on the launcher window.
5941 mDispatcher->onWindowInfosChanged(
5942 {{*appearingWindow->getInfo(), *originalWindow->getInfo()}, {}, 0, 0});
5943 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
5944 injectMotionEvent(*mDispatcher,
5945 MotionEventBuilder(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN)
5946 .pointer(PointerBuilder(1, ToolType::FINGER).x(110).y(110))
5947 .build()));
5948 originalWindow->consumeMotionEvent(WithMotionAction(ACTION_CANCEL));
5949 appearingWindow->consumeMotionEvent(WithMotionAction(ACTION_DOWN));
5950 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
5951 injectMotionEvent(*mDispatcher,
5952 MotionEventBuilder(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN)
5953 .pointer(PointerBuilder(1, ToolType::FINGER).x(120).y(120))
5954 .build()));
5955 appearingWindow->consumeMotionEvent(WithMotionAction(ACTION_MOVE));
5956
5957 originalWindow->assertNoEvents();
5958 appearingWindow->assertNoEvents();
5959}
5960
Prabir Pradhan8ede1d12023-05-08 19:37:44 +00005961TEST_F(InputDispatcherTest, NotifiesDeviceInteractionsWithMotions) {
Prabir Pradhan8a5c41d2023-06-08 19:13:46 +00005962 using Uid = gui::Uid;
Prabir Pradhan8ede1d12023-05-08 19:37:44 +00005963 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
5964
5965 sp<FakeWindowHandle> leftWindow =
5966 sp<FakeWindowHandle>::make(application, mDispatcher, "Left", ADISPLAY_ID_DEFAULT);
5967 leftWindow->setFrame(Rect(0, 0, 100, 100));
Prabir Pradhanaeebeb42023-06-13 19:53:03 +00005968 leftWindow->setOwnerInfo(gui::Pid{1}, Uid{101});
Prabir Pradhan8ede1d12023-05-08 19:37:44 +00005969
5970 sp<FakeWindowHandle> rightSpy =
5971 sp<FakeWindowHandle>::make(application, mDispatcher, "Right spy", ADISPLAY_ID_DEFAULT);
5972 rightSpy->setFrame(Rect(100, 0, 200, 100));
Prabir Pradhanaeebeb42023-06-13 19:53:03 +00005973 rightSpy->setOwnerInfo(gui::Pid{2}, Uid{102});
Prabir Pradhan8ede1d12023-05-08 19:37:44 +00005974 rightSpy->setSpy(true);
5975 rightSpy->setTrustedOverlay(true);
5976
5977 sp<FakeWindowHandle> rightWindow =
5978 sp<FakeWindowHandle>::make(application, mDispatcher, "Right", ADISPLAY_ID_DEFAULT);
5979 rightWindow->setFrame(Rect(100, 0, 200, 100));
Prabir Pradhanaeebeb42023-06-13 19:53:03 +00005980 rightWindow->setOwnerInfo(gui::Pid{3}, Uid{103});
Prabir Pradhan8ede1d12023-05-08 19:37:44 +00005981
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07005982 mDispatcher->onWindowInfosChanged(
5983 {{*rightSpy->getInfo(), *rightWindow->getInfo(), *leftWindow->getInfo()}, {}, 0, 0});
Prabir Pradhan8ede1d12023-05-08 19:37:44 +00005984
5985 // Touch in the left window
5986 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
5987 .pointer(PointerBuilder(0, ToolType::FINGER).x(50).y(50))
5988 .build());
5989 ASSERT_NO_FATAL_FAILURE(leftWindow->consumeMotionDown());
5990 mDispatcher->waitForIdle();
Prabir Pradhan8a5c41d2023-06-08 19:13:46 +00005991 ASSERT_NO_FATAL_FAILURE(
5992 mFakePolicy->assertNotifyDeviceInteractionWasCalled(DEVICE_ID, {Uid{101}}));
Prabir Pradhan8ede1d12023-05-08 19:37:44 +00005993
5994 // Touch another finger over the right windows
5995 mDispatcher->notifyMotion(MotionArgsBuilder(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
5996 .pointer(PointerBuilder(0, ToolType::FINGER).x(50).y(50))
5997 .pointer(PointerBuilder(1, ToolType::FINGER).x(150).y(50))
5998 .build());
5999 ASSERT_NO_FATAL_FAILURE(rightSpy->consumeMotionDown());
6000 ASSERT_NO_FATAL_FAILURE(rightWindow->consumeMotionDown());
6001 ASSERT_NO_FATAL_FAILURE(leftWindow->consumeMotionMove());
6002 mDispatcher->waitForIdle();
6003 ASSERT_NO_FATAL_FAILURE(
Prabir Pradhan8a5c41d2023-06-08 19:13:46 +00006004 mFakePolicy->assertNotifyDeviceInteractionWasCalled(DEVICE_ID,
6005 {Uid{101}, Uid{102}, Uid{103}}));
Prabir Pradhan8ede1d12023-05-08 19:37:44 +00006006
6007 // Release finger over left window. The UP actions are not treated as device interaction.
6008 // The windows that did not receive the UP pointer will receive MOVE events, but since this
6009 // is part of the UP action, we do not treat this as device interaction.
6010 mDispatcher->notifyMotion(MotionArgsBuilder(POINTER_0_UP, AINPUT_SOURCE_TOUCHSCREEN)
6011 .pointer(PointerBuilder(0, ToolType::FINGER).x(50).y(50))
6012 .pointer(PointerBuilder(1, ToolType::FINGER).x(150).y(50))
6013 .build());
6014 ASSERT_NO_FATAL_FAILURE(leftWindow->consumeMotionUp());
6015 ASSERT_NO_FATAL_FAILURE(rightSpy->consumeMotionMove());
6016 ASSERT_NO_FATAL_FAILURE(rightWindow->consumeMotionMove());
6017 mDispatcher->waitForIdle();
6018 ASSERT_NO_FATAL_FAILURE(mFakePolicy->assertNotifyDeviceInteractionWasNotCalled());
6019
6020 // Move remaining finger
6021 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN)
6022 .pointer(PointerBuilder(1, ToolType::FINGER).x(150).y(50))
6023 .build());
6024 ASSERT_NO_FATAL_FAILURE(rightSpy->consumeMotionMove());
6025 ASSERT_NO_FATAL_FAILURE(rightWindow->consumeMotionMove());
6026 mDispatcher->waitForIdle();
6027 ASSERT_NO_FATAL_FAILURE(
Prabir Pradhan8a5c41d2023-06-08 19:13:46 +00006028 mFakePolicy->assertNotifyDeviceInteractionWasCalled(DEVICE_ID, {Uid{102}, Uid{103}}));
Prabir Pradhan8ede1d12023-05-08 19:37:44 +00006029
6030 // Release all fingers
6031 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN)
6032 .pointer(PointerBuilder(1, ToolType::FINGER).x(150).y(50))
6033 .build());
6034 ASSERT_NO_FATAL_FAILURE(rightSpy->consumeMotionUp());
6035 ASSERT_NO_FATAL_FAILURE(rightWindow->consumeMotionUp());
6036 mDispatcher->waitForIdle();
6037 ASSERT_NO_FATAL_FAILURE(mFakePolicy->assertNotifyDeviceInteractionWasNotCalled());
6038}
6039
6040TEST_F(InputDispatcherTest, NotifiesDeviceInteractionsWithKeys) {
6041 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
6042
6043 sp<FakeWindowHandle> window =
6044 sp<FakeWindowHandle>::make(application, mDispatcher, "Window", ADISPLAY_ID_DEFAULT);
6045 window->setFrame(Rect(0, 0, 100, 100));
Prabir Pradhanaeebeb42023-06-13 19:53:03 +00006046 window->setOwnerInfo(gui::Pid{1}, gui::Uid{101});
Prabir Pradhan8ede1d12023-05-08 19:37:44 +00006047
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07006048 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Prabir Pradhan8ede1d12023-05-08 19:37:44 +00006049 setFocusedWindow(window);
6050 ASSERT_NO_FATAL_FAILURE(window->consumeFocusEvent(true));
6051
6052 mDispatcher->notifyKey(KeyArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_KEYBOARD).build());
6053 ASSERT_NO_FATAL_FAILURE(window->consumeKeyDown(ADISPLAY_ID_DEFAULT));
6054 mDispatcher->waitForIdle();
Prabir Pradhan8a5c41d2023-06-08 19:13:46 +00006055 ASSERT_NO_FATAL_FAILURE(
6056 mFakePolicy->assertNotifyDeviceInteractionWasCalled(DEVICE_ID, {gui::Uid{101}}));
Prabir Pradhan8ede1d12023-05-08 19:37:44 +00006057
6058 // The UP actions are not treated as device interaction.
6059 mDispatcher->notifyKey(KeyArgsBuilder(ACTION_UP, AINPUT_SOURCE_KEYBOARD).build());
6060 ASSERT_NO_FATAL_FAILURE(window->consumeKeyUp(ADISPLAY_ID_DEFAULT));
6061 mDispatcher->waitForIdle();
6062 ASSERT_NO_FATAL_FAILURE(mFakePolicy->assertNotifyDeviceInteractionWasNotCalled());
6063}
6064
Prabir Pradhan5893d362023-11-17 04:30:40 +00006065TEST_F(InputDispatcherTest, HoverEnterExitSynthesisUsesNewEventId) {
6066 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
6067
6068 sp<FakeWindowHandle> left = sp<FakeWindowHandle>::make(application, mDispatcher, "Left Window",
6069 ADISPLAY_ID_DEFAULT);
6070 left->setFrame(Rect(0, 0, 100, 100));
6071 sp<FakeWindowHandle> right = sp<FakeWindowHandle>::make(application, mDispatcher,
6072 "Right Window", ADISPLAY_ID_DEFAULT);
6073 right->setFrame(Rect(100, 0, 200, 100));
6074 sp<FakeWindowHandle> spy =
6075 sp<FakeWindowHandle>::make(application, mDispatcher, "Spy Window", ADISPLAY_ID_DEFAULT);
6076 spy->setFrame(Rect(0, 0, 200, 100));
6077 spy->setTrustedOverlay(true);
6078 spy->setSpy(true);
6079
6080 mDispatcher->onWindowInfosChanged(
6081 {{*spy->getInfo(), *left->getInfo(), *right->getInfo()}, {}, 0, 0});
6082
6083 // Send hover move to the left window, and ensure hover enter is synthesized with a new eventId.
6084 NotifyMotionArgs notifyArgs = generateMotionArgs(ACTION_HOVER_MOVE, AINPUT_SOURCE_STYLUS,
6085 ADISPLAY_ID_DEFAULT, {PointF{50, 50}});
6086 mDispatcher->notifyMotion(notifyArgs);
6087
Siarhei Vishniakoud3061ab2023-12-18 20:41:08 -08006088 std::unique_ptr<MotionEvent> leftEnter = left->consumeMotionEvent(
Prabir Pradhan5893d362023-11-17 04:30:40 +00006089 AllOf(WithMotionAction(ACTION_HOVER_ENTER), Not(WithEventId(notifyArgs.id)),
6090 WithEventIdSource(IdGenerator::Source::INPUT_DISPATCHER)));
Siarhei Vishniakoud3061ab2023-12-18 20:41:08 -08006091 ASSERT_NE(nullptr, leftEnter);
Prabir Pradhan5893d362023-11-17 04:30:40 +00006092 spy->consumeMotionEvent(AllOf(WithMotionAction(ACTION_HOVER_ENTER),
6093 Not(WithEventId(notifyArgs.id)),
Siarhei Vishniakoud3061ab2023-12-18 20:41:08 -08006094 Not(WithEventId(leftEnter->getId())),
Prabir Pradhan5893d362023-11-17 04:30:40 +00006095 WithEventIdSource(IdGenerator::Source::INPUT_DISPATCHER)));
6096
6097 // Send move to the right window, and ensure hover exit and enter are synthesized with new ids.
6098 notifyArgs = generateMotionArgs(ACTION_HOVER_MOVE, AINPUT_SOURCE_STYLUS, ADISPLAY_ID_DEFAULT,
6099 {PointF{150, 50}});
6100 mDispatcher->notifyMotion(notifyArgs);
6101
Siarhei Vishniakoud3061ab2023-12-18 20:41:08 -08006102 std::unique_ptr<MotionEvent> leftExit = left->consumeMotionEvent(
Prabir Pradhan5893d362023-11-17 04:30:40 +00006103 AllOf(WithMotionAction(ACTION_HOVER_EXIT), Not(WithEventId(notifyArgs.id)),
6104 WithEventIdSource(IdGenerator::Source::INPUT_DISPATCHER)));
Siarhei Vishniakoud3061ab2023-12-18 20:41:08 -08006105 ASSERT_NE(nullptr, leftExit);
Prabir Pradhan5893d362023-11-17 04:30:40 +00006106 right->consumeMotionEvent(AllOf(WithMotionAction(ACTION_HOVER_ENTER),
6107 Not(WithEventId(notifyArgs.id)),
Siarhei Vishniakoud3061ab2023-12-18 20:41:08 -08006108 Not(WithEventId(leftExit->getId())),
Prabir Pradhan5893d362023-11-17 04:30:40 +00006109 WithEventIdSource(IdGenerator::Source::INPUT_DISPATCHER)));
6110
6111 spy->consumeMotionEvent(AllOf(WithMotionAction(ACTION_HOVER_MOVE), WithEventId(notifyArgs.id)));
6112}
6113
Prabir Pradhanb0dad3a2023-11-02 20:52:47 +00006114class InputDispatcherFallbackKeyTest : public InputDispatcherTest {
6115protected:
6116 std::shared_ptr<FakeApplicationHandle> mApp;
6117 sp<FakeWindowHandle> mWindow;
6118
6119 virtual void SetUp() override {
6120 InputDispatcherTest::SetUp();
6121
6122 mApp = std::make_shared<FakeApplicationHandle>();
6123
6124 mWindow = sp<FakeWindowHandle>::make(mApp, mDispatcher, "Window", ADISPLAY_ID_DEFAULT);
6125 mWindow->setFrame(Rect(0, 0, 100, 100));
6126
6127 mDispatcher->onWindowInfosChanged({{*mWindow->getInfo()}, {}, 0, 0});
6128 setFocusedWindow(mWindow);
6129 ASSERT_NO_FATAL_FAILURE(mWindow->consumeFocusEvent(/*hasFocus=*/true));
6130 }
6131
6132 void setFallback(int32_t keycode) {
6133 mFakePolicy->setUnhandledKeyHandler([keycode](const KeyEvent& event) {
6134 return KeyEventBuilder(event).keyCode(keycode).build();
6135 });
6136 }
6137
6138 void consumeKey(bool handled, const ::testing::Matcher<KeyEvent>& matcher) {
Siarhei Vishniakoud3061ab2023-12-18 20:41:08 -08006139 std::unique_ptr<KeyEvent> event = mWindow->consumeKey(handled);
6140 ASSERT_NE(nullptr, event);
6141 ASSERT_THAT(*event, matcher);
Prabir Pradhanb0dad3a2023-11-02 20:52:47 +00006142 }
6143};
6144
6145TEST_F(InputDispatcherFallbackKeyTest, PolicyNotNotifiedForHandledKey) {
6146 mDispatcher->notifyKey(
6147 KeyArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_KEYBOARD).keyCode(AKEYCODE_A).build());
6148 consumeKey(/*handled=*/true, AllOf(WithKeyAction(ACTION_DOWN), WithKeyCode(AKEYCODE_A)));
6149 ASSERT_NO_FATAL_FAILURE(mFakePolicy->assertUnhandledKeyNotReported());
6150}
6151
6152TEST_F(InputDispatcherFallbackKeyTest, PolicyNotifiedForUnhandledKey) {
6153 mDispatcher->notifyKey(
6154 KeyArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_KEYBOARD).keyCode(AKEYCODE_A).build());
6155 consumeKey(/*handled=*/false, AllOf(WithKeyAction(ACTION_DOWN), WithKeyCode(AKEYCODE_A)));
6156 ASSERT_NO_FATAL_FAILURE(mFakePolicy->assertUnhandledKeyReported(AKEYCODE_A));
6157}
6158
6159TEST_F(InputDispatcherFallbackKeyTest, NoFallbackRequestedByPolicy) {
6160 mDispatcher->notifyKey(
6161 KeyArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_KEYBOARD).keyCode(AKEYCODE_A).build());
6162
6163 // Do not handle this key event.
6164 consumeKey(/*handled=*/false,
6165 AllOf(WithKeyAction(ACTION_DOWN), WithKeyCode(AKEYCODE_A), WithFlags(0)));
6166 ASSERT_NO_FATAL_FAILURE(mFakePolicy->assertUnhandledKeyReported(AKEYCODE_A));
6167
6168 // Since the policy did not request any fallback to be generated, ensure there are no events.
6169 ASSERT_NO_FATAL_FAILURE(mFakePolicy->assertUnhandledKeyNotReported());
6170}
6171
6172TEST_F(InputDispatcherFallbackKeyTest, FallbackDispatchForUnhandledKey) {
6173 setFallback(AKEYCODE_B);
6174 mDispatcher->notifyKey(
6175 KeyArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_KEYBOARD).keyCode(AKEYCODE_A).build());
6176
6177 // Do not handle this key event.
6178 consumeKey(/*handled=*/false,
6179 AllOf(WithKeyAction(ACTION_DOWN), WithKeyCode(AKEYCODE_A), WithFlags(0)));
6180
6181 // Since the key was not handled, ensure the fallback event was dispatched instead.
6182 ASSERT_NO_FATAL_FAILURE(mFakePolicy->assertUnhandledKeyReported(AKEYCODE_A));
6183 consumeKey(/*handled=*/true,
6184 AllOf(WithKeyAction(ACTION_DOWN), WithKeyCode(AKEYCODE_B),
6185 WithFlags(AKEY_EVENT_FLAG_FALLBACK)));
6186
6187 // Release the original key, and ensure the fallback key is also released.
6188 mDispatcher->notifyKey(
6189 KeyArgsBuilder(ACTION_UP, AINPUT_SOURCE_KEYBOARD).keyCode(AKEYCODE_A).build());
6190 consumeKey(/*handled=*/false,
6191 AllOf(WithKeyAction(ACTION_UP), WithKeyCode(AKEYCODE_A), WithFlags(0)));
6192 ASSERT_NO_FATAL_FAILURE(mFakePolicy->assertUnhandledKeyReported(AKEYCODE_A));
6193 consumeKey(/*handled=*/true,
6194 AllOf(WithKeyAction(ACTION_UP), WithKeyCode(AKEYCODE_B),
6195 WithFlags(AKEY_EVENT_FLAG_FALLBACK)));
6196
6197 ASSERT_NO_FATAL_FAILURE(mFakePolicy->assertUnhandledKeyNotReported());
6198 mWindow->assertNoEvents();
6199}
6200
6201TEST_F(InputDispatcherFallbackKeyTest, AppHandlesPreviouslyUnhandledKey) {
6202 setFallback(AKEYCODE_B);
6203 mDispatcher->notifyKey(
6204 KeyArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_KEYBOARD).keyCode(AKEYCODE_A).build());
6205
6206 // Do not handle this key event, but handle the fallback.
6207 consumeKey(/*handled=*/false,
6208 AllOf(WithKeyAction(ACTION_DOWN), WithKeyCode(AKEYCODE_A), WithFlags(0)));
6209 ASSERT_NO_FATAL_FAILURE(mFakePolicy->assertUnhandledKeyReported(AKEYCODE_A));
6210 consumeKey(/*handled=*/true,
6211 AllOf(WithKeyAction(ACTION_DOWN), WithKeyCode(AKEYCODE_B),
6212 WithFlags(AKEY_EVENT_FLAG_FALLBACK)));
6213
6214 // Release the original key, and ensure the fallback key is also released.
6215 mDispatcher->notifyKey(
6216 KeyArgsBuilder(ACTION_UP, AINPUT_SOURCE_KEYBOARD).keyCode(AKEYCODE_A).build());
6217 // But this time, the app handles the original key.
6218 consumeKey(/*handled=*/true,
6219 AllOf(WithKeyAction(ACTION_UP), WithKeyCode(AKEYCODE_A), WithFlags(0)));
6220 ASSERT_NO_FATAL_FAILURE(mFakePolicy->assertUnhandledKeyReported(AKEYCODE_A));
6221 // Ensure the fallback key is canceled.
6222 consumeKey(/*handled=*/true,
6223 AllOf(WithKeyAction(ACTION_UP), WithKeyCode(AKEYCODE_B),
6224 WithFlags(AKEY_EVENT_FLAG_FALLBACK | AKEY_EVENT_FLAG_CANCELED)));
6225
6226 ASSERT_NO_FATAL_FAILURE(mFakePolicy->assertUnhandledKeyNotReported());
6227 mWindow->assertNoEvents();
6228}
6229
6230TEST_F(InputDispatcherFallbackKeyTest, AppDoesNotHandleFallback) {
6231 setFallback(AKEYCODE_B);
6232 mDispatcher->notifyKey(
6233 KeyArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_KEYBOARD).keyCode(AKEYCODE_A).build());
6234
6235 // Do not handle this key event.
6236 consumeKey(/*handled=*/false,
6237 AllOf(WithKeyAction(ACTION_DOWN), WithKeyCode(AKEYCODE_A), WithFlags(0)));
6238 ASSERT_NO_FATAL_FAILURE(mFakePolicy->assertUnhandledKeyReported(AKEYCODE_A));
6239 // App does not handle the fallback either, so ensure another fallback is not generated.
6240 setFallback(AKEYCODE_C);
6241 consumeKey(/*handled=*/false,
6242 AllOf(WithKeyAction(ACTION_DOWN), WithKeyCode(AKEYCODE_B),
6243 WithFlags(AKEY_EVENT_FLAG_FALLBACK)));
6244
6245 // Release the original key, and ensure the fallback key is also released.
6246 setFallback(AKEYCODE_B);
6247 mDispatcher->notifyKey(
6248 KeyArgsBuilder(ACTION_UP, AINPUT_SOURCE_KEYBOARD).keyCode(AKEYCODE_A).build());
6249 consumeKey(/*handled=*/false,
6250 AllOf(WithKeyAction(ACTION_UP), WithKeyCode(AKEYCODE_A), WithFlags(0)));
6251 ASSERT_NO_FATAL_FAILURE(mFakePolicy->assertUnhandledKeyReported(AKEYCODE_A));
6252 consumeKey(/*handled=*/false,
6253 AllOf(WithKeyAction(ACTION_UP), WithKeyCode(AKEYCODE_B),
6254 WithFlags(AKEY_EVENT_FLAG_FALLBACK)));
6255
6256 ASSERT_NO_FATAL_FAILURE(mFakePolicy->assertUnhandledKeyNotReported());
6257 mWindow->assertNoEvents();
6258}
6259
6260TEST_F(InputDispatcherFallbackKeyTest, InconsistentPolicyCancelsFallback) {
6261 setFallback(AKEYCODE_B);
6262 mDispatcher->notifyKey(
6263 KeyArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_KEYBOARD).keyCode(AKEYCODE_A).build());
6264
6265 // Do not handle this key event, so fallback is generated.
6266 consumeKey(/*handled=*/false,
6267 AllOf(WithKeyAction(ACTION_DOWN), WithKeyCode(AKEYCODE_A), WithFlags(0)));
6268 ASSERT_NO_FATAL_FAILURE(mFakePolicy->assertUnhandledKeyReported(AKEYCODE_A));
6269 consumeKey(/*handled=*/true,
6270 AllOf(WithKeyAction(ACTION_DOWN), WithKeyCode(AKEYCODE_B),
6271 WithFlags(AKEY_EVENT_FLAG_FALLBACK)));
6272
6273 // Release the original key, but assume the policy is misbehaving and it
6274 // generates an inconsistent fallback to the one from the DOWN event.
6275 setFallback(AKEYCODE_C);
6276 mDispatcher->notifyKey(
6277 KeyArgsBuilder(ACTION_UP, AINPUT_SOURCE_KEYBOARD).keyCode(AKEYCODE_A).build());
6278 consumeKey(/*handled=*/false,
6279 AllOf(WithKeyAction(ACTION_UP), WithKeyCode(AKEYCODE_A), WithFlags(0)));
6280 ASSERT_NO_FATAL_FAILURE(mFakePolicy->assertUnhandledKeyReported(AKEYCODE_A));
6281 // Ensure the fallback key reported before as DOWN is canceled due to the inconsistency.
6282 consumeKey(/*handled=*/true,
6283 AllOf(WithKeyAction(ACTION_UP), WithKeyCode(AKEYCODE_B),
6284 WithFlags(AKEY_EVENT_FLAG_FALLBACK | AKEY_EVENT_FLAG_CANCELED)));
6285
6286 ASSERT_NO_FATAL_FAILURE(mFakePolicy->assertUnhandledKeyNotReported());
6287 mWindow->assertNoEvents();
6288}
6289
6290TEST_F(InputDispatcherFallbackKeyTest, CanceledKeyCancelsFallback) {
6291 setFallback(AKEYCODE_B);
6292 mDispatcher->notifyKey(
6293 KeyArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_KEYBOARD).keyCode(AKEYCODE_A).build());
6294
6295 // Do not handle this key event, so fallback is generated.
6296 consumeKey(/*handled=*/false,
6297 AllOf(WithKeyAction(ACTION_DOWN), WithKeyCode(AKEYCODE_A), WithFlags(0)));
6298 ASSERT_NO_FATAL_FAILURE(mFakePolicy->assertUnhandledKeyReported(AKEYCODE_A));
6299 consumeKey(/*handled=*/true,
6300 AllOf(WithKeyAction(ACTION_DOWN), WithKeyCode(AKEYCODE_B),
6301 WithFlags(AKEY_EVENT_FLAG_FALLBACK)));
6302
6303 // The original key is canceled.
6304 mDispatcher->notifyKey(KeyArgsBuilder(ACTION_UP, AINPUT_SOURCE_KEYBOARD)
6305 .keyCode(AKEYCODE_A)
6306 .addFlag(AKEY_EVENT_FLAG_CANCELED)
6307 .build());
6308 consumeKey(/*handled=*/false,
6309 AllOf(WithKeyAction(ACTION_UP), WithKeyCode(AKEYCODE_A),
6310 WithFlags(AKEY_EVENT_FLAG_CANCELED)));
6311 ASSERT_NO_FATAL_FAILURE(mFakePolicy->assertUnhandledKeyReported(AKEYCODE_A));
6312 // Ensure the fallback key is also canceled due to the original key being canceled.
6313 consumeKey(/*handled=*/true,
6314 AllOf(WithKeyAction(ACTION_UP), WithKeyCode(AKEYCODE_B),
6315 WithFlags(AKEY_EVENT_FLAG_FALLBACK | AKEY_EVENT_FLAG_CANCELED)));
6316
6317 ASSERT_NO_FATAL_FAILURE(mFakePolicy->assertUnhandledKeyNotReported());
6318 mWindow->assertNoEvents();
6319}
6320
Prabir Pradhanfa2c69f2024-02-01 20:31:34 +00006321TEST_F(InputDispatcherFallbackKeyTest, InputChannelRemovedDuringPolicyCall) {
Prabir Pradhanb13da8f2024-01-09 23:10:13 +00006322 setFallback(AKEYCODE_B);
6323 mDispatcher->notifyKey(
6324 KeyArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_KEYBOARD).keyCode(AKEYCODE_A).build());
6325
6326 // Do not handle this key event.
6327 consumeKey(/*handled=*/false,
6328 AllOf(WithKeyAction(ACTION_DOWN), WithKeyCode(AKEYCODE_A), WithFlags(0)));
6329 ASSERT_NO_FATAL_FAILURE(mFakePolicy->assertUnhandledKeyReported(AKEYCODE_A));
6330 consumeKey(/*handled=*/true,
6331 AllOf(WithKeyAction(ACTION_DOWN), WithKeyCode(AKEYCODE_B),
6332 WithFlags(AKEY_EVENT_FLAG_FALLBACK)));
6333
6334 mFakePolicy->setUnhandledKeyHandler([&](const KeyEvent& event) {
6335 // When the unhandled key is reported to the policy next, remove the input channel.
6336 mDispatcher->removeInputChannel(mWindow->getToken());
6337 return KeyEventBuilder(event).keyCode(AKEYCODE_B).build();
6338 });
6339 // Release the original key, and let the app now handle the previously unhandled key.
6340 // This should result in the previously generated fallback key to be cancelled.
6341 // Since the policy was notified of the unhandled DOWN event earlier, it will also be notified
6342 // of the UP event for consistency. The Dispatcher calls into the policy from its own thread
6343 // without holding the lock, because it need to synchronously fetch the fallback key. While in
6344 // the policy call, we will now remove the input channel. Once the policy call returns, the
6345 // Dispatcher will no longer have a channel to send cancellation events to. Ensure this does
6346 // not cause any crashes.
6347 mDispatcher->notifyKey(
6348 KeyArgsBuilder(ACTION_UP, AINPUT_SOURCE_KEYBOARD).keyCode(AKEYCODE_A).build());
6349 consumeKey(/*handled=*/true,
6350 AllOf(WithKeyAction(ACTION_UP), WithKeyCode(AKEYCODE_A), WithFlags(0)));
6351 ASSERT_NO_FATAL_FAILURE(mFakePolicy->assertUnhandledKeyReported(AKEYCODE_A));
6352}
6353
Prabir Pradhanfa2c69f2024-02-01 20:31:34 +00006354TEST_F(InputDispatcherFallbackKeyTest, WindowRemovedDuringPolicyCall) {
6355 setFallback(AKEYCODE_B);
6356 mDispatcher->notifyKey(
6357 KeyArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_KEYBOARD).keyCode(AKEYCODE_A).build());
6358
6359 // Do not handle this key event.
6360 consumeKey(/*handled=*/false,
6361 AllOf(WithKeyAction(ACTION_DOWN), WithKeyCode(AKEYCODE_A), WithFlags(0)));
6362 ASSERT_NO_FATAL_FAILURE(mFakePolicy->assertUnhandledKeyReported(AKEYCODE_A));
6363 consumeKey(/*handled=*/true,
6364 AllOf(WithKeyAction(ACTION_DOWN), WithKeyCode(AKEYCODE_B),
6365 WithFlags(AKEY_EVENT_FLAG_FALLBACK)));
6366
6367 mFakePolicy->setUnhandledKeyHandler([&](const KeyEvent& event) {
6368 // When the unhandled key is reported to the policy next, remove the window.
6369 mDispatcher->onWindowInfosChanged({{}, {}, 0, 0});
6370 return KeyEventBuilder(event).keyCode(AKEYCODE_B).build();
6371 });
6372 // Release the original key, which the app will not handle. When this unhandled key is reported
6373 // to the policy, the window will be removed.
6374 mDispatcher->notifyKey(
6375 KeyArgsBuilder(ACTION_UP, AINPUT_SOURCE_KEYBOARD).keyCode(AKEYCODE_A).build());
6376 consumeKey(/*handled=*/false,
6377 AllOf(WithKeyAction(ACTION_UP), WithKeyCode(AKEYCODE_A), WithFlags(0)));
6378 ASSERT_NO_FATAL_FAILURE(mFakePolicy->assertUnhandledKeyReported(AKEYCODE_A));
6379
6380 // Since the window was removed, it loses focus, and the channel state will be reset.
6381 consumeKey(/*handled=*/true,
6382 AllOf(WithKeyAction(ACTION_UP), WithKeyCode(AKEYCODE_B),
6383 WithFlags(AKEY_EVENT_FLAG_FALLBACK | AKEY_EVENT_FLAG_CANCELED)));
6384 mWindow->consumeFocusEvent(false);
6385 mWindow->assertNoEvents();
6386}
6387
6388TEST_F(InputDispatcherFallbackKeyTest, WindowRemovedWhileAwaitingFinishedSignal) {
6389 setFallback(AKEYCODE_B);
6390 mDispatcher->notifyKey(
6391 KeyArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_KEYBOARD).keyCode(AKEYCODE_A).build());
6392
6393 // Do not handle this key event.
6394 consumeKey(/*handled=*/false,
6395 AllOf(WithKeyAction(ACTION_DOWN), WithKeyCode(AKEYCODE_A), WithFlags(0)));
6396 ASSERT_NO_FATAL_FAILURE(mFakePolicy->assertUnhandledKeyReported(AKEYCODE_A));
6397 const auto [seq, event] = mWindow->receiveEvent();
6398 ASSERT_TRUE(seq.has_value() && event != nullptr) << "Failed to receive fallback event";
6399 ASSERT_EQ(event->getType(), InputEventType::KEY);
6400 ASSERT_THAT(static_cast<const KeyEvent&>(*event),
6401 AllOf(WithKeyAction(ACTION_DOWN), WithKeyCode(AKEYCODE_B),
6402 WithFlags(AKEY_EVENT_FLAG_FALLBACK)));
6403
6404 // Remove the window now, which should generate a cancellations and make the window lose focus.
6405 mDispatcher->onWindowInfosChanged({{}, {}, 0, 0});
6406 consumeKey(/*handled=*/true,
6407 AllOf(WithKeyAction(ACTION_UP), WithKeyCode(AKEYCODE_A),
6408 WithFlags(AKEY_EVENT_FLAG_CANCELED)));
6409 consumeKey(/*handled=*/true,
6410 AllOf(WithKeyAction(ACTION_UP), WithKeyCode(AKEYCODE_B),
6411 WithFlags(AKEY_EVENT_FLAG_FALLBACK | AKEY_EVENT_FLAG_CANCELED)));
6412 mWindow->consumeFocusEvent(false);
6413
6414 // Finish the event by reporting it as handled.
6415 mWindow->finishEvent(*seq);
6416 mWindow->assertNoEvents();
6417}
6418
Garfield Tan1c7bc862020-01-28 13:24:04 -08006419class InputDispatcherKeyRepeatTest : public InputDispatcherTest {
6420protected:
Siarhei Vishniakoufa2a0492023-11-14 13:13:18 -08006421 static constexpr std::chrono::nanoseconds KEY_REPEAT_TIMEOUT = 40ms;
6422 static constexpr std::chrono::nanoseconds KEY_REPEAT_DELAY = 40ms;
Garfield Tan1c7bc862020-01-28 13:24:04 -08006423
Chris Yea209fde2020-07-22 13:54:51 -07006424 std::shared_ptr<FakeApplicationHandle> mApp;
Garfield Tan1c7bc862020-01-28 13:24:04 -08006425 sp<FakeWindowHandle> mWindow;
6426
6427 virtual void SetUp() override {
Prabir Pradhandae52792023-12-15 07:36:40 +00006428 InputDispatcherTest::SetUp();
Garfield Tan1c7bc862020-01-28 13:24:04 -08006429
Prabir Pradhandae52792023-12-15 07:36:40 +00006430 mDispatcher->setKeyRepeatConfiguration(KEY_REPEAT_TIMEOUT, KEY_REPEAT_DELAY);
Garfield Tan1c7bc862020-01-28 13:24:04 -08006431 setUpWindow();
6432 }
6433
6434 void setUpWindow() {
Chris Yea209fde2020-07-22 13:54:51 -07006435 mApp = std::make_shared<FakeApplicationHandle>();
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07006436 mWindow = sp<FakeWindowHandle>::make(mApp, mDispatcher, "Fake Window", ADISPLAY_ID_DEFAULT);
Garfield Tan1c7bc862020-01-28 13:24:04 -08006437
Vishnu Nair47074b82020-08-14 11:54:47 -07006438 mWindow->setFocusable(true);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07006439 mDispatcher->onWindowInfosChanged({{*mWindow->getInfo()}, {}, 0, 0});
Vishnu Nair958da932020-08-21 17:12:37 -07006440 setFocusedWindow(mWindow);
Garfield Tan1c7bc862020-01-28 13:24:04 -08006441 mWindow->consumeFocusEvent(true);
6442 }
6443
Chris Ye2ad95392020-09-01 13:44:44 -07006444 void sendAndConsumeKeyDown(int32_t deviceId) {
Garfield Tan1c7bc862020-01-28 13:24:04 -08006445 NotifyKeyArgs keyArgs = generateKeyArgs(AKEY_EVENT_ACTION_DOWN, ADISPLAY_ID_DEFAULT);
Chris Ye2ad95392020-09-01 13:44:44 -07006446 keyArgs.deviceId = deviceId;
Garfield Tan1c7bc862020-01-28 13:24:04 -08006447 keyArgs.policyFlags |= POLICY_FLAG_TRUSTED; // Otherwise it won't generate repeat event
Prabir Pradhan678438e2023-04-13 19:32:51 +00006448 mDispatcher->notifyKey(keyArgs);
Garfield Tan1c7bc862020-01-28 13:24:04 -08006449
6450 // Window should receive key down event.
6451 mWindow->consumeKeyDown(ADISPLAY_ID_DEFAULT);
6452 }
6453
6454 void expectKeyRepeatOnce(int32_t repeatCount) {
6455 SCOPED_TRACE(StringPrintf("Checking event with repeat count %" PRId32, repeatCount));
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07006456 mWindow->consumeKeyEvent(
6457 AllOf(WithKeyAction(AKEY_EVENT_ACTION_DOWN), WithRepeatCount(repeatCount)));
Garfield Tan1c7bc862020-01-28 13:24:04 -08006458 }
6459
Chris Ye2ad95392020-09-01 13:44:44 -07006460 void sendAndConsumeKeyUp(int32_t deviceId) {
Garfield Tan1c7bc862020-01-28 13:24:04 -08006461 NotifyKeyArgs keyArgs = generateKeyArgs(AKEY_EVENT_ACTION_UP, ADISPLAY_ID_DEFAULT);
Chris Ye2ad95392020-09-01 13:44:44 -07006462 keyArgs.deviceId = deviceId;
Garfield Tan1c7bc862020-01-28 13:24:04 -08006463 keyArgs.policyFlags |= POLICY_FLAG_TRUSTED; // Unless it won't generate repeat event
Prabir Pradhan678438e2023-04-13 19:32:51 +00006464 mDispatcher->notifyKey(keyArgs);
Garfield Tan1c7bc862020-01-28 13:24:04 -08006465
6466 // Window should receive key down event.
Prabir Pradhan7662a8d2023-12-15 01:58:14 +00006467 mWindow->consumeKeyUp(ADISPLAY_ID_DEFAULT,
Harry Cutts33476232023-01-30 19:57:29 +00006468 /*expectedFlags=*/0);
Garfield Tan1c7bc862020-01-28 13:24:04 -08006469 }
Hu Guofe3c8f12023-09-22 17:20:15 +08006470
6471 void injectKeyRepeat(int32_t repeatCount) {
6472 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
6473 injectKey(*mDispatcher, AKEY_EVENT_ACTION_DOWN, repeatCount, ADISPLAY_ID_DEFAULT))
6474 << "Inject key event should return InputEventInjectionResult::SUCCEEDED";
6475 }
Garfield Tan1c7bc862020-01-28 13:24:04 -08006476};
6477
6478TEST_F(InputDispatcherKeyRepeatTest, FocusedWindow_ReceivesKeyRepeat) {
Harry Cutts33476232023-01-30 19:57:29 +00006479 sendAndConsumeKeyDown(/*deviceId=*/1);
Chris Ye2ad95392020-09-01 13:44:44 -07006480 for (int32_t repeatCount = 1; repeatCount <= 10; ++repeatCount) {
6481 expectKeyRepeatOnce(repeatCount);
6482 }
6483}
6484
6485TEST_F(InputDispatcherKeyRepeatTest, FocusedWindow_ReceivesKeyRepeatFromTwoDevices) {
Harry Cutts33476232023-01-30 19:57:29 +00006486 sendAndConsumeKeyDown(/*deviceId=*/1);
Chris Ye2ad95392020-09-01 13:44:44 -07006487 for (int32_t repeatCount = 1; repeatCount <= 10; ++repeatCount) {
6488 expectKeyRepeatOnce(repeatCount);
6489 }
Harry Cutts33476232023-01-30 19:57:29 +00006490 sendAndConsumeKeyDown(/*deviceId=*/2);
Chris Ye2ad95392020-09-01 13:44:44 -07006491 /* repeatCount will start from 1 for deviceId 2 */
Garfield Tan1c7bc862020-01-28 13:24:04 -08006492 for (int32_t repeatCount = 1; repeatCount <= 10; ++repeatCount) {
6493 expectKeyRepeatOnce(repeatCount);
6494 }
6495}
6496
6497TEST_F(InputDispatcherKeyRepeatTest, FocusedWindow_StopsKeyRepeatAfterUp) {
Harry Cutts33476232023-01-30 19:57:29 +00006498 sendAndConsumeKeyDown(/*deviceId=*/1);
6499 expectKeyRepeatOnce(/*repeatCount=*/1);
6500 sendAndConsumeKeyUp(/*deviceId=*/1);
Chris Ye2ad95392020-09-01 13:44:44 -07006501 mWindow->assertNoEvents();
6502}
6503
6504TEST_F(InputDispatcherKeyRepeatTest, FocusedWindow_KeyRepeatAfterStaleDeviceKeyUp) {
Harry Cutts33476232023-01-30 19:57:29 +00006505 sendAndConsumeKeyDown(/*deviceId=*/1);
6506 expectKeyRepeatOnce(/*repeatCount=*/1);
6507 sendAndConsumeKeyDown(/*deviceId=*/2);
6508 expectKeyRepeatOnce(/*repeatCount=*/1);
Chris Ye2ad95392020-09-01 13:44:44 -07006509 // Stale key up from device 1.
Harry Cutts33476232023-01-30 19:57:29 +00006510 sendAndConsumeKeyUp(/*deviceId=*/1);
Chris Ye2ad95392020-09-01 13:44:44 -07006511 // Device 2 is still down, keep repeating
Harry Cutts33476232023-01-30 19:57:29 +00006512 expectKeyRepeatOnce(/*repeatCount=*/2);
6513 expectKeyRepeatOnce(/*repeatCount=*/3);
Chris Ye2ad95392020-09-01 13:44:44 -07006514 // Device 2 key up
Harry Cutts33476232023-01-30 19:57:29 +00006515 sendAndConsumeKeyUp(/*deviceId=*/2);
Chris Ye2ad95392020-09-01 13:44:44 -07006516 mWindow->assertNoEvents();
6517}
6518
6519TEST_F(InputDispatcherKeyRepeatTest, FocusedWindow_KeyRepeatStopsAfterRepeatingKeyUp) {
Harry Cutts33476232023-01-30 19:57:29 +00006520 sendAndConsumeKeyDown(/*deviceId=*/1);
6521 expectKeyRepeatOnce(/*repeatCount=*/1);
6522 sendAndConsumeKeyDown(/*deviceId=*/2);
6523 expectKeyRepeatOnce(/*repeatCount=*/1);
Chris Ye2ad95392020-09-01 13:44:44 -07006524 // Device 2 which holds the key repeating goes up, expect the repeating to stop.
Harry Cutts33476232023-01-30 19:57:29 +00006525 sendAndConsumeKeyUp(/*deviceId=*/2);
Chris Ye2ad95392020-09-01 13:44:44 -07006526 // Device 1 still holds key down, but the repeating was already stopped
Garfield Tan1c7bc862020-01-28 13:24:04 -08006527 mWindow->assertNoEvents();
6528}
6529
liushenxiang42232912021-05-21 20:24:09 +08006530TEST_F(InputDispatcherKeyRepeatTest, FocusedWindow_StopsKeyRepeatAfterDisableInputDevice) {
6531 sendAndConsumeKeyDown(DEVICE_ID);
Harry Cutts33476232023-01-30 19:57:29 +00006532 expectKeyRepeatOnce(/*repeatCount=*/1);
Prabir Pradhan678438e2023-04-13 19:32:51 +00006533 mDispatcher->notifyDeviceReset({/*id=*/10, /*eventTime=*/20, DEVICE_ID});
liushenxiang42232912021-05-21 20:24:09 +08006534 mWindow->consumeKeyUp(ADISPLAY_ID_DEFAULT,
6535 AKEY_EVENT_FLAG_CANCELED | AKEY_EVENT_FLAG_LONG_PRESS);
6536 mWindow->assertNoEvents();
6537}
6538
Garfield Tan1c7bc862020-01-28 13:24:04 -08006539TEST_F(InputDispatcherKeyRepeatTest, FocusedWindow_RepeatKeyEventsUseEventIdFromInputDispatcher) {
Michael Wrighte1cbbd62023-02-22 19:32:13 +00006540 GTEST_SKIP() << "Flaky test (b/270393106)";
Harry Cutts33476232023-01-30 19:57:29 +00006541 sendAndConsumeKeyDown(/*deviceId=*/1);
Garfield Tan1c7bc862020-01-28 13:24:04 -08006542 for (int32_t repeatCount = 1; repeatCount <= 10; ++repeatCount) {
Siarhei Vishniakoud3061ab2023-12-18 20:41:08 -08006543 std::unique_ptr<KeyEvent> repeatEvent = mWindow->consumeKey();
6544 ASSERT_NE(nullptr, repeatEvent);
Garfield Tan1c7bc862020-01-28 13:24:04 -08006545 EXPECT_EQ(IdGenerator::Source::INPUT_DISPATCHER,
Siarhei Vishniakoud3061ab2023-12-18 20:41:08 -08006546 IdGenerator::getSource(repeatEvent->getId()));
Garfield Tan1c7bc862020-01-28 13:24:04 -08006547 }
6548}
6549
6550TEST_F(InputDispatcherKeyRepeatTest, FocusedWindow_RepeatKeyEventsUseUniqueEventId) {
Michael Wrighte1cbbd62023-02-22 19:32:13 +00006551 GTEST_SKIP() << "Flaky test (b/270393106)";
Harry Cutts33476232023-01-30 19:57:29 +00006552 sendAndConsumeKeyDown(/*deviceId=*/1);
Garfield Tan1c7bc862020-01-28 13:24:04 -08006553
6554 std::unordered_set<int32_t> idSet;
6555 for (int32_t repeatCount = 1; repeatCount <= 10; ++repeatCount) {
Siarhei Vishniakoud3061ab2023-12-18 20:41:08 -08006556 std::unique_ptr<KeyEvent> repeatEvent = mWindow->consumeKey();
6557 ASSERT_NE(nullptr, repeatEvent);
6558 int32_t id = repeatEvent->getId();
Garfield Tan1c7bc862020-01-28 13:24:04 -08006559 EXPECT_EQ(idSet.end(), idSet.find(id));
6560 idSet.insert(id);
6561 }
6562}
6563
Hu Guofe3c8f12023-09-22 17:20:15 +08006564TEST_F(InputDispatcherKeyRepeatTest, FocusedWindow_CorrectRepeatCountWhenInjectKeyRepeat) {
6565 injectKeyRepeat(0);
6566 mWindow->consumeKeyDown(ADISPLAY_ID_DEFAULT);
6567 for (int32_t repeatCount = 1; repeatCount <= 2; ++repeatCount) {
6568 expectKeyRepeatOnce(repeatCount);
6569 }
6570 injectKeyRepeat(1);
6571 // Expect repeatCount to be 3 instead of 1
6572 expectKeyRepeatOnce(3);
6573}
6574
Arthur Hung2fbf37f2018-09-13 18:16:41 +08006575/* Test InputDispatcher for MultiDisplay */
6576class InputDispatcherFocusOnTwoDisplaysTest : public InputDispatcherTest {
6577public:
Prabir Pradhan3608aad2019-10-02 17:08:26 -07006578 virtual void SetUp() override {
Arthur Hung2fbf37f2018-09-13 18:16:41 +08006579 InputDispatcherTest::SetUp();
Arthur Hungb92218b2018-08-14 12:00:21 +08006580
Chris Yea209fde2020-07-22 13:54:51 -07006581 application1 = std::make_shared<FakeApplicationHandle>();
Siarhei Vishniakou870ecec2020-12-09 08:07:46 -10006582 windowInPrimary =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07006583 sp<FakeWindowHandle>::make(application1, mDispatcher, "D_1", ADISPLAY_ID_DEFAULT);
Siarhei Vishniakoub9b15352019-11-26 13:19:26 -08006584
Arthur Hung2fbf37f2018-09-13 18:16:41 +08006585 // Set focus window for primary display, but focused display would be second one.
6586 mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application1);
Vishnu Nair47074b82020-08-14 11:54:47 -07006587 windowInPrimary->setFocusable(true);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07006588 mDispatcher->onWindowInfosChanged({{*windowInPrimary->getInfo()}, {}, 0, 0});
6589
Vishnu Nair958da932020-08-21 17:12:37 -07006590 setFocusedWindow(windowInPrimary);
Siarhei Vishniakouf1035d42019-09-20 16:32:01 +01006591 windowInPrimary->consumeFocusEvent(true);
Arthur Hungb92218b2018-08-14 12:00:21 +08006592
Chris Yea209fde2020-07-22 13:54:51 -07006593 application2 = std::make_shared<FakeApplicationHandle>();
Siarhei Vishniakou870ecec2020-12-09 08:07:46 -10006594 windowInSecondary =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07006595 sp<FakeWindowHandle>::make(application2, mDispatcher, "D_2", SECOND_DISPLAY_ID);
Arthur Hung2fbf37f2018-09-13 18:16:41 +08006596 // Set focus to second display window.
Arthur Hung2fbf37f2018-09-13 18:16:41 +08006597 // Set focus display to second one.
6598 mDispatcher->setFocusedDisplay(SECOND_DISPLAY_ID);
6599 // Set focus window for second display.
6600 mDispatcher->setFocusedApplication(SECOND_DISPLAY_ID, application2);
Vishnu Nair47074b82020-08-14 11:54:47 -07006601 windowInSecondary->setFocusable(true);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07006602 mDispatcher->onWindowInfosChanged(
6603 {{*windowInPrimary->getInfo(), *windowInSecondary->getInfo()}, {}, 0, 0});
Vishnu Nair958da932020-08-21 17:12:37 -07006604 setFocusedWindow(windowInSecondary);
Siarhei Vishniakouf1035d42019-09-20 16:32:01 +01006605 windowInSecondary->consumeFocusEvent(true);
Arthur Hung2fbf37f2018-09-13 18:16:41 +08006606 }
6607
Prabir Pradhan3608aad2019-10-02 17:08:26 -07006608 virtual void TearDown() override {
Arthur Hung2fbf37f2018-09-13 18:16:41 +08006609 InputDispatcherTest::TearDown();
6610
Chris Yea209fde2020-07-22 13:54:51 -07006611 application1.reset();
Arthur Hung2fbf37f2018-09-13 18:16:41 +08006612 windowInPrimary.clear();
Chris Yea209fde2020-07-22 13:54:51 -07006613 application2.reset();
Arthur Hung2fbf37f2018-09-13 18:16:41 +08006614 windowInSecondary.clear();
6615 }
6616
6617protected:
Chris Yea209fde2020-07-22 13:54:51 -07006618 std::shared_ptr<FakeApplicationHandle> application1;
Arthur Hung2fbf37f2018-09-13 18:16:41 +08006619 sp<FakeWindowHandle> windowInPrimary;
Chris Yea209fde2020-07-22 13:54:51 -07006620 std::shared_ptr<FakeApplicationHandle> application2;
Arthur Hung2fbf37f2018-09-13 18:16:41 +08006621 sp<FakeWindowHandle> windowInSecondary;
6622};
6623
6624TEST_F(InputDispatcherFocusOnTwoDisplaysTest, SetInputWindow_MultiDisplayTouch) {
6625 // Test touch down on primary display.
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08006626 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07006627 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT))
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08006628 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
Siarhei Vishniakouc5ca85c2019-11-15 17:20:00 -08006629 windowInPrimary->consumeMotionDown(ADISPLAY_ID_DEFAULT);
Arthur Hungb92218b2018-08-14 12:00:21 +08006630 windowInSecondary->assertNoEvents();
6631
Arthur Hung2fbf37f2018-09-13 18:16:41 +08006632 // Test touch down on second display.
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08006633 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07006634 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, SECOND_DISPLAY_ID))
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08006635 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
Arthur Hungb92218b2018-08-14 12:00:21 +08006636 windowInPrimary->assertNoEvents();
Siarhei Vishniakouc5ca85c2019-11-15 17:20:00 -08006637 windowInSecondary->consumeMotionDown(SECOND_DISPLAY_ID);
Arthur Hungb92218b2018-08-14 12:00:21 +08006638}
6639
Arthur Hung2fbf37f2018-09-13 18:16:41 +08006640TEST_F(InputDispatcherFocusOnTwoDisplaysTest, SetInputWindow_MultiDisplayFocus) {
Tiger Huang721e26f2018-07-24 22:26:19 +08006641 // Test inject a key down with display id specified.
Prabir Pradhan93f342c2021-03-11 15:05:30 -08006642 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07006643 injectKeyDownNoRepeat(*mDispatcher, ADISPLAY_ID_DEFAULT))
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08006644 << "Inject key event should return InputEventInjectionResult::SUCCEEDED";
Siarhei Vishniakouc5ca85c2019-11-15 17:20:00 -08006645 windowInPrimary->consumeKeyDown(ADISPLAY_ID_DEFAULT);
Tiger Huang721e26f2018-07-24 22:26:19 +08006646 windowInSecondary->assertNoEvents();
6647
6648 // Test inject a key down without display id specified.
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07006649 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectKeyDownNoRepeat(*mDispatcher))
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08006650 << "Inject key event should return InputEventInjectionResult::SUCCEEDED";
Arthur Hungb92218b2018-08-14 12:00:21 +08006651 windowInPrimary->assertNoEvents();
Siarhei Vishniakouc5ca85c2019-11-15 17:20:00 -08006652 windowInSecondary->consumeKeyDown(ADISPLAY_ID_NONE);
Arthur Hungb92218b2018-08-14 12:00:21 +08006653
Siarhei Vishniakoub9b15352019-11-26 13:19:26 -08006654 // Remove all windows in secondary display.
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07006655 mDispatcher->onWindowInfosChanged({{*windowInPrimary->getInfo()}, {}, 0, 0});
Arthur Hungb92218b2018-08-14 12:00:21 +08006656
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08006657 // Old focus should receive a cancel event.
Prabir Pradhan7662a8d2023-12-15 01:58:14 +00006658 windowInSecondary->consumeKeyUp(ADISPLAY_ID_NONE, AKEY_EVENT_FLAG_CANCELED);
Arthur Hungb92218b2018-08-14 12:00:21 +08006659
6660 // Test inject a key down, should timeout because of no target window.
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07006661 ASSERT_NO_FATAL_FAILURE(assertInjectedKeyTimesOut(*mDispatcher));
Arthur Hungb92218b2018-08-14 12:00:21 +08006662 windowInPrimary->assertNoEvents();
Siarhei Vishniakouf1035d42019-09-20 16:32:01 +01006663 windowInSecondary->consumeFocusEvent(false);
Arthur Hungb92218b2018-08-14 12:00:21 +08006664 windowInSecondary->assertNoEvents();
6665}
6666
Arthur Hung2fbf37f2018-09-13 18:16:41 +08006667// Test per-display input monitors for motion event.
6668TEST_F(InputDispatcherFocusOnTwoDisplaysTest, MonitorMotionEvent_MultiDisplay) {
chaviwd1c23182019-12-20 18:44:56 -08006669 FakeMonitorReceiver monitorInPrimary =
Prabir Pradhanfb549072023-10-05 19:17:36 +00006670 FakeMonitorReceiver(*mDispatcher, "M_1", ADISPLAY_ID_DEFAULT);
chaviwd1c23182019-12-20 18:44:56 -08006671 FakeMonitorReceiver monitorInSecondary =
Prabir Pradhanfb549072023-10-05 19:17:36 +00006672 FakeMonitorReceiver(*mDispatcher, "M_2", SECOND_DISPLAY_ID);
Arthur Hung2fbf37f2018-09-13 18:16:41 +08006673
6674 // Test touch down on primary display.
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08006675 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07006676 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT))
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08006677 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
Siarhei Vishniakouc5ca85c2019-11-15 17:20:00 -08006678 windowInPrimary->consumeMotionDown(ADISPLAY_ID_DEFAULT);
chaviwd1c23182019-12-20 18:44:56 -08006679 monitorInPrimary.consumeMotionDown(ADISPLAY_ID_DEFAULT);
Arthur Hung2fbf37f2018-09-13 18:16:41 +08006680 windowInSecondary->assertNoEvents();
chaviwd1c23182019-12-20 18:44:56 -08006681 monitorInSecondary.assertNoEvents();
Arthur Hung2fbf37f2018-09-13 18:16:41 +08006682
6683 // Test touch down on second display.
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08006684 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07006685 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, SECOND_DISPLAY_ID))
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08006686 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
Arthur Hung2fbf37f2018-09-13 18:16:41 +08006687 windowInPrimary->assertNoEvents();
chaviwd1c23182019-12-20 18:44:56 -08006688 monitorInPrimary.assertNoEvents();
Siarhei Vishniakouc5ca85c2019-11-15 17:20:00 -08006689 windowInSecondary->consumeMotionDown(SECOND_DISPLAY_ID);
chaviwd1c23182019-12-20 18:44:56 -08006690 monitorInSecondary.consumeMotionDown(SECOND_DISPLAY_ID);
Arthur Hung2fbf37f2018-09-13 18:16:41 +08006691
Siarhei Vishniakou92c8fd52023-01-29 14:57:43 -08006692 // Lift up the touch from the second display
6693 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07006694 injectMotionUp(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, SECOND_DISPLAY_ID))
Siarhei Vishniakou92c8fd52023-01-29 14:57:43 -08006695 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
6696 windowInSecondary->consumeMotionUp(SECOND_DISPLAY_ID);
6697 monitorInSecondary.consumeMotionUp(SECOND_DISPLAY_ID);
6698
Arthur Hung2fbf37f2018-09-13 18:16:41 +08006699 // Test inject a non-pointer motion event.
6700 // If specific a display, it will dispatch to the focused window of particular display,
6701 // or it will dispatch to the focused window of focused display.
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08006702 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07006703 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TRACKBALL, ADISPLAY_ID_NONE))
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08006704 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
Arthur Hung2fbf37f2018-09-13 18:16:41 +08006705 windowInPrimary->assertNoEvents();
chaviwd1c23182019-12-20 18:44:56 -08006706 monitorInPrimary.assertNoEvents();
Siarhei Vishniakouc5ca85c2019-11-15 17:20:00 -08006707 windowInSecondary->consumeMotionDown(ADISPLAY_ID_NONE);
chaviwd1c23182019-12-20 18:44:56 -08006708 monitorInSecondary.consumeMotionDown(ADISPLAY_ID_NONE);
Arthur Hung2fbf37f2018-09-13 18:16:41 +08006709}
6710
6711// Test per-display input monitors for key event.
6712TEST_F(InputDispatcherFocusOnTwoDisplaysTest, MonitorKeyEvent_MultiDisplay) {
Siarhei Vishniakou870ecec2020-12-09 08:07:46 -10006713 // Input monitor per display.
chaviwd1c23182019-12-20 18:44:56 -08006714 FakeMonitorReceiver monitorInPrimary =
Prabir Pradhanfb549072023-10-05 19:17:36 +00006715 FakeMonitorReceiver(*mDispatcher, "M_1", ADISPLAY_ID_DEFAULT);
chaviwd1c23182019-12-20 18:44:56 -08006716 FakeMonitorReceiver monitorInSecondary =
Prabir Pradhanfb549072023-10-05 19:17:36 +00006717 FakeMonitorReceiver(*mDispatcher, "M_2", SECOND_DISPLAY_ID);
Arthur Hung2fbf37f2018-09-13 18:16:41 +08006718
6719 // Test inject a key down.
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07006720 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectKeyDown(*mDispatcher))
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08006721 << "Inject key event should return InputEventInjectionResult::SUCCEEDED";
Arthur Hung2fbf37f2018-09-13 18:16:41 +08006722 windowInPrimary->assertNoEvents();
chaviwd1c23182019-12-20 18:44:56 -08006723 monitorInPrimary.assertNoEvents();
Siarhei Vishniakouc5ca85c2019-11-15 17:20:00 -08006724 windowInSecondary->consumeKeyDown(ADISPLAY_ID_NONE);
chaviwd1c23182019-12-20 18:44:56 -08006725 monitorInSecondary.consumeKeyDown(ADISPLAY_ID_NONE);
Arthur Hung2fbf37f2018-09-13 18:16:41 +08006726}
6727
Vishnu Nair958da932020-08-21 17:12:37 -07006728TEST_F(InputDispatcherFocusOnTwoDisplaysTest, CanFocusWindowOnUnfocusedDisplay) {
6729 sp<FakeWindowHandle> secondWindowInPrimary =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07006730 sp<FakeWindowHandle>::make(application1, mDispatcher, "D_1_W2", ADISPLAY_ID_DEFAULT);
Vishnu Nair958da932020-08-21 17:12:37 -07006731 secondWindowInPrimary->setFocusable(true);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07006732 mDispatcher->onWindowInfosChanged(
6733 {{*windowInPrimary->getInfo(), *secondWindowInPrimary->getInfo(),
6734 *windowInSecondary->getInfo()},
6735 {},
6736 0,
6737 0});
Vishnu Nair958da932020-08-21 17:12:37 -07006738 setFocusedWindow(secondWindowInPrimary);
6739 windowInPrimary->consumeFocusEvent(false);
6740 secondWindowInPrimary->consumeFocusEvent(true);
6741
6742 // Test inject a key down.
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07006743 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
6744 injectKeyDown(*mDispatcher, ADISPLAY_ID_DEFAULT))
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08006745 << "Inject key event should return InputEventInjectionResult::SUCCEEDED";
Vishnu Nair958da932020-08-21 17:12:37 -07006746 windowInPrimary->assertNoEvents();
6747 windowInSecondary->assertNoEvents();
6748 secondWindowInPrimary->consumeKeyDown(ADISPLAY_ID_DEFAULT);
6749}
6750
Arthur Hungdfd528e2021-12-08 13:23:04 +00006751TEST_F(InputDispatcherFocusOnTwoDisplaysTest, CancelTouch_MultiDisplay) {
6752 FakeMonitorReceiver monitorInPrimary =
Prabir Pradhanfb549072023-10-05 19:17:36 +00006753 FakeMonitorReceiver(*mDispatcher, "M_1", ADISPLAY_ID_DEFAULT);
Arthur Hungdfd528e2021-12-08 13:23:04 +00006754 FakeMonitorReceiver monitorInSecondary =
Prabir Pradhanfb549072023-10-05 19:17:36 +00006755 FakeMonitorReceiver(*mDispatcher, "M_2", SECOND_DISPLAY_ID);
Arthur Hungdfd528e2021-12-08 13:23:04 +00006756
6757 // Test touch down on primary display.
6758 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07006759 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT))
Arthur Hungdfd528e2021-12-08 13:23:04 +00006760 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
6761 windowInPrimary->consumeMotionDown(ADISPLAY_ID_DEFAULT);
6762 monitorInPrimary.consumeMotionDown(ADISPLAY_ID_DEFAULT);
6763
6764 // Test touch down on second display.
6765 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07006766 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, SECOND_DISPLAY_ID))
Arthur Hungdfd528e2021-12-08 13:23:04 +00006767 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
6768 windowInSecondary->consumeMotionDown(SECOND_DISPLAY_ID);
6769 monitorInSecondary.consumeMotionDown(SECOND_DISPLAY_ID);
6770
6771 // Trigger cancel touch.
6772 mDispatcher->cancelCurrentTouch();
6773 windowInPrimary->consumeMotionCancel(ADISPLAY_ID_DEFAULT);
6774 monitorInPrimary.consumeMotionCancel(ADISPLAY_ID_DEFAULT);
6775 windowInSecondary->consumeMotionCancel(SECOND_DISPLAY_ID);
6776 monitorInSecondary.consumeMotionCancel(SECOND_DISPLAY_ID);
6777
6778 // Test inject a move motion event, no window/monitor should receive the event.
6779 ASSERT_EQ(InputEventInjectionResult::FAILED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07006780 injectMotionEvent(*mDispatcher, AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN,
Arthur Hungdfd528e2021-12-08 13:23:04 +00006781 ADISPLAY_ID_DEFAULT, {110, 200}))
6782 << "Inject motion event should return InputEventInjectionResult::FAILED";
6783 windowInPrimary->assertNoEvents();
6784 monitorInPrimary.assertNoEvents();
6785
6786 ASSERT_EQ(InputEventInjectionResult::FAILED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07006787 injectMotionEvent(*mDispatcher, AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN,
Arthur Hungdfd528e2021-12-08 13:23:04 +00006788 SECOND_DISPLAY_ID, {110, 200}))
6789 << "Inject motion event should return InputEventInjectionResult::FAILED";
6790 windowInSecondary->assertNoEvents();
6791 monitorInSecondary.assertNoEvents();
6792}
6793
Hu Guocb134f12023-12-23 13:42:44 +00006794/**
6795 * Send a key to the primary display and to the secondary display.
6796 * Then cause the key on the primary display to be canceled by sending in a stale key.
6797 * Ensure that the key on the primary display is canceled, and that the key on the secondary display
6798 * does not get canceled.
6799 */
6800TEST_F(InputDispatcherFocusOnTwoDisplaysTest, WhenDropKeyEvent_OnlyCancelCorrespondingKeyGesture) {
6801 // Send a key down on primary display
6802 mDispatcher->notifyKey(
6803 KeyArgsBuilder(AKEY_EVENT_ACTION_DOWN, AINPUT_SOURCE_KEYBOARD)
6804 .displayId(ADISPLAY_ID_DEFAULT)
6805 .policyFlags(DEFAULT_POLICY_FLAGS | POLICY_FLAG_DISABLE_KEY_REPEAT)
6806 .build());
6807 windowInPrimary->consumeKeyEvent(
6808 AllOf(WithKeyAction(AKEY_EVENT_ACTION_DOWN), WithDisplayId(ADISPLAY_ID_DEFAULT)));
6809 windowInSecondary->assertNoEvents();
6810
6811 // Send a key down on second display
6812 mDispatcher->notifyKey(
6813 KeyArgsBuilder(AKEY_EVENT_ACTION_DOWN, AINPUT_SOURCE_KEYBOARD)
6814 .displayId(SECOND_DISPLAY_ID)
6815 .policyFlags(DEFAULT_POLICY_FLAGS | POLICY_FLAG_DISABLE_KEY_REPEAT)
6816 .build());
6817 windowInSecondary->consumeKeyEvent(
6818 AllOf(WithKeyAction(AKEY_EVENT_ACTION_DOWN), WithDisplayId(SECOND_DISPLAY_ID)));
6819 windowInPrimary->assertNoEvents();
6820
6821 // Send a valid key up event on primary display that will be dropped because it is stale
6822 NotifyKeyArgs staleKeyUp =
6823 KeyArgsBuilder(AKEY_EVENT_ACTION_UP, AINPUT_SOURCE_KEYBOARD)
6824 .displayId(ADISPLAY_ID_DEFAULT)
6825 .policyFlags(DEFAULT_POLICY_FLAGS | POLICY_FLAG_DISABLE_KEY_REPEAT)
6826 .build();
6827 static constexpr std::chrono::duration STALE_EVENT_TIMEOUT = 10ms;
6828 mFakePolicy->setStaleEventTimeout(STALE_EVENT_TIMEOUT);
6829 std::this_thread::sleep_for(STALE_EVENT_TIMEOUT);
6830 mDispatcher->notifyKey(staleKeyUp);
6831
6832 // Only the key gesture corresponding to the dropped event should receive the cancel event.
6833 // Therefore, windowInPrimary should get the cancel event and windowInSecondary should not
6834 // receive any events.
6835 windowInPrimary->consumeKeyEvent(AllOf(WithKeyAction(AKEY_EVENT_ACTION_UP),
6836 WithDisplayId(ADISPLAY_ID_DEFAULT),
6837 WithFlags(AKEY_EVENT_FLAG_CANCELED)));
6838 windowInSecondary->assertNoEvents();
6839}
6840
6841/**
6842 * Similar to 'WhenDropKeyEvent_OnlyCancelCorrespondingKeyGesture' but for motion events.
6843 */
6844TEST_F(InputDispatcherFocusOnTwoDisplaysTest, WhenDropMotionEvent_OnlyCancelCorrespondingGesture) {
6845 // Send touch down on primary display.
6846 mDispatcher->notifyMotion(
6847 MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
6848 .pointer(PointerBuilder(/*id=*/0, ToolType::FINGER).x(100).y(200))
6849 .displayId(ADISPLAY_ID_DEFAULT)
6850 .build());
6851 windowInPrimary->consumeMotionEvent(
6852 AllOf(WithMotionAction(ACTION_DOWN), WithDisplayId(ADISPLAY_ID_DEFAULT)));
6853 windowInSecondary->assertNoEvents();
6854
6855 // Send touch down on second display.
6856 mDispatcher->notifyMotion(
6857 MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
6858 .pointer(PointerBuilder(/*id=*/0, ToolType::FINGER).x(100).y(200))
6859 .displayId(SECOND_DISPLAY_ID)
6860 .build());
6861 windowInPrimary->assertNoEvents();
6862 windowInSecondary->consumeMotionEvent(
6863 AllOf(WithMotionAction(ACTION_DOWN), WithDisplayId(SECOND_DISPLAY_ID)));
6864
6865 // inject a valid MotionEvent on primary display that will be stale when it arrives.
6866 NotifyMotionArgs staleMotionUp =
6867 MotionArgsBuilder(ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN)
6868 .displayId(ADISPLAY_ID_DEFAULT)
6869 .pointer(PointerBuilder(/*id=*/0, ToolType::FINGER).x(100).y(200))
6870 .build();
6871 static constexpr std::chrono::duration STALE_EVENT_TIMEOUT = 10ms;
6872 mFakePolicy->setStaleEventTimeout(STALE_EVENT_TIMEOUT);
6873 std::this_thread::sleep_for(STALE_EVENT_TIMEOUT);
6874 mDispatcher->notifyMotion(staleMotionUp);
6875
6876 // For stale motion events, we let the gesture to complete. This behaviour is different from key
6877 // events, where we would cancel the current keys instead.
6878 windowInPrimary->consumeMotionEvent(WithMotionAction(ACTION_UP));
6879 windowInSecondary->assertNoEvents();
6880}
6881
Jackal Guof9696682018-10-05 12:23:23 +08006882class InputFilterTest : public InputDispatcherTest {
6883protected:
Prabir Pradhan81420cc2021-09-06 10:28:50 -07006884 void testNotifyMotion(int32_t displayId, bool expectToBeFiltered,
6885 const ui::Transform& transform = ui::Transform()) {
Jackal Guof9696682018-10-05 12:23:23 +08006886 NotifyMotionArgs motionArgs;
6887
Siarhei Vishniakou870ecec2020-12-09 08:07:46 -10006888 motionArgs =
6889 generateMotionArgs(AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN, displayId);
Prabir Pradhan678438e2023-04-13 19:32:51 +00006890 mDispatcher->notifyMotion(motionArgs);
Siarhei Vishniakou870ecec2020-12-09 08:07:46 -10006891 motionArgs =
6892 generateMotionArgs(AMOTION_EVENT_ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN, displayId);
Prabir Pradhan678438e2023-04-13 19:32:51 +00006893 mDispatcher->notifyMotion(motionArgs);
Siarhei Vishniakou2bfa9052019-11-21 18:10:54 -08006894 ASSERT_TRUE(mDispatcher->waitForIdle());
Jackal Guof9696682018-10-05 12:23:23 +08006895 if (expectToBeFiltered) {
Siarhei Vishniakou3218fc02023-06-15 20:41:02 -07006896 const auto xy = transform.transform(motionArgs.pointerCoords[0].getXYValue());
Prabir Pradhan81420cc2021-09-06 10:28:50 -07006897 mFakePolicy->assertFilterInputEventWasCalled(motionArgs, xy);
Jackal Guof9696682018-10-05 12:23:23 +08006898 } else {
6899 mFakePolicy->assertFilterInputEventWasNotCalled();
6900 }
6901 }
6902
6903 void testNotifyKey(bool expectToBeFiltered) {
6904 NotifyKeyArgs keyArgs;
6905
6906 keyArgs = generateKeyArgs(AKEY_EVENT_ACTION_DOWN);
Prabir Pradhan678438e2023-04-13 19:32:51 +00006907 mDispatcher->notifyKey(keyArgs);
Jackal Guof9696682018-10-05 12:23:23 +08006908 keyArgs = generateKeyArgs(AKEY_EVENT_ACTION_UP);
Prabir Pradhan678438e2023-04-13 19:32:51 +00006909 mDispatcher->notifyKey(keyArgs);
Siarhei Vishniakou2bfa9052019-11-21 18:10:54 -08006910 ASSERT_TRUE(mDispatcher->waitForIdle());
Jackal Guof9696682018-10-05 12:23:23 +08006911
6912 if (expectToBeFiltered) {
Siarhei Vishniakou8935a802019-11-15 16:41:44 -08006913 mFakePolicy->assertFilterInputEventWasCalled(keyArgs);
Jackal Guof9696682018-10-05 12:23:23 +08006914 } else {
6915 mFakePolicy->assertFilterInputEventWasNotCalled();
6916 }
6917 }
6918};
6919
6920// Test InputFilter for MotionEvent
6921TEST_F(InputFilterTest, MotionEvent_InputFilter) {
6922 // Since the InputFilter is disabled by default, check if touch events aren't filtered.
Harry Cutts101ee9b2023-07-06 18:04:14 +00006923 testNotifyMotion(ADISPLAY_ID_DEFAULT, /*expectToBeFiltered=*/false);
6924 testNotifyMotion(SECOND_DISPLAY_ID, /*expectToBeFiltered=*/false);
Jackal Guof9696682018-10-05 12:23:23 +08006925
6926 // Enable InputFilter
6927 mDispatcher->setInputFilterEnabled(true);
6928 // Test touch on both primary and second display, and check if both events are filtered.
Harry Cutts101ee9b2023-07-06 18:04:14 +00006929 testNotifyMotion(ADISPLAY_ID_DEFAULT, /*expectToBeFiltered=*/true);
6930 testNotifyMotion(SECOND_DISPLAY_ID, /*expectToBeFiltered=*/true);
Jackal Guof9696682018-10-05 12:23:23 +08006931
6932 // Disable InputFilter
6933 mDispatcher->setInputFilterEnabled(false);
6934 // Test touch on both primary and second display, and check if both events aren't filtered.
Harry Cutts101ee9b2023-07-06 18:04:14 +00006935 testNotifyMotion(ADISPLAY_ID_DEFAULT, /*expectToBeFiltered=*/false);
6936 testNotifyMotion(SECOND_DISPLAY_ID, /*expectToBeFiltered=*/false);
Jackal Guof9696682018-10-05 12:23:23 +08006937}
6938
6939// Test InputFilter for KeyEvent
6940TEST_F(InputFilterTest, KeyEvent_InputFilter) {
6941 // Since the InputFilter is disabled by default, check if key event aren't filtered.
Harry Cutts101ee9b2023-07-06 18:04:14 +00006942 testNotifyKey(/*expectToBeFiltered=*/false);
Jackal Guof9696682018-10-05 12:23:23 +08006943
6944 // Enable InputFilter
6945 mDispatcher->setInputFilterEnabled(true);
6946 // Send a key event, and check if it is filtered.
Harry Cutts101ee9b2023-07-06 18:04:14 +00006947 testNotifyKey(/*expectToBeFiltered=*/true);
Jackal Guof9696682018-10-05 12:23:23 +08006948
6949 // Disable InputFilter
6950 mDispatcher->setInputFilterEnabled(false);
6951 // Send a key event, and check if it isn't filtered.
Harry Cutts101ee9b2023-07-06 18:04:14 +00006952 testNotifyKey(/*expectToBeFiltered=*/false);
Jackal Guof9696682018-10-05 12:23:23 +08006953}
6954
Prabir Pradhan81420cc2021-09-06 10:28:50 -07006955// Ensure that MotionEvents sent to the InputFilter through InputListener are converted to the
6956// logical display coordinate space.
6957TEST_F(InputFilterTest, MotionEvent_UsesLogicalDisplayCoordinates_notifyMotion) {
6958 ui::Transform firstDisplayTransform;
6959 firstDisplayTransform.set({1.1, 2.2, 3.3, 4.4, 5.5, 6.6, 0, 0, 1});
6960 ui::Transform secondDisplayTransform;
6961 secondDisplayTransform.set({-6.6, -5.5, -4.4, -3.3, -2.2, -1.1, 0, 0, 1});
6962
6963 std::vector<gui::DisplayInfo> displayInfos(2);
6964 displayInfos[0].displayId = ADISPLAY_ID_DEFAULT;
6965 displayInfos[0].transform = firstDisplayTransform;
6966 displayInfos[1].displayId = SECOND_DISPLAY_ID;
6967 displayInfos[1].transform = secondDisplayTransform;
6968
Patrick Williamsd828f302023-04-28 17:52:08 -05006969 mDispatcher->onWindowInfosChanged({{}, displayInfos, 0, 0});
Prabir Pradhan81420cc2021-09-06 10:28:50 -07006970
6971 // Enable InputFilter
6972 mDispatcher->setInputFilterEnabled(true);
6973
6974 // Ensure the correct transforms are used for the displays.
Harry Cutts101ee9b2023-07-06 18:04:14 +00006975 testNotifyMotion(ADISPLAY_ID_DEFAULT, /*expectToBeFiltered=*/true, firstDisplayTransform);
6976 testNotifyMotion(SECOND_DISPLAY_ID, /*expectToBeFiltered=*/true, secondDisplayTransform);
Prabir Pradhan81420cc2021-09-06 10:28:50 -07006977}
6978
Siarhei Vishniakou5d552c42021-05-21 05:02:22 +00006979class InputFilterInjectionPolicyTest : public InputDispatcherTest {
6980protected:
6981 virtual void SetUp() override {
6982 InputDispatcherTest::SetUp();
6983
6984 /**
6985 * We don't need to enable input filter to test the injected event policy, but we enabled it
6986 * here to make the tests more realistic, since this policy only matters when inputfilter is
6987 * on.
6988 */
6989 mDispatcher->setInputFilterEnabled(true);
6990
6991 std::shared_ptr<InputApplicationHandle> application =
6992 std::make_shared<FakeApplicationHandle>();
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07006993 mWindow = sp<FakeWindowHandle>::make(application, mDispatcher, "Test Window",
6994 ADISPLAY_ID_DEFAULT);
Siarhei Vishniakou5d552c42021-05-21 05:02:22 +00006995
6996 mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application);
6997 mWindow->setFocusable(true);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07006998 mDispatcher->onWindowInfosChanged({{*mWindow->getInfo()}, {}, 0, 0});
Siarhei Vishniakou5d552c42021-05-21 05:02:22 +00006999 setFocusedWindow(mWindow);
7000 mWindow->consumeFocusEvent(true);
7001 }
7002
Siarhei Vishniakouf00a4ec2021-06-16 03:55:32 +00007003 void testInjectedKey(int32_t policyFlags, int32_t injectedDeviceId, int32_t resolvedDeviceId,
7004 int32_t flags) {
Siarhei Vishniakou5d552c42021-05-21 05:02:22 +00007005 KeyEvent event;
7006
7007 const nsecs_t eventTime = systemTime(SYSTEM_TIME_MONOTONIC);
7008 event.initialize(InputEvent::nextId(), injectedDeviceId, AINPUT_SOURCE_KEYBOARD,
7009 ADISPLAY_ID_NONE, INVALID_HMAC, AKEY_EVENT_ACTION_DOWN, 0, AKEYCODE_A,
Harry Cutts33476232023-01-30 19:57:29 +00007010 KEY_A, AMETA_NONE, /*repeatCount=*/0, eventTime, eventTime);
Siarhei Vishniakou5d552c42021-05-21 05:02:22 +00007011 const int32_t additionalPolicyFlags =
7012 POLICY_FLAG_PASS_TO_USER | POLICY_FLAG_DISABLE_KEY_REPEAT;
7013 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Harry Cutts33476232023-01-30 19:57:29 +00007014 mDispatcher->injectInputEvent(&event, /*targetUid=*/{},
Siarhei Vishniakou4648fea2023-06-27 01:00:12 +00007015 InputEventInjectionSync::WAIT_FOR_RESULT, 100ms,
Siarhei Vishniakou5d552c42021-05-21 05:02:22 +00007016 policyFlags | additionalPolicyFlags));
7017
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07007018 mWindow->consumeKeyEvent(AllOf(WithDeviceId(resolvedDeviceId), WithFlags(flags)));
Siarhei Vishniakouf00a4ec2021-06-16 03:55:32 +00007019 }
7020
7021 void testInjectedMotion(int32_t policyFlags, int32_t injectedDeviceId, int32_t resolvedDeviceId,
7022 int32_t flags) {
7023 MotionEvent event;
7024 PointerProperties pointerProperties[1];
7025 PointerCoords pointerCoords[1];
7026 pointerProperties[0].clear();
7027 pointerProperties[0].id = 0;
7028 pointerCoords[0].clear();
7029 pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_X, 300);
7030 pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_Y, 400);
7031
7032 ui::Transform identityTransform;
7033 const nsecs_t eventTime = systemTime(SYSTEM_TIME_MONOTONIC);
7034 event.initialize(InputEvent::nextId(), injectedDeviceId, AINPUT_SOURCE_TOUCHSCREEN,
7035 DISPLAY_ID, INVALID_HMAC, AMOTION_EVENT_ACTION_DOWN, 0, 0,
7036 AMOTION_EVENT_EDGE_FLAG_NONE, AMETA_NONE, 0, MotionClassification::NONE,
7037 identityTransform, 0, 0, AMOTION_EVENT_INVALID_CURSOR_POSITION,
Prabir Pradhanb9b18502021-08-26 12:30:32 -07007038 AMOTION_EVENT_INVALID_CURSOR_POSITION, identityTransform, eventTime,
Evan Rosky09576692021-07-01 12:22:09 -07007039 eventTime,
Harry Cutts101ee9b2023-07-06 18:04:14 +00007040 /*pointerCount=*/1, pointerProperties, pointerCoords);
Siarhei Vishniakouf00a4ec2021-06-16 03:55:32 +00007041
7042 const int32_t additionalPolicyFlags = POLICY_FLAG_PASS_TO_USER;
7043 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Harry Cutts33476232023-01-30 19:57:29 +00007044 mDispatcher->injectInputEvent(&event, /*targetUid=*/{},
Siarhei Vishniakou4648fea2023-06-27 01:00:12 +00007045 InputEventInjectionSync::WAIT_FOR_RESULT, 100ms,
Siarhei Vishniakouf00a4ec2021-06-16 03:55:32 +00007046 policyFlags | additionalPolicyFlags));
7047
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07007048 mWindow->consumeMotionEvent(AllOf(WithFlags(flags), WithDeviceId(resolvedDeviceId)));
Siarhei Vishniakou5d552c42021-05-21 05:02:22 +00007049 }
7050
7051private:
7052 sp<FakeWindowHandle> mWindow;
7053};
7054
7055TEST_F(InputFilterInjectionPolicyTest, TrustedFilteredEvents_KeepOriginalDeviceId) {
Siarhei Vishniakouf00a4ec2021-06-16 03:55:32 +00007056 // Must have POLICY_FLAG_FILTERED here to indicate that the event has gone through the input
7057 // filter. Without it, the event will no different from a regularly injected event, and the
7058 // injected device id will be overwritten.
Harry Cutts33476232023-01-30 19:57:29 +00007059 testInjectedKey(POLICY_FLAG_FILTERED, /*injectedDeviceId=*/3, /*resolvedDeviceId=*/3,
7060 /*flags=*/0);
Siarhei Vishniakou5d552c42021-05-21 05:02:22 +00007061}
7062
Siarhei Vishniakouf00a4ec2021-06-16 03:55:32 +00007063TEST_F(InputFilterInjectionPolicyTest, KeyEventsInjectedFromAccessibility_HaveAccessibilityFlag) {
Siarhei Vishniakou5d552c42021-05-21 05:02:22 +00007064 testInjectedKey(POLICY_FLAG_FILTERED | POLICY_FLAG_INJECTED_FROM_ACCESSIBILITY,
Harry Cutts33476232023-01-30 19:57:29 +00007065 /*injectedDeviceId=*/3, /*resolvedDeviceId=*/3,
Siarhei Vishniakouf00a4ec2021-06-16 03:55:32 +00007066 AKEY_EVENT_FLAG_IS_ACCESSIBILITY_EVENT);
7067}
7068
7069TEST_F(InputFilterInjectionPolicyTest,
7070 MotionEventsInjectedFromAccessibility_HaveAccessibilityFlag) {
7071 testInjectedMotion(POLICY_FLAG_FILTERED | POLICY_FLAG_INJECTED_FROM_ACCESSIBILITY,
Harry Cutts33476232023-01-30 19:57:29 +00007072 /*injectedDeviceId=*/3, /*resolvedDeviceId=*/3,
Siarhei Vishniakouf00a4ec2021-06-16 03:55:32 +00007073 AMOTION_EVENT_FLAG_IS_ACCESSIBILITY_EVENT);
Siarhei Vishniakou5d552c42021-05-21 05:02:22 +00007074}
7075
7076TEST_F(InputFilterInjectionPolicyTest, RegularInjectedEvents_ReceiveVirtualDeviceId) {
Harry Cutts33476232023-01-30 19:57:29 +00007077 testInjectedKey(/*policyFlags=*/0, /*injectedDeviceId=*/3,
7078 /*resolvedDeviceId=*/VIRTUAL_KEYBOARD_ID, /*flags=*/0);
Siarhei Vishniakou5d552c42021-05-21 05:02:22 +00007079}
7080
Yeabkal Wubshitb8aadfa2024-01-17 17:03:42 -08007081class InputDispatcherUserActivityPokeTests : public InputDispatcherTest {
7082protected:
7083 virtual void SetUp() override {
7084 InputDispatcherTest::SetUp();
7085
7086 std::shared_ptr<FakeApplicationHandle> application =
7087 std::make_shared<FakeApplicationHandle>();
7088 application->setDispatchingTimeout(100ms);
7089 mWindow = sp<FakeWindowHandle>::make(application, mDispatcher, "TestWindow",
7090 ADISPLAY_ID_DEFAULT);
Yeabkal Wubshit222d83d2024-01-24 18:00:09 +00007091 mWindow->setFrame(Rect(0, 0, 100, 100));
Yeabkal Wubshitb8aadfa2024-01-17 17:03:42 -08007092 mWindow->setDispatchingTimeout(100ms);
7093 mWindow->setFocusable(true);
7094
7095 // Set focused application.
7096 mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application);
7097
7098 mDispatcher->onWindowInfosChanged({{*mWindow->getInfo()}, {}, 0, 0});
7099 setFocusedWindow(mWindow);
7100 mWindow->consumeFocusEvent(true);
7101 }
7102
7103 void notifyAndConsumeMotion(int32_t action, uint32_t source, int32_t displayId,
7104 nsecs_t eventTime) {
7105 mDispatcher->notifyMotion(MotionArgsBuilder(action, source)
7106 .displayId(displayId)
7107 .eventTime(eventTime)
7108 .pointer(PointerBuilder(0, ToolType::FINGER).x(50).y(50))
7109 .build());
7110 mWindow->consumeMotionEvent(WithMotionAction(action));
7111 }
7112
7113private:
7114 sp<FakeWindowHandle> mWindow;
7115};
7116
7117TEST_F_WITH_FLAGS(
7118 InputDispatcherUserActivityPokeTests, MinPokeTimeObserved,
7119 REQUIRES_FLAGS_ENABLED(ACONFIG_FLAG(com::android::input::flags,
7120 rate_limit_user_activity_poke_in_dispatcher))) {
7121 mDispatcher->setMinTimeBetweenUserActivityPokes(50ms);
7122
7123 // First event of type TOUCH. Should poke.
7124 notifyAndConsumeMotion(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
7125 milliseconds_to_nanoseconds(50));
7126 mFakePolicy->assertUserActivityPoked(
7127 {{milliseconds_to_nanoseconds(50), USER_ACTIVITY_EVENT_TOUCH, ADISPLAY_ID_DEFAULT}});
7128
7129 // 80ns > 50ns has passed since previous TOUCH event. Should poke.
7130 notifyAndConsumeMotion(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
7131 milliseconds_to_nanoseconds(130));
7132 mFakePolicy->assertUserActivityPoked(
7133 {{milliseconds_to_nanoseconds(130), USER_ACTIVITY_EVENT_TOUCH, ADISPLAY_ID_DEFAULT}});
7134
7135 // First event of type OTHER. Should poke (despite being within 50ns of previous TOUCH event).
7136 notifyAndConsumeMotion(ACTION_SCROLL, AINPUT_SOURCE_ROTARY_ENCODER, ADISPLAY_ID_DEFAULT,
7137 milliseconds_to_nanoseconds(135));
7138 mFakePolicy->assertUserActivityPoked(
7139 {{milliseconds_to_nanoseconds(135), USER_ACTIVITY_EVENT_OTHER, ADISPLAY_ID_DEFAULT}});
7140
7141 // Within 50ns of previous TOUCH event. Should NOT poke.
7142 notifyAndConsumeMotion(ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
7143 milliseconds_to_nanoseconds(140));
7144 mFakePolicy->assertUserActivityNotPoked();
7145
7146 // Within 50ns of previous OTHER event. Should NOT poke.
7147 notifyAndConsumeMotion(ACTION_SCROLL, AINPUT_SOURCE_ROTARY_ENCODER, ADISPLAY_ID_DEFAULT,
7148 milliseconds_to_nanoseconds(150));
7149 mFakePolicy->assertUserActivityNotPoked();
7150
7151 // Within 50ns of previous TOUCH event (which was at time 130). Should NOT poke.
7152 // Note that STYLUS is mapped to TOUCH user activity, since it's a pointer-type source.
7153 notifyAndConsumeMotion(ACTION_DOWN, AINPUT_SOURCE_STYLUS, ADISPLAY_ID_DEFAULT,
7154 milliseconds_to_nanoseconds(160));
7155 mFakePolicy->assertUserActivityNotPoked();
7156
7157 // 65ns > 50ns has passed since previous OTHER event. Should poke.
7158 notifyAndConsumeMotion(ACTION_SCROLL, AINPUT_SOURCE_ROTARY_ENCODER, ADISPLAY_ID_DEFAULT,
7159 milliseconds_to_nanoseconds(200));
7160 mFakePolicy->assertUserActivityPoked(
7161 {{milliseconds_to_nanoseconds(200), USER_ACTIVITY_EVENT_OTHER, ADISPLAY_ID_DEFAULT}});
7162
7163 // 170ns > 50ns has passed since previous TOUCH event. Should poke.
7164 notifyAndConsumeMotion(ACTION_UP, AINPUT_SOURCE_STYLUS, ADISPLAY_ID_DEFAULT,
7165 milliseconds_to_nanoseconds(300));
7166 mFakePolicy->assertUserActivityPoked(
7167 {{milliseconds_to_nanoseconds(300), USER_ACTIVITY_EVENT_TOUCH, ADISPLAY_ID_DEFAULT}});
7168
7169 // Assert that there's no more user activity poke event.
7170 mFakePolicy->assertUserActivityNotPoked();
7171}
7172
7173TEST_F_WITH_FLAGS(
7174 InputDispatcherUserActivityPokeTests, DefaultMinPokeTimeOf100MsUsed,
7175 REQUIRES_FLAGS_ENABLED(ACONFIG_FLAG(com::android::input::flags,
7176 rate_limit_user_activity_poke_in_dispatcher))) {
7177 notifyAndConsumeMotion(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
7178 milliseconds_to_nanoseconds(200));
7179 mFakePolicy->assertUserActivityPoked(
7180 {{milliseconds_to_nanoseconds(200), USER_ACTIVITY_EVENT_TOUCH, ADISPLAY_ID_DEFAULT}});
7181
7182 notifyAndConsumeMotion(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
7183 milliseconds_to_nanoseconds(280));
7184 mFakePolicy->assertUserActivityNotPoked();
7185
7186 notifyAndConsumeMotion(ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
7187 milliseconds_to_nanoseconds(340));
7188 mFakePolicy->assertUserActivityPoked(
7189 {{milliseconds_to_nanoseconds(340), USER_ACTIVITY_EVENT_TOUCH, ADISPLAY_ID_DEFAULT}});
7190}
7191
7192TEST_F_WITH_FLAGS(
7193 InputDispatcherUserActivityPokeTests, ZeroMinPokeTimeDisablesRateLimiting,
7194 REQUIRES_FLAGS_ENABLED(ACONFIG_FLAG(com::android::input::flags,
7195 rate_limit_user_activity_poke_in_dispatcher))) {
7196 mDispatcher->setMinTimeBetweenUserActivityPokes(0ms);
7197
7198 notifyAndConsumeMotion(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, 20);
7199 mFakePolicy->assertUserActivityPoked();
7200
7201 notifyAndConsumeMotion(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, 30);
7202 mFakePolicy->assertUserActivityPoked();
7203}
7204
chaviwfd6d3512019-03-25 13:23:49 -07007205class InputDispatcherOnPointerDownOutsideFocus : public InputDispatcherTest {
Prabir Pradhan3608aad2019-10-02 17:08:26 -07007206 virtual void SetUp() override {
chaviwfd6d3512019-03-25 13:23:49 -07007207 InputDispatcherTest::SetUp();
7208
Chris Yea209fde2020-07-22 13:54:51 -07007209 std::shared_ptr<FakeApplicationHandle> application =
7210 std::make_shared<FakeApplicationHandle>();
Siarhei Vishniakou870ecec2020-12-09 08:07:46 -10007211 mUnfocusedWindow =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07007212 sp<FakeWindowHandle>::make(application, mDispatcher, "Top", ADISPLAY_ID_DEFAULT);
chaviwfd6d3512019-03-25 13:23:49 -07007213 mUnfocusedWindow->setFrame(Rect(0, 0, 30, 30));
chaviwfd6d3512019-03-25 13:23:49 -07007214
Siarhei Vishniakoub9b15352019-11-26 13:19:26 -08007215 mFocusedWindow =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07007216 sp<FakeWindowHandle>::make(application, mDispatcher, "Second", ADISPLAY_ID_DEFAULT);
Siarhei Vishniakoub9b15352019-11-26 13:19:26 -08007217 mFocusedWindow->setFrame(Rect(50, 50, 100, 100));
chaviwfd6d3512019-03-25 13:23:49 -07007218
7219 // Set focused application.
7220 mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application);
Vishnu Nair47074b82020-08-14 11:54:47 -07007221 mFocusedWindow->setFocusable(true);
chaviwfd6d3512019-03-25 13:23:49 -07007222
7223 // Expect one focus window exist in display.
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07007224 mDispatcher->onWindowInfosChanged(
7225 {{*mUnfocusedWindow->getInfo(), *mFocusedWindow->getInfo()}, {}, 0, 0});
Vishnu Nair958da932020-08-21 17:12:37 -07007226 setFocusedWindow(mFocusedWindow);
Siarhei Vishniakouf1035d42019-09-20 16:32:01 +01007227 mFocusedWindow->consumeFocusEvent(true);
chaviwfd6d3512019-03-25 13:23:49 -07007228 }
7229
Prabir Pradhan3608aad2019-10-02 17:08:26 -07007230 virtual void TearDown() override {
chaviwfd6d3512019-03-25 13:23:49 -07007231 InputDispatcherTest::TearDown();
7232
7233 mUnfocusedWindow.clear();
Siarhei Vishniakoub9b15352019-11-26 13:19:26 -08007234 mFocusedWindow.clear();
chaviwfd6d3512019-03-25 13:23:49 -07007235 }
7236
7237protected:
7238 sp<FakeWindowHandle> mUnfocusedWindow;
Siarhei Vishniakoub9b15352019-11-26 13:19:26 -08007239 sp<FakeWindowHandle> mFocusedWindow;
Siarhei Vishniakoufb9fcda2020-05-04 14:59:19 -07007240 static constexpr PointF FOCUSED_WINDOW_TOUCH_POINT = {60, 60};
chaviwfd6d3512019-03-25 13:23:49 -07007241};
7242
7243// Have two windows, one with focus. Inject MotionEvent with source TOUCHSCREEN and action
7244// DOWN on the window that doesn't have focus. Ensure the window that didn't have focus received
7245// the onPointerDownOutsideFocus callback.
7246TEST_F(InputDispatcherOnPointerDownOutsideFocus, OnPointerDownOutsideFocus_Success) {
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08007247 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07007248 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
Siarhei Vishniakoufb9fcda2020-05-04 14:59:19 -07007249 {20, 20}))
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08007250 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
Siarhei Vishniakou03aee2a2020-04-13 20:44:54 -07007251 mUnfocusedWindow->consumeMotionDown();
chaviwfd6d3512019-03-25 13:23:49 -07007252
Siarhei Vishniakou2bfa9052019-11-21 18:10:54 -08007253 ASSERT_TRUE(mDispatcher->waitForIdle());
chaviwfd6d3512019-03-25 13:23:49 -07007254 mFakePolicy->assertOnPointerDownEquals(mUnfocusedWindow->getToken());
7255}
7256
7257// Have two windows, one with focus. Inject MotionEvent with source TRACKBALL and action
7258// DOWN on the window that doesn't have focus. Ensure no window received the
7259// onPointerDownOutsideFocus callback.
7260TEST_F(InputDispatcherOnPointerDownOutsideFocus, OnPointerDownOutsideFocus_NonPointerSource) {
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08007261 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07007262 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TRACKBALL, ADISPLAY_ID_DEFAULT,
7263 {20, 20}))
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08007264 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
Siarhei Vishniakou03aee2a2020-04-13 20:44:54 -07007265 mFocusedWindow->consumeMotionDown();
chaviwfd6d3512019-03-25 13:23:49 -07007266
Siarhei Vishniakou2bfa9052019-11-21 18:10:54 -08007267 ASSERT_TRUE(mDispatcher->waitForIdle());
7268 mFakePolicy->assertOnPointerDownWasNotCalled();
chaviwfd6d3512019-03-25 13:23:49 -07007269}
7270
7271// Have two windows, one with focus. Inject KeyEvent with action DOWN on the window that doesn't
7272// have focus. Ensure no window received the onPointerDownOutsideFocus callback.
7273TEST_F(InputDispatcherOnPointerDownOutsideFocus, OnPointerDownOutsideFocus_NonMotionFailure) {
Prabir Pradhan93f342c2021-03-11 15:05:30 -08007274 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07007275 injectKeyDownNoRepeat(*mDispatcher, ADISPLAY_ID_DEFAULT))
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08007276 << "Inject key event should return InputEventInjectionResult::SUCCEEDED";
Siarhei Vishniakou03aee2a2020-04-13 20:44:54 -07007277 mFocusedWindow->consumeKeyDown(ADISPLAY_ID_DEFAULT);
chaviwfd6d3512019-03-25 13:23:49 -07007278
Siarhei Vishniakou2bfa9052019-11-21 18:10:54 -08007279 ASSERT_TRUE(mDispatcher->waitForIdle());
7280 mFakePolicy->assertOnPointerDownWasNotCalled();
chaviwfd6d3512019-03-25 13:23:49 -07007281}
7282
7283// Have two windows, one with focus. Inject MotionEvent with source TOUCHSCREEN and action
7284// DOWN on the window that already has focus. Ensure no window received the
7285// onPointerDownOutsideFocus callback.
Siarhei Vishniakou870ecec2020-12-09 08:07:46 -10007286TEST_F(InputDispatcherOnPointerDownOutsideFocus, OnPointerDownOutsideFocus_OnAlreadyFocusedWindow) {
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08007287 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07007288 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
Siarhei Vishniakoufb9fcda2020-05-04 14:59:19 -07007289 FOCUSED_WINDOW_TOUCH_POINT))
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08007290 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
Siarhei Vishniakou03aee2a2020-04-13 20:44:54 -07007291 mFocusedWindow->consumeMotionDown();
chaviwfd6d3512019-03-25 13:23:49 -07007292
Siarhei Vishniakou2bfa9052019-11-21 18:10:54 -08007293 ASSERT_TRUE(mDispatcher->waitForIdle());
7294 mFakePolicy->assertOnPointerDownWasNotCalled();
chaviwfd6d3512019-03-25 13:23:49 -07007295}
7296
Prabir Pradhan47cf0a02021-03-11 20:30:57 -08007297// Have two windows, one with focus. Injecting a trusted DOWN MotionEvent with the flag
7298// NO_FOCUS_CHANGE on the unfocused window should not call the onPointerDownOutsideFocus callback.
7299TEST_F(InputDispatcherOnPointerDownOutsideFocus, NoFocusChangeFlag) {
7300 const MotionEvent event =
7301 MotionEventBuilder(AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_MOUSE)
7302 .eventTime(systemTime(SYSTEM_TIME_MONOTONIC))
Siarhei Vishniakou6d73f832022-07-21 17:27:03 -07007303 .pointer(PointerBuilder(/*id=*/0, ToolType::FINGER).x(20).y(20))
Prabir Pradhan47cf0a02021-03-11 20:30:57 -08007304 .addFlag(AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE)
7305 .build();
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07007306 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectMotionEvent(*mDispatcher, event))
Prabir Pradhan47cf0a02021-03-11 20:30:57 -08007307 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
7308 mUnfocusedWindow->consumeAnyMotionDown(ADISPLAY_ID_DEFAULT, AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
7309
7310 ASSERT_TRUE(mDispatcher->waitForIdle());
7311 mFakePolicy->assertOnPointerDownWasNotCalled();
7312 // Ensure that the unfocused window did not receive any FOCUS events.
7313 mUnfocusedWindow->assertNoEvents();
7314}
7315
chaviwaf87b3e2019-10-01 16:59:28 -07007316// These tests ensures we can send touch events to a single client when there are multiple input
7317// windows that point to the same client token.
7318class InputDispatcherMultiWindowSameTokenTests : public InputDispatcherTest {
7319 virtual void SetUp() override {
7320 InputDispatcherTest::SetUp();
7321
Chris Yea209fde2020-07-22 13:54:51 -07007322 std::shared_ptr<FakeApplicationHandle> application =
7323 std::make_shared<FakeApplicationHandle>();
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07007324 mWindow1 = sp<FakeWindowHandle>::make(application, mDispatcher, "Fake Window 1",
7325 ADISPLAY_ID_DEFAULT);
chaviwaf87b3e2019-10-01 16:59:28 -07007326 mWindow1->setFrame(Rect(0, 0, 100, 100));
7327
Prabir Pradhane7cc69c2024-01-05 21:35:28 +00007328 mWindow2 = mWindow1->clone(ADISPLAY_ID_DEFAULT);
chaviwaf87b3e2019-10-01 16:59:28 -07007329 mWindow2->setFrame(Rect(100, 100, 200, 200));
7330
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07007331 mDispatcher->onWindowInfosChanged({{*mWindow1->getInfo(), *mWindow2->getInfo()}, {}, 0, 0});
chaviwaf87b3e2019-10-01 16:59:28 -07007332 }
7333
7334protected:
7335 sp<FakeWindowHandle> mWindow1;
7336 sp<FakeWindowHandle> mWindow2;
7337
7338 // Helper function to convert the point from screen coordinates into the window's space
chaviw3277faf2021-05-19 16:45:23 -05007339 static PointF getPointInWindow(const WindowInfo* windowInfo, const PointF& point) {
chaviw1ff3d1e2020-07-01 15:53:47 -07007340 vec2 vals = windowInfo->transform.transform(point.x, point.y);
7341 return {vals.x, vals.y};
chaviwaf87b3e2019-10-01 16:59:28 -07007342 }
7343
7344 void consumeMotionEvent(const sp<FakeWindowHandle>& window, int32_t expectedAction,
7345 const std::vector<PointF>& points) {
Siarhei Vishniakouf1035d42019-09-20 16:32:01 +01007346 const std::string name = window->getName();
Siarhei Vishniakoud3061ab2023-12-18 20:41:08 -08007347 std::unique_ptr<MotionEvent> motionEvent =
Prabir Pradhan7662a8d2023-12-15 01:58:14 +00007348 window->consumeMotionEvent(WithMotionAction(expectedAction));
Siarhei Vishniakoud3061ab2023-12-18 20:41:08 -08007349 ASSERT_NE(nullptr, motionEvent);
7350 ASSERT_EQ(points.size(), motionEvent->getPointerCount());
chaviwaf87b3e2019-10-01 16:59:28 -07007351
7352 for (size_t i = 0; i < points.size(); i++) {
7353 float expectedX = points[i].x;
7354 float expectedY = points[i].y;
7355
Siarhei Vishniakoud3061ab2023-12-18 20:41:08 -08007356 EXPECT_EQ(expectedX, motionEvent->getX(i))
chaviwaf87b3e2019-10-01 16:59:28 -07007357 << "expected " << expectedX << " for x[" << i << "] coord of " << name.c_str()
Siarhei Vishniakoud3061ab2023-12-18 20:41:08 -08007358 << ", got " << motionEvent->getX(i);
7359 EXPECT_EQ(expectedY, motionEvent->getY(i))
chaviwaf87b3e2019-10-01 16:59:28 -07007360 << "expected " << expectedY << " for y[" << i << "] coord of " << name.c_str()
Siarhei Vishniakoud3061ab2023-12-18 20:41:08 -08007361 << ", got " << motionEvent->getY(i);
chaviwaf87b3e2019-10-01 16:59:28 -07007362 }
7363 }
chaviw9eaa22c2020-07-01 16:21:27 -07007364
Prabir Pradhanbb3f1c02024-01-04 20:17:14 +00007365 void touchAndAssertPositions(sp<FakeWindowHandle> touchedWindow, int32_t action,
7366 const std::vector<PointF>& touchedPoints,
chaviw9eaa22c2020-07-01 16:21:27 -07007367 std::vector<PointF> expectedPoints) {
Prabir Pradhan678438e2023-04-13 19:32:51 +00007368 mDispatcher->notifyMotion(generateMotionArgs(action, AINPUT_SOURCE_TOUCHSCREEN,
7369 ADISPLAY_ID_DEFAULT, touchedPoints));
chaviw9eaa22c2020-07-01 16:21:27 -07007370
Prabir Pradhanbb3f1c02024-01-04 20:17:14 +00007371 consumeMotionEvent(touchedWindow, action, expectedPoints);
chaviw9eaa22c2020-07-01 16:21:27 -07007372 }
chaviwaf87b3e2019-10-01 16:59:28 -07007373};
7374
7375TEST_F(InputDispatcherMultiWindowSameTokenTests, SingleTouchSameScale) {
7376 // Touch Window 1
7377 PointF touchedPoint = {10, 10};
7378 PointF expectedPoint = getPointInWindow(mWindow1->getInfo(), touchedPoint);
Prabir Pradhanbb3f1c02024-01-04 20:17:14 +00007379 touchAndAssertPositions(mWindow1, AMOTION_EVENT_ACTION_DOWN, {touchedPoint}, {expectedPoint});
chaviwaf87b3e2019-10-01 16:59:28 -07007380
7381 // Release touch on Window 1
Prabir Pradhanbb3f1c02024-01-04 20:17:14 +00007382 touchAndAssertPositions(mWindow1, AMOTION_EVENT_ACTION_UP, {touchedPoint}, {expectedPoint});
chaviwaf87b3e2019-10-01 16:59:28 -07007383
7384 // Touch Window 2
7385 touchedPoint = {150, 150};
7386 expectedPoint = getPointInWindow(mWindow2->getInfo(), touchedPoint);
Prabir Pradhanbb3f1c02024-01-04 20:17:14 +00007387 touchAndAssertPositions(mWindow2, AMOTION_EVENT_ACTION_DOWN, {touchedPoint}, {expectedPoint});
chaviwaf87b3e2019-10-01 16:59:28 -07007388}
7389
chaviw9eaa22c2020-07-01 16:21:27 -07007390TEST_F(InputDispatcherMultiWindowSameTokenTests, SingleTouchDifferentTransform) {
7391 // Set scale value for window2
chaviwaf87b3e2019-10-01 16:59:28 -07007392 mWindow2->setWindowScale(0.5f, 0.5f);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07007393 mDispatcher->onWindowInfosChanged({{*mWindow1->getInfo(), *mWindow2->getInfo()}, {}, 0, 0});
chaviwaf87b3e2019-10-01 16:59:28 -07007394
7395 // Touch Window 1
7396 PointF touchedPoint = {10, 10};
7397 PointF expectedPoint = getPointInWindow(mWindow1->getInfo(), touchedPoint);
Prabir Pradhanbb3f1c02024-01-04 20:17:14 +00007398 touchAndAssertPositions(mWindow1, AMOTION_EVENT_ACTION_DOWN, {touchedPoint}, {expectedPoint});
chaviwaf87b3e2019-10-01 16:59:28 -07007399 // Release touch on Window 1
Prabir Pradhanbb3f1c02024-01-04 20:17:14 +00007400 touchAndAssertPositions(mWindow1, AMOTION_EVENT_ACTION_UP, {touchedPoint}, {expectedPoint});
chaviwaf87b3e2019-10-01 16:59:28 -07007401
7402 // Touch Window 2
7403 touchedPoint = {150, 150};
7404 expectedPoint = getPointInWindow(mWindow2->getInfo(), touchedPoint);
Prabir Pradhanbb3f1c02024-01-04 20:17:14 +00007405 touchAndAssertPositions(mWindow2, AMOTION_EVENT_ACTION_DOWN, {touchedPoint}, {expectedPoint});
7406 touchAndAssertPositions(mWindow2, AMOTION_EVENT_ACTION_UP, {touchedPoint}, {expectedPoint});
chaviwaf87b3e2019-10-01 16:59:28 -07007407
chaviw9eaa22c2020-07-01 16:21:27 -07007408 // Update the transform so rotation is set
7409 mWindow2->setWindowTransform(0, -1, 1, 0);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07007410 mDispatcher->onWindowInfosChanged({{*mWindow1->getInfo(), *mWindow2->getInfo()}, {}, 0, 0});
chaviw9eaa22c2020-07-01 16:21:27 -07007411 expectedPoint = getPointInWindow(mWindow2->getInfo(), touchedPoint);
Prabir Pradhanbb3f1c02024-01-04 20:17:14 +00007412 touchAndAssertPositions(mWindow2, AMOTION_EVENT_ACTION_DOWN, {touchedPoint}, {expectedPoint});
chaviwaf87b3e2019-10-01 16:59:28 -07007413}
7414
chaviw9eaa22c2020-07-01 16:21:27 -07007415TEST_F(InputDispatcherMultiWindowSameTokenTests, MultipleTouchDifferentTransform) {
Chavi Weingarten65f98b82020-01-16 18:56:50 +00007416 mWindow2->setWindowScale(0.5f, 0.5f);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07007417 mDispatcher->onWindowInfosChanged({{*mWindow1->getInfo(), *mWindow2->getInfo()}, {}, 0, 0});
Chavi Weingarten65f98b82020-01-16 18:56:50 +00007418
7419 // Touch Window 1
7420 std::vector<PointF> touchedPoints = {PointF{10, 10}};
7421 std::vector<PointF> expectedPoints = {getPointInWindow(mWindow1->getInfo(), touchedPoints[0])};
Prabir Pradhanbb3f1c02024-01-04 20:17:14 +00007422 touchAndAssertPositions(mWindow1, AMOTION_EVENT_ACTION_DOWN, touchedPoints, expectedPoints);
Chavi Weingarten65f98b82020-01-16 18:56:50 +00007423
7424 // Touch Window 2
Prabir Pradhanbb3f1c02024-01-04 20:17:14 +00007425 // Since this is part of the same touch gesture that has already been dispatched to Window 1,
7426 // the touch stream from Window 2 will be merged with the stream in Window 1. The merged stream
7427 // will continue to be dispatched through Window 1.
chaviw9eaa22c2020-07-01 16:21:27 -07007428 touchedPoints.push_back(PointF{150, 150});
7429 expectedPoints.push_back(getPointInWindow(mWindow2->getInfo(), touchedPoints[1]));
Prabir Pradhanbb3f1c02024-01-04 20:17:14 +00007430 touchAndAssertPositions(mWindow1, POINTER_1_DOWN, touchedPoints, expectedPoints);
Chavi Weingarten65f98b82020-01-16 18:56:50 +00007431
chaviw9eaa22c2020-07-01 16:21:27 -07007432 // Release Window 2
Prabir Pradhanbb3f1c02024-01-04 20:17:14 +00007433 touchAndAssertPositions(mWindow1, POINTER_1_UP, touchedPoints, expectedPoints);
chaviw9eaa22c2020-07-01 16:21:27 -07007434 expectedPoints.pop_back();
Chavi Weingarten65f98b82020-01-16 18:56:50 +00007435
chaviw9eaa22c2020-07-01 16:21:27 -07007436 // Update the transform so rotation is set for Window 2
7437 mWindow2->setWindowTransform(0, -1, 1, 0);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07007438 mDispatcher->onWindowInfosChanged({{*mWindow1->getInfo(), *mWindow2->getInfo()}, {}, 0, 0});
chaviw9eaa22c2020-07-01 16:21:27 -07007439 expectedPoints.push_back(getPointInWindow(mWindow2->getInfo(), touchedPoints[1]));
Prabir Pradhanbb3f1c02024-01-04 20:17:14 +00007440 touchAndAssertPositions(mWindow1, POINTER_1_DOWN, touchedPoints, expectedPoints);
Chavi Weingarten65f98b82020-01-16 18:56:50 +00007441}
7442
chaviw9eaa22c2020-07-01 16:21:27 -07007443TEST_F(InputDispatcherMultiWindowSameTokenTests, MultipleTouchMoveDifferentTransform) {
Chavi Weingarten65f98b82020-01-16 18:56:50 +00007444 mWindow2->setWindowScale(0.5f, 0.5f);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07007445 mDispatcher->onWindowInfosChanged({{*mWindow1->getInfo(), *mWindow2->getInfo()}, {}, 0, 0});
Chavi Weingarten65f98b82020-01-16 18:56:50 +00007446
7447 // Touch Window 1
7448 std::vector<PointF> touchedPoints = {PointF{10, 10}};
7449 std::vector<PointF> expectedPoints = {getPointInWindow(mWindow1->getInfo(), touchedPoints[0])};
Prabir Pradhanbb3f1c02024-01-04 20:17:14 +00007450 touchAndAssertPositions(mWindow1, AMOTION_EVENT_ACTION_DOWN, touchedPoints, expectedPoints);
Chavi Weingarten65f98b82020-01-16 18:56:50 +00007451
7452 // Touch Window 2
chaviw9eaa22c2020-07-01 16:21:27 -07007453 touchedPoints.push_back(PointF{150, 150});
7454 expectedPoints.push_back(getPointInWindow(mWindow2->getInfo(), touchedPoints[1]));
Chavi Weingarten65f98b82020-01-16 18:56:50 +00007455
Prabir Pradhanbb3f1c02024-01-04 20:17:14 +00007456 touchAndAssertPositions(mWindow1, POINTER_1_DOWN, touchedPoints, expectedPoints);
Chavi Weingarten65f98b82020-01-16 18:56:50 +00007457
7458 // Move both windows
7459 touchedPoints = {{20, 20}, {175, 175}};
7460 expectedPoints = {getPointInWindow(mWindow1->getInfo(), touchedPoints[0]),
7461 getPointInWindow(mWindow2->getInfo(), touchedPoints[1])};
7462
Prabir Pradhanbb3f1c02024-01-04 20:17:14 +00007463 touchAndAssertPositions(mWindow1, AMOTION_EVENT_ACTION_MOVE, touchedPoints, expectedPoints);
Chavi Weingarten65f98b82020-01-16 18:56:50 +00007464
chaviw9eaa22c2020-07-01 16:21:27 -07007465 // Release Window 2
Prabir Pradhanbb3f1c02024-01-04 20:17:14 +00007466 touchAndAssertPositions(mWindow1, POINTER_1_UP, touchedPoints, expectedPoints);
chaviw9eaa22c2020-07-01 16:21:27 -07007467 expectedPoints.pop_back();
7468
7469 // Touch Window 2
7470 mWindow2->setWindowTransform(0, -1, 1, 0);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07007471 mDispatcher->onWindowInfosChanged({{*mWindow1->getInfo(), *mWindow2->getInfo()}, {}, 0, 0});
chaviw9eaa22c2020-07-01 16:21:27 -07007472 expectedPoints.push_back(getPointInWindow(mWindow2->getInfo(), touchedPoints[1]));
Prabir Pradhanbb3f1c02024-01-04 20:17:14 +00007473 touchAndAssertPositions(mWindow1, POINTER_1_DOWN, touchedPoints, expectedPoints);
chaviw9eaa22c2020-07-01 16:21:27 -07007474
7475 // Move both windows
7476 touchedPoints = {{20, 20}, {175, 175}};
7477 expectedPoints = {getPointInWindow(mWindow1->getInfo(), touchedPoints[0]),
7478 getPointInWindow(mWindow2->getInfo(), touchedPoints[1])};
7479
Prabir Pradhanbb3f1c02024-01-04 20:17:14 +00007480 touchAndAssertPositions(mWindow1, AMOTION_EVENT_ACTION_MOVE, touchedPoints, expectedPoints);
Chavi Weingarten65f98b82020-01-16 18:56:50 +00007481}
7482
7483TEST_F(InputDispatcherMultiWindowSameTokenTests, MultipleWindowsFirstTouchWithScale) {
7484 mWindow1->setWindowScale(0.5f, 0.5f);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07007485 mDispatcher->onWindowInfosChanged({{*mWindow1->getInfo(), *mWindow2->getInfo()}, {}, 0, 0});
Chavi Weingarten65f98b82020-01-16 18:56:50 +00007486
7487 // Touch Window 1
7488 std::vector<PointF> touchedPoints = {PointF{10, 10}};
7489 std::vector<PointF> expectedPoints = {getPointInWindow(mWindow1->getInfo(), touchedPoints[0])};
Prabir Pradhanbb3f1c02024-01-04 20:17:14 +00007490 touchAndAssertPositions(mWindow1, AMOTION_EVENT_ACTION_DOWN, touchedPoints, expectedPoints);
Chavi Weingarten65f98b82020-01-16 18:56:50 +00007491
7492 // Touch Window 2
chaviw9eaa22c2020-07-01 16:21:27 -07007493 touchedPoints.push_back(PointF{150, 150});
7494 expectedPoints.push_back(getPointInWindow(mWindow2->getInfo(), touchedPoints[1]));
Chavi Weingarten65f98b82020-01-16 18:56:50 +00007495
Prabir Pradhanbb3f1c02024-01-04 20:17:14 +00007496 touchAndAssertPositions(mWindow1, POINTER_1_DOWN, touchedPoints, expectedPoints);
Chavi Weingarten65f98b82020-01-16 18:56:50 +00007497
7498 // Move both windows
7499 touchedPoints = {{20, 20}, {175, 175}};
7500 expectedPoints = {getPointInWindow(mWindow1->getInfo(), touchedPoints[0]),
7501 getPointInWindow(mWindow2->getInfo(), touchedPoints[1])};
7502
Prabir Pradhanbb3f1c02024-01-04 20:17:14 +00007503 touchAndAssertPositions(mWindow1, AMOTION_EVENT_ACTION_MOVE, touchedPoints, expectedPoints);
Chavi Weingarten65f98b82020-01-16 18:56:50 +00007504}
7505
Siarhei Vishniakou0f6558d2023-04-21 12:05:13 -07007506/**
7507 * When one of the windows is slippery, the touch should not slip into the other window with the
7508 * same input channel.
7509 */
7510TEST_F(InputDispatcherMultiWindowSameTokenTests, TouchDoesNotSlipEvenIfSlippery) {
7511 mWindow1->setSlippery(true);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07007512 mDispatcher->onWindowInfosChanged({{*mWindow1->getInfo(), *mWindow2->getInfo()}, {}, 0, 0});
Siarhei Vishniakou0f6558d2023-04-21 12:05:13 -07007513
7514 // Touch down in window 1
7515 mDispatcher->notifyMotion(generateMotionArgs(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN,
7516 ADISPLAY_ID_DEFAULT, {{50, 50}}));
7517 consumeMotionEvent(mWindow1, ACTION_DOWN, {{50, 50}});
7518
7519 // Move touch to be above window 2. Even though window 1 is slippery, touch should not slip.
7520 // That means the gesture should continue normally, without any ACTION_CANCEL or ACTION_DOWN
7521 // getting generated.
7522 mDispatcher->notifyMotion(generateMotionArgs(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN,
7523 ADISPLAY_ID_DEFAULT, {{150, 150}}));
7524
7525 consumeMotionEvent(mWindow1, ACTION_MOVE, {{150, 150}});
7526}
7527
Siarhei Vishniakoud5876ba2023-05-15 17:58:34 -07007528/**
7529 * When hover starts in one window and continues into the other, there should be a HOVER_EXIT and
7530 * a HOVER_ENTER generated, even if the windows have the same token. This is because the new window
7531 * that the pointer is hovering over may have a different transform.
7532 */
7533TEST_F(InputDispatcherMultiWindowSameTokenTests, HoverIntoClone) {
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07007534 mDispatcher->onWindowInfosChanged({{*mWindow1->getInfo(), *mWindow2->getInfo()}, {}, 0, 0});
Siarhei Vishniakoud5876ba2023-05-15 17:58:34 -07007535
7536 // Start hover in window 1
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -07007537 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_ENTER, AINPUT_SOURCE_TOUCHSCREEN)
7538 .pointer(PointerBuilder(0, ToolType::FINGER).x(50).y(50))
7539 .build());
Siarhei Vishniakoud5876ba2023-05-15 17:58:34 -07007540 consumeMotionEvent(mWindow1, ACTION_HOVER_ENTER,
7541 {getPointInWindow(mWindow1->getInfo(), PointF{50, 50})});
Siarhei Vishniakoud5876ba2023-05-15 17:58:34 -07007542 // Move hover to window 2.
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -07007543 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_MOVE, AINPUT_SOURCE_TOUCHSCREEN)
7544 .pointer(PointerBuilder(0, ToolType::FINGER).x(150).y(150))
7545 .build());
Siarhei Vishniakoud5876ba2023-05-15 17:58:34 -07007546 consumeMotionEvent(mWindow1, ACTION_HOVER_EXIT, {{50, 50}});
Prabir Pradhanbb3f1c02024-01-04 20:17:14 +00007547 consumeMotionEvent(mWindow2, ACTION_HOVER_ENTER,
Siarhei Vishniakoud5876ba2023-05-15 17:58:34 -07007548 {getPointInWindow(mWindow2->getInfo(), PointF{150, 150})});
7549}
7550
Siarhei Vishniakou4cb50ca2020-05-26 21:43:02 -07007551class InputDispatcherSingleWindowAnr : public InputDispatcherTest {
7552 virtual void SetUp() override {
7553 InputDispatcherTest::SetUp();
7554
Chris Yea209fde2020-07-22 13:54:51 -07007555 mApplication = std::make_shared<FakeApplicationHandle>();
Siarhei Vishniakouf83c6932023-07-07 17:48:10 -07007556 mApplication->setDispatchingTimeout(100ms);
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07007557 mWindow = sp<FakeWindowHandle>::make(mApplication, mDispatcher, "TestWindow",
7558 ADISPLAY_ID_DEFAULT);
Siarhei Vishniakou4cb50ca2020-05-26 21:43:02 -07007559 mWindow->setFrame(Rect(0, 0, 30, 30));
Siarhei Vishniakouf83c6932023-07-07 17:48:10 -07007560 mWindow->setDispatchingTimeout(100ms);
Vishnu Nair47074b82020-08-14 11:54:47 -07007561 mWindow->setFocusable(true);
Siarhei Vishniakou4cb50ca2020-05-26 21:43:02 -07007562
7563 // Set focused application.
7564 mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, mApplication);
7565
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07007566 mDispatcher->onWindowInfosChanged({{*mWindow->getInfo()}, {}, 0, 0});
Vishnu Nair958da932020-08-21 17:12:37 -07007567 setFocusedWindow(mWindow);
Siarhei Vishniakou4cb50ca2020-05-26 21:43:02 -07007568 mWindow->consumeFocusEvent(true);
7569 }
7570
7571 virtual void TearDown() override {
7572 InputDispatcherTest::TearDown();
7573 mWindow.clear();
7574 }
7575
7576protected:
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07007577 static constexpr std::chrono::duration SPY_TIMEOUT = 200ms;
Chris Yea209fde2020-07-22 13:54:51 -07007578 std::shared_ptr<FakeApplicationHandle> mApplication;
Siarhei Vishniakou4cb50ca2020-05-26 21:43:02 -07007579 sp<FakeWindowHandle> mWindow;
7580 static constexpr PointF WINDOW_LOCATION = {20, 20};
7581
7582 void tapOnWindow() {
Siarhei Vishniakou67bf2162023-11-16 13:29:50 -08007583 const auto touchingPointer = PointerBuilder(/*id=*/0, ToolType::FINGER)
7584 .x(WINDOW_LOCATION.x)
7585 .y(WINDOW_LOCATION.y);
7586 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
7587 .pointer(touchingPointer)
7588 .build());
7589 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN)
7590 .pointer(touchingPointer)
7591 .build());
Siarhei Vishniakou4cb50ca2020-05-26 21:43:02 -07007592 }
Prabir Pradhan1376fcd2022-01-21 09:56:35 -08007593
7594 sp<FakeWindowHandle> addSpyWindow() {
7595 sp<FakeWindowHandle> spy =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07007596 sp<FakeWindowHandle>::make(mApplication, mDispatcher, "Spy", ADISPLAY_ID_DEFAULT);
Prabir Pradhan1376fcd2022-01-21 09:56:35 -08007597 spy->setTrustedOverlay(true);
7598 spy->setFocusable(false);
Prabir Pradhan51e7db02022-02-07 06:02:57 -08007599 spy->setSpy(true);
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07007600 spy->setDispatchingTimeout(SPY_TIMEOUT);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07007601 mDispatcher->onWindowInfosChanged({{*spy->getInfo(), *mWindow->getInfo()}, {}, 0, 0});
Prabir Pradhan1376fcd2022-01-21 09:56:35 -08007602 return spy;
7603 }
Siarhei Vishniakou4cb50ca2020-05-26 21:43:02 -07007604};
7605
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07007606// Send a tap and respond, which should not cause an ANR.
7607TEST_F(InputDispatcherSingleWindowAnr, WhenTouchIsConsumed_NoAnr) {
7608 tapOnWindow();
7609 mWindow->consumeMotionDown();
7610 mWindow->consumeMotionUp();
7611 ASSERT_TRUE(mDispatcher->waitForIdle());
7612 mFakePolicy->assertNotifyAnrWasNotCalled();
7613}
7614
7615// Send a regular key and respond, which should not cause an ANR.
7616TEST_F(InputDispatcherSingleWindowAnr, WhenKeyIsConsumed_NoAnr) {
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07007617 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectKeyDownNoRepeat(*mDispatcher));
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07007618 mWindow->consumeKeyDown(ADISPLAY_ID_NONE);
7619 ASSERT_TRUE(mDispatcher->waitForIdle());
7620 mFakePolicy->assertNotifyAnrWasNotCalled();
7621}
7622
Siarhei Vishniakoue41c4512020-09-08 19:35:58 -05007623TEST_F(InputDispatcherSingleWindowAnr, WhenFocusedApplicationChanges_NoAnr) {
7624 mWindow->setFocusable(false);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07007625 mDispatcher->onWindowInfosChanged({{*mWindow->getInfo()}, {}, 0, 0});
Siarhei Vishniakoue41c4512020-09-08 19:35:58 -05007626 mWindow->consumeFocusEvent(false);
7627
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08007628 InputEventInjectionResult result =
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07007629 injectKey(*mDispatcher, AKEY_EVENT_ACTION_DOWN, /*repeatCount=*/0, ADISPLAY_ID_DEFAULT,
7630 InputEventInjectionSync::NONE, CONSUME_TIMEOUT_EVENT_EXPECTED,
Harry Cutts33476232023-01-30 19:57:29 +00007631 /*allowKeyRepeat=*/false);
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08007632 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, result);
Siarhei Vishniakoue41c4512020-09-08 19:35:58 -05007633 // Key will not go to window because we have no focused window.
7634 // The 'no focused window' ANR timer should start instead.
7635
7636 // Now, the focused application goes away.
7637 mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, nullptr);
7638 // The key should get dropped and there should be no ANR.
7639
7640 ASSERT_TRUE(mDispatcher->waitForIdle());
7641 mFakePolicy->assertNotifyAnrWasNotCalled();
7642}
7643
Siarhei Vishniakou4cb50ca2020-05-26 21:43:02 -07007644// Send an event to the app and have the app not respond right away.
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07007645// When ANR is raised, policy will tell the dispatcher to cancel the events for that window.
7646// So InputDispatcher will enqueue ACTION_CANCEL event as well.
Siarhei Vishniakou4cb50ca2020-05-26 21:43:02 -07007647TEST_F(InputDispatcherSingleWindowAnr, OnPointerDown_BasicAnr) {
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08007648 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07007649 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
Siarhei Vishniakou4cb50ca2020-05-26 21:43:02 -07007650 WINDOW_LOCATION));
7651
Siarhei Vishniakoud3061ab2023-12-18 20:41:08 -08007652 const auto [sequenceNum, _] = mWindow->receiveEvent(); // ACTION_DOWN
Siarhei Vishniakou4cb50ca2020-05-26 21:43:02 -07007653 ASSERT_TRUE(sequenceNum);
7654 const std::chrono::duration timeout = mWindow->getDispatchingTimeout(DISPATCHING_TIMEOUT);
Prabir Pradhanedd96402022-02-15 01:46:16 -08007655 mFakePolicy->assertNotifyWindowUnresponsiveWasCalled(timeout, mWindow);
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07007656
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07007657 mWindow->finishEvent(*sequenceNum);
Siarhei Vishniakou1ae72f12023-01-29 12:55:30 -08007658 mWindow->consumeMotionEvent(
7659 AllOf(WithMotionAction(ACTION_CANCEL), WithDisplayId(ADISPLAY_ID_DEFAULT)));
Siarhei Vishniakou4cb50ca2020-05-26 21:43:02 -07007660 ASSERT_TRUE(mDispatcher->waitForIdle());
Prabir Pradhanedd96402022-02-15 01:46:16 -08007661 mFakePolicy->assertNotifyWindowResponsiveWasCalled(mWindow->getToken(), mWindow->getPid());
Siarhei Vishniakou4cb50ca2020-05-26 21:43:02 -07007662}
7663
7664// Send a key to the app and have the app not respond right away.
7665TEST_F(InputDispatcherSingleWindowAnr, OnKeyDown_BasicAnr) {
7666 // Inject a key, and don't respond - expect that ANR is called.
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07007667 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectKeyDownNoRepeat(*mDispatcher));
Siarhei Vishniakoud3061ab2023-12-18 20:41:08 -08007668 const auto [sequenceNum, _] = mWindow->receiveEvent();
Siarhei Vishniakou4cb50ca2020-05-26 21:43:02 -07007669 ASSERT_TRUE(sequenceNum);
Siarhei Vishniakou4cb50ca2020-05-26 21:43:02 -07007670 const std::chrono::duration timeout = mWindow->getDispatchingTimeout(DISPATCHING_TIMEOUT);
Prabir Pradhanedd96402022-02-15 01:46:16 -08007671 mFakePolicy->assertNotifyWindowUnresponsiveWasCalled(timeout, mWindow);
Siarhei Vishniakou4cb50ca2020-05-26 21:43:02 -07007672 ASSERT_TRUE(mDispatcher->waitForIdle());
7673}
7674
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07007675// We have a focused application, but no focused window
7676TEST_F(InputDispatcherSingleWindowAnr, FocusedApplication_NoFocusedWindow) {
Vishnu Nair47074b82020-08-14 11:54:47 -07007677 mWindow->setFocusable(false);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07007678 mDispatcher->onWindowInfosChanged({{*mWindow->getInfo()}, {}, 0, 0});
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07007679 mWindow->consumeFocusEvent(false);
7680
7681 // taps on the window work as normal
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08007682 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07007683 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07007684 WINDOW_LOCATION));
7685 ASSERT_NO_FATAL_FAILURE(mWindow->consumeMotionDown());
7686 mDispatcher->waitForIdle();
7687 mFakePolicy->assertNotifyAnrWasNotCalled();
7688
7689 // Once a focused event arrives, we get an ANR for this application
7690 // We specify the injection timeout to be smaller than the application timeout, to ensure that
7691 // injection times out (instead of failing).
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08007692 const InputEventInjectionResult result =
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07007693 injectKey(*mDispatcher, AKEY_EVENT_ACTION_DOWN, /*repeatCount=*/0, ADISPLAY_ID_DEFAULT,
Siarhei Vishniakouf83c6932023-07-07 17:48:10 -07007694 InputEventInjectionSync::WAIT_FOR_RESULT, 50ms, /*allowKeyRepeat=*/false);
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08007695 ASSERT_EQ(InputEventInjectionResult::TIMED_OUT, result);
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07007696 const std::chrono::duration timeout = mApplication->getDispatchingTimeout(DISPATCHING_TIMEOUT);
Vishnu Naire4df8752022-09-08 09:17:55 -07007697 mFakePolicy->assertNotifyNoFocusedWindowAnrWasCalled(timeout, mApplication);
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07007698 ASSERT_TRUE(mDispatcher->waitForIdle());
7699}
7700
Siarhei Vishniakou289e9242022-02-15 14:50:16 -08007701/**
7702 * Make sure the stale key is dropped before causing an ANR. So even if there's no focused window,
7703 * there will not be an ANR.
7704 */
7705TEST_F(InputDispatcherSingleWindowAnr, StaleKeyEventDoesNotAnr) {
7706 mWindow->setFocusable(false);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07007707 mDispatcher->onWindowInfosChanged({{*mWindow->getInfo()}, {}, 0, 0});
Siarhei Vishniakou289e9242022-02-15 14:50:16 -08007708 mWindow->consumeFocusEvent(false);
7709
7710 KeyEvent event;
Siarhei Vishniakoua7333112023-10-27 13:33:29 -07007711 static constexpr std::chrono::duration STALE_EVENT_TIMEOUT = 1000ms;
7712 mFakePolicy->setStaleEventTimeout(STALE_EVENT_TIMEOUT);
Siarhei Vishniakou289e9242022-02-15 14:50:16 -08007713 const nsecs_t eventTime = systemTime(SYSTEM_TIME_MONOTONIC) -
7714 std::chrono::nanoseconds(STALE_EVENT_TIMEOUT).count();
7715
7716 // Define a valid key down event that is stale (too old).
7717 event.initialize(InputEvent::nextId(), DEVICE_ID, AINPUT_SOURCE_KEYBOARD, ADISPLAY_ID_NONE,
Harry Cutts101ee9b2023-07-06 18:04:14 +00007718 INVALID_HMAC, AKEY_EVENT_ACTION_DOWN, /*flags=*/0, AKEYCODE_A, KEY_A,
Hu Guofe3c8f12023-09-22 17:20:15 +08007719 AMETA_NONE, /*repeatCount=*/0, eventTime, eventTime);
Siarhei Vishniakou289e9242022-02-15 14:50:16 -08007720
Hu Guofe3c8f12023-09-22 17:20:15 +08007721 const int32_t policyFlags =
7722 POLICY_FLAG_FILTERED | POLICY_FLAG_PASS_TO_USER | POLICY_FLAG_DISABLE_KEY_REPEAT;
Siarhei Vishniakou289e9242022-02-15 14:50:16 -08007723
7724 InputEventInjectionResult result =
Harry Cutts33476232023-01-30 19:57:29 +00007725 mDispatcher->injectInputEvent(&event, /*targetUid=*/{},
Siarhei Vishniakou289e9242022-02-15 14:50:16 -08007726 InputEventInjectionSync::WAIT_FOR_RESULT,
7727 INJECT_EVENT_TIMEOUT, policyFlags);
7728 ASSERT_EQ(InputEventInjectionResult::FAILED, result)
7729 << "Injection should fail because the event is stale";
7730
7731 ASSERT_TRUE(mDispatcher->waitForIdle());
7732 mFakePolicy->assertNotifyAnrWasNotCalled();
7733 mWindow->assertNoEvents();
7734}
7735
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07007736// We have a focused application, but no focused window
Siarhei Vishniakou234129c2020-10-22 22:28:12 -05007737// Make sure that we don't notify policy twice about the same ANR.
7738TEST_F(InputDispatcherSingleWindowAnr, NoFocusedWindow_DoesNotSendDuplicateAnr) {
Siarhei Vishniakou06405fc2023-09-22 13:40:51 -07007739 const std::chrono::duration appTimeout = 400ms;
7740 mApplication->setDispatchingTimeout(appTimeout);
7741 mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, mApplication);
7742
Vishnu Nair47074b82020-08-14 11:54:47 -07007743 mWindow->setFocusable(false);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07007744 mDispatcher->onWindowInfosChanged({{*mWindow->getInfo()}, {}, 0, 0});
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07007745 mWindow->consumeFocusEvent(false);
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07007746
7747 // Once a focused event arrives, we get an ANR for this application
7748 // We specify the injection timeout to be smaller than the application timeout, to ensure that
7749 // injection times out (instead of failing).
Siarhei Vishniakou06405fc2023-09-22 13:40:51 -07007750 const std::chrono::duration eventInjectionTimeout = 100ms;
7751 ASSERT_LT(eventInjectionTimeout, appTimeout);
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08007752 const InputEventInjectionResult result =
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07007753 injectKey(*mDispatcher, AKEY_EVENT_ACTION_DOWN, /*repeatCount=*/0, ADISPLAY_ID_DEFAULT,
Siarhei Vishniakou06405fc2023-09-22 13:40:51 -07007754 InputEventInjectionSync::WAIT_FOR_RESULT, eventInjectionTimeout,
7755 /*allowKeyRepeat=*/false);
7756 ASSERT_EQ(InputEventInjectionResult::TIMED_OUT, result)
7757 << "result=" << ftl::enum_string(result);
7758 // We already waited for 'eventInjectionTimeout`, because the countdown started when the event
7759 // was first injected. So now we have (appTimeout - eventInjectionTimeout) left to wait.
7760 std::chrono::duration remainingWaitTime = appTimeout - eventInjectionTimeout;
7761 mFakePolicy->assertNotifyNoFocusedWindowAnrWasCalled(remainingWaitTime, mApplication);
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07007762
Vishnu Naire4df8752022-09-08 09:17:55 -07007763 std::this_thread::sleep_for(appTimeout);
Siarhei Vishniakou234129c2020-10-22 22:28:12 -05007764 // ANR should not be raised again. It is up to policy to do that if it desires.
7765 mFakePolicy->assertNotifyAnrWasNotCalled();
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07007766
Siarhei Vishniakou234129c2020-10-22 22:28:12 -05007767 // If we now get a focused window, the ANR should stop, but the policy handles that via
7768 // 'notifyFocusChanged' callback. This is implemented in the policy so we can't test it here.
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07007769 ASSERT_TRUE(mDispatcher->waitForIdle());
7770}
7771
7772// We have a focused application, but no focused window
7773TEST_F(InputDispatcherSingleWindowAnr, NoFocusedWindow_DropsFocusedEvents) {
Vishnu Nair47074b82020-08-14 11:54:47 -07007774 mWindow->setFocusable(false);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07007775 mDispatcher->onWindowInfosChanged({{*mWindow->getInfo()}, {}, 0, 0});
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07007776 mWindow->consumeFocusEvent(false);
7777
7778 // Once a focused event arrives, we get an ANR for this application
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07007779 ASSERT_NO_FATAL_FAILURE(assertInjectedKeyTimesOut(*mDispatcher));
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07007780
Vishnu Naire4df8752022-09-08 09:17:55 -07007781 const std::chrono::duration timeout = mApplication->getDispatchingTimeout(DISPATCHING_TIMEOUT);
7782 mFakePolicy->assertNotifyNoFocusedWindowAnrWasCalled(timeout, mApplication);
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07007783
7784 // Future focused events get dropped right away
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07007785 ASSERT_EQ(InputEventInjectionResult::FAILED, injectKeyDown(*mDispatcher));
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07007786 ASSERT_TRUE(mDispatcher->waitForIdle());
7787 mWindow->assertNoEvents();
7788}
7789
7790/**
7791 * Ensure that the implementation is valid. Since we are using multiset to keep track of the
7792 * ANR timeouts, we are allowing entries with identical timestamps in the same connection.
7793 * If we process 1 of the events, but ANR on the second event with the same timestamp,
7794 * the ANR mechanism should still work.
7795 *
7796 * In this test, we are injecting DOWN and UP events with the same timestamps, and acknowledging the
7797 * DOWN event, while not responding on the second one.
7798 */
7799TEST_F(InputDispatcherSingleWindowAnr, Anr_HandlesEventsWithIdenticalTimestamps) {
7800 nsecs_t currentTime = systemTime(SYSTEM_TIME_MONOTONIC);
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07007801 injectMotionEvent(*mDispatcher, AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN,
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07007802 ADISPLAY_ID_DEFAULT, WINDOW_LOCATION,
7803 {AMOTION_EVENT_INVALID_CURSOR_POSITION,
7804 AMOTION_EVENT_INVALID_CURSOR_POSITION},
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08007805 500ms, InputEventInjectionSync::WAIT_FOR_RESULT, currentTime);
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07007806
7807 // Now send ACTION_UP, with identical timestamp
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07007808 injectMotionEvent(*mDispatcher, AMOTION_EVENT_ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN,
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07007809 ADISPLAY_ID_DEFAULT, WINDOW_LOCATION,
7810 {AMOTION_EVENT_INVALID_CURSOR_POSITION,
7811 AMOTION_EVENT_INVALID_CURSOR_POSITION},
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08007812 500ms, InputEventInjectionSync::WAIT_FOR_RESULT, currentTime);
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07007813
7814 // We have now sent down and up. Let's consume first event and then ANR on the second.
7815 mWindow->consumeMotionDown(ADISPLAY_ID_DEFAULT);
7816 const std::chrono::duration timeout = mWindow->getDispatchingTimeout(DISPATCHING_TIMEOUT);
Prabir Pradhanedd96402022-02-15 01:46:16 -08007817 mFakePolicy->assertNotifyWindowUnresponsiveWasCalled(timeout, mWindow);
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07007818}
7819
Prabir Pradhan1376fcd2022-01-21 09:56:35 -08007820// A spy window can receive an ANR
7821TEST_F(InputDispatcherSingleWindowAnr, SpyWindowAnr) {
7822 sp<FakeWindowHandle> spy = addSpyWindow();
7823
7824 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07007825 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
Prabir Pradhan1376fcd2022-01-21 09:56:35 -08007826 WINDOW_LOCATION));
7827 mWindow->consumeMotionDown();
7828
Siarhei Vishniakoud3061ab2023-12-18 20:41:08 -08007829 const auto [sequenceNum, _] = spy->receiveEvent(); // ACTION_DOWN
Prabir Pradhan1376fcd2022-01-21 09:56:35 -08007830 ASSERT_TRUE(sequenceNum);
7831 const std::chrono::duration timeout = spy->getDispatchingTimeout(DISPATCHING_TIMEOUT);
Prabir Pradhanedd96402022-02-15 01:46:16 -08007832 mFakePolicy->assertNotifyWindowUnresponsiveWasCalled(timeout, spy);
Prabir Pradhan1376fcd2022-01-21 09:56:35 -08007833
7834 spy->finishEvent(*sequenceNum);
Siarhei Vishniakou1ae72f12023-01-29 12:55:30 -08007835 spy->consumeMotionEvent(
7836 AllOf(WithMotionAction(ACTION_CANCEL), WithDisplayId(ADISPLAY_ID_DEFAULT)));
Prabir Pradhan1376fcd2022-01-21 09:56:35 -08007837 ASSERT_TRUE(mDispatcher->waitForIdle());
Prabir Pradhanedd96402022-02-15 01:46:16 -08007838 mFakePolicy->assertNotifyWindowResponsiveWasCalled(spy->getToken(), mWindow->getPid());
Prabir Pradhan1376fcd2022-01-21 09:56:35 -08007839}
7840
7841// If an app is not responding to a key event, spy windows should continue to receive
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07007842// new motion events
Prabir Pradhan1376fcd2022-01-21 09:56:35 -08007843TEST_F(InputDispatcherSingleWindowAnr, SpyWindowReceivesEventsDuringAppAnrOnKey) {
7844 sp<FakeWindowHandle> spy = addSpyWindow();
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07007845
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08007846 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07007847 injectKeyDown(*mDispatcher, ADISPLAY_ID_DEFAULT));
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07007848 mWindow->consumeKeyDown(ADISPLAY_ID_DEFAULT);
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07007849 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectKeyUp(*mDispatcher, ADISPLAY_ID_DEFAULT));
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07007850
7851 // Stuck on the ACTION_UP
7852 const std::chrono::duration timeout = mWindow->getDispatchingTimeout(DISPATCHING_TIMEOUT);
Prabir Pradhanedd96402022-02-15 01:46:16 -08007853 mFakePolicy->assertNotifyWindowUnresponsiveWasCalled(timeout, mWindow);
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07007854
Prabir Pradhan1376fcd2022-01-21 09:56:35 -08007855 // New tap will go to the spy window, but not to the window
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07007856 tapOnWindow();
Prabir Pradhan1376fcd2022-01-21 09:56:35 -08007857 spy->consumeMotionDown(ADISPLAY_ID_DEFAULT);
7858 spy->consumeMotionUp(ADISPLAY_ID_DEFAULT);
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07007859
7860 mWindow->consumeKeyUp(ADISPLAY_ID_DEFAULT); // still the previous motion
7861 mDispatcher->waitForIdle();
Prabir Pradhanedd96402022-02-15 01:46:16 -08007862 mFakePolicy->assertNotifyWindowResponsiveWasCalled(mWindow->getToken(), mWindow->getPid());
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07007863 mWindow->assertNoEvents();
Prabir Pradhan1376fcd2022-01-21 09:56:35 -08007864 spy->assertNoEvents();
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07007865}
7866
Prabir Pradhan1376fcd2022-01-21 09:56:35 -08007867// If an app is not responding to a motion event, spy windows should continue to receive
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07007868// new motion events
Prabir Pradhan1376fcd2022-01-21 09:56:35 -08007869TEST_F(InputDispatcherSingleWindowAnr, SpyWindowReceivesEventsDuringAppAnrOnMotion) {
7870 sp<FakeWindowHandle> spy = addSpyWindow();
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07007871
7872 tapOnWindow();
Prabir Pradhan1376fcd2022-01-21 09:56:35 -08007873 spy->consumeMotionDown(ADISPLAY_ID_DEFAULT);
7874 spy->consumeMotionUp(ADISPLAY_ID_DEFAULT);
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07007875
7876 mWindow->consumeMotionDown();
7877 // Stuck on the ACTION_UP
7878 const std::chrono::duration timeout = mWindow->getDispatchingTimeout(DISPATCHING_TIMEOUT);
Prabir Pradhanedd96402022-02-15 01:46:16 -08007879 mFakePolicy->assertNotifyWindowUnresponsiveWasCalled(timeout, mWindow);
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07007880
Prabir Pradhan1376fcd2022-01-21 09:56:35 -08007881 // New tap will go to the spy window, but not to the window
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07007882 tapOnWindow();
Prabir Pradhan1376fcd2022-01-21 09:56:35 -08007883 spy->consumeMotionDown(ADISPLAY_ID_DEFAULT);
7884 spy->consumeMotionUp(ADISPLAY_ID_DEFAULT);
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07007885
7886 mWindow->consumeMotionUp(ADISPLAY_ID_DEFAULT); // still the previous motion
7887 mDispatcher->waitForIdle();
Prabir Pradhanedd96402022-02-15 01:46:16 -08007888 mFakePolicy->assertNotifyWindowResponsiveWasCalled(mWindow->getToken(), mWindow->getPid());
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07007889 mWindow->assertNoEvents();
Prabir Pradhan1376fcd2022-01-21 09:56:35 -08007890 spy->assertNoEvents();
7891}
7892
7893TEST_F(InputDispatcherSingleWindowAnr, UnresponsiveMonitorAnr) {
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07007894 mDispatcher->setMonitorDispatchingTimeoutForTest(SPY_TIMEOUT);
Prabir Pradhan1376fcd2022-01-21 09:56:35 -08007895
Prabir Pradhanfb549072023-10-05 19:17:36 +00007896 FakeMonitorReceiver monitor = FakeMonitorReceiver(*mDispatcher, "M_1", ADISPLAY_ID_DEFAULT);
Prabir Pradhan1376fcd2022-01-21 09:56:35 -08007897
7898 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07007899 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
Prabir Pradhan1376fcd2022-01-21 09:56:35 -08007900 WINDOW_LOCATION));
7901
7902 mWindow->consumeMotionDown(ADISPLAY_ID_DEFAULT);
7903 const std::optional<uint32_t> consumeSeq = monitor.receiveEvent();
7904 ASSERT_TRUE(consumeSeq);
7905
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07007906 mFakePolicy->assertNotifyWindowUnresponsiveWasCalled(SPY_TIMEOUT, monitor.getToken(),
7907 MONITOR_PID);
Prabir Pradhan1376fcd2022-01-21 09:56:35 -08007908
7909 monitor.finishEvent(*consumeSeq);
7910 monitor.consumeMotionCancel(ADISPLAY_ID_DEFAULT);
7911
7912 ASSERT_TRUE(mDispatcher->waitForIdle());
Prabir Pradhanedd96402022-02-15 01:46:16 -08007913 mFakePolicy->assertNotifyWindowResponsiveWasCalled(monitor.getToken(), MONITOR_PID);
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07007914}
7915
7916// If a window is unresponsive, then you get anr. if the window later catches up and starts to
7917// process events, you don't get an anr. When the window later becomes unresponsive again, you
7918// get an ANR again.
7919// 1. tap -> block on ACTION_UP -> receive ANR
7920// 2. consume all pending events (= queue becomes healthy again)
7921// 3. tap again -> block on ACTION_UP again -> receive ANR second time
7922TEST_F(InputDispatcherSingleWindowAnr, SameWindow_CanReceiveAnrTwice) {
7923 tapOnWindow();
7924
7925 mWindow->consumeMotionDown();
7926 // Block on ACTION_UP
7927 const std::chrono::duration timeout = mWindow->getDispatchingTimeout(DISPATCHING_TIMEOUT);
Prabir Pradhanedd96402022-02-15 01:46:16 -08007928 mFakePolicy->assertNotifyWindowUnresponsiveWasCalled(timeout, mWindow);
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07007929 mWindow->consumeMotionUp(); // Now the connection should be healthy again
7930 mDispatcher->waitForIdle();
Prabir Pradhanedd96402022-02-15 01:46:16 -08007931 mFakePolicy->assertNotifyWindowResponsiveWasCalled(mWindow->getToken(), mWindow->getPid());
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07007932 mWindow->assertNoEvents();
7933
7934 tapOnWindow();
7935 mWindow->consumeMotionDown();
Prabir Pradhanedd96402022-02-15 01:46:16 -08007936 mFakePolicy->assertNotifyWindowUnresponsiveWasCalled(timeout, mWindow);
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07007937 mWindow->consumeMotionUp();
7938
7939 mDispatcher->waitForIdle();
Prabir Pradhanedd96402022-02-15 01:46:16 -08007940 mFakePolicy->assertNotifyWindowResponsiveWasCalled(mWindow->getToken(), mWindow->getPid());
Siarhei Vishniakou234129c2020-10-22 22:28:12 -05007941 mFakePolicy->assertNotifyAnrWasNotCalled();
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07007942 mWindow->assertNoEvents();
7943}
7944
Siarhei Vishniakou234129c2020-10-22 22:28:12 -05007945// If a connection remains unresponsive for a while, make sure policy is only notified once about
7946// it.
7947TEST_F(InputDispatcherSingleWindowAnr, Policy_DoesNotGetDuplicateAnr) {
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08007948 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07007949 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07007950 WINDOW_LOCATION));
7951
7952 const std::chrono::duration windowTimeout = mWindow->getDispatchingTimeout(DISPATCHING_TIMEOUT);
Prabir Pradhanedd96402022-02-15 01:46:16 -08007953 mFakePolicy->assertNotifyWindowUnresponsiveWasCalled(windowTimeout, mWindow);
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07007954 std::this_thread::sleep_for(windowTimeout);
Siarhei Vishniakou234129c2020-10-22 22:28:12 -05007955 // 'notifyConnectionUnresponsive' should only be called once per connection
7956 mFakePolicy->assertNotifyAnrWasNotCalled();
7957 // When the ANR happened, dispatcher should abort the current event stream via ACTION_CANCEL
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07007958 mWindow->consumeMotionDown();
Siarhei Vishniakou1ae72f12023-01-29 12:55:30 -08007959 mWindow->consumeMotionEvent(
7960 AllOf(WithMotionAction(ACTION_CANCEL), WithDisplayId(ADISPLAY_ID_DEFAULT)));
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07007961 mWindow->assertNoEvents();
Siarhei Vishniakou234129c2020-10-22 22:28:12 -05007962 mDispatcher->waitForIdle();
Prabir Pradhanedd96402022-02-15 01:46:16 -08007963 mFakePolicy->assertNotifyWindowResponsiveWasCalled(mWindow->getToken(), mWindow->getPid());
Siarhei Vishniakou234129c2020-10-22 22:28:12 -05007964 mFakePolicy->assertNotifyAnrWasNotCalled();
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07007965}
7966
7967/**
7968 * If a window is processing a motion event, and then a key event comes in, the key event should
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07007969 * not get delivered to the focused window until the motion is processed.
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07007970 */
7971TEST_F(InputDispatcherSingleWindowAnr, Key_StaysPendingWhileMotionIsProcessed) {
Siarhei Vishniakouef2b4502023-12-28 11:51:47 -08007972 // The timeouts in this test are established by relying on the fact that the "key waiting for
7973 // events timeout" is equal to 500ms.
7974 ASSERT_EQ(mFakePolicy->getKeyWaitingForEventsTimeout(), 500ms);
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07007975 mWindow->setDispatchingTimeout(2s); // Set a long ANR timeout to prevent it from triggering
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07007976 mDispatcher->onWindowInfosChanged({{*mWindow->getInfo()}, {}, 0, 0});
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07007977
7978 tapOnWindow();
Siarhei Vishniakoud3061ab2023-12-18 20:41:08 -08007979 const auto& [downSequenceNum, downEvent] = mWindow->receiveEvent();
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07007980 ASSERT_TRUE(downSequenceNum);
Siarhei Vishniakoud3061ab2023-12-18 20:41:08 -08007981 const auto& [upSequenceNum, upEvent] = mWindow->receiveEvent();
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07007982 ASSERT_TRUE(upSequenceNum);
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07007983
Siarhei Vishniakouef2b4502023-12-28 11:51:47 -08007984 // Don't finish the events yet, and send a key
7985 mDispatcher->notifyKey(
7986 KeyArgsBuilder(AKEY_EVENT_ACTION_DOWN, AINPUT_SOURCE_KEYBOARD)
7987 .policyFlags(DEFAULT_POLICY_FLAGS | POLICY_FLAG_DISABLE_KEY_REPEAT)
7988 .build());
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07007989 // Key will not be sent to the window, yet, because the window is still processing events
7990 // and the key remains pending, waiting for the touch events to be processed
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07007991 // Make sure that `assertNoEvents` doesn't wait too long, because it could cause an ANR.
Siarhei Vishniakouef2b4502023-12-28 11:51:47 -08007992 mWindow->assertNoEvents(100ms);
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07007993
Siarhei Vishniakouef2b4502023-12-28 11:51:47 -08007994 std::this_thread::sleep_for(400ms);
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07007995 // if we wait long enough though, dispatcher will give up, and still send the key
7996 // to the focused window, even though we have not yet finished the motion event
7997 mWindow->consumeKeyDown(ADISPLAY_ID_DEFAULT);
7998 mWindow->finishEvent(*downSequenceNum);
7999 mWindow->finishEvent(*upSequenceNum);
8000}
8001
8002/**
8003 * If a window is processing a motion event, and then a key event comes in, the key event should
8004 * not go to the focused window until the motion is processed.
8005 * If then a new motion comes in, then the pending key event should be going to the currently
8006 * focused window right away.
8007 */
8008TEST_F(InputDispatcherSingleWindowAnr,
Siarhei Vishniakouef2b4502023-12-28 11:51:47 -08008009 PendingKey_IsDeliveredWhileMotionIsProcessingAndNewTouchComesIn) {
8010 // The timeouts in this test are established by relying on the fact that the "key waiting for
8011 // events timeout" is equal to 500ms.
8012 ASSERT_EQ(mFakePolicy->getKeyWaitingForEventsTimeout(), 500ms);
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07008013 mWindow->setDispatchingTimeout(2s); // Set a long ANR timeout to prevent it from triggering
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07008014 mDispatcher->onWindowInfosChanged({{*mWindow->getInfo()}, {}, 0, 0});
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07008015
8016 tapOnWindow();
Siarhei Vishniakoud3061ab2023-12-18 20:41:08 -08008017 const auto& [downSequenceNum, _] = mWindow->receiveEvent();
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07008018 ASSERT_TRUE(downSequenceNum);
Siarhei Vishniakoud3061ab2023-12-18 20:41:08 -08008019 const auto& [upSequenceNum, upEvent] = mWindow->receiveEvent();
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07008020 ASSERT_TRUE(upSequenceNum);
8021 // Don't finish the events yet, and send a key
Siarhei Vishniakou67bf2162023-11-16 13:29:50 -08008022 mDispatcher->notifyKey(
8023 KeyArgsBuilder(AKEY_EVENT_ACTION_DOWN, AINPUT_SOURCE_KEYBOARD)
8024 .policyFlags(DEFAULT_POLICY_FLAGS | POLICY_FLAG_DISABLE_KEY_REPEAT)
8025 .build());
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07008026 // At this point, key is still pending, and should not be sent to the application yet.
Siarhei Vishniakouef2b4502023-12-28 11:51:47 -08008027 mWindow->assertNoEvents(100ms);
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07008028
8029 // Now tap down again. It should cause the pending key to go to the focused window right away.
8030 tapOnWindow();
Siarhei Vishniakouef2b4502023-12-28 11:51:47 -08008031 // Now that we tapped, we should receive the key immediately.
8032 // Since there's still room for slowness, we use 200ms, which is much less than
8033 // the "key waiting for events' timeout of 500ms minus the already waited 100ms duration.
8034 std::unique_ptr<InputEvent> keyEvent = mWindow->consume(200ms);
8035 ASSERT_NE(nullptr, keyEvent);
8036 ASSERT_EQ(InputEventType::KEY, keyEvent->getType());
8037 ASSERT_THAT(static_cast<KeyEvent&>(*keyEvent), WithKeyAction(AKEY_EVENT_ACTION_DOWN));
8038 // it doesn't matter that we haven't ack'd the other events yet. We can finish events in any
8039 // order.
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07008040 mWindow->finishEvent(*downSequenceNum); // first tap's ACTION_DOWN
8041 mWindow->finishEvent(*upSequenceNum); // first tap's ACTION_UP
Siarhei Vishniakou67bf2162023-11-16 13:29:50 -08008042 mWindow->consumeMotionEvent(WithMotionAction(ACTION_DOWN));
8043 mWindow->consumeMotionEvent(WithMotionAction(ACTION_UP));
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07008044 mWindow->assertNoEvents();
8045}
8046
Siarhei Vishniakouadb9fc92023-05-26 10:46:09 -07008047/**
8048 * Send an event to the app and have the app not respond right away.
8049 * When ANR is raised, policy will tell the dispatcher to cancel the events for that window.
8050 * So InputDispatcher will enqueue ACTION_CANCEL event as well.
8051 * At some point, the window becomes responsive again.
8052 * Ensure that subsequent events get dropped, and the next gesture is delivered.
8053 */
8054TEST_F(InputDispatcherSingleWindowAnr, TwoGesturesWithAnr) {
8055 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
8056 .pointer(PointerBuilder(0, ToolType::FINGER).x(10).y(10))
8057 .build());
8058
Siarhei Vishniakoud3061ab2023-12-18 20:41:08 -08008059 const auto [sequenceNum, _] = mWindow->receiveEvent(); // ACTION_DOWN
Siarhei Vishniakouadb9fc92023-05-26 10:46:09 -07008060 ASSERT_TRUE(sequenceNum);
8061 const std::chrono::duration timeout = mWindow->getDispatchingTimeout(DISPATCHING_TIMEOUT);
8062 mFakePolicy->assertNotifyWindowUnresponsiveWasCalled(timeout, mWindow);
8063
8064 mWindow->finishEvent(*sequenceNum);
8065 mWindow->consumeMotionEvent(WithMotionAction(ACTION_CANCEL));
8066 ASSERT_TRUE(mDispatcher->waitForIdle());
8067 mFakePolicy->assertNotifyWindowResponsiveWasCalled(mWindow->getToken(), mWindow->getPid());
8068
8069 // Now that the window is responsive, let's continue the gesture.
8070 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN)
8071 .pointer(PointerBuilder(0, ToolType::FINGER).x(11).y(11))
8072 .build());
8073
8074 mDispatcher->notifyMotion(MotionArgsBuilder(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
8075 .pointer(PointerBuilder(0, ToolType::FINGER).x(11).y(11))
8076 .pointer(PointerBuilder(1, ToolType::FINGER).x(3).y(3))
8077 .build());
8078
8079 mDispatcher->notifyMotion(MotionArgsBuilder(POINTER_1_UP, AINPUT_SOURCE_TOUCHSCREEN)
8080 .pointer(PointerBuilder(0, ToolType::FINGER).x(11).y(11))
8081 .pointer(PointerBuilder(1, ToolType::FINGER).x(3).y(3))
8082 .build());
8083 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN)
8084 .pointer(PointerBuilder(0, ToolType::FINGER).x(11).y(11))
8085 .build());
8086 // We already canceled this pointer, so the window shouldn't get any new events.
8087 mWindow->assertNoEvents();
8088
8089 // Start another one.
8090 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
8091 .pointer(PointerBuilder(0, ToolType::FINGER).x(15).y(15))
8092 .build());
8093 mWindow->consumeMotionEvent(WithMotionAction(ACTION_DOWN));
8094}
8095
Prabir Pradhanfc364722024-02-08 17:51:20 +00008096// Send an event to the app and have the app not respond right away. Then remove the app window.
8097// When the window is removed, the dispatcher will cancel the events for that window.
8098// So InputDispatcher will enqueue ACTION_CANCEL event as well.
8099TEST_F(InputDispatcherSingleWindowAnr, AnrAfterWindowRemoval) {
8100 mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_DOWN,
8101 AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
8102 {WINDOW_LOCATION}));
8103
8104 const auto [sequenceNum, _] = mWindow->receiveEvent(); // ACTION_DOWN
8105 ASSERT_TRUE(sequenceNum);
8106
8107 // Remove the window, but the input channel should remain alive.
8108 mDispatcher->onWindowInfosChanged({{}, {}, 0, 0});
8109
8110 const std::chrono::duration timeout = mWindow->getDispatchingTimeout(DISPATCHING_TIMEOUT);
8111 // Since the window was removed, Dispatcher does not know the PID associated with the window
8112 // anymore, so the policy is notified without the PID.
8113 mFakePolicy->assertNotifyWindowUnresponsiveWasCalled(timeout, mWindow->getToken(),
8114 /*pid=*/std::nullopt);
8115
8116 mWindow->finishEvent(*sequenceNum);
8117 // The cancellation was generated when the window was removed, along with the focus event.
8118 mWindow->consumeMotionEvent(
8119 AllOf(WithMotionAction(ACTION_CANCEL), WithDisplayId(ADISPLAY_ID_DEFAULT)));
8120 mWindow->consumeFocusEvent(false);
8121 ASSERT_TRUE(mDispatcher->waitForIdle());
8122 mFakePolicy->assertNotifyWindowResponsiveWasCalled(mWindow->getToken(), /*pid=*/std::nullopt);
8123}
8124
8125// Send an event to the app and have the app not respond right away. Wait for the policy to be
8126// notified of the unresponsive window, then remove the app window.
8127TEST_F(InputDispatcherSingleWindowAnr, AnrFollowedByWindowRemoval) {
8128 mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_DOWN,
8129 AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
8130 {WINDOW_LOCATION}));
8131
8132 const auto [sequenceNum, _] = mWindow->receiveEvent(); // ACTION_DOWN
8133 ASSERT_TRUE(sequenceNum);
8134 const std::chrono::duration timeout = mWindow->getDispatchingTimeout(DISPATCHING_TIMEOUT);
8135 mFakePolicy->assertNotifyWindowUnresponsiveWasCalled(timeout, mWindow);
8136
8137 // Remove the window, but the input channel should remain alive.
8138 mDispatcher->onWindowInfosChanged({{}, {}, 0, 0});
8139
8140 mWindow->finishEvent(*sequenceNum);
8141 // The cancellation was generated during the ANR, and the window lost focus when it was removed.
8142 mWindow->consumeMotionEvent(
8143 AllOf(WithMotionAction(ACTION_CANCEL), WithDisplayId(ADISPLAY_ID_DEFAULT)));
8144 mWindow->consumeFocusEvent(false);
8145 ASSERT_TRUE(mDispatcher->waitForIdle());
8146 // Since the window was removed, Dispatcher does not know the PID associated with the window
8147 // becoming responsive, so the policy is notified without the PID.
8148 mFakePolicy->assertNotifyWindowResponsiveWasCalled(mWindow->getToken(), /*pid=*/std::nullopt);
8149}
8150
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07008151class InputDispatcherMultiWindowAnr : public InputDispatcherTest {
8152 virtual void SetUp() override {
8153 InputDispatcherTest::SetUp();
8154
Chris Yea209fde2020-07-22 13:54:51 -07008155 mApplication = std::make_shared<FakeApplicationHandle>();
Siarhei Vishniakouf83c6932023-07-07 17:48:10 -07008156 mApplication->setDispatchingTimeout(100ms);
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07008157 mUnfocusedWindow = sp<FakeWindowHandle>::make(mApplication, mDispatcher, "Unfocused",
8158 ADISPLAY_ID_DEFAULT);
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07008159 mUnfocusedWindow->setFrame(Rect(0, 0, 30, 30));
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07008160 // Adding FLAG_WATCH_OUTSIDE_TOUCH to receive ACTION_OUTSIDE when another window is tapped
Prabir Pradhan4d5c52f2022-01-31 08:52:10 -08008161 mUnfocusedWindow->setWatchOutsideTouch(true);
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07008162
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07008163 mFocusedWindow = sp<FakeWindowHandle>::make(mApplication, mDispatcher, "Focused",
8164 ADISPLAY_ID_DEFAULT);
Siarhei Vishniakouf83c6932023-07-07 17:48:10 -07008165 mFocusedWindow->setDispatchingTimeout(100ms);
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07008166 mFocusedWindow->setFrame(Rect(50, 50, 100, 100));
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07008167
8168 // Set focused application.
8169 mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, mApplication);
Vishnu Nair47074b82020-08-14 11:54:47 -07008170 mFocusedWindow->setFocusable(true);
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07008171
8172 // Expect one focus window exist in display.
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07008173 mDispatcher->onWindowInfosChanged(
8174 {{*mUnfocusedWindow->getInfo(), *mFocusedWindow->getInfo()}, {}, 0, 0});
Vishnu Nair958da932020-08-21 17:12:37 -07008175 setFocusedWindow(mFocusedWindow);
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07008176 mFocusedWindow->consumeFocusEvent(true);
8177 }
8178
8179 virtual void TearDown() override {
8180 InputDispatcherTest::TearDown();
8181
8182 mUnfocusedWindow.clear();
8183 mFocusedWindow.clear();
8184 }
8185
8186protected:
Chris Yea209fde2020-07-22 13:54:51 -07008187 std::shared_ptr<FakeApplicationHandle> mApplication;
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07008188 sp<FakeWindowHandle> mUnfocusedWindow;
8189 sp<FakeWindowHandle> mFocusedWindow;
8190 static constexpr PointF UNFOCUSED_WINDOW_LOCATION = {20, 20};
8191 static constexpr PointF FOCUSED_WINDOW_LOCATION = {75, 75};
8192 static constexpr PointF LOCATION_OUTSIDE_ALL_WINDOWS = {40, 40};
8193
8194 void tapOnFocusedWindow() { tap(FOCUSED_WINDOW_LOCATION); }
8195
8196 void tapOnUnfocusedWindow() { tap(UNFOCUSED_WINDOW_LOCATION); }
8197
8198private:
8199 void tap(const PointF& location) {
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08008200 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07008201 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07008202 location));
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08008203 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07008204 injectMotionUp(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07008205 location));
8206 }
8207};
8208
8209// If we have 2 windows that are both unresponsive, the one with the shortest timeout
8210// should be ANR'd first.
8211TEST_F(InputDispatcherMultiWindowAnr, TwoWindows_BothUnresponsive) {
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08008212 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakou2899c552023-07-10 18:20:46 -07008213 injectMotionEvent(*mDispatcher,
8214 MotionEventBuilder(AMOTION_EVENT_ACTION_DOWN,
8215 AINPUT_SOURCE_TOUCHSCREEN)
8216 .pointer(PointerBuilder(0, ToolType::FINGER)
8217 .x(FOCUSED_WINDOW_LOCATION.x)
8218 .y(FOCUSED_WINDOW_LOCATION.y))
8219 .build()));
8220 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
8221 injectMotionEvent(*mDispatcher,
8222 MotionEventBuilder(AMOTION_EVENT_ACTION_UP,
8223 AINPUT_SOURCE_TOUCHSCREEN)
8224 .pointer(PointerBuilder(0, ToolType::FINGER)
8225 .x(FOCUSED_WINDOW_LOCATION.x)
8226 .y(FOCUSED_WINDOW_LOCATION.y))
8227 .build()));
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07008228 mFocusedWindow->consumeMotionDown();
Siarhei Vishniakou2899c552023-07-10 18:20:46 -07008229 mFocusedWindow->consumeMotionUp();
Prabir Pradhan7662a8d2023-12-15 01:58:14 +00008230 mUnfocusedWindow->consumeMotionOutside(ADISPLAY_ID_DEFAULT, /*flags=*/0);
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07008231 // We consumed all events, so no ANR
8232 ASSERT_TRUE(mDispatcher->waitForIdle());
8233 mFakePolicy->assertNotifyAnrWasNotCalled();
8234
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08008235 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakou2899c552023-07-10 18:20:46 -07008236 injectMotionEvent(*mDispatcher,
8237 MotionEventBuilder(AMOTION_EVENT_ACTION_DOWN,
8238 AINPUT_SOURCE_TOUCHSCREEN)
8239 .pointer(PointerBuilder(0, ToolType::FINGER)
8240 .x(FOCUSED_WINDOW_LOCATION.x)
8241 .y(FOCUSED_WINDOW_LOCATION.y))
8242 .build()));
Siarhei Vishniakoud3061ab2023-12-18 20:41:08 -08008243 const auto [unfocusedSequenceNum, _] = mUnfocusedWindow->receiveEvent();
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07008244 ASSERT_TRUE(unfocusedSequenceNum);
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07008245
8246 const std::chrono::duration timeout =
8247 mFocusedWindow->getDispatchingTimeout(DISPATCHING_TIMEOUT);
Prabir Pradhanedd96402022-02-15 01:46:16 -08008248 mFakePolicy->assertNotifyWindowUnresponsiveWasCalled(timeout, mFocusedWindow);
Siarhei Vishniakou2899c552023-07-10 18:20:46 -07008249
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07008250 mUnfocusedWindow->finishEvent(*unfocusedSequenceNum);
Siarhei Vishniakou234129c2020-10-22 22:28:12 -05008251 mFocusedWindow->consumeMotionDown();
8252 // This cancel is generated because the connection was unresponsive
8253 mFocusedWindow->consumeMotionCancel();
8254 mFocusedWindow->assertNoEvents();
8255 mUnfocusedWindow->assertNoEvents();
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07008256 ASSERT_TRUE(mDispatcher->waitForIdle());
Prabir Pradhanedd96402022-02-15 01:46:16 -08008257 mFakePolicy->assertNotifyWindowResponsiveWasCalled(mFocusedWindow->getToken(),
8258 mFocusedWindow->getPid());
Siarhei Vishniakou234129c2020-10-22 22:28:12 -05008259 mFakePolicy->assertNotifyAnrWasNotCalled();
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07008260}
8261
8262// If we have 2 windows with identical timeouts that are both unresponsive,
8263// it doesn't matter which order they should have ANR.
8264// But we should receive ANR for both.
8265TEST_F(InputDispatcherMultiWindowAnr, TwoWindows_BothUnresponsiveWithSameTimeout) {
8266 // Set the timeout for unfocused window to match the focused window
Siarhei Vishniakouf83c6932023-07-07 17:48:10 -07008267 mUnfocusedWindow->setDispatchingTimeout(
8268 mFocusedWindow->getDispatchingTimeout(DISPATCHING_TIMEOUT));
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07008269 mDispatcher->onWindowInfosChanged(
8270 {{*mUnfocusedWindow->getInfo(), *mFocusedWindow->getInfo()}, {}, 0, 0});
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07008271
8272 tapOnFocusedWindow();
8273 // we should have ACTION_DOWN/ACTION_UP on focused window and ACTION_OUTSIDE on unfocused window
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07008274 // We don't know which window will ANR first. But both of them should happen eventually.
Siarhei Vishniakouf83c6932023-07-07 17:48:10 -07008275 std::array<sp<IBinder>, 2> anrConnectionTokens = {mFakePolicy->getUnresponsiveWindowToken(
8276 mFocusedWindow->getDispatchingTimeout(
8277 DISPATCHING_TIMEOUT)),
8278 mFakePolicy->getUnresponsiveWindowToken(0ms)};
8279
8280 ASSERT_THAT(anrConnectionTokens,
8281 ::testing::UnorderedElementsAre(testing::Eq(mFocusedWindow->getToken()),
8282 testing::Eq(mUnfocusedWindow->getToken())));
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07008283
8284 ASSERT_TRUE(mDispatcher->waitForIdle());
8285 mFakePolicy->assertNotifyAnrWasNotCalled();
Siarhei Vishniakou234129c2020-10-22 22:28:12 -05008286
8287 mFocusedWindow->consumeMotionDown();
8288 mFocusedWindow->consumeMotionUp();
8289 mUnfocusedWindow->consumeMotionOutside();
8290
Siarhei Vishniakouf83c6932023-07-07 17:48:10 -07008291 std::array<sp<IBinder>, 2> responsiveTokens = {mFakePolicy->getResponsiveWindowToken(),
8292 mFakePolicy->getResponsiveWindowToken()};
Siarhei Vishniakou234129c2020-10-22 22:28:12 -05008293
8294 // Both applications should be marked as responsive, in any order
Siarhei Vishniakouf83c6932023-07-07 17:48:10 -07008295 ASSERT_THAT(responsiveTokens,
8296 ::testing::UnorderedElementsAre(testing::Eq(mFocusedWindow->getToken()),
8297 testing::Eq(mUnfocusedWindow->getToken())));
Siarhei Vishniakou234129c2020-10-22 22:28:12 -05008298 mFakePolicy->assertNotifyAnrWasNotCalled();
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07008299}
8300
8301// If a window is already not responding, the second tap on the same window should be ignored.
8302// We should also log an error to account for the dropped event (not tested here).
8303// At the same time, FLAG_WATCH_OUTSIDE_TOUCH targets should not receive any events.
8304TEST_F(InputDispatcherMultiWindowAnr, DuringAnr_SecondTapIsIgnored) {
8305 tapOnFocusedWindow();
Prabir Pradhan7662a8d2023-12-15 01:58:14 +00008306 mUnfocusedWindow->consumeMotionOutside(ADISPLAY_ID_DEFAULT, /*flags=*/0);
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07008307 // Receive the events, but don't respond
Siarhei Vishniakoud3061ab2023-12-18 20:41:08 -08008308 const auto [downEventSequenceNum, downEvent] = mFocusedWindow->receiveEvent(); // ACTION_DOWN
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07008309 ASSERT_TRUE(downEventSequenceNum);
Siarhei Vishniakoud3061ab2023-12-18 20:41:08 -08008310 const auto [upEventSequenceNum, upEvent] = mFocusedWindow->receiveEvent(); // ACTION_UP
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07008311 ASSERT_TRUE(upEventSequenceNum);
8312 const std::chrono::duration timeout =
8313 mFocusedWindow->getDispatchingTimeout(DISPATCHING_TIMEOUT);
Prabir Pradhanedd96402022-02-15 01:46:16 -08008314 mFakePolicy->assertNotifyWindowUnresponsiveWasCalled(timeout, mFocusedWindow);
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07008315
8316 // Tap once again
8317 // We cannot use "tapOnFocusedWindow" because it asserts the injection result to be success
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08008318 ASSERT_EQ(InputEventInjectionResult::FAILED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07008319 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07008320 FOCUSED_WINDOW_LOCATION));
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08008321 ASSERT_EQ(InputEventInjectionResult::FAILED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07008322 injectMotionUp(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07008323 FOCUSED_WINDOW_LOCATION));
8324 // Unfocused window does not receive ACTION_OUTSIDE because the tapped window is not a
8325 // valid touch target
8326 mUnfocusedWindow->assertNoEvents();
8327
8328 // Consume the first tap
8329 mFocusedWindow->finishEvent(*downEventSequenceNum);
8330 mFocusedWindow->finishEvent(*upEventSequenceNum);
8331 ASSERT_TRUE(mDispatcher->waitForIdle());
8332 // The second tap did not go to the focused window
8333 mFocusedWindow->assertNoEvents();
Siarhei Vishniakou234129c2020-10-22 22:28:12 -05008334 // Since all events are finished, connection should be deemed healthy again
Prabir Pradhanedd96402022-02-15 01:46:16 -08008335 mFakePolicy->assertNotifyWindowResponsiveWasCalled(mFocusedWindow->getToken(),
8336 mFocusedWindow->getPid());
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07008337 mFakePolicy->assertNotifyAnrWasNotCalled();
8338}
8339
8340// If you tap outside of all windows, there will not be ANR
8341TEST_F(InputDispatcherMultiWindowAnr, TapOutsideAllWindows_DoesNotAnr) {
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08008342 ASSERT_EQ(InputEventInjectionResult::FAILED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07008343 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07008344 LOCATION_OUTSIDE_ALL_WINDOWS));
8345 ASSERT_TRUE(mDispatcher->waitForIdle());
8346 mFakePolicy->assertNotifyAnrWasNotCalled();
8347}
8348
8349// Since the focused window is paused, tapping on it should not produce any events
8350TEST_F(InputDispatcherMultiWindowAnr, Window_CanBePaused) {
8351 mFocusedWindow->setPaused(true);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07008352 mDispatcher->onWindowInfosChanged(
8353 {{*mUnfocusedWindow->getInfo(), *mFocusedWindow->getInfo()}, {}, 0, 0});
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07008354
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08008355 ASSERT_EQ(InputEventInjectionResult::FAILED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07008356 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07008357 FOCUSED_WINDOW_LOCATION));
8358
8359 std::this_thread::sleep_for(mFocusedWindow->getDispatchingTimeout(DISPATCHING_TIMEOUT));
8360 ASSERT_TRUE(mDispatcher->waitForIdle());
8361 // Should not ANR because the window is paused, and touches shouldn't go to it
8362 mFakePolicy->assertNotifyAnrWasNotCalled();
8363
8364 mFocusedWindow->assertNoEvents();
8365 mUnfocusedWindow->assertNoEvents();
8366}
8367
8368/**
8369 * If a window is processing a motion event, and then a key event comes in, the key event should
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07008370 * not get delivered to the focused window until the motion is processed.
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07008371 * If a different window becomes focused at this time, the key should go to that window instead.
8372 *
8373 * Warning!!!
8374 * This test depends on the value of android::inputdispatcher::KEY_WAITING_FOR_MOTION_TIMEOUT
8375 * and the injection timeout that we specify when injecting the key.
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07008376 * We must have the injection timeout (100ms) be smaller than
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07008377 * KEY_WAITING_FOR_MOTION_TIMEOUT (currently 500ms).
8378 *
8379 * If that value changes, this test should also change.
8380 */
8381TEST_F(InputDispatcherMultiWindowAnr, PendingKey_GoesToNewlyFocusedWindow) {
8382 // Set a long ANR timeout to prevent it from triggering
8383 mFocusedWindow->setDispatchingTimeout(2s);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07008384 mDispatcher->onWindowInfosChanged(
8385 {{*mFocusedWindow->getInfo(), *mUnfocusedWindow->getInfo()}, {}, 0, 0});
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07008386
8387 tapOnUnfocusedWindow();
Siarhei Vishniakoud3061ab2023-12-18 20:41:08 -08008388 const auto [downSequenceNum, downEvent] = mUnfocusedWindow->receiveEvent();
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07008389 ASSERT_TRUE(downSequenceNum);
Siarhei Vishniakoud3061ab2023-12-18 20:41:08 -08008390 const auto [upSequenceNum, upEvent] = mUnfocusedWindow->receiveEvent();
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07008391 ASSERT_TRUE(upSequenceNum);
8392 // Don't finish the events yet, and send a key
8393 // Injection will succeed because we will eventually give up and send the key to the focused
8394 // window even if motions are still being processed.
8395
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08008396 InputEventInjectionResult result =
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07008397 injectKey(*mDispatcher, AKEY_EVENT_ACTION_DOWN, /*repeatCount=*/0, ADISPLAY_ID_DEFAULT,
8398 InputEventInjectionSync::NONE, /*injectionTimeout=*/100ms);
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08008399 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, result);
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07008400 // Key will not be sent to the window, yet, because the window is still processing events
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07008401 // and the key remains pending, waiting for the touch events to be processed.
8402 // Make sure `assertNoEvents` doesn't take too long. It uses CONSUME_TIMEOUT_NO_EVENT_EXPECTED
8403 // under the hood.
8404 static_assert(CONSUME_TIMEOUT_NO_EVENT_EXPECTED < 100ms);
8405 mFocusedWindow->assertNoEvents();
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07008406
8407 // Switch the focus to the "unfocused" window that we tapped. Expect the key to go there
Vishnu Nair47074b82020-08-14 11:54:47 -07008408 mFocusedWindow->setFocusable(false);
8409 mUnfocusedWindow->setFocusable(true);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07008410 mDispatcher->onWindowInfosChanged(
8411 {{*mFocusedWindow->getInfo(), *mUnfocusedWindow->getInfo()}, {}, 0, 0});
Vishnu Nair958da932020-08-21 17:12:37 -07008412 setFocusedWindow(mUnfocusedWindow);
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07008413
8414 // Focus events should precede the key events
8415 mUnfocusedWindow->consumeFocusEvent(true);
8416 mFocusedWindow->consumeFocusEvent(false);
8417
8418 // Finish the tap events, which should unblock dispatcher
8419 mUnfocusedWindow->finishEvent(*downSequenceNum);
8420 mUnfocusedWindow->finishEvent(*upSequenceNum);
8421
8422 // Now that all queues are cleared and no backlog in the connections, the key event
8423 // can finally go to the newly focused "mUnfocusedWindow".
8424 mUnfocusedWindow->consumeKeyDown(ADISPLAY_ID_DEFAULT);
8425 mFocusedWindow->assertNoEvents();
8426 mUnfocusedWindow->assertNoEvents();
Siarhei Vishniakou234129c2020-10-22 22:28:12 -05008427 mFakePolicy->assertNotifyAnrWasNotCalled();
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07008428}
8429
8430// When the touch stream is split across 2 windows, and one of them does not respond,
8431// then ANR should be raised and the touch should be canceled for the unresponsive window.
8432// The other window should not be affected by that.
8433TEST_F(InputDispatcherMultiWindowAnr, SplitTouch_SingleWindowAnr) {
8434 // Touch Window 1
Prabir Pradhan678438e2023-04-13 19:32:51 +00008435 mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_DOWN,
8436 AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
8437 {FOCUSED_WINDOW_LOCATION}));
Prabir Pradhan7662a8d2023-12-15 01:58:14 +00008438 mUnfocusedWindow->consumeMotionOutside(ADISPLAY_ID_DEFAULT, /*flags=*/0);
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07008439
8440 // Touch Window 2
Prabir Pradhan678438e2023-04-13 19:32:51 +00008441 mDispatcher->notifyMotion(
8442 generateMotionArgs(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
8443 {FOCUSED_WINDOW_LOCATION, UNFOCUSED_WINDOW_LOCATION}));
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07008444
8445 const std::chrono::duration timeout =
8446 mFocusedWindow->getDispatchingTimeout(DISPATCHING_TIMEOUT);
Prabir Pradhanedd96402022-02-15 01:46:16 -08008447 mFakePolicy->assertNotifyWindowUnresponsiveWasCalled(timeout, mFocusedWindow);
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07008448
8449 mUnfocusedWindow->consumeMotionDown();
8450 mFocusedWindow->consumeMotionDown();
8451 // Focused window may or may not receive ACTION_MOVE
8452 // But it should definitely receive ACTION_CANCEL due to the ANR
Siarhei Vishniakoud3061ab2023-12-18 20:41:08 -08008453 const auto [moveOrCancelSequenceNum, event] = mFocusedWindow->receiveEvent();
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07008454 ASSERT_TRUE(moveOrCancelSequenceNum);
8455 mFocusedWindow->finishEvent(*moveOrCancelSequenceNum);
8456 ASSERT_NE(nullptr, event);
Siarhei Vishniakou63b63612023-04-12 11:00:23 -07008457 ASSERT_EQ(event->getType(), InputEventType::MOTION);
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07008458 MotionEvent& motionEvent = static_cast<MotionEvent&>(*event);
8459 if (motionEvent.getAction() == AMOTION_EVENT_ACTION_MOVE) {
8460 mFocusedWindow->consumeMotionCancel();
8461 } else {
8462 ASSERT_EQ(AMOTION_EVENT_ACTION_CANCEL, motionEvent.getAction());
8463 }
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07008464 ASSERT_TRUE(mDispatcher->waitForIdle());
Prabir Pradhanedd96402022-02-15 01:46:16 -08008465 mFakePolicy->assertNotifyWindowResponsiveWasCalled(mFocusedWindow->getToken(),
8466 mFocusedWindow->getPid());
Siarhei Vishniakou234129c2020-10-22 22:28:12 -05008467
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07008468 mUnfocusedWindow->assertNoEvents();
8469 mFocusedWindow->assertNoEvents();
Siarhei Vishniakou234129c2020-10-22 22:28:12 -05008470 mFakePolicy->assertNotifyAnrWasNotCalled();
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07008471}
8472
Siarhei Vishniakouf56b2692020-09-08 19:43:33 -05008473/**
8474 * If we have no focused window, and a key comes in, we start the ANR timer.
8475 * The focused application should add a focused window before the timer runs out to prevent ANR.
8476 *
8477 * If the user touches another application during this time, the key should be dropped.
8478 * Next, if a new focused window comes in, without toggling the focused application,
8479 * then no ANR should occur.
8480 *
8481 * Normally, we would expect the new focused window to be accompanied by 'setFocusedApplication',
8482 * but in some cases the policy may not update the focused application.
8483 */
8484TEST_F(InputDispatcherMultiWindowAnr, FocusedWindowWithoutSetFocusedApplication_NoAnr) {
8485 std::shared_ptr<FakeApplicationHandle> focusedApplication =
8486 std::make_shared<FakeApplicationHandle>();
Siarhei Vishniakouc033dfb2023-10-03 10:45:16 -07008487 focusedApplication->setDispatchingTimeout(300ms);
Siarhei Vishniakouf56b2692020-09-08 19:43:33 -05008488 mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, focusedApplication);
8489 // The application that owns 'mFocusedWindow' and 'mUnfocusedWindow' is not focused.
8490 mFocusedWindow->setFocusable(false);
8491
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07008492 mDispatcher->onWindowInfosChanged(
8493 {{*mFocusedWindow->getInfo(), *mUnfocusedWindow->getInfo()}, {}, 0, 0});
Siarhei Vishniakouf56b2692020-09-08 19:43:33 -05008494 mFocusedWindow->consumeFocusEvent(false);
8495
8496 // Send a key. The ANR timer should start because there is no focused window.
8497 // 'focusedApplication' will get blamed if this timer completes.
8498 // Key will not be sent anywhere because we have no focused window. It will remain pending.
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08008499 InputEventInjectionResult result =
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07008500 injectKey(*mDispatcher, AKEY_EVENT_ACTION_DOWN, /*repeatCount=*/0, ADISPLAY_ID_DEFAULT,
8501 InputEventInjectionSync::NONE, /*injectionTimeout=*/100ms,
Harry Cutts33476232023-01-30 19:57:29 +00008502 /*allowKeyRepeat=*/false);
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08008503 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, result);
Siarhei Vishniakouf56b2692020-09-08 19:43:33 -05008504
8505 // Wait until dispatcher starts the "no focused window" timer. If we don't wait here,
8506 // then the injected touches won't cause the focused event to get dropped.
8507 // The dispatcher only checks for whether the queue should be pruned upon queueing.
8508 // If we inject the touch right away and the ANR timer hasn't started, the touch event would
8509 // simply be added to the queue without 'shouldPruneInboundQueueLocked' returning 'true'.
8510 // For this test, it means that the key would get delivered to the window once it becomes
8511 // focused.
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07008512 std::this_thread::sleep_for(100ms);
Siarhei Vishniakouf56b2692020-09-08 19:43:33 -05008513
8514 // Touch unfocused window. This should force the pending key to get dropped.
Prabir Pradhan678438e2023-04-13 19:32:51 +00008515 mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_DOWN,
8516 AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
8517 {UNFOCUSED_WINDOW_LOCATION}));
Siarhei Vishniakouf56b2692020-09-08 19:43:33 -05008518
8519 // We do not consume the motion right away, because that would require dispatcher to first
8520 // process (== drop) the key event, and by that time, ANR will be raised.
8521 // Set the focused window first.
8522 mFocusedWindow->setFocusable(true);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07008523 mDispatcher->onWindowInfosChanged(
8524 {{*mFocusedWindow->getInfo(), *mUnfocusedWindow->getInfo()}, {}, 0, 0});
Siarhei Vishniakouf56b2692020-09-08 19:43:33 -05008525 setFocusedWindow(mFocusedWindow);
8526 mFocusedWindow->consumeFocusEvent(true);
8527 // We do not call "setFocusedApplication" here, even though the newly focused window belongs
8528 // to another application. This could be a bug / behaviour in the policy.
8529
8530 mUnfocusedWindow->consumeMotionDown();
8531
8532 ASSERT_TRUE(mDispatcher->waitForIdle());
8533 // Should not ANR because we actually have a focused window. It was just added too slowly.
8534 ASSERT_NO_FATAL_FAILURE(mFakePolicy->assertNotifyAnrWasNotCalled());
8535}
8536
Siarhei Vishniakou99e407b2023-12-26 18:09:32 -08008537/**
8538 * If we are pruning input queue, we should never drop pointer events. Otherwise, we risk having
8539 * an inconsistent event stream inside the dispatcher. In this test, we make sure that the
8540 * dispatcher doesn't prune pointer events incorrectly.
8541 *
8542 * This test reproduces a crash in InputDispatcher.
8543 * To reproduce the crash, we need to simulate the conditions for "pruning input queue" to occur.
8544 *
8545 * Keep the currently focused application (mApplication), and have no focused window.
8546 * We set up two additional windows:
8547 * 1) The navigation bar window. This simulates the system "NavigationBar", which is used in the
8548 * 3-button navigation mode. This window injects a BACK button when it's touched. 2) The application
8549 * window. This window is not focusable, but is touchable.
8550 *
8551 * We first touch the navigation bar, which causes it to inject a key. Since there's no focused
8552 * window, the dispatcher doesn't process this key, and all other events inside dispatcher are now
8553 * blocked. The dispatcher is waiting for 'mApplication' to add a focused window.
8554 *
8555 * Now, we touch "Another window". This window is owned by a different application than
8556 * 'mApplication'. This causes the dispatcher to stop waiting for 'mApplication' to add a focused
8557 * window. Now, the "pruning input queue" behaviour should kick in, and the dispatcher should start
8558 * dropping the events from its queue. Ensure that no crash occurs.
8559 *
8560 * In this test, we are setting long timeouts to prevent ANRs and events dropped due to being stale.
8561 * This does not affect the test running time.
8562 */
8563TEST_F(InputDispatcherMultiWindowAnr, PruningInputQueueShouldNotDropPointerEvents) {
8564 std::shared_ptr<FakeApplicationHandle> systemUiApplication =
8565 std::make_shared<FakeApplicationHandle>();
8566 systemUiApplication->setDispatchingTimeout(3000ms);
8567 mFakePolicy->setStaleEventTimeout(3000ms);
8568 sp<FakeWindowHandle> navigationBar =
8569 sp<FakeWindowHandle>::make(systemUiApplication, mDispatcher, "NavigationBar",
8570 ADISPLAY_ID_DEFAULT);
8571 navigationBar->setFocusable(false);
8572 navigationBar->setWatchOutsideTouch(true);
8573 navigationBar->setFrame(Rect(0, 0, 100, 100));
8574
8575 mApplication->setDispatchingTimeout(3000ms);
8576 // 'mApplication' is already focused, but we call it again here to make it explicit.
8577 mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, mApplication);
8578
8579 std::shared_ptr<FakeApplicationHandle> anotherApplication =
8580 std::make_shared<FakeApplicationHandle>();
8581 sp<FakeWindowHandle> appWindow =
8582 sp<FakeWindowHandle>::make(anotherApplication, mDispatcher, "Another window",
8583 ADISPLAY_ID_DEFAULT);
8584 appWindow->setFocusable(false);
8585 appWindow->setFrame(Rect(100, 100, 200, 200));
8586
8587 mDispatcher->onWindowInfosChanged(
8588 {{*navigationBar->getInfo(), *appWindow->getInfo()}, {}, 0, 0});
8589 // 'mFocusedWindow' is no longer in the dispatcher window list, and therefore loses focus
8590 mFocusedWindow->consumeFocusEvent(false);
8591
8592 // Touch down the navigation bar. It consumes the touch and injects a key into the dispatcher
8593 // in response.
8594 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
8595 .pointer(PointerBuilder(0, ToolType::FINGER).x(50).y(50))
8596 .build());
8597 navigationBar->consumeMotionEvent(WithMotionAction(ACTION_DOWN));
8598
8599 // Key will not be sent anywhere because we have no focused window. It will remain pending.
8600 // Pretend we are injecting KEYCODE_BACK, but it doesn't actually matter what key it is.
8601 InputEventInjectionResult result =
8602 injectKey(*mDispatcher, AKEY_EVENT_ACTION_DOWN, /*repeatCount=*/0, ADISPLAY_ID_DEFAULT,
8603 InputEventInjectionSync::NONE, /*injectionTimeout=*/100ms,
8604 /*allowKeyRepeat=*/false);
8605 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, result);
8606
8607 // Finish the gesture - lift up finger and inject ACTION_UP key event
8608 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN)
8609 .pointer(PointerBuilder(0, ToolType::FINGER).x(50).y(50))
8610 .build());
8611 result = injectKey(*mDispatcher, AKEY_EVENT_ACTION_UP, /*repeatCount=*/0, ADISPLAY_ID_DEFAULT,
8612 InputEventInjectionSync::NONE, /*injectionTimeout=*/100ms,
8613 /*allowKeyRepeat=*/false);
8614 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, result);
8615 // The key that was injected is blocking the dispatcher, so the navigation bar shouldn't be
8616 // getting any events yet.
8617 navigationBar->assertNoEvents();
8618
8619 // Now touch "Another window". This touch is going to a different application than the one we
8620 // are waiting for (which is 'mApplication').
8621 // This should cause the dispatcher to drop the pending focus-dispatched events (like the key
8622 // trying to be injected) and to continue processing the rest of the events in the original
8623 // order.
8624 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
8625 .pointer(PointerBuilder(0, ToolType::FINGER).x(150).y(150))
8626 .build());
8627 navigationBar->consumeMotionEvent(WithMotionAction(ACTION_UP));
8628 navigationBar->consumeMotionEvent(WithMotionAction(ACTION_OUTSIDE));
8629 appWindow->consumeMotionEvent(WithMotionAction(ACTION_DOWN));
8630
8631 appWindow->assertNoEvents();
8632 navigationBar->assertNoEvents();
8633}
8634
Siarhei Vishniakoua2862a02020-07-20 16:36:46 -05008635// These tests ensure we cannot send touch events to a window that's positioned behind a window
8636// that has feature NO_INPUT_CHANNEL.
8637// Layout:
8638// Top (closest to user)
8639// mNoInputWindow (above all windows)
8640// mBottomWindow
8641// Bottom (furthest from user)
8642class InputDispatcherMultiWindowOcclusionTests : public InputDispatcherTest {
8643 virtual void SetUp() override {
8644 InputDispatcherTest::SetUp();
8645
8646 mApplication = std::make_shared<FakeApplicationHandle>();
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07008647 mNoInputWindow =
8648 sp<FakeWindowHandle>::make(mApplication, mDispatcher,
8649 "Window without input channel", ADISPLAY_ID_DEFAULT,
Prabir Pradhane7cc69c2024-01-05 21:35:28 +00008650 /*createInputChannel=*/false);
Prabir Pradhan51e7db02022-02-07 06:02:57 -08008651 mNoInputWindow->setNoInputChannel(true);
Siarhei Vishniakoua2862a02020-07-20 16:36:46 -05008652 mNoInputWindow->setFrame(Rect(0, 0, 100, 100));
8653 // It's perfectly valid for this window to not have an associated input channel
8654
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07008655 mBottomWindow = sp<FakeWindowHandle>::make(mApplication, mDispatcher, "Bottom window",
8656 ADISPLAY_ID_DEFAULT);
Siarhei Vishniakoua2862a02020-07-20 16:36:46 -05008657 mBottomWindow->setFrame(Rect(0, 0, 100, 100));
8658
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07008659 mDispatcher->onWindowInfosChanged(
8660 {{*mNoInputWindow->getInfo(), *mBottomWindow->getInfo()}, {}, 0, 0});
Siarhei Vishniakoua2862a02020-07-20 16:36:46 -05008661 }
8662
8663protected:
8664 std::shared_ptr<FakeApplicationHandle> mApplication;
8665 sp<FakeWindowHandle> mNoInputWindow;
8666 sp<FakeWindowHandle> mBottomWindow;
8667};
8668
8669TEST_F(InputDispatcherMultiWindowOcclusionTests, NoInputChannelFeature_DropsTouches) {
8670 PointF touchedPoint = {10, 10};
8671
Prabir Pradhan678438e2023-04-13 19:32:51 +00008672 mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_DOWN,
8673 AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
8674 {touchedPoint}));
Siarhei Vishniakoua2862a02020-07-20 16:36:46 -05008675
8676 mNoInputWindow->assertNoEvents();
8677 // Even though the window 'mNoInputWindow' positioned above 'mBottomWindow' does not have
8678 // an input channel, it is not marked as FLAG_NOT_TOUCHABLE,
8679 // and therefore should prevent mBottomWindow from receiving touches
8680 mBottomWindow->assertNoEvents();
8681}
8682
8683/**
8684 * If a window has feature NO_INPUT_CHANNEL, and somehow (by mistake) still has an input channel,
8685 * ensure that this window does not receive any touches, and blocks touches to windows underneath.
8686 */
8687TEST_F(InputDispatcherMultiWindowOcclusionTests,
8688 NoInputChannelFeature_DropsTouchesWithValidChannel) {
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07008689 mNoInputWindow = sp<FakeWindowHandle>::make(mApplication, mDispatcher,
8690 "Window with input channel and NO_INPUT_CHANNEL",
8691 ADISPLAY_ID_DEFAULT);
Siarhei Vishniakoua2862a02020-07-20 16:36:46 -05008692
Prabir Pradhan51e7db02022-02-07 06:02:57 -08008693 mNoInputWindow->setNoInputChannel(true);
Siarhei Vishniakoua2862a02020-07-20 16:36:46 -05008694 mNoInputWindow->setFrame(Rect(0, 0, 100, 100));
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07008695 mDispatcher->onWindowInfosChanged(
8696 {{*mNoInputWindow->getInfo(), *mBottomWindow->getInfo()}, {}, 0, 0});
Siarhei Vishniakoua2862a02020-07-20 16:36:46 -05008697
8698 PointF touchedPoint = {10, 10};
8699
Prabir Pradhan678438e2023-04-13 19:32:51 +00008700 mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_DOWN,
8701 AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
8702 {touchedPoint}));
Siarhei Vishniakoua2862a02020-07-20 16:36:46 -05008703
8704 mNoInputWindow->assertNoEvents();
8705 mBottomWindow->assertNoEvents();
8706}
8707
Vishnu Nair958da932020-08-21 17:12:37 -07008708class InputDispatcherMirrorWindowFocusTests : public InputDispatcherTest {
8709protected:
8710 std::shared_ptr<FakeApplicationHandle> mApp;
8711 sp<FakeWindowHandle> mWindow;
8712 sp<FakeWindowHandle> mMirror;
8713
8714 virtual void SetUp() override {
8715 InputDispatcherTest::SetUp();
8716 mApp = std::make_shared<FakeApplicationHandle>();
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07008717 mWindow = sp<FakeWindowHandle>::make(mApp, mDispatcher, "TestWindow", ADISPLAY_ID_DEFAULT);
Prabir Pradhane7cc69c2024-01-05 21:35:28 +00008718 mMirror = mWindow->clone(ADISPLAY_ID_DEFAULT);
Vishnu Nair958da932020-08-21 17:12:37 -07008719 mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, mApp);
8720 mWindow->setFocusable(true);
8721 mMirror->setFocusable(true);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07008722 mDispatcher->onWindowInfosChanged({{*mWindow->getInfo(), *mMirror->getInfo()}, {}, 0, 0});
Vishnu Nair958da932020-08-21 17:12:37 -07008723 }
8724};
8725
8726TEST_F(InputDispatcherMirrorWindowFocusTests, CanGetFocus) {
8727 // Request focus on a mirrored window
8728 setFocusedWindow(mMirror);
8729
8730 // window gets focused
8731 mWindow->consumeFocusEvent(true);
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07008732 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectKeyDown(*mDispatcher))
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08008733 << "Inject key event should return InputEventInjectionResult::SUCCEEDED";
Vishnu Nair958da932020-08-21 17:12:37 -07008734 mWindow->consumeKeyDown(ADISPLAY_ID_NONE);
8735}
8736
8737// A focused & mirrored window remains focused only if the window and its mirror are both
8738// focusable.
8739TEST_F(InputDispatcherMirrorWindowFocusTests, FocusedIfAllWindowsFocusable) {
8740 setFocusedWindow(mMirror);
8741
Prabir Pradhanbb3f1c02024-01-04 20:17:14 +00008742 // window gets focused because it is above the mirror
Vishnu Nair958da932020-08-21 17:12:37 -07008743 mWindow->consumeFocusEvent(true);
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07008744 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectKeyDown(*mDispatcher))
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08008745 << "Inject key event should return InputEventInjectionResult::SUCCEEDED";
Vishnu Nair958da932020-08-21 17:12:37 -07008746 mWindow->consumeKeyDown(ADISPLAY_ID_NONE);
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07008747 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectKeyUp(*mDispatcher))
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08008748 << "Inject key event should return InputEventInjectionResult::SUCCEEDED";
Vishnu Nair958da932020-08-21 17:12:37 -07008749 mWindow->consumeKeyUp(ADISPLAY_ID_NONE);
8750
8751 mMirror->setFocusable(false);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07008752 mDispatcher->onWindowInfosChanged({{*mWindow->getInfo(), *mMirror->getInfo()}, {}, 0, 0});
Vishnu Nair958da932020-08-21 17:12:37 -07008753
8754 // window loses focus since one of the windows associated with the token in not focusable
8755 mWindow->consumeFocusEvent(false);
8756
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07008757 ASSERT_EQ(InputEventInjectionResult::TIMED_OUT, injectKeyDown(*mDispatcher))
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08008758 << "Inject key event should return InputEventInjectionResult::TIMED_OUT";
Vishnu Nair958da932020-08-21 17:12:37 -07008759 mWindow->assertNoEvents();
8760}
8761
8762// A focused & mirrored window remains focused until the window and its mirror both become
8763// invisible.
8764TEST_F(InputDispatcherMirrorWindowFocusTests, FocusedIfAnyWindowVisible) {
8765 setFocusedWindow(mMirror);
8766
8767 // window gets focused
8768 mWindow->consumeFocusEvent(true);
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07008769 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectKeyDown(*mDispatcher))
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08008770 << "Inject key event should return InputEventInjectionResult::SUCCEEDED";
Vishnu Nair958da932020-08-21 17:12:37 -07008771 mWindow->consumeKeyDown(ADISPLAY_ID_NONE);
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07008772 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectKeyUp(*mDispatcher))
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08008773 << "Inject key event should return InputEventInjectionResult::SUCCEEDED";
Vishnu Nair958da932020-08-21 17:12:37 -07008774 mWindow->consumeKeyUp(ADISPLAY_ID_NONE);
8775
8776 mMirror->setVisible(false);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07008777 mDispatcher->onWindowInfosChanged({{*mWindow->getInfo(), *mMirror->getInfo()}, {}, 0, 0});
Vishnu Nair958da932020-08-21 17:12:37 -07008778
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07008779 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectKeyDown(*mDispatcher))
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08008780 << "Inject key event should return InputEventInjectionResult::SUCCEEDED";
Vishnu Nair958da932020-08-21 17:12:37 -07008781 mWindow->consumeKeyDown(ADISPLAY_ID_NONE);
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07008782 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectKeyUp(*mDispatcher))
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08008783 << "Inject key event should return InputEventInjectionResult::SUCCEEDED";
Vishnu Nair958da932020-08-21 17:12:37 -07008784 mWindow->consumeKeyUp(ADISPLAY_ID_NONE);
8785
8786 mWindow->setVisible(false);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07008787 mDispatcher->onWindowInfosChanged({{*mWindow->getInfo(), *mMirror->getInfo()}, {}, 0, 0});
Vishnu Nair958da932020-08-21 17:12:37 -07008788
8789 // window loses focus only after all windows associated with the token become invisible.
8790 mWindow->consumeFocusEvent(false);
8791
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07008792 ASSERT_EQ(InputEventInjectionResult::TIMED_OUT, injectKeyDown(*mDispatcher))
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08008793 << "Inject key event should return InputEventInjectionResult::TIMED_OUT";
Vishnu Nair958da932020-08-21 17:12:37 -07008794 mWindow->assertNoEvents();
8795}
8796
8797// A focused & mirrored window remains focused until both windows are removed.
8798TEST_F(InputDispatcherMirrorWindowFocusTests, FocusedWhileWindowsAlive) {
8799 setFocusedWindow(mMirror);
8800
8801 // window gets focused
8802 mWindow->consumeFocusEvent(true);
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07008803 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectKeyDown(*mDispatcher))
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08008804 << "Inject key event should return InputEventInjectionResult::SUCCEEDED";
Vishnu Nair958da932020-08-21 17:12:37 -07008805 mWindow->consumeKeyDown(ADISPLAY_ID_NONE);
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07008806 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectKeyUp(*mDispatcher))
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08008807 << "Inject key event should return InputEventInjectionResult::SUCCEEDED";
Vishnu Nair958da932020-08-21 17:12:37 -07008808 mWindow->consumeKeyUp(ADISPLAY_ID_NONE);
8809
8810 // single window is removed but the window token remains focused
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07008811 mDispatcher->onWindowInfosChanged({{*mMirror->getInfo()}, {}, 0, 0});
Vishnu Nair958da932020-08-21 17:12:37 -07008812
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07008813 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectKeyDown(*mDispatcher))
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08008814 << "Inject key event should return InputEventInjectionResult::SUCCEEDED";
Prabir Pradhanbb3f1c02024-01-04 20:17:14 +00008815 mMirror->consumeKeyDown(ADISPLAY_ID_NONE);
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07008816 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectKeyUp(*mDispatcher))
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08008817 << "Inject key event should return InputEventInjectionResult::SUCCEEDED";
Prabir Pradhanbb3f1c02024-01-04 20:17:14 +00008818 mMirror->consumeKeyUp(ADISPLAY_ID_NONE);
Vishnu Nair958da932020-08-21 17:12:37 -07008819
8820 // Both windows are removed
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07008821 mDispatcher->onWindowInfosChanged({{}, {}, 0, 0});
Vishnu Nair958da932020-08-21 17:12:37 -07008822 mWindow->consumeFocusEvent(false);
8823
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07008824 ASSERT_EQ(InputEventInjectionResult::TIMED_OUT, injectKeyDown(*mDispatcher))
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08008825 << "Inject key event should return InputEventInjectionResult::TIMED_OUT";
Vishnu Nair958da932020-08-21 17:12:37 -07008826 mWindow->assertNoEvents();
8827}
8828
8829// Focus request can be pending until one window becomes visible.
8830TEST_F(InputDispatcherMirrorWindowFocusTests, DeferFocusWhenInvisible) {
8831 // Request focus on an invisible mirror.
8832 mWindow->setVisible(false);
8833 mMirror->setVisible(false);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07008834 mDispatcher->onWindowInfosChanged({{*mWindow->getInfo(), *mMirror->getInfo()}, {}, 0, 0});
Vishnu Nair958da932020-08-21 17:12:37 -07008835 setFocusedWindow(mMirror);
8836
8837 // Injected key goes to pending queue.
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08008838 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07008839 injectKey(*mDispatcher, AKEY_EVENT_ACTION_DOWN, /*repeatCount=*/0,
8840 ADISPLAY_ID_DEFAULT, InputEventInjectionSync::NONE));
Vishnu Nair958da932020-08-21 17:12:37 -07008841
8842 mMirror->setVisible(true);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07008843 mDispatcher->onWindowInfosChanged({{*mWindow->getInfo(), *mMirror->getInfo()}, {}, 0, 0});
Vishnu Nair958da932020-08-21 17:12:37 -07008844
8845 // window gets focused
8846 mWindow->consumeFocusEvent(true);
8847 // window gets the pending key event
8848 mWindow->consumeKeyDown(ADISPLAY_ID_DEFAULT);
8849}
Prabir Pradhan99987712020-11-10 18:43:05 -08008850
8851class InputDispatcherPointerCaptureTests : public InputDispatcherTest {
8852protected:
8853 std::shared_ptr<FakeApplicationHandle> mApp;
8854 sp<FakeWindowHandle> mWindow;
8855 sp<FakeWindowHandle> mSecondWindow;
8856
8857 void SetUp() override {
8858 InputDispatcherTest::SetUp();
8859 mApp = std::make_shared<FakeApplicationHandle>();
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07008860 mWindow = sp<FakeWindowHandle>::make(mApp, mDispatcher, "TestWindow", ADISPLAY_ID_DEFAULT);
Prabir Pradhan99987712020-11-10 18:43:05 -08008861 mWindow->setFocusable(true);
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07008862 mSecondWindow =
8863 sp<FakeWindowHandle>::make(mApp, mDispatcher, "TestWindow2", ADISPLAY_ID_DEFAULT);
Prabir Pradhan99987712020-11-10 18:43:05 -08008864 mSecondWindow->setFocusable(true);
8865
8866 mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, mApp);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07008867 mDispatcher->onWindowInfosChanged(
8868 {{*mWindow->getInfo(), *mSecondWindow->getInfo()}, {}, 0, 0});
Prabir Pradhan99987712020-11-10 18:43:05 -08008869
8870 setFocusedWindow(mWindow);
8871 mWindow->consumeFocusEvent(true);
8872 }
8873
Prabir Pradhan5cc1a692021-08-06 14:01:18 +00008874 void notifyPointerCaptureChanged(const PointerCaptureRequest& request) {
Prabir Pradhan678438e2023-04-13 19:32:51 +00008875 mDispatcher->notifyPointerCaptureChanged(generatePointerCaptureChangedArgs(request));
Prabir Pradhan99987712020-11-10 18:43:05 -08008876 }
8877
Prabir Pradhan5cc1a692021-08-06 14:01:18 +00008878 PointerCaptureRequest requestAndVerifyPointerCapture(const sp<FakeWindowHandle>& window,
8879 bool enabled) {
Prabir Pradhan99987712020-11-10 18:43:05 -08008880 mDispatcher->requestPointerCapture(window->getToken(), enabled);
Hiroki Sato25040232024-02-22 17:21:22 +09008881 auto request = mFakePolicy->assertSetPointerCaptureCalled(window, enabled);
Prabir Pradhan5cc1a692021-08-06 14:01:18 +00008882 notifyPointerCaptureChanged(request);
Prabir Pradhan99987712020-11-10 18:43:05 -08008883 window->consumeCaptureEvent(enabled);
Prabir Pradhan5cc1a692021-08-06 14:01:18 +00008884 return request;
Prabir Pradhan99987712020-11-10 18:43:05 -08008885 }
8886};
8887
8888TEST_F(InputDispatcherPointerCaptureTests, EnablePointerCaptureWhenFocused) {
8889 // Ensure that capture cannot be obtained for unfocused windows.
8890 mDispatcher->requestPointerCapture(mSecondWindow->getToken(), true);
8891 mFakePolicy->assertSetPointerCaptureNotCalled();
8892 mSecondWindow->assertNoEvents();
8893
8894 // Ensure that capture can be enabled from the focus window.
8895 requestAndVerifyPointerCapture(mWindow, true);
8896
8897 // Ensure that capture cannot be disabled from a window that does not have capture.
8898 mDispatcher->requestPointerCapture(mSecondWindow->getToken(), false);
8899 mFakePolicy->assertSetPointerCaptureNotCalled();
8900
8901 // Ensure that capture can be disabled from the window with capture.
8902 requestAndVerifyPointerCapture(mWindow, false);
8903}
8904
8905TEST_F(InputDispatcherPointerCaptureTests, DisablesPointerCaptureAfterWindowLosesFocus) {
Prabir Pradhan5cc1a692021-08-06 14:01:18 +00008906 auto request = requestAndVerifyPointerCapture(mWindow, true);
Prabir Pradhan99987712020-11-10 18:43:05 -08008907
8908 setFocusedWindow(mSecondWindow);
8909
8910 // Ensure that the capture disabled event was sent first.
8911 mWindow->consumeCaptureEvent(false);
8912 mWindow->consumeFocusEvent(false);
8913 mSecondWindow->consumeFocusEvent(true);
Hiroki Sato25040232024-02-22 17:21:22 +09008914 mFakePolicy->assertSetPointerCaptureCalled(mWindow, false);
Prabir Pradhan99987712020-11-10 18:43:05 -08008915
8916 // Ensure that additional state changes from InputReader are not sent to the window.
Prabir Pradhan5cc1a692021-08-06 14:01:18 +00008917 notifyPointerCaptureChanged({});
8918 notifyPointerCaptureChanged(request);
8919 notifyPointerCaptureChanged({});
Prabir Pradhan99987712020-11-10 18:43:05 -08008920 mWindow->assertNoEvents();
8921 mSecondWindow->assertNoEvents();
8922 mFakePolicy->assertSetPointerCaptureNotCalled();
8923}
8924
8925TEST_F(InputDispatcherPointerCaptureTests, UnexpectedStateChangeDisablesPointerCapture) {
Prabir Pradhan5cc1a692021-08-06 14:01:18 +00008926 auto request = requestAndVerifyPointerCapture(mWindow, true);
Prabir Pradhan99987712020-11-10 18:43:05 -08008927
8928 // InputReader unexpectedly disables and enables pointer capture.
Prabir Pradhan5cc1a692021-08-06 14:01:18 +00008929 notifyPointerCaptureChanged({});
8930 notifyPointerCaptureChanged(request);
Prabir Pradhan99987712020-11-10 18:43:05 -08008931
8932 // Ensure that Pointer Capture is disabled.
Hiroki Sato25040232024-02-22 17:21:22 +09008933 mFakePolicy->assertSetPointerCaptureCalled(mWindow, false);
Prabir Pradhan99987712020-11-10 18:43:05 -08008934 mWindow->consumeCaptureEvent(false);
8935 mWindow->assertNoEvents();
8936}
8937
Prabir Pradhan167e6d92021-02-04 16:18:17 -08008938TEST_F(InputDispatcherPointerCaptureTests, OutOfOrderRequests) {
8939 requestAndVerifyPointerCapture(mWindow, true);
8940
8941 // The first window loses focus.
8942 setFocusedWindow(mSecondWindow);
Hiroki Sato25040232024-02-22 17:21:22 +09008943 mFakePolicy->assertSetPointerCaptureCalled(mWindow, false);
Prabir Pradhan167e6d92021-02-04 16:18:17 -08008944 mWindow->consumeCaptureEvent(false);
8945
8946 // Request Pointer Capture from the second window before the notification from InputReader
8947 // arrives.
8948 mDispatcher->requestPointerCapture(mSecondWindow->getToken(), true);
Hiroki Sato25040232024-02-22 17:21:22 +09008949 auto request = mFakePolicy->assertSetPointerCaptureCalled(mSecondWindow, true);
Prabir Pradhan167e6d92021-02-04 16:18:17 -08008950
8951 // InputReader notifies Pointer Capture was disabled (because of the focus change).
Prabir Pradhan5cc1a692021-08-06 14:01:18 +00008952 notifyPointerCaptureChanged({});
Prabir Pradhan167e6d92021-02-04 16:18:17 -08008953
8954 // InputReader notifies Pointer Capture was enabled (because of mSecondWindow's request).
Prabir Pradhan5cc1a692021-08-06 14:01:18 +00008955 notifyPointerCaptureChanged(request);
Prabir Pradhan167e6d92021-02-04 16:18:17 -08008956
8957 mSecondWindow->consumeFocusEvent(true);
8958 mSecondWindow->consumeCaptureEvent(true);
8959}
8960
Prabir Pradhan5cc1a692021-08-06 14:01:18 +00008961TEST_F(InputDispatcherPointerCaptureTests, EnableRequestFollowsSequenceNumbers) {
8962 // App repeatedly enables and disables capture.
8963 mDispatcher->requestPointerCapture(mWindow->getToken(), true);
Hiroki Sato25040232024-02-22 17:21:22 +09008964 auto firstRequest = mFakePolicy->assertSetPointerCaptureCalled(mWindow, true);
Prabir Pradhan5cc1a692021-08-06 14:01:18 +00008965 mDispatcher->requestPointerCapture(mWindow->getToken(), false);
Hiroki Sato25040232024-02-22 17:21:22 +09008966 mFakePolicy->assertSetPointerCaptureCalled(mWindow, false);
Prabir Pradhan5cc1a692021-08-06 14:01:18 +00008967 mDispatcher->requestPointerCapture(mWindow->getToken(), true);
Hiroki Sato25040232024-02-22 17:21:22 +09008968 auto secondRequest = mFakePolicy->assertSetPointerCaptureCalled(mWindow, true);
Prabir Pradhan5cc1a692021-08-06 14:01:18 +00008969
8970 // InputReader notifies that PointerCapture has been enabled for the first request. Since the
8971 // first request is now stale, this should do nothing.
8972 notifyPointerCaptureChanged(firstRequest);
8973 mWindow->assertNoEvents();
8974
8975 // InputReader notifies that the second request was enabled.
8976 notifyPointerCaptureChanged(secondRequest);
8977 mWindow->consumeCaptureEvent(true);
8978}
8979
Prabir Pradhan7092e262022-05-03 16:51:09 +00008980TEST_F(InputDispatcherPointerCaptureTests, RapidToggleRequests) {
8981 requestAndVerifyPointerCapture(mWindow, true);
8982
8983 // App toggles pointer capture off and on.
8984 mDispatcher->requestPointerCapture(mWindow->getToken(), false);
Hiroki Sato25040232024-02-22 17:21:22 +09008985 mFakePolicy->assertSetPointerCaptureCalled(mWindow, false);
Prabir Pradhan7092e262022-05-03 16:51:09 +00008986
8987 mDispatcher->requestPointerCapture(mWindow->getToken(), true);
Hiroki Sato25040232024-02-22 17:21:22 +09008988 auto enableRequest = mFakePolicy->assertSetPointerCaptureCalled(mWindow, true);
Prabir Pradhan7092e262022-05-03 16:51:09 +00008989
8990 // InputReader notifies that the latest "enable" request was processed, while skipping over the
8991 // preceding "disable" request.
8992 notifyPointerCaptureChanged(enableRequest);
8993
8994 // Since pointer capture was never disabled during the rapid toggle, the window does not receive
8995 // any notifications.
8996 mWindow->assertNoEvents();
8997}
8998
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -07008999/**
9000 * One window. Hover mouse in the window, and then start capture. Make sure that the relative
9001 * mouse movements don't affect the previous mouse hovering state.
9002 * When pointer capture is enabled, the incoming events are always ACTION_MOVE (there are no
9003 * HOVER_MOVE events).
9004 */
9005TEST_F(InputDispatcherPointerCaptureTests, MouseHoverAndPointerCapture) {
9006 // Mouse hover on the window
9007 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_ENTER, AINPUT_SOURCE_MOUSE)
9008 .pointer(PointerBuilder(0, ToolType::MOUSE).x(100).y(110))
9009 .build());
9010 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_MOVE, AINPUT_SOURCE_MOUSE)
9011 .pointer(PointerBuilder(0, ToolType::MOUSE).x(100).y(110))
9012 .build());
9013
9014 mWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_HOVER_ENTER)));
9015 mWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_HOVER_MOVE)));
9016
9017 // Start pointer capture
9018 requestAndVerifyPointerCapture(mWindow, true);
9019
9020 // Send some relative mouse movements and receive them in the window.
9021 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_MOUSE_RELATIVE)
9022 .pointer(PointerBuilder(0, ToolType::MOUSE).x(10).y(11))
9023 .build());
9024 mWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_MOVE), WithCoords(10, 11),
9025 WithSource(AINPUT_SOURCE_MOUSE_RELATIVE)));
9026
9027 // Stop pointer capture
9028 requestAndVerifyPointerCapture(mWindow, false);
9029
9030 // Continue hovering on the window
9031 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_MOVE, AINPUT_SOURCE_MOUSE)
9032 .pointer(PointerBuilder(0, ToolType::MOUSE).x(105).y(115))
9033 .build());
9034 mWindow->consumeMotionEvent(
9035 AllOf(WithMotionAction(ACTION_HOVER_MOVE), WithSource(AINPUT_SOURCE_MOUSE)));
9036
9037 mWindow->assertNoEvents();
9038}
9039
Hiroki Sato25040232024-02-22 17:21:22 +09009040using InputDispatcherPointerCaptureDeathTest = InputDispatcherPointerCaptureTests;
9041
9042TEST_F(InputDispatcherPointerCaptureDeathTest,
9043 NotifyPointerCaptureChangedWithWrongTokenAbortsDispatcher) {
9044 testing::GTEST_FLAG(death_test_style) = "threadsafe";
9045 ScopedSilentDeath _silentDeath;
9046
9047 mDispatcher->requestPointerCapture(mWindow->getToken(), true);
9048 auto request = mFakePolicy->assertSetPointerCaptureCalled(mWindow, true);
9049
9050 // Dispatch a pointer changed event with a wrong token.
9051 request.window = mSecondWindow->getToken();
9052 ASSERT_DEATH(
9053 {
9054 notifyPointerCaptureChanged(request);
9055 mSecondWindow->consumeCaptureEvent(true);
9056 },
9057 "Unexpected requested window for Pointer Capture.");
9058}
9059
Bernardo Rufinoc3b7b8c2021-01-29 17:38:07 +00009060class InputDispatcherUntrustedTouchesTest : public InputDispatcherTest {
9061protected:
9062 constexpr static const float MAXIMUM_OBSCURING_OPACITY = 0.8;
Bernardo Rufino7393d172021-02-26 13:56:11 +00009063
9064 constexpr static const float OPACITY_ABOVE_THRESHOLD = 0.9;
9065 static_assert(OPACITY_ABOVE_THRESHOLD > MAXIMUM_OBSCURING_OPACITY);
9066
9067 constexpr static const float OPACITY_BELOW_THRESHOLD = 0.7;
9068 static_assert(OPACITY_BELOW_THRESHOLD < MAXIMUM_OBSCURING_OPACITY);
9069
9070 // When combined twice, ie 1 - (1 - 0.5)*(1 - 0.5) = 0.75 < 8, is still below the threshold
9071 constexpr static const float OPACITY_FAR_BELOW_THRESHOLD = 0.5;
9072 static_assert(OPACITY_FAR_BELOW_THRESHOLD < MAXIMUM_OBSCURING_OPACITY);
9073 static_assert(1 - (1 - OPACITY_FAR_BELOW_THRESHOLD) * (1 - OPACITY_FAR_BELOW_THRESHOLD) <
9074 MAXIMUM_OBSCURING_OPACITY);
9075
Prabir Pradhan8a5c41d2023-06-08 19:13:46 +00009076 static constexpr gui::Uid TOUCHED_APP_UID{10001};
9077 static constexpr gui::Uid APP_B_UID{10002};
9078 static constexpr gui::Uid APP_C_UID{10003};
Bernardo Rufinoc3b7b8c2021-01-29 17:38:07 +00009079
9080 sp<FakeWindowHandle> mTouchWindow;
9081
9082 virtual void SetUp() override {
9083 InputDispatcherTest::SetUp();
Bernardo Rufino6d52e542021-02-15 18:38:10 +00009084 mTouchWindow = getWindow(TOUCHED_APP_UID, "Touched");
Bernardo Rufinoc3b7b8c2021-01-29 17:38:07 +00009085 mDispatcher->setMaximumObscuringOpacityForTouch(MAXIMUM_OBSCURING_OPACITY);
9086 }
9087
9088 virtual void TearDown() override {
9089 InputDispatcherTest::TearDown();
9090 mTouchWindow.clear();
9091 }
9092
Prabir Pradhan8a5c41d2023-06-08 19:13:46 +00009093 sp<FakeWindowHandle> getOccludingWindow(gui::Uid uid, std::string name, TouchOcclusionMode mode,
chaviw3277faf2021-05-19 16:45:23 -05009094 float alpha = 1.0f) {
Bernardo Rufinoc3b7b8c2021-01-29 17:38:07 +00009095 sp<FakeWindowHandle> window = getWindow(uid, name);
Prabir Pradhan4d5c52f2022-01-31 08:52:10 -08009096 window->setTouchable(false);
Bernardo Rufinoc3b7b8c2021-01-29 17:38:07 +00009097 window->setTouchOcclusionMode(mode);
Bernardo Rufino1d0d1f22021-02-12 15:08:43 +00009098 window->setAlpha(alpha);
Bernardo Rufinoc3b7b8c2021-01-29 17:38:07 +00009099 return window;
9100 }
9101
Prabir Pradhan8a5c41d2023-06-08 19:13:46 +00009102 sp<FakeWindowHandle> getWindow(gui::Uid uid, std::string name) {
Bernardo Rufinoc3b7b8c2021-01-29 17:38:07 +00009103 std::shared_ptr<FakeApplicationHandle> app = std::make_shared<FakeApplicationHandle>();
9104 sp<FakeWindowHandle> window =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07009105 sp<FakeWindowHandle>::make(app, mDispatcher, name, ADISPLAY_ID_DEFAULT);
Bernardo Rufinoc3b7b8c2021-01-29 17:38:07 +00009106 // Generate an arbitrary PID based on the UID
Prabir Pradhanaeebeb42023-06-13 19:53:03 +00009107 window->setOwnerInfo(gui::Pid{static_cast<pid_t>(1777 + (uid.val() % 10000))}, uid);
Bernardo Rufinoc3b7b8c2021-01-29 17:38:07 +00009108 return window;
9109 }
9110
9111 void touch(const std::vector<PointF>& points = {PointF{100, 200}}) {
Prabir Pradhan678438e2023-04-13 19:32:51 +00009112 mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_DOWN,
9113 AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
9114 points));
Bernardo Rufinoc3b7b8c2021-01-29 17:38:07 +00009115 }
9116};
9117
9118TEST_F(InputDispatcherUntrustedTouchesTest, WindowWithBlockUntrustedOcclusionMode_BlocksTouch) {
Bernardo Rufino1d0d1f22021-02-12 15:08:43 +00009119 const sp<FakeWindowHandle>& w =
Bernardo Rufinoc3b7b8c2021-01-29 17:38:07 +00009120 getOccludingWindow(APP_B_UID, "B", TouchOcclusionMode::BLOCK_UNTRUSTED);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07009121 mDispatcher->onWindowInfosChanged({{*w->getInfo(), *mTouchWindow->getInfo()}, {}, 0, 0});
Bernardo Rufinoc3b7b8c2021-01-29 17:38:07 +00009122
9123 touch();
9124
9125 mTouchWindow->assertNoEvents();
9126}
9127
Bernardo Rufinoa43a5a42021-02-17 12:21:14 +00009128TEST_F(InputDispatcherUntrustedTouchesTest,
Bernardo Rufino7393d172021-02-26 13:56:11 +00009129 WindowWithBlockUntrustedOcclusionModeWithOpacityBelowThreshold_BlocksTouch) {
9130 const sp<FakeWindowHandle>& w =
9131 getOccludingWindow(APP_B_UID, "B", TouchOcclusionMode::BLOCK_UNTRUSTED, 0.7f);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07009132 mDispatcher->onWindowInfosChanged({{*w->getInfo(), *mTouchWindow->getInfo()}, {}, 0, 0});
Bernardo Rufino7393d172021-02-26 13:56:11 +00009133
9134 touch();
9135
9136 mTouchWindow->assertNoEvents();
9137}
9138
9139TEST_F(InputDispatcherUntrustedTouchesTest,
Bernardo Rufinoa43a5a42021-02-17 12:21:14 +00009140 WindowWithBlockUntrustedOcclusionMode_DoesNotReceiveTouch) {
9141 const sp<FakeWindowHandle>& w =
9142 getOccludingWindow(APP_B_UID, "B", TouchOcclusionMode::BLOCK_UNTRUSTED);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07009143 mDispatcher->onWindowInfosChanged({{*w->getInfo(), *mTouchWindow->getInfo()}, {}, 0, 0});
Bernardo Rufinoa43a5a42021-02-17 12:21:14 +00009144
9145 touch();
9146
9147 w->assertNoEvents();
9148}
9149
Bernardo Rufinoc3b7b8c2021-01-29 17:38:07 +00009150TEST_F(InputDispatcherUntrustedTouchesTest, WindowWithAllowOcclusionMode_AllowsTouch) {
Bernardo Rufino1d0d1f22021-02-12 15:08:43 +00009151 const sp<FakeWindowHandle>& w = getOccludingWindow(APP_B_UID, "B", TouchOcclusionMode::ALLOW);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07009152 mDispatcher->onWindowInfosChanged({{*w->getInfo(), *mTouchWindow->getInfo()}, {}, 0, 0});
Bernardo Rufinoc3b7b8c2021-01-29 17:38:07 +00009153
9154 touch();
9155
9156 mTouchWindow->consumeAnyMotionDown();
9157}
9158
9159TEST_F(InputDispatcherUntrustedTouchesTest, TouchOutsideOccludingWindow_AllowsTouch) {
Bernardo Rufino1d0d1f22021-02-12 15:08:43 +00009160 const sp<FakeWindowHandle>& w =
Bernardo Rufinoc3b7b8c2021-01-29 17:38:07 +00009161 getOccludingWindow(APP_B_UID, "B", TouchOcclusionMode::BLOCK_UNTRUSTED);
Bernardo Rufino1d0d1f22021-02-12 15:08:43 +00009162 w->setFrame(Rect(0, 0, 50, 50));
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07009163 mDispatcher->onWindowInfosChanged({{*w->getInfo(), *mTouchWindow->getInfo()}, {}, 0, 0});
Bernardo Rufinoc3b7b8c2021-01-29 17:38:07 +00009164
9165 touch({PointF{100, 100}});
9166
9167 mTouchWindow->consumeAnyMotionDown();
9168}
9169
9170TEST_F(InputDispatcherUntrustedTouchesTest, WindowFromSameUid_AllowsTouch) {
Bernardo Rufino1d0d1f22021-02-12 15:08:43 +00009171 const sp<FakeWindowHandle>& w =
Bernardo Rufino6d52e542021-02-15 18:38:10 +00009172 getOccludingWindow(TOUCHED_APP_UID, "A", TouchOcclusionMode::BLOCK_UNTRUSTED);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07009173 mDispatcher->onWindowInfosChanged({{*w->getInfo(), *mTouchWindow->getInfo()}, {}, 0, 0});
Bernardo Rufino1d0d1f22021-02-12 15:08:43 +00009174
9175 touch();
9176
9177 mTouchWindow->consumeAnyMotionDown();
9178}
9179
9180TEST_F(InputDispatcherUntrustedTouchesTest, WindowWithZeroOpacity_AllowsTouch) {
9181 const sp<FakeWindowHandle>& w =
9182 getOccludingWindow(APP_B_UID, "B", TouchOcclusionMode::BLOCK_UNTRUSTED, 0.0f);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07009183 mDispatcher->onWindowInfosChanged({{*w->getInfo(), *mTouchWindow->getInfo()}, {}, 0, 0});
Bernardo Rufinoc3b7b8c2021-01-29 17:38:07 +00009184
9185 touch();
9186
9187 mTouchWindow->consumeAnyMotionDown();
9188}
9189
Bernardo Rufinoa43a5a42021-02-17 12:21:14 +00009190TEST_F(InputDispatcherUntrustedTouchesTest, WindowWithZeroOpacity_DoesNotReceiveTouch) {
9191 const sp<FakeWindowHandle>& w =
9192 getOccludingWindow(APP_B_UID, "B", TouchOcclusionMode::BLOCK_UNTRUSTED, 0.0f);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07009193 mDispatcher->onWindowInfosChanged({{*w->getInfo(), *mTouchWindow->getInfo()}, {}, 0, 0});
Bernardo Rufinoa43a5a42021-02-17 12:21:14 +00009194
9195 touch();
9196
9197 w->assertNoEvents();
9198}
9199
9200/**
9201 * This is important to make sure apps can't indirectly learn the position of touches (outside vs
9202 * inside) while letting them pass-through. Note that even though touch passes through the occluding
9203 * window, the occluding window will still receive ACTION_OUTSIDE event.
9204 */
9205TEST_F(InputDispatcherUntrustedTouchesTest,
9206 WindowWithZeroOpacityAndWatchOutside_ReceivesOutsideEvent) {
9207 const sp<FakeWindowHandle>& w =
9208 getOccludingWindow(APP_B_UID, "B", TouchOcclusionMode::BLOCK_UNTRUSTED, 0.0f);
Prabir Pradhan4d5c52f2022-01-31 08:52:10 -08009209 w->setWatchOutsideTouch(true);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07009210 mDispatcher->onWindowInfosChanged({{*w->getInfo(), *mTouchWindow->getInfo()}, {}, 0, 0});
Bernardo Rufinoa43a5a42021-02-17 12:21:14 +00009211
9212 touch();
9213
9214 w->consumeMotionOutside();
9215}
9216
9217TEST_F(InputDispatcherUntrustedTouchesTest, OutsideEvent_HasZeroCoordinates) {
9218 const sp<FakeWindowHandle>& w =
9219 getOccludingWindow(APP_B_UID, "B", TouchOcclusionMode::BLOCK_UNTRUSTED, 0.0f);
Prabir Pradhan4d5c52f2022-01-31 08:52:10 -08009220 w->setWatchOutsideTouch(true);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07009221 mDispatcher->onWindowInfosChanged({{*w->getInfo(), *mTouchWindow->getInfo()}, {}, 0, 0});
Bernardo Rufinoa43a5a42021-02-17 12:21:14 +00009222
9223 touch();
9224
Prabir Pradhandfabf8a2022-01-21 08:19:30 -08009225 w->consumeMotionOutsideWithZeroedCoords();
Bernardo Rufinoa43a5a42021-02-17 12:21:14 +00009226}
9227
Bernardo Rufinoc3b7b8c2021-01-29 17:38:07 +00009228TEST_F(InputDispatcherUntrustedTouchesTest, WindowWithOpacityBelowThreshold_AllowsTouch) {
Bernardo Rufino1d0d1f22021-02-12 15:08:43 +00009229 const sp<FakeWindowHandle>& w =
Bernardo Rufino7393d172021-02-26 13:56:11 +00009230 getOccludingWindow(APP_B_UID, "B", TouchOcclusionMode::USE_OPACITY,
9231 OPACITY_BELOW_THRESHOLD);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07009232 mDispatcher->onWindowInfosChanged({{*w->getInfo(), *mTouchWindow->getInfo()}, {}, 0, 0});
Bernardo Rufino1d0d1f22021-02-12 15:08:43 +00009233
9234 touch();
9235
9236 mTouchWindow->consumeAnyMotionDown();
9237}
9238
9239TEST_F(InputDispatcherUntrustedTouchesTest, WindowWithOpacityAtThreshold_AllowsTouch) {
9240 const sp<FakeWindowHandle>& w =
9241 getOccludingWindow(APP_B_UID, "B", TouchOcclusionMode::USE_OPACITY,
9242 MAXIMUM_OBSCURING_OPACITY);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07009243 mDispatcher->onWindowInfosChanged({{*w->getInfo(), *mTouchWindow->getInfo()}, {}, 0, 0});
Bernardo Rufinoc3b7b8c2021-01-29 17:38:07 +00009244
9245 touch();
9246
9247 mTouchWindow->consumeAnyMotionDown();
9248}
9249
9250TEST_F(InputDispatcherUntrustedTouchesTest, WindowWithOpacityAboveThreshold_BlocksTouch) {
Bernardo Rufino1d0d1f22021-02-12 15:08:43 +00009251 const sp<FakeWindowHandle>& w =
Bernardo Rufino7393d172021-02-26 13:56:11 +00009252 getOccludingWindow(APP_B_UID, "B", TouchOcclusionMode::USE_OPACITY,
9253 OPACITY_ABOVE_THRESHOLD);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07009254 mDispatcher->onWindowInfosChanged({{*w->getInfo(), *mTouchWindow->getInfo()}, {}, 0, 0});
Bernardo Rufino1d0d1f22021-02-12 15:08:43 +00009255
9256 touch();
9257
9258 mTouchWindow->assertNoEvents();
9259}
9260
9261TEST_F(InputDispatcherUntrustedTouchesTest, WindowsWithCombinedOpacityAboveThreshold_BlocksTouch) {
9262 // Resulting opacity = 1 - (1 - 0.7)*(1 - 0.7) = .91
9263 const sp<FakeWindowHandle>& w1 =
Bernardo Rufino7393d172021-02-26 13:56:11 +00009264 getOccludingWindow(APP_B_UID, "B1", TouchOcclusionMode::USE_OPACITY,
9265 OPACITY_BELOW_THRESHOLD);
Bernardo Rufino1d0d1f22021-02-12 15:08:43 +00009266 const sp<FakeWindowHandle>& w2 =
Bernardo Rufino7393d172021-02-26 13:56:11 +00009267 getOccludingWindow(APP_B_UID, "B2", TouchOcclusionMode::USE_OPACITY,
9268 OPACITY_BELOW_THRESHOLD);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07009269 mDispatcher->onWindowInfosChanged(
9270 {{*w1->getInfo(), *w2->getInfo(), *mTouchWindow->getInfo()}, {}, 0, 0});
Bernardo Rufino1d0d1f22021-02-12 15:08:43 +00009271
9272 touch();
9273
9274 mTouchWindow->assertNoEvents();
9275}
9276
9277TEST_F(InputDispatcherUntrustedTouchesTest, WindowsWithCombinedOpacityBelowThreshold_AllowsTouch) {
9278 // Resulting opacity = 1 - (1 - 0.5)*(1 - 0.5) = .75
9279 const sp<FakeWindowHandle>& w1 =
Bernardo Rufino7393d172021-02-26 13:56:11 +00009280 getOccludingWindow(APP_B_UID, "B1", TouchOcclusionMode::USE_OPACITY,
9281 OPACITY_FAR_BELOW_THRESHOLD);
Bernardo Rufino1d0d1f22021-02-12 15:08:43 +00009282 const sp<FakeWindowHandle>& w2 =
Bernardo Rufino7393d172021-02-26 13:56:11 +00009283 getOccludingWindow(APP_B_UID, "B2", TouchOcclusionMode::USE_OPACITY,
9284 OPACITY_FAR_BELOW_THRESHOLD);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07009285 mDispatcher->onWindowInfosChanged(
9286 {{*w1->getInfo(), *w2->getInfo(), *mTouchWindow->getInfo()}, {}, 0, 0});
Bernardo Rufino1d0d1f22021-02-12 15:08:43 +00009287
9288 touch();
9289
9290 mTouchWindow->consumeAnyMotionDown();
9291}
9292
9293TEST_F(InputDispatcherUntrustedTouchesTest,
9294 WindowsFromDifferentAppsEachBelowThreshold_AllowsTouch) {
9295 const sp<FakeWindowHandle>& wB =
Bernardo Rufino7393d172021-02-26 13:56:11 +00009296 getOccludingWindow(APP_B_UID, "B", TouchOcclusionMode::USE_OPACITY,
9297 OPACITY_BELOW_THRESHOLD);
Bernardo Rufino1d0d1f22021-02-12 15:08:43 +00009298 const sp<FakeWindowHandle>& wC =
Bernardo Rufino7393d172021-02-26 13:56:11 +00009299 getOccludingWindow(APP_C_UID, "C", TouchOcclusionMode::USE_OPACITY,
9300 OPACITY_BELOW_THRESHOLD);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07009301 mDispatcher->onWindowInfosChanged(
9302 {{*wB->getInfo(), *wC->getInfo(), *mTouchWindow->getInfo()}, {}, 0, 0});
Bernardo Rufino1d0d1f22021-02-12 15:08:43 +00009303
9304 touch();
9305
9306 mTouchWindow->consumeAnyMotionDown();
9307}
9308
9309TEST_F(InputDispatcherUntrustedTouchesTest, WindowsFromDifferentAppsOneAboveThreshold_BlocksTouch) {
9310 const sp<FakeWindowHandle>& wB =
Bernardo Rufino7393d172021-02-26 13:56:11 +00009311 getOccludingWindow(APP_B_UID, "B", TouchOcclusionMode::USE_OPACITY,
9312 OPACITY_BELOW_THRESHOLD);
Bernardo Rufino1d0d1f22021-02-12 15:08:43 +00009313 const sp<FakeWindowHandle>& wC =
Bernardo Rufino7393d172021-02-26 13:56:11 +00009314 getOccludingWindow(APP_C_UID, "C", TouchOcclusionMode::USE_OPACITY,
9315 OPACITY_ABOVE_THRESHOLD);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07009316 mDispatcher->onWindowInfosChanged(
9317 {{*wB->getInfo(), *wC->getInfo(), *mTouchWindow->getInfo()}, {}, 0, 0});
Bernardo Rufinoc3b7b8c2021-01-29 17:38:07 +00009318
9319 touch();
9320
9321 mTouchWindow->assertNoEvents();
9322}
9323
Bernardo Rufino6d52e542021-02-15 18:38:10 +00009324TEST_F(InputDispatcherUntrustedTouchesTest,
9325 WindowWithOpacityAboveThresholdAndSelfWindow_BlocksTouch) {
9326 const sp<FakeWindowHandle>& wA =
Bernardo Rufino7393d172021-02-26 13:56:11 +00009327 getOccludingWindow(TOUCHED_APP_UID, "T", TouchOcclusionMode::USE_OPACITY,
9328 OPACITY_BELOW_THRESHOLD);
Bernardo Rufino6d52e542021-02-15 18:38:10 +00009329 const sp<FakeWindowHandle>& wB =
Bernardo Rufino7393d172021-02-26 13:56:11 +00009330 getOccludingWindow(APP_B_UID, "B", TouchOcclusionMode::USE_OPACITY,
9331 OPACITY_ABOVE_THRESHOLD);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07009332 mDispatcher->onWindowInfosChanged(
9333 {{*wA->getInfo(), *wB->getInfo(), *mTouchWindow->getInfo()}, {}, 0, 0});
Bernardo Rufino6d52e542021-02-15 18:38:10 +00009334
9335 touch();
9336
9337 mTouchWindow->assertNoEvents();
9338}
9339
9340TEST_F(InputDispatcherUntrustedTouchesTest,
9341 WindowWithOpacityBelowThresholdAndSelfWindow_AllowsTouch) {
9342 const sp<FakeWindowHandle>& wA =
Bernardo Rufino7393d172021-02-26 13:56:11 +00009343 getOccludingWindow(TOUCHED_APP_UID, "T", TouchOcclusionMode::USE_OPACITY,
9344 OPACITY_ABOVE_THRESHOLD);
Bernardo Rufino6d52e542021-02-15 18:38:10 +00009345 const sp<FakeWindowHandle>& wB =
Bernardo Rufino7393d172021-02-26 13:56:11 +00009346 getOccludingWindow(APP_B_UID, "B", TouchOcclusionMode::USE_OPACITY,
9347 OPACITY_BELOW_THRESHOLD);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07009348 mDispatcher->onWindowInfosChanged(
9349 {{*wA->getInfo(), *wB->getInfo(), *mTouchWindow->getInfo()}, {}, 0, 0});
Bernardo Rufino6d52e542021-02-15 18:38:10 +00009350
9351 touch();
9352
9353 mTouchWindow->consumeAnyMotionDown();
9354}
9355
9356TEST_F(InputDispatcherUntrustedTouchesTest, SelfWindowWithOpacityAboveThreshold_AllowsTouch) {
9357 const sp<FakeWindowHandle>& w =
Bernardo Rufino7393d172021-02-26 13:56:11 +00009358 getOccludingWindow(TOUCHED_APP_UID, "T", TouchOcclusionMode::USE_OPACITY,
9359 OPACITY_ABOVE_THRESHOLD);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07009360 mDispatcher->onWindowInfosChanged({{*w->getInfo(), *mTouchWindow->getInfo()}, {}, 0, 0});
Bernardo Rufino6d52e542021-02-15 18:38:10 +00009361
9362 touch();
9363
9364 mTouchWindow->consumeAnyMotionDown();
9365}
9366
9367TEST_F(InputDispatcherUntrustedTouchesTest, SelfWindowWithBlockUntrustedMode_AllowsTouch) {
9368 const sp<FakeWindowHandle>& w =
9369 getOccludingWindow(TOUCHED_APP_UID, "T", TouchOcclusionMode::BLOCK_UNTRUSTED);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07009370 mDispatcher->onWindowInfosChanged({{*w->getInfo(), *mTouchWindow->getInfo()}, {}, 0, 0});
Bernardo Rufino6d52e542021-02-15 18:38:10 +00009371
9372 touch();
9373
9374 mTouchWindow->consumeAnyMotionDown();
9375}
9376
Bernardo Rufinoccd3dd62021-02-15 18:47:42 +00009377TEST_F(InputDispatcherUntrustedTouchesTest,
9378 OpacityThresholdIs0AndWindowAboveThreshold_BlocksTouch) {
9379 mDispatcher->setMaximumObscuringOpacityForTouch(0.0f);
9380 const sp<FakeWindowHandle>& w =
9381 getOccludingWindow(APP_B_UID, "B", TouchOcclusionMode::USE_OPACITY, 0.1f);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07009382 mDispatcher->onWindowInfosChanged({{*w->getInfo(), *mTouchWindow->getInfo()}, {}, 0, 0});
Bernardo Rufinoccd3dd62021-02-15 18:47:42 +00009383
9384 touch();
9385
9386 mTouchWindow->assertNoEvents();
9387}
9388
9389TEST_F(InputDispatcherUntrustedTouchesTest, OpacityThresholdIs0AndWindowAtThreshold_AllowsTouch) {
9390 mDispatcher->setMaximumObscuringOpacityForTouch(0.0f);
9391 const sp<FakeWindowHandle>& w =
9392 getOccludingWindow(APP_B_UID, "B", TouchOcclusionMode::USE_OPACITY, 0.0f);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07009393 mDispatcher->onWindowInfosChanged({{*w->getInfo(), *mTouchWindow->getInfo()}, {}, 0, 0});
Bernardo Rufinoccd3dd62021-02-15 18:47:42 +00009394
9395 touch();
9396
9397 mTouchWindow->consumeAnyMotionDown();
9398}
9399
9400TEST_F(InputDispatcherUntrustedTouchesTest,
9401 OpacityThresholdIs1AndWindowBelowThreshold_AllowsTouch) {
9402 mDispatcher->setMaximumObscuringOpacityForTouch(1.0f);
9403 const sp<FakeWindowHandle>& w =
Bernardo Rufino7393d172021-02-26 13:56:11 +00009404 getOccludingWindow(APP_B_UID, "B", TouchOcclusionMode::USE_OPACITY,
9405 OPACITY_ABOVE_THRESHOLD);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07009406 mDispatcher->onWindowInfosChanged({{*w->getInfo(), *mTouchWindow->getInfo()}, {}, 0, 0});
Bernardo Rufino7393d172021-02-26 13:56:11 +00009407
9408 touch();
9409
9410 mTouchWindow->consumeAnyMotionDown();
9411}
9412
9413TEST_F(InputDispatcherUntrustedTouchesTest,
9414 WindowWithBlockUntrustedModeAndWindowWithOpacityBelowFromSameApp_BlocksTouch) {
9415 const sp<FakeWindowHandle>& w1 =
9416 getOccludingWindow(APP_B_UID, "B", TouchOcclusionMode::BLOCK_UNTRUSTED,
9417 OPACITY_BELOW_THRESHOLD);
9418 const sp<FakeWindowHandle>& w2 =
9419 getOccludingWindow(APP_B_UID, "B", TouchOcclusionMode::USE_OPACITY,
9420 OPACITY_BELOW_THRESHOLD);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07009421 mDispatcher->onWindowInfosChanged(
9422 {{*w1->getInfo(), *w2->getInfo(), *mTouchWindow->getInfo()}, {}, 0, 0});
Bernardo Rufino7393d172021-02-26 13:56:11 +00009423
9424 touch();
9425
9426 mTouchWindow->assertNoEvents();
9427}
9428
9429/**
9430 * Window B of BLOCK_UNTRUSTED occlusion mode is enough to block the touch, we're testing that the
9431 * addition of another window (C) of USE_OPACITY occlusion mode and opacity below the threshold
9432 * (which alone would result in allowing touches) does not affect the blocking behavior.
9433 */
9434TEST_F(InputDispatcherUntrustedTouchesTest,
9435 WindowWithBlockUntrustedModeAndWindowWithOpacityBelowFromDifferentApps_BlocksTouch) {
9436 const sp<FakeWindowHandle>& wB =
9437 getOccludingWindow(APP_B_UID, "B", TouchOcclusionMode::BLOCK_UNTRUSTED,
9438 OPACITY_BELOW_THRESHOLD);
9439 const sp<FakeWindowHandle>& wC =
9440 getOccludingWindow(APP_C_UID, "C", TouchOcclusionMode::USE_OPACITY,
9441 OPACITY_BELOW_THRESHOLD);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07009442 mDispatcher->onWindowInfosChanged(
9443 {{*wB->getInfo(), *wC->getInfo(), *mTouchWindow->getInfo()}, {}, 0, 0});
Bernardo Rufino7393d172021-02-26 13:56:11 +00009444
9445 touch();
9446
9447 mTouchWindow->assertNoEvents();
9448}
9449
9450/**
9451 * This test is testing that a window from a different UID but with same application token doesn't
9452 * block the touch. Apps can share the application token for close UI collaboration for example.
9453 */
9454TEST_F(InputDispatcherUntrustedTouchesTest,
9455 WindowWithSameApplicationTokenFromDifferentApp_AllowsTouch) {
9456 const sp<FakeWindowHandle>& w =
9457 getOccludingWindow(APP_B_UID, "B", TouchOcclusionMode::BLOCK_UNTRUSTED);
9458 w->setApplicationToken(mTouchWindow->getApplicationToken());
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07009459 mDispatcher->onWindowInfosChanged({{*w->getInfo(), *mTouchWindow->getInfo()}, {}, 0, 0});
Bernardo Rufinoccd3dd62021-02-15 18:47:42 +00009460
9461 touch();
9462
9463 mTouchWindow->consumeAnyMotionDown();
9464}
9465
arthurhungb89ccb02020-12-30 16:19:01 +08009466class InputDispatcherDragTests : public InputDispatcherTest {
9467protected:
9468 std::shared_ptr<FakeApplicationHandle> mApp;
9469 sp<FakeWindowHandle> mWindow;
9470 sp<FakeWindowHandle> mSecondWindow;
9471 sp<FakeWindowHandle> mDragWindow;
Vaibhav Devmurari6abcf8f2022-06-06 10:08:05 +00009472 sp<FakeWindowHandle> mSpyWindow;
Arthur Hungb75c2aa2022-07-15 09:35:36 +00009473 // Mouse would force no-split, set the id as non-zero to verify if drag state could track it.
9474 static constexpr int32_t MOUSE_POINTER_ID = 1;
arthurhungb89ccb02020-12-30 16:19:01 +08009475
9476 void SetUp() override {
9477 InputDispatcherTest::SetUp();
9478 mApp = std::make_shared<FakeApplicationHandle>();
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07009479 mWindow = sp<FakeWindowHandle>::make(mApp, mDispatcher, "TestWindow", ADISPLAY_ID_DEFAULT);
arthurhungb89ccb02020-12-30 16:19:01 +08009480 mWindow->setFrame(Rect(0, 0, 100, 100));
arthurhungb89ccb02020-12-30 16:19:01 +08009481
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07009482 mSecondWindow =
9483 sp<FakeWindowHandle>::make(mApp, mDispatcher, "TestWindow2", ADISPLAY_ID_DEFAULT);
arthurhungb89ccb02020-12-30 16:19:01 +08009484 mSecondWindow->setFrame(Rect(100, 0, 200, 100));
arthurhungb89ccb02020-12-30 16:19:01 +08009485
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07009486 mSpyWindow =
9487 sp<FakeWindowHandle>::make(mApp, mDispatcher, "SpyWindow", ADISPLAY_ID_DEFAULT);
Vaibhav Devmurari6abcf8f2022-06-06 10:08:05 +00009488 mSpyWindow->setSpy(true);
9489 mSpyWindow->setTrustedOverlay(true);
9490 mSpyWindow->setFrame(Rect(0, 0, 200, 100));
9491
arthurhungb89ccb02020-12-30 16:19:01 +08009492 mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, mApp);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07009493 mDispatcher->onWindowInfosChanged(
9494 {{*mSpyWindow->getInfo(), *mWindow->getInfo(), *mSecondWindow->getInfo()},
9495 {},
9496 0,
9497 0});
arthurhungb89ccb02020-12-30 16:19:01 +08009498 }
9499
Arthur Hungb75c2aa2022-07-15 09:35:36 +00009500 void injectDown(int fromSource = AINPUT_SOURCE_TOUCHSCREEN) {
9501 switch (fromSource) {
9502 case AINPUT_SOURCE_TOUCHSCREEN:
9503 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07009504 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN,
Arthur Hungb75c2aa2022-07-15 09:35:36 +00009505 ADISPLAY_ID_DEFAULT, {50, 50}))
9506 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
9507 break;
9508 case AINPUT_SOURCE_STYLUS:
9509 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07009510 injectMotionEvent(*mDispatcher,
9511 MotionEventBuilder(AMOTION_EVENT_ACTION_DOWN,
9512 AINPUT_SOURCE_STYLUS)
9513 .buttonState(
9514 AMOTION_EVENT_BUTTON_STYLUS_PRIMARY)
9515 .pointer(PointerBuilder(0, ToolType::STYLUS)
9516 .x(50)
9517 .y(50))
9518 .build()));
Arthur Hungb75c2aa2022-07-15 09:35:36 +00009519 break;
9520 case AINPUT_SOURCE_MOUSE:
9521 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07009522 injectMotionEvent(*mDispatcher,
9523 MotionEventBuilder(AMOTION_EVENT_ACTION_DOWN,
9524 AINPUT_SOURCE_MOUSE)
9525 .buttonState(AMOTION_EVENT_BUTTON_PRIMARY)
9526 .pointer(PointerBuilder(MOUSE_POINTER_ID,
9527 ToolType::MOUSE)
9528 .x(50)
9529 .y(50))
9530 .build()));
Arthur Hungb75c2aa2022-07-15 09:35:36 +00009531 break;
9532 default:
9533 FAIL() << "Source " << fromSource << " doesn't support drag and drop";
9534 }
arthurhungb89ccb02020-12-30 16:19:01 +08009535
9536 // Window should receive motion event.
9537 mWindow->consumeMotionDown(ADISPLAY_ID_DEFAULT);
Vaibhav Devmurari6abcf8f2022-06-06 10:08:05 +00009538 // Spy window should also receive motion event
9539 mSpyWindow->consumeMotionDown(ADISPLAY_ID_DEFAULT);
Arthur Hung54745652022-04-20 07:17:41 +00009540 }
9541
9542 // Start performing drag, we will create a drag window and transfer touch to it.
9543 // @param sendDown : if true, send a motion down on first window before perform drag and drop.
9544 // Returns true on success.
Arthur Hungb75c2aa2022-07-15 09:35:36 +00009545 bool startDrag(bool sendDown = true, int fromSource = AINPUT_SOURCE_TOUCHSCREEN) {
Arthur Hung54745652022-04-20 07:17:41 +00009546 if (sendDown) {
Arthur Hungb75c2aa2022-07-15 09:35:36 +00009547 injectDown(fromSource);
Arthur Hung54745652022-04-20 07:17:41 +00009548 }
arthurhungb89ccb02020-12-30 16:19:01 +08009549
9550 // The drag window covers the entire display
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07009551 mDragWindow =
9552 sp<FakeWindowHandle>::make(mApp, mDispatcher, "DragWindow", ADISPLAY_ID_DEFAULT);
Vaibhav Devmurari6abcf8f2022-06-06 10:08:05 +00009553 mDragWindow->setTouchableRegion(Region{{0, 0, 0, 0}});
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07009554 mDispatcher->onWindowInfosChanged({{*mDragWindow->getInfo(), *mSpyWindow->getInfo(),
9555 *mWindow->getInfo(), *mSecondWindow->getInfo()},
9556 {},
9557 0,
9558 0});
arthurhungb89ccb02020-12-30 16:19:01 +08009559
9560 // Transfer touch focus to the drag window
Arthur Hung54745652022-04-20 07:17:41 +00009561 bool transferred =
Prabir Pradhan367f3432024-02-13 23:05:58 +00009562 mDispatcher->transferTouchGesture(mWindow->getToken(), mDragWindow->getToken(),
9563 /*isDragDrop=*/true);
Arthur Hung54745652022-04-20 07:17:41 +00009564 if (transferred) {
9565 mWindow->consumeMotionCancel();
Prabir Pradhan65455c72024-02-13 21:46:41 +00009566 mDragWindow->consumeMotionDown(ADISPLAY_ID_DEFAULT, AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
Arthur Hung54745652022-04-20 07:17:41 +00009567 }
9568 return transferred;
arthurhungb89ccb02020-12-30 16:19:01 +08009569 }
9570};
9571
9572TEST_F(InputDispatcherDragTests, DragEnterAndDragExit) {
Arthur Hungb75c2aa2022-07-15 09:35:36 +00009573 startDrag();
arthurhungb89ccb02020-12-30 16:19:01 +08009574
9575 // Move on window.
9576 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07009577 injectMotionEvent(*mDispatcher, AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN,
arthurhungb89ccb02020-12-30 16:19:01 +08009578 ADISPLAY_ID_DEFAULT, {50, 50}))
9579 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
Prabir Pradhan65455c72024-02-13 21:46:41 +00009580 mDragWindow->consumeMotionMove(ADISPLAY_ID_DEFAULT, AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
arthurhungb89ccb02020-12-30 16:19:01 +08009581 mWindow->consumeDragEvent(false, 50, 50);
9582 mSecondWindow->assertNoEvents();
9583
9584 // Move to another window.
9585 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07009586 injectMotionEvent(*mDispatcher, AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN,
arthurhungb89ccb02020-12-30 16:19:01 +08009587 ADISPLAY_ID_DEFAULT, {150, 50}))
9588 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
Prabir Pradhan65455c72024-02-13 21:46:41 +00009589 mDragWindow->consumeMotionMove(ADISPLAY_ID_DEFAULT, AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
arthurhungb89ccb02020-12-30 16:19:01 +08009590 mWindow->consumeDragEvent(true, 150, 50);
9591 mSecondWindow->consumeDragEvent(false, 50, 50);
9592
9593 // Move back to original window.
9594 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07009595 injectMotionEvent(*mDispatcher, AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN,
arthurhungb89ccb02020-12-30 16:19:01 +08009596 ADISPLAY_ID_DEFAULT, {50, 50}))
9597 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
Prabir Pradhan65455c72024-02-13 21:46:41 +00009598 mDragWindow->consumeMotionMove(ADISPLAY_ID_DEFAULT, AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
arthurhungb89ccb02020-12-30 16:19:01 +08009599 mWindow->consumeDragEvent(false, 50, 50);
9600 mSecondWindow->consumeDragEvent(true, -50, 50);
9601
9602 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07009603 injectMotionUp(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
9604 {50, 50}))
arthurhungb89ccb02020-12-30 16:19:01 +08009605 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
Prabir Pradhan65455c72024-02-13 21:46:41 +00009606 mDragWindow->consumeMotionUp(ADISPLAY_ID_DEFAULT, AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
arthurhungb89ccb02020-12-30 16:19:01 +08009607 mWindow->assertNoEvents();
9608 mSecondWindow->assertNoEvents();
9609}
9610
Vaibhav Devmurari6abcf8f2022-06-06 10:08:05 +00009611TEST_F(InputDispatcherDragTests, DragEnterAndPointerDownPilfersPointers) {
Arthur Hungb75c2aa2022-07-15 09:35:36 +00009612 startDrag();
Vaibhav Devmurari6abcf8f2022-06-06 10:08:05 +00009613
9614 // No cancel event after drag start
9615 mSpyWindow->assertNoEvents();
9616
9617 const MotionEvent secondFingerDownEvent =
9618 MotionEventBuilder(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
9619 .eventTime(systemTime(SYSTEM_TIME_MONOTONIC))
Siarhei Vishniakou6d73f832022-07-21 17:27:03 -07009620 .pointer(PointerBuilder(/*id=*/0, ToolType::FINGER).x(50).y(50))
9621 .pointer(PointerBuilder(/*id=*/1, ToolType::FINGER).x(60).y(60))
Vaibhav Devmurari6abcf8f2022-06-06 10:08:05 +00009622 .build();
9623 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07009624 injectMotionEvent(*mDispatcher, secondFingerDownEvent, INJECT_EVENT_TIMEOUT,
Vaibhav Devmurari6abcf8f2022-06-06 10:08:05 +00009625 InputEventInjectionSync::WAIT_FOR_RESULT))
9626 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
9627
9628 // Receives cancel for first pointer after next pointer down
9629 mSpyWindow->consumeMotionCancel();
9630 mSpyWindow->consumeMotionDown();
9631
9632 mSpyWindow->assertNoEvents();
9633}
9634
arthurhungf452d0b2021-01-06 00:19:52 +08009635TEST_F(InputDispatcherDragTests, DragAndDrop) {
Arthur Hungb75c2aa2022-07-15 09:35:36 +00009636 startDrag();
arthurhungf452d0b2021-01-06 00:19:52 +08009637
9638 // Move on window.
9639 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07009640 injectMotionEvent(*mDispatcher, AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN,
arthurhungf452d0b2021-01-06 00:19:52 +08009641 ADISPLAY_ID_DEFAULT, {50, 50}))
9642 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
Prabir Pradhan65455c72024-02-13 21:46:41 +00009643 mDragWindow->consumeMotionMove(ADISPLAY_ID_DEFAULT, AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
arthurhungf452d0b2021-01-06 00:19:52 +08009644 mWindow->consumeDragEvent(false, 50, 50);
9645 mSecondWindow->assertNoEvents();
9646
9647 // Move to another window.
9648 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07009649 injectMotionEvent(*mDispatcher, AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN,
arthurhungf452d0b2021-01-06 00:19:52 +08009650 ADISPLAY_ID_DEFAULT, {150, 50}))
9651 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
Prabir Pradhan65455c72024-02-13 21:46:41 +00009652 mDragWindow->consumeMotionMove(ADISPLAY_ID_DEFAULT, AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
arthurhungf452d0b2021-01-06 00:19:52 +08009653 mWindow->consumeDragEvent(true, 150, 50);
9654 mSecondWindow->consumeDragEvent(false, 50, 50);
9655
9656 // drop to another window.
9657 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07009658 injectMotionUp(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
arthurhungf452d0b2021-01-06 00:19:52 +08009659 {150, 50}))
9660 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
Prabir Pradhan65455c72024-02-13 21:46:41 +00009661 mDragWindow->consumeMotionUp(ADISPLAY_ID_DEFAULT, AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
Siarhei Vishniakoua66d65e2023-06-16 10:32:51 -07009662 mFakePolicy->assertDropTargetEquals(*mDispatcher, mSecondWindow->getToken());
arthurhungf452d0b2021-01-06 00:19:52 +08009663 mWindow->assertNoEvents();
9664 mSecondWindow->assertNoEvents();
9665}
9666
Vaibhav Devmurari110ba322023-11-17 10:47:16 +00009667TEST_F(InputDispatcherDragTests, DragAndDropNotCancelledIfSomeOtherPointerIsPilfered) {
9668 startDrag();
9669
9670 // No cancel event after drag start
9671 mSpyWindow->assertNoEvents();
9672
9673 const MotionEvent secondFingerDownEvent =
9674 MotionEventBuilder(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
9675 .eventTime(systemTime(SYSTEM_TIME_MONOTONIC))
9676 .pointer(PointerBuilder(/*id=*/0, ToolType::FINGER).x(50).y(50))
9677 .pointer(PointerBuilder(/*id=*/1, ToolType::FINGER).x(60).y(60))
9678 .build();
9679 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
9680 injectMotionEvent(*mDispatcher, secondFingerDownEvent, INJECT_EVENT_TIMEOUT,
9681 InputEventInjectionSync::WAIT_FOR_RESULT))
9682 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
9683
9684 // Receives cancel for first pointer after next pointer down
9685 mSpyWindow->consumeMotionEvent(WithMotionAction(ACTION_CANCEL));
Siarhei Vishniakou1ff00cc2023-12-13 16:12:13 -08009686 mSpyWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithPointerIds({1})));
Vaibhav Devmurari110ba322023-11-17 10:47:16 +00009687 mDragWindow->consumeMotionEvent(WithMotionAction(ACTION_MOVE));
9688
9689 mSpyWindow->assertNoEvents();
9690
9691 // Spy window calls pilfer pointers
9692 EXPECT_EQ(OK, mDispatcher->pilferPointers(mSpyWindow->getToken()));
9693 mDragWindow->assertNoEvents();
9694
9695 const MotionEvent firstFingerMoveEvent =
Siarhei Vishniakou96a15572023-12-18 10:47:52 -08009696 MotionEventBuilder(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN)
Vaibhav Devmurari110ba322023-11-17 10:47:16 +00009697 .eventTime(systemTime(SYSTEM_TIME_MONOTONIC))
9698 .pointer(PointerBuilder(/*id=*/0, ToolType::FINGER).x(60).y(60))
9699 .pointer(PointerBuilder(/*id=*/1, ToolType::FINGER).x(60).y(60))
9700 .build();
9701 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakou96a15572023-12-18 10:47:52 -08009702 injectMotionEvent(*mDispatcher, firstFingerMoveEvent, INJECT_EVENT_TIMEOUT,
Vaibhav Devmurari110ba322023-11-17 10:47:16 +00009703 InputEventInjectionSync::WAIT_FOR_RESULT))
9704 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
9705
9706 // Drag window should still receive the new event
Prabir Pradhan65455c72024-02-13 21:46:41 +00009707 mDragWindow->consumeMotionEvent(
9708 AllOf(WithMotionAction(ACTION_MOVE), WithFlags(AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE)));
Vaibhav Devmurari110ba322023-11-17 10:47:16 +00009709 mDragWindow->assertNoEvents();
9710}
9711
arthurhung6d4bed92021-03-17 11:59:33 +08009712TEST_F(InputDispatcherDragTests, StylusDragAndDrop) {
Arthur Hungb75c2aa2022-07-15 09:35:36 +00009713 startDrag(true, AINPUT_SOURCE_STYLUS);
arthurhung6d4bed92021-03-17 11:59:33 +08009714
9715 // Move on window and keep button pressed.
9716 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07009717 injectMotionEvent(*mDispatcher,
arthurhung6d4bed92021-03-17 11:59:33 +08009718 MotionEventBuilder(AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_STYLUS)
9719 .buttonState(AMOTION_EVENT_BUTTON_STYLUS_PRIMARY)
Siarhei Vishniakou6d73f832022-07-21 17:27:03 -07009720 .pointer(PointerBuilder(0, ToolType::STYLUS).x(50).y(50))
arthurhung6d4bed92021-03-17 11:59:33 +08009721 .build()))
9722 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
Prabir Pradhan65455c72024-02-13 21:46:41 +00009723 mDragWindow->consumeMotionMove(ADISPLAY_ID_DEFAULT, AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
arthurhung6d4bed92021-03-17 11:59:33 +08009724 mWindow->consumeDragEvent(false, 50, 50);
9725 mSecondWindow->assertNoEvents();
9726
9727 // Move to another window and release button, expect to drop item.
9728 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07009729 injectMotionEvent(*mDispatcher,
arthurhung6d4bed92021-03-17 11:59:33 +08009730 MotionEventBuilder(AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_STYLUS)
9731 .buttonState(0)
Siarhei Vishniakou6d73f832022-07-21 17:27:03 -07009732 .pointer(PointerBuilder(0, ToolType::STYLUS).x(150).y(50))
arthurhung6d4bed92021-03-17 11:59:33 +08009733 .build()))
9734 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
Prabir Pradhan65455c72024-02-13 21:46:41 +00009735 mDragWindow->consumeMotionMove(ADISPLAY_ID_DEFAULT, AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
arthurhung6d4bed92021-03-17 11:59:33 +08009736 mWindow->assertNoEvents();
9737 mSecondWindow->assertNoEvents();
Siarhei Vishniakoua66d65e2023-06-16 10:32:51 -07009738 mFakePolicy->assertDropTargetEquals(*mDispatcher, mSecondWindow->getToken());
arthurhung6d4bed92021-03-17 11:59:33 +08009739
9740 // nothing to the window.
9741 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07009742 injectMotionEvent(*mDispatcher,
arthurhung6d4bed92021-03-17 11:59:33 +08009743 MotionEventBuilder(AMOTION_EVENT_ACTION_UP, AINPUT_SOURCE_STYLUS)
9744 .buttonState(0)
Siarhei Vishniakou6d73f832022-07-21 17:27:03 -07009745 .pointer(PointerBuilder(0, ToolType::STYLUS).x(150).y(50))
arthurhung6d4bed92021-03-17 11:59:33 +08009746 .build()))
9747 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
Prabir Pradhan65455c72024-02-13 21:46:41 +00009748 mDragWindow->consumeMotionUp(ADISPLAY_ID_DEFAULT, AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
arthurhung6d4bed92021-03-17 11:59:33 +08009749 mWindow->assertNoEvents();
9750 mSecondWindow->assertNoEvents();
9751}
9752
Arthur Hung54745652022-04-20 07:17:41 +00009753TEST_F(InputDispatcherDragTests, DragAndDropOnInvalidWindow) {
Arthur Hungb75c2aa2022-07-15 09:35:36 +00009754 startDrag();
Arthur Hung6d0571e2021-04-09 20:18:16 +08009755
9756 // Set second window invisible.
9757 mSecondWindow->setVisible(false);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07009758 mDispatcher->onWindowInfosChanged(
9759 {{*mDragWindow->getInfo(), *mWindow->getInfo(), *mSecondWindow->getInfo()}, {}, 0, 0});
Arthur Hung6d0571e2021-04-09 20:18:16 +08009760
9761 // Move on window.
9762 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07009763 injectMotionEvent(*mDispatcher, AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN,
Arthur Hung6d0571e2021-04-09 20:18:16 +08009764 ADISPLAY_ID_DEFAULT, {50, 50}))
9765 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
Prabir Pradhan65455c72024-02-13 21:46:41 +00009766 mDragWindow->consumeMotionMove(ADISPLAY_ID_DEFAULT, AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
Arthur Hung6d0571e2021-04-09 20:18:16 +08009767 mWindow->consumeDragEvent(false, 50, 50);
9768 mSecondWindow->assertNoEvents();
9769
9770 // Move to another window.
9771 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07009772 injectMotionEvent(*mDispatcher, AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN,
Arthur Hung6d0571e2021-04-09 20:18:16 +08009773 ADISPLAY_ID_DEFAULT, {150, 50}))
9774 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
Prabir Pradhan65455c72024-02-13 21:46:41 +00009775 mDragWindow->consumeMotionMove(ADISPLAY_ID_DEFAULT, AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
Arthur Hung6d0571e2021-04-09 20:18:16 +08009776 mWindow->consumeDragEvent(true, 150, 50);
9777 mSecondWindow->assertNoEvents();
9778
9779 // drop to another window.
9780 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07009781 injectMotionUp(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
Arthur Hung6d0571e2021-04-09 20:18:16 +08009782 {150, 50}))
9783 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
Prabir Pradhan65455c72024-02-13 21:46:41 +00009784 mDragWindow->consumeMotionUp(ADISPLAY_ID_DEFAULT, AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
Siarhei Vishniakoua66d65e2023-06-16 10:32:51 -07009785 mFakePolicy->assertDropTargetEquals(*mDispatcher, nullptr);
Arthur Hung6d0571e2021-04-09 20:18:16 +08009786 mWindow->assertNoEvents();
9787 mSecondWindow->assertNoEvents();
9788}
9789
Arthur Hung54745652022-04-20 07:17:41 +00009790TEST_F(InputDispatcherDragTests, NoDragAndDropWhenMultiFingers) {
Arthur Hungb75c2aa2022-07-15 09:35:36 +00009791 // Ensure window could track pointerIds if it didn't support split touch.
9792 mWindow->setPreventSplitting(true);
9793
Arthur Hung54745652022-04-20 07:17:41 +00009794 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07009795 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
Arthur Hung54745652022-04-20 07:17:41 +00009796 {50, 50}))
9797 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
9798 mWindow->consumeMotionDown(ADISPLAY_ID_DEFAULT);
9799
9800 const MotionEvent secondFingerDownEvent =
9801 MotionEventBuilder(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
9802 .displayId(ADISPLAY_ID_DEFAULT)
9803 .eventTime(systemTime(SYSTEM_TIME_MONOTONIC))
Siarhei Vishniakou6d73f832022-07-21 17:27:03 -07009804 .pointer(PointerBuilder(/*id=*/0, ToolType::FINGER).x(50).y(50))
9805 .pointer(PointerBuilder(/*id=*/1, ToolType::FINGER).x(75).y(50))
Arthur Hung54745652022-04-20 07:17:41 +00009806 .build();
9807 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07009808 injectMotionEvent(*mDispatcher, secondFingerDownEvent, INJECT_EVENT_TIMEOUT,
Arthur Hung54745652022-04-20 07:17:41 +00009809 InputEventInjectionSync::WAIT_FOR_RESULT))
9810 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
Harry Cutts33476232023-01-30 19:57:29 +00009811 mWindow->consumeMotionPointerDown(/*pointerIndex=*/1);
Arthur Hung54745652022-04-20 07:17:41 +00009812
9813 // Should not perform drag and drop when window has multi fingers.
Arthur Hungb75c2aa2022-07-15 09:35:36 +00009814 ASSERT_FALSE(startDrag(false));
Arthur Hung54745652022-04-20 07:17:41 +00009815}
9816
9817TEST_F(InputDispatcherDragTests, DragAndDropWhenSplitTouch) {
9818 // First down on second window.
9819 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07009820 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
Arthur Hung54745652022-04-20 07:17:41 +00009821 {150, 50}))
9822 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
9823
9824 mSecondWindow->consumeMotionDown(ADISPLAY_ID_DEFAULT);
9825
9826 // Second down on first window.
9827 const MotionEvent secondFingerDownEvent =
9828 MotionEventBuilder(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
9829 .displayId(ADISPLAY_ID_DEFAULT)
9830 .eventTime(systemTime(SYSTEM_TIME_MONOTONIC))
Siarhei Vishniakou6d73f832022-07-21 17:27:03 -07009831 .pointer(PointerBuilder(/*id=*/0, ToolType::FINGER).x(150).y(50))
9832 .pointer(PointerBuilder(/*id=*/1, ToolType::FINGER).x(50).y(50))
Arthur Hung54745652022-04-20 07:17:41 +00009833 .build();
9834 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07009835 injectMotionEvent(*mDispatcher, secondFingerDownEvent, INJECT_EVENT_TIMEOUT,
Arthur Hung54745652022-04-20 07:17:41 +00009836 InputEventInjectionSync::WAIT_FOR_RESULT))
9837 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
9838 mWindow->consumeMotionDown(ADISPLAY_ID_DEFAULT);
Prabir Pradhan9d5f9ce2024-01-24 00:03:41 +00009839 mSecondWindow->consumeMotionMove(ADISPLAY_ID_DEFAULT);
Arthur Hung54745652022-04-20 07:17:41 +00009840
9841 // Perform drag and drop from first window.
Arthur Hungb75c2aa2022-07-15 09:35:36 +00009842 ASSERT_TRUE(startDrag(false));
Arthur Hung54745652022-04-20 07:17:41 +00009843
9844 // Move on window.
9845 const MotionEvent secondFingerMoveEvent =
9846 MotionEventBuilder(AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN)
9847 .eventTime(systemTime(SYSTEM_TIME_MONOTONIC))
Siarhei Vishniakou6d73f832022-07-21 17:27:03 -07009848 .pointer(PointerBuilder(/*id=*/0, ToolType::FINGER).x(150).y(50))
9849 .pointer(PointerBuilder(/*id=*/1, ToolType::FINGER).x(50).y(50))
Arthur Hung54745652022-04-20 07:17:41 +00009850 .build();
9851 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07009852 injectMotionEvent(*mDispatcher, secondFingerMoveEvent, INJECT_EVENT_TIMEOUT,
Arthur Hung54745652022-04-20 07:17:41 +00009853 InputEventInjectionSync::WAIT_FOR_RESULT));
Prabir Pradhan65455c72024-02-13 21:46:41 +00009854 mDragWindow->consumeMotionMove(ADISPLAY_ID_DEFAULT, AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
Arthur Hung54745652022-04-20 07:17:41 +00009855 mWindow->consumeDragEvent(false, 50, 50);
9856 mSecondWindow->consumeMotionMove();
9857
9858 // Release the drag pointer should perform drop.
9859 const MotionEvent secondFingerUpEvent =
9860 MotionEventBuilder(POINTER_1_UP, AINPUT_SOURCE_TOUCHSCREEN)
9861 .eventTime(systemTime(SYSTEM_TIME_MONOTONIC))
Siarhei Vishniakou6d73f832022-07-21 17:27:03 -07009862 .pointer(PointerBuilder(/*id=*/0, ToolType::FINGER).x(150).y(50))
9863 .pointer(PointerBuilder(/*id=*/1, ToolType::FINGER).x(50).y(50))
Arthur Hung54745652022-04-20 07:17:41 +00009864 .build();
9865 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07009866 injectMotionEvent(*mDispatcher, secondFingerUpEvent, INJECT_EVENT_TIMEOUT,
Arthur Hung54745652022-04-20 07:17:41 +00009867 InputEventInjectionSync::WAIT_FOR_RESULT));
Prabir Pradhan65455c72024-02-13 21:46:41 +00009868 mDragWindow->consumeMotionUp(ADISPLAY_ID_DEFAULT, AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
Siarhei Vishniakoua66d65e2023-06-16 10:32:51 -07009869 mFakePolicy->assertDropTargetEquals(*mDispatcher, mWindow->getToken());
Arthur Hung54745652022-04-20 07:17:41 +00009870 mWindow->assertNoEvents();
9871 mSecondWindow->consumeMotionMove();
9872}
9873
Arthur Hung3915c1f2022-05-31 07:17:17 +00009874TEST_F(InputDispatcherDragTests, DragAndDropWhenMultiDisplays) {
Arthur Hungb75c2aa2022-07-15 09:35:36 +00009875 startDrag();
Arthur Hung3915c1f2022-05-31 07:17:17 +00009876
9877 // Update window of second display.
9878 sp<FakeWindowHandle> windowInSecondary =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07009879 sp<FakeWindowHandle>::make(mApp, mDispatcher, "D_2", SECOND_DISPLAY_ID);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07009880 mDispatcher->onWindowInfosChanged(
9881 {{*mDragWindow->getInfo(), *mSpyWindow->getInfo(), *mWindow->getInfo(),
9882 *mSecondWindow->getInfo(), *windowInSecondary->getInfo()},
9883 {},
9884 0,
9885 0});
Arthur Hung3915c1f2022-05-31 07:17:17 +00009886
9887 // Let second display has a touch state.
9888 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07009889 injectMotionEvent(*mDispatcher,
Arthur Hung3915c1f2022-05-31 07:17:17 +00009890 MotionEventBuilder(AMOTION_EVENT_ACTION_DOWN,
9891 AINPUT_SOURCE_TOUCHSCREEN)
9892 .displayId(SECOND_DISPLAY_ID)
Siarhei Vishniakou6d73f832022-07-21 17:27:03 -07009893 .pointer(PointerBuilder(0, ToolType::FINGER).x(100).y(100))
Arthur Hung3915c1f2022-05-31 07:17:17 +00009894 .build()));
Prabir Pradhan7662a8d2023-12-15 01:58:14 +00009895 windowInSecondary->consumeMotionDown(SECOND_DISPLAY_ID, /*expectedFlag=*/0);
Arthur Hung3915c1f2022-05-31 07:17:17 +00009896 // Update window again.
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07009897 mDispatcher->onWindowInfosChanged(
9898 {{*mDragWindow->getInfo(), *mSpyWindow->getInfo(), *mWindow->getInfo(),
9899 *mSecondWindow->getInfo(), *windowInSecondary->getInfo()},
9900 {},
9901 0,
9902 0});
Arthur Hung3915c1f2022-05-31 07:17:17 +00009903
9904 // Move on window.
9905 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07009906 injectMotionEvent(*mDispatcher, AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN,
Arthur Hung3915c1f2022-05-31 07:17:17 +00009907 ADISPLAY_ID_DEFAULT, {50, 50}))
9908 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
Prabir Pradhan65455c72024-02-13 21:46:41 +00009909 mDragWindow->consumeMotionMove(ADISPLAY_ID_DEFAULT, AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
Arthur Hung3915c1f2022-05-31 07:17:17 +00009910 mWindow->consumeDragEvent(false, 50, 50);
9911 mSecondWindow->assertNoEvents();
9912
9913 // Move to another window.
9914 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07009915 injectMotionEvent(*mDispatcher, AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN,
Arthur Hung3915c1f2022-05-31 07:17:17 +00009916 ADISPLAY_ID_DEFAULT, {150, 50}))
9917 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
Prabir Pradhan65455c72024-02-13 21:46:41 +00009918 mDragWindow->consumeMotionMove(ADISPLAY_ID_DEFAULT, AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
Arthur Hung3915c1f2022-05-31 07:17:17 +00009919 mWindow->consumeDragEvent(true, 150, 50);
9920 mSecondWindow->consumeDragEvent(false, 50, 50);
9921
9922 // drop to another window.
9923 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07009924 injectMotionUp(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
Arthur Hung3915c1f2022-05-31 07:17:17 +00009925 {150, 50}))
9926 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
Prabir Pradhan65455c72024-02-13 21:46:41 +00009927 mDragWindow->consumeMotionUp(ADISPLAY_ID_DEFAULT, AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
Siarhei Vishniakoua66d65e2023-06-16 10:32:51 -07009928 mFakePolicy->assertDropTargetEquals(*mDispatcher, mSecondWindow->getToken());
Arthur Hung3915c1f2022-05-31 07:17:17 +00009929 mWindow->assertNoEvents();
9930 mSecondWindow->assertNoEvents();
9931}
9932
Arthur Hungb75c2aa2022-07-15 09:35:36 +00009933TEST_F(InputDispatcherDragTests, MouseDragAndDrop) {
9934 startDrag(true, AINPUT_SOURCE_MOUSE);
9935 // Move on window.
9936 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07009937 injectMotionEvent(*mDispatcher,
Arthur Hungb75c2aa2022-07-15 09:35:36 +00009938 MotionEventBuilder(AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_MOUSE)
9939 .buttonState(AMOTION_EVENT_BUTTON_PRIMARY)
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07009940 .pointer(PointerBuilder(MOUSE_POINTER_ID, ToolType::MOUSE)
Arthur Hungb75c2aa2022-07-15 09:35:36 +00009941 .x(50)
9942 .y(50))
9943 .build()))
9944 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
Prabir Pradhan65455c72024-02-13 21:46:41 +00009945 mDragWindow->consumeMotionMove(ADISPLAY_ID_DEFAULT, AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
Arthur Hungb75c2aa2022-07-15 09:35:36 +00009946 mWindow->consumeDragEvent(false, 50, 50);
9947 mSecondWindow->assertNoEvents();
9948
9949 // Move to another window.
9950 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07009951 injectMotionEvent(*mDispatcher,
Arthur Hungb75c2aa2022-07-15 09:35:36 +00009952 MotionEventBuilder(AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_MOUSE)
9953 .buttonState(AMOTION_EVENT_BUTTON_PRIMARY)
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07009954 .pointer(PointerBuilder(MOUSE_POINTER_ID, ToolType::MOUSE)
Arthur Hungb75c2aa2022-07-15 09:35:36 +00009955 .x(150)
9956 .y(50))
9957 .build()))
9958 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
Prabir Pradhan65455c72024-02-13 21:46:41 +00009959 mDragWindow->consumeMotionMove(ADISPLAY_ID_DEFAULT, AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
Arthur Hungb75c2aa2022-07-15 09:35:36 +00009960 mWindow->consumeDragEvent(true, 150, 50);
9961 mSecondWindow->consumeDragEvent(false, 50, 50);
9962
9963 // drop to another window.
9964 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07009965 injectMotionEvent(*mDispatcher,
Arthur Hungb75c2aa2022-07-15 09:35:36 +00009966 MotionEventBuilder(AMOTION_EVENT_ACTION_UP, AINPUT_SOURCE_MOUSE)
9967 .buttonState(0)
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07009968 .pointer(PointerBuilder(MOUSE_POINTER_ID, ToolType::MOUSE)
Arthur Hungb75c2aa2022-07-15 09:35:36 +00009969 .x(150)
9970 .y(50))
9971 .build()))
9972 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
Prabir Pradhan65455c72024-02-13 21:46:41 +00009973 mDragWindow->consumeMotionUp(ADISPLAY_ID_DEFAULT, AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
Siarhei Vishniakoua66d65e2023-06-16 10:32:51 -07009974 mFakePolicy->assertDropTargetEquals(*mDispatcher, mSecondWindow->getToken());
Arthur Hungb75c2aa2022-07-15 09:35:36 +00009975 mWindow->assertNoEvents();
9976 mSecondWindow->assertNoEvents();
9977}
9978
Linnan Li5af92f92023-07-14 14:36:22 +08009979/**
9980 * Start drag and drop with a pointer whose id is not 0, cancel the current touch, and ensure drag
9981 * and drop is also canceled. Then inject a simple gesture, and ensure dispatcher does not crash.
9982 */
9983TEST_F(InputDispatcherDragTests, DragAndDropFinishedWhenCancelCurrentTouch) {
9984 // Down on second window
9985 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
9986 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
9987 {150, 50}))
9988 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
9989
9990 ASSERT_NO_FATAL_FAILURE(mSecondWindow->consumeMotionDown());
9991 ASSERT_NO_FATAL_FAILURE(mSpyWindow->consumeMotionDown());
9992
9993 // Down on first window
9994 const MotionEvent secondFingerDownEvent =
9995 MotionEventBuilder(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
9996 .displayId(ADISPLAY_ID_DEFAULT)
9997 .pointer(PointerBuilder(/*id=*/0, ToolType::FINGER).x(150).y(50))
9998 .pointer(PointerBuilder(/*id=*/1, ToolType::FINGER).x(50).y(50))
9999 .build();
10000 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
10001 injectMotionEvent(*mDispatcher, secondFingerDownEvent, INJECT_EVENT_TIMEOUT,
10002 InputEventInjectionSync::WAIT_FOR_RESULT))
10003 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
10004 ASSERT_NO_FATAL_FAILURE(mWindow->consumeMotionDown());
10005 ASSERT_NO_FATAL_FAILURE(mSecondWindow->consumeMotionMove());
10006 ASSERT_NO_FATAL_FAILURE(mSpyWindow->consumeMotionPointerDown(1));
10007
10008 // Start drag on first window
10009 ASSERT_TRUE(startDrag(/*sendDown=*/false, AINPUT_SOURCE_TOUCHSCREEN));
10010
10011 // Trigger cancel
10012 mDispatcher->cancelCurrentTouch();
10013 ASSERT_NO_FATAL_FAILURE(mSecondWindow->consumeMotionCancel());
Prabir Pradhan65455c72024-02-13 21:46:41 +000010014 ASSERT_NO_FATAL_FAILURE(mDragWindow->consumeMotionCancel(ADISPLAY_ID_DEFAULT,
10015 AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE));
Linnan Li5af92f92023-07-14 14:36:22 +080010016 ASSERT_NO_FATAL_FAILURE(mSpyWindow->consumeMotionCancel());
10017
10018 ASSERT_TRUE(mDispatcher->waitForIdle());
10019 // The D&D finished with nullptr
10020 mFakePolicy->assertDropTargetEquals(*mDispatcher, nullptr);
10021
10022 // Remove drag window
10023 mDispatcher->onWindowInfosChanged({{*mWindow->getInfo(), *mSecondWindow->getInfo()}, {}, 0, 0});
10024
10025 // Inject a simple gesture, ensure dispatcher not crashed
10026 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
10027 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
10028 PointF{50, 50}))
10029 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
10030 ASSERT_NO_FATAL_FAILURE(mWindow->consumeMotionDown());
10031
10032 const MotionEvent moveEvent =
10033 MotionEventBuilder(AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN)
10034 .displayId(ADISPLAY_ID_DEFAULT)
10035 .pointer(PointerBuilder(/*id=*/0, ToolType::FINGER).x(50).y(50))
10036 .build();
10037 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
10038 injectMotionEvent(*mDispatcher, moveEvent, INJECT_EVENT_TIMEOUT,
10039 InputEventInjectionSync::WAIT_FOR_RESULT))
10040 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
10041 ASSERT_NO_FATAL_FAILURE(mWindow->consumeMotionMove());
10042
10043 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
10044 injectMotionUp(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
10045 {50, 50}))
10046 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
10047 ASSERT_NO_FATAL_FAILURE(mWindow->consumeMotionUp());
10048}
10049
Prabir Pradhan9cd9eb62023-11-22 17:58:06 +000010050TEST_F(InputDispatcherDragTests, NoDragAndDropWithHoveringPointer) {
10051 // Start hovering over the window.
10052 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
10053 injectMotionEvent(*mDispatcher, ACTION_HOVER_ENTER, AINPUT_SOURCE_MOUSE,
10054 ADISPLAY_ID_DEFAULT, {50, 50}));
10055
10056 ASSERT_NO_FATAL_FAILURE(mWindow->consumeMotionEvent(WithMotionAction(ACTION_HOVER_ENTER)));
10057 ASSERT_NO_FATAL_FAILURE(mSpyWindow->consumeMotionEvent(WithMotionAction(ACTION_HOVER_ENTER)));
10058
10059 ASSERT_FALSE(startDrag(/*sendDown=*/false))
10060 << "Drag and drop should not work with a hovering pointer";
10061}
10062
Vishnu Nair062a8672021-09-03 16:07:44 -070010063class InputDispatcherDropInputFeatureTest : public InputDispatcherTest {};
10064
10065TEST_F(InputDispatcherDropInputFeatureTest, WindowDropsInput) {
10066 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -070010067 sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher,
10068 "Test window", ADISPLAY_ID_DEFAULT);
Prabir Pradhan51e7db02022-02-07 06:02:57 -080010069 window->setDropInput(true);
Vishnu Nair062a8672021-09-03 16:07:44 -070010070 mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application);
10071 window->setFocusable(true);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070010072 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Vishnu Nair062a8672021-09-03 16:07:44 -070010073 setFocusedWindow(window);
Harry Cutts33476232023-01-30 19:57:29 +000010074 window->consumeFocusEvent(/*hasFocus=*/true, /*inTouchMode=*/true);
Vishnu Nair062a8672021-09-03 16:07:44 -070010075
10076 // With the flag set, window should not get any input
Prabir Pradhan678438e2023-04-13 19:32:51 +000010077 mDispatcher->notifyKey(generateKeyArgs(AKEY_EVENT_ACTION_DOWN, ADISPLAY_ID_DEFAULT));
Vishnu Nair062a8672021-09-03 16:07:44 -070010078 window->assertNoEvents();
10079
Prabir Pradhan678438e2023-04-13 19:32:51 +000010080 mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_DOWN,
10081 AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT));
Siarhei Vishniakou5c02a712023-05-15 15:45:02 -070010082 mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN,
10083 ADISPLAY_ID_DEFAULT));
Siarhei Vishniakoud908f5a2023-11-16 10:25:12 -080010084 mDispatcher->waitForIdle();
Vishnu Nair062a8672021-09-03 16:07:44 -070010085 window->assertNoEvents();
10086
10087 // With the flag cleared, the window should get input
Prabir Pradhan51e7db02022-02-07 06:02:57 -080010088 window->setDropInput(false);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070010089 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Vishnu Nair062a8672021-09-03 16:07:44 -070010090
Prabir Pradhan678438e2023-04-13 19:32:51 +000010091 mDispatcher->notifyKey(generateKeyArgs(AKEY_EVENT_ACTION_UP, ADISPLAY_ID_DEFAULT));
Vishnu Nair062a8672021-09-03 16:07:44 -070010092 window->consumeKeyUp(ADISPLAY_ID_DEFAULT);
10093
Prabir Pradhan678438e2023-04-13 19:32:51 +000010094 mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_DOWN,
10095 AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT));
Vishnu Nair062a8672021-09-03 16:07:44 -070010096 window->consumeMotionDown(ADISPLAY_ID_DEFAULT);
10097 window->assertNoEvents();
10098}
10099
10100TEST_F(InputDispatcherDropInputFeatureTest, ObscuredWindowDropsInput) {
10101 std::shared_ptr<FakeApplicationHandle> obscuringApplication =
10102 std::make_shared<FakeApplicationHandle>();
10103 sp<FakeWindowHandle> obscuringWindow =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -070010104 sp<FakeWindowHandle>::make(obscuringApplication, mDispatcher, "obscuringWindow",
10105 ADISPLAY_ID_DEFAULT);
Vishnu Nair062a8672021-09-03 16:07:44 -070010106 obscuringWindow->setFrame(Rect(0, 0, 50, 50));
Prabir Pradhanaeebeb42023-06-13 19:53:03 +000010107 obscuringWindow->setOwnerInfo(gui::Pid{111}, gui::Uid{111});
Prabir Pradhan4d5c52f2022-01-31 08:52:10 -080010108 obscuringWindow->setTouchable(false);
Vishnu Nair062a8672021-09-03 16:07:44 -070010109 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -070010110 sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher,
10111 "Test window", ADISPLAY_ID_DEFAULT);
Prabir Pradhan51e7db02022-02-07 06:02:57 -080010112 window->setDropInputIfObscured(true);
Prabir Pradhanaeebeb42023-06-13 19:53:03 +000010113 window->setOwnerInfo(gui::Pid{222}, gui::Uid{222});
Vishnu Nair062a8672021-09-03 16:07:44 -070010114 mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application);
10115 window->setFocusable(true);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070010116 mDispatcher->onWindowInfosChanged(
10117 {{*obscuringWindow->getInfo(), *window->getInfo()}, {}, 0, 0});
Vishnu Nair062a8672021-09-03 16:07:44 -070010118 setFocusedWindow(window);
Harry Cutts33476232023-01-30 19:57:29 +000010119 window->consumeFocusEvent(/*hasFocus=*/true, /*inTouchMode=*/true);
Vishnu Nair062a8672021-09-03 16:07:44 -070010120
10121 // With the flag set, window should not get any input
Prabir Pradhan678438e2023-04-13 19:32:51 +000010122 mDispatcher->notifyKey(generateKeyArgs(AKEY_EVENT_ACTION_DOWN, ADISPLAY_ID_DEFAULT));
Vishnu Nair062a8672021-09-03 16:07:44 -070010123 window->assertNoEvents();
10124
Prabir Pradhan678438e2023-04-13 19:32:51 +000010125 mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_DOWN,
10126 AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT));
Siarhei Vishniakou5c02a712023-05-15 15:45:02 -070010127 mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN,
10128 ADISPLAY_ID_DEFAULT));
Vishnu Nair062a8672021-09-03 16:07:44 -070010129 window->assertNoEvents();
10130
10131 // With the flag cleared, the window should get input
Prabir Pradhan51e7db02022-02-07 06:02:57 -080010132 window->setDropInputIfObscured(false);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070010133 mDispatcher->onWindowInfosChanged(
10134 {{*obscuringWindow->getInfo(), *window->getInfo()}, {}, 0, 0});
Vishnu Nair062a8672021-09-03 16:07:44 -070010135
Prabir Pradhan678438e2023-04-13 19:32:51 +000010136 mDispatcher->notifyKey(generateKeyArgs(AKEY_EVENT_ACTION_UP, ADISPLAY_ID_DEFAULT));
Vishnu Nair062a8672021-09-03 16:07:44 -070010137 window->consumeKeyUp(ADISPLAY_ID_DEFAULT);
10138
Prabir Pradhan678438e2023-04-13 19:32:51 +000010139 mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_DOWN,
10140 AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT));
Vishnu Nair062a8672021-09-03 16:07:44 -070010141 window->consumeMotionDown(ADISPLAY_ID_DEFAULT, AMOTION_EVENT_FLAG_WINDOW_IS_PARTIALLY_OBSCURED);
10142 window->assertNoEvents();
10143}
10144
10145TEST_F(InputDispatcherDropInputFeatureTest, UnobscuredWindowGetsInput) {
10146 std::shared_ptr<FakeApplicationHandle> obscuringApplication =
10147 std::make_shared<FakeApplicationHandle>();
10148 sp<FakeWindowHandle> obscuringWindow =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -070010149 sp<FakeWindowHandle>::make(obscuringApplication, mDispatcher, "obscuringWindow",
10150 ADISPLAY_ID_DEFAULT);
Vishnu Nair062a8672021-09-03 16:07:44 -070010151 obscuringWindow->setFrame(Rect(0, 0, 50, 50));
Prabir Pradhanaeebeb42023-06-13 19:53:03 +000010152 obscuringWindow->setOwnerInfo(gui::Pid{111}, gui::Uid{111});
Prabir Pradhan4d5c52f2022-01-31 08:52:10 -080010153 obscuringWindow->setTouchable(false);
Vishnu Nair062a8672021-09-03 16:07:44 -070010154 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -070010155 sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher,
10156 "Test window", ADISPLAY_ID_DEFAULT);
Prabir Pradhan51e7db02022-02-07 06:02:57 -080010157 window->setDropInputIfObscured(true);
Prabir Pradhanaeebeb42023-06-13 19:53:03 +000010158 window->setOwnerInfo(gui::Pid{222}, gui::Uid{222});
Vishnu Nair062a8672021-09-03 16:07:44 -070010159 mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application);
10160 window->setFocusable(true);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070010161 mDispatcher->onWindowInfosChanged(
10162 {{*obscuringWindow->getInfo(), *window->getInfo()}, {}, 0, 0});
Vishnu Nair062a8672021-09-03 16:07:44 -070010163 setFocusedWindow(window);
Harry Cutts33476232023-01-30 19:57:29 +000010164 window->consumeFocusEvent(/*hasFocus=*/true, /*inTouchMode=*/true);
Vishnu Nair062a8672021-09-03 16:07:44 -070010165
10166 // With the flag set, window should not get any input
Prabir Pradhan678438e2023-04-13 19:32:51 +000010167 mDispatcher->notifyKey(generateKeyArgs(AKEY_EVENT_ACTION_DOWN, ADISPLAY_ID_DEFAULT));
Vishnu Nair062a8672021-09-03 16:07:44 -070010168 window->assertNoEvents();
10169
Prabir Pradhan678438e2023-04-13 19:32:51 +000010170 mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_DOWN,
10171 AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT));
Siarhei Vishniakou5c02a712023-05-15 15:45:02 -070010172 mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN,
10173 ADISPLAY_ID_DEFAULT));
Vishnu Nair062a8672021-09-03 16:07:44 -070010174 window->assertNoEvents();
10175
10176 // When the window is no longer obscured because it went on top, it should get input
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070010177 mDispatcher->onWindowInfosChanged(
10178 {{*window->getInfo(), *obscuringWindow->getInfo()}, {}, 0, 0});
Vishnu Nair062a8672021-09-03 16:07:44 -070010179
Prabir Pradhan678438e2023-04-13 19:32:51 +000010180 mDispatcher->notifyKey(generateKeyArgs(AKEY_EVENT_ACTION_UP, ADISPLAY_ID_DEFAULT));
Vishnu Nair062a8672021-09-03 16:07:44 -070010181 window->consumeKeyUp(ADISPLAY_ID_DEFAULT);
10182
Prabir Pradhan678438e2023-04-13 19:32:51 +000010183 mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_DOWN,
10184 AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT));
Vishnu Nair062a8672021-09-03 16:07:44 -070010185 window->consumeMotionDown(ADISPLAY_ID_DEFAULT);
10186 window->assertNoEvents();
10187}
10188
Antonio Kantekf16f2832021-09-28 04:39:20 +000010189class InputDispatcherTouchModeChangedTests : public InputDispatcherTest {
10190protected:
10191 std::shared_ptr<FakeApplicationHandle> mApp;
Antonio Kantek15beb512022-06-13 22:35:41 +000010192 std::shared_ptr<FakeApplicationHandle> mSecondaryApp;
Antonio Kantekf16f2832021-09-28 04:39:20 +000010193 sp<FakeWindowHandle> mWindow;
10194 sp<FakeWindowHandle> mSecondWindow;
Antonio Kantek15beb512022-06-13 22:35:41 +000010195 sp<FakeWindowHandle> mThirdWindow;
Antonio Kantekf16f2832021-09-28 04:39:20 +000010196
10197 void SetUp() override {
10198 InputDispatcherTest::SetUp();
10199
10200 mApp = std::make_shared<FakeApplicationHandle>();
Antonio Kantek15beb512022-06-13 22:35:41 +000010201 mSecondaryApp = std::make_shared<FakeApplicationHandle>();
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -070010202 mWindow = sp<FakeWindowHandle>::make(mApp, mDispatcher, "TestWindow", ADISPLAY_ID_DEFAULT);
Antonio Kantekf16f2832021-09-28 04:39:20 +000010203 mWindow->setFocusable(true);
Antonio Kantek26defcf2022-02-08 01:12:27 +000010204 setFocusedWindow(mWindow);
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -070010205 mSecondWindow =
10206 sp<FakeWindowHandle>::make(mApp, mDispatcher, "TestWindow2", ADISPLAY_ID_DEFAULT);
Antonio Kantekf16f2832021-09-28 04:39:20 +000010207 mSecondWindow->setFocusable(true);
Antonio Kantek15beb512022-06-13 22:35:41 +000010208 mThirdWindow =
10209 sp<FakeWindowHandle>::make(mSecondaryApp, mDispatcher,
10210 "TestWindow3_SecondaryDisplay", SECOND_DISPLAY_ID);
10211 mThirdWindow->setFocusable(true);
Antonio Kantekf16f2832021-09-28 04:39:20 +000010212
10213 mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, mApp);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070010214 mDispatcher->onWindowInfosChanged(
10215 {{*mWindow->getInfo(), *mSecondWindow->getInfo(), *mThirdWindow->getInfo()},
10216 {},
10217 0,
10218 0});
Antonio Kantek15beb512022-06-13 22:35:41 +000010219 mThirdWindow->setOwnerInfo(SECONDARY_WINDOW_PID, SECONDARY_WINDOW_UID);
Antonio Kantekf16f2832021-09-28 04:39:20 +000010220 mWindow->consumeFocusEvent(true);
Antonio Kantek26defcf2022-02-08 01:12:27 +000010221
Antonio Kantek15beb512022-06-13 22:35:41 +000010222 // Set main display initial touch mode to InputDispatcher::kDefaultInTouchMode.
Prabir Pradhan5735a322022-04-11 17:23:34 +000010223 if (mDispatcher->setInTouchMode(InputDispatcher::kDefaultInTouchMode, WINDOW_PID,
Harry Cutts33476232023-01-30 19:57:29 +000010224 WINDOW_UID, /*hasPermission=*/true, ADISPLAY_ID_DEFAULT)) {
Antonio Kantek48710e42022-03-24 14:19:30 -070010225 mWindow->consumeTouchModeEvent(InputDispatcher::kDefaultInTouchMode);
10226 mSecondWindow->consumeTouchModeEvent(InputDispatcher::kDefaultInTouchMode);
Antonio Kantek15beb512022-06-13 22:35:41 +000010227 mThirdWindow->assertNoEvents();
10228 }
10229
10230 // Set secondary display initial touch mode to InputDispatcher::kDefaultInTouchMode.
10231 if (mDispatcher->setInTouchMode(InputDispatcher::kDefaultInTouchMode, SECONDARY_WINDOW_PID,
Harry Cutts33476232023-01-30 19:57:29 +000010232 SECONDARY_WINDOW_UID, /*hasPermission=*/true,
Antonio Kantek15beb512022-06-13 22:35:41 +000010233 SECOND_DISPLAY_ID)) {
10234 mWindow->assertNoEvents();
10235 mSecondWindow->assertNoEvents();
10236 mThirdWindow->consumeTouchModeEvent(InputDispatcher::kDefaultInTouchMode);
Antonio Kantek48710e42022-03-24 14:19:30 -070010237 }
Antonio Kantekf16f2832021-09-28 04:39:20 +000010238 }
10239
Prabir Pradhanaeebeb42023-06-13 19:53:03 +000010240 void changeAndVerifyTouchModeInMainDisplayOnly(bool inTouchMode, gui::Pid pid, gui::Uid uid,
Antonio Kantek15beb512022-06-13 22:35:41 +000010241 bool hasPermission) {
Antonio Kanteka042c022022-07-06 16:51:07 -070010242 ASSERT_TRUE(mDispatcher->setInTouchMode(inTouchMode, pid, uid, hasPermission,
10243 ADISPLAY_ID_DEFAULT));
Antonio Kantekf16f2832021-09-28 04:39:20 +000010244 mWindow->consumeTouchModeEvent(inTouchMode);
10245 mSecondWindow->consumeTouchModeEvent(inTouchMode);
Antonio Kantek15beb512022-06-13 22:35:41 +000010246 mThirdWindow->assertNoEvents();
Antonio Kantekf16f2832021-09-28 04:39:20 +000010247 }
10248};
10249
Antonio Kantek26defcf2022-02-08 01:12:27 +000010250TEST_F(InputDispatcherTouchModeChangedTests, FocusedWindowCanChangeTouchMode) {
Antonio Kantekea47acb2021-12-23 12:41:25 -080010251 const WindowInfo& windowInfo = *mWindow->getInfo();
Antonio Kantek15beb512022-06-13 22:35:41 +000010252 changeAndVerifyTouchModeInMainDisplayOnly(!InputDispatcher::kDefaultInTouchMode,
10253 windowInfo.ownerPid, windowInfo.ownerUid,
Harry Cutts33476232023-01-30 19:57:29 +000010254 /* hasPermission=*/false);
Antonio Kantekf16f2832021-09-28 04:39:20 +000010255}
10256
Antonio Kantek26defcf2022-02-08 01:12:27 +000010257TEST_F(InputDispatcherTouchModeChangedTests, NonFocusedWindowOwnerCannotChangeTouchMode) {
10258 const WindowInfo& windowInfo = *mWindow->getInfo();
Prabir Pradhanaeebeb42023-06-13 19:53:03 +000010259 gui::Pid ownerPid = windowInfo.ownerPid;
Prabir Pradhan8a5c41d2023-06-08 19:13:46 +000010260 gui::Uid ownerUid = windowInfo.ownerUid;
Prabir Pradhanaeebeb42023-06-13 19:53:03 +000010261 mWindow->setOwnerInfo(gui::Pid::INVALID, gui::Uid::INVALID);
Antonio Kantek26defcf2022-02-08 01:12:27 +000010262 ASSERT_FALSE(mDispatcher->setInTouchMode(InputDispatcher::kDefaultInTouchMode, ownerPid,
Harry Cutts33476232023-01-30 19:57:29 +000010263 ownerUid, /*hasPermission=*/false,
Antonio Kanteka042c022022-07-06 16:51:07 -070010264 ADISPLAY_ID_DEFAULT));
Antonio Kantek26defcf2022-02-08 01:12:27 +000010265 mWindow->assertNoEvents();
10266 mSecondWindow->assertNoEvents();
10267}
10268
10269TEST_F(InputDispatcherTouchModeChangedTests, NonWindowOwnerMayChangeTouchModeOnPermissionGranted) {
10270 const WindowInfo& windowInfo = *mWindow->getInfo();
Prabir Pradhanaeebeb42023-06-13 19:53:03 +000010271 gui::Pid ownerPid = windowInfo.ownerPid;
Prabir Pradhan8a5c41d2023-06-08 19:13:46 +000010272 gui::Uid ownerUid = windowInfo.ownerUid;
Prabir Pradhanaeebeb42023-06-13 19:53:03 +000010273 mWindow->setOwnerInfo(gui::Pid::INVALID, gui::Uid::INVALID);
Antonio Kantek15beb512022-06-13 22:35:41 +000010274 changeAndVerifyTouchModeInMainDisplayOnly(!InputDispatcher::kDefaultInTouchMode, ownerPid,
Harry Cutts33476232023-01-30 19:57:29 +000010275 ownerUid, /*hasPermission=*/true);
Antonio Kantek26defcf2022-02-08 01:12:27 +000010276}
10277
Antonio Kantekf16f2832021-09-28 04:39:20 +000010278TEST_F(InputDispatcherTouchModeChangedTests, EventIsNotGeneratedIfNotChangingTouchMode) {
Antonio Kantekea47acb2021-12-23 12:41:25 -080010279 const WindowInfo& windowInfo = *mWindow->getInfo();
Antonio Kantek26defcf2022-02-08 01:12:27 +000010280 ASSERT_FALSE(mDispatcher->setInTouchMode(InputDispatcher::kDefaultInTouchMode,
10281 windowInfo.ownerPid, windowInfo.ownerUid,
Harry Cutts33476232023-01-30 19:57:29 +000010282 /*hasPermission=*/true, ADISPLAY_ID_DEFAULT));
Antonio Kantekf16f2832021-09-28 04:39:20 +000010283 mWindow->assertNoEvents();
10284 mSecondWindow->assertNoEvents();
10285}
10286
Antonio Kantek15beb512022-06-13 22:35:41 +000010287TEST_F(InputDispatcherTouchModeChangedTests, ChangeTouchOnSecondaryDisplayOnly) {
10288 const WindowInfo& windowInfo = *mThirdWindow->getInfo();
10289 ASSERT_TRUE(mDispatcher->setInTouchMode(!InputDispatcher::kDefaultInTouchMode,
10290 windowInfo.ownerPid, windowInfo.ownerUid,
Harry Cutts33476232023-01-30 19:57:29 +000010291 /*hasPermission=*/true, SECOND_DISPLAY_ID));
Antonio Kantek15beb512022-06-13 22:35:41 +000010292 mWindow->assertNoEvents();
10293 mSecondWindow->assertNoEvents();
10294 mThirdWindow->consumeTouchModeEvent(!InputDispatcher::kDefaultInTouchMode);
10295}
10296
Antonio Kantek48710e42022-03-24 14:19:30 -070010297TEST_F(InputDispatcherTouchModeChangedTests, CanChangeTouchModeWhenOwningLastInteractedWindow) {
10298 // Interact with the window first.
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070010299 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
10300 injectKeyDown(*mDispatcher, ADISPLAY_ID_DEFAULT))
Antonio Kantek48710e42022-03-24 14:19:30 -070010301 << "Inject key event should return InputEventInjectionResult::SUCCEEDED";
10302 mWindow->consumeKeyDown(ADISPLAY_ID_DEFAULT);
10303
10304 // Then remove focus.
10305 mWindow->setFocusable(false);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070010306 mDispatcher->onWindowInfosChanged({{*mWindow->getInfo()}, {}, 0, 0});
Antonio Kantek48710e42022-03-24 14:19:30 -070010307
10308 // Assert that caller can switch touch mode by owning one of the last interacted window.
10309 const WindowInfo& windowInfo = *mWindow->getInfo();
10310 ASSERT_TRUE(mDispatcher->setInTouchMode(!InputDispatcher::kDefaultInTouchMode,
10311 windowInfo.ownerPid, windowInfo.ownerUid,
Harry Cutts33476232023-01-30 19:57:29 +000010312 /*hasPermission=*/false, ADISPLAY_ID_DEFAULT));
Antonio Kantek48710e42022-03-24 14:19:30 -070010313}
10314
Prabir Pradhan07e05b62021-11-19 03:57:24 -080010315class InputDispatcherSpyWindowTest : public InputDispatcherTest {
10316public:
Prabir Pradhan4d5c52f2022-01-31 08:52:10 -080010317 sp<FakeWindowHandle> createSpy() {
Prabir Pradhan07e05b62021-11-19 03:57:24 -080010318 std::shared_ptr<FakeApplicationHandle> application =
10319 std::make_shared<FakeApplicationHandle>();
10320 std::string name = "Fake Spy ";
10321 name += std::to_string(mSpyCount++);
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -070010322 sp<FakeWindowHandle> spy = sp<FakeWindowHandle>::make(application, mDispatcher,
10323 name.c_str(), ADISPLAY_ID_DEFAULT);
Prabir Pradhan51e7db02022-02-07 06:02:57 -080010324 spy->setSpy(true);
Prabir Pradhan5c85e052021-12-22 02:27:12 -080010325 spy->setTrustedOverlay(true);
Prabir Pradhan07e05b62021-11-19 03:57:24 -080010326 return spy;
10327 }
10328
10329 sp<FakeWindowHandle> createForeground() {
10330 std::shared_ptr<FakeApplicationHandle> application =
10331 std::make_shared<FakeApplicationHandle>();
10332 sp<FakeWindowHandle> window =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -070010333 sp<FakeWindowHandle>::make(application, mDispatcher, "Fake Window",
10334 ADISPLAY_ID_DEFAULT);
Prabir Pradhan1376fcd2022-01-21 09:56:35 -080010335 window->setFocusable(true);
Prabir Pradhan07e05b62021-11-19 03:57:24 -080010336 return window;
10337 }
10338
10339private:
10340 int mSpyCount{0};
10341};
10342
Prabir Pradhana3ab87a2022-01-27 10:00:21 -080010343using InputDispatcherSpyWindowDeathTest = InputDispatcherSpyWindowTest;
Prabir Pradhan07e05b62021-11-19 03:57:24 -080010344/**
Prabir Pradhan5c85e052021-12-22 02:27:12 -080010345 * Adding a spy window that is not a trusted overlay causes Dispatcher to abort.
10346 */
Prabir Pradhana3ab87a2022-01-27 10:00:21 -080010347TEST_F(InputDispatcherSpyWindowDeathTest, UntrustedSpy_AbortsDispatcher) {
Siarhei Vishniakou21f77bd2023-07-18 17:51:35 -070010348 testing::GTEST_FLAG(death_test_style) = "threadsafe";
Prabir Pradhana3ab87a2022-01-27 10:00:21 -080010349 ScopedSilentDeath _silentDeath;
10350
Prabir Pradhan4d5c52f2022-01-31 08:52:10 -080010351 auto spy = createSpy();
Prabir Pradhan5c85e052021-12-22 02:27:12 -080010352 spy->setTrustedOverlay(false);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070010353 ASSERT_DEATH(mDispatcher->onWindowInfosChanged({{*spy->getInfo()}, {}, 0, 0}),
Prabir Pradhan5c85e052021-12-22 02:27:12 -080010354 ".* not a trusted overlay");
10355}
10356
10357/**
Prabir Pradhan07e05b62021-11-19 03:57:24 -080010358 * Input injection into a display with a spy window but no foreground windows should succeed.
10359 */
10360TEST_F(InputDispatcherSpyWindowTest, NoForegroundWindow) {
Prabir Pradhan4d5c52f2022-01-31 08:52:10 -080010361 auto spy = createSpy();
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070010362 mDispatcher->onWindowInfosChanged({{*spy->getInfo()}, {}, 0, 0});
Prabir Pradhan07e05b62021-11-19 03:57:24 -080010363
10364 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070010365 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT))
Prabir Pradhan07e05b62021-11-19 03:57:24 -080010366 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
10367 spy->consumeMotionDown(ADISPLAY_ID_DEFAULT);
10368}
10369
10370/**
10371 * Verify the order in which different input windows receive events. The touched foreground window
10372 * (if there is one) should always receive the event first. When there are multiple spy windows, the
10373 * spy windows will receive the event according to their Z-order, where the top-most spy window will
10374 * receive events before ones belows it.
10375 *
10376 * Here, we set up a scenario with four windows in the following Z order from the top:
10377 * spy1, spy2, window, spy3.
10378 * We then inject an event and verify that the foreground "window" receives it first, followed by
10379 * "spy1" and "spy2". The "spy3" does not receive the event because it is underneath the foreground
10380 * window.
10381 */
10382TEST_F(InputDispatcherSpyWindowTest, ReceivesInputInOrder) {
10383 auto window = createForeground();
Prabir Pradhan4d5c52f2022-01-31 08:52:10 -080010384 auto spy1 = createSpy();
10385 auto spy2 = createSpy();
10386 auto spy3 = createSpy();
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070010387 mDispatcher->onWindowInfosChanged(
10388 {{*spy1->getInfo(), *spy2->getInfo(), *window->getInfo(), *spy3->getInfo()}, {}, 0, 0});
Prabir Pradhan07e05b62021-11-19 03:57:24 -080010389 const std::vector<sp<FakeWindowHandle>> channels{spy1, spy2, window, spy3};
10390 const size_t numChannels = channels.size();
10391
Michael Wright8e9a8562022-02-09 13:44:29 +000010392 base::unique_fd epollFd(epoll_create1(EPOLL_CLOEXEC));
Prabir Pradhan07e05b62021-11-19 03:57:24 -080010393 if (!epollFd.ok()) {
10394 FAIL() << "Failed to create epoll fd";
10395 }
10396
10397 for (size_t i = 0; i < numChannels; i++) {
10398 struct epoll_event event = {.events = EPOLLIN, .data.u64 = i};
10399 if (epoll_ctl(epollFd.get(), EPOLL_CTL_ADD, channels[i]->getChannelFd(), &event) < 0) {
10400 FAIL() << "Failed to add fd to epoll";
10401 }
10402 }
10403
10404 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070010405 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT))
Prabir Pradhan07e05b62021-11-19 03:57:24 -080010406 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
10407
10408 std::vector<size_t> eventOrder;
10409 std::vector<struct epoll_event> events(numChannels);
10410 for (;;) {
10411 const int nFds = epoll_wait(epollFd.get(), events.data(), static_cast<int>(numChannels),
10412 (100ms).count());
10413 if (nFds < 0) {
10414 FAIL() << "Failed to call epoll_wait";
10415 }
10416 if (nFds == 0) {
10417 break; // epoll_wait timed out
10418 }
10419 for (int i = 0; i < nFds; i++) {
Colin Cross5b799302022-10-18 21:52:41 -070010420 ASSERT_EQ(static_cast<uint32_t>(EPOLLIN), events[i].events);
Siarhei Vishniakou31977182022-09-30 08:51:23 -070010421 eventOrder.push_back(static_cast<size_t>(events[i].data.u64));
Prabir Pradhan07e05b62021-11-19 03:57:24 -080010422 channels[i]->consumeMotionDown();
10423 }
10424 }
10425
10426 // Verify the order in which the events were received.
10427 EXPECT_EQ(3u, eventOrder.size());
10428 EXPECT_EQ(2u, eventOrder[0]); // index 2: window
10429 EXPECT_EQ(0u, eventOrder[1]); // index 0: spy1
10430 EXPECT_EQ(1u, eventOrder[2]); // index 1: spy2
10431}
10432
10433/**
10434 * A spy window using the NOT_TOUCHABLE flag does not receive events.
10435 */
10436TEST_F(InputDispatcherSpyWindowTest, NotTouchable) {
10437 auto window = createForeground();
Prabir Pradhan4d5c52f2022-01-31 08:52:10 -080010438 auto spy = createSpy();
10439 spy->setTouchable(false);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070010440 mDispatcher->onWindowInfosChanged({{*spy->getInfo(), *window->getInfo()}, {}, 0, 0});
Prabir Pradhan07e05b62021-11-19 03:57:24 -080010441
10442 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070010443 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT))
Prabir Pradhan07e05b62021-11-19 03:57:24 -080010444 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
10445 window->consumeMotionDown(ADISPLAY_ID_DEFAULT);
10446 spy->assertNoEvents();
10447}
10448
10449/**
10450 * A spy window will only receive gestures that originate within its touchable region. Gestures that
10451 * have their ACTION_DOWN outside of the touchable region of the spy window will not be dispatched
10452 * to the window.
10453 */
10454TEST_F(InputDispatcherSpyWindowTest, TouchableRegion) {
10455 auto window = createForeground();
Prabir Pradhan4d5c52f2022-01-31 08:52:10 -080010456 auto spy = createSpy();
Prabir Pradhan07e05b62021-11-19 03:57:24 -080010457 spy->setTouchableRegion(Region{{0, 0, 20, 20}});
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070010458 mDispatcher->onWindowInfosChanged({{*spy->getInfo(), *window->getInfo()}, {}, 0, 0});
Prabir Pradhan07e05b62021-11-19 03:57:24 -080010459
10460 // Inject an event outside the spy window's touchable region.
10461 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070010462 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT))
Prabir Pradhan07e05b62021-11-19 03:57:24 -080010463 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
10464 window->consumeMotionDown();
10465 spy->assertNoEvents();
10466 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070010467 injectMotionUp(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT))
Prabir Pradhan07e05b62021-11-19 03:57:24 -080010468 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
10469 window->consumeMotionUp();
10470 spy->assertNoEvents();
10471
10472 // Inject an event inside the spy window's touchable region.
10473 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070010474 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
Prabir Pradhan07e05b62021-11-19 03:57:24 -080010475 {5, 10}))
10476 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
10477 window->consumeMotionDown();
10478 spy->consumeMotionDown();
10479}
10480
10481/**
Prabir Pradhan07e05b62021-11-19 03:57:24 -080010482 * A spy window can listen for touches outside its touchable region using the WATCH_OUTSIDE_TOUCHES
Prabir Pradhandfabf8a2022-01-21 08:19:30 -080010483 * flag, but it will get zero-ed out coordinates if the foreground has a different owner.
Prabir Pradhan07e05b62021-11-19 03:57:24 -080010484 */
10485TEST_F(InputDispatcherSpyWindowTest, WatchOutsideTouches) {
10486 auto window = createForeground();
Prabir Pradhanaeebeb42023-06-13 19:53:03 +000010487 window->setOwnerInfo(gui::Pid{12}, gui::Uid{34});
Prabir Pradhan4d5c52f2022-01-31 08:52:10 -080010488 auto spy = createSpy();
10489 spy->setWatchOutsideTouch(true);
Prabir Pradhanaeebeb42023-06-13 19:53:03 +000010490 spy->setOwnerInfo(gui::Pid{56}, gui::Uid{78});
Prabir Pradhan07e05b62021-11-19 03:57:24 -080010491 spy->setFrame(Rect{0, 0, 20, 20});
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070010492 mDispatcher->onWindowInfosChanged({{*spy->getInfo(), *window->getInfo()}, {}, 0, 0});
Prabir Pradhan07e05b62021-11-19 03:57:24 -080010493
10494 // Inject an event outside the spy window's frame and touchable region.
10495 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070010496 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
Prabir Pradhandfabf8a2022-01-21 08:19:30 -080010497 {100, 200}))
Prabir Pradhan07e05b62021-11-19 03:57:24 -080010498 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
10499 window->consumeMotionDown();
Prabir Pradhandfabf8a2022-01-21 08:19:30 -080010500 spy->consumeMotionOutsideWithZeroedCoords();
Prabir Pradhan07e05b62021-11-19 03:57:24 -080010501}
10502
10503/**
Prabir Pradhan07e05b62021-11-19 03:57:24 -080010504 * Even when a spy window spans over multiple foreground windows, the spy should receive all
10505 * pointers that are down within its bounds.
10506 */
10507TEST_F(InputDispatcherSpyWindowTest, ReceivesMultiplePointers) {
10508 auto windowLeft = createForeground();
10509 windowLeft->setFrame({0, 0, 100, 200});
10510 auto windowRight = createForeground();
10511 windowRight->setFrame({100, 0, 200, 200});
Prabir Pradhan4d5c52f2022-01-31 08:52:10 -080010512 auto spy = createSpy();
Prabir Pradhan07e05b62021-11-19 03:57:24 -080010513 spy->setFrame({0, 0, 200, 200});
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070010514 mDispatcher->onWindowInfosChanged(
10515 {{*spy->getInfo(), *windowLeft->getInfo(), *windowRight->getInfo()}, {}, 0, 0});
Prabir Pradhan07e05b62021-11-19 03:57:24 -080010516
10517 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070010518 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
Prabir Pradhan07e05b62021-11-19 03:57:24 -080010519 {50, 50}))
10520 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
10521 windowLeft->consumeMotionDown();
10522 spy->consumeMotionDown();
10523
10524 const MotionEvent secondFingerDownEvent =
Siarhei Vishniakoua16e3a22022-03-02 15:26:40 -080010525 MotionEventBuilder(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
Prabir Pradhan07e05b62021-11-19 03:57:24 -080010526 .eventTime(systemTime(SYSTEM_TIME_MONOTONIC))
Siarhei Vishniakou6d73f832022-07-21 17:27:03 -070010527 .pointer(PointerBuilder(/*id=*/0, ToolType::FINGER).x(50).y(50))
10528 .pointer(PointerBuilder(/*id=*/1, ToolType::FINGER).x(150).y(50))
Prabir Pradhan07e05b62021-11-19 03:57:24 -080010529 .build();
10530 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070010531 injectMotionEvent(*mDispatcher, secondFingerDownEvent, INJECT_EVENT_TIMEOUT,
Prabir Pradhan07e05b62021-11-19 03:57:24 -080010532 InputEventInjectionSync::WAIT_FOR_RESULT))
10533 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
10534 windowRight->consumeMotionDown();
Harry Cutts33476232023-01-30 19:57:29 +000010535 spy->consumeMotionPointerDown(/*pointerIndex=*/1);
Prabir Pradhan07e05b62021-11-19 03:57:24 -080010536}
10537
10538/**
10539 * When the first pointer lands outside the spy window and the second pointer lands inside it, the
10540 * the spy should receive the second pointer with ACTION_DOWN.
10541 */
10542TEST_F(InputDispatcherSpyWindowTest, ReceivesSecondPointerAsDown) {
10543 auto window = createForeground();
10544 window->setFrame({0, 0, 200, 200});
Prabir Pradhan4d5c52f2022-01-31 08:52:10 -080010545 auto spyRight = createSpy();
Prabir Pradhan07e05b62021-11-19 03:57:24 -080010546 spyRight->setFrame({100, 0, 200, 200});
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070010547 mDispatcher->onWindowInfosChanged({{*spyRight->getInfo(), *window->getInfo()}, {}, 0, 0});
Prabir Pradhan07e05b62021-11-19 03:57:24 -080010548
10549 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070010550 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
Prabir Pradhan07e05b62021-11-19 03:57:24 -080010551 {50, 50}))
10552 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
10553 window->consumeMotionDown();
10554 spyRight->assertNoEvents();
10555
10556 const MotionEvent secondFingerDownEvent =
Siarhei Vishniakoua16e3a22022-03-02 15:26:40 -080010557 MotionEventBuilder(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
Prabir Pradhan07e05b62021-11-19 03:57:24 -080010558 .eventTime(systemTime(SYSTEM_TIME_MONOTONIC))
Siarhei Vishniakou6d73f832022-07-21 17:27:03 -070010559 .pointer(PointerBuilder(/*id=*/0, ToolType::FINGER).x(50).y(50))
10560 .pointer(PointerBuilder(/*id=*/1, ToolType::FINGER).x(150).y(50))
Prabir Pradhan07e05b62021-11-19 03:57:24 -080010561 .build();
10562 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070010563 injectMotionEvent(*mDispatcher, secondFingerDownEvent, INJECT_EVENT_TIMEOUT,
Prabir Pradhan07e05b62021-11-19 03:57:24 -080010564 InputEventInjectionSync::WAIT_FOR_RESULT))
10565 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
Harry Cutts33476232023-01-30 19:57:29 +000010566 window->consumeMotionPointerDown(/*pointerIndex=*/1);
Prabir Pradhan07e05b62021-11-19 03:57:24 -080010567 spyRight->consumeMotionDown();
10568}
10569
Prabir Pradhan1376fcd2022-01-21 09:56:35 -080010570/**
10571 * The spy window should not be able to affect whether or not touches are split. Only the foreground
10572 * windows should be allowed to control split touch.
10573 */
10574TEST_F(InputDispatcherSpyWindowTest, SplitIfNoForegroundWindowTouched) {
Prabir Pradhan76bdecb2022-01-31 11:14:15 -080010575 // This spy window prevents touch splitting. However, we still expect to split touches
Prabir Pradhan1376fcd2022-01-21 09:56:35 -080010576 // because a foreground window has not disabled splitting.
Prabir Pradhan4d5c52f2022-01-31 08:52:10 -080010577 auto spy = createSpy();
Prabir Pradhan76bdecb2022-01-31 11:14:15 -080010578 spy->setPreventSplitting(true);
Prabir Pradhan1376fcd2022-01-21 09:56:35 -080010579
Prabir Pradhan1376fcd2022-01-21 09:56:35 -080010580 auto window = createForeground();
10581 window->setFrame(Rect(0, 0, 100, 100));
Prabir Pradhan1376fcd2022-01-21 09:56:35 -080010582
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070010583 mDispatcher->onWindowInfosChanged({{*spy->getInfo(), *window->getInfo()}, {}, 0, 0});
Prabir Pradhan1376fcd2022-01-21 09:56:35 -080010584
10585 // First finger down, no window touched.
10586 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070010587 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
Prabir Pradhan1376fcd2022-01-21 09:56:35 -080010588 {100, 200}))
10589 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
10590 spy->consumeMotionDown(ADISPLAY_ID_DEFAULT);
10591 window->assertNoEvents();
10592
10593 // Second finger down on window, the window should receive touch down.
10594 const MotionEvent secondFingerDownEvent =
Siarhei Vishniakoua16e3a22022-03-02 15:26:40 -080010595 MotionEventBuilder(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
Prabir Pradhan1376fcd2022-01-21 09:56:35 -080010596 .displayId(ADISPLAY_ID_DEFAULT)
10597 .eventTime(systemTime(SYSTEM_TIME_MONOTONIC))
Siarhei Vishniakou6d73f832022-07-21 17:27:03 -070010598 .pointer(PointerBuilder(/*id=*/0, ToolType::FINGER).x(100).y(200))
10599 .pointer(PointerBuilder(/*id=*/1, ToolType::FINGER).x(50).y(50))
Prabir Pradhan1376fcd2022-01-21 09:56:35 -080010600 .build();
10601 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070010602 injectMotionEvent(*mDispatcher, secondFingerDownEvent, INJECT_EVENT_TIMEOUT,
Prabir Pradhan1376fcd2022-01-21 09:56:35 -080010603 InputEventInjectionSync::WAIT_FOR_RESULT))
10604 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
10605
10606 window->consumeMotionDown(ADISPLAY_ID_DEFAULT);
Harry Cutts33476232023-01-30 19:57:29 +000010607 spy->consumeMotionPointerDown(/*pointerIndex=*/1);
Prabir Pradhan1376fcd2022-01-21 09:56:35 -080010608}
10609
10610/**
10611 * A spy window will usually be implemented as an un-focusable window. Verify that these windows
10612 * do not receive key events.
10613 */
10614TEST_F(InputDispatcherSpyWindowTest, UnfocusableSpyDoesNotReceiveKeyEvents) {
Prabir Pradhan4d5c52f2022-01-31 08:52:10 -080010615 auto spy = createSpy();
Prabir Pradhan1376fcd2022-01-21 09:56:35 -080010616 spy->setFocusable(false);
10617
10618 auto window = createForeground();
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070010619 mDispatcher->onWindowInfosChanged({{*spy->getInfo(), *window->getInfo()}, {}, 0, 0});
Prabir Pradhan1376fcd2022-01-21 09:56:35 -080010620 setFocusedWindow(window);
10621 window->consumeFocusEvent(true);
10622
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070010623 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectKeyDown(*mDispatcher))
Prabir Pradhan1376fcd2022-01-21 09:56:35 -080010624 << "Inject key event should return InputEventInjectionResult::SUCCEEDED";
10625 window->consumeKeyDown(ADISPLAY_ID_NONE);
10626
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070010627 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectKeyUp(*mDispatcher))
Prabir Pradhan1376fcd2022-01-21 09:56:35 -080010628 << "Inject key event should return InputEventInjectionResult::SUCCEEDED";
10629 window->consumeKeyUp(ADISPLAY_ID_NONE);
10630
10631 spy->assertNoEvents();
10632}
10633
Vaibhav Devmurariff798f32022-05-09 23:45:04 +000010634using InputDispatcherPilferPointersTest = InputDispatcherSpyWindowTest;
10635
10636/**
10637 * A spy window can pilfer pointers. When this happens, touch gestures used by the spy window that
10638 * are currently sent to any other windows - including other spy windows - will also be cancelled.
10639 */
10640TEST_F(InputDispatcherPilferPointersTest, PilferPointers) {
10641 auto window = createForeground();
10642 auto spy1 = createSpy();
10643 auto spy2 = createSpy();
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070010644 mDispatcher->onWindowInfosChanged(
10645 {{*spy1->getInfo(), *spy2->getInfo(), *window->getInfo()}, {}, 0, 0});
Vaibhav Devmurariff798f32022-05-09 23:45:04 +000010646
10647 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070010648 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT))
Vaibhav Devmurariff798f32022-05-09 23:45:04 +000010649 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
10650 window->consumeMotionDown();
10651 spy1->consumeMotionDown();
10652 spy2->consumeMotionDown();
10653
10654 // Pilfer pointers from the second spy window.
10655 EXPECT_EQ(OK, mDispatcher->pilferPointers(spy2->getToken()));
10656 spy2->assertNoEvents();
10657 spy1->consumeMotionCancel();
10658 window->consumeMotionCancel();
10659
10660 // The rest of the gesture should only be sent to the second spy window.
10661 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070010662 injectMotionEvent(*mDispatcher, AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN,
Vaibhav Devmurariff798f32022-05-09 23:45:04 +000010663 ADISPLAY_ID_DEFAULT))
10664 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
10665 spy2->consumeMotionMove();
10666 spy1->assertNoEvents();
10667 window->assertNoEvents();
10668}
10669
10670/**
10671 * A spy window can pilfer pointers for a gesture even after the foreground window has been removed
10672 * in the middle of the gesture.
10673 */
10674TEST_F(InputDispatcherPilferPointersTest, CanPilferAfterWindowIsRemovedMidStream) {
10675 auto window = createForeground();
10676 auto spy = createSpy();
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070010677 mDispatcher->onWindowInfosChanged({{*spy->getInfo(), *window->getInfo()}, {}, 0, 0});
Vaibhav Devmurariff798f32022-05-09 23:45:04 +000010678
10679 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070010680 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT))
Vaibhav Devmurariff798f32022-05-09 23:45:04 +000010681 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
10682 window->consumeMotionDown(ADISPLAY_ID_DEFAULT);
10683 spy->consumeMotionDown(ADISPLAY_ID_DEFAULT);
10684
10685 window->releaseChannel();
10686
10687 EXPECT_EQ(OK, mDispatcher->pilferPointers(spy->getToken()));
10688
10689 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070010690 injectMotionUp(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT))
Vaibhav Devmurariff798f32022-05-09 23:45:04 +000010691 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
10692 spy->consumeMotionUp(ADISPLAY_ID_DEFAULT);
10693}
10694
10695/**
10696 * After a spy window pilfers pointers, new pointers that go down in its bounds should be sent to
10697 * the spy, but not to any other windows.
10698 */
10699TEST_F(InputDispatcherPilferPointersTest, ContinuesToReceiveGestureAfterPilfer) {
10700 auto spy = createSpy();
10701 auto window = createForeground();
10702
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070010703 mDispatcher->onWindowInfosChanged({{*spy->getInfo(), *window->getInfo()}, {}, 0, 0});
Vaibhav Devmurariff798f32022-05-09 23:45:04 +000010704
10705 // First finger down on the window and the spy.
10706 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070010707 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
Vaibhav Devmurariff798f32022-05-09 23:45:04 +000010708 {100, 200}))
10709 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
10710 spy->consumeMotionDown();
10711 window->consumeMotionDown();
10712
10713 // Spy window pilfers the pointers.
10714 EXPECT_EQ(OK, mDispatcher->pilferPointers(spy->getToken()));
10715 window->consumeMotionCancel();
10716
10717 // Second finger down on the window and spy, but the window should not receive the pointer down.
10718 const MotionEvent secondFingerDownEvent =
10719 MotionEventBuilder(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
10720 .displayId(ADISPLAY_ID_DEFAULT)
10721 .eventTime(systemTime(SYSTEM_TIME_MONOTONIC))
Siarhei Vishniakou6d73f832022-07-21 17:27:03 -070010722 .pointer(PointerBuilder(/*id=*/0, ToolType::FINGER).x(100).y(200))
10723 .pointer(PointerBuilder(/*id=*/1, ToolType::FINGER).x(50).y(50))
Vaibhav Devmurariff798f32022-05-09 23:45:04 +000010724 .build();
10725 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070010726 injectMotionEvent(*mDispatcher, secondFingerDownEvent, INJECT_EVENT_TIMEOUT,
Vaibhav Devmurariff798f32022-05-09 23:45:04 +000010727 InputEventInjectionSync::WAIT_FOR_RESULT))
10728 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
10729
Harry Cutts33476232023-01-30 19:57:29 +000010730 spy->consumeMotionPointerDown(/*pointerIndex=*/1);
Vaibhav Devmurariff798f32022-05-09 23:45:04 +000010731
10732 // Third finger goes down outside all windows, so injection should fail.
10733 const MotionEvent thirdFingerDownEvent =
10734 MotionEventBuilder(POINTER_2_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
10735 .displayId(ADISPLAY_ID_DEFAULT)
10736 .eventTime(systemTime(SYSTEM_TIME_MONOTONIC))
Siarhei Vishniakou6d73f832022-07-21 17:27:03 -070010737 .pointer(PointerBuilder(/*id=*/0, ToolType::FINGER).x(100).y(200))
10738 .pointer(PointerBuilder(/*id=*/1, ToolType::FINGER).x(50).y(50))
10739 .pointer(PointerBuilder(/*id=*/2, ToolType::FINGER).x(-5).y(-5))
Vaibhav Devmurariff798f32022-05-09 23:45:04 +000010740 .build();
10741 ASSERT_EQ(InputEventInjectionResult::FAILED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070010742 injectMotionEvent(*mDispatcher, thirdFingerDownEvent, INJECT_EVENT_TIMEOUT,
Vaibhav Devmurariff798f32022-05-09 23:45:04 +000010743 InputEventInjectionSync::WAIT_FOR_RESULT))
Siarhei Vishniakou1ae72f12023-01-29 12:55:30 -080010744 << "Inject motion event should return InputEventInjectionResult::FAILED";
Vaibhav Devmurariff798f32022-05-09 23:45:04 +000010745
10746 spy->assertNoEvents();
10747 window->assertNoEvents();
10748}
10749
10750/**
10751 * After a spy window pilfers pointers, only the pointers used by the spy should be canceled
10752 */
10753TEST_F(InputDispatcherPilferPointersTest, PartiallyPilferRequiredPointers) {
10754 auto spy = createSpy();
10755 spy->setFrame(Rect(0, 0, 100, 100));
10756 auto window = createForeground();
10757 window->setFrame(Rect(0, 0, 200, 200));
10758
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070010759 mDispatcher->onWindowInfosChanged({{*spy->getInfo(), *window->getInfo()}, {}, 0, 0});
Vaibhav Devmurariff798f32022-05-09 23:45:04 +000010760
10761 // First finger down on the window only
10762 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070010763 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
Vaibhav Devmurariff798f32022-05-09 23:45:04 +000010764 {150, 150}))
10765 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
10766 window->consumeMotionDown();
10767
10768 // Second finger down on the spy and window
10769 const MotionEvent secondFingerDownEvent =
10770 MotionEventBuilder(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
10771 .displayId(ADISPLAY_ID_DEFAULT)
10772 .eventTime(systemTime(SYSTEM_TIME_MONOTONIC))
Siarhei Vishniakou6d73f832022-07-21 17:27:03 -070010773 .pointer(PointerBuilder(/*id=*/0, ToolType::FINGER).x(150).y(150))
10774 .pointer(PointerBuilder(/*id=*/1, ToolType::FINGER).x(10).y(10))
Vaibhav Devmurariff798f32022-05-09 23:45:04 +000010775 .build();
10776 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070010777 injectMotionEvent(*mDispatcher, secondFingerDownEvent, INJECT_EVENT_TIMEOUT,
Vaibhav Devmurariff798f32022-05-09 23:45:04 +000010778 InputEventInjectionSync::WAIT_FOR_RESULT))
10779 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
10780 spy->consumeMotionDown();
10781 window->consumeMotionPointerDown(1);
10782
10783 // Third finger down on the spy and window
10784 const MotionEvent thirdFingerDownEvent =
10785 MotionEventBuilder(POINTER_2_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
10786 .displayId(ADISPLAY_ID_DEFAULT)
10787 .eventTime(systemTime(SYSTEM_TIME_MONOTONIC))
Siarhei Vishniakou6d73f832022-07-21 17:27:03 -070010788 .pointer(PointerBuilder(/*id=*/0, ToolType::FINGER).x(150).y(150))
10789 .pointer(PointerBuilder(/*id=*/1, ToolType::FINGER).x(10).y(10))
10790 .pointer(PointerBuilder(/*id=*/2, ToolType::FINGER).x(50).y(50))
Vaibhav Devmurariff798f32022-05-09 23:45:04 +000010791 .build();
10792 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070010793 injectMotionEvent(*mDispatcher, thirdFingerDownEvent, INJECT_EVENT_TIMEOUT,
Vaibhav Devmurariff798f32022-05-09 23:45:04 +000010794 InputEventInjectionSync::WAIT_FOR_RESULT))
10795 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
10796 spy->consumeMotionPointerDown(1);
10797 window->consumeMotionPointerDown(2);
10798
10799 // Spy window pilfers the pointers.
10800 EXPECT_EQ(OK, mDispatcher->pilferPointers(spy->getToken()));
Harry Cutts101ee9b2023-07-06 18:04:14 +000010801 window->consumeMotionPointerUp(/*idx=*/2, ADISPLAY_ID_DEFAULT, AMOTION_EVENT_FLAG_CANCELED);
10802 window->consumeMotionPointerUp(/*idx=*/1, ADISPLAY_ID_DEFAULT, AMOTION_EVENT_FLAG_CANCELED);
Vaibhav Devmurariff798f32022-05-09 23:45:04 +000010803
10804 spy->assertNoEvents();
10805 window->assertNoEvents();
10806}
10807
10808/**
10809 * After a spy window pilfers pointers, all pilfered pointers that have already been dispatched to
10810 * other windows should be canceled. If this results in the cancellation of all pointers for some
10811 * window, then that window should receive ACTION_CANCEL.
10812 */
10813TEST_F(InputDispatcherPilferPointersTest, PilferAllRequiredPointers) {
10814 auto spy = createSpy();
10815 spy->setFrame(Rect(0, 0, 100, 100));
10816 auto window = createForeground();
10817 window->setFrame(Rect(0, 0, 200, 200));
10818
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070010819 mDispatcher->onWindowInfosChanged({{*spy->getInfo(), *window->getInfo()}, {}, 0, 0});
Vaibhav Devmurariff798f32022-05-09 23:45:04 +000010820
10821 // First finger down on both spy and window
10822 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070010823 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
Vaibhav Devmurariff798f32022-05-09 23:45:04 +000010824 {10, 10}))
10825 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
10826 window->consumeMotionDown();
10827 spy->consumeMotionDown();
10828
10829 // Second finger down on the spy and window
10830 const MotionEvent secondFingerDownEvent =
10831 MotionEventBuilder(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
10832 .displayId(ADISPLAY_ID_DEFAULT)
10833 .eventTime(systemTime(SYSTEM_TIME_MONOTONIC))
Siarhei Vishniakou6d73f832022-07-21 17:27:03 -070010834 .pointer(PointerBuilder(/*id=*/0, ToolType::FINGER).x(10).y(10))
10835 .pointer(PointerBuilder(/*id=*/1, ToolType::FINGER).x(50).y(50))
Vaibhav Devmurariff798f32022-05-09 23:45:04 +000010836 .build();
10837 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070010838 injectMotionEvent(*mDispatcher, secondFingerDownEvent, INJECT_EVENT_TIMEOUT,
Vaibhav Devmurariff798f32022-05-09 23:45:04 +000010839 InputEventInjectionSync::WAIT_FOR_RESULT))
10840 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
10841 spy->consumeMotionPointerDown(1);
10842 window->consumeMotionPointerDown(1);
10843
10844 // Spy window pilfers the pointers.
10845 EXPECT_EQ(OK, mDispatcher->pilferPointers(spy->getToken()));
10846 window->consumeMotionCancel();
10847
10848 spy->assertNoEvents();
10849 window->assertNoEvents();
10850}
10851
10852/**
10853 * After a spy window pilfers pointers, new pointers that are not touching the spy window can still
10854 * be sent to other windows
10855 */
10856TEST_F(InputDispatcherPilferPointersTest, CanReceivePointersAfterPilfer) {
10857 auto spy = createSpy();
10858 spy->setFrame(Rect(0, 0, 100, 100));
10859 auto window = createForeground();
10860 window->setFrame(Rect(0, 0, 200, 200));
10861
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070010862 mDispatcher->onWindowInfosChanged({{*spy->getInfo(), *window->getInfo()}, {}, 0, 0});
Vaibhav Devmurariff798f32022-05-09 23:45:04 +000010863
10864 // First finger down on both window and spy
10865 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070010866 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
Vaibhav Devmurariff798f32022-05-09 23:45:04 +000010867 {10, 10}))
10868 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
10869 window->consumeMotionDown();
10870 spy->consumeMotionDown();
10871
10872 // Spy window pilfers the pointers.
10873 EXPECT_EQ(OK, mDispatcher->pilferPointers(spy->getToken()));
10874 window->consumeMotionCancel();
10875
10876 // Second finger down on the window only
10877 const MotionEvent secondFingerDownEvent =
10878 MotionEventBuilder(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
10879 .displayId(ADISPLAY_ID_DEFAULT)
10880 .eventTime(systemTime(SYSTEM_TIME_MONOTONIC))
Siarhei Vishniakou6d73f832022-07-21 17:27:03 -070010881 .pointer(PointerBuilder(/*id=*/0, ToolType::FINGER).x(10).y(10))
10882 .pointer(PointerBuilder(/*id=*/1, ToolType::FINGER).x(150).y(150))
Vaibhav Devmurariff798f32022-05-09 23:45:04 +000010883 .build();
10884 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070010885 injectMotionEvent(*mDispatcher, secondFingerDownEvent, INJECT_EVENT_TIMEOUT,
Vaibhav Devmurariff798f32022-05-09 23:45:04 +000010886 InputEventInjectionSync::WAIT_FOR_RESULT))
10887 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
10888 window->consumeMotionDown();
10889 window->assertNoEvents();
10890
10891 // TODO(b/232530217): do not send the unnecessary MOVE event and delete the next line
10892 spy->consumeMotionMove();
10893 spy->assertNoEvents();
10894}
10895
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -070010896/**
10897 * A window on the left and a window on the right. Also, a spy window that's above all of the
10898 * windows, and spanning both left and right windows.
10899 * Send simultaneous motion streams from two different devices, one to the left window, and another
10900 * to the right window.
10901 * Pilfer from spy window.
10902 * Check that the pilfering only affects the pointers that are actually being received by the spy.
10903 */
10904TEST_F(InputDispatcherPilferPointersTest, MultiDevicePilfer) {
10905 sp<FakeWindowHandle> spy = createSpy();
10906 spy->setFrame(Rect(0, 0, 200, 200));
10907 sp<FakeWindowHandle> leftWindow = createForeground();
10908 leftWindow->setFrame(Rect(0, 0, 100, 100));
10909
10910 sp<FakeWindowHandle> rightWindow = createForeground();
10911 rightWindow->setFrame(Rect(100, 0, 200, 100));
10912
10913 constexpr int32_t stylusDeviceId = 1;
10914 constexpr int32_t touchDeviceId = 2;
10915
10916 mDispatcher->onWindowInfosChanged(
10917 {{*spy->getInfo(), *leftWindow->getInfo(), *rightWindow->getInfo()}, {}, 0, 0});
10918
10919 // Stylus down on left window and spy
10920 mDispatcher->notifyMotion(MotionArgsBuilder(AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_STYLUS)
10921 .deviceId(stylusDeviceId)
10922 .pointer(PointerBuilder(0, ToolType::STYLUS).x(50).y(50))
10923 .build());
10924 leftWindow->consumeMotionEvent(
10925 AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(stylusDeviceId)));
10926 spy->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(stylusDeviceId)));
10927
10928 // Finger down on right window and spy - but spy already has stylus
10929 mDispatcher->notifyMotion(
10930 MotionArgsBuilder(AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
10931 .deviceId(touchDeviceId)
10932 .pointer(PointerBuilder(0, ToolType::FINGER).x(150).y(50))
10933 .build());
10934 rightWindow->consumeMotionEvent(
10935 AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(touchDeviceId)));
Siarhei Vishniakou2899c552023-07-10 18:20:46 -070010936 spy->assertNoEvents();
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -070010937
10938 // Act: pilfer from spy. Spy is currently receiving touch events.
10939 EXPECT_EQ(OK, mDispatcher->pilferPointers(spy->getToken()));
Siarhei Vishniakou2899c552023-07-10 18:20:46 -070010940 leftWindow->consumeMotionEvent(
10941 AllOf(WithMotionAction(ACTION_CANCEL), WithDeviceId(stylusDeviceId)));
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -070010942 rightWindow->consumeMotionEvent(
10943 AllOf(WithMotionAction(ACTION_CANCEL), WithDeviceId(touchDeviceId)));
10944
10945 // Continue movements from both stylus and touch. Touch will be delivered to spy, but not stylus
10946 mDispatcher->notifyMotion(MotionArgsBuilder(AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_STYLUS)
10947 .deviceId(stylusDeviceId)
10948 .pointer(PointerBuilder(0, ToolType::STYLUS).x(51).y(52))
10949 .build());
10950 mDispatcher->notifyMotion(
10951 MotionArgsBuilder(AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN)
10952 .deviceId(touchDeviceId)
10953 .pointer(PointerBuilder(0, ToolType::FINGER).x(151).y(52))
10954 .build());
Siarhei Vishniakou2899c552023-07-10 18:20:46 -070010955 spy->consumeMotionEvent(AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(stylusDeviceId)));
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -070010956
10957 spy->assertNoEvents();
10958 leftWindow->assertNoEvents();
10959 rightWindow->assertNoEvents();
10960}
10961
Prabir Pradhan9cd9eb62023-11-22 17:58:06 +000010962TEST_F(InputDispatcherPilferPointersTest, NoPilferingWithHoveringPointers) {
10963 auto window = createForeground();
10964 auto spy = createSpy();
10965 mDispatcher->onWindowInfosChanged({{*spy->getInfo(), *window->getInfo()}, {}, 0, 0});
10966
10967 mDispatcher->notifyMotion(
10968 MotionArgsBuilder(ACTION_HOVER_ENTER, AINPUT_SOURCE_MOUSE)
10969 .deviceId(1)
10970 .pointer(PointerBuilder(/*id=*/0, ToolType::MOUSE).x(100).y(200))
10971 .build());
10972 window->consumeMotionEvent(WithMotionAction(ACTION_HOVER_ENTER));
10973 spy->consumeMotionEvent(WithMotionAction(ACTION_HOVER_ENTER));
10974
10975 // Pilfer pointers from the spy window should fail.
10976 EXPECT_NE(OK, mDispatcher->pilferPointers(spy->getToken()));
10977 spy->assertNoEvents();
10978 window->assertNoEvents();
10979}
10980
Prabir Pradhand65552b2021-10-07 11:23:50 -070010981class InputDispatcherStylusInterceptorTest : public InputDispatcherTest {
10982public:
10983 std::pair<sp<FakeWindowHandle>, sp<FakeWindowHandle>> setupStylusOverlayScenario() {
10984 std::shared_ptr<FakeApplicationHandle> overlayApplication =
10985 std::make_shared<FakeApplicationHandle>();
10986 sp<FakeWindowHandle> overlay =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -070010987 sp<FakeWindowHandle>::make(overlayApplication, mDispatcher,
10988 "Stylus interceptor window", ADISPLAY_ID_DEFAULT);
Prabir Pradhand65552b2021-10-07 11:23:50 -070010989 overlay->setFocusable(false);
Prabir Pradhanaeebeb42023-06-13 19:53:03 +000010990 overlay->setOwnerInfo(gui::Pid{111}, gui::Uid{111});
Prabir Pradhan4d5c52f2022-01-31 08:52:10 -080010991 overlay->setTouchable(false);
Prabir Pradhan51e7db02022-02-07 06:02:57 -080010992 overlay->setInterceptsStylus(true);
Prabir Pradhand65552b2021-10-07 11:23:50 -070010993 overlay->setTrustedOverlay(true);
10994
10995 std::shared_ptr<FakeApplicationHandle> application =
10996 std::make_shared<FakeApplicationHandle>();
10997 sp<FakeWindowHandle> window =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -070010998 sp<FakeWindowHandle>::make(application, mDispatcher, "Application window",
10999 ADISPLAY_ID_DEFAULT);
Prabir Pradhand65552b2021-10-07 11:23:50 -070011000 window->setFocusable(true);
Prabir Pradhanaeebeb42023-06-13 19:53:03 +000011001 window->setOwnerInfo(gui::Pid{222}, gui::Uid{222});
Prabir Pradhand65552b2021-10-07 11:23:50 -070011002
11003 mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070011004 mDispatcher->onWindowInfosChanged({{*overlay->getInfo(), *window->getInfo()}, {}, 0, 0});
Prabir Pradhand65552b2021-10-07 11:23:50 -070011005 setFocusedWindow(window);
Harry Cutts33476232023-01-30 19:57:29 +000011006 window->consumeFocusEvent(/*hasFocus=*/true, /*inTouchMode=*/true);
Prabir Pradhand65552b2021-10-07 11:23:50 -070011007 return {std::move(overlay), std::move(window)};
11008 }
11009
11010 void sendFingerEvent(int32_t action) {
Prabir Pradhan678438e2023-04-13 19:32:51 +000011011 mDispatcher->notifyMotion(
Prabir Pradhand65552b2021-10-07 11:23:50 -070011012 generateMotionArgs(action, AINPUT_SOURCE_TOUCHSCREEN | AINPUT_SOURCE_STYLUS,
Prabir Pradhan678438e2023-04-13 19:32:51 +000011013 ADISPLAY_ID_DEFAULT, {PointF{20, 20}}));
Prabir Pradhand65552b2021-10-07 11:23:50 -070011014 }
11015
11016 void sendStylusEvent(int32_t action) {
11017 NotifyMotionArgs motionArgs =
11018 generateMotionArgs(action, AINPUT_SOURCE_TOUCHSCREEN | AINPUT_SOURCE_STYLUS,
11019 ADISPLAY_ID_DEFAULT, {PointF{30, 40}});
Siarhei Vishniakou6d73f832022-07-21 17:27:03 -070011020 motionArgs.pointerProperties[0].toolType = ToolType::STYLUS;
Prabir Pradhan678438e2023-04-13 19:32:51 +000011021 mDispatcher->notifyMotion(motionArgs);
Prabir Pradhand65552b2021-10-07 11:23:50 -070011022 }
11023};
11024
Prabir Pradhana3ab87a2022-01-27 10:00:21 -080011025using InputDispatcherStylusInterceptorDeathTest = InputDispatcherStylusInterceptorTest;
11026
11027TEST_F(InputDispatcherStylusInterceptorDeathTest, UntrustedOverlay_AbortsDispatcher) {
Siarhei Vishniakouad3b6822023-06-22 14:17:35 -070011028 testing::GTEST_FLAG(death_test_style) = "threadsafe";
Prabir Pradhana3ab87a2022-01-27 10:00:21 -080011029 ScopedSilentDeath _silentDeath;
11030
Prabir Pradhand65552b2021-10-07 11:23:50 -070011031 auto [overlay, window] = setupStylusOverlayScenario();
11032 overlay->setTrustedOverlay(false);
11033 // Configuring an untrusted overlay as a stylus interceptor should cause Dispatcher to abort.
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070011034 ASSERT_DEATH(mDispatcher->onWindowInfosChanged(
11035 {{*overlay->getInfo(), *window->getInfo()}, {}, 0, 0}),
Prabir Pradhand65552b2021-10-07 11:23:50 -070011036 ".* not a trusted overlay");
11037}
11038
11039TEST_F(InputDispatcherStylusInterceptorTest, ConsmesOnlyStylusEvents) {
11040 auto [overlay, window] = setupStylusOverlayScenario();
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070011041 mDispatcher->onWindowInfosChanged({{*overlay->getInfo(), *window->getInfo()}, {}, 0, 0});
Prabir Pradhand65552b2021-10-07 11:23:50 -070011042
11043 sendStylusEvent(AMOTION_EVENT_ACTION_DOWN);
11044 overlay->consumeMotionDown();
11045 sendStylusEvent(AMOTION_EVENT_ACTION_UP);
11046 overlay->consumeMotionUp();
11047
11048 sendFingerEvent(AMOTION_EVENT_ACTION_DOWN);
11049 window->consumeMotionDown();
11050 sendFingerEvent(AMOTION_EVENT_ACTION_UP);
11051 window->consumeMotionUp();
11052
11053 overlay->assertNoEvents();
11054 window->assertNoEvents();
11055}
11056
11057TEST_F(InputDispatcherStylusInterceptorTest, SpyWindowStylusInterceptor) {
11058 auto [overlay, window] = setupStylusOverlayScenario();
Prabir Pradhan51e7db02022-02-07 06:02:57 -080011059 overlay->setSpy(true);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070011060 mDispatcher->onWindowInfosChanged({{*overlay->getInfo(), *window->getInfo()}, {}, 0, 0});
Prabir Pradhand65552b2021-10-07 11:23:50 -070011061
11062 sendStylusEvent(AMOTION_EVENT_ACTION_DOWN);
11063 overlay->consumeMotionDown();
11064 window->consumeMotionDown();
11065 sendStylusEvent(AMOTION_EVENT_ACTION_UP);
11066 overlay->consumeMotionUp();
11067 window->consumeMotionUp();
11068
11069 sendFingerEvent(AMOTION_EVENT_ACTION_DOWN);
11070 window->consumeMotionDown();
11071 sendFingerEvent(AMOTION_EVENT_ACTION_UP);
11072 window->consumeMotionUp();
11073
11074 overlay->assertNoEvents();
11075 window->assertNoEvents();
11076}
11077
Prabir Pradhan6dfbf262022-03-14 15:24:30 +000011078/**
11079 * Set up a scenario to test the behavior used by the stylus handwriting detection feature.
11080 * The scenario is as follows:
11081 * - The stylus interceptor overlay is configured as a spy window.
11082 * - The stylus interceptor spy receives the start of a new stylus gesture.
11083 * - It pilfers pointers and then configures itself to no longer be a spy.
11084 * - The stylus interceptor continues to receive the rest of the gesture.
11085 */
11086TEST_F(InputDispatcherStylusInterceptorTest, StylusHandwritingScenario) {
11087 auto [overlay, window] = setupStylusOverlayScenario();
11088 overlay->setSpy(true);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070011089 mDispatcher->onWindowInfosChanged({{*overlay->getInfo(), *window->getInfo()}, {}, 0, 0});
Prabir Pradhan6dfbf262022-03-14 15:24:30 +000011090
11091 sendStylusEvent(AMOTION_EVENT_ACTION_DOWN);
11092 overlay->consumeMotionDown();
11093 window->consumeMotionDown();
11094
11095 // The interceptor pilfers the pointers.
11096 EXPECT_EQ(OK, mDispatcher->pilferPointers(overlay->getToken()));
11097 window->consumeMotionCancel();
11098
11099 // The interceptor configures itself so that it is no longer a spy.
11100 overlay->setSpy(false);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070011101 mDispatcher->onWindowInfosChanged({{*overlay->getInfo(), *window->getInfo()}, {}, 0, 0});
Prabir Pradhan6dfbf262022-03-14 15:24:30 +000011102
11103 // It continues to receive the rest of the stylus gesture.
11104 sendStylusEvent(AMOTION_EVENT_ACTION_MOVE);
11105 overlay->consumeMotionMove();
11106 sendStylusEvent(AMOTION_EVENT_ACTION_UP);
11107 overlay->consumeMotionUp();
11108
11109 window->assertNoEvents();
11110}
11111
Prabir Pradhan5735a322022-04-11 17:23:34 +000011112struct User {
Prabir Pradhanaeebeb42023-06-13 19:53:03 +000011113 gui::Pid mPid;
Prabir Pradhan8a5c41d2023-06-08 19:13:46 +000011114 gui::Uid mUid;
Prabir Pradhan5735a322022-04-11 17:23:34 +000011115 uint32_t mPolicyFlags{DEFAULT_POLICY_FLAGS};
11116 std::unique_ptr<InputDispatcher>& mDispatcher;
11117
Prabir Pradhanaeebeb42023-06-13 19:53:03 +000011118 User(std::unique_ptr<InputDispatcher>& dispatcher, gui::Pid pid, gui::Uid uid)
Prabir Pradhan5735a322022-04-11 17:23:34 +000011119 : mPid(pid), mUid(uid), mDispatcher(dispatcher) {}
11120
11121 InputEventInjectionResult injectTargetedMotion(int32_t action) const {
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070011122 return injectMotionEvent(*mDispatcher, action, AINPUT_SOURCE_TOUCHSCREEN,
Prabir Pradhan5735a322022-04-11 17:23:34 +000011123 ADISPLAY_ID_DEFAULT, {100, 200},
11124 {AMOTION_EVENT_INVALID_CURSOR_POSITION,
11125 AMOTION_EVENT_INVALID_CURSOR_POSITION},
11126 INJECT_EVENT_TIMEOUT, InputEventInjectionSync::WAIT_FOR_RESULT,
11127 systemTime(SYSTEM_TIME_MONOTONIC), {mUid}, mPolicyFlags);
11128 }
11129
11130 InputEventInjectionResult injectTargetedKey(int32_t action) const {
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070011131 return inputdispatcher::injectKey(*mDispatcher, action, /*repeatCount=*/0, ADISPLAY_ID_NONE,
Prabir Pradhan5735a322022-04-11 17:23:34 +000011132 InputEventInjectionSync::WAIT_FOR_RESULT,
Harry Cutts33476232023-01-30 19:57:29 +000011133 INJECT_EVENT_TIMEOUT, /*allowKeyRepeat=*/false, {mUid},
Prabir Pradhan5735a322022-04-11 17:23:34 +000011134 mPolicyFlags);
11135 }
11136
Siarhei Vishniakoue3ce4122023-08-23 10:26:46 -070011137 sp<FakeWindowHandle> createWindow(const char* name) const {
Prabir Pradhan5735a322022-04-11 17:23:34 +000011138 std::shared_ptr<FakeApplicationHandle> overlayApplication =
11139 std::make_shared<FakeApplicationHandle>();
Siarhei Vishniakoue3ce4122023-08-23 10:26:46 -070011140 sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(overlayApplication, mDispatcher,
11141 name, ADISPLAY_ID_DEFAULT);
Prabir Pradhan5735a322022-04-11 17:23:34 +000011142 window->setOwnerInfo(mPid, mUid);
11143 return window;
11144 }
11145};
11146
11147using InputDispatcherTargetedInjectionTest = InputDispatcherTest;
11148
11149TEST_F(InputDispatcherTargetedInjectionTest, CanInjectIntoOwnedWindow) {
Prabir Pradhanaeebeb42023-06-13 19:53:03 +000011150 auto owner = User(mDispatcher, gui::Pid{10}, gui::Uid{11});
Siarhei Vishniakoue3ce4122023-08-23 10:26:46 -070011151 auto window = owner.createWindow("Owned window");
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070011152 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Prabir Pradhan5735a322022-04-11 17:23:34 +000011153
11154 EXPECT_EQ(InputEventInjectionResult::SUCCEEDED,
11155 owner.injectTargetedMotion(AMOTION_EVENT_ACTION_DOWN));
11156 window->consumeMotionDown();
11157
11158 setFocusedWindow(window);
11159 window->consumeFocusEvent(true);
11160
11161 EXPECT_EQ(InputEventInjectionResult::SUCCEEDED,
11162 owner.injectTargetedKey(AKEY_EVENT_ACTION_DOWN));
11163 window->consumeKeyDown(ADISPLAY_ID_NONE);
11164}
11165
11166TEST_F(InputDispatcherTargetedInjectionTest, CannotInjectIntoUnownedWindow) {
Prabir Pradhanaeebeb42023-06-13 19:53:03 +000011167 auto owner = User(mDispatcher, gui::Pid{10}, gui::Uid{11});
Siarhei Vishniakoue3ce4122023-08-23 10:26:46 -070011168 auto window = owner.createWindow("Owned window");
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070011169 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Prabir Pradhan5735a322022-04-11 17:23:34 +000011170
Prabir Pradhanaeebeb42023-06-13 19:53:03 +000011171 auto rando = User(mDispatcher, gui::Pid{20}, gui::Uid{21});
Prabir Pradhan5735a322022-04-11 17:23:34 +000011172 EXPECT_EQ(InputEventInjectionResult::TARGET_MISMATCH,
11173 rando.injectTargetedMotion(AMOTION_EVENT_ACTION_DOWN));
11174
11175 setFocusedWindow(window);
11176 window->consumeFocusEvent(true);
11177
11178 EXPECT_EQ(InputEventInjectionResult::TARGET_MISMATCH,
11179 rando.injectTargetedKey(AKEY_EVENT_ACTION_DOWN));
11180 window->assertNoEvents();
11181}
11182
11183TEST_F(InputDispatcherTargetedInjectionTest, CanInjectIntoOwnedSpyWindow) {
Prabir Pradhanaeebeb42023-06-13 19:53:03 +000011184 auto owner = User(mDispatcher, gui::Pid{10}, gui::Uid{11});
Siarhei Vishniakoue3ce4122023-08-23 10:26:46 -070011185 auto window = owner.createWindow("Owned window");
11186 auto spy = owner.createWindow("Owned spy");
Prabir Pradhan5735a322022-04-11 17:23:34 +000011187 spy->setSpy(true);
11188 spy->setTrustedOverlay(true);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070011189 mDispatcher->onWindowInfosChanged({{*spy->getInfo(), *window->getInfo()}, {}, 0, 0});
Prabir Pradhan5735a322022-04-11 17:23:34 +000011190
11191 EXPECT_EQ(InputEventInjectionResult::SUCCEEDED,
11192 owner.injectTargetedMotion(AMOTION_EVENT_ACTION_DOWN));
11193 spy->consumeMotionDown();
11194 window->consumeMotionDown();
11195}
11196
11197TEST_F(InputDispatcherTargetedInjectionTest, CannotInjectIntoUnownedSpyWindow) {
Prabir Pradhanaeebeb42023-06-13 19:53:03 +000011198 auto owner = User(mDispatcher, gui::Pid{10}, gui::Uid{11});
Siarhei Vishniakoue3ce4122023-08-23 10:26:46 -070011199 auto window = owner.createWindow("Owned window");
Prabir Pradhan5735a322022-04-11 17:23:34 +000011200
Prabir Pradhanaeebeb42023-06-13 19:53:03 +000011201 auto rando = User(mDispatcher, gui::Pid{20}, gui::Uid{21});
Siarhei Vishniakoue3ce4122023-08-23 10:26:46 -070011202 auto randosSpy = rando.createWindow("Rando's spy");
Prabir Pradhan5735a322022-04-11 17:23:34 +000011203 randosSpy->setSpy(true);
11204 randosSpy->setTrustedOverlay(true);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070011205 mDispatcher->onWindowInfosChanged({{*randosSpy->getInfo(), *window->getInfo()}, {}, 0, 0});
Prabir Pradhan5735a322022-04-11 17:23:34 +000011206
11207 // The event is targeted at owner's window, so injection should succeed, but the spy should
11208 // not receive the event.
11209 EXPECT_EQ(InputEventInjectionResult::SUCCEEDED,
11210 owner.injectTargetedMotion(AMOTION_EVENT_ACTION_DOWN));
11211 randosSpy->assertNoEvents();
11212 window->consumeMotionDown();
11213}
11214
11215TEST_F(InputDispatcherTargetedInjectionTest, CanInjectIntoAnyWindowWhenNotTargeting) {
Prabir Pradhanaeebeb42023-06-13 19:53:03 +000011216 auto owner = User(mDispatcher, gui::Pid{10}, gui::Uid{11});
Siarhei Vishniakoue3ce4122023-08-23 10:26:46 -070011217 auto window = owner.createWindow("Owned window");
Prabir Pradhan5735a322022-04-11 17:23:34 +000011218
Prabir Pradhanaeebeb42023-06-13 19:53:03 +000011219 auto rando = User(mDispatcher, gui::Pid{20}, gui::Uid{21});
Siarhei Vishniakoue3ce4122023-08-23 10:26:46 -070011220 auto randosSpy = rando.createWindow("Rando's spy");
Prabir Pradhan5735a322022-04-11 17:23:34 +000011221 randosSpy->setSpy(true);
11222 randosSpy->setTrustedOverlay(true);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070011223 mDispatcher->onWindowInfosChanged({{*randosSpy->getInfo(), *window->getInfo()}, {}, 0, 0});
Prabir Pradhan5735a322022-04-11 17:23:34 +000011224
11225 // A user that has injection permission can inject into any window.
11226 EXPECT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070011227 injectMotionEvent(*mDispatcher, AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN,
Prabir Pradhan5735a322022-04-11 17:23:34 +000011228 ADISPLAY_ID_DEFAULT));
11229 randosSpy->consumeMotionDown();
11230 window->consumeMotionDown();
11231
11232 setFocusedWindow(randosSpy);
11233 randosSpy->consumeFocusEvent(true);
11234
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070011235 EXPECT_EQ(InputEventInjectionResult::SUCCEEDED, injectKeyDown(*mDispatcher));
Prabir Pradhan5735a322022-04-11 17:23:34 +000011236 randosSpy->consumeKeyDown(ADISPLAY_ID_NONE);
11237 window->assertNoEvents();
11238}
11239
Siarhei Vishniakou580fb3a2023-05-05 15:02:20 -070011240TEST_F(InputDispatcherTargetedInjectionTest, CannotGenerateActionOutsideToOtherUids) {
Prabir Pradhanaeebeb42023-06-13 19:53:03 +000011241 auto owner = User(mDispatcher, gui::Pid{10}, gui::Uid{11});
Siarhei Vishniakoue3ce4122023-08-23 10:26:46 -070011242 auto window = owner.createWindow("Owned window");
Prabir Pradhan5735a322022-04-11 17:23:34 +000011243
Prabir Pradhanaeebeb42023-06-13 19:53:03 +000011244 auto rando = User(mDispatcher, gui::Pid{20}, gui::Uid{21});
Siarhei Vishniakoue3ce4122023-08-23 10:26:46 -070011245 auto randosWindow = rando.createWindow("Rando's window");
Prabir Pradhan5735a322022-04-11 17:23:34 +000011246 randosWindow->setFrame(Rect{-10, -10, -5, -5});
11247 randosWindow->setWatchOutsideTouch(true);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070011248 mDispatcher->onWindowInfosChanged({{*randosWindow->getInfo(), *window->getInfo()}, {}, 0, 0});
Prabir Pradhan5735a322022-04-11 17:23:34 +000011249
Siarhei Vishniakou580fb3a2023-05-05 15:02:20 -070011250 // Do not allow generation of ACTION_OUTSIDE events into windows owned by different uids.
Prabir Pradhan5735a322022-04-11 17:23:34 +000011251 EXPECT_EQ(InputEventInjectionResult::SUCCEEDED,
11252 owner.injectTargetedMotion(AMOTION_EVENT_ACTION_DOWN));
11253 window->consumeMotionDown();
Siarhei Vishniakou580fb3a2023-05-05 15:02:20 -070011254 randosWindow->assertNoEvents();
Prabir Pradhan5735a322022-04-11 17:23:34 +000011255}
11256
Prabir Pradhan64f21d22023-11-28 21:19:42 +000011257using InputDispatcherPointerInWindowTest = InputDispatcherTest;
11258
11259TEST_F(InputDispatcherPointerInWindowTest, PointerInWindowWhenHovering) {
11260 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
11261
11262 sp<FakeWindowHandle> left = sp<FakeWindowHandle>::make(application, mDispatcher, "Left Window",
11263 ADISPLAY_ID_DEFAULT);
11264 left->setFrame(Rect(0, 0, 100, 100));
11265 sp<FakeWindowHandle> right = sp<FakeWindowHandle>::make(application, mDispatcher,
11266 "Right Window", ADISPLAY_ID_DEFAULT);
11267 right->setFrame(Rect(100, 0, 200, 100));
11268 sp<FakeWindowHandle> spy =
11269 sp<FakeWindowHandle>::make(application, mDispatcher, "Spy Window", ADISPLAY_ID_DEFAULT);
11270 spy->setFrame(Rect(0, 0, 200, 100));
11271 spy->setTrustedOverlay(true);
11272 spy->setSpy(true);
11273
11274 mDispatcher->onWindowInfosChanged(
11275 {{*spy->getInfo(), *left->getInfo(), *right->getInfo()}, {}, 0, 0});
11276
11277 // Hover into the left window.
11278 mDispatcher->notifyMotion(
11279 MotionArgsBuilder(ACTION_HOVER_ENTER, AINPUT_SOURCE_STYLUS)
11280 .pointer(PointerBuilder(/*id=*/0, ToolType::STYLUS).x(50).y(50))
11281 .build());
11282
11283 left->consumeMotionEvent(WithMotionAction(ACTION_HOVER_ENTER));
11284 spy->consumeMotionEvent(WithMotionAction(ACTION_HOVER_ENTER));
11285
11286 ASSERT_TRUE(mDispatcher->isPointerInWindow(left->getToken(), ADISPLAY_ID_DEFAULT, DEVICE_ID,
11287 /*pointerId=*/0));
11288 ASSERT_TRUE(mDispatcher->isPointerInWindow(spy->getToken(), ADISPLAY_ID_DEFAULT, DEVICE_ID,
11289 /*pointerId=*/0));
11290 ASSERT_FALSE(mDispatcher->isPointerInWindow(right->getToken(), ADISPLAY_ID_DEFAULT, DEVICE_ID,
11291 /*pointerId=*/0));
11292
11293 // Hover move to the right window.
11294 mDispatcher->notifyMotion(
11295 MotionArgsBuilder(ACTION_HOVER_MOVE, AINPUT_SOURCE_STYLUS)
11296 .pointer(PointerBuilder(/*id=*/0, ToolType::STYLUS).x(150).y(50))
11297 .build());
11298
11299 left->consumeMotionEvent(WithMotionAction(ACTION_HOVER_EXIT));
11300 right->consumeMotionEvent(WithMotionAction(ACTION_HOVER_ENTER));
11301 spy->consumeMotionEvent(WithMotionAction(ACTION_HOVER_MOVE));
11302
11303 ASSERT_FALSE(mDispatcher->isPointerInWindow(left->getToken(), ADISPLAY_ID_DEFAULT, DEVICE_ID,
11304 /*pointerId=*/0));
11305 ASSERT_TRUE(mDispatcher->isPointerInWindow(spy->getToken(), ADISPLAY_ID_DEFAULT, DEVICE_ID,
11306 /*pointerId=*/0));
11307 ASSERT_TRUE(mDispatcher->isPointerInWindow(right->getToken(), ADISPLAY_ID_DEFAULT, DEVICE_ID,
11308 /*pointerId=*/0));
11309
11310 // Stop hovering.
11311 mDispatcher->notifyMotion(
11312 MotionArgsBuilder(ACTION_HOVER_EXIT, AINPUT_SOURCE_STYLUS)
11313 .pointer(PointerBuilder(/*id=*/0, ToolType::STYLUS).x(150).y(50))
11314 .build());
11315
11316 right->consumeMotionEvent(WithMotionAction(ACTION_HOVER_EXIT));
11317 spy->consumeMotionEvent(WithMotionAction(ACTION_HOVER_EXIT));
11318
11319 ASSERT_FALSE(mDispatcher->isPointerInWindow(left->getToken(), ADISPLAY_ID_DEFAULT, DEVICE_ID,
11320 /*pointerId=*/0));
11321 ASSERT_FALSE(mDispatcher->isPointerInWindow(spy->getToken(), ADISPLAY_ID_DEFAULT, DEVICE_ID,
11322 /*pointerId=*/0));
11323 ASSERT_FALSE(mDispatcher->isPointerInWindow(right->getToken(), ADISPLAY_ID_DEFAULT, DEVICE_ID,
11324 /*pointerId=*/0));
11325}
11326
11327TEST_F(InputDispatcherPointerInWindowTest, PointerInWindowWithSplitTouch) {
11328 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
11329
11330 sp<FakeWindowHandle> left = sp<FakeWindowHandle>::make(application, mDispatcher, "Left Window",
11331 ADISPLAY_ID_DEFAULT);
11332 left->setFrame(Rect(0, 0, 100, 100));
11333 sp<FakeWindowHandle> right = sp<FakeWindowHandle>::make(application, mDispatcher,
11334 "Right Window", ADISPLAY_ID_DEFAULT);
11335 right->setFrame(Rect(100, 0, 200, 100));
11336 sp<FakeWindowHandle> spy =
11337 sp<FakeWindowHandle>::make(application, mDispatcher, "Spy Window", ADISPLAY_ID_DEFAULT);
11338 spy->setFrame(Rect(0, 0, 200, 100));
11339 spy->setTrustedOverlay(true);
11340 spy->setSpy(true);
11341
11342 mDispatcher->onWindowInfosChanged(
11343 {{*spy->getInfo(), *left->getInfo(), *right->getInfo()}, {}, 0, 0});
11344
11345 // First pointer down on left window.
11346 mDispatcher->notifyMotion(
11347 MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
11348 .pointer(PointerBuilder(/*id=*/0, ToolType::FINGER).x(50).y(50))
11349 .build());
11350
11351 left->consumeMotionDown();
11352 spy->consumeMotionDown();
11353
11354 ASSERT_TRUE(mDispatcher->isPointerInWindow(left->getToken(), ADISPLAY_ID_DEFAULT, DEVICE_ID,
11355 /*pointerId=*/0));
11356 ASSERT_TRUE(mDispatcher->isPointerInWindow(spy->getToken(), ADISPLAY_ID_DEFAULT, DEVICE_ID,
11357 /*pointerId=*/0));
11358 ASSERT_FALSE(mDispatcher->isPointerInWindow(right->getToken(), ADISPLAY_ID_DEFAULT, DEVICE_ID,
11359 /*pointerId=*/0));
11360
11361 // Second pointer down on right window.
11362 mDispatcher->notifyMotion(
11363 MotionArgsBuilder(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
11364 .pointer(PointerBuilder(/*id=*/0, ToolType::FINGER).x(50).y(50))
11365 .pointer(PointerBuilder(/*id=*/1, ToolType::FINGER).x(150).y(50))
11366 .build());
11367
11368 left->consumeMotionMove();
11369 right->consumeMotionDown();
11370 spy->consumeMotionEvent(WithMotionAction(POINTER_1_DOWN));
11371
11372 ASSERT_TRUE(mDispatcher->isPointerInWindow(left->getToken(), ADISPLAY_ID_DEFAULT, DEVICE_ID,
11373 /*pointerId=*/0));
11374 ASSERT_TRUE(mDispatcher->isPointerInWindow(spy->getToken(), ADISPLAY_ID_DEFAULT, DEVICE_ID,
11375 /*pointerId=*/0));
11376 ASSERT_FALSE(mDispatcher->isPointerInWindow(right->getToken(), ADISPLAY_ID_DEFAULT, DEVICE_ID,
11377 /*pointerId=*/0));
11378 ASSERT_FALSE(mDispatcher->isPointerInWindow(left->getToken(), ADISPLAY_ID_DEFAULT, DEVICE_ID,
11379 /*pointerId=*/1));
11380 ASSERT_TRUE(mDispatcher->isPointerInWindow(spy->getToken(), ADISPLAY_ID_DEFAULT, DEVICE_ID,
11381 /*pointerId=*/1));
11382 ASSERT_TRUE(mDispatcher->isPointerInWindow(right->getToken(), ADISPLAY_ID_DEFAULT, DEVICE_ID,
11383 /*pointerId=*/1));
11384
11385 // Second pointer up.
11386 mDispatcher->notifyMotion(
11387 MotionArgsBuilder(POINTER_1_UP, AINPUT_SOURCE_TOUCHSCREEN)
11388 .pointer(PointerBuilder(/*id=*/0, ToolType::FINGER).x(50).y(50))
11389 .pointer(PointerBuilder(/*id=*/1, ToolType::FINGER).x(150).y(50))
11390 .build());
11391
11392 left->consumeMotionMove();
11393 right->consumeMotionUp();
11394 spy->consumeMotionEvent(WithMotionAction(POINTER_1_UP));
11395
11396 ASSERT_TRUE(mDispatcher->isPointerInWindow(left->getToken(), ADISPLAY_ID_DEFAULT, DEVICE_ID,
11397 /*pointerId=*/0));
11398 ASSERT_TRUE(mDispatcher->isPointerInWindow(spy->getToken(), ADISPLAY_ID_DEFAULT, DEVICE_ID,
11399 /*pointerId=*/0));
11400 ASSERT_FALSE(mDispatcher->isPointerInWindow(right->getToken(), ADISPLAY_ID_DEFAULT, DEVICE_ID,
11401 /*pointerId=*/0));
11402 ASSERT_FALSE(mDispatcher->isPointerInWindow(left->getToken(), ADISPLAY_ID_DEFAULT, DEVICE_ID,
11403 /*pointerId=*/1));
11404 ASSERT_FALSE(mDispatcher->isPointerInWindow(spy->getToken(), ADISPLAY_ID_DEFAULT, DEVICE_ID,
11405 /*pointerId=*/1));
11406 ASSERT_FALSE(mDispatcher->isPointerInWindow(right->getToken(), ADISPLAY_ID_DEFAULT, DEVICE_ID,
11407 /*pointerId=*/1));
11408
11409 // First pointer up.
11410 mDispatcher->notifyMotion(
11411 MotionArgsBuilder(ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN)
11412 .pointer(PointerBuilder(/*id=*/0, ToolType::FINGER).x(50).y(50))
11413 .build());
11414
11415 left->consumeMotionUp();
11416 spy->consumeMotionUp();
11417
11418 ASSERT_FALSE(mDispatcher->isPointerInWindow(left->getToken(), ADISPLAY_ID_DEFAULT, DEVICE_ID,
11419 /*pointerId=*/0));
11420 ASSERT_FALSE(mDispatcher->isPointerInWindow(spy->getToken(), ADISPLAY_ID_DEFAULT, DEVICE_ID,
11421 /*pointerId=*/0));
11422 ASSERT_FALSE(mDispatcher->isPointerInWindow(right->getToken(), ADISPLAY_ID_DEFAULT, DEVICE_ID,
11423 /*pointerId=*/0));
11424}
11425
11426TEST_F(InputDispatcherPointerInWindowTest, MultipleDevicesControllingOneMouse) {
11427 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
11428
11429 sp<FakeWindowHandle> left = sp<FakeWindowHandle>::make(application, mDispatcher, "Left Window",
11430 ADISPLAY_ID_DEFAULT);
11431 left->setFrame(Rect(0, 0, 100, 100));
11432 sp<FakeWindowHandle> right = sp<FakeWindowHandle>::make(application, mDispatcher,
11433 "Right Window", ADISPLAY_ID_DEFAULT);
11434 right->setFrame(Rect(100, 0, 200, 100));
11435
11436 mDispatcher->onWindowInfosChanged({{*left->getInfo(), *right->getInfo()}, {}, 0, 0});
11437
11438 ASSERT_FALSE(mDispatcher->isPointerInWindow(left->getToken(), ADISPLAY_ID_DEFAULT, DEVICE_ID,
11439 /*pointerId=*/0));
11440 ASSERT_FALSE(mDispatcher->isPointerInWindow(right->getToken(), ADISPLAY_ID_DEFAULT, DEVICE_ID,
11441 /*pointerId=*/0));
11442
11443 // Hover move into the window.
11444 mDispatcher->notifyMotion(
11445 MotionArgsBuilder(ACTION_HOVER_MOVE, AINPUT_SOURCE_MOUSE)
11446 .pointer(PointerBuilder(/*id=*/0, ToolType::MOUSE).x(50).y(50))
11447 .rawXCursorPosition(50)
11448 .rawYCursorPosition(50)
11449 .deviceId(DEVICE_ID)
11450 .build());
11451
11452 left->consumeMotionEvent(WithMotionAction(ACTION_HOVER_ENTER));
11453
11454 ASSERT_TRUE(mDispatcher->isPointerInWindow(left->getToken(), ADISPLAY_ID_DEFAULT, DEVICE_ID,
11455 /*pointerId=*/0));
11456
11457 // Move the mouse with another device. This cancels the hovering pointer from the first device.
11458 mDispatcher->notifyMotion(
11459 MotionArgsBuilder(ACTION_HOVER_MOVE, AINPUT_SOURCE_MOUSE)
11460 .pointer(PointerBuilder(/*id=*/0, ToolType::MOUSE).x(51).y(50))
11461 .rawXCursorPosition(51)
11462 .rawYCursorPosition(50)
11463 .deviceId(SECOND_DEVICE_ID)
11464 .build());
11465
11466 left->consumeMotionEvent(WithMotionAction(ACTION_HOVER_EXIT));
11467 left->consumeMotionEvent(WithMotionAction(ACTION_HOVER_ENTER));
11468
11469 // TODO(b/313689709): InputDispatcher's touch state is not updated, even though the window gets
11470 // a HOVER_EXIT from the first device.
11471 ASSERT_TRUE(mDispatcher->isPointerInWindow(left->getToken(), ADISPLAY_ID_DEFAULT, DEVICE_ID,
11472 /*pointerId=*/0));
11473 ASSERT_TRUE(mDispatcher->isPointerInWindow(left->getToken(), ADISPLAY_ID_DEFAULT,
11474 SECOND_DEVICE_ID,
11475 /*pointerId=*/0));
11476
11477 // Move the mouse outside the window. Document the current behavior, where the window does not
11478 // receive HOVER_EXIT even though the mouse left the window.
11479 mDispatcher->notifyMotion(
11480 MotionArgsBuilder(ACTION_HOVER_MOVE, AINPUT_SOURCE_MOUSE)
11481 .pointer(PointerBuilder(/*id=*/0, ToolType::MOUSE).x(150).y(50))
11482 .rawXCursorPosition(150)
11483 .rawYCursorPosition(50)
11484 .deviceId(SECOND_DEVICE_ID)
11485 .build());
11486
11487 left->consumeMotionEvent(WithMotionAction(ACTION_HOVER_EXIT));
11488 right->consumeMotionEvent(WithMotionAction(ACTION_HOVER_ENTER));
11489 ASSERT_TRUE(mDispatcher->isPointerInWindow(left->getToken(), ADISPLAY_ID_DEFAULT, DEVICE_ID,
11490 /*pointerId=*/0));
11491 ASSERT_FALSE(mDispatcher->isPointerInWindow(left->getToken(), ADISPLAY_ID_DEFAULT,
11492 SECOND_DEVICE_ID,
11493 /*pointerId=*/0));
11494}
11495
Garfield Tane84e6f92019-08-29 17:28:41 -070011496} // namespace android::inputdispatcher