blob: 62a92352e539bf4221fbbdf146d91fcadd4b9f5a [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;
Siarhei Vishniakou85eb5802024-04-01 11:40:59 -070062using testing::Pointee;
63using testing::UnorderedElementsAre;
Dominik Laskowski2f01d772022-03-23 16:01:29 -070064
Siarhei Vishniakouf4043212023-09-18 19:33:03 -070065namespace {
66
Michael Wrightd02c5b62014-02-10 15:10:22 -080067// An arbitrary time value.
Prabir Pradhan5735a322022-04-11 17:23:34 +000068static constexpr nsecs_t ARBITRARY_TIME = 1234;
Michael Wrightd02c5b62014-02-10 15:10:22 -080069
70// An arbitrary device id.
Prabir Pradhan9205e422023-05-16 20:06:13 +000071static constexpr int32_t DEVICE_ID = DEFAULT_DEVICE_ID;
Siarhei Vishniakou060f82b2023-01-27 06:39:14 -080072static constexpr int32_t SECOND_DEVICE_ID = 2;
Michael Wrightd02c5b62014-02-10 15:10:22 -080073
Jeff Brownf086ddb2014-02-11 14:28:48 -080074// An arbitrary display id.
Arthur Hungabbb9d82021-09-01 14:52:30 +000075static constexpr int32_t DISPLAY_ID = ADISPLAY_ID_DEFAULT;
76static constexpr int32_t SECOND_DISPLAY_ID = 1;
Jeff Brownf086ddb2014-02-11 14:28:48 -080077
Prabir Pradhan8ede1d12023-05-08 19:37:44 +000078// Ensure common actions are interchangeable between keys and motions for convenience.
79static_assert(AMOTION_EVENT_ACTION_DOWN == AKEY_EVENT_ACTION_DOWN);
80static_assert(AMOTION_EVENT_ACTION_UP == AKEY_EVENT_ACTION_UP);
Siarhei Vishniakouf372b812023-02-14 18:06:51 -080081static constexpr int32_t ACTION_DOWN = AMOTION_EVENT_ACTION_DOWN;
82static constexpr int32_t ACTION_MOVE = AMOTION_EVENT_ACTION_MOVE;
83static constexpr int32_t ACTION_UP = AMOTION_EVENT_ACTION_UP;
84static constexpr int32_t ACTION_HOVER_ENTER = AMOTION_EVENT_ACTION_HOVER_ENTER;
Siarhei Vishniakoua235c042023-05-02 09:59:09 -070085static constexpr int32_t ACTION_HOVER_MOVE = AMOTION_EVENT_ACTION_HOVER_MOVE;
Siarhei Vishniakouf372b812023-02-14 18:06:51 -080086static constexpr int32_t ACTION_HOVER_EXIT = AMOTION_EVENT_ACTION_HOVER_EXIT;
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -070087static constexpr int32_t ACTION_SCROLL = AMOTION_EVENT_ACTION_SCROLL;
Siarhei Vishniakou487c49b2022-12-02 15:48:57 -080088static constexpr int32_t ACTION_OUTSIDE = AMOTION_EVENT_ACTION_OUTSIDE;
Siarhei Vishniakou1ae72f12023-01-29 12:55:30 -080089static constexpr int32_t ACTION_CANCEL = AMOTION_EVENT_ACTION_CANCEL;
Siarhei Vishniakouf372b812023-02-14 18:06:51 -080090/**
91 * The POINTER_DOWN(0) is an unusual, but valid, action. It just means that the new pointer in the
92 * MotionEvent is at the index 0 rather than 1 (or later). That is, the pointer id=0 (which is at
93 * index 0) is the new pointer going down. The same pointer could have been placed at a different
94 * index, and the action would become POINTER_1_DOWN, 2, etc..; these would all be valid. In
95 * general, we try to place pointer id = 0 at the index 0. Of course, this is not possible if
96 * pointer id=0 leaves but the pointer id=1 remains.
97 */
98static constexpr int32_t POINTER_0_DOWN =
99 AMOTION_EVENT_ACTION_POINTER_DOWN | (0 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT);
Siarhei Vishniakoua16e3a22022-03-02 15:26:40 -0800100static constexpr int32_t POINTER_1_DOWN =
101 AMOTION_EVENT_ACTION_POINTER_DOWN | (1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT);
Prabir Pradhanb60b1dc2022-03-15 14:02:35 +0000102static constexpr int32_t POINTER_2_DOWN =
103 AMOTION_EVENT_ACTION_POINTER_DOWN | (2 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT);
Vaibhav Devmurari882bd9b2022-06-23 14:54:54 +0000104static constexpr int32_t POINTER_3_DOWN =
105 AMOTION_EVENT_ACTION_POINTER_DOWN | (3 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT);
Arthur Hungc539dbb2022-12-08 07:45:36 +0000106static constexpr int32_t POINTER_0_UP =
107 AMOTION_EVENT_ACTION_POINTER_UP | (0 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT);
Siarhei Vishniakoua16e3a22022-03-02 15:26:40 -0800108static constexpr int32_t POINTER_1_UP =
109 AMOTION_EVENT_ACTION_POINTER_UP | (1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT);
Harry Cuttsb166c002023-05-09 13:06:05 +0000110static constexpr int32_t POINTER_2_UP =
111 AMOTION_EVENT_ACTION_POINTER_UP | (2 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT);
Siarhei Vishniakoua16e3a22022-03-02 15:26:40 -0800112
Antonio Kantek15beb512022-06-13 22:35:41 +0000113// The default pid and uid for the windows created on the secondary display by the test.
Prabir Pradhanaeebeb42023-06-13 19:53:03 +0000114static constexpr gui::Pid SECONDARY_WINDOW_PID{1010};
Prabir Pradhan8a5c41d2023-06-08 19:13:46 +0000115static constexpr gui::Uid SECONDARY_WINDOW_UID{1012};
Antonio Kantek15beb512022-06-13 22:35:41 +0000116
Siarhei Vishniakou58cfc602020-12-14 23:21:30 +0000117// An arbitrary pid of the gesture monitor window
Prabir Pradhanaeebeb42023-06-13 19:53:03 +0000118static constexpr gui::Pid MONITOR_PID{2001};
Siarhei Vishniakou58cfc602020-12-14 23:21:30 +0000119
Arthur Hungc539dbb2022-12-08 07:45:36 +0000120static constexpr int expectedWallpaperFlags =
121 AMOTION_EVENT_FLAG_WINDOW_IS_OBSCURED | AMOTION_EVENT_FLAG_WINDOW_IS_PARTIALLY_OBSCURED;
122
Siarhei Vishniakou56e79092023-02-21 19:13:16 -0800123using ReservedInputDeviceId::VIRTUAL_KEYBOARD_ID;
124
Gang Wang342c9272020-01-13 13:15:04 -0500125/**
126 * Return a DOWN key event with KEYCODE_A.
127 */
128static KeyEvent getTestKeyEvent() {
129 KeyEvent event;
130
Garfield Tanfbe732e2020-01-24 11:26:14 -0800131 event.initialize(InputEvent::nextId(), DEVICE_ID, AINPUT_SOURCE_KEYBOARD, ADISPLAY_ID_NONE,
132 INVALID_HMAC, AKEY_EVENT_ACTION_DOWN, 0, AKEYCODE_A, KEY_A, AMETA_NONE, 0,
133 ARBITRARY_TIME, ARBITRARY_TIME);
Gang Wang342c9272020-01-13 13:15:04 -0500134 return event;
135}
136
Siarhei Vishniakoued89cbb2023-10-13 10:42:44 -0700137/**
138 * Provide a local override for a flag value. The value is restored when the object of this class
139 * goes out of scope.
140 * This class is not intended to be used directly, because its usage is cumbersome.
141 * Instead, a wrapper macro SCOPED_FLAG_OVERRIDE is provided.
142 */
143class ScopedFlagOverride {
144public:
145 ScopedFlagOverride(std::function<bool()> read, std::function<void(bool)> write, bool value)
146 : mInitialValue(read()), mWriteValue(write) {
147 mWriteValue(value);
148 }
149 ~ScopedFlagOverride() { mWriteValue(mInitialValue); }
150
151private:
152 const bool mInitialValue;
153 std::function<void(bool)> mWriteValue;
154};
155
156typedef bool (*readFlagValueFunction)();
157typedef void (*writeFlagValueFunction)(bool);
158
159/**
160 * Use this macro to locally override a flag value.
161 * Example usage:
162 * SCOPED_FLAG_OVERRIDE(enable_multi_device_same_window_stream, false);
163 * Note: this works by creating a local variable in your current scope. Don't call this twice for
164 * the same flag, because the variable names will clash!
165 */
166#define SCOPED_FLAG_OVERRIDE(NAME, VALUE) \
167 readFlagValueFunction read##NAME = com::android::input::flags::NAME; \
168 writeFlagValueFunction write##NAME = com::android::input::flags::NAME; \
169 ScopedFlagOverride override##NAME(read##NAME, write##NAME, (VALUE))
170
Siarhei Vishniakouf4043212023-09-18 19:33:03 -0700171} // namespace
Michael Wrightd02c5b62014-02-10 15:10:22 -0800172
Michael Wrightd02c5b62014-02-10 15:10:22 -0800173// --- InputDispatcherTest ---
174
175class InputDispatcherTest : public testing::Test {
176protected:
Prabir Pradhana41d2442023-04-20 21:30:40 +0000177 std::unique_ptr<FakeInputDispatcherPolicy> mFakePolicy;
Siarhei Vishniakou18050092021-09-01 13:32:49 -0700178 std::unique_ptr<InputDispatcher> mDispatcher;
Prabir Pradhanc5340732024-03-20 22:53:52 +0000179 std::shared_ptr<VerifyingTrace> mVerifyingTrace;
Michael Wrightd02c5b62014-02-10 15:10:22 -0800180
Siarhei Vishniakouf2652122021-03-05 21:39:46 +0000181 void SetUp() override {
Prabir Pradhanc5340732024-03-20 22:53:52 +0000182 mVerifyingTrace = std::make_shared<VerifyingTrace>();
183 FakeWindowHandle::sOnEventReceivedCallback = [this](const auto& _1, const auto& _2) {
184 handleEventReceivedByWindow(_1, _2);
185 };
186
Prabir Pradhana41d2442023-04-20 21:30:40 +0000187 mFakePolicy = std::make_unique<FakeInputDispatcherPolicy>();
Prabir Pradhandc3a2ad2024-02-05 19:03:51 +0000188 mDispatcher = std::make_unique<InputDispatcher>(*mFakePolicy,
189 std::make_unique<FakeInputTracingBackend>(
Prabir Pradhanc5340732024-03-20 22:53:52 +0000190 mVerifyingTrace));
Siarhei Vishniakoua7333112023-10-27 13:33:29 -0700191
Harry Cutts101ee9b2023-07-06 18:04:14 +0000192 mDispatcher->setInputDispatchMode(/*enabled=*/true, /*frozen=*/false);
Siarhei Vishniakou870ecec2020-12-09 08:07:46 -1000193 // Start InputDispatcher thread
Prabir Pradhan3608aad2019-10-02 17:08:26 -0700194 ASSERT_EQ(OK, mDispatcher->start());
Michael Wrightd02c5b62014-02-10 15:10:22 -0800195 }
196
Siarhei Vishniakouf2652122021-03-05 21:39:46 +0000197 void TearDown() override {
Prabir Pradhanc5340732024-03-20 22:53:52 +0000198 ASSERT_NO_FATAL_FAILURE(mVerifyingTrace->verifyExpectedEventsTraced());
199 FakeWindowHandle::sOnEventReceivedCallback = nullptr;
200
Prabir Pradhan3608aad2019-10-02 17:08:26 -0700201 ASSERT_EQ(OK, mDispatcher->stop());
Prabir Pradhana41d2442023-04-20 21:30:40 +0000202 mFakePolicy.reset();
Siarhei Vishniakou18050092021-09-01 13:32:49 -0700203 mDispatcher.reset();
Michael Wrightd02c5b62014-02-10 15:10:22 -0800204 }
Siarhei Vishniakou4cb50ca2020-05-26 21:43:02 -0700205
Prabir Pradhanc5340732024-03-20 22:53:52 +0000206 void handleEventReceivedByWindow(const std::unique_ptr<InputEvent>& event,
207 const gui::WindowInfo& info) {
208 if (!event) {
209 return;
210 }
211
212 switch (event->getType()) {
213 case InputEventType::KEY: {
214 mVerifyingTrace->expectKeyDispatchTraced(static_cast<KeyEvent&>(*event), info.id);
215 break;
216 }
217 case InputEventType::MOTION: {
218 mVerifyingTrace->expectMotionDispatchTraced(static_cast<MotionEvent&>(*event),
219 info.id);
220 break;
221 }
222 default:
223 break;
224 }
225 }
226
Siarhei Vishniakou4cb50ca2020-05-26 21:43:02 -0700227 /**
228 * Used for debugging when writing the test
229 */
230 void dumpDispatcherState() {
231 std::string dump;
232 mDispatcher->dump(dump);
233 std::stringstream ss(dump);
234 std::string to;
235
236 while (std::getline(ss, to, '\n')) {
237 ALOGE("%s", to.c_str());
238 }
239 }
Vishnu Nair958da932020-08-21 17:12:37 -0700240
Chavi Weingarten847e8512023-03-29 00:26:09 +0000241 void setFocusedWindow(const sp<WindowInfoHandle>& window) {
Vishnu Nair958da932020-08-21 17:12:37 -0700242 FocusRequest request;
243 request.token = window->getToken();
Siarhei Vishniakou5d552c42021-05-21 05:02:22 +0000244 request.windowName = window->getName();
Vishnu Nair958da932020-08-21 17:12:37 -0700245 request.timestamp = systemTime(SYSTEM_TIME_MONOTONIC);
246 request.displayId = window->getInfo()->displayId;
247 mDispatcher->setFocusedWindow(request);
248 }
Michael Wrightd02c5b62014-02-10 15:10:22 -0800249};
250
Michael Wrightd02c5b62014-02-10 15:10:22 -0800251TEST_F(InputDispatcherTest, InjectInputEvent_ValidatesKeyEvents) {
252 KeyEvent event;
253
254 // Rejects undefined key actions.
Garfield Tanfbe732e2020-01-24 11:26:14 -0800255 event.initialize(InputEvent::nextId(), DEVICE_ID, AINPUT_SOURCE_KEYBOARD, ADISPLAY_ID_NONE,
256 INVALID_HMAC,
Harry Cutts101ee9b2023-07-06 18:04:14 +0000257 /*action=*/-1, 0, AKEYCODE_A, KEY_A, AMETA_NONE, 0, ARBITRARY_TIME,
Siarhei Vishniakou9c858ac2020-01-23 14:20:11 -0600258 ARBITRARY_TIME);
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -0800259 ASSERT_EQ(InputEventInjectionResult::FAILED,
Harry Cutts33476232023-01-30 19:57:29 +0000260 mDispatcher->injectInputEvent(&event, /*targetUid=*/{}, InputEventInjectionSync::NONE,
Prabir Pradhan5735a322022-04-11 17:23:34 +0000261 0ms, 0))
Michael Wrightd02c5b62014-02-10 15:10:22 -0800262 << "Should reject key events with undefined action.";
263
264 // Rejects ACTION_MULTIPLE since it is not supported despite being defined in the API.
Garfield Tanfbe732e2020-01-24 11:26:14 -0800265 event.initialize(InputEvent::nextId(), DEVICE_ID, AINPUT_SOURCE_KEYBOARD, ADISPLAY_ID_NONE,
266 INVALID_HMAC, AKEY_EVENT_ACTION_MULTIPLE, 0, AKEYCODE_A, KEY_A, AMETA_NONE, 0,
Siarhei Vishniakou9c858ac2020-01-23 14:20:11 -0600267 ARBITRARY_TIME, ARBITRARY_TIME);
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -0800268 ASSERT_EQ(InputEventInjectionResult::FAILED,
Harry Cutts33476232023-01-30 19:57:29 +0000269 mDispatcher->injectInputEvent(&event, /*targetUid=*/{}, InputEventInjectionSync::NONE,
Prabir Pradhan5735a322022-04-11 17:23:34 +0000270 0ms, 0))
Michael Wrightd02c5b62014-02-10 15:10:22 -0800271 << "Should reject key events with ACTION_MULTIPLE.";
272}
273
274TEST_F(InputDispatcherTest, InjectInputEvent_ValidatesMotionEvents) {
275 MotionEvent event;
276 PointerProperties pointerProperties[MAX_POINTERS + 1];
277 PointerCoords pointerCoords[MAX_POINTERS + 1];
Siarhei Vishniakou01747382022-01-20 13:23:27 -0800278 for (size_t i = 0; i <= MAX_POINTERS; i++) {
Michael Wrightd02c5b62014-02-10 15:10:22 -0800279 pointerProperties[i].clear();
280 pointerProperties[i].id = i;
281 pointerCoords[i].clear();
282 }
283
Siarhei Vishniakou49e59222018-12-28 18:17:15 -0800284 // Some constants commonly used below
285 constexpr int32_t source = AINPUT_SOURCE_TOUCHSCREEN;
286 constexpr int32_t edgeFlags = AMOTION_EVENT_EDGE_FLAG_NONE;
287 constexpr int32_t metaState = AMETA_NONE;
288 constexpr MotionClassification classification = MotionClassification::NONE;
289
chaviw9eaa22c2020-07-01 16:21:27 -0700290 ui::Transform identityTransform;
Michael Wrightd02c5b62014-02-10 15:10:22 -0800291 // Rejects undefined motion actions.
Garfield Tanfbe732e2020-01-24 11:26:14 -0800292 event.initialize(InputEvent::nextId(), DEVICE_ID, source, DISPLAY_ID, INVALID_HMAC,
Harry Cutts101ee9b2023-07-06 18:04:14 +0000293 /*action=*/-1, 0, 0, edgeFlags, metaState, 0, classification,
chaviw9eaa22c2020-07-01 16:21:27 -0700294 identityTransform, 0, 0, AMOTION_EVENT_INVALID_CURSOR_POSITION,
Prabir Pradhanb9b18502021-08-26 12:30:32 -0700295 AMOTION_EVENT_INVALID_CURSOR_POSITION, identityTransform, ARBITRARY_TIME,
296 ARBITRARY_TIME,
Harry Cutts101ee9b2023-07-06 18:04:14 +0000297 /*pointerCount=*/1, pointerProperties, pointerCoords);
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -0800298 ASSERT_EQ(InputEventInjectionResult::FAILED,
Harry Cutts33476232023-01-30 19:57:29 +0000299 mDispatcher->injectInputEvent(&event, /*targetUid=*/{}, InputEventInjectionSync::NONE,
Prabir Pradhan5735a322022-04-11 17:23:34 +0000300 0ms, 0))
Michael Wrightd02c5b62014-02-10 15:10:22 -0800301 << "Should reject motion events with undefined action.";
302
303 // Rejects pointer down with invalid index.
Garfield Tanfbe732e2020-01-24 11:26:14 -0800304 event.initialize(InputEvent::nextId(), DEVICE_ID, source, DISPLAY_ID, INVALID_HMAC,
Siarhei Vishniakoua16e3a22022-03-02 15:26:40 -0800305 POINTER_1_DOWN, 0, 0, edgeFlags, metaState, 0, classification,
306 identityTransform, 0, 0, AMOTION_EVENT_INVALID_CURSOR_POSITION,
307 AMOTION_EVENT_INVALID_CURSOR_POSITION, identityTransform, ARBITRARY_TIME,
308 ARBITRARY_TIME,
Harry Cutts101ee9b2023-07-06 18:04:14 +0000309 /*pointerCount=*/1, pointerProperties, pointerCoords);
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -0800310 ASSERT_EQ(InputEventInjectionResult::FAILED,
Harry Cutts33476232023-01-30 19:57:29 +0000311 mDispatcher->injectInputEvent(&event, /*targetUid=*/{}, InputEventInjectionSync::NONE,
Prabir Pradhan5735a322022-04-11 17:23:34 +0000312 0ms, 0))
Michael Wrightd02c5b62014-02-10 15:10:22 -0800313 << "Should reject motion events with pointer down index too large.";
314
Garfield Tanfbe732e2020-01-24 11:26:14 -0800315 event.initialize(InputEvent::nextId(), DEVICE_ID, source, DISPLAY_ID, INVALID_HMAC,
Garfield Tan00f511d2019-06-12 16:55:40 -0700316 AMOTION_EVENT_ACTION_POINTER_DOWN |
317 (~0U << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT),
chaviw9eaa22c2020-07-01 16:21:27 -0700318 0, 0, edgeFlags, metaState, 0, classification, identityTransform, 0, 0,
319 AMOTION_EVENT_INVALID_CURSOR_POSITION, AMOTION_EVENT_INVALID_CURSOR_POSITION,
Prabir Pradhanb9b18502021-08-26 12:30:32 -0700320 identityTransform, ARBITRARY_TIME, ARBITRARY_TIME,
Harry Cutts101ee9b2023-07-06 18:04:14 +0000321 /*pointerCount=*/1, pointerProperties, pointerCoords);
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -0800322 ASSERT_EQ(InputEventInjectionResult::FAILED,
Harry Cutts33476232023-01-30 19:57:29 +0000323 mDispatcher->injectInputEvent(&event, /*targetUid=*/{}, InputEventInjectionSync::NONE,
Prabir Pradhan5735a322022-04-11 17:23:34 +0000324 0ms, 0))
Michael Wrightd02c5b62014-02-10 15:10:22 -0800325 << "Should reject motion events with pointer down index too small.";
326
327 // Rejects pointer up with invalid index.
Garfield Tanfbe732e2020-01-24 11:26:14 -0800328 event.initialize(InputEvent::nextId(), DEVICE_ID, source, DISPLAY_ID, INVALID_HMAC,
Siarhei Vishniakoua16e3a22022-03-02 15:26:40 -0800329 POINTER_1_UP, 0, 0, edgeFlags, metaState, 0, classification, identityTransform,
330 0, 0, AMOTION_EVENT_INVALID_CURSOR_POSITION,
331 AMOTION_EVENT_INVALID_CURSOR_POSITION, identityTransform, ARBITRARY_TIME,
332 ARBITRARY_TIME,
Harry Cutts101ee9b2023-07-06 18:04:14 +0000333 /*pointerCount=*/1, pointerProperties, pointerCoords);
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -0800334 ASSERT_EQ(InputEventInjectionResult::FAILED,
Harry Cutts33476232023-01-30 19:57:29 +0000335 mDispatcher->injectInputEvent(&event, /*targetUid=*/{}, InputEventInjectionSync::NONE,
Prabir Pradhan5735a322022-04-11 17:23:34 +0000336 0ms, 0))
Michael Wrightd02c5b62014-02-10 15:10:22 -0800337 << "Should reject motion events with pointer up index too large.";
338
Garfield Tanfbe732e2020-01-24 11:26:14 -0800339 event.initialize(InputEvent::nextId(), DEVICE_ID, source, DISPLAY_ID, INVALID_HMAC,
Garfield Tan00f511d2019-06-12 16:55:40 -0700340 AMOTION_EVENT_ACTION_POINTER_UP |
341 (~0U << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT),
chaviw9eaa22c2020-07-01 16:21:27 -0700342 0, 0, edgeFlags, metaState, 0, classification, identityTransform, 0, 0,
343 AMOTION_EVENT_INVALID_CURSOR_POSITION, AMOTION_EVENT_INVALID_CURSOR_POSITION,
Prabir Pradhanb9b18502021-08-26 12:30:32 -0700344 identityTransform, ARBITRARY_TIME, ARBITRARY_TIME,
Harry Cutts101ee9b2023-07-06 18:04:14 +0000345 /*pointerCount=*/1, pointerProperties, pointerCoords);
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -0800346 ASSERT_EQ(InputEventInjectionResult::FAILED,
Harry Cutts33476232023-01-30 19:57:29 +0000347 mDispatcher->injectInputEvent(&event, /*targetUid=*/{}, InputEventInjectionSync::NONE,
Prabir Pradhan5735a322022-04-11 17:23:34 +0000348 0ms, 0))
Michael Wrightd02c5b62014-02-10 15:10:22 -0800349 << "Should reject motion events with pointer up index too small.";
350
351 // Rejects motion events with invalid number of pointers.
Garfield Tanfbe732e2020-01-24 11:26:14 -0800352 event.initialize(InputEvent::nextId(), DEVICE_ID, source, DISPLAY_ID, INVALID_HMAC,
353 AMOTION_EVENT_ACTION_DOWN, 0, 0, edgeFlags, metaState, 0, classification,
chaviw9eaa22c2020-07-01 16:21:27 -0700354 identityTransform, 0, 0, AMOTION_EVENT_INVALID_CURSOR_POSITION,
Prabir Pradhanb9b18502021-08-26 12:30:32 -0700355 AMOTION_EVENT_INVALID_CURSOR_POSITION, identityTransform, ARBITRARY_TIME,
356 ARBITRARY_TIME,
Harry Cutts101ee9b2023-07-06 18:04:14 +0000357 /*pointerCount=*/0, pointerProperties, pointerCoords);
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -0800358 ASSERT_EQ(InputEventInjectionResult::FAILED,
Harry Cutts33476232023-01-30 19:57:29 +0000359 mDispatcher->injectInputEvent(&event, /*targetUid=*/{}, InputEventInjectionSync::NONE,
Prabir Pradhan5735a322022-04-11 17:23:34 +0000360 0ms, 0))
Michael Wrightd02c5b62014-02-10 15:10:22 -0800361 << "Should reject motion events with 0 pointers.";
362
Garfield Tanfbe732e2020-01-24 11:26:14 -0800363 event.initialize(InputEvent::nextId(), DEVICE_ID, source, DISPLAY_ID, INVALID_HMAC,
364 AMOTION_EVENT_ACTION_DOWN, 0, 0, edgeFlags, metaState, 0, classification,
chaviw9eaa22c2020-07-01 16:21:27 -0700365 identityTransform, 0, 0, AMOTION_EVENT_INVALID_CURSOR_POSITION,
Prabir Pradhanb9b18502021-08-26 12:30:32 -0700366 AMOTION_EVENT_INVALID_CURSOR_POSITION, identityTransform, ARBITRARY_TIME,
367 ARBITRARY_TIME,
Harry Cutts101ee9b2023-07-06 18:04:14 +0000368 /*pointerCount=*/MAX_POINTERS + 1, pointerProperties, pointerCoords);
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -0800369 ASSERT_EQ(InputEventInjectionResult::FAILED,
Harry Cutts33476232023-01-30 19:57:29 +0000370 mDispatcher->injectInputEvent(&event, /*targetUid=*/{}, InputEventInjectionSync::NONE,
Prabir Pradhan5735a322022-04-11 17:23:34 +0000371 0ms, 0))
Michael Wrightd02c5b62014-02-10 15:10:22 -0800372 << "Should reject motion events with more than MAX_POINTERS pointers.";
373
374 // Rejects motion events with invalid pointer ids.
375 pointerProperties[0].id = -1;
Garfield Tanfbe732e2020-01-24 11:26:14 -0800376 event.initialize(InputEvent::nextId(), DEVICE_ID, source, DISPLAY_ID, INVALID_HMAC,
377 AMOTION_EVENT_ACTION_DOWN, 0, 0, edgeFlags, metaState, 0, classification,
chaviw9eaa22c2020-07-01 16:21:27 -0700378 identityTransform, 0, 0, AMOTION_EVENT_INVALID_CURSOR_POSITION,
Prabir Pradhanb9b18502021-08-26 12:30:32 -0700379 AMOTION_EVENT_INVALID_CURSOR_POSITION, identityTransform, ARBITRARY_TIME,
380 ARBITRARY_TIME,
Harry Cutts101ee9b2023-07-06 18:04:14 +0000381 /*pointerCount=*/1, pointerProperties, pointerCoords);
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -0800382 ASSERT_EQ(InputEventInjectionResult::FAILED,
Harry Cutts33476232023-01-30 19:57:29 +0000383 mDispatcher->injectInputEvent(&event, /*targetUid=*/{}, InputEventInjectionSync::NONE,
Prabir Pradhan5735a322022-04-11 17:23:34 +0000384 0ms, 0))
Michael Wrightd02c5b62014-02-10 15:10:22 -0800385 << "Should reject motion events with pointer ids less than 0.";
386
387 pointerProperties[0].id = MAX_POINTER_ID + 1;
Garfield Tanfbe732e2020-01-24 11:26:14 -0800388 event.initialize(InputEvent::nextId(), DEVICE_ID, source, DISPLAY_ID, INVALID_HMAC,
389 AMOTION_EVENT_ACTION_DOWN, 0, 0, edgeFlags, metaState, 0, classification,
chaviw9eaa22c2020-07-01 16:21:27 -0700390 identityTransform, 0, 0, AMOTION_EVENT_INVALID_CURSOR_POSITION,
Prabir Pradhanb9b18502021-08-26 12:30:32 -0700391 AMOTION_EVENT_INVALID_CURSOR_POSITION, identityTransform, ARBITRARY_TIME,
392 ARBITRARY_TIME,
Harry Cutts101ee9b2023-07-06 18:04:14 +0000393 /*pointerCount=*/1, pointerProperties, pointerCoords);
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -0800394 ASSERT_EQ(InputEventInjectionResult::FAILED,
Harry Cutts33476232023-01-30 19:57:29 +0000395 mDispatcher->injectInputEvent(&event, /*targetUid=*/{}, InputEventInjectionSync::NONE,
Prabir Pradhan5735a322022-04-11 17:23:34 +0000396 0ms, 0))
Michael Wrightd02c5b62014-02-10 15:10:22 -0800397 << "Should reject motion events with pointer ids greater than MAX_POINTER_ID.";
398
399 // Rejects motion events with duplicate pointer ids.
400 pointerProperties[0].id = 1;
401 pointerProperties[1].id = 1;
Garfield Tanfbe732e2020-01-24 11:26:14 -0800402 event.initialize(InputEvent::nextId(), DEVICE_ID, source, DISPLAY_ID, INVALID_HMAC,
403 AMOTION_EVENT_ACTION_DOWN, 0, 0, edgeFlags, metaState, 0, classification,
chaviw9eaa22c2020-07-01 16:21:27 -0700404 identityTransform, 0, 0, AMOTION_EVENT_INVALID_CURSOR_POSITION,
Prabir Pradhanb9b18502021-08-26 12:30:32 -0700405 AMOTION_EVENT_INVALID_CURSOR_POSITION, identityTransform, ARBITRARY_TIME,
406 ARBITRARY_TIME,
Harry Cutts101ee9b2023-07-06 18:04:14 +0000407 /*pointerCount=*/2, pointerProperties, pointerCoords);
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -0800408 ASSERT_EQ(InputEventInjectionResult::FAILED,
Harry Cutts33476232023-01-30 19:57:29 +0000409 mDispatcher->injectInputEvent(&event, /*targetUid=*/{}, InputEventInjectionSync::NONE,
Prabir Pradhan5735a322022-04-11 17:23:34 +0000410 0ms, 0))
Michael Wrightd02c5b62014-02-10 15:10:22 -0800411 << "Should reject motion events with duplicate pointer ids.";
412}
413
Siarhei Vishniakou2bfa9052019-11-21 18:10:54 -0800414/* Test InputDispatcher for notifyConfigurationChanged and notifySwitch events */
415
416TEST_F(InputDispatcherTest, NotifyConfigurationChanged_CallsPolicy) {
417 constexpr nsecs_t eventTime = 20;
Prabir Pradhan678438e2023-04-13 19:32:51 +0000418 mDispatcher->notifyConfigurationChanged({/*id=*/10, eventTime});
Siarhei Vishniakou2bfa9052019-11-21 18:10:54 -0800419 ASSERT_TRUE(mDispatcher->waitForIdle());
420
421 mFakePolicy->assertNotifyConfigurationChangedWasCalled(eventTime);
422}
423
424TEST_F(InputDispatcherTest, NotifySwitch_CallsPolicy) {
Prabir Pradhana8fe7c52023-12-14 22:07:23 +0000425 NotifySwitchArgs args(InputEvent::nextId(), /*eventTime=*/20, /*policyFlags=*/0,
426 /*switchValues=*/1,
Harry Cutts33476232023-01-30 19:57:29 +0000427 /*switchMask=*/2);
Prabir Pradhan678438e2023-04-13 19:32:51 +0000428 mDispatcher->notifySwitch(args);
Siarhei Vishniakou2bfa9052019-11-21 18:10:54 -0800429
430 // InputDispatcher adds POLICY_FLAG_TRUSTED because the event went through InputListener
431 args.policyFlags |= POLICY_FLAG_TRUSTED;
432 mFakePolicy->assertNotifySwitchWasCalled(args);
433}
434
Siarhei Vishniakouadeb6fa2023-05-26 09:11:06 -0700435namespace {
436
Siarhei Vishniakou097c3db2020-05-06 14:18:38 -0700437static constexpr std::chrono::duration INJECT_EVENT_TIMEOUT = 500ms;
Siarhei Vishniakou540dbae2020-05-05 18:17:17 -0700438
Prabir Pradhan112b1ad2023-09-21 09:53:53 +0000439class FakeMonitorReceiver {
440public:
Siarhei Vishniakou2defec02023-06-08 17:24:44 -0700441 FakeMonitorReceiver(InputDispatcher& dispatcher, const std::string name, int32_t displayId)
442 : mInputReceiver(*dispatcher.createInputMonitor(displayId, name, MONITOR_PID), name) {}
Prabir Pradhan112b1ad2023-09-21 09:53:53 +0000443
Siarhei Vishniakou2defec02023-06-08 17:24:44 -0700444 sp<IBinder> getToken() { return mInputReceiver.getToken(); }
Prabir Pradhan112b1ad2023-09-21 09:53:53 +0000445
446 void consumeKeyDown(int32_t expectedDisplayId, int32_t expectedFlags = 0) {
Siarhei Vishniakou2defec02023-06-08 17:24:44 -0700447 mInputReceiver.consumeEvent(InputEventType::KEY, AKEY_EVENT_ACTION_DOWN, expectedDisplayId,
448 expectedFlags);
Prabir Pradhan112b1ad2023-09-21 09:53:53 +0000449 }
450
451 std::optional<int32_t> receiveEvent() {
Siarhei Vishniakoud3061ab2023-12-18 20:41:08 -0800452 const auto [sequenceNum, _] = mInputReceiver.receiveEvent(CONSUME_TIMEOUT_EVENT_EXPECTED);
453 return sequenceNum;
Prabir Pradhan112b1ad2023-09-21 09:53:53 +0000454 }
455
Siarhei Vishniakou2defec02023-06-08 17:24:44 -0700456 void finishEvent(uint32_t consumeSeq) { return mInputReceiver.finishEvent(consumeSeq); }
Prabir Pradhan112b1ad2023-09-21 09:53:53 +0000457
458 void consumeMotionDown(int32_t expectedDisplayId, int32_t expectedFlags = 0) {
Siarhei Vishniakou2defec02023-06-08 17:24:44 -0700459 mInputReceiver.consumeEvent(InputEventType::MOTION, AMOTION_EVENT_ACTION_DOWN,
460 expectedDisplayId, expectedFlags);
Prabir Pradhan112b1ad2023-09-21 09:53:53 +0000461 }
462
463 void consumeMotionMove(int32_t expectedDisplayId, int32_t expectedFlags = 0) {
Siarhei Vishniakou2defec02023-06-08 17:24:44 -0700464 mInputReceiver.consumeEvent(InputEventType::MOTION, AMOTION_EVENT_ACTION_MOVE,
465 expectedDisplayId, expectedFlags);
Prabir Pradhan112b1ad2023-09-21 09:53:53 +0000466 }
467
468 void consumeMotionUp(int32_t expectedDisplayId, int32_t expectedFlags = 0) {
Siarhei Vishniakou2defec02023-06-08 17:24:44 -0700469 mInputReceiver.consumeEvent(InputEventType::MOTION, AMOTION_EVENT_ACTION_UP,
470 expectedDisplayId, expectedFlags);
Prabir Pradhan112b1ad2023-09-21 09:53:53 +0000471 }
472
473 void consumeMotionCancel(int32_t expectedDisplayId, int32_t expectedFlags = 0) {
Siarhei Vishniakou2defec02023-06-08 17:24:44 -0700474 mInputReceiver.consumeMotionEvent(
Prabir Pradhan112b1ad2023-09-21 09:53:53 +0000475 AllOf(WithMotionAction(AMOTION_EVENT_ACTION_CANCEL),
476 WithDisplayId(expectedDisplayId),
477 WithFlags(expectedFlags | AMOTION_EVENT_FLAG_CANCELED)));
478 }
479
480 void consumeMotionPointerDown(int32_t pointerIdx) {
481 int32_t action = AMOTION_EVENT_ACTION_POINTER_DOWN |
482 (pointerIdx << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT);
Siarhei Vishniakou2defec02023-06-08 17:24:44 -0700483 mInputReceiver.consumeEvent(InputEventType::MOTION, action, ADISPLAY_ID_DEFAULT,
484 /*expectedFlags=*/0);
Prabir Pradhan112b1ad2023-09-21 09:53:53 +0000485 }
486
487 void consumeMotionEvent(const ::testing::Matcher<MotionEvent>& matcher) {
Siarhei Vishniakou2defec02023-06-08 17:24:44 -0700488 mInputReceiver.consumeMotionEvent(matcher);
Prabir Pradhan112b1ad2023-09-21 09:53:53 +0000489 }
490
Siarhei Vishniakoud3061ab2023-12-18 20:41:08 -0800491 std::unique_ptr<MotionEvent> consumeMotion() { return mInputReceiver.consumeMotion(); }
Prabir Pradhan112b1ad2023-09-21 09:53:53 +0000492
Siarhei Vishniakouef2b4502023-12-28 11:51:47 -0800493 void assertNoEvents() { mInputReceiver.assertNoEvents(CONSUME_TIMEOUT_NO_EVENT_EXPECTED); }
Prabir Pradhan112b1ad2023-09-21 09:53:53 +0000494
495private:
Siarhei Vishniakou2defec02023-06-08 17:24:44 -0700496 FakeInputReceiver mInputReceiver;
Prabir Pradhan112b1ad2023-09-21 09:53:53 +0000497};
498
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -0800499static InputEventInjectionResult injectKey(
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -0700500 InputDispatcher& dispatcher, int32_t action, int32_t repeatCount,
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -0800501 int32_t displayId = ADISPLAY_ID_NONE,
502 InputEventInjectionSync syncMode = InputEventInjectionSync::WAIT_FOR_RESULT,
Prabir Pradhan93f342c2021-03-11 15:05:30 -0800503 std::chrono::milliseconds injectionTimeout = INJECT_EVENT_TIMEOUT,
Prabir Pradhan8a5c41d2023-06-08 19:13:46 +0000504 bool allowKeyRepeat = true, std::optional<gui::Uid> targetUid = {},
Prabir Pradhan5735a322022-04-11 17:23:34 +0000505 uint32_t policyFlags = DEFAULT_POLICY_FLAGS) {
Arthur Hungb92218b2018-08-14 12:00:21 +0800506 KeyEvent event;
507 nsecs_t currentTime = systemTime(SYSTEM_TIME_MONOTONIC);
508
509 // Define a valid key down event.
Garfield Tanfbe732e2020-01-24 11:26:14 -0800510 event.initialize(InputEvent::nextId(), DEVICE_ID, AINPUT_SOURCE_KEYBOARD, displayId,
Harry Cutts33476232023-01-30 19:57:29 +0000511 INVALID_HMAC, action, /*flags=*/0, AKEYCODE_A, KEY_A, AMETA_NONE, repeatCount,
512 currentTime, currentTime);
Arthur Hungb92218b2018-08-14 12:00:21 +0800513
Prabir Pradhan93f342c2021-03-11 15:05:30 -0800514 if (!allowKeyRepeat) {
515 policyFlags |= POLICY_FLAG_DISABLE_KEY_REPEAT;
516 }
Arthur Hungb92218b2018-08-14 12:00:21 +0800517 // Inject event until dispatch out.
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -0700518 return dispatcher.injectInputEvent(&event, targetUid, syncMode, injectionTimeout, policyFlags);
Arthur Hungb92218b2018-08-14 12:00:21 +0800519}
520
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -0700521static void assertInjectedKeyTimesOut(InputDispatcher& dispatcher) {
522 InputEventInjectionResult result =
523 injectKey(dispatcher, AKEY_EVENT_ACTION_DOWN, /*repeatCount=*/0, ADISPLAY_ID_NONE,
524 InputEventInjectionSync::WAIT_FOR_RESULT, CONSUME_TIMEOUT_NO_EVENT_EXPECTED);
525 if (result != InputEventInjectionResult::TIMED_OUT) {
526 FAIL() << "Injection should have timed out, but got " << ftl::enum_string(result);
527 }
528}
529
530static InputEventInjectionResult injectKeyDown(InputDispatcher& dispatcher,
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -0800531 int32_t displayId = ADISPLAY_ID_NONE) {
Harry Cutts33476232023-01-30 19:57:29 +0000532 return injectKey(dispatcher, AKEY_EVENT_ACTION_DOWN, /*repeatCount=*/0, displayId);
Siarhei Vishniakou4cb50ca2020-05-26 21:43:02 -0700533}
534
Prabir Pradhan93f342c2021-03-11 15:05:30 -0800535// Inject a down event that has key repeat disabled. This allows InputDispatcher to idle without
536// sending a subsequent key up. When key repeat is enabled, the dispatcher cannot idle because it
537// has to be woken up to process the repeating key.
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -0700538static InputEventInjectionResult injectKeyDownNoRepeat(InputDispatcher& dispatcher,
539 int32_t displayId = ADISPLAY_ID_NONE) {
Harry Cutts33476232023-01-30 19:57:29 +0000540 return injectKey(dispatcher, AKEY_EVENT_ACTION_DOWN, /*repeatCount=*/0, displayId,
Prabir Pradhan93f342c2021-03-11 15:05:30 -0800541 InputEventInjectionSync::WAIT_FOR_RESULT, INJECT_EVENT_TIMEOUT,
Harry Cutts33476232023-01-30 19:57:29 +0000542 /*allowKeyRepeat=*/false);
Prabir Pradhan93f342c2021-03-11 15:05:30 -0800543}
544
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -0700545static InputEventInjectionResult injectKeyUp(InputDispatcher& dispatcher,
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -0800546 int32_t displayId = ADISPLAY_ID_NONE) {
Harry Cutts33476232023-01-30 19:57:29 +0000547 return injectKey(dispatcher, AKEY_EVENT_ACTION_UP, /*repeatCount=*/0, displayId);
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -0700548}
549
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -0800550static InputEventInjectionResult injectMotionEvent(
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -0700551 InputDispatcher& dispatcher, const MotionEvent& event,
Garfield Tandf26e862020-07-01 20:18:19 -0700552 std::chrono::milliseconds injectionTimeout = INJECT_EVENT_TIMEOUT,
Prabir Pradhan5735a322022-04-11 17:23:34 +0000553 InputEventInjectionSync injectionMode = InputEventInjectionSync::WAIT_FOR_RESULT,
Prabir Pradhan8a5c41d2023-06-08 19:13:46 +0000554 std::optional<gui::Uid> targetUid = {}, uint32_t policyFlags = DEFAULT_POLICY_FLAGS) {
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -0700555 return dispatcher.injectInputEvent(&event, targetUid, injectionMode, injectionTimeout,
556 policyFlags);
Garfield Tandf26e862020-07-01 20:18:19 -0700557}
558
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -0800559static InputEventInjectionResult injectMotionEvent(
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -0700560 InputDispatcher& dispatcher, int32_t action, int32_t source, int32_t displayId,
561 const PointF& position = {100, 200},
Siarhei Vishniakou4cb50ca2020-05-26 21:43:02 -0700562 const PointF& cursorPosition = {AMOTION_EVENT_INVALID_CURSOR_POSITION,
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -0700563 AMOTION_EVENT_INVALID_CURSOR_POSITION},
564 std::chrono::milliseconds injectionTimeout = INJECT_EVENT_TIMEOUT,
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -0800565 InputEventInjectionSync injectionMode = InputEventInjectionSync::WAIT_FOR_RESULT,
Prabir Pradhan5735a322022-04-11 17:23:34 +0000566 nsecs_t eventTime = systemTime(SYSTEM_TIME_MONOTONIC),
Prabir Pradhan8a5c41d2023-06-08 19:13:46 +0000567 std::optional<gui::Uid> targetUid = {}, uint32_t policyFlags = DEFAULT_POLICY_FLAGS) {
Siarhei Vishniakou90ee4782023-05-08 11:57:24 -0700568 MotionEventBuilder motionBuilder =
569 MotionEventBuilder(action, source)
570 .displayId(displayId)
571 .eventTime(eventTime)
572 .rawXCursorPosition(cursorPosition.x)
573 .rawYCursorPosition(cursorPosition.y)
574 .pointer(
575 PointerBuilder(/*id=*/0, ToolType::FINGER).x(position.x).y(position.y));
576 if (MotionEvent::getActionMasked(action) == ACTION_DOWN) {
577 motionBuilder.downTime(eventTime);
578 }
Arthur Hungb92218b2018-08-14 12:00:21 +0800579
580 // Inject event until dispatch out.
Siarhei Vishniakou90ee4782023-05-08 11:57:24 -0700581 return injectMotionEvent(dispatcher, motionBuilder.build(), injectionTimeout, injectionMode,
582 targetUid, policyFlags);
Arthur Hungb92218b2018-08-14 12:00:21 +0800583}
584
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -0700585static InputEventInjectionResult injectMotionDown(InputDispatcher& dispatcher, int32_t source,
586 int32_t displayId,
587 const PointF& location = {100, 200}) {
Siarhei Vishniakou4cb50ca2020-05-26 21:43:02 -0700588 return injectMotionEvent(dispatcher, AMOTION_EVENT_ACTION_DOWN, source, displayId, location);
Garfield Tan00f511d2019-06-12 16:55:40 -0700589}
590
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -0700591static InputEventInjectionResult injectMotionUp(InputDispatcher& dispatcher, int32_t source,
592 int32_t displayId,
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -0800593 const PointF& location = {100, 200}) {
Siarhei Vishniakou4cb50ca2020-05-26 21:43:02 -0700594 return injectMotionEvent(dispatcher, AMOTION_EVENT_ACTION_UP, source, displayId, location);
Michael Wright3a240c42019-12-10 20:53:41 +0000595}
596
Jackal Guof9696682018-10-05 12:23:23 +0800597static NotifyKeyArgs generateKeyArgs(int32_t action, int32_t displayId = ADISPLAY_ID_NONE) {
598 nsecs_t currentTime = systemTime(SYSTEM_TIME_MONOTONIC);
599 // Define a valid key event.
Prabir Pradhana8fe7c52023-12-14 22:07:23 +0000600 NotifyKeyArgs args(InputEvent::nextId(), currentTime, /*readTime=*/0, DEVICE_ID,
601 AINPUT_SOURCE_KEYBOARD, displayId, POLICY_FLAG_PASS_TO_USER, action,
602 /*flags=*/0, AKEYCODE_A, KEY_A, AMETA_NONE, currentTime);
Jackal Guof9696682018-10-05 12:23:23 +0800603
604 return args;
605}
606
Josep del Riob3981622023-04-18 15:49:45 +0000607static NotifyKeyArgs generateSystemShortcutArgs(int32_t action,
608 int32_t displayId = ADISPLAY_ID_NONE) {
609 nsecs_t currentTime = systemTime(SYSTEM_TIME_MONOTONIC);
610 // Define a valid key event.
Prabir Pradhana8fe7c52023-12-14 22:07:23 +0000611 NotifyKeyArgs args(InputEvent::nextId(), currentTime, /*readTime=*/0, DEVICE_ID,
612 AINPUT_SOURCE_KEYBOARD, displayId, 0, action, /*flags=*/0, AKEYCODE_C, KEY_C,
613 AMETA_META_ON, currentTime);
Josep del Riob3981622023-04-18 15:49:45 +0000614
615 return args;
616}
617
618static NotifyKeyArgs generateAssistantKeyArgs(int32_t action,
619 int32_t displayId = ADISPLAY_ID_NONE) {
620 nsecs_t currentTime = systemTime(SYSTEM_TIME_MONOTONIC);
621 // Define a valid key event.
Prabir Pradhana8fe7c52023-12-14 22:07:23 +0000622 NotifyKeyArgs args(InputEvent::nextId(), currentTime, /*readTime=*/0, DEVICE_ID,
623 AINPUT_SOURCE_KEYBOARD, displayId, 0, action, /*flags=*/0, AKEYCODE_ASSIST,
624 KEY_ASSISTANT, AMETA_NONE, currentTime);
Josep del Riob3981622023-04-18 15:49:45 +0000625
626 return args;
627}
628
Prabir Pradhan678438e2023-04-13 19:32:51 +0000629[[nodiscard]] static NotifyMotionArgs generateMotionArgs(int32_t action, int32_t source,
630 int32_t displayId,
631 const std::vector<PointF>& points) {
chaviwd1c23182019-12-20 18:44:56 -0800632 size_t pointerCount = points.size();
chaviwaf87b3e2019-10-01 16:59:28 -0700633 if (action == AMOTION_EVENT_ACTION_DOWN || action == AMOTION_EVENT_ACTION_UP) {
634 EXPECT_EQ(1U, pointerCount) << "Actions DOWN and UP can only contain a single pointer";
635 }
636
chaviwd1c23182019-12-20 18:44:56 -0800637 PointerProperties pointerProperties[pointerCount];
638 PointerCoords pointerCoords[pointerCount];
Jackal Guof9696682018-10-05 12:23:23 +0800639
chaviwd1c23182019-12-20 18:44:56 -0800640 for (size_t i = 0; i < pointerCount; i++) {
641 pointerProperties[i].clear();
642 pointerProperties[i].id = i;
Siarhei Vishniakou6d73f832022-07-21 17:27:03 -0700643 pointerProperties[i].toolType = ToolType::FINGER;
Jackal Guof9696682018-10-05 12:23:23 +0800644
chaviwd1c23182019-12-20 18:44:56 -0800645 pointerCoords[i].clear();
646 pointerCoords[i].setAxisValue(AMOTION_EVENT_AXIS_X, points[i].x);
647 pointerCoords[i].setAxisValue(AMOTION_EVENT_AXIS_Y, points[i].y);
648 }
Jackal Guof9696682018-10-05 12:23:23 +0800649
650 nsecs_t currentTime = systemTime(SYSTEM_TIME_MONOTONIC);
651 // Define a valid motion event.
Prabir Pradhana8fe7c52023-12-14 22:07:23 +0000652 NotifyMotionArgs args(InputEvent::nextId(), currentTime, /*readTime=*/0, DEVICE_ID, source,
653 displayId, POLICY_FLAG_PASS_TO_USER, action, /*actionButton=*/0,
654 /*flags=*/0, AMETA_NONE, /*buttonState=*/0, MotionClassification::NONE,
chaviwd1c23182019-12-20 18:44:56 -0800655 AMOTION_EVENT_EDGE_FLAG_NONE, pointerCount, pointerProperties,
Harry Cutts101ee9b2023-07-06 18:04:14 +0000656 pointerCoords, /*xPrecision=*/0, /*yPrecision=*/0,
Garfield Tan00f511d2019-06-12 16:55:40 -0700657 AMOTION_EVENT_INVALID_CURSOR_POSITION,
Harry Cutts101ee9b2023-07-06 18:04:14 +0000658 AMOTION_EVENT_INVALID_CURSOR_POSITION, currentTime, /*videoFrames=*/{});
Jackal Guof9696682018-10-05 12:23:23 +0800659
660 return args;
661}
662
Siarhei Vishniakoua16e3a22022-03-02 15:26:40 -0800663static NotifyMotionArgs generateTouchArgs(int32_t action, const std::vector<PointF>& points) {
664 return generateMotionArgs(action, AINPUT_SOURCE_TOUCHSCREEN, DISPLAY_ID, points);
665}
666
chaviwd1c23182019-12-20 18:44:56 -0800667static NotifyMotionArgs generateMotionArgs(int32_t action, int32_t source, int32_t displayId) {
668 return generateMotionArgs(action, source, displayId, {PointF{100, 200}});
669}
670
Prabir Pradhan5cc1a692021-08-06 14:01:18 +0000671static NotifyPointerCaptureChangedArgs generatePointerCaptureChangedArgs(
672 const PointerCaptureRequest& request) {
Prabir Pradhana8fe7c52023-12-14 22:07:23 +0000673 return NotifyPointerCaptureChangedArgs(InputEvent::nextId(), systemTime(SYSTEM_TIME_MONOTONIC),
674 request);
Prabir Pradhan99987712020-11-10 18:43:05 -0800675}
676
Siarhei Vishniakouadeb6fa2023-05-26 09:11:06 -0700677} // namespace
678
Siarhei Vishniakou7aa3e942021-11-18 09:49:11 -0800679/**
680 * When a window unexpectedly disposes of its input channel, policy should be notified about the
681 * broken channel.
682 */
683TEST_F(InputDispatcherTest, WhenInputChannelBreaks_PolicyIsNotified) {
684 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
685 sp<FakeWindowHandle> window =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -0700686 sp<FakeWindowHandle>::make(application, mDispatcher,
687 "Window that breaks its input channel", ADISPLAY_ID_DEFAULT);
Siarhei Vishniakou7aa3e942021-11-18 09:49:11 -0800688
Siarhei Vishniakouc41de372023-07-20 13:14:26 -0700689 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Siarhei Vishniakou7aa3e942021-11-18 09:49:11 -0800690
691 // Window closes its channel, but the window remains.
692 window->destroyReceiver();
693 mFakePolicy->assertNotifyInputChannelBrokenWasCalled(window->getInfo()->token);
694}
695
Arthur Hungb92218b2018-08-14 12:00:21 +0800696TEST_F(InputDispatcherTest, SetInputWindow_SingleWindowTouch) {
Chris Yea209fde2020-07-22 13:54:51 -0700697 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -0700698 sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher,
699 "Fake Window", ADISPLAY_ID_DEFAULT);
Arthur Hungb92218b2018-08-14 12:00:21 +0800700
Siarhei Vishniakouc41de372023-07-20 13:14:26 -0700701 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -0800702 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -0700703 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT))
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -0800704 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
Arthur Hungb92218b2018-08-14 12:00:21 +0800705
706 // Window should receive motion event.
Siarhei Vishniakouc5ca85c2019-11-15 17:20:00 -0800707 window->consumeMotionDown(ADISPLAY_ID_DEFAULT);
Arthur Hungb92218b2018-08-14 12:00:21 +0800708}
709
Siarhei Vishniakouaeed0da2024-01-09 08:57:13 -0800710using InputDispatcherDeathTest = InputDispatcherTest;
711
712/**
713 * When 'onWindowInfosChanged' arguments contain a duplicate entry for the same window, dispatcher
714 * should crash.
715 */
716TEST_F(InputDispatcherDeathTest, DuplicateWindowInfosAbortDispatcher) {
717 testing::GTEST_FLAG(death_test_style) = "threadsafe";
718 ScopedSilentDeath _silentDeath;
719
720 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
721 sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher,
722 "Fake Window", ADISPLAY_ID_DEFAULT);
723 ASSERT_DEATH(mDispatcher->onWindowInfosChanged(
724 {{*window->getInfo(), *window->getInfo()}, {}, 0, 0}),
725 "Incorrect WindowInfosUpdate provided");
726}
727
Prabir Pradhanc44ce4d2021-10-05 05:26:29 -0700728TEST_F(InputDispatcherTest, WhenDisplayNotSpecified_InjectMotionToDefaultDisplay) {
729 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -0700730 sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher,
731 "Fake Window", ADISPLAY_ID_DEFAULT);
Prabir Pradhanc44ce4d2021-10-05 05:26:29 -0700732
Siarhei Vishniakouc41de372023-07-20 13:14:26 -0700733 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Prabir Pradhanc44ce4d2021-10-05 05:26:29 -0700734 // Inject a MotionEvent to an unknown display.
735 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -0700736 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_NONE))
Prabir Pradhanc44ce4d2021-10-05 05:26:29 -0700737 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
738
739 // Window should receive motion event.
740 window->consumeMotionDown(ADISPLAY_ID_DEFAULT);
741}
742
Siarhei Vishniakoufb9fcda2020-05-04 14:59:19 -0700743/**
Siarhei Vishniakouc41de372023-07-20 13:14:26 -0700744 * Calling onWindowInfosChanged once should not cause any issues.
745 * This test serves as a sanity check for the next test, where onWindowInfosChanged is
Siarhei Vishniakoufb9fcda2020-05-04 14:59:19 -0700746 * called twice.
747 */
Prabir Pradhan76bdecb2022-01-31 11:14:15 -0800748TEST_F(InputDispatcherTest, SetInputWindowOnceWithSingleTouchWindow) {
Chris Yea209fde2020-07-22 13:54:51 -0700749 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -0700750 sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher,
751 "Fake Window", ADISPLAY_ID_DEFAULT);
Siarhei Vishniakoufb9fcda2020-05-04 14:59:19 -0700752 window->setFrame(Rect(0, 0, 100, 100));
Siarhei Vishniakoufb9fcda2020-05-04 14:59:19 -0700753
Siarhei Vishniakouc41de372023-07-20 13:14:26 -0700754 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -0800755 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -0700756 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
Siarhei Vishniakoufb9fcda2020-05-04 14:59:19 -0700757 {50, 50}))
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -0800758 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
Siarhei Vishniakoufb9fcda2020-05-04 14:59:19 -0700759
760 // Window should receive motion event.
761 window->consumeMotionDown(ADISPLAY_ID_DEFAULT);
762}
763
764/**
Siarhei Vishniakouc41de372023-07-20 13:14:26 -0700765 * Calling onWindowInfosChanged twice, with the same info, should not cause any issues.
Siarhei Vishniakoufb9fcda2020-05-04 14:59:19 -0700766 */
767TEST_F(InputDispatcherTest, SetInputWindowTwice_SingleWindowTouch) {
Chris Yea209fde2020-07-22 13:54:51 -0700768 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -0700769 sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher,
770 "Fake Window", ADISPLAY_ID_DEFAULT);
Siarhei Vishniakoufb9fcda2020-05-04 14:59:19 -0700771 window->setFrame(Rect(0, 0, 100, 100));
Siarhei Vishniakoufb9fcda2020-05-04 14:59:19 -0700772
Siarhei Vishniakouc41de372023-07-20 13:14:26 -0700773 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
774 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -0800775 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -0700776 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
Siarhei Vishniakoufb9fcda2020-05-04 14:59:19 -0700777 {50, 50}))
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -0800778 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
Siarhei Vishniakoufb9fcda2020-05-04 14:59:19 -0700779
780 // Window should receive motion event.
781 window->consumeMotionDown(ADISPLAY_ID_DEFAULT);
782}
783
Arthur Hungb92218b2018-08-14 12:00:21 +0800784// The foreground window should receive the first touch down event.
785TEST_F(InputDispatcherTest, SetInputWindow_MultiWindowsTouch) {
Chris Yea209fde2020-07-22 13:54:51 -0700786 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
Siarhei Vishniakou870ecec2020-12-09 08:07:46 -1000787 sp<FakeWindowHandle> windowTop =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -0700788 sp<FakeWindowHandle>::make(application, mDispatcher, "Top", ADISPLAY_ID_DEFAULT);
Siarhei Vishniakou870ecec2020-12-09 08:07:46 -1000789 sp<FakeWindowHandle> windowSecond =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -0700790 sp<FakeWindowHandle>::make(application, mDispatcher, "Second", ADISPLAY_ID_DEFAULT);
Arthur Hungb92218b2018-08-14 12:00:21 +0800791
Siarhei Vishniakouc41de372023-07-20 13:14:26 -0700792 mDispatcher->onWindowInfosChanged(
793 {{*windowTop->getInfo(), *windowSecond->getInfo()}, {}, 0, 0});
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -0800794 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -0700795 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT))
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -0800796 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
Arthur Hungb92218b2018-08-14 12:00:21 +0800797
798 // Top window should receive the touch down event. Second window should not receive anything.
Siarhei Vishniakouc5ca85c2019-11-15 17:20:00 -0800799 windowTop->consumeMotionDown(ADISPLAY_ID_DEFAULT);
Arthur Hungb92218b2018-08-14 12:00:21 +0800800 windowSecond->assertNoEvents();
801}
802
Siarhei Vishniakouca205502021-07-16 21:31:58 +0000803/**
804 * Two windows: A top window, and a wallpaper behind the window.
805 * Touch goes to the top window, and then top window disappears. Ensure that wallpaper window
806 * gets ACTION_CANCEL.
Prabir Pradhan4d5c52f2022-01-31 08:52:10 -0800807 * 1. foregroundWindow <-- dup touch to wallpaper
808 * 2. wallpaperWindow <-- is wallpaper
Siarhei Vishniakouca205502021-07-16 21:31:58 +0000809 */
810TEST_F(InputDispatcherTest, WhenForegroundWindowDisappears_WallpaperTouchIsCanceled) {
811 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
812 sp<FakeWindowHandle> foregroundWindow =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -0700813 sp<FakeWindowHandle>::make(application, mDispatcher, "Foreground", ADISPLAY_ID_DEFAULT);
Prabir Pradhan4d5c52f2022-01-31 08:52:10 -0800814 foregroundWindow->setDupTouchToWallpaper(true);
Siarhei Vishniakouca205502021-07-16 21:31:58 +0000815 sp<FakeWindowHandle> wallpaperWindow =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -0700816 sp<FakeWindowHandle>::make(application, mDispatcher, "Wallpaper", ADISPLAY_ID_DEFAULT);
Prabir Pradhan4d5c52f2022-01-31 08:52:10 -0800817 wallpaperWindow->setIsWallpaper(true);
Siarhei Vishniakouca205502021-07-16 21:31:58 +0000818
Siarhei Vishniakouc41de372023-07-20 13:14:26 -0700819 mDispatcher->onWindowInfosChanged(
820 {{*foregroundWindow->getInfo(), *wallpaperWindow->getInfo()}, {}, 0, 0});
Siarhei Vishniakouca205502021-07-16 21:31:58 +0000821 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoud908f5a2023-11-16 10:25:12 -0800822 injectMotionEvent(*mDispatcher,
823 MotionEventBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
824 .pointer(PointerBuilder(0, ToolType::FINGER).x(100).y(200))
825 .build()))
Siarhei Vishniakouca205502021-07-16 21:31:58 +0000826 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
827
828 // Both foreground window and its wallpaper should receive the touch down
829 foregroundWindow->consumeMotionDown();
830 wallpaperWindow->consumeMotionDown(ADISPLAY_ID_DEFAULT, expectedWallpaperFlags);
831
832 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoud908f5a2023-11-16 10:25:12 -0800833 injectMotionEvent(*mDispatcher,
834 MotionEventBuilder(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN)
835 .pointer(PointerBuilder(0, ToolType::FINGER).x(110).y(200))
836 .build()))
Siarhei Vishniakouca205502021-07-16 21:31:58 +0000837 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
838
Siarhei Vishniakoud908f5a2023-11-16 10:25:12 -0800839 foregroundWindow->consumeMotionEvent(WithMotionAction(ACTION_MOVE));
Siarhei Vishniakouca205502021-07-16 21:31:58 +0000840 wallpaperWindow->consumeMotionMove(ADISPLAY_ID_DEFAULT, expectedWallpaperFlags);
841
842 // Now the foreground window goes away, but the wallpaper stays
Siarhei Vishniakouc41de372023-07-20 13:14:26 -0700843 mDispatcher->onWindowInfosChanged({{*wallpaperWindow->getInfo()}, {}, 0, 0});
Siarhei Vishniakouca205502021-07-16 21:31:58 +0000844 foregroundWindow->consumeMotionCancel();
845 // Since the "parent" window of the wallpaper is gone, wallpaper should receive cancel, too.
846 wallpaperWindow->consumeMotionCancel(ADISPLAY_ID_DEFAULT, expectedWallpaperFlags);
847}
848
849/**
Siarhei Vishniakou82dc0422023-02-17 23:12:52 -0800850 * Two fingers down on the window, and lift off the first finger.
851 * Next, cancel the gesture to the window by removing the window. Make sure that the CANCEL event
852 * contains a single pointer.
853 */
854TEST_F(InputDispatcherTest, CancelAfterPointer0Up) {
855 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
856 sp<FakeWindowHandle> window =
857 sp<FakeWindowHandle>::make(application, mDispatcher, "Window", ADISPLAY_ID_DEFAULT);
858
Siarhei Vishniakouc41de372023-07-20 13:14:26 -0700859 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Siarhei Vishniakou82dc0422023-02-17 23:12:52 -0800860 // First touch pointer down on right window
Prabir Pradhan678438e2023-04-13 19:32:51 +0000861 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
862 .pointer(PointerBuilder(0, ToolType::FINGER).x(100).y(100))
863 .build());
Siarhei Vishniakou82dc0422023-02-17 23:12:52 -0800864 // Second touch pointer down
Prabir Pradhan678438e2023-04-13 19:32:51 +0000865 mDispatcher->notifyMotion(MotionArgsBuilder(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
866 .pointer(PointerBuilder(0, ToolType::FINGER).x(100).y(100))
867 .pointer(PointerBuilder(1, ToolType::FINGER).x(110).y(100))
868 .build());
Siarhei Vishniakou82dc0422023-02-17 23:12:52 -0800869 // First touch pointer lifts. The second one remains down
Prabir Pradhan678438e2023-04-13 19:32:51 +0000870 mDispatcher->notifyMotion(MotionArgsBuilder(POINTER_0_UP, AINPUT_SOURCE_TOUCHSCREEN)
871 .pointer(PointerBuilder(0, ToolType::FINGER).x(100).y(100))
872 .pointer(PointerBuilder(1, ToolType::FINGER).x(110).y(100))
873 .build());
Siarhei Vishniakou82dc0422023-02-17 23:12:52 -0800874 window->consumeMotionEvent(WithMotionAction(ACTION_DOWN));
875 window->consumeMotionEvent(WithMotionAction(POINTER_1_DOWN));
876 window->consumeMotionEvent(WithMotionAction(POINTER_0_UP));
877
878 // Remove the window. The gesture should be canceled
Siarhei Vishniakouc41de372023-07-20 13:14:26 -0700879 mDispatcher->onWindowInfosChanged({{}, {}, 0, 0});
Siarhei Vishniakou82dc0422023-02-17 23:12:52 -0800880 const std::map<int32_t, PointF> expectedPointers{{1, PointF{110, 100}}};
881 window->consumeMotionEvent(
882 AllOf(WithMotionAction(ACTION_CANCEL), WithPointers(expectedPointers)));
883}
884
885/**
Siarhei Vishniakou2b030972021-11-18 10:01:27 -0800886 * Same test as WhenForegroundWindowDisappears_WallpaperTouchIsCanceled above,
887 * with the following differences:
888 * After ACTION_DOWN, Wallpaper window hangs up its channel, which forces the dispatcher to
889 * clean up the connection.
890 * This later may crash dispatcher during ACTION_CANCEL synthesis, if the dispatcher is not careful.
891 * Ensure that there's no crash in the dispatcher.
892 */
893TEST_F(InputDispatcherTest, WhenWallpaperDisappears_NoCrash) {
894 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
895 sp<FakeWindowHandle> foregroundWindow =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -0700896 sp<FakeWindowHandle>::make(application, mDispatcher, "Foreground", ADISPLAY_ID_DEFAULT);
Prabir Pradhan4d5c52f2022-01-31 08:52:10 -0800897 foregroundWindow->setDupTouchToWallpaper(true);
Siarhei Vishniakou2b030972021-11-18 10:01:27 -0800898 sp<FakeWindowHandle> wallpaperWindow =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -0700899 sp<FakeWindowHandle>::make(application, mDispatcher, "Wallpaper", ADISPLAY_ID_DEFAULT);
Prabir Pradhan4d5c52f2022-01-31 08:52:10 -0800900 wallpaperWindow->setIsWallpaper(true);
Siarhei Vishniakou2b030972021-11-18 10:01:27 -0800901
Siarhei Vishniakouc41de372023-07-20 13:14:26 -0700902 mDispatcher->onWindowInfosChanged(
903 {{*foregroundWindow->getInfo(), *wallpaperWindow->getInfo()}, {}, 0, 0});
Siarhei Vishniakou2b030972021-11-18 10:01:27 -0800904 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -0700905 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
Siarhei Vishniakou2b030972021-11-18 10:01:27 -0800906 {100, 200}))
907 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
908
909 // Both foreground window and its wallpaper should receive the touch down
910 foregroundWindow->consumeMotionDown();
911 wallpaperWindow->consumeMotionDown(ADISPLAY_ID_DEFAULT, expectedWallpaperFlags);
912
913 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -0700914 injectMotionEvent(*mDispatcher, AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN,
Siarhei Vishniakou2b030972021-11-18 10:01:27 -0800915 ADISPLAY_ID_DEFAULT, {110, 200}))
916 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
917
918 foregroundWindow->consumeMotionMove();
919 wallpaperWindow->consumeMotionMove(ADISPLAY_ID_DEFAULT, expectedWallpaperFlags);
920
921 // Wallpaper closes its channel, but the window remains.
922 wallpaperWindow->destroyReceiver();
923 mFakePolicy->assertNotifyInputChannelBrokenWasCalled(wallpaperWindow->getInfo()->token);
924
925 // Now the foreground window goes away, but the wallpaper stays, even though its channel
926 // is no longer valid.
Siarhei Vishniakouc41de372023-07-20 13:14:26 -0700927 mDispatcher->onWindowInfosChanged({{*wallpaperWindow->getInfo()}, {}, 0, 0});
Siarhei Vishniakou2b030972021-11-18 10:01:27 -0800928 foregroundWindow->consumeMotionCancel();
929}
930
Arthur Hungc539dbb2022-12-08 07:45:36 +0000931class ShouldSplitTouchFixture : public InputDispatcherTest,
932 public ::testing::WithParamInterface<bool> {};
933INSTANTIATE_TEST_SUITE_P(InputDispatcherTest, ShouldSplitTouchFixture,
934 ::testing::Values(true, false));
Siarhei Vishniakou2b030972021-11-18 10:01:27 -0800935/**
Siarhei Vishniakouca205502021-07-16 21:31:58 +0000936 * A single window that receives touch (on top), and a wallpaper window underneath it.
937 * The top window gets a multitouch gesture.
938 * Ensure that wallpaper gets the same gesture.
939 */
Arthur Hungc539dbb2022-12-08 07:45:36 +0000940TEST_P(ShouldSplitTouchFixture, WallpaperWindowReceivesMultiTouch) {
Siarhei Vishniakouca205502021-07-16 21:31:58 +0000941 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
Arthur Hungc539dbb2022-12-08 07:45:36 +0000942 sp<FakeWindowHandle> foregroundWindow =
943 sp<FakeWindowHandle>::make(application, mDispatcher, "Foreground", ADISPLAY_ID_DEFAULT);
944 foregroundWindow->setDupTouchToWallpaper(true);
945 foregroundWindow->setPreventSplitting(GetParam());
Siarhei Vishniakouca205502021-07-16 21:31:58 +0000946
947 sp<FakeWindowHandle> wallpaperWindow =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -0700948 sp<FakeWindowHandle>::make(application, mDispatcher, "Wallpaper", ADISPLAY_ID_DEFAULT);
Prabir Pradhan4d5c52f2022-01-31 08:52:10 -0800949 wallpaperWindow->setIsWallpaper(true);
Siarhei Vishniakouca205502021-07-16 21:31:58 +0000950
Siarhei Vishniakouc41de372023-07-20 13:14:26 -0700951 mDispatcher->onWindowInfosChanged(
952 {{*foregroundWindow->getInfo(), *wallpaperWindow->getInfo()}, {}, 0, 0});
Siarhei Vishniakouca205502021-07-16 21:31:58 +0000953
954 // Touch down on top window
955 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -0700956 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
Siarhei Vishniakouca205502021-07-16 21:31:58 +0000957 {100, 100}))
958 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
959
960 // Both top window and its wallpaper should receive the touch down
Arthur Hungc539dbb2022-12-08 07:45:36 +0000961 foregroundWindow->consumeMotionDown();
Siarhei Vishniakouca205502021-07-16 21:31:58 +0000962 wallpaperWindow->consumeMotionDown(ADISPLAY_ID_DEFAULT, expectedWallpaperFlags);
963
964 // Second finger down on the top window
965 const MotionEvent secondFingerDownEvent =
Siarhei Vishniakoua16e3a22022-03-02 15:26:40 -0800966 MotionEventBuilder(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
Siarhei Vishniakouca205502021-07-16 21:31:58 +0000967 .eventTime(systemTime(SYSTEM_TIME_MONOTONIC))
Siarhei Vishniakou6d73f832022-07-21 17:27:03 -0700968 .pointer(PointerBuilder(/*id=*/0, ToolType::FINGER).x(100).y(100))
969 .pointer(PointerBuilder(/*id=*/1, ToolType::FINGER).x(150).y(150))
Siarhei Vishniakouca205502021-07-16 21:31:58 +0000970 .build();
971 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -0700972 injectMotionEvent(*mDispatcher, secondFingerDownEvent, INJECT_EVENT_TIMEOUT,
Siarhei Vishniakouca205502021-07-16 21:31:58 +0000973 InputEventInjectionSync::WAIT_FOR_RESULT))
974 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
975
Harry Cutts33476232023-01-30 19:57:29 +0000976 foregroundWindow->consumeMotionPointerDown(/*pointerIndex=*/1);
977 wallpaperWindow->consumeMotionPointerDown(/*pointerIndex=*/1, ADISPLAY_ID_DEFAULT,
Siarhei Vishniakouca205502021-07-16 21:31:58 +0000978 expectedWallpaperFlags);
Arthur Hungc539dbb2022-12-08 07:45:36 +0000979
980 const MotionEvent secondFingerUpEvent =
981 MotionEventBuilder(POINTER_0_UP, AINPUT_SOURCE_TOUCHSCREEN)
982 .displayId(ADISPLAY_ID_DEFAULT)
983 .eventTime(systemTime(SYSTEM_TIME_MONOTONIC))
Siarhei Vishniakou6d73f832022-07-21 17:27:03 -0700984 .pointer(PointerBuilder(/*id=*/0, ToolType::FINGER).x(100).y(100))
985 .pointer(PointerBuilder(/*id=*/1, ToolType::FINGER).x(150).y(150))
Arthur Hungc539dbb2022-12-08 07:45:36 +0000986 .build();
987 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -0700988 injectMotionEvent(*mDispatcher, secondFingerUpEvent, INJECT_EVENT_TIMEOUT,
Arthur Hungc539dbb2022-12-08 07:45:36 +0000989 InputEventInjectionSync::WAIT_FOR_RESULT))
990 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
991 foregroundWindow->consumeMotionPointerUp(0);
992 wallpaperWindow->consumeMotionPointerUp(0, ADISPLAY_ID_DEFAULT, expectedWallpaperFlags);
993
994 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -0700995 injectMotionEvent(*mDispatcher,
Siarhei Vishniakou92c8fd52023-01-29 14:57:43 -0800996 MotionEventBuilder(AMOTION_EVENT_ACTION_UP,
997 AINPUT_SOURCE_TOUCHSCREEN)
998 .displayId(ADISPLAY_ID_DEFAULT)
999 .eventTime(systemTime(SYSTEM_TIME_MONOTONIC))
Harry Cutts101ee9b2023-07-06 18:04:14 +00001000 .pointer(PointerBuilder(/*id=*/1, ToolType::FINGER)
Siarhei Vishniakou92c8fd52023-01-29 14:57:43 -08001001 .x(100)
1002 .y(100))
1003 .build(),
1004 INJECT_EVENT_TIMEOUT, InputEventInjectionSync::WAIT_FOR_RESULT))
Arthur Hungc539dbb2022-12-08 07:45:36 +00001005 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
1006 foregroundWindow->consumeMotionUp(ADISPLAY_ID_DEFAULT);
1007 wallpaperWindow->consumeMotionUp(ADISPLAY_ID_DEFAULT, expectedWallpaperFlags);
Siarhei Vishniakouca205502021-07-16 21:31:58 +00001008}
1009
1010/**
1011 * Two windows: a window on the left and window on the right.
1012 * A third window, wallpaper, is behind both windows, and spans both top windows.
1013 * The first touch down goes to the left window. A second pointer touches down on the right window.
1014 * The touch is split, so both left and right windows should receive ACTION_DOWN.
1015 * The wallpaper will get the full event, so it should receive ACTION_DOWN followed by
1016 * ACTION_POINTER_DOWN(1).
1017 */
1018TEST_F(InputDispatcherTest, TwoWindows_SplitWallpaperTouch) {
1019 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
1020 sp<FakeWindowHandle> leftWindow =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07001021 sp<FakeWindowHandle>::make(application, mDispatcher, "Left", ADISPLAY_ID_DEFAULT);
Siarhei Vishniakouca205502021-07-16 21:31:58 +00001022 leftWindow->setFrame(Rect(0, 0, 200, 200));
Prabir Pradhan4d5c52f2022-01-31 08:52:10 -08001023 leftWindow->setDupTouchToWallpaper(true);
Siarhei Vishniakouca205502021-07-16 21:31:58 +00001024
1025 sp<FakeWindowHandle> rightWindow =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07001026 sp<FakeWindowHandle>::make(application, mDispatcher, "Right", ADISPLAY_ID_DEFAULT);
Siarhei Vishniakouca205502021-07-16 21:31:58 +00001027 rightWindow->setFrame(Rect(200, 0, 400, 200));
Prabir Pradhan4d5c52f2022-01-31 08:52:10 -08001028 rightWindow->setDupTouchToWallpaper(true);
Siarhei Vishniakouca205502021-07-16 21:31:58 +00001029
1030 sp<FakeWindowHandle> wallpaperWindow =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07001031 sp<FakeWindowHandle>::make(application, mDispatcher, "Wallpaper", ADISPLAY_ID_DEFAULT);
Siarhei Vishniakouca205502021-07-16 21:31:58 +00001032 wallpaperWindow->setFrame(Rect(0, 0, 400, 200));
Prabir Pradhan4d5c52f2022-01-31 08:52:10 -08001033 wallpaperWindow->setIsWallpaper(true);
Siarhei Vishniakouca205502021-07-16 21:31:58 +00001034
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07001035 mDispatcher->onWindowInfosChanged(
1036 {{*leftWindow->getInfo(), *rightWindow->getInfo(), *wallpaperWindow->getInfo()},
1037 {},
1038 0,
1039 0});
Siarhei Vishniakouca205502021-07-16 21:31:58 +00001040
1041 // Touch down on left window
1042 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07001043 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
Siarhei Vishniakouca205502021-07-16 21:31:58 +00001044 {100, 100}))
1045 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
1046
1047 // Both foreground window and its wallpaper should receive the touch down
1048 leftWindow->consumeMotionDown();
1049 wallpaperWindow->consumeMotionDown(ADISPLAY_ID_DEFAULT, expectedWallpaperFlags);
1050
1051 // Second finger down on the right window
1052 const MotionEvent secondFingerDownEvent =
Siarhei Vishniakoua16e3a22022-03-02 15:26:40 -08001053 MotionEventBuilder(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
Siarhei Vishniakouca205502021-07-16 21:31:58 +00001054 .eventTime(systemTime(SYSTEM_TIME_MONOTONIC))
Siarhei Vishniakou6d73f832022-07-21 17:27:03 -07001055 .pointer(PointerBuilder(/*id=*/0, ToolType::FINGER).x(100).y(100))
1056 .pointer(PointerBuilder(/*id=*/1, ToolType::FINGER).x(300).y(100))
Siarhei Vishniakouca205502021-07-16 21:31:58 +00001057 .build();
1058 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07001059 injectMotionEvent(*mDispatcher, secondFingerDownEvent, INJECT_EVENT_TIMEOUT,
Siarhei Vishniakouca205502021-07-16 21:31:58 +00001060 InputEventInjectionSync::WAIT_FOR_RESULT))
1061 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
1062
1063 leftWindow->consumeMotionMove();
1064 // Since the touch is split, right window gets ACTION_DOWN
1065 rightWindow->consumeMotionDown(ADISPLAY_ID_DEFAULT);
Harry Cutts33476232023-01-30 19:57:29 +00001066 wallpaperWindow->consumeMotionPointerDown(/*pointerIndex=*/1, ADISPLAY_ID_DEFAULT,
Siarhei Vishniakouca205502021-07-16 21:31:58 +00001067 expectedWallpaperFlags);
1068
1069 // Now, leftWindow, which received the first finger, disappears.
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07001070 mDispatcher->onWindowInfosChanged(
1071 {{*rightWindow->getInfo(), *wallpaperWindow->getInfo()}, {}, 0, 0});
Siarhei Vishniakouca205502021-07-16 21:31:58 +00001072 leftWindow->consumeMotionCancel();
1073 // Since a "parent" window of the wallpaper is gone, wallpaper should receive cancel, too.
1074 wallpaperWindow->consumeMotionCancel(ADISPLAY_ID_DEFAULT, expectedWallpaperFlags);
1075
1076 // The pointer that's still down on the right window moves, and goes to the right window only.
1077 // As far as the dispatcher's concerned though, both pointers are still present.
1078 const MotionEvent secondFingerMoveEvent =
1079 MotionEventBuilder(AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN)
1080 .eventTime(systemTime(SYSTEM_TIME_MONOTONIC))
Siarhei Vishniakou6d73f832022-07-21 17:27:03 -07001081 .pointer(PointerBuilder(/*id=*/0, ToolType::FINGER).x(100).y(100))
1082 .pointer(PointerBuilder(/*id=*/1, ToolType::FINGER).x(310).y(110))
Siarhei Vishniakouca205502021-07-16 21:31:58 +00001083 .build();
1084 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07001085 injectMotionEvent(*mDispatcher, secondFingerMoveEvent, INJECT_EVENT_TIMEOUT,
Siarhei Vishniakouca205502021-07-16 21:31:58 +00001086 InputEventInjectionSync::WAIT_FOR_RESULT));
1087 rightWindow->consumeMotionMove();
1088
1089 leftWindow->assertNoEvents();
1090 rightWindow->assertNoEvents();
1091 wallpaperWindow->assertNoEvents();
1092}
1093
Arthur Hungc539dbb2022-12-08 07:45:36 +00001094/**
1095 * Two windows: a window on the left with dup touch to wallpaper and window on the right without it.
1096 * The touch slips to the right window. so left window and wallpaper should receive ACTION_CANCEL
1097 * The right window should receive ACTION_DOWN.
1098 */
1099TEST_F(InputDispatcherTest, WallpaperWindowWhenSlippery) {
Arthur Hung74c248d2022-11-23 07:09:59 +00001100 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
Arthur Hungc539dbb2022-12-08 07:45:36 +00001101 sp<FakeWindowHandle> leftWindow =
1102 sp<FakeWindowHandle>::make(application, mDispatcher, "Left", ADISPLAY_ID_DEFAULT);
1103 leftWindow->setFrame(Rect(0, 0, 200, 200));
1104 leftWindow->setDupTouchToWallpaper(true);
1105 leftWindow->setSlippery(true);
1106
1107 sp<FakeWindowHandle> rightWindow =
1108 sp<FakeWindowHandle>::make(application, mDispatcher, "Right", ADISPLAY_ID_DEFAULT);
1109 rightWindow->setFrame(Rect(200, 0, 400, 200));
Arthur Hung74c248d2022-11-23 07:09:59 +00001110
1111 sp<FakeWindowHandle> wallpaperWindow =
1112 sp<FakeWindowHandle>::make(application, mDispatcher, "Wallpaper", ADISPLAY_ID_DEFAULT);
1113 wallpaperWindow->setIsWallpaper(true);
Arthur Hung74c248d2022-11-23 07:09:59 +00001114
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07001115 mDispatcher->onWindowInfosChanged(
1116 {{*leftWindow->getInfo(), *rightWindow->getInfo(), *wallpaperWindow->getInfo()},
1117 {},
1118 0,
1119 0});
Arthur Hung74c248d2022-11-23 07:09:59 +00001120
Arthur Hungc539dbb2022-12-08 07:45:36 +00001121 // Touch down on left window
Arthur Hung74c248d2022-11-23 07:09:59 +00001122 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07001123 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
Arthur Hungc539dbb2022-12-08 07:45:36 +00001124 {100, 100}))
Arthur Hung74c248d2022-11-23 07:09:59 +00001125 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
Arthur Hungc539dbb2022-12-08 07:45:36 +00001126
1127 // Both foreground window and its wallpaper should receive the touch down
1128 leftWindow->consumeMotionDown();
Arthur Hung74c248d2022-11-23 07:09:59 +00001129 wallpaperWindow->consumeMotionDown(ADISPLAY_ID_DEFAULT, expectedWallpaperFlags);
1130
Arthur Hungc539dbb2022-12-08 07:45:36 +00001131 // Move to right window, the left window should receive cancel.
Arthur Hung74c248d2022-11-23 07:09:59 +00001132 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07001133 injectMotionEvent(*mDispatcher, AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN,
Arthur Hungc539dbb2022-12-08 07:45:36 +00001134 ADISPLAY_ID_DEFAULT, {201, 100}))
Arthur Hung74c248d2022-11-23 07:09:59 +00001135 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
1136
Arthur Hungc539dbb2022-12-08 07:45:36 +00001137 leftWindow->consumeMotionCancel();
1138 rightWindow->consumeMotionDown(ADISPLAY_ID_DEFAULT);
1139 wallpaperWindow->consumeMotionCancel(ADISPLAY_ID_DEFAULT, expectedWallpaperFlags);
Arthur Hung74c248d2022-11-23 07:09:59 +00001140}
1141
Siarhei Vishniakoua16e3a22022-03-02 15:26:40 -08001142/**
Siarhei Vishniakou5bf25d92023-02-08 15:43:38 -08001143 * The policy typically sets POLICY_FLAG_PASS_TO_USER to the events. But when the display is not
1144 * interactive, it might stop sending this flag.
1145 * In this test, we check that if the policy stops sending this flag mid-gesture, we still ensure
1146 * to have a consistent input stream.
1147 *
1148 * Test procedure:
1149 * DOWN -> POINTER_DOWN -> (stop sending POLICY_FLAG_PASS_TO_USER) -> CANCEL.
1150 * DOWN (new gesture).
1151 *
1152 * In the bad implementation, we could potentially drop the CANCEL event, and get an inconsistent
1153 * state in the dispatcher. This would cause the final DOWN event to not be delivered to the app.
1154 *
1155 * We technically just need a single window here, but we are using two windows (spy on top and a
1156 * regular window below) to emulate the actual situation where it happens on the device.
1157 */
1158TEST_F(InputDispatcherTest, TwoPointerCancelInconsistentPolicy) {
1159 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
1160 sp<FakeWindowHandle> spyWindow =
1161 sp<FakeWindowHandle>::make(application, mDispatcher, "Spy", ADISPLAY_ID_DEFAULT);
1162 spyWindow->setFrame(Rect(0, 0, 200, 200));
1163 spyWindow->setTrustedOverlay(true);
1164 spyWindow->setSpy(true);
1165
1166 sp<FakeWindowHandle> window =
1167 sp<FakeWindowHandle>::make(application, mDispatcher, "Window", ADISPLAY_ID_DEFAULT);
1168 window->setFrame(Rect(0, 0, 200, 200));
1169
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07001170 mDispatcher->onWindowInfosChanged({{*spyWindow->getInfo(), *window->getInfo()}, {}, 0, 0});
Siarhei Vishniakou5bf25d92023-02-08 15:43:38 -08001171 const int32_t touchDeviceId = 4;
Siarhei Vishniakou5bf25d92023-02-08 15:43:38 -08001172
1173 // Two pointers down
Prabir Pradhan678438e2023-04-13 19:32:51 +00001174 mDispatcher->notifyMotion(
1175 MotionArgsBuilder(AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
1176 .deviceId(touchDeviceId)
1177 .policyFlags(DEFAULT_POLICY_FLAGS)
1178 .pointer(PointerBuilder(0, ToolType::FINGER).x(100).y(100))
1179 .build());
Siarhei Vishniakou5bf25d92023-02-08 15:43:38 -08001180
Prabir Pradhan678438e2023-04-13 19:32:51 +00001181 mDispatcher->notifyMotion(MotionArgsBuilder(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
1182 .deviceId(touchDeviceId)
1183 .policyFlags(DEFAULT_POLICY_FLAGS)
1184 .pointer(PointerBuilder(0, ToolType::FINGER).x(100).y(100))
1185 .pointer(PointerBuilder(1, ToolType::FINGER).x(120).y(120))
1186 .build());
Siarhei Vishniakou5bf25d92023-02-08 15:43:38 -08001187 spyWindow->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_DOWN));
1188 spyWindow->consumeMotionEvent(WithMotionAction(POINTER_1_DOWN));
1189 window->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_DOWN));
1190 window->consumeMotionEvent(WithMotionAction(POINTER_1_DOWN));
1191
1192 // Cancel the current gesture. Send the cancel without the default policy flags.
Prabir Pradhan678438e2023-04-13 19:32:51 +00001193 mDispatcher->notifyMotion(
1194 MotionArgsBuilder(AMOTION_EVENT_ACTION_CANCEL, AINPUT_SOURCE_TOUCHSCREEN)
1195 .deviceId(touchDeviceId)
1196 .policyFlags(0)
1197 .pointer(PointerBuilder(0, ToolType::FINGER).x(100).y(100))
1198 .pointer(PointerBuilder(1, ToolType::FINGER).x(120).y(120))
1199 .build());
Siarhei Vishniakou5bf25d92023-02-08 15:43:38 -08001200 spyWindow->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_CANCEL));
1201 window->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_CANCEL));
1202
1203 // We don't need to reset the device to reproduce the issue, but the reset event typically
1204 // follows, so we keep it here to model the actual listener behaviour more closely.
Prabir Pradhan678438e2023-04-13 19:32:51 +00001205 mDispatcher->notifyDeviceReset({/*id=*/1, systemTime(SYSTEM_TIME_MONOTONIC), touchDeviceId});
Siarhei Vishniakou5bf25d92023-02-08 15:43:38 -08001206
1207 // Start new gesture
Prabir Pradhan678438e2023-04-13 19:32:51 +00001208 mDispatcher->notifyMotion(
1209 MotionArgsBuilder(AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
1210 .deviceId(touchDeviceId)
1211 .policyFlags(DEFAULT_POLICY_FLAGS)
1212 .pointer(PointerBuilder(0, ToolType::FINGER).x(100).y(100))
1213 .build());
Siarhei Vishniakou5bf25d92023-02-08 15:43:38 -08001214 spyWindow->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_DOWN));
1215 window->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_DOWN));
1216
1217 // No more events
1218 spyWindow->assertNoEvents();
1219 window->assertNoEvents();
1220}
1221
1222/**
Linnan Li907ae732023-09-05 17:14:21 +08001223 * Same as the above 'TwoPointerCancelInconsistentPolicy' test, but for hovers.
1224 * The policy typically sets POLICY_FLAG_PASS_TO_USER to the events. But when the display is not
1225 * interactive, it might stop sending this flag.
1226 * We've already ensured the consistency of the touch event in this case, and we should also ensure
1227 * the consistency of the hover event in this case.
1228 *
1229 * Test procedure:
1230 * HOVER_ENTER -> HOVER_MOVE -> (stop sending POLICY_FLAG_PASS_TO_USER) -> HOVER_EXIT
1231 * HOVER_ENTER -> HOVER_MOVE -> HOVER_EXIT
1232 *
1233 * We expect to receive two full streams of hover events.
1234 */
1235TEST_F(InputDispatcherTest, HoverEventInconsistentPolicy) {
1236 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
1237
1238 sp<FakeWindowHandle> window =
1239 sp<FakeWindowHandle>::make(application, mDispatcher, "Window", ADISPLAY_ID_DEFAULT);
1240 window->setFrame(Rect(0, 0, 300, 300));
1241
1242 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
1243
1244 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_ENTER, AINPUT_SOURCE_STYLUS)
1245 .policyFlags(DEFAULT_POLICY_FLAGS)
1246 .pointer(PointerBuilder(0, ToolType::STYLUS).x(100).y(101))
1247 .build());
1248 window->consumeMotionEvent(WithMotionAction(ACTION_HOVER_ENTER));
1249
1250 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_MOVE, AINPUT_SOURCE_STYLUS)
1251 .policyFlags(DEFAULT_POLICY_FLAGS)
1252 .pointer(PointerBuilder(0, ToolType::STYLUS).x(101).y(102))
1253 .build());
1254 window->consumeMotionEvent(WithMotionAction(ACTION_HOVER_MOVE));
1255
1256 // Send hover exit without the default policy flags.
1257 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_EXIT, AINPUT_SOURCE_STYLUS)
1258 .policyFlags(0)
1259 .pointer(PointerBuilder(0, ToolType::STYLUS).x(101).y(102))
1260 .build());
1261
1262 window->consumeMotionEvent(WithMotionAction(ACTION_HOVER_EXIT));
1263
1264 // Send a simple hover event stream, ensure dispatcher not crashed and window can receive
1265 // right event.
1266 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_ENTER, AINPUT_SOURCE_STYLUS)
1267 .policyFlags(DEFAULT_POLICY_FLAGS)
1268 .pointer(PointerBuilder(0, ToolType::STYLUS).x(200).y(201))
1269 .build());
1270 window->consumeMotionEvent(WithMotionAction(ACTION_HOVER_ENTER));
1271
1272 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_MOVE, AINPUT_SOURCE_STYLUS)
1273 .policyFlags(DEFAULT_POLICY_FLAGS)
1274 .pointer(PointerBuilder(0, ToolType::STYLUS).x(201).y(202))
1275 .build());
1276 window->consumeMotionEvent(WithMotionAction(ACTION_HOVER_MOVE));
1277
1278 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_EXIT, AINPUT_SOURCE_STYLUS)
1279 .policyFlags(DEFAULT_POLICY_FLAGS)
1280 .pointer(PointerBuilder(0, ToolType::STYLUS).x(201).y(202))
1281 .build());
1282 window->consumeMotionEvent(WithMotionAction(ACTION_HOVER_EXIT));
1283}
1284
1285/**
Siarhei Vishniakoue0431e42023-01-28 17:01:39 -08001286 * Two windows: a window on the left and a window on the right.
1287 * Mouse is hovered from the right window into the left window.
1288 * Next, we tap on the left window, where the cursor was last seen.
1289 * The second tap is done onto the right window.
1290 * The mouse and tap are from two different devices.
1291 * We technically don't need to set the downtime / eventtime for these events, but setting these
1292 * explicitly helps during debugging.
1293 * This test reproduces a crash where there is a mismatch between the downTime and eventTime.
1294 * In the buggy implementation, a tap on the right window would cause a crash.
1295 */
Siarhei Vishniakoued89cbb2023-10-13 10:42:44 -07001296TEST_F(InputDispatcherTest, HoverFromLeftToRightAndTap_legacy) {
1297 SCOPED_FLAG_OVERRIDE(enable_multi_device_same_window_stream, false);
1298
Siarhei Vishniakoue0431e42023-01-28 17:01:39 -08001299 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
1300 sp<FakeWindowHandle> leftWindow =
1301 sp<FakeWindowHandle>::make(application, mDispatcher, "Left", ADISPLAY_ID_DEFAULT);
1302 leftWindow->setFrame(Rect(0, 0, 200, 200));
1303
1304 sp<FakeWindowHandle> rightWindow =
1305 sp<FakeWindowHandle>::make(application, mDispatcher, "Right", ADISPLAY_ID_DEFAULT);
1306 rightWindow->setFrame(Rect(200, 0, 400, 200));
1307
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07001308 mDispatcher->onWindowInfosChanged(
1309 {{*leftWindow->getInfo(), *rightWindow->getInfo()}, {}, 0, 0});
Siarhei Vishniakoue0431e42023-01-28 17:01:39 -08001310 // All times need to start at the current time, otherwise the dispatcher will drop the events as
1311 // stale.
1312 const nsecs_t baseTime = systemTime(SYSTEM_TIME_MONOTONIC);
1313 const int32_t mouseDeviceId = 6;
1314 const int32_t touchDeviceId = 4;
1315 // Move the cursor from right
1316 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07001317 injectMotionEvent(*mDispatcher,
Siarhei Vishniakoue0431e42023-01-28 17:01:39 -08001318 MotionEventBuilder(AMOTION_EVENT_ACTION_HOVER_MOVE,
1319 AINPUT_SOURCE_MOUSE)
1320 .deviceId(mouseDeviceId)
1321 .downTime(baseTime + 10)
1322 .eventTime(baseTime + 20)
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07001323 .pointer(PointerBuilder(0, ToolType::MOUSE).x(300).y(100))
Siarhei Vishniakoue0431e42023-01-28 17:01:39 -08001324 .build()));
1325 rightWindow->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_ENTER));
1326
1327 // .. to the left window
1328 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07001329 injectMotionEvent(*mDispatcher,
Siarhei Vishniakoue0431e42023-01-28 17:01:39 -08001330 MotionEventBuilder(AMOTION_EVENT_ACTION_HOVER_MOVE,
1331 AINPUT_SOURCE_MOUSE)
1332 .deviceId(mouseDeviceId)
1333 .downTime(baseTime + 10)
1334 .eventTime(baseTime + 30)
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07001335 .pointer(PointerBuilder(0, ToolType::MOUSE).x(110).y(100))
Siarhei Vishniakoue0431e42023-01-28 17:01:39 -08001336 .build()));
1337 rightWindow->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_EXIT));
1338 leftWindow->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_ENTER));
1339 // Now tap the left window
1340 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07001341 injectMotionEvent(*mDispatcher,
Siarhei Vishniakoue0431e42023-01-28 17:01:39 -08001342 MotionEventBuilder(AMOTION_EVENT_ACTION_DOWN,
1343 AINPUT_SOURCE_TOUCHSCREEN)
1344 .deviceId(touchDeviceId)
1345 .downTime(baseTime + 40)
1346 .eventTime(baseTime + 40)
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07001347 .pointer(PointerBuilder(0, ToolType::FINGER).x(100).y(100))
Siarhei Vishniakoue0431e42023-01-28 17:01:39 -08001348 .build()));
1349 leftWindow->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_EXIT));
1350 leftWindow->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_DOWN));
1351
1352 // release tap
1353 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07001354 injectMotionEvent(*mDispatcher,
Siarhei Vishniakoue0431e42023-01-28 17:01:39 -08001355 MotionEventBuilder(AMOTION_EVENT_ACTION_UP,
1356 AINPUT_SOURCE_TOUCHSCREEN)
1357 .deviceId(touchDeviceId)
1358 .downTime(baseTime + 40)
1359 .eventTime(baseTime + 50)
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07001360 .pointer(PointerBuilder(0, ToolType::FINGER).x(100).y(100))
Siarhei Vishniakoue0431e42023-01-28 17:01:39 -08001361 .build()));
1362 leftWindow->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_UP));
1363
1364 // Tap the window on the right
1365 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07001366 injectMotionEvent(*mDispatcher,
Siarhei Vishniakoue0431e42023-01-28 17:01:39 -08001367 MotionEventBuilder(AMOTION_EVENT_ACTION_DOWN,
1368 AINPUT_SOURCE_TOUCHSCREEN)
1369 .deviceId(touchDeviceId)
1370 .downTime(baseTime + 60)
1371 .eventTime(baseTime + 60)
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07001372 .pointer(PointerBuilder(0, ToolType::FINGER).x(300).y(100))
Siarhei Vishniakoue0431e42023-01-28 17:01:39 -08001373 .build()));
1374 rightWindow->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_DOWN));
1375
1376 // release tap
1377 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07001378 injectMotionEvent(*mDispatcher,
Siarhei Vishniakoue0431e42023-01-28 17:01:39 -08001379 MotionEventBuilder(AMOTION_EVENT_ACTION_UP,
1380 AINPUT_SOURCE_TOUCHSCREEN)
1381 .deviceId(touchDeviceId)
1382 .downTime(baseTime + 60)
1383 .eventTime(baseTime + 70)
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07001384 .pointer(PointerBuilder(0, ToolType::FINGER).x(300).y(100))
Siarhei Vishniakoue0431e42023-01-28 17:01:39 -08001385 .build()));
1386 rightWindow->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_UP));
1387
1388 // No more events
1389 leftWindow->assertNoEvents();
1390 rightWindow->assertNoEvents();
1391}
1392
1393/**
Siarhei Vishniakoued89cbb2023-10-13 10:42:44 -07001394 * Two windows: a window on the left and a window on the right.
1395 * Mouse is hovered from the right window into the left window.
1396 * Next, we tap on the left window, where the cursor was last seen.
1397 * The second tap is done onto the right window.
1398 * The mouse and tap are from two different devices.
1399 * We technically don't need to set the downtime / eventtime for these events, but setting these
1400 * explicitly helps during debugging.
1401 * This test reproduces a crash where there is a mismatch between the downTime and eventTime.
1402 * In the buggy implementation, a tap on the right window would cause a crash.
1403 */
1404TEST_F(InputDispatcherTest, HoverFromLeftToRightAndTap) {
1405 SCOPED_FLAG_OVERRIDE(enable_multi_device_same_window_stream, true);
1406
1407 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
1408 sp<FakeWindowHandle> leftWindow =
1409 sp<FakeWindowHandle>::make(application, mDispatcher, "Left", ADISPLAY_ID_DEFAULT);
1410 leftWindow->setFrame(Rect(0, 0, 200, 200));
1411
1412 sp<FakeWindowHandle> rightWindow =
1413 sp<FakeWindowHandle>::make(application, mDispatcher, "Right", ADISPLAY_ID_DEFAULT);
1414 rightWindow->setFrame(Rect(200, 0, 400, 200));
1415
1416 mDispatcher->onWindowInfosChanged(
1417 {{*leftWindow->getInfo(), *rightWindow->getInfo()}, {}, 0, 0});
1418 // All times need to start at the current time, otherwise the dispatcher will drop the events as
1419 // stale.
1420 const nsecs_t baseTime = systemTime(SYSTEM_TIME_MONOTONIC);
1421 const int32_t mouseDeviceId = 6;
1422 const int32_t touchDeviceId = 4;
1423 // Move the cursor from right
1424 mDispatcher->notifyMotion(
1425 MotionArgsBuilder(AMOTION_EVENT_ACTION_HOVER_MOVE, AINPUT_SOURCE_MOUSE)
1426 .deviceId(mouseDeviceId)
1427 .downTime(baseTime + 10)
1428 .eventTime(baseTime + 20)
1429 .pointer(PointerBuilder(0, ToolType::MOUSE).x(300).y(100))
1430 .build());
1431 rightWindow->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_ENTER));
1432
1433 // .. to the left window
1434 mDispatcher->notifyMotion(
1435 MotionArgsBuilder(AMOTION_EVENT_ACTION_HOVER_MOVE, AINPUT_SOURCE_MOUSE)
1436 .deviceId(mouseDeviceId)
1437 .downTime(baseTime + 10)
1438 .eventTime(baseTime + 30)
1439 .pointer(PointerBuilder(0, ToolType::MOUSE).x(110).y(100))
1440 .build());
1441 rightWindow->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_EXIT));
1442 leftWindow->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_ENTER));
1443 // Now tap the left window
1444 mDispatcher->notifyMotion(
1445 MotionArgsBuilder(AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
1446 .deviceId(touchDeviceId)
1447 .downTime(baseTime + 40)
1448 .eventTime(baseTime + 40)
1449 .pointer(PointerBuilder(0, ToolType::FINGER).x(100).y(100))
1450 .build());
1451 leftWindow->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_DOWN));
1452
1453 // release tap
1454 mDispatcher->notifyMotion(MotionArgsBuilder(AMOTION_EVENT_ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN)
1455 .deviceId(touchDeviceId)
1456 .downTime(baseTime + 40)
1457 .eventTime(baseTime + 50)
1458 .pointer(PointerBuilder(0, ToolType::FINGER).x(100).y(100))
1459 .build());
1460 leftWindow->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_UP));
1461
1462 // Tap the window on the right
1463 mDispatcher->notifyMotion(
1464 MotionArgsBuilder(AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
1465 .deviceId(touchDeviceId)
1466 .downTime(baseTime + 60)
1467 .eventTime(baseTime + 60)
1468 .pointer(PointerBuilder(0, ToolType::FINGER).x(300).y(100))
1469 .build());
1470 rightWindow->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_DOWN));
1471
1472 // release tap
1473 mDispatcher->notifyMotion(MotionArgsBuilder(AMOTION_EVENT_ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN)
1474 .deviceId(touchDeviceId)
1475 .downTime(baseTime + 60)
1476 .eventTime(baseTime + 70)
1477 .pointer(PointerBuilder(0, ToolType::FINGER).x(300).y(100))
1478 .build());
1479 rightWindow->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_UP));
1480
1481 // No more events
1482 leftWindow->assertNoEvents();
1483 rightWindow->assertNoEvents();
1484}
1485
1486/**
Siarhei Vishniakoua235c042023-05-02 09:59:09 -07001487 * Start hovering in a window. While this hover is still active, make another window appear on top.
1488 * The top, obstructing window has no input channel, so it's not supposed to receive input.
1489 * While the top window is present, the hovering is stopped.
1490 * Later, hovering gets resumed again.
1491 * Ensure that new hover gesture is handled correctly.
1492 * This test reproduces a crash where the HOVER_EXIT event wasn't getting dispatched correctly
1493 * to the window that's currently being hovered over.
1494 */
1495TEST_F(InputDispatcherTest, HoverWhileWindowAppears) {
1496 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
1497 sp<FakeWindowHandle> window =
1498 sp<FakeWindowHandle>::make(application, mDispatcher, "Window", ADISPLAY_ID_DEFAULT);
1499 window->setFrame(Rect(0, 0, 200, 200));
1500
1501 // Only a single window is present at first
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07001502 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Siarhei Vishniakoua235c042023-05-02 09:59:09 -07001503
1504 // Start hovering in the window
1505 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_ENTER, AINPUT_SOURCE_STYLUS)
1506 .pointer(PointerBuilder(0, ToolType::STYLUS).x(100).y(100))
1507 .build());
1508 window->consumeMotionEvent(WithMotionAction(ACTION_HOVER_ENTER));
1509
1510 // Now, an obscuring window appears!
1511 sp<FakeWindowHandle> obscuringWindow =
1512 sp<FakeWindowHandle>::make(application, mDispatcher, "Obscuring window",
1513 ADISPLAY_ID_DEFAULT,
Prabir Pradhane7cc69c2024-01-05 21:35:28 +00001514 /*createInputChannel=*/false);
Siarhei Vishniakoua235c042023-05-02 09:59:09 -07001515 obscuringWindow->setFrame(Rect(0, 0, 200, 200));
1516 obscuringWindow->setTouchOcclusionMode(TouchOcclusionMode::BLOCK_UNTRUSTED);
1517 obscuringWindow->setOwnerInfo(SECONDARY_WINDOW_PID, SECONDARY_WINDOW_UID);
1518 obscuringWindow->setNoInputChannel(true);
1519 obscuringWindow->setFocusable(false);
1520 obscuringWindow->setAlpha(1.0);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07001521 mDispatcher->onWindowInfosChanged(
1522 {{*obscuringWindow->getInfo(), *window->getInfo()}, {}, 0, 0});
Siarhei Vishniakoua235c042023-05-02 09:59:09 -07001523
1524 // While this new obscuring window is present, the hovering is stopped
1525 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_EXIT, AINPUT_SOURCE_STYLUS)
1526 .pointer(PointerBuilder(0, ToolType::STYLUS).x(100).y(100))
1527 .build());
1528 window->consumeMotionEvent(WithMotionAction(ACTION_HOVER_EXIT));
1529
1530 // Now the obscuring window goes away.
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07001531 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Siarhei Vishniakoua235c042023-05-02 09:59:09 -07001532
1533 // And a new hover gesture starts.
1534 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_ENTER, AINPUT_SOURCE_STYLUS)
1535 .pointer(PointerBuilder(0, ToolType::STYLUS).x(100).y(100))
1536 .build());
1537 window->consumeMotionEvent(WithMotionAction(ACTION_HOVER_ENTER));
1538}
1539
1540/**
1541 * Same test as 'HoverWhileWindowAppears' above, but here, we also send some HOVER_MOVE events to
1542 * the obscuring window.
1543 */
1544TEST_F(InputDispatcherTest, HoverMoveWhileWindowAppears) {
1545 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
1546 sp<FakeWindowHandle> window =
1547 sp<FakeWindowHandle>::make(application, mDispatcher, "Window", ADISPLAY_ID_DEFAULT);
1548 window->setFrame(Rect(0, 0, 200, 200));
1549
1550 // Only a single window is present at first
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07001551 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Siarhei Vishniakoua235c042023-05-02 09:59:09 -07001552
1553 // Start hovering in the window
1554 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_ENTER, AINPUT_SOURCE_STYLUS)
1555 .pointer(PointerBuilder(0, ToolType::STYLUS).x(100).y(100))
1556 .build());
1557 window->consumeMotionEvent(WithMotionAction(ACTION_HOVER_ENTER));
1558
1559 // Now, an obscuring window appears!
1560 sp<FakeWindowHandle> obscuringWindow =
1561 sp<FakeWindowHandle>::make(application, mDispatcher, "Obscuring window",
1562 ADISPLAY_ID_DEFAULT,
Prabir Pradhane7cc69c2024-01-05 21:35:28 +00001563 /*createInputChannel=*/false);
Siarhei Vishniakoua235c042023-05-02 09:59:09 -07001564 obscuringWindow->setFrame(Rect(0, 0, 200, 200));
1565 obscuringWindow->setTouchOcclusionMode(TouchOcclusionMode::BLOCK_UNTRUSTED);
1566 obscuringWindow->setOwnerInfo(SECONDARY_WINDOW_PID, SECONDARY_WINDOW_UID);
1567 obscuringWindow->setNoInputChannel(true);
1568 obscuringWindow->setFocusable(false);
1569 obscuringWindow->setAlpha(1.0);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07001570 mDispatcher->onWindowInfosChanged(
1571 {{*obscuringWindow->getInfo(), *window->getInfo()}, {}, 0, 0});
Siarhei Vishniakoua235c042023-05-02 09:59:09 -07001572
1573 // While this new obscuring window is present, the hovering continues. The event can't go to the
1574 // bottom window due to obstructed touches, so it should generate HOVER_EXIT for that window.
1575 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_MOVE, AINPUT_SOURCE_STYLUS)
1576 .pointer(PointerBuilder(0, ToolType::STYLUS).x(100).y(100))
1577 .build());
1578 obscuringWindow->assertNoEvents();
1579 window->consumeMotionEvent(WithMotionAction(ACTION_HOVER_EXIT));
1580
1581 // Now the obscuring window goes away.
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07001582 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Siarhei Vishniakoua235c042023-05-02 09:59:09 -07001583
1584 // Hovering continues in the same position. The hovering pointer re-enters the bottom window,
1585 // so it should generate a HOVER_ENTER
1586 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_MOVE, AINPUT_SOURCE_STYLUS)
1587 .pointer(PointerBuilder(0, ToolType::STYLUS).x(100).y(100))
1588 .build());
1589 window->consumeMotionEvent(WithMotionAction(ACTION_HOVER_ENTER));
1590
1591 // Now the MOVE should be getting dispatched normally
1592 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_MOVE, AINPUT_SOURCE_STYLUS)
1593 .pointer(PointerBuilder(0, ToolType::STYLUS).x(110).y(110))
1594 .build());
1595 window->consumeMotionEvent(WithMotionAction(ACTION_HOVER_MOVE));
1596}
1597
1598/**
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -07001599 * Hover mouse over a window, and then send ACTION_SCROLL. Ensure both the hover and the scroll
1600 * events are delivered to the window.
1601 */
1602TEST_F(InputDispatcherTest, HoverMoveAndScroll) {
1603 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
1604 sp<FakeWindowHandle> window =
1605 sp<FakeWindowHandle>::make(application, mDispatcher, "Window", ADISPLAY_ID_DEFAULT);
1606 window->setFrame(Rect(0, 0, 200, 200));
1607 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
1608
1609 // Start hovering in the window
1610 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_ENTER, AINPUT_SOURCE_MOUSE)
1611 .pointer(PointerBuilder(0, ToolType::MOUSE).x(100).y(110))
1612 .build());
1613 window->consumeMotionEvent(WithMotionAction(ACTION_HOVER_ENTER));
1614
1615 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_MOVE, AINPUT_SOURCE_MOUSE)
1616 .pointer(PointerBuilder(0, ToolType::MOUSE).x(110).y(120))
1617 .build());
1618 window->consumeMotionEvent(WithMotionAction(ACTION_HOVER_MOVE));
1619
1620 // Scroll with the mouse
1621 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_SCROLL, AINPUT_SOURCE_MOUSE)
1622 .pointer(PointerBuilder(0, ToolType::MOUSE).x(110).y(120))
1623 .build());
1624 window->consumeMotionEvent(WithMotionAction(ACTION_SCROLL));
1625}
1626
1627using InputDispatcherMultiDeviceTest = InputDispatcherTest;
1628
1629/**
Siarhei Vishniakou2899c552023-07-10 18:20:46 -07001630 * One window. Stylus down on the window. Next, touch from another device goes down. Ensure that
1631 * touch is dropped, because stylus should be preferred over touch.
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -07001632 */
Siarhei Vishniakou2899c552023-07-10 18:20:46 -07001633TEST_F(InputDispatcherMultiDeviceTest, StylusDownBlocksTouchDown) {
Siarhei Vishniakoued89cbb2023-10-13 10:42:44 -07001634 SCOPED_FLAG_OVERRIDE(enable_multi_device_same_window_stream, false);
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -07001635 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
1636 sp<FakeWindowHandle> window =
1637 sp<FakeWindowHandle>::make(application, mDispatcher, "Window", ADISPLAY_ID_DEFAULT);
1638 window->setFrame(Rect(0, 0, 200, 200));
1639
1640 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
1641
1642 constexpr int32_t touchDeviceId = 4;
1643 constexpr int32_t stylusDeviceId = 2;
1644
1645 // Stylus down
1646 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_STYLUS)
1647 .deviceId(stylusDeviceId)
1648 .pointer(PointerBuilder(0, ToolType::STYLUS).x(100).y(110))
1649 .build());
1650 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(stylusDeviceId)));
1651
1652 // Touch down
1653 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
1654 .deviceId(touchDeviceId)
1655 .pointer(PointerBuilder(0, ToolType::FINGER).x(140).y(145))
1656 .build());
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -07001657
1658 // Touch move
1659 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN)
1660 .deviceId(touchDeviceId)
1661 .pointer(PointerBuilder(0, ToolType::FINGER).x(141).y(146))
1662 .build());
Siarhei Vishniakou2899c552023-07-10 18:20:46 -07001663 // Touch is ignored because stylus is already down
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -07001664
Siarhei Vishniakou2899c552023-07-10 18:20:46 -07001665 // Subsequent stylus movements are delivered correctly
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -07001666 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_STYLUS)
1667 .deviceId(stylusDeviceId)
1668 .pointer(PointerBuilder(0, ToolType::STYLUS).x(101).y(111))
1669 .build());
Siarhei Vishniakou2899c552023-07-10 18:20:46 -07001670 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(stylusDeviceId),
1671 WithCoords(101, 111)));
1672
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -07001673 window->assertNoEvents();
1674}
1675
1676/**
Siarhei Vishniakoued89cbb2023-10-13 10:42:44 -07001677 * One window. Stylus down on the window. Next, touch from another device goes down. Ensure that
1678 * touch is not dropped, because multiple devices are allowed to be active in the same window.
1679 */
1680TEST_F(InputDispatcherMultiDeviceTest, StylusDownDoesNotBlockTouchDown) {
1681 SCOPED_FLAG_OVERRIDE(enable_multi_device_same_window_stream, true);
1682 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
1683 sp<FakeWindowHandle> window =
1684 sp<FakeWindowHandle>::make(application, mDispatcher, "Window", ADISPLAY_ID_DEFAULT);
1685 window->setFrame(Rect(0, 0, 200, 200));
1686
1687 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
1688
1689 constexpr int32_t touchDeviceId = 4;
1690 constexpr int32_t stylusDeviceId = 2;
1691
1692 // Stylus down
1693 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_STYLUS)
1694 .deviceId(stylusDeviceId)
1695 .pointer(PointerBuilder(0, ToolType::STYLUS).x(100).y(110))
1696 .build());
1697 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(stylusDeviceId)));
1698
1699 // Touch down
1700 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
1701 .deviceId(touchDeviceId)
1702 .pointer(PointerBuilder(0, ToolType::FINGER).x(140).y(145))
1703 .build());
1704 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(touchDeviceId)));
1705
1706 // Touch move
1707 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN)
1708 .deviceId(touchDeviceId)
1709 .pointer(PointerBuilder(0, ToolType::FINGER).x(141).y(146))
1710 .build());
1711 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(touchDeviceId)));
1712
1713 // Stylus move
1714 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_STYLUS)
1715 .deviceId(stylusDeviceId)
1716 .pointer(PointerBuilder(0, ToolType::STYLUS).x(101).y(111))
1717 .build());
1718 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(stylusDeviceId),
1719 WithCoords(101, 111)));
1720
1721 window->assertNoEvents();
1722}
1723
1724/**
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -07001725 * One window and one spy window. Stylus down on the window. Next, touch from another device goes
Siarhei Vishniakou2899c552023-07-10 18:20:46 -07001726 * down. Ensure that touch is dropped, because stylus should be preferred over touch.
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -07001727 * Similar test as above, but with added SPY window.
1728 */
Siarhei Vishniakou2899c552023-07-10 18:20:46 -07001729TEST_F(InputDispatcherMultiDeviceTest, StylusDownWithSpyBlocksTouchDown) {
Siarhei Vishniakoued89cbb2023-10-13 10:42:44 -07001730 SCOPED_FLAG_OVERRIDE(enable_multi_device_same_window_stream, false);
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -07001731 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
1732 sp<FakeWindowHandle> window =
1733 sp<FakeWindowHandle>::make(application, mDispatcher, "Window", ADISPLAY_ID_DEFAULT);
1734 sp<FakeWindowHandle> spyWindow =
1735 sp<FakeWindowHandle>::make(application, mDispatcher, "Spy", ADISPLAY_ID_DEFAULT);
1736 spyWindow->setFrame(Rect(0, 0, 200, 200));
1737 spyWindow->setTrustedOverlay(true);
1738 spyWindow->setSpy(true);
1739 window->setFrame(Rect(0, 0, 200, 200));
1740
1741 mDispatcher->onWindowInfosChanged({{*spyWindow->getInfo(), *window->getInfo()}, {}, 0, 0});
1742
1743 constexpr int32_t touchDeviceId = 4;
1744 constexpr int32_t stylusDeviceId = 2;
1745
1746 // Stylus down
1747 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_STYLUS)
1748 .deviceId(stylusDeviceId)
1749 .pointer(PointerBuilder(0, ToolType::STYLUS).x(100).y(110))
1750 .build());
1751 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(stylusDeviceId)));
1752 spyWindow->consumeMotionEvent(
1753 AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(stylusDeviceId)));
1754
1755 // Touch down
1756 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
1757 .deviceId(touchDeviceId)
1758 .pointer(PointerBuilder(0, ToolType::FINGER).x(140).y(145))
1759 .build());
1760
1761 // Touch move
1762 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN)
1763 .deviceId(touchDeviceId)
1764 .pointer(PointerBuilder(0, ToolType::FINGER).x(141).y(146))
1765 .build());
Siarhei Vishniakou2899c552023-07-10 18:20:46 -07001766
1767 // Touch is ignored because stylus is already down
1768
1769 // Subsequent stylus movements are delivered correctly
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -07001770 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_STYLUS)
1771 .deviceId(stylusDeviceId)
1772 .pointer(PointerBuilder(0, ToolType::STYLUS).x(101).y(111))
1773 .build());
Siarhei Vishniakou2899c552023-07-10 18:20:46 -07001774 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(stylusDeviceId),
1775 WithCoords(101, 111)));
1776 spyWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(stylusDeviceId),
1777 WithCoords(101, 111)));
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -07001778
1779 window->assertNoEvents();
1780 spyWindow->assertNoEvents();
1781}
1782
1783/**
Siarhei Vishniakoued89cbb2023-10-13 10:42:44 -07001784 * One window and one spy window. Stylus down on the window. Next, touch from another device goes
1785 * down. Ensure that touch is not dropped, because multiple devices can be active at the same time.
1786 * Similar test as above, but with added SPY window.
1787 */
1788TEST_F(InputDispatcherMultiDeviceTest, StylusDownWithSpyDoesNotBlockTouchDown) {
1789 SCOPED_FLAG_OVERRIDE(enable_multi_device_same_window_stream, true);
1790 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
1791 sp<FakeWindowHandle> window =
1792 sp<FakeWindowHandle>::make(application, mDispatcher, "Window", ADISPLAY_ID_DEFAULT);
1793 sp<FakeWindowHandle> spyWindow =
1794 sp<FakeWindowHandle>::make(application, mDispatcher, "Spy", ADISPLAY_ID_DEFAULT);
1795 spyWindow->setFrame(Rect(0, 0, 200, 200));
1796 spyWindow->setTrustedOverlay(true);
1797 spyWindow->setSpy(true);
1798 window->setFrame(Rect(0, 0, 200, 200));
1799
1800 mDispatcher->onWindowInfosChanged({{*spyWindow->getInfo(), *window->getInfo()}, {}, 0, 0});
1801
1802 constexpr int32_t touchDeviceId = 4;
1803 constexpr int32_t stylusDeviceId = 2;
1804
1805 // Stylus down
1806 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_STYLUS)
1807 .deviceId(stylusDeviceId)
1808 .pointer(PointerBuilder(0, ToolType::STYLUS).x(100).y(110))
1809 .build());
1810 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(stylusDeviceId)));
1811 spyWindow->consumeMotionEvent(
1812 AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(stylusDeviceId)));
1813
1814 // Touch down
1815 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
1816 .deviceId(touchDeviceId)
1817 .pointer(PointerBuilder(0, ToolType::FINGER).x(140).y(145))
1818 .build());
1819 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(touchDeviceId)));
1820 spyWindow->consumeMotionEvent(
1821 AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(touchDeviceId)));
1822
1823 // Touch move
1824 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN)
1825 .deviceId(touchDeviceId)
1826 .pointer(PointerBuilder(0, ToolType::FINGER).x(141).y(146))
1827 .build());
1828 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(touchDeviceId)));
1829 spyWindow->consumeMotionEvent(
1830 AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(touchDeviceId)));
1831
1832 // Subsequent stylus movements are delivered correctly
1833 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_STYLUS)
1834 .deviceId(stylusDeviceId)
1835 .pointer(PointerBuilder(0, ToolType::STYLUS).x(101).y(111))
1836 .build());
1837 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(stylusDeviceId),
1838 WithCoords(101, 111)));
1839 spyWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(stylusDeviceId),
1840 WithCoords(101, 111)));
1841
1842 window->assertNoEvents();
1843 spyWindow->assertNoEvents();
1844}
1845
1846/**
Siarhei Vishniakou2899c552023-07-10 18:20:46 -07001847 * One window. Stylus hover on the window. Next, touch from another device goes down. Ensure that
Siarhei Vishniakou3ad54f52023-11-02 16:54:40 -07001848 * touch is dropped, because stylus hover takes precedence.
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -07001849 */
Siarhei Vishniakou3ad54f52023-11-02 16:54:40 -07001850TEST_F(InputDispatcherMultiDeviceTest, StylusHoverBlocksTouchDown) {
Siarhei Vishniakoued89cbb2023-10-13 10:42:44 -07001851 SCOPED_FLAG_OVERRIDE(enable_multi_device_same_window_stream, false);
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -07001852 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
1853 sp<FakeWindowHandle> window =
1854 sp<FakeWindowHandle>::make(application, mDispatcher, "Window", ADISPLAY_ID_DEFAULT);
1855 window->setFrame(Rect(0, 0, 200, 200));
1856
1857 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
1858
1859 constexpr int32_t touchDeviceId = 4;
1860 constexpr int32_t stylusDeviceId = 2;
1861
1862 // Stylus down on the window
1863 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_ENTER, AINPUT_SOURCE_STYLUS)
1864 .deviceId(stylusDeviceId)
1865 .pointer(PointerBuilder(0, ToolType::STYLUS).x(100).y(110))
1866 .build());
1867 window->consumeMotionEvent(
1868 AllOf(WithMotionAction(ACTION_HOVER_ENTER), WithDeviceId(stylusDeviceId)));
1869
1870 // Touch down on window
1871 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
1872 .deviceId(touchDeviceId)
1873 .pointer(PointerBuilder(0, ToolType::FINGER).x(140).y(145))
1874 .build());
1875 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN)
1876 .deviceId(touchDeviceId)
1877 .pointer(PointerBuilder(0, ToolType::FINGER).x(141).y(146))
1878 .build());
Siarhei Vishniakou2899c552023-07-10 18:20:46 -07001879
Siarhei Vishniakou3ad54f52023-11-02 16:54:40 -07001880 // Touch is ignored because stylus is hovering
Siarhei Vishniakou2899c552023-07-10 18:20:46 -07001881
Siarhei Vishniakou3ad54f52023-11-02 16:54:40 -07001882 // Subsequent stylus movements are delivered correctly
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -07001883 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_MOVE, AINPUT_SOURCE_STYLUS)
1884 .deviceId(stylusDeviceId)
1885 .pointer(PointerBuilder(0, ToolType::STYLUS).x(101).y(111))
1886 .build());
Siarhei Vishniakou3ad54f52023-11-02 16:54:40 -07001887 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_HOVER_MOVE),
1888 WithDeviceId(stylusDeviceId), WithCoords(101, 111)));
Siarhei Vishniakou2899c552023-07-10 18:20:46 -07001889
Siarhei Vishniakou3ad54f52023-11-02 16:54:40 -07001890 // and subsequent touches continue to be ignored
Siarhei Vishniakou2899c552023-07-10 18:20:46 -07001891 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN)
1892 .deviceId(touchDeviceId)
1893 .pointer(PointerBuilder(0, ToolType::FINGER).x(142).y(147))
1894 .build());
Siarhei Vishniakou3ad54f52023-11-02 16:54:40 -07001895 window->assertNoEvents();
Siarhei Vishniakou2899c552023-07-10 18:20:46 -07001896}
1897
1898/**
Siarhei Vishniakoued89cbb2023-10-13 10:42:44 -07001899 * One window. Stylus hover on the window. Next, touch from another device goes down. Ensure that
1900 * touch is not dropped, because stylus hover and touch can be both active at the same time.
1901 */
1902TEST_F(InputDispatcherMultiDeviceTest, StylusHoverDoesNotBlockTouchDown) {
1903 SCOPED_FLAG_OVERRIDE(enable_multi_device_same_window_stream, true);
1904 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
1905 sp<FakeWindowHandle> window =
1906 sp<FakeWindowHandle>::make(application, mDispatcher, "Window", ADISPLAY_ID_DEFAULT);
1907 window->setFrame(Rect(0, 0, 200, 200));
1908
1909 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
1910
1911 constexpr int32_t touchDeviceId = 4;
1912 constexpr int32_t stylusDeviceId = 2;
1913
1914 // Stylus down on the window
1915 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_ENTER, AINPUT_SOURCE_STYLUS)
1916 .deviceId(stylusDeviceId)
1917 .pointer(PointerBuilder(0, ToolType::STYLUS).x(100).y(110))
1918 .build());
1919 window->consumeMotionEvent(
1920 AllOf(WithMotionAction(ACTION_HOVER_ENTER), WithDeviceId(stylusDeviceId)));
1921
1922 // Touch down on window
1923 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
1924 .deviceId(touchDeviceId)
1925 .pointer(PointerBuilder(0, ToolType::FINGER).x(140).y(145))
1926 .build());
1927 // Touch move on window
1928 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(touchDeviceId)));
1929 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN)
1930 .deviceId(touchDeviceId)
1931 .pointer(PointerBuilder(0, ToolType::FINGER).x(141).y(146))
1932 .build());
1933 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(touchDeviceId)));
1934
1935 // Subsequent stylus movements are delivered correctly
1936 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_MOVE, AINPUT_SOURCE_STYLUS)
1937 .deviceId(stylusDeviceId)
1938 .pointer(PointerBuilder(0, ToolType::STYLUS).x(101).y(111))
1939 .build());
1940 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_HOVER_MOVE),
1941 WithDeviceId(stylusDeviceId), WithCoords(101, 111)));
1942
1943 // and subsequent touches continue to work
1944 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN)
1945 .deviceId(touchDeviceId)
1946 .pointer(PointerBuilder(0, ToolType::FINGER).x(142).y(147))
1947 .build());
1948 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(touchDeviceId)));
1949 window->assertNoEvents();
1950}
1951
1952/**
Siarhei Vishniakou2899c552023-07-10 18:20:46 -07001953 * One window. Touch down on the window. Then, stylus hover on the window from another device.
Siarhei Vishniakou3ad54f52023-11-02 16:54:40 -07001954 * Ensure that touch is canceled, because stylus hover should take precedence.
Siarhei Vishniakou2899c552023-07-10 18:20:46 -07001955 */
Siarhei Vishniakou3ad54f52023-11-02 16:54:40 -07001956TEST_F(InputDispatcherMultiDeviceTest, TouchIsCanceledByStylusHover) {
Siarhei Vishniakoued89cbb2023-10-13 10:42:44 -07001957 SCOPED_FLAG_OVERRIDE(enable_multi_device_same_window_stream, false);
Siarhei Vishniakou2899c552023-07-10 18:20:46 -07001958 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
1959 sp<FakeWindowHandle> window =
1960 sp<FakeWindowHandle>::make(application, mDispatcher, "Window", ADISPLAY_ID_DEFAULT);
1961 window->setFrame(Rect(0, 0, 200, 200));
1962
1963 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
1964
1965 constexpr int32_t touchDeviceId = 4;
1966 constexpr int32_t stylusDeviceId = 2;
1967
1968 // Touch down on window
1969 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
1970 .deviceId(touchDeviceId)
1971 .pointer(PointerBuilder(0, ToolType::FINGER).x(140).y(145))
1972 .build());
1973 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN)
1974 .deviceId(touchDeviceId)
1975 .pointer(PointerBuilder(0, ToolType::FINGER).x(141).y(146))
1976 .build());
1977 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(touchDeviceId)));
1978 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(touchDeviceId)));
1979
1980 // Stylus hover on the window
1981 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_ENTER, AINPUT_SOURCE_STYLUS)
1982 .deviceId(stylusDeviceId)
1983 .pointer(PointerBuilder(0, ToolType::STYLUS).x(100).y(110))
1984 .build());
1985 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_MOVE, AINPUT_SOURCE_STYLUS)
1986 .deviceId(stylusDeviceId)
1987 .pointer(PointerBuilder(0, ToolType::STYLUS).x(101).y(111))
1988 .build());
Siarhei Vishniakou3ad54f52023-11-02 16:54:40 -07001989 // Stylus hover movement causes touch to be canceled
1990 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_CANCEL), WithDeviceId(touchDeviceId),
1991 WithCoords(141, 146)));
1992 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_HOVER_ENTER),
1993 WithDeviceId(stylusDeviceId), WithCoords(100, 110)));
1994 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_HOVER_MOVE),
1995 WithDeviceId(stylusDeviceId), WithCoords(101, 111)));
Siarhei Vishniakou2899c552023-07-10 18:20:46 -07001996
Siarhei Vishniakou3ad54f52023-11-02 16:54:40 -07001997 // Subsequent touch movements are ignored
Siarhei Vishniakou2899c552023-07-10 18:20:46 -07001998 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN)
1999 .deviceId(touchDeviceId)
2000 .pointer(PointerBuilder(0, ToolType::FINGER).x(142).y(147))
2001 .build());
Siarhei Vishniakou3ad54f52023-11-02 16:54:40 -07002002
2003 window->assertNoEvents();
Siarhei Vishniakou2899c552023-07-10 18:20:46 -07002004}
2005
2006/**
Siarhei Vishniakoued89cbb2023-10-13 10:42:44 -07002007 * One window. Touch down on the window. Then, stylus hover on the window from another device.
2008 * Ensure that touch is not canceled, because stylus hover can be active at the same time as touch.
2009 */
2010TEST_F(InputDispatcherMultiDeviceTest, TouchIsNotCanceledByStylusHover) {
2011 SCOPED_FLAG_OVERRIDE(enable_multi_device_same_window_stream, true);
2012 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
2013 sp<FakeWindowHandle> window =
2014 sp<FakeWindowHandle>::make(application, mDispatcher, "Window", ADISPLAY_ID_DEFAULT);
2015 window->setFrame(Rect(0, 0, 200, 200));
2016
2017 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
2018
2019 constexpr int32_t touchDeviceId = 4;
2020 constexpr int32_t stylusDeviceId = 2;
2021
2022 // Touch down on window
2023 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
2024 .deviceId(touchDeviceId)
2025 .pointer(PointerBuilder(0, ToolType::FINGER).x(140).y(145))
2026 .build());
2027 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN)
2028 .deviceId(touchDeviceId)
2029 .pointer(PointerBuilder(0, ToolType::FINGER).x(141).y(146))
2030 .build());
2031 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(touchDeviceId)));
2032 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(touchDeviceId)));
2033
2034 // Stylus hover on the window
2035 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_ENTER, AINPUT_SOURCE_STYLUS)
2036 .deviceId(stylusDeviceId)
2037 .pointer(PointerBuilder(0, ToolType::STYLUS).x(100).y(110))
2038 .build());
2039 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_MOVE, AINPUT_SOURCE_STYLUS)
2040 .deviceId(stylusDeviceId)
2041 .pointer(PointerBuilder(0, ToolType::STYLUS).x(101).y(111))
2042 .build());
2043 // Stylus hover movement is received normally
2044 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_HOVER_ENTER),
2045 WithDeviceId(stylusDeviceId), WithCoords(100, 110)));
2046 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_HOVER_MOVE),
2047 WithDeviceId(stylusDeviceId), WithCoords(101, 111)));
2048
2049 // Subsequent touch movements also work
2050 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN)
2051 .deviceId(touchDeviceId)
2052 .pointer(PointerBuilder(0, ToolType::FINGER).x(142).y(147))
2053 .build());
2054 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(touchDeviceId),
2055 WithCoords(142, 147)));
2056
2057 window->assertNoEvents();
2058}
2059
2060/**
Siarhei Vishniakou2899c552023-07-10 18:20:46 -07002061 * One window. Stylus down on the window. Then, stylus from another device goes down. Ensure that
2062 * the latest stylus takes over. That is, old stylus should be canceled and the new stylus should
2063 * become active.
2064 */
2065TEST_F(InputDispatcherMultiDeviceTest, LatestStylusWins) {
Siarhei Vishniakoued89cbb2023-10-13 10:42:44 -07002066 SCOPED_FLAG_OVERRIDE(enable_multi_device_same_window_stream, false);
Siarhei Vishniakou2899c552023-07-10 18:20:46 -07002067 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
2068 sp<FakeWindowHandle> window =
2069 sp<FakeWindowHandle>::make(application, mDispatcher, "Window", ADISPLAY_ID_DEFAULT);
2070 window->setFrame(Rect(0, 0, 200, 200));
2071
2072 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
2073
2074 constexpr int32_t stylusDeviceId1 = 3;
2075 constexpr int32_t stylusDeviceId2 = 5;
2076
2077 // Touch down on window
2078 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_STYLUS)
2079 .deviceId(stylusDeviceId1)
2080 .pointer(PointerBuilder(0, ToolType::STYLUS).x(99).y(100))
2081 .build());
2082 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_STYLUS)
2083 .deviceId(stylusDeviceId1)
2084 .pointer(PointerBuilder(0, ToolType::STYLUS).x(100).y(101))
2085 .build());
2086 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(stylusDeviceId1)));
2087 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(stylusDeviceId1)));
2088
2089 // Second stylus down
2090 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_STYLUS)
2091 .deviceId(stylusDeviceId2)
2092 .pointer(PointerBuilder(0, ToolType::STYLUS).x(9).y(10))
2093 .build());
2094 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_STYLUS)
2095 .deviceId(stylusDeviceId2)
2096 .pointer(PointerBuilder(0, ToolType::STYLUS).x(10).y(11))
2097 .build());
2098
2099 // First stylus is canceled, second one takes over.
2100 window->consumeMotionEvent(
2101 AllOf(WithMotionAction(ACTION_CANCEL), WithDeviceId(stylusDeviceId1)));
2102 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(stylusDeviceId2)));
2103 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(stylusDeviceId2)));
2104
2105 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_STYLUS)
2106 .deviceId(stylusDeviceId1)
2107 .pointer(PointerBuilder(0, ToolType::STYLUS).x(101).y(102))
2108 .build());
2109 // Subsequent stylus movements are delivered correctly
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -07002110 window->assertNoEvents();
2111}
2112
2113/**
Siarhei Vishniakoued89cbb2023-10-13 10:42:44 -07002114 * One window. Stylus down on the window. Then, stylus from another device goes down. Ensure that
2115 * both stylus devices can function simultaneously.
2116 */
2117TEST_F(InputDispatcherMultiDeviceTest, TwoStylusDevicesActiveAtTheSameTime) {
2118 SCOPED_FLAG_OVERRIDE(enable_multi_device_same_window_stream, true);
2119 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
2120 sp<FakeWindowHandle> window =
2121 sp<FakeWindowHandle>::make(application, mDispatcher, "Window", ADISPLAY_ID_DEFAULT);
2122 window->setFrame(Rect(0, 0, 200, 200));
2123
2124 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
2125
2126 constexpr int32_t stylusDeviceId1 = 3;
2127 constexpr int32_t stylusDeviceId2 = 5;
2128
2129 // Touch down on window
2130 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_STYLUS)
2131 .deviceId(stylusDeviceId1)
2132 .pointer(PointerBuilder(0, ToolType::STYLUS).x(99).y(100))
2133 .build());
2134 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_STYLUS)
2135 .deviceId(stylusDeviceId1)
2136 .pointer(PointerBuilder(0, ToolType::STYLUS).x(100).y(101))
2137 .build());
2138 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(stylusDeviceId1)));
2139 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(stylusDeviceId1)));
2140
2141 // Second stylus down
2142 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_STYLUS)
2143 .deviceId(stylusDeviceId2)
2144 .pointer(PointerBuilder(0, ToolType::STYLUS).x(9).y(10))
2145 .build());
2146 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_STYLUS)
2147 .deviceId(stylusDeviceId2)
2148 .pointer(PointerBuilder(0, ToolType::STYLUS).x(10).y(11))
2149 .build());
2150 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(stylusDeviceId2)));
2151 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(stylusDeviceId2)));
2152
2153 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_STYLUS)
2154 .deviceId(stylusDeviceId1)
2155 .pointer(PointerBuilder(0, ToolType::STYLUS).x(101).y(102))
2156 .build());
2157 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(stylusDeviceId1)));
2158 window->assertNoEvents();
2159}
2160
2161/**
Siarhei Vishniakou2899c552023-07-10 18:20:46 -07002162 * One window. Touch down on the window. Then, stylus down on the window from another device.
2163 * Ensure that is canceled, because stylus down should be preferred over touch.
2164 */
2165TEST_F(InputDispatcherMultiDeviceTest, TouchIsCanceledByStylusDown) {
Siarhei Vishniakoued89cbb2023-10-13 10:42:44 -07002166 SCOPED_FLAG_OVERRIDE(enable_multi_device_same_window_stream, false);
Siarhei Vishniakou2899c552023-07-10 18:20:46 -07002167 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
2168 sp<FakeWindowHandle> window =
2169 sp<FakeWindowHandle>::make(application, mDispatcher, "Window", ADISPLAY_ID_DEFAULT);
2170 window->setFrame(Rect(0, 0, 200, 200));
2171
2172 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
2173
2174 constexpr int32_t touchDeviceId = 4;
2175 constexpr int32_t stylusDeviceId = 2;
2176
2177 // Touch down on window
2178 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
2179 .deviceId(touchDeviceId)
2180 .pointer(PointerBuilder(0, ToolType::FINGER).x(140).y(145))
2181 .build());
2182 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN)
2183 .deviceId(touchDeviceId)
2184 .pointer(PointerBuilder(0, ToolType::FINGER).x(141).y(146))
2185 .build());
2186 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(touchDeviceId)));
2187 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(touchDeviceId)));
2188
2189 // Stylus down on the window
2190 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_STYLUS)
2191 .deviceId(stylusDeviceId)
2192 .pointer(PointerBuilder(0, ToolType::STYLUS).x(100).y(110))
2193 .build());
2194 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_CANCEL), WithDeviceId(touchDeviceId)));
2195 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(stylusDeviceId)));
2196
2197 // Subsequent stylus movements are delivered correctly
2198 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_STYLUS)
2199 .deviceId(stylusDeviceId)
2200 .pointer(PointerBuilder(0, ToolType::STYLUS).x(101).y(111))
2201 .build());
2202 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(stylusDeviceId),
2203 WithCoords(101, 111)));
2204}
2205
2206/**
Siarhei Vishniakoued89cbb2023-10-13 10:42:44 -07002207 * One window. Touch down on the window. Then, stylus down on the window from another device.
2208 * Ensure that both touch and stylus are functioning independently.
2209 */
2210TEST_F(InputDispatcherMultiDeviceTest, TouchIsNotCanceledByStylusDown) {
2211 SCOPED_FLAG_OVERRIDE(enable_multi_device_same_window_stream, true);
2212 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
2213 sp<FakeWindowHandle> window =
2214 sp<FakeWindowHandle>::make(application, mDispatcher, "Window", ADISPLAY_ID_DEFAULT);
2215 window->setFrame(Rect(0, 0, 200, 200));
2216
2217 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
2218
2219 constexpr int32_t touchDeviceId = 4;
2220 constexpr int32_t stylusDeviceId = 2;
2221
2222 // Touch down on window
2223 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
2224 .deviceId(touchDeviceId)
2225 .pointer(PointerBuilder(0, ToolType::FINGER).x(140).y(145))
2226 .build());
2227 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN)
2228 .deviceId(touchDeviceId)
2229 .pointer(PointerBuilder(0, ToolType::FINGER).x(141).y(146))
2230 .build());
2231 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(touchDeviceId)));
2232 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(touchDeviceId)));
2233
2234 // Stylus down on the window
2235 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_STYLUS)
2236 .deviceId(stylusDeviceId)
2237 .pointer(PointerBuilder(0, ToolType::STYLUS).x(100).y(110))
2238 .build());
2239 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(stylusDeviceId)));
2240
2241 // Subsequent stylus movements are delivered correctly
2242 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_STYLUS)
2243 .deviceId(stylusDeviceId)
2244 .pointer(PointerBuilder(0, ToolType::STYLUS).x(101).y(111))
2245 .build());
2246 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(stylusDeviceId),
2247 WithCoords(101, 111)));
2248
2249 // Touch continues to work too
2250 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN)
2251 .deviceId(touchDeviceId)
2252 .pointer(PointerBuilder(0, ToolType::FINGER).x(148).y(149))
2253 .build());
2254 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(touchDeviceId)));
2255}
2256
2257/**
Siarhei Vishniakouf372b812023-02-14 18:06:51 -08002258 * Two windows: a window on the left and a window on the right.
2259 * Mouse is clicked on the left window and remains down. Touch is touched on the right and remains
2260 * down. Then, on the left window, also place second touch pointer down.
2261 * This test tries to reproduce a crash.
2262 * In the buggy implementation, second pointer down on the left window would cause a crash.
2263 */
Siarhei Vishniakoued89cbb2023-10-13 10:42:44 -07002264TEST_F(InputDispatcherMultiDeviceTest, MultiDeviceSplitTouch_legacy) {
2265 SCOPED_FLAG_OVERRIDE(enable_multi_device_same_window_stream, false);
Siarhei Vishniakouf372b812023-02-14 18:06:51 -08002266 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
2267 sp<FakeWindowHandle> leftWindow =
2268 sp<FakeWindowHandle>::make(application, mDispatcher, "Left", ADISPLAY_ID_DEFAULT);
2269 leftWindow->setFrame(Rect(0, 0, 200, 200));
2270
2271 sp<FakeWindowHandle> rightWindow =
2272 sp<FakeWindowHandle>::make(application, mDispatcher, "Right", ADISPLAY_ID_DEFAULT);
2273 rightWindow->setFrame(Rect(200, 0, 400, 200));
2274
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07002275 mDispatcher->onWindowInfosChanged(
2276 {{*leftWindow->getInfo(), *rightWindow->getInfo()}, {}, 0, 0});
Siarhei Vishniakouf372b812023-02-14 18:06:51 -08002277
2278 const int32_t touchDeviceId = 4;
2279 const int32_t mouseDeviceId = 6;
Siarhei Vishniakouf372b812023-02-14 18:06:51 -08002280
2281 // Start hovering over the left window
Prabir Pradhan678438e2023-04-13 19:32:51 +00002282 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_ENTER, AINPUT_SOURCE_MOUSE)
2283 .deviceId(mouseDeviceId)
2284 .pointer(PointerBuilder(0, ToolType::MOUSE).x(100).y(100))
2285 .build());
Siarhei Vishniakouf372b812023-02-14 18:06:51 -08002286 leftWindow->consumeMotionEvent(
2287 AllOf(WithMotionAction(ACTION_HOVER_ENTER), WithDeviceId(mouseDeviceId)));
2288
2289 // Mouse down on left window
Prabir Pradhan678438e2023-04-13 19:32:51 +00002290 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_MOUSE)
2291 .deviceId(mouseDeviceId)
2292 .buttonState(AMOTION_EVENT_BUTTON_PRIMARY)
2293 .pointer(PointerBuilder(0, ToolType::MOUSE).x(100).y(100))
2294 .build());
Siarhei Vishniakouf372b812023-02-14 18:06:51 -08002295
2296 leftWindow->consumeMotionEvent(
2297 AllOf(WithMotionAction(ACTION_HOVER_EXIT), WithDeviceId(mouseDeviceId)));
2298 leftWindow->consumeMotionEvent(
2299 AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(mouseDeviceId)));
2300
Prabir Pradhan678438e2023-04-13 19:32:51 +00002301 mDispatcher->notifyMotion(
2302 MotionArgsBuilder(AMOTION_EVENT_ACTION_BUTTON_PRESS, AINPUT_SOURCE_MOUSE)
2303 .deviceId(mouseDeviceId)
2304 .buttonState(AMOTION_EVENT_BUTTON_PRIMARY)
2305 .actionButton(AMOTION_EVENT_BUTTON_PRIMARY)
2306 .pointer(PointerBuilder(0, ToolType::MOUSE).x(100).y(100))
2307 .build());
Siarhei Vishniakouf372b812023-02-14 18:06:51 -08002308 leftWindow->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_BUTTON_PRESS));
2309
2310 // First touch pointer down on right window
Prabir Pradhan678438e2023-04-13 19:32:51 +00002311 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
2312 .deviceId(touchDeviceId)
2313 .pointer(PointerBuilder(0, ToolType::FINGER).x(300).y(100))
2314 .build());
Siarhei Vishniakou2899c552023-07-10 18:20:46 -07002315 leftWindow->assertNoEvents();
2316
Siarhei Vishniakouf372b812023-02-14 18:06:51 -08002317 rightWindow->consumeMotionEvent(WithMotionAction(ACTION_DOWN));
2318
2319 // Second touch pointer down on left window
Prabir Pradhan678438e2023-04-13 19:32:51 +00002320 mDispatcher->notifyMotion(MotionArgsBuilder(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
2321 .deviceId(touchDeviceId)
2322 .pointer(PointerBuilder(0, ToolType::FINGER).x(300).y(100))
2323 .pointer(PointerBuilder(1, ToolType::FINGER).x(100).y(100))
2324 .build());
Siarhei Vishniakou2899c552023-07-10 18:20:46 -07002325 // Since this is now a new splittable pointer going down on the left window, and it's coming
2326 // from a different device, the current gesture in the left window (pointer down) should first
2327 // be canceled.
2328 leftWindow->consumeMotionEvent(
2329 AllOf(WithMotionAction(ACTION_CANCEL), WithDeviceId(mouseDeviceId)));
Siarhei Vishniakouf372b812023-02-14 18:06:51 -08002330 leftWindow->consumeMotionEvent(
2331 AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(touchDeviceId)));
2332 // This MOVE event is not necessary (doesn't carry any new information), but it's there in the
2333 // current implementation.
2334 const std::map<int32_t, PointF> expectedPointers{{0, PointF{100, 100}}};
2335 rightWindow->consumeMotionEvent(
2336 AllOf(WithMotionAction(ACTION_MOVE), WithPointers(expectedPointers)));
2337
2338 leftWindow->assertNoEvents();
2339 rightWindow->assertNoEvents();
2340}
2341
2342/**
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -07002343 * Two windows: a window on the left and a window on the right.
Siarhei Vishniakoued89cbb2023-10-13 10:42:44 -07002344 * Mouse is clicked on the left window and remains down. Touch is touched on the right and remains
2345 * down. Then, on the left window, also place second touch pointer down.
2346 * This test tries to reproduce a crash.
2347 * In the buggy implementation, second pointer down on the left window would cause a crash.
2348 */
2349TEST_F(InputDispatcherMultiDeviceTest, MultiDeviceSplitTouch) {
2350 SCOPED_FLAG_OVERRIDE(enable_multi_device_same_window_stream, true);
2351 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
2352 sp<FakeWindowHandle> leftWindow =
2353 sp<FakeWindowHandle>::make(application, mDispatcher, "Left", ADISPLAY_ID_DEFAULT);
2354 leftWindow->setFrame(Rect(0, 0, 200, 200));
2355
2356 sp<FakeWindowHandle> rightWindow =
2357 sp<FakeWindowHandle>::make(application, mDispatcher, "Right", ADISPLAY_ID_DEFAULT);
2358 rightWindow->setFrame(Rect(200, 0, 400, 200));
2359
2360 mDispatcher->onWindowInfosChanged(
2361 {{*leftWindow->getInfo(), *rightWindow->getInfo()}, {}, 0, 0});
2362
2363 const int32_t touchDeviceId = 4;
2364 const int32_t mouseDeviceId = 6;
2365
2366 // Start hovering over the left window
2367 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_ENTER, AINPUT_SOURCE_MOUSE)
2368 .deviceId(mouseDeviceId)
2369 .pointer(PointerBuilder(0, ToolType::MOUSE).x(100).y(100))
2370 .build());
2371 leftWindow->consumeMotionEvent(
2372 AllOf(WithMotionAction(ACTION_HOVER_ENTER), WithDeviceId(mouseDeviceId)));
2373
2374 // Mouse down on left window
2375 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_MOUSE)
2376 .deviceId(mouseDeviceId)
2377 .buttonState(AMOTION_EVENT_BUTTON_PRIMARY)
2378 .pointer(PointerBuilder(0, ToolType::MOUSE).x(100).y(100))
2379 .build());
2380
2381 leftWindow->consumeMotionEvent(
2382 AllOf(WithMotionAction(ACTION_HOVER_EXIT), WithDeviceId(mouseDeviceId)));
2383 leftWindow->consumeMotionEvent(
2384 AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(mouseDeviceId)));
2385
2386 mDispatcher->notifyMotion(
2387 MotionArgsBuilder(AMOTION_EVENT_ACTION_BUTTON_PRESS, AINPUT_SOURCE_MOUSE)
2388 .deviceId(mouseDeviceId)
2389 .buttonState(AMOTION_EVENT_BUTTON_PRIMARY)
2390 .actionButton(AMOTION_EVENT_BUTTON_PRIMARY)
2391 .pointer(PointerBuilder(0, ToolType::MOUSE).x(100).y(100))
2392 .build());
2393 leftWindow->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_BUTTON_PRESS));
2394
2395 // First touch pointer down on right window
2396 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
2397 .deviceId(touchDeviceId)
2398 .pointer(PointerBuilder(0, ToolType::FINGER).x(300).y(100))
2399 .build());
2400 leftWindow->assertNoEvents();
2401
2402 rightWindow->consumeMotionEvent(WithMotionAction(ACTION_DOWN));
2403
2404 // Second touch pointer down on left window
2405 mDispatcher->notifyMotion(MotionArgsBuilder(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
2406 .deviceId(touchDeviceId)
2407 .pointer(PointerBuilder(0, ToolType::FINGER).x(300).y(100))
2408 .pointer(PointerBuilder(1, ToolType::FINGER).x(100).y(100))
2409 .build());
2410 // Since this is now a new splittable pointer going down on the left window, and it's coming
2411 // from a different device, it will be split and delivered to left window separately.
2412 leftWindow->consumeMotionEvent(
2413 AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(touchDeviceId)));
2414 // This MOVE event is not necessary (doesn't carry any new information), but it's there in the
2415 // current implementation.
2416 const std::map<int32_t, PointF> expectedPointers{{0, PointF{100, 100}}};
2417 rightWindow->consumeMotionEvent(
2418 AllOf(WithMotionAction(ACTION_MOVE), WithPointers(expectedPointers)));
2419
2420 leftWindow->assertNoEvents();
2421 rightWindow->assertNoEvents();
2422}
2423
2424/**
2425 * Two windows: a window on the left and a window on the right.
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -07002426 * Mouse is hovered on the left window and stylus is hovered on the right window.
2427 */
2428TEST_F(InputDispatcherMultiDeviceTest, MultiDeviceHover) {
2429 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
2430 sp<FakeWindowHandle> leftWindow =
2431 sp<FakeWindowHandle>::make(application, mDispatcher, "Left", ADISPLAY_ID_DEFAULT);
2432 leftWindow->setFrame(Rect(0, 0, 200, 200));
2433
2434 sp<FakeWindowHandle> rightWindow =
2435 sp<FakeWindowHandle>::make(application, mDispatcher, "Right", ADISPLAY_ID_DEFAULT);
2436 rightWindow->setFrame(Rect(200, 0, 400, 200));
2437
2438 mDispatcher->onWindowInfosChanged(
2439 {{*leftWindow->getInfo(), *rightWindow->getInfo()}, {}, 0, 0});
2440
2441 const int32_t stylusDeviceId = 3;
2442 const int32_t mouseDeviceId = 6;
2443
2444 // Start hovering over the left window
2445 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_ENTER, AINPUT_SOURCE_MOUSE)
2446 .deviceId(mouseDeviceId)
2447 .pointer(PointerBuilder(0, ToolType::MOUSE).x(100).y(110))
2448 .build());
2449 leftWindow->consumeMotionEvent(
2450 AllOf(WithMotionAction(ACTION_HOVER_ENTER), WithDeviceId(mouseDeviceId)));
2451
2452 // Stylus hovered on right window
2453 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_ENTER, AINPUT_SOURCE_STYLUS)
2454 .deviceId(stylusDeviceId)
2455 .pointer(PointerBuilder(0, ToolType::STYLUS).x(300).y(100))
2456 .build());
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -07002457 rightWindow->consumeMotionEvent(
2458 AllOf(WithMotionAction(ACTION_HOVER_ENTER), WithDeviceId(stylusDeviceId)));
2459
2460 // Subsequent HOVER_MOVE events are dispatched correctly.
2461 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_MOVE, AINPUT_SOURCE_MOUSE)
2462 .deviceId(mouseDeviceId)
2463 .pointer(PointerBuilder(0, ToolType::MOUSE).x(110).y(120))
2464 .build());
2465 leftWindow->consumeMotionEvent(
Siarhei Vishniakou2899c552023-07-10 18:20:46 -07002466 AllOf(WithMotionAction(ACTION_HOVER_MOVE), WithDeviceId(mouseDeviceId)));
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -07002467
2468 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_MOVE, AINPUT_SOURCE_STYLUS)
2469 .deviceId(stylusDeviceId)
2470 .pointer(PointerBuilder(0, ToolType::STYLUS).x(310).y(110))
2471 .build());
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -07002472 rightWindow->consumeMotionEvent(
Siarhei Vishniakou2899c552023-07-10 18:20:46 -07002473 AllOf(WithMotionAction(ACTION_HOVER_MOVE), WithDeviceId(stylusDeviceId)));
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -07002474
2475 leftWindow->assertNoEvents();
2476 rightWindow->assertNoEvents();
2477}
2478
2479/**
2480 * Three windows: a window on the left and a window on the right.
2481 * And a spy window that's positioned above all of them.
2482 * Stylus down on the left window and remains down. Touch goes down on the right and remains down.
2483 * Check the stream that's received by the spy.
2484 */
Siarhei Vishniakoued89cbb2023-10-13 10:42:44 -07002485TEST_F(InputDispatcherMultiDeviceTest, MultiDeviceWithSpy_legacy) {
2486 SCOPED_FLAG_OVERRIDE(enable_multi_device_same_window_stream, false);
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -07002487 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
2488
2489 sp<FakeWindowHandle> spyWindow =
2490 sp<FakeWindowHandle>::make(application, mDispatcher, "Spy", ADISPLAY_ID_DEFAULT);
2491 spyWindow->setFrame(Rect(0, 0, 400, 400));
2492 spyWindow->setTrustedOverlay(true);
2493 spyWindow->setSpy(true);
2494
2495 sp<FakeWindowHandle> leftWindow =
2496 sp<FakeWindowHandle>::make(application, mDispatcher, "Left", ADISPLAY_ID_DEFAULT);
2497 leftWindow->setFrame(Rect(0, 0, 200, 200));
2498
2499 sp<FakeWindowHandle> rightWindow =
2500 sp<FakeWindowHandle>::make(application, mDispatcher, "Right", ADISPLAY_ID_DEFAULT);
2501
2502 rightWindow->setFrame(Rect(200, 0, 400, 200));
2503
2504 mDispatcher->onWindowInfosChanged(
2505 {{*spyWindow->getInfo(), *leftWindow->getInfo(), *rightWindow->getInfo()}, {}, 0, 0});
2506
2507 const int32_t stylusDeviceId = 1;
2508 const int32_t touchDeviceId = 2;
2509
2510 // Stylus down on the left window
2511 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_STYLUS)
2512 .deviceId(stylusDeviceId)
2513 .pointer(PointerBuilder(0, ToolType::STYLUS).x(100).y(100))
2514 .build());
2515 leftWindow->consumeMotionEvent(
2516 AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(stylusDeviceId)));
2517 spyWindow->consumeMotionEvent(
2518 AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(stylusDeviceId)));
2519
2520 // Touch down on the right window
2521 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
2522 .deviceId(touchDeviceId)
2523 .pointer(PointerBuilder(0, ToolType::FINGER).x(300).y(100))
2524 .build());
Siarhei Vishniakou2899c552023-07-10 18:20:46 -07002525 leftWindow->assertNoEvents();
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -07002526 rightWindow->consumeMotionEvent(
2527 AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(touchDeviceId)));
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -07002528
Siarhei Vishniakou2899c552023-07-10 18:20:46 -07002529 // Spy window does not receive touch events, because stylus events take precedence, and it
2530 // already has an active stylus gesture.
2531
2532 // Stylus movements continue. They should be delivered to the left window and to the spy window
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -07002533 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_STYLUS)
2534 .deviceId(stylusDeviceId)
2535 .pointer(PointerBuilder(0, ToolType::STYLUS).x(110).y(110))
2536 .build());
Siarhei Vishniakou2899c552023-07-10 18:20:46 -07002537 leftWindow->consumeMotionEvent(
2538 AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(stylusDeviceId)));
2539 spyWindow->consumeMotionEvent(
2540 AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(stylusDeviceId)));
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -07002541
Siarhei Vishniakou2899c552023-07-10 18:20:46 -07002542 // Further MOVE events keep going to the right window only
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -07002543 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN)
2544 .deviceId(touchDeviceId)
2545 .pointer(PointerBuilder(0, ToolType::FINGER).x(310).y(110))
2546 .build());
2547 rightWindow->consumeMotionEvent(
2548 AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(touchDeviceId)));
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -07002549
2550 spyWindow->assertNoEvents();
2551 leftWindow->assertNoEvents();
2552 rightWindow->assertNoEvents();
2553}
2554
2555/**
Siarhei Vishniakoued89cbb2023-10-13 10:42:44 -07002556 * Three windows: a window on the left and a window on the right.
2557 * And a spy window that's positioned above all of them.
2558 * Stylus down on the left window and remains down. Touch goes down on the right and remains down.
2559 * Check the stream that's received by the spy.
2560 */
2561TEST_F(InputDispatcherMultiDeviceTest, MultiDeviceWithSpy) {
2562 SCOPED_FLAG_OVERRIDE(enable_multi_device_same_window_stream, true);
2563 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
2564
2565 sp<FakeWindowHandle> spyWindow =
2566 sp<FakeWindowHandle>::make(application, mDispatcher, "Spy", ADISPLAY_ID_DEFAULT);
2567 spyWindow->setFrame(Rect(0, 0, 400, 400));
2568 spyWindow->setTrustedOverlay(true);
2569 spyWindow->setSpy(true);
2570
2571 sp<FakeWindowHandle> leftWindow =
2572 sp<FakeWindowHandle>::make(application, mDispatcher, "Left", ADISPLAY_ID_DEFAULT);
2573 leftWindow->setFrame(Rect(0, 0, 200, 200));
2574
2575 sp<FakeWindowHandle> rightWindow =
2576 sp<FakeWindowHandle>::make(application, mDispatcher, "Right", ADISPLAY_ID_DEFAULT);
2577
2578 rightWindow->setFrame(Rect(200, 0, 400, 200));
2579
2580 mDispatcher->onWindowInfosChanged(
2581 {{*spyWindow->getInfo(), *leftWindow->getInfo(), *rightWindow->getInfo()}, {}, 0, 0});
2582
2583 const int32_t stylusDeviceId = 1;
2584 const int32_t touchDeviceId = 2;
2585
2586 // Stylus down on the left window
2587 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_STYLUS)
2588 .deviceId(stylusDeviceId)
2589 .pointer(PointerBuilder(0, ToolType::STYLUS).x(100).y(100))
2590 .build());
2591 leftWindow->consumeMotionEvent(
2592 AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(stylusDeviceId)));
2593 spyWindow->consumeMotionEvent(
2594 AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(stylusDeviceId)));
2595
2596 // Touch down on the right window
2597 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
2598 .deviceId(touchDeviceId)
2599 .pointer(PointerBuilder(0, ToolType::FINGER).x(300).y(100))
2600 .build());
2601 leftWindow->assertNoEvents();
2602 rightWindow->consumeMotionEvent(
2603 AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(touchDeviceId)));
2604 spyWindow->consumeMotionEvent(
2605 AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(touchDeviceId)));
2606
2607 // Stylus movements continue. They should be delivered to the left window and to the spy window
2608 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_STYLUS)
2609 .deviceId(stylusDeviceId)
2610 .pointer(PointerBuilder(0, ToolType::STYLUS).x(110).y(110))
2611 .build());
2612 leftWindow->consumeMotionEvent(
2613 AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(stylusDeviceId)));
2614 spyWindow->consumeMotionEvent(
2615 AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(stylusDeviceId)));
2616
2617 // Further touch MOVE events keep going to the right window and to the spy
2618 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN)
2619 .deviceId(touchDeviceId)
2620 .pointer(PointerBuilder(0, ToolType::FINGER).x(310).y(110))
2621 .build());
2622 rightWindow->consumeMotionEvent(
2623 AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(touchDeviceId)));
2624 spyWindow->consumeMotionEvent(
2625 AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(touchDeviceId)));
2626
2627 spyWindow->assertNoEvents();
2628 leftWindow->assertNoEvents();
2629 rightWindow->assertNoEvents();
2630}
2631
2632/**
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -07002633 * Three windows: a window on the left, a window on the right, and a spy window positioned above
2634 * both.
2635 * Check hover in left window and touch down in the right window.
Siarhei Vishniakou3ad54f52023-11-02 16:54:40 -07002636 * At first, spy should receive hover. Spy shouldn't receive touch while stylus is hovering.
Siarhei Vishniakou2899c552023-07-10 18:20:46 -07002637 * At the same time, left and right should be getting independent streams of hovering and touch,
2638 * respectively.
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -07002639 */
Siarhei Vishniakou3ad54f52023-11-02 16:54:40 -07002640TEST_F(InputDispatcherMultiDeviceTest, MultiDeviceHoverBlocksTouchWithSpy) {
Siarhei Vishniakoued89cbb2023-10-13 10:42:44 -07002641 SCOPED_FLAG_OVERRIDE(enable_multi_device_same_window_stream, false);
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -07002642 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
2643
2644 sp<FakeWindowHandle> spyWindow =
2645 sp<FakeWindowHandle>::make(application, mDispatcher, "Spy", ADISPLAY_ID_DEFAULT);
2646 spyWindow->setFrame(Rect(0, 0, 400, 400));
2647 spyWindow->setTrustedOverlay(true);
2648 spyWindow->setSpy(true);
2649
2650 sp<FakeWindowHandle> leftWindow =
2651 sp<FakeWindowHandle>::make(application, mDispatcher, "Left", ADISPLAY_ID_DEFAULT);
2652 leftWindow->setFrame(Rect(0, 0, 200, 200));
2653
2654 sp<FakeWindowHandle> rightWindow =
2655 sp<FakeWindowHandle>::make(application, mDispatcher, "Right", ADISPLAY_ID_DEFAULT);
2656 rightWindow->setFrame(Rect(200, 0, 400, 200));
2657
2658 mDispatcher->onWindowInfosChanged(
2659 {{*spyWindow->getInfo(), *leftWindow->getInfo(), *rightWindow->getInfo()}, {}, 0, 0});
2660
2661 const int32_t stylusDeviceId = 1;
2662 const int32_t touchDeviceId = 2;
2663
2664 // Stylus hover on the left window
2665 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_ENTER, AINPUT_SOURCE_STYLUS)
2666 .deviceId(stylusDeviceId)
2667 .pointer(PointerBuilder(0, ToolType::STYLUS).x(100).y(100))
2668 .build());
2669 leftWindow->consumeMotionEvent(
2670 AllOf(WithMotionAction(ACTION_HOVER_ENTER), WithDeviceId(stylusDeviceId)));
2671 spyWindow->consumeMotionEvent(
2672 AllOf(WithMotionAction(ACTION_HOVER_ENTER), WithDeviceId(stylusDeviceId)));
2673
Siarhei Vishniakou2899c552023-07-10 18:20:46 -07002674 // Touch down on the right window. Spy doesn't receive this touch because it already has
2675 // stylus hovering there.
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -07002676 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
2677 .deviceId(touchDeviceId)
2678 .pointer(PointerBuilder(0, ToolType::FINGER).x(300).y(100))
2679 .build());
Siarhei Vishniakou2899c552023-07-10 18:20:46 -07002680 leftWindow->assertNoEvents();
Siarhei Vishniakou3ad54f52023-11-02 16:54:40 -07002681 spyWindow->assertNoEvents();
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -07002682 rightWindow->consumeMotionEvent(
2683 AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(touchDeviceId)));
2684
Siarhei Vishniakou3ad54f52023-11-02 16:54:40 -07002685 // Stylus movements continue. They should be delivered to the left window and the spy.
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -07002686 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_MOVE, AINPUT_SOURCE_STYLUS)
2687 .deviceId(stylusDeviceId)
2688 .pointer(PointerBuilder(0, ToolType::STYLUS).x(110).y(110))
2689 .build());
Siarhei Vishniakou2899c552023-07-10 18:20:46 -07002690 leftWindow->consumeMotionEvent(
2691 AllOf(WithMotionAction(ACTION_HOVER_MOVE), WithDeviceId(stylusDeviceId)));
Siarhei Vishniakou3ad54f52023-11-02 16:54:40 -07002692 spyWindow->consumeMotionEvent(
2693 AllOf(WithMotionAction(ACTION_HOVER_MOVE), WithDeviceId(stylusDeviceId)));
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -07002694
Siarhei Vishniakou3ad54f52023-11-02 16:54:40 -07002695 // Touch movements continue. They should be delivered to the right window only
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -07002696 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN)
2697 .deviceId(touchDeviceId)
2698 .pointer(PointerBuilder(0, ToolType::FINGER).x(301).y(101))
2699 .build());
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -07002700 rightWindow->consumeMotionEvent(
2701 AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(touchDeviceId)));
2702
2703 spyWindow->assertNoEvents();
2704 leftWindow->assertNoEvents();
2705 rightWindow->assertNoEvents();
2706}
2707
2708/**
Siarhei Vishniakoued89cbb2023-10-13 10:42:44 -07002709 * Three windows: a window on the left, a window on the right, and a spy window positioned above
2710 * both.
2711 * Check hover in left window and touch down in the right window.
2712 * At first, spy should receive hover. Next, spy should receive touch.
2713 * At the same time, left and right should be getting independent streams of hovering and touch,
2714 * respectively.
2715 */
2716TEST_F(InputDispatcherMultiDeviceTest, MultiDeviceHoverDoesNotBlockTouchWithSpy) {
2717 SCOPED_FLAG_OVERRIDE(enable_multi_device_same_window_stream, true);
2718 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
2719
2720 sp<FakeWindowHandle> spyWindow =
2721 sp<FakeWindowHandle>::make(application, mDispatcher, "Spy", ADISPLAY_ID_DEFAULT);
2722 spyWindow->setFrame(Rect(0, 0, 400, 400));
2723 spyWindow->setTrustedOverlay(true);
2724 spyWindow->setSpy(true);
2725
2726 sp<FakeWindowHandle> leftWindow =
2727 sp<FakeWindowHandle>::make(application, mDispatcher, "Left", ADISPLAY_ID_DEFAULT);
2728 leftWindow->setFrame(Rect(0, 0, 200, 200));
2729
2730 sp<FakeWindowHandle> rightWindow =
2731 sp<FakeWindowHandle>::make(application, mDispatcher, "Right", ADISPLAY_ID_DEFAULT);
2732 rightWindow->setFrame(Rect(200, 0, 400, 200));
2733
2734 mDispatcher->onWindowInfosChanged(
2735 {{*spyWindow->getInfo(), *leftWindow->getInfo(), *rightWindow->getInfo()}, {}, 0, 0});
2736
2737 const int32_t stylusDeviceId = 1;
2738 const int32_t touchDeviceId = 2;
2739
2740 // Stylus hover on the left window
2741 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_ENTER, AINPUT_SOURCE_STYLUS)
2742 .deviceId(stylusDeviceId)
2743 .pointer(PointerBuilder(0, ToolType::STYLUS).x(100).y(100))
2744 .build());
2745 leftWindow->consumeMotionEvent(
2746 AllOf(WithMotionAction(ACTION_HOVER_ENTER), WithDeviceId(stylusDeviceId)));
2747 spyWindow->consumeMotionEvent(
2748 AllOf(WithMotionAction(ACTION_HOVER_ENTER), WithDeviceId(stylusDeviceId)));
2749
2750 // Touch down on the right window.
2751 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
2752 .deviceId(touchDeviceId)
2753 .pointer(PointerBuilder(0, ToolType::FINGER).x(300).y(100))
2754 .build());
2755 leftWindow->assertNoEvents();
2756 spyWindow->consumeMotionEvent(
2757 AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(touchDeviceId)));
2758 rightWindow->consumeMotionEvent(
2759 AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(touchDeviceId)));
2760
2761 // Stylus movements continue. They should be delivered to the left window and the spy.
2762 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_MOVE, AINPUT_SOURCE_STYLUS)
2763 .deviceId(stylusDeviceId)
2764 .pointer(PointerBuilder(0, ToolType::STYLUS).x(110).y(110))
2765 .build());
2766 leftWindow->consumeMotionEvent(
2767 AllOf(WithMotionAction(ACTION_HOVER_MOVE), WithDeviceId(stylusDeviceId)));
2768 spyWindow->consumeMotionEvent(
2769 AllOf(WithMotionAction(ACTION_HOVER_MOVE), WithDeviceId(stylusDeviceId)));
2770
2771 // Touch movements continue. They should be delivered to the right window and the spy
2772 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN)
2773 .deviceId(touchDeviceId)
2774 .pointer(PointerBuilder(0, ToolType::FINGER).x(301).y(101))
2775 .build());
2776 rightWindow->consumeMotionEvent(
2777 AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(touchDeviceId)));
2778 spyWindow->consumeMotionEvent(
2779 AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(touchDeviceId)));
2780
2781 spyWindow->assertNoEvents();
2782 leftWindow->assertNoEvents();
2783 rightWindow->assertNoEvents();
2784}
2785
2786/**
Siarhei Vishniakouf372b812023-02-14 18:06:51 -08002787 * On a single window, use two different devices: mouse and touch.
2788 * Touch happens first, with two pointers going down, and then the first pointer leaving.
2789 * Mouse is clicked next, which causes the touch stream to be aborted with ACTION_CANCEL.
2790 * Finally, a second touch pointer goes down again. Ensure the second touch pointer is ignored,
2791 * because the mouse is currently down, and a POINTER_DOWN event from the touchscreen does not
2792 * represent a new gesture.
2793 */
Siarhei Vishniakoued89cbb2023-10-13 10:42:44 -07002794TEST_F(InputDispatcherMultiDeviceTest, MixedTouchAndMouseWithPointerDown_legacy) {
2795 SCOPED_FLAG_OVERRIDE(enable_multi_device_same_window_stream, false);
Siarhei Vishniakouf372b812023-02-14 18:06:51 -08002796 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
2797 sp<FakeWindowHandle> window =
2798 sp<FakeWindowHandle>::make(application, mDispatcher, "Window", ADISPLAY_ID_DEFAULT);
2799 window->setFrame(Rect(0, 0, 400, 400));
2800
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07002801 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Siarhei Vishniakouf372b812023-02-14 18:06:51 -08002802
2803 const int32_t touchDeviceId = 4;
2804 const int32_t mouseDeviceId = 6;
Siarhei Vishniakouf372b812023-02-14 18:06:51 -08002805
Siarhei Vishniakou4e1ffa52023-02-21 11:50:34 -08002806 // First touch pointer down
Prabir Pradhan678438e2023-04-13 19:32:51 +00002807 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
2808 .deviceId(touchDeviceId)
2809 .pointer(PointerBuilder(0, ToolType::FINGER).x(300).y(100))
2810 .build());
Siarhei Vishniakouf372b812023-02-14 18:06:51 -08002811 // Second touch pointer down
Prabir Pradhan678438e2023-04-13 19:32:51 +00002812 mDispatcher->notifyMotion(MotionArgsBuilder(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
2813 .deviceId(touchDeviceId)
2814 .pointer(PointerBuilder(0, ToolType::FINGER).x(300).y(100))
2815 .pointer(PointerBuilder(1, ToolType::FINGER).x(350).y(100))
2816 .build());
Siarhei Vishniakouf372b812023-02-14 18:06:51 -08002817 // First touch pointer lifts. The second one remains down
Prabir Pradhan678438e2023-04-13 19:32:51 +00002818 mDispatcher->notifyMotion(MotionArgsBuilder(POINTER_0_UP, AINPUT_SOURCE_TOUCHSCREEN)
2819 .deviceId(touchDeviceId)
2820 .pointer(PointerBuilder(0, ToolType::FINGER).x(300).y(100))
2821 .pointer(PointerBuilder(1, ToolType::FINGER).x(350).y(100))
2822 .build());
Siarhei Vishniakouf372b812023-02-14 18:06:51 -08002823 window->consumeMotionEvent(WithMotionAction(ACTION_DOWN));
2824 window->consumeMotionEvent(WithMotionAction(POINTER_1_DOWN));
2825 window->consumeMotionEvent(WithMotionAction(POINTER_0_UP));
2826
2827 // Mouse down. The touch should be canceled
Prabir Pradhan678438e2023-04-13 19:32:51 +00002828 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_MOUSE)
2829 .deviceId(mouseDeviceId)
2830 .buttonState(AMOTION_EVENT_BUTTON_PRIMARY)
2831 .pointer(PointerBuilder(0, ToolType::MOUSE).x(320).y(100))
2832 .build());
Siarhei Vishniakouf372b812023-02-14 18:06:51 -08002833
2834 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_CANCEL), WithDeviceId(touchDeviceId),
Siarhei Vishniakou82dc0422023-02-17 23:12:52 -08002835 WithPointerCount(1u)));
Siarhei Vishniakouf372b812023-02-14 18:06:51 -08002836 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(mouseDeviceId)));
2837
Prabir Pradhan678438e2023-04-13 19:32:51 +00002838 mDispatcher->notifyMotion(
2839 MotionArgsBuilder(AMOTION_EVENT_ACTION_BUTTON_PRESS, AINPUT_SOURCE_MOUSE)
2840 .deviceId(mouseDeviceId)
2841 .buttonState(AMOTION_EVENT_BUTTON_PRIMARY)
2842 .actionButton(AMOTION_EVENT_BUTTON_PRIMARY)
2843 .pointer(PointerBuilder(0, ToolType::MOUSE).x(320).y(100))
2844 .build());
Siarhei Vishniakouf372b812023-02-14 18:06:51 -08002845 window->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_BUTTON_PRESS));
2846
2847 // Second touch pointer down.
Prabir Pradhan678438e2023-04-13 19:32:51 +00002848 mDispatcher->notifyMotion(MotionArgsBuilder(POINTER_0_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
2849 .deviceId(touchDeviceId)
2850 .pointer(PointerBuilder(0, ToolType::FINGER).x(300).y(100))
2851 .pointer(PointerBuilder(1, ToolType::FINGER).x(350).y(100))
2852 .build());
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -07002853 // Since we already canceled this touch gesture, it will be ignored until a completely new
2854 // gesture is started. This is easier to implement than trying to keep track of the new pointer
2855 // and generating an ACTION_DOWN instead of ACTION_POINTER_DOWN.
2856 // However, mouse movements should continue to work.
2857 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_MOUSE)
2858 .deviceId(mouseDeviceId)
2859 .buttonState(AMOTION_EVENT_BUTTON_PRIMARY)
2860 .pointer(PointerBuilder(0, ToolType::MOUSE).x(330).y(110))
2861 .build());
2862 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(mouseDeviceId)));
2863
Siarhei Vishniakouf372b812023-02-14 18:06:51 -08002864 window->assertNoEvents();
2865}
2866
2867/**
Siarhei Vishniakoued89cbb2023-10-13 10:42:44 -07002868 * On a single window, use two different devices: mouse and touch.
2869 * Touch happens first, with two pointers going down, and then the first pointer leaving.
2870 * Mouse is clicked next, which should not interfere with the touch stream.
2871 * Finally, a second touch pointer goes down again. Ensure the second touch pointer is also
2872 * delivered correctly.
2873 */
2874TEST_F(InputDispatcherMultiDeviceTest, MixedTouchAndMouseWithPointerDown) {
2875 SCOPED_FLAG_OVERRIDE(enable_multi_device_same_window_stream, true);
2876 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
2877 sp<FakeWindowHandle> window =
2878 sp<FakeWindowHandle>::make(application, mDispatcher, "Window", ADISPLAY_ID_DEFAULT);
2879 window->setFrame(Rect(0, 0, 400, 400));
2880
2881 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
2882
2883 const int32_t touchDeviceId = 4;
2884 const int32_t mouseDeviceId = 6;
2885
2886 // First touch pointer down
2887 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
2888 .deviceId(touchDeviceId)
2889 .pointer(PointerBuilder(0, ToolType::FINGER).x(300).y(100))
2890 .build());
2891 // Second touch pointer down
2892 mDispatcher->notifyMotion(MotionArgsBuilder(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
2893 .deviceId(touchDeviceId)
2894 .pointer(PointerBuilder(0, ToolType::FINGER).x(300).y(100))
2895 .pointer(PointerBuilder(1, ToolType::FINGER).x(350).y(100))
2896 .build());
2897 // First touch pointer lifts. The second one remains down
2898 mDispatcher->notifyMotion(MotionArgsBuilder(POINTER_0_UP, AINPUT_SOURCE_TOUCHSCREEN)
2899 .deviceId(touchDeviceId)
2900 .pointer(PointerBuilder(0, ToolType::FINGER).x(300).y(100))
2901 .pointer(PointerBuilder(1, ToolType::FINGER).x(350).y(100))
2902 .build());
2903 window->consumeMotionEvent(WithMotionAction(ACTION_DOWN));
2904 window->consumeMotionEvent(WithMotionAction(POINTER_1_DOWN));
2905 window->consumeMotionEvent(WithMotionAction(POINTER_0_UP));
2906
2907 // Mouse down
2908 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_MOUSE)
2909 .deviceId(mouseDeviceId)
2910 .buttonState(AMOTION_EVENT_BUTTON_PRIMARY)
2911 .pointer(PointerBuilder(0, ToolType::MOUSE).x(320).y(100))
2912 .build());
2913
2914 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(mouseDeviceId)));
2915
2916 mDispatcher->notifyMotion(
2917 MotionArgsBuilder(AMOTION_EVENT_ACTION_BUTTON_PRESS, AINPUT_SOURCE_MOUSE)
2918 .deviceId(mouseDeviceId)
2919 .buttonState(AMOTION_EVENT_BUTTON_PRIMARY)
2920 .actionButton(AMOTION_EVENT_BUTTON_PRIMARY)
2921 .pointer(PointerBuilder(0, ToolType::MOUSE).x(320).y(100))
2922 .build());
2923 window->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_BUTTON_PRESS));
2924
2925 // Second touch pointer down.
2926 mDispatcher->notifyMotion(MotionArgsBuilder(POINTER_0_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
2927 .deviceId(touchDeviceId)
2928 .pointer(PointerBuilder(0, ToolType::FINGER).x(300).y(100))
2929 .pointer(PointerBuilder(1, ToolType::FINGER).x(350).y(100))
2930 .build());
2931 window->consumeMotionEvent(AllOf(WithMotionAction(POINTER_0_DOWN), WithDeviceId(touchDeviceId),
2932 WithPointerCount(2u)));
2933
2934 // Mouse movements should continue to work
2935 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_MOUSE)
2936 .deviceId(mouseDeviceId)
2937 .buttonState(AMOTION_EVENT_BUTTON_PRIMARY)
2938 .pointer(PointerBuilder(0, ToolType::MOUSE).x(330).y(110))
2939 .build());
2940 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(mouseDeviceId)));
2941
2942 window->assertNoEvents();
2943}
2944
2945/**
Siarhei Vishniakou56e79092023-02-21 19:13:16 -08002946 * Inject a touch down and then send a new event via 'notifyMotion'. Ensure the new event cancels
2947 * the injected event.
2948 */
Siarhei Vishniakoued89cbb2023-10-13 10:42:44 -07002949TEST_F(InputDispatcherMultiDeviceTest, UnfinishedInjectedEvent_legacy) {
2950 SCOPED_FLAG_OVERRIDE(enable_multi_device_same_window_stream, false);
Siarhei Vishniakou56e79092023-02-21 19:13:16 -08002951 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
2952 sp<FakeWindowHandle> window =
2953 sp<FakeWindowHandle>::make(application, mDispatcher, "Window", ADISPLAY_ID_DEFAULT);
2954 window->setFrame(Rect(0, 0, 400, 400));
2955
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07002956 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Siarhei Vishniakou56e79092023-02-21 19:13:16 -08002957
2958 const int32_t touchDeviceId = 4;
Siarhei Vishniakou56e79092023-02-21 19:13:16 -08002959 // Pretend a test injects an ACTION_DOWN mouse event, but forgets to lift up the touch after
2960 // completion.
2961 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07002962 injectMotionEvent(*mDispatcher,
Siarhei Vishniakou56e79092023-02-21 19:13:16 -08002963 MotionEventBuilder(ACTION_DOWN, AINPUT_SOURCE_MOUSE)
2964 .deviceId(ReservedInputDeviceId::VIRTUAL_KEYBOARD_ID)
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07002965 .pointer(PointerBuilder(0, ToolType::MOUSE).x(50).y(50))
Siarhei Vishniakou56e79092023-02-21 19:13:16 -08002966 .build()));
2967 window->consumeMotionEvent(
2968 AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(VIRTUAL_KEYBOARD_ID)));
2969
2970 // Now a real touch comes. Rather than crashing or dropping the real event, the injected pointer
2971 // should be canceled and the new gesture should take over.
Prabir Pradhan678438e2023-04-13 19:32:51 +00002972 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
2973 .deviceId(touchDeviceId)
2974 .pointer(PointerBuilder(0, ToolType::FINGER).x(300).y(100))
2975 .build());
Siarhei Vishniakou56e79092023-02-21 19:13:16 -08002976
2977 window->consumeMotionEvent(
2978 AllOf(WithMotionAction(ACTION_CANCEL), WithDeviceId(VIRTUAL_KEYBOARD_ID)));
2979 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(touchDeviceId)));
2980}
2981
2982/**
Siarhei Vishniakoued89cbb2023-10-13 10:42:44 -07002983 * Inject a touch down and then send a new event via 'notifyMotion'. Ensure the new event runs
2984 * parallel to the injected event.
2985 */
2986TEST_F(InputDispatcherMultiDeviceTest, UnfinishedInjectedEvent) {
2987 SCOPED_FLAG_OVERRIDE(enable_multi_device_same_window_stream, true);
2988 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
2989 sp<FakeWindowHandle> window =
2990 sp<FakeWindowHandle>::make(application, mDispatcher, "Window", ADISPLAY_ID_DEFAULT);
2991 window->setFrame(Rect(0, 0, 400, 400));
2992
2993 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
2994
2995 const int32_t touchDeviceId = 4;
2996 // Pretend a test injects an ACTION_DOWN mouse event, but forgets to lift up the touch after
2997 // completion.
2998 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
2999 injectMotionEvent(*mDispatcher,
3000 MotionEventBuilder(ACTION_DOWN, AINPUT_SOURCE_MOUSE)
3001 .deviceId(ReservedInputDeviceId::VIRTUAL_KEYBOARD_ID)
3002 .pointer(PointerBuilder(0, ToolType::MOUSE).x(50).y(50))
3003 .build()));
3004 window->consumeMotionEvent(
3005 AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(VIRTUAL_KEYBOARD_ID)));
3006
3007 // Now a real touch comes. The injected pointer will remain, and the new gesture will also be
3008 // allowed through.
3009 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
3010 .deviceId(touchDeviceId)
3011 .pointer(PointerBuilder(0, ToolType::FINGER).x(300).y(100))
3012 .build());
3013 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(touchDeviceId)));
3014}
3015
3016/**
Siarhei Vishniakou6464e462023-02-06 18:57:59 -08003017 * This test is similar to the test above, but the sequence of injected events is different.
3018 *
3019 * Two windows: a window on the left and a window on the right.
3020 * Mouse is hovered over the left window.
3021 * Next, we tap on the left window, where the cursor was last seen.
3022 *
3023 * After that, we inject one finger down onto the right window, and then a second finger down onto
3024 * the left window.
3025 * The touch is split, so this last gesture should cause 2 ACTION_DOWN events, one in the right
3026 * window (first), and then another on the left window (second).
3027 * This test reproduces a crash where there is a mismatch between the downTime and eventTime.
3028 * In the buggy implementation, second finger down on the left window would cause a crash.
3029 */
Siarhei Vishniakoued89cbb2023-10-13 10:42:44 -07003030TEST_F(InputDispatcherMultiDeviceTest, HoverTapAndSplitTouch_legacy) {
3031 SCOPED_FLAG_OVERRIDE(enable_multi_device_same_window_stream, false);
Siarhei Vishniakou6464e462023-02-06 18:57:59 -08003032 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
3033 sp<FakeWindowHandle> leftWindow =
3034 sp<FakeWindowHandle>::make(application, mDispatcher, "Left", ADISPLAY_ID_DEFAULT);
3035 leftWindow->setFrame(Rect(0, 0, 200, 200));
3036
3037 sp<FakeWindowHandle> rightWindow =
3038 sp<FakeWindowHandle>::make(application, mDispatcher, "Right", ADISPLAY_ID_DEFAULT);
3039 rightWindow->setFrame(Rect(200, 0, 400, 200));
3040
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07003041 mDispatcher->onWindowInfosChanged(
3042 {{*leftWindow->getInfo(), *rightWindow->getInfo()}, {}, 0, 0});
Siarhei Vishniakou6464e462023-02-06 18:57:59 -08003043
3044 const int32_t mouseDeviceId = 6;
3045 const int32_t touchDeviceId = 4;
3046 // Hover over the left window. Keep the cursor there.
3047 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07003048 injectMotionEvent(*mDispatcher,
Siarhei Vishniakou6464e462023-02-06 18:57:59 -08003049 MotionEventBuilder(AMOTION_EVENT_ACTION_HOVER_ENTER,
3050 AINPUT_SOURCE_MOUSE)
3051 .deviceId(mouseDeviceId)
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07003052 .pointer(PointerBuilder(0, ToolType::MOUSE).x(50).y(50))
Siarhei Vishniakou6464e462023-02-06 18:57:59 -08003053 .build()));
3054 leftWindow->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_ENTER));
3055
3056 // Tap on left window
3057 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07003058 injectMotionEvent(*mDispatcher,
Siarhei Vishniakou6464e462023-02-06 18:57:59 -08003059 MotionEventBuilder(AMOTION_EVENT_ACTION_DOWN,
3060 AINPUT_SOURCE_TOUCHSCREEN)
3061 .deviceId(touchDeviceId)
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07003062 .pointer(PointerBuilder(0, ToolType::FINGER).x(100).y(100))
Siarhei Vishniakou6464e462023-02-06 18:57:59 -08003063 .build()));
3064
3065 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07003066 injectMotionEvent(*mDispatcher,
Siarhei Vishniakou6464e462023-02-06 18:57:59 -08003067 MotionEventBuilder(AMOTION_EVENT_ACTION_UP,
3068 AINPUT_SOURCE_TOUCHSCREEN)
3069 .deviceId(touchDeviceId)
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07003070 .pointer(PointerBuilder(0, ToolType::FINGER).x(100).y(100))
Siarhei Vishniakou6464e462023-02-06 18:57:59 -08003071 .build()));
3072 leftWindow->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_EXIT));
3073 leftWindow->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_DOWN));
3074 leftWindow->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_UP));
3075
3076 // First finger down on right window
3077 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07003078 injectMotionEvent(*mDispatcher,
Siarhei Vishniakou6464e462023-02-06 18:57:59 -08003079 MotionEventBuilder(AMOTION_EVENT_ACTION_DOWN,
3080 AINPUT_SOURCE_TOUCHSCREEN)
3081 .deviceId(touchDeviceId)
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07003082 .pointer(PointerBuilder(0, ToolType::FINGER).x(300).y(100))
Siarhei Vishniakou6464e462023-02-06 18:57:59 -08003083 .build()));
3084 rightWindow->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_DOWN));
3085
3086 // Second finger down on the left window
3087 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07003088 injectMotionEvent(*mDispatcher,
Siarhei Vishniakou6464e462023-02-06 18:57:59 -08003089 MotionEventBuilder(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
3090 .deviceId(touchDeviceId)
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07003091 .pointer(PointerBuilder(0, ToolType::FINGER).x(300).y(100))
3092 .pointer(PointerBuilder(1, ToolType::FINGER).x(100).y(100))
Siarhei Vishniakou6464e462023-02-06 18:57:59 -08003093 .build()));
3094 leftWindow->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_DOWN));
3095 rightWindow->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_MOVE));
3096
3097 // No more events
3098 leftWindow->assertNoEvents();
3099 rightWindow->assertNoEvents();
3100}
3101
3102/**
Siarhei Vishniakoued89cbb2023-10-13 10:42:44 -07003103 * This test is similar to the test above, but the sequence of injected events is different.
3104 *
3105 * Two windows: a window on the left and a window on the right.
3106 * Mouse is hovered over the left window.
3107 * Next, we tap on the left window, where the cursor was last seen.
3108 *
3109 * After that, we send one finger down onto the right window, and then a second finger down onto
3110 * the left window.
3111 * The touch is split, so this last gesture should cause 2 ACTION_DOWN events, one in the right
3112 * window (first), and then another on the left window (second).
3113 * This test reproduces a crash where there is a mismatch between the downTime and eventTime.
3114 * In the buggy implementation, second finger down on the left window would cause a crash.
3115 */
3116TEST_F(InputDispatcherMultiDeviceTest, HoverTapAndSplitTouch) {
3117 SCOPED_FLAG_OVERRIDE(enable_multi_device_same_window_stream, true);
3118 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
3119 sp<FakeWindowHandle> leftWindow =
3120 sp<FakeWindowHandle>::make(application, mDispatcher, "Left", ADISPLAY_ID_DEFAULT);
3121 leftWindow->setFrame(Rect(0, 0, 200, 200));
3122
3123 sp<FakeWindowHandle> rightWindow =
3124 sp<FakeWindowHandle>::make(application, mDispatcher, "Right", ADISPLAY_ID_DEFAULT);
3125 rightWindow->setFrame(Rect(200, 0, 400, 200));
3126
3127 mDispatcher->onWindowInfosChanged(
3128 {{*leftWindow->getInfo(), *rightWindow->getInfo()}, {}, 0, 0});
3129
3130 const int32_t mouseDeviceId = 6;
3131 const int32_t touchDeviceId = 4;
3132 // Hover over the left window. Keep the cursor there.
3133 mDispatcher->notifyMotion(
3134 MotionArgsBuilder(AMOTION_EVENT_ACTION_HOVER_ENTER, AINPUT_SOURCE_MOUSE)
3135 .deviceId(mouseDeviceId)
3136 .pointer(PointerBuilder(0, ToolType::MOUSE).x(50).y(50))
3137 .build());
3138 leftWindow->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_ENTER));
3139
3140 // Tap on left window
3141 mDispatcher->notifyMotion(
3142 MotionArgsBuilder(AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
3143 .deviceId(touchDeviceId)
3144 .pointer(PointerBuilder(0, ToolType::FINGER).x(100).y(100))
3145 .build());
3146
3147 mDispatcher->notifyMotion(MotionArgsBuilder(AMOTION_EVENT_ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN)
3148 .deviceId(touchDeviceId)
3149 .pointer(PointerBuilder(0, ToolType::FINGER).x(100).y(100))
3150 .build());
3151 leftWindow->consumeMotionEvent(
3152 AllOf(WithMotionAction(AMOTION_EVENT_ACTION_DOWN), WithDeviceId(touchDeviceId)));
3153 leftWindow->consumeMotionEvent(
3154 AllOf(WithMotionAction(AMOTION_EVENT_ACTION_UP), WithDeviceId(touchDeviceId)));
3155
3156 // First finger down on right window
3157 mDispatcher->notifyMotion(
3158 MotionArgsBuilder(AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
3159 .deviceId(touchDeviceId)
3160 .pointer(PointerBuilder(0, ToolType::FINGER).x(300).y(100))
3161 .build());
3162 rightWindow->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_DOWN));
3163
3164 // Second finger down on the left window
3165 mDispatcher->notifyMotion(MotionArgsBuilder(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
3166 .deviceId(touchDeviceId)
3167 .pointer(PointerBuilder(0, ToolType::FINGER).x(300).y(100))
3168 .pointer(PointerBuilder(1, ToolType::FINGER).x(100).y(100))
3169 .build());
3170 leftWindow->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_DOWN));
3171 rightWindow->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_MOVE));
3172
3173 // No more events
3174 leftWindow->assertNoEvents();
3175 rightWindow->assertNoEvents();
3176}
3177
3178/**
Siarhei Vishniakou2e3e4432023-02-09 18:34:11 -08003179 * Start hovering with a stylus device, and then tap with a touch device. Ensure no crash occurs.
3180 * While the touch is down, new hover events from the stylus device should be ignored. After the
3181 * touch is gone, stylus hovering should start working again.
3182 */
Siarhei Vishniakou3ad54f52023-11-02 16:54:40 -07003183TEST_F(InputDispatcherMultiDeviceTest, StylusHoverIgnoresTouchTap) {
Siarhei Vishniakoued89cbb2023-10-13 10:42:44 -07003184 SCOPED_FLAG_OVERRIDE(enable_multi_device_same_window_stream, false);
Siarhei Vishniakou2e3e4432023-02-09 18:34:11 -08003185 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
3186 sp<FakeWindowHandle> window =
3187 sp<FakeWindowHandle>::make(application, mDispatcher, "Window", ADISPLAY_ID_DEFAULT);
3188 window->setFrame(Rect(0, 0, 200, 200));
3189
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07003190 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Siarhei Vishniakou2e3e4432023-02-09 18:34:11 -08003191
3192 const int32_t stylusDeviceId = 5;
3193 const int32_t touchDeviceId = 4;
3194 // Start hovering with stylus
3195 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07003196 injectMotionEvent(*mDispatcher,
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -07003197 MotionEventBuilder(ACTION_HOVER_ENTER, AINPUT_SOURCE_STYLUS)
Siarhei Vishniakou2e3e4432023-02-09 18:34:11 -08003198 .deviceId(stylusDeviceId)
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07003199 .pointer(PointerBuilder(0, ToolType::STYLUS).x(50).y(50))
Siarhei Vishniakou2e3e4432023-02-09 18:34:11 -08003200 .build()));
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -07003201 window->consumeMotionEvent(WithMotionAction(ACTION_HOVER_ENTER));
Siarhei Vishniakou2e3e4432023-02-09 18:34:11 -08003202
3203 // Finger down on the window
3204 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07003205 injectMotionEvent(*mDispatcher,
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -07003206 MotionEventBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
Siarhei Vishniakou2e3e4432023-02-09 18:34:11 -08003207 .deviceId(touchDeviceId)
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07003208 .pointer(PointerBuilder(0, ToolType::FINGER).x(100).y(100))
Siarhei Vishniakou2e3e4432023-02-09 18:34:11 -08003209 .build()));
Siarhei Vishniakou3ad54f52023-11-02 16:54:40 -07003210 // The touch device should be ignored!
Siarhei Vishniakou2e3e4432023-02-09 18:34:11 -08003211
Siarhei Vishniakou2899c552023-07-10 18:20:46 -07003212 // Continue hovering with stylus.
3213 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07003214 injectMotionEvent(*mDispatcher,
Siarhei Vishniakou2e3e4432023-02-09 18:34:11 -08003215 MotionEventBuilder(AMOTION_EVENT_ACTION_HOVER_MOVE,
3216 AINPUT_SOURCE_STYLUS)
3217 .deviceId(stylusDeviceId)
Siarhei Vishniakou25537f82023-07-18 14:35:47 -07003218 .pointer(PointerBuilder(0, ToolType::STYLUS).x(60).y(60))
Siarhei Vishniakou2e3e4432023-02-09 18:34:11 -08003219 .build()));
Siarhei Vishniakou3ad54f52023-11-02 16:54:40 -07003220 // Hovers continue to work
3221 window->consumeMotionEvent(
3222 AllOf(WithMotionAction(ACTION_HOVER_MOVE), WithDeviceId(stylusDeviceId)));
Siarhei Vishniakou2e3e4432023-02-09 18:34:11 -08003223
3224 // Lift up the finger
3225 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07003226 injectMotionEvent(*mDispatcher,
Siarhei Vishniakou2e3e4432023-02-09 18:34:11 -08003227 MotionEventBuilder(AMOTION_EVENT_ACTION_UP,
3228 AINPUT_SOURCE_TOUCHSCREEN)
3229 .deviceId(touchDeviceId)
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07003230 .pointer(PointerBuilder(0, ToolType::FINGER).x(100).y(100))
Siarhei Vishniakou2e3e4432023-02-09 18:34:11 -08003231 .build()));
Siarhei Vishniakou2e3e4432023-02-09 18:34:11 -08003232
Siarhei Vishniakou2e3e4432023-02-09 18:34:11 -08003233 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07003234 injectMotionEvent(*mDispatcher,
Siarhei Vishniakou2e3e4432023-02-09 18:34:11 -08003235 MotionEventBuilder(AMOTION_EVENT_ACTION_HOVER_MOVE,
3236 AINPUT_SOURCE_STYLUS)
3237 .deviceId(stylusDeviceId)
Siarhei Vishniakou25537f82023-07-18 14:35:47 -07003238 .pointer(PointerBuilder(0, ToolType::STYLUS).x(70).y(70))
Siarhei Vishniakou2e3e4432023-02-09 18:34:11 -08003239 .build()));
Siarhei Vishniakou3ad54f52023-11-02 16:54:40 -07003240 window->consumeMotionEvent(
3241 AllOf(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_MOVE), WithDeviceId(stylusDeviceId)));
Siarhei Vishniakou2e3e4432023-02-09 18:34:11 -08003242 window->assertNoEvents();
3243}
3244
3245/**
Siarhei Vishniakoued89cbb2023-10-13 10:42:44 -07003246 * Start hovering with a stylus device, and then tap with a touch device. Ensure no crash occurs.
3247 * While the touch is down, hovering from the stylus is not affected. After the touch is gone,
3248 * check that the stylus hovering continues to work.
3249 */
3250TEST_F(InputDispatcherMultiDeviceTest, StylusHoverWithTouchTap) {
3251 SCOPED_FLAG_OVERRIDE(enable_multi_device_same_window_stream, true);
3252 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
3253 sp<FakeWindowHandle> window =
3254 sp<FakeWindowHandle>::make(application, mDispatcher, "Window", ADISPLAY_ID_DEFAULT);
3255 window->setFrame(Rect(0, 0, 200, 200));
3256
3257 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
3258
3259 const int32_t stylusDeviceId = 5;
3260 const int32_t touchDeviceId = 4;
3261 // Start hovering with stylus
3262 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_ENTER, AINPUT_SOURCE_STYLUS)
3263 .deviceId(stylusDeviceId)
3264 .pointer(PointerBuilder(0, ToolType::STYLUS).x(50).y(50))
3265 .build());
3266 window->consumeMotionEvent(WithMotionAction(ACTION_HOVER_ENTER));
3267
3268 // Finger down on the window
3269 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
3270 .deviceId(touchDeviceId)
3271 .pointer(PointerBuilder(0, ToolType::FINGER).x(100).y(100))
3272 .build());
3273 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(touchDeviceId)));
3274
3275 // Continue hovering with stylus.
3276 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_MOVE, AINPUT_SOURCE_STYLUS)
3277 .deviceId(stylusDeviceId)
3278 .pointer(PointerBuilder(0, ToolType::STYLUS).x(60).y(60))
3279 .build());
3280 // Hovers continue to work
3281 window->consumeMotionEvent(
3282 AllOf(WithMotionAction(ACTION_HOVER_MOVE), WithDeviceId(stylusDeviceId)));
3283
3284 // Lift up the finger
3285 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN)
3286 .deviceId(touchDeviceId)
3287 .pointer(PointerBuilder(0, ToolType::FINGER).x(100).y(100))
3288 .build());
3289 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_UP), WithDeviceId(touchDeviceId)));
3290
3291 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_MOVE, AINPUT_SOURCE_STYLUS)
3292 .deviceId(stylusDeviceId)
3293 .pointer(PointerBuilder(0, ToolType::STYLUS).x(70).y(70))
3294 .build());
3295 window->consumeMotionEvent(
3296 AllOf(WithMotionAction(ACTION_HOVER_MOVE), WithDeviceId(stylusDeviceId)));
3297 window->assertNoEvents();
3298}
3299
3300/**
Siarhei Vishniakouf77f60a2023-10-23 17:26:05 -07003301 * If stylus is down anywhere on the screen, then touches should not be delivered to windows that
3302 * have InputConfig::GLOBAL_STYLUS_BLOCKS_TOUCH.
3303 *
3304 * Two windows: one on the left and one on the right.
3305 * The window on the right has GLOBAL_STYLUS_BLOCKS_TOUCH config.
3306 * Stylus down on the left window, and then touch down on the right window.
3307 * Check that the right window doesn't get touches while the stylus is down on the left window.
3308 */
3309TEST_F(InputDispatcherMultiDeviceTest, GlobalStylusDownBlocksTouch) {
3310 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
3311 sp<FakeWindowHandle> leftWindow =
3312 sp<FakeWindowHandle>::make(application, mDispatcher, "Left window",
3313 ADISPLAY_ID_DEFAULT);
3314 leftWindow->setFrame(Rect(0, 0, 100, 100));
3315
3316 sp<FakeWindowHandle> sbtRightWindow =
3317 sp<FakeWindowHandle>::make(application, mDispatcher,
3318 "Stylus blocks touch (right) window", ADISPLAY_ID_DEFAULT);
3319 sbtRightWindow->setFrame(Rect(100, 100, 200, 200));
3320 sbtRightWindow->setGlobalStylusBlocksTouch(true);
3321
3322 mDispatcher->onWindowInfosChanged(
3323 {{*leftWindow->getInfo(), *sbtRightWindow->getInfo()}, {}, 0, 0});
3324
3325 const int32_t stylusDeviceId = 5;
3326 const int32_t touchDeviceId = 4;
3327
3328 // Stylus down in the left window
3329 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_STYLUS)
3330 .pointer(PointerBuilder(0, ToolType::STYLUS).x(50).y(52))
3331 .deviceId(stylusDeviceId)
3332 .build());
3333 leftWindow->consumeMotionEvent(
3334 AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(stylusDeviceId)));
3335
3336 // Finger tap on the right window
3337 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
3338 .pointer(PointerBuilder(0, ToolType::FINGER).x(150).y(151))
3339 .deviceId(touchDeviceId)
3340 .build());
3341 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN)
3342 .pointer(PointerBuilder(0, ToolType::FINGER).x(150).y(151))
3343 .deviceId(touchDeviceId)
3344 .build());
3345
3346 // The touch should be blocked, because stylus is down somewhere else on screen!
3347 sbtRightWindow->assertNoEvents();
3348
3349 // Continue stylus motion, and ensure it's not impacted.
3350 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_STYLUS)
3351 .pointer(PointerBuilder(0, ToolType::STYLUS).x(51).y(53))
3352 .deviceId(stylusDeviceId)
3353 .build());
3354 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_UP, AINPUT_SOURCE_STYLUS)
3355 .pointer(PointerBuilder(0, ToolType::STYLUS).x(51).y(53))
3356 .deviceId(stylusDeviceId)
3357 .build());
3358 leftWindow->consumeMotionEvent(
3359 AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(stylusDeviceId)));
3360 leftWindow->consumeMotionEvent(
3361 AllOf(WithMotionAction(ACTION_UP), WithDeviceId(stylusDeviceId)));
3362
3363 // Now that the stylus gesture is done, touches should be getting delivered correctly.
3364 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
3365 .pointer(PointerBuilder(0, ToolType::FINGER).x(151).y(153))
3366 .deviceId(touchDeviceId)
3367 .build());
3368 sbtRightWindow->consumeMotionEvent(
3369 AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(touchDeviceId)));
3370}
3371
3372/**
3373 * If stylus is hovering anywhere on the screen, then touches should not be delivered to windows
3374 * that have InputConfig::GLOBAL_STYLUS_BLOCKS_TOUCH.
3375 *
3376 * Two windows: one on the left and one on the right.
3377 * The window on the right has GLOBAL_STYLUS_BLOCKS_TOUCH config.
3378 * Stylus hover on the left window, and then touch down on the right window.
3379 * Check that the right window doesn't get touches while the stylus is hovering on the left window.
3380 */
3381TEST_F(InputDispatcherMultiDeviceTest, GlobalStylusHoverBlocksTouch) {
3382 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
3383 sp<FakeWindowHandle> leftWindow =
3384 sp<FakeWindowHandle>::make(application, mDispatcher, "Left window",
3385 ADISPLAY_ID_DEFAULT);
3386 leftWindow->setFrame(Rect(0, 0, 100, 100));
3387
3388 sp<FakeWindowHandle> sbtRightWindow =
3389 sp<FakeWindowHandle>::make(application, mDispatcher,
3390 "Stylus blocks touch (right) window", ADISPLAY_ID_DEFAULT);
3391 sbtRightWindow->setFrame(Rect(100, 100, 200, 200));
3392 sbtRightWindow->setGlobalStylusBlocksTouch(true);
3393
3394 mDispatcher->onWindowInfosChanged(
3395 {{*leftWindow->getInfo(), *sbtRightWindow->getInfo()}, {}, 0, 0});
3396
3397 const int32_t stylusDeviceId = 5;
3398 const int32_t touchDeviceId = 4;
3399
3400 // Stylus hover in the left window
3401 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_ENTER, AINPUT_SOURCE_STYLUS)
3402 .pointer(PointerBuilder(0, ToolType::STYLUS).x(50).y(52))
3403 .deviceId(stylusDeviceId)
3404 .build());
3405 leftWindow->consumeMotionEvent(
3406 AllOf(WithMotionAction(ACTION_HOVER_ENTER), WithDeviceId(stylusDeviceId)));
3407
3408 // Finger tap on the right window
3409 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
3410 .pointer(PointerBuilder(0, ToolType::FINGER).x(150).y(151))
3411 .deviceId(touchDeviceId)
3412 .build());
3413 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN)
3414 .pointer(PointerBuilder(0, ToolType::FINGER).x(150).y(151))
3415 .deviceId(touchDeviceId)
3416 .build());
3417
3418 // The touch should be blocked, because stylus is hovering somewhere else on screen!
3419 sbtRightWindow->assertNoEvents();
3420
3421 // Continue stylus motion, and ensure it's not impacted.
3422 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_MOVE, AINPUT_SOURCE_STYLUS)
3423 .pointer(PointerBuilder(0, ToolType::STYLUS).x(51).y(53))
3424 .deviceId(stylusDeviceId)
3425 .build());
3426 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_EXIT, AINPUT_SOURCE_STYLUS)
3427 .pointer(PointerBuilder(0, ToolType::STYLUS).x(51).y(53))
3428 .deviceId(stylusDeviceId)
3429 .build());
3430 leftWindow->consumeMotionEvent(
3431 AllOf(WithMotionAction(ACTION_HOVER_MOVE), WithDeviceId(stylusDeviceId)));
3432 leftWindow->consumeMotionEvent(
3433 AllOf(WithMotionAction(ACTION_HOVER_EXIT), WithDeviceId(stylusDeviceId)));
3434
3435 // Now that the stylus gesture is done, touches should be getting delivered correctly.
3436 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
3437 .pointer(PointerBuilder(0, ToolType::FINGER).x(151).y(153))
3438 .deviceId(touchDeviceId)
3439 .build());
3440 sbtRightWindow->consumeMotionEvent(
3441 AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(touchDeviceId)));
3442}
3443
3444/**
Siarhei Vishniakouf372b812023-02-14 18:06:51 -08003445 * A spy window above a window with no input channel.
3446 * Start hovering with a stylus device, and then tap with it.
3447 * Ensure spy window receives the entire sequence.
3448 */
3449TEST_F(InputDispatcherTest, StylusHoverAndDownNoInputChannel) {
3450 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
3451 sp<FakeWindowHandle> spyWindow =
3452 sp<FakeWindowHandle>::make(application, mDispatcher, "Spy", ADISPLAY_ID_DEFAULT);
3453 spyWindow->setFrame(Rect(0, 0, 200, 200));
3454 spyWindow->setTrustedOverlay(true);
3455 spyWindow->setSpy(true);
3456 sp<FakeWindowHandle> window =
3457 sp<FakeWindowHandle>::make(application, mDispatcher, "Window", ADISPLAY_ID_DEFAULT);
3458 window->setNoInputChannel(true);
3459 window->setFrame(Rect(0, 0, 200, 200));
3460
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07003461 mDispatcher->onWindowInfosChanged({{*spyWindow->getInfo(), *window->getInfo()}, {}, 0, 0});
Siarhei Vishniakouf372b812023-02-14 18:06:51 -08003462
Siarhei Vishniakouf372b812023-02-14 18:06:51 -08003463 // Start hovering with stylus
Prabir Pradhan678438e2023-04-13 19:32:51 +00003464 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_ENTER, AINPUT_SOURCE_STYLUS)
3465 .pointer(PointerBuilder(0, ToolType::STYLUS).x(50).y(50))
3466 .build());
Siarhei Vishniakouf372b812023-02-14 18:06:51 -08003467 spyWindow->consumeMotionEvent(WithMotionAction(ACTION_HOVER_ENTER));
3468 // Stop hovering
Prabir Pradhan678438e2023-04-13 19:32:51 +00003469 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_EXIT, AINPUT_SOURCE_STYLUS)
3470 .pointer(PointerBuilder(0, ToolType::STYLUS).x(50).y(50))
3471 .build());
Siarhei Vishniakouf372b812023-02-14 18:06:51 -08003472 spyWindow->consumeMotionEvent(WithMotionAction(ACTION_HOVER_EXIT));
3473
3474 // Stylus touches down
Prabir Pradhan678438e2023-04-13 19:32:51 +00003475 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_STYLUS)
3476 .pointer(PointerBuilder(0, ToolType::STYLUS).x(50).y(50))
3477 .build());
Siarhei Vishniakouf372b812023-02-14 18:06:51 -08003478 spyWindow->consumeMotionEvent(WithMotionAction(ACTION_DOWN));
3479
3480 // Stylus goes up
Prabir Pradhan678438e2023-04-13 19:32:51 +00003481 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_UP, AINPUT_SOURCE_STYLUS)
3482 .pointer(PointerBuilder(0, ToolType::STYLUS).x(50).y(50))
3483 .build());
Siarhei Vishniakouf372b812023-02-14 18:06:51 -08003484 spyWindow->consumeMotionEvent(WithMotionAction(ACTION_UP));
3485
3486 // Again hover
Prabir Pradhan678438e2023-04-13 19:32:51 +00003487 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_ENTER, AINPUT_SOURCE_STYLUS)
3488 .pointer(PointerBuilder(0, ToolType::STYLUS).x(50).y(50))
3489 .build());
Siarhei Vishniakouf372b812023-02-14 18:06:51 -08003490 spyWindow->consumeMotionEvent(WithMotionAction(ACTION_HOVER_ENTER));
3491 // Stop hovering
Prabir Pradhan678438e2023-04-13 19:32:51 +00003492 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_EXIT, AINPUT_SOURCE_STYLUS)
3493 .pointer(PointerBuilder(0, ToolType::STYLUS).x(50).y(50))
3494 .build());
Siarhei Vishniakouf372b812023-02-14 18:06:51 -08003495 spyWindow->consumeMotionEvent(WithMotionAction(ACTION_HOVER_EXIT));
3496
3497 // No more events
3498 spyWindow->assertNoEvents();
3499 window->assertNoEvents();
3500}
3501
3502/**
Siarhei Vishniakou6b71b632023-10-27 21:34:46 -07003503 * A stale stylus HOVER_EXIT event is injected. Since it's a stale event, it should generally be
3504 * rejected. But since we already have an ongoing gesture, this event should be processed.
3505 * This prevents inconsistent events being handled inside the dispatcher.
3506 */
3507TEST_F(InputDispatcherTest, StaleStylusHoverGestureIsComplete) {
3508 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
3509
3510 sp<FakeWindowHandle> window =
3511 sp<FakeWindowHandle>::make(application, mDispatcher, "Window", ADISPLAY_ID_DEFAULT);
3512 window->setFrame(Rect(0, 0, 200, 200));
3513
3514 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
3515
3516 // Start hovering with stylus
3517 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_ENTER, AINPUT_SOURCE_STYLUS)
3518 .pointer(PointerBuilder(0, ToolType::STYLUS).x(50).y(50))
3519 .build());
3520 window->consumeMotionEvent(WithMotionAction(ACTION_HOVER_ENTER));
3521
3522 NotifyMotionArgs hoverExit = MotionArgsBuilder(ACTION_HOVER_EXIT, AINPUT_SOURCE_STYLUS)
3523 .pointer(PointerBuilder(0, ToolType::STYLUS).x(50).y(50))
3524 .build();
3525 // Make this 'hoverExit' event stale
3526 mFakePolicy->setStaleEventTimeout(100ms);
3527 std::this_thread::sleep_for(100ms);
3528
3529 // It shouldn't be dropped by the dispatcher, even though it's stale.
3530 mDispatcher->notifyMotion(hoverExit);
3531 window->consumeMotionEvent(WithMotionAction(ACTION_HOVER_EXIT));
3532
3533 // Stylus starts hovering again! There should be no crash.
3534 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_ENTER, AINPUT_SOURCE_STYLUS)
3535 .pointer(PointerBuilder(0, ToolType::STYLUS).x(51).y(51))
3536 .build());
3537 window->consumeMotionEvent(WithMotionAction(ACTION_HOVER_ENTER));
3538}
3539
3540/**
Siarhei Vishniakouf372b812023-02-14 18:06:51 -08003541 * Start hovering with a mouse, and then tap with a touch device. Pilfer the touch stream.
3542 * Next, click with the mouse device. Both windows (spy and regular) should receive the new mouse
3543 * ACTION_DOWN event because that's a new gesture, and pilfering should no longer be active.
3544 * While the mouse is down, new move events from the touch device should be ignored.
3545 */
Siarhei Vishniakoued89cbb2023-10-13 10:42:44 -07003546TEST_F(InputDispatcherTest, TouchPilferAndMouseMove_legacy) {
3547 SCOPED_FLAG_OVERRIDE(enable_multi_device_same_window_stream, false);
Siarhei Vishniakouf372b812023-02-14 18:06:51 -08003548 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
3549 sp<FakeWindowHandle> spyWindow =
3550 sp<FakeWindowHandle>::make(application, mDispatcher, "Spy", ADISPLAY_ID_DEFAULT);
3551 spyWindow->setFrame(Rect(0, 0, 200, 200));
3552 spyWindow->setTrustedOverlay(true);
3553 spyWindow->setSpy(true);
3554 sp<FakeWindowHandle> window =
3555 sp<FakeWindowHandle>::make(application, mDispatcher, "Window", ADISPLAY_ID_DEFAULT);
3556 window->setFrame(Rect(0, 0, 200, 200));
3557
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07003558 mDispatcher->onWindowInfosChanged({{*spyWindow->getInfo(), *window->getInfo()}, {}, 0, 0});
Siarhei Vishniakouf372b812023-02-14 18:06:51 -08003559
3560 const int32_t mouseDeviceId = 7;
3561 const int32_t touchDeviceId = 4;
Siarhei Vishniakouf372b812023-02-14 18:06:51 -08003562
3563 // Hover a bit with mouse first
Prabir Pradhan678438e2023-04-13 19:32:51 +00003564 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_ENTER, AINPUT_SOURCE_MOUSE)
3565 .deviceId(mouseDeviceId)
3566 .pointer(PointerBuilder(0, ToolType::MOUSE).x(100).y(100))
3567 .build());
Siarhei Vishniakouf372b812023-02-14 18:06:51 -08003568 spyWindow->consumeMotionEvent(
3569 AllOf(WithMotionAction(ACTION_HOVER_ENTER), WithDeviceId(mouseDeviceId)));
3570 window->consumeMotionEvent(
3571 AllOf(WithMotionAction(ACTION_HOVER_ENTER), WithDeviceId(mouseDeviceId)));
3572
3573 // Start touching
Prabir Pradhan678438e2023-04-13 19:32:51 +00003574 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
3575 .deviceId(touchDeviceId)
3576 .pointer(PointerBuilder(0, ToolType::FINGER).x(50).y(50))
3577 .build());
Siarhei Vishniakouf372b812023-02-14 18:06:51 -08003578 spyWindow->consumeMotionEvent(WithMotionAction(ACTION_HOVER_EXIT));
3579 window->consumeMotionEvent(WithMotionAction(ACTION_HOVER_EXIT));
3580 spyWindow->consumeMotionEvent(WithMotionAction(ACTION_DOWN));
3581 window->consumeMotionEvent(WithMotionAction(ACTION_DOWN));
3582
Prabir Pradhan678438e2023-04-13 19:32:51 +00003583 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN)
3584 .deviceId(touchDeviceId)
3585 .pointer(PointerBuilder(0, ToolType::FINGER).x(55).y(55))
3586 .build());
Siarhei Vishniakouf372b812023-02-14 18:06:51 -08003587 spyWindow->consumeMotionEvent(WithMotionAction(ACTION_MOVE));
3588 window->consumeMotionEvent(WithMotionAction(ACTION_MOVE));
3589
3590 // Pilfer the stream
3591 EXPECT_EQ(OK, mDispatcher->pilferPointers(spyWindow->getToken()));
3592 window->consumeMotionEvent(WithMotionAction(ACTION_CANCEL));
3593
Prabir Pradhan678438e2023-04-13 19:32:51 +00003594 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN)
3595 .deviceId(touchDeviceId)
3596 .pointer(PointerBuilder(0, ToolType::FINGER).x(60).y(60))
3597 .build());
Siarhei Vishniakouf372b812023-02-14 18:06:51 -08003598 spyWindow->consumeMotionEvent(WithMotionAction(ACTION_MOVE));
3599
3600 // Mouse down
Prabir Pradhan678438e2023-04-13 19:32:51 +00003601 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_MOUSE)
3602 .deviceId(mouseDeviceId)
3603 .buttonState(AMOTION_EVENT_BUTTON_PRIMARY)
3604 .pointer(PointerBuilder(0, ToolType::MOUSE).x(100).y(100))
3605 .build());
Siarhei Vishniakouf372b812023-02-14 18:06:51 -08003606
3607 spyWindow->consumeMotionEvent(
3608 AllOf(WithMotionAction(ACTION_CANCEL), WithDeviceId(touchDeviceId)));
3609 spyWindow->consumeMotionEvent(
3610 AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(mouseDeviceId)));
3611 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(mouseDeviceId)));
3612
Prabir Pradhan678438e2023-04-13 19:32:51 +00003613 mDispatcher->notifyMotion(
3614 MotionArgsBuilder(AMOTION_EVENT_ACTION_BUTTON_PRESS, AINPUT_SOURCE_MOUSE)
3615 .deviceId(mouseDeviceId)
3616 .buttonState(AMOTION_EVENT_BUTTON_PRIMARY)
3617 .actionButton(AMOTION_EVENT_BUTTON_PRIMARY)
3618 .pointer(PointerBuilder(0, ToolType::MOUSE).x(100).y(100))
3619 .build());
Siarhei Vishniakouf372b812023-02-14 18:06:51 -08003620 spyWindow->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_BUTTON_PRESS));
3621 window->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_BUTTON_PRESS));
3622
3623 // Mouse move!
Prabir Pradhan678438e2023-04-13 19:32:51 +00003624 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_MOUSE)
3625 .deviceId(mouseDeviceId)
3626 .buttonState(AMOTION_EVENT_BUTTON_PRIMARY)
3627 .pointer(PointerBuilder(0, ToolType::MOUSE).x(110).y(110))
3628 .build());
Siarhei Vishniakouf372b812023-02-14 18:06:51 -08003629 spyWindow->consumeMotionEvent(WithMotionAction(ACTION_MOVE));
3630 window->consumeMotionEvent(WithMotionAction(ACTION_MOVE));
3631
3632 // Touch move!
Prabir Pradhan678438e2023-04-13 19:32:51 +00003633 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN)
3634 .deviceId(touchDeviceId)
3635 .pointer(PointerBuilder(0, ToolType::FINGER).x(65).y(65))
3636 .build());
Siarhei Vishniakouf372b812023-02-14 18:06:51 -08003637
3638 // No more events
3639 spyWindow->assertNoEvents();
3640 window->assertNoEvents();
3641}
3642
3643/**
Siarhei Vishniakoued89cbb2023-10-13 10:42:44 -07003644 * Start hovering with a mouse, and then tap with a touch device. Pilfer the touch stream.
3645 * Next, click with the mouse device. Both windows (spy and regular) should receive the new mouse
3646 * ACTION_DOWN event because that's a new gesture, and pilfering should no longer be active.
3647 * While the mouse is down, new move events from the touch device should continue to work.
3648 */
3649TEST_F(InputDispatcherTest, TouchPilferAndMouseMove) {
3650 SCOPED_FLAG_OVERRIDE(enable_multi_device_same_window_stream, true);
3651 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
3652 sp<FakeWindowHandle> spyWindow =
3653 sp<FakeWindowHandle>::make(application, mDispatcher, "Spy", ADISPLAY_ID_DEFAULT);
3654 spyWindow->setFrame(Rect(0, 0, 200, 200));
3655 spyWindow->setTrustedOverlay(true);
3656 spyWindow->setSpy(true);
3657 sp<FakeWindowHandle> window =
3658 sp<FakeWindowHandle>::make(application, mDispatcher, "Window", ADISPLAY_ID_DEFAULT);
3659 window->setFrame(Rect(0, 0, 200, 200));
3660
3661 mDispatcher->onWindowInfosChanged({{*spyWindow->getInfo(), *window->getInfo()}, {}, 0, 0});
3662
3663 const int32_t mouseDeviceId = 7;
3664 const int32_t touchDeviceId = 4;
3665
3666 // Hover a bit with mouse first
3667 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_ENTER, AINPUT_SOURCE_MOUSE)
3668 .deviceId(mouseDeviceId)
3669 .pointer(PointerBuilder(0, ToolType::MOUSE).x(100).y(100))
3670 .build());
3671 spyWindow->consumeMotionEvent(
3672 AllOf(WithMotionAction(ACTION_HOVER_ENTER), WithDeviceId(mouseDeviceId)));
3673 window->consumeMotionEvent(
3674 AllOf(WithMotionAction(ACTION_HOVER_ENTER), WithDeviceId(mouseDeviceId)));
3675
3676 // Start touching
3677 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
3678 .deviceId(touchDeviceId)
3679 .pointer(PointerBuilder(0, ToolType::FINGER).x(50).y(50))
3680 .build());
3681
3682 spyWindow->consumeMotionEvent(WithMotionAction(ACTION_DOWN));
3683 window->consumeMotionEvent(WithMotionAction(ACTION_DOWN));
3684
3685 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN)
3686 .deviceId(touchDeviceId)
3687 .pointer(PointerBuilder(0, ToolType::FINGER).x(55).y(55))
3688 .build());
3689 spyWindow->consumeMotionEvent(WithMotionAction(ACTION_MOVE));
3690 window->consumeMotionEvent(WithMotionAction(ACTION_MOVE));
3691
3692 // Pilfer the stream
3693 EXPECT_EQ(OK, mDispatcher->pilferPointers(spyWindow->getToken()));
3694 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_CANCEL), WithDeviceId(touchDeviceId)));
3695 // Hover is not pilfered! Only touch.
3696
3697 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN)
3698 .deviceId(touchDeviceId)
3699 .pointer(PointerBuilder(0, ToolType::FINGER).x(60).y(60))
3700 .build());
3701 spyWindow->consumeMotionEvent(WithMotionAction(ACTION_MOVE));
3702
3703 // Mouse down
3704 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_MOUSE)
3705 .deviceId(mouseDeviceId)
3706 .buttonState(AMOTION_EVENT_BUTTON_PRIMARY)
3707 .pointer(PointerBuilder(0, ToolType::MOUSE).x(100).y(100))
3708 .build());
3709
3710 spyWindow->consumeMotionEvent(
3711 AllOf(WithMotionAction(ACTION_HOVER_EXIT), WithDeviceId(mouseDeviceId)));
3712 spyWindow->consumeMotionEvent(
3713 AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(mouseDeviceId)));
3714 window->consumeMotionEvent(
3715 AllOf(WithMotionAction(ACTION_HOVER_EXIT), WithDeviceId(mouseDeviceId)));
3716 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(mouseDeviceId)));
3717
3718 mDispatcher->notifyMotion(
3719 MotionArgsBuilder(AMOTION_EVENT_ACTION_BUTTON_PRESS, AINPUT_SOURCE_MOUSE)
3720 .deviceId(mouseDeviceId)
3721 .buttonState(AMOTION_EVENT_BUTTON_PRIMARY)
3722 .actionButton(AMOTION_EVENT_BUTTON_PRIMARY)
3723 .pointer(PointerBuilder(0, ToolType::MOUSE).x(100).y(100))
3724 .build());
3725 spyWindow->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_BUTTON_PRESS));
3726 window->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_BUTTON_PRESS));
3727
3728 // Mouse move!
3729 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_MOUSE)
3730 .deviceId(mouseDeviceId)
3731 .buttonState(AMOTION_EVENT_BUTTON_PRIMARY)
3732 .pointer(PointerBuilder(0, ToolType::MOUSE).x(110).y(110))
3733 .build());
3734 spyWindow->consumeMotionEvent(
3735 AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(mouseDeviceId)));
3736 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(mouseDeviceId)));
3737
3738 // Touch move!
3739 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN)
3740 .deviceId(touchDeviceId)
3741 .pointer(PointerBuilder(0, ToolType::FINGER).x(65).y(65))
3742 .build());
3743 spyWindow->consumeMotionEvent(
3744 AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(touchDeviceId)));
3745
3746 // No more events
3747 spyWindow->assertNoEvents();
3748 window->assertNoEvents();
3749}
3750
3751/**
Siarhei Vishniakoua16e3a22022-03-02 15:26:40 -08003752 * On the display, have a single window, and also an area where there's no window.
3753 * First pointer touches the "no window" area of the screen. Second pointer touches the window.
3754 * Make sure that the window receives the second pointer, and first pointer is simply ignored.
3755 */
3756TEST_F(InputDispatcherTest, SplitWorksWhenEmptyAreaIsTouched) {
3757 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
3758 sp<FakeWindowHandle> window =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07003759 sp<FakeWindowHandle>::make(application, mDispatcher, "Window", DISPLAY_ID);
Siarhei Vishniakoua16e3a22022-03-02 15:26:40 -08003760
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07003761 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Siarhei Vishniakoua16e3a22022-03-02 15:26:40 -08003762
3763 // Touch down on the empty space
Prabir Pradhan678438e2023-04-13 19:32:51 +00003764 mDispatcher->notifyMotion(generateTouchArgs(AMOTION_EVENT_ACTION_DOWN, {{-1, -1}}));
Siarhei Vishniakoua16e3a22022-03-02 15:26:40 -08003765
3766 mDispatcher->waitForIdle();
3767 window->assertNoEvents();
3768
3769 // Now touch down on the window with another pointer
Prabir Pradhan678438e2023-04-13 19:32:51 +00003770 mDispatcher->notifyMotion(generateTouchArgs(POINTER_1_DOWN, {{-1, -1}, {10, 10}}));
Siarhei Vishniakoua16e3a22022-03-02 15:26:40 -08003771 mDispatcher->waitForIdle();
3772 window->consumeMotionDown();
3773}
3774
3775/**
3776 * Same test as above, but instead of touching the empty space, the first touch goes to
3777 * non-touchable window.
3778 */
3779TEST_F(InputDispatcherTest, SplitWorksWhenNonTouchableWindowIsTouched) {
3780 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
3781 sp<FakeWindowHandle> window1 =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07003782 sp<FakeWindowHandle>::make(application, mDispatcher, "Window1", DISPLAY_ID);
Siarhei Vishniakoua16e3a22022-03-02 15:26:40 -08003783 window1->setTouchableRegion(Region{{0, 0, 100, 100}});
3784 window1->setTouchable(false);
3785 sp<FakeWindowHandle> window2 =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07003786 sp<FakeWindowHandle>::make(application, mDispatcher, "Window2", DISPLAY_ID);
Siarhei Vishniakoua16e3a22022-03-02 15:26:40 -08003787 window2->setTouchableRegion(Region{{100, 0, 200, 100}});
3788
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07003789 mDispatcher->onWindowInfosChanged({{*window1->getInfo(), *window2->getInfo()}, {}, 0, 0});
Siarhei Vishniakoua16e3a22022-03-02 15:26:40 -08003790
Siarhei Vishniakoua16e3a22022-03-02 15:26:40 -08003791 // Touch down on the non-touchable window
Prabir Pradhan678438e2023-04-13 19:32:51 +00003792 mDispatcher->notifyMotion(generateTouchArgs(AMOTION_EVENT_ACTION_DOWN, {{50, 50}}));
Siarhei Vishniakoua16e3a22022-03-02 15:26:40 -08003793
3794 mDispatcher->waitForIdle();
3795 window1->assertNoEvents();
3796 window2->assertNoEvents();
3797
3798 // Now touch down on the window with another pointer
Prabir Pradhan678438e2023-04-13 19:32:51 +00003799 mDispatcher->notifyMotion(generateTouchArgs(POINTER_1_DOWN, {{50, 50}, {150, 50}}));
Siarhei Vishniakoua16e3a22022-03-02 15:26:40 -08003800 mDispatcher->waitForIdle();
3801 window2->consumeMotionDown();
3802}
3803
Vaibhav Devmurari882bd9b2022-06-23 14:54:54 +00003804/**
3805 * When splitting touch events the downTime should be adjusted such that the downTime corresponds
3806 * to the event time of the first ACTION_DOWN sent to the particular window.
3807 */
3808TEST_F(InputDispatcherTest, SplitTouchesSendCorrectActionDownTime) {
3809 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
3810 sp<FakeWindowHandle> window1 =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07003811 sp<FakeWindowHandle>::make(application, mDispatcher, "Window1", DISPLAY_ID);
Vaibhav Devmurari882bd9b2022-06-23 14:54:54 +00003812 window1->setTouchableRegion(Region{{0, 0, 100, 100}});
3813 sp<FakeWindowHandle> window2 =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07003814 sp<FakeWindowHandle>::make(application, mDispatcher, "Window2", DISPLAY_ID);
Vaibhav Devmurari882bd9b2022-06-23 14:54:54 +00003815 window2->setTouchableRegion(Region{{100, 0, 200, 100}});
3816
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07003817 mDispatcher->onWindowInfosChanged({{*window1->getInfo(), *window2->getInfo()}, {}, 0, 0});
Vaibhav Devmurari882bd9b2022-06-23 14:54:54 +00003818
Vaibhav Devmurari882bd9b2022-06-23 14:54:54 +00003819 // Touch down on the first window
Prabir Pradhan678438e2023-04-13 19:32:51 +00003820 mDispatcher->notifyMotion(generateTouchArgs(AMOTION_EVENT_ACTION_DOWN, {{50, 50}}));
Vaibhav Devmurari882bd9b2022-06-23 14:54:54 +00003821 mDispatcher->waitForIdle();
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07003822
Prabir Pradhan9d5f9ce2024-01-24 00:03:41 +00003823 const std::unique_ptr<MotionEvent> firstDown =
3824 window1->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN)));
3825 ASSERT_EQ(firstDown->getDownTime(), firstDown->getEventTime());
Vaibhav Devmurari882bd9b2022-06-23 14:54:54 +00003826 window2->assertNoEvents();
Vaibhav Devmurari882bd9b2022-06-23 14:54:54 +00003827
3828 // Now touch down on the window with another pointer
Prabir Pradhan678438e2023-04-13 19:32:51 +00003829 mDispatcher->notifyMotion(generateTouchArgs(POINTER_1_DOWN, {{50, 50}, {150, 50}}));
Vaibhav Devmurari882bd9b2022-06-23 14:54:54 +00003830 mDispatcher->waitForIdle();
Prabir Pradhan9d5f9ce2024-01-24 00:03:41 +00003831
3832 const std::unique_ptr<MotionEvent> secondDown =
3833 window2->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN)));
3834 ASSERT_EQ(secondDown->getDownTime(), secondDown->getEventTime());
3835 ASSERT_NE(firstDown->getDownTime(), secondDown->getDownTime());
3836 // We currently send MOVE events to all windows receiving a split touch when there is any change
3837 // in the touch state, even when none of the pointers in the split window actually moved.
3838 // Document this behavior in the test.
3839 window1->consumeMotionMove();
Vaibhav Devmurari882bd9b2022-06-23 14:54:54 +00003840
3841 // Now move the pointer on the second window
Prabir Pradhan678438e2023-04-13 19:32:51 +00003842 mDispatcher->notifyMotion(generateTouchArgs(AMOTION_EVENT_ACTION_MOVE, {{50, 50}, {151, 51}}));
Vaibhav Devmurari882bd9b2022-06-23 14:54:54 +00003843 mDispatcher->waitForIdle();
Prabir Pradhan9d5f9ce2024-01-24 00:03:41 +00003844
3845 window2->consumeMotionEvent(WithDownTime(secondDown->getDownTime()));
3846 window1->consumeMotionEvent(WithDownTime(firstDown->getDownTime()));
Vaibhav Devmurari882bd9b2022-06-23 14:54:54 +00003847
3848 // Now add new touch down on the second window
Prabir Pradhan678438e2023-04-13 19:32:51 +00003849 mDispatcher->notifyMotion(generateTouchArgs(POINTER_2_DOWN, {{50, 50}, {151, 51}, {150, 50}}));
Vaibhav Devmurari882bd9b2022-06-23 14:54:54 +00003850 mDispatcher->waitForIdle();
Vaibhav Devmurari882bd9b2022-06-23 14:54:54 +00003851
Prabir Pradhan9d5f9ce2024-01-24 00:03:41 +00003852 window2->consumeMotionEvent(
3853 AllOf(WithMotionAction(POINTER_1_DOWN), WithDownTime(secondDown->getDownTime())));
3854 window1->consumeMotionEvent(WithDownTime(firstDown->getDownTime()));
Vaibhav Devmurari882bd9b2022-06-23 14:54:54 +00003855
3856 // Now move the pointer on the first window
Prabir Pradhan678438e2023-04-13 19:32:51 +00003857 mDispatcher->notifyMotion(
3858 generateTouchArgs(AMOTION_EVENT_ACTION_MOVE, {{51, 51}, {151, 51}, {150, 50}}));
Vaibhav Devmurari882bd9b2022-06-23 14:54:54 +00003859 mDispatcher->waitForIdle();
Vaibhav Devmurari882bd9b2022-06-23 14:54:54 +00003860
Prabir Pradhan9d5f9ce2024-01-24 00:03:41 +00003861 window1->consumeMotionEvent(WithDownTime(firstDown->getDownTime()));
3862 window2->consumeMotionEvent(WithDownTime(secondDown->getDownTime()));
3863
3864 // Now add new touch down on the first window
Prabir Pradhan678438e2023-04-13 19:32:51 +00003865 mDispatcher->notifyMotion(
3866 generateTouchArgs(POINTER_3_DOWN, {{51, 51}, {151, 51}, {150, 50}, {50, 50}}));
Vaibhav Devmurari882bd9b2022-06-23 14:54:54 +00003867 mDispatcher->waitForIdle();
Prabir Pradhan9d5f9ce2024-01-24 00:03:41 +00003868
3869 window1->consumeMotionEvent(
3870 AllOf(WithMotionAction(POINTER_1_DOWN), WithDownTime(firstDown->getDownTime())));
3871 window2->consumeMotionEvent(WithDownTime(secondDown->getDownTime()));
Vaibhav Devmurari882bd9b2022-06-23 14:54:54 +00003872}
3873
Garfield Tandf26e862020-07-01 20:18:19 -07003874TEST_F(InputDispatcherTest, HoverMoveEnterMouseClickAndHoverMoveExit) {
Chris Yea209fde2020-07-22 13:54:51 -07003875 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
Garfield Tandf26e862020-07-01 20:18:19 -07003876 sp<FakeWindowHandle> windowLeft =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07003877 sp<FakeWindowHandle>::make(application, mDispatcher, "Left", ADISPLAY_ID_DEFAULT);
Garfield Tandf26e862020-07-01 20:18:19 -07003878 windowLeft->setFrame(Rect(0, 0, 600, 800));
Garfield Tandf26e862020-07-01 20:18:19 -07003879 sp<FakeWindowHandle> windowRight =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07003880 sp<FakeWindowHandle>::make(application, mDispatcher, "Right", ADISPLAY_ID_DEFAULT);
Garfield Tandf26e862020-07-01 20:18:19 -07003881 windowRight->setFrame(Rect(600, 0, 1200, 800));
Garfield Tandf26e862020-07-01 20:18:19 -07003882
3883 mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application);
3884
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07003885 mDispatcher->onWindowInfosChanged(
3886 {{*windowLeft->getInfo(), *windowRight->getInfo()}, {}, 0, 0});
Garfield Tandf26e862020-07-01 20:18:19 -07003887
3888 // Start cursor position in right window so that we can move the cursor to left window.
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08003889 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07003890 injectMotionEvent(*mDispatcher,
Garfield Tandf26e862020-07-01 20:18:19 -07003891 MotionEventBuilder(AMOTION_EVENT_ACTION_HOVER_MOVE,
3892 AINPUT_SOURCE_MOUSE)
Siarhei Vishniakou6d73f832022-07-21 17:27:03 -07003893 .pointer(PointerBuilder(0, ToolType::MOUSE).x(900).y(400))
Garfield Tandf26e862020-07-01 20:18:19 -07003894 .build()));
Siarhei Vishniakou5cee1e32022-11-29 12:35:39 -08003895 windowRight->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_ENTER));
Garfield Tandf26e862020-07-01 20:18:19 -07003896
3897 // Move cursor into left window
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08003898 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07003899 injectMotionEvent(*mDispatcher,
Garfield Tandf26e862020-07-01 20:18:19 -07003900 MotionEventBuilder(AMOTION_EVENT_ACTION_HOVER_MOVE,
3901 AINPUT_SOURCE_MOUSE)
Siarhei Vishniakou6d73f832022-07-21 17:27:03 -07003902 .pointer(PointerBuilder(0, ToolType::MOUSE).x(300).y(400))
Garfield Tandf26e862020-07-01 20:18:19 -07003903 .build()));
Siarhei Vishniakou5cee1e32022-11-29 12:35:39 -08003904 windowRight->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_EXIT));
3905 windowLeft->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_ENTER));
Garfield Tandf26e862020-07-01 20:18:19 -07003906
3907 // Inject a series of mouse events for a mouse click
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08003908 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07003909 injectMotionEvent(*mDispatcher,
Garfield Tandf26e862020-07-01 20:18:19 -07003910 MotionEventBuilder(AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_MOUSE)
3911 .buttonState(AMOTION_EVENT_BUTTON_PRIMARY)
Siarhei Vishniakou6d73f832022-07-21 17:27:03 -07003912 .pointer(PointerBuilder(0, ToolType::MOUSE).x(300).y(400))
Garfield Tandf26e862020-07-01 20:18:19 -07003913 .build()));
Siarhei Vishniakouf372b812023-02-14 18:06:51 -08003914 windowLeft->consumeMotionEvent(WithMotionAction(ACTION_HOVER_EXIT));
3915 windowLeft->consumeMotionEvent(WithMotionAction(ACTION_DOWN));
Garfield Tandf26e862020-07-01 20:18:19 -07003916
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08003917 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07003918 injectMotionEvent(*mDispatcher,
Garfield Tandf26e862020-07-01 20:18:19 -07003919 MotionEventBuilder(AMOTION_EVENT_ACTION_BUTTON_PRESS,
3920 AINPUT_SOURCE_MOUSE)
3921 .buttonState(AMOTION_EVENT_BUTTON_PRIMARY)
3922 .actionButton(AMOTION_EVENT_BUTTON_PRIMARY)
Siarhei Vishniakou6d73f832022-07-21 17:27:03 -07003923 .pointer(PointerBuilder(0, ToolType::MOUSE).x(300).y(400))
Garfield Tandf26e862020-07-01 20:18:19 -07003924 .build()));
Siarhei Vishniakou5cee1e32022-11-29 12:35:39 -08003925 windowLeft->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_BUTTON_PRESS));
Garfield Tandf26e862020-07-01 20:18:19 -07003926
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08003927 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07003928 injectMotionEvent(*mDispatcher,
Garfield Tandf26e862020-07-01 20:18:19 -07003929 MotionEventBuilder(AMOTION_EVENT_ACTION_BUTTON_RELEASE,
3930 AINPUT_SOURCE_MOUSE)
3931 .buttonState(0)
3932 .actionButton(AMOTION_EVENT_BUTTON_PRIMARY)
Siarhei Vishniakou6d73f832022-07-21 17:27:03 -07003933 .pointer(PointerBuilder(0, ToolType::MOUSE).x(300).y(400))
Garfield Tandf26e862020-07-01 20:18:19 -07003934 .build()));
Siarhei Vishniakou5cee1e32022-11-29 12:35:39 -08003935 windowLeft->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_BUTTON_RELEASE));
Garfield Tandf26e862020-07-01 20:18:19 -07003936
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08003937 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07003938 injectMotionEvent(*mDispatcher,
Garfield Tandf26e862020-07-01 20:18:19 -07003939 MotionEventBuilder(AMOTION_EVENT_ACTION_UP, AINPUT_SOURCE_MOUSE)
3940 .buttonState(0)
Siarhei Vishniakou6d73f832022-07-21 17:27:03 -07003941 .pointer(PointerBuilder(0, ToolType::MOUSE).x(300).y(400))
Garfield Tandf26e862020-07-01 20:18:19 -07003942 .build()));
3943 windowLeft->consumeMotionUp(ADISPLAY_ID_DEFAULT);
3944
3945 // Move mouse cursor back to right window
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08003946 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07003947 injectMotionEvent(*mDispatcher,
Garfield Tandf26e862020-07-01 20:18:19 -07003948 MotionEventBuilder(AMOTION_EVENT_ACTION_HOVER_MOVE,
3949 AINPUT_SOURCE_MOUSE)
Siarhei Vishniakou6d73f832022-07-21 17:27:03 -07003950 .pointer(PointerBuilder(0, ToolType::MOUSE).x(900).y(400))
Garfield Tandf26e862020-07-01 20:18:19 -07003951 .build()));
Siarhei Vishniakou5cee1e32022-11-29 12:35:39 -08003952 windowRight->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_ENTER));
Siarhei Vishniakou5cee1e32022-11-29 12:35:39 -08003953
3954 // No more events
3955 windowLeft->assertNoEvents();
3956 windowRight->assertNoEvents();
3957}
3958
Siarhei Vishniakouf372b812023-02-14 18:06:51 -08003959/**
3960 * Put two fingers down (and don't release them) and click the mouse button.
3961 * The clicking of mouse is a new ACTION_DOWN event. Since it's from a different device, the
3962 * currently active gesture should be canceled, and the new one should proceed.
3963 */
Siarhei Vishniakoued89cbb2023-10-13 10:42:44 -07003964TEST_F(InputDispatcherTest, TwoPointersDownMouseClick_legacy) {
3965 SCOPED_FLAG_OVERRIDE(enable_multi_device_same_window_stream, false);
Siarhei Vishniakouf372b812023-02-14 18:06:51 -08003966 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
3967 sp<FakeWindowHandle> window =
3968 sp<FakeWindowHandle>::make(application, mDispatcher, "Window", ADISPLAY_ID_DEFAULT);
3969 window->setFrame(Rect(0, 0, 600, 800));
3970
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07003971 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Siarhei Vishniakouf372b812023-02-14 18:06:51 -08003972
3973 const int32_t touchDeviceId = 4;
3974 const int32_t mouseDeviceId = 6;
Siarhei Vishniakouf372b812023-02-14 18:06:51 -08003975
3976 // Two pointers down
Prabir Pradhan678438e2023-04-13 19:32:51 +00003977 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
3978 .deviceId(touchDeviceId)
3979 .pointer(PointerBuilder(0, ToolType::FINGER).x(100).y(100))
3980 .build());
Siarhei Vishniakouf372b812023-02-14 18:06:51 -08003981
Prabir Pradhan678438e2023-04-13 19:32:51 +00003982 mDispatcher->notifyMotion(MotionArgsBuilder(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
3983 .deviceId(touchDeviceId)
3984 .pointer(PointerBuilder(0, ToolType::FINGER).x(100).y(100))
3985 .pointer(PointerBuilder(1, ToolType::FINGER).x(120).y(120))
3986 .build());
Siarhei Vishniakouf372b812023-02-14 18:06:51 -08003987 window->consumeMotionEvent(WithMotionAction(ACTION_DOWN));
3988 window->consumeMotionEvent(WithMotionAction(POINTER_1_DOWN));
3989
3990 // Inject a series of mouse events for a mouse click
Prabir Pradhan678438e2023-04-13 19:32:51 +00003991 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_MOUSE)
3992 .deviceId(mouseDeviceId)
3993 .buttonState(AMOTION_EVENT_BUTTON_PRIMARY)
3994 .pointer(PointerBuilder(0, ToolType::MOUSE).x(300).y(400))
3995 .build());
Siarhei Vishniakouf372b812023-02-14 18:06:51 -08003996 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_CANCEL), WithDeviceId(touchDeviceId),
3997 WithPointerCount(2u)));
3998 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(mouseDeviceId)));
3999
Prabir Pradhan678438e2023-04-13 19:32:51 +00004000 mDispatcher->notifyMotion(
4001 MotionArgsBuilder(AMOTION_EVENT_ACTION_BUTTON_PRESS, AINPUT_SOURCE_MOUSE)
4002 .deviceId(mouseDeviceId)
4003 .buttonState(AMOTION_EVENT_BUTTON_PRIMARY)
4004 .actionButton(AMOTION_EVENT_BUTTON_PRIMARY)
4005 .pointer(PointerBuilder(0, ToolType::MOUSE).x(300).y(400))
4006 .build());
Siarhei Vishniakouf372b812023-02-14 18:06:51 -08004007 window->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_BUTTON_PRESS));
4008
4009 // Try to send more touch events while the mouse is down. Since it's a continuation of an
4010 // already canceled gesture, it should be ignored.
Prabir Pradhan678438e2023-04-13 19:32:51 +00004011 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN)
4012 .deviceId(touchDeviceId)
4013 .pointer(PointerBuilder(0, ToolType::FINGER).x(101).y(101))
4014 .pointer(PointerBuilder(1, ToolType::FINGER).x(121).y(121))
4015 .build());
Siarhei Vishniakouf372b812023-02-14 18:06:51 -08004016 window->assertNoEvents();
4017}
4018
Siarhei Vishniakoued89cbb2023-10-13 10:42:44 -07004019/**
4020 * Put two fingers down (and don't release them) and click the mouse button.
4021 * The clicking of mouse is a new ACTION_DOWN event. Since it's from a different device, the
4022 * currently active gesture should not be canceled, and the new one should proceed in parallel.
4023 */
4024TEST_F(InputDispatcherTest, TwoPointersDownMouseClick) {
4025 SCOPED_FLAG_OVERRIDE(enable_multi_device_same_window_stream, true);
4026 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
4027 sp<FakeWindowHandle> window =
4028 sp<FakeWindowHandle>::make(application, mDispatcher, "Window", ADISPLAY_ID_DEFAULT);
4029 window->setFrame(Rect(0, 0, 600, 800));
4030
4031 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
4032
4033 const int32_t touchDeviceId = 4;
4034 const int32_t mouseDeviceId = 6;
4035
4036 // Two pointers down
4037 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
4038 .deviceId(touchDeviceId)
4039 .pointer(PointerBuilder(0, ToolType::FINGER).x(100).y(100))
4040 .build());
4041
4042 mDispatcher->notifyMotion(MotionArgsBuilder(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
4043 .deviceId(touchDeviceId)
4044 .pointer(PointerBuilder(0, ToolType::FINGER).x(100).y(100))
4045 .pointer(PointerBuilder(1, ToolType::FINGER).x(120).y(120))
4046 .build());
4047 window->consumeMotionEvent(WithMotionAction(ACTION_DOWN));
4048 window->consumeMotionEvent(WithMotionAction(POINTER_1_DOWN));
4049
4050 // Send a series of mouse events for a mouse click
4051 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_MOUSE)
4052 .deviceId(mouseDeviceId)
4053 .buttonState(AMOTION_EVENT_BUTTON_PRIMARY)
4054 .pointer(PointerBuilder(0, ToolType::MOUSE).x(300).y(400))
4055 .build());
4056 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(mouseDeviceId)));
4057
4058 mDispatcher->notifyMotion(
4059 MotionArgsBuilder(AMOTION_EVENT_ACTION_BUTTON_PRESS, AINPUT_SOURCE_MOUSE)
4060 .deviceId(mouseDeviceId)
4061 .buttonState(AMOTION_EVENT_BUTTON_PRIMARY)
4062 .actionButton(AMOTION_EVENT_BUTTON_PRIMARY)
4063 .pointer(PointerBuilder(0, ToolType::MOUSE).x(300).y(400))
4064 .build());
4065 window->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_BUTTON_PRESS));
4066
4067 // Try to send more touch events while the mouse is down. Since it's a continuation of an
4068 // already active gesture, it should be sent normally.
4069 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN)
4070 .deviceId(touchDeviceId)
4071 .pointer(PointerBuilder(0, ToolType::FINGER).x(101).y(101))
4072 .pointer(PointerBuilder(1, ToolType::FINGER).x(121).y(121))
4073 .build());
4074 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(touchDeviceId)));
4075 window->assertNoEvents();
4076}
4077
Siarhei Vishniakou5cee1e32022-11-29 12:35:39 -08004078TEST_F(InputDispatcherTest, HoverWithSpyWindows) {
4079 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
4080
4081 sp<FakeWindowHandle> spyWindow =
4082 sp<FakeWindowHandle>::make(application, mDispatcher, "Spy", ADISPLAY_ID_DEFAULT);
4083 spyWindow->setFrame(Rect(0, 0, 600, 800));
4084 spyWindow->setTrustedOverlay(true);
4085 spyWindow->setSpy(true);
4086 sp<FakeWindowHandle> window =
4087 sp<FakeWindowHandle>::make(application, mDispatcher, "Window", ADISPLAY_ID_DEFAULT);
4088 window->setFrame(Rect(0, 0, 600, 800));
4089
4090 mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07004091 mDispatcher->onWindowInfosChanged({{*spyWindow->getInfo(), *window->getInfo()}, {}, 0, 0});
Siarhei Vishniakou5cee1e32022-11-29 12:35:39 -08004092
4093 // Send mouse cursor to the window
4094 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07004095 injectMotionEvent(*mDispatcher,
Siarhei Vishniakou5cee1e32022-11-29 12:35:39 -08004096 MotionEventBuilder(AMOTION_EVENT_ACTION_HOVER_ENTER,
4097 AINPUT_SOURCE_MOUSE)
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07004098 .pointer(PointerBuilder(0, ToolType::MOUSE).x(100).y(100))
Siarhei Vishniakou5cee1e32022-11-29 12:35:39 -08004099 .build()));
4100
4101 window->consumeMotionEvent(AllOf(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_ENTER),
4102 WithSource(AINPUT_SOURCE_MOUSE)));
4103 spyWindow->consumeMotionEvent(AllOf(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_ENTER),
4104 WithSource(AINPUT_SOURCE_MOUSE)));
4105
4106 window->assertNoEvents();
4107 spyWindow->assertNoEvents();
Garfield Tandf26e862020-07-01 20:18:19 -07004108}
4109
Siarhei Vishniakoued89cbb2023-10-13 10:42:44 -07004110TEST_F(InputDispatcherTest, MouseAndTouchWithSpyWindows_legacy) {
4111 SCOPED_FLAG_OVERRIDE(enable_multi_device_same_window_stream, false);
Siarhei Vishniakou060f82b2023-01-27 06:39:14 -08004112 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
4113
4114 sp<FakeWindowHandle> spyWindow =
4115 sp<FakeWindowHandle>::make(application, mDispatcher, "Spy", ADISPLAY_ID_DEFAULT);
4116 spyWindow->setFrame(Rect(0, 0, 600, 800));
4117 spyWindow->setTrustedOverlay(true);
4118 spyWindow->setSpy(true);
4119 sp<FakeWindowHandle> window =
4120 sp<FakeWindowHandle>::make(application, mDispatcher, "Window", ADISPLAY_ID_DEFAULT);
4121 window->setFrame(Rect(0, 0, 600, 800));
4122
4123 mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07004124 mDispatcher->onWindowInfosChanged({{*spyWindow->getInfo(), *window->getInfo()}, {}, 0, 0});
Siarhei Vishniakou060f82b2023-01-27 06:39:14 -08004125
4126 // Send mouse cursor to the window
4127 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07004128 injectMotionEvent(*mDispatcher,
Siarhei Vishniakou060f82b2023-01-27 06:39:14 -08004129 MotionEventBuilder(AMOTION_EVENT_ACTION_HOVER_ENTER,
4130 AINPUT_SOURCE_MOUSE)
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07004131 .pointer(PointerBuilder(0, ToolType::MOUSE).x(100).y(100))
Siarhei Vishniakou060f82b2023-01-27 06:39:14 -08004132 .build()));
4133
4134 // Move mouse cursor
4135 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07004136 injectMotionEvent(*mDispatcher,
Siarhei Vishniakou060f82b2023-01-27 06:39:14 -08004137 MotionEventBuilder(AMOTION_EVENT_ACTION_HOVER_MOVE,
4138 AINPUT_SOURCE_MOUSE)
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07004139 .pointer(PointerBuilder(0, ToolType::MOUSE).x(110).y(110))
Siarhei Vishniakou060f82b2023-01-27 06:39:14 -08004140 .build()));
4141
4142 window->consumeMotionEvent(AllOf(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_ENTER),
4143 WithSource(AINPUT_SOURCE_MOUSE)));
4144 spyWindow->consumeMotionEvent(AllOf(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_ENTER),
4145 WithSource(AINPUT_SOURCE_MOUSE)));
4146 window->consumeMotionEvent(AllOf(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_MOVE),
4147 WithSource(AINPUT_SOURCE_MOUSE)));
4148 spyWindow->consumeMotionEvent(AllOf(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_MOVE),
4149 WithSource(AINPUT_SOURCE_MOUSE)));
4150 // Touch down on the window
4151 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07004152 injectMotionEvent(*mDispatcher,
Siarhei Vishniakou060f82b2023-01-27 06:39:14 -08004153 MotionEventBuilder(AMOTION_EVENT_ACTION_DOWN,
4154 AINPUT_SOURCE_TOUCHSCREEN)
4155 .deviceId(SECOND_DEVICE_ID)
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07004156 .pointer(PointerBuilder(0, ToolType::FINGER).x(200).y(200))
Siarhei Vishniakou060f82b2023-01-27 06:39:14 -08004157 .build()));
4158 window->consumeMotionEvent(AllOf(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_EXIT),
4159 WithSource(AINPUT_SOURCE_MOUSE)));
4160 spyWindow->consumeMotionEvent(AllOf(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_EXIT),
4161 WithSource(AINPUT_SOURCE_MOUSE)));
4162 window->consumeMotionEvent(AllOf(WithMotionAction(AMOTION_EVENT_ACTION_DOWN),
4163 WithSource(AINPUT_SOURCE_TOUCHSCREEN)));
4164 spyWindow->consumeMotionEvent(AllOf(WithMotionAction(AMOTION_EVENT_ACTION_DOWN),
4165 WithSource(AINPUT_SOURCE_TOUCHSCREEN)));
4166
4167 // pilfer the motion, retaining the gesture on the spy window.
4168 EXPECT_EQ(OK, mDispatcher->pilferPointers(spyWindow->getToken()));
4169 window->consumeMotionEvent(AllOf(WithMotionAction(AMOTION_EVENT_ACTION_CANCEL),
4170 WithSource(AINPUT_SOURCE_TOUCHSCREEN)));
4171
4172 // Touch UP on the window
4173 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07004174 injectMotionEvent(*mDispatcher,
Siarhei Vishniakou060f82b2023-01-27 06:39:14 -08004175 MotionEventBuilder(AMOTION_EVENT_ACTION_UP,
4176 AINPUT_SOURCE_TOUCHSCREEN)
4177 .deviceId(SECOND_DEVICE_ID)
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07004178 .pointer(PointerBuilder(0, ToolType::FINGER).x(200).y(200))
Siarhei Vishniakou060f82b2023-01-27 06:39:14 -08004179 .build()));
4180 spyWindow->consumeMotionEvent(AllOf(WithMotionAction(AMOTION_EVENT_ACTION_UP),
4181 WithSource(AINPUT_SOURCE_TOUCHSCREEN)));
4182
4183 // Previously, a touch was pilfered. However, that gesture was just finished. Now, we are going
4184 // to send a new gesture. It should again go to both windows (spy and the window below), just
4185 // like the first gesture did, before pilfering. The window configuration has not changed.
4186
4187 // One more tap - DOWN
4188 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07004189 injectMotionEvent(*mDispatcher,
Siarhei Vishniakou060f82b2023-01-27 06:39:14 -08004190 MotionEventBuilder(AMOTION_EVENT_ACTION_DOWN,
4191 AINPUT_SOURCE_TOUCHSCREEN)
4192 .deviceId(SECOND_DEVICE_ID)
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07004193 .pointer(PointerBuilder(0, ToolType::FINGER).x(250).y(250))
Siarhei Vishniakou060f82b2023-01-27 06:39:14 -08004194 .build()));
4195 window->consumeMotionEvent(AllOf(WithMotionAction(AMOTION_EVENT_ACTION_DOWN),
4196 WithSource(AINPUT_SOURCE_TOUCHSCREEN)));
4197 spyWindow->consumeMotionEvent(AllOf(WithMotionAction(AMOTION_EVENT_ACTION_DOWN),
4198 WithSource(AINPUT_SOURCE_TOUCHSCREEN)));
4199
4200 // Touch UP on the window
4201 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07004202 injectMotionEvent(*mDispatcher,
Siarhei Vishniakou060f82b2023-01-27 06:39:14 -08004203 MotionEventBuilder(AMOTION_EVENT_ACTION_UP,
4204 AINPUT_SOURCE_TOUCHSCREEN)
4205 .deviceId(SECOND_DEVICE_ID)
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07004206 .pointer(PointerBuilder(0, ToolType::FINGER).x(250).y(250))
Siarhei Vishniakou060f82b2023-01-27 06:39:14 -08004207 .build()));
4208 window->consumeMotionEvent(AllOf(WithMotionAction(AMOTION_EVENT_ACTION_UP),
4209 WithSource(AINPUT_SOURCE_TOUCHSCREEN)));
4210 spyWindow->consumeMotionEvent(AllOf(WithMotionAction(AMOTION_EVENT_ACTION_UP),
4211 WithSource(AINPUT_SOURCE_TOUCHSCREEN)));
4212
4213 window->assertNoEvents();
4214 spyWindow->assertNoEvents();
4215}
4216
Siarhei Vishniakoued89cbb2023-10-13 10:42:44 -07004217TEST_F(InputDispatcherTest, MouseAndTouchWithSpyWindows) {
4218 SCOPED_FLAG_OVERRIDE(enable_multi_device_same_window_stream, true);
4219 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
4220
4221 sp<FakeWindowHandle> spyWindow =
4222 sp<FakeWindowHandle>::make(application, mDispatcher, "Spy", ADISPLAY_ID_DEFAULT);
4223 spyWindow->setFrame(Rect(0, 0, 600, 800));
4224 spyWindow->setTrustedOverlay(true);
4225 spyWindow->setSpy(true);
4226 sp<FakeWindowHandle> window =
4227 sp<FakeWindowHandle>::make(application, mDispatcher, "Window", ADISPLAY_ID_DEFAULT);
4228 window->setFrame(Rect(0, 0, 600, 800));
4229
4230 mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application);
4231 mDispatcher->onWindowInfosChanged({{*spyWindow->getInfo(), *window->getInfo()}, {}, 0, 0});
4232
4233 // Send mouse cursor to the window
4234 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_ENTER, AINPUT_SOURCE_MOUSE)
4235 .pointer(PointerBuilder(0, ToolType::MOUSE).x(100).y(100))
4236 .build());
4237
4238 // Move mouse cursor
4239 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_MOVE, AINPUT_SOURCE_MOUSE)
4240 .pointer(PointerBuilder(0, ToolType::MOUSE).x(110).y(110))
4241 .build());
4242
4243 window->consumeMotionEvent(
4244 AllOf(WithMotionAction(ACTION_HOVER_ENTER), WithSource(AINPUT_SOURCE_MOUSE)));
4245 spyWindow->consumeMotionEvent(
4246 AllOf(WithMotionAction(ACTION_HOVER_ENTER), WithSource(AINPUT_SOURCE_MOUSE)));
4247 window->consumeMotionEvent(
4248 AllOf(WithMotionAction(ACTION_HOVER_MOVE), WithSource(AINPUT_SOURCE_MOUSE)));
4249 spyWindow->consumeMotionEvent(
4250 AllOf(WithMotionAction(ACTION_HOVER_MOVE), WithSource(AINPUT_SOURCE_MOUSE)));
4251 // Touch down on the window
4252 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
4253 .deviceId(SECOND_DEVICE_ID)
4254 .pointer(PointerBuilder(0, ToolType::FINGER).x(200).y(200))
4255 .build());
4256 window->consumeMotionEvent(
4257 AllOf(WithMotionAction(ACTION_DOWN), WithSource(AINPUT_SOURCE_TOUCHSCREEN)));
4258 spyWindow->consumeMotionEvent(
4259 AllOf(WithMotionAction(ACTION_DOWN), WithSource(AINPUT_SOURCE_TOUCHSCREEN)));
4260
4261 // pilfer the motion, retaining the gesture on the spy window.
4262 EXPECT_EQ(OK, mDispatcher->pilferPointers(spyWindow->getToken()));
4263 window->consumeMotionEvent(
4264 AllOf(WithMotionAction(ACTION_CANCEL), WithSource(AINPUT_SOURCE_TOUCHSCREEN)));
4265 // Mouse hover is not pilfered
4266
4267 // Touch UP on the window
4268 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN)
4269 .deviceId(SECOND_DEVICE_ID)
4270 .pointer(PointerBuilder(0, ToolType::FINGER).x(200).y(200))
4271 .build());
4272 spyWindow->consumeMotionEvent(
4273 AllOf(WithMotionAction(ACTION_UP), WithSource(AINPUT_SOURCE_TOUCHSCREEN)));
4274
4275 // Previously, a touch was pilfered. However, that gesture was just finished. Now, we are going
4276 // to send a new gesture. It should again go to both windows (spy and the window below), just
4277 // like the first gesture did, before pilfering. The window configuration has not changed.
4278
4279 // One more tap - DOWN
4280 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
4281 .deviceId(SECOND_DEVICE_ID)
4282 .pointer(PointerBuilder(0, ToolType::FINGER).x(250).y(250))
4283 .build());
4284 window->consumeMotionEvent(
4285 AllOf(WithMotionAction(ACTION_DOWN), WithSource(AINPUT_SOURCE_TOUCHSCREEN)));
4286 spyWindow->consumeMotionEvent(
4287 AllOf(WithMotionAction(ACTION_DOWN), WithSource(AINPUT_SOURCE_TOUCHSCREEN)));
4288
4289 // Touch UP on the window
4290 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN)
4291 .deviceId(SECOND_DEVICE_ID)
4292 .pointer(PointerBuilder(0, ToolType::FINGER).x(250).y(250))
4293 .build());
4294 window->consumeMotionEvent(
4295 AllOf(WithMotionAction(ACTION_UP), WithSource(AINPUT_SOURCE_TOUCHSCREEN)));
4296 spyWindow->consumeMotionEvent(
4297 AllOf(WithMotionAction(ACTION_UP), WithSource(AINPUT_SOURCE_TOUCHSCREEN)));
4298
4299 // Mouse movement continues normally as well
4300 // Move mouse cursor
4301 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_MOVE, AINPUT_SOURCE_MOUSE)
4302 .pointer(PointerBuilder(0, ToolType::MOUSE).x(120).y(130))
4303 .build());
4304 window->consumeMotionEvent(
4305 AllOf(WithMotionAction(ACTION_HOVER_MOVE), WithSource(AINPUT_SOURCE_MOUSE)));
4306 spyWindow->consumeMotionEvent(
4307 AllOf(WithMotionAction(ACTION_HOVER_MOVE), WithSource(AINPUT_SOURCE_MOUSE)));
4308
4309 window->assertNoEvents();
4310 spyWindow->assertNoEvents();
4311}
4312
Garfield Tandf26e862020-07-01 20:18:19 -07004313// This test is different from the test above that HOVER_ENTER and HOVER_EXIT events are injected
4314// directly in this test.
4315TEST_F(InputDispatcherTest, HoverEnterMouseClickAndHoverExit) {
Chris Yea209fde2020-07-22 13:54:51 -07004316 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
Garfield Tandf26e862020-07-01 20:18:19 -07004317 sp<FakeWindowHandle> window =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07004318 sp<FakeWindowHandle>::make(application, mDispatcher, "Window", ADISPLAY_ID_DEFAULT);
Garfield Tandf26e862020-07-01 20:18:19 -07004319 window->setFrame(Rect(0, 0, 1200, 800));
Garfield Tandf26e862020-07-01 20:18:19 -07004320
4321 mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application);
4322
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07004323 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Garfield Tandf26e862020-07-01 20:18:19 -07004324
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08004325 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07004326 injectMotionEvent(*mDispatcher,
Garfield Tandf26e862020-07-01 20:18:19 -07004327 MotionEventBuilder(AMOTION_EVENT_ACTION_HOVER_ENTER,
4328 AINPUT_SOURCE_MOUSE)
Siarhei Vishniakou6d73f832022-07-21 17:27:03 -07004329 .pointer(PointerBuilder(0, ToolType::MOUSE).x(300).y(400))
Garfield Tandf26e862020-07-01 20:18:19 -07004330 .build()));
Siarhei Vishniakou5cee1e32022-11-29 12:35:39 -08004331 window->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_ENTER));
Garfield Tandf26e862020-07-01 20:18:19 -07004332 // Inject a series of mouse events for a mouse click
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08004333 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07004334 injectMotionEvent(*mDispatcher,
Garfield Tandf26e862020-07-01 20:18:19 -07004335 MotionEventBuilder(AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_MOUSE)
4336 .buttonState(AMOTION_EVENT_BUTTON_PRIMARY)
Siarhei Vishniakou6d73f832022-07-21 17:27:03 -07004337 .pointer(PointerBuilder(0, ToolType::MOUSE).x(300).y(400))
Garfield Tandf26e862020-07-01 20:18:19 -07004338 .build()));
Siarhei Vishniakouf372b812023-02-14 18:06:51 -08004339 window->consumeMotionEvent(WithMotionAction(ACTION_HOVER_EXIT));
4340 window->consumeMotionEvent(WithMotionAction(ACTION_DOWN));
Garfield Tandf26e862020-07-01 20:18:19 -07004341
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08004342 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07004343 injectMotionEvent(*mDispatcher,
Garfield Tandf26e862020-07-01 20:18:19 -07004344 MotionEventBuilder(AMOTION_EVENT_ACTION_BUTTON_PRESS,
4345 AINPUT_SOURCE_MOUSE)
4346 .buttonState(AMOTION_EVENT_BUTTON_PRIMARY)
4347 .actionButton(AMOTION_EVENT_BUTTON_PRIMARY)
Siarhei Vishniakou6d73f832022-07-21 17:27:03 -07004348 .pointer(PointerBuilder(0, ToolType::MOUSE).x(300).y(400))
Garfield Tandf26e862020-07-01 20:18:19 -07004349 .build()));
Siarhei Vishniakou5cee1e32022-11-29 12:35:39 -08004350 window->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_BUTTON_PRESS));
Garfield Tandf26e862020-07-01 20:18:19 -07004351
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08004352 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07004353 injectMotionEvent(*mDispatcher,
Garfield Tandf26e862020-07-01 20:18:19 -07004354 MotionEventBuilder(AMOTION_EVENT_ACTION_BUTTON_RELEASE,
4355 AINPUT_SOURCE_MOUSE)
4356 .buttonState(0)
4357 .actionButton(AMOTION_EVENT_BUTTON_PRIMARY)
Siarhei Vishniakou6d73f832022-07-21 17:27:03 -07004358 .pointer(PointerBuilder(0, ToolType::MOUSE).x(300).y(400))
Garfield Tandf26e862020-07-01 20:18:19 -07004359 .build()));
Siarhei Vishniakou5cee1e32022-11-29 12:35:39 -08004360 window->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_BUTTON_RELEASE));
Garfield Tandf26e862020-07-01 20:18:19 -07004361
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08004362 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07004363 injectMotionEvent(*mDispatcher,
Garfield Tandf26e862020-07-01 20:18:19 -07004364 MotionEventBuilder(AMOTION_EVENT_ACTION_UP, AINPUT_SOURCE_MOUSE)
4365 .buttonState(0)
Siarhei Vishniakou6d73f832022-07-21 17:27:03 -07004366 .pointer(PointerBuilder(0, ToolType::MOUSE).x(300).y(400))
Garfield Tandf26e862020-07-01 20:18:19 -07004367 .build()));
4368 window->consumeMotionUp(ADISPLAY_ID_DEFAULT);
4369
Siarhei Vishniakoua235c042023-05-02 09:59:09 -07004370 // We already canceled the hovering implicitly by injecting the "DOWN" event without lifting the
4371 // hover first. Therefore, injection of HOVER_EXIT is inconsistent, and should fail.
4372 ASSERT_EQ(InputEventInjectionResult::FAILED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07004373 injectMotionEvent(*mDispatcher,
Garfield Tandf26e862020-07-01 20:18:19 -07004374 MotionEventBuilder(AMOTION_EVENT_ACTION_HOVER_EXIT,
4375 AINPUT_SOURCE_MOUSE)
Siarhei Vishniakou6d73f832022-07-21 17:27:03 -07004376 .pointer(PointerBuilder(0, ToolType::MOUSE).x(300).y(400))
Garfield Tandf26e862020-07-01 20:18:19 -07004377 .build()));
Siarhei Vishniakouf372b812023-02-14 18:06:51 -08004378 window->assertNoEvents();
Garfield Tandf26e862020-07-01 20:18:19 -07004379}
4380
Siarhei Vishniakou0b0374d2022-11-17 17:40:53 -08004381/**
Siarhei Vishniakoub581f7f2022-12-07 20:23:06 +00004382 * Hover over a window, and then remove that window. Make sure that HOVER_EXIT for that event
4383 * is generated.
4384 */
4385TEST_F(InputDispatcherTest, HoverExitIsSentToRemovedWindow) {
4386 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
4387 sp<FakeWindowHandle> window =
4388 sp<FakeWindowHandle>::make(application, mDispatcher, "Window", ADISPLAY_ID_DEFAULT);
4389 window->setFrame(Rect(0, 0, 1200, 800));
4390
4391 mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application);
4392
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07004393 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Siarhei Vishniakoub581f7f2022-12-07 20:23:06 +00004394
4395 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07004396 injectMotionEvent(*mDispatcher,
Siarhei Vishniakoub581f7f2022-12-07 20:23:06 +00004397 MotionEventBuilder(AMOTION_EVENT_ACTION_HOVER_ENTER,
4398 AINPUT_SOURCE_MOUSE)
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07004399 .pointer(PointerBuilder(0, ToolType::MOUSE).x(300).y(400))
Siarhei Vishniakoub581f7f2022-12-07 20:23:06 +00004400 .build()));
4401 window->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_ENTER));
4402
4403 // Remove the window, but keep the channel.
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07004404 mDispatcher->onWindowInfosChanged({{}, {}, 0, 0});
Siarhei Vishniakoub581f7f2022-12-07 20:23:06 +00004405 window->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_EXIT));
4406}
4407
4408/**
Daniel Norman7487dfa2023-08-02 16:39:45 -07004409 * Test that invalid HOVER events sent by accessibility do not cause a fatal crash.
4410 */
Ameer Armalycff4fa52023-10-04 23:45:11 +00004411TEST_F_WITH_FLAGS(InputDispatcherTest, InvalidA11yHoverStreamDoesNotCrash,
4412 REQUIRES_FLAGS_DISABLED(ACONFIG_FLAG(com::android::input::flags,
4413 a11y_crash_on_inconsistent_event_stream))) {
Daniel Norman7487dfa2023-08-02 16:39:45 -07004414 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
4415 sp<FakeWindowHandle> window =
4416 sp<FakeWindowHandle>::make(application, mDispatcher, "Window", ADISPLAY_ID_DEFAULT);
4417 window->setFrame(Rect(0, 0, 1200, 800));
4418
4419 mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application);
4420
4421 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
4422
4423 MotionEventBuilder hoverEnterBuilder =
4424 MotionEventBuilder(AMOTION_EVENT_ACTION_HOVER_ENTER, AINPUT_SOURCE_MOUSE)
4425 .pointer(PointerBuilder(0, ToolType::MOUSE).x(300).y(400))
4426 .addFlag(AMOTION_EVENT_FLAG_IS_ACCESSIBILITY_EVENT);
4427 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
4428 injectMotionEvent(*mDispatcher, hoverEnterBuilder.build()));
4429 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
4430 injectMotionEvent(*mDispatcher, hoverEnterBuilder.build()));
4431 window->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_ENTER));
4432 window->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_ENTER));
4433}
4434
4435/**
Siarhei Vishniakou4e1ffa52023-02-21 11:50:34 -08004436 * If mouse is hovering when the touch goes down, the hovering should be stopped via HOVER_EXIT.
4437 */
Siarhei Vishniakoued89cbb2023-10-13 10:42:44 -07004438TEST_F(InputDispatcherTest, TouchDownAfterMouseHover_legacy) {
4439 SCOPED_FLAG_OVERRIDE(enable_multi_device_same_window_stream, false);
Siarhei Vishniakou4e1ffa52023-02-21 11:50:34 -08004440 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
4441 sp<FakeWindowHandle> window =
4442 sp<FakeWindowHandle>::make(application, mDispatcher, "Window", ADISPLAY_ID_DEFAULT);
4443 window->setFrame(Rect(0, 0, 100, 100));
4444
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07004445 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Siarhei Vishniakou4e1ffa52023-02-21 11:50:34 -08004446
4447 const int32_t mouseDeviceId = 7;
4448 const int32_t touchDeviceId = 4;
Siarhei Vishniakou4e1ffa52023-02-21 11:50:34 -08004449
4450 // Start hovering with the mouse
Prabir Pradhan678438e2023-04-13 19:32:51 +00004451 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_ENTER, AINPUT_SOURCE_MOUSE)
4452 .deviceId(mouseDeviceId)
4453 .pointer(PointerBuilder(0, ToolType::MOUSE).x(10).y(10))
4454 .build());
Siarhei Vishniakou4e1ffa52023-02-21 11:50:34 -08004455 window->consumeMotionEvent(
4456 AllOf(WithMotionAction(ACTION_HOVER_ENTER), WithDeviceId(mouseDeviceId)));
4457
4458 // Touch goes down
Prabir Pradhan678438e2023-04-13 19:32:51 +00004459 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
4460 .deviceId(touchDeviceId)
4461 .pointer(PointerBuilder(0, ToolType::FINGER).x(50).y(50))
4462 .build());
Siarhei Vishniakou4e1ffa52023-02-21 11:50:34 -08004463
4464 window->consumeMotionEvent(
4465 AllOf(WithMotionAction(ACTION_HOVER_EXIT), WithDeviceId(mouseDeviceId)));
4466 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(touchDeviceId)));
4467}
4468
4469/**
Siarhei Vishniakoued89cbb2023-10-13 10:42:44 -07004470 * If mouse is hovering when the touch goes down, the hovering should not be stopped.
4471 */
4472TEST_F(InputDispatcherTest, TouchDownAfterMouseHover) {
4473 SCOPED_FLAG_OVERRIDE(enable_multi_device_same_window_stream, true);
4474 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
4475 sp<FakeWindowHandle> window =
4476 sp<FakeWindowHandle>::make(application, mDispatcher, "Window", ADISPLAY_ID_DEFAULT);
4477 window->setFrame(Rect(0, 0, 100, 100));
4478
4479 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
4480
4481 const int32_t mouseDeviceId = 7;
4482 const int32_t touchDeviceId = 4;
4483
4484 // Start hovering with the mouse
4485 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_ENTER, AINPUT_SOURCE_MOUSE)
4486 .deviceId(mouseDeviceId)
4487 .pointer(PointerBuilder(0, ToolType::MOUSE).x(10).y(10))
4488 .build());
4489 window->consumeMotionEvent(
4490 AllOf(WithMotionAction(ACTION_HOVER_ENTER), WithDeviceId(mouseDeviceId)));
4491
4492 // Touch goes down
4493 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
4494 .deviceId(touchDeviceId)
4495 .pointer(PointerBuilder(0, ToolType::FINGER).x(50).y(50))
4496 .build());
4497 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(touchDeviceId)));
4498}
4499
4500/**
Siarhei Vishniakou0b0374d2022-11-17 17:40:53 -08004501 * Inject a mouse hover event followed by a tap from touchscreen.
Siarhei Vishniakoub581f7f2022-12-07 20:23:06 +00004502 * The tap causes a HOVER_EXIT event to be generated because the current event
4503 * stream's source has been switched.
Siarhei Vishniakou0b0374d2022-11-17 17:40:53 -08004504 */
Siarhei Vishniakoued89cbb2023-10-13 10:42:44 -07004505TEST_F(InputDispatcherTest, MouseHoverAndTouchTap_legacy) {
4506 SCOPED_FLAG_OVERRIDE(enable_multi_device_same_window_stream, false);
Siarhei Vishniakou0b0374d2022-11-17 17:40:53 -08004507 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
4508 sp<FakeWindowHandle> window =
4509 sp<FakeWindowHandle>::make(application, mDispatcher, "Window", ADISPLAY_ID_DEFAULT);
4510 window->setFrame(Rect(0, 0, 100, 100));
4511
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07004512 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -07004513 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_MOVE, AINPUT_SOURCE_MOUSE)
4514 .pointer(PointerBuilder(0, ToolType::MOUSE).x(50).y(50))
4515 .build());
Siarhei Vishniakou0b0374d2022-11-17 17:40:53 -08004516 ASSERT_NO_FATAL_FAILURE(
4517 window->consumeMotionEvent(AllOf(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_ENTER),
4518 WithSource(AINPUT_SOURCE_MOUSE))));
Siarhei Vishniakou0b0374d2022-11-17 17:40:53 -08004519
4520 // Tap on the window
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -07004521 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
4522 .pointer(PointerBuilder(0, ToolType::FINGER).x(10).y(10))
4523 .build());
Siarhei Vishniakou0b0374d2022-11-17 17:40:53 -08004524 ASSERT_NO_FATAL_FAILURE(
Siarhei Vishniakoub581f7f2022-12-07 20:23:06 +00004525 window->consumeMotionEvent(AllOf(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_EXIT),
4526 WithSource(AINPUT_SOURCE_MOUSE))));
4527
4528 ASSERT_NO_FATAL_FAILURE(
Siarhei Vishniakou0b0374d2022-11-17 17:40:53 -08004529 window->consumeMotionEvent(AllOf(WithMotionAction(AMOTION_EVENT_ACTION_DOWN),
4530 WithSource(AINPUT_SOURCE_TOUCHSCREEN))));
4531
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -07004532 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN)
4533 .pointer(PointerBuilder(0, ToolType::FINGER).x(10).y(10))
4534 .build());
Siarhei Vishniakou0b0374d2022-11-17 17:40:53 -08004535 ASSERT_NO_FATAL_FAILURE(
4536 window->consumeMotionEvent(AllOf(WithMotionAction(AMOTION_EVENT_ACTION_UP),
4537 WithSource(AINPUT_SOURCE_TOUCHSCREEN))));
4538}
4539
Siarhei Vishniakoued89cbb2023-10-13 10:42:44 -07004540/**
4541 * Send a mouse hover event followed by a tap from touchscreen.
4542 * The tap causes a HOVER_EXIT event to be generated because the current event
4543 * stream's source has been switched.
4544 */
4545TEST_F(InputDispatcherTest, MouseHoverAndTouchTap) {
4546 SCOPED_FLAG_OVERRIDE(enable_multi_device_same_window_stream, true);
4547 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
4548 sp<FakeWindowHandle> window =
4549 sp<FakeWindowHandle>::make(application, mDispatcher, "Window", ADISPLAY_ID_DEFAULT);
4550 window->setFrame(Rect(0, 0, 100, 100));
4551
4552 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
4553 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_MOVE, AINPUT_SOURCE_MOUSE)
4554 .pointer(PointerBuilder(0, ToolType::MOUSE).x(50).y(50))
4555 .build());
4556
4557 window->consumeMotionEvent(AllOf(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_ENTER),
4558 WithSource(AINPUT_SOURCE_MOUSE)));
4559
4560 // Tap on the window
4561 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
4562 .pointer(PointerBuilder(0, ToolType::FINGER).x(10).y(10))
4563 .build());
4564
4565 window->consumeMotionEvent(AllOf(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_EXIT),
4566 WithSource(AINPUT_SOURCE_MOUSE)));
4567
4568 window->consumeMotionEvent(AllOf(WithMotionAction(AMOTION_EVENT_ACTION_DOWN),
4569 WithSource(AINPUT_SOURCE_TOUCHSCREEN)));
4570
4571 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN)
4572 .pointer(PointerBuilder(0, ToolType::FINGER).x(10).y(10))
4573 .build());
4574
4575 window->consumeMotionEvent(AllOf(WithMotionAction(AMOTION_EVENT_ACTION_UP),
4576 WithSource(AINPUT_SOURCE_TOUCHSCREEN)));
4577}
4578
Tommy Nordgrendae9dfc2022-10-13 11:25:57 +02004579TEST_F(InputDispatcherTest, HoverEnterMoveRemoveWindowsInSecondDisplay) {
4580 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
4581 sp<FakeWindowHandle> windowDefaultDisplay =
4582 sp<FakeWindowHandle>::make(application, mDispatcher, "DefaultDisplay",
4583 ADISPLAY_ID_DEFAULT);
4584 windowDefaultDisplay->setFrame(Rect(0, 0, 600, 800));
4585 sp<FakeWindowHandle> windowSecondDisplay =
4586 sp<FakeWindowHandle>::make(application, mDispatcher, "SecondDisplay",
4587 SECOND_DISPLAY_ID);
4588 windowSecondDisplay->setFrame(Rect(0, 0, 600, 800));
4589
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07004590 mDispatcher->onWindowInfosChanged(
4591 {{*windowDefaultDisplay->getInfo(), *windowSecondDisplay->getInfo()}, {}, 0, 0});
Tommy Nordgrendae9dfc2022-10-13 11:25:57 +02004592
4593 // Set cursor position in window in default display and check that hover enter and move
4594 // events are generated.
4595 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07004596 injectMotionEvent(*mDispatcher,
Tommy Nordgrendae9dfc2022-10-13 11:25:57 +02004597 MotionEventBuilder(AMOTION_EVENT_ACTION_HOVER_MOVE,
4598 AINPUT_SOURCE_MOUSE)
4599 .displayId(ADISPLAY_ID_DEFAULT)
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07004600 .pointer(PointerBuilder(0, ToolType::MOUSE).x(300).y(600))
Tommy Nordgrendae9dfc2022-10-13 11:25:57 +02004601 .build()));
Siarhei Vishniakou5cee1e32022-11-29 12:35:39 -08004602 windowDefaultDisplay->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_ENTER));
Tommy Nordgrendae9dfc2022-10-13 11:25:57 +02004603
4604 // Remove all windows in secondary display and check that no event happens on window in
4605 // primary display.
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07004606 mDispatcher->onWindowInfosChanged({{*windowDefaultDisplay->getInfo()}, {}, 0, 0});
4607
Tommy Nordgrendae9dfc2022-10-13 11:25:57 +02004608 windowDefaultDisplay->assertNoEvents();
4609
4610 // Move cursor position in window in default display and check that only hover move
4611 // event is generated and not hover enter event.
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07004612 mDispatcher->onWindowInfosChanged(
4613 {{*windowDefaultDisplay->getInfo(), *windowSecondDisplay->getInfo()}, {}, 0, 0});
Tommy Nordgrendae9dfc2022-10-13 11:25:57 +02004614 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07004615 injectMotionEvent(*mDispatcher,
Tommy Nordgrendae9dfc2022-10-13 11:25:57 +02004616 MotionEventBuilder(AMOTION_EVENT_ACTION_HOVER_MOVE,
4617 AINPUT_SOURCE_MOUSE)
4618 .displayId(ADISPLAY_ID_DEFAULT)
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07004619 .pointer(PointerBuilder(0, ToolType::MOUSE).x(400).y(700))
Tommy Nordgrendae9dfc2022-10-13 11:25:57 +02004620 .build()));
Siarhei Vishniakou5cee1e32022-11-29 12:35:39 -08004621 windowDefaultDisplay->consumeMotionEvent(
4622 AllOf(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_MOVE),
4623 WithSource(AINPUT_SOURCE_MOUSE)));
Tommy Nordgrendae9dfc2022-10-13 11:25:57 +02004624 windowDefaultDisplay->assertNoEvents();
4625}
4626
Garfield Tan00f511d2019-06-12 16:55:40 -07004627TEST_F(InputDispatcherTest, DispatchMouseEventsUnderCursor) {
Chris Yea209fde2020-07-22 13:54:51 -07004628 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
Garfield Tan00f511d2019-06-12 16:55:40 -07004629
4630 sp<FakeWindowHandle> windowLeft =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07004631 sp<FakeWindowHandle>::make(application, mDispatcher, "Left", ADISPLAY_ID_DEFAULT);
Garfield Tan00f511d2019-06-12 16:55:40 -07004632 windowLeft->setFrame(Rect(0, 0, 600, 800));
Garfield Tan00f511d2019-06-12 16:55:40 -07004633 sp<FakeWindowHandle> windowRight =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07004634 sp<FakeWindowHandle>::make(application, mDispatcher, "Right", ADISPLAY_ID_DEFAULT);
Garfield Tan00f511d2019-06-12 16:55:40 -07004635 windowRight->setFrame(Rect(600, 0, 1200, 800));
Garfield Tan00f511d2019-06-12 16:55:40 -07004636
4637 mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application);
4638
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07004639 mDispatcher->onWindowInfosChanged(
4640 {{*windowLeft->getInfo(), *windowRight->getInfo()}, {}, 0, 0});
Garfield Tan00f511d2019-06-12 16:55:40 -07004641
4642 // Inject an event with coordinate in the area of right window, with mouse cursor in the area of
4643 // left window. This event should be dispatched to the left window.
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08004644 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07004645 injectMotionEvent(*mDispatcher, AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_MOUSE,
Siarhei Vishniakou4cb50ca2020-05-26 21:43:02 -07004646 ADISPLAY_ID_DEFAULT, {610, 400}, {599, 400}));
Siarhei Vishniakouc5ca85c2019-11-15 17:20:00 -08004647 windowLeft->consumeMotionDown(ADISPLAY_ID_DEFAULT);
Garfield Tan00f511d2019-06-12 16:55:40 -07004648 windowRight->assertNoEvents();
4649}
4650
Siarhei Vishniakou2bfa9052019-11-21 18:10:54 -08004651TEST_F(InputDispatcherTest, NotifyDeviceReset_CancelsKeyStream) {
Chris Yea209fde2020-07-22 13:54:51 -07004652 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07004653 sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher,
4654 "Fake Window", ADISPLAY_ID_DEFAULT);
Vishnu Nair47074b82020-08-14 11:54:47 -07004655 window->setFocusable(true);
Siarhei Vishniakou2bfa9052019-11-21 18:10:54 -08004656
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07004657 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Vishnu Nair958da932020-08-21 17:12:37 -07004658 setFocusedWindow(window);
4659
Siarhei Vishniakouf1035d42019-09-20 16:32:01 +01004660 window->consumeFocusEvent(true);
Siarhei Vishniakou2bfa9052019-11-21 18:10:54 -08004661
Prabir Pradhan678438e2023-04-13 19:32:51 +00004662 mDispatcher->notifyKey(generateKeyArgs(AKEY_EVENT_ACTION_DOWN, ADISPLAY_ID_DEFAULT));
Siarhei Vishniakou2bfa9052019-11-21 18:10:54 -08004663
4664 // Window should receive key down event.
4665 window->consumeKeyDown(ADISPLAY_ID_DEFAULT);
4666
4667 // When device reset happens, that key stream should be terminated with FLAG_CANCELED
4668 // on the app side.
Prabir Pradhan678438e2023-04-13 19:32:51 +00004669 mDispatcher->notifyDeviceReset({/*id=*/10, /*eventTime=*/20, DEVICE_ID});
Prabir Pradhan7662a8d2023-12-15 01:58:14 +00004670 window->consumeKeyUp(ADISPLAY_ID_DEFAULT, AKEY_EVENT_FLAG_CANCELED);
Siarhei Vishniakou2bfa9052019-11-21 18:10:54 -08004671}
4672
4673TEST_F(InputDispatcherTest, NotifyDeviceReset_CancelsMotionStream) {
Chris Yea209fde2020-07-22 13:54:51 -07004674 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07004675 sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher,
4676 "Fake Window", ADISPLAY_ID_DEFAULT);
Siarhei Vishniakou2bfa9052019-11-21 18:10:54 -08004677
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07004678 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Siarhei Vishniakou2bfa9052019-11-21 18:10:54 -08004679
Prabir Pradhan678438e2023-04-13 19:32:51 +00004680 mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_DOWN,
4681 AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT));
Siarhei Vishniakou2bfa9052019-11-21 18:10:54 -08004682
4683 // Window should receive motion down event.
4684 window->consumeMotionDown(ADISPLAY_ID_DEFAULT);
4685
4686 // When device reset happens, that motion stream should be terminated with ACTION_CANCEL
4687 // on the app side.
Prabir Pradhan678438e2023-04-13 19:32:51 +00004688 mDispatcher->notifyDeviceReset({/*id=*/10, /*eventTime=*/20, DEVICE_ID});
Siarhei Vishniakou1ae72f12023-01-29 12:55:30 -08004689 window->consumeMotionEvent(
4690 AllOf(WithMotionAction(ACTION_CANCEL), WithDisplayId(ADISPLAY_ID_DEFAULT)));
Siarhei Vishniakou2bfa9052019-11-21 18:10:54 -08004691}
4692
Siarhei Vishniakou0686f0c2023-05-02 11:56:15 -07004693TEST_F(InputDispatcherTest, NotifyDeviceResetCancelsHoveringStream) {
4694 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
4695 sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher,
4696 "Fake Window", ADISPLAY_ID_DEFAULT);
4697
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07004698 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Siarhei Vishniakou0686f0c2023-05-02 11:56:15 -07004699
4700 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_ENTER, AINPUT_SOURCE_STYLUS)
4701 .pointer(PointerBuilder(0, ToolType::STYLUS).x(10).y(10))
4702 .build());
4703
4704 window->consumeMotionEvent(WithMotionAction(ACTION_HOVER_ENTER));
4705
4706 // When device reset happens, that hover stream should be terminated with ACTION_HOVER_EXIT
4707 mDispatcher->notifyDeviceReset({/*id=*/10, /*eventTime=*/20, DEVICE_ID});
4708 window->consumeMotionEvent(WithMotionAction(ACTION_HOVER_EXIT));
4709
4710 // After the device has been reset, a new hovering stream can be sent to the window
4711 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_ENTER, AINPUT_SOURCE_STYLUS)
4712 .pointer(PointerBuilder(0, ToolType::STYLUS).x(15).y(15))
4713 .build());
4714 window->consumeMotionEvent(WithMotionAction(ACTION_HOVER_ENTER));
4715}
4716
Arthur Hung2ee6d0b2022-03-03 20:19:38 +08004717TEST_F(InputDispatcherTest, InterceptKeyByPolicy) {
4718 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07004719 sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher,
4720 "Fake Window", ADISPLAY_ID_DEFAULT);
Arthur Hung2ee6d0b2022-03-03 20:19:38 +08004721 window->setFocusable(true);
4722
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07004723 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Arthur Hung2ee6d0b2022-03-03 20:19:38 +08004724 setFocusedWindow(window);
4725
4726 window->consumeFocusEvent(true);
4727
Prabir Pradhan678438e2023-04-13 19:32:51 +00004728 const NotifyKeyArgs keyArgs = generateKeyArgs(AKEY_EVENT_ACTION_DOWN, ADISPLAY_ID_DEFAULT);
Arthur Hung2ee6d0b2022-03-03 20:19:38 +08004729 const std::chrono::milliseconds interceptKeyTimeout = 50ms;
4730 const nsecs_t injectTime = keyArgs.eventTime;
4731 mFakePolicy->setInterceptKeyTimeout(interceptKeyTimeout);
Prabir Pradhan678438e2023-04-13 19:32:51 +00004732 mDispatcher->notifyKey(keyArgs);
Arthur Hung2ee6d0b2022-03-03 20:19:38 +08004733 // The dispatching time should be always greater than or equal to intercept key timeout.
4734 window->consumeKeyDown(ADISPLAY_ID_DEFAULT);
4735 ASSERT_TRUE((systemTime(SYSTEM_TIME_MONOTONIC) - injectTime) >=
4736 std::chrono::nanoseconds(interceptKeyTimeout).count());
4737}
4738
Siarhei Vishniakouf54d2ab2023-06-09 13:23:53 -07004739/**
4740 * Keys with ACTION_UP are delivered immediately, even if a long 'intercept key timeout' is set.
4741 */
Arthur Hung2ee6d0b2022-03-03 20:19:38 +08004742TEST_F(InputDispatcherTest, InterceptKeyIfKeyUp) {
4743 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07004744 sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher,
4745 "Fake Window", ADISPLAY_ID_DEFAULT);
Arthur Hung2ee6d0b2022-03-03 20:19:38 +08004746 window->setFocusable(true);
4747
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07004748 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Arthur Hung2ee6d0b2022-03-03 20:19:38 +08004749 setFocusedWindow(window);
4750
4751 window->consumeFocusEvent(true);
4752
Prabir Pradhan678438e2023-04-13 19:32:51 +00004753 mDispatcher->notifyKey(generateKeyArgs(AKEY_EVENT_ACTION_DOWN, ADISPLAY_ID_DEFAULT));
Arthur Hung2ee6d0b2022-03-03 20:19:38 +08004754 window->consumeKeyDown(ADISPLAY_ID_DEFAULT);
Siarhei Vishniakouf54d2ab2023-06-09 13:23:53 -07004755
4756 // Set a value that's significantly larger than the default consumption timeout. If the
4757 // implementation is correct, the actual value doesn't matter; it won't slow down the test.
4758 mFakePolicy->setInterceptKeyTimeout(600ms);
4759 mDispatcher->notifyKey(generateKeyArgs(AKEY_EVENT_ACTION_UP, ADISPLAY_ID_DEFAULT));
4760 // Window should receive key event immediately when same key up.
Arthur Hung2ee6d0b2022-03-03 20:19:38 +08004761 window->consumeKeyUp(ADISPLAY_ID_DEFAULT);
4762}
4763
Prabir Pradhanc44ce4d2021-10-05 05:26:29 -07004764/**
Siarhei Vishniakou487c49b2022-12-02 15:48:57 -08004765 * Two windows. First is a regular window. Second does not overlap with the first, and has
4766 * WATCH_OUTSIDE_TOUCH.
4767 * Both windows are owned by the same UID.
4768 * Tap first window. Make sure that the second window receives ACTION_OUTSIDE with correct, non-zero
4769 * coordinates. The coordinates are not zeroed out because both windows are owned by the same UID.
4770 */
4771TEST_F(InputDispatcherTest, ActionOutsideForOwnedWindowHasValidCoordinates) {
4772 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -07004773 sp<FakeWindowHandle> window =
4774 sp<FakeWindowHandle>::make(application, mDispatcher, "Window", ADISPLAY_ID_DEFAULT);
Siarhei Vishniakou487c49b2022-12-02 15:48:57 -08004775 window->setFrame(Rect{0, 0, 100, 100});
4776
4777 sp<FakeWindowHandle> outsideWindow =
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -07004778 sp<FakeWindowHandle>::make(application, mDispatcher, "Outside Window",
Siarhei Vishniakou487c49b2022-12-02 15:48:57 -08004779 ADISPLAY_ID_DEFAULT);
4780 outsideWindow->setFrame(Rect{100, 100, 200, 200});
4781 outsideWindow->setWatchOutsideTouch(true);
4782 // outsideWindow must be above 'window' to receive ACTION_OUTSIDE events when 'window' is tapped
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07004783 mDispatcher->onWindowInfosChanged({{*outsideWindow->getInfo(), *window->getInfo()}, {}, 0, 0});
Siarhei Vishniakou487c49b2022-12-02 15:48:57 -08004784
4785 // Tap on first window.
Prabir Pradhan678438e2023-04-13 19:32:51 +00004786 mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_DOWN,
4787 AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
4788 {PointF{50, 50}}));
Siarhei Vishniakou487c49b2022-12-02 15:48:57 -08004789 window->consumeMotionDown();
4790 // The coordinates of the tap in 'outsideWindow' are relative to its top left corner.
4791 // Therefore, we should offset them by (100, 100) relative to the screen's top left corner.
4792 outsideWindow->consumeMotionEvent(
4793 AllOf(WithMotionAction(ACTION_OUTSIDE), WithCoords(-50, -50)));
Prabir Pradhan502a7252023-12-01 16:11:24 +00004794
4795 // Ensure outsideWindow doesn't get any more events for the gesture.
4796 mDispatcher->notifyMotion(generateMotionArgs(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN,
4797 ADISPLAY_ID_DEFAULT, {PointF{51, 51}}));
4798 window->consumeMotionMove();
4799 outsideWindow->assertNoEvents();
Siarhei Vishniakou487c49b2022-12-02 15:48:57 -08004800}
4801
4802/**
Prabir Pradhanb60b1dc2022-03-15 14:02:35 +00004803 * This test documents the behavior of WATCH_OUTSIDE_TOUCH. The window will get ACTION_OUTSIDE when
4804 * a another pointer causes ACTION_DOWN to be sent to another window for the first time. Only one
4805 * ACTION_OUTSIDE event is sent per gesture.
4806 */
4807TEST_F(InputDispatcherTest, ActionOutsideSentOnlyWhenAWindowIsTouched) {
4808 // There are three windows that do not overlap. `window` wants to WATCH_OUTSIDE_TOUCH.
4809 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07004810 sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher,
4811 "First Window", ADISPLAY_ID_DEFAULT);
Prabir Pradhanb60b1dc2022-03-15 14:02:35 +00004812 window->setWatchOutsideTouch(true);
4813 window->setFrame(Rect{0, 0, 100, 100});
4814 sp<FakeWindowHandle> secondWindow =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07004815 sp<FakeWindowHandle>::make(application, mDispatcher, "Second Window",
4816 ADISPLAY_ID_DEFAULT);
Prabir Pradhanb60b1dc2022-03-15 14:02:35 +00004817 secondWindow->setFrame(Rect{100, 100, 200, 200});
4818 sp<FakeWindowHandle> thirdWindow =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07004819 sp<FakeWindowHandle>::make(application, mDispatcher, "Third Window",
4820 ADISPLAY_ID_DEFAULT);
Prabir Pradhanb60b1dc2022-03-15 14:02:35 +00004821 thirdWindow->setFrame(Rect{200, 200, 300, 300});
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07004822 mDispatcher->onWindowInfosChanged(
4823 {{*window->getInfo(), *secondWindow->getInfo(), *thirdWindow->getInfo()}, {}, 0, 0});
Prabir Pradhanb60b1dc2022-03-15 14:02:35 +00004824
4825 // First pointer lands outside all windows. `window` does not get ACTION_OUTSIDE.
Prabir Pradhan678438e2023-04-13 19:32:51 +00004826 mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_DOWN,
4827 AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
4828 {PointF{-10, -10}}));
Prabir Pradhanb60b1dc2022-03-15 14:02:35 +00004829 window->assertNoEvents();
4830 secondWindow->assertNoEvents();
4831
4832 // The second pointer lands inside `secondWindow`, which should receive a DOWN event.
4833 // Now, `window` should get ACTION_OUTSIDE.
Prabir Pradhan678438e2023-04-13 19:32:51 +00004834 mDispatcher->notifyMotion(generateMotionArgs(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN,
4835 ADISPLAY_ID_DEFAULT,
4836 {PointF{-10, -10}, PointF{105, 105}}));
Siarhei Vishniakou487c49b2022-12-02 15:48:57 -08004837 const std::map<int32_t, PointF> expectedPointers{{0, PointF{-10, -10}}, {1, PointF{105, 105}}};
4838 window->consumeMotionEvent(
4839 AllOf(WithMotionAction(ACTION_OUTSIDE), WithPointers(expectedPointers)));
Prabir Pradhanb60b1dc2022-03-15 14:02:35 +00004840 secondWindow->consumeMotionDown();
4841 thirdWindow->assertNoEvents();
4842
4843 // The third pointer lands inside `thirdWindow`, which should receive a DOWN event. There is
4844 // no ACTION_OUTSIDE sent to `window` because one has already been sent for this gesture.
Prabir Pradhan678438e2023-04-13 19:32:51 +00004845 mDispatcher->notifyMotion(
4846 generateMotionArgs(POINTER_2_DOWN, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
4847 {PointF{-10, -10}, PointF{105, 105}, PointF{205, 205}}));
Prabir Pradhanb60b1dc2022-03-15 14:02:35 +00004848 window->assertNoEvents();
4849 secondWindow->consumeMotionMove();
4850 thirdWindow->consumeMotionDown();
4851}
4852
Prabir Pradhan814fe082022-07-22 20:22:18 +00004853TEST_F(InputDispatcherTest, OnWindowInfosChanged_RemoveAllWindowsOnDisplay) {
4854 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07004855 sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher,
4856 "Fake Window", ADISPLAY_ID_DEFAULT);
Prabir Pradhan814fe082022-07-22 20:22:18 +00004857 window->setFocusable(true);
4858
Patrick Williamsd828f302023-04-28 17:52:08 -05004859 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Prabir Pradhan814fe082022-07-22 20:22:18 +00004860 setFocusedWindow(window);
4861
4862 window->consumeFocusEvent(true);
4863
Prabir Pradhan678438e2023-04-13 19:32:51 +00004864 const NotifyKeyArgs keyDown = generateKeyArgs(AKEY_EVENT_ACTION_DOWN, ADISPLAY_ID_DEFAULT);
4865 const NotifyKeyArgs keyUp = generateKeyArgs(AKEY_EVENT_ACTION_UP, ADISPLAY_ID_DEFAULT);
4866 mDispatcher->notifyKey(keyDown);
4867 mDispatcher->notifyKey(keyUp);
Prabir Pradhan814fe082022-07-22 20:22:18 +00004868
4869 window->consumeKeyDown(ADISPLAY_ID_DEFAULT);
4870 window->consumeKeyUp(ADISPLAY_ID_DEFAULT);
4871
4872 // All windows are removed from the display. Ensure that we can no longer dispatch to it.
Patrick Williamsd828f302023-04-28 17:52:08 -05004873 mDispatcher->onWindowInfosChanged({{}, {}, 0, 0});
Prabir Pradhan814fe082022-07-22 20:22:18 +00004874
4875 window->consumeFocusEvent(false);
4876
Prabir Pradhan678438e2023-04-13 19:32:51 +00004877 mDispatcher->notifyKey(keyDown);
4878 mDispatcher->notifyKey(keyUp);
Prabir Pradhan814fe082022-07-22 20:22:18 +00004879 window->assertNoEvents();
4880}
4881
Arthur Hung96483742022-11-15 03:30:48 +00004882TEST_F(InputDispatcherTest, NonSplitTouchableWindowReceivesMultiTouch) {
4883 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
4884 sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher,
4885 "Fake Window", ADISPLAY_ID_DEFAULT);
4886 // Ensure window is non-split and have some transform.
4887 window->setPreventSplitting(true);
4888 window->setWindowOffset(20, 40);
Patrick Williamsd828f302023-04-28 17:52:08 -05004889 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Arthur Hung96483742022-11-15 03:30:48 +00004890
4891 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07004892 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
Arthur Hung96483742022-11-15 03:30:48 +00004893 {50, 50}))
4894 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
4895 window->consumeMotionDown(ADISPLAY_ID_DEFAULT);
4896
4897 const MotionEvent secondFingerDownEvent =
4898 MotionEventBuilder(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
4899 .displayId(ADISPLAY_ID_DEFAULT)
4900 .eventTime(systemTime(SYSTEM_TIME_MONOTONIC))
Siarhei Vishniakou6d73f832022-07-21 17:27:03 -07004901 .pointer(PointerBuilder(/*id=*/0, ToolType::FINGER).x(50).y(50))
4902 .pointer(PointerBuilder(/*id=*/1, ToolType::FINGER).x(-30).y(-50))
Arthur Hung96483742022-11-15 03:30:48 +00004903 .build();
4904 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07004905 injectMotionEvent(*mDispatcher, secondFingerDownEvent, INJECT_EVENT_TIMEOUT,
Arthur Hung96483742022-11-15 03:30:48 +00004906 InputEventInjectionSync::WAIT_FOR_RESULT))
4907 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
4908
Siarhei Vishniakoud3061ab2023-12-18 20:41:08 -08004909 std::unique_ptr<MotionEvent> event = window->consumeMotionEvent();
4910 ASSERT_NE(nullptr, event);
4911 EXPECT_EQ(POINTER_1_DOWN, event->getAction());
4912 EXPECT_EQ(70, event->getX(0)); // 50 + 20
4913 EXPECT_EQ(90, event->getY(0)); // 50 + 40
4914 EXPECT_EQ(-10, event->getX(1)); // -30 + 20
4915 EXPECT_EQ(-10, event->getY(1)); // -50 + 40
Arthur Hung96483742022-11-15 03:30:48 +00004916}
4917
Siarhei Vishniakou25537f82023-07-18 14:35:47 -07004918/**
4919 * Two windows: a splittable and a non-splittable.
4920 * The non-splittable window shouldn't receive any "incomplete" gestures.
4921 * Send the first pointer to the splittable window, and then touch the non-splittable window.
4922 * The second pointer should be dropped because the initial window is splittable, so it won't get
4923 * any pointers outside of it, and the second window is non-splittable, so it shouldn't get any
4924 * "incomplete" gestures.
4925 */
4926TEST_F(InputDispatcherTest, SplittableAndNonSplittableWindows) {
4927 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
4928 sp<FakeWindowHandle> leftWindow =
4929 sp<FakeWindowHandle>::make(application, mDispatcher, "Left splittable Window",
4930 ADISPLAY_ID_DEFAULT);
4931 leftWindow->setPreventSplitting(false);
4932 leftWindow->setFrame(Rect(0, 0, 100, 100));
4933 sp<FakeWindowHandle> rightWindow =
4934 sp<FakeWindowHandle>::make(application, mDispatcher, "Right non-splittable Window",
4935 ADISPLAY_ID_DEFAULT);
4936 rightWindow->setPreventSplitting(true);
4937 rightWindow->setFrame(Rect(100, 100, 200, 200));
4938 mDispatcher->onWindowInfosChanged(
4939 {{*leftWindow->getInfo(), *rightWindow->getInfo()}, {}, 0, 0});
4940
4941 // Touch down on left, splittable window
4942 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
4943 .pointer(PointerBuilder(0, ToolType::FINGER).x(50).y(50))
4944 .build());
4945 leftWindow->consumeMotionEvent(WithMotionAction(ACTION_DOWN));
4946
4947 mDispatcher->notifyMotion(
4948 MotionArgsBuilder(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
4949 .pointer(PointerBuilder(/*id=*/0, ToolType::FINGER).x(50).y(50))
4950 .pointer(PointerBuilder(/*id=*/1, ToolType::FINGER).x(150).y(150))
4951 .build());
4952 leftWindow->assertNoEvents();
4953 rightWindow->assertNoEvents();
4954}
4955
Harry Cuttsb166c002023-05-09 13:06:05 +00004956TEST_F(InputDispatcherTest, TouchpadThreeFingerSwipeOnlySentToTrustedOverlays) {
4957 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
4958 sp<FakeWindowHandle> window =
4959 sp<FakeWindowHandle>::make(application, mDispatcher, "Window", ADISPLAY_ID_DEFAULT);
4960 window->setFrame(Rect(0, 0, 400, 400));
4961 sp<FakeWindowHandle> trustedOverlay =
4962 sp<FakeWindowHandle>::make(application, mDispatcher, "Trusted Overlay",
4963 ADISPLAY_ID_DEFAULT);
4964 trustedOverlay->setSpy(true);
4965 trustedOverlay->setTrustedOverlay(true);
4966
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07004967 mDispatcher->onWindowInfosChanged({{*trustedOverlay->getInfo(), *window->getInfo()}, {}, 0, 0});
Harry Cuttsb166c002023-05-09 13:06:05 +00004968
4969 // Start a three-finger touchpad swipe
4970 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_MOUSE)
4971 .pointer(PointerBuilder(0, ToolType::FINGER).x(200).y(100))
4972 .classification(MotionClassification::MULTI_FINGER_SWIPE)
4973 .build());
4974 mDispatcher->notifyMotion(MotionArgsBuilder(POINTER_1_DOWN, AINPUT_SOURCE_MOUSE)
4975 .pointer(PointerBuilder(0, ToolType::FINGER).x(200).y(100))
4976 .pointer(PointerBuilder(1, ToolType::FINGER).x(250).y(100))
4977 .classification(MotionClassification::MULTI_FINGER_SWIPE)
4978 .build());
4979 mDispatcher->notifyMotion(MotionArgsBuilder(POINTER_2_DOWN, AINPUT_SOURCE_MOUSE)
4980 .pointer(PointerBuilder(0, ToolType::FINGER).x(200).y(100))
4981 .pointer(PointerBuilder(1, ToolType::FINGER).x(250).y(100))
4982 .pointer(PointerBuilder(2, ToolType::FINGER).x(300).y(100))
4983 .classification(MotionClassification::MULTI_FINGER_SWIPE)
4984 .build());
4985
4986 trustedOverlay->consumeMotionEvent(WithMotionAction(ACTION_DOWN));
4987 trustedOverlay->consumeMotionEvent(WithMotionAction(POINTER_1_DOWN));
4988 trustedOverlay->consumeMotionEvent(WithMotionAction(POINTER_2_DOWN));
4989
4990 // Move the swipe a bit
4991 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_MOUSE)
4992 .pointer(PointerBuilder(0, ToolType::FINGER).x(200).y(105))
4993 .pointer(PointerBuilder(1, ToolType::FINGER).x(250).y(105))
4994 .pointer(PointerBuilder(2, ToolType::FINGER).x(300).y(105))
4995 .classification(MotionClassification::MULTI_FINGER_SWIPE)
4996 .build());
4997
4998 trustedOverlay->consumeMotionEvent(WithMotionAction(ACTION_MOVE));
4999
5000 // End the swipe
5001 mDispatcher->notifyMotion(MotionArgsBuilder(POINTER_2_UP, AINPUT_SOURCE_MOUSE)
5002 .pointer(PointerBuilder(0, ToolType::FINGER).x(200).y(105))
5003 .pointer(PointerBuilder(1, ToolType::FINGER).x(250).y(105))
5004 .pointer(PointerBuilder(2, ToolType::FINGER).x(300).y(105))
5005 .classification(MotionClassification::MULTI_FINGER_SWIPE)
5006 .build());
5007 mDispatcher->notifyMotion(MotionArgsBuilder(POINTER_1_UP, AINPUT_SOURCE_MOUSE)
5008 .pointer(PointerBuilder(0, ToolType::FINGER).x(200).y(105))
5009 .pointer(PointerBuilder(1, ToolType::FINGER).x(250).y(105))
5010 .classification(MotionClassification::MULTI_FINGER_SWIPE)
5011 .build());
5012 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_UP, AINPUT_SOURCE_MOUSE)
5013 .pointer(PointerBuilder(0, ToolType::FINGER).x(200).y(105))
5014 .classification(MotionClassification::MULTI_FINGER_SWIPE)
5015 .build());
5016
5017 trustedOverlay->consumeMotionEvent(WithMotionAction(POINTER_2_UP));
5018 trustedOverlay->consumeMotionEvent(WithMotionAction(POINTER_1_UP));
5019 trustedOverlay->consumeMotionEvent(WithMotionAction(ACTION_UP));
5020
5021 window->assertNoEvents();
5022}
5023
5024TEST_F(InputDispatcherTest, TouchpadThreeFingerSwipeNotSentToSingleWindow) {
5025 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
5026 sp<FakeWindowHandle> window =
5027 sp<FakeWindowHandle>::make(application, mDispatcher, "Window", ADISPLAY_ID_DEFAULT);
5028 window->setFrame(Rect(0, 0, 400, 400));
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07005029 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Harry Cuttsb166c002023-05-09 13:06:05 +00005030
5031 // Start a three-finger touchpad swipe
5032 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_MOUSE)
5033 .pointer(PointerBuilder(0, ToolType::FINGER).x(200).y(100))
5034 .classification(MotionClassification::MULTI_FINGER_SWIPE)
5035 .build());
5036 mDispatcher->notifyMotion(MotionArgsBuilder(POINTER_1_DOWN, AINPUT_SOURCE_MOUSE)
5037 .pointer(PointerBuilder(0, ToolType::FINGER).x(200).y(100))
5038 .pointer(PointerBuilder(1, ToolType::FINGER).x(250).y(100))
5039 .classification(MotionClassification::MULTI_FINGER_SWIPE)
5040 .build());
5041 mDispatcher->notifyMotion(MotionArgsBuilder(POINTER_2_DOWN, AINPUT_SOURCE_MOUSE)
5042 .pointer(PointerBuilder(0, ToolType::FINGER).x(200).y(100))
5043 .pointer(PointerBuilder(1, ToolType::FINGER).x(250).y(100))
5044 .pointer(PointerBuilder(2, ToolType::FINGER).x(300).y(100))
5045 .classification(MotionClassification::MULTI_FINGER_SWIPE)
5046 .build());
5047
5048 // Move the swipe a bit
5049 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_MOUSE)
5050 .pointer(PointerBuilder(0, ToolType::FINGER).x(200).y(105))
5051 .pointer(PointerBuilder(1, ToolType::FINGER).x(250).y(105))
5052 .pointer(PointerBuilder(2, ToolType::FINGER).x(300).y(105))
5053 .classification(MotionClassification::MULTI_FINGER_SWIPE)
5054 .build());
5055
5056 // End the swipe
5057 mDispatcher->notifyMotion(MotionArgsBuilder(POINTER_2_UP, AINPUT_SOURCE_MOUSE)
5058 .pointer(PointerBuilder(0, ToolType::FINGER).x(200).y(105))
5059 .pointer(PointerBuilder(1, ToolType::FINGER).x(250).y(105))
5060 .pointer(PointerBuilder(2, ToolType::FINGER).x(300).y(105))
5061 .classification(MotionClassification::MULTI_FINGER_SWIPE)
5062 .build());
5063 mDispatcher->notifyMotion(MotionArgsBuilder(POINTER_1_UP, AINPUT_SOURCE_MOUSE)
5064 .pointer(PointerBuilder(0, ToolType::FINGER).x(200).y(105))
5065 .pointer(PointerBuilder(1, ToolType::FINGER).x(250).y(105))
5066 .classification(MotionClassification::MULTI_FINGER_SWIPE)
5067 .build());
5068 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_UP, AINPUT_SOURCE_MOUSE)
5069 .pointer(PointerBuilder(0, ToolType::FINGER).x(200).y(105))
5070 .classification(MotionClassification::MULTI_FINGER_SWIPE)
5071 .build());
5072
5073 window->assertNoEvents();
5074}
5075
Prabir Pradhanb60b1dc2022-03-15 14:02:35 +00005076/**
Siarhei Vishniakouadb9fc92023-05-26 10:46:09 -07005077 * Send a two-pointer gesture to a single window. The window's orientation changes in response to
5078 * the first pointer.
Prabir Pradhan69d00bf2023-06-23 19:55:18 +00005079 * Ensure that the second pointer and the subsequent gesture is correctly delivered to the window.
Siarhei Vishniakouadb9fc92023-05-26 10:46:09 -07005080 */
5081TEST_F(InputDispatcherTest, MultiplePointersWithRotatingWindow) {
5082 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
5083 sp<FakeWindowHandle> window =
5084 sp<FakeWindowHandle>::make(application, mDispatcher, "Window", ADISPLAY_ID_DEFAULT);
5085 window->setFrame(Rect(0, 0, 400, 400));
Siarhei Vishniakou700424c2023-07-18 17:18:42 -07005086 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Siarhei Vishniakouadb9fc92023-05-26 10:46:09 -07005087
5088 const nsecs_t baseTime = systemTime(SYSTEM_TIME_MONOTONIC);
5089 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
5090 .downTime(baseTime + 10)
5091 .eventTime(baseTime + 10)
5092 .pointer(PointerBuilder(0, ToolType::FINGER).x(100).y(100))
5093 .build());
5094
5095 window->consumeMotionEvent(WithMotionAction(ACTION_DOWN));
5096
Siarhei Vishniakouadb9fc92023-05-26 10:46:09 -07005097 // Change the transform so that the orientation is now different from original.
Siarhei Vishniakou700424c2023-07-18 17:18:42 -07005098 window->setWindowTransform(0, -1, 1, 0);
Siarhei Vishniakouadb9fc92023-05-26 10:46:09 -07005099
Siarhei Vishniakou700424c2023-07-18 17:18:42 -07005100 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Siarhei Vishniakouadb9fc92023-05-26 10:46:09 -07005101
Siarhei Vishniakouadb9fc92023-05-26 10:46:09 -07005102 mDispatcher->notifyMotion(MotionArgsBuilder(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
5103 .downTime(baseTime + 10)
5104 .eventTime(baseTime + 30)
5105 .pointer(PointerBuilder(0, ToolType::FINGER).x(100).y(100))
5106 .pointer(PointerBuilder(1, ToolType::FINGER).x(200).y(200))
5107 .build());
5108
Prabir Pradhan69d00bf2023-06-23 19:55:18 +00005109 window->consumeMotionEvent(WithMotionAction(POINTER_1_DOWN));
5110
5111 // Finish the gesture and start a new one. Ensure all events are sent to the window.
Siarhei Vishniakouadb9fc92023-05-26 10:46:09 -07005112 mDispatcher->notifyMotion(MotionArgsBuilder(POINTER_1_UP, AINPUT_SOURCE_TOUCHSCREEN)
5113 .downTime(baseTime + 10)
5114 .eventTime(baseTime + 40)
5115 .pointer(PointerBuilder(0, ToolType::FINGER).x(100).y(100))
5116 .pointer(PointerBuilder(1, ToolType::FINGER).x(200).y(200))
5117 .build());
Prabir Pradhan69d00bf2023-06-23 19:55:18 +00005118
5119 window->consumeMotionEvent(WithMotionAction(POINTER_1_UP));
5120
Siarhei Vishniakouadb9fc92023-05-26 10:46:09 -07005121 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN)
5122 .downTime(baseTime + 10)
5123 .eventTime(baseTime + 50)
5124 .pointer(PointerBuilder(0, ToolType::FINGER).x(100).y(100))
5125 .build());
5126
Prabir Pradhan69d00bf2023-06-23 19:55:18 +00005127 window->consumeMotionEvent(WithMotionAction(ACTION_UP));
5128
Siarhei Vishniakouadb9fc92023-05-26 10:46:09 -07005129 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
5130 .downTime(baseTime + 60)
5131 .eventTime(baseTime + 60)
5132 .pointer(PointerBuilder(0, ToolType::FINGER).x(40).y(40))
5133 .build());
5134
Siarhei Vishniakou700424c2023-07-18 17:18:42 -07005135 window->consumeMotionEvent(WithMotionAction(ACTION_DOWN));
Siarhei Vishniakouadb9fc92023-05-26 10:46:09 -07005136}
5137
5138/**
Hu Guo771a7692023-09-17 20:51:08 +08005139 * When there are multiple screens, such as screen projection to TV or screen recording, if the
5140 * cancel event occurs, the coordinates of the cancel event should be sent to the target screen, and
5141 * its coordinates should be converted by the transform of the windows of target screen.
5142 */
5143TEST_F(InputDispatcherTest, WhenMultiDisplayWindowSameToken_DispatchCancelToTargetDisplay) {
5144 // This case will create a window and a spy window on the default display and mirror
5145 // window on the second display. cancel event is sent through spy window pilferPointers
5146 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
5147
5148 sp<FakeWindowHandle> spyWindowDefaultDisplay =
5149 sp<FakeWindowHandle>::make(application, mDispatcher, "Spy", ADISPLAY_ID_DEFAULT);
5150 spyWindowDefaultDisplay->setTrustedOverlay(true);
5151 spyWindowDefaultDisplay->setSpy(true);
5152
5153 sp<FakeWindowHandle> windowDefaultDisplay =
5154 sp<FakeWindowHandle>::make(application, mDispatcher, "DefaultDisplay",
5155 ADISPLAY_ID_DEFAULT);
5156 windowDefaultDisplay->setWindowTransform(1, 0, 0, 1);
5157
5158 sp<FakeWindowHandle> windowSecondDisplay = windowDefaultDisplay->clone(SECOND_DISPLAY_ID);
5159 windowSecondDisplay->setWindowTransform(2, 0, 0, 2);
5160
5161 // Add the windows to the dispatcher
5162 mDispatcher->onWindowInfosChanged(
5163 {{*spyWindowDefaultDisplay->getInfo(), *windowDefaultDisplay->getInfo(),
5164 *windowSecondDisplay->getInfo()},
5165 {},
5166 0,
5167 0});
5168
5169 // Send down to ADISPLAY_ID_DEFAULT
5170 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
5171 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
5172 {100, 100}))
5173 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
5174
5175 spyWindowDefaultDisplay->consumeMotionDown();
5176 windowDefaultDisplay->consumeMotionDown();
5177
5178 EXPECT_EQ(OK, mDispatcher->pilferPointers(spyWindowDefaultDisplay->getToken()));
5179
5180 // windowDefaultDisplay gets cancel
Siarhei Vishniakoud3061ab2023-12-18 20:41:08 -08005181 std::unique_ptr<MotionEvent> event = windowDefaultDisplay->consumeMotionEvent();
5182 ASSERT_NE(nullptr, event);
5183 EXPECT_EQ(AMOTION_EVENT_ACTION_CANCEL, event->getAction());
Hu Guo771a7692023-09-17 20:51:08 +08005184
5185 // The cancel event is sent to windowDefaultDisplay of the ADISPLAY_ID_DEFAULT display, so the
5186 // coordinates of the cancel are converted by windowDefaultDisplay's transform, the x and y
5187 // coordinates are both 100, otherwise if the cancel event is sent to windowSecondDisplay of
5188 // SECOND_DISPLAY_ID, the x and y coordinates are 200
Siarhei Vishniakoud3061ab2023-12-18 20:41:08 -08005189 EXPECT_EQ(100, event->getX(0));
5190 EXPECT_EQ(100, event->getY(0));
Hu Guo771a7692023-09-17 20:51:08 +08005191}
5192
5193/**
Prabir Pradhanc44ce4d2021-10-05 05:26:29 -07005194 * Ensure the correct coordinate spaces are used by InputDispatcher.
5195 *
5196 * InputDispatcher works in the display space, so its coordinate system is relative to the display
5197 * panel. Windows get events in the window space, and get raw coordinates in the logical display
5198 * space.
5199 */
5200class InputDispatcherDisplayProjectionTest : public InputDispatcherTest {
5201public:
5202 void SetUp() override {
5203 InputDispatcherTest::SetUp();
Prabir Pradhan33e3baa2022-12-06 20:30:22 +00005204 removeAllWindowsAndDisplays();
Prabir Pradhanc44ce4d2021-10-05 05:26:29 -07005205 }
5206
5207 void addDisplayInfo(int displayId, const ui::Transform& transform) {
5208 gui::DisplayInfo info;
5209 info.displayId = displayId;
5210 info.transform = transform;
5211 mDisplayInfos.push_back(std::move(info));
Patrick Williamsd828f302023-04-28 17:52:08 -05005212 mDispatcher->onWindowInfosChanged({mWindowInfos, mDisplayInfos, 0, 0});
Prabir Pradhanc44ce4d2021-10-05 05:26:29 -07005213 }
5214
5215 void addWindow(const sp<WindowInfoHandle>& windowHandle) {
5216 mWindowInfos.push_back(*windowHandle->getInfo());
Patrick Williamsd828f302023-04-28 17:52:08 -05005217 mDispatcher->onWindowInfosChanged({mWindowInfos, mDisplayInfos, 0, 0});
Prabir Pradhanc44ce4d2021-10-05 05:26:29 -07005218 }
5219
Prabir Pradhan33e3baa2022-12-06 20:30:22 +00005220 void removeAllWindowsAndDisplays() {
5221 mDisplayInfos.clear();
5222 mWindowInfos.clear();
5223 }
5224
Prabir Pradhanc44ce4d2021-10-05 05:26:29 -07005225 // Set up a test scenario where the display has a scaled projection and there are two windows
5226 // on the display.
5227 std::pair<sp<FakeWindowHandle>, sp<FakeWindowHandle>> setupScaledDisplayScenario() {
5228 // The display has a projection that has a scale factor of 2 and 4 in the x and y directions
5229 // respectively.
5230 ui::Transform displayTransform;
5231 displayTransform.set(2, 0, 0, 4);
5232 addDisplayInfo(ADISPLAY_ID_DEFAULT, displayTransform);
5233
5234 std::shared_ptr<FakeApplicationHandle> application =
5235 std::make_shared<FakeApplicationHandle>();
5236
5237 // Add two windows to the display. Their frames are represented in the display space.
5238 sp<FakeWindowHandle> firstWindow =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07005239 sp<FakeWindowHandle>::make(application, mDispatcher, "First Window",
5240 ADISPLAY_ID_DEFAULT);
Prabir Pradhanc44ce4d2021-10-05 05:26:29 -07005241 firstWindow->setFrame(Rect(0, 0, 100, 200), displayTransform);
5242 addWindow(firstWindow);
5243
5244 sp<FakeWindowHandle> secondWindow =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07005245 sp<FakeWindowHandle>::make(application, mDispatcher, "Second Window",
5246 ADISPLAY_ID_DEFAULT);
Prabir Pradhanc44ce4d2021-10-05 05:26:29 -07005247 secondWindow->setFrame(Rect(100, 200, 200, 400), displayTransform);
5248 addWindow(secondWindow);
5249 return {std::move(firstWindow), std::move(secondWindow)};
5250 }
5251
5252private:
5253 std::vector<gui::DisplayInfo> mDisplayInfos;
5254 std::vector<gui::WindowInfo> mWindowInfos;
5255};
5256
Prabir Pradhan33e3baa2022-12-06 20:30:22 +00005257TEST_F(InputDispatcherDisplayProjectionTest, HitTestCoordinateSpaceConsistency) {
Prabir Pradhanc44ce4d2021-10-05 05:26:29 -07005258 auto [firstWindow, secondWindow] = setupScaledDisplayScenario();
5259 // Send down to the first window. The point is represented in the display space. The point is
Prabir Pradhan33e3baa2022-12-06 20:30:22 +00005260 // selected so that if the hit test was performed with the point and the bounds being in
5261 // different coordinate spaces, the event would end up in the incorrect window.
Prabir Pradhan678438e2023-04-13 19:32:51 +00005262 mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_DOWN,
5263 AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
5264 {PointF{75, 55}}));
Prabir Pradhanc44ce4d2021-10-05 05:26:29 -07005265
5266 firstWindow->consumeMotionDown();
5267 secondWindow->assertNoEvents();
5268}
5269
5270// Ensure that when a MotionEvent is injected through the InputDispatcher::injectInputEvent() API,
5271// the event should be treated as being in the logical display space.
5272TEST_F(InputDispatcherDisplayProjectionTest, InjectionInLogicalDisplaySpace) {
5273 auto [firstWindow, secondWindow] = setupScaledDisplayScenario();
5274 // Send down to the first window. The point is represented in the logical display space. The
5275 // point is selected so that if the hit test was done in logical display space, then it would
5276 // end up in the incorrect window.
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07005277 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
Prabir Pradhanc44ce4d2021-10-05 05:26:29 -07005278 PointF{75 * 2, 55 * 4});
5279
5280 firstWindow->consumeMotionDown();
5281 secondWindow->assertNoEvents();
5282}
5283
Prabir Pradhandaa2f142021-12-10 09:30:08 +00005284// Ensure that when a MotionEvent that has a custom transform is injected, the post-transformed
5285// event should be treated as being in the logical display space.
5286TEST_F(InputDispatcherDisplayProjectionTest, InjectionWithTransformInLogicalDisplaySpace) {
5287 auto [firstWindow, secondWindow] = setupScaledDisplayScenario();
5288
5289 const std::array<float, 9> matrix = {1.1, 2.2, 3.3, 4.4, 5.5, 6.6, 0.0, 0.0, 1.0};
5290 ui::Transform injectedEventTransform;
5291 injectedEventTransform.set(matrix);
5292 const vec2 expectedPoint{75, 55}; // The injected point in the logical display space.
5293 const vec2 untransformedPoint = injectedEventTransform.inverse().transform(expectedPoint);
5294
5295 MotionEvent event = MotionEventBuilder(AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
5296 .displayId(ADISPLAY_ID_DEFAULT)
5297 .eventTime(systemTime(SYSTEM_TIME_MONOTONIC))
Siarhei Vishniakou6d73f832022-07-21 17:27:03 -07005298 .pointer(PointerBuilder(/*id=*/0, ToolType::FINGER)
Prabir Pradhandaa2f142021-12-10 09:30:08 +00005299 .x(untransformedPoint.x)
5300 .y(untransformedPoint.y))
5301 .build();
5302 event.transform(matrix);
5303
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07005304 injectMotionEvent(*mDispatcher, event, INJECT_EVENT_TIMEOUT,
Prabir Pradhandaa2f142021-12-10 09:30:08 +00005305 InputEventInjectionSync::WAIT_FOR_RESULT);
5306
5307 firstWindow->consumeMotionDown();
5308 secondWindow->assertNoEvents();
5309}
5310
Prabir Pradhanc44ce4d2021-10-05 05:26:29 -07005311TEST_F(InputDispatcherDisplayProjectionTest, WindowGetsEventsInCorrectCoordinateSpace) {
5312 auto [firstWindow, secondWindow] = setupScaledDisplayScenario();
5313
5314 // Send down to the second window.
Prabir Pradhan678438e2023-04-13 19:32:51 +00005315 mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_DOWN,
5316 AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
5317 {PointF{150, 220}}));
Prabir Pradhanc44ce4d2021-10-05 05:26:29 -07005318
5319 firstWindow->assertNoEvents();
Siarhei Vishniakoud3061ab2023-12-18 20:41:08 -08005320 std::unique_ptr<MotionEvent> event = secondWindow->consumeMotionEvent();
5321 ASSERT_NE(nullptr, event);
5322 EXPECT_EQ(AMOTION_EVENT_ACTION_DOWN, event->getAction());
Prabir Pradhanc44ce4d2021-10-05 05:26:29 -07005323
5324 // Ensure that the events from the "getRaw" API are in logical display coordinates.
Siarhei Vishniakoud3061ab2023-12-18 20:41:08 -08005325 EXPECT_EQ(300, event->getRawX(0));
5326 EXPECT_EQ(880, event->getRawY(0));
Prabir Pradhanc44ce4d2021-10-05 05:26:29 -07005327
5328 // Ensure that the x and y values are in the window's coordinate space.
5329 // The left-top of the second window is at (100, 200) in display space, which is (200, 800) in
5330 // the logical display space. This will be the origin of the window space.
Siarhei Vishniakoud3061ab2023-12-18 20:41:08 -08005331 EXPECT_EQ(100, event->getX(0));
5332 EXPECT_EQ(80, event->getY(0));
Prabir Pradhanc44ce4d2021-10-05 05:26:29 -07005333}
5334
Prabir Pradhan112b1ad2023-09-21 09:53:53 +00005335TEST_F(InputDispatcherDisplayProjectionTest, CancelMotionWithCorrectCoordinates) {
5336 auto [firstWindow, secondWindow] = setupScaledDisplayScenario();
5337 // The monitor will always receive events in the logical display's coordinate space, because
5338 // it does not have a window.
Prabir Pradhanfb549072023-10-05 19:17:36 +00005339 FakeMonitorReceiver monitor{*mDispatcher, "Monitor", ADISPLAY_ID_DEFAULT};
Prabir Pradhan112b1ad2023-09-21 09:53:53 +00005340
5341 // Send down to the first window.
5342 mDispatcher->notifyMotion(generateMotionArgs(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN,
5343 ADISPLAY_ID_DEFAULT, {PointF{50, 100}}));
5344 firstWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithCoords(100, 400)));
5345 monitor.consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithCoords(100, 400)));
5346
5347 // Second pointer goes down on second window.
5348 mDispatcher->notifyMotion(generateMotionArgs(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN,
5349 ADISPLAY_ID_DEFAULT,
5350 {PointF{50, 100}, PointF{150, 220}}));
5351 secondWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithCoords(100, 80)));
5352 const std::map<int32_t, PointF> expectedMonitorPointers{{0, PointF{100, 400}},
5353 {1, PointF{300, 880}}};
5354 monitor.consumeMotionEvent(
5355 AllOf(WithMotionAction(POINTER_1_DOWN), WithPointers(expectedMonitorPointers)));
5356
5357 mDispatcher->cancelCurrentTouch();
5358
5359 firstWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_CANCEL), WithCoords(100, 400)));
5360 secondWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_CANCEL), WithCoords(100, 80)));
5361 monitor.consumeMotionEvent(
5362 AllOf(WithMotionAction(ACTION_CANCEL), WithPointers(expectedMonitorPointers)));
5363}
5364
Prabir Pradhan1c29a092023-09-21 10:29:29 +00005365TEST_F(InputDispatcherDisplayProjectionTest, SynthesizeDownWithCorrectCoordinates) {
5366 auto [firstWindow, secondWindow] = setupScaledDisplayScenario();
5367
5368 // Send down to the first window.
5369 mDispatcher->notifyMotion(generateMotionArgs(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN,
5370 ADISPLAY_ID_DEFAULT, {PointF{50, 100}}));
5371 firstWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithCoords(100, 400)));
5372
5373 // The pointer is transferred to the second window, and the second window receives it in the
5374 // correct coordinate space.
Prabir Pradhan367f3432024-02-13 23:05:58 +00005375 mDispatcher->transferTouchGesture(firstWindow->getToken(), secondWindow->getToken());
Prabir Pradhan1c29a092023-09-21 10:29:29 +00005376 firstWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_CANCEL), WithCoords(100, 400)));
5377 secondWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithCoords(-100, -400)));
5378}
5379
Prabir Pradhan0dfcac72023-10-05 20:04:21 +00005380TEST_F(InputDispatcherDisplayProjectionTest, SynthesizeHoverEnterExitWithCorrectCoordinates) {
5381 auto [firstWindow, secondWindow] = setupScaledDisplayScenario();
5382
5383 // Send hover move to the second window, and ensure it shows up as hover enter.
5384 mDispatcher->notifyMotion(generateMotionArgs(ACTION_HOVER_MOVE, AINPUT_SOURCE_STYLUS,
5385 ADISPLAY_ID_DEFAULT, {PointF{150, 220}}));
5386 secondWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_HOVER_ENTER),
5387 WithCoords(100, 80), WithRawCoords(300, 880)));
5388
5389 // Touch down at the same location and ensure a hover exit is synthesized.
5390 mDispatcher->notifyMotion(generateMotionArgs(ACTION_DOWN, AINPUT_SOURCE_STYLUS,
5391 ADISPLAY_ID_DEFAULT, {PointF{150, 220}}));
5392 secondWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_HOVER_EXIT), WithCoords(100, 80),
5393 WithRawCoords(300, 880)));
5394 secondWindow->consumeMotionEvent(
5395 AllOf(WithMotionAction(ACTION_DOWN), WithCoords(100, 80), WithRawCoords(300, 880)));
5396 secondWindow->assertNoEvents();
5397 firstWindow->assertNoEvents();
5398}
5399
Prabir Pradhan453ae732023-10-13 14:30:14 +00005400// Same as above, but while the window is being mirrored.
5401TEST_F(InputDispatcherDisplayProjectionTest,
5402 SynthesizeHoverEnterExitWithCorrectCoordinatesWhenMirrored) {
5403 auto [firstWindow, secondWindow] = setupScaledDisplayScenario();
5404
5405 const std::array<float, 9> matrix = {1.1, 2.2, 3.3, 4.4, 5.5, 6.6, 0.0, 0.0, 1.0};
5406 ui::Transform secondDisplayTransform;
5407 secondDisplayTransform.set(matrix);
5408 addDisplayInfo(SECOND_DISPLAY_ID, secondDisplayTransform);
5409
5410 sp<FakeWindowHandle> secondWindowClone = secondWindow->clone(SECOND_DISPLAY_ID);
5411 secondWindowClone->setWindowTransform(1.1, 2.2, 3.3, 4.4);
5412 addWindow(secondWindowClone);
5413
5414 // Send hover move to the second window, and ensure it shows up as hover enter.
5415 mDispatcher->notifyMotion(generateMotionArgs(ACTION_HOVER_MOVE, AINPUT_SOURCE_STYLUS,
5416 ADISPLAY_ID_DEFAULT, {PointF{150, 220}}));
5417 secondWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_HOVER_ENTER),
5418 WithCoords(100, 80), WithRawCoords(300, 880)));
5419
5420 // Touch down at the same location and ensure a hover exit is synthesized for the correct
5421 // display.
5422 mDispatcher->notifyMotion(generateMotionArgs(ACTION_DOWN, AINPUT_SOURCE_STYLUS,
5423 ADISPLAY_ID_DEFAULT, {PointF{150, 220}}));
5424 secondWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_HOVER_EXIT), WithCoords(100, 80),
5425 WithRawCoords(300, 880)));
5426 secondWindow->consumeMotionEvent(
5427 AllOf(WithMotionAction(ACTION_DOWN), WithCoords(100, 80), WithRawCoords(300, 880)));
5428 secondWindow->assertNoEvents();
5429 firstWindow->assertNoEvents();
5430}
5431
Prabir Pradhan0dfcac72023-10-05 20:04:21 +00005432TEST_F(InputDispatcherDisplayProjectionTest, SynthesizeHoverCancelationWithCorrectCoordinates) {
5433 auto [firstWindow, secondWindow] = setupScaledDisplayScenario();
5434
5435 // Send hover enter to second window
5436 mDispatcher->notifyMotion(generateMotionArgs(ACTION_HOVER_ENTER, AINPUT_SOURCE_STYLUS,
5437 ADISPLAY_ID_DEFAULT, {PointF{150, 220}}));
5438 secondWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_HOVER_ENTER),
5439 WithCoords(100, 80), WithRawCoords(300, 880)));
5440
5441 mDispatcher->cancelCurrentTouch();
5442
5443 secondWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_HOVER_EXIT), WithCoords(100, 80),
5444 WithRawCoords(300, 880)));
5445 secondWindow->assertNoEvents();
5446 firstWindow->assertNoEvents();
5447}
5448
Prabir Pradhan453ae732023-10-13 14:30:14 +00005449// Same as above, but while the window is being mirrored.
Prabir Pradhan16463382023-10-12 23:03:19 +00005450TEST_F(InputDispatcherDisplayProjectionTest,
5451 SynthesizeHoverCancelationWithCorrectCoordinatesWhenMirrored) {
5452 auto [firstWindow, secondWindow] = setupScaledDisplayScenario();
5453
5454 const std::array<float, 9> matrix = {1.1, 2.2, 3.3, 4.4, 5.5, 6.6, 0.0, 0.0, 1.0};
5455 ui::Transform secondDisplayTransform;
5456 secondDisplayTransform.set(matrix);
5457 addDisplayInfo(SECOND_DISPLAY_ID, secondDisplayTransform);
5458
5459 sp<FakeWindowHandle> secondWindowClone = secondWindow->clone(SECOND_DISPLAY_ID);
5460 secondWindowClone->setWindowTransform(1.1, 2.2, 3.3, 4.4);
5461 addWindow(secondWindowClone);
5462
5463 // Send hover enter to second window
5464 mDispatcher->notifyMotion(generateMotionArgs(ACTION_HOVER_ENTER, AINPUT_SOURCE_STYLUS,
5465 ADISPLAY_ID_DEFAULT, {PointF{150, 220}}));
5466 secondWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_HOVER_ENTER),
5467 WithCoords(100, 80), WithRawCoords(300, 880),
5468 WithDisplayId(ADISPLAY_ID_DEFAULT)));
5469
5470 mDispatcher->cancelCurrentTouch();
5471
5472 // Ensure the cancelation happens with the correct displayId and the correct coordinates.
5473 secondWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_HOVER_EXIT), WithCoords(100, 80),
5474 WithRawCoords(300, 880),
5475 WithDisplayId(ADISPLAY_ID_DEFAULT)));
5476 secondWindow->assertNoEvents();
5477 firstWindow->assertNoEvents();
5478}
5479
Prabir Pradhan33e3baa2022-12-06 20:30:22 +00005480/** Ensure consistent behavior of InputDispatcher in all orientations. */
5481class InputDispatcherDisplayOrientationFixture
5482 : public InputDispatcherDisplayProjectionTest,
5483 public ::testing::WithParamInterface<ui::Rotation> {};
5484
5485// This test verifies the touchable region of a window for all rotations of the display by tapping
5486// in different locations on the display, specifically points close to the four corners of a
5487// window.
5488TEST_P(InputDispatcherDisplayOrientationFixture, HitTestInDifferentOrientations) {
5489 constexpr static int32_t displayWidth = 400;
5490 constexpr static int32_t displayHeight = 800;
5491
5492 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
5493
5494 const auto rotation = GetParam();
5495
5496 // Set up the display with the specified rotation.
5497 const bool isRotated = rotation == ui::ROTATION_90 || rotation == ui::ROTATION_270;
5498 const int32_t logicalDisplayWidth = isRotated ? displayHeight : displayWidth;
5499 const int32_t logicalDisplayHeight = isRotated ? displayWidth : displayHeight;
5500 const ui::Transform displayTransform(ui::Transform::toRotationFlags(rotation),
5501 logicalDisplayWidth, logicalDisplayHeight);
5502 addDisplayInfo(ADISPLAY_ID_DEFAULT, displayTransform);
5503
5504 // Create a window with its bounds determined in the logical display.
5505 const Rect frameInLogicalDisplay(100, 100, 200, 300);
5506 const Rect frameInDisplay = displayTransform.inverse().transform(frameInLogicalDisplay);
5507 sp<FakeWindowHandle> window =
5508 sp<FakeWindowHandle>::make(application, mDispatcher, "Window", ADISPLAY_ID_DEFAULT);
5509 window->setFrame(frameInDisplay, displayTransform);
5510 addWindow(window);
5511
5512 // The following points in logical display space should be inside the window.
5513 static const std::array<vec2, 4> insidePoints{
5514 {{100, 100}, {199.99, 100}, {100, 299.99}, {199.99, 299.99}}};
5515 for (const auto pointInsideWindow : insidePoints) {
5516 const vec2 p = displayTransform.inverse().transform(pointInsideWindow);
5517 const PointF pointInDisplaySpace{p.x, p.y};
Prabir Pradhan678438e2023-04-13 19:32:51 +00005518 mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_DOWN,
5519 AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
5520 {pointInDisplaySpace}));
Prabir Pradhan33e3baa2022-12-06 20:30:22 +00005521 window->consumeMotionDown();
5522
Prabir Pradhan678438e2023-04-13 19:32:51 +00005523 mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_UP,
5524 AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
5525 {pointInDisplaySpace}));
Prabir Pradhan33e3baa2022-12-06 20:30:22 +00005526 window->consumeMotionUp();
5527 }
5528
5529 // The following points in logical display space should be outside the window.
5530 static const std::array<vec2, 5> outsidePoints{
5531 {{200, 100}, {100, 300}, {200, 300}, {100, 99.99}, {99.99, 100}}};
5532 for (const auto pointOutsideWindow : outsidePoints) {
5533 const vec2 p = displayTransform.inverse().transform(pointOutsideWindow);
5534 const PointF pointInDisplaySpace{p.x, p.y};
Prabir Pradhan678438e2023-04-13 19:32:51 +00005535 mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_DOWN,
5536 AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
5537 {pointInDisplaySpace}));
Prabir Pradhan33e3baa2022-12-06 20:30:22 +00005538
Prabir Pradhan678438e2023-04-13 19:32:51 +00005539 mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_UP,
5540 AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
5541 {pointInDisplaySpace}));
Prabir Pradhan33e3baa2022-12-06 20:30:22 +00005542 }
5543 window->assertNoEvents();
5544}
5545
Linnan Li5e5645e2024-03-05 14:43:05 +00005546// This test verifies the occlusion detection for all rotations of the display by tapping
5547// in different locations on the display, specifically points close to the four corners of a
5548// window.
5549TEST_P(InputDispatcherDisplayOrientationFixture, BlockUntrustClickInDifferentOrientations) {
5550 constexpr static int32_t displayWidth = 400;
5551 constexpr static int32_t displayHeight = 800;
5552
5553 std::shared_ptr<FakeApplicationHandle> untrustedWindowApplication =
5554 std::make_shared<FakeApplicationHandle>();
5555 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
5556
5557 const auto rotation = GetParam();
5558
5559 // Set up the display with the specified rotation.
5560 const bool isRotated = rotation == ui::ROTATION_90 || rotation == ui::ROTATION_270;
5561 const int32_t logicalDisplayWidth = isRotated ? displayHeight : displayWidth;
5562 const int32_t logicalDisplayHeight = isRotated ? displayWidth : displayHeight;
5563 const ui::Transform displayTransform(ui::Transform::toRotationFlags(rotation),
5564 logicalDisplayWidth, logicalDisplayHeight);
5565 addDisplayInfo(ADISPLAY_ID_DEFAULT, displayTransform);
5566
5567 // Create a window that not trusted.
5568 const Rect untrustedWindowFrameInLogicalDisplay(100, 100, 200, 300);
5569
5570 const Rect untrustedWindowFrameInDisplay =
5571 displayTransform.inverse().transform(untrustedWindowFrameInLogicalDisplay);
5572
5573 sp<FakeWindowHandle> untrustedWindow =
5574 sp<FakeWindowHandle>::make(untrustedWindowApplication, mDispatcher, "UntrustedWindow",
5575 ADISPLAY_ID_DEFAULT);
5576 untrustedWindow->setFrame(untrustedWindowFrameInDisplay, displayTransform);
5577 untrustedWindow->setTrustedOverlay(false);
5578 untrustedWindow->setTouchOcclusionMode(TouchOcclusionMode::BLOCK_UNTRUSTED);
5579 untrustedWindow->setTouchable(false);
5580 untrustedWindow->setAlpha(1.0f);
5581 untrustedWindow->setOwnerInfo(gui::Pid{1}, gui::Uid{101});
5582 addWindow(untrustedWindow);
5583
5584 // Create a simple app window below the untrusted window.
5585 const Rect simpleAppWindowFrameInLogicalDisplay(0, 0, 300, 600);
5586 const Rect simpleAppWindowFrameInDisplay =
5587 displayTransform.inverse().transform(simpleAppWindowFrameInLogicalDisplay);
5588
5589 sp<FakeWindowHandle> simpleAppWindow =
5590 sp<FakeWindowHandle>::make(application, mDispatcher, "SimpleAppWindow",
5591 ADISPLAY_ID_DEFAULT);
5592 simpleAppWindow->setFrame(simpleAppWindowFrameInDisplay, displayTransform);
5593 simpleAppWindow->setOwnerInfo(gui::Pid{2}, gui::Uid{202});
5594 addWindow(simpleAppWindow);
5595
5596 // The following points in logical display space should be inside the untrusted window, so
5597 // the simple window could not receive events that coordinate is these point.
5598 static const std::array<vec2, 4> untrustedPoints{
5599 {{100, 100}, {199.99, 100}, {100, 299.99}, {199.99, 299.99}}};
5600
5601 for (const auto untrustedPoint : untrustedPoints) {
5602 const vec2 p = displayTransform.inverse().transform(untrustedPoint);
5603 const PointF pointInDisplaySpace{p.x, p.y};
5604 mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_DOWN,
5605 AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
5606 {pointInDisplaySpace}));
5607 mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_UP,
5608 AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
5609 {pointInDisplaySpace}));
5610 }
5611 untrustedWindow->assertNoEvents();
5612 simpleAppWindow->assertNoEvents();
5613 // The following points in logical display space should be outside the untrusted window, so
5614 // the simple window should receive events that coordinate is these point.
5615 static const std::array<vec2, 5> trustedPoints{
5616 {{200, 100}, {100, 300}, {200, 300}, {100, 99.99}, {99.99, 100}}};
5617 for (const auto trustedPoint : trustedPoints) {
5618 const vec2 p = displayTransform.inverse().transform(trustedPoint);
5619 const PointF pointInDisplaySpace{p.x, p.y};
5620 mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_DOWN,
5621 AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
5622 {pointInDisplaySpace}));
5623 simpleAppWindow->consumeMotionDown(ADISPLAY_ID_DEFAULT,
5624 AMOTION_EVENT_FLAG_WINDOW_IS_PARTIALLY_OBSCURED);
5625 mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_UP,
5626 AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
5627 {pointInDisplaySpace}));
5628 simpleAppWindow->consumeMotionUp(ADISPLAY_ID_DEFAULT,
5629 AMOTION_EVENT_FLAG_WINDOW_IS_PARTIALLY_OBSCURED);
5630 }
5631 untrustedWindow->assertNoEvents();
5632}
5633
Prabir Pradhan33e3baa2022-12-06 20:30:22 +00005634// Run the precision tests for all rotations.
5635INSTANTIATE_TEST_SUITE_P(InputDispatcherDisplayOrientationTests,
5636 InputDispatcherDisplayOrientationFixture,
5637 ::testing::Values(ui::ROTATION_0, ui::ROTATION_90, ui::ROTATION_180,
5638 ui::ROTATION_270),
5639 [](const testing::TestParamInfo<ui::Rotation>& testParamInfo) {
5640 return ftl::enum_string(testParamInfo.param);
5641 });
5642
Siarhei Vishniakou18050092021-09-01 13:32:49 -07005643using TransferFunction = std::function<bool(const std::unique_ptr<InputDispatcher>& dispatcher,
5644 sp<IBinder>, sp<IBinder>)>;
Siarhei Vishniakoud0c6bc82021-03-13 03:14:52 +00005645
5646class TransferTouchFixture : public InputDispatcherTest,
5647 public ::testing::WithParamInterface<TransferFunction> {};
5648
5649TEST_P(TransferTouchFixture, TransferTouch_OnePointer) {
Chris Yea209fde2020-07-22 13:54:51 -07005650 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
Svet Ganov5d3bc372020-01-26 23:11:07 -08005651
5652 // Create a couple of windows
Siarhei Vishniakou870ecec2020-12-09 08:07:46 -10005653 sp<FakeWindowHandle> firstWindow =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07005654 sp<FakeWindowHandle>::make(application, mDispatcher, "First Window",
5655 ADISPLAY_ID_DEFAULT);
Arthur Hungc539dbb2022-12-08 07:45:36 +00005656 firstWindow->setDupTouchToWallpaper(true);
Siarhei Vishniakou870ecec2020-12-09 08:07:46 -10005657 sp<FakeWindowHandle> secondWindow =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07005658 sp<FakeWindowHandle>::make(application, mDispatcher, "Second Window",
5659 ADISPLAY_ID_DEFAULT);
Arthur Hungc539dbb2022-12-08 07:45:36 +00005660 sp<FakeWindowHandle> wallpaper =
5661 sp<FakeWindowHandle>::make(application, mDispatcher, "Wallpaper", ADISPLAY_ID_DEFAULT);
5662 wallpaper->setIsWallpaper(true);
Prabir Pradhan65455c72024-02-13 21:46:41 +00005663 // Add the windows to the dispatcher, and ensure the first window is focused
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07005664 mDispatcher->onWindowInfosChanged(
5665 {{*firstWindow->getInfo(), *secondWindow->getInfo(), *wallpaper->getInfo()}, {}, 0, 0});
Prabir Pradhan65455c72024-02-13 21:46:41 +00005666 setFocusedWindow(firstWindow);
5667 firstWindow->consumeFocusEvent(true);
Svet Ganov5d3bc372020-01-26 23:11:07 -08005668
5669 // Send down to the first window
Prabir Pradhan678438e2023-04-13 19:32:51 +00005670 mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_DOWN,
5671 AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT));
Arthur Hungc539dbb2022-12-08 07:45:36 +00005672
Svet Ganov5d3bc372020-01-26 23:11:07 -08005673 // Only the first window should get the down event
5674 firstWindow->consumeMotionDown();
5675 secondWindow->assertNoEvents();
Arthur Hungc539dbb2022-12-08 07:45:36 +00005676 wallpaper->consumeMotionDown(ADISPLAY_ID_DEFAULT, expectedWallpaperFlags);
Prabir Pradhan65455c72024-02-13 21:46:41 +00005677 // Dispatcher reports pointer down outside focus for the wallpaper
5678 mFakePolicy->assertOnPointerDownEquals(wallpaper->getToken());
Svet Ganov5d3bc372020-01-26 23:11:07 -08005679
Siarhei Vishniakoud0c6bc82021-03-13 03:14:52 +00005680 // Transfer touch to the second window
5681 TransferFunction f = GetParam();
5682 const bool success = f(mDispatcher, firstWindow->getToken(), secondWindow->getToken());
5683 ASSERT_TRUE(success);
Svet Ganov5d3bc372020-01-26 23:11:07 -08005684 // The first window gets cancel and the second gets down
5685 firstWindow->consumeMotionCancel();
Prabir Pradhan65455c72024-02-13 21:46:41 +00005686 secondWindow->consumeMotionDown(ADISPLAY_ID_DEFAULT, AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
Arthur Hungc539dbb2022-12-08 07:45:36 +00005687 wallpaper->consumeMotionCancel(ADISPLAY_ID_DEFAULT, expectedWallpaperFlags);
Prabir Pradhan65455c72024-02-13 21:46:41 +00005688 // There should not be any changes to the focused window when transferring touch
5689 ASSERT_NO_FATAL_FAILURE(mFakePolicy->assertOnPointerDownWasNotCalled());
Svet Ganov5d3bc372020-01-26 23:11:07 -08005690
5691 // Send up event to the second window
Prabir Pradhan678438e2023-04-13 19:32:51 +00005692 mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN,
5693 ADISPLAY_ID_DEFAULT));
Prabir Pradhan65455c72024-02-13 21:46:41 +00005694 // The first window gets no events and the second gets up
Svet Ganov5d3bc372020-01-26 23:11:07 -08005695 firstWindow->assertNoEvents();
Prabir Pradhan65455c72024-02-13 21:46:41 +00005696 secondWindow->consumeMotionUp(ADISPLAY_ID_DEFAULT, AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
Arthur Hungc539dbb2022-12-08 07:45:36 +00005697 wallpaper->assertNoEvents();
Svet Ganov5d3bc372020-01-26 23:11:07 -08005698}
5699
Siarhei Vishniakou7ae7afd2022-03-31 15:26:13 -07005700/**
Prabir Pradhan367f3432024-02-13 23:05:58 +00005701 * When 'transferTouchGesture' API is invoked, dispatcher needs to find the "best" window to take
5702 * touch from. When we have spy windows, there are several windows to choose from: either spy, or
5703 * the 'real' (non-spy) window. Always prefer the 'real' window because that's what would be most
Siarhei Vishniakou7ae7afd2022-03-31 15:26:13 -07005704 * natural to the user.
5705 * In this test, we are sending a pointer to both spy window and first window. We then try to
5706 * transfer touch to the second window. The dispatcher should identify the first window as the
5707 * one that should lose the gesture, and therefore the action should be to move the gesture from
5708 * the first window to the second.
Prabir Pradhan367f3432024-02-13 23:05:58 +00005709 * The main goal here is to test the behaviour of 'transferTouchGesture' API, but it's still valid
5710 * to test the other API, as well.
Siarhei Vishniakou7ae7afd2022-03-31 15:26:13 -07005711 */
5712TEST_P(TransferTouchFixture, TransferTouch_MultipleWindowsWithSpy) {
5713 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
5714
5715 // Create a couple of windows + a spy window
5716 sp<FakeWindowHandle> spyWindow =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07005717 sp<FakeWindowHandle>::make(application, mDispatcher, "Spy", ADISPLAY_ID_DEFAULT);
Siarhei Vishniakou7ae7afd2022-03-31 15:26:13 -07005718 spyWindow->setTrustedOverlay(true);
5719 spyWindow->setSpy(true);
5720 sp<FakeWindowHandle> firstWindow =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07005721 sp<FakeWindowHandle>::make(application, mDispatcher, "First", ADISPLAY_ID_DEFAULT);
Siarhei Vishniakou7ae7afd2022-03-31 15:26:13 -07005722 sp<FakeWindowHandle> secondWindow =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07005723 sp<FakeWindowHandle>::make(application, mDispatcher, "Second", ADISPLAY_ID_DEFAULT);
Siarhei Vishniakou7ae7afd2022-03-31 15:26:13 -07005724
5725 // Add the windows to the dispatcher
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07005726 mDispatcher->onWindowInfosChanged(
5727 {{*spyWindow->getInfo(), *firstWindow->getInfo(), *secondWindow->getInfo()}, {}, 0, 0});
Siarhei Vishniakou7ae7afd2022-03-31 15:26:13 -07005728
5729 // Send down to the first window
Prabir Pradhan678438e2023-04-13 19:32:51 +00005730 mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_DOWN,
5731 AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT));
Siarhei Vishniakou7ae7afd2022-03-31 15:26:13 -07005732 // Only the first window and spy should get the down event
5733 spyWindow->consumeMotionDown();
5734 firstWindow->consumeMotionDown();
5735
5736 // Transfer touch to the second window. Non-spy window should be preferred over the spy window
Prabir Pradhan367f3432024-02-13 23:05:58 +00005737 // if f === 'transferTouchGesture'.
Siarhei Vishniakou7ae7afd2022-03-31 15:26:13 -07005738 TransferFunction f = GetParam();
5739 const bool success = f(mDispatcher, firstWindow->getToken(), secondWindow->getToken());
5740 ASSERT_TRUE(success);
5741 // The first window gets cancel and the second gets down
5742 firstWindow->consumeMotionCancel();
Prabir Pradhan65455c72024-02-13 21:46:41 +00005743 secondWindow->consumeMotionDown(ADISPLAY_ID_DEFAULT, AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
Siarhei Vishniakou7ae7afd2022-03-31 15:26:13 -07005744
5745 // Send up event to the second window
Prabir Pradhan678438e2023-04-13 19:32:51 +00005746 mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN,
5747 ADISPLAY_ID_DEFAULT));
Siarhei Vishniakou7ae7afd2022-03-31 15:26:13 -07005748 // The first window gets no events and the second+spy get up
5749 firstWindow->assertNoEvents();
5750 spyWindow->consumeMotionUp();
Prabir Pradhan65455c72024-02-13 21:46:41 +00005751 secondWindow->consumeMotionUp(ADISPLAY_ID_DEFAULT, AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
Siarhei Vishniakou7ae7afd2022-03-31 15:26:13 -07005752}
5753
Siarhei Vishniakoud0c6bc82021-03-13 03:14:52 +00005754TEST_P(TransferTouchFixture, TransferTouch_TwoPointersNonSplitTouch) {
Chris Yea209fde2020-07-22 13:54:51 -07005755 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
Svet Ganov5d3bc372020-01-26 23:11:07 -08005756
5757 PointF touchPoint = {10, 10};
5758
5759 // Create a couple of windows
Siarhei Vishniakou870ecec2020-12-09 08:07:46 -10005760 sp<FakeWindowHandle> firstWindow =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07005761 sp<FakeWindowHandle>::make(application, mDispatcher, "First Window",
5762 ADISPLAY_ID_DEFAULT);
Prabir Pradhan76bdecb2022-01-31 11:14:15 -08005763 firstWindow->setPreventSplitting(true);
Siarhei Vishniakou870ecec2020-12-09 08:07:46 -10005764 sp<FakeWindowHandle> secondWindow =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07005765 sp<FakeWindowHandle>::make(application, mDispatcher, "Second Window",
5766 ADISPLAY_ID_DEFAULT);
Prabir Pradhan76bdecb2022-01-31 11:14:15 -08005767 secondWindow->setPreventSplitting(true);
Svet Ganov5d3bc372020-01-26 23:11:07 -08005768
5769 // Add the windows to the dispatcher
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07005770 mDispatcher->onWindowInfosChanged(
5771 {{*firstWindow->getInfo(), *secondWindow->getInfo()}, {}, 0, 0});
Svet Ganov5d3bc372020-01-26 23:11:07 -08005772
5773 // Send down to the first window
Prabir Pradhan678438e2023-04-13 19:32:51 +00005774 mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_DOWN,
5775 AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
5776 {touchPoint}));
Svet Ganov5d3bc372020-01-26 23:11:07 -08005777 // Only the first window should get the down event
5778 firstWindow->consumeMotionDown();
5779 secondWindow->assertNoEvents();
5780
5781 // Send pointer down to the first window
Prabir Pradhan678438e2023-04-13 19:32:51 +00005782 mDispatcher->notifyMotion(generateMotionArgs(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN,
5783 ADISPLAY_ID_DEFAULT, {touchPoint, touchPoint}));
Svet Ganov5d3bc372020-01-26 23:11:07 -08005784 // Only the first window should get the pointer down event
5785 firstWindow->consumeMotionPointerDown(1);
5786 secondWindow->assertNoEvents();
5787
5788 // Transfer touch focus to the second window
Siarhei Vishniakoud0c6bc82021-03-13 03:14:52 +00005789 TransferFunction f = GetParam();
5790 bool success = f(mDispatcher, firstWindow->getToken(), secondWindow->getToken());
5791 ASSERT_TRUE(success);
Svet Ganov5d3bc372020-01-26 23:11:07 -08005792 // The first window gets cancel and the second gets down and pointer down
5793 firstWindow->consumeMotionCancel();
Prabir Pradhan65455c72024-02-13 21:46:41 +00005794 secondWindow->consumeMotionDown(ADISPLAY_ID_DEFAULT, AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
5795 secondWindow->consumeMotionPointerDown(1, ADISPLAY_ID_DEFAULT,
5796 AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
Svet Ganov5d3bc372020-01-26 23:11:07 -08005797
5798 // Send pointer up to the second window
Prabir Pradhan678438e2023-04-13 19:32:51 +00005799 mDispatcher->notifyMotion(generateMotionArgs(POINTER_1_UP, AINPUT_SOURCE_TOUCHSCREEN,
5800 ADISPLAY_ID_DEFAULT, {touchPoint, touchPoint}));
Svet Ganov5d3bc372020-01-26 23:11:07 -08005801 // The first window gets nothing and the second gets pointer up
5802 firstWindow->assertNoEvents();
Prabir Pradhan65455c72024-02-13 21:46:41 +00005803 secondWindow->consumeMotionPointerUp(1, ADISPLAY_ID_DEFAULT,
5804 AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
Svet Ganov5d3bc372020-01-26 23:11:07 -08005805
5806 // Send up event to the second window
Prabir Pradhan678438e2023-04-13 19:32:51 +00005807 mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN,
5808 ADISPLAY_ID_DEFAULT));
Svet Ganov5d3bc372020-01-26 23:11:07 -08005809 // The first window gets nothing and the second gets up
5810 firstWindow->assertNoEvents();
Prabir Pradhan65455c72024-02-13 21:46:41 +00005811 secondWindow->consumeMotionUp(ADISPLAY_ID_DEFAULT, AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
Svet Ganov5d3bc372020-01-26 23:11:07 -08005812}
5813
Arthur Hungc539dbb2022-12-08 07:45:36 +00005814TEST_P(TransferTouchFixture, TransferTouch_MultipleWallpapers) {
5815 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
5816
5817 // Create a couple of windows
5818 sp<FakeWindowHandle> firstWindow =
5819 sp<FakeWindowHandle>::make(application, mDispatcher, "First Window",
5820 ADISPLAY_ID_DEFAULT);
5821 firstWindow->setDupTouchToWallpaper(true);
5822 sp<FakeWindowHandle> secondWindow =
5823 sp<FakeWindowHandle>::make(application, mDispatcher, "Second Window",
5824 ADISPLAY_ID_DEFAULT);
5825 secondWindow->setDupTouchToWallpaper(true);
5826
5827 sp<FakeWindowHandle> wallpaper1 =
5828 sp<FakeWindowHandle>::make(application, mDispatcher, "Wallpaper1", ADISPLAY_ID_DEFAULT);
5829 wallpaper1->setIsWallpaper(true);
5830
5831 sp<FakeWindowHandle> wallpaper2 =
5832 sp<FakeWindowHandle>::make(application, mDispatcher, "Wallpaper2", ADISPLAY_ID_DEFAULT);
5833 wallpaper2->setIsWallpaper(true);
5834 // Add the windows to the dispatcher
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07005835 mDispatcher->onWindowInfosChanged({{*firstWindow->getInfo(), *wallpaper1->getInfo(),
5836 *secondWindow->getInfo(), *wallpaper2->getInfo()},
5837 {},
5838 0,
5839 0});
Arthur Hungc539dbb2022-12-08 07:45:36 +00005840
5841 // Send down to the first window
Prabir Pradhan678438e2023-04-13 19:32:51 +00005842 mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_DOWN,
5843 AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT));
Arthur Hungc539dbb2022-12-08 07:45:36 +00005844
5845 // Only the first window should get the down event
5846 firstWindow->consumeMotionDown();
5847 secondWindow->assertNoEvents();
5848 wallpaper1->consumeMotionDown(ADISPLAY_ID_DEFAULT, expectedWallpaperFlags);
5849 wallpaper2->assertNoEvents();
5850
5851 // Transfer touch focus to the second window
5852 TransferFunction f = GetParam();
5853 bool success = f(mDispatcher, firstWindow->getToken(), secondWindow->getToken());
5854 ASSERT_TRUE(success);
5855
5856 // The first window gets cancel and the second gets down
5857 firstWindow->consumeMotionCancel();
Prabir Pradhan65455c72024-02-13 21:46:41 +00005858 secondWindow->consumeMotionDown(ADISPLAY_ID_DEFAULT, AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
Arthur Hungc539dbb2022-12-08 07:45:36 +00005859 wallpaper1->consumeMotionCancel(ADISPLAY_ID_DEFAULT, expectedWallpaperFlags);
Prabir Pradhan65455c72024-02-13 21:46:41 +00005860 wallpaper2->consumeMotionDown(ADISPLAY_ID_DEFAULT,
5861 expectedWallpaperFlags | AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
Arthur Hungc539dbb2022-12-08 07:45:36 +00005862
5863 // Send up event to the second window
Prabir Pradhan678438e2023-04-13 19:32:51 +00005864 mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN,
5865 ADISPLAY_ID_DEFAULT));
Arthur Hungc539dbb2022-12-08 07:45:36 +00005866 // The first window gets no events and the second gets up
5867 firstWindow->assertNoEvents();
Prabir Pradhan65455c72024-02-13 21:46:41 +00005868 secondWindow->consumeMotionUp(ADISPLAY_ID_DEFAULT, AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
Arthur Hungc539dbb2022-12-08 07:45:36 +00005869 wallpaper1->assertNoEvents();
Prabir Pradhan65455c72024-02-13 21:46:41 +00005870 wallpaper2->consumeMotionUp(ADISPLAY_ID_DEFAULT,
5871 expectedWallpaperFlags | AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
Arthur Hungc539dbb2022-12-08 07:45:36 +00005872}
5873
Siarhei Vishniakoud0c6bc82021-03-13 03:14:52 +00005874// For the cases of single pointer touch and two pointers non-split touch, the api's
Prabir Pradhan367f3432024-02-13 23:05:58 +00005875// 'transferTouchGesture' and 'transferTouchOnDisplay' are equivalent in behaviour. They only differ
Siarhei Vishniakoud0c6bc82021-03-13 03:14:52 +00005876// for the case where there are multiple pointers split across several windows.
Prabir Pradhan367f3432024-02-13 23:05:58 +00005877INSTANTIATE_TEST_SUITE_P(
5878 InputDispatcherTransferFunctionTests, TransferTouchFixture,
5879 ::testing::Values(
5880 [&](const std::unique_ptr<InputDispatcher>& dispatcher, sp<IBinder> /*ignored*/,
5881 sp<IBinder> destChannelToken) {
5882 return dispatcher->transferTouchOnDisplay(destChannelToken,
5883 ADISPLAY_ID_DEFAULT);
5884 },
5885 [&](const std::unique_ptr<InputDispatcher>& dispatcher, sp<IBinder> from,
5886 sp<IBinder> to) {
5887 return dispatcher->transferTouchGesture(from, to,
5888 /*isDragAndDrop=*/false);
5889 }));
Siarhei Vishniakoud0c6bc82021-03-13 03:14:52 +00005890
Prabir Pradhan367f3432024-02-13 23:05:58 +00005891TEST_F(InputDispatcherTest, TransferTouch_TwoPointersSplitTouch) {
Chris Yea209fde2020-07-22 13:54:51 -07005892 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
Svet Ganov5d3bc372020-01-26 23:11:07 -08005893
Siarhei Vishniakou870ecec2020-12-09 08:07:46 -10005894 sp<FakeWindowHandle> firstWindow =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07005895 sp<FakeWindowHandle>::make(application, mDispatcher, "First Window",
5896 ADISPLAY_ID_DEFAULT);
Svet Ganov5d3bc372020-01-26 23:11:07 -08005897 firstWindow->setFrame(Rect(0, 0, 600, 400));
Svet Ganov5d3bc372020-01-26 23:11:07 -08005898
Siarhei Vishniakou870ecec2020-12-09 08:07:46 -10005899 sp<FakeWindowHandle> secondWindow =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07005900 sp<FakeWindowHandle>::make(application, mDispatcher, "Second Window",
5901 ADISPLAY_ID_DEFAULT);
Svet Ganov5d3bc372020-01-26 23:11:07 -08005902 secondWindow->setFrame(Rect(0, 400, 600, 800));
Svet Ganov5d3bc372020-01-26 23:11:07 -08005903
5904 // Add the windows to the dispatcher
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07005905 mDispatcher->onWindowInfosChanged(
5906 {{*firstWindow->getInfo(), *secondWindow->getInfo()}, {}, 0, 0});
Svet Ganov5d3bc372020-01-26 23:11:07 -08005907
5908 PointF pointInFirst = {300, 200};
5909 PointF pointInSecond = {300, 600};
5910
5911 // Send down to the first window
Prabir Pradhan678438e2023-04-13 19:32:51 +00005912 mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_DOWN,
5913 AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
5914 {pointInFirst}));
Svet Ganov5d3bc372020-01-26 23:11:07 -08005915 // Only the first window should get the down event
5916 firstWindow->consumeMotionDown();
5917 secondWindow->assertNoEvents();
5918
5919 // Send down to the second window
Prabir Pradhan678438e2023-04-13 19:32:51 +00005920 mDispatcher->notifyMotion(generateMotionArgs(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN,
5921 ADISPLAY_ID_DEFAULT,
5922 {pointInFirst, pointInSecond}));
Svet Ganov5d3bc372020-01-26 23:11:07 -08005923 // The first window gets a move and the second a down
5924 firstWindow->consumeMotionMove();
5925 secondWindow->consumeMotionDown();
5926
Prabir Pradhan367f3432024-02-13 23:05:58 +00005927 // Transfer touch to the second window
5928 mDispatcher->transferTouchGesture(firstWindow->getToken(), secondWindow->getToken());
Svet Ganov5d3bc372020-01-26 23:11:07 -08005929 // The first window gets cancel and the new gets pointer down (it already saw down)
5930 firstWindow->consumeMotionCancel();
Prabir Pradhan65455c72024-02-13 21:46:41 +00005931 secondWindow->consumeMotionPointerDown(1, ADISPLAY_ID_DEFAULT,
5932 AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
Svet Ganov5d3bc372020-01-26 23:11:07 -08005933
5934 // Send pointer up to the second window
Prabir Pradhan678438e2023-04-13 19:32:51 +00005935 mDispatcher->notifyMotion(generateMotionArgs(POINTER_1_UP, AINPUT_SOURCE_TOUCHSCREEN,
5936 ADISPLAY_ID_DEFAULT,
5937 {pointInFirst, pointInSecond}));
Svet Ganov5d3bc372020-01-26 23:11:07 -08005938 // The first window gets nothing and the second gets pointer up
5939 firstWindow->assertNoEvents();
Prabir Pradhan65455c72024-02-13 21:46:41 +00005940 secondWindow->consumeMotionPointerUp(1, ADISPLAY_ID_DEFAULT,
5941 AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
Svet Ganov5d3bc372020-01-26 23:11:07 -08005942
5943 // Send up event to the second window
Prabir Pradhan678438e2023-04-13 19:32:51 +00005944 mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN,
5945 ADISPLAY_ID_DEFAULT));
Svet Ganov5d3bc372020-01-26 23:11:07 -08005946 // The first window gets nothing and the second gets up
5947 firstWindow->assertNoEvents();
Prabir Pradhan65455c72024-02-13 21:46:41 +00005948 secondWindow->consumeMotionUp(ADISPLAY_ID_DEFAULT, AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
Svet Ganov5d3bc372020-01-26 23:11:07 -08005949}
5950
Prabir Pradhan367f3432024-02-13 23:05:58 +00005951// Same as TransferTouch_TwoPointersSplitTouch, but using 'transferTouchOnDisplay' api.
5952// Unlike 'transferTouchGesture', calling 'transferTouchOnDisplay' when there are two windows
5953// receiving touch is not supported, so the touch should continue on those windows and the
5954// transferred-to window should get nothing.
5955TEST_F(InputDispatcherTest, TransferTouchOnDisplay_TwoPointersSplitTouch) {
Siarhei Vishniakoud0c6bc82021-03-13 03:14:52 +00005956 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
5957
Siarhei Vishniakoud0c6bc82021-03-13 03:14:52 +00005958 sp<FakeWindowHandle> firstWindow =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07005959 sp<FakeWindowHandle>::make(application, mDispatcher, "First Window",
5960 ADISPLAY_ID_DEFAULT);
Siarhei Vishniakoud0c6bc82021-03-13 03:14:52 +00005961 firstWindow->setFrame(Rect(0, 0, 600, 400));
Siarhei Vishniakoud0c6bc82021-03-13 03:14:52 +00005962
Siarhei Vishniakoud0c6bc82021-03-13 03:14:52 +00005963 sp<FakeWindowHandle> secondWindow =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07005964 sp<FakeWindowHandle>::make(application, mDispatcher, "Second Window",
5965 ADISPLAY_ID_DEFAULT);
Siarhei Vishniakoud0c6bc82021-03-13 03:14:52 +00005966 secondWindow->setFrame(Rect(0, 400, 600, 800));
Siarhei Vishniakoud0c6bc82021-03-13 03:14:52 +00005967
5968 // Add the windows to the dispatcher
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07005969 mDispatcher->onWindowInfosChanged(
5970 {{*firstWindow->getInfo(), *secondWindow->getInfo()}, {}, 0, 0});
Siarhei Vishniakoud0c6bc82021-03-13 03:14:52 +00005971
5972 PointF pointInFirst = {300, 200};
5973 PointF pointInSecond = {300, 600};
5974
5975 // Send down to the first window
Prabir Pradhan678438e2023-04-13 19:32:51 +00005976 mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_DOWN,
5977 AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
5978 {pointInFirst}));
Siarhei Vishniakoud0c6bc82021-03-13 03:14:52 +00005979 // Only the first window should get the down event
5980 firstWindow->consumeMotionDown();
5981 secondWindow->assertNoEvents();
5982
5983 // Send down to the second window
Prabir Pradhan678438e2023-04-13 19:32:51 +00005984 mDispatcher->notifyMotion(generateMotionArgs(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN,
5985 ADISPLAY_ID_DEFAULT,
5986 {pointInFirst, pointInSecond}));
Siarhei Vishniakoud0c6bc82021-03-13 03:14:52 +00005987 // The first window gets a move and the second a down
5988 firstWindow->consumeMotionMove();
5989 secondWindow->consumeMotionDown();
5990
5991 // Transfer touch focus to the second window
Siarhei Vishniakou7ae7afd2022-03-31 15:26:13 -07005992 const bool transferred =
Prabir Pradhan367f3432024-02-13 23:05:58 +00005993 mDispatcher->transferTouchOnDisplay(secondWindow->getToken(), ADISPLAY_ID_DEFAULT);
5994 // The 'transferTouchOnDisplay' call should not succeed, because there are 2 touched windows
Siarhei Vishniakoud0c6bc82021-03-13 03:14:52 +00005995 ASSERT_FALSE(transferred);
5996 firstWindow->assertNoEvents();
5997 secondWindow->assertNoEvents();
5998
5999 // The rest of the dispatch should proceed as normal
6000 // Send pointer up to the second window
Prabir Pradhan678438e2023-04-13 19:32:51 +00006001 mDispatcher->notifyMotion(generateMotionArgs(POINTER_1_UP, AINPUT_SOURCE_TOUCHSCREEN,
6002 ADISPLAY_ID_DEFAULT,
6003 {pointInFirst, pointInSecond}));
Siarhei Vishniakoud0c6bc82021-03-13 03:14:52 +00006004 // The first window gets MOVE and the second gets pointer up
6005 firstWindow->consumeMotionMove();
6006 secondWindow->consumeMotionUp();
6007
6008 // Send up event to the first window
Prabir Pradhan678438e2023-04-13 19:32:51 +00006009 mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN,
6010 ADISPLAY_ID_DEFAULT));
Siarhei Vishniakoud0c6bc82021-03-13 03:14:52 +00006011 // The first window gets nothing and the second gets up
6012 firstWindow->consumeMotionUp();
6013 secondWindow->assertNoEvents();
6014}
6015
Arthur Hungabbb9d82021-09-01 14:52:30 +00006016// This case will create two windows and one mirrored window on the default display and mirror
Prabir Pradhan367f3432024-02-13 23:05:58 +00006017// two windows on the second display. It will test if 'transferTouchGesture' works fine if we put
Arthur Hungabbb9d82021-09-01 14:52:30 +00006018// the windows info of second display before default display.
Prabir Pradhan367f3432024-02-13 23:05:58 +00006019TEST_F(InputDispatcherTest, TransferTouch_CloneSurface) {
Arthur Hungabbb9d82021-09-01 14:52:30 +00006020 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
6021 sp<FakeWindowHandle> firstWindowInPrimary =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07006022 sp<FakeWindowHandle>::make(application, mDispatcher, "D_1_W1", ADISPLAY_ID_DEFAULT);
Arthur Hungabbb9d82021-09-01 14:52:30 +00006023 firstWindowInPrimary->setFrame(Rect(0, 0, 100, 100));
Arthur Hungabbb9d82021-09-01 14:52:30 +00006024 sp<FakeWindowHandle> secondWindowInPrimary =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07006025 sp<FakeWindowHandle>::make(application, mDispatcher, "D_1_W2", ADISPLAY_ID_DEFAULT);
Arthur Hungabbb9d82021-09-01 14:52:30 +00006026 secondWindowInPrimary->setFrame(Rect(100, 0, 200, 100));
Arthur Hungabbb9d82021-09-01 14:52:30 +00006027
Siarhei Vishniakouadb9fc92023-05-26 10:46:09 -07006028 sp<FakeWindowHandle> mirrorWindowInPrimary = firstWindowInPrimary->clone(ADISPLAY_ID_DEFAULT);
Arthur Hungabbb9d82021-09-01 14:52:30 +00006029 mirrorWindowInPrimary->setFrame(Rect(0, 100, 100, 200));
Arthur Hungabbb9d82021-09-01 14:52:30 +00006030
Siarhei Vishniakouadb9fc92023-05-26 10:46:09 -07006031 sp<FakeWindowHandle> firstWindowInSecondary = firstWindowInPrimary->clone(SECOND_DISPLAY_ID);
Arthur Hungabbb9d82021-09-01 14:52:30 +00006032 firstWindowInSecondary->setFrame(Rect(0, 0, 100, 100));
Arthur Hungabbb9d82021-09-01 14:52:30 +00006033
Siarhei Vishniakouadb9fc92023-05-26 10:46:09 -07006034 sp<FakeWindowHandle> secondWindowInSecondary = secondWindowInPrimary->clone(SECOND_DISPLAY_ID);
Arthur Hungabbb9d82021-09-01 14:52:30 +00006035 secondWindowInPrimary->setFrame(Rect(100, 0, 200, 100));
Arthur Hungabbb9d82021-09-01 14:52:30 +00006036
6037 // Update window info, let it find window handle of second display first.
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07006038 mDispatcher->onWindowInfosChanged(
6039 {{*firstWindowInSecondary->getInfo(), *secondWindowInSecondary->getInfo(),
6040 *mirrorWindowInPrimary->getInfo(), *firstWindowInPrimary->getInfo(),
6041 *secondWindowInPrimary->getInfo()},
6042 {},
6043 0,
6044 0});
Arthur Hungabbb9d82021-09-01 14:52:30 +00006045
6046 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07006047 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
Arthur Hungabbb9d82021-09-01 14:52:30 +00006048 {50, 50}))
6049 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
6050
6051 // Window should receive motion event.
6052 firstWindowInPrimary->consumeMotionDown(ADISPLAY_ID_DEFAULT);
6053
Prabir Pradhan367f3432024-02-13 23:05:58 +00006054 // Transfer touch
6055 ASSERT_TRUE(mDispatcher->transferTouchGesture(firstWindowInPrimary->getToken(),
6056 secondWindowInPrimary->getToken()));
Arthur Hungabbb9d82021-09-01 14:52:30 +00006057 // The first window gets cancel.
6058 firstWindowInPrimary->consumeMotionCancel();
Prabir Pradhan65455c72024-02-13 21:46:41 +00006059 secondWindowInPrimary->consumeMotionDown(ADISPLAY_ID_DEFAULT,
6060 AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
Arthur Hungabbb9d82021-09-01 14:52:30 +00006061
6062 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07006063 injectMotionEvent(*mDispatcher, AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN,
Arthur Hungabbb9d82021-09-01 14:52:30 +00006064 ADISPLAY_ID_DEFAULT, {150, 50}))
6065 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
6066 firstWindowInPrimary->assertNoEvents();
Prabir Pradhan65455c72024-02-13 21:46:41 +00006067 secondWindowInPrimary->consumeMotionMove(ADISPLAY_ID_DEFAULT,
6068 AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
Arthur Hungabbb9d82021-09-01 14:52:30 +00006069
6070 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07006071 injectMotionUp(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
Arthur Hungabbb9d82021-09-01 14:52:30 +00006072 {150, 50}))
6073 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
6074 firstWindowInPrimary->assertNoEvents();
Prabir Pradhan65455c72024-02-13 21:46:41 +00006075 secondWindowInPrimary->consumeMotionUp(ADISPLAY_ID_DEFAULT, AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
Arthur Hungabbb9d82021-09-01 14:52:30 +00006076}
6077
Prabir Pradhan367f3432024-02-13 23:05:58 +00006078// Same as TransferTouch_CloneSurface, but this touch on the secondary display and use
6079// 'transferTouchOnDisplay' api.
6080TEST_F(InputDispatcherTest, TransferTouchOnDisplay_CloneSurface) {
Arthur Hungabbb9d82021-09-01 14:52:30 +00006081 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
6082 sp<FakeWindowHandle> firstWindowInPrimary =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07006083 sp<FakeWindowHandle>::make(application, mDispatcher, "D_1_W1", ADISPLAY_ID_DEFAULT);
Arthur Hungabbb9d82021-09-01 14:52:30 +00006084 firstWindowInPrimary->setFrame(Rect(0, 0, 100, 100));
Arthur Hungabbb9d82021-09-01 14:52:30 +00006085 sp<FakeWindowHandle> secondWindowInPrimary =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07006086 sp<FakeWindowHandle>::make(application, mDispatcher, "D_1_W2", ADISPLAY_ID_DEFAULT);
Arthur Hungabbb9d82021-09-01 14:52:30 +00006087 secondWindowInPrimary->setFrame(Rect(100, 0, 200, 100));
Arthur Hungabbb9d82021-09-01 14:52:30 +00006088
Siarhei Vishniakouadb9fc92023-05-26 10:46:09 -07006089 sp<FakeWindowHandle> mirrorWindowInPrimary = firstWindowInPrimary->clone(ADISPLAY_ID_DEFAULT);
Arthur Hungabbb9d82021-09-01 14:52:30 +00006090 mirrorWindowInPrimary->setFrame(Rect(0, 100, 100, 200));
Arthur Hungabbb9d82021-09-01 14:52:30 +00006091
Siarhei Vishniakouadb9fc92023-05-26 10:46:09 -07006092 sp<FakeWindowHandle> firstWindowInSecondary = firstWindowInPrimary->clone(SECOND_DISPLAY_ID);
Arthur Hungabbb9d82021-09-01 14:52:30 +00006093 firstWindowInSecondary->setFrame(Rect(0, 0, 100, 100));
Arthur Hungabbb9d82021-09-01 14:52:30 +00006094
Siarhei Vishniakouadb9fc92023-05-26 10:46:09 -07006095 sp<FakeWindowHandle> secondWindowInSecondary = secondWindowInPrimary->clone(SECOND_DISPLAY_ID);
Arthur Hungabbb9d82021-09-01 14:52:30 +00006096 secondWindowInPrimary->setFrame(Rect(100, 0, 200, 100));
Arthur Hungabbb9d82021-09-01 14:52:30 +00006097
6098 // Update window info, let it find window handle of second display first.
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07006099 mDispatcher->onWindowInfosChanged(
6100 {{*firstWindowInSecondary->getInfo(), *secondWindowInSecondary->getInfo(),
6101 *mirrorWindowInPrimary->getInfo(), *firstWindowInPrimary->getInfo(),
6102 *secondWindowInPrimary->getInfo()},
6103 {},
6104 0,
6105 0});
Arthur Hungabbb9d82021-09-01 14:52:30 +00006106
6107 // Touch on second display.
6108 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07006109 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, SECOND_DISPLAY_ID,
6110 {50, 50}))
Arthur Hungabbb9d82021-09-01 14:52:30 +00006111 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
6112
6113 // Window should receive motion event.
Prabir Pradhanbb3f1c02024-01-04 20:17:14 +00006114 firstWindowInSecondary->consumeMotionDown(SECOND_DISPLAY_ID);
Arthur Hungabbb9d82021-09-01 14:52:30 +00006115
6116 // Transfer touch focus
Prabir Pradhan367f3432024-02-13 23:05:58 +00006117 ASSERT_TRUE(mDispatcher->transferTouchOnDisplay(secondWindowInSecondary->getToken(),
6118 SECOND_DISPLAY_ID));
Arthur Hungabbb9d82021-09-01 14:52:30 +00006119
6120 // The first window gets cancel.
Prabir Pradhanbb3f1c02024-01-04 20:17:14 +00006121 firstWindowInSecondary->consumeMotionCancel(SECOND_DISPLAY_ID);
Prabir Pradhan65455c72024-02-13 21:46:41 +00006122 secondWindowInSecondary->consumeMotionDown(SECOND_DISPLAY_ID,
6123 AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
Arthur Hungabbb9d82021-09-01 14:52:30 +00006124
6125 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07006126 injectMotionEvent(*mDispatcher, AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN,
Arthur Hungabbb9d82021-09-01 14:52:30 +00006127 SECOND_DISPLAY_ID, {150, 50}))
6128 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
Prabir Pradhanbb3f1c02024-01-04 20:17:14 +00006129 firstWindowInSecondary->assertNoEvents();
Prabir Pradhan65455c72024-02-13 21:46:41 +00006130 secondWindowInSecondary->consumeMotionMove(SECOND_DISPLAY_ID,
6131 AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
Arthur Hungabbb9d82021-09-01 14:52:30 +00006132
6133 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07006134 injectMotionUp(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, SECOND_DISPLAY_ID, {150, 50}))
Arthur Hungabbb9d82021-09-01 14:52:30 +00006135 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
Prabir Pradhanbb3f1c02024-01-04 20:17:14 +00006136 firstWindowInSecondary->assertNoEvents();
Prabir Pradhan65455c72024-02-13 21:46:41 +00006137 secondWindowInSecondary->consumeMotionUp(SECOND_DISPLAY_ID, AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
Arthur Hungabbb9d82021-09-01 14:52:30 +00006138}
6139
Siarhei Vishniakouf1035d42019-09-20 16:32:01 +01006140TEST_F(InputDispatcherTest, FocusedWindow_ReceivesFocusEventAndKeyEvent) {
Chris Yea209fde2020-07-22 13:54:51 -07006141 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07006142 sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher,
6143 "Fake Window", ADISPLAY_ID_DEFAULT);
Siarhei Vishniakouf1035d42019-09-20 16:32:01 +01006144
Vishnu Nair47074b82020-08-14 11:54:47 -07006145 window->setFocusable(true);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07006146 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Vishnu Nair958da932020-08-21 17:12:37 -07006147 setFocusedWindow(window);
Siarhei Vishniakouf1035d42019-09-20 16:32:01 +01006148
6149 window->consumeFocusEvent(true);
6150
Prabir Pradhan678438e2023-04-13 19:32:51 +00006151 mDispatcher->notifyKey(generateKeyArgs(AKEY_EVENT_ACTION_DOWN, ADISPLAY_ID_DEFAULT));
Siarhei Vishniakouf1035d42019-09-20 16:32:01 +01006152
6153 // Window should receive key down event.
6154 window->consumeKeyDown(ADISPLAY_ID_DEFAULT);
Josep del Riob3981622023-04-18 15:49:45 +00006155
6156 // Should have poked user activity
Siarhei Vishniakou4fd86732023-05-24 17:33:01 +00006157 mDispatcher->waitForIdle();
Josep del Riob3981622023-04-18 15:49:45 +00006158 mFakePolicy->assertUserActivityPoked();
6159}
6160
6161TEST_F(InputDispatcherTest, FocusedWindow_DisableUserActivity) {
6162 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
6163 sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher,
6164 "Fake Window", ADISPLAY_ID_DEFAULT);
6165
6166 window->setDisableUserActivity(true);
6167 window->setFocusable(true);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07006168 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Josep del Riob3981622023-04-18 15:49:45 +00006169 setFocusedWindow(window);
6170
6171 window->consumeFocusEvent(true);
6172
6173 mDispatcher->notifyKey(generateKeyArgs(AKEY_EVENT_ACTION_DOWN, ADISPLAY_ID_DEFAULT));
6174
6175 // Window should receive key down event.
6176 window->consumeKeyDown(ADISPLAY_ID_DEFAULT);
6177
6178 // Should have poked user activity
Siarhei Vishniakou4fd86732023-05-24 17:33:01 +00006179 mDispatcher->waitForIdle();
Josep del Riob3981622023-04-18 15:49:45 +00006180 mFakePolicy->assertUserActivityNotPoked();
6181}
6182
6183TEST_F(InputDispatcherTest, FocusedWindow_DoesNotReceiveSystemShortcut) {
6184 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
6185 sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher,
6186 "Fake Window", ADISPLAY_ID_DEFAULT);
6187
6188 window->setFocusable(true);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07006189 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Josep del Riob3981622023-04-18 15:49:45 +00006190 setFocusedWindow(window);
6191
6192 window->consumeFocusEvent(true);
6193
6194 mDispatcher->notifyKey(generateSystemShortcutArgs(AKEY_EVENT_ACTION_DOWN, ADISPLAY_ID_DEFAULT));
6195 mDispatcher->waitForIdle();
6196
6197 // System key is not passed down
6198 window->assertNoEvents();
6199
6200 // Should have poked user activity
6201 mFakePolicy->assertUserActivityPoked();
6202}
6203
6204TEST_F(InputDispatcherTest, FocusedWindow_DoesNotReceiveAssistantKey) {
6205 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
6206 sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher,
6207 "Fake Window", ADISPLAY_ID_DEFAULT);
6208
6209 window->setFocusable(true);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07006210 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Josep del Riob3981622023-04-18 15:49:45 +00006211 setFocusedWindow(window);
6212
6213 window->consumeFocusEvent(true);
6214
6215 mDispatcher->notifyKey(generateAssistantKeyArgs(AKEY_EVENT_ACTION_DOWN, ADISPLAY_ID_DEFAULT));
6216 mDispatcher->waitForIdle();
6217
6218 // System key is not passed down
6219 window->assertNoEvents();
6220
6221 // Should have poked user activity
6222 mFakePolicy->assertUserActivityPoked();
6223}
6224
6225TEST_F(InputDispatcherTest, FocusedWindow_SystemKeyIgnoresDisableUserActivity) {
6226 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
6227 sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher,
6228 "Fake Window", ADISPLAY_ID_DEFAULT);
6229
6230 window->setDisableUserActivity(true);
6231 window->setFocusable(true);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07006232 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Josep del Riob3981622023-04-18 15:49:45 +00006233 setFocusedWindow(window);
6234
6235 window->consumeFocusEvent(true);
6236
6237 mDispatcher->notifyKey(generateSystemShortcutArgs(AKEY_EVENT_ACTION_DOWN, ADISPLAY_ID_DEFAULT));
6238 mDispatcher->waitForIdle();
6239
6240 // System key is not passed down
6241 window->assertNoEvents();
6242
6243 // Should have poked user activity
6244 mFakePolicy->assertUserActivityPoked();
Siarhei Vishniakouf1035d42019-09-20 16:32:01 +01006245}
6246
Siarhei Vishniakou90ee4782023-05-08 11:57:24 -07006247TEST_F(InputDispatcherTest, InjectedTouchesPokeUserActivity) {
6248 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
6249 sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher,
6250 "Fake Window", ADISPLAY_ID_DEFAULT);
6251
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07006252 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Siarhei Vishniakou90ee4782023-05-08 11:57:24 -07006253
6254 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07006255 injectMotionEvent(*mDispatcher, AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN,
Siarhei Vishniakou90ee4782023-05-08 11:57:24 -07006256 ADISPLAY_ID_DEFAULT, {100, 100}))
6257 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
6258
6259 window->consumeMotionEvent(
6260 AllOf(WithMotionAction(ACTION_DOWN), WithDisplayId(ADISPLAY_ID_DEFAULT)));
6261
6262 // Should have poked user activity
Siarhei Vishniakou4fd86732023-05-24 17:33:01 +00006263 mDispatcher->waitForIdle();
Siarhei Vishniakou90ee4782023-05-08 11:57:24 -07006264 mFakePolicy->assertUserActivityPoked();
6265}
6266
Siarhei Vishniakouf1035d42019-09-20 16:32:01 +01006267TEST_F(InputDispatcherTest, UnfocusedWindow_DoesNotReceiveFocusEventOrKeyEvent) {
Chris Yea209fde2020-07-22 13:54:51 -07006268 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07006269 sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher,
6270 "Fake Window", ADISPLAY_ID_DEFAULT);
Siarhei Vishniakouf1035d42019-09-20 16:32:01 +01006271
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07006272 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Siarhei Vishniakouf1035d42019-09-20 16:32:01 +01006273
Prabir Pradhan678438e2023-04-13 19:32:51 +00006274 mDispatcher->notifyKey(generateKeyArgs(AKEY_EVENT_ACTION_DOWN, ADISPLAY_ID_DEFAULT));
Siarhei Vishniakouf1035d42019-09-20 16:32:01 +01006275 mDispatcher->waitForIdle();
6276
6277 window->assertNoEvents();
6278}
6279
6280// If a window is touchable, but does not have focus, it should receive motion events, but not keys
6281TEST_F(InputDispatcherTest, UnfocusedWindow_ReceivesMotionsButNotKeys) {
Chris Yea209fde2020-07-22 13:54:51 -07006282 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07006283 sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher,
6284 "Fake Window", ADISPLAY_ID_DEFAULT);
Siarhei Vishniakouf1035d42019-09-20 16:32:01 +01006285
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07006286 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Siarhei Vishniakouf1035d42019-09-20 16:32:01 +01006287
6288 // Send key
Prabir Pradhan678438e2023-04-13 19:32:51 +00006289 mDispatcher->notifyKey(generateKeyArgs(AKEY_EVENT_ACTION_DOWN, ADISPLAY_ID_DEFAULT));
Siarhei Vishniakouf1035d42019-09-20 16:32:01 +01006290 // Send motion
Prabir Pradhan678438e2023-04-13 19:32:51 +00006291 mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_DOWN,
6292 AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT));
Siarhei Vishniakouf1035d42019-09-20 16:32:01 +01006293
6294 // Window should receive only the motion event
6295 window->consumeMotionDown(ADISPLAY_ID_DEFAULT);
6296 window->assertNoEvents(); // Key event or focus event will not be received
6297}
6298
arthurhungea3f4fc2020-12-21 23:18:53 +08006299TEST_F(InputDispatcherTest, PointerCancel_SendCancelWhenSplitTouch) {
6300 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
6301
arthurhungea3f4fc2020-12-21 23:18:53 +08006302 sp<FakeWindowHandle> firstWindow =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07006303 sp<FakeWindowHandle>::make(application, mDispatcher, "First Window",
6304 ADISPLAY_ID_DEFAULT);
arthurhungea3f4fc2020-12-21 23:18:53 +08006305 firstWindow->setFrame(Rect(0, 0, 600, 400));
arthurhungea3f4fc2020-12-21 23:18:53 +08006306
arthurhungea3f4fc2020-12-21 23:18:53 +08006307 sp<FakeWindowHandle> secondWindow =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07006308 sp<FakeWindowHandle>::make(application, mDispatcher, "Second Window",
6309 ADISPLAY_ID_DEFAULT);
arthurhungea3f4fc2020-12-21 23:18:53 +08006310 secondWindow->setFrame(Rect(0, 400, 600, 800));
arthurhungea3f4fc2020-12-21 23:18:53 +08006311
6312 // Add the windows to the dispatcher
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07006313 mDispatcher->onWindowInfosChanged(
6314 {{*firstWindow->getInfo(), *secondWindow->getInfo()}, {}, 0, 0});
arthurhungea3f4fc2020-12-21 23:18:53 +08006315
6316 PointF pointInFirst = {300, 200};
6317 PointF pointInSecond = {300, 600};
6318
6319 // Send down to the first window
Prabir Pradhan678438e2023-04-13 19:32:51 +00006320 mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_DOWN,
6321 AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
6322 {pointInFirst}));
arthurhungea3f4fc2020-12-21 23:18:53 +08006323 // Only the first window should get the down event
6324 firstWindow->consumeMotionDown();
6325 secondWindow->assertNoEvents();
6326
6327 // Send down to the second window
Prabir Pradhan678438e2023-04-13 19:32:51 +00006328 mDispatcher->notifyMotion(generateMotionArgs(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN,
6329 ADISPLAY_ID_DEFAULT,
6330 {pointInFirst, pointInSecond}));
arthurhungea3f4fc2020-12-21 23:18:53 +08006331 // The first window gets a move and the second a down
6332 firstWindow->consumeMotionMove();
6333 secondWindow->consumeMotionDown();
6334
6335 // Send pointer cancel to the second window
6336 NotifyMotionArgs pointerUpMotionArgs =
Siarhei Vishniakoua16e3a22022-03-02 15:26:40 -08006337 generateMotionArgs(POINTER_1_UP, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
arthurhungea3f4fc2020-12-21 23:18:53 +08006338 {pointInFirst, pointInSecond});
6339 pointerUpMotionArgs.flags |= AMOTION_EVENT_FLAG_CANCELED;
Prabir Pradhan678438e2023-04-13 19:32:51 +00006340 mDispatcher->notifyMotion(pointerUpMotionArgs);
arthurhungea3f4fc2020-12-21 23:18:53 +08006341 // The first window gets move and the second gets cancel.
6342 firstWindow->consumeMotionMove(ADISPLAY_ID_DEFAULT, AMOTION_EVENT_FLAG_CANCELED);
6343 secondWindow->consumeMotionCancel(ADISPLAY_ID_DEFAULT, AMOTION_EVENT_FLAG_CANCELED);
6344
6345 // Send up event.
Prabir Pradhan678438e2023-04-13 19:32:51 +00006346 mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN,
6347 ADISPLAY_ID_DEFAULT));
arthurhungea3f4fc2020-12-21 23:18:53 +08006348 // The first window gets up and the second gets nothing.
6349 firstWindow->consumeMotionUp();
6350 secondWindow->assertNoEvents();
6351}
6352
Siarhei Vishniakouf94ae022021-02-04 01:23:17 +00006353TEST_F(InputDispatcherTest, SendTimeline_DoesNotCrashDispatcher) {
6354 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
6355
6356 sp<FakeWindowHandle> window =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07006357 sp<FakeWindowHandle>::make(application, mDispatcher, "Window", ADISPLAY_ID_DEFAULT);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07006358 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Siarhei Vishniakouf94ae022021-02-04 01:23:17 +00006359 std::array<nsecs_t, GraphicsTimeline::SIZE> graphicsTimeline;
6360 graphicsTimeline[GraphicsTimeline::GPU_COMPLETED_TIME] = 2;
6361 graphicsTimeline[GraphicsTimeline::PRESENT_TIME] = 3;
6362
Harry Cutts33476232023-01-30 19:57:29 +00006363 window->sendTimeline(/*inputEventId=*/1, graphicsTimeline);
Siarhei Vishniakouf94ae022021-02-04 01:23:17 +00006364 window->assertNoEvents();
6365 mDispatcher->waitForIdle();
6366}
6367
Prabir Pradhan1376fcd2022-01-21 09:56:35 -08006368using InputDispatcherMonitorTest = InputDispatcherTest;
6369
Siarhei Vishniakouca205502021-07-16 21:31:58 +00006370/**
6371 * Two entities that receive touch: A window, and a global monitor.
6372 * The touch goes to the window, and then the window disappears.
6373 * The monitor does not get cancel right away. But if more events come in, the touch gets canceled
6374 * for the monitor, as well.
6375 * 1. foregroundWindow
6376 * 2. monitor <-- global monitor (doesn't observe z order, receives all events)
6377 */
Prabir Pradhan1376fcd2022-01-21 09:56:35 -08006378TEST_F(InputDispatcherMonitorTest, MonitorTouchIsCanceledWhenForegroundWindowDisappears) {
Siarhei Vishniakouca205502021-07-16 21:31:58 +00006379 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
6380 sp<FakeWindowHandle> window =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07006381 sp<FakeWindowHandle>::make(application, mDispatcher, "Foreground", ADISPLAY_ID_DEFAULT);
Siarhei Vishniakouca205502021-07-16 21:31:58 +00006382
Prabir Pradhanfb549072023-10-05 19:17:36 +00006383 FakeMonitorReceiver monitor = FakeMonitorReceiver(*mDispatcher, "M_1", ADISPLAY_ID_DEFAULT);
Siarhei Vishniakouca205502021-07-16 21:31:58 +00006384
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07006385 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Siarhei Vishniakouca205502021-07-16 21:31:58 +00006386 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07006387 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
Siarhei Vishniakouca205502021-07-16 21:31:58 +00006388 {100, 200}))
6389 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
6390
6391 // Both the foreground window and the global monitor should receive the touch down
6392 window->consumeMotionDown();
6393 monitor.consumeMotionDown(ADISPLAY_ID_DEFAULT);
6394
6395 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07006396 injectMotionEvent(*mDispatcher, AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN,
Siarhei Vishniakouca205502021-07-16 21:31:58 +00006397 ADISPLAY_ID_DEFAULT, {110, 200}))
6398 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
6399
6400 window->consumeMotionMove();
6401 monitor.consumeMotionMove(ADISPLAY_ID_DEFAULT);
6402
6403 // Now the foreground window goes away
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07006404 mDispatcher->onWindowInfosChanged({{}, {}, 0, 0});
Siarhei Vishniakouca205502021-07-16 21:31:58 +00006405 window->consumeMotionCancel();
6406 monitor.assertNoEvents(); // Global monitor does not get a cancel yet
6407
6408 // If more events come in, there will be no more foreground window to send them to. This will
6409 // cause a cancel for the monitor, as well.
6410 ASSERT_EQ(InputEventInjectionResult::FAILED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07006411 injectMotionEvent(*mDispatcher, AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN,
Siarhei Vishniakouca205502021-07-16 21:31:58 +00006412 ADISPLAY_ID_DEFAULT, {120, 200}))
6413 << "Injection should fail because the window was removed";
6414 window->assertNoEvents();
6415 // Global monitor now gets the cancel
6416 monitor.consumeMotionCancel(ADISPLAY_ID_DEFAULT);
6417}
6418
Prabir Pradhan1376fcd2022-01-21 09:56:35 -08006419TEST_F(InputDispatcherMonitorTest, ReceivesMotionEvents) {
Chris Yea209fde2020-07-22 13:54:51 -07006420 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07006421 sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher,
6422 "Fake Window", ADISPLAY_ID_DEFAULT);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07006423 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Michael Wright3a240c42019-12-10 20:53:41 +00006424
Prabir Pradhanfb549072023-10-05 19:17:36 +00006425 FakeMonitorReceiver monitor = FakeMonitorReceiver(*mDispatcher, "M_1", ADISPLAY_ID_DEFAULT);
Michael Wright3a240c42019-12-10 20:53:41 +00006426
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08006427 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07006428 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT))
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08006429 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
Michael Wright3a240c42019-12-10 20:53:41 +00006430 window->consumeMotionDown(ADISPLAY_ID_DEFAULT);
chaviwd1c23182019-12-20 18:44:56 -08006431 monitor.consumeMotionDown(ADISPLAY_ID_DEFAULT);
Michael Wright3a240c42019-12-10 20:53:41 +00006432}
6433
Prabir Pradhan1376fcd2022-01-21 09:56:35 -08006434TEST_F(InputDispatcherMonitorTest, MonitorCannotPilferPointers) {
Prabir Pradhanfb549072023-10-05 19:17:36 +00006435 FakeMonitorReceiver monitor = FakeMonitorReceiver(*mDispatcher, "M_1", ADISPLAY_ID_DEFAULT);
Michael Wright3a240c42019-12-10 20:53:41 +00006436
Chris Yea209fde2020-07-22 13:54:51 -07006437 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07006438 sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher,
6439 "Fake Window", ADISPLAY_ID_DEFAULT);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07006440 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Michael Wright3a240c42019-12-10 20:53:41 +00006441
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08006442 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07006443 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT))
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08006444 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
chaviwd1c23182019-12-20 18:44:56 -08006445 monitor.consumeMotionDown(ADISPLAY_ID_DEFAULT);
Prabir Pradhan1376fcd2022-01-21 09:56:35 -08006446 window->consumeMotionDown(ADISPLAY_ID_DEFAULT);
Michael Wright3a240c42019-12-10 20:53:41 +00006447
Prabir Pradhan1376fcd2022-01-21 09:56:35 -08006448 // Pilfer pointers from the monitor.
6449 // This should not do anything and the window should continue to receive events.
6450 EXPECT_NE(OK, mDispatcher->pilferPointers(monitor.getToken()));
Michael Wright3a240c42019-12-10 20:53:41 +00006451
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08006452 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07006453 injectMotionEvent(*mDispatcher, AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN,
Prabir Pradhan1376fcd2022-01-21 09:56:35 -08006454 ADISPLAY_ID_DEFAULT))
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08006455 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
Prabir Pradhan1376fcd2022-01-21 09:56:35 -08006456
6457 monitor.consumeMotionMove(ADISPLAY_ID_DEFAULT);
6458 window->consumeMotionMove(ADISPLAY_ID_DEFAULT);
Michael Wright3a240c42019-12-10 20:53:41 +00006459}
6460
Prabir Pradhan1376fcd2022-01-21 09:56:35 -08006461TEST_F(InputDispatcherMonitorTest, NoWindowTransform) {
Evan Rosky84f07f02021-04-16 10:42:42 -07006462 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07006463 sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher,
6464 "Fake Window", ADISPLAY_ID_DEFAULT);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07006465 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Evan Rosky84f07f02021-04-16 10:42:42 -07006466 window->setWindowOffset(20, 40);
6467 window->setWindowTransform(0, 1, -1, 0);
6468
Prabir Pradhanfb549072023-10-05 19:17:36 +00006469 FakeMonitorReceiver monitor = FakeMonitorReceiver(*mDispatcher, "M_1", ADISPLAY_ID_DEFAULT);
Evan Rosky84f07f02021-04-16 10:42:42 -07006470
6471 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07006472 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT))
Evan Rosky84f07f02021-04-16 10:42:42 -07006473 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
6474 window->consumeMotionDown(ADISPLAY_ID_DEFAULT);
Siarhei Vishniakoud3061ab2023-12-18 20:41:08 -08006475 std::unique_ptr<MotionEvent> event = monitor.consumeMotion();
6476 ASSERT_NE(nullptr, event);
Evan Rosky84f07f02021-04-16 10:42:42 -07006477 // Even though window has transform, gesture monitor must not.
6478 ASSERT_EQ(ui::Transform(), event->getTransform());
6479}
6480
Prabir Pradhan1376fcd2022-01-21 09:56:35 -08006481TEST_F(InputDispatcherMonitorTest, InjectionFailsWithNoWindow) {
Arthur Hungb3307ee2021-10-14 10:57:37 +00006482 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
Prabir Pradhanfb549072023-10-05 19:17:36 +00006483 FakeMonitorReceiver monitor = FakeMonitorReceiver(*mDispatcher, "M_1", ADISPLAY_ID_DEFAULT);
Arthur Hungb3307ee2021-10-14 10:57:37 +00006484
Prabir Pradhan1376fcd2022-01-21 09:56:35 -08006485 ASSERT_EQ(InputEventInjectionResult::FAILED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07006486 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT))
Prabir Pradhan1376fcd2022-01-21 09:56:35 -08006487 << "Injection should fail if there is a monitor, but no touchable window";
6488 monitor.assertNoEvents();
Arthur Hungb3307ee2021-10-14 10:57:37 +00006489}
6490
Linnan Lid8150952024-01-26 18:07:17 +00006491/**
6492 * Two displays
6493 * The first monitor has a foreground window, a monitor
6494 * The second window has only one monitor.
6495 * We first inject a Down event into the first display, this injection should succeed and both
6496 * the foreground window and monitor should receive a down event, then inject a Down event into
6497 * the second display as well, this injection should fail, at this point, the first display
6498 * window and monitor should not receive a cancel or any other event.
6499 * Continue to inject Move and UP events to the first display, the events should be received
6500 * normally by the foreground window and monitor.
6501 */
6502TEST_F(InputDispatcherMonitorTest, MonitorTouchIsNotCanceledWhenAnotherEmptyDisplayReceiveEvents) {
6503 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
6504 sp<FakeWindowHandle> window =
6505 sp<FakeWindowHandle>::make(application, mDispatcher, "Foreground", ADISPLAY_ID_DEFAULT);
6506
6507 FakeMonitorReceiver monitor = FakeMonitorReceiver(*mDispatcher, "M_1", ADISPLAY_ID_DEFAULT);
6508 FakeMonitorReceiver secondMonitor = FakeMonitorReceiver(*mDispatcher, "M_2", SECOND_DISPLAY_ID);
6509
6510 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
6511 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
6512 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
6513 {100, 200}))
6514 << "The down event injected into the first display should succeed";
6515
6516 window->consumeMotionDown();
6517 monitor.consumeMotionDown(ADISPLAY_ID_DEFAULT);
Linnan Lid8150952024-01-26 18:07:17 +00006518
6519 ASSERT_EQ(InputEventInjectionResult::FAILED,
6520 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, SECOND_DISPLAY_ID,
6521 {100, 200}))
Prabir Pradhana0d43d42024-01-30 00:27:08 +00006522 << "The down event injected into the second display should fail since there's no "
6523 "touchable window";
Linnan Lid8150952024-01-26 18:07:17 +00006524
6525 // Continue to inject event to first display.
6526 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
6527 injectMotionEvent(*mDispatcher, AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN,
6528 ADISPLAY_ID_DEFAULT, {110, 220}))
6529 << "The move event injected into the first display should succeed";
6530
6531 window->consumeMotionMove();
6532 monitor.consumeMotionMove(ADISPLAY_ID_DEFAULT);
Linnan Lid8150952024-01-26 18:07:17 +00006533
6534 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
6535 injectMotionUp(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
6536 {110, 220}))
6537 << "The up event injected into the first display should succeed";
6538
6539 window->consumeMotionUp();
6540 monitor.consumeMotionUp(ADISPLAY_ID_DEFAULT);
Prabir Pradhana0d43d42024-01-30 00:27:08 +00006541
6542 window->assertNoEvents();
6543 monitor.assertNoEvents();
Linnan Lid8150952024-01-26 18:07:17 +00006544 secondMonitor.assertNoEvents();
6545}
6546
6547/**
6548 * Two displays
6549 * There is a monitor and foreground window on each display.
6550 * First, we inject down events into each of the two displays, at this point, the foreground windows
6551 * and monitors on both displays should receive down events.
6552 * At this point, the foreground window of the second display goes away, the gone window should
6553 * receive the cancel event, and the other windows and monitors should not receive any events.
6554 * Inject a move event into the second display. At this point, the injection should fail because
6555 * the second display no longer has a foreground window. At this point, the monitor on the second
6556 * display should receive a cancel event, and any windows or monitors on the first display should
6557 * not receive any events, and any subsequent injection of events into the second display should
6558 * also fail.
6559 * Continue to inject events into the first display, and the events should all be injected
6560 * successfully and received normally.
6561 */
6562TEST_F(InputDispatcherMonitorTest, MonitorTouchIsNotCancelWhenAnotherDisplayMonitorTouchCanceled) {
6563 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
6564 sp<FakeWindowHandle> window =
6565 sp<FakeWindowHandle>::make(application, mDispatcher, "Foreground", ADISPLAY_ID_DEFAULT);
6566 sp<FakeWindowHandle> secondWindow =
6567 sp<FakeWindowHandle>::make(application, mDispatcher, "SecondForeground",
6568 SECOND_DISPLAY_ID);
6569
6570 FakeMonitorReceiver monitor = FakeMonitorReceiver(*mDispatcher, "M_1", ADISPLAY_ID_DEFAULT);
6571 FakeMonitorReceiver secondMonitor = FakeMonitorReceiver(*mDispatcher, "M_2", SECOND_DISPLAY_ID);
6572
6573 // There is a foreground window on both displays.
6574 mDispatcher->onWindowInfosChanged({{*window->getInfo(), *secondWindow->getInfo()}, {}, 0, 0});
6575 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
6576 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
6577 {100, 200}))
6578 << "The down event injected into the first display should succeed";
6579
6580 window->consumeMotionDown(ADISPLAY_ID_DEFAULT);
6581 monitor.consumeMotionDown(ADISPLAY_ID_DEFAULT);
Linnan Lid8150952024-01-26 18:07:17 +00006582
6583 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
6584 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, SECOND_DISPLAY_ID,
6585 {100, 200}))
6586 << "The down event injected into the second display should succeed";
6587
Linnan Lid8150952024-01-26 18:07:17 +00006588 secondWindow->consumeMotionDown(SECOND_DISPLAY_ID);
6589 secondMonitor.consumeMotionDown(SECOND_DISPLAY_ID);
6590
6591 // Now second window is gone away.
6592 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
6593
6594 // The gone window should receive a cancel, and the monitor on the second display should not
6595 // receive any events.
Linnan Lid8150952024-01-26 18:07:17 +00006596 secondWindow->consumeMotionCancel(SECOND_DISPLAY_ID);
6597 secondMonitor.assertNoEvents();
6598
6599 ASSERT_EQ(InputEventInjectionResult::FAILED,
6600 injectMotionEvent(*mDispatcher, AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN,
6601 SECOND_DISPLAY_ID, {110, 220}))
Prabir Pradhana0d43d42024-01-30 00:27:08 +00006602 << "The move event injected into the second display should fail because there's no "
6603 "touchable window";
Linnan Lid8150952024-01-26 18:07:17 +00006604 // Now the monitor on the second display should receive a cancel event.
6605 secondMonitor.consumeMotionCancel(SECOND_DISPLAY_ID);
Linnan Lid8150952024-01-26 18:07:17 +00006606
6607 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
6608 injectMotionEvent(*mDispatcher, AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN,
6609 ADISPLAY_ID_DEFAULT, {110, 200}))
6610 << "The move event injected into the first display should succeed";
6611
6612 window->consumeMotionMove();
6613 monitor.consumeMotionMove(ADISPLAY_ID_DEFAULT);
Linnan Lid8150952024-01-26 18:07:17 +00006614
6615 ASSERT_EQ(InputEventInjectionResult::FAILED,
Prabir Pradhana0d43d42024-01-30 00:27:08 +00006616 injectMotionUp(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, SECOND_DISPLAY_ID,
6617 {110, 220}))
6618 << "The up event injected into the second display should fail because there's no "
6619 "touchable window";
Linnan Lid8150952024-01-26 18:07:17 +00006620
6621 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
6622 injectMotionUp(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
6623 {110, 220}))
6624 << "The up event injected into the first display should succeed";
6625
6626 window->consumeMotionUp(ADISPLAY_ID_DEFAULT);
6627 monitor.consumeMotionUp(ADISPLAY_ID_DEFAULT);
Prabir Pradhana0d43d42024-01-30 00:27:08 +00006628
Linnan Lid8150952024-01-26 18:07:17 +00006629 window->assertNoEvents();
6630 monitor.assertNoEvents();
Prabir Pradhana0d43d42024-01-30 00:27:08 +00006631 secondWindow->assertNoEvents();
6632 secondMonitor.assertNoEvents();
Linnan Lid8150952024-01-26 18:07:17 +00006633}
6634
6635/**
6636 * One display with transform
6637 * There is a foreground window and a monitor on the display
6638 * Inject down event and move event sequentially, the foreground window and monitor can receive down
6639 * event and move event, then let the foreground window go away, the foreground window receives
6640 * cancel event, inject move event again, the monitor receives cancel event, all the events received
6641 * by the monitor should be with the same transform as the display
6642 */
6643TEST_F(InputDispatcherMonitorTest, MonitorTouchCancelEventWithDisplayTransform) {
6644 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
6645 sp<FakeWindowHandle> window =
6646 sp<FakeWindowHandle>::make(application, mDispatcher, "Foreground", ADISPLAY_ID_DEFAULT);
6647 FakeMonitorReceiver monitor = FakeMonitorReceiver(*mDispatcher, "M_1", ADISPLAY_ID_DEFAULT);
6648
6649 ui::Transform transform;
6650 transform.set({1.1, 2.2, 3.3, 4.4, 5.5, 6.6, 0, 0, 1});
6651
6652 gui::DisplayInfo displayInfo;
6653 displayInfo.displayId = ADISPLAY_ID_DEFAULT;
6654 displayInfo.transform = transform;
6655
6656 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {displayInfo}, 0, 0});
6657
6658 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
6659 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
6660 {100, 200}))
6661 << "The down event injected should succeed";
6662
6663 window->consumeMotionDown();
6664 std::unique_ptr<MotionEvent> downMotionEvent = monitor.consumeMotion();
6665 EXPECT_EQ(transform, downMotionEvent->getTransform());
6666 EXPECT_EQ(AMOTION_EVENT_ACTION_DOWN, downMotionEvent->getAction());
6667
6668 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
6669 injectMotionEvent(*mDispatcher, AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN,
6670 ADISPLAY_ID_DEFAULT, {110, 220}))
6671 << "The move event injected should succeed";
6672
6673 window->consumeMotionMove();
6674 std::unique_ptr<MotionEvent> moveMotionEvent = monitor.consumeMotion();
6675 EXPECT_EQ(transform, moveMotionEvent->getTransform());
6676 EXPECT_EQ(AMOTION_EVENT_ACTION_MOVE, moveMotionEvent->getAction());
6677
6678 // Let foreground window gone
6679 mDispatcher->onWindowInfosChanged({{}, {displayInfo}, 0, 0});
6680
Prabir Pradhana0d43d42024-01-30 00:27:08 +00006681 // Foreground window should receive a cancel event, but not the monitor.
Linnan Lid8150952024-01-26 18:07:17 +00006682 window->consumeMotionCancel();
Linnan Lid8150952024-01-26 18:07:17 +00006683
6684 ASSERT_EQ(InputEventInjectionResult::FAILED,
6685 injectMotionEvent(*mDispatcher, AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN,
6686 ADISPLAY_ID_DEFAULT, {110, 220}))
6687 << "The move event injected should failed";
6688 // Now foreground should not receive any events, but monitor should receive a cancel event
6689 // with transform that same as display's display.
Linnan Lid8150952024-01-26 18:07:17 +00006690 std::unique_ptr<MotionEvent> cancelMotionEvent = monitor.consumeMotion();
6691 EXPECT_EQ(transform, cancelMotionEvent->getTransform());
6692 EXPECT_EQ(ADISPLAY_ID_DEFAULT, cancelMotionEvent->getDisplayId());
6693 EXPECT_EQ(AMOTION_EVENT_ACTION_CANCEL, cancelMotionEvent->getAction());
6694
6695 // Other event inject to this display should fail.
6696 ASSERT_EQ(InputEventInjectionResult::FAILED,
6697 injectMotionEvent(*mDispatcher, AMOTION_EVENT_ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN,
6698 ADISPLAY_ID_DEFAULT, {110, 220}))
Prabir Pradhana0d43d42024-01-30 00:27:08 +00006699 << "The up event injected should fail because the touched window was removed";
Linnan Lid8150952024-01-26 18:07:17 +00006700 window->assertNoEvents();
6701 monitor.assertNoEvents();
6702}
6703
chaviw81e2bb92019-12-18 15:03:51 -08006704TEST_F(InputDispatcherTest, TestMoveEvent) {
Chris Yea209fde2020-07-22 13:54:51 -07006705 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07006706 sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher,
6707 "Fake Window", ADISPLAY_ID_DEFAULT);
chaviw81e2bb92019-12-18 15:03:51 -08006708
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07006709 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
chaviw81e2bb92019-12-18 15:03:51 -08006710
6711 NotifyMotionArgs motionArgs =
6712 generateMotionArgs(AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN,
6713 ADISPLAY_ID_DEFAULT);
6714
Prabir Pradhan678438e2023-04-13 19:32:51 +00006715 mDispatcher->notifyMotion(motionArgs);
chaviw81e2bb92019-12-18 15:03:51 -08006716 // Window should receive motion down event.
6717 window->consumeMotionDown(ADISPLAY_ID_DEFAULT);
6718
6719 motionArgs.action = AMOTION_EVENT_ACTION_MOVE;
Garfield Tanc51d1ba2020-01-28 13:24:04 -08006720 motionArgs.id += 1;
chaviw81e2bb92019-12-18 15:03:51 -08006721 motionArgs.eventTime = systemTime(SYSTEM_TIME_MONOTONIC);
6722 motionArgs.pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_X,
6723 motionArgs.pointerCoords[0].getX() - 10);
6724
Prabir Pradhan678438e2023-04-13 19:32:51 +00006725 mDispatcher->notifyMotion(motionArgs);
Prabir Pradhan7662a8d2023-12-15 01:58:14 +00006726 window->consumeMotionMove(ADISPLAY_ID_DEFAULT, /*expectedFlags=*/0);
chaviw81e2bb92019-12-18 15:03:51 -08006727}
6728
Siarhei Vishniakouf1035d42019-09-20 16:32:01 +01006729/**
6730 * Dispatcher has touch mode enabled by default. Typically, the policy overrides that value to
6731 * the device default right away. In the test scenario, we check both the default value,
6732 * and the action of enabling / disabling.
6733 */
6734TEST_F(InputDispatcherTest, TouchModeState_IsSentToApps) {
Chris Yea209fde2020-07-22 13:54:51 -07006735 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07006736 sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher,
6737 "Test window", ADISPLAY_ID_DEFAULT);
Antonio Kantekea47acb2021-12-23 12:41:25 -08006738 const WindowInfo& windowInfo = *window->getInfo();
Siarhei Vishniakouf1035d42019-09-20 16:32:01 +01006739
6740 // Set focused application.
6741 mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application);
Vishnu Nair47074b82020-08-14 11:54:47 -07006742 window->setFocusable(true);
Siarhei Vishniakouf1035d42019-09-20 16:32:01 +01006743
6744 SCOPED_TRACE("Check default value of touch mode");
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07006745 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Vishnu Nair958da932020-08-21 17:12:37 -07006746 setFocusedWindow(window);
Harry Cutts33476232023-01-30 19:57:29 +00006747 window->consumeFocusEvent(/*hasFocus=*/true, /*inTouchMode=*/true);
Siarhei Vishniakouf1035d42019-09-20 16:32:01 +01006748
6749 SCOPED_TRACE("Remove the window to trigger focus loss");
Vishnu Nair47074b82020-08-14 11:54:47 -07006750 window->setFocusable(false);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07006751 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Harry Cutts33476232023-01-30 19:57:29 +00006752 window->consumeFocusEvent(/*hasFocus=*/false, /*inTouchMode=*/true);
Siarhei Vishniakouf1035d42019-09-20 16:32:01 +01006753
6754 SCOPED_TRACE("Disable touch mode");
Antonio Kantekea47acb2021-12-23 12:41:25 -08006755 mDispatcher->setInTouchMode(false, windowInfo.ownerPid, windowInfo.ownerUid,
Harry Cutts33476232023-01-30 19:57:29 +00006756 /*hasPermission=*/true, ADISPLAY_ID_DEFAULT);
Antonio Kantekf16f2832021-09-28 04:39:20 +00006757 window->consumeTouchModeEvent(false);
Vishnu Nair47074b82020-08-14 11:54:47 -07006758 window->setFocusable(true);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07006759 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Vishnu Nair958da932020-08-21 17:12:37 -07006760 setFocusedWindow(window);
Harry Cutts33476232023-01-30 19:57:29 +00006761 window->consumeFocusEvent(/*hasFocus=*/true, /*inTouchMode=*/false);
Siarhei Vishniakouf1035d42019-09-20 16:32:01 +01006762
6763 SCOPED_TRACE("Remove the window to trigger focus loss");
Vishnu Nair47074b82020-08-14 11:54:47 -07006764 window->setFocusable(false);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07006765 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Harry Cutts33476232023-01-30 19:57:29 +00006766 window->consumeFocusEvent(/*hasFocus=*/false, /*inTouchMode=*/false);
Siarhei Vishniakouf1035d42019-09-20 16:32:01 +01006767
6768 SCOPED_TRACE("Enable touch mode again");
Antonio Kantekea47acb2021-12-23 12:41:25 -08006769 mDispatcher->setInTouchMode(true, windowInfo.ownerPid, windowInfo.ownerUid,
Harry Cutts33476232023-01-30 19:57:29 +00006770 /*hasPermission=*/true, ADISPLAY_ID_DEFAULT);
Antonio Kantekf16f2832021-09-28 04:39:20 +00006771 window->consumeTouchModeEvent(true);
Vishnu Nair47074b82020-08-14 11:54:47 -07006772 window->setFocusable(true);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07006773 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Vishnu Nair958da932020-08-21 17:12:37 -07006774 setFocusedWindow(window);
Harry Cutts33476232023-01-30 19:57:29 +00006775 window->consumeFocusEvent(/*hasFocus=*/true, /*inTouchMode=*/true);
Siarhei Vishniakouf1035d42019-09-20 16:32:01 +01006776
6777 window->assertNoEvents();
6778}
6779
Gang Wange9087892020-01-07 12:17:14 -05006780TEST_F(InputDispatcherTest, VerifyInputEvent_KeyEvent) {
Chris Yea209fde2020-07-22 13:54:51 -07006781 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07006782 sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher,
6783 "Test window", ADISPLAY_ID_DEFAULT);
Gang Wange9087892020-01-07 12:17:14 -05006784
6785 mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application);
Vishnu Nair47074b82020-08-14 11:54:47 -07006786 window->setFocusable(true);
Gang Wange9087892020-01-07 12:17:14 -05006787
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07006788 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Vishnu Nair958da932020-08-21 17:12:37 -07006789 setFocusedWindow(window);
6790
Harry Cutts33476232023-01-30 19:57:29 +00006791 window->consumeFocusEvent(/*hasFocus=*/true, /*inTouchMode=*/true);
Gang Wange9087892020-01-07 12:17:14 -05006792
Prabir Pradhan678438e2023-04-13 19:32:51 +00006793 const NotifyKeyArgs keyArgs = generateKeyArgs(AKEY_EVENT_ACTION_DOWN);
6794 mDispatcher->notifyKey(keyArgs);
Gang Wange9087892020-01-07 12:17:14 -05006795
Siarhei Vishniakoud3061ab2023-12-18 20:41:08 -08006796 std::unique_ptr<KeyEvent> event = window->consumeKey();
6797 ASSERT_NE(event, nullptr);
6798 std::unique_ptr<VerifiedInputEvent> verified = mDispatcher->verifyInputEvent(*event);
Gang Wange9087892020-01-07 12:17:14 -05006799 ASSERT_NE(verified, nullptr);
6800 ASSERT_EQ(verified->type, VerifiedInputEvent::Type::KEY);
6801
6802 ASSERT_EQ(keyArgs.eventTime, verified->eventTimeNanos);
6803 ASSERT_EQ(keyArgs.deviceId, verified->deviceId);
6804 ASSERT_EQ(keyArgs.source, verified->source);
6805 ASSERT_EQ(keyArgs.displayId, verified->displayId);
6806
6807 const VerifiedKeyEvent& verifiedKey = static_cast<const VerifiedKeyEvent&>(*verified);
6808
6809 ASSERT_EQ(keyArgs.action, verifiedKey.action);
Gang Wange9087892020-01-07 12:17:14 -05006810 ASSERT_EQ(keyArgs.flags & VERIFIED_KEY_EVENT_FLAGS, verifiedKey.flags);
Siarhei Vishniakouf355bf92021-12-09 10:43:21 -08006811 ASSERT_EQ(keyArgs.downTime, verifiedKey.downTimeNanos);
Gang Wange9087892020-01-07 12:17:14 -05006812 ASSERT_EQ(keyArgs.keyCode, verifiedKey.keyCode);
6813 ASSERT_EQ(keyArgs.scanCode, verifiedKey.scanCode);
6814 ASSERT_EQ(keyArgs.metaState, verifiedKey.metaState);
6815 ASSERT_EQ(0, verifiedKey.repeatCount);
6816}
6817
Siarhei Vishniakou47040bf2020-02-28 15:03:13 -08006818TEST_F(InputDispatcherTest, VerifyInputEvent_MotionEvent) {
Chris Yea209fde2020-07-22 13:54:51 -07006819 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07006820 sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher,
6821 "Test window", ADISPLAY_ID_DEFAULT);
Siarhei Vishniakou47040bf2020-02-28 15:03:13 -08006822
6823 mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application);
6824
Prabir Pradhanb5cb9572021-09-24 06:35:16 -07006825 ui::Transform transform;
6826 transform.set({1.1, 2.2, 3.3, 4.4, 5.5, 6.6, 0, 0, 1});
6827
6828 gui::DisplayInfo displayInfo;
6829 displayInfo.displayId = ADISPLAY_ID_DEFAULT;
6830 displayInfo.transform = transform;
6831
Patrick Williamsd828f302023-04-28 17:52:08 -05006832 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {displayInfo}, 0, 0});
Siarhei Vishniakou47040bf2020-02-28 15:03:13 -08006833
Prabir Pradhan678438e2023-04-13 19:32:51 +00006834 const NotifyMotionArgs motionArgs =
Siarhei Vishniakou47040bf2020-02-28 15:03:13 -08006835 generateMotionArgs(AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN,
6836 ADISPLAY_ID_DEFAULT);
Prabir Pradhan678438e2023-04-13 19:32:51 +00006837 mDispatcher->notifyMotion(motionArgs);
Siarhei Vishniakou47040bf2020-02-28 15:03:13 -08006838
Siarhei Vishniakoud3061ab2023-12-18 20:41:08 -08006839 std::unique_ptr<MotionEvent> event = window->consumeMotionEvent();
6840 ASSERT_NE(nullptr, event);
6841 std::unique_ptr<VerifiedInputEvent> verified = mDispatcher->verifyInputEvent(*event);
Siarhei Vishniakou47040bf2020-02-28 15:03:13 -08006842 ASSERT_NE(verified, nullptr);
6843 ASSERT_EQ(verified->type, VerifiedInputEvent::Type::MOTION);
6844
6845 EXPECT_EQ(motionArgs.eventTime, verified->eventTimeNanos);
6846 EXPECT_EQ(motionArgs.deviceId, verified->deviceId);
6847 EXPECT_EQ(motionArgs.source, verified->source);
6848 EXPECT_EQ(motionArgs.displayId, verified->displayId);
6849
6850 const VerifiedMotionEvent& verifiedMotion = static_cast<const VerifiedMotionEvent&>(*verified);
6851
Prabir Pradhanb5cb9572021-09-24 06:35:16 -07006852 const vec2 rawXY =
6853 MotionEvent::calculateTransformedXY(motionArgs.source, transform,
6854 motionArgs.pointerCoords[0].getXYValue());
6855 EXPECT_EQ(rawXY.x, verifiedMotion.rawX);
6856 EXPECT_EQ(rawXY.y, verifiedMotion.rawY);
Siarhei Vishniakou47040bf2020-02-28 15:03:13 -08006857 EXPECT_EQ(motionArgs.action & AMOTION_EVENT_ACTION_MASK, verifiedMotion.actionMasked);
Siarhei Vishniakou47040bf2020-02-28 15:03:13 -08006858 EXPECT_EQ(motionArgs.flags & VERIFIED_MOTION_EVENT_FLAGS, verifiedMotion.flags);
Siarhei Vishniakouf355bf92021-12-09 10:43:21 -08006859 EXPECT_EQ(motionArgs.downTime, verifiedMotion.downTimeNanos);
Siarhei Vishniakou47040bf2020-02-28 15:03:13 -08006860 EXPECT_EQ(motionArgs.metaState, verifiedMotion.metaState);
6861 EXPECT_EQ(motionArgs.buttonState, verifiedMotion.buttonState);
6862}
6863
chaviw09c8d2d2020-08-24 15:48:26 -07006864/**
6865 * Ensure that separate calls to sign the same data are generating the same key.
6866 * We avoid asserting against INVALID_HMAC. Since the key is random, there is a non-zero chance
6867 * that a specific key and data combination would produce INVALID_HMAC, which would cause flaky
6868 * tests.
6869 */
6870TEST_F(InputDispatcherTest, GeneratedHmac_IsConsistent) {
6871 KeyEvent event = getTestKeyEvent();
6872 VerifiedKeyEvent verifiedEvent = verifiedKeyEventFromKeyEvent(event);
6873
6874 std::array<uint8_t, 32> hmac1 = mDispatcher->sign(verifiedEvent);
6875 std::array<uint8_t, 32> hmac2 = mDispatcher->sign(verifiedEvent);
6876 ASSERT_EQ(hmac1, hmac2);
6877}
6878
6879/**
6880 * Ensure that changes in VerifiedKeyEvent produce a different hmac.
6881 */
6882TEST_F(InputDispatcherTest, GeneratedHmac_ChangesWhenFieldsChange) {
6883 KeyEvent event = getTestKeyEvent();
6884 VerifiedKeyEvent verifiedEvent = verifiedKeyEventFromKeyEvent(event);
6885 std::array<uint8_t, 32> initialHmac = mDispatcher->sign(verifiedEvent);
6886
6887 verifiedEvent.deviceId += 1;
6888 ASSERT_NE(initialHmac, mDispatcher->sign(verifiedEvent));
6889
6890 verifiedEvent.source += 1;
6891 ASSERT_NE(initialHmac, mDispatcher->sign(verifiedEvent));
6892
6893 verifiedEvent.eventTimeNanos += 1;
6894 ASSERT_NE(initialHmac, mDispatcher->sign(verifiedEvent));
6895
6896 verifiedEvent.displayId += 1;
6897 ASSERT_NE(initialHmac, mDispatcher->sign(verifiedEvent));
6898
6899 verifiedEvent.action += 1;
6900 ASSERT_NE(initialHmac, mDispatcher->sign(verifiedEvent));
6901
6902 verifiedEvent.downTimeNanos += 1;
6903 ASSERT_NE(initialHmac, mDispatcher->sign(verifiedEvent));
6904
6905 verifiedEvent.flags += 1;
6906 ASSERT_NE(initialHmac, mDispatcher->sign(verifiedEvent));
6907
6908 verifiedEvent.keyCode += 1;
6909 ASSERT_NE(initialHmac, mDispatcher->sign(verifiedEvent));
6910
6911 verifiedEvent.scanCode += 1;
6912 ASSERT_NE(initialHmac, mDispatcher->sign(verifiedEvent));
6913
6914 verifiedEvent.metaState += 1;
6915 ASSERT_NE(initialHmac, mDispatcher->sign(verifiedEvent));
6916
6917 verifiedEvent.repeatCount += 1;
6918 ASSERT_NE(initialHmac, mDispatcher->sign(verifiedEvent));
6919}
6920
Vishnu Nair958da932020-08-21 17:12:37 -07006921TEST_F(InputDispatcherTest, SetFocusedWindow) {
6922 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
6923 sp<FakeWindowHandle> windowTop =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07006924 sp<FakeWindowHandle>::make(application, mDispatcher, "Top", ADISPLAY_ID_DEFAULT);
Vishnu Nair958da932020-08-21 17:12:37 -07006925 sp<FakeWindowHandle> windowSecond =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07006926 sp<FakeWindowHandle>::make(application, mDispatcher, "Second", ADISPLAY_ID_DEFAULT);
Vishnu Nair958da932020-08-21 17:12:37 -07006927 mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application);
6928
6929 // Top window is also focusable but is not granted focus.
6930 windowTop->setFocusable(true);
6931 windowSecond->setFocusable(true);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07006932 mDispatcher->onWindowInfosChanged(
6933 {{*windowTop->getInfo(), *windowSecond->getInfo()}, {}, 0, 0});
Vishnu Nair958da932020-08-21 17:12:37 -07006934 setFocusedWindow(windowSecond);
6935
6936 windowSecond->consumeFocusEvent(true);
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07006937 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectKeyDown(*mDispatcher))
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08006938 << "Inject key event should return InputEventInjectionResult::SUCCEEDED";
Vishnu Nair958da932020-08-21 17:12:37 -07006939
6940 // Focused window should receive event.
6941 windowSecond->consumeKeyDown(ADISPLAY_ID_NONE);
6942 windowTop->assertNoEvents();
6943}
6944
6945TEST_F(InputDispatcherTest, SetFocusedWindow_DropRequestInvalidChannel) {
6946 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
6947 sp<FakeWindowHandle> window =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07006948 sp<FakeWindowHandle>::make(application, mDispatcher, "TestWindow", ADISPLAY_ID_DEFAULT);
Vishnu Nair958da932020-08-21 17:12:37 -07006949 mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application);
6950
6951 window->setFocusable(true);
6952 // Release channel for window is no longer valid.
6953 window->releaseChannel();
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07006954 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Vishnu Nair958da932020-08-21 17:12:37 -07006955 setFocusedWindow(window);
6956
6957 // Test inject a key down, should timeout.
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07006958 ASSERT_NO_FATAL_FAILURE(assertInjectedKeyTimesOut(*mDispatcher));
Vishnu Nair958da932020-08-21 17:12:37 -07006959
6960 // window channel is invalid, so it should not receive any input event.
6961 window->assertNoEvents();
6962}
6963
6964TEST_F(InputDispatcherTest, SetFocusedWindow_DropRequestNoFocusableWindow) {
6965 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
6966 sp<FakeWindowHandle> window =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07006967 sp<FakeWindowHandle>::make(application, mDispatcher, "TestWindow", ADISPLAY_ID_DEFAULT);
Prabir Pradhan76bdecb2022-01-31 11:14:15 -08006968 window->setFocusable(false);
Vishnu Nair958da932020-08-21 17:12:37 -07006969 mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application);
6970
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07006971 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Vishnu Nair958da932020-08-21 17:12:37 -07006972 setFocusedWindow(window);
6973
6974 // Test inject a key down, should timeout.
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07006975 ASSERT_NO_FATAL_FAILURE(assertInjectedKeyTimesOut(*mDispatcher));
Vishnu Nair958da932020-08-21 17:12:37 -07006976
Prabir Pradhan76bdecb2022-01-31 11:14:15 -08006977 // window is not focusable, so it should not receive any input event.
Vishnu Nair958da932020-08-21 17:12:37 -07006978 window->assertNoEvents();
6979}
6980
6981TEST_F(InputDispatcherTest, SetFocusedWindow_CheckFocusedToken) {
6982 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
6983 sp<FakeWindowHandle> windowTop =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07006984 sp<FakeWindowHandle>::make(application, mDispatcher, "Top", ADISPLAY_ID_DEFAULT);
Vishnu Nair958da932020-08-21 17:12:37 -07006985 sp<FakeWindowHandle> windowSecond =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07006986 sp<FakeWindowHandle>::make(application, mDispatcher, "Second", ADISPLAY_ID_DEFAULT);
Vishnu Nair958da932020-08-21 17:12:37 -07006987 mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application);
6988
6989 windowTop->setFocusable(true);
6990 windowSecond->setFocusable(true);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07006991 mDispatcher->onWindowInfosChanged(
6992 {{*windowTop->getInfo(), *windowSecond->getInfo()}, {}, 0, 0});
Vishnu Nair958da932020-08-21 17:12:37 -07006993 setFocusedWindow(windowTop);
6994 windowTop->consumeFocusEvent(true);
6995
Chavi Weingarten847e8512023-03-29 00:26:09 +00006996 windowTop->editInfo()->focusTransferTarget = windowSecond->getToken();
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07006997 mDispatcher->onWindowInfosChanged(
6998 {{*windowTop->getInfo(), *windowSecond->getInfo()}, {}, 0, 0});
Vishnu Nair958da932020-08-21 17:12:37 -07006999 windowSecond->consumeFocusEvent(true);
7000 windowTop->consumeFocusEvent(false);
7001
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07007002 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectKeyDown(*mDispatcher))
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08007003 << "Inject key event should return InputEventInjectionResult::SUCCEEDED";
Vishnu Nair958da932020-08-21 17:12:37 -07007004
7005 // Focused window should receive event.
7006 windowSecond->consumeKeyDown(ADISPLAY_ID_NONE);
7007}
7008
Chavi Weingarten847e8512023-03-29 00:26:09 +00007009TEST_F(InputDispatcherTest, SetFocusedWindow_TransferFocusTokenNotFocusable) {
Vishnu Nair958da932020-08-21 17:12:37 -07007010 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
7011 sp<FakeWindowHandle> windowTop =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07007012 sp<FakeWindowHandle>::make(application, mDispatcher, "Top", ADISPLAY_ID_DEFAULT);
Vishnu Nair958da932020-08-21 17:12:37 -07007013 sp<FakeWindowHandle> windowSecond =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07007014 sp<FakeWindowHandle>::make(application, mDispatcher, "Second", ADISPLAY_ID_DEFAULT);
Vishnu Nair958da932020-08-21 17:12:37 -07007015 mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application);
7016
7017 windowTop->setFocusable(true);
Chavi Weingarten847e8512023-03-29 00:26:09 +00007018 windowSecond->setFocusable(false);
7019 windowTop->editInfo()->focusTransferTarget = windowSecond->getToken();
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07007020 mDispatcher->onWindowInfosChanged(
7021 {{*windowTop->getInfo(), *windowSecond->getInfo()}, {}, 0, 0});
Chavi Weingarten847e8512023-03-29 00:26:09 +00007022 setFocusedWindow(windowTop);
7023 windowTop->consumeFocusEvent(true);
Vishnu Nair958da932020-08-21 17:12:37 -07007024
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07007025 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectKeyDown(*mDispatcher))
Chavi Weingarten847e8512023-03-29 00:26:09 +00007026 << "Inject key event should return InputEventInjectionResult::SUCCEEDED";
Vishnu Nair958da932020-08-21 17:12:37 -07007027
7028 // Event should be dropped.
Chavi Weingarten847e8512023-03-29 00:26:09 +00007029 windowTop->consumeKeyDown(ADISPLAY_ID_NONE);
Vishnu Nair958da932020-08-21 17:12:37 -07007030 windowSecond->assertNoEvents();
7031}
7032
7033TEST_F(InputDispatcherTest, SetFocusedWindow_DeferInvisibleWindow) {
7034 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
7035 sp<FakeWindowHandle> window =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07007036 sp<FakeWindowHandle>::make(application, mDispatcher, "TestWindow", ADISPLAY_ID_DEFAULT);
Vishnu Nair958da932020-08-21 17:12:37 -07007037 sp<FakeWindowHandle> previousFocusedWindow =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07007038 sp<FakeWindowHandle>::make(application, mDispatcher, "previousFocusedWindow",
7039 ADISPLAY_ID_DEFAULT);
Vishnu Nair958da932020-08-21 17:12:37 -07007040 mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application);
7041
7042 window->setFocusable(true);
7043 previousFocusedWindow->setFocusable(true);
7044 window->setVisible(false);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07007045 mDispatcher->onWindowInfosChanged(
7046 {{*window->getInfo(), *previousFocusedWindow->getInfo()}, {}, 0, 0});
Vishnu Nair958da932020-08-21 17:12:37 -07007047 setFocusedWindow(previousFocusedWindow);
7048 previousFocusedWindow->consumeFocusEvent(true);
7049
7050 // Requesting focus on invisible window takes focus from currently focused window.
7051 setFocusedWindow(window);
7052 previousFocusedWindow->consumeFocusEvent(false);
7053
7054 // Injected key goes to pending queue.
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08007055 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07007056 injectKey(*mDispatcher, AKEY_EVENT_ACTION_DOWN, /*repeatCount=*/0,
7057 ADISPLAY_ID_DEFAULT, InputEventInjectionSync::NONE));
Vishnu Nair958da932020-08-21 17:12:37 -07007058
7059 // Window does not get focus event or key down.
7060 window->assertNoEvents();
7061
7062 // Window becomes visible.
7063 window->setVisible(true);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07007064 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Vishnu Nair958da932020-08-21 17:12:37 -07007065
7066 // Window receives focus event.
7067 window->consumeFocusEvent(true);
7068 // Focused window receives key down.
7069 window->consumeKeyDown(ADISPLAY_ID_DEFAULT);
7070}
7071
Vishnu Nair599f1412021-06-21 10:39:58 -07007072TEST_F(InputDispatcherTest, DisplayRemoved) {
7073 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
7074 sp<FakeWindowHandle> window =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07007075 sp<FakeWindowHandle>::make(application, mDispatcher, "window", ADISPLAY_ID_DEFAULT);
Vishnu Nair599f1412021-06-21 10:39:58 -07007076 mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application);
7077
7078 // window is granted focus.
7079 window->setFocusable(true);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07007080 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Vishnu Nair599f1412021-06-21 10:39:58 -07007081 setFocusedWindow(window);
7082 window->consumeFocusEvent(true);
7083
7084 // When a display is removed window loses focus.
7085 mDispatcher->displayRemoved(ADISPLAY_ID_DEFAULT);
7086 window->consumeFocusEvent(false);
7087}
7088
Siarhei Vishniakou870ecec2020-12-09 08:07:46 -10007089/**
7090 * Launch two windows, with different owners. One window (slipperyExitWindow) has Flag::SLIPPERY,
7091 * and overlaps the other window, slipperyEnterWindow. The window 'slipperyExitWindow' is on top
7092 * of the 'slipperyEnterWindow'.
7093 *
7094 * Inject touch down into the top window. Upon receipt of the DOWN event, move the window in such
7095 * a way so that the touched location is no longer covered by the top window.
7096 *
7097 * Next, inject a MOVE event. Because the top window already moved earlier, this event is now
7098 * positioned over the bottom (slipperyEnterWindow) only. And because the top window had
7099 * Flag::SLIPPERY, this will cause the top window to lose the touch event (it will receive
7100 * ACTION_CANCEL instead), and the bottom window will receive a newly generated gesture (starting
7101 * with ACTION_DOWN).
7102 * Thus, the touch has been transferred from the top window into the bottom window, because the top
7103 * window moved itself away from the touched location and had Flag::SLIPPERY.
7104 *
7105 * Even though the top window moved away from the touched location, it is still obscuring the bottom
7106 * window. It's just not obscuring it at the touched location. That means, FLAG_WINDOW_IS_PARTIALLY_
7107 * OBSCURED should be set for the MotionEvent that reaches the bottom window.
7108 *
7109 * In this test, we ensure that the event received by the bottom window has
7110 * FLAG_WINDOW_IS_PARTIALLY_OBSCURED.
7111 */
7112TEST_F(InputDispatcherTest, SlipperyWindow_SetsFlagPartiallyObscured) {
Prabir Pradhanaeebeb42023-06-13 19:53:03 +00007113 constexpr gui::Pid SLIPPERY_PID{WINDOW_PID.val() + 1};
Prabir Pradhan8a5c41d2023-06-08 19:13:46 +00007114 constexpr gui::Uid SLIPPERY_UID{WINDOW_UID.val() + 1};
Siarhei Vishniakou870ecec2020-12-09 08:07:46 -10007115
7116 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
7117 mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application);
7118
7119 sp<FakeWindowHandle> slipperyExitWindow =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07007120 sp<FakeWindowHandle>::make(application, mDispatcher, "Top", ADISPLAY_ID_DEFAULT);
Prabir Pradhan4d5c52f2022-01-31 08:52:10 -08007121 slipperyExitWindow->setSlippery(true);
Siarhei Vishniakou870ecec2020-12-09 08:07:46 -10007122 // Make sure this one overlaps the bottom window
7123 slipperyExitWindow->setFrame(Rect(25, 25, 75, 75));
7124 // Change the owner uid/pid of the window so that it is considered to be occluding the bottom
7125 // one. Windows with the same owner are not considered to be occluding each other.
7126 slipperyExitWindow->setOwnerInfo(SLIPPERY_PID, SLIPPERY_UID);
7127
7128 sp<FakeWindowHandle> slipperyEnterWindow =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07007129 sp<FakeWindowHandle>::make(application, mDispatcher, "Second", ADISPLAY_ID_DEFAULT);
Siarhei Vishniakou870ecec2020-12-09 08:07:46 -10007130 slipperyExitWindow->setFrame(Rect(0, 0, 100, 100));
7131
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07007132 mDispatcher->onWindowInfosChanged(
7133 {{*slipperyExitWindow->getInfo(), *slipperyEnterWindow->getInfo()}, {}, 0, 0});
Siarhei Vishniakou870ecec2020-12-09 08:07:46 -10007134
7135 // Use notifyMotion instead of injecting to avoid dealing with injection permissions
Prabir Pradhan678438e2023-04-13 19:32:51 +00007136 mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_DOWN,
7137 AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
7138 {{50, 50}}));
Siarhei Vishniakou870ecec2020-12-09 08:07:46 -10007139 slipperyExitWindow->consumeMotionDown();
7140 slipperyExitWindow->setFrame(Rect(70, 70, 100, 100));
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07007141 mDispatcher->onWindowInfosChanged(
7142 {{*slipperyExitWindow->getInfo(), *slipperyEnterWindow->getInfo()}, {}, 0, 0});
Siarhei Vishniakou870ecec2020-12-09 08:07:46 -10007143
Prabir Pradhan678438e2023-04-13 19:32:51 +00007144 mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_MOVE,
7145 AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
7146 {{51, 51}}));
Siarhei Vishniakou870ecec2020-12-09 08:07:46 -10007147
7148 slipperyExitWindow->consumeMotionCancel();
7149
7150 slipperyEnterWindow->consumeMotionDown(ADISPLAY_ID_DEFAULT,
7151 AMOTION_EVENT_FLAG_WINDOW_IS_PARTIALLY_OBSCURED);
7152}
7153
Siarhei Vishniakouafa08cc2023-05-08 22:35:50 -07007154/**
7155 * Two windows, one on the left and another on the right. The left window is slippery. The right
7156 * window isn't eligible to receive touch because it specifies InputConfig::DROP_INPUT. When the
7157 * touch moves from the left window into the right window, the gesture should continue to go to the
7158 * left window. Touch shouldn't slip because the right window can't receive touches. This test
7159 * reproduces a crash.
7160 */
7161TEST_F(InputDispatcherTest, TouchSlippingIntoWindowThatDropsTouches) {
7162 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
7163
7164 sp<FakeWindowHandle> leftSlipperyWindow =
7165 sp<FakeWindowHandle>::make(application, mDispatcher, "Left", ADISPLAY_ID_DEFAULT);
7166 leftSlipperyWindow->setSlippery(true);
7167 leftSlipperyWindow->setFrame(Rect(0, 0, 100, 100));
7168
7169 sp<FakeWindowHandle> rightDropTouchesWindow =
7170 sp<FakeWindowHandle>::make(application, mDispatcher, "Right", ADISPLAY_ID_DEFAULT);
7171 rightDropTouchesWindow->setFrame(Rect(100, 0, 200, 100));
7172 rightDropTouchesWindow->setDropInput(true);
7173
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07007174 mDispatcher->onWindowInfosChanged(
7175 {{*leftSlipperyWindow->getInfo(), *rightDropTouchesWindow->getInfo()}, {}, 0, 0});
Siarhei Vishniakouafa08cc2023-05-08 22:35:50 -07007176
7177 // Start touch in the left window
7178 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
7179 .pointer(PointerBuilder(0, ToolType::FINGER).x(50).y(50))
7180 .build());
7181 leftSlipperyWindow->consumeMotionDown();
7182
7183 // And move it into the right window
7184 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN)
7185 .pointer(PointerBuilder(0, ToolType::FINGER).x(150).y(50))
7186 .build());
7187
7188 // Since the right window isn't eligible to receive input, touch does not slip.
7189 // The left window continues to receive the gesture.
7190 leftSlipperyWindow->consumeMotionEvent(WithMotionAction(ACTION_MOVE));
7191 rightDropTouchesWindow->assertNoEvents();
7192}
7193
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -07007194/**
7195 * A single window is on screen first. Touch is injected into that window. Next, a second window
7196 * appears. Since the first window is slippery, touch will move from the first window to the second.
7197 */
7198TEST_F(InputDispatcherTest, InjectedTouchSlips) {
7199 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
7200 sp<FakeWindowHandle> originalWindow =
7201 sp<FakeWindowHandle>::make(application, mDispatcher, "Original", ADISPLAY_ID_DEFAULT);
7202 originalWindow->setFrame(Rect(0, 0, 200, 200));
7203 originalWindow->setSlippery(true);
7204
7205 sp<FakeWindowHandle> appearingWindow =
7206 sp<FakeWindowHandle>::make(application, mDispatcher, "Appearing", ADISPLAY_ID_DEFAULT);
7207 appearingWindow->setFrame(Rect(0, 0, 200, 200));
7208
7209 mDispatcher->onWindowInfosChanged({{*originalWindow->getInfo()}, {}, 0, 0});
7210
7211 // Touch down on the original window
7212 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
7213 injectMotionEvent(*mDispatcher,
7214 MotionEventBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
7215 .pointer(PointerBuilder(1, ToolType::FINGER).x(100).y(100))
7216 .build()));
7217 originalWindow->consumeMotionEvent(WithMotionAction(ACTION_DOWN));
7218
7219 // Now, a new window appears. This could be, for example, a notification shade that appears
7220 // after user starts to drag down on the launcher window.
7221 mDispatcher->onWindowInfosChanged(
7222 {{*appearingWindow->getInfo(), *originalWindow->getInfo()}, {}, 0, 0});
7223 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
7224 injectMotionEvent(*mDispatcher,
7225 MotionEventBuilder(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN)
7226 .pointer(PointerBuilder(1, ToolType::FINGER).x(110).y(110))
7227 .build()));
7228 originalWindow->consumeMotionEvent(WithMotionAction(ACTION_CANCEL));
7229 appearingWindow->consumeMotionEvent(WithMotionAction(ACTION_DOWN));
7230 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
7231 injectMotionEvent(*mDispatcher,
7232 MotionEventBuilder(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN)
7233 .pointer(PointerBuilder(1, ToolType::FINGER).x(120).y(120))
7234 .build()));
7235 appearingWindow->consumeMotionEvent(WithMotionAction(ACTION_MOVE));
7236
7237 originalWindow->assertNoEvents();
7238 appearingWindow->assertNoEvents();
7239}
7240
Prabir Pradhan8ede1d12023-05-08 19:37:44 +00007241TEST_F(InputDispatcherTest, NotifiesDeviceInteractionsWithMotions) {
Prabir Pradhan8a5c41d2023-06-08 19:13:46 +00007242 using Uid = gui::Uid;
Prabir Pradhan8ede1d12023-05-08 19:37:44 +00007243 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
7244
7245 sp<FakeWindowHandle> leftWindow =
7246 sp<FakeWindowHandle>::make(application, mDispatcher, "Left", ADISPLAY_ID_DEFAULT);
7247 leftWindow->setFrame(Rect(0, 0, 100, 100));
Prabir Pradhanaeebeb42023-06-13 19:53:03 +00007248 leftWindow->setOwnerInfo(gui::Pid{1}, Uid{101});
Prabir Pradhan8ede1d12023-05-08 19:37:44 +00007249
7250 sp<FakeWindowHandle> rightSpy =
7251 sp<FakeWindowHandle>::make(application, mDispatcher, "Right spy", ADISPLAY_ID_DEFAULT);
7252 rightSpy->setFrame(Rect(100, 0, 200, 100));
Prabir Pradhanaeebeb42023-06-13 19:53:03 +00007253 rightSpy->setOwnerInfo(gui::Pid{2}, Uid{102});
Prabir Pradhan8ede1d12023-05-08 19:37:44 +00007254 rightSpy->setSpy(true);
7255 rightSpy->setTrustedOverlay(true);
7256
7257 sp<FakeWindowHandle> rightWindow =
7258 sp<FakeWindowHandle>::make(application, mDispatcher, "Right", ADISPLAY_ID_DEFAULT);
7259 rightWindow->setFrame(Rect(100, 0, 200, 100));
Prabir Pradhanaeebeb42023-06-13 19:53:03 +00007260 rightWindow->setOwnerInfo(gui::Pid{3}, Uid{103});
Prabir Pradhan8ede1d12023-05-08 19:37:44 +00007261
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07007262 mDispatcher->onWindowInfosChanged(
7263 {{*rightSpy->getInfo(), *rightWindow->getInfo(), *leftWindow->getInfo()}, {}, 0, 0});
Prabir Pradhan8ede1d12023-05-08 19:37:44 +00007264
7265 // Touch in the left window
7266 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
7267 .pointer(PointerBuilder(0, ToolType::FINGER).x(50).y(50))
7268 .build());
7269 ASSERT_NO_FATAL_FAILURE(leftWindow->consumeMotionDown());
7270 mDispatcher->waitForIdle();
Prabir Pradhan8a5c41d2023-06-08 19:13:46 +00007271 ASSERT_NO_FATAL_FAILURE(
7272 mFakePolicy->assertNotifyDeviceInteractionWasCalled(DEVICE_ID, {Uid{101}}));
Prabir Pradhan8ede1d12023-05-08 19:37:44 +00007273
7274 // Touch another finger over the right windows
7275 mDispatcher->notifyMotion(MotionArgsBuilder(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
7276 .pointer(PointerBuilder(0, ToolType::FINGER).x(50).y(50))
7277 .pointer(PointerBuilder(1, ToolType::FINGER).x(150).y(50))
7278 .build());
7279 ASSERT_NO_FATAL_FAILURE(rightSpy->consumeMotionDown());
7280 ASSERT_NO_FATAL_FAILURE(rightWindow->consumeMotionDown());
7281 ASSERT_NO_FATAL_FAILURE(leftWindow->consumeMotionMove());
7282 mDispatcher->waitForIdle();
7283 ASSERT_NO_FATAL_FAILURE(
Prabir Pradhan8a5c41d2023-06-08 19:13:46 +00007284 mFakePolicy->assertNotifyDeviceInteractionWasCalled(DEVICE_ID,
7285 {Uid{101}, Uid{102}, Uid{103}}));
Prabir Pradhan8ede1d12023-05-08 19:37:44 +00007286
7287 // Release finger over left window. The UP actions are not treated as device interaction.
7288 // The windows that did not receive the UP pointer will receive MOVE events, but since this
7289 // is part of the UP action, we do not treat this as device interaction.
7290 mDispatcher->notifyMotion(MotionArgsBuilder(POINTER_0_UP, AINPUT_SOURCE_TOUCHSCREEN)
7291 .pointer(PointerBuilder(0, ToolType::FINGER).x(50).y(50))
7292 .pointer(PointerBuilder(1, ToolType::FINGER).x(150).y(50))
7293 .build());
7294 ASSERT_NO_FATAL_FAILURE(leftWindow->consumeMotionUp());
7295 ASSERT_NO_FATAL_FAILURE(rightSpy->consumeMotionMove());
7296 ASSERT_NO_FATAL_FAILURE(rightWindow->consumeMotionMove());
7297 mDispatcher->waitForIdle();
7298 ASSERT_NO_FATAL_FAILURE(mFakePolicy->assertNotifyDeviceInteractionWasNotCalled());
7299
7300 // Move remaining finger
7301 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN)
7302 .pointer(PointerBuilder(1, ToolType::FINGER).x(150).y(50))
7303 .build());
7304 ASSERT_NO_FATAL_FAILURE(rightSpy->consumeMotionMove());
7305 ASSERT_NO_FATAL_FAILURE(rightWindow->consumeMotionMove());
7306 mDispatcher->waitForIdle();
7307 ASSERT_NO_FATAL_FAILURE(
Prabir Pradhan8a5c41d2023-06-08 19:13:46 +00007308 mFakePolicy->assertNotifyDeviceInteractionWasCalled(DEVICE_ID, {Uid{102}, Uid{103}}));
Prabir Pradhan8ede1d12023-05-08 19:37:44 +00007309
7310 // Release all fingers
7311 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN)
7312 .pointer(PointerBuilder(1, ToolType::FINGER).x(150).y(50))
7313 .build());
7314 ASSERT_NO_FATAL_FAILURE(rightSpy->consumeMotionUp());
7315 ASSERT_NO_FATAL_FAILURE(rightWindow->consumeMotionUp());
7316 mDispatcher->waitForIdle();
7317 ASSERT_NO_FATAL_FAILURE(mFakePolicy->assertNotifyDeviceInteractionWasNotCalled());
7318}
7319
7320TEST_F(InputDispatcherTest, NotifiesDeviceInteractionsWithKeys) {
7321 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
7322
7323 sp<FakeWindowHandle> window =
7324 sp<FakeWindowHandle>::make(application, mDispatcher, "Window", ADISPLAY_ID_DEFAULT);
7325 window->setFrame(Rect(0, 0, 100, 100));
Prabir Pradhanaeebeb42023-06-13 19:53:03 +00007326 window->setOwnerInfo(gui::Pid{1}, gui::Uid{101});
Prabir Pradhan8ede1d12023-05-08 19:37:44 +00007327
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07007328 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Prabir Pradhan8ede1d12023-05-08 19:37:44 +00007329 setFocusedWindow(window);
7330 ASSERT_NO_FATAL_FAILURE(window->consumeFocusEvent(true));
7331
7332 mDispatcher->notifyKey(KeyArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_KEYBOARD).build());
7333 ASSERT_NO_FATAL_FAILURE(window->consumeKeyDown(ADISPLAY_ID_DEFAULT));
7334 mDispatcher->waitForIdle();
Prabir Pradhan8a5c41d2023-06-08 19:13:46 +00007335 ASSERT_NO_FATAL_FAILURE(
7336 mFakePolicy->assertNotifyDeviceInteractionWasCalled(DEVICE_ID, {gui::Uid{101}}));
Prabir Pradhan8ede1d12023-05-08 19:37:44 +00007337
7338 // The UP actions are not treated as device interaction.
7339 mDispatcher->notifyKey(KeyArgsBuilder(ACTION_UP, AINPUT_SOURCE_KEYBOARD).build());
7340 ASSERT_NO_FATAL_FAILURE(window->consumeKeyUp(ADISPLAY_ID_DEFAULT));
7341 mDispatcher->waitForIdle();
7342 ASSERT_NO_FATAL_FAILURE(mFakePolicy->assertNotifyDeviceInteractionWasNotCalled());
7343}
7344
Prabir Pradhan5893d362023-11-17 04:30:40 +00007345TEST_F(InputDispatcherTest, HoverEnterExitSynthesisUsesNewEventId) {
7346 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
7347
7348 sp<FakeWindowHandle> left = sp<FakeWindowHandle>::make(application, mDispatcher, "Left Window",
7349 ADISPLAY_ID_DEFAULT);
7350 left->setFrame(Rect(0, 0, 100, 100));
7351 sp<FakeWindowHandle> right = sp<FakeWindowHandle>::make(application, mDispatcher,
7352 "Right Window", ADISPLAY_ID_DEFAULT);
7353 right->setFrame(Rect(100, 0, 200, 100));
7354 sp<FakeWindowHandle> spy =
7355 sp<FakeWindowHandle>::make(application, mDispatcher, "Spy Window", ADISPLAY_ID_DEFAULT);
7356 spy->setFrame(Rect(0, 0, 200, 100));
7357 spy->setTrustedOverlay(true);
7358 spy->setSpy(true);
7359
7360 mDispatcher->onWindowInfosChanged(
7361 {{*spy->getInfo(), *left->getInfo(), *right->getInfo()}, {}, 0, 0});
7362
7363 // Send hover move to the left window, and ensure hover enter is synthesized with a new eventId.
7364 NotifyMotionArgs notifyArgs = generateMotionArgs(ACTION_HOVER_MOVE, AINPUT_SOURCE_STYLUS,
7365 ADISPLAY_ID_DEFAULT, {PointF{50, 50}});
7366 mDispatcher->notifyMotion(notifyArgs);
7367
Siarhei Vishniakoud3061ab2023-12-18 20:41:08 -08007368 std::unique_ptr<MotionEvent> leftEnter = left->consumeMotionEvent(
Prabir Pradhan5893d362023-11-17 04:30:40 +00007369 AllOf(WithMotionAction(ACTION_HOVER_ENTER), Not(WithEventId(notifyArgs.id)),
7370 WithEventIdSource(IdGenerator::Source::INPUT_DISPATCHER)));
Siarhei Vishniakoud3061ab2023-12-18 20:41:08 -08007371 ASSERT_NE(nullptr, leftEnter);
Prabir Pradhan5893d362023-11-17 04:30:40 +00007372 spy->consumeMotionEvent(AllOf(WithMotionAction(ACTION_HOVER_ENTER),
7373 Not(WithEventId(notifyArgs.id)),
Siarhei Vishniakoud3061ab2023-12-18 20:41:08 -08007374 Not(WithEventId(leftEnter->getId())),
Prabir Pradhan5893d362023-11-17 04:30:40 +00007375 WithEventIdSource(IdGenerator::Source::INPUT_DISPATCHER)));
7376
7377 // Send move to the right window, and ensure hover exit and enter are synthesized with new ids.
7378 notifyArgs = generateMotionArgs(ACTION_HOVER_MOVE, AINPUT_SOURCE_STYLUS, ADISPLAY_ID_DEFAULT,
7379 {PointF{150, 50}});
7380 mDispatcher->notifyMotion(notifyArgs);
7381
Siarhei Vishniakoud3061ab2023-12-18 20:41:08 -08007382 std::unique_ptr<MotionEvent> leftExit = left->consumeMotionEvent(
Prabir Pradhan5893d362023-11-17 04:30:40 +00007383 AllOf(WithMotionAction(ACTION_HOVER_EXIT), Not(WithEventId(notifyArgs.id)),
7384 WithEventIdSource(IdGenerator::Source::INPUT_DISPATCHER)));
Siarhei Vishniakoud3061ab2023-12-18 20:41:08 -08007385 ASSERT_NE(nullptr, leftExit);
Prabir Pradhan5893d362023-11-17 04:30:40 +00007386 right->consumeMotionEvent(AllOf(WithMotionAction(ACTION_HOVER_ENTER),
7387 Not(WithEventId(notifyArgs.id)),
Siarhei Vishniakoud3061ab2023-12-18 20:41:08 -08007388 Not(WithEventId(leftExit->getId())),
Prabir Pradhan5893d362023-11-17 04:30:40 +00007389 WithEventIdSource(IdGenerator::Source::INPUT_DISPATCHER)));
7390
7391 spy->consumeMotionEvent(AllOf(WithMotionAction(ACTION_HOVER_MOVE), WithEventId(notifyArgs.id)));
7392}
7393
Prabir Pradhanb0dad3a2023-11-02 20:52:47 +00007394class InputDispatcherFallbackKeyTest : public InputDispatcherTest {
7395protected:
7396 std::shared_ptr<FakeApplicationHandle> mApp;
7397 sp<FakeWindowHandle> mWindow;
7398
7399 virtual void SetUp() override {
7400 InputDispatcherTest::SetUp();
7401
7402 mApp = std::make_shared<FakeApplicationHandle>();
7403
7404 mWindow = sp<FakeWindowHandle>::make(mApp, mDispatcher, "Window", ADISPLAY_ID_DEFAULT);
7405 mWindow->setFrame(Rect(0, 0, 100, 100));
7406
7407 mDispatcher->onWindowInfosChanged({{*mWindow->getInfo()}, {}, 0, 0});
7408 setFocusedWindow(mWindow);
7409 ASSERT_NO_FATAL_FAILURE(mWindow->consumeFocusEvent(/*hasFocus=*/true));
7410 }
7411
7412 void setFallback(int32_t keycode) {
7413 mFakePolicy->setUnhandledKeyHandler([keycode](const KeyEvent& event) {
7414 return KeyEventBuilder(event).keyCode(keycode).build();
7415 });
7416 }
7417
7418 void consumeKey(bool handled, const ::testing::Matcher<KeyEvent>& matcher) {
Siarhei Vishniakoud3061ab2023-12-18 20:41:08 -08007419 std::unique_ptr<KeyEvent> event = mWindow->consumeKey(handled);
7420 ASSERT_NE(nullptr, event);
7421 ASSERT_THAT(*event, matcher);
Prabir Pradhanb0dad3a2023-11-02 20:52:47 +00007422 }
7423};
7424
7425TEST_F(InputDispatcherFallbackKeyTest, PolicyNotNotifiedForHandledKey) {
7426 mDispatcher->notifyKey(
7427 KeyArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_KEYBOARD).keyCode(AKEYCODE_A).build());
7428 consumeKey(/*handled=*/true, AllOf(WithKeyAction(ACTION_DOWN), WithKeyCode(AKEYCODE_A)));
7429 ASSERT_NO_FATAL_FAILURE(mFakePolicy->assertUnhandledKeyNotReported());
7430}
7431
7432TEST_F(InputDispatcherFallbackKeyTest, PolicyNotifiedForUnhandledKey) {
7433 mDispatcher->notifyKey(
7434 KeyArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_KEYBOARD).keyCode(AKEYCODE_A).build());
7435 consumeKey(/*handled=*/false, AllOf(WithKeyAction(ACTION_DOWN), WithKeyCode(AKEYCODE_A)));
7436 ASSERT_NO_FATAL_FAILURE(mFakePolicy->assertUnhandledKeyReported(AKEYCODE_A));
7437}
7438
7439TEST_F(InputDispatcherFallbackKeyTest, NoFallbackRequestedByPolicy) {
7440 mDispatcher->notifyKey(
7441 KeyArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_KEYBOARD).keyCode(AKEYCODE_A).build());
7442
7443 // Do not handle this key event.
7444 consumeKey(/*handled=*/false,
7445 AllOf(WithKeyAction(ACTION_DOWN), WithKeyCode(AKEYCODE_A), WithFlags(0)));
7446 ASSERT_NO_FATAL_FAILURE(mFakePolicy->assertUnhandledKeyReported(AKEYCODE_A));
7447
7448 // Since the policy did not request any fallback to be generated, ensure there are no events.
7449 ASSERT_NO_FATAL_FAILURE(mFakePolicy->assertUnhandledKeyNotReported());
7450}
7451
7452TEST_F(InputDispatcherFallbackKeyTest, FallbackDispatchForUnhandledKey) {
7453 setFallback(AKEYCODE_B);
7454 mDispatcher->notifyKey(
7455 KeyArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_KEYBOARD).keyCode(AKEYCODE_A).build());
7456
7457 // Do not handle this key event.
7458 consumeKey(/*handled=*/false,
7459 AllOf(WithKeyAction(ACTION_DOWN), WithKeyCode(AKEYCODE_A), WithFlags(0)));
7460
7461 // Since the key was not handled, ensure the fallback event was dispatched instead.
7462 ASSERT_NO_FATAL_FAILURE(mFakePolicy->assertUnhandledKeyReported(AKEYCODE_A));
7463 consumeKey(/*handled=*/true,
7464 AllOf(WithKeyAction(ACTION_DOWN), WithKeyCode(AKEYCODE_B),
7465 WithFlags(AKEY_EVENT_FLAG_FALLBACK)));
7466
7467 // Release the original key, and ensure the fallback key is also released.
7468 mDispatcher->notifyKey(
7469 KeyArgsBuilder(ACTION_UP, AINPUT_SOURCE_KEYBOARD).keyCode(AKEYCODE_A).build());
7470 consumeKey(/*handled=*/false,
7471 AllOf(WithKeyAction(ACTION_UP), WithKeyCode(AKEYCODE_A), WithFlags(0)));
7472 ASSERT_NO_FATAL_FAILURE(mFakePolicy->assertUnhandledKeyReported(AKEYCODE_A));
7473 consumeKey(/*handled=*/true,
7474 AllOf(WithKeyAction(ACTION_UP), WithKeyCode(AKEYCODE_B),
7475 WithFlags(AKEY_EVENT_FLAG_FALLBACK)));
7476
7477 ASSERT_NO_FATAL_FAILURE(mFakePolicy->assertUnhandledKeyNotReported());
7478 mWindow->assertNoEvents();
7479}
7480
7481TEST_F(InputDispatcherFallbackKeyTest, AppHandlesPreviouslyUnhandledKey) {
7482 setFallback(AKEYCODE_B);
7483 mDispatcher->notifyKey(
7484 KeyArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_KEYBOARD).keyCode(AKEYCODE_A).build());
7485
7486 // Do not handle this key event, but handle the fallback.
7487 consumeKey(/*handled=*/false,
7488 AllOf(WithKeyAction(ACTION_DOWN), WithKeyCode(AKEYCODE_A), WithFlags(0)));
7489 ASSERT_NO_FATAL_FAILURE(mFakePolicy->assertUnhandledKeyReported(AKEYCODE_A));
7490 consumeKey(/*handled=*/true,
7491 AllOf(WithKeyAction(ACTION_DOWN), WithKeyCode(AKEYCODE_B),
7492 WithFlags(AKEY_EVENT_FLAG_FALLBACK)));
7493
7494 // Release the original key, and ensure the fallback key is also released.
7495 mDispatcher->notifyKey(
7496 KeyArgsBuilder(ACTION_UP, AINPUT_SOURCE_KEYBOARD).keyCode(AKEYCODE_A).build());
7497 // But this time, the app handles the original key.
7498 consumeKey(/*handled=*/true,
7499 AllOf(WithKeyAction(ACTION_UP), WithKeyCode(AKEYCODE_A), WithFlags(0)));
7500 ASSERT_NO_FATAL_FAILURE(mFakePolicy->assertUnhandledKeyReported(AKEYCODE_A));
7501 // Ensure the fallback key is canceled.
7502 consumeKey(/*handled=*/true,
7503 AllOf(WithKeyAction(ACTION_UP), WithKeyCode(AKEYCODE_B),
7504 WithFlags(AKEY_EVENT_FLAG_FALLBACK | AKEY_EVENT_FLAG_CANCELED)));
7505
7506 ASSERT_NO_FATAL_FAILURE(mFakePolicy->assertUnhandledKeyNotReported());
7507 mWindow->assertNoEvents();
7508}
7509
7510TEST_F(InputDispatcherFallbackKeyTest, AppDoesNotHandleFallback) {
7511 setFallback(AKEYCODE_B);
7512 mDispatcher->notifyKey(
7513 KeyArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_KEYBOARD).keyCode(AKEYCODE_A).build());
7514
7515 // Do not handle this key event.
7516 consumeKey(/*handled=*/false,
7517 AllOf(WithKeyAction(ACTION_DOWN), WithKeyCode(AKEYCODE_A), WithFlags(0)));
7518 ASSERT_NO_FATAL_FAILURE(mFakePolicy->assertUnhandledKeyReported(AKEYCODE_A));
7519 // App does not handle the fallback either, so ensure another fallback is not generated.
7520 setFallback(AKEYCODE_C);
7521 consumeKey(/*handled=*/false,
7522 AllOf(WithKeyAction(ACTION_DOWN), WithKeyCode(AKEYCODE_B),
7523 WithFlags(AKEY_EVENT_FLAG_FALLBACK)));
7524
7525 // Release the original key, and ensure the fallback key is also released.
7526 setFallback(AKEYCODE_B);
7527 mDispatcher->notifyKey(
7528 KeyArgsBuilder(ACTION_UP, AINPUT_SOURCE_KEYBOARD).keyCode(AKEYCODE_A).build());
7529 consumeKey(/*handled=*/false,
7530 AllOf(WithKeyAction(ACTION_UP), WithKeyCode(AKEYCODE_A), WithFlags(0)));
7531 ASSERT_NO_FATAL_FAILURE(mFakePolicy->assertUnhandledKeyReported(AKEYCODE_A));
7532 consumeKey(/*handled=*/false,
7533 AllOf(WithKeyAction(ACTION_UP), WithKeyCode(AKEYCODE_B),
7534 WithFlags(AKEY_EVENT_FLAG_FALLBACK)));
7535
7536 ASSERT_NO_FATAL_FAILURE(mFakePolicy->assertUnhandledKeyNotReported());
7537 mWindow->assertNoEvents();
7538}
7539
7540TEST_F(InputDispatcherFallbackKeyTest, InconsistentPolicyCancelsFallback) {
7541 setFallback(AKEYCODE_B);
7542 mDispatcher->notifyKey(
7543 KeyArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_KEYBOARD).keyCode(AKEYCODE_A).build());
7544
7545 // Do not handle this key event, so fallback is generated.
7546 consumeKey(/*handled=*/false,
7547 AllOf(WithKeyAction(ACTION_DOWN), WithKeyCode(AKEYCODE_A), WithFlags(0)));
7548 ASSERT_NO_FATAL_FAILURE(mFakePolicy->assertUnhandledKeyReported(AKEYCODE_A));
7549 consumeKey(/*handled=*/true,
7550 AllOf(WithKeyAction(ACTION_DOWN), WithKeyCode(AKEYCODE_B),
7551 WithFlags(AKEY_EVENT_FLAG_FALLBACK)));
7552
7553 // Release the original key, but assume the policy is misbehaving and it
7554 // generates an inconsistent fallback to the one from the DOWN event.
7555 setFallback(AKEYCODE_C);
7556 mDispatcher->notifyKey(
7557 KeyArgsBuilder(ACTION_UP, AINPUT_SOURCE_KEYBOARD).keyCode(AKEYCODE_A).build());
7558 consumeKey(/*handled=*/false,
7559 AllOf(WithKeyAction(ACTION_UP), WithKeyCode(AKEYCODE_A), WithFlags(0)));
7560 ASSERT_NO_FATAL_FAILURE(mFakePolicy->assertUnhandledKeyReported(AKEYCODE_A));
7561 // Ensure the fallback key reported before as DOWN is canceled due to the inconsistency.
7562 consumeKey(/*handled=*/true,
7563 AllOf(WithKeyAction(ACTION_UP), WithKeyCode(AKEYCODE_B),
7564 WithFlags(AKEY_EVENT_FLAG_FALLBACK | AKEY_EVENT_FLAG_CANCELED)));
7565
7566 ASSERT_NO_FATAL_FAILURE(mFakePolicy->assertUnhandledKeyNotReported());
7567 mWindow->assertNoEvents();
7568}
7569
7570TEST_F(InputDispatcherFallbackKeyTest, CanceledKeyCancelsFallback) {
7571 setFallback(AKEYCODE_B);
7572 mDispatcher->notifyKey(
7573 KeyArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_KEYBOARD).keyCode(AKEYCODE_A).build());
7574
7575 // Do not handle this key event, so fallback is generated.
7576 consumeKey(/*handled=*/false,
7577 AllOf(WithKeyAction(ACTION_DOWN), WithKeyCode(AKEYCODE_A), WithFlags(0)));
7578 ASSERT_NO_FATAL_FAILURE(mFakePolicy->assertUnhandledKeyReported(AKEYCODE_A));
7579 consumeKey(/*handled=*/true,
7580 AllOf(WithKeyAction(ACTION_DOWN), WithKeyCode(AKEYCODE_B),
7581 WithFlags(AKEY_EVENT_FLAG_FALLBACK)));
7582
7583 // The original key is canceled.
7584 mDispatcher->notifyKey(KeyArgsBuilder(ACTION_UP, AINPUT_SOURCE_KEYBOARD)
7585 .keyCode(AKEYCODE_A)
7586 .addFlag(AKEY_EVENT_FLAG_CANCELED)
7587 .build());
7588 consumeKey(/*handled=*/false,
7589 AllOf(WithKeyAction(ACTION_UP), WithKeyCode(AKEYCODE_A),
7590 WithFlags(AKEY_EVENT_FLAG_CANCELED)));
7591 ASSERT_NO_FATAL_FAILURE(mFakePolicy->assertUnhandledKeyReported(AKEYCODE_A));
7592 // Ensure the fallback key is also canceled due to the original key being canceled.
7593 consumeKey(/*handled=*/true,
7594 AllOf(WithKeyAction(ACTION_UP), WithKeyCode(AKEYCODE_B),
7595 WithFlags(AKEY_EVENT_FLAG_FALLBACK | AKEY_EVENT_FLAG_CANCELED)));
7596
7597 ASSERT_NO_FATAL_FAILURE(mFakePolicy->assertUnhandledKeyNotReported());
7598 mWindow->assertNoEvents();
7599}
7600
Prabir Pradhanfa2c69f2024-02-01 20:31:34 +00007601TEST_F(InputDispatcherFallbackKeyTest, InputChannelRemovedDuringPolicyCall) {
Prabir Pradhanb13da8f2024-01-09 23:10:13 +00007602 setFallback(AKEYCODE_B);
7603 mDispatcher->notifyKey(
7604 KeyArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_KEYBOARD).keyCode(AKEYCODE_A).build());
7605
7606 // Do not handle this key event.
7607 consumeKey(/*handled=*/false,
7608 AllOf(WithKeyAction(ACTION_DOWN), WithKeyCode(AKEYCODE_A), WithFlags(0)));
7609 ASSERT_NO_FATAL_FAILURE(mFakePolicy->assertUnhandledKeyReported(AKEYCODE_A));
7610 consumeKey(/*handled=*/true,
7611 AllOf(WithKeyAction(ACTION_DOWN), WithKeyCode(AKEYCODE_B),
7612 WithFlags(AKEY_EVENT_FLAG_FALLBACK)));
7613
7614 mFakePolicy->setUnhandledKeyHandler([&](const KeyEvent& event) {
7615 // When the unhandled key is reported to the policy next, remove the input channel.
7616 mDispatcher->removeInputChannel(mWindow->getToken());
7617 return KeyEventBuilder(event).keyCode(AKEYCODE_B).build();
7618 });
7619 // Release the original key, and let the app now handle the previously unhandled key.
7620 // This should result in the previously generated fallback key to be cancelled.
7621 // Since the policy was notified of the unhandled DOWN event earlier, it will also be notified
7622 // of the UP event for consistency. The Dispatcher calls into the policy from its own thread
7623 // without holding the lock, because it need to synchronously fetch the fallback key. While in
7624 // the policy call, we will now remove the input channel. Once the policy call returns, the
7625 // Dispatcher will no longer have a channel to send cancellation events to. Ensure this does
7626 // not cause any crashes.
7627 mDispatcher->notifyKey(
7628 KeyArgsBuilder(ACTION_UP, AINPUT_SOURCE_KEYBOARD).keyCode(AKEYCODE_A).build());
7629 consumeKey(/*handled=*/true,
7630 AllOf(WithKeyAction(ACTION_UP), WithKeyCode(AKEYCODE_A), WithFlags(0)));
7631 ASSERT_NO_FATAL_FAILURE(mFakePolicy->assertUnhandledKeyReported(AKEYCODE_A));
7632}
7633
Prabir Pradhanfa2c69f2024-02-01 20:31:34 +00007634TEST_F(InputDispatcherFallbackKeyTest, WindowRemovedDuringPolicyCall) {
7635 setFallback(AKEYCODE_B);
7636 mDispatcher->notifyKey(
7637 KeyArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_KEYBOARD).keyCode(AKEYCODE_A).build());
7638
7639 // Do not handle this key event.
7640 consumeKey(/*handled=*/false,
7641 AllOf(WithKeyAction(ACTION_DOWN), WithKeyCode(AKEYCODE_A), WithFlags(0)));
7642 ASSERT_NO_FATAL_FAILURE(mFakePolicy->assertUnhandledKeyReported(AKEYCODE_A));
7643 consumeKey(/*handled=*/true,
7644 AllOf(WithKeyAction(ACTION_DOWN), WithKeyCode(AKEYCODE_B),
7645 WithFlags(AKEY_EVENT_FLAG_FALLBACK)));
7646
7647 mFakePolicy->setUnhandledKeyHandler([&](const KeyEvent& event) {
7648 // When the unhandled key is reported to the policy next, remove the window.
7649 mDispatcher->onWindowInfosChanged({{}, {}, 0, 0});
7650 return KeyEventBuilder(event).keyCode(AKEYCODE_B).build();
7651 });
7652 // Release the original key, which the app will not handle. When this unhandled key is reported
7653 // to the policy, the window will be removed.
7654 mDispatcher->notifyKey(
7655 KeyArgsBuilder(ACTION_UP, AINPUT_SOURCE_KEYBOARD).keyCode(AKEYCODE_A).build());
7656 consumeKey(/*handled=*/false,
7657 AllOf(WithKeyAction(ACTION_UP), WithKeyCode(AKEYCODE_A), WithFlags(0)));
7658 ASSERT_NO_FATAL_FAILURE(mFakePolicy->assertUnhandledKeyReported(AKEYCODE_A));
7659
7660 // Since the window was removed, it loses focus, and the channel state will be reset.
7661 consumeKey(/*handled=*/true,
7662 AllOf(WithKeyAction(ACTION_UP), WithKeyCode(AKEYCODE_B),
7663 WithFlags(AKEY_EVENT_FLAG_FALLBACK | AKEY_EVENT_FLAG_CANCELED)));
7664 mWindow->consumeFocusEvent(false);
7665 mWindow->assertNoEvents();
7666}
7667
7668TEST_F(InputDispatcherFallbackKeyTest, WindowRemovedWhileAwaitingFinishedSignal) {
7669 setFallback(AKEYCODE_B);
7670 mDispatcher->notifyKey(
7671 KeyArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_KEYBOARD).keyCode(AKEYCODE_A).build());
7672
7673 // Do not handle this key event.
7674 consumeKey(/*handled=*/false,
7675 AllOf(WithKeyAction(ACTION_DOWN), WithKeyCode(AKEYCODE_A), WithFlags(0)));
7676 ASSERT_NO_FATAL_FAILURE(mFakePolicy->assertUnhandledKeyReported(AKEYCODE_A));
7677 const auto [seq, event] = mWindow->receiveEvent();
7678 ASSERT_TRUE(seq.has_value() && event != nullptr) << "Failed to receive fallback event";
7679 ASSERT_EQ(event->getType(), InputEventType::KEY);
7680 ASSERT_THAT(static_cast<const KeyEvent&>(*event),
7681 AllOf(WithKeyAction(ACTION_DOWN), WithKeyCode(AKEYCODE_B),
7682 WithFlags(AKEY_EVENT_FLAG_FALLBACK)));
7683
7684 // Remove the window now, which should generate a cancellations and make the window lose focus.
7685 mDispatcher->onWindowInfosChanged({{}, {}, 0, 0});
7686 consumeKey(/*handled=*/true,
7687 AllOf(WithKeyAction(ACTION_UP), WithKeyCode(AKEYCODE_A),
7688 WithFlags(AKEY_EVENT_FLAG_CANCELED)));
7689 consumeKey(/*handled=*/true,
7690 AllOf(WithKeyAction(ACTION_UP), WithKeyCode(AKEYCODE_B),
7691 WithFlags(AKEY_EVENT_FLAG_FALLBACK | AKEY_EVENT_FLAG_CANCELED)));
7692 mWindow->consumeFocusEvent(false);
7693
7694 // Finish the event by reporting it as handled.
7695 mWindow->finishEvent(*seq);
7696 mWindow->assertNoEvents();
7697}
7698
Garfield Tan1c7bc862020-01-28 13:24:04 -08007699class InputDispatcherKeyRepeatTest : public InputDispatcherTest {
7700protected:
Siarhei Vishniakoufa2a0492023-11-14 13:13:18 -08007701 static constexpr std::chrono::nanoseconds KEY_REPEAT_TIMEOUT = 40ms;
7702 static constexpr std::chrono::nanoseconds KEY_REPEAT_DELAY = 40ms;
Garfield Tan1c7bc862020-01-28 13:24:04 -08007703
Chris Yea209fde2020-07-22 13:54:51 -07007704 std::shared_ptr<FakeApplicationHandle> mApp;
Garfield Tan1c7bc862020-01-28 13:24:04 -08007705 sp<FakeWindowHandle> mWindow;
7706
7707 virtual void SetUp() override {
Prabir Pradhandae52792023-12-15 07:36:40 +00007708 InputDispatcherTest::SetUp();
Garfield Tan1c7bc862020-01-28 13:24:04 -08007709
Prabir Pradhandae52792023-12-15 07:36:40 +00007710 mDispatcher->setKeyRepeatConfiguration(KEY_REPEAT_TIMEOUT, KEY_REPEAT_DELAY);
Garfield Tan1c7bc862020-01-28 13:24:04 -08007711 setUpWindow();
7712 }
7713
7714 void setUpWindow() {
Chris Yea209fde2020-07-22 13:54:51 -07007715 mApp = std::make_shared<FakeApplicationHandle>();
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07007716 mWindow = sp<FakeWindowHandle>::make(mApp, mDispatcher, "Fake Window", ADISPLAY_ID_DEFAULT);
Garfield Tan1c7bc862020-01-28 13:24:04 -08007717
Vishnu Nair47074b82020-08-14 11:54:47 -07007718 mWindow->setFocusable(true);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07007719 mDispatcher->onWindowInfosChanged({{*mWindow->getInfo()}, {}, 0, 0});
Vishnu Nair958da932020-08-21 17:12:37 -07007720 setFocusedWindow(mWindow);
Garfield Tan1c7bc862020-01-28 13:24:04 -08007721 mWindow->consumeFocusEvent(true);
7722 }
7723
Chris Ye2ad95392020-09-01 13:44:44 -07007724 void sendAndConsumeKeyDown(int32_t deviceId) {
Garfield Tan1c7bc862020-01-28 13:24:04 -08007725 NotifyKeyArgs keyArgs = generateKeyArgs(AKEY_EVENT_ACTION_DOWN, ADISPLAY_ID_DEFAULT);
Chris Ye2ad95392020-09-01 13:44:44 -07007726 keyArgs.deviceId = deviceId;
Garfield Tan1c7bc862020-01-28 13:24:04 -08007727 keyArgs.policyFlags |= POLICY_FLAG_TRUSTED; // Otherwise it won't generate repeat event
Prabir Pradhan678438e2023-04-13 19:32:51 +00007728 mDispatcher->notifyKey(keyArgs);
Garfield Tan1c7bc862020-01-28 13:24:04 -08007729
7730 // Window should receive key down event.
7731 mWindow->consumeKeyDown(ADISPLAY_ID_DEFAULT);
7732 }
7733
7734 void expectKeyRepeatOnce(int32_t repeatCount) {
7735 SCOPED_TRACE(StringPrintf("Checking event with repeat count %" PRId32, repeatCount));
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07007736 mWindow->consumeKeyEvent(
7737 AllOf(WithKeyAction(AKEY_EVENT_ACTION_DOWN), WithRepeatCount(repeatCount)));
Garfield Tan1c7bc862020-01-28 13:24:04 -08007738 }
7739
Chris Ye2ad95392020-09-01 13:44:44 -07007740 void sendAndConsumeKeyUp(int32_t deviceId) {
Garfield Tan1c7bc862020-01-28 13:24:04 -08007741 NotifyKeyArgs keyArgs = generateKeyArgs(AKEY_EVENT_ACTION_UP, ADISPLAY_ID_DEFAULT);
Chris Ye2ad95392020-09-01 13:44:44 -07007742 keyArgs.deviceId = deviceId;
Garfield Tan1c7bc862020-01-28 13:24:04 -08007743 keyArgs.policyFlags |= POLICY_FLAG_TRUSTED; // Unless it won't generate repeat event
Prabir Pradhan678438e2023-04-13 19:32:51 +00007744 mDispatcher->notifyKey(keyArgs);
Garfield Tan1c7bc862020-01-28 13:24:04 -08007745
7746 // Window should receive key down event.
Prabir Pradhan7662a8d2023-12-15 01:58:14 +00007747 mWindow->consumeKeyUp(ADISPLAY_ID_DEFAULT,
Harry Cutts33476232023-01-30 19:57:29 +00007748 /*expectedFlags=*/0);
Garfield Tan1c7bc862020-01-28 13:24:04 -08007749 }
Hu Guofe3c8f12023-09-22 17:20:15 +08007750
7751 void injectKeyRepeat(int32_t repeatCount) {
7752 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
7753 injectKey(*mDispatcher, AKEY_EVENT_ACTION_DOWN, repeatCount, ADISPLAY_ID_DEFAULT))
7754 << "Inject key event should return InputEventInjectionResult::SUCCEEDED";
7755 }
Garfield Tan1c7bc862020-01-28 13:24:04 -08007756};
7757
7758TEST_F(InputDispatcherKeyRepeatTest, FocusedWindow_ReceivesKeyRepeat) {
Harry Cutts33476232023-01-30 19:57:29 +00007759 sendAndConsumeKeyDown(/*deviceId=*/1);
Chris Ye2ad95392020-09-01 13:44:44 -07007760 for (int32_t repeatCount = 1; repeatCount <= 10; ++repeatCount) {
7761 expectKeyRepeatOnce(repeatCount);
7762 }
7763}
7764
7765TEST_F(InputDispatcherKeyRepeatTest, FocusedWindow_ReceivesKeyRepeatFromTwoDevices) {
Harry Cutts33476232023-01-30 19:57:29 +00007766 sendAndConsumeKeyDown(/*deviceId=*/1);
Chris Ye2ad95392020-09-01 13:44:44 -07007767 for (int32_t repeatCount = 1; repeatCount <= 10; ++repeatCount) {
7768 expectKeyRepeatOnce(repeatCount);
7769 }
Harry Cutts33476232023-01-30 19:57:29 +00007770 sendAndConsumeKeyDown(/*deviceId=*/2);
Chris Ye2ad95392020-09-01 13:44:44 -07007771 /* repeatCount will start from 1 for deviceId 2 */
Garfield Tan1c7bc862020-01-28 13:24:04 -08007772 for (int32_t repeatCount = 1; repeatCount <= 10; ++repeatCount) {
7773 expectKeyRepeatOnce(repeatCount);
7774 }
7775}
7776
7777TEST_F(InputDispatcherKeyRepeatTest, FocusedWindow_StopsKeyRepeatAfterUp) {
Harry Cutts33476232023-01-30 19:57:29 +00007778 sendAndConsumeKeyDown(/*deviceId=*/1);
7779 expectKeyRepeatOnce(/*repeatCount=*/1);
7780 sendAndConsumeKeyUp(/*deviceId=*/1);
Chris Ye2ad95392020-09-01 13:44:44 -07007781 mWindow->assertNoEvents();
7782}
7783
7784TEST_F(InputDispatcherKeyRepeatTest, FocusedWindow_KeyRepeatAfterStaleDeviceKeyUp) {
Harry Cutts33476232023-01-30 19:57:29 +00007785 sendAndConsumeKeyDown(/*deviceId=*/1);
7786 expectKeyRepeatOnce(/*repeatCount=*/1);
7787 sendAndConsumeKeyDown(/*deviceId=*/2);
7788 expectKeyRepeatOnce(/*repeatCount=*/1);
Chris Ye2ad95392020-09-01 13:44:44 -07007789 // Stale key up from device 1.
Harry Cutts33476232023-01-30 19:57:29 +00007790 sendAndConsumeKeyUp(/*deviceId=*/1);
Chris Ye2ad95392020-09-01 13:44:44 -07007791 // Device 2 is still down, keep repeating
Harry Cutts33476232023-01-30 19:57:29 +00007792 expectKeyRepeatOnce(/*repeatCount=*/2);
7793 expectKeyRepeatOnce(/*repeatCount=*/3);
Chris Ye2ad95392020-09-01 13:44:44 -07007794 // Device 2 key up
Harry Cutts33476232023-01-30 19:57:29 +00007795 sendAndConsumeKeyUp(/*deviceId=*/2);
Chris Ye2ad95392020-09-01 13:44:44 -07007796 mWindow->assertNoEvents();
7797}
7798
7799TEST_F(InputDispatcherKeyRepeatTest, FocusedWindow_KeyRepeatStopsAfterRepeatingKeyUp) {
Harry Cutts33476232023-01-30 19:57:29 +00007800 sendAndConsumeKeyDown(/*deviceId=*/1);
7801 expectKeyRepeatOnce(/*repeatCount=*/1);
7802 sendAndConsumeKeyDown(/*deviceId=*/2);
7803 expectKeyRepeatOnce(/*repeatCount=*/1);
Chris Ye2ad95392020-09-01 13:44:44 -07007804 // Device 2 which holds the key repeating goes up, expect the repeating to stop.
Harry Cutts33476232023-01-30 19:57:29 +00007805 sendAndConsumeKeyUp(/*deviceId=*/2);
Chris Ye2ad95392020-09-01 13:44:44 -07007806 // Device 1 still holds key down, but the repeating was already stopped
Garfield Tan1c7bc862020-01-28 13:24:04 -08007807 mWindow->assertNoEvents();
7808}
7809
liushenxiang42232912021-05-21 20:24:09 +08007810TEST_F(InputDispatcherKeyRepeatTest, FocusedWindow_StopsKeyRepeatAfterDisableInputDevice) {
7811 sendAndConsumeKeyDown(DEVICE_ID);
Harry Cutts33476232023-01-30 19:57:29 +00007812 expectKeyRepeatOnce(/*repeatCount=*/1);
Prabir Pradhan678438e2023-04-13 19:32:51 +00007813 mDispatcher->notifyDeviceReset({/*id=*/10, /*eventTime=*/20, DEVICE_ID});
liushenxiang42232912021-05-21 20:24:09 +08007814 mWindow->consumeKeyUp(ADISPLAY_ID_DEFAULT,
7815 AKEY_EVENT_FLAG_CANCELED | AKEY_EVENT_FLAG_LONG_PRESS);
7816 mWindow->assertNoEvents();
7817}
7818
Garfield Tan1c7bc862020-01-28 13:24:04 -08007819TEST_F(InputDispatcherKeyRepeatTest, FocusedWindow_RepeatKeyEventsUseEventIdFromInputDispatcher) {
Michael Wrighte1cbbd62023-02-22 19:32:13 +00007820 GTEST_SKIP() << "Flaky test (b/270393106)";
Harry Cutts33476232023-01-30 19:57:29 +00007821 sendAndConsumeKeyDown(/*deviceId=*/1);
Garfield Tan1c7bc862020-01-28 13:24:04 -08007822 for (int32_t repeatCount = 1; repeatCount <= 10; ++repeatCount) {
Siarhei Vishniakoud3061ab2023-12-18 20:41:08 -08007823 std::unique_ptr<KeyEvent> repeatEvent = mWindow->consumeKey();
7824 ASSERT_NE(nullptr, repeatEvent);
Garfield Tan1c7bc862020-01-28 13:24:04 -08007825 EXPECT_EQ(IdGenerator::Source::INPUT_DISPATCHER,
Siarhei Vishniakoud3061ab2023-12-18 20:41:08 -08007826 IdGenerator::getSource(repeatEvent->getId()));
Garfield Tan1c7bc862020-01-28 13:24:04 -08007827 }
7828}
7829
7830TEST_F(InputDispatcherKeyRepeatTest, FocusedWindow_RepeatKeyEventsUseUniqueEventId) {
Michael Wrighte1cbbd62023-02-22 19:32:13 +00007831 GTEST_SKIP() << "Flaky test (b/270393106)";
Harry Cutts33476232023-01-30 19:57:29 +00007832 sendAndConsumeKeyDown(/*deviceId=*/1);
Garfield Tan1c7bc862020-01-28 13:24:04 -08007833
7834 std::unordered_set<int32_t> idSet;
7835 for (int32_t repeatCount = 1; repeatCount <= 10; ++repeatCount) {
Siarhei Vishniakoud3061ab2023-12-18 20:41:08 -08007836 std::unique_ptr<KeyEvent> repeatEvent = mWindow->consumeKey();
7837 ASSERT_NE(nullptr, repeatEvent);
7838 int32_t id = repeatEvent->getId();
Garfield Tan1c7bc862020-01-28 13:24:04 -08007839 EXPECT_EQ(idSet.end(), idSet.find(id));
7840 idSet.insert(id);
7841 }
7842}
7843
Hu Guofe3c8f12023-09-22 17:20:15 +08007844TEST_F(InputDispatcherKeyRepeatTest, FocusedWindow_CorrectRepeatCountWhenInjectKeyRepeat) {
7845 injectKeyRepeat(0);
7846 mWindow->consumeKeyDown(ADISPLAY_ID_DEFAULT);
7847 for (int32_t repeatCount = 1; repeatCount <= 2; ++repeatCount) {
7848 expectKeyRepeatOnce(repeatCount);
7849 }
7850 injectKeyRepeat(1);
7851 // Expect repeatCount to be 3 instead of 1
7852 expectKeyRepeatOnce(3);
7853}
7854
Arthur Hung2fbf37f2018-09-13 18:16:41 +08007855/* Test InputDispatcher for MultiDisplay */
7856class InputDispatcherFocusOnTwoDisplaysTest : public InputDispatcherTest {
7857public:
Prabir Pradhan3608aad2019-10-02 17:08:26 -07007858 virtual void SetUp() override {
Arthur Hung2fbf37f2018-09-13 18:16:41 +08007859 InputDispatcherTest::SetUp();
Arthur Hungb92218b2018-08-14 12:00:21 +08007860
Chris Yea209fde2020-07-22 13:54:51 -07007861 application1 = std::make_shared<FakeApplicationHandle>();
Siarhei Vishniakou870ecec2020-12-09 08:07:46 -10007862 windowInPrimary =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07007863 sp<FakeWindowHandle>::make(application1, mDispatcher, "D_1", ADISPLAY_ID_DEFAULT);
Siarhei Vishniakoub9b15352019-11-26 13:19:26 -08007864
Arthur Hung2fbf37f2018-09-13 18:16:41 +08007865 // Set focus window for primary display, but focused display would be second one.
7866 mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application1);
Vishnu Nair47074b82020-08-14 11:54:47 -07007867 windowInPrimary->setFocusable(true);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07007868 mDispatcher->onWindowInfosChanged({{*windowInPrimary->getInfo()}, {}, 0, 0});
7869
Vishnu Nair958da932020-08-21 17:12:37 -07007870 setFocusedWindow(windowInPrimary);
Siarhei Vishniakouf1035d42019-09-20 16:32:01 +01007871 windowInPrimary->consumeFocusEvent(true);
Arthur Hungb92218b2018-08-14 12:00:21 +08007872
Chris Yea209fde2020-07-22 13:54:51 -07007873 application2 = std::make_shared<FakeApplicationHandle>();
Siarhei Vishniakou870ecec2020-12-09 08:07:46 -10007874 windowInSecondary =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07007875 sp<FakeWindowHandle>::make(application2, mDispatcher, "D_2", SECOND_DISPLAY_ID);
Arthur Hung2fbf37f2018-09-13 18:16:41 +08007876 // Set focus to second display window.
Arthur Hung2fbf37f2018-09-13 18:16:41 +08007877 // Set focus display to second one.
7878 mDispatcher->setFocusedDisplay(SECOND_DISPLAY_ID);
7879 // Set focus window for second display.
7880 mDispatcher->setFocusedApplication(SECOND_DISPLAY_ID, application2);
Vishnu Nair47074b82020-08-14 11:54:47 -07007881 windowInSecondary->setFocusable(true);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07007882 mDispatcher->onWindowInfosChanged(
7883 {{*windowInPrimary->getInfo(), *windowInSecondary->getInfo()}, {}, 0, 0});
Vishnu Nair958da932020-08-21 17:12:37 -07007884 setFocusedWindow(windowInSecondary);
Siarhei Vishniakouf1035d42019-09-20 16:32:01 +01007885 windowInSecondary->consumeFocusEvent(true);
Arthur Hung2fbf37f2018-09-13 18:16:41 +08007886 }
7887
Prabir Pradhan3608aad2019-10-02 17:08:26 -07007888 virtual void TearDown() override {
Arthur Hung2fbf37f2018-09-13 18:16:41 +08007889 InputDispatcherTest::TearDown();
7890
Chris Yea209fde2020-07-22 13:54:51 -07007891 application1.reset();
Arthur Hung2fbf37f2018-09-13 18:16:41 +08007892 windowInPrimary.clear();
Chris Yea209fde2020-07-22 13:54:51 -07007893 application2.reset();
Arthur Hung2fbf37f2018-09-13 18:16:41 +08007894 windowInSecondary.clear();
7895 }
7896
7897protected:
Chris Yea209fde2020-07-22 13:54:51 -07007898 std::shared_ptr<FakeApplicationHandle> application1;
Arthur Hung2fbf37f2018-09-13 18:16:41 +08007899 sp<FakeWindowHandle> windowInPrimary;
Chris Yea209fde2020-07-22 13:54:51 -07007900 std::shared_ptr<FakeApplicationHandle> application2;
Arthur Hung2fbf37f2018-09-13 18:16:41 +08007901 sp<FakeWindowHandle> windowInSecondary;
7902};
7903
7904TEST_F(InputDispatcherFocusOnTwoDisplaysTest, SetInputWindow_MultiDisplayTouch) {
7905 // Test touch down on primary display.
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08007906 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07007907 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT))
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08007908 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
Siarhei Vishniakouc5ca85c2019-11-15 17:20:00 -08007909 windowInPrimary->consumeMotionDown(ADISPLAY_ID_DEFAULT);
Arthur Hungb92218b2018-08-14 12:00:21 +08007910 windowInSecondary->assertNoEvents();
7911
Arthur Hung2fbf37f2018-09-13 18:16:41 +08007912 // Test touch down on second display.
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08007913 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07007914 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, SECOND_DISPLAY_ID))
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08007915 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
Arthur Hungb92218b2018-08-14 12:00:21 +08007916 windowInPrimary->assertNoEvents();
Siarhei Vishniakouc5ca85c2019-11-15 17:20:00 -08007917 windowInSecondary->consumeMotionDown(SECOND_DISPLAY_ID);
Arthur Hungb92218b2018-08-14 12:00:21 +08007918}
7919
Arthur Hung2fbf37f2018-09-13 18:16:41 +08007920TEST_F(InputDispatcherFocusOnTwoDisplaysTest, SetInputWindow_MultiDisplayFocus) {
Tiger Huang721e26f2018-07-24 22:26:19 +08007921 // Test inject a key down with display id specified.
Prabir Pradhan93f342c2021-03-11 15:05:30 -08007922 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07007923 injectKeyDownNoRepeat(*mDispatcher, ADISPLAY_ID_DEFAULT))
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08007924 << "Inject key event should return InputEventInjectionResult::SUCCEEDED";
Siarhei Vishniakouc5ca85c2019-11-15 17:20:00 -08007925 windowInPrimary->consumeKeyDown(ADISPLAY_ID_DEFAULT);
Tiger Huang721e26f2018-07-24 22:26:19 +08007926 windowInSecondary->assertNoEvents();
7927
7928 // Test inject a key down without display id specified.
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07007929 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectKeyDownNoRepeat(*mDispatcher))
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08007930 << "Inject key event should return InputEventInjectionResult::SUCCEEDED";
Arthur Hungb92218b2018-08-14 12:00:21 +08007931 windowInPrimary->assertNoEvents();
Siarhei Vishniakouc5ca85c2019-11-15 17:20:00 -08007932 windowInSecondary->consumeKeyDown(ADISPLAY_ID_NONE);
Arthur Hungb92218b2018-08-14 12:00:21 +08007933
Siarhei Vishniakoub9b15352019-11-26 13:19:26 -08007934 // Remove all windows in secondary display.
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07007935 mDispatcher->onWindowInfosChanged({{*windowInPrimary->getInfo()}, {}, 0, 0});
Arthur Hungb92218b2018-08-14 12:00:21 +08007936
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08007937 // Old focus should receive a cancel event.
Prabir Pradhan7662a8d2023-12-15 01:58:14 +00007938 windowInSecondary->consumeKeyUp(ADISPLAY_ID_NONE, AKEY_EVENT_FLAG_CANCELED);
Arthur Hungb92218b2018-08-14 12:00:21 +08007939
7940 // Test inject a key down, should timeout because of no target window.
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07007941 ASSERT_NO_FATAL_FAILURE(assertInjectedKeyTimesOut(*mDispatcher));
Arthur Hungb92218b2018-08-14 12:00:21 +08007942 windowInPrimary->assertNoEvents();
Siarhei Vishniakouf1035d42019-09-20 16:32:01 +01007943 windowInSecondary->consumeFocusEvent(false);
Arthur Hungb92218b2018-08-14 12:00:21 +08007944 windowInSecondary->assertNoEvents();
7945}
7946
Arthur Hung2fbf37f2018-09-13 18:16:41 +08007947// Test per-display input monitors for motion event.
7948TEST_F(InputDispatcherFocusOnTwoDisplaysTest, MonitorMotionEvent_MultiDisplay) {
chaviwd1c23182019-12-20 18:44:56 -08007949 FakeMonitorReceiver monitorInPrimary =
Prabir Pradhanfb549072023-10-05 19:17:36 +00007950 FakeMonitorReceiver(*mDispatcher, "M_1", ADISPLAY_ID_DEFAULT);
chaviwd1c23182019-12-20 18:44:56 -08007951 FakeMonitorReceiver monitorInSecondary =
Prabir Pradhanfb549072023-10-05 19:17:36 +00007952 FakeMonitorReceiver(*mDispatcher, "M_2", SECOND_DISPLAY_ID);
Arthur Hung2fbf37f2018-09-13 18:16:41 +08007953
7954 // Test touch down on primary display.
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08007955 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07007956 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT))
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08007957 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
Siarhei Vishniakouc5ca85c2019-11-15 17:20:00 -08007958 windowInPrimary->consumeMotionDown(ADISPLAY_ID_DEFAULT);
chaviwd1c23182019-12-20 18:44:56 -08007959 monitorInPrimary.consumeMotionDown(ADISPLAY_ID_DEFAULT);
Arthur Hung2fbf37f2018-09-13 18:16:41 +08007960 windowInSecondary->assertNoEvents();
chaviwd1c23182019-12-20 18:44:56 -08007961 monitorInSecondary.assertNoEvents();
Arthur Hung2fbf37f2018-09-13 18:16:41 +08007962
7963 // Test touch down on second display.
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08007964 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07007965 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, SECOND_DISPLAY_ID))
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08007966 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
Arthur Hung2fbf37f2018-09-13 18:16:41 +08007967 windowInPrimary->assertNoEvents();
chaviwd1c23182019-12-20 18:44:56 -08007968 monitorInPrimary.assertNoEvents();
Siarhei Vishniakouc5ca85c2019-11-15 17:20:00 -08007969 windowInSecondary->consumeMotionDown(SECOND_DISPLAY_ID);
chaviwd1c23182019-12-20 18:44:56 -08007970 monitorInSecondary.consumeMotionDown(SECOND_DISPLAY_ID);
Arthur Hung2fbf37f2018-09-13 18:16:41 +08007971
Siarhei Vishniakou92c8fd52023-01-29 14:57:43 -08007972 // Lift up the touch from the second display
7973 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07007974 injectMotionUp(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, SECOND_DISPLAY_ID))
Siarhei Vishniakou92c8fd52023-01-29 14:57:43 -08007975 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
7976 windowInSecondary->consumeMotionUp(SECOND_DISPLAY_ID);
7977 monitorInSecondary.consumeMotionUp(SECOND_DISPLAY_ID);
7978
Arthur Hung2fbf37f2018-09-13 18:16:41 +08007979 // Test inject a non-pointer motion event.
7980 // If specific a display, it will dispatch to the focused window of particular display,
7981 // or it will dispatch to the focused window of focused display.
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08007982 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07007983 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TRACKBALL, ADISPLAY_ID_NONE))
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08007984 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
Arthur Hung2fbf37f2018-09-13 18:16:41 +08007985 windowInPrimary->assertNoEvents();
chaviwd1c23182019-12-20 18:44:56 -08007986 monitorInPrimary.assertNoEvents();
Siarhei Vishniakouc5ca85c2019-11-15 17:20:00 -08007987 windowInSecondary->consumeMotionDown(ADISPLAY_ID_NONE);
chaviwd1c23182019-12-20 18:44:56 -08007988 monitorInSecondary.consumeMotionDown(ADISPLAY_ID_NONE);
Arthur Hung2fbf37f2018-09-13 18:16:41 +08007989}
7990
7991// Test per-display input monitors for key event.
7992TEST_F(InputDispatcherFocusOnTwoDisplaysTest, MonitorKeyEvent_MultiDisplay) {
Siarhei Vishniakou870ecec2020-12-09 08:07:46 -10007993 // Input monitor per display.
chaviwd1c23182019-12-20 18:44:56 -08007994 FakeMonitorReceiver monitorInPrimary =
Prabir Pradhanfb549072023-10-05 19:17:36 +00007995 FakeMonitorReceiver(*mDispatcher, "M_1", ADISPLAY_ID_DEFAULT);
chaviwd1c23182019-12-20 18:44:56 -08007996 FakeMonitorReceiver monitorInSecondary =
Prabir Pradhanfb549072023-10-05 19:17:36 +00007997 FakeMonitorReceiver(*mDispatcher, "M_2", SECOND_DISPLAY_ID);
Arthur Hung2fbf37f2018-09-13 18:16:41 +08007998
7999 // Test inject a key down.
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07008000 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectKeyDown(*mDispatcher))
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08008001 << "Inject key event should return InputEventInjectionResult::SUCCEEDED";
Arthur Hung2fbf37f2018-09-13 18:16:41 +08008002 windowInPrimary->assertNoEvents();
chaviwd1c23182019-12-20 18:44:56 -08008003 monitorInPrimary.assertNoEvents();
Siarhei Vishniakouc5ca85c2019-11-15 17:20:00 -08008004 windowInSecondary->consumeKeyDown(ADISPLAY_ID_NONE);
chaviwd1c23182019-12-20 18:44:56 -08008005 monitorInSecondary.consumeKeyDown(ADISPLAY_ID_NONE);
Arthur Hung2fbf37f2018-09-13 18:16:41 +08008006}
8007
Vishnu Nair958da932020-08-21 17:12:37 -07008008TEST_F(InputDispatcherFocusOnTwoDisplaysTest, CanFocusWindowOnUnfocusedDisplay) {
8009 sp<FakeWindowHandle> secondWindowInPrimary =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07008010 sp<FakeWindowHandle>::make(application1, mDispatcher, "D_1_W2", ADISPLAY_ID_DEFAULT);
Vishnu Nair958da932020-08-21 17:12:37 -07008011 secondWindowInPrimary->setFocusable(true);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07008012 mDispatcher->onWindowInfosChanged(
8013 {{*windowInPrimary->getInfo(), *secondWindowInPrimary->getInfo(),
8014 *windowInSecondary->getInfo()},
8015 {},
8016 0,
8017 0});
Vishnu Nair958da932020-08-21 17:12:37 -07008018 setFocusedWindow(secondWindowInPrimary);
8019 windowInPrimary->consumeFocusEvent(false);
8020 secondWindowInPrimary->consumeFocusEvent(true);
8021
8022 // Test inject a key down.
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07008023 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
8024 injectKeyDown(*mDispatcher, ADISPLAY_ID_DEFAULT))
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08008025 << "Inject key event should return InputEventInjectionResult::SUCCEEDED";
Vishnu Nair958da932020-08-21 17:12:37 -07008026 windowInPrimary->assertNoEvents();
8027 windowInSecondary->assertNoEvents();
8028 secondWindowInPrimary->consumeKeyDown(ADISPLAY_ID_DEFAULT);
8029}
8030
Arthur Hungdfd528e2021-12-08 13:23:04 +00008031TEST_F(InputDispatcherFocusOnTwoDisplaysTest, CancelTouch_MultiDisplay) {
8032 FakeMonitorReceiver monitorInPrimary =
Prabir Pradhanfb549072023-10-05 19:17:36 +00008033 FakeMonitorReceiver(*mDispatcher, "M_1", ADISPLAY_ID_DEFAULT);
Arthur Hungdfd528e2021-12-08 13:23:04 +00008034 FakeMonitorReceiver monitorInSecondary =
Prabir Pradhanfb549072023-10-05 19:17:36 +00008035 FakeMonitorReceiver(*mDispatcher, "M_2", SECOND_DISPLAY_ID);
Arthur Hungdfd528e2021-12-08 13:23:04 +00008036
8037 // Test touch down on primary display.
8038 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07008039 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT))
Arthur Hungdfd528e2021-12-08 13:23:04 +00008040 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
8041 windowInPrimary->consumeMotionDown(ADISPLAY_ID_DEFAULT);
8042 monitorInPrimary.consumeMotionDown(ADISPLAY_ID_DEFAULT);
8043
8044 // Test touch down on second display.
8045 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07008046 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, SECOND_DISPLAY_ID))
Arthur Hungdfd528e2021-12-08 13:23:04 +00008047 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
8048 windowInSecondary->consumeMotionDown(SECOND_DISPLAY_ID);
8049 monitorInSecondary.consumeMotionDown(SECOND_DISPLAY_ID);
8050
8051 // Trigger cancel touch.
8052 mDispatcher->cancelCurrentTouch();
8053 windowInPrimary->consumeMotionCancel(ADISPLAY_ID_DEFAULT);
8054 monitorInPrimary.consumeMotionCancel(ADISPLAY_ID_DEFAULT);
8055 windowInSecondary->consumeMotionCancel(SECOND_DISPLAY_ID);
8056 monitorInSecondary.consumeMotionCancel(SECOND_DISPLAY_ID);
8057
8058 // Test inject a move motion event, no window/monitor should receive the event.
8059 ASSERT_EQ(InputEventInjectionResult::FAILED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07008060 injectMotionEvent(*mDispatcher, AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN,
Arthur Hungdfd528e2021-12-08 13:23:04 +00008061 ADISPLAY_ID_DEFAULT, {110, 200}))
8062 << "Inject motion event should return InputEventInjectionResult::FAILED";
8063 windowInPrimary->assertNoEvents();
8064 monitorInPrimary.assertNoEvents();
8065
8066 ASSERT_EQ(InputEventInjectionResult::FAILED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07008067 injectMotionEvent(*mDispatcher, AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN,
Arthur Hungdfd528e2021-12-08 13:23:04 +00008068 SECOND_DISPLAY_ID, {110, 200}))
8069 << "Inject motion event should return InputEventInjectionResult::FAILED";
8070 windowInSecondary->assertNoEvents();
8071 monitorInSecondary.assertNoEvents();
8072}
8073
Hu Guocb134f12023-12-23 13:42:44 +00008074/**
8075 * Send a key to the primary display and to the secondary display.
8076 * Then cause the key on the primary display to be canceled by sending in a stale key.
8077 * Ensure that the key on the primary display is canceled, and that the key on the secondary display
8078 * does not get canceled.
8079 */
8080TEST_F(InputDispatcherFocusOnTwoDisplaysTest, WhenDropKeyEvent_OnlyCancelCorrespondingKeyGesture) {
8081 // Send a key down on primary display
8082 mDispatcher->notifyKey(
8083 KeyArgsBuilder(AKEY_EVENT_ACTION_DOWN, AINPUT_SOURCE_KEYBOARD)
8084 .displayId(ADISPLAY_ID_DEFAULT)
8085 .policyFlags(DEFAULT_POLICY_FLAGS | POLICY_FLAG_DISABLE_KEY_REPEAT)
8086 .build());
8087 windowInPrimary->consumeKeyEvent(
8088 AllOf(WithKeyAction(AKEY_EVENT_ACTION_DOWN), WithDisplayId(ADISPLAY_ID_DEFAULT)));
8089 windowInSecondary->assertNoEvents();
8090
8091 // Send a key down on second display
8092 mDispatcher->notifyKey(
8093 KeyArgsBuilder(AKEY_EVENT_ACTION_DOWN, AINPUT_SOURCE_KEYBOARD)
8094 .displayId(SECOND_DISPLAY_ID)
8095 .policyFlags(DEFAULT_POLICY_FLAGS | POLICY_FLAG_DISABLE_KEY_REPEAT)
8096 .build());
8097 windowInSecondary->consumeKeyEvent(
8098 AllOf(WithKeyAction(AKEY_EVENT_ACTION_DOWN), WithDisplayId(SECOND_DISPLAY_ID)));
8099 windowInPrimary->assertNoEvents();
8100
8101 // Send a valid key up event on primary display that will be dropped because it is stale
8102 NotifyKeyArgs staleKeyUp =
8103 KeyArgsBuilder(AKEY_EVENT_ACTION_UP, AINPUT_SOURCE_KEYBOARD)
8104 .displayId(ADISPLAY_ID_DEFAULT)
8105 .policyFlags(DEFAULT_POLICY_FLAGS | POLICY_FLAG_DISABLE_KEY_REPEAT)
8106 .build();
8107 static constexpr std::chrono::duration STALE_EVENT_TIMEOUT = 10ms;
8108 mFakePolicy->setStaleEventTimeout(STALE_EVENT_TIMEOUT);
8109 std::this_thread::sleep_for(STALE_EVENT_TIMEOUT);
8110 mDispatcher->notifyKey(staleKeyUp);
8111
8112 // Only the key gesture corresponding to the dropped event should receive the cancel event.
8113 // Therefore, windowInPrimary should get the cancel event and windowInSecondary should not
8114 // receive any events.
8115 windowInPrimary->consumeKeyEvent(AllOf(WithKeyAction(AKEY_EVENT_ACTION_UP),
8116 WithDisplayId(ADISPLAY_ID_DEFAULT),
8117 WithFlags(AKEY_EVENT_FLAG_CANCELED)));
8118 windowInSecondary->assertNoEvents();
8119}
8120
8121/**
8122 * Similar to 'WhenDropKeyEvent_OnlyCancelCorrespondingKeyGesture' but for motion events.
8123 */
8124TEST_F(InputDispatcherFocusOnTwoDisplaysTest, WhenDropMotionEvent_OnlyCancelCorrespondingGesture) {
8125 // Send touch down on primary display.
8126 mDispatcher->notifyMotion(
8127 MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
8128 .pointer(PointerBuilder(/*id=*/0, ToolType::FINGER).x(100).y(200))
8129 .displayId(ADISPLAY_ID_DEFAULT)
8130 .build());
8131 windowInPrimary->consumeMotionEvent(
8132 AllOf(WithMotionAction(ACTION_DOWN), WithDisplayId(ADISPLAY_ID_DEFAULT)));
8133 windowInSecondary->assertNoEvents();
8134
8135 // Send touch down on second display.
8136 mDispatcher->notifyMotion(
8137 MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
8138 .pointer(PointerBuilder(/*id=*/0, ToolType::FINGER).x(100).y(200))
8139 .displayId(SECOND_DISPLAY_ID)
8140 .build());
8141 windowInPrimary->assertNoEvents();
8142 windowInSecondary->consumeMotionEvent(
8143 AllOf(WithMotionAction(ACTION_DOWN), WithDisplayId(SECOND_DISPLAY_ID)));
8144
8145 // inject a valid MotionEvent on primary display that will be stale when it arrives.
8146 NotifyMotionArgs staleMotionUp =
8147 MotionArgsBuilder(ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN)
8148 .displayId(ADISPLAY_ID_DEFAULT)
8149 .pointer(PointerBuilder(/*id=*/0, ToolType::FINGER).x(100).y(200))
8150 .build();
8151 static constexpr std::chrono::duration STALE_EVENT_TIMEOUT = 10ms;
8152 mFakePolicy->setStaleEventTimeout(STALE_EVENT_TIMEOUT);
8153 std::this_thread::sleep_for(STALE_EVENT_TIMEOUT);
8154 mDispatcher->notifyMotion(staleMotionUp);
8155
8156 // For stale motion events, we let the gesture to complete. This behaviour is different from key
8157 // events, where we would cancel the current keys instead.
8158 windowInPrimary->consumeMotionEvent(WithMotionAction(ACTION_UP));
8159 windowInSecondary->assertNoEvents();
8160}
8161
Jackal Guof9696682018-10-05 12:23:23 +08008162class InputFilterTest : public InputDispatcherTest {
8163protected:
Prabir Pradhan81420cc2021-09-06 10:28:50 -07008164 void testNotifyMotion(int32_t displayId, bool expectToBeFiltered,
8165 const ui::Transform& transform = ui::Transform()) {
Jackal Guof9696682018-10-05 12:23:23 +08008166 NotifyMotionArgs motionArgs;
8167
Siarhei Vishniakou870ecec2020-12-09 08:07:46 -10008168 motionArgs =
8169 generateMotionArgs(AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN, displayId);
Prabir Pradhan678438e2023-04-13 19:32:51 +00008170 mDispatcher->notifyMotion(motionArgs);
Siarhei Vishniakou870ecec2020-12-09 08:07:46 -10008171 motionArgs =
8172 generateMotionArgs(AMOTION_EVENT_ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN, displayId);
Prabir Pradhan678438e2023-04-13 19:32:51 +00008173 mDispatcher->notifyMotion(motionArgs);
Siarhei Vishniakou2bfa9052019-11-21 18:10:54 -08008174 ASSERT_TRUE(mDispatcher->waitForIdle());
Jackal Guof9696682018-10-05 12:23:23 +08008175 if (expectToBeFiltered) {
Siarhei Vishniakou3218fc02023-06-15 20:41:02 -07008176 const auto xy = transform.transform(motionArgs.pointerCoords[0].getXYValue());
Prabir Pradhan81420cc2021-09-06 10:28:50 -07008177 mFakePolicy->assertFilterInputEventWasCalled(motionArgs, xy);
Jackal Guof9696682018-10-05 12:23:23 +08008178 } else {
8179 mFakePolicy->assertFilterInputEventWasNotCalled();
8180 }
8181 }
8182
8183 void testNotifyKey(bool expectToBeFiltered) {
8184 NotifyKeyArgs keyArgs;
8185
8186 keyArgs = generateKeyArgs(AKEY_EVENT_ACTION_DOWN);
Prabir Pradhan678438e2023-04-13 19:32:51 +00008187 mDispatcher->notifyKey(keyArgs);
Jackal Guof9696682018-10-05 12:23:23 +08008188 keyArgs = generateKeyArgs(AKEY_EVENT_ACTION_UP);
Prabir Pradhan678438e2023-04-13 19:32:51 +00008189 mDispatcher->notifyKey(keyArgs);
Siarhei Vishniakou2bfa9052019-11-21 18:10:54 -08008190 ASSERT_TRUE(mDispatcher->waitForIdle());
Jackal Guof9696682018-10-05 12:23:23 +08008191
8192 if (expectToBeFiltered) {
Siarhei Vishniakou8935a802019-11-15 16:41:44 -08008193 mFakePolicy->assertFilterInputEventWasCalled(keyArgs);
Jackal Guof9696682018-10-05 12:23:23 +08008194 } else {
8195 mFakePolicy->assertFilterInputEventWasNotCalled();
8196 }
8197 }
8198};
8199
8200// Test InputFilter for MotionEvent
8201TEST_F(InputFilterTest, MotionEvent_InputFilter) {
8202 // Since the InputFilter is disabled by default, check if touch events aren't filtered.
Harry Cutts101ee9b2023-07-06 18:04:14 +00008203 testNotifyMotion(ADISPLAY_ID_DEFAULT, /*expectToBeFiltered=*/false);
8204 testNotifyMotion(SECOND_DISPLAY_ID, /*expectToBeFiltered=*/false);
Jackal Guof9696682018-10-05 12:23:23 +08008205
8206 // Enable InputFilter
8207 mDispatcher->setInputFilterEnabled(true);
8208 // Test touch on both primary and second display, and check if both events are filtered.
Harry Cutts101ee9b2023-07-06 18:04:14 +00008209 testNotifyMotion(ADISPLAY_ID_DEFAULT, /*expectToBeFiltered=*/true);
8210 testNotifyMotion(SECOND_DISPLAY_ID, /*expectToBeFiltered=*/true);
Jackal Guof9696682018-10-05 12:23:23 +08008211
8212 // Disable InputFilter
8213 mDispatcher->setInputFilterEnabled(false);
8214 // Test touch on both primary and second display, and check if both events aren't filtered.
Harry Cutts101ee9b2023-07-06 18:04:14 +00008215 testNotifyMotion(ADISPLAY_ID_DEFAULT, /*expectToBeFiltered=*/false);
8216 testNotifyMotion(SECOND_DISPLAY_ID, /*expectToBeFiltered=*/false);
Jackal Guof9696682018-10-05 12:23:23 +08008217}
8218
8219// Test InputFilter for KeyEvent
8220TEST_F(InputFilterTest, KeyEvent_InputFilter) {
8221 // Since the InputFilter is disabled by default, check if key event aren't filtered.
Harry Cutts101ee9b2023-07-06 18:04:14 +00008222 testNotifyKey(/*expectToBeFiltered=*/false);
Jackal Guof9696682018-10-05 12:23:23 +08008223
8224 // Enable InputFilter
8225 mDispatcher->setInputFilterEnabled(true);
8226 // Send a key event, and check if it is filtered.
Harry Cutts101ee9b2023-07-06 18:04:14 +00008227 testNotifyKey(/*expectToBeFiltered=*/true);
Jackal Guof9696682018-10-05 12:23:23 +08008228
8229 // Disable InputFilter
8230 mDispatcher->setInputFilterEnabled(false);
8231 // Send a key event, and check if it isn't filtered.
Harry Cutts101ee9b2023-07-06 18:04:14 +00008232 testNotifyKey(/*expectToBeFiltered=*/false);
Jackal Guof9696682018-10-05 12:23:23 +08008233}
8234
Prabir Pradhan81420cc2021-09-06 10:28:50 -07008235// Ensure that MotionEvents sent to the InputFilter through InputListener are converted to the
8236// logical display coordinate space.
8237TEST_F(InputFilterTest, MotionEvent_UsesLogicalDisplayCoordinates_notifyMotion) {
8238 ui::Transform firstDisplayTransform;
8239 firstDisplayTransform.set({1.1, 2.2, 3.3, 4.4, 5.5, 6.6, 0, 0, 1});
8240 ui::Transform secondDisplayTransform;
8241 secondDisplayTransform.set({-6.6, -5.5, -4.4, -3.3, -2.2, -1.1, 0, 0, 1});
8242
8243 std::vector<gui::DisplayInfo> displayInfos(2);
8244 displayInfos[0].displayId = ADISPLAY_ID_DEFAULT;
8245 displayInfos[0].transform = firstDisplayTransform;
8246 displayInfos[1].displayId = SECOND_DISPLAY_ID;
8247 displayInfos[1].transform = secondDisplayTransform;
8248
Patrick Williamsd828f302023-04-28 17:52:08 -05008249 mDispatcher->onWindowInfosChanged({{}, displayInfos, 0, 0});
Prabir Pradhan81420cc2021-09-06 10:28:50 -07008250
8251 // Enable InputFilter
8252 mDispatcher->setInputFilterEnabled(true);
8253
8254 // Ensure the correct transforms are used for the displays.
Harry Cutts101ee9b2023-07-06 18:04:14 +00008255 testNotifyMotion(ADISPLAY_ID_DEFAULT, /*expectToBeFiltered=*/true, firstDisplayTransform);
8256 testNotifyMotion(SECOND_DISPLAY_ID, /*expectToBeFiltered=*/true, secondDisplayTransform);
Prabir Pradhan81420cc2021-09-06 10:28:50 -07008257}
8258
Siarhei Vishniakou5d552c42021-05-21 05:02:22 +00008259class InputFilterInjectionPolicyTest : public InputDispatcherTest {
8260protected:
8261 virtual void SetUp() override {
8262 InputDispatcherTest::SetUp();
8263
8264 /**
8265 * We don't need to enable input filter to test the injected event policy, but we enabled it
8266 * here to make the tests more realistic, since this policy only matters when inputfilter is
8267 * on.
8268 */
8269 mDispatcher->setInputFilterEnabled(true);
8270
8271 std::shared_ptr<InputApplicationHandle> application =
8272 std::make_shared<FakeApplicationHandle>();
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07008273 mWindow = sp<FakeWindowHandle>::make(application, mDispatcher, "Test Window",
8274 ADISPLAY_ID_DEFAULT);
Siarhei Vishniakou5d552c42021-05-21 05:02:22 +00008275
8276 mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application);
8277 mWindow->setFocusable(true);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07008278 mDispatcher->onWindowInfosChanged({{*mWindow->getInfo()}, {}, 0, 0});
Siarhei Vishniakou5d552c42021-05-21 05:02:22 +00008279 setFocusedWindow(mWindow);
8280 mWindow->consumeFocusEvent(true);
8281 }
8282
Siarhei Vishniakouf00a4ec2021-06-16 03:55:32 +00008283 void testInjectedKey(int32_t policyFlags, int32_t injectedDeviceId, int32_t resolvedDeviceId,
8284 int32_t flags) {
Siarhei Vishniakou5d552c42021-05-21 05:02:22 +00008285 KeyEvent event;
8286
8287 const nsecs_t eventTime = systemTime(SYSTEM_TIME_MONOTONIC);
8288 event.initialize(InputEvent::nextId(), injectedDeviceId, AINPUT_SOURCE_KEYBOARD,
8289 ADISPLAY_ID_NONE, INVALID_HMAC, AKEY_EVENT_ACTION_DOWN, 0, AKEYCODE_A,
Harry Cutts33476232023-01-30 19:57:29 +00008290 KEY_A, AMETA_NONE, /*repeatCount=*/0, eventTime, eventTime);
Siarhei Vishniakou5d552c42021-05-21 05:02:22 +00008291 const int32_t additionalPolicyFlags =
8292 POLICY_FLAG_PASS_TO_USER | POLICY_FLAG_DISABLE_KEY_REPEAT;
8293 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Harry Cutts33476232023-01-30 19:57:29 +00008294 mDispatcher->injectInputEvent(&event, /*targetUid=*/{},
Siarhei Vishniakou4648fea2023-06-27 01:00:12 +00008295 InputEventInjectionSync::WAIT_FOR_RESULT, 100ms,
Siarhei Vishniakou5d552c42021-05-21 05:02:22 +00008296 policyFlags | additionalPolicyFlags));
8297
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07008298 mWindow->consumeKeyEvent(AllOf(WithDeviceId(resolvedDeviceId), WithFlags(flags)));
Siarhei Vishniakouf00a4ec2021-06-16 03:55:32 +00008299 }
8300
8301 void testInjectedMotion(int32_t policyFlags, int32_t injectedDeviceId, int32_t resolvedDeviceId,
8302 int32_t flags) {
8303 MotionEvent event;
8304 PointerProperties pointerProperties[1];
8305 PointerCoords pointerCoords[1];
8306 pointerProperties[0].clear();
8307 pointerProperties[0].id = 0;
8308 pointerCoords[0].clear();
8309 pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_X, 300);
8310 pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_Y, 400);
8311
8312 ui::Transform identityTransform;
8313 const nsecs_t eventTime = systemTime(SYSTEM_TIME_MONOTONIC);
8314 event.initialize(InputEvent::nextId(), injectedDeviceId, AINPUT_SOURCE_TOUCHSCREEN,
8315 DISPLAY_ID, INVALID_HMAC, AMOTION_EVENT_ACTION_DOWN, 0, 0,
8316 AMOTION_EVENT_EDGE_FLAG_NONE, AMETA_NONE, 0, MotionClassification::NONE,
8317 identityTransform, 0, 0, AMOTION_EVENT_INVALID_CURSOR_POSITION,
Prabir Pradhanb9b18502021-08-26 12:30:32 -07008318 AMOTION_EVENT_INVALID_CURSOR_POSITION, identityTransform, eventTime,
Evan Rosky09576692021-07-01 12:22:09 -07008319 eventTime,
Harry Cutts101ee9b2023-07-06 18:04:14 +00008320 /*pointerCount=*/1, pointerProperties, pointerCoords);
Siarhei Vishniakouf00a4ec2021-06-16 03:55:32 +00008321
8322 const int32_t additionalPolicyFlags = POLICY_FLAG_PASS_TO_USER;
8323 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Harry Cutts33476232023-01-30 19:57:29 +00008324 mDispatcher->injectInputEvent(&event, /*targetUid=*/{},
Siarhei Vishniakou4648fea2023-06-27 01:00:12 +00008325 InputEventInjectionSync::WAIT_FOR_RESULT, 100ms,
Siarhei Vishniakouf00a4ec2021-06-16 03:55:32 +00008326 policyFlags | additionalPolicyFlags));
8327
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07008328 mWindow->consumeMotionEvent(AllOf(WithFlags(flags), WithDeviceId(resolvedDeviceId)));
Siarhei Vishniakou5d552c42021-05-21 05:02:22 +00008329 }
8330
8331private:
8332 sp<FakeWindowHandle> mWindow;
8333};
8334
8335TEST_F(InputFilterInjectionPolicyTest, TrustedFilteredEvents_KeepOriginalDeviceId) {
Siarhei Vishniakouf00a4ec2021-06-16 03:55:32 +00008336 // Must have POLICY_FLAG_FILTERED here to indicate that the event has gone through the input
8337 // filter. Without it, the event will no different from a regularly injected event, and the
8338 // injected device id will be overwritten.
Harry Cutts33476232023-01-30 19:57:29 +00008339 testInjectedKey(POLICY_FLAG_FILTERED, /*injectedDeviceId=*/3, /*resolvedDeviceId=*/3,
8340 /*flags=*/0);
Siarhei Vishniakou5d552c42021-05-21 05:02:22 +00008341}
8342
Siarhei Vishniakouf00a4ec2021-06-16 03:55:32 +00008343TEST_F(InputFilterInjectionPolicyTest, KeyEventsInjectedFromAccessibility_HaveAccessibilityFlag) {
Siarhei Vishniakou5d552c42021-05-21 05:02:22 +00008344 testInjectedKey(POLICY_FLAG_FILTERED | POLICY_FLAG_INJECTED_FROM_ACCESSIBILITY,
Harry Cutts33476232023-01-30 19:57:29 +00008345 /*injectedDeviceId=*/3, /*resolvedDeviceId=*/3,
Siarhei Vishniakouf00a4ec2021-06-16 03:55:32 +00008346 AKEY_EVENT_FLAG_IS_ACCESSIBILITY_EVENT);
8347}
8348
8349TEST_F(InputFilterInjectionPolicyTest,
8350 MotionEventsInjectedFromAccessibility_HaveAccessibilityFlag) {
8351 testInjectedMotion(POLICY_FLAG_FILTERED | POLICY_FLAG_INJECTED_FROM_ACCESSIBILITY,
Harry Cutts33476232023-01-30 19:57:29 +00008352 /*injectedDeviceId=*/3, /*resolvedDeviceId=*/3,
Siarhei Vishniakouf00a4ec2021-06-16 03:55:32 +00008353 AMOTION_EVENT_FLAG_IS_ACCESSIBILITY_EVENT);
Siarhei Vishniakou5d552c42021-05-21 05:02:22 +00008354}
8355
8356TEST_F(InputFilterInjectionPolicyTest, RegularInjectedEvents_ReceiveVirtualDeviceId) {
Harry Cutts33476232023-01-30 19:57:29 +00008357 testInjectedKey(/*policyFlags=*/0, /*injectedDeviceId=*/3,
8358 /*resolvedDeviceId=*/VIRTUAL_KEYBOARD_ID, /*flags=*/0);
Siarhei Vishniakou5d552c42021-05-21 05:02:22 +00008359}
8360
Yeabkal Wubshitb8aadfa2024-01-17 17:03:42 -08008361class InputDispatcherUserActivityPokeTests : public InputDispatcherTest {
8362protected:
8363 virtual void SetUp() override {
8364 InputDispatcherTest::SetUp();
8365
8366 std::shared_ptr<FakeApplicationHandle> application =
8367 std::make_shared<FakeApplicationHandle>();
8368 application->setDispatchingTimeout(100ms);
8369 mWindow = sp<FakeWindowHandle>::make(application, mDispatcher, "TestWindow",
8370 ADISPLAY_ID_DEFAULT);
Yeabkal Wubshit222d83d2024-01-24 18:00:09 +00008371 mWindow->setFrame(Rect(0, 0, 100, 100));
Yeabkal Wubshitb8aadfa2024-01-17 17:03:42 -08008372 mWindow->setDispatchingTimeout(100ms);
8373 mWindow->setFocusable(true);
8374
8375 // Set focused application.
8376 mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application);
8377
8378 mDispatcher->onWindowInfosChanged({{*mWindow->getInfo()}, {}, 0, 0});
8379 setFocusedWindow(mWindow);
8380 mWindow->consumeFocusEvent(true);
8381 }
8382
8383 void notifyAndConsumeMotion(int32_t action, uint32_t source, int32_t displayId,
8384 nsecs_t eventTime) {
8385 mDispatcher->notifyMotion(MotionArgsBuilder(action, source)
8386 .displayId(displayId)
8387 .eventTime(eventTime)
8388 .pointer(PointerBuilder(0, ToolType::FINGER).x(50).y(50))
8389 .build());
8390 mWindow->consumeMotionEvent(WithMotionAction(action));
8391 }
8392
8393private:
8394 sp<FakeWindowHandle> mWindow;
8395};
8396
8397TEST_F_WITH_FLAGS(
8398 InputDispatcherUserActivityPokeTests, MinPokeTimeObserved,
8399 REQUIRES_FLAGS_ENABLED(ACONFIG_FLAG(com::android::input::flags,
8400 rate_limit_user_activity_poke_in_dispatcher))) {
8401 mDispatcher->setMinTimeBetweenUserActivityPokes(50ms);
8402
8403 // First event of type TOUCH. Should poke.
8404 notifyAndConsumeMotion(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
8405 milliseconds_to_nanoseconds(50));
8406 mFakePolicy->assertUserActivityPoked(
8407 {{milliseconds_to_nanoseconds(50), USER_ACTIVITY_EVENT_TOUCH, ADISPLAY_ID_DEFAULT}});
8408
8409 // 80ns > 50ns has passed since previous TOUCH event. Should poke.
8410 notifyAndConsumeMotion(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
8411 milliseconds_to_nanoseconds(130));
8412 mFakePolicy->assertUserActivityPoked(
8413 {{milliseconds_to_nanoseconds(130), USER_ACTIVITY_EVENT_TOUCH, ADISPLAY_ID_DEFAULT}});
8414
8415 // First event of type OTHER. Should poke (despite being within 50ns of previous TOUCH event).
8416 notifyAndConsumeMotion(ACTION_SCROLL, AINPUT_SOURCE_ROTARY_ENCODER, ADISPLAY_ID_DEFAULT,
8417 milliseconds_to_nanoseconds(135));
8418 mFakePolicy->assertUserActivityPoked(
8419 {{milliseconds_to_nanoseconds(135), USER_ACTIVITY_EVENT_OTHER, ADISPLAY_ID_DEFAULT}});
8420
8421 // Within 50ns of previous TOUCH event. Should NOT poke.
8422 notifyAndConsumeMotion(ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
8423 milliseconds_to_nanoseconds(140));
8424 mFakePolicy->assertUserActivityNotPoked();
8425
8426 // Within 50ns of previous OTHER event. Should NOT poke.
8427 notifyAndConsumeMotion(ACTION_SCROLL, AINPUT_SOURCE_ROTARY_ENCODER, ADISPLAY_ID_DEFAULT,
8428 milliseconds_to_nanoseconds(150));
8429 mFakePolicy->assertUserActivityNotPoked();
8430
8431 // Within 50ns of previous TOUCH event (which was at time 130). Should NOT poke.
8432 // Note that STYLUS is mapped to TOUCH user activity, since it's a pointer-type source.
8433 notifyAndConsumeMotion(ACTION_DOWN, AINPUT_SOURCE_STYLUS, ADISPLAY_ID_DEFAULT,
8434 milliseconds_to_nanoseconds(160));
8435 mFakePolicy->assertUserActivityNotPoked();
8436
8437 // 65ns > 50ns has passed since previous OTHER event. Should poke.
8438 notifyAndConsumeMotion(ACTION_SCROLL, AINPUT_SOURCE_ROTARY_ENCODER, ADISPLAY_ID_DEFAULT,
8439 milliseconds_to_nanoseconds(200));
8440 mFakePolicy->assertUserActivityPoked(
8441 {{milliseconds_to_nanoseconds(200), USER_ACTIVITY_EVENT_OTHER, ADISPLAY_ID_DEFAULT}});
8442
8443 // 170ns > 50ns has passed since previous TOUCH event. Should poke.
8444 notifyAndConsumeMotion(ACTION_UP, AINPUT_SOURCE_STYLUS, ADISPLAY_ID_DEFAULT,
8445 milliseconds_to_nanoseconds(300));
8446 mFakePolicy->assertUserActivityPoked(
8447 {{milliseconds_to_nanoseconds(300), USER_ACTIVITY_EVENT_TOUCH, ADISPLAY_ID_DEFAULT}});
8448
8449 // Assert that there's no more user activity poke event.
8450 mFakePolicy->assertUserActivityNotPoked();
8451}
8452
8453TEST_F_WITH_FLAGS(
8454 InputDispatcherUserActivityPokeTests, DefaultMinPokeTimeOf100MsUsed,
8455 REQUIRES_FLAGS_ENABLED(ACONFIG_FLAG(com::android::input::flags,
8456 rate_limit_user_activity_poke_in_dispatcher))) {
8457 notifyAndConsumeMotion(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
8458 milliseconds_to_nanoseconds(200));
8459 mFakePolicy->assertUserActivityPoked(
8460 {{milliseconds_to_nanoseconds(200), USER_ACTIVITY_EVENT_TOUCH, ADISPLAY_ID_DEFAULT}});
8461
8462 notifyAndConsumeMotion(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
8463 milliseconds_to_nanoseconds(280));
8464 mFakePolicy->assertUserActivityNotPoked();
8465
8466 notifyAndConsumeMotion(ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
8467 milliseconds_to_nanoseconds(340));
8468 mFakePolicy->assertUserActivityPoked(
8469 {{milliseconds_to_nanoseconds(340), USER_ACTIVITY_EVENT_TOUCH, ADISPLAY_ID_DEFAULT}});
8470}
8471
8472TEST_F_WITH_FLAGS(
8473 InputDispatcherUserActivityPokeTests, ZeroMinPokeTimeDisablesRateLimiting,
8474 REQUIRES_FLAGS_ENABLED(ACONFIG_FLAG(com::android::input::flags,
8475 rate_limit_user_activity_poke_in_dispatcher))) {
8476 mDispatcher->setMinTimeBetweenUserActivityPokes(0ms);
8477
8478 notifyAndConsumeMotion(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, 20);
8479 mFakePolicy->assertUserActivityPoked();
8480
8481 notifyAndConsumeMotion(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, 30);
8482 mFakePolicy->assertUserActivityPoked();
8483}
8484
chaviwfd6d3512019-03-25 13:23:49 -07008485class InputDispatcherOnPointerDownOutsideFocus : public InputDispatcherTest {
Prabir Pradhan3608aad2019-10-02 17:08:26 -07008486 virtual void SetUp() override {
chaviwfd6d3512019-03-25 13:23:49 -07008487 InputDispatcherTest::SetUp();
8488
Chris Yea209fde2020-07-22 13:54:51 -07008489 std::shared_ptr<FakeApplicationHandle> application =
8490 std::make_shared<FakeApplicationHandle>();
Siarhei Vishniakou870ecec2020-12-09 08:07:46 -10008491 mUnfocusedWindow =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07008492 sp<FakeWindowHandle>::make(application, mDispatcher, "Top", ADISPLAY_ID_DEFAULT);
chaviwfd6d3512019-03-25 13:23:49 -07008493 mUnfocusedWindow->setFrame(Rect(0, 0, 30, 30));
chaviwfd6d3512019-03-25 13:23:49 -07008494
Siarhei Vishniakoub9b15352019-11-26 13:19:26 -08008495 mFocusedWindow =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07008496 sp<FakeWindowHandle>::make(application, mDispatcher, "Second", ADISPLAY_ID_DEFAULT);
Siarhei Vishniakoub9b15352019-11-26 13:19:26 -08008497 mFocusedWindow->setFrame(Rect(50, 50, 100, 100));
chaviwfd6d3512019-03-25 13:23:49 -07008498
8499 // Set focused application.
8500 mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application);
Vishnu Nair47074b82020-08-14 11:54:47 -07008501 mFocusedWindow->setFocusable(true);
chaviwfd6d3512019-03-25 13:23:49 -07008502
8503 // Expect one focus window exist in display.
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07008504 mDispatcher->onWindowInfosChanged(
8505 {{*mUnfocusedWindow->getInfo(), *mFocusedWindow->getInfo()}, {}, 0, 0});
Vishnu Nair958da932020-08-21 17:12:37 -07008506 setFocusedWindow(mFocusedWindow);
Siarhei Vishniakouf1035d42019-09-20 16:32:01 +01008507 mFocusedWindow->consumeFocusEvent(true);
chaviwfd6d3512019-03-25 13:23:49 -07008508 }
8509
Prabir Pradhan3608aad2019-10-02 17:08:26 -07008510 virtual void TearDown() override {
chaviwfd6d3512019-03-25 13:23:49 -07008511 InputDispatcherTest::TearDown();
8512
8513 mUnfocusedWindow.clear();
Siarhei Vishniakoub9b15352019-11-26 13:19:26 -08008514 mFocusedWindow.clear();
chaviwfd6d3512019-03-25 13:23:49 -07008515 }
8516
8517protected:
8518 sp<FakeWindowHandle> mUnfocusedWindow;
Siarhei Vishniakoub9b15352019-11-26 13:19:26 -08008519 sp<FakeWindowHandle> mFocusedWindow;
Siarhei Vishniakoufb9fcda2020-05-04 14:59:19 -07008520 static constexpr PointF FOCUSED_WINDOW_TOUCH_POINT = {60, 60};
chaviwfd6d3512019-03-25 13:23:49 -07008521};
8522
8523// Have two windows, one with focus. Inject MotionEvent with source TOUCHSCREEN and action
8524// DOWN on the window that doesn't have focus. Ensure the window that didn't have focus received
8525// the onPointerDownOutsideFocus callback.
8526TEST_F(InputDispatcherOnPointerDownOutsideFocus, OnPointerDownOutsideFocus_Success) {
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08008527 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07008528 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
Siarhei Vishniakoufb9fcda2020-05-04 14:59:19 -07008529 {20, 20}))
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08008530 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
Siarhei Vishniakou03aee2a2020-04-13 20:44:54 -07008531 mUnfocusedWindow->consumeMotionDown();
chaviwfd6d3512019-03-25 13:23:49 -07008532
Siarhei Vishniakou2bfa9052019-11-21 18:10:54 -08008533 ASSERT_TRUE(mDispatcher->waitForIdle());
chaviwfd6d3512019-03-25 13:23:49 -07008534 mFakePolicy->assertOnPointerDownEquals(mUnfocusedWindow->getToken());
8535}
8536
8537// Have two windows, one with focus. Inject MotionEvent with source TRACKBALL and action
8538// DOWN on the window that doesn't have focus. Ensure no window received the
8539// onPointerDownOutsideFocus callback.
8540TEST_F(InputDispatcherOnPointerDownOutsideFocus, OnPointerDownOutsideFocus_NonPointerSource) {
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08008541 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07008542 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TRACKBALL, ADISPLAY_ID_DEFAULT,
8543 {20, 20}))
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08008544 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
Siarhei Vishniakou03aee2a2020-04-13 20:44:54 -07008545 mFocusedWindow->consumeMotionDown();
chaviwfd6d3512019-03-25 13:23:49 -07008546
Siarhei Vishniakou2bfa9052019-11-21 18:10:54 -08008547 ASSERT_TRUE(mDispatcher->waitForIdle());
8548 mFakePolicy->assertOnPointerDownWasNotCalled();
chaviwfd6d3512019-03-25 13:23:49 -07008549}
8550
8551// Have two windows, one with focus. Inject KeyEvent with action DOWN on the window that doesn't
8552// have focus. Ensure no window received the onPointerDownOutsideFocus callback.
8553TEST_F(InputDispatcherOnPointerDownOutsideFocus, OnPointerDownOutsideFocus_NonMotionFailure) {
Prabir Pradhan93f342c2021-03-11 15:05:30 -08008554 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07008555 injectKeyDownNoRepeat(*mDispatcher, ADISPLAY_ID_DEFAULT))
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08008556 << "Inject key event should return InputEventInjectionResult::SUCCEEDED";
Siarhei Vishniakou03aee2a2020-04-13 20:44:54 -07008557 mFocusedWindow->consumeKeyDown(ADISPLAY_ID_DEFAULT);
chaviwfd6d3512019-03-25 13:23:49 -07008558
Siarhei Vishniakou2bfa9052019-11-21 18:10:54 -08008559 ASSERT_TRUE(mDispatcher->waitForIdle());
8560 mFakePolicy->assertOnPointerDownWasNotCalled();
chaviwfd6d3512019-03-25 13:23:49 -07008561}
8562
8563// Have two windows, one with focus. Inject MotionEvent with source TOUCHSCREEN and action
8564// DOWN on the window that already has focus. Ensure no window received the
8565// onPointerDownOutsideFocus callback.
Siarhei Vishniakou870ecec2020-12-09 08:07:46 -10008566TEST_F(InputDispatcherOnPointerDownOutsideFocus, OnPointerDownOutsideFocus_OnAlreadyFocusedWindow) {
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08008567 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07008568 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
Siarhei Vishniakoufb9fcda2020-05-04 14:59:19 -07008569 FOCUSED_WINDOW_TOUCH_POINT))
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08008570 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
Siarhei Vishniakou03aee2a2020-04-13 20:44:54 -07008571 mFocusedWindow->consumeMotionDown();
chaviwfd6d3512019-03-25 13:23:49 -07008572
Siarhei Vishniakou2bfa9052019-11-21 18:10:54 -08008573 ASSERT_TRUE(mDispatcher->waitForIdle());
8574 mFakePolicy->assertOnPointerDownWasNotCalled();
chaviwfd6d3512019-03-25 13:23:49 -07008575}
8576
Prabir Pradhan47cf0a02021-03-11 20:30:57 -08008577// Have two windows, one with focus. Injecting a trusted DOWN MotionEvent with the flag
8578// NO_FOCUS_CHANGE on the unfocused window should not call the onPointerDownOutsideFocus callback.
8579TEST_F(InputDispatcherOnPointerDownOutsideFocus, NoFocusChangeFlag) {
8580 const MotionEvent event =
8581 MotionEventBuilder(AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_MOUSE)
8582 .eventTime(systemTime(SYSTEM_TIME_MONOTONIC))
Siarhei Vishniakou6d73f832022-07-21 17:27:03 -07008583 .pointer(PointerBuilder(/*id=*/0, ToolType::FINGER).x(20).y(20))
Prabir Pradhan47cf0a02021-03-11 20:30:57 -08008584 .addFlag(AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE)
8585 .build();
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07008586 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectMotionEvent(*mDispatcher, event))
Prabir Pradhan47cf0a02021-03-11 20:30:57 -08008587 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
8588 mUnfocusedWindow->consumeAnyMotionDown(ADISPLAY_ID_DEFAULT, AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
8589
8590 ASSERT_TRUE(mDispatcher->waitForIdle());
8591 mFakePolicy->assertOnPointerDownWasNotCalled();
8592 // Ensure that the unfocused window did not receive any FOCUS events.
8593 mUnfocusedWindow->assertNoEvents();
8594}
8595
chaviwaf87b3e2019-10-01 16:59:28 -07008596// These tests ensures we can send touch events to a single client when there are multiple input
8597// windows that point to the same client token.
8598class InputDispatcherMultiWindowSameTokenTests : public InputDispatcherTest {
8599 virtual void SetUp() override {
8600 InputDispatcherTest::SetUp();
8601
Chris Yea209fde2020-07-22 13:54:51 -07008602 std::shared_ptr<FakeApplicationHandle> application =
8603 std::make_shared<FakeApplicationHandle>();
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07008604 mWindow1 = sp<FakeWindowHandle>::make(application, mDispatcher, "Fake Window 1",
8605 ADISPLAY_ID_DEFAULT);
chaviwaf87b3e2019-10-01 16:59:28 -07008606 mWindow1->setFrame(Rect(0, 0, 100, 100));
8607
Prabir Pradhane7cc69c2024-01-05 21:35:28 +00008608 mWindow2 = mWindow1->clone(ADISPLAY_ID_DEFAULT);
chaviwaf87b3e2019-10-01 16:59:28 -07008609 mWindow2->setFrame(Rect(100, 100, 200, 200));
8610
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07008611 mDispatcher->onWindowInfosChanged({{*mWindow1->getInfo(), *mWindow2->getInfo()}, {}, 0, 0});
chaviwaf87b3e2019-10-01 16:59:28 -07008612 }
8613
8614protected:
8615 sp<FakeWindowHandle> mWindow1;
8616 sp<FakeWindowHandle> mWindow2;
8617
8618 // Helper function to convert the point from screen coordinates into the window's space
chaviw3277faf2021-05-19 16:45:23 -05008619 static PointF getPointInWindow(const WindowInfo* windowInfo, const PointF& point) {
chaviw1ff3d1e2020-07-01 15:53:47 -07008620 vec2 vals = windowInfo->transform.transform(point.x, point.y);
8621 return {vals.x, vals.y};
chaviwaf87b3e2019-10-01 16:59:28 -07008622 }
8623
8624 void consumeMotionEvent(const sp<FakeWindowHandle>& window, int32_t expectedAction,
8625 const std::vector<PointF>& points) {
Siarhei Vishniakouf1035d42019-09-20 16:32:01 +01008626 const std::string name = window->getName();
Siarhei Vishniakoud3061ab2023-12-18 20:41:08 -08008627 std::unique_ptr<MotionEvent> motionEvent =
Prabir Pradhan7662a8d2023-12-15 01:58:14 +00008628 window->consumeMotionEvent(WithMotionAction(expectedAction));
Siarhei Vishniakoud3061ab2023-12-18 20:41:08 -08008629 ASSERT_NE(nullptr, motionEvent);
8630 ASSERT_EQ(points.size(), motionEvent->getPointerCount());
chaviwaf87b3e2019-10-01 16:59:28 -07008631
8632 for (size_t i = 0; i < points.size(); i++) {
8633 float expectedX = points[i].x;
8634 float expectedY = points[i].y;
8635
Siarhei Vishniakoud3061ab2023-12-18 20:41:08 -08008636 EXPECT_EQ(expectedX, motionEvent->getX(i))
chaviwaf87b3e2019-10-01 16:59:28 -07008637 << "expected " << expectedX << " for x[" << i << "] coord of " << name.c_str()
Siarhei Vishniakoud3061ab2023-12-18 20:41:08 -08008638 << ", got " << motionEvent->getX(i);
8639 EXPECT_EQ(expectedY, motionEvent->getY(i))
chaviwaf87b3e2019-10-01 16:59:28 -07008640 << "expected " << expectedY << " for y[" << i << "] coord of " << name.c_str()
Siarhei Vishniakoud3061ab2023-12-18 20:41:08 -08008641 << ", got " << motionEvent->getY(i);
chaviwaf87b3e2019-10-01 16:59:28 -07008642 }
8643 }
chaviw9eaa22c2020-07-01 16:21:27 -07008644
Prabir Pradhanbb3f1c02024-01-04 20:17:14 +00008645 void touchAndAssertPositions(sp<FakeWindowHandle> touchedWindow, int32_t action,
8646 const std::vector<PointF>& touchedPoints,
chaviw9eaa22c2020-07-01 16:21:27 -07008647 std::vector<PointF> expectedPoints) {
Prabir Pradhan678438e2023-04-13 19:32:51 +00008648 mDispatcher->notifyMotion(generateMotionArgs(action, AINPUT_SOURCE_TOUCHSCREEN,
8649 ADISPLAY_ID_DEFAULT, touchedPoints));
chaviw9eaa22c2020-07-01 16:21:27 -07008650
Prabir Pradhanbb3f1c02024-01-04 20:17:14 +00008651 consumeMotionEvent(touchedWindow, action, expectedPoints);
chaviw9eaa22c2020-07-01 16:21:27 -07008652 }
chaviwaf87b3e2019-10-01 16:59:28 -07008653};
8654
8655TEST_F(InputDispatcherMultiWindowSameTokenTests, SingleTouchSameScale) {
8656 // Touch Window 1
8657 PointF touchedPoint = {10, 10};
8658 PointF expectedPoint = getPointInWindow(mWindow1->getInfo(), touchedPoint);
Prabir Pradhanbb3f1c02024-01-04 20:17:14 +00008659 touchAndAssertPositions(mWindow1, AMOTION_EVENT_ACTION_DOWN, {touchedPoint}, {expectedPoint});
chaviwaf87b3e2019-10-01 16:59:28 -07008660
8661 // Release touch on Window 1
Prabir Pradhanbb3f1c02024-01-04 20:17:14 +00008662 touchAndAssertPositions(mWindow1, AMOTION_EVENT_ACTION_UP, {touchedPoint}, {expectedPoint});
chaviwaf87b3e2019-10-01 16:59:28 -07008663
8664 // Touch Window 2
8665 touchedPoint = {150, 150};
8666 expectedPoint = getPointInWindow(mWindow2->getInfo(), touchedPoint);
Prabir Pradhanbb3f1c02024-01-04 20:17:14 +00008667 touchAndAssertPositions(mWindow2, AMOTION_EVENT_ACTION_DOWN, {touchedPoint}, {expectedPoint});
chaviwaf87b3e2019-10-01 16:59:28 -07008668}
8669
chaviw9eaa22c2020-07-01 16:21:27 -07008670TEST_F(InputDispatcherMultiWindowSameTokenTests, SingleTouchDifferentTransform) {
8671 // Set scale value for window2
chaviwaf87b3e2019-10-01 16:59:28 -07008672 mWindow2->setWindowScale(0.5f, 0.5f);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07008673 mDispatcher->onWindowInfosChanged({{*mWindow1->getInfo(), *mWindow2->getInfo()}, {}, 0, 0});
chaviwaf87b3e2019-10-01 16:59:28 -07008674
8675 // Touch Window 1
8676 PointF touchedPoint = {10, 10};
8677 PointF expectedPoint = getPointInWindow(mWindow1->getInfo(), touchedPoint);
Prabir Pradhanbb3f1c02024-01-04 20:17:14 +00008678 touchAndAssertPositions(mWindow1, AMOTION_EVENT_ACTION_DOWN, {touchedPoint}, {expectedPoint});
chaviwaf87b3e2019-10-01 16:59:28 -07008679 // Release touch on Window 1
Prabir Pradhanbb3f1c02024-01-04 20:17:14 +00008680 touchAndAssertPositions(mWindow1, AMOTION_EVENT_ACTION_UP, {touchedPoint}, {expectedPoint});
chaviwaf87b3e2019-10-01 16:59:28 -07008681
8682 // Touch Window 2
8683 touchedPoint = {150, 150};
8684 expectedPoint = getPointInWindow(mWindow2->getInfo(), touchedPoint);
Prabir Pradhanbb3f1c02024-01-04 20:17:14 +00008685 touchAndAssertPositions(mWindow2, AMOTION_EVENT_ACTION_DOWN, {touchedPoint}, {expectedPoint});
8686 touchAndAssertPositions(mWindow2, AMOTION_EVENT_ACTION_UP, {touchedPoint}, {expectedPoint});
chaviwaf87b3e2019-10-01 16:59:28 -07008687
chaviw9eaa22c2020-07-01 16:21:27 -07008688 // Update the transform so rotation is set
8689 mWindow2->setWindowTransform(0, -1, 1, 0);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07008690 mDispatcher->onWindowInfosChanged({{*mWindow1->getInfo(), *mWindow2->getInfo()}, {}, 0, 0});
chaviw9eaa22c2020-07-01 16:21:27 -07008691 expectedPoint = getPointInWindow(mWindow2->getInfo(), touchedPoint);
Prabir Pradhanbb3f1c02024-01-04 20:17:14 +00008692 touchAndAssertPositions(mWindow2, AMOTION_EVENT_ACTION_DOWN, {touchedPoint}, {expectedPoint});
chaviwaf87b3e2019-10-01 16:59:28 -07008693}
8694
chaviw9eaa22c2020-07-01 16:21:27 -07008695TEST_F(InputDispatcherMultiWindowSameTokenTests, MultipleTouchDifferentTransform) {
Chavi Weingarten65f98b82020-01-16 18:56:50 +00008696 mWindow2->setWindowScale(0.5f, 0.5f);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07008697 mDispatcher->onWindowInfosChanged({{*mWindow1->getInfo(), *mWindow2->getInfo()}, {}, 0, 0});
Chavi Weingarten65f98b82020-01-16 18:56:50 +00008698
8699 // Touch Window 1
8700 std::vector<PointF> touchedPoints = {PointF{10, 10}};
8701 std::vector<PointF> expectedPoints = {getPointInWindow(mWindow1->getInfo(), touchedPoints[0])};
Prabir Pradhanbb3f1c02024-01-04 20:17:14 +00008702 touchAndAssertPositions(mWindow1, AMOTION_EVENT_ACTION_DOWN, touchedPoints, expectedPoints);
Chavi Weingarten65f98b82020-01-16 18:56:50 +00008703
8704 // Touch Window 2
Prabir Pradhanbb3f1c02024-01-04 20:17:14 +00008705 // Since this is part of the same touch gesture that has already been dispatched to Window 1,
8706 // the touch stream from Window 2 will be merged with the stream in Window 1. The merged stream
8707 // will continue to be dispatched through Window 1.
chaviw9eaa22c2020-07-01 16:21:27 -07008708 touchedPoints.push_back(PointF{150, 150});
8709 expectedPoints.push_back(getPointInWindow(mWindow2->getInfo(), touchedPoints[1]));
Prabir Pradhanbb3f1c02024-01-04 20:17:14 +00008710 touchAndAssertPositions(mWindow1, POINTER_1_DOWN, touchedPoints, expectedPoints);
Chavi Weingarten65f98b82020-01-16 18:56:50 +00008711
chaviw9eaa22c2020-07-01 16:21:27 -07008712 // Release Window 2
Prabir Pradhanbb3f1c02024-01-04 20:17:14 +00008713 touchAndAssertPositions(mWindow1, POINTER_1_UP, touchedPoints, expectedPoints);
chaviw9eaa22c2020-07-01 16:21:27 -07008714 expectedPoints.pop_back();
Chavi Weingarten65f98b82020-01-16 18:56:50 +00008715
chaviw9eaa22c2020-07-01 16:21:27 -07008716 // Update the transform so rotation is set for Window 2
8717 mWindow2->setWindowTransform(0, -1, 1, 0);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07008718 mDispatcher->onWindowInfosChanged({{*mWindow1->getInfo(), *mWindow2->getInfo()}, {}, 0, 0});
chaviw9eaa22c2020-07-01 16:21:27 -07008719 expectedPoints.push_back(getPointInWindow(mWindow2->getInfo(), touchedPoints[1]));
Prabir Pradhanbb3f1c02024-01-04 20:17:14 +00008720 touchAndAssertPositions(mWindow1, POINTER_1_DOWN, touchedPoints, expectedPoints);
Chavi Weingarten65f98b82020-01-16 18:56:50 +00008721}
8722
chaviw9eaa22c2020-07-01 16:21:27 -07008723TEST_F(InputDispatcherMultiWindowSameTokenTests, MultipleTouchMoveDifferentTransform) {
Chavi Weingarten65f98b82020-01-16 18:56:50 +00008724 mWindow2->setWindowScale(0.5f, 0.5f);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07008725 mDispatcher->onWindowInfosChanged({{*mWindow1->getInfo(), *mWindow2->getInfo()}, {}, 0, 0});
Chavi Weingarten65f98b82020-01-16 18:56:50 +00008726
8727 // Touch Window 1
8728 std::vector<PointF> touchedPoints = {PointF{10, 10}};
8729 std::vector<PointF> expectedPoints = {getPointInWindow(mWindow1->getInfo(), touchedPoints[0])};
Prabir Pradhanbb3f1c02024-01-04 20:17:14 +00008730 touchAndAssertPositions(mWindow1, AMOTION_EVENT_ACTION_DOWN, touchedPoints, expectedPoints);
Chavi Weingarten65f98b82020-01-16 18:56:50 +00008731
8732 // Touch Window 2
chaviw9eaa22c2020-07-01 16:21:27 -07008733 touchedPoints.push_back(PointF{150, 150});
8734 expectedPoints.push_back(getPointInWindow(mWindow2->getInfo(), touchedPoints[1]));
Chavi Weingarten65f98b82020-01-16 18:56:50 +00008735
Prabir Pradhanbb3f1c02024-01-04 20:17:14 +00008736 touchAndAssertPositions(mWindow1, POINTER_1_DOWN, touchedPoints, expectedPoints);
Chavi Weingarten65f98b82020-01-16 18:56:50 +00008737
8738 // Move both windows
8739 touchedPoints = {{20, 20}, {175, 175}};
8740 expectedPoints = {getPointInWindow(mWindow1->getInfo(), touchedPoints[0]),
8741 getPointInWindow(mWindow2->getInfo(), touchedPoints[1])};
8742
Prabir Pradhanbb3f1c02024-01-04 20:17:14 +00008743 touchAndAssertPositions(mWindow1, AMOTION_EVENT_ACTION_MOVE, touchedPoints, expectedPoints);
Chavi Weingarten65f98b82020-01-16 18:56:50 +00008744
chaviw9eaa22c2020-07-01 16:21:27 -07008745 // Release Window 2
Prabir Pradhanbb3f1c02024-01-04 20:17:14 +00008746 touchAndAssertPositions(mWindow1, POINTER_1_UP, touchedPoints, expectedPoints);
chaviw9eaa22c2020-07-01 16:21:27 -07008747 expectedPoints.pop_back();
8748
8749 // Touch Window 2
8750 mWindow2->setWindowTransform(0, -1, 1, 0);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07008751 mDispatcher->onWindowInfosChanged({{*mWindow1->getInfo(), *mWindow2->getInfo()}, {}, 0, 0});
chaviw9eaa22c2020-07-01 16:21:27 -07008752 expectedPoints.push_back(getPointInWindow(mWindow2->getInfo(), touchedPoints[1]));
Prabir Pradhanbb3f1c02024-01-04 20:17:14 +00008753 touchAndAssertPositions(mWindow1, POINTER_1_DOWN, touchedPoints, expectedPoints);
chaviw9eaa22c2020-07-01 16:21:27 -07008754
8755 // Move both windows
8756 touchedPoints = {{20, 20}, {175, 175}};
8757 expectedPoints = {getPointInWindow(mWindow1->getInfo(), touchedPoints[0]),
8758 getPointInWindow(mWindow2->getInfo(), touchedPoints[1])};
8759
Prabir Pradhanbb3f1c02024-01-04 20:17:14 +00008760 touchAndAssertPositions(mWindow1, AMOTION_EVENT_ACTION_MOVE, touchedPoints, expectedPoints);
Chavi Weingarten65f98b82020-01-16 18:56:50 +00008761}
8762
8763TEST_F(InputDispatcherMultiWindowSameTokenTests, MultipleWindowsFirstTouchWithScale) {
8764 mWindow1->setWindowScale(0.5f, 0.5f);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07008765 mDispatcher->onWindowInfosChanged({{*mWindow1->getInfo(), *mWindow2->getInfo()}, {}, 0, 0});
Chavi Weingarten65f98b82020-01-16 18:56:50 +00008766
8767 // Touch Window 1
8768 std::vector<PointF> touchedPoints = {PointF{10, 10}};
8769 std::vector<PointF> expectedPoints = {getPointInWindow(mWindow1->getInfo(), touchedPoints[0])};
Prabir Pradhanbb3f1c02024-01-04 20:17:14 +00008770 touchAndAssertPositions(mWindow1, AMOTION_EVENT_ACTION_DOWN, touchedPoints, expectedPoints);
Chavi Weingarten65f98b82020-01-16 18:56:50 +00008771
8772 // Touch Window 2
chaviw9eaa22c2020-07-01 16:21:27 -07008773 touchedPoints.push_back(PointF{150, 150});
8774 expectedPoints.push_back(getPointInWindow(mWindow2->getInfo(), touchedPoints[1]));
Chavi Weingarten65f98b82020-01-16 18:56:50 +00008775
Prabir Pradhanbb3f1c02024-01-04 20:17:14 +00008776 touchAndAssertPositions(mWindow1, POINTER_1_DOWN, touchedPoints, expectedPoints);
Chavi Weingarten65f98b82020-01-16 18:56:50 +00008777
8778 // Move both windows
8779 touchedPoints = {{20, 20}, {175, 175}};
8780 expectedPoints = {getPointInWindow(mWindow1->getInfo(), touchedPoints[0]),
8781 getPointInWindow(mWindow2->getInfo(), touchedPoints[1])};
8782
Prabir Pradhanbb3f1c02024-01-04 20:17:14 +00008783 touchAndAssertPositions(mWindow1, AMOTION_EVENT_ACTION_MOVE, touchedPoints, expectedPoints);
Chavi Weingarten65f98b82020-01-16 18:56:50 +00008784}
8785
Siarhei Vishniakou0f6558d2023-04-21 12:05:13 -07008786/**
8787 * When one of the windows is slippery, the touch should not slip into the other window with the
8788 * same input channel.
8789 */
8790TEST_F(InputDispatcherMultiWindowSameTokenTests, TouchDoesNotSlipEvenIfSlippery) {
8791 mWindow1->setSlippery(true);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07008792 mDispatcher->onWindowInfosChanged({{*mWindow1->getInfo(), *mWindow2->getInfo()}, {}, 0, 0});
Siarhei Vishniakou0f6558d2023-04-21 12:05:13 -07008793
8794 // Touch down in window 1
8795 mDispatcher->notifyMotion(generateMotionArgs(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN,
8796 ADISPLAY_ID_DEFAULT, {{50, 50}}));
8797 consumeMotionEvent(mWindow1, ACTION_DOWN, {{50, 50}});
8798
8799 // Move touch to be above window 2. Even though window 1 is slippery, touch should not slip.
8800 // That means the gesture should continue normally, without any ACTION_CANCEL or ACTION_DOWN
8801 // getting generated.
8802 mDispatcher->notifyMotion(generateMotionArgs(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN,
8803 ADISPLAY_ID_DEFAULT, {{150, 150}}));
8804
8805 consumeMotionEvent(mWindow1, ACTION_MOVE, {{150, 150}});
8806}
8807
Siarhei Vishniakoud5876ba2023-05-15 17:58:34 -07008808/**
8809 * When hover starts in one window and continues into the other, there should be a HOVER_EXIT and
8810 * a HOVER_ENTER generated, even if the windows have the same token. This is because the new window
8811 * that the pointer is hovering over may have a different transform.
8812 */
8813TEST_F(InputDispatcherMultiWindowSameTokenTests, HoverIntoClone) {
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07008814 mDispatcher->onWindowInfosChanged({{*mWindow1->getInfo(), *mWindow2->getInfo()}, {}, 0, 0});
Siarhei Vishniakoud5876ba2023-05-15 17:58:34 -07008815
8816 // Start hover in window 1
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -07008817 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_ENTER, AINPUT_SOURCE_TOUCHSCREEN)
8818 .pointer(PointerBuilder(0, ToolType::FINGER).x(50).y(50))
8819 .build());
Siarhei Vishniakoud5876ba2023-05-15 17:58:34 -07008820 consumeMotionEvent(mWindow1, ACTION_HOVER_ENTER,
8821 {getPointInWindow(mWindow1->getInfo(), PointF{50, 50})});
Siarhei Vishniakoud5876ba2023-05-15 17:58:34 -07008822 // Move hover to window 2.
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -07008823 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_MOVE, AINPUT_SOURCE_TOUCHSCREEN)
8824 .pointer(PointerBuilder(0, ToolType::FINGER).x(150).y(150))
8825 .build());
Siarhei Vishniakoud5876ba2023-05-15 17:58:34 -07008826 consumeMotionEvent(mWindow1, ACTION_HOVER_EXIT, {{50, 50}});
Prabir Pradhanbb3f1c02024-01-04 20:17:14 +00008827 consumeMotionEvent(mWindow2, ACTION_HOVER_ENTER,
Siarhei Vishniakoud5876ba2023-05-15 17:58:34 -07008828 {getPointInWindow(mWindow2->getInfo(), PointF{150, 150})});
8829}
8830
Siarhei Vishniakou4cb50ca2020-05-26 21:43:02 -07008831class InputDispatcherSingleWindowAnr : public InputDispatcherTest {
8832 virtual void SetUp() override {
8833 InputDispatcherTest::SetUp();
8834
Chris Yea209fde2020-07-22 13:54:51 -07008835 mApplication = std::make_shared<FakeApplicationHandle>();
Siarhei Vishniakouf83c6932023-07-07 17:48:10 -07008836 mApplication->setDispatchingTimeout(100ms);
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07008837 mWindow = sp<FakeWindowHandle>::make(mApplication, mDispatcher, "TestWindow",
8838 ADISPLAY_ID_DEFAULT);
Siarhei Vishniakou4cb50ca2020-05-26 21:43:02 -07008839 mWindow->setFrame(Rect(0, 0, 30, 30));
Siarhei Vishniakouf83c6932023-07-07 17:48:10 -07008840 mWindow->setDispatchingTimeout(100ms);
Vishnu Nair47074b82020-08-14 11:54:47 -07008841 mWindow->setFocusable(true);
Siarhei Vishniakou4cb50ca2020-05-26 21:43:02 -07008842
8843 // Set focused application.
8844 mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, mApplication);
8845
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07008846 mDispatcher->onWindowInfosChanged({{*mWindow->getInfo()}, {}, 0, 0});
Vishnu Nair958da932020-08-21 17:12:37 -07008847 setFocusedWindow(mWindow);
Siarhei Vishniakou4cb50ca2020-05-26 21:43:02 -07008848 mWindow->consumeFocusEvent(true);
8849 }
8850
8851 virtual void TearDown() override {
8852 InputDispatcherTest::TearDown();
8853 mWindow.clear();
8854 }
8855
8856protected:
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07008857 static constexpr std::chrono::duration SPY_TIMEOUT = 200ms;
Chris Yea209fde2020-07-22 13:54:51 -07008858 std::shared_ptr<FakeApplicationHandle> mApplication;
Siarhei Vishniakou4cb50ca2020-05-26 21:43:02 -07008859 sp<FakeWindowHandle> mWindow;
8860 static constexpr PointF WINDOW_LOCATION = {20, 20};
8861
8862 void tapOnWindow() {
Siarhei Vishniakou67bf2162023-11-16 13:29:50 -08008863 const auto touchingPointer = PointerBuilder(/*id=*/0, ToolType::FINGER)
8864 .x(WINDOW_LOCATION.x)
8865 .y(WINDOW_LOCATION.y);
8866 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
8867 .pointer(touchingPointer)
8868 .build());
8869 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN)
8870 .pointer(touchingPointer)
8871 .build());
Siarhei Vishniakou4cb50ca2020-05-26 21:43:02 -07008872 }
Prabir Pradhan1376fcd2022-01-21 09:56:35 -08008873
8874 sp<FakeWindowHandle> addSpyWindow() {
8875 sp<FakeWindowHandle> spy =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07008876 sp<FakeWindowHandle>::make(mApplication, mDispatcher, "Spy", ADISPLAY_ID_DEFAULT);
Prabir Pradhan1376fcd2022-01-21 09:56:35 -08008877 spy->setTrustedOverlay(true);
8878 spy->setFocusable(false);
Prabir Pradhan51e7db02022-02-07 06:02:57 -08008879 spy->setSpy(true);
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07008880 spy->setDispatchingTimeout(SPY_TIMEOUT);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07008881 mDispatcher->onWindowInfosChanged({{*spy->getInfo(), *mWindow->getInfo()}, {}, 0, 0});
Prabir Pradhan1376fcd2022-01-21 09:56:35 -08008882 return spy;
8883 }
Siarhei Vishniakou4cb50ca2020-05-26 21:43:02 -07008884};
8885
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07008886// Send a tap and respond, which should not cause an ANR.
8887TEST_F(InputDispatcherSingleWindowAnr, WhenTouchIsConsumed_NoAnr) {
8888 tapOnWindow();
8889 mWindow->consumeMotionDown();
8890 mWindow->consumeMotionUp();
8891 ASSERT_TRUE(mDispatcher->waitForIdle());
8892 mFakePolicy->assertNotifyAnrWasNotCalled();
8893}
8894
8895// Send a regular key and respond, which should not cause an ANR.
8896TEST_F(InputDispatcherSingleWindowAnr, WhenKeyIsConsumed_NoAnr) {
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07008897 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectKeyDownNoRepeat(*mDispatcher));
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07008898 mWindow->consumeKeyDown(ADISPLAY_ID_NONE);
8899 ASSERT_TRUE(mDispatcher->waitForIdle());
8900 mFakePolicy->assertNotifyAnrWasNotCalled();
8901}
8902
Siarhei Vishniakoue41c4512020-09-08 19:35:58 -05008903TEST_F(InputDispatcherSingleWindowAnr, WhenFocusedApplicationChanges_NoAnr) {
8904 mWindow->setFocusable(false);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07008905 mDispatcher->onWindowInfosChanged({{*mWindow->getInfo()}, {}, 0, 0});
Siarhei Vishniakoue41c4512020-09-08 19:35:58 -05008906 mWindow->consumeFocusEvent(false);
8907
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08008908 InputEventInjectionResult result =
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07008909 injectKey(*mDispatcher, AKEY_EVENT_ACTION_DOWN, /*repeatCount=*/0, ADISPLAY_ID_DEFAULT,
8910 InputEventInjectionSync::NONE, CONSUME_TIMEOUT_EVENT_EXPECTED,
Harry Cutts33476232023-01-30 19:57:29 +00008911 /*allowKeyRepeat=*/false);
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08008912 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, result);
Siarhei Vishniakoue41c4512020-09-08 19:35:58 -05008913 // Key will not go to window because we have no focused window.
8914 // The 'no focused window' ANR timer should start instead.
8915
8916 // Now, the focused application goes away.
8917 mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, nullptr);
8918 // The key should get dropped and there should be no ANR.
8919
8920 ASSERT_TRUE(mDispatcher->waitForIdle());
8921 mFakePolicy->assertNotifyAnrWasNotCalled();
8922}
8923
Siarhei Vishniakou4cb50ca2020-05-26 21:43:02 -07008924// Send an event to the app and have the app not respond right away.
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07008925// When ANR is raised, policy will tell the dispatcher to cancel the events for that window.
8926// So InputDispatcher will enqueue ACTION_CANCEL event as well.
Siarhei Vishniakou4cb50ca2020-05-26 21:43:02 -07008927TEST_F(InputDispatcherSingleWindowAnr, OnPointerDown_BasicAnr) {
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08008928 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07008929 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
Siarhei Vishniakou4cb50ca2020-05-26 21:43:02 -07008930 WINDOW_LOCATION));
8931
Siarhei Vishniakoud3061ab2023-12-18 20:41:08 -08008932 const auto [sequenceNum, _] = mWindow->receiveEvent(); // ACTION_DOWN
Siarhei Vishniakou4cb50ca2020-05-26 21:43:02 -07008933 ASSERT_TRUE(sequenceNum);
8934 const std::chrono::duration timeout = mWindow->getDispatchingTimeout(DISPATCHING_TIMEOUT);
Prabir Pradhanedd96402022-02-15 01:46:16 -08008935 mFakePolicy->assertNotifyWindowUnresponsiveWasCalled(timeout, mWindow);
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07008936
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07008937 mWindow->finishEvent(*sequenceNum);
Siarhei Vishniakou1ae72f12023-01-29 12:55:30 -08008938 mWindow->consumeMotionEvent(
8939 AllOf(WithMotionAction(ACTION_CANCEL), WithDisplayId(ADISPLAY_ID_DEFAULT)));
Siarhei Vishniakou4cb50ca2020-05-26 21:43:02 -07008940 ASSERT_TRUE(mDispatcher->waitForIdle());
Prabir Pradhanedd96402022-02-15 01:46:16 -08008941 mFakePolicy->assertNotifyWindowResponsiveWasCalled(mWindow->getToken(), mWindow->getPid());
Siarhei Vishniakou4cb50ca2020-05-26 21:43:02 -07008942}
8943
8944// Send a key to the app and have the app not respond right away.
8945TEST_F(InputDispatcherSingleWindowAnr, OnKeyDown_BasicAnr) {
8946 // Inject a key, and don't respond - expect that ANR is called.
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07008947 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectKeyDownNoRepeat(*mDispatcher));
Siarhei Vishniakoud3061ab2023-12-18 20:41:08 -08008948 const auto [sequenceNum, _] = mWindow->receiveEvent();
Siarhei Vishniakou4cb50ca2020-05-26 21:43:02 -07008949 ASSERT_TRUE(sequenceNum);
Siarhei Vishniakou4cb50ca2020-05-26 21:43:02 -07008950 const std::chrono::duration timeout = mWindow->getDispatchingTimeout(DISPATCHING_TIMEOUT);
Prabir Pradhanedd96402022-02-15 01:46:16 -08008951 mFakePolicy->assertNotifyWindowUnresponsiveWasCalled(timeout, mWindow);
Siarhei Vishniakou4cb50ca2020-05-26 21:43:02 -07008952 ASSERT_TRUE(mDispatcher->waitForIdle());
8953}
8954
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07008955// We have a focused application, but no focused window
8956TEST_F(InputDispatcherSingleWindowAnr, FocusedApplication_NoFocusedWindow) {
Vishnu Nair47074b82020-08-14 11:54:47 -07008957 mWindow->setFocusable(false);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07008958 mDispatcher->onWindowInfosChanged({{*mWindow->getInfo()}, {}, 0, 0});
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07008959 mWindow->consumeFocusEvent(false);
8960
8961 // taps on the window work as normal
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08008962 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07008963 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07008964 WINDOW_LOCATION));
8965 ASSERT_NO_FATAL_FAILURE(mWindow->consumeMotionDown());
8966 mDispatcher->waitForIdle();
8967 mFakePolicy->assertNotifyAnrWasNotCalled();
8968
8969 // Once a focused event arrives, we get an ANR for this application
8970 // We specify the injection timeout to be smaller than the application timeout, to ensure that
8971 // injection times out (instead of failing).
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08008972 const InputEventInjectionResult result =
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07008973 injectKey(*mDispatcher, AKEY_EVENT_ACTION_DOWN, /*repeatCount=*/0, ADISPLAY_ID_DEFAULT,
Siarhei Vishniakouf83c6932023-07-07 17:48:10 -07008974 InputEventInjectionSync::WAIT_FOR_RESULT, 50ms, /*allowKeyRepeat=*/false);
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08008975 ASSERT_EQ(InputEventInjectionResult::TIMED_OUT, result);
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07008976 const std::chrono::duration timeout = mApplication->getDispatchingTimeout(DISPATCHING_TIMEOUT);
Vishnu Naire4df8752022-09-08 09:17:55 -07008977 mFakePolicy->assertNotifyNoFocusedWindowAnrWasCalled(timeout, mApplication);
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07008978 ASSERT_TRUE(mDispatcher->waitForIdle());
8979}
8980
Siarhei Vishniakou289e9242022-02-15 14:50:16 -08008981/**
8982 * Make sure the stale key is dropped before causing an ANR. So even if there's no focused window,
8983 * there will not be an ANR.
8984 */
8985TEST_F(InputDispatcherSingleWindowAnr, StaleKeyEventDoesNotAnr) {
8986 mWindow->setFocusable(false);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07008987 mDispatcher->onWindowInfosChanged({{*mWindow->getInfo()}, {}, 0, 0});
Siarhei Vishniakou289e9242022-02-15 14:50:16 -08008988 mWindow->consumeFocusEvent(false);
8989
8990 KeyEvent event;
Siarhei Vishniakoua7333112023-10-27 13:33:29 -07008991 static constexpr std::chrono::duration STALE_EVENT_TIMEOUT = 1000ms;
8992 mFakePolicy->setStaleEventTimeout(STALE_EVENT_TIMEOUT);
Siarhei Vishniakou289e9242022-02-15 14:50:16 -08008993 const nsecs_t eventTime = systemTime(SYSTEM_TIME_MONOTONIC) -
8994 std::chrono::nanoseconds(STALE_EVENT_TIMEOUT).count();
8995
8996 // Define a valid key down event that is stale (too old).
8997 event.initialize(InputEvent::nextId(), DEVICE_ID, AINPUT_SOURCE_KEYBOARD, ADISPLAY_ID_NONE,
Harry Cutts101ee9b2023-07-06 18:04:14 +00008998 INVALID_HMAC, AKEY_EVENT_ACTION_DOWN, /*flags=*/0, AKEYCODE_A, KEY_A,
Hu Guofe3c8f12023-09-22 17:20:15 +08008999 AMETA_NONE, /*repeatCount=*/0, eventTime, eventTime);
Siarhei Vishniakou289e9242022-02-15 14:50:16 -08009000
Hu Guofe3c8f12023-09-22 17:20:15 +08009001 const int32_t policyFlags =
9002 POLICY_FLAG_FILTERED | POLICY_FLAG_PASS_TO_USER | POLICY_FLAG_DISABLE_KEY_REPEAT;
Siarhei Vishniakou289e9242022-02-15 14:50:16 -08009003
9004 InputEventInjectionResult result =
Harry Cutts33476232023-01-30 19:57:29 +00009005 mDispatcher->injectInputEvent(&event, /*targetUid=*/{},
Siarhei Vishniakou289e9242022-02-15 14:50:16 -08009006 InputEventInjectionSync::WAIT_FOR_RESULT,
9007 INJECT_EVENT_TIMEOUT, policyFlags);
9008 ASSERT_EQ(InputEventInjectionResult::FAILED, result)
9009 << "Injection should fail because the event is stale";
9010
9011 ASSERT_TRUE(mDispatcher->waitForIdle());
9012 mFakePolicy->assertNotifyAnrWasNotCalled();
9013 mWindow->assertNoEvents();
9014}
9015
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009016// We have a focused application, but no focused window
Siarhei Vishniakou234129c2020-10-22 22:28:12 -05009017// Make sure that we don't notify policy twice about the same ANR.
9018TEST_F(InputDispatcherSingleWindowAnr, NoFocusedWindow_DoesNotSendDuplicateAnr) {
Siarhei Vishniakou06405fc2023-09-22 13:40:51 -07009019 const std::chrono::duration appTimeout = 400ms;
9020 mApplication->setDispatchingTimeout(appTimeout);
9021 mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, mApplication);
9022
Vishnu Nair47074b82020-08-14 11:54:47 -07009023 mWindow->setFocusable(false);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07009024 mDispatcher->onWindowInfosChanged({{*mWindow->getInfo()}, {}, 0, 0});
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009025 mWindow->consumeFocusEvent(false);
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009026
9027 // Once a focused event arrives, we get an ANR for this application
9028 // We specify the injection timeout to be smaller than the application timeout, to ensure that
9029 // injection times out (instead of failing).
Siarhei Vishniakou06405fc2023-09-22 13:40:51 -07009030 const std::chrono::duration eventInjectionTimeout = 100ms;
9031 ASSERT_LT(eventInjectionTimeout, appTimeout);
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08009032 const InputEventInjectionResult result =
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07009033 injectKey(*mDispatcher, AKEY_EVENT_ACTION_DOWN, /*repeatCount=*/0, ADISPLAY_ID_DEFAULT,
Siarhei Vishniakou06405fc2023-09-22 13:40:51 -07009034 InputEventInjectionSync::WAIT_FOR_RESULT, eventInjectionTimeout,
9035 /*allowKeyRepeat=*/false);
9036 ASSERT_EQ(InputEventInjectionResult::TIMED_OUT, result)
9037 << "result=" << ftl::enum_string(result);
9038 // We already waited for 'eventInjectionTimeout`, because the countdown started when the event
9039 // was first injected. So now we have (appTimeout - eventInjectionTimeout) left to wait.
9040 std::chrono::duration remainingWaitTime = appTimeout - eventInjectionTimeout;
9041 mFakePolicy->assertNotifyNoFocusedWindowAnrWasCalled(remainingWaitTime, mApplication);
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009042
Vishnu Naire4df8752022-09-08 09:17:55 -07009043 std::this_thread::sleep_for(appTimeout);
Siarhei Vishniakou234129c2020-10-22 22:28:12 -05009044 // ANR should not be raised again. It is up to policy to do that if it desires.
9045 mFakePolicy->assertNotifyAnrWasNotCalled();
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009046
Siarhei Vishniakou234129c2020-10-22 22:28:12 -05009047 // If we now get a focused window, the ANR should stop, but the policy handles that via
9048 // 'notifyFocusChanged' callback. This is implemented in the policy so we can't test it here.
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009049 ASSERT_TRUE(mDispatcher->waitForIdle());
9050}
9051
9052// We have a focused application, but no focused window
9053TEST_F(InputDispatcherSingleWindowAnr, NoFocusedWindow_DropsFocusedEvents) {
Vishnu Nair47074b82020-08-14 11:54:47 -07009054 mWindow->setFocusable(false);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07009055 mDispatcher->onWindowInfosChanged({{*mWindow->getInfo()}, {}, 0, 0});
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009056 mWindow->consumeFocusEvent(false);
9057
9058 // Once a focused event arrives, we get an ANR for this application
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07009059 ASSERT_NO_FATAL_FAILURE(assertInjectedKeyTimesOut(*mDispatcher));
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009060
Vishnu Naire4df8752022-09-08 09:17:55 -07009061 const std::chrono::duration timeout = mApplication->getDispatchingTimeout(DISPATCHING_TIMEOUT);
9062 mFakePolicy->assertNotifyNoFocusedWindowAnrWasCalled(timeout, mApplication);
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009063
9064 // Future focused events get dropped right away
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07009065 ASSERT_EQ(InputEventInjectionResult::FAILED, injectKeyDown(*mDispatcher));
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009066 ASSERT_TRUE(mDispatcher->waitForIdle());
9067 mWindow->assertNoEvents();
9068}
9069
9070/**
9071 * Ensure that the implementation is valid. Since we are using multiset to keep track of the
9072 * ANR timeouts, we are allowing entries with identical timestamps in the same connection.
9073 * If we process 1 of the events, but ANR on the second event with the same timestamp,
9074 * the ANR mechanism should still work.
9075 *
9076 * In this test, we are injecting DOWN and UP events with the same timestamps, and acknowledging the
9077 * DOWN event, while not responding on the second one.
9078 */
9079TEST_F(InputDispatcherSingleWindowAnr, Anr_HandlesEventsWithIdenticalTimestamps) {
9080 nsecs_t currentTime = systemTime(SYSTEM_TIME_MONOTONIC);
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07009081 injectMotionEvent(*mDispatcher, AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN,
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009082 ADISPLAY_ID_DEFAULT, WINDOW_LOCATION,
9083 {AMOTION_EVENT_INVALID_CURSOR_POSITION,
9084 AMOTION_EVENT_INVALID_CURSOR_POSITION},
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08009085 500ms, InputEventInjectionSync::WAIT_FOR_RESULT, currentTime);
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009086
9087 // Now send ACTION_UP, with identical timestamp
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07009088 injectMotionEvent(*mDispatcher, AMOTION_EVENT_ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN,
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009089 ADISPLAY_ID_DEFAULT, WINDOW_LOCATION,
9090 {AMOTION_EVENT_INVALID_CURSOR_POSITION,
9091 AMOTION_EVENT_INVALID_CURSOR_POSITION},
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08009092 500ms, InputEventInjectionSync::WAIT_FOR_RESULT, currentTime);
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009093
9094 // We have now sent down and up. Let's consume first event and then ANR on the second.
9095 mWindow->consumeMotionDown(ADISPLAY_ID_DEFAULT);
9096 const std::chrono::duration timeout = mWindow->getDispatchingTimeout(DISPATCHING_TIMEOUT);
Prabir Pradhanedd96402022-02-15 01:46:16 -08009097 mFakePolicy->assertNotifyWindowUnresponsiveWasCalled(timeout, mWindow);
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009098}
9099
Prabir Pradhan1376fcd2022-01-21 09:56:35 -08009100// A spy window can receive an ANR
9101TEST_F(InputDispatcherSingleWindowAnr, SpyWindowAnr) {
9102 sp<FakeWindowHandle> spy = addSpyWindow();
9103
9104 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07009105 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
Prabir Pradhan1376fcd2022-01-21 09:56:35 -08009106 WINDOW_LOCATION));
9107 mWindow->consumeMotionDown();
9108
Siarhei Vishniakoud3061ab2023-12-18 20:41:08 -08009109 const auto [sequenceNum, _] = spy->receiveEvent(); // ACTION_DOWN
Prabir Pradhan1376fcd2022-01-21 09:56:35 -08009110 ASSERT_TRUE(sequenceNum);
9111 const std::chrono::duration timeout = spy->getDispatchingTimeout(DISPATCHING_TIMEOUT);
Prabir Pradhanedd96402022-02-15 01:46:16 -08009112 mFakePolicy->assertNotifyWindowUnresponsiveWasCalled(timeout, spy);
Prabir Pradhan1376fcd2022-01-21 09:56:35 -08009113
9114 spy->finishEvent(*sequenceNum);
Siarhei Vishniakou1ae72f12023-01-29 12:55:30 -08009115 spy->consumeMotionEvent(
9116 AllOf(WithMotionAction(ACTION_CANCEL), WithDisplayId(ADISPLAY_ID_DEFAULT)));
Prabir Pradhan1376fcd2022-01-21 09:56:35 -08009117 ASSERT_TRUE(mDispatcher->waitForIdle());
Prabir Pradhanedd96402022-02-15 01:46:16 -08009118 mFakePolicy->assertNotifyWindowResponsiveWasCalled(spy->getToken(), mWindow->getPid());
Prabir Pradhan1376fcd2022-01-21 09:56:35 -08009119}
9120
9121// If an app is not responding to a key event, spy windows should continue to receive
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009122// new motion events
Prabir Pradhan1376fcd2022-01-21 09:56:35 -08009123TEST_F(InputDispatcherSingleWindowAnr, SpyWindowReceivesEventsDuringAppAnrOnKey) {
9124 sp<FakeWindowHandle> spy = addSpyWindow();
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009125
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08009126 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07009127 injectKeyDown(*mDispatcher, ADISPLAY_ID_DEFAULT));
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009128 mWindow->consumeKeyDown(ADISPLAY_ID_DEFAULT);
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07009129 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectKeyUp(*mDispatcher, ADISPLAY_ID_DEFAULT));
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009130
9131 // Stuck on the ACTION_UP
9132 const std::chrono::duration timeout = mWindow->getDispatchingTimeout(DISPATCHING_TIMEOUT);
Prabir Pradhanedd96402022-02-15 01:46:16 -08009133 mFakePolicy->assertNotifyWindowUnresponsiveWasCalled(timeout, mWindow);
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009134
Prabir Pradhan1376fcd2022-01-21 09:56:35 -08009135 // New tap will go to the spy window, but not to the window
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009136 tapOnWindow();
Prabir Pradhan1376fcd2022-01-21 09:56:35 -08009137 spy->consumeMotionDown(ADISPLAY_ID_DEFAULT);
9138 spy->consumeMotionUp(ADISPLAY_ID_DEFAULT);
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009139
9140 mWindow->consumeKeyUp(ADISPLAY_ID_DEFAULT); // still the previous motion
9141 mDispatcher->waitForIdle();
Prabir Pradhanedd96402022-02-15 01:46:16 -08009142 mFakePolicy->assertNotifyWindowResponsiveWasCalled(mWindow->getToken(), mWindow->getPid());
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009143 mWindow->assertNoEvents();
Prabir Pradhan1376fcd2022-01-21 09:56:35 -08009144 spy->assertNoEvents();
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009145}
9146
Prabir Pradhan1376fcd2022-01-21 09:56:35 -08009147// If an app is not responding to a motion event, spy windows should continue to receive
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009148// new motion events
Prabir Pradhan1376fcd2022-01-21 09:56:35 -08009149TEST_F(InputDispatcherSingleWindowAnr, SpyWindowReceivesEventsDuringAppAnrOnMotion) {
9150 sp<FakeWindowHandle> spy = addSpyWindow();
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009151
9152 tapOnWindow();
Prabir Pradhan1376fcd2022-01-21 09:56:35 -08009153 spy->consumeMotionDown(ADISPLAY_ID_DEFAULT);
9154 spy->consumeMotionUp(ADISPLAY_ID_DEFAULT);
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009155
9156 mWindow->consumeMotionDown();
9157 // Stuck on the ACTION_UP
9158 const std::chrono::duration timeout = mWindow->getDispatchingTimeout(DISPATCHING_TIMEOUT);
Prabir Pradhanedd96402022-02-15 01:46:16 -08009159 mFakePolicy->assertNotifyWindowUnresponsiveWasCalled(timeout, mWindow);
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009160
Prabir Pradhan1376fcd2022-01-21 09:56:35 -08009161 // New tap will go to the spy window, but not to the window
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009162 tapOnWindow();
Prabir Pradhan1376fcd2022-01-21 09:56:35 -08009163 spy->consumeMotionDown(ADISPLAY_ID_DEFAULT);
9164 spy->consumeMotionUp(ADISPLAY_ID_DEFAULT);
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009165
9166 mWindow->consumeMotionUp(ADISPLAY_ID_DEFAULT); // still the previous motion
9167 mDispatcher->waitForIdle();
Prabir Pradhanedd96402022-02-15 01:46:16 -08009168 mFakePolicy->assertNotifyWindowResponsiveWasCalled(mWindow->getToken(), mWindow->getPid());
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009169 mWindow->assertNoEvents();
Prabir Pradhan1376fcd2022-01-21 09:56:35 -08009170 spy->assertNoEvents();
9171}
9172
9173TEST_F(InputDispatcherSingleWindowAnr, UnresponsiveMonitorAnr) {
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07009174 mDispatcher->setMonitorDispatchingTimeoutForTest(SPY_TIMEOUT);
Prabir Pradhan1376fcd2022-01-21 09:56:35 -08009175
Prabir Pradhanfb549072023-10-05 19:17:36 +00009176 FakeMonitorReceiver monitor = FakeMonitorReceiver(*mDispatcher, "M_1", ADISPLAY_ID_DEFAULT);
Prabir Pradhan1376fcd2022-01-21 09:56:35 -08009177
9178 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07009179 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
Prabir Pradhan1376fcd2022-01-21 09:56:35 -08009180 WINDOW_LOCATION));
9181
9182 mWindow->consumeMotionDown(ADISPLAY_ID_DEFAULT);
9183 const std::optional<uint32_t> consumeSeq = monitor.receiveEvent();
9184 ASSERT_TRUE(consumeSeq);
9185
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07009186 mFakePolicy->assertNotifyWindowUnresponsiveWasCalled(SPY_TIMEOUT, monitor.getToken(),
9187 MONITOR_PID);
Prabir Pradhan1376fcd2022-01-21 09:56:35 -08009188
9189 monitor.finishEvent(*consumeSeq);
9190 monitor.consumeMotionCancel(ADISPLAY_ID_DEFAULT);
9191
9192 ASSERT_TRUE(mDispatcher->waitForIdle());
Prabir Pradhanedd96402022-02-15 01:46:16 -08009193 mFakePolicy->assertNotifyWindowResponsiveWasCalled(monitor.getToken(), MONITOR_PID);
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009194}
9195
9196// If a window is unresponsive, then you get anr. if the window later catches up and starts to
9197// process events, you don't get an anr. When the window later becomes unresponsive again, you
9198// get an ANR again.
9199// 1. tap -> block on ACTION_UP -> receive ANR
9200// 2. consume all pending events (= queue becomes healthy again)
9201// 3. tap again -> block on ACTION_UP again -> receive ANR second time
9202TEST_F(InputDispatcherSingleWindowAnr, SameWindow_CanReceiveAnrTwice) {
9203 tapOnWindow();
9204
9205 mWindow->consumeMotionDown();
9206 // Block on ACTION_UP
9207 const std::chrono::duration timeout = mWindow->getDispatchingTimeout(DISPATCHING_TIMEOUT);
Prabir Pradhanedd96402022-02-15 01:46:16 -08009208 mFakePolicy->assertNotifyWindowUnresponsiveWasCalled(timeout, mWindow);
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009209 mWindow->consumeMotionUp(); // Now the connection should be healthy again
9210 mDispatcher->waitForIdle();
Prabir Pradhanedd96402022-02-15 01:46:16 -08009211 mFakePolicy->assertNotifyWindowResponsiveWasCalled(mWindow->getToken(), mWindow->getPid());
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009212 mWindow->assertNoEvents();
9213
9214 tapOnWindow();
9215 mWindow->consumeMotionDown();
Prabir Pradhanedd96402022-02-15 01:46:16 -08009216 mFakePolicy->assertNotifyWindowUnresponsiveWasCalled(timeout, mWindow);
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009217 mWindow->consumeMotionUp();
9218
9219 mDispatcher->waitForIdle();
Prabir Pradhanedd96402022-02-15 01:46:16 -08009220 mFakePolicy->assertNotifyWindowResponsiveWasCalled(mWindow->getToken(), mWindow->getPid());
Siarhei Vishniakou234129c2020-10-22 22:28:12 -05009221 mFakePolicy->assertNotifyAnrWasNotCalled();
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009222 mWindow->assertNoEvents();
9223}
9224
Siarhei Vishniakou234129c2020-10-22 22:28:12 -05009225// If a connection remains unresponsive for a while, make sure policy is only notified once about
9226// it.
9227TEST_F(InputDispatcherSingleWindowAnr, Policy_DoesNotGetDuplicateAnr) {
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08009228 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07009229 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009230 WINDOW_LOCATION));
9231
9232 const std::chrono::duration windowTimeout = mWindow->getDispatchingTimeout(DISPATCHING_TIMEOUT);
Prabir Pradhanedd96402022-02-15 01:46:16 -08009233 mFakePolicy->assertNotifyWindowUnresponsiveWasCalled(windowTimeout, mWindow);
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009234 std::this_thread::sleep_for(windowTimeout);
Siarhei Vishniakou234129c2020-10-22 22:28:12 -05009235 // 'notifyConnectionUnresponsive' should only be called once per connection
9236 mFakePolicy->assertNotifyAnrWasNotCalled();
9237 // When the ANR happened, dispatcher should abort the current event stream via ACTION_CANCEL
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009238 mWindow->consumeMotionDown();
Siarhei Vishniakou1ae72f12023-01-29 12:55:30 -08009239 mWindow->consumeMotionEvent(
9240 AllOf(WithMotionAction(ACTION_CANCEL), WithDisplayId(ADISPLAY_ID_DEFAULT)));
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009241 mWindow->assertNoEvents();
Siarhei Vishniakou234129c2020-10-22 22:28:12 -05009242 mDispatcher->waitForIdle();
Prabir Pradhanedd96402022-02-15 01:46:16 -08009243 mFakePolicy->assertNotifyWindowResponsiveWasCalled(mWindow->getToken(), mWindow->getPid());
Siarhei Vishniakou234129c2020-10-22 22:28:12 -05009244 mFakePolicy->assertNotifyAnrWasNotCalled();
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009245}
9246
9247/**
9248 * 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 -07009249 * not get delivered to the focused window until the motion is processed.
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009250 */
9251TEST_F(InputDispatcherSingleWindowAnr, Key_StaysPendingWhileMotionIsProcessed) {
Siarhei Vishniakouef2b4502023-12-28 11:51:47 -08009252 // The timeouts in this test are established by relying on the fact that the "key waiting for
9253 // events timeout" is equal to 500ms.
9254 ASSERT_EQ(mFakePolicy->getKeyWaitingForEventsTimeout(), 500ms);
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009255 mWindow->setDispatchingTimeout(2s); // Set a long ANR timeout to prevent it from triggering
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07009256 mDispatcher->onWindowInfosChanged({{*mWindow->getInfo()}, {}, 0, 0});
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009257
9258 tapOnWindow();
Siarhei Vishniakoud3061ab2023-12-18 20:41:08 -08009259 const auto& [downSequenceNum, downEvent] = mWindow->receiveEvent();
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009260 ASSERT_TRUE(downSequenceNum);
Siarhei Vishniakoud3061ab2023-12-18 20:41:08 -08009261 const auto& [upSequenceNum, upEvent] = mWindow->receiveEvent();
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009262 ASSERT_TRUE(upSequenceNum);
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009263
Siarhei Vishniakouef2b4502023-12-28 11:51:47 -08009264 // Don't finish the events yet, and send a key
9265 mDispatcher->notifyKey(
9266 KeyArgsBuilder(AKEY_EVENT_ACTION_DOWN, AINPUT_SOURCE_KEYBOARD)
9267 .policyFlags(DEFAULT_POLICY_FLAGS | POLICY_FLAG_DISABLE_KEY_REPEAT)
9268 .build());
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009269 // Key will not be sent to the window, yet, because the window is still processing events
9270 // and the key remains pending, waiting for the touch events to be processed
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07009271 // Make sure that `assertNoEvents` doesn't wait too long, because it could cause an ANR.
Siarhei Vishniakouef2b4502023-12-28 11:51:47 -08009272 mWindow->assertNoEvents(100ms);
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009273
Siarhei Vishniakouef2b4502023-12-28 11:51:47 -08009274 std::this_thread::sleep_for(400ms);
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009275 // if we wait long enough though, dispatcher will give up, and still send the key
9276 // to the focused window, even though we have not yet finished the motion event
9277 mWindow->consumeKeyDown(ADISPLAY_ID_DEFAULT);
9278 mWindow->finishEvent(*downSequenceNum);
9279 mWindow->finishEvent(*upSequenceNum);
9280}
9281
9282/**
9283 * If a window is processing a motion event, and then a key event comes in, the key event should
9284 * not go to the focused window until the motion is processed.
9285 * If then a new motion comes in, then the pending key event should be going to the currently
9286 * focused window right away.
9287 */
9288TEST_F(InputDispatcherSingleWindowAnr,
Siarhei Vishniakouef2b4502023-12-28 11:51:47 -08009289 PendingKey_IsDeliveredWhileMotionIsProcessingAndNewTouchComesIn) {
9290 // The timeouts in this test are established by relying on the fact that the "key waiting for
9291 // events timeout" is equal to 500ms.
9292 ASSERT_EQ(mFakePolicy->getKeyWaitingForEventsTimeout(), 500ms);
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009293 mWindow->setDispatchingTimeout(2s); // Set a long ANR timeout to prevent it from triggering
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07009294 mDispatcher->onWindowInfosChanged({{*mWindow->getInfo()}, {}, 0, 0});
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009295
9296 tapOnWindow();
Siarhei Vishniakoud3061ab2023-12-18 20:41:08 -08009297 const auto& [downSequenceNum, _] = mWindow->receiveEvent();
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009298 ASSERT_TRUE(downSequenceNum);
Siarhei Vishniakoud3061ab2023-12-18 20:41:08 -08009299 const auto& [upSequenceNum, upEvent] = mWindow->receiveEvent();
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009300 ASSERT_TRUE(upSequenceNum);
9301 // Don't finish the events yet, and send a key
Siarhei Vishniakou67bf2162023-11-16 13:29:50 -08009302 mDispatcher->notifyKey(
9303 KeyArgsBuilder(AKEY_EVENT_ACTION_DOWN, AINPUT_SOURCE_KEYBOARD)
9304 .policyFlags(DEFAULT_POLICY_FLAGS | POLICY_FLAG_DISABLE_KEY_REPEAT)
9305 .build());
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009306 // At this point, key is still pending, and should not be sent to the application yet.
Siarhei Vishniakouef2b4502023-12-28 11:51:47 -08009307 mWindow->assertNoEvents(100ms);
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009308
9309 // Now tap down again. It should cause the pending key to go to the focused window right away.
9310 tapOnWindow();
Siarhei Vishniakouef2b4502023-12-28 11:51:47 -08009311 // Now that we tapped, we should receive the key immediately.
9312 // Since there's still room for slowness, we use 200ms, which is much less than
9313 // the "key waiting for events' timeout of 500ms minus the already waited 100ms duration.
9314 std::unique_ptr<InputEvent> keyEvent = mWindow->consume(200ms);
9315 ASSERT_NE(nullptr, keyEvent);
9316 ASSERT_EQ(InputEventType::KEY, keyEvent->getType());
9317 ASSERT_THAT(static_cast<KeyEvent&>(*keyEvent), WithKeyAction(AKEY_EVENT_ACTION_DOWN));
9318 // it doesn't matter that we haven't ack'd the other events yet. We can finish events in any
9319 // order.
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009320 mWindow->finishEvent(*downSequenceNum); // first tap's ACTION_DOWN
9321 mWindow->finishEvent(*upSequenceNum); // first tap's ACTION_UP
Siarhei Vishniakou67bf2162023-11-16 13:29:50 -08009322 mWindow->consumeMotionEvent(WithMotionAction(ACTION_DOWN));
9323 mWindow->consumeMotionEvent(WithMotionAction(ACTION_UP));
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009324 mWindow->assertNoEvents();
9325}
9326
Siarhei Vishniakouadb9fc92023-05-26 10:46:09 -07009327/**
9328 * Send an event to the app and have the app not respond right away.
9329 * When ANR is raised, policy will tell the dispatcher to cancel the events for that window.
9330 * So InputDispatcher will enqueue ACTION_CANCEL event as well.
9331 * At some point, the window becomes responsive again.
9332 * Ensure that subsequent events get dropped, and the next gesture is delivered.
9333 */
9334TEST_F(InputDispatcherSingleWindowAnr, TwoGesturesWithAnr) {
9335 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
9336 .pointer(PointerBuilder(0, ToolType::FINGER).x(10).y(10))
9337 .build());
9338
Siarhei Vishniakoud3061ab2023-12-18 20:41:08 -08009339 const auto [sequenceNum, _] = mWindow->receiveEvent(); // ACTION_DOWN
Siarhei Vishniakouadb9fc92023-05-26 10:46:09 -07009340 ASSERT_TRUE(sequenceNum);
9341 const std::chrono::duration timeout = mWindow->getDispatchingTimeout(DISPATCHING_TIMEOUT);
9342 mFakePolicy->assertNotifyWindowUnresponsiveWasCalled(timeout, mWindow);
9343
9344 mWindow->finishEvent(*sequenceNum);
9345 mWindow->consumeMotionEvent(WithMotionAction(ACTION_CANCEL));
9346 ASSERT_TRUE(mDispatcher->waitForIdle());
9347 mFakePolicy->assertNotifyWindowResponsiveWasCalled(mWindow->getToken(), mWindow->getPid());
9348
9349 // Now that the window is responsive, let's continue the gesture.
9350 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN)
9351 .pointer(PointerBuilder(0, ToolType::FINGER).x(11).y(11))
9352 .build());
9353
9354 mDispatcher->notifyMotion(MotionArgsBuilder(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
9355 .pointer(PointerBuilder(0, ToolType::FINGER).x(11).y(11))
9356 .pointer(PointerBuilder(1, ToolType::FINGER).x(3).y(3))
9357 .build());
9358
9359 mDispatcher->notifyMotion(MotionArgsBuilder(POINTER_1_UP, AINPUT_SOURCE_TOUCHSCREEN)
9360 .pointer(PointerBuilder(0, ToolType::FINGER).x(11).y(11))
9361 .pointer(PointerBuilder(1, ToolType::FINGER).x(3).y(3))
9362 .build());
9363 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN)
9364 .pointer(PointerBuilder(0, ToolType::FINGER).x(11).y(11))
9365 .build());
9366 // We already canceled this pointer, so the window shouldn't get any new events.
9367 mWindow->assertNoEvents();
9368
9369 // Start another one.
9370 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
9371 .pointer(PointerBuilder(0, ToolType::FINGER).x(15).y(15))
9372 .build());
9373 mWindow->consumeMotionEvent(WithMotionAction(ACTION_DOWN));
9374}
9375
Prabir Pradhanfc364722024-02-08 17:51:20 +00009376// Send an event to the app and have the app not respond right away. Then remove the app window.
9377// When the window is removed, the dispatcher will cancel the events for that window.
9378// So InputDispatcher will enqueue ACTION_CANCEL event as well.
9379TEST_F(InputDispatcherSingleWindowAnr, AnrAfterWindowRemoval) {
9380 mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_DOWN,
9381 AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
9382 {WINDOW_LOCATION}));
9383
9384 const auto [sequenceNum, _] = mWindow->receiveEvent(); // ACTION_DOWN
9385 ASSERT_TRUE(sequenceNum);
9386
9387 // Remove the window, but the input channel should remain alive.
9388 mDispatcher->onWindowInfosChanged({{}, {}, 0, 0});
9389
9390 const std::chrono::duration timeout = mWindow->getDispatchingTimeout(DISPATCHING_TIMEOUT);
9391 // Since the window was removed, Dispatcher does not know the PID associated with the window
9392 // anymore, so the policy is notified without the PID.
9393 mFakePolicy->assertNotifyWindowUnresponsiveWasCalled(timeout, mWindow->getToken(),
9394 /*pid=*/std::nullopt);
9395
9396 mWindow->finishEvent(*sequenceNum);
9397 // The cancellation was generated when the window was removed, along with the focus event.
9398 mWindow->consumeMotionEvent(
9399 AllOf(WithMotionAction(ACTION_CANCEL), WithDisplayId(ADISPLAY_ID_DEFAULT)));
9400 mWindow->consumeFocusEvent(false);
9401 ASSERT_TRUE(mDispatcher->waitForIdle());
9402 mFakePolicy->assertNotifyWindowResponsiveWasCalled(mWindow->getToken(), /*pid=*/std::nullopt);
9403}
9404
9405// Send an event to the app and have the app not respond right away. Wait for the policy to be
9406// notified of the unresponsive window, then remove the app window.
9407TEST_F(InputDispatcherSingleWindowAnr, AnrFollowedByWindowRemoval) {
9408 mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_DOWN,
9409 AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
9410 {WINDOW_LOCATION}));
9411
9412 const auto [sequenceNum, _] = mWindow->receiveEvent(); // ACTION_DOWN
9413 ASSERT_TRUE(sequenceNum);
9414 const std::chrono::duration timeout = mWindow->getDispatchingTimeout(DISPATCHING_TIMEOUT);
9415 mFakePolicy->assertNotifyWindowUnresponsiveWasCalled(timeout, mWindow);
9416
9417 // Remove the window, but the input channel should remain alive.
9418 mDispatcher->onWindowInfosChanged({{}, {}, 0, 0});
9419
9420 mWindow->finishEvent(*sequenceNum);
9421 // The cancellation was generated during the ANR, and the window lost focus when it was removed.
9422 mWindow->consumeMotionEvent(
9423 AllOf(WithMotionAction(ACTION_CANCEL), WithDisplayId(ADISPLAY_ID_DEFAULT)));
9424 mWindow->consumeFocusEvent(false);
9425 ASSERT_TRUE(mDispatcher->waitForIdle());
9426 // Since the window was removed, Dispatcher does not know the PID associated with the window
9427 // becoming responsive, so the policy is notified without the PID.
9428 mFakePolicy->assertNotifyWindowResponsiveWasCalled(mWindow->getToken(), /*pid=*/std::nullopt);
9429}
9430
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009431class InputDispatcherMultiWindowAnr : public InputDispatcherTest {
9432 virtual void SetUp() override {
9433 InputDispatcherTest::SetUp();
9434
Chris Yea209fde2020-07-22 13:54:51 -07009435 mApplication = std::make_shared<FakeApplicationHandle>();
Siarhei Vishniakouf83c6932023-07-07 17:48:10 -07009436 mApplication->setDispatchingTimeout(100ms);
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07009437 mUnfocusedWindow = sp<FakeWindowHandle>::make(mApplication, mDispatcher, "Unfocused",
9438 ADISPLAY_ID_DEFAULT);
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009439 mUnfocusedWindow->setFrame(Rect(0, 0, 30, 30));
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009440 // Adding FLAG_WATCH_OUTSIDE_TOUCH to receive ACTION_OUTSIDE when another window is tapped
Prabir Pradhan4d5c52f2022-01-31 08:52:10 -08009441 mUnfocusedWindow->setWatchOutsideTouch(true);
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009442
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07009443 mFocusedWindow = sp<FakeWindowHandle>::make(mApplication, mDispatcher, "Focused",
9444 ADISPLAY_ID_DEFAULT);
Siarhei Vishniakouf83c6932023-07-07 17:48:10 -07009445 mFocusedWindow->setDispatchingTimeout(100ms);
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009446 mFocusedWindow->setFrame(Rect(50, 50, 100, 100));
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009447
9448 // Set focused application.
9449 mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, mApplication);
Vishnu Nair47074b82020-08-14 11:54:47 -07009450 mFocusedWindow->setFocusable(true);
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009451
9452 // Expect one focus window exist in display.
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07009453 mDispatcher->onWindowInfosChanged(
9454 {{*mUnfocusedWindow->getInfo(), *mFocusedWindow->getInfo()}, {}, 0, 0});
Vishnu Nair958da932020-08-21 17:12:37 -07009455 setFocusedWindow(mFocusedWindow);
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009456 mFocusedWindow->consumeFocusEvent(true);
9457 }
9458
9459 virtual void TearDown() override {
9460 InputDispatcherTest::TearDown();
9461
9462 mUnfocusedWindow.clear();
9463 mFocusedWindow.clear();
9464 }
9465
9466protected:
Chris Yea209fde2020-07-22 13:54:51 -07009467 std::shared_ptr<FakeApplicationHandle> mApplication;
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009468 sp<FakeWindowHandle> mUnfocusedWindow;
9469 sp<FakeWindowHandle> mFocusedWindow;
9470 static constexpr PointF UNFOCUSED_WINDOW_LOCATION = {20, 20};
9471 static constexpr PointF FOCUSED_WINDOW_LOCATION = {75, 75};
9472 static constexpr PointF LOCATION_OUTSIDE_ALL_WINDOWS = {40, 40};
9473
9474 void tapOnFocusedWindow() { tap(FOCUSED_WINDOW_LOCATION); }
9475
9476 void tapOnUnfocusedWindow() { tap(UNFOCUSED_WINDOW_LOCATION); }
9477
9478private:
9479 void tap(const PointF& location) {
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08009480 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07009481 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009482 location));
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08009483 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07009484 injectMotionUp(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009485 location));
9486 }
9487};
9488
9489// If we have 2 windows that are both unresponsive, the one with the shortest timeout
9490// should be ANR'd first.
9491TEST_F(InputDispatcherMultiWindowAnr, TwoWindows_BothUnresponsive) {
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08009492 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakou2899c552023-07-10 18:20:46 -07009493 injectMotionEvent(*mDispatcher,
9494 MotionEventBuilder(AMOTION_EVENT_ACTION_DOWN,
9495 AINPUT_SOURCE_TOUCHSCREEN)
9496 .pointer(PointerBuilder(0, ToolType::FINGER)
9497 .x(FOCUSED_WINDOW_LOCATION.x)
9498 .y(FOCUSED_WINDOW_LOCATION.y))
9499 .build()));
9500 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
9501 injectMotionEvent(*mDispatcher,
9502 MotionEventBuilder(AMOTION_EVENT_ACTION_UP,
9503 AINPUT_SOURCE_TOUCHSCREEN)
9504 .pointer(PointerBuilder(0, ToolType::FINGER)
9505 .x(FOCUSED_WINDOW_LOCATION.x)
9506 .y(FOCUSED_WINDOW_LOCATION.y))
9507 .build()));
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009508 mFocusedWindow->consumeMotionDown();
Siarhei Vishniakou2899c552023-07-10 18:20:46 -07009509 mFocusedWindow->consumeMotionUp();
Prabir Pradhan7662a8d2023-12-15 01:58:14 +00009510 mUnfocusedWindow->consumeMotionOutside(ADISPLAY_ID_DEFAULT, /*flags=*/0);
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009511 // We consumed all events, so no ANR
9512 ASSERT_TRUE(mDispatcher->waitForIdle());
9513 mFakePolicy->assertNotifyAnrWasNotCalled();
9514
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08009515 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakou2899c552023-07-10 18:20:46 -07009516 injectMotionEvent(*mDispatcher,
9517 MotionEventBuilder(AMOTION_EVENT_ACTION_DOWN,
9518 AINPUT_SOURCE_TOUCHSCREEN)
9519 .pointer(PointerBuilder(0, ToolType::FINGER)
9520 .x(FOCUSED_WINDOW_LOCATION.x)
9521 .y(FOCUSED_WINDOW_LOCATION.y))
9522 .build()));
Siarhei Vishniakoud3061ab2023-12-18 20:41:08 -08009523 const auto [unfocusedSequenceNum, _] = mUnfocusedWindow->receiveEvent();
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009524 ASSERT_TRUE(unfocusedSequenceNum);
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009525
9526 const std::chrono::duration timeout =
9527 mFocusedWindow->getDispatchingTimeout(DISPATCHING_TIMEOUT);
Prabir Pradhanedd96402022-02-15 01:46:16 -08009528 mFakePolicy->assertNotifyWindowUnresponsiveWasCalled(timeout, mFocusedWindow);
Siarhei Vishniakou2899c552023-07-10 18:20:46 -07009529
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009530 mUnfocusedWindow->finishEvent(*unfocusedSequenceNum);
Siarhei Vishniakou234129c2020-10-22 22:28:12 -05009531 mFocusedWindow->consumeMotionDown();
9532 // This cancel is generated because the connection was unresponsive
9533 mFocusedWindow->consumeMotionCancel();
9534 mFocusedWindow->assertNoEvents();
9535 mUnfocusedWindow->assertNoEvents();
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009536 ASSERT_TRUE(mDispatcher->waitForIdle());
Prabir Pradhanedd96402022-02-15 01:46:16 -08009537 mFakePolicy->assertNotifyWindowResponsiveWasCalled(mFocusedWindow->getToken(),
9538 mFocusedWindow->getPid());
Siarhei Vishniakou234129c2020-10-22 22:28:12 -05009539 mFakePolicy->assertNotifyAnrWasNotCalled();
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009540}
9541
9542// If we have 2 windows with identical timeouts that are both unresponsive,
9543// it doesn't matter which order they should have ANR.
9544// But we should receive ANR for both.
9545TEST_F(InputDispatcherMultiWindowAnr, TwoWindows_BothUnresponsiveWithSameTimeout) {
9546 // Set the timeout for unfocused window to match the focused window
Siarhei Vishniakouf83c6932023-07-07 17:48:10 -07009547 mUnfocusedWindow->setDispatchingTimeout(
9548 mFocusedWindow->getDispatchingTimeout(DISPATCHING_TIMEOUT));
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07009549 mDispatcher->onWindowInfosChanged(
9550 {{*mUnfocusedWindow->getInfo(), *mFocusedWindow->getInfo()}, {}, 0, 0});
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009551
9552 tapOnFocusedWindow();
9553 // we should have ACTION_DOWN/ACTION_UP on focused window and ACTION_OUTSIDE on unfocused window
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009554 // We don't know which window will ANR first. But both of them should happen eventually.
Siarhei Vishniakouf83c6932023-07-07 17:48:10 -07009555 std::array<sp<IBinder>, 2> anrConnectionTokens = {mFakePolicy->getUnresponsiveWindowToken(
9556 mFocusedWindow->getDispatchingTimeout(
9557 DISPATCHING_TIMEOUT)),
9558 mFakePolicy->getUnresponsiveWindowToken(0ms)};
9559
9560 ASSERT_THAT(anrConnectionTokens,
9561 ::testing::UnorderedElementsAre(testing::Eq(mFocusedWindow->getToken()),
9562 testing::Eq(mUnfocusedWindow->getToken())));
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009563
9564 ASSERT_TRUE(mDispatcher->waitForIdle());
9565 mFakePolicy->assertNotifyAnrWasNotCalled();
Siarhei Vishniakou234129c2020-10-22 22:28:12 -05009566
9567 mFocusedWindow->consumeMotionDown();
9568 mFocusedWindow->consumeMotionUp();
9569 mUnfocusedWindow->consumeMotionOutside();
9570
Siarhei Vishniakouf83c6932023-07-07 17:48:10 -07009571 std::array<sp<IBinder>, 2> responsiveTokens = {mFakePolicy->getResponsiveWindowToken(),
9572 mFakePolicy->getResponsiveWindowToken()};
Siarhei Vishniakou234129c2020-10-22 22:28:12 -05009573
9574 // Both applications should be marked as responsive, in any order
Siarhei Vishniakouf83c6932023-07-07 17:48:10 -07009575 ASSERT_THAT(responsiveTokens,
9576 ::testing::UnorderedElementsAre(testing::Eq(mFocusedWindow->getToken()),
9577 testing::Eq(mUnfocusedWindow->getToken())));
Siarhei Vishniakou234129c2020-10-22 22:28:12 -05009578 mFakePolicy->assertNotifyAnrWasNotCalled();
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009579}
9580
9581// If a window is already not responding, the second tap on the same window should be ignored.
9582// We should also log an error to account for the dropped event (not tested here).
9583// At the same time, FLAG_WATCH_OUTSIDE_TOUCH targets should not receive any events.
9584TEST_F(InputDispatcherMultiWindowAnr, DuringAnr_SecondTapIsIgnored) {
9585 tapOnFocusedWindow();
Prabir Pradhan7662a8d2023-12-15 01:58:14 +00009586 mUnfocusedWindow->consumeMotionOutside(ADISPLAY_ID_DEFAULT, /*flags=*/0);
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009587 // Receive the events, but don't respond
Siarhei Vishniakoud3061ab2023-12-18 20:41:08 -08009588 const auto [downEventSequenceNum, downEvent] = mFocusedWindow->receiveEvent(); // ACTION_DOWN
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009589 ASSERT_TRUE(downEventSequenceNum);
Siarhei Vishniakoud3061ab2023-12-18 20:41:08 -08009590 const auto [upEventSequenceNum, upEvent] = mFocusedWindow->receiveEvent(); // ACTION_UP
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009591 ASSERT_TRUE(upEventSequenceNum);
9592 const std::chrono::duration timeout =
9593 mFocusedWindow->getDispatchingTimeout(DISPATCHING_TIMEOUT);
Prabir Pradhanedd96402022-02-15 01:46:16 -08009594 mFakePolicy->assertNotifyWindowUnresponsiveWasCalled(timeout, mFocusedWindow);
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009595
9596 // Tap once again
9597 // We cannot use "tapOnFocusedWindow" because it asserts the injection result to be success
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08009598 ASSERT_EQ(InputEventInjectionResult::FAILED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07009599 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009600 FOCUSED_WINDOW_LOCATION));
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08009601 ASSERT_EQ(InputEventInjectionResult::FAILED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07009602 injectMotionUp(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009603 FOCUSED_WINDOW_LOCATION));
9604 // Unfocused window does not receive ACTION_OUTSIDE because the tapped window is not a
9605 // valid touch target
9606 mUnfocusedWindow->assertNoEvents();
9607
9608 // Consume the first tap
9609 mFocusedWindow->finishEvent(*downEventSequenceNum);
9610 mFocusedWindow->finishEvent(*upEventSequenceNum);
9611 ASSERT_TRUE(mDispatcher->waitForIdle());
9612 // The second tap did not go to the focused window
9613 mFocusedWindow->assertNoEvents();
Siarhei Vishniakou234129c2020-10-22 22:28:12 -05009614 // Since all events are finished, connection should be deemed healthy again
Prabir Pradhanedd96402022-02-15 01:46:16 -08009615 mFakePolicy->assertNotifyWindowResponsiveWasCalled(mFocusedWindow->getToken(),
9616 mFocusedWindow->getPid());
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009617 mFakePolicy->assertNotifyAnrWasNotCalled();
9618}
9619
9620// If you tap outside of all windows, there will not be ANR
9621TEST_F(InputDispatcherMultiWindowAnr, TapOutsideAllWindows_DoesNotAnr) {
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08009622 ASSERT_EQ(InputEventInjectionResult::FAILED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07009623 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009624 LOCATION_OUTSIDE_ALL_WINDOWS));
9625 ASSERT_TRUE(mDispatcher->waitForIdle());
9626 mFakePolicy->assertNotifyAnrWasNotCalled();
9627}
9628
9629// Since the focused window is paused, tapping on it should not produce any events
9630TEST_F(InputDispatcherMultiWindowAnr, Window_CanBePaused) {
9631 mFocusedWindow->setPaused(true);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07009632 mDispatcher->onWindowInfosChanged(
9633 {{*mUnfocusedWindow->getInfo(), *mFocusedWindow->getInfo()}, {}, 0, 0});
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009634
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08009635 ASSERT_EQ(InputEventInjectionResult::FAILED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07009636 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009637 FOCUSED_WINDOW_LOCATION));
9638
9639 std::this_thread::sleep_for(mFocusedWindow->getDispatchingTimeout(DISPATCHING_TIMEOUT));
9640 ASSERT_TRUE(mDispatcher->waitForIdle());
9641 // Should not ANR because the window is paused, and touches shouldn't go to it
9642 mFakePolicy->assertNotifyAnrWasNotCalled();
9643
9644 mFocusedWindow->assertNoEvents();
9645 mUnfocusedWindow->assertNoEvents();
9646}
9647
9648/**
9649 * 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 -07009650 * not get delivered to the focused window until the motion is processed.
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009651 * If a different window becomes focused at this time, the key should go to that window instead.
9652 *
9653 * Warning!!!
9654 * This test depends on the value of android::inputdispatcher::KEY_WAITING_FOR_MOTION_TIMEOUT
9655 * and the injection timeout that we specify when injecting the key.
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07009656 * We must have the injection timeout (100ms) be smaller than
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009657 * KEY_WAITING_FOR_MOTION_TIMEOUT (currently 500ms).
9658 *
9659 * If that value changes, this test should also change.
9660 */
9661TEST_F(InputDispatcherMultiWindowAnr, PendingKey_GoesToNewlyFocusedWindow) {
9662 // Set a long ANR timeout to prevent it from triggering
9663 mFocusedWindow->setDispatchingTimeout(2s);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07009664 mDispatcher->onWindowInfosChanged(
9665 {{*mFocusedWindow->getInfo(), *mUnfocusedWindow->getInfo()}, {}, 0, 0});
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009666
9667 tapOnUnfocusedWindow();
Siarhei Vishniakoud3061ab2023-12-18 20:41:08 -08009668 const auto [downSequenceNum, downEvent] = mUnfocusedWindow->receiveEvent();
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009669 ASSERT_TRUE(downSequenceNum);
Siarhei Vishniakoud3061ab2023-12-18 20:41:08 -08009670 const auto [upSequenceNum, upEvent] = mUnfocusedWindow->receiveEvent();
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009671 ASSERT_TRUE(upSequenceNum);
9672 // Don't finish the events yet, and send a key
9673 // Injection will succeed because we will eventually give up and send the key to the focused
9674 // window even if motions are still being processed.
9675
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08009676 InputEventInjectionResult result =
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07009677 injectKey(*mDispatcher, AKEY_EVENT_ACTION_DOWN, /*repeatCount=*/0, ADISPLAY_ID_DEFAULT,
9678 InputEventInjectionSync::NONE, /*injectionTimeout=*/100ms);
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08009679 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, result);
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009680 // Key will not be sent to the window, yet, because the window is still processing events
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07009681 // and the key remains pending, waiting for the touch events to be processed.
9682 // Make sure `assertNoEvents` doesn't take too long. It uses CONSUME_TIMEOUT_NO_EVENT_EXPECTED
9683 // under the hood.
9684 static_assert(CONSUME_TIMEOUT_NO_EVENT_EXPECTED < 100ms);
9685 mFocusedWindow->assertNoEvents();
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009686
9687 // Switch the focus to the "unfocused" window that we tapped. Expect the key to go there
Vishnu Nair47074b82020-08-14 11:54:47 -07009688 mFocusedWindow->setFocusable(false);
9689 mUnfocusedWindow->setFocusable(true);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07009690 mDispatcher->onWindowInfosChanged(
9691 {{*mFocusedWindow->getInfo(), *mUnfocusedWindow->getInfo()}, {}, 0, 0});
Vishnu Nair958da932020-08-21 17:12:37 -07009692 setFocusedWindow(mUnfocusedWindow);
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009693
9694 // Focus events should precede the key events
9695 mUnfocusedWindow->consumeFocusEvent(true);
9696 mFocusedWindow->consumeFocusEvent(false);
9697
9698 // Finish the tap events, which should unblock dispatcher
9699 mUnfocusedWindow->finishEvent(*downSequenceNum);
9700 mUnfocusedWindow->finishEvent(*upSequenceNum);
9701
9702 // Now that all queues are cleared and no backlog in the connections, the key event
9703 // can finally go to the newly focused "mUnfocusedWindow".
9704 mUnfocusedWindow->consumeKeyDown(ADISPLAY_ID_DEFAULT);
9705 mFocusedWindow->assertNoEvents();
9706 mUnfocusedWindow->assertNoEvents();
Siarhei Vishniakou234129c2020-10-22 22:28:12 -05009707 mFakePolicy->assertNotifyAnrWasNotCalled();
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009708}
9709
9710// When the touch stream is split across 2 windows, and one of them does not respond,
9711// then ANR should be raised and the touch should be canceled for the unresponsive window.
9712// The other window should not be affected by that.
9713TEST_F(InputDispatcherMultiWindowAnr, SplitTouch_SingleWindowAnr) {
9714 // Touch Window 1
Prabir Pradhan678438e2023-04-13 19:32:51 +00009715 mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_DOWN,
9716 AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
9717 {FOCUSED_WINDOW_LOCATION}));
Prabir Pradhan7662a8d2023-12-15 01:58:14 +00009718 mUnfocusedWindow->consumeMotionOutside(ADISPLAY_ID_DEFAULT, /*flags=*/0);
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009719
9720 // Touch Window 2
Prabir Pradhan678438e2023-04-13 19:32:51 +00009721 mDispatcher->notifyMotion(
9722 generateMotionArgs(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
9723 {FOCUSED_WINDOW_LOCATION, UNFOCUSED_WINDOW_LOCATION}));
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009724
9725 const std::chrono::duration timeout =
9726 mFocusedWindow->getDispatchingTimeout(DISPATCHING_TIMEOUT);
Prabir Pradhanedd96402022-02-15 01:46:16 -08009727 mFakePolicy->assertNotifyWindowUnresponsiveWasCalled(timeout, mFocusedWindow);
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009728
9729 mUnfocusedWindow->consumeMotionDown();
9730 mFocusedWindow->consumeMotionDown();
9731 // Focused window may or may not receive ACTION_MOVE
9732 // But it should definitely receive ACTION_CANCEL due to the ANR
Siarhei Vishniakoud3061ab2023-12-18 20:41:08 -08009733 const auto [moveOrCancelSequenceNum, event] = mFocusedWindow->receiveEvent();
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009734 ASSERT_TRUE(moveOrCancelSequenceNum);
9735 mFocusedWindow->finishEvent(*moveOrCancelSequenceNum);
9736 ASSERT_NE(nullptr, event);
Siarhei Vishniakou63b63612023-04-12 11:00:23 -07009737 ASSERT_EQ(event->getType(), InputEventType::MOTION);
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009738 MotionEvent& motionEvent = static_cast<MotionEvent&>(*event);
9739 if (motionEvent.getAction() == AMOTION_EVENT_ACTION_MOVE) {
9740 mFocusedWindow->consumeMotionCancel();
9741 } else {
9742 ASSERT_EQ(AMOTION_EVENT_ACTION_CANCEL, motionEvent.getAction());
9743 }
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009744 ASSERT_TRUE(mDispatcher->waitForIdle());
Prabir Pradhanedd96402022-02-15 01:46:16 -08009745 mFakePolicy->assertNotifyWindowResponsiveWasCalled(mFocusedWindow->getToken(),
9746 mFocusedWindow->getPid());
Siarhei Vishniakou234129c2020-10-22 22:28:12 -05009747
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009748 mUnfocusedWindow->assertNoEvents();
9749 mFocusedWindow->assertNoEvents();
Siarhei Vishniakou234129c2020-10-22 22:28:12 -05009750 mFakePolicy->assertNotifyAnrWasNotCalled();
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009751}
9752
Siarhei Vishniakouf56b2692020-09-08 19:43:33 -05009753/**
9754 * If we have no focused window, and a key comes in, we start the ANR timer.
9755 * The focused application should add a focused window before the timer runs out to prevent ANR.
9756 *
9757 * If the user touches another application during this time, the key should be dropped.
9758 * Next, if a new focused window comes in, without toggling the focused application,
9759 * then no ANR should occur.
9760 *
9761 * Normally, we would expect the new focused window to be accompanied by 'setFocusedApplication',
9762 * but in some cases the policy may not update the focused application.
9763 */
9764TEST_F(InputDispatcherMultiWindowAnr, FocusedWindowWithoutSetFocusedApplication_NoAnr) {
9765 std::shared_ptr<FakeApplicationHandle> focusedApplication =
9766 std::make_shared<FakeApplicationHandle>();
Siarhei Vishniakouc033dfb2023-10-03 10:45:16 -07009767 focusedApplication->setDispatchingTimeout(300ms);
Siarhei Vishniakouf56b2692020-09-08 19:43:33 -05009768 mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, focusedApplication);
9769 // The application that owns 'mFocusedWindow' and 'mUnfocusedWindow' is not focused.
9770 mFocusedWindow->setFocusable(false);
9771
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07009772 mDispatcher->onWindowInfosChanged(
9773 {{*mFocusedWindow->getInfo(), *mUnfocusedWindow->getInfo()}, {}, 0, 0});
Siarhei Vishniakouf56b2692020-09-08 19:43:33 -05009774 mFocusedWindow->consumeFocusEvent(false);
9775
9776 // Send a key. The ANR timer should start because there is no focused window.
9777 // 'focusedApplication' will get blamed if this timer completes.
9778 // Key will not be sent anywhere because we have no focused window. It will remain pending.
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08009779 InputEventInjectionResult result =
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07009780 injectKey(*mDispatcher, AKEY_EVENT_ACTION_DOWN, /*repeatCount=*/0, ADISPLAY_ID_DEFAULT,
9781 InputEventInjectionSync::NONE, /*injectionTimeout=*/100ms,
Harry Cutts33476232023-01-30 19:57:29 +00009782 /*allowKeyRepeat=*/false);
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08009783 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, result);
Siarhei Vishniakouf56b2692020-09-08 19:43:33 -05009784
9785 // Wait until dispatcher starts the "no focused window" timer. If we don't wait here,
9786 // then the injected touches won't cause the focused event to get dropped.
9787 // The dispatcher only checks for whether the queue should be pruned upon queueing.
9788 // If we inject the touch right away and the ANR timer hasn't started, the touch event would
9789 // simply be added to the queue without 'shouldPruneInboundQueueLocked' returning 'true'.
9790 // For this test, it means that the key would get delivered to the window once it becomes
9791 // focused.
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07009792 std::this_thread::sleep_for(100ms);
Siarhei Vishniakouf56b2692020-09-08 19:43:33 -05009793
9794 // Touch unfocused window. This should force the pending key to get dropped.
Prabir Pradhan678438e2023-04-13 19:32:51 +00009795 mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_DOWN,
9796 AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
9797 {UNFOCUSED_WINDOW_LOCATION}));
Siarhei Vishniakouf56b2692020-09-08 19:43:33 -05009798
9799 // We do not consume the motion right away, because that would require dispatcher to first
9800 // process (== drop) the key event, and by that time, ANR will be raised.
9801 // Set the focused window first.
9802 mFocusedWindow->setFocusable(true);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07009803 mDispatcher->onWindowInfosChanged(
9804 {{*mFocusedWindow->getInfo(), *mUnfocusedWindow->getInfo()}, {}, 0, 0});
Siarhei Vishniakouf56b2692020-09-08 19:43:33 -05009805 setFocusedWindow(mFocusedWindow);
9806 mFocusedWindow->consumeFocusEvent(true);
9807 // We do not call "setFocusedApplication" here, even though the newly focused window belongs
9808 // to another application. This could be a bug / behaviour in the policy.
9809
9810 mUnfocusedWindow->consumeMotionDown();
9811
9812 ASSERT_TRUE(mDispatcher->waitForIdle());
9813 // Should not ANR because we actually have a focused window. It was just added too slowly.
9814 ASSERT_NO_FATAL_FAILURE(mFakePolicy->assertNotifyAnrWasNotCalled());
9815}
9816
Siarhei Vishniakou99e407b2023-12-26 18:09:32 -08009817/**
9818 * If we are pruning input queue, we should never drop pointer events. Otherwise, we risk having
9819 * an inconsistent event stream inside the dispatcher. In this test, we make sure that the
9820 * dispatcher doesn't prune pointer events incorrectly.
9821 *
9822 * This test reproduces a crash in InputDispatcher.
9823 * To reproduce the crash, we need to simulate the conditions for "pruning input queue" to occur.
9824 *
9825 * Keep the currently focused application (mApplication), and have no focused window.
9826 * We set up two additional windows:
9827 * 1) The navigation bar window. This simulates the system "NavigationBar", which is used in the
9828 * 3-button navigation mode. This window injects a BACK button when it's touched. 2) The application
9829 * window. This window is not focusable, but is touchable.
9830 *
9831 * We first touch the navigation bar, which causes it to inject a key. Since there's no focused
9832 * window, the dispatcher doesn't process this key, and all other events inside dispatcher are now
9833 * blocked. The dispatcher is waiting for 'mApplication' to add a focused window.
9834 *
9835 * Now, we touch "Another window". This window is owned by a different application than
9836 * 'mApplication'. This causes the dispatcher to stop waiting for 'mApplication' to add a focused
9837 * window. Now, the "pruning input queue" behaviour should kick in, and the dispatcher should start
9838 * dropping the events from its queue. Ensure that no crash occurs.
9839 *
9840 * In this test, we are setting long timeouts to prevent ANRs and events dropped due to being stale.
9841 * This does not affect the test running time.
9842 */
9843TEST_F(InputDispatcherMultiWindowAnr, PruningInputQueueShouldNotDropPointerEvents) {
9844 std::shared_ptr<FakeApplicationHandle> systemUiApplication =
9845 std::make_shared<FakeApplicationHandle>();
9846 systemUiApplication->setDispatchingTimeout(3000ms);
9847 mFakePolicy->setStaleEventTimeout(3000ms);
9848 sp<FakeWindowHandle> navigationBar =
9849 sp<FakeWindowHandle>::make(systemUiApplication, mDispatcher, "NavigationBar",
9850 ADISPLAY_ID_DEFAULT);
9851 navigationBar->setFocusable(false);
9852 navigationBar->setWatchOutsideTouch(true);
9853 navigationBar->setFrame(Rect(0, 0, 100, 100));
9854
9855 mApplication->setDispatchingTimeout(3000ms);
9856 // 'mApplication' is already focused, but we call it again here to make it explicit.
9857 mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, mApplication);
9858
9859 std::shared_ptr<FakeApplicationHandle> anotherApplication =
9860 std::make_shared<FakeApplicationHandle>();
9861 sp<FakeWindowHandle> appWindow =
9862 sp<FakeWindowHandle>::make(anotherApplication, mDispatcher, "Another window",
9863 ADISPLAY_ID_DEFAULT);
9864 appWindow->setFocusable(false);
9865 appWindow->setFrame(Rect(100, 100, 200, 200));
9866
9867 mDispatcher->onWindowInfosChanged(
9868 {{*navigationBar->getInfo(), *appWindow->getInfo()}, {}, 0, 0});
9869 // 'mFocusedWindow' is no longer in the dispatcher window list, and therefore loses focus
9870 mFocusedWindow->consumeFocusEvent(false);
9871
9872 // Touch down the navigation bar. It consumes the touch and injects a key into the dispatcher
9873 // in response.
9874 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
9875 .pointer(PointerBuilder(0, ToolType::FINGER).x(50).y(50))
9876 .build());
9877 navigationBar->consumeMotionEvent(WithMotionAction(ACTION_DOWN));
9878
9879 // Key will not be sent anywhere because we have no focused window. It will remain pending.
9880 // Pretend we are injecting KEYCODE_BACK, but it doesn't actually matter what key it is.
9881 InputEventInjectionResult result =
9882 injectKey(*mDispatcher, AKEY_EVENT_ACTION_DOWN, /*repeatCount=*/0, ADISPLAY_ID_DEFAULT,
9883 InputEventInjectionSync::NONE, /*injectionTimeout=*/100ms,
9884 /*allowKeyRepeat=*/false);
9885 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, result);
9886
9887 // Finish the gesture - lift up finger and inject ACTION_UP key event
9888 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN)
9889 .pointer(PointerBuilder(0, ToolType::FINGER).x(50).y(50))
9890 .build());
9891 result = injectKey(*mDispatcher, AKEY_EVENT_ACTION_UP, /*repeatCount=*/0, ADISPLAY_ID_DEFAULT,
9892 InputEventInjectionSync::NONE, /*injectionTimeout=*/100ms,
9893 /*allowKeyRepeat=*/false);
9894 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, result);
9895 // The key that was injected is blocking the dispatcher, so the navigation bar shouldn't be
9896 // getting any events yet.
9897 navigationBar->assertNoEvents();
9898
9899 // Now touch "Another window". This touch is going to a different application than the one we
9900 // are waiting for (which is 'mApplication').
9901 // This should cause the dispatcher to drop the pending focus-dispatched events (like the key
9902 // trying to be injected) and to continue processing the rest of the events in the original
9903 // order.
9904 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
9905 .pointer(PointerBuilder(0, ToolType::FINGER).x(150).y(150))
9906 .build());
9907 navigationBar->consumeMotionEvent(WithMotionAction(ACTION_UP));
9908 navigationBar->consumeMotionEvent(WithMotionAction(ACTION_OUTSIDE));
9909 appWindow->consumeMotionEvent(WithMotionAction(ACTION_DOWN));
9910
9911 appWindow->assertNoEvents();
9912 navigationBar->assertNoEvents();
9913}
9914
Siarhei Vishniakoua2862a02020-07-20 16:36:46 -05009915// These tests ensure we cannot send touch events to a window that's positioned behind a window
9916// that has feature NO_INPUT_CHANNEL.
9917// Layout:
9918// Top (closest to user)
9919// mNoInputWindow (above all windows)
9920// mBottomWindow
9921// Bottom (furthest from user)
9922class InputDispatcherMultiWindowOcclusionTests : public InputDispatcherTest {
9923 virtual void SetUp() override {
9924 InputDispatcherTest::SetUp();
9925
9926 mApplication = std::make_shared<FakeApplicationHandle>();
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07009927 mNoInputWindow =
9928 sp<FakeWindowHandle>::make(mApplication, mDispatcher,
9929 "Window without input channel", ADISPLAY_ID_DEFAULT,
Prabir Pradhane7cc69c2024-01-05 21:35:28 +00009930 /*createInputChannel=*/false);
Prabir Pradhan51e7db02022-02-07 06:02:57 -08009931 mNoInputWindow->setNoInputChannel(true);
Siarhei Vishniakoua2862a02020-07-20 16:36:46 -05009932 mNoInputWindow->setFrame(Rect(0, 0, 100, 100));
9933 // It's perfectly valid for this window to not have an associated input channel
9934
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07009935 mBottomWindow = sp<FakeWindowHandle>::make(mApplication, mDispatcher, "Bottom window",
9936 ADISPLAY_ID_DEFAULT);
Siarhei Vishniakoua2862a02020-07-20 16:36:46 -05009937 mBottomWindow->setFrame(Rect(0, 0, 100, 100));
9938
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07009939 mDispatcher->onWindowInfosChanged(
9940 {{*mNoInputWindow->getInfo(), *mBottomWindow->getInfo()}, {}, 0, 0});
Siarhei Vishniakoua2862a02020-07-20 16:36:46 -05009941 }
9942
9943protected:
9944 std::shared_ptr<FakeApplicationHandle> mApplication;
9945 sp<FakeWindowHandle> mNoInputWindow;
9946 sp<FakeWindowHandle> mBottomWindow;
9947};
9948
9949TEST_F(InputDispatcherMultiWindowOcclusionTests, NoInputChannelFeature_DropsTouches) {
9950 PointF touchedPoint = {10, 10};
9951
Prabir Pradhan678438e2023-04-13 19:32:51 +00009952 mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_DOWN,
9953 AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
9954 {touchedPoint}));
Siarhei Vishniakoua2862a02020-07-20 16:36:46 -05009955
9956 mNoInputWindow->assertNoEvents();
9957 // Even though the window 'mNoInputWindow' positioned above 'mBottomWindow' does not have
9958 // an input channel, it is not marked as FLAG_NOT_TOUCHABLE,
9959 // and therefore should prevent mBottomWindow from receiving touches
9960 mBottomWindow->assertNoEvents();
9961}
9962
9963/**
9964 * If a window has feature NO_INPUT_CHANNEL, and somehow (by mistake) still has an input channel,
9965 * ensure that this window does not receive any touches, and blocks touches to windows underneath.
9966 */
9967TEST_F(InputDispatcherMultiWindowOcclusionTests,
9968 NoInputChannelFeature_DropsTouchesWithValidChannel) {
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07009969 mNoInputWindow = sp<FakeWindowHandle>::make(mApplication, mDispatcher,
9970 "Window with input channel and NO_INPUT_CHANNEL",
9971 ADISPLAY_ID_DEFAULT);
Siarhei Vishniakoua2862a02020-07-20 16:36:46 -05009972
Prabir Pradhan51e7db02022-02-07 06:02:57 -08009973 mNoInputWindow->setNoInputChannel(true);
Siarhei Vishniakoua2862a02020-07-20 16:36:46 -05009974 mNoInputWindow->setFrame(Rect(0, 0, 100, 100));
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07009975 mDispatcher->onWindowInfosChanged(
9976 {{*mNoInputWindow->getInfo(), *mBottomWindow->getInfo()}, {}, 0, 0});
Siarhei Vishniakoua2862a02020-07-20 16:36:46 -05009977
9978 PointF touchedPoint = {10, 10};
9979
Prabir Pradhan678438e2023-04-13 19:32:51 +00009980 mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_DOWN,
9981 AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
9982 {touchedPoint}));
Siarhei Vishniakoua2862a02020-07-20 16:36:46 -05009983
9984 mNoInputWindow->assertNoEvents();
9985 mBottomWindow->assertNoEvents();
9986}
9987
Vishnu Nair958da932020-08-21 17:12:37 -07009988class InputDispatcherMirrorWindowFocusTests : public InputDispatcherTest {
9989protected:
9990 std::shared_ptr<FakeApplicationHandle> mApp;
9991 sp<FakeWindowHandle> mWindow;
9992 sp<FakeWindowHandle> mMirror;
9993
9994 virtual void SetUp() override {
9995 InputDispatcherTest::SetUp();
9996 mApp = std::make_shared<FakeApplicationHandle>();
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07009997 mWindow = sp<FakeWindowHandle>::make(mApp, mDispatcher, "TestWindow", ADISPLAY_ID_DEFAULT);
Prabir Pradhane7cc69c2024-01-05 21:35:28 +00009998 mMirror = mWindow->clone(ADISPLAY_ID_DEFAULT);
Vishnu Nair958da932020-08-21 17:12:37 -07009999 mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, mApp);
10000 mWindow->setFocusable(true);
10001 mMirror->setFocusable(true);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070010002 mDispatcher->onWindowInfosChanged({{*mWindow->getInfo(), *mMirror->getInfo()}, {}, 0, 0});
Vishnu Nair958da932020-08-21 17:12:37 -070010003 }
10004};
10005
10006TEST_F(InputDispatcherMirrorWindowFocusTests, CanGetFocus) {
10007 // Request focus on a mirrored window
10008 setFocusedWindow(mMirror);
10009
10010 // window gets focused
10011 mWindow->consumeFocusEvent(true);
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070010012 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectKeyDown(*mDispatcher))
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -080010013 << "Inject key event should return InputEventInjectionResult::SUCCEEDED";
Vishnu Nair958da932020-08-21 17:12:37 -070010014 mWindow->consumeKeyDown(ADISPLAY_ID_NONE);
10015}
10016
10017// A focused & mirrored window remains focused only if the window and its mirror are both
10018// focusable.
10019TEST_F(InputDispatcherMirrorWindowFocusTests, FocusedIfAllWindowsFocusable) {
10020 setFocusedWindow(mMirror);
10021
Prabir Pradhanbb3f1c02024-01-04 20:17:14 +000010022 // window gets focused because it is above the mirror
Vishnu Nair958da932020-08-21 17:12:37 -070010023 mWindow->consumeFocusEvent(true);
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070010024 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectKeyDown(*mDispatcher))
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -080010025 << "Inject key event should return InputEventInjectionResult::SUCCEEDED";
Vishnu Nair958da932020-08-21 17:12:37 -070010026 mWindow->consumeKeyDown(ADISPLAY_ID_NONE);
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070010027 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectKeyUp(*mDispatcher))
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -080010028 << "Inject key event should return InputEventInjectionResult::SUCCEEDED";
Vishnu Nair958da932020-08-21 17:12:37 -070010029 mWindow->consumeKeyUp(ADISPLAY_ID_NONE);
10030
10031 mMirror->setFocusable(false);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070010032 mDispatcher->onWindowInfosChanged({{*mWindow->getInfo(), *mMirror->getInfo()}, {}, 0, 0});
Vishnu Nair958da932020-08-21 17:12:37 -070010033
10034 // window loses focus since one of the windows associated with the token in not focusable
10035 mWindow->consumeFocusEvent(false);
10036
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070010037 ASSERT_EQ(InputEventInjectionResult::TIMED_OUT, injectKeyDown(*mDispatcher))
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -080010038 << "Inject key event should return InputEventInjectionResult::TIMED_OUT";
Vishnu Nair958da932020-08-21 17:12:37 -070010039 mWindow->assertNoEvents();
10040}
10041
10042// A focused & mirrored window remains focused until the window and its mirror both become
10043// invisible.
10044TEST_F(InputDispatcherMirrorWindowFocusTests, FocusedIfAnyWindowVisible) {
10045 setFocusedWindow(mMirror);
10046
10047 // window gets focused
10048 mWindow->consumeFocusEvent(true);
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070010049 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectKeyDown(*mDispatcher))
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -080010050 << "Inject key event should return InputEventInjectionResult::SUCCEEDED";
Vishnu Nair958da932020-08-21 17:12:37 -070010051 mWindow->consumeKeyDown(ADISPLAY_ID_NONE);
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070010052 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectKeyUp(*mDispatcher))
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -080010053 << "Inject key event should return InputEventInjectionResult::SUCCEEDED";
Vishnu Nair958da932020-08-21 17:12:37 -070010054 mWindow->consumeKeyUp(ADISPLAY_ID_NONE);
10055
10056 mMirror->setVisible(false);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070010057 mDispatcher->onWindowInfosChanged({{*mWindow->getInfo(), *mMirror->getInfo()}, {}, 0, 0});
Vishnu Nair958da932020-08-21 17:12:37 -070010058
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070010059 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectKeyDown(*mDispatcher))
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -080010060 << "Inject key event should return InputEventInjectionResult::SUCCEEDED";
Vishnu Nair958da932020-08-21 17:12:37 -070010061 mWindow->consumeKeyDown(ADISPLAY_ID_NONE);
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070010062 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectKeyUp(*mDispatcher))
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -080010063 << "Inject key event should return InputEventInjectionResult::SUCCEEDED";
Vishnu Nair958da932020-08-21 17:12:37 -070010064 mWindow->consumeKeyUp(ADISPLAY_ID_NONE);
10065
10066 mWindow->setVisible(false);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070010067 mDispatcher->onWindowInfosChanged({{*mWindow->getInfo(), *mMirror->getInfo()}, {}, 0, 0});
Vishnu Nair958da932020-08-21 17:12:37 -070010068
10069 // window loses focus only after all windows associated with the token become invisible.
10070 mWindow->consumeFocusEvent(false);
10071
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070010072 ASSERT_EQ(InputEventInjectionResult::TIMED_OUT, injectKeyDown(*mDispatcher))
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -080010073 << "Inject key event should return InputEventInjectionResult::TIMED_OUT";
Vishnu Nair958da932020-08-21 17:12:37 -070010074 mWindow->assertNoEvents();
10075}
10076
10077// A focused & mirrored window remains focused until both windows are removed.
10078TEST_F(InputDispatcherMirrorWindowFocusTests, FocusedWhileWindowsAlive) {
10079 setFocusedWindow(mMirror);
10080
10081 // window gets focused
10082 mWindow->consumeFocusEvent(true);
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070010083 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectKeyDown(*mDispatcher))
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -080010084 << "Inject key event should return InputEventInjectionResult::SUCCEEDED";
Vishnu Nair958da932020-08-21 17:12:37 -070010085 mWindow->consumeKeyDown(ADISPLAY_ID_NONE);
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070010086 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectKeyUp(*mDispatcher))
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -080010087 << "Inject key event should return InputEventInjectionResult::SUCCEEDED";
Vishnu Nair958da932020-08-21 17:12:37 -070010088 mWindow->consumeKeyUp(ADISPLAY_ID_NONE);
10089
10090 // single window is removed but the window token remains focused
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070010091 mDispatcher->onWindowInfosChanged({{*mMirror->getInfo()}, {}, 0, 0});
Vishnu Nair958da932020-08-21 17:12:37 -070010092
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070010093 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectKeyDown(*mDispatcher))
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -080010094 << "Inject key event should return InputEventInjectionResult::SUCCEEDED";
Prabir Pradhanbb3f1c02024-01-04 20:17:14 +000010095 mMirror->consumeKeyDown(ADISPLAY_ID_NONE);
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070010096 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectKeyUp(*mDispatcher))
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -080010097 << "Inject key event should return InputEventInjectionResult::SUCCEEDED";
Prabir Pradhanbb3f1c02024-01-04 20:17:14 +000010098 mMirror->consumeKeyUp(ADISPLAY_ID_NONE);
Vishnu Nair958da932020-08-21 17:12:37 -070010099
10100 // Both windows are removed
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070010101 mDispatcher->onWindowInfosChanged({{}, {}, 0, 0});
Vishnu Nair958da932020-08-21 17:12:37 -070010102 mWindow->consumeFocusEvent(false);
10103
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070010104 ASSERT_EQ(InputEventInjectionResult::TIMED_OUT, injectKeyDown(*mDispatcher))
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -080010105 << "Inject key event should return InputEventInjectionResult::TIMED_OUT";
Vishnu Nair958da932020-08-21 17:12:37 -070010106 mWindow->assertNoEvents();
10107}
10108
10109// Focus request can be pending until one window becomes visible.
10110TEST_F(InputDispatcherMirrorWindowFocusTests, DeferFocusWhenInvisible) {
10111 // Request focus on an invisible mirror.
10112 mWindow->setVisible(false);
10113 mMirror->setVisible(false);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070010114 mDispatcher->onWindowInfosChanged({{*mWindow->getInfo(), *mMirror->getInfo()}, {}, 0, 0});
Vishnu Nair958da932020-08-21 17:12:37 -070010115 setFocusedWindow(mMirror);
10116
10117 // Injected key goes to pending queue.
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -080010118 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070010119 injectKey(*mDispatcher, AKEY_EVENT_ACTION_DOWN, /*repeatCount=*/0,
10120 ADISPLAY_ID_DEFAULT, InputEventInjectionSync::NONE));
Vishnu Nair958da932020-08-21 17:12:37 -070010121
10122 mMirror->setVisible(true);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070010123 mDispatcher->onWindowInfosChanged({{*mWindow->getInfo(), *mMirror->getInfo()}, {}, 0, 0});
Vishnu Nair958da932020-08-21 17:12:37 -070010124
10125 // window gets focused
10126 mWindow->consumeFocusEvent(true);
10127 // window gets the pending key event
10128 mWindow->consumeKeyDown(ADISPLAY_ID_DEFAULT);
10129}
Prabir Pradhan99987712020-11-10 18:43:05 -080010130
10131class InputDispatcherPointerCaptureTests : public InputDispatcherTest {
10132protected:
10133 std::shared_ptr<FakeApplicationHandle> mApp;
10134 sp<FakeWindowHandle> mWindow;
10135 sp<FakeWindowHandle> mSecondWindow;
10136
10137 void SetUp() override {
10138 InputDispatcherTest::SetUp();
10139 mApp = std::make_shared<FakeApplicationHandle>();
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -070010140 mWindow = sp<FakeWindowHandle>::make(mApp, mDispatcher, "TestWindow", ADISPLAY_ID_DEFAULT);
Prabir Pradhan99987712020-11-10 18:43:05 -080010141 mWindow->setFocusable(true);
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -070010142 mSecondWindow =
10143 sp<FakeWindowHandle>::make(mApp, mDispatcher, "TestWindow2", ADISPLAY_ID_DEFAULT);
Prabir Pradhan99987712020-11-10 18:43:05 -080010144 mSecondWindow->setFocusable(true);
10145
10146 mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, mApp);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070010147 mDispatcher->onWindowInfosChanged(
10148 {{*mWindow->getInfo(), *mSecondWindow->getInfo()}, {}, 0, 0});
Prabir Pradhan99987712020-11-10 18:43:05 -080010149
10150 setFocusedWindow(mWindow);
10151 mWindow->consumeFocusEvent(true);
10152 }
10153
Prabir Pradhan5cc1a692021-08-06 14:01:18 +000010154 void notifyPointerCaptureChanged(const PointerCaptureRequest& request) {
Prabir Pradhan678438e2023-04-13 19:32:51 +000010155 mDispatcher->notifyPointerCaptureChanged(generatePointerCaptureChangedArgs(request));
Prabir Pradhan99987712020-11-10 18:43:05 -080010156 }
10157
Prabir Pradhan5cc1a692021-08-06 14:01:18 +000010158 PointerCaptureRequest requestAndVerifyPointerCapture(const sp<FakeWindowHandle>& window,
10159 bool enabled) {
Prabir Pradhan99987712020-11-10 18:43:05 -080010160 mDispatcher->requestPointerCapture(window->getToken(), enabled);
Hiroki Sato25040232024-02-22 17:21:22 +090010161 auto request = mFakePolicy->assertSetPointerCaptureCalled(window, enabled);
Prabir Pradhan5cc1a692021-08-06 14:01:18 +000010162 notifyPointerCaptureChanged(request);
Prabir Pradhan99987712020-11-10 18:43:05 -080010163 window->consumeCaptureEvent(enabled);
Prabir Pradhan5cc1a692021-08-06 14:01:18 +000010164 return request;
Prabir Pradhan99987712020-11-10 18:43:05 -080010165 }
10166};
10167
10168TEST_F(InputDispatcherPointerCaptureTests, EnablePointerCaptureWhenFocused) {
10169 // Ensure that capture cannot be obtained for unfocused windows.
10170 mDispatcher->requestPointerCapture(mSecondWindow->getToken(), true);
10171 mFakePolicy->assertSetPointerCaptureNotCalled();
10172 mSecondWindow->assertNoEvents();
10173
10174 // Ensure that capture can be enabled from the focus window.
10175 requestAndVerifyPointerCapture(mWindow, true);
10176
10177 // Ensure that capture cannot be disabled from a window that does not have capture.
10178 mDispatcher->requestPointerCapture(mSecondWindow->getToken(), false);
10179 mFakePolicy->assertSetPointerCaptureNotCalled();
10180
10181 // Ensure that capture can be disabled from the window with capture.
10182 requestAndVerifyPointerCapture(mWindow, false);
10183}
10184
10185TEST_F(InputDispatcherPointerCaptureTests, DisablesPointerCaptureAfterWindowLosesFocus) {
Prabir Pradhan5cc1a692021-08-06 14:01:18 +000010186 auto request = requestAndVerifyPointerCapture(mWindow, true);
Prabir Pradhan99987712020-11-10 18:43:05 -080010187
10188 setFocusedWindow(mSecondWindow);
10189
10190 // Ensure that the capture disabled event was sent first.
10191 mWindow->consumeCaptureEvent(false);
10192 mWindow->consumeFocusEvent(false);
10193 mSecondWindow->consumeFocusEvent(true);
Hiroki Sato25040232024-02-22 17:21:22 +090010194 mFakePolicy->assertSetPointerCaptureCalled(mWindow, false);
Prabir Pradhan99987712020-11-10 18:43:05 -080010195
10196 // Ensure that additional state changes from InputReader are not sent to the window.
Prabir Pradhan5cc1a692021-08-06 14:01:18 +000010197 notifyPointerCaptureChanged({});
10198 notifyPointerCaptureChanged(request);
10199 notifyPointerCaptureChanged({});
Prabir Pradhan99987712020-11-10 18:43:05 -080010200 mWindow->assertNoEvents();
10201 mSecondWindow->assertNoEvents();
10202 mFakePolicy->assertSetPointerCaptureNotCalled();
10203}
10204
10205TEST_F(InputDispatcherPointerCaptureTests, UnexpectedStateChangeDisablesPointerCapture) {
Prabir Pradhan5cc1a692021-08-06 14:01:18 +000010206 auto request = requestAndVerifyPointerCapture(mWindow, true);
Prabir Pradhan99987712020-11-10 18:43:05 -080010207
10208 // InputReader unexpectedly disables and enables pointer capture.
Prabir Pradhan5cc1a692021-08-06 14:01:18 +000010209 notifyPointerCaptureChanged({});
10210 notifyPointerCaptureChanged(request);
Prabir Pradhan99987712020-11-10 18:43:05 -080010211
10212 // Ensure that Pointer Capture is disabled.
Hiroki Sato25040232024-02-22 17:21:22 +090010213 mFakePolicy->assertSetPointerCaptureCalled(mWindow, false);
Prabir Pradhan99987712020-11-10 18:43:05 -080010214 mWindow->consumeCaptureEvent(false);
10215 mWindow->assertNoEvents();
10216}
10217
Prabir Pradhan167e6d92021-02-04 16:18:17 -080010218TEST_F(InputDispatcherPointerCaptureTests, OutOfOrderRequests) {
10219 requestAndVerifyPointerCapture(mWindow, true);
10220
10221 // The first window loses focus.
10222 setFocusedWindow(mSecondWindow);
Hiroki Sato25040232024-02-22 17:21:22 +090010223 mFakePolicy->assertSetPointerCaptureCalled(mWindow, false);
Prabir Pradhan167e6d92021-02-04 16:18:17 -080010224 mWindow->consumeCaptureEvent(false);
10225
10226 // Request Pointer Capture from the second window before the notification from InputReader
10227 // arrives.
10228 mDispatcher->requestPointerCapture(mSecondWindow->getToken(), true);
Hiroki Sato25040232024-02-22 17:21:22 +090010229 auto request = mFakePolicy->assertSetPointerCaptureCalled(mSecondWindow, true);
Prabir Pradhan167e6d92021-02-04 16:18:17 -080010230
10231 // InputReader notifies Pointer Capture was disabled (because of the focus change).
Prabir Pradhan5cc1a692021-08-06 14:01:18 +000010232 notifyPointerCaptureChanged({});
Prabir Pradhan167e6d92021-02-04 16:18:17 -080010233
10234 // InputReader notifies Pointer Capture was enabled (because of mSecondWindow's request).
Prabir Pradhan5cc1a692021-08-06 14:01:18 +000010235 notifyPointerCaptureChanged(request);
Prabir Pradhan167e6d92021-02-04 16:18:17 -080010236
10237 mSecondWindow->consumeFocusEvent(true);
10238 mSecondWindow->consumeCaptureEvent(true);
10239}
10240
Prabir Pradhan5cc1a692021-08-06 14:01:18 +000010241TEST_F(InputDispatcherPointerCaptureTests, EnableRequestFollowsSequenceNumbers) {
10242 // App repeatedly enables and disables capture.
10243 mDispatcher->requestPointerCapture(mWindow->getToken(), true);
Hiroki Sato25040232024-02-22 17:21:22 +090010244 auto firstRequest = mFakePolicy->assertSetPointerCaptureCalled(mWindow, true);
Prabir Pradhan5cc1a692021-08-06 14:01:18 +000010245 mDispatcher->requestPointerCapture(mWindow->getToken(), false);
Hiroki Sato25040232024-02-22 17:21:22 +090010246 mFakePolicy->assertSetPointerCaptureCalled(mWindow, false);
Prabir Pradhan5cc1a692021-08-06 14:01:18 +000010247 mDispatcher->requestPointerCapture(mWindow->getToken(), true);
Hiroki Sato25040232024-02-22 17:21:22 +090010248 auto secondRequest = mFakePolicy->assertSetPointerCaptureCalled(mWindow, true);
Prabir Pradhan5cc1a692021-08-06 14:01:18 +000010249
10250 // InputReader notifies that PointerCapture has been enabled for the first request. Since the
10251 // first request is now stale, this should do nothing.
10252 notifyPointerCaptureChanged(firstRequest);
10253 mWindow->assertNoEvents();
10254
10255 // InputReader notifies that the second request was enabled.
10256 notifyPointerCaptureChanged(secondRequest);
10257 mWindow->consumeCaptureEvent(true);
10258}
10259
Prabir Pradhan7092e262022-05-03 16:51:09 +000010260TEST_F(InputDispatcherPointerCaptureTests, RapidToggleRequests) {
10261 requestAndVerifyPointerCapture(mWindow, true);
10262
10263 // App toggles pointer capture off and on.
10264 mDispatcher->requestPointerCapture(mWindow->getToken(), false);
Hiroki Sato25040232024-02-22 17:21:22 +090010265 mFakePolicy->assertSetPointerCaptureCalled(mWindow, false);
Prabir Pradhan7092e262022-05-03 16:51:09 +000010266
10267 mDispatcher->requestPointerCapture(mWindow->getToken(), true);
Hiroki Sato25040232024-02-22 17:21:22 +090010268 auto enableRequest = mFakePolicy->assertSetPointerCaptureCalled(mWindow, true);
Prabir Pradhan7092e262022-05-03 16:51:09 +000010269
10270 // InputReader notifies that the latest "enable" request was processed, while skipping over the
10271 // preceding "disable" request.
10272 notifyPointerCaptureChanged(enableRequest);
10273
10274 // Since pointer capture was never disabled during the rapid toggle, the window does not receive
10275 // any notifications.
10276 mWindow->assertNoEvents();
10277}
10278
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -070010279/**
10280 * One window. Hover mouse in the window, and then start capture. Make sure that the relative
10281 * mouse movements don't affect the previous mouse hovering state.
10282 * When pointer capture is enabled, the incoming events are always ACTION_MOVE (there are no
10283 * HOVER_MOVE events).
10284 */
10285TEST_F(InputDispatcherPointerCaptureTests, MouseHoverAndPointerCapture) {
10286 // Mouse hover on the window
10287 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_ENTER, AINPUT_SOURCE_MOUSE)
10288 .pointer(PointerBuilder(0, ToolType::MOUSE).x(100).y(110))
10289 .build());
10290 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_MOVE, AINPUT_SOURCE_MOUSE)
10291 .pointer(PointerBuilder(0, ToolType::MOUSE).x(100).y(110))
10292 .build());
10293
10294 mWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_HOVER_ENTER)));
10295 mWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_HOVER_MOVE)));
10296
10297 // Start pointer capture
10298 requestAndVerifyPointerCapture(mWindow, true);
10299
10300 // Send some relative mouse movements and receive them in the window.
10301 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_MOUSE_RELATIVE)
10302 .pointer(PointerBuilder(0, ToolType::MOUSE).x(10).y(11))
10303 .build());
10304 mWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_MOVE), WithCoords(10, 11),
10305 WithSource(AINPUT_SOURCE_MOUSE_RELATIVE)));
10306
10307 // Stop pointer capture
10308 requestAndVerifyPointerCapture(mWindow, false);
10309
10310 // Continue hovering on the window
10311 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_MOVE, AINPUT_SOURCE_MOUSE)
10312 .pointer(PointerBuilder(0, ToolType::MOUSE).x(105).y(115))
10313 .build());
10314 mWindow->consumeMotionEvent(
10315 AllOf(WithMotionAction(ACTION_HOVER_MOVE), WithSource(AINPUT_SOURCE_MOUSE)));
10316
10317 mWindow->assertNoEvents();
10318}
10319
Hiroki Sato25040232024-02-22 17:21:22 +090010320using InputDispatcherPointerCaptureDeathTest = InputDispatcherPointerCaptureTests;
10321
10322TEST_F(InputDispatcherPointerCaptureDeathTest,
10323 NotifyPointerCaptureChangedWithWrongTokenAbortsDispatcher) {
10324 testing::GTEST_FLAG(death_test_style) = "threadsafe";
10325 ScopedSilentDeath _silentDeath;
10326
10327 mDispatcher->requestPointerCapture(mWindow->getToken(), true);
10328 auto request = mFakePolicy->assertSetPointerCaptureCalled(mWindow, true);
10329
10330 // Dispatch a pointer changed event with a wrong token.
10331 request.window = mSecondWindow->getToken();
10332 ASSERT_DEATH(
10333 {
10334 notifyPointerCaptureChanged(request);
10335 mSecondWindow->consumeCaptureEvent(true);
10336 },
10337 "Unexpected requested window for Pointer Capture.");
10338}
10339
Bernardo Rufinoc3b7b8c2021-01-29 17:38:07 +000010340class InputDispatcherUntrustedTouchesTest : public InputDispatcherTest {
10341protected:
10342 constexpr static const float MAXIMUM_OBSCURING_OPACITY = 0.8;
Bernardo Rufino7393d172021-02-26 13:56:11 +000010343
10344 constexpr static const float OPACITY_ABOVE_THRESHOLD = 0.9;
10345 static_assert(OPACITY_ABOVE_THRESHOLD > MAXIMUM_OBSCURING_OPACITY);
10346
10347 constexpr static const float OPACITY_BELOW_THRESHOLD = 0.7;
10348 static_assert(OPACITY_BELOW_THRESHOLD < MAXIMUM_OBSCURING_OPACITY);
10349
10350 // When combined twice, ie 1 - (1 - 0.5)*(1 - 0.5) = 0.75 < 8, is still below the threshold
10351 constexpr static const float OPACITY_FAR_BELOW_THRESHOLD = 0.5;
10352 static_assert(OPACITY_FAR_BELOW_THRESHOLD < MAXIMUM_OBSCURING_OPACITY);
10353 static_assert(1 - (1 - OPACITY_FAR_BELOW_THRESHOLD) * (1 - OPACITY_FAR_BELOW_THRESHOLD) <
10354 MAXIMUM_OBSCURING_OPACITY);
10355
Prabir Pradhan8a5c41d2023-06-08 19:13:46 +000010356 static constexpr gui::Uid TOUCHED_APP_UID{10001};
10357 static constexpr gui::Uid APP_B_UID{10002};
10358 static constexpr gui::Uid APP_C_UID{10003};
Bernardo Rufinoc3b7b8c2021-01-29 17:38:07 +000010359
10360 sp<FakeWindowHandle> mTouchWindow;
10361
10362 virtual void SetUp() override {
10363 InputDispatcherTest::SetUp();
Bernardo Rufino6d52e542021-02-15 18:38:10 +000010364 mTouchWindow = getWindow(TOUCHED_APP_UID, "Touched");
Bernardo Rufinoc3b7b8c2021-01-29 17:38:07 +000010365 mDispatcher->setMaximumObscuringOpacityForTouch(MAXIMUM_OBSCURING_OPACITY);
10366 }
10367
10368 virtual void TearDown() override {
10369 InputDispatcherTest::TearDown();
10370 mTouchWindow.clear();
10371 }
10372
Prabir Pradhan8a5c41d2023-06-08 19:13:46 +000010373 sp<FakeWindowHandle> getOccludingWindow(gui::Uid uid, std::string name, TouchOcclusionMode mode,
chaviw3277faf2021-05-19 16:45:23 -050010374 float alpha = 1.0f) {
Bernardo Rufinoc3b7b8c2021-01-29 17:38:07 +000010375 sp<FakeWindowHandle> window = getWindow(uid, name);
Prabir Pradhan4d5c52f2022-01-31 08:52:10 -080010376 window->setTouchable(false);
Bernardo Rufinoc3b7b8c2021-01-29 17:38:07 +000010377 window->setTouchOcclusionMode(mode);
Bernardo Rufino1d0d1f22021-02-12 15:08:43 +000010378 window->setAlpha(alpha);
Bernardo Rufinoc3b7b8c2021-01-29 17:38:07 +000010379 return window;
10380 }
10381
Prabir Pradhan8a5c41d2023-06-08 19:13:46 +000010382 sp<FakeWindowHandle> getWindow(gui::Uid uid, std::string name) {
Bernardo Rufinoc3b7b8c2021-01-29 17:38:07 +000010383 std::shared_ptr<FakeApplicationHandle> app = std::make_shared<FakeApplicationHandle>();
10384 sp<FakeWindowHandle> window =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -070010385 sp<FakeWindowHandle>::make(app, mDispatcher, name, ADISPLAY_ID_DEFAULT);
Bernardo Rufinoc3b7b8c2021-01-29 17:38:07 +000010386 // Generate an arbitrary PID based on the UID
Prabir Pradhanaeebeb42023-06-13 19:53:03 +000010387 window->setOwnerInfo(gui::Pid{static_cast<pid_t>(1777 + (uid.val() % 10000))}, uid);
Bernardo Rufinoc3b7b8c2021-01-29 17:38:07 +000010388 return window;
10389 }
10390
10391 void touch(const std::vector<PointF>& points = {PointF{100, 200}}) {
Prabir Pradhan678438e2023-04-13 19:32:51 +000010392 mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_DOWN,
10393 AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
10394 points));
Bernardo Rufinoc3b7b8c2021-01-29 17:38:07 +000010395 }
10396};
10397
10398TEST_F(InputDispatcherUntrustedTouchesTest, WindowWithBlockUntrustedOcclusionMode_BlocksTouch) {
Bernardo Rufino1d0d1f22021-02-12 15:08:43 +000010399 const sp<FakeWindowHandle>& w =
Bernardo Rufinoc3b7b8c2021-01-29 17:38:07 +000010400 getOccludingWindow(APP_B_UID, "B", TouchOcclusionMode::BLOCK_UNTRUSTED);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070010401 mDispatcher->onWindowInfosChanged({{*w->getInfo(), *mTouchWindow->getInfo()}, {}, 0, 0});
Bernardo Rufinoc3b7b8c2021-01-29 17:38:07 +000010402
10403 touch();
10404
10405 mTouchWindow->assertNoEvents();
10406}
10407
Bernardo Rufinoa43a5a42021-02-17 12:21:14 +000010408TEST_F(InputDispatcherUntrustedTouchesTest,
Bernardo Rufino7393d172021-02-26 13:56:11 +000010409 WindowWithBlockUntrustedOcclusionModeWithOpacityBelowThreshold_BlocksTouch) {
10410 const sp<FakeWindowHandle>& w =
10411 getOccludingWindow(APP_B_UID, "B", TouchOcclusionMode::BLOCK_UNTRUSTED, 0.7f);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070010412 mDispatcher->onWindowInfosChanged({{*w->getInfo(), *mTouchWindow->getInfo()}, {}, 0, 0});
Bernardo Rufino7393d172021-02-26 13:56:11 +000010413
10414 touch();
10415
10416 mTouchWindow->assertNoEvents();
10417}
10418
10419TEST_F(InputDispatcherUntrustedTouchesTest,
Bernardo Rufinoa43a5a42021-02-17 12:21:14 +000010420 WindowWithBlockUntrustedOcclusionMode_DoesNotReceiveTouch) {
10421 const sp<FakeWindowHandle>& w =
10422 getOccludingWindow(APP_B_UID, "B", TouchOcclusionMode::BLOCK_UNTRUSTED);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070010423 mDispatcher->onWindowInfosChanged({{*w->getInfo(), *mTouchWindow->getInfo()}, {}, 0, 0});
Bernardo Rufinoa43a5a42021-02-17 12:21:14 +000010424
10425 touch();
10426
10427 w->assertNoEvents();
10428}
10429
Bernardo Rufinoc3b7b8c2021-01-29 17:38:07 +000010430TEST_F(InputDispatcherUntrustedTouchesTest, WindowWithAllowOcclusionMode_AllowsTouch) {
Bernardo Rufino1d0d1f22021-02-12 15:08:43 +000010431 const sp<FakeWindowHandle>& w = getOccludingWindow(APP_B_UID, "B", TouchOcclusionMode::ALLOW);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070010432 mDispatcher->onWindowInfosChanged({{*w->getInfo(), *mTouchWindow->getInfo()}, {}, 0, 0});
Bernardo Rufinoc3b7b8c2021-01-29 17:38:07 +000010433
10434 touch();
10435
10436 mTouchWindow->consumeAnyMotionDown();
10437}
10438
10439TEST_F(InputDispatcherUntrustedTouchesTest, TouchOutsideOccludingWindow_AllowsTouch) {
Bernardo Rufino1d0d1f22021-02-12 15:08:43 +000010440 const sp<FakeWindowHandle>& w =
Bernardo Rufinoc3b7b8c2021-01-29 17:38:07 +000010441 getOccludingWindow(APP_B_UID, "B", TouchOcclusionMode::BLOCK_UNTRUSTED);
Bernardo Rufino1d0d1f22021-02-12 15:08:43 +000010442 w->setFrame(Rect(0, 0, 50, 50));
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070010443 mDispatcher->onWindowInfosChanged({{*w->getInfo(), *mTouchWindow->getInfo()}, {}, 0, 0});
Bernardo Rufinoc3b7b8c2021-01-29 17:38:07 +000010444
10445 touch({PointF{100, 100}});
10446
10447 mTouchWindow->consumeAnyMotionDown();
10448}
10449
10450TEST_F(InputDispatcherUntrustedTouchesTest, WindowFromSameUid_AllowsTouch) {
Bernardo Rufino1d0d1f22021-02-12 15:08:43 +000010451 const sp<FakeWindowHandle>& w =
Bernardo Rufino6d52e542021-02-15 18:38:10 +000010452 getOccludingWindow(TOUCHED_APP_UID, "A", TouchOcclusionMode::BLOCK_UNTRUSTED);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070010453 mDispatcher->onWindowInfosChanged({{*w->getInfo(), *mTouchWindow->getInfo()}, {}, 0, 0});
Bernardo Rufino1d0d1f22021-02-12 15:08:43 +000010454
10455 touch();
10456
10457 mTouchWindow->consumeAnyMotionDown();
10458}
10459
10460TEST_F(InputDispatcherUntrustedTouchesTest, WindowWithZeroOpacity_AllowsTouch) {
10461 const sp<FakeWindowHandle>& w =
10462 getOccludingWindow(APP_B_UID, "B", TouchOcclusionMode::BLOCK_UNTRUSTED, 0.0f);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070010463 mDispatcher->onWindowInfosChanged({{*w->getInfo(), *mTouchWindow->getInfo()}, {}, 0, 0});
Bernardo Rufinoc3b7b8c2021-01-29 17:38:07 +000010464
10465 touch();
10466
10467 mTouchWindow->consumeAnyMotionDown();
10468}
10469
Bernardo Rufinoa43a5a42021-02-17 12:21:14 +000010470TEST_F(InputDispatcherUntrustedTouchesTest, WindowWithZeroOpacity_DoesNotReceiveTouch) {
10471 const sp<FakeWindowHandle>& w =
10472 getOccludingWindow(APP_B_UID, "B", TouchOcclusionMode::BLOCK_UNTRUSTED, 0.0f);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070010473 mDispatcher->onWindowInfosChanged({{*w->getInfo(), *mTouchWindow->getInfo()}, {}, 0, 0});
Bernardo Rufinoa43a5a42021-02-17 12:21:14 +000010474
10475 touch();
10476
10477 w->assertNoEvents();
10478}
10479
10480/**
10481 * This is important to make sure apps can't indirectly learn the position of touches (outside vs
10482 * inside) while letting them pass-through. Note that even though touch passes through the occluding
10483 * window, the occluding window will still receive ACTION_OUTSIDE event.
10484 */
10485TEST_F(InputDispatcherUntrustedTouchesTest,
10486 WindowWithZeroOpacityAndWatchOutside_ReceivesOutsideEvent) {
10487 const sp<FakeWindowHandle>& w =
10488 getOccludingWindow(APP_B_UID, "B", TouchOcclusionMode::BLOCK_UNTRUSTED, 0.0f);
Prabir Pradhan4d5c52f2022-01-31 08:52:10 -080010489 w->setWatchOutsideTouch(true);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070010490 mDispatcher->onWindowInfosChanged({{*w->getInfo(), *mTouchWindow->getInfo()}, {}, 0, 0});
Bernardo Rufinoa43a5a42021-02-17 12:21:14 +000010491
10492 touch();
10493
10494 w->consumeMotionOutside();
10495}
10496
10497TEST_F(InputDispatcherUntrustedTouchesTest, OutsideEvent_HasZeroCoordinates) {
10498 const sp<FakeWindowHandle>& w =
10499 getOccludingWindow(APP_B_UID, "B", TouchOcclusionMode::BLOCK_UNTRUSTED, 0.0f);
Prabir Pradhan4d5c52f2022-01-31 08:52:10 -080010500 w->setWatchOutsideTouch(true);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070010501 mDispatcher->onWindowInfosChanged({{*w->getInfo(), *mTouchWindow->getInfo()}, {}, 0, 0});
Bernardo Rufinoa43a5a42021-02-17 12:21:14 +000010502
10503 touch();
10504
Prabir Pradhandfabf8a2022-01-21 08:19:30 -080010505 w->consumeMotionOutsideWithZeroedCoords();
Bernardo Rufinoa43a5a42021-02-17 12:21:14 +000010506}
10507
Bernardo Rufinoc3b7b8c2021-01-29 17:38:07 +000010508TEST_F(InputDispatcherUntrustedTouchesTest, WindowWithOpacityBelowThreshold_AllowsTouch) {
Bernardo Rufino1d0d1f22021-02-12 15:08:43 +000010509 const sp<FakeWindowHandle>& w =
Bernardo Rufino7393d172021-02-26 13:56:11 +000010510 getOccludingWindow(APP_B_UID, "B", TouchOcclusionMode::USE_OPACITY,
10511 OPACITY_BELOW_THRESHOLD);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070010512 mDispatcher->onWindowInfosChanged({{*w->getInfo(), *mTouchWindow->getInfo()}, {}, 0, 0});
Bernardo Rufino1d0d1f22021-02-12 15:08:43 +000010513
10514 touch();
10515
10516 mTouchWindow->consumeAnyMotionDown();
10517}
10518
10519TEST_F(InputDispatcherUntrustedTouchesTest, WindowWithOpacityAtThreshold_AllowsTouch) {
10520 const sp<FakeWindowHandle>& w =
10521 getOccludingWindow(APP_B_UID, "B", TouchOcclusionMode::USE_OPACITY,
10522 MAXIMUM_OBSCURING_OPACITY);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070010523 mDispatcher->onWindowInfosChanged({{*w->getInfo(), *mTouchWindow->getInfo()}, {}, 0, 0});
Bernardo Rufinoc3b7b8c2021-01-29 17:38:07 +000010524
10525 touch();
10526
10527 mTouchWindow->consumeAnyMotionDown();
10528}
10529
10530TEST_F(InputDispatcherUntrustedTouchesTest, WindowWithOpacityAboveThreshold_BlocksTouch) {
Bernardo Rufino1d0d1f22021-02-12 15:08:43 +000010531 const sp<FakeWindowHandle>& w =
Bernardo Rufino7393d172021-02-26 13:56:11 +000010532 getOccludingWindow(APP_B_UID, "B", TouchOcclusionMode::USE_OPACITY,
10533 OPACITY_ABOVE_THRESHOLD);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070010534 mDispatcher->onWindowInfosChanged({{*w->getInfo(), *mTouchWindow->getInfo()}, {}, 0, 0});
Bernardo Rufino1d0d1f22021-02-12 15:08:43 +000010535
10536 touch();
10537
10538 mTouchWindow->assertNoEvents();
10539}
10540
10541TEST_F(InputDispatcherUntrustedTouchesTest, WindowsWithCombinedOpacityAboveThreshold_BlocksTouch) {
10542 // Resulting opacity = 1 - (1 - 0.7)*(1 - 0.7) = .91
10543 const sp<FakeWindowHandle>& w1 =
Bernardo Rufino7393d172021-02-26 13:56:11 +000010544 getOccludingWindow(APP_B_UID, "B1", TouchOcclusionMode::USE_OPACITY,
10545 OPACITY_BELOW_THRESHOLD);
Bernardo Rufino1d0d1f22021-02-12 15:08:43 +000010546 const sp<FakeWindowHandle>& w2 =
Bernardo Rufino7393d172021-02-26 13:56:11 +000010547 getOccludingWindow(APP_B_UID, "B2", TouchOcclusionMode::USE_OPACITY,
10548 OPACITY_BELOW_THRESHOLD);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070010549 mDispatcher->onWindowInfosChanged(
10550 {{*w1->getInfo(), *w2->getInfo(), *mTouchWindow->getInfo()}, {}, 0, 0});
Bernardo Rufino1d0d1f22021-02-12 15:08:43 +000010551
10552 touch();
10553
10554 mTouchWindow->assertNoEvents();
10555}
10556
10557TEST_F(InputDispatcherUntrustedTouchesTest, WindowsWithCombinedOpacityBelowThreshold_AllowsTouch) {
10558 // Resulting opacity = 1 - (1 - 0.5)*(1 - 0.5) = .75
10559 const sp<FakeWindowHandle>& w1 =
Bernardo Rufino7393d172021-02-26 13:56:11 +000010560 getOccludingWindow(APP_B_UID, "B1", TouchOcclusionMode::USE_OPACITY,
10561 OPACITY_FAR_BELOW_THRESHOLD);
Bernardo Rufino1d0d1f22021-02-12 15:08:43 +000010562 const sp<FakeWindowHandle>& w2 =
Bernardo Rufino7393d172021-02-26 13:56:11 +000010563 getOccludingWindow(APP_B_UID, "B2", TouchOcclusionMode::USE_OPACITY,
10564 OPACITY_FAR_BELOW_THRESHOLD);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070010565 mDispatcher->onWindowInfosChanged(
10566 {{*w1->getInfo(), *w2->getInfo(), *mTouchWindow->getInfo()}, {}, 0, 0});
Bernardo Rufino1d0d1f22021-02-12 15:08:43 +000010567
10568 touch();
10569
10570 mTouchWindow->consumeAnyMotionDown();
10571}
10572
10573TEST_F(InputDispatcherUntrustedTouchesTest,
10574 WindowsFromDifferentAppsEachBelowThreshold_AllowsTouch) {
10575 const sp<FakeWindowHandle>& wB =
Bernardo Rufino7393d172021-02-26 13:56:11 +000010576 getOccludingWindow(APP_B_UID, "B", TouchOcclusionMode::USE_OPACITY,
10577 OPACITY_BELOW_THRESHOLD);
Bernardo Rufino1d0d1f22021-02-12 15:08:43 +000010578 const sp<FakeWindowHandle>& wC =
Bernardo Rufino7393d172021-02-26 13:56:11 +000010579 getOccludingWindow(APP_C_UID, "C", TouchOcclusionMode::USE_OPACITY,
10580 OPACITY_BELOW_THRESHOLD);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070010581 mDispatcher->onWindowInfosChanged(
10582 {{*wB->getInfo(), *wC->getInfo(), *mTouchWindow->getInfo()}, {}, 0, 0});
Bernardo Rufino1d0d1f22021-02-12 15:08:43 +000010583
10584 touch();
10585
10586 mTouchWindow->consumeAnyMotionDown();
10587}
10588
10589TEST_F(InputDispatcherUntrustedTouchesTest, WindowsFromDifferentAppsOneAboveThreshold_BlocksTouch) {
10590 const sp<FakeWindowHandle>& wB =
Bernardo Rufino7393d172021-02-26 13:56:11 +000010591 getOccludingWindow(APP_B_UID, "B", TouchOcclusionMode::USE_OPACITY,
10592 OPACITY_BELOW_THRESHOLD);
Bernardo Rufino1d0d1f22021-02-12 15:08:43 +000010593 const sp<FakeWindowHandle>& wC =
Bernardo Rufino7393d172021-02-26 13:56:11 +000010594 getOccludingWindow(APP_C_UID, "C", TouchOcclusionMode::USE_OPACITY,
10595 OPACITY_ABOVE_THRESHOLD);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070010596 mDispatcher->onWindowInfosChanged(
10597 {{*wB->getInfo(), *wC->getInfo(), *mTouchWindow->getInfo()}, {}, 0, 0});
Bernardo Rufinoc3b7b8c2021-01-29 17:38:07 +000010598
10599 touch();
10600
10601 mTouchWindow->assertNoEvents();
10602}
10603
Bernardo Rufino6d52e542021-02-15 18:38:10 +000010604TEST_F(InputDispatcherUntrustedTouchesTest,
10605 WindowWithOpacityAboveThresholdAndSelfWindow_BlocksTouch) {
10606 const sp<FakeWindowHandle>& wA =
Bernardo Rufino7393d172021-02-26 13:56:11 +000010607 getOccludingWindow(TOUCHED_APP_UID, "T", TouchOcclusionMode::USE_OPACITY,
10608 OPACITY_BELOW_THRESHOLD);
Bernardo Rufino6d52e542021-02-15 18:38:10 +000010609 const sp<FakeWindowHandle>& wB =
Bernardo Rufino7393d172021-02-26 13:56:11 +000010610 getOccludingWindow(APP_B_UID, "B", TouchOcclusionMode::USE_OPACITY,
10611 OPACITY_ABOVE_THRESHOLD);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070010612 mDispatcher->onWindowInfosChanged(
10613 {{*wA->getInfo(), *wB->getInfo(), *mTouchWindow->getInfo()}, {}, 0, 0});
Bernardo Rufino6d52e542021-02-15 18:38:10 +000010614
10615 touch();
10616
10617 mTouchWindow->assertNoEvents();
10618}
10619
10620TEST_F(InputDispatcherUntrustedTouchesTest,
10621 WindowWithOpacityBelowThresholdAndSelfWindow_AllowsTouch) {
10622 const sp<FakeWindowHandle>& wA =
Bernardo Rufino7393d172021-02-26 13:56:11 +000010623 getOccludingWindow(TOUCHED_APP_UID, "T", TouchOcclusionMode::USE_OPACITY,
10624 OPACITY_ABOVE_THRESHOLD);
Bernardo Rufino6d52e542021-02-15 18:38:10 +000010625 const sp<FakeWindowHandle>& wB =
Bernardo Rufino7393d172021-02-26 13:56:11 +000010626 getOccludingWindow(APP_B_UID, "B", TouchOcclusionMode::USE_OPACITY,
10627 OPACITY_BELOW_THRESHOLD);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070010628 mDispatcher->onWindowInfosChanged(
10629 {{*wA->getInfo(), *wB->getInfo(), *mTouchWindow->getInfo()}, {}, 0, 0});
Bernardo Rufino6d52e542021-02-15 18:38:10 +000010630
10631 touch();
10632
10633 mTouchWindow->consumeAnyMotionDown();
10634}
10635
10636TEST_F(InputDispatcherUntrustedTouchesTest, SelfWindowWithOpacityAboveThreshold_AllowsTouch) {
10637 const sp<FakeWindowHandle>& w =
Bernardo Rufino7393d172021-02-26 13:56:11 +000010638 getOccludingWindow(TOUCHED_APP_UID, "T", TouchOcclusionMode::USE_OPACITY,
10639 OPACITY_ABOVE_THRESHOLD);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070010640 mDispatcher->onWindowInfosChanged({{*w->getInfo(), *mTouchWindow->getInfo()}, {}, 0, 0});
Bernardo Rufino6d52e542021-02-15 18:38:10 +000010641
10642 touch();
10643
10644 mTouchWindow->consumeAnyMotionDown();
10645}
10646
10647TEST_F(InputDispatcherUntrustedTouchesTest, SelfWindowWithBlockUntrustedMode_AllowsTouch) {
10648 const sp<FakeWindowHandle>& w =
10649 getOccludingWindow(TOUCHED_APP_UID, "T", TouchOcclusionMode::BLOCK_UNTRUSTED);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070010650 mDispatcher->onWindowInfosChanged({{*w->getInfo(), *mTouchWindow->getInfo()}, {}, 0, 0});
Bernardo Rufino6d52e542021-02-15 18:38:10 +000010651
10652 touch();
10653
10654 mTouchWindow->consumeAnyMotionDown();
10655}
10656
Bernardo Rufinoccd3dd62021-02-15 18:47:42 +000010657TEST_F(InputDispatcherUntrustedTouchesTest,
10658 OpacityThresholdIs0AndWindowAboveThreshold_BlocksTouch) {
10659 mDispatcher->setMaximumObscuringOpacityForTouch(0.0f);
10660 const sp<FakeWindowHandle>& w =
10661 getOccludingWindow(APP_B_UID, "B", TouchOcclusionMode::USE_OPACITY, 0.1f);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070010662 mDispatcher->onWindowInfosChanged({{*w->getInfo(), *mTouchWindow->getInfo()}, {}, 0, 0});
Bernardo Rufinoccd3dd62021-02-15 18:47:42 +000010663
10664 touch();
10665
10666 mTouchWindow->assertNoEvents();
10667}
10668
10669TEST_F(InputDispatcherUntrustedTouchesTest, OpacityThresholdIs0AndWindowAtThreshold_AllowsTouch) {
10670 mDispatcher->setMaximumObscuringOpacityForTouch(0.0f);
10671 const sp<FakeWindowHandle>& w =
10672 getOccludingWindow(APP_B_UID, "B", TouchOcclusionMode::USE_OPACITY, 0.0f);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070010673 mDispatcher->onWindowInfosChanged({{*w->getInfo(), *mTouchWindow->getInfo()}, {}, 0, 0});
Bernardo Rufinoccd3dd62021-02-15 18:47:42 +000010674
10675 touch();
10676
10677 mTouchWindow->consumeAnyMotionDown();
10678}
10679
10680TEST_F(InputDispatcherUntrustedTouchesTest,
10681 OpacityThresholdIs1AndWindowBelowThreshold_AllowsTouch) {
10682 mDispatcher->setMaximumObscuringOpacityForTouch(1.0f);
10683 const sp<FakeWindowHandle>& w =
Bernardo Rufino7393d172021-02-26 13:56:11 +000010684 getOccludingWindow(APP_B_UID, "B", TouchOcclusionMode::USE_OPACITY,
10685 OPACITY_ABOVE_THRESHOLD);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070010686 mDispatcher->onWindowInfosChanged({{*w->getInfo(), *mTouchWindow->getInfo()}, {}, 0, 0});
Bernardo Rufino7393d172021-02-26 13:56:11 +000010687
10688 touch();
10689
10690 mTouchWindow->consumeAnyMotionDown();
10691}
10692
10693TEST_F(InputDispatcherUntrustedTouchesTest,
10694 WindowWithBlockUntrustedModeAndWindowWithOpacityBelowFromSameApp_BlocksTouch) {
10695 const sp<FakeWindowHandle>& w1 =
10696 getOccludingWindow(APP_B_UID, "B", TouchOcclusionMode::BLOCK_UNTRUSTED,
10697 OPACITY_BELOW_THRESHOLD);
10698 const sp<FakeWindowHandle>& w2 =
10699 getOccludingWindow(APP_B_UID, "B", TouchOcclusionMode::USE_OPACITY,
10700 OPACITY_BELOW_THRESHOLD);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070010701 mDispatcher->onWindowInfosChanged(
10702 {{*w1->getInfo(), *w2->getInfo(), *mTouchWindow->getInfo()}, {}, 0, 0});
Bernardo Rufino7393d172021-02-26 13:56:11 +000010703
10704 touch();
10705
10706 mTouchWindow->assertNoEvents();
10707}
10708
10709/**
10710 * Window B of BLOCK_UNTRUSTED occlusion mode is enough to block the touch, we're testing that the
10711 * addition of another window (C) of USE_OPACITY occlusion mode and opacity below the threshold
10712 * (which alone would result in allowing touches) does not affect the blocking behavior.
10713 */
10714TEST_F(InputDispatcherUntrustedTouchesTest,
10715 WindowWithBlockUntrustedModeAndWindowWithOpacityBelowFromDifferentApps_BlocksTouch) {
10716 const sp<FakeWindowHandle>& wB =
10717 getOccludingWindow(APP_B_UID, "B", TouchOcclusionMode::BLOCK_UNTRUSTED,
10718 OPACITY_BELOW_THRESHOLD);
10719 const sp<FakeWindowHandle>& wC =
10720 getOccludingWindow(APP_C_UID, "C", TouchOcclusionMode::USE_OPACITY,
10721 OPACITY_BELOW_THRESHOLD);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070010722 mDispatcher->onWindowInfosChanged(
10723 {{*wB->getInfo(), *wC->getInfo(), *mTouchWindow->getInfo()}, {}, 0, 0});
Bernardo Rufino7393d172021-02-26 13:56:11 +000010724
10725 touch();
10726
10727 mTouchWindow->assertNoEvents();
10728}
10729
10730/**
10731 * This test is testing that a window from a different UID but with same application token doesn't
10732 * block the touch. Apps can share the application token for close UI collaboration for example.
10733 */
10734TEST_F(InputDispatcherUntrustedTouchesTest,
10735 WindowWithSameApplicationTokenFromDifferentApp_AllowsTouch) {
10736 const sp<FakeWindowHandle>& w =
10737 getOccludingWindow(APP_B_UID, "B", TouchOcclusionMode::BLOCK_UNTRUSTED);
10738 w->setApplicationToken(mTouchWindow->getApplicationToken());
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070010739 mDispatcher->onWindowInfosChanged({{*w->getInfo(), *mTouchWindow->getInfo()}, {}, 0, 0});
Bernardo Rufinoccd3dd62021-02-15 18:47:42 +000010740
10741 touch();
10742
10743 mTouchWindow->consumeAnyMotionDown();
10744}
10745
arthurhungb89ccb02020-12-30 16:19:01 +080010746class InputDispatcherDragTests : public InputDispatcherTest {
10747protected:
10748 std::shared_ptr<FakeApplicationHandle> mApp;
10749 sp<FakeWindowHandle> mWindow;
10750 sp<FakeWindowHandle> mSecondWindow;
10751 sp<FakeWindowHandle> mDragWindow;
Vaibhav Devmurari6abcf8f2022-06-06 10:08:05 +000010752 sp<FakeWindowHandle> mSpyWindow;
Arthur Hungb75c2aa2022-07-15 09:35:36 +000010753 // Mouse would force no-split, set the id as non-zero to verify if drag state could track it.
10754 static constexpr int32_t MOUSE_POINTER_ID = 1;
arthurhungb89ccb02020-12-30 16:19:01 +080010755
10756 void SetUp() override {
10757 InputDispatcherTest::SetUp();
10758 mApp = std::make_shared<FakeApplicationHandle>();
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -070010759 mWindow = sp<FakeWindowHandle>::make(mApp, mDispatcher, "TestWindow", ADISPLAY_ID_DEFAULT);
arthurhungb89ccb02020-12-30 16:19:01 +080010760 mWindow->setFrame(Rect(0, 0, 100, 100));
arthurhungb89ccb02020-12-30 16:19:01 +080010761
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -070010762 mSecondWindow =
10763 sp<FakeWindowHandle>::make(mApp, mDispatcher, "TestWindow2", ADISPLAY_ID_DEFAULT);
arthurhungb89ccb02020-12-30 16:19:01 +080010764 mSecondWindow->setFrame(Rect(100, 0, 200, 100));
arthurhungb89ccb02020-12-30 16:19:01 +080010765
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -070010766 mSpyWindow =
10767 sp<FakeWindowHandle>::make(mApp, mDispatcher, "SpyWindow", ADISPLAY_ID_DEFAULT);
Vaibhav Devmurari6abcf8f2022-06-06 10:08:05 +000010768 mSpyWindow->setSpy(true);
10769 mSpyWindow->setTrustedOverlay(true);
10770 mSpyWindow->setFrame(Rect(0, 0, 200, 100));
10771
arthurhungb89ccb02020-12-30 16:19:01 +080010772 mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, mApp);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070010773 mDispatcher->onWindowInfosChanged(
10774 {{*mSpyWindow->getInfo(), *mWindow->getInfo(), *mSecondWindow->getInfo()},
10775 {},
10776 0,
10777 0});
arthurhungb89ccb02020-12-30 16:19:01 +080010778 }
10779
Arthur Hungb75c2aa2022-07-15 09:35:36 +000010780 void injectDown(int fromSource = AINPUT_SOURCE_TOUCHSCREEN) {
10781 switch (fromSource) {
10782 case AINPUT_SOURCE_TOUCHSCREEN:
10783 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070010784 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN,
Arthur Hungb75c2aa2022-07-15 09:35:36 +000010785 ADISPLAY_ID_DEFAULT, {50, 50}))
10786 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
10787 break;
10788 case AINPUT_SOURCE_STYLUS:
10789 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070010790 injectMotionEvent(*mDispatcher,
10791 MotionEventBuilder(AMOTION_EVENT_ACTION_DOWN,
10792 AINPUT_SOURCE_STYLUS)
10793 .buttonState(
10794 AMOTION_EVENT_BUTTON_STYLUS_PRIMARY)
10795 .pointer(PointerBuilder(0, ToolType::STYLUS)
10796 .x(50)
10797 .y(50))
10798 .build()));
Arthur Hungb75c2aa2022-07-15 09:35:36 +000010799 break;
10800 case AINPUT_SOURCE_MOUSE:
10801 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070010802 injectMotionEvent(*mDispatcher,
10803 MotionEventBuilder(AMOTION_EVENT_ACTION_DOWN,
10804 AINPUT_SOURCE_MOUSE)
10805 .buttonState(AMOTION_EVENT_BUTTON_PRIMARY)
10806 .pointer(PointerBuilder(MOUSE_POINTER_ID,
10807 ToolType::MOUSE)
10808 .x(50)
10809 .y(50))
10810 .build()));
Arthur Hungb75c2aa2022-07-15 09:35:36 +000010811 break;
10812 default:
10813 FAIL() << "Source " << fromSource << " doesn't support drag and drop";
10814 }
arthurhungb89ccb02020-12-30 16:19:01 +080010815
10816 // Window should receive motion event.
10817 mWindow->consumeMotionDown(ADISPLAY_ID_DEFAULT);
Vaibhav Devmurari6abcf8f2022-06-06 10:08:05 +000010818 // Spy window should also receive motion event
10819 mSpyWindow->consumeMotionDown(ADISPLAY_ID_DEFAULT);
Arthur Hung54745652022-04-20 07:17:41 +000010820 }
10821
10822 // Start performing drag, we will create a drag window and transfer touch to it.
10823 // @param sendDown : if true, send a motion down on first window before perform drag and drop.
10824 // Returns true on success.
Arthur Hungb75c2aa2022-07-15 09:35:36 +000010825 bool startDrag(bool sendDown = true, int fromSource = AINPUT_SOURCE_TOUCHSCREEN) {
Arthur Hung54745652022-04-20 07:17:41 +000010826 if (sendDown) {
Arthur Hungb75c2aa2022-07-15 09:35:36 +000010827 injectDown(fromSource);
Arthur Hung54745652022-04-20 07:17:41 +000010828 }
arthurhungb89ccb02020-12-30 16:19:01 +080010829
10830 // The drag window covers the entire display
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -070010831 mDragWindow =
10832 sp<FakeWindowHandle>::make(mApp, mDispatcher, "DragWindow", ADISPLAY_ID_DEFAULT);
Vaibhav Devmurari6abcf8f2022-06-06 10:08:05 +000010833 mDragWindow->setTouchableRegion(Region{{0, 0, 0, 0}});
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070010834 mDispatcher->onWindowInfosChanged({{*mDragWindow->getInfo(), *mSpyWindow->getInfo(),
10835 *mWindow->getInfo(), *mSecondWindow->getInfo()},
10836 {},
10837 0,
10838 0});
arthurhungb89ccb02020-12-30 16:19:01 +080010839
10840 // Transfer touch focus to the drag window
Arthur Hung54745652022-04-20 07:17:41 +000010841 bool transferred =
Prabir Pradhan367f3432024-02-13 23:05:58 +000010842 mDispatcher->transferTouchGesture(mWindow->getToken(), mDragWindow->getToken(),
10843 /*isDragDrop=*/true);
Arthur Hung54745652022-04-20 07:17:41 +000010844 if (transferred) {
10845 mWindow->consumeMotionCancel();
Prabir Pradhan65455c72024-02-13 21:46:41 +000010846 mDragWindow->consumeMotionDown(ADISPLAY_ID_DEFAULT, AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
Arthur Hung54745652022-04-20 07:17:41 +000010847 }
10848 return transferred;
arthurhungb89ccb02020-12-30 16:19:01 +080010849 }
10850};
10851
10852TEST_F(InputDispatcherDragTests, DragEnterAndDragExit) {
Arthur Hungb75c2aa2022-07-15 09:35:36 +000010853 startDrag();
arthurhungb89ccb02020-12-30 16:19:01 +080010854
10855 // Move on window.
10856 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070010857 injectMotionEvent(*mDispatcher, AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN,
arthurhungb89ccb02020-12-30 16:19:01 +080010858 ADISPLAY_ID_DEFAULT, {50, 50}))
10859 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
Prabir Pradhan65455c72024-02-13 21:46:41 +000010860 mDragWindow->consumeMotionMove(ADISPLAY_ID_DEFAULT, AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
arthurhungb89ccb02020-12-30 16:19:01 +080010861 mWindow->consumeDragEvent(false, 50, 50);
10862 mSecondWindow->assertNoEvents();
10863
10864 // Move to another window.
10865 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070010866 injectMotionEvent(*mDispatcher, AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN,
arthurhungb89ccb02020-12-30 16:19:01 +080010867 ADISPLAY_ID_DEFAULT, {150, 50}))
10868 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
Prabir Pradhan65455c72024-02-13 21:46:41 +000010869 mDragWindow->consumeMotionMove(ADISPLAY_ID_DEFAULT, AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
arthurhungb89ccb02020-12-30 16:19:01 +080010870 mWindow->consumeDragEvent(true, 150, 50);
10871 mSecondWindow->consumeDragEvent(false, 50, 50);
10872
10873 // Move back to original window.
10874 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070010875 injectMotionEvent(*mDispatcher, AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN,
arthurhungb89ccb02020-12-30 16:19:01 +080010876 ADISPLAY_ID_DEFAULT, {50, 50}))
10877 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
Prabir Pradhan65455c72024-02-13 21:46:41 +000010878 mDragWindow->consumeMotionMove(ADISPLAY_ID_DEFAULT, AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
arthurhungb89ccb02020-12-30 16:19:01 +080010879 mWindow->consumeDragEvent(false, 50, 50);
10880 mSecondWindow->consumeDragEvent(true, -50, 50);
10881
10882 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070010883 injectMotionUp(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
10884 {50, 50}))
arthurhungb89ccb02020-12-30 16:19:01 +080010885 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
Prabir Pradhan65455c72024-02-13 21:46:41 +000010886 mDragWindow->consumeMotionUp(ADISPLAY_ID_DEFAULT, AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
arthurhungb89ccb02020-12-30 16:19:01 +080010887 mWindow->assertNoEvents();
10888 mSecondWindow->assertNoEvents();
10889}
10890
Vaibhav Devmurari6abcf8f2022-06-06 10:08:05 +000010891TEST_F(InputDispatcherDragTests, DragEnterAndPointerDownPilfersPointers) {
Arthur Hungb75c2aa2022-07-15 09:35:36 +000010892 startDrag();
Vaibhav Devmurari6abcf8f2022-06-06 10:08:05 +000010893
10894 // No cancel event after drag start
10895 mSpyWindow->assertNoEvents();
10896
10897 const MotionEvent secondFingerDownEvent =
10898 MotionEventBuilder(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
10899 .eventTime(systemTime(SYSTEM_TIME_MONOTONIC))
Siarhei Vishniakou6d73f832022-07-21 17:27:03 -070010900 .pointer(PointerBuilder(/*id=*/0, ToolType::FINGER).x(50).y(50))
10901 .pointer(PointerBuilder(/*id=*/1, ToolType::FINGER).x(60).y(60))
Vaibhav Devmurari6abcf8f2022-06-06 10:08:05 +000010902 .build();
10903 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070010904 injectMotionEvent(*mDispatcher, secondFingerDownEvent, INJECT_EVENT_TIMEOUT,
Vaibhav Devmurari6abcf8f2022-06-06 10:08:05 +000010905 InputEventInjectionSync::WAIT_FOR_RESULT))
10906 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
10907
10908 // Receives cancel for first pointer after next pointer down
10909 mSpyWindow->consumeMotionCancel();
10910 mSpyWindow->consumeMotionDown();
10911
10912 mSpyWindow->assertNoEvents();
10913}
10914
arthurhungf452d0b2021-01-06 00:19:52 +080010915TEST_F(InputDispatcherDragTests, DragAndDrop) {
Arthur Hungb75c2aa2022-07-15 09:35:36 +000010916 startDrag();
arthurhungf452d0b2021-01-06 00:19:52 +080010917
10918 // Move on window.
10919 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070010920 injectMotionEvent(*mDispatcher, AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN,
arthurhungf452d0b2021-01-06 00:19:52 +080010921 ADISPLAY_ID_DEFAULT, {50, 50}))
10922 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
Prabir Pradhan65455c72024-02-13 21:46:41 +000010923 mDragWindow->consumeMotionMove(ADISPLAY_ID_DEFAULT, AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
arthurhungf452d0b2021-01-06 00:19:52 +080010924 mWindow->consumeDragEvent(false, 50, 50);
10925 mSecondWindow->assertNoEvents();
10926
10927 // Move to another window.
10928 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070010929 injectMotionEvent(*mDispatcher, AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN,
arthurhungf452d0b2021-01-06 00:19:52 +080010930 ADISPLAY_ID_DEFAULT, {150, 50}))
10931 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
Prabir Pradhan65455c72024-02-13 21:46:41 +000010932 mDragWindow->consumeMotionMove(ADISPLAY_ID_DEFAULT, AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
arthurhungf452d0b2021-01-06 00:19:52 +080010933 mWindow->consumeDragEvent(true, 150, 50);
10934 mSecondWindow->consumeDragEvent(false, 50, 50);
10935
10936 // drop to another window.
10937 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070010938 injectMotionUp(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
arthurhungf452d0b2021-01-06 00:19:52 +080010939 {150, 50}))
10940 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
Prabir Pradhan65455c72024-02-13 21:46:41 +000010941 mDragWindow->consumeMotionUp(ADISPLAY_ID_DEFAULT, AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
Siarhei Vishniakoua66d65e2023-06-16 10:32:51 -070010942 mFakePolicy->assertDropTargetEquals(*mDispatcher, mSecondWindow->getToken());
arthurhungf452d0b2021-01-06 00:19:52 +080010943 mWindow->assertNoEvents();
10944 mSecondWindow->assertNoEvents();
10945}
10946
Vaibhav Devmurari110ba322023-11-17 10:47:16 +000010947TEST_F(InputDispatcherDragTests, DragAndDropNotCancelledIfSomeOtherPointerIsPilfered) {
10948 startDrag();
10949
10950 // No cancel event after drag start
10951 mSpyWindow->assertNoEvents();
10952
10953 const MotionEvent secondFingerDownEvent =
10954 MotionEventBuilder(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
10955 .eventTime(systemTime(SYSTEM_TIME_MONOTONIC))
10956 .pointer(PointerBuilder(/*id=*/0, ToolType::FINGER).x(50).y(50))
10957 .pointer(PointerBuilder(/*id=*/1, ToolType::FINGER).x(60).y(60))
10958 .build();
10959 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
10960 injectMotionEvent(*mDispatcher, secondFingerDownEvent, INJECT_EVENT_TIMEOUT,
10961 InputEventInjectionSync::WAIT_FOR_RESULT))
10962 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
10963
10964 // Receives cancel for first pointer after next pointer down
10965 mSpyWindow->consumeMotionEvent(WithMotionAction(ACTION_CANCEL));
Siarhei Vishniakou1ff00cc2023-12-13 16:12:13 -080010966 mSpyWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithPointerIds({1})));
Vaibhav Devmurari110ba322023-11-17 10:47:16 +000010967 mDragWindow->consumeMotionEvent(WithMotionAction(ACTION_MOVE));
10968
10969 mSpyWindow->assertNoEvents();
10970
10971 // Spy window calls pilfer pointers
10972 EXPECT_EQ(OK, mDispatcher->pilferPointers(mSpyWindow->getToken()));
10973 mDragWindow->assertNoEvents();
10974
10975 const MotionEvent firstFingerMoveEvent =
Siarhei Vishniakou96a15572023-12-18 10:47:52 -080010976 MotionEventBuilder(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN)
Vaibhav Devmurari110ba322023-11-17 10:47:16 +000010977 .eventTime(systemTime(SYSTEM_TIME_MONOTONIC))
10978 .pointer(PointerBuilder(/*id=*/0, ToolType::FINGER).x(60).y(60))
10979 .pointer(PointerBuilder(/*id=*/1, ToolType::FINGER).x(60).y(60))
10980 .build();
10981 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakou96a15572023-12-18 10:47:52 -080010982 injectMotionEvent(*mDispatcher, firstFingerMoveEvent, INJECT_EVENT_TIMEOUT,
Vaibhav Devmurari110ba322023-11-17 10:47:16 +000010983 InputEventInjectionSync::WAIT_FOR_RESULT))
10984 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
10985
10986 // Drag window should still receive the new event
Prabir Pradhan65455c72024-02-13 21:46:41 +000010987 mDragWindow->consumeMotionEvent(
10988 AllOf(WithMotionAction(ACTION_MOVE), WithFlags(AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE)));
Vaibhav Devmurari110ba322023-11-17 10:47:16 +000010989 mDragWindow->assertNoEvents();
10990}
10991
arthurhung6d4bed92021-03-17 11:59:33 +080010992TEST_F(InputDispatcherDragTests, StylusDragAndDrop) {
Arthur Hungb75c2aa2022-07-15 09:35:36 +000010993 startDrag(true, AINPUT_SOURCE_STYLUS);
arthurhung6d4bed92021-03-17 11:59:33 +080010994
10995 // Move on window and keep button pressed.
10996 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070010997 injectMotionEvent(*mDispatcher,
arthurhung6d4bed92021-03-17 11:59:33 +080010998 MotionEventBuilder(AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_STYLUS)
10999 .buttonState(AMOTION_EVENT_BUTTON_STYLUS_PRIMARY)
Siarhei Vishniakou6d73f832022-07-21 17:27:03 -070011000 .pointer(PointerBuilder(0, ToolType::STYLUS).x(50).y(50))
arthurhung6d4bed92021-03-17 11:59:33 +080011001 .build()))
11002 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
Prabir Pradhan65455c72024-02-13 21:46:41 +000011003 mDragWindow->consumeMotionMove(ADISPLAY_ID_DEFAULT, AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
arthurhung6d4bed92021-03-17 11:59:33 +080011004 mWindow->consumeDragEvent(false, 50, 50);
11005 mSecondWindow->assertNoEvents();
11006
11007 // Move to another window and release button, expect to drop item.
11008 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070011009 injectMotionEvent(*mDispatcher,
arthurhung6d4bed92021-03-17 11:59:33 +080011010 MotionEventBuilder(AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_STYLUS)
11011 .buttonState(0)
Siarhei Vishniakou6d73f832022-07-21 17:27:03 -070011012 .pointer(PointerBuilder(0, ToolType::STYLUS).x(150).y(50))
arthurhung6d4bed92021-03-17 11:59:33 +080011013 .build()))
11014 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
Prabir Pradhan65455c72024-02-13 21:46:41 +000011015 mDragWindow->consumeMotionMove(ADISPLAY_ID_DEFAULT, AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
arthurhung6d4bed92021-03-17 11:59:33 +080011016 mWindow->assertNoEvents();
11017 mSecondWindow->assertNoEvents();
Siarhei Vishniakoua66d65e2023-06-16 10:32:51 -070011018 mFakePolicy->assertDropTargetEquals(*mDispatcher, mSecondWindow->getToken());
arthurhung6d4bed92021-03-17 11:59:33 +080011019
11020 // nothing to the window.
11021 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070011022 injectMotionEvent(*mDispatcher,
arthurhung6d4bed92021-03-17 11:59:33 +080011023 MotionEventBuilder(AMOTION_EVENT_ACTION_UP, AINPUT_SOURCE_STYLUS)
11024 .buttonState(0)
Siarhei Vishniakou6d73f832022-07-21 17:27:03 -070011025 .pointer(PointerBuilder(0, ToolType::STYLUS).x(150).y(50))
arthurhung6d4bed92021-03-17 11:59:33 +080011026 .build()))
11027 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
Prabir Pradhan65455c72024-02-13 21:46:41 +000011028 mDragWindow->consumeMotionUp(ADISPLAY_ID_DEFAULT, AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
arthurhung6d4bed92021-03-17 11:59:33 +080011029 mWindow->assertNoEvents();
11030 mSecondWindow->assertNoEvents();
11031}
11032
Arthur Hung54745652022-04-20 07:17:41 +000011033TEST_F(InputDispatcherDragTests, DragAndDropOnInvalidWindow) {
Arthur Hungb75c2aa2022-07-15 09:35:36 +000011034 startDrag();
Arthur Hung6d0571e2021-04-09 20:18:16 +080011035
11036 // Set second window invisible.
11037 mSecondWindow->setVisible(false);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070011038 mDispatcher->onWindowInfosChanged(
11039 {{*mDragWindow->getInfo(), *mWindow->getInfo(), *mSecondWindow->getInfo()}, {}, 0, 0});
Arthur Hung6d0571e2021-04-09 20:18:16 +080011040
11041 // Move on window.
11042 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070011043 injectMotionEvent(*mDispatcher, AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN,
Arthur Hung6d0571e2021-04-09 20:18:16 +080011044 ADISPLAY_ID_DEFAULT, {50, 50}))
11045 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
Prabir Pradhan65455c72024-02-13 21:46:41 +000011046 mDragWindow->consumeMotionMove(ADISPLAY_ID_DEFAULT, AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
Arthur Hung6d0571e2021-04-09 20:18:16 +080011047 mWindow->consumeDragEvent(false, 50, 50);
11048 mSecondWindow->assertNoEvents();
11049
11050 // Move to another window.
11051 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070011052 injectMotionEvent(*mDispatcher, AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN,
Arthur Hung6d0571e2021-04-09 20:18:16 +080011053 ADISPLAY_ID_DEFAULT, {150, 50}))
11054 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
Prabir Pradhan65455c72024-02-13 21:46:41 +000011055 mDragWindow->consumeMotionMove(ADISPLAY_ID_DEFAULT, AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
Arthur Hung6d0571e2021-04-09 20:18:16 +080011056 mWindow->consumeDragEvent(true, 150, 50);
11057 mSecondWindow->assertNoEvents();
11058
11059 // drop to another window.
11060 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070011061 injectMotionUp(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
Arthur Hung6d0571e2021-04-09 20:18:16 +080011062 {150, 50}))
11063 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
Prabir Pradhan65455c72024-02-13 21:46:41 +000011064 mDragWindow->consumeMotionUp(ADISPLAY_ID_DEFAULT, AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
Siarhei Vishniakoua66d65e2023-06-16 10:32:51 -070011065 mFakePolicy->assertDropTargetEquals(*mDispatcher, nullptr);
Arthur Hung6d0571e2021-04-09 20:18:16 +080011066 mWindow->assertNoEvents();
11067 mSecondWindow->assertNoEvents();
11068}
11069
Arthur Hung54745652022-04-20 07:17:41 +000011070TEST_F(InputDispatcherDragTests, NoDragAndDropWhenMultiFingers) {
Arthur Hungb75c2aa2022-07-15 09:35:36 +000011071 // Ensure window could track pointerIds if it didn't support split touch.
11072 mWindow->setPreventSplitting(true);
11073
Arthur Hung54745652022-04-20 07:17:41 +000011074 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070011075 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
Arthur Hung54745652022-04-20 07:17:41 +000011076 {50, 50}))
11077 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
11078 mWindow->consumeMotionDown(ADISPLAY_ID_DEFAULT);
11079
11080 const MotionEvent secondFingerDownEvent =
11081 MotionEventBuilder(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
11082 .displayId(ADISPLAY_ID_DEFAULT)
11083 .eventTime(systemTime(SYSTEM_TIME_MONOTONIC))
Siarhei Vishniakou6d73f832022-07-21 17:27:03 -070011084 .pointer(PointerBuilder(/*id=*/0, ToolType::FINGER).x(50).y(50))
11085 .pointer(PointerBuilder(/*id=*/1, ToolType::FINGER).x(75).y(50))
Arthur Hung54745652022-04-20 07:17:41 +000011086 .build();
11087 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070011088 injectMotionEvent(*mDispatcher, secondFingerDownEvent, INJECT_EVENT_TIMEOUT,
Arthur Hung54745652022-04-20 07:17:41 +000011089 InputEventInjectionSync::WAIT_FOR_RESULT))
11090 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
Harry Cutts33476232023-01-30 19:57:29 +000011091 mWindow->consumeMotionPointerDown(/*pointerIndex=*/1);
Arthur Hung54745652022-04-20 07:17:41 +000011092
11093 // Should not perform drag and drop when window has multi fingers.
Arthur Hungb75c2aa2022-07-15 09:35:36 +000011094 ASSERT_FALSE(startDrag(false));
Arthur Hung54745652022-04-20 07:17:41 +000011095}
11096
11097TEST_F(InputDispatcherDragTests, DragAndDropWhenSplitTouch) {
11098 // First down on second window.
11099 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070011100 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
Arthur Hung54745652022-04-20 07:17:41 +000011101 {150, 50}))
11102 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
11103
11104 mSecondWindow->consumeMotionDown(ADISPLAY_ID_DEFAULT);
11105
11106 // Second down on first window.
11107 const MotionEvent secondFingerDownEvent =
11108 MotionEventBuilder(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
11109 .displayId(ADISPLAY_ID_DEFAULT)
11110 .eventTime(systemTime(SYSTEM_TIME_MONOTONIC))
Siarhei Vishniakou6d73f832022-07-21 17:27:03 -070011111 .pointer(PointerBuilder(/*id=*/0, ToolType::FINGER).x(150).y(50))
11112 .pointer(PointerBuilder(/*id=*/1, ToolType::FINGER).x(50).y(50))
Arthur Hung54745652022-04-20 07:17:41 +000011113 .build();
11114 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070011115 injectMotionEvent(*mDispatcher, secondFingerDownEvent, INJECT_EVENT_TIMEOUT,
Arthur Hung54745652022-04-20 07:17:41 +000011116 InputEventInjectionSync::WAIT_FOR_RESULT))
11117 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
11118 mWindow->consumeMotionDown(ADISPLAY_ID_DEFAULT);
Prabir Pradhan9d5f9ce2024-01-24 00:03:41 +000011119 mSecondWindow->consumeMotionMove(ADISPLAY_ID_DEFAULT);
Arthur Hung54745652022-04-20 07:17:41 +000011120
11121 // Perform drag and drop from first window.
Arthur Hungb75c2aa2022-07-15 09:35:36 +000011122 ASSERT_TRUE(startDrag(false));
Arthur Hung54745652022-04-20 07:17:41 +000011123
11124 // Move on window.
11125 const MotionEvent secondFingerMoveEvent =
11126 MotionEventBuilder(AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN)
11127 .eventTime(systemTime(SYSTEM_TIME_MONOTONIC))
Siarhei Vishniakou6d73f832022-07-21 17:27:03 -070011128 .pointer(PointerBuilder(/*id=*/0, ToolType::FINGER).x(150).y(50))
11129 .pointer(PointerBuilder(/*id=*/1, ToolType::FINGER).x(50).y(50))
Arthur Hung54745652022-04-20 07:17:41 +000011130 .build();
11131 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070011132 injectMotionEvent(*mDispatcher, secondFingerMoveEvent, INJECT_EVENT_TIMEOUT,
Arthur Hung54745652022-04-20 07:17:41 +000011133 InputEventInjectionSync::WAIT_FOR_RESULT));
Prabir Pradhan65455c72024-02-13 21:46:41 +000011134 mDragWindow->consumeMotionMove(ADISPLAY_ID_DEFAULT, AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
Arthur Hung54745652022-04-20 07:17:41 +000011135 mWindow->consumeDragEvent(false, 50, 50);
11136 mSecondWindow->consumeMotionMove();
11137
11138 // Release the drag pointer should perform drop.
11139 const MotionEvent secondFingerUpEvent =
11140 MotionEventBuilder(POINTER_1_UP, AINPUT_SOURCE_TOUCHSCREEN)
11141 .eventTime(systemTime(SYSTEM_TIME_MONOTONIC))
Siarhei Vishniakou6d73f832022-07-21 17:27:03 -070011142 .pointer(PointerBuilder(/*id=*/0, ToolType::FINGER).x(150).y(50))
11143 .pointer(PointerBuilder(/*id=*/1, ToolType::FINGER).x(50).y(50))
Arthur Hung54745652022-04-20 07:17:41 +000011144 .build();
11145 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070011146 injectMotionEvent(*mDispatcher, secondFingerUpEvent, INJECT_EVENT_TIMEOUT,
Arthur Hung54745652022-04-20 07:17:41 +000011147 InputEventInjectionSync::WAIT_FOR_RESULT));
Prabir Pradhan65455c72024-02-13 21:46:41 +000011148 mDragWindow->consumeMotionUp(ADISPLAY_ID_DEFAULT, AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
Siarhei Vishniakoua66d65e2023-06-16 10:32:51 -070011149 mFakePolicy->assertDropTargetEquals(*mDispatcher, mWindow->getToken());
Arthur Hung54745652022-04-20 07:17:41 +000011150 mWindow->assertNoEvents();
11151 mSecondWindow->consumeMotionMove();
11152}
11153
Arthur Hung3915c1f2022-05-31 07:17:17 +000011154TEST_F(InputDispatcherDragTests, DragAndDropWhenMultiDisplays) {
Arthur Hungb75c2aa2022-07-15 09:35:36 +000011155 startDrag();
Arthur Hung3915c1f2022-05-31 07:17:17 +000011156
11157 // Update window of second display.
11158 sp<FakeWindowHandle> windowInSecondary =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -070011159 sp<FakeWindowHandle>::make(mApp, mDispatcher, "D_2", SECOND_DISPLAY_ID);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070011160 mDispatcher->onWindowInfosChanged(
11161 {{*mDragWindow->getInfo(), *mSpyWindow->getInfo(), *mWindow->getInfo(),
11162 *mSecondWindow->getInfo(), *windowInSecondary->getInfo()},
11163 {},
11164 0,
11165 0});
Arthur Hung3915c1f2022-05-31 07:17:17 +000011166
11167 // Let second display has a touch state.
11168 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070011169 injectMotionEvent(*mDispatcher,
Arthur Hung3915c1f2022-05-31 07:17:17 +000011170 MotionEventBuilder(AMOTION_EVENT_ACTION_DOWN,
11171 AINPUT_SOURCE_TOUCHSCREEN)
11172 .displayId(SECOND_DISPLAY_ID)
Siarhei Vishniakou6d73f832022-07-21 17:27:03 -070011173 .pointer(PointerBuilder(0, ToolType::FINGER).x(100).y(100))
Arthur Hung3915c1f2022-05-31 07:17:17 +000011174 .build()));
Prabir Pradhan7662a8d2023-12-15 01:58:14 +000011175 windowInSecondary->consumeMotionDown(SECOND_DISPLAY_ID, /*expectedFlag=*/0);
Arthur Hung3915c1f2022-05-31 07:17:17 +000011176 // Update window again.
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070011177 mDispatcher->onWindowInfosChanged(
11178 {{*mDragWindow->getInfo(), *mSpyWindow->getInfo(), *mWindow->getInfo(),
11179 *mSecondWindow->getInfo(), *windowInSecondary->getInfo()},
11180 {},
11181 0,
11182 0});
Arthur Hung3915c1f2022-05-31 07:17:17 +000011183
11184 // Move on window.
11185 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070011186 injectMotionEvent(*mDispatcher, AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN,
Arthur Hung3915c1f2022-05-31 07:17:17 +000011187 ADISPLAY_ID_DEFAULT, {50, 50}))
11188 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
Prabir Pradhan65455c72024-02-13 21:46:41 +000011189 mDragWindow->consumeMotionMove(ADISPLAY_ID_DEFAULT, AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
Arthur Hung3915c1f2022-05-31 07:17:17 +000011190 mWindow->consumeDragEvent(false, 50, 50);
11191 mSecondWindow->assertNoEvents();
11192
11193 // Move to another window.
11194 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070011195 injectMotionEvent(*mDispatcher, AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN,
Arthur Hung3915c1f2022-05-31 07:17:17 +000011196 ADISPLAY_ID_DEFAULT, {150, 50}))
11197 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
Prabir Pradhan65455c72024-02-13 21:46:41 +000011198 mDragWindow->consumeMotionMove(ADISPLAY_ID_DEFAULT, AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
Arthur Hung3915c1f2022-05-31 07:17:17 +000011199 mWindow->consumeDragEvent(true, 150, 50);
11200 mSecondWindow->consumeDragEvent(false, 50, 50);
11201
11202 // drop to another window.
11203 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070011204 injectMotionUp(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
Arthur Hung3915c1f2022-05-31 07:17:17 +000011205 {150, 50}))
11206 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
Prabir Pradhan65455c72024-02-13 21:46:41 +000011207 mDragWindow->consumeMotionUp(ADISPLAY_ID_DEFAULT, AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
Siarhei Vishniakoua66d65e2023-06-16 10:32:51 -070011208 mFakePolicy->assertDropTargetEquals(*mDispatcher, mSecondWindow->getToken());
Arthur Hung3915c1f2022-05-31 07:17:17 +000011209 mWindow->assertNoEvents();
11210 mSecondWindow->assertNoEvents();
11211}
11212
Arthur Hungb75c2aa2022-07-15 09:35:36 +000011213TEST_F(InputDispatcherDragTests, MouseDragAndDrop) {
11214 startDrag(true, AINPUT_SOURCE_MOUSE);
11215 // Move on window.
11216 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070011217 injectMotionEvent(*mDispatcher,
Arthur Hungb75c2aa2022-07-15 09:35:36 +000011218 MotionEventBuilder(AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_MOUSE)
11219 .buttonState(AMOTION_EVENT_BUTTON_PRIMARY)
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070011220 .pointer(PointerBuilder(MOUSE_POINTER_ID, ToolType::MOUSE)
Arthur Hungb75c2aa2022-07-15 09:35:36 +000011221 .x(50)
11222 .y(50))
11223 .build()))
11224 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
Prabir Pradhan65455c72024-02-13 21:46:41 +000011225 mDragWindow->consumeMotionMove(ADISPLAY_ID_DEFAULT, AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
Arthur Hungb75c2aa2022-07-15 09:35:36 +000011226 mWindow->consumeDragEvent(false, 50, 50);
11227 mSecondWindow->assertNoEvents();
11228
11229 // Move to another window.
11230 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070011231 injectMotionEvent(*mDispatcher,
Arthur Hungb75c2aa2022-07-15 09:35:36 +000011232 MotionEventBuilder(AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_MOUSE)
11233 .buttonState(AMOTION_EVENT_BUTTON_PRIMARY)
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070011234 .pointer(PointerBuilder(MOUSE_POINTER_ID, ToolType::MOUSE)
Arthur Hungb75c2aa2022-07-15 09:35:36 +000011235 .x(150)
11236 .y(50))
11237 .build()))
11238 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
Prabir Pradhan65455c72024-02-13 21:46:41 +000011239 mDragWindow->consumeMotionMove(ADISPLAY_ID_DEFAULT, AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
Arthur Hungb75c2aa2022-07-15 09:35:36 +000011240 mWindow->consumeDragEvent(true, 150, 50);
11241 mSecondWindow->consumeDragEvent(false, 50, 50);
11242
11243 // drop to another window.
11244 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070011245 injectMotionEvent(*mDispatcher,
Arthur Hungb75c2aa2022-07-15 09:35:36 +000011246 MotionEventBuilder(AMOTION_EVENT_ACTION_UP, AINPUT_SOURCE_MOUSE)
11247 .buttonState(0)
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070011248 .pointer(PointerBuilder(MOUSE_POINTER_ID, ToolType::MOUSE)
Arthur Hungb75c2aa2022-07-15 09:35:36 +000011249 .x(150)
11250 .y(50))
11251 .build()))
11252 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
Prabir Pradhan65455c72024-02-13 21:46:41 +000011253 mDragWindow->consumeMotionUp(ADISPLAY_ID_DEFAULT, AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
Siarhei Vishniakoua66d65e2023-06-16 10:32:51 -070011254 mFakePolicy->assertDropTargetEquals(*mDispatcher, mSecondWindow->getToken());
Arthur Hungb75c2aa2022-07-15 09:35:36 +000011255 mWindow->assertNoEvents();
11256 mSecondWindow->assertNoEvents();
11257}
11258
Linnan Li5af92f92023-07-14 14:36:22 +080011259/**
11260 * Start drag and drop with a pointer whose id is not 0, cancel the current touch, and ensure drag
11261 * and drop is also canceled. Then inject a simple gesture, and ensure dispatcher does not crash.
11262 */
11263TEST_F(InputDispatcherDragTests, DragAndDropFinishedWhenCancelCurrentTouch) {
11264 // Down on second window
11265 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
11266 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
11267 {150, 50}))
11268 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
11269
11270 ASSERT_NO_FATAL_FAILURE(mSecondWindow->consumeMotionDown());
11271 ASSERT_NO_FATAL_FAILURE(mSpyWindow->consumeMotionDown());
11272
11273 // Down on first window
11274 const MotionEvent secondFingerDownEvent =
11275 MotionEventBuilder(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
11276 .displayId(ADISPLAY_ID_DEFAULT)
11277 .pointer(PointerBuilder(/*id=*/0, ToolType::FINGER).x(150).y(50))
11278 .pointer(PointerBuilder(/*id=*/1, ToolType::FINGER).x(50).y(50))
11279 .build();
11280 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
11281 injectMotionEvent(*mDispatcher, secondFingerDownEvent, INJECT_EVENT_TIMEOUT,
11282 InputEventInjectionSync::WAIT_FOR_RESULT))
11283 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
11284 ASSERT_NO_FATAL_FAILURE(mWindow->consumeMotionDown());
11285 ASSERT_NO_FATAL_FAILURE(mSecondWindow->consumeMotionMove());
11286 ASSERT_NO_FATAL_FAILURE(mSpyWindow->consumeMotionPointerDown(1));
11287
11288 // Start drag on first window
11289 ASSERT_TRUE(startDrag(/*sendDown=*/false, AINPUT_SOURCE_TOUCHSCREEN));
11290
11291 // Trigger cancel
11292 mDispatcher->cancelCurrentTouch();
11293 ASSERT_NO_FATAL_FAILURE(mSecondWindow->consumeMotionCancel());
Prabir Pradhan65455c72024-02-13 21:46:41 +000011294 ASSERT_NO_FATAL_FAILURE(mDragWindow->consumeMotionCancel(ADISPLAY_ID_DEFAULT,
11295 AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE));
Linnan Li5af92f92023-07-14 14:36:22 +080011296 ASSERT_NO_FATAL_FAILURE(mSpyWindow->consumeMotionCancel());
11297
11298 ASSERT_TRUE(mDispatcher->waitForIdle());
11299 // The D&D finished with nullptr
11300 mFakePolicy->assertDropTargetEquals(*mDispatcher, nullptr);
11301
11302 // Remove drag window
11303 mDispatcher->onWindowInfosChanged({{*mWindow->getInfo(), *mSecondWindow->getInfo()}, {}, 0, 0});
11304
11305 // Inject a simple gesture, ensure dispatcher not crashed
11306 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
11307 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
11308 PointF{50, 50}))
11309 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
11310 ASSERT_NO_FATAL_FAILURE(mWindow->consumeMotionDown());
11311
11312 const MotionEvent moveEvent =
11313 MotionEventBuilder(AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN)
11314 .displayId(ADISPLAY_ID_DEFAULT)
11315 .pointer(PointerBuilder(/*id=*/0, ToolType::FINGER).x(50).y(50))
11316 .build();
11317 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
11318 injectMotionEvent(*mDispatcher, moveEvent, INJECT_EVENT_TIMEOUT,
11319 InputEventInjectionSync::WAIT_FOR_RESULT))
11320 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
11321 ASSERT_NO_FATAL_FAILURE(mWindow->consumeMotionMove());
11322
11323 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
11324 injectMotionUp(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
11325 {50, 50}))
11326 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
11327 ASSERT_NO_FATAL_FAILURE(mWindow->consumeMotionUp());
11328}
11329
Prabir Pradhan9cd9eb62023-11-22 17:58:06 +000011330TEST_F(InputDispatcherDragTests, NoDragAndDropWithHoveringPointer) {
11331 // Start hovering over the window.
11332 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
11333 injectMotionEvent(*mDispatcher, ACTION_HOVER_ENTER, AINPUT_SOURCE_MOUSE,
11334 ADISPLAY_ID_DEFAULT, {50, 50}));
11335
11336 ASSERT_NO_FATAL_FAILURE(mWindow->consumeMotionEvent(WithMotionAction(ACTION_HOVER_ENTER)));
11337 ASSERT_NO_FATAL_FAILURE(mSpyWindow->consumeMotionEvent(WithMotionAction(ACTION_HOVER_ENTER)));
11338
11339 ASSERT_FALSE(startDrag(/*sendDown=*/false))
11340 << "Drag and drop should not work with a hovering pointer";
11341}
11342
Vishnu Nair062a8672021-09-03 16:07:44 -070011343class InputDispatcherDropInputFeatureTest : public InputDispatcherTest {};
11344
11345TEST_F(InputDispatcherDropInputFeatureTest, WindowDropsInput) {
11346 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -070011347 sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher,
11348 "Test window", ADISPLAY_ID_DEFAULT);
Prabir Pradhan51e7db02022-02-07 06:02:57 -080011349 window->setDropInput(true);
Vishnu Nair062a8672021-09-03 16:07:44 -070011350 mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application);
11351 window->setFocusable(true);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070011352 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Vishnu Nair062a8672021-09-03 16:07:44 -070011353 setFocusedWindow(window);
Harry Cutts33476232023-01-30 19:57:29 +000011354 window->consumeFocusEvent(/*hasFocus=*/true, /*inTouchMode=*/true);
Vishnu Nair062a8672021-09-03 16:07:44 -070011355
11356 // With the flag set, window should not get any input
Prabir Pradhan678438e2023-04-13 19:32:51 +000011357 mDispatcher->notifyKey(generateKeyArgs(AKEY_EVENT_ACTION_DOWN, ADISPLAY_ID_DEFAULT));
Vishnu Nair062a8672021-09-03 16:07:44 -070011358 window->assertNoEvents();
11359
Prabir Pradhan678438e2023-04-13 19:32:51 +000011360 mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_DOWN,
11361 AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT));
Siarhei Vishniakou5c02a712023-05-15 15:45:02 -070011362 mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN,
11363 ADISPLAY_ID_DEFAULT));
Siarhei Vishniakoud908f5a2023-11-16 10:25:12 -080011364 mDispatcher->waitForIdle();
Vishnu Nair062a8672021-09-03 16:07:44 -070011365 window->assertNoEvents();
11366
11367 // With the flag cleared, the window should get input
Prabir Pradhan51e7db02022-02-07 06:02:57 -080011368 window->setDropInput(false);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070011369 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Vishnu Nair062a8672021-09-03 16:07:44 -070011370
Prabir Pradhan678438e2023-04-13 19:32:51 +000011371 mDispatcher->notifyKey(generateKeyArgs(AKEY_EVENT_ACTION_UP, ADISPLAY_ID_DEFAULT));
Vishnu Nair062a8672021-09-03 16:07:44 -070011372 window->consumeKeyUp(ADISPLAY_ID_DEFAULT);
11373
Prabir Pradhan678438e2023-04-13 19:32:51 +000011374 mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_DOWN,
11375 AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT));
Vishnu Nair062a8672021-09-03 16:07:44 -070011376 window->consumeMotionDown(ADISPLAY_ID_DEFAULT);
11377 window->assertNoEvents();
11378}
11379
11380TEST_F(InputDispatcherDropInputFeatureTest, ObscuredWindowDropsInput) {
11381 std::shared_ptr<FakeApplicationHandle> obscuringApplication =
11382 std::make_shared<FakeApplicationHandle>();
11383 sp<FakeWindowHandle> obscuringWindow =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -070011384 sp<FakeWindowHandle>::make(obscuringApplication, mDispatcher, "obscuringWindow",
11385 ADISPLAY_ID_DEFAULT);
Vishnu Nair062a8672021-09-03 16:07:44 -070011386 obscuringWindow->setFrame(Rect(0, 0, 50, 50));
Prabir Pradhanaeebeb42023-06-13 19:53:03 +000011387 obscuringWindow->setOwnerInfo(gui::Pid{111}, gui::Uid{111});
Prabir Pradhan4d5c52f2022-01-31 08:52:10 -080011388 obscuringWindow->setTouchable(false);
Vishnu Nair062a8672021-09-03 16:07:44 -070011389 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -070011390 sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher,
11391 "Test window", ADISPLAY_ID_DEFAULT);
Prabir Pradhan51e7db02022-02-07 06:02:57 -080011392 window->setDropInputIfObscured(true);
Prabir Pradhanaeebeb42023-06-13 19:53:03 +000011393 window->setOwnerInfo(gui::Pid{222}, gui::Uid{222});
Vishnu Nair062a8672021-09-03 16:07:44 -070011394 mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application);
11395 window->setFocusable(true);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070011396 mDispatcher->onWindowInfosChanged(
11397 {{*obscuringWindow->getInfo(), *window->getInfo()}, {}, 0, 0});
Vishnu Nair062a8672021-09-03 16:07:44 -070011398 setFocusedWindow(window);
Harry Cutts33476232023-01-30 19:57:29 +000011399 window->consumeFocusEvent(/*hasFocus=*/true, /*inTouchMode=*/true);
Vishnu Nair062a8672021-09-03 16:07:44 -070011400
11401 // With the flag set, window should not get any input
Prabir Pradhan678438e2023-04-13 19:32:51 +000011402 mDispatcher->notifyKey(generateKeyArgs(AKEY_EVENT_ACTION_DOWN, ADISPLAY_ID_DEFAULT));
Vishnu Nair062a8672021-09-03 16:07:44 -070011403 window->assertNoEvents();
11404
Prabir Pradhan678438e2023-04-13 19:32:51 +000011405 mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_DOWN,
11406 AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT));
Siarhei Vishniakou5c02a712023-05-15 15:45:02 -070011407 mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN,
11408 ADISPLAY_ID_DEFAULT));
Vishnu Nair062a8672021-09-03 16:07:44 -070011409 window->assertNoEvents();
11410
11411 // With the flag cleared, the window should get input
Prabir Pradhan51e7db02022-02-07 06:02:57 -080011412 window->setDropInputIfObscured(false);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070011413 mDispatcher->onWindowInfosChanged(
11414 {{*obscuringWindow->getInfo(), *window->getInfo()}, {}, 0, 0});
Vishnu Nair062a8672021-09-03 16:07:44 -070011415
Prabir Pradhan678438e2023-04-13 19:32:51 +000011416 mDispatcher->notifyKey(generateKeyArgs(AKEY_EVENT_ACTION_UP, ADISPLAY_ID_DEFAULT));
Vishnu Nair062a8672021-09-03 16:07:44 -070011417 window->consumeKeyUp(ADISPLAY_ID_DEFAULT);
11418
Prabir Pradhan678438e2023-04-13 19:32:51 +000011419 mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_DOWN,
11420 AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT));
Vishnu Nair062a8672021-09-03 16:07:44 -070011421 window->consumeMotionDown(ADISPLAY_ID_DEFAULT, AMOTION_EVENT_FLAG_WINDOW_IS_PARTIALLY_OBSCURED);
11422 window->assertNoEvents();
11423}
11424
11425TEST_F(InputDispatcherDropInputFeatureTest, UnobscuredWindowGetsInput) {
11426 std::shared_ptr<FakeApplicationHandle> obscuringApplication =
11427 std::make_shared<FakeApplicationHandle>();
11428 sp<FakeWindowHandle> obscuringWindow =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -070011429 sp<FakeWindowHandle>::make(obscuringApplication, mDispatcher, "obscuringWindow",
11430 ADISPLAY_ID_DEFAULT);
Vishnu Nair062a8672021-09-03 16:07:44 -070011431 obscuringWindow->setFrame(Rect(0, 0, 50, 50));
Prabir Pradhanaeebeb42023-06-13 19:53:03 +000011432 obscuringWindow->setOwnerInfo(gui::Pid{111}, gui::Uid{111});
Prabir Pradhan4d5c52f2022-01-31 08:52:10 -080011433 obscuringWindow->setTouchable(false);
Vishnu Nair062a8672021-09-03 16:07:44 -070011434 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -070011435 sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher,
11436 "Test window", ADISPLAY_ID_DEFAULT);
Prabir Pradhan51e7db02022-02-07 06:02:57 -080011437 window->setDropInputIfObscured(true);
Prabir Pradhanaeebeb42023-06-13 19:53:03 +000011438 window->setOwnerInfo(gui::Pid{222}, gui::Uid{222});
Vishnu Nair062a8672021-09-03 16:07:44 -070011439 mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application);
11440 window->setFocusable(true);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070011441 mDispatcher->onWindowInfosChanged(
11442 {{*obscuringWindow->getInfo(), *window->getInfo()}, {}, 0, 0});
Vishnu Nair062a8672021-09-03 16:07:44 -070011443 setFocusedWindow(window);
Harry Cutts33476232023-01-30 19:57:29 +000011444 window->consumeFocusEvent(/*hasFocus=*/true, /*inTouchMode=*/true);
Vishnu Nair062a8672021-09-03 16:07:44 -070011445
11446 // With the flag set, window should not get any input
Prabir Pradhan678438e2023-04-13 19:32:51 +000011447 mDispatcher->notifyKey(generateKeyArgs(AKEY_EVENT_ACTION_DOWN, ADISPLAY_ID_DEFAULT));
Vishnu Nair062a8672021-09-03 16:07:44 -070011448 window->assertNoEvents();
11449
Prabir Pradhan678438e2023-04-13 19:32:51 +000011450 mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_DOWN,
11451 AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT));
Siarhei Vishniakou5c02a712023-05-15 15:45:02 -070011452 mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN,
11453 ADISPLAY_ID_DEFAULT));
Vishnu Nair062a8672021-09-03 16:07:44 -070011454 window->assertNoEvents();
11455
11456 // When the window is no longer obscured because it went on top, it should get input
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070011457 mDispatcher->onWindowInfosChanged(
11458 {{*window->getInfo(), *obscuringWindow->getInfo()}, {}, 0, 0});
Vishnu Nair062a8672021-09-03 16:07:44 -070011459
Prabir Pradhan678438e2023-04-13 19:32:51 +000011460 mDispatcher->notifyKey(generateKeyArgs(AKEY_EVENT_ACTION_UP, ADISPLAY_ID_DEFAULT));
Vishnu Nair062a8672021-09-03 16:07:44 -070011461 window->consumeKeyUp(ADISPLAY_ID_DEFAULT);
11462
Prabir Pradhan678438e2023-04-13 19:32:51 +000011463 mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_DOWN,
11464 AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT));
Vishnu Nair062a8672021-09-03 16:07:44 -070011465 window->consumeMotionDown(ADISPLAY_ID_DEFAULT);
11466 window->assertNoEvents();
11467}
11468
Antonio Kantekf16f2832021-09-28 04:39:20 +000011469class InputDispatcherTouchModeChangedTests : public InputDispatcherTest {
11470protected:
11471 std::shared_ptr<FakeApplicationHandle> mApp;
Antonio Kantek15beb512022-06-13 22:35:41 +000011472 std::shared_ptr<FakeApplicationHandle> mSecondaryApp;
Antonio Kantekf16f2832021-09-28 04:39:20 +000011473 sp<FakeWindowHandle> mWindow;
11474 sp<FakeWindowHandle> mSecondWindow;
Antonio Kantek15beb512022-06-13 22:35:41 +000011475 sp<FakeWindowHandle> mThirdWindow;
Antonio Kantekf16f2832021-09-28 04:39:20 +000011476
11477 void SetUp() override {
11478 InputDispatcherTest::SetUp();
11479
11480 mApp = std::make_shared<FakeApplicationHandle>();
Antonio Kantek15beb512022-06-13 22:35:41 +000011481 mSecondaryApp = std::make_shared<FakeApplicationHandle>();
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -070011482 mWindow = sp<FakeWindowHandle>::make(mApp, mDispatcher, "TestWindow", ADISPLAY_ID_DEFAULT);
Antonio Kantekf16f2832021-09-28 04:39:20 +000011483 mWindow->setFocusable(true);
Antonio Kantek26defcf2022-02-08 01:12:27 +000011484 setFocusedWindow(mWindow);
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -070011485 mSecondWindow =
11486 sp<FakeWindowHandle>::make(mApp, mDispatcher, "TestWindow2", ADISPLAY_ID_DEFAULT);
Antonio Kantekf16f2832021-09-28 04:39:20 +000011487 mSecondWindow->setFocusable(true);
Antonio Kantek15beb512022-06-13 22:35:41 +000011488 mThirdWindow =
11489 sp<FakeWindowHandle>::make(mSecondaryApp, mDispatcher,
11490 "TestWindow3_SecondaryDisplay", SECOND_DISPLAY_ID);
11491 mThirdWindow->setFocusable(true);
Antonio Kantekf16f2832021-09-28 04:39:20 +000011492
11493 mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, mApp);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070011494 mDispatcher->onWindowInfosChanged(
11495 {{*mWindow->getInfo(), *mSecondWindow->getInfo(), *mThirdWindow->getInfo()},
11496 {},
11497 0,
11498 0});
Antonio Kantek15beb512022-06-13 22:35:41 +000011499 mThirdWindow->setOwnerInfo(SECONDARY_WINDOW_PID, SECONDARY_WINDOW_UID);
Antonio Kantekf16f2832021-09-28 04:39:20 +000011500 mWindow->consumeFocusEvent(true);
Antonio Kantek26defcf2022-02-08 01:12:27 +000011501
Antonio Kantek15beb512022-06-13 22:35:41 +000011502 // Set main display initial touch mode to InputDispatcher::kDefaultInTouchMode.
Prabir Pradhan5735a322022-04-11 17:23:34 +000011503 if (mDispatcher->setInTouchMode(InputDispatcher::kDefaultInTouchMode, WINDOW_PID,
Harry Cutts33476232023-01-30 19:57:29 +000011504 WINDOW_UID, /*hasPermission=*/true, ADISPLAY_ID_DEFAULT)) {
Antonio Kantek48710e42022-03-24 14:19:30 -070011505 mWindow->consumeTouchModeEvent(InputDispatcher::kDefaultInTouchMode);
11506 mSecondWindow->consumeTouchModeEvent(InputDispatcher::kDefaultInTouchMode);
Antonio Kantek15beb512022-06-13 22:35:41 +000011507 mThirdWindow->assertNoEvents();
11508 }
11509
11510 // Set secondary display initial touch mode to InputDispatcher::kDefaultInTouchMode.
11511 if (mDispatcher->setInTouchMode(InputDispatcher::kDefaultInTouchMode, SECONDARY_WINDOW_PID,
Harry Cutts33476232023-01-30 19:57:29 +000011512 SECONDARY_WINDOW_UID, /*hasPermission=*/true,
Antonio Kantek15beb512022-06-13 22:35:41 +000011513 SECOND_DISPLAY_ID)) {
11514 mWindow->assertNoEvents();
11515 mSecondWindow->assertNoEvents();
11516 mThirdWindow->consumeTouchModeEvent(InputDispatcher::kDefaultInTouchMode);
Antonio Kantek48710e42022-03-24 14:19:30 -070011517 }
Antonio Kantekf16f2832021-09-28 04:39:20 +000011518 }
11519
Prabir Pradhanaeebeb42023-06-13 19:53:03 +000011520 void changeAndVerifyTouchModeInMainDisplayOnly(bool inTouchMode, gui::Pid pid, gui::Uid uid,
Antonio Kantek15beb512022-06-13 22:35:41 +000011521 bool hasPermission) {
Antonio Kanteka042c022022-07-06 16:51:07 -070011522 ASSERT_TRUE(mDispatcher->setInTouchMode(inTouchMode, pid, uid, hasPermission,
11523 ADISPLAY_ID_DEFAULT));
Antonio Kantekf16f2832021-09-28 04:39:20 +000011524 mWindow->consumeTouchModeEvent(inTouchMode);
11525 mSecondWindow->consumeTouchModeEvent(inTouchMode);
Antonio Kantek15beb512022-06-13 22:35:41 +000011526 mThirdWindow->assertNoEvents();
Antonio Kantekf16f2832021-09-28 04:39:20 +000011527 }
11528};
11529
Antonio Kantek26defcf2022-02-08 01:12:27 +000011530TEST_F(InputDispatcherTouchModeChangedTests, FocusedWindowCanChangeTouchMode) {
Antonio Kantekea47acb2021-12-23 12:41:25 -080011531 const WindowInfo& windowInfo = *mWindow->getInfo();
Antonio Kantek15beb512022-06-13 22:35:41 +000011532 changeAndVerifyTouchModeInMainDisplayOnly(!InputDispatcher::kDefaultInTouchMode,
11533 windowInfo.ownerPid, windowInfo.ownerUid,
Harry Cutts33476232023-01-30 19:57:29 +000011534 /* hasPermission=*/false);
Antonio Kantekf16f2832021-09-28 04:39:20 +000011535}
11536
Antonio Kantek26defcf2022-02-08 01:12:27 +000011537TEST_F(InputDispatcherTouchModeChangedTests, NonFocusedWindowOwnerCannotChangeTouchMode) {
11538 const WindowInfo& windowInfo = *mWindow->getInfo();
Prabir Pradhanaeebeb42023-06-13 19:53:03 +000011539 gui::Pid ownerPid = windowInfo.ownerPid;
Prabir Pradhan8a5c41d2023-06-08 19:13:46 +000011540 gui::Uid ownerUid = windowInfo.ownerUid;
Prabir Pradhanaeebeb42023-06-13 19:53:03 +000011541 mWindow->setOwnerInfo(gui::Pid::INVALID, gui::Uid::INVALID);
Antonio Kantek26defcf2022-02-08 01:12:27 +000011542 ASSERT_FALSE(mDispatcher->setInTouchMode(InputDispatcher::kDefaultInTouchMode, ownerPid,
Harry Cutts33476232023-01-30 19:57:29 +000011543 ownerUid, /*hasPermission=*/false,
Antonio Kanteka042c022022-07-06 16:51:07 -070011544 ADISPLAY_ID_DEFAULT));
Antonio Kantek26defcf2022-02-08 01:12:27 +000011545 mWindow->assertNoEvents();
11546 mSecondWindow->assertNoEvents();
11547}
11548
11549TEST_F(InputDispatcherTouchModeChangedTests, NonWindowOwnerMayChangeTouchModeOnPermissionGranted) {
11550 const WindowInfo& windowInfo = *mWindow->getInfo();
Prabir Pradhanaeebeb42023-06-13 19:53:03 +000011551 gui::Pid ownerPid = windowInfo.ownerPid;
Prabir Pradhan8a5c41d2023-06-08 19:13:46 +000011552 gui::Uid ownerUid = windowInfo.ownerUid;
Prabir Pradhanaeebeb42023-06-13 19:53:03 +000011553 mWindow->setOwnerInfo(gui::Pid::INVALID, gui::Uid::INVALID);
Antonio Kantek15beb512022-06-13 22:35:41 +000011554 changeAndVerifyTouchModeInMainDisplayOnly(!InputDispatcher::kDefaultInTouchMode, ownerPid,
Harry Cutts33476232023-01-30 19:57:29 +000011555 ownerUid, /*hasPermission=*/true);
Antonio Kantek26defcf2022-02-08 01:12:27 +000011556}
11557
Antonio Kantekf16f2832021-09-28 04:39:20 +000011558TEST_F(InputDispatcherTouchModeChangedTests, EventIsNotGeneratedIfNotChangingTouchMode) {
Antonio Kantekea47acb2021-12-23 12:41:25 -080011559 const WindowInfo& windowInfo = *mWindow->getInfo();
Antonio Kantek26defcf2022-02-08 01:12:27 +000011560 ASSERT_FALSE(mDispatcher->setInTouchMode(InputDispatcher::kDefaultInTouchMode,
11561 windowInfo.ownerPid, windowInfo.ownerUid,
Harry Cutts33476232023-01-30 19:57:29 +000011562 /*hasPermission=*/true, ADISPLAY_ID_DEFAULT));
Antonio Kantekf16f2832021-09-28 04:39:20 +000011563 mWindow->assertNoEvents();
11564 mSecondWindow->assertNoEvents();
11565}
11566
Antonio Kantek15beb512022-06-13 22:35:41 +000011567TEST_F(InputDispatcherTouchModeChangedTests, ChangeTouchOnSecondaryDisplayOnly) {
11568 const WindowInfo& windowInfo = *mThirdWindow->getInfo();
11569 ASSERT_TRUE(mDispatcher->setInTouchMode(!InputDispatcher::kDefaultInTouchMode,
11570 windowInfo.ownerPid, windowInfo.ownerUid,
Harry Cutts33476232023-01-30 19:57:29 +000011571 /*hasPermission=*/true, SECOND_DISPLAY_ID));
Antonio Kantek15beb512022-06-13 22:35:41 +000011572 mWindow->assertNoEvents();
11573 mSecondWindow->assertNoEvents();
11574 mThirdWindow->consumeTouchModeEvent(!InputDispatcher::kDefaultInTouchMode);
11575}
11576
Antonio Kantek48710e42022-03-24 14:19:30 -070011577TEST_F(InputDispatcherTouchModeChangedTests, CanChangeTouchModeWhenOwningLastInteractedWindow) {
11578 // Interact with the window first.
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070011579 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
11580 injectKeyDown(*mDispatcher, ADISPLAY_ID_DEFAULT))
Antonio Kantek48710e42022-03-24 14:19:30 -070011581 << "Inject key event should return InputEventInjectionResult::SUCCEEDED";
11582 mWindow->consumeKeyDown(ADISPLAY_ID_DEFAULT);
11583
11584 // Then remove focus.
11585 mWindow->setFocusable(false);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070011586 mDispatcher->onWindowInfosChanged({{*mWindow->getInfo()}, {}, 0, 0});
Antonio Kantek48710e42022-03-24 14:19:30 -070011587
11588 // Assert that caller can switch touch mode by owning one of the last interacted window.
11589 const WindowInfo& windowInfo = *mWindow->getInfo();
11590 ASSERT_TRUE(mDispatcher->setInTouchMode(!InputDispatcher::kDefaultInTouchMode,
11591 windowInfo.ownerPid, windowInfo.ownerUid,
Harry Cutts33476232023-01-30 19:57:29 +000011592 /*hasPermission=*/false, ADISPLAY_ID_DEFAULT));
Antonio Kantek48710e42022-03-24 14:19:30 -070011593}
11594
Prabir Pradhan07e05b62021-11-19 03:57:24 -080011595class InputDispatcherSpyWindowTest : public InputDispatcherTest {
11596public:
Prabir Pradhan4d5c52f2022-01-31 08:52:10 -080011597 sp<FakeWindowHandle> createSpy() {
Prabir Pradhan07e05b62021-11-19 03:57:24 -080011598 std::shared_ptr<FakeApplicationHandle> application =
11599 std::make_shared<FakeApplicationHandle>();
11600 std::string name = "Fake Spy ";
11601 name += std::to_string(mSpyCount++);
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -070011602 sp<FakeWindowHandle> spy = sp<FakeWindowHandle>::make(application, mDispatcher,
11603 name.c_str(), ADISPLAY_ID_DEFAULT);
Prabir Pradhan51e7db02022-02-07 06:02:57 -080011604 spy->setSpy(true);
Prabir Pradhan5c85e052021-12-22 02:27:12 -080011605 spy->setTrustedOverlay(true);
Prabir Pradhan07e05b62021-11-19 03:57:24 -080011606 return spy;
11607 }
11608
11609 sp<FakeWindowHandle> createForeground() {
11610 std::shared_ptr<FakeApplicationHandle> application =
11611 std::make_shared<FakeApplicationHandle>();
11612 sp<FakeWindowHandle> window =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -070011613 sp<FakeWindowHandle>::make(application, mDispatcher, "Fake Window",
11614 ADISPLAY_ID_DEFAULT);
Prabir Pradhan1376fcd2022-01-21 09:56:35 -080011615 window->setFocusable(true);
Prabir Pradhan07e05b62021-11-19 03:57:24 -080011616 return window;
11617 }
11618
11619private:
11620 int mSpyCount{0};
11621};
11622
Prabir Pradhana3ab87a2022-01-27 10:00:21 -080011623using InputDispatcherSpyWindowDeathTest = InputDispatcherSpyWindowTest;
Prabir Pradhan07e05b62021-11-19 03:57:24 -080011624/**
Prabir Pradhan5c85e052021-12-22 02:27:12 -080011625 * Adding a spy window that is not a trusted overlay causes Dispatcher to abort.
11626 */
Prabir Pradhana3ab87a2022-01-27 10:00:21 -080011627TEST_F(InputDispatcherSpyWindowDeathTest, UntrustedSpy_AbortsDispatcher) {
Siarhei Vishniakou21f77bd2023-07-18 17:51:35 -070011628 testing::GTEST_FLAG(death_test_style) = "threadsafe";
Prabir Pradhana3ab87a2022-01-27 10:00:21 -080011629 ScopedSilentDeath _silentDeath;
11630
Prabir Pradhan4d5c52f2022-01-31 08:52:10 -080011631 auto spy = createSpy();
Prabir Pradhan5c85e052021-12-22 02:27:12 -080011632 spy->setTrustedOverlay(false);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070011633 ASSERT_DEATH(mDispatcher->onWindowInfosChanged({{*spy->getInfo()}, {}, 0, 0}),
Prabir Pradhan5c85e052021-12-22 02:27:12 -080011634 ".* not a trusted overlay");
11635}
11636
11637/**
Prabir Pradhan07e05b62021-11-19 03:57:24 -080011638 * Input injection into a display with a spy window but no foreground windows should succeed.
11639 */
11640TEST_F(InputDispatcherSpyWindowTest, NoForegroundWindow) {
Prabir Pradhan4d5c52f2022-01-31 08:52:10 -080011641 auto spy = createSpy();
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070011642 mDispatcher->onWindowInfosChanged({{*spy->getInfo()}, {}, 0, 0});
Prabir Pradhan07e05b62021-11-19 03:57:24 -080011643
11644 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070011645 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT))
Prabir Pradhan07e05b62021-11-19 03:57:24 -080011646 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
11647 spy->consumeMotionDown(ADISPLAY_ID_DEFAULT);
11648}
11649
11650/**
11651 * Verify the order in which different input windows receive events. The touched foreground window
11652 * (if there is one) should always receive the event first. When there are multiple spy windows, the
11653 * spy windows will receive the event according to their Z-order, where the top-most spy window will
11654 * receive events before ones belows it.
11655 *
11656 * Here, we set up a scenario with four windows in the following Z order from the top:
11657 * spy1, spy2, window, spy3.
11658 * We then inject an event and verify that the foreground "window" receives it first, followed by
11659 * "spy1" and "spy2". The "spy3" does not receive the event because it is underneath the foreground
11660 * window.
11661 */
11662TEST_F(InputDispatcherSpyWindowTest, ReceivesInputInOrder) {
11663 auto window = createForeground();
Prabir Pradhan4d5c52f2022-01-31 08:52:10 -080011664 auto spy1 = createSpy();
11665 auto spy2 = createSpy();
11666 auto spy3 = createSpy();
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070011667 mDispatcher->onWindowInfosChanged(
11668 {{*spy1->getInfo(), *spy2->getInfo(), *window->getInfo(), *spy3->getInfo()}, {}, 0, 0});
Prabir Pradhan07e05b62021-11-19 03:57:24 -080011669 const std::vector<sp<FakeWindowHandle>> channels{spy1, spy2, window, spy3};
11670 const size_t numChannels = channels.size();
11671
Michael Wright8e9a8562022-02-09 13:44:29 +000011672 base::unique_fd epollFd(epoll_create1(EPOLL_CLOEXEC));
Prabir Pradhan07e05b62021-11-19 03:57:24 -080011673 if (!epollFd.ok()) {
11674 FAIL() << "Failed to create epoll fd";
11675 }
11676
11677 for (size_t i = 0; i < numChannels; i++) {
11678 struct epoll_event event = {.events = EPOLLIN, .data.u64 = i};
11679 if (epoll_ctl(epollFd.get(), EPOLL_CTL_ADD, channels[i]->getChannelFd(), &event) < 0) {
11680 FAIL() << "Failed to add fd to epoll";
11681 }
11682 }
11683
11684 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070011685 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT))
Prabir Pradhan07e05b62021-11-19 03:57:24 -080011686 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
11687
11688 std::vector<size_t> eventOrder;
11689 std::vector<struct epoll_event> events(numChannels);
11690 for (;;) {
11691 const int nFds = epoll_wait(epollFd.get(), events.data(), static_cast<int>(numChannels),
11692 (100ms).count());
11693 if (nFds < 0) {
11694 FAIL() << "Failed to call epoll_wait";
11695 }
11696 if (nFds == 0) {
11697 break; // epoll_wait timed out
11698 }
11699 for (int i = 0; i < nFds; i++) {
Colin Cross5b799302022-10-18 21:52:41 -070011700 ASSERT_EQ(static_cast<uint32_t>(EPOLLIN), events[i].events);
Siarhei Vishniakou31977182022-09-30 08:51:23 -070011701 eventOrder.push_back(static_cast<size_t>(events[i].data.u64));
Prabir Pradhan07e05b62021-11-19 03:57:24 -080011702 channels[i]->consumeMotionDown();
11703 }
11704 }
11705
11706 // Verify the order in which the events were received.
11707 EXPECT_EQ(3u, eventOrder.size());
11708 EXPECT_EQ(2u, eventOrder[0]); // index 2: window
11709 EXPECT_EQ(0u, eventOrder[1]); // index 0: spy1
11710 EXPECT_EQ(1u, eventOrder[2]); // index 1: spy2
11711}
11712
11713/**
11714 * A spy window using the NOT_TOUCHABLE flag does not receive events.
11715 */
11716TEST_F(InputDispatcherSpyWindowTest, NotTouchable) {
11717 auto window = createForeground();
Prabir Pradhan4d5c52f2022-01-31 08:52:10 -080011718 auto spy = createSpy();
11719 spy->setTouchable(false);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070011720 mDispatcher->onWindowInfosChanged({{*spy->getInfo(), *window->getInfo()}, {}, 0, 0});
Prabir Pradhan07e05b62021-11-19 03:57:24 -080011721
11722 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070011723 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT))
Prabir Pradhan07e05b62021-11-19 03:57:24 -080011724 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
11725 window->consumeMotionDown(ADISPLAY_ID_DEFAULT);
11726 spy->assertNoEvents();
11727}
11728
11729/**
11730 * A spy window will only receive gestures that originate within its touchable region. Gestures that
11731 * have their ACTION_DOWN outside of the touchable region of the spy window will not be dispatched
11732 * to the window.
11733 */
11734TEST_F(InputDispatcherSpyWindowTest, TouchableRegion) {
11735 auto window = createForeground();
Prabir Pradhan4d5c52f2022-01-31 08:52:10 -080011736 auto spy = createSpy();
Prabir Pradhan07e05b62021-11-19 03:57:24 -080011737 spy->setTouchableRegion(Region{{0, 0, 20, 20}});
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070011738 mDispatcher->onWindowInfosChanged({{*spy->getInfo(), *window->getInfo()}, {}, 0, 0});
Prabir Pradhan07e05b62021-11-19 03:57:24 -080011739
11740 // Inject an event outside the spy window's touchable region.
11741 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070011742 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT))
Prabir Pradhan07e05b62021-11-19 03:57:24 -080011743 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
11744 window->consumeMotionDown();
11745 spy->assertNoEvents();
11746 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070011747 injectMotionUp(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT))
Prabir Pradhan07e05b62021-11-19 03:57:24 -080011748 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
11749 window->consumeMotionUp();
11750 spy->assertNoEvents();
11751
11752 // Inject an event inside the spy window's touchable region.
11753 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070011754 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
Prabir Pradhan07e05b62021-11-19 03:57:24 -080011755 {5, 10}))
11756 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
11757 window->consumeMotionDown();
11758 spy->consumeMotionDown();
11759}
11760
11761/**
Prabir Pradhan07e05b62021-11-19 03:57:24 -080011762 * A spy window can listen for touches outside its touchable region using the WATCH_OUTSIDE_TOUCHES
Prabir Pradhandfabf8a2022-01-21 08:19:30 -080011763 * flag, but it will get zero-ed out coordinates if the foreground has a different owner.
Prabir Pradhan07e05b62021-11-19 03:57:24 -080011764 */
11765TEST_F(InputDispatcherSpyWindowTest, WatchOutsideTouches) {
11766 auto window = createForeground();
Prabir Pradhanaeebeb42023-06-13 19:53:03 +000011767 window->setOwnerInfo(gui::Pid{12}, gui::Uid{34});
Prabir Pradhan4d5c52f2022-01-31 08:52:10 -080011768 auto spy = createSpy();
11769 spy->setWatchOutsideTouch(true);
Prabir Pradhanaeebeb42023-06-13 19:53:03 +000011770 spy->setOwnerInfo(gui::Pid{56}, gui::Uid{78});
Prabir Pradhan07e05b62021-11-19 03:57:24 -080011771 spy->setFrame(Rect{0, 0, 20, 20});
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070011772 mDispatcher->onWindowInfosChanged({{*spy->getInfo(), *window->getInfo()}, {}, 0, 0});
Prabir Pradhan07e05b62021-11-19 03:57:24 -080011773
11774 // Inject an event outside the spy window's frame and touchable region.
11775 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070011776 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
Prabir Pradhandfabf8a2022-01-21 08:19:30 -080011777 {100, 200}))
Prabir Pradhan07e05b62021-11-19 03:57:24 -080011778 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
11779 window->consumeMotionDown();
Prabir Pradhandfabf8a2022-01-21 08:19:30 -080011780 spy->consumeMotionOutsideWithZeroedCoords();
Prabir Pradhan07e05b62021-11-19 03:57:24 -080011781}
11782
11783/**
Prabir Pradhan07e05b62021-11-19 03:57:24 -080011784 * Even when a spy window spans over multiple foreground windows, the spy should receive all
11785 * pointers that are down within its bounds.
11786 */
11787TEST_F(InputDispatcherSpyWindowTest, ReceivesMultiplePointers) {
11788 auto windowLeft = createForeground();
11789 windowLeft->setFrame({0, 0, 100, 200});
11790 auto windowRight = createForeground();
11791 windowRight->setFrame({100, 0, 200, 200});
Prabir Pradhan4d5c52f2022-01-31 08:52:10 -080011792 auto spy = createSpy();
Prabir Pradhan07e05b62021-11-19 03:57:24 -080011793 spy->setFrame({0, 0, 200, 200});
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070011794 mDispatcher->onWindowInfosChanged(
11795 {{*spy->getInfo(), *windowLeft->getInfo(), *windowRight->getInfo()}, {}, 0, 0});
Prabir Pradhan07e05b62021-11-19 03:57:24 -080011796
11797 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070011798 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
Prabir Pradhan07e05b62021-11-19 03:57:24 -080011799 {50, 50}))
11800 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
11801 windowLeft->consumeMotionDown();
11802 spy->consumeMotionDown();
11803
11804 const MotionEvent secondFingerDownEvent =
Siarhei Vishniakoua16e3a22022-03-02 15:26:40 -080011805 MotionEventBuilder(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
Prabir Pradhan07e05b62021-11-19 03:57:24 -080011806 .eventTime(systemTime(SYSTEM_TIME_MONOTONIC))
Siarhei Vishniakou6d73f832022-07-21 17:27:03 -070011807 .pointer(PointerBuilder(/*id=*/0, ToolType::FINGER).x(50).y(50))
11808 .pointer(PointerBuilder(/*id=*/1, ToolType::FINGER).x(150).y(50))
Prabir Pradhan07e05b62021-11-19 03:57:24 -080011809 .build();
11810 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070011811 injectMotionEvent(*mDispatcher, secondFingerDownEvent, INJECT_EVENT_TIMEOUT,
Prabir Pradhan07e05b62021-11-19 03:57:24 -080011812 InputEventInjectionSync::WAIT_FOR_RESULT))
11813 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
11814 windowRight->consumeMotionDown();
Harry Cutts33476232023-01-30 19:57:29 +000011815 spy->consumeMotionPointerDown(/*pointerIndex=*/1);
Prabir Pradhan07e05b62021-11-19 03:57:24 -080011816}
11817
11818/**
11819 * When the first pointer lands outside the spy window and the second pointer lands inside it, the
11820 * the spy should receive the second pointer with ACTION_DOWN.
11821 */
11822TEST_F(InputDispatcherSpyWindowTest, ReceivesSecondPointerAsDown) {
11823 auto window = createForeground();
11824 window->setFrame({0, 0, 200, 200});
Prabir Pradhan4d5c52f2022-01-31 08:52:10 -080011825 auto spyRight = createSpy();
Prabir Pradhan07e05b62021-11-19 03:57:24 -080011826 spyRight->setFrame({100, 0, 200, 200});
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070011827 mDispatcher->onWindowInfosChanged({{*spyRight->getInfo(), *window->getInfo()}, {}, 0, 0});
Prabir Pradhan07e05b62021-11-19 03:57:24 -080011828
11829 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070011830 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
Prabir Pradhan07e05b62021-11-19 03:57:24 -080011831 {50, 50}))
11832 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
11833 window->consumeMotionDown();
11834 spyRight->assertNoEvents();
11835
11836 const MotionEvent secondFingerDownEvent =
Siarhei Vishniakoua16e3a22022-03-02 15:26:40 -080011837 MotionEventBuilder(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
Prabir Pradhan07e05b62021-11-19 03:57:24 -080011838 .eventTime(systemTime(SYSTEM_TIME_MONOTONIC))
Siarhei Vishniakou6d73f832022-07-21 17:27:03 -070011839 .pointer(PointerBuilder(/*id=*/0, ToolType::FINGER).x(50).y(50))
11840 .pointer(PointerBuilder(/*id=*/1, ToolType::FINGER).x(150).y(50))
Prabir Pradhan07e05b62021-11-19 03:57:24 -080011841 .build();
11842 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070011843 injectMotionEvent(*mDispatcher, secondFingerDownEvent, INJECT_EVENT_TIMEOUT,
Prabir Pradhan07e05b62021-11-19 03:57:24 -080011844 InputEventInjectionSync::WAIT_FOR_RESULT))
11845 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
Harry Cutts33476232023-01-30 19:57:29 +000011846 window->consumeMotionPointerDown(/*pointerIndex=*/1);
Prabir Pradhan07e05b62021-11-19 03:57:24 -080011847 spyRight->consumeMotionDown();
11848}
11849
Prabir Pradhan1376fcd2022-01-21 09:56:35 -080011850/**
11851 * The spy window should not be able to affect whether or not touches are split. Only the foreground
11852 * windows should be allowed to control split touch.
11853 */
11854TEST_F(InputDispatcherSpyWindowTest, SplitIfNoForegroundWindowTouched) {
Prabir Pradhan76bdecb2022-01-31 11:14:15 -080011855 // This spy window prevents touch splitting. However, we still expect to split touches
Prabir Pradhan1376fcd2022-01-21 09:56:35 -080011856 // because a foreground window has not disabled splitting.
Prabir Pradhan4d5c52f2022-01-31 08:52:10 -080011857 auto spy = createSpy();
Prabir Pradhan76bdecb2022-01-31 11:14:15 -080011858 spy->setPreventSplitting(true);
Prabir Pradhan1376fcd2022-01-21 09:56:35 -080011859
Prabir Pradhan1376fcd2022-01-21 09:56:35 -080011860 auto window = createForeground();
11861 window->setFrame(Rect(0, 0, 100, 100));
Prabir Pradhan1376fcd2022-01-21 09:56:35 -080011862
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070011863 mDispatcher->onWindowInfosChanged({{*spy->getInfo(), *window->getInfo()}, {}, 0, 0});
Prabir Pradhan1376fcd2022-01-21 09:56:35 -080011864
11865 // First finger down, no window touched.
11866 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070011867 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
Prabir Pradhan1376fcd2022-01-21 09:56:35 -080011868 {100, 200}))
11869 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
11870 spy->consumeMotionDown(ADISPLAY_ID_DEFAULT);
11871 window->assertNoEvents();
11872
11873 // Second finger down on window, the window should receive touch down.
11874 const MotionEvent secondFingerDownEvent =
Siarhei Vishniakoua16e3a22022-03-02 15:26:40 -080011875 MotionEventBuilder(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
Prabir Pradhan1376fcd2022-01-21 09:56:35 -080011876 .displayId(ADISPLAY_ID_DEFAULT)
11877 .eventTime(systemTime(SYSTEM_TIME_MONOTONIC))
Siarhei Vishniakou6d73f832022-07-21 17:27:03 -070011878 .pointer(PointerBuilder(/*id=*/0, ToolType::FINGER).x(100).y(200))
11879 .pointer(PointerBuilder(/*id=*/1, ToolType::FINGER).x(50).y(50))
Prabir Pradhan1376fcd2022-01-21 09:56:35 -080011880 .build();
11881 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070011882 injectMotionEvent(*mDispatcher, secondFingerDownEvent, INJECT_EVENT_TIMEOUT,
Prabir Pradhan1376fcd2022-01-21 09:56:35 -080011883 InputEventInjectionSync::WAIT_FOR_RESULT))
11884 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
11885
11886 window->consumeMotionDown(ADISPLAY_ID_DEFAULT);
Harry Cutts33476232023-01-30 19:57:29 +000011887 spy->consumeMotionPointerDown(/*pointerIndex=*/1);
Prabir Pradhan1376fcd2022-01-21 09:56:35 -080011888}
11889
11890/**
11891 * A spy window will usually be implemented as an un-focusable window. Verify that these windows
11892 * do not receive key events.
11893 */
11894TEST_F(InputDispatcherSpyWindowTest, UnfocusableSpyDoesNotReceiveKeyEvents) {
Prabir Pradhan4d5c52f2022-01-31 08:52:10 -080011895 auto spy = createSpy();
Prabir Pradhan1376fcd2022-01-21 09:56:35 -080011896 spy->setFocusable(false);
11897
11898 auto window = createForeground();
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070011899 mDispatcher->onWindowInfosChanged({{*spy->getInfo(), *window->getInfo()}, {}, 0, 0});
Prabir Pradhan1376fcd2022-01-21 09:56:35 -080011900 setFocusedWindow(window);
11901 window->consumeFocusEvent(true);
11902
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070011903 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectKeyDown(*mDispatcher))
Prabir Pradhan1376fcd2022-01-21 09:56:35 -080011904 << "Inject key event should return InputEventInjectionResult::SUCCEEDED";
11905 window->consumeKeyDown(ADISPLAY_ID_NONE);
11906
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070011907 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectKeyUp(*mDispatcher))
Prabir Pradhan1376fcd2022-01-21 09:56:35 -080011908 << "Inject key event should return InputEventInjectionResult::SUCCEEDED";
11909 window->consumeKeyUp(ADISPLAY_ID_NONE);
11910
11911 spy->assertNoEvents();
11912}
11913
Vaibhav Devmurariff798f32022-05-09 23:45:04 +000011914using InputDispatcherPilferPointersTest = InputDispatcherSpyWindowTest;
11915
11916/**
11917 * A spy window can pilfer pointers. When this happens, touch gestures used by the spy window that
11918 * are currently sent to any other windows - including other spy windows - will also be cancelled.
11919 */
11920TEST_F(InputDispatcherPilferPointersTest, PilferPointers) {
11921 auto window = createForeground();
11922 auto spy1 = createSpy();
11923 auto spy2 = createSpy();
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070011924 mDispatcher->onWindowInfosChanged(
11925 {{*spy1->getInfo(), *spy2->getInfo(), *window->getInfo()}, {}, 0, 0});
Vaibhav Devmurariff798f32022-05-09 23:45:04 +000011926
11927 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070011928 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT))
Vaibhav Devmurariff798f32022-05-09 23:45:04 +000011929 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
11930 window->consumeMotionDown();
11931 spy1->consumeMotionDown();
11932 spy2->consumeMotionDown();
11933
11934 // Pilfer pointers from the second spy window.
11935 EXPECT_EQ(OK, mDispatcher->pilferPointers(spy2->getToken()));
11936 spy2->assertNoEvents();
11937 spy1->consumeMotionCancel();
11938 window->consumeMotionCancel();
11939
11940 // The rest of the gesture should only be sent to the second spy window.
11941 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070011942 injectMotionEvent(*mDispatcher, AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN,
Vaibhav Devmurariff798f32022-05-09 23:45:04 +000011943 ADISPLAY_ID_DEFAULT))
11944 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
11945 spy2->consumeMotionMove();
11946 spy1->assertNoEvents();
11947 window->assertNoEvents();
11948}
11949
11950/**
11951 * A spy window can pilfer pointers for a gesture even after the foreground window has been removed
11952 * in the middle of the gesture.
11953 */
11954TEST_F(InputDispatcherPilferPointersTest, CanPilferAfterWindowIsRemovedMidStream) {
11955 auto window = createForeground();
11956 auto spy = createSpy();
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070011957 mDispatcher->onWindowInfosChanged({{*spy->getInfo(), *window->getInfo()}, {}, 0, 0});
Vaibhav Devmurariff798f32022-05-09 23:45:04 +000011958
11959 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070011960 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT))
Vaibhav Devmurariff798f32022-05-09 23:45:04 +000011961 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
11962 window->consumeMotionDown(ADISPLAY_ID_DEFAULT);
11963 spy->consumeMotionDown(ADISPLAY_ID_DEFAULT);
11964
11965 window->releaseChannel();
11966
11967 EXPECT_EQ(OK, mDispatcher->pilferPointers(spy->getToken()));
11968
11969 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070011970 injectMotionUp(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT))
Vaibhav Devmurariff798f32022-05-09 23:45:04 +000011971 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
11972 spy->consumeMotionUp(ADISPLAY_ID_DEFAULT);
11973}
11974
11975/**
11976 * After a spy window pilfers pointers, new pointers that go down in its bounds should be sent to
11977 * the spy, but not to any other windows.
11978 */
11979TEST_F(InputDispatcherPilferPointersTest, ContinuesToReceiveGestureAfterPilfer) {
11980 auto spy = createSpy();
11981 auto window = createForeground();
11982
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070011983 mDispatcher->onWindowInfosChanged({{*spy->getInfo(), *window->getInfo()}, {}, 0, 0});
Vaibhav Devmurariff798f32022-05-09 23:45:04 +000011984
11985 // First finger down on the window and the spy.
11986 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070011987 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
Vaibhav Devmurariff798f32022-05-09 23:45:04 +000011988 {100, 200}))
11989 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
11990 spy->consumeMotionDown();
11991 window->consumeMotionDown();
11992
11993 // Spy window pilfers the pointers.
11994 EXPECT_EQ(OK, mDispatcher->pilferPointers(spy->getToken()));
11995 window->consumeMotionCancel();
11996
11997 // Second finger down on the window and spy, but the window should not receive the pointer down.
11998 const MotionEvent secondFingerDownEvent =
11999 MotionEventBuilder(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
12000 .displayId(ADISPLAY_ID_DEFAULT)
12001 .eventTime(systemTime(SYSTEM_TIME_MONOTONIC))
Siarhei Vishniakou6d73f832022-07-21 17:27:03 -070012002 .pointer(PointerBuilder(/*id=*/0, ToolType::FINGER).x(100).y(200))
12003 .pointer(PointerBuilder(/*id=*/1, ToolType::FINGER).x(50).y(50))
Vaibhav Devmurariff798f32022-05-09 23:45:04 +000012004 .build();
12005 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070012006 injectMotionEvent(*mDispatcher, secondFingerDownEvent, INJECT_EVENT_TIMEOUT,
Vaibhav Devmurariff798f32022-05-09 23:45:04 +000012007 InputEventInjectionSync::WAIT_FOR_RESULT))
12008 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
12009
Harry Cutts33476232023-01-30 19:57:29 +000012010 spy->consumeMotionPointerDown(/*pointerIndex=*/1);
Vaibhav Devmurariff798f32022-05-09 23:45:04 +000012011
12012 // Third finger goes down outside all windows, so injection should fail.
12013 const MotionEvent thirdFingerDownEvent =
12014 MotionEventBuilder(POINTER_2_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
12015 .displayId(ADISPLAY_ID_DEFAULT)
12016 .eventTime(systemTime(SYSTEM_TIME_MONOTONIC))
Siarhei Vishniakou6d73f832022-07-21 17:27:03 -070012017 .pointer(PointerBuilder(/*id=*/0, ToolType::FINGER).x(100).y(200))
12018 .pointer(PointerBuilder(/*id=*/1, ToolType::FINGER).x(50).y(50))
12019 .pointer(PointerBuilder(/*id=*/2, ToolType::FINGER).x(-5).y(-5))
Vaibhav Devmurariff798f32022-05-09 23:45:04 +000012020 .build();
12021 ASSERT_EQ(InputEventInjectionResult::FAILED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070012022 injectMotionEvent(*mDispatcher, thirdFingerDownEvent, INJECT_EVENT_TIMEOUT,
Vaibhav Devmurariff798f32022-05-09 23:45:04 +000012023 InputEventInjectionSync::WAIT_FOR_RESULT))
Siarhei Vishniakou1ae72f12023-01-29 12:55:30 -080012024 << "Inject motion event should return InputEventInjectionResult::FAILED";
Vaibhav Devmurariff798f32022-05-09 23:45:04 +000012025
12026 spy->assertNoEvents();
12027 window->assertNoEvents();
12028}
12029
12030/**
12031 * After a spy window pilfers pointers, only the pointers used by the spy should be canceled
12032 */
12033TEST_F(InputDispatcherPilferPointersTest, PartiallyPilferRequiredPointers) {
12034 auto spy = createSpy();
12035 spy->setFrame(Rect(0, 0, 100, 100));
12036 auto window = createForeground();
12037 window->setFrame(Rect(0, 0, 200, 200));
12038
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070012039 mDispatcher->onWindowInfosChanged({{*spy->getInfo(), *window->getInfo()}, {}, 0, 0});
Vaibhav Devmurariff798f32022-05-09 23:45:04 +000012040
12041 // First finger down on the window only
12042 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070012043 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
Vaibhav Devmurariff798f32022-05-09 23:45:04 +000012044 {150, 150}))
12045 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
12046 window->consumeMotionDown();
12047
12048 // Second finger down on the spy and window
12049 const MotionEvent secondFingerDownEvent =
12050 MotionEventBuilder(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
12051 .displayId(ADISPLAY_ID_DEFAULT)
12052 .eventTime(systemTime(SYSTEM_TIME_MONOTONIC))
Siarhei Vishniakou6d73f832022-07-21 17:27:03 -070012053 .pointer(PointerBuilder(/*id=*/0, ToolType::FINGER).x(150).y(150))
12054 .pointer(PointerBuilder(/*id=*/1, ToolType::FINGER).x(10).y(10))
Vaibhav Devmurariff798f32022-05-09 23:45:04 +000012055 .build();
12056 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070012057 injectMotionEvent(*mDispatcher, secondFingerDownEvent, INJECT_EVENT_TIMEOUT,
Vaibhav Devmurariff798f32022-05-09 23:45:04 +000012058 InputEventInjectionSync::WAIT_FOR_RESULT))
12059 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
12060 spy->consumeMotionDown();
12061 window->consumeMotionPointerDown(1);
12062
12063 // Third finger down on the spy and window
12064 const MotionEvent thirdFingerDownEvent =
12065 MotionEventBuilder(POINTER_2_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
12066 .displayId(ADISPLAY_ID_DEFAULT)
12067 .eventTime(systemTime(SYSTEM_TIME_MONOTONIC))
Siarhei Vishniakou6d73f832022-07-21 17:27:03 -070012068 .pointer(PointerBuilder(/*id=*/0, ToolType::FINGER).x(150).y(150))
12069 .pointer(PointerBuilder(/*id=*/1, ToolType::FINGER).x(10).y(10))
12070 .pointer(PointerBuilder(/*id=*/2, ToolType::FINGER).x(50).y(50))
Vaibhav Devmurariff798f32022-05-09 23:45:04 +000012071 .build();
12072 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070012073 injectMotionEvent(*mDispatcher, thirdFingerDownEvent, INJECT_EVENT_TIMEOUT,
Vaibhav Devmurariff798f32022-05-09 23:45:04 +000012074 InputEventInjectionSync::WAIT_FOR_RESULT))
12075 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
12076 spy->consumeMotionPointerDown(1);
12077 window->consumeMotionPointerDown(2);
12078
12079 // Spy window pilfers the pointers.
12080 EXPECT_EQ(OK, mDispatcher->pilferPointers(spy->getToken()));
Harry Cutts101ee9b2023-07-06 18:04:14 +000012081 window->consumeMotionPointerUp(/*idx=*/2, ADISPLAY_ID_DEFAULT, AMOTION_EVENT_FLAG_CANCELED);
12082 window->consumeMotionPointerUp(/*idx=*/1, ADISPLAY_ID_DEFAULT, AMOTION_EVENT_FLAG_CANCELED);
Vaibhav Devmurariff798f32022-05-09 23:45:04 +000012083
12084 spy->assertNoEvents();
12085 window->assertNoEvents();
12086}
12087
12088/**
12089 * After a spy window pilfers pointers, all pilfered pointers that have already been dispatched to
12090 * other windows should be canceled. If this results in the cancellation of all pointers for some
12091 * window, then that window should receive ACTION_CANCEL.
12092 */
12093TEST_F(InputDispatcherPilferPointersTest, PilferAllRequiredPointers) {
12094 auto spy = createSpy();
12095 spy->setFrame(Rect(0, 0, 100, 100));
12096 auto window = createForeground();
12097 window->setFrame(Rect(0, 0, 200, 200));
12098
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070012099 mDispatcher->onWindowInfosChanged({{*spy->getInfo(), *window->getInfo()}, {}, 0, 0});
Vaibhav Devmurariff798f32022-05-09 23:45:04 +000012100
12101 // First finger down on both spy and window
12102 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070012103 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
Vaibhav Devmurariff798f32022-05-09 23:45:04 +000012104 {10, 10}))
12105 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
12106 window->consumeMotionDown();
12107 spy->consumeMotionDown();
12108
12109 // Second finger down on the spy and window
12110 const MotionEvent secondFingerDownEvent =
12111 MotionEventBuilder(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
12112 .displayId(ADISPLAY_ID_DEFAULT)
12113 .eventTime(systemTime(SYSTEM_TIME_MONOTONIC))
Siarhei Vishniakou6d73f832022-07-21 17:27:03 -070012114 .pointer(PointerBuilder(/*id=*/0, ToolType::FINGER).x(10).y(10))
12115 .pointer(PointerBuilder(/*id=*/1, ToolType::FINGER).x(50).y(50))
Vaibhav Devmurariff798f32022-05-09 23:45:04 +000012116 .build();
12117 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070012118 injectMotionEvent(*mDispatcher, secondFingerDownEvent, INJECT_EVENT_TIMEOUT,
Vaibhav Devmurariff798f32022-05-09 23:45:04 +000012119 InputEventInjectionSync::WAIT_FOR_RESULT))
12120 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
12121 spy->consumeMotionPointerDown(1);
12122 window->consumeMotionPointerDown(1);
12123
12124 // Spy window pilfers the pointers.
12125 EXPECT_EQ(OK, mDispatcher->pilferPointers(spy->getToken()));
12126 window->consumeMotionCancel();
12127
12128 spy->assertNoEvents();
12129 window->assertNoEvents();
12130}
12131
12132/**
12133 * After a spy window pilfers pointers, new pointers that are not touching the spy window can still
12134 * be sent to other windows
12135 */
12136TEST_F(InputDispatcherPilferPointersTest, CanReceivePointersAfterPilfer) {
12137 auto spy = createSpy();
12138 spy->setFrame(Rect(0, 0, 100, 100));
12139 auto window = createForeground();
12140 window->setFrame(Rect(0, 0, 200, 200));
12141
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070012142 mDispatcher->onWindowInfosChanged({{*spy->getInfo(), *window->getInfo()}, {}, 0, 0});
Vaibhav Devmurariff798f32022-05-09 23:45:04 +000012143
12144 // First finger down on both window and spy
12145 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070012146 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
Vaibhav Devmurariff798f32022-05-09 23:45:04 +000012147 {10, 10}))
12148 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
12149 window->consumeMotionDown();
12150 spy->consumeMotionDown();
12151
12152 // Spy window pilfers the pointers.
12153 EXPECT_EQ(OK, mDispatcher->pilferPointers(spy->getToken()));
12154 window->consumeMotionCancel();
12155
12156 // Second finger down on the window only
12157 const MotionEvent secondFingerDownEvent =
12158 MotionEventBuilder(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
12159 .displayId(ADISPLAY_ID_DEFAULT)
12160 .eventTime(systemTime(SYSTEM_TIME_MONOTONIC))
Siarhei Vishniakou6d73f832022-07-21 17:27:03 -070012161 .pointer(PointerBuilder(/*id=*/0, ToolType::FINGER).x(10).y(10))
12162 .pointer(PointerBuilder(/*id=*/1, ToolType::FINGER).x(150).y(150))
Vaibhav Devmurariff798f32022-05-09 23:45:04 +000012163 .build();
12164 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070012165 injectMotionEvent(*mDispatcher, secondFingerDownEvent, INJECT_EVENT_TIMEOUT,
Vaibhav Devmurariff798f32022-05-09 23:45:04 +000012166 InputEventInjectionSync::WAIT_FOR_RESULT))
12167 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
12168 window->consumeMotionDown();
12169 window->assertNoEvents();
12170
12171 // TODO(b/232530217): do not send the unnecessary MOVE event and delete the next line
12172 spy->consumeMotionMove();
12173 spy->assertNoEvents();
12174}
12175
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -070012176/**
12177 * A window on the left and a window on the right. Also, a spy window that's above all of the
12178 * windows, and spanning both left and right windows.
12179 * Send simultaneous motion streams from two different devices, one to the left window, and another
12180 * to the right window.
12181 * Pilfer from spy window.
12182 * Check that the pilfering only affects the pointers that are actually being received by the spy.
12183 */
Siarhei Vishniakoued89cbb2023-10-13 10:42:44 -070012184TEST_F(InputDispatcherPilferPointersTest, MultiDevicePilfer_legacy) {
12185 SCOPED_FLAG_OVERRIDE(enable_multi_device_same_window_stream, false);
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -070012186 sp<FakeWindowHandle> spy = createSpy();
12187 spy->setFrame(Rect(0, 0, 200, 200));
12188 sp<FakeWindowHandle> leftWindow = createForeground();
12189 leftWindow->setFrame(Rect(0, 0, 100, 100));
12190
12191 sp<FakeWindowHandle> rightWindow = createForeground();
12192 rightWindow->setFrame(Rect(100, 0, 200, 100));
12193
12194 constexpr int32_t stylusDeviceId = 1;
12195 constexpr int32_t touchDeviceId = 2;
12196
12197 mDispatcher->onWindowInfosChanged(
12198 {{*spy->getInfo(), *leftWindow->getInfo(), *rightWindow->getInfo()}, {}, 0, 0});
12199
12200 // Stylus down on left window and spy
12201 mDispatcher->notifyMotion(MotionArgsBuilder(AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_STYLUS)
12202 .deviceId(stylusDeviceId)
12203 .pointer(PointerBuilder(0, ToolType::STYLUS).x(50).y(50))
12204 .build());
12205 leftWindow->consumeMotionEvent(
12206 AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(stylusDeviceId)));
12207 spy->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(stylusDeviceId)));
12208
12209 // Finger down on right window and spy - but spy already has stylus
12210 mDispatcher->notifyMotion(
12211 MotionArgsBuilder(AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
12212 .deviceId(touchDeviceId)
12213 .pointer(PointerBuilder(0, ToolType::FINGER).x(150).y(50))
12214 .build());
12215 rightWindow->consumeMotionEvent(
12216 AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(touchDeviceId)));
Siarhei Vishniakou2899c552023-07-10 18:20:46 -070012217 spy->assertNoEvents();
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -070012218
12219 // Act: pilfer from spy. Spy is currently receiving touch events.
12220 EXPECT_EQ(OK, mDispatcher->pilferPointers(spy->getToken()));
Siarhei Vishniakou2899c552023-07-10 18:20:46 -070012221 leftWindow->consumeMotionEvent(
12222 AllOf(WithMotionAction(ACTION_CANCEL), WithDeviceId(stylusDeviceId)));
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -070012223 rightWindow->consumeMotionEvent(
12224 AllOf(WithMotionAction(ACTION_CANCEL), WithDeviceId(touchDeviceId)));
12225
12226 // Continue movements from both stylus and touch. Touch will be delivered to spy, but not stylus
12227 mDispatcher->notifyMotion(MotionArgsBuilder(AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_STYLUS)
12228 .deviceId(stylusDeviceId)
12229 .pointer(PointerBuilder(0, ToolType::STYLUS).x(51).y(52))
12230 .build());
12231 mDispatcher->notifyMotion(
12232 MotionArgsBuilder(AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN)
12233 .deviceId(touchDeviceId)
12234 .pointer(PointerBuilder(0, ToolType::FINGER).x(151).y(52))
12235 .build());
Siarhei Vishniakou2899c552023-07-10 18:20:46 -070012236 spy->consumeMotionEvent(AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(stylusDeviceId)));
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -070012237
12238 spy->assertNoEvents();
12239 leftWindow->assertNoEvents();
12240 rightWindow->assertNoEvents();
12241}
12242
Siarhei Vishniakoued89cbb2023-10-13 10:42:44 -070012243/**
12244 * A window on the left and a window on the right. Also, a spy window that's above all of the
12245 * windows, and spanning both left and right windows.
12246 * Send simultaneous motion streams from two different devices, one to the left window, and another
12247 * to the right window.
12248 * Pilfer from spy window.
12249 * Check that the pilfering affects all of the pointers that are actually being received by the spy.
12250 * The spy should receive both the touch and the stylus events after pilfer.
12251 */
12252TEST_F(InputDispatcherPilferPointersTest, MultiDevicePilfer) {
12253 SCOPED_FLAG_OVERRIDE(enable_multi_device_same_window_stream, true);
12254 sp<FakeWindowHandle> spy = createSpy();
12255 spy->setFrame(Rect(0, 0, 200, 200));
12256 sp<FakeWindowHandle> leftWindow = createForeground();
12257 leftWindow->setFrame(Rect(0, 0, 100, 100));
12258
12259 sp<FakeWindowHandle> rightWindow = createForeground();
12260 rightWindow->setFrame(Rect(100, 0, 200, 100));
12261
12262 constexpr int32_t stylusDeviceId = 1;
12263 constexpr int32_t touchDeviceId = 2;
12264
12265 mDispatcher->onWindowInfosChanged(
12266 {{*spy->getInfo(), *leftWindow->getInfo(), *rightWindow->getInfo()}, {}, 0, 0});
12267
12268 // Stylus down on left window and spy
12269 mDispatcher->notifyMotion(MotionArgsBuilder(AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_STYLUS)
12270 .deviceId(stylusDeviceId)
12271 .pointer(PointerBuilder(0, ToolType::STYLUS).x(50).y(50))
12272 .build());
12273 leftWindow->consumeMotionEvent(
12274 AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(stylusDeviceId)));
12275 spy->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(stylusDeviceId)));
12276
12277 // Finger down on right window and spy
12278 mDispatcher->notifyMotion(
12279 MotionArgsBuilder(AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
12280 .deviceId(touchDeviceId)
12281 .pointer(PointerBuilder(0, ToolType::FINGER).x(150).y(50))
12282 .build());
12283 rightWindow->consumeMotionEvent(
12284 AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(touchDeviceId)));
12285 spy->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(touchDeviceId)));
12286
12287 // Act: pilfer from spy. Spy is currently receiving touch events.
12288 EXPECT_EQ(OK, mDispatcher->pilferPointers(spy->getToken()));
12289 leftWindow->consumeMotionEvent(
12290 AllOf(WithMotionAction(ACTION_CANCEL), WithDeviceId(stylusDeviceId)));
12291 rightWindow->consumeMotionEvent(
12292 AllOf(WithMotionAction(ACTION_CANCEL), WithDeviceId(touchDeviceId)));
12293
12294 // Continue movements from both stylus and touch. Touch and stylus will be delivered to spy
Siarhei Vishniakou92bca1c2024-04-01 14:06:59 -070012295 // Instead of sending the two MOVE events for each input device together, and then receiving
12296 // them both, process them one at at time. InputConsumer is always in the batching mode, which
12297 // means that the two MOVE events will be initially put into a batch. Once the events are
12298 // batched, the 'consume' call may result in any of the MOVE events to be sent first (depending
12299 // on the implementation of InputConsumer), which would mean that the order of the received
12300 // events could be different depending on whether there are 1 or 2 events pending in the
12301 // InputChannel at the time the test calls 'consume'. To make assertions simpler here, and to
12302 // avoid this confusing behaviour, send and receive each MOVE event separately.
Siarhei Vishniakoued89cbb2023-10-13 10:42:44 -070012303 mDispatcher->notifyMotion(MotionArgsBuilder(AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_STYLUS)
12304 .deviceId(stylusDeviceId)
12305 .pointer(PointerBuilder(0, ToolType::STYLUS).x(51).y(52))
12306 .build());
Siarhei Vishniakou92bca1c2024-04-01 14:06:59 -070012307 spy->consumeMotionEvent(AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(stylusDeviceId)));
Siarhei Vishniakoued89cbb2023-10-13 10:42:44 -070012308 mDispatcher->notifyMotion(
12309 MotionArgsBuilder(AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN)
12310 .deviceId(touchDeviceId)
12311 .pointer(PointerBuilder(0, ToolType::FINGER).x(151).y(52))
12312 .build());
Siarhei Vishniakou92bca1c2024-04-01 14:06:59 -070012313 spy->consumeMotionEvent(AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(touchDeviceId)));
Siarhei Vishniakoued89cbb2023-10-13 10:42:44 -070012314
12315 spy->assertNoEvents();
12316 leftWindow->assertNoEvents();
12317 rightWindow->assertNoEvents();
12318}
12319
Prabir Pradhan9cd9eb62023-11-22 17:58:06 +000012320TEST_F(InputDispatcherPilferPointersTest, NoPilferingWithHoveringPointers) {
12321 auto window = createForeground();
12322 auto spy = createSpy();
12323 mDispatcher->onWindowInfosChanged({{*spy->getInfo(), *window->getInfo()}, {}, 0, 0});
12324
12325 mDispatcher->notifyMotion(
12326 MotionArgsBuilder(ACTION_HOVER_ENTER, AINPUT_SOURCE_MOUSE)
12327 .deviceId(1)
12328 .pointer(PointerBuilder(/*id=*/0, ToolType::MOUSE).x(100).y(200))
12329 .build());
12330 window->consumeMotionEvent(WithMotionAction(ACTION_HOVER_ENTER));
12331 spy->consumeMotionEvent(WithMotionAction(ACTION_HOVER_ENTER));
12332
12333 // Pilfer pointers from the spy window should fail.
12334 EXPECT_NE(OK, mDispatcher->pilferPointers(spy->getToken()));
12335 spy->assertNoEvents();
12336 window->assertNoEvents();
12337}
12338
Prabir Pradhand65552b2021-10-07 11:23:50 -070012339class InputDispatcherStylusInterceptorTest : public InputDispatcherTest {
12340public:
12341 std::pair<sp<FakeWindowHandle>, sp<FakeWindowHandle>> setupStylusOverlayScenario() {
12342 std::shared_ptr<FakeApplicationHandle> overlayApplication =
12343 std::make_shared<FakeApplicationHandle>();
12344 sp<FakeWindowHandle> overlay =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -070012345 sp<FakeWindowHandle>::make(overlayApplication, mDispatcher,
12346 "Stylus interceptor window", ADISPLAY_ID_DEFAULT);
Prabir Pradhand65552b2021-10-07 11:23:50 -070012347 overlay->setFocusable(false);
Prabir Pradhanaeebeb42023-06-13 19:53:03 +000012348 overlay->setOwnerInfo(gui::Pid{111}, gui::Uid{111});
Prabir Pradhan4d5c52f2022-01-31 08:52:10 -080012349 overlay->setTouchable(false);
Prabir Pradhan51e7db02022-02-07 06:02:57 -080012350 overlay->setInterceptsStylus(true);
Prabir Pradhand65552b2021-10-07 11:23:50 -070012351 overlay->setTrustedOverlay(true);
12352
12353 std::shared_ptr<FakeApplicationHandle> application =
12354 std::make_shared<FakeApplicationHandle>();
12355 sp<FakeWindowHandle> window =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -070012356 sp<FakeWindowHandle>::make(application, mDispatcher, "Application window",
12357 ADISPLAY_ID_DEFAULT);
Prabir Pradhand65552b2021-10-07 11:23:50 -070012358 window->setFocusable(true);
Prabir Pradhanaeebeb42023-06-13 19:53:03 +000012359 window->setOwnerInfo(gui::Pid{222}, gui::Uid{222});
Prabir Pradhand65552b2021-10-07 11:23:50 -070012360
12361 mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070012362 mDispatcher->onWindowInfosChanged({{*overlay->getInfo(), *window->getInfo()}, {}, 0, 0});
Prabir Pradhand65552b2021-10-07 11:23:50 -070012363 setFocusedWindow(window);
Harry Cutts33476232023-01-30 19:57:29 +000012364 window->consumeFocusEvent(/*hasFocus=*/true, /*inTouchMode=*/true);
Prabir Pradhand65552b2021-10-07 11:23:50 -070012365 return {std::move(overlay), std::move(window)};
12366 }
12367
12368 void sendFingerEvent(int32_t action) {
Prabir Pradhan678438e2023-04-13 19:32:51 +000012369 mDispatcher->notifyMotion(
Prabir Pradhand65552b2021-10-07 11:23:50 -070012370 generateMotionArgs(action, AINPUT_SOURCE_TOUCHSCREEN | AINPUT_SOURCE_STYLUS,
Prabir Pradhan678438e2023-04-13 19:32:51 +000012371 ADISPLAY_ID_DEFAULT, {PointF{20, 20}}));
Prabir Pradhand65552b2021-10-07 11:23:50 -070012372 }
12373
12374 void sendStylusEvent(int32_t action) {
12375 NotifyMotionArgs motionArgs =
12376 generateMotionArgs(action, AINPUT_SOURCE_TOUCHSCREEN | AINPUT_SOURCE_STYLUS,
12377 ADISPLAY_ID_DEFAULT, {PointF{30, 40}});
Siarhei Vishniakou6d73f832022-07-21 17:27:03 -070012378 motionArgs.pointerProperties[0].toolType = ToolType::STYLUS;
Prabir Pradhan678438e2023-04-13 19:32:51 +000012379 mDispatcher->notifyMotion(motionArgs);
Prabir Pradhand65552b2021-10-07 11:23:50 -070012380 }
12381};
12382
Prabir Pradhana3ab87a2022-01-27 10:00:21 -080012383using InputDispatcherStylusInterceptorDeathTest = InputDispatcherStylusInterceptorTest;
12384
12385TEST_F(InputDispatcherStylusInterceptorDeathTest, UntrustedOverlay_AbortsDispatcher) {
Siarhei Vishniakouad3b6822023-06-22 14:17:35 -070012386 testing::GTEST_FLAG(death_test_style) = "threadsafe";
Prabir Pradhana3ab87a2022-01-27 10:00:21 -080012387 ScopedSilentDeath _silentDeath;
12388
Prabir Pradhand65552b2021-10-07 11:23:50 -070012389 auto [overlay, window] = setupStylusOverlayScenario();
12390 overlay->setTrustedOverlay(false);
12391 // Configuring an untrusted overlay as a stylus interceptor should cause Dispatcher to abort.
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070012392 ASSERT_DEATH(mDispatcher->onWindowInfosChanged(
12393 {{*overlay->getInfo(), *window->getInfo()}, {}, 0, 0}),
Prabir Pradhand65552b2021-10-07 11:23:50 -070012394 ".* not a trusted overlay");
12395}
12396
12397TEST_F(InputDispatcherStylusInterceptorTest, ConsmesOnlyStylusEvents) {
12398 auto [overlay, window] = setupStylusOverlayScenario();
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070012399 mDispatcher->onWindowInfosChanged({{*overlay->getInfo(), *window->getInfo()}, {}, 0, 0});
Prabir Pradhand65552b2021-10-07 11:23:50 -070012400
12401 sendStylusEvent(AMOTION_EVENT_ACTION_DOWN);
12402 overlay->consumeMotionDown();
12403 sendStylusEvent(AMOTION_EVENT_ACTION_UP);
12404 overlay->consumeMotionUp();
12405
12406 sendFingerEvent(AMOTION_EVENT_ACTION_DOWN);
12407 window->consumeMotionDown();
12408 sendFingerEvent(AMOTION_EVENT_ACTION_UP);
12409 window->consumeMotionUp();
12410
12411 overlay->assertNoEvents();
12412 window->assertNoEvents();
12413}
12414
12415TEST_F(InputDispatcherStylusInterceptorTest, SpyWindowStylusInterceptor) {
12416 auto [overlay, window] = setupStylusOverlayScenario();
Prabir Pradhan51e7db02022-02-07 06:02:57 -080012417 overlay->setSpy(true);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070012418 mDispatcher->onWindowInfosChanged({{*overlay->getInfo(), *window->getInfo()}, {}, 0, 0});
Prabir Pradhand65552b2021-10-07 11:23:50 -070012419
12420 sendStylusEvent(AMOTION_EVENT_ACTION_DOWN);
12421 overlay->consumeMotionDown();
12422 window->consumeMotionDown();
12423 sendStylusEvent(AMOTION_EVENT_ACTION_UP);
12424 overlay->consumeMotionUp();
12425 window->consumeMotionUp();
12426
12427 sendFingerEvent(AMOTION_EVENT_ACTION_DOWN);
12428 window->consumeMotionDown();
12429 sendFingerEvent(AMOTION_EVENT_ACTION_UP);
12430 window->consumeMotionUp();
12431
12432 overlay->assertNoEvents();
12433 window->assertNoEvents();
12434}
12435
Prabir Pradhan6dfbf262022-03-14 15:24:30 +000012436/**
12437 * Set up a scenario to test the behavior used by the stylus handwriting detection feature.
12438 * The scenario is as follows:
12439 * - The stylus interceptor overlay is configured as a spy window.
12440 * - The stylus interceptor spy receives the start of a new stylus gesture.
12441 * - It pilfers pointers and then configures itself to no longer be a spy.
12442 * - The stylus interceptor continues to receive the rest of the gesture.
12443 */
12444TEST_F(InputDispatcherStylusInterceptorTest, StylusHandwritingScenario) {
12445 auto [overlay, window] = setupStylusOverlayScenario();
12446 overlay->setSpy(true);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070012447 mDispatcher->onWindowInfosChanged({{*overlay->getInfo(), *window->getInfo()}, {}, 0, 0});
Prabir Pradhan6dfbf262022-03-14 15:24:30 +000012448
12449 sendStylusEvent(AMOTION_EVENT_ACTION_DOWN);
12450 overlay->consumeMotionDown();
12451 window->consumeMotionDown();
12452
12453 // The interceptor pilfers the pointers.
12454 EXPECT_EQ(OK, mDispatcher->pilferPointers(overlay->getToken()));
12455 window->consumeMotionCancel();
12456
12457 // The interceptor configures itself so that it is no longer a spy.
12458 overlay->setSpy(false);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070012459 mDispatcher->onWindowInfosChanged({{*overlay->getInfo(), *window->getInfo()}, {}, 0, 0});
Prabir Pradhan6dfbf262022-03-14 15:24:30 +000012460
12461 // It continues to receive the rest of the stylus gesture.
12462 sendStylusEvent(AMOTION_EVENT_ACTION_MOVE);
12463 overlay->consumeMotionMove();
12464 sendStylusEvent(AMOTION_EVENT_ACTION_UP);
12465 overlay->consumeMotionUp();
12466
12467 window->assertNoEvents();
12468}
12469
Prabir Pradhan5735a322022-04-11 17:23:34 +000012470struct User {
Prabir Pradhanaeebeb42023-06-13 19:53:03 +000012471 gui::Pid mPid;
Prabir Pradhan8a5c41d2023-06-08 19:13:46 +000012472 gui::Uid mUid;
Prabir Pradhan5735a322022-04-11 17:23:34 +000012473 uint32_t mPolicyFlags{DEFAULT_POLICY_FLAGS};
12474 std::unique_ptr<InputDispatcher>& mDispatcher;
12475
Prabir Pradhanaeebeb42023-06-13 19:53:03 +000012476 User(std::unique_ptr<InputDispatcher>& dispatcher, gui::Pid pid, gui::Uid uid)
Prabir Pradhan5735a322022-04-11 17:23:34 +000012477 : mPid(pid), mUid(uid), mDispatcher(dispatcher) {}
12478
12479 InputEventInjectionResult injectTargetedMotion(int32_t action) const {
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070012480 return injectMotionEvent(*mDispatcher, action, AINPUT_SOURCE_TOUCHSCREEN,
Prabir Pradhan5735a322022-04-11 17:23:34 +000012481 ADISPLAY_ID_DEFAULT, {100, 200},
12482 {AMOTION_EVENT_INVALID_CURSOR_POSITION,
12483 AMOTION_EVENT_INVALID_CURSOR_POSITION},
12484 INJECT_EVENT_TIMEOUT, InputEventInjectionSync::WAIT_FOR_RESULT,
12485 systemTime(SYSTEM_TIME_MONOTONIC), {mUid}, mPolicyFlags);
12486 }
12487
12488 InputEventInjectionResult injectTargetedKey(int32_t action) const {
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070012489 return inputdispatcher::injectKey(*mDispatcher, action, /*repeatCount=*/0, ADISPLAY_ID_NONE,
Prabir Pradhan5735a322022-04-11 17:23:34 +000012490 InputEventInjectionSync::WAIT_FOR_RESULT,
Harry Cutts33476232023-01-30 19:57:29 +000012491 INJECT_EVENT_TIMEOUT, /*allowKeyRepeat=*/false, {mUid},
Prabir Pradhan5735a322022-04-11 17:23:34 +000012492 mPolicyFlags);
12493 }
12494
Siarhei Vishniakoue3ce4122023-08-23 10:26:46 -070012495 sp<FakeWindowHandle> createWindow(const char* name) const {
Prabir Pradhan5735a322022-04-11 17:23:34 +000012496 std::shared_ptr<FakeApplicationHandle> overlayApplication =
12497 std::make_shared<FakeApplicationHandle>();
Siarhei Vishniakoue3ce4122023-08-23 10:26:46 -070012498 sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(overlayApplication, mDispatcher,
12499 name, ADISPLAY_ID_DEFAULT);
Prabir Pradhan5735a322022-04-11 17:23:34 +000012500 window->setOwnerInfo(mPid, mUid);
12501 return window;
12502 }
12503};
12504
12505using InputDispatcherTargetedInjectionTest = InputDispatcherTest;
12506
12507TEST_F(InputDispatcherTargetedInjectionTest, CanInjectIntoOwnedWindow) {
Prabir Pradhanaeebeb42023-06-13 19:53:03 +000012508 auto owner = User(mDispatcher, gui::Pid{10}, gui::Uid{11});
Siarhei Vishniakoue3ce4122023-08-23 10:26:46 -070012509 auto window = owner.createWindow("Owned window");
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070012510 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Prabir Pradhan5735a322022-04-11 17:23:34 +000012511
12512 EXPECT_EQ(InputEventInjectionResult::SUCCEEDED,
12513 owner.injectTargetedMotion(AMOTION_EVENT_ACTION_DOWN));
12514 window->consumeMotionDown();
12515
12516 setFocusedWindow(window);
12517 window->consumeFocusEvent(true);
12518
12519 EXPECT_EQ(InputEventInjectionResult::SUCCEEDED,
12520 owner.injectTargetedKey(AKEY_EVENT_ACTION_DOWN));
12521 window->consumeKeyDown(ADISPLAY_ID_NONE);
12522}
12523
12524TEST_F(InputDispatcherTargetedInjectionTest, CannotInjectIntoUnownedWindow) {
Prabir Pradhanaeebeb42023-06-13 19:53:03 +000012525 auto owner = User(mDispatcher, gui::Pid{10}, gui::Uid{11});
Siarhei Vishniakoue3ce4122023-08-23 10:26:46 -070012526 auto window = owner.createWindow("Owned window");
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070012527 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Prabir Pradhan5735a322022-04-11 17:23:34 +000012528
Prabir Pradhanaeebeb42023-06-13 19:53:03 +000012529 auto rando = User(mDispatcher, gui::Pid{20}, gui::Uid{21});
Prabir Pradhan5735a322022-04-11 17:23:34 +000012530 EXPECT_EQ(InputEventInjectionResult::TARGET_MISMATCH,
12531 rando.injectTargetedMotion(AMOTION_EVENT_ACTION_DOWN));
12532
12533 setFocusedWindow(window);
12534 window->consumeFocusEvent(true);
12535
12536 EXPECT_EQ(InputEventInjectionResult::TARGET_MISMATCH,
12537 rando.injectTargetedKey(AKEY_EVENT_ACTION_DOWN));
12538 window->assertNoEvents();
12539}
12540
12541TEST_F(InputDispatcherTargetedInjectionTest, CanInjectIntoOwnedSpyWindow) {
Prabir Pradhanaeebeb42023-06-13 19:53:03 +000012542 auto owner = User(mDispatcher, gui::Pid{10}, gui::Uid{11});
Siarhei Vishniakoue3ce4122023-08-23 10:26:46 -070012543 auto window = owner.createWindow("Owned window");
12544 auto spy = owner.createWindow("Owned spy");
Prabir Pradhan5735a322022-04-11 17:23:34 +000012545 spy->setSpy(true);
12546 spy->setTrustedOverlay(true);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070012547 mDispatcher->onWindowInfosChanged({{*spy->getInfo(), *window->getInfo()}, {}, 0, 0});
Prabir Pradhan5735a322022-04-11 17:23:34 +000012548
12549 EXPECT_EQ(InputEventInjectionResult::SUCCEEDED,
12550 owner.injectTargetedMotion(AMOTION_EVENT_ACTION_DOWN));
12551 spy->consumeMotionDown();
12552 window->consumeMotionDown();
12553}
12554
12555TEST_F(InputDispatcherTargetedInjectionTest, CannotInjectIntoUnownedSpyWindow) {
Prabir Pradhanaeebeb42023-06-13 19:53:03 +000012556 auto owner = User(mDispatcher, gui::Pid{10}, gui::Uid{11});
Siarhei Vishniakoue3ce4122023-08-23 10:26:46 -070012557 auto window = owner.createWindow("Owned window");
Prabir Pradhan5735a322022-04-11 17:23:34 +000012558
Prabir Pradhanaeebeb42023-06-13 19:53:03 +000012559 auto rando = User(mDispatcher, gui::Pid{20}, gui::Uid{21});
Siarhei Vishniakoue3ce4122023-08-23 10:26:46 -070012560 auto randosSpy = rando.createWindow("Rando's spy");
Prabir Pradhan5735a322022-04-11 17:23:34 +000012561 randosSpy->setSpy(true);
12562 randosSpy->setTrustedOverlay(true);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070012563 mDispatcher->onWindowInfosChanged({{*randosSpy->getInfo(), *window->getInfo()}, {}, 0, 0});
Prabir Pradhan5735a322022-04-11 17:23:34 +000012564
12565 // The event is targeted at owner's window, so injection should succeed, but the spy should
12566 // not receive the event.
12567 EXPECT_EQ(InputEventInjectionResult::SUCCEEDED,
12568 owner.injectTargetedMotion(AMOTION_EVENT_ACTION_DOWN));
12569 randosSpy->assertNoEvents();
12570 window->consumeMotionDown();
12571}
12572
12573TEST_F(InputDispatcherTargetedInjectionTest, CanInjectIntoAnyWindowWhenNotTargeting) {
Prabir Pradhanaeebeb42023-06-13 19:53:03 +000012574 auto owner = User(mDispatcher, gui::Pid{10}, gui::Uid{11});
Siarhei Vishniakoue3ce4122023-08-23 10:26:46 -070012575 auto window = owner.createWindow("Owned window");
Prabir Pradhan5735a322022-04-11 17:23:34 +000012576
Prabir Pradhanaeebeb42023-06-13 19:53:03 +000012577 auto rando = User(mDispatcher, gui::Pid{20}, gui::Uid{21});
Siarhei Vishniakoue3ce4122023-08-23 10:26:46 -070012578 auto randosSpy = rando.createWindow("Rando's spy");
Prabir Pradhan5735a322022-04-11 17:23:34 +000012579 randosSpy->setSpy(true);
12580 randosSpy->setTrustedOverlay(true);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070012581 mDispatcher->onWindowInfosChanged({{*randosSpy->getInfo(), *window->getInfo()}, {}, 0, 0});
Prabir Pradhan5735a322022-04-11 17:23:34 +000012582
12583 // A user that has injection permission can inject into any window.
12584 EXPECT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070012585 injectMotionEvent(*mDispatcher, AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN,
Prabir Pradhan5735a322022-04-11 17:23:34 +000012586 ADISPLAY_ID_DEFAULT));
12587 randosSpy->consumeMotionDown();
12588 window->consumeMotionDown();
12589
12590 setFocusedWindow(randosSpy);
12591 randosSpy->consumeFocusEvent(true);
12592
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070012593 EXPECT_EQ(InputEventInjectionResult::SUCCEEDED, injectKeyDown(*mDispatcher));
Prabir Pradhan5735a322022-04-11 17:23:34 +000012594 randosSpy->consumeKeyDown(ADISPLAY_ID_NONE);
12595 window->assertNoEvents();
12596}
12597
Siarhei Vishniakou580fb3a2023-05-05 15:02:20 -070012598TEST_F(InputDispatcherTargetedInjectionTest, CannotGenerateActionOutsideToOtherUids) {
Prabir Pradhanaeebeb42023-06-13 19:53:03 +000012599 auto owner = User(mDispatcher, gui::Pid{10}, gui::Uid{11});
Siarhei Vishniakoue3ce4122023-08-23 10:26:46 -070012600 auto window = owner.createWindow("Owned window");
Prabir Pradhan5735a322022-04-11 17:23:34 +000012601
Prabir Pradhanaeebeb42023-06-13 19:53:03 +000012602 auto rando = User(mDispatcher, gui::Pid{20}, gui::Uid{21});
Siarhei Vishniakoue3ce4122023-08-23 10:26:46 -070012603 auto randosWindow = rando.createWindow("Rando's window");
Prabir Pradhan5735a322022-04-11 17:23:34 +000012604 randosWindow->setFrame(Rect{-10, -10, -5, -5});
12605 randosWindow->setWatchOutsideTouch(true);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070012606 mDispatcher->onWindowInfosChanged({{*randosWindow->getInfo(), *window->getInfo()}, {}, 0, 0});
Prabir Pradhan5735a322022-04-11 17:23:34 +000012607
Siarhei Vishniakou580fb3a2023-05-05 15:02:20 -070012608 // Do not allow generation of ACTION_OUTSIDE events into windows owned by different uids.
Prabir Pradhan5735a322022-04-11 17:23:34 +000012609 EXPECT_EQ(InputEventInjectionResult::SUCCEEDED,
12610 owner.injectTargetedMotion(AMOTION_EVENT_ACTION_DOWN));
12611 window->consumeMotionDown();
Siarhei Vishniakou580fb3a2023-05-05 15:02:20 -070012612 randosWindow->assertNoEvents();
Prabir Pradhan5735a322022-04-11 17:23:34 +000012613}
12614
Prabir Pradhan64f21d22023-11-28 21:19:42 +000012615using InputDispatcherPointerInWindowTest = InputDispatcherTest;
12616
12617TEST_F(InputDispatcherPointerInWindowTest, PointerInWindowWhenHovering) {
12618 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
12619
12620 sp<FakeWindowHandle> left = sp<FakeWindowHandle>::make(application, mDispatcher, "Left Window",
12621 ADISPLAY_ID_DEFAULT);
12622 left->setFrame(Rect(0, 0, 100, 100));
12623 sp<FakeWindowHandle> right = sp<FakeWindowHandle>::make(application, mDispatcher,
12624 "Right Window", ADISPLAY_ID_DEFAULT);
12625 right->setFrame(Rect(100, 0, 200, 100));
12626 sp<FakeWindowHandle> spy =
12627 sp<FakeWindowHandle>::make(application, mDispatcher, "Spy Window", ADISPLAY_ID_DEFAULT);
12628 spy->setFrame(Rect(0, 0, 200, 100));
12629 spy->setTrustedOverlay(true);
12630 spy->setSpy(true);
12631
12632 mDispatcher->onWindowInfosChanged(
12633 {{*spy->getInfo(), *left->getInfo(), *right->getInfo()}, {}, 0, 0});
12634
12635 // Hover into the left window.
12636 mDispatcher->notifyMotion(
12637 MotionArgsBuilder(ACTION_HOVER_ENTER, AINPUT_SOURCE_STYLUS)
12638 .pointer(PointerBuilder(/*id=*/0, ToolType::STYLUS).x(50).y(50))
12639 .build());
12640
12641 left->consumeMotionEvent(WithMotionAction(ACTION_HOVER_ENTER));
12642 spy->consumeMotionEvent(WithMotionAction(ACTION_HOVER_ENTER));
12643
12644 ASSERT_TRUE(mDispatcher->isPointerInWindow(left->getToken(), ADISPLAY_ID_DEFAULT, DEVICE_ID,
12645 /*pointerId=*/0));
12646 ASSERT_TRUE(mDispatcher->isPointerInWindow(spy->getToken(), ADISPLAY_ID_DEFAULT, DEVICE_ID,
12647 /*pointerId=*/0));
12648 ASSERT_FALSE(mDispatcher->isPointerInWindow(right->getToken(), ADISPLAY_ID_DEFAULT, DEVICE_ID,
12649 /*pointerId=*/0));
12650
12651 // Hover move to the right window.
12652 mDispatcher->notifyMotion(
12653 MotionArgsBuilder(ACTION_HOVER_MOVE, AINPUT_SOURCE_STYLUS)
12654 .pointer(PointerBuilder(/*id=*/0, ToolType::STYLUS).x(150).y(50))
12655 .build());
12656
12657 left->consumeMotionEvent(WithMotionAction(ACTION_HOVER_EXIT));
12658 right->consumeMotionEvent(WithMotionAction(ACTION_HOVER_ENTER));
12659 spy->consumeMotionEvent(WithMotionAction(ACTION_HOVER_MOVE));
12660
12661 ASSERT_FALSE(mDispatcher->isPointerInWindow(left->getToken(), ADISPLAY_ID_DEFAULT, DEVICE_ID,
12662 /*pointerId=*/0));
12663 ASSERT_TRUE(mDispatcher->isPointerInWindow(spy->getToken(), ADISPLAY_ID_DEFAULT, DEVICE_ID,
12664 /*pointerId=*/0));
12665 ASSERT_TRUE(mDispatcher->isPointerInWindow(right->getToken(), ADISPLAY_ID_DEFAULT, DEVICE_ID,
12666 /*pointerId=*/0));
12667
12668 // Stop hovering.
12669 mDispatcher->notifyMotion(
12670 MotionArgsBuilder(ACTION_HOVER_EXIT, AINPUT_SOURCE_STYLUS)
12671 .pointer(PointerBuilder(/*id=*/0, ToolType::STYLUS).x(150).y(50))
12672 .build());
12673
12674 right->consumeMotionEvent(WithMotionAction(ACTION_HOVER_EXIT));
12675 spy->consumeMotionEvent(WithMotionAction(ACTION_HOVER_EXIT));
12676
12677 ASSERT_FALSE(mDispatcher->isPointerInWindow(left->getToken(), ADISPLAY_ID_DEFAULT, DEVICE_ID,
12678 /*pointerId=*/0));
12679 ASSERT_FALSE(mDispatcher->isPointerInWindow(spy->getToken(), ADISPLAY_ID_DEFAULT, DEVICE_ID,
12680 /*pointerId=*/0));
12681 ASSERT_FALSE(mDispatcher->isPointerInWindow(right->getToken(), ADISPLAY_ID_DEFAULT, DEVICE_ID,
12682 /*pointerId=*/0));
12683}
12684
12685TEST_F(InputDispatcherPointerInWindowTest, PointerInWindowWithSplitTouch) {
12686 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
12687
12688 sp<FakeWindowHandle> left = sp<FakeWindowHandle>::make(application, mDispatcher, "Left Window",
12689 ADISPLAY_ID_DEFAULT);
12690 left->setFrame(Rect(0, 0, 100, 100));
12691 sp<FakeWindowHandle> right = sp<FakeWindowHandle>::make(application, mDispatcher,
12692 "Right Window", ADISPLAY_ID_DEFAULT);
12693 right->setFrame(Rect(100, 0, 200, 100));
12694 sp<FakeWindowHandle> spy =
12695 sp<FakeWindowHandle>::make(application, mDispatcher, "Spy Window", ADISPLAY_ID_DEFAULT);
12696 spy->setFrame(Rect(0, 0, 200, 100));
12697 spy->setTrustedOverlay(true);
12698 spy->setSpy(true);
12699
12700 mDispatcher->onWindowInfosChanged(
12701 {{*spy->getInfo(), *left->getInfo(), *right->getInfo()}, {}, 0, 0});
12702
12703 // First pointer down on left window.
12704 mDispatcher->notifyMotion(
12705 MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
12706 .pointer(PointerBuilder(/*id=*/0, ToolType::FINGER).x(50).y(50))
12707 .build());
12708
12709 left->consumeMotionDown();
12710 spy->consumeMotionDown();
12711
12712 ASSERT_TRUE(mDispatcher->isPointerInWindow(left->getToken(), ADISPLAY_ID_DEFAULT, DEVICE_ID,
12713 /*pointerId=*/0));
12714 ASSERT_TRUE(mDispatcher->isPointerInWindow(spy->getToken(), ADISPLAY_ID_DEFAULT, DEVICE_ID,
12715 /*pointerId=*/0));
12716 ASSERT_FALSE(mDispatcher->isPointerInWindow(right->getToken(), ADISPLAY_ID_DEFAULT, DEVICE_ID,
12717 /*pointerId=*/0));
12718
12719 // Second pointer down on right window.
12720 mDispatcher->notifyMotion(
12721 MotionArgsBuilder(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
12722 .pointer(PointerBuilder(/*id=*/0, ToolType::FINGER).x(50).y(50))
12723 .pointer(PointerBuilder(/*id=*/1, ToolType::FINGER).x(150).y(50))
12724 .build());
12725
12726 left->consumeMotionMove();
12727 right->consumeMotionDown();
12728 spy->consumeMotionEvent(WithMotionAction(POINTER_1_DOWN));
12729
12730 ASSERT_TRUE(mDispatcher->isPointerInWindow(left->getToken(), ADISPLAY_ID_DEFAULT, DEVICE_ID,
12731 /*pointerId=*/0));
12732 ASSERT_TRUE(mDispatcher->isPointerInWindow(spy->getToken(), ADISPLAY_ID_DEFAULT, DEVICE_ID,
12733 /*pointerId=*/0));
12734 ASSERT_FALSE(mDispatcher->isPointerInWindow(right->getToken(), ADISPLAY_ID_DEFAULT, DEVICE_ID,
12735 /*pointerId=*/0));
12736 ASSERT_FALSE(mDispatcher->isPointerInWindow(left->getToken(), ADISPLAY_ID_DEFAULT, DEVICE_ID,
12737 /*pointerId=*/1));
12738 ASSERT_TRUE(mDispatcher->isPointerInWindow(spy->getToken(), ADISPLAY_ID_DEFAULT, DEVICE_ID,
12739 /*pointerId=*/1));
12740 ASSERT_TRUE(mDispatcher->isPointerInWindow(right->getToken(), ADISPLAY_ID_DEFAULT, DEVICE_ID,
12741 /*pointerId=*/1));
12742
12743 // Second pointer up.
12744 mDispatcher->notifyMotion(
12745 MotionArgsBuilder(POINTER_1_UP, AINPUT_SOURCE_TOUCHSCREEN)
12746 .pointer(PointerBuilder(/*id=*/0, ToolType::FINGER).x(50).y(50))
12747 .pointer(PointerBuilder(/*id=*/1, ToolType::FINGER).x(150).y(50))
12748 .build());
12749
12750 left->consumeMotionMove();
12751 right->consumeMotionUp();
12752 spy->consumeMotionEvent(WithMotionAction(POINTER_1_UP));
12753
12754 ASSERT_TRUE(mDispatcher->isPointerInWindow(left->getToken(), ADISPLAY_ID_DEFAULT, DEVICE_ID,
12755 /*pointerId=*/0));
12756 ASSERT_TRUE(mDispatcher->isPointerInWindow(spy->getToken(), ADISPLAY_ID_DEFAULT, DEVICE_ID,
12757 /*pointerId=*/0));
12758 ASSERT_FALSE(mDispatcher->isPointerInWindow(right->getToken(), ADISPLAY_ID_DEFAULT, DEVICE_ID,
12759 /*pointerId=*/0));
12760 ASSERT_FALSE(mDispatcher->isPointerInWindow(left->getToken(), ADISPLAY_ID_DEFAULT, DEVICE_ID,
12761 /*pointerId=*/1));
12762 ASSERT_FALSE(mDispatcher->isPointerInWindow(spy->getToken(), ADISPLAY_ID_DEFAULT, DEVICE_ID,
12763 /*pointerId=*/1));
12764 ASSERT_FALSE(mDispatcher->isPointerInWindow(right->getToken(), ADISPLAY_ID_DEFAULT, DEVICE_ID,
12765 /*pointerId=*/1));
12766
12767 // First pointer up.
12768 mDispatcher->notifyMotion(
12769 MotionArgsBuilder(ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN)
12770 .pointer(PointerBuilder(/*id=*/0, ToolType::FINGER).x(50).y(50))
12771 .build());
12772
12773 left->consumeMotionUp();
12774 spy->consumeMotionUp();
12775
12776 ASSERT_FALSE(mDispatcher->isPointerInWindow(left->getToken(), ADISPLAY_ID_DEFAULT, DEVICE_ID,
12777 /*pointerId=*/0));
12778 ASSERT_FALSE(mDispatcher->isPointerInWindow(spy->getToken(), ADISPLAY_ID_DEFAULT, DEVICE_ID,
12779 /*pointerId=*/0));
12780 ASSERT_FALSE(mDispatcher->isPointerInWindow(right->getToken(), ADISPLAY_ID_DEFAULT, DEVICE_ID,
12781 /*pointerId=*/0));
12782}
12783
Siarhei Vishniakoued89cbb2023-10-13 10:42:44 -070012784TEST_F(InputDispatcherPointerInWindowTest, MultipleDevicesControllingOneMouse_legacy) {
12785 SCOPED_FLAG_OVERRIDE(enable_multi_device_same_window_stream, false);
Prabir Pradhan64f21d22023-11-28 21:19:42 +000012786 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
12787
12788 sp<FakeWindowHandle> left = sp<FakeWindowHandle>::make(application, mDispatcher, "Left Window",
12789 ADISPLAY_ID_DEFAULT);
12790 left->setFrame(Rect(0, 0, 100, 100));
12791 sp<FakeWindowHandle> right = sp<FakeWindowHandle>::make(application, mDispatcher,
12792 "Right Window", ADISPLAY_ID_DEFAULT);
12793 right->setFrame(Rect(100, 0, 200, 100));
12794
12795 mDispatcher->onWindowInfosChanged({{*left->getInfo(), *right->getInfo()}, {}, 0, 0});
12796
12797 ASSERT_FALSE(mDispatcher->isPointerInWindow(left->getToken(), ADISPLAY_ID_DEFAULT, DEVICE_ID,
12798 /*pointerId=*/0));
12799 ASSERT_FALSE(mDispatcher->isPointerInWindow(right->getToken(), ADISPLAY_ID_DEFAULT, DEVICE_ID,
12800 /*pointerId=*/0));
12801
12802 // Hover move into the window.
12803 mDispatcher->notifyMotion(
12804 MotionArgsBuilder(ACTION_HOVER_MOVE, AINPUT_SOURCE_MOUSE)
12805 .pointer(PointerBuilder(/*id=*/0, ToolType::MOUSE).x(50).y(50))
12806 .rawXCursorPosition(50)
12807 .rawYCursorPosition(50)
12808 .deviceId(DEVICE_ID)
12809 .build());
12810
12811 left->consumeMotionEvent(WithMotionAction(ACTION_HOVER_ENTER));
12812
12813 ASSERT_TRUE(mDispatcher->isPointerInWindow(left->getToken(), ADISPLAY_ID_DEFAULT, DEVICE_ID,
12814 /*pointerId=*/0));
12815
12816 // Move the mouse with another device. This cancels the hovering pointer from the first device.
12817 mDispatcher->notifyMotion(
12818 MotionArgsBuilder(ACTION_HOVER_MOVE, AINPUT_SOURCE_MOUSE)
12819 .pointer(PointerBuilder(/*id=*/0, ToolType::MOUSE).x(51).y(50))
12820 .rawXCursorPosition(51)
12821 .rawYCursorPosition(50)
12822 .deviceId(SECOND_DEVICE_ID)
12823 .build());
12824
12825 left->consumeMotionEvent(WithMotionAction(ACTION_HOVER_EXIT));
12826 left->consumeMotionEvent(WithMotionAction(ACTION_HOVER_ENTER));
12827
12828 // TODO(b/313689709): InputDispatcher's touch state is not updated, even though the window gets
12829 // a HOVER_EXIT from the first device.
12830 ASSERT_TRUE(mDispatcher->isPointerInWindow(left->getToken(), ADISPLAY_ID_DEFAULT, DEVICE_ID,
12831 /*pointerId=*/0));
12832 ASSERT_TRUE(mDispatcher->isPointerInWindow(left->getToken(), ADISPLAY_ID_DEFAULT,
12833 SECOND_DEVICE_ID,
12834 /*pointerId=*/0));
12835
12836 // Move the mouse outside the window. Document the current behavior, where the window does not
12837 // receive HOVER_EXIT even though the mouse left the window.
12838 mDispatcher->notifyMotion(
12839 MotionArgsBuilder(ACTION_HOVER_MOVE, AINPUT_SOURCE_MOUSE)
12840 .pointer(PointerBuilder(/*id=*/0, ToolType::MOUSE).x(150).y(50))
12841 .rawXCursorPosition(150)
12842 .rawYCursorPosition(50)
12843 .deviceId(SECOND_DEVICE_ID)
12844 .build());
12845
12846 left->consumeMotionEvent(WithMotionAction(ACTION_HOVER_EXIT));
12847 right->consumeMotionEvent(WithMotionAction(ACTION_HOVER_ENTER));
12848 ASSERT_TRUE(mDispatcher->isPointerInWindow(left->getToken(), ADISPLAY_ID_DEFAULT, DEVICE_ID,
12849 /*pointerId=*/0));
12850 ASSERT_FALSE(mDispatcher->isPointerInWindow(left->getToken(), ADISPLAY_ID_DEFAULT,
12851 SECOND_DEVICE_ID,
12852 /*pointerId=*/0));
12853}
12854
Siarhei Vishniakoued89cbb2023-10-13 10:42:44 -070012855/**
12856 * TODO(b/313689709) - correctly support multiple mouse devices, because they should be controlling
12857 * the same cursor, and therefore have a shared motion event stream.
12858 */
12859TEST_F(InputDispatcherPointerInWindowTest, MultipleDevicesControllingOneMouse) {
12860 SCOPED_FLAG_OVERRIDE(enable_multi_device_same_window_stream, true);
12861 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
12862
12863 sp<FakeWindowHandle> left = sp<FakeWindowHandle>::make(application, mDispatcher, "Left Window",
12864 ADISPLAY_ID_DEFAULT);
12865 left->setFrame(Rect(0, 0, 100, 100));
12866 sp<FakeWindowHandle> right = sp<FakeWindowHandle>::make(application, mDispatcher,
12867 "Right Window", ADISPLAY_ID_DEFAULT);
12868 right->setFrame(Rect(100, 0, 200, 100));
12869
12870 mDispatcher->onWindowInfosChanged({{*left->getInfo(), *right->getInfo()}, {}, 0, 0});
12871
12872 ASSERT_FALSE(mDispatcher->isPointerInWindow(left->getToken(), ADISPLAY_ID_DEFAULT, DEVICE_ID,
12873 /*pointerId=*/0));
12874 ASSERT_FALSE(mDispatcher->isPointerInWindow(right->getToken(), ADISPLAY_ID_DEFAULT, DEVICE_ID,
12875 /*pointerId=*/0));
12876
12877 // Hover move into the window.
12878 mDispatcher->notifyMotion(
12879 MotionArgsBuilder(ACTION_HOVER_MOVE, AINPUT_SOURCE_MOUSE)
12880 .pointer(PointerBuilder(/*id=*/0, ToolType::MOUSE).x(50).y(50))
12881 .rawXCursorPosition(50)
12882 .rawYCursorPosition(50)
12883 .deviceId(DEVICE_ID)
12884 .build());
12885
12886 left->consumeMotionEvent(WithMotionAction(ACTION_HOVER_ENTER));
12887
12888 ASSERT_TRUE(mDispatcher->isPointerInWindow(left->getToken(), ADISPLAY_ID_DEFAULT, DEVICE_ID,
12889 /*pointerId=*/0));
12890
12891 // Move the mouse with another device
12892 mDispatcher->notifyMotion(
12893 MotionArgsBuilder(ACTION_HOVER_MOVE, AINPUT_SOURCE_MOUSE)
12894 .pointer(PointerBuilder(/*id=*/0, ToolType::MOUSE).x(51).y(50))
12895 .rawXCursorPosition(51)
12896 .rawYCursorPosition(50)
12897 .deviceId(SECOND_DEVICE_ID)
12898 .build());
12899 left->consumeMotionEvent(WithMotionAction(ACTION_HOVER_ENTER));
12900
12901 // TODO(b/313689709): InputDispatcher's touch state is not updated, even though the window gets
12902 // a HOVER_EXIT from the first device.
12903 ASSERT_TRUE(mDispatcher->isPointerInWindow(left->getToken(), ADISPLAY_ID_DEFAULT, DEVICE_ID,
12904 /*pointerId=*/0));
12905 ASSERT_TRUE(mDispatcher->isPointerInWindow(left->getToken(), ADISPLAY_ID_DEFAULT,
12906 SECOND_DEVICE_ID,
12907 /*pointerId=*/0));
12908
12909 // Move the mouse outside the window. Document the current behavior, where the window does not
12910 // receive HOVER_EXIT even though the mouse left the window.
12911 mDispatcher->notifyMotion(
12912 MotionArgsBuilder(ACTION_HOVER_MOVE, AINPUT_SOURCE_MOUSE)
12913 .pointer(PointerBuilder(/*id=*/0, ToolType::MOUSE).x(150).y(50))
12914 .rawXCursorPosition(150)
12915 .rawYCursorPosition(50)
12916 .deviceId(SECOND_DEVICE_ID)
12917 .build());
12918
12919 right->consumeMotionEvent(WithMotionAction(ACTION_HOVER_ENTER));
12920 ASSERT_TRUE(mDispatcher->isPointerInWindow(left->getToken(), ADISPLAY_ID_DEFAULT, DEVICE_ID,
12921 /*pointerId=*/0));
12922 ASSERT_FALSE(mDispatcher->isPointerInWindow(left->getToken(), ADISPLAY_ID_DEFAULT,
12923 SECOND_DEVICE_ID,
12924 /*pointerId=*/0));
12925}
12926
Garfield Tane84e6f92019-08-29 17:28:41 -070012927} // namespace android::inputdispatcher