blob: 7f25608dd789f79eea74128a71794387031cb6bd [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 Vishniakoued89cbb2023-10-13 10:42:44 -0700135/**
136 * Provide a local override for a flag value. The value is restored when the object of this class
137 * goes out of scope.
138 * This class is not intended to be used directly, because its usage is cumbersome.
139 * Instead, a wrapper macro SCOPED_FLAG_OVERRIDE is provided.
140 */
141class ScopedFlagOverride {
142public:
143 ScopedFlagOverride(std::function<bool()> read, std::function<void(bool)> write, bool value)
144 : mInitialValue(read()), mWriteValue(write) {
145 mWriteValue(value);
146 }
147 ~ScopedFlagOverride() { mWriteValue(mInitialValue); }
148
149private:
150 const bool mInitialValue;
151 std::function<void(bool)> mWriteValue;
152};
153
154typedef bool (*readFlagValueFunction)();
155typedef void (*writeFlagValueFunction)(bool);
156
157/**
158 * Use this macro to locally override a flag value.
159 * Example usage:
160 * SCOPED_FLAG_OVERRIDE(enable_multi_device_same_window_stream, false);
161 * Note: this works by creating a local variable in your current scope. Don't call this twice for
162 * the same flag, because the variable names will clash!
163 */
164#define SCOPED_FLAG_OVERRIDE(NAME, VALUE) \
165 readFlagValueFunction read##NAME = com::android::input::flags::NAME; \
166 writeFlagValueFunction write##NAME = com::android::input::flags::NAME; \
167 ScopedFlagOverride override##NAME(read##NAME, write##NAME, (VALUE))
168
Siarhei Vishniakouf4043212023-09-18 19:33:03 -0700169} // namespace
Michael Wrightd02c5b62014-02-10 15:10:22 -0800170
Michael Wrightd02c5b62014-02-10 15:10:22 -0800171// --- InputDispatcherTest ---
172
173class InputDispatcherTest : public testing::Test {
174protected:
Prabir Pradhana41d2442023-04-20 21:30:40 +0000175 std::unique_ptr<FakeInputDispatcherPolicy> mFakePolicy;
Siarhei Vishniakou18050092021-09-01 13:32:49 -0700176 std::unique_ptr<InputDispatcher> mDispatcher;
Prabir Pradhanc5340732024-03-20 22:53:52 +0000177 std::shared_ptr<VerifyingTrace> mVerifyingTrace;
Michael Wrightd02c5b62014-02-10 15:10:22 -0800178
Siarhei Vishniakouf2652122021-03-05 21:39:46 +0000179 void SetUp() override {
Prabir Pradhanc5340732024-03-20 22:53:52 +0000180 mVerifyingTrace = std::make_shared<VerifyingTrace>();
181 FakeWindowHandle::sOnEventReceivedCallback = [this](const auto& _1, const auto& _2) {
182 handleEventReceivedByWindow(_1, _2);
183 };
184
Prabir Pradhana41d2442023-04-20 21:30:40 +0000185 mFakePolicy = std::make_unique<FakeInputDispatcherPolicy>();
Prabir Pradhandc3a2ad2024-02-05 19:03:51 +0000186 mDispatcher = std::make_unique<InputDispatcher>(*mFakePolicy,
187 std::make_unique<FakeInputTracingBackend>(
Prabir Pradhanc5340732024-03-20 22:53:52 +0000188 mVerifyingTrace));
Siarhei Vishniakoua7333112023-10-27 13:33:29 -0700189
Harry Cutts101ee9b2023-07-06 18:04:14 +0000190 mDispatcher->setInputDispatchMode(/*enabled=*/true, /*frozen=*/false);
Siarhei Vishniakou870ecec2020-12-09 08:07:46 -1000191 // Start InputDispatcher thread
Prabir Pradhan3608aad2019-10-02 17:08:26 -0700192 ASSERT_EQ(OK, mDispatcher->start());
Michael Wrightd02c5b62014-02-10 15:10:22 -0800193 }
194
Siarhei Vishniakouf2652122021-03-05 21:39:46 +0000195 void TearDown() override {
Prabir Pradhanc5340732024-03-20 22:53:52 +0000196 ASSERT_NO_FATAL_FAILURE(mVerifyingTrace->verifyExpectedEventsTraced());
197 FakeWindowHandle::sOnEventReceivedCallback = nullptr;
198
Prabir Pradhan3608aad2019-10-02 17:08:26 -0700199 ASSERT_EQ(OK, mDispatcher->stop());
Prabir Pradhana41d2442023-04-20 21:30:40 +0000200 mFakePolicy.reset();
Siarhei Vishniakou18050092021-09-01 13:32:49 -0700201 mDispatcher.reset();
Michael Wrightd02c5b62014-02-10 15:10:22 -0800202 }
Siarhei Vishniakou4cb50ca2020-05-26 21:43:02 -0700203
Prabir Pradhanc5340732024-03-20 22:53:52 +0000204 void handleEventReceivedByWindow(const std::unique_ptr<InputEvent>& event,
205 const gui::WindowInfo& info) {
206 if (!event) {
207 return;
208 }
209
210 switch (event->getType()) {
211 case InputEventType::KEY: {
212 mVerifyingTrace->expectKeyDispatchTraced(static_cast<KeyEvent&>(*event), info.id);
213 break;
214 }
215 case InputEventType::MOTION: {
216 mVerifyingTrace->expectMotionDispatchTraced(static_cast<MotionEvent&>(*event),
217 info.id);
218 break;
219 }
220 default:
221 break;
222 }
223 }
224
Siarhei Vishniakou4cb50ca2020-05-26 21:43:02 -0700225 /**
226 * Used for debugging when writing the test
227 */
228 void dumpDispatcherState() {
229 std::string dump;
230 mDispatcher->dump(dump);
231 std::stringstream ss(dump);
232 std::string to;
233
234 while (std::getline(ss, to, '\n')) {
235 ALOGE("%s", to.c_str());
236 }
237 }
Vishnu Nair958da932020-08-21 17:12:37 -0700238
Chavi Weingarten847e8512023-03-29 00:26:09 +0000239 void setFocusedWindow(const sp<WindowInfoHandle>& window) {
Vishnu Nair958da932020-08-21 17:12:37 -0700240 FocusRequest request;
241 request.token = window->getToken();
Siarhei Vishniakou5d552c42021-05-21 05:02:22 +0000242 request.windowName = window->getName();
Vishnu Nair958da932020-08-21 17:12:37 -0700243 request.timestamp = systemTime(SYSTEM_TIME_MONOTONIC);
244 request.displayId = window->getInfo()->displayId;
245 mDispatcher->setFocusedWindow(request);
246 }
Michael Wrightd02c5b62014-02-10 15:10:22 -0800247};
248
Michael Wrightd02c5b62014-02-10 15:10:22 -0800249TEST_F(InputDispatcherTest, InjectInputEvent_ValidatesKeyEvents) {
250 KeyEvent event;
251
252 // Rejects undefined key actions.
Garfield Tanfbe732e2020-01-24 11:26:14 -0800253 event.initialize(InputEvent::nextId(), DEVICE_ID, AINPUT_SOURCE_KEYBOARD, ADISPLAY_ID_NONE,
254 INVALID_HMAC,
Harry Cutts101ee9b2023-07-06 18:04:14 +0000255 /*action=*/-1, 0, AKEYCODE_A, KEY_A, AMETA_NONE, 0, ARBITRARY_TIME,
Siarhei Vishniakou9c858ac2020-01-23 14:20:11 -0600256 ARBITRARY_TIME);
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -0800257 ASSERT_EQ(InputEventInjectionResult::FAILED,
Harry Cutts33476232023-01-30 19:57:29 +0000258 mDispatcher->injectInputEvent(&event, /*targetUid=*/{}, InputEventInjectionSync::NONE,
Prabir Pradhan5735a322022-04-11 17:23:34 +0000259 0ms, 0))
Michael Wrightd02c5b62014-02-10 15:10:22 -0800260 << "Should reject key events with undefined action.";
261
262 // Rejects ACTION_MULTIPLE since it is not supported despite being defined in the API.
Garfield Tanfbe732e2020-01-24 11:26:14 -0800263 event.initialize(InputEvent::nextId(), DEVICE_ID, AINPUT_SOURCE_KEYBOARD, ADISPLAY_ID_NONE,
264 INVALID_HMAC, AKEY_EVENT_ACTION_MULTIPLE, 0, AKEYCODE_A, KEY_A, AMETA_NONE, 0,
Siarhei Vishniakou9c858ac2020-01-23 14:20:11 -0600265 ARBITRARY_TIME, ARBITRARY_TIME);
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -0800266 ASSERT_EQ(InputEventInjectionResult::FAILED,
Harry Cutts33476232023-01-30 19:57:29 +0000267 mDispatcher->injectInputEvent(&event, /*targetUid=*/{}, InputEventInjectionSync::NONE,
Prabir Pradhan5735a322022-04-11 17:23:34 +0000268 0ms, 0))
Michael Wrightd02c5b62014-02-10 15:10:22 -0800269 << "Should reject key events with ACTION_MULTIPLE.";
270}
271
272TEST_F(InputDispatcherTest, InjectInputEvent_ValidatesMotionEvents) {
273 MotionEvent event;
274 PointerProperties pointerProperties[MAX_POINTERS + 1];
275 PointerCoords pointerCoords[MAX_POINTERS + 1];
Siarhei Vishniakou01747382022-01-20 13:23:27 -0800276 for (size_t i = 0; i <= MAX_POINTERS; i++) {
Michael Wrightd02c5b62014-02-10 15:10:22 -0800277 pointerProperties[i].clear();
278 pointerProperties[i].id = i;
279 pointerCoords[i].clear();
280 }
281
Siarhei Vishniakou49e59222018-12-28 18:17:15 -0800282 // Some constants commonly used below
283 constexpr int32_t source = AINPUT_SOURCE_TOUCHSCREEN;
284 constexpr int32_t edgeFlags = AMOTION_EVENT_EDGE_FLAG_NONE;
285 constexpr int32_t metaState = AMETA_NONE;
286 constexpr MotionClassification classification = MotionClassification::NONE;
287
chaviw9eaa22c2020-07-01 16:21:27 -0700288 ui::Transform identityTransform;
Michael Wrightd02c5b62014-02-10 15:10:22 -0800289 // Rejects undefined motion actions.
Garfield Tanfbe732e2020-01-24 11:26:14 -0800290 event.initialize(InputEvent::nextId(), DEVICE_ID, source, DISPLAY_ID, INVALID_HMAC,
Harry Cutts101ee9b2023-07-06 18:04:14 +0000291 /*action=*/-1, 0, 0, edgeFlags, metaState, 0, classification,
chaviw9eaa22c2020-07-01 16:21:27 -0700292 identityTransform, 0, 0, AMOTION_EVENT_INVALID_CURSOR_POSITION,
Prabir Pradhanb9b18502021-08-26 12:30:32 -0700293 AMOTION_EVENT_INVALID_CURSOR_POSITION, identityTransform, ARBITRARY_TIME,
294 ARBITRARY_TIME,
Harry Cutts101ee9b2023-07-06 18:04:14 +0000295 /*pointerCount=*/1, pointerProperties, pointerCoords);
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -0800296 ASSERT_EQ(InputEventInjectionResult::FAILED,
Harry Cutts33476232023-01-30 19:57:29 +0000297 mDispatcher->injectInputEvent(&event, /*targetUid=*/{}, InputEventInjectionSync::NONE,
Prabir Pradhan5735a322022-04-11 17:23:34 +0000298 0ms, 0))
Michael Wrightd02c5b62014-02-10 15:10:22 -0800299 << "Should reject motion events with undefined action.";
300
301 // Rejects pointer down with invalid index.
Garfield Tanfbe732e2020-01-24 11:26:14 -0800302 event.initialize(InputEvent::nextId(), DEVICE_ID, source, DISPLAY_ID, INVALID_HMAC,
Siarhei Vishniakoua16e3a22022-03-02 15:26:40 -0800303 POINTER_1_DOWN, 0, 0, edgeFlags, metaState, 0, classification,
304 identityTransform, 0, 0, AMOTION_EVENT_INVALID_CURSOR_POSITION,
305 AMOTION_EVENT_INVALID_CURSOR_POSITION, identityTransform, ARBITRARY_TIME,
306 ARBITRARY_TIME,
Harry Cutts101ee9b2023-07-06 18:04:14 +0000307 /*pointerCount=*/1, pointerProperties, pointerCoords);
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -0800308 ASSERT_EQ(InputEventInjectionResult::FAILED,
Harry Cutts33476232023-01-30 19:57:29 +0000309 mDispatcher->injectInputEvent(&event, /*targetUid=*/{}, InputEventInjectionSync::NONE,
Prabir Pradhan5735a322022-04-11 17:23:34 +0000310 0ms, 0))
Michael Wrightd02c5b62014-02-10 15:10:22 -0800311 << "Should reject motion events with pointer down index too large.";
312
Garfield Tanfbe732e2020-01-24 11:26:14 -0800313 event.initialize(InputEvent::nextId(), DEVICE_ID, source, DISPLAY_ID, INVALID_HMAC,
Garfield Tan00f511d2019-06-12 16:55:40 -0700314 AMOTION_EVENT_ACTION_POINTER_DOWN |
315 (~0U << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT),
chaviw9eaa22c2020-07-01 16:21:27 -0700316 0, 0, edgeFlags, metaState, 0, classification, identityTransform, 0, 0,
317 AMOTION_EVENT_INVALID_CURSOR_POSITION, AMOTION_EVENT_INVALID_CURSOR_POSITION,
Prabir Pradhanb9b18502021-08-26 12:30:32 -0700318 identityTransform, ARBITRARY_TIME, ARBITRARY_TIME,
Harry Cutts101ee9b2023-07-06 18:04:14 +0000319 /*pointerCount=*/1, pointerProperties, pointerCoords);
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -0800320 ASSERT_EQ(InputEventInjectionResult::FAILED,
Harry Cutts33476232023-01-30 19:57:29 +0000321 mDispatcher->injectInputEvent(&event, /*targetUid=*/{}, InputEventInjectionSync::NONE,
Prabir Pradhan5735a322022-04-11 17:23:34 +0000322 0ms, 0))
Michael Wrightd02c5b62014-02-10 15:10:22 -0800323 << "Should reject motion events with pointer down index too small.";
324
325 // Rejects pointer up with invalid index.
Garfield Tanfbe732e2020-01-24 11:26:14 -0800326 event.initialize(InputEvent::nextId(), DEVICE_ID, source, DISPLAY_ID, INVALID_HMAC,
Siarhei Vishniakoua16e3a22022-03-02 15:26:40 -0800327 POINTER_1_UP, 0, 0, edgeFlags, metaState, 0, classification, identityTransform,
328 0, 0, AMOTION_EVENT_INVALID_CURSOR_POSITION,
329 AMOTION_EVENT_INVALID_CURSOR_POSITION, identityTransform, ARBITRARY_TIME,
330 ARBITRARY_TIME,
Harry Cutts101ee9b2023-07-06 18:04:14 +0000331 /*pointerCount=*/1, pointerProperties, pointerCoords);
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -0800332 ASSERT_EQ(InputEventInjectionResult::FAILED,
Harry Cutts33476232023-01-30 19:57:29 +0000333 mDispatcher->injectInputEvent(&event, /*targetUid=*/{}, InputEventInjectionSync::NONE,
Prabir Pradhan5735a322022-04-11 17:23:34 +0000334 0ms, 0))
Michael Wrightd02c5b62014-02-10 15:10:22 -0800335 << "Should reject motion events with pointer up index too large.";
336
Garfield Tanfbe732e2020-01-24 11:26:14 -0800337 event.initialize(InputEvent::nextId(), DEVICE_ID, source, DISPLAY_ID, INVALID_HMAC,
Garfield Tan00f511d2019-06-12 16:55:40 -0700338 AMOTION_EVENT_ACTION_POINTER_UP |
339 (~0U << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT),
chaviw9eaa22c2020-07-01 16:21:27 -0700340 0, 0, edgeFlags, metaState, 0, classification, identityTransform, 0, 0,
341 AMOTION_EVENT_INVALID_CURSOR_POSITION, AMOTION_EVENT_INVALID_CURSOR_POSITION,
Prabir Pradhanb9b18502021-08-26 12:30:32 -0700342 identityTransform, ARBITRARY_TIME, ARBITRARY_TIME,
Harry Cutts101ee9b2023-07-06 18:04:14 +0000343 /*pointerCount=*/1, pointerProperties, pointerCoords);
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -0800344 ASSERT_EQ(InputEventInjectionResult::FAILED,
Harry Cutts33476232023-01-30 19:57:29 +0000345 mDispatcher->injectInputEvent(&event, /*targetUid=*/{}, InputEventInjectionSync::NONE,
Prabir Pradhan5735a322022-04-11 17:23:34 +0000346 0ms, 0))
Michael Wrightd02c5b62014-02-10 15:10:22 -0800347 << "Should reject motion events with pointer up index too small.";
348
349 // Rejects motion events with invalid number of pointers.
Garfield Tanfbe732e2020-01-24 11:26:14 -0800350 event.initialize(InputEvent::nextId(), DEVICE_ID, source, DISPLAY_ID, INVALID_HMAC,
351 AMOTION_EVENT_ACTION_DOWN, 0, 0, edgeFlags, metaState, 0, classification,
chaviw9eaa22c2020-07-01 16:21:27 -0700352 identityTransform, 0, 0, AMOTION_EVENT_INVALID_CURSOR_POSITION,
Prabir Pradhanb9b18502021-08-26 12:30:32 -0700353 AMOTION_EVENT_INVALID_CURSOR_POSITION, identityTransform, ARBITRARY_TIME,
354 ARBITRARY_TIME,
Harry Cutts101ee9b2023-07-06 18:04:14 +0000355 /*pointerCount=*/0, pointerProperties, pointerCoords);
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -0800356 ASSERT_EQ(InputEventInjectionResult::FAILED,
Harry Cutts33476232023-01-30 19:57:29 +0000357 mDispatcher->injectInputEvent(&event, /*targetUid=*/{}, InputEventInjectionSync::NONE,
Prabir Pradhan5735a322022-04-11 17:23:34 +0000358 0ms, 0))
Michael Wrightd02c5b62014-02-10 15:10:22 -0800359 << "Should reject motion events with 0 pointers.";
360
Garfield Tanfbe732e2020-01-24 11:26:14 -0800361 event.initialize(InputEvent::nextId(), DEVICE_ID, source, DISPLAY_ID, INVALID_HMAC,
362 AMOTION_EVENT_ACTION_DOWN, 0, 0, edgeFlags, metaState, 0, classification,
chaviw9eaa22c2020-07-01 16:21:27 -0700363 identityTransform, 0, 0, AMOTION_EVENT_INVALID_CURSOR_POSITION,
Prabir Pradhanb9b18502021-08-26 12:30:32 -0700364 AMOTION_EVENT_INVALID_CURSOR_POSITION, identityTransform, ARBITRARY_TIME,
365 ARBITRARY_TIME,
Harry Cutts101ee9b2023-07-06 18:04:14 +0000366 /*pointerCount=*/MAX_POINTERS + 1, pointerProperties, pointerCoords);
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -0800367 ASSERT_EQ(InputEventInjectionResult::FAILED,
Harry Cutts33476232023-01-30 19:57:29 +0000368 mDispatcher->injectInputEvent(&event, /*targetUid=*/{}, InputEventInjectionSync::NONE,
Prabir Pradhan5735a322022-04-11 17:23:34 +0000369 0ms, 0))
Michael Wrightd02c5b62014-02-10 15:10:22 -0800370 << "Should reject motion events with more than MAX_POINTERS pointers.";
371
372 // Rejects motion events with invalid pointer ids.
373 pointerProperties[0].id = -1;
Garfield Tanfbe732e2020-01-24 11:26:14 -0800374 event.initialize(InputEvent::nextId(), DEVICE_ID, source, DISPLAY_ID, INVALID_HMAC,
375 AMOTION_EVENT_ACTION_DOWN, 0, 0, edgeFlags, metaState, 0, classification,
chaviw9eaa22c2020-07-01 16:21:27 -0700376 identityTransform, 0, 0, AMOTION_EVENT_INVALID_CURSOR_POSITION,
Prabir Pradhanb9b18502021-08-26 12:30:32 -0700377 AMOTION_EVENT_INVALID_CURSOR_POSITION, identityTransform, ARBITRARY_TIME,
378 ARBITRARY_TIME,
Harry Cutts101ee9b2023-07-06 18:04:14 +0000379 /*pointerCount=*/1, pointerProperties, pointerCoords);
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -0800380 ASSERT_EQ(InputEventInjectionResult::FAILED,
Harry Cutts33476232023-01-30 19:57:29 +0000381 mDispatcher->injectInputEvent(&event, /*targetUid=*/{}, InputEventInjectionSync::NONE,
Prabir Pradhan5735a322022-04-11 17:23:34 +0000382 0ms, 0))
Michael Wrightd02c5b62014-02-10 15:10:22 -0800383 << "Should reject motion events with pointer ids less than 0.";
384
385 pointerProperties[0].id = MAX_POINTER_ID + 1;
Garfield Tanfbe732e2020-01-24 11:26:14 -0800386 event.initialize(InputEvent::nextId(), DEVICE_ID, source, DISPLAY_ID, INVALID_HMAC,
387 AMOTION_EVENT_ACTION_DOWN, 0, 0, edgeFlags, metaState, 0, classification,
chaviw9eaa22c2020-07-01 16:21:27 -0700388 identityTransform, 0, 0, AMOTION_EVENT_INVALID_CURSOR_POSITION,
Prabir Pradhanb9b18502021-08-26 12:30:32 -0700389 AMOTION_EVENT_INVALID_CURSOR_POSITION, identityTransform, ARBITRARY_TIME,
390 ARBITRARY_TIME,
Harry Cutts101ee9b2023-07-06 18:04:14 +0000391 /*pointerCount=*/1, pointerProperties, pointerCoords);
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -0800392 ASSERT_EQ(InputEventInjectionResult::FAILED,
Harry Cutts33476232023-01-30 19:57:29 +0000393 mDispatcher->injectInputEvent(&event, /*targetUid=*/{}, InputEventInjectionSync::NONE,
Prabir Pradhan5735a322022-04-11 17:23:34 +0000394 0ms, 0))
Michael Wrightd02c5b62014-02-10 15:10:22 -0800395 << "Should reject motion events with pointer ids greater than MAX_POINTER_ID.";
396
397 // Rejects motion events with duplicate pointer ids.
398 pointerProperties[0].id = 1;
399 pointerProperties[1].id = 1;
Garfield Tanfbe732e2020-01-24 11:26:14 -0800400 event.initialize(InputEvent::nextId(), DEVICE_ID, source, DISPLAY_ID, INVALID_HMAC,
401 AMOTION_EVENT_ACTION_DOWN, 0, 0, edgeFlags, metaState, 0, classification,
chaviw9eaa22c2020-07-01 16:21:27 -0700402 identityTransform, 0, 0, AMOTION_EVENT_INVALID_CURSOR_POSITION,
Prabir Pradhanb9b18502021-08-26 12:30:32 -0700403 AMOTION_EVENT_INVALID_CURSOR_POSITION, identityTransform, ARBITRARY_TIME,
404 ARBITRARY_TIME,
Harry Cutts101ee9b2023-07-06 18:04:14 +0000405 /*pointerCount=*/2, pointerProperties, pointerCoords);
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -0800406 ASSERT_EQ(InputEventInjectionResult::FAILED,
Harry Cutts33476232023-01-30 19:57:29 +0000407 mDispatcher->injectInputEvent(&event, /*targetUid=*/{}, InputEventInjectionSync::NONE,
Prabir Pradhan5735a322022-04-11 17:23:34 +0000408 0ms, 0))
Michael Wrightd02c5b62014-02-10 15:10:22 -0800409 << "Should reject motion events with duplicate pointer ids.";
410}
411
Siarhei Vishniakou2bfa9052019-11-21 18:10:54 -0800412/* Test InputDispatcher for notifyConfigurationChanged and notifySwitch events */
413
414TEST_F(InputDispatcherTest, NotifyConfigurationChanged_CallsPolicy) {
415 constexpr nsecs_t eventTime = 20;
Prabir Pradhan678438e2023-04-13 19:32:51 +0000416 mDispatcher->notifyConfigurationChanged({/*id=*/10, eventTime});
Siarhei Vishniakou2bfa9052019-11-21 18:10:54 -0800417 ASSERT_TRUE(mDispatcher->waitForIdle());
418
419 mFakePolicy->assertNotifyConfigurationChangedWasCalled(eventTime);
420}
421
422TEST_F(InputDispatcherTest, NotifySwitch_CallsPolicy) {
Prabir Pradhana8fe7c52023-12-14 22:07:23 +0000423 NotifySwitchArgs args(InputEvent::nextId(), /*eventTime=*/20, /*policyFlags=*/0,
424 /*switchValues=*/1,
Harry Cutts33476232023-01-30 19:57:29 +0000425 /*switchMask=*/2);
Prabir Pradhan678438e2023-04-13 19:32:51 +0000426 mDispatcher->notifySwitch(args);
Siarhei Vishniakou2bfa9052019-11-21 18:10:54 -0800427
428 // InputDispatcher adds POLICY_FLAG_TRUSTED because the event went through InputListener
429 args.policyFlags |= POLICY_FLAG_TRUSTED;
430 mFakePolicy->assertNotifySwitchWasCalled(args);
431}
432
Siarhei Vishniakouadeb6fa2023-05-26 09:11:06 -0700433namespace {
434
Siarhei Vishniakou097c3db2020-05-06 14:18:38 -0700435static constexpr std::chrono::duration INJECT_EVENT_TIMEOUT = 500ms;
Siarhei Vishniakou540dbae2020-05-05 18:17:17 -0700436
Prabir Pradhan112b1ad2023-09-21 09:53:53 +0000437class FakeMonitorReceiver {
438public:
Siarhei Vishniakou2defec02023-06-08 17:24:44 -0700439 FakeMonitorReceiver(InputDispatcher& dispatcher, const std::string name, int32_t displayId)
440 : mInputReceiver(*dispatcher.createInputMonitor(displayId, name, MONITOR_PID), name) {}
Prabir Pradhan112b1ad2023-09-21 09:53:53 +0000441
Siarhei Vishniakou2defec02023-06-08 17:24:44 -0700442 sp<IBinder> getToken() { return mInputReceiver.getToken(); }
Prabir Pradhan112b1ad2023-09-21 09:53:53 +0000443
444 void consumeKeyDown(int32_t expectedDisplayId, int32_t expectedFlags = 0) {
Siarhei Vishniakou2defec02023-06-08 17:24:44 -0700445 mInputReceiver.consumeEvent(InputEventType::KEY, AKEY_EVENT_ACTION_DOWN, expectedDisplayId,
446 expectedFlags);
Prabir Pradhan112b1ad2023-09-21 09:53:53 +0000447 }
448
449 std::optional<int32_t> receiveEvent() {
Siarhei Vishniakoud3061ab2023-12-18 20:41:08 -0800450 const auto [sequenceNum, _] = mInputReceiver.receiveEvent(CONSUME_TIMEOUT_EVENT_EXPECTED);
451 return sequenceNum;
Prabir Pradhan112b1ad2023-09-21 09:53:53 +0000452 }
453
Siarhei Vishniakou2defec02023-06-08 17:24:44 -0700454 void finishEvent(uint32_t consumeSeq) { return mInputReceiver.finishEvent(consumeSeq); }
Prabir Pradhan112b1ad2023-09-21 09:53:53 +0000455
456 void consumeMotionDown(int32_t expectedDisplayId, int32_t expectedFlags = 0) {
Siarhei Vishniakou2defec02023-06-08 17:24:44 -0700457 mInputReceiver.consumeEvent(InputEventType::MOTION, AMOTION_EVENT_ACTION_DOWN,
458 expectedDisplayId, expectedFlags);
Prabir Pradhan112b1ad2023-09-21 09:53:53 +0000459 }
460
461 void consumeMotionMove(int32_t expectedDisplayId, int32_t expectedFlags = 0) {
Siarhei Vishniakou2defec02023-06-08 17:24:44 -0700462 mInputReceiver.consumeEvent(InputEventType::MOTION, AMOTION_EVENT_ACTION_MOVE,
463 expectedDisplayId, expectedFlags);
Prabir Pradhan112b1ad2023-09-21 09:53:53 +0000464 }
465
466 void consumeMotionUp(int32_t expectedDisplayId, int32_t expectedFlags = 0) {
Siarhei Vishniakou2defec02023-06-08 17:24:44 -0700467 mInputReceiver.consumeEvent(InputEventType::MOTION, AMOTION_EVENT_ACTION_UP,
468 expectedDisplayId, expectedFlags);
Prabir Pradhan112b1ad2023-09-21 09:53:53 +0000469 }
470
471 void consumeMotionCancel(int32_t expectedDisplayId, int32_t expectedFlags = 0) {
Siarhei Vishniakou2defec02023-06-08 17:24:44 -0700472 mInputReceiver.consumeMotionEvent(
Prabir Pradhan112b1ad2023-09-21 09:53:53 +0000473 AllOf(WithMotionAction(AMOTION_EVENT_ACTION_CANCEL),
474 WithDisplayId(expectedDisplayId),
475 WithFlags(expectedFlags | AMOTION_EVENT_FLAG_CANCELED)));
476 }
477
478 void consumeMotionPointerDown(int32_t pointerIdx) {
479 int32_t action = AMOTION_EVENT_ACTION_POINTER_DOWN |
480 (pointerIdx << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT);
Siarhei Vishniakou2defec02023-06-08 17:24:44 -0700481 mInputReceiver.consumeEvent(InputEventType::MOTION, action, ADISPLAY_ID_DEFAULT,
482 /*expectedFlags=*/0);
Prabir Pradhan112b1ad2023-09-21 09:53:53 +0000483 }
484
485 void consumeMotionEvent(const ::testing::Matcher<MotionEvent>& matcher) {
Siarhei Vishniakou2defec02023-06-08 17:24:44 -0700486 mInputReceiver.consumeMotionEvent(matcher);
Prabir Pradhan112b1ad2023-09-21 09:53:53 +0000487 }
488
Siarhei Vishniakoud3061ab2023-12-18 20:41:08 -0800489 std::unique_ptr<MotionEvent> consumeMotion() { return mInputReceiver.consumeMotion(); }
Prabir Pradhan112b1ad2023-09-21 09:53:53 +0000490
Siarhei Vishniakouef2b4502023-12-28 11:51:47 -0800491 void assertNoEvents() { mInputReceiver.assertNoEvents(CONSUME_TIMEOUT_NO_EVENT_EXPECTED); }
Prabir Pradhan112b1ad2023-09-21 09:53:53 +0000492
493private:
Siarhei Vishniakou2defec02023-06-08 17:24:44 -0700494 FakeInputReceiver mInputReceiver;
Prabir Pradhan112b1ad2023-09-21 09:53:53 +0000495};
496
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -0800497static InputEventInjectionResult injectKey(
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -0700498 InputDispatcher& dispatcher, int32_t action, int32_t repeatCount,
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -0800499 int32_t displayId = ADISPLAY_ID_NONE,
500 InputEventInjectionSync syncMode = InputEventInjectionSync::WAIT_FOR_RESULT,
Prabir Pradhan93f342c2021-03-11 15:05:30 -0800501 std::chrono::milliseconds injectionTimeout = INJECT_EVENT_TIMEOUT,
Prabir Pradhan8a5c41d2023-06-08 19:13:46 +0000502 bool allowKeyRepeat = true, std::optional<gui::Uid> targetUid = {},
Prabir Pradhan5735a322022-04-11 17:23:34 +0000503 uint32_t policyFlags = DEFAULT_POLICY_FLAGS) {
Arthur Hungb92218b2018-08-14 12:00:21 +0800504 KeyEvent event;
505 nsecs_t currentTime = systemTime(SYSTEM_TIME_MONOTONIC);
506
507 // Define a valid key down event.
Garfield Tanfbe732e2020-01-24 11:26:14 -0800508 event.initialize(InputEvent::nextId(), DEVICE_ID, AINPUT_SOURCE_KEYBOARD, displayId,
Harry Cutts33476232023-01-30 19:57:29 +0000509 INVALID_HMAC, action, /*flags=*/0, AKEYCODE_A, KEY_A, AMETA_NONE, repeatCount,
510 currentTime, currentTime);
Arthur Hungb92218b2018-08-14 12:00:21 +0800511
Prabir Pradhan93f342c2021-03-11 15:05:30 -0800512 if (!allowKeyRepeat) {
513 policyFlags |= POLICY_FLAG_DISABLE_KEY_REPEAT;
514 }
Arthur Hungb92218b2018-08-14 12:00:21 +0800515 // Inject event until dispatch out.
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -0700516 return dispatcher.injectInputEvent(&event, targetUid, syncMode, injectionTimeout, policyFlags);
Arthur Hungb92218b2018-08-14 12:00:21 +0800517}
518
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -0700519static void assertInjectedKeyTimesOut(InputDispatcher& dispatcher) {
520 InputEventInjectionResult result =
521 injectKey(dispatcher, AKEY_EVENT_ACTION_DOWN, /*repeatCount=*/0, ADISPLAY_ID_NONE,
522 InputEventInjectionSync::WAIT_FOR_RESULT, CONSUME_TIMEOUT_NO_EVENT_EXPECTED);
523 if (result != InputEventInjectionResult::TIMED_OUT) {
524 FAIL() << "Injection should have timed out, but got " << ftl::enum_string(result);
525 }
526}
527
528static InputEventInjectionResult injectKeyDown(InputDispatcher& dispatcher,
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -0800529 int32_t displayId = ADISPLAY_ID_NONE) {
Harry Cutts33476232023-01-30 19:57:29 +0000530 return injectKey(dispatcher, AKEY_EVENT_ACTION_DOWN, /*repeatCount=*/0, displayId);
Siarhei Vishniakou4cb50ca2020-05-26 21:43:02 -0700531}
532
Prabir Pradhan93f342c2021-03-11 15:05:30 -0800533// Inject a down event that has key repeat disabled. This allows InputDispatcher to idle without
534// sending a subsequent key up. When key repeat is enabled, the dispatcher cannot idle because it
535// has to be woken up to process the repeating key.
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -0700536static InputEventInjectionResult injectKeyDownNoRepeat(InputDispatcher& dispatcher,
537 int32_t displayId = ADISPLAY_ID_NONE) {
Harry Cutts33476232023-01-30 19:57:29 +0000538 return injectKey(dispatcher, AKEY_EVENT_ACTION_DOWN, /*repeatCount=*/0, displayId,
Prabir Pradhan93f342c2021-03-11 15:05:30 -0800539 InputEventInjectionSync::WAIT_FOR_RESULT, INJECT_EVENT_TIMEOUT,
Harry Cutts33476232023-01-30 19:57:29 +0000540 /*allowKeyRepeat=*/false);
Prabir Pradhan93f342c2021-03-11 15:05:30 -0800541}
542
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -0700543static InputEventInjectionResult injectKeyUp(InputDispatcher& dispatcher,
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -0800544 int32_t displayId = ADISPLAY_ID_NONE) {
Harry Cutts33476232023-01-30 19:57:29 +0000545 return injectKey(dispatcher, AKEY_EVENT_ACTION_UP, /*repeatCount=*/0, displayId);
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -0700546}
547
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -0800548static InputEventInjectionResult injectMotionEvent(
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -0700549 InputDispatcher& dispatcher, const MotionEvent& event,
Garfield Tandf26e862020-07-01 20:18:19 -0700550 std::chrono::milliseconds injectionTimeout = INJECT_EVENT_TIMEOUT,
Prabir Pradhan5735a322022-04-11 17:23:34 +0000551 InputEventInjectionSync injectionMode = InputEventInjectionSync::WAIT_FOR_RESULT,
Prabir Pradhan8a5c41d2023-06-08 19:13:46 +0000552 std::optional<gui::Uid> targetUid = {}, uint32_t policyFlags = DEFAULT_POLICY_FLAGS) {
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -0700553 return dispatcher.injectInputEvent(&event, targetUid, injectionMode, injectionTimeout,
554 policyFlags);
Garfield Tandf26e862020-07-01 20:18:19 -0700555}
556
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -0800557static InputEventInjectionResult injectMotionEvent(
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -0700558 InputDispatcher& dispatcher, int32_t action, int32_t source, int32_t displayId,
559 const PointF& position = {100, 200},
Siarhei Vishniakou4cb50ca2020-05-26 21:43:02 -0700560 const PointF& cursorPosition = {AMOTION_EVENT_INVALID_CURSOR_POSITION,
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -0700561 AMOTION_EVENT_INVALID_CURSOR_POSITION},
562 std::chrono::milliseconds injectionTimeout = INJECT_EVENT_TIMEOUT,
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -0800563 InputEventInjectionSync injectionMode = InputEventInjectionSync::WAIT_FOR_RESULT,
Prabir Pradhan5735a322022-04-11 17:23:34 +0000564 nsecs_t eventTime = systemTime(SYSTEM_TIME_MONOTONIC),
Prabir Pradhan8a5c41d2023-06-08 19:13:46 +0000565 std::optional<gui::Uid> targetUid = {}, uint32_t policyFlags = DEFAULT_POLICY_FLAGS) {
Siarhei Vishniakou90ee4782023-05-08 11:57:24 -0700566 MotionEventBuilder motionBuilder =
567 MotionEventBuilder(action, source)
568 .displayId(displayId)
569 .eventTime(eventTime)
570 .rawXCursorPosition(cursorPosition.x)
571 .rawYCursorPosition(cursorPosition.y)
572 .pointer(
573 PointerBuilder(/*id=*/0, ToolType::FINGER).x(position.x).y(position.y));
574 if (MotionEvent::getActionMasked(action) == ACTION_DOWN) {
575 motionBuilder.downTime(eventTime);
576 }
Arthur Hungb92218b2018-08-14 12:00:21 +0800577
578 // Inject event until dispatch out.
Siarhei Vishniakou90ee4782023-05-08 11:57:24 -0700579 return injectMotionEvent(dispatcher, motionBuilder.build(), injectionTimeout, injectionMode,
580 targetUid, policyFlags);
Arthur Hungb92218b2018-08-14 12:00:21 +0800581}
582
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -0700583static InputEventInjectionResult injectMotionDown(InputDispatcher& dispatcher, int32_t source,
584 int32_t displayId,
585 const PointF& location = {100, 200}) {
Siarhei Vishniakou4cb50ca2020-05-26 21:43:02 -0700586 return injectMotionEvent(dispatcher, AMOTION_EVENT_ACTION_DOWN, source, displayId, location);
Garfield Tan00f511d2019-06-12 16:55:40 -0700587}
588
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -0700589static InputEventInjectionResult injectMotionUp(InputDispatcher& dispatcher, int32_t source,
590 int32_t displayId,
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -0800591 const PointF& location = {100, 200}) {
Siarhei Vishniakou4cb50ca2020-05-26 21:43:02 -0700592 return injectMotionEvent(dispatcher, AMOTION_EVENT_ACTION_UP, source, displayId, location);
Michael Wright3a240c42019-12-10 20:53:41 +0000593}
594
Jackal Guof9696682018-10-05 12:23:23 +0800595static NotifyKeyArgs generateKeyArgs(int32_t action, int32_t displayId = ADISPLAY_ID_NONE) {
596 nsecs_t currentTime = systemTime(SYSTEM_TIME_MONOTONIC);
597 // Define a valid key event.
Prabir Pradhana8fe7c52023-12-14 22:07:23 +0000598 NotifyKeyArgs args(InputEvent::nextId(), currentTime, /*readTime=*/0, DEVICE_ID,
599 AINPUT_SOURCE_KEYBOARD, displayId, POLICY_FLAG_PASS_TO_USER, action,
600 /*flags=*/0, AKEYCODE_A, KEY_A, AMETA_NONE, currentTime);
Jackal Guof9696682018-10-05 12:23:23 +0800601
602 return args;
603}
604
Josep del Riob3981622023-04-18 15:49:45 +0000605static NotifyKeyArgs generateSystemShortcutArgs(int32_t action,
606 int32_t displayId = ADISPLAY_ID_NONE) {
607 nsecs_t currentTime = systemTime(SYSTEM_TIME_MONOTONIC);
608 // Define a valid key event.
Prabir Pradhana8fe7c52023-12-14 22:07:23 +0000609 NotifyKeyArgs args(InputEvent::nextId(), currentTime, /*readTime=*/0, DEVICE_ID,
610 AINPUT_SOURCE_KEYBOARD, displayId, 0, action, /*flags=*/0, AKEYCODE_C, KEY_C,
611 AMETA_META_ON, currentTime);
Josep del Riob3981622023-04-18 15:49:45 +0000612
613 return args;
614}
615
616static NotifyKeyArgs generateAssistantKeyArgs(int32_t action,
617 int32_t displayId = ADISPLAY_ID_NONE) {
618 nsecs_t currentTime = systemTime(SYSTEM_TIME_MONOTONIC);
619 // Define a valid key event.
Prabir Pradhana8fe7c52023-12-14 22:07:23 +0000620 NotifyKeyArgs args(InputEvent::nextId(), currentTime, /*readTime=*/0, DEVICE_ID,
621 AINPUT_SOURCE_KEYBOARD, displayId, 0, action, /*flags=*/0, AKEYCODE_ASSIST,
622 KEY_ASSISTANT, AMETA_NONE, currentTime);
Josep del Riob3981622023-04-18 15:49:45 +0000623
624 return args;
625}
626
Prabir Pradhan678438e2023-04-13 19:32:51 +0000627[[nodiscard]] static NotifyMotionArgs generateMotionArgs(int32_t action, int32_t source,
628 int32_t displayId,
629 const std::vector<PointF>& points) {
chaviwd1c23182019-12-20 18:44:56 -0800630 size_t pointerCount = points.size();
chaviwaf87b3e2019-10-01 16:59:28 -0700631 if (action == AMOTION_EVENT_ACTION_DOWN || action == AMOTION_EVENT_ACTION_UP) {
632 EXPECT_EQ(1U, pointerCount) << "Actions DOWN and UP can only contain a single pointer";
633 }
634
chaviwd1c23182019-12-20 18:44:56 -0800635 PointerProperties pointerProperties[pointerCount];
636 PointerCoords pointerCoords[pointerCount];
Jackal Guof9696682018-10-05 12:23:23 +0800637
chaviwd1c23182019-12-20 18:44:56 -0800638 for (size_t i = 0; i < pointerCount; i++) {
639 pointerProperties[i].clear();
640 pointerProperties[i].id = i;
Siarhei Vishniakou6d73f832022-07-21 17:27:03 -0700641 pointerProperties[i].toolType = ToolType::FINGER;
Jackal Guof9696682018-10-05 12:23:23 +0800642
chaviwd1c23182019-12-20 18:44:56 -0800643 pointerCoords[i].clear();
644 pointerCoords[i].setAxisValue(AMOTION_EVENT_AXIS_X, points[i].x);
645 pointerCoords[i].setAxisValue(AMOTION_EVENT_AXIS_Y, points[i].y);
646 }
Jackal Guof9696682018-10-05 12:23:23 +0800647
648 nsecs_t currentTime = systemTime(SYSTEM_TIME_MONOTONIC);
649 // Define a valid motion event.
Prabir Pradhana8fe7c52023-12-14 22:07:23 +0000650 NotifyMotionArgs args(InputEvent::nextId(), currentTime, /*readTime=*/0, DEVICE_ID, source,
651 displayId, POLICY_FLAG_PASS_TO_USER, action, /*actionButton=*/0,
652 /*flags=*/0, AMETA_NONE, /*buttonState=*/0, MotionClassification::NONE,
chaviwd1c23182019-12-20 18:44:56 -0800653 AMOTION_EVENT_EDGE_FLAG_NONE, pointerCount, pointerProperties,
Harry Cutts101ee9b2023-07-06 18:04:14 +0000654 pointerCoords, /*xPrecision=*/0, /*yPrecision=*/0,
Garfield Tan00f511d2019-06-12 16:55:40 -0700655 AMOTION_EVENT_INVALID_CURSOR_POSITION,
Harry Cutts101ee9b2023-07-06 18:04:14 +0000656 AMOTION_EVENT_INVALID_CURSOR_POSITION, currentTime, /*videoFrames=*/{});
Jackal Guof9696682018-10-05 12:23:23 +0800657
658 return args;
659}
660
Siarhei Vishniakoua16e3a22022-03-02 15:26:40 -0800661static NotifyMotionArgs generateTouchArgs(int32_t action, const std::vector<PointF>& points) {
662 return generateMotionArgs(action, AINPUT_SOURCE_TOUCHSCREEN, DISPLAY_ID, points);
663}
664
chaviwd1c23182019-12-20 18:44:56 -0800665static NotifyMotionArgs generateMotionArgs(int32_t action, int32_t source, int32_t displayId) {
666 return generateMotionArgs(action, source, displayId, {PointF{100, 200}});
667}
668
Prabir Pradhan5cc1a692021-08-06 14:01:18 +0000669static NotifyPointerCaptureChangedArgs generatePointerCaptureChangedArgs(
670 const PointerCaptureRequest& request) {
Prabir Pradhana8fe7c52023-12-14 22:07:23 +0000671 return NotifyPointerCaptureChangedArgs(InputEvent::nextId(), systemTime(SYSTEM_TIME_MONOTONIC),
672 request);
Prabir Pradhan99987712020-11-10 18:43:05 -0800673}
674
Siarhei Vishniakouadeb6fa2023-05-26 09:11:06 -0700675} // namespace
676
Siarhei Vishniakou7aa3e942021-11-18 09:49:11 -0800677/**
678 * When a window unexpectedly disposes of its input channel, policy should be notified about the
679 * broken channel.
680 */
681TEST_F(InputDispatcherTest, WhenInputChannelBreaks_PolicyIsNotified) {
682 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
683 sp<FakeWindowHandle> window =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -0700684 sp<FakeWindowHandle>::make(application, mDispatcher,
685 "Window that breaks its input channel", ADISPLAY_ID_DEFAULT);
Siarhei Vishniakou7aa3e942021-11-18 09:49:11 -0800686
Siarhei Vishniakouc41de372023-07-20 13:14:26 -0700687 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Siarhei Vishniakou7aa3e942021-11-18 09:49:11 -0800688
689 // Window closes its channel, but the window remains.
690 window->destroyReceiver();
691 mFakePolicy->assertNotifyInputChannelBrokenWasCalled(window->getInfo()->token);
692}
693
Arthur Hungb92218b2018-08-14 12:00:21 +0800694TEST_F(InputDispatcherTest, SetInputWindow_SingleWindowTouch) {
Chris Yea209fde2020-07-22 13:54:51 -0700695 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -0700696 sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher,
697 "Fake Window", ADISPLAY_ID_DEFAULT);
Arthur Hungb92218b2018-08-14 12:00:21 +0800698
Siarhei Vishniakouc41de372023-07-20 13:14:26 -0700699 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -0800700 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -0700701 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT))
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -0800702 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
Arthur Hungb92218b2018-08-14 12:00:21 +0800703
704 // Window should receive motion event.
Siarhei Vishniakouc5ca85c2019-11-15 17:20:00 -0800705 window->consumeMotionDown(ADISPLAY_ID_DEFAULT);
Arthur Hungb92218b2018-08-14 12:00:21 +0800706}
707
Siarhei Vishniakouaeed0da2024-01-09 08:57:13 -0800708using InputDispatcherDeathTest = InputDispatcherTest;
709
710/**
711 * When 'onWindowInfosChanged' arguments contain a duplicate entry for the same window, dispatcher
712 * should crash.
713 */
714TEST_F(InputDispatcherDeathTest, DuplicateWindowInfosAbortDispatcher) {
715 testing::GTEST_FLAG(death_test_style) = "threadsafe";
716 ScopedSilentDeath _silentDeath;
717
718 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
719 sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher,
720 "Fake Window", ADISPLAY_ID_DEFAULT);
721 ASSERT_DEATH(mDispatcher->onWindowInfosChanged(
722 {{*window->getInfo(), *window->getInfo()}, {}, 0, 0}),
723 "Incorrect WindowInfosUpdate provided");
724}
725
Prabir Pradhanc44ce4d2021-10-05 05:26:29 -0700726TEST_F(InputDispatcherTest, WhenDisplayNotSpecified_InjectMotionToDefaultDisplay) {
727 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -0700728 sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher,
729 "Fake Window", ADISPLAY_ID_DEFAULT);
Prabir Pradhanc44ce4d2021-10-05 05:26:29 -0700730
Siarhei Vishniakouc41de372023-07-20 13:14:26 -0700731 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Prabir Pradhanc44ce4d2021-10-05 05:26:29 -0700732 // Inject a MotionEvent to an unknown display.
733 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -0700734 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_NONE))
Prabir Pradhanc44ce4d2021-10-05 05:26:29 -0700735 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
736
737 // Window should receive motion event.
738 window->consumeMotionDown(ADISPLAY_ID_DEFAULT);
739}
740
Siarhei Vishniakoufb9fcda2020-05-04 14:59:19 -0700741/**
Siarhei Vishniakouc41de372023-07-20 13:14:26 -0700742 * Calling onWindowInfosChanged once should not cause any issues.
743 * This test serves as a sanity check for the next test, where onWindowInfosChanged is
Siarhei Vishniakoufb9fcda2020-05-04 14:59:19 -0700744 * called twice.
745 */
Prabir Pradhan76bdecb2022-01-31 11:14:15 -0800746TEST_F(InputDispatcherTest, SetInputWindowOnceWithSingleTouchWindow) {
Chris Yea209fde2020-07-22 13:54:51 -0700747 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -0700748 sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher,
749 "Fake Window", ADISPLAY_ID_DEFAULT);
Siarhei Vishniakoufb9fcda2020-05-04 14:59:19 -0700750 window->setFrame(Rect(0, 0, 100, 100));
Siarhei Vishniakoufb9fcda2020-05-04 14:59:19 -0700751
Siarhei Vishniakouc41de372023-07-20 13:14:26 -0700752 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -0800753 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -0700754 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
Siarhei Vishniakoufb9fcda2020-05-04 14:59:19 -0700755 {50, 50}))
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -0800756 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
Siarhei Vishniakoufb9fcda2020-05-04 14:59:19 -0700757
758 // Window should receive motion event.
759 window->consumeMotionDown(ADISPLAY_ID_DEFAULT);
760}
761
762/**
Siarhei Vishniakouc41de372023-07-20 13:14:26 -0700763 * Calling onWindowInfosChanged twice, with the same info, should not cause any issues.
Siarhei Vishniakoufb9fcda2020-05-04 14:59:19 -0700764 */
765TEST_F(InputDispatcherTest, SetInputWindowTwice_SingleWindowTouch) {
Chris Yea209fde2020-07-22 13:54:51 -0700766 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -0700767 sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher,
768 "Fake Window", ADISPLAY_ID_DEFAULT);
Siarhei Vishniakoufb9fcda2020-05-04 14:59:19 -0700769 window->setFrame(Rect(0, 0, 100, 100));
Siarhei Vishniakoufb9fcda2020-05-04 14:59:19 -0700770
Siarhei Vishniakouc41de372023-07-20 13:14:26 -0700771 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
772 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -0800773 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -0700774 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
Siarhei Vishniakoufb9fcda2020-05-04 14:59:19 -0700775 {50, 50}))
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -0800776 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
Siarhei Vishniakoufb9fcda2020-05-04 14:59:19 -0700777
778 // Window should receive motion event.
779 window->consumeMotionDown(ADISPLAY_ID_DEFAULT);
780}
781
Arthur Hungb92218b2018-08-14 12:00:21 +0800782// The foreground window should receive the first touch down event.
783TEST_F(InputDispatcherTest, SetInputWindow_MultiWindowsTouch) {
Chris Yea209fde2020-07-22 13:54:51 -0700784 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
Siarhei Vishniakou870ecec2020-12-09 08:07:46 -1000785 sp<FakeWindowHandle> windowTop =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -0700786 sp<FakeWindowHandle>::make(application, mDispatcher, "Top", ADISPLAY_ID_DEFAULT);
Siarhei Vishniakou870ecec2020-12-09 08:07:46 -1000787 sp<FakeWindowHandle> windowSecond =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -0700788 sp<FakeWindowHandle>::make(application, mDispatcher, "Second", ADISPLAY_ID_DEFAULT);
Arthur Hungb92218b2018-08-14 12:00:21 +0800789
Siarhei Vishniakouc41de372023-07-20 13:14:26 -0700790 mDispatcher->onWindowInfosChanged(
791 {{*windowTop->getInfo(), *windowSecond->getInfo()}, {}, 0, 0});
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -0800792 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -0700793 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT))
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -0800794 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
Arthur Hungb92218b2018-08-14 12:00:21 +0800795
796 // Top window should receive the touch down event. Second window should not receive anything.
Siarhei Vishniakouc5ca85c2019-11-15 17:20:00 -0800797 windowTop->consumeMotionDown(ADISPLAY_ID_DEFAULT);
Arthur Hungb92218b2018-08-14 12:00:21 +0800798 windowSecond->assertNoEvents();
799}
800
Siarhei Vishniakouca205502021-07-16 21:31:58 +0000801/**
802 * Two windows: A top window, and a wallpaper behind the window.
803 * Touch goes to the top window, and then top window disappears. Ensure that wallpaper window
804 * gets ACTION_CANCEL.
Prabir Pradhan4d5c52f2022-01-31 08:52:10 -0800805 * 1. foregroundWindow <-- dup touch to wallpaper
806 * 2. wallpaperWindow <-- is wallpaper
Siarhei Vishniakouca205502021-07-16 21:31:58 +0000807 */
808TEST_F(InputDispatcherTest, WhenForegroundWindowDisappears_WallpaperTouchIsCanceled) {
809 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
810 sp<FakeWindowHandle> foregroundWindow =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -0700811 sp<FakeWindowHandle>::make(application, mDispatcher, "Foreground", ADISPLAY_ID_DEFAULT);
Prabir Pradhan4d5c52f2022-01-31 08:52:10 -0800812 foregroundWindow->setDupTouchToWallpaper(true);
Siarhei Vishniakouca205502021-07-16 21:31:58 +0000813 sp<FakeWindowHandle> wallpaperWindow =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -0700814 sp<FakeWindowHandle>::make(application, mDispatcher, "Wallpaper", ADISPLAY_ID_DEFAULT);
Prabir Pradhan4d5c52f2022-01-31 08:52:10 -0800815 wallpaperWindow->setIsWallpaper(true);
Siarhei Vishniakouca205502021-07-16 21:31:58 +0000816
Siarhei Vishniakouc41de372023-07-20 13:14:26 -0700817 mDispatcher->onWindowInfosChanged(
818 {{*foregroundWindow->getInfo(), *wallpaperWindow->getInfo()}, {}, 0, 0});
Siarhei Vishniakouca205502021-07-16 21:31:58 +0000819 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoud908f5a2023-11-16 10:25:12 -0800820 injectMotionEvent(*mDispatcher,
821 MotionEventBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
822 .pointer(PointerBuilder(0, ToolType::FINGER).x(100).y(200))
823 .build()))
Siarhei Vishniakouca205502021-07-16 21:31:58 +0000824 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
825
826 // Both foreground window and its wallpaper should receive the touch down
827 foregroundWindow->consumeMotionDown();
828 wallpaperWindow->consumeMotionDown(ADISPLAY_ID_DEFAULT, expectedWallpaperFlags);
829
830 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoud908f5a2023-11-16 10:25:12 -0800831 injectMotionEvent(*mDispatcher,
832 MotionEventBuilder(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN)
833 .pointer(PointerBuilder(0, ToolType::FINGER).x(110).y(200))
834 .build()))
Siarhei Vishniakouca205502021-07-16 21:31:58 +0000835 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
836
Siarhei Vishniakoud908f5a2023-11-16 10:25:12 -0800837 foregroundWindow->consumeMotionEvent(WithMotionAction(ACTION_MOVE));
Siarhei Vishniakouca205502021-07-16 21:31:58 +0000838 wallpaperWindow->consumeMotionMove(ADISPLAY_ID_DEFAULT, expectedWallpaperFlags);
839
840 // Now the foreground window goes away, but the wallpaper stays
Siarhei Vishniakouc41de372023-07-20 13:14:26 -0700841 mDispatcher->onWindowInfosChanged({{*wallpaperWindow->getInfo()}, {}, 0, 0});
Siarhei Vishniakouca205502021-07-16 21:31:58 +0000842 foregroundWindow->consumeMotionCancel();
843 // Since the "parent" window of the wallpaper is gone, wallpaper should receive cancel, too.
844 wallpaperWindow->consumeMotionCancel(ADISPLAY_ID_DEFAULT, expectedWallpaperFlags);
845}
846
847/**
Siarhei Vishniakou82dc0422023-02-17 23:12:52 -0800848 * Two fingers down on the window, and lift off the first finger.
849 * Next, cancel the gesture to the window by removing the window. Make sure that the CANCEL event
850 * contains a single pointer.
851 */
852TEST_F(InputDispatcherTest, CancelAfterPointer0Up) {
853 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
854 sp<FakeWindowHandle> window =
855 sp<FakeWindowHandle>::make(application, mDispatcher, "Window", ADISPLAY_ID_DEFAULT);
856
Siarhei Vishniakouc41de372023-07-20 13:14:26 -0700857 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Siarhei Vishniakou82dc0422023-02-17 23:12:52 -0800858 // First touch pointer down on right window
Prabir Pradhan678438e2023-04-13 19:32:51 +0000859 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
860 .pointer(PointerBuilder(0, ToolType::FINGER).x(100).y(100))
861 .build());
Siarhei Vishniakou82dc0422023-02-17 23:12:52 -0800862 // Second touch pointer down
Prabir Pradhan678438e2023-04-13 19:32:51 +0000863 mDispatcher->notifyMotion(MotionArgsBuilder(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
864 .pointer(PointerBuilder(0, ToolType::FINGER).x(100).y(100))
865 .pointer(PointerBuilder(1, ToolType::FINGER).x(110).y(100))
866 .build());
Siarhei Vishniakou82dc0422023-02-17 23:12:52 -0800867 // First touch pointer lifts. The second one remains down
Prabir Pradhan678438e2023-04-13 19:32:51 +0000868 mDispatcher->notifyMotion(MotionArgsBuilder(POINTER_0_UP, AINPUT_SOURCE_TOUCHSCREEN)
869 .pointer(PointerBuilder(0, ToolType::FINGER).x(100).y(100))
870 .pointer(PointerBuilder(1, ToolType::FINGER).x(110).y(100))
871 .build());
Siarhei Vishniakou82dc0422023-02-17 23:12:52 -0800872 window->consumeMotionEvent(WithMotionAction(ACTION_DOWN));
873 window->consumeMotionEvent(WithMotionAction(POINTER_1_DOWN));
874 window->consumeMotionEvent(WithMotionAction(POINTER_0_UP));
875
876 // Remove the window. The gesture should be canceled
Siarhei Vishniakouc41de372023-07-20 13:14:26 -0700877 mDispatcher->onWindowInfosChanged({{}, {}, 0, 0});
Siarhei Vishniakou82dc0422023-02-17 23:12:52 -0800878 const std::map<int32_t, PointF> expectedPointers{{1, PointF{110, 100}}};
879 window->consumeMotionEvent(
880 AllOf(WithMotionAction(ACTION_CANCEL), WithPointers(expectedPointers)));
881}
882
883/**
Siarhei Vishniakou2b030972021-11-18 10:01:27 -0800884 * Same test as WhenForegroundWindowDisappears_WallpaperTouchIsCanceled above,
885 * with the following differences:
886 * After ACTION_DOWN, Wallpaper window hangs up its channel, which forces the dispatcher to
887 * clean up the connection.
888 * This later may crash dispatcher during ACTION_CANCEL synthesis, if the dispatcher is not careful.
889 * Ensure that there's no crash in the dispatcher.
890 */
891TEST_F(InputDispatcherTest, WhenWallpaperDisappears_NoCrash) {
892 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
893 sp<FakeWindowHandle> foregroundWindow =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -0700894 sp<FakeWindowHandle>::make(application, mDispatcher, "Foreground", ADISPLAY_ID_DEFAULT);
Prabir Pradhan4d5c52f2022-01-31 08:52:10 -0800895 foregroundWindow->setDupTouchToWallpaper(true);
Siarhei Vishniakou2b030972021-11-18 10:01:27 -0800896 sp<FakeWindowHandle> wallpaperWindow =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -0700897 sp<FakeWindowHandle>::make(application, mDispatcher, "Wallpaper", ADISPLAY_ID_DEFAULT);
Prabir Pradhan4d5c52f2022-01-31 08:52:10 -0800898 wallpaperWindow->setIsWallpaper(true);
Siarhei Vishniakou2b030972021-11-18 10:01:27 -0800899
Siarhei Vishniakouc41de372023-07-20 13:14:26 -0700900 mDispatcher->onWindowInfosChanged(
901 {{*foregroundWindow->getInfo(), *wallpaperWindow->getInfo()}, {}, 0, 0});
Siarhei Vishniakou2b030972021-11-18 10:01:27 -0800902 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -0700903 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
Siarhei Vishniakou2b030972021-11-18 10:01:27 -0800904 {100, 200}))
905 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
906
907 // Both foreground window and its wallpaper should receive the touch down
908 foregroundWindow->consumeMotionDown();
909 wallpaperWindow->consumeMotionDown(ADISPLAY_ID_DEFAULT, expectedWallpaperFlags);
910
911 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -0700912 injectMotionEvent(*mDispatcher, AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN,
Siarhei Vishniakou2b030972021-11-18 10:01:27 -0800913 ADISPLAY_ID_DEFAULT, {110, 200}))
914 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
915
916 foregroundWindow->consumeMotionMove();
917 wallpaperWindow->consumeMotionMove(ADISPLAY_ID_DEFAULT, expectedWallpaperFlags);
918
919 // Wallpaper closes its channel, but the window remains.
920 wallpaperWindow->destroyReceiver();
921 mFakePolicy->assertNotifyInputChannelBrokenWasCalled(wallpaperWindow->getInfo()->token);
922
923 // Now the foreground window goes away, but the wallpaper stays, even though its channel
924 // is no longer valid.
Siarhei Vishniakouc41de372023-07-20 13:14:26 -0700925 mDispatcher->onWindowInfosChanged({{*wallpaperWindow->getInfo()}, {}, 0, 0});
Siarhei Vishniakou2b030972021-11-18 10:01:27 -0800926 foregroundWindow->consumeMotionCancel();
927}
928
Arthur Hungc539dbb2022-12-08 07:45:36 +0000929class ShouldSplitTouchFixture : public InputDispatcherTest,
930 public ::testing::WithParamInterface<bool> {};
931INSTANTIATE_TEST_SUITE_P(InputDispatcherTest, ShouldSplitTouchFixture,
932 ::testing::Values(true, false));
Siarhei Vishniakou2b030972021-11-18 10:01:27 -0800933/**
Siarhei Vishniakouca205502021-07-16 21:31:58 +0000934 * A single window that receives touch (on top), and a wallpaper window underneath it.
935 * The top window gets a multitouch gesture.
936 * Ensure that wallpaper gets the same gesture.
937 */
Arthur Hungc539dbb2022-12-08 07:45:36 +0000938TEST_P(ShouldSplitTouchFixture, WallpaperWindowReceivesMultiTouch) {
Siarhei Vishniakouca205502021-07-16 21:31:58 +0000939 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
Arthur Hungc539dbb2022-12-08 07:45:36 +0000940 sp<FakeWindowHandle> foregroundWindow =
941 sp<FakeWindowHandle>::make(application, mDispatcher, "Foreground", ADISPLAY_ID_DEFAULT);
942 foregroundWindow->setDupTouchToWallpaper(true);
943 foregroundWindow->setPreventSplitting(GetParam());
Siarhei Vishniakouca205502021-07-16 21:31:58 +0000944
945 sp<FakeWindowHandle> wallpaperWindow =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -0700946 sp<FakeWindowHandle>::make(application, mDispatcher, "Wallpaper", ADISPLAY_ID_DEFAULT);
Prabir Pradhan4d5c52f2022-01-31 08:52:10 -0800947 wallpaperWindow->setIsWallpaper(true);
Siarhei Vishniakouca205502021-07-16 21:31:58 +0000948
Siarhei Vishniakouc41de372023-07-20 13:14:26 -0700949 mDispatcher->onWindowInfosChanged(
950 {{*foregroundWindow->getInfo(), *wallpaperWindow->getInfo()}, {}, 0, 0});
Siarhei Vishniakouca205502021-07-16 21:31:58 +0000951
952 // Touch down on top window
953 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -0700954 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
Siarhei Vishniakouca205502021-07-16 21:31:58 +0000955 {100, 100}))
956 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
957
958 // Both top window and its wallpaper should receive the touch down
Arthur Hungc539dbb2022-12-08 07:45:36 +0000959 foregroundWindow->consumeMotionDown();
Siarhei Vishniakouca205502021-07-16 21:31:58 +0000960 wallpaperWindow->consumeMotionDown(ADISPLAY_ID_DEFAULT, expectedWallpaperFlags);
961
962 // Second finger down on the top window
963 const MotionEvent secondFingerDownEvent =
Siarhei Vishniakoua16e3a22022-03-02 15:26:40 -0800964 MotionEventBuilder(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
Siarhei Vishniakouca205502021-07-16 21:31:58 +0000965 .eventTime(systemTime(SYSTEM_TIME_MONOTONIC))
Siarhei Vishniakou6d73f832022-07-21 17:27:03 -0700966 .pointer(PointerBuilder(/*id=*/0, ToolType::FINGER).x(100).y(100))
967 .pointer(PointerBuilder(/*id=*/1, ToolType::FINGER).x(150).y(150))
Siarhei Vishniakouca205502021-07-16 21:31:58 +0000968 .build();
969 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -0700970 injectMotionEvent(*mDispatcher, secondFingerDownEvent, INJECT_EVENT_TIMEOUT,
Siarhei Vishniakouca205502021-07-16 21:31:58 +0000971 InputEventInjectionSync::WAIT_FOR_RESULT))
972 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
973
Harry Cutts33476232023-01-30 19:57:29 +0000974 foregroundWindow->consumeMotionPointerDown(/*pointerIndex=*/1);
975 wallpaperWindow->consumeMotionPointerDown(/*pointerIndex=*/1, ADISPLAY_ID_DEFAULT,
Siarhei Vishniakouca205502021-07-16 21:31:58 +0000976 expectedWallpaperFlags);
Arthur Hungc539dbb2022-12-08 07:45:36 +0000977
978 const MotionEvent secondFingerUpEvent =
979 MotionEventBuilder(POINTER_0_UP, AINPUT_SOURCE_TOUCHSCREEN)
980 .displayId(ADISPLAY_ID_DEFAULT)
981 .eventTime(systemTime(SYSTEM_TIME_MONOTONIC))
Siarhei Vishniakou6d73f832022-07-21 17:27:03 -0700982 .pointer(PointerBuilder(/*id=*/0, ToolType::FINGER).x(100).y(100))
983 .pointer(PointerBuilder(/*id=*/1, ToolType::FINGER).x(150).y(150))
Arthur Hungc539dbb2022-12-08 07:45:36 +0000984 .build();
985 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -0700986 injectMotionEvent(*mDispatcher, secondFingerUpEvent, INJECT_EVENT_TIMEOUT,
Arthur Hungc539dbb2022-12-08 07:45:36 +0000987 InputEventInjectionSync::WAIT_FOR_RESULT))
988 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
989 foregroundWindow->consumeMotionPointerUp(0);
990 wallpaperWindow->consumeMotionPointerUp(0, ADISPLAY_ID_DEFAULT, expectedWallpaperFlags);
991
992 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -0700993 injectMotionEvent(*mDispatcher,
Siarhei Vishniakou92c8fd52023-01-29 14:57:43 -0800994 MotionEventBuilder(AMOTION_EVENT_ACTION_UP,
995 AINPUT_SOURCE_TOUCHSCREEN)
996 .displayId(ADISPLAY_ID_DEFAULT)
997 .eventTime(systemTime(SYSTEM_TIME_MONOTONIC))
Harry Cutts101ee9b2023-07-06 18:04:14 +0000998 .pointer(PointerBuilder(/*id=*/1, ToolType::FINGER)
Siarhei Vishniakou92c8fd52023-01-29 14:57:43 -0800999 .x(100)
1000 .y(100))
1001 .build(),
1002 INJECT_EVENT_TIMEOUT, InputEventInjectionSync::WAIT_FOR_RESULT))
Arthur Hungc539dbb2022-12-08 07:45:36 +00001003 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
1004 foregroundWindow->consumeMotionUp(ADISPLAY_ID_DEFAULT);
1005 wallpaperWindow->consumeMotionUp(ADISPLAY_ID_DEFAULT, expectedWallpaperFlags);
Siarhei Vishniakouca205502021-07-16 21:31:58 +00001006}
1007
1008/**
1009 * Two windows: a window on the left and window on the right.
1010 * A third window, wallpaper, is behind both windows, and spans both top windows.
1011 * The first touch down goes to the left window. A second pointer touches down on the right window.
1012 * The touch is split, so both left and right windows should receive ACTION_DOWN.
1013 * The wallpaper will get the full event, so it should receive ACTION_DOWN followed by
1014 * ACTION_POINTER_DOWN(1).
1015 */
1016TEST_F(InputDispatcherTest, TwoWindows_SplitWallpaperTouch) {
1017 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
1018 sp<FakeWindowHandle> leftWindow =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07001019 sp<FakeWindowHandle>::make(application, mDispatcher, "Left", ADISPLAY_ID_DEFAULT);
Siarhei Vishniakouca205502021-07-16 21:31:58 +00001020 leftWindow->setFrame(Rect(0, 0, 200, 200));
Prabir Pradhan4d5c52f2022-01-31 08:52:10 -08001021 leftWindow->setDupTouchToWallpaper(true);
Siarhei Vishniakouca205502021-07-16 21:31:58 +00001022
1023 sp<FakeWindowHandle> rightWindow =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07001024 sp<FakeWindowHandle>::make(application, mDispatcher, "Right", ADISPLAY_ID_DEFAULT);
Siarhei Vishniakouca205502021-07-16 21:31:58 +00001025 rightWindow->setFrame(Rect(200, 0, 400, 200));
Prabir Pradhan4d5c52f2022-01-31 08:52:10 -08001026 rightWindow->setDupTouchToWallpaper(true);
Siarhei Vishniakouca205502021-07-16 21:31:58 +00001027
1028 sp<FakeWindowHandle> wallpaperWindow =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07001029 sp<FakeWindowHandle>::make(application, mDispatcher, "Wallpaper", ADISPLAY_ID_DEFAULT);
Siarhei Vishniakouca205502021-07-16 21:31:58 +00001030 wallpaperWindow->setFrame(Rect(0, 0, 400, 200));
Prabir Pradhan4d5c52f2022-01-31 08:52:10 -08001031 wallpaperWindow->setIsWallpaper(true);
Siarhei Vishniakouca205502021-07-16 21:31:58 +00001032
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07001033 mDispatcher->onWindowInfosChanged(
1034 {{*leftWindow->getInfo(), *rightWindow->getInfo(), *wallpaperWindow->getInfo()},
1035 {},
1036 0,
1037 0});
Siarhei Vishniakouca205502021-07-16 21:31:58 +00001038
1039 // Touch down on left window
1040 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07001041 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
Siarhei Vishniakouca205502021-07-16 21:31:58 +00001042 {100, 100}))
1043 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
1044
1045 // Both foreground window and its wallpaper should receive the touch down
1046 leftWindow->consumeMotionDown();
1047 wallpaperWindow->consumeMotionDown(ADISPLAY_ID_DEFAULT, expectedWallpaperFlags);
1048
1049 // Second finger down on the right window
1050 const MotionEvent secondFingerDownEvent =
Siarhei Vishniakoua16e3a22022-03-02 15:26:40 -08001051 MotionEventBuilder(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
Siarhei Vishniakouca205502021-07-16 21:31:58 +00001052 .eventTime(systemTime(SYSTEM_TIME_MONOTONIC))
Siarhei Vishniakou6d73f832022-07-21 17:27:03 -07001053 .pointer(PointerBuilder(/*id=*/0, ToolType::FINGER).x(100).y(100))
1054 .pointer(PointerBuilder(/*id=*/1, ToolType::FINGER).x(300).y(100))
Siarhei Vishniakouca205502021-07-16 21:31:58 +00001055 .build();
1056 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07001057 injectMotionEvent(*mDispatcher, secondFingerDownEvent, INJECT_EVENT_TIMEOUT,
Siarhei Vishniakouca205502021-07-16 21:31:58 +00001058 InputEventInjectionSync::WAIT_FOR_RESULT))
1059 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
1060
1061 leftWindow->consumeMotionMove();
1062 // Since the touch is split, right window gets ACTION_DOWN
1063 rightWindow->consumeMotionDown(ADISPLAY_ID_DEFAULT);
Harry Cutts33476232023-01-30 19:57:29 +00001064 wallpaperWindow->consumeMotionPointerDown(/*pointerIndex=*/1, ADISPLAY_ID_DEFAULT,
Siarhei Vishniakouca205502021-07-16 21:31:58 +00001065 expectedWallpaperFlags);
1066
1067 // Now, leftWindow, which received the first finger, disappears.
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07001068 mDispatcher->onWindowInfosChanged(
1069 {{*rightWindow->getInfo(), *wallpaperWindow->getInfo()}, {}, 0, 0});
Siarhei Vishniakouca205502021-07-16 21:31:58 +00001070 leftWindow->consumeMotionCancel();
1071 // Since a "parent" window of the wallpaper is gone, wallpaper should receive cancel, too.
1072 wallpaperWindow->consumeMotionCancel(ADISPLAY_ID_DEFAULT, expectedWallpaperFlags);
1073
1074 // The pointer that's still down on the right window moves, and goes to the right window only.
1075 // As far as the dispatcher's concerned though, both pointers are still present.
1076 const MotionEvent secondFingerMoveEvent =
1077 MotionEventBuilder(AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN)
1078 .eventTime(systemTime(SYSTEM_TIME_MONOTONIC))
Siarhei Vishniakou6d73f832022-07-21 17:27:03 -07001079 .pointer(PointerBuilder(/*id=*/0, ToolType::FINGER).x(100).y(100))
1080 .pointer(PointerBuilder(/*id=*/1, ToolType::FINGER).x(310).y(110))
Siarhei Vishniakouca205502021-07-16 21:31:58 +00001081 .build();
1082 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07001083 injectMotionEvent(*mDispatcher, secondFingerMoveEvent, INJECT_EVENT_TIMEOUT,
Siarhei Vishniakouca205502021-07-16 21:31:58 +00001084 InputEventInjectionSync::WAIT_FOR_RESULT));
1085 rightWindow->consumeMotionMove();
1086
1087 leftWindow->assertNoEvents();
1088 rightWindow->assertNoEvents();
1089 wallpaperWindow->assertNoEvents();
1090}
1091
Arthur Hungc539dbb2022-12-08 07:45:36 +00001092/**
1093 * Two windows: a window on the left with dup touch to wallpaper and window on the right without it.
1094 * The touch slips to the right window. so left window and wallpaper should receive ACTION_CANCEL
1095 * The right window should receive ACTION_DOWN.
1096 */
1097TEST_F(InputDispatcherTest, WallpaperWindowWhenSlippery) {
Arthur Hung74c248d2022-11-23 07:09:59 +00001098 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
Arthur Hungc539dbb2022-12-08 07:45:36 +00001099 sp<FakeWindowHandle> leftWindow =
1100 sp<FakeWindowHandle>::make(application, mDispatcher, "Left", ADISPLAY_ID_DEFAULT);
1101 leftWindow->setFrame(Rect(0, 0, 200, 200));
1102 leftWindow->setDupTouchToWallpaper(true);
1103 leftWindow->setSlippery(true);
1104
1105 sp<FakeWindowHandle> rightWindow =
1106 sp<FakeWindowHandle>::make(application, mDispatcher, "Right", ADISPLAY_ID_DEFAULT);
1107 rightWindow->setFrame(Rect(200, 0, 400, 200));
Arthur Hung74c248d2022-11-23 07:09:59 +00001108
1109 sp<FakeWindowHandle> wallpaperWindow =
1110 sp<FakeWindowHandle>::make(application, mDispatcher, "Wallpaper", ADISPLAY_ID_DEFAULT);
1111 wallpaperWindow->setIsWallpaper(true);
Arthur Hung74c248d2022-11-23 07:09:59 +00001112
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07001113 mDispatcher->onWindowInfosChanged(
1114 {{*leftWindow->getInfo(), *rightWindow->getInfo(), *wallpaperWindow->getInfo()},
1115 {},
1116 0,
1117 0});
Arthur Hung74c248d2022-11-23 07:09:59 +00001118
Arthur Hungc539dbb2022-12-08 07:45:36 +00001119 // Touch down on left window
Arthur Hung74c248d2022-11-23 07:09:59 +00001120 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07001121 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
Arthur Hungc539dbb2022-12-08 07:45:36 +00001122 {100, 100}))
Arthur Hung74c248d2022-11-23 07:09:59 +00001123 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
Arthur Hungc539dbb2022-12-08 07:45:36 +00001124
1125 // Both foreground window and its wallpaper should receive the touch down
1126 leftWindow->consumeMotionDown();
Arthur Hung74c248d2022-11-23 07:09:59 +00001127 wallpaperWindow->consumeMotionDown(ADISPLAY_ID_DEFAULT, expectedWallpaperFlags);
1128
Arthur Hungc539dbb2022-12-08 07:45:36 +00001129 // Move to right window, the left window should receive cancel.
Arthur Hung74c248d2022-11-23 07:09:59 +00001130 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07001131 injectMotionEvent(*mDispatcher, AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN,
Arthur Hungc539dbb2022-12-08 07:45:36 +00001132 ADISPLAY_ID_DEFAULT, {201, 100}))
Arthur Hung74c248d2022-11-23 07:09:59 +00001133 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
1134
Arthur Hungc539dbb2022-12-08 07:45:36 +00001135 leftWindow->consumeMotionCancel();
1136 rightWindow->consumeMotionDown(ADISPLAY_ID_DEFAULT);
1137 wallpaperWindow->consumeMotionCancel(ADISPLAY_ID_DEFAULT, expectedWallpaperFlags);
Arthur Hung74c248d2022-11-23 07:09:59 +00001138}
1139
Siarhei Vishniakoua16e3a22022-03-02 15:26:40 -08001140/**
Siarhei Vishniakou5bf25d92023-02-08 15:43:38 -08001141 * The policy typically sets POLICY_FLAG_PASS_TO_USER to the events. But when the display is not
1142 * interactive, it might stop sending this flag.
1143 * In this test, we check that if the policy stops sending this flag mid-gesture, we still ensure
1144 * to have a consistent input stream.
1145 *
1146 * Test procedure:
1147 * DOWN -> POINTER_DOWN -> (stop sending POLICY_FLAG_PASS_TO_USER) -> CANCEL.
1148 * DOWN (new gesture).
1149 *
1150 * In the bad implementation, we could potentially drop the CANCEL event, and get an inconsistent
1151 * state in the dispatcher. This would cause the final DOWN event to not be delivered to the app.
1152 *
1153 * We technically just need a single window here, but we are using two windows (spy on top and a
1154 * regular window below) to emulate the actual situation where it happens on the device.
1155 */
1156TEST_F(InputDispatcherTest, TwoPointerCancelInconsistentPolicy) {
1157 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
1158 sp<FakeWindowHandle> spyWindow =
1159 sp<FakeWindowHandle>::make(application, mDispatcher, "Spy", ADISPLAY_ID_DEFAULT);
1160 spyWindow->setFrame(Rect(0, 0, 200, 200));
1161 spyWindow->setTrustedOverlay(true);
1162 spyWindow->setSpy(true);
1163
1164 sp<FakeWindowHandle> window =
1165 sp<FakeWindowHandle>::make(application, mDispatcher, "Window", ADISPLAY_ID_DEFAULT);
1166 window->setFrame(Rect(0, 0, 200, 200));
1167
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07001168 mDispatcher->onWindowInfosChanged({{*spyWindow->getInfo(), *window->getInfo()}, {}, 0, 0});
Siarhei Vishniakou5bf25d92023-02-08 15:43:38 -08001169 const int32_t touchDeviceId = 4;
Siarhei Vishniakou5bf25d92023-02-08 15:43:38 -08001170
1171 // Two pointers down
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
Prabir Pradhan678438e2023-04-13 19:32:51 +00001179 mDispatcher->notifyMotion(MotionArgsBuilder(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
1180 .deviceId(touchDeviceId)
1181 .policyFlags(DEFAULT_POLICY_FLAGS)
1182 .pointer(PointerBuilder(0, ToolType::FINGER).x(100).y(100))
1183 .pointer(PointerBuilder(1, ToolType::FINGER).x(120).y(120))
1184 .build());
Siarhei Vishniakou5bf25d92023-02-08 15:43:38 -08001185 spyWindow->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_DOWN));
1186 spyWindow->consumeMotionEvent(WithMotionAction(POINTER_1_DOWN));
1187 window->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_DOWN));
1188 window->consumeMotionEvent(WithMotionAction(POINTER_1_DOWN));
1189
1190 // Cancel the current gesture. Send the cancel without the default policy flags.
Prabir Pradhan678438e2023-04-13 19:32:51 +00001191 mDispatcher->notifyMotion(
1192 MotionArgsBuilder(AMOTION_EVENT_ACTION_CANCEL, AINPUT_SOURCE_TOUCHSCREEN)
1193 .deviceId(touchDeviceId)
1194 .policyFlags(0)
1195 .pointer(PointerBuilder(0, ToolType::FINGER).x(100).y(100))
1196 .pointer(PointerBuilder(1, ToolType::FINGER).x(120).y(120))
1197 .build());
Siarhei Vishniakou5bf25d92023-02-08 15:43:38 -08001198 spyWindow->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_CANCEL));
1199 window->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_CANCEL));
1200
1201 // We don't need to reset the device to reproduce the issue, but the reset event typically
1202 // follows, so we keep it here to model the actual listener behaviour more closely.
Prabir Pradhan678438e2023-04-13 19:32:51 +00001203 mDispatcher->notifyDeviceReset({/*id=*/1, systemTime(SYSTEM_TIME_MONOTONIC), touchDeviceId});
Siarhei Vishniakou5bf25d92023-02-08 15:43:38 -08001204
1205 // Start new gesture
Prabir Pradhan678438e2023-04-13 19:32:51 +00001206 mDispatcher->notifyMotion(
1207 MotionArgsBuilder(AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
1208 .deviceId(touchDeviceId)
1209 .policyFlags(DEFAULT_POLICY_FLAGS)
1210 .pointer(PointerBuilder(0, ToolType::FINGER).x(100).y(100))
1211 .build());
Siarhei Vishniakou5bf25d92023-02-08 15:43:38 -08001212 spyWindow->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_DOWN));
1213 window->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_DOWN));
1214
1215 // No more events
1216 spyWindow->assertNoEvents();
1217 window->assertNoEvents();
1218}
1219
1220/**
Linnan Li907ae732023-09-05 17:14:21 +08001221 * Same as the above 'TwoPointerCancelInconsistentPolicy' test, but for hovers.
1222 * The policy typically sets POLICY_FLAG_PASS_TO_USER to the events. But when the display is not
1223 * interactive, it might stop sending this flag.
1224 * We've already ensured the consistency of the touch event in this case, and we should also ensure
1225 * the consistency of the hover event in this case.
1226 *
1227 * Test procedure:
1228 * HOVER_ENTER -> HOVER_MOVE -> (stop sending POLICY_FLAG_PASS_TO_USER) -> HOVER_EXIT
1229 * HOVER_ENTER -> HOVER_MOVE -> HOVER_EXIT
1230 *
1231 * We expect to receive two full streams of hover events.
1232 */
1233TEST_F(InputDispatcherTest, HoverEventInconsistentPolicy) {
1234 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
1235
1236 sp<FakeWindowHandle> window =
1237 sp<FakeWindowHandle>::make(application, mDispatcher, "Window", ADISPLAY_ID_DEFAULT);
1238 window->setFrame(Rect(0, 0, 300, 300));
1239
1240 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
1241
1242 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_ENTER, AINPUT_SOURCE_STYLUS)
1243 .policyFlags(DEFAULT_POLICY_FLAGS)
1244 .pointer(PointerBuilder(0, ToolType::STYLUS).x(100).y(101))
1245 .build());
1246 window->consumeMotionEvent(WithMotionAction(ACTION_HOVER_ENTER));
1247
1248 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_MOVE, AINPUT_SOURCE_STYLUS)
1249 .policyFlags(DEFAULT_POLICY_FLAGS)
1250 .pointer(PointerBuilder(0, ToolType::STYLUS).x(101).y(102))
1251 .build());
1252 window->consumeMotionEvent(WithMotionAction(ACTION_HOVER_MOVE));
1253
1254 // Send hover exit without the default policy flags.
1255 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_EXIT, AINPUT_SOURCE_STYLUS)
1256 .policyFlags(0)
1257 .pointer(PointerBuilder(0, ToolType::STYLUS).x(101).y(102))
1258 .build());
1259
1260 window->consumeMotionEvent(WithMotionAction(ACTION_HOVER_EXIT));
1261
1262 // Send a simple hover event stream, ensure dispatcher not crashed and window can receive
1263 // right event.
1264 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_ENTER, AINPUT_SOURCE_STYLUS)
1265 .policyFlags(DEFAULT_POLICY_FLAGS)
1266 .pointer(PointerBuilder(0, ToolType::STYLUS).x(200).y(201))
1267 .build());
1268 window->consumeMotionEvent(WithMotionAction(ACTION_HOVER_ENTER));
1269
1270 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_MOVE, AINPUT_SOURCE_STYLUS)
1271 .policyFlags(DEFAULT_POLICY_FLAGS)
1272 .pointer(PointerBuilder(0, ToolType::STYLUS).x(201).y(202))
1273 .build());
1274 window->consumeMotionEvent(WithMotionAction(ACTION_HOVER_MOVE));
1275
1276 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_EXIT, AINPUT_SOURCE_STYLUS)
1277 .policyFlags(DEFAULT_POLICY_FLAGS)
1278 .pointer(PointerBuilder(0, ToolType::STYLUS).x(201).y(202))
1279 .build());
1280 window->consumeMotionEvent(WithMotionAction(ACTION_HOVER_EXIT));
1281}
1282
1283/**
Siarhei Vishniakoue0431e42023-01-28 17:01:39 -08001284 * Two windows: a window on the left and a window on the right.
1285 * Mouse is hovered from the right window into the left window.
1286 * Next, we tap on the left window, where the cursor was last seen.
1287 * The second tap is done onto the right window.
1288 * The mouse and tap are from two different devices.
1289 * We technically don't need to set the downtime / eventtime for these events, but setting these
1290 * explicitly helps during debugging.
1291 * This test reproduces a crash where there is a mismatch between the downTime and eventTime.
1292 * In the buggy implementation, a tap on the right window would cause a crash.
1293 */
Siarhei Vishniakoued89cbb2023-10-13 10:42:44 -07001294TEST_F(InputDispatcherTest, HoverFromLeftToRightAndTap_legacy) {
1295 SCOPED_FLAG_OVERRIDE(enable_multi_device_same_window_stream, false);
1296
Siarhei Vishniakoue0431e42023-01-28 17:01:39 -08001297 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
1298 sp<FakeWindowHandle> leftWindow =
1299 sp<FakeWindowHandle>::make(application, mDispatcher, "Left", ADISPLAY_ID_DEFAULT);
1300 leftWindow->setFrame(Rect(0, 0, 200, 200));
1301
1302 sp<FakeWindowHandle> rightWindow =
1303 sp<FakeWindowHandle>::make(application, mDispatcher, "Right", ADISPLAY_ID_DEFAULT);
1304 rightWindow->setFrame(Rect(200, 0, 400, 200));
1305
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07001306 mDispatcher->onWindowInfosChanged(
1307 {{*leftWindow->getInfo(), *rightWindow->getInfo()}, {}, 0, 0});
Siarhei Vishniakoue0431e42023-01-28 17:01:39 -08001308 // All times need to start at the current time, otherwise the dispatcher will drop the events as
1309 // stale.
1310 const nsecs_t baseTime = systemTime(SYSTEM_TIME_MONOTONIC);
1311 const int32_t mouseDeviceId = 6;
1312 const int32_t touchDeviceId = 4;
1313 // Move the cursor from right
1314 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07001315 injectMotionEvent(*mDispatcher,
Siarhei Vishniakoue0431e42023-01-28 17:01:39 -08001316 MotionEventBuilder(AMOTION_EVENT_ACTION_HOVER_MOVE,
1317 AINPUT_SOURCE_MOUSE)
1318 .deviceId(mouseDeviceId)
1319 .downTime(baseTime + 10)
1320 .eventTime(baseTime + 20)
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07001321 .pointer(PointerBuilder(0, ToolType::MOUSE).x(300).y(100))
Siarhei Vishniakoue0431e42023-01-28 17:01:39 -08001322 .build()));
1323 rightWindow->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_ENTER));
1324
1325 // .. to the left window
1326 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07001327 injectMotionEvent(*mDispatcher,
Siarhei Vishniakoue0431e42023-01-28 17:01:39 -08001328 MotionEventBuilder(AMOTION_EVENT_ACTION_HOVER_MOVE,
1329 AINPUT_SOURCE_MOUSE)
1330 .deviceId(mouseDeviceId)
1331 .downTime(baseTime + 10)
1332 .eventTime(baseTime + 30)
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07001333 .pointer(PointerBuilder(0, ToolType::MOUSE).x(110).y(100))
Siarhei Vishniakoue0431e42023-01-28 17:01:39 -08001334 .build()));
1335 rightWindow->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_EXIT));
1336 leftWindow->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_ENTER));
1337 // Now tap the left window
1338 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07001339 injectMotionEvent(*mDispatcher,
Siarhei Vishniakoue0431e42023-01-28 17:01:39 -08001340 MotionEventBuilder(AMOTION_EVENT_ACTION_DOWN,
1341 AINPUT_SOURCE_TOUCHSCREEN)
1342 .deviceId(touchDeviceId)
1343 .downTime(baseTime + 40)
1344 .eventTime(baseTime + 40)
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07001345 .pointer(PointerBuilder(0, ToolType::FINGER).x(100).y(100))
Siarhei Vishniakoue0431e42023-01-28 17:01:39 -08001346 .build()));
1347 leftWindow->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_EXIT));
1348 leftWindow->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_DOWN));
1349
1350 // release tap
1351 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07001352 injectMotionEvent(*mDispatcher,
Siarhei Vishniakoue0431e42023-01-28 17:01:39 -08001353 MotionEventBuilder(AMOTION_EVENT_ACTION_UP,
1354 AINPUT_SOURCE_TOUCHSCREEN)
1355 .deviceId(touchDeviceId)
1356 .downTime(baseTime + 40)
1357 .eventTime(baseTime + 50)
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07001358 .pointer(PointerBuilder(0, ToolType::FINGER).x(100).y(100))
Siarhei Vishniakoue0431e42023-01-28 17:01:39 -08001359 .build()));
1360 leftWindow->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_UP));
1361
1362 // Tap the window on the right
1363 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07001364 injectMotionEvent(*mDispatcher,
Siarhei Vishniakoue0431e42023-01-28 17:01:39 -08001365 MotionEventBuilder(AMOTION_EVENT_ACTION_DOWN,
1366 AINPUT_SOURCE_TOUCHSCREEN)
1367 .deviceId(touchDeviceId)
1368 .downTime(baseTime + 60)
1369 .eventTime(baseTime + 60)
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07001370 .pointer(PointerBuilder(0, ToolType::FINGER).x(300).y(100))
Siarhei Vishniakoue0431e42023-01-28 17:01:39 -08001371 .build()));
1372 rightWindow->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_DOWN));
1373
1374 // release tap
1375 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07001376 injectMotionEvent(*mDispatcher,
Siarhei Vishniakoue0431e42023-01-28 17:01:39 -08001377 MotionEventBuilder(AMOTION_EVENT_ACTION_UP,
1378 AINPUT_SOURCE_TOUCHSCREEN)
1379 .deviceId(touchDeviceId)
1380 .downTime(baseTime + 60)
1381 .eventTime(baseTime + 70)
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07001382 .pointer(PointerBuilder(0, ToolType::FINGER).x(300).y(100))
Siarhei Vishniakoue0431e42023-01-28 17:01:39 -08001383 .build()));
1384 rightWindow->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_UP));
1385
1386 // No more events
1387 leftWindow->assertNoEvents();
1388 rightWindow->assertNoEvents();
1389}
1390
1391/**
Siarhei Vishniakoued89cbb2023-10-13 10:42:44 -07001392 * Two windows: a window on the left and a window on the right.
1393 * Mouse is hovered from the right window into the left window.
1394 * Next, we tap on the left window, where the cursor was last seen.
1395 * The second tap is done onto the right window.
1396 * The mouse and tap are from two different devices.
1397 * We technically don't need to set the downtime / eventtime for these events, but setting these
1398 * explicitly helps during debugging.
1399 * This test reproduces a crash where there is a mismatch between the downTime and eventTime.
1400 * In the buggy implementation, a tap on the right window would cause a crash.
1401 */
1402TEST_F(InputDispatcherTest, HoverFromLeftToRightAndTap) {
1403 SCOPED_FLAG_OVERRIDE(enable_multi_device_same_window_stream, true);
1404
1405 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
1406 sp<FakeWindowHandle> leftWindow =
1407 sp<FakeWindowHandle>::make(application, mDispatcher, "Left", ADISPLAY_ID_DEFAULT);
1408 leftWindow->setFrame(Rect(0, 0, 200, 200));
1409
1410 sp<FakeWindowHandle> rightWindow =
1411 sp<FakeWindowHandle>::make(application, mDispatcher, "Right", ADISPLAY_ID_DEFAULT);
1412 rightWindow->setFrame(Rect(200, 0, 400, 200));
1413
1414 mDispatcher->onWindowInfosChanged(
1415 {{*leftWindow->getInfo(), *rightWindow->getInfo()}, {}, 0, 0});
1416 // All times need to start at the current time, otherwise the dispatcher will drop the events as
1417 // stale.
1418 const nsecs_t baseTime = systemTime(SYSTEM_TIME_MONOTONIC);
1419 const int32_t mouseDeviceId = 6;
1420 const int32_t touchDeviceId = 4;
1421 // Move the cursor from right
1422 mDispatcher->notifyMotion(
1423 MotionArgsBuilder(AMOTION_EVENT_ACTION_HOVER_MOVE, AINPUT_SOURCE_MOUSE)
1424 .deviceId(mouseDeviceId)
1425 .downTime(baseTime + 10)
1426 .eventTime(baseTime + 20)
1427 .pointer(PointerBuilder(0, ToolType::MOUSE).x(300).y(100))
1428 .build());
1429 rightWindow->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_ENTER));
1430
1431 // .. to the left window
1432 mDispatcher->notifyMotion(
1433 MotionArgsBuilder(AMOTION_EVENT_ACTION_HOVER_MOVE, AINPUT_SOURCE_MOUSE)
1434 .deviceId(mouseDeviceId)
1435 .downTime(baseTime + 10)
1436 .eventTime(baseTime + 30)
1437 .pointer(PointerBuilder(0, ToolType::MOUSE).x(110).y(100))
1438 .build());
1439 rightWindow->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_EXIT));
1440 leftWindow->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_ENTER));
1441 // Now tap the left window
1442 mDispatcher->notifyMotion(
1443 MotionArgsBuilder(AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
1444 .deviceId(touchDeviceId)
1445 .downTime(baseTime + 40)
1446 .eventTime(baseTime + 40)
1447 .pointer(PointerBuilder(0, ToolType::FINGER).x(100).y(100))
1448 .build());
1449 leftWindow->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_DOWN));
1450
1451 // release tap
1452 mDispatcher->notifyMotion(MotionArgsBuilder(AMOTION_EVENT_ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN)
1453 .deviceId(touchDeviceId)
1454 .downTime(baseTime + 40)
1455 .eventTime(baseTime + 50)
1456 .pointer(PointerBuilder(0, ToolType::FINGER).x(100).y(100))
1457 .build());
1458 leftWindow->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_UP));
1459
1460 // Tap the window on the right
1461 mDispatcher->notifyMotion(
1462 MotionArgsBuilder(AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
1463 .deviceId(touchDeviceId)
1464 .downTime(baseTime + 60)
1465 .eventTime(baseTime + 60)
1466 .pointer(PointerBuilder(0, ToolType::FINGER).x(300).y(100))
1467 .build());
1468 rightWindow->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_DOWN));
1469
1470 // release tap
1471 mDispatcher->notifyMotion(MotionArgsBuilder(AMOTION_EVENT_ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN)
1472 .deviceId(touchDeviceId)
1473 .downTime(baseTime + 60)
1474 .eventTime(baseTime + 70)
1475 .pointer(PointerBuilder(0, ToolType::FINGER).x(300).y(100))
1476 .build());
1477 rightWindow->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_UP));
1478
1479 // No more events
1480 leftWindow->assertNoEvents();
1481 rightWindow->assertNoEvents();
1482}
1483
1484/**
Siarhei Vishniakoua235c042023-05-02 09:59:09 -07001485 * Start hovering in a window. While this hover is still active, make another window appear on top.
1486 * The top, obstructing window has no input channel, so it's not supposed to receive input.
1487 * While the top window is present, the hovering is stopped.
1488 * Later, hovering gets resumed again.
1489 * Ensure that new hover gesture is handled correctly.
1490 * This test reproduces a crash where the HOVER_EXIT event wasn't getting dispatched correctly
1491 * to the window that's currently being hovered over.
1492 */
1493TEST_F(InputDispatcherTest, HoverWhileWindowAppears) {
1494 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
1495 sp<FakeWindowHandle> window =
1496 sp<FakeWindowHandle>::make(application, mDispatcher, "Window", ADISPLAY_ID_DEFAULT);
1497 window->setFrame(Rect(0, 0, 200, 200));
1498
1499 // Only a single window is present at first
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07001500 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Siarhei Vishniakoua235c042023-05-02 09:59:09 -07001501
1502 // Start hovering in the window
1503 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_ENTER, AINPUT_SOURCE_STYLUS)
1504 .pointer(PointerBuilder(0, ToolType::STYLUS).x(100).y(100))
1505 .build());
1506 window->consumeMotionEvent(WithMotionAction(ACTION_HOVER_ENTER));
1507
1508 // Now, an obscuring window appears!
1509 sp<FakeWindowHandle> obscuringWindow =
1510 sp<FakeWindowHandle>::make(application, mDispatcher, "Obscuring window",
1511 ADISPLAY_ID_DEFAULT,
Prabir Pradhane7cc69c2024-01-05 21:35:28 +00001512 /*createInputChannel=*/false);
Siarhei Vishniakoua235c042023-05-02 09:59:09 -07001513 obscuringWindow->setFrame(Rect(0, 0, 200, 200));
1514 obscuringWindow->setTouchOcclusionMode(TouchOcclusionMode::BLOCK_UNTRUSTED);
1515 obscuringWindow->setOwnerInfo(SECONDARY_WINDOW_PID, SECONDARY_WINDOW_UID);
1516 obscuringWindow->setNoInputChannel(true);
1517 obscuringWindow->setFocusable(false);
1518 obscuringWindow->setAlpha(1.0);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07001519 mDispatcher->onWindowInfosChanged(
1520 {{*obscuringWindow->getInfo(), *window->getInfo()}, {}, 0, 0});
Siarhei Vishniakoua235c042023-05-02 09:59:09 -07001521
1522 // While this new obscuring window is present, the hovering is stopped
1523 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_EXIT, AINPUT_SOURCE_STYLUS)
1524 .pointer(PointerBuilder(0, ToolType::STYLUS).x(100).y(100))
1525 .build());
1526 window->consumeMotionEvent(WithMotionAction(ACTION_HOVER_EXIT));
1527
1528 // Now the obscuring window goes away.
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07001529 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Siarhei Vishniakoua235c042023-05-02 09:59:09 -07001530
1531 // And a new hover gesture starts.
1532 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_ENTER, AINPUT_SOURCE_STYLUS)
1533 .pointer(PointerBuilder(0, ToolType::STYLUS).x(100).y(100))
1534 .build());
1535 window->consumeMotionEvent(WithMotionAction(ACTION_HOVER_ENTER));
1536}
1537
1538/**
1539 * Same test as 'HoverWhileWindowAppears' above, but here, we also send some HOVER_MOVE events to
1540 * the obscuring window.
1541 */
1542TEST_F(InputDispatcherTest, HoverMoveWhileWindowAppears) {
1543 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
1544 sp<FakeWindowHandle> window =
1545 sp<FakeWindowHandle>::make(application, mDispatcher, "Window", ADISPLAY_ID_DEFAULT);
1546 window->setFrame(Rect(0, 0, 200, 200));
1547
1548 // Only a single window is present at first
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07001549 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Siarhei Vishniakoua235c042023-05-02 09:59:09 -07001550
1551 // Start hovering in the window
1552 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_ENTER, AINPUT_SOURCE_STYLUS)
1553 .pointer(PointerBuilder(0, ToolType::STYLUS).x(100).y(100))
1554 .build());
1555 window->consumeMotionEvent(WithMotionAction(ACTION_HOVER_ENTER));
1556
1557 // Now, an obscuring window appears!
1558 sp<FakeWindowHandle> obscuringWindow =
1559 sp<FakeWindowHandle>::make(application, mDispatcher, "Obscuring window",
1560 ADISPLAY_ID_DEFAULT,
Prabir Pradhane7cc69c2024-01-05 21:35:28 +00001561 /*createInputChannel=*/false);
Siarhei Vishniakoua235c042023-05-02 09:59:09 -07001562 obscuringWindow->setFrame(Rect(0, 0, 200, 200));
1563 obscuringWindow->setTouchOcclusionMode(TouchOcclusionMode::BLOCK_UNTRUSTED);
1564 obscuringWindow->setOwnerInfo(SECONDARY_WINDOW_PID, SECONDARY_WINDOW_UID);
1565 obscuringWindow->setNoInputChannel(true);
1566 obscuringWindow->setFocusable(false);
1567 obscuringWindow->setAlpha(1.0);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07001568 mDispatcher->onWindowInfosChanged(
1569 {{*obscuringWindow->getInfo(), *window->getInfo()}, {}, 0, 0});
Siarhei Vishniakoua235c042023-05-02 09:59:09 -07001570
1571 // While this new obscuring window is present, the hovering continues. The event can't go to the
1572 // bottom window due to obstructed touches, so it should generate HOVER_EXIT for that window.
1573 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_MOVE, AINPUT_SOURCE_STYLUS)
1574 .pointer(PointerBuilder(0, ToolType::STYLUS).x(100).y(100))
1575 .build());
1576 obscuringWindow->assertNoEvents();
1577 window->consumeMotionEvent(WithMotionAction(ACTION_HOVER_EXIT));
1578
1579 // Now the obscuring window goes away.
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07001580 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Siarhei Vishniakoua235c042023-05-02 09:59:09 -07001581
1582 // Hovering continues in the same position. The hovering pointer re-enters the bottom window,
1583 // so it should generate a HOVER_ENTER
1584 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_MOVE, AINPUT_SOURCE_STYLUS)
1585 .pointer(PointerBuilder(0, ToolType::STYLUS).x(100).y(100))
1586 .build());
1587 window->consumeMotionEvent(WithMotionAction(ACTION_HOVER_ENTER));
1588
1589 // Now the MOVE should be getting dispatched normally
1590 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_MOVE, AINPUT_SOURCE_STYLUS)
1591 .pointer(PointerBuilder(0, ToolType::STYLUS).x(110).y(110))
1592 .build());
1593 window->consumeMotionEvent(WithMotionAction(ACTION_HOVER_MOVE));
1594}
1595
1596/**
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -07001597 * Hover mouse over a window, and then send ACTION_SCROLL. Ensure both the hover and the scroll
1598 * events are delivered to the window.
1599 */
1600TEST_F(InputDispatcherTest, HoverMoveAndScroll) {
1601 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
1602 sp<FakeWindowHandle> window =
1603 sp<FakeWindowHandle>::make(application, mDispatcher, "Window", ADISPLAY_ID_DEFAULT);
1604 window->setFrame(Rect(0, 0, 200, 200));
1605 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
1606
1607 // Start hovering in the window
1608 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_ENTER, AINPUT_SOURCE_MOUSE)
1609 .pointer(PointerBuilder(0, ToolType::MOUSE).x(100).y(110))
1610 .build());
1611 window->consumeMotionEvent(WithMotionAction(ACTION_HOVER_ENTER));
1612
1613 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_MOVE, AINPUT_SOURCE_MOUSE)
1614 .pointer(PointerBuilder(0, ToolType::MOUSE).x(110).y(120))
1615 .build());
1616 window->consumeMotionEvent(WithMotionAction(ACTION_HOVER_MOVE));
1617
1618 // Scroll with the mouse
1619 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_SCROLL, AINPUT_SOURCE_MOUSE)
1620 .pointer(PointerBuilder(0, ToolType::MOUSE).x(110).y(120))
1621 .build());
1622 window->consumeMotionEvent(WithMotionAction(ACTION_SCROLL));
1623}
1624
1625using InputDispatcherMultiDeviceTest = InputDispatcherTest;
1626
1627/**
Siarhei Vishniakou2899c552023-07-10 18:20:46 -07001628 * One window. Stylus down on the window. Next, touch from another device goes down. Ensure that
1629 * touch is dropped, because stylus should be preferred over touch.
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -07001630 */
Siarhei Vishniakou2899c552023-07-10 18:20:46 -07001631TEST_F(InputDispatcherMultiDeviceTest, StylusDownBlocksTouchDown) {
Siarhei Vishniakoued89cbb2023-10-13 10:42:44 -07001632 SCOPED_FLAG_OVERRIDE(enable_multi_device_same_window_stream, false);
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -07001633 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
1634 sp<FakeWindowHandle> window =
1635 sp<FakeWindowHandle>::make(application, mDispatcher, "Window", ADISPLAY_ID_DEFAULT);
1636 window->setFrame(Rect(0, 0, 200, 200));
1637
1638 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
1639
1640 constexpr int32_t touchDeviceId = 4;
1641 constexpr int32_t stylusDeviceId = 2;
1642
1643 // Stylus down
1644 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_STYLUS)
1645 .deviceId(stylusDeviceId)
1646 .pointer(PointerBuilder(0, ToolType::STYLUS).x(100).y(110))
1647 .build());
1648 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(stylusDeviceId)));
1649
1650 // Touch down
1651 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
1652 .deviceId(touchDeviceId)
1653 .pointer(PointerBuilder(0, ToolType::FINGER).x(140).y(145))
1654 .build());
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -07001655
1656 // Touch move
1657 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN)
1658 .deviceId(touchDeviceId)
1659 .pointer(PointerBuilder(0, ToolType::FINGER).x(141).y(146))
1660 .build());
Siarhei Vishniakou2899c552023-07-10 18:20:46 -07001661 // Touch is ignored because stylus is already down
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -07001662
Siarhei Vishniakou2899c552023-07-10 18:20:46 -07001663 // Subsequent stylus movements are delivered correctly
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -07001664 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_STYLUS)
1665 .deviceId(stylusDeviceId)
1666 .pointer(PointerBuilder(0, ToolType::STYLUS).x(101).y(111))
1667 .build());
Siarhei Vishniakou2899c552023-07-10 18:20:46 -07001668 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(stylusDeviceId),
1669 WithCoords(101, 111)));
1670
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -07001671 window->assertNoEvents();
1672}
1673
1674/**
Siarhei Vishniakoued89cbb2023-10-13 10:42:44 -07001675 * One window. Stylus down on the window. Next, touch from another device goes down. Ensure that
1676 * touch is not dropped, because multiple devices are allowed to be active in the same window.
1677 */
1678TEST_F(InputDispatcherMultiDeviceTest, StylusDownDoesNotBlockTouchDown) {
1679 SCOPED_FLAG_OVERRIDE(enable_multi_device_same_window_stream, true);
1680 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
1681 sp<FakeWindowHandle> window =
1682 sp<FakeWindowHandle>::make(application, mDispatcher, "Window", ADISPLAY_ID_DEFAULT);
1683 window->setFrame(Rect(0, 0, 200, 200));
1684
1685 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
1686
1687 constexpr int32_t touchDeviceId = 4;
1688 constexpr int32_t stylusDeviceId = 2;
1689
1690 // Stylus down
1691 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_STYLUS)
1692 .deviceId(stylusDeviceId)
1693 .pointer(PointerBuilder(0, ToolType::STYLUS).x(100).y(110))
1694 .build());
1695 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(stylusDeviceId)));
1696
1697 // Touch down
1698 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
1699 .deviceId(touchDeviceId)
1700 .pointer(PointerBuilder(0, ToolType::FINGER).x(140).y(145))
1701 .build());
1702 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(touchDeviceId)));
1703
1704 // Touch move
1705 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN)
1706 .deviceId(touchDeviceId)
1707 .pointer(PointerBuilder(0, ToolType::FINGER).x(141).y(146))
1708 .build());
1709 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(touchDeviceId)));
1710
1711 // Stylus move
1712 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_STYLUS)
1713 .deviceId(stylusDeviceId)
1714 .pointer(PointerBuilder(0, ToolType::STYLUS).x(101).y(111))
1715 .build());
1716 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(stylusDeviceId),
1717 WithCoords(101, 111)));
1718
1719 window->assertNoEvents();
1720}
1721
1722/**
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -07001723 * One window and one spy window. Stylus down on the window. Next, touch from another device goes
Siarhei Vishniakou2899c552023-07-10 18:20:46 -07001724 * down. Ensure that touch is dropped, because stylus should be preferred over touch.
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -07001725 * Similar test as above, but with added SPY window.
1726 */
Siarhei Vishniakou2899c552023-07-10 18:20:46 -07001727TEST_F(InputDispatcherMultiDeviceTest, StylusDownWithSpyBlocksTouchDown) {
Siarhei Vishniakoued89cbb2023-10-13 10:42:44 -07001728 SCOPED_FLAG_OVERRIDE(enable_multi_device_same_window_stream, false);
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -07001729 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
1730 sp<FakeWindowHandle> window =
1731 sp<FakeWindowHandle>::make(application, mDispatcher, "Window", ADISPLAY_ID_DEFAULT);
1732 sp<FakeWindowHandle> spyWindow =
1733 sp<FakeWindowHandle>::make(application, mDispatcher, "Spy", ADISPLAY_ID_DEFAULT);
1734 spyWindow->setFrame(Rect(0, 0, 200, 200));
1735 spyWindow->setTrustedOverlay(true);
1736 spyWindow->setSpy(true);
1737 window->setFrame(Rect(0, 0, 200, 200));
1738
1739 mDispatcher->onWindowInfosChanged({{*spyWindow->getInfo(), *window->getInfo()}, {}, 0, 0});
1740
1741 constexpr int32_t touchDeviceId = 4;
1742 constexpr int32_t stylusDeviceId = 2;
1743
1744 // Stylus down
1745 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_STYLUS)
1746 .deviceId(stylusDeviceId)
1747 .pointer(PointerBuilder(0, ToolType::STYLUS).x(100).y(110))
1748 .build());
1749 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(stylusDeviceId)));
1750 spyWindow->consumeMotionEvent(
1751 AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(stylusDeviceId)));
1752
1753 // Touch down
1754 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
1755 .deviceId(touchDeviceId)
1756 .pointer(PointerBuilder(0, ToolType::FINGER).x(140).y(145))
1757 .build());
1758
1759 // Touch move
1760 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN)
1761 .deviceId(touchDeviceId)
1762 .pointer(PointerBuilder(0, ToolType::FINGER).x(141).y(146))
1763 .build());
Siarhei Vishniakou2899c552023-07-10 18:20:46 -07001764
1765 // Touch is ignored because stylus is already down
1766
1767 // Subsequent stylus movements are delivered correctly
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -07001768 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_STYLUS)
1769 .deviceId(stylusDeviceId)
1770 .pointer(PointerBuilder(0, ToolType::STYLUS).x(101).y(111))
1771 .build());
Siarhei Vishniakou2899c552023-07-10 18:20:46 -07001772 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(stylusDeviceId),
1773 WithCoords(101, 111)));
1774 spyWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(stylusDeviceId),
1775 WithCoords(101, 111)));
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -07001776
1777 window->assertNoEvents();
1778 spyWindow->assertNoEvents();
1779}
1780
1781/**
Siarhei Vishniakoued89cbb2023-10-13 10:42:44 -07001782 * One window and one spy window. Stylus down on the window. Next, touch from another device goes
1783 * down. Ensure that touch is not dropped, because multiple devices can be active at the same time.
1784 * Similar test as above, but with added SPY window.
1785 */
1786TEST_F(InputDispatcherMultiDeviceTest, StylusDownWithSpyDoesNotBlockTouchDown) {
1787 SCOPED_FLAG_OVERRIDE(enable_multi_device_same_window_stream, true);
1788 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
1789 sp<FakeWindowHandle> window =
1790 sp<FakeWindowHandle>::make(application, mDispatcher, "Window", ADISPLAY_ID_DEFAULT);
1791 sp<FakeWindowHandle> spyWindow =
1792 sp<FakeWindowHandle>::make(application, mDispatcher, "Spy", ADISPLAY_ID_DEFAULT);
1793 spyWindow->setFrame(Rect(0, 0, 200, 200));
1794 spyWindow->setTrustedOverlay(true);
1795 spyWindow->setSpy(true);
1796 window->setFrame(Rect(0, 0, 200, 200));
1797
1798 mDispatcher->onWindowInfosChanged({{*spyWindow->getInfo(), *window->getInfo()}, {}, 0, 0});
1799
1800 constexpr int32_t touchDeviceId = 4;
1801 constexpr int32_t stylusDeviceId = 2;
1802
1803 // Stylus down
1804 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_STYLUS)
1805 .deviceId(stylusDeviceId)
1806 .pointer(PointerBuilder(0, ToolType::STYLUS).x(100).y(110))
1807 .build());
1808 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(stylusDeviceId)));
1809 spyWindow->consumeMotionEvent(
1810 AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(stylusDeviceId)));
1811
1812 // Touch down
1813 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
1814 .deviceId(touchDeviceId)
1815 .pointer(PointerBuilder(0, ToolType::FINGER).x(140).y(145))
1816 .build());
1817 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(touchDeviceId)));
1818 spyWindow->consumeMotionEvent(
1819 AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(touchDeviceId)));
1820
1821 // Touch move
1822 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN)
1823 .deviceId(touchDeviceId)
1824 .pointer(PointerBuilder(0, ToolType::FINGER).x(141).y(146))
1825 .build());
1826 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(touchDeviceId)));
1827 spyWindow->consumeMotionEvent(
1828 AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(touchDeviceId)));
1829
1830 // Subsequent stylus movements are delivered correctly
1831 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_STYLUS)
1832 .deviceId(stylusDeviceId)
1833 .pointer(PointerBuilder(0, ToolType::STYLUS).x(101).y(111))
1834 .build());
1835 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(stylusDeviceId),
1836 WithCoords(101, 111)));
1837 spyWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(stylusDeviceId),
1838 WithCoords(101, 111)));
1839
1840 window->assertNoEvents();
1841 spyWindow->assertNoEvents();
1842}
1843
1844/**
Siarhei Vishniakou2899c552023-07-10 18:20:46 -07001845 * One window. Stylus hover on the window. Next, touch from another device goes down. Ensure that
Siarhei Vishniakou3ad54f52023-11-02 16:54:40 -07001846 * touch is dropped, because stylus hover takes precedence.
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -07001847 */
Siarhei Vishniakou3ad54f52023-11-02 16:54:40 -07001848TEST_F(InputDispatcherMultiDeviceTest, StylusHoverBlocksTouchDown) {
Siarhei Vishniakoued89cbb2023-10-13 10:42:44 -07001849 SCOPED_FLAG_OVERRIDE(enable_multi_device_same_window_stream, false);
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -07001850 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
1851 sp<FakeWindowHandle> window =
1852 sp<FakeWindowHandle>::make(application, mDispatcher, "Window", ADISPLAY_ID_DEFAULT);
1853 window->setFrame(Rect(0, 0, 200, 200));
1854
1855 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
1856
1857 constexpr int32_t touchDeviceId = 4;
1858 constexpr int32_t stylusDeviceId = 2;
1859
1860 // Stylus down on the window
1861 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_ENTER, AINPUT_SOURCE_STYLUS)
1862 .deviceId(stylusDeviceId)
1863 .pointer(PointerBuilder(0, ToolType::STYLUS).x(100).y(110))
1864 .build());
1865 window->consumeMotionEvent(
1866 AllOf(WithMotionAction(ACTION_HOVER_ENTER), WithDeviceId(stylusDeviceId)));
1867
1868 // Touch down on window
1869 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
1870 .deviceId(touchDeviceId)
1871 .pointer(PointerBuilder(0, ToolType::FINGER).x(140).y(145))
1872 .build());
1873 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN)
1874 .deviceId(touchDeviceId)
1875 .pointer(PointerBuilder(0, ToolType::FINGER).x(141).y(146))
1876 .build());
Siarhei Vishniakou2899c552023-07-10 18:20:46 -07001877
Siarhei Vishniakou3ad54f52023-11-02 16:54:40 -07001878 // Touch is ignored because stylus is hovering
Siarhei Vishniakou2899c552023-07-10 18:20:46 -07001879
Siarhei Vishniakou3ad54f52023-11-02 16:54:40 -07001880 // Subsequent stylus movements are delivered correctly
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -07001881 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_MOVE, AINPUT_SOURCE_STYLUS)
1882 .deviceId(stylusDeviceId)
1883 .pointer(PointerBuilder(0, ToolType::STYLUS).x(101).y(111))
1884 .build());
Siarhei Vishniakou3ad54f52023-11-02 16:54:40 -07001885 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_HOVER_MOVE),
1886 WithDeviceId(stylusDeviceId), WithCoords(101, 111)));
Siarhei Vishniakou2899c552023-07-10 18:20:46 -07001887
Siarhei Vishniakou3ad54f52023-11-02 16:54:40 -07001888 // and subsequent touches continue to be ignored
Siarhei Vishniakou2899c552023-07-10 18:20:46 -07001889 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN)
1890 .deviceId(touchDeviceId)
1891 .pointer(PointerBuilder(0, ToolType::FINGER).x(142).y(147))
1892 .build());
Siarhei Vishniakou3ad54f52023-11-02 16:54:40 -07001893 window->assertNoEvents();
Siarhei Vishniakou2899c552023-07-10 18:20:46 -07001894}
1895
1896/**
Siarhei Vishniakoued89cbb2023-10-13 10:42:44 -07001897 * One window. Stylus hover on the window. Next, touch from another device goes down. Ensure that
1898 * touch is not dropped, because stylus hover and touch can be both active at the same time.
1899 */
1900TEST_F(InputDispatcherMultiDeviceTest, StylusHoverDoesNotBlockTouchDown) {
1901 SCOPED_FLAG_OVERRIDE(enable_multi_device_same_window_stream, true);
1902 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
1903 sp<FakeWindowHandle> window =
1904 sp<FakeWindowHandle>::make(application, mDispatcher, "Window", ADISPLAY_ID_DEFAULT);
1905 window->setFrame(Rect(0, 0, 200, 200));
1906
1907 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
1908
1909 constexpr int32_t touchDeviceId = 4;
1910 constexpr int32_t stylusDeviceId = 2;
1911
1912 // Stylus down on the window
1913 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_ENTER, AINPUT_SOURCE_STYLUS)
1914 .deviceId(stylusDeviceId)
1915 .pointer(PointerBuilder(0, ToolType::STYLUS).x(100).y(110))
1916 .build());
1917 window->consumeMotionEvent(
1918 AllOf(WithMotionAction(ACTION_HOVER_ENTER), WithDeviceId(stylusDeviceId)));
1919
1920 // Touch down on window
1921 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
1922 .deviceId(touchDeviceId)
1923 .pointer(PointerBuilder(0, ToolType::FINGER).x(140).y(145))
1924 .build());
1925 // Touch move on window
1926 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(touchDeviceId)));
1927 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN)
1928 .deviceId(touchDeviceId)
1929 .pointer(PointerBuilder(0, ToolType::FINGER).x(141).y(146))
1930 .build());
1931 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(touchDeviceId)));
1932
1933 // Subsequent stylus movements are delivered correctly
1934 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_MOVE, AINPUT_SOURCE_STYLUS)
1935 .deviceId(stylusDeviceId)
1936 .pointer(PointerBuilder(0, ToolType::STYLUS).x(101).y(111))
1937 .build());
1938 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_HOVER_MOVE),
1939 WithDeviceId(stylusDeviceId), WithCoords(101, 111)));
1940
1941 // and subsequent touches continue to work
1942 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN)
1943 .deviceId(touchDeviceId)
1944 .pointer(PointerBuilder(0, ToolType::FINGER).x(142).y(147))
1945 .build());
1946 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(touchDeviceId)));
1947 window->assertNoEvents();
1948}
1949
1950/**
Siarhei Vishniakou2899c552023-07-10 18:20:46 -07001951 * One window. Touch down on the window. Then, stylus hover on the window from another device.
Siarhei Vishniakou3ad54f52023-11-02 16:54:40 -07001952 * Ensure that touch is canceled, because stylus hover should take precedence.
Siarhei Vishniakou2899c552023-07-10 18:20:46 -07001953 */
Siarhei Vishniakou3ad54f52023-11-02 16:54:40 -07001954TEST_F(InputDispatcherMultiDeviceTest, TouchIsCanceledByStylusHover) {
Siarhei Vishniakoued89cbb2023-10-13 10:42:44 -07001955 SCOPED_FLAG_OVERRIDE(enable_multi_device_same_window_stream, false);
Siarhei Vishniakou2899c552023-07-10 18:20:46 -07001956 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
1957 sp<FakeWindowHandle> window =
1958 sp<FakeWindowHandle>::make(application, mDispatcher, "Window", ADISPLAY_ID_DEFAULT);
1959 window->setFrame(Rect(0, 0, 200, 200));
1960
1961 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
1962
1963 constexpr int32_t touchDeviceId = 4;
1964 constexpr int32_t stylusDeviceId = 2;
1965
1966 // Touch down on window
1967 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
1968 .deviceId(touchDeviceId)
1969 .pointer(PointerBuilder(0, ToolType::FINGER).x(140).y(145))
1970 .build());
1971 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN)
1972 .deviceId(touchDeviceId)
1973 .pointer(PointerBuilder(0, ToolType::FINGER).x(141).y(146))
1974 .build());
1975 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(touchDeviceId)));
1976 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(touchDeviceId)));
1977
1978 // Stylus hover on the window
1979 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_ENTER, AINPUT_SOURCE_STYLUS)
1980 .deviceId(stylusDeviceId)
1981 .pointer(PointerBuilder(0, ToolType::STYLUS).x(100).y(110))
1982 .build());
1983 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_MOVE, AINPUT_SOURCE_STYLUS)
1984 .deviceId(stylusDeviceId)
1985 .pointer(PointerBuilder(0, ToolType::STYLUS).x(101).y(111))
1986 .build());
Siarhei Vishniakou3ad54f52023-11-02 16:54:40 -07001987 // Stylus hover movement causes touch to be canceled
1988 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_CANCEL), WithDeviceId(touchDeviceId),
1989 WithCoords(141, 146)));
1990 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_HOVER_ENTER),
1991 WithDeviceId(stylusDeviceId), WithCoords(100, 110)));
1992 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_HOVER_MOVE),
1993 WithDeviceId(stylusDeviceId), WithCoords(101, 111)));
Siarhei Vishniakou2899c552023-07-10 18:20:46 -07001994
Siarhei Vishniakou3ad54f52023-11-02 16:54:40 -07001995 // Subsequent touch movements are ignored
Siarhei Vishniakou2899c552023-07-10 18:20:46 -07001996 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN)
1997 .deviceId(touchDeviceId)
1998 .pointer(PointerBuilder(0, ToolType::FINGER).x(142).y(147))
1999 .build());
Siarhei Vishniakou3ad54f52023-11-02 16:54:40 -07002000
2001 window->assertNoEvents();
Siarhei Vishniakou2899c552023-07-10 18:20:46 -07002002}
2003
2004/**
Siarhei Vishniakoued89cbb2023-10-13 10:42:44 -07002005 * One window. Touch down on the window. Then, stylus hover on the window from another device.
2006 * Ensure that touch is not canceled, because stylus hover can be active at the same time as touch.
2007 */
2008TEST_F(InputDispatcherMultiDeviceTest, TouchIsNotCanceledByStylusHover) {
2009 SCOPED_FLAG_OVERRIDE(enable_multi_device_same_window_stream, true);
2010 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
2011 sp<FakeWindowHandle> window =
2012 sp<FakeWindowHandle>::make(application, mDispatcher, "Window", ADISPLAY_ID_DEFAULT);
2013 window->setFrame(Rect(0, 0, 200, 200));
2014
2015 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
2016
2017 constexpr int32_t touchDeviceId = 4;
2018 constexpr int32_t stylusDeviceId = 2;
2019
2020 // Touch down on window
2021 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
2022 .deviceId(touchDeviceId)
2023 .pointer(PointerBuilder(0, ToolType::FINGER).x(140).y(145))
2024 .build());
2025 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN)
2026 .deviceId(touchDeviceId)
2027 .pointer(PointerBuilder(0, ToolType::FINGER).x(141).y(146))
2028 .build());
2029 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(touchDeviceId)));
2030 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(touchDeviceId)));
2031
2032 // Stylus hover on the window
2033 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_ENTER, AINPUT_SOURCE_STYLUS)
2034 .deviceId(stylusDeviceId)
2035 .pointer(PointerBuilder(0, ToolType::STYLUS).x(100).y(110))
2036 .build());
2037 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_MOVE, AINPUT_SOURCE_STYLUS)
2038 .deviceId(stylusDeviceId)
2039 .pointer(PointerBuilder(0, ToolType::STYLUS).x(101).y(111))
2040 .build());
2041 // Stylus hover movement is received normally
2042 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_HOVER_ENTER),
2043 WithDeviceId(stylusDeviceId), WithCoords(100, 110)));
2044 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_HOVER_MOVE),
2045 WithDeviceId(stylusDeviceId), WithCoords(101, 111)));
2046
2047 // Subsequent touch movements also work
2048 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN)
2049 .deviceId(touchDeviceId)
2050 .pointer(PointerBuilder(0, ToolType::FINGER).x(142).y(147))
2051 .build());
2052 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(touchDeviceId),
2053 WithCoords(142, 147)));
2054
2055 window->assertNoEvents();
2056}
2057
2058/**
Siarhei Vishniakou2899c552023-07-10 18:20:46 -07002059 * One window. Stylus down on the window. Then, stylus from another device goes down. Ensure that
2060 * the latest stylus takes over. That is, old stylus should be canceled and the new stylus should
2061 * become active.
2062 */
2063TEST_F(InputDispatcherMultiDeviceTest, LatestStylusWins) {
Siarhei Vishniakoued89cbb2023-10-13 10:42:44 -07002064 SCOPED_FLAG_OVERRIDE(enable_multi_device_same_window_stream, false);
Siarhei Vishniakou2899c552023-07-10 18:20:46 -07002065 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
2066 sp<FakeWindowHandle> window =
2067 sp<FakeWindowHandle>::make(application, mDispatcher, "Window", ADISPLAY_ID_DEFAULT);
2068 window->setFrame(Rect(0, 0, 200, 200));
2069
2070 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
2071
2072 constexpr int32_t stylusDeviceId1 = 3;
2073 constexpr int32_t stylusDeviceId2 = 5;
2074
2075 // Touch down on window
2076 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_STYLUS)
2077 .deviceId(stylusDeviceId1)
2078 .pointer(PointerBuilder(0, ToolType::STYLUS).x(99).y(100))
2079 .build());
2080 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_STYLUS)
2081 .deviceId(stylusDeviceId1)
2082 .pointer(PointerBuilder(0, ToolType::STYLUS).x(100).y(101))
2083 .build());
2084 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(stylusDeviceId1)));
2085 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(stylusDeviceId1)));
2086
2087 // Second stylus down
2088 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_STYLUS)
2089 .deviceId(stylusDeviceId2)
2090 .pointer(PointerBuilder(0, ToolType::STYLUS).x(9).y(10))
2091 .build());
2092 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_STYLUS)
2093 .deviceId(stylusDeviceId2)
2094 .pointer(PointerBuilder(0, ToolType::STYLUS).x(10).y(11))
2095 .build());
2096
2097 // First stylus is canceled, second one takes over.
2098 window->consumeMotionEvent(
2099 AllOf(WithMotionAction(ACTION_CANCEL), WithDeviceId(stylusDeviceId1)));
2100 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(stylusDeviceId2)));
2101 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(stylusDeviceId2)));
2102
2103 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_STYLUS)
2104 .deviceId(stylusDeviceId1)
2105 .pointer(PointerBuilder(0, ToolType::STYLUS).x(101).y(102))
2106 .build());
2107 // Subsequent stylus movements are delivered correctly
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -07002108 window->assertNoEvents();
2109}
2110
2111/**
Siarhei Vishniakoued89cbb2023-10-13 10:42:44 -07002112 * One window. Stylus down on the window. Then, stylus from another device goes down. Ensure that
2113 * both stylus devices can function simultaneously.
2114 */
2115TEST_F(InputDispatcherMultiDeviceTest, TwoStylusDevicesActiveAtTheSameTime) {
2116 SCOPED_FLAG_OVERRIDE(enable_multi_device_same_window_stream, true);
2117 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
2118 sp<FakeWindowHandle> window =
2119 sp<FakeWindowHandle>::make(application, mDispatcher, "Window", ADISPLAY_ID_DEFAULT);
2120 window->setFrame(Rect(0, 0, 200, 200));
2121
2122 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
2123
2124 constexpr int32_t stylusDeviceId1 = 3;
2125 constexpr int32_t stylusDeviceId2 = 5;
2126
2127 // Touch down on window
2128 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_STYLUS)
2129 .deviceId(stylusDeviceId1)
2130 .pointer(PointerBuilder(0, ToolType::STYLUS).x(99).y(100))
2131 .build());
2132 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_STYLUS)
2133 .deviceId(stylusDeviceId1)
2134 .pointer(PointerBuilder(0, ToolType::STYLUS).x(100).y(101))
2135 .build());
2136 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(stylusDeviceId1)));
2137 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(stylusDeviceId1)));
2138
2139 // Second stylus down
2140 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_STYLUS)
2141 .deviceId(stylusDeviceId2)
2142 .pointer(PointerBuilder(0, ToolType::STYLUS).x(9).y(10))
2143 .build());
2144 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_STYLUS)
2145 .deviceId(stylusDeviceId2)
2146 .pointer(PointerBuilder(0, ToolType::STYLUS).x(10).y(11))
2147 .build());
2148 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(stylusDeviceId2)));
2149 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(stylusDeviceId2)));
2150
2151 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_STYLUS)
2152 .deviceId(stylusDeviceId1)
2153 .pointer(PointerBuilder(0, ToolType::STYLUS).x(101).y(102))
2154 .build());
2155 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(stylusDeviceId1)));
2156 window->assertNoEvents();
2157}
2158
2159/**
Siarhei Vishniakou2899c552023-07-10 18:20:46 -07002160 * One window. Touch down on the window. Then, stylus down on the window from another device.
2161 * Ensure that is canceled, because stylus down should be preferred over touch.
2162 */
2163TEST_F(InputDispatcherMultiDeviceTest, TouchIsCanceledByStylusDown) {
Siarhei Vishniakoued89cbb2023-10-13 10:42:44 -07002164 SCOPED_FLAG_OVERRIDE(enable_multi_device_same_window_stream, false);
Siarhei Vishniakou2899c552023-07-10 18:20:46 -07002165 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
2166 sp<FakeWindowHandle> window =
2167 sp<FakeWindowHandle>::make(application, mDispatcher, "Window", ADISPLAY_ID_DEFAULT);
2168 window->setFrame(Rect(0, 0, 200, 200));
2169
2170 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
2171
2172 constexpr int32_t touchDeviceId = 4;
2173 constexpr int32_t stylusDeviceId = 2;
2174
2175 // Touch down on window
2176 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
2177 .deviceId(touchDeviceId)
2178 .pointer(PointerBuilder(0, ToolType::FINGER).x(140).y(145))
2179 .build());
2180 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN)
2181 .deviceId(touchDeviceId)
2182 .pointer(PointerBuilder(0, ToolType::FINGER).x(141).y(146))
2183 .build());
2184 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(touchDeviceId)));
2185 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(touchDeviceId)));
2186
2187 // Stylus down on the window
2188 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_STYLUS)
2189 .deviceId(stylusDeviceId)
2190 .pointer(PointerBuilder(0, ToolType::STYLUS).x(100).y(110))
2191 .build());
2192 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_CANCEL), WithDeviceId(touchDeviceId)));
2193 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(stylusDeviceId)));
2194
2195 // Subsequent stylus movements are delivered correctly
2196 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_STYLUS)
2197 .deviceId(stylusDeviceId)
2198 .pointer(PointerBuilder(0, ToolType::STYLUS).x(101).y(111))
2199 .build());
2200 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(stylusDeviceId),
2201 WithCoords(101, 111)));
2202}
2203
2204/**
Siarhei Vishniakoued89cbb2023-10-13 10:42:44 -07002205 * One window. Touch down on the window. Then, stylus down on the window from another device.
2206 * Ensure that both touch and stylus are functioning independently.
2207 */
2208TEST_F(InputDispatcherMultiDeviceTest, TouchIsNotCanceledByStylusDown) {
2209 SCOPED_FLAG_OVERRIDE(enable_multi_device_same_window_stream, true);
2210 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
2211 sp<FakeWindowHandle> window =
2212 sp<FakeWindowHandle>::make(application, mDispatcher, "Window", ADISPLAY_ID_DEFAULT);
2213 window->setFrame(Rect(0, 0, 200, 200));
2214
2215 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
2216
2217 constexpr int32_t touchDeviceId = 4;
2218 constexpr int32_t stylusDeviceId = 2;
2219
2220 // Touch down on window
2221 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
2222 .deviceId(touchDeviceId)
2223 .pointer(PointerBuilder(0, ToolType::FINGER).x(140).y(145))
2224 .build());
2225 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN)
2226 .deviceId(touchDeviceId)
2227 .pointer(PointerBuilder(0, ToolType::FINGER).x(141).y(146))
2228 .build());
2229 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(touchDeviceId)));
2230 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(touchDeviceId)));
2231
2232 // Stylus down on the window
2233 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_STYLUS)
2234 .deviceId(stylusDeviceId)
2235 .pointer(PointerBuilder(0, ToolType::STYLUS).x(100).y(110))
2236 .build());
2237 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(stylusDeviceId)));
2238
2239 // Subsequent stylus movements are delivered correctly
2240 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_STYLUS)
2241 .deviceId(stylusDeviceId)
2242 .pointer(PointerBuilder(0, ToolType::STYLUS).x(101).y(111))
2243 .build());
2244 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(stylusDeviceId),
2245 WithCoords(101, 111)));
2246
2247 // Touch continues to work too
2248 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN)
2249 .deviceId(touchDeviceId)
2250 .pointer(PointerBuilder(0, ToolType::FINGER).x(148).y(149))
2251 .build());
2252 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(touchDeviceId)));
2253}
2254
2255/**
Siarhei Vishniakouf372b812023-02-14 18:06:51 -08002256 * Two windows: a window on the left and a window on the right.
2257 * Mouse is clicked on the left window and remains down. Touch is touched on the right and remains
2258 * down. Then, on the left window, also place second touch pointer down.
2259 * This test tries to reproduce a crash.
2260 * In the buggy implementation, second pointer down on the left window would cause a crash.
2261 */
Siarhei Vishniakoued89cbb2023-10-13 10:42:44 -07002262TEST_F(InputDispatcherMultiDeviceTest, MultiDeviceSplitTouch_legacy) {
2263 SCOPED_FLAG_OVERRIDE(enable_multi_device_same_window_stream, false);
Siarhei Vishniakouf372b812023-02-14 18:06:51 -08002264 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
2265 sp<FakeWindowHandle> leftWindow =
2266 sp<FakeWindowHandle>::make(application, mDispatcher, "Left", ADISPLAY_ID_DEFAULT);
2267 leftWindow->setFrame(Rect(0, 0, 200, 200));
2268
2269 sp<FakeWindowHandle> rightWindow =
2270 sp<FakeWindowHandle>::make(application, mDispatcher, "Right", ADISPLAY_ID_DEFAULT);
2271 rightWindow->setFrame(Rect(200, 0, 400, 200));
2272
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07002273 mDispatcher->onWindowInfosChanged(
2274 {{*leftWindow->getInfo(), *rightWindow->getInfo()}, {}, 0, 0});
Siarhei Vishniakouf372b812023-02-14 18:06:51 -08002275
2276 const int32_t touchDeviceId = 4;
2277 const int32_t mouseDeviceId = 6;
Siarhei Vishniakouf372b812023-02-14 18:06:51 -08002278
2279 // Start hovering over the left window
Prabir Pradhan678438e2023-04-13 19:32:51 +00002280 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_ENTER, AINPUT_SOURCE_MOUSE)
2281 .deviceId(mouseDeviceId)
2282 .pointer(PointerBuilder(0, ToolType::MOUSE).x(100).y(100))
2283 .build());
Siarhei Vishniakouf372b812023-02-14 18:06:51 -08002284 leftWindow->consumeMotionEvent(
2285 AllOf(WithMotionAction(ACTION_HOVER_ENTER), WithDeviceId(mouseDeviceId)));
2286
2287 // Mouse down on left window
Prabir Pradhan678438e2023-04-13 19:32:51 +00002288 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_MOUSE)
2289 .deviceId(mouseDeviceId)
2290 .buttonState(AMOTION_EVENT_BUTTON_PRIMARY)
2291 .pointer(PointerBuilder(0, ToolType::MOUSE).x(100).y(100))
2292 .build());
Siarhei Vishniakouf372b812023-02-14 18:06:51 -08002293
2294 leftWindow->consumeMotionEvent(
2295 AllOf(WithMotionAction(ACTION_HOVER_EXIT), WithDeviceId(mouseDeviceId)));
2296 leftWindow->consumeMotionEvent(
2297 AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(mouseDeviceId)));
2298
Prabir Pradhan678438e2023-04-13 19:32:51 +00002299 mDispatcher->notifyMotion(
2300 MotionArgsBuilder(AMOTION_EVENT_ACTION_BUTTON_PRESS, AINPUT_SOURCE_MOUSE)
2301 .deviceId(mouseDeviceId)
2302 .buttonState(AMOTION_EVENT_BUTTON_PRIMARY)
2303 .actionButton(AMOTION_EVENT_BUTTON_PRIMARY)
2304 .pointer(PointerBuilder(0, ToolType::MOUSE).x(100).y(100))
2305 .build());
Siarhei Vishniakouf372b812023-02-14 18:06:51 -08002306 leftWindow->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_BUTTON_PRESS));
2307
2308 // First touch pointer down on right window
Prabir Pradhan678438e2023-04-13 19:32:51 +00002309 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
2310 .deviceId(touchDeviceId)
2311 .pointer(PointerBuilder(0, ToolType::FINGER).x(300).y(100))
2312 .build());
Siarhei Vishniakou2899c552023-07-10 18:20:46 -07002313 leftWindow->assertNoEvents();
2314
Siarhei Vishniakouf372b812023-02-14 18:06:51 -08002315 rightWindow->consumeMotionEvent(WithMotionAction(ACTION_DOWN));
2316
2317 // Second touch pointer down on left window
Prabir Pradhan678438e2023-04-13 19:32:51 +00002318 mDispatcher->notifyMotion(MotionArgsBuilder(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
2319 .deviceId(touchDeviceId)
2320 .pointer(PointerBuilder(0, ToolType::FINGER).x(300).y(100))
2321 .pointer(PointerBuilder(1, ToolType::FINGER).x(100).y(100))
2322 .build());
Siarhei Vishniakou2899c552023-07-10 18:20:46 -07002323 // Since this is now a new splittable pointer going down on the left window, and it's coming
2324 // from a different device, the current gesture in the left window (pointer down) should first
2325 // be canceled.
2326 leftWindow->consumeMotionEvent(
2327 AllOf(WithMotionAction(ACTION_CANCEL), WithDeviceId(mouseDeviceId)));
Siarhei Vishniakouf372b812023-02-14 18:06:51 -08002328 leftWindow->consumeMotionEvent(
2329 AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(touchDeviceId)));
2330 // This MOVE event is not necessary (doesn't carry any new information), but it's there in the
2331 // current implementation.
2332 const std::map<int32_t, PointF> expectedPointers{{0, PointF{100, 100}}};
2333 rightWindow->consumeMotionEvent(
2334 AllOf(WithMotionAction(ACTION_MOVE), WithPointers(expectedPointers)));
2335
2336 leftWindow->assertNoEvents();
2337 rightWindow->assertNoEvents();
2338}
2339
2340/**
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -07002341 * Two windows: a window on the left and a window on the right.
Siarhei Vishniakoued89cbb2023-10-13 10:42:44 -07002342 * Mouse is clicked on the left window and remains down. Touch is touched on the right and remains
2343 * down. Then, on the left window, also place second touch pointer down.
2344 * This test tries to reproduce a crash.
2345 * In the buggy implementation, second pointer down on the left window would cause a crash.
2346 */
2347TEST_F(InputDispatcherMultiDeviceTest, MultiDeviceSplitTouch) {
2348 SCOPED_FLAG_OVERRIDE(enable_multi_device_same_window_stream, true);
2349 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
2350 sp<FakeWindowHandle> leftWindow =
2351 sp<FakeWindowHandle>::make(application, mDispatcher, "Left", ADISPLAY_ID_DEFAULT);
2352 leftWindow->setFrame(Rect(0, 0, 200, 200));
2353
2354 sp<FakeWindowHandle> rightWindow =
2355 sp<FakeWindowHandle>::make(application, mDispatcher, "Right", ADISPLAY_ID_DEFAULT);
2356 rightWindow->setFrame(Rect(200, 0, 400, 200));
2357
2358 mDispatcher->onWindowInfosChanged(
2359 {{*leftWindow->getInfo(), *rightWindow->getInfo()}, {}, 0, 0});
2360
2361 const int32_t touchDeviceId = 4;
2362 const int32_t mouseDeviceId = 6;
2363
2364 // Start hovering over the left window
2365 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_ENTER, AINPUT_SOURCE_MOUSE)
2366 .deviceId(mouseDeviceId)
2367 .pointer(PointerBuilder(0, ToolType::MOUSE).x(100).y(100))
2368 .build());
2369 leftWindow->consumeMotionEvent(
2370 AllOf(WithMotionAction(ACTION_HOVER_ENTER), WithDeviceId(mouseDeviceId)));
2371
2372 // Mouse down on left window
2373 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_MOUSE)
2374 .deviceId(mouseDeviceId)
2375 .buttonState(AMOTION_EVENT_BUTTON_PRIMARY)
2376 .pointer(PointerBuilder(0, ToolType::MOUSE).x(100).y(100))
2377 .build());
2378
2379 leftWindow->consumeMotionEvent(
2380 AllOf(WithMotionAction(ACTION_HOVER_EXIT), WithDeviceId(mouseDeviceId)));
2381 leftWindow->consumeMotionEvent(
2382 AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(mouseDeviceId)));
2383
2384 mDispatcher->notifyMotion(
2385 MotionArgsBuilder(AMOTION_EVENT_ACTION_BUTTON_PRESS, AINPUT_SOURCE_MOUSE)
2386 .deviceId(mouseDeviceId)
2387 .buttonState(AMOTION_EVENT_BUTTON_PRIMARY)
2388 .actionButton(AMOTION_EVENT_BUTTON_PRIMARY)
2389 .pointer(PointerBuilder(0, ToolType::MOUSE).x(100).y(100))
2390 .build());
2391 leftWindow->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_BUTTON_PRESS));
2392
2393 // First touch pointer down on right window
2394 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
2395 .deviceId(touchDeviceId)
2396 .pointer(PointerBuilder(0, ToolType::FINGER).x(300).y(100))
2397 .build());
2398 leftWindow->assertNoEvents();
2399
2400 rightWindow->consumeMotionEvent(WithMotionAction(ACTION_DOWN));
2401
2402 // Second touch pointer down on left window
2403 mDispatcher->notifyMotion(MotionArgsBuilder(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
2404 .deviceId(touchDeviceId)
2405 .pointer(PointerBuilder(0, ToolType::FINGER).x(300).y(100))
2406 .pointer(PointerBuilder(1, ToolType::FINGER).x(100).y(100))
2407 .build());
2408 // Since this is now a new splittable pointer going down on the left window, and it's coming
2409 // from a different device, it will be split and delivered to left window separately.
2410 leftWindow->consumeMotionEvent(
2411 AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(touchDeviceId)));
2412 // This MOVE event is not necessary (doesn't carry any new information), but it's there in the
2413 // current implementation.
2414 const std::map<int32_t, PointF> expectedPointers{{0, PointF{100, 100}}};
2415 rightWindow->consumeMotionEvent(
2416 AllOf(WithMotionAction(ACTION_MOVE), WithPointers(expectedPointers)));
2417
2418 leftWindow->assertNoEvents();
2419 rightWindow->assertNoEvents();
2420}
2421
2422/**
2423 * Two windows: a window on the left and a window on the right.
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -07002424 * Mouse is hovered on the left window and stylus is hovered on the right window.
2425 */
2426TEST_F(InputDispatcherMultiDeviceTest, MultiDeviceHover) {
2427 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
2428 sp<FakeWindowHandle> leftWindow =
2429 sp<FakeWindowHandle>::make(application, mDispatcher, "Left", ADISPLAY_ID_DEFAULT);
2430 leftWindow->setFrame(Rect(0, 0, 200, 200));
2431
2432 sp<FakeWindowHandle> rightWindow =
2433 sp<FakeWindowHandle>::make(application, mDispatcher, "Right", ADISPLAY_ID_DEFAULT);
2434 rightWindow->setFrame(Rect(200, 0, 400, 200));
2435
2436 mDispatcher->onWindowInfosChanged(
2437 {{*leftWindow->getInfo(), *rightWindow->getInfo()}, {}, 0, 0});
2438
2439 const int32_t stylusDeviceId = 3;
2440 const int32_t mouseDeviceId = 6;
2441
2442 // Start hovering over the left window
2443 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_ENTER, AINPUT_SOURCE_MOUSE)
2444 .deviceId(mouseDeviceId)
2445 .pointer(PointerBuilder(0, ToolType::MOUSE).x(100).y(110))
2446 .build());
2447 leftWindow->consumeMotionEvent(
2448 AllOf(WithMotionAction(ACTION_HOVER_ENTER), WithDeviceId(mouseDeviceId)));
2449
2450 // Stylus hovered on right window
2451 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_ENTER, AINPUT_SOURCE_STYLUS)
2452 .deviceId(stylusDeviceId)
2453 .pointer(PointerBuilder(0, ToolType::STYLUS).x(300).y(100))
2454 .build());
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -07002455 rightWindow->consumeMotionEvent(
2456 AllOf(WithMotionAction(ACTION_HOVER_ENTER), WithDeviceId(stylusDeviceId)));
2457
2458 // Subsequent HOVER_MOVE events are dispatched correctly.
2459 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_MOVE, AINPUT_SOURCE_MOUSE)
2460 .deviceId(mouseDeviceId)
2461 .pointer(PointerBuilder(0, ToolType::MOUSE).x(110).y(120))
2462 .build());
2463 leftWindow->consumeMotionEvent(
Siarhei Vishniakou2899c552023-07-10 18:20:46 -07002464 AllOf(WithMotionAction(ACTION_HOVER_MOVE), WithDeviceId(mouseDeviceId)));
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -07002465
2466 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_MOVE, AINPUT_SOURCE_STYLUS)
2467 .deviceId(stylusDeviceId)
2468 .pointer(PointerBuilder(0, ToolType::STYLUS).x(310).y(110))
2469 .build());
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -07002470 rightWindow->consumeMotionEvent(
Siarhei Vishniakou2899c552023-07-10 18:20:46 -07002471 AllOf(WithMotionAction(ACTION_HOVER_MOVE), WithDeviceId(stylusDeviceId)));
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -07002472
2473 leftWindow->assertNoEvents();
2474 rightWindow->assertNoEvents();
2475}
2476
2477/**
2478 * Three windows: a window on the left and a window on the right.
2479 * And a spy window that's positioned above all of them.
2480 * Stylus down on the left window and remains down. Touch goes down on the right and remains down.
2481 * Check the stream that's received by the spy.
2482 */
Siarhei Vishniakoued89cbb2023-10-13 10:42:44 -07002483TEST_F(InputDispatcherMultiDeviceTest, MultiDeviceWithSpy_legacy) {
2484 SCOPED_FLAG_OVERRIDE(enable_multi_device_same_window_stream, false);
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -07002485 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
2486
2487 sp<FakeWindowHandle> spyWindow =
2488 sp<FakeWindowHandle>::make(application, mDispatcher, "Spy", ADISPLAY_ID_DEFAULT);
2489 spyWindow->setFrame(Rect(0, 0, 400, 400));
2490 spyWindow->setTrustedOverlay(true);
2491 spyWindow->setSpy(true);
2492
2493 sp<FakeWindowHandle> leftWindow =
2494 sp<FakeWindowHandle>::make(application, mDispatcher, "Left", ADISPLAY_ID_DEFAULT);
2495 leftWindow->setFrame(Rect(0, 0, 200, 200));
2496
2497 sp<FakeWindowHandle> rightWindow =
2498 sp<FakeWindowHandle>::make(application, mDispatcher, "Right", ADISPLAY_ID_DEFAULT);
2499
2500 rightWindow->setFrame(Rect(200, 0, 400, 200));
2501
2502 mDispatcher->onWindowInfosChanged(
2503 {{*spyWindow->getInfo(), *leftWindow->getInfo(), *rightWindow->getInfo()}, {}, 0, 0});
2504
2505 const int32_t stylusDeviceId = 1;
2506 const int32_t touchDeviceId = 2;
2507
2508 // Stylus down on the left window
2509 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_STYLUS)
2510 .deviceId(stylusDeviceId)
2511 .pointer(PointerBuilder(0, ToolType::STYLUS).x(100).y(100))
2512 .build());
2513 leftWindow->consumeMotionEvent(
2514 AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(stylusDeviceId)));
2515 spyWindow->consumeMotionEvent(
2516 AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(stylusDeviceId)));
2517
2518 // Touch down on the right window
2519 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
2520 .deviceId(touchDeviceId)
2521 .pointer(PointerBuilder(0, ToolType::FINGER).x(300).y(100))
2522 .build());
Siarhei Vishniakou2899c552023-07-10 18:20:46 -07002523 leftWindow->assertNoEvents();
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -07002524 rightWindow->consumeMotionEvent(
2525 AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(touchDeviceId)));
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -07002526
Siarhei Vishniakou2899c552023-07-10 18:20:46 -07002527 // Spy window does not receive touch events, because stylus events take precedence, and it
2528 // already has an active stylus gesture.
2529
2530 // Stylus movements continue. They should be delivered to the left window and to the spy window
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -07002531 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_STYLUS)
2532 .deviceId(stylusDeviceId)
2533 .pointer(PointerBuilder(0, ToolType::STYLUS).x(110).y(110))
2534 .build());
Siarhei Vishniakou2899c552023-07-10 18:20:46 -07002535 leftWindow->consumeMotionEvent(
2536 AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(stylusDeviceId)));
2537 spyWindow->consumeMotionEvent(
2538 AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(stylusDeviceId)));
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -07002539
Siarhei Vishniakou2899c552023-07-10 18:20:46 -07002540 // Further MOVE events keep going to the right window only
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -07002541 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN)
2542 .deviceId(touchDeviceId)
2543 .pointer(PointerBuilder(0, ToolType::FINGER).x(310).y(110))
2544 .build());
2545 rightWindow->consumeMotionEvent(
2546 AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(touchDeviceId)));
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -07002547
2548 spyWindow->assertNoEvents();
2549 leftWindow->assertNoEvents();
2550 rightWindow->assertNoEvents();
2551}
2552
2553/**
Siarhei Vishniakoued89cbb2023-10-13 10:42:44 -07002554 * Three windows: a window on the left and a window on the right.
2555 * And a spy window that's positioned above all of them.
2556 * Stylus down on the left window and remains down. Touch goes down on the right and remains down.
2557 * Check the stream that's received by the spy.
2558 */
2559TEST_F(InputDispatcherMultiDeviceTest, MultiDeviceWithSpy) {
2560 SCOPED_FLAG_OVERRIDE(enable_multi_device_same_window_stream, true);
2561 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
2562
2563 sp<FakeWindowHandle> spyWindow =
2564 sp<FakeWindowHandle>::make(application, mDispatcher, "Spy", ADISPLAY_ID_DEFAULT);
2565 spyWindow->setFrame(Rect(0, 0, 400, 400));
2566 spyWindow->setTrustedOverlay(true);
2567 spyWindow->setSpy(true);
2568
2569 sp<FakeWindowHandle> leftWindow =
2570 sp<FakeWindowHandle>::make(application, mDispatcher, "Left", ADISPLAY_ID_DEFAULT);
2571 leftWindow->setFrame(Rect(0, 0, 200, 200));
2572
2573 sp<FakeWindowHandle> rightWindow =
2574 sp<FakeWindowHandle>::make(application, mDispatcher, "Right", ADISPLAY_ID_DEFAULT);
2575
2576 rightWindow->setFrame(Rect(200, 0, 400, 200));
2577
2578 mDispatcher->onWindowInfosChanged(
2579 {{*spyWindow->getInfo(), *leftWindow->getInfo(), *rightWindow->getInfo()}, {}, 0, 0});
2580
2581 const int32_t stylusDeviceId = 1;
2582 const int32_t touchDeviceId = 2;
2583
2584 // Stylus down on the left window
2585 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_STYLUS)
2586 .deviceId(stylusDeviceId)
2587 .pointer(PointerBuilder(0, ToolType::STYLUS).x(100).y(100))
2588 .build());
2589 leftWindow->consumeMotionEvent(
2590 AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(stylusDeviceId)));
2591 spyWindow->consumeMotionEvent(
2592 AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(stylusDeviceId)));
2593
2594 // Touch down on the right window
2595 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
2596 .deviceId(touchDeviceId)
2597 .pointer(PointerBuilder(0, ToolType::FINGER).x(300).y(100))
2598 .build());
2599 leftWindow->assertNoEvents();
2600 rightWindow->consumeMotionEvent(
2601 AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(touchDeviceId)));
2602 spyWindow->consumeMotionEvent(
2603 AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(touchDeviceId)));
2604
2605 // Stylus movements continue. They should be delivered to the left window and to the spy window
2606 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_STYLUS)
2607 .deviceId(stylusDeviceId)
2608 .pointer(PointerBuilder(0, ToolType::STYLUS).x(110).y(110))
2609 .build());
2610 leftWindow->consumeMotionEvent(
2611 AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(stylusDeviceId)));
2612 spyWindow->consumeMotionEvent(
2613 AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(stylusDeviceId)));
2614
2615 // Further touch MOVE events keep going to the right window and to the spy
2616 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN)
2617 .deviceId(touchDeviceId)
2618 .pointer(PointerBuilder(0, ToolType::FINGER).x(310).y(110))
2619 .build());
2620 rightWindow->consumeMotionEvent(
2621 AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(touchDeviceId)));
2622 spyWindow->consumeMotionEvent(
2623 AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(touchDeviceId)));
2624
2625 spyWindow->assertNoEvents();
2626 leftWindow->assertNoEvents();
2627 rightWindow->assertNoEvents();
2628}
2629
2630/**
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -07002631 * Three windows: a window on the left, a window on the right, and a spy window positioned above
2632 * both.
2633 * Check hover in left window and touch down in the right window.
Siarhei Vishniakou3ad54f52023-11-02 16:54:40 -07002634 * At first, spy should receive hover. Spy shouldn't receive touch while stylus is hovering.
Siarhei Vishniakou2899c552023-07-10 18:20:46 -07002635 * At the same time, left and right should be getting independent streams of hovering and touch,
2636 * respectively.
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -07002637 */
Siarhei Vishniakou3ad54f52023-11-02 16:54:40 -07002638TEST_F(InputDispatcherMultiDeviceTest, MultiDeviceHoverBlocksTouchWithSpy) {
Siarhei Vishniakoued89cbb2023-10-13 10:42:44 -07002639 SCOPED_FLAG_OVERRIDE(enable_multi_device_same_window_stream, false);
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -07002640 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
2641
2642 sp<FakeWindowHandle> spyWindow =
2643 sp<FakeWindowHandle>::make(application, mDispatcher, "Spy", ADISPLAY_ID_DEFAULT);
2644 spyWindow->setFrame(Rect(0, 0, 400, 400));
2645 spyWindow->setTrustedOverlay(true);
2646 spyWindow->setSpy(true);
2647
2648 sp<FakeWindowHandle> leftWindow =
2649 sp<FakeWindowHandle>::make(application, mDispatcher, "Left", ADISPLAY_ID_DEFAULT);
2650 leftWindow->setFrame(Rect(0, 0, 200, 200));
2651
2652 sp<FakeWindowHandle> rightWindow =
2653 sp<FakeWindowHandle>::make(application, mDispatcher, "Right", ADISPLAY_ID_DEFAULT);
2654 rightWindow->setFrame(Rect(200, 0, 400, 200));
2655
2656 mDispatcher->onWindowInfosChanged(
2657 {{*spyWindow->getInfo(), *leftWindow->getInfo(), *rightWindow->getInfo()}, {}, 0, 0});
2658
2659 const int32_t stylusDeviceId = 1;
2660 const int32_t touchDeviceId = 2;
2661
2662 // Stylus hover on the left window
2663 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_ENTER, AINPUT_SOURCE_STYLUS)
2664 .deviceId(stylusDeviceId)
2665 .pointer(PointerBuilder(0, ToolType::STYLUS).x(100).y(100))
2666 .build());
2667 leftWindow->consumeMotionEvent(
2668 AllOf(WithMotionAction(ACTION_HOVER_ENTER), WithDeviceId(stylusDeviceId)));
2669 spyWindow->consumeMotionEvent(
2670 AllOf(WithMotionAction(ACTION_HOVER_ENTER), WithDeviceId(stylusDeviceId)));
2671
Siarhei Vishniakou2899c552023-07-10 18:20:46 -07002672 // Touch down on the right window. Spy doesn't receive this touch because it already has
2673 // stylus hovering there.
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -07002674 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
2675 .deviceId(touchDeviceId)
2676 .pointer(PointerBuilder(0, ToolType::FINGER).x(300).y(100))
2677 .build());
Siarhei Vishniakou2899c552023-07-10 18:20:46 -07002678 leftWindow->assertNoEvents();
Siarhei Vishniakou3ad54f52023-11-02 16:54:40 -07002679 spyWindow->assertNoEvents();
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -07002680 rightWindow->consumeMotionEvent(
2681 AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(touchDeviceId)));
2682
Siarhei Vishniakou3ad54f52023-11-02 16:54:40 -07002683 // Stylus movements continue. They should be delivered to the left window and the spy.
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -07002684 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_MOVE, AINPUT_SOURCE_STYLUS)
2685 .deviceId(stylusDeviceId)
2686 .pointer(PointerBuilder(0, ToolType::STYLUS).x(110).y(110))
2687 .build());
Siarhei Vishniakou2899c552023-07-10 18:20:46 -07002688 leftWindow->consumeMotionEvent(
2689 AllOf(WithMotionAction(ACTION_HOVER_MOVE), WithDeviceId(stylusDeviceId)));
Siarhei Vishniakou3ad54f52023-11-02 16:54:40 -07002690 spyWindow->consumeMotionEvent(
2691 AllOf(WithMotionAction(ACTION_HOVER_MOVE), WithDeviceId(stylusDeviceId)));
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -07002692
Siarhei Vishniakou3ad54f52023-11-02 16:54:40 -07002693 // Touch movements continue. They should be delivered to the right window only
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -07002694 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN)
2695 .deviceId(touchDeviceId)
2696 .pointer(PointerBuilder(0, ToolType::FINGER).x(301).y(101))
2697 .build());
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -07002698 rightWindow->consumeMotionEvent(
2699 AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(touchDeviceId)));
2700
2701 spyWindow->assertNoEvents();
2702 leftWindow->assertNoEvents();
2703 rightWindow->assertNoEvents();
2704}
2705
2706/**
Siarhei Vishniakoued89cbb2023-10-13 10:42:44 -07002707 * Three windows: a window on the left, a window on the right, and a spy window positioned above
2708 * both.
2709 * Check hover in left window and touch down in the right window.
2710 * At first, spy should receive hover. Next, spy should receive touch.
2711 * At the same time, left and right should be getting independent streams of hovering and touch,
2712 * respectively.
2713 */
2714TEST_F(InputDispatcherMultiDeviceTest, MultiDeviceHoverDoesNotBlockTouchWithSpy) {
2715 SCOPED_FLAG_OVERRIDE(enable_multi_device_same_window_stream, true);
2716 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
2717
2718 sp<FakeWindowHandle> spyWindow =
2719 sp<FakeWindowHandle>::make(application, mDispatcher, "Spy", ADISPLAY_ID_DEFAULT);
2720 spyWindow->setFrame(Rect(0, 0, 400, 400));
2721 spyWindow->setTrustedOverlay(true);
2722 spyWindow->setSpy(true);
2723
2724 sp<FakeWindowHandle> leftWindow =
2725 sp<FakeWindowHandle>::make(application, mDispatcher, "Left", ADISPLAY_ID_DEFAULT);
2726 leftWindow->setFrame(Rect(0, 0, 200, 200));
2727
2728 sp<FakeWindowHandle> rightWindow =
2729 sp<FakeWindowHandle>::make(application, mDispatcher, "Right", ADISPLAY_ID_DEFAULT);
2730 rightWindow->setFrame(Rect(200, 0, 400, 200));
2731
2732 mDispatcher->onWindowInfosChanged(
2733 {{*spyWindow->getInfo(), *leftWindow->getInfo(), *rightWindow->getInfo()}, {}, 0, 0});
2734
2735 const int32_t stylusDeviceId = 1;
2736 const int32_t touchDeviceId = 2;
2737
2738 // Stylus hover on the left window
2739 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_ENTER, AINPUT_SOURCE_STYLUS)
2740 .deviceId(stylusDeviceId)
2741 .pointer(PointerBuilder(0, ToolType::STYLUS).x(100).y(100))
2742 .build());
2743 leftWindow->consumeMotionEvent(
2744 AllOf(WithMotionAction(ACTION_HOVER_ENTER), WithDeviceId(stylusDeviceId)));
2745 spyWindow->consumeMotionEvent(
2746 AllOf(WithMotionAction(ACTION_HOVER_ENTER), WithDeviceId(stylusDeviceId)));
2747
2748 // Touch down on the right window.
2749 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
2750 .deviceId(touchDeviceId)
2751 .pointer(PointerBuilder(0, ToolType::FINGER).x(300).y(100))
2752 .build());
2753 leftWindow->assertNoEvents();
2754 spyWindow->consumeMotionEvent(
2755 AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(touchDeviceId)));
2756 rightWindow->consumeMotionEvent(
2757 AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(touchDeviceId)));
2758
2759 // Stylus movements continue. They should be delivered to the left window and the spy.
2760 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_MOVE, AINPUT_SOURCE_STYLUS)
2761 .deviceId(stylusDeviceId)
2762 .pointer(PointerBuilder(0, ToolType::STYLUS).x(110).y(110))
2763 .build());
2764 leftWindow->consumeMotionEvent(
2765 AllOf(WithMotionAction(ACTION_HOVER_MOVE), WithDeviceId(stylusDeviceId)));
2766 spyWindow->consumeMotionEvent(
2767 AllOf(WithMotionAction(ACTION_HOVER_MOVE), WithDeviceId(stylusDeviceId)));
2768
2769 // Touch movements continue. They should be delivered to the right window and the spy
2770 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN)
2771 .deviceId(touchDeviceId)
2772 .pointer(PointerBuilder(0, ToolType::FINGER).x(301).y(101))
2773 .build());
2774 rightWindow->consumeMotionEvent(
2775 AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(touchDeviceId)));
2776 spyWindow->consumeMotionEvent(
2777 AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(touchDeviceId)));
2778
2779 spyWindow->assertNoEvents();
2780 leftWindow->assertNoEvents();
2781 rightWindow->assertNoEvents();
2782}
2783
2784/**
Siarhei Vishniakouf372b812023-02-14 18:06:51 -08002785 * On a single window, use two different devices: mouse and touch.
2786 * Touch happens first, with two pointers going down, and then the first pointer leaving.
2787 * Mouse is clicked next, which causes the touch stream to be aborted with ACTION_CANCEL.
2788 * Finally, a second touch pointer goes down again. Ensure the second touch pointer is ignored,
2789 * because the mouse is currently down, and a POINTER_DOWN event from the touchscreen does not
2790 * represent a new gesture.
2791 */
Siarhei Vishniakoued89cbb2023-10-13 10:42:44 -07002792TEST_F(InputDispatcherMultiDeviceTest, MixedTouchAndMouseWithPointerDown_legacy) {
2793 SCOPED_FLAG_OVERRIDE(enable_multi_device_same_window_stream, false);
Siarhei Vishniakouf372b812023-02-14 18:06:51 -08002794 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
2795 sp<FakeWindowHandle> window =
2796 sp<FakeWindowHandle>::make(application, mDispatcher, "Window", ADISPLAY_ID_DEFAULT);
2797 window->setFrame(Rect(0, 0, 400, 400));
2798
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07002799 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Siarhei Vishniakouf372b812023-02-14 18:06:51 -08002800
2801 const int32_t touchDeviceId = 4;
2802 const int32_t mouseDeviceId = 6;
Siarhei Vishniakouf372b812023-02-14 18:06:51 -08002803
Siarhei Vishniakou4e1ffa52023-02-21 11:50:34 -08002804 // First touch pointer down
Prabir Pradhan678438e2023-04-13 19:32:51 +00002805 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
2806 .deviceId(touchDeviceId)
2807 .pointer(PointerBuilder(0, ToolType::FINGER).x(300).y(100))
2808 .build());
Siarhei Vishniakouf372b812023-02-14 18:06:51 -08002809 // Second touch pointer down
Prabir Pradhan678438e2023-04-13 19:32:51 +00002810 mDispatcher->notifyMotion(MotionArgsBuilder(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
2811 .deviceId(touchDeviceId)
2812 .pointer(PointerBuilder(0, ToolType::FINGER).x(300).y(100))
2813 .pointer(PointerBuilder(1, ToolType::FINGER).x(350).y(100))
2814 .build());
Siarhei Vishniakouf372b812023-02-14 18:06:51 -08002815 // First touch pointer lifts. The second one remains down
Prabir Pradhan678438e2023-04-13 19:32:51 +00002816 mDispatcher->notifyMotion(MotionArgsBuilder(POINTER_0_UP, AINPUT_SOURCE_TOUCHSCREEN)
2817 .deviceId(touchDeviceId)
2818 .pointer(PointerBuilder(0, ToolType::FINGER).x(300).y(100))
2819 .pointer(PointerBuilder(1, ToolType::FINGER).x(350).y(100))
2820 .build());
Siarhei Vishniakouf372b812023-02-14 18:06:51 -08002821 window->consumeMotionEvent(WithMotionAction(ACTION_DOWN));
2822 window->consumeMotionEvent(WithMotionAction(POINTER_1_DOWN));
2823 window->consumeMotionEvent(WithMotionAction(POINTER_0_UP));
2824
2825 // Mouse down. The touch should be canceled
Prabir Pradhan678438e2023-04-13 19:32:51 +00002826 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_MOUSE)
2827 .deviceId(mouseDeviceId)
2828 .buttonState(AMOTION_EVENT_BUTTON_PRIMARY)
2829 .pointer(PointerBuilder(0, ToolType::MOUSE).x(320).y(100))
2830 .build());
Siarhei Vishniakouf372b812023-02-14 18:06:51 -08002831
2832 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_CANCEL), WithDeviceId(touchDeviceId),
Siarhei Vishniakou82dc0422023-02-17 23:12:52 -08002833 WithPointerCount(1u)));
Siarhei Vishniakouf372b812023-02-14 18:06:51 -08002834 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(mouseDeviceId)));
2835
Prabir Pradhan678438e2023-04-13 19:32:51 +00002836 mDispatcher->notifyMotion(
2837 MotionArgsBuilder(AMOTION_EVENT_ACTION_BUTTON_PRESS, AINPUT_SOURCE_MOUSE)
2838 .deviceId(mouseDeviceId)
2839 .buttonState(AMOTION_EVENT_BUTTON_PRIMARY)
2840 .actionButton(AMOTION_EVENT_BUTTON_PRIMARY)
2841 .pointer(PointerBuilder(0, ToolType::MOUSE).x(320).y(100))
2842 .build());
Siarhei Vishniakouf372b812023-02-14 18:06:51 -08002843 window->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_BUTTON_PRESS));
2844
2845 // Second touch pointer down.
Prabir Pradhan678438e2023-04-13 19:32:51 +00002846 mDispatcher->notifyMotion(MotionArgsBuilder(POINTER_0_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
2847 .deviceId(touchDeviceId)
2848 .pointer(PointerBuilder(0, ToolType::FINGER).x(300).y(100))
2849 .pointer(PointerBuilder(1, ToolType::FINGER).x(350).y(100))
2850 .build());
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -07002851 // Since we already canceled this touch gesture, it will be ignored until a completely new
2852 // gesture is started. This is easier to implement than trying to keep track of the new pointer
2853 // and generating an ACTION_DOWN instead of ACTION_POINTER_DOWN.
2854 // However, mouse movements should continue to work.
2855 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_MOUSE)
2856 .deviceId(mouseDeviceId)
2857 .buttonState(AMOTION_EVENT_BUTTON_PRIMARY)
2858 .pointer(PointerBuilder(0, ToolType::MOUSE).x(330).y(110))
2859 .build());
2860 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(mouseDeviceId)));
2861
Siarhei Vishniakouf372b812023-02-14 18:06:51 -08002862 window->assertNoEvents();
2863}
2864
2865/**
Siarhei Vishniakoued89cbb2023-10-13 10:42:44 -07002866 * On a single window, use two different devices: mouse and touch.
2867 * Touch happens first, with two pointers going down, and then the first pointer leaving.
2868 * Mouse is clicked next, which should not interfere with the touch stream.
2869 * Finally, a second touch pointer goes down again. Ensure the second touch pointer is also
2870 * delivered correctly.
2871 */
2872TEST_F(InputDispatcherMultiDeviceTest, MixedTouchAndMouseWithPointerDown) {
2873 SCOPED_FLAG_OVERRIDE(enable_multi_device_same_window_stream, true);
2874 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
2875 sp<FakeWindowHandle> window =
2876 sp<FakeWindowHandle>::make(application, mDispatcher, "Window", ADISPLAY_ID_DEFAULT);
2877 window->setFrame(Rect(0, 0, 400, 400));
2878
2879 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
2880
2881 const int32_t touchDeviceId = 4;
2882 const int32_t mouseDeviceId = 6;
2883
2884 // First touch pointer down
2885 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
2886 .deviceId(touchDeviceId)
2887 .pointer(PointerBuilder(0, ToolType::FINGER).x(300).y(100))
2888 .build());
2889 // Second touch pointer down
2890 mDispatcher->notifyMotion(MotionArgsBuilder(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
2891 .deviceId(touchDeviceId)
2892 .pointer(PointerBuilder(0, ToolType::FINGER).x(300).y(100))
2893 .pointer(PointerBuilder(1, ToolType::FINGER).x(350).y(100))
2894 .build());
2895 // First touch pointer lifts. The second one remains down
2896 mDispatcher->notifyMotion(MotionArgsBuilder(POINTER_0_UP, AINPUT_SOURCE_TOUCHSCREEN)
2897 .deviceId(touchDeviceId)
2898 .pointer(PointerBuilder(0, ToolType::FINGER).x(300).y(100))
2899 .pointer(PointerBuilder(1, ToolType::FINGER).x(350).y(100))
2900 .build());
2901 window->consumeMotionEvent(WithMotionAction(ACTION_DOWN));
2902 window->consumeMotionEvent(WithMotionAction(POINTER_1_DOWN));
2903 window->consumeMotionEvent(WithMotionAction(POINTER_0_UP));
2904
2905 // Mouse down
2906 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_MOUSE)
2907 .deviceId(mouseDeviceId)
2908 .buttonState(AMOTION_EVENT_BUTTON_PRIMARY)
2909 .pointer(PointerBuilder(0, ToolType::MOUSE).x(320).y(100))
2910 .build());
2911
2912 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(mouseDeviceId)));
2913
2914 mDispatcher->notifyMotion(
2915 MotionArgsBuilder(AMOTION_EVENT_ACTION_BUTTON_PRESS, AINPUT_SOURCE_MOUSE)
2916 .deviceId(mouseDeviceId)
2917 .buttonState(AMOTION_EVENT_BUTTON_PRIMARY)
2918 .actionButton(AMOTION_EVENT_BUTTON_PRIMARY)
2919 .pointer(PointerBuilder(0, ToolType::MOUSE).x(320).y(100))
2920 .build());
2921 window->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_BUTTON_PRESS));
2922
2923 // Second touch pointer down.
2924 mDispatcher->notifyMotion(MotionArgsBuilder(POINTER_0_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
2925 .deviceId(touchDeviceId)
2926 .pointer(PointerBuilder(0, ToolType::FINGER).x(300).y(100))
2927 .pointer(PointerBuilder(1, ToolType::FINGER).x(350).y(100))
2928 .build());
2929 window->consumeMotionEvent(AllOf(WithMotionAction(POINTER_0_DOWN), WithDeviceId(touchDeviceId),
2930 WithPointerCount(2u)));
2931
2932 // Mouse movements should continue to work
2933 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_MOUSE)
2934 .deviceId(mouseDeviceId)
2935 .buttonState(AMOTION_EVENT_BUTTON_PRIMARY)
2936 .pointer(PointerBuilder(0, ToolType::MOUSE).x(330).y(110))
2937 .build());
2938 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(mouseDeviceId)));
2939
2940 window->assertNoEvents();
2941}
2942
2943/**
Siarhei Vishniakou56e79092023-02-21 19:13:16 -08002944 * Inject a touch down and then send a new event via 'notifyMotion'. Ensure the new event cancels
2945 * the injected event.
2946 */
Siarhei Vishniakoued89cbb2023-10-13 10:42:44 -07002947TEST_F(InputDispatcherMultiDeviceTest, UnfinishedInjectedEvent_legacy) {
2948 SCOPED_FLAG_OVERRIDE(enable_multi_device_same_window_stream, false);
Siarhei Vishniakou56e79092023-02-21 19:13:16 -08002949 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
2950 sp<FakeWindowHandle> window =
2951 sp<FakeWindowHandle>::make(application, mDispatcher, "Window", ADISPLAY_ID_DEFAULT);
2952 window->setFrame(Rect(0, 0, 400, 400));
2953
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07002954 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Siarhei Vishniakou56e79092023-02-21 19:13:16 -08002955
2956 const int32_t touchDeviceId = 4;
Siarhei Vishniakou56e79092023-02-21 19:13:16 -08002957 // Pretend a test injects an ACTION_DOWN mouse event, but forgets to lift up the touch after
2958 // completion.
2959 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07002960 injectMotionEvent(*mDispatcher,
Siarhei Vishniakou56e79092023-02-21 19:13:16 -08002961 MotionEventBuilder(ACTION_DOWN, AINPUT_SOURCE_MOUSE)
2962 .deviceId(ReservedInputDeviceId::VIRTUAL_KEYBOARD_ID)
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07002963 .pointer(PointerBuilder(0, ToolType::MOUSE).x(50).y(50))
Siarhei Vishniakou56e79092023-02-21 19:13:16 -08002964 .build()));
2965 window->consumeMotionEvent(
2966 AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(VIRTUAL_KEYBOARD_ID)));
2967
2968 // Now a real touch comes. Rather than crashing or dropping the real event, the injected pointer
2969 // should be canceled and the new gesture should take over.
Prabir Pradhan678438e2023-04-13 19:32:51 +00002970 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
2971 .deviceId(touchDeviceId)
2972 .pointer(PointerBuilder(0, ToolType::FINGER).x(300).y(100))
2973 .build());
Siarhei Vishniakou56e79092023-02-21 19:13:16 -08002974
2975 window->consumeMotionEvent(
2976 AllOf(WithMotionAction(ACTION_CANCEL), WithDeviceId(VIRTUAL_KEYBOARD_ID)));
2977 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(touchDeviceId)));
2978}
2979
2980/**
Siarhei Vishniakoued89cbb2023-10-13 10:42:44 -07002981 * Inject a touch down and then send a new event via 'notifyMotion'. Ensure the new event runs
2982 * parallel to the injected event.
2983 */
2984TEST_F(InputDispatcherMultiDeviceTest, UnfinishedInjectedEvent) {
2985 SCOPED_FLAG_OVERRIDE(enable_multi_device_same_window_stream, true);
2986 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
2987 sp<FakeWindowHandle> window =
2988 sp<FakeWindowHandle>::make(application, mDispatcher, "Window", ADISPLAY_ID_DEFAULT);
2989 window->setFrame(Rect(0, 0, 400, 400));
2990
2991 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
2992
2993 const int32_t touchDeviceId = 4;
2994 // Pretend a test injects an ACTION_DOWN mouse event, but forgets to lift up the touch after
2995 // completion.
2996 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
2997 injectMotionEvent(*mDispatcher,
2998 MotionEventBuilder(ACTION_DOWN, AINPUT_SOURCE_MOUSE)
2999 .deviceId(ReservedInputDeviceId::VIRTUAL_KEYBOARD_ID)
3000 .pointer(PointerBuilder(0, ToolType::MOUSE).x(50).y(50))
3001 .build()));
3002 window->consumeMotionEvent(
3003 AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(VIRTUAL_KEYBOARD_ID)));
3004
3005 // Now a real touch comes. The injected pointer will remain, and the new gesture will also be
3006 // allowed through.
3007 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
3008 .deviceId(touchDeviceId)
3009 .pointer(PointerBuilder(0, ToolType::FINGER).x(300).y(100))
3010 .build());
3011 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(touchDeviceId)));
3012}
3013
3014/**
Siarhei Vishniakou6464e462023-02-06 18:57:59 -08003015 * This test is similar to the test above, but the sequence of injected events is different.
3016 *
3017 * Two windows: a window on the left and a window on the right.
3018 * Mouse is hovered over the left window.
3019 * Next, we tap on the left window, where the cursor was last seen.
3020 *
3021 * After that, we inject one finger down onto the right window, and then a second finger down onto
3022 * the left window.
3023 * The touch is split, so this last gesture should cause 2 ACTION_DOWN events, one in the right
3024 * window (first), and then another on the left window (second).
3025 * This test reproduces a crash where there is a mismatch between the downTime and eventTime.
3026 * In the buggy implementation, second finger down on the left window would cause a crash.
3027 */
Siarhei Vishniakoued89cbb2023-10-13 10:42:44 -07003028TEST_F(InputDispatcherMultiDeviceTest, HoverTapAndSplitTouch_legacy) {
3029 SCOPED_FLAG_OVERRIDE(enable_multi_device_same_window_stream, false);
Siarhei Vishniakou6464e462023-02-06 18:57:59 -08003030 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
3031 sp<FakeWindowHandle> leftWindow =
3032 sp<FakeWindowHandle>::make(application, mDispatcher, "Left", ADISPLAY_ID_DEFAULT);
3033 leftWindow->setFrame(Rect(0, 0, 200, 200));
3034
3035 sp<FakeWindowHandle> rightWindow =
3036 sp<FakeWindowHandle>::make(application, mDispatcher, "Right", ADISPLAY_ID_DEFAULT);
3037 rightWindow->setFrame(Rect(200, 0, 400, 200));
3038
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07003039 mDispatcher->onWindowInfosChanged(
3040 {{*leftWindow->getInfo(), *rightWindow->getInfo()}, {}, 0, 0});
Siarhei Vishniakou6464e462023-02-06 18:57:59 -08003041
3042 const int32_t mouseDeviceId = 6;
3043 const int32_t touchDeviceId = 4;
3044 // Hover over the left window. Keep the cursor there.
3045 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07003046 injectMotionEvent(*mDispatcher,
Siarhei Vishniakou6464e462023-02-06 18:57:59 -08003047 MotionEventBuilder(AMOTION_EVENT_ACTION_HOVER_ENTER,
3048 AINPUT_SOURCE_MOUSE)
3049 .deviceId(mouseDeviceId)
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07003050 .pointer(PointerBuilder(0, ToolType::MOUSE).x(50).y(50))
Siarhei Vishniakou6464e462023-02-06 18:57:59 -08003051 .build()));
3052 leftWindow->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_ENTER));
3053
3054 // Tap on left window
3055 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07003056 injectMotionEvent(*mDispatcher,
Siarhei Vishniakou6464e462023-02-06 18:57:59 -08003057 MotionEventBuilder(AMOTION_EVENT_ACTION_DOWN,
3058 AINPUT_SOURCE_TOUCHSCREEN)
3059 .deviceId(touchDeviceId)
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07003060 .pointer(PointerBuilder(0, ToolType::FINGER).x(100).y(100))
Siarhei Vishniakou6464e462023-02-06 18:57:59 -08003061 .build()));
3062
3063 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07003064 injectMotionEvent(*mDispatcher,
Siarhei Vishniakou6464e462023-02-06 18:57:59 -08003065 MotionEventBuilder(AMOTION_EVENT_ACTION_UP,
3066 AINPUT_SOURCE_TOUCHSCREEN)
3067 .deviceId(touchDeviceId)
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07003068 .pointer(PointerBuilder(0, ToolType::FINGER).x(100).y(100))
Siarhei Vishniakou6464e462023-02-06 18:57:59 -08003069 .build()));
3070 leftWindow->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_EXIT));
3071 leftWindow->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_DOWN));
3072 leftWindow->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_UP));
3073
3074 // First finger down on right window
3075 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07003076 injectMotionEvent(*mDispatcher,
Siarhei Vishniakou6464e462023-02-06 18:57:59 -08003077 MotionEventBuilder(AMOTION_EVENT_ACTION_DOWN,
3078 AINPUT_SOURCE_TOUCHSCREEN)
3079 .deviceId(touchDeviceId)
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07003080 .pointer(PointerBuilder(0, ToolType::FINGER).x(300).y(100))
Siarhei Vishniakou6464e462023-02-06 18:57:59 -08003081 .build()));
3082 rightWindow->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_DOWN));
3083
3084 // Second finger down on the left window
3085 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07003086 injectMotionEvent(*mDispatcher,
Siarhei Vishniakou6464e462023-02-06 18:57:59 -08003087 MotionEventBuilder(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
3088 .deviceId(touchDeviceId)
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07003089 .pointer(PointerBuilder(0, ToolType::FINGER).x(300).y(100))
3090 .pointer(PointerBuilder(1, ToolType::FINGER).x(100).y(100))
Siarhei Vishniakou6464e462023-02-06 18:57:59 -08003091 .build()));
3092 leftWindow->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_DOWN));
3093 rightWindow->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_MOVE));
3094
3095 // No more events
3096 leftWindow->assertNoEvents();
3097 rightWindow->assertNoEvents();
3098}
3099
3100/**
Siarhei Vishniakoued89cbb2023-10-13 10:42:44 -07003101 * This test is similar to the test above, but the sequence of injected events is different.
3102 *
3103 * Two windows: a window on the left and a window on the right.
3104 * Mouse is hovered over the left window.
3105 * Next, we tap on the left window, where the cursor was last seen.
3106 *
3107 * After that, we send one finger down onto the right window, and then a second finger down onto
3108 * the left window.
3109 * The touch is split, so this last gesture should cause 2 ACTION_DOWN events, one in the right
3110 * window (first), and then another on the left window (second).
3111 * This test reproduces a crash where there is a mismatch between the downTime and eventTime.
3112 * In the buggy implementation, second finger down on the left window would cause a crash.
3113 */
3114TEST_F(InputDispatcherMultiDeviceTest, HoverTapAndSplitTouch) {
3115 SCOPED_FLAG_OVERRIDE(enable_multi_device_same_window_stream, true);
3116 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
3117 sp<FakeWindowHandle> leftWindow =
3118 sp<FakeWindowHandle>::make(application, mDispatcher, "Left", ADISPLAY_ID_DEFAULT);
3119 leftWindow->setFrame(Rect(0, 0, 200, 200));
3120
3121 sp<FakeWindowHandle> rightWindow =
3122 sp<FakeWindowHandle>::make(application, mDispatcher, "Right", ADISPLAY_ID_DEFAULT);
3123 rightWindow->setFrame(Rect(200, 0, 400, 200));
3124
3125 mDispatcher->onWindowInfosChanged(
3126 {{*leftWindow->getInfo(), *rightWindow->getInfo()}, {}, 0, 0});
3127
3128 const int32_t mouseDeviceId = 6;
3129 const int32_t touchDeviceId = 4;
3130 // Hover over the left window. Keep the cursor there.
3131 mDispatcher->notifyMotion(
3132 MotionArgsBuilder(AMOTION_EVENT_ACTION_HOVER_ENTER, AINPUT_SOURCE_MOUSE)
3133 .deviceId(mouseDeviceId)
3134 .pointer(PointerBuilder(0, ToolType::MOUSE).x(50).y(50))
3135 .build());
3136 leftWindow->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_ENTER));
3137
3138 // Tap on left window
3139 mDispatcher->notifyMotion(
3140 MotionArgsBuilder(AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
3141 .deviceId(touchDeviceId)
3142 .pointer(PointerBuilder(0, ToolType::FINGER).x(100).y(100))
3143 .build());
3144
3145 mDispatcher->notifyMotion(MotionArgsBuilder(AMOTION_EVENT_ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN)
3146 .deviceId(touchDeviceId)
3147 .pointer(PointerBuilder(0, ToolType::FINGER).x(100).y(100))
3148 .build());
3149 leftWindow->consumeMotionEvent(
3150 AllOf(WithMotionAction(AMOTION_EVENT_ACTION_DOWN), WithDeviceId(touchDeviceId)));
3151 leftWindow->consumeMotionEvent(
3152 AllOf(WithMotionAction(AMOTION_EVENT_ACTION_UP), WithDeviceId(touchDeviceId)));
3153
3154 // First finger down on right window
3155 mDispatcher->notifyMotion(
3156 MotionArgsBuilder(AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
3157 .deviceId(touchDeviceId)
3158 .pointer(PointerBuilder(0, ToolType::FINGER).x(300).y(100))
3159 .build());
3160 rightWindow->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_DOWN));
3161
3162 // Second finger down on the left window
3163 mDispatcher->notifyMotion(MotionArgsBuilder(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
3164 .deviceId(touchDeviceId)
3165 .pointer(PointerBuilder(0, ToolType::FINGER).x(300).y(100))
3166 .pointer(PointerBuilder(1, ToolType::FINGER).x(100).y(100))
3167 .build());
3168 leftWindow->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_DOWN));
3169 rightWindow->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_MOVE));
3170
3171 // No more events
3172 leftWindow->assertNoEvents();
3173 rightWindow->assertNoEvents();
3174}
3175
3176/**
Siarhei Vishniakou2e3e4432023-02-09 18:34:11 -08003177 * Start hovering with a stylus device, and then tap with a touch device. Ensure no crash occurs.
3178 * While the touch is down, new hover events from the stylus device should be ignored. After the
3179 * touch is gone, stylus hovering should start working again.
3180 */
Siarhei Vishniakou3ad54f52023-11-02 16:54:40 -07003181TEST_F(InputDispatcherMultiDeviceTest, StylusHoverIgnoresTouchTap) {
Siarhei Vishniakoued89cbb2023-10-13 10:42:44 -07003182 SCOPED_FLAG_OVERRIDE(enable_multi_device_same_window_stream, false);
Siarhei Vishniakou2e3e4432023-02-09 18:34:11 -08003183 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
3184 sp<FakeWindowHandle> window =
3185 sp<FakeWindowHandle>::make(application, mDispatcher, "Window", ADISPLAY_ID_DEFAULT);
3186 window->setFrame(Rect(0, 0, 200, 200));
3187
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07003188 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Siarhei Vishniakou2e3e4432023-02-09 18:34:11 -08003189
3190 const int32_t stylusDeviceId = 5;
3191 const int32_t touchDeviceId = 4;
3192 // Start hovering with stylus
3193 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07003194 injectMotionEvent(*mDispatcher,
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -07003195 MotionEventBuilder(ACTION_HOVER_ENTER, AINPUT_SOURCE_STYLUS)
Siarhei Vishniakou2e3e4432023-02-09 18:34:11 -08003196 .deviceId(stylusDeviceId)
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07003197 .pointer(PointerBuilder(0, ToolType::STYLUS).x(50).y(50))
Siarhei Vishniakou2e3e4432023-02-09 18:34:11 -08003198 .build()));
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -07003199 window->consumeMotionEvent(WithMotionAction(ACTION_HOVER_ENTER));
Siarhei Vishniakou2e3e4432023-02-09 18:34:11 -08003200
3201 // Finger down on the window
3202 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07003203 injectMotionEvent(*mDispatcher,
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -07003204 MotionEventBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
Siarhei Vishniakou2e3e4432023-02-09 18:34:11 -08003205 .deviceId(touchDeviceId)
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07003206 .pointer(PointerBuilder(0, ToolType::FINGER).x(100).y(100))
Siarhei Vishniakou2e3e4432023-02-09 18:34:11 -08003207 .build()));
Siarhei Vishniakou3ad54f52023-11-02 16:54:40 -07003208 // The touch device should be ignored!
Siarhei Vishniakou2e3e4432023-02-09 18:34:11 -08003209
Siarhei Vishniakou2899c552023-07-10 18:20:46 -07003210 // Continue hovering with stylus.
3211 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07003212 injectMotionEvent(*mDispatcher,
Siarhei Vishniakou2e3e4432023-02-09 18:34:11 -08003213 MotionEventBuilder(AMOTION_EVENT_ACTION_HOVER_MOVE,
3214 AINPUT_SOURCE_STYLUS)
3215 .deviceId(stylusDeviceId)
Siarhei Vishniakou25537f82023-07-18 14:35:47 -07003216 .pointer(PointerBuilder(0, ToolType::STYLUS).x(60).y(60))
Siarhei Vishniakou2e3e4432023-02-09 18:34:11 -08003217 .build()));
Siarhei Vishniakou3ad54f52023-11-02 16:54:40 -07003218 // Hovers continue to work
3219 window->consumeMotionEvent(
3220 AllOf(WithMotionAction(ACTION_HOVER_MOVE), WithDeviceId(stylusDeviceId)));
Siarhei Vishniakou2e3e4432023-02-09 18:34:11 -08003221
3222 // Lift up the finger
3223 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07003224 injectMotionEvent(*mDispatcher,
Siarhei Vishniakou2e3e4432023-02-09 18:34:11 -08003225 MotionEventBuilder(AMOTION_EVENT_ACTION_UP,
3226 AINPUT_SOURCE_TOUCHSCREEN)
3227 .deviceId(touchDeviceId)
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07003228 .pointer(PointerBuilder(0, ToolType::FINGER).x(100).y(100))
Siarhei Vishniakou2e3e4432023-02-09 18:34:11 -08003229 .build()));
Siarhei Vishniakou2e3e4432023-02-09 18:34:11 -08003230
Siarhei Vishniakou2e3e4432023-02-09 18:34:11 -08003231 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07003232 injectMotionEvent(*mDispatcher,
Siarhei Vishniakou2e3e4432023-02-09 18:34:11 -08003233 MotionEventBuilder(AMOTION_EVENT_ACTION_HOVER_MOVE,
3234 AINPUT_SOURCE_STYLUS)
3235 .deviceId(stylusDeviceId)
Siarhei Vishniakou25537f82023-07-18 14:35:47 -07003236 .pointer(PointerBuilder(0, ToolType::STYLUS).x(70).y(70))
Siarhei Vishniakou2e3e4432023-02-09 18:34:11 -08003237 .build()));
Siarhei Vishniakou3ad54f52023-11-02 16:54:40 -07003238 window->consumeMotionEvent(
3239 AllOf(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_MOVE), WithDeviceId(stylusDeviceId)));
Siarhei Vishniakou2e3e4432023-02-09 18:34:11 -08003240 window->assertNoEvents();
3241}
3242
3243/**
Siarhei Vishniakoued89cbb2023-10-13 10:42:44 -07003244 * Start hovering with a stylus device, and then tap with a touch device. Ensure no crash occurs.
3245 * While the touch is down, hovering from the stylus is not affected. After the touch is gone,
3246 * check that the stylus hovering continues to work.
3247 */
3248TEST_F(InputDispatcherMultiDeviceTest, StylusHoverWithTouchTap) {
3249 SCOPED_FLAG_OVERRIDE(enable_multi_device_same_window_stream, true);
3250 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
3251 sp<FakeWindowHandle> window =
3252 sp<FakeWindowHandle>::make(application, mDispatcher, "Window", ADISPLAY_ID_DEFAULT);
3253 window->setFrame(Rect(0, 0, 200, 200));
3254
3255 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
3256
3257 const int32_t stylusDeviceId = 5;
3258 const int32_t touchDeviceId = 4;
3259 // Start hovering with stylus
3260 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_ENTER, AINPUT_SOURCE_STYLUS)
3261 .deviceId(stylusDeviceId)
3262 .pointer(PointerBuilder(0, ToolType::STYLUS).x(50).y(50))
3263 .build());
3264 window->consumeMotionEvent(WithMotionAction(ACTION_HOVER_ENTER));
3265
3266 // Finger down on the window
3267 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
3268 .deviceId(touchDeviceId)
3269 .pointer(PointerBuilder(0, ToolType::FINGER).x(100).y(100))
3270 .build());
3271 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(touchDeviceId)));
3272
3273 // Continue hovering with stylus.
3274 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_MOVE, AINPUT_SOURCE_STYLUS)
3275 .deviceId(stylusDeviceId)
3276 .pointer(PointerBuilder(0, ToolType::STYLUS).x(60).y(60))
3277 .build());
3278 // Hovers continue to work
3279 window->consumeMotionEvent(
3280 AllOf(WithMotionAction(ACTION_HOVER_MOVE), WithDeviceId(stylusDeviceId)));
3281
3282 // Lift up the finger
3283 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN)
3284 .deviceId(touchDeviceId)
3285 .pointer(PointerBuilder(0, ToolType::FINGER).x(100).y(100))
3286 .build());
3287 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_UP), WithDeviceId(touchDeviceId)));
3288
3289 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_MOVE, AINPUT_SOURCE_STYLUS)
3290 .deviceId(stylusDeviceId)
3291 .pointer(PointerBuilder(0, ToolType::STYLUS).x(70).y(70))
3292 .build());
3293 window->consumeMotionEvent(
3294 AllOf(WithMotionAction(ACTION_HOVER_MOVE), WithDeviceId(stylusDeviceId)));
3295 window->assertNoEvents();
3296}
3297
3298/**
Siarhei Vishniakouf77f60a2023-10-23 17:26:05 -07003299 * If stylus is down anywhere on the screen, then touches should not be delivered to windows that
3300 * have InputConfig::GLOBAL_STYLUS_BLOCKS_TOUCH.
3301 *
3302 * Two windows: one on the left and one on the right.
3303 * The window on the right has GLOBAL_STYLUS_BLOCKS_TOUCH config.
3304 * Stylus down on the left window, and then touch down on the right window.
3305 * Check that the right window doesn't get touches while the stylus is down on the left window.
3306 */
3307TEST_F(InputDispatcherMultiDeviceTest, GlobalStylusDownBlocksTouch) {
3308 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
3309 sp<FakeWindowHandle> leftWindow =
3310 sp<FakeWindowHandle>::make(application, mDispatcher, "Left window",
3311 ADISPLAY_ID_DEFAULT);
3312 leftWindow->setFrame(Rect(0, 0, 100, 100));
3313
3314 sp<FakeWindowHandle> sbtRightWindow =
3315 sp<FakeWindowHandle>::make(application, mDispatcher,
3316 "Stylus blocks touch (right) window", ADISPLAY_ID_DEFAULT);
3317 sbtRightWindow->setFrame(Rect(100, 100, 200, 200));
3318 sbtRightWindow->setGlobalStylusBlocksTouch(true);
3319
3320 mDispatcher->onWindowInfosChanged(
3321 {{*leftWindow->getInfo(), *sbtRightWindow->getInfo()}, {}, 0, 0});
3322
3323 const int32_t stylusDeviceId = 5;
3324 const int32_t touchDeviceId = 4;
3325
3326 // Stylus down in the left window
3327 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_STYLUS)
3328 .pointer(PointerBuilder(0, ToolType::STYLUS).x(50).y(52))
3329 .deviceId(stylusDeviceId)
3330 .build());
3331 leftWindow->consumeMotionEvent(
3332 AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(stylusDeviceId)));
3333
3334 // Finger tap on the right window
3335 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
3336 .pointer(PointerBuilder(0, ToolType::FINGER).x(150).y(151))
3337 .deviceId(touchDeviceId)
3338 .build());
3339 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN)
3340 .pointer(PointerBuilder(0, ToolType::FINGER).x(150).y(151))
3341 .deviceId(touchDeviceId)
3342 .build());
3343
3344 // The touch should be blocked, because stylus is down somewhere else on screen!
3345 sbtRightWindow->assertNoEvents();
3346
3347 // Continue stylus motion, and ensure it's not impacted.
3348 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_STYLUS)
3349 .pointer(PointerBuilder(0, ToolType::STYLUS).x(51).y(53))
3350 .deviceId(stylusDeviceId)
3351 .build());
3352 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_UP, AINPUT_SOURCE_STYLUS)
3353 .pointer(PointerBuilder(0, ToolType::STYLUS).x(51).y(53))
3354 .deviceId(stylusDeviceId)
3355 .build());
3356 leftWindow->consumeMotionEvent(
3357 AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(stylusDeviceId)));
3358 leftWindow->consumeMotionEvent(
3359 AllOf(WithMotionAction(ACTION_UP), WithDeviceId(stylusDeviceId)));
3360
3361 // Now that the stylus gesture is done, touches should be getting delivered correctly.
3362 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
3363 .pointer(PointerBuilder(0, ToolType::FINGER).x(151).y(153))
3364 .deviceId(touchDeviceId)
3365 .build());
3366 sbtRightWindow->consumeMotionEvent(
3367 AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(touchDeviceId)));
3368}
3369
3370/**
3371 * If stylus is hovering anywhere on the screen, then touches should not be delivered to windows
3372 * that have InputConfig::GLOBAL_STYLUS_BLOCKS_TOUCH.
3373 *
3374 * Two windows: one on the left and one on the right.
3375 * The window on the right has GLOBAL_STYLUS_BLOCKS_TOUCH config.
3376 * Stylus hover on the left window, and then touch down on the right window.
3377 * Check that the right window doesn't get touches while the stylus is hovering on the left window.
3378 */
3379TEST_F(InputDispatcherMultiDeviceTest, GlobalStylusHoverBlocksTouch) {
3380 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
3381 sp<FakeWindowHandle> leftWindow =
3382 sp<FakeWindowHandle>::make(application, mDispatcher, "Left window",
3383 ADISPLAY_ID_DEFAULT);
3384 leftWindow->setFrame(Rect(0, 0, 100, 100));
3385
3386 sp<FakeWindowHandle> sbtRightWindow =
3387 sp<FakeWindowHandle>::make(application, mDispatcher,
3388 "Stylus blocks touch (right) window", ADISPLAY_ID_DEFAULT);
3389 sbtRightWindow->setFrame(Rect(100, 100, 200, 200));
3390 sbtRightWindow->setGlobalStylusBlocksTouch(true);
3391
3392 mDispatcher->onWindowInfosChanged(
3393 {{*leftWindow->getInfo(), *sbtRightWindow->getInfo()}, {}, 0, 0});
3394
3395 const int32_t stylusDeviceId = 5;
3396 const int32_t touchDeviceId = 4;
3397
3398 // Stylus hover in the left window
3399 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_ENTER, AINPUT_SOURCE_STYLUS)
3400 .pointer(PointerBuilder(0, ToolType::STYLUS).x(50).y(52))
3401 .deviceId(stylusDeviceId)
3402 .build());
3403 leftWindow->consumeMotionEvent(
3404 AllOf(WithMotionAction(ACTION_HOVER_ENTER), WithDeviceId(stylusDeviceId)));
3405
3406 // Finger tap on the right window
3407 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
3408 .pointer(PointerBuilder(0, ToolType::FINGER).x(150).y(151))
3409 .deviceId(touchDeviceId)
3410 .build());
3411 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN)
3412 .pointer(PointerBuilder(0, ToolType::FINGER).x(150).y(151))
3413 .deviceId(touchDeviceId)
3414 .build());
3415
3416 // The touch should be blocked, because stylus is hovering somewhere else on screen!
3417 sbtRightWindow->assertNoEvents();
3418
3419 // Continue stylus motion, and ensure it's not impacted.
3420 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_MOVE, AINPUT_SOURCE_STYLUS)
3421 .pointer(PointerBuilder(0, ToolType::STYLUS).x(51).y(53))
3422 .deviceId(stylusDeviceId)
3423 .build());
3424 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_EXIT, AINPUT_SOURCE_STYLUS)
3425 .pointer(PointerBuilder(0, ToolType::STYLUS).x(51).y(53))
3426 .deviceId(stylusDeviceId)
3427 .build());
3428 leftWindow->consumeMotionEvent(
3429 AllOf(WithMotionAction(ACTION_HOVER_MOVE), WithDeviceId(stylusDeviceId)));
3430 leftWindow->consumeMotionEvent(
3431 AllOf(WithMotionAction(ACTION_HOVER_EXIT), WithDeviceId(stylusDeviceId)));
3432
3433 // Now that the stylus gesture is done, touches should be getting delivered correctly.
3434 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
3435 .pointer(PointerBuilder(0, ToolType::FINGER).x(151).y(153))
3436 .deviceId(touchDeviceId)
3437 .build());
3438 sbtRightWindow->consumeMotionEvent(
3439 AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(touchDeviceId)));
3440}
3441
3442/**
Siarhei Vishniakouf372b812023-02-14 18:06:51 -08003443 * A spy window above a window with no input channel.
3444 * Start hovering with a stylus device, and then tap with it.
3445 * Ensure spy window receives the entire sequence.
3446 */
3447TEST_F(InputDispatcherTest, StylusHoverAndDownNoInputChannel) {
3448 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
3449 sp<FakeWindowHandle> spyWindow =
3450 sp<FakeWindowHandle>::make(application, mDispatcher, "Spy", ADISPLAY_ID_DEFAULT);
3451 spyWindow->setFrame(Rect(0, 0, 200, 200));
3452 spyWindow->setTrustedOverlay(true);
3453 spyWindow->setSpy(true);
3454 sp<FakeWindowHandle> window =
3455 sp<FakeWindowHandle>::make(application, mDispatcher, "Window", ADISPLAY_ID_DEFAULT);
3456 window->setNoInputChannel(true);
3457 window->setFrame(Rect(0, 0, 200, 200));
3458
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07003459 mDispatcher->onWindowInfosChanged({{*spyWindow->getInfo(), *window->getInfo()}, {}, 0, 0});
Siarhei Vishniakouf372b812023-02-14 18:06:51 -08003460
Siarhei Vishniakouf372b812023-02-14 18:06:51 -08003461 // Start hovering with stylus
Prabir Pradhan678438e2023-04-13 19:32:51 +00003462 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_ENTER, AINPUT_SOURCE_STYLUS)
3463 .pointer(PointerBuilder(0, ToolType::STYLUS).x(50).y(50))
3464 .build());
Siarhei Vishniakouf372b812023-02-14 18:06:51 -08003465 spyWindow->consumeMotionEvent(WithMotionAction(ACTION_HOVER_ENTER));
3466 // Stop hovering
Prabir Pradhan678438e2023-04-13 19:32:51 +00003467 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_EXIT, AINPUT_SOURCE_STYLUS)
3468 .pointer(PointerBuilder(0, ToolType::STYLUS).x(50).y(50))
3469 .build());
Siarhei Vishniakouf372b812023-02-14 18:06:51 -08003470 spyWindow->consumeMotionEvent(WithMotionAction(ACTION_HOVER_EXIT));
3471
3472 // Stylus touches down
Prabir Pradhan678438e2023-04-13 19:32:51 +00003473 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_STYLUS)
3474 .pointer(PointerBuilder(0, ToolType::STYLUS).x(50).y(50))
3475 .build());
Siarhei Vishniakouf372b812023-02-14 18:06:51 -08003476 spyWindow->consumeMotionEvent(WithMotionAction(ACTION_DOWN));
3477
3478 // Stylus goes up
Prabir Pradhan678438e2023-04-13 19:32:51 +00003479 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_UP, AINPUT_SOURCE_STYLUS)
3480 .pointer(PointerBuilder(0, ToolType::STYLUS).x(50).y(50))
3481 .build());
Siarhei Vishniakouf372b812023-02-14 18:06:51 -08003482 spyWindow->consumeMotionEvent(WithMotionAction(ACTION_UP));
3483
3484 // Again hover
Prabir Pradhan678438e2023-04-13 19:32:51 +00003485 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_ENTER, AINPUT_SOURCE_STYLUS)
3486 .pointer(PointerBuilder(0, ToolType::STYLUS).x(50).y(50))
3487 .build());
Siarhei Vishniakouf372b812023-02-14 18:06:51 -08003488 spyWindow->consumeMotionEvent(WithMotionAction(ACTION_HOVER_ENTER));
3489 // Stop hovering
Prabir Pradhan678438e2023-04-13 19:32:51 +00003490 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_EXIT, AINPUT_SOURCE_STYLUS)
3491 .pointer(PointerBuilder(0, ToolType::STYLUS).x(50).y(50))
3492 .build());
Siarhei Vishniakouf372b812023-02-14 18:06:51 -08003493 spyWindow->consumeMotionEvent(WithMotionAction(ACTION_HOVER_EXIT));
3494
3495 // No more events
3496 spyWindow->assertNoEvents();
3497 window->assertNoEvents();
3498}
3499
3500/**
Siarhei Vishniakou6b71b632023-10-27 21:34:46 -07003501 * A stale stylus HOVER_EXIT event is injected. Since it's a stale event, it should generally be
3502 * rejected. But since we already have an ongoing gesture, this event should be processed.
3503 * This prevents inconsistent events being handled inside the dispatcher.
3504 */
3505TEST_F(InputDispatcherTest, StaleStylusHoverGestureIsComplete) {
3506 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
3507
3508 sp<FakeWindowHandle> window =
3509 sp<FakeWindowHandle>::make(application, mDispatcher, "Window", ADISPLAY_ID_DEFAULT);
3510 window->setFrame(Rect(0, 0, 200, 200));
3511
3512 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
3513
3514 // Start hovering with stylus
3515 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_ENTER, AINPUT_SOURCE_STYLUS)
3516 .pointer(PointerBuilder(0, ToolType::STYLUS).x(50).y(50))
3517 .build());
3518 window->consumeMotionEvent(WithMotionAction(ACTION_HOVER_ENTER));
3519
3520 NotifyMotionArgs hoverExit = MotionArgsBuilder(ACTION_HOVER_EXIT, AINPUT_SOURCE_STYLUS)
3521 .pointer(PointerBuilder(0, ToolType::STYLUS).x(50).y(50))
3522 .build();
3523 // Make this 'hoverExit' event stale
3524 mFakePolicy->setStaleEventTimeout(100ms);
3525 std::this_thread::sleep_for(100ms);
3526
3527 // It shouldn't be dropped by the dispatcher, even though it's stale.
3528 mDispatcher->notifyMotion(hoverExit);
3529 window->consumeMotionEvent(WithMotionAction(ACTION_HOVER_EXIT));
3530
3531 // Stylus starts hovering again! There should be no crash.
3532 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_ENTER, AINPUT_SOURCE_STYLUS)
3533 .pointer(PointerBuilder(0, ToolType::STYLUS).x(51).y(51))
3534 .build());
3535 window->consumeMotionEvent(WithMotionAction(ACTION_HOVER_ENTER));
3536}
3537
3538/**
Siarhei Vishniakouf372b812023-02-14 18:06:51 -08003539 * Start hovering with a mouse, and then tap with a touch device. Pilfer the touch stream.
3540 * Next, click with the mouse device. Both windows (spy and regular) should receive the new mouse
3541 * ACTION_DOWN event because that's a new gesture, and pilfering should no longer be active.
3542 * While the mouse is down, new move events from the touch device should be ignored.
3543 */
Siarhei Vishniakoued89cbb2023-10-13 10:42:44 -07003544TEST_F(InputDispatcherTest, TouchPilferAndMouseMove_legacy) {
3545 SCOPED_FLAG_OVERRIDE(enable_multi_device_same_window_stream, false);
Siarhei Vishniakouf372b812023-02-14 18:06:51 -08003546 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
3547 sp<FakeWindowHandle> spyWindow =
3548 sp<FakeWindowHandle>::make(application, mDispatcher, "Spy", ADISPLAY_ID_DEFAULT);
3549 spyWindow->setFrame(Rect(0, 0, 200, 200));
3550 spyWindow->setTrustedOverlay(true);
3551 spyWindow->setSpy(true);
3552 sp<FakeWindowHandle> window =
3553 sp<FakeWindowHandle>::make(application, mDispatcher, "Window", ADISPLAY_ID_DEFAULT);
3554 window->setFrame(Rect(0, 0, 200, 200));
3555
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07003556 mDispatcher->onWindowInfosChanged({{*spyWindow->getInfo(), *window->getInfo()}, {}, 0, 0});
Siarhei Vishniakouf372b812023-02-14 18:06:51 -08003557
3558 const int32_t mouseDeviceId = 7;
3559 const int32_t touchDeviceId = 4;
Siarhei Vishniakouf372b812023-02-14 18:06:51 -08003560
3561 // Hover a bit with mouse first
Prabir Pradhan678438e2023-04-13 19:32:51 +00003562 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_ENTER, AINPUT_SOURCE_MOUSE)
3563 .deviceId(mouseDeviceId)
3564 .pointer(PointerBuilder(0, ToolType::MOUSE).x(100).y(100))
3565 .build());
Siarhei Vishniakouf372b812023-02-14 18:06:51 -08003566 spyWindow->consumeMotionEvent(
3567 AllOf(WithMotionAction(ACTION_HOVER_ENTER), WithDeviceId(mouseDeviceId)));
3568 window->consumeMotionEvent(
3569 AllOf(WithMotionAction(ACTION_HOVER_ENTER), WithDeviceId(mouseDeviceId)));
3570
3571 // Start touching
Prabir Pradhan678438e2023-04-13 19:32:51 +00003572 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
3573 .deviceId(touchDeviceId)
3574 .pointer(PointerBuilder(0, ToolType::FINGER).x(50).y(50))
3575 .build());
Siarhei Vishniakouf372b812023-02-14 18:06:51 -08003576 spyWindow->consumeMotionEvent(WithMotionAction(ACTION_HOVER_EXIT));
3577 window->consumeMotionEvent(WithMotionAction(ACTION_HOVER_EXIT));
3578 spyWindow->consumeMotionEvent(WithMotionAction(ACTION_DOWN));
3579 window->consumeMotionEvent(WithMotionAction(ACTION_DOWN));
3580
Prabir Pradhan678438e2023-04-13 19:32:51 +00003581 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN)
3582 .deviceId(touchDeviceId)
3583 .pointer(PointerBuilder(0, ToolType::FINGER).x(55).y(55))
3584 .build());
Siarhei Vishniakouf372b812023-02-14 18:06:51 -08003585 spyWindow->consumeMotionEvent(WithMotionAction(ACTION_MOVE));
3586 window->consumeMotionEvent(WithMotionAction(ACTION_MOVE));
3587
3588 // Pilfer the stream
3589 EXPECT_EQ(OK, mDispatcher->pilferPointers(spyWindow->getToken()));
3590 window->consumeMotionEvent(WithMotionAction(ACTION_CANCEL));
3591
Prabir Pradhan678438e2023-04-13 19:32:51 +00003592 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN)
3593 .deviceId(touchDeviceId)
3594 .pointer(PointerBuilder(0, ToolType::FINGER).x(60).y(60))
3595 .build());
Siarhei Vishniakouf372b812023-02-14 18:06:51 -08003596 spyWindow->consumeMotionEvent(WithMotionAction(ACTION_MOVE));
3597
3598 // Mouse down
Prabir Pradhan678438e2023-04-13 19:32:51 +00003599 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_MOUSE)
3600 .deviceId(mouseDeviceId)
3601 .buttonState(AMOTION_EVENT_BUTTON_PRIMARY)
3602 .pointer(PointerBuilder(0, ToolType::MOUSE).x(100).y(100))
3603 .build());
Siarhei Vishniakouf372b812023-02-14 18:06:51 -08003604
3605 spyWindow->consumeMotionEvent(
3606 AllOf(WithMotionAction(ACTION_CANCEL), WithDeviceId(touchDeviceId)));
3607 spyWindow->consumeMotionEvent(
3608 AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(mouseDeviceId)));
3609 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(mouseDeviceId)));
3610
Prabir Pradhan678438e2023-04-13 19:32:51 +00003611 mDispatcher->notifyMotion(
3612 MotionArgsBuilder(AMOTION_EVENT_ACTION_BUTTON_PRESS, AINPUT_SOURCE_MOUSE)
3613 .deviceId(mouseDeviceId)
3614 .buttonState(AMOTION_EVENT_BUTTON_PRIMARY)
3615 .actionButton(AMOTION_EVENT_BUTTON_PRIMARY)
3616 .pointer(PointerBuilder(0, ToolType::MOUSE).x(100).y(100))
3617 .build());
Siarhei Vishniakouf372b812023-02-14 18:06:51 -08003618 spyWindow->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_BUTTON_PRESS));
3619 window->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_BUTTON_PRESS));
3620
3621 // Mouse move!
Prabir Pradhan678438e2023-04-13 19:32:51 +00003622 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_MOUSE)
3623 .deviceId(mouseDeviceId)
3624 .buttonState(AMOTION_EVENT_BUTTON_PRIMARY)
3625 .pointer(PointerBuilder(0, ToolType::MOUSE).x(110).y(110))
3626 .build());
Siarhei Vishniakouf372b812023-02-14 18:06:51 -08003627 spyWindow->consumeMotionEvent(WithMotionAction(ACTION_MOVE));
3628 window->consumeMotionEvent(WithMotionAction(ACTION_MOVE));
3629
3630 // Touch move!
Prabir Pradhan678438e2023-04-13 19:32:51 +00003631 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN)
3632 .deviceId(touchDeviceId)
3633 .pointer(PointerBuilder(0, ToolType::FINGER).x(65).y(65))
3634 .build());
Siarhei Vishniakouf372b812023-02-14 18:06:51 -08003635
3636 // No more events
3637 spyWindow->assertNoEvents();
3638 window->assertNoEvents();
3639}
3640
3641/**
Siarhei Vishniakoued89cbb2023-10-13 10:42:44 -07003642 * Start hovering with a mouse, and then tap with a touch device. Pilfer the touch stream.
3643 * Next, click with the mouse device. Both windows (spy and regular) should receive the new mouse
3644 * ACTION_DOWN event because that's a new gesture, and pilfering should no longer be active.
3645 * While the mouse is down, new move events from the touch device should continue to work.
3646 */
3647TEST_F(InputDispatcherTest, TouchPilferAndMouseMove) {
3648 SCOPED_FLAG_OVERRIDE(enable_multi_device_same_window_stream, true);
3649 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
3650 sp<FakeWindowHandle> spyWindow =
3651 sp<FakeWindowHandle>::make(application, mDispatcher, "Spy", ADISPLAY_ID_DEFAULT);
3652 spyWindow->setFrame(Rect(0, 0, 200, 200));
3653 spyWindow->setTrustedOverlay(true);
3654 spyWindow->setSpy(true);
3655 sp<FakeWindowHandle> window =
3656 sp<FakeWindowHandle>::make(application, mDispatcher, "Window", ADISPLAY_ID_DEFAULT);
3657 window->setFrame(Rect(0, 0, 200, 200));
3658
3659 mDispatcher->onWindowInfosChanged({{*spyWindow->getInfo(), *window->getInfo()}, {}, 0, 0});
3660
3661 const int32_t mouseDeviceId = 7;
3662 const int32_t touchDeviceId = 4;
3663
3664 // Hover a bit with mouse first
3665 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_ENTER, AINPUT_SOURCE_MOUSE)
3666 .deviceId(mouseDeviceId)
3667 .pointer(PointerBuilder(0, ToolType::MOUSE).x(100).y(100))
3668 .build());
3669 spyWindow->consumeMotionEvent(
3670 AllOf(WithMotionAction(ACTION_HOVER_ENTER), WithDeviceId(mouseDeviceId)));
3671 window->consumeMotionEvent(
3672 AllOf(WithMotionAction(ACTION_HOVER_ENTER), WithDeviceId(mouseDeviceId)));
3673
3674 // Start touching
3675 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
3676 .deviceId(touchDeviceId)
3677 .pointer(PointerBuilder(0, ToolType::FINGER).x(50).y(50))
3678 .build());
3679
3680 spyWindow->consumeMotionEvent(WithMotionAction(ACTION_DOWN));
3681 window->consumeMotionEvent(WithMotionAction(ACTION_DOWN));
3682
3683 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN)
3684 .deviceId(touchDeviceId)
3685 .pointer(PointerBuilder(0, ToolType::FINGER).x(55).y(55))
3686 .build());
3687 spyWindow->consumeMotionEvent(WithMotionAction(ACTION_MOVE));
3688 window->consumeMotionEvent(WithMotionAction(ACTION_MOVE));
3689
3690 // Pilfer the stream
3691 EXPECT_EQ(OK, mDispatcher->pilferPointers(spyWindow->getToken()));
3692 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_CANCEL), WithDeviceId(touchDeviceId)));
3693 // Hover is not pilfered! Only touch.
3694
3695 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN)
3696 .deviceId(touchDeviceId)
3697 .pointer(PointerBuilder(0, ToolType::FINGER).x(60).y(60))
3698 .build());
3699 spyWindow->consumeMotionEvent(WithMotionAction(ACTION_MOVE));
3700
3701 // Mouse down
3702 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_MOUSE)
3703 .deviceId(mouseDeviceId)
3704 .buttonState(AMOTION_EVENT_BUTTON_PRIMARY)
3705 .pointer(PointerBuilder(0, ToolType::MOUSE).x(100).y(100))
3706 .build());
3707
3708 spyWindow->consumeMotionEvent(
3709 AllOf(WithMotionAction(ACTION_HOVER_EXIT), WithDeviceId(mouseDeviceId)));
3710 spyWindow->consumeMotionEvent(
3711 AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(mouseDeviceId)));
3712 window->consumeMotionEvent(
3713 AllOf(WithMotionAction(ACTION_HOVER_EXIT), WithDeviceId(mouseDeviceId)));
3714 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(mouseDeviceId)));
3715
3716 mDispatcher->notifyMotion(
3717 MotionArgsBuilder(AMOTION_EVENT_ACTION_BUTTON_PRESS, AINPUT_SOURCE_MOUSE)
3718 .deviceId(mouseDeviceId)
3719 .buttonState(AMOTION_EVENT_BUTTON_PRIMARY)
3720 .actionButton(AMOTION_EVENT_BUTTON_PRIMARY)
3721 .pointer(PointerBuilder(0, ToolType::MOUSE).x(100).y(100))
3722 .build());
3723 spyWindow->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_BUTTON_PRESS));
3724 window->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_BUTTON_PRESS));
3725
3726 // Mouse move!
3727 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_MOUSE)
3728 .deviceId(mouseDeviceId)
3729 .buttonState(AMOTION_EVENT_BUTTON_PRIMARY)
3730 .pointer(PointerBuilder(0, ToolType::MOUSE).x(110).y(110))
3731 .build());
3732 spyWindow->consumeMotionEvent(
3733 AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(mouseDeviceId)));
3734 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(mouseDeviceId)));
3735
3736 // Touch move!
3737 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN)
3738 .deviceId(touchDeviceId)
3739 .pointer(PointerBuilder(0, ToolType::FINGER).x(65).y(65))
3740 .build());
3741 spyWindow->consumeMotionEvent(
3742 AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(touchDeviceId)));
3743
3744 // No more events
3745 spyWindow->assertNoEvents();
3746 window->assertNoEvents();
3747}
3748
3749/**
Siarhei Vishniakoua16e3a22022-03-02 15:26:40 -08003750 * On the display, have a single window, and also an area where there's no window.
3751 * First pointer touches the "no window" area of the screen. Second pointer touches the window.
3752 * Make sure that the window receives the second pointer, and first pointer is simply ignored.
3753 */
3754TEST_F(InputDispatcherTest, SplitWorksWhenEmptyAreaIsTouched) {
3755 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
3756 sp<FakeWindowHandle> window =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07003757 sp<FakeWindowHandle>::make(application, mDispatcher, "Window", DISPLAY_ID);
Siarhei Vishniakoua16e3a22022-03-02 15:26:40 -08003758
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07003759 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Siarhei Vishniakoua16e3a22022-03-02 15:26:40 -08003760
3761 // Touch down on the empty space
Prabir Pradhan678438e2023-04-13 19:32:51 +00003762 mDispatcher->notifyMotion(generateTouchArgs(AMOTION_EVENT_ACTION_DOWN, {{-1, -1}}));
Siarhei Vishniakoua16e3a22022-03-02 15:26:40 -08003763
3764 mDispatcher->waitForIdle();
3765 window->assertNoEvents();
3766
3767 // Now touch down on the window with another pointer
Prabir Pradhan678438e2023-04-13 19:32:51 +00003768 mDispatcher->notifyMotion(generateTouchArgs(POINTER_1_DOWN, {{-1, -1}, {10, 10}}));
Siarhei Vishniakoua16e3a22022-03-02 15:26:40 -08003769 mDispatcher->waitForIdle();
3770 window->consumeMotionDown();
3771}
3772
3773/**
3774 * Same test as above, but instead of touching the empty space, the first touch goes to
3775 * non-touchable window.
3776 */
3777TEST_F(InputDispatcherTest, SplitWorksWhenNonTouchableWindowIsTouched) {
3778 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
3779 sp<FakeWindowHandle> window1 =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07003780 sp<FakeWindowHandle>::make(application, mDispatcher, "Window1", DISPLAY_ID);
Siarhei Vishniakoua16e3a22022-03-02 15:26:40 -08003781 window1->setTouchableRegion(Region{{0, 0, 100, 100}});
3782 window1->setTouchable(false);
3783 sp<FakeWindowHandle> window2 =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07003784 sp<FakeWindowHandle>::make(application, mDispatcher, "Window2", DISPLAY_ID);
Siarhei Vishniakoua16e3a22022-03-02 15:26:40 -08003785 window2->setTouchableRegion(Region{{100, 0, 200, 100}});
3786
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07003787 mDispatcher->onWindowInfosChanged({{*window1->getInfo(), *window2->getInfo()}, {}, 0, 0});
Siarhei Vishniakoua16e3a22022-03-02 15:26:40 -08003788
Siarhei Vishniakoua16e3a22022-03-02 15:26:40 -08003789 // Touch down on the non-touchable window
Prabir Pradhan678438e2023-04-13 19:32:51 +00003790 mDispatcher->notifyMotion(generateTouchArgs(AMOTION_EVENT_ACTION_DOWN, {{50, 50}}));
Siarhei Vishniakoua16e3a22022-03-02 15:26:40 -08003791
3792 mDispatcher->waitForIdle();
3793 window1->assertNoEvents();
3794 window2->assertNoEvents();
3795
3796 // Now touch down on the window with another pointer
Prabir Pradhan678438e2023-04-13 19:32:51 +00003797 mDispatcher->notifyMotion(generateTouchArgs(POINTER_1_DOWN, {{50, 50}, {150, 50}}));
Siarhei Vishniakoua16e3a22022-03-02 15:26:40 -08003798 mDispatcher->waitForIdle();
3799 window2->consumeMotionDown();
3800}
3801
Vaibhav Devmurari882bd9b2022-06-23 14:54:54 +00003802/**
3803 * When splitting touch events the downTime should be adjusted such that the downTime corresponds
3804 * to the event time of the first ACTION_DOWN sent to the particular window.
3805 */
3806TEST_F(InputDispatcherTest, SplitTouchesSendCorrectActionDownTime) {
3807 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
3808 sp<FakeWindowHandle> window1 =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07003809 sp<FakeWindowHandle>::make(application, mDispatcher, "Window1", DISPLAY_ID);
Vaibhav Devmurari882bd9b2022-06-23 14:54:54 +00003810 window1->setTouchableRegion(Region{{0, 0, 100, 100}});
3811 sp<FakeWindowHandle> window2 =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07003812 sp<FakeWindowHandle>::make(application, mDispatcher, "Window2", DISPLAY_ID);
Vaibhav Devmurari882bd9b2022-06-23 14:54:54 +00003813 window2->setTouchableRegion(Region{{100, 0, 200, 100}});
3814
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07003815 mDispatcher->onWindowInfosChanged({{*window1->getInfo(), *window2->getInfo()}, {}, 0, 0});
Vaibhav Devmurari882bd9b2022-06-23 14:54:54 +00003816
Vaibhav Devmurari882bd9b2022-06-23 14:54:54 +00003817 // Touch down on the first window
Prabir Pradhan678438e2023-04-13 19:32:51 +00003818 mDispatcher->notifyMotion(generateTouchArgs(AMOTION_EVENT_ACTION_DOWN, {{50, 50}}));
Vaibhav Devmurari882bd9b2022-06-23 14:54:54 +00003819 mDispatcher->waitForIdle();
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07003820
Prabir Pradhan9d5f9ce2024-01-24 00:03:41 +00003821 const std::unique_ptr<MotionEvent> firstDown =
3822 window1->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN)));
3823 ASSERT_EQ(firstDown->getDownTime(), firstDown->getEventTime());
Vaibhav Devmurari882bd9b2022-06-23 14:54:54 +00003824 window2->assertNoEvents();
Vaibhav Devmurari882bd9b2022-06-23 14:54:54 +00003825
3826 // Now touch down on the window with another pointer
Prabir Pradhan678438e2023-04-13 19:32:51 +00003827 mDispatcher->notifyMotion(generateTouchArgs(POINTER_1_DOWN, {{50, 50}, {150, 50}}));
Vaibhav Devmurari882bd9b2022-06-23 14:54:54 +00003828 mDispatcher->waitForIdle();
Prabir Pradhan9d5f9ce2024-01-24 00:03:41 +00003829
3830 const std::unique_ptr<MotionEvent> secondDown =
3831 window2->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN)));
3832 ASSERT_EQ(secondDown->getDownTime(), secondDown->getEventTime());
3833 ASSERT_NE(firstDown->getDownTime(), secondDown->getDownTime());
3834 // We currently send MOVE events to all windows receiving a split touch when there is any change
3835 // in the touch state, even when none of the pointers in the split window actually moved.
3836 // Document this behavior in the test.
3837 window1->consumeMotionMove();
Vaibhav Devmurari882bd9b2022-06-23 14:54:54 +00003838
3839 // Now move the pointer on the second window
Prabir Pradhan678438e2023-04-13 19:32:51 +00003840 mDispatcher->notifyMotion(generateTouchArgs(AMOTION_EVENT_ACTION_MOVE, {{50, 50}, {151, 51}}));
Vaibhav Devmurari882bd9b2022-06-23 14:54:54 +00003841 mDispatcher->waitForIdle();
Prabir Pradhan9d5f9ce2024-01-24 00:03:41 +00003842
3843 window2->consumeMotionEvent(WithDownTime(secondDown->getDownTime()));
3844 window1->consumeMotionEvent(WithDownTime(firstDown->getDownTime()));
Vaibhav Devmurari882bd9b2022-06-23 14:54:54 +00003845
3846 // Now add new touch down on the second window
Prabir Pradhan678438e2023-04-13 19:32:51 +00003847 mDispatcher->notifyMotion(generateTouchArgs(POINTER_2_DOWN, {{50, 50}, {151, 51}, {150, 50}}));
Vaibhav Devmurari882bd9b2022-06-23 14:54:54 +00003848 mDispatcher->waitForIdle();
Vaibhav Devmurari882bd9b2022-06-23 14:54:54 +00003849
Prabir Pradhan9d5f9ce2024-01-24 00:03:41 +00003850 window2->consumeMotionEvent(
3851 AllOf(WithMotionAction(POINTER_1_DOWN), WithDownTime(secondDown->getDownTime())));
3852 window1->consumeMotionEvent(WithDownTime(firstDown->getDownTime()));
Vaibhav Devmurari882bd9b2022-06-23 14:54:54 +00003853
3854 // Now move the pointer on the first window
Prabir Pradhan678438e2023-04-13 19:32:51 +00003855 mDispatcher->notifyMotion(
3856 generateTouchArgs(AMOTION_EVENT_ACTION_MOVE, {{51, 51}, {151, 51}, {150, 50}}));
Vaibhav Devmurari882bd9b2022-06-23 14:54:54 +00003857 mDispatcher->waitForIdle();
Vaibhav Devmurari882bd9b2022-06-23 14:54:54 +00003858
Prabir Pradhan9d5f9ce2024-01-24 00:03:41 +00003859 window1->consumeMotionEvent(WithDownTime(firstDown->getDownTime()));
3860 window2->consumeMotionEvent(WithDownTime(secondDown->getDownTime()));
3861
3862 // Now add new touch down on the first window
Prabir Pradhan678438e2023-04-13 19:32:51 +00003863 mDispatcher->notifyMotion(
3864 generateTouchArgs(POINTER_3_DOWN, {{51, 51}, {151, 51}, {150, 50}, {50, 50}}));
Vaibhav Devmurari882bd9b2022-06-23 14:54:54 +00003865 mDispatcher->waitForIdle();
Prabir Pradhan9d5f9ce2024-01-24 00:03:41 +00003866
3867 window1->consumeMotionEvent(
3868 AllOf(WithMotionAction(POINTER_1_DOWN), WithDownTime(firstDown->getDownTime())));
3869 window2->consumeMotionEvent(WithDownTime(secondDown->getDownTime()));
Vaibhav Devmurari882bd9b2022-06-23 14:54:54 +00003870}
3871
Garfield Tandf26e862020-07-01 20:18:19 -07003872TEST_F(InputDispatcherTest, HoverMoveEnterMouseClickAndHoverMoveExit) {
Chris Yea209fde2020-07-22 13:54:51 -07003873 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
Garfield Tandf26e862020-07-01 20:18:19 -07003874 sp<FakeWindowHandle> windowLeft =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07003875 sp<FakeWindowHandle>::make(application, mDispatcher, "Left", ADISPLAY_ID_DEFAULT);
Garfield Tandf26e862020-07-01 20:18:19 -07003876 windowLeft->setFrame(Rect(0, 0, 600, 800));
Garfield Tandf26e862020-07-01 20:18:19 -07003877 sp<FakeWindowHandle> windowRight =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07003878 sp<FakeWindowHandle>::make(application, mDispatcher, "Right", ADISPLAY_ID_DEFAULT);
Garfield Tandf26e862020-07-01 20:18:19 -07003879 windowRight->setFrame(Rect(600, 0, 1200, 800));
Garfield Tandf26e862020-07-01 20:18:19 -07003880
3881 mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application);
3882
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07003883 mDispatcher->onWindowInfosChanged(
3884 {{*windowLeft->getInfo(), *windowRight->getInfo()}, {}, 0, 0});
Garfield Tandf26e862020-07-01 20:18:19 -07003885
3886 // Start cursor position in right window so that we can move the cursor to left window.
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08003887 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07003888 injectMotionEvent(*mDispatcher,
Garfield Tandf26e862020-07-01 20:18:19 -07003889 MotionEventBuilder(AMOTION_EVENT_ACTION_HOVER_MOVE,
3890 AINPUT_SOURCE_MOUSE)
Siarhei Vishniakou6d73f832022-07-21 17:27:03 -07003891 .pointer(PointerBuilder(0, ToolType::MOUSE).x(900).y(400))
Garfield Tandf26e862020-07-01 20:18:19 -07003892 .build()));
Siarhei Vishniakou5cee1e32022-11-29 12:35:39 -08003893 windowRight->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_ENTER));
Garfield Tandf26e862020-07-01 20:18:19 -07003894
3895 // Move cursor into left window
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08003896 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07003897 injectMotionEvent(*mDispatcher,
Garfield Tandf26e862020-07-01 20:18:19 -07003898 MotionEventBuilder(AMOTION_EVENT_ACTION_HOVER_MOVE,
3899 AINPUT_SOURCE_MOUSE)
Siarhei Vishniakou6d73f832022-07-21 17:27:03 -07003900 .pointer(PointerBuilder(0, ToolType::MOUSE).x(300).y(400))
Garfield Tandf26e862020-07-01 20:18:19 -07003901 .build()));
Siarhei Vishniakou5cee1e32022-11-29 12:35:39 -08003902 windowRight->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_EXIT));
3903 windowLeft->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_ENTER));
Garfield Tandf26e862020-07-01 20:18:19 -07003904
3905 // Inject a series of mouse events for a mouse click
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08003906 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07003907 injectMotionEvent(*mDispatcher,
Garfield Tandf26e862020-07-01 20:18:19 -07003908 MotionEventBuilder(AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_MOUSE)
3909 .buttonState(AMOTION_EVENT_BUTTON_PRIMARY)
Siarhei Vishniakou6d73f832022-07-21 17:27:03 -07003910 .pointer(PointerBuilder(0, ToolType::MOUSE).x(300).y(400))
Garfield Tandf26e862020-07-01 20:18:19 -07003911 .build()));
Siarhei Vishniakouf372b812023-02-14 18:06:51 -08003912 windowLeft->consumeMotionEvent(WithMotionAction(ACTION_HOVER_EXIT));
3913 windowLeft->consumeMotionEvent(WithMotionAction(ACTION_DOWN));
Garfield Tandf26e862020-07-01 20:18:19 -07003914
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08003915 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07003916 injectMotionEvent(*mDispatcher,
Garfield Tandf26e862020-07-01 20:18:19 -07003917 MotionEventBuilder(AMOTION_EVENT_ACTION_BUTTON_PRESS,
3918 AINPUT_SOURCE_MOUSE)
3919 .buttonState(AMOTION_EVENT_BUTTON_PRIMARY)
3920 .actionButton(AMOTION_EVENT_BUTTON_PRIMARY)
Siarhei Vishniakou6d73f832022-07-21 17:27:03 -07003921 .pointer(PointerBuilder(0, ToolType::MOUSE).x(300).y(400))
Garfield Tandf26e862020-07-01 20:18:19 -07003922 .build()));
Siarhei Vishniakou5cee1e32022-11-29 12:35:39 -08003923 windowLeft->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_BUTTON_PRESS));
Garfield Tandf26e862020-07-01 20:18:19 -07003924
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08003925 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07003926 injectMotionEvent(*mDispatcher,
Garfield Tandf26e862020-07-01 20:18:19 -07003927 MotionEventBuilder(AMOTION_EVENT_ACTION_BUTTON_RELEASE,
3928 AINPUT_SOURCE_MOUSE)
3929 .buttonState(0)
3930 .actionButton(AMOTION_EVENT_BUTTON_PRIMARY)
Siarhei Vishniakou6d73f832022-07-21 17:27:03 -07003931 .pointer(PointerBuilder(0, ToolType::MOUSE).x(300).y(400))
Garfield Tandf26e862020-07-01 20:18:19 -07003932 .build()));
Siarhei Vishniakou5cee1e32022-11-29 12:35:39 -08003933 windowLeft->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_BUTTON_RELEASE));
Garfield Tandf26e862020-07-01 20:18:19 -07003934
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08003935 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07003936 injectMotionEvent(*mDispatcher,
Garfield Tandf26e862020-07-01 20:18:19 -07003937 MotionEventBuilder(AMOTION_EVENT_ACTION_UP, AINPUT_SOURCE_MOUSE)
3938 .buttonState(0)
Siarhei Vishniakou6d73f832022-07-21 17:27:03 -07003939 .pointer(PointerBuilder(0, ToolType::MOUSE).x(300).y(400))
Garfield Tandf26e862020-07-01 20:18:19 -07003940 .build()));
3941 windowLeft->consumeMotionUp(ADISPLAY_ID_DEFAULT);
3942
3943 // Move mouse cursor back to right window
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08003944 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07003945 injectMotionEvent(*mDispatcher,
Garfield Tandf26e862020-07-01 20:18:19 -07003946 MotionEventBuilder(AMOTION_EVENT_ACTION_HOVER_MOVE,
3947 AINPUT_SOURCE_MOUSE)
Siarhei Vishniakou6d73f832022-07-21 17:27:03 -07003948 .pointer(PointerBuilder(0, ToolType::MOUSE).x(900).y(400))
Garfield Tandf26e862020-07-01 20:18:19 -07003949 .build()));
Siarhei Vishniakou5cee1e32022-11-29 12:35:39 -08003950 windowRight->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_ENTER));
Siarhei Vishniakou5cee1e32022-11-29 12:35:39 -08003951
3952 // No more events
3953 windowLeft->assertNoEvents();
3954 windowRight->assertNoEvents();
3955}
3956
Siarhei Vishniakouf372b812023-02-14 18:06:51 -08003957/**
3958 * Put two fingers down (and don't release them) and click the mouse button.
3959 * The clicking of mouse is a new ACTION_DOWN event. Since it's from a different device, the
3960 * currently active gesture should be canceled, and the new one should proceed.
3961 */
Siarhei Vishniakoued89cbb2023-10-13 10:42:44 -07003962TEST_F(InputDispatcherTest, TwoPointersDownMouseClick_legacy) {
3963 SCOPED_FLAG_OVERRIDE(enable_multi_device_same_window_stream, false);
Siarhei Vishniakouf372b812023-02-14 18:06:51 -08003964 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
3965 sp<FakeWindowHandle> window =
3966 sp<FakeWindowHandle>::make(application, mDispatcher, "Window", ADISPLAY_ID_DEFAULT);
3967 window->setFrame(Rect(0, 0, 600, 800));
3968
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07003969 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Siarhei Vishniakouf372b812023-02-14 18:06:51 -08003970
3971 const int32_t touchDeviceId = 4;
3972 const int32_t mouseDeviceId = 6;
Siarhei Vishniakouf372b812023-02-14 18:06:51 -08003973
3974 // Two pointers down
Prabir Pradhan678438e2023-04-13 19:32:51 +00003975 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
3976 .deviceId(touchDeviceId)
3977 .pointer(PointerBuilder(0, ToolType::FINGER).x(100).y(100))
3978 .build());
Siarhei Vishniakouf372b812023-02-14 18:06:51 -08003979
Prabir Pradhan678438e2023-04-13 19:32:51 +00003980 mDispatcher->notifyMotion(MotionArgsBuilder(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
3981 .deviceId(touchDeviceId)
3982 .pointer(PointerBuilder(0, ToolType::FINGER).x(100).y(100))
3983 .pointer(PointerBuilder(1, ToolType::FINGER).x(120).y(120))
3984 .build());
Siarhei Vishniakouf372b812023-02-14 18:06:51 -08003985 window->consumeMotionEvent(WithMotionAction(ACTION_DOWN));
3986 window->consumeMotionEvent(WithMotionAction(POINTER_1_DOWN));
3987
3988 // Inject a series of mouse events for a mouse click
Prabir Pradhan678438e2023-04-13 19:32:51 +00003989 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_MOUSE)
3990 .deviceId(mouseDeviceId)
3991 .buttonState(AMOTION_EVENT_BUTTON_PRIMARY)
3992 .pointer(PointerBuilder(0, ToolType::MOUSE).x(300).y(400))
3993 .build());
Siarhei Vishniakouf372b812023-02-14 18:06:51 -08003994 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_CANCEL), WithDeviceId(touchDeviceId),
3995 WithPointerCount(2u)));
3996 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(mouseDeviceId)));
3997
Prabir Pradhan678438e2023-04-13 19:32:51 +00003998 mDispatcher->notifyMotion(
3999 MotionArgsBuilder(AMOTION_EVENT_ACTION_BUTTON_PRESS, AINPUT_SOURCE_MOUSE)
4000 .deviceId(mouseDeviceId)
4001 .buttonState(AMOTION_EVENT_BUTTON_PRIMARY)
4002 .actionButton(AMOTION_EVENT_BUTTON_PRIMARY)
4003 .pointer(PointerBuilder(0, ToolType::MOUSE).x(300).y(400))
4004 .build());
Siarhei Vishniakouf372b812023-02-14 18:06:51 -08004005 window->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_BUTTON_PRESS));
4006
4007 // Try to send more touch events while the mouse is down. Since it's a continuation of an
4008 // already canceled gesture, it should be ignored.
Prabir Pradhan678438e2023-04-13 19:32:51 +00004009 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN)
4010 .deviceId(touchDeviceId)
4011 .pointer(PointerBuilder(0, ToolType::FINGER).x(101).y(101))
4012 .pointer(PointerBuilder(1, ToolType::FINGER).x(121).y(121))
4013 .build());
Siarhei Vishniakouf372b812023-02-14 18:06:51 -08004014 window->assertNoEvents();
4015}
4016
Siarhei Vishniakoued89cbb2023-10-13 10:42:44 -07004017/**
4018 * Put two fingers down (and don't release them) and click the mouse button.
4019 * The clicking of mouse is a new ACTION_DOWN event. Since it's from a different device, the
4020 * currently active gesture should not be canceled, and the new one should proceed in parallel.
4021 */
4022TEST_F(InputDispatcherTest, TwoPointersDownMouseClick) {
4023 SCOPED_FLAG_OVERRIDE(enable_multi_device_same_window_stream, true);
4024 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
4025 sp<FakeWindowHandle> window =
4026 sp<FakeWindowHandle>::make(application, mDispatcher, "Window", ADISPLAY_ID_DEFAULT);
4027 window->setFrame(Rect(0, 0, 600, 800));
4028
4029 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
4030
4031 const int32_t touchDeviceId = 4;
4032 const int32_t mouseDeviceId = 6;
4033
4034 // Two pointers down
4035 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
4036 .deviceId(touchDeviceId)
4037 .pointer(PointerBuilder(0, ToolType::FINGER).x(100).y(100))
4038 .build());
4039
4040 mDispatcher->notifyMotion(MotionArgsBuilder(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
4041 .deviceId(touchDeviceId)
4042 .pointer(PointerBuilder(0, ToolType::FINGER).x(100).y(100))
4043 .pointer(PointerBuilder(1, ToolType::FINGER).x(120).y(120))
4044 .build());
4045 window->consumeMotionEvent(WithMotionAction(ACTION_DOWN));
4046 window->consumeMotionEvent(WithMotionAction(POINTER_1_DOWN));
4047
4048 // Send a series of mouse events for a mouse click
4049 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_MOUSE)
4050 .deviceId(mouseDeviceId)
4051 .buttonState(AMOTION_EVENT_BUTTON_PRIMARY)
4052 .pointer(PointerBuilder(0, ToolType::MOUSE).x(300).y(400))
4053 .build());
4054 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(mouseDeviceId)));
4055
4056 mDispatcher->notifyMotion(
4057 MotionArgsBuilder(AMOTION_EVENT_ACTION_BUTTON_PRESS, AINPUT_SOURCE_MOUSE)
4058 .deviceId(mouseDeviceId)
4059 .buttonState(AMOTION_EVENT_BUTTON_PRIMARY)
4060 .actionButton(AMOTION_EVENT_BUTTON_PRIMARY)
4061 .pointer(PointerBuilder(0, ToolType::MOUSE).x(300).y(400))
4062 .build());
4063 window->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_BUTTON_PRESS));
4064
4065 // Try to send more touch events while the mouse is down. Since it's a continuation of an
4066 // already active gesture, it should be sent normally.
4067 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN)
4068 .deviceId(touchDeviceId)
4069 .pointer(PointerBuilder(0, ToolType::FINGER).x(101).y(101))
4070 .pointer(PointerBuilder(1, ToolType::FINGER).x(121).y(121))
4071 .build());
4072 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(touchDeviceId)));
4073 window->assertNoEvents();
4074}
4075
Siarhei Vishniakou5cee1e32022-11-29 12:35:39 -08004076TEST_F(InputDispatcherTest, HoverWithSpyWindows) {
4077 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
4078
4079 sp<FakeWindowHandle> spyWindow =
4080 sp<FakeWindowHandle>::make(application, mDispatcher, "Spy", ADISPLAY_ID_DEFAULT);
4081 spyWindow->setFrame(Rect(0, 0, 600, 800));
4082 spyWindow->setTrustedOverlay(true);
4083 spyWindow->setSpy(true);
4084 sp<FakeWindowHandle> window =
4085 sp<FakeWindowHandle>::make(application, mDispatcher, "Window", ADISPLAY_ID_DEFAULT);
4086 window->setFrame(Rect(0, 0, 600, 800));
4087
4088 mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07004089 mDispatcher->onWindowInfosChanged({{*spyWindow->getInfo(), *window->getInfo()}, {}, 0, 0});
Siarhei Vishniakou5cee1e32022-11-29 12:35:39 -08004090
4091 // Send mouse cursor to the window
4092 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07004093 injectMotionEvent(*mDispatcher,
Siarhei Vishniakou5cee1e32022-11-29 12:35:39 -08004094 MotionEventBuilder(AMOTION_EVENT_ACTION_HOVER_ENTER,
4095 AINPUT_SOURCE_MOUSE)
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07004096 .pointer(PointerBuilder(0, ToolType::MOUSE).x(100).y(100))
Siarhei Vishniakou5cee1e32022-11-29 12:35:39 -08004097 .build()));
4098
4099 window->consumeMotionEvent(AllOf(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_ENTER),
4100 WithSource(AINPUT_SOURCE_MOUSE)));
4101 spyWindow->consumeMotionEvent(AllOf(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_ENTER),
4102 WithSource(AINPUT_SOURCE_MOUSE)));
4103
4104 window->assertNoEvents();
4105 spyWindow->assertNoEvents();
Garfield Tandf26e862020-07-01 20:18:19 -07004106}
4107
Siarhei Vishniakoued89cbb2023-10-13 10:42:44 -07004108TEST_F(InputDispatcherTest, MouseAndTouchWithSpyWindows_legacy) {
4109 SCOPED_FLAG_OVERRIDE(enable_multi_device_same_window_stream, false);
Siarhei Vishniakou060f82b2023-01-27 06:39:14 -08004110 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
4111
4112 sp<FakeWindowHandle> spyWindow =
4113 sp<FakeWindowHandle>::make(application, mDispatcher, "Spy", ADISPLAY_ID_DEFAULT);
4114 spyWindow->setFrame(Rect(0, 0, 600, 800));
4115 spyWindow->setTrustedOverlay(true);
4116 spyWindow->setSpy(true);
4117 sp<FakeWindowHandle> window =
4118 sp<FakeWindowHandle>::make(application, mDispatcher, "Window", ADISPLAY_ID_DEFAULT);
4119 window->setFrame(Rect(0, 0, 600, 800));
4120
4121 mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07004122 mDispatcher->onWindowInfosChanged({{*spyWindow->getInfo(), *window->getInfo()}, {}, 0, 0});
Siarhei Vishniakou060f82b2023-01-27 06:39:14 -08004123
4124 // Send mouse cursor to the window
4125 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07004126 injectMotionEvent(*mDispatcher,
Siarhei Vishniakou060f82b2023-01-27 06:39:14 -08004127 MotionEventBuilder(AMOTION_EVENT_ACTION_HOVER_ENTER,
4128 AINPUT_SOURCE_MOUSE)
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07004129 .pointer(PointerBuilder(0, ToolType::MOUSE).x(100).y(100))
Siarhei Vishniakou060f82b2023-01-27 06:39:14 -08004130 .build()));
4131
4132 // Move mouse cursor
4133 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07004134 injectMotionEvent(*mDispatcher,
Siarhei Vishniakou060f82b2023-01-27 06:39:14 -08004135 MotionEventBuilder(AMOTION_EVENT_ACTION_HOVER_MOVE,
4136 AINPUT_SOURCE_MOUSE)
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07004137 .pointer(PointerBuilder(0, ToolType::MOUSE).x(110).y(110))
Siarhei Vishniakou060f82b2023-01-27 06:39:14 -08004138 .build()));
4139
4140 window->consumeMotionEvent(AllOf(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_ENTER),
4141 WithSource(AINPUT_SOURCE_MOUSE)));
4142 spyWindow->consumeMotionEvent(AllOf(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_ENTER),
4143 WithSource(AINPUT_SOURCE_MOUSE)));
4144 window->consumeMotionEvent(AllOf(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_MOVE),
4145 WithSource(AINPUT_SOURCE_MOUSE)));
4146 spyWindow->consumeMotionEvent(AllOf(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_MOVE),
4147 WithSource(AINPUT_SOURCE_MOUSE)));
4148 // Touch down on the window
4149 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07004150 injectMotionEvent(*mDispatcher,
Siarhei Vishniakou060f82b2023-01-27 06:39:14 -08004151 MotionEventBuilder(AMOTION_EVENT_ACTION_DOWN,
4152 AINPUT_SOURCE_TOUCHSCREEN)
4153 .deviceId(SECOND_DEVICE_ID)
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07004154 .pointer(PointerBuilder(0, ToolType::FINGER).x(200).y(200))
Siarhei Vishniakou060f82b2023-01-27 06:39:14 -08004155 .build()));
4156 window->consumeMotionEvent(AllOf(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_EXIT),
4157 WithSource(AINPUT_SOURCE_MOUSE)));
4158 spyWindow->consumeMotionEvent(AllOf(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_EXIT),
4159 WithSource(AINPUT_SOURCE_MOUSE)));
4160 window->consumeMotionEvent(AllOf(WithMotionAction(AMOTION_EVENT_ACTION_DOWN),
4161 WithSource(AINPUT_SOURCE_TOUCHSCREEN)));
4162 spyWindow->consumeMotionEvent(AllOf(WithMotionAction(AMOTION_EVENT_ACTION_DOWN),
4163 WithSource(AINPUT_SOURCE_TOUCHSCREEN)));
4164
4165 // pilfer the motion, retaining the gesture on the spy window.
4166 EXPECT_EQ(OK, mDispatcher->pilferPointers(spyWindow->getToken()));
4167 window->consumeMotionEvent(AllOf(WithMotionAction(AMOTION_EVENT_ACTION_CANCEL),
4168 WithSource(AINPUT_SOURCE_TOUCHSCREEN)));
4169
4170 // Touch UP on the window
4171 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07004172 injectMotionEvent(*mDispatcher,
Siarhei Vishniakou060f82b2023-01-27 06:39:14 -08004173 MotionEventBuilder(AMOTION_EVENT_ACTION_UP,
4174 AINPUT_SOURCE_TOUCHSCREEN)
4175 .deviceId(SECOND_DEVICE_ID)
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07004176 .pointer(PointerBuilder(0, ToolType::FINGER).x(200).y(200))
Siarhei Vishniakou060f82b2023-01-27 06:39:14 -08004177 .build()));
4178 spyWindow->consumeMotionEvent(AllOf(WithMotionAction(AMOTION_EVENT_ACTION_UP),
4179 WithSource(AINPUT_SOURCE_TOUCHSCREEN)));
4180
4181 // Previously, a touch was pilfered. However, that gesture was just finished. Now, we are going
4182 // to send a new gesture. It should again go to both windows (spy and the window below), just
4183 // like the first gesture did, before pilfering. The window configuration has not changed.
4184
4185 // One more tap - DOWN
4186 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07004187 injectMotionEvent(*mDispatcher,
Siarhei Vishniakou060f82b2023-01-27 06:39:14 -08004188 MotionEventBuilder(AMOTION_EVENT_ACTION_DOWN,
4189 AINPUT_SOURCE_TOUCHSCREEN)
4190 .deviceId(SECOND_DEVICE_ID)
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07004191 .pointer(PointerBuilder(0, ToolType::FINGER).x(250).y(250))
Siarhei Vishniakou060f82b2023-01-27 06:39:14 -08004192 .build()));
4193 window->consumeMotionEvent(AllOf(WithMotionAction(AMOTION_EVENT_ACTION_DOWN),
4194 WithSource(AINPUT_SOURCE_TOUCHSCREEN)));
4195 spyWindow->consumeMotionEvent(AllOf(WithMotionAction(AMOTION_EVENT_ACTION_DOWN),
4196 WithSource(AINPUT_SOURCE_TOUCHSCREEN)));
4197
4198 // Touch UP on the window
4199 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07004200 injectMotionEvent(*mDispatcher,
Siarhei Vishniakou060f82b2023-01-27 06:39:14 -08004201 MotionEventBuilder(AMOTION_EVENT_ACTION_UP,
4202 AINPUT_SOURCE_TOUCHSCREEN)
4203 .deviceId(SECOND_DEVICE_ID)
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07004204 .pointer(PointerBuilder(0, ToolType::FINGER).x(250).y(250))
Siarhei Vishniakou060f82b2023-01-27 06:39:14 -08004205 .build()));
4206 window->consumeMotionEvent(AllOf(WithMotionAction(AMOTION_EVENT_ACTION_UP),
4207 WithSource(AINPUT_SOURCE_TOUCHSCREEN)));
4208 spyWindow->consumeMotionEvent(AllOf(WithMotionAction(AMOTION_EVENT_ACTION_UP),
4209 WithSource(AINPUT_SOURCE_TOUCHSCREEN)));
4210
4211 window->assertNoEvents();
4212 spyWindow->assertNoEvents();
4213}
4214
Siarhei Vishniakoued89cbb2023-10-13 10:42:44 -07004215TEST_F(InputDispatcherTest, MouseAndTouchWithSpyWindows) {
4216 SCOPED_FLAG_OVERRIDE(enable_multi_device_same_window_stream, true);
4217 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
4218
4219 sp<FakeWindowHandle> spyWindow =
4220 sp<FakeWindowHandle>::make(application, mDispatcher, "Spy", ADISPLAY_ID_DEFAULT);
4221 spyWindow->setFrame(Rect(0, 0, 600, 800));
4222 spyWindow->setTrustedOverlay(true);
4223 spyWindow->setSpy(true);
4224 sp<FakeWindowHandle> window =
4225 sp<FakeWindowHandle>::make(application, mDispatcher, "Window", ADISPLAY_ID_DEFAULT);
4226 window->setFrame(Rect(0, 0, 600, 800));
4227
4228 mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application);
4229 mDispatcher->onWindowInfosChanged({{*spyWindow->getInfo(), *window->getInfo()}, {}, 0, 0});
4230
4231 // Send mouse cursor to the window
4232 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_ENTER, AINPUT_SOURCE_MOUSE)
4233 .pointer(PointerBuilder(0, ToolType::MOUSE).x(100).y(100))
4234 .build());
4235
4236 // Move mouse cursor
4237 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_MOVE, AINPUT_SOURCE_MOUSE)
4238 .pointer(PointerBuilder(0, ToolType::MOUSE).x(110).y(110))
4239 .build());
4240
4241 window->consumeMotionEvent(
4242 AllOf(WithMotionAction(ACTION_HOVER_ENTER), WithSource(AINPUT_SOURCE_MOUSE)));
4243 spyWindow->consumeMotionEvent(
4244 AllOf(WithMotionAction(ACTION_HOVER_ENTER), WithSource(AINPUT_SOURCE_MOUSE)));
4245 window->consumeMotionEvent(
4246 AllOf(WithMotionAction(ACTION_HOVER_MOVE), WithSource(AINPUT_SOURCE_MOUSE)));
4247 spyWindow->consumeMotionEvent(
4248 AllOf(WithMotionAction(ACTION_HOVER_MOVE), WithSource(AINPUT_SOURCE_MOUSE)));
4249 // Touch down on the window
4250 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
4251 .deviceId(SECOND_DEVICE_ID)
4252 .pointer(PointerBuilder(0, ToolType::FINGER).x(200).y(200))
4253 .build());
4254 window->consumeMotionEvent(
4255 AllOf(WithMotionAction(ACTION_DOWN), WithSource(AINPUT_SOURCE_TOUCHSCREEN)));
4256 spyWindow->consumeMotionEvent(
4257 AllOf(WithMotionAction(ACTION_DOWN), WithSource(AINPUT_SOURCE_TOUCHSCREEN)));
4258
4259 // pilfer the motion, retaining the gesture on the spy window.
4260 EXPECT_EQ(OK, mDispatcher->pilferPointers(spyWindow->getToken()));
4261 window->consumeMotionEvent(
4262 AllOf(WithMotionAction(ACTION_CANCEL), WithSource(AINPUT_SOURCE_TOUCHSCREEN)));
4263 // Mouse hover is not pilfered
4264
4265 // Touch UP on the window
4266 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN)
4267 .deviceId(SECOND_DEVICE_ID)
4268 .pointer(PointerBuilder(0, ToolType::FINGER).x(200).y(200))
4269 .build());
4270 spyWindow->consumeMotionEvent(
4271 AllOf(WithMotionAction(ACTION_UP), WithSource(AINPUT_SOURCE_TOUCHSCREEN)));
4272
4273 // Previously, a touch was pilfered. However, that gesture was just finished. Now, we are going
4274 // to send a new gesture. It should again go to both windows (spy and the window below), just
4275 // like the first gesture did, before pilfering. The window configuration has not changed.
4276
4277 // One more tap - DOWN
4278 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
4279 .deviceId(SECOND_DEVICE_ID)
4280 .pointer(PointerBuilder(0, ToolType::FINGER).x(250).y(250))
4281 .build());
4282 window->consumeMotionEvent(
4283 AllOf(WithMotionAction(ACTION_DOWN), WithSource(AINPUT_SOURCE_TOUCHSCREEN)));
4284 spyWindow->consumeMotionEvent(
4285 AllOf(WithMotionAction(ACTION_DOWN), WithSource(AINPUT_SOURCE_TOUCHSCREEN)));
4286
4287 // Touch UP on the window
4288 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN)
4289 .deviceId(SECOND_DEVICE_ID)
4290 .pointer(PointerBuilder(0, ToolType::FINGER).x(250).y(250))
4291 .build());
4292 window->consumeMotionEvent(
4293 AllOf(WithMotionAction(ACTION_UP), WithSource(AINPUT_SOURCE_TOUCHSCREEN)));
4294 spyWindow->consumeMotionEvent(
4295 AllOf(WithMotionAction(ACTION_UP), WithSource(AINPUT_SOURCE_TOUCHSCREEN)));
4296
4297 // Mouse movement continues normally as well
4298 // Move mouse cursor
4299 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_MOVE, AINPUT_SOURCE_MOUSE)
4300 .pointer(PointerBuilder(0, ToolType::MOUSE).x(120).y(130))
4301 .build());
4302 window->consumeMotionEvent(
4303 AllOf(WithMotionAction(ACTION_HOVER_MOVE), WithSource(AINPUT_SOURCE_MOUSE)));
4304 spyWindow->consumeMotionEvent(
4305 AllOf(WithMotionAction(ACTION_HOVER_MOVE), WithSource(AINPUT_SOURCE_MOUSE)));
4306
4307 window->assertNoEvents();
4308 spyWindow->assertNoEvents();
4309}
4310
Garfield Tandf26e862020-07-01 20:18:19 -07004311// This test is different from the test above that HOVER_ENTER and HOVER_EXIT events are injected
4312// directly in this test.
4313TEST_F(InputDispatcherTest, HoverEnterMouseClickAndHoverExit) {
Chris Yea209fde2020-07-22 13:54:51 -07004314 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
Garfield Tandf26e862020-07-01 20:18:19 -07004315 sp<FakeWindowHandle> window =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07004316 sp<FakeWindowHandle>::make(application, mDispatcher, "Window", ADISPLAY_ID_DEFAULT);
Garfield Tandf26e862020-07-01 20:18:19 -07004317 window->setFrame(Rect(0, 0, 1200, 800));
Garfield Tandf26e862020-07-01 20:18:19 -07004318
4319 mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application);
4320
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07004321 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Garfield Tandf26e862020-07-01 20:18:19 -07004322
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08004323 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07004324 injectMotionEvent(*mDispatcher,
Garfield Tandf26e862020-07-01 20:18:19 -07004325 MotionEventBuilder(AMOTION_EVENT_ACTION_HOVER_ENTER,
4326 AINPUT_SOURCE_MOUSE)
Siarhei Vishniakou6d73f832022-07-21 17:27:03 -07004327 .pointer(PointerBuilder(0, ToolType::MOUSE).x(300).y(400))
Garfield Tandf26e862020-07-01 20:18:19 -07004328 .build()));
Siarhei Vishniakou5cee1e32022-11-29 12:35:39 -08004329 window->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_ENTER));
Garfield Tandf26e862020-07-01 20:18:19 -07004330 // Inject a series of mouse events for a mouse click
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08004331 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07004332 injectMotionEvent(*mDispatcher,
Garfield Tandf26e862020-07-01 20:18:19 -07004333 MotionEventBuilder(AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_MOUSE)
4334 .buttonState(AMOTION_EVENT_BUTTON_PRIMARY)
Siarhei Vishniakou6d73f832022-07-21 17:27:03 -07004335 .pointer(PointerBuilder(0, ToolType::MOUSE).x(300).y(400))
Garfield Tandf26e862020-07-01 20:18:19 -07004336 .build()));
Siarhei Vishniakouf372b812023-02-14 18:06:51 -08004337 window->consumeMotionEvent(WithMotionAction(ACTION_HOVER_EXIT));
4338 window->consumeMotionEvent(WithMotionAction(ACTION_DOWN));
Garfield Tandf26e862020-07-01 20:18:19 -07004339
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08004340 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07004341 injectMotionEvent(*mDispatcher,
Garfield Tandf26e862020-07-01 20:18:19 -07004342 MotionEventBuilder(AMOTION_EVENT_ACTION_BUTTON_PRESS,
4343 AINPUT_SOURCE_MOUSE)
4344 .buttonState(AMOTION_EVENT_BUTTON_PRIMARY)
4345 .actionButton(AMOTION_EVENT_BUTTON_PRIMARY)
Siarhei Vishniakou6d73f832022-07-21 17:27:03 -07004346 .pointer(PointerBuilder(0, ToolType::MOUSE).x(300).y(400))
Garfield Tandf26e862020-07-01 20:18:19 -07004347 .build()));
Siarhei Vishniakou5cee1e32022-11-29 12:35:39 -08004348 window->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_BUTTON_PRESS));
Garfield Tandf26e862020-07-01 20:18:19 -07004349
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08004350 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07004351 injectMotionEvent(*mDispatcher,
Garfield Tandf26e862020-07-01 20:18:19 -07004352 MotionEventBuilder(AMOTION_EVENT_ACTION_BUTTON_RELEASE,
4353 AINPUT_SOURCE_MOUSE)
4354 .buttonState(0)
4355 .actionButton(AMOTION_EVENT_BUTTON_PRIMARY)
Siarhei Vishniakou6d73f832022-07-21 17:27:03 -07004356 .pointer(PointerBuilder(0, ToolType::MOUSE).x(300).y(400))
Garfield Tandf26e862020-07-01 20:18:19 -07004357 .build()));
Siarhei Vishniakou5cee1e32022-11-29 12:35:39 -08004358 window->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_BUTTON_RELEASE));
Garfield Tandf26e862020-07-01 20:18:19 -07004359
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08004360 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07004361 injectMotionEvent(*mDispatcher,
Garfield Tandf26e862020-07-01 20:18:19 -07004362 MotionEventBuilder(AMOTION_EVENT_ACTION_UP, AINPUT_SOURCE_MOUSE)
4363 .buttonState(0)
Siarhei Vishniakou6d73f832022-07-21 17:27:03 -07004364 .pointer(PointerBuilder(0, ToolType::MOUSE).x(300).y(400))
Garfield Tandf26e862020-07-01 20:18:19 -07004365 .build()));
4366 window->consumeMotionUp(ADISPLAY_ID_DEFAULT);
4367
Siarhei Vishniakoua235c042023-05-02 09:59:09 -07004368 // We already canceled the hovering implicitly by injecting the "DOWN" event without lifting the
4369 // hover first. Therefore, injection of HOVER_EXIT is inconsistent, and should fail.
4370 ASSERT_EQ(InputEventInjectionResult::FAILED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07004371 injectMotionEvent(*mDispatcher,
Garfield Tandf26e862020-07-01 20:18:19 -07004372 MotionEventBuilder(AMOTION_EVENT_ACTION_HOVER_EXIT,
4373 AINPUT_SOURCE_MOUSE)
Siarhei Vishniakou6d73f832022-07-21 17:27:03 -07004374 .pointer(PointerBuilder(0, ToolType::MOUSE).x(300).y(400))
Garfield Tandf26e862020-07-01 20:18:19 -07004375 .build()));
Siarhei Vishniakouf372b812023-02-14 18:06:51 -08004376 window->assertNoEvents();
Garfield Tandf26e862020-07-01 20:18:19 -07004377}
4378
Siarhei Vishniakou0b0374d2022-11-17 17:40:53 -08004379/**
Siarhei Vishniakoub581f7f2022-12-07 20:23:06 +00004380 * Hover over a window, and then remove that window. Make sure that HOVER_EXIT for that event
4381 * is generated.
4382 */
4383TEST_F(InputDispatcherTest, HoverExitIsSentToRemovedWindow) {
4384 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
4385 sp<FakeWindowHandle> window =
4386 sp<FakeWindowHandle>::make(application, mDispatcher, "Window", ADISPLAY_ID_DEFAULT);
4387 window->setFrame(Rect(0, 0, 1200, 800));
4388
4389 mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application);
4390
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07004391 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Siarhei Vishniakoub581f7f2022-12-07 20:23:06 +00004392
4393 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07004394 injectMotionEvent(*mDispatcher,
Siarhei Vishniakoub581f7f2022-12-07 20:23:06 +00004395 MotionEventBuilder(AMOTION_EVENT_ACTION_HOVER_ENTER,
4396 AINPUT_SOURCE_MOUSE)
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07004397 .pointer(PointerBuilder(0, ToolType::MOUSE).x(300).y(400))
Siarhei Vishniakoub581f7f2022-12-07 20:23:06 +00004398 .build()));
4399 window->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_ENTER));
4400
4401 // Remove the window, but keep the channel.
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07004402 mDispatcher->onWindowInfosChanged({{}, {}, 0, 0});
Siarhei Vishniakoub581f7f2022-12-07 20:23:06 +00004403 window->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_EXIT));
4404}
4405
4406/**
Daniel Norman7487dfa2023-08-02 16:39:45 -07004407 * Test that invalid HOVER events sent by accessibility do not cause a fatal crash.
4408 */
Ameer Armalycff4fa52023-10-04 23:45:11 +00004409TEST_F_WITH_FLAGS(InputDispatcherTest, InvalidA11yHoverStreamDoesNotCrash,
4410 REQUIRES_FLAGS_DISABLED(ACONFIG_FLAG(com::android::input::flags,
4411 a11y_crash_on_inconsistent_event_stream))) {
Daniel Norman7487dfa2023-08-02 16:39:45 -07004412 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
4413 sp<FakeWindowHandle> window =
4414 sp<FakeWindowHandle>::make(application, mDispatcher, "Window", ADISPLAY_ID_DEFAULT);
4415 window->setFrame(Rect(0, 0, 1200, 800));
4416
4417 mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application);
4418
4419 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
4420
4421 MotionEventBuilder hoverEnterBuilder =
4422 MotionEventBuilder(AMOTION_EVENT_ACTION_HOVER_ENTER, AINPUT_SOURCE_MOUSE)
4423 .pointer(PointerBuilder(0, ToolType::MOUSE).x(300).y(400))
4424 .addFlag(AMOTION_EVENT_FLAG_IS_ACCESSIBILITY_EVENT);
4425 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
4426 injectMotionEvent(*mDispatcher, hoverEnterBuilder.build()));
4427 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
4428 injectMotionEvent(*mDispatcher, hoverEnterBuilder.build()));
4429 window->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_ENTER));
4430 window->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_ENTER));
4431}
4432
4433/**
Siarhei Vishniakou4e1ffa52023-02-21 11:50:34 -08004434 * If mouse is hovering when the touch goes down, the hovering should be stopped via HOVER_EXIT.
4435 */
Siarhei Vishniakoued89cbb2023-10-13 10:42:44 -07004436TEST_F(InputDispatcherTest, TouchDownAfterMouseHover_legacy) {
4437 SCOPED_FLAG_OVERRIDE(enable_multi_device_same_window_stream, false);
Siarhei Vishniakou4e1ffa52023-02-21 11:50:34 -08004438 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
4439 sp<FakeWindowHandle> window =
4440 sp<FakeWindowHandle>::make(application, mDispatcher, "Window", ADISPLAY_ID_DEFAULT);
4441 window->setFrame(Rect(0, 0, 100, 100));
4442
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07004443 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Siarhei Vishniakou4e1ffa52023-02-21 11:50:34 -08004444
4445 const int32_t mouseDeviceId = 7;
4446 const int32_t touchDeviceId = 4;
Siarhei Vishniakou4e1ffa52023-02-21 11:50:34 -08004447
4448 // Start hovering with the mouse
Prabir Pradhan678438e2023-04-13 19:32:51 +00004449 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_ENTER, AINPUT_SOURCE_MOUSE)
4450 .deviceId(mouseDeviceId)
4451 .pointer(PointerBuilder(0, ToolType::MOUSE).x(10).y(10))
4452 .build());
Siarhei Vishniakou4e1ffa52023-02-21 11:50:34 -08004453 window->consumeMotionEvent(
4454 AllOf(WithMotionAction(ACTION_HOVER_ENTER), WithDeviceId(mouseDeviceId)));
4455
4456 // Touch goes down
Prabir Pradhan678438e2023-04-13 19:32:51 +00004457 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
4458 .deviceId(touchDeviceId)
4459 .pointer(PointerBuilder(0, ToolType::FINGER).x(50).y(50))
4460 .build());
Siarhei Vishniakou4e1ffa52023-02-21 11:50:34 -08004461
4462 window->consumeMotionEvent(
4463 AllOf(WithMotionAction(ACTION_HOVER_EXIT), WithDeviceId(mouseDeviceId)));
4464 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(touchDeviceId)));
4465}
4466
4467/**
Siarhei Vishniakoued89cbb2023-10-13 10:42:44 -07004468 * If mouse is hovering when the touch goes down, the hovering should not be stopped.
4469 */
4470TEST_F(InputDispatcherTest, TouchDownAfterMouseHover) {
4471 SCOPED_FLAG_OVERRIDE(enable_multi_device_same_window_stream, true);
4472 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
4473 sp<FakeWindowHandle> window =
4474 sp<FakeWindowHandle>::make(application, mDispatcher, "Window", ADISPLAY_ID_DEFAULT);
4475 window->setFrame(Rect(0, 0, 100, 100));
4476
4477 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
4478
4479 const int32_t mouseDeviceId = 7;
4480 const int32_t touchDeviceId = 4;
4481
4482 // Start hovering with the mouse
4483 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_ENTER, AINPUT_SOURCE_MOUSE)
4484 .deviceId(mouseDeviceId)
4485 .pointer(PointerBuilder(0, ToolType::MOUSE).x(10).y(10))
4486 .build());
4487 window->consumeMotionEvent(
4488 AllOf(WithMotionAction(ACTION_HOVER_ENTER), WithDeviceId(mouseDeviceId)));
4489
4490 // Touch goes down
4491 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
4492 .deviceId(touchDeviceId)
4493 .pointer(PointerBuilder(0, ToolType::FINGER).x(50).y(50))
4494 .build());
4495 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(touchDeviceId)));
4496}
4497
4498/**
Siarhei Vishniakou0b0374d2022-11-17 17:40:53 -08004499 * Inject a mouse hover event followed by a tap from touchscreen.
Siarhei Vishniakoub581f7f2022-12-07 20:23:06 +00004500 * The tap causes a HOVER_EXIT event to be generated because the current event
4501 * stream's source has been switched.
Siarhei Vishniakou0b0374d2022-11-17 17:40:53 -08004502 */
Siarhei Vishniakoued89cbb2023-10-13 10:42:44 -07004503TEST_F(InputDispatcherTest, MouseHoverAndTouchTap_legacy) {
4504 SCOPED_FLAG_OVERRIDE(enable_multi_device_same_window_stream, false);
Siarhei Vishniakou0b0374d2022-11-17 17:40:53 -08004505 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
4506 sp<FakeWindowHandle> window =
4507 sp<FakeWindowHandle>::make(application, mDispatcher, "Window", ADISPLAY_ID_DEFAULT);
4508 window->setFrame(Rect(0, 0, 100, 100));
4509
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07004510 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -07004511 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_MOVE, AINPUT_SOURCE_MOUSE)
4512 .pointer(PointerBuilder(0, ToolType::MOUSE).x(50).y(50))
4513 .build());
Siarhei Vishniakou0b0374d2022-11-17 17:40:53 -08004514 ASSERT_NO_FATAL_FAILURE(
4515 window->consumeMotionEvent(AllOf(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_ENTER),
4516 WithSource(AINPUT_SOURCE_MOUSE))));
Siarhei Vishniakou0b0374d2022-11-17 17:40:53 -08004517
4518 // Tap on the window
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -07004519 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
4520 .pointer(PointerBuilder(0, ToolType::FINGER).x(10).y(10))
4521 .build());
Siarhei Vishniakou0b0374d2022-11-17 17:40:53 -08004522 ASSERT_NO_FATAL_FAILURE(
Siarhei Vishniakoub581f7f2022-12-07 20:23:06 +00004523 window->consumeMotionEvent(AllOf(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_EXIT),
4524 WithSource(AINPUT_SOURCE_MOUSE))));
4525
4526 ASSERT_NO_FATAL_FAILURE(
Siarhei Vishniakou0b0374d2022-11-17 17:40:53 -08004527 window->consumeMotionEvent(AllOf(WithMotionAction(AMOTION_EVENT_ACTION_DOWN),
4528 WithSource(AINPUT_SOURCE_TOUCHSCREEN))));
4529
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -07004530 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN)
4531 .pointer(PointerBuilder(0, ToolType::FINGER).x(10).y(10))
4532 .build());
Siarhei Vishniakou0b0374d2022-11-17 17:40:53 -08004533 ASSERT_NO_FATAL_FAILURE(
4534 window->consumeMotionEvent(AllOf(WithMotionAction(AMOTION_EVENT_ACTION_UP),
4535 WithSource(AINPUT_SOURCE_TOUCHSCREEN))));
4536}
4537
Siarhei Vishniakoued89cbb2023-10-13 10:42:44 -07004538/**
4539 * Send a mouse hover event followed by a tap from touchscreen.
4540 * The tap causes a HOVER_EXIT event to be generated because the current event
4541 * stream's source has been switched.
4542 */
4543TEST_F(InputDispatcherTest, MouseHoverAndTouchTap) {
4544 SCOPED_FLAG_OVERRIDE(enable_multi_device_same_window_stream, true);
4545 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
4546 sp<FakeWindowHandle> window =
4547 sp<FakeWindowHandle>::make(application, mDispatcher, "Window", ADISPLAY_ID_DEFAULT);
4548 window->setFrame(Rect(0, 0, 100, 100));
4549
4550 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
4551 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_MOVE, AINPUT_SOURCE_MOUSE)
4552 .pointer(PointerBuilder(0, ToolType::MOUSE).x(50).y(50))
4553 .build());
4554
4555 window->consumeMotionEvent(AllOf(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_ENTER),
4556 WithSource(AINPUT_SOURCE_MOUSE)));
4557
4558 // Tap on the window
4559 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
4560 .pointer(PointerBuilder(0, ToolType::FINGER).x(10).y(10))
4561 .build());
4562
4563 window->consumeMotionEvent(AllOf(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_EXIT),
4564 WithSource(AINPUT_SOURCE_MOUSE)));
4565
4566 window->consumeMotionEvent(AllOf(WithMotionAction(AMOTION_EVENT_ACTION_DOWN),
4567 WithSource(AINPUT_SOURCE_TOUCHSCREEN)));
4568
4569 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN)
4570 .pointer(PointerBuilder(0, ToolType::FINGER).x(10).y(10))
4571 .build());
4572
4573 window->consumeMotionEvent(AllOf(WithMotionAction(AMOTION_EVENT_ACTION_UP),
4574 WithSource(AINPUT_SOURCE_TOUCHSCREEN)));
4575}
4576
Tommy Nordgrendae9dfc2022-10-13 11:25:57 +02004577TEST_F(InputDispatcherTest, HoverEnterMoveRemoveWindowsInSecondDisplay) {
4578 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
4579 sp<FakeWindowHandle> windowDefaultDisplay =
4580 sp<FakeWindowHandle>::make(application, mDispatcher, "DefaultDisplay",
4581 ADISPLAY_ID_DEFAULT);
4582 windowDefaultDisplay->setFrame(Rect(0, 0, 600, 800));
4583 sp<FakeWindowHandle> windowSecondDisplay =
4584 sp<FakeWindowHandle>::make(application, mDispatcher, "SecondDisplay",
4585 SECOND_DISPLAY_ID);
4586 windowSecondDisplay->setFrame(Rect(0, 0, 600, 800));
4587
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07004588 mDispatcher->onWindowInfosChanged(
4589 {{*windowDefaultDisplay->getInfo(), *windowSecondDisplay->getInfo()}, {}, 0, 0});
Tommy Nordgrendae9dfc2022-10-13 11:25:57 +02004590
4591 // Set cursor position in window in default display and check that hover enter and move
4592 // events are generated.
4593 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07004594 injectMotionEvent(*mDispatcher,
Tommy Nordgrendae9dfc2022-10-13 11:25:57 +02004595 MotionEventBuilder(AMOTION_EVENT_ACTION_HOVER_MOVE,
4596 AINPUT_SOURCE_MOUSE)
4597 .displayId(ADISPLAY_ID_DEFAULT)
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07004598 .pointer(PointerBuilder(0, ToolType::MOUSE).x(300).y(600))
Tommy Nordgrendae9dfc2022-10-13 11:25:57 +02004599 .build()));
Siarhei Vishniakou5cee1e32022-11-29 12:35:39 -08004600 windowDefaultDisplay->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_ENTER));
Tommy Nordgrendae9dfc2022-10-13 11:25:57 +02004601
4602 // Remove all windows in secondary display and check that no event happens on window in
4603 // primary display.
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07004604 mDispatcher->onWindowInfosChanged({{*windowDefaultDisplay->getInfo()}, {}, 0, 0});
4605
Tommy Nordgrendae9dfc2022-10-13 11:25:57 +02004606 windowDefaultDisplay->assertNoEvents();
4607
4608 // Move cursor position in window in default display and check that only hover move
4609 // event is generated and not hover enter event.
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07004610 mDispatcher->onWindowInfosChanged(
4611 {{*windowDefaultDisplay->getInfo(), *windowSecondDisplay->getInfo()}, {}, 0, 0});
Tommy Nordgrendae9dfc2022-10-13 11:25:57 +02004612 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07004613 injectMotionEvent(*mDispatcher,
Tommy Nordgrendae9dfc2022-10-13 11:25:57 +02004614 MotionEventBuilder(AMOTION_EVENT_ACTION_HOVER_MOVE,
4615 AINPUT_SOURCE_MOUSE)
4616 .displayId(ADISPLAY_ID_DEFAULT)
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07004617 .pointer(PointerBuilder(0, ToolType::MOUSE).x(400).y(700))
Tommy Nordgrendae9dfc2022-10-13 11:25:57 +02004618 .build()));
Siarhei Vishniakou5cee1e32022-11-29 12:35:39 -08004619 windowDefaultDisplay->consumeMotionEvent(
4620 AllOf(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_MOVE),
4621 WithSource(AINPUT_SOURCE_MOUSE)));
Tommy Nordgrendae9dfc2022-10-13 11:25:57 +02004622 windowDefaultDisplay->assertNoEvents();
4623}
4624
Garfield Tan00f511d2019-06-12 16:55:40 -07004625TEST_F(InputDispatcherTest, DispatchMouseEventsUnderCursor) {
Chris Yea209fde2020-07-22 13:54:51 -07004626 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
Garfield Tan00f511d2019-06-12 16:55:40 -07004627
4628 sp<FakeWindowHandle> windowLeft =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07004629 sp<FakeWindowHandle>::make(application, mDispatcher, "Left", ADISPLAY_ID_DEFAULT);
Garfield Tan00f511d2019-06-12 16:55:40 -07004630 windowLeft->setFrame(Rect(0, 0, 600, 800));
Garfield Tan00f511d2019-06-12 16:55:40 -07004631 sp<FakeWindowHandle> windowRight =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07004632 sp<FakeWindowHandle>::make(application, mDispatcher, "Right", ADISPLAY_ID_DEFAULT);
Garfield Tan00f511d2019-06-12 16:55:40 -07004633 windowRight->setFrame(Rect(600, 0, 1200, 800));
Garfield Tan00f511d2019-06-12 16:55:40 -07004634
4635 mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application);
4636
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07004637 mDispatcher->onWindowInfosChanged(
4638 {{*windowLeft->getInfo(), *windowRight->getInfo()}, {}, 0, 0});
Garfield Tan00f511d2019-06-12 16:55:40 -07004639
4640 // Inject an event with coordinate in the area of right window, with mouse cursor in the area of
4641 // left window. This event should be dispatched to the left window.
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08004642 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07004643 injectMotionEvent(*mDispatcher, AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_MOUSE,
Siarhei Vishniakou4cb50ca2020-05-26 21:43:02 -07004644 ADISPLAY_ID_DEFAULT, {610, 400}, {599, 400}));
Siarhei Vishniakouc5ca85c2019-11-15 17:20:00 -08004645 windowLeft->consumeMotionDown(ADISPLAY_ID_DEFAULT);
Garfield Tan00f511d2019-06-12 16:55:40 -07004646 windowRight->assertNoEvents();
4647}
4648
Siarhei Vishniakou2bfa9052019-11-21 18:10:54 -08004649TEST_F(InputDispatcherTest, NotifyDeviceReset_CancelsKeyStream) {
Chris Yea209fde2020-07-22 13:54:51 -07004650 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07004651 sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher,
4652 "Fake Window", ADISPLAY_ID_DEFAULT);
Vishnu Nair47074b82020-08-14 11:54:47 -07004653 window->setFocusable(true);
Siarhei Vishniakou2bfa9052019-11-21 18:10:54 -08004654
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07004655 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Vishnu Nair958da932020-08-21 17:12:37 -07004656 setFocusedWindow(window);
4657
Siarhei Vishniakouf1035d42019-09-20 16:32:01 +01004658 window->consumeFocusEvent(true);
Siarhei Vishniakou2bfa9052019-11-21 18:10:54 -08004659
Prabir Pradhan678438e2023-04-13 19:32:51 +00004660 mDispatcher->notifyKey(generateKeyArgs(AKEY_EVENT_ACTION_DOWN, ADISPLAY_ID_DEFAULT));
Siarhei Vishniakou2bfa9052019-11-21 18:10:54 -08004661
4662 // Window should receive key down event.
4663 window->consumeKeyDown(ADISPLAY_ID_DEFAULT);
4664
4665 // When device reset happens, that key stream should be terminated with FLAG_CANCELED
4666 // on the app side.
Prabir Pradhan678438e2023-04-13 19:32:51 +00004667 mDispatcher->notifyDeviceReset({/*id=*/10, /*eventTime=*/20, DEVICE_ID});
Prabir Pradhan7662a8d2023-12-15 01:58:14 +00004668 window->consumeKeyUp(ADISPLAY_ID_DEFAULT, AKEY_EVENT_FLAG_CANCELED);
Siarhei Vishniakou2bfa9052019-11-21 18:10:54 -08004669}
4670
4671TEST_F(InputDispatcherTest, NotifyDeviceReset_CancelsMotionStream) {
Chris Yea209fde2020-07-22 13:54:51 -07004672 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07004673 sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher,
4674 "Fake Window", ADISPLAY_ID_DEFAULT);
Siarhei Vishniakou2bfa9052019-11-21 18:10:54 -08004675
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07004676 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Siarhei Vishniakou2bfa9052019-11-21 18:10:54 -08004677
Prabir Pradhan678438e2023-04-13 19:32:51 +00004678 mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_DOWN,
4679 AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT));
Siarhei Vishniakou2bfa9052019-11-21 18:10:54 -08004680
4681 // Window should receive motion down event.
4682 window->consumeMotionDown(ADISPLAY_ID_DEFAULT);
4683
4684 // When device reset happens, that motion stream should be terminated with ACTION_CANCEL
4685 // on the app side.
Prabir Pradhan678438e2023-04-13 19:32:51 +00004686 mDispatcher->notifyDeviceReset({/*id=*/10, /*eventTime=*/20, DEVICE_ID});
Siarhei Vishniakou1ae72f12023-01-29 12:55:30 -08004687 window->consumeMotionEvent(
4688 AllOf(WithMotionAction(ACTION_CANCEL), WithDisplayId(ADISPLAY_ID_DEFAULT)));
Siarhei Vishniakou2bfa9052019-11-21 18:10:54 -08004689}
4690
Siarhei Vishniakou0686f0c2023-05-02 11:56:15 -07004691TEST_F(InputDispatcherTest, NotifyDeviceResetCancelsHoveringStream) {
4692 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
4693 sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher,
4694 "Fake Window", ADISPLAY_ID_DEFAULT);
4695
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07004696 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Siarhei Vishniakou0686f0c2023-05-02 11:56:15 -07004697
4698 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_ENTER, AINPUT_SOURCE_STYLUS)
4699 .pointer(PointerBuilder(0, ToolType::STYLUS).x(10).y(10))
4700 .build());
4701
4702 window->consumeMotionEvent(WithMotionAction(ACTION_HOVER_ENTER));
4703
4704 // When device reset happens, that hover stream should be terminated with ACTION_HOVER_EXIT
4705 mDispatcher->notifyDeviceReset({/*id=*/10, /*eventTime=*/20, DEVICE_ID});
4706 window->consumeMotionEvent(WithMotionAction(ACTION_HOVER_EXIT));
4707
4708 // After the device has been reset, a new hovering stream can be sent to the window
4709 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_ENTER, AINPUT_SOURCE_STYLUS)
4710 .pointer(PointerBuilder(0, ToolType::STYLUS).x(15).y(15))
4711 .build());
4712 window->consumeMotionEvent(WithMotionAction(ACTION_HOVER_ENTER));
4713}
4714
Arthur Hung2ee6d0b2022-03-03 20:19:38 +08004715TEST_F(InputDispatcherTest, InterceptKeyByPolicy) {
4716 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07004717 sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher,
4718 "Fake Window", ADISPLAY_ID_DEFAULT);
Arthur Hung2ee6d0b2022-03-03 20:19:38 +08004719 window->setFocusable(true);
4720
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07004721 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Arthur Hung2ee6d0b2022-03-03 20:19:38 +08004722 setFocusedWindow(window);
4723
4724 window->consumeFocusEvent(true);
4725
Prabir Pradhan678438e2023-04-13 19:32:51 +00004726 const NotifyKeyArgs keyArgs = generateKeyArgs(AKEY_EVENT_ACTION_DOWN, ADISPLAY_ID_DEFAULT);
Arthur Hung2ee6d0b2022-03-03 20:19:38 +08004727 const std::chrono::milliseconds interceptKeyTimeout = 50ms;
4728 const nsecs_t injectTime = keyArgs.eventTime;
4729 mFakePolicy->setInterceptKeyTimeout(interceptKeyTimeout);
Prabir Pradhan678438e2023-04-13 19:32:51 +00004730 mDispatcher->notifyKey(keyArgs);
Arthur Hung2ee6d0b2022-03-03 20:19:38 +08004731 // The dispatching time should be always greater than or equal to intercept key timeout.
4732 window->consumeKeyDown(ADISPLAY_ID_DEFAULT);
4733 ASSERT_TRUE((systemTime(SYSTEM_TIME_MONOTONIC) - injectTime) >=
4734 std::chrono::nanoseconds(interceptKeyTimeout).count());
4735}
4736
Siarhei Vishniakouf54d2ab2023-06-09 13:23:53 -07004737/**
4738 * Keys with ACTION_UP are delivered immediately, even if a long 'intercept key timeout' is set.
4739 */
Arthur Hung2ee6d0b2022-03-03 20:19:38 +08004740TEST_F(InputDispatcherTest, InterceptKeyIfKeyUp) {
4741 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07004742 sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher,
4743 "Fake Window", ADISPLAY_ID_DEFAULT);
Arthur Hung2ee6d0b2022-03-03 20:19:38 +08004744 window->setFocusable(true);
4745
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07004746 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Arthur Hung2ee6d0b2022-03-03 20:19:38 +08004747 setFocusedWindow(window);
4748
4749 window->consumeFocusEvent(true);
4750
Prabir Pradhan678438e2023-04-13 19:32:51 +00004751 mDispatcher->notifyKey(generateKeyArgs(AKEY_EVENT_ACTION_DOWN, ADISPLAY_ID_DEFAULT));
Arthur Hung2ee6d0b2022-03-03 20:19:38 +08004752 window->consumeKeyDown(ADISPLAY_ID_DEFAULT);
Siarhei Vishniakouf54d2ab2023-06-09 13:23:53 -07004753
4754 // Set a value that's significantly larger than the default consumption timeout. If the
4755 // implementation is correct, the actual value doesn't matter; it won't slow down the test.
4756 mFakePolicy->setInterceptKeyTimeout(600ms);
4757 mDispatcher->notifyKey(generateKeyArgs(AKEY_EVENT_ACTION_UP, ADISPLAY_ID_DEFAULT));
4758 // Window should receive key event immediately when same key up.
Arthur Hung2ee6d0b2022-03-03 20:19:38 +08004759 window->consumeKeyUp(ADISPLAY_ID_DEFAULT);
4760}
4761
Prabir Pradhanc44ce4d2021-10-05 05:26:29 -07004762/**
Siarhei Vishniakou487c49b2022-12-02 15:48:57 -08004763 * Two windows. First is a regular window. Second does not overlap with the first, and has
4764 * WATCH_OUTSIDE_TOUCH.
4765 * Both windows are owned by the same UID.
4766 * Tap first window. Make sure that the second window receives ACTION_OUTSIDE with correct, non-zero
4767 * coordinates. The coordinates are not zeroed out because both windows are owned by the same UID.
4768 */
4769TEST_F(InputDispatcherTest, ActionOutsideForOwnedWindowHasValidCoordinates) {
4770 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -07004771 sp<FakeWindowHandle> window =
4772 sp<FakeWindowHandle>::make(application, mDispatcher, "Window", ADISPLAY_ID_DEFAULT);
Siarhei Vishniakou487c49b2022-12-02 15:48:57 -08004773 window->setFrame(Rect{0, 0, 100, 100});
4774
4775 sp<FakeWindowHandle> outsideWindow =
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -07004776 sp<FakeWindowHandle>::make(application, mDispatcher, "Outside Window",
Siarhei Vishniakou487c49b2022-12-02 15:48:57 -08004777 ADISPLAY_ID_DEFAULT);
4778 outsideWindow->setFrame(Rect{100, 100, 200, 200});
4779 outsideWindow->setWatchOutsideTouch(true);
4780 // outsideWindow must be above 'window' to receive ACTION_OUTSIDE events when 'window' is tapped
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07004781 mDispatcher->onWindowInfosChanged({{*outsideWindow->getInfo(), *window->getInfo()}, {}, 0, 0});
Siarhei Vishniakou487c49b2022-12-02 15:48:57 -08004782
4783 // Tap on first window.
Prabir Pradhan678438e2023-04-13 19:32:51 +00004784 mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_DOWN,
4785 AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
4786 {PointF{50, 50}}));
Siarhei Vishniakou487c49b2022-12-02 15:48:57 -08004787 window->consumeMotionDown();
4788 // The coordinates of the tap in 'outsideWindow' are relative to its top left corner.
4789 // Therefore, we should offset them by (100, 100) relative to the screen's top left corner.
4790 outsideWindow->consumeMotionEvent(
4791 AllOf(WithMotionAction(ACTION_OUTSIDE), WithCoords(-50, -50)));
Prabir Pradhan502a7252023-12-01 16:11:24 +00004792
4793 // Ensure outsideWindow doesn't get any more events for the gesture.
4794 mDispatcher->notifyMotion(generateMotionArgs(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN,
4795 ADISPLAY_ID_DEFAULT, {PointF{51, 51}}));
4796 window->consumeMotionMove();
4797 outsideWindow->assertNoEvents();
Siarhei Vishniakou487c49b2022-12-02 15:48:57 -08004798}
4799
4800/**
Prabir Pradhanb60b1dc2022-03-15 14:02:35 +00004801 * This test documents the behavior of WATCH_OUTSIDE_TOUCH. The window will get ACTION_OUTSIDE when
4802 * a another pointer causes ACTION_DOWN to be sent to another window for the first time. Only one
4803 * ACTION_OUTSIDE event is sent per gesture.
4804 */
4805TEST_F(InputDispatcherTest, ActionOutsideSentOnlyWhenAWindowIsTouched) {
4806 // There are three windows that do not overlap. `window` wants to WATCH_OUTSIDE_TOUCH.
4807 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07004808 sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher,
4809 "First Window", ADISPLAY_ID_DEFAULT);
Prabir Pradhanb60b1dc2022-03-15 14:02:35 +00004810 window->setWatchOutsideTouch(true);
4811 window->setFrame(Rect{0, 0, 100, 100});
4812 sp<FakeWindowHandle> secondWindow =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07004813 sp<FakeWindowHandle>::make(application, mDispatcher, "Second Window",
4814 ADISPLAY_ID_DEFAULT);
Prabir Pradhanb60b1dc2022-03-15 14:02:35 +00004815 secondWindow->setFrame(Rect{100, 100, 200, 200});
4816 sp<FakeWindowHandle> thirdWindow =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07004817 sp<FakeWindowHandle>::make(application, mDispatcher, "Third Window",
4818 ADISPLAY_ID_DEFAULT);
Prabir Pradhanb60b1dc2022-03-15 14:02:35 +00004819 thirdWindow->setFrame(Rect{200, 200, 300, 300});
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07004820 mDispatcher->onWindowInfosChanged(
4821 {{*window->getInfo(), *secondWindow->getInfo(), *thirdWindow->getInfo()}, {}, 0, 0});
Prabir Pradhanb60b1dc2022-03-15 14:02:35 +00004822
4823 // First pointer lands outside all windows. `window` does not get ACTION_OUTSIDE.
Prabir Pradhan678438e2023-04-13 19:32:51 +00004824 mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_DOWN,
4825 AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
4826 {PointF{-10, -10}}));
Prabir Pradhanb60b1dc2022-03-15 14:02:35 +00004827 window->assertNoEvents();
4828 secondWindow->assertNoEvents();
4829
4830 // The second pointer lands inside `secondWindow`, which should receive a DOWN event.
4831 // Now, `window` should get ACTION_OUTSIDE.
Prabir Pradhan678438e2023-04-13 19:32:51 +00004832 mDispatcher->notifyMotion(generateMotionArgs(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN,
4833 ADISPLAY_ID_DEFAULT,
4834 {PointF{-10, -10}, PointF{105, 105}}));
Siarhei Vishniakou487c49b2022-12-02 15:48:57 -08004835 const std::map<int32_t, PointF> expectedPointers{{0, PointF{-10, -10}}, {1, PointF{105, 105}}};
4836 window->consumeMotionEvent(
4837 AllOf(WithMotionAction(ACTION_OUTSIDE), WithPointers(expectedPointers)));
Prabir Pradhanb60b1dc2022-03-15 14:02:35 +00004838 secondWindow->consumeMotionDown();
4839 thirdWindow->assertNoEvents();
4840
4841 // The third pointer lands inside `thirdWindow`, which should receive a DOWN event. There is
4842 // no ACTION_OUTSIDE sent to `window` because one has already been sent for this gesture.
Prabir Pradhan678438e2023-04-13 19:32:51 +00004843 mDispatcher->notifyMotion(
4844 generateMotionArgs(POINTER_2_DOWN, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
4845 {PointF{-10, -10}, PointF{105, 105}, PointF{205, 205}}));
Prabir Pradhanb60b1dc2022-03-15 14:02:35 +00004846 window->assertNoEvents();
4847 secondWindow->consumeMotionMove();
4848 thirdWindow->consumeMotionDown();
4849}
4850
Prabir Pradhan814fe082022-07-22 20:22:18 +00004851TEST_F(InputDispatcherTest, OnWindowInfosChanged_RemoveAllWindowsOnDisplay) {
4852 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07004853 sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher,
4854 "Fake Window", ADISPLAY_ID_DEFAULT);
Prabir Pradhan814fe082022-07-22 20:22:18 +00004855 window->setFocusable(true);
4856
Patrick Williamsd828f302023-04-28 17:52:08 -05004857 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Prabir Pradhan814fe082022-07-22 20:22:18 +00004858 setFocusedWindow(window);
4859
4860 window->consumeFocusEvent(true);
4861
Prabir Pradhan678438e2023-04-13 19:32:51 +00004862 const NotifyKeyArgs keyDown = generateKeyArgs(AKEY_EVENT_ACTION_DOWN, ADISPLAY_ID_DEFAULT);
4863 const NotifyKeyArgs keyUp = generateKeyArgs(AKEY_EVENT_ACTION_UP, ADISPLAY_ID_DEFAULT);
4864 mDispatcher->notifyKey(keyDown);
4865 mDispatcher->notifyKey(keyUp);
Prabir Pradhan814fe082022-07-22 20:22:18 +00004866
4867 window->consumeKeyDown(ADISPLAY_ID_DEFAULT);
4868 window->consumeKeyUp(ADISPLAY_ID_DEFAULT);
4869
4870 // All windows are removed from the display. Ensure that we can no longer dispatch to it.
Patrick Williamsd828f302023-04-28 17:52:08 -05004871 mDispatcher->onWindowInfosChanged({{}, {}, 0, 0});
Prabir Pradhan814fe082022-07-22 20:22:18 +00004872
4873 window->consumeFocusEvent(false);
4874
Prabir Pradhan678438e2023-04-13 19:32:51 +00004875 mDispatcher->notifyKey(keyDown);
4876 mDispatcher->notifyKey(keyUp);
Prabir Pradhan814fe082022-07-22 20:22:18 +00004877 window->assertNoEvents();
4878}
4879
Arthur Hung96483742022-11-15 03:30:48 +00004880TEST_F(InputDispatcherTest, NonSplitTouchableWindowReceivesMultiTouch) {
4881 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
4882 sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher,
4883 "Fake Window", ADISPLAY_ID_DEFAULT);
4884 // Ensure window is non-split and have some transform.
4885 window->setPreventSplitting(true);
4886 window->setWindowOffset(20, 40);
Patrick Williamsd828f302023-04-28 17:52:08 -05004887 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Arthur Hung96483742022-11-15 03:30:48 +00004888
4889 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07004890 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
Arthur Hung96483742022-11-15 03:30:48 +00004891 {50, 50}))
4892 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
4893 window->consumeMotionDown(ADISPLAY_ID_DEFAULT);
4894
4895 const MotionEvent secondFingerDownEvent =
4896 MotionEventBuilder(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
4897 .displayId(ADISPLAY_ID_DEFAULT)
4898 .eventTime(systemTime(SYSTEM_TIME_MONOTONIC))
Siarhei Vishniakou6d73f832022-07-21 17:27:03 -07004899 .pointer(PointerBuilder(/*id=*/0, ToolType::FINGER).x(50).y(50))
4900 .pointer(PointerBuilder(/*id=*/1, ToolType::FINGER).x(-30).y(-50))
Arthur Hung96483742022-11-15 03:30:48 +00004901 .build();
4902 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07004903 injectMotionEvent(*mDispatcher, secondFingerDownEvent, INJECT_EVENT_TIMEOUT,
Arthur Hung96483742022-11-15 03:30:48 +00004904 InputEventInjectionSync::WAIT_FOR_RESULT))
4905 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
4906
Siarhei Vishniakoud3061ab2023-12-18 20:41:08 -08004907 std::unique_ptr<MotionEvent> event = window->consumeMotionEvent();
4908 ASSERT_NE(nullptr, event);
4909 EXPECT_EQ(POINTER_1_DOWN, event->getAction());
4910 EXPECT_EQ(70, event->getX(0)); // 50 + 20
4911 EXPECT_EQ(90, event->getY(0)); // 50 + 40
4912 EXPECT_EQ(-10, event->getX(1)); // -30 + 20
4913 EXPECT_EQ(-10, event->getY(1)); // -50 + 40
Arthur Hung96483742022-11-15 03:30:48 +00004914}
4915
Siarhei Vishniakou25537f82023-07-18 14:35:47 -07004916/**
4917 * Two windows: a splittable and a non-splittable.
4918 * The non-splittable window shouldn't receive any "incomplete" gestures.
4919 * Send the first pointer to the splittable window, and then touch the non-splittable window.
4920 * The second pointer should be dropped because the initial window is splittable, so it won't get
4921 * any pointers outside of it, and the second window is non-splittable, so it shouldn't get any
4922 * "incomplete" gestures.
4923 */
4924TEST_F(InputDispatcherTest, SplittableAndNonSplittableWindows) {
4925 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
4926 sp<FakeWindowHandle> leftWindow =
4927 sp<FakeWindowHandle>::make(application, mDispatcher, "Left splittable Window",
4928 ADISPLAY_ID_DEFAULT);
4929 leftWindow->setPreventSplitting(false);
4930 leftWindow->setFrame(Rect(0, 0, 100, 100));
4931 sp<FakeWindowHandle> rightWindow =
4932 sp<FakeWindowHandle>::make(application, mDispatcher, "Right non-splittable Window",
4933 ADISPLAY_ID_DEFAULT);
4934 rightWindow->setPreventSplitting(true);
4935 rightWindow->setFrame(Rect(100, 100, 200, 200));
4936 mDispatcher->onWindowInfosChanged(
4937 {{*leftWindow->getInfo(), *rightWindow->getInfo()}, {}, 0, 0});
4938
4939 // Touch down on left, splittable window
4940 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
4941 .pointer(PointerBuilder(0, ToolType::FINGER).x(50).y(50))
4942 .build());
4943 leftWindow->consumeMotionEvent(WithMotionAction(ACTION_DOWN));
4944
4945 mDispatcher->notifyMotion(
4946 MotionArgsBuilder(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
4947 .pointer(PointerBuilder(/*id=*/0, ToolType::FINGER).x(50).y(50))
4948 .pointer(PointerBuilder(/*id=*/1, ToolType::FINGER).x(150).y(150))
4949 .build());
4950 leftWindow->assertNoEvents();
4951 rightWindow->assertNoEvents();
4952}
4953
Harry Cuttsb166c002023-05-09 13:06:05 +00004954TEST_F(InputDispatcherTest, TouchpadThreeFingerSwipeOnlySentToTrustedOverlays) {
4955 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
4956 sp<FakeWindowHandle> window =
4957 sp<FakeWindowHandle>::make(application, mDispatcher, "Window", ADISPLAY_ID_DEFAULT);
4958 window->setFrame(Rect(0, 0, 400, 400));
4959 sp<FakeWindowHandle> trustedOverlay =
4960 sp<FakeWindowHandle>::make(application, mDispatcher, "Trusted Overlay",
4961 ADISPLAY_ID_DEFAULT);
4962 trustedOverlay->setSpy(true);
4963 trustedOverlay->setTrustedOverlay(true);
4964
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07004965 mDispatcher->onWindowInfosChanged({{*trustedOverlay->getInfo(), *window->getInfo()}, {}, 0, 0});
Harry Cuttsb166c002023-05-09 13:06:05 +00004966
4967 // Start a three-finger touchpad swipe
4968 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_MOUSE)
4969 .pointer(PointerBuilder(0, ToolType::FINGER).x(200).y(100))
4970 .classification(MotionClassification::MULTI_FINGER_SWIPE)
4971 .build());
4972 mDispatcher->notifyMotion(MotionArgsBuilder(POINTER_1_DOWN, AINPUT_SOURCE_MOUSE)
4973 .pointer(PointerBuilder(0, ToolType::FINGER).x(200).y(100))
4974 .pointer(PointerBuilder(1, ToolType::FINGER).x(250).y(100))
4975 .classification(MotionClassification::MULTI_FINGER_SWIPE)
4976 .build());
4977 mDispatcher->notifyMotion(MotionArgsBuilder(POINTER_2_DOWN, AINPUT_SOURCE_MOUSE)
4978 .pointer(PointerBuilder(0, ToolType::FINGER).x(200).y(100))
4979 .pointer(PointerBuilder(1, ToolType::FINGER).x(250).y(100))
4980 .pointer(PointerBuilder(2, ToolType::FINGER).x(300).y(100))
4981 .classification(MotionClassification::MULTI_FINGER_SWIPE)
4982 .build());
4983
4984 trustedOverlay->consumeMotionEvent(WithMotionAction(ACTION_DOWN));
4985 trustedOverlay->consumeMotionEvent(WithMotionAction(POINTER_1_DOWN));
4986 trustedOverlay->consumeMotionEvent(WithMotionAction(POINTER_2_DOWN));
4987
4988 // Move the swipe a bit
4989 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_MOUSE)
4990 .pointer(PointerBuilder(0, ToolType::FINGER).x(200).y(105))
4991 .pointer(PointerBuilder(1, ToolType::FINGER).x(250).y(105))
4992 .pointer(PointerBuilder(2, ToolType::FINGER).x(300).y(105))
4993 .classification(MotionClassification::MULTI_FINGER_SWIPE)
4994 .build());
4995
4996 trustedOverlay->consumeMotionEvent(WithMotionAction(ACTION_MOVE));
4997
4998 // End the swipe
4999 mDispatcher->notifyMotion(MotionArgsBuilder(POINTER_2_UP, AINPUT_SOURCE_MOUSE)
5000 .pointer(PointerBuilder(0, ToolType::FINGER).x(200).y(105))
5001 .pointer(PointerBuilder(1, ToolType::FINGER).x(250).y(105))
5002 .pointer(PointerBuilder(2, ToolType::FINGER).x(300).y(105))
5003 .classification(MotionClassification::MULTI_FINGER_SWIPE)
5004 .build());
5005 mDispatcher->notifyMotion(MotionArgsBuilder(POINTER_1_UP, AINPUT_SOURCE_MOUSE)
5006 .pointer(PointerBuilder(0, ToolType::FINGER).x(200).y(105))
5007 .pointer(PointerBuilder(1, ToolType::FINGER).x(250).y(105))
5008 .classification(MotionClassification::MULTI_FINGER_SWIPE)
5009 .build());
5010 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_UP, AINPUT_SOURCE_MOUSE)
5011 .pointer(PointerBuilder(0, ToolType::FINGER).x(200).y(105))
5012 .classification(MotionClassification::MULTI_FINGER_SWIPE)
5013 .build());
5014
5015 trustedOverlay->consumeMotionEvent(WithMotionAction(POINTER_2_UP));
5016 trustedOverlay->consumeMotionEvent(WithMotionAction(POINTER_1_UP));
5017 trustedOverlay->consumeMotionEvent(WithMotionAction(ACTION_UP));
5018
5019 window->assertNoEvents();
5020}
5021
5022TEST_F(InputDispatcherTest, TouchpadThreeFingerSwipeNotSentToSingleWindow) {
5023 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
5024 sp<FakeWindowHandle> window =
5025 sp<FakeWindowHandle>::make(application, mDispatcher, "Window", ADISPLAY_ID_DEFAULT);
5026 window->setFrame(Rect(0, 0, 400, 400));
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07005027 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Harry Cuttsb166c002023-05-09 13:06:05 +00005028
5029 // Start a three-finger touchpad swipe
5030 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_MOUSE)
5031 .pointer(PointerBuilder(0, ToolType::FINGER).x(200).y(100))
5032 .classification(MotionClassification::MULTI_FINGER_SWIPE)
5033 .build());
5034 mDispatcher->notifyMotion(MotionArgsBuilder(POINTER_1_DOWN, AINPUT_SOURCE_MOUSE)
5035 .pointer(PointerBuilder(0, ToolType::FINGER).x(200).y(100))
5036 .pointer(PointerBuilder(1, ToolType::FINGER).x(250).y(100))
5037 .classification(MotionClassification::MULTI_FINGER_SWIPE)
5038 .build());
5039 mDispatcher->notifyMotion(MotionArgsBuilder(POINTER_2_DOWN, AINPUT_SOURCE_MOUSE)
5040 .pointer(PointerBuilder(0, ToolType::FINGER).x(200).y(100))
5041 .pointer(PointerBuilder(1, ToolType::FINGER).x(250).y(100))
5042 .pointer(PointerBuilder(2, ToolType::FINGER).x(300).y(100))
5043 .classification(MotionClassification::MULTI_FINGER_SWIPE)
5044 .build());
5045
5046 // Move the swipe a bit
5047 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_MOUSE)
5048 .pointer(PointerBuilder(0, ToolType::FINGER).x(200).y(105))
5049 .pointer(PointerBuilder(1, ToolType::FINGER).x(250).y(105))
5050 .pointer(PointerBuilder(2, ToolType::FINGER).x(300).y(105))
5051 .classification(MotionClassification::MULTI_FINGER_SWIPE)
5052 .build());
5053
5054 // End the swipe
5055 mDispatcher->notifyMotion(MotionArgsBuilder(POINTER_2_UP, AINPUT_SOURCE_MOUSE)
5056 .pointer(PointerBuilder(0, ToolType::FINGER).x(200).y(105))
5057 .pointer(PointerBuilder(1, ToolType::FINGER).x(250).y(105))
5058 .pointer(PointerBuilder(2, ToolType::FINGER).x(300).y(105))
5059 .classification(MotionClassification::MULTI_FINGER_SWIPE)
5060 .build());
5061 mDispatcher->notifyMotion(MotionArgsBuilder(POINTER_1_UP, AINPUT_SOURCE_MOUSE)
5062 .pointer(PointerBuilder(0, ToolType::FINGER).x(200).y(105))
5063 .pointer(PointerBuilder(1, ToolType::FINGER).x(250).y(105))
5064 .classification(MotionClassification::MULTI_FINGER_SWIPE)
5065 .build());
5066 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_UP, AINPUT_SOURCE_MOUSE)
5067 .pointer(PointerBuilder(0, ToolType::FINGER).x(200).y(105))
5068 .classification(MotionClassification::MULTI_FINGER_SWIPE)
5069 .build());
5070
5071 window->assertNoEvents();
5072}
5073
Prabir Pradhanb60b1dc2022-03-15 14:02:35 +00005074/**
Siarhei Vishniakouadb9fc92023-05-26 10:46:09 -07005075 * Send a two-pointer gesture to a single window. The window's orientation changes in response to
5076 * the first pointer.
Prabir Pradhan69d00bf2023-06-23 19:55:18 +00005077 * Ensure that the second pointer and the subsequent gesture is correctly delivered to the window.
Siarhei Vishniakouadb9fc92023-05-26 10:46:09 -07005078 */
5079TEST_F(InputDispatcherTest, MultiplePointersWithRotatingWindow) {
5080 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
5081 sp<FakeWindowHandle> window =
5082 sp<FakeWindowHandle>::make(application, mDispatcher, "Window", ADISPLAY_ID_DEFAULT);
5083 window->setFrame(Rect(0, 0, 400, 400));
Siarhei Vishniakou700424c2023-07-18 17:18:42 -07005084 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Siarhei Vishniakouadb9fc92023-05-26 10:46:09 -07005085
5086 const nsecs_t baseTime = systemTime(SYSTEM_TIME_MONOTONIC);
5087 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
5088 .downTime(baseTime + 10)
5089 .eventTime(baseTime + 10)
5090 .pointer(PointerBuilder(0, ToolType::FINGER).x(100).y(100))
5091 .build());
5092
5093 window->consumeMotionEvent(WithMotionAction(ACTION_DOWN));
5094
Siarhei Vishniakouadb9fc92023-05-26 10:46:09 -07005095 // Change the transform so that the orientation is now different from original.
Siarhei Vishniakou700424c2023-07-18 17:18:42 -07005096 window->setWindowTransform(0, -1, 1, 0);
Siarhei Vishniakouadb9fc92023-05-26 10:46:09 -07005097
Siarhei Vishniakou700424c2023-07-18 17:18:42 -07005098 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Siarhei Vishniakouadb9fc92023-05-26 10:46:09 -07005099
Siarhei Vishniakouadb9fc92023-05-26 10:46:09 -07005100 mDispatcher->notifyMotion(MotionArgsBuilder(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
5101 .downTime(baseTime + 10)
5102 .eventTime(baseTime + 30)
5103 .pointer(PointerBuilder(0, ToolType::FINGER).x(100).y(100))
5104 .pointer(PointerBuilder(1, ToolType::FINGER).x(200).y(200))
5105 .build());
5106
Prabir Pradhan69d00bf2023-06-23 19:55:18 +00005107 window->consumeMotionEvent(WithMotionAction(POINTER_1_DOWN));
5108
5109 // Finish the gesture and start a new one. Ensure all events are sent to the window.
Siarhei Vishniakouadb9fc92023-05-26 10:46:09 -07005110 mDispatcher->notifyMotion(MotionArgsBuilder(POINTER_1_UP, AINPUT_SOURCE_TOUCHSCREEN)
5111 .downTime(baseTime + 10)
5112 .eventTime(baseTime + 40)
5113 .pointer(PointerBuilder(0, ToolType::FINGER).x(100).y(100))
5114 .pointer(PointerBuilder(1, ToolType::FINGER).x(200).y(200))
5115 .build());
Prabir Pradhan69d00bf2023-06-23 19:55:18 +00005116
5117 window->consumeMotionEvent(WithMotionAction(POINTER_1_UP));
5118
Siarhei Vishniakouadb9fc92023-05-26 10:46:09 -07005119 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN)
5120 .downTime(baseTime + 10)
5121 .eventTime(baseTime + 50)
5122 .pointer(PointerBuilder(0, ToolType::FINGER).x(100).y(100))
5123 .build());
5124
Prabir Pradhan69d00bf2023-06-23 19:55:18 +00005125 window->consumeMotionEvent(WithMotionAction(ACTION_UP));
5126
Siarhei Vishniakouadb9fc92023-05-26 10:46:09 -07005127 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
5128 .downTime(baseTime + 60)
5129 .eventTime(baseTime + 60)
5130 .pointer(PointerBuilder(0, ToolType::FINGER).x(40).y(40))
5131 .build());
5132
Siarhei Vishniakou700424c2023-07-18 17:18:42 -07005133 window->consumeMotionEvent(WithMotionAction(ACTION_DOWN));
Siarhei Vishniakouadb9fc92023-05-26 10:46:09 -07005134}
5135
5136/**
Hu Guo771a7692023-09-17 20:51:08 +08005137 * When there are multiple screens, such as screen projection to TV or screen recording, if the
5138 * cancel event occurs, the coordinates of the cancel event should be sent to the target screen, and
5139 * its coordinates should be converted by the transform of the windows of target screen.
5140 */
5141TEST_F(InputDispatcherTest, WhenMultiDisplayWindowSameToken_DispatchCancelToTargetDisplay) {
5142 // This case will create a window and a spy window on the default display and mirror
5143 // window on the second display. cancel event is sent through spy window pilferPointers
5144 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
5145
5146 sp<FakeWindowHandle> spyWindowDefaultDisplay =
5147 sp<FakeWindowHandle>::make(application, mDispatcher, "Spy", ADISPLAY_ID_DEFAULT);
5148 spyWindowDefaultDisplay->setTrustedOverlay(true);
5149 spyWindowDefaultDisplay->setSpy(true);
5150
5151 sp<FakeWindowHandle> windowDefaultDisplay =
5152 sp<FakeWindowHandle>::make(application, mDispatcher, "DefaultDisplay",
5153 ADISPLAY_ID_DEFAULT);
5154 windowDefaultDisplay->setWindowTransform(1, 0, 0, 1);
5155
5156 sp<FakeWindowHandle> windowSecondDisplay = windowDefaultDisplay->clone(SECOND_DISPLAY_ID);
5157 windowSecondDisplay->setWindowTransform(2, 0, 0, 2);
5158
5159 // Add the windows to the dispatcher
5160 mDispatcher->onWindowInfosChanged(
5161 {{*spyWindowDefaultDisplay->getInfo(), *windowDefaultDisplay->getInfo(),
5162 *windowSecondDisplay->getInfo()},
5163 {},
5164 0,
5165 0});
5166
5167 // Send down to ADISPLAY_ID_DEFAULT
5168 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
5169 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
5170 {100, 100}))
5171 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
5172
5173 spyWindowDefaultDisplay->consumeMotionDown();
5174 windowDefaultDisplay->consumeMotionDown();
5175
5176 EXPECT_EQ(OK, mDispatcher->pilferPointers(spyWindowDefaultDisplay->getToken()));
5177
5178 // windowDefaultDisplay gets cancel
Siarhei Vishniakoud3061ab2023-12-18 20:41:08 -08005179 std::unique_ptr<MotionEvent> event = windowDefaultDisplay->consumeMotionEvent();
5180 ASSERT_NE(nullptr, event);
5181 EXPECT_EQ(AMOTION_EVENT_ACTION_CANCEL, event->getAction());
Hu Guo771a7692023-09-17 20:51:08 +08005182
5183 // The cancel event is sent to windowDefaultDisplay of the ADISPLAY_ID_DEFAULT display, so the
5184 // coordinates of the cancel are converted by windowDefaultDisplay's transform, the x and y
5185 // coordinates are both 100, otherwise if the cancel event is sent to windowSecondDisplay of
5186 // SECOND_DISPLAY_ID, the x and y coordinates are 200
Siarhei Vishniakoud3061ab2023-12-18 20:41:08 -08005187 EXPECT_EQ(100, event->getX(0));
5188 EXPECT_EQ(100, event->getY(0));
Hu Guo771a7692023-09-17 20:51:08 +08005189}
5190
5191/**
Prabir Pradhanc44ce4d2021-10-05 05:26:29 -07005192 * Ensure the correct coordinate spaces are used by InputDispatcher.
5193 *
5194 * InputDispatcher works in the display space, so its coordinate system is relative to the display
5195 * panel. Windows get events in the window space, and get raw coordinates in the logical display
5196 * space.
5197 */
5198class InputDispatcherDisplayProjectionTest : public InputDispatcherTest {
5199public:
5200 void SetUp() override {
5201 InputDispatcherTest::SetUp();
Prabir Pradhan33e3baa2022-12-06 20:30:22 +00005202 removeAllWindowsAndDisplays();
Prabir Pradhanc44ce4d2021-10-05 05:26:29 -07005203 }
5204
5205 void addDisplayInfo(int displayId, const ui::Transform& transform) {
5206 gui::DisplayInfo info;
5207 info.displayId = displayId;
5208 info.transform = transform;
5209 mDisplayInfos.push_back(std::move(info));
Patrick Williamsd828f302023-04-28 17:52:08 -05005210 mDispatcher->onWindowInfosChanged({mWindowInfos, mDisplayInfos, 0, 0});
Prabir Pradhanc44ce4d2021-10-05 05:26:29 -07005211 }
5212
5213 void addWindow(const sp<WindowInfoHandle>& windowHandle) {
5214 mWindowInfos.push_back(*windowHandle->getInfo());
Patrick Williamsd828f302023-04-28 17:52:08 -05005215 mDispatcher->onWindowInfosChanged({mWindowInfos, mDisplayInfos, 0, 0});
Prabir Pradhanc44ce4d2021-10-05 05:26:29 -07005216 }
5217
Prabir Pradhan33e3baa2022-12-06 20:30:22 +00005218 void removeAllWindowsAndDisplays() {
5219 mDisplayInfos.clear();
5220 mWindowInfos.clear();
5221 }
5222
Prabir Pradhanc44ce4d2021-10-05 05:26:29 -07005223 // Set up a test scenario where the display has a scaled projection and there are two windows
5224 // on the display.
5225 std::pair<sp<FakeWindowHandle>, sp<FakeWindowHandle>> setupScaledDisplayScenario() {
5226 // The display has a projection that has a scale factor of 2 and 4 in the x and y directions
5227 // respectively.
5228 ui::Transform displayTransform;
5229 displayTransform.set(2, 0, 0, 4);
5230 addDisplayInfo(ADISPLAY_ID_DEFAULT, displayTransform);
5231
5232 std::shared_ptr<FakeApplicationHandle> application =
5233 std::make_shared<FakeApplicationHandle>();
5234
5235 // Add two windows to the display. Their frames are represented in the display space.
5236 sp<FakeWindowHandle> firstWindow =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07005237 sp<FakeWindowHandle>::make(application, mDispatcher, "First Window",
5238 ADISPLAY_ID_DEFAULT);
Prabir Pradhanc44ce4d2021-10-05 05:26:29 -07005239 firstWindow->setFrame(Rect(0, 0, 100, 200), displayTransform);
5240 addWindow(firstWindow);
5241
5242 sp<FakeWindowHandle> secondWindow =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07005243 sp<FakeWindowHandle>::make(application, mDispatcher, "Second Window",
5244 ADISPLAY_ID_DEFAULT);
Prabir Pradhanc44ce4d2021-10-05 05:26:29 -07005245 secondWindow->setFrame(Rect(100, 200, 200, 400), displayTransform);
5246 addWindow(secondWindow);
5247 return {std::move(firstWindow), std::move(secondWindow)};
5248 }
5249
5250private:
5251 std::vector<gui::DisplayInfo> mDisplayInfos;
5252 std::vector<gui::WindowInfo> mWindowInfos;
5253};
5254
Prabir Pradhan33e3baa2022-12-06 20:30:22 +00005255TEST_F(InputDispatcherDisplayProjectionTest, HitTestCoordinateSpaceConsistency) {
Prabir Pradhanc44ce4d2021-10-05 05:26:29 -07005256 auto [firstWindow, secondWindow] = setupScaledDisplayScenario();
5257 // Send down to the first window. The point is represented in the display space. The point is
Prabir Pradhan33e3baa2022-12-06 20:30:22 +00005258 // selected so that if the hit test was performed with the point and the bounds being in
5259 // different coordinate spaces, the event would end up in the incorrect window.
Prabir Pradhan678438e2023-04-13 19:32:51 +00005260 mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_DOWN,
5261 AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
5262 {PointF{75, 55}}));
Prabir Pradhanc44ce4d2021-10-05 05:26:29 -07005263
5264 firstWindow->consumeMotionDown();
5265 secondWindow->assertNoEvents();
5266}
5267
5268// Ensure that when a MotionEvent is injected through the InputDispatcher::injectInputEvent() API,
5269// the event should be treated as being in the logical display space.
5270TEST_F(InputDispatcherDisplayProjectionTest, InjectionInLogicalDisplaySpace) {
5271 auto [firstWindow, secondWindow] = setupScaledDisplayScenario();
5272 // Send down to the first window. The point is represented in the logical display space. The
5273 // point is selected so that if the hit test was done in logical display space, then it would
5274 // end up in the incorrect window.
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07005275 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
Prabir Pradhanc44ce4d2021-10-05 05:26:29 -07005276 PointF{75 * 2, 55 * 4});
5277
5278 firstWindow->consumeMotionDown();
5279 secondWindow->assertNoEvents();
5280}
5281
Prabir Pradhandaa2f142021-12-10 09:30:08 +00005282// Ensure that when a MotionEvent that has a custom transform is injected, the post-transformed
5283// event should be treated as being in the logical display space.
5284TEST_F(InputDispatcherDisplayProjectionTest, InjectionWithTransformInLogicalDisplaySpace) {
5285 auto [firstWindow, secondWindow] = setupScaledDisplayScenario();
5286
5287 const std::array<float, 9> matrix = {1.1, 2.2, 3.3, 4.4, 5.5, 6.6, 0.0, 0.0, 1.0};
5288 ui::Transform injectedEventTransform;
5289 injectedEventTransform.set(matrix);
5290 const vec2 expectedPoint{75, 55}; // The injected point in the logical display space.
5291 const vec2 untransformedPoint = injectedEventTransform.inverse().transform(expectedPoint);
5292
5293 MotionEvent event = MotionEventBuilder(AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
5294 .displayId(ADISPLAY_ID_DEFAULT)
5295 .eventTime(systemTime(SYSTEM_TIME_MONOTONIC))
Siarhei Vishniakou6d73f832022-07-21 17:27:03 -07005296 .pointer(PointerBuilder(/*id=*/0, ToolType::FINGER)
Prabir Pradhandaa2f142021-12-10 09:30:08 +00005297 .x(untransformedPoint.x)
5298 .y(untransformedPoint.y))
5299 .build();
5300 event.transform(matrix);
5301
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07005302 injectMotionEvent(*mDispatcher, event, INJECT_EVENT_TIMEOUT,
Prabir Pradhandaa2f142021-12-10 09:30:08 +00005303 InputEventInjectionSync::WAIT_FOR_RESULT);
5304
5305 firstWindow->consumeMotionDown();
5306 secondWindow->assertNoEvents();
5307}
5308
Prabir Pradhanc44ce4d2021-10-05 05:26:29 -07005309TEST_F(InputDispatcherDisplayProjectionTest, WindowGetsEventsInCorrectCoordinateSpace) {
5310 auto [firstWindow, secondWindow] = setupScaledDisplayScenario();
5311
5312 // Send down to the second window.
Prabir Pradhan678438e2023-04-13 19:32:51 +00005313 mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_DOWN,
5314 AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
5315 {PointF{150, 220}}));
Prabir Pradhanc44ce4d2021-10-05 05:26:29 -07005316
5317 firstWindow->assertNoEvents();
Siarhei Vishniakoud3061ab2023-12-18 20:41:08 -08005318 std::unique_ptr<MotionEvent> event = secondWindow->consumeMotionEvent();
5319 ASSERT_NE(nullptr, event);
5320 EXPECT_EQ(AMOTION_EVENT_ACTION_DOWN, event->getAction());
Prabir Pradhanc44ce4d2021-10-05 05:26:29 -07005321
5322 // Ensure that the events from the "getRaw" API are in logical display coordinates.
Siarhei Vishniakoud3061ab2023-12-18 20:41:08 -08005323 EXPECT_EQ(300, event->getRawX(0));
5324 EXPECT_EQ(880, event->getRawY(0));
Prabir Pradhanc44ce4d2021-10-05 05:26:29 -07005325
5326 // Ensure that the x and y values are in the window's coordinate space.
5327 // The left-top of the second window is at (100, 200) in display space, which is (200, 800) in
5328 // the logical display space. This will be the origin of the window space.
Siarhei Vishniakoud3061ab2023-12-18 20:41:08 -08005329 EXPECT_EQ(100, event->getX(0));
5330 EXPECT_EQ(80, event->getY(0));
Prabir Pradhanc44ce4d2021-10-05 05:26:29 -07005331}
5332
Prabir Pradhan112b1ad2023-09-21 09:53:53 +00005333TEST_F(InputDispatcherDisplayProjectionTest, CancelMotionWithCorrectCoordinates) {
5334 auto [firstWindow, secondWindow] = setupScaledDisplayScenario();
5335 // The monitor will always receive events in the logical display's coordinate space, because
5336 // it does not have a window.
Prabir Pradhanfb549072023-10-05 19:17:36 +00005337 FakeMonitorReceiver monitor{*mDispatcher, "Monitor", ADISPLAY_ID_DEFAULT};
Prabir Pradhan112b1ad2023-09-21 09:53:53 +00005338
5339 // Send down to the first window.
5340 mDispatcher->notifyMotion(generateMotionArgs(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN,
5341 ADISPLAY_ID_DEFAULT, {PointF{50, 100}}));
5342 firstWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithCoords(100, 400)));
5343 monitor.consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithCoords(100, 400)));
5344
5345 // Second pointer goes down on second window.
5346 mDispatcher->notifyMotion(generateMotionArgs(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN,
5347 ADISPLAY_ID_DEFAULT,
5348 {PointF{50, 100}, PointF{150, 220}}));
5349 secondWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithCoords(100, 80)));
5350 const std::map<int32_t, PointF> expectedMonitorPointers{{0, PointF{100, 400}},
5351 {1, PointF{300, 880}}};
5352 monitor.consumeMotionEvent(
5353 AllOf(WithMotionAction(POINTER_1_DOWN), WithPointers(expectedMonitorPointers)));
5354
5355 mDispatcher->cancelCurrentTouch();
5356
5357 firstWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_CANCEL), WithCoords(100, 400)));
5358 secondWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_CANCEL), WithCoords(100, 80)));
5359 monitor.consumeMotionEvent(
5360 AllOf(WithMotionAction(ACTION_CANCEL), WithPointers(expectedMonitorPointers)));
5361}
5362
Prabir Pradhan1c29a092023-09-21 10:29:29 +00005363TEST_F(InputDispatcherDisplayProjectionTest, SynthesizeDownWithCorrectCoordinates) {
5364 auto [firstWindow, secondWindow] = setupScaledDisplayScenario();
5365
5366 // Send down to the first window.
5367 mDispatcher->notifyMotion(generateMotionArgs(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN,
5368 ADISPLAY_ID_DEFAULT, {PointF{50, 100}}));
5369 firstWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithCoords(100, 400)));
5370
5371 // The pointer is transferred to the second window, and the second window receives it in the
5372 // correct coordinate space.
Prabir Pradhan367f3432024-02-13 23:05:58 +00005373 mDispatcher->transferTouchGesture(firstWindow->getToken(), secondWindow->getToken());
Prabir Pradhan1c29a092023-09-21 10:29:29 +00005374 firstWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_CANCEL), WithCoords(100, 400)));
5375 secondWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithCoords(-100, -400)));
5376}
5377
Prabir Pradhan0dfcac72023-10-05 20:04:21 +00005378TEST_F(InputDispatcherDisplayProjectionTest, SynthesizeHoverEnterExitWithCorrectCoordinates) {
5379 auto [firstWindow, secondWindow] = setupScaledDisplayScenario();
5380
5381 // Send hover move to the second window, and ensure it shows up as hover enter.
5382 mDispatcher->notifyMotion(generateMotionArgs(ACTION_HOVER_MOVE, AINPUT_SOURCE_STYLUS,
5383 ADISPLAY_ID_DEFAULT, {PointF{150, 220}}));
5384 secondWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_HOVER_ENTER),
5385 WithCoords(100, 80), WithRawCoords(300, 880)));
5386
5387 // Touch down at the same location and ensure a hover exit is synthesized.
5388 mDispatcher->notifyMotion(generateMotionArgs(ACTION_DOWN, AINPUT_SOURCE_STYLUS,
5389 ADISPLAY_ID_DEFAULT, {PointF{150, 220}}));
5390 secondWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_HOVER_EXIT), WithCoords(100, 80),
5391 WithRawCoords(300, 880)));
5392 secondWindow->consumeMotionEvent(
5393 AllOf(WithMotionAction(ACTION_DOWN), WithCoords(100, 80), WithRawCoords(300, 880)));
5394 secondWindow->assertNoEvents();
5395 firstWindow->assertNoEvents();
5396}
5397
Prabir Pradhan453ae732023-10-13 14:30:14 +00005398// Same as above, but while the window is being mirrored.
5399TEST_F(InputDispatcherDisplayProjectionTest,
5400 SynthesizeHoverEnterExitWithCorrectCoordinatesWhenMirrored) {
5401 auto [firstWindow, secondWindow] = setupScaledDisplayScenario();
5402
5403 const std::array<float, 9> matrix = {1.1, 2.2, 3.3, 4.4, 5.5, 6.6, 0.0, 0.0, 1.0};
5404 ui::Transform secondDisplayTransform;
5405 secondDisplayTransform.set(matrix);
5406 addDisplayInfo(SECOND_DISPLAY_ID, secondDisplayTransform);
5407
5408 sp<FakeWindowHandle> secondWindowClone = secondWindow->clone(SECOND_DISPLAY_ID);
5409 secondWindowClone->setWindowTransform(1.1, 2.2, 3.3, 4.4);
5410 addWindow(secondWindowClone);
5411
5412 // Send hover move to the second window, and ensure it shows up as hover enter.
5413 mDispatcher->notifyMotion(generateMotionArgs(ACTION_HOVER_MOVE, AINPUT_SOURCE_STYLUS,
5414 ADISPLAY_ID_DEFAULT, {PointF{150, 220}}));
5415 secondWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_HOVER_ENTER),
5416 WithCoords(100, 80), WithRawCoords(300, 880)));
5417
5418 // Touch down at the same location and ensure a hover exit is synthesized for the correct
5419 // display.
5420 mDispatcher->notifyMotion(generateMotionArgs(ACTION_DOWN, AINPUT_SOURCE_STYLUS,
5421 ADISPLAY_ID_DEFAULT, {PointF{150, 220}}));
5422 secondWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_HOVER_EXIT), WithCoords(100, 80),
5423 WithRawCoords(300, 880)));
5424 secondWindow->consumeMotionEvent(
5425 AllOf(WithMotionAction(ACTION_DOWN), WithCoords(100, 80), WithRawCoords(300, 880)));
5426 secondWindow->assertNoEvents();
5427 firstWindow->assertNoEvents();
5428}
5429
Prabir Pradhan0dfcac72023-10-05 20:04:21 +00005430TEST_F(InputDispatcherDisplayProjectionTest, SynthesizeHoverCancelationWithCorrectCoordinates) {
5431 auto [firstWindow, secondWindow] = setupScaledDisplayScenario();
5432
5433 // Send hover enter to second window
5434 mDispatcher->notifyMotion(generateMotionArgs(ACTION_HOVER_ENTER, AINPUT_SOURCE_STYLUS,
5435 ADISPLAY_ID_DEFAULT, {PointF{150, 220}}));
5436 secondWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_HOVER_ENTER),
5437 WithCoords(100, 80), WithRawCoords(300, 880)));
5438
5439 mDispatcher->cancelCurrentTouch();
5440
5441 secondWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_HOVER_EXIT), WithCoords(100, 80),
5442 WithRawCoords(300, 880)));
5443 secondWindow->assertNoEvents();
5444 firstWindow->assertNoEvents();
5445}
5446
Prabir Pradhan453ae732023-10-13 14:30:14 +00005447// Same as above, but while the window is being mirrored.
Prabir Pradhan16463382023-10-12 23:03:19 +00005448TEST_F(InputDispatcherDisplayProjectionTest,
5449 SynthesizeHoverCancelationWithCorrectCoordinatesWhenMirrored) {
5450 auto [firstWindow, secondWindow] = setupScaledDisplayScenario();
5451
5452 const std::array<float, 9> matrix = {1.1, 2.2, 3.3, 4.4, 5.5, 6.6, 0.0, 0.0, 1.0};
5453 ui::Transform secondDisplayTransform;
5454 secondDisplayTransform.set(matrix);
5455 addDisplayInfo(SECOND_DISPLAY_ID, secondDisplayTransform);
5456
5457 sp<FakeWindowHandle> secondWindowClone = secondWindow->clone(SECOND_DISPLAY_ID);
5458 secondWindowClone->setWindowTransform(1.1, 2.2, 3.3, 4.4);
5459 addWindow(secondWindowClone);
5460
5461 // Send hover enter to second window
5462 mDispatcher->notifyMotion(generateMotionArgs(ACTION_HOVER_ENTER, AINPUT_SOURCE_STYLUS,
5463 ADISPLAY_ID_DEFAULT, {PointF{150, 220}}));
5464 secondWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_HOVER_ENTER),
5465 WithCoords(100, 80), WithRawCoords(300, 880),
5466 WithDisplayId(ADISPLAY_ID_DEFAULT)));
5467
5468 mDispatcher->cancelCurrentTouch();
5469
5470 // Ensure the cancelation happens with the correct displayId and the correct coordinates.
5471 secondWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_HOVER_EXIT), WithCoords(100, 80),
5472 WithRawCoords(300, 880),
5473 WithDisplayId(ADISPLAY_ID_DEFAULT)));
5474 secondWindow->assertNoEvents();
5475 firstWindow->assertNoEvents();
5476}
5477
Prabir Pradhan33e3baa2022-12-06 20:30:22 +00005478/** Ensure consistent behavior of InputDispatcher in all orientations. */
5479class InputDispatcherDisplayOrientationFixture
5480 : public InputDispatcherDisplayProjectionTest,
5481 public ::testing::WithParamInterface<ui::Rotation> {};
5482
5483// This test verifies the touchable region of a window for all rotations of the display by tapping
5484// in different locations on the display, specifically points close to the four corners of a
5485// window.
5486TEST_P(InputDispatcherDisplayOrientationFixture, HitTestInDifferentOrientations) {
5487 constexpr static int32_t displayWidth = 400;
5488 constexpr static int32_t displayHeight = 800;
5489
5490 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
5491
5492 const auto rotation = GetParam();
5493
5494 // Set up the display with the specified rotation.
5495 const bool isRotated = rotation == ui::ROTATION_90 || rotation == ui::ROTATION_270;
5496 const int32_t logicalDisplayWidth = isRotated ? displayHeight : displayWidth;
5497 const int32_t logicalDisplayHeight = isRotated ? displayWidth : displayHeight;
5498 const ui::Transform displayTransform(ui::Transform::toRotationFlags(rotation),
5499 logicalDisplayWidth, logicalDisplayHeight);
5500 addDisplayInfo(ADISPLAY_ID_DEFAULT, displayTransform);
5501
5502 // Create a window with its bounds determined in the logical display.
5503 const Rect frameInLogicalDisplay(100, 100, 200, 300);
5504 const Rect frameInDisplay = displayTransform.inverse().transform(frameInLogicalDisplay);
5505 sp<FakeWindowHandle> window =
5506 sp<FakeWindowHandle>::make(application, mDispatcher, "Window", ADISPLAY_ID_DEFAULT);
5507 window->setFrame(frameInDisplay, displayTransform);
5508 addWindow(window);
5509
5510 // The following points in logical display space should be inside the window.
5511 static const std::array<vec2, 4> insidePoints{
5512 {{100, 100}, {199.99, 100}, {100, 299.99}, {199.99, 299.99}}};
5513 for (const auto pointInsideWindow : insidePoints) {
5514 const vec2 p = displayTransform.inverse().transform(pointInsideWindow);
5515 const PointF pointInDisplaySpace{p.x, p.y};
Prabir Pradhan678438e2023-04-13 19:32:51 +00005516 mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_DOWN,
5517 AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
5518 {pointInDisplaySpace}));
Prabir Pradhan33e3baa2022-12-06 20:30:22 +00005519 window->consumeMotionDown();
5520
Prabir Pradhan678438e2023-04-13 19:32:51 +00005521 mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_UP,
5522 AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
5523 {pointInDisplaySpace}));
Prabir Pradhan33e3baa2022-12-06 20:30:22 +00005524 window->consumeMotionUp();
5525 }
5526
5527 // The following points in logical display space should be outside the window.
5528 static const std::array<vec2, 5> outsidePoints{
5529 {{200, 100}, {100, 300}, {200, 300}, {100, 99.99}, {99.99, 100}}};
5530 for (const auto pointOutsideWindow : outsidePoints) {
5531 const vec2 p = displayTransform.inverse().transform(pointOutsideWindow);
5532 const PointF pointInDisplaySpace{p.x, p.y};
Prabir Pradhan678438e2023-04-13 19:32:51 +00005533 mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_DOWN,
5534 AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
5535 {pointInDisplaySpace}));
Prabir Pradhan33e3baa2022-12-06 20:30:22 +00005536
Prabir Pradhan678438e2023-04-13 19:32:51 +00005537 mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_UP,
5538 AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
5539 {pointInDisplaySpace}));
Prabir Pradhan33e3baa2022-12-06 20:30:22 +00005540 }
5541 window->assertNoEvents();
5542}
5543
Linnan Li5e5645e2024-03-05 14:43:05 +00005544// This test verifies the occlusion detection for all rotations of the display by tapping
5545// in different locations on the display, specifically points close to the four corners of a
5546// window.
5547TEST_P(InputDispatcherDisplayOrientationFixture, BlockUntrustClickInDifferentOrientations) {
5548 constexpr static int32_t displayWidth = 400;
5549 constexpr static int32_t displayHeight = 800;
5550
5551 std::shared_ptr<FakeApplicationHandle> untrustedWindowApplication =
5552 std::make_shared<FakeApplicationHandle>();
5553 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
5554
5555 const auto rotation = GetParam();
5556
5557 // Set up the display with the specified rotation.
5558 const bool isRotated = rotation == ui::ROTATION_90 || rotation == ui::ROTATION_270;
5559 const int32_t logicalDisplayWidth = isRotated ? displayHeight : displayWidth;
5560 const int32_t logicalDisplayHeight = isRotated ? displayWidth : displayHeight;
5561 const ui::Transform displayTransform(ui::Transform::toRotationFlags(rotation),
5562 logicalDisplayWidth, logicalDisplayHeight);
5563 addDisplayInfo(ADISPLAY_ID_DEFAULT, displayTransform);
5564
5565 // Create a window that not trusted.
5566 const Rect untrustedWindowFrameInLogicalDisplay(100, 100, 200, 300);
5567
5568 const Rect untrustedWindowFrameInDisplay =
5569 displayTransform.inverse().transform(untrustedWindowFrameInLogicalDisplay);
5570
5571 sp<FakeWindowHandle> untrustedWindow =
5572 sp<FakeWindowHandle>::make(untrustedWindowApplication, mDispatcher, "UntrustedWindow",
5573 ADISPLAY_ID_DEFAULT);
5574 untrustedWindow->setFrame(untrustedWindowFrameInDisplay, displayTransform);
5575 untrustedWindow->setTrustedOverlay(false);
5576 untrustedWindow->setTouchOcclusionMode(TouchOcclusionMode::BLOCK_UNTRUSTED);
5577 untrustedWindow->setTouchable(false);
5578 untrustedWindow->setAlpha(1.0f);
5579 untrustedWindow->setOwnerInfo(gui::Pid{1}, gui::Uid{101});
5580 addWindow(untrustedWindow);
5581
5582 // Create a simple app window below the untrusted window.
5583 const Rect simpleAppWindowFrameInLogicalDisplay(0, 0, 300, 600);
5584 const Rect simpleAppWindowFrameInDisplay =
5585 displayTransform.inverse().transform(simpleAppWindowFrameInLogicalDisplay);
5586
5587 sp<FakeWindowHandle> simpleAppWindow =
5588 sp<FakeWindowHandle>::make(application, mDispatcher, "SimpleAppWindow",
5589 ADISPLAY_ID_DEFAULT);
5590 simpleAppWindow->setFrame(simpleAppWindowFrameInDisplay, displayTransform);
5591 simpleAppWindow->setOwnerInfo(gui::Pid{2}, gui::Uid{202});
5592 addWindow(simpleAppWindow);
5593
5594 // The following points in logical display space should be inside the untrusted window, so
5595 // the simple window could not receive events that coordinate is these point.
5596 static const std::array<vec2, 4> untrustedPoints{
5597 {{100, 100}, {199.99, 100}, {100, 299.99}, {199.99, 299.99}}};
5598
5599 for (const auto untrustedPoint : untrustedPoints) {
5600 const vec2 p = displayTransform.inverse().transform(untrustedPoint);
5601 const PointF pointInDisplaySpace{p.x, p.y};
5602 mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_DOWN,
5603 AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
5604 {pointInDisplaySpace}));
5605 mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_UP,
5606 AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
5607 {pointInDisplaySpace}));
5608 }
5609 untrustedWindow->assertNoEvents();
5610 simpleAppWindow->assertNoEvents();
5611 // The following points in logical display space should be outside the untrusted window, so
5612 // the simple window should receive events that coordinate is these point.
5613 static const std::array<vec2, 5> trustedPoints{
5614 {{200, 100}, {100, 300}, {200, 300}, {100, 99.99}, {99.99, 100}}};
5615 for (const auto trustedPoint : trustedPoints) {
5616 const vec2 p = displayTransform.inverse().transform(trustedPoint);
5617 const PointF pointInDisplaySpace{p.x, p.y};
5618 mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_DOWN,
5619 AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
5620 {pointInDisplaySpace}));
5621 simpleAppWindow->consumeMotionDown(ADISPLAY_ID_DEFAULT,
5622 AMOTION_EVENT_FLAG_WINDOW_IS_PARTIALLY_OBSCURED);
5623 mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_UP,
5624 AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
5625 {pointInDisplaySpace}));
5626 simpleAppWindow->consumeMotionUp(ADISPLAY_ID_DEFAULT,
5627 AMOTION_EVENT_FLAG_WINDOW_IS_PARTIALLY_OBSCURED);
5628 }
5629 untrustedWindow->assertNoEvents();
5630}
5631
Prabir Pradhan33e3baa2022-12-06 20:30:22 +00005632// Run the precision tests for all rotations.
5633INSTANTIATE_TEST_SUITE_P(InputDispatcherDisplayOrientationTests,
5634 InputDispatcherDisplayOrientationFixture,
5635 ::testing::Values(ui::ROTATION_0, ui::ROTATION_90, ui::ROTATION_180,
5636 ui::ROTATION_270),
5637 [](const testing::TestParamInfo<ui::Rotation>& testParamInfo) {
5638 return ftl::enum_string(testParamInfo.param);
5639 });
5640
Siarhei Vishniakou18050092021-09-01 13:32:49 -07005641using TransferFunction = std::function<bool(const std::unique_ptr<InputDispatcher>& dispatcher,
5642 sp<IBinder>, sp<IBinder>)>;
Siarhei Vishniakoud0c6bc82021-03-13 03:14:52 +00005643
5644class TransferTouchFixture : public InputDispatcherTest,
5645 public ::testing::WithParamInterface<TransferFunction> {};
5646
5647TEST_P(TransferTouchFixture, TransferTouch_OnePointer) {
Chris Yea209fde2020-07-22 13:54:51 -07005648 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
Svet Ganov5d3bc372020-01-26 23:11:07 -08005649
5650 // Create a couple of windows
Siarhei Vishniakou870ecec2020-12-09 08:07:46 -10005651 sp<FakeWindowHandle> firstWindow =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07005652 sp<FakeWindowHandle>::make(application, mDispatcher, "First Window",
5653 ADISPLAY_ID_DEFAULT);
Arthur Hungc539dbb2022-12-08 07:45:36 +00005654 firstWindow->setDupTouchToWallpaper(true);
Siarhei Vishniakou870ecec2020-12-09 08:07:46 -10005655 sp<FakeWindowHandle> secondWindow =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07005656 sp<FakeWindowHandle>::make(application, mDispatcher, "Second Window",
5657 ADISPLAY_ID_DEFAULT);
Arthur Hungc539dbb2022-12-08 07:45:36 +00005658 sp<FakeWindowHandle> wallpaper =
5659 sp<FakeWindowHandle>::make(application, mDispatcher, "Wallpaper", ADISPLAY_ID_DEFAULT);
5660 wallpaper->setIsWallpaper(true);
Prabir Pradhan65455c72024-02-13 21:46:41 +00005661 // Add the windows to the dispatcher, and ensure the first window is focused
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07005662 mDispatcher->onWindowInfosChanged(
5663 {{*firstWindow->getInfo(), *secondWindow->getInfo(), *wallpaper->getInfo()}, {}, 0, 0});
Prabir Pradhan65455c72024-02-13 21:46:41 +00005664 setFocusedWindow(firstWindow);
5665 firstWindow->consumeFocusEvent(true);
Svet Ganov5d3bc372020-01-26 23:11:07 -08005666
5667 // Send down to the first window
Prabir Pradhan678438e2023-04-13 19:32:51 +00005668 mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_DOWN,
5669 AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT));
Arthur Hungc539dbb2022-12-08 07:45:36 +00005670
Svet Ganov5d3bc372020-01-26 23:11:07 -08005671 // Only the first window should get the down event
5672 firstWindow->consumeMotionDown();
5673 secondWindow->assertNoEvents();
Arthur Hungc539dbb2022-12-08 07:45:36 +00005674 wallpaper->consumeMotionDown(ADISPLAY_ID_DEFAULT, expectedWallpaperFlags);
Prabir Pradhan65455c72024-02-13 21:46:41 +00005675 // Dispatcher reports pointer down outside focus for the wallpaper
5676 mFakePolicy->assertOnPointerDownEquals(wallpaper->getToken());
Svet Ganov5d3bc372020-01-26 23:11:07 -08005677
Siarhei Vishniakoud0c6bc82021-03-13 03:14:52 +00005678 // Transfer touch to the second window
5679 TransferFunction f = GetParam();
5680 const bool success = f(mDispatcher, firstWindow->getToken(), secondWindow->getToken());
5681 ASSERT_TRUE(success);
Svet Ganov5d3bc372020-01-26 23:11:07 -08005682 // The first window gets cancel and the second gets down
5683 firstWindow->consumeMotionCancel();
Prabir Pradhan65455c72024-02-13 21:46:41 +00005684 secondWindow->consumeMotionDown(ADISPLAY_ID_DEFAULT, AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
Arthur Hungc539dbb2022-12-08 07:45:36 +00005685 wallpaper->consumeMotionCancel(ADISPLAY_ID_DEFAULT, expectedWallpaperFlags);
Prabir Pradhan65455c72024-02-13 21:46:41 +00005686 // There should not be any changes to the focused window when transferring touch
5687 ASSERT_NO_FATAL_FAILURE(mFakePolicy->assertOnPointerDownWasNotCalled());
Svet Ganov5d3bc372020-01-26 23:11:07 -08005688
5689 // Send up event to the second window
Prabir Pradhan678438e2023-04-13 19:32:51 +00005690 mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN,
5691 ADISPLAY_ID_DEFAULT));
Prabir Pradhan65455c72024-02-13 21:46:41 +00005692 // The first window gets no events and the second gets up
Svet Ganov5d3bc372020-01-26 23:11:07 -08005693 firstWindow->assertNoEvents();
Prabir Pradhan65455c72024-02-13 21:46:41 +00005694 secondWindow->consumeMotionUp(ADISPLAY_ID_DEFAULT, AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
Arthur Hungc539dbb2022-12-08 07:45:36 +00005695 wallpaper->assertNoEvents();
Svet Ganov5d3bc372020-01-26 23:11:07 -08005696}
5697
Siarhei Vishniakou7ae7afd2022-03-31 15:26:13 -07005698/**
Prabir Pradhan367f3432024-02-13 23:05:58 +00005699 * When 'transferTouchGesture' API is invoked, dispatcher needs to find the "best" window to take
5700 * touch from. When we have spy windows, there are several windows to choose from: either spy, or
5701 * the 'real' (non-spy) window. Always prefer the 'real' window because that's what would be most
Siarhei Vishniakou7ae7afd2022-03-31 15:26:13 -07005702 * natural to the user.
5703 * In this test, we are sending a pointer to both spy window and first window. We then try to
5704 * transfer touch to the second window. The dispatcher should identify the first window as the
5705 * one that should lose the gesture, and therefore the action should be to move the gesture from
5706 * the first window to the second.
Prabir Pradhan367f3432024-02-13 23:05:58 +00005707 * The main goal here is to test the behaviour of 'transferTouchGesture' API, but it's still valid
5708 * to test the other API, as well.
Siarhei Vishniakou7ae7afd2022-03-31 15:26:13 -07005709 */
5710TEST_P(TransferTouchFixture, TransferTouch_MultipleWindowsWithSpy) {
5711 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
5712
5713 // Create a couple of windows + a spy window
5714 sp<FakeWindowHandle> spyWindow =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07005715 sp<FakeWindowHandle>::make(application, mDispatcher, "Spy", ADISPLAY_ID_DEFAULT);
Siarhei Vishniakou7ae7afd2022-03-31 15:26:13 -07005716 spyWindow->setTrustedOverlay(true);
5717 spyWindow->setSpy(true);
5718 sp<FakeWindowHandle> firstWindow =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07005719 sp<FakeWindowHandle>::make(application, mDispatcher, "First", ADISPLAY_ID_DEFAULT);
Siarhei Vishniakou7ae7afd2022-03-31 15:26:13 -07005720 sp<FakeWindowHandle> secondWindow =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07005721 sp<FakeWindowHandle>::make(application, mDispatcher, "Second", ADISPLAY_ID_DEFAULT);
Siarhei Vishniakou7ae7afd2022-03-31 15:26:13 -07005722
5723 // Add the windows to the dispatcher
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07005724 mDispatcher->onWindowInfosChanged(
5725 {{*spyWindow->getInfo(), *firstWindow->getInfo(), *secondWindow->getInfo()}, {}, 0, 0});
Siarhei Vishniakou7ae7afd2022-03-31 15:26:13 -07005726
5727 // Send down to the first window
Prabir Pradhan678438e2023-04-13 19:32:51 +00005728 mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_DOWN,
5729 AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT));
Siarhei Vishniakou7ae7afd2022-03-31 15:26:13 -07005730 // Only the first window and spy should get the down event
5731 spyWindow->consumeMotionDown();
5732 firstWindow->consumeMotionDown();
5733
5734 // Transfer touch to the second window. Non-spy window should be preferred over the spy window
Prabir Pradhan367f3432024-02-13 23:05:58 +00005735 // if f === 'transferTouchGesture'.
Siarhei Vishniakou7ae7afd2022-03-31 15:26:13 -07005736 TransferFunction f = GetParam();
5737 const bool success = f(mDispatcher, firstWindow->getToken(), secondWindow->getToken());
5738 ASSERT_TRUE(success);
5739 // The first window gets cancel and the second gets down
5740 firstWindow->consumeMotionCancel();
Prabir Pradhan65455c72024-02-13 21:46:41 +00005741 secondWindow->consumeMotionDown(ADISPLAY_ID_DEFAULT, AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
Siarhei Vishniakou7ae7afd2022-03-31 15:26:13 -07005742
5743 // Send up event to the second window
Prabir Pradhan678438e2023-04-13 19:32:51 +00005744 mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN,
5745 ADISPLAY_ID_DEFAULT));
Siarhei Vishniakou7ae7afd2022-03-31 15:26:13 -07005746 // The first window gets no events and the second+spy get up
5747 firstWindow->assertNoEvents();
5748 spyWindow->consumeMotionUp();
Prabir Pradhan65455c72024-02-13 21:46:41 +00005749 secondWindow->consumeMotionUp(ADISPLAY_ID_DEFAULT, AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
Siarhei Vishniakou7ae7afd2022-03-31 15:26:13 -07005750}
5751
Siarhei Vishniakoud0c6bc82021-03-13 03:14:52 +00005752TEST_P(TransferTouchFixture, TransferTouch_TwoPointersNonSplitTouch) {
Chris Yea209fde2020-07-22 13:54:51 -07005753 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
Svet Ganov5d3bc372020-01-26 23:11:07 -08005754
5755 PointF touchPoint = {10, 10};
5756
5757 // Create a couple of windows
Siarhei Vishniakou870ecec2020-12-09 08:07:46 -10005758 sp<FakeWindowHandle> firstWindow =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07005759 sp<FakeWindowHandle>::make(application, mDispatcher, "First Window",
5760 ADISPLAY_ID_DEFAULT);
Prabir Pradhan76bdecb2022-01-31 11:14:15 -08005761 firstWindow->setPreventSplitting(true);
Siarhei Vishniakou870ecec2020-12-09 08:07:46 -10005762 sp<FakeWindowHandle> secondWindow =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07005763 sp<FakeWindowHandle>::make(application, mDispatcher, "Second Window",
5764 ADISPLAY_ID_DEFAULT);
Prabir Pradhan76bdecb2022-01-31 11:14:15 -08005765 secondWindow->setPreventSplitting(true);
Svet Ganov5d3bc372020-01-26 23:11:07 -08005766
5767 // Add the windows to the dispatcher
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07005768 mDispatcher->onWindowInfosChanged(
5769 {{*firstWindow->getInfo(), *secondWindow->getInfo()}, {}, 0, 0});
Svet Ganov5d3bc372020-01-26 23:11:07 -08005770
5771 // Send down to the first window
Prabir Pradhan678438e2023-04-13 19:32:51 +00005772 mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_DOWN,
5773 AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
5774 {touchPoint}));
Svet Ganov5d3bc372020-01-26 23:11:07 -08005775 // Only the first window should get the down event
5776 firstWindow->consumeMotionDown();
5777 secondWindow->assertNoEvents();
5778
5779 // Send pointer down to the first window
Prabir Pradhan678438e2023-04-13 19:32:51 +00005780 mDispatcher->notifyMotion(generateMotionArgs(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN,
5781 ADISPLAY_ID_DEFAULT, {touchPoint, touchPoint}));
Svet Ganov5d3bc372020-01-26 23:11:07 -08005782 // Only the first window should get the pointer down event
5783 firstWindow->consumeMotionPointerDown(1);
5784 secondWindow->assertNoEvents();
5785
5786 // Transfer touch focus to the second window
Siarhei Vishniakoud0c6bc82021-03-13 03:14:52 +00005787 TransferFunction f = GetParam();
5788 bool success = f(mDispatcher, firstWindow->getToken(), secondWindow->getToken());
5789 ASSERT_TRUE(success);
Svet Ganov5d3bc372020-01-26 23:11:07 -08005790 // The first window gets cancel and the second gets down and pointer down
5791 firstWindow->consumeMotionCancel();
Prabir Pradhan65455c72024-02-13 21:46:41 +00005792 secondWindow->consumeMotionDown(ADISPLAY_ID_DEFAULT, AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
5793 secondWindow->consumeMotionPointerDown(1, ADISPLAY_ID_DEFAULT,
5794 AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
Svet Ganov5d3bc372020-01-26 23:11:07 -08005795
5796 // Send pointer up to the second window
Prabir Pradhan678438e2023-04-13 19:32:51 +00005797 mDispatcher->notifyMotion(generateMotionArgs(POINTER_1_UP, AINPUT_SOURCE_TOUCHSCREEN,
5798 ADISPLAY_ID_DEFAULT, {touchPoint, touchPoint}));
Svet Ganov5d3bc372020-01-26 23:11:07 -08005799 // The first window gets nothing and the second gets pointer up
5800 firstWindow->assertNoEvents();
Prabir Pradhan65455c72024-02-13 21:46:41 +00005801 secondWindow->consumeMotionPointerUp(1, ADISPLAY_ID_DEFAULT,
5802 AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
Svet Ganov5d3bc372020-01-26 23:11:07 -08005803
5804 // Send up event to the second window
Prabir Pradhan678438e2023-04-13 19:32:51 +00005805 mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN,
5806 ADISPLAY_ID_DEFAULT));
Svet Ganov5d3bc372020-01-26 23:11:07 -08005807 // The first window gets nothing and the second gets up
5808 firstWindow->assertNoEvents();
Prabir Pradhan65455c72024-02-13 21:46:41 +00005809 secondWindow->consumeMotionUp(ADISPLAY_ID_DEFAULT, AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
Svet Ganov5d3bc372020-01-26 23:11:07 -08005810}
5811
Arthur Hungc539dbb2022-12-08 07:45:36 +00005812TEST_P(TransferTouchFixture, TransferTouch_MultipleWallpapers) {
5813 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
5814
5815 // Create a couple of windows
5816 sp<FakeWindowHandle> firstWindow =
5817 sp<FakeWindowHandle>::make(application, mDispatcher, "First Window",
5818 ADISPLAY_ID_DEFAULT);
5819 firstWindow->setDupTouchToWallpaper(true);
5820 sp<FakeWindowHandle> secondWindow =
5821 sp<FakeWindowHandle>::make(application, mDispatcher, "Second Window",
5822 ADISPLAY_ID_DEFAULT);
5823 secondWindow->setDupTouchToWallpaper(true);
5824
5825 sp<FakeWindowHandle> wallpaper1 =
5826 sp<FakeWindowHandle>::make(application, mDispatcher, "Wallpaper1", ADISPLAY_ID_DEFAULT);
5827 wallpaper1->setIsWallpaper(true);
5828
5829 sp<FakeWindowHandle> wallpaper2 =
5830 sp<FakeWindowHandle>::make(application, mDispatcher, "Wallpaper2", ADISPLAY_ID_DEFAULT);
5831 wallpaper2->setIsWallpaper(true);
5832 // Add the windows to the dispatcher
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07005833 mDispatcher->onWindowInfosChanged({{*firstWindow->getInfo(), *wallpaper1->getInfo(),
5834 *secondWindow->getInfo(), *wallpaper2->getInfo()},
5835 {},
5836 0,
5837 0});
Arthur Hungc539dbb2022-12-08 07:45:36 +00005838
5839 // Send down to the first window
Prabir Pradhan678438e2023-04-13 19:32:51 +00005840 mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_DOWN,
5841 AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT));
Arthur Hungc539dbb2022-12-08 07:45:36 +00005842
5843 // Only the first window should get the down event
5844 firstWindow->consumeMotionDown();
5845 secondWindow->assertNoEvents();
5846 wallpaper1->consumeMotionDown(ADISPLAY_ID_DEFAULT, expectedWallpaperFlags);
5847 wallpaper2->assertNoEvents();
5848
5849 // Transfer touch focus to the second window
5850 TransferFunction f = GetParam();
5851 bool success = f(mDispatcher, firstWindow->getToken(), secondWindow->getToken());
5852 ASSERT_TRUE(success);
5853
5854 // The first window gets cancel and the second gets down
5855 firstWindow->consumeMotionCancel();
Prabir Pradhan65455c72024-02-13 21:46:41 +00005856 secondWindow->consumeMotionDown(ADISPLAY_ID_DEFAULT, AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
Arthur Hungc539dbb2022-12-08 07:45:36 +00005857 wallpaper1->consumeMotionCancel(ADISPLAY_ID_DEFAULT, expectedWallpaperFlags);
Prabir Pradhan65455c72024-02-13 21:46:41 +00005858 wallpaper2->consumeMotionDown(ADISPLAY_ID_DEFAULT,
5859 expectedWallpaperFlags | AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
Arthur Hungc539dbb2022-12-08 07:45:36 +00005860
5861 // Send up event to the second window
Prabir Pradhan678438e2023-04-13 19:32:51 +00005862 mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN,
5863 ADISPLAY_ID_DEFAULT));
Arthur Hungc539dbb2022-12-08 07:45:36 +00005864 // The first window gets no events and the second gets up
5865 firstWindow->assertNoEvents();
Prabir Pradhan65455c72024-02-13 21:46:41 +00005866 secondWindow->consumeMotionUp(ADISPLAY_ID_DEFAULT, AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
Arthur Hungc539dbb2022-12-08 07:45:36 +00005867 wallpaper1->assertNoEvents();
Prabir Pradhan65455c72024-02-13 21:46:41 +00005868 wallpaper2->consumeMotionUp(ADISPLAY_ID_DEFAULT,
5869 expectedWallpaperFlags | AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
Arthur Hungc539dbb2022-12-08 07:45:36 +00005870}
5871
Siarhei Vishniakoud0c6bc82021-03-13 03:14:52 +00005872// For the cases of single pointer touch and two pointers non-split touch, the api's
Prabir Pradhan367f3432024-02-13 23:05:58 +00005873// 'transferTouchGesture' and 'transferTouchOnDisplay' are equivalent in behaviour. They only differ
Siarhei Vishniakoud0c6bc82021-03-13 03:14:52 +00005874// for the case where there are multiple pointers split across several windows.
Prabir Pradhan367f3432024-02-13 23:05:58 +00005875INSTANTIATE_TEST_SUITE_P(
5876 InputDispatcherTransferFunctionTests, TransferTouchFixture,
5877 ::testing::Values(
5878 [&](const std::unique_ptr<InputDispatcher>& dispatcher, sp<IBinder> /*ignored*/,
5879 sp<IBinder> destChannelToken) {
5880 return dispatcher->transferTouchOnDisplay(destChannelToken,
5881 ADISPLAY_ID_DEFAULT);
5882 },
5883 [&](const std::unique_ptr<InputDispatcher>& dispatcher, sp<IBinder> from,
5884 sp<IBinder> to) {
5885 return dispatcher->transferTouchGesture(from, to,
5886 /*isDragAndDrop=*/false);
5887 }));
Siarhei Vishniakoud0c6bc82021-03-13 03:14:52 +00005888
Prabir Pradhan367f3432024-02-13 23:05:58 +00005889TEST_F(InputDispatcherTest, TransferTouch_TwoPointersSplitTouch) {
Chris Yea209fde2020-07-22 13:54:51 -07005890 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
Svet Ganov5d3bc372020-01-26 23:11:07 -08005891
Siarhei Vishniakou870ecec2020-12-09 08:07:46 -10005892 sp<FakeWindowHandle> firstWindow =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07005893 sp<FakeWindowHandle>::make(application, mDispatcher, "First Window",
5894 ADISPLAY_ID_DEFAULT);
Svet Ganov5d3bc372020-01-26 23:11:07 -08005895 firstWindow->setFrame(Rect(0, 0, 600, 400));
Svet Ganov5d3bc372020-01-26 23:11:07 -08005896
Siarhei Vishniakou870ecec2020-12-09 08:07:46 -10005897 sp<FakeWindowHandle> secondWindow =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07005898 sp<FakeWindowHandle>::make(application, mDispatcher, "Second Window",
5899 ADISPLAY_ID_DEFAULT);
Svet Ganov5d3bc372020-01-26 23:11:07 -08005900 secondWindow->setFrame(Rect(0, 400, 600, 800));
Svet Ganov5d3bc372020-01-26 23:11:07 -08005901
5902 // Add the windows to the dispatcher
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07005903 mDispatcher->onWindowInfosChanged(
5904 {{*firstWindow->getInfo(), *secondWindow->getInfo()}, {}, 0, 0});
Svet Ganov5d3bc372020-01-26 23:11:07 -08005905
5906 PointF pointInFirst = {300, 200};
5907 PointF pointInSecond = {300, 600};
5908
5909 // Send down to the first window
Prabir Pradhan678438e2023-04-13 19:32:51 +00005910 mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_DOWN,
5911 AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
5912 {pointInFirst}));
Svet Ganov5d3bc372020-01-26 23:11:07 -08005913 // Only the first window should get the down event
5914 firstWindow->consumeMotionDown();
5915 secondWindow->assertNoEvents();
5916
5917 // Send down to the second window
Prabir Pradhan678438e2023-04-13 19:32:51 +00005918 mDispatcher->notifyMotion(generateMotionArgs(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN,
5919 ADISPLAY_ID_DEFAULT,
5920 {pointInFirst, pointInSecond}));
Svet Ganov5d3bc372020-01-26 23:11:07 -08005921 // The first window gets a move and the second a down
5922 firstWindow->consumeMotionMove();
5923 secondWindow->consumeMotionDown();
5924
Prabir Pradhan367f3432024-02-13 23:05:58 +00005925 // Transfer touch to the second window
5926 mDispatcher->transferTouchGesture(firstWindow->getToken(), secondWindow->getToken());
Svet Ganov5d3bc372020-01-26 23:11:07 -08005927 // The first window gets cancel and the new gets pointer down (it already saw down)
5928 firstWindow->consumeMotionCancel();
Prabir Pradhan65455c72024-02-13 21:46:41 +00005929 secondWindow->consumeMotionPointerDown(1, ADISPLAY_ID_DEFAULT,
5930 AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
Svet Ganov5d3bc372020-01-26 23:11:07 -08005931
5932 // Send pointer up to the second window
Prabir Pradhan678438e2023-04-13 19:32:51 +00005933 mDispatcher->notifyMotion(generateMotionArgs(POINTER_1_UP, AINPUT_SOURCE_TOUCHSCREEN,
5934 ADISPLAY_ID_DEFAULT,
5935 {pointInFirst, pointInSecond}));
Svet Ganov5d3bc372020-01-26 23:11:07 -08005936 // The first window gets nothing and the second gets pointer up
5937 firstWindow->assertNoEvents();
Prabir Pradhan65455c72024-02-13 21:46:41 +00005938 secondWindow->consumeMotionPointerUp(1, ADISPLAY_ID_DEFAULT,
5939 AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
Svet Ganov5d3bc372020-01-26 23:11:07 -08005940
5941 // Send up event to the second window
Prabir Pradhan678438e2023-04-13 19:32:51 +00005942 mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN,
5943 ADISPLAY_ID_DEFAULT));
Svet Ganov5d3bc372020-01-26 23:11:07 -08005944 // The first window gets nothing and the second gets up
5945 firstWindow->assertNoEvents();
Prabir Pradhan65455c72024-02-13 21:46:41 +00005946 secondWindow->consumeMotionUp(ADISPLAY_ID_DEFAULT, AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
Svet Ganov5d3bc372020-01-26 23:11:07 -08005947}
5948
Prabir Pradhan367f3432024-02-13 23:05:58 +00005949// Same as TransferTouch_TwoPointersSplitTouch, but using 'transferTouchOnDisplay' api.
5950// Unlike 'transferTouchGesture', calling 'transferTouchOnDisplay' when there are two windows
5951// receiving touch is not supported, so the touch should continue on those windows and the
5952// transferred-to window should get nothing.
5953TEST_F(InputDispatcherTest, TransferTouchOnDisplay_TwoPointersSplitTouch) {
Siarhei Vishniakoud0c6bc82021-03-13 03:14:52 +00005954 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
5955
Siarhei Vishniakoud0c6bc82021-03-13 03:14:52 +00005956 sp<FakeWindowHandle> firstWindow =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07005957 sp<FakeWindowHandle>::make(application, mDispatcher, "First Window",
5958 ADISPLAY_ID_DEFAULT);
Siarhei Vishniakoud0c6bc82021-03-13 03:14:52 +00005959 firstWindow->setFrame(Rect(0, 0, 600, 400));
Siarhei Vishniakoud0c6bc82021-03-13 03:14:52 +00005960
Siarhei Vishniakoud0c6bc82021-03-13 03:14:52 +00005961 sp<FakeWindowHandle> secondWindow =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07005962 sp<FakeWindowHandle>::make(application, mDispatcher, "Second Window",
5963 ADISPLAY_ID_DEFAULT);
Siarhei Vishniakoud0c6bc82021-03-13 03:14:52 +00005964 secondWindow->setFrame(Rect(0, 400, 600, 800));
Siarhei Vishniakoud0c6bc82021-03-13 03:14:52 +00005965
5966 // Add the windows to the dispatcher
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07005967 mDispatcher->onWindowInfosChanged(
5968 {{*firstWindow->getInfo(), *secondWindow->getInfo()}, {}, 0, 0});
Siarhei Vishniakoud0c6bc82021-03-13 03:14:52 +00005969
5970 PointF pointInFirst = {300, 200};
5971 PointF pointInSecond = {300, 600};
5972
5973 // Send down to the first window
Prabir Pradhan678438e2023-04-13 19:32:51 +00005974 mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_DOWN,
5975 AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
5976 {pointInFirst}));
Siarhei Vishniakoud0c6bc82021-03-13 03:14:52 +00005977 // Only the first window should get the down event
5978 firstWindow->consumeMotionDown();
5979 secondWindow->assertNoEvents();
5980
5981 // Send down to the second window
Prabir Pradhan678438e2023-04-13 19:32:51 +00005982 mDispatcher->notifyMotion(generateMotionArgs(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN,
5983 ADISPLAY_ID_DEFAULT,
5984 {pointInFirst, pointInSecond}));
Siarhei Vishniakoud0c6bc82021-03-13 03:14:52 +00005985 // The first window gets a move and the second a down
5986 firstWindow->consumeMotionMove();
5987 secondWindow->consumeMotionDown();
5988
5989 // Transfer touch focus to the second window
Siarhei Vishniakou7ae7afd2022-03-31 15:26:13 -07005990 const bool transferred =
Prabir Pradhan367f3432024-02-13 23:05:58 +00005991 mDispatcher->transferTouchOnDisplay(secondWindow->getToken(), ADISPLAY_ID_DEFAULT);
5992 // The 'transferTouchOnDisplay' call should not succeed, because there are 2 touched windows
Siarhei Vishniakoud0c6bc82021-03-13 03:14:52 +00005993 ASSERT_FALSE(transferred);
5994 firstWindow->assertNoEvents();
5995 secondWindow->assertNoEvents();
5996
5997 // The rest of the dispatch should proceed as normal
5998 // Send pointer up to the second window
Prabir Pradhan678438e2023-04-13 19:32:51 +00005999 mDispatcher->notifyMotion(generateMotionArgs(POINTER_1_UP, AINPUT_SOURCE_TOUCHSCREEN,
6000 ADISPLAY_ID_DEFAULT,
6001 {pointInFirst, pointInSecond}));
Siarhei Vishniakoud0c6bc82021-03-13 03:14:52 +00006002 // The first window gets MOVE and the second gets pointer up
6003 firstWindow->consumeMotionMove();
6004 secondWindow->consumeMotionUp();
6005
6006 // Send up event to the first window
Prabir Pradhan678438e2023-04-13 19:32:51 +00006007 mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN,
6008 ADISPLAY_ID_DEFAULT));
Siarhei Vishniakoud0c6bc82021-03-13 03:14:52 +00006009 // The first window gets nothing and the second gets up
6010 firstWindow->consumeMotionUp();
6011 secondWindow->assertNoEvents();
6012}
6013
Arthur Hungabbb9d82021-09-01 14:52:30 +00006014// This case will create two windows and one mirrored window on the default display and mirror
Prabir Pradhan367f3432024-02-13 23:05:58 +00006015// two windows on the second display. It will test if 'transferTouchGesture' works fine if we put
Arthur Hungabbb9d82021-09-01 14:52:30 +00006016// the windows info of second display before default display.
Prabir Pradhan367f3432024-02-13 23:05:58 +00006017TEST_F(InputDispatcherTest, TransferTouch_CloneSurface) {
Arthur Hungabbb9d82021-09-01 14:52:30 +00006018 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
6019 sp<FakeWindowHandle> firstWindowInPrimary =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07006020 sp<FakeWindowHandle>::make(application, mDispatcher, "D_1_W1", ADISPLAY_ID_DEFAULT);
Arthur Hungabbb9d82021-09-01 14:52:30 +00006021 firstWindowInPrimary->setFrame(Rect(0, 0, 100, 100));
Arthur Hungabbb9d82021-09-01 14:52:30 +00006022 sp<FakeWindowHandle> secondWindowInPrimary =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07006023 sp<FakeWindowHandle>::make(application, mDispatcher, "D_1_W2", ADISPLAY_ID_DEFAULT);
Arthur Hungabbb9d82021-09-01 14:52:30 +00006024 secondWindowInPrimary->setFrame(Rect(100, 0, 200, 100));
Arthur Hungabbb9d82021-09-01 14:52:30 +00006025
Siarhei Vishniakouadb9fc92023-05-26 10:46:09 -07006026 sp<FakeWindowHandle> mirrorWindowInPrimary = firstWindowInPrimary->clone(ADISPLAY_ID_DEFAULT);
Arthur Hungabbb9d82021-09-01 14:52:30 +00006027 mirrorWindowInPrimary->setFrame(Rect(0, 100, 100, 200));
Arthur Hungabbb9d82021-09-01 14:52:30 +00006028
Siarhei Vishniakouadb9fc92023-05-26 10:46:09 -07006029 sp<FakeWindowHandle> firstWindowInSecondary = firstWindowInPrimary->clone(SECOND_DISPLAY_ID);
Arthur Hungabbb9d82021-09-01 14:52:30 +00006030 firstWindowInSecondary->setFrame(Rect(0, 0, 100, 100));
Arthur Hungabbb9d82021-09-01 14:52:30 +00006031
Siarhei Vishniakouadb9fc92023-05-26 10:46:09 -07006032 sp<FakeWindowHandle> secondWindowInSecondary = secondWindowInPrimary->clone(SECOND_DISPLAY_ID);
Arthur Hungabbb9d82021-09-01 14:52:30 +00006033 secondWindowInPrimary->setFrame(Rect(100, 0, 200, 100));
Arthur Hungabbb9d82021-09-01 14:52:30 +00006034
6035 // Update window info, let it find window handle of second display first.
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07006036 mDispatcher->onWindowInfosChanged(
6037 {{*firstWindowInSecondary->getInfo(), *secondWindowInSecondary->getInfo(),
6038 *mirrorWindowInPrimary->getInfo(), *firstWindowInPrimary->getInfo(),
6039 *secondWindowInPrimary->getInfo()},
6040 {},
6041 0,
6042 0});
Arthur Hungabbb9d82021-09-01 14:52:30 +00006043
6044 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07006045 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
Arthur Hungabbb9d82021-09-01 14:52:30 +00006046 {50, 50}))
6047 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
6048
6049 // Window should receive motion event.
6050 firstWindowInPrimary->consumeMotionDown(ADISPLAY_ID_DEFAULT);
6051
Prabir Pradhan367f3432024-02-13 23:05:58 +00006052 // Transfer touch
6053 ASSERT_TRUE(mDispatcher->transferTouchGesture(firstWindowInPrimary->getToken(),
6054 secondWindowInPrimary->getToken()));
Arthur Hungabbb9d82021-09-01 14:52:30 +00006055 // The first window gets cancel.
6056 firstWindowInPrimary->consumeMotionCancel();
Prabir Pradhan65455c72024-02-13 21:46:41 +00006057 secondWindowInPrimary->consumeMotionDown(ADISPLAY_ID_DEFAULT,
6058 AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
Arthur Hungabbb9d82021-09-01 14:52:30 +00006059
6060 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07006061 injectMotionEvent(*mDispatcher, AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN,
Arthur Hungabbb9d82021-09-01 14:52:30 +00006062 ADISPLAY_ID_DEFAULT, {150, 50}))
6063 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
6064 firstWindowInPrimary->assertNoEvents();
Prabir Pradhan65455c72024-02-13 21:46:41 +00006065 secondWindowInPrimary->consumeMotionMove(ADISPLAY_ID_DEFAULT,
6066 AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
Arthur Hungabbb9d82021-09-01 14:52:30 +00006067
6068 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07006069 injectMotionUp(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
Arthur Hungabbb9d82021-09-01 14:52:30 +00006070 {150, 50}))
6071 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
6072 firstWindowInPrimary->assertNoEvents();
Prabir Pradhan65455c72024-02-13 21:46:41 +00006073 secondWindowInPrimary->consumeMotionUp(ADISPLAY_ID_DEFAULT, AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
Arthur Hungabbb9d82021-09-01 14:52:30 +00006074}
6075
Prabir Pradhan367f3432024-02-13 23:05:58 +00006076// Same as TransferTouch_CloneSurface, but this touch on the secondary display and use
6077// 'transferTouchOnDisplay' api.
6078TEST_F(InputDispatcherTest, TransferTouchOnDisplay_CloneSurface) {
Arthur Hungabbb9d82021-09-01 14:52:30 +00006079 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
6080 sp<FakeWindowHandle> firstWindowInPrimary =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07006081 sp<FakeWindowHandle>::make(application, mDispatcher, "D_1_W1", ADISPLAY_ID_DEFAULT);
Arthur Hungabbb9d82021-09-01 14:52:30 +00006082 firstWindowInPrimary->setFrame(Rect(0, 0, 100, 100));
Arthur Hungabbb9d82021-09-01 14:52:30 +00006083 sp<FakeWindowHandle> secondWindowInPrimary =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07006084 sp<FakeWindowHandle>::make(application, mDispatcher, "D_1_W2", ADISPLAY_ID_DEFAULT);
Arthur Hungabbb9d82021-09-01 14:52:30 +00006085 secondWindowInPrimary->setFrame(Rect(100, 0, 200, 100));
Arthur Hungabbb9d82021-09-01 14:52:30 +00006086
Siarhei Vishniakouadb9fc92023-05-26 10:46:09 -07006087 sp<FakeWindowHandle> mirrorWindowInPrimary = firstWindowInPrimary->clone(ADISPLAY_ID_DEFAULT);
Arthur Hungabbb9d82021-09-01 14:52:30 +00006088 mirrorWindowInPrimary->setFrame(Rect(0, 100, 100, 200));
Arthur Hungabbb9d82021-09-01 14:52:30 +00006089
Siarhei Vishniakouadb9fc92023-05-26 10:46:09 -07006090 sp<FakeWindowHandle> firstWindowInSecondary = firstWindowInPrimary->clone(SECOND_DISPLAY_ID);
Arthur Hungabbb9d82021-09-01 14:52:30 +00006091 firstWindowInSecondary->setFrame(Rect(0, 0, 100, 100));
Arthur Hungabbb9d82021-09-01 14:52:30 +00006092
Siarhei Vishniakouadb9fc92023-05-26 10:46:09 -07006093 sp<FakeWindowHandle> secondWindowInSecondary = secondWindowInPrimary->clone(SECOND_DISPLAY_ID);
Arthur Hungabbb9d82021-09-01 14:52:30 +00006094 secondWindowInPrimary->setFrame(Rect(100, 0, 200, 100));
Arthur Hungabbb9d82021-09-01 14:52:30 +00006095
6096 // Update window info, let it find window handle of second display first.
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07006097 mDispatcher->onWindowInfosChanged(
6098 {{*firstWindowInSecondary->getInfo(), *secondWindowInSecondary->getInfo(),
6099 *mirrorWindowInPrimary->getInfo(), *firstWindowInPrimary->getInfo(),
6100 *secondWindowInPrimary->getInfo()},
6101 {},
6102 0,
6103 0});
Arthur Hungabbb9d82021-09-01 14:52:30 +00006104
6105 // Touch on second display.
6106 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07006107 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, SECOND_DISPLAY_ID,
6108 {50, 50}))
Arthur Hungabbb9d82021-09-01 14:52:30 +00006109 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
6110
6111 // Window should receive motion event.
Prabir Pradhanbb3f1c02024-01-04 20:17:14 +00006112 firstWindowInSecondary->consumeMotionDown(SECOND_DISPLAY_ID);
Arthur Hungabbb9d82021-09-01 14:52:30 +00006113
6114 // Transfer touch focus
Prabir Pradhan367f3432024-02-13 23:05:58 +00006115 ASSERT_TRUE(mDispatcher->transferTouchOnDisplay(secondWindowInSecondary->getToken(),
6116 SECOND_DISPLAY_ID));
Arthur Hungabbb9d82021-09-01 14:52:30 +00006117
6118 // The first window gets cancel.
Prabir Pradhanbb3f1c02024-01-04 20:17:14 +00006119 firstWindowInSecondary->consumeMotionCancel(SECOND_DISPLAY_ID);
Prabir Pradhan65455c72024-02-13 21:46:41 +00006120 secondWindowInSecondary->consumeMotionDown(SECOND_DISPLAY_ID,
6121 AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
Arthur Hungabbb9d82021-09-01 14:52:30 +00006122
6123 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07006124 injectMotionEvent(*mDispatcher, AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN,
Arthur Hungabbb9d82021-09-01 14:52:30 +00006125 SECOND_DISPLAY_ID, {150, 50}))
6126 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
Prabir Pradhanbb3f1c02024-01-04 20:17:14 +00006127 firstWindowInSecondary->assertNoEvents();
Prabir Pradhan65455c72024-02-13 21:46:41 +00006128 secondWindowInSecondary->consumeMotionMove(SECOND_DISPLAY_ID,
6129 AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
Arthur Hungabbb9d82021-09-01 14:52:30 +00006130
6131 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07006132 injectMotionUp(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, SECOND_DISPLAY_ID, {150, 50}))
Arthur Hungabbb9d82021-09-01 14:52:30 +00006133 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
Prabir Pradhanbb3f1c02024-01-04 20:17:14 +00006134 firstWindowInSecondary->assertNoEvents();
Prabir Pradhan65455c72024-02-13 21:46:41 +00006135 secondWindowInSecondary->consumeMotionUp(SECOND_DISPLAY_ID, AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
Arthur Hungabbb9d82021-09-01 14:52:30 +00006136}
6137
Siarhei Vishniakouf1035d42019-09-20 16:32:01 +01006138TEST_F(InputDispatcherTest, FocusedWindow_ReceivesFocusEventAndKeyEvent) {
Chris Yea209fde2020-07-22 13:54:51 -07006139 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07006140 sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher,
6141 "Fake Window", ADISPLAY_ID_DEFAULT);
Siarhei Vishniakouf1035d42019-09-20 16:32:01 +01006142
Vishnu Nair47074b82020-08-14 11:54:47 -07006143 window->setFocusable(true);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07006144 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Vishnu Nair958da932020-08-21 17:12:37 -07006145 setFocusedWindow(window);
Siarhei Vishniakouf1035d42019-09-20 16:32:01 +01006146
6147 window->consumeFocusEvent(true);
6148
Prabir Pradhan678438e2023-04-13 19:32:51 +00006149 mDispatcher->notifyKey(generateKeyArgs(AKEY_EVENT_ACTION_DOWN, ADISPLAY_ID_DEFAULT));
Siarhei Vishniakouf1035d42019-09-20 16:32:01 +01006150
6151 // Window should receive key down event.
6152 window->consumeKeyDown(ADISPLAY_ID_DEFAULT);
Josep del Riob3981622023-04-18 15:49:45 +00006153
6154 // Should have poked user activity
Siarhei Vishniakou4fd86732023-05-24 17:33:01 +00006155 mDispatcher->waitForIdle();
Josep del Riob3981622023-04-18 15:49:45 +00006156 mFakePolicy->assertUserActivityPoked();
6157}
6158
6159TEST_F(InputDispatcherTest, FocusedWindow_DisableUserActivity) {
6160 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
6161 sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher,
6162 "Fake Window", ADISPLAY_ID_DEFAULT);
6163
6164 window->setDisableUserActivity(true);
6165 window->setFocusable(true);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07006166 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Josep del Riob3981622023-04-18 15:49:45 +00006167 setFocusedWindow(window);
6168
6169 window->consumeFocusEvent(true);
6170
6171 mDispatcher->notifyKey(generateKeyArgs(AKEY_EVENT_ACTION_DOWN, ADISPLAY_ID_DEFAULT));
6172
6173 // Window should receive key down event.
6174 window->consumeKeyDown(ADISPLAY_ID_DEFAULT);
6175
6176 // Should have poked user activity
Siarhei Vishniakou4fd86732023-05-24 17:33:01 +00006177 mDispatcher->waitForIdle();
Josep del Riob3981622023-04-18 15:49:45 +00006178 mFakePolicy->assertUserActivityNotPoked();
6179}
6180
6181TEST_F(InputDispatcherTest, FocusedWindow_DoesNotReceiveSystemShortcut) {
6182 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
6183 sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher,
6184 "Fake Window", ADISPLAY_ID_DEFAULT);
6185
6186 window->setFocusable(true);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07006187 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Josep del Riob3981622023-04-18 15:49:45 +00006188 setFocusedWindow(window);
6189
6190 window->consumeFocusEvent(true);
6191
6192 mDispatcher->notifyKey(generateSystemShortcutArgs(AKEY_EVENT_ACTION_DOWN, ADISPLAY_ID_DEFAULT));
6193 mDispatcher->waitForIdle();
6194
6195 // System key is not passed down
6196 window->assertNoEvents();
6197
6198 // Should have poked user activity
6199 mFakePolicy->assertUserActivityPoked();
6200}
6201
6202TEST_F(InputDispatcherTest, FocusedWindow_DoesNotReceiveAssistantKey) {
6203 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
6204 sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher,
6205 "Fake Window", ADISPLAY_ID_DEFAULT);
6206
6207 window->setFocusable(true);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07006208 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Josep del Riob3981622023-04-18 15:49:45 +00006209 setFocusedWindow(window);
6210
6211 window->consumeFocusEvent(true);
6212
6213 mDispatcher->notifyKey(generateAssistantKeyArgs(AKEY_EVENT_ACTION_DOWN, ADISPLAY_ID_DEFAULT));
6214 mDispatcher->waitForIdle();
6215
6216 // System key is not passed down
6217 window->assertNoEvents();
6218
6219 // Should have poked user activity
6220 mFakePolicy->assertUserActivityPoked();
6221}
6222
6223TEST_F(InputDispatcherTest, FocusedWindow_SystemKeyIgnoresDisableUserActivity) {
6224 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
6225 sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher,
6226 "Fake Window", ADISPLAY_ID_DEFAULT);
6227
6228 window->setDisableUserActivity(true);
6229 window->setFocusable(true);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07006230 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Josep del Riob3981622023-04-18 15:49:45 +00006231 setFocusedWindow(window);
6232
6233 window->consumeFocusEvent(true);
6234
6235 mDispatcher->notifyKey(generateSystemShortcutArgs(AKEY_EVENT_ACTION_DOWN, ADISPLAY_ID_DEFAULT));
6236 mDispatcher->waitForIdle();
6237
6238 // System key is not passed down
6239 window->assertNoEvents();
6240
6241 // Should have poked user activity
6242 mFakePolicy->assertUserActivityPoked();
Siarhei Vishniakouf1035d42019-09-20 16:32:01 +01006243}
6244
Siarhei Vishniakou90ee4782023-05-08 11:57:24 -07006245TEST_F(InputDispatcherTest, InjectedTouchesPokeUserActivity) {
6246 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
6247 sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher,
6248 "Fake Window", ADISPLAY_ID_DEFAULT);
6249
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07006250 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Siarhei Vishniakou90ee4782023-05-08 11:57:24 -07006251
6252 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07006253 injectMotionEvent(*mDispatcher, AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN,
Siarhei Vishniakou90ee4782023-05-08 11:57:24 -07006254 ADISPLAY_ID_DEFAULT, {100, 100}))
6255 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
6256
6257 window->consumeMotionEvent(
6258 AllOf(WithMotionAction(ACTION_DOWN), WithDisplayId(ADISPLAY_ID_DEFAULT)));
6259
6260 // Should have poked user activity
Siarhei Vishniakou4fd86732023-05-24 17:33:01 +00006261 mDispatcher->waitForIdle();
Siarhei Vishniakou90ee4782023-05-08 11:57:24 -07006262 mFakePolicy->assertUserActivityPoked();
6263}
6264
Siarhei Vishniakouf1035d42019-09-20 16:32:01 +01006265TEST_F(InputDispatcherTest, UnfocusedWindow_DoesNotReceiveFocusEventOrKeyEvent) {
Chris Yea209fde2020-07-22 13:54:51 -07006266 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07006267 sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher,
6268 "Fake Window", ADISPLAY_ID_DEFAULT);
Siarhei Vishniakouf1035d42019-09-20 16:32:01 +01006269
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07006270 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Siarhei Vishniakouf1035d42019-09-20 16:32:01 +01006271
Prabir Pradhan678438e2023-04-13 19:32:51 +00006272 mDispatcher->notifyKey(generateKeyArgs(AKEY_EVENT_ACTION_DOWN, ADISPLAY_ID_DEFAULT));
Siarhei Vishniakouf1035d42019-09-20 16:32:01 +01006273 mDispatcher->waitForIdle();
6274
6275 window->assertNoEvents();
6276}
6277
6278// If a window is touchable, but does not have focus, it should receive motion events, but not keys
6279TEST_F(InputDispatcherTest, UnfocusedWindow_ReceivesMotionsButNotKeys) {
Chris Yea209fde2020-07-22 13:54:51 -07006280 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07006281 sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher,
6282 "Fake Window", ADISPLAY_ID_DEFAULT);
Siarhei Vishniakouf1035d42019-09-20 16:32:01 +01006283
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07006284 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Siarhei Vishniakouf1035d42019-09-20 16:32:01 +01006285
6286 // Send key
Prabir Pradhan678438e2023-04-13 19:32:51 +00006287 mDispatcher->notifyKey(generateKeyArgs(AKEY_EVENT_ACTION_DOWN, ADISPLAY_ID_DEFAULT));
Siarhei Vishniakouf1035d42019-09-20 16:32:01 +01006288 // Send motion
Prabir Pradhan678438e2023-04-13 19:32:51 +00006289 mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_DOWN,
6290 AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT));
Siarhei Vishniakouf1035d42019-09-20 16:32:01 +01006291
6292 // Window should receive only the motion event
6293 window->consumeMotionDown(ADISPLAY_ID_DEFAULT);
6294 window->assertNoEvents(); // Key event or focus event will not be received
6295}
6296
arthurhungea3f4fc2020-12-21 23:18:53 +08006297TEST_F(InputDispatcherTest, PointerCancel_SendCancelWhenSplitTouch) {
6298 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
6299
arthurhungea3f4fc2020-12-21 23:18:53 +08006300 sp<FakeWindowHandle> firstWindow =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07006301 sp<FakeWindowHandle>::make(application, mDispatcher, "First Window",
6302 ADISPLAY_ID_DEFAULT);
arthurhungea3f4fc2020-12-21 23:18:53 +08006303 firstWindow->setFrame(Rect(0, 0, 600, 400));
arthurhungea3f4fc2020-12-21 23:18:53 +08006304
arthurhungea3f4fc2020-12-21 23:18:53 +08006305 sp<FakeWindowHandle> secondWindow =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07006306 sp<FakeWindowHandle>::make(application, mDispatcher, "Second Window",
6307 ADISPLAY_ID_DEFAULT);
arthurhungea3f4fc2020-12-21 23:18:53 +08006308 secondWindow->setFrame(Rect(0, 400, 600, 800));
arthurhungea3f4fc2020-12-21 23:18:53 +08006309
6310 // Add the windows to the dispatcher
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07006311 mDispatcher->onWindowInfosChanged(
6312 {{*firstWindow->getInfo(), *secondWindow->getInfo()}, {}, 0, 0});
arthurhungea3f4fc2020-12-21 23:18:53 +08006313
6314 PointF pointInFirst = {300, 200};
6315 PointF pointInSecond = {300, 600};
6316
6317 // Send down to the first window
Prabir Pradhan678438e2023-04-13 19:32:51 +00006318 mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_DOWN,
6319 AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
6320 {pointInFirst}));
arthurhungea3f4fc2020-12-21 23:18:53 +08006321 // Only the first window should get the down event
6322 firstWindow->consumeMotionDown();
6323 secondWindow->assertNoEvents();
6324
6325 // Send down to the second window
Prabir Pradhan678438e2023-04-13 19:32:51 +00006326 mDispatcher->notifyMotion(generateMotionArgs(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN,
6327 ADISPLAY_ID_DEFAULT,
6328 {pointInFirst, pointInSecond}));
arthurhungea3f4fc2020-12-21 23:18:53 +08006329 // The first window gets a move and the second a down
6330 firstWindow->consumeMotionMove();
6331 secondWindow->consumeMotionDown();
6332
6333 // Send pointer cancel to the second window
6334 NotifyMotionArgs pointerUpMotionArgs =
Siarhei Vishniakoua16e3a22022-03-02 15:26:40 -08006335 generateMotionArgs(POINTER_1_UP, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
arthurhungea3f4fc2020-12-21 23:18:53 +08006336 {pointInFirst, pointInSecond});
6337 pointerUpMotionArgs.flags |= AMOTION_EVENT_FLAG_CANCELED;
Prabir Pradhan678438e2023-04-13 19:32:51 +00006338 mDispatcher->notifyMotion(pointerUpMotionArgs);
arthurhungea3f4fc2020-12-21 23:18:53 +08006339 // The first window gets move and the second gets cancel.
6340 firstWindow->consumeMotionMove(ADISPLAY_ID_DEFAULT, AMOTION_EVENT_FLAG_CANCELED);
6341 secondWindow->consumeMotionCancel(ADISPLAY_ID_DEFAULT, AMOTION_EVENT_FLAG_CANCELED);
6342
6343 // Send up event.
Prabir Pradhan678438e2023-04-13 19:32:51 +00006344 mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN,
6345 ADISPLAY_ID_DEFAULT));
arthurhungea3f4fc2020-12-21 23:18:53 +08006346 // The first window gets up and the second gets nothing.
6347 firstWindow->consumeMotionUp();
6348 secondWindow->assertNoEvents();
6349}
6350
Siarhei Vishniakouf94ae022021-02-04 01:23:17 +00006351TEST_F(InputDispatcherTest, SendTimeline_DoesNotCrashDispatcher) {
6352 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
6353
6354 sp<FakeWindowHandle> window =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07006355 sp<FakeWindowHandle>::make(application, mDispatcher, "Window", ADISPLAY_ID_DEFAULT);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07006356 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Siarhei Vishniakouf94ae022021-02-04 01:23:17 +00006357 std::array<nsecs_t, GraphicsTimeline::SIZE> graphicsTimeline;
6358 graphicsTimeline[GraphicsTimeline::GPU_COMPLETED_TIME] = 2;
6359 graphicsTimeline[GraphicsTimeline::PRESENT_TIME] = 3;
6360
Harry Cutts33476232023-01-30 19:57:29 +00006361 window->sendTimeline(/*inputEventId=*/1, graphicsTimeline);
Siarhei Vishniakouf94ae022021-02-04 01:23:17 +00006362 window->assertNoEvents();
6363 mDispatcher->waitForIdle();
6364}
6365
Prabir Pradhan1376fcd2022-01-21 09:56:35 -08006366using InputDispatcherMonitorTest = InputDispatcherTest;
6367
Siarhei Vishniakouca205502021-07-16 21:31:58 +00006368/**
6369 * Two entities that receive touch: A window, and a global monitor.
6370 * The touch goes to the window, and then the window disappears.
6371 * The monitor does not get cancel right away. But if more events come in, the touch gets canceled
6372 * for the monitor, as well.
6373 * 1. foregroundWindow
6374 * 2. monitor <-- global monitor (doesn't observe z order, receives all events)
6375 */
Prabir Pradhan1376fcd2022-01-21 09:56:35 -08006376TEST_F(InputDispatcherMonitorTest, MonitorTouchIsCanceledWhenForegroundWindowDisappears) {
Siarhei Vishniakouca205502021-07-16 21:31:58 +00006377 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
6378 sp<FakeWindowHandle> window =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07006379 sp<FakeWindowHandle>::make(application, mDispatcher, "Foreground", ADISPLAY_ID_DEFAULT);
Siarhei Vishniakouca205502021-07-16 21:31:58 +00006380
Prabir Pradhanfb549072023-10-05 19:17:36 +00006381 FakeMonitorReceiver monitor = FakeMonitorReceiver(*mDispatcher, "M_1", ADISPLAY_ID_DEFAULT);
Siarhei Vishniakouca205502021-07-16 21:31:58 +00006382
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07006383 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Siarhei Vishniakouca205502021-07-16 21:31:58 +00006384 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07006385 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
Siarhei Vishniakouca205502021-07-16 21:31:58 +00006386 {100, 200}))
6387 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
6388
6389 // Both the foreground window and the global monitor should receive the touch down
6390 window->consumeMotionDown();
6391 monitor.consumeMotionDown(ADISPLAY_ID_DEFAULT);
6392
6393 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07006394 injectMotionEvent(*mDispatcher, AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN,
Siarhei Vishniakouca205502021-07-16 21:31:58 +00006395 ADISPLAY_ID_DEFAULT, {110, 200}))
6396 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
6397
6398 window->consumeMotionMove();
6399 monitor.consumeMotionMove(ADISPLAY_ID_DEFAULT);
6400
6401 // Now the foreground window goes away
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07006402 mDispatcher->onWindowInfosChanged({{}, {}, 0, 0});
Siarhei Vishniakouca205502021-07-16 21:31:58 +00006403 window->consumeMotionCancel();
6404 monitor.assertNoEvents(); // Global monitor does not get a cancel yet
6405
6406 // If more events come in, there will be no more foreground window to send them to. This will
6407 // cause a cancel for the monitor, as well.
6408 ASSERT_EQ(InputEventInjectionResult::FAILED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07006409 injectMotionEvent(*mDispatcher, AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN,
Siarhei Vishniakouca205502021-07-16 21:31:58 +00006410 ADISPLAY_ID_DEFAULT, {120, 200}))
6411 << "Injection should fail because the window was removed";
6412 window->assertNoEvents();
6413 // Global monitor now gets the cancel
6414 monitor.consumeMotionCancel(ADISPLAY_ID_DEFAULT);
6415}
6416
Prabir Pradhan1376fcd2022-01-21 09:56:35 -08006417TEST_F(InputDispatcherMonitorTest, ReceivesMotionEvents) {
Chris Yea209fde2020-07-22 13:54:51 -07006418 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07006419 sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher,
6420 "Fake Window", ADISPLAY_ID_DEFAULT);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07006421 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Michael Wright3a240c42019-12-10 20:53:41 +00006422
Prabir Pradhanfb549072023-10-05 19:17:36 +00006423 FakeMonitorReceiver monitor = FakeMonitorReceiver(*mDispatcher, "M_1", ADISPLAY_ID_DEFAULT);
Michael Wright3a240c42019-12-10 20:53:41 +00006424
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08006425 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07006426 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT))
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08006427 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
Michael Wright3a240c42019-12-10 20:53:41 +00006428 window->consumeMotionDown(ADISPLAY_ID_DEFAULT);
chaviwd1c23182019-12-20 18:44:56 -08006429 monitor.consumeMotionDown(ADISPLAY_ID_DEFAULT);
Michael Wright3a240c42019-12-10 20:53:41 +00006430}
6431
Prabir Pradhan1376fcd2022-01-21 09:56:35 -08006432TEST_F(InputDispatcherMonitorTest, MonitorCannotPilferPointers) {
Prabir Pradhanfb549072023-10-05 19:17:36 +00006433 FakeMonitorReceiver monitor = FakeMonitorReceiver(*mDispatcher, "M_1", ADISPLAY_ID_DEFAULT);
Michael Wright3a240c42019-12-10 20:53:41 +00006434
Chris Yea209fde2020-07-22 13:54:51 -07006435 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07006436 sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher,
6437 "Fake Window", ADISPLAY_ID_DEFAULT);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07006438 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Michael Wright3a240c42019-12-10 20:53:41 +00006439
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08006440 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07006441 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT))
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08006442 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
chaviwd1c23182019-12-20 18:44:56 -08006443 monitor.consumeMotionDown(ADISPLAY_ID_DEFAULT);
Prabir Pradhan1376fcd2022-01-21 09:56:35 -08006444 window->consumeMotionDown(ADISPLAY_ID_DEFAULT);
Michael Wright3a240c42019-12-10 20:53:41 +00006445
Prabir Pradhan1376fcd2022-01-21 09:56:35 -08006446 // Pilfer pointers from the monitor.
6447 // This should not do anything and the window should continue to receive events.
6448 EXPECT_NE(OK, mDispatcher->pilferPointers(monitor.getToken()));
Michael Wright3a240c42019-12-10 20:53:41 +00006449
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08006450 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07006451 injectMotionEvent(*mDispatcher, AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN,
Prabir Pradhan1376fcd2022-01-21 09:56:35 -08006452 ADISPLAY_ID_DEFAULT))
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08006453 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
Prabir Pradhan1376fcd2022-01-21 09:56:35 -08006454
6455 monitor.consumeMotionMove(ADISPLAY_ID_DEFAULT);
6456 window->consumeMotionMove(ADISPLAY_ID_DEFAULT);
Michael Wright3a240c42019-12-10 20:53:41 +00006457}
6458
Prabir Pradhan1376fcd2022-01-21 09:56:35 -08006459TEST_F(InputDispatcherMonitorTest, NoWindowTransform) {
Evan Rosky84f07f02021-04-16 10:42:42 -07006460 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07006461 sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher,
6462 "Fake Window", ADISPLAY_ID_DEFAULT);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07006463 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Evan Rosky84f07f02021-04-16 10:42:42 -07006464 window->setWindowOffset(20, 40);
6465 window->setWindowTransform(0, 1, -1, 0);
6466
Prabir Pradhanfb549072023-10-05 19:17:36 +00006467 FakeMonitorReceiver monitor = FakeMonitorReceiver(*mDispatcher, "M_1", ADISPLAY_ID_DEFAULT);
Evan Rosky84f07f02021-04-16 10:42:42 -07006468
6469 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07006470 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT))
Evan Rosky84f07f02021-04-16 10:42:42 -07006471 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
6472 window->consumeMotionDown(ADISPLAY_ID_DEFAULT);
Siarhei Vishniakoud3061ab2023-12-18 20:41:08 -08006473 std::unique_ptr<MotionEvent> event = monitor.consumeMotion();
6474 ASSERT_NE(nullptr, event);
Evan Rosky84f07f02021-04-16 10:42:42 -07006475 // Even though window has transform, gesture monitor must not.
6476 ASSERT_EQ(ui::Transform(), event->getTransform());
6477}
6478
Prabir Pradhan1376fcd2022-01-21 09:56:35 -08006479TEST_F(InputDispatcherMonitorTest, InjectionFailsWithNoWindow) {
Arthur Hungb3307ee2021-10-14 10:57:37 +00006480 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
Prabir Pradhanfb549072023-10-05 19:17:36 +00006481 FakeMonitorReceiver monitor = FakeMonitorReceiver(*mDispatcher, "M_1", ADISPLAY_ID_DEFAULT);
Arthur Hungb3307ee2021-10-14 10:57:37 +00006482
Prabir Pradhan1376fcd2022-01-21 09:56:35 -08006483 ASSERT_EQ(InputEventInjectionResult::FAILED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07006484 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT))
Prabir Pradhan1376fcd2022-01-21 09:56:35 -08006485 << "Injection should fail if there is a monitor, but no touchable window";
6486 monitor.assertNoEvents();
Arthur Hungb3307ee2021-10-14 10:57:37 +00006487}
6488
Linnan Lid8150952024-01-26 18:07:17 +00006489/**
6490 * Two displays
6491 * The first monitor has a foreground window, a monitor
6492 * The second window has only one monitor.
6493 * We first inject a Down event into the first display, this injection should succeed and both
6494 * the foreground window and monitor should receive a down event, then inject a Down event into
6495 * the second display as well, this injection should fail, at this point, the first display
6496 * window and monitor should not receive a cancel or any other event.
6497 * Continue to inject Move and UP events to the first display, the events should be received
6498 * normally by the foreground window and monitor.
6499 */
6500TEST_F(InputDispatcherMonitorTest, MonitorTouchIsNotCanceledWhenAnotherEmptyDisplayReceiveEvents) {
6501 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
6502 sp<FakeWindowHandle> window =
6503 sp<FakeWindowHandle>::make(application, mDispatcher, "Foreground", ADISPLAY_ID_DEFAULT);
6504
6505 FakeMonitorReceiver monitor = FakeMonitorReceiver(*mDispatcher, "M_1", ADISPLAY_ID_DEFAULT);
6506 FakeMonitorReceiver secondMonitor = FakeMonitorReceiver(*mDispatcher, "M_2", SECOND_DISPLAY_ID);
6507
6508 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
6509 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
6510 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
6511 {100, 200}))
6512 << "The down event injected into the first display should succeed";
6513
6514 window->consumeMotionDown();
6515 monitor.consumeMotionDown(ADISPLAY_ID_DEFAULT);
Linnan Lid8150952024-01-26 18:07:17 +00006516
6517 ASSERT_EQ(InputEventInjectionResult::FAILED,
6518 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, SECOND_DISPLAY_ID,
6519 {100, 200}))
Prabir Pradhana0d43d42024-01-30 00:27:08 +00006520 << "The down event injected into the second display should fail since there's no "
6521 "touchable window";
Linnan Lid8150952024-01-26 18:07:17 +00006522
6523 // Continue to inject event to first display.
6524 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
6525 injectMotionEvent(*mDispatcher, AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN,
6526 ADISPLAY_ID_DEFAULT, {110, 220}))
6527 << "The move event injected into the first display should succeed";
6528
6529 window->consumeMotionMove();
6530 monitor.consumeMotionMove(ADISPLAY_ID_DEFAULT);
Linnan Lid8150952024-01-26 18:07:17 +00006531
6532 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
6533 injectMotionUp(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
6534 {110, 220}))
6535 << "The up event injected into the first display should succeed";
6536
6537 window->consumeMotionUp();
6538 monitor.consumeMotionUp(ADISPLAY_ID_DEFAULT);
Prabir Pradhana0d43d42024-01-30 00:27:08 +00006539
6540 window->assertNoEvents();
6541 monitor.assertNoEvents();
Linnan Lid8150952024-01-26 18:07:17 +00006542 secondMonitor.assertNoEvents();
6543}
6544
6545/**
6546 * Two displays
6547 * There is a monitor and foreground window on each display.
6548 * First, we inject down events into each of the two displays, at this point, the foreground windows
6549 * and monitors on both displays should receive down events.
6550 * At this point, the foreground window of the second display goes away, the gone window should
6551 * receive the cancel event, and the other windows and monitors should not receive any events.
6552 * Inject a move event into the second display. At this point, the injection should fail because
6553 * the second display no longer has a foreground window. At this point, the monitor on the second
6554 * display should receive a cancel event, and any windows or monitors on the first display should
6555 * not receive any events, and any subsequent injection of events into the second display should
6556 * also fail.
6557 * Continue to inject events into the first display, and the events should all be injected
6558 * successfully and received normally.
6559 */
6560TEST_F(InputDispatcherMonitorTest, MonitorTouchIsNotCancelWhenAnotherDisplayMonitorTouchCanceled) {
6561 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
6562 sp<FakeWindowHandle> window =
6563 sp<FakeWindowHandle>::make(application, mDispatcher, "Foreground", ADISPLAY_ID_DEFAULT);
6564 sp<FakeWindowHandle> secondWindow =
6565 sp<FakeWindowHandle>::make(application, mDispatcher, "SecondForeground",
6566 SECOND_DISPLAY_ID);
6567
6568 FakeMonitorReceiver monitor = FakeMonitorReceiver(*mDispatcher, "M_1", ADISPLAY_ID_DEFAULT);
6569 FakeMonitorReceiver secondMonitor = FakeMonitorReceiver(*mDispatcher, "M_2", SECOND_DISPLAY_ID);
6570
6571 // There is a foreground window on both displays.
6572 mDispatcher->onWindowInfosChanged({{*window->getInfo(), *secondWindow->getInfo()}, {}, 0, 0});
6573 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
6574 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
6575 {100, 200}))
6576 << "The down event injected into the first display should succeed";
6577
6578 window->consumeMotionDown(ADISPLAY_ID_DEFAULT);
6579 monitor.consumeMotionDown(ADISPLAY_ID_DEFAULT);
Linnan Lid8150952024-01-26 18:07:17 +00006580
6581 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
6582 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, SECOND_DISPLAY_ID,
6583 {100, 200}))
6584 << "The down event injected into the second display should succeed";
6585
Linnan Lid8150952024-01-26 18:07:17 +00006586 secondWindow->consumeMotionDown(SECOND_DISPLAY_ID);
6587 secondMonitor.consumeMotionDown(SECOND_DISPLAY_ID);
6588
6589 // Now second window is gone away.
6590 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
6591
6592 // The gone window should receive a cancel, and the monitor on the second display should not
6593 // receive any events.
Linnan Lid8150952024-01-26 18:07:17 +00006594 secondWindow->consumeMotionCancel(SECOND_DISPLAY_ID);
6595 secondMonitor.assertNoEvents();
6596
6597 ASSERT_EQ(InputEventInjectionResult::FAILED,
6598 injectMotionEvent(*mDispatcher, AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN,
6599 SECOND_DISPLAY_ID, {110, 220}))
Prabir Pradhana0d43d42024-01-30 00:27:08 +00006600 << "The move event injected into the second display should fail because there's no "
6601 "touchable window";
Linnan Lid8150952024-01-26 18:07:17 +00006602 // Now the monitor on the second display should receive a cancel event.
6603 secondMonitor.consumeMotionCancel(SECOND_DISPLAY_ID);
Linnan Lid8150952024-01-26 18:07:17 +00006604
6605 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
6606 injectMotionEvent(*mDispatcher, AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN,
6607 ADISPLAY_ID_DEFAULT, {110, 200}))
6608 << "The move event injected into the first display should succeed";
6609
6610 window->consumeMotionMove();
6611 monitor.consumeMotionMove(ADISPLAY_ID_DEFAULT);
Linnan Lid8150952024-01-26 18:07:17 +00006612
6613 ASSERT_EQ(InputEventInjectionResult::FAILED,
Prabir Pradhana0d43d42024-01-30 00:27:08 +00006614 injectMotionUp(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, SECOND_DISPLAY_ID,
6615 {110, 220}))
6616 << "The up event injected into the second display should fail because there's no "
6617 "touchable window";
Linnan Lid8150952024-01-26 18:07:17 +00006618
6619 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
6620 injectMotionUp(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
6621 {110, 220}))
6622 << "The up event injected into the first display should succeed";
6623
6624 window->consumeMotionUp(ADISPLAY_ID_DEFAULT);
6625 monitor.consumeMotionUp(ADISPLAY_ID_DEFAULT);
Prabir Pradhana0d43d42024-01-30 00:27:08 +00006626
Linnan Lid8150952024-01-26 18:07:17 +00006627 window->assertNoEvents();
6628 monitor.assertNoEvents();
Prabir Pradhana0d43d42024-01-30 00:27:08 +00006629 secondWindow->assertNoEvents();
6630 secondMonitor.assertNoEvents();
Linnan Lid8150952024-01-26 18:07:17 +00006631}
6632
6633/**
6634 * One display with transform
6635 * There is a foreground window and a monitor on the display
6636 * Inject down event and move event sequentially, the foreground window and monitor can receive down
6637 * event and move event, then let the foreground window go away, the foreground window receives
6638 * cancel event, inject move event again, the monitor receives cancel event, all the events received
6639 * by the monitor should be with the same transform as the display
6640 */
6641TEST_F(InputDispatcherMonitorTest, MonitorTouchCancelEventWithDisplayTransform) {
6642 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
6643 sp<FakeWindowHandle> window =
6644 sp<FakeWindowHandle>::make(application, mDispatcher, "Foreground", ADISPLAY_ID_DEFAULT);
6645 FakeMonitorReceiver monitor = FakeMonitorReceiver(*mDispatcher, "M_1", ADISPLAY_ID_DEFAULT);
6646
6647 ui::Transform transform;
6648 transform.set({1.1, 2.2, 3.3, 4.4, 5.5, 6.6, 0, 0, 1});
6649
6650 gui::DisplayInfo displayInfo;
6651 displayInfo.displayId = ADISPLAY_ID_DEFAULT;
6652 displayInfo.transform = transform;
6653
6654 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {displayInfo}, 0, 0});
6655
6656 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
6657 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
6658 {100, 200}))
6659 << "The down event injected should succeed";
6660
6661 window->consumeMotionDown();
6662 std::unique_ptr<MotionEvent> downMotionEvent = monitor.consumeMotion();
6663 EXPECT_EQ(transform, downMotionEvent->getTransform());
6664 EXPECT_EQ(AMOTION_EVENT_ACTION_DOWN, downMotionEvent->getAction());
6665
6666 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
6667 injectMotionEvent(*mDispatcher, AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN,
6668 ADISPLAY_ID_DEFAULT, {110, 220}))
6669 << "The move event injected should succeed";
6670
6671 window->consumeMotionMove();
6672 std::unique_ptr<MotionEvent> moveMotionEvent = monitor.consumeMotion();
6673 EXPECT_EQ(transform, moveMotionEvent->getTransform());
6674 EXPECT_EQ(AMOTION_EVENT_ACTION_MOVE, moveMotionEvent->getAction());
6675
6676 // Let foreground window gone
6677 mDispatcher->onWindowInfosChanged({{}, {displayInfo}, 0, 0});
6678
Prabir Pradhana0d43d42024-01-30 00:27:08 +00006679 // Foreground window should receive a cancel event, but not the monitor.
Linnan Lid8150952024-01-26 18:07:17 +00006680 window->consumeMotionCancel();
Linnan Lid8150952024-01-26 18:07:17 +00006681
6682 ASSERT_EQ(InputEventInjectionResult::FAILED,
6683 injectMotionEvent(*mDispatcher, AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN,
6684 ADISPLAY_ID_DEFAULT, {110, 220}))
6685 << "The move event injected should failed";
6686 // Now foreground should not receive any events, but monitor should receive a cancel event
6687 // with transform that same as display's display.
Linnan Lid8150952024-01-26 18:07:17 +00006688 std::unique_ptr<MotionEvent> cancelMotionEvent = monitor.consumeMotion();
6689 EXPECT_EQ(transform, cancelMotionEvent->getTransform());
6690 EXPECT_EQ(ADISPLAY_ID_DEFAULT, cancelMotionEvent->getDisplayId());
6691 EXPECT_EQ(AMOTION_EVENT_ACTION_CANCEL, cancelMotionEvent->getAction());
6692
6693 // Other event inject to this display should fail.
6694 ASSERT_EQ(InputEventInjectionResult::FAILED,
6695 injectMotionEvent(*mDispatcher, AMOTION_EVENT_ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN,
6696 ADISPLAY_ID_DEFAULT, {110, 220}))
Prabir Pradhana0d43d42024-01-30 00:27:08 +00006697 << "The up event injected should fail because the touched window was removed";
Linnan Lid8150952024-01-26 18:07:17 +00006698 window->assertNoEvents();
6699 monitor.assertNoEvents();
6700}
6701
chaviw81e2bb92019-12-18 15:03:51 -08006702TEST_F(InputDispatcherTest, TestMoveEvent) {
Chris Yea209fde2020-07-22 13:54:51 -07006703 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07006704 sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher,
6705 "Fake Window", ADISPLAY_ID_DEFAULT);
chaviw81e2bb92019-12-18 15:03:51 -08006706
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07006707 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
chaviw81e2bb92019-12-18 15:03:51 -08006708
6709 NotifyMotionArgs motionArgs =
6710 generateMotionArgs(AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN,
6711 ADISPLAY_ID_DEFAULT);
6712
Prabir Pradhan678438e2023-04-13 19:32:51 +00006713 mDispatcher->notifyMotion(motionArgs);
chaviw81e2bb92019-12-18 15:03:51 -08006714 // Window should receive motion down event.
6715 window->consumeMotionDown(ADISPLAY_ID_DEFAULT);
6716
6717 motionArgs.action = AMOTION_EVENT_ACTION_MOVE;
Garfield Tanc51d1ba2020-01-28 13:24:04 -08006718 motionArgs.id += 1;
chaviw81e2bb92019-12-18 15:03:51 -08006719 motionArgs.eventTime = systemTime(SYSTEM_TIME_MONOTONIC);
6720 motionArgs.pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_X,
6721 motionArgs.pointerCoords[0].getX() - 10);
6722
Prabir Pradhan678438e2023-04-13 19:32:51 +00006723 mDispatcher->notifyMotion(motionArgs);
Prabir Pradhan7662a8d2023-12-15 01:58:14 +00006724 window->consumeMotionMove(ADISPLAY_ID_DEFAULT, /*expectedFlags=*/0);
chaviw81e2bb92019-12-18 15:03:51 -08006725}
6726
Siarhei Vishniakouf1035d42019-09-20 16:32:01 +01006727/**
6728 * Dispatcher has touch mode enabled by default. Typically, the policy overrides that value to
6729 * the device default right away. In the test scenario, we check both the default value,
6730 * and the action of enabling / disabling.
6731 */
6732TEST_F(InputDispatcherTest, TouchModeState_IsSentToApps) {
Chris Yea209fde2020-07-22 13:54:51 -07006733 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07006734 sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher,
6735 "Test window", ADISPLAY_ID_DEFAULT);
Antonio Kantekea47acb2021-12-23 12:41:25 -08006736 const WindowInfo& windowInfo = *window->getInfo();
Siarhei Vishniakouf1035d42019-09-20 16:32:01 +01006737
6738 // Set focused application.
6739 mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application);
Vishnu Nair47074b82020-08-14 11:54:47 -07006740 window->setFocusable(true);
Siarhei Vishniakouf1035d42019-09-20 16:32:01 +01006741
6742 SCOPED_TRACE("Check default value of touch mode");
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07006743 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Vishnu Nair958da932020-08-21 17:12:37 -07006744 setFocusedWindow(window);
Harry Cutts33476232023-01-30 19:57:29 +00006745 window->consumeFocusEvent(/*hasFocus=*/true, /*inTouchMode=*/true);
Siarhei Vishniakouf1035d42019-09-20 16:32:01 +01006746
6747 SCOPED_TRACE("Remove the window to trigger focus loss");
Vishnu Nair47074b82020-08-14 11:54:47 -07006748 window->setFocusable(false);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07006749 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Harry Cutts33476232023-01-30 19:57:29 +00006750 window->consumeFocusEvent(/*hasFocus=*/false, /*inTouchMode=*/true);
Siarhei Vishniakouf1035d42019-09-20 16:32:01 +01006751
6752 SCOPED_TRACE("Disable touch mode");
Antonio Kantekea47acb2021-12-23 12:41:25 -08006753 mDispatcher->setInTouchMode(false, windowInfo.ownerPid, windowInfo.ownerUid,
Harry Cutts33476232023-01-30 19:57:29 +00006754 /*hasPermission=*/true, ADISPLAY_ID_DEFAULT);
Antonio Kantekf16f2832021-09-28 04:39:20 +00006755 window->consumeTouchModeEvent(false);
Vishnu Nair47074b82020-08-14 11:54:47 -07006756 window->setFocusable(true);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07006757 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Vishnu Nair958da932020-08-21 17:12:37 -07006758 setFocusedWindow(window);
Harry Cutts33476232023-01-30 19:57:29 +00006759 window->consumeFocusEvent(/*hasFocus=*/true, /*inTouchMode=*/false);
Siarhei Vishniakouf1035d42019-09-20 16:32:01 +01006760
6761 SCOPED_TRACE("Remove the window to trigger focus loss");
Vishnu Nair47074b82020-08-14 11:54:47 -07006762 window->setFocusable(false);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07006763 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Harry Cutts33476232023-01-30 19:57:29 +00006764 window->consumeFocusEvent(/*hasFocus=*/false, /*inTouchMode=*/false);
Siarhei Vishniakouf1035d42019-09-20 16:32:01 +01006765
6766 SCOPED_TRACE("Enable touch mode again");
Antonio Kantekea47acb2021-12-23 12:41:25 -08006767 mDispatcher->setInTouchMode(true, windowInfo.ownerPid, windowInfo.ownerUid,
Harry Cutts33476232023-01-30 19:57:29 +00006768 /*hasPermission=*/true, ADISPLAY_ID_DEFAULT);
Antonio Kantekf16f2832021-09-28 04:39:20 +00006769 window->consumeTouchModeEvent(true);
Vishnu Nair47074b82020-08-14 11:54:47 -07006770 window->setFocusable(true);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07006771 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Vishnu Nair958da932020-08-21 17:12:37 -07006772 setFocusedWindow(window);
Harry Cutts33476232023-01-30 19:57:29 +00006773 window->consumeFocusEvent(/*hasFocus=*/true, /*inTouchMode=*/true);
Siarhei Vishniakouf1035d42019-09-20 16:32:01 +01006774
6775 window->assertNoEvents();
6776}
6777
Gang Wange9087892020-01-07 12:17:14 -05006778TEST_F(InputDispatcherTest, VerifyInputEvent_KeyEvent) {
Chris Yea209fde2020-07-22 13:54:51 -07006779 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07006780 sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher,
6781 "Test window", ADISPLAY_ID_DEFAULT);
Gang Wange9087892020-01-07 12:17:14 -05006782
6783 mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application);
Vishnu Nair47074b82020-08-14 11:54:47 -07006784 window->setFocusable(true);
Gang Wange9087892020-01-07 12:17:14 -05006785
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07006786 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Vishnu Nair958da932020-08-21 17:12:37 -07006787 setFocusedWindow(window);
6788
Harry Cutts33476232023-01-30 19:57:29 +00006789 window->consumeFocusEvent(/*hasFocus=*/true, /*inTouchMode=*/true);
Gang Wange9087892020-01-07 12:17:14 -05006790
Prabir Pradhan678438e2023-04-13 19:32:51 +00006791 const NotifyKeyArgs keyArgs = generateKeyArgs(AKEY_EVENT_ACTION_DOWN);
6792 mDispatcher->notifyKey(keyArgs);
Gang Wange9087892020-01-07 12:17:14 -05006793
Siarhei Vishniakoud3061ab2023-12-18 20:41:08 -08006794 std::unique_ptr<KeyEvent> event = window->consumeKey();
6795 ASSERT_NE(event, nullptr);
6796 std::unique_ptr<VerifiedInputEvent> verified = mDispatcher->verifyInputEvent(*event);
Gang Wange9087892020-01-07 12:17:14 -05006797 ASSERT_NE(verified, nullptr);
6798 ASSERT_EQ(verified->type, VerifiedInputEvent::Type::KEY);
6799
6800 ASSERT_EQ(keyArgs.eventTime, verified->eventTimeNanos);
6801 ASSERT_EQ(keyArgs.deviceId, verified->deviceId);
6802 ASSERT_EQ(keyArgs.source, verified->source);
6803 ASSERT_EQ(keyArgs.displayId, verified->displayId);
6804
6805 const VerifiedKeyEvent& verifiedKey = static_cast<const VerifiedKeyEvent&>(*verified);
6806
6807 ASSERT_EQ(keyArgs.action, verifiedKey.action);
Gang Wange9087892020-01-07 12:17:14 -05006808 ASSERT_EQ(keyArgs.flags & VERIFIED_KEY_EVENT_FLAGS, verifiedKey.flags);
Siarhei Vishniakouf355bf92021-12-09 10:43:21 -08006809 ASSERT_EQ(keyArgs.downTime, verifiedKey.downTimeNanos);
Gang Wange9087892020-01-07 12:17:14 -05006810 ASSERT_EQ(keyArgs.keyCode, verifiedKey.keyCode);
6811 ASSERT_EQ(keyArgs.scanCode, verifiedKey.scanCode);
6812 ASSERT_EQ(keyArgs.metaState, verifiedKey.metaState);
6813 ASSERT_EQ(0, verifiedKey.repeatCount);
6814}
6815
Siarhei Vishniakou47040bf2020-02-28 15:03:13 -08006816TEST_F(InputDispatcherTest, VerifyInputEvent_MotionEvent) {
Chris Yea209fde2020-07-22 13:54:51 -07006817 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07006818 sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher,
6819 "Test window", ADISPLAY_ID_DEFAULT);
Siarhei Vishniakou47040bf2020-02-28 15:03:13 -08006820
6821 mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application);
6822
Prabir Pradhanb5cb9572021-09-24 06:35:16 -07006823 ui::Transform transform;
6824 transform.set({1.1, 2.2, 3.3, 4.4, 5.5, 6.6, 0, 0, 1});
6825
6826 gui::DisplayInfo displayInfo;
6827 displayInfo.displayId = ADISPLAY_ID_DEFAULT;
6828 displayInfo.transform = transform;
6829
Patrick Williamsd828f302023-04-28 17:52:08 -05006830 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {displayInfo}, 0, 0});
Siarhei Vishniakou47040bf2020-02-28 15:03:13 -08006831
Prabir Pradhan678438e2023-04-13 19:32:51 +00006832 const NotifyMotionArgs motionArgs =
Siarhei Vishniakou47040bf2020-02-28 15:03:13 -08006833 generateMotionArgs(AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN,
6834 ADISPLAY_ID_DEFAULT);
Prabir Pradhan678438e2023-04-13 19:32:51 +00006835 mDispatcher->notifyMotion(motionArgs);
Siarhei Vishniakou47040bf2020-02-28 15:03:13 -08006836
Siarhei Vishniakoud3061ab2023-12-18 20:41:08 -08006837 std::unique_ptr<MotionEvent> event = window->consumeMotionEvent();
6838 ASSERT_NE(nullptr, event);
6839 std::unique_ptr<VerifiedInputEvent> verified = mDispatcher->verifyInputEvent(*event);
Siarhei Vishniakou47040bf2020-02-28 15:03:13 -08006840 ASSERT_NE(verified, nullptr);
6841 ASSERT_EQ(verified->type, VerifiedInputEvent::Type::MOTION);
6842
6843 EXPECT_EQ(motionArgs.eventTime, verified->eventTimeNanos);
6844 EXPECT_EQ(motionArgs.deviceId, verified->deviceId);
6845 EXPECT_EQ(motionArgs.source, verified->source);
6846 EXPECT_EQ(motionArgs.displayId, verified->displayId);
6847
6848 const VerifiedMotionEvent& verifiedMotion = static_cast<const VerifiedMotionEvent&>(*verified);
6849
Prabir Pradhanb5cb9572021-09-24 06:35:16 -07006850 const vec2 rawXY =
6851 MotionEvent::calculateTransformedXY(motionArgs.source, transform,
6852 motionArgs.pointerCoords[0].getXYValue());
6853 EXPECT_EQ(rawXY.x, verifiedMotion.rawX);
6854 EXPECT_EQ(rawXY.y, verifiedMotion.rawY);
Siarhei Vishniakou47040bf2020-02-28 15:03:13 -08006855 EXPECT_EQ(motionArgs.action & AMOTION_EVENT_ACTION_MASK, verifiedMotion.actionMasked);
Siarhei Vishniakou47040bf2020-02-28 15:03:13 -08006856 EXPECT_EQ(motionArgs.flags & VERIFIED_MOTION_EVENT_FLAGS, verifiedMotion.flags);
Siarhei Vishniakouf355bf92021-12-09 10:43:21 -08006857 EXPECT_EQ(motionArgs.downTime, verifiedMotion.downTimeNanos);
Siarhei Vishniakou47040bf2020-02-28 15:03:13 -08006858 EXPECT_EQ(motionArgs.metaState, verifiedMotion.metaState);
6859 EXPECT_EQ(motionArgs.buttonState, verifiedMotion.buttonState);
6860}
6861
chaviw09c8d2d2020-08-24 15:48:26 -07006862/**
6863 * Ensure that separate calls to sign the same data are generating the same key.
6864 * We avoid asserting against INVALID_HMAC. Since the key is random, there is a non-zero chance
6865 * that a specific key and data combination would produce INVALID_HMAC, which would cause flaky
6866 * tests.
6867 */
6868TEST_F(InputDispatcherTest, GeneratedHmac_IsConsistent) {
6869 KeyEvent event = getTestKeyEvent();
6870 VerifiedKeyEvent verifiedEvent = verifiedKeyEventFromKeyEvent(event);
6871
6872 std::array<uint8_t, 32> hmac1 = mDispatcher->sign(verifiedEvent);
6873 std::array<uint8_t, 32> hmac2 = mDispatcher->sign(verifiedEvent);
6874 ASSERT_EQ(hmac1, hmac2);
6875}
6876
6877/**
6878 * Ensure that changes in VerifiedKeyEvent produce a different hmac.
6879 */
6880TEST_F(InputDispatcherTest, GeneratedHmac_ChangesWhenFieldsChange) {
6881 KeyEvent event = getTestKeyEvent();
6882 VerifiedKeyEvent verifiedEvent = verifiedKeyEventFromKeyEvent(event);
6883 std::array<uint8_t, 32> initialHmac = mDispatcher->sign(verifiedEvent);
6884
6885 verifiedEvent.deviceId += 1;
6886 ASSERT_NE(initialHmac, mDispatcher->sign(verifiedEvent));
6887
6888 verifiedEvent.source += 1;
6889 ASSERT_NE(initialHmac, mDispatcher->sign(verifiedEvent));
6890
6891 verifiedEvent.eventTimeNanos += 1;
6892 ASSERT_NE(initialHmac, mDispatcher->sign(verifiedEvent));
6893
6894 verifiedEvent.displayId += 1;
6895 ASSERT_NE(initialHmac, mDispatcher->sign(verifiedEvent));
6896
6897 verifiedEvent.action += 1;
6898 ASSERT_NE(initialHmac, mDispatcher->sign(verifiedEvent));
6899
6900 verifiedEvent.downTimeNanos += 1;
6901 ASSERT_NE(initialHmac, mDispatcher->sign(verifiedEvent));
6902
6903 verifiedEvent.flags += 1;
6904 ASSERT_NE(initialHmac, mDispatcher->sign(verifiedEvent));
6905
6906 verifiedEvent.keyCode += 1;
6907 ASSERT_NE(initialHmac, mDispatcher->sign(verifiedEvent));
6908
6909 verifiedEvent.scanCode += 1;
6910 ASSERT_NE(initialHmac, mDispatcher->sign(verifiedEvent));
6911
6912 verifiedEvent.metaState += 1;
6913 ASSERT_NE(initialHmac, mDispatcher->sign(verifiedEvent));
6914
6915 verifiedEvent.repeatCount += 1;
6916 ASSERT_NE(initialHmac, mDispatcher->sign(verifiedEvent));
6917}
6918
Vishnu Nair958da932020-08-21 17:12:37 -07006919TEST_F(InputDispatcherTest, SetFocusedWindow) {
6920 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
6921 sp<FakeWindowHandle> windowTop =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07006922 sp<FakeWindowHandle>::make(application, mDispatcher, "Top", ADISPLAY_ID_DEFAULT);
Vishnu Nair958da932020-08-21 17:12:37 -07006923 sp<FakeWindowHandle> windowSecond =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07006924 sp<FakeWindowHandle>::make(application, mDispatcher, "Second", ADISPLAY_ID_DEFAULT);
Vishnu Nair958da932020-08-21 17:12:37 -07006925 mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application);
6926
6927 // Top window is also focusable but is not granted focus.
6928 windowTop->setFocusable(true);
6929 windowSecond->setFocusable(true);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07006930 mDispatcher->onWindowInfosChanged(
6931 {{*windowTop->getInfo(), *windowSecond->getInfo()}, {}, 0, 0});
Vishnu Nair958da932020-08-21 17:12:37 -07006932 setFocusedWindow(windowSecond);
6933
6934 windowSecond->consumeFocusEvent(true);
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07006935 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectKeyDown(*mDispatcher))
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08006936 << "Inject key event should return InputEventInjectionResult::SUCCEEDED";
Vishnu Nair958da932020-08-21 17:12:37 -07006937
6938 // Focused window should receive event.
6939 windowSecond->consumeKeyDown(ADISPLAY_ID_NONE);
6940 windowTop->assertNoEvents();
6941}
6942
6943TEST_F(InputDispatcherTest, SetFocusedWindow_DropRequestInvalidChannel) {
6944 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
6945 sp<FakeWindowHandle> window =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07006946 sp<FakeWindowHandle>::make(application, mDispatcher, "TestWindow", ADISPLAY_ID_DEFAULT);
Vishnu Nair958da932020-08-21 17:12:37 -07006947 mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application);
6948
6949 window->setFocusable(true);
6950 // Release channel for window is no longer valid.
6951 window->releaseChannel();
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07006952 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Vishnu Nair958da932020-08-21 17:12:37 -07006953 setFocusedWindow(window);
6954
6955 // Test inject a key down, should timeout.
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07006956 ASSERT_NO_FATAL_FAILURE(assertInjectedKeyTimesOut(*mDispatcher));
Vishnu Nair958da932020-08-21 17:12:37 -07006957
6958 // window channel is invalid, so it should not receive any input event.
6959 window->assertNoEvents();
6960}
6961
6962TEST_F(InputDispatcherTest, SetFocusedWindow_DropRequestNoFocusableWindow) {
6963 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
6964 sp<FakeWindowHandle> window =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07006965 sp<FakeWindowHandle>::make(application, mDispatcher, "TestWindow", ADISPLAY_ID_DEFAULT);
Prabir Pradhan76bdecb2022-01-31 11:14:15 -08006966 window->setFocusable(false);
Vishnu Nair958da932020-08-21 17:12:37 -07006967 mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application);
6968
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07006969 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Vishnu Nair958da932020-08-21 17:12:37 -07006970 setFocusedWindow(window);
6971
6972 // Test inject a key down, should timeout.
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07006973 ASSERT_NO_FATAL_FAILURE(assertInjectedKeyTimesOut(*mDispatcher));
Vishnu Nair958da932020-08-21 17:12:37 -07006974
Prabir Pradhan76bdecb2022-01-31 11:14:15 -08006975 // window is not focusable, so it should not receive any input event.
Vishnu Nair958da932020-08-21 17:12:37 -07006976 window->assertNoEvents();
6977}
6978
6979TEST_F(InputDispatcherTest, SetFocusedWindow_CheckFocusedToken) {
6980 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
6981 sp<FakeWindowHandle> windowTop =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07006982 sp<FakeWindowHandle>::make(application, mDispatcher, "Top", ADISPLAY_ID_DEFAULT);
Vishnu Nair958da932020-08-21 17:12:37 -07006983 sp<FakeWindowHandle> windowSecond =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07006984 sp<FakeWindowHandle>::make(application, mDispatcher, "Second", ADISPLAY_ID_DEFAULT);
Vishnu Nair958da932020-08-21 17:12:37 -07006985 mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application);
6986
6987 windowTop->setFocusable(true);
6988 windowSecond->setFocusable(true);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07006989 mDispatcher->onWindowInfosChanged(
6990 {{*windowTop->getInfo(), *windowSecond->getInfo()}, {}, 0, 0});
Vishnu Nair958da932020-08-21 17:12:37 -07006991 setFocusedWindow(windowTop);
6992 windowTop->consumeFocusEvent(true);
6993
Chavi Weingarten847e8512023-03-29 00:26:09 +00006994 windowTop->editInfo()->focusTransferTarget = windowSecond->getToken();
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07006995 mDispatcher->onWindowInfosChanged(
6996 {{*windowTop->getInfo(), *windowSecond->getInfo()}, {}, 0, 0});
Vishnu Nair958da932020-08-21 17:12:37 -07006997 windowSecond->consumeFocusEvent(true);
6998 windowTop->consumeFocusEvent(false);
6999
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07007000 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectKeyDown(*mDispatcher))
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08007001 << "Inject key event should return InputEventInjectionResult::SUCCEEDED";
Vishnu Nair958da932020-08-21 17:12:37 -07007002
7003 // Focused window should receive event.
7004 windowSecond->consumeKeyDown(ADISPLAY_ID_NONE);
7005}
7006
Chavi Weingarten847e8512023-03-29 00:26:09 +00007007TEST_F(InputDispatcherTest, SetFocusedWindow_TransferFocusTokenNotFocusable) {
Vishnu Nair958da932020-08-21 17:12:37 -07007008 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
7009 sp<FakeWindowHandle> windowTop =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07007010 sp<FakeWindowHandle>::make(application, mDispatcher, "Top", ADISPLAY_ID_DEFAULT);
Vishnu Nair958da932020-08-21 17:12:37 -07007011 sp<FakeWindowHandle> windowSecond =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07007012 sp<FakeWindowHandle>::make(application, mDispatcher, "Second", ADISPLAY_ID_DEFAULT);
Vishnu Nair958da932020-08-21 17:12:37 -07007013 mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application);
7014
7015 windowTop->setFocusable(true);
Chavi Weingarten847e8512023-03-29 00:26:09 +00007016 windowSecond->setFocusable(false);
7017 windowTop->editInfo()->focusTransferTarget = windowSecond->getToken();
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07007018 mDispatcher->onWindowInfosChanged(
7019 {{*windowTop->getInfo(), *windowSecond->getInfo()}, {}, 0, 0});
Chavi Weingarten847e8512023-03-29 00:26:09 +00007020 setFocusedWindow(windowTop);
7021 windowTop->consumeFocusEvent(true);
Vishnu Nair958da932020-08-21 17:12:37 -07007022
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07007023 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectKeyDown(*mDispatcher))
Chavi Weingarten847e8512023-03-29 00:26:09 +00007024 << "Inject key event should return InputEventInjectionResult::SUCCEEDED";
Vishnu Nair958da932020-08-21 17:12:37 -07007025
7026 // Event should be dropped.
Chavi Weingarten847e8512023-03-29 00:26:09 +00007027 windowTop->consumeKeyDown(ADISPLAY_ID_NONE);
Vishnu Nair958da932020-08-21 17:12:37 -07007028 windowSecond->assertNoEvents();
7029}
7030
7031TEST_F(InputDispatcherTest, SetFocusedWindow_DeferInvisibleWindow) {
7032 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
7033 sp<FakeWindowHandle> window =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07007034 sp<FakeWindowHandle>::make(application, mDispatcher, "TestWindow", ADISPLAY_ID_DEFAULT);
Vishnu Nair958da932020-08-21 17:12:37 -07007035 sp<FakeWindowHandle> previousFocusedWindow =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07007036 sp<FakeWindowHandle>::make(application, mDispatcher, "previousFocusedWindow",
7037 ADISPLAY_ID_DEFAULT);
Vishnu Nair958da932020-08-21 17:12:37 -07007038 mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application);
7039
7040 window->setFocusable(true);
7041 previousFocusedWindow->setFocusable(true);
7042 window->setVisible(false);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07007043 mDispatcher->onWindowInfosChanged(
7044 {{*window->getInfo(), *previousFocusedWindow->getInfo()}, {}, 0, 0});
Vishnu Nair958da932020-08-21 17:12:37 -07007045 setFocusedWindow(previousFocusedWindow);
7046 previousFocusedWindow->consumeFocusEvent(true);
7047
7048 // Requesting focus on invisible window takes focus from currently focused window.
7049 setFocusedWindow(window);
7050 previousFocusedWindow->consumeFocusEvent(false);
7051
7052 // Injected key goes to pending queue.
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08007053 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07007054 injectKey(*mDispatcher, AKEY_EVENT_ACTION_DOWN, /*repeatCount=*/0,
7055 ADISPLAY_ID_DEFAULT, InputEventInjectionSync::NONE));
Vishnu Nair958da932020-08-21 17:12:37 -07007056
7057 // Window does not get focus event or key down.
7058 window->assertNoEvents();
7059
7060 // Window becomes visible.
7061 window->setVisible(true);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07007062 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Vishnu Nair958da932020-08-21 17:12:37 -07007063
7064 // Window receives focus event.
7065 window->consumeFocusEvent(true);
7066 // Focused window receives key down.
7067 window->consumeKeyDown(ADISPLAY_ID_DEFAULT);
7068}
7069
Vishnu Nair599f1412021-06-21 10:39:58 -07007070TEST_F(InputDispatcherTest, DisplayRemoved) {
7071 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
7072 sp<FakeWindowHandle> window =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07007073 sp<FakeWindowHandle>::make(application, mDispatcher, "window", ADISPLAY_ID_DEFAULT);
Vishnu Nair599f1412021-06-21 10:39:58 -07007074 mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application);
7075
7076 // window is granted focus.
7077 window->setFocusable(true);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07007078 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Vishnu Nair599f1412021-06-21 10:39:58 -07007079 setFocusedWindow(window);
7080 window->consumeFocusEvent(true);
7081
7082 // When a display is removed window loses focus.
7083 mDispatcher->displayRemoved(ADISPLAY_ID_DEFAULT);
7084 window->consumeFocusEvent(false);
7085}
7086
Siarhei Vishniakou870ecec2020-12-09 08:07:46 -10007087/**
7088 * Launch two windows, with different owners. One window (slipperyExitWindow) has Flag::SLIPPERY,
7089 * and overlaps the other window, slipperyEnterWindow. The window 'slipperyExitWindow' is on top
7090 * of the 'slipperyEnterWindow'.
7091 *
7092 * Inject touch down into the top window. Upon receipt of the DOWN event, move the window in such
7093 * a way so that the touched location is no longer covered by the top window.
7094 *
7095 * Next, inject a MOVE event. Because the top window already moved earlier, this event is now
7096 * positioned over the bottom (slipperyEnterWindow) only. And because the top window had
7097 * Flag::SLIPPERY, this will cause the top window to lose the touch event (it will receive
7098 * ACTION_CANCEL instead), and the bottom window will receive a newly generated gesture (starting
7099 * with ACTION_DOWN).
7100 * Thus, the touch has been transferred from the top window into the bottom window, because the top
7101 * window moved itself away from the touched location and had Flag::SLIPPERY.
7102 *
7103 * Even though the top window moved away from the touched location, it is still obscuring the bottom
7104 * window. It's just not obscuring it at the touched location. That means, FLAG_WINDOW_IS_PARTIALLY_
7105 * OBSCURED should be set for the MotionEvent that reaches the bottom window.
7106 *
7107 * In this test, we ensure that the event received by the bottom window has
7108 * FLAG_WINDOW_IS_PARTIALLY_OBSCURED.
7109 */
7110TEST_F(InputDispatcherTest, SlipperyWindow_SetsFlagPartiallyObscured) {
Prabir Pradhanaeebeb42023-06-13 19:53:03 +00007111 constexpr gui::Pid SLIPPERY_PID{WINDOW_PID.val() + 1};
Prabir Pradhan8a5c41d2023-06-08 19:13:46 +00007112 constexpr gui::Uid SLIPPERY_UID{WINDOW_UID.val() + 1};
Siarhei Vishniakou870ecec2020-12-09 08:07:46 -10007113
7114 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
7115 mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application);
7116
7117 sp<FakeWindowHandle> slipperyExitWindow =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07007118 sp<FakeWindowHandle>::make(application, mDispatcher, "Top", ADISPLAY_ID_DEFAULT);
Prabir Pradhan4d5c52f2022-01-31 08:52:10 -08007119 slipperyExitWindow->setSlippery(true);
Siarhei Vishniakou870ecec2020-12-09 08:07:46 -10007120 // Make sure this one overlaps the bottom window
7121 slipperyExitWindow->setFrame(Rect(25, 25, 75, 75));
7122 // Change the owner uid/pid of the window so that it is considered to be occluding the bottom
7123 // one. Windows with the same owner are not considered to be occluding each other.
7124 slipperyExitWindow->setOwnerInfo(SLIPPERY_PID, SLIPPERY_UID);
7125
7126 sp<FakeWindowHandle> slipperyEnterWindow =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07007127 sp<FakeWindowHandle>::make(application, mDispatcher, "Second", ADISPLAY_ID_DEFAULT);
Siarhei Vishniakou870ecec2020-12-09 08:07:46 -10007128 slipperyExitWindow->setFrame(Rect(0, 0, 100, 100));
7129
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07007130 mDispatcher->onWindowInfosChanged(
7131 {{*slipperyExitWindow->getInfo(), *slipperyEnterWindow->getInfo()}, {}, 0, 0});
Siarhei Vishniakou870ecec2020-12-09 08:07:46 -10007132
7133 // Use notifyMotion instead of injecting to avoid dealing with injection permissions
Prabir Pradhan678438e2023-04-13 19:32:51 +00007134 mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_DOWN,
7135 AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
7136 {{50, 50}}));
Siarhei Vishniakou870ecec2020-12-09 08:07:46 -10007137 slipperyExitWindow->consumeMotionDown();
7138 slipperyExitWindow->setFrame(Rect(70, 70, 100, 100));
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07007139 mDispatcher->onWindowInfosChanged(
7140 {{*slipperyExitWindow->getInfo(), *slipperyEnterWindow->getInfo()}, {}, 0, 0});
Siarhei Vishniakou870ecec2020-12-09 08:07:46 -10007141
Prabir Pradhan678438e2023-04-13 19:32:51 +00007142 mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_MOVE,
7143 AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
7144 {{51, 51}}));
Siarhei Vishniakou870ecec2020-12-09 08:07:46 -10007145
7146 slipperyExitWindow->consumeMotionCancel();
7147
7148 slipperyEnterWindow->consumeMotionDown(ADISPLAY_ID_DEFAULT,
7149 AMOTION_EVENT_FLAG_WINDOW_IS_PARTIALLY_OBSCURED);
7150}
7151
Siarhei Vishniakouafa08cc2023-05-08 22:35:50 -07007152/**
7153 * Two windows, one on the left and another on the right. The left window is slippery. The right
7154 * window isn't eligible to receive touch because it specifies InputConfig::DROP_INPUT. When the
7155 * touch moves from the left window into the right window, the gesture should continue to go to the
7156 * left window. Touch shouldn't slip because the right window can't receive touches. This test
7157 * reproduces a crash.
7158 */
7159TEST_F(InputDispatcherTest, TouchSlippingIntoWindowThatDropsTouches) {
7160 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
7161
7162 sp<FakeWindowHandle> leftSlipperyWindow =
7163 sp<FakeWindowHandle>::make(application, mDispatcher, "Left", ADISPLAY_ID_DEFAULT);
7164 leftSlipperyWindow->setSlippery(true);
7165 leftSlipperyWindow->setFrame(Rect(0, 0, 100, 100));
7166
7167 sp<FakeWindowHandle> rightDropTouchesWindow =
7168 sp<FakeWindowHandle>::make(application, mDispatcher, "Right", ADISPLAY_ID_DEFAULT);
7169 rightDropTouchesWindow->setFrame(Rect(100, 0, 200, 100));
7170 rightDropTouchesWindow->setDropInput(true);
7171
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07007172 mDispatcher->onWindowInfosChanged(
7173 {{*leftSlipperyWindow->getInfo(), *rightDropTouchesWindow->getInfo()}, {}, 0, 0});
Siarhei Vishniakouafa08cc2023-05-08 22:35:50 -07007174
7175 // Start touch in the left window
7176 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
7177 .pointer(PointerBuilder(0, ToolType::FINGER).x(50).y(50))
7178 .build());
7179 leftSlipperyWindow->consumeMotionDown();
7180
7181 // And move it into the right window
7182 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN)
7183 .pointer(PointerBuilder(0, ToolType::FINGER).x(150).y(50))
7184 .build());
7185
7186 // Since the right window isn't eligible to receive input, touch does not slip.
7187 // The left window continues to receive the gesture.
7188 leftSlipperyWindow->consumeMotionEvent(WithMotionAction(ACTION_MOVE));
7189 rightDropTouchesWindow->assertNoEvents();
7190}
7191
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -07007192/**
7193 * A single window is on screen first. Touch is injected into that window. Next, a second window
7194 * appears. Since the first window is slippery, touch will move from the first window to the second.
7195 */
7196TEST_F(InputDispatcherTest, InjectedTouchSlips) {
7197 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
7198 sp<FakeWindowHandle> originalWindow =
7199 sp<FakeWindowHandle>::make(application, mDispatcher, "Original", ADISPLAY_ID_DEFAULT);
7200 originalWindow->setFrame(Rect(0, 0, 200, 200));
7201 originalWindow->setSlippery(true);
7202
7203 sp<FakeWindowHandle> appearingWindow =
7204 sp<FakeWindowHandle>::make(application, mDispatcher, "Appearing", ADISPLAY_ID_DEFAULT);
7205 appearingWindow->setFrame(Rect(0, 0, 200, 200));
7206
7207 mDispatcher->onWindowInfosChanged({{*originalWindow->getInfo()}, {}, 0, 0});
7208
7209 // Touch down on the original window
7210 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
7211 injectMotionEvent(*mDispatcher,
7212 MotionEventBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
7213 .pointer(PointerBuilder(1, ToolType::FINGER).x(100).y(100))
7214 .build()));
7215 originalWindow->consumeMotionEvent(WithMotionAction(ACTION_DOWN));
7216
7217 // Now, a new window appears. This could be, for example, a notification shade that appears
7218 // after user starts to drag down on the launcher window.
7219 mDispatcher->onWindowInfosChanged(
7220 {{*appearingWindow->getInfo(), *originalWindow->getInfo()}, {}, 0, 0});
7221 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
7222 injectMotionEvent(*mDispatcher,
7223 MotionEventBuilder(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN)
7224 .pointer(PointerBuilder(1, ToolType::FINGER).x(110).y(110))
7225 .build()));
7226 originalWindow->consumeMotionEvent(WithMotionAction(ACTION_CANCEL));
7227 appearingWindow->consumeMotionEvent(WithMotionAction(ACTION_DOWN));
7228 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
7229 injectMotionEvent(*mDispatcher,
7230 MotionEventBuilder(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN)
7231 .pointer(PointerBuilder(1, ToolType::FINGER).x(120).y(120))
7232 .build()));
7233 appearingWindow->consumeMotionEvent(WithMotionAction(ACTION_MOVE));
7234
7235 originalWindow->assertNoEvents();
7236 appearingWindow->assertNoEvents();
7237}
7238
Prabir Pradhan8ede1d12023-05-08 19:37:44 +00007239TEST_F(InputDispatcherTest, NotifiesDeviceInteractionsWithMotions) {
Prabir Pradhan8a5c41d2023-06-08 19:13:46 +00007240 using Uid = gui::Uid;
Prabir Pradhan8ede1d12023-05-08 19:37:44 +00007241 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
7242
7243 sp<FakeWindowHandle> leftWindow =
7244 sp<FakeWindowHandle>::make(application, mDispatcher, "Left", ADISPLAY_ID_DEFAULT);
7245 leftWindow->setFrame(Rect(0, 0, 100, 100));
Prabir Pradhanaeebeb42023-06-13 19:53:03 +00007246 leftWindow->setOwnerInfo(gui::Pid{1}, Uid{101});
Prabir Pradhan8ede1d12023-05-08 19:37:44 +00007247
7248 sp<FakeWindowHandle> rightSpy =
7249 sp<FakeWindowHandle>::make(application, mDispatcher, "Right spy", ADISPLAY_ID_DEFAULT);
7250 rightSpy->setFrame(Rect(100, 0, 200, 100));
Prabir Pradhanaeebeb42023-06-13 19:53:03 +00007251 rightSpy->setOwnerInfo(gui::Pid{2}, Uid{102});
Prabir Pradhan8ede1d12023-05-08 19:37:44 +00007252 rightSpy->setSpy(true);
7253 rightSpy->setTrustedOverlay(true);
7254
7255 sp<FakeWindowHandle> rightWindow =
7256 sp<FakeWindowHandle>::make(application, mDispatcher, "Right", ADISPLAY_ID_DEFAULT);
7257 rightWindow->setFrame(Rect(100, 0, 200, 100));
Prabir Pradhanaeebeb42023-06-13 19:53:03 +00007258 rightWindow->setOwnerInfo(gui::Pid{3}, Uid{103});
Prabir Pradhan8ede1d12023-05-08 19:37:44 +00007259
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07007260 mDispatcher->onWindowInfosChanged(
7261 {{*rightSpy->getInfo(), *rightWindow->getInfo(), *leftWindow->getInfo()}, {}, 0, 0});
Prabir Pradhan8ede1d12023-05-08 19:37:44 +00007262
7263 // Touch in the left window
7264 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
7265 .pointer(PointerBuilder(0, ToolType::FINGER).x(50).y(50))
7266 .build());
7267 ASSERT_NO_FATAL_FAILURE(leftWindow->consumeMotionDown());
7268 mDispatcher->waitForIdle();
Prabir Pradhan8a5c41d2023-06-08 19:13:46 +00007269 ASSERT_NO_FATAL_FAILURE(
7270 mFakePolicy->assertNotifyDeviceInteractionWasCalled(DEVICE_ID, {Uid{101}}));
Prabir Pradhan8ede1d12023-05-08 19:37:44 +00007271
7272 // Touch another finger over the right windows
7273 mDispatcher->notifyMotion(MotionArgsBuilder(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
7274 .pointer(PointerBuilder(0, ToolType::FINGER).x(50).y(50))
7275 .pointer(PointerBuilder(1, ToolType::FINGER).x(150).y(50))
7276 .build());
7277 ASSERT_NO_FATAL_FAILURE(rightSpy->consumeMotionDown());
7278 ASSERT_NO_FATAL_FAILURE(rightWindow->consumeMotionDown());
7279 ASSERT_NO_FATAL_FAILURE(leftWindow->consumeMotionMove());
7280 mDispatcher->waitForIdle();
7281 ASSERT_NO_FATAL_FAILURE(
Prabir Pradhan8a5c41d2023-06-08 19:13:46 +00007282 mFakePolicy->assertNotifyDeviceInteractionWasCalled(DEVICE_ID,
7283 {Uid{101}, Uid{102}, Uid{103}}));
Prabir Pradhan8ede1d12023-05-08 19:37:44 +00007284
7285 // Release finger over left window. The UP actions are not treated as device interaction.
7286 // The windows that did not receive the UP pointer will receive MOVE events, but since this
7287 // is part of the UP action, we do not treat this as device interaction.
7288 mDispatcher->notifyMotion(MotionArgsBuilder(POINTER_0_UP, AINPUT_SOURCE_TOUCHSCREEN)
7289 .pointer(PointerBuilder(0, ToolType::FINGER).x(50).y(50))
7290 .pointer(PointerBuilder(1, ToolType::FINGER).x(150).y(50))
7291 .build());
7292 ASSERT_NO_FATAL_FAILURE(leftWindow->consumeMotionUp());
7293 ASSERT_NO_FATAL_FAILURE(rightSpy->consumeMotionMove());
7294 ASSERT_NO_FATAL_FAILURE(rightWindow->consumeMotionMove());
7295 mDispatcher->waitForIdle();
7296 ASSERT_NO_FATAL_FAILURE(mFakePolicy->assertNotifyDeviceInteractionWasNotCalled());
7297
7298 // Move remaining finger
7299 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN)
7300 .pointer(PointerBuilder(1, ToolType::FINGER).x(150).y(50))
7301 .build());
7302 ASSERT_NO_FATAL_FAILURE(rightSpy->consumeMotionMove());
7303 ASSERT_NO_FATAL_FAILURE(rightWindow->consumeMotionMove());
7304 mDispatcher->waitForIdle();
7305 ASSERT_NO_FATAL_FAILURE(
Prabir Pradhan8a5c41d2023-06-08 19:13:46 +00007306 mFakePolicy->assertNotifyDeviceInteractionWasCalled(DEVICE_ID, {Uid{102}, Uid{103}}));
Prabir Pradhan8ede1d12023-05-08 19:37:44 +00007307
7308 // Release all fingers
7309 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN)
7310 .pointer(PointerBuilder(1, ToolType::FINGER).x(150).y(50))
7311 .build());
7312 ASSERT_NO_FATAL_FAILURE(rightSpy->consumeMotionUp());
7313 ASSERT_NO_FATAL_FAILURE(rightWindow->consumeMotionUp());
7314 mDispatcher->waitForIdle();
7315 ASSERT_NO_FATAL_FAILURE(mFakePolicy->assertNotifyDeviceInteractionWasNotCalled());
7316}
7317
7318TEST_F(InputDispatcherTest, NotifiesDeviceInteractionsWithKeys) {
7319 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
7320
7321 sp<FakeWindowHandle> window =
7322 sp<FakeWindowHandle>::make(application, mDispatcher, "Window", ADISPLAY_ID_DEFAULT);
7323 window->setFrame(Rect(0, 0, 100, 100));
Prabir Pradhanaeebeb42023-06-13 19:53:03 +00007324 window->setOwnerInfo(gui::Pid{1}, gui::Uid{101});
Prabir Pradhan8ede1d12023-05-08 19:37:44 +00007325
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07007326 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Prabir Pradhan8ede1d12023-05-08 19:37:44 +00007327 setFocusedWindow(window);
7328 ASSERT_NO_FATAL_FAILURE(window->consumeFocusEvent(true));
7329
7330 mDispatcher->notifyKey(KeyArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_KEYBOARD).build());
7331 ASSERT_NO_FATAL_FAILURE(window->consumeKeyDown(ADISPLAY_ID_DEFAULT));
7332 mDispatcher->waitForIdle();
Prabir Pradhan8a5c41d2023-06-08 19:13:46 +00007333 ASSERT_NO_FATAL_FAILURE(
7334 mFakePolicy->assertNotifyDeviceInteractionWasCalled(DEVICE_ID, {gui::Uid{101}}));
Prabir Pradhan8ede1d12023-05-08 19:37:44 +00007335
7336 // The UP actions are not treated as device interaction.
7337 mDispatcher->notifyKey(KeyArgsBuilder(ACTION_UP, AINPUT_SOURCE_KEYBOARD).build());
7338 ASSERT_NO_FATAL_FAILURE(window->consumeKeyUp(ADISPLAY_ID_DEFAULT));
7339 mDispatcher->waitForIdle();
7340 ASSERT_NO_FATAL_FAILURE(mFakePolicy->assertNotifyDeviceInteractionWasNotCalled());
7341}
7342
Prabir Pradhan5893d362023-11-17 04:30:40 +00007343TEST_F(InputDispatcherTest, HoverEnterExitSynthesisUsesNewEventId) {
7344 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
7345
7346 sp<FakeWindowHandle> left = sp<FakeWindowHandle>::make(application, mDispatcher, "Left Window",
7347 ADISPLAY_ID_DEFAULT);
7348 left->setFrame(Rect(0, 0, 100, 100));
7349 sp<FakeWindowHandle> right = sp<FakeWindowHandle>::make(application, mDispatcher,
7350 "Right Window", ADISPLAY_ID_DEFAULT);
7351 right->setFrame(Rect(100, 0, 200, 100));
7352 sp<FakeWindowHandle> spy =
7353 sp<FakeWindowHandle>::make(application, mDispatcher, "Spy Window", ADISPLAY_ID_DEFAULT);
7354 spy->setFrame(Rect(0, 0, 200, 100));
7355 spy->setTrustedOverlay(true);
7356 spy->setSpy(true);
7357
7358 mDispatcher->onWindowInfosChanged(
7359 {{*spy->getInfo(), *left->getInfo(), *right->getInfo()}, {}, 0, 0});
7360
7361 // Send hover move to the left window, and ensure hover enter is synthesized with a new eventId.
7362 NotifyMotionArgs notifyArgs = generateMotionArgs(ACTION_HOVER_MOVE, AINPUT_SOURCE_STYLUS,
7363 ADISPLAY_ID_DEFAULT, {PointF{50, 50}});
7364 mDispatcher->notifyMotion(notifyArgs);
7365
Siarhei Vishniakoud3061ab2023-12-18 20:41:08 -08007366 std::unique_ptr<MotionEvent> leftEnter = left->consumeMotionEvent(
Prabir Pradhan5893d362023-11-17 04:30:40 +00007367 AllOf(WithMotionAction(ACTION_HOVER_ENTER), Not(WithEventId(notifyArgs.id)),
7368 WithEventIdSource(IdGenerator::Source::INPUT_DISPATCHER)));
Siarhei Vishniakoud3061ab2023-12-18 20:41:08 -08007369 ASSERT_NE(nullptr, leftEnter);
Prabir Pradhan5893d362023-11-17 04:30:40 +00007370 spy->consumeMotionEvent(AllOf(WithMotionAction(ACTION_HOVER_ENTER),
7371 Not(WithEventId(notifyArgs.id)),
Siarhei Vishniakoud3061ab2023-12-18 20:41:08 -08007372 Not(WithEventId(leftEnter->getId())),
Prabir Pradhan5893d362023-11-17 04:30:40 +00007373 WithEventIdSource(IdGenerator::Source::INPUT_DISPATCHER)));
7374
7375 // Send move to the right window, and ensure hover exit and enter are synthesized with new ids.
7376 notifyArgs = generateMotionArgs(ACTION_HOVER_MOVE, AINPUT_SOURCE_STYLUS, ADISPLAY_ID_DEFAULT,
7377 {PointF{150, 50}});
7378 mDispatcher->notifyMotion(notifyArgs);
7379
Siarhei Vishniakoud3061ab2023-12-18 20:41:08 -08007380 std::unique_ptr<MotionEvent> leftExit = left->consumeMotionEvent(
Prabir Pradhan5893d362023-11-17 04:30:40 +00007381 AllOf(WithMotionAction(ACTION_HOVER_EXIT), Not(WithEventId(notifyArgs.id)),
7382 WithEventIdSource(IdGenerator::Source::INPUT_DISPATCHER)));
Siarhei Vishniakoud3061ab2023-12-18 20:41:08 -08007383 ASSERT_NE(nullptr, leftExit);
Prabir Pradhan5893d362023-11-17 04:30:40 +00007384 right->consumeMotionEvent(AllOf(WithMotionAction(ACTION_HOVER_ENTER),
7385 Not(WithEventId(notifyArgs.id)),
Siarhei Vishniakoud3061ab2023-12-18 20:41:08 -08007386 Not(WithEventId(leftExit->getId())),
Prabir Pradhan5893d362023-11-17 04:30:40 +00007387 WithEventIdSource(IdGenerator::Source::INPUT_DISPATCHER)));
7388
7389 spy->consumeMotionEvent(AllOf(WithMotionAction(ACTION_HOVER_MOVE), WithEventId(notifyArgs.id)));
7390}
7391
Prabir Pradhanb0dad3a2023-11-02 20:52:47 +00007392class InputDispatcherFallbackKeyTest : public InputDispatcherTest {
7393protected:
7394 std::shared_ptr<FakeApplicationHandle> mApp;
7395 sp<FakeWindowHandle> mWindow;
7396
7397 virtual void SetUp() override {
7398 InputDispatcherTest::SetUp();
7399
7400 mApp = std::make_shared<FakeApplicationHandle>();
7401
7402 mWindow = sp<FakeWindowHandle>::make(mApp, mDispatcher, "Window", ADISPLAY_ID_DEFAULT);
7403 mWindow->setFrame(Rect(0, 0, 100, 100));
7404
7405 mDispatcher->onWindowInfosChanged({{*mWindow->getInfo()}, {}, 0, 0});
7406 setFocusedWindow(mWindow);
7407 ASSERT_NO_FATAL_FAILURE(mWindow->consumeFocusEvent(/*hasFocus=*/true));
7408 }
7409
7410 void setFallback(int32_t keycode) {
7411 mFakePolicy->setUnhandledKeyHandler([keycode](const KeyEvent& event) {
7412 return KeyEventBuilder(event).keyCode(keycode).build();
7413 });
7414 }
7415
7416 void consumeKey(bool handled, const ::testing::Matcher<KeyEvent>& matcher) {
Siarhei Vishniakoud3061ab2023-12-18 20:41:08 -08007417 std::unique_ptr<KeyEvent> event = mWindow->consumeKey(handled);
7418 ASSERT_NE(nullptr, event);
7419 ASSERT_THAT(*event, matcher);
Prabir Pradhanb0dad3a2023-11-02 20:52:47 +00007420 }
7421};
7422
7423TEST_F(InputDispatcherFallbackKeyTest, PolicyNotNotifiedForHandledKey) {
7424 mDispatcher->notifyKey(
7425 KeyArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_KEYBOARD).keyCode(AKEYCODE_A).build());
7426 consumeKey(/*handled=*/true, AllOf(WithKeyAction(ACTION_DOWN), WithKeyCode(AKEYCODE_A)));
7427 ASSERT_NO_FATAL_FAILURE(mFakePolicy->assertUnhandledKeyNotReported());
7428}
7429
7430TEST_F(InputDispatcherFallbackKeyTest, PolicyNotifiedForUnhandledKey) {
7431 mDispatcher->notifyKey(
7432 KeyArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_KEYBOARD).keyCode(AKEYCODE_A).build());
7433 consumeKey(/*handled=*/false, AllOf(WithKeyAction(ACTION_DOWN), WithKeyCode(AKEYCODE_A)));
7434 ASSERT_NO_FATAL_FAILURE(mFakePolicy->assertUnhandledKeyReported(AKEYCODE_A));
7435}
7436
7437TEST_F(InputDispatcherFallbackKeyTest, NoFallbackRequestedByPolicy) {
7438 mDispatcher->notifyKey(
7439 KeyArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_KEYBOARD).keyCode(AKEYCODE_A).build());
7440
7441 // Do not handle this key event.
7442 consumeKey(/*handled=*/false,
7443 AllOf(WithKeyAction(ACTION_DOWN), WithKeyCode(AKEYCODE_A), WithFlags(0)));
7444 ASSERT_NO_FATAL_FAILURE(mFakePolicy->assertUnhandledKeyReported(AKEYCODE_A));
7445
7446 // Since the policy did not request any fallback to be generated, ensure there are no events.
7447 ASSERT_NO_FATAL_FAILURE(mFakePolicy->assertUnhandledKeyNotReported());
7448}
7449
7450TEST_F(InputDispatcherFallbackKeyTest, FallbackDispatchForUnhandledKey) {
7451 setFallback(AKEYCODE_B);
7452 mDispatcher->notifyKey(
7453 KeyArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_KEYBOARD).keyCode(AKEYCODE_A).build());
7454
7455 // Do not handle this key event.
7456 consumeKey(/*handled=*/false,
7457 AllOf(WithKeyAction(ACTION_DOWN), WithKeyCode(AKEYCODE_A), WithFlags(0)));
7458
7459 // Since the key was not handled, ensure the fallback event was dispatched instead.
7460 ASSERT_NO_FATAL_FAILURE(mFakePolicy->assertUnhandledKeyReported(AKEYCODE_A));
7461 consumeKey(/*handled=*/true,
7462 AllOf(WithKeyAction(ACTION_DOWN), WithKeyCode(AKEYCODE_B),
7463 WithFlags(AKEY_EVENT_FLAG_FALLBACK)));
7464
7465 // Release the original key, and ensure the fallback key is also released.
7466 mDispatcher->notifyKey(
7467 KeyArgsBuilder(ACTION_UP, AINPUT_SOURCE_KEYBOARD).keyCode(AKEYCODE_A).build());
7468 consumeKey(/*handled=*/false,
7469 AllOf(WithKeyAction(ACTION_UP), WithKeyCode(AKEYCODE_A), WithFlags(0)));
7470 ASSERT_NO_FATAL_FAILURE(mFakePolicy->assertUnhandledKeyReported(AKEYCODE_A));
7471 consumeKey(/*handled=*/true,
7472 AllOf(WithKeyAction(ACTION_UP), WithKeyCode(AKEYCODE_B),
7473 WithFlags(AKEY_EVENT_FLAG_FALLBACK)));
7474
7475 ASSERT_NO_FATAL_FAILURE(mFakePolicy->assertUnhandledKeyNotReported());
7476 mWindow->assertNoEvents();
7477}
7478
7479TEST_F(InputDispatcherFallbackKeyTest, AppHandlesPreviouslyUnhandledKey) {
7480 setFallback(AKEYCODE_B);
7481 mDispatcher->notifyKey(
7482 KeyArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_KEYBOARD).keyCode(AKEYCODE_A).build());
7483
7484 // Do not handle this key event, but handle the fallback.
7485 consumeKey(/*handled=*/false,
7486 AllOf(WithKeyAction(ACTION_DOWN), WithKeyCode(AKEYCODE_A), WithFlags(0)));
7487 ASSERT_NO_FATAL_FAILURE(mFakePolicy->assertUnhandledKeyReported(AKEYCODE_A));
7488 consumeKey(/*handled=*/true,
7489 AllOf(WithKeyAction(ACTION_DOWN), WithKeyCode(AKEYCODE_B),
7490 WithFlags(AKEY_EVENT_FLAG_FALLBACK)));
7491
7492 // Release the original key, and ensure the fallback key is also released.
7493 mDispatcher->notifyKey(
7494 KeyArgsBuilder(ACTION_UP, AINPUT_SOURCE_KEYBOARD).keyCode(AKEYCODE_A).build());
7495 // But this time, the app handles the original key.
7496 consumeKey(/*handled=*/true,
7497 AllOf(WithKeyAction(ACTION_UP), WithKeyCode(AKEYCODE_A), WithFlags(0)));
7498 ASSERT_NO_FATAL_FAILURE(mFakePolicy->assertUnhandledKeyReported(AKEYCODE_A));
7499 // Ensure the fallback key is canceled.
7500 consumeKey(/*handled=*/true,
7501 AllOf(WithKeyAction(ACTION_UP), WithKeyCode(AKEYCODE_B),
7502 WithFlags(AKEY_EVENT_FLAG_FALLBACK | AKEY_EVENT_FLAG_CANCELED)));
7503
7504 ASSERT_NO_FATAL_FAILURE(mFakePolicy->assertUnhandledKeyNotReported());
7505 mWindow->assertNoEvents();
7506}
7507
7508TEST_F(InputDispatcherFallbackKeyTest, AppDoesNotHandleFallback) {
7509 setFallback(AKEYCODE_B);
7510 mDispatcher->notifyKey(
7511 KeyArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_KEYBOARD).keyCode(AKEYCODE_A).build());
7512
7513 // Do not handle this key event.
7514 consumeKey(/*handled=*/false,
7515 AllOf(WithKeyAction(ACTION_DOWN), WithKeyCode(AKEYCODE_A), WithFlags(0)));
7516 ASSERT_NO_FATAL_FAILURE(mFakePolicy->assertUnhandledKeyReported(AKEYCODE_A));
7517 // App does not handle the fallback either, so ensure another fallback is not generated.
7518 setFallback(AKEYCODE_C);
7519 consumeKey(/*handled=*/false,
7520 AllOf(WithKeyAction(ACTION_DOWN), WithKeyCode(AKEYCODE_B),
7521 WithFlags(AKEY_EVENT_FLAG_FALLBACK)));
7522
7523 // Release the original key, and ensure the fallback key is also released.
7524 setFallback(AKEYCODE_B);
7525 mDispatcher->notifyKey(
7526 KeyArgsBuilder(ACTION_UP, AINPUT_SOURCE_KEYBOARD).keyCode(AKEYCODE_A).build());
7527 consumeKey(/*handled=*/false,
7528 AllOf(WithKeyAction(ACTION_UP), WithKeyCode(AKEYCODE_A), WithFlags(0)));
7529 ASSERT_NO_FATAL_FAILURE(mFakePolicy->assertUnhandledKeyReported(AKEYCODE_A));
7530 consumeKey(/*handled=*/false,
7531 AllOf(WithKeyAction(ACTION_UP), WithKeyCode(AKEYCODE_B),
7532 WithFlags(AKEY_EVENT_FLAG_FALLBACK)));
7533
7534 ASSERT_NO_FATAL_FAILURE(mFakePolicy->assertUnhandledKeyNotReported());
7535 mWindow->assertNoEvents();
7536}
7537
7538TEST_F(InputDispatcherFallbackKeyTest, InconsistentPolicyCancelsFallback) {
7539 setFallback(AKEYCODE_B);
7540 mDispatcher->notifyKey(
7541 KeyArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_KEYBOARD).keyCode(AKEYCODE_A).build());
7542
7543 // Do not handle this key event, so fallback is generated.
7544 consumeKey(/*handled=*/false,
7545 AllOf(WithKeyAction(ACTION_DOWN), WithKeyCode(AKEYCODE_A), WithFlags(0)));
7546 ASSERT_NO_FATAL_FAILURE(mFakePolicy->assertUnhandledKeyReported(AKEYCODE_A));
7547 consumeKey(/*handled=*/true,
7548 AllOf(WithKeyAction(ACTION_DOWN), WithKeyCode(AKEYCODE_B),
7549 WithFlags(AKEY_EVENT_FLAG_FALLBACK)));
7550
7551 // Release the original key, but assume the policy is misbehaving and it
7552 // generates an inconsistent fallback to the one from the DOWN event.
7553 setFallback(AKEYCODE_C);
7554 mDispatcher->notifyKey(
7555 KeyArgsBuilder(ACTION_UP, AINPUT_SOURCE_KEYBOARD).keyCode(AKEYCODE_A).build());
7556 consumeKey(/*handled=*/false,
7557 AllOf(WithKeyAction(ACTION_UP), WithKeyCode(AKEYCODE_A), WithFlags(0)));
7558 ASSERT_NO_FATAL_FAILURE(mFakePolicy->assertUnhandledKeyReported(AKEYCODE_A));
7559 // Ensure the fallback key reported before as DOWN is canceled due to the inconsistency.
7560 consumeKey(/*handled=*/true,
7561 AllOf(WithKeyAction(ACTION_UP), WithKeyCode(AKEYCODE_B),
7562 WithFlags(AKEY_EVENT_FLAG_FALLBACK | AKEY_EVENT_FLAG_CANCELED)));
7563
7564 ASSERT_NO_FATAL_FAILURE(mFakePolicy->assertUnhandledKeyNotReported());
7565 mWindow->assertNoEvents();
7566}
7567
7568TEST_F(InputDispatcherFallbackKeyTest, CanceledKeyCancelsFallback) {
7569 setFallback(AKEYCODE_B);
7570 mDispatcher->notifyKey(
7571 KeyArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_KEYBOARD).keyCode(AKEYCODE_A).build());
7572
7573 // Do not handle this key event, so fallback is generated.
7574 consumeKey(/*handled=*/false,
7575 AllOf(WithKeyAction(ACTION_DOWN), WithKeyCode(AKEYCODE_A), WithFlags(0)));
7576 ASSERT_NO_FATAL_FAILURE(mFakePolicy->assertUnhandledKeyReported(AKEYCODE_A));
7577 consumeKey(/*handled=*/true,
7578 AllOf(WithKeyAction(ACTION_DOWN), WithKeyCode(AKEYCODE_B),
7579 WithFlags(AKEY_EVENT_FLAG_FALLBACK)));
7580
7581 // The original key is canceled.
7582 mDispatcher->notifyKey(KeyArgsBuilder(ACTION_UP, AINPUT_SOURCE_KEYBOARD)
7583 .keyCode(AKEYCODE_A)
7584 .addFlag(AKEY_EVENT_FLAG_CANCELED)
7585 .build());
7586 consumeKey(/*handled=*/false,
7587 AllOf(WithKeyAction(ACTION_UP), WithKeyCode(AKEYCODE_A),
7588 WithFlags(AKEY_EVENT_FLAG_CANCELED)));
7589 ASSERT_NO_FATAL_FAILURE(mFakePolicy->assertUnhandledKeyReported(AKEYCODE_A));
7590 // Ensure the fallback key is also canceled due to the original key being canceled.
7591 consumeKey(/*handled=*/true,
7592 AllOf(WithKeyAction(ACTION_UP), WithKeyCode(AKEYCODE_B),
7593 WithFlags(AKEY_EVENT_FLAG_FALLBACK | AKEY_EVENT_FLAG_CANCELED)));
7594
7595 ASSERT_NO_FATAL_FAILURE(mFakePolicy->assertUnhandledKeyNotReported());
7596 mWindow->assertNoEvents();
7597}
7598
Prabir Pradhanfa2c69f2024-02-01 20:31:34 +00007599TEST_F(InputDispatcherFallbackKeyTest, InputChannelRemovedDuringPolicyCall) {
Prabir Pradhanb13da8f2024-01-09 23:10:13 +00007600 setFallback(AKEYCODE_B);
7601 mDispatcher->notifyKey(
7602 KeyArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_KEYBOARD).keyCode(AKEYCODE_A).build());
7603
7604 // Do not handle this key event.
7605 consumeKey(/*handled=*/false,
7606 AllOf(WithKeyAction(ACTION_DOWN), WithKeyCode(AKEYCODE_A), WithFlags(0)));
7607 ASSERT_NO_FATAL_FAILURE(mFakePolicy->assertUnhandledKeyReported(AKEYCODE_A));
7608 consumeKey(/*handled=*/true,
7609 AllOf(WithKeyAction(ACTION_DOWN), WithKeyCode(AKEYCODE_B),
7610 WithFlags(AKEY_EVENT_FLAG_FALLBACK)));
7611
7612 mFakePolicy->setUnhandledKeyHandler([&](const KeyEvent& event) {
7613 // When the unhandled key is reported to the policy next, remove the input channel.
7614 mDispatcher->removeInputChannel(mWindow->getToken());
7615 return KeyEventBuilder(event).keyCode(AKEYCODE_B).build();
7616 });
7617 // Release the original key, and let the app now handle the previously unhandled key.
7618 // This should result in the previously generated fallback key to be cancelled.
7619 // Since the policy was notified of the unhandled DOWN event earlier, it will also be notified
7620 // of the UP event for consistency. The Dispatcher calls into the policy from its own thread
7621 // without holding the lock, because it need to synchronously fetch the fallback key. While in
7622 // the policy call, we will now remove the input channel. Once the policy call returns, the
7623 // Dispatcher will no longer have a channel to send cancellation events to. Ensure this does
7624 // not cause any crashes.
7625 mDispatcher->notifyKey(
7626 KeyArgsBuilder(ACTION_UP, AINPUT_SOURCE_KEYBOARD).keyCode(AKEYCODE_A).build());
7627 consumeKey(/*handled=*/true,
7628 AllOf(WithKeyAction(ACTION_UP), WithKeyCode(AKEYCODE_A), WithFlags(0)));
7629 ASSERT_NO_FATAL_FAILURE(mFakePolicy->assertUnhandledKeyReported(AKEYCODE_A));
7630}
7631
Prabir Pradhanfa2c69f2024-02-01 20:31:34 +00007632TEST_F(InputDispatcherFallbackKeyTest, WindowRemovedDuringPolicyCall) {
7633 setFallback(AKEYCODE_B);
7634 mDispatcher->notifyKey(
7635 KeyArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_KEYBOARD).keyCode(AKEYCODE_A).build());
7636
7637 // Do not handle this key event.
7638 consumeKey(/*handled=*/false,
7639 AllOf(WithKeyAction(ACTION_DOWN), WithKeyCode(AKEYCODE_A), WithFlags(0)));
7640 ASSERT_NO_FATAL_FAILURE(mFakePolicy->assertUnhandledKeyReported(AKEYCODE_A));
7641 consumeKey(/*handled=*/true,
7642 AllOf(WithKeyAction(ACTION_DOWN), WithKeyCode(AKEYCODE_B),
7643 WithFlags(AKEY_EVENT_FLAG_FALLBACK)));
7644
7645 mFakePolicy->setUnhandledKeyHandler([&](const KeyEvent& event) {
7646 // When the unhandled key is reported to the policy next, remove the window.
7647 mDispatcher->onWindowInfosChanged({{}, {}, 0, 0});
7648 return KeyEventBuilder(event).keyCode(AKEYCODE_B).build();
7649 });
7650 // Release the original key, which the app will not handle. When this unhandled key is reported
7651 // to the policy, the window will be removed.
7652 mDispatcher->notifyKey(
7653 KeyArgsBuilder(ACTION_UP, AINPUT_SOURCE_KEYBOARD).keyCode(AKEYCODE_A).build());
7654 consumeKey(/*handled=*/false,
7655 AllOf(WithKeyAction(ACTION_UP), WithKeyCode(AKEYCODE_A), WithFlags(0)));
7656 ASSERT_NO_FATAL_FAILURE(mFakePolicy->assertUnhandledKeyReported(AKEYCODE_A));
7657
7658 // Since the window was removed, it loses focus, and the channel state will be reset.
7659 consumeKey(/*handled=*/true,
7660 AllOf(WithKeyAction(ACTION_UP), WithKeyCode(AKEYCODE_B),
7661 WithFlags(AKEY_EVENT_FLAG_FALLBACK | AKEY_EVENT_FLAG_CANCELED)));
7662 mWindow->consumeFocusEvent(false);
7663 mWindow->assertNoEvents();
7664}
7665
7666TEST_F(InputDispatcherFallbackKeyTest, WindowRemovedWhileAwaitingFinishedSignal) {
7667 setFallback(AKEYCODE_B);
7668 mDispatcher->notifyKey(
7669 KeyArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_KEYBOARD).keyCode(AKEYCODE_A).build());
7670
7671 // Do not handle this key event.
7672 consumeKey(/*handled=*/false,
7673 AllOf(WithKeyAction(ACTION_DOWN), WithKeyCode(AKEYCODE_A), WithFlags(0)));
7674 ASSERT_NO_FATAL_FAILURE(mFakePolicy->assertUnhandledKeyReported(AKEYCODE_A));
7675 const auto [seq, event] = mWindow->receiveEvent();
7676 ASSERT_TRUE(seq.has_value() && event != nullptr) << "Failed to receive fallback event";
7677 ASSERT_EQ(event->getType(), InputEventType::KEY);
7678 ASSERT_THAT(static_cast<const KeyEvent&>(*event),
7679 AllOf(WithKeyAction(ACTION_DOWN), WithKeyCode(AKEYCODE_B),
7680 WithFlags(AKEY_EVENT_FLAG_FALLBACK)));
7681
7682 // Remove the window now, which should generate a cancellations and make the window lose focus.
7683 mDispatcher->onWindowInfosChanged({{}, {}, 0, 0});
7684 consumeKey(/*handled=*/true,
7685 AllOf(WithKeyAction(ACTION_UP), WithKeyCode(AKEYCODE_A),
7686 WithFlags(AKEY_EVENT_FLAG_CANCELED)));
7687 consumeKey(/*handled=*/true,
7688 AllOf(WithKeyAction(ACTION_UP), WithKeyCode(AKEYCODE_B),
7689 WithFlags(AKEY_EVENT_FLAG_FALLBACK | AKEY_EVENT_FLAG_CANCELED)));
7690 mWindow->consumeFocusEvent(false);
7691
7692 // Finish the event by reporting it as handled.
7693 mWindow->finishEvent(*seq);
7694 mWindow->assertNoEvents();
7695}
7696
Garfield Tan1c7bc862020-01-28 13:24:04 -08007697class InputDispatcherKeyRepeatTest : public InputDispatcherTest {
7698protected:
Siarhei Vishniakoufa2a0492023-11-14 13:13:18 -08007699 static constexpr std::chrono::nanoseconds KEY_REPEAT_TIMEOUT = 40ms;
7700 static constexpr std::chrono::nanoseconds KEY_REPEAT_DELAY = 40ms;
Garfield Tan1c7bc862020-01-28 13:24:04 -08007701
Chris Yea209fde2020-07-22 13:54:51 -07007702 std::shared_ptr<FakeApplicationHandle> mApp;
Garfield Tan1c7bc862020-01-28 13:24:04 -08007703 sp<FakeWindowHandle> mWindow;
7704
7705 virtual void SetUp() override {
Prabir Pradhandae52792023-12-15 07:36:40 +00007706 InputDispatcherTest::SetUp();
Garfield Tan1c7bc862020-01-28 13:24:04 -08007707
Prabir Pradhandae52792023-12-15 07:36:40 +00007708 mDispatcher->setKeyRepeatConfiguration(KEY_REPEAT_TIMEOUT, KEY_REPEAT_DELAY);
Garfield Tan1c7bc862020-01-28 13:24:04 -08007709 setUpWindow();
7710 }
7711
7712 void setUpWindow() {
Chris Yea209fde2020-07-22 13:54:51 -07007713 mApp = std::make_shared<FakeApplicationHandle>();
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07007714 mWindow = sp<FakeWindowHandle>::make(mApp, mDispatcher, "Fake Window", ADISPLAY_ID_DEFAULT);
Garfield Tan1c7bc862020-01-28 13:24:04 -08007715
Vishnu Nair47074b82020-08-14 11:54:47 -07007716 mWindow->setFocusable(true);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07007717 mDispatcher->onWindowInfosChanged({{*mWindow->getInfo()}, {}, 0, 0});
Vishnu Nair958da932020-08-21 17:12:37 -07007718 setFocusedWindow(mWindow);
Garfield Tan1c7bc862020-01-28 13:24:04 -08007719 mWindow->consumeFocusEvent(true);
7720 }
7721
Chris Ye2ad95392020-09-01 13:44:44 -07007722 void sendAndConsumeKeyDown(int32_t deviceId) {
Garfield Tan1c7bc862020-01-28 13:24:04 -08007723 NotifyKeyArgs keyArgs = generateKeyArgs(AKEY_EVENT_ACTION_DOWN, ADISPLAY_ID_DEFAULT);
Chris Ye2ad95392020-09-01 13:44:44 -07007724 keyArgs.deviceId = deviceId;
Garfield Tan1c7bc862020-01-28 13:24:04 -08007725 keyArgs.policyFlags |= POLICY_FLAG_TRUSTED; // Otherwise it won't generate repeat event
Prabir Pradhan678438e2023-04-13 19:32:51 +00007726 mDispatcher->notifyKey(keyArgs);
Garfield Tan1c7bc862020-01-28 13:24:04 -08007727
7728 // Window should receive key down event.
7729 mWindow->consumeKeyDown(ADISPLAY_ID_DEFAULT);
7730 }
7731
7732 void expectKeyRepeatOnce(int32_t repeatCount) {
7733 SCOPED_TRACE(StringPrintf("Checking event with repeat count %" PRId32, repeatCount));
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07007734 mWindow->consumeKeyEvent(
7735 AllOf(WithKeyAction(AKEY_EVENT_ACTION_DOWN), WithRepeatCount(repeatCount)));
Garfield Tan1c7bc862020-01-28 13:24:04 -08007736 }
7737
Chris Ye2ad95392020-09-01 13:44:44 -07007738 void sendAndConsumeKeyUp(int32_t deviceId) {
Garfield Tan1c7bc862020-01-28 13:24:04 -08007739 NotifyKeyArgs keyArgs = generateKeyArgs(AKEY_EVENT_ACTION_UP, ADISPLAY_ID_DEFAULT);
Chris Ye2ad95392020-09-01 13:44:44 -07007740 keyArgs.deviceId = deviceId;
Garfield Tan1c7bc862020-01-28 13:24:04 -08007741 keyArgs.policyFlags |= POLICY_FLAG_TRUSTED; // Unless it won't generate repeat event
Prabir Pradhan678438e2023-04-13 19:32:51 +00007742 mDispatcher->notifyKey(keyArgs);
Garfield Tan1c7bc862020-01-28 13:24:04 -08007743
7744 // Window should receive key down event.
Prabir Pradhan7662a8d2023-12-15 01:58:14 +00007745 mWindow->consumeKeyUp(ADISPLAY_ID_DEFAULT,
Harry Cutts33476232023-01-30 19:57:29 +00007746 /*expectedFlags=*/0);
Garfield Tan1c7bc862020-01-28 13:24:04 -08007747 }
Hu Guofe3c8f12023-09-22 17:20:15 +08007748
7749 void injectKeyRepeat(int32_t repeatCount) {
7750 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
7751 injectKey(*mDispatcher, AKEY_EVENT_ACTION_DOWN, repeatCount, ADISPLAY_ID_DEFAULT))
7752 << "Inject key event should return InputEventInjectionResult::SUCCEEDED";
7753 }
Garfield Tan1c7bc862020-01-28 13:24:04 -08007754};
7755
7756TEST_F(InputDispatcherKeyRepeatTest, FocusedWindow_ReceivesKeyRepeat) {
Harry Cutts33476232023-01-30 19:57:29 +00007757 sendAndConsumeKeyDown(/*deviceId=*/1);
Chris Ye2ad95392020-09-01 13:44:44 -07007758 for (int32_t repeatCount = 1; repeatCount <= 10; ++repeatCount) {
7759 expectKeyRepeatOnce(repeatCount);
7760 }
7761}
7762
7763TEST_F(InputDispatcherKeyRepeatTest, FocusedWindow_ReceivesKeyRepeatFromTwoDevices) {
Harry Cutts33476232023-01-30 19:57:29 +00007764 sendAndConsumeKeyDown(/*deviceId=*/1);
Chris Ye2ad95392020-09-01 13:44:44 -07007765 for (int32_t repeatCount = 1; repeatCount <= 10; ++repeatCount) {
7766 expectKeyRepeatOnce(repeatCount);
7767 }
Harry Cutts33476232023-01-30 19:57:29 +00007768 sendAndConsumeKeyDown(/*deviceId=*/2);
Chris Ye2ad95392020-09-01 13:44:44 -07007769 /* repeatCount will start from 1 for deviceId 2 */
Garfield Tan1c7bc862020-01-28 13:24:04 -08007770 for (int32_t repeatCount = 1; repeatCount <= 10; ++repeatCount) {
7771 expectKeyRepeatOnce(repeatCount);
7772 }
7773}
7774
7775TEST_F(InputDispatcherKeyRepeatTest, FocusedWindow_StopsKeyRepeatAfterUp) {
Harry Cutts33476232023-01-30 19:57:29 +00007776 sendAndConsumeKeyDown(/*deviceId=*/1);
7777 expectKeyRepeatOnce(/*repeatCount=*/1);
7778 sendAndConsumeKeyUp(/*deviceId=*/1);
Chris Ye2ad95392020-09-01 13:44:44 -07007779 mWindow->assertNoEvents();
7780}
7781
7782TEST_F(InputDispatcherKeyRepeatTest, FocusedWindow_KeyRepeatAfterStaleDeviceKeyUp) {
Harry Cutts33476232023-01-30 19:57:29 +00007783 sendAndConsumeKeyDown(/*deviceId=*/1);
7784 expectKeyRepeatOnce(/*repeatCount=*/1);
7785 sendAndConsumeKeyDown(/*deviceId=*/2);
7786 expectKeyRepeatOnce(/*repeatCount=*/1);
Chris Ye2ad95392020-09-01 13:44:44 -07007787 // Stale key up from device 1.
Harry Cutts33476232023-01-30 19:57:29 +00007788 sendAndConsumeKeyUp(/*deviceId=*/1);
Chris Ye2ad95392020-09-01 13:44:44 -07007789 // Device 2 is still down, keep repeating
Harry Cutts33476232023-01-30 19:57:29 +00007790 expectKeyRepeatOnce(/*repeatCount=*/2);
7791 expectKeyRepeatOnce(/*repeatCount=*/3);
Chris Ye2ad95392020-09-01 13:44:44 -07007792 // Device 2 key up
Harry Cutts33476232023-01-30 19:57:29 +00007793 sendAndConsumeKeyUp(/*deviceId=*/2);
Chris Ye2ad95392020-09-01 13:44:44 -07007794 mWindow->assertNoEvents();
7795}
7796
7797TEST_F(InputDispatcherKeyRepeatTest, FocusedWindow_KeyRepeatStopsAfterRepeatingKeyUp) {
Harry Cutts33476232023-01-30 19:57:29 +00007798 sendAndConsumeKeyDown(/*deviceId=*/1);
7799 expectKeyRepeatOnce(/*repeatCount=*/1);
7800 sendAndConsumeKeyDown(/*deviceId=*/2);
7801 expectKeyRepeatOnce(/*repeatCount=*/1);
Chris Ye2ad95392020-09-01 13:44:44 -07007802 // Device 2 which holds the key repeating goes up, expect the repeating to stop.
Harry Cutts33476232023-01-30 19:57:29 +00007803 sendAndConsumeKeyUp(/*deviceId=*/2);
Chris Ye2ad95392020-09-01 13:44:44 -07007804 // Device 1 still holds key down, but the repeating was already stopped
Garfield Tan1c7bc862020-01-28 13:24:04 -08007805 mWindow->assertNoEvents();
7806}
7807
liushenxiang42232912021-05-21 20:24:09 +08007808TEST_F(InputDispatcherKeyRepeatTest, FocusedWindow_StopsKeyRepeatAfterDisableInputDevice) {
7809 sendAndConsumeKeyDown(DEVICE_ID);
Harry Cutts33476232023-01-30 19:57:29 +00007810 expectKeyRepeatOnce(/*repeatCount=*/1);
Prabir Pradhan678438e2023-04-13 19:32:51 +00007811 mDispatcher->notifyDeviceReset({/*id=*/10, /*eventTime=*/20, DEVICE_ID});
liushenxiang42232912021-05-21 20:24:09 +08007812 mWindow->consumeKeyUp(ADISPLAY_ID_DEFAULT,
7813 AKEY_EVENT_FLAG_CANCELED | AKEY_EVENT_FLAG_LONG_PRESS);
7814 mWindow->assertNoEvents();
7815}
7816
Garfield Tan1c7bc862020-01-28 13:24:04 -08007817TEST_F(InputDispatcherKeyRepeatTest, FocusedWindow_RepeatKeyEventsUseEventIdFromInputDispatcher) {
Michael Wrighte1cbbd62023-02-22 19:32:13 +00007818 GTEST_SKIP() << "Flaky test (b/270393106)";
Harry Cutts33476232023-01-30 19:57:29 +00007819 sendAndConsumeKeyDown(/*deviceId=*/1);
Garfield Tan1c7bc862020-01-28 13:24:04 -08007820 for (int32_t repeatCount = 1; repeatCount <= 10; ++repeatCount) {
Siarhei Vishniakoud3061ab2023-12-18 20:41:08 -08007821 std::unique_ptr<KeyEvent> repeatEvent = mWindow->consumeKey();
7822 ASSERT_NE(nullptr, repeatEvent);
Garfield Tan1c7bc862020-01-28 13:24:04 -08007823 EXPECT_EQ(IdGenerator::Source::INPUT_DISPATCHER,
Siarhei Vishniakoud3061ab2023-12-18 20:41:08 -08007824 IdGenerator::getSource(repeatEvent->getId()));
Garfield Tan1c7bc862020-01-28 13:24:04 -08007825 }
7826}
7827
7828TEST_F(InputDispatcherKeyRepeatTest, FocusedWindow_RepeatKeyEventsUseUniqueEventId) {
Michael Wrighte1cbbd62023-02-22 19:32:13 +00007829 GTEST_SKIP() << "Flaky test (b/270393106)";
Harry Cutts33476232023-01-30 19:57:29 +00007830 sendAndConsumeKeyDown(/*deviceId=*/1);
Garfield Tan1c7bc862020-01-28 13:24:04 -08007831
7832 std::unordered_set<int32_t> idSet;
7833 for (int32_t repeatCount = 1; repeatCount <= 10; ++repeatCount) {
Siarhei Vishniakoud3061ab2023-12-18 20:41:08 -08007834 std::unique_ptr<KeyEvent> repeatEvent = mWindow->consumeKey();
7835 ASSERT_NE(nullptr, repeatEvent);
7836 int32_t id = repeatEvent->getId();
Garfield Tan1c7bc862020-01-28 13:24:04 -08007837 EXPECT_EQ(idSet.end(), idSet.find(id));
7838 idSet.insert(id);
7839 }
7840}
7841
Hu Guofe3c8f12023-09-22 17:20:15 +08007842TEST_F(InputDispatcherKeyRepeatTest, FocusedWindow_CorrectRepeatCountWhenInjectKeyRepeat) {
7843 injectKeyRepeat(0);
7844 mWindow->consumeKeyDown(ADISPLAY_ID_DEFAULT);
7845 for (int32_t repeatCount = 1; repeatCount <= 2; ++repeatCount) {
7846 expectKeyRepeatOnce(repeatCount);
7847 }
7848 injectKeyRepeat(1);
7849 // Expect repeatCount to be 3 instead of 1
7850 expectKeyRepeatOnce(3);
7851}
7852
Arthur Hung2fbf37f2018-09-13 18:16:41 +08007853/* Test InputDispatcher for MultiDisplay */
7854class InputDispatcherFocusOnTwoDisplaysTest : public InputDispatcherTest {
7855public:
Prabir Pradhan3608aad2019-10-02 17:08:26 -07007856 virtual void SetUp() override {
Arthur Hung2fbf37f2018-09-13 18:16:41 +08007857 InputDispatcherTest::SetUp();
Arthur Hungb92218b2018-08-14 12:00:21 +08007858
Chris Yea209fde2020-07-22 13:54:51 -07007859 application1 = std::make_shared<FakeApplicationHandle>();
Siarhei Vishniakou870ecec2020-12-09 08:07:46 -10007860 windowInPrimary =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07007861 sp<FakeWindowHandle>::make(application1, mDispatcher, "D_1", ADISPLAY_ID_DEFAULT);
Siarhei Vishniakoub9b15352019-11-26 13:19:26 -08007862
Arthur Hung2fbf37f2018-09-13 18:16:41 +08007863 // Set focus window for primary display, but focused display would be second one.
7864 mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application1);
Vishnu Nair47074b82020-08-14 11:54:47 -07007865 windowInPrimary->setFocusable(true);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07007866 mDispatcher->onWindowInfosChanged({{*windowInPrimary->getInfo()}, {}, 0, 0});
7867
Vishnu Nair958da932020-08-21 17:12:37 -07007868 setFocusedWindow(windowInPrimary);
Siarhei Vishniakouf1035d42019-09-20 16:32:01 +01007869 windowInPrimary->consumeFocusEvent(true);
Arthur Hungb92218b2018-08-14 12:00:21 +08007870
Chris Yea209fde2020-07-22 13:54:51 -07007871 application2 = std::make_shared<FakeApplicationHandle>();
Siarhei Vishniakou870ecec2020-12-09 08:07:46 -10007872 windowInSecondary =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07007873 sp<FakeWindowHandle>::make(application2, mDispatcher, "D_2", SECOND_DISPLAY_ID);
Arthur Hung2fbf37f2018-09-13 18:16:41 +08007874 // Set focus to second display window.
Arthur Hung2fbf37f2018-09-13 18:16:41 +08007875 // Set focus display to second one.
7876 mDispatcher->setFocusedDisplay(SECOND_DISPLAY_ID);
7877 // Set focus window for second display.
7878 mDispatcher->setFocusedApplication(SECOND_DISPLAY_ID, application2);
Vishnu Nair47074b82020-08-14 11:54:47 -07007879 windowInSecondary->setFocusable(true);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07007880 mDispatcher->onWindowInfosChanged(
7881 {{*windowInPrimary->getInfo(), *windowInSecondary->getInfo()}, {}, 0, 0});
Vishnu Nair958da932020-08-21 17:12:37 -07007882 setFocusedWindow(windowInSecondary);
Siarhei Vishniakouf1035d42019-09-20 16:32:01 +01007883 windowInSecondary->consumeFocusEvent(true);
Arthur Hung2fbf37f2018-09-13 18:16:41 +08007884 }
7885
Prabir Pradhan3608aad2019-10-02 17:08:26 -07007886 virtual void TearDown() override {
Arthur Hung2fbf37f2018-09-13 18:16:41 +08007887 InputDispatcherTest::TearDown();
7888
Chris Yea209fde2020-07-22 13:54:51 -07007889 application1.reset();
Arthur Hung2fbf37f2018-09-13 18:16:41 +08007890 windowInPrimary.clear();
Chris Yea209fde2020-07-22 13:54:51 -07007891 application2.reset();
Arthur Hung2fbf37f2018-09-13 18:16:41 +08007892 windowInSecondary.clear();
7893 }
7894
7895protected:
Chris Yea209fde2020-07-22 13:54:51 -07007896 std::shared_ptr<FakeApplicationHandle> application1;
Arthur Hung2fbf37f2018-09-13 18:16:41 +08007897 sp<FakeWindowHandle> windowInPrimary;
Chris Yea209fde2020-07-22 13:54:51 -07007898 std::shared_ptr<FakeApplicationHandle> application2;
Arthur Hung2fbf37f2018-09-13 18:16:41 +08007899 sp<FakeWindowHandle> windowInSecondary;
7900};
7901
7902TEST_F(InputDispatcherFocusOnTwoDisplaysTest, SetInputWindow_MultiDisplayTouch) {
7903 // Test touch down on primary display.
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08007904 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07007905 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT))
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08007906 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
Siarhei Vishniakouc5ca85c2019-11-15 17:20:00 -08007907 windowInPrimary->consumeMotionDown(ADISPLAY_ID_DEFAULT);
Arthur Hungb92218b2018-08-14 12:00:21 +08007908 windowInSecondary->assertNoEvents();
7909
Arthur Hung2fbf37f2018-09-13 18:16:41 +08007910 // Test touch down on second display.
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08007911 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07007912 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, SECOND_DISPLAY_ID))
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08007913 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
Arthur Hungb92218b2018-08-14 12:00:21 +08007914 windowInPrimary->assertNoEvents();
Siarhei Vishniakouc5ca85c2019-11-15 17:20:00 -08007915 windowInSecondary->consumeMotionDown(SECOND_DISPLAY_ID);
Arthur Hungb92218b2018-08-14 12:00:21 +08007916}
7917
Arthur Hung2fbf37f2018-09-13 18:16:41 +08007918TEST_F(InputDispatcherFocusOnTwoDisplaysTest, SetInputWindow_MultiDisplayFocus) {
Tiger Huang721e26f2018-07-24 22:26:19 +08007919 // Test inject a key down with display id specified.
Prabir Pradhan93f342c2021-03-11 15:05:30 -08007920 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07007921 injectKeyDownNoRepeat(*mDispatcher, ADISPLAY_ID_DEFAULT))
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08007922 << "Inject key event should return InputEventInjectionResult::SUCCEEDED";
Siarhei Vishniakouc5ca85c2019-11-15 17:20:00 -08007923 windowInPrimary->consumeKeyDown(ADISPLAY_ID_DEFAULT);
Tiger Huang721e26f2018-07-24 22:26:19 +08007924 windowInSecondary->assertNoEvents();
7925
7926 // Test inject a key down without display id specified.
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07007927 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectKeyDownNoRepeat(*mDispatcher))
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08007928 << "Inject key event should return InputEventInjectionResult::SUCCEEDED";
Arthur Hungb92218b2018-08-14 12:00:21 +08007929 windowInPrimary->assertNoEvents();
Siarhei Vishniakouc5ca85c2019-11-15 17:20:00 -08007930 windowInSecondary->consumeKeyDown(ADISPLAY_ID_NONE);
Arthur Hungb92218b2018-08-14 12:00:21 +08007931
Siarhei Vishniakoub9b15352019-11-26 13:19:26 -08007932 // Remove all windows in secondary display.
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07007933 mDispatcher->onWindowInfosChanged({{*windowInPrimary->getInfo()}, {}, 0, 0});
Arthur Hungb92218b2018-08-14 12:00:21 +08007934
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08007935 // Old focus should receive a cancel event.
Prabir Pradhan7662a8d2023-12-15 01:58:14 +00007936 windowInSecondary->consumeKeyUp(ADISPLAY_ID_NONE, AKEY_EVENT_FLAG_CANCELED);
Arthur Hungb92218b2018-08-14 12:00:21 +08007937
7938 // Test inject a key down, should timeout because of no target window.
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07007939 ASSERT_NO_FATAL_FAILURE(assertInjectedKeyTimesOut(*mDispatcher));
Arthur Hungb92218b2018-08-14 12:00:21 +08007940 windowInPrimary->assertNoEvents();
Siarhei Vishniakouf1035d42019-09-20 16:32:01 +01007941 windowInSecondary->consumeFocusEvent(false);
Arthur Hungb92218b2018-08-14 12:00:21 +08007942 windowInSecondary->assertNoEvents();
7943}
7944
Arthur Hung2fbf37f2018-09-13 18:16:41 +08007945// Test per-display input monitors for motion event.
7946TEST_F(InputDispatcherFocusOnTwoDisplaysTest, MonitorMotionEvent_MultiDisplay) {
chaviwd1c23182019-12-20 18:44:56 -08007947 FakeMonitorReceiver monitorInPrimary =
Prabir Pradhanfb549072023-10-05 19:17:36 +00007948 FakeMonitorReceiver(*mDispatcher, "M_1", ADISPLAY_ID_DEFAULT);
chaviwd1c23182019-12-20 18:44:56 -08007949 FakeMonitorReceiver monitorInSecondary =
Prabir Pradhanfb549072023-10-05 19:17:36 +00007950 FakeMonitorReceiver(*mDispatcher, "M_2", SECOND_DISPLAY_ID);
Arthur Hung2fbf37f2018-09-13 18:16:41 +08007951
7952 // Test touch down on primary display.
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08007953 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07007954 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT))
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08007955 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
Siarhei Vishniakouc5ca85c2019-11-15 17:20:00 -08007956 windowInPrimary->consumeMotionDown(ADISPLAY_ID_DEFAULT);
chaviwd1c23182019-12-20 18:44:56 -08007957 monitorInPrimary.consumeMotionDown(ADISPLAY_ID_DEFAULT);
Arthur Hung2fbf37f2018-09-13 18:16:41 +08007958 windowInSecondary->assertNoEvents();
chaviwd1c23182019-12-20 18:44:56 -08007959 monitorInSecondary.assertNoEvents();
Arthur Hung2fbf37f2018-09-13 18:16:41 +08007960
7961 // Test touch down on second display.
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08007962 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07007963 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, SECOND_DISPLAY_ID))
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08007964 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
Arthur Hung2fbf37f2018-09-13 18:16:41 +08007965 windowInPrimary->assertNoEvents();
chaviwd1c23182019-12-20 18:44:56 -08007966 monitorInPrimary.assertNoEvents();
Siarhei Vishniakouc5ca85c2019-11-15 17:20:00 -08007967 windowInSecondary->consumeMotionDown(SECOND_DISPLAY_ID);
chaviwd1c23182019-12-20 18:44:56 -08007968 monitorInSecondary.consumeMotionDown(SECOND_DISPLAY_ID);
Arthur Hung2fbf37f2018-09-13 18:16:41 +08007969
Siarhei Vishniakou92c8fd52023-01-29 14:57:43 -08007970 // Lift up the touch from the second display
7971 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07007972 injectMotionUp(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, SECOND_DISPLAY_ID))
Siarhei Vishniakou92c8fd52023-01-29 14:57:43 -08007973 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
7974 windowInSecondary->consumeMotionUp(SECOND_DISPLAY_ID);
7975 monitorInSecondary.consumeMotionUp(SECOND_DISPLAY_ID);
7976
Arthur Hung2fbf37f2018-09-13 18:16:41 +08007977 // Test inject a non-pointer motion event.
7978 // If specific a display, it will dispatch to the focused window of particular display,
7979 // or it will dispatch to the focused window of focused display.
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08007980 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07007981 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TRACKBALL, ADISPLAY_ID_NONE))
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08007982 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
Arthur Hung2fbf37f2018-09-13 18:16:41 +08007983 windowInPrimary->assertNoEvents();
chaviwd1c23182019-12-20 18:44:56 -08007984 monitorInPrimary.assertNoEvents();
Siarhei Vishniakouc5ca85c2019-11-15 17:20:00 -08007985 windowInSecondary->consumeMotionDown(ADISPLAY_ID_NONE);
chaviwd1c23182019-12-20 18:44:56 -08007986 monitorInSecondary.consumeMotionDown(ADISPLAY_ID_NONE);
Arthur Hung2fbf37f2018-09-13 18:16:41 +08007987}
7988
7989// Test per-display input monitors for key event.
7990TEST_F(InputDispatcherFocusOnTwoDisplaysTest, MonitorKeyEvent_MultiDisplay) {
Siarhei Vishniakou870ecec2020-12-09 08:07:46 -10007991 // Input monitor per display.
chaviwd1c23182019-12-20 18:44:56 -08007992 FakeMonitorReceiver monitorInPrimary =
Prabir Pradhanfb549072023-10-05 19:17:36 +00007993 FakeMonitorReceiver(*mDispatcher, "M_1", ADISPLAY_ID_DEFAULT);
chaviwd1c23182019-12-20 18:44:56 -08007994 FakeMonitorReceiver monitorInSecondary =
Prabir Pradhanfb549072023-10-05 19:17:36 +00007995 FakeMonitorReceiver(*mDispatcher, "M_2", SECOND_DISPLAY_ID);
Arthur Hung2fbf37f2018-09-13 18:16:41 +08007996
7997 // Test inject a key down.
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07007998 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectKeyDown(*mDispatcher))
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08007999 << "Inject key event should return InputEventInjectionResult::SUCCEEDED";
Arthur Hung2fbf37f2018-09-13 18:16:41 +08008000 windowInPrimary->assertNoEvents();
chaviwd1c23182019-12-20 18:44:56 -08008001 monitorInPrimary.assertNoEvents();
Siarhei Vishniakouc5ca85c2019-11-15 17:20:00 -08008002 windowInSecondary->consumeKeyDown(ADISPLAY_ID_NONE);
chaviwd1c23182019-12-20 18:44:56 -08008003 monitorInSecondary.consumeKeyDown(ADISPLAY_ID_NONE);
Arthur Hung2fbf37f2018-09-13 18:16:41 +08008004}
8005
Vishnu Nair958da932020-08-21 17:12:37 -07008006TEST_F(InputDispatcherFocusOnTwoDisplaysTest, CanFocusWindowOnUnfocusedDisplay) {
8007 sp<FakeWindowHandle> secondWindowInPrimary =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07008008 sp<FakeWindowHandle>::make(application1, mDispatcher, "D_1_W2", ADISPLAY_ID_DEFAULT);
Vishnu Nair958da932020-08-21 17:12:37 -07008009 secondWindowInPrimary->setFocusable(true);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07008010 mDispatcher->onWindowInfosChanged(
8011 {{*windowInPrimary->getInfo(), *secondWindowInPrimary->getInfo(),
8012 *windowInSecondary->getInfo()},
8013 {},
8014 0,
8015 0});
Vishnu Nair958da932020-08-21 17:12:37 -07008016 setFocusedWindow(secondWindowInPrimary);
8017 windowInPrimary->consumeFocusEvent(false);
8018 secondWindowInPrimary->consumeFocusEvent(true);
8019
8020 // Test inject a key down.
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07008021 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
8022 injectKeyDown(*mDispatcher, ADISPLAY_ID_DEFAULT))
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08008023 << "Inject key event should return InputEventInjectionResult::SUCCEEDED";
Vishnu Nair958da932020-08-21 17:12:37 -07008024 windowInPrimary->assertNoEvents();
8025 windowInSecondary->assertNoEvents();
8026 secondWindowInPrimary->consumeKeyDown(ADISPLAY_ID_DEFAULT);
8027}
8028
Arthur Hungdfd528e2021-12-08 13:23:04 +00008029TEST_F(InputDispatcherFocusOnTwoDisplaysTest, CancelTouch_MultiDisplay) {
8030 FakeMonitorReceiver monitorInPrimary =
Prabir Pradhanfb549072023-10-05 19:17:36 +00008031 FakeMonitorReceiver(*mDispatcher, "M_1", ADISPLAY_ID_DEFAULT);
Arthur Hungdfd528e2021-12-08 13:23:04 +00008032 FakeMonitorReceiver monitorInSecondary =
Prabir Pradhanfb549072023-10-05 19:17:36 +00008033 FakeMonitorReceiver(*mDispatcher, "M_2", SECOND_DISPLAY_ID);
Arthur Hungdfd528e2021-12-08 13:23:04 +00008034
8035 // Test touch down on primary display.
8036 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07008037 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT))
Arthur Hungdfd528e2021-12-08 13:23:04 +00008038 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
8039 windowInPrimary->consumeMotionDown(ADISPLAY_ID_DEFAULT);
8040 monitorInPrimary.consumeMotionDown(ADISPLAY_ID_DEFAULT);
8041
8042 // Test touch down on second display.
8043 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07008044 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, SECOND_DISPLAY_ID))
Arthur Hungdfd528e2021-12-08 13:23:04 +00008045 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
8046 windowInSecondary->consumeMotionDown(SECOND_DISPLAY_ID);
8047 monitorInSecondary.consumeMotionDown(SECOND_DISPLAY_ID);
8048
8049 // Trigger cancel touch.
8050 mDispatcher->cancelCurrentTouch();
8051 windowInPrimary->consumeMotionCancel(ADISPLAY_ID_DEFAULT);
8052 monitorInPrimary.consumeMotionCancel(ADISPLAY_ID_DEFAULT);
8053 windowInSecondary->consumeMotionCancel(SECOND_DISPLAY_ID);
8054 monitorInSecondary.consumeMotionCancel(SECOND_DISPLAY_ID);
8055
8056 // Test inject a move motion event, no window/monitor should receive the event.
8057 ASSERT_EQ(InputEventInjectionResult::FAILED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07008058 injectMotionEvent(*mDispatcher, AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN,
Arthur Hungdfd528e2021-12-08 13:23:04 +00008059 ADISPLAY_ID_DEFAULT, {110, 200}))
8060 << "Inject motion event should return InputEventInjectionResult::FAILED";
8061 windowInPrimary->assertNoEvents();
8062 monitorInPrimary.assertNoEvents();
8063
8064 ASSERT_EQ(InputEventInjectionResult::FAILED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07008065 injectMotionEvent(*mDispatcher, AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN,
Arthur Hungdfd528e2021-12-08 13:23:04 +00008066 SECOND_DISPLAY_ID, {110, 200}))
8067 << "Inject motion event should return InputEventInjectionResult::FAILED";
8068 windowInSecondary->assertNoEvents();
8069 monitorInSecondary.assertNoEvents();
8070}
8071
Hu Guocb134f12023-12-23 13:42:44 +00008072/**
8073 * Send a key to the primary display and to the secondary display.
8074 * Then cause the key on the primary display to be canceled by sending in a stale key.
8075 * Ensure that the key on the primary display is canceled, and that the key on the secondary display
8076 * does not get canceled.
8077 */
8078TEST_F(InputDispatcherFocusOnTwoDisplaysTest, WhenDropKeyEvent_OnlyCancelCorrespondingKeyGesture) {
8079 // Send a key down on primary display
8080 mDispatcher->notifyKey(
8081 KeyArgsBuilder(AKEY_EVENT_ACTION_DOWN, AINPUT_SOURCE_KEYBOARD)
8082 .displayId(ADISPLAY_ID_DEFAULT)
8083 .policyFlags(DEFAULT_POLICY_FLAGS | POLICY_FLAG_DISABLE_KEY_REPEAT)
8084 .build());
8085 windowInPrimary->consumeKeyEvent(
8086 AllOf(WithKeyAction(AKEY_EVENT_ACTION_DOWN), WithDisplayId(ADISPLAY_ID_DEFAULT)));
8087 windowInSecondary->assertNoEvents();
8088
8089 // Send a key down on second display
8090 mDispatcher->notifyKey(
8091 KeyArgsBuilder(AKEY_EVENT_ACTION_DOWN, AINPUT_SOURCE_KEYBOARD)
8092 .displayId(SECOND_DISPLAY_ID)
8093 .policyFlags(DEFAULT_POLICY_FLAGS | POLICY_FLAG_DISABLE_KEY_REPEAT)
8094 .build());
8095 windowInSecondary->consumeKeyEvent(
8096 AllOf(WithKeyAction(AKEY_EVENT_ACTION_DOWN), WithDisplayId(SECOND_DISPLAY_ID)));
8097 windowInPrimary->assertNoEvents();
8098
8099 // Send a valid key up event on primary display that will be dropped because it is stale
8100 NotifyKeyArgs staleKeyUp =
8101 KeyArgsBuilder(AKEY_EVENT_ACTION_UP, AINPUT_SOURCE_KEYBOARD)
8102 .displayId(ADISPLAY_ID_DEFAULT)
8103 .policyFlags(DEFAULT_POLICY_FLAGS | POLICY_FLAG_DISABLE_KEY_REPEAT)
8104 .build();
8105 static constexpr std::chrono::duration STALE_EVENT_TIMEOUT = 10ms;
8106 mFakePolicy->setStaleEventTimeout(STALE_EVENT_TIMEOUT);
8107 std::this_thread::sleep_for(STALE_EVENT_TIMEOUT);
8108 mDispatcher->notifyKey(staleKeyUp);
8109
8110 // Only the key gesture corresponding to the dropped event should receive the cancel event.
8111 // Therefore, windowInPrimary should get the cancel event and windowInSecondary should not
8112 // receive any events.
8113 windowInPrimary->consumeKeyEvent(AllOf(WithKeyAction(AKEY_EVENT_ACTION_UP),
8114 WithDisplayId(ADISPLAY_ID_DEFAULT),
8115 WithFlags(AKEY_EVENT_FLAG_CANCELED)));
8116 windowInSecondary->assertNoEvents();
8117}
8118
8119/**
8120 * Similar to 'WhenDropKeyEvent_OnlyCancelCorrespondingKeyGesture' but for motion events.
8121 */
8122TEST_F(InputDispatcherFocusOnTwoDisplaysTest, WhenDropMotionEvent_OnlyCancelCorrespondingGesture) {
8123 // Send touch down on primary display.
8124 mDispatcher->notifyMotion(
8125 MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
8126 .pointer(PointerBuilder(/*id=*/0, ToolType::FINGER).x(100).y(200))
8127 .displayId(ADISPLAY_ID_DEFAULT)
8128 .build());
8129 windowInPrimary->consumeMotionEvent(
8130 AllOf(WithMotionAction(ACTION_DOWN), WithDisplayId(ADISPLAY_ID_DEFAULT)));
8131 windowInSecondary->assertNoEvents();
8132
8133 // Send touch down on second display.
8134 mDispatcher->notifyMotion(
8135 MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
8136 .pointer(PointerBuilder(/*id=*/0, ToolType::FINGER).x(100).y(200))
8137 .displayId(SECOND_DISPLAY_ID)
8138 .build());
8139 windowInPrimary->assertNoEvents();
8140 windowInSecondary->consumeMotionEvent(
8141 AllOf(WithMotionAction(ACTION_DOWN), WithDisplayId(SECOND_DISPLAY_ID)));
8142
8143 // inject a valid MotionEvent on primary display that will be stale when it arrives.
8144 NotifyMotionArgs staleMotionUp =
8145 MotionArgsBuilder(ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN)
8146 .displayId(ADISPLAY_ID_DEFAULT)
8147 .pointer(PointerBuilder(/*id=*/0, ToolType::FINGER).x(100).y(200))
8148 .build();
8149 static constexpr std::chrono::duration STALE_EVENT_TIMEOUT = 10ms;
8150 mFakePolicy->setStaleEventTimeout(STALE_EVENT_TIMEOUT);
8151 std::this_thread::sleep_for(STALE_EVENT_TIMEOUT);
8152 mDispatcher->notifyMotion(staleMotionUp);
8153
8154 // For stale motion events, we let the gesture to complete. This behaviour is different from key
8155 // events, where we would cancel the current keys instead.
8156 windowInPrimary->consumeMotionEvent(WithMotionAction(ACTION_UP));
8157 windowInSecondary->assertNoEvents();
8158}
8159
Jackal Guof9696682018-10-05 12:23:23 +08008160class InputFilterTest : public InputDispatcherTest {
8161protected:
Prabir Pradhan81420cc2021-09-06 10:28:50 -07008162 void testNotifyMotion(int32_t displayId, bool expectToBeFiltered,
8163 const ui::Transform& transform = ui::Transform()) {
Jackal Guof9696682018-10-05 12:23:23 +08008164 NotifyMotionArgs motionArgs;
8165
Siarhei Vishniakou870ecec2020-12-09 08:07:46 -10008166 motionArgs =
8167 generateMotionArgs(AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN, displayId);
Prabir Pradhan678438e2023-04-13 19:32:51 +00008168 mDispatcher->notifyMotion(motionArgs);
Siarhei Vishniakou870ecec2020-12-09 08:07:46 -10008169 motionArgs =
8170 generateMotionArgs(AMOTION_EVENT_ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN, displayId);
Prabir Pradhan678438e2023-04-13 19:32:51 +00008171 mDispatcher->notifyMotion(motionArgs);
Siarhei Vishniakou2bfa9052019-11-21 18:10:54 -08008172 ASSERT_TRUE(mDispatcher->waitForIdle());
Jackal Guof9696682018-10-05 12:23:23 +08008173 if (expectToBeFiltered) {
Siarhei Vishniakou3218fc02023-06-15 20:41:02 -07008174 const auto xy = transform.transform(motionArgs.pointerCoords[0].getXYValue());
Prabir Pradhan81420cc2021-09-06 10:28:50 -07008175 mFakePolicy->assertFilterInputEventWasCalled(motionArgs, xy);
Jackal Guof9696682018-10-05 12:23:23 +08008176 } else {
8177 mFakePolicy->assertFilterInputEventWasNotCalled();
8178 }
8179 }
8180
8181 void testNotifyKey(bool expectToBeFiltered) {
8182 NotifyKeyArgs keyArgs;
8183
8184 keyArgs = generateKeyArgs(AKEY_EVENT_ACTION_DOWN);
Prabir Pradhan678438e2023-04-13 19:32:51 +00008185 mDispatcher->notifyKey(keyArgs);
Jackal Guof9696682018-10-05 12:23:23 +08008186 keyArgs = generateKeyArgs(AKEY_EVENT_ACTION_UP);
Prabir Pradhan678438e2023-04-13 19:32:51 +00008187 mDispatcher->notifyKey(keyArgs);
Siarhei Vishniakou2bfa9052019-11-21 18:10:54 -08008188 ASSERT_TRUE(mDispatcher->waitForIdle());
Jackal Guof9696682018-10-05 12:23:23 +08008189
8190 if (expectToBeFiltered) {
Siarhei Vishniakou8935a802019-11-15 16:41:44 -08008191 mFakePolicy->assertFilterInputEventWasCalled(keyArgs);
Jackal Guof9696682018-10-05 12:23:23 +08008192 } else {
8193 mFakePolicy->assertFilterInputEventWasNotCalled();
8194 }
8195 }
8196};
8197
8198// Test InputFilter for MotionEvent
8199TEST_F(InputFilterTest, MotionEvent_InputFilter) {
8200 // Since the InputFilter is disabled by default, check if touch events aren't filtered.
Harry Cutts101ee9b2023-07-06 18:04:14 +00008201 testNotifyMotion(ADISPLAY_ID_DEFAULT, /*expectToBeFiltered=*/false);
8202 testNotifyMotion(SECOND_DISPLAY_ID, /*expectToBeFiltered=*/false);
Jackal Guof9696682018-10-05 12:23:23 +08008203
8204 // Enable InputFilter
8205 mDispatcher->setInputFilterEnabled(true);
8206 // Test touch on both primary and second display, and check if both events are filtered.
Harry Cutts101ee9b2023-07-06 18:04:14 +00008207 testNotifyMotion(ADISPLAY_ID_DEFAULT, /*expectToBeFiltered=*/true);
8208 testNotifyMotion(SECOND_DISPLAY_ID, /*expectToBeFiltered=*/true);
Jackal Guof9696682018-10-05 12:23:23 +08008209
8210 // Disable InputFilter
8211 mDispatcher->setInputFilterEnabled(false);
8212 // Test touch on both primary and second display, and check if both events aren't filtered.
Harry Cutts101ee9b2023-07-06 18:04:14 +00008213 testNotifyMotion(ADISPLAY_ID_DEFAULT, /*expectToBeFiltered=*/false);
8214 testNotifyMotion(SECOND_DISPLAY_ID, /*expectToBeFiltered=*/false);
Jackal Guof9696682018-10-05 12:23:23 +08008215}
8216
8217// Test InputFilter for KeyEvent
8218TEST_F(InputFilterTest, KeyEvent_InputFilter) {
8219 // Since the InputFilter is disabled by default, check if key event aren't filtered.
Harry Cutts101ee9b2023-07-06 18:04:14 +00008220 testNotifyKey(/*expectToBeFiltered=*/false);
Jackal Guof9696682018-10-05 12:23:23 +08008221
8222 // Enable InputFilter
8223 mDispatcher->setInputFilterEnabled(true);
8224 // Send a key event, and check if it is filtered.
Harry Cutts101ee9b2023-07-06 18:04:14 +00008225 testNotifyKey(/*expectToBeFiltered=*/true);
Jackal Guof9696682018-10-05 12:23:23 +08008226
8227 // Disable InputFilter
8228 mDispatcher->setInputFilterEnabled(false);
8229 // Send a key event, and check if it isn't filtered.
Harry Cutts101ee9b2023-07-06 18:04:14 +00008230 testNotifyKey(/*expectToBeFiltered=*/false);
Jackal Guof9696682018-10-05 12:23:23 +08008231}
8232
Prabir Pradhan81420cc2021-09-06 10:28:50 -07008233// Ensure that MotionEvents sent to the InputFilter through InputListener are converted to the
8234// logical display coordinate space.
8235TEST_F(InputFilterTest, MotionEvent_UsesLogicalDisplayCoordinates_notifyMotion) {
8236 ui::Transform firstDisplayTransform;
8237 firstDisplayTransform.set({1.1, 2.2, 3.3, 4.4, 5.5, 6.6, 0, 0, 1});
8238 ui::Transform secondDisplayTransform;
8239 secondDisplayTransform.set({-6.6, -5.5, -4.4, -3.3, -2.2, -1.1, 0, 0, 1});
8240
8241 std::vector<gui::DisplayInfo> displayInfos(2);
8242 displayInfos[0].displayId = ADISPLAY_ID_DEFAULT;
8243 displayInfos[0].transform = firstDisplayTransform;
8244 displayInfos[1].displayId = SECOND_DISPLAY_ID;
8245 displayInfos[1].transform = secondDisplayTransform;
8246
Patrick Williamsd828f302023-04-28 17:52:08 -05008247 mDispatcher->onWindowInfosChanged({{}, displayInfos, 0, 0});
Prabir Pradhan81420cc2021-09-06 10:28:50 -07008248
8249 // Enable InputFilter
8250 mDispatcher->setInputFilterEnabled(true);
8251
8252 // Ensure the correct transforms are used for the displays.
Harry Cutts101ee9b2023-07-06 18:04:14 +00008253 testNotifyMotion(ADISPLAY_ID_DEFAULT, /*expectToBeFiltered=*/true, firstDisplayTransform);
8254 testNotifyMotion(SECOND_DISPLAY_ID, /*expectToBeFiltered=*/true, secondDisplayTransform);
Prabir Pradhan81420cc2021-09-06 10:28:50 -07008255}
8256
Siarhei Vishniakou5d552c42021-05-21 05:02:22 +00008257class InputFilterInjectionPolicyTest : public InputDispatcherTest {
8258protected:
8259 virtual void SetUp() override {
8260 InputDispatcherTest::SetUp();
8261
8262 /**
8263 * We don't need to enable input filter to test the injected event policy, but we enabled it
8264 * here to make the tests more realistic, since this policy only matters when inputfilter is
8265 * on.
8266 */
8267 mDispatcher->setInputFilterEnabled(true);
8268
8269 std::shared_ptr<InputApplicationHandle> application =
8270 std::make_shared<FakeApplicationHandle>();
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07008271 mWindow = sp<FakeWindowHandle>::make(application, mDispatcher, "Test Window",
8272 ADISPLAY_ID_DEFAULT);
Siarhei Vishniakou5d552c42021-05-21 05:02:22 +00008273
8274 mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application);
8275 mWindow->setFocusable(true);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07008276 mDispatcher->onWindowInfosChanged({{*mWindow->getInfo()}, {}, 0, 0});
Siarhei Vishniakou5d552c42021-05-21 05:02:22 +00008277 setFocusedWindow(mWindow);
8278 mWindow->consumeFocusEvent(true);
8279 }
8280
Siarhei Vishniakouf00a4ec2021-06-16 03:55:32 +00008281 void testInjectedKey(int32_t policyFlags, int32_t injectedDeviceId, int32_t resolvedDeviceId,
8282 int32_t flags) {
Siarhei Vishniakou5d552c42021-05-21 05:02:22 +00008283 KeyEvent event;
8284
8285 const nsecs_t eventTime = systemTime(SYSTEM_TIME_MONOTONIC);
8286 event.initialize(InputEvent::nextId(), injectedDeviceId, AINPUT_SOURCE_KEYBOARD,
8287 ADISPLAY_ID_NONE, INVALID_HMAC, AKEY_EVENT_ACTION_DOWN, 0, AKEYCODE_A,
Harry Cutts33476232023-01-30 19:57:29 +00008288 KEY_A, AMETA_NONE, /*repeatCount=*/0, eventTime, eventTime);
Siarhei Vishniakou5d552c42021-05-21 05:02:22 +00008289 const int32_t additionalPolicyFlags =
8290 POLICY_FLAG_PASS_TO_USER | POLICY_FLAG_DISABLE_KEY_REPEAT;
8291 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Harry Cutts33476232023-01-30 19:57:29 +00008292 mDispatcher->injectInputEvent(&event, /*targetUid=*/{},
Siarhei Vishniakou4648fea2023-06-27 01:00:12 +00008293 InputEventInjectionSync::WAIT_FOR_RESULT, 100ms,
Siarhei Vishniakou5d552c42021-05-21 05:02:22 +00008294 policyFlags | additionalPolicyFlags));
8295
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07008296 mWindow->consumeKeyEvent(AllOf(WithDeviceId(resolvedDeviceId), WithFlags(flags)));
Siarhei Vishniakouf00a4ec2021-06-16 03:55:32 +00008297 }
8298
8299 void testInjectedMotion(int32_t policyFlags, int32_t injectedDeviceId, int32_t resolvedDeviceId,
8300 int32_t flags) {
8301 MotionEvent event;
8302 PointerProperties pointerProperties[1];
8303 PointerCoords pointerCoords[1];
8304 pointerProperties[0].clear();
8305 pointerProperties[0].id = 0;
8306 pointerCoords[0].clear();
8307 pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_X, 300);
8308 pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_Y, 400);
8309
8310 ui::Transform identityTransform;
8311 const nsecs_t eventTime = systemTime(SYSTEM_TIME_MONOTONIC);
8312 event.initialize(InputEvent::nextId(), injectedDeviceId, AINPUT_SOURCE_TOUCHSCREEN,
8313 DISPLAY_ID, INVALID_HMAC, AMOTION_EVENT_ACTION_DOWN, 0, 0,
8314 AMOTION_EVENT_EDGE_FLAG_NONE, AMETA_NONE, 0, MotionClassification::NONE,
8315 identityTransform, 0, 0, AMOTION_EVENT_INVALID_CURSOR_POSITION,
Prabir Pradhanb9b18502021-08-26 12:30:32 -07008316 AMOTION_EVENT_INVALID_CURSOR_POSITION, identityTransform, eventTime,
Evan Rosky09576692021-07-01 12:22:09 -07008317 eventTime,
Harry Cutts101ee9b2023-07-06 18:04:14 +00008318 /*pointerCount=*/1, pointerProperties, pointerCoords);
Siarhei Vishniakouf00a4ec2021-06-16 03:55:32 +00008319
8320 const int32_t additionalPolicyFlags = POLICY_FLAG_PASS_TO_USER;
8321 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Harry Cutts33476232023-01-30 19:57:29 +00008322 mDispatcher->injectInputEvent(&event, /*targetUid=*/{},
Siarhei Vishniakou4648fea2023-06-27 01:00:12 +00008323 InputEventInjectionSync::WAIT_FOR_RESULT, 100ms,
Siarhei Vishniakouf00a4ec2021-06-16 03:55:32 +00008324 policyFlags | additionalPolicyFlags));
8325
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07008326 mWindow->consumeMotionEvent(AllOf(WithFlags(flags), WithDeviceId(resolvedDeviceId)));
Siarhei Vishniakou5d552c42021-05-21 05:02:22 +00008327 }
8328
8329private:
8330 sp<FakeWindowHandle> mWindow;
8331};
8332
8333TEST_F(InputFilterInjectionPolicyTest, TrustedFilteredEvents_KeepOriginalDeviceId) {
Siarhei Vishniakouf00a4ec2021-06-16 03:55:32 +00008334 // Must have POLICY_FLAG_FILTERED here to indicate that the event has gone through the input
8335 // filter. Without it, the event will no different from a regularly injected event, and the
8336 // injected device id will be overwritten.
Harry Cutts33476232023-01-30 19:57:29 +00008337 testInjectedKey(POLICY_FLAG_FILTERED, /*injectedDeviceId=*/3, /*resolvedDeviceId=*/3,
8338 /*flags=*/0);
Siarhei Vishniakou5d552c42021-05-21 05:02:22 +00008339}
8340
Siarhei Vishniakouf00a4ec2021-06-16 03:55:32 +00008341TEST_F(InputFilterInjectionPolicyTest, KeyEventsInjectedFromAccessibility_HaveAccessibilityFlag) {
Siarhei Vishniakou5d552c42021-05-21 05:02:22 +00008342 testInjectedKey(POLICY_FLAG_FILTERED | POLICY_FLAG_INJECTED_FROM_ACCESSIBILITY,
Harry Cutts33476232023-01-30 19:57:29 +00008343 /*injectedDeviceId=*/3, /*resolvedDeviceId=*/3,
Siarhei Vishniakouf00a4ec2021-06-16 03:55:32 +00008344 AKEY_EVENT_FLAG_IS_ACCESSIBILITY_EVENT);
8345}
8346
8347TEST_F(InputFilterInjectionPolicyTest,
8348 MotionEventsInjectedFromAccessibility_HaveAccessibilityFlag) {
8349 testInjectedMotion(POLICY_FLAG_FILTERED | POLICY_FLAG_INJECTED_FROM_ACCESSIBILITY,
Harry Cutts33476232023-01-30 19:57:29 +00008350 /*injectedDeviceId=*/3, /*resolvedDeviceId=*/3,
Siarhei Vishniakouf00a4ec2021-06-16 03:55:32 +00008351 AMOTION_EVENT_FLAG_IS_ACCESSIBILITY_EVENT);
Siarhei Vishniakou5d552c42021-05-21 05:02:22 +00008352}
8353
8354TEST_F(InputFilterInjectionPolicyTest, RegularInjectedEvents_ReceiveVirtualDeviceId) {
Harry Cutts33476232023-01-30 19:57:29 +00008355 testInjectedKey(/*policyFlags=*/0, /*injectedDeviceId=*/3,
8356 /*resolvedDeviceId=*/VIRTUAL_KEYBOARD_ID, /*flags=*/0);
Siarhei Vishniakou5d552c42021-05-21 05:02:22 +00008357}
8358
Yeabkal Wubshitb8aadfa2024-01-17 17:03:42 -08008359class InputDispatcherUserActivityPokeTests : public InputDispatcherTest {
8360protected:
8361 virtual void SetUp() override {
8362 InputDispatcherTest::SetUp();
8363
8364 std::shared_ptr<FakeApplicationHandle> application =
8365 std::make_shared<FakeApplicationHandle>();
8366 application->setDispatchingTimeout(100ms);
8367 mWindow = sp<FakeWindowHandle>::make(application, mDispatcher, "TestWindow",
8368 ADISPLAY_ID_DEFAULT);
Yeabkal Wubshit222d83d2024-01-24 18:00:09 +00008369 mWindow->setFrame(Rect(0, 0, 100, 100));
Yeabkal Wubshitb8aadfa2024-01-17 17:03:42 -08008370 mWindow->setDispatchingTimeout(100ms);
8371 mWindow->setFocusable(true);
8372
8373 // Set focused application.
8374 mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application);
8375
8376 mDispatcher->onWindowInfosChanged({{*mWindow->getInfo()}, {}, 0, 0});
8377 setFocusedWindow(mWindow);
8378 mWindow->consumeFocusEvent(true);
8379 }
8380
8381 void notifyAndConsumeMotion(int32_t action, uint32_t source, int32_t displayId,
8382 nsecs_t eventTime) {
8383 mDispatcher->notifyMotion(MotionArgsBuilder(action, source)
8384 .displayId(displayId)
8385 .eventTime(eventTime)
8386 .pointer(PointerBuilder(0, ToolType::FINGER).x(50).y(50))
8387 .build());
8388 mWindow->consumeMotionEvent(WithMotionAction(action));
8389 }
8390
8391private:
8392 sp<FakeWindowHandle> mWindow;
8393};
8394
8395TEST_F_WITH_FLAGS(
8396 InputDispatcherUserActivityPokeTests, MinPokeTimeObserved,
8397 REQUIRES_FLAGS_ENABLED(ACONFIG_FLAG(com::android::input::flags,
8398 rate_limit_user_activity_poke_in_dispatcher))) {
8399 mDispatcher->setMinTimeBetweenUserActivityPokes(50ms);
8400
8401 // First event of type TOUCH. Should poke.
8402 notifyAndConsumeMotion(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
8403 milliseconds_to_nanoseconds(50));
8404 mFakePolicy->assertUserActivityPoked(
8405 {{milliseconds_to_nanoseconds(50), USER_ACTIVITY_EVENT_TOUCH, ADISPLAY_ID_DEFAULT}});
8406
8407 // 80ns > 50ns has passed since previous TOUCH event. Should poke.
8408 notifyAndConsumeMotion(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
8409 milliseconds_to_nanoseconds(130));
8410 mFakePolicy->assertUserActivityPoked(
8411 {{milliseconds_to_nanoseconds(130), USER_ACTIVITY_EVENT_TOUCH, ADISPLAY_ID_DEFAULT}});
8412
8413 // First event of type OTHER. Should poke (despite being within 50ns of previous TOUCH event).
8414 notifyAndConsumeMotion(ACTION_SCROLL, AINPUT_SOURCE_ROTARY_ENCODER, ADISPLAY_ID_DEFAULT,
8415 milliseconds_to_nanoseconds(135));
8416 mFakePolicy->assertUserActivityPoked(
8417 {{milliseconds_to_nanoseconds(135), USER_ACTIVITY_EVENT_OTHER, ADISPLAY_ID_DEFAULT}});
8418
8419 // Within 50ns of previous TOUCH event. Should NOT poke.
8420 notifyAndConsumeMotion(ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
8421 milliseconds_to_nanoseconds(140));
8422 mFakePolicy->assertUserActivityNotPoked();
8423
8424 // Within 50ns of previous OTHER event. Should NOT poke.
8425 notifyAndConsumeMotion(ACTION_SCROLL, AINPUT_SOURCE_ROTARY_ENCODER, ADISPLAY_ID_DEFAULT,
8426 milliseconds_to_nanoseconds(150));
8427 mFakePolicy->assertUserActivityNotPoked();
8428
8429 // Within 50ns of previous TOUCH event (which was at time 130). Should NOT poke.
8430 // Note that STYLUS is mapped to TOUCH user activity, since it's a pointer-type source.
8431 notifyAndConsumeMotion(ACTION_DOWN, AINPUT_SOURCE_STYLUS, ADISPLAY_ID_DEFAULT,
8432 milliseconds_to_nanoseconds(160));
8433 mFakePolicy->assertUserActivityNotPoked();
8434
8435 // 65ns > 50ns has passed since previous OTHER event. Should poke.
8436 notifyAndConsumeMotion(ACTION_SCROLL, AINPUT_SOURCE_ROTARY_ENCODER, ADISPLAY_ID_DEFAULT,
8437 milliseconds_to_nanoseconds(200));
8438 mFakePolicy->assertUserActivityPoked(
8439 {{milliseconds_to_nanoseconds(200), USER_ACTIVITY_EVENT_OTHER, ADISPLAY_ID_DEFAULT}});
8440
8441 // 170ns > 50ns has passed since previous TOUCH event. Should poke.
8442 notifyAndConsumeMotion(ACTION_UP, AINPUT_SOURCE_STYLUS, ADISPLAY_ID_DEFAULT,
8443 milliseconds_to_nanoseconds(300));
8444 mFakePolicy->assertUserActivityPoked(
8445 {{milliseconds_to_nanoseconds(300), USER_ACTIVITY_EVENT_TOUCH, ADISPLAY_ID_DEFAULT}});
8446
8447 // Assert that there's no more user activity poke event.
8448 mFakePolicy->assertUserActivityNotPoked();
8449}
8450
8451TEST_F_WITH_FLAGS(
8452 InputDispatcherUserActivityPokeTests, DefaultMinPokeTimeOf100MsUsed,
8453 REQUIRES_FLAGS_ENABLED(ACONFIG_FLAG(com::android::input::flags,
8454 rate_limit_user_activity_poke_in_dispatcher))) {
8455 notifyAndConsumeMotion(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
8456 milliseconds_to_nanoseconds(200));
8457 mFakePolicy->assertUserActivityPoked(
8458 {{milliseconds_to_nanoseconds(200), USER_ACTIVITY_EVENT_TOUCH, ADISPLAY_ID_DEFAULT}});
8459
8460 notifyAndConsumeMotion(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
8461 milliseconds_to_nanoseconds(280));
8462 mFakePolicy->assertUserActivityNotPoked();
8463
8464 notifyAndConsumeMotion(ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
8465 milliseconds_to_nanoseconds(340));
8466 mFakePolicy->assertUserActivityPoked(
8467 {{milliseconds_to_nanoseconds(340), USER_ACTIVITY_EVENT_TOUCH, ADISPLAY_ID_DEFAULT}});
8468}
8469
8470TEST_F_WITH_FLAGS(
8471 InputDispatcherUserActivityPokeTests, ZeroMinPokeTimeDisablesRateLimiting,
8472 REQUIRES_FLAGS_ENABLED(ACONFIG_FLAG(com::android::input::flags,
8473 rate_limit_user_activity_poke_in_dispatcher))) {
8474 mDispatcher->setMinTimeBetweenUserActivityPokes(0ms);
8475
8476 notifyAndConsumeMotion(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, 20);
8477 mFakePolicy->assertUserActivityPoked();
8478
8479 notifyAndConsumeMotion(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, 30);
8480 mFakePolicy->assertUserActivityPoked();
8481}
8482
chaviwfd6d3512019-03-25 13:23:49 -07008483class InputDispatcherOnPointerDownOutsideFocus : public InputDispatcherTest {
Prabir Pradhan3608aad2019-10-02 17:08:26 -07008484 virtual void SetUp() override {
chaviwfd6d3512019-03-25 13:23:49 -07008485 InputDispatcherTest::SetUp();
8486
Chris Yea209fde2020-07-22 13:54:51 -07008487 std::shared_ptr<FakeApplicationHandle> application =
8488 std::make_shared<FakeApplicationHandle>();
Siarhei Vishniakou870ecec2020-12-09 08:07:46 -10008489 mUnfocusedWindow =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07008490 sp<FakeWindowHandle>::make(application, mDispatcher, "Top", ADISPLAY_ID_DEFAULT);
chaviwfd6d3512019-03-25 13:23:49 -07008491 mUnfocusedWindow->setFrame(Rect(0, 0, 30, 30));
chaviwfd6d3512019-03-25 13:23:49 -07008492
Siarhei Vishniakoub9b15352019-11-26 13:19:26 -08008493 mFocusedWindow =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07008494 sp<FakeWindowHandle>::make(application, mDispatcher, "Second", ADISPLAY_ID_DEFAULT);
Siarhei Vishniakoub9b15352019-11-26 13:19:26 -08008495 mFocusedWindow->setFrame(Rect(50, 50, 100, 100));
chaviwfd6d3512019-03-25 13:23:49 -07008496
8497 // Set focused application.
8498 mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application);
Vishnu Nair47074b82020-08-14 11:54:47 -07008499 mFocusedWindow->setFocusable(true);
chaviwfd6d3512019-03-25 13:23:49 -07008500
8501 // Expect one focus window exist in display.
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07008502 mDispatcher->onWindowInfosChanged(
8503 {{*mUnfocusedWindow->getInfo(), *mFocusedWindow->getInfo()}, {}, 0, 0});
Vishnu Nair958da932020-08-21 17:12:37 -07008504 setFocusedWindow(mFocusedWindow);
Siarhei Vishniakouf1035d42019-09-20 16:32:01 +01008505 mFocusedWindow->consumeFocusEvent(true);
chaviwfd6d3512019-03-25 13:23:49 -07008506 }
8507
Prabir Pradhan3608aad2019-10-02 17:08:26 -07008508 virtual void TearDown() override {
chaviwfd6d3512019-03-25 13:23:49 -07008509 InputDispatcherTest::TearDown();
8510
8511 mUnfocusedWindow.clear();
Siarhei Vishniakoub9b15352019-11-26 13:19:26 -08008512 mFocusedWindow.clear();
chaviwfd6d3512019-03-25 13:23:49 -07008513 }
8514
8515protected:
8516 sp<FakeWindowHandle> mUnfocusedWindow;
Siarhei Vishniakoub9b15352019-11-26 13:19:26 -08008517 sp<FakeWindowHandle> mFocusedWindow;
Siarhei Vishniakoufb9fcda2020-05-04 14:59:19 -07008518 static constexpr PointF FOCUSED_WINDOW_TOUCH_POINT = {60, 60};
chaviwfd6d3512019-03-25 13:23:49 -07008519};
8520
8521// Have two windows, one with focus. Inject MotionEvent with source TOUCHSCREEN and action
8522// DOWN on the window that doesn't have focus. Ensure the window that didn't have focus received
8523// the onPointerDownOutsideFocus callback.
8524TEST_F(InputDispatcherOnPointerDownOutsideFocus, OnPointerDownOutsideFocus_Success) {
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08008525 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07008526 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
Siarhei Vishniakoufb9fcda2020-05-04 14:59:19 -07008527 {20, 20}))
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08008528 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
Siarhei Vishniakou03aee2a2020-04-13 20:44:54 -07008529 mUnfocusedWindow->consumeMotionDown();
chaviwfd6d3512019-03-25 13:23:49 -07008530
Siarhei Vishniakou2bfa9052019-11-21 18:10:54 -08008531 ASSERT_TRUE(mDispatcher->waitForIdle());
chaviwfd6d3512019-03-25 13:23:49 -07008532 mFakePolicy->assertOnPointerDownEquals(mUnfocusedWindow->getToken());
8533}
8534
8535// Have two windows, one with focus. Inject MotionEvent with source TRACKBALL and action
8536// DOWN on the window that doesn't have focus. Ensure no window received the
8537// onPointerDownOutsideFocus callback.
8538TEST_F(InputDispatcherOnPointerDownOutsideFocus, OnPointerDownOutsideFocus_NonPointerSource) {
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08008539 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07008540 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TRACKBALL, ADISPLAY_ID_DEFAULT,
8541 {20, 20}))
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08008542 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
Siarhei Vishniakou03aee2a2020-04-13 20:44:54 -07008543 mFocusedWindow->consumeMotionDown();
chaviwfd6d3512019-03-25 13:23:49 -07008544
Siarhei Vishniakou2bfa9052019-11-21 18:10:54 -08008545 ASSERT_TRUE(mDispatcher->waitForIdle());
8546 mFakePolicy->assertOnPointerDownWasNotCalled();
chaviwfd6d3512019-03-25 13:23:49 -07008547}
8548
8549// Have two windows, one with focus. Inject KeyEvent with action DOWN on the window that doesn't
8550// have focus. Ensure no window received the onPointerDownOutsideFocus callback.
8551TEST_F(InputDispatcherOnPointerDownOutsideFocus, OnPointerDownOutsideFocus_NonMotionFailure) {
Prabir Pradhan93f342c2021-03-11 15:05:30 -08008552 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07008553 injectKeyDownNoRepeat(*mDispatcher, ADISPLAY_ID_DEFAULT))
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08008554 << "Inject key event should return InputEventInjectionResult::SUCCEEDED";
Siarhei Vishniakou03aee2a2020-04-13 20:44:54 -07008555 mFocusedWindow->consumeKeyDown(ADISPLAY_ID_DEFAULT);
chaviwfd6d3512019-03-25 13:23:49 -07008556
Siarhei Vishniakou2bfa9052019-11-21 18:10:54 -08008557 ASSERT_TRUE(mDispatcher->waitForIdle());
8558 mFakePolicy->assertOnPointerDownWasNotCalled();
chaviwfd6d3512019-03-25 13:23:49 -07008559}
8560
8561// Have two windows, one with focus. Inject MotionEvent with source TOUCHSCREEN and action
8562// DOWN on the window that already has focus. Ensure no window received the
8563// onPointerDownOutsideFocus callback.
Siarhei Vishniakou870ecec2020-12-09 08:07:46 -10008564TEST_F(InputDispatcherOnPointerDownOutsideFocus, OnPointerDownOutsideFocus_OnAlreadyFocusedWindow) {
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08008565 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07008566 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
Siarhei Vishniakoufb9fcda2020-05-04 14:59:19 -07008567 FOCUSED_WINDOW_TOUCH_POINT))
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08008568 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
Siarhei Vishniakou03aee2a2020-04-13 20:44:54 -07008569 mFocusedWindow->consumeMotionDown();
chaviwfd6d3512019-03-25 13:23:49 -07008570
Siarhei Vishniakou2bfa9052019-11-21 18:10:54 -08008571 ASSERT_TRUE(mDispatcher->waitForIdle());
8572 mFakePolicy->assertOnPointerDownWasNotCalled();
chaviwfd6d3512019-03-25 13:23:49 -07008573}
8574
Prabir Pradhan47cf0a02021-03-11 20:30:57 -08008575// Have two windows, one with focus. Injecting a trusted DOWN MotionEvent with the flag
8576// NO_FOCUS_CHANGE on the unfocused window should not call the onPointerDownOutsideFocus callback.
8577TEST_F(InputDispatcherOnPointerDownOutsideFocus, NoFocusChangeFlag) {
8578 const MotionEvent event =
8579 MotionEventBuilder(AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_MOUSE)
8580 .eventTime(systemTime(SYSTEM_TIME_MONOTONIC))
Siarhei Vishniakou6d73f832022-07-21 17:27:03 -07008581 .pointer(PointerBuilder(/*id=*/0, ToolType::FINGER).x(20).y(20))
Prabir Pradhan47cf0a02021-03-11 20:30:57 -08008582 .addFlag(AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE)
8583 .build();
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07008584 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectMotionEvent(*mDispatcher, event))
Prabir Pradhan47cf0a02021-03-11 20:30:57 -08008585 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
8586 mUnfocusedWindow->consumeAnyMotionDown(ADISPLAY_ID_DEFAULT, AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
8587
8588 ASSERT_TRUE(mDispatcher->waitForIdle());
8589 mFakePolicy->assertOnPointerDownWasNotCalled();
8590 // Ensure that the unfocused window did not receive any FOCUS events.
8591 mUnfocusedWindow->assertNoEvents();
8592}
8593
chaviwaf87b3e2019-10-01 16:59:28 -07008594// These tests ensures we can send touch events to a single client when there are multiple input
8595// windows that point to the same client token.
8596class InputDispatcherMultiWindowSameTokenTests : public InputDispatcherTest {
8597 virtual void SetUp() override {
8598 InputDispatcherTest::SetUp();
8599
Chris Yea209fde2020-07-22 13:54:51 -07008600 std::shared_ptr<FakeApplicationHandle> application =
8601 std::make_shared<FakeApplicationHandle>();
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07008602 mWindow1 = sp<FakeWindowHandle>::make(application, mDispatcher, "Fake Window 1",
8603 ADISPLAY_ID_DEFAULT);
chaviwaf87b3e2019-10-01 16:59:28 -07008604 mWindow1->setFrame(Rect(0, 0, 100, 100));
8605
Prabir Pradhane7cc69c2024-01-05 21:35:28 +00008606 mWindow2 = mWindow1->clone(ADISPLAY_ID_DEFAULT);
chaviwaf87b3e2019-10-01 16:59:28 -07008607 mWindow2->setFrame(Rect(100, 100, 200, 200));
8608
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07008609 mDispatcher->onWindowInfosChanged({{*mWindow1->getInfo(), *mWindow2->getInfo()}, {}, 0, 0});
chaviwaf87b3e2019-10-01 16:59:28 -07008610 }
8611
8612protected:
8613 sp<FakeWindowHandle> mWindow1;
8614 sp<FakeWindowHandle> mWindow2;
8615
8616 // Helper function to convert the point from screen coordinates into the window's space
chaviw3277faf2021-05-19 16:45:23 -05008617 static PointF getPointInWindow(const WindowInfo* windowInfo, const PointF& point) {
chaviw1ff3d1e2020-07-01 15:53:47 -07008618 vec2 vals = windowInfo->transform.transform(point.x, point.y);
8619 return {vals.x, vals.y};
chaviwaf87b3e2019-10-01 16:59:28 -07008620 }
8621
8622 void consumeMotionEvent(const sp<FakeWindowHandle>& window, int32_t expectedAction,
8623 const std::vector<PointF>& points) {
Siarhei Vishniakouf1035d42019-09-20 16:32:01 +01008624 const std::string name = window->getName();
Siarhei Vishniakoud3061ab2023-12-18 20:41:08 -08008625 std::unique_ptr<MotionEvent> motionEvent =
Prabir Pradhan7662a8d2023-12-15 01:58:14 +00008626 window->consumeMotionEvent(WithMotionAction(expectedAction));
Siarhei Vishniakoud3061ab2023-12-18 20:41:08 -08008627 ASSERT_NE(nullptr, motionEvent);
8628 ASSERT_EQ(points.size(), motionEvent->getPointerCount());
chaviwaf87b3e2019-10-01 16:59:28 -07008629
8630 for (size_t i = 0; i < points.size(); i++) {
8631 float expectedX = points[i].x;
8632 float expectedY = points[i].y;
8633
Siarhei Vishniakoud3061ab2023-12-18 20:41:08 -08008634 EXPECT_EQ(expectedX, motionEvent->getX(i))
chaviwaf87b3e2019-10-01 16:59:28 -07008635 << "expected " << expectedX << " for x[" << i << "] coord of " << name.c_str()
Siarhei Vishniakoud3061ab2023-12-18 20:41:08 -08008636 << ", got " << motionEvent->getX(i);
8637 EXPECT_EQ(expectedY, motionEvent->getY(i))
chaviwaf87b3e2019-10-01 16:59:28 -07008638 << "expected " << expectedY << " for y[" << i << "] coord of " << name.c_str()
Siarhei Vishniakoud3061ab2023-12-18 20:41:08 -08008639 << ", got " << motionEvent->getY(i);
chaviwaf87b3e2019-10-01 16:59:28 -07008640 }
8641 }
chaviw9eaa22c2020-07-01 16:21:27 -07008642
Prabir Pradhanbb3f1c02024-01-04 20:17:14 +00008643 void touchAndAssertPositions(sp<FakeWindowHandle> touchedWindow, int32_t action,
8644 const std::vector<PointF>& touchedPoints,
chaviw9eaa22c2020-07-01 16:21:27 -07008645 std::vector<PointF> expectedPoints) {
Prabir Pradhan678438e2023-04-13 19:32:51 +00008646 mDispatcher->notifyMotion(generateMotionArgs(action, AINPUT_SOURCE_TOUCHSCREEN,
8647 ADISPLAY_ID_DEFAULT, touchedPoints));
chaviw9eaa22c2020-07-01 16:21:27 -07008648
Prabir Pradhanbb3f1c02024-01-04 20:17:14 +00008649 consumeMotionEvent(touchedWindow, action, expectedPoints);
chaviw9eaa22c2020-07-01 16:21:27 -07008650 }
chaviwaf87b3e2019-10-01 16:59:28 -07008651};
8652
8653TEST_F(InputDispatcherMultiWindowSameTokenTests, SingleTouchSameScale) {
8654 // Touch Window 1
8655 PointF touchedPoint = {10, 10};
8656 PointF expectedPoint = getPointInWindow(mWindow1->getInfo(), touchedPoint);
Prabir Pradhanbb3f1c02024-01-04 20:17:14 +00008657 touchAndAssertPositions(mWindow1, AMOTION_EVENT_ACTION_DOWN, {touchedPoint}, {expectedPoint});
chaviwaf87b3e2019-10-01 16:59:28 -07008658
8659 // Release touch on Window 1
Prabir Pradhanbb3f1c02024-01-04 20:17:14 +00008660 touchAndAssertPositions(mWindow1, AMOTION_EVENT_ACTION_UP, {touchedPoint}, {expectedPoint});
chaviwaf87b3e2019-10-01 16:59:28 -07008661
8662 // Touch Window 2
8663 touchedPoint = {150, 150};
8664 expectedPoint = getPointInWindow(mWindow2->getInfo(), touchedPoint);
Prabir Pradhanbb3f1c02024-01-04 20:17:14 +00008665 touchAndAssertPositions(mWindow2, AMOTION_EVENT_ACTION_DOWN, {touchedPoint}, {expectedPoint});
chaviwaf87b3e2019-10-01 16:59:28 -07008666}
8667
chaviw9eaa22c2020-07-01 16:21:27 -07008668TEST_F(InputDispatcherMultiWindowSameTokenTests, SingleTouchDifferentTransform) {
8669 // Set scale value for window2
chaviwaf87b3e2019-10-01 16:59:28 -07008670 mWindow2->setWindowScale(0.5f, 0.5f);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07008671 mDispatcher->onWindowInfosChanged({{*mWindow1->getInfo(), *mWindow2->getInfo()}, {}, 0, 0});
chaviwaf87b3e2019-10-01 16:59:28 -07008672
8673 // Touch Window 1
8674 PointF touchedPoint = {10, 10};
8675 PointF expectedPoint = getPointInWindow(mWindow1->getInfo(), touchedPoint);
Prabir Pradhanbb3f1c02024-01-04 20:17:14 +00008676 touchAndAssertPositions(mWindow1, AMOTION_EVENT_ACTION_DOWN, {touchedPoint}, {expectedPoint});
chaviwaf87b3e2019-10-01 16:59:28 -07008677 // Release touch on Window 1
Prabir Pradhanbb3f1c02024-01-04 20:17:14 +00008678 touchAndAssertPositions(mWindow1, AMOTION_EVENT_ACTION_UP, {touchedPoint}, {expectedPoint});
chaviwaf87b3e2019-10-01 16:59:28 -07008679
8680 // Touch Window 2
8681 touchedPoint = {150, 150};
8682 expectedPoint = getPointInWindow(mWindow2->getInfo(), touchedPoint);
Prabir Pradhanbb3f1c02024-01-04 20:17:14 +00008683 touchAndAssertPositions(mWindow2, AMOTION_EVENT_ACTION_DOWN, {touchedPoint}, {expectedPoint});
8684 touchAndAssertPositions(mWindow2, AMOTION_EVENT_ACTION_UP, {touchedPoint}, {expectedPoint});
chaviwaf87b3e2019-10-01 16:59:28 -07008685
chaviw9eaa22c2020-07-01 16:21:27 -07008686 // Update the transform so rotation is set
8687 mWindow2->setWindowTransform(0, -1, 1, 0);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07008688 mDispatcher->onWindowInfosChanged({{*mWindow1->getInfo(), *mWindow2->getInfo()}, {}, 0, 0});
chaviw9eaa22c2020-07-01 16:21:27 -07008689 expectedPoint = getPointInWindow(mWindow2->getInfo(), touchedPoint);
Prabir Pradhanbb3f1c02024-01-04 20:17:14 +00008690 touchAndAssertPositions(mWindow2, AMOTION_EVENT_ACTION_DOWN, {touchedPoint}, {expectedPoint});
chaviwaf87b3e2019-10-01 16:59:28 -07008691}
8692
chaviw9eaa22c2020-07-01 16:21:27 -07008693TEST_F(InputDispatcherMultiWindowSameTokenTests, MultipleTouchDifferentTransform) {
Chavi Weingarten65f98b82020-01-16 18:56:50 +00008694 mWindow2->setWindowScale(0.5f, 0.5f);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07008695 mDispatcher->onWindowInfosChanged({{*mWindow1->getInfo(), *mWindow2->getInfo()}, {}, 0, 0});
Chavi Weingarten65f98b82020-01-16 18:56:50 +00008696
8697 // Touch Window 1
8698 std::vector<PointF> touchedPoints = {PointF{10, 10}};
8699 std::vector<PointF> expectedPoints = {getPointInWindow(mWindow1->getInfo(), touchedPoints[0])};
Prabir Pradhanbb3f1c02024-01-04 20:17:14 +00008700 touchAndAssertPositions(mWindow1, AMOTION_EVENT_ACTION_DOWN, touchedPoints, expectedPoints);
Chavi Weingarten65f98b82020-01-16 18:56:50 +00008701
8702 // Touch Window 2
Prabir Pradhanbb3f1c02024-01-04 20:17:14 +00008703 // Since this is part of the same touch gesture that has already been dispatched to Window 1,
8704 // the touch stream from Window 2 will be merged with the stream in Window 1. The merged stream
8705 // will continue to be dispatched through Window 1.
chaviw9eaa22c2020-07-01 16:21:27 -07008706 touchedPoints.push_back(PointF{150, 150});
8707 expectedPoints.push_back(getPointInWindow(mWindow2->getInfo(), touchedPoints[1]));
Prabir Pradhanbb3f1c02024-01-04 20:17:14 +00008708 touchAndAssertPositions(mWindow1, POINTER_1_DOWN, touchedPoints, expectedPoints);
Chavi Weingarten65f98b82020-01-16 18:56:50 +00008709
chaviw9eaa22c2020-07-01 16:21:27 -07008710 // Release Window 2
Prabir Pradhanbb3f1c02024-01-04 20:17:14 +00008711 touchAndAssertPositions(mWindow1, POINTER_1_UP, touchedPoints, expectedPoints);
chaviw9eaa22c2020-07-01 16:21:27 -07008712 expectedPoints.pop_back();
Chavi Weingarten65f98b82020-01-16 18:56:50 +00008713
chaviw9eaa22c2020-07-01 16:21:27 -07008714 // Update the transform so rotation is set for Window 2
8715 mWindow2->setWindowTransform(0, -1, 1, 0);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07008716 mDispatcher->onWindowInfosChanged({{*mWindow1->getInfo(), *mWindow2->getInfo()}, {}, 0, 0});
chaviw9eaa22c2020-07-01 16:21:27 -07008717 expectedPoints.push_back(getPointInWindow(mWindow2->getInfo(), touchedPoints[1]));
Prabir Pradhanbb3f1c02024-01-04 20:17:14 +00008718 touchAndAssertPositions(mWindow1, POINTER_1_DOWN, touchedPoints, expectedPoints);
Chavi Weingarten65f98b82020-01-16 18:56:50 +00008719}
8720
chaviw9eaa22c2020-07-01 16:21:27 -07008721TEST_F(InputDispatcherMultiWindowSameTokenTests, MultipleTouchMoveDifferentTransform) {
Chavi Weingarten65f98b82020-01-16 18:56:50 +00008722 mWindow2->setWindowScale(0.5f, 0.5f);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07008723 mDispatcher->onWindowInfosChanged({{*mWindow1->getInfo(), *mWindow2->getInfo()}, {}, 0, 0});
Chavi Weingarten65f98b82020-01-16 18:56:50 +00008724
8725 // Touch Window 1
8726 std::vector<PointF> touchedPoints = {PointF{10, 10}};
8727 std::vector<PointF> expectedPoints = {getPointInWindow(mWindow1->getInfo(), touchedPoints[0])};
Prabir Pradhanbb3f1c02024-01-04 20:17:14 +00008728 touchAndAssertPositions(mWindow1, AMOTION_EVENT_ACTION_DOWN, touchedPoints, expectedPoints);
Chavi Weingarten65f98b82020-01-16 18:56:50 +00008729
8730 // Touch Window 2
chaviw9eaa22c2020-07-01 16:21:27 -07008731 touchedPoints.push_back(PointF{150, 150});
8732 expectedPoints.push_back(getPointInWindow(mWindow2->getInfo(), touchedPoints[1]));
Chavi Weingarten65f98b82020-01-16 18:56:50 +00008733
Prabir Pradhanbb3f1c02024-01-04 20:17:14 +00008734 touchAndAssertPositions(mWindow1, POINTER_1_DOWN, touchedPoints, expectedPoints);
Chavi Weingarten65f98b82020-01-16 18:56:50 +00008735
8736 // Move both windows
8737 touchedPoints = {{20, 20}, {175, 175}};
8738 expectedPoints = {getPointInWindow(mWindow1->getInfo(), touchedPoints[0]),
8739 getPointInWindow(mWindow2->getInfo(), touchedPoints[1])};
8740
Prabir Pradhanbb3f1c02024-01-04 20:17:14 +00008741 touchAndAssertPositions(mWindow1, AMOTION_EVENT_ACTION_MOVE, touchedPoints, expectedPoints);
Chavi Weingarten65f98b82020-01-16 18:56:50 +00008742
chaviw9eaa22c2020-07-01 16:21:27 -07008743 // Release Window 2
Prabir Pradhanbb3f1c02024-01-04 20:17:14 +00008744 touchAndAssertPositions(mWindow1, POINTER_1_UP, touchedPoints, expectedPoints);
chaviw9eaa22c2020-07-01 16:21:27 -07008745 expectedPoints.pop_back();
8746
8747 // Touch Window 2
8748 mWindow2->setWindowTransform(0, -1, 1, 0);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07008749 mDispatcher->onWindowInfosChanged({{*mWindow1->getInfo(), *mWindow2->getInfo()}, {}, 0, 0});
chaviw9eaa22c2020-07-01 16:21:27 -07008750 expectedPoints.push_back(getPointInWindow(mWindow2->getInfo(), touchedPoints[1]));
Prabir Pradhanbb3f1c02024-01-04 20:17:14 +00008751 touchAndAssertPositions(mWindow1, POINTER_1_DOWN, touchedPoints, expectedPoints);
chaviw9eaa22c2020-07-01 16:21:27 -07008752
8753 // Move both windows
8754 touchedPoints = {{20, 20}, {175, 175}};
8755 expectedPoints = {getPointInWindow(mWindow1->getInfo(), touchedPoints[0]),
8756 getPointInWindow(mWindow2->getInfo(), touchedPoints[1])};
8757
Prabir Pradhanbb3f1c02024-01-04 20:17:14 +00008758 touchAndAssertPositions(mWindow1, AMOTION_EVENT_ACTION_MOVE, touchedPoints, expectedPoints);
Chavi Weingarten65f98b82020-01-16 18:56:50 +00008759}
8760
8761TEST_F(InputDispatcherMultiWindowSameTokenTests, MultipleWindowsFirstTouchWithScale) {
8762 mWindow1->setWindowScale(0.5f, 0.5f);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07008763 mDispatcher->onWindowInfosChanged({{*mWindow1->getInfo(), *mWindow2->getInfo()}, {}, 0, 0});
Chavi Weingarten65f98b82020-01-16 18:56:50 +00008764
8765 // Touch Window 1
8766 std::vector<PointF> touchedPoints = {PointF{10, 10}};
8767 std::vector<PointF> expectedPoints = {getPointInWindow(mWindow1->getInfo(), touchedPoints[0])};
Prabir Pradhanbb3f1c02024-01-04 20:17:14 +00008768 touchAndAssertPositions(mWindow1, AMOTION_EVENT_ACTION_DOWN, touchedPoints, expectedPoints);
Chavi Weingarten65f98b82020-01-16 18:56:50 +00008769
8770 // Touch Window 2
chaviw9eaa22c2020-07-01 16:21:27 -07008771 touchedPoints.push_back(PointF{150, 150});
8772 expectedPoints.push_back(getPointInWindow(mWindow2->getInfo(), touchedPoints[1]));
Chavi Weingarten65f98b82020-01-16 18:56:50 +00008773
Prabir Pradhanbb3f1c02024-01-04 20:17:14 +00008774 touchAndAssertPositions(mWindow1, POINTER_1_DOWN, touchedPoints, expectedPoints);
Chavi Weingarten65f98b82020-01-16 18:56:50 +00008775
8776 // Move both windows
8777 touchedPoints = {{20, 20}, {175, 175}};
8778 expectedPoints = {getPointInWindow(mWindow1->getInfo(), touchedPoints[0]),
8779 getPointInWindow(mWindow2->getInfo(), touchedPoints[1])};
8780
Prabir Pradhanbb3f1c02024-01-04 20:17:14 +00008781 touchAndAssertPositions(mWindow1, AMOTION_EVENT_ACTION_MOVE, touchedPoints, expectedPoints);
Chavi Weingarten65f98b82020-01-16 18:56:50 +00008782}
8783
Siarhei Vishniakou0f6558d2023-04-21 12:05:13 -07008784/**
8785 * When one of the windows is slippery, the touch should not slip into the other window with the
8786 * same input channel.
8787 */
8788TEST_F(InputDispatcherMultiWindowSameTokenTests, TouchDoesNotSlipEvenIfSlippery) {
8789 mWindow1->setSlippery(true);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07008790 mDispatcher->onWindowInfosChanged({{*mWindow1->getInfo(), *mWindow2->getInfo()}, {}, 0, 0});
Siarhei Vishniakou0f6558d2023-04-21 12:05:13 -07008791
8792 // Touch down in window 1
8793 mDispatcher->notifyMotion(generateMotionArgs(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN,
8794 ADISPLAY_ID_DEFAULT, {{50, 50}}));
8795 consumeMotionEvent(mWindow1, ACTION_DOWN, {{50, 50}});
8796
8797 // Move touch to be above window 2. Even though window 1 is slippery, touch should not slip.
8798 // That means the gesture should continue normally, without any ACTION_CANCEL or ACTION_DOWN
8799 // getting generated.
8800 mDispatcher->notifyMotion(generateMotionArgs(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN,
8801 ADISPLAY_ID_DEFAULT, {{150, 150}}));
8802
8803 consumeMotionEvent(mWindow1, ACTION_MOVE, {{150, 150}});
8804}
8805
Siarhei Vishniakoud5876ba2023-05-15 17:58:34 -07008806/**
8807 * When hover starts in one window and continues into the other, there should be a HOVER_EXIT and
8808 * a HOVER_ENTER generated, even if the windows have the same token. This is because the new window
8809 * that the pointer is hovering over may have a different transform.
8810 */
8811TEST_F(InputDispatcherMultiWindowSameTokenTests, HoverIntoClone) {
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07008812 mDispatcher->onWindowInfosChanged({{*mWindow1->getInfo(), *mWindow2->getInfo()}, {}, 0, 0});
Siarhei Vishniakoud5876ba2023-05-15 17:58:34 -07008813
8814 // Start hover in window 1
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -07008815 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_ENTER, AINPUT_SOURCE_TOUCHSCREEN)
8816 .pointer(PointerBuilder(0, ToolType::FINGER).x(50).y(50))
8817 .build());
Siarhei Vishniakoud5876ba2023-05-15 17:58:34 -07008818 consumeMotionEvent(mWindow1, ACTION_HOVER_ENTER,
8819 {getPointInWindow(mWindow1->getInfo(), PointF{50, 50})});
Siarhei Vishniakoud5876ba2023-05-15 17:58:34 -07008820 // Move hover to window 2.
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -07008821 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_MOVE, AINPUT_SOURCE_TOUCHSCREEN)
8822 .pointer(PointerBuilder(0, ToolType::FINGER).x(150).y(150))
8823 .build());
Siarhei Vishniakoud5876ba2023-05-15 17:58:34 -07008824 consumeMotionEvent(mWindow1, ACTION_HOVER_EXIT, {{50, 50}});
Prabir Pradhanbb3f1c02024-01-04 20:17:14 +00008825 consumeMotionEvent(mWindow2, ACTION_HOVER_ENTER,
Siarhei Vishniakoud5876ba2023-05-15 17:58:34 -07008826 {getPointInWindow(mWindow2->getInfo(), PointF{150, 150})});
8827}
8828
Siarhei Vishniakou4cb50ca2020-05-26 21:43:02 -07008829class InputDispatcherSingleWindowAnr : public InputDispatcherTest {
8830 virtual void SetUp() override {
8831 InputDispatcherTest::SetUp();
8832
Chris Yea209fde2020-07-22 13:54:51 -07008833 mApplication = std::make_shared<FakeApplicationHandle>();
Siarhei Vishniakouf83c6932023-07-07 17:48:10 -07008834 mApplication->setDispatchingTimeout(100ms);
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07008835 mWindow = sp<FakeWindowHandle>::make(mApplication, mDispatcher, "TestWindow",
8836 ADISPLAY_ID_DEFAULT);
Siarhei Vishniakou4cb50ca2020-05-26 21:43:02 -07008837 mWindow->setFrame(Rect(0, 0, 30, 30));
Siarhei Vishniakouf83c6932023-07-07 17:48:10 -07008838 mWindow->setDispatchingTimeout(100ms);
Vishnu Nair47074b82020-08-14 11:54:47 -07008839 mWindow->setFocusable(true);
Siarhei Vishniakou4cb50ca2020-05-26 21:43:02 -07008840
8841 // Set focused application.
8842 mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, mApplication);
8843
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07008844 mDispatcher->onWindowInfosChanged({{*mWindow->getInfo()}, {}, 0, 0});
Vishnu Nair958da932020-08-21 17:12:37 -07008845 setFocusedWindow(mWindow);
Siarhei Vishniakou4cb50ca2020-05-26 21:43:02 -07008846 mWindow->consumeFocusEvent(true);
8847 }
8848
8849 virtual void TearDown() override {
8850 InputDispatcherTest::TearDown();
8851 mWindow.clear();
8852 }
8853
8854protected:
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07008855 static constexpr std::chrono::duration SPY_TIMEOUT = 200ms;
Chris Yea209fde2020-07-22 13:54:51 -07008856 std::shared_ptr<FakeApplicationHandle> mApplication;
Siarhei Vishniakou4cb50ca2020-05-26 21:43:02 -07008857 sp<FakeWindowHandle> mWindow;
8858 static constexpr PointF WINDOW_LOCATION = {20, 20};
8859
8860 void tapOnWindow() {
Siarhei Vishniakou67bf2162023-11-16 13:29:50 -08008861 const auto touchingPointer = PointerBuilder(/*id=*/0, ToolType::FINGER)
8862 .x(WINDOW_LOCATION.x)
8863 .y(WINDOW_LOCATION.y);
8864 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
8865 .pointer(touchingPointer)
8866 .build());
8867 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN)
8868 .pointer(touchingPointer)
8869 .build());
Siarhei Vishniakou4cb50ca2020-05-26 21:43:02 -07008870 }
Prabir Pradhan1376fcd2022-01-21 09:56:35 -08008871
8872 sp<FakeWindowHandle> addSpyWindow() {
8873 sp<FakeWindowHandle> spy =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07008874 sp<FakeWindowHandle>::make(mApplication, mDispatcher, "Spy", ADISPLAY_ID_DEFAULT);
Prabir Pradhan1376fcd2022-01-21 09:56:35 -08008875 spy->setTrustedOverlay(true);
8876 spy->setFocusable(false);
Prabir Pradhan51e7db02022-02-07 06:02:57 -08008877 spy->setSpy(true);
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07008878 spy->setDispatchingTimeout(SPY_TIMEOUT);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07008879 mDispatcher->onWindowInfosChanged({{*spy->getInfo(), *mWindow->getInfo()}, {}, 0, 0});
Prabir Pradhan1376fcd2022-01-21 09:56:35 -08008880 return spy;
8881 }
Siarhei Vishniakou4cb50ca2020-05-26 21:43:02 -07008882};
8883
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07008884// Send a tap and respond, which should not cause an ANR.
8885TEST_F(InputDispatcherSingleWindowAnr, WhenTouchIsConsumed_NoAnr) {
8886 tapOnWindow();
8887 mWindow->consumeMotionDown();
8888 mWindow->consumeMotionUp();
8889 ASSERT_TRUE(mDispatcher->waitForIdle());
8890 mFakePolicy->assertNotifyAnrWasNotCalled();
8891}
8892
8893// Send a regular key and respond, which should not cause an ANR.
8894TEST_F(InputDispatcherSingleWindowAnr, WhenKeyIsConsumed_NoAnr) {
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07008895 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectKeyDownNoRepeat(*mDispatcher));
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07008896 mWindow->consumeKeyDown(ADISPLAY_ID_NONE);
8897 ASSERT_TRUE(mDispatcher->waitForIdle());
8898 mFakePolicy->assertNotifyAnrWasNotCalled();
8899}
8900
Siarhei Vishniakoue41c4512020-09-08 19:35:58 -05008901TEST_F(InputDispatcherSingleWindowAnr, WhenFocusedApplicationChanges_NoAnr) {
8902 mWindow->setFocusable(false);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07008903 mDispatcher->onWindowInfosChanged({{*mWindow->getInfo()}, {}, 0, 0});
Siarhei Vishniakoue41c4512020-09-08 19:35:58 -05008904 mWindow->consumeFocusEvent(false);
8905
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08008906 InputEventInjectionResult result =
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07008907 injectKey(*mDispatcher, AKEY_EVENT_ACTION_DOWN, /*repeatCount=*/0, ADISPLAY_ID_DEFAULT,
8908 InputEventInjectionSync::NONE, CONSUME_TIMEOUT_EVENT_EXPECTED,
Harry Cutts33476232023-01-30 19:57:29 +00008909 /*allowKeyRepeat=*/false);
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08008910 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, result);
Siarhei Vishniakoue41c4512020-09-08 19:35:58 -05008911 // Key will not go to window because we have no focused window.
8912 // The 'no focused window' ANR timer should start instead.
8913
8914 // Now, the focused application goes away.
8915 mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, nullptr);
8916 // The key should get dropped and there should be no ANR.
8917
8918 ASSERT_TRUE(mDispatcher->waitForIdle());
8919 mFakePolicy->assertNotifyAnrWasNotCalled();
8920}
8921
Siarhei Vishniakou4cb50ca2020-05-26 21:43:02 -07008922// Send an event to the app and have the app not respond right away.
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07008923// When ANR is raised, policy will tell the dispatcher to cancel the events for that window.
8924// So InputDispatcher will enqueue ACTION_CANCEL event as well.
Siarhei Vishniakou4cb50ca2020-05-26 21:43:02 -07008925TEST_F(InputDispatcherSingleWindowAnr, OnPointerDown_BasicAnr) {
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08008926 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07008927 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
Siarhei Vishniakou4cb50ca2020-05-26 21:43:02 -07008928 WINDOW_LOCATION));
8929
Siarhei Vishniakoud3061ab2023-12-18 20:41:08 -08008930 const auto [sequenceNum, _] = mWindow->receiveEvent(); // ACTION_DOWN
Siarhei Vishniakou4cb50ca2020-05-26 21:43:02 -07008931 ASSERT_TRUE(sequenceNum);
8932 const std::chrono::duration timeout = mWindow->getDispatchingTimeout(DISPATCHING_TIMEOUT);
Prabir Pradhanedd96402022-02-15 01:46:16 -08008933 mFakePolicy->assertNotifyWindowUnresponsiveWasCalled(timeout, mWindow);
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07008934
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07008935 mWindow->finishEvent(*sequenceNum);
Siarhei Vishniakou1ae72f12023-01-29 12:55:30 -08008936 mWindow->consumeMotionEvent(
8937 AllOf(WithMotionAction(ACTION_CANCEL), WithDisplayId(ADISPLAY_ID_DEFAULT)));
Siarhei Vishniakou4cb50ca2020-05-26 21:43:02 -07008938 ASSERT_TRUE(mDispatcher->waitForIdle());
Prabir Pradhanedd96402022-02-15 01:46:16 -08008939 mFakePolicy->assertNotifyWindowResponsiveWasCalled(mWindow->getToken(), mWindow->getPid());
Siarhei Vishniakou4cb50ca2020-05-26 21:43:02 -07008940}
8941
8942// Send a key to the app and have the app not respond right away.
8943TEST_F(InputDispatcherSingleWindowAnr, OnKeyDown_BasicAnr) {
8944 // Inject a key, and don't respond - expect that ANR is called.
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07008945 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectKeyDownNoRepeat(*mDispatcher));
Siarhei Vishniakoud3061ab2023-12-18 20:41:08 -08008946 const auto [sequenceNum, _] = mWindow->receiveEvent();
Siarhei Vishniakou4cb50ca2020-05-26 21:43:02 -07008947 ASSERT_TRUE(sequenceNum);
Siarhei Vishniakou4cb50ca2020-05-26 21:43:02 -07008948 const std::chrono::duration timeout = mWindow->getDispatchingTimeout(DISPATCHING_TIMEOUT);
Prabir Pradhanedd96402022-02-15 01:46:16 -08008949 mFakePolicy->assertNotifyWindowUnresponsiveWasCalled(timeout, mWindow);
Siarhei Vishniakou4cb50ca2020-05-26 21:43:02 -07008950 ASSERT_TRUE(mDispatcher->waitForIdle());
8951}
8952
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07008953// We have a focused application, but no focused window
8954TEST_F(InputDispatcherSingleWindowAnr, FocusedApplication_NoFocusedWindow) {
Vishnu Nair47074b82020-08-14 11:54:47 -07008955 mWindow->setFocusable(false);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07008956 mDispatcher->onWindowInfosChanged({{*mWindow->getInfo()}, {}, 0, 0});
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07008957 mWindow->consumeFocusEvent(false);
8958
8959 // taps on the window work as normal
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08008960 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07008961 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07008962 WINDOW_LOCATION));
8963 ASSERT_NO_FATAL_FAILURE(mWindow->consumeMotionDown());
8964 mDispatcher->waitForIdle();
8965 mFakePolicy->assertNotifyAnrWasNotCalled();
8966
8967 // Once a focused event arrives, we get an ANR for this application
8968 // We specify the injection timeout to be smaller than the application timeout, to ensure that
8969 // injection times out (instead of failing).
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08008970 const InputEventInjectionResult result =
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07008971 injectKey(*mDispatcher, AKEY_EVENT_ACTION_DOWN, /*repeatCount=*/0, ADISPLAY_ID_DEFAULT,
Siarhei Vishniakouf83c6932023-07-07 17:48:10 -07008972 InputEventInjectionSync::WAIT_FOR_RESULT, 50ms, /*allowKeyRepeat=*/false);
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08008973 ASSERT_EQ(InputEventInjectionResult::TIMED_OUT, result);
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07008974 const std::chrono::duration timeout = mApplication->getDispatchingTimeout(DISPATCHING_TIMEOUT);
Vishnu Naire4df8752022-09-08 09:17:55 -07008975 mFakePolicy->assertNotifyNoFocusedWindowAnrWasCalled(timeout, mApplication);
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07008976 ASSERT_TRUE(mDispatcher->waitForIdle());
8977}
8978
Siarhei Vishniakou289e9242022-02-15 14:50:16 -08008979/**
8980 * Make sure the stale key is dropped before causing an ANR. So even if there's no focused window,
8981 * there will not be an ANR.
8982 */
8983TEST_F(InputDispatcherSingleWindowAnr, StaleKeyEventDoesNotAnr) {
8984 mWindow->setFocusable(false);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07008985 mDispatcher->onWindowInfosChanged({{*mWindow->getInfo()}, {}, 0, 0});
Siarhei Vishniakou289e9242022-02-15 14:50:16 -08008986 mWindow->consumeFocusEvent(false);
8987
8988 KeyEvent event;
Siarhei Vishniakoua7333112023-10-27 13:33:29 -07008989 static constexpr std::chrono::duration STALE_EVENT_TIMEOUT = 1000ms;
8990 mFakePolicy->setStaleEventTimeout(STALE_EVENT_TIMEOUT);
Siarhei Vishniakou289e9242022-02-15 14:50:16 -08008991 const nsecs_t eventTime = systemTime(SYSTEM_TIME_MONOTONIC) -
8992 std::chrono::nanoseconds(STALE_EVENT_TIMEOUT).count();
8993
8994 // Define a valid key down event that is stale (too old).
8995 event.initialize(InputEvent::nextId(), DEVICE_ID, AINPUT_SOURCE_KEYBOARD, ADISPLAY_ID_NONE,
Harry Cutts101ee9b2023-07-06 18:04:14 +00008996 INVALID_HMAC, AKEY_EVENT_ACTION_DOWN, /*flags=*/0, AKEYCODE_A, KEY_A,
Hu Guofe3c8f12023-09-22 17:20:15 +08008997 AMETA_NONE, /*repeatCount=*/0, eventTime, eventTime);
Siarhei Vishniakou289e9242022-02-15 14:50:16 -08008998
Hu Guofe3c8f12023-09-22 17:20:15 +08008999 const int32_t policyFlags =
9000 POLICY_FLAG_FILTERED | POLICY_FLAG_PASS_TO_USER | POLICY_FLAG_DISABLE_KEY_REPEAT;
Siarhei Vishniakou289e9242022-02-15 14:50:16 -08009001
9002 InputEventInjectionResult result =
Harry Cutts33476232023-01-30 19:57:29 +00009003 mDispatcher->injectInputEvent(&event, /*targetUid=*/{},
Siarhei Vishniakou289e9242022-02-15 14:50:16 -08009004 InputEventInjectionSync::WAIT_FOR_RESULT,
9005 INJECT_EVENT_TIMEOUT, policyFlags);
9006 ASSERT_EQ(InputEventInjectionResult::FAILED, result)
9007 << "Injection should fail because the event is stale";
9008
9009 ASSERT_TRUE(mDispatcher->waitForIdle());
9010 mFakePolicy->assertNotifyAnrWasNotCalled();
9011 mWindow->assertNoEvents();
9012}
9013
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009014// We have a focused application, but no focused window
Siarhei Vishniakou234129c2020-10-22 22:28:12 -05009015// Make sure that we don't notify policy twice about the same ANR.
9016TEST_F(InputDispatcherSingleWindowAnr, NoFocusedWindow_DoesNotSendDuplicateAnr) {
Siarhei Vishniakou06405fc2023-09-22 13:40:51 -07009017 const std::chrono::duration appTimeout = 400ms;
9018 mApplication->setDispatchingTimeout(appTimeout);
9019 mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, mApplication);
9020
Vishnu Nair47074b82020-08-14 11:54:47 -07009021 mWindow->setFocusable(false);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07009022 mDispatcher->onWindowInfosChanged({{*mWindow->getInfo()}, {}, 0, 0});
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009023 mWindow->consumeFocusEvent(false);
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009024
9025 // Once a focused event arrives, we get an ANR for this application
9026 // We specify the injection timeout to be smaller than the application timeout, to ensure that
9027 // injection times out (instead of failing).
Siarhei Vishniakou06405fc2023-09-22 13:40:51 -07009028 const std::chrono::duration eventInjectionTimeout = 100ms;
9029 ASSERT_LT(eventInjectionTimeout, appTimeout);
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08009030 const InputEventInjectionResult result =
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07009031 injectKey(*mDispatcher, AKEY_EVENT_ACTION_DOWN, /*repeatCount=*/0, ADISPLAY_ID_DEFAULT,
Siarhei Vishniakou06405fc2023-09-22 13:40:51 -07009032 InputEventInjectionSync::WAIT_FOR_RESULT, eventInjectionTimeout,
9033 /*allowKeyRepeat=*/false);
9034 ASSERT_EQ(InputEventInjectionResult::TIMED_OUT, result)
9035 << "result=" << ftl::enum_string(result);
9036 // We already waited for 'eventInjectionTimeout`, because the countdown started when the event
9037 // was first injected. So now we have (appTimeout - eventInjectionTimeout) left to wait.
9038 std::chrono::duration remainingWaitTime = appTimeout - eventInjectionTimeout;
9039 mFakePolicy->assertNotifyNoFocusedWindowAnrWasCalled(remainingWaitTime, mApplication);
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009040
Vishnu Naire4df8752022-09-08 09:17:55 -07009041 std::this_thread::sleep_for(appTimeout);
Siarhei Vishniakou234129c2020-10-22 22:28:12 -05009042 // ANR should not be raised again. It is up to policy to do that if it desires.
9043 mFakePolicy->assertNotifyAnrWasNotCalled();
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009044
Siarhei Vishniakou234129c2020-10-22 22:28:12 -05009045 // If we now get a focused window, the ANR should stop, but the policy handles that via
9046 // 'notifyFocusChanged' callback. This is implemented in the policy so we can't test it here.
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009047 ASSERT_TRUE(mDispatcher->waitForIdle());
9048}
9049
9050// We have a focused application, but no focused window
9051TEST_F(InputDispatcherSingleWindowAnr, NoFocusedWindow_DropsFocusedEvents) {
Vishnu Nair47074b82020-08-14 11:54:47 -07009052 mWindow->setFocusable(false);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07009053 mDispatcher->onWindowInfosChanged({{*mWindow->getInfo()}, {}, 0, 0});
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009054 mWindow->consumeFocusEvent(false);
9055
9056 // Once a focused event arrives, we get an ANR for this application
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07009057 ASSERT_NO_FATAL_FAILURE(assertInjectedKeyTimesOut(*mDispatcher));
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009058
Vishnu Naire4df8752022-09-08 09:17:55 -07009059 const std::chrono::duration timeout = mApplication->getDispatchingTimeout(DISPATCHING_TIMEOUT);
9060 mFakePolicy->assertNotifyNoFocusedWindowAnrWasCalled(timeout, mApplication);
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009061
9062 // Future focused events get dropped right away
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07009063 ASSERT_EQ(InputEventInjectionResult::FAILED, injectKeyDown(*mDispatcher));
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009064 ASSERT_TRUE(mDispatcher->waitForIdle());
9065 mWindow->assertNoEvents();
9066}
9067
9068/**
9069 * Ensure that the implementation is valid. Since we are using multiset to keep track of the
9070 * ANR timeouts, we are allowing entries with identical timestamps in the same connection.
9071 * If we process 1 of the events, but ANR on the second event with the same timestamp,
9072 * the ANR mechanism should still work.
9073 *
9074 * In this test, we are injecting DOWN and UP events with the same timestamps, and acknowledging the
9075 * DOWN event, while not responding on the second one.
9076 */
9077TEST_F(InputDispatcherSingleWindowAnr, Anr_HandlesEventsWithIdenticalTimestamps) {
9078 nsecs_t currentTime = systemTime(SYSTEM_TIME_MONOTONIC);
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07009079 injectMotionEvent(*mDispatcher, AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN,
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009080 ADISPLAY_ID_DEFAULT, WINDOW_LOCATION,
9081 {AMOTION_EVENT_INVALID_CURSOR_POSITION,
9082 AMOTION_EVENT_INVALID_CURSOR_POSITION},
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08009083 500ms, InputEventInjectionSync::WAIT_FOR_RESULT, currentTime);
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009084
9085 // Now send ACTION_UP, with identical timestamp
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07009086 injectMotionEvent(*mDispatcher, AMOTION_EVENT_ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN,
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009087 ADISPLAY_ID_DEFAULT, WINDOW_LOCATION,
9088 {AMOTION_EVENT_INVALID_CURSOR_POSITION,
9089 AMOTION_EVENT_INVALID_CURSOR_POSITION},
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08009090 500ms, InputEventInjectionSync::WAIT_FOR_RESULT, currentTime);
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009091
9092 // We have now sent down and up. Let's consume first event and then ANR on the second.
9093 mWindow->consumeMotionDown(ADISPLAY_ID_DEFAULT);
9094 const std::chrono::duration timeout = mWindow->getDispatchingTimeout(DISPATCHING_TIMEOUT);
Prabir Pradhanedd96402022-02-15 01:46:16 -08009095 mFakePolicy->assertNotifyWindowUnresponsiveWasCalled(timeout, mWindow);
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009096}
9097
Prabir Pradhan1376fcd2022-01-21 09:56:35 -08009098// A spy window can receive an ANR
9099TEST_F(InputDispatcherSingleWindowAnr, SpyWindowAnr) {
9100 sp<FakeWindowHandle> spy = addSpyWindow();
9101
9102 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07009103 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
Prabir Pradhan1376fcd2022-01-21 09:56:35 -08009104 WINDOW_LOCATION));
9105 mWindow->consumeMotionDown();
9106
Siarhei Vishniakoud3061ab2023-12-18 20:41:08 -08009107 const auto [sequenceNum, _] = spy->receiveEvent(); // ACTION_DOWN
Prabir Pradhan1376fcd2022-01-21 09:56:35 -08009108 ASSERT_TRUE(sequenceNum);
9109 const std::chrono::duration timeout = spy->getDispatchingTimeout(DISPATCHING_TIMEOUT);
Prabir Pradhanedd96402022-02-15 01:46:16 -08009110 mFakePolicy->assertNotifyWindowUnresponsiveWasCalled(timeout, spy);
Prabir Pradhan1376fcd2022-01-21 09:56:35 -08009111
9112 spy->finishEvent(*sequenceNum);
Siarhei Vishniakou1ae72f12023-01-29 12:55:30 -08009113 spy->consumeMotionEvent(
9114 AllOf(WithMotionAction(ACTION_CANCEL), WithDisplayId(ADISPLAY_ID_DEFAULT)));
Prabir Pradhan1376fcd2022-01-21 09:56:35 -08009115 ASSERT_TRUE(mDispatcher->waitForIdle());
Prabir Pradhanedd96402022-02-15 01:46:16 -08009116 mFakePolicy->assertNotifyWindowResponsiveWasCalled(spy->getToken(), mWindow->getPid());
Prabir Pradhan1376fcd2022-01-21 09:56:35 -08009117}
9118
9119// If an app is not responding to a key event, spy windows should continue to receive
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009120// new motion events
Prabir Pradhan1376fcd2022-01-21 09:56:35 -08009121TEST_F(InputDispatcherSingleWindowAnr, SpyWindowReceivesEventsDuringAppAnrOnKey) {
9122 sp<FakeWindowHandle> spy = addSpyWindow();
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009123
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08009124 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07009125 injectKeyDown(*mDispatcher, ADISPLAY_ID_DEFAULT));
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009126 mWindow->consumeKeyDown(ADISPLAY_ID_DEFAULT);
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07009127 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectKeyUp(*mDispatcher, ADISPLAY_ID_DEFAULT));
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009128
9129 // Stuck on the ACTION_UP
9130 const std::chrono::duration timeout = mWindow->getDispatchingTimeout(DISPATCHING_TIMEOUT);
Prabir Pradhanedd96402022-02-15 01:46:16 -08009131 mFakePolicy->assertNotifyWindowUnresponsiveWasCalled(timeout, mWindow);
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009132
Prabir Pradhan1376fcd2022-01-21 09:56:35 -08009133 // New tap will go to the spy window, but not to the window
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009134 tapOnWindow();
Prabir Pradhan1376fcd2022-01-21 09:56:35 -08009135 spy->consumeMotionDown(ADISPLAY_ID_DEFAULT);
9136 spy->consumeMotionUp(ADISPLAY_ID_DEFAULT);
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009137
9138 mWindow->consumeKeyUp(ADISPLAY_ID_DEFAULT); // still the previous motion
9139 mDispatcher->waitForIdle();
Prabir Pradhanedd96402022-02-15 01:46:16 -08009140 mFakePolicy->assertNotifyWindowResponsiveWasCalled(mWindow->getToken(), mWindow->getPid());
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009141 mWindow->assertNoEvents();
Prabir Pradhan1376fcd2022-01-21 09:56:35 -08009142 spy->assertNoEvents();
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009143}
9144
Prabir Pradhan1376fcd2022-01-21 09:56:35 -08009145// If an app is not responding to a motion event, spy windows should continue to receive
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009146// new motion events
Prabir Pradhan1376fcd2022-01-21 09:56:35 -08009147TEST_F(InputDispatcherSingleWindowAnr, SpyWindowReceivesEventsDuringAppAnrOnMotion) {
9148 sp<FakeWindowHandle> spy = addSpyWindow();
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009149
9150 tapOnWindow();
Prabir Pradhan1376fcd2022-01-21 09:56:35 -08009151 spy->consumeMotionDown(ADISPLAY_ID_DEFAULT);
9152 spy->consumeMotionUp(ADISPLAY_ID_DEFAULT);
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009153
9154 mWindow->consumeMotionDown();
9155 // Stuck on the ACTION_UP
9156 const std::chrono::duration timeout = mWindow->getDispatchingTimeout(DISPATCHING_TIMEOUT);
Prabir Pradhanedd96402022-02-15 01:46:16 -08009157 mFakePolicy->assertNotifyWindowUnresponsiveWasCalled(timeout, mWindow);
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009158
Prabir Pradhan1376fcd2022-01-21 09:56:35 -08009159 // New tap will go to the spy window, but not to the window
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009160 tapOnWindow();
Prabir Pradhan1376fcd2022-01-21 09:56:35 -08009161 spy->consumeMotionDown(ADISPLAY_ID_DEFAULT);
9162 spy->consumeMotionUp(ADISPLAY_ID_DEFAULT);
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009163
9164 mWindow->consumeMotionUp(ADISPLAY_ID_DEFAULT); // still the previous motion
9165 mDispatcher->waitForIdle();
Prabir Pradhanedd96402022-02-15 01:46:16 -08009166 mFakePolicy->assertNotifyWindowResponsiveWasCalled(mWindow->getToken(), mWindow->getPid());
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009167 mWindow->assertNoEvents();
Prabir Pradhan1376fcd2022-01-21 09:56:35 -08009168 spy->assertNoEvents();
9169}
9170
9171TEST_F(InputDispatcherSingleWindowAnr, UnresponsiveMonitorAnr) {
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07009172 mDispatcher->setMonitorDispatchingTimeoutForTest(SPY_TIMEOUT);
Prabir Pradhan1376fcd2022-01-21 09:56:35 -08009173
Prabir Pradhanfb549072023-10-05 19:17:36 +00009174 FakeMonitorReceiver monitor = FakeMonitorReceiver(*mDispatcher, "M_1", ADISPLAY_ID_DEFAULT);
Prabir Pradhan1376fcd2022-01-21 09:56:35 -08009175
9176 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07009177 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
Prabir Pradhan1376fcd2022-01-21 09:56:35 -08009178 WINDOW_LOCATION));
9179
9180 mWindow->consumeMotionDown(ADISPLAY_ID_DEFAULT);
9181 const std::optional<uint32_t> consumeSeq = monitor.receiveEvent();
9182 ASSERT_TRUE(consumeSeq);
9183
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07009184 mFakePolicy->assertNotifyWindowUnresponsiveWasCalled(SPY_TIMEOUT, monitor.getToken(),
9185 MONITOR_PID);
Prabir Pradhan1376fcd2022-01-21 09:56:35 -08009186
9187 monitor.finishEvent(*consumeSeq);
9188 monitor.consumeMotionCancel(ADISPLAY_ID_DEFAULT);
9189
9190 ASSERT_TRUE(mDispatcher->waitForIdle());
Prabir Pradhanedd96402022-02-15 01:46:16 -08009191 mFakePolicy->assertNotifyWindowResponsiveWasCalled(monitor.getToken(), MONITOR_PID);
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009192}
9193
9194// If a window is unresponsive, then you get anr. if the window later catches up and starts to
9195// process events, you don't get an anr. When the window later becomes unresponsive again, you
9196// get an ANR again.
9197// 1. tap -> block on ACTION_UP -> receive ANR
9198// 2. consume all pending events (= queue becomes healthy again)
9199// 3. tap again -> block on ACTION_UP again -> receive ANR second time
9200TEST_F(InputDispatcherSingleWindowAnr, SameWindow_CanReceiveAnrTwice) {
9201 tapOnWindow();
9202
9203 mWindow->consumeMotionDown();
9204 // Block on ACTION_UP
9205 const std::chrono::duration timeout = mWindow->getDispatchingTimeout(DISPATCHING_TIMEOUT);
Prabir Pradhanedd96402022-02-15 01:46:16 -08009206 mFakePolicy->assertNotifyWindowUnresponsiveWasCalled(timeout, mWindow);
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009207 mWindow->consumeMotionUp(); // Now the connection should be healthy again
9208 mDispatcher->waitForIdle();
Prabir Pradhanedd96402022-02-15 01:46:16 -08009209 mFakePolicy->assertNotifyWindowResponsiveWasCalled(mWindow->getToken(), mWindow->getPid());
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009210 mWindow->assertNoEvents();
9211
9212 tapOnWindow();
9213 mWindow->consumeMotionDown();
Prabir Pradhanedd96402022-02-15 01:46:16 -08009214 mFakePolicy->assertNotifyWindowUnresponsiveWasCalled(timeout, mWindow);
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009215 mWindow->consumeMotionUp();
9216
9217 mDispatcher->waitForIdle();
Prabir Pradhanedd96402022-02-15 01:46:16 -08009218 mFakePolicy->assertNotifyWindowResponsiveWasCalled(mWindow->getToken(), mWindow->getPid());
Siarhei Vishniakou234129c2020-10-22 22:28:12 -05009219 mFakePolicy->assertNotifyAnrWasNotCalled();
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009220 mWindow->assertNoEvents();
9221}
9222
Siarhei Vishniakou234129c2020-10-22 22:28:12 -05009223// If a connection remains unresponsive for a while, make sure policy is only notified once about
9224// it.
9225TEST_F(InputDispatcherSingleWindowAnr, Policy_DoesNotGetDuplicateAnr) {
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08009226 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07009227 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009228 WINDOW_LOCATION));
9229
9230 const std::chrono::duration windowTimeout = mWindow->getDispatchingTimeout(DISPATCHING_TIMEOUT);
Prabir Pradhanedd96402022-02-15 01:46:16 -08009231 mFakePolicy->assertNotifyWindowUnresponsiveWasCalled(windowTimeout, mWindow);
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009232 std::this_thread::sleep_for(windowTimeout);
Siarhei Vishniakou234129c2020-10-22 22:28:12 -05009233 // 'notifyConnectionUnresponsive' should only be called once per connection
9234 mFakePolicy->assertNotifyAnrWasNotCalled();
9235 // When the ANR happened, dispatcher should abort the current event stream via ACTION_CANCEL
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009236 mWindow->consumeMotionDown();
Siarhei Vishniakou1ae72f12023-01-29 12:55:30 -08009237 mWindow->consumeMotionEvent(
9238 AllOf(WithMotionAction(ACTION_CANCEL), WithDisplayId(ADISPLAY_ID_DEFAULT)));
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009239 mWindow->assertNoEvents();
Siarhei Vishniakou234129c2020-10-22 22:28:12 -05009240 mDispatcher->waitForIdle();
Prabir Pradhanedd96402022-02-15 01:46:16 -08009241 mFakePolicy->assertNotifyWindowResponsiveWasCalled(mWindow->getToken(), mWindow->getPid());
Siarhei Vishniakou234129c2020-10-22 22:28:12 -05009242 mFakePolicy->assertNotifyAnrWasNotCalled();
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009243}
9244
9245/**
9246 * 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 -07009247 * not get delivered to the focused window until the motion is processed.
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009248 */
9249TEST_F(InputDispatcherSingleWindowAnr, Key_StaysPendingWhileMotionIsProcessed) {
Siarhei Vishniakouef2b4502023-12-28 11:51:47 -08009250 // The timeouts in this test are established by relying on the fact that the "key waiting for
9251 // events timeout" is equal to 500ms.
9252 ASSERT_EQ(mFakePolicy->getKeyWaitingForEventsTimeout(), 500ms);
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009253 mWindow->setDispatchingTimeout(2s); // Set a long ANR timeout to prevent it from triggering
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07009254 mDispatcher->onWindowInfosChanged({{*mWindow->getInfo()}, {}, 0, 0});
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009255
9256 tapOnWindow();
Siarhei Vishniakoud3061ab2023-12-18 20:41:08 -08009257 const auto& [downSequenceNum, downEvent] = mWindow->receiveEvent();
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009258 ASSERT_TRUE(downSequenceNum);
Siarhei Vishniakoud3061ab2023-12-18 20:41:08 -08009259 const auto& [upSequenceNum, upEvent] = mWindow->receiveEvent();
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009260 ASSERT_TRUE(upSequenceNum);
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009261
Siarhei Vishniakouef2b4502023-12-28 11:51:47 -08009262 // Don't finish the events yet, and send a key
9263 mDispatcher->notifyKey(
9264 KeyArgsBuilder(AKEY_EVENT_ACTION_DOWN, AINPUT_SOURCE_KEYBOARD)
9265 .policyFlags(DEFAULT_POLICY_FLAGS | POLICY_FLAG_DISABLE_KEY_REPEAT)
9266 .build());
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009267 // Key will not be sent to the window, yet, because the window is still processing events
9268 // and the key remains pending, waiting for the touch events to be processed
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07009269 // Make sure that `assertNoEvents` doesn't wait too long, because it could cause an ANR.
Siarhei Vishniakouef2b4502023-12-28 11:51:47 -08009270 mWindow->assertNoEvents(100ms);
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009271
Siarhei Vishniakouef2b4502023-12-28 11:51:47 -08009272 std::this_thread::sleep_for(400ms);
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009273 // if we wait long enough though, dispatcher will give up, and still send the key
9274 // to the focused window, even though we have not yet finished the motion event
9275 mWindow->consumeKeyDown(ADISPLAY_ID_DEFAULT);
9276 mWindow->finishEvent(*downSequenceNum);
9277 mWindow->finishEvent(*upSequenceNum);
9278}
9279
9280/**
9281 * If a window is processing a motion event, and then a key event comes in, the key event should
9282 * not go to the focused window until the motion is processed.
9283 * If then a new motion comes in, then the pending key event should be going to the currently
9284 * focused window right away.
9285 */
9286TEST_F(InputDispatcherSingleWindowAnr,
Siarhei Vishniakouef2b4502023-12-28 11:51:47 -08009287 PendingKey_IsDeliveredWhileMotionIsProcessingAndNewTouchComesIn) {
9288 // The timeouts in this test are established by relying on the fact that the "key waiting for
9289 // events timeout" is equal to 500ms.
9290 ASSERT_EQ(mFakePolicy->getKeyWaitingForEventsTimeout(), 500ms);
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009291 mWindow->setDispatchingTimeout(2s); // Set a long ANR timeout to prevent it from triggering
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07009292 mDispatcher->onWindowInfosChanged({{*mWindow->getInfo()}, {}, 0, 0});
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009293
9294 tapOnWindow();
Siarhei Vishniakoud3061ab2023-12-18 20:41:08 -08009295 const auto& [downSequenceNum, _] = mWindow->receiveEvent();
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009296 ASSERT_TRUE(downSequenceNum);
Siarhei Vishniakoud3061ab2023-12-18 20:41:08 -08009297 const auto& [upSequenceNum, upEvent] = mWindow->receiveEvent();
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009298 ASSERT_TRUE(upSequenceNum);
9299 // Don't finish the events yet, and send a key
Siarhei Vishniakou67bf2162023-11-16 13:29:50 -08009300 mDispatcher->notifyKey(
9301 KeyArgsBuilder(AKEY_EVENT_ACTION_DOWN, AINPUT_SOURCE_KEYBOARD)
9302 .policyFlags(DEFAULT_POLICY_FLAGS | POLICY_FLAG_DISABLE_KEY_REPEAT)
9303 .build());
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009304 // At this point, key is still pending, and should not be sent to the application yet.
Siarhei Vishniakouef2b4502023-12-28 11:51:47 -08009305 mWindow->assertNoEvents(100ms);
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009306
9307 // Now tap down again. It should cause the pending key to go to the focused window right away.
9308 tapOnWindow();
Siarhei Vishniakouef2b4502023-12-28 11:51:47 -08009309 // Now that we tapped, we should receive the key immediately.
9310 // Since there's still room for slowness, we use 200ms, which is much less than
9311 // the "key waiting for events' timeout of 500ms minus the already waited 100ms duration.
9312 std::unique_ptr<InputEvent> keyEvent = mWindow->consume(200ms);
9313 ASSERT_NE(nullptr, keyEvent);
9314 ASSERT_EQ(InputEventType::KEY, keyEvent->getType());
9315 ASSERT_THAT(static_cast<KeyEvent&>(*keyEvent), WithKeyAction(AKEY_EVENT_ACTION_DOWN));
9316 // it doesn't matter that we haven't ack'd the other events yet. We can finish events in any
9317 // order.
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009318 mWindow->finishEvent(*downSequenceNum); // first tap's ACTION_DOWN
9319 mWindow->finishEvent(*upSequenceNum); // first tap's ACTION_UP
Siarhei Vishniakou67bf2162023-11-16 13:29:50 -08009320 mWindow->consumeMotionEvent(WithMotionAction(ACTION_DOWN));
9321 mWindow->consumeMotionEvent(WithMotionAction(ACTION_UP));
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009322 mWindow->assertNoEvents();
9323}
9324
Siarhei Vishniakouadb9fc92023-05-26 10:46:09 -07009325/**
9326 * Send an event to the app and have the app not respond right away.
9327 * When ANR is raised, policy will tell the dispatcher to cancel the events for that window.
9328 * So InputDispatcher will enqueue ACTION_CANCEL event as well.
9329 * At some point, the window becomes responsive again.
9330 * Ensure that subsequent events get dropped, and the next gesture is delivered.
9331 */
9332TEST_F(InputDispatcherSingleWindowAnr, TwoGesturesWithAnr) {
9333 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
9334 .pointer(PointerBuilder(0, ToolType::FINGER).x(10).y(10))
9335 .build());
9336
Siarhei Vishniakoud3061ab2023-12-18 20:41:08 -08009337 const auto [sequenceNum, _] = mWindow->receiveEvent(); // ACTION_DOWN
Siarhei Vishniakouadb9fc92023-05-26 10:46:09 -07009338 ASSERT_TRUE(sequenceNum);
9339 const std::chrono::duration timeout = mWindow->getDispatchingTimeout(DISPATCHING_TIMEOUT);
9340 mFakePolicy->assertNotifyWindowUnresponsiveWasCalled(timeout, mWindow);
9341
9342 mWindow->finishEvent(*sequenceNum);
9343 mWindow->consumeMotionEvent(WithMotionAction(ACTION_CANCEL));
9344 ASSERT_TRUE(mDispatcher->waitForIdle());
9345 mFakePolicy->assertNotifyWindowResponsiveWasCalled(mWindow->getToken(), mWindow->getPid());
9346
9347 // Now that the window is responsive, let's continue the gesture.
9348 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN)
9349 .pointer(PointerBuilder(0, ToolType::FINGER).x(11).y(11))
9350 .build());
9351
9352 mDispatcher->notifyMotion(MotionArgsBuilder(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
9353 .pointer(PointerBuilder(0, ToolType::FINGER).x(11).y(11))
9354 .pointer(PointerBuilder(1, ToolType::FINGER).x(3).y(3))
9355 .build());
9356
9357 mDispatcher->notifyMotion(MotionArgsBuilder(POINTER_1_UP, AINPUT_SOURCE_TOUCHSCREEN)
9358 .pointer(PointerBuilder(0, ToolType::FINGER).x(11).y(11))
9359 .pointer(PointerBuilder(1, ToolType::FINGER).x(3).y(3))
9360 .build());
9361 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN)
9362 .pointer(PointerBuilder(0, ToolType::FINGER).x(11).y(11))
9363 .build());
9364 // We already canceled this pointer, so the window shouldn't get any new events.
9365 mWindow->assertNoEvents();
9366
9367 // Start another one.
9368 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
9369 .pointer(PointerBuilder(0, ToolType::FINGER).x(15).y(15))
9370 .build());
9371 mWindow->consumeMotionEvent(WithMotionAction(ACTION_DOWN));
9372}
9373
Prabir Pradhanfc364722024-02-08 17:51:20 +00009374// Send an event to the app and have the app not respond right away. Then remove the app window.
9375// When the window is removed, the dispatcher will cancel the events for that window.
9376// So InputDispatcher will enqueue ACTION_CANCEL event as well.
9377TEST_F(InputDispatcherSingleWindowAnr, AnrAfterWindowRemoval) {
9378 mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_DOWN,
9379 AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
9380 {WINDOW_LOCATION}));
9381
9382 const auto [sequenceNum, _] = mWindow->receiveEvent(); // ACTION_DOWN
9383 ASSERT_TRUE(sequenceNum);
9384
9385 // Remove the window, but the input channel should remain alive.
9386 mDispatcher->onWindowInfosChanged({{}, {}, 0, 0});
9387
9388 const std::chrono::duration timeout = mWindow->getDispatchingTimeout(DISPATCHING_TIMEOUT);
9389 // Since the window was removed, Dispatcher does not know the PID associated with the window
9390 // anymore, so the policy is notified without the PID.
9391 mFakePolicy->assertNotifyWindowUnresponsiveWasCalled(timeout, mWindow->getToken(),
9392 /*pid=*/std::nullopt);
9393
9394 mWindow->finishEvent(*sequenceNum);
9395 // The cancellation was generated when the window was removed, along with the focus event.
9396 mWindow->consumeMotionEvent(
9397 AllOf(WithMotionAction(ACTION_CANCEL), WithDisplayId(ADISPLAY_ID_DEFAULT)));
9398 mWindow->consumeFocusEvent(false);
9399 ASSERT_TRUE(mDispatcher->waitForIdle());
9400 mFakePolicy->assertNotifyWindowResponsiveWasCalled(mWindow->getToken(), /*pid=*/std::nullopt);
9401}
9402
9403// Send an event to the app and have the app not respond right away. Wait for the policy to be
9404// notified of the unresponsive window, then remove the app window.
9405TEST_F(InputDispatcherSingleWindowAnr, AnrFollowedByWindowRemoval) {
9406 mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_DOWN,
9407 AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
9408 {WINDOW_LOCATION}));
9409
9410 const auto [sequenceNum, _] = mWindow->receiveEvent(); // ACTION_DOWN
9411 ASSERT_TRUE(sequenceNum);
9412 const std::chrono::duration timeout = mWindow->getDispatchingTimeout(DISPATCHING_TIMEOUT);
9413 mFakePolicy->assertNotifyWindowUnresponsiveWasCalled(timeout, mWindow);
9414
9415 // Remove the window, but the input channel should remain alive.
9416 mDispatcher->onWindowInfosChanged({{}, {}, 0, 0});
9417
9418 mWindow->finishEvent(*sequenceNum);
9419 // The cancellation was generated during the ANR, and the window lost focus when it was removed.
9420 mWindow->consumeMotionEvent(
9421 AllOf(WithMotionAction(ACTION_CANCEL), WithDisplayId(ADISPLAY_ID_DEFAULT)));
9422 mWindow->consumeFocusEvent(false);
9423 ASSERT_TRUE(mDispatcher->waitForIdle());
9424 // Since the window was removed, Dispatcher does not know the PID associated with the window
9425 // becoming responsive, so the policy is notified without the PID.
9426 mFakePolicy->assertNotifyWindowResponsiveWasCalled(mWindow->getToken(), /*pid=*/std::nullopt);
9427}
9428
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009429class InputDispatcherMultiWindowAnr : public InputDispatcherTest {
9430 virtual void SetUp() override {
9431 InputDispatcherTest::SetUp();
9432
Chris Yea209fde2020-07-22 13:54:51 -07009433 mApplication = std::make_shared<FakeApplicationHandle>();
Siarhei Vishniakouf83c6932023-07-07 17:48:10 -07009434 mApplication->setDispatchingTimeout(100ms);
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07009435 mUnfocusedWindow = sp<FakeWindowHandle>::make(mApplication, mDispatcher, "Unfocused",
9436 ADISPLAY_ID_DEFAULT);
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009437 mUnfocusedWindow->setFrame(Rect(0, 0, 30, 30));
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009438 // Adding FLAG_WATCH_OUTSIDE_TOUCH to receive ACTION_OUTSIDE when another window is tapped
Prabir Pradhan4d5c52f2022-01-31 08:52:10 -08009439 mUnfocusedWindow->setWatchOutsideTouch(true);
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009440
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07009441 mFocusedWindow = sp<FakeWindowHandle>::make(mApplication, mDispatcher, "Focused",
9442 ADISPLAY_ID_DEFAULT);
Siarhei Vishniakouf83c6932023-07-07 17:48:10 -07009443 mFocusedWindow->setDispatchingTimeout(100ms);
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009444 mFocusedWindow->setFrame(Rect(50, 50, 100, 100));
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009445
9446 // Set focused application.
9447 mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, mApplication);
Vishnu Nair47074b82020-08-14 11:54:47 -07009448 mFocusedWindow->setFocusable(true);
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009449
9450 // Expect one focus window exist in display.
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07009451 mDispatcher->onWindowInfosChanged(
9452 {{*mUnfocusedWindow->getInfo(), *mFocusedWindow->getInfo()}, {}, 0, 0});
Vishnu Nair958da932020-08-21 17:12:37 -07009453 setFocusedWindow(mFocusedWindow);
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009454 mFocusedWindow->consumeFocusEvent(true);
9455 }
9456
9457 virtual void TearDown() override {
9458 InputDispatcherTest::TearDown();
9459
9460 mUnfocusedWindow.clear();
9461 mFocusedWindow.clear();
9462 }
9463
9464protected:
Chris Yea209fde2020-07-22 13:54:51 -07009465 std::shared_ptr<FakeApplicationHandle> mApplication;
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009466 sp<FakeWindowHandle> mUnfocusedWindow;
9467 sp<FakeWindowHandle> mFocusedWindow;
9468 static constexpr PointF UNFOCUSED_WINDOW_LOCATION = {20, 20};
9469 static constexpr PointF FOCUSED_WINDOW_LOCATION = {75, 75};
9470 static constexpr PointF LOCATION_OUTSIDE_ALL_WINDOWS = {40, 40};
9471
9472 void tapOnFocusedWindow() { tap(FOCUSED_WINDOW_LOCATION); }
9473
9474 void tapOnUnfocusedWindow() { tap(UNFOCUSED_WINDOW_LOCATION); }
9475
9476private:
9477 void tap(const PointF& location) {
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08009478 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07009479 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009480 location));
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08009481 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07009482 injectMotionUp(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009483 location));
9484 }
9485};
9486
9487// If we have 2 windows that are both unresponsive, the one with the shortest timeout
9488// should be ANR'd first.
9489TEST_F(InputDispatcherMultiWindowAnr, TwoWindows_BothUnresponsive) {
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08009490 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakou2899c552023-07-10 18:20:46 -07009491 injectMotionEvent(*mDispatcher,
9492 MotionEventBuilder(AMOTION_EVENT_ACTION_DOWN,
9493 AINPUT_SOURCE_TOUCHSCREEN)
9494 .pointer(PointerBuilder(0, ToolType::FINGER)
9495 .x(FOCUSED_WINDOW_LOCATION.x)
9496 .y(FOCUSED_WINDOW_LOCATION.y))
9497 .build()));
9498 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
9499 injectMotionEvent(*mDispatcher,
9500 MotionEventBuilder(AMOTION_EVENT_ACTION_UP,
9501 AINPUT_SOURCE_TOUCHSCREEN)
9502 .pointer(PointerBuilder(0, ToolType::FINGER)
9503 .x(FOCUSED_WINDOW_LOCATION.x)
9504 .y(FOCUSED_WINDOW_LOCATION.y))
9505 .build()));
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009506 mFocusedWindow->consumeMotionDown();
Siarhei Vishniakou2899c552023-07-10 18:20:46 -07009507 mFocusedWindow->consumeMotionUp();
Prabir Pradhan7662a8d2023-12-15 01:58:14 +00009508 mUnfocusedWindow->consumeMotionOutside(ADISPLAY_ID_DEFAULT, /*flags=*/0);
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009509 // We consumed all events, so no ANR
9510 ASSERT_TRUE(mDispatcher->waitForIdle());
9511 mFakePolicy->assertNotifyAnrWasNotCalled();
9512
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08009513 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakou2899c552023-07-10 18:20:46 -07009514 injectMotionEvent(*mDispatcher,
9515 MotionEventBuilder(AMOTION_EVENT_ACTION_DOWN,
9516 AINPUT_SOURCE_TOUCHSCREEN)
9517 .pointer(PointerBuilder(0, ToolType::FINGER)
9518 .x(FOCUSED_WINDOW_LOCATION.x)
9519 .y(FOCUSED_WINDOW_LOCATION.y))
9520 .build()));
Siarhei Vishniakoud3061ab2023-12-18 20:41:08 -08009521 const auto [unfocusedSequenceNum, _] = mUnfocusedWindow->receiveEvent();
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009522 ASSERT_TRUE(unfocusedSequenceNum);
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009523
9524 const std::chrono::duration timeout =
9525 mFocusedWindow->getDispatchingTimeout(DISPATCHING_TIMEOUT);
Prabir Pradhanedd96402022-02-15 01:46:16 -08009526 mFakePolicy->assertNotifyWindowUnresponsiveWasCalled(timeout, mFocusedWindow);
Siarhei Vishniakou2899c552023-07-10 18:20:46 -07009527
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009528 mUnfocusedWindow->finishEvent(*unfocusedSequenceNum);
Siarhei Vishniakou234129c2020-10-22 22:28:12 -05009529 mFocusedWindow->consumeMotionDown();
9530 // This cancel is generated because the connection was unresponsive
9531 mFocusedWindow->consumeMotionCancel();
9532 mFocusedWindow->assertNoEvents();
9533 mUnfocusedWindow->assertNoEvents();
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009534 ASSERT_TRUE(mDispatcher->waitForIdle());
Prabir Pradhanedd96402022-02-15 01:46:16 -08009535 mFakePolicy->assertNotifyWindowResponsiveWasCalled(mFocusedWindow->getToken(),
9536 mFocusedWindow->getPid());
Siarhei Vishniakou234129c2020-10-22 22:28:12 -05009537 mFakePolicy->assertNotifyAnrWasNotCalled();
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009538}
9539
9540// If we have 2 windows with identical timeouts that are both unresponsive,
9541// it doesn't matter which order they should have ANR.
9542// But we should receive ANR for both.
9543TEST_F(InputDispatcherMultiWindowAnr, TwoWindows_BothUnresponsiveWithSameTimeout) {
9544 // Set the timeout for unfocused window to match the focused window
Siarhei Vishniakouf83c6932023-07-07 17:48:10 -07009545 mUnfocusedWindow->setDispatchingTimeout(
9546 mFocusedWindow->getDispatchingTimeout(DISPATCHING_TIMEOUT));
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07009547 mDispatcher->onWindowInfosChanged(
9548 {{*mUnfocusedWindow->getInfo(), *mFocusedWindow->getInfo()}, {}, 0, 0});
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009549
9550 tapOnFocusedWindow();
9551 // we should have ACTION_DOWN/ACTION_UP on focused window and ACTION_OUTSIDE on unfocused window
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009552 // We don't know which window will ANR first. But both of them should happen eventually.
Siarhei Vishniakouf83c6932023-07-07 17:48:10 -07009553 std::array<sp<IBinder>, 2> anrConnectionTokens = {mFakePolicy->getUnresponsiveWindowToken(
9554 mFocusedWindow->getDispatchingTimeout(
9555 DISPATCHING_TIMEOUT)),
9556 mFakePolicy->getUnresponsiveWindowToken(0ms)};
9557
9558 ASSERT_THAT(anrConnectionTokens,
9559 ::testing::UnorderedElementsAre(testing::Eq(mFocusedWindow->getToken()),
9560 testing::Eq(mUnfocusedWindow->getToken())));
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009561
9562 ASSERT_TRUE(mDispatcher->waitForIdle());
9563 mFakePolicy->assertNotifyAnrWasNotCalled();
Siarhei Vishniakou234129c2020-10-22 22:28:12 -05009564
9565 mFocusedWindow->consumeMotionDown();
9566 mFocusedWindow->consumeMotionUp();
9567 mUnfocusedWindow->consumeMotionOutside();
9568
Siarhei Vishniakouf83c6932023-07-07 17:48:10 -07009569 std::array<sp<IBinder>, 2> responsiveTokens = {mFakePolicy->getResponsiveWindowToken(),
9570 mFakePolicy->getResponsiveWindowToken()};
Siarhei Vishniakou234129c2020-10-22 22:28:12 -05009571
9572 // Both applications should be marked as responsive, in any order
Siarhei Vishniakouf83c6932023-07-07 17:48:10 -07009573 ASSERT_THAT(responsiveTokens,
9574 ::testing::UnorderedElementsAre(testing::Eq(mFocusedWindow->getToken()),
9575 testing::Eq(mUnfocusedWindow->getToken())));
Siarhei Vishniakou234129c2020-10-22 22:28:12 -05009576 mFakePolicy->assertNotifyAnrWasNotCalled();
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009577}
9578
9579// If a window is already not responding, the second tap on the same window should be ignored.
9580// We should also log an error to account for the dropped event (not tested here).
9581// At the same time, FLAG_WATCH_OUTSIDE_TOUCH targets should not receive any events.
9582TEST_F(InputDispatcherMultiWindowAnr, DuringAnr_SecondTapIsIgnored) {
9583 tapOnFocusedWindow();
Prabir Pradhan7662a8d2023-12-15 01:58:14 +00009584 mUnfocusedWindow->consumeMotionOutside(ADISPLAY_ID_DEFAULT, /*flags=*/0);
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009585 // Receive the events, but don't respond
Siarhei Vishniakoud3061ab2023-12-18 20:41:08 -08009586 const auto [downEventSequenceNum, downEvent] = mFocusedWindow->receiveEvent(); // ACTION_DOWN
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009587 ASSERT_TRUE(downEventSequenceNum);
Siarhei Vishniakoud3061ab2023-12-18 20:41:08 -08009588 const auto [upEventSequenceNum, upEvent] = mFocusedWindow->receiveEvent(); // ACTION_UP
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009589 ASSERT_TRUE(upEventSequenceNum);
9590 const std::chrono::duration timeout =
9591 mFocusedWindow->getDispatchingTimeout(DISPATCHING_TIMEOUT);
Prabir Pradhanedd96402022-02-15 01:46:16 -08009592 mFakePolicy->assertNotifyWindowUnresponsiveWasCalled(timeout, mFocusedWindow);
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009593
9594 // Tap once again
9595 // We cannot use "tapOnFocusedWindow" because it asserts the injection result to be success
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08009596 ASSERT_EQ(InputEventInjectionResult::FAILED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07009597 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009598 FOCUSED_WINDOW_LOCATION));
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08009599 ASSERT_EQ(InputEventInjectionResult::FAILED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07009600 injectMotionUp(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009601 FOCUSED_WINDOW_LOCATION));
9602 // Unfocused window does not receive ACTION_OUTSIDE because the tapped window is not a
9603 // valid touch target
9604 mUnfocusedWindow->assertNoEvents();
9605
9606 // Consume the first tap
9607 mFocusedWindow->finishEvent(*downEventSequenceNum);
9608 mFocusedWindow->finishEvent(*upEventSequenceNum);
9609 ASSERT_TRUE(mDispatcher->waitForIdle());
9610 // The second tap did not go to the focused window
9611 mFocusedWindow->assertNoEvents();
Siarhei Vishniakou234129c2020-10-22 22:28:12 -05009612 // Since all events are finished, connection should be deemed healthy again
Prabir Pradhanedd96402022-02-15 01:46:16 -08009613 mFakePolicy->assertNotifyWindowResponsiveWasCalled(mFocusedWindow->getToken(),
9614 mFocusedWindow->getPid());
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009615 mFakePolicy->assertNotifyAnrWasNotCalled();
9616}
9617
9618// If you tap outside of all windows, there will not be ANR
9619TEST_F(InputDispatcherMultiWindowAnr, TapOutsideAllWindows_DoesNotAnr) {
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08009620 ASSERT_EQ(InputEventInjectionResult::FAILED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07009621 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009622 LOCATION_OUTSIDE_ALL_WINDOWS));
9623 ASSERT_TRUE(mDispatcher->waitForIdle());
9624 mFakePolicy->assertNotifyAnrWasNotCalled();
9625}
9626
9627// Since the focused window is paused, tapping on it should not produce any events
9628TEST_F(InputDispatcherMultiWindowAnr, Window_CanBePaused) {
9629 mFocusedWindow->setPaused(true);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07009630 mDispatcher->onWindowInfosChanged(
9631 {{*mUnfocusedWindow->getInfo(), *mFocusedWindow->getInfo()}, {}, 0, 0});
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009632
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08009633 ASSERT_EQ(InputEventInjectionResult::FAILED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07009634 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009635 FOCUSED_WINDOW_LOCATION));
9636
9637 std::this_thread::sleep_for(mFocusedWindow->getDispatchingTimeout(DISPATCHING_TIMEOUT));
9638 ASSERT_TRUE(mDispatcher->waitForIdle());
9639 // Should not ANR because the window is paused, and touches shouldn't go to it
9640 mFakePolicy->assertNotifyAnrWasNotCalled();
9641
9642 mFocusedWindow->assertNoEvents();
9643 mUnfocusedWindow->assertNoEvents();
9644}
9645
9646/**
9647 * 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 -07009648 * not get delivered to the focused window until the motion is processed.
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009649 * If a different window becomes focused at this time, the key should go to that window instead.
9650 *
9651 * Warning!!!
9652 * This test depends on the value of android::inputdispatcher::KEY_WAITING_FOR_MOTION_TIMEOUT
9653 * and the injection timeout that we specify when injecting the key.
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07009654 * We must have the injection timeout (100ms) be smaller than
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009655 * KEY_WAITING_FOR_MOTION_TIMEOUT (currently 500ms).
9656 *
9657 * If that value changes, this test should also change.
9658 */
9659TEST_F(InputDispatcherMultiWindowAnr, PendingKey_GoesToNewlyFocusedWindow) {
9660 // Set a long ANR timeout to prevent it from triggering
9661 mFocusedWindow->setDispatchingTimeout(2s);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07009662 mDispatcher->onWindowInfosChanged(
9663 {{*mFocusedWindow->getInfo(), *mUnfocusedWindow->getInfo()}, {}, 0, 0});
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009664
9665 tapOnUnfocusedWindow();
Siarhei Vishniakoud3061ab2023-12-18 20:41:08 -08009666 const auto [downSequenceNum, downEvent] = mUnfocusedWindow->receiveEvent();
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009667 ASSERT_TRUE(downSequenceNum);
Siarhei Vishniakoud3061ab2023-12-18 20:41:08 -08009668 const auto [upSequenceNum, upEvent] = mUnfocusedWindow->receiveEvent();
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009669 ASSERT_TRUE(upSequenceNum);
9670 // Don't finish the events yet, and send a key
9671 // Injection will succeed because we will eventually give up and send the key to the focused
9672 // window even if motions are still being processed.
9673
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08009674 InputEventInjectionResult result =
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07009675 injectKey(*mDispatcher, AKEY_EVENT_ACTION_DOWN, /*repeatCount=*/0, ADISPLAY_ID_DEFAULT,
9676 InputEventInjectionSync::NONE, /*injectionTimeout=*/100ms);
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08009677 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, result);
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009678 // Key will not be sent to the window, yet, because the window is still processing events
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07009679 // and the key remains pending, waiting for the touch events to be processed.
9680 // Make sure `assertNoEvents` doesn't take too long. It uses CONSUME_TIMEOUT_NO_EVENT_EXPECTED
9681 // under the hood.
9682 static_assert(CONSUME_TIMEOUT_NO_EVENT_EXPECTED < 100ms);
9683 mFocusedWindow->assertNoEvents();
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009684
9685 // Switch the focus to the "unfocused" window that we tapped. Expect the key to go there
Vishnu Nair47074b82020-08-14 11:54:47 -07009686 mFocusedWindow->setFocusable(false);
9687 mUnfocusedWindow->setFocusable(true);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07009688 mDispatcher->onWindowInfosChanged(
9689 {{*mFocusedWindow->getInfo(), *mUnfocusedWindow->getInfo()}, {}, 0, 0});
Vishnu Nair958da932020-08-21 17:12:37 -07009690 setFocusedWindow(mUnfocusedWindow);
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009691
9692 // Focus events should precede the key events
9693 mUnfocusedWindow->consumeFocusEvent(true);
9694 mFocusedWindow->consumeFocusEvent(false);
9695
9696 // Finish the tap events, which should unblock dispatcher
9697 mUnfocusedWindow->finishEvent(*downSequenceNum);
9698 mUnfocusedWindow->finishEvent(*upSequenceNum);
9699
9700 // Now that all queues are cleared and no backlog in the connections, the key event
9701 // can finally go to the newly focused "mUnfocusedWindow".
9702 mUnfocusedWindow->consumeKeyDown(ADISPLAY_ID_DEFAULT);
9703 mFocusedWindow->assertNoEvents();
9704 mUnfocusedWindow->assertNoEvents();
Siarhei Vishniakou234129c2020-10-22 22:28:12 -05009705 mFakePolicy->assertNotifyAnrWasNotCalled();
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009706}
9707
9708// When the touch stream is split across 2 windows, and one of them does not respond,
9709// then ANR should be raised and the touch should be canceled for the unresponsive window.
9710// The other window should not be affected by that.
9711TEST_F(InputDispatcherMultiWindowAnr, SplitTouch_SingleWindowAnr) {
9712 // Touch Window 1
Prabir Pradhan678438e2023-04-13 19:32:51 +00009713 mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_DOWN,
9714 AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
9715 {FOCUSED_WINDOW_LOCATION}));
Prabir Pradhan7662a8d2023-12-15 01:58:14 +00009716 mUnfocusedWindow->consumeMotionOutside(ADISPLAY_ID_DEFAULT, /*flags=*/0);
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009717
9718 // Touch Window 2
Prabir Pradhan678438e2023-04-13 19:32:51 +00009719 mDispatcher->notifyMotion(
9720 generateMotionArgs(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
9721 {FOCUSED_WINDOW_LOCATION, UNFOCUSED_WINDOW_LOCATION}));
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009722
9723 const std::chrono::duration timeout =
9724 mFocusedWindow->getDispatchingTimeout(DISPATCHING_TIMEOUT);
Prabir Pradhanedd96402022-02-15 01:46:16 -08009725 mFakePolicy->assertNotifyWindowUnresponsiveWasCalled(timeout, mFocusedWindow);
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009726
9727 mUnfocusedWindow->consumeMotionDown();
9728 mFocusedWindow->consumeMotionDown();
9729 // Focused window may or may not receive ACTION_MOVE
9730 // But it should definitely receive ACTION_CANCEL due to the ANR
Siarhei Vishniakoud3061ab2023-12-18 20:41:08 -08009731 const auto [moveOrCancelSequenceNum, event] = mFocusedWindow->receiveEvent();
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009732 ASSERT_TRUE(moveOrCancelSequenceNum);
9733 mFocusedWindow->finishEvent(*moveOrCancelSequenceNum);
9734 ASSERT_NE(nullptr, event);
Siarhei Vishniakou63b63612023-04-12 11:00:23 -07009735 ASSERT_EQ(event->getType(), InputEventType::MOTION);
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009736 MotionEvent& motionEvent = static_cast<MotionEvent&>(*event);
9737 if (motionEvent.getAction() == AMOTION_EVENT_ACTION_MOVE) {
9738 mFocusedWindow->consumeMotionCancel();
9739 } else {
9740 ASSERT_EQ(AMOTION_EVENT_ACTION_CANCEL, motionEvent.getAction());
9741 }
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009742 ASSERT_TRUE(mDispatcher->waitForIdle());
Prabir Pradhanedd96402022-02-15 01:46:16 -08009743 mFakePolicy->assertNotifyWindowResponsiveWasCalled(mFocusedWindow->getToken(),
9744 mFocusedWindow->getPid());
Siarhei Vishniakou234129c2020-10-22 22:28:12 -05009745
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009746 mUnfocusedWindow->assertNoEvents();
9747 mFocusedWindow->assertNoEvents();
Siarhei Vishniakou234129c2020-10-22 22:28:12 -05009748 mFakePolicy->assertNotifyAnrWasNotCalled();
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009749}
9750
Siarhei Vishniakouf56b2692020-09-08 19:43:33 -05009751/**
9752 * If we have no focused window, and a key comes in, we start the ANR timer.
9753 * The focused application should add a focused window before the timer runs out to prevent ANR.
9754 *
9755 * If the user touches another application during this time, the key should be dropped.
9756 * Next, if a new focused window comes in, without toggling the focused application,
9757 * then no ANR should occur.
9758 *
9759 * Normally, we would expect the new focused window to be accompanied by 'setFocusedApplication',
9760 * but in some cases the policy may not update the focused application.
9761 */
9762TEST_F(InputDispatcherMultiWindowAnr, FocusedWindowWithoutSetFocusedApplication_NoAnr) {
9763 std::shared_ptr<FakeApplicationHandle> focusedApplication =
9764 std::make_shared<FakeApplicationHandle>();
Siarhei Vishniakouc033dfb2023-10-03 10:45:16 -07009765 focusedApplication->setDispatchingTimeout(300ms);
Siarhei Vishniakouf56b2692020-09-08 19:43:33 -05009766 mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, focusedApplication);
9767 // The application that owns 'mFocusedWindow' and 'mUnfocusedWindow' is not focused.
9768 mFocusedWindow->setFocusable(false);
9769
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07009770 mDispatcher->onWindowInfosChanged(
9771 {{*mFocusedWindow->getInfo(), *mUnfocusedWindow->getInfo()}, {}, 0, 0});
Siarhei Vishniakouf56b2692020-09-08 19:43:33 -05009772 mFocusedWindow->consumeFocusEvent(false);
9773
9774 // Send a key. The ANR timer should start because there is no focused window.
9775 // 'focusedApplication' will get blamed if this timer completes.
9776 // Key will not be sent anywhere because we have no focused window. It will remain pending.
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08009777 InputEventInjectionResult result =
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07009778 injectKey(*mDispatcher, AKEY_EVENT_ACTION_DOWN, /*repeatCount=*/0, ADISPLAY_ID_DEFAULT,
9779 InputEventInjectionSync::NONE, /*injectionTimeout=*/100ms,
Harry Cutts33476232023-01-30 19:57:29 +00009780 /*allowKeyRepeat=*/false);
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08009781 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, result);
Siarhei Vishniakouf56b2692020-09-08 19:43:33 -05009782
9783 // Wait until dispatcher starts the "no focused window" timer. If we don't wait here,
9784 // then the injected touches won't cause the focused event to get dropped.
9785 // The dispatcher only checks for whether the queue should be pruned upon queueing.
9786 // If we inject the touch right away and the ANR timer hasn't started, the touch event would
9787 // simply be added to the queue without 'shouldPruneInboundQueueLocked' returning 'true'.
9788 // For this test, it means that the key would get delivered to the window once it becomes
9789 // focused.
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07009790 std::this_thread::sleep_for(100ms);
Siarhei Vishniakouf56b2692020-09-08 19:43:33 -05009791
9792 // Touch unfocused window. This should force the pending key to get dropped.
Prabir Pradhan678438e2023-04-13 19:32:51 +00009793 mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_DOWN,
9794 AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
9795 {UNFOCUSED_WINDOW_LOCATION}));
Siarhei Vishniakouf56b2692020-09-08 19:43:33 -05009796
9797 // We do not consume the motion right away, because that would require dispatcher to first
9798 // process (== drop) the key event, and by that time, ANR will be raised.
9799 // Set the focused window first.
9800 mFocusedWindow->setFocusable(true);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07009801 mDispatcher->onWindowInfosChanged(
9802 {{*mFocusedWindow->getInfo(), *mUnfocusedWindow->getInfo()}, {}, 0, 0});
Siarhei Vishniakouf56b2692020-09-08 19:43:33 -05009803 setFocusedWindow(mFocusedWindow);
9804 mFocusedWindow->consumeFocusEvent(true);
9805 // We do not call "setFocusedApplication" here, even though the newly focused window belongs
9806 // to another application. This could be a bug / behaviour in the policy.
9807
9808 mUnfocusedWindow->consumeMotionDown();
9809
9810 ASSERT_TRUE(mDispatcher->waitForIdle());
9811 // Should not ANR because we actually have a focused window. It was just added too slowly.
9812 ASSERT_NO_FATAL_FAILURE(mFakePolicy->assertNotifyAnrWasNotCalled());
9813}
9814
Siarhei Vishniakou99e407b2023-12-26 18:09:32 -08009815/**
9816 * If we are pruning input queue, we should never drop pointer events. Otherwise, we risk having
9817 * an inconsistent event stream inside the dispatcher. In this test, we make sure that the
9818 * dispatcher doesn't prune pointer events incorrectly.
9819 *
9820 * This test reproduces a crash in InputDispatcher.
9821 * To reproduce the crash, we need to simulate the conditions for "pruning input queue" to occur.
9822 *
9823 * Keep the currently focused application (mApplication), and have no focused window.
9824 * We set up two additional windows:
9825 * 1) The navigation bar window. This simulates the system "NavigationBar", which is used in the
9826 * 3-button navigation mode. This window injects a BACK button when it's touched. 2) The application
9827 * window. This window is not focusable, but is touchable.
9828 *
9829 * We first touch the navigation bar, which causes it to inject a key. Since there's no focused
9830 * window, the dispatcher doesn't process this key, and all other events inside dispatcher are now
9831 * blocked. The dispatcher is waiting for 'mApplication' to add a focused window.
9832 *
9833 * Now, we touch "Another window". This window is owned by a different application than
9834 * 'mApplication'. This causes the dispatcher to stop waiting for 'mApplication' to add a focused
9835 * window. Now, the "pruning input queue" behaviour should kick in, and the dispatcher should start
9836 * dropping the events from its queue. Ensure that no crash occurs.
9837 *
9838 * In this test, we are setting long timeouts to prevent ANRs and events dropped due to being stale.
9839 * This does not affect the test running time.
9840 */
9841TEST_F(InputDispatcherMultiWindowAnr, PruningInputQueueShouldNotDropPointerEvents) {
9842 std::shared_ptr<FakeApplicationHandle> systemUiApplication =
9843 std::make_shared<FakeApplicationHandle>();
9844 systemUiApplication->setDispatchingTimeout(3000ms);
9845 mFakePolicy->setStaleEventTimeout(3000ms);
9846 sp<FakeWindowHandle> navigationBar =
9847 sp<FakeWindowHandle>::make(systemUiApplication, mDispatcher, "NavigationBar",
9848 ADISPLAY_ID_DEFAULT);
9849 navigationBar->setFocusable(false);
9850 navigationBar->setWatchOutsideTouch(true);
9851 navigationBar->setFrame(Rect(0, 0, 100, 100));
9852
9853 mApplication->setDispatchingTimeout(3000ms);
9854 // 'mApplication' is already focused, but we call it again here to make it explicit.
9855 mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, mApplication);
9856
9857 std::shared_ptr<FakeApplicationHandle> anotherApplication =
9858 std::make_shared<FakeApplicationHandle>();
9859 sp<FakeWindowHandle> appWindow =
9860 sp<FakeWindowHandle>::make(anotherApplication, mDispatcher, "Another window",
9861 ADISPLAY_ID_DEFAULT);
9862 appWindow->setFocusable(false);
9863 appWindow->setFrame(Rect(100, 100, 200, 200));
9864
9865 mDispatcher->onWindowInfosChanged(
9866 {{*navigationBar->getInfo(), *appWindow->getInfo()}, {}, 0, 0});
9867 // 'mFocusedWindow' is no longer in the dispatcher window list, and therefore loses focus
9868 mFocusedWindow->consumeFocusEvent(false);
9869
9870 // Touch down the navigation bar. It consumes the touch and injects a key into the dispatcher
9871 // in response.
9872 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
9873 .pointer(PointerBuilder(0, ToolType::FINGER).x(50).y(50))
9874 .build());
9875 navigationBar->consumeMotionEvent(WithMotionAction(ACTION_DOWN));
9876
9877 // Key will not be sent anywhere because we have no focused window. It will remain pending.
9878 // Pretend we are injecting KEYCODE_BACK, but it doesn't actually matter what key it is.
9879 InputEventInjectionResult result =
9880 injectKey(*mDispatcher, AKEY_EVENT_ACTION_DOWN, /*repeatCount=*/0, ADISPLAY_ID_DEFAULT,
9881 InputEventInjectionSync::NONE, /*injectionTimeout=*/100ms,
9882 /*allowKeyRepeat=*/false);
9883 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, result);
9884
9885 // Finish the gesture - lift up finger and inject ACTION_UP key event
9886 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN)
9887 .pointer(PointerBuilder(0, ToolType::FINGER).x(50).y(50))
9888 .build());
9889 result = injectKey(*mDispatcher, AKEY_EVENT_ACTION_UP, /*repeatCount=*/0, ADISPLAY_ID_DEFAULT,
9890 InputEventInjectionSync::NONE, /*injectionTimeout=*/100ms,
9891 /*allowKeyRepeat=*/false);
9892 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, result);
9893 // The key that was injected is blocking the dispatcher, so the navigation bar shouldn't be
9894 // getting any events yet.
9895 navigationBar->assertNoEvents();
9896
9897 // Now touch "Another window". This touch is going to a different application than the one we
9898 // are waiting for (which is 'mApplication').
9899 // This should cause the dispatcher to drop the pending focus-dispatched events (like the key
9900 // trying to be injected) and to continue processing the rest of the events in the original
9901 // order.
9902 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
9903 .pointer(PointerBuilder(0, ToolType::FINGER).x(150).y(150))
9904 .build());
9905 navigationBar->consumeMotionEvent(WithMotionAction(ACTION_UP));
9906 navigationBar->consumeMotionEvent(WithMotionAction(ACTION_OUTSIDE));
9907 appWindow->consumeMotionEvent(WithMotionAction(ACTION_DOWN));
9908
9909 appWindow->assertNoEvents();
9910 navigationBar->assertNoEvents();
9911}
9912
Siarhei Vishniakoua2862a02020-07-20 16:36:46 -05009913// These tests ensure we cannot send touch events to a window that's positioned behind a window
9914// that has feature NO_INPUT_CHANNEL.
9915// Layout:
9916// Top (closest to user)
9917// mNoInputWindow (above all windows)
9918// mBottomWindow
9919// Bottom (furthest from user)
9920class InputDispatcherMultiWindowOcclusionTests : public InputDispatcherTest {
9921 virtual void SetUp() override {
9922 InputDispatcherTest::SetUp();
9923
9924 mApplication = std::make_shared<FakeApplicationHandle>();
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07009925 mNoInputWindow =
9926 sp<FakeWindowHandle>::make(mApplication, mDispatcher,
9927 "Window without input channel", ADISPLAY_ID_DEFAULT,
Prabir Pradhane7cc69c2024-01-05 21:35:28 +00009928 /*createInputChannel=*/false);
Prabir Pradhan51e7db02022-02-07 06:02:57 -08009929 mNoInputWindow->setNoInputChannel(true);
Siarhei Vishniakoua2862a02020-07-20 16:36:46 -05009930 mNoInputWindow->setFrame(Rect(0, 0, 100, 100));
9931 // It's perfectly valid for this window to not have an associated input channel
9932
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07009933 mBottomWindow = sp<FakeWindowHandle>::make(mApplication, mDispatcher, "Bottom window",
9934 ADISPLAY_ID_DEFAULT);
Siarhei Vishniakoua2862a02020-07-20 16:36:46 -05009935 mBottomWindow->setFrame(Rect(0, 0, 100, 100));
9936
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07009937 mDispatcher->onWindowInfosChanged(
9938 {{*mNoInputWindow->getInfo(), *mBottomWindow->getInfo()}, {}, 0, 0});
Siarhei Vishniakoua2862a02020-07-20 16:36:46 -05009939 }
9940
9941protected:
9942 std::shared_ptr<FakeApplicationHandle> mApplication;
9943 sp<FakeWindowHandle> mNoInputWindow;
9944 sp<FakeWindowHandle> mBottomWindow;
9945};
9946
9947TEST_F(InputDispatcherMultiWindowOcclusionTests, NoInputChannelFeature_DropsTouches) {
9948 PointF touchedPoint = {10, 10};
9949
Prabir Pradhan678438e2023-04-13 19:32:51 +00009950 mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_DOWN,
9951 AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
9952 {touchedPoint}));
Siarhei Vishniakoua2862a02020-07-20 16:36:46 -05009953
9954 mNoInputWindow->assertNoEvents();
9955 // Even though the window 'mNoInputWindow' positioned above 'mBottomWindow' does not have
9956 // an input channel, it is not marked as FLAG_NOT_TOUCHABLE,
9957 // and therefore should prevent mBottomWindow from receiving touches
9958 mBottomWindow->assertNoEvents();
9959}
9960
9961/**
9962 * If a window has feature NO_INPUT_CHANNEL, and somehow (by mistake) still has an input channel,
9963 * ensure that this window does not receive any touches, and blocks touches to windows underneath.
9964 */
9965TEST_F(InputDispatcherMultiWindowOcclusionTests,
9966 NoInputChannelFeature_DropsTouchesWithValidChannel) {
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07009967 mNoInputWindow = sp<FakeWindowHandle>::make(mApplication, mDispatcher,
9968 "Window with input channel and NO_INPUT_CHANNEL",
9969 ADISPLAY_ID_DEFAULT);
Siarhei Vishniakoua2862a02020-07-20 16:36:46 -05009970
Prabir Pradhan51e7db02022-02-07 06:02:57 -08009971 mNoInputWindow->setNoInputChannel(true);
Siarhei Vishniakoua2862a02020-07-20 16:36:46 -05009972 mNoInputWindow->setFrame(Rect(0, 0, 100, 100));
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07009973 mDispatcher->onWindowInfosChanged(
9974 {{*mNoInputWindow->getInfo(), *mBottomWindow->getInfo()}, {}, 0, 0});
Siarhei Vishniakoua2862a02020-07-20 16:36:46 -05009975
9976 PointF touchedPoint = {10, 10};
9977
Prabir Pradhan678438e2023-04-13 19:32:51 +00009978 mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_DOWN,
9979 AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
9980 {touchedPoint}));
Siarhei Vishniakoua2862a02020-07-20 16:36:46 -05009981
9982 mNoInputWindow->assertNoEvents();
9983 mBottomWindow->assertNoEvents();
9984}
9985
Vishnu Nair958da932020-08-21 17:12:37 -07009986class InputDispatcherMirrorWindowFocusTests : public InputDispatcherTest {
9987protected:
9988 std::shared_ptr<FakeApplicationHandle> mApp;
9989 sp<FakeWindowHandle> mWindow;
9990 sp<FakeWindowHandle> mMirror;
9991
9992 virtual void SetUp() override {
9993 InputDispatcherTest::SetUp();
9994 mApp = std::make_shared<FakeApplicationHandle>();
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07009995 mWindow = sp<FakeWindowHandle>::make(mApp, mDispatcher, "TestWindow", ADISPLAY_ID_DEFAULT);
Prabir Pradhane7cc69c2024-01-05 21:35:28 +00009996 mMirror = mWindow->clone(ADISPLAY_ID_DEFAULT);
Vishnu Nair958da932020-08-21 17:12:37 -07009997 mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, mApp);
9998 mWindow->setFocusable(true);
9999 mMirror->setFocusable(true);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070010000 mDispatcher->onWindowInfosChanged({{*mWindow->getInfo(), *mMirror->getInfo()}, {}, 0, 0});
Vishnu Nair958da932020-08-21 17:12:37 -070010001 }
10002};
10003
10004TEST_F(InputDispatcherMirrorWindowFocusTests, CanGetFocus) {
10005 // Request focus on a mirrored window
10006 setFocusedWindow(mMirror);
10007
10008 // window gets focused
10009 mWindow->consumeFocusEvent(true);
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070010010 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectKeyDown(*mDispatcher))
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -080010011 << "Inject key event should return InputEventInjectionResult::SUCCEEDED";
Vishnu Nair958da932020-08-21 17:12:37 -070010012 mWindow->consumeKeyDown(ADISPLAY_ID_NONE);
10013}
10014
10015// A focused & mirrored window remains focused only if the window and its mirror are both
10016// focusable.
10017TEST_F(InputDispatcherMirrorWindowFocusTests, FocusedIfAllWindowsFocusable) {
10018 setFocusedWindow(mMirror);
10019
Prabir Pradhanbb3f1c02024-01-04 20:17:14 +000010020 // window gets focused because it is above the mirror
Vishnu Nair958da932020-08-21 17:12:37 -070010021 mWindow->consumeFocusEvent(true);
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070010022 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectKeyDown(*mDispatcher))
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -080010023 << "Inject key event should return InputEventInjectionResult::SUCCEEDED";
Vishnu Nair958da932020-08-21 17:12:37 -070010024 mWindow->consumeKeyDown(ADISPLAY_ID_NONE);
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070010025 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectKeyUp(*mDispatcher))
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -080010026 << "Inject key event should return InputEventInjectionResult::SUCCEEDED";
Vishnu Nair958da932020-08-21 17:12:37 -070010027 mWindow->consumeKeyUp(ADISPLAY_ID_NONE);
10028
10029 mMirror->setFocusable(false);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070010030 mDispatcher->onWindowInfosChanged({{*mWindow->getInfo(), *mMirror->getInfo()}, {}, 0, 0});
Vishnu Nair958da932020-08-21 17:12:37 -070010031
10032 // window loses focus since one of the windows associated with the token in not focusable
10033 mWindow->consumeFocusEvent(false);
10034
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070010035 ASSERT_EQ(InputEventInjectionResult::TIMED_OUT, injectKeyDown(*mDispatcher))
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -080010036 << "Inject key event should return InputEventInjectionResult::TIMED_OUT";
Vishnu Nair958da932020-08-21 17:12:37 -070010037 mWindow->assertNoEvents();
10038}
10039
10040// A focused & mirrored window remains focused until the window and its mirror both become
10041// invisible.
10042TEST_F(InputDispatcherMirrorWindowFocusTests, FocusedIfAnyWindowVisible) {
10043 setFocusedWindow(mMirror);
10044
10045 // window gets focused
10046 mWindow->consumeFocusEvent(true);
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070010047 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectKeyDown(*mDispatcher))
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -080010048 << "Inject key event should return InputEventInjectionResult::SUCCEEDED";
Vishnu Nair958da932020-08-21 17:12:37 -070010049 mWindow->consumeKeyDown(ADISPLAY_ID_NONE);
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070010050 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectKeyUp(*mDispatcher))
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -080010051 << "Inject key event should return InputEventInjectionResult::SUCCEEDED";
Vishnu Nair958da932020-08-21 17:12:37 -070010052 mWindow->consumeKeyUp(ADISPLAY_ID_NONE);
10053
10054 mMirror->setVisible(false);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070010055 mDispatcher->onWindowInfosChanged({{*mWindow->getInfo(), *mMirror->getInfo()}, {}, 0, 0});
Vishnu Nair958da932020-08-21 17:12:37 -070010056
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070010057 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectKeyDown(*mDispatcher))
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -080010058 << "Inject key event should return InputEventInjectionResult::SUCCEEDED";
Vishnu Nair958da932020-08-21 17:12:37 -070010059 mWindow->consumeKeyDown(ADISPLAY_ID_NONE);
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070010060 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectKeyUp(*mDispatcher))
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -080010061 << "Inject key event should return InputEventInjectionResult::SUCCEEDED";
Vishnu Nair958da932020-08-21 17:12:37 -070010062 mWindow->consumeKeyUp(ADISPLAY_ID_NONE);
10063
10064 mWindow->setVisible(false);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070010065 mDispatcher->onWindowInfosChanged({{*mWindow->getInfo(), *mMirror->getInfo()}, {}, 0, 0});
Vishnu Nair958da932020-08-21 17:12:37 -070010066
10067 // window loses focus only after all windows associated with the token become invisible.
10068 mWindow->consumeFocusEvent(false);
10069
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070010070 ASSERT_EQ(InputEventInjectionResult::TIMED_OUT, injectKeyDown(*mDispatcher))
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -080010071 << "Inject key event should return InputEventInjectionResult::TIMED_OUT";
Vishnu Nair958da932020-08-21 17:12:37 -070010072 mWindow->assertNoEvents();
10073}
10074
10075// A focused & mirrored window remains focused until both windows are removed.
10076TEST_F(InputDispatcherMirrorWindowFocusTests, FocusedWhileWindowsAlive) {
10077 setFocusedWindow(mMirror);
10078
10079 // window gets focused
10080 mWindow->consumeFocusEvent(true);
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070010081 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectKeyDown(*mDispatcher))
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -080010082 << "Inject key event should return InputEventInjectionResult::SUCCEEDED";
Vishnu Nair958da932020-08-21 17:12:37 -070010083 mWindow->consumeKeyDown(ADISPLAY_ID_NONE);
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070010084 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectKeyUp(*mDispatcher))
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -080010085 << "Inject key event should return InputEventInjectionResult::SUCCEEDED";
Vishnu Nair958da932020-08-21 17:12:37 -070010086 mWindow->consumeKeyUp(ADISPLAY_ID_NONE);
10087
10088 // single window is removed but the window token remains focused
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070010089 mDispatcher->onWindowInfosChanged({{*mMirror->getInfo()}, {}, 0, 0});
Vishnu Nair958da932020-08-21 17:12:37 -070010090
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070010091 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectKeyDown(*mDispatcher))
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -080010092 << "Inject key event should return InputEventInjectionResult::SUCCEEDED";
Prabir Pradhanbb3f1c02024-01-04 20:17:14 +000010093 mMirror->consumeKeyDown(ADISPLAY_ID_NONE);
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070010094 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectKeyUp(*mDispatcher))
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -080010095 << "Inject key event should return InputEventInjectionResult::SUCCEEDED";
Prabir Pradhanbb3f1c02024-01-04 20:17:14 +000010096 mMirror->consumeKeyUp(ADISPLAY_ID_NONE);
Vishnu Nair958da932020-08-21 17:12:37 -070010097
10098 // Both windows are removed
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070010099 mDispatcher->onWindowInfosChanged({{}, {}, 0, 0});
Vishnu Nair958da932020-08-21 17:12:37 -070010100 mWindow->consumeFocusEvent(false);
10101
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070010102 ASSERT_EQ(InputEventInjectionResult::TIMED_OUT, injectKeyDown(*mDispatcher))
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -080010103 << "Inject key event should return InputEventInjectionResult::TIMED_OUT";
Vishnu Nair958da932020-08-21 17:12:37 -070010104 mWindow->assertNoEvents();
10105}
10106
10107// Focus request can be pending until one window becomes visible.
10108TEST_F(InputDispatcherMirrorWindowFocusTests, DeferFocusWhenInvisible) {
10109 // Request focus on an invisible mirror.
10110 mWindow->setVisible(false);
10111 mMirror->setVisible(false);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070010112 mDispatcher->onWindowInfosChanged({{*mWindow->getInfo(), *mMirror->getInfo()}, {}, 0, 0});
Vishnu Nair958da932020-08-21 17:12:37 -070010113 setFocusedWindow(mMirror);
10114
10115 // Injected key goes to pending queue.
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -080010116 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070010117 injectKey(*mDispatcher, AKEY_EVENT_ACTION_DOWN, /*repeatCount=*/0,
10118 ADISPLAY_ID_DEFAULT, InputEventInjectionSync::NONE));
Vishnu Nair958da932020-08-21 17:12:37 -070010119
10120 mMirror->setVisible(true);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070010121 mDispatcher->onWindowInfosChanged({{*mWindow->getInfo(), *mMirror->getInfo()}, {}, 0, 0});
Vishnu Nair958da932020-08-21 17:12:37 -070010122
10123 // window gets focused
10124 mWindow->consumeFocusEvent(true);
10125 // window gets the pending key event
10126 mWindow->consumeKeyDown(ADISPLAY_ID_DEFAULT);
10127}
Prabir Pradhan99987712020-11-10 18:43:05 -080010128
10129class InputDispatcherPointerCaptureTests : public InputDispatcherTest {
10130protected:
10131 std::shared_ptr<FakeApplicationHandle> mApp;
10132 sp<FakeWindowHandle> mWindow;
10133 sp<FakeWindowHandle> mSecondWindow;
10134
10135 void SetUp() override {
10136 InputDispatcherTest::SetUp();
10137 mApp = std::make_shared<FakeApplicationHandle>();
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -070010138 mWindow = sp<FakeWindowHandle>::make(mApp, mDispatcher, "TestWindow", ADISPLAY_ID_DEFAULT);
Prabir Pradhan99987712020-11-10 18:43:05 -080010139 mWindow->setFocusable(true);
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -070010140 mSecondWindow =
10141 sp<FakeWindowHandle>::make(mApp, mDispatcher, "TestWindow2", ADISPLAY_ID_DEFAULT);
Prabir Pradhan99987712020-11-10 18:43:05 -080010142 mSecondWindow->setFocusable(true);
10143
10144 mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, mApp);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070010145 mDispatcher->onWindowInfosChanged(
10146 {{*mWindow->getInfo(), *mSecondWindow->getInfo()}, {}, 0, 0});
Prabir Pradhan99987712020-11-10 18:43:05 -080010147
10148 setFocusedWindow(mWindow);
10149 mWindow->consumeFocusEvent(true);
10150 }
10151
Prabir Pradhan5cc1a692021-08-06 14:01:18 +000010152 void notifyPointerCaptureChanged(const PointerCaptureRequest& request) {
Prabir Pradhan678438e2023-04-13 19:32:51 +000010153 mDispatcher->notifyPointerCaptureChanged(generatePointerCaptureChangedArgs(request));
Prabir Pradhan99987712020-11-10 18:43:05 -080010154 }
10155
Prabir Pradhan5cc1a692021-08-06 14:01:18 +000010156 PointerCaptureRequest requestAndVerifyPointerCapture(const sp<FakeWindowHandle>& window,
10157 bool enabled) {
Prabir Pradhan99987712020-11-10 18:43:05 -080010158 mDispatcher->requestPointerCapture(window->getToken(), enabled);
Hiroki Sato25040232024-02-22 17:21:22 +090010159 auto request = mFakePolicy->assertSetPointerCaptureCalled(window, enabled);
Prabir Pradhan5cc1a692021-08-06 14:01:18 +000010160 notifyPointerCaptureChanged(request);
Prabir Pradhan99987712020-11-10 18:43:05 -080010161 window->consumeCaptureEvent(enabled);
Prabir Pradhan5cc1a692021-08-06 14:01:18 +000010162 return request;
Prabir Pradhan99987712020-11-10 18:43:05 -080010163 }
10164};
10165
10166TEST_F(InputDispatcherPointerCaptureTests, EnablePointerCaptureWhenFocused) {
10167 // Ensure that capture cannot be obtained for unfocused windows.
10168 mDispatcher->requestPointerCapture(mSecondWindow->getToken(), true);
10169 mFakePolicy->assertSetPointerCaptureNotCalled();
10170 mSecondWindow->assertNoEvents();
10171
10172 // Ensure that capture can be enabled from the focus window.
10173 requestAndVerifyPointerCapture(mWindow, true);
10174
10175 // Ensure that capture cannot be disabled from a window that does not have capture.
10176 mDispatcher->requestPointerCapture(mSecondWindow->getToken(), false);
10177 mFakePolicy->assertSetPointerCaptureNotCalled();
10178
10179 // Ensure that capture can be disabled from the window with capture.
10180 requestAndVerifyPointerCapture(mWindow, false);
10181}
10182
10183TEST_F(InputDispatcherPointerCaptureTests, DisablesPointerCaptureAfterWindowLosesFocus) {
Prabir Pradhan5cc1a692021-08-06 14:01:18 +000010184 auto request = requestAndVerifyPointerCapture(mWindow, true);
Prabir Pradhan99987712020-11-10 18:43:05 -080010185
10186 setFocusedWindow(mSecondWindow);
10187
10188 // Ensure that the capture disabled event was sent first.
10189 mWindow->consumeCaptureEvent(false);
10190 mWindow->consumeFocusEvent(false);
10191 mSecondWindow->consumeFocusEvent(true);
Hiroki Sato25040232024-02-22 17:21:22 +090010192 mFakePolicy->assertSetPointerCaptureCalled(mWindow, false);
Prabir Pradhan99987712020-11-10 18:43:05 -080010193
10194 // Ensure that additional state changes from InputReader are not sent to the window.
Prabir Pradhan5cc1a692021-08-06 14:01:18 +000010195 notifyPointerCaptureChanged({});
10196 notifyPointerCaptureChanged(request);
10197 notifyPointerCaptureChanged({});
Prabir Pradhan99987712020-11-10 18:43:05 -080010198 mWindow->assertNoEvents();
10199 mSecondWindow->assertNoEvents();
10200 mFakePolicy->assertSetPointerCaptureNotCalled();
10201}
10202
10203TEST_F(InputDispatcherPointerCaptureTests, UnexpectedStateChangeDisablesPointerCapture) {
Prabir Pradhan5cc1a692021-08-06 14:01:18 +000010204 auto request = requestAndVerifyPointerCapture(mWindow, true);
Prabir Pradhan99987712020-11-10 18:43:05 -080010205
10206 // InputReader unexpectedly disables and enables pointer capture.
Prabir Pradhan5cc1a692021-08-06 14:01:18 +000010207 notifyPointerCaptureChanged({});
10208 notifyPointerCaptureChanged(request);
Prabir Pradhan99987712020-11-10 18:43:05 -080010209
10210 // Ensure that Pointer Capture is disabled.
Hiroki Sato25040232024-02-22 17:21:22 +090010211 mFakePolicy->assertSetPointerCaptureCalled(mWindow, false);
Prabir Pradhan99987712020-11-10 18:43:05 -080010212 mWindow->consumeCaptureEvent(false);
10213 mWindow->assertNoEvents();
10214}
10215
Prabir Pradhan167e6d92021-02-04 16:18:17 -080010216TEST_F(InputDispatcherPointerCaptureTests, OutOfOrderRequests) {
10217 requestAndVerifyPointerCapture(mWindow, true);
10218
10219 // The first window loses focus.
10220 setFocusedWindow(mSecondWindow);
Hiroki Sato25040232024-02-22 17:21:22 +090010221 mFakePolicy->assertSetPointerCaptureCalled(mWindow, false);
Prabir Pradhan167e6d92021-02-04 16:18:17 -080010222 mWindow->consumeCaptureEvent(false);
10223
10224 // Request Pointer Capture from the second window before the notification from InputReader
10225 // arrives.
10226 mDispatcher->requestPointerCapture(mSecondWindow->getToken(), true);
Hiroki Sato25040232024-02-22 17:21:22 +090010227 auto request = mFakePolicy->assertSetPointerCaptureCalled(mSecondWindow, true);
Prabir Pradhan167e6d92021-02-04 16:18:17 -080010228
10229 // InputReader notifies Pointer Capture was disabled (because of the focus change).
Prabir Pradhan5cc1a692021-08-06 14:01:18 +000010230 notifyPointerCaptureChanged({});
Prabir Pradhan167e6d92021-02-04 16:18:17 -080010231
10232 // InputReader notifies Pointer Capture was enabled (because of mSecondWindow's request).
Prabir Pradhan5cc1a692021-08-06 14:01:18 +000010233 notifyPointerCaptureChanged(request);
Prabir Pradhan167e6d92021-02-04 16:18:17 -080010234
10235 mSecondWindow->consumeFocusEvent(true);
10236 mSecondWindow->consumeCaptureEvent(true);
10237}
10238
Prabir Pradhan5cc1a692021-08-06 14:01:18 +000010239TEST_F(InputDispatcherPointerCaptureTests, EnableRequestFollowsSequenceNumbers) {
10240 // App repeatedly enables and disables capture.
10241 mDispatcher->requestPointerCapture(mWindow->getToken(), true);
Hiroki Sato25040232024-02-22 17:21:22 +090010242 auto firstRequest = mFakePolicy->assertSetPointerCaptureCalled(mWindow, true);
Prabir Pradhan5cc1a692021-08-06 14:01:18 +000010243 mDispatcher->requestPointerCapture(mWindow->getToken(), false);
Hiroki Sato25040232024-02-22 17:21:22 +090010244 mFakePolicy->assertSetPointerCaptureCalled(mWindow, false);
Prabir Pradhan5cc1a692021-08-06 14:01:18 +000010245 mDispatcher->requestPointerCapture(mWindow->getToken(), true);
Hiroki Sato25040232024-02-22 17:21:22 +090010246 auto secondRequest = mFakePolicy->assertSetPointerCaptureCalled(mWindow, true);
Prabir Pradhan5cc1a692021-08-06 14:01:18 +000010247
10248 // InputReader notifies that PointerCapture has been enabled for the first request. Since the
10249 // first request is now stale, this should do nothing.
10250 notifyPointerCaptureChanged(firstRequest);
10251 mWindow->assertNoEvents();
10252
10253 // InputReader notifies that the second request was enabled.
10254 notifyPointerCaptureChanged(secondRequest);
10255 mWindow->consumeCaptureEvent(true);
10256}
10257
Prabir Pradhan7092e262022-05-03 16:51:09 +000010258TEST_F(InputDispatcherPointerCaptureTests, RapidToggleRequests) {
10259 requestAndVerifyPointerCapture(mWindow, true);
10260
10261 // App toggles pointer capture off and on.
10262 mDispatcher->requestPointerCapture(mWindow->getToken(), false);
Hiroki Sato25040232024-02-22 17:21:22 +090010263 mFakePolicy->assertSetPointerCaptureCalled(mWindow, false);
Prabir Pradhan7092e262022-05-03 16:51:09 +000010264
10265 mDispatcher->requestPointerCapture(mWindow->getToken(), true);
Hiroki Sato25040232024-02-22 17:21:22 +090010266 auto enableRequest = mFakePolicy->assertSetPointerCaptureCalled(mWindow, true);
Prabir Pradhan7092e262022-05-03 16:51:09 +000010267
10268 // InputReader notifies that the latest "enable" request was processed, while skipping over the
10269 // preceding "disable" request.
10270 notifyPointerCaptureChanged(enableRequest);
10271
10272 // Since pointer capture was never disabled during the rapid toggle, the window does not receive
10273 // any notifications.
10274 mWindow->assertNoEvents();
10275}
10276
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -070010277/**
10278 * One window. Hover mouse in the window, and then start capture. Make sure that the relative
10279 * mouse movements don't affect the previous mouse hovering state.
10280 * When pointer capture is enabled, the incoming events are always ACTION_MOVE (there are no
10281 * HOVER_MOVE events).
10282 */
10283TEST_F(InputDispatcherPointerCaptureTests, MouseHoverAndPointerCapture) {
10284 // Mouse hover on the window
10285 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_ENTER, AINPUT_SOURCE_MOUSE)
10286 .pointer(PointerBuilder(0, ToolType::MOUSE).x(100).y(110))
10287 .build());
10288 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_MOVE, AINPUT_SOURCE_MOUSE)
10289 .pointer(PointerBuilder(0, ToolType::MOUSE).x(100).y(110))
10290 .build());
10291
10292 mWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_HOVER_ENTER)));
10293 mWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_HOVER_MOVE)));
10294
10295 // Start pointer capture
10296 requestAndVerifyPointerCapture(mWindow, true);
10297
10298 // Send some relative mouse movements and receive them in the window.
10299 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_MOUSE_RELATIVE)
10300 .pointer(PointerBuilder(0, ToolType::MOUSE).x(10).y(11))
10301 .build());
10302 mWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_MOVE), WithCoords(10, 11),
10303 WithSource(AINPUT_SOURCE_MOUSE_RELATIVE)));
10304
10305 // Stop pointer capture
10306 requestAndVerifyPointerCapture(mWindow, false);
10307
10308 // Continue hovering on the window
10309 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_MOVE, AINPUT_SOURCE_MOUSE)
10310 .pointer(PointerBuilder(0, ToolType::MOUSE).x(105).y(115))
10311 .build());
10312 mWindow->consumeMotionEvent(
10313 AllOf(WithMotionAction(ACTION_HOVER_MOVE), WithSource(AINPUT_SOURCE_MOUSE)));
10314
10315 mWindow->assertNoEvents();
10316}
10317
Hiroki Sato25040232024-02-22 17:21:22 +090010318using InputDispatcherPointerCaptureDeathTest = InputDispatcherPointerCaptureTests;
10319
10320TEST_F(InputDispatcherPointerCaptureDeathTest,
10321 NotifyPointerCaptureChangedWithWrongTokenAbortsDispatcher) {
10322 testing::GTEST_FLAG(death_test_style) = "threadsafe";
10323 ScopedSilentDeath _silentDeath;
10324
10325 mDispatcher->requestPointerCapture(mWindow->getToken(), true);
10326 auto request = mFakePolicy->assertSetPointerCaptureCalled(mWindow, true);
10327
10328 // Dispatch a pointer changed event with a wrong token.
10329 request.window = mSecondWindow->getToken();
10330 ASSERT_DEATH(
10331 {
10332 notifyPointerCaptureChanged(request);
10333 mSecondWindow->consumeCaptureEvent(true);
10334 },
10335 "Unexpected requested window for Pointer Capture.");
10336}
10337
Bernardo Rufinoc3b7b8c2021-01-29 17:38:07 +000010338class InputDispatcherUntrustedTouchesTest : public InputDispatcherTest {
10339protected:
10340 constexpr static const float MAXIMUM_OBSCURING_OPACITY = 0.8;
Bernardo Rufino7393d172021-02-26 13:56:11 +000010341
10342 constexpr static const float OPACITY_ABOVE_THRESHOLD = 0.9;
10343 static_assert(OPACITY_ABOVE_THRESHOLD > MAXIMUM_OBSCURING_OPACITY);
10344
10345 constexpr static const float OPACITY_BELOW_THRESHOLD = 0.7;
10346 static_assert(OPACITY_BELOW_THRESHOLD < MAXIMUM_OBSCURING_OPACITY);
10347
10348 // When combined twice, ie 1 - (1 - 0.5)*(1 - 0.5) = 0.75 < 8, is still below the threshold
10349 constexpr static const float OPACITY_FAR_BELOW_THRESHOLD = 0.5;
10350 static_assert(OPACITY_FAR_BELOW_THRESHOLD < MAXIMUM_OBSCURING_OPACITY);
10351 static_assert(1 - (1 - OPACITY_FAR_BELOW_THRESHOLD) * (1 - OPACITY_FAR_BELOW_THRESHOLD) <
10352 MAXIMUM_OBSCURING_OPACITY);
10353
Prabir Pradhan8a5c41d2023-06-08 19:13:46 +000010354 static constexpr gui::Uid TOUCHED_APP_UID{10001};
10355 static constexpr gui::Uid APP_B_UID{10002};
10356 static constexpr gui::Uid APP_C_UID{10003};
Bernardo Rufinoc3b7b8c2021-01-29 17:38:07 +000010357
10358 sp<FakeWindowHandle> mTouchWindow;
10359
10360 virtual void SetUp() override {
10361 InputDispatcherTest::SetUp();
Bernardo Rufino6d52e542021-02-15 18:38:10 +000010362 mTouchWindow = getWindow(TOUCHED_APP_UID, "Touched");
Bernardo Rufinoc3b7b8c2021-01-29 17:38:07 +000010363 mDispatcher->setMaximumObscuringOpacityForTouch(MAXIMUM_OBSCURING_OPACITY);
10364 }
10365
10366 virtual void TearDown() override {
10367 InputDispatcherTest::TearDown();
10368 mTouchWindow.clear();
10369 }
10370
Prabir Pradhan8a5c41d2023-06-08 19:13:46 +000010371 sp<FakeWindowHandle> getOccludingWindow(gui::Uid uid, std::string name, TouchOcclusionMode mode,
chaviw3277faf2021-05-19 16:45:23 -050010372 float alpha = 1.0f) {
Bernardo Rufinoc3b7b8c2021-01-29 17:38:07 +000010373 sp<FakeWindowHandle> window = getWindow(uid, name);
Prabir Pradhan4d5c52f2022-01-31 08:52:10 -080010374 window->setTouchable(false);
Bernardo Rufinoc3b7b8c2021-01-29 17:38:07 +000010375 window->setTouchOcclusionMode(mode);
Bernardo Rufino1d0d1f22021-02-12 15:08:43 +000010376 window->setAlpha(alpha);
Bernardo Rufinoc3b7b8c2021-01-29 17:38:07 +000010377 return window;
10378 }
10379
Prabir Pradhan8a5c41d2023-06-08 19:13:46 +000010380 sp<FakeWindowHandle> getWindow(gui::Uid uid, std::string name) {
Bernardo Rufinoc3b7b8c2021-01-29 17:38:07 +000010381 std::shared_ptr<FakeApplicationHandle> app = std::make_shared<FakeApplicationHandle>();
10382 sp<FakeWindowHandle> window =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -070010383 sp<FakeWindowHandle>::make(app, mDispatcher, name, ADISPLAY_ID_DEFAULT);
Bernardo Rufinoc3b7b8c2021-01-29 17:38:07 +000010384 // Generate an arbitrary PID based on the UID
Prabir Pradhanaeebeb42023-06-13 19:53:03 +000010385 window->setOwnerInfo(gui::Pid{static_cast<pid_t>(1777 + (uid.val() % 10000))}, uid);
Bernardo Rufinoc3b7b8c2021-01-29 17:38:07 +000010386 return window;
10387 }
10388
10389 void touch(const std::vector<PointF>& points = {PointF{100, 200}}) {
Prabir Pradhan678438e2023-04-13 19:32:51 +000010390 mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_DOWN,
10391 AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
10392 points));
Bernardo Rufinoc3b7b8c2021-01-29 17:38:07 +000010393 }
10394};
10395
10396TEST_F(InputDispatcherUntrustedTouchesTest, WindowWithBlockUntrustedOcclusionMode_BlocksTouch) {
Bernardo Rufino1d0d1f22021-02-12 15:08:43 +000010397 const sp<FakeWindowHandle>& w =
Bernardo Rufinoc3b7b8c2021-01-29 17:38:07 +000010398 getOccludingWindow(APP_B_UID, "B", TouchOcclusionMode::BLOCK_UNTRUSTED);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070010399 mDispatcher->onWindowInfosChanged({{*w->getInfo(), *mTouchWindow->getInfo()}, {}, 0, 0});
Bernardo Rufinoc3b7b8c2021-01-29 17:38:07 +000010400
10401 touch();
10402
10403 mTouchWindow->assertNoEvents();
10404}
10405
Bernardo Rufinoa43a5a42021-02-17 12:21:14 +000010406TEST_F(InputDispatcherUntrustedTouchesTest,
Bernardo Rufino7393d172021-02-26 13:56:11 +000010407 WindowWithBlockUntrustedOcclusionModeWithOpacityBelowThreshold_BlocksTouch) {
10408 const sp<FakeWindowHandle>& w =
10409 getOccludingWindow(APP_B_UID, "B", TouchOcclusionMode::BLOCK_UNTRUSTED, 0.7f);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070010410 mDispatcher->onWindowInfosChanged({{*w->getInfo(), *mTouchWindow->getInfo()}, {}, 0, 0});
Bernardo Rufino7393d172021-02-26 13:56:11 +000010411
10412 touch();
10413
10414 mTouchWindow->assertNoEvents();
10415}
10416
10417TEST_F(InputDispatcherUntrustedTouchesTest,
Bernardo Rufinoa43a5a42021-02-17 12:21:14 +000010418 WindowWithBlockUntrustedOcclusionMode_DoesNotReceiveTouch) {
10419 const sp<FakeWindowHandle>& w =
10420 getOccludingWindow(APP_B_UID, "B", TouchOcclusionMode::BLOCK_UNTRUSTED);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070010421 mDispatcher->onWindowInfosChanged({{*w->getInfo(), *mTouchWindow->getInfo()}, {}, 0, 0});
Bernardo Rufinoa43a5a42021-02-17 12:21:14 +000010422
10423 touch();
10424
10425 w->assertNoEvents();
10426}
10427
Bernardo Rufinoc3b7b8c2021-01-29 17:38:07 +000010428TEST_F(InputDispatcherUntrustedTouchesTest, WindowWithAllowOcclusionMode_AllowsTouch) {
Bernardo Rufino1d0d1f22021-02-12 15:08:43 +000010429 const sp<FakeWindowHandle>& w = getOccludingWindow(APP_B_UID, "B", TouchOcclusionMode::ALLOW);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070010430 mDispatcher->onWindowInfosChanged({{*w->getInfo(), *mTouchWindow->getInfo()}, {}, 0, 0});
Bernardo Rufinoc3b7b8c2021-01-29 17:38:07 +000010431
10432 touch();
10433
10434 mTouchWindow->consumeAnyMotionDown();
10435}
10436
10437TEST_F(InputDispatcherUntrustedTouchesTest, TouchOutsideOccludingWindow_AllowsTouch) {
Bernardo Rufino1d0d1f22021-02-12 15:08:43 +000010438 const sp<FakeWindowHandle>& w =
Bernardo Rufinoc3b7b8c2021-01-29 17:38:07 +000010439 getOccludingWindow(APP_B_UID, "B", TouchOcclusionMode::BLOCK_UNTRUSTED);
Bernardo Rufino1d0d1f22021-02-12 15:08:43 +000010440 w->setFrame(Rect(0, 0, 50, 50));
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070010441 mDispatcher->onWindowInfosChanged({{*w->getInfo(), *mTouchWindow->getInfo()}, {}, 0, 0});
Bernardo Rufinoc3b7b8c2021-01-29 17:38:07 +000010442
10443 touch({PointF{100, 100}});
10444
10445 mTouchWindow->consumeAnyMotionDown();
10446}
10447
10448TEST_F(InputDispatcherUntrustedTouchesTest, WindowFromSameUid_AllowsTouch) {
Bernardo Rufino1d0d1f22021-02-12 15:08:43 +000010449 const sp<FakeWindowHandle>& w =
Bernardo Rufino6d52e542021-02-15 18:38:10 +000010450 getOccludingWindow(TOUCHED_APP_UID, "A", TouchOcclusionMode::BLOCK_UNTRUSTED);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070010451 mDispatcher->onWindowInfosChanged({{*w->getInfo(), *mTouchWindow->getInfo()}, {}, 0, 0});
Bernardo Rufino1d0d1f22021-02-12 15:08:43 +000010452
10453 touch();
10454
10455 mTouchWindow->consumeAnyMotionDown();
10456}
10457
10458TEST_F(InputDispatcherUntrustedTouchesTest, WindowWithZeroOpacity_AllowsTouch) {
10459 const sp<FakeWindowHandle>& w =
10460 getOccludingWindow(APP_B_UID, "B", TouchOcclusionMode::BLOCK_UNTRUSTED, 0.0f);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070010461 mDispatcher->onWindowInfosChanged({{*w->getInfo(), *mTouchWindow->getInfo()}, {}, 0, 0});
Bernardo Rufinoc3b7b8c2021-01-29 17:38:07 +000010462
10463 touch();
10464
10465 mTouchWindow->consumeAnyMotionDown();
10466}
10467
Bernardo Rufinoa43a5a42021-02-17 12:21:14 +000010468TEST_F(InputDispatcherUntrustedTouchesTest, WindowWithZeroOpacity_DoesNotReceiveTouch) {
10469 const sp<FakeWindowHandle>& w =
10470 getOccludingWindow(APP_B_UID, "B", TouchOcclusionMode::BLOCK_UNTRUSTED, 0.0f);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070010471 mDispatcher->onWindowInfosChanged({{*w->getInfo(), *mTouchWindow->getInfo()}, {}, 0, 0});
Bernardo Rufinoa43a5a42021-02-17 12:21:14 +000010472
10473 touch();
10474
10475 w->assertNoEvents();
10476}
10477
10478/**
10479 * This is important to make sure apps can't indirectly learn the position of touches (outside vs
10480 * inside) while letting them pass-through. Note that even though touch passes through the occluding
10481 * window, the occluding window will still receive ACTION_OUTSIDE event.
10482 */
10483TEST_F(InputDispatcherUntrustedTouchesTest,
10484 WindowWithZeroOpacityAndWatchOutside_ReceivesOutsideEvent) {
10485 const sp<FakeWindowHandle>& w =
10486 getOccludingWindow(APP_B_UID, "B", TouchOcclusionMode::BLOCK_UNTRUSTED, 0.0f);
Prabir Pradhan4d5c52f2022-01-31 08:52:10 -080010487 w->setWatchOutsideTouch(true);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070010488 mDispatcher->onWindowInfosChanged({{*w->getInfo(), *mTouchWindow->getInfo()}, {}, 0, 0});
Bernardo Rufinoa43a5a42021-02-17 12:21:14 +000010489
10490 touch();
10491
10492 w->consumeMotionOutside();
10493}
10494
10495TEST_F(InputDispatcherUntrustedTouchesTest, OutsideEvent_HasZeroCoordinates) {
10496 const sp<FakeWindowHandle>& w =
10497 getOccludingWindow(APP_B_UID, "B", TouchOcclusionMode::BLOCK_UNTRUSTED, 0.0f);
Prabir Pradhan4d5c52f2022-01-31 08:52:10 -080010498 w->setWatchOutsideTouch(true);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070010499 mDispatcher->onWindowInfosChanged({{*w->getInfo(), *mTouchWindow->getInfo()}, {}, 0, 0});
Bernardo Rufinoa43a5a42021-02-17 12:21:14 +000010500
10501 touch();
10502
Prabir Pradhandfabf8a2022-01-21 08:19:30 -080010503 w->consumeMotionOutsideWithZeroedCoords();
Bernardo Rufinoa43a5a42021-02-17 12:21:14 +000010504}
10505
Bernardo Rufinoc3b7b8c2021-01-29 17:38:07 +000010506TEST_F(InputDispatcherUntrustedTouchesTest, WindowWithOpacityBelowThreshold_AllowsTouch) {
Bernardo Rufino1d0d1f22021-02-12 15:08:43 +000010507 const sp<FakeWindowHandle>& w =
Bernardo Rufino7393d172021-02-26 13:56:11 +000010508 getOccludingWindow(APP_B_UID, "B", TouchOcclusionMode::USE_OPACITY,
10509 OPACITY_BELOW_THRESHOLD);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070010510 mDispatcher->onWindowInfosChanged({{*w->getInfo(), *mTouchWindow->getInfo()}, {}, 0, 0});
Bernardo Rufino1d0d1f22021-02-12 15:08:43 +000010511
10512 touch();
10513
10514 mTouchWindow->consumeAnyMotionDown();
10515}
10516
10517TEST_F(InputDispatcherUntrustedTouchesTest, WindowWithOpacityAtThreshold_AllowsTouch) {
10518 const sp<FakeWindowHandle>& w =
10519 getOccludingWindow(APP_B_UID, "B", TouchOcclusionMode::USE_OPACITY,
10520 MAXIMUM_OBSCURING_OPACITY);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070010521 mDispatcher->onWindowInfosChanged({{*w->getInfo(), *mTouchWindow->getInfo()}, {}, 0, 0});
Bernardo Rufinoc3b7b8c2021-01-29 17:38:07 +000010522
10523 touch();
10524
10525 mTouchWindow->consumeAnyMotionDown();
10526}
10527
10528TEST_F(InputDispatcherUntrustedTouchesTest, WindowWithOpacityAboveThreshold_BlocksTouch) {
Bernardo Rufino1d0d1f22021-02-12 15:08:43 +000010529 const sp<FakeWindowHandle>& w =
Bernardo Rufino7393d172021-02-26 13:56:11 +000010530 getOccludingWindow(APP_B_UID, "B", TouchOcclusionMode::USE_OPACITY,
10531 OPACITY_ABOVE_THRESHOLD);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070010532 mDispatcher->onWindowInfosChanged({{*w->getInfo(), *mTouchWindow->getInfo()}, {}, 0, 0});
Bernardo Rufino1d0d1f22021-02-12 15:08:43 +000010533
10534 touch();
10535
10536 mTouchWindow->assertNoEvents();
10537}
10538
10539TEST_F(InputDispatcherUntrustedTouchesTest, WindowsWithCombinedOpacityAboveThreshold_BlocksTouch) {
10540 // Resulting opacity = 1 - (1 - 0.7)*(1 - 0.7) = .91
10541 const sp<FakeWindowHandle>& w1 =
Bernardo Rufino7393d172021-02-26 13:56:11 +000010542 getOccludingWindow(APP_B_UID, "B1", TouchOcclusionMode::USE_OPACITY,
10543 OPACITY_BELOW_THRESHOLD);
Bernardo Rufino1d0d1f22021-02-12 15:08:43 +000010544 const sp<FakeWindowHandle>& w2 =
Bernardo Rufino7393d172021-02-26 13:56:11 +000010545 getOccludingWindow(APP_B_UID, "B2", TouchOcclusionMode::USE_OPACITY,
10546 OPACITY_BELOW_THRESHOLD);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070010547 mDispatcher->onWindowInfosChanged(
10548 {{*w1->getInfo(), *w2->getInfo(), *mTouchWindow->getInfo()}, {}, 0, 0});
Bernardo Rufino1d0d1f22021-02-12 15:08:43 +000010549
10550 touch();
10551
10552 mTouchWindow->assertNoEvents();
10553}
10554
10555TEST_F(InputDispatcherUntrustedTouchesTest, WindowsWithCombinedOpacityBelowThreshold_AllowsTouch) {
10556 // Resulting opacity = 1 - (1 - 0.5)*(1 - 0.5) = .75
10557 const sp<FakeWindowHandle>& w1 =
Bernardo Rufino7393d172021-02-26 13:56:11 +000010558 getOccludingWindow(APP_B_UID, "B1", TouchOcclusionMode::USE_OPACITY,
10559 OPACITY_FAR_BELOW_THRESHOLD);
Bernardo Rufino1d0d1f22021-02-12 15:08:43 +000010560 const sp<FakeWindowHandle>& w2 =
Bernardo Rufino7393d172021-02-26 13:56:11 +000010561 getOccludingWindow(APP_B_UID, "B2", TouchOcclusionMode::USE_OPACITY,
10562 OPACITY_FAR_BELOW_THRESHOLD);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070010563 mDispatcher->onWindowInfosChanged(
10564 {{*w1->getInfo(), *w2->getInfo(), *mTouchWindow->getInfo()}, {}, 0, 0});
Bernardo Rufino1d0d1f22021-02-12 15:08:43 +000010565
10566 touch();
10567
10568 mTouchWindow->consumeAnyMotionDown();
10569}
10570
10571TEST_F(InputDispatcherUntrustedTouchesTest,
10572 WindowsFromDifferentAppsEachBelowThreshold_AllowsTouch) {
10573 const sp<FakeWindowHandle>& wB =
Bernardo Rufino7393d172021-02-26 13:56:11 +000010574 getOccludingWindow(APP_B_UID, "B", TouchOcclusionMode::USE_OPACITY,
10575 OPACITY_BELOW_THRESHOLD);
Bernardo Rufino1d0d1f22021-02-12 15:08:43 +000010576 const sp<FakeWindowHandle>& wC =
Bernardo Rufino7393d172021-02-26 13:56:11 +000010577 getOccludingWindow(APP_C_UID, "C", TouchOcclusionMode::USE_OPACITY,
10578 OPACITY_BELOW_THRESHOLD);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070010579 mDispatcher->onWindowInfosChanged(
10580 {{*wB->getInfo(), *wC->getInfo(), *mTouchWindow->getInfo()}, {}, 0, 0});
Bernardo Rufino1d0d1f22021-02-12 15:08:43 +000010581
10582 touch();
10583
10584 mTouchWindow->consumeAnyMotionDown();
10585}
10586
10587TEST_F(InputDispatcherUntrustedTouchesTest, WindowsFromDifferentAppsOneAboveThreshold_BlocksTouch) {
10588 const sp<FakeWindowHandle>& wB =
Bernardo Rufino7393d172021-02-26 13:56:11 +000010589 getOccludingWindow(APP_B_UID, "B", TouchOcclusionMode::USE_OPACITY,
10590 OPACITY_BELOW_THRESHOLD);
Bernardo Rufino1d0d1f22021-02-12 15:08:43 +000010591 const sp<FakeWindowHandle>& wC =
Bernardo Rufino7393d172021-02-26 13:56:11 +000010592 getOccludingWindow(APP_C_UID, "C", TouchOcclusionMode::USE_OPACITY,
10593 OPACITY_ABOVE_THRESHOLD);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070010594 mDispatcher->onWindowInfosChanged(
10595 {{*wB->getInfo(), *wC->getInfo(), *mTouchWindow->getInfo()}, {}, 0, 0});
Bernardo Rufinoc3b7b8c2021-01-29 17:38:07 +000010596
10597 touch();
10598
10599 mTouchWindow->assertNoEvents();
10600}
10601
Bernardo Rufino6d52e542021-02-15 18:38:10 +000010602TEST_F(InputDispatcherUntrustedTouchesTest,
10603 WindowWithOpacityAboveThresholdAndSelfWindow_BlocksTouch) {
10604 const sp<FakeWindowHandle>& wA =
Bernardo Rufino7393d172021-02-26 13:56:11 +000010605 getOccludingWindow(TOUCHED_APP_UID, "T", TouchOcclusionMode::USE_OPACITY,
10606 OPACITY_BELOW_THRESHOLD);
Bernardo Rufino6d52e542021-02-15 18:38:10 +000010607 const sp<FakeWindowHandle>& wB =
Bernardo Rufino7393d172021-02-26 13:56:11 +000010608 getOccludingWindow(APP_B_UID, "B", TouchOcclusionMode::USE_OPACITY,
10609 OPACITY_ABOVE_THRESHOLD);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070010610 mDispatcher->onWindowInfosChanged(
10611 {{*wA->getInfo(), *wB->getInfo(), *mTouchWindow->getInfo()}, {}, 0, 0});
Bernardo Rufino6d52e542021-02-15 18:38:10 +000010612
10613 touch();
10614
10615 mTouchWindow->assertNoEvents();
10616}
10617
10618TEST_F(InputDispatcherUntrustedTouchesTest,
10619 WindowWithOpacityBelowThresholdAndSelfWindow_AllowsTouch) {
10620 const sp<FakeWindowHandle>& wA =
Bernardo Rufino7393d172021-02-26 13:56:11 +000010621 getOccludingWindow(TOUCHED_APP_UID, "T", TouchOcclusionMode::USE_OPACITY,
10622 OPACITY_ABOVE_THRESHOLD);
Bernardo Rufino6d52e542021-02-15 18:38:10 +000010623 const sp<FakeWindowHandle>& wB =
Bernardo Rufino7393d172021-02-26 13:56:11 +000010624 getOccludingWindow(APP_B_UID, "B", TouchOcclusionMode::USE_OPACITY,
10625 OPACITY_BELOW_THRESHOLD);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070010626 mDispatcher->onWindowInfosChanged(
10627 {{*wA->getInfo(), *wB->getInfo(), *mTouchWindow->getInfo()}, {}, 0, 0});
Bernardo Rufino6d52e542021-02-15 18:38:10 +000010628
10629 touch();
10630
10631 mTouchWindow->consumeAnyMotionDown();
10632}
10633
10634TEST_F(InputDispatcherUntrustedTouchesTest, SelfWindowWithOpacityAboveThreshold_AllowsTouch) {
10635 const sp<FakeWindowHandle>& w =
Bernardo Rufino7393d172021-02-26 13:56:11 +000010636 getOccludingWindow(TOUCHED_APP_UID, "T", TouchOcclusionMode::USE_OPACITY,
10637 OPACITY_ABOVE_THRESHOLD);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070010638 mDispatcher->onWindowInfosChanged({{*w->getInfo(), *mTouchWindow->getInfo()}, {}, 0, 0});
Bernardo Rufino6d52e542021-02-15 18:38:10 +000010639
10640 touch();
10641
10642 mTouchWindow->consumeAnyMotionDown();
10643}
10644
10645TEST_F(InputDispatcherUntrustedTouchesTest, SelfWindowWithBlockUntrustedMode_AllowsTouch) {
10646 const sp<FakeWindowHandle>& w =
10647 getOccludingWindow(TOUCHED_APP_UID, "T", TouchOcclusionMode::BLOCK_UNTRUSTED);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070010648 mDispatcher->onWindowInfosChanged({{*w->getInfo(), *mTouchWindow->getInfo()}, {}, 0, 0});
Bernardo Rufino6d52e542021-02-15 18:38:10 +000010649
10650 touch();
10651
10652 mTouchWindow->consumeAnyMotionDown();
10653}
10654
Bernardo Rufinoccd3dd62021-02-15 18:47:42 +000010655TEST_F(InputDispatcherUntrustedTouchesTest,
10656 OpacityThresholdIs0AndWindowAboveThreshold_BlocksTouch) {
10657 mDispatcher->setMaximumObscuringOpacityForTouch(0.0f);
10658 const sp<FakeWindowHandle>& w =
10659 getOccludingWindow(APP_B_UID, "B", TouchOcclusionMode::USE_OPACITY, 0.1f);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070010660 mDispatcher->onWindowInfosChanged({{*w->getInfo(), *mTouchWindow->getInfo()}, {}, 0, 0});
Bernardo Rufinoccd3dd62021-02-15 18:47:42 +000010661
10662 touch();
10663
10664 mTouchWindow->assertNoEvents();
10665}
10666
10667TEST_F(InputDispatcherUntrustedTouchesTest, OpacityThresholdIs0AndWindowAtThreshold_AllowsTouch) {
10668 mDispatcher->setMaximumObscuringOpacityForTouch(0.0f);
10669 const sp<FakeWindowHandle>& w =
10670 getOccludingWindow(APP_B_UID, "B", TouchOcclusionMode::USE_OPACITY, 0.0f);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070010671 mDispatcher->onWindowInfosChanged({{*w->getInfo(), *mTouchWindow->getInfo()}, {}, 0, 0});
Bernardo Rufinoccd3dd62021-02-15 18:47:42 +000010672
10673 touch();
10674
10675 mTouchWindow->consumeAnyMotionDown();
10676}
10677
10678TEST_F(InputDispatcherUntrustedTouchesTest,
10679 OpacityThresholdIs1AndWindowBelowThreshold_AllowsTouch) {
10680 mDispatcher->setMaximumObscuringOpacityForTouch(1.0f);
10681 const sp<FakeWindowHandle>& w =
Bernardo Rufino7393d172021-02-26 13:56:11 +000010682 getOccludingWindow(APP_B_UID, "B", TouchOcclusionMode::USE_OPACITY,
10683 OPACITY_ABOVE_THRESHOLD);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070010684 mDispatcher->onWindowInfosChanged({{*w->getInfo(), *mTouchWindow->getInfo()}, {}, 0, 0});
Bernardo Rufino7393d172021-02-26 13:56:11 +000010685
10686 touch();
10687
10688 mTouchWindow->consumeAnyMotionDown();
10689}
10690
10691TEST_F(InputDispatcherUntrustedTouchesTest,
10692 WindowWithBlockUntrustedModeAndWindowWithOpacityBelowFromSameApp_BlocksTouch) {
10693 const sp<FakeWindowHandle>& w1 =
10694 getOccludingWindow(APP_B_UID, "B", TouchOcclusionMode::BLOCK_UNTRUSTED,
10695 OPACITY_BELOW_THRESHOLD);
10696 const sp<FakeWindowHandle>& w2 =
10697 getOccludingWindow(APP_B_UID, "B", TouchOcclusionMode::USE_OPACITY,
10698 OPACITY_BELOW_THRESHOLD);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070010699 mDispatcher->onWindowInfosChanged(
10700 {{*w1->getInfo(), *w2->getInfo(), *mTouchWindow->getInfo()}, {}, 0, 0});
Bernardo Rufino7393d172021-02-26 13:56:11 +000010701
10702 touch();
10703
10704 mTouchWindow->assertNoEvents();
10705}
10706
10707/**
10708 * Window B of BLOCK_UNTRUSTED occlusion mode is enough to block the touch, we're testing that the
10709 * addition of another window (C) of USE_OPACITY occlusion mode and opacity below the threshold
10710 * (which alone would result in allowing touches) does not affect the blocking behavior.
10711 */
10712TEST_F(InputDispatcherUntrustedTouchesTest,
10713 WindowWithBlockUntrustedModeAndWindowWithOpacityBelowFromDifferentApps_BlocksTouch) {
10714 const sp<FakeWindowHandle>& wB =
10715 getOccludingWindow(APP_B_UID, "B", TouchOcclusionMode::BLOCK_UNTRUSTED,
10716 OPACITY_BELOW_THRESHOLD);
10717 const sp<FakeWindowHandle>& wC =
10718 getOccludingWindow(APP_C_UID, "C", TouchOcclusionMode::USE_OPACITY,
10719 OPACITY_BELOW_THRESHOLD);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070010720 mDispatcher->onWindowInfosChanged(
10721 {{*wB->getInfo(), *wC->getInfo(), *mTouchWindow->getInfo()}, {}, 0, 0});
Bernardo Rufino7393d172021-02-26 13:56:11 +000010722
10723 touch();
10724
10725 mTouchWindow->assertNoEvents();
10726}
10727
10728/**
10729 * This test is testing that a window from a different UID but with same application token doesn't
10730 * block the touch. Apps can share the application token for close UI collaboration for example.
10731 */
10732TEST_F(InputDispatcherUntrustedTouchesTest,
10733 WindowWithSameApplicationTokenFromDifferentApp_AllowsTouch) {
10734 const sp<FakeWindowHandle>& w =
10735 getOccludingWindow(APP_B_UID, "B", TouchOcclusionMode::BLOCK_UNTRUSTED);
10736 w->setApplicationToken(mTouchWindow->getApplicationToken());
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070010737 mDispatcher->onWindowInfosChanged({{*w->getInfo(), *mTouchWindow->getInfo()}, {}, 0, 0});
Bernardo Rufinoccd3dd62021-02-15 18:47:42 +000010738
10739 touch();
10740
10741 mTouchWindow->consumeAnyMotionDown();
10742}
10743
arthurhungb89ccb02020-12-30 16:19:01 +080010744class InputDispatcherDragTests : public InputDispatcherTest {
10745protected:
10746 std::shared_ptr<FakeApplicationHandle> mApp;
10747 sp<FakeWindowHandle> mWindow;
10748 sp<FakeWindowHandle> mSecondWindow;
10749 sp<FakeWindowHandle> mDragWindow;
Vaibhav Devmurari6abcf8f2022-06-06 10:08:05 +000010750 sp<FakeWindowHandle> mSpyWindow;
Arthur Hungb75c2aa2022-07-15 09:35:36 +000010751 // Mouse would force no-split, set the id as non-zero to verify if drag state could track it.
10752 static constexpr int32_t MOUSE_POINTER_ID = 1;
arthurhungb89ccb02020-12-30 16:19:01 +080010753
10754 void SetUp() override {
10755 InputDispatcherTest::SetUp();
10756 mApp = std::make_shared<FakeApplicationHandle>();
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -070010757 mWindow = sp<FakeWindowHandle>::make(mApp, mDispatcher, "TestWindow", ADISPLAY_ID_DEFAULT);
arthurhungb89ccb02020-12-30 16:19:01 +080010758 mWindow->setFrame(Rect(0, 0, 100, 100));
arthurhungb89ccb02020-12-30 16:19:01 +080010759
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -070010760 mSecondWindow =
10761 sp<FakeWindowHandle>::make(mApp, mDispatcher, "TestWindow2", ADISPLAY_ID_DEFAULT);
arthurhungb89ccb02020-12-30 16:19:01 +080010762 mSecondWindow->setFrame(Rect(100, 0, 200, 100));
arthurhungb89ccb02020-12-30 16:19:01 +080010763
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -070010764 mSpyWindow =
10765 sp<FakeWindowHandle>::make(mApp, mDispatcher, "SpyWindow", ADISPLAY_ID_DEFAULT);
Vaibhav Devmurari6abcf8f2022-06-06 10:08:05 +000010766 mSpyWindow->setSpy(true);
10767 mSpyWindow->setTrustedOverlay(true);
10768 mSpyWindow->setFrame(Rect(0, 0, 200, 100));
10769
arthurhungb89ccb02020-12-30 16:19:01 +080010770 mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, mApp);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070010771 mDispatcher->onWindowInfosChanged(
10772 {{*mSpyWindow->getInfo(), *mWindow->getInfo(), *mSecondWindow->getInfo()},
10773 {},
10774 0,
10775 0});
arthurhungb89ccb02020-12-30 16:19:01 +080010776 }
10777
Arthur Hungb75c2aa2022-07-15 09:35:36 +000010778 void injectDown(int fromSource = AINPUT_SOURCE_TOUCHSCREEN) {
10779 switch (fromSource) {
10780 case AINPUT_SOURCE_TOUCHSCREEN:
10781 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070010782 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN,
Arthur Hungb75c2aa2022-07-15 09:35:36 +000010783 ADISPLAY_ID_DEFAULT, {50, 50}))
10784 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
10785 break;
10786 case AINPUT_SOURCE_STYLUS:
10787 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070010788 injectMotionEvent(*mDispatcher,
10789 MotionEventBuilder(AMOTION_EVENT_ACTION_DOWN,
10790 AINPUT_SOURCE_STYLUS)
10791 .buttonState(
10792 AMOTION_EVENT_BUTTON_STYLUS_PRIMARY)
10793 .pointer(PointerBuilder(0, ToolType::STYLUS)
10794 .x(50)
10795 .y(50))
10796 .build()));
Arthur Hungb75c2aa2022-07-15 09:35:36 +000010797 break;
10798 case AINPUT_SOURCE_MOUSE:
10799 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070010800 injectMotionEvent(*mDispatcher,
10801 MotionEventBuilder(AMOTION_EVENT_ACTION_DOWN,
10802 AINPUT_SOURCE_MOUSE)
10803 .buttonState(AMOTION_EVENT_BUTTON_PRIMARY)
10804 .pointer(PointerBuilder(MOUSE_POINTER_ID,
10805 ToolType::MOUSE)
10806 .x(50)
10807 .y(50))
10808 .build()));
Arthur Hungb75c2aa2022-07-15 09:35:36 +000010809 break;
10810 default:
10811 FAIL() << "Source " << fromSource << " doesn't support drag and drop";
10812 }
arthurhungb89ccb02020-12-30 16:19:01 +080010813
10814 // Window should receive motion event.
10815 mWindow->consumeMotionDown(ADISPLAY_ID_DEFAULT);
Vaibhav Devmurari6abcf8f2022-06-06 10:08:05 +000010816 // Spy window should also receive motion event
10817 mSpyWindow->consumeMotionDown(ADISPLAY_ID_DEFAULT);
Arthur Hung54745652022-04-20 07:17:41 +000010818 }
10819
10820 // Start performing drag, we will create a drag window and transfer touch to it.
10821 // @param sendDown : if true, send a motion down on first window before perform drag and drop.
10822 // Returns true on success.
Arthur Hungb75c2aa2022-07-15 09:35:36 +000010823 bool startDrag(bool sendDown = true, int fromSource = AINPUT_SOURCE_TOUCHSCREEN) {
Arthur Hung54745652022-04-20 07:17:41 +000010824 if (sendDown) {
Arthur Hungb75c2aa2022-07-15 09:35:36 +000010825 injectDown(fromSource);
Arthur Hung54745652022-04-20 07:17:41 +000010826 }
arthurhungb89ccb02020-12-30 16:19:01 +080010827
10828 // The drag window covers the entire display
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -070010829 mDragWindow =
10830 sp<FakeWindowHandle>::make(mApp, mDispatcher, "DragWindow", ADISPLAY_ID_DEFAULT);
Vaibhav Devmurari6abcf8f2022-06-06 10:08:05 +000010831 mDragWindow->setTouchableRegion(Region{{0, 0, 0, 0}});
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070010832 mDispatcher->onWindowInfosChanged({{*mDragWindow->getInfo(), *mSpyWindow->getInfo(),
10833 *mWindow->getInfo(), *mSecondWindow->getInfo()},
10834 {},
10835 0,
10836 0});
arthurhungb89ccb02020-12-30 16:19:01 +080010837
10838 // Transfer touch focus to the drag window
Arthur Hung54745652022-04-20 07:17:41 +000010839 bool transferred =
Prabir Pradhan367f3432024-02-13 23:05:58 +000010840 mDispatcher->transferTouchGesture(mWindow->getToken(), mDragWindow->getToken(),
10841 /*isDragDrop=*/true);
Arthur Hung54745652022-04-20 07:17:41 +000010842 if (transferred) {
10843 mWindow->consumeMotionCancel();
Prabir Pradhan65455c72024-02-13 21:46:41 +000010844 mDragWindow->consumeMotionDown(ADISPLAY_ID_DEFAULT, AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
Arthur Hung54745652022-04-20 07:17:41 +000010845 }
10846 return transferred;
arthurhungb89ccb02020-12-30 16:19:01 +080010847 }
10848};
10849
10850TEST_F(InputDispatcherDragTests, DragEnterAndDragExit) {
Arthur Hungb75c2aa2022-07-15 09:35:36 +000010851 startDrag();
arthurhungb89ccb02020-12-30 16:19:01 +080010852
10853 // Move on window.
10854 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070010855 injectMotionEvent(*mDispatcher, AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN,
arthurhungb89ccb02020-12-30 16:19:01 +080010856 ADISPLAY_ID_DEFAULT, {50, 50}))
10857 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
Prabir Pradhan65455c72024-02-13 21:46:41 +000010858 mDragWindow->consumeMotionMove(ADISPLAY_ID_DEFAULT, AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
arthurhungb89ccb02020-12-30 16:19:01 +080010859 mWindow->consumeDragEvent(false, 50, 50);
10860 mSecondWindow->assertNoEvents();
10861
10862 // Move to another window.
10863 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070010864 injectMotionEvent(*mDispatcher, AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN,
arthurhungb89ccb02020-12-30 16:19:01 +080010865 ADISPLAY_ID_DEFAULT, {150, 50}))
10866 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
Prabir Pradhan65455c72024-02-13 21:46:41 +000010867 mDragWindow->consumeMotionMove(ADISPLAY_ID_DEFAULT, AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
arthurhungb89ccb02020-12-30 16:19:01 +080010868 mWindow->consumeDragEvent(true, 150, 50);
10869 mSecondWindow->consumeDragEvent(false, 50, 50);
10870
10871 // Move back to original window.
10872 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070010873 injectMotionEvent(*mDispatcher, AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN,
arthurhungb89ccb02020-12-30 16:19:01 +080010874 ADISPLAY_ID_DEFAULT, {50, 50}))
10875 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
Prabir Pradhan65455c72024-02-13 21:46:41 +000010876 mDragWindow->consumeMotionMove(ADISPLAY_ID_DEFAULT, AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
arthurhungb89ccb02020-12-30 16:19:01 +080010877 mWindow->consumeDragEvent(false, 50, 50);
10878 mSecondWindow->consumeDragEvent(true, -50, 50);
10879
10880 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070010881 injectMotionUp(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
10882 {50, 50}))
arthurhungb89ccb02020-12-30 16:19:01 +080010883 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
Prabir Pradhan65455c72024-02-13 21:46:41 +000010884 mDragWindow->consumeMotionUp(ADISPLAY_ID_DEFAULT, AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
arthurhungb89ccb02020-12-30 16:19:01 +080010885 mWindow->assertNoEvents();
10886 mSecondWindow->assertNoEvents();
10887}
10888
Vaibhav Devmurari6abcf8f2022-06-06 10:08:05 +000010889TEST_F(InputDispatcherDragTests, DragEnterAndPointerDownPilfersPointers) {
Arthur Hungb75c2aa2022-07-15 09:35:36 +000010890 startDrag();
Vaibhav Devmurari6abcf8f2022-06-06 10:08:05 +000010891
10892 // No cancel event after drag start
10893 mSpyWindow->assertNoEvents();
10894
10895 const MotionEvent secondFingerDownEvent =
10896 MotionEventBuilder(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
10897 .eventTime(systemTime(SYSTEM_TIME_MONOTONIC))
Siarhei Vishniakou6d73f832022-07-21 17:27:03 -070010898 .pointer(PointerBuilder(/*id=*/0, ToolType::FINGER).x(50).y(50))
10899 .pointer(PointerBuilder(/*id=*/1, ToolType::FINGER).x(60).y(60))
Vaibhav Devmurari6abcf8f2022-06-06 10:08:05 +000010900 .build();
10901 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070010902 injectMotionEvent(*mDispatcher, secondFingerDownEvent, INJECT_EVENT_TIMEOUT,
Vaibhav Devmurari6abcf8f2022-06-06 10:08:05 +000010903 InputEventInjectionSync::WAIT_FOR_RESULT))
10904 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
10905
10906 // Receives cancel for first pointer after next pointer down
10907 mSpyWindow->consumeMotionCancel();
10908 mSpyWindow->consumeMotionDown();
10909
10910 mSpyWindow->assertNoEvents();
10911}
10912
arthurhungf452d0b2021-01-06 00:19:52 +080010913TEST_F(InputDispatcherDragTests, DragAndDrop) {
Arthur Hungb75c2aa2022-07-15 09:35:36 +000010914 startDrag();
arthurhungf452d0b2021-01-06 00:19:52 +080010915
10916 // Move on window.
10917 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070010918 injectMotionEvent(*mDispatcher, AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN,
arthurhungf452d0b2021-01-06 00:19:52 +080010919 ADISPLAY_ID_DEFAULT, {50, 50}))
10920 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
Prabir Pradhan65455c72024-02-13 21:46:41 +000010921 mDragWindow->consumeMotionMove(ADISPLAY_ID_DEFAULT, AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
arthurhungf452d0b2021-01-06 00:19:52 +080010922 mWindow->consumeDragEvent(false, 50, 50);
10923 mSecondWindow->assertNoEvents();
10924
10925 // Move to another window.
10926 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070010927 injectMotionEvent(*mDispatcher, AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN,
arthurhungf452d0b2021-01-06 00:19:52 +080010928 ADISPLAY_ID_DEFAULT, {150, 50}))
10929 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
Prabir Pradhan65455c72024-02-13 21:46:41 +000010930 mDragWindow->consumeMotionMove(ADISPLAY_ID_DEFAULT, AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
arthurhungf452d0b2021-01-06 00:19:52 +080010931 mWindow->consumeDragEvent(true, 150, 50);
10932 mSecondWindow->consumeDragEvent(false, 50, 50);
10933
10934 // drop to another window.
10935 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070010936 injectMotionUp(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
arthurhungf452d0b2021-01-06 00:19:52 +080010937 {150, 50}))
10938 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
Prabir Pradhan65455c72024-02-13 21:46:41 +000010939 mDragWindow->consumeMotionUp(ADISPLAY_ID_DEFAULT, AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
Siarhei Vishniakoua66d65e2023-06-16 10:32:51 -070010940 mFakePolicy->assertDropTargetEquals(*mDispatcher, mSecondWindow->getToken());
arthurhungf452d0b2021-01-06 00:19:52 +080010941 mWindow->assertNoEvents();
10942 mSecondWindow->assertNoEvents();
10943}
10944
Vaibhav Devmurari110ba322023-11-17 10:47:16 +000010945TEST_F(InputDispatcherDragTests, DragAndDropNotCancelledIfSomeOtherPointerIsPilfered) {
10946 startDrag();
10947
10948 // No cancel event after drag start
10949 mSpyWindow->assertNoEvents();
10950
10951 const MotionEvent secondFingerDownEvent =
10952 MotionEventBuilder(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
10953 .eventTime(systemTime(SYSTEM_TIME_MONOTONIC))
10954 .pointer(PointerBuilder(/*id=*/0, ToolType::FINGER).x(50).y(50))
10955 .pointer(PointerBuilder(/*id=*/1, ToolType::FINGER).x(60).y(60))
10956 .build();
10957 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
10958 injectMotionEvent(*mDispatcher, secondFingerDownEvent, INJECT_EVENT_TIMEOUT,
10959 InputEventInjectionSync::WAIT_FOR_RESULT))
10960 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
10961
10962 // Receives cancel for first pointer after next pointer down
10963 mSpyWindow->consumeMotionEvent(WithMotionAction(ACTION_CANCEL));
Siarhei Vishniakou1ff00cc2023-12-13 16:12:13 -080010964 mSpyWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithPointerIds({1})));
Vaibhav Devmurari110ba322023-11-17 10:47:16 +000010965 mDragWindow->consumeMotionEvent(WithMotionAction(ACTION_MOVE));
10966
10967 mSpyWindow->assertNoEvents();
10968
10969 // Spy window calls pilfer pointers
10970 EXPECT_EQ(OK, mDispatcher->pilferPointers(mSpyWindow->getToken()));
10971 mDragWindow->assertNoEvents();
10972
10973 const MotionEvent firstFingerMoveEvent =
Siarhei Vishniakou96a15572023-12-18 10:47:52 -080010974 MotionEventBuilder(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN)
Vaibhav Devmurari110ba322023-11-17 10:47:16 +000010975 .eventTime(systemTime(SYSTEM_TIME_MONOTONIC))
10976 .pointer(PointerBuilder(/*id=*/0, ToolType::FINGER).x(60).y(60))
10977 .pointer(PointerBuilder(/*id=*/1, ToolType::FINGER).x(60).y(60))
10978 .build();
10979 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakou96a15572023-12-18 10:47:52 -080010980 injectMotionEvent(*mDispatcher, firstFingerMoveEvent, INJECT_EVENT_TIMEOUT,
Vaibhav Devmurari110ba322023-11-17 10:47:16 +000010981 InputEventInjectionSync::WAIT_FOR_RESULT))
10982 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
10983
10984 // Drag window should still receive the new event
Prabir Pradhan65455c72024-02-13 21:46:41 +000010985 mDragWindow->consumeMotionEvent(
10986 AllOf(WithMotionAction(ACTION_MOVE), WithFlags(AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE)));
Vaibhav Devmurari110ba322023-11-17 10:47:16 +000010987 mDragWindow->assertNoEvents();
10988}
10989
arthurhung6d4bed92021-03-17 11:59:33 +080010990TEST_F(InputDispatcherDragTests, StylusDragAndDrop) {
Arthur Hungb75c2aa2022-07-15 09:35:36 +000010991 startDrag(true, AINPUT_SOURCE_STYLUS);
arthurhung6d4bed92021-03-17 11:59:33 +080010992
10993 // Move on window and keep button pressed.
10994 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070010995 injectMotionEvent(*mDispatcher,
arthurhung6d4bed92021-03-17 11:59:33 +080010996 MotionEventBuilder(AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_STYLUS)
10997 .buttonState(AMOTION_EVENT_BUTTON_STYLUS_PRIMARY)
Siarhei Vishniakou6d73f832022-07-21 17:27:03 -070010998 .pointer(PointerBuilder(0, ToolType::STYLUS).x(50).y(50))
arthurhung6d4bed92021-03-17 11:59:33 +080010999 .build()))
11000 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
Prabir Pradhan65455c72024-02-13 21:46:41 +000011001 mDragWindow->consumeMotionMove(ADISPLAY_ID_DEFAULT, AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
arthurhung6d4bed92021-03-17 11:59:33 +080011002 mWindow->consumeDragEvent(false, 50, 50);
11003 mSecondWindow->assertNoEvents();
11004
11005 // Move to another window and release button, expect to drop item.
11006 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070011007 injectMotionEvent(*mDispatcher,
arthurhung6d4bed92021-03-17 11:59:33 +080011008 MotionEventBuilder(AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_STYLUS)
11009 .buttonState(0)
Siarhei Vishniakou6d73f832022-07-21 17:27:03 -070011010 .pointer(PointerBuilder(0, ToolType::STYLUS).x(150).y(50))
arthurhung6d4bed92021-03-17 11:59:33 +080011011 .build()))
11012 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
Prabir Pradhan65455c72024-02-13 21:46:41 +000011013 mDragWindow->consumeMotionMove(ADISPLAY_ID_DEFAULT, AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
arthurhung6d4bed92021-03-17 11:59:33 +080011014 mWindow->assertNoEvents();
11015 mSecondWindow->assertNoEvents();
Siarhei Vishniakoua66d65e2023-06-16 10:32:51 -070011016 mFakePolicy->assertDropTargetEquals(*mDispatcher, mSecondWindow->getToken());
arthurhung6d4bed92021-03-17 11:59:33 +080011017
11018 // nothing to the window.
11019 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070011020 injectMotionEvent(*mDispatcher,
arthurhung6d4bed92021-03-17 11:59:33 +080011021 MotionEventBuilder(AMOTION_EVENT_ACTION_UP, AINPUT_SOURCE_STYLUS)
11022 .buttonState(0)
Siarhei Vishniakou6d73f832022-07-21 17:27:03 -070011023 .pointer(PointerBuilder(0, ToolType::STYLUS).x(150).y(50))
arthurhung6d4bed92021-03-17 11:59:33 +080011024 .build()))
11025 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
Prabir Pradhan65455c72024-02-13 21:46:41 +000011026 mDragWindow->consumeMotionUp(ADISPLAY_ID_DEFAULT, AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
arthurhung6d4bed92021-03-17 11:59:33 +080011027 mWindow->assertNoEvents();
11028 mSecondWindow->assertNoEvents();
11029}
11030
Arthur Hung54745652022-04-20 07:17:41 +000011031TEST_F(InputDispatcherDragTests, DragAndDropOnInvalidWindow) {
Arthur Hungb75c2aa2022-07-15 09:35:36 +000011032 startDrag();
Arthur Hung6d0571e2021-04-09 20:18:16 +080011033
11034 // Set second window invisible.
11035 mSecondWindow->setVisible(false);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070011036 mDispatcher->onWindowInfosChanged(
11037 {{*mDragWindow->getInfo(), *mWindow->getInfo(), *mSecondWindow->getInfo()}, {}, 0, 0});
Arthur Hung6d0571e2021-04-09 20:18:16 +080011038
11039 // Move on window.
11040 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070011041 injectMotionEvent(*mDispatcher, AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN,
Arthur Hung6d0571e2021-04-09 20:18:16 +080011042 ADISPLAY_ID_DEFAULT, {50, 50}))
11043 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
Prabir Pradhan65455c72024-02-13 21:46:41 +000011044 mDragWindow->consumeMotionMove(ADISPLAY_ID_DEFAULT, AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
Arthur Hung6d0571e2021-04-09 20:18:16 +080011045 mWindow->consumeDragEvent(false, 50, 50);
11046 mSecondWindow->assertNoEvents();
11047
11048 // Move to another window.
11049 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070011050 injectMotionEvent(*mDispatcher, AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN,
Arthur Hung6d0571e2021-04-09 20:18:16 +080011051 ADISPLAY_ID_DEFAULT, {150, 50}))
11052 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
Prabir Pradhan65455c72024-02-13 21:46:41 +000011053 mDragWindow->consumeMotionMove(ADISPLAY_ID_DEFAULT, AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
Arthur Hung6d0571e2021-04-09 20:18:16 +080011054 mWindow->consumeDragEvent(true, 150, 50);
11055 mSecondWindow->assertNoEvents();
11056
11057 // drop to another window.
11058 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070011059 injectMotionUp(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
Arthur Hung6d0571e2021-04-09 20:18:16 +080011060 {150, 50}))
11061 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
Prabir Pradhan65455c72024-02-13 21:46:41 +000011062 mDragWindow->consumeMotionUp(ADISPLAY_ID_DEFAULT, AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
Siarhei Vishniakoua66d65e2023-06-16 10:32:51 -070011063 mFakePolicy->assertDropTargetEquals(*mDispatcher, nullptr);
Arthur Hung6d0571e2021-04-09 20:18:16 +080011064 mWindow->assertNoEvents();
11065 mSecondWindow->assertNoEvents();
11066}
11067
Arthur Hung54745652022-04-20 07:17:41 +000011068TEST_F(InputDispatcherDragTests, NoDragAndDropWhenMultiFingers) {
Arthur Hungb75c2aa2022-07-15 09:35:36 +000011069 // Ensure window could track pointerIds if it didn't support split touch.
11070 mWindow->setPreventSplitting(true);
11071
Arthur Hung54745652022-04-20 07:17:41 +000011072 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070011073 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
Arthur Hung54745652022-04-20 07:17:41 +000011074 {50, 50}))
11075 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
11076 mWindow->consumeMotionDown(ADISPLAY_ID_DEFAULT);
11077
11078 const MotionEvent secondFingerDownEvent =
11079 MotionEventBuilder(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
11080 .displayId(ADISPLAY_ID_DEFAULT)
11081 .eventTime(systemTime(SYSTEM_TIME_MONOTONIC))
Siarhei Vishniakou6d73f832022-07-21 17:27:03 -070011082 .pointer(PointerBuilder(/*id=*/0, ToolType::FINGER).x(50).y(50))
11083 .pointer(PointerBuilder(/*id=*/1, ToolType::FINGER).x(75).y(50))
Arthur Hung54745652022-04-20 07:17:41 +000011084 .build();
11085 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070011086 injectMotionEvent(*mDispatcher, secondFingerDownEvent, INJECT_EVENT_TIMEOUT,
Arthur Hung54745652022-04-20 07:17:41 +000011087 InputEventInjectionSync::WAIT_FOR_RESULT))
11088 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
Harry Cutts33476232023-01-30 19:57:29 +000011089 mWindow->consumeMotionPointerDown(/*pointerIndex=*/1);
Arthur Hung54745652022-04-20 07:17:41 +000011090
11091 // Should not perform drag and drop when window has multi fingers.
Arthur Hungb75c2aa2022-07-15 09:35:36 +000011092 ASSERT_FALSE(startDrag(false));
Arthur Hung54745652022-04-20 07:17:41 +000011093}
11094
11095TEST_F(InputDispatcherDragTests, DragAndDropWhenSplitTouch) {
11096 // First down on second window.
11097 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070011098 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
Arthur Hung54745652022-04-20 07:17:41 +000011099 {150, 50}))
11100 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
11101
11102 mSecondWindow->consumeMotionDown(ADISPLAY_ID_DEFAULT);
11103
11104 // Second down on first window.
11105 const MotionEvent secondFingerDownEvent =
11106 MotionEventBuilder(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
11107 .displayId(ADISPLAY_ID_DEFAULT)
11108 .eventTime(systemTime(SYSTEM_TIME_MONOTONIC))
Siarhei Vishniakou6d73f832022-07-21 17:27:03 -070011109 .pointer(PointerBuilder(/*id=*/0, ToolType::FINGER).x(150).y(50))
11110 .pointer(PointerBuilder(/*id=*/1, ToolType::FINGER).x(50).y(50))
Arthur Hung54745652022-04-20 07:17:41 +000011111 .build();
11112 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070011113 injectMotionEvent(*mDispatcher, secondFingerDownEvent, INJECT_EVENT_TIMEOUT,
Arthur Hung54745652022-04-20 07:17:41 +000011114 InputEventInjectionSync::WAIT_FOR_RESULT))
11115 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
11116 mWindow->consumeMotionDown(ADISPLAY_ID_DEFAULT);
Prabir Pradhan9d5f9ce2024-01-24 00:03:41 +000011117 mSecondWindow->consumeMotionMove(ADISPLAY_ID_DEFAULT);
Arthur Hung54745652022-04-20 07:17:41 +000011118
11119 // Perform drag and drop from first window.
Arthur Hungb75c2aa2022-07-15 09:35:36 +000011120 ASSERT_TRUE(startDrag(false));
Arthur Hung54745652022-04-20 07:17:41 +000011121
11122 // Move on window.
11123 const MotionEvent secondFingerMoveEvent =
11124 MotionEventBuilder(AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN)
11125 .eventTime(systemTime(SYSTEM_TIME_MONOTONIC))
Siarhei Vishniakou6d73f832022-07-21 17:27:03 -070011126 .pointer(PointerBuilder(/*id=*/0, ToolType::FINGER).x(150).y(50))
11127 .pointer(PointerBuilder(/*id=*/1, ToolType::FINGER).x(50).y(50))
Arthur Hung54745652022-04-20 07:17:41 +000011128 .build();
11129 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070011130 injectMotionEvent(*mDispatcher, secondFingerMoveEvent, INJECT_EVENT_TIMEOUT,
Arthur Hung54745652022-04-20 07:17:41 +000011131 InputEventInjectionSync::WAIT_FOR_RESULT));
Prabir Pradhan65455c72024-02-13 21:46:41 +000011132 mDragWindow->consumeMotionMove(ADISPLAY_ID_DEFAULT, AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
Arthur Hung54745652022-04-20 07:17:41 +000011133 mWindow->consumeDragEvent(false, 50, 50);
11134 mSecondWindow->consumeMotionMove();
11135
11136 // Release the drag pointer should perform drop.
11137 const MotionEvent secondFingerUpEvent =
11138 MotionEventBuilder(POINTER_1_UP, AINPUT_SOURCE_TOUCHSCREEN)
11139 .eventTime(systemTime(SYSTEM_TIME_MONOTONIC))
Siarhei Vishniakou6d73f832022-07-21 17:27:03 -070011140 .pointer(PointerBuilder(/*id=*/0, ToolType::FINGER).x(150).y(50))
11141 .pointer(PointerBuilder(/*id=*/1, ToolType::FINGER).x(50).y(50))
Arthur Hung54745652022-04-20 07:17:41 +000011142 .build();
11143 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070011144 injectMotionEvent(*mDispatcher, secondFingerUpEvent, INJECT_EVENT_TIMEOUT,
Arthur Hung54745652022-04-20 07:17:41 +000011145 InputEventInjectionSync::WAIT_FOR_RESULT));
Prabir Pradhan65455c72024-02-13 21:46:41 +000011146 mDragWindow->consumeMotionUp(ADISPLAY_ID_DEFAULT, AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
Siarhei Vishniakoua66d65e2023-06-16 10:32:51 -070011147 mFakePolicy->assertDropTargetEquals(*mDispatcher, mWindow->getToken());
Arthur Hung54745652022-04-20 07:17:41 +000011148 mWindow->assertNoEvents();
11149 mSecondWindow->consumeMotionMove();
11150}
11151
Arthur Hung3915c1f2022-05-31 07:17:17 +000011152TEST_F(InputDispatcherDragTests, DragAndDropWhenMultiDisplays) {
Arthur Hungb75c2aa2022-07-15 09:35:36 +000011153 startDrag();
Arthur Hung3915c1f2022-05-31 07:17:17 +000011154
11155 // Update window of second display.
11156 sp<FakeWindowHandle> windowInSecondary =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -070011157 sp<FakeWindowHandle>::make(mApp, mDispatcher, "D_2", SECOND_DISPLAY_ID);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070011158 mDispatcher->onWindowInfosChanged(
11159 {{*mDragWindow->getInfo(), *mSpyWindow->getInfo(), *mWindow->getInfo(),
11160 *mSecondWindow->getInfo(), *windowInSecondary->getInfo()},
11161 {},
11162 0,
11163 0});
Arthur Hung3915c1f2022-05-31 07:17:17 +000011164
11165 // Let second display has a touch state.
11166 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070011167 injectMotionEvent(*mDispatcher,
Arthur Hung3915c1f2022-05-31 07:17:17 +000011168 MotionEventBuilder(AMOTION_EVENT_ACTION_DOWN,
11169 AINPUT_SOURCE_TOUCHSCREEN)
11170 .displayId(SECOND_DISPLAY_ID)
Siarhei Vishniakou6d73f832022-07-21 17:27:03 -070011171 .pointer(PointerBuilder(0, ToolType::FINGER).x(100).y(100))
Arthur Hung3915c1f2022-05-31 07:17:17 +000011172 .build()));
Prabir Pradhan7662a8d2023-12-15 01:58:14 +000011173 windowInSecondary->consumeMotionDown(SECOND_DISPLAY_ID, /*expectedFlag=*/0);
Arthur Hung3915c1f2022-05-31 07:17:17 +000011174 // Update window again.
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070011175 mDispatcher->onWindowInfosChanged(
11176 {{*mDragWindow->getInfo(), *mSpyWindow->getInfo(), *mWindow->getInfo(),
11177 *mSecondWindow->getInfo(), *windowInSecondary->getInfo()},
11178 {},
11179 0,
11180 0});
Arthur Hung3915c1f2022-05-31 07:17:17 +000011181
11182 // Move on window.
11183 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070011184 injectMotionEvent(*mDispatcher, AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN,
Arthur Hung3915c1f2022-05-31 07:17:17 +000011185 ADISPLAY_ID_DEFAULT, {50, 50}))
11186 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
Prabir Pradhan65455c72024-02-13 21:46:41 +000011187 mDragWindow->consumeMotionMove(ADISPLAY_ID_DEFAULT, AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
Arthur Hung3915c1f2022-05-31 07:17:17 +000011188 mWindow->consumeDragEvent(false, 50, 50);
11189 mSecondWindow->assertNoEvents();
11190
11191 // Move to another window.
11192 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070011193 injectMotionEvent(*mDispatcher, AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN,
Arthur Hung3915c1f2022-05-31 07:17:17 +000011194 ADISPLAY_ID_DEFAULT, {150, 50}))
11195 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
Prabir Pradhan65455c72024-02-13 21:46:41 +000011196 mDragWindow->consumeMotionMove(ADISPLAY_ID_DEFAULT, AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
Arthur Hung3915c1f2022-05-31 07:17:17 +000011197 mWindow->consumeDragEvent(true, 150, 50);
11198 mSecondWindow->consumeDragEvent(false, 50, 50);
11199
11200 // drop to another window.
11201 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070011202 injectMotionUp(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
Arthur Hung3915c1f2022-05-31 07:17:17 +000011203 {150, 50}))
11204 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
Prabir Pradhan65455c72024-02-13 21:46:41 +000011205 mDragWindow->consumeMotionUp(ADISPLAY_ID_DEFAULT, AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
Siarhei Vishniakoua66d65e2023-06-16 10:32:51 -070011206 mFakePolicy->assertDropTargetEquals(*mDispatcher, mSecondWindow->getToken());
Arthur Hung3915c1f2022-05-31 07:17:17 +000011207 mWindow->assertNoEvents();
11208 mSecondWindow->assertNoEvents();
11209}
11210
Arthur Hungb75c2aa2022-07-15 09:35:36 +000011211TEST_F(InputDispatcherDragTests, MouseDragAndDrop) {
11212 startDrag(true, AINPUT_SOURCE_MOUSE);
11213 // Move on window.
11214 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070011215 injectMotionEvent(*mDispatcher,
Arthur Hungb75c2aa2022-07-15 09:35:36 +000011216 MotionEventBuilder(AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_MOUSE)
11217 .buttonState(AMOTION_EVENT_BUTTON_PRIMARY)
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070011218 .pointer(PointerBuilder(MOUSE_POINTER_ID, ToolType::MOUSE)
Arthur Hungb75c2aa2022-07-15 09:35:36 +000011219 .x(50)
11220 .y(50))
11221 .build()))
11222 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
Prabir Pradhan65455c72024-02-13 21:46:41 +000011223 mDragWindow->consumeMotionMove(ADISPLAY_ID_DEFAULT, AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
Arthur Hungb75c2aa2022-07-15 09:35:36 +000011224 mWindow->consumeDragEvent(false, 50, 50);
11225 mSecondWindow->assertNoEvents();
11226
11227 // Move to another window.
11228 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070011229 injectMotionEvent(*mDispatcher,
Arthur Hungb75c2aa2022-07-15 09:35:36 +000011230 MotionEventBuilder(AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_MOUSE)
11231 .buttonState(AMOTION_EVENT_BUTTON_PRIMARY)
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070011232 .pointer(PointerBuilder(MOUSE_POINTER_ID, ToolType::MOUSE)
Arthur Hungb75c2aa2022-07-15 09:35:36 +000011233 .x(150)
11234 .y(50))
11235 .build()))
11236 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
Prabir Pradhan65455c72024-02-13 21:46:41 +000011237 mDragWindow->consumeMotionMove(ADISPLAY_ID_DEFAULT, AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
Arthur Hungb75c2aa2022-07-15 09:35:36 +000011238 mWindow->consumeDragEvent(true, 150, 50);
11239 mSecondWindow->consumeDragEvent(false, 50, 50);
11240
11241 // drop to another window.
11242 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070011243 injectMotionEvent(*mDispatcher,
Arthur Hungb75c2aa2022-07-15 09:35:36 +000011244 MotionEventBuilder(AMOTION_EVENT_ACTION_UP, AINPUT_SOURCE_MOUSE)
11245 .buttonState(0)
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070011246 .pointer(PointerBuilder(MOUSE_POINTER_ID, ToolType::MOUSE)
Arthur Hungb75c2aa2022-07-15 09:35:36 +000011247 .x(150)
11248 .y(50))
11249 .build()))
11250 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
Prabir Pradhan65455c72024-02-13 21:46:41 +000011251 mDragWindow->consumeMotionUp(ADISPLAY_ID_DEFAULT, AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
Siarhei Vishniakoua66d65e2023-06-16 10:32:51 -070011252 mFakePolicy->assertDropTargetEquals(*mDispatcher, mSecondWindow->getToken());
Arthur Hungb75c2aa2022-07-15 09:35:36 +000011253 mWindow->assertNoEvents();
11254 mSecondWindow->assertNoEvents();
11255}
11256
Linnan Li5af92f92023-07-14 14:36:22 +080011257/**
11258 * Start drag and drop with a pointer whose id is not 0, cancel the current touch, and ensure drag
11259 * and drop is also canceled. Then inject a simple gesture, and ensure dispatcher does not crash.
11260 */
11261TEST_F(InputDispatcherDragTests, DragAndDropFinishedWhenCancelCurrentTouch) {
11262 // Down on second window
11263 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
11264 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
11265 {150, 50}))
11266 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
11267
11268 ASSERT_NO_FATAL_FAILURE(mSecondWindow->consumeMotionDown());
11269 ASSERT_NO_FATAL_FAILURE(mSpyWindow->consumeMotionDown());
11270
11271 // Down on first window
11272 const MotionEvent secondFingerDownEvent =
11273 MotionEventBuilder(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
11274 .displayId(ADISPLAY_ID_DEFAULT)
11275 .pointer(PointerBuilder(/*id=*/0, ToolType::FINGER).x(150).y(50))
11276 .pointer(PointerBuilder(/*id=*/1, ToolType::FINGER).x(50).y(50))
11277 .build();
11278 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
11279 injectMotionEvent(*mDispatcher, secondFingerDownEvent, INJECT_EVENT_TIMEOUT,
11280 InputEventInjectionSync::WAIT_FOR_RESULT))
11281 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
11282 ASSERT_NO_FATAL_FAILURE(mWindow->consumeMotionDown());
11283 ASSERT_NO_FATAL_FAILURE(mSecondWindow->consumeMotionMove());
11284 ASSERT_NO_FATAL_FAILURE(mSpyWindow->consumeMotionPointerDown(1));
11285
11286 // Start drag on first window
11287 ASSERT_TRUE(startDrag(/*sendDown=*/false, AINPUT_SOURCE_TOUCHSCREEN));
11288
11289 // Trigger cancel
11290 mDispatcher->cancelCurrentTouch();
11291 ASSERT_NO_FATAL_FAILURE(mSecondWindow->consumeMotionCancel());
Prabir Pradhan65455c72024-02-13 21:46:41 +000011292 ASSERT_NO_FATAL_FAILURE(mDragWindow->consumeMotionCancel(ADISPLAY_ID_DEFAULT,
11293 AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE));
Linnan Li5af92f92023-07-14 14:36:22 +080011294 ASSERT_NO_FATAL_FAILURE(mSpyWindow->consumeMotionCancel());
11295
11296 ASSERT_TRUE(mDispatcher->waitForIdle());
11297 // The D&D finished with nullptr
11298 mFakePolicy->assertDropTargetEquals(*mDispatcher, nullptr);
11299
11300 // Remove drag window
11301 mDispatcher->onWindowInfosChanged({{*mWindow->getInfo(), *mSecondWindow->getInfo()}, {}, 0, 0});
11302
11303 // Inject a simple gesture, ensure dispatcher not crashed
11304 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
11305 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
11306 PointF{50, 50}))
11307 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
11308 ASSERT_NO_FATAL_FAILURE(mWindow->consumeMotionDown());
11309
11310 const MotionEvent moveEvent =
11311 MotionEventBuilder(AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN)
11312 .displayId(ADISPLAY_ID_DEFAULT)
11313 .pointer(PointerBuilder(/*id=*/0, ToolType::FINGER).x(50).y(50))
11314 .build();
11315 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
11316 injectMotionEvent(*mDispatcher, moveEvent, INJECT_EVENT_TIMEOUT,
11317 InputEventInjectionSync::WAIT_FOR_RESULT))
11318 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
11319 ASSERT_NO_FATAL_FAILURE(mWindow->consumeMotionMove());
11320
11321 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
11322 injectMotionUp(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
11323 {50, 50}))
11324 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
11325 ASSERT_NO_FATAL_FAILURE(mWindow->consumeMotionUp());
11326}
11327
Prabir Pradhan9cd9eb62023-11-22 17:58:06 +000011328TEST_F(InputDispatcherDragTests, NoDragAndDropWithHoveringPointer) {
11329 // Start hovering over the window.
11330 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
11331 injectMotionEvent(*mDispatcher, ACTION_HOVER_ENTER, AINPUT_SOURCE_MOUSE,
11332 ADISPLAY_ID_DEFAULT, {50, 50}));
11333
11334 ASSERT_NO_FATAL_FAILURE(mWindow->consumeMotionEvent(WithMotionAction(ACTION_HOVER_ENTER)));
11335 ASSERT_NO_FATAL_FAILURE(mSpyWindow->consumeMotionEvent(WithMotionAction(ACTION_HOVER_ENTER)));
11336
11337 ASSERT_FALSE(startDrag(/*sendDown=*/false))
11338 << "Drag and drop should not work with a hovering pointer";
11339}
11340
Vishnu Nair062a8672021-09-03 16:07:44 -070011341class InputDispatcherDropInputFeatureTest : public InputDispatcherTest {};
11342
11343TEST_F(InputDispatcherDropInputFeatureTest, WindowDropsInput) {
11344 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -070011345 sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher,
11346 "Test window", ADISPLAY_ID_DEFAULT);
Prabir Pradhan51e7db02022-02-07 06:02:57 -080011347 window->setDropInput(true);
Vishnu Nair062a8672021-09-03 16:07:44 -070011348 mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application);
11349 window->setFocusable(true);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070011350 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Vishnu Nair062a8672021-09-03 16:07:44 -070011351 setFocusedWindow(window);
Harry Cutts33476232023-01-30 19:57:29 +000011352 window->consumeFocusEvent(/*hasFocus=*/true, /*inTouchMode=*/true);
Vishnu Nair062a8672021-09-03 16:07:44 -070011353
11354 // With the flag set, window should not get any input
Prabir Pradhan678438e2023-04-13 19:32:51 +000011355 mDispatcher->notifyKey(generateKeyArgs(AKEY_EVENT_ACTION_DOWN, ADISPLAY_ID_DEFAULT));
Vishnu Nair062a8672021-09-03 16:07:44 -070011356 window->assertNoEvents();
11357
Prabir Pradhan678438e2023-04-13 19:32:51 +000011358 mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_DOWN,
11359 AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT));
Siarhei Vishniakou5c02a712023-05-15 15:45:02 -070011360 mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN,
11361 ADISPLAY_ID_DEFAULT));
Siarhei Vishniakoud908f5a2023-11-16 10:25:12 -080011362 mDispatcher->waitForIdle();
Vishnu Nair062a8672021-09-03 16:07:44 -070011363 window->assertNoEvents();
11364
11365 // With the flag cleared, the window should get input
Prabir Pradhan51e7db02022-02-07 06:02:57 -080011366 window->setDropInput(false);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070011367 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Vishnu Nair062a8672021-09-03 16:07:44 -070011368
Prabir Pradhan678438e2023-04-13 19:32:51 +000011369 mDispatcher->notifyKey(generateKeyArgs(AKEY_EVENT_ACTION_UP, ADISPLAY_ID_DEFAULT));
Vishnu Nair062a8672021-09-03 16:07:44 -070011370 window->consumeKeyUp(ADISPLAY_ID_DEFAULT);
11371
Prabir Pradhan678438e2023-04-13 19:32:51 +000011372 mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_DOWN,
11373 AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT));
Vishnu Nair062a8672021-09-03 16:07:44 -070011374 window->consumeMotionDown(ADISPLAY_ID_DEFAULT);
11375 window->assertNoEvents();
11376}
11377
11378TEST_F(InputDispatcherDropInputFeatureTest, ObscuredWindowDropsInput) {
11379 std::shared_ptr<FakeApplicationHandle> obscuringApplication =
11380 std::make_shared<FakeApplicationHandle>();
11381 sp<FakeWindowHandle> obscuringWindow =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -070011382 sp<FakeWindowHandle>::make(obscuringApplication, mDispatcher, "obscuringWindow",
11383 ADISPLAY_ID_DEFAULT);
Vishnu Nair062a8672021-09-03 16:07:44 -070011384 obscuringWindow->setFrame(Rect(0, 0, 50, 50));
Prabir Pradhanaeebeb42023-06-13 19:53:03 +000011385 obscuringWindow->setOwnerInfo(gui::Pid{111}, gui::Uid{111});
Prabir Pradhan4d5c52f2022-01-31 08:52:10 -080011386 obscuringWindow->setTouchable(false);
Vishnu Nair062a8672021-09-03 16:07:44 -070011387 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -070011388 sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher,
11389 "Test window", ADISPLAY_ID_DEFAULT);
Prabir Pradhan51e7db02022-02-07 06:02:57 -080011390 window->setDropInputIfObscured(true);
Prabir Pradhanaeebeb42023-06-13 19:53:03 +000011391 window->setOwnerInfo(gui::Pid{222}, gui::Uid{222});
Vishnu Nair062a8672021-09-03 16:07:44 -070011392 mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application);
11393 window->setFocusable(true);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070011394 mDispatcher->onWindowInfosChanged(
11395 {{*obscuringWindow->getInfo(), *window->getInfo()}, {}, 0, 0});
Vishnu Nair062a8672021-09-03 16:07:44 -070011396 setFocusedWindow(window);
Harry Cutts33476232023-01-30 19:57:29 +000011397 window->consumeFocusEvent(/*hasFocus=*/true, /*inTouchMode=*/true);
Vishnu Nair062a8672021-09-03 16:07:44 -070011398
11399 // With the flag set, window should not get any input
Prabir Pradhan678438e2023-04-13 19:32:51 +000011400 mDispatcher->notifyKey(generateKeyArgs(AKEY_EVENT_ACTION_DOWN, ADISPLAY_ID_DEFAULT));
Vishnu Nair062a8672021-09-03 16:07:44 -070011401 window->assertNoEvents();
11402
Prabir Pradhan678438e2023-04-13 19:32:51 +000011403 mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_DOWN,
11404 AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT));
Siarhei Vishniakou5c02a712023-05-15 15:45:02 -070011405 mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN,
11406 ADISPLAY_ID_DEFAULT));
Vishnu Nair062a8672021-09-03 16:07:44 -070011407 window->assertNoEvents();
11408
11409 // With the flag cleared, the window should get input
Prabir Pradhan51e7db02022-02-07 06:02:57 -080011410 window->setDropInputIfObscured(false);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070011411 mDispatcher->onWindowInfosChanged(
11412 {{*obscuringWindow->getInfo(), *window->getInfo()}, {}, 0, 0});
Vishnu Nair062a8672021-09-03 16:07:44 -070011413
Prabir Pradhan678438e2023-04-13 19:32:51 +000011414 mDispatcher->notifyKey(generateKeyArgs(AKEY_EVENT_ACTION_UP, ADISPLAY_ID_DEFAULT));
Vishnu Nair062a8672021-09-03 16:07:44 -070011415 window->consumeKeyUp(ADISPLAY_ID_DEFAULT);
11416
Prabir Pradhan678438e2023-04-13 19:32:51 +000011417 mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_DOWN,
11418 AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT));
Vishnu Nair062a8672021-09-03 16:07:44 -070011419 window->consumeMotionDown(ADISPLAY_ID_DEFAULT, AMOTION_EVENT_FLAG_WINDOW_IS_PARTIALLY_OBSCURED);
11420 window->assertNoEvents();
11421}
11422
11423TEST_F(InputDispatcherDropInputFeatureTest, UnobscuredWindowGetsInput) {
11424 std::shared_ptr<FakeApplicationHandle> obscuringApplication =
11425 std::make_shared<FakeApplicationHandle>();
11426 sp<FakeWindowHandle> obscuringWindow =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -070011427 sp<FakeWindowHandle>::make(obscuringApplication, mDispatcher, "obscuringWindow",
11428 ADISPLAY_ID_DEFAULT);
Vishnu Nair062a8672021-09-03 16:07:44 -070011429 obscuringWindow->setFrame(Rect(0, 0, 50, 50));
Prabir Pradhanaeebeb42023-06-13 19:53:03 +000011430 obscuringWindow->setOwnerInfo(gui::Pid{111}, gui::Uid{111});
Prabir Pradhan4d5c52f2022-01-31 08:52:10 -080011431 obscuringWindow->setTouchable(false);
Vishnu Nair062a8672021-09-03 16:07:44 -070011432 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -070011433 sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher,
11434 "Test window", ADISPLAY_ID_DEFAULT);
Prabir Pradhan51e7db02022-02-07 06:02:57 -080011435 window->setDropInputIfObscured(true);
Prabir Pradhanaeebeb42023-06-13 19:53:03 +000011436 window->setOwnerInfo(gui::Pid{222}, gui::Uid{222});
Vishnu Nair062a8672021-09-03 16:07:44 -070011437 mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application);
11438 window->setFocusable(true);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070011439 mDispatcher->onWindowInfosChanged(
11440 {{*obscuringWindow->getInfo(), *window->getInfo()}, {}, 0, 0});
Vishnu Nair062a8672021-09-03 16:07:44 -070011441 setFocusedWindow(window);
Harry Cutts33476232023-01-30 19:57:29 +000011442 window->consumeFocusEvent(/*hasFocus=*/true, /*inTouchMode=*/true);
Vishnu Nair062a8672021-09-03 16:07:44 -070011443
11444 // With the flag set, window should not get any input
Prabir Pradhan678438e2023-04-13 19:32:51 +000011445 mDispatcher->notifyKey(generateKeyArgs(AKEY_EVENT_ACTION_DOWN, ADISPLAY_ID_DEFAULT));
Vishnu Nair062a8672021-09-03 16:07:44 -070011446 window->assertNoEvents();
11447
Prabir Pradhan678438e2023-04-13 19:32:51 +000011448 mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_DOWN,
11449 AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT));
Siarhei Vishniakou5c02a712023-05-15 15:45:02 -070011450 mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN,
11451 ADISPLAY_ID_DEFAULT));
Vishnu Nair062a8672021-09-03 16:07:44 -070011452 window->assertNoEvents();
11453
11454 // When the window is no longer obscured because it went on top, it should get input
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070011455 mDispatcher->onWindowInfosChanged(
11456 {{*window->getInfo(), *obscuringWindow->getInfo()}, {}, 0, 0});
Vishnu Nair062a8672021-09-03 16:07:44 -070011457
Prabir Pradhan678438e2023-04-13 19:32:51 +000011458 mDispatcher->notifyKey(generateKeyArgs(AKEY_EVENT_ACTION_UP, ADISPLAY_ID_DEFAULT));
Vishnu Nair062a8672021-09-03 16:07:44 -070011459 window->consumeKeyUp(ADISPLAY_ID_DEFAULT);
11460
Prabir Pradhan678438e2023-04-13 19:32:51 +000011461 mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_DOWN,
11462 AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT));
Vishnu Nair062a8672021-09-03 16:07:44 -070011463 window->consumeMotionDown(ADISPLAY_ID_DEFAULT);
11464 window->assertNoEvents();
11465}
11466
Antonio Kantekf16f2832021-09-28 04:39:20 +000011467class InputDispatcherTouchModeChangedTests : public InputDispatcherTest {
11468protected:
11469 std::shared_ptr<FakeApplicationHandle> mApp;
Antonio Kantek15beb512022-06-13 22:35:41 +000011470 std::shared_ptr<FakeApplicationHandle> mSecondaryApp;
Antonio Kantekf16f2832021-09-28 04:39:20 +000011471 sp<FakeWindowHandle> mWindow;
11472 sp<FakeWindowHandle> mSecondWindow;
Antonio Kantek15beb512022-06-13 22:35:41 +000011473 sp<FakeWindowHandle> mThirdWindow;
Antonio Kantekf16f2832021-09-28 04:39:20 +000011474
11475 void SetUp() override {
11476 InputDispatcherTest::SetUp();
11477
11478 mApp = std::make_shared<FakeApplicationHandle>();
Antonio Kantek15beb512022-06-13 22:35:41 +000011479 mSecondaryApp = std::make_shared<FakeApplicationHandle>();
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -070011480 mWindow = sp<FakeWindowHandle>::make(mApp, mDispatcher, "TestWindow", ADISPLAY_ID_DEFAULT);
Antonio Kantekf16f2832021-09-28 04:39:20 +000011481 mWindow->setFocusable(true);
Antonio Kantek26defcf2022-02-08 01:12:27 +000011482 setFocusedWindow(mWindow);
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -070011483 mSecondWindow =
11484 sp<FakeWindowHandle>::make(mApp, mDispatcher, "TestWindow2", ADISPLAY_ID_DEFAULT);
Antonio Kantekf16f2832021-09-28 04:39:20 +000011485 mSecondWindow->setFocusable(true);
Antonio Kantek15beb512022-06-13 22:35:41 +000011486 mThirdWindow =
11487 sp<FakeWindowHandle>::make(mSecondaryApp, mDispatcher,
11488 "TestWindow3_SecondaryDisplay", SECOND_DISPLAY_ID);
11489 mThirdWindow->setFocusable(true);
Antonio Kantekf16f2832021-09-28 04:39:20 +000011490
11491 mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, mApp);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070011492 mDispatcher->onWindowInfosChanged(
11493 {{*mWindow->getInfo(), *mSecondWindow->getInfo(), *mThirdWindow->getInfo()},
11494 {},
11495 0,
11496 0});
Antonio Kantek15beb512022-06-13 22:35:41 +000011497 mThirdWindow->setOwnerInfo(SECONDARY_WINDOW_PID, SECONDARY_WINDOW_UID);
Antonio Kantekf16f2832021-09-28 04:39:20 +000011498 mWindow->consumeFocusEvent(true);
Antonio Kantek26defcf2022-02-08 01:12:27 +000011499
Antonio Kantek15beb512022-06-13 22:35:41 +000011500 // Set main display initial touch mode to InputDispatcher::kDefaultInTouchMode.
Prabir Pradhan5735a322022-04-11 17:23:34 +000011501 if (mDispatcher->setInTouchMode(InputDispatcher::kDefaultInTouchMode, WINDOW_PID,
Harry Cutts33476232023-01-30 19:57:29 +000011502 WINDOW_UID, /*hasPermission=*/true, ADISPLAY_ID_DEFAULT)) {
Antonio Kantek48710e42022-03-24 14:19:30 -070011503 mWindow->consumeTouchModeEvent(InputDispatcher::kDefaultInTouchMode);
11504 mSecondWindow->consumeTouchModeEvent(InputDispatcher::kDefaultInTouchMode);
Antonio Kantek15beb512022-06-13 22:35:41 +000011505 mThirdWindow->assertNoEvents();
11506 }
11507
11508 // Set secondary display initial touch mode to InputDispatcher::kDefaultInTouchMode.
11509 if (mDispatcher->setInTouchMode(InputDispatcher::kDefaultInTouchMode, SECONDARY_WINDOW_PID,
Harry Cutts33476232023-01-30 19:57:29 +000011510 SECONDARY_WINDOW_UID, /*hasPermission=*/true,
Antonio Kantek15beb512022-06-13 22:35:41 +000011511 SECOND_DISPLAY_ID)) {
11512 mWindow->assertNoEvents();
11513 mSecondWindow->assertNoEvents();
11514 mThirdWindow->consumeTouchModeEvent(InputDispatcher::kDefaultInTouchMode);
Antonio Kantek48710e42022-03-24 14:19:30 -070011515 }
Antonio Kantekf16f2832021-09-28 04:39:20 +000011516 }
11517
Prabir Pradhanaeebeb42023-06-13 19:53:03 +000011518 void changeAndVerifyTouchModeInMainDisplayOnly(bool inTouchMode, gui::Pid pid, gui::Uid uid,
Antonio Kantek15beb512022-06-13 22:35:41 +000011519 bool hasPermission) {
Antonio Kanteka042c022022-07-06 16:51:07 -070011520 ASSERT_TRUE(mDispatcher->setInTouchMode(inTouchMode, pid, uid, hasPermission,
11521 ADISPLAY_ID_DEFAULT));
Antonio Kantekf16f2832021-09-28 04:39:20 +000011522 mWindow->consumeTouchModeEvent(inTouchMode);
11523 mSecondWindow->consumeTouchModeEvent(inTouchMode);
Antonio Kantek15beb512022-06-13 22:35:41 +000011524 mThirdWindow->assertNoEvents();
Antonio Kantekf16f2832021-09-28 04:39:20 +000011525 }
11526};
11527
Antonio Kantek26defcf2022-02-08 01:12:27 +000011528TEST_F(InputDispatcherTouchModeChangedTests, FocusedWindowCanChangeTouchMode) {
Antonio Kantekea47acb2021-12-23 12:41:25 -080011529 const WindowInfo& windowInfo = *mWindow->getInfo();
Antonio Kantek15beb512022-06-13 22:35:41 +000011530 changeAndVerifyTouchModeInMainDisplayOnly(!InputDispatcher::kDefaultInTouchMode,
11531 windowInfo.ownerPid, windowInfo.ownerUid,
Harry Cutts33476232023-01-30 19:57:29 +000011532 /* hasPermission=*/false);
Antonio Kantekf16f2832021-09-28 04:39:20 +000011533}
11534
Antonio Kantek26defcf2022-02-08 01:12:27 +000011535TEST_F(InputDispatcherTouchModeChangedTests, NonFocusedWindowOwnerCannotChangeTouchMode) {
11536 const WindowInfo& windowInfo = *mWindow->getInfo();
Prabir Pradhanaeebeb42023-06-13 19:53:03 +000011537 gui::Pid ownerPid = windowInfo.ownerPid;
Prabir Pradhan8a5c41d2023-06-08 19:13:46 +000011538 gui::Uid ownerUid = windowInfo.ownerUid;
Prabir Pradhanaeebeb42023-06-13 19:53:03 +000011539 mWindow->setOwnerInfo(gui::Pid::INVALID, gui::Uid::INVALID);
Antonio Kantek26defcf2022-02-08 01:12:27 +000011540 ASSERT_FALSE(mDispatcher->setInTouchMode(InputDispatcher::kDefaultInTouchMode, ownerPid,
Harry Cutts33476232023-01-30 19:57:29 +000011541 ownerUid, /*hasPermission=*/false,
Antonio Kanteka042c022022-07-06 16:51:07 -070011542 ADISPLAY_ID_DEFAULT));
Antonio Kantek26defcf2022-02-08 01:12:27 +000011543 mWindow->assertNoEvents();
11544 mSecondWindow->assertNoEvents();
11545}
11546
11547TEST_F(InputDispatcherTouchModeChangedTests, NonWindowOwnerMayChangeTouchModeOnPermissionGranted) {
11548 const WindowInfo& windowInfo = *mWindow->getInfo();
Prabir Pradhanaeebeb42023-06-13 19:53:03 +000011549 gui::Pid ownerPid = windowInfo.ownerPid;
Prabir Pradhan8a5c41d2023-06-08 19:13:46 +000011550 gui::Uid ownerUid = windowInfo.ownerUid;
Prabir Pradhanaeebeb42023-06-13 19:53:03 +000011551 mWindow->setOwnerInfo(gui::Pid::INVALID, gui::Uid::INVALID);
Antonio Kantek15beb512022-06-13 22:35:41 +000011552 changeAndVerifyTouchModeInMainDisplayOnly(!InputDispatcher::kDefaultInTouchMode, ownerPid,
Harry Cutts33476232023-01-30 19:57:29 +000011553 ownerUid, /*hasPermission=*/true);
Antonio Kantek26defcf2022-02-08 01:12:27 +000011554}
11555
Antonio Kantekf16f2832021-09-28 04:39:20 +000011556TEST_F(InputDispatcherTouchModeChangedTests, EventIsNotGeneratedIfNotChangingTouchMode) {
Antonio Kantekea47acb2021-12-23 12:41:25 -080011557 const WindowInfo& windowInfo = *mWindow->getInfo();
Antonio Kantek26defcf2022-02-08 01:12:27 +000011558 ASSERT_FALSE(mDispatcher->setInTouchMode(InputDispatcher::kDefaultInTouchMode,
11559 windowInfo.ownerPid, windowInfo.ownerUid,
Harry Cutts33476232023-01-30 19:57:29 +000011560 /*hasPermission=*/true, ADISPLAY_ID_DEFAULT));
Antonio Kantekf16f2832021-09-28 04:39:20 +000011561 mWindow->assertNoEvents();
11562 mSecondWindow->assertNoEvents();
11563}
11564
Antonio Kantek15beb512022-06-13 22:35:41 +000011565TEST_F(InputDispatcherTouchModeChangedTests, ChangeTouchOnSecondaryDisplayOnly) {
11566 const WindowInfo& windowInfo = *mThirdWindow->getInfo();
11567 ASSERT_TRUE(mDispatcher->setInTouchMode(!InputDispatcher::kDefaultInTouchMode,
11568 windowInfo.ownerPid, windowInfo.ownerUid,
Harry Cutts33476232023-01-30 19:57:29 +000011569 /*hasPermission=*/true, SECOND_DISPLAY_ID));
Antonio Kantek15beb512022-06-13 22:35:41 +000011570 mWindow->assertNoEvents();
11571 mSecondWindow->assertNoEvents();
11572 mThirdWindow->consumeTouchModeEvent(!InputDispatcher::kDefaultInTouchMode);
11573}
11574
Antonio Kantek48710e42022-03-24 14:19:30 -070011575TEST_F(InputDispatcherTouchModeChangedTests, CanChangeTouchModeWhenOwningLastInteractedWindow) {
11576 // Interact with the window first.
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070011577 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
11578 injectKeyDown(*mDispatcher, ADISPLAY_ID_DEFAULT))
Antonio Kantek48710e42022-03-24 14:19:30 -070011579 << "Inject key event should return InputEventInjectionResult::SUCCEEDED";
11580 mWindow->consumeKeyDown(ADISPLAY_ID_DEFAULT);
11581
11582 // Then remove focus.
11583 mWindow->setFocusable(false);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070011584 mDispatcher->onWindowInfosChanged({{*mWindow->getInfo()}, {}, 0, 0});
Antonio Kantek48710e42022-03-24 14:19:30 -070011585
11586 // Assert that caller can switch touch mode by owning one of the last interacted window.
11587 const WindowInfo& windowInfo = *mWindow->getInfo();
11588 ASSERT_TRUE(mDispatcher->setInTouchMode(!InputDispatcher::kDefaultInTouchMode,
11589 windowInfo.ownerPid, windowInfo.ownerUid,
Harry Cutts33476232023-01-30 19:57:29 +000011590 /*hasPermission=*/false, ADISPLAY_ID_DEFAULT));
Antonio Kantek48710e42022-03-24 14:19:30 -070011591}
11592
Prabir Pradhan07e05b62021-11-19 03:57:24 -080011593class InputDispatcherSpyWindowTest : public InputDispatcherTest {
11594public:
Prabir Pradhan4d5c52f2022-01-31 08:52:10 -080011595 sp<FakeWindowHandle> createSpy() {
Prabir Pradhan07e05b62021-11-19 03:57:24 -080011596 std::shared_ptr<FakeApplicationHandle> application =
11597 std::make_shared<FakeApplicationHandle>();
11598 std::string name = "Fake Spy ";
11599 name += std::to_string(mSpyCount++);
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -070011600 sp<FakeWindowHandle> spy = sp<FakeWindowHandle>::make(application, mDispatcher,
11601 name.c_str(), ADISPLAY_ID_DEFAULT);
Prabir Pradhan51e7db02022-02-07 06:02:57 -080011602 spy->setSpy(true);
Prabir Pradhan5c85e052021-12-22 02:27:12 -080011603 spy->setTrustedOverlay(true);
Prabir Pradhan07e05b62021-11-19 03:57:24 -080011604 return spy;
11605 }
11606
11607 sp<FakeWindowHandle> createForeground() {
11608 std::shared_ptr<FakeApplicationHandle> application =
11609 std::make_shared<FakeApplicationHandle>();
11610 sp<FakeWindowHandle> window =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -070011611 sp<FakeWindowHandle>::make(application, mDispatcher, "Fake Window",
11612 ADISPLAY_ID_DEFAULT);
Prabir Pradhan1376fcd2022-01-21 09:56:35 -080011613 window->setFocusable(true);
Prabir Pradhan07e05b62021-11-19 03:57:24 -080011614 return window;
11615 }
11616
11617private:
11618 int mSpyCount{0};
11619};
11620
Prabir Pradhana3ab87a2022-01-27 10:00:21 -080011621using InputDispatcherSpyWindowDeathTest = InputDispatcherSpyWindowTest;
Prabir Pradhan07e05b62021-11-19 03:57:24 -080011622/**
Prabir Pradhan5c85e052021-12-22 02:27:12 -080011623 * Adding a spy window that is not a trusted overlay causes Dispatcher to abort.
11624 */
Prabir Pradhana3ab87a2022-01-27 10:00:21 -080011625TEST_F(InputDispatcherSpyWindowDeathTest, UntrustedSpy_AbortsDispatcher) {
Siarhei Vishniakou21f77bd2023-07-18 17:51:35 -070011626 testing::GTEST_FLAG(death_test_style) = "threadsafe";
Prabir Pradhana3ab87a2022-01-27 10:00:21 -080011627 ScopedSilentDeath _silentDeath;
11628
Prabir Pradhan4d5c52f2022-01-31 08:52:10 -080011629 auto spy = createSpy();
Prabir Pradhan5c85e052021-12-22 02:27:12 -080011630 spy->setTrustedOverlay(false);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070011631 ASSERT_DEATH(mDispatcher->onWindowInfosChanged({{*spy->getInfo()}, {}, 0, 0}),
Prabir Pradhan5c85e052021-12-22 02:27:12 -080011632 ".* not a trusted overlay");
11633}
11634
11635/**
Prabir Pradhan07e05b62021-11-19 03:57:24 -080011636 * Input injection into a display with a spy window but no foreground windows should succeed.
11637 */
11638TEST_F(InputDispatcherSpyWindowTest, NoForegroundWindow) {
Prabir Pradhan4d5c52f2022-01-31 08:52:10 -080011639 auto spy = createSpy();
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070011640 mDispatcher->onWindowInfosChanged({{*spy->getInfo()}, {}, 0, 0});
Prabir Pradhan07e05b62021-11-19 03:57:24 -080011641
11642 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070011643 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT))
Prabir Pradhan07e05b62021-11-19 03:57:24 -080011644 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
11645 spy->consumeMotionDown(ADISPLAY_ID_DEFAULT);
11646}
11647
11648/**
11649 * Verify the order in which different input windows receive events. The touched foreground window
11650 * (if there is one) should always receive the event first. When there are multiple spy windows, the
11651 * spy windows will receive the event according to their Z-order, where the top-most spy window will
11652 * receive events before ones belows it.
11653 *
11654 * Here, we set up a scenario with four windows in the following Z order from the top:
11655 * spy1, spy2, window, spy3.
11656 * We then inject an event and verify that the foreground "window" receives it first, followed by
11657 * "spy1" and "spy2". The "spy3" does not receive the event because it is underneath the foreground
11658 * window.
11659 */
11660TEST_F(InputDispatcherSpyWindowTest, ReceivesInputInOrder) {
11661 auto window = createForeground();
Prabir Pradhan4d5c52f2022-01-31 08:52:10 -080011662 auto spy1 = createSpy();
11663 auto spy2 = createSpy();
11664 auto spy3 = createSpy();
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070011665 mDispatcher->onWindowInfosChanged(
11666 {{*spy1->getInfo(), *spy2->getInfo(), *window->getInfo(), *spy3->getInfo()}, {}, 0, 0});
Prabir Pradhan07e05b62021-11-19 03:57:24 -080011667 const std::vector<sp<FakeWindowHandle>> channels{spy1, spy2, window, spy3};
11668 const size_t numChannels = channels.size();
11669
Michael Wright8e9a8562022-02-09 13:44:29 +000011670 base::unique_fd epollFd(epoll_create1(EPOLL_CLOEXEC));
Prabir Pradhan07e05b62021-11-19 03:57:24 -080011671 if (!epollFd.ok()) {
11672 FAIL() << "Failed to create epoll fd";
11673 }
11674
11675 for (size_t i = 0; i < numChannels; i++) {
11676 struct epoll_event event = {.events = EPOLLIN, .data.u64 = i};
11677 if (epoll_ctl(epollFd.get(), EPOLL_CTL_ADD, channels[i]->getChannelFd(), &event) < 0) {
11678 FAIL() << "Failed to add fd to epoll";
11679 }
11680 }
11681
11682 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070011683 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT))
Prabir Pradhan07e05b62021-11-19 03:57:24 -080011684 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
11685
11686 std::vector<size_t> eventOrder;
11687 std::vector<struct epoll_event> events(numChannels);
11688 for (;;) {
11689 const int nFds = epoll_wait(epollFd.get(), events.data(), static_cast<int>(numChannels),
11690 (100ms).count());
11691 if (nFds < 0) {
11692 FAIL() << "Failed to call epoll_wait";
11693 }
11694 if (nFds == 0) {
11695 break; // epoll_wait timed out
11696 }
11697 for (int i = 0; i < nFds; i++) {
Colin Cross5b799302022-10-18 21:52:41 -070011698 ASSERT_EQ(static_cast<uint32_t>(EPOLLIN), events[i].events);
Siarhei Vishniakou31977182022-09-30 08:51:23 -070011699 eventOrder.push_back(static_cast<size_t>(events[i].data.u64));
Prabir Pradhan07e05b62021-11-19 03:57:24 -080011700 channels[i]->consumeMotionDown();
11701 }
11702 }
11703
11704 // Verify the order in which the events were received.
11705 EXPECT_EQ(3u, eventOrder.size());
11706 EXPECT_EQ(2u, eventOrder[0]); // index 2: window
11707 EXPECT_EQ(0u, eventOrder[1]); // index 0: spy1
11708 EXPECT_EQ(1u, eventOrder[2]); // index 1: spy2
11709}
11710
11711/**
11712 * A spy window using the NOT_TOUCHABLE flag does not receive events.
11713 */
11714TEST_F(InputDispatcherSpyWindowTest, NotTouchable) {
11715 auto window = createForeground();
Prabir Pradhan4d5c52f2022-01-31 08:52:10 -080011716 auto spy = createSpy();
11717 spy->setTouchable(false);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070011718 mDispatcher->onWindowInfosChanged({{*spy->getInfo(), *window->getInfo()}, {}, 0, 0});
Prabir Pradhan07e05b62021-11-19 03:57:24 -080011719
11720 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070011721 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT))
Prabir Pradhan07e05b62021-11-19 03:57:24 -080011722 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
11723 window->consumeMotionDown(ADISPLAY_ID_DEFAULT);
11724 spy->assertNoEvents();
11725}
11726
11727/**
11728 * A spy window will only receive gestures that originate within its touchable region. Gestures that
11729 * have their ACTION_DOWN outside of the touchable region of the spy window will not be dispatched
11730 * to the window.
11731 */
11732TEST_F(InputDispatcherSpyWindowTest, TouchableRegion) {
11733 auto window = createForeground();
Prabir Pradhan4d5c52f2022-01-31 08:52:10 -080011734 auto spy = createSpy();
Prabir Pradhan07e05b62021-11-19 03:57:24 -080011735 spy->setTouchableRegion(Region{{0, 0, 20, 20}});
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070011736 mDispatcher->onWindowInfosChanged({{*spy->getInfo(), *window->getInfo()}, {}, 0, 0});
Prabir Pradhan07e05b62021-11-19 03:57:24 -080011737
11738 // Inject an event outside the spy window's touchable region.
11739 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070011740 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT))
Prabir Pradhan07e05b62021-11-19 03:57:24 -080011741 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
11742 window->consumeMotionDown();
11743 spy->assertNoEvents();
11744 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070011745 injectMotionUp(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT))
Prabir Pradhan07e05b62021-11-19 03:57:24 -080011746 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
11747 window->consumeMotionUp();
11748 spy->assertNoEvents();
11749
11750 // Inject an event inside the spy window's touchable region.
11751 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070011752 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
Prabir Pradhan07e05b62021-11-19 03:57:24 -080011753 {5, 10}))
11754 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
11755 window->consumeMotionDown();
11756 spy->consumeMotionDown();
11757}
11758
11759/**
Prabir Pradhan07e05b62021-11-19 03:57:24 -080011760 * A spy window can listen for touches outside its touchable region using the WATCH_OUTSIDE_TOUCHES
Prabir Pradhandfabf8a2022-01-21 08:19:30 -080011761 * flag, but it will get zero-ed out coordinates if the foreground has a different owner.
Prabir Pradhan07e05b62021-11-19 03:57:24 -080011762 */
11763TEST_F(InputDispatcherSpyWindowTest, WatchOutsideTouches) {
11764 auto window = createForeground();
Prabir Pradhanaeebeb42023-06-13 19:53:03 +000011765 window->setOwnerInfo(gui::Pid{12}, gui::Uid{34});
Prabir Pradhan4d5c52f2022-01-31 08:52:10 -080011766 auto spy = createSpy();
11767 spy->setWatchOutsideTouch(true);
Prabir Pradhanaeebeb42023-06-13 19:53:03 +000011768 spy->setOwnerInfo(gui::Pid{56}, gui::Uid{78});
Prabir Pradhan07e05b62021-11-19 03:57:24 -080011769 spy->setFrame(Rect{0, 0, 20, 20});
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070011770 mDispatcher->onWindowInfosChanged({{*spy->getInfo(), *window->getInfo()}, {}, 0, 0});
Prabir Pradhan07e05b62021-11-19 03:57:24 -080011771
11772 // Inject an event outside the spy window's frame and touchable region.
11773 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070011774 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
Prabir Pradhandfabf8a2022-01-21 08:19:30 -080011775 {100, 200}))
Prabir Pradhan07e05b62021-11-19 03:57:24 -080011776 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
11777 window->consumeMotionDown();
Prabir Pradhandfabf8a2022-01-21 08:19:30 -080011778 spy->consumeMotionOutsideWithZeroedCoords();
Prabir Pradhan07e05b62021-11-19 03:57:24 -080011779}
11780
11781/**
Prabir Pradhan07e05b62021-11-19 03:57:24 -080011782 * Even when a spy window spans over multiple foreground windows, the spy should receive all
11783 * pointers that are down within its bounds.
11784 */
11785TEST_F(InputDispatcherSpyWindowTest, ReceivesMultiplePointers) {
11786 auto windowLeft = createForeground();
11787 windowLeft->setFrame({0, 0, 100, 200});
11788 auto windowRight = createForeground();
11789 windowRight->setFrame({100, 0, 200, 200});
Prabir Pradhan4d5c52f2022-01-31 08:52:10 -080011790 auto spy = createSpy();
Prabir Pradhan07e05b62021-11-19 03:57:24 -080011791 spy->setFrame({0, 0, 200, 200});
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070011792 mDispatcher->onWindowInfosChanged(
11793 {{*spy->getInfo(), *windowLeft->getInfo(), *windowRight->getInfo()}, {}, 0, 0});
Prabir Pradhan07e05b62021-11-19 03:57:24 -080011794
11795 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070011796 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
Prabir Pradhan07e05b62021-11-19 03:57:24 -080011797 {50, 50}))
11798 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
11799 windowLeft->consumeMotionDown();
11800 spy->consumeMotionDown();
11801
11802 const MotionEvent secondFingerDownEvent =
Siarhei Vishniakoua16e3a22022-03-02 15:26:40 -080011803 MotionEventBuilder(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
Prabir Pradhan07e05b62021-11-19 03:57:24 -080011804 .eventTime(systemTime(SYSTEM_TIME_MONOTONIC))
Siarhei Vishniakou6d73f832022-07-21 17:27:03 -070011805 .pointer(PointerBuilder(/*id=*/0, ToolType::FINGER).x(50).y(50))
11806 .pointer(PointerBuilder(/*id=*/1, ToolType::FINGER).x(150).y(50))
Prabir Pradhan07e05b62021-11-19 03:57:24 -080011807 .build();
11808 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070011809 injectMotionEvent(*mDispatcher, secondFingerDownEvent, INJECT_EVENT_TIMEOUT,
Prabir Pradhan07e05b62021-11-19 03:57:24 -080011810 InputEventInjectionSync::WAIT_FOR_RESULT))
11811 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
11812 windowRight->consumeMotionDown();
Harry Cutts33476232023-01-30 19:57:29 +000011813 spy->consumeMotionPointerDown(/*pointerIndex=*/1);
Prabir Pradhan07e05b62021-11-19 03:57:24 -080011814}
11815
11816/**
11817 * When the first pointer lands outside the spy window and the second pointer lands inside it, the
11818 * the spy should receive the second pointer with ACTION_DOWN.
11819 */
11820TEST_F(InputDispatcherSpyWindowTest, ReceivesSecondPointerAsDown) {
11821 auto window = createForeground();
11822 window->setFrame({0, 0, 200, 200});
Prabir Pradhan4d5c52f2022-01-31 08:52:10 -080011823 auto spyRight = createSpy();
Prabir Pradhan07e05b62021-11-19 03:57:24 -080011824 spyRight->setFrame({100, 0, 200, 200});
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070011825 mDispatcher->onWindowInfosChanged({{*spyRight->getInfo(), *window->getInfo()}, {}, 0, 0});
Prabir Pradhan07e05b62021-11-19 03:57:24 -080011826
11827 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070011828 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
Prabir Pradhan07e05b62021-11-19 03:57:24 -080011829 {50, 50}))
11830 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
11831 window->consumeMotionDown();
11832 spyRight->assertNoEvents();
11833
11834 const MotionEvent secondFingerDownEvent =
Siarhei Vishniakoua16e3a22022-03-02 15:26:40 -080011835 MotionEventBuilder(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
Prabir Pradhan07e05b62021-11-19 03:57:24 -080011836 .eventTime(systemTime(SYSTEM_TIME_MONOTONIC))
Siarhei Vishniakou6d73f832022-07-21 17:27:03 -070011837 .pointer(PointerBuilder(/*id=*/0, ToolType::FINGER).x(50).y(50))
11838 .pointer(PointerBuilder(/*id=*/1, ToolType::FINGER).x(150).y(50))
Prabir Pradhan07e05b62021-11-19 03:57:24 -080011839 .build();
11840 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070011841 injectMotionEvent(*mDispatcher, secondFingerDownEvent, INJECT_EVENT_TIMEOUT,
Prabir Pradhan07e05b62021-11-19 03:57:24 -080011842 InputEventInjectionSync::WAIT_FOR_RESULT))
11843 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
Harry Cutts33476232023-01-30 19:57:29 +000011844 window->consumeMotionPointerDown(/*pointerIndex=*/1);
Prabir Pradhan07e05b62021-11-19 03:57:24 -080011845 spyRight->consumeMotionDown();
11846}
11847
Prabir Pradhan1376fcd2022-01-21 09:56:35 -080011848/**
11849 * The spy window should not be able to affect whether or not touches are split. Only the foreground
11850 * windows should be allowed to control split touch.
11851 */
11852TEST_F(InputDispatcherSpyWindowTest, SplitIfNoForegroundWindowTouched) {
Prabir Pradhan76bdecb2022-01-31 11:14:15 -080011853 // This spy window prevents touch splitting. However, we still expect to split touches
Prabir Pradhan1376fcd2022-01-21 09:56:35 -080011854 // because a foreground window has not disabled splitting.
Prabir Pradhan4d5c52f2022-01-31 08:52:10 -080011855 auto spy = createSpy();
Prabir Pradhan76bdecb2022-01-31 11:14:15 -080011856 spy->setPreventSplitting(true);
Prabir Pradhan1376fcd2022-01-21 09:56:35 -080011857
Prabir Pradhan1376fcd2022-01-21 09:56:35 -080011858 auto window = createForeground();
11859 window->setFrame(Rect(0, 0, 100, 100));
Prabir Pradhan1376fcd2022-01-21 09:56:35 -080011860
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070011861 mDispatcher->onWindowInfosChanged({{*spy->getInfo(), *window->getInfo()}, {}, 0, 0});
Prabir Pradhan1376fcd2022-01-21 09:56:35 -080011862
11863 // First finger down, no window touched.
11864 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070011865 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
Prabir Pradhan1376fcd2022-01-21 09:56:35 -080011866 {100, 200}))
11867 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
11868 spy->consumeMotionDown(ADISPLAY_ID_DEFAULT);
11869 window->assertNoEvents();
11870
11871 // Second finger down on window, the window should receive touch down.
11872 const MotionEvent secondFingerDownEvent =
Siarhei Vishniakoua16e3a22022-03-02 15:26:40 -080011873 MotionEventBuilder(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
Prabir Pradhan1376fcd2022-01-21 09:56:35 -080011874 .displayId(ADISPLAY_ID_DEFAULT)
11875 .eventTime(systemTime(SYSTEM_TIME_MONOTONIC))
Siarhei Vishniakou6d73f832022-07-21 17:27:03 -070011876 .pointer(PointerBuilder(/*id=*/0, ToolType::FINGER).x(100).y(200))
11877 .pointer(PointerBuilder(/*id=*/1, ToolType::FINGER).x(50).y(50))
Prabir Pradhan1376fcd2022-01-21 09:56:35 -080011878 .build();
11879 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070011880 injectMotionEvent(*mDispatcher, secondFingerDownEvent, INJECT_EVENT_TIMEOUT,
Prabir Pradhan1376fcd2022-01-21 09:56:35 -080011881 InputEventInjectionSync::WAIT_FOR_RESULT))
11882 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
11883
11884 window->consumeMotionDown(ADISPLAY_ID_DEFAULT);
Harry Cutts33476232023-01-30 19:57:29 +000011885 spy->consumeMotionPointerDown(/*pointerIndex=*/1);
Prabir Pradhan1376fcd2022-01-21 09:56:35 -080011886}
11887
11888/**
11889 * A spy window will usually be implemented as an un-focusable window. Verify that these windows
11890 * do not receive key events.
11891 */
11892TEST_F(InputDispatcherSpyWindowTest, UnfocusableSpyDoesNotReceiveKeyEvents) {
Prabir Pradhan4d5c52f2022-01-31 08:52:10 -080011893 auto spy = createSpy();
Prabir Pradhan1376fcd2022-01-21 09:56:35 -080011894 spy->setFocusable(false);
11895
11896 auto window = createForeground();
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070011897 mDispatcher->onWindowInfosChanged({{*spy->getInfo(), *window->getInfo()}, {}, 0, 0});
Prabir Pradhan1376fcd2022-01-21 09:56:35 -080011898 setFocusedWindow(window);
11899 window->consumeFocusEvent(true);
11900
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070011901 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectKeyDown(*mDispatcher))
Prabir Pradhan1376fcd2022-01-21 09:56:35 -080011902 << "Inject key event should return InputEventInjectionResult::SUCCEEDED";
11903 window->consumeKeyDown(ADISPLAY_ID_NONE);
11904
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070011905 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectKeyUp(*mDispatcher))
Prabir Pradhan1376fcd2022-01-21 09:56:35 -080011906 << "Inject key event should return InputEventInjectionResult::SUCCEEDED";
11907 window->consumeKeyUp(ADISPLAY_ID_NONE);
11908
11909 spy->assertNoEvents();
11910}
11911
Vaibhav Devmurariff798f32022-05-09 23:45:04 +000011912using InputDispatcherPilferPointersTest = InputDispatcherSpyWindowTest;
11913
11914/**
11915 * A spy window can pilfer pointers. When this happens, touch gestures used by the spy window that
11916 * are currently sent to any other windows - including other spy windows - will also be cancelled.
11917 */
11918TEST_F(InputDispatcherPilferPointersTest, PilferPointers) {
11919 auto window = createForeground();
11920 auto spy1 = createSpy();
11921 auto spy2 = createSpy();
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070011922 mDispatcher->onWindowInfosChanged(
11923 {{*spy1->getInfo(), *spy2->getInfo(), *window->getInfo()}, {}, 0, 0});
Vaibhav Devmurariff798f32022-05-09 23:45:04 +000011924
11925 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070011926 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT))
Vaibhav Devmurariff798f32022-05-09 23:45:04 +000011927 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
11928 window->consumeMotionDown();
11929 spy1->consumeMotionDown();
11930 spy2->consumeMotionDown();
11931
11932 // Pilfer pointers from the second spy window.
11933 EXPECT_EQ(OK, mDispatcher->pilferPointers(spy2->getToken()));
11934 spy2->assertNoEvents();
11935 spy1->consumeMotionCancel();
11936 window->consumeMotionCancel();
11937
11938 // The rest of the gesture should only be sent to the second spy window.
11939 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070011940 injectMotionEvent(*mDispatcher, AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN,
Vaibhav Devmurariff798f32022-05-09 23:45:04 +000011941 ADISPLAY_ID_DEFAULT))
11942 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
11943 spy2->consumeMotionMove();
11944 spy1->assertNoEvents();
11945 window->assertNoEvents();
11946}
11947
11948/**
11949 * A spy window can pilfer pointers for a gesture even after the foreground window has been removed
11950 * in the middle of the gesture.
11951 */
11952TEST_F(InputDispatcherPilferPointersTest, CanPilferAfterWindowIsRemovedMidStream) {
11953 auto window = createForeground();
11954 auto spy = createSpy();
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070011955 mDispatcher->onWindowInfosChanged({{*spy->getInfo(), *window->getInfo()}, {}, 0, 0});
Vaibhav Devmurariff798f32022-05-09 23:45:04 +000011956
11957 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070011958 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT))
Vaibhav Devmurariff798f32022-05-09 23:45:04 +000011959 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
11960 window->consumeMotionDown(ADISPLAY_ID_DEFAULT);
11961 spy->consumeMotionDown(ADISPLAY_ID_DEFAULT);
11962
11963 window->releaseChannel();
11964
11965 EXPECT_EQ(OK, mDispatcher->pilferPointers(spy->getToken()));
11966
11967 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070011968 injectMotionUp(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT))
Vaibhav Devmurariff798f32022-05-09 23:45:04 +000011969 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
11970 spy->consumeMotionUp(ADISPLAY_ID_DEFAULT);
11971}
11972
11973/**
11974 * After a spy window pilfers pointers, new pointers that go down in its bounds should be sent to
11975 * the spy, but not to any other windows.
11976 */
11977TEST_F(InputDispatcherPilferPointersTest, ContinuesToReceiveGestureAfterPilfer) {
11978 auto spy = createSpy();
11979 auto window = createForeground();
11980
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070011981 mDispatcher->onWindowInfosChanged({{*spy->getInfo(), *window->getInfo()}, {}, 0, 0});
Vaibhav Devmurariff798f32022-05-09 23:45:04 +000011982
11983 // First finger down on the window and the spy.
11984 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070011985 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
Vaibhav Devmurariff798f32022-05-09 23:45:04 +000011986 {100, 200}))
11987 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
11988 spy->consumeMotionDown();
11989 window->consumeMotionDown();
11990
11991 // Spy window pilfers the pointers.
11992 EXPECT_EQ(OK, mDispatcher->pilferPointers(spy->getToken()));
11993 window->consumeMotionCancel();
11994
11995 // Second finger down on the window and spy, but the window should not receive the pointer down.
11996 const MotionEvent secondFingerDownEvent =
11997 MotionEventBuilder(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
11998 .displayId(ADISPLAY_ID_DEFAULT)
11999 .eventTime(systemTime(SYSTEM_TIME_MONOTONIC))
Siarhei Vishniakou6d73f832022-07-21 17:27:03 -070012000 .pointer(PointerBuilder(/*id=*/0, ToolType::FINGER).x(100).y(200))
12001 .pointer(PointerBuilder(/*id=*/1, ToolType::FINGER).x(50).y(50))
Vaibhav Devmurariff798f32022-05-09 23:45:04 +000012002 .build();
12003 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070012004 injectMotionEvent(*mDispatcher, secondFingerDownEvent, INJECT_EVENT_TIMEOUT,
Vaibhav Devmurariff798f32022-05-09 23:45:04 +000012005 InputEventInjectionSync::WAIT_FOR_RESULT))
12006 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
12007
Harry Cutts33476232023-01-30 19:57:29 +000012008 spy->consumeMotionPointerDown(/*pointerIndex=*/1);
Vaibhav Devmurariff798f32022-05-09 23:45:04 +000012009
12010 // Third finger goes down outside all windows, so injection should fail.
12011 const MotionEvent thirdFingerDownEvent =
12012 MotionEventBuilder(POINTER_2_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
12013 .displayId(ADISPLAY_ID_DEFAULT)
12014 .eventTime(systemTime(SYSTEM_TIME_MONOTONIC))
Siarhei Vishniakou6d73f832022-07-21 17:27:03 -070012015 .pointer(PointerBuilder(/*id=*/0, ToolType::FINGER).x(100).y(200))
12016 .pointer(PointerBuilder(/*id=*/1, ToolType::FINGER).x(50).y(50))
12017 .pointer(PointerBuilder(/*id=*/2, ToolType::FINGER).x(-5).y(-5))
Vaibhav Devmurariff798f32022-05-09 23:45:04 +000012018 .build();
12019 ASSERT_EQ(InputEventInjectionResult::FAILED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070012020 injectMotionEvent(*mDispatcher, thirdFingerDownEvent, INJECT_EVENT_TIMEOUT,
Vaibhav Devmurariff798f32022-05-09 23:45:04 +000012021 InputEventInjectionSync::WAIT_FOR_RESULT))
Siarhei Vishniakou1ae72f12023-01-29 12:55:30 -080012022 << "Inject motion event should return InputEventInjectionResult::FAILED";
Vaibhav Devmurariff798f32022-05-09 23:45:04 +000012023
12024 spy->assertNoEvents();
12025 window->assertNoEvents();
12026}
12027
12028/**
12029 * After a spy window pilfers pointers, only the pointers used by the spy should be canceled
12030 */
12031TEST_F(InputDispatcherPilferPointersTest, PartiallyPilferRequiredPointers) {
12032 auto spy = createSpy();
12033 spy->setFrame(Rect(0, 0, 100, 100));
12034 auto window = createForeground();
12035 window->setFrame(Rect(0, 0, 200, 200));
12036
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070012037 mDispatcher->onWindowInfosChanged({{*spy->getInfo(), *window->getInfo()}, {}, 0, 0});
Vaibhav Devmurariff798f32022-05-09 23:45:04 +000012038
12039 // First finger down on the window only
12040 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070012041 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
Vaibhav Devmurariff798f32022-05-09 23:45:04 +000012042 {150, 150}))
12043 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
12044 window->consumeMotionDown();
12045
12046 // Second finger down on the spy and window
12047 const MotionEvent secondFingerDownEvent =
12048 MotionEventBuilder(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
12049 .displayId(ADISPLAY_ID_DEFAULT)
12050 .eventTime(systemTime(SYSTEM_TIME_MONOTONIC))
Siarhei Vishniakou6d73f832022-07-21 17:27:03 -070012051 .pointer(PointerBuilder(/*id=*/0, ToolType::FINGER).x(150).y(150))
12052 .pointer(PointerBuilder(/*id=*/1, ToolType::FINGER).x(10).y(10))
Vaibhav Devmurariff798f32022-05-09 23:45:04 +000012053 .build();
12054 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070012055 injectMotionEvent(*mDispatcher, secondFingerDownEvent, INJECT_EVENT_TIMEOUT,
Vaibhav Devmurariff798f32022-05-09 23:45:04 +000012056 InputEventInjectionSync::WAIT_FOR_RESULT))
12057 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
12058 spy->consumeMotionDown();
12059 window->consumeMotionPointerDown(1);
12060
12061 // Third finger down on the spy and window
12062 const MotionEvent thirdFingerDownEvent =
12063 MotionEventBuilder(POINTER_2_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
12064 .displayId(ADISPLAY_ID_DEFAULT)
12065 .eventTime(systemTime(SYSTEM_TIME_MONOTONIC))
Siarhei Vishniakou6d73f832022-07-21 17:27:03 -070012066 .pointer(PointerBuilder(/*id=*/0, ToolType::FINGER).x(150).y(150))
12067 .pointer(PointerBuilder(/*id=*/1, ToolType::FINGER).x(10).y(10))
12068 .pointer(PointerBuilder(/*id=*/2, ToolType::FINGER).x(50).y(50))
Vaibhav Devmurariff798f32022-05-09 23:45:04 +000012069 .build();
12070 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070012071 injectMotionEvent(*mDispatcher, thirdFingerDownEvent, INJECT_EVENT_TIMEOUT,
Vaibhav Devmurariff798f32022-05-09 23:45:04 +000012072 InputEventInjectionSync::WAIT_FOR_RESULT))
12073 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
12074 spy->consumeMotionPointerDown(1);
12075 window->consumeMotionPointerDown(2);
12076
12077 // Spy window pilfers the pointers.
12078 EXPECT_EQ(OK, mDispatcher->pilferPointers(spy->getToken()));
Harry Cutts101ee9b2023-07-06 18:04:14 +000012079 window->consumeMotionPointerUp(/*idx=*/2, ADISPLAY_ID_DEFAULT, AMOTION_EVENT_FLAG_CANCELED);
12080 window->consumeMotionPointerUp(/*idx=*/1, ADISPLAY_ID_DEFAULT, AMOTION_EVENT_FLAG_CANCELED);
Vaibhav Devmurariff798f32022-05-09 23:45:04 +000012081
12082 spy->assertNoEvents();
12083 window->assertNoEvents();
12084}
12085
12086/**
12087 * After a spy window pilfers pointers, all pilfered pointers that have already been dispatched to
12088 * other windows should be canceled. If this results in the cancellation of all pointers for some
12089 * window, then that window should receive ACTION_CANCEL.
12090 */
12091TEST_F(InputDispatcherPilferPointersTest, PilferAllRequiredPointers) {
12092 auto spy = createSpy();
12093 spy->setFrame(Rect(0, 0, 100, 100));
12094 auto window = createForeground();
12095 window->setFrame(Rect(0, 0, 200, 200));
12096
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070012097 mDispatcher->onWindowInfosChanged({{*spy->getInfo(), *window->getInfo()}, {}, 0, 0});
Vaibhav Devmurariff798f32022-05-09 23:45:04 +000012098
12099 // First finger down on both spy and window
12100 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070012101 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
Vaibhav Devmurariff798f32022-05-09 23:45:04 +000012102 {10, 10}))
12103 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
12104 window->consumeMotionDown();
12105 spy->consumeMotionDown();
12106
12107 // Second finger down on the spy and window
12108 const MotionEvent secondFingerDownEvent =
12109 MotionEventBuilder(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
12110 .displayId(ADISPLAY_ID_DEFAULT)
12111 .eventTime(systemTime(SYSTEM_TIME_MONOTONIC))
Siarhei Vishniakou6d73f832022-07-21 17:27:03 -070012112 .pointer(PointerBuilder(/*id=*/0, ToolType::FINGER).x(10).y(10))
12113 .pointer(PointerBuilder(/*id=*/1, ToolType::FINGER).x(50).y(50))
Vaibhav Devmurariff798f32022-05-09 23:45:04 +000012114 .build();
12115 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070012116 injectMotionEvent(*mDispatcher, secondFingerDownEvent, INJECT_EVENT_TIMEOUT,
Vaibhav Devmurariff798f32022-05-09 23:45:04 +000012117 InputEventInjectionSync::WAIT_FOR_RESULT))
12118 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
12119 spy->consumeMotionPointerDown(1);
12120 window->consumeMotionPointerDown(1);
12121
12122 // Spy window pilfers the pointers.
12123 EXPECT_EQ(OK, mDispatcher->pilferPointers(spy->getToken()));
12124 window->consumeMotionCancel();
12125
12126 spy->assertNoEvents();
12127 window->assertNoEvents();
12128}
12129
12130/**
12131 * After a spy window pilfers pointers, new pointers that are not touching the spy window can still
12132 * be sent to other windows
12133 */
12134TEST_F(InputDispatcherPilferPointersTest, CanReceivePointersAfterPilfer) {
12135 auto spy = createSpy();
12136 spy->setFrame(Rect(0, 0, 100, 100));
12137 auto window = createForeground();
12138 window->setFrame(Rect(0, 0, 200, 200));
12139
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070012140 mDispatcher->onWindowInfosChanged({{*spy->getInfo(), *window->getInfo()}, {}, 0, 0});
Vaibhav Devmurariff798f32022-05-09 23:45:04 +000012141
12142 // First finger down on both window and spy
12143 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070012144 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
Vaibhav Devmurariff798f32022-05-09 23:45:04 +000012145 {10, 10}))
12146 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
12147 window->consumeMotionDown();
12148 spy->consumeMotionDown();
12149
12150 // Spy window pilfers the pointers.
12151 EXPECT_EQ(OK, mDispatcher->pilferPointers(spy->getToken()));
12152 window->consumeMotionCancel();
12153
12154 // Second finger down on the window only
12155 const MotionEvent secondFingerDownEvent =
12156 MotionEventBuilder(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
12157 .displayId(ADISPLAY_ID_DEFAULT)
12158 .eventTime(systemTime(SYSTEM_TIME_MONOTONIC))
Siarhei Vishniakou6d73f832022-07-21 17:27:03 -070012159 .pointer(PointerBuilder(/*id=*/0, ToolType::FINGER).x(10).y(10))
12160 .pointer(PointerBuilder(/*id=*/1, ToolType::FINGER).x(150).y(150))
Vaibhav Devmurariff798f32022-05-09 23:45:04 +000012161 .build();
12162 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070012163 injectMotionEvent(*mDispatcher, secondFingerDownEvent, INJECT_EVENT_TIMEOUT,
Vaibhav Devmurariff798f32022-05-09 23:45:04 +000012164 InputEventInjectionSync::WAIT_FOR_RESULT))
12165 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
12166 window->consumeMotionDown();
12167 window->assertNoEvents();
12168
12169 // TODO(b/232530217): do not send the unnecessary MOVE event and delete the next line
12170 spy->consumeMotionMove();
12171 spy->assertNoEvents();
12172}
12173
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -070012174/**
12175 * A window on the left and a window on the right. Also, a spy window that's above all of the
12176 * windows, and spanning both left and right windows.
12177 * Send simultaneous motion streams from two different devices, one to the left window, and another
12178 * to the right window.
12179 * Pilfer from spy window.
12180 * Check that the pilfering only affects the pointers that are actually being received by the spy.
12181 */
Siarhei Vishniakoued89cbb2023-10-13 10:42:44 -070012182TEST_F(InputDispatcherPilferPointersTest, MultiDevicePilfer_legacy) {
12183 SCOPED_FLAG_OVERRIDE(enable_multi_device_same_window_stream, false);
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -070012184 sp<FakeWindowHandle> spy = createSpy();
12185 spy->setFrame(Rect(0, 0, 200, 200));
12186 sp<FakeWindowHandle> leftWindow = createForeground();
12187 leftWindow->setFrame(Rect(0, 0, 100, 100));
12188
12189 sp<FakeWindowHandle> rightWindow = createForeground();
12190 rightWindow->setFrame(Rect(100, 0, 200, 100));
12191
12192 constexpr int32_t stylusDeviceId = 1;
12193 constexpr int32_t touchDeviceId = 2;
12194
12195 mDispatcher->onWindowInfosChanged(
12196 {{*spy->getInfo(), *leftWindow->getInfo(), *rightWindow->getInfo()}, {}, 0, 0});
12197
12198 // Stylus down on left window and spy
12199 mDispatcher->notifyMotion(MotionArgsBuilder(AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_STYLUS)
12200 .deviceId(stylusDeviceId)
12201 .pointer(PointerBuilder(0, ToolType::STYLUS).x(50).y(50))
12202 .build());
12203 leftWindow->consumeMotionEvent(
12204 AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(stylusDeviceId)));
12205 spy->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(stylusDeviceId)));
12206
12207 // Finger down on right window and spy - but spy already has stylus
12208 mDispatcher->notifyMotion(
12209 MotionArgsBuilder(AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
12210 .deviceId(touchDeviceId)
12211 .pointer(PointerBuilder(0, ToolType::FINGER).x(150).y(50))
12212 .build());
12213 rightWindow->consumeMotionEvent(
12214 AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(touchDeviceId)));
Siarhei Vishniakou2899c552023-07-10 18:20:46 -070012215 spy->assertNoEvents();
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -070012216
12217 // Act: pilfer from spy. Spy is currently receiving touch events.
12218 EXPECT_EQ(OK, mDispatcher->pilferPointers(spy->getToken()));
Siarhei Vishniakou2899c552023-07-10 18:20:46 -070012219 leftWindow->consumeMotionEvent(
12220 AllOf(WithMotionAction(ACTION_CANCEL), WithDeviceId(stylusDeviceId)));
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -070012221 rightWindow->consumeMotionEvent(
12222 AllOf(WithMotionAction(ACTION_CANCEL), WithDeviceId(touchDeviceId)));
12223
12224 // Continue movements from both stylus and touch. Touch will be delivered to spy, but not stylus
12225 mDispatcher->notifyMotion(MotionArgsBuilder(AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_STYLUS)
12226 .deviceId(stylusDeviceId)
12227 .pointer(PointerBuilder(0, ToolType::STYLUS).x(51).y(52))
12228 .build());
12229 mDispatcher->notifyMotion(
12230 MotionArgsBuilder(AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN)
12231 .deviceId(touchDeviceId)
12232 .pointer(PointerBuilder(0, ToolType::FINGER).x(151).y(52))
12233 .build());
Siarhei Vishniakou2899c552023-07-10 18:20:46 -070012234 spy->consumeMotionEvent(AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(stylusDeviceId)));
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -070012235
12236 spy->assertNoEvents();
12237 leftWindow->assertNoEvents();
12238 rightWindow->assertNoEvents();
12239}
12240
Siarhei Vishniakoued89cbb2023-10-13 10:42:44 -070012241/**
12242 * A window on the left and a window on the right. Also, a spy window that's above all of the
12243 * windows, and spanning both left and right windows.
12244 * Send simultaneous motion streams from two different devices, one to the left window, and another
12245 * to the right window.
12246 * Pilfer from spy window.
12247 * Check that the pilfering affects all of the pointers that are actually being received by the spy.
12248 * The spy should receive both the touch and the stylus events after pilfer.
12249 */
12250TEST_F(InputDispatcherPilferPointersTest, MultiDevicePilfer) {
12251 SCOPED_FLAG_OVERRIDE(enable_multi_device_same_window_stream, true);
12252 sp<FakeWindowHandle> spy = createSpy();
12253 spy->setFrame(Rect(0, 0, 200, 200));
12254 sp<FakeWindowHandle> leftWindow = createForeground();
12255 leftWindow->setFrame(Rect(0, 0, 100, 100));
12256
12257 sp<FakeWindowHandle> rightWindow = createForeground();
12258 rightWindow->setFrame(Rect(100, 0, 200, 100));
12259
12260 constexpr int32_t stylusDeviceId = 1;
12261 constexpr int32_t touchDeviceId = 2;
12262
12263 mDispatcher->onWindowInfosChanged(
12264 {{*spy->getInfo(), *leftWindow->getInfo(), *rightWindow->getInfo()}, {}, 0, 0});
12265
12266 // Stylus down on left window and spy
12267 mDispatcher->notifyMotion(MotionArgsBuilder(AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_STYLUS)
12268 .deviceId(stylusDeviceId)
12269 .pointer(PointerBuilder(0, ToolType::STYLUS).x(50).y(50))
12270 .build());
12271 leftWindow->consumeMotionEvent(
12272 AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(stylusDeviceId)));
12273 spy->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(stylusDeviceId)));
12274
12275 // Finger down on right window and spy
12276 mDispatcher->notifyMotion(
12277 MotionArgsBuilder(AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
12278 .deviceId(touchDeviceId)
12279 .pointer(PointerBuilder(0, ToolType::FINGER).x(150).y(50))
12280 .build());
12281 rightWindow->consumeMotionEvent(
12282 AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(touchDeviceId)));
12283 spy->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(touchDeviceId)));
12284
12285 // Act: pilfer from spy. Spy is currently receiving touch events.
12286 EXPECT_EQ(OK, mDispatcher->pilferPointers(spy->getToken()));
12287 leftWindow->consumeMotionEvent(
12288 AllOf(WithMotionAction(ACTION_CANCEL), WithDeviceId(stylusDeviceId)));
12289 rightWindow->consumeMotionEvent(
12290 AllOf(WithMotionAction(ACTION_CANCEL), WithDeviceId(touchDeviceId)));
12291
12292 // Continue movements from both stylus and touch. Touch and stylus will be delivered to spy
12293 mDispatcher->notifyMotion(MotionArgsBuilder(AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_STYLUS)
12294 .deviceId(stylusDeviceId)
12295 .pointer(PointerBuilder(0, ToolType::STYLUS).x(51).y(52))
12296 .build());
12297 mDispatcher->notifyMotion(
12298 MotionArgsBuilder(AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN)
12299 .deviceId(touchDeviceId)
12300 .pointer(PointerBuilder(0, ToolType::FINGER).x(151).y(52))
12301 .build());
12302 spy->consumeMotionEvent(AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(stylusDeviceId)));
12303 spy->consumeMotionEvent(AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(touchDeviceId)));
12304
12305 spy->assertNoEvents();
12306 leftWindow->assertNoEvents();
12307 rightWindow->assertNoEvents();
12308}
12309
Prabir Pradhan9cd9eb62023-11-22 17:58:06 +000012310TEST_F(InputDispatcherPilferPointersTest, NoPilferingWithHoveringPointers) {
12311 auto window = createForeground();
12312 auto spy = createSpy();
12313 mDispatcher->onWindowInfosChanged({{*spy->getInfo(), *window->getInfo()}, {}, 0, 0});
12314
12315 mDispatcher->notifyMotion(
12316 MotionArgsBuilder(ACTION_HOVER_ENTER, AINPUT_SOURCE_MOUSE)
12317 .deviceId(1)
12318 .pointer(PointerBuilder(/*id=*/0, ToolType::MOUSE).x(100).y(200))
12319 .build());
12320 window->consumeMotionEvent(WithMotionAction(ACTION_HOVER_ENTER));
12321 spy->consumeMotionEvent(WithMotionAction(ACTION_HOVER_ENTER));
12322
12323 // Pilfer pointers from the spy window should fail.
12324 EXPECT_NE(OK, mDispatcher->pilferPointers(spy->getToken()));
12325 spy->assertNoEvents();
12326 window->assertNoEvents();
12327}
12328
Prabir Pradhand65552b2021-10-07 11:23:50 -070012329class InputDispatcherStylusInterceptorTest : public InputDispatcherTest {
12330public:
12331 std::pair<sp<FakeWindowHandle>, sp<FakeWindowHandle>> setupStylusOverlayScenario() {
12332 std::shared_ptr<FakeApplicationHandle> overlayApplication =
12333 std::make_shared<FakeApplicationHandle>();
12334 sp<FakeWindowHandle> overlay =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -070012335 sp<FakeWindowHandle>::make(overlayApplication, mDispatcher,
12336 "Stylus interceptor window", ADISPLAY_ID_DEFAULT);
Prabir Pradhand65552b2021-10-07 11:23:50 -070012337 overlay->setFocusable(false);
Prabir Pradhanaeebeb42023-06-13 19:53:03 +000012338 overlay->setOwnerInfo(gui::Pid{111}, gui::Uid{111});
Prabir Pradhan4d5c52f2022-01-31 08:52:10 -080012339 overlay->setTouchable(false);
Prabir Pradhan51e7db02022-02-07 06:02:57 -080012340 overlay->setInterceptsStylus(true);
Prabir Pradhand65552b2021-10-07 11:23:50 -070012341 overlay->setTrustedOverlay(true);
12342
12343 std::shared_ptr<FakeApplicationHandle> application =
12344 std::make_shared<FakeApplicationHandle>();
12345 sp<FakeWindowHandle> window =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -070012346 sp<FakeWindowHandle>::make(application, mDispatcher, "Application window",
12347 ADISPLAY_ID_DEFAULT);
Prabir Pradhand65552b2021-10-07 11:23:50 -070012348 window->setFocusable(true);
Prabir Pradhanaeebeb42023-06-13 19:53:03 +000012349 window->setOwnerInfo(gui::Pid{222}, gui::Uid{222});
Prabir Pradhand65552b2021-10-07 11:23:50 -070012350
12351 mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070012352 mDispatcher->onWindowInfosChanged({{*overlay->getInfo(), *window->getInfo()}, {}, 0, 0});
Prabir Pradhand65552b2021-10-07 11:23:50 -070012353 setFocusedWindow(window);
Harry Cutts33476232023-01-30 19:57:29 +000012354 window->consumeFocusEvent(/*hasFocus=*/true, /*inTouchMode=*/true);
Prabir Pradhand65552b2021-10-07 11:23:50 -070012355 return {std::move(overlay), std::move(window)};
12356 }
12357
12358 void sendFingerEvent(int32_t action) {
Prabir Pradhan678438e2023-04-13 19:32:51 +000012359 mDispatcher->notifyMotion(
Prabir Pradhand65552b2021-10-07 11:23:50 -070012360 generateMotionArgs(action, AINPUT_SOURCE_TOUCHSCREEN | AINPUT_SOURCE_STYLUS,
Prabir Pradhan678438e2023-04-13 19:32:51 +000012361 ADISPLAY_ID_DEFAULT, {PointF{20, 20}}));
Prabir Pradhand65552b2021-10-07 11:23:50 -070012362 }
12363
12364 void sendStylusEvent(int32_t action) {
12365 NotifyMotionArgs motionArgs =
12366 generateMotionArgs(action, AINPUT_SOURCE_TOUCHSCREEN | AINPUT_SOURCE_STYLUS,
12367 ADISPLAY_ID_DEFAULT, {PointF{30, 40}});
Siarhei Vishniakou6d73f832022-07-21 17:27:03 -070012368 motionArgs.pointerProperties[0].toolType = ToolType::STYLUS;
Prabir Pradhan678438e2023-04-13 19:32:51 +000012369 mDispatcher->notifyMotion(motionArgs);
Prabir Pradhand65552b2021-10-07 11:23:50 -070012370 }
12371};
12372
Prabir Pradhana3ab87a2022-01-27 10:00:21 -080012373using InputDispatcherStylusInterceptorDeathTest = InputDispatcherStylusInterceptorTest;
12374
12375TEST_F(InputDispatcherStylusInterceptorDeathTest, UntrustedOverlay_AbortsDispatcher) {
Siarhei Vishniakouad3b6822023-06-22 14:17:35 -070012376 testing::GTEST_FLAG(death_test_style) = "threadsafe";
Prabir Pradhana3ab87a2022-01-27 10:00:21 -080012377 ScopedSilentDeath _silentDeath;
12378
Prabir Pradhand65552b2021-10-07 11:23:50 -070012379 auto [overlay, window] = setupStylusOverlayScenario();
12380 overlay->setTrustedOverlay(false);
12381 // Configuring an untrusted overlay as a stylus interceptor should cause Dispatcher to abort.
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070012382 ASSERT_DEATH(mDispatcher->onWindowInfosChanged(
12383 {{*overlay->getInfo(), *window->getInfo()}, {}, 0, 0}),
Prabir Pradhand65552b2021-10-07 11:23:50 -070012384 ".* not a trusted overlay");
12385}
12386
12387TEST_F(InputDispatcherStylusInterceptorTest, ConsmesOnlyStylusEvents) {
12388 auto [overlay, window] = setupStylusOverlayScenario();
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070012389 mDispatcher->onWindowInfosChanged({{*overlay->getInfo(), *window->getInfo()}, {}, 0, 0});
Prabir Pradhand65552b2021-10-07 11:23:50 -070012390
12391 sendStylusEvent(AMOTION_EVENT_ACTION_DOWN);
12392 overlay->consumeMotionDown();
12393 sendStylusEvent(AMOTION_EVENT_ACTION_UP);
12394 overlay->consumeMotionUp();
12395
12396 sendFingerEvent(AMOTION_EVENT_ACTION_DOWN);
12397 window->consumeMotionDown();
12398 sendFingerEvent(AMOTION_EVENT_ACTION_UP);
12399 window->consumeMotionUp();
12400
12401 overlay->assertNoEvents();
12402 window->assertNoEvents();
12403}
12404
12405TEST_F(InputDispatcherStylusInterceptorTest, SpyWindowStylusInterceptor) {
12406 auto [overlay, window] = setupStylusOverlayScenario();
Prabir Pradhan51e7db02022-02-07 06:02:57 -080012407 overlay->setSpy(true);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070012408 mDispatcher->onWindowInfosChanged({{*overlay->getInfo(), *window->getInfo()}, {}, 0, 0});
Prabir Pradhand65552b2021-10-07 11:23:50 -070012409
12410 sendStylusEvent(AMOTION_EVENT_ACTION_DOWN);
12411 overlay->consumeMotionDown();
12412 window->consumeMotionDown();
12413 sendStylusEvent(AMOTION_EVENT_ACTION_UP);
12414 overlay->consumeMotionUp();
12415 window->consumeMotionUp();
12416
12417 sendFingerEvent(AMOTION_EVENT_ACTION_DOWN);
12418 window->consumeMotionDown();
12419 sendFingerEvent(AMOTION_EVENT_ACTION_UP);
12420 window->consumeMotionUp();
12421
12422 overlay->assertNoEvents();
12423 window->assertNoEvents();
12424}
12425
Prabir Pradhan6dfbf262022-03-14 15:24:30 +000012426/**
12427 * Set up a scenario to test the behavior used by the stylus handwriting detection feature.
12428 * The scenario is as follows:
12429 * - The stylus interceptor overlay is configured as a spy window.
12430 * - The stylus interceptor spy receives the start of a new stylus gesture.
12431 * - It pilfers pointers and then configures itself to no longer be a spy.
12432 * - The stylus interceptor continues to receive the rest of the gesture.
12433 */
12434TEST_F(InputDispatcherStylusInterceptorTest, StylusHandwritingScenario) {
12435 auto [overlay, window] = setupStylusOverlayScenario();
12436 overlay->setSpy(true);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070012437 mDispatcher->onWindowInfosChanged({{*overlay->getInfo(), *window->getInfo()}, {}, 0, 0});
Prabir Pradhan6dfbf262022-03-14 15:24:30 +000012438
12439 sendStylusEvent(AMOTION_EVENT_ACTION_DOWN);
12440 overlay->consumeMotionDown();
12441 window->consumeMotionDown();
12442
12443 // The interceptor pilfers the pointers.
12444 EXPECT_EQ(OK, mDispatcher->pilferPointers(overlay->getToken()));
12445 window->consumeMotionCancel();
12446
12447 // The interceptor configures itself so that it is no longer a spy.
12448 overlay->setSpy(false);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070012449 mDispatcher->onWindowInfosChanged({{*overlay->getInfo(), *window->getInfo()}, {}, 0, 0});
Prabir Pradhan6dfbf262022-03-14 15:24:30 +000012450
12451 // It continues to receive the rest of the stylus gesture.
12452 sendStylusEvent(AMOTION_EVENT_ACTION_MOVE);
12453 overlay->consumeMotionMove();
12454 sendStylusEvent(AMOTION_EVENT_ACTION_UP);
12455 overlay->consumeMotionUp();
12456
12457 window->assertNoEvents();
12458}
12459
Prabir Pradhan5735a322022-04-11 17:23:34 +000012460struct User {
Prabir Pradhanaeebeb42023-06-13 19:53:03 +000012461 gui::Pid mPid;
Prabir Pradhan8a5c41d2023-06-08 19:13:46 +000012462 gui::Uid mUid;
Prabir Pradhan5735a322022-04-11 17:23:34 +000012463 uint32_t mPolicyFlags{DEFAULT_POLICY_FLAGS};
12464 std::unique_ptr<InputDispatcher>& mDispatcher;
12465
Prabir Pradhanaeebeb42023-06-13 19:53:03 +000012466 User(std::unique_ptr<InputDispatcher>& dispatcher, gui::Pid pid, gui::Uid uid)
Prabir Pradhan5735a322022-04-11 17:23:34 +000012467 : mPid(pid), mUid(uid), mDispatcher(dispatcher) {}
12468
12469 InputEventInjectionResult injectTargetedMotion(int32_t action) const {
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070012470 return injectMotionEvent(*mDispatcher, action, AINPUT_SOURCE_TOUCHSCREEN,
Prabir Pradhan5735a322022-04-11 17:23:34 +000012471 ADISPLAY_ID_DEFAULT, {100, 200},
12472 {AMOTION_EVENT_INVALID_CURSOR_POSITION,
12473 AMOTION_EVENT_INVALID_CURSOR_POSITION},
12474 INJECT_EVENT_TIMEOUT, InputEventInjectionSync::WAIT_FOR_RESULT,
12475 systemTime(SYSTEM_TIME_MONOTONIC), {mUid}, mPolicyFlags);
12476 }
12477
12478 InputEventInjectionResult injectTargetedKey(int32_t action) const {
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070012479 return inputdispatcher::injectKey(*mDispatcher, action, /*repeatCount=*/0, ADISPLAY_ID_NONE,
Prabir Pradhan5735a322022-04-11 17:23:34 +000012480 InputEventInjectionSync::WAIT_FOR_RESULT,
Harry Cutts33476232023-01-30 19:57:29 +000012481 INJECT_EVENT_TIMEOUT, /*allowKeyRepeat=*/false, {mUid},
Prabir Pradhan5735a322022-04-11 17:23:34 +000012482 mPolicyFlags);
12483 }
12484
Siarhei Vishniakoue3ce4122023-08-23 10:26:46 -070012485 sp<FakeWindowHandle> createWindow(const char* name) const {
Prabir Pradhan5735a322022-04-11 17:23:34 +000012486 std::shared_ptr<FakeApplicationHandle> overlayApplication =
12487 std::make_shared<FakeApplicationHandle>();
Siarhei Vishniakoue3ce4122023-08-23 10:26:46 -070012488 sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(overlayApplication, mDispatcher,
12489 name, ADISPLAY_ID_DEFAULT);
Prabir Pradhan5735a322022-04-11 17:23:34 +000012490 window->setOwnerInfo(mPid, mUid);
12491 return window;
12492 }
12493};
12494
12495using InputDispatcherTargetedInjectionTest = InputDispatcherTest;
12496
12497TEST_F(InputDispatcherTargetedInjectionTest, CanInjectIntoOwnedWindow) {
Prabir Pradhanaeebeb42023-06-13 19:53:03 +000012498 auto owner = User(mDispatcher, gui::Pid{10}, gui::Uid{11});
Siarhei Vishniakoue3ce4122023-08-23 10:26:46 -070012499 auto window = owner.createWindow("Owned window");
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070012500 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Prabir Pradhan5735a322022-04-11 17:23:34 +000012501
12502 EXPECT_EQ(InputEventInjectionResult::SUCCEEDED,
12503 owner.injectTargetedMotion(AMOTION_EVENT_ACTION_DOWN));
12504 window->consumeMotionDown();
12505
12506 setFocusedWindow(window);
12507 window->consumeFocusEvent(true);
12508
12509 EXPECT_EQ(InputEventInjectionResult::SUCCEEDED,
12510 owner.injectTargetedKey(AKEY_EVENT_ACTION_DOWN));
12511 window->consumeKeyDown(ADISPLAY_ID_NONE);
12512}
12513
12514TEST_F(InputDispatcherTargetedInjectionTest, CannotInjectIntoUnownedWindow) {
Prabir Pradhanaeebeb42023-06-13 19:53:03 +000012515 auto owner = User(mDispatcher, gui::Pid{10}, gui::Uid{11});
Siarhei Vishniakoue3ce4122023-08-23 10:26:46 -070012516 auto window = owner.createWindow("Owned window");
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070012517 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Prabir Pradhan5735a322022-04-11 17:23:34 +000012518
Prabir Pradhanaeebeb42023-06-13 19:53:03 +000012519 auto rando = User(mDispatcher, gui::Pid{20}, gui::Uid{21});
Prabir Pradhan5735a322022-04-11 17:23:34 +000012520 EXPECT_EQ(InputEventInjectionResult::TARGET_MISMATCH,
12521 rando.injectTargetedMotion(AMOTION_EVENT_ACTION_DOWN));
12522
12523 setFocusedWindow(window);
12524 window->consumeFocusEvent(true);
12525
12526 EXPECT_EQ(InputEventInjectionResult::TARGET_MISMATCH,
12527 rando.injectTargetedKey(AKEY_EVENT_ACTION_DOWN));
12528 window->assertNoEvents();
12529}
12530
12531TEST_F(InputDispatcherTargetedInjectionTest, CanInjectIntoOwnedSpyWindow) {
Prabir Pradhanaeebeb42023-06-13 19:53:03 +000012532 auto owner = User(mDispatcher, gui::Pid{10}, gui::Uid{11});
Siarhei Vishniakoue3ce4122023-08-23 10:26:46 -070012533 auto window = owner.createWindow("Owned window");
12534 auto spy = owner.createWindow("Owned spy");
Prabir Pradhan5735a322022-04-11 17:23:34 +000012535 spy->setSpy(true);
12536 spy->setTrustedOverlay(true);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070012537 mDispatcher->onWindowInfosChanged({{*spy->getInfo(), *window->getInfo()}, {}, 0, 0});
Prabir Pradhan5735a322022-04-11 17:23:34 +000012538
12539 EXPECT_EQ(InputEventInjectionResult::SUCCEEDED,
12540 owner.injectTargetedMotion(AMOTION_EVENT_ACTION_DOWN));
12541 spy->consumeMotionDown();
12542 window->consumeMotionDown();
12543}
12544
12545TEST_F(InputDispatcherTargetedInjectionTest, CannotInjectIntoUnownedSpyWindow) {
Prabir Pradhanaeebeb42023-06-13 19:53:03 +000012546 auto owner = User(mDispatcher, gui::Pid{10}, gui::Uid{11});
Siarhei Vishniakoue3ce4122023-08-23 10:26:46 -070012547 auto window = owner.createWindow("Owned window");
Prabir Pradhan5735a322022-04-11 17:23:34 +000012548
Prabir Pradhanaeebeb42023-06-13 19:53:03 +000012549 auto rando = User(mDispatcher, gui::Pid{20}, gui::Uid{21});
Siarhei Vishniakoue3ce4122023-08-23 10:26:46 -070012550 auto randosSpy = rando.createWindow("Rando's spy");
Prabir Pradhan5735a322022-04-11 17:23:34 +000012551 randosSpy->setSpy(true);
12552 randosSpy->setTrustedOverlay(true);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070012553 mDispatcher->onWindowInfosChanged({{*randosSpy->getInfo(), *window->getInfo()}, {}, 0, 0});
Prabir Pradhan5735a322022-04-11 17:23:34 +000012554
12555 // The event is targeted at owner's window, so injection should succeed, but the spy should
12556 // not receive the event.
12557 EXPECT_EQ(InputEventInjectionResult::SUCCEEDED,
12558 owner.injectTargetedMotion(AMOTION_EVENT_ACTION_DOWN));
12559 randosSpy->assertNoEvents();
12560 window->consumeMotionDown();
12561}
12562
12563TEST_F(InputDispatcherTargetedInjectionTest, CanInjectIntoAnyWindowWhenNotTargeting) {
Prabir Pradhanaeebeb42023-06-13 19:53:03 +000012564 auto owner = User(mDispatcher, gui::Pid{10}, gui::Uid{11});
Siarhei Vishniakoue3ce4122023-08-23 10:26:46 -070012565 auto window = owner.createWindow("Owned window");
Prabir Pradhan5735a322022-04-11 17:23:34 +000012566
Prabir Pradhanaeebeb42023-06-13 19:53:03 +000012567 auto rando = User(mDispatcher, gui::Pid{20}, gui::Uid{21});
Siarhei Vishniakoue3ce4122023-08-23 10:26:46 -070012568 auto randosSpy = rando.createWindow("Rando's spy");
Prabir Pradhan5735a322022-04-11 17:23:34 +000012569 randosSpy->setSpy(true);
12570 randosSpy->setTrustedOverlay(true);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070012571 mDispatcher->onWindowInfosChanged({{*randosSpy->getInfo(), *window->getInfo()}, {}, 0, 0});
Prabir Pradhan5735a322022-04-11 17:23:34 +000012572
12573 // A user that has injection permission can inject into any window.
12574 EXPECT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070012575 injectMotionEvent(*mDispatcher, AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN,
Prabir Pradhan5735a322022-04-11 17:23:34 +000012576 ADISPLAY_ID_DEFAULT));
12577 randosSpy->consumeMotionDown();
12578 window->consumeMotionDown();
12579
12580 setFocusedWindow(randosSpy);
12581 randosSpy->consumeFocusEvent(true);
12582
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070012583 EXPECT_EQ(InputEventInjectionResult::SUCCEEDED, injectKeyDown(*mDispatcher));
Prabir Pradhan5735a322022-04-11 17:23:34 +000012584 randosSpy->consumeKeyDown(ADISPLAY_ID_NONE);
12585 window->assertNoEvents();
12586}
12587
Siarhei Vishniakou580fb3a2023-05-05 15:02:20 -070012588TEST_F(InputDispatcherTargetedInjectionTest, CannotGenerateActionOutsideToOtherUids) {
Prabir Pradhanaeebeb42023-06-13 19:53:03 +000012589 auto owner = User(mDispatcher, gui::Pid{10}, gui::Uid{11});
Siarhei Vishniakoue3ce4122023-08-23 10:26:46 -070012590 auto window = owner.createWindow("Owned window");
Prabir Pradhan5735a322022-04-11 17:23:34 +000012591
Prabir Pradhanaeebeb42023-06-13 19:53:03 +000012592 auto rando = User(mDispatcher, gui::Pid{20}, gui::Uid{21});
Siarhei Vishniakoue3ce4122023-08-23 10:26:46 -070012593 auto randosWindow = rando.createWindow("Rando's window");
Prabir Pradhan5735a322022-04-11 17:23:34 +000012594 randosWindow->setFrame(Rect{-10, -10, -5, -5});
12595 randosWindow->setWatchOutsideTouch(true);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070012596 mDispatcher->onWindowInfosChanged({{*randosWindow->getInfo(), *window->getInfo()}, {}, 0, 0});
Prabir Pradhan5735a322022-04-11 17:23:34 +000012597
Siarhei Vishniakou580fb3a2023-05-05 15:02:20 -070012598 // Do not allow generation of ACTION_OUTSIDE events into windows owned by different uids.
Prabir Pradhan5735a322022-04-11 17:23:34 +000012599 EXPECT_EQ(InputEventInjectionResult::SUCCEEDED,
12600 owner.injectTargetedMotion(AMOTION_EVENT_ACTION_DOWN));
12601 window->consumeMotionDown();
Siarhei Vishniakou580fb3a2023-05-05 15:02:20 -070012602 randosWindow->assertNoEvents();
Prabir Pradhan5735a322022-04-11 17:23:34 +000012603}
12604
Prabir Pradhan64f21d22023-11-28 21:19:42 +000012605using InputDispatcherPointerInWindowTest = InputDispatcherTest;
12606
12607TEST_F(InputDispatcherPointerInWindowTest, PointerInWindowWhenHovering) {
12608 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
12609
12610 sp<FakeWindowHandle> left = sp<FakeWindowHandle>::make(application, mDispatcher, "Left Window",
12611 ADISPLAY_ID_DEFAULT);
12612 left->setFrame(Rect(0, 0, 100, 100));
12613 sp<FakeWindowHandle> right = sp<FakeWindowHandle>::make(application, mDispatcher,
12614 "Right Window", ADISPLAY_ID_DEFAULT);
12615 right->setFrame(Rect(100, 0, 200, 100));
12616 sp<FakeWindowHandle> spy =
12617 sp<FakeWindowHandle>::make(application, mDispatcher, "Spy Window", ADISPLAY_ID_DEFAULT);
12618 spy->setFrame(Rect(0, 0, 200, 100));
12619 spy->setTrustedOverlay(true);
12620 spy->setSpy(true);
12621
12622 mDispatcher->onWindowInfosChanged(
12623 {{*spy->getInfo(), *left->getInfo(), *right->getInfo()}, {}, 0, 0});
12624
12625 // Hover into the left window.
12626 mDispatcher->notifyMotion(
12627 MotionArgsBuilder(ACTION_HOVER_ENTER, AINPUT_SOURCE_STYLUS)
12628 .pointer(PointerBuilder(/*id=*/0, ToolType::STYLUS).x(50).y(50))
12629 .build());
12630
12631 left->consumeMotionEvent(WithMotionAction(ACTION_HOVER_ENTER));
12632 spy->consumeMotionEvent(WithMotionAction(ACTION_HOVER_ENTER));
12633
12634 ASSERT_TRUE(mDispatcher->isPointerInWindow(left->getToken(), ADISPLAY_ID_DEFAULT, DEVICE_ID,
12635 /*pointerId=*/0));
12636 ASSERT_TRUE(mDispatcher->isPointerInWindow(spy->getToken(), ADISPLAY_ID_DEFAULT, DEVICE_ID,
12637 /*pointerId=*/0));
12638 ASSERT_FALSE(mDispatcher->isPointerInWindow(right->getToken(), ADISPLAY_ID_DEFAULT, DEVICE_ID,
12639 /*pointerId=*/0));
12640
12641 // Hover move to the right window.
12642 mDispatcher->notifyMotion(
12643 MotionArgsBuilder(ACTION_HOVER_MOVE, AINPUT_SOURCE_STYLUS)
12644 .pointer(PointerBuilder(/*id=*/0, ToolType::STYLUS).x(150).y(50))
12645 .build());
12646
12647 left->consumeMotionEvent(WithMotionAction(ACTION_HOVER_EXIT));
12648 right->consumeMotionEvent(WithMotionAction(ACTION_HOVER_ENTER));
12649 spy->consumeMotionEvent(WithMotionAction(ACTION_HOVER_MOVE));
12650
12651 ASSERT_FALSE(mDispatcher->isPointerInWindow(left->getToken(), ADISPLAY_ID_DEFAULT, DEVICE_ID,
12652 /*pointerId=*/0));
12653 ASSERT_TRUE(mDispatcher->isPointerInWindow(spy->getToken(), ADISPLAY_ID_DEFAULT, DEVICE_ID,
12654 /*pointerId=*/0));
12655 ASSERT_TRUE(mDispatcher->isPointerInWindow(right->getToken(), ADISPLAY_ID_DEFAULT, DEVICE_ID,
12656 /*pointerId=*/0));
12657
12658 // Stop hovering.
12659 mDispatcher->notifyMotion(
12660 MotionArgsBuilder(ACTION_HOVER_EXIT, AINPUT_SOURCE_STYLUS)
12661 .pointer(PointerBuilder(/*id=*/0, ToolType::STYLUS).x(150).y(50))
12662 .build());
12663
12664 right->consumeMotionEvent(WithMotionAction(ACTION_HOVER_EXIT));
12665 spy->consumeMotionEvent(WithMotionAction(ACTION_HOVER_EXIT));
12666
12667 ASSERT_FALSE(mDispatcher->isPointerInWindow(left->getToken(), ADISPLAY_ID_DEFAULT, DEVICE_ID,
12668 /*pointerId=*/0));
12669 ASSERT_FALSE(mDispatcher->isPointerInWindow(spy->getToken(), ADISPLAY_ID_DEFAULT, DEVICE_ID,
12670 /*pointerId=*/0));
12671 ASSERT_FALSE(mDispatcher->isPointerInWindow(right->getToken(), ADISPLAY_ID_DEFAULT, DEVICE_ID,
12672 /*pointerId=*/0));
12673}
12674
12675TEST_F(InputDispatcherPointerInWindowTest, PointerInWindowWithSplitTouch) {
12676 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
12677
12678 sp<FakeWindowHandle> left = sp<FakeWindowHandle>::make(application, mDispatcher, "Left Window",
12679 ADISPLAY_ID_DEFAULT);
12680 left->setFrame(Rect(0, 0, 100, 100));
12681 sp<FakeWindowHandle> right = sp<FakeWindowHandle>::make(application, mDispatcher,
12682 "Right Window", ADISPLAY_ID_DEFAULT);
12683 right->setFrame(Rect(100, 0, 200, 100));
12684 sp<FakeWindowHandle> spy =
12685 sp<FakeWindowHandle>::make(application, mDispatcher, "Spy Window", ADISPLAY_ID_DEFAULT);
12686 spy->setFrame(Rect(0, 0, 200, 100));
12687 spy->setTrustedOverlay(true);
12688 spy->setSpy(true);
12689
12690 mDispatcher->onWindowInfosChanged(
12691 {{*spy->getInfo(), *left->getInfo(), *right->getInfo()}, {}, 0, 0});
12692
12693 // First pointer down on left window.
12694 mDispatcher->notifyMotion(
12695 MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
12696 .pointer(PointerBuilder(/*id=*/0, ToolType::FINGER).x(50).y(50))
12697 .build());
12698
12699 left->consumeMotionDown();
12700 spy->consumeMotionDown();
12701
12702 ASSERT_TRUE(mDispatcher->isPointerInWindow(left->getToken(), ADISPLAY_ID_DEFAULT, DEVICE_ID,
12703 /*pointerId=*/0));
12704 ASSERT_TRUE(mDispatcher->isPointerInWindow(spy->getToken(), ADISPLAY_ID_DEFAULT, DEVICE_ID,
12705 /*pointerId=*/0));
12706 ASSERT_FALSE(mDispatcher->isPointerInWindow(right->getToken(), ADISPLAY_ID_DEFAULT, DEVICE_ID,
12707 /*pointerId=*/0));
12708
12709 // Second pointer down on right window.
12710 mDispatcher->notifyMotion(
12711 MotionArgsBuilder(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
12712 .pointer(PointerBuilder(/*id=*/0, ToolType::FINGER).x(50).y(50))
12713 .pointer(PointerBuilder(/*id=*/1, ToolType::FINGER).x(150).y(50))
12714 .build());
12715
12716 left->consumeMotionMove();
12717 right->consumeMotionDown();
12718 spy->consumeMotionEvent(WithMotionAction(POINTER_1_DOWN));
12719
12720 ASSERT_TRUE(mDispatcher->isPointerInWindow(left->getToken(), ADISPLAY_ID_DEFAULT, DEVICE_ID,
12721 /*pointerId=*/0));
12722 ASSERT_TRUE(mDispatcher->isPointerInWindow(spy->getToken(), ADISPLAY_ID_DEFAULT, DEVICE_ID,
12723 /*pointerId=*/0));
12724 ASSERT_FALSE(mDispatcher->isPointerInWindow(right->getToken(), ADISPLAY_ID_DEFAULT, DEVICE_ID,
12725 /*pointerId=*/0));
12726 ASSERT_FALSE(mDispatcher->isPointerInWindow(left->getToken(), ADISPLAY_ID_DEFAULT, DEVICE_ID,
12727 /*pointerId=*/1));
12728 ASSERT_TRUE(mDispatcher->isPointerInWindow(spy->getToken(), ADISPLAY_ID_DEFAULT, DEVICE_ID,
12729 /*pointerId=*/1));
12730 ASSERT_TRUE(mDispatcher->isPointerInWindow(right->getToken(), ADISPLAY_ID_DEFAULT, DEVICE_ID,
12731 /*pointerId=*/1));
12732
12733 // Second pointer up.
12734 mDispatcher->notifyMotion(
12735 MotionArgsBuilder(POINTER_1_UP, AINPUT_SOURCE_TOUCHSCREEN)
12736 .pointer(PointerBuilder(/*id=*/0, ToolType::FINGER).x(50).y(50))
12737 .pointer(PointerBuilder(/*id=*/1, ToolType::FINGER).x(150).y(50))
12738 .build());
12739
12740 left->consumeMotionMove();
12741 right->consumeMotionUp();
12742 spy->consumeMotionEvent(WithMotionAction(POINTER_1_UP));
12743
12744 ASSERT_TRUE(mDispatcher->isPointerInWindow(left->getToken(), ADISPLAY_ID_DEFAULT, DEVICE_ID,
12745 /*pointerId=*/0));
12746 ASSERT_TRUE(mDispatcher->isPointerInWindow(spy->getToken(), ADISPLAY_ID_DEFAULT, DEVICE_ID,
12747 /*pointerId=*/0));
12748 ASSERT_FALSE(mDispatcher->isPointerInWindow(right->getToken(), ADISPLAY_ID_DEFAULT, DEVICE_ID,
12749 /*pointerId=*/0));
12750 ASSERT_FALSE(mDispatcher->isPointerInWindow(left->getToken(), ADISPLAY_ID_DEFAULT, DEVICE_ID,
12751 /*pointerId=*/1));
12752 ASSERT_FALSE(mDispatcher->isPointerInWindow(spy->getToken(), ADISPLAY_ID_DEFAULT, DEVICE_ID,
12753 /*pointerId=*/1));
12754 ASSERT_FALSE(mDispatcher->isPointerInWindow(right->getToken(), ADISPLAY_ID_DEFAULT, DEVICE_ID,
12755 /*pointerId=*/1));
12756
12757 // First pointer up.
12758 mDispatcher->notifyMotion(
12759 MotionArgsBuilder(ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN)
12760 .pointer(PointerBuilder(/*id=*/0, ToolType::FINGER).x(50).y(50))
12761 .build());
12762
12763 left->consumeMotionUp();
12764 spy->consumeMotionUp();
12765
12766 ASSERT_FALSE(mDispatcher->isPointerInWindow(left->getToken(), ADISPLAY_ID_DEFAULT, DEVICE_ID,
12767 /*pointerId=*/0));
12768 ASSERT_FALSE(mDispatcher->isPointerInWindow(spy->getToken(), ADISPLAY_ID_DEFAULT, DEVICE_ID,
12769 /*pointerId=*/0));
12770 ASSERT_FALSE(mDispatcher->isPointerInWindow(right->getToken(), ADISPLAY_ID_DEFAULT, DEVICE_ID,
12771 /*pointerId=*/0));
12772}
12773
Siarhei Vishniakoued89cbb2023-10-13 10:42:44 -070012774TEST_F(InputDispatcherPointerInWindowTest, MultipleDevicesControllingOneMouse_legacy) {
12775 SCOPED_FLAG_OVERRIDE(enable_multi_device_same_window_stream, false);
Prabir Pradhan64f21d22023-11-28 21:19:42 +000012776 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
12777
12778 sp<FakeWindowHandle> left = sp<FakeWindowHandle>::make(application, mDispatcher, "Left Window",
12779 ADISPLAY_ID_DEFAULT);
12780 left->setFrame(Rect(0, 0, 100, 100));
12781 sp<FakeWindowHandle> right = sp<FakeWindowHandle>::make(application, mDispatcher,
12782 "Right Window", ADISPLAY_ID_DEFAULT);
12783 right->setFrame(Rect(100, 0, 200, 100));
12784
12785 mDispatcher->onWindowInfosChanged({{*left->getInfo(), *right->getInfo()}, {}, 0, 0});
12786
12787 ASSERT_FALSE(mDispatcher->isPointerInWindow(left->getToken(), ADISPLAY_ID_DEFAULT, DEVICE_ID,
12788 /*pointerId=*/0));
12789 ASSERT_FALSE(mDispatcher->isPointerInWindow(right->getToken(), ADISPLAY_ID_DEFAULT, DEVICE_ID,
12790 /*pointerId=*/0));
12791
12792 // Hover move into the window.
12793 mDispatcher->notifyMotion(
12794 MotionArgsBuilder(ACTION_HOVER_MOVE, AINPUT_SOURCE_MOUSE)
12795 .pointer(PointerBuilder(/*id=*/0, ToolType::MOUSE).x(50).y(50))
12796 .rawXCursorPosition(50)
12797 .rawYCursorPosition(50)
12798 .deviceId(DEVICE_ID)
12799 .build());
12800
12801 left->consumeMotionEvent(WithMotionAction(ACTION_HOVER_ENTER));
12802
12803 ASSERT_TRUE(mDispatcher->isPointerInWindow(left->getToken(), ADISPLAY_ID_DEFAULT, DEVICE_ID,
12804 /*pointerId=*/0));
12805
12806 // Move the mouse with another device. This cancels the hovering pointer from the first device.
12807 mDispatcher->notifyMotion(
12808 MotionArgsBuilder(ACTION_HOVER_MOVE, AINPUT_SOURCE_MOUSE)
12809 .pointer(PointerBuilder(/*id=*/0, ToolType::MOUSE).x(51).y(50))
12810 .rawXCursorPosition(51)
12811 .rawYCursorPosition(50)
12812 .deviceId(SECOND_DEVICE_ID)
12813 .build());
12814
12815 left->consumeMotionEvent(WithMotionAction(ACTION_HOVER_EXIT));
12816 left->consumeMotionEvent(WithMotionAction(ACTION_HOVER_ENTER));
12817
12818 // TODO(b/313689709): InputDispatcher's touch state is not updated, even though the window gets
12819 // a HOVER_EXIT from the first device.
12820 ASSERT_TRUE(mDispatcher->isPointerInWindow(left->getToken(), ADISPLAY_ID_DEFAULT, DEVICE_ID,
12821 /*pointerId=*/0));
12822 ASSERT_TRUE(mDispatcher->isPointerInWindow(left->getToken(), ADISPLAY_ID_DEFAULT,
12823 SECOND_DEVICE_ID,
12824 /*pointerId=*/0));
12825
12826 // Move the mouse outside the window. Document the current behavior, where the window does not
12827 // receive HOVER_EXIT even though the mouse left the window.
12828 mDispatcher->notifyMotion(
12829 MotionArgsBuilder(ACTION_HOVER_MOVE, AINPUT_SOURCE_MOUSE)
12830 .pointer(PointerBuilder(/*id=*/0, ToolType::MOUSE).x(150).y(50))
12831 .rawXCursorPosition(150)
12832 .rawYCursorPosition(50)
12833 .deviceId(SECOND_DEVICE_ID)
12834 .build());
12835
12836 left->consumeMotionEvent(WithMotionAction(ACTION_HOVER_EXIT));
12837 right->consumeMotionEvent(WithMotionAction(ACTION_HOVER_ENTER));
12838 ASSERT_TRUE(mDispatcher->isPointerInWindow(left->getToken(), ADISPLAY_ID_DEFAULT, DEVICE_ID,
12839 /*pointerId=*/0));
12840 ASSERT_FALSE(mDispatcher->isPointerInWindow(left->getToken(), ADISPLAY_ID_DEFAULT,
12841 SECOND_DEVICE_ID,
12842 /*pointerId=*/0));
12843}
12844
Siarhei Vishniakoued89cbb2023-10-13 10:42:44 -070012845/**
12846 * TODO(b/313689709) - correctly support multiple mouse devices, because they should be controlling
12847 * the same cursor, and therefore have a shared motion event stream.
12848 */
12849TEST_F(InputDispatcherPointerInWindowTest, MultipleDevicesControllingOneMouse) {
12850 SCOPED_FLAG_OVERRIDE(enable_multi_device_same_window_stream, true);
12851 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
12852
12853 sp<FakeWindowHandle> left = sp<FakeWindowHandle>::make(application, mDispatcher, "Left Window",
12854 ADISPLAY_ID_DEFAULT);
12855 left->setFrame(Rect(0, 0, 100, 100));
12856 sp<FakeWindowHandle> right = sp<FakeWindowHandle>::make(application, mDispatcher,
12857 "Right Window", ADISPLAY_ID_DEFAULT);
12858 right->setFrame(Rect(100, 0, 200, 100));
12859
12860 mDispatcher->onWindowInfosChanged({{*left->getInfo(), *right->getInfo()}, {}, 0, 0});
12861
12862 ASSERT_FALSE(mDispatcher->isPointerInWindow(left->getToken(), ADISPLAY_ID_DEFAULT, DEVICE_ID,
12863 /*pointerId=*/0));
12864 ASSERT_FALSE(mDispatcher->isPointerInWindow(right->getToken(), ADISPLAY_ID_DEFAULT, DEVICE_ID,
12865 /*pointerId=*/0));
12866
12867 // Hover move into the window.
12868 mDispatcher->notifyMotion(
12869 MotionArgsBuilder(ACTION_HOVER_MOVE, AINPUT_SOURCE_MOUSE)
12870 .pointer(PointerBuilder(/*id=*/0, ToolType::MOUSE).x(50).y(50))
12871 .rawXCursorPosition(50)
12872 .rawYCursorPosition(50)
12873 .deviceId(DEVICE_ID)
12874 .build());
12875
12876 left->consumeMotionEvent(WithMotionAction(ACTION_HOVER_ENTER));
12877
12878 ASSERT_TRUE(mDispatcher->isPointerInWindow(left->getToken(), ADISPLAY_ID_DEFAULT, DEVICE_ID,
12879 /*pointerId=*/0));
12880
12881 // Move the mouse with another device
12882 mDispatcher->notifyMotion(
12883 MotionArgsBuilder(ACTION_HOVER_MOVE, AINPUT_SOURCE_MOUSE)
12884 .pointer(PointerBuilder(/*id=*/0, ToolType::MOUSE).x(51).y(50))
12885 .rawXCursorPosition(51)
12886 .rawYCursorPosition(50)
12887 .deviceId(SECOND_DEVICE_ID)
12888 .build());
12889 left->consumeMotionEvent(WithMotionAction(ACTION_HOVER_ENTER));
12890
12891 // TODO(b/313689709): InputDispatcher's touch state is not updated, even though the window gets
12892 // a HOVER_EXIT from the first device.
12893 ASSERT_TRUE(mDispatcher->isPointerInWindow(left->getToken(), ADISPLAY_ID_DEFAULT, DEVICE_ID,
12894 /*pointerId=*/0));
12895 ASSERT_TRUE(mDispatcher->isPointerInWindow(left->getToken(), ADISPLAY_ID_DEFAULT,
12896 SECOND_DEVICE_ID,
12897 /*pointerId=*/0));
12898
12899 // Move the mouse outside the window. Document the current behavior, where the window does not
12900 // receive HOVER_EXIT even though the mouse left the window.
12901 mDispatcher->notifyMotion(
12902 MotionArgsBuilder(ACTION_HOVER_MOVE, AINPUT_SOURCE_MOUSE)
12903 .pointer(PointerBuilder(/*id=*/0, ToolType::MOUSE).x(150).y(50))
12904 .rawXCursorPosition(150)
12905 .rawYCursorPosition(50)
12906 .deviceId(SECOND_DEVICE_ID)
12907 .build());
12908
12909 right->consumeMotionEvent(WithMotionAction(ACTION_HOVER_ENTER));
12910 ASSERT_TRUE(mDispatcher->isPointerInWindow(left->getToken(), ADISPLAY_ID_DEFAULT, DEVICE_ID,
12911 /*pointerId=*/0));
12912 ASSERT_FALSE(mDispatcher->isPointerInWindow(left->getToken(), ADISPLAY_ID_DEFAULT,
12913 SECOND_DEVICE_ID,
12914 /*pointerId=*/0));
12915}
12916
Garfield Tane84e6f92019-08-29 17:28:41 -070012917} // namespace android::inputdispatcher