blob: ccd28f31f4562a9ac3033d0c022dd0817897edbd [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/**
Linnan Liccf6ce32024-04-11 20:32:13 +08004803 * Three windows:
4804 * - Left window
4805 * - Right window
4806 * - Outside window(watch for ACTION_OUTSIDE events)
4807 * The windows "left" and "outside" share the same owner, the window "right" has a different owner,
4808 * In order to allow the outside window can receive the ACTION_OUTSIDE events, the outside window is
4809 * positioned above the "left" and "right" windows, and it doesn't overlap with them.
4810 *
4811 * First, device A report a down event landed in the right window, the outside window can receive
4812 * an ACTION_OUTSIDE event that with zeroed coordinates, the device B report a down event landed
4813 * in the left window, the outside window can receive an ACTION_OUTSIDE event the with valid
4814 * coordinates, after these, device A and device B continue report MOVE event, the right and left
4815 * window can receive it, but outside window event can't receive it.
4816 */
4817TEST_F(InputDispatcherTest, ActionOutsideForOwnedWindowHasValidCoordinatesWhenMultiDevice) {
4818 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
4819 sp<FakeWindowHandle> leftWindow =
4820 sp<FakeWindowHandle>::make(application, mDispatcher, "Left Window",
4821 ADISPLAY_ID_DEFAULT);
4822 leftWindow->setFrame(Rect{0, 0, 100, 100});
4823 leftWindow->setOwnerInfo(gui::Pid{1}, gui::Uid{101});
4824
4825 sp<FakeWindowHandle> outsideWindow =
4826 sp<FakeWindowHandle>::make(application, mDispatcher, "Outside Window",
4827 ADISPLAY_ID_DEFAULT);
4828 outsideWindow->setFrame(Rect{100, 100, 200, 200});
4829 outsideWindow->setOwnerInfo(gui::Pid{1}, gui::Uid{101});
4830 outsideWindow->setWatchOutsideTouch(true);
4831
4832 std::shared_ptr<FakeApplicationHandle> anotherApplication =
4833 std::make_shared<FakeApplicationHandle>();
4834 sp<FakeWindowHandle> rightWindow =
4835 sp<FakeWindowHandle>::make(anotherApplication, mDispatcher, "Right Window",
4836 ADISPLAY_ID_DEFAULT);
4837 rightWindow->setFrame(Rect{100, 0, 200, 100});
4838 rightWindow->setOwnerInfo(gui::Pid{2}, gui::Uid{202});
4839
4840 // OutsideWindow must be above left window and right window to receive ACTION_OUTSIDE events
4841 // when left window or right window is tapped
4842 mDispatcher->onWindowInfosChanged(
4843 {{*outsideWindow->getInfo(), *leftWindow->getInfo(), *rightWindow->getInfo()},
4844 {},
4845 0,
4846 0});
4847
4848 const DeviceId deviceA = 9;
4849 const DeviceId deviceB = 3;
4850
4851 // Tap on right window use device A
4852 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
4853 .pointer(PointerBuilder(0, ToolType::FINGER).x(150).y(50))
4854 .deviceId(deviceA)
4855 .build());
4856 leftWindow->assertNoEvents();
4857 rightWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(deviceA)));
4858 // Right window is belonged to another owner, so outsideWindow should receive ACTION_OUTSIDE
4859 // with zeroed coords.
4860 outsideWindow->consumeMotionEvent(
4861 AllOf(WithMotionAction(ACTION_OUTSIDE), WithDeviceId(deviceA), WithCoords(0, 0)));
4862
4863 // Tap on left window use device B
4864 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
4865 .pointer(PointerBuilder(0, ToolType::FINGER).x(50).y(50))
4866 .deviceId(deviceB)
4867 .build());
4868 leftWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(deviceB)));
4869 rightWindow->assertNoEvents();
4870 // Because new gesture down on the left window that has the same owner with outside Window, the
4871 // outside Window should receive the ACTION_OUTSIDE with coords.
4872 outsideWindow->consumeMotionEvent(
4873 AllOf(WithMotionAction(ACTION_OUTSIDE), WithDeviceId(deviceB), WithCoords(-50, -50)));
4874
4875 // Ensure that windows that can only accept outside do not receive remaining gestures
4876 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN)
4877 .pointer(PointerBuilder(0, ToolType::FINGER).x(151).y(51))
4878 .deviceId(deviceA)
4879 .build());
4880 leftWindow->assertNoEvents();
4881 rightWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(deviceA)));
4882
4883 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN)
4884 .pointer(PointerBuilder(0, ToolType::FINGER).x(51).y(51))
4885 .deviceId(deviceB)
4886 .build());
4887 leftWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(deviceB)));
4888 rightWindow->assertNoEvents();
4889 outsideWindow->assertNoEvents();
4890}
4891
4892/**
Prabir Pradhanb60b1dc2022-03-15 14:02:35 +00004893 * This test documents the behavior of WATCH_OUTSIDE_TOUCH. The window will get ACTION_OUTSIDE when
4894 * a another pointer causes ACTION_DOWN to be sent to another window for the first time. Only one
4895 * ACTION_OUTSIDE event is sent per gesture.
4896 */
4897TEST_F(InputDispatcherTest, ActionOutsideSentOnlyWhenAWindowIsTouched) {
4898 // There are three windows that do not overlap. `window` wants to WATCH_OUTSIDE_TOUCH.
4899 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07004900 sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher,
4901 "First Window", ADISPLAY_ID_DEFAULT);
Prabir Pradhanb60b1dc2022-03-15 14:02:35 +00004902 window->setWatchOutsideTouch(true);
4903 window->setFrame(Rect{0, 0, 100, 100});
4904 sp<FakeWindowHandle> secondWindow =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07004905 sp<FakeWindowHandle>::make(application, mDispatcher, "Second Window",
4906 ADISPLAY_ID_DEFAULT);
Prabir Pradhanb60b1dc2022-03-15 14:02:35 +00004907 secondWindow->setFrame(Rect{100, 100, 200, 200});
4908 sp<FakeWindowHandle> thirdWindow =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07004909 sp<FakeWindowHandle>::make(application, mDispatcher, "Third Window",
4910 ADISPLAY_ID_DEFAULT);
Prabir Pradhanb60b1dc2022-03-15 14:02:35 +00004911 thirdWindow->setFrame(Rect{200, 200, 300, 300});
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07004912 mDispatcher->onWindowInfosChanged(
4913 {{*window->getInfo(), *secondWindow->getInfo(), *thirdWindow->getInfo()}, {}, 0, 0});
Prabir Pradhanb60b1dc2022-03-15 14:02:35 +00004914
4915 // First pointer lands outside all windows. `window` does not get ACTION_OUTSIDE.
Prabir Pradhan678438e2023-04-13 19:32:51 +00004916 mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_DOWN,
4917 AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
4918 {PointF{-10, -10}}));
Prabir Pradhanb60b1dc2022-03-15 14:02:35 +00004919 window->assertNoEvents();
4920 secondWindow->assertNoEvents();
4921
4922 // The second pointer lands inside `secondWindow`, which should receive a DOWN event.
4923 // Now, `window` should get ACTION_OUTSIDE.
Prabir Pradhan678438e2023-04-13 19:32:51 +00004924 mDispatcher->notifyMotion(generateMotionArgs(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN,
4925 ADISPLAY_ID_DEFAULT,
4926 {PointF{-10, -10}, PointF{105, 105}}));
Siarhei Vishniakou487c49b2022-12-02 15:48:57 -08004927 const std::map<int32_t, PointF> expectedPointers{{0, PointF{-10, -10}}, {1, PointF{105, 105}}};
4928 window->consumeMotionEvent(
4929 AllOf(WithMotionAction(ACTION_OUTSIDE), WithPointers(expectedPointers)));
Prabir Pradhanb60b1dc2022-03-15 14:02:35 +00004930 secondWindow->consumeMotionDown();
4931 thirdWindow->assertNoEvents();
4932
4933 // The third pointer lands inside `thirdWindow`, which should receive a DOWN event. There is
4934 // no ACTION_OUTSIDE sent to `window` because one has already been sent for this gesture.
Prabir Pradhan678438e2023-04-13 19:32:51 +00004935 mDispatcher->notifyMotion(
4936 generateMotionArgs(POINTER_2_DOWN, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
4937 {PointF{-10, -10}, PointF{105, 105}, PointF{205, 205}}));
Prabir Pradhanb60b1dc2022-03-15 14:02:35 +00004938 window->assertNoEvents();
4939 secondWindow->consumeMotionMove();
4940 thirdWindow->consumeMotionDown();
4941}
4942
Prabir Pradhan814fe082022-07-22 20:22:18 +00004943TEST_F(InputDispatcherTest, OnWindowInfosChanged_RemoveAllWindowsOnDisplay) {
4944 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07004945 sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher,
4946 "Fake Window", ADISPLAY_ID_DEFAULT);
Prabir Pradhan814fe082022-07-22 20:22:18 +00004947 window->setFocusable(true);
4948
Patrick Williamsd828f302023-04-28 17:52:08 -05004949 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Prabir Pradhan814fe082022-07-22 20:22:18 +00004950 setFocusedWindow(window);
4951
4952 window->consumeFocusEvent(true);
4953
Prabir Pradhan678438e2023-04-13 19:32:51 +00004954 const NotifyKeyArgs keyDown = generateKeyArgs(AKEY_EVENT_ACTION_DOWN, ADISPLAY_ID_DEFAULT);
4955 const NotifyKeyArgs keyUp = generateKeyArgs(AKEY_EVENT_ACTION_UP, ADISPLAY_ID_DEFAULT);
4956 mDispatcher->notifyKey(keyDown);
4957 mDispatcher->notifyKey(keyUp);
Prabir Pradhan814fe082022-07-22 20:22:18 +00004958
4959 window->consumeKeyDown(ADISPLAY_ID_DEFAULT);
4960 window->consumeKeyUp(ADISPLAY_ID_DEFAULT);
4961
4962 // All windows are removed from the display. Ensure that we can no longer dispatch to it.
Patrick Williamsd828f302023-04-28 17:52:08 -05004963 mDispatcher->onWindowInfosChanged({{}, {}, 0, 0});
Prabir Pradhan814fe082022-07-22 20:22:18 +00004964
4965 window->consumeFocusEvent(false);
4966
Prabir Pradhan678438e2023-04-13 19:32:51 +00004967 mDispatcher->notifyKey(keyDown);
4968 mDispatcher->notifyKey(keyUp);
Prabir Pradhan814fe082022-07-22 20:22:18 +00004969 window->assertNoEvents();
4970}
4971
Arthur Hung96483742022-11-15 03:30:48 +00004972TEST_F(InputDispatcherTest, NonSplitTouchableWindowReceivesMultiTouch) {
4973 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
4974 sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher,
4975 "Fake Window", ADISPLAY_ID_DEFAULT);
4976 // Ensure window is non-split and have some transform.
4977 window->setPreventSplitting(true);
4978 window->setWindowOffset(20, 40);
Patrick Williamsd828f302023-04-28 17:52:08 -05004979 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Arthur Hung96483742022-11-15 03:30:48 +00004980
4981 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07004982 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
Arthur Hung96483742022-11-15 03:30:48 +00004983 {50, 50}))
4984 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
4985 window->consumeMotionDown(ADISPLAY_ID_DEFAULT);
4986
4987 const MotionEvent secondFingerDownEvent =
4988 MotionEventBuilder(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
4989 .displayId(ADISPLAY_ID_DEFAULT)
4990 .eventTime(systemTime(SYSTEM_TIME_MONOTONIC))
Siarhei Vishniakou6d73f832022-07-21 17:27:03 -07004991 .pointer(PointerBuilder(/*id=*/0, ToolType::FINGER).x(50).y(50))
4992 .pointer(PointerBuilder(/*id=*/1, ToolType::FINGER).x(-30).y(-50))
Arthur Hung96483742022-11-15 03:30:48 +00004993 .build();
4994 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07004995 injectMotionEvent(*mDispatcher, secondFingerDownEvent, INJECT_EVENT_TIMEOUT,
Arthur Hung96483742022-11-15 03:30:48 +00004996 InputEventInjectionSync::WAIT_FOR_RESULT))
4997 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
4998
Siarhei Vishniakoud3061ab2023-12-18 20:41:08 -08004999 std::unique_ptr<MotionEvent> event = window->consumeMotionEvent();
5000 ASSERT_NE(nullptr, event);
5001 EXPECT_EQ(POINTER_1_DOWN, event->getAction());
5002 EXPECT_EQ(70, event->getX(0)); // 50 + 20
5003 EXPECT_EQ(90, event->getY(0)); // 50 + 40
5004 EXPECT_EQ(-10, event->getX(1)); // -30 + 20
5005 EXPECT_EQ(-10, event->getY(1)); // -50 + 40
Arthur Hung96483742022-11-15 03:30:48 +00005006}
5007
Siarhei Vishniakou25537f82023-07-18 14:35:47 -07005008/**
5009 * Two windows: a splittable and a non-splittable.
5010 * The non-splittable window shouldn't receive any "incomplete" gestures.
5011 * Send the first pointer to the splittable window, and then touch the non-splittable window.
5012 * The second pointer should be dropped because the initial window is splittable, so it won't get
5013 * any pointers outside of it, and the second window is non-splittable, so it shouldn't get any
5014 * "incomplete" gestures.
5015 */
5016TEST_F(InputDispatcherTest, SplittableAndNonSplittableWindows) {
5017 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
5018 sp<FakeWindowHandle> leftWindow =
5019 sp<FakeWindowHandle>::make(application, mDispatcher, "Left splittable Window",
5020 ADISPLAY_ID_DEFAULT);
5021 leftWindow->setPreventSplitting(false);
5022 leftWindow->setFrame(Rect(0, 0, 100, 100));
5023 sp<FakeWindowHandle> rightWindow =
5024 sp<FakeWindowHandle>::make(application, mDispatcher, "Right non-splittable Window",
5025 ADISPLAY_ID_DEFAULT);
5026 rightWindow->setPreventSplitting(true);
5027 rightWindow->setFrame(Rect(100, 100, 200, 200));
5028 mDispatcher->onWindowInfosChanged(
5029 {{*leftWindow->getInfo(), *rightWindow->getInfo()}, {}, 0, 0});
5030
5031 // Touch down on left, splittable window
5032 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
5033 .pointer(PointerBuilder(0, ToolType::FINGER).x(50).y(50))
5034 .build());
5035 leftWindow->consumeMotionEvent(WithMotionAction(ACTION_DOWN));
5036
5037 mDispatcher->notifyMotion(
5038 MotionArgsBuilder(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
5039 .pointer(PointerBuilder(/*id=*/0, ToolType::FINGER).x(50).y(50))
5040 .pointer(PointerBuilder(/*id=*/1, ToolType::FINGER).x(150).y(150))
5041 .build());
5042 leftWindow->assertNoEvents();
5043 rightWindow->assertNoEvents();
5044}
5045
Harry Cuttsb166c002023-05-09 13:06:05 +00005046TEST_F(InputDispatcherTest, TouchpadThreeFingerSwipeOnlySentToTrustedOverlays) {
5047 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
5048 sp<FakeWindowHandle> window =
5049 sp<FakeWindowHandle>::make(application, mDispatcher, "Window", ADISPLAY_ID_DEFAULT);
5050 window->setFrame(Rect(0, 0, 400, 400));
5051 sp<FakeWindowHandle> trustedOverlay =
5052 sp<FakeWindowHandle>::make(application, mDispatcher, "Trusted Overlay",
5053 ADISPLAY_ID_DEFAULT);
5054 trustedOverlay->setSpy(true);
5055 trustedOverlay->setTrustedOverlay(true);
5056
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07005057 mDispatcher->onWindowInfosChanged({{*trustedOverlay->getInfo(), *window->getInfo()}, {}, 0, 0});
Harry Cuttsb166c002023-05-09 13:06:05 +00005058
5059 // Start a three-finger touchpad swipe
5060 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_MOUSE)
5061 .pointer(PointerBuilder(0, ToolType::FINGER).x(200).y(100))
5062 .classification(MotionClassification::MULTI_FINGER_SWIPE)
5063 .build());
5064 mDispatcher->notifyMotion(MotionArgsBuilder(POINTER_1_DOWN, AINPUT_SOURCE_MOUSE)
5065 .pointer(PointerBuilder(0, ToolType::FINGER).x(200).y(100))
5066 .pointer(PointerBuilder(1, ToolType::FINGER).x(250).y(100))
5067 .classification(MotionClassification::MULTI_FINGER_SWIPE)
5068 .build());
5069 mDispatcher->notifyMotion(MotionArgsBuilder(POINTER_2_DOWN, AINPUT_SOURCE_MOUSE)
5070 .pointer(PointerBuilder(0, ToolType::FINGER).x(200).y(100))
5071 .pointer(PointerBuilder(1, ToolType::FINGER).x(250).y(100))
5072 .pointer(PointerBuilder(2, ToolType::FINGER).x(300).y(100))
5073 .classification(MotionClassification::MULTI_FINGER_SWIPE)
5074 .build());
5075
5076 trustedOverlay->consumeMotionEvent(WithMotionAction(ACTION_DOWN));
5077 trustedOverlay->consumeMotionEvent(WithMotionAction(POINTER_1_DOWN));
5078 trustedOverlay->consumeMotionEvent(WithMotionAction(POINTER_2_DOWN));
5079
5080 // Move the swipe a bit
5081 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_MOUSE)
5082 .pointer(PointerBuilder(0, ToolType::FINGER).x(200).y(105))
5083 .pointer(PointerBuilder(1, ToolType::FINGER).x(250).y(105))
5084 .pointer(PointerBuilder(2, ToolType::FINGER).x(300).y(105))
5085 .classification(MotionClassification::MULTI_FINGER_SWIPE)
5086 .build());
5087
5088 trustedOverlay->consumeMotionEvent(WithMotionAction(ACTION_MOVE));
5089
5090 // End the swipe
5091 mDispatcher->notifyMotion(MotionArgsBuilder(POINTER_2_UP, AINPUT_SOURCE_MOUSE)
5092 .pointer(PointerBuilder(0, ToolType::FINGER).x(200).y(105))
5093 .pointer(PointerBuilder(1, ToolType::FINGER).x(250).y(105))
5094 .pointer(PointerBuilder(2, ToolType::FINGER).x(300).y(105))
5095 .classification(MotionClassification::MULTI_FINGER_SWIPE)
5096 .build());
5097 mDispatcher->notifyMotion(MotionArgsBuilder(POINTER_1_UP, AINPUT_SOURCE_MOUSE)
5098 .pointer(PointerBuilder(0, ToolType::FINGER).x(200).y(105))
5099 .pointer(PointerBuilder(1, ToolType::FINGER).x(250).y(105))
5100 .classification(MotionClassification::MULTI_FINGER_SWIPE)
5101 .build());
5102 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_UP, AINPUT_SOURCE_MOUSE)
5103 .pointer(PointerBuilder(0, ToolType::FINGER).x(200).y(105))
5104 .classification(MotionClassification::MULTI_FINGER_SWIPE)
5105 .build());
5106
5107 trustedOverlay->consumeMotionEvent(WithMotionAction(POINTER_2_UP));
5108 trustedOverlay->consumeMotionEvent(WithMotionAction(POINTER_1_UP));
5109 trustedOverlay->consumeMotionEvent(WithMotionAction(ACTION_UP));
5110
5111 window->assertNoEvents();
5112}
5113
5114TEST_F(InputDispatcherTest, TouchpadThreeFingerSwipeNotSentToSingleWindow) {
5115 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
5116 sp<FakeWindowHandle> window =
5117 sp<FakeWindowHandle>::make(application, mDispatcher, "Window", ADISPLAY_ID_DEFAULT);
5118 window->setFrame(Rect(0, 0, 400, 400));
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07005119 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Harry Cuttsb166c002023-05-09 13:06:05 +00005120
5121 // Start a three-finger touchpad swipe
5122 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_MOUSE)
5123 .pointer(PointerBuilder(0, ToolType::FINGER).x(200).y(100))
5124 .classification(MotionClassification::MULTI_FINGER_SWIPE)
5125 .build());
5126 mDispatcher->notifyMotion(MotionArgsBuilder(POINTER_1_DOWN, AINPUT_SOURCE_MOUSE)
5127 .pointer(PointerBuilder(0, ToolType::FINGER).x(200).y(100))
5128 .pointer(PointerBuilder(1, ToolType::FINGER).x(250).y(100))
5129 .classification(MotionClassification::MULTI_FINGER_SWIPE)
5130 .build());
5131 mDispatcher->notifyMotion(MotionArgsBuilder(POINTER_2_DOWN, AINPUT_SOURCE_MOUSE)
5132 .pointer(PointerBuilder(0, ToolType::FINGER).x(200).y(100))
5133 .pointer(PointerBuilder(1, ToolType::FINGER).x(250).y(100))
5134 .pointer(PointerBuilder(2, ToolType::FINGER).x(300).y(100))
5135 .classification(MotionClassification::MULTI_FINGER_SWIPE)
5136 .build());
5137
5138 // Move the swipe a bit
5139 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_MOUSE)
5140 .pointer(PointerBuilder(0, ToolType::FINGER).x(200).y(105))
5141 .pointer(PointerBuilder(1, ToolType::FINGER).x(250).y(105))
5142 .pointer(PointerBuilder(2, ToolType::FINGER).x(300).y(105))
5143 .classification(MotionClassification::MULTI_FINGER_SWIPE)
5144 .build());
5145
5146 // End the swipe
5147 mDispatcher->notifyMotion(MotionArgsBuilder(POINTER_2_UP, AINPUT_SOURCE_MOUSE)
5148 .pointer(PointerBuilder(0, ToolType::FINGER).x(200).y(105))
5149 .pointer(PointerBuilder(1, ToolType::FINGER).x(250).y(105))
5150 .pointer(PointerBuilder(2, ToolType::FINGER).x(300).y(105))
5151 .classification(MotionClassification::MULTI_FINGER_SWIPE)
5152 .build());
5153 mDispatcher->notifyMotion(MotionArgsBuilder(POINTER_1_UP, AINPUT_SOURCE_MOUSE)
5154 .pointer(PointerBuilder(0, ToolType::FINGER).x(200).y(105))
5155 .pointer(PointerBuilder(1, ToolType::FINGER).x(250).y(105))
5156 .classification(MotionClassification::MULTI_FINGER_SWIPE)
5157 .build());
5158 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_UP, AINPUT_SOURCE_MOUSE)
5159 .pointer(PointerBuilder(0, ToolType::FINGER).x(200).y(105))
5160 .classification(MotionClassification::MULTI_FINGER_SWIPE)
5161 .build());
5162
5163 window->assertNoEvents();
5164}
5165
Prabir Pradhanb60b1dc2022-03-15 14:02:35 +00005166/**
Siarhei Vishniakouadb9fc92023-05-26 10:46:09 -07005167 * Send a two-pointer gesture to a single window. The window's orientation changes in response to
5168 * the first pointer.
Prabir Pradhan69d00bf2023-06-23 19:55:18 +00005169 * Ensure that the second pointer and the subsequent gesture is correctly delivered to the window.
Siarhei Vishniakouadb9fc92023-05-26 10:46:09 -07005170 */
5171TEST_F(InputDispatcherTest, MultiplePointersWithRotatingWindow) {
5172 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
5173 sp<FakeWindowHandle> window =
5174 sp<FakeWindowHandle>::make(application, mDispatcher, "Window", ADISPLAY_ID_DEFAULT);
5175 window->setFrame(Rect(0, 0, 400, 400));
Siarhei Vishniakou700424c2023-07-18 17:18:42 -07005176 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Siarhei Vishniakouadb9fc92023-05-26 10:46:09 -07005177
5178 const nsecs_t baseTime = systemTime(SYSTEM_TIME_MONOTONIC);
5179 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
5180 .downTime(baseTime + 10)
5181 .eventTime(baseTime + 10)
5182 .pointer(PointerBuilder(0, ToolType::FINGER).x(100).y(100))
5183 .build());
5184
5185 window->consumeMotionEvent(WithMotionAction(ACTION_DOWN));
5186
Siarhei Vishniakouadb9fc92023-05-26 10:46:09 -07005187 // Change the transform so that the orientation is now different from original.
Siarhei Vishniakou700424c2023-07-18 17:18:42 -07005188 window->setWindowTransform(0, -1, 1, 0);
Siarhei Vishniakouadb9fc92023-05-26 10:46:09 -07005189
Siarhei Vishniakou700424c2023-07-18 17:18:42 -07005190 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Siarhei Vishniakouadb9fc92023-05-26 10:46:09 -07005191
Siarhei Vishniakouadb9fc92023-05-26 10:46:09 -07005192 mDispatcher->notifyMotion(MotionArgsBuilder(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
5193 .downTime(baseTime + 10)
5194 .eventTime(baseTime + 30)
5195 .pointer(PointerBuilder(0, ToolType::FINGER).x(100).y(100))
5196 .pointer(PointerBuilder(1, ToolType::FINGER).x(200).y(200))
5197 .build());
5198
Prabir Pradhan69d00bf2023-06-23 19:55:18 +00005199 window->consumeMotionEvent(WithMotionAction(POINTER_1_DOWN));
5200
5201 // Finish the gesture and start a new one. Ensure all events are sent to the window.
Siarhei Vishniakouadb9fc92023-05-26 10:46:09 -07005202 mDispatcher->notifyMotion(MotionArgsBuilder(POINTER_1_UP, AINPUT_SOURCE_TOUCHSCREEN)
5203 .downTime(baseTime + 10)
5204 .eventTime(baseTime + 40)
5205 .pointer(PointerBuilder(0, ToolType::FINGER).x(100).y(100))
5206 .pointer(PointerBuilder(1, ToolType::FINGER).x(200).y(200))
5207 .build());
Prabir Pradhan69d00bf2023-06-23 19:55:18 +00005208
5209 window->consumeMotionEvent(WithMotionAction(POINTER_1_UP));
5210
Siarhei Vishniakouadb9fc92023-05-26 10:46:09 -07005211 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN)
5212 .downTime(baseTime + 10)
5213 .eventTime(baseTime + 50)
5214 .pointer(PointerBuilder(0, ToolType::FINGER).x(100).y(100))
5215 .build());
5216
Prabir Pradhan69d00bf2023-06-23 19:55:18 +00005217 window->consumeMotionEvent(WithMotionAction(ACTION_UP));
5218
Siarhei Vishniakouadb9fc92023-05-26 10:46:09 -07005219 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
5220 .downTime(baseTime + 60)
5221 .eventTime(baseTime + 60)
5222 .pointer(PointerBuilder(0, ToolType::FINGER).x(40).y(40))
5223 .build());
5224
Siarhei Vishniakou700424c2023-07-18 17:18:42 -07005225 window->consumeMotionEvent(WithMotionAction(ACTION_DOWN));
Siarhei Vishniakouadb9fc92023-05-26 10:46:09 -07005226}
5227
5228/**
Hu Guo771a7692023-09-17 20:51:08 +08005229 * When there are multiple screens, such as screen projection to TV or screen recording, if the
5230 * cancel event occurs, the coordinates of the cancel event should be sent to the target screen, and
5231 * its coordinates should be converted by the transform of the windows of target screen.
5232 */
5233TEST_F(InputDispatcherTest, WhenMultiDisplayWindowSameToken_DispatchCancelToTargetDisplay) {
5234 // This case will create a window and a spy window on the default display and mirror
5235 // window on the second display. cancel event is sent through spy window pilferPointers
5236 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
5237
5238 sp<FakeWindowHandle> spyWindowDefaultDisplay =
5239 sp<FakeWindowHandle>::make(application, mDispatcher, "Spy", ADISPLAY_ID_DEFAULT);
5240 spyWindowDefaultDisplay->setTrustedOverlay(true);
5241 spyWindowDefaultDisplay->setSpy(true);
5242
5243 sp<FakeWindowHandle> windowDefaultDisplay =
5244 sp<FakeWindowHandle>::make(application, mDispatcher, "DefaultDisplay",
5245 ADISPLAY_ID_DEFAULT);
5246 windowDefaultDisplay->setWindowTransform(1, 0, 0, 1);
5247
5248 sp<FakeWindowHandle> windowSecondDisplay = windowDefaultDisplay->clone(SECOND_DISPLAY_ID);
5249 windowSecondDisplay->setWindowTransform(2, 0, 0, 2);
5250
5251 // Add the windows to the dispatcher
5252 mDispatcher->onWindowInfosChanged(
5253 {{*spyWindowDefaultDisplay->getInfo(), *windowDefaultDisplay->getInfo(),
5254 *windowSecondDisplay->getInfo()},
5255 {},
5256 0,
5257 0});
5258
5259 // Send down to ADISPLAY_ID_DEFAULT
5260 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
5261 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
5262 {100, 100}))
5263 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
5264
5265 spyWindowDefaultDisplay->consumeMotionDown();
5266 windowDefaultDisplay->consumeMotionDown();
5267
5268 EXPECT_EQ(OK, mDispatcher->pilferPointers(spyWindowDefaultDisplay->getToken()));
5269
5270 // windowDefaultDisplay gets cancel
Siarhei Vishniakoud3061ab2023-12-18 20:41:08 -08005271 std::unique_ptr<MotionEvent> event = windowDefaultDisplay->consumeMotionEvent();
5272 ASSERT_NE(nullptr, event);
5273 EXPECT_EQ(AMOTION_EVENT_ACTION_CANCEL, event->getAction());
Hu Guo771a7692023-09-17 20:51:08 +08005274
5275 // The cancel event is sent to windowDefaultDisplay of the ADISPLAY_ID_DEFAULT display, so the
5276 // coordinates of the cancel are converted by windowDefaultDisplay's transform, the x and y
5277 // coordinates are both 100, otherwise if the cancel event is sent to windowSecondDisplay of
5278 // SECOND_DISPLAY_ID, the x and y coordinates are 200
Siarhei Vishniakoud3061ab2023-12-18 20:41:08 -08005279 EXPECT_EQ(100, event->getX(0));
5280 EXPECT_EQ(100, event->getY(0));
Hu Guo771a7692023-09-17 20:51:08 +08005281}
5282
5283/**
Prabir Pradhanc44ce4d2021-10-05 05:26:29 -07005284 * Ensure the correct coordinate spaces are used by InputDispatcher.
5285 *
5286 * InputDispatcher works in the display space, so its coordinate system is relative to the display
5287 * panel. Windows get events in the window space, and get raw coordinates in the logical display
5288 * space.
5289 */
5290class InputDispatcherDisplayProjectionTest : public InputDispatcherTest {
5291public:
5292 void SetUp() override {
5293 InputDispatcherTest::SetUp();
Prabir Pradhan33e3baa2022-12-06 20:30:22 +00005294 removeAllWindowsAndDisplays();
Prabir Pradhanc44ce4d2021-10-05 05:26:29 -07005295 }
5296
5297 void addDisplayInfo(int displayId, const ui::Transform& transform) {
5298 gui::DisplayInfo info;
5299 info.displayId = displayId;
5300 info.transform = transform;
5301 mDisplayInfos.push_back(std::move(info));
Patrick Williamsd828f302023-04-28 17:52:08 -05005302 mDispatcher->onWindowInfosChanged({mWindowInfos, mDisplayInfos, 0, 0});
Prabir Pradhanc44ce4d2021-10-05 05:26:29 -07005303 }
5304
5305 void addWindow(const sp<WindowInfoHandle>& windowHandle) {
5306 mWindowInfos.push_back(*windowHandle->getInfo());
Patrick Williamsd828f302023-04-28 17:52:08 -05005307 mDispatcher->onWindowInfosChanged({mWindowInfos, mDisplayInfos, 0, 0});
Prabir Pradhanc44ce4d2021-10-05 05:26:29 -07005308 }
5309
Prabir Pradhan33e3baa2022-12-06 20:30:22 +00005310 void removeAllWindowsAndDisplays() {
5311 mDisplayInfos.clear();
5312 mWindowInfos.clear();
5313 }
5314
Prabir Pradhanc44ce4d2021-10-05 05:26:29 -07005315 // Set up a test scenario where the display has a scaled projection and there are two windows
5316 // on the display.
5317 std::pair<sp<FakeWindowHandle>, sp<FakeWindowHandle>> setupScaledDisplayScenario() {
5318 // The display has a projection that has a scale factor of 2 and 4 in the x and y directions
5319 // respectively.
5320 ui::Transform displayTransform;
5321 displayTransform.set(2, 0, 0, 4);
5322 addDisplayInfo(ADISPLAY_ID_DEFAULT, displayTransform);
5323
5324 std::shared_ptr<FakeApplicationHandle> application =
5325 std::make_shared<FakeApplicationHandle>();
5326
5327 // Add two windows to the display. Their frames are represented in the display space.
5328 sp<FakeWindowHandle> firstWindow =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07005329 sp<FakeWindowHandle>::make(application, mDispatcher, "First Window",
5330 ADISPLAY_ID_DEFAULT);
Prabir Pradhanc44ce4d2021-10-05 05:26:29 -07005331 firstWindow->setFrame(Rect(0, 0, 100, 200), displayTransform);
5332 addWindow(firstWindow);
5333
5334 sp<FakeWindowHandle> secondWindow =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07005335 sp<FakeWindowHandle>::make(application, mDispatcher, "Second Window",
5336 ADISPLAY_ID_DEFAULT);
Prabir Pradhanc44ce4d2021-10-05 05:26:29 -07005337 secondWindow->setFrame(Rect(100, 200, 200, 400), displayTransform);
5338 addWindow(secondWindow);
5339 return {std::move(firstWindow), std::move(secondWindow)};
5340 }
5341
5342private:
5343 std::vector<gui::DisplayInfo> mDisplayInfos;
5344 std::vector<gui::WindowInfo> mWindowInfos;
5345};
5346
Prabir Pradhan33e3baa2022-12-06 20:30:22 +00005347TEST_F(InputDispatcherDisplayProjectionTest, HitTestCoordinateSpaceConsistency) {
Prabir Pradhanc44ce4d2021-10-05 05:26:29 -07005348 auto [firstWindow, secondWindow] = setupScaledDisplayScenario();
5349 // Send down to the first window. The point is represented in the display space. The point is
Prabir Pradhan33e3baa2022-12-06 20:30:22 +00005350 // selected so that if the hit test was performed with the point and the bounds being in
5351 // different coordinate spaces, the event would end up in the incorrect window.
Prabir Pradhan678438e2023-04-13 19:32:51 +00005352 mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_DOWN,
5353 AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
5354 {PointF{75, 55}}));
Prabir Pradhanc44ce4d2021-10-05 05:26:29 -07005355
5356 firstWindow->consumeMotionDown();
5357 secondWindow->assertNoEvents();
5358}
5359
5360// Ensure that when a MotionEvent is injected through the InputDispatcher::injectInputEvent() API,
5361// the event should be treated as being in the logical display space.
5362TEST_F(InputDispatcherDisplayProjectionTest, InjectionInLogicalDisplaySpace) {
5363 auto [firstWindow, secondWindow] = setupScaledDisplayScenario();
5364 // Send down to the first window. The point is represented in the logical display space. The
5365 // point is selected so that if the hit test was done in logical display space, then it would
5366 // end up in the incorrect window.
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07005367 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
Prabir Pradhanc44ce4d2021-10-05 05:26:29 -07005368 PointF{75 * 2, 55 * 4});
5369
5370 firstWindow->consumeMotionDown();
5371 secondWindow->assertNoEvents();
5372}
5373
Prabir Pradhandaa2f142021-12-10 09:30:08 +00005374// Ensure that when a MotionEvent that has a custom transform is injected, the post-transformed
5375// event should be treated as being in the logical display space.
5376TEST_F(InputDispatcherDisplayProjectionTest, InjectionWithTransformInLogicalDisplaySpace) {
5377 auto [firstWindow, secondWindow] = setupScaledDisplayScenario();
5378
5379 const std::array<float, 9> matrix = {1.1, 2.2, 3.3, 4.4, 5.5, 6.6, 0.0, 0.0, 1.0};
5380 ui::Transform injectedEventTransform;
5381 injectedEventTransform.set(matrix);
5382 const vec2 expectedPoint{75, 55}; // The injected point in the logical display space.
5383 const vec2 untransformedPoint = injectedEventTransform.inverse().transform(expectedPoint);
5384
5385 MotionEvent event = MotionEventBuilder(AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
5386 .displayId(ADISPLAY_ID_DEFAULT)
5387 .eventTime(systemTime(SYSTEM_TIME_MONOTONIC))
Siarhei Vishniakou6d73f832022-07-21 17:27:03 -07005388 .pointer(PointerBuilder(/*id=*/0, ToolType::FINGER)
Prabir Pradhandaa2f142021-12-10 09:30:08 +00005389 .x(untransformedPoint.x)
5390 .y(untransformedPoint.y))
5391 .build();
5392 event.transform(matrix);
5393
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07005394 injectMotionEvent(*mDispatcher, event, INJECT_EVENT_TIMEOUT,
Prabir Pradhandaa2f142021-12-10 09:30:08 +00005395 InputEventInjectionSync::WAIT_FOR_RESULT);
5396
5397 firstWindow->consumeMotionDown();
5398 secondWindow->assertNoEvents();
5399}
5400
Prabir Pradhanc44ce4d2021-10-05 05:26:29 -07005401TEST_F(InputDispatcherDisplayProjectionTest, WindowGetsEventsInCorrectCoordinateSpace) {
5402 auto [firstWindow, secondWindow] = setupScaledDisplayScenario();
5403
5404 // Send down to the second window.
Prabir Pradhan678438e2023-04-13 19:32:51 +00005405 mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_DOWN,
5406 AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
5407 {PointF{150, 220}}));
Prabir Pradhanc44ce4d2021-10-05 05:26:29 -07005408
5409 firstWindow->assertNoEvents();
Siarhei Vishniakoud3061ab2023-12-18 20:41:08 -08005410 std::unique_ptr<MotionEvent> event = secondWindow->consumeMotionEvent();
5411 ASSERT_NE(nullptr, event);
5412 EXPECT_EQ(AMOTION_EVENT_ACTION_DOWN, event->getAction());
Prabir Pradhanc44ce4d2021-10-05 05:26:29 -07005413
5414 // Ensure that the events from the "getRaw" API are in logical display coordinates.
Siarhei Vishniakoud3061ab2023-12-18 20:41:08 -08005415 EXPECT_EQ(300, event->getRawX(0));
5416 EXPECT_EQ(880, event->getRawY(0));
Prabir Pradhanc44ce4d2021-10-05 05:26:29 -07005417
5418 // Ensure that the x and y values are in the window's coordinate space.
5419 // The left-top of the second window is at (100, 200) in display space, which is (200, 800) in
5420 // the logical display space. This will be the origin of the window space.
Siarhei Vishniakoud3061ab2023-12-18 20:41:08 -08005421 EXPECT_EQ(100, event->getX(0));
5422 EXPECT_EQ(80, event->getY(0));
Prabir Pradhanc44ce4d2021-10-05 05:26:29 -07005423}
5424
Prabir Pradhan112b1ad2023-09-21 09:53:53 +00005425TEST_F(InputDispatcherDisplayProjectionTest, CancelMotionWithCorrectCoordinates) {
5426 auto [firstWindow, secondWindow] = setupScaledDisplayScenario();
5427 // The monitor will always receive events in the logical display's coordinate space, because
5428 // it does not have a window.
Prabir Pradhanfb549072023-10-05 19:17:36 +00005429 FakeMonitorReceiver monitor{*mDispatcher, "Monitor", ADISPLAY_ID_DEFAULT};
Prabir Pradhan112b1ad2023-09-21 09:53:53 +00005430
5431 // Send down to the first window.
5432 mDispatcher->notifyMotion(generateMotionArgs(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN,
5433 ADISPLAY_ID_DEFAULT, {PointF{50, 100}}));
5434 firstWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithCoords(100, 400)));
5435 monitor.consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithCoords(100, 400)));
5436
5437 // Second pointer goes down on second window.
5438 mDispatcher->notifyMotion(generateMotionArgs(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN,
5439 ADISPLAY_ID_DEFAULT,
5440 {PointF{50, 100}, PointF{150, 220}}));
5441 secondWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithCoords(100, 80)));
5442 const std::map<int32_t, PointF> expectedMonitorPointers{{0, PointF{100, 400}},
5443 {1, PointF{300, 880}}};
5444 monitor.consumeMotionEvent(
5445 AllOf(WithMotionAction(POINTER_1_DOWN), WithPointers(expectedMonitorPointers)));
5446
5447 mDispatcher->cancelCurrentTouch();
5448
5449 firstWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_CANCEL), WithCoords(100, 400)));
5450 secondWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_CANCEL), WithCoords(100, 80)));
5451 monitor.consumeMotionEvent(
5452 AllOf(WithMotionAction(ACTION_CANCEL), WithPointers(expectedMonitorPointers)));
5453}
5454
Prabir Pradhan1c29a092023-09-21 10:29:29 +00005455TEST_F(InputDispatcherDisplayProjectionTest, SynthesizeDownWithCorrectCoordinates) {
5456 auto [firstWindow, secondWindow] = setupScaledDisplayScenario();
5457
5458 // Send down to the first window.
5459 mDispatcher->notifyMotion(generateMotionArgs(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN,
5460 ADISPLAY_ID_DEFAULT, {PointF{50, 100}}));
5461 firstWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithCoords(100, 400)));
5462
5463 // The pointer is transferred to the second window, and the second window receives it in the
5464 // correct coordinate space.
Prabir Pradhan367f3432024-02-13 23:05:58 +00005465 mDispatcher->transferTouchGesture(firstWindow->getToken(), secondWindow->getToken());
Prabir Pradhan1c29a092023-09-21 10:29:29 +00005466 firstWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_CANCEL), WithCoords(100, 400)));
5467 secondWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithCoords(-100, -400)));
5468}
5469
Prabir Pradhan0dfcac72023-10-05 20:04:21 +00005470TEST_F(InputDispatcherDisplayProjectionTest, SynthesizeHoverEnterExitWithCorrectCoordinates) {
5471 auto [firstWindow, secondWindow] = setupScaledDisplayScenario();
5472
5473 // Send hover move to the second window, and ensure it shows up as hover enter.
5474 mDispatcher->notifyMotion(generateMotionArgs(ACTION_HOVER_MOVE, AINPUT_SOURCE_STYLUS,
5475 ADISPLAY_ID_DEFAULT, {PointF{150, 220}}));
5476 secondWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_HOVER_ENTER),
5477 WithCoords(100, 80), WithRawCoords(300, 880)));
5478
5479 // Touch down at the same location and ensure a hover exit is synthesized.
5480 mDispatcher->notifyMotion(generateMotionArgs(ACTION_DOWN, AINPUT_SOURCE_STYLUS,
5481 ADISPLAY_ID_DEFAULT, {PointF{150, 220}}));
5482 secondWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_HOVER_EXIT), WithCoords(100, 80),
5483 WithRawCoords(300, 880)));
5484 secondWindow->consumeMotionEvent(
5485 AllOf(WithMotionAction(ACTION_DOWN), WithCoords(100, 80), WithRawCoords(300, 880)));
5486 secondWindow->assertNoEvents();
5487 firstWindow->assertNoEvents();
5488}
5489
Prabir Pradhan453ae732023-10-13 14:30:14 +00005490// Same as above, but while the window is being mirrored.
5491TEST_F(InputDispatcherDisplayProjectionTest,
5492 SynthesizeHoverEnterExitWithCorrectCoordinatesWhenMirrored) {
5493 auto [firstWindow, secondWindow] = setupScaledDisplayScenario();
5494
5495 const std::array<float, 9> matrix = {1.1, 2.2, 3.3, 4.4, 5.5, 6.6, 0.0, 0.0, 1.0};
5496 ui::Transform secondDisplayTransform;
5497 secondDisplayTransform.set(matrix);
5498 addDisplayInfo(SECOND_DISPLAY_ID, secondDisplayTransform);
5499
5500 sp<FakeWindowHandle> secondWindowClone = secondWindow->clone(SECOND_DISPLAY_ID);
5501 secondWindowClone->setWindowTransform(1.1, 2.2, 3.3, 4.4);
5502 addWindow(secondWindowClone);
5503
5504 // Send hover move to the second window, and ensure it shows up as hover enter.
5505 mDispatcher->notifyMotion(generateMotionArgs(ACTION_HOVER_MOVE, AINPUT_SOURCE_STYLUS,
5506 ADISPLAY_ID_DEFAULT, {PointF{150, 220}}));
5507 secondWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_HOVER_ENTER),
5508 WithCoords(100, 80), WithRawCoords(300, 880)));
5509
5510 // Touch down at the same location and ensure a hover exit is synthesized for the correct
5511 // display.
5512 mDispatcher->notifyMotion(generateMotionArgs(ACTION_DOWN, AINPUT_SOURCE_STYLUS,
5513 ADISPLAY_ID_DEFAULT, {PointF{150, 220}}));
5514 secondWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_HOVER_EXIT), WithCoords(100, 80),
5515 WithRawCoords(300, 880)));
5516 secondWindow->consumeMotionEvent(
5517 AllOf(WithMotionAction(ACTION_DOWN), WithCoords(100, 80), WithRawCoords(300, 880)));
5518 secondWindow->assertNoEvents();
5519 firstWindow->assertNoEvents();
5520}
5521
Prabir Pradhan0dfcac72023-10-05 20:04:21 +00005522TEST_F(InputDispatcherDisplayProjectionTest, SynthesizeHoverCancelationWithCorrectCoordinates) {
5523 auto [firstWindow, secondWindow] = setupScaledDisplayScenario();
5524
5525 // Send hover enter to second window
5526 mDispatcher->notifyMotion(generateMotionArgs(ACTION_HOVER_ENTER, AINPUT_SOURCE_STYLUS,
5527 ADISPLAY_ID_DEFAULT, {PointF{150, 220}}));
5528 secondWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_HOVER_ENTER),
5529 WithCoords(100, 80), WithRawCoords(300, 880)));
5530
5531 mDispatcher->cancelCurrentTouch();
5532
5533 secondWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_HOVER_EXIT), WithCoords(100, 80),
5534 WithRawCoords(300, 880)));
5535 secondWindow->assertNoEvents();
5536 firstWindow->assertNoEvents();
5537}
5538
Prabir Pradhan453ae732023-10-13 14:30:14 +00005539// Same as above, but while the window is being mirrored.
Prabir Pradhan16463382023-10-12 23:03:19 +00005540TEST_F(InputDispatcherDisplayProjectionTest,
5541 SynthesizeHoverCancelationWithCorrectCoordinatesWhenMirrored) {
5542 auto [firstWindow, secondWindow] = setupScaledDisplayScenario();
5543
5544 const std::array<float, 9> matrix = {1.1, 2.2, 3.3, 4.4, 5.5, 6.6, 0.0, 0.0, 1.0};
5545 ui::Transform secondDisplayTransform;
5546 secondDisplayTransform.set(matrix);
5547 addDisplayInfo(SECOND_DISPLAY_ID, secondDisplayTransform);
5548
5549 sp<FakeWindowHandle> secondWindowClone = secondWindow->clone(SECOND_DISPLAY_ID);
5550 secondWindowClone->setWindowTransform(1.1, 2.2, 3.3, 4.4);
5551 addWindow(secondWindowClone);
5552
5553 // Send hover enter to second window
5554 mDispatcher->notifyMotion(generateMotionArgs(ACTION_HOVER_ENTER, AINPUT_SOURCE_STYLUS,
5555 ADISPLAY_ID_DEFAULT, {PointF{150, 220}}));
5556 secondWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_HOVER_ENTER),
5557 WithCoords(100, 80), WithRawCoords(300, 880),
5558 WithDisplayId(ADISPLAY_ID_DEFAULT)));
5559
5560 mDispatcher->cancelCurrentTouch();
5561
5562 // Ensure the cancelation happens with the correct displayId and the correct coordinates.
5563 secondWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_HOVER_EXIT), WithCoords(100, 80),
5564 WithRawCoords(300, 880),
5565 WithDisplayId(ADISPLAY_ID_DEFAULT)));
5566 secondWindow->assertNoEvents();
5567 firstWindow->assertNoEvents();
5568}
5569
Prabir Pradhan33e3baa2022-12-06 20:30:22 +00005570/** Ensure consistent behavior of InputDispatcher in all orientations. */
5571class InputDispatcherDisplayOrientationFixture
5572 : public InputDispatcherDisplayProjectionTest,
5573 public ::testing::WithParamInterface<ui::Rotation> {};
5574
5575// This test verifies the touchable region of a window for all rotations of the display by tapping
5576// in different locations on the display, specifically points close to the four corners of a
5577// window.
5578TEST_P(InputDispatcherDisplayOrientationFixture, HitTestInDifferentOrientations) {
5579 constexpr static int32_t displayWidth = 400;
5580 constexpr static int32_t displayHeight = 800;
5581
5582 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
5583
5584 const auto rotation = GetParam();
5585
5586 // Set up the display with the specified rotation.
5587 const bool isRotated = rotation == ui::ROTATION_90 || rotation == ui::ROTATION_270;
5588 const int32_t logicalDisplayWidth = isRotated ? displayHeight : displayWidth;
5589 const int32_t logicalDisplayHeight = isRotated ? displayWidth : displayHeight;
5590 const ui::Transform displayTransform(ui::Transform::toRotationFlags(rotation),
5591 logicalDisplayWidth, logicalDisplayHeight);
5592 addDisplayInfo(ADISPLAY_ID_DEFAULT, displayTransform);
5593
5594 // Create a window with its bounds determined in the logical display.
5595 const Rect frameInLogicalDisplay(100, 100, 200, 300);
5596 const Rect frameInDisplay = displayTransform.inverse().transform(frameInLogicalDisplay);
5597 sp<FakeWindowHandle> window =
5598 sp<FakeWindowHandle>::make(application, mDispatcher, "Window", ADISPLAY_ID_DEFAULT);
5599 window->setFrame(frameInDisplay, displayTransform);
5600 addWindow(window);
5601
5602 // The following points in logical display space should be inside the window.
5603 static const std::array<vec2, 4> insidePoints{
5604 {{100, 100}, {199.99, 100}, {100, 299.99}, {199.99, 299.99}}};
5605 for (const auto pointInsideWindow : insidePoints) {
5606 const vec2 p = displayTransform.inverse().transform(pointInsideWindow);
5607 const PointF pointInDisplaySpace{p.x, p.y};
Prabir Pradhan678438e2023-04-13 19:32:51 +00005608 mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_DOWN,
5609 AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
5610 {pointInDisplaySpace}));
Prabir Pradhan33e3baa2022-12-06 20:30:22 +00005611 window->consumeMotionDown();
5612
Prabir Pradhan678438e2023-04-13 19:32:51 +00005613 mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_UP,
5614 AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
5615 {pointInDisplaySpace}));
Prabir Pradhan33e3baa2022-12-06 20:30:22 +00005616 window->consumeMotionUp();
5617 }
5618
5619 // The following points in logical display space should be outside the window.
5620 static const std::array<vec2, 5> outsidePoints{
5621 {{200, 100}, {100, 300}, {200, 300}, {100, 99.99}, {99.99, 100}}};
5622 for (const auto pointOutsideWindow : outsidePoints) {
5623 const vec2 p = displayTransform.inverse().transform(pointOutsideWindow);
5624 const PointF pointInDisplaySpace{p.x, p.y};
Prabir Pradhan678438e2023-04-13 19:32:51 +00005625 mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_DOWN,
5626 AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
5627 {pointInDisplaySpace}));
Prabir Pradhan33e3baa2022-12-06 20:30:22 +00005628
Prabir Pradhan678438e2023-04-13 19:32:51 +00005629 mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_UP,
5630 AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
5631 {pointInDisplaySpace}));
Prabir Pradhan33e3baa2022-12-06 20:30:22 +00005632 }
5633 window->assertNoEvents();
5634}
5635
Linnan Li5e5645e2024-03-05 14:43:05 +00005636// This test verifies the occlusion detection for all rotations of the display by tapping
5637// in different locations on the display, specifically points close to the four corners of a
5638// window.
5639TEST_P(InputDispatcherDisplayOrientationFixture, BlockUntrustClickInDifferentOrientations) {
5640 constexpr static int32_t displayWidth = 400;
5641 constexpr static int32_t displayHeight = 800;
5642
5643 std::shared_ptr<FakeApplicationHandle> untrustedWindowApplication =
5644 std::make_shared<FakeApplicationHandle>();
5645 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
5646
5647 const auto rotation = GetParam();
5648
5649 // Set up the display with the specified rotation.
5650 const bool isRotated = rotation == ui::ROTATION_90 || rotation == ui::ROTATION_270;
5651 const int32_t logicalDisplayWidth = isRotated ? displayHeight : displayWidth;
5652 const int32_t logicalDisplayHeight = isRotated ? displayWidth : displayHeight;
5653 const ui::Transform displayTransform(ui::Transform::toRotationFlags(rotation),
5654 logicalDisplayWidth, logicalDisplayHeight);
5655 addDisplayInfo(ADISPLAY_ID_DEFAULT, displayTransform);
5656
5657 // Create a window that not trusted.
5658 const Rect untrustedWindowFrameInLogicalDisplay(100, 100, 200, 300);
5659
5660 const Rect untrustedWindowFrameInDisplay =
5661 displayTransform.inverse().transform(untrustedWindowFrameInLogicalDisplay);
5662
5663 sp<FakeWindowHandle> untrustedWindow =
5664 sp<FakeWindowHandle>::make(untrustedWindowApplication, mDispatcher, "UntrustedWindow",
5665 ADISPLAY_ID_DEFAULT);
5666 untrustedWindow->setFrame(untrustedWindowFrameInDisplay, displayTransform);
5667 untrustedWindow->setTrustedOverlay(false);
5668 untrustedWindow->setTouchOcclusionMode(TouchOcclusionMode::BLOCK_UNTRUSTED);
5669 untrustedWindow->setTouchable(false);
5670 untrustedWindow->setAlpha(1.0f);
5671 untrustedWindow->setOwnerInfo(gui::Pid{1}, gui::Uid{101});
5672 addWindow(untrustedWindow);
5673
5674 // Create a simple app window below the untrusted window.
5675 const Rect simpleAppWindowFrameInLogicalDisplay(0, 0, 300, 600);
5676 const Rect simpleAppWindowFrameInDisplay =
5677 displayTransform.inverse().transform(simpleAppWindowFrameInLogicalDisplay);
5678
5679 sp<FakeWindowHandle> simpleAppWindow =
5680 sp<FakeWindowHandle>::make(application, mDispatcher, "SimpleAppWindow",
5681 ADISPLAY_ID_DEFAULT);
5682 simpleAppWindow->setFrame(simpleAppWindowFrameInDisplay, displayTransform);
5683 simpleAppWindow->setOwnerInfo(gui::Pid{2}, gui::Uid{202});
5684 addWindow(simpleAppWindow);
5685
5686 // The following points in logical display space should be inside the untrusted window, so
5687 // the simple window could not receive events that coordinate is these point.
5688 static const std::array<vec2, 4> untrustedPoints{
5689 {{100, 100}, {199.99, 100}, {100, 299.99}, {199.99, 299.99}}};
5690
5691 for (const auto untrustedPoint : untrustedPoints) {
5692 const vec2 p = displayTransform.inverse().transform(untrustedPoint);
5693 const PointF pointInDisplaySpace{p.x, p.y};
5694 mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_DOWN,
5695 AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
5696 {pointInDisplaySpace}));
5697 mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_UP,
5698 AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
5699 {pointInDisplaySpace}));
5700 }
5701 untrustedWindow->assertNoEvents();
5702 simpleAppWindow->assertNoEvents();
5703 // The following points in logical display space should be outside the untrusted window, so
5704 // the simple window should receive events that coordinate is these point.
5705 static const std::array<vec2, 5> trustedPoints{
5706 {{200, 100}, {100, 300}, {200, 300}, {100, 99.99}, {99.99, 100}}};
5707 for (const auto trustedPoint : trustedPoints) {
5708 const vec2 p = displayTransform.inverse().transform(trustedPoint);
5709 const PointF pointInDisplaySpace{p.x, p.y};
5710 mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_DOWN,
5711 AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
5712 {pointInDisplaySpace}));
5713 simpleAppWindow->consumeMotionDown(ADISPLAY_ID_DEFAULT,
5714 AMOTION_EVENT_FLAG_WINDOW_IS_PARTIALLY_OBSCURED);
5715 mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_UP,
5716 AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
5717 {pointInDisplaySpace}));
5718 simpleAppWindow->consumeMotionUp(ADISPLAY_ID_DEFAULT,
5719 AMOTION_EVENT_FLAG_WINDOW_IS_PARTIALLY_OBSCURED);
5720 }
5721 untrustedWindow->assertNoEvents();
5722}
5723
Prabir Pradhan33e3baa2022-12-06 20:30:22 +00005724// Run the precision tests for all rotations.
5725INSTANTIATE_TEST_SUITE_P(InputDispatcherDisplayOrientationTests,
5726 InputDispatcherDisplayOrientationFixture,
5727 ::testing::Values(ui::ROTATION_0, ui::ROTATION_90, ui::ROTATION_180,
5728 ui::ROTATION_270),
5729 [](const testing::TestParamInfo<ui::Rotation>& testParamInfo) {
5730 return ftl::enum_string(testParamInfo.param);
5731 });
5732
Siarhei Vishniakou18050092021-09-01 13:32:49 -07005733using TransferFunction = std::function<bool(const std::unique_ptr<InputDispatcher>& dispatcher,
5734 sp<IBinder>, sp<IBinder>)>;
Siarhei Vishniakoud0c6bc82021-03-13 03:14:52 +00005735
5736class TransferTouchFixture : public InputDispatcherTest,
5737 public ::testing::WithParamInterface<TransferFunction> {};
5738
5739TEST_P(TransferTouchFixture, TransferTouch_OnePointer) {
Chris Yea209fde2020-07-22 13:54:51 -07005740 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
Svet Ganov5d3bc372020-01-26 23:11:07 -08005741
5742 // Create a couple of windows
Siarhei Vishniakou870ecec2020-12-09 08:07:46 -10005743 sp<FakeWindowHandle> firstWindow =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07005744 sp<FakeWindowHandle>::make(application, mDispatcher, "First Window",
5745 ADISPLAY_ID_DEFAULT);
Arthur Hungc539dbb2022-12-08 07:45:36 +00005746 firstWindow->setDupTouchToWallpaper(true);
Siarhei Vishniakou870ecec2020-12-09 08:07:46 -10005747 sp<FakeWindowHandle> secondWindow =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07005748 sp<FakeWindowHandle>::make(application, mDispatcher, "Second Window",
5749 ADISPLAY_ID_DEFAULT);
Arthur Hungc539dbb2022-12-08 07:45:36 +00005750 sp<FakeWindowHandle> wallpaper =
5751 sp<FakeWindowHandle>::make(application, mDispatcher, "Wallpaper", ADISPLAY_ID_DEFAULT);
5752 wallpaper->setIsWallpaper(true);
Prabir Pradhan65455c72024-02-13 21:46:41 +00005753 // Add the windows to the dispatcher, and ensure the first window is focused
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07005754 mDispatcher->onWindowInfosChanged(
5755 {{*firstWindow->getInfo(), *secondWindow->getInfo(), *wallpaper->getInfo()}, {}, 0, 0});
Prabir Pradhan65455c72024-02-13 21:46:41 +00005756 setFocusedWindow(firstWindow);
5757 firstWindow->consumeFocusEvent(true);
Svet Ganov5d3bc372020-01-26 23:11:07 -08005758
5759 // Send down to the first window
Prabir Pradhan678438e2023-04-13 19:32:51 +00005760 mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_DOWN,
5761 AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT));
Arthur Hungc539dbb2022-12-08 07:45:36 +00005762
Svet Ganov5d3bc372020-01-26 23:11:07 -08005763 // Only the first window should get the down event
5764 firstWindow->consumeMotionDown();
5765 secondWindow->assertNoEvents();
Arthur Hungc539dbb2022-12-08 07:45:36 +00005766 wallpaper->consumeMotionDown(ADISPLAY_ID_DEFAULT, expectedWallpaperFlags);
Prabir Pradhan65455c72024-02-13 21:46:41 +00005767 // Dispatcher reports pointer down outside focus for the wallpaper
5768 mFakePolicy->assertOnPointerDownEquals(wallpaper->getToken());
Svet Ganov5d3bc372020-01-26 23:11:07 -08005769
Siarhei Vishniakoud0c6bc82021-03-13 03:14:52 +00005770 // Transfer touch to the second window
5771 TransferFunction f = GetParam();
5772 const bool success = f(mDispatcher, firstWindow->getToken(), secondWindow->getToken());
5773 ASSERT_TRUE(success);
Svet Ganov5d3bc372020-01-26 23:11:07 -08005774 // The first window gets cancel and the second gets down
5775 firstWindow->consumeMotionCancel();
Prabir Pradhan65455c72024-02-13 21:46:41 +00005776 secondWindow->consumeMotionDown(ADISPLAY_ID_DEFAULT, AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
Arthur Hungc539dbb2022-12-08 07:45:36 +00005777 wallpaper->consumeMotionCancel(ADISPLAY_ID_DEFAULT, expectedWallpaperFlags);
Prabir Pradhan65455c72024-02-13 21:46:41 +00005778 // There should not be any changes to the focused window when transferring touch
5779 ASSERT_NO_FATAL_FAILURE(mFakePolicy->assertOnPointerDownWasNotCalled());
Svet Ganov5d3bc372020-01-26 23:11:07 -08005780
5781 // Send up event to the second window
Prabir Pradhan678438e2023-04-13 19:32:51 +00005782 mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN,
5783 ADISPLAY_ID_DEFAULT));
Prabir Pradhan65455c72024-02-13 21:46:41 +00005784 // The first window gets no events and the second gets up
Svet Ganov5d3bc372020-01-26 23:11:07 -08005785 firstWindow->assertNoEvents();
Prabir Pradhan65455c72024-02-13 21:46:41 +00005786 secondWindow->consumeMotionUp(ADISPLAY_ID_DEFAULT, AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
Arthur Hungc539dbb2022-12-08 07:45:36 +00005787 wallpaper->assertNoEvents();
Svet Ganov5d3bc372020-01-26 23:11:07 -08005788}
5789
Siarhei Vishniakou7ae7afd2022-03-31 15:26:13 -07005790/**
Prabir Pradhan367f3432024-02-13 23:05:58 +00005791 * When 'transferTouchGesture' API is invoked, dispatcher needs to find the "best" window to take
5792 * touch from. When we have spy windows, there are several windows to choose from: either spy, or
5793 * the 'real' (non-spy) window. Always prefer the 'real' window because that's what would be most
Siarhei Vishniakou7ae7afd2022-03-31 15:26:13 -07005794 * natural to the user.
5795 * In this test, we are sending a pointer to both spy window and first window. We then try to
5796 * transfer touch to the second window. The dispatcher should identify the first window as the
5797 * one that should lose the gesture, and therefore the action should be to move the gesture from
5798 * the first window to the second.
Prabir Pradhan367f3432024-02-13 23:05:58 +00005799 * The main goal here is to test the behaviour of 'transferTouchGesture' API, but it's still valid
5800 * to test the other API, as well.
Siarhei Vishniakou7ae7afd2022-03-31 15:26:13 -07005801 */
5802TEST_P(TransferTouchFixture, TransferTouch_MultipleWindowsWithSpy) {
5803 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
5804
5805 // Create a couple of windows + a spy window
5806 sp<FakeWindowHandle> spyWindow =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07005807 sp<FakeWindowHandle>::make(application, mDispatcher, "Spy", ADISPLAY_ID_DEFAULT);
Siarhei Vishniakou7ae7afd2022-03-31 15:26:13 -07005808 spyWindow->setTrustedOverlay(true);
5809 spyWindow->setSpy(true);
5810 sp<FakeWindowHandle> firstWindow =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07005811 sp<FakeWindowHandle>::make(application, mDispatcher, "First", ADISPLAY_ID_DEFAULT);
Siarhei Vishniakou7ae7afd2022-03-31 15:26:13 -07005812 sp<FakeWindowHandle> secondWindow =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07005813 sp<FakeWindowHandle>::make(application, mDispatcher, "Second", ADISPLAY_ID_DEFAULT);
Siarhei Vishniakou7ae7afd2022-03-31 15:26:13 -07005814
5815 // Add the windows to the dispatcher
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07005816 mDispatcher->onWindowInfosChanged(
5817 {{*spyWindow->getInfo(), *firstWindow->getInfo(), *secondWindow->getInfo()}, {}, 0, 0});
Siarhei Vishniakou7ae7afd2022-03-31 15:26:13 -07005818
5819 // Send down to the first window
Prabir Pradhan678438e2023-04-13 19:32:51 +00005820 mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_DOWN,
5821 AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT));
Siarhei Vishniakou7ae7afd2022-03-31 15:26:13 -07005822 // Only the first window and spy should get the down event
5823 spyWindow->consumeMotionDown();
5824 firstWindow->consumeMotionDown();
5825
5826 // Transfer touch to the second window. Non-spy window should be preferred over the spy window
Prabir Pradhan367f3432024-02-13 23:05:58 +00005827 // if f === 'transferTouchGesture'.
Siarhei Vishniakou7ae7afd2022-03-31 15:26:13 -07005828 TransferFunction f = GetParam();
5829 const bool success = f(mDispatcher, firstWindow->getToken(), secondWindow->getToken());
5830 ASSERT_TRUE(success);
5831 // The first window gets cancel and the second gets down
5832 firstWindow->consumeMotionCancel();
Prabir Pradhan65455c72024-02-13 21:46:41 +00005833 secondWindow->consumeMotionDown(ADISPLAY_ID_DEFAULT, AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
Siarhei Vishniakou7ae7afd2022-03-31 15:26:13 -07005834
5835 // Send up event to the second window
Prabir Pradhan678438e2023-04-13 19:32:51 +00005836 mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN,
5837 ADISPLAY_ID_DEFAULT));
Siarhei Vishniakou7ae7afd2022-03-31 15:26:13 -07005838 // The first window gets no events and the second+spy get up
5839 firstWindow->assertNoEvents();
5840 spyWindow->consumeMotionUp();
Prabir Pradhan65455c72024-02-13 21:46:41 +00005841 secondWindow->consumeMotionUp(ADISPLAY_ID_DEFAULT, AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
Siarhei Vishniakou7ae7afd2022-03-31 15:26:13 -07005842}
5843
Siarhei Vishniakoud0c6bc82021-03-13 03:14:52 +00005844TEST_P(TransferTouchFixture, TransferTouch_TwoPointersNonSplitTouch) {
Chris Yea209fde2020-07-22 13:54:51 -07005845 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
Svet Ganov5d3bc372020-01-26 23:11:07 -08005846
5847 PointF touchPoint = {10, 10};
5848
5849 // Create a couple of windows
Siarhei Vishniakou870ecec2020-12-09 08:07:46 -10005850 sp<FakeWindowHandle> firstWindow =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07005851 sp<FakeWindowHandle>::make(application, mDispatcher, "First Window",
5852 ADISPLAY_ID_DEFAULT);
Prabir Pradhan76bdecb2022-01-31 11:14:15 -08005853 firstWindow->setPreventSplitting(true);
Siarhei Vishniakou870ecec2020-12-09 08:07:46 -10005854 sp<FakeWindowHandle> secondWindow =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07005855 sp<FakeWindowHandle>::make(application, mDispatcher, "Second Window",
5856 ADISPLAY_ID_DEFAULT);
Prabir Pradhan76bdecb2022-01-31 11:14:15 -08005857 secondWindow->setPreventSplitting(true);
Svet Ganov5d3bc372020-01-26 23:11:07 -08005858
5859 // Add the windows to the dispatcher
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07005860 mDispatcher->onWindowInfosChanged(
5861 {{*firstWindow->getInfo(), *secondWindow->getInfo()}, {}, 0, 0});
Svet Ganov5d3bc372020-01-26 23:11:07 -08005862
5863 // Send down to the first window
Prabir Pradhan678438e2023-04-13 19:32:51 +00005864 mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_DOWN,
5865 AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
5866 {touchPoint}));
Svet Ganov5d3bc372020-01-26 23:11:07 -08005867 // Only the first window should get the down event
5868 firstWindow->consumeMotionDown();
5869 secondWindow->assertNoEvents();
5870
5871 // Send pointer down to the first window
Prabir Pradhan678438e2023-04-13 19:32:51 +00005872 mDispatcher->notifyMotion(generateMotionArgs(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN,
5873 ADISPLAY_ID_DEFAULT, {touchPoint, touchPoint}));
Svet Ganov5d3bc372020-01-26 23:11:07 -08005874 // Only the first window should get the pointer down event
5875 firstWindow->consumeMotionPointerDown(1);
5876 secondWindow->assertNoEvents();
5877
5878 // Transfer touch focus to the second window
Siarhei Vishniakoud0c6bc82021-03-13 03:14:52 +00005879 TransferFunction f = GetParam();
5880 bool success = f(mDispatcher, firstWindow->getToken(), secondWindow->getToken());
5881 ASSERT_TRUE(success);
Svet Ganov5d3bc372020-01-26 23:11:07 -08005882 // The first window gets cancel and the second gets down and pointer down
5883 firstWindow->consumeMotionCancel();
Prabir Pradhan65455c72024-02-13 21:46:41 +00005884 secondWindow->consumeMotionDown(ADISPLAY_ID_DEFAULT, AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
5885 secondWindow->consumeMotionPointerDown(1, ADISPLAY_ID_DEFAULT,
5886 AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
Svet Ganov5d3bc372020-01-26 23:11:07 -08005887
5888 // Send pointer up to the second window
Prabir Pradhan678438e2023-04-13 19:32:51 +00005889 mDispatcher->notifyMotion(generateMotionArgs(POINTER_1_UP, AINPUT_SOURCE_TOUCHSCREEN,
5890 ADISPLAY_ID_DEFAULT, {touchPoint, touchPoint}));
Svet Ganov5d3bc372020-01-26 23:11:07 -08005891 // The first window gets nothing and the second gets pointer up
5892 firstWindow->assertNoEvents();
Prabir Pradhan65455c72024-02-13 21:46:41 +00005893 secondWindow->consumeMotionPointerUp(1, ADISPLAY_ID_DEFAULT,
5894 AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
Svet Ganov5d3bc372020-01-26 23:11:07 -08005895
5896 // Send up event to the second window
Prabir Pradhan678438e2023-04-13 19:32:51 +00005897 mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN,
5898 ADISPLAY_ID_DEFAULT));
Svet Ganov5d3bc372020-01-26 23:11:07 -08005899 // The first window gets nothing and the second gets up
5900 firstWindow->assertNoEvents();
Prabir Pradhan65455c72024-02-13 21:46:41 +00005901 secondWindow->consumeMotionUp(ADISPLAY_ID_DEFAULT, AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
Svet Ganov5d3bc372020-01-26 23:11:07 -08005902}
5903
Arthur Hungc539dbb2022-12-08 07:45:36 +00005904TEST_P(TransferTouchFixture, TransferTouch_MultipleWallpapers) {
5905 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
5906
5907 // Create a couple of windows
5908 sp<FakeWindowHandle> firstWindow =
5909 sp<FakeWindowHandle>::make(application, mDispatcher, "First Window",
5910 ADISPLAY_ID_DEFAULT);
5911 firstWindow->setDupTouchToWallpaper(true);
5912 sp<FakeWindowHandle> secondWindow =
5913 sp<FakeWindowHandle>::make(application, mDispatcher, "Second Window",
5914 ADISPLAY_ID_DEFAULT);
5915 secondWindow->setDupTouchToWallpaper(true);
5916
5917 sp<FakeWindowHandle> wallpaper1 =
5918 sp<FakeWindowHandle>::make(application, mDispatcher, "Wallpaper1", ADISPLAY_ID_DEFAULT);
5919 wallpaper1->setIsWallpaper(true);
5920
5921 sp<FakeWindowHandle> wallpaper2 =
5922 sp<FakeWindowHandle>::make(application, mDispatcher, "Wallpaper2", ADISPLAY_ID_DEFAULT);
5923 wallpaper2->setIsWallpaper(true);
5924 // Add the windows to the dispatcher
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07005925 mDispatcher->onWindowInfosChanged({{*firstWindow->getInfo(), *wallpaper1->getInfo(),
5926 *secondWindow->getInfo(), *wallpaper2->getInfo()},
5927 {},
5928 0,
5929 0});
Arthur Hungc539dbb2022-12-08 07:45:36 +00005930
5931 // Send down to the first window
Prabir Pradhan678438e2023-04-13 19:32:51 +00005932 mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_DOWN,
5933 AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT));
Arthur Hungc539dbb2022-12-08 07:45:36 +00005934
5935 // Only the first window should get the down event
5936 firstWindow->consumeMotionDown();
5937 secondWindow->assertNoEvents();
5938 wallpaper1->consumeMotionDown(ADISPLAY_ID_DEFAULT, expectedWallpaperFlags);
5939 wallpaper2->assertNoEvents();
5940
5941 // Transfer touch focus to the second window
5942 TransferFunction f = GetParam();
5943 bool success = f(mDispatcher, firstWindow->getToken(), secondWindow->getToken());
5944 ASSERT_TRUE(success);
5945
5946 // The first window gets cancel and the second gets down
5947 firstWindow->consumeMotionCancel();
Prabir Pradhan65455c72024-02-13 21:46:41 +00005948 secondWindow->consumeMotionDown(ADISPLAY_ID_DEFAULT, AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
Arthur Hungc539dbb2022-12-08 07:45:36 +00005949 wallpaper1->consumeMotionCancel(ADISPLAY_ID_DEFAULT, expectedWallpaperFlags);
Prabir Pradhan65455c72024-02-13 21:46:41 +00005950 wallpaper2->consumeMotionDown(ADISPLAY_ID_DEFAULT,
5951 expectedWallpaperFlags | AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
Arthur Hungc539dbb2022-12-08 07:45:36 +00005952
5953 // Send up event to the second window
Prabir Pradhan678438e2023-04-13 19:32:51 +00005954 mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN,
5955 ADISPLAY_ID_DEFAULT));
Arthur Hungc539dbb2022-12-08 07:45:36 +00005956 // The first window gets no events and the second gets up
5957 firstWindow->assertNoEvents();
Prabir Pradhan65455c72024-02-13 21:46:41 +00005958 secondWindow->consumeMotionUp(ADISPLAY_ID_DEFAULT, AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
Arthur Hungc539dbb2022-12-08 07:45:36 +00005959 wallpaper1->assertNoEvents();
Prabir Pradhan65455c72024-02-13 21:46:41 +00005960 wallpaper2->consumeMotionUp(ADISPLAY_ID_DEFAULT,
5961 expectedWallpaperFlags | AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
Arthur Hungc539dbb2022-12-08 07:45:36 +00005962}
5963
Siarhei Vishniakoud0c6bc82021-03-13 03:14:52 +00005964// For the cases of single pointer touch and two pointers non-split touch, the api's
Prabir Pradhan367f3432024-02-13 23:05:58 +00005965// 'transferTouchGesture' and 'transferTouchOnDisplay' are equivalent in behaviour. They only differ
Siarhei Vishniakoud0c6bc82021-03-13 03:14:52 +00005966// for the case where there are multiple pointers split across several windows.
Prabir Pradhan367f3432024-02-13 23:05:58 +00005967INSTANTIATE_TEST_SUITE_P(
5968 InputDispatcherTransferFunctionTests, TransferTouchFixture,
5969 ::testing::Values(
5970 [&](const std::unique_ptr<InputDispatcher>& dispatcher, sp<IBinder> /*ignored*/,
5971 sp<IBinder> destChannelToken) {
5972 return dispatcher->transferTouchOnDisplay(destChannelToken,
5973 ADISPLAY_ID_DEFAULT);
5974 },
5975 [&](const std::unique_ptr<InputDispatcher>& dispatcher, sp<IBinder> from,
5976 sp<IBinder> to) {
5977 return dispatcher->transferTouchGesture(from, to,
5978 /*isDragAndDrop=*/false);
5979 }));
Siarhei Vishniakoud0c6bc82021-03-13 03:14:52 +00005980
Prabir Pradhan367f3432024-02-13 23:05:58 +00005981TEST_F(InputDispatcherTest, TransferTouch_TwoPointersSplitTouch) {
Chris Yea209fde2020-07-22 13:54:51 -07005982 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
Svet Ganov5d3bc372020-01-26 23:11:07 -08005983
Siarhei Vishniakou870ecec2020-12-09 08:07:46 -10005984 sp<FakeWindowHandle> firstWindow =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07005985 sp<FakeWindowHandle>::make(application, mDispatcher, "First Window",
5986 ADISPLAY_ID_DEFAULT);
Svet Ganov5d3bc372020-01-26 23:11:07 -08005987 firstWindow->setFrame(Rect(0, 0, 600, 400));
Svet Ganov5d3bc372020-01-26 23:11:07 -08005988
Siarhei Vishniakou870ecec2020-12-09 08:07:46 -10005989 sp<FakeWindowHandle> secondWindow =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07005990 sp<FakeWindowHandle>::make(application, mDispatcher, "Second Window",
5991 ADISPLAY_ID_DEFAULT);
Svet Ganov5d3bc372020-01-26 23:11:07 -08005992 secondWindow->setFrame(Rect(0, 400, 600, 800));
Svet Ganov5d3bc372020-01-26 23:11:07 -08005993
5994 // Add the windows to the dispatcher
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07005995 mDispatcher->onWindowInfosChanged(
5996 {{*firstWindow->getInfo(), *secondWindow->getInfo()}, {}, 0, 0});
Svet Ganov5d3bc372020-01-26 23:11:07 -08005997
5998 PointF pointInFirst = {300, 200};
5999 PointF pointInSecond = {300, 600};
6000
6001 // Send down to the first window
Prabir Pradhan678438e2023-04-13 19:32:51 +00006002 mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_DOWN,
6003 AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
6004 {pointInFirst}));
Svet Ganov5d3bc372020-01-26 23:11:07 -08006005 // Only the first window should get the down event
6006 firstWindow->consumeMotionDown();
6007 secondWindow->assertNoEvents();
6008
6009 // Send down to the second window
Prabir Pradhan678438e2023-04-13 19:32:51 +00006010 mDispatcher->notifyMotion(generateMotionArgs(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN,
6011 ADISPLAY_ID_DEFAULT,
6012 {pointInFirst, pointInSecond}));
Svet Ganov5d3bc372020-01-26 23:11:07 -08006013 // The first window gets a move and the second a down
6014 firstWindow->consumeMotionMove();
6015 secondWindow->consumeMotionDown();
6016
Prabir Pradhan367f3432024-02-13 23:05:58 +00006017 // Transfer touch to the second window
6018 mDispatcher->transferTouchGesture(firstWindow->getToken(), secondWindow->getToken());
Svet Ganov5d3bc372020-01-26 23:11:07 -08006019 // The first window gets cancel and the new gets pointer down (it already saw down)
6020 firstWindow->consumeMotionCancel();
Prabir Pradhan65455c72024-02-13 21:46:41 +00006021 secondWindow->consumeMotionPointerDown(1, ADISPLAY_ID_DEFAULT,
6022 AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
Svet Ganov5d3bc372020-01-26 23:11:07 -08006023
6024 // Send pointer up to the second window
Prabir Pradhan678438e2023-04-13 19:32:51 +00006025 mDispatcher->notifyMotion(generateMotionArgs(POINTER_1_UP, AINPUT_SOURCE_TOUCHSCREEN,
6026 ADISPLAY_ID_DEFAULT,
6027 {pointInFirst, pointInSecond}));
Svet Ganov5d3bc372020-01-26 23:11:07 -08006028 // The first window gets nothing and the second gets pointer up
6029 firstWindow->assertNoEvents();
Prabir Pradhan65455c72024-02-13 21:46:41 +00006030 secondWindow->consumeMotionPointerUp(1, ADISPLAY_ID_DEFAULT,
6031 AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
Svet Ganov5d3bc372020-01-26 23:11:07 -08006032
6033 // Send up event to the second window
Prabir Pradhan678438e2023-04-13 19:32:51 +00006034 mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN,
6035 ADISPLAY_ID_DEFAULT));
Svet Ganov5d3bc372020-01-26 23:11:07 -08006036 // The first window gets nothing and the second gets up
6037 firstWindow->assertNoEvents();
Prabir Pradhan65455c72024-02-13 21:46:41 +00006038 secondWindow->consumeMotionUp(ADISPLAY_ID_DEFAULT, AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
Svet Ganov5d3bc372020-01-26 23:11:07 -08006039}
6040
Prabir Pradhan367f3432024-02-13 23:05:58 +00006041// Same as TransferTouch_TwoPointersSplitTouch, but using 'transferTouchOnDisplay' api.
6042// Unlike 'transferTouchGesture', calling 'transferTouchOnDisplay' when there are two windows
6043// receiving touch is not supported, so the touch should continue on those windows and the
6044// transferred-to window should get nothing.
6045TEST_F(InputDispatcherTest, TransferTouchOnDisplay_TwoPointersSplitTouch) {
Siarhei Vishniakoud0c6bc82021-03-13 03:14:52 +00006046 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
6047
Siarhei Vishniakoud0c6bc82021-03-13 03:14:52 +00006048 sp<FakeWindowHandle> firstWindow =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07006049 sp<FakeWindowHandle>::make(application, mDispatcher, "First Window",
6050 ADISPLAY_ID_DEFAULT);
Siarhei Vishniakoud0c6bc82021-03-13 03:14:52 +00006051 firstWindow->setFrame(Rect(0, 0, 600, 400));
Siarhei Vishniakoud0c6bc82021-03-13 03:14:52 +00006052
Siarhei Vishniakoud0c6bc82021-03-13 03:14:52 +00006053 sp<FakeWindowHandle> secondWindow =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07006054 sp<FakeWindowHandle>::make(application, mDispatcher, "Second Window",
6055 ADISPLAY_ID_DEFAULT);
Siarhei Vishniakoud0c6bc82021-03-13 03:14:52 +00006056 secondWindow->setFrame(Rect(0, 400, 600, 800));
Siarhei Vishniakoud0c6bc82021-03-13 03:14:52 +00006057
6058 // Add the windows to the dispatcher
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07006059 mDispatcher->onWindowInfosChanged(
6060 {{*firstWindow->getInfo(), *secondWindow->getInfo()}, {}, 0, 0});
Siarhei Vishniakoud0c6bc82021-03-13 03:14:52 +00006061
6062 PointF pointInFirst = {300, 200};
6063 PointF pointInSecond = {300, 600};
6064
6065 // Send down to the first window
Prabir Pradhan678438e2023-04-13 19:32:51 +00006066 mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_DOWN,
6067 AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
6068 {pointInFirst}));
Siarhei Vishniakoud0c6bc82021-03-13 03:14:52 +00006069 // Only the first window should get the down event
6070 firstWindow->consumeMotionDown();
6071 secondWindow->assertNoEvents();
6072
6073 // Send down to the second window
Prabir Pradhan678438e2023-04-13 19:32:51 +00006074 mDispatcher->notifyMotion(generateMotionArgs(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN,
6075 ADISPLAY_ID_DEFAULT,
6076 {pointInFirst, pointInSecond}));
Siarhei Vishniakoud0c6bc82021-03-13 03:14:52 +00006077 // The first window gets a move and the second a down
6078 firstWindow->consumeMotionMove();
6079 secondWindow->consumeMotionDown();
6080
6081 // Transfer touch focus to the second window
Siarhei Vishniakou7ae7afd2022-03-31 15:26:13 -07006082 const bool transferred =
Prabir Pradhan367f3432024-02-13 23:05:58 +00006083 mDispatcher->transferTouchOnDisplay(secondWindow->getToken(), ADISPLAY_ID_DEFAULT);
6084 // The 'transferTouchOnDisplay' call should not succeed, because there are 2 touched windows
Siarhei Vishniakoud0c6bc82021-03-13 03:14:52 +00006085 ASSERT_FALSE(transferred);
6086 firstWindow->assertNoEvents();
6087 secondWindow->assertNoEvents();
6088
6089 // The rest of the dispatch should proceed as normal
6090 // Send pointer up to the second window
Prabir Pradhan678438e2023-04-13 19:32:51 +00006091 mDispatcher->notifyMotion(generateMotionArgs(POINTER_1_UP, AINPUT_SOURCE_TOUCHSCREEN,
6092 ADISPLAY_ID_DEFAULT,
6093 {pointInFirst, pointInSecond}));
Siarhei Vishniakoud0c6bc82021-03-13 03:14:52 +00006094 // The first window gets MOVE and the second gets pointer up
6095 firstWindow->consumeMotionMove();
6096 secondWindow->consumeMotionUp();
6097
6098 // Send up event to the first window
Prabir Pradhan678438e2023-04-13 19:32:51 +00006099 mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN,
6100 ADISPLAY_ID_DEFAULT));
Siarhei Vishniakoud0c6bc82021-03-13 03:14:52 +00006101 // The first window gets nothing and the second gets up
6102 firstWindow->consumeMotionUp();
6103 secondWindow->assertNoEvents();
6104}
6105
Arthur Hungabbb9d82021-09-01 14:52:30 +00006106// This case will create two windows and one mirrored window on the default display and mirror
Prabir Pradhan367f3432024-02-13 23:05:58 +00006107// two windows on the second display. It will test if 'transferTouchGesture' works fine if we put
Arthur Hungabbb9d82021-09-01 14:52:30 +00006108// the windows info of second display before default display.
Prabir Pradhan367f3432024-02-13 23:05:58 +00006109TEST_F(InputDispatcherTest, TransferTouch_CloneSurface) {
Arthur Hungabbb9d82021-09-01 14:52:30 +00006110 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
6111 sp<FakeWindowHandle> firstWindowInPrimary =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07006112 sp<FakeWindowHandle>::make(application, mDispatcher, "D_1_W1", ADISPLAY_ID_DEFAULT);
Arthur Hungabbb9d82021-09-01 14:52:30 +00006113 firstWindowInPrimary->setFrame(Rect(0, 0, 100, 100));
Arthur Hungabbb9d82021-09-01 14:52:30 +00006114 sp<FakeWindowHandle> secondWindowInPrimary =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07006115 sp<FakeWindowHandle>::make(application, mDispatcher, "D_1_W2", ADISPLAY_ID_DEFAULT);
Arthur Hungabbb9d82021-09-01 14:52:30 +00006116 secondWindowInPrimary->setFrame(Rect(100, 0, 200, 100));
Arthur Hungabbb9d82021-09-01 14:52:30 +00006117
Siarhei Vishniakouadb9fc92023-05-26 10:46:09 -07006118 sp<FakeWindowHandle> mirrorWindowInPrimary = firstWindowInPrimary->clone(ADISPLAY_ID_DEFAULT);
Arthur Hungabbb9d82021-09-01 14:52:30 +00006119 mirrorWindowInPrimary->setFrame(Rect(0, 100, 100, 200));
Arthur Hungabbb9d82021-09-01 14:52:30 +00006120
Siarhei Vishniakouadb9fc92023-05-26 10:46:09 -07006121 sp<FakeWindowHandle> firstWindowInSecondary = firstWindowInPrimary->clone(SECOND_DISPLAY_ID);
Arthur Hungabbb9d82021-09-01 14:52:30 +00006122 firstWindowInSecondary->setFrame(Rect(0, 0, 100, 100));
Arthur Hungabbb9d82021-09-01 14:52:30 +00006123
Siarhei Vishniakouadb9fc92023-05-26 10:46:09 -07006124 sp<FakeWindowHandle> secondWindowInSecondary = secondWindowInPrimary->clone(SECOND_DISPLAY_ID);
Arthur Hungabbb9d82021-09-01 14:52:30 +00006125 secondWindowInPrimary->setFrame(Rect(100, 0, 200, 100));
Arthur Hungabbb9d82021-09-01 14:52:30 +00006126
6127 // Update window info, let it find window handle of second display first.
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07006128 mDispatcher->onWindowInfosChanged(
6129 {{*firstWindowInSecondary->getInfo(), *secondWindowInSecondary->getInfo(),
6130 *mirrorWindowInPrimary->getInfo(), *firstWindowInPrimary->getInfo(),
6131 *secondWindowInPrimary->getInfo()},
6132 {},
6133 0,
6134 0});
Arthur Hungabbb9d82021-09-01 14:52:30 +00006135
6136 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07006137 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
Arthur Hungabbb9d82021-09-01 14:52:30 +00006138 {50, 50}))
6139 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
6140
6141 // Window should receive motion event.
6142 firstWindowInPrimary->consumeMotionDown(ADISPLAY_ID_DEFAULT);
6143
Prabir Pradhan367f3432024-02-13 23:05:58 +00006144 // Transfer touch
6145 ASSERT_TRUE(mDispatcher->transferTouchGesture(firstWindowInPrimary->getToken(),
6146 secondWindowInPrimary->getToken()));
Arthur Hungabbb9d82021-09-01 14:52:30 +00006147 // The first window gets cancel.
6148 firstWindowInPrimary->consumeMotionCancel();
Prabir Pradhan65455c72024-02-13 21:46:41 +00006149 secondWindowInPrimary->consumeMotionDown(ADISPLAY_ID_DEFAULT,
6150 AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
Arthur Hungabbb9d82021-09-01 14:52:30 +00006151
6152 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07006153 injectMotionEvent(*mDispatcher, AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN,
Arthur Hungabbb9d82021-09-01 14:52:30 +00006154 ADISPLAY_ID_DEFAULT, {150, 50}))
6155 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
6156 firstWindowInPrimary->assertNoEvents();
Prabir Pradhan65455c72024-02-13 21:46:41 +00006157 secondWindowInPrimary->consumeMotionMove(ADISPLAY_ID_DEFAULT,
6158 AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
Arthur Hungabbb9d82021-09-01 14:52:30 +00006159
6160 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07006161 injectMotionUp(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
Arthur Hungabbb9d82021-09-01 14:52:30 +00006162 {150, 50}))
6163 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
6164 firstWindowInPrimary->assertNoEvents();
Prabir Pradhan65455c72024-02-13 21:46:41 +00006165 secondWindowInPrimary->consumeMotionUp(ADISPLAY_ID_DEFAULT, AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
Arthur Hungabbb9d82021-09-01 14:52:30 +00006166}
6167
Prabir Pradhan367f3432024-02-13 23:05:58 +00006168// Same as TransferTouch_CloneSurface, but this touch on the secondary display and use
6169// 'transferTouchOnDisplay' api.
6170TEST_F(InputDispatcherTest, TransferTouchOnDisplay_CloneSurface) {
Arthur Hungabbb9d82021-09-01 14:52:30 +00006171 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
6172 sp<FakeWindowHandle> firstWindowInPrimary =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07006173 sp<FakeWindowHandle>::make(application, mDispatcher, "D_1_W1", ADISPLAY_ID_DEFAULT);
Arthur Hungabbb9d82021-09-01 14:52:30 +00006174 firstWindowInPrimary->setFrame(Rect(0, 0, 100, 100));
Arthur Hungabbb9d82021-09-01 14:52:30 +00006175 sp<FakeWindowHandle> secondWindowInPrimary =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07006176 sp<FakeWindowHandle>::make(application, mDispatcher, "D_1_W2", ADISPLAY_ID_DEFAULT);
Arthur Hungabbb9d82021-09-01 14:52:30 +00006177 secondWindowInPrimary->setFrame(Rect(100, 0, 200, 100));
Arthur Hungabbb9d82021-09-01 14:52:30 +00006178
Siarhei Vishniakouadb9fc92023-05-26 10:46:09 -07006179 sp<FakeWindowHandle> mirrorWindowInPrimary = firstWindowInPrimary->clone(ADISPLAY_ID_DEFAULT);
Arthur Hungabbb9d82021-09-01 14:52:30 +00006180 mirrorWindowInPrimary->setFrame(Rect(0, 100, 100, 200));
Arthur Hungabbb9d82021-09-01 14:52:30 +00006181
Siarhei Vishniakouadb9fc92023-05-26 10:46:09 -07006182 sp<FakeWindowHandle> firstWindowInSecondary = firstWindowInPrimary->clone(SECOND_DISPLAY_ID);
Arthur Hungabbb9d82021-09-01 14:52:30 +00006183 firstWindowInSecondary->setFrame(Rect(0, 0, 100, 100));
Arthur Hungabbb9d82021-09-01 14:52:30 +00006184
Siarhei Vishniakouadb9fc92023-05-26 10:46:09 -07006185 sp<FakeWindowHandle> secondWindowInSecondary = secondWindowInPrimary->clone(SECOND_DISPLAY_ID);
Arthur Hungabbb9d82021-09-01 14:52:30 +00006186 secondWindowInPrimary->setFrame(Rect(100, 0, 200, 100));
Arthur Hungabbb9d82021-09-01 14:52:30 +00006187
6188 // Update window info, let it find window handle of second display first.
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07006189 mDispatcher->onWindowInfosChanged(
6190 {{*firstWindowInSecondary->getInfo(), *secondWindowInSecondary->getInfo(),
6191 *mirrorWindowInPrimary->getInfo(), *firstWindowInPrimary->getInfo(),
6192 *secondWindowInPrimary->getInfo()},
6193 {},
6194 0,
6195 0});
Arthur Hungabbb9d82021-09-01 14:52:30 +00006196
6197 // Touch on second display.
6198 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07006199 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, SECOND_DISPLAY_ID,
6200 {50, 50}))
Arthur Hungabbb9d82021-09-01 14:52:30 +00006201 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
6202
6203 // Window should receive motion event.
Prabir Pradhanbb3f1c02024-01-04 20:17:14 +00006204 firstWindowInSecondary->consumeMotionDown(SECOND_DISPLAY_ID);
Arthur Hungabbb9d82021-09-01 14:52:30 +00006205
6206 // Transfer touch focus
Prabir Pradhan367f3432024-02-13 23:05:58 +00006207 ASSERT_TRUE(mDispatcher->transferTouchOnDisplay(secondWindowInSecondary->getToken(),
6208 SECOND_DISPLAY_ID));
Arthur Hungabbb9d82021-09-01 14:52:30 +00006209
6210 // The first window gets cancel.
Prabir Pradhanbb3f1c02024-01-04 20:17:14 +00006211 firstWindowInSecondary->consumeMotionCancel(SECOND_DISPLAY_ID);
Prabir Pradhan65455c72024-02-13 21:46:41 +00006212 secondWindowInSecondary->consumeMotionDown(SECOND_DISPLAY_ID,
6213 AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
Arthur Hungabbb9d82021-09-01 14:52:30 +00006214
6215 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07006216 injectMotionEvent(*mDispatcher, AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN,
Arthur Hungabbb9d82021-09-01 14:52:30 +00006217 SECOND_DISPLAY_ID, {150, 50}))
6218 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
Prabir Pradhanbb3f1c02024-01-04 20:17:14 +00006219 firstWindowInSecondary->assertNoEvents();
Prabir Pradhan65455c72024-02-13 21:46:41 +00006220 secondWindowInSecondary->consumeMotionMove(SECOND_DISPLAY_ID,
6221 AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
Arthur Hungabbb9d82021-09-01 14:52:30 +00006222
6223 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07006224 injectMotionUp(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, SECOND_DISPLAY_ID, {150, 50}))
Arthur Hungabbb9d82021-09-01 14:52:30 +00006225 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
Prabir Pradhanbb3f1c02024-01-04 20:17:14 +00006226 firstWindowInSecondary->assertNoEvents();
Prabir Pradhan65455c72024-02-13 21:46:41 +00006227 secondWindowInSecondary->consumeMotionUp(SECOND_DISPLAY_ID, AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
Arthur Hungabbb9d82021-09-01 14:52:30 +00006228}
6229
Siarhei Vishniakouf1035d42019-09-20 16:32:01 +01006230TEST_F(InputDispatcherTest, FocusedWindow_ReceivesFocusEventAndKeyEvent) {
Chris Yea209fde2020-07-22 13:54:51 -07006231 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07006232 sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher,
6233 "Fake Window", ADISPLAY_ID_DEFAULT);
Siarhei Vishniakouf1035d42019-09-20 16:32:01 +01006234
Vishnu Nair47074b82020-08-14 11:54:47 -07006235 window->setFocusable(true);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07006236 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Vishnu Nair958da932020-08-21 17:12:37 -07006237 setFocusedWindow(window);
Siarhei Vishniakouf1035d42019-09-20 16:32:01 +01006238
6239 window->consumeFocusEvent(true);
6240
Prabir Pradhan678438e2023-04-13 19:32:51 +00006241 mDispatcher->notifyKey(generateKeyArgs(AKEY_EVENT_ACTION_DOWN, ADISPLAY_ID_DEFAULT));
Siarhei Vishniakouf1035d42019-09-20 16:32:01 +01006242
6243 // Window should receive key down event.
6244 window->consumeKeyDown(ADISPLAY_ID_DEFAULT);
Josep del Riob3981622023-04-18 15:49:45 +00006245
6246 // Should have poked user activity
Siarhei Vishniakou4fd86732023-05-24 17:33:01 +00006247 mDispatcher->waitForIdle();
Josep del Riob3981622023-04-18 15:49:45 +00006248 mFakePolicy->assertUserActivityPoked();
6249}
6250
6251TEST_F(InputDispatcherTest, FocusedWindow_DisableUserActivity) {
6252 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
6253 sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher,
6254 "Fake Window", ADISPLAY_ID_DEFAULT);
6255
6256 window->setDisableUserActivity(true);
6257 window->setFocusable(true);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07006258 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Josep del Riob3981622023-04-18 15:49:45 +00006259 setFocusedWindow(window);
6260
6261 window->consumeFocusEvent(true);
6262
6263 mDispatcher->notifyKey(generateKeyArgs(AKEY_EVENT_ACTION_DOWN, ADISPLAY_ID_DEFAULT));
6264
6265 // Window should receive key down event.
6266 window->consumeKeyDown(ADISPLAY_ID_DEFAULT);
6267
6268 // Should have poked user activity
Siarhei Vishniakou4fd86732023-05-24 17:33:01 +00006269 mDispatcher->waitForIdle();
Josep del Riob3981622023-04-18 15:49:45 +00006270 mFakePolicy->assertUserActivityNotPoked();
6271}
6272
6273TEST_F(InputDispatcherTest, FocusedWindow_DoesNotReceiveSystemShortcut) {
6274 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
6275 sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher,
6276 "Fake Window", ADISPLAY_ID_DEFAULT);
6277
6278 window->setFocusable(true);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07006279 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Josep del Riob3981622023-04-18 15:49:45 +00006280 setFocusedWindow(window);
6281
6282 window->consumeFocusEvent(true);
6283
6284 mDispatcher->notifyKey(generateSystemShortcutArgs(AKEY_EVENT_ACTION_DOWN, ADISPLAY_ID_DEFAULT));
6285 mDispatcher->waitForIdle();
6286
6287 // System key is not passed down
6288 window->assertNoEvents();
6289
6290 // Should have poked user activity
6291 mFakePolicy->assertUserActivityPoked();
6292}
6293
6294TEST_F(InputDispatcherTest, FocusedWindow_DoesNotReceiveAssistantKey) {
6295 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
6296 sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher,
6297 "Fake Window", ADISPLAY_ID_DEFAULT);
6298
6299 window->setFocusable(true);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07006300 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Josep del Riob3981622023-04-18 15:49:45 +00006301 setFocusedWindow(window);
6302
6303 window->consumeFocusEvent(true);
6304
6305 mDispatcher->notifyKey(generateAssistantKeyArgs(AKEY_EVENT_ACTION_DOWN, ADISPLAY_ID_DEFAULT));
6306 mDispatcher->waitForIdle();
6307
6308 // System key is not passed down
6309 window->assertNoEvents();
6310
6311 // Should have poked user activity
6312 mFakePolicy->assertUserActivityPoked();
6313}
6314
6315TEST_F(InputDispatcherTest, FocusedWindow_SystemKeyIgnoresDisableUserActivity) {
6316 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
6317 sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher,
6318 "Fake Window", ADISPLAY_ID_DEFAULT);
6319
6320 window->setDisableUserActivity(true);
6321 window->setFocusable(true);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07006322 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Josep del Riob3981622023-04-18 15:49:45 +00006323 setFocusedWindow(window);
6324
6325 window->consumeFocusEvent(true);
6326
6327 mDispatcher->notifyKey(generateSystemShortcutArgs(AKEY_EVENT_ACTION_DOWN, ADISPLAY_ID_DEFAULT));
6328 mDispatcher->waitForIdle();
6329
6330 // System key is not passed down
6331 window->assertNoEvents();
6332
6333 // Should have poked user activity
6334 mFakePolicy->assertUserActivityPoked();
Siarhei Vishniakouf1035d42019-09-20 16:32:01 +01006335}
6336
Siarhei Vishniakou90ee4782023-05-08 11:57:24 -07006337TEST_F(InputDispatcherTest, InjectedTouchesPokeUserActivity) {
6338 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
6339 sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher,
6340 "Fake Window", ADISPLAY_ID_DEFAULT);
6341
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07006342 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Siarhei Vishniakou90ee4782023-05-08 11:57:24 -07006343
6344 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07006345 injectMotionEvent(*mDispatcher, AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN,
Siarhei Vishniakou90ee4782023-05-08 11:57:24 -07006346 ADISPLAY_ID_DEFAULT, {100, 100}))
6347 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
6348
6349 window->consumeMotionEvent(
6350 AllOf(WithMotionAction(ACTION_DOWN), WithDisplayId(ADISPLAY_ID_DEFAULT)));
6351
6352 // Should have poked user activity
Siarhei Vishniakou4fd86732023-05-24 17:33:01 +00006353 mDispatcher->waitForIdle();
Siarhei Vishniakou90ee4782023-05-08 11:57:24 -07006354 mFakePolicy->assertUserActivityPoked();
6355}
6356
Siarhei Vishniakouf1035d42019-09-20 16:32:01 +01006357TEST_F(InputDispatcherTest, UnfocusedWindow_DoesNotReceiveFocusEventOrKeyEvent) {
Chris Yea209fde2020-07-22 13:54:51 -07006358 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07006359 sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher,
6360 "Fake Window", ADISPLAY_ID_DEFAULT);
Siarhei Vishniakouf1035d42019-09-20 16:32:01 +01006361
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07006362 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Siarhei Vishniakouf1035d42019-09-20 16:32:01 +01006363
Prabir Pradhan678438e2023-04-13 19:32:51 +00006364 mDispatcher->notifyKey(generateKeyArgs(AKEY_EVENT_ACTION_DOWN, ADISPLAY_ID_DEFAULT));
Siarhei Vishniakouf1035d42019-09-20 16:32:01 +01006365 mDispatcher->waitForIdle();
6366
6367 window->assertNoEvents();
6368}
6369
6370// If a window is touchable, but does not have focus, it should receive motion events, but not keys
6371TEST_F(InputDispatcherTest, UnfocusedWindow_ReceivesMotionsButNotKeys) {
Chris Yea209fde2020-07-22 13:54:51 -07006372 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07006373 sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher,
6374 "Fake Window", ADISPLAY_ID_DEFAULT);
Siarhei Vishniakouf1035d42019-09-20 16:32:01 +01006375
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07006376 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Siarhei Vishniakouf1035d42019-09-20 16:32:01 +01006377
6378 // Send key
Prabir Pradhan678438e2023-04-13 19:32:51 +00006379 mDispatcher->notifyKey(generateKeyArgs(AKEY_EVENT_ACTION_DOWN, ADISPLAY_ID_DEFAULT));
Siarhei Vishniakouf1035d42019-09-20 16:32:01 +01006380 // Send motion
Prabir Pradhan678438e2023-04-13 19:32:51 +00006381 mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_DOWN,
6382 AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT));
Siarhei Vishniakouf1035d42019-09-20 16:32:01 +01006383
6384 // Window should receive only the motion event
6385 window->consumeMotionDown(ADISPLAY_ID_DEFAULT);
6386 window->assertNoEvents(); // Key event or focus event will not be received
6387}
6388
arthurhungea3f4fc2020-12-21 23:18:53 +08006389TEST_F(InputDispatcherTest, PointerCancel_SendCancelWhenSplitTouch) {
6390 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
6391
arthurhungea3f4fc2020-12-21 23:18:53 +08006392 sp<FakeWindowHandle> firstWindow =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07006393 sp<FakeWindowHandle>::make(application, mDispatcher, "First Window",
6394 ADISPLAY_ID_DEFAULT);
arthurhungea3f4fc2020-12-21 23:18:53 +08006395 firstWindow->setFrame(Rect(0, 0, 600, 400));
arthurhungea3f4fc2020-12-21 23:18:53 +08006396
arthurhungea3f4fc2020-12-21 23:18:53 +08006397 sp<FakeWindowHandle> secondWindow =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07006398 sp<FakeWindowHandle>::make(application, mDispatcher, "Second Window",
6399 ADISPLAY_ID_DEFAULT);
arthurhungea3f4fc2020-12-21 23:18:53 +08006400 secondWindow->setFrame(Rect(0, 400, 600, 800));
arthurhungea3f4fc2020-12-21 23:18:53 +08006401
6402 // Add the windows to the dispatcher
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07006403 mDispatcher->onWindowInfosChanged(
6404 {{*firstWindow->getInfo(), *secondWindow->getInfo()}, {}, 0, 0});
arthurhungea3f4fc2020-12-21 23:18:53 +08006405
6406 PointF pointInFirst = {300, 200};
6407 PointF pointInSecond = {300, 600};
6408
6409 // Send down to the first window
Prabir Pradhan678438e2023-04-13 19:32:51 +00006410 mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_DOWN,
6411 AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
6412 {pointInFirst}));
arthurhungea3f4fc2020-12-21 23:18:53 +08006413 // Only the first window should get the down event
6414 firstWindow->consumeMotionDown();
6415 secondWindow->assertNoEvents();
6416
6417 // Send down to the second window
Prabir Pradhan678438e2023-04-13 19:32:51 +00006418 mDispatcher->notifyMotion(generateMotionArgs(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN,
6419 ADISPLAY_ID_DEFAULT,
6420 {pointInFirst, pointInSecond}));
arthurhungea3f4fc2020-12-21 23:18:53 +08006421 // The first window gets a move and the second a down
6422 firstWindow->consumeMotionMove();
6423 secondWindow->consumeMotionDown();
6424
6425 // Send pointer cancel to the second window
6426 NotifyMotionArgs pointerUpMotionArgs =
Siarhei Vishniakoua16e3a22022-03-02 15:26:40 -08006427 generateMotionArgs(POINTER_1_UP, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
arthurhungea3f4fc2020-12-21 23:18:53 +08006428 {pointInFirst, pointInSecond});
6429 pointerUpMotionArgs.flags |= AMOTION_EVENT_FLAG_CANCELED;
Prabir Pradhan678438e2023-04-13 19:32:51 +00006430 mDispatcher->notifyMotion(pointerUpMotionArgs);
arthurhungea3f4fc2020-12-21 23:18:53 +08006431 // The first window gets move and the second gets cancel.
6432 firstWindow->consumeMotionMove(ADISPLAY_ID_DEFAULT, AMOTION_EVENT_FLAG_CANCELED);
6433 secondWindow->consumeMotionCancel(ADISPLAY_ID_DEFAULT, AMOTION_EVENT_FLAG_CANCELED);
6434
6435 // Send up event.
Prabir Pradhan678438e2023-04-13 19:32:51 +00006436 mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN,
6437 ADISPLAY_ID_DEFAULT));
arthurhungea3f4fc2020-12-21 23:18:53 +08006438 // The first window gets up and the second gets nothing.
6439 firstWindow->consumeMotionUp();
6440 secondWindow->assertNoEvents();
6441}
6442
Siarhei Vishniakouf94ae022021-02-04 01:23:17 +00006443TEST_F(InputDispatcherTest, SendTimeline_DoesNotCrashDispatcher) {
6444 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
6445
6446 sp<FakeWindowHandle> window =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07006447 sp<FakeWindowHandle>::make(application, mDispatcher, "Window", ADISPLAY_ID_DEFAULT);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07006448 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Siarhei Vishniakouf94ae022021-02-04 01:23:17 +00006449 std::array<nsecs_t, GraphicsTimeline::SIZE> graphicsTimeline;
6450 graphicsTimeline[GraphicsTimeline::GPU_COMPLETED_TIME] = 2;
6451 graphicsTimeline[GraphicsTimeline::PRESENT_TIME] = 3;
6452
Harry Cutts33476232023-01-30 19:57:29 +00006453 window->sendTimeline(/*inputEventId=*/1, graphicsTimeline);
Siarhei Vishniakouf94ae022021-02-04 01:23:17 +00006454 window->assertNoEvents();
6455 mDispatcher->waitForIdle();
6456}
6457
Prabir Pradhan1376fcd2022-01-21 09:56:35 -08006458using InputDispatcherMonitorTest = InputDispatcherTest;
6459
Siarhei Vishniakouca205502021-07-16 21:31:58 +00006460/**
6461 * Two entities that receive touch: A window, and a global monitor.
6462 * The touch goes to the window, and then the window disappears.
6463 * The monitor does not get cancel right away. But if more events come in, the touch gets canceled
6464 * for the monitor, as well.
6465 * 1. foregroundWindow
6466 * 2. monitor <-- global monitor (doesn't observe z order, receives all events)
6467 */
Prabir Pradhan1376fcd2022-01-21 09:56:35 -08006468TEST_F(InputDispatcherMonitorTest, MonitorTouchIsCanceledWhenForegroundWindowDisappears) {
Siarhei Vishniakouca205502021-07-16 21:31:58 +00006469 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
6470 sp<FakeWindowHandle> window =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07006471 sp<FakeWindowHandle>::make(application, mDispatcher, "Foreground", ADISPLAY_ID_DEFAULT);
Siarhei Vishniakouca205502021-07-16 21:31:58 +00006472
Prabir Pradhanfb549072023-10-05 19:17:36 +00006473 FakeMonitorReceiver monitor = FakeMonitorReceiver(*mDispatcher, "M_1", ADISPLAY_ID_DEFAULT);
Siarhei Vishniakouca205502021-07-16 21:31:58 +00006474
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07006475 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Siarhei Vishniakouca205502021-07-16 21:31:58 +00006476 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07006477 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
Siarhei Vishniakouca205502021-07-16 21:31:58 +00006478 {100, 200}))
6479 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
6480
6481 // Both the foreground window and the global monitor should receive the touch down
6482 window->consumeMotionDown();
6483 monitor.consumeMotionDown(ADISPLAY_ID_DEFAULT);
6484
6485 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07006486 injectMotionEvent(*mDispatcher, AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN,
Siarhei Vishniakouca205502021-07-16 21:31:58 +00006487 ADISPLAY_ID_DEFAULT, {110, 200}))
6488 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
6489
6490 window->consumeMotionMove();
6491 monitor.consumeMotionMove(ADISPLAY_ID_DEFAULT);
6492
6493 // Now the foreground window goes away
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07006494 mDispatcher->onWindowInfosChanged({{}, {}, 0, 0});
Siarhei Vishniakouca205502021-07-16 21:31:58 +00006495 window->consumeMotionCancel();
6496 monitor.assertNoEvents(); // Global monitor does not get a cancel yet
6497
6498 // If more events come in, there will be no more foreground window to send them to. This will
6499 // cause a cancel for the monitor, as well.
6500 ASSERT_EQ(InputEventInjectionResult::FAILED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07006501 injectMotionEvent(*mDispatcher, AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN,
Siarhei Vishniakouca205502021-07-16 21:31:58 +00006502 ADISPLAY_ID_DEFAULT, {120, 200}))
6503 << "Injection should fail because the window was removed";
6504 window->assertNoEvents();
6505 // Global monitor now gets the cancel
6506 monitor.consumeMotionCancel(ADISPLAY_ID_DEFAULT);
6507}
6508
Prabir Pradhan1376fcd2022-01-21 09:56:35 -08006509TEST_F(InputDispatcherMonitorTest, ReceivesMotionEvents) {
Chris Yea209fde2020-07-22 13:54:51 -07006510 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07006511 sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher,
6512 "Fake Window", ADISPLAY_ID_DEFAULT);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07006513 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Michael Wright3a240c42019-12-10 20:53:41 +00006514
Prabir Pradhanfb549072023-10-05 19:17:36 +00006515 FakeMonitorReceiver monitor = FakeMonitorReceiver(*mDispatcher, "M_1", ADISPLAY_ID_DEFAULT);
Michael Wright3a240c42019-12-10 20:53:41 +00006516
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08006517 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07006518 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT))
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08006519 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
Michael Wright3a240c42019-12-10 20:53:41 +00006520 window->consumeMotionDown(ADISPLAY_ID_DEFAULT);
chaviwd1c23182019-12-20 18:44:56 -08006521 monitor.consumeMotionDown(ADISPLAY_ID_DEFAULT);
Michael Wright3a240c42019-12-10 20:53:41 +00006522}
6523
Prabir Pradhan1376fcd2022-01-21 09:56:35 -08006524TEST_F(InputDispatcherMonitorTest, MonitorCannotPilferPointers) {
Prabir Pradhanfb549072023-10-05 19:17:36 +00006525 FakeMonitorReceiver monitor = FakeMonitorReceiver(*mDispatcher, "M_1", ADISPLAY_ID_DEFAULT);
Michael Wright3a240c42019-12-10 20:53:41 +00006526
Chris Yea209fde2020-07-22 13:54:51 -07006527 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07006528 sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher,
6529 "Fake Window", ADISPLAY_ID_DEFAULT);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07006530 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Michael Wright3a240c42019-12-10 20:53:41 +00006531
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08006532 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07006533 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT))
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08006534 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
chaviwd1c23182019-12-20 18:44:56 -08006535 monitor.consumeMotionDown(ADISPLAY_ID_DEFAULT);
Prabir Pradhan1376fcd2022-01-21 09:56:35 -08006536 window->consumeMotionDown(ADISPLAY_ID_DEFAULT);
Michael Wright3a240c42019-12-10 20:53:41 +00006537
Prabir Pradhan1376fcd2022-01-21 09:56:35 -08006538 // Pilfer pointers from the monitor.
6539 // This should not do anything and the window should continue to receive events.
6540 EXPECT_NE(OK, mDispatcher->pilferPointers(monitor.getToken()));
Michael Wright3a240c42019-12-10 20:53:41 +00006541
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08006542 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07006543 injectMotionEvent(*mDispatcher, AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN,
Prabir Pradhan1376fcd2022-01-21 09:56:35 -08006544 ADISPLAY_ID_DEFAULT))
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08006545 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
Prabir Pradhan1376fcd2022-01-21 09:56:35 -08006546
6547 monitor.consumeMotionMove(ADISPLAY_ID_DEFAULT);
6548 window->consumeMotionMove(ADISPLAY_ID_DEFAULT);
Michael Wright3a240c42019-12-10 20:53:41 +00006549}
6550
Prabir Pradhan1376fcd2022-01-21 09:56:35 -08006551TEST_F(InputDispatcherMonitorTest, NoWindowTransform) {
Evan Rosky84f07f02021-04-16 10:42:42 -07006552 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07006553 sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher,
6554 "Fake Window", ADISPLAY_ID_DEFAULT);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07006555 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Evan Rosky84f07f02021-04-16 10:42:42 -07006556 window->setWindowOffset(20, 40);
6557 window->setWindowTransform(0, 1, -1, 0);
6558
Prabir Pradhanfb549072023-10-05 19:17:36 +00006559 FakeMonitorReceiver monitor = FakeMonitorReceiver(*mDispatcher, "M_1", ADISPLAY_ID_DEFAULT);
Evan Rosky84f07f02021-04-16 10:42:42 -07006560
6561 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07006562 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT))
Evan Rosky84f07f02021-04-16 10:42:42 -07006563 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
6564 window->consumeMotionDown(ADISPLAY_ID_DEFAULT);
Siarhei Vishniakoud3061ab2023-12-18 20:41:08 -08006565 std::unique_ptr<MotionEvent> event = monitor.consumeMotion();
6566 ASSERT_NE(nullptr, event);
Evan Rosky84f07f02021-04-16 10:42:42 -07006567 // Even though window has transform, gesture monitor must not.
6568 ASSERT_EQ(ui::Transform(), event->getTransform());
6569}
6570
Prabir Pradhan1376fcd2022-01-21 09:56:35 -08006571TEST_F(InputDispatcherMonitorTest, InjectionFailsWithNoWindow) {
Arthur Hungb3307ee2021-10-14 10:57:37 +00006572 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
Prabir Pradhanfb549072023-10-05 19:17:36 +00006573 FakeMonitorReceiver monitor = FakeMonitorReceiver(*mDispatcher, "M_1", ADISPLAY_ID_DEFAULT);
Arthur Hungb3307ee2021-10-14 10:57:37 +00006574
Prabir Pradhan1376fcd2022-01-21 09:56:35 -08006575 ASSERT_EQ(InputEventInjectionResult::FAILED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07006576 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT))
Prabir Pradhan1376fcd2022-01-21 09:56:35 -08006577 << "Injection should fail if there is a monitor, but no touchable window";
6578 monitor.assertNoEvents();
Arthur Hungb3307ee2021-10-14 10:57:37 +00006579}
6580
Linnan Lid8150952024-01-26 18:07:17 +00006581/**
6582 * Two displays
6583 * The first monitor has a foreground window, a monitor
6584 * The second window has only one monitor.
6585 * We first inject a Down event into the first display, this injection should succeed and both
6586 * the foreground window and monitor should receive a down event, then inject a Down event into
6587 * the second display as well, this injection should fail, at this point, the first display
6588 * window and monitor should not receive a cancel or any other event.
6589 * Continue to inject Move and UP events to the first display, the events should be received
6590 * normally by the foreground window and monitor.
6591 */
6592TEST_F(InputDispatcherMonitorTest, MonitorTouchIsNotCanceledWhenAnotherEmptyDisplayReceiveEvents) {
6593 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
6594 sp<FakeWindowHandle> window =
6595 sp<FakeWindowHandle>::make(application, mDispatcher, "Foreground", ADISPLAY_ID_DEFAULT);
6596
6597 FakeMonitorReceiver monitor = FakeMonitorReceiver(*mDispatcher, "M_1", ADISPLAY_ID_DEFAULT);
6598 FakeMonitorReceiver secondMonitor = FakeMonitorReceiver(*mDispatcher, "M_2", SECOND_DISPLAY_ID);
6599
6600 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
6601 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
6602 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
6603 {100, 200}))
6604 << "The down event injected into the first display should succeed";
6605
6606 window->consumeMotionDown();
6607 monitor.consumeMotionDown(ADISPLAY_ID_DEFAULT);
Linnan Lid8150952024-01-26 18:07:17 +00006608
6609 ASSERT_EQ(InputEventInjectionResult::FAILED,
6610 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, SECOND_DISPLAY_ID,
6611 {100, 200}))
Prabir Pradhana0d43d42024-01-30 00:27:08 +00006612 << "The down event injected into the second display should fail since there's no "
6613 "touchable window";
Linnan Lid8150952024-01-26 18:07:17 +00006614
6615 // Continue to inject event to first display.
6616 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
6617 injectMotionEvent(*mDispatcher, AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN,
6618 ADISPLAY_ID_DEFAULT, {110, 220}))
6619 << "The move event injected into the first display should succeed";
6620
6621 window->consumeMotionMove();
6622 monitor.consumeMotionMove(ADISPLAY_ID_DEFAULT);
Linnan Lid8150952024-01-26 18:07:17 +00006623
6624 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
6625 injectMotionUp(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
6626 {110, 220}))
6627 << "The up event injected into the first display should succeed";
6628
6629 window->consumeMotionUp();
6630 monitor.consumeMotionUp(ADISPLAY_ID_DEFAULT);
Prabir Pradhana0d43d42024-01-30 00:27:08 +00006631
6632 window->assertNoEvents();
6633 monitor.assertNoEvents();
Linnan Lid8150952024-01-26 18:07:17 +00006634 secondMonitor.assertNoEvents();
6635}
6636
6637/**
6638 * Two displays
6639 * There is a monitor and foreground window on each display.
6640 * First, we inject down events into each of the two displays, at this point, the foreground windows
6641 * and monitors on both displays should receive down events.
6642 * At this point, the foreground window of the second display goes away, the gone window should
6643 * receive the cancel event, and the other windows and monitors should not receive any events.
6644 * Inject a move event into the second display. At this point, the injection should fail because
6645 * the second display no longer has a foreground window. At this point, the monitor on the second
6646 * display should receive a cancel event, and any windows or monitors on the first display should
6647 * not receive any events, and any subsequent injection of events into the second display should
6648 * also fail.
6649 * Continue to inject events into the first display, and the events should all be injected
6650 * successfully and received normally.
6651 */
6652TEST_F(InputDispatcherMonitorTest, MonitorTouchIsNotCancelWhenAnotherDisplayMonitorTouchCanceled) {
6653 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
6654 sp<FakeWindowHandle> window =
6655 sp<FakeWindowHandle>::make(application, mDispatcher, "Foreground", ADISPLAY_ID_DEFAULT);
6656 sp<FakeWindowHandle> secondWindow =
6657 sp<FakeWindowHandle>::make(application, mDispatcher, "SecondForeground",
6658 SECOND_DISPLAY_ID);
6659
6660 FakeMonitorReceiver monitor = FakeMonitorReceiver(*mDispatcher, "M_1", ADISPLAY_ID_DEFAULT);
6661 FakeMonitorReceiver secondMonitor = FakeMonitorReceiver(*mDispatcher, "M_2", SECOND_DISPLAY_ID);
6662
6663 // There is a foreground window on both displays.
6664 mDispatcher->onWindowInfosChanged({{*window->getInfo(), *secondWindow->getInfo()}, {}, 0, 0});
6665 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
6666 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
6667 {100, 200}))
6668 << "The down event injected into the first display should succeed";
6669
6670 window->consumeMotionDown(ADISPLAY_ID_DEFAULT);
6671 monitor.consumeMotionDown(ADISPLAY_ID_DEFAULT);
Linnan Lid8150952024-01-26 18:07:17 +00006672
6673 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
6674 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, SECOND_DISPLAY_ID,
6675 {100, 200}))
6676 << "The down event injected into the second display should succeed";
6677
Linnan Lid8150952024-01-26 18:07:17 +00006678 secondWindow->consumeMotionDown(SECOND_DISPLAY_ID);
6679 secondMonitor.consumeMotionDown(SECOND_DISPLAY_ID);
6680
6681 // Now second window is gone away.
6682 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
6683
6684 // The gone window should receive a cancel, and the monitor on the second display should not
6685 // receive any events.
Linnan Lid8150952024-01-26 18:07:17 +00006686 secondWindow->consumeMotionCancel(SECOND_DISPLAY_ID);
6687 secondMonitor.assertNoEvents();
6688
6689 ASSERT_EQ(InputEventInjectionResult::FAILED,
6690 injectMotionEvent(*mDispatcher, AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN,
6691 SECOND_DISPLAY_ID, {110, 220}))
Prabir Pradhana0d43d42024-01-30 00:27:08 +00006692 << "The move event injected into the second display should fail because there's no "
6693 "touchable window";
Linnan Lid8150952024-01-26 18:07:17 +00006694 // Now the monitor on the second display should receive a cancel event.
6695 secondMonitor.consumeMotionCancel(SECOND_DISPLAY_ID);
Linnan Lid8150952024-01-26 18:07:17 +00006696
6697 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
6698 injectMotionEvent(*mDispatcher, AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN,
6699 ADISPLAY_ID_DEFAULT, {110, 200}))
6700 << "The move event injected into the first display should succeed";
6701
6702 window->consumeMotionMove();
6703 monitor.consumeMotionMove(ADISPLAY_ID_DEFAULT);
Linnan Lid8150952024-01-26 18:07:17 +00006704
6705 ASSERT_EQ(InputEventInjectionResult::FAILED,
Prabir Pradhana0d43d42024-01-30 00:27:08 +00006706 injectMotionUp(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, SECOND_DISPLAY_ID,
6707 {110, 220}))
6708 << "The up event injected into the second display should fail because there's no "
6709 "touchable window";
Linnan Lid8150952024-01-26 18:07:17 +00006710
6711 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
6712 injectMotionUp(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
6713 {110, 220}))
6714 << "The up event injected into the first display should succeed";
6715
6716 window->consumeMotionUp(ADISPLAY_ID_DEFAULT);
6717 monitor.consumeMotionUp(ADISPLAY_ID_DEFAULT);
Prabir Pradhana0d43d42024-01-30 00:27:08 +00006718
Linnan Lid8150952024-01-26 18:07:17 +00006719 window->assertNoEvents();
6720 monitor.assertNoEvents();
Prabir Pradhana0d43d42024-01-30 00:27:08 +00006721 secondWindow->assertNoEvents();
6722 secondMonitor.assertNoEvents();
Linnan Lid8150952024-01-26 18:07:17 +00006723}
6724
6725/**
6726 * One display with transform
6727 * There is a foreground window and a monitor on the display
6728 * Inject down event and move event sequentially, the foreground window and monitor can receive down
6729 * event and move event, then let the foreground window go away, the foreground window receives
6730 * cancel event, inject move event again, the monitor receives cancel event, all the events received
6731 * by the monitor should be with the same transform as the display
6732 */
6733TEST_F(InputDispatcherMonitorTest, MonitorTouchCancelEventWithDisplayTransform) {
6734 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
6735 sp<FakeWindowHandle> window =
6736 sp<FakeWindowHandle>::make(application, mDispatcher, "Foreground", ADISPLAY_ID_DEFAULT);
6737 FakeMonitorReceiver monitor = FakeMonitorReceiver(*mDispatcher, "M_1", ADISPLAY_ID_DEFAULT);
6738
6739 ui::Transform transform;
6740 transform.set({1.1, 2.2, 3.3, 4.4, 5.5, 6.6, 0, 0, 1});
6741
6742 gui::DisplayInfo displayInfo;
6743 displayInfo.displayId = ADISPLAY_ID_DEFAULT;
6744 displayInfo.transform = transform;
6745
6746 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {displayInfo}, 0, 0});
6747
6748 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
6749 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
6750 {100, 200}))
6751 << "The down event injected should succeed";
6752
6753 window->consumeMotionDown();
6754 std::unique_ptr<MotionEvent> downMotionEvent = monitor.consumeMotion();
6755 EXPECT_EQ(transform, downMotionEvent->getTransform());
6756 EXPECT_EQ(AMOTION_EVENT_ACTION_DOWN, downMotionEvent->getAction());
6757
6758 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
6759 injectMotionEvent(*mDispatcher, AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN,
6760 ADISPLAY_ID_DEFAULT, {110, 220}))
6761 << "The move event injected should succeed";
6762
6763 window->consumeMotionMove();
6764 std::unique_ptr<MotionEvent> moveMotionEvent = monitor.consumeMotion();
6765 EXPECT_EQ(transform, moveMotionEvent->getTransform());
6766 EXPECT_EQ(AMOTION_EVENT_ACTION_MOVE, moveMotionEvent->getAction());
6767
6768 // Let foreground window gone
6769 mDispatcher->onWindowInfosChanged({{}, {displayInfo}, 0, 0});
6770
Prabir Pradhana0d43d42024-01-30 00:27:08 +00006771 // Foreground window should receive a cancel event, but not the monitor.
Linnan Lid8150952024-01-26 18:07:17 +00006772 window->consumeMotionCancel();
Linnan Lid8150952024-01-26 18:07:17 +00006773
6774 ASSERT_EQ(InputEventInjectionResult::FAILED,
6775 injectMotionEvent(*mDispatcher, AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN,
6776 ADISPLAY_ID_DEFAULT, {110, 220}))
6777 << "The move event injected should failed";
6778 // Now foreground should not receive any events, but monitor should receive a cancel event
6779 // with transform that same as display's display.
Linnan Lid8150952024-01-26 18:07:17 +00006780 std::unique_ptr<MotionEvent> cancelMotionEvent = monitor.consumeMotion();
6781 EXPECT_EQ(transform, cancelMotionEvent->getTransform());
6782 EXPECT_EQ(ADISPLAY_ID_DEFAULT, cancelMotionEvent->getDisplayId());
6783 EXPECT_EQ(AMOTION_EVENT_ACTION_CANCEL, cancelMotionEvent->getAction());
6784
6785 // Other event inject to this display should fail.
6786 ASSERT_EQ(InputEventInjectionResult::FAILED,
6787 injectMotionEvent(*mDispatcher, AMOTION_EVENT_ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN,
6788 ADISPLAY_ID_DEFAULT, {110, 220}))
Prabir Pradhana0d43d42024-01-30 00:27:08 +00006789 << "The up event injected should fail because the touched window was removed";
Linnan Lid8150952024-01-26 18:07:17 +00006790 window->assertNoEvents();
6791 monitor.assertNoEvents();
6792}
6793
chaviw81e2bb92019-12-18 15:03:51 -08006794TEST_F(InputDispatcherTest, TestMoveEvent) {
Chris Yea209fde2020-07-22 13:54:51 -07006795 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07006796 sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher,
6797 "Fake Window", ADISPLAY_ID_DEFAULT);
chaviw81e2bb92019-12-18 15:03:51 -08006798
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07006799 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
chaviw81e2bb92019-12-18 15:03:51 -08006800
6801 NotifyMotionArgs motionArgs =
6802 generateMotionArgs(AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN,
6803 ADISPLAY_ID_DEFAULT);
6804
Prabir Pradhan678438e2023-04-13 19:32:51 +00006805 mDispatcher->notifyMotion(motionArgs);
chaviw81e2bb92019-12-18 15:03:51 -08006806 // Window should receive motion down event.
6807 window->consumeMotionDown(ADISPLAY_ID_DEFAULT);
6808
6809 motionArgs.action = AMOTION_EVENT_ACTION_MOVE;
Garfield Tanc51d1ba2020-01-28 13:24:04 -08006810 motionArgs.id += 1;
chaviw81e2bb92019-12-18 15:03:51 -08006811 motionArgs.eventTime = systemTime(SYSTEM_TIME_MONOTONIC);
6812 motionArgs.pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_X,
6813 motionArgs.pointerCoords[0].getX() - 10);
6814
Prabir Pradhan678438e2023-04-13 19:32:51 +00006815 mDispatcher->notifyMotion(motionArgs);
Prabir Pradhan7662a8d2023-12-15 01:58:14 +00006816 window->consumeMotionMove(ADISPLAY_ID_DEFAULT, /*expectedFlags=*/0);
chaviw81e2bb92019-12-18 15:03:51 -08006817}
6818
Siarhei Vishniakouf1035d42019-09-20 16:32:01 +01006819/**
6820 * Dispatcher has touch mode enabled by default. Typically, the policy overrides that value to
6821 * the device default right away. In the test scenario, we check both the default value,
6822 * and the action of enabling / disabling.
6823 */
6824TEST_F(InputDispatcherTest, TouchModeState_IsSentToApps) {
Chris Yea209fde2020-07-22 13:54:51 -07006825 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07006826 sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher,
6827 "Test window", ADISPLAY_ID_DEFAULT);
Antonio Kantekea47acb2021-12-23 12:41:25 -08006828 const WindowInfo& windowInfo = *window->getInfo();
Siarhei Vishniakouf1035d42019-09-20 16:32:01 +01006829
6830 // Set focused application.
6831 mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application);
Vishnu Nair47074b82020-08-14 11:54:47 -07006832 window->setFocusable(true);
Siarhei Vishniakouf1035d42019-09-20 16:32:01 +01006833
6834 SCOPED_TRACE("Check default value of touch mode");
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07006835 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Vishnu Nair958da932020-08-21 17:12:37 -07006836 setFocusedWindow(window);
Harry Cutts33476232023-01-30 19:57:29 +00006837 window->consumeFocusEvent(/*hasFocus=*/true, /*inTouchMode=*/true);
Siarhei Vishniakouf1035d42019-09-20 16:32:01 +01006838
6839 SCOPED_TRACE("Remove the window to trigger focus loss");
Vishnu Nair47074b82020-08-14 11:54:47 -07006840 window->setFocusable(false);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07006841 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Harry Cutts33476232023-01-30 19:57:29 +00006842 window->consumeFocusEvent(/*hasFocus=*/false, /*inTouchMode=*/true);
Siarhei Vishniakouf1035d42019-09-20 16:32:01 +01006843
6844 SCOPED_TRACE("Disable touch mode");
Antonio Kantekea47acb2021-12-23 12:41:25 -08006845 mDispatcher->setInTouchMode(false, windowInfo.ownerPid, windowInfo.ownerUid,
Harry Cutts33476232023-01-30 19:57:29 +00006846 /*hasPermission=*/true, ADISPLAY_ID_DEFAULT);
Antonio Kantekf16f2832021-09-28 04:39:20 +00006847 window->consumeTouchModeEvent(false);
Vishnu Nair47074b82020-08-14 11:54:47 -07006848 window->setFocusable(true);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07006849 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Vishnu Nair958da932020-08-21 17:12:37 -07006850 setFocusedWindow(window);
Harry Cutts33476232023-01-30 19:57:29 +00006851 window->consumeFocusEvent(/*hasFocus=*/true, /*inTouchMode=*/false);
Siarhei Vishniakouf1035d42019-09-20 16:32:01 +01006852
6853 SCOPED_TRACE("Remove the window to trigger focus loss");
Vishnu Nair47074b82020-08-14 11:54:47 -07006854 window->setFocusable(false);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07006855 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Harry Cutts33476232023-01-30 19:57:29 +00006856 window->consumeFocusEvent(/*hasFocus=*/false, /*inTouchMode=*/false);
Siarhei Vishniakouf1035d42019-09-20 16:32:01 +01006857
6858 SCOPED_TRACE("Enable touch mode again");
Antonio Kantekea47acb2021-12-23 12:41:25 -08006859 mDispatcher->setInTouchMode(true, windowInfo.ownerPid, windowInfo.ownerUid,
Harry Cutts33476232023-01-30 19:57:29 +00006860 /*hasPermission=*/true, ADISPLAY_ID_DEFAULT);
Antonio Kantekf16f2832021-09-28 04:39:20 +00006861 window->consumeTouchModeEvent(true);
Vishnu Nair47074b82020-08-14 11:54:47 -07006862 window->setFocusable(true);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07006863 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Vishnu Nair958da932020-08-21 17:12:37 -07006864 setFocusedWindow(window);
Harry Cutts33476232023-01-30 19:57:29 +00006865 window->consumeFocusEvent(/*hasFocus=*/true, /*inTouchMode=*/true);
Siarhei Vishniakouf1035d42019-09-20 16:32:01 +01006866
6867 window->assertNoEvents();
6868}
6869
Gang Wange9087892020-01-07 12:17:14 -05006870TEST_F(InputDispatcherTest, VerifyInputEvent_KeyEvent) {
Chris Yea209fde2020-07-22 13:54:51 -07006871 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07006872 sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher,
6873 "Test window", ADISPLAY_ID_DEFAULT);
Gang Wange9087892020-01-07 12:17:14 -05006874
6875 mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application);
Vishnu Nair47074b82020-08-14 11:54:47 -07006876 window->setFocusable(true);
Gang Wange9087892020-01-07 12:17:14 -05006877
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07006878 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Vishnu Nair958da932020-08-21 17:12:37 -07006879 setFocusedWindow(window);
6880
Harry Cutts33476232023-01-30 19:57:29 +00006881 window->consumeFocusEvent(/*hasFocus=*/true, /*inTouchMode=*/true);
Gang Wange9087892020-01-07 12:17:14 -05006882
Prabir Pradhan678438e2023-04-13 19:32:51 +00006883 const NotifyKeyArgs keyArgs = generateKeyArgs(AKEY_EVENT_ACTION_DOWN);
6884 mDispatcher->notifyKey(keyArgs);
Gang Wange9087892020-01-07 12:17:14 -05006885
Siarhei Vishniakoud3061ab2023-12-18 20:41:08 -08006886 std::unique_ptr<KeyEvent> event = window->consumeKey();
6887 ASSERT_NE(event, nullptr);
6888 std::unique_ptr<VerifiedInputEvent> verified = mDispatcher->verifyInputEvent(*event);
Gang Wange9087892020-01-07 12:17:14 -05006889 ASSERT_NE(verified, nullptr);
6890 ASSERT_EQ(verified->type, VerifiedInputEvent::Type::KEY);
6891
6892 ASSERT_EQ(keyArgs.eventTime, verified->eventTimeNanos);
6893 ASSERT_EQ(keyArgs.deviceId, verified->deviceId);
6894 ASSERT_EQ(keyArgs.source, verified->source);
6895 ASSERT_EQ(keyArgs.displayId, verified->displayId);
6896
6897 const VerifiedKeyEvent& verifiedKey = static_cast<const VerifiedKeyEvent&>(*verified);
6898
6899 ASSERT_EQ(keyArgs.action, verifiedKey.action);
Gang Wange9087892020-01-07 12:17:14 -05006900 ASSERT_EQ(keyArgs.flags & VERIFIED_KEY_EVENT_FLAGS, verifiedKey.flags);
Siarhei Vishniakouf355bf92021-12-09 10:43:21 -08006901 ASSERT_EQ(keyArgs.downTime, verifiedKey.downTimeNanos);
Gang Wange9087892020-01-07 12:17:14 -05006902 ASSERT_EQ(keyArgs.keyCode, verifiedKey.keyCode);
6903 ASSERT_EQ(keyArgs.scanCode, verifiedKey.scanCode);
6904 ASSERT_EQ(keyArgs.metaState, verifiedKey.metaState);
6905 ASSERT_EQ(0, verifiedKey.repeatCount);
6906}
6907
Siarhei Vishniakou47040bf2020-02-28 15:03:13 -08006908TEST_F(InputDispatcherTest, VerifyInputEvent_MotionEvent) {
Chris Yea209fde2020-07-22 13:54:51 -07006909 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07006910 sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher,
6911 "Test window", ADISPLAY_ID_DEFAULT);
Siarhei Vishniakou47040bf2020-02-28 15:03:13 -08006912
6913 mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application);
6914
Prabir Pradhanb5cb9572021-09-24 06:35:16 -07006915 ui::Transform transform;
6916 transform.set({1.1, 2.2, 3.3, 4.4, 5.5, 6.6, 0, 0, 1});
6917
6918 gui::DisplayInfo displayInfo;
6919 displayInfo.displayId = ADISPLAY_ID_DEFAULT;
6920 displayInfo.transform = transform;
6921
Patrick Williamsd828f302023-04-28 17:52:08 -05006922 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {displayInfo}, 0, 0});
Siarhei Vishniakou47040bf2020-02-28 15:03:13 -08006923
Prabir Pradhan678438e2023-04-13 19:32:51 +00006924 const NotifyMotionArgs motionArgs =
Siarhei Vishniakou47040bf2020-02-28 15:03:13 -08006925 generateMotionArgs(AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN,
6926 ADISPLAY_ID_DEFAULT);
Prabir Pradhan678438e2023-04-13 19:32:51 +00006927 mDispatcher->notifyMotion(motionArgs);
Siarhei Vishniakou47040bf2020-02-28 15:03:13 -08006928
Siarhei Vishniakoud3061ab2023-12-18 20:41:08 -08006929 std::unique_ptr<MotionEvent> event = window->consumeMotionEvent();
6930 ASSERT_NE(nullptr, event);
6931 std::unique_ptr<VerifiedInputEvent> verified = mDispatcher->verifyInputEvent(*event);
Siarhei Vishniakou47040bf2020-02-28 15:03:13 -08006932 ASSERT_NE(verified, nullptr);
6933 ASSERT_EQ(verified->type, VerifiedInputEvent::Type::MOTION);
6934
6935 EXPECT_EQ(motionArgs.eventTime, verified->eventTimeNanos);
6936 EXPECT_EQ(motionArgs.deviceId, verified->deviceId);
6937 EXPECT_EQ(motionArgs.source, verified->source);
6938 EXPECT_EQ(motionArgs.displayId, verified->displayId);
6939
6940 const VerifiedMotionEvent& verifiedMotion = static_cast<const VerifiedMotionEvent&>(*verified);
6941
Prabir Pradhanb5cb9572021-09-24 06:35:16 -07006942 const vec2 rawXY =
6943 MotionEvent::calculateTransformedXY(motionArgs.source, transform,
6944 motionArgs.pointerCoords[0].getXYValue());
6945 EXPECT_EQ(rawXY.x, verifiedMotion.rawX);
6946 EXPECT_EQ(rawXY.y, verifiedMotion.rawY);
Siarhei Vishniakou47040bf2020-02-28 15:03:13 -08006947 EXPECT_EQ(motionArgs.action & AMOTION_EVENT_ACTION_MASK, verifiedMotion.actionMasked);
Siarhei Vishniakou47040bf2020-02-28 15:03:13 -08006948 EXPECT_EQ(motionArgs.flags & VERIFIED_MOTION_EVENT_FLAGS, verifiedMotion.flags);
Siarhei Vishniakouf355bf92021-12-09 10:43:21 -08006949 EXPECT_EQ(motionArgs.downTime, verifiedMotion.downTimeNanos);
Siarhei Vishniakou47040bf2020-02-28 15:03:13 -08006950 EXPECT_EQ(motionArgs.metaState, verifiedMotion.metaState);
6951 EXPECT_EQ(motionArgs.buttonState, verifiedMotion.buttonState);
6952}
6953
chaviw09c8d2d2020-08-24 15:48:26 -07006954/**
6955 * Ensure that separate calls to sign the same data are generating the same key.
6956 * We avoid asserting against INVALID_HMAC. Since the key is random, there is a non-zero chance
6957 * that a specific key and data combination would produce INVALID_HMAC, which would cause flaky
6958 * tests.
6959 */
6960TEST_F(InputDispatcherTest, GeneratedHmac_IsConsistent) {
6961 KeyEvent event = getTestKeyEvent();
6962 VerifiedKeyEvent verifiedEvent = verifiedKeyEventFromKeyEvent(event);
6963
6964 std::array<uint8_t, 32> hmac1 = mDispatcher->sign(verifiedEvent);
6965 std::array<uint8_t, 32> hmac2 = mDispatcher->sign(verifiedEvent);
6966 ASSERT_EQ(hmac1, hmac2);
6967}
6968
6969/**
6970 * Ensure that changes in VerifiedKeyEvent produce a different hmac.
6971 */
6972TEST_F(InputDispatcherTest, GeneratedHmac_ChangesWhenFieldsChange) {
6973 KeyEvent event = getTestKeyEvent();
6974 VerifiedKeyEvent verifiedEvent = verifiedKeyEventFromKeyEvent(event);
6975 std::array<uint8_t, 32> initialHmac = mDispatcher->sign(verifiedEvent);
6976
6977 verifiedEvent.deviceId += 1;
6978 ASSERT_NE(initialHmac, mDispatcher->sign(verifiedEvent));
6979
6980 verifiedEvent.source += 1;
6981 ASSERT_NE(initialHmac, mDispatcher->sign(verifiedEvent));
6982
6983 verifiedEvent.eventTimeNanos += 1;
6984 ASSERT_NE(initialHmac, mDispatcher->sign(verifiedEvent));
6985
6986 verifiedEvent.displayId += 1;
6987 ASSERT_NE(initialHmac, mDispatcher->sign(verifiedEvent));
6988
6989 verifiedEvent.action += 1;
6990 ASSERT_NE(initialHmac, mDispatcher->sign(verifiedEvent));
6991
6992 verifiedEvent.downTimeNanos += 1;
6993 ASSERT_NE(initialHmac, mDispatcher->sign(verifiedEvent));
6994
6995 verifiedEvent.flags += 1;
6996 ASSERT_NE(initialHmac, mDispatcher->sign(verifiedEvent));
6997
6998 verifiedEvent.keyCode += 1;
6999 ASSERT_NE(initialHmac, mDispatcher->sign(verifiedEvent));
7000
7001 verifiedEvent.scanCode += 1;
7002 ASSERT_NE(initialHmac, mDispatcher->sign(verifiedEvent));
7003
7004 verifiedEvent.metaState += 1;
7005 ASSERT_NE(initialHmac, mDispatcher->sign(verifiedEvent));
7006
7007 verifiedEvent.repeatCount += 1;
7008 ASSERT_NE(initialHmac, mDispatcher->sign(verifiedEvent));
7009}
7010
Vishnu Nair958da932020-08-21 17:12:37 -07007011TEST_F(InputDispatcherTest, SetFocusedWindow) {
7012 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
7013 sp<FakeWindowHandle> windowTop =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07007014 sp<FakeWindowHandle>::make(application, mDispatcher, "Top", ADISPLAY_ID_DEFAULT);
Vishnu Nair958da932020-08-21 17:12:37 -07007015 sp<FakeWindowHandle> windowSecond =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07007016 sp<FakeWindowHandle>::make(application, mDispatcher, "Second", ADISPLAY_ID_DEFAULT);
Vishnu Nair958da932020-08-21 17:12:37 -07007017 mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application);
7018
7019 // Top window is also focusable but is not granted focus.
7020 windowTop->setFocusable(true);
7021 windowSecond->setFocusable(true);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07007022 mDispatcher->onWindowInfosChanged(
7023 {{*windowTop->getInfo(), *windowSecond->getInfo()}, {}, 0, 0});
Vishnu Nair958da932020-08-21 17:12:37 -07007024 setFocusedWindow(windowSecond);
7025
7026 windowSecond->consumeFocusEvent(true);
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07007027 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectKeyDown(*mDispatcher))
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08007028 << "Inject key event should return InputEventInjectionResult::SUCCEEDED";
Vishnu Nair958da932020-08-21 17:12:37 -07007029
7030 // Focused window should receive event.
7031 windowSecond->consumeKeyDown(ADISPLAY_ID_NONE);
7032 windowTop->assertNoEvents();
7033}
7034
7035TEST_F(InputDispatcherTest, SetFocusedWindow_DropRequestInvalidChannel) {
7036 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
7037 sp<FakeWindowHandle> window =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07007038 sp<FakeWindowHandle>::make(application, mDispatcher, "TestWindow", ADISPLAY_ID_DEFAULT);
Vishnu Nair958da932020-08-21 17:12:37 -07007039 mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application);
7040
7041 window->setFocusable(true);
7042 // Release channel for window is no longer valid.
7043 window->releaseChannel();
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07007044 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Vishnu Nair958da932020-08-21 17:12:37 -07007045 setFocusedWindow(window);
7046
7047 // Test inject a key down, should timeout.
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07007048 ASSERT_NO_FATAL_FAILURE(assertInjectedKeyTimesOut(*mDispatcher));
Vishnu Nair958da932020-08-21 17:12:37 -07007049
7050 // window channel is invalid, so it should not receive any input event.
7051 window->assertNoEvents();
7052}
7053
7054TEST_F(InputDispatcherTest, SetFocusedWindow_DropRequestNoFocusableWindow) {
7055 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
7056 sp<FakeWindowHandle> window =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07007057 sp<FakeWindowHandle>::make(application, mDispatcher, "TestWindow", ADISPLAY_ID_DEFAULT);
Prabir Pradhan76bdecb2022-01-31 11:14:15 -08007058 window->setFocusable(false);
Vishnu Nair958da932020-08-21 17:12:37 -07007059 mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application);
7060
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07007061 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Vishnu Nair958da932020-08-21 17:12:37 -07007062 setFocusedWindow(window);
7063
7064 // Test inject a key down, should timeout.
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07007065 ASSERT_NO_FATAL_FAILURE(assertInjectedKeyTimesOut(*mDispatcher));
Vishnu Nair958da932020-08-21 17:12:37 -07007066
Prabir Pradhan76bdecb2022-01-31 11:14:15 -08007067 // window is not focusable, so it should not receive any input event.
Vishnu Nair958da932020-08-21 17:12:37 -07007068 window->assertNoEvents();
7069}
7070
7071TEST_F(InputDispatcherTest, SetFocusedWindow_CheckFocusedToken) {
7072 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
7073 sp<FakeWindowHandle> windowTop =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07007074 sp<FakeWindowHandle>::make(application, mDispatcher, "Top", ADISPLAY_ID_DEFAULT);
Vishnu Nair958da932020-08-21 17:12:37 -07007075 sp<FakeWindowHandle> windowSecond =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07007076 sp<FakeWindowHandle>::make(application, mDispatcher, "Second", ADISPLAY_ID_DEFAULT);
Vishnu Nair958da932020-08-21 17:12:37 -07007077 mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application);
7078
7079 windowTop->setFocusable(true);
7080 windowSecond->setFocusable(true);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07007081 mDispatcher->onWindowInfosChanged(
7082 {{*windowTop->getInfo(), *windowSecond->getInfo()}, {}, 0, 0});
Vishnu Nair958da932020-08-21 17:12:37 -07007083 setFocusedWindow(windowTop);
7084 windowTop->consumeFocusEvent(true);
7085
Chavi Weingarten847e8512023-03-29 00:26:09 +00007086 windowTop->editInfo()->focusTransferTarget = windowSecond->getToken();
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07007087 mDispatcher->onWindowInfosChanged(
7088 {{*windowTop->getInfo(), *windowSecond->getInfo()}, {}, 0, 0});
Vishnu Nair958da932020-08-21 17:12:37 -07007089 windowSecond->consumeFocusEvent(true);
7090 windowTop->consumeFocusEvent(false);
7091
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07007092 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectKeyDown(*mDispatcher))
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08007093 << "Inject key event should return InputEventInjectionResult::SUCCEEDED";
Vishnu Nair958da932020-08-21 17:12:37 -07007094
7095 // Focused window should receive event.
7096 windowSecond->consumeKeyDown(ADISPLAY_ID_NONE);
7097}
7098
Chavi Weingarten847e8512023-03-29 00:26:09 +00007099TEST_F(InputDispatcherTest, SetFocusedWindow_TransferFocusTokenNotFocusable) {
Vishnu Nair958da932020-08-21 17:12:37 -07007100 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
7101 sp<FakeWindowHandle> windowTop =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07007102 sp<FakeWindowHandle>::make(application, mDispatcher, "Top", ADISPLAY_ID_DEFAULT);
Vishnu Nair958da932020-08-21 17:12:37 -07007103 sp<FakeWindowHandle> windowSecond =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07007104 sp<FakeWindowHandle>::make(application, mDispatcher, "Second", ADISPLAY_ID_DEFAULT);
Vishnu Nair958da932020-08-21 17:12:37 -07007105 mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application);
7106
7107 windowTop->setFocusable(true);
Chavi Weingarten847e8512023-03-29 00:26:09 +00007108 windowSecond->setFocusable(false);
7109 windowTop->editInfo()->focusTransferTarget = windowSecond->getToken();
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07007110 mDispatcher->onWindowInfosChanged(
7111 {{*windowTop->getInfo(), *windowSecond->getInfo()}, {}, 0, 0});
Chavi Weingarten847e8512023-03-29 00:26:09 +00007112 setFocusedWindow(windowTop);
7113 windowTop->consumeFocusEvent(true);
Vishnu Nair958da932020-08-21 17:12:37 -07007114
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07007115 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectKeyDown(*mDispatcher))
Chavi Weingarten847e8512023-03-29 00:26:09 +00007116 << "Inject key event should return InputEventInjectionResult::SUCCEEDED";
Vishnu Nair958da932020-08-21 17:12:37 -07007117
7118 // Event should be dropped.
Chavi Weingarten847e8512023-03-29 00:26:09 +00007119 windowTop->consumeKeyDown(ADISPLAY_ID_NONE);
Vishnu Nair958da932020-08-21 17:12:37 -07007120 windowSecond->assertNoEvents();
7121}
7122
7123TEST_F(InputDispatcherTest, SetFocusedWindow_DeferInvisibleWindow) {
7124 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
7125 sp<FakeWindowHandle> window =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07007126 sp<FakeWindowHandle>::make(application, mDispatcher, "TestWindow", ADISPLAY_ID_DEFAULT);
Vishnu Nair958da932020-08-21 17:12:37 -07007127 sp<FakeWindowHandle> previousFocusedWindow =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07007128 sp<FakeWindowHandle>::make(application, mDispatcher, "previousFocusedWindow",
7129 ADISPLAY_ID_DEFAULT);
Vishnu Nair958da932020-08-21 17:12:37 -07007130 mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application);
7131
7132 window->setFocusable(true);
7133 previousFocusedWindow->setFocusable(true);
7134 window->setVisible(false);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07007135 mDispatcher->onWindowInfosChanged(
7136 {{*window->getInfo(), *previousFocusedWindow->getInfo()}, {}, 0, 0});
Vishnu Nair958da932020-08-21 17:12:37 -07007137 setFocusedWindow(previousFocusedWindow);
7138 previousFocusedWindow->consumeFocusEvent(true);
7139
7140 // Requesting focus on invisible window takes focus from currently focused window.
7141 setFocusedWindow(window);
7142 previousFocusedWindow->consumeFocusEvent(false);
7143
7144 // Injected key goes to pending queue.
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08007145 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07007146 injectKey(*mDispatcher, AKEY_EVENT_ACTION_DOWN, /*repeatCount=*/0,
7147 ADISPLAY_ID_DEFAULT, InputEventInjectionSync::NONE));
Vishnu Nair958da932020-08-21 17:12:37 -07007148
7149 // Window does not get focus event or key down.
7150 window->assertNoEvents();
7151
7152 // Window becomes visible.
7153 window->setVisible(true);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07007154 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Vishnu Nair958da932020-08-21 17:12:37 -07007155
7156 // Window receives focus event.
7157 window->consumeFocusEvent(true);
7158 // Focused window receives key down.
7159 window->consumeKeyDown(ADISPLAY_ID_DEFAULT);
7160}
7161
Vishnu Nair599f1412021-06-21 10:39:58 -07007162TEST_F(InputDispatcherTest, DisplayRemoved) {
7163 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
7164 sp<FakeWindowHandle> window =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07007165 sp<FakeWindowHandle>::make(application, mDispatcher, "window", ADISPLAY_ID_DEFAULT);
Vishnu Nair599f1412021-06-21 10:39:58 -07007166 mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application);
7167
7168 // window is granted focus.
7169 window->setFocusable(true);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07007170 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Vishnu Nair599f1412021-06-21 10:39:58 -07007171 setFocusedWindow(window);
7172 window->consumeFocusEvent(true);
7173
7174 // When a display is removed window loses focus.
7175 mDispatcher->displayRemoved(ADISPLAY_ID_DEFAULT);
7176 window->consumeFocusEvent(false);
7177}
7178
Siarhei Vishniakou870ecec2020-12-09 08:07:46 -10007179/**
7180 * Launch two windows, with different owners. One window (slipperyExitWindow) has Flag::SLIPPERY,
7181 * and overlaps the other window, slipperyEnterWindow. The window 'slipperyExitWindow' is on top
7182 * of the 'slipperyEnterWindow'.
7183 *
7184 * Inject touch down into the top window. Upon receipt of the DOWN event, move the window in such
7185 * a way so that the touched location is no longer covered by the top window.
7186 *
7187 * Next, inject a MOVE event. Because the top window already moved earlier, this event is now
7188 * positioned over the bottom (slipperyEnterWindow) only. And because the top window had
7189 * Flag::SLIPPERY, this will cause the top window to lose the touch event (it will receive
7190 * ACTION_CANCEL instead), and the bottom window will receive a newly generated gesture (starting
7191 * with ACTION_DOWN).
7192 * Thus, the touch has been transferred from the top window into the bottom window, because the top
7193 * window moved itself away from the touched location and had Flag::SLIPPERY.
7194 *
7195 * Even though the top window moved away from the touched location, it is still obscuring the bottom
7196 * window. It's just not obscuring it at the touched location. That means, FLAG_WINDOW_IS_PARTIALLY_
7197 * OBSCURED should be set for the MotionEvent that reaches the bottom window.
7198 *
7199 * In this test, we ensure that the event received by the bottom window has
7200 * FLAG_WINDOW_IS_PARTIALLY_OBSCURED.
7201 */
7202TEST_F(InputDispatcherTest, SlipperyWindow_SetsFlagPartiallyObscured) {
Prabir Pradhanaeebeb42023-06-13 19:53:03 +00007203 constexpr gui::Pid SLIPPERY_PID{WINDOW_PID.val() + 1};
Prabir Pradhan8a5c41d2023-06-08 19:13:46 +00007204 constexpr gui::Uid SLIPPERY_UID{WINDOW_UID.val() + 1};
Siarhei Vishniakou870ecec2020-12-09 08:07:46 -10007205
7206 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
7207 mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application);
7208
7209 sp<FakeWindowHandle> slipperyExitWindow =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07007210 sp<FakeWindowHandle>::make(application, mDispatcher, "Top", ADISPLAY_ID_DEFAULT);
Prabir Pradhan4d5c52f2022-01-31 08:52:10 -08007211 slipperyExitWindow->setSlippery(true);
Siarhei Vishniakou870ecec2020-12-09 08:07:46 -10007212 // Make sure this one overlaps the bottom window
7213 slipperyExitWindow->setFrame(Rect(25, 25, 75, 75));
7214 // Change the owner uid/pid of the window so that it is considered to be occluding the bottom
7215 // one. Windows with the same owner are not considered to be occluding each other.
7216 slipperyExitWindow->setOwnerInfo(SLIPPERY_PID, SLIPPERY_UID);
7217
7218 sp<FakeWindowHandle> slipperyEnterWindow =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07007219 sp<FakeWindowHandle>::make(application, mDispatcher, "Second", ADISPLAY_ID_DEFAULT);
Siarhei Vishniakou870ecec2020-12-09 08:07:46 -10007220 slipperyExitWindow->setFrame(Rect(0, 0, 100, 100));
7221
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07007222 mDispatcher->onWindowInfosChanged(
7223 {{*slipperyExitWindow->getInfo(), *slipperyEnterWindow->getInfo()}, {}, 0, 0});
Siarhei Vishniakou870ecec2020-12-09 08:07:46 -10007224
7225 // Use notifyMotion instead of injecting to avoid dealing with injection permissions
Prabir Pradhan678438e2023-04-13 19:32:51 +00007226 mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_DOWN,
7227 AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
7228 {{50, 50}}));
Siarhei Vishniakou870ecec2020-12-09 08:07:46 -10007229 slipperyExitWindow->consumeMotionDown();
7230 slipperyExitWindow->setFrame(Rect(70, 70, 100, 100));
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07007231 mDispatcher->onWindowInfosChanged(
7232 {{*slipperyExitWindow->getInfo(), *slipperyEnterWindow->getInfo()}, {}, 0, 0});
Siarhei Vishniakou870ecec2020-12-09 08:07:46 -10007233
Prabir Pradhan678438e2023-04-13 19:32:51 +00007234 mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_MOVE,
7235 AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
7236 {{51, 51}}));
Siarhei Vishniakou870ecec2020-12-09 08:07:46 -10007237
7238 slipperyExitWindow->consumeMotionCancel();
7239
7240 slipperyEnterWindow->consumeMotionDown(ADISPLAY_ID_DEFAULT,
7241 AMOTION_EVENT_FLAG_WINDOW_IS_PARTIALLY_OBSCURED);
7242}
7243
Siarhei Vishniakouafa08cc2023-05-08 22:35:50 -07007244/**
7245 * Two windows, one on the left and another on the right. The left window is slippery. The right
7246 * window isn't eligible to receive touch because it specifies InputConfig::DROP_INPUT. When the
7247 * touch moves from the left window into the right window, the gesture should continue to go to the
7248 * left window. Touch shouldn't slip because the right window can't receive touches. This test
7249 * reproduces a crash.
7250 */
7251TEST_F(InputDispatcherTest, TouchSlippingIntoWindowThatDropsTouches) {
7252 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
7253
7254 sp<FakeWindowHandle> leftSlipperyWindow =
7255 sp<FakeWindowHandle>::make(application, mDispatcher, "Left", ADISPLAY_ID_DEFAULT);
7256 leftSlipperyWindow->setSlippery(true);
7257 leftSlipperyWindow->setFrame(Rect(0, 0, 100, 100));
7258
7259 sp<FakeWindowHandle> rightDropTouchesWindow =
7260 sp<FakeWindowHandle>::make(application, mDispatcher, "Right", ADISPLAY_ID_DEFAULT);
7261 rightDropTouchesWindow->setFrame(Rect(100, 0, 200, 100));
7262 rightDropTouchesWindow->setDropInput(true);
7263
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07007264 mDispatcher->onWindowInfosChanged(
7265 {{*leftSlipperyWindow->getInfo(), *rightDropTouchesWindow->getInfo()}, {}, 0, 0});
Siarhei Vishniakouafa08cc2023-05-08 22:35:50 -07007266
7267 // Start touch in the left window
7268 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
7269 .pointer(PointerBuilder(0, ToolType::FINGER).x(50).y(50))
7270 .build());
7271 leftSlipperyWindow->consumeMotionDown();
7272
7273 // And move it into the right window
7274 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN)
7275 .pointer(PointerBuilder(0, ToolType::FINGER).x(150).y(50))
7276 .build());
7277
7278 // Since the right window isn't eligible to receive input, touch does not slip.
7279 // The left window continues to receive the gesture.
7280 leftSlipperyWindow->consumeMotionEvent(WithMotionAction(ACTION_MOVE));
7281 rightDropTouchesWindow->assertNoEvents();
7282}
7283
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -07007284/**
7285 * A single window is on screen first. Touch is injected into that window. Next, a second window
7286 * appears. Since the first window is slippery, touch will move from the first window to the second.
7287 */
7288TEST_F(InputDispatcherTest, InjectedTouchSlips) {
7289 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
7290 sp<FakeWindowHandle> originalWindow =
7291 sp<FakeWindowHandle>::make(application, mDispatcher, "Original", ADISPLAY_ID_DEFAULT);
7292 originalWindow->setFrame(Rect(0, 0, 200, 200));
7293 originalWindow->setSlippery(true);
7294
7295 sp<FakeWindowHandle> appearingWindow =
7296 sp<FakeWindowHandle>::make(application, mDispatcher, "Appearing", ADISPLAY_ID_DEFAULT);
7297 appearingWindow->setFrame(Rect(0, 0, 200, 200));
7298
7299 mDispatcher->onWindowInfosChanged({{*originalWindow->getInfo()}, {}, 0, 0});
7300
7301 // Touch down on the original window
7302 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
7303 injectMotionEvent(*mDispatcher,
7304 MotionEventBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
7305 .pointer(PointerBuilder(1, ToolType::FINGER).x(100).y(100))
7306 .build()));
7307 originalWindow->consumeMotionEvent(WithMotionAction(ACTION_DOWN));
7308
7309 // Now, a new window appears. This could be, for example, a notification shade that appears
7310 // after user starts to drag down on the launcher window.
7311 mDispatcher->onWindowInfosChanged(
7312 {{*appearingWindow->getInfo(), *originalWindow->getInfo()}, {}, 0, 0});
7313 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
7314 injectMotionEvent(*mDispatcher,
7315 MotionEventBuilder(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN)
7316 .pointer(PointerBuilder(1, ToolType::FINGER).x(110).y(110))
7317 .build()));
7318 originalWindow->consumeMotionEvent(WithMotionAction(ACTION_CANCEL));
7319 appearingWindow->consumeMotionEvent(WithMotionAction(ACTION_DOWN));
7320 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
7321 injectMotionEvent(*mDispatcher,
7322 MotionEventBuilder(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN)
7323 .pointer(PointerBuilder(1, ToolType::FINGER).x(120).y(120))
7324 .build()));
7325 appearingWindow->consumeMotionEvent(WithMotionAction(ACTION_MOVE));
7326
7327 originalWindow->assertNoEvents();
7328 appearingWindow->assertNoEvents();
7329}
7330
Prabir Pradhan8ede1d12023-05-08 19:37:44 +00007331TEST_F(InputDispatcherTest, NotifiesDeviceInteractionsWithMotions) {
Prabir Pradhan8a5c41d2023-06-08 19:13:46 +00007332 using Uid = gui::Uid;
Prabir Pradhan8ede1d12023-05-08 19:37:44 +00007333 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
7334
7335 sp<FakeWindowHandle> leftWindow =
7336 sp<FakeWindowHandle>::make(application, mDispatcher, "Left", ADISPLAY_ID_DEFAULT);
7337 leftWindow->setFrame(Rect(0, 0, 100, 100));
Prabir Pradhanaeebeb42023-06-13 19:53:03 +00007338 leftWindow->setOwnerInfo(gui::Pid{1}, Uid{101});
Prabir Pradhan8ede1d12023-05-08 19:37:44 +00007339
7340 sp<FakeWindowHandle> rightSpy =
7341 sp<FakeWindowHandle>::make(application, mDispatcher, "Right spy", ADISPLAY_ID_DEFAULT);
7342 rightSpy->setFrame(Rect(100, 0, 200, 100));
Prabir Pradhanaeebeb42023-06-13 19:53:03 +00007343 rightSpy->setOwnerInfo(gui::Pid{2}, Uid{102});
Prabir Pradhan8ede1d12023-05-08 19:37:44 +00007344 rightSpy->setSpy(true);
7345 rightSpy->setTrustedOverlay(true);
7346
7347 sp<FakeWindowHandle> rightWindow =
7348 sp<FakeWindowHandle>::make(application, mDispatcher, "Right", ADISPLAY_ID_DEFAULT);
7349 rightWindow->setFrame(Rect(100, 0, 200, 100));
Prabir Pradhanaeebeb42023-06-13 19:53:03 +00007350 rightWindow->setOwnerInfo(gui::Pid{3}, Uid{103});
Prabir Pradhan8ede1d12023-05-08 19:37:44 +00007351
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07007352 mDispatcher->onWindowInfosChanged(
7353 {{*rightSpy->getInfo(), *rightWindow->getInfo(), *leftWindow->getInfo()}, {}, 0, 0});
Prabir Pradhan8ede1d12023-05-08 19:37:44 +00007354
7355 // Touch in the left window
7356 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
7357 .pointer(PointerBuilder(0, ToolType::FINGER).x(50).y(50))
7358 .build());
7359 ASSERT_NO_FATAL_FAILURE(leftWindow->consumeMotionDown());
7360 mDispatcher->waitForIdle();
Prabir Pradhan8a5c41d2023-06-08 19:13:46 +00007361 ASSERT_NO_FATAL_FAILURE(
7362 mFakePolicy->assertNotifyDeviceInteractionWasCalled(DEVICE_ID, {Uid{101}}));
Prabir Pradhan8ede1d12023-05-08 19:37:44 +00007363
7364 // Touch another finger over the right windows
7365 mDispatcher->notifyMotion(MotionArgsBuilder(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
7366 .pointer(PointerBuilder(0, ToolType::FINGER).x(50).y(50))
7367 .pointer(PointerBuilder(1, ToolType::FINGER).x(150).y(50))
7368 .build());
7369 ASSERT_NO_FATAL_FAILURE(rightSpy->consumeMotionDown());
7370 ASSERT_NO_FATAL_FAILURE(rightWindow->consumeMotionDown());
7371 ASSERT_NO_FATAL_FAILURE(leftWindow->consumeMotionMove());
7372 mDispatcher->waitForIdle();
7373 ASSERT_NO_FATAL_FAILURE(
Prabir Pradhan8a5c41d2023-06-08 19:13:46 +00007374 mFakePolicy->assertNotifyDeviceInteractionWasCalled(DEVICE_ID,
7375 {Uid{101}, Uid{102}, Uid{103}}));
Prabir Pradhan8ede1d12023-05-08 19:37:44 +00007376
7377 // Release finger over left window. The UP actions are not treated as device interaction.
7378 // The windows that did not receive the UP pointer will receive MOVE events, but since this
7379 // is part of the UP action, we do not treat this as device interaction.
7380 mDispatcher->notifyMotion(MotionArgsBuilder(POINTER_0_UP, AINPUT_SOURCE_TOUCHSCREEN)
7381 .pointer(PointerBuilder(0, ToolType::FINGER).x(50).y(50))
7382 .pointer(PointerBuilder(1, ToolType::FINGER).x(150).y(50))
7383 .build());
7384 ASSERT_NO_FATAL_FAILURE(leftWindow->consumeMotionUp());
7385 ASSERT_NO_FATAL_FAILURE(rightSpy->consumeMotionMove());
7386 ASSERT_NO_FATAL_FAILURE(rightWindow->consumeMotionMove());
7387 mDispatcher->waitForIdle();
7388 ASSERT_NO_FATAL_FAILURE(mFakePolicy->assertNotifyDeviceInteractionWasNotCalled());
7389
7390 // Move remaining finger
7391 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN)
7392 .pointer(PointerBuilder(1, ToolType::FINGER).x(150).y(50))
7393 .build());
7394 ASSERT_NO_FATAL_FAILURE(rightSpy->consumeMotionMove());
7395 ASSERT_NO_FATAL_FAILURE(rightWindow->consumeMotionMove());
7396 mDispatcher->waitForIdle();
7397 ASSERT_NO_FATAL_FAILURE(
Prabir Pradhan8a5c41d2023-06-08 19:13:46 +00007398 mFakePolicy->assertNotifyDeviceInteractionWasCalled(DEVICE_ID, {Uid{102}, Uid{103}}));
Prabir Pradhan8ede1d12023-05-08 19:37:44 +00007399
7400 // Release all fingers
7401 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN)
7402 .pointer(PointerBuilder(1, ToolType::FINGER).x(150).y(50))
7403 .build());
7404 ASSERT_NO_FATAL_FAILURE(rightSpy->consumeMotionUp());
7405 ASSERT_NO_FATAL_FAILURE(rightWindow->consumeMotionUp());
7406 mDispatcher->waitForIdle();
7407 ASSERT_NO_FATAL_FAILURE(mFakePolicy->assertNotifyDeviceInteractionWasNotCalled());
7408}
7409
7410TEST_F(InputDispatcherTest, NotifiesDeviceInteractionsWithKeys) {
7411 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
7412
7413 sp<FakeWindowHandle> window =
7414 sp<FakeWindowHandle>::make(application, mDispatcher, "Window", ADISPLAY_ID_DEFAULT);
7415 window->setFrame(Rect(0, 0, 100, 100));
Prabir Pradhanaeebeb42023-06-13 19:53:03 +00007416 window->setOwnerInfo(gui::Pid{1}, gui::Uid{101});
Prabir Pradhan8ede1d12023-05-08 19:37:44 +00007417
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07007418 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Prabir Pradhan8ede1d12023-05-08 19:37:44 +00007419 setFocusedWindow(window);
7420 ASSERT_NO_FATAL_FAILURE(window->consumeFocusEvent(true));
7421
7422 mDispatcher->notifyKey(KeyArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_KEYBOARD).build());
7423 ASSERT_NO_FATAL_FAILURE(window->consumeKeyDown(ADISPLAY_ID_DEFAULT));
7424 mDispatcher->waitForIdle();
Prabir Pradhan8a5c41d2023-06-08 19:13:46 +00007425 ASSERT_NO_FATAL_FAILURE(
7426 mFakePolicy->assertNotifyDeviceInteractionWasCalled(DEVICE_ID, {gui::Uid{101}}));
Prabir Pradhan8ede1d12023-05-08 19:37:44 +00007427
7428 // The UP actions are not treated as device interaction.
7429 mDispatcher->notifyKey(KeyArgsBuilder(ACTION_UP, AINPUT_SOURCE_KEYBOARD).build());
7430 ASSERT_NO_FATAL_FAILURE(window->consumeKeyUp(ADISPLAY_ID_DEFAULT));
7431 mDispatcher->waitForIdle();
7432 ASSERT_NO_FATAL_FAILURE(mFakePolicy->assertNotifyDeviceInteractionWasNotCalled());
7433}
7434
Prabir Pradhan5893d362023-11-17 04:30:40 +00007435TEST_F(InputDispatcherTest, HoverEnterExitSynthesisUsesNewEventId) {
7436 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
7437
7438 sp<FakeWindowHandle> left = sp<FakeWindowHandle>::make(application, mDispatcher, "Left Window",
7439 ADISPLAY_ID_DEFAULT);
7440 left->setFrame(Rect(0, 0, 100, 100));
7441 sp<FakeWindowHandle> right = sp<FakeWindowHandle>::make(application, mDispatcher,
7442 "Right Window", ADISPLAY_ID_DEFAULT);
7443 right->setFrame(Rect(100, 0, 200, 100));
7444 sp<FakeWindowHandle> spy =
7445 sp<FakeWindowHandle>::make(application, mDispatcher, "Spy Window", ADISPLAY_ID_DEFAULT);
7446 spy->setFrame(Rect(0, 0, 200, 100));
7447 spy->setTrustedOverlay(true);
7448 spy->setSpy(true);
7449
7450 mDispatcher->onWindowInfosChanged(
7451 {{*spy->getInfo(), *left->getInfo(), *right->getInfo()}, {}, 0, 0});
7452
7453 // Send hover move to the left window, and ensure hover enter is synthesized with a new eventId.
7454 NotifyMotionArgs notifyArgs = generateMotionArgs(ACTION_HOVER_MOVE, AINPUT_SOURCE_STYLUS,
7455 ADISPLAY_ID_DEFAULT, {PointF{50, 50}});
7456 mDispatcher->notifyMotion(notifyArgs);
7457
Siarhei Vishniakoud3061ab2023-12-18 20:41:08 -08007458 std::unique_ptr<MotionEvent> leftEnter = left->consumeMotionEvent(
Prabir Pradhan5893d362023-11-17 04:30:40 +00007459 AllOf(WithMotionAction(ACTION_HOVER_ENTER), Not(WithEventId(notifyArgs.id)),
7460 WithEventIdSource(IdGenerator::Source::INPUT_DISPATCHER)));
Siarhei Vishniakoud3061ab2023-12-18 20:41:08 -08007461 ASSERT_NE(nullptr, leftEnter);
Prabir Pradhan5893d362023-11-17 04:30:40 +00007462 spy->consumeMotionEvent(AllOf(WithMotionAction(ACTION_HOVER_ENTER),
7463 Not(WithEventId(notifyArgs.id)),
Siarhei Vishniakoud3061ab2023-12-18 20:41:08 -08007464 Not(WithEventId(leftEnter->getId())),
Prabir Pradhan5893d362023-11-17 04:30:40 +00007465 WithEventIdSource(IdGenerator::Source::INPUT_DISPATCHER)));
7466
7467 // Send move to the right window, and ensure hover exit and enter are synthesized with new ids.
7468 notifyArgs = generateMotionArgs(ACTION_HOVER_MOVE, AINPUT_SOURCE_STYLUS, ADISPLAY_ID_DEFAULT,
7469 {PointF{150, 50}});
7470 mDispatcher->notifyMotion(notifyArgs);
7471
Siarhei Vishniakoud3061ab2023-12-18 20:41:08 -08007472 std::unique_ptr<MotionEvent> leftExit = left->consumeMotionEvent(
Prabir Pradhan5893d362023-11-17 04:30:40 +00007473 AllOf(WithMotionAction(ACTION_HOVER_EXIT), Not(WithEventId(notifyArgs.id)),
7474 WithEventIdSource(IdGenerator::Source::INPUT_DISPATCHER)));
Siarhei Vishniakoud3061ab2023-12-18 20:41:08 -08007475 ASSERT_NE(nullptr, leftExit);
Prabir Pradhan5893d362023-11-17 04:30:40 +00007476 right->consumeMotionEvent(AllOf(WithMotionAction(ACTION_HOVER_ENTER),
7477 Not(WithEventId(notifyArgs.id)),
Siarhei Vishniakoud3061ab2023-12-18 20:41:08 -08007478 Not(WithEventId(leftExit->getId())),
Prabir Pradhan5893d362023-11-17 04:30:40 +00007479 WithEventIdSource(IdGenerator::Source::INPUT_DISPATCHER)));
7480
7481 spy->consumeMotionEvent(AllOf(WithMotionAction(ACTION_HOVER_MOVE), WithEventId(notifyArgs.id)));
7482}
7483
Linnan Liccf6ce32024-04-11 20:32:13 +08007484/**
7485 * When a device reports a DOWN event, which lands in a window that supports splits, and then the
7486 * device then reports a POINTER_DOWN, which lands in the location of a non-existing window, then
7487 * the previous window should receive this event and not be dropped.
7488 */
7489TEST_F(InputDispatcherMultiDeviceTest, SingleDevicePointerDownEventRetentionWithoutWindowTarget) {
7490 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
7491 sp<FakeWindowHandle> window =
7492 sp<FakeWindowHandle>::make(application, mDispatcher, "Window", ADISPLAY_ID_DEFAULT);
7493 window->setFrame(Rect(0, 0, 100, 100));
7494 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
7495
7496 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
7497 .pointer(PointerBuilder(0, ToolType::FINGER).x(50).y(50))
7498 .build());
7499
7500 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN)));
7501
7502 mDispatcher->notifyMotion(MotionArgsBuilder(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
7503 .pointer(PointerBuilder(0, ToolType::FINGER).x(50).y(50))
7504 .pointer(PointerBuilder(1, ToolType::FINGER).x(200).y(200))
7505 .build());
7506
7507 window->consumeMotionEvent(AllOf(WithMotionAction(POINTER_1_DOWN)));
7508}
7509
7510/**
7511 * When deviceA reports a DOWN event, which lands in a window that supports splits, and then deviceB
7512 * also reports a DOWN event, which lands in the location of a non-existing window, then the
7513 * previous window should receive deviceB's event and it should be dropped.
7514 */
7515TEST_F(InputDispatcherMultiDeviceTest, SecondDeviceDownEventDroppedWithoutWindowTarget) {
7516 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
7517 sp<FakeWindowHandle> window =
7518 sp<FakeWindowHandle>::make(application, mDispatcher, "Window", ADISPLAY_ID_DEFAULT);
7519 window->setFrame(Rect(0, 0, 100, 100));
7520 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
7521
7522 const DeviceId deviceA = 9;
7523 const DeviceId deviceB = 3;
7524
7525 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
7526 .pointer(PointerBuilder(0, ToolType::FINGER).x(50).y(50))
7527 .deviceId(deviceA)
7528 .build());
7529 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(deviceA)));
7530
7531 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
7532 .pointer(PointerBuilder(0, ToolType::FINGER).x(200).y(200))
7533 .deviceId(deviceB)
7534 .build());
7535 window->assertNoEvents();
7536}
7537
Prabir Pradhanb0dad3a2023-11-02 20:52:47 +00007538class InputDispatcherFallbackKeyTest : public InputDispatcherTest {
7539protected:
7540 std::shared_ptr<FakeApplicationHandle> mApp;
7541 sp<FakeWindowHandle> mWindow;
7542
7543 virtual void SetUp() override {
7544 InputDispatcherTest::SetUp();
7545
7546 mApp = std::make_shared<FakeApplicationHandle>();
7547
7548 mWindow = sp<FakeWindowHandle>::make(mApp, mDispatcher, "Window", ADISPLAY_ID_DEFAULT);
7549 mWindow->setFrame(Rect(0, 0, 100, 100));
7550
7551 mDispatcher->onWindowInfosChanged({{*mWindow->getInfo()}, {}, 0, 0});
7552 setFocusedWindow(mWindow);
7553 ASSERT_NO_FATAL_FAILURE(mWindow->consumeFocusEvent(/*hasFocus=*/true));
7554 }
7555
7556 void setFallback(int32_t keycode) {
7557 mFakePolicy->setUnhandledKeyHandler([keycode](const KeyEvent& event) {
7558 return KeyEventBuilder(event).keyCode(keycode).build();
7559 });
7560 }
7561
7562 void consumeKey(bool handled, const ::testing::Matcher<KeyEvent>& matcher) {
Siarhei Vishniakoud3061ab2023-12-18 20:41:08 -08007563 std::unique_ptr<KeyEvent> event = mWindow->consumeKey(handled);
7564 ASSERT_NE(nullptr, event);
7565 ASSERT_THAT(*event, matcher);
Prabir Pradhanb0dad3a2023-11-02 20:52:47 +00007566 }
7567};
7568
7569TEST_F(InputDispatcherFallbackKeyTest, PolicyNotNotifiedForHandledKey) {
7570 mDispatcher->notifyKey(
7571 KeyArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_KEYBOARD).keyCode(AKEYCODE_A).build());
7572 consumeKey(/*handled=*/true, AllOf(WithKeyAction(ACTION_DOWN), WithKeyCode(AKEYCODE_A)));
7573 ASSERT_NO_FATAL_FAILURE(mFakePolicy->assertUnhandledKeyNotReported());
7574}
7575
7576TEST_F(InputDispatcherFallbackKeyTest, PolicyNotifiedForUnhandledKey) {
7577 mDispatcher->notifyKey(
7578 KeyArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_KEYBOARD).keyCode(AKEYCODE_A).build());
7579 consumeKey(/*handled=*/false, AllOf(WithKeyAction(ACTION_DOWN), WithKeyCode(AKEYCODE_A)));
7580 ASSERT_NO_FATAL_FAILURE(mFakePolicy->assertUnhandledKeyReported(AKEYCODE_A));
7581}
7582
7583TEST_F(InputDispatcherFallbackKeyTest, NoFallbackRequestedByPolicy) {
7584 mDispatcher->notifyKey(
7585 KeyArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_KEYBOARD).keyCode(AKEYCODE_A).build());
7586
7587 // Do not handle this key event.
7588 consumeKey(/*handled=*/false,
7589 AllOf(WithKeyAction(ACTION_DOWN), WithKeyCode(AKEYCODE_A), WithFlags(0)));
7590 ASSERT_NO_FATAL_FAILURE(mFakePolicy->assertUnhandledKeyReported(AKEYCODE_A));
7591
7592 // Since the policy did not request any fallback to be generated, ensure there are no events.
7593 ASSERT_NO_FATAL_FAILURE(mFakePolicy->assertUnhandledKeyNotReported());
7594}
7595
7596TEST_F(InputDispatcherFallbackKeyTest, FallbackDispatchForUnhandledKey) {
7597 setFallback(AKEYCODE_B);
7598 mDispatcher->notifyKey(
7599 KeyArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_KEYBOARD).keyCode(AKEYCODE_A).build());
7600
7601 // Do not handle this key event.
7602 consumeKey(/*handled=*/false,
7603 AllOf(WithKeyAction(ACTION_DOWN), WithKeyCode(AKEYCODE_A), WithFlags(0)));
7604
7605 // Since the key was not handled, ensure the fallback event was dispatched instead.
7606 ASSERT_NO_FATAL_FAILURE(mFakePolicy->assertUnhandledKeyReported(AKEYCODE_A));
7607 consumeKey(/*handled=*/true,
7608 AllOf(WithKeyAction(ACTION_DOWN), WithKeyCode(AKEYCODE_B),
7609 WithFlags(AKEY_EVENT_FLAG_FALLBACK)));
7610
7611 // Release the original key, and ensure the fallback key is also released.
7612 mDispatcher->notifyKey(
7613 KeyArgsBuilder(ACTION_UP, AINPUT_SOURCE_KEYBOARD).keyCode(AKEYCODE_A).build());
7614 consumeKey(/*handled=*/false,
7615 AllOf(WithKeyAction(ACTION_UP), WithKeyCode(AKEYCODE_A), WithFlags(0)));
7616 ASSERT_NO_FATAL_FAILURE(mFakePolicy->assertUnhandledKeyReported(AKEYCODE_A));
7617 consumeKey(/*handled=*/true,
7618 AllOf(WithKeyAction(ACTION_UP), WithKeyCode(AKEYCODE_B),
7619 WithFlags(AKEY_EVENT_FLAG_FALLBACK)));
7620
7621 ASSERT_NO_FATAL_FAILURE(mFakePolicy->assertUnhandledKeyNotReported());
7622 mWindow->assertNoEvents();
7623}
7624
7625TEST_F(InputDispatcherFallbackKeyTest, AppHandlesPreviouslyUnhandledKey) {
7626 setFallback(AKEYCODE_B);
7627 mDispatcher->notifyKey(
7628 KeyArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_KEYBOARD).keyCode(AKEYCODE_A).build());
7629
7630 // Do not handle this key event, but handle the fallback.
7631 consumeKey(/*handled=*/false,
7632 AllOf(WithKeyAction(ACTION_DOWN), WithKeyCode(AKEYCODE_A), WithFlags(0)));
7633 ASSERT_NO_FATAL_FAILURE(mFakePolicy->assertUnhandledKeyReported(AKEYCODE_A));
7634 consumeKey(/*handled=*/true,
7635 AllOf(WithKeyAction(ACTION_DOWN), WithKeyCode(AKEYCODE_B),
7636 WithFlags(AKEY_EVENT_FLAG_FALLBACK)));
7637
7638 // Release the original key, and ensure the fallback key is also released.
7639 mDispatcher->notifyKey(
7640 KeyArgsBuilder(ACTION_UP, AINPUT_SOURCE_KEYBOARD).keyCode(AKEYCODE_A).build());
7641 // But this time, the app handles the original key.
7642 consumeKey(/*handled=*/true,
7643 AllOf(WithKeyAction(ACTION_UP), WithKeyCode(AKEYCODE_A), WithFlags(0)));
7644 ASSERT_NO_FATAL_FAILURE(mFakePolicy->assertUnhandledKeyReported(AKEYCODE_A));
7645 // Ensure the fallback key is canceled.
7646 consumeKey(/*handled=*/true,
7647 AllOf(WithKeyAction(ACTION_UP), WithKeyCode(AKEYCODE_B),
7648 WithFlags(AKEY_EVENT_FLAG_FALLBACK | AKEY_EVENT_FLAG_CANCELED)));
7649
7650 ASSERT_NO_FATAL_FAILURE(mFakePolicy->assertUnhandledKeyNotReported());
7651 mWindow->assertNoEvents();
7652}
7653
7654TEST_F(InputDispatcherFallbackKeyTest, AppDoesNotHandleFallback) {
7655 setFallback(AKEYCODE_B);
7656 mDispatcher->notifyKey(
7657 KeyArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_KEYBOARD).keyCode(AKEYCODE_A).build());
7658
7659 // Do not handle this key event.
7660 consumeKey(/*handled=*/false,
7661 AllOf(WithKeyAction(ACTION_DOWN), WithKeyCode(AKEYCODE_A), WithFlags(0)));
7662 ASSERT_NO_FATAL_FAILURE(mFakePolicy->assertUnhandledKeyReported(AKEYCODE_A));
7663 // App does not handle the fallback either, so ensure another fallback is not generated.
7664 setFallback(AKEYCODE_C);
7665 consumeKey(/*handled=*/false,
7666 AllOf(WithKeyAction(ACTION_DOWN), WithKeyCode(AKEYCODE_B),
7667 WithFlags(AKEY_EVENT_FLAG_FALLBACK)));
7668
7669 // Release the original key, and ensure the fallback key is also released.
7670 setFallback(AKEYCODE_B);
7671 mDispatcher->notifyKey(
7672 KeyArgsBuilder(ACTION_UP, AINPUT_SOURCE_KEYBOARD).keyCode(AKEYCODE_A).build());
7673 consumeKey(/*handled=*/false,
7674 AllOf(WithKeyAction(ACTION_UP), WithKeyCode(AKEYCODE_A), WithFlags(0)));
7675 ASSERT_NO_FATAL_FAILURE(mFakePolicy->assertUnhandledKeyReported(AKEYCODE_A));
7676 consumeKey(/*handled=*/false,
7677 AllOf(WithKeyAction(ACTION_UP), WithKeyCode(AKEYCODE_B),
7678 WithFlags(AKEY_EVENT_FLAG_FALLBACK)));
7679
7680 ASSERT_NO_FATAL_FAILURE(mFakePolicy->assertUnhandledKeyNotReported());
7681 mWindow->assertNoEvents();
7682}
7683
7684TEST_F(InputDispatcherFallbackKeyTest, InconsistentPolicyCancelsFallback) {
7685 setFallback(AKEYCODE_B);
7686 mDispatcher->notifyKey(
7687 KeyArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_KEYBOARD).keyCode(AKEYCODE_A).build());
7688
7689 // Do not handle this key event, so fallback is generated.
7690 consumeKey(/*handled=*/false,
7691 AllOf(WithKeyAction(ACTION_DOWN), WithKeyCode(AKEYCODE_A), WithFlags(0)));
7692 ASSERT_NO_FATAL_FAILURE(mFakePolicy->assertUnhandledKeyReported(AKEYCODE_A));
7693 consumeKey(/*handled=*/true,
7694 AllOf(WithKeyAction(ACTION_DOWN), WithKeyCode(AKEYCODE_B),
7695 WithFlags(AKEY_EVENT_FLAG_FALLBACK)));
7696
7697 // Release the original key, but assume the policy is misbehaving and it
7698 // generates an inconsistent fallback to the one from the DOWN event.
7699 setFallback(AKEYCODE_C);
7700 mDispatcher->notifyKey(
7701 KeyArgsBuilder(ACTION_UP, AINPUT_SOURCE_KEYBOARD).keyCode(AKEYCODE_A).build());
7702 consumeKey(/*handled=*/false,
7703 AllOf(WithKeyAction(ACTION_UP), WithKeyCode(AKEYCODE_A), WithFlags(0)));
7704 ASSERT_NO_FATAL_FAILURE(mFakePolicy->assertUnhandledKeyReported(AKEYCODE_A));
7705 // Ensure the fallback key reported before as DOWN is canceled due to the inconsistency.
7706 consumeKey(/*handled=*/true,
7707 AllOf(WithKeyAction(ACTION_UP), WithKeyCode(AKEYCODE_B),
7708 WithFlags(AKEY_EVENT_FLAG_FALLBACK | AKEY_EVENT_FLAG_CANCELED)));
7709
7710 ASSERT_NO_FATAL_FAILURE(mFakePolicy->assertUnhandledKeyNotReported());
7711 mWindow->assertNoEvents();
7712}
7713
7714TEST_F(InputDispatcherFallbackKeyTest, CanceledKeyCancelsFallback) {
7715 setFallback(AKEYCODE_B);
7716 mDispatcher->notifyKey(
7717 KeyArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_KEYBOARD).keyCode(AKEYCODE_A).build());
7718
7719 // Do not handle this key event, so fallback is generated.
7720 consumeKey(/*handled=*/false,
7721 AllOf(WithKeyAction(ACTION_DOWN), WithKeyCode(AKEYCODE_A), WithFlags(0)));
7722 ASSERT_NO_FATAL_FAILURE(mFakePolicy->assertUnhandledKeyReported(AKEYCODE_A));
7723 consumeKey(/*handled=*/true,
7724 AllOf(WithKeyAction(ACTION_DOWN), WithKeyCode(AKEYCODE_B),
7725 WithFlags(AKEY_EVENT_FLAG_FALLBACK)));
7726
7727 // The original key is canceled.
7728 mDispatcher->notifyKey(KeyArgsBuilder(ACTION_UP, AINPUT_SOURCE_KEYBOARD)
7729 .keyCode(AKEYCODE_A)
7730 .addFlag(AKEY_EVENT_FLAG_CANCELED)
7731 .build());
7732 consumeKey(/*handled=*/false,
7733 AllOf(WithKeyAction(ACTION_UP), WithKeyCode(AKEYCODE_A),
7734 WithFlags(AKEY_EVENT_FLAG_CANCELED)));
7735 ASSERT_NO_FATAL_FAILURE(mFakePolicy->assertUnhandledKeyReported(AKEYCODE_A));
7736 // Ensure the fallback key is also canceled due to the original key being canceled.
7737 consumeKey(/*handled=*/true,
7738 AllOf(WithKeyAction(ACTION_UP), WithKeyCode(AKEYCODE_B),
7739 WithFlags(AKEY_EVENT_FLAG_FALLBACK | AKEY_EVENT_FLAG_CANCELED)));
7740
7741 ASSERT_NO_FATAL_FAILURE(mFakePolicy->assertUnhandledKeyNotReported());
7742 mWindow->assertNoEvents();
7743}
7744
Prabir Pradhanfa2c69f2024-02-01 20:31:34 +00007745TEST_F(InputDispatcherFallbackKeyTest, InputChannelRemovedDuringPolicyCall) {
Prabir Pradhanb13da8f2024-01-09 23:10:13 +00007746 setFallback(AKEYCODE_B);
7747 mDispatcher->notifyKey(
7748 KeyArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_KEYBOARD).keyCode(AKEYCODE_A).build());
7749
7750 // Do not handle this key event.
7751 consumeKey(/*handled=*/false,
7752 AllOf(WithKeyAction(ACTION_DOWN), WithKeyCode(AKEYCODE_A), WithFlags(0)));
7753 ASSERT_NO_FATAL_FAILURE(mFakePolicy->assertUnhandledKeyReported(AKEYCODE_A));
7754 consumeKey(/*handled=*/true,
7755 AllOf(WithKeyAction(ACTION_DOWN), WithKeyCode(AKEYCODE_B),
7756 WithFlags(AKEY_EVENT_FLAG_FALLBACK)));
7757
7758 mFakePolicy->setUnhandledKeyHandler([&](const KeyEvent& event) {
7759 // When the unhandled key is reported to the policy next, remove the input channel.
7760 mDispatcher->removeInputChannel(mWindow->getToken());
7761 return KeyEventBuilder(event).keyCode(AKEYCODE_B).build();
7762 });
7763 // Release the original key, and let the app now handle the previously unhandled key.
7764 // This should result in the previously generated fallback key to be cancelled.
7765 // Since the policy was notified of the unhandled DOWN event earlier, it will also be notified
7766 // of the UP event for consistency. The Dispatcher calls into the policy from its own thread
7767 // without holding the lock, because it need to synchronously fetch the fallback key. While in
7768 // the policy call, we will now remove the input channel. Once the policy call returns, the
7769 // Dispatcher will no longer have a channel to send cancellation events to. Ensure this does
7770 // not cause any crashes.
7771 mDispatcher->notifyKey(
7772 KeyArgsBuilder(ACTION_UP, AINPUT_SOURCE_KEYBOARD).keyCode(AKEYCODE_A).build());
7773 consumeKey(/*handled=*/true,
7774 AllOf(WithKeyAction(ACTION_UP), WithKeyCode(AKEYCODE_A), WithFlags(0)));
7775 ASSERT_NO_FATAL_FAILURE(mFakePolicy->assertUnhandledKeyReported(AKEYCODE_A));
7776}
7777
Prabir Pradhanfa2c69f2024-02-01 20:31:34 +00007778TEST_F(InputDispatcherFallbackKeyTest, WindowRemovedDuringPolicyCall) {
7779 setFallback(AKEYCODE_B);
7780 mDispatcher->notifyKey(
7781 KeyArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_KEYBOARD).keyCode(AKEYCODE_A).build());
7782
7783 // Do not handle this key event.
7784 consumeKey(/*handled=*/false,
7785 AllOf(WithKeyAction(ACTION_DOWN), WithKeyCode(AKEYCODE_A), WithFlags(0)));
7786 ASSERT_NO_FATAL_FAILURE(mFakePolicy->assertUnhandledKeyReported(AKEYCODE_A));
7787 consumeKey(/*handled=*/true,
7788 AllOf(WithKeyAction(ACTION_DOWN), WithKeyCode(AKEYCODE_B),
7789 WithFlags(AKEY_EVENT_FLAG_FALLBACK)));
7790
7791 mFakePolicy->setUnhandledKeyHandler([&](const KeyEvent& event) {
7792 // When the unhandled key is reported to the policy next, remove the window.
7793 mDispatcher->onWindowInfosChanged({{}, {}, 0, 0});
7794 return KeyEventBuilder(event).keyCode(AKEYCODE_B).build();
7795 });
7796 // Release the original key, which the app will not handle. When this unhandled key is reported
7797 // to the policy, the window will be removed.
7798 mDispatcher->notifyKey(
7799 KeyArgsBuilder(ACTION_UP, AINPUT_SOURCE_KEYBOARD).keyCode(AKEYCODE_A).build());
7800 consumeKey(/*handled=*/false,
7801 AllOf(WithKeyAction(ACTION_UP), WithKeyCode(AKEYCODE_A), WithFlags(0)));
7802 ASSERT_NO_FATAL_FAILURE(mFakePolicy->assertUnhandledKeyReported(AKEYCODE_A));
7803
7804 // Since the window was removed, it loses focus, and the channel state will be reset.
7805 consumeKey(/*handled=*/true,
7806 AllOf(WithKeyAction(ACTION_UP), WithKeyCode(AKEYCODE_B),
7807 WithFlags(AKEY_EVENT_FLAG_FALLBACK | AKEY_EVENT_FLAG_CANCELED)));
7808 mWindow->consumeFocusEvent(false);
7809 mWindow->assertNoEvents();
7810}
7811
7812TEST_F(InputDispatcherFallbackKeyTest, WindowRemovedWhileAwaitingFinishedSignal) {
7813 setFallback(AKEYCODE_B);
7814 mDispatcher->notifyKey(
7815 KeyArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_KEYBOARD).keyCode(AKEYCODE_A).build());
7816
7817 // Do not handle this key event.
7818 consumeKey(/*handled=*/false,
7819 AllOf(WithKeyAction(ACTION_DOWN), WithKeyCode(AKEYCODE_A), WithFlags(0)));
7820 ASSERT_NO_FATAL_FAILURE(mFakePolicy->assertUnhandledKeyReported(AKEYCODE_A));
7821 const auto [seq, event] = mWindow->receiveEvent();
7822 ASSERT_TRUE(seq.has_value() && event != nullptr) << "Failed to receive fallback event";
7823 ASSERT_EQ(event->getType(), InputEventType::KEY);
7824 ASSERT_THAT(static_cast<const KeyEvent&>(*event),
7825 AllOf(WithKeyAction(ACTION_DOWN), WithKeyCode(AKEYCODE_B),
7826 WithFlags(AKEY_EVENT_FLAG_FALLBACK)));
7827
7828 // Remove the window now, which should generate a cancellations and make the window lose focus.
7829 mDispatcher->onWindowInfosChanged({{}, {}, 0, 0});
7830 consumeKey(/*handled=*/true,
7831 AllOf(WithKeyAction(ACTION_UP), WithKeyCode(AKEYCODE_A),
7832 WithFlags(AKEY_EVENT_FLAG_CANCELED)));
7833 consumeKey(/*handled=*/true,
7834 AllOf(WithKeyAction(ACTION_UP), WithKeyCode(AKEYCODE_B),
7835 WithFlags(AKEY_EVENT_FLAG_FALLBACK | AKEY_EVENT_FLAG_CANCELED)));
7836 mWindow->consumeFocusEvent(false);
7837
7838 // Finish the event by reporting it as handled.
7839 mWindow->finishEvent(*seq);
7840 mWindow->assertNoEvents();
7841}
7842
Garfield Tan1c7bc862020-01-28 13:24:04 -08007843class InputDispatcherKeyRepeatTest : public InputDispatcherTest {
7844protected:
Siarhei Vishniakoufa2a0492023-11-14 13:13:18 -08007845 static constexpr std::chrono::nanoseconds KEY_REPEAT_TIMEOUT = 40ms;
7846 static constexpr std::chrono::nanoseconds KEY_REPEAT_DELAY = 40ms;
Garfield Tan1c7bc862020-01-28 13:24:04 -08007847
Chris Yea209fde2020-07-22 13:54:51 -07007848 std::shared_ptr<FakeApplicationHandle> mApp;
Garfield Tan1c7bc862020-01-28 13:24:04 -08007849 sp<FakeWindowHandle> mWindow;
7850
7851 virtual void SetUp() override {
Prabir Pradhandae52792023-12-15 07:36:40 +00007852 InputDispatcherTest::SetUp();
Garfield Tan1c7bc862020-01-28 13:24:04 -08007853
Prabir Pradhandae52792023-12-15 07:36:40 +00007854 mDispatcher->setKeyRepeatConfiguration(KEY_REPEAT_TIMEOUT, KEY_REPEAT_DELAY);
Garfield Tan1c7bc862020-01-28 13:24:04 -08007855 setUpWindow();
7856 }
7857
7858 void setUpWindow() {
Chris Yea209fde2020-07-22 13:54:51 -07007859 mApp = std::make_shared<FakeApplicationHandle>();
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07007860 mWindow = sp<FakeWindowHandle>::make(mApp, mDispatcher, "Fake Window", ADISPLAY_ID_DEFAULT);
Garfield Tan1c7bc862020-01-28 13:24:04 -08007861
Vishnu Nair47074b82020-08-14 11:54:47 -07007862 mWindow->setFocusable(true);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07007863 mDispatcher->onWindowInfosChanged({{*mWindow->getInfo()}, {}, 0, 0});
Vishnu Nair958da932020-08-21 17:12:37 -07007864 setFocusedWindow(mWindow);
Garfield Tan1c7bc862020-01-28 13:24:04 -08007865 mWindow->consumeFocusEvent(true);
7866 }
7867
Chris Ye2ad95392020-09-01 13:44:44 -07007868 void sendAndConsumeKeyDown(int32_t deviceId) {
Garfield Tan1c7bc862020-01-28 13:24:04 -08007869 NotifyKeyArgs keyArgs = generateKeyArgs(AKEY_EVENT_ACTION_DOWN, ADISPLAY_ID_DEFAULT);
Chris Ye2ad95392020-09-01 13:44:44 -07007870 keyArgs.deviceId = deviceId;
Garfield Tan1c7bc862020-01-28 13:24:04 -08007871 keyArgs.policyFlags |= POLICY_FLAG_TRUSTED; // Otherwise it won't generate repeat event
Prabir Pradhan678438e2023-04-13 19:32:51 +00007872 mDispatcher->notifyKey(keyArgs);
Garfield Tan1c7bc862020-01-28 13:24:04 -08007873
7874 // Window should receive key down event.
7875 mWindow->consumeKeyDown(ADISPLAY_ID_DEFAULT);
7876 }
7877
7878 void expectKeyRepeatOnce(int32_t repeatCount) {
7879 SCOPED_TRACE(StringPrintf("Checking event with repeat count %" PRId32, repeatCount));
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07007880 mWindow->consumeKeyEvent(
7881 AllOf(WithKeyAction(AKEY_EVENT_ACTION_DOWN), WithRepeatCount(repeatCount)));
Garfield Tan1c7bc862020-01-28 13:24:04 -08007882 }
7883
Chris Ye2ad95392020-09-01 13:44:44 -07007884 void sendAndConsumeKeyUp(int32_t deviceId) {
Garfield Tan1c7bc862020-01-28 13:24:04 -08007885 NotifyKeyArgs keyArgs = generateKeyArgs(AKEY_EVENT_ACTION_UP, ADISPLAY_ID_DEFAULT);
Chris Ye2ad95392020-09-01 13:44:44 -07007886 keyArgs.deviceId = deviceId;
Garfield Tan1c7bc862020-01-28 13:24:04 -08007887 keyArgs.policyFlags |= POLICY_FLAG_TRUSTED; // Unless it won't generate repeat event
Prabir Pradhan678438e2023-04-13 19:32:51 +00007888 mDispatcher->notifyKey(keyArgs);
Garfield Tan1c7bc862020-01-28 13:24:04 -08007889
7890 // Window should receive key down event.
Prabir Pradhan7662a8d2023-12-15 01:58:14 +00007891 mWindow->consumeKeyUp(ADISPLAY_ID_DEFAULT,
Harry Cutts33476232023-01-30 19:57:29 +00007892 /*expectedFlags=*/0);
Garfield Tan1c7bc862020-01-28 13:24:04 -08007893 }
Hu Guofe3c8f12023-09-22 17:20:15 +08007894
7895 void injectKeyRepeat(int32_t repeatCount) {
7896 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
7897 injectKey(*mDispatcher, AKEY_EVENT_ACTION_DOWN, repeatCount, ADISPLAY_ID_DEFAULT))
7898 << "Inject key event should return InputEventInjectionResult::SUCCEEDED";
7899 }
Garfield Tan1c7bc862020-01-28 13:24:04 -08007900};
7901
7902TEST_F(InputDispatcherKeyRepeatTest, FocusedWindow_ReceivesKeyRepeat) {
Harry Cutts33476232023-01-30 19:57:29 +00007903 sendAndConsumeKeyDown(/*deviceId=*/1);
Chris Ye2ad95392020-09-01 13:44:44 -07007904 for (int32_t repeatCount = 1; repeatCount <= 10; ++repeatCount) {
7905 expectKeyRepeatOnce(repeatCount);
7906 }
7907}
7908
7909TEST_F(InputDispatcherKeyRepeatTest, FocusedWindow_ReceivesKeyRepeatFromTwoDevices) {
Harry Cutts33476232023-01-30 19:57:29 +00007910 sendAndConsumeKeyDown(/*deviceId=*/1);
Chris Ye2ad95392020-09-01 13:44:44 -07007911 for (int32_t repeatCount = 1; repeatCount <= 10; ++repeatCount) {
7912 expectKeyRepeatOnce(repeatCount);
7913 }
Harry Cutts33476232023-01-30 19:57:29 +00007914 sendAndConsumeKeyDown(/*deviceId=*/2);
Chris Ye2ad95392020-09-01 13:44:44 -07007915 /* repeatCount will start from 1 for deviceId 2 */
Garfield Tan1c7bc862020-01-28 13:24:04 -08007916 for (int32_t repeatCount = 1; repeatCount <= 10; ++repeatCount) {
7917 expectKeyRepeatOnce(repeatCount);
7918 }
7919}
7920
7921TEST_F(InputDispatcherKeyRepeatTest, FocusedWindow_StopsKeyRepeatAfterUp) {
Harry Cutts33476232023-01-30 19:57:29 +00007922 sendAndConsumeKeyDown(/*deviceId=*/1);
7923 expectKeyRepeatOnce(/*repeatCount=*/1);
7924 sendAndConsumeKeyUp(/*deviceId=*/1);
Chris Ye2ad95392020-09-01 13:44:44 -07007925 mWindow->assertNoEvents();
7926}
7927
7928TEST_F(InputDispatcherKeyRepeatTest, FocusedWindow_KeyRepeatAfterStaleDeviceKeyUp) {
Harry Cutts33476232023-01-30 19:57:29 +00007929 sendAndConsumeKeyDown(/*deviceId=*/1);
7930 expectKeyRepeatOnce(/*repeatCount=*/1);
7931 sendAndConsumeKeyDown(/*deviceId=*/2);
7932 expectKeyRepeatOnce(/*repeatCount=*/1);
Chris Ye2ad95392020-09-01 13:44:44 -07007933 // Stale key up from device 1.
Harry Cutts33476232023-01-30 19:57:29 +00007934 sendAndConsumeKeyUp(/*deviceId=*/1);
Chris Ye2ad95392020-09-01 13:44:44 -07007935 // Device 2 is still down, keep repeating
Harry Cutts33476232023-01-30 19:57:29 +00007936 expectKeyRepeatOnce(/*repeatCount=*/2);
7937 expectKeyRepeatOnce(/*repeatCount=*/3);
Chris Ye2ad95392020-09-01 13:44:44 -07007938 // Device 2 key up
Harry Cutts33476232023-01-30 19:57:29 +00007939 sendAndConsumeKeyUp(/*deviceId=*/2);
Chris Ye2ad95392020-09-01 13:44:44 -07007940 mWindow->assertNoEvents();
7941}
7942
7943TEST_F(InputDispatcherKeyRepeatTest, FocusedWindow_KeyRepeatStopsAfterRepeatingKeyUp) {
Harry Cutts33476232023-01-30 19:57:29 +00007944 sendAndConsumeKeyDown(/*deviceId=*/1);
7945 expectKeyRepeatOnce(/*repeatCount=*/1);
7946 sendAndConsumeKeyDown(/*deviceId=*/2);
7947 expectKeyRepeatOnce(/*repeatCount=*/1);
Chris Ye2ad95392020-09-01 13:44:44 -07007948 // Device 2 which holds the key repeating goes up, expect the repeating to stop.
Harry Cutts33476232023-01-30 19:57:29 +00007949 sendAndConsumeKeyUp(/*deviceId=*/2);
Chris Ye2ad95392020-09-01 13:44:44 -07007950 // Device 1 still holds key down, but the repeating was already stopped
Garfield Tan1c7bc862020-01-28 13:24:04 -08007951 mWindow->assertNoEvents();
7952}
7953
liushenxiang42232912021-05-21 20:24:09 +08007954TEST_F(InputDispatcherKeyRepeatTest, FocusedWindow_StopsKeyRepeatAfterDisableInputDevice) {
7955 sendAndConsumeKeyDown(DEVICE_ID);
Harry Cutts33476232023-01-30 19:57:29 +00007956 expectKeyRepeatOnce(/*repeatCount=*/1);
Prabir Pradhan678438e2023-04-13 19:32:51 +00007957 mDispatcher->notifyDeviceReset({/*id=*/10, /*eventTime=*/20, DEVICE_ID});
liushenxiang42232912021-05-21 20:24:09 +08007958 mWindow->consumeKeyUp(ADISPLAY_ID_DEFAULT,
7959 AKEY_EVENT_FLAG_CANCELED | AKEY_EVENT_FLAG_LONG_PRESS);
7960 mWindow->assertNoEvents();
7961}
7962
Garfield Tan1c7bc862020-01-28 13:24:04 -08007963TEST_F(InputDispatcherKeyRepeatTest, FocusedWindow_RepeatKeyEventsUseEventIdFromInputDispatcher) {
Michael Wrighte1cbbd62023-02-22 19:32:13 +00007964 GTEST_SKIP() << "Flaky test (b/270393106)";
Harry Cutts33476232023-01-30 19:57:29 +00007965 sendAndConsumeKeyDown(/*deviceId=*/1);
Garfield Tan1c7bc862020-01-28 13:24:04 -08007966 for (int32_t repeatCount = 1; repeatCount <= 10; ++repeatCount) {
Siarhei Vishniakoud3061ab2023-12-18 20:41:08 -08007967 std::unique_ptr<KeyEvent> repeatEvent = mWindow->consumeKey();
7968 ASSERT_NE(nullptr, repeatEvent);
Garfield Tan1c7bc862020-01-28 13:24:04 -08007969 EXPECT_EQ(IdGenerator::Source::INPUT_DISPATCHER,
Siarhei Vishniakoud3061ab2023-12-18 20:41:08 -08007970 IdGenerator::getSource(repeatEvent->getId()));
Garfield Tan1c7bc862020-01-28 13:24:04 -08007971 }
7972}
7973
7974TEST_F(InputDispatcherKeyRepeatTest, FocusedWindow_RepeatKeyEventsUseUniqueEventId) {
Michael Wrighte1cbbd62023-02-22 19:32:13 +00007975 GTEST_SKIP() << "Flaky test (b/270393106)";
Harry Cutts33476232023-01-30 19:57:29 +00007976 sendAndConsumeKeyDown(/*deviceId=*/1);
Garfield Tan1c7bc862020-01-28 13:24:04 -08007977
7978 std::unordered_set<int32_t> idSet;
7979 for (int32_t repeatCount = 1; repeatCount <= 10; ++repeatCount) {
Siarhei Vishniakoud3061ab2023-12-18 20:41:08 -08007980 std::unique_ptr<KeyEvent> repeatEvent = mWindow->consumeKey();
7981 ASSERT_NE(nullptr, repeatEvent);
7982 int32_t id = repeatEvent->getId();
Garfield Tan1c7bc862020-01-28 13:24:04 -08007983 EXPECT_EQ(idSet.end(), idSet.find(id));
7984 idSet.insert(id);
7985 }
7986}
7987
Hu Guofe3c8f12023-09-22 17:20:15 +08007988TEST_F(InputDispatcherKeyRepeatTest, FocusedWindow_CorrectRepeatCountWhenInjectKeyRepeat) {
7989 injectKeyRepeat(0);
7990 mWindow->consumeKeyDown(ADISPLAY_ID_DEFAULT);
7991 for (int32_t repeatCount = 1; repeatCount <= 2; ++repeatCount) {
7992 expectKeyRepeatOnce(repeatCount);
7993 }
7994 injectKeyRepeat(1);
7995 // Expect repeatCount to be 3 instead of 1
7996 expectKeyRepeatOnce(3);
7997}
7998
Arthur Hung2fbf37f2018-09-13 18:16:41 +08007999/* Test InputDispatcher for MultiDisplay */
8000class InputDispatcherFocusOnTwoDisplaysTest : public InputDispatcherTest {
8001public:
Prabir Pradhan3608aad2019-10-02 17:08:26 -07008002 virtual void SetUp() override {
Arthur Hung2fbf37f2018-09-13 18:16:41 +08008003 InputDispatcherTest::SetUp();
Arthur Hungb92218b2018-08-14 12:00:21 +08008004
Chris Yea209fde2020-07-22 13:54:51 -07008005 application1 = std::make_shared<FakeApplicationHandle>();
Siarhei Vishniakou870ecec2020-12-09 08:07:46 -10008006 windowInPrimary =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07008007 sp<FakeWindowHandle>::make(application1, mDispatcher, "D_1", ADISPLAY_ID_DEFAULT);
Siarhei Vishniakoub9b15352019-11-26 13:19:26 -08008008
Arthur Hung2fbf37f2018-09-13 18:16:41 +08008009 // Set focus window for primary display, but focused display would be second one.
8010 mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application1);
Vishnu Nair47074b82020-08-14 11:54:47 -07008011 windowInPrimary->setFocusable(true);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07008012 mDispatcher->onWindowInfosChanged({{*windowInPrimary->getInfo()}, {}, 0, 0});
8013
Vishnu Nair958da932020-08-21 17:12:37 -07008014 setFocusedWindow(windowInPrimary);
Siarhei Vishniakouf1035d42019-09-20 16:32:01 +01008015 windowInPrimary->consumeFocusEvent(true);
Arthur Hungb92218b2018-08-14 12:00:21 +08008016
Chris Yea209fde2020-07-22 13:54:51 -07008017 application2 = std::make_shared<FakeApplicationHandle>();
Siarhei Vishniakou870ecec2020-12-09 08:07:46 -10008018 windowInSecondary =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07008019 sp<FakeWindowHandle>::make(application2, mDispatcher, "D_2", SECOND_DISPLAY_ID);
Arthur Hung2fbf37f2018-09-13 18:16:41 +08008020 // Set focus to second display window.
Arthur Hung2fbf37f2018-09-13 18:16:41 +08008021 // Set focus display to second one.
8022 mDispatcher->setFocusedDisplay(SECOND_DISPLAY_ID);
8023 // Set focus window for second display.
8024 mDispatcher->setFocusedApplication(SECOND_DISPLAY_ID, application2);
Vishnu Nair47074b82020-08-14 11:54:47 -07008025 windowInSecondary->setFocusable(true);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07008026 mDispatcher->onWindowInfosChanged(
8027 {{*windowInPrimary->getInfo(), *windowInSecondary->getInfo()}, {}, 0, 0});
Vishnu Nair958da932020-08-21 17:12:37 -07008028 setFocusedWindow(windowInSecondary);
Siarhei Vishniakouf1035d42019-09-20 16:32:01 +01008029 windowInSecondary->consumeFocusEvent(true);
Arthur Hung2fbf37f2018-09-13 18:16:41 +08008030 }
8031
Prabir Pradhan3608aad2019-10-02 17:08:26 -07008032 virtual void TearDown() override {
Arthur Hung2fbf37f2018-09-13 18:16:41 +08008033 InputDispatcherTest::TearDown();
8034
Chris Yea209fde2020-07-22 13:54:51 -07008035 application1.reset();
Arthur Hung2fbf37f2018-09-13 18:16:41 +08008036 windowInPrimary.clear();
Chris Yea209fde2020-07-22 13:54:51 -07008037 application2.reset();
Arthur Hung2fbf37f2018-09-13 18:16:41 +08008038 windowInSecondary.clear();
8039 }
8040
8041protected:
Chris Yea209fde2020-07-22 13:54:51 -07008042 std::shared_ptr<FakeApplicationHandle> application1;
Arthur Hung2fbf37f2018-09-13 18:16:41 +08008043 sp<FakeWindowHandle> windowInPrimary;
Chris Yea209fde2020-07-22 13:54:51 -07008044 std::shared_ptr<FakeApplicationHandle> application2;
Arthur Hung2fbf37f2018-09-13 18:16:41 +08008045 sp<FakeWindowHandle> windowInSecondary;
8046};
8047
8048TEST_F(InputDispatcherFocusOnTwoDisplaysTest, SetInputWindow_MultiDisplayTouch) {
8049 // Test touch down on primary display.
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08008050 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07008051 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT))
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08008052 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
Siarhei Vishniakouc5ca85c2019-11-15 17:20:00 -08008053 windowInPrimary->consumeMotionDown(ADISPLAY_ID_DEFAULT);
Arthur Hungb92218b2018-08-14 12:00:21 +08008054 windowInSecondary->assertNoEvents();
8055
Arthur Hung2fbf37f2018-09-13 18:16:41 +08008056 // Test touch down on second display.
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08008057 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07008058 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, SECOND_DISPLAY_ID))
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08008059 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
Arthur Hungb92218b2018-08-14 12:00:21 +08008060 windowInPrimary->assertNoEvents();
Siarhei Vishniakouc5ca85c2019-11-15 17:20:00 -08008061 windowInSecondary->consumeMotionDown(SECOND_DISPLAY_ID);
Arthur Hungb92218b2018-08-14 12:00:21 +08008062}
8063
Arthur Hung2fbf37f2018-09-13 18:16:41 +08008064TEST_F(InputDispatcherFocusOnTwoDisplaysTest, SetInputWindow_MultiDisplayFocus) {
Tiger Huang721e26f2018-07-24 22:26:19 +08008065 // Test inject a key down with display id specified.
Prabir Pradhan93f342c2021-03-11 15:05:30 -08008066 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07008067 injectKeyDownNoRepeat(*mDispatcher, ADISPLAY_ID_DEFAULT))
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08008068 << "Inject key event should return InputEventInjectionResult::SUCCEEDED";
Siarhei Vishniakouc5ca85c2019-11-15 17:20:00 -08008069 windowInPrimary->consumeKeyDown(ADISPLAY_ID_DEFAULT);
Tiger Huang721e26f2018-07-24 22:26:19 +08008070 windowInSecondary->assertNoEvents();
8071
8072 // Test inject a key down without display id specified.
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07008073 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectKeyDownNoRepeat(*mDispatcher))
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08008074 << "Inject key event should return InputEventInjectionResult::SUCCEEDED";
Arthur Hungb92218b2018-08-14 12:00:21 +08008075 windowInPrimary->assertNoEvents();
Siarhei Vishniakouc5ca85c2019-11-15 17:20:00 -08008076 windowInSecondary->consumeKeyDown(ADISPLAY_ID_NONE);
Arthur Hungb92218b2018-08-14 12:00:21 +08008077
Siarhei Vishniakoub9b15352019-11-26 13:19:26 -08008078 // Remove all windows in secondary display.
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07008079 mDispatcher->onWindowInfosChanged({{*windowInPrimary->getInfo()}, {}, 0, 0});
Arthur Hungb92218b2018-08-14 12:00:21 +08008080
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08008081 // Old focus should receive a cancel event.
Prabir Pradhan7662a8d2023-12-15 01:58:14 +00008082 windowInSecondary->consumeKeyUp(ADISPLAY_ID_NONE, AKEY_EVENT_FLAG_CANCELED);
Arthur Hungb92218b2018-08-14 12:00:21 +08008083
8084 // Test inject a key down, should timeout because of no target window.
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07008085 ASSERT_NO_FATAL_FAILURE(assertInjectedKeyTimesOut(*mDispatcher));
Arthur Hungb92218b2018-08-14 12:00:21 +08008086 windowInPrimary->assertNoEvents();
Siarhei Vishniakouf1035d42019-09-20 16:32:01 +01008087 windowInSecondary->consumeFocusEvent(false);
Arthur Hungb92218b2018-08-14 12:00:21 +08008088 windowInSecondary->assertNoEvents();
8089}
8090
Arthur Hung2fbf37f2018-09-13 18:16:41 +08008091// Test per-display input monitors for motion event.
8092TEST_F(InputDispatcherFocusOnTwoDisplaysTest, MonitorMotionEvent_MultiDisplay) {
chaviwd1c23182019-12-20 18:44:56 -08008093 FakeMonitorReceiver monitorInPrimary =
Prabir Pradhanfb549072023-10-05 19:17:36 +00008094 FakeMonitorReceiver(*mDispatcher, "M_1", ADISPLAY_ID_DEFAULT);
chaviwd1c23182019-12-20 18:44:56 -08008095 FakeMonitorReceiver monitorInSecondary =
Prabir Pradhanfb549072023-10-05 19:17:36 +00008096 FakeMonitorReceiver(*mDispatcher, "M_2", SECOND_DISPLAY_ID);
Arthur Hung2fbf37f2018-09-13 18:16:41 +08008097
8098 // Test touch down on primary display.
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08008099 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07008100 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT))
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08008101 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
Siarhei Vishniakouc5ca85c2019-11-15 17:20:00 -08008102 windowInPrimary->consumeMotionDown(ADISPLAY_ID_DEFAULT);
chaviwd1c23182019-12-20 18:44:56 -08008103 monitorInPrimary.consumeMotionDown(ADISPLAY_ID_DEFAULT);
Arthur Hung2fbf37f2018-09-13 18:16:41 +08008104 windowInSecondary->assertNoEvents();
chaviwd1c23182019-12-20 18:44:56 -08008105 monitorInSecondary.assertNoEvents();
Arthur Hung2fbf37f2018-09-13 18:16:41 +08008106
8107 // Test touch down on second display.
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08008108 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07008109 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, SECOND_DISPLAY_ID))
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08008110 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
Arthur Hung2fbf37f2018-09-13 18:16:41 +08008111 windowInPrimary->assertNoEvents();
chaviwd1c23182019-12-20 18:44:56 -08008112 monitorInPrimary.assertNoEvents();
Siarhei Vishniakouc5ca85c2019-11-15 17:20:00 -08008113 windowInSecondary->consumeMotionDown(SECOND_DISPLAY_ID);
chaviwd1c23182019-12-20 18:44:56 -08008114 monitorInSecondary.consumeMotionDown(SECOND_DISPLAY_ID);
Arthur Hung2fbf37f2018-09-13 18:16:41 +08008115
Siarhei Vishniakou92c8fd52023-01-29 14:57:43 -08008116 // Lift up the touch from the second display
8117 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07008118 injectMotionUp(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, SECOND_DISPLAY_ID))
Siarhei Vishniakou92c8fd52023-01-29 14:57:43 -08008119 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
8120 windowInSecondary->consumeMotionUp(SECOND_DISPLAY_ID);
8121 monitorInSecondary.consumeMotionUp(SECOND_DISPLAY_ID);
8122
Arthur Hung2fbf37f2018-09-13 18:16:41 +08008123 // Test inject a non-pointer motion event.
8124 // If specific a display, it will dispatch to the focused window of particular display,
8125 // or it will dispatch to the focused window of focused display.
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08008126 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07008127 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TRACKBALL, ADISPLAY_ID_NONE))
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08008128 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
Arthur Hung2fbf37f2018-09-13 18:16:41 +08008129 windowInPrimary->assertNoEvents();
chaviwd1c23182019-12-20 18:44:56 -08008130 monitorInPrimary.assertNoEvents();
Siarhei Vishniakouc5ca85c2019-11-15 17:20:00 -08008131 windowInSecondary->consumeMotionDown(ADISPLAY_ID_NONE);
chaviwd1c23182019-12-20 18:44:56 -08008132 monitorInSecondary.consumeMotionDown(ADISPLAY_ID_NONE);
Arthur Hung2fbf37f2018-09-13 18:16:41 +08008133}
8134
8135// Test per-display input monitors for key event.
8136TEST_F(InputDispatcherFocusOnTwoDisplaysTest, MonitorKeyEvent_MultiDisplay) {
Siarhei Vishniakou870ecec2020-12-09 08:07:46 -10008137 // Input monitor per display.
chaviwd1c23182019-12-20 18:44:56 -08008138 FakeMonitorReceiver monitorInPrimary =
Prabir Pradhanfb549072023-10-05 19:17:36 +00008139 FakeMonitorReceiver(*mDispatcher, "M_1", ADISPLAY_ID_DEFAULT);
chaviwd1c23182019-12-20 18:44:56 -08008140 FakeMonitorReceiver monitorInSecondary =
Prabir Pradhanfb549072023-10-05 19:17:36 +00008141 FakeMonitorReceiver(*mDispatcher, "M_2", SECOND_DISPLAY_ID);
Arthur Hung2fbf37f2018-09-13 18:16:41 +08008142
8143 // Test inject a key down.
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07008144 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectKeyDown(*mDispatcher))
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08008145 << "Inject key event should return InputEventInjectionResult::SUCCEEDED";
Arthur Hung2fbf37f2018-09-13 18:16:41 +08008146 windowInPrimary->assertNoEvents();
chaviwd1c23182019-12-20 18:44:56 -08008147 monitorInPrimary.assertNoEvents();
Siarhei Vishniakouc5ca85c2019-11-15 17:20:00 -08008148 windowInSecondary->consumeKeyDown(ADISPLAY_ID_NONE);
chaviwd1c23182019-12-20 18:44:56 -08008149 monitorInSecondary.consumeKeyDown(ADISPLAY_ID_NONE);
Arthur Hung2fbf37f2018-09-13 18:16:41 +08008150}
8151
Vishnu Nair958da932020-08-21 17:12:37 -07008152TEST_F(InputDispatcherFocusOnTwoDisplaysTest, CanFocusWindowOnUnfocusedDisplay) {
8153 sp<FakeWindowHandle> secondWindowInPrimary =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07008154 sp<FakeWindowHandle>::make(application1, mDispatcher, "D_1_W2", ADISPLAY_ID_DEFAULT);
Vishnu Nair958da932020-08-21 17:12:37 -07008155 secondWindowInPrimary->setFocusable(true);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07008156 mDispatcher->onWindowInfosChanged(
8157 {{*windowInPrimary->getInfo(), *secondWindowInPrimary->getInfo(),
8158 *windowInSecondary->getInfo()},
8159 {},
8160 0,
8161 0});
Vishnu Nair958da932020-08-21 17:12:37 -07008162 setFocusedWindow(secondWindowInPrimary);
8163 windowInPrimary->consumeFocusEvent(false);
8164 secondWindowInPrimary->consumeFocusEvent(true);
8165
8166 // Test inject a key down.
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07008167 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
8168 injectKeyDown(*mDispatcher, ADISPLAY_ID_DEFAULT))
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08008169 << "Inject key event should return InputEventInjectionResult::SUCCEEDED";
Vishnu Nair958da932020-08-21 17:12:37 -07008170 windowInPrimary->assertNoEvents();
8171 windowInSecondary->assertNoEvents();
8172 secondWindowInPrimary->consumeKeyDown(ADISPLAY_ID_DEFAULT);
8173}
8174
Arthur Hungdfd528e2021-12-08 13:23:04 +00008175TEST_F(InputDispatcherFocusOnTwoDisplaysTest, CancelTouch_MultiDisplay) {
8176 FakeMonitorReceiver monitorInPrimary =
Prabir Pradhanfb549072023-10-05 19:17:36 +00008177 FakeMonitorReceiver(*mDispatcher, "M_1", ADISPLAY_ID_DEFAULT);
Arthur Hungdfd528e2021-12-08 13:23:04 +00008178 FakeMonitorReceiver monitorInSecondary =
Prabir Pradhanfb549072023-10-05 19:17:36 +00008179 FakeMonitorReceiver(*mDispatcher, "M_2", SECOND_DISPLAY_ID);
Arthur Hungdfd528e2021-12-08 13:23:04 +00008180
8181 // Test touch down on primary display.
8182 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07008183 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT))
Arthur Hungdfd528e2021-12-08 13:23:04 +00008184 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
8185 windowInPrimary->consumeMotionDown(ADISPLAY_ID_DEFAULT);
8186 monitorInPrimary.consumeMotionDown(ADISPLAY_ID_DEFAULT);
8187
8188 // Test touch down on second display.
8189 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07008190 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, SECOND_DISPLAY_ID))
Arthur Hungdfd528e2021-12-08 13:23:04 +00008191 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
8192 windowInSecondary->consumeMotionDown(SECOND_DISPLAY_ID);
8193 monitorInSecondary.consumeMotionDown(SECOND_DISPLAY_ID);
8194
8195 // Trigger cancel touch.
8196 mDispatcher->cancelCurrentTouch();
8197 windowInPrimary->consumeMotionCancel(ADISPLAY_ID_DEFAULT);
8198 monitorInPrimary.consumeMotionCancel(ADISPLAY_ID_DEFAULT);
8199 windowInSecondary->consumeMotionCancel(SECOND_DISPLAY_ID);
8200 monitorInSecondary.consumeMotionCancel(SECOND_DISPLAY_ID);
8201
8202 // Test inject a move motion event, no window/monitor should receive the event.
8203 ASSERT_EQ(InputEventInjectionResult::FAILED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07008204 injectMotionEvent(*mDispatcher, AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN,
Arthur Hungdfd528e2021-12-08 13:23:04 +00008205 ADISPLAY_ID_DEFAULT, {110, 200}))
8206 << "Inject motion event should return InputEventInjectionResult::FAILED";
8207 windowInPrimary->assertNoEvents();
8208 monitorInPrimary.assertNoEvents();
8209
8210 ASSERT_EQ(InputEventInjectionResult::FAILED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07008211 injectMotionEvent(*mDispatcher, AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN,
Arthur Hungdfd528e2021-12-08 13:23:04 +00008212 SECOND_DISPLAY_ID, {110, 200}))
8213 << "Inject motion event should return InputEventInjectionResult::FAILED";
8214 windowInSecondary->assertNoEvents();
8215 monitorInSecondary.assertNoEvents();
8216}
8217
Hu Guocb134f12023-12-23 13:42:44 +00008218/**
8219 * Send a key to the primary display and to the secondary display.
8220 * Then cause the key on the primary display to be canceled by sending in a stale key.
8221 * Ensure that the key on the primary display is canceled, and that the key on the secondary display
8222 * does not get canceled.
8223 */
8224TEST_F(InputDispatcherFocusOnTwoDisplaysTest, WhenDropKeyEvent_OnlyCancelCorrespondingKeyGesture) {
8225 // Send a key down on primary display
8226 mDispatcher->notifyKey(
8227 KeyArgsBuilder(AKEY_EVENT_ACTION_DOWN, AINPUT_SOURCE_KEYBOARD)
8228 .displayId(ADISPLAY_ID_DEFAULT)
8229 .policyFlags(DEFAULT_POLICY_FLAGS | POLICY_FLAG_DISABLE_KEY_REPEAT)
8230 .build());
8231 windowInPrimary->consumeKeyEvent(
8232 AllOf(WithKeyAction(AKEY_EVENT_ACTION_DOWN), WithDisplayId(ADISPLAY_ID_DEFAULT)));
8233 windowInSecondary->assertNoEvents();
8234
8235 // Send a key down on second display
8236 mDispatcher->notifyKey(
8237 KeyArgsBuilder(AKEY_EVENT_ACTION_DOWN, AINPUT_SOURCE_KEYBOARD)
8238 .displayId(SECOND_DISPLAY_ID)
8239 .policyFlags(DEFAULT_POLICY_FLAGS | POLICY_FLAG_DISABLE_KEY_REPEAT)
8240 .build());
8241 windowInSecondary->consumeKeyEvent(
8242 AllOf(WithKeyAction(AKEY_EVENT_ACTION_DOWN), WithDisplayId(SECOND_DISPLAY_ID)));
8243 windowInPrimary->assertNoEvents();
8244
8245 // Send a valid key up event on primary display that will be dropped because it is stale
8246 NotifyKeyArgs staleKeyUp =
8247 KeyArgsBuilder(AKEY_EVENT_ACTION_UP, AINPUT_SOURCE_KEYBOARD)
8248 .displayId(ADISPLAY_ID_DEFAULT)
8249 .policyFlags(DEFAULT_POLICY_FLAGS | POLICY_FLAG_DISABLE_KEY_REPEAT)
8250 .build();
8251 static constexpr std::chrono::duration STALE_EVENT_TIMEOUT = 10ms;
8252 mFakePolicy->setStaleEventTimeout(STALE_EVENT_TIMEOUT);
8253 std::this_thread::sleep_for(STALE_EVENT_TIMEOUT);
8254 mDispatcher->notifyKey(staleKeyUp);
8255
8256 // Only the key gesture corresponding to the dropped event should receive the cancel event.
8257 // Therefore, windowInPrimary should get the cancel event and windowInSecondary should not
8258 // receive any events.
8259 windowInPrimary->consumeKeyEvent(AllOf(WithKeyAction(AKEY_EVENT_ACTION_UP),
8260 WithDisplayId(ADISPLAY_ID_DEFAULT),
8261 WithFlags(AKEY_EVENT_FLAG_CANCELED)));
8262 windowInSecondary->assertNoEvents();
8263}
8264
8265/**
8266 * Similar to 'WhenDropKeyEvent_OnlyCancelCorrespondingKeyGesture' but for motion events.
8267 */
8268TEST_F(InputDispatcherFocusOnTwoDisplaysTest, WhenDropMotionEvent_OnlyCancelCorrespondingGesture) {
8269 // Send touch down on primary display.
8270 mDispatcher->notifyMotion(
8271 MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
8272 .pointer(PointerBuilder(/*id=*/0, ToolType::FINGER).x(100).y(200))
8273 .displayId(ADISPLAY_ID_DEFAULT)
8274 .build());
8275 windowInPrimary->consumeMotionEvent(
8276 AllOf(WithMotionAction(ACTION_DOWN), WithDisplayId(ADISPLAY_ID_DEFAULT)));
8277 windowInSecondary->assertNoEvents();
8278
8279 // Send touch down on second display.
8280 mDispatcher->notifyMotion(
8281 MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
8282 .pointer(PointerBuilder(/*id=*/0, ToolType::FINGER).x(100).y(200))
8283 .displayId(SECOND_DISPLAY_ID)
8284 .build());
8285 windowInPrimary->assertNoEvents();
8286 windowInSecondary->consumeMotionEvent(
8287 AllOf(WithMotionAction(ACTION_DOWN), WithDisplayId(SECOND_DISPLAY_ID)));
8288
8289 // inject a valid MotionEvent on primary display that will be stale when it arrives.
8290 NotifyMotionArgs staleMotionUp =
8291 MotionArgsBuilder(ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN)
8292 .displayId(ADISPLAY_ID_DEFAULT)
8293 .pointer(PointerBuilder(/*id=*/0, ToolType::FINGER).x(100).y(200))
8294 .build();
8295 static constexpr std::chrono::duration STALE_EVENT_TIMEOUT = 10ms;
8296 mFakePolicy->setStaleEventTimeout(STALE_EVENT_TIMEOUT);
8297 std::this_thread::sleep_for(STALE_EVENT_TIMEOUT);
8298 mDispatcher->notifyMotion(staleMotionUp);
8299
8300 // For stale motion events, we let the gesture to complete. This behaviour is different from key
8301 // events, where we would cancel the current keys instead.
8302 windowInPrimary->consumeMotionEvent(WithMotionAction(ACTION_UP));
8303 windowInSecondary->assertNoEvents();
8304}
8305
Jackal Guof9696682018-10-05 12:23:23 +08008306class InputFilterTest : public InputDispatcherTest {
8307protected:
Prabir Pradhan81420cc2021-09-06 10:28:50 -07008308 void testNotifyMotion(int32_t displayId, bool expectToBeFiltered,
8309 const ui::Transform& transform = ui::Transform()) {
Jackal Guof9696682018-10-05 12:23:23 +08008310 NotifyMotionArgs motionArgs;
8311
Siarhei Vishniakou870ecec2020-12-09 08:07:46 -10008312 motionArgs =
8313 generateMotionArgs(AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN, displayId);
Prabir Pradhan678438e2023-04-13 19:32:51 +00008314 mDispatcher->notifyMotion(motionArgs);
Siarhei Vishniakou870ecec2020-12-09 08:07:46 -10008315 motionArgs =
8316 generateMotionArgs(AMOTION_EVENT_ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN, displayId);
Prabir Pradhan678438e2023-04-13 19:32:51 +00008317 mDispatcher->notifyMotion(motionArgs);
Siarhei Vishniakou2bfa9052019-11-21 18:10:54 -08008318 ASSERT_TRUE(mDispatcher->waitForIdle());
Jackal Guof9696682018-10-05 12:23:23 +08008319 if (expectToBeFiltered) {
Siarhei Vishniakou3218fc02023-06-15 20:41:02 -07008320 const auto xy = transform.transform(motionArgs.pointerCoords[0].getXYValue());
Prabir Pradhan81420cc2021-09-06 10:28:50 -07008321 mFakePolicy->assertFilterInputEventWasCalled(motionArgs, xy);
Jackal Guof9696682018-10-05 12:23:23 +08008322 } else {
8323 mFakePolicy->assertFilterInputEventWasNotCalled();
8324 }
8325 }
8326
8327 void testNotifyKey(bool expectToBeFiltered) {
8328 NotifyKeyArgs keyArgs;
8329
8330 keyArgs = generateKeyArgs(AKEY_EVENT_ACTION_DOWN);
Prabir Pradhan678438e2023-04-13 19:32:51 +00008331 mDispatcher->notifyKey(keyArgs);
Jackal Guof9696682018-10-05 12:23:23 +08008332 keyArgs = generateKeyArgs(AKEY_EVENT_ACTION_UP);
Prabir Pradhan678438e2023-04-13 19:32:51 +00008333 mDispatcher->notifyKey(keyArgs);
Siarhei Vishniakou2bfa9052019-11-21 18:10:54 -08008334 ASSERT_TRUE(mDispatcher->waitForIdle());
Jackal Guof9696682018-10-05 12:23:23 +08008335
8336 if (expectToBeFiltered) {
Siarhei Vishniakou8935a802019-11-15 16:41:44 -08008337 mFakePolicy->assertFilterInputEventWasCalled(keyArgs);
Jackal Guof9696682018-10-05 12:23:23 +08008338 } else {
8339 mFakePolicy->assertFilterInputEventWasNotCalled();
8340 }
8341 }
8342};
8343
8344// Test InputFilter for MotionEvent
8345TEST_F(InputFilterTest, MotionEvent_InputFilter) {
8346 // Since the InputFilter is disabled by default, check if touch events aren't filtered.
Harry Cutts101ee9b2023-07-06 18:04:14 +00008347 testNotifyMotion(ADISPLAY_ID_DEFAULT, /*expectToBeFiltered=*/false);
8348 testNotifyMotion(SECOND_DISPLAY_ID, /*expectToBeFiltered=*/false);
Jackal Guof9696682018-10-05 12:23:23 +08008349
8350 // Enable InputFilter
8351 mDispatcher->setInputFilterEnabled(true);
8352 // Test touch on both primary and second display, and check if both events are filtered.
Harry Cutts101ee9b2023-07-06 18:04:14 +00008353 testNotifyMotion(ADISPLAY_ID_DEFAULT, /*expectToBeFiltered=*/true);
8354 testNotifyMotion(SECOND_DISPLAY_ID, /*expectToBeFiltered=*/true);
Jackal Guof9696682018-10-05 12:23:23 +08008355
8356 // Disable InputFilter
8357 mDispatcher->setInputFilterEnabled(false);
8358 // Test touch on both primary and second display, and check if both events aren't filtered.
Harry Cutts101ee9b2023-07-06 18:04:14 +00008359 testNotifyMotion(ADISPLAY_ID_DEFAULT, /*expectToBeFiltered=*/false);
8360 testNotifyMotion(SECOND_DISPLAY_ID, /*expectToBeFiltered=*/false);
Jackal Guof9696682018-10-05 12:23:23 +08008361}
8362
8363// Test InputFilter for KeyEvent
8364TEST_F(InputFilterTest, KeyEvent_InputFilter) {
8365 // Since the InputFilter is disabled by default, check if key event aren't filtered.
Harry Cutts101ee9b2023-07-06 18:04:14 +00008366 testNotifyKey(/*expectToBeFiltered=*/false);
Jackal Guof9696682018-10-05 12:23:23 +08008367
8368 // Enable InputFilter
8369 mDispatcher->setInputFilterEnabled(true);
8370 // Send a key event, and check if it is filtered.
Harry Cutts101ee9b2023-07-06 18:04:14 +00008371 testNotifyKey(/*expectToBeFiltered=*/true);
Jackal Guof9696682018-10-05 12:23:23 +08008372
8373 // Disable InputFilter
8374 mDispatcher->setInputFilterEnabled(false);
8375 // Send a key event, and check if it isn't filtered.
Harry Cutts101ee9b2023-07-06 18:04:14 +00008376 testNotifyKey(/*expectToBeFiltered=*/false);
Jackal Guof9696682018-10-05 12:23:23 +08008377}
8378
Prabir Pradhan81420cc2021-09-06 10:28:50 -07008379// Ensure that MotionEvents sent to the InputFilter through InputListener are converted to the
8380// logical display coordinate space.
8381TEST_F(InputFilterTest, MotionEvent_UsesLogicalDisplayCoordinates_notifyMotion) {
8382 ui::Transform firstDisplayTransform;
8383 firstDisplayTransform.set({1.1, 2.2, 3.3, 4.4, 5.5, 6.6, 0, 0, 1});
8384 ui::Transform secondDisplayTransform;
8385 secondDisplayTransform.set({-6.6, -5.5, -4.4, -3.3, -2.2, -1.1, 0, 0, 1});
8386
8387 std::vector<gui::DisplayInfo> displayInfos(2);
8388 displayInfos[0].displayId = ADISPLAY_ID_DEFAULT;
8389 displayInfos[0].transform = firstDisplayTransform;
8390 displayInfos[1].displayId = SECOND_DISPLAY_ID;
8391 displayInfos[1].transform = secondDisplayTransform;
8392
Patrick Williamsd828f302023-04-28 17:52:08 -05008393 mDispatcher->onWindowInfosChanged({{}, displayInfos, 0, 0});
Prabir Pradhan81420cc2021-09-06 10:28:50 -07008394
8395 // Enable InputFilter
8396 mDispatcher->setInputFilterEnabled(true);
8397
8398 // Ensure the correct transforms are used for the displays.
Harry Cutts101ee9b2023-07-06 18:04:14 +00008399 testNotifyMotion(ADISPLAY_ID_DEFAULT, /*expectToBeFiltered=*/true, firstDisplayTransform);
8400 testNotifyMotion(SECOND_DISPLAY_ID, /*expectToBeFiltered=*/true, secondDisplayTransform);
Prabir Pradhan81420cc2021-09-06 10:28:50 -07008401}
8402
Siarhei Vishniakou5d552c42021-05-21 05:02:22 +00008403class InputFilterInjectionPolicyTest : public InputDispatcherTest {
8404protected:
8405 virtual void SetUp() override {
8406 InputDispatcherTest::SetUp();
8407
8408 /**
8409 * We don't need to enable input filter to test the injected event policy, but we enabled it
8410 * here to make the tests more realistic, since this policy only matters when inputfilter is
8411 * on.
8412 */
8413 mDispatcher->setInputFilterEnabled(true);
8414
8415 std::shared_ptr<InputApplicationHandle> application =
8416 std::make_shared<FakeApplicationHandle>();
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07008417 mWindow = sp<FakeWindowHandle>::make(application, mDispatcher, "Test Window",
8418 ADISPLAY_ID_DEFAULT);
Siarhei Vishniakou5d552c42021-05-21 05:02:22 +00008419
8420 mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application);
8421 mWindow->setFocusable(true);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07008422 mDispatcher->onWindowInfosChanged({{*mWindow->getInfo()}, {}, 0, 0});
Siarhei Vishniakou5d552c42021-05-21 05:02:22 +00008423 setFocusedWindow(mWindow);
8424 mWindow->consumeFocusEvent(true);
8425 }
8426
Siarhei Vishniakouf00a4ec2021-06-16 03:55:32 +00008427 void testInjectedKey(int32_t policyFlags, int32_t injectedDeviceId, int32_t resolvedDeviceId,
8428 int32_t flags) {
Siarhei Vishniakou5d552c42021-05-21 05:02:22 +00008429 KeyEvent event;
8430
8431 const nsecs_t eventTime = systemTime(SYSTEM_TIME_MONOTONIC);
8432 event.initialize(InputEvent::nextId(), injectedDeviceId, AINPUT_SOURCE_KEYBOARD,
8433 ADISPLAY_ID_NONE, INVALID_HMAC, AKEY_EVENT_ACTION_DOWN, 0, AKEYCODE_A,
Harry Cutts33476232023-01-30 19:57:29 +00008434 KEY_A, AMETA_NONE, /*repeatCount=*/0, eventTime, eventTime);
Siarhei Vishniakou5d552c42021-05-21 05:02:22 +00008435 const int32_t additionalPolicyFlags =
8436 POLICY_FLAG_PASS_TO_USER | POLICY_FLAG_DISABLE_KEY_REPEAT;
8437 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Harry Cutts33476232023-01-30 19:57:29 +00008438 mDispatcher->injectInputEvent(&event, /*targetUid=*/{},
Siarhei Vishniakou4648fea2023-06-27 01:00:12 +00008439 InputEventInjectionSync::WAIT_FOR_RESULT, 100ms,
Siarhei Vishniakou5d552c42021-05-21 05:02:22 +00008440 policyFlags | additionalPolicyFlags));
8441
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07008442 mWindow->consumeKeyEvent(AllOf(WithDeviceId(resolvedDeviceId), WithFlags(flags)));
Siarhei Vishniakouf00a4ec2021-06-16 03:55:32 +00008443 }
8444
8445 void testInjectedMotion(int32_t policyFlags, int32_t injectedDeviceId, int32_t resolvedDeviceId,
8446 int32_t flags) {
8447 MotionEvent event;
8448 PointerProperties pointerProperties[1];
8449 PointerCoords pointerCoords[1];
8450 pointerProperties[0].clear();
8451 pointerProperties[0].id = 0;
8452 pointerCoords[0].clear();
8453 pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_X, 300);
8454 pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_Y, 400);
8455
8456 ui::Transform identityTransform;
8457 const nsecs_t eventTime = systemTime(SYSTEM_TIME_MONOTONIC);
8458 event.initialize(InputEvent::nextId(), injectedDeviceId, AINPUT_SOURCE_TOUCHSCREEN,
8459 DISPLAY_ID, INVALID_HMAC, AMOTION_EVENT_ACTION_DOWN, 0, 0,
8460 AMOTION_EVENT_EDGE_FLAG_NONE, AMETA_NONE, 0, MotionClassification::NONE,
8461 identityTransform, 0, 0, AMOTION_EVENT_INVALID_CURSOR_POSITION,
Prabir Pradhanb9b18502021-08-26 12:30:32 -07008462 AMOTION_EVENT_INVALID_CURSOR_POSITION, identityTransform, eventTime,
Evan Rosky09576692021-07-01 12:22:09 -07008463 eventTime,
Harry Cutts101ee9b2023-07-06 18:04:14 +00008464 /*pointerCount=*/1, pointerProperties, pointerCoords);
Siarhei Vishniakouf00a4ec2021-06-16 03:55:32 +00008465
8466 const int32_t additionalPolicyFlags = POLICY_FLAG_PASS_TO_USER;
8467 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Harry Cutts33476232023-01-30 19:57:29 +00008468 mDispatcher->injectInputEvent(&event, /*targetUid=*/{},
Siarhei Vishniakou4648fea2023-06-27 01:00:12 +00008469 InputEventInjectionSync::WAIT_FOR_RESULT, 100ms,
Siarhei Vishniakouf00a4ec2021-06-16 03:55:32 +00008470 policyFlags | additionalPolicyFlags));
8471
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07008472 mWindow->consumeMotionEvent(AllOf(WithFlags(flags), WithDeviceId(resolvedDeviceId)));
Siarhei Vishniakou5d552c42021-05-21 05:02:22 +00008473 }
8474
8475private:
8476 sp<FakeWindowHandle> mWindow;
8477};
8478
8479TEST_F(InputFilterInjectionPolicyTest, TrustedFilteredEvents_KeepOriginalDeviceId) {
Siarhei Vishniakouf00a4ec2021-06-16 03:55:32 +00008480 // Must have POLICY_FLAG_FILTERED here to indicate that the event has gone through the input
8481 // filter. Without it, the event will no different from a regularly injected event, and the
8482 // injected device id will be overwritten.
Harry Cutts33476232023-01-30 19:57:29 +00008483 testInjectedKey(POLICY_FLAG_FILTERED, /*injectedDeviceId=*/3, /*resolvedDeviceId=*/3,
8484 /*flags=*/0);
Siarhei Vishniakou5d552c42021-05-21 05:02:22 +00008485}
8486
Siarhei Vishniakouf00a4ec2021-06-16 03:55:32 +00008487TEST_F(InputFilterInjectionPolicyTest, KeyEventsInjectedFromAccessibility_HaveAccessibilityFlag) {
Siarhei Vishniakou5d552c42021-05-21 05:02:22 +00008488 testInjectedKey(POLICY_FLAG_FILTERED | POLICY_FLAG_INJECTED_FROM_ACCESSIBILITY,
Harry Cutts33476232023-01-30 19:57:29 +00008489 /*injectedDeviceId=*/3, /*resolvedDeviceId=*/3,
Siarhei Vishniakouf00a4ec2021-06-16 03:55:32 +00008490 AKEY_EVENT_FLAG_IS_ACCESSIBILITY_EVENT);
8491}
8492
8493TEST_F(InputFilterInjectionPolicyTest,
8494 MotionEventsInjectedFromAccessibility_HaveAccessibilityFlag) {
8495 testInjectedMotion(POLICY_FLAG_FILTERED | POLICY_FLAG_INJECTED_FROM_ACCESSIBILITY,
Harry Cutts33476232023-01-30 19:57:29 +00008496 /*injectedDeviceId=*/3, /*resolvedDeviceId=*/3,
Siarhei Vishniakouf00a4ec2021-06-16 03:55:32 +00008497 AMOTION_EVENT_FLAG_IS_ACCESSIBILITY_EVENT);
Siarhei Vishniakou5d552c42021-05-21 05:02:22 +00008498}
8499
8500TEST_F(InputFilterInjectionPolicyTest, RegularInjectedEvents_ReceiveVirtualDeviceId) {
Harry Cutts33476232023-01-30 19:57:29 +00008501 testInjectedKey(/*policyFlags=*/0, /*injectedDeviceId=*/3,
8502 /*resolvedDeviceId=*/VIRTUAL_KEYBOARD_ID, /*flags=*/0);
Siarhei Vishniakou5d552c42021-05-21 05:02:22 +00008503}
8504
Yeabkal Wubshitb8aadfa2024-01-17 17:03:42 -08008505class InputDispatcherUserActivityPokeTests : public InputDispatcherTest {
8506protected:
8507 virtual void SetUp() override {
8508 InputDispatcherTest::SetUp();
8509
8510 std::shared_ptr<FakeApplicationHandle> application =
8511 std::make_shared<FakeApplicationHandle>();
8512 application->setDispatchingTimeout(100ms);
8513 mWindow = sp<FakeWindowHandle>::make(application, mDispatcher, "TestWindow",
8514 ADISPLAY_ID_DEFAULT);
Yeabkal Wubshit222d83d2024-01-24 18:00:09 +00008515 mWindow->setFrame(Rect(0, 0, 100, 100));
Yeabkal Wubshitb8aadfa2024-01-17 17:03:42 -08008516 mWindow->setDispatchingTimeout(100ms);
8517 mWindow->setFocusable(true);
8518
8519 // Set focused application.
8520 mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application);
8521
8522 mDispatcher->onWindowInfosChanged({{*mWindow->getInfo()}, {}, 0, 0});
8523 setFocusedWindow(mWindow);
8524 mWindow->consumeFocusEvent(true);
8525 }
8526
8527 void notifyAndConsumeMotion(int32_t action, uint32_t source, int32_t displayId,
8528 nsecs_t eventTime) {
8529 mDispatcher->notifyMotion(MotionArgsBuilder(action, source)
8530 .displayId(displayId)
8531 .eventTime(eventTime)
8532 .pointer(PointerBuilder(0, ToolType::FINGER).x(50).y(50))
8533 .build());
8534 mWindow->consumeMotionEvent(WithMotionAction(action));
8535 }
8536
8537private:
8538 sp<FakeWindowHandle> mWindow;
8539};
8540
8541TEST_F_WITH_FLAGS(
8542 InputDispatcherUserActivityPokeTests, MinPokeTimeObserved,
8543 REQUIRES_FLAGS_ENABLED(ACONFIG_FLAG(com::android::input::flags,
8544 rate_limit_user_activity_poke_in_dispatcher))) {
8545 mDispatcher->setMinTimeBetweenUserActivityPokes(50ms);
8546
8547 // First event of type TOUCH. Should poke.
8548 notifyAndConsumeMotion(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
8549 milliseconds_to_nanoseconds(50));
8550 mFakePolicy->assertUserActivityPoked(
8551 {{milliseconds_to_nanoseconds(50), USER_ACTIVITY_EVENT_TOUCH, ADISPLAY_ID_DEFAULT}});
8552
8553 // 80ns > 50ns has passed since previous TOUCH event. Should poke.
8554 notifyAndConsumeMotion(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
8555 milliseconds_to_nanoseconds(130));
8556 mFakePolicy->assertUserActivityPoked(
8557 {{milliseconds_to_nanoseconds(130), USER_ACTIVITY_EVENT_TOUCH, ADISPLAY_ID_DEFAULT}});
8558
8559 // First event of type OTHER. Should poke (despite being within 50ns of previous TOUCH event).
8560 notifyAndConsumeMotion(ACTION_SCROLL, AINPUT_SOURCE_ROTARY_ENCODER, ADISPLAY_ID_DEFAULT,
8561 milliseconds_to_nanoseconds(135));
8562 mFakePolicy->assertUserActivityPoked(
8563 {{milliseconds_to_nanoseconds(135), USER_ACTIVITY_EVENT_OTHER, ADISPLAY_ID_DEFAULT}});
8564
8565 // Within 50ns of previous TOUCH event. Should NOT poke.
8566 notifyAndConsumeMotion(ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
8567 milliseconds_to_nanoseconds(140));
8568 mFakePolicy->assertUserActivityNotPoked();
8569
8570 // Within 50ns of previous OTHER event. Should NOT poke.
8571 notifyAndConsumeMotion(ACTION_SCROLL, AINPUT_SOURCE_ROTARY_ENCODER, ADISPLAY_ID_DEFAULT,
8572 milliseconds_to_nanoseconds(150));
8573 mFakePolicy->assertUserActivityNotPoked();
8574
8575 // Within 50ns of previous TOUCH event (which was at time 130). Should NOT poke.
8576 // Note that STYLUS is mapped to TOUCH user activity, since it's a pointer-type source.
8577 notifyAndConsumeMotion(ACTION_DOWN, AINPUT_SOURCE_STYLUS, ADISPLAY_ID_DEFAULT,
8578 milliseconds_to_nanoseconds(160));
8579 mFakePolicy->assertUserActivityNotPoked();
8580
8581 // 65ns > 50ns has passed since previous OTHER event. Should poke.
8582 notifyAndConsumeMotion(ACTION_SCROLL, AINPUT_SOURCE_ROTARY_ENCODER, ADISPLAY_ID_DEFAULT,
8583 milliseconds_to_nanoseconds(200));
8584 mFakePolicy->assertUserActivityPoked(
8585 {{milliseconds_to_nanoseconds(200), USER_ACTIVITY_EVENT_OTHER, ADISPLAY_ID_DEFAULT}});
8586
8587 // 170ns > 50ns has passed since previous TOUCH event. Should poke.
8588 notifyAndConsumeMotion(ACTION_UP, AINPUT_SOURCE_STYLUS, ADISPLAY_ID_DEFAULT,
8589 milliseconds_to_nanoseconds(300));
8590 mFakePolicy->assertUserActivityPoked(
8591 {{milliseconds_to_nanoseconds(300), USER_ACTIVITY_EVENT_TOUCH, ADISPLAY_ID_DEFAULT}});
8592
8593 // Assert that there's no more user activity poke event.
8594 mFakePolicy->assertUserActivityNotPoked();
8595}
8596
8597TEST_F_WITH_FLAGS(
8598 InputDispatcherUserActivityPokeTests, DefaultMinPokeTimeOf100MsUsed,
8599 REQUIRES_FLAGS_ENABLED(ACONFIG_FLAG(com::android::input::flags,
8600 rate_limit_user_activity_poke_in_dispatcher))) {
8601 notifyAndConsumeMotion(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
8602 milliseconds_to_nanoseconds(200));
8603 mFakePolicy->assertUserActivityPoked(
8604 {{milliseconds_to_nanoseconds(200), USER_ACTIVITY_EVENT_TOUCH, ADISPLAY_ID_DEFAULT}});
8605
8606 notifyAndConsumeMotion(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
8607 milliseconds_to_nanoseconds(280));
8608 mFakePolicy->assertUserActivityNotPoked();
8609
8610 notifyAndConsumeMotion(ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
8611 milliseconds_to_nanoseconds(340));
8612 mFakePolicy->assertUserActivityPoked(
8613 {{milliseconds_to_nanoseconds(340), USER_ACTIVITY_EVENT_TOUCH, ADISPLAY_ID_DEFAULT}});
8614}
8615
8616TEST_F_WITH_FLAGS(
8617 InputDispatcherUserActivityPokeTests, ZeroMinPokeTimeDisablesRateLimiting,
8618 REQUIRES_FLAGS_ENABLED(ACONFIG_FLAG(com::android::input::flags,
8619 rate_limit_user_activity_poke_in_dispatcher))) {
8620 mDispatcher->setMinTimeBetweenUserActivityPokes(0ms);
8621
8622 notifyAndConsumeMotion(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, 20);
8623 mFakePolicy->assertUserActivityPoked();
8624
8625 notifyAndConsumeMotion(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, 30);
8626 mFakePolicy->assertUserActivityPoked();
8627}
8628
chaviwfd6d3512019-03-25 13:23:49 -07008629class InputDispatcherOnPointerDownOutsideFocus : public InputDispatcherTest {
Prabir Pradhan3608aad2019-10-02 17:08:26 -07008630 virtual void SetUp() override {
chaviwfd6d3512019-03-25 13:23:49 -07008631 InputDispatcherTest::SetUp();
8632
Chris Yea209fde2020-07-22 13:54:51 -07008633 std::shared_ptr<FakeApplicationHandle> application =
8634 std::make_shared<FakeApplicationHandle>();
Siarhei Vishniakou870ecec2020-12-09 08:07:46 -10008635 mUnfocusedWindow =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07008636 sp<FakeWindowHandle>::make(application, mDispatcher, "Top", ADISPLAY_ID_DEFAULT);
chaviwfd6d3512019-03-25 13:23:49 -07008637 mUnfocusedWindow->setFrame(Rect(0, 0, 30, 30));
chaviwfd6d3512019-03-25 13:23:49 -07008638
Siarhei Vishniakoub9b15352019-11-26 13:19:26 -08008639 mFocusedWindow =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07008640 sp<FakeWindowHandle>::make(application, mDispatcher, "Second", ADISPLAY_ID_DEFAULT);
Siarhei Vishniakoub9b15352019-11-26 13:19:26 -08008641 mFocusedWindow->setFrame(Rect(50, 50, 100, 100));
chaviwfd6d3512019-03-25 13:23:49 -07008642
8643 // Set focused application.
8644 mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application);
Vishnu Nair47074b82020-08-14 11:54:47 -07008645 mFocusedWindow->setFocusable(true);
chaviwfd6d3512019-03-25 13:23:49 -07008646
8647 // Expect one focus window exist in display.
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07008648 mDispatcher->onWindowInfosChanged(
8649 {{*mUnfocusedWindow->getInfo(), *mFocusedWindow->getInfo()}, {}, 0, 0});
Vishnu Nair958da932020-08-21 17:12:37 -07008650 setFocusedWindow(mFocusedWindow);
Siarhei Vishniakouf1035d42019-09-20 16:32:01 +01008651 mFocusedWindow->consumeFocusEvent(true);
chaviwfd6d3512019-03-25 13:23:49 -07008652 }
8653
Prabir Pradhan3608aad2019-10-02 17:08:26 -07008654 virtual void TearDown() override {
chaviwfd6d3512019-03-25 13:23:49 -07008655 InputDispatcherTest::TearDown();
8656
8657 mUnfocusedWindow.clear();
Siarhei Vishniakoub9b15352019-11-26 13:19:26 -08008658 mFocusedWindow.clear();
chaviwfd6d3512019-03-25 13:23:49 -07008659 }
8660
8661protected:
8662 sp<FakeWindowHandle> mUnfocusedWindow;
Siarhei Vishniakoub9b15352019-11-26 13:19:26 -08008663 sp<FakeWindowHandle> mFocusedWindow;
Siarhei Vishniakoufb9fcda2020-05-04 14:59:19 -07008664 static constexpr PointF FOCUSED_WINDOW_TOUCH_POINT = {60, 60};
chaviwfd6d3512019-03-25 13:23:49 -07008665};
8666
8667// Have two windows, one with focus. Inject MotionEvent with source TOUCHSCREEN and action
8668// DOWN on the window that doesn't have focus. Ensure the window that didn't have focus received
8669// the onPointerDownOutsideFocus callback.
8670TEST_F(InputDispatcherOnPointerDownOutsideFocus, OnPointerDownOutsideFocus_Success) {
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08008671 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07008672 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
Siarhei Vishniakoufb9fcda2020-05-04 14:59:19 -07008673 {20, 20}))
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08008674 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
Siarhei Vishniakou03aee2a2020-04-13 20:44:54 -07008675 mUnfocusedWindow->consumeMotionDown();
chaviwfd6d3512019-03-25 13:23:49 -07008676
Siarhei Vishniakou2bfa9052019-11-21 18:10:54 -08008677 ASSERT_TRUE(mDispatcher->waitForIdle());
chaviwfd6d3512019-03-25 13:23:49 -07008678 mFakePolicy->assertOnPointerDownEquals(mUnfocusedWindow->getToken());
8679}
8680
8681// Have two windows, one with focus. Inject MotionEvent with source TRACKBALL and action
8682// DOWN on the window that doesn't have focus. Ensure no window received the
8683// onPointerDownOutsideFocus callback.
8684TEST_F(InputDispatcherOnPointerDownOutsideFocus, OnPointerDownOutsideFocus_NonPointerSource) {
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08008685 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07008686 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TRACKBALL, ADISPLAY_ID_DEFAULT,
8687 {20, 20}))
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08008688 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
Siarhei Vishniakou03aee2a2020-04-13 20:44:54 -07008689 mFocusedWindow->consumeMotionDown();
chaviwfd6d3512019-03-25 13:23:49 -07008690
Siarhei Vishniakou2bfa9052019-11-21 18:10:54 -08008691 ASSERT_TRUE(mDispatcher->waitForIdle());
8692 mFakePolicy->assertOnPointerDownWasNotCalled();
chaviwfd6d3512019-03-25 13:23:49 -07008693}
8694
8695// Have two windows, one with focus. Inject KeyEvent with action DOWN on the window that doesn't
8696// have focus. Ensure no window received the onPointerDownOutsideFocus callback.
8697TEST_F(InputDispatcherOnPointerDownOutsideFocus, OnPointerDownOutsideFocus_NonMotionFailure) {
Prabir Pradhan93f342c2021-03-11 15:05:30 -08008698 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07008699 injectKeyDownNoRepeat(*mDispatcher, ADISPLAY_ID_DEFAULT))
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08008700 << "Inject key event should return InputEventInjectionResult::SUCCEEDED";
Siarhei Vishniakou03aee2a2020-04-13 20:44:54 -07008701 mFocusedWindow->consumeKeyDown(ADISPLAY_ID_DEFAULT);
chaviwfd6d3512019-03-25 13:23:49 -07008702
Siarhei Vishniakou2bfa9052019-11-21 18:10:54 -08008703 ASSERT_TRUE(mDispatcher->waitForIdle());
8704 mFakePolicy->assertOnPointerDownWasNotCalled();
chaviwfd6d3512019-03-25 13:23:49 -07008705}
8706
8707// Have two windows, one with focus. Inject MotionEvent with source TOUCHSCREEN and action
8708// DOWN on the window that already has focus. Ensure no window received the
8709// onPointerDownOutsideFocus callback.
Siarhei Vishniakou870ecec2020-12-09 08:07:46 -10008710TEST_F(InputDispatcherOnPointerDownOutsideFocus, OnPointerDownOutsideFocus_OnAlreadyFocusedWindow) {
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08008711 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07008712 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
Siarhei Vishniakoufb9fcda2020-05-04 14:59:19 -07008713 FOCUSED_WINDOW_TOUCH_POINT))
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08008714 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
Siarhei Vishniakou03aee2a2020-04-13 20:44:54 -07008715 mFocusedWindow->consumeMotionDown();
chaviwfd6d3512019-03-25 13:23:49 -07008716
Siarhei Vishniakou2bfa9052019-11-21 18:10:54 -08008717 ASSERT_TRUE(mDispatcher->waitForIdle());
8718 mFakePolicy->assertOnPointerDownWasNotCalled();
chaviwfd6d3512019-03-25 13:23:49 -07008719}
8720
Prabir Pradhan47cf0a02021-03-11 20:30:57 -08008721// Have two windows, one with focus. Injecting a trusted DOWN MotionEvent with the flag
8722// NO_FOCUS_CHANGE on the unfocused window should not call the onPointerDownOutsideFocus callback.
8723TEST_F(InputDispatcherOnPointerDownOutsideFocus, NoFocusChangeFlag) {
8724 const MotionEvent event =
8725 MotionEventBuilder(AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_MOUSE)
8726 .eventTime(systemTime(SYSTEM_TIME_MONOTONIC))
Siarhei Vishniakou6d73f832022-07-21 17:27:03 -07008727 .pointer(PointerBuilder(/*id=*/0, ToolType::FINGER).x(20).y(20))
Prabir Pradhan47cf0a02021-03-11 20:30:57 -08008728 .addFlag(AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE)
8729 .build();
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07008730 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectMotionEvent(*mDispatcher, event))
Prabir Pradhan47cf0a02021-03-11 20:30:57 -08008731 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
8732 mUnfocusedWindow->consumeAnyMotionDown(ADISPLAY_ID_DEFAULT, AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
8733
8734 ASSERT_TRUE(mDispatcher->waitForIdle());
8735 mFakePolicy->assertOnPointerDownWasNotCalled();
8736 // Ensure that the unfocused window did not receive any FOCUS events.
8737 mUnfocusedWindow->assertNoEvents();
8738}
8739
chaviwaf87b3e2019-10-01 16:59:28 -07008740// These tests ensures we can send touch events to a single client when there are multiple input
8741// windows that point to the same client token.
8742class InputDispatcherMultiWindowSameTokenTests : public InputDispatcherTest {
8743 virtual void SetUp() override {
8744 InputDispatcherTest::SetUp();
8745
Chris Yea209fde2020-07-22 13:54:51 -07008746 std::shared_ptr<FakeApplicationHandle> application =
8747 std::make_shared<FakeApplicationHandle>();
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07008748 mWindow1 = sp<FakeWindowHandle>::make(application, mDispatcher, "Fake Window 1",
8749 ADISPLAY_ID_DEFAULT);
chaviwaf87b3e2019-10-01 16:59:28 -07008750 mWindow1->setFrame(Rect(0, 0, 100, 100));
8751
Prabir Pradhane7cc69c2024-01-05 21:35:28 +00008752 mWindow2 = mWindow1->clone(ADISPLAY_ID_DEFAULT);
chaviwaf87b3e2019-10-01 16:59:28 -07008753 mWindow2->setFrame(Rect(100, 100, 200, 200));
8754
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07008755 mDispatcher->onWindowInfosChanged({{*mWindow1->getInfo(), *mWindow2->getInfo()}, {}, 0, 0});
chaviwaf87b3e2019-10-01 16:59:28 -07008756 }
8757
8758protected:
8759 sp<FakeWindowHandle> mWindow1;
8760 sp<FakeWindowHandle> mWindow2;
8761
8762 // Helper function to convert the point from screen coordinates into the window's space
chaviw3277faf2021-05-19 16:45:23 -05008763 static PointF getPointInWindow(const WindowInfo* windowInfo, const PointF& point) {
chaviw1ff3d1e2020-07-01 15:53:47 -07008764 vec2 vals = windowInfo->transform.transform(point.x, point.y);
8765 return {vals.x, vals.y};
chaviwaf87b3e2019-10-01 16:59:28 -07008766 }
8767
8768 void consumeMotionEvent(const sp<FakeWindowHandle>& window, int32_t expectedAction,
8769 const std::vector<PointF>& points) {
Siarhei Vishniakouf1035d42019-09-20 16:32:01 +01008770 const std::string name = window->getName();
Siarhei Vishniakoud3061ab2023-12-18 20:41:08 -08008771 std::unique_ptr<MotionEvent> motionEvent =
Prabir Pradhan7662a8d2023-12-15 01:58:14 +00008772 window->consumeMotionEvent(WithMotionAction(expectedAction));
Siarhei Vishniakoud3061ab2023-12-18 20:41:08 -08008773 ASSERT_NE(nullptr, motionEvent);
8774 ASSERT_EQ(points.size(), motionEvent->getPointerCount());
chaviwaf87b3e2019-10-01 16:59:28 -07008775
8776 for (size_t i = 0; i < points.size(); i++) {
8777 float expectedX = points[i].x;
8778 float expectedY = points[i].y;
8779
Siarhei Vishniakoud3061ab2023-12-18 20:41:08 -08008780 EXPECT_EQ(expectedX, motionEvent->getX(i))
chaviwaf87b3e2019-10-01 16:59:28 -07008781 << "expected " << expectedX << " for x[" << i << "] coord of " << name.c_str()
Siarhei Vishniakoud3061ab2023-12-18 20:41:08 -08008782 << ", got " << motionEvent->getX(i);
8783 EXPECT_EQ(expectedY, motionEvent->getY(i))
chaviwaf87b3e2019-10-01 16:59:28 -07008784 << "expected " << expectedY << " for y[" << i << "] coord of " << name.c_str()
Siarhei Vishniakoud3061ab2023-12-18 20:41:08 -08008785 << ", got " << motionEvent->getY(i);
chaviwaf87b3e2019-10-01 16:59:28 -07008786 }
8787 }
chaviw9eaa22c2020-07-01 16:21:27 -07008788
Prabir Pradhanbb3f1c02024-01-04 20:17:14 +00008789 void touchAndAssertPositions(sp<FakeWindowHandle> touchedWindow, int32_t action,
8790 const std::vector<PointF>& touchedPoints,
chaviw9eaa22c2020-07-01 16:21:27 -07008791 std::vector<PointF> expectedPoints) {
Prabir Pradhan678438e2023-04-13 19:32:51 +00008792 mDispatcher->notifyMotion(generateMotionArgs(action, AINPUT_SOURCE_TOUCHSCREEN,
8793 ADISPLAY_ID_DEFAULT, touchedPoints));
chaviw9eaa22c2020-07-01 16:21:27 -07008794
Prabir Pradhanbb3f1c02024-01-04 20:17:14 +00008795 consumeMotionEvent(touchedWindow, action, expectedPoints);
chaviw9eaa22c2020-07-01 16:21:27 -07008796 }
chaviwaf87b3e2019-10-01 16:59:28 -07008797};
8798
8799TEST_F(InputDispatcherMultiWindowSameTokenTests, SingleTouchSameScale) {
8800 // Touch Window 1
8801 PointF touchedPoint = {10, 10};
8802 PointF expectedPoint = getPointInWindow(mWindow1->getInfo(), touchedPoint);
Prabir Pradhanbb3f1c02024-01-04 20:17:14 +00008803 touchAndAssertPositions(mWindow1, AMOTION_EVENT_ACTION_DOWN, {touchedPoint}, {expectedPoint});
chaviwaf87b3e2019-10-01 16:59:28 -07008804
8805 // Release touch on Window 1
Prabir Pradhanbb3f1c02024-01-04 20:17:14 +00008806 touchAndAssertPositions(mWindow1, AMOTION_EVENT_ACTION_UP, {touchedPoint}, {expectedPoint});
chaviwaf87b3e2019-10-01 16:59:28 -07008807
8808 // Touch Window 2
8809 touchedPoint = {150, 150};
8810 expectedPoint = getPointInWindow(mWindow2->getInfo(), touchedPoint);
Prabir Pradhanbb3f1c02024-01-04 20:17:14 +00008811 touchAndAssertPositions(mWindow2, AMOTION_EVENT_ACTION_DOWN, {touchedPoint}, {expectedPoint});
chaviwaf87b3e2019-10-01 16:59:28 -07008812}
8813
chaviw9eaa22c2020-07-01 16:21:27 -07008814TEST_F(InputDispatcherMultiWindowSameTokenTests, SingleTouchDifferentTransform) {
8815 // Set scale value for window2
chaviwaf87b3e2019-10-01 16:59:28 -07008816 mWindow2->setWindowScale(0.5f, 0.5f);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07008817 mDispatcher->onWindowInfosChanged({{*mWindow1->getInfo(), *mWindow2->getInfo()}, {}, 0, 0});
chaviwaf87b3e2019-10-01 16:59:28 -07008818
8819 // Touch Window 1
8820 PointF touchedPoint = {10, 10};
8821 PointF expectedPoint = getPointInWindow(mWindow1->getInfo(), touchedPoint);
Prabir Pradhanbb3f1c02024-01-04 20:17:14 +00008822 touchAndAssertPositions(mWindow1, AMOTION_EVENT_ACTION_DOWN, {touchedPoint}, {expectedPoint});
chaviwaf87b3e2019-10-01 16:59:28 -07008823 // Release touch on Window 1
Prabir Pradhanbb3f1c02024-01-04 20:17:14 +00008824 touchAndAssertPositions(mWindow1, AMOTION_EVENT_ACTION_UP, {touchedPoint}, {expectedPoint});
chaviwaf87b3e2019-10-01 16:59:28 -07008825
8826 // Touch Window 2
8827 touchedPoint = {150, 150};
8828 expectedPoint = getPointInWindow(mWindow2->getInfo(), touchedPoint);
Prabir Pradhanbb3f1c02024-01-04 20:17:14 +00008829 touchAndAssertPositions(mWindow2, AMOTION_EVENT_ACTION_DOWN, {touchedPoint}, {expectedPoint});
8830 touchAndAssertPositions(mWindow2, AMOTION_EVENT_ACTION_UP, {touchedPoint}, {expectedPoint});
chaviwaf87b3e2019-10-01 16:59:28 -07008831
chaviw9eaa22c2020-07-01 16:21:27 -07008832 // Update the transform so rotation is set
8833 mWindow2->setWindowTransform(0, -1, 1, 0);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07008834 mDispatcher->onWindowInfosChanged({{*mWindow1->getInfo(), *mWindow2->getInfo()}, {}, 0, 0});
chaviw9eaa22c2020-07-01 16:21:27 -07008835 expectedPoint = getPointInWindow(mWindow2->getInfo(), touchedPoint);
Prabir Pradhanbb3f1c02024-01-04 20:17:14 +00008836 touchAndAssertPositions(mWindow2, AMOTION_EVENT_ACTION_DOWN, {touchedPoint}, {expectedPoint});
chaviwaf87b3e2019-10-01 16:59:28 -07008837}
8838
chaviw9eaa22c2020-07-01 16:21:27 -07008839TEST_F(InputDispatcherMultiWindowSameTokenTests, MultipleTouchDifferentTransform) {
Chavi Weingarten65f98b82020-01-16 18:56:50 +00008840 mWindow2->setWindowScale(0.5f, 0.5f);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07008841 mDispatcher->onWindowInfosChanged({{*mWindow1->getInfo(), *mWindow2->getInfo()}, {}, 0, 0});
Chavi Weingarten65f98b82020-01-16 18:56:50 +00008842
8843 // Touch Window 1
8844 std::vector<PointF> touchedPoints = {PointF{10, 10}};
8845 std::vector<PointF> expectedPoints = {getPointInWindow(mWindow1->getInfo(), touchedPoints[0])};
Prabir Pradhanbb3f1c02024-01-04 20:17:14 +00008846 touchAndAssertPositions(mWindow1, AMOTION_EVENT_ACTION_DOWN, touchedPoints, expectedPoints);
Chavi Weingarten65f98b82020-01-16 18:56:50 +00008847
8848 // Touch Window 2
Prabir Pradhanbb3f1c02024-01-04 20:17:14 +00008849 // Since this is part of the same touch gesture that has already been dispatched to Window 1,
8850 // the touch stream from Window 2 will be merged with the stream in Window 1. The merged stream
8851 // will continue to be dispatched through Window 1.
chaviw9eaa22c2020-07-01 16:21:27 -07008852 touchedPoints.push_back(PointF{150, 150});
8853 expectedPoints.push_back(getPointInWindow(mWindow2->getInfo(), touchedPoints[1]));
Prabir Pradhanbb3f1c02024-01-04 20:17:14 +00008854 touchAndAssertPositions(mWindow1, POINTER_1_DOWN, touchedPoints, expectedPoints);
Chavi Weingarten65f98b82020-01-16 18:56:50 +00008855
chaviw9eaa22c2020-07-01 16:21:27 -07008856 // Release Window 2
Prabir Pradhanbb3f1c02024-01-04 20:17:14 +00008857 touchAndAssertPositions(mWindow1, POINTER_1_UP, touchedPoints, expectedPoints);
chaviw9eaa22c2020-07-01 16:21:27 -07008858 expectedPoints.pop_back();
Chavi Weingarten65f98b82020-01-16 18:56:50 +00008859
chaviw9eaa22c2020-07-01 16:21:27 -07008860 // Update the transform so rotation is set for Window 2
8861 mWindow2->setWindowTransform(0, -1, 1, 0);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07008862 mDispatcher->onWindowInfosChanged({{*mWindow1->getInfo(), *mWindow2->getInfo()}, {}, 0, 0});
chaviw9eaa22c2020-07-01 16:21:27 -07008863 expectedPoints.push_back(getPointInWindow(mWindow2->getInfo(), touchedPoints[1]));
Prabir Pradhanbb3f1c02024-01-04 20:17:14 +00008864 touchAndAssertPositions(mWindow1, POINTER_1_DOWN, touchedPoints, expectedPoints);
Chavi Weingarten65f98b82020-01-16 18:56:50 +00008865}
8866
chaviw9eaa22c2020-07-01 16:21:27 -07008867TEST_F(InputDispatcherMultiWindowSameTokenTests, MultipleTouchMoveDifferentTransform) {
Chavi Weingarten65f98b82020-01-16 18:56:50 +00008868 mWindow2->setWindowScale(0.5f, 0.5f);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07008869 mDispatcher->onWindowInfosChanged({{*mWindow1->getInfo(), *mWindow2->getInfo()}, {}, 0, 0});
Chavi Weingarten65f98b82020-01-16 18:56:50 +00008870
8871 // Touch Window 1
8872 std::vector<PointF> touchedPoints = {PointF{10, 10}};
8873 std::vector<PointF> expectedPoints = {getPointInWindow(mWindow1->getInfo(), touchedPoints[0])};
Prabir Pradhanbb3f1c02024-01-04 20:17:14 +00008874 touchAndAssertPositions(mWindow1, AMOTION_EVENT_ACTION_DOWN, touchedPoints, expectedPoints);
Chavi Weingarten65f98b82020-01-16 18:56:50 +00008875
8876 // Touch Window 2
chaviw9eaa22c2020-07-01 16:21:27 -07008877 touchedPoints.push_back(PointF{150, 150});
8878 expectedPoints.push_back(getPointInWindow(mWindow2->getInfo(), touchedPoints[1]));
Chavi Weingarten65f98b82020-01-16 18:56:50 +00008879
Prabir Pradhanbb3f1c02024-01-04 20:17:14 +00008880 touchAndAssertPositions(mWindow1, POINTER_1_DOWN, touchedPoints, expectedPoints);
Chavi Weingarten65f98b82020-01-16 18:56:50 +00008881
8882 // Move both windows
8883 touchedPoints = {{20, 20}, {175, 175}};
8884 expectedPoints = {getPointInWindow(mWindow1->getInfo(), touchedPoints[0]),
8885 getPointInWindow(mWindow2->getInfo(), touchedPoints[1])};
8886
Prabir Pradhanbb3f1c02024-01-04 20:17:14 +00008887 touchAndAssertPositions(mWindow1, AMOTION_EVENT_ACTION_MOVE, touchedPoints, expectedPoints);
Chavi Weingarten65f98b82020-01-16 18:56:50 +00008888
chaviw9eaa22c2020-07-01 16:21:27 -07008889 // Release Window 2
Prabir Pradhanbb3f1c02024-01-04 20:17:14 +00008890 touchAndAssertPositions(mWindow1, POINTER_1_UP, touchedPoints, expectedPoints);
chaviw9eaa22c2020-07-01 16:21:27 -07008891 expectedPoints.pop_back();
8892
8893 // Touch Window 2
8894 mWindow2->setWindowTransform(0, -1, 1, 0);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07008895 mDispatcher->onWindowInfosChanged({{*mWindow1->getInfo(), *mWindow2->getInfo()}, {}, 0, 0});
chaviw9eaa22c2020-07-01 16:21:27 -07008896 expectedPoints.push_back(getPointInWindow(mWindow2->getInfo(), touchedPoints[1]));
Prabir Pradhanbb3f1c02024-01-04 20:17:14 +00008897 touchAndAssertPositions(mWindow1, POINTER_1_DOWN, touchedPoints, expectedPoints);
chaviw9eaa22c2020-07-01 16:21:27 -07008898
8899 // Move both windows
8900 touchedPoints = {{20, 20}, {175, 175}};
8901 expectedPoints = {getPointInWindow(mWindow1->getInfo(), touchedPoints[0]),
8902 getPointInWindow(mWindow2->getInfo(), touchedPoints[1])};
8903
Prabir Pradhanbb3f1c02024-01-04 20:17:14 +00008904 touchAndAssertPositions(mWindow1, AMOTION_EVENT_ACTION_MOVE, touchedPoints, expectedPoints);
Chavi Weingarten65f98b82020-01-16 18:56:50 +00008905}
8906
8907TEST_F(InputDispatcherMultiWindowSameTokenTests, MultipleWindowsFirstTouchWithScale) {
8908 mWindow1->setWindowScale(0.5f, 0.5f);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07008909 mDispatcher->onWindowInfosChanged({{*mWindow1->getInfo(), *mWindow2->getInfo()}, {}, 0, 0});
Chavi Weingarten65f98b82020-01-16 18:56:50 +00008910
8911 // Touch Window 1
8912 std::vector<PointF> touchedPoints = {PointF{10, 10}};
8913 std::vector<PointF> expectedPoints = {getPointInWindow(mWindow1->getInfo(), touchedPoints[0])};
Prabir Pradhanbb3f1c02024-01-04 20:17:14 +00008914 touchAndAssertPositions(mWindow1, AMOTION_EVENT_ACTION_DOWN, touchedPoints, expectedPoints);
Chavi Weingarten65f98b82020-01-16 18:56:50 +00008915
8916 // Touch Window 2
chaviw9eaa22c2020-07-01 16:21:27 -07008917 touchedPoints.push_back(PointF{150, 150});
8918 expectedPoints.push_back(getPointInWindow(mWindow2->getInfo(), touchedPoints[1]));
Chavi Weingarten65f98b82020-01-16 18:56:50 +00008919
Prabir Pradhanbb3f1c02024-01-04 20:17:14 +00008920 touchAndAssertPositions(mWindow1, POINTER_1_DOWN, touchedPoints, expectedPoints);
Chavi Weingarten65f98b82020-01-16 18:56:50 +00008921
8922 // Move both windows
8923 touchedPoints = {{20, 20}, {175, 175}};
8924 expectedPoints = {getPointInWindow(mWindow1->getInfo(), touchedPoints[0]),
8925 getPointInWindow(mWindow2->getInfo(), touchedPoints[1])};
8926
Prabir Pradhanbb3f1c02024-01-04 20:17:14 +00008927 touchAndAssertPositions(mWindow1, AMOTION_EVENT_ACTION_MOVE, touchedPoints, expectedPoints);
Chavi Weingarten65f98b82020-01-16 18:56:50 +00008928}
8929
Siarhei Vishniakou0f6558d2023-04-21 12:05:13 -07008930/**
8931 * When one of the windows is slippery, the touch should not slip into the other window with the
8932 * same input channel.
8933 */
8934TEST_F(InputDispatcherMultiWindowSameTokenTests, TouchDoesNotSlipEvenIfSlippery) {
8935 mWindow1->setSlippery(true);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07008936 mDispatcher->onWindowInfosChanged({{*mWindow1->getInfo(), *mWindow2->getInfo()}, {}, 0, 0});
Siarhei Vishniakou0f6558d2023-04-21 12:05:13 -07008937
8938 // Touch down in window 1
8939 mDispatcher->notifyMotion(generateMotionArgs(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN,
8940 ADISPLAY_ID_DEFAULT, {{50, 50}}));
8941 consumeMotionEvent(mWindow1, ACTION_DOWN, {{50, 50}});
8942
8943 // Move touch to be above window 2. Even though window 1 is slippery, touch should not slip.
8944 // That means the gesture should continue normally, without any ACTION_CANCEL or ACTION_DOWN
8945 // getting generated.
8946 mDispatcher->notifyMotion(generateMotionArgs(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN,
8947 ADISPLAY_ID_DEFAULT, {{150, 150}}));
8948
8949 consumeMotionEvent(mWindow1, ACTION_MOVE, {{150, 150}});
8950}
8951
Siarhei Vishniakoud5876ba2023-05-15 17:58:34 -07008952/**
8953 * When hover starts in one window and continues into the other, there should be a HOVER_EXIT and
8954 * a HOVER_ENTER generated, even if the windows have the same token. This is because the new window
8955 * that the pointer is hovering over may have a different transform.
8956 */
8957TEST_F(InputDispatcherMultiWindowSameTokenTests, HoverIntoClone) {
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07008958 mDispatcher->onWindowInfosChanged({{*mWindow1->getInfo(), *mWindow2->getInfo()}, {}, 0, 0});
Siarhei Vishniakoud5876ba2023-05-15 17:58:34 -07008959
8960 // Start hover in window 1
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -07008961 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_ENTER, AINPUT_SOURCE_TOUCHSCREEN)
8962 .pointer(PointerBuilder(0, ToolType::FINGER).x(50).y(50))
8963 .build());
Siarhei Vishniakoud5876ba2023-05-15 17:58:34 -07008964 consumeMotionEvent(mWindow1, ACTION_HOVER_ENTER,
8965 {getPointInWindow(mWindow1->getInfo(), PointF{50, 50})});
Siarhei Vishniakoud5876ba2023-05-15 17:58:34 -07008966 // Move hover to window 2.
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -07008967 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_MOVE, AINPUT_SOURCE_TOUCHSCREEN)
8968 .pointer(PointerBuilder(0, ToolType::FINGER).x(150).y(150))
8969 .build());
Siarhei Vishniakoud5876ba2023-05-15 17:58:34 -07008970 consumeMotionEvent(mWindow1, ACTION_HOVER_EXIT, {{50, 50}});
Prabir Pradhanbb3f1c02024-01-04 20:17:14 +00008971 consumeMotionEvent(mWindow2, ACTION_HOVER_ENTER,
Siarhei Vishniakoud5876ba2023-05-15 17:58:34 -07008972 {getPointInWindow(mWindow2->getInfo(), PointF{150, 150})});
8973}
8974
Siarhei Vishniakou4cb50ca2020-05-26 21:43:02 -07008975class InputDispatcherSingleWindowAnr : public InputDispatcherTest {
8976 virtual void SetUp() override {
8977 InputDispatcherTest::SetUp();
8978
Chris Yea209fde2020-07-22 13:54:51 -07008979 mApplication = std::make_shared<FakeApplicationHandle>();
Siarhei Vishniakouf83c6932023-07-07 17:48:10 -07008980 mApplication->setDispatchingTimeout(100ms);
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07008981 mWindow = sp<FakeWindowHandle>::make(mApplication, mDispatcher, "TestWindow",
8982 ADISPLAY_ID_DEFAULT);
Siarhei Vishniakou4cb50ca2020-05-26 21:43:02 -07008983 mWindow->setFrame(Rect(0, 0, 30, 30));
Siarhei Vishniakouf83c6932023-07-07 17:48:10 -07008984 mWindow->setDispatchingTimeout(100ms);
Vishnu Nair47074b82020-08-14 11:54:47 -07008985 mWindow->setFocusable(true);
Siarhei Vishniakou4cb50ca2020-05-26 21:43:02 -07008986
8987 // Set focused application.
8988 mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, mApplication);
8989
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07008990 mDispatcher->onWindowInfosChanged({{*mWindow->getInfo()}, {}, 0, 0});
Vishnu Nair958da932020-08-21 17:12:37 -07008991 setFocusedWindow(mWindow);
Siarhei Vishniakou4cb50ca2020-05-26 21:43:02 -07008992 mWindow->consumeFocusEvent(true);
8993 }
8994
8995 virtual void TearDown() override {
8996 InputDispatcherTest::TearDown();
8997 mWindow.clear();
8998 }
8999
9000protected:
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07009001 static constexpr std::chrono::duration SPY_TIMEOUT = 200ms;
Chris Yea209fde2020-07-22 13:54:51 -07009002 std::shared_ptr<FakeApplicationHandle> mApplication;
Siarhei Vishniakou4cb50ca2020-05-26 21:43:02 -07009003 sp<FakeWindowHandle> mWindow;
9004 static constexpr PointF WINDOW_LOCATION = {20, 20};
9005
9006 void tapOnWindow() {
Siarhei Vishniakou67bf2162023-11-16 13:29:50 -08009007 const auto touchingPointer = PointerBuilder(/*id=*/0, ToolType::FINGER)
9008 .x(WINDOW_LOCATION.x)
9009 .y(WINDOW_LOCATION.y);
9010 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
9011 .pointer(touchingPointer)
9012 .build());
9013 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN)
9014 .pointer(touchingPointer)
9015 .build());
Siarhei Vishniakou4cb50ca2020-05-26 21:43:02 -07009016 }
Prabir Pradhan1376fcd2022-01-21 09:56:35 -08009017
9018 sp<FakeWindowHandle> addSpyWindow() {
9019 sp<FakeWindowHandle> spy =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07009020 sp<FakeWindowHandle>::make(mApplication, mDispatcher, "Spy", ADISPLAY_ID_DEFAULT);
Prabir Pradhan1376fcd2022-01-21 09:56:35 -08009021 spy->setTrustedOverlay(true);
9022 spy->setFocusable(false);
Prabir Pradhan51e7db02022-02-07 06:02:57 -08009023 spy->setSpy(true);
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07009024 spy->setDispatchingTimeout(SPY_TIMEOUT);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07009025 mDispatcher->onWindowInfosChanged({{*spy->getInfo(), *mWindow->getInfo()}, {}, 0, 0});
Prabir Pradhan1376fcd2022-01-21 09:56:35 -08009026 return spy;
9027 }
Siarhei Vishniakou4cb50ca2020-05-26 21:43:02 -07009028};
9029
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009030// Send a tap and respond, which should not cause an ANR.
9031TEST_F(InputDispatcherSingleWindowAnr, WhenTouchIsConsumed_NoAnr) {
9032 tapOnWindow();
9033 mWindow->consumeMotionDown();
9034 mWindow->consumeMotionUp();
9035 ASSERT_TRUE(mDispatcher->waitForIdle());
9036 mFakePolicy->assertNotifyAnrWasNotCalled();
9037}
9038
9039// Send a regular key and respond, which should not cause an ANR.
9040TEST_F(InputDispatcherSingleWindowAnr, WhenKeyIsConsumed_NoAnr) {
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07009041 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectKeyDownNoRepeat(*mDispatcher));
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009042 mWindow->consumeKeyDown(ADISPLAY_ID_NONE);
9043 ASSERT_TRUE(mDispatcher->waitForIdle());
9044 mFakePolicy->assertNotifyAnrWasNotCalled();
9045}
9046
Siarhei Vishniakoue41c4512020-09-08 19:35:58 -05009047TEST_F(InputDispatcherSingleWindowAnr, WhenFocusedApplicationChanges_NoAnr) {
9048 mWindow->setFocusable(false);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07009049 mDispatcher->onWindowInfosChanged({{*mWindow->getInfo()}, {}, 0, 0});
Siarhei Vishniakoue41c4512020-09-08 19:35:58 -05009050 mWindow->consumeFocusEvent(false);
9051
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08009052 InputEventInjectionResult result =
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07009053 injectKey(*mDispatcher, AKEY_EVENT_ACTION_DOWN, /*repeatCount=*/0, ADISPLAY_ID_DEFAULT,
9054 InputEventInjectionSync::NONE, CONSUME_TIMEOUT_EVENT_EXPECTED,
Harry Cutts33476232023-01-30 19:57:29 +00009055 /*allowKeyRepeat=*/false);
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08009056 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, result);
Siarhei Vishniakoue41c4512020-09-08 19:35:58 -05009057 // Key will not go to window because we have no focused window.
9058 // The 'no focused window' ANR timer should start instead.
9059
9060 // Now, the focused application goes away.
9061 mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, nullptr);
9062 // The key should get dropped and there should be no ANR.
9063
9064 ASSERT_TRUE(mDispatcher->waitForIdle());
9065 mFakePolicy->assertNotifyAnrWasNotCalled();
9066}
9067
Siarhei Vishniakou4cb50ca2020-05-26 21:43:02 -07009068// Send an event to the app and have the app not respond right away.
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009069// When ANR is raised, policy will tell the dispatcher to cancel the events for that window.
9070// So InputDispatcher will enqueue ACTION_CANCEL event as well.
Siarhei Vishniakou4cb50ca2020-05-26 21:43:02 -07009071TEST_F(InputDispatcherSingleWindowAnr, OnPointerDown_BasicAnr) {
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08009072 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07009073 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
Siarhei Vishniakou4cb50ca2020-05-26 21:43:02 -07009074 WINDOW_LOCATION));
9075
Siarhei Vishniakoud3061ab2023-12-18 20:41:08 -08009076 const auto [sequenceNum, _] = mWindow->receiveEvent(); // ACTION_DOWN
Siarhei Vishniakou4cb50ca2020-05-26 21:43:02 -07009077 ASSERT_TRUE(sequenceNum);
9078 const std::chrono::duration timeout = mWindow->getDispatchingTimeout(DISPATCHING_TIMEOUT);
Prabir Pradhanedd96402022-02-15 01:46:16 -08009079 mFakePolicy->assertNotifyWindowUnresponsiveWasCalled(timeout, mWindow);
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009080
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009081 mWindow->finishEvent(*sequenceNum);
Siarhei Vishniakou1ae72f12023-01-29 12:55:30 -08009082 mWindow->consumeMotionEvent(
9083 AllOf(WithMotionAction(ACTION_CANCEL), WithDisplayId(ADISPLAY_ID_DEFAULT)));
Siarhei Vishniakou4cb50ca2020-05-26 21:43:02 -07009084 ASSERT_TRUE(mDispatcher->waitForIdle());
Prabir Pradhanedd96402022-02-15 01:46:16 -08009085 mFakePolicy->assertNotifyWindowResponsiveWasCalled(mWindow->getToken(), mWindow->getPid());
Siarhei Vishniakou4cb50ca2020-05-26 21:43:02 -07009086}
9087
9088// Send a key to the app and have the app not respond right away.
9089TEST_F(InputDispatcherSingleWindowAnr, OnKeyDown_BasicAnr) {
9090 // Inject a key, and don't respond - expect that ANR is called.
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07009091 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectKeyDownNoRepeat(*mDispatcher));
Siarhei Vishniakoud3061ab2023-12-18 20:41:08 -08009092 const auto [sequenceNum, _] = mWindow->receiveEvent();
Siarhei Vishniakou4cb50ca2020-05-26 21:43:02 -07009093 ASSERT_TRUE(sequenceNum);
Siarhei Vishniakou4cb50ca2020-05-26 21:43:02 -07009094 const std::chrono::duration timeout = mWindow->getDispatchingTimeout(DISPATCHING_TIMEOUT);
Prabir Pradhanedd96402022-02-15 01:46:16 -08009095 mFakePolicy->assertNotifyWindowUnresponsiveWasCalled(timeout, mWindow);
Siarhei Vishniakou4cb50ca2020-05-26 21:43:02 -07009096 ASSERT_TRUE(mDispatcher->waitForIdle());
9097}
9098
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009099// We have a focused application, but no focused window
9100TEST_F(InputDispatcherSingleWindowAnr, FocusedApplication_NoFocusedWindow) {
Vishnu Nair47074b82020-08-14 11:54:47 -07009101 mWindow->setFocusable(false);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07009102 mDispatcher->onWindowInfosChanged({{*mWindow->getInfo()}, {}, 0, 0});
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009103 mWindow->consumeFocusEvent(false);
9104
9105 // taps on the window work as normal
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08009106 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07009107 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009108 WINDOW_LOCATION));
9109 ASSERT_NO_FATAL_FAILURE(mWindow->consumeMotionDown());
9110 mDispatcher->waitForIdle();
9111 mFakePolicy->assertNotifyAnrWasNotCalled();
9112
9113 // Once a focused event arrives, we get an ANR for this application
9114 // We specify the injection timeout to be smaller than the application timeout, to ensure that
9115 // injection times out (instead of failing).
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08009116 const InputEventInjectionResult result =
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07009117 injectKey(*mDispatcher, AKEY_EVENT_ACTION_DOWN, /*repeatCount=*/0, ADISPLAY_ID_DEFAULT,
Siarhei Vishniakouf83c6932023-07-07 17:48:10 -07009118 InputEventInjectionSync::WAIT_FOR_RESULT, 50ms, /*allowKeyRepeat=*/false);
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08009119 ASSERT_EQ(InputEventInjectionResult::TIMED_OUT, result);
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009120 const std::chrono::duration timeout = mApplication->getDispatchingTimeout(DISPATCHING_TIMEOUT);
Vishnu Naire4df8752022-09-08 09:17:55 -07009121 mFakePolicy->assertNotifyNoFocusedWindowAnrWasCalled(timeout, mApplication);
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009122 ASSERT_TRUE(mDispatcher->waitForIdle());
9123}
9124
Siarhei Vishniakou289e9242022-02-15 14:50:16 -08009125/**
9126 * Make sure the stale key is dropped before causing an ANR. So even if there's no focused window,
9127 * there will not be an ANR.
9128 */
9129TEST_F(InputDispatcherSingleWindowAnr, StaleKeyEventDoesNotAnr) {
9130 mWindow->setFocusable(false);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07009131 mDispatcher->onWindowInfosChanged({{*mWindow->getInfo()}, {}, 0, 0});
Siarhei Vishniakou289e9242022-02-15 14:50:16 -08009132 mWindow->consumeFocusEvent(false);
9133
9134 KeyEvent event;
Siarhei Vishniakoua7333112023-10-27 13:33:29 -07009135 static constexpr std::chrono::duration STALE_EVENT_TIMEOUT = 1000ms;
9136 mFakePolicy->setStaleEventTimeout(STALE_EVENT_TIMEOUT);
Siarhei Vishniakou289e9242022-02-15 14:50:16 -08009137 const nsecs_t eventTime = systemTime(SYSTEM_TIME_MONOTONIC) -
9138 std::chrono::nanoseconds(STALE_EVENT_TIMEOUT).count();
9139
9140 // Define a valid key down event that is stale (too old).
9141 event.initialize(InputEvent::nextId(), DEVICE_ID, AINPUT_SOURCE_KEYBOARD, ADISPLAY_ID_NONE,
Harry Cutts101ee9b2023-07-06 18:04:14 +00009142 INVALID_HMAC, AKEY_EVENT_ACTION_DOWN, /*flags=*/0, AKEYCODE_A, KEY_A,
Hu Guofe3c8f12023-09-22 17:20:15 +08009143 AMETA_NONE, /*repeatCount=*/0, eventTime, eventTime);
Siarhei Vishniakou289e9242022-02-15 14:50:16 -08009144
Hu Guofe3c8f12023-09-22 17:20:15 +08009145 const int32_t policyFlags =
9146 POLICY_FLAG_FILTERED | POLICY_FLAG_PASS_TO_USER | POLICY_FLAG_DISABLE_KEY_REPEAT;
Siarhei Vishniakou289e9242022-02-15 14:50:16 -08009147
9148 InputEventInjectionResult result =
Harry Cutts33476232023-01-30 19:57:29 +00009149 mDispatcher->injectInputEvent(&event, /*targetUid=*/{},
Siarhei Vishniakou289e9242022-02-15 14:50:16 -08009150 InputEventInjectionSync::WAIT_FOR_RESULT,
9151 INJECT_EVENT_TIMEOUT, policyFlags);
9152 ASSERT_EQ(InputEventInjectionResult::FAILED, result)
9153 << "Injection should fail because the event is stale";
9154
9155 ASSERT_TRUE(mDispatcher->waitForIdle());
9156 mFakePolicy->assertNotifyAnrWasNotCalled();
9157 mWindow->assertNoEvents();
9158}
9159
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009160// We have a focused application, but no focused window
Siarhei Vishniakou234129c2020-10-22 22:28:12 -05009161// Make sure that we don't notify policy twice about the same ANR.
9162TEST_F(InputDispatcherSingleWindowAnr, NoFocusedWindow_DoesNotSendDuplicateAnr) {
Siarhei Vishniakou06405fc2023-09-22 13:40:51 -07009163 const std::chrono::duration appTimeout = 400ms;
9164 mApplication->setDispatchingTimeout(appTimeout);
9165 mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, mApplication);
9166
Vishnu Nair47074b82020-08-14 11:54:47 -07009167 mWindow->setFocusable(false);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07009168 mDispatcher->onWindowInfosChanged({{*mWindow->getInfo()}, {}, 0, 0});
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009169 mWindow->consumeFocusEvent(false);
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009170
9171 // Once a focused event arrives, we get an ANR for this application
9172 // We specify the injection timeout to be smaller than the application timeout, to ensure that
9173 // injection times out (instead of failing).
Siarhei Vishniakou06405fc2023-09-22 13:40:51 -07009174 const std::chrono::duration eventInjectionTimeout = 100ms;
9175 ASSERT_LT(eventInjectionTimeout, appTimeout);
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08009176 const InputEventInjectionResult result =
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07009177 injectKey(*mDispatcher, AKEY_EVENT_ACTION_DOWN, /*repeatCount=*/0, ADISPLAY_ID_DEFAULT,
Siarhei Vishniakou06405fc2023-09-22 13:40:51 -07009178 InputEventInjectionSync::WAIT_FOR_RESULT, eventInjectionTimeout,
9179 /*allowKeyRepeat=*/false);
9180 ASSERT_EQ(InputEventInjectionResult::TIMED_OUT, result)
9181 << "result=" << ftl::enum_string(result);
9182 // We already waited for 'eventInjectionTimeout`, because the countdown started when the event
9183 // was first injected. So now we have (appTimeout - eventInjectionTimeout) left to wait.
9184 std::chrono::duration remainingWaitTime = appTimeout - eventInjectionTimeout;
9185 mFakePolicy->assertNotifyNoFocusedWindowAnrWasCalled(remainingWaitTime, mApplication);
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009186
Vishnu Naire4df8752022-09-08 09:17:55 -07009187 std::this_thread::sleep_for(appTimeout);
Siarhei Vishniakou234129c2020-10-22 22:28:12 -05009188 // ANR should not be raised again. It is up to policy to do that if it desires.
9189 mFakePolicy->assertNotifyAnrWasNotCalled();
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009190
Siarhei Vishniakou234129c2020-10-22 22:28:12 -05009191 // If we now get a focused window, the ANR should stop, but the policy handles that via
9192 // 'notifyFocusChanged' callback. This is implemented in the policy so we can't test it here.
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009193 ASSERT_TRUE(mDispatcher->waitForIdle());
9194}
9195
9196// We have a focused application, but no focused window
9197TEST_F(InputDispatcherSingleWindowAnr, NoFocusedWindow_DropsFocusedEvents) {
Vishnu Nair47074b82020-08-14 11:54:47 -07009198 mWindow->setFocusable(false);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07009199 mDispatcher->onWindowInfosChanged({{*mWindow->getInfo()}, {}, 0, 0});
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009200 mWindow->consumeFocusEvent(false);
9201
9202 // Once a focused event arrives, we get an ANR for this application
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07009203 ASSERT_NO_FATAL_FAILURE(assertInjectedKeyTimesOut(*mDispatcher));
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009204
Vishnu Naire4df8752022-09-08 09:17:55 -07009205 const std::chrono::duration timeout = mApplication->getDispatchingTimeout(DISPATCHING_TIMEOUT);
9206 mFakePolicy->assertNotifyNoFocusedWindowAnrWasCalled(timeout, mApplication);
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009207
9208 // Future focused events get dropped right away
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07009209 ASSERT_EQ(InputEventInjectionResult::FAILED, injectKeyDown(*mDispatcher));
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009210 ASSERT_TRUE(mDispatcher->waitForIdle());
9211 mWindow->assertNoEvents();
9212}
9213
9214/**
9215 * Ensure that the implementation is valid. Since we are using multiset to keep track of the
9216 * ANR timeouts, we are allowing entries with identical timestamps in the same connection.
9217 * If we process 1 of the events, but ANR on the second event with the same timestamp,
9218 * the ANR mechanism should still work.
9219 *
9220 * In this test, we are injecting DOWN and UP events with the same timestamps, and acknowledging the
9221 * DOWN event, while not responding on the second one.
9222 */
9223TEST_F(InputDispatcherSingleWindowAnr, Anr_HandlesEventsWithIdenticalTimestamps) {
9224 nsecs_t currentTime = systemTime(SYSTEM_TIME_MONOTONIC);
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07009225 injectMotionEvent(*mDispatcher, AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN,
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009226 ADISPLAY_ID_DEFAULT, WINDOW_LOCATION,
9227 {AMOTION_EVENT_INVALID_CURSOR_POSITION,
9228 AMOTION_EVENT_INVALID_CURSOR_POSITION},
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08009229 500ms, InputEventInjectionSync::WAIT_FOR_RESULT, currentTime);
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009230
9231 // Now send ACTION_UP, with identical timestamp
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07009232 injectMotionEvent(*mDispatcher, AMOTION_EVENT_ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN,
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009233 ADISPLAY_ID_DEFAULT, WINDOW_LOCATION,
9234 {AMOTION_EVENT_INVALID_CURSOR_POSITION,
9235 AMOTION_EVENT_INVALID_CURSOR_POSITION},
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08009236 500ms, InputEventInjectionSync::WAIT_FOR_RESULT, currentTime);
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009237
9238 // We have now sent down and up. Let's consume first event and then ANR on the second.
9239 mWindow->consumeMotionDown(ADISPLAY_ID_DEFAULT);
9240 const std::chrono::duration timeout = mWindow->getDispatchingTimeout(DISPATCHING_TIMEOUT);
Prabir Pradhanedd96402022-02-15 01:46:16 -08009241 mFakePolicy->assertNotifyWindowUnresponsiveWasCalled(timeout, mWindow);
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009242}
9243
Prabir Pradhan1376fcd2022-01-21 09:56:35 -08009244// A spy window can receive an ANR
9245TEST_F(InputDispatcherSingleWindowAnr, SpyWindowAnr) {
9246 sp<FakeWindowHandle> spy = addSpyWindow();
9247
9248 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07009249 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
Prabir Pradhan1376fcd2022-01-21 09:56:35 -08009250 WINDOW_LOCATION));
9251 mWindow->consumeMotionDown();
9252
Siarhei Vishniakoud3061ab2023-12-18 20:41:08 -08009253 const auto [sequenceNum, _] = spy->receiveEvent(); // ACTION_DOWN
Prabir Pradhan1376fcd2022-01-21 09:56:35 -08009254 ASSERT_TRUE(sequenceNum);
9255 const std::chrono::duration timeout = spy->getDispatchingTimeout(DISPATCHING_TIMEOUT);
Prabir Pradhanedd96402022-02-15 01:46:16 -08009256 mFakePolicy->assertNotifyWindowUnresponsiveWasCalled(timeout, spy);
Prabir Pradhan1376fcd2022-01-21 09:56:35 -08009257
9258 spy->finishEvent(*sequenceNum);
Siarhei Vishniakou1ae72f12023-01-29 12:55:30 -08009259 spy->consumeMotionEvent(
9260 AllOf(WithMotionAction(ACTION_CANCEL), WithDisplayId(ADISPLAY_ID_DEFAULT)));
Prabir Pradhan1376fcd2022-01-21 09:56:35 -08009261 ASSERT_TRUE(mDispatcher->waitForIdle());
Prabir Pradhanedd96402022-02-15 01:46:16 -08009262 mFakePolicy->assertNotifyWindowResponsiveWasCalled(spy->getToken(), mWindow->getPid());
Prabir Pradhan1376fcd2022-01-21 09:56:35 -08009263}
9264
9265// If an app is not responding to a key event, spy windows should continue to receive
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009266// new motion events
Prabir Pradhan1376fcd2022-01-21 09:56:35 -08009267TEST_F(InputDispatcherSingleWindowAnr, SpyWindowReceivesEventsDuringAppAnrOnKey) {
9268 sp<FakeWindowHandle> spy = addSpyWindow();
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009269
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08009270 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07009271 injectKeyDown(*mDispatcher, ADISPLAY_ID_DEFAULT));
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009272 mWindow->consumeKeyDown(ADISPLAY_ID_DEFAULT);
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07009273 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectKeyUp(*mDispatcher, ADISPLAY_ID_DEFAULT));
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009274
9275 // Stuck on the ACTION_UP
9276 const std::chrono::duration timeout = mWindow->getDispatchingTimeout(DISPATCHING_TIMEOUT);
Prabir Pradhanedd96402022-02-15 01:46:16 -08009277 mFakePolicy->assertNotifyWindowUnresponsiveWasCalled(timeout, mWindow);
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009278
Prabir Pradhan1376fcd2022-01-21 09:56:35 -08009279 // New tap will go to the spy window, but not to the window
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009280 tapOnWindow();
Prabir Pradhan1376fcd2022-01-21 09:56:35 -08009281 spy->consumeMotionDown(ADISPLAY_ID_DEFAULT);
9282 spy->consumeMotionUp(ADISPLAY_ID_DEFAULT);
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009283
9284 mWindow->consumeKeyUp(ADISPLAY_ID_DEFAULT); // still the previous motion
9285 mDispatcher->waitForIdle();
Prabir Pradhanedd96402022-02-15 01:46:16 -08009286 mFakePolicy->assertNotifyWindowResponsiveWasCalled(mWindow->getToken(), mWindow->getPid());
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009287 mWindow->assertNoEvents();
Prabir Pradhan1376fcd2022-01-21 09:56:35 -08009288 spy->assertNoEvents();
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009289}
9290
Prabir Pradhan1376fcd2022-01-21 09:56:35 -08009291// If an app is not responding to a motion event, spy windows should continue to receive
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009292// new motion events
Prabir Pradhan1376fcd2022-01-21 09:56:35 -08009293TEST_F(InputDispatcherSingleWindowAnr, SpyWindowReceivesEventsDuringAppAnrOnMotion) {
9294 sp<FakeWindowHandle> spy = addSpyWindow();
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009295
9296 tapOnWindow();
Prabir Pradhan1376fcd2022-01-21 09:56:35 -08009297 spy->consumeMotionDown(ADISPLAY_ID_DEFAULT);
9298 spy->consumeMotionUp(ADISPLAY_ID_DEFAULT);
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009299
9300 mWindow->consumeMotionDown();
9301 // Stuck on the ACTION_UP
9302 const std::chrono::duration timeout = mWindow->getDispatchingTimeout(DISPATCHING_TIMEOUT);
Prabir Pradhanedd96402022-02-15 01:46:16 -08009303 mFakePolicy->assertNotifyWindowUnresponsiveWasCalled(timeout, mWindow);
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009304
Prabir Pradhan1376fcd2022-01-21 09:56:35 -08009305 // New tap will go to the spy window, but not to the window
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009306 tapOnWindow();
Prabir Pradhan1376fcd2022-01-21 09:56:35 -08009307 spy->consumeMotionDown(ADISPLAY_ID_DEFAULT);
9308 spy->consumeMotionUp(ADISPLAY_ID_DEFAULT);
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009309
9310 mWindow->consumeMotionUp(ADISPLAY_ID_DEFAULT); // still the previous motion
9311 mDispatcher->waitForIdle();
Prabir Pradhanedd96402022-02-15 01:46:16 -08009312 mFakePolicy->assertNotifyWindowResponsiveWasCalled(mWindow->getToken(), mWindow->getPid());
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009313 mWindow->assertNoEvents();
Prabir Pradhan1376fcd2022-01-21 09:56:35 -08009314 spy->assertNoEvents();
9315}
9316
9317TEST_F(InputDispatcherSingleWindowAnr, UnresponsiveMonitorAnr) {
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07009318 mDispatcher->setMonitorDispatchingTimeoutForTest(SPY_TIMEOUT);
Prabir Pradhan1376fcd2022-01-21 09:56:35 -08009319
Prabir Pradhanfb549072023-10-05 19:17:36 +00009320 FakeMonitorReceiver monitor = FakeMonitorReceiver(*mDispatcher, "M_1", ADISPLAY_ID_DEFAULT);
Prabir Pradhan1376fcd2022-01-21 09:56:35 -08009321
9322 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07009323 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
Prabir Pradhan1376fcd2022-01-21 09:56:35 -08009324 WINDOW_LOCATION));
9325
9326 mWindow->consumeMotionDown(ADISPLAY_ID_DEFAULT);
9327 const std::optional<uint32_t> consumeSeq = monitor.receiveEvent();
9328 ASSERT_TRUE(consumeSeq);
9329
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07009330 mFakePolicy->assertNotifyWindowUnresponsiveWasCalled(SPY_TIMEOUT, monitor.getToken(),
9331 MONITOR_PID);
Prabir Pradhan1376fcd2022-01-21 09:56:35 -08009332
9333 monitor.finishEvent(*consumeSeq);
9334 monitor.consumeMotionCancel(ADISPLAY_ID_DEFAULT);
9335
9336 ASSERT_TRUE(mDispatcher->waitForIdle());
Prabir Pradhanedd96402022-02-15 01:46:16 -08009337 mFakePolicy->assertNotifyWindowResponsiveWasCalled(monitor.getToken(), MONITOR_PID);
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009338}
9339
9340// If a window is unresponsive, then you get anr. if the window later catches up and starts to
9341// process events, you don't get an anr. When the window later becomes unresponsive again, you
9342// get an ANR again.
9343// 1. tap -> block on ACTION_UP -> receive ANR
9344// 2. consume all pending events (= queue becomes healthy again)
9345// 3. tap again -> block on ACTION_UP again -> receive ANR second time
9346TEST_F(InputDispatcherSingleWindowAnr, SameWindow_CanReceiveAnrTwice) {
9347 tapOnWindow();
9348
9349 mWindow->consumeMotionDown();
9350 // Block on ACTION_UP
9351 const std::chrono::duration timeout = mWindow->getDispatchingTimeout(DISPATCHING_TIMEOUT);
Prabir Pradhanedd96402022-02-15 01:46:16 -08009352 mFakePolicy->assertNotifyWindowUnresponsiveWasCalled(timeout, mWindow);
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009353 mWindow->consumeMotionUp(); // Now the connection should be healthy again
9354 mDispatcher->waitForIdle();
Prabir Pradhanedd96402022-02-15 01:46:16 -08009355 mFakePolicy->assertNotifyWindowResponsiveWasCalled(mWindow->getToken(), mWindow->getPid());
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009356 mWindow->assertNoEvents();
9357
9358 tapOnWindow();
9359 mWindow->consumeMotionDown();
Prabir Pradhanedd96402022-02-15 01:46:16 -08009360 mFakePolicy->assertNotifyWindowUnresponsiveWasCalled(timeout, mWindow);
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009361 mWindow->consumeMotionUp();
9362
9363 mDispatcher->waitForIdle();
Prabir Pradhanedd96402022-02-15 01:46:16 -08009364 mFakePolicy->assertNotifyWindowResponsiveWasCalled(mWindow->getToken(), mWindow->getPid());
Siarhei Vishniakou234129c2020-10-22 22:28:12 -05009365 mFakePolicy->assertNotifyAnrWasNotCalled();
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009366 mWindow->assertNoEvents();
9367}
9368
Siarhei Vishniakou234129c2020-10-22 22:28:12 -05009369// If a connection remains unresponsive for a while, make sure policy is only notified once about
9370// it.
9371TEST_F(InputDispatcherSingleWindowAnr, Policy_DoesNotGetDuplicateAnr) {
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08009372 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07009373 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009374 WINDOW_LOCATION));
9375
9376 const std::chrono::duration windowTimeout = mWindow->getDispatchingTimeout(DISPATCHING_TIMEOUT);
Prabir Pradhanedd96402022-02-15 01:46:16 -08009377 mFakePolicy->assertNotifyWindowUnresponsiveWasCalled(windowTimeout, mWindow);
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009378 std::this_thread::sleep_for(windowTimeout);
Siarhei Vishniakou234129c2020-10-22 22:28:12 -05009379 // 'notifyConnectionUnresponsive' should only be called once per connection
9380 mFakePolicy->assertNotifyAnrWasNotCalled();
9381 // When the ANR happened, dispatcher should abort the current event stream via ACTION_CANCEL
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009382 mWindow->consumeMotionDown();
Siarhei Vishniakou1ae72f12023-01-29 12:55:30 -08009383 mWindow->consumeMotionEvent(
9384 AllOf(WithMotionAction(ACTION_CANCEL), WithDisplayId(ADISPLAY_ID_DEFAULT)));
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009385 mWindow->assertNoEvents();
Siarhei Vishniakou234129c2020-10-22 22:28:12 -05009386 mDispatcher->waitForIdle();
Prabir Pradhanedd96402022-02-15 01:46:16 -08009387 mFakePolicy->assertNotifyWindowResponsiveWasCalled(mWindow->getToken(), mWindow->getPid());
Siarhei Vishniakou234129c2020-10-22 22:28:12 -05009388 mFakePolicy->assertNotifyAnrWasNotCalled();
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009389}
9390
9391/**
9392 * 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 -07009393 * not get delivered to the focused window until the motion is processed.
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009394 */
9395TEST_F(InputDispatcherSingleWindowAnr, Key_StaysPendingWhileMotionIsProcessed) {
Siarhei Vishniakouef2b4502023-12-28 11:51:47 -08009396 // The timeouts in this test are established by relying on the fact that the "key waiting for
9397 // events timeout" is equal to 500ms.
9398 ASSERT_EQ(mFakePolicy->getKeyWaitingForEventsTimeout(), 500ms);
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009399 mWindow->setDispatchingTimeout(2s); // Set a long ANR timeout to prevent it from triggering
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07009400 mDispatcher->onWindowInfosChanged({{*mWindow->getInfo()}, {}, 0, 0});
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009401
9402 tapOnWindow();
Siarhei Vishniakoud3061ab2023-12-18 20:41:08 -08009403 const auto& [downSequenceNum, downEvent] = mWindow->receiveEvent();
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009404 ASSERT_TRUE(downSequenceNum);
Siarhei Vishniakoud3061ab2023-12-18 20:41:08 -08009405 const auto& [upSequenceNum, upEvent] = mWindow->receiveEvent();
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009406 ASSERT_TRUE(upSequenceNum);
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009407
Siarhei Vishniakouef2b4502023-12-28 11:51:47 -08009408 // Don't finish the events yet, and send a key
9409 mDispatcher->notifyKey(
9410 KeyArgsBuilder(AKEY_EVENT_ACTION_DOWN, AINPUT_SOURCE_KEYBOARD)
9411 .policyFlags(DEFAULT_POLICY_FLAGS | POLICY_FLAG_DISABLE_KEY_REPEAT)
9412 .build());
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009413 // Key will not be sent to the window, yet, because the window is still processing events
9414 // and the key remains pending, waiting for the touch events to be processed
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07009415 // Make sure that `assertNoEvents` doesn't wait too long, because it could cause an ANR.
Siarhei Vishniakouef2b4502023-12-28 11:51:47 -08009416 mWindow->assertNoEvents(100ms);
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009417
Siarhei Vishniakouef2b4502023-12-28 11:51:47 -08009418 std::this_thread::sleep_for(400ms);
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009419 // if we wait long enough though, dispatcher will give up, and still send the key
9420 // to the focused window, even though we have not yet finished the motion event
9421 mWindow->consumeKeyDown(ADISPLAY_ID_DEFAULT);
9422 mWindow->finishEvent(*downSequenceNum);
9423 mWindow->finishEvent(*upSequenceNum);
9424}
9425
9426/**
9427 * If a window is processing a motion event, and then a key event comes in, the key event should
9428 * not go to the focused window until the motion is processed.
9429 * If then a new motion comes in, then the pending key event should be going to the currently
9430 * focused window right away.
9431 */
9432TEST_F(InputDispatcherSingleWindowAnr,
Siarhei Vishniakouef2b4502023-12-28 11:51:47 -08009433 PendingKey_IsDeliveredWhileMotionIsProcessingAndNewTouchComesIn) {
9434 // The timeouts in this test are established by relying on the fact that the "key waiting for
9435 // events timeout" is equal to 500ms.
9436 ASSERT_EQ(mFakePolicy->getKeyWaitingForEventsTimeout(), 500ms);
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009437 mWindow->setDispatchingTimeout(2s); // Set a long ANR timeout to prevent it from triggering
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07009438 mDispatcher->onWindowInfosChanged({{*mWindow->getInfo()}, {}, 0, 0});
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009439
9440 tapOnWindow();
Siarhei Vishniakoud3061ab2023-12-18 20:41:08 -08009441 const auto& [downSequenceNum, _] = mWindow->receiveEvent();
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009442 ASSERT_TRUE(downSequenceNum);
Siarhei Vishniakoud3061ab2023-12-18 20:41:08 -08009443 const auto& [upSequenceNum, upEvent] = mWindow->receiveEvent();
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009444 ASSERT_TRUE(upSequenceNum);
9445 // Don't finish the events yet, and send a key
Siarhei Vishniakou67bf2162023-11-16 13:29:50 -08009446 mDispatcher->notifyKey(
9447 KeyArgsBuilder(AKEY_EVENT_ACTION_DOWN, AINPUT_SOURCE_KEYBOARD)
9448 .policyFlags(DEFAULT_POLICY_FLAGS | POLICY_FLAG_DISABLE_KEY_REPEAT)
9449 .build());
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009450 // At this point, key is still pending, and should not be sent to the application yet.
Siarhei Vishniakouef2b4502023-12-28 11:51:47 -08009451 mWindow->assertNoEvents(100ms);
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009452
9453 // Now tap down again. It should cause the pending key to go to the focused window right away.
9454 tapOnWindow();
Siarhei Vishniakouef2b4502023-12-28 11:51:47 -08009455 // Now that we tapped, we should receive the key immediately.
9456 // Since there's still room for slowness, we use 200ms, which is much less than
9457 // the "key waiting for events' timeout of 500ms minus the already waited 100ms duration.
9458 std::unique_ptr<InputEvent> keyEvent = mWindow->consume(200ms);
9459 ASSERT_NE(nullptr, keyEvent);
9460 ASSERT_EQ(InputEventType::KEY, keyEvent->getType());
9461 ASSERT_THAT(static_cast<KeyEvent&>(*keyEvent), WithKeyAction(AKEY_EVENT_ACTION_DOWN));
9462 // it doesn't matter that we haven't ack'd the other events yet. We can finish events in any
9463 // order.
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009464 mWindow->finishEvent(*downSequenceNum); // first tap's ACTION_DOWN
9465 mWindow->finishEvent(*upSequenceNum); // first tap's ACTION_UP
Siarhei Vishniakou67bf2162023-11-16 13:29:50 -08009466 mWindow->consumeMotionEvent(WithMotionAction(ACTION_DOWN));
9467 mWindow->consumeMotionEvent(WithMotionAction(ACTION_UP));
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009468 mWindow->assertNoEvents();
9469}
9470
Siarhei Vishniakouadb9fc92023-05-26 10:46:09 -07009471/**
9472 * Send an event to the app and have the app not respond right away.
9473 * When ANR is raised, policy will tell the dispatcher to cancel the events for that window.
9474 * So InputDispatcher will enqueue ACTION_CANCEL event as well.
9475 * At some point, the window becomes responsive again.
9476 * Ensure that subsequent events get dropped, and the next gesture is delivered.
9477 */
9478TEST_F(InputDispatcherSingleWindowAnr, TwoGesturesWithAnr) {
9479 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
9480 .pointer(PointerBuilder(0, ToolType::FINGER).x(10).y(10))
9481 .build());
9482
Siarhei Vishniakoud3061ab2023-12-18 20:41:08 -08009483 const auto [sequenceNum, _] = mWindow->receiveEvent(); // ACTION_DOWN
Siarhei Vishniakouadb9fc92023-05-26 10:46:09 -07009484 ASSERT_TRUE(sequenceNum);
9485 const std::chrono::duration timeout = mWindow->getDispatchingTimeout(DISPATCHING_TIMEOUT);
9486 mFakePolicy->assertNotifyWindowUnresponsiveWasCalled(timeout, mWindow);
9487
9488 mWindow->finishEvent(*sequenceNum);
9489 mWindow->consumeMotionEvent(WithMotionAction(ACTION_CANCEL));
9490 ASSERT_TRUE(mDispatcher->waitForIdle());
9491 mFakePolicy->assertNotifyWindowResponsiveWasCalled(mWindow->getToken(), mWindow->getPid());
9492
9493 // Now that the window is responsive, let's continue the gesture.
9494 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN)
9495 .pointer(PointerBuilder(0, ToolType::FINGER).x(11).y(11))
9496 .build());
9497
9498 mDispatcher->notifyMotion(MotionArgsBuilder(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
9499 .pointer(PointerBuilder(0, ToolType::FINGER).x(11).y(11))
9500 .pointer(PointerBuilder(1, ToolType::FINGER).x(3).y(3))
9501 .build());
9502
9503 mDispatcher->notifyMotion(MotionArgsBuilder(POINTER_1_UP, AINPUT_SOURCE_TOUCHSCREEN)
9504 .pointer(PointerBuilder(0, ToolType::FINGER).x(11).y(11))
9505 .pointer(PointerBuilder(1, ToolType::FINGER).x(3).y(3))
9506 .build());
9507 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN)
9508 .pointer(PointerBuilder(0, ToolType::FINGER).x(11).y(11))
9509 .build());
9510 // We already canceled this pointer, so the window shouldn't get any new events.
9511 mWindow->assertNoEvents();
9512
9513 // Start another one.
9514 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
9515 .pointer(PointerBuilder(0, ToolType::FINGER).x(15).y(15))
9516 .build());
9517 mWindow->consumeMotionEvent(WithMotionAction(ACTION_DOWN));
9518}
9519
Prabir Pradhanfc364722024-02-08 17:51:20 +00009520// Send an event to the app and have the app not respond right away. Then remove the app window.
9521// When the window is removed, the dispatcher will cancel the events for that window.
9522// So InputDispatcher will enqueue ACTION_CANCEL event as well.
9523TEST_F(InputDispatcherSingleWindowAnr, AnrAfterWindowRemoval) {
9524 mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_DOWN,
9525 AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
9526 {WINDOW_LOCATION}));
9527
9528 const auto [sequenceNum, _] = mWindow->receiveEvent(); // ACTION_DOWN
9529 ASSERT_TRUE(sequenceNum);
9530
9531 // Remove the window, but the input channel should remain alive.
9532 mDispatcher->onWindowInfosChanged({{}, {}, 0, 0});
9533
9534 const std::chrono::duration timeout = mWindow->getDispatchingTimeout(DISPATCHING_TIMEOUT);
9535 // Since the window was removed, Dispatcher does not know the PID associated with the window
9536 // anymore, so the policy is notified without the PID.
9537 mFakePolicy->assertNotifyWindowUnresponsiveWasCalled(timeout, mWindow->getToken(),
9538 /*pid=*/std::nullopt);
9539
9540 mWindow->finishEvent(*sequenceNum);
9541 // The cancellation was generated when the window was removed, along with the focus event.
9542 mWindow->consumeMotionEvent(
9543 AllOf(WithMotionAction(ACTION_CANCEL), WithDisplayId(ADISPLAY_ID_DEFAULT)));
9544 mWindow->consumeFocusEvent(false);
9545 ASSERT_TRUE(mDispatcher->waitForIdle());
9546 mFakePolicy->assertNotifyWindowResponsiveWasCalled(mWindow->getToken(), /*pid=*/std::nullopt);
9547}
9548
9549// Send an event to the app and have the app not respond right away. Wait for the policy to be
9550// notified of the unresponsive window, then remove the app window.
9551TEST_F(InputDispatcherSingleWindowAnr, AnrFollowedByWindowRemoval) {
9552 mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_DOWN,
9553 AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
9554 {WINDOW_LOCATION}));
9555
9556 const auto [sequenceNum, _] = mWindow->receiveEvent(); // ACTION_DOWN
9557 ASSERT_TRUE(sequenceNum);
9558 const std::chrono::duration timeout = mWindow->getDispatchingTimeout(DISPATCHING_TIMEOUT);
9559 mFakePolicy->assertNotifyWindowUnresponsiveWasCalled(timeout, mWindow);
9560
9561 // Remove the window, but the input channel should remain alive.
9562 mDispatcher->onWindowInfosChanged({{}, {}, 0, 0});
9563
9564 mWindow->finishEvent(*sequenceNum);
9565 // The cancellation was generated during the ANR, and the window lost focus when it was removed.
9566 mWindow->consumeMotionEvent(
9567 AllOf(WithMotionAction(ACTION_CANCEL), WithDisplayId(ADISPLAY_ID_DEFAULT)));
9568 mWindow->consumeFocusEvent(false);
9569 ASSERT_TRUE(mDispatcher->waitForIdle());
9570 // Since the window was removed, Dispatcher does not know the PID associated with the window
9571 // becoming responsive, so the policy is notified without the PID.
9572 mFakePolicy->assertNotifyWindowResponsiveWasCalled(mWindow->getToken(), /*pid=*/std::nullopt);
9573}
9574
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009575class InputDispatcherMultiWindowAnr : public InputDispatcherTest {
9576 virtual void SetUp() override {
9577 InputDispatcherTest::SetUp();
9578
Chris Yea209fde2020-07-22 13:54:51 -07009579 mApplication = std::make_shared<FakeApplicationHandle>();
Siarhei Vishniakouf83c6932023-07-07 17:48:10 -07009580 mApplication->setDispatchingTimeout(100ms);
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07009581 mUnfocusedWindow = sp<FakeWindowHandle>::make(mApplication, mDispatcher, "Unfocused",
9582 ADISPLAY_ID_DEFAULT);
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009583 mUnfocusedWindow->setFrame(Rect(0, 0, 30, 30));
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009584 // Adding FLAG_WATCH_OUTSIDE_TOUCH to receive ACTION_OUTSIDE when another window is tapped
Prabir Pradhan4d5c52f2022-01-31 08:52:10 -08009585 mUnfocusedWindow->setWatchOutsideTouch(true);
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009586
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07009587 mFocusedWindow = sp<FakeWindowHandle>::make(mApplication, mDispatcher, "Focused",
9588 ADISPLAY_ID_DEFAULT);
Siarhei Vishniakouf83c6932023-07-07 17:48:10 -07009589 mFocusedWindow->setDispatchingTimeout(100ms);
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009590 mFocusedWindow->setFrame(Rect(50, 50, 100, 100));
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009591
9592 // Set focused application.
9593 mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, mApplication);
Vishnu Nair47074b82020-08-14 11:54:47 -07009594 mFocusedWindow->setFocusable(true);
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009595
9596 // Expect one focus window exist in display.
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07009597 mDispatcher->onWindowInfosChanged(
9598 {{*mUnfocusedWindow->getInfo(), *mFocusedWindow->getInfo()}, {}, 0, 0});
Vishnu Nair958da932020-08-21 17:12:37 -07009599 setFocusedWindow(mFocusedWindow);
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009600 mFocusedWindow->consumeFocusEvent(true);
9601 }
9602
9603 virtual void TearDown() override {
9604 InputDispatcherTest::TearDown();
9605
9606 mUnfocusedWindow.clear();
9607 mFocusedWindow.clear();
9608 }
9609
9610protected:
Chris Yea209fde2020-07-22 13:54:51 -07009611 std::shared_ptr<FakeApplicationHandle> mApplication;
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009612 sp<FakeWindowHandle> mUnfocusedWindow;
9613 sp<FakeWindowHandle> mFocusedWindow;
9614 static constexpr PointF UNFOCUSED_WINDOW_LOCATION = {20, 20};
9615 static constexpr PointF FOCUSED_WINDOW_LOCATION = {75, 75};
9616 static constexpr PointF LOCATION_OUTSIDE_ALL_WINDOWS = {40, 40};
9617
9618 void tapOnFocusedWindow() { tap(FOCUSED_WINDOW_LOCATION); }
9619
9620 void tapOnUnfocusedWindow() { tap(UNFOCUSED_WINDOW_LOCATION); }
9621
9622private:
9623 void tap(const PointF& location) {
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08009624 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07009625 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009626 location));
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08009627 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07009628 injectMotionUp(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009629 location));
9630 }
9631};
9632
9633// If we have 2 windows that are both unresponsive, the one with the shortest timeout
9634// should be ANR'd first.
9635TEST_F(InputDispatcherMultiWindowAnr, TwoWindows_BothUnresponsive) {
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08009636 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakou2899c552023-07-10 18:20:46 -07009637 injectMotionEvent(*mDispatcher,
9638 MotionEventBuilder(AMOTION_EVENT_ACTION_DOWN,
9639 AINPUT_SOURCE_TOUCHSCREEN)
9640 .pointer(PointerBuilder(0, ToolType::FINGER)
9641 .x(FOCUSED_WINDOW_LOCATION.x)
9642 .y(FOCUSED_WINDOW_LOCATION.y))
9643 .build()));
9644 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
9645 injectMotionEvent(*mDispatcher,
9646 MotionEventBuilder(AMOTION_EVENT_ACTION_UP,
9647 AINPUT_SOURCE_TOUCHSCREEN)
9648 .pointer(PointerBuilder(0, ToolType::FINGER)
9649 .x(FOCUSED_WINDOW_LOCATION.x)
9650 .y(FOCUSED_WINDOW_LOCATION.y))
9651 .build()));
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009652 mFocusedWindow->consumeMotionDown();
Siarhei Vishniakou2899c552023-07-10 18:20:46 -07009653 mFocusedWindow->consumeMotionUp();
Prabir Pradhan7662a8d2023-12-15 01:58:14 +00009654 mUnfocusedWindow->consumeMotionOutside(ADISPLAY_ID_DEFAULT, /*flags=*/0);
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009655 // We consumed all events, so no ANR
9656 ASSERT_TRUE(mDispatcher->waitForIdle());
9657 mFakePolicy->assertNotifyAnrWasNotCalled();
9658
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08009659 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakou2899c552023-07-10 18:20:46 -07009660 injectMotionEvent(*mDispatcher,
9661 MotionEventBuilder(AMOTION_EVENT_ACTION_DOWN,
9662 AINPUT_SOURCE_TOUCHSCREEN)
9663 .pointer(PointerBuilder(0, ToolType::FINGER)
9664 .x(FOCUSED_WINDOW_LOCATION.x)
9665 .y(FOCUSED_WINDOW_LOCATION.y))
9666 .build()));
Siarhei Vishniakoud3061ab2023-12-18 20:41:08 -08009667 const auto [unfocusedSequenceNum, _] = mUnfocusedWindow->receiveEvent();
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009668 ASSERT_TRUE(unfocusedSequenceNum);
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009669
9670 const std::chrono::duration timeout =
9671 mFocusedWindow->getDispatchingTimeout(DISPATCHING_TIMEOUT);
Prabir Pradhanedd96402022-02-15 01:46:16 -08009672 mFakePolicy->assertNotifyWindowUnresponsiveWasCalled(timeout, mFocusedWindow);
Siarhei Vishniakou2899c552023-07-10 18:20:46 -07009673
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009674 mUnfocusedWindow->finishEvent(*unfocusedSequenceNum);
Siarhei Vishniakou234129c2020-10-22 22:28:12 -05009675 mFocusedWindow->consumeMotionDown();
9676 // This cancel is generated because the connection was unresponsive
9677 mFocusedWindow->consumeMotionCancel();
9678 mFocusedWindow->assertNoEvents();
9679 mUnfocusedWindow->assertNoEvents();
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009680 ASSERT_TRUE(mDispatcher->waitForIdle());
Prabir Pradhanedd96402022-02-15 01:46:16 -08009681 mFakePolicy->assertNotifyWindowResponsiveWasCalled(mFocusedWindow->getToken(),
9682 mFocusedWindow->getPid());
Siarhei Vishniakou234129c2020-10-22 22:28:12 -05009683 mFakePolicy->assertNotifyAnrWasNotCalled();
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009684}
9685
9686// If we have 2 windows with identical timeouts that are both unresponsive,
9687// it doesn't matter which order they should have ANR.
9688// But we should receive ANR for both.
9689TEST_F(InputDispatcherMultiWindowAnr, TwoWindows_BothUnresponsiveWithSameTimeout) {
9690 // Set the timeout for unfocused window to match the focused window
Siarhei Vishniakouf83c6932023-07-07 17:48:10 -07009691 mUnfocusedWindow->setDispatchingTimeout(
9692 mFocusedWindow->getDispatchingTimeout(DISPATCHING_TIMEOUT));
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07009693 mDispatcher->onWindowInfosChanged(
9694 {{*mUnfocusedWindow->getInfo(), *mFocusedWindow->getInfo()}, {}, 0, 0});
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009695
9696 tapOnFocusedWindow();
9697 // we should have ACTION_DOWN/ACTION_UP on focused window and ACTION_OUTSIDE on unfocused window
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009698 // We don't know which window will ANR first. But both of them should happen eventually.
Siarhei Vishniakouf83c6932023-07-07 17:48:10 -07009699 std::array<sp<IBinder>, 2> anrConnectionTokens = {mFakePolicy->getUnresponsiveWindowToken(
9700 mFocusedWindow->getDispatchingTimeout(
9701 DISPATCHING_TIMEOUT)),
9702 mFakePolicy->getUnresponsiveWindowToken(0ms)};
9703
9704 ASSERT_THAT(anrConnectionTokens,
9705 ::testing::UnorderedElementsAre(testing::Eq(mFocusedWindow->getToken()),
9706 testing::Eq(mUnfocusedWindow->getToken())));
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009707
9708 ASSERT_TRUE(mDispatcher->waitForIdle());
9709 mFakePolicy->assertNotifyAnrWasNotCalled();
Siarhei Vishniakou234129c2020-10-22 22:28:12 -05009710
9711 mFocusedWindow->consumeMotionDown();
9712 mFocusedWindow->consumeMotionUp();
9713 mUnfocusedWindow->consumeMotionOutside();
9714
Siarhei Vishniakouf83c6932023-07-07 17:48:10 -07009715 std::array<sp<IBinder>, 2> responsiveTokens = {mFakePolicy->getResponsiveWindowToken(),
9716 mFakePolicy->getResponsiveWindowToken()};
Siarhei Vishniakou234129c2020-10-22 22:28:12 -05009717
9718 // Both applications should be marked as responsive, in any order
Siarhei Vishniakouf83c6932023-07-07 17:48:10 -07009719 ASSERT_THAT(responsiveTokens,
9720 ::testing::UnorderedElementsAre(testing::Eq(mFocusedWindow->getToken()),
9721 testing::Eq(mUnfocusedWindow->getToken())));
Siarhei Vishniakou234129c2020-10-22 22:28:12 -05009722 mFakePolicy->assertNotifyAnrWasNotCalled();
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009723}
9724
9725// If a window is already not responding, the second tap on the same window should be ignored.
9726// We should also log an error to account for the dropped event (not tested here).
9727// At the same time, FLAG_WATCH_OUTSIDE_TOUCH targets should not receive any events.
9728TEST_F(InputDispatcherMultiWindowAnr, DuringAnr_SecondTapIsIgnored) {
9729 tapOnFocusedWindow();
Prabir Pradhan7662a8d2023-12-15 01:58:14 +00009730 mUnfocusedWindow->consumeMotionOutside(ADISPLAY_ID_DEFAULT, /*flags=*/0);
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009731 // Receive the events, but don't respond
Siarhei Vishniakoud3061ab2023-12-18 20:41:08 -08009732 const auto [downEventSequenceNum, downEvent] = mFocusedWindow->receiveEvent(); // ACTION_DOWN
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009733 ASSERT_TRUE(downEventSequenceNum);
Siarhei Vishniakoud3061ab2023-12-18 20:41:08 -08009734 const auto [upEventSequenceNum, upEvent] = mFocusedWindow->receiveEvent(); // ACTION_UP
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009735 ASSERT_TRUE(upEventSequenceNum);
9736 const std::chrono::duration timeout =
9737 mFocusedWindow->getDispatchingTimeout(DISPATCHING_TIMEOUT);
Prabir Pradhanedd96402022-02-15 01:46:16 -08009738 mFakePolicy->assertNotifyWindowUnresponsiveWasCalled(timeout, mFocusedWindow);
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009739
9740 // Tap once again
9741 // We cannot use "tapOnFocusedWindow" because it asserts the injection result to be success
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08009742 ASSERT_EQ(InputEventInjectionResult::FAILED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07009743 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009744 FOCUSED_WINDOW_LOCATION));
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08009745 ASSERT_EQ(InputEventInjectionResult::FAILED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07009746 injectMotionUp(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009747 FOCUSED_WINDOW_LOCATION));
9748 // Unfocused window does not receive ACTION_OUTSIDE because the tapped window is not a
9749 // valid touch target
9750 mUnfocusedWindow->assertNoEvents();
9751
9752 // Consume the first tap
9753 mFocusedWindow->finishEvent(*downEventSequenceNum);
9754 mFocusedWindow->finishEvent(*upEventSequenceNum);
9755 ASSERT_TRUE(mDispatcher->waitForIdle());
9756 // The second tap did not go to the focused window
9757 mFocusedWindow->assertNoEvents();
Siarhei Vishniakou234129c2020-10-22 22:28:12 -05009758 // Since all events are finished, connection should be deemed healthy again
Prabir Pradhanedd96402022-02-15 01:46:16 -08009759 mFakePolicy->assertNotifyWindowResponsiveWasCalled(mFocusedWindow->getToken(),
9760 mFocusedWindow->getPid());
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009761 mFakePolicy->assertNotifyAnrWasNotCalled();
9762}
9763
9764// If you tap outside of all windows, there will not be ANR
9765TEST_F(InputDispatcherMultiWindowAnr, TapOutsideAllWindows_DoesNotAnr) {
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08009766 ASSERT_EQ(InputEventInjectionResult::FAILED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07009767 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009768 LOCATION_OUTSIDE_ALL_WINDOWS));
9769 ASSERT_TRUE(mDispatcher->waitForIdle());
9770 mFakePolicy->assertNotifyAnrWasNotCalled();
9771}
9772
9773// Since the focused window is paused, tapping on it should not produce any events
9774TEST_F(InputDispatcherMultiWindowAnr, Window_CanBePaused) {
9775 mFocusedWindow->setPaused(true);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07009776 mDispatcher->onWindowInfosChanged(
9777 {{*mUnfocusedWindow->getInfo(), *mFocusedWindow->getInfo()}, {}, 0, 0});
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009778
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08009779 ASSERT_EQ(InputEventInjectionResult::FAILED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07009780 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009781 FOCUSED_WINDOW_LOCATION));
9782
9783 std::this_thread::sleep_for(mFocusedWindow->getDispatchingTimeout(DISPATCHING_TIMEOUT));
9784 ASSERT_TRUE(mDispatcher->waitForIdle());
9785 // Should not ANR because the window is paused, and touches shouldn't go to it
9786 mFakePolicy->assertNotifyAnrWasNotCalled();
9787
9788 mFocusedWindow->assertNoEvents();
9789 mUnfocusedWindow->assertNoEvents();
9790}
9791
9792/**
9793 * 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 -07009794 * not get delivered to the focused window until the motion is processed.
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009795 * If a different window becomes focused at this time, the key should go to that window instead.
9796 *
9797 * Warning!!!
9798 * This test depends on the value of android::inputdispatcher::KEY_WAITING_FOR_MOTION_TIMEOUT
9799 * and the injection timeout that we specify when injecting the key.
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07009800 * We must have the injection timeout (100ms) be smaller than
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009801 * KEY_WAITING_FOR_MOTION_TIMEOUT (currently 500ms).
9802 *
9803 * If that value changes, this test should also change.
9804 */
9805TEST_F(InputDispatcherMultiWindowAnr, PendingKey_GoesToNewlyFocusedWindow) {
9806 // Set a long ANR timeout to prevent it from triggering
9807 mFocusedWindow->setDispatchingTimeout(2s);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07009808 mDispatcher->onWindowInfosChanged(
9809 {{*mFocusedWindow->getInfo(), *mUnfocusedWindow->getInfo()}, {}, 0, 0});
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009810
9811 tapOnUnfocusedWindow();
Siarhei Vishniakoud3061ab2023-12-18 20:41:08 -08009812 const auto [downSequenceNum, downEvent] = mUnfocusedWindow->receiveEvent();
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009813 ASSERT_TRUE(downSequenceNum);
Siarhei Vishniakoud3061ab2023-12-18 20:41:08 -08009814 const auto [upSequenceNum, upEvent] = mUnfocusedWindow->receiveEvent();
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009815 ASSERT_TRUE(upSequenceNum);
9816 // Don't finish the events yet, and send a key
9817 // Injection will succeed because we will eventually give up and send the key to the focused
9818 // window even if motions are still being processed.
9819
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08009820 InputEventInjectionResult result =
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07009821 injectKey(*mDispatcher, AKEY_EVENT_ACTION_DOWN, /*repeatCount=*/0, ADISPLAY_ID_DEFAULT,
9822 InputEventInjectionSync::NONE, /*injectionTimeout=*/100ms);
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08009823 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, result);
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009824 // Key will not be sent to the window, yet, because the window is still processing events
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07009825 // and the key remains pending, waiting for the touch events to be processed.
9826 // Make sure `assertNoEvents` doesn't take too long. It uses CONSUME_TIMEOUT_NO_EVENT_EXPECTED
9827 // under the hood.
9828 static_assert(CONSUME_TIMEOUT_NO_EVENT_EXPECTED < 100ms);
9829 mFocusedWindow->assertNoEvents();
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009830
9831 // Switch the focus to the "unfocused" window that we tapped. Expect the key to go there
Vishnu Nair47074b82020-08-14 11:54:47 -07009832 mFocusedWindow->setFocusable(false);
9833 mUnfocusedWindow->setFocusable(true);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07009834 mDispatcher->onWindowInfosChanged(
9835 {{*mFocusedWindow->getInfo(), *mUnfocusedWindow->getInfo()}, {}, 0, 0});
Vishnu Nair958da932020-08-21 17:12:37 -07009836 setFocusedWindow(mUnfocusedWindow);
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009837
9838 // Focus events should precede the key events
9839 mUnfocusedWindow->consumeFocusEvent(true);
9840 mFocusedWindow->consumeFocusEvent(false);
9841
9842 // Finish the tap events, which should unblock dispatcher
9843 mUnfocusedWindow->finishEvent(*downSequenceNum);
9844 mUnfocusedWindow->finishEvent(*upSequenceNum);
9845
9846 // Now that all queues are cleared and no backlog in the connections, the key event
9847 // can finally go to the newly focused "mUnfocusedWindow".
9848 mUnfocusedWindow->consumeKeyDown(ADISPLAY_ID_DEFAULT);
9849 mFocusedWindow->assertNoEvents();
9850 mUnfocusedWindow->assertNoEvents();
Siarhei Vishniakou234129c2020-10-22 22:28:12 -05009851 mFakePolicy->assertNotifyAnrWasNotCalled();
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009852}
9853
9854// When the touch stream is split across 2 windows, and one of them does not respond,
9855// then ANR should be raised and the touch should be canceled for the unresponsive window.
9856// The other window should not be affected by that.
9857TEST_F(InputDispatcherMultiWindowAnr, SplitTouch_SingleWindowAnr) {
9858 // Touch Window 1
Prabir Pradhan678438e2023-04-13 19:32:51 +00009859 mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_DOWN,
9860 AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
9861 {FOCUSED_WINDOW_LOCATION}));
Prabir Pradhan7662a8d2023-12-15 01:58:14 +00009862 mUnfocusedWindow->consumeMotionOutside(ADISPLAY_ID_DEFAULT, /*flags=*/0);
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009863
9864 // Touch Window 2
Prabir Pradhan678438e2023-04-13 19:32:51 +00009865 mDispatcher->notifyMotion(
9866 generateMotionArgs(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
9867 {FOCUSED_WINDOW_LOCATION, UNFOCUSED_WINDOW_LOCATION}));
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009868
9869 const std::chrono::duration timeout =
9870 mFocusedWindow->getDispatchingTimeout(DISPATCHING_TIMEOUT);
Prabir Pradhanedd96402022-02-15 01:46:16 -08009871 mFakePolicy->assertNotifyWindowUnresponsiveWasCalled(timeout, mFocusedWindow);
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009872
9873 mUnfocusedWindow->consumeMotionDown();
9874 mFocusedWindow->consumeMotionDown();
9875 // Focused window may or may not receive ACTION_MOVE
9876 // But it should definitely receive ACTION_CANCEL due to the ANR
Siarhei Vishniakoud3061ab2023-12-18 20:41:08 -08009877 const auto [moveOrCancelSequenceNum, event] = mFocusedWindow->receiveEvent();
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009878 ASSERT_TRUE(moveOrCancelSequenceNum);
9879 mFocusedWindow->finishEvent(*moveOrCancelSequenceNum);
9880 ASSERT_NE(nullptr, event);
Siarhei Vishniakou63b63612023-04-12 11:00:23 -07009881 ASSERT_EQ(event->getType(), InputEventType::MOTION);
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009882 MotionEvent& motionEvent = static_cast<MotionEvent&>(*event);
9883 if (motionEvent.getAction() == AMOTION_EVENT_ACTION_MOVE) {
9884 mFocusedWindow->consumeMotionCancel();
9885 } else {
9886 ASSERT_EQ(AMOTION_EVENT_ACTION_CANCEL, motionEvent.getAction());
9887 }
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009888 ASSERT_TRUE(mDispatcher->waitForIdle());
Prabir Pradhanedd96402022-02-15 01:46:16 -08009889 mFakePolicy->assertNotifyWindowResponsiveWasCalled(mFocusedWindow->getToken(),
9890 mFocusedWindow->getPid());
Siarhei Vishniakou234129c2020-10-22 22:28:12 -05009891
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009892 mUnfocusedWindow->assertNoEvents();
9893 mFocusedWindow->assertNoEvents();
Siarhei Vishniakou234129c2020-10-22 22:28:12 -05009894 mFakePolicy->assertNotifyAnrWasNotCalled();
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009895}
9896
Siarhei Vishniakouf56b2692020-09-08 19:43:33 -05009897/**
9898 * If we have no focused window, and a key comes in, we start the ANR timer.
9899 * The focused application should add a focused window before the timer runs out to prevent ANR.
9900 *
9901 * If the user touches another application during this time, the key should be dropped.
9902 * Next, if a new focused window comes in, without toggling the focused application,
9903 * then no ANR should occur.
9904 *
9905 * Normally, we would expect the new focused window to be accompanied by 'setFocusedApplication',
9906 * but in some cases the policy may not update the focused application.
9907 */
9908TEST_F(InputDispatcherMultiWindowAnr, FocusedWindowWithoutSetFocusedApplication_NoAnr) {
9909 std::shared_ptr<FakeApplicationHandle> focusedApplication =
9910 std::make_shared<FakeApplicationHandle>();
Siarhei Vishniakouc033dfb2023-10-03 10:45:16 -07009911 focusedApplication->setDispatchingTimeout(300ms);
Siarhei Vishniakouf56b2692020-09-08 19:43:33 -05009912 mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, focusedApplication);
9913 // The application that owns 'mFocusedWindow' and 'mUnfocusedWindow' is not focused.
9914 mFocusedWindow->setFocusable(false);
9915
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07009916 mDispatcher->onWindowInfosChanged(
9917 {{*mFocusedWindow->getInfo(), *mUnfocusedWindow->getInfo()}, {}, 0, 0});
Siarhei Vishniakouf56b2692020-09-08 19:43:33 -05009918 mFocusedWindow->consumeFocusEvent(false);
9919
9920 // Send a key. The ANR timer should start because there is no focused window.
9921 // 'focusedApplication' will get blamed if this timer completes.
9922 // Key will not be sent anywhere because we have no focused window. It will remain pending.
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08009923 InputEventInjectionResult result =
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07009924 injectKey(*mDispatcher, AKEY_EVENT_ACTION_DOWN, /*repeatCount=*/0, ADISPLAY_ID_DEFAULT,
9925 InputEventInjectionSync::NONE, /*injectionTimeout=*/100ms,
Harry Cutts33476232023-01-30 19:57:29 +00009926 /*allowKeyRepeat=*/false);
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08009927 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, result);
Siarhei Vishniakouf56b2692020-09-08 19:43:33 -05009928
9929 // Wait until dispatcher starts the "no focused window" timer. If we don't wait here,
9930 // then the injected touches won't cause the focused event to get dropped.
9931 // The dispatcher only checks for whether the queue should be pruned upon queueing.
9932 // If we inject the touch right away and the ANR timer hasn't started, the touch event would
9933 // simply be added to the queue without 'shouldPruneInboundQueueLocked' returning 'true'.
9934 // For this test, it means that the key would get delivered to the window once it becomes
9935 // focused.
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07009936 std::this_thread::sleep_for(100ms);
Siarhei Vishniakouf56b2692020-09-08 19:43:33 -05009937
9938 // Touch unfocused window. This should force the pending key to get dropped.
Prabir Pradhan678438e2023-04-13 19:32:51 +00009939 mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_DOWN,
9940 AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
9941 {UNFOCUSED_WINDOW_LOCATION}));
Siarhei Vishniakouf56b2692020-09-08 19:43:33 -05009942
9943 // We do not consume the motion right away, because that would require dispatcher to first
9944 // process (== drop) the key event, and by that time, ANR will be raised.
9945 // Set the focused window first.
9946 mFocusedWindow->setFocusable(true);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07009947 mDispatcher->onWindowInfosChanged(
9948 {{*mFocusedWindow->getInfo(), *mUnfocusedWindow->getInfo()}, {}, 0, 0});
Siarhei Vishniakouf56b2692020-09-08 19:43:33 -05009949 setFocusedWindow(mFocusedWindow);
9950 mFocusedWindow->consumeFocusEvent(true);
9951 // We do not call "setFocusedApplication" here, even though the newly focused window belongs
9952 // to another application. This could be a bug / behaviour in the policy.
9953
9954 mUnfocusedWindow->consumeMotionDown();
9955
9956 ASSERT_TRUE(mDispatcher->waitForIdle());
9957 // Should not ANR because we actually have a focused window. It was just added too slowly.
9958 ASSERT_NO_FATAL_FAILURE(mFakePolicy->assertNotifyAnrWasNotCalled());
9959}
9960
Siarhei Vishniakou99e407b2023-12-26 18:09:32 -08009961/**
9962 * If we are pruning input queue, we should never drop pointer events. Otherwise, we risk having
9963 * an inconsistent event stream inside the dispatcher. In this test, we make sure that the
9964 * dispatcher doesn't prune pointer events incorrectly.
9965 *
9966 * This test reproduces a crash in InputDispatcher.
9967 * To reproduce the crash, we need to simulate the conditions for "pruning input queue" to occur.
9968 *
9969 * Keep the currently focused application (mApplication), and have no focused window.
9970 * We set up two additional windows:
9971 * 1) The navigation bar window. This simulates the system "NavigationBar", which is used in the
9972 * 3-button navigation mode. This window injects a BACK button when it's touched. 2) The application
9973 * window. This window is not focusable, but is touchable.
9974 *
9975 * We first touch the navigation bar, which causes it to inject a key. Since there's no focused
9976 * window, the dispatcher doesn't process this key, and all other events inside dispatcher are now
9977 * blocked. The dispatcher is waiting for 'mApplication' to add a focused window.
9978 *
9979 * Now, we touch "Another window". This window is owned by a different application than
9980 * 'mApplication'. This causes the dispatcher to stop waiting for 'mApplication' to add a focused
9981 * window. Now, the "pruning input queue" behaviour should kick in, and the dispatcher should start
9982 * dropping the events from its queue. Ensure that no crash occurs.
9983 *
9984 * In this test, we are setting long timeouts to prevent ANRs and events dropped due to being stale.
9985 * This does not affect the test running time.
9986 */
9987TEST_F(InputDispatcherMultiWindowAnr, PruningInputQueueShouldNotDropPointerEvents) {
9988 std::shared_ptr<FakeApplicationHandle> systemUiApplication =
9989 std::make_shared<FakeApplicationHandle>();
9990 systemUiApplication->setDispatchingTimeout(3000ms);
9991 mFakePolicy->setStaleEventTimeout(3000ms);
9992 sp<FakeWindowHandle> navigationBar =
9993 sp<FakeWindowHandle>::make(systemUiApplication, mDispatcher, "NavigationBar",
9994 ADISPLAY_ID_DEFAULT);
9995 navigationBar->setFocusable(false);
9996 navigationBar->setWatchOutsideTouch(true);
9997 navigationBar->setFrame(Rect(0, 0, 100, 100));
9998
9999 mApplication->setDispatchingTimeout(3000ms);
10000 // 'mApplication' is already focused, but we call it again here to make it explicit.
10001 mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, mApplication);
10002
10003 std::shared_ptr<FakeApplicationHandle> anotherApplication =
10004 std::make_shared<FakeApplicationHandle>();
10005 sp<FakeWindowHandle> appWindow =
10006 sp<FakeWindowHandle>::make(anotherApplication, mDispatcher, "Another window",
10007 ADISPLAY_ID_DEFAULT);
10008 appWindow->setFocusable(false);
10009 appWindow->setFrame(Rect(100, 100, 200, 200));
10010
10011 mDispatcher->onWindowInfosChanged(
10012 {{*navigationBar->getInfo(), *appWindow->getInfo()}, {}, 0, 0});
10013 // 'mFocusedWindow' is no longer in the dispatcher window list, and therefore loses focus
10014 mFocusedWindow->consumeFocusEvent(false);
10015
10016 // Touch down the navigation bar. It consumes the touch and injects a key into the dispatcher
10017 // in response.
10018 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
10019 .pointer(PointerBuilder(0, ToolType::FINGER).x(50).y(50))
10020 .build());
10021 navigationBar->consumeMotionEvent(WithMotionAction(ACTION_DOWN));
10022
10023 // Key will not be sent anywhere because we have no focused window. It will remain pending.
10024 // Pretend we are injecting KEYCODE_BACK, but it doesn't actually matter what key it is.
10025 InputEventInjectionResult result =
10026 injectKey(*mDispatcher, AKEY_EVENT_ACTION_DOWN, /*repeatCount=*/0, ADISPLAY_ID_DEFAULT,
10027 InputEventInjectionSync::NONE, /*injectionTimeout=*/100ms,
10028 /*allowKeyRepeat=*/false);
10029 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, result);
10030
10031 // Finish the gesture - lift up finger and inject ACTION_UP key event
10032 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN)
10033 .pointer(PointerBuilder(0, ToolType::FINGER).x(50).y(50))
10034 .build());
10035 result = injectKey(*mDispatcher, AKEY_EVENT_ACTION_UP, /*repeatCount=*/0, ADISPLAY_ID_DEFAULT,
10036 InputEventInjectionSync::NONE, /*injectionTimeout=*/100ms,
10037 /*allowKeyRepeat=*/false);
10038 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, result);
10039 // The key that was injected is blocking the dispatcher, so the navigation bar shouldn't be
10040 // getting any events yet.
10041 navigationBar->assertNoEvents();
10042
10043 // Now touch "Another window". This touch is going to a different application than the one we
10044 // are waiting for (which is 'mApplication').
10045 // This should cause the dispatcher to drop the pending focus-dispatched events (like the key
10046 // trying to be injected) and to continue processing the rest of the events in the original
10047 // order.
10048 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
10049 .pointer(PointerBuilder(0, ToolType::FINGER).x(150).y(150))
10050 .build());
10051 navigationBar->consumeMotionEvent(WithMotionAction(ACTION_UP));
10052 navigationBar->consumeMotionEvent(WithMotionAction(ACTION_OUTSIDE));
10053 appWindow->consumeMotionEvent(WithMotionAction(ACTION_DOWN));
10054
10055 appWindow->assertNoEvents();
10056 navigationBar->assertNoEvents();
10057}
10058
Siarhei Vishniakoua2862a02020-07-20 16:36:46 -050010059// These tests ensure we cannot send touch events to a window that's positioned behind a window
10060// that has feature NO_INPUT_CHANNEL.
10061// Layout:
10062// Top (closest to user)
10063// mNoInputWindow (above all windows)
10064// mBottomWindow
10065// Bottom (furthest from user)
10066class InputDispatcherMultiWindowOcclusionTests : public InputDispatcherTest {
10067 virtual void SetUp() override {
10068 InputDispatcherTest::SetUp();
10069
10070 mApplication = std::make_shared<FakeApplicationHandle>();
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -070010071 mNoInputWindow =
10072 sp<FakeWindowHandle>::make(mApplication, mDispatcher,
10073 "Window without input channel", ADISPLAY_ID_DEFAULT,
Prabir Pradhane7cc69c2024-01-05 21:35:28 +000010074 /*createInputChannel=*/false);
Prabir Pradhan51e7db02022-02-07 06:02:57 -080010075 mNoInputWindow->setNoInputChannel(true);
Siarhei Vishniakoua2862a02020-07-20 16:36:46 -050010076 mNoInputWindow->setFrame(Rect(0, 0, 100, 100));
10077 // It's perfectly valid for this window to not have an associated input channel
10078
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -070010079 mBottomWindow = sp<FakeWindowHandle>::make(mApplication, mDispatcher, "Bottom window",
10080 ADISPLAY_ID_DEFAULT);
Siarhei Vishniakoua2862a02020-07-20 16:36:46 -050010081 mBottomWindow->setFrame(Rect(0, 0, 100, 100));
10082
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070010083 mDispatcher->onWindowInfosChanged(
10084 {{*mNoInputWindow->getInfo(), *mBottomWindow->getInfo()}, {}, 0, 0});
Siarhei Vishniakoua2862a02020-07-20 16:36:46 -050010085 }
10086
10087protected:
10088 std::shared_ptr<FakeApplicationHandle> mApplication;
10089 sp<FakeWindowHandle> mNoInputWindow;
10090 sp<FakeWindowHandle> mBottomWindow;
10091};
10092
10093TEST_F(InputDispatcherMultiWindowOcclusionTests, NoInputChannelFeature_DropsTouches) {
10094 PointF touchedPoint = {10, 10};
10095
Prabir Pradhan678438e2023-04-13 19:32:51 +000010096 mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_DOWN,
10097 AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
10098 {touchedPoint}));
Siarhei Vishniakoua2862a02020-07-20 16:36:46 -050010099
10100 mNoInputWindow->assertNoEvents();
10101 // Even though the window 'mNoInputWindow' positioned above 'mBottomWindow' does not have
10102 // an input channel, it is not marked as FLAG_NOT_TOUCHABLE,
10103 // and therefore should prevent mBottomWindow from receiving touches
10104 mBottomWindow->assertNoEvents();
10105}
10106
10107/**
10108 * If a window has feature NO_INPUT_CHANNEL, and somehow (by mistake) still has an input channel,
10109 * ensure that this window does not receive any touches, and blocks touches to windows underneath.
10110 */
10111TEST_F(InputDispatcherMultiWindowOcclusionTests,
10112 NoInputChannelFeature_DropsTouchesWithValidChannel) {
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -070010113 mNoInputWindow = sp<FakeWindowHandle>::make(mApplication, mDispatcher,
10114 "Window with input channel and NO_INPUT_CHANNEL",
10115 ADISPLAY_ID_DEFAULT);
Siarhei Vishniakoua2862a02020-07-20 16:36:46 -050010116
Prabir Pradhan51e7db02022-02-07 06:02:57 -080010117 mNoInputWindow->setNoInputChannel(true);
Siarhei Vishniakoua2862a02020-07-20 16:36:46 -050010118 mNoInputWindow->setFrame(Rect(0, 0, 100, 100));
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070010119 mDispatcher->onWindowInfosChanged(
10120 {{*mNoInputWindow->getInfo(), *mBottomWindow->getInfo()}, {}, 0, 0});
Siarhei Vishniakoua2862a02020-07-20 16:36:46 -050010121
10122 PointF touchedPoint = {10, 10};
10123
Prabir Pradhan678438e2023-04-13 19:32:51 +000010124 mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_DOWN,
10125 AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
10126 {touchedPoint}));
Siarhei Vishniakoua2862a02020-07-20 16:36:46 -050010127
10128 mNoInputWindow->assertNoEvents();
10129 mBottomWindow->assertNoEvents();
10130}
10131
Vishnu Nair958da932020-08-21 17:12:37 -070010132class InputDispatcherMirrorWindowFocusTests : public InputDispatcherTest {
10133protected:
10134 std::shared_ptr<FakeApplicationHandle> mApp;
10135 sp<FakeWindowHandle> mWindow;
10136 sp<FakeWindowHandle> mMirror;
10137
10138 virtual void SetUp() override {
10139 InputDispatcherTest::SetUp();
10140 mApp = std::make_shared<FakeApplicationHandle>();
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -070010141 mWindow = sp<FakeWindowHandle>::make(mApp, mDispatcher, "TestWindow", ADISPLAY_ID_DEFAULT);
Prabir Pradhane7cc69c2024-01-05 21:35:28 +000010142 mMirror = mWindow->clone(ADISPLAY_ID_DEFAULT);
Vishnu Nair958da932020-08-21 17:12:37 -070010143 mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, mApp);
10144 mWindow->setFocusable(true);
10145 mMirror->setFocusable(true);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070010146 mDispatcher->onWindowInfosChanged({{*mWindow->getInfo(), *mMirror->getInfo()}, {}, 0, 0});
Vishnu Nair958da932020-08-21 17:12:37 -070010147 }
10148};
10149
10150TEST_F(InputDispatcherMirrorWindowFocusTests, CanGetFocus) {
10151 // Request focus on a mirrored window
10152 setFocusedWindow(mMirror);
10153
10154 // window gets focused
10155 mWindow->consumeFocusEvent(true);
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070010156 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectKeyDown(*mDispatcher))
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -080010157 << "Inject key event should return InputEventInjectionResult::SUCCEEDED";
Vishnu Nair958da932020-08-21 17:12:37 -070010158 mWindow->consumeKeyDown(ADISPLAY_ID_NONE);
10159}
10160
10161// A focused & mirrored window remains focused only if the window and its mirror are both
10162// focusable.
10163TEST_F(InputDispatcherMirrorWindowFocusTests, FocusedIfAllWindowsFocusable) {
10164 setFocusedWindow(mMirror);
10165
Prabir Pradhanbb3f1c02024-01-04 20:17:14 +000010166 // window gets focused because it is above the mirror
Vishnu Nair958da932020-08-21 17:12:37 -070010167 mWindow->consumeFocusEvent(true);
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070010168 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectKeyDown(*mDispatcher))
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -080010169 << "Inject key event should return InputEventInjectionResult::SUCCEEDED";
Vishnu Nair958da932020-08-21 17:12:37 -070010170 mWindow->consumeKeyDown(ADISPLAY_ID_NONE);
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070010171 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectKeyUp(*mDispatcher))
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -080010172 << "Inject key event should return InputEventInjectionResult::SUCCEEDED";
Vishnu Nair958da932020-08-21 17:12:37 -070010173 mWindow->consumeKeyUp(ADISPLAY_ID_NONE);
10174
10175 mMirror->setFocusable(false);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070010176 mDispatcher->onWindowInfosChanged({{*mWindow->getInfo(), *mMirror->getInfo()}, {}, 0, 0});
Vishnu Nair958da932020-08-21 17:12:37 -070010177
10178 // window loses focus since one of the windows associated with the token in not focusable
10179 mWindow->consumeFocusEvent(false);
10180
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070010181 ASSERT_EQ(InputEventInjectionResult::TIMED_OUT, injectKeyDown(*mDispatcher))
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -080010182 << "Inject key event should return InputEventInjectionResult::TIMED_OUT";
Vishnu Nair958da932020-08-21 17:12:37 -070010183 mWindow->assertNoEvents();
10184}
10185
10186// A focused & mirrored window remains focused until the window and its mirror both become
10187// invisible.
10188TEST_F(InputDispatcherMirrorWindowFocusTests, FocusedIfAnyWindowVisible) {
10189 setFocusedWindow(mMirror);
10190
10191 // window gets focused
10192 mWindow->consumeFocusEvent(true);
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070010193 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectKeyDown(*mDispatcher))
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -080010194 << "Inject key event should return InputEventInjectionResult::SUCCEEDED";
Vishnu Nair958da932020-08-21 17:12:37 -070010195 mWindow->consumeKeyDown(ADISPLAY_ID_NONE);
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070010196 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectKeyUp(*mDispatcher))
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -080010197 << "Inject key event should return InputEventInjectionResult::SUCCEEDED";
Vishnu Nair958da932020-08-21 17:12:37 -070010198 mWindow->consumeKeyUp(ADISPLAY_ID_NONE);
10199
10200 mMirror->setVisible(false);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070010201 mDispatcher->onWindowInfosChanged({{*mWindow->getInfo(), *mMirror->getInfo()}, {}, 0, 0});
Vishnu Nair958da932020-08-21 17:12:37 -070010202
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070010203 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectKeyDown(*mDispatcher))
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -080010204 << "Inject key event should return InputEventInjectionResult::SUCCEEDED";
Vishnu Nair958da932020-08-21 17:12:37 -070010205 mWindow->consumeKeyDown(ADISPLAY_ID_NONE);
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070010206 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectKeyUp(*mDispatcher))
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -080010207 << "Inject key event should return InputEventInjectionResult::SUCCEEDED";
Vishnu Nair958da932020-08-21 17:12:37 -070010208 mWindow->consumeKeyUp(ADISPLAY_ID_NONE);
10209
10210 mWindow->setVisible(false);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070010211 mDispatcher->onWindowInfosChanged({{*mWindow->getInfo(), *mMirror->getInfo()}, {}, 0, 0});
Vishnu Nair958da932020-08-21 17:12:37 -070010212
10213 // window loses focus only after all windows associated with the token become invisible.
10214 mWindow->consumeFocusEvent(false);
10215
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070010216 ASSERT_EQ(InputEventInjectionResult::TIMED_OUT, injectKeyDown(*mDispatcher))
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -080010217 << "Inject key event should return InputEventInjectionResult::TIMED_OUT";
Vishnu Nair958da932020-08-21 17:12:37 -070010218 mWindow->assertNoEvents();
10219}
10220
10221// A focused & mirrored window remains focused until both windows are removed.
10222TEST_F(InputDispatcherMirrorWindowFocusTests, FocusedWhileWindowsAlive) {
10223 setFocusedWindow(mMirror);
10224
10225 // window gets focused
10226 mWindow->consumeFocusEvent(true);
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070010227 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectKeyDown(*mDispatcher))
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -080010228 << "Inject key event should return InputEventInjectionResult::SUCCEEDED";
Vishnu Nair958da932020-08-21 17:12:37 -070010229 mWindow->consumeKeyDown(ADISPLAY_ID_NONE);
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070010230 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectKeyUp(*mDispatcher))
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -080010231 << "Inject key event should return InputEventInjectionResult::SUCCEEDED";
Vishnu Nair958da932020-08-21 17:12:37 -070010232 mWindow->consumeKeyUp(ADISPLAY_ID_NONE);
10233
10234 // single window is removed but the window token remains focused
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070010235 mDispatcher->onWindowInfosChanged({{*mMirror->getInfo()}, {}, 0, 0});
Vishnu Nair958da932020-08-21 17:12:37 -070010236
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070010237 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectKeyDown(*mDispatcher))
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -080010238 << "Inject key event should return InputEventInjectionResult::SUCCEEDED";
Prabir Pradhanbb3f1c02024-01-04 20:17:14 +000010239 mMirror->consumeKeyDown(ADISPLAY_ID_NONE);
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070010240 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectKeyUp(*mDispatcher))
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -080010241 << "Inject key event should return InputEventInjectionResult::SUCCEEDED";
Prabir Pradhanbb3f1c02024-01-04 20:17:14 +000010242 mMirror->consumeKeyUp(ADISPLAY_ID_NONE);
Vishnu Nair958da932020-08-21 17:12:37 -070010243
10244 // Both windows are removed
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070010245 mDispatcher->onWindowInfosChanged({{}, {}, 0, 0});
Vishnu Nair958da932020-08-21 17:12:37 -070010246 mWindow->consumeFocusEvent(false);
10247
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070010248 ASSERT_EQ(InputEventInjectionResult::TIMED_OUT, injectKeyDown(*mDispatcher))
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -080010249 << "Inject key event should return InputEventInjectionResult::TIMED_OUT";
Vishnu Nair958da932020-08-21 17:12:37 -070010250 mWindow->assertNoEvents();
10251}
10252
10253// Focus request can be pending until one window becomes visible.
10254TEST_F(InputDispatcherMirrorWindowFocusTests, DeferFocusWhenInvisible) {
10255 // Request focus on an invisible mirror.
10256 mWindow->setVisible(false);
10257 mMirror->setVisible(false);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070010258 mDispatcher->onWindowInfosChanged({{*mWindow->getInfo(), *mMirror->getInfo()}, {}, 0, 0});
Vishnu Nair958da932020-08-21 17:12:37 -070010259 setFocusedWindow(mMirror);
10260
10261 // Injected key goes to pending queue.
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -080010262 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070010263 injectKey(*mDispatcher, AKEY_EVENT_ACTION_DOWN, /*repeatCount=*/0,
10264 ADISPLAY_ID_DEFAULT, InputEventInjectionSync::NONE));
Vishnu Nair958da932020-08-21 17:12:37 -070010265
10266 mMirror->setVisible(true);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070010267 mDispatcher->onWindowInfosChanged({{*mWindow->getInfo(), *mMirror->getInfo()}, {}, 0, 0});
Vishnu Nair958da932020-08-21 17:12:37 -070010268
10269 // window gets focused
10270 mWindow->consumeFocusEvent(true);
10271 // window gets the pending key event
10272 mWindow->consumeKeyDown(ADISPLAY_ID_DEFAULT);
10273}
Prabir Pradhan99987712020-11-10 18:43:05 -080010274
10275class InputDispatcherPointerCaptureTests : public InputDispatcherTest {
10276protected:
10277 std::shared_ptr<FakeApplicationHandle> mApp;
10278 sp<FakeWindowHandle> mWindow;
10279 sp<FakeWindowHandle> mSecondWindow;
10280
10281 void SetUp() override {
10282 InputDispatcherTest::SetUp();
10283 mApp = std::make_shared<FakeApplicationHandle>();
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -070010284 mWindow = sp<FakeWindowHandle>::make(mApp, mDispatcher, "TestWindow", ADISPLAY_ID_DEFAULT);
Prabir Pradhan99987712020-11-10 18:43:05 -080010285 mWindow->setFocusable(true);
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -070010286 mSecondWindow =
10287 sp<FakeWindowHandle>::make(mApp, mDispatcher, "TestWindow2", ADISPLAY_ID_DEFAULT);
Prabir Pradhan99987712020-11-10 18:43:05 -080010288 mSecondWindow->setFocusable(true);
10289
10290 mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, mApp);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070010291 mDispatcher->onWindowInfosChanged(
10292 {{*mWindow->getInfo(), *mSecondWindow->getInfo()}, {}, 0, 0});
Prabir Pradhan99987712020-11-10 18:43:05 -080010293
10294 setFocusedWindow(mWindow);
10295 mWindow->consumeFocusEvent(true);
10296 }
10297
Prabir Pradhan5cc1a692021-08-06 14:01:18 +000010298 void notifyPointerCaptureChanged(const PointerCaptureRequest& request) {
Prabir Pradhan678438e2023-04-13 19:32:51 +000010299 mDispatcher->notifyPointerCaptureChanged(generatePointerCaptureChangedArgs(request));
Prabir Pradhan99987712020-11-10 18:43:05 -080010300 }
10301
Prabir Pradhan5cc1a692021-08-06 14:01:18 +000010302 PointerCaptureRequest requestAndVerifyPointerCapture(const sp<FakeWindowHandle>& window,
10303 bool enabled) {
Prabir Pradhan99987712020-11-10 18:43:05 -080010304 mDispatcher->requestPointerCapture(window->getToken(), enabled);
Hiroki Sato25040232024-02-22 17:21:22 +090010305 auto request = mFakePolicy->assertSetPointerCaptureCalled(window, enabled);
Prabir Pradhan5cc1a692021-08-06 14:01:18 +000010306 notifyPointerCaptureChanged(request);
Prabir Pradhan99987712020-11-10 18:43:05 -080010307 window->consumeCaptureEvent(enabled);
Prabir Pradhan5cc1a692021-08-06 14:01:18 +000010308 return request;
Prabir Pradhan99987712020-11-10 18:43:05 -080010309 }
10310};
10311
10312TEST_F(InputDispatcherPointerCaptureTests, EnablePointerCaptureWhenFocused) {
10313 // Ensure that capture cannot be obtained for unfocused windows.
10314 mDispatcher->requestPointerCapture(mSecondWindow->getToken(), true);
10315 mFakePolicy->assertSetPointerCaptureNotCalled();
10316 mSecondWindow->assertNoEvents();
10317
10318 // Ensure that capture can be enabled from the focus window.
10319 requestAndVerifyPointerCapture(mWindow, true);
10320
10321 // Ensure that capture cannot be disabled from a window that does not have capture.
10322 mDispatcher->requestPointerCapture(mSecondWindow->getToken(), false);
10323 mFakePolicy->assertSetPointerCaptureNotCalled();
10324
10325 // Ensure that capture can be disabled from the window with capture.
10326 requestAndVerifyPointerCapture(mWindow, false);
10327}
10328
10329TEST_F(InputDispatcherPointerCaptureTests, DisablesPointerCaptureAfterWindowLosesFocus) {
Prabir Pradhan5cc1a692021-08-06 14:01:18 +000010330 auto request = requestAndVerifyPointerCapture(mWindow, true);
Prabir Pradhan99987712020-11-10 18:43:05 -080010331
10332 setFocusedWindow(mSecondWindow);
10333
10334 // Ensure that the capture disabled event was sent first.
10335 mWindow->consumeCaptureEvent(false);
10336 mWindow->consumeFocusEvent(false);
10337 mSecondWindow->consumeFocusEvent(true);
Hiroki Sato25040232024-02-22 17:21:22 +090010338 mFakePolicy->assertSetPointerCaptureCalled(mWindow, false);
Prabir Pradhan99987712020-11-10 18:43:05 -080010339
10340 // Ensure that additional state changes from InputReader are not sent to the window.
Prabir Pradhan5cc1a692021-08-06 14:01:18 +000010341 notifyPointerCaptureChanged({});
10342 notifyPointerCaptureChanged(request);
10343 notifyPointerCaptureChanged({});
Prabir Pradhan99987712020-11-10 18:43:05 -080010344 mWindow->assertNoEvents();
10345 mSecondWindow->assertNoEvents();
10346 mFakePolicy->assertSetPointerCaptureNotCalled();
10347}
10348
10349TEST_F(InputDispatcherPointerCaptureTests, UnexpectedStateChangeDisablesPointerCapture) {
Prabir Pradhan5cc1a692021-08-06 14:01:18 +000010350 auto request = requestAndVerifyPointerCapture(mWindow, true);
Prabir Pradhan99987712020-11-10 18:43:05 -080010351
10352 // InputReader unexpectedly disables and enables pointer capture.
Prabir Pradhan5cc1a692021-08-06 14:01:18 +000010353 notifyPointerCaptureChanged({});
10354 notifyPointerCaptureChanged(request);
Prabir Pradhan99987712020-11-10 18:43:05 -080010355
10356 // Ensure that Pointer Capture is disabled.
Hiroki Sato25040232024-02-22 17:21:22 +090010357 mFakePolicy->assertSetPointerCaptureCalled(mWindow, false);
Prabir Pradhan99987712020-11-10 18:43:05 -080010358 mWindow->consumeCaptureEvent(false);
10359 mWindow->assertNoEvents();
10360}
10361
Prabir Pradhan167e6d92021-02-04 16:18:17 -080010362TEST_F(InputDispatcherPointerCaptureTests, OutOfOrderRequests) {
10363 requestAndVerifyPointerCapture(mWindow, true);
10364
10365 // The first window loses focus.
10366 setFocusedWindow(mSecondWindow);
Hiroki Sato25040232024-02-22 17:21:22 +090010367 mFakePolicy->assertSetPointerCaptureCalled(mWindow, false);
Prabir Pradhan167e6d92021-02-04 16:18:17 -080010368 mWindow->consumeCaptureEvent(false);
10369
10370 // Request Pointer Capture from the second window before the notification from InputReader
10371 // arrives.
10372 mDispatcher->requestPointerCapture(mSecondWindow->getToken(), true);
Hiroki Sato25040232024-02-22 17:21:22 +090010373 auto request = mFakePolicy->assertSetPointerCaptureCalled(mSecondWindow, true);
Prabir Pradhan167e6d92021-02-04 16:18:17 -080010374
10375 // InputReader notifies Pointer Capture was disabled (because of the focus change).
Prabir Pradhan5cc1a692021-08-06 14:01:18 +000010376 notifyPointerCaptureChanged({});
Prabir Pradhan167e6d92021-02-04 16:18:17 -080010377
10378 // InputReader notifies Pointer Capture was enabled (because of mSecondWindow's request).
Prabir Pradhan5cc1a692021-08-06 14:01:18 +000010379 notifyPointerCaptureChanged(request);
Prabir Pradhan167e6d92021-02-04 16:18:17 -080010380
10381 mSecondWindow->consumeFocusEvent(true);
10382 mSecondWindow->consumeCaptureEvent(true);
10383}
10384
Prabir Pradhan5cc1a692021-08-06 14:01:18 +000010385TEST_F(InputDispatcherPointerCaptureTests, EnableRequestFollowsSequenceNumbers) {
10386 // App repeatedly enables and disables capture.
10387 mDispatcher->requestPointerCapture(mWindow->getToken(), true);
Hiroki Sato25040232024-02-22 17:21:22 +090010388 auto firstRequest = mFakePolicy->assertSetPointerCaptureCalled(mWindow, true);
Prabir Pradhan5cc1a692021-08-06 14:01:18 +000010389 mDispatcher->requestPointerCapture(mWindow->getToken(), false);
Hiroki Sato25040232024-02-22 17:21:22 +090010390 mFakePolicy->assertSetPointerCaptureCalled(mWindow, false);
Prabir Pradhan5cc1a692021-08-06 14:01:18 +000010391 mDispatcher->requestPointerCapture(mWindow->getToken(), true);
Hiroki Sato25040232024-02-22 17:21:22 +090010392 auto secondRequest = mFakePolicy->assertSetPointerCaptureCalled(mWindow, true);
Prabir Pradhan5cc1a692021-08-06 14:01:18 +000010393
10394 // InputReader notifies that PointerCapture has been enabled for the first request. Since the
10395 // first request is now stale, this should do nothing.
10396 notifyPointerCaptureChanged(firstRequest);
10397 mWindow->assertNoEvents();
10398
10399 // InputReader notifies that the second request was enabled.
10400 notifyPointerCaptureChanged(secondRequest);
10401 mWindow->consumeCaptureEvent(true);
10402}
10403
Prabir Pradhan7092e262022-05-03 16:51:09 +000010404TEST_F(InputDispatcherPointerCaptureTests, RapidToggleRequests) {
10405 requestAndVerifyPointerCapture(mWindow, true);
10406
10407 // App toggles pointer capture off and on.
10408 mDispatcher->requestPointerCapture(mWindow->getToken(), false);
Hiroki Sato25040232024-02-22 17:21:22 +090010409 mFakePolicy->assertSetPointerCaptureCalled(mWindow, false);
Prabir Pradhan7092e262022-05-03 16:51:09 +000010410
10411 mDispatcher->requestPointerCapture(mWindow->getToken(), true);
Hiroki Sato25040232024-02-22 17:21:22 +090010412 auto enableRequest = mFakePolicy->assertSetPointerCaptureCalled(mWindow, true);
Prabir Pradhan7092e262022-05-03 16:51:09 +000010413
10414 // InputReader notifies that the latest "enable" request was processed, while skipping over the
10415 // preceding "disable" request.
10416 notifyPointerCaptureChanged(enableRequest);
10417
10418 // Since pointer capture was never disabled during the rapid toggle, the window does not receive
10419 // any notifications.
10420 mWindow->assertNoEvents();
10421}
10422
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -070010423/**
10424 * One window. Hover mouse in the window, and then start capture. Make sure that the relative
10425 * mouse movements don't affect the previous mouse hovering state.
10426 * When pointer capture is enabled, the incoming events are always ACTION_MOVE (there are no
10427 * HOVER_MOVE events).
10428 */
10429TEST_F(InputDispatcherPointerCaptureTests, MouseHoverAndPointerCapture) {
10430 // Mouse hover on the window
10431 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_ENTER, AINPUT_SOURCE_MOUSE)
10432 .pointer(PointerBuilder(0, ToolType::MOUSE).x(100).y(110))
10433 .build());
10434 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_MOVE, AINPUT_SOURCE_MOUSE)
10435 .pointer(PointerBuilder(0, ToolType::MOUSE).x(100).y(110))
10436 .build());
10437
10438 mWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_HOVER_ENTER)));
10439 mWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_HOVER_MOVE)));
10440
10441 // Start pointer capture
10442 requestAndVerifyPointerCapture(mWindow, true);
10443
10444 // Send some relative mouse movements and receive them in the window.
10445 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_MOUSE_RELATIVE)
10446 .pointer(PointerBuilder(0, ToolType::MOUSE).x(10).y(11))
10447 .build());
10448 mWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_MOVE), WithCoords(10, 11),
10449 WithSource(AINPUT_SOURCE_MOUSE_RELATIVE)));
10450
10451 // Stop pointer capture
10452 requestAndVerifyPointerCapture(mWindow, false);
10453
10454 // Continue hovering on the window
10455 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_MOVE, AINPUT_SOURCE_MOUSE)
10456 .pointer(PointerBuilder(0, ToolType::MOUSE).x(105).y(115))
10457 .build());
10458 mWindow->consumeMotionEvent(
10459 AllOf(WithMotionAction(ACTION_HOVER_MOVE), WithSource(AINPUT_SOURCE_MOUSE)));
10460
10461 mWindow->assertNoEvents();
10462}
10463
Hiroki Sato25040232024-02-22 17:21:22 +090010464using InputDispatcherPointerCaptureDeathTest = InputDispatcherPointerCaptureTests;
10465
10466TEST_F(InputDispatcherPointerCaptureDeathTest,
10467 NotifyPointerCaptureChangedWithWrongTokenAbortsDispatcher) {
10468 testing::GTEST_FLAG(death_test_style) = "threadsafe";
10469 ScopedSilentDeath _silentDeath;
10470
10471 mDispatcher->requestPointerCapture(mWindow->getToken(), true);
10472 auto request = mFakePolicy->assertSetPointerCaptureCalled(mWindow, true);
10473
10474 // Dispatch a pointer changed event with a wrong token.
10475 request.window = mSecondWindow->getToken();
10476 ASSERT_DEATH(
10477 {
10478 notifyPointerCaptureChanged(request);
10479 mSecondWindow->consumeCaptureEvent(true);
10480 },
10481 "Unexpected requested window for Pointer Capture.");
10482}
10483
Bernardo Rufinoc3b7b8c2021-01-29 17:38:07 +000010484class InputDispatcherUntrustedTouchesTest : public InputDispatcherTest {
10485protected:
10486 constexpr static const float MAXIMUM_OBSCURING_OPACITY = 0.8;
Bernardo Rufino7393d172021-02-26 13:56:11 +000010487
10488 constexpr static const float OPACITY_ABOVE_THRESHOLD = 0.9;
10489 static_assert(OPACITY_ABOVE_THRESHOLD > MAXIMUM_OBSCURING_OPACITY);
10490
10491 constexpr static const float OPACITY_BELOW_THRESHOLD = 0.7;
10492 static_assert(OPACITY_BELOW_THRESHOLD < MAXIMUM_OBSCURING_OPACITY);
10493
10494 // When combined twice, ie 1 - (1 - 0.5)*(1 - 0.5) = 0.75 < 8, is still below the threshold
10495 constexpr static const float OPACITY_FAR_BELOW_THRESHOLD = 0.5;
10496 static_assert(OPACITY_FAR_BELOW_THRESHOLD < MAXIMUM_OBSCURING_OPACITY);
10497 static_assert(1 - (1 - OPACITY_FAR_BELOW_THRESHOLD) * (1 - OPACITY_FAR_BELOW_THRESHOLD) <
10498 MAXIMUM_OBSCURING_OPACITY);
10499
Prabir Pradhan8a5c41d2023-06-08 19:13:46 +000010500 static constexpr gui::Uid TOUCHED_APP_UID{10001};
10501 static constexpr gui::Uid APP_B_UID{10002};
10502 static constexpr gui::Uid APP_C_UID{10003};
Bernardo Rufinoc3b7b8c2021-01-29 17:38:07 +000010503
10504 sp<FakeWindowHandle> mTouchWindow;
10505
10506 virtual void SetUp() override {
10507 InputDispatcherTest::SetUp();
Bernardo Rufino6d52e542021-02-15 18:38:10 +000010508 mTouchWindow = getWindow(TOUCHED_APP_UID, "Touched");
Bernardo Rufinoc3b7b8c2021-01-29 17:38:07 +000010509 mDispatcher->setMaximumObscuringOpacityForTouch(MAXIMUM_OBSCURING_OPACITY);
10510 }
10511
10512 virtual void TearDown() override {
10513 InputDispatcherTest::TearDown();
10514 mTouchWindow.clear();
10515 }
10516
Prabir Pradhan8a5c41d2023-06-08 19:13:46 +000010517 sp<FakeWindowHandle> getOccludingWindow(gui::Uid uid, std::string name, TouchOcclusionMode mode,
chaviw3277faf2021-05-19 16:45:23 -050010518 float alpha = 1.0f) {
Bernardo Rufinoc3b7b8c2021-01-29 17:38:07 +000010519 sp<FakeWindowHandle> window = getWindow(uid, name);
Prabir Pradhan4d5c52f2022-01-31 08:52:10 -080010520 window->setTouchable(false);
Bernardo Rufinoc3b7b8c2021-01-29 17:38:07 +000010521 window->setTouchOcclusionMode(mode);
Bernardo Rufino1d0d1f22021-02-12 15:08:43 +000010522 window->setAlpha(alpha);
Bernardo Rufinoc3b7b8c2021-01-29 17:38:07 +000010523 return window;
10524 }
10525
Prabir Pradhan8a5c41d2023-06-08 19:13:46 +000010526 sp<FakeWindowHandle> getWindow(gui::Uid uid, std::string name) {
Bernardo Rufinoc3b7b8c2021-01-29 17:38:07 +000010527 std::shared_ptr<FakeApplicationHandle> app = std::make_shared<FakeApplicationHandle>();
10528 sp<FakeWindowHandle> window =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -070010529 sp<FakeWindowHandle>::make(app, mDispatcher, name, ADISPLAY_ID_DEFAULT);
Bernardo Rufinoc3b7b8c2021-01-29 17:38:07 +000010530 // Generate an arbitrary PID based on the UID
Prabir Pradhanaeebeb42023-06-13 19:53:03 +000010531 window->setOwnerInfo(gui::Pid{static_cast<pid_t>(1777 + (uid.val() % 10000))}, uid);
Bernardo Rufinoc3b7b8c2021-01-29 17:38:07 +000010532 return window;
10533 }
10534
10535 void touch(const std::vector<PointF>& points = {PointF{100, 200}}) {
Prabir Pradhan678438e2023-04-13 19:32:51 +000010536 mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_DOWN,
10537 AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
10538 points));
Bernardo Rufinoc3b7b8c2021-01-29 17:38:07 +000010539 }
10540};
10541
10542TEST_F(InputDispatcherUntrustedTouchesTest, WindowWithBlockUntrustedOcclusionMode_BlocksTouch) {
Bernardo Rufino1d0d1f22021-02-12 15:08:43 +000010543 const sp<FakeWindowHandle>& w =
Bernardo Rufinoc3b7b8c2021-01-29 17:38:07 +000010544 getOccludingWindow(APP_B_UID, "B", TouchOcclusionMode::BLOCK_UNTRUSTED);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070010545 mDispatcher->onWindowInfosChanged({{*w->getInfo(), *mTouchWindow->getInfo()}, {}, 0, 0});
Bernardo Rufinoc3b7b8c2021-01-29 17:38:07 +000010546
10547 touch();
10548
10549 mTouchWindow->assertNoEvents();
10550}
10551
Bernardo Rufinoa43a5a42021-02-17 12:21:14 +000010552TEST_F(InputDispatcherUntrustedTouchesTest,
Bernardo Rufino7393d172021-02-26 13:56:11 +000010553 WindowWithBlockUntrustedOcclusionModeWithOpacityBelowThreshold_BlocksTouch) {
10554 const sp<FakeWindowHandle>& w =
10555 getOccludingWindow(APP_B_UID, "B", TouchOcclusionMode::BLOCK_UNTRUSTED, 0.7f);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070010556 mDispatcher->onWindowInfosChanged({{*w->getInfo(), *mTouchWindow->getInfo()}, {}, 0, 0});
Bernardo Rufino7393d172021-02-26 13:56:11 +000010557
10558 touch();
10559
10560 mTouchWindow->assertNoEvents();
10561}
10562
10563TEST_F(InputDispatcherUntrustedTouchesTest,
Bernardo Rufinoa43a5a42021-02-17 12:21:14 +000010564 WindowWithBlockUntrustedOcclusionMode_DoesNotReceiveTouch) {
10565 const sp<FakeWindowHandle>& w =
10566 getOccludingWindow(APP_B_UID, "B", TouchOcclusionMode::BLOCK_UNTRUSTED);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070010567 mDispatcher->onWindowInfosChanged({{*w->getInfo(), *mTouchWindow->getInfo()}, {}, 0, 0});
Bernardo Rufinoa43a5a42021-02-17 12:21:14 +000010568
10569 touch();
10570
10571 w->assertNoEvents();
10572}
10573
Bernardo Rufinoc3b7b8c2021-01-29 17:38:07 +000010574TEST_F(InputDispatcherUntrustedTouchesTest, WindowWithAllowOcclusionMode_AllowsTouch) {
Bernardo Rufino1d0d1f22021-02-12 15:08:43 +000010575 const sp<FakeWindowHandle>& w = getOccludingWindow(APP_B_UID, "B", TouchOcclusionMode::ALLOW);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070010576 mDispatcher->onWindowInfosChanged({{*w->getInfo(), *mTouchWindow->getInfo()}, {}, 0, 0});
Bernardo Rufinoc3b7b8c2021-01-29 17:38:07 +000010577
10578 touch();
10579
10580 mTouchWindow->consumeAnyMotionDown();
10581}
10582
10583TEST_F(InputDispatcherUntrustedTouchesTest, TouchOutsideOccludingWindow_AllowsTouch) {
Bernardo Rufino1d0d1f22021-02-12 15:08:43 +000010584 const sp<FakeWindowHandle>& w =
Bernardo Rufinoc3b7b8c2021-01-29 17:38:07 +000010585 getOccludingWindow(APP_B_UID, "B", TouchOcclusionMode::BLOCK_UNTRUSTED);
Bernardo Rufino1d0d1f22021-02-12 15:08:43 +000010586 w->setFrame(Rect(0, 0, 50, 50));
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070010587 mDispatcher->onWindowInfosChanged({{*w->getInfo(), *mTouchWindow->getInfo()}, {}, 0, 0});
Bernardo Rufinoc3b7b8c2021-01-29 17:38:07 +000010588
10589 touch({PointF{100, 100}});
10590
10591 mTouchWindow->consumeAnyMotionDown();
10592}
10593
10594TEST_F(InputDispatcherUntrustedTouchesTest, WindowFromSameUid_AllowsTouch) {
Bernardo Rufino1d0d1f22021-02-12 15:08:43 +000010595 const sp<FakeWindowHandle>& w =
Bernardo Rufino6d52e542021-02-15 18:38:10 +000010596 getOccludingWindow(TOUCHED_APP_UID, "A", TouchOcclusionMode::BLOCK_UNTRUSTED);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070010597 mDispatcher->onWindowInfosChanged({{*w->getInfo(), *mTouchWindow->getInfo()}, {}, 0, 0});
Bernardo Rufino1d0d1f22021-02-12 15:08:43 +000010598
10599 touch();
10600
10601 mTouchWindow->consumeAnyMotionDown();
10602}
10603
10604TEST_F(InputDispatcherUntrustedTouchesTest, WindowWithZeroOpacity_AllowsTouch) {
10605 const sp<FakeWindowHandle>& w =
10606 getOccludingWindow(APP_B_UID, "B", TouchOcclusionMode::BLOCK_UNTRUSTED, 0.0f);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070010607 mDispatcher->onWindowInfosChanged({{*w->getInfo(), *mTouchWindow->getInfo()}, {}, 0, 0});
Bernardo Rufinoc3b7b8c2021-01-29 17:38:07 +000010608
10609 touch();
10610
10611 mTouchWindow->consumeAnyMotionDown();
10612}
10613
Bernardo Rufinoa43a5a42021-02-17 12:21:14 +000010614TEST_F(InputDispatcherUntrustedTouchesTest, WindowWithZeroOpacity_DoesNotReceiveTouch) {
10615 const sp<FakeWindowHandle>& w =
10616 getOccludingWindow(APP_B_UID, "B", TouchOcclusionMode::BLOCK_UNTRUSTED, 0.0f);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070010617 mDispatcher->onWindowInfosChanged({{*w->getInfo(), *mTouchWindow->getInfo()}, {}, 0, 0});
Bernardo Rufinoa43a5a42021-02-17 12:21:14 +000010618
10619 touch();
10620
10621 w->assertNoEvents();
10622}
10623
10624/**
10625 * This is important to make sure apps can't indirectly learn the position of touches (outside vs
10626 * inside) while letting them pass-through. Note that even though touch passes through the occluding
10627 * window, the occluding window will still receive ACTION_OUTSIDE event.
10628 */
10629TEST_F(InputDispatcherUntrustedTouchesTest,
10630 WindowWithZeroOpacityAndWatchOutside_ReceivesOutsideEvent) {
10631 const sp<FakeWindowHandle>& w =
10632 getOccludingWindow(APP_B_UID, "B", TouchOcclusionMode::BLOCK_UNTRUSTED, 0.0f);
Prabir Pradhan4d5c52f2022-01-31 08:52:10 -080010633 w->setWatchOutsideTouch(true);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070010634 mDispatcher->onWindowInfosChanged({{*w->getInfo(), *mTouchWindow->getInfo()}, {}, 0, 0});
Bernardo Rufinoa43a5a42021-02-17 12:21:14 +000010635
10636 touch();
10637
10638 w->consumeMotionOutside();
10639}
10640
10641TEST_F(InputDispatcherUntrustedTouchesTest, OutsideEvent_HasZeroCoordinates) {
10642 const sp<FakeWindowHandle>& w =
10643 getOccludingWindow(APP_B_UID, "B", TouchOcclusionMode::BLOCK_UNTRUSTED, 0.0f);
Prabir Pradhan4d5c52f2022-01-31 08:52:10 -080010644 w->setWatchOutsideTouch(true);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070010645 mDispatcher->onWindowInfosChanged({{*w->getInfo(), *mTouchWindow->getInfo()}, {}, 0, 0});
Bernardo Rufinoa43a5a42021-02-17 12:21:14 +000010646
10647 touch();
10648
Prabir Pradhandfabf8a2022-01-21 08:19:30 -080010649 w->consumeMotionOutsideWithZeroedCoords();
Bernardo Rufinoa43a5a42021-02-17 12:21:14 +000010650}
10651
Bernardo Rufinoc3b7b8c2021-01-29 17:38:07 +000010652TEST_F(InputDispatcherUntrustedTouchesTest, WindowWithOpacityBelowThreshold_AllowsTouch) {
Bernardo Rufino1d0d1f22021-02-12 15:08:43 +000010653 const sp<FakeWindowHandle>& w =
Bernardo Rufino7393d172021-02-26 13:56:11 +000010654 getOccludingWindow(APP_B_UID, "B", TouchOcclusionMode::USE_OPACITY,
10655 OPACITY_BELOW_THRESHOLD);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070010656 mDispatcher->onWindowInfosChanged({{*w->getInfo(), *mTouchWindow->getInfo()}, {}, 0, 0});
Bernardo Rufino1d0d1f22021-02-12 15:08:43 +000010657
10658 touch();
10659
10660 mTouchWindow->consumeAnyMotionDown();
10661}
10662
10663TEST_F(InputDispatcherUntrustedTouchesTest, WindowWithOpacityAtThreshold_AllowsTouch) {
10664 const sp<FakeWindowHandle>& w =
10665 getOccludingWindow(APP_B_UID, "B", TouchOcclusionMode::USE_OPACITY,
10666 MAXIMUM_OBSCURING_OPACITY);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070010667 mDispatcher->onWindowInfosChanged({{*w->getInfo(), *mTouchWindow->getInfo()}, {}, 0, 0});
Bernardo Rufinoc3b7b8c2021-01-29 17:38:07 +000010668
10669 touch();
10670
10671 mTouchWindow->consumeAnyMotionDown();
10672}
10673
10674TEST_F(InputDispatcherUntrustedTouchesTest, WindowWithOpacityAboveThreshold_BlocksTouch) {
Bernardo Rufino1d0d1f22021-02-12 15:08:43 +000010675 const sp<FakeWindowHandle>& w =
Bernardo Rufino7393d172021-02-26 13:56:11 +000010676 getOccludingWindow(APP_B_UID, "B", TouchOcclusionMode::USE_OPACITY,
10677 OPACITY_ABOVE_THRESHOLD);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070010678 mDispatcher->onWindowInfosChanged({{*w->getInfo(), *mTouchWindow->getInfo()}, {}, 0, 0});
Bernardo Rufino1d0d1f22021-02-12 15:08:43 +000010679
10680 touch();
10681
10682 mTouchWindow->assertNoEvents();
10683}
10684
10685TEST_F(InputDispatcherUntrustedTouchesTest, WindowsWithCombinedOpacityAboveThreshold_BlocksTouch) {
10686 // Resulting opacity = 1 - (1 - 0.7)*(1 - 0.7) = .91
10687 const sp<FakeWindowHandle>& w1 =
Bernardo Rufino7393d172021-02-26 13:56:11 +000010688 getOccludingWindow(APP_B_UID, "B1", TouchOcclusionMode::USE_OPACITY,
10689 OPACITY_BELOW_THRESHOLD);
Bernardo Rufino1d0d1f22021-02-12 15:08:43 +000010690 const sp<FakeWindowHandle>& w2 =
Bernardo Rufino7393d172021-02-26 13:56:11 +000010691 getOccludingWindow(APP_B_UID, "B2", TouchOcclusionMode::USE_OPACITY,
10692 OPACITY_BELOW_THRESHOLD);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070010693 mDispatcher->onWindowInfosChanged(
10694 {{*w1->getInfo(), *w2->getInfo(), *mTouchWindow->getInfo()}, {}, 0, 0});
Bernardo Rufino1d0d1f22021-02-12 15:08:43 +000010695
10696 touch();
10697
10698 mTouchWindow->assertNoEvents();
10699}
10700
10701TEST_F(InputDispatcherUntrustedTouchesTest, WindowsWithCombinedOpacityBelowThreshold_AllowsTouch) {
10702 // Resulting opacity = 1 - (1 - 0.5)*(1 - 0.5) = .75
10703 const sp<FakeWindowHandle>& w1 =
Bernardo Rufino7393d172021-02-26 13:56:11 +000010704 getOccludingWindow(APP_B_UID, "B1", TouchOcclusionMode::USE_OPACITY,
10705 OPACITY_FAR_BELOW_THRESHOLD);
Bernardo Rufino1d0d1f22021-02-12 15:08:43 +000010706 const sp<FakeWindowHandle>& w2 =
Bernardo Rufino7393d172021-02-26 13:56:11 +000010707 getOccludingWindow(APP_B_UID, "B2", TouchOcclusionMode::USE_OPACITY,
10708 OPACITY_FAR_BELOW_THRESHOLD);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070010709 mDispatcher->onWindowInfosChanged(
10710 {{*w1->getInfo(), *w2->getInfo(), *mTouchWindow->getInfo()}, {}, 0, 0});
Bernardo Rufino1d0d1f22021-02-12 15:08:43 +000010711
10712 touch();
10713
10714 mTouchWindow->consumeAnyMotionDown();
10715}
10716
10717TEST_F(InputDispatcherUntrustedTouchesTest,
10718 WindowsFromDifferentAppsEachBelowThreshold_AllowsTouch) {
10719 const sp<FakeWindowHandle>& wB =
Bernardo Rufino7393d172021-02-26 13:56:11 +000010720 getOccludingWindow(APP_B_UID, "B", TouchOcclusionMode::USE_OPACITY,
10721 OPACITY_BELOW_THRESHOLD);
Bernardo Rufino1d0d1f22021-02-12 15:08:43 +000010722 const sp<FakeWindowHandle>& wC =
Bernardo Rufino7393d172021-02-26 13:56:11 +000010723 getOccludingWindow(APP_C_UID, "C", TouchOcclusionMode::USE_OPACITY,
10724 OPACITY_BELOW_THRESHOLD);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070010725 mDispatcher->onWindowInfosChanged(
10726 {{*wB->getInfo(), *wC->getInfo(), *mTouchWindow->getInfo()}, {}, 0, 0});
Bernardo Rufino1d0d1f22021-02-12 15:08:43 +000010727
10728 touch();
10729
10730 mTouchWindow->consumeAnyMotionDown();
10731}
10732
10733TEST_F(InputDispatcherUntrustedTouchesTest, WindowsFromDifferentAppsOneAboveThreshold_BlocksTouch) {
10734 const sp<FakeWindowHandle>& wB =
Bernardo Rufino7393d172021-02-26 13:56:11 +000010735 getOccludingWindow(APP_B_UID, "B", TouchOcclusionMode::USE_OPACITY,
10736 OPACITY_BELOW_THRESHOLD);
Bernardo Rufino1d0d1f22021-02-12 15:08:43 +000010737 const sp<FakeWindowHandle>& wC =
Bernardo Rufino7393d172021-02-26 13:56:11 +000010738 getOccludingWindow(APP_C_UID, "C", TouchOcclusionMode::USE_OPACITY,
10739 OPACITY_ABOVE_THRESHOLD);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070010740 mDispatcher->onWindowInfosChanged(
10741 {{*wB->getInfo(), *wC->getInfo(), *mTouchWindow->getInfo()}, {}, 0, 0});
Bernardo Rufinoc3b7b8c2021-01-29 17:38:07 +000010742
10743 touch();
10744
10745 mTouchWindow->assertNoEvents();
10746}
10747
Bernardo Rufino6d52e542021-02-15 18:38:10 +000010748TEST_F(InputDispatcherUntrustedTouchesTest,
10749 WindowWithOpacityAboveThresholdAndSelfWindow_BlocksTouch) {
10750 const sp<FakeWindowHandle>& wA =
Bernardo Rufino7393d172021-02-26 13:56:11 +000010751 getOccludingWindow(TOUCHED_APP_UID, "T", TouchOcclusionMode::USE_OPACITY,
10752 OPACITY_BELOW_THRESHOLD);
Bernardo Rufino6d52e542021-02-15 18:38:10 +000010753 const sp<FakeWindowHandle>& wB =
Bernardo Rufino7393d172021-02-26 13:56:11 +000010754 getOccludingWindow(APP_B_UID, "B", TouchOcclusionMode::USE_OPACITY,
10755 OPACITY_ABOVE_THRESHOLD);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070010756 mDispatcher->onWindowInfosChanged(
10757 {{*wA->getInfo(), *wB->getInfo(), *mTouchWindow->getInfo()}, {}, 0, 0});
Bernardo Rufino6d52e542021-02-15 18:38:10 +000010758
10759 touch();
10760
10761 mTouchWindow->assertNoEvents();
10762}
10763
10764TEST_F(InputDispatcherUntrustedTouchesTest,
10765 WindowWithOpacityBelowThresholdAndSelfWindow_AllowsTouch) {
10766 const sp<FakeWindowHandle>& wA =
Bernardo Rufino7393d172021-02-26 13:56:11 +000010767 getOccludingWindow(TOUCHED_APP_UID, "T", TouchOcclusionMode::USE_OPACITY,
10768 OPACITY_ABOVE_THRESHOLD);
Bernardo Rufino6d52e542021-02-15 18:38:10 +000010769 const sp<FakeWindowHandle>& wB =
Bernardo Rufino7393d172021-02-26 13:56:11 +000010770 getOccludingWindow(APP_B_UID, "B", TouchOcclusionMode::USE_OPACITY,
10771 OPACITY_BELOW_THRESHOLD);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070010772 mDispatcher->onWindowInfosChanged(
10773 {{*wA->getInfo(), *wB->getInfo(), *mTouchWindow->getInfo()}, {}, 0, 0});
Bernardo Rufino6d52e542021-02-15 18:38:10 +000010774
10775 touch();
10776
10777 mTouchWindow->consumeAnyMotionDown();
10778}
10779
10780TEST_F(InputDispatcherUntrustedTouchesTest, SelfWindowWithOpacityAboveThreshold_AllowsTouch) {
10781 const sp<FakeWindowHandle>& w =
Bernardo Rufino7393d172021-02-26 13:56:11 +000010782 getOccludingWindow(TOUCHED_APP_UID, "T", TouchOcclusionMode::USE_OPACITY,
10783 OPACITY_ABOVE_THRESHOLD);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070010784 mDispatcher->onWindowInfosChanged({{*w->getInfo(), *mTouchWindow->getInfo()}, {}, 0, 0});
Bernardo Rufino6d52e542021-02-15 18:38:10 +000010785
10786 touch();
10787
10788 mTouchWindow->consumeAnyMotionDown();
10789}
10790
10791TEST_F(InputDispatcherUntrustedTouchesTest, SelfWindowWithBlockUntrustedMode_AllowsTouch) {
10792 const sp<FakeWindowHandle>& w =
10793 getOccludingWindow(TOUCHED_APP_UID, "T", TouchOcclusionMode::BLOCK_UNTRUSTED);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070010794 mDispatcher->onWindowInfosChanged({{*w->getInfo(), *mTouchWindow->getInfo()}, {}, 0, 0});
Bernardo Rufino6d52e542021-02-15 18:38:10 +000010795
10796 touch();
10797
10798 mTouchWindow->consumeAnyMotionDown();
10799}
10800
Bernardo Rufinoccd3dd62021-02-15 18:47:42 +000010801TEST_F(InputDispatcherUntrustedTouchesTest,
10802 OpacityThresholdIs0AndWindowAboveThreshold_BlocksTouch) {
10803 mDispatcher->setMaximumObscuringOpacityForTouch(0.0f);
10804 const sp<FakeWindowHandle>& w =
10805 getOccludingWindow(APP_B_UID, "B", TouchOcclusionMode::USE_OPACITY, 0.1f);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070010806 mDispatcher->onWindowInfosChanged({{*w->getInfo(), *mTouchWindow->getInfo()}, {}, 0, 0});
Bernardo Rufinoccd3dd62021-02-15 18:47:42 +000010807
10808 touch();
10809
10810 mTouchWindow->assertNoEvents();
10811}
10812
10813TEST_F(InputDispatcherUntrustedTouchesTest, OpacityThresholdIs0AndWindowAtThreshold_AllowsTouch) {
10814 mDispatcher->setMaximumObscuringOpacityForTouch(0.0f);
10815 const sp<FakeWindowHandle>& w =
10816 getOccludingWindow(APP_B_UID, "B", TouchOcclusionMode::USE_OPACITY, 0.0f);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070010817 mDispatcher->onWindowInfosChanged({{*w->getInfo(), *mTouchWindow->getInfo()}, {}, 0, 0});
Bernardo Rufinoccd3dd62021-02-15 18:47:42 +000010818
10819 touch();
10820
10821 mTouchWindow->consumeAnyMotionDown();
10822}
10823
10824TEST_F(InputDispatcherUntrustedTouchesTest,
10825 OpacityThresholdIs1AndWindowBelowThreshold_AllowsTouch) {
10826 mDispatcher->setMaximumObscuringOpacityForTouch(1.0f);
10827 const sp<FakeWindowHandle>& w =
Bernardo Rufino7393d172021-02-26 13:56:11 +000010828 getOccludingWindow(APP_B_UID, "B", TouchOcclusionMode::USE_OPACITY,
10829 OPACITY_ABOVE_THRESHOLD);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070010830 mDispatcher->onWindowInfosChanged({{*w->getInfo(), *mTouchWindow->getInfo()}, {}, 0, 0});
Bernardo Rufino7393d172021-02-26 13:56:11 +000010831
10832 touch();
10833
10834 mTouchWindow->consumeAnyMotionDown();
10835}
10836
10837TEST_F(InputDispatcherUntrustedTouchesTest,
10838 WindowWithBlockUntrustedModeAndWindowWithOpacityBelowFromSameApp_BlocksTouch) {
10839 const sp<FakeWindowHandle>& w1 =
10840 getOccludingWindow(APP_B_UID, "B", TouchOcclusionMode::BLOCK_UNTRUSTED,
10841 OPACITY_BELOW_THRESHOLD);
10842 const sp<FakeWindowHandle>& w2 =
10843 getOccludingWindow(APP_B_UID, "B", TouchOcclusionMode::USE_OPACITY,
10844 OPACITY_BELOW_THRESHOLD);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070010845 mDispatcher->onWindowInfosChanged(
10846 {{*w1->getInfo(), *w2->getInfo(), *mTouchWindow->getInfo()}, {}, 0, 0});
Bernardo Rufino7393d172021-02-26 13:56:11 +000010847
10848 touch();
10849
10850 mTouchWindow->assertNoEvents();
10851}
10852
10853/**
10854 * Window B of BLOCK_UNTRUSTED occlusion mode is enough to block the touch, we're testing that the
10855 * addition of another window (C) of USE_OPACITY occlusion mode and opacity below the threshold
10856 * (which alone would result in allowing touches) does not affect the blocking behavior.
10857 */
10858TEST_F(InputDispatcherUntrustedTouchesTest,
10859 WindowWithBlockUntrustedModeAndWindowWithOpacityBelowFromDifferentApps_BlocksTouch) {
10860 const sp<FakeWindowHandle>& wB =
10861 getOccludingWindow(APP_B_UID, "B", TouchOcclusionMode::BLOCK_UNTRUSTED,
10862 OPACITY_BELOW_THRESHOLD);
10863 const sp<FakeWindowHandle>& wC =
10864 getOccludingWindow(APP_C_UID, "C", TouchOcclusionMode::USE_OPACITY,
10865 OPACITY_BELOW_THRESHOLD);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070010866 mDispatcher->onWindowInfosChanged(
10867 {{*wB->getInfo(), *wC->getInfo(), *mTouchWindow->getInfo()}, {}, 0, 0});
Bernardo Rufino7393d172021-02-26 13:56:11 +000010868
10869 touch();
10870
10871 mTouchWindow->assertNoEvents();
10872}
10873
10874/**
10875 * This test is testing that a window from a different UID but with same application token doesn't
10876 * block the touch. Apps can share the application token for close UI collaboration for example.
10877 */
10878TEST_F(InputDispatcherUntrustedTouchesTest,
10879 WindowWithSameApplicationTokenFromDifferentApp_AllowsTouch) {
10880 const sp<FakeWindowHandle>& w =
10881 getOccludingWindow(APP_B_UID, "B", TouchOcclusionMode::BLOCK_UNTRUSTED);
10882 w->setApplicationToken(mTouchWindow->getApplicationToken());
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070010883 mDispatcher->onWindowInfosChanged({{*w->getInfo(), *mTouchWindow->getInfo()}, {}, 0, 0});
Bernardo Rufinoccd3dd62021-02-15 18:47:42 +000010884
10885 touch();
10886
10887 mTouchWindow->consumeAnyMotionDown();
10888}
10889
arthurhungb89ccb02020-12-30 16:19:01 +080010890class InputDispatcherDragTests : public InputDispatcherTest {
10891protected:
10892 std::shared_ptr<FakeApplicationHandle> mApp;
10893 sp<FakeWindowHandle> mWindow;
10894 sp<FakeWindowHandle> mSecondWindow;
10895 sp<FakeWindowHandle> mDragWindow;
Vaibhav Devmurari6abcf8f2022-06-06 10:08:05 +000010896 sp<FakeWindowHandle> mSpyWindow;
Arthur Hungb75c2aa2022-07-15 09:35:36 +000010897 // Mouse would force no-split, set the id as non-zero to verify if drag state could track it.
10898 static constexpr int32_t MOUSE_POINTER_ID = 1;
arthurhungb89ccb02020-12-30 16:19:01 +080010899
10900 void SetUp() override {
10901 InputDispatcherTest::SetUp();
10902 mApp = std::make_shared<FakeApplicationHandle>();
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -070010903 mWindow = sp<FakeWindowHandle>::make(mApp, mDispatcher, "TestWindow", ADISPLAY_ID_DEFAULT);
arthurhungb89ccb02020-12-30 16:19:01 +080010904 mWindow->setFrame(Rect(0, 0, 100, 100));
arthurhungb89ccb02020-12-30 16:19:01 +080010905
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -070010906 mSecondWindow =
10907 sp<FakeWindowHandle>::make(mApp, mDispatcher, "TestWindow2", ADISPLAY_ID_DEFAULT);
arthurhungb89ccb02020-12-30 16:19:01 +080010908 mSecondWindow->setFrame(Rect(100, 0, 200, 100));
arthurhungb89ccb02020-12-30 16:19:01 +080010909
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -070010910 mSpyWindow =
10911 sp<FakeWindowHandle>::make(mApp, mDispatcher, "SpyWindow", ADISPLAY_ID_DEFAULT);
Vaibhav Devmurari6abcf8f2022-06-06 10:08:05 +000010912 mSpyWindow->setSpy(true);
10913 mSpyWindow->setTrustedOverlay(true);
10914 mSpyWindow->setFrame(Rect(0, 0, 200, 100));
10915
arthurhungb89ccb02020-12-30 16:19:01 +080010916 mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, mApp);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070010917 mDispatcher->onWindowInfosChanged(
10918 {{*mSpyWindow->getInfo(), *mWindow->getInfo(), *mSecondWindow->getInfo()},
10919 {},
10920 0,
10921 0});
arthurhungb89ccb02020-12-30 16:19:01 +080010922 }
10923
Arthur Hungb75c2aa2022-07-15 09:35:36 +000010924 void injectDown(int fromSource = AINPUT_SOURCE_TOUCHSCREEN) {
10925 switch (fromSource) {
10926 case AINPUT_SOURCE_TOUCHSCREEN:
10927 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070010928 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN,
Arthur Hungb75c2aa2022-07-15 09:35:36 +000010929 ADISPLAY_ID_DEFAULT, {50, 50}))
10930 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
10931 break;
10932 case AINPUT_SOURCE_STYLUS:
10933 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070010934 injectMotionEvent(*mDispatcher,
10935 MotionEventBuilder(AMOTION_EVENT_ACTION_DOWN,
10936 AINPUT_SOURCE_STYLUS)
10937 .buttonState(
10938 AMOTION_EVENT_BUTTON_STYLUS_PRIMARY)
10939 .pointer(PointerBuilder(0, ToolType::STYLUS)
10940 .x(50)
10941 .y(50))
10942 .build()));
Arthur Hungb75c2aa2022-07-15 09:35:36 +000010943 break;
10944 case AINPUT_SOURCE_MOUSE:
10945 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070010946 injectMotionEvent(*mDispatcher,
10947 MotionEventBuilder(AMOTION_EVENT_ACTION_DOWN,
10948 AINPUT_SOURCE_MOUSE)
10949 .buttonState(AMOTION_EVENT_BUTTON_PRIMARY)
10950 .pointer(PointerBuilder(MOUSE_POINTER_ID,
10951 ToolType::MOUSE)
10952 .x(50)
10953 .y(50))
10954 .build()));
Arthur Hungb75c2aa2022-07-15 09:35:36 +000010955 break;
10956 default:
10957 FAIL() << "Source " << fromSource << " doesn't support drag and drop";
10958 }
arthurhungb89ccb02020-12-30 16:19:01 +080010959
10960 // Window should receive motion event.
10961 mWindow->consumeMotionDown(ADISPLAY_ID_DEFAULT);
Vaibhav Devmurari6abcf8f2022-06-06 10:08:05 +000010962 // Spy window should also receive motion event
10963 mSpyWindow->consumeMotionDown(ADISPLAY_ID_DEFAULT);
Arthur Hung54745652022-04-20 07:17:41 +000010964 }
10965
10966 // Start performing drag, we will create a drag window and transfer touch to it.
10967 // @param sendDown : if true, send a motion down on first window before perform drag and drop.
10968 // Returns true on success.
Arthur Hungb75c2aa2022-07-15 09:35:36 +000010969 bool startDrag(bool sendDown = true, int fromSource = AINPUT_SOURCE_TOUCHSCREEN) {
Arthur Hung54745652022-04-20 07:17:41 +000010970 if (sendDown) {
Arthur Hungb75c2aa2022-07-15 09:35:36 +000010971 injectDown(fromSource);
Arthur Hung54745652022-04-20 07:17:41 +000010972 }
arthurhungb89ccb02020-12-30 16:19:01 +080010973
10974 // The drag window covers the entire display
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -070010975 mDragWindow =
10976 sp<FakeWindowHandle>::make(mApp, mDispatcher, "DragWindow", ADISPLAY_ID_DEFAULT);
Vaibhav Devmurari6abcf8f2022-06-06 10:08:05 +000010977 mDragWindow->setTouchableRegion(Region{{0, 0, 0, 0}});
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070010978 mDispatcher->onWindowInfosChanged({{*mDragWindow->getInfo(), *mSpyWindow->getInfo(),
10979 *mWindow->getInfo(), *mSecondWindow->getInfo()},
10980 {},
10981 0,
10982 0});
arthurhungb89ccb02020-12-30 16:19:01 +080010983
10984 // Transfer touch focus to the drag window
Arthur Hung54745652022-04-20 07:17:41 +000010985 bool transferred =
Prabir Pradhan367f3432024-02-13 23:05:58 +000010986 mDispatcher->transferTouchGesture(mWindow->getToken(), mDragWindow->getToken(),
10987 /*isDragDrop=*/true);
Arthur Hung54745652022-04-20 07:17:41 +000010988 if (transferred) {
10989 mWindow->consumeMotionCancel();
Prabir Pradhan65455c72024-02-13 21:46:41 +000010990 mDragWindow->consumeMotionDown(ADISPLAY_ID_DEFAULT, AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
Arthur Hung54745652022-04-20 07:17:41 +000010991 }
10992 return transferred;
arthurhungb89ccb02020-12-30 16:19:01 +080010993 }
10994};
10995
10996TEST_F(InputDispatcherDragTests, DragEnterAndDragExit) {
Arthur Hungb75c2aa2022-07-15 09:35:36 +000010997 startDrag();
arthurhungb89ccb02020-12-30 16:19:01 +080010998
10999 // Move on window.
11000 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070011001 injectMotionEvent(*mDispatcher, AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN,
arthurhungb89ccb02020-12-30 16:19:01 +080011002 ADISPLAY_ID_DEFAULT, {50, 50}))
11003 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
Prabir Pradhan65455c72024-02-13 21:46:41 +000011004 mDragWindow->consumeMotionMove(ADISPLAY_ID_DEFAULT, AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
arthurhungb89ccb02020-12-30 16:19:01 +080011005 mWindow->consumeDragEvent(false, 50, 50);
11006 mSecondWindow->assertNoEvents();
11007
11008 // Move to another window.
11009 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070011010 injectMotionEvent(*mDispatcher, AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN,
arthurhungb89ccb02020-12-30 16:19:01 +080011011 ADISPLAY_ID_DEFAULT, {150, 50}))
11012 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
Prabir Pradhan65455c72024-02-13 21:46:41 +000011013 mDragWindow->consumeMotionMove(ADISPLAY_ID_DEFAULT, AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
arthurhungb89ccb02020-12-30 16:19:01 +080011014 mWindow->consumeDragEvent(true, 150, 50);
11015 mSecondWindow->consumeDragEvent(false, 50, 50);
11016
11017 // Move back to original window.
11018 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070011019 injectMotionEvent(*mDispatcher, AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN,
arthurhungb89ccb02020-12-30 16:19:01 +080011020 ADISPLAY_ID_DEFAULT, {50, 50}))
11021 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
Prabir Pradhan65455c72024-02-13 21:46:41 +000011022 mDragWindow->consumeMotionMove(ADISPLAY_ID_DEFAULT, AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
arthurhungb89ccb02020-12-30 16:19:01 +080011023 mWindow->consumeDragEvent(false, 50, 50);
11024 mSecondWindow->consumeDragEvent(true, -50, 50);
11025
11026 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070011027 injectMotionUp(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
11028 {50, 50}))
arthurhungb89ccb02020-12-30 16:19:01 +080011029 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
Prabir Pradhan65455c72024-02-13 21:46:41 +000011030 mDragWindow->consumeMotionUp(ADISPLAY_ID_DEFAULT, AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
arthurhungb89ccb02020-12-30 16:19:01 +080011031 mWindow->assertNoEvents();
11032 mSecondWindow->assertNoEvents();
11033}
11034
Vaibhav Devmurari6abcf8f2022-06-06 10:08:05 +000011035TEST_F(InputDispatcherDragTests, DragEnterAndPointerDownPilfersPointers) {
Arthur Hungb75c2aa2022-07-15 09:35:36 +000011036 startDrag();
Vaibhav Devmurari6abcf8f2022-06-06 10:08:05 +000011037
11038 // No cancel event after drag start
11039 mSpyWindow->assertNoEvents();
11040
11041 const MotionEvent secondFingerDownEvent =
11042 MotionEventBuilder(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
11043 .eventTime(systemTime(SYSTEM_TIME_MONOTONIC))
Siarhei Vishniakou6d73f832022-07-21 17:27:03 -070011044 .pointer(PointerBuilder(/*id=*/0, ToolType::FINGER).x(50).y(50))
11045 .pointer(PointerBuilder(/*id=*/1, ToolType::FINGER).x(60).y(60))
Vaibhav Devmurari6abcf8f2022-06-06 10:08:05 +000011046 .build();
11047 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070011048 injectMotionEvent(*mDispatcher, secondFingerDownEvent, INJECT_EVENT_TIMEOUT,
Vaibhav Devmurari6abcf8f2022-06-06 10:08:05 +000011049 InputEventInjectionSync::WAIT_FOR_RESULT))
11050 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
11051
11052 // Receives cancel for first pointer after next pointer down
11053 mSpyWindow->consumeMotionCancel();
11054 mSpyWindow->consumeMotionDown();
11055
11056 mSpyWindow->assertNoEvents();
11057}
11058
arthurhungf452d0b2021-01-06 00:19:52 +080011059TEST_F(InputDispatcherDragTests, DragAndDrop) {
Arthur Hungb75c2aa2022-07-15 09:35:36 +000011060 startDrag();
arthurhungf452d0b2021-01-06 00:19:52 +080011061
11062 // Move on window.
11063 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070011064 injectMotionEvent(*mDispatcher, AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN,
arthurhungf452d0b2021-01-06 00:19:52 +080011065 ADISPLAY_ID_DEFAULT, {50, 50}))
11066 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
Prabir Pradhan65455c72024-02-13 21:46:41 +000011067 mDragWindow->consumeMotionMove(ADISPLAY_ID_DEFAULT, AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
arthurhungf452d0b2021-01-06 00:19:52 +080011068 mWindow->consumeDragEvent(false, 50, 50);
11069 mSecondWindow->assertNoEvents();
11070
11071 // Move to another window.
11072 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070011073 injectMotionEvent(*mDispatcher, AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN,
arthurhungf452d0b2021-01-06 00:19:52 +080011074 ADISPLAY_ID_DEFAULT, {150, 50}))
11075 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
Prabir Pradhan65455c72024-02-13 21:46:41 +000011076 mDragWindow->consumeMotionMove(ADISPLAY_ID_DEFAULT, AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
arthurhungf452d0b2021-01-06 00:19:52 +080011077 mWindow->consumeDragEvent(true, 150, 50);
11078 mSecondWindow->consumeDragEvent(false, 50, 50);
11079
11080 // drop to another window.
11081 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070011082 injectMotionUp(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
arthurhungf452d0b2021-01-06 00:19:52 +080011083 {150, 50}))
11084 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
Prabir Pradhan65455c72024-02-13 21:46:41 +000011085 mDragWindow->consumeMotionUp(ADISPLAY_ID_DEFAULT, AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
Siarhei Vishniakoua66d65e2023-06-16 10:32:51 -070011086 mFakePolicy->assertDropTargetEquals(*mDispatcher, mSecondWindow->getToken());
arthurhungf452d0b2021-01-06 00:19:52 +080011087 mWindow->assertNoEvents();
11088 mSecondWindow->assertNoEvents();
11089}
11090
Vaibhav Devmurari110ba322023-11-17 10:47:16 +000011091TEST_F(InputDispatcherDragTests, DragAndDropNotCancelledIfSomeOtherPointerIsPilfered) {
11092 startDrag();
11093
11094 // No cancel event after drag start
11095 mSpyWindow->assertNoEvents();
11096
11097 const MotionEvent secondFingerDownEvent =
11098 MotionEventBuilder(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
11099 .eventTime(systemTime(SYSTEM_TIME_MONOTONIC))
11100 .pointer(PointerBuilder(/*id=*/0, ToolType::FINGER).x(50).y(50))
11101 .pointer(PointerBuilder(/*id=*/1, ToolType::FINGER).x(60).y(60))
11102 .build();
11103 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
11104 injectMotionEvent(*mDispatcher, secondFingerDownEvent, INJECT_EVENT_TIMEOUT,
11105 InputEventInjectionSync::WAIT_FOR_RESULT))
11106 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
11107
11108 // Receives cancel for first pointer after next pointer down
11109 mSpyWindow->consumeMotionEvent(WithMotionAction(ACTION_CANCEL));
Siarhei Vishniakou1ff00cc2023-12-13 16:12:13 -080011110 mSpyWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithPointerIds({1})));
Vaibhav Devmurari110ba322023-11-17 10:47:16 +000011111 mDragWindow->consumeMotionEvent(WithMotionAction(ACTION_MOVE));
11112
11113 mSpyWindow->assertNoEvents();
11114
11115 // Spy window calls pilfer pointers
11116 EXPECT_EQ(OK, mDispatcher->pilferPointers(mSpyWindow->getToken()));
11117 mDragWindow->assertNoEvents();
11118
11119 const MotionEvent firstFingerMoveEvent =
Siarhei Vishniakou96a15572023-12-18 10:47:52 -080011120 MotionEventBuilder(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN)
Vaibhav Devmurari110ba322023-11-17 10:47:16 +000011121 .eventTime(systemTime(SYSTEM_TIME_MONOTONIC))
11122 .pointer(PointerBuilder(/*id=*/0, ToolType::FINGER).x(60).y(60))
11123 .pointer(PointerBuilder(/*id=*/1, ToolType::FINGER).x(60).y(60))
11124 .build();
11125 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakou96a15572023-12-18 10:47:52 -080011126 injectMotionEvent(*mDispatcher, firstFingerMoveEvent, INJECT_EVENT_TIMEOUT,
Vaibhav Devmurari110ba322023-11-17 10:47:16 +000011127 InputEventInjectionSync::WAIT_FOR_RESULT))
11128 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
11129
11130 // Drag window should still receive the new event
Prabir Pradhan65455c72024-02-13 21:46:41 +000011131 mDragWindow->consumeMotionEvent(
11132 AllOf(WithMotionAction(ACTION_MOVE), WithFlags(AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE)));
Vaibhav Devmurari110ba322023-11-17 10:47:16 +000011133 mDragWindow->assertNoEvents();
11134}
11135
arthurhung6d4bed92021-03-17 11:59:33 +080011136TEST_F(InputDispatcherDragTests, StylusDragAndDrop) {
Arthur Hungb75c2aa2022-07-15 09:35:36 +000011137 startDrag(true, AINPUT_SOURCE_STYLUS);
arthurhung6d4bed92021-03-17 11:59:33 +080011138
11139 // Move on window and keep button pressed.
11140 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070011141 injectMotionEvent(*mDispatcher,
arthurhung6d4bed92021-03-17 11:59:33 +080011142 MotionEventBuilder(AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_STYLUS)
11143 .buttonState(AMOTION_EVENT_BUTTON_STYLUS_PRIMARY)
Siarhei Vishniakou6d73f832022-07-21 17:27:03 -070011144 .pointer(PointerBuilder(0, ToolType::STYLUS).x(50).y(50))
arthurhung6d4bed92021-03-17 11:59:33 +080011145 .build()))
11146 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
Prabir Pradhan65455c72024-02-13 21:46:41 +000011147 mDragWindow->consumeMotionMove(ADISPLAY_ID_DEFAULT, AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
arthurhung6d4bed92021-03-17 11:59:33 +080011148 mWindow->consumeDragEvent(false, 50, 50);
11149 mSecondWindow->assertNoEvents();
11150
11151 // Move to another window and release button, expect to drop item.
11152 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070011153 injectMotionEvent(*mDispatcher,
arthurhung6d4bed92021-03-17 11:59:33 +080011154 MotionEventBuilder(AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_STYLUS)
11155 .buttonState(0)
Siarhei Vishniakou6d73f832022-07-21 17:27:03 -070011156 .pointer(PointerBuilder(0, ToolType::STYLUS).x(150).y(50))
arthurhung6d4bed92021-03-17 11:59:33 +080011157 .build()))
11158 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
Prabir Pradhan65455c72024-02-13 21:46:41 +000011159 mDragWindow->consumeMotionMove(ADISPLAY_ID_DEFAULT, AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
arthurhung6d4bed92021-03-17 11:59:33 +080011160 mWindow->assertNoEvents();
11161 mSecondWindow->assertNoEvents();
Siarhei Vishniakoua66d65e2023-06-16 10:32:51 -070011162 mFakePolicy->assertDropTargetEquals(*mDispatcher, mSecondWindow->getToken());
arthurhung6d4bed92021-03-17 11:59:33 +080011163
11164 // nothing to the window.
11165 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070011166 injectMotionEvent(*mDispatcher,
arthurhung6d4bed92021-03-17 11:59:33 +080011167 MotionEventBuilder(AMOTION_EVENT_ACTION_UP, AINPUT_SOURCE_STYLUS)
11168 .buttonState(0)
Siarhei Vishniakou6d73f832022-07-21 17:27:03 -070011169 .pointer(PointerBuilder(0, ToolType::STYLUS).x(150).y(50))
arthurhung6d4bed92021-03-17 11:59:33 +080011170 .build()))
11171 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
Prabir Pradhan65455c72024-02-13 21:46:41 +000011172 mDragWindow->consumeMotionUp(ADISPLAY_ID_DEFAULT, AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
arthurhung6d4bed92021-03-17 11:59:33 +080011173 mWindow->assertNoEvents();
11174 mSecondWindow->assertNoEvents();
11175}
11176
Arthur Hung54745652022-04-20 07:17:41 +000011177TEST_F(InputDispatcherDragTests, DragAndDropOnInvalidWindow) {
Arthur Hungb75c2aa2022-07-15 09:35:36 +000011178 startDrag();
Arthur Hung6d0571e2021-04-09 20:18:16 +080011179
11180 // Set second window invisible.
11181 mSecondWindow->setVisible(false);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070011182 mDispatcher->onWindowInfosChanged(
11183 {{*mDragWindow->getInfo(), *mWindow->getInfo(), *mSecondWindow->getInfo()}, {}, 0, 0});
Arthur Hung6d0571e2021-04-09 20:18:16 +080011184
11185 // Move on window.
11186 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070011187 injectMotionEvent(*mDispatcher, AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN,
Arthur Hung6d0571e2021-04-09 20:18:16 +080011188 ADISPLAY_ID_DEFAULT, {50, 50}))
11189 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
Prabir Pradhan65455c72024-02-13 21:46:41 +000011190 mDragWindow->consumeMotionMove(ADISPLAY_ID_DEFAULT, AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
Arthur Hung6d0571e2021-04-09 20:18:16 +080011191 mWindow->consumeDragEvent(false, 50, 50);
11192 mSecondWindow->assertNoEvents();
11193
11194 // Move to another window.
11195 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070011196 injectMotionEvent(*mDispatcher, AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN,
Arthur Hung6d0571e2021-04-09 20:18:16 +080011197 ADISPLAY_ID_DEFAULT, {150, 50}))
11198 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
Prabir Pradhan65455c72024-02-13 21:46:41 +000011199 mDragWindow->consumeMotionMove(ADISPLAY_ID_DEFAULT, AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
Arthur Hung6d0571e2021-04-09 20:18:16 +080011200 mWindow->consumeDragEvent(true, 150, 50);
11201 mSecondWindow->assertNoEvents();
11202
11203 // drop to another window.
11204 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070011205 injectMotionUp(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
Arthur Hung6d0571e2021-04-09 20:18:16 +080011206 {150, 50}))
11207 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
Prabir Pradhan65455c72024-02-13 21:46:41 +000011208 mDragWindow->consumeMotionUp(ADISPLAY_ID_DEFAULT, AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
Siarhei Vishniakoua66d65e2023-06-16 10:32:51 -070011209 mFakePolicy->assertDropTargetEquals(*mDispatcher, nullptr);
Arthur Hung6d0571e2021-04-09 20:18:16 +080011210 mWindow->assertNoEvents();
11211 mSecondWindow->assertNoEvents();
11212}
11213
Arthur Hung54745652022-04-20 07:17:41 +000011214TEST_F(InputDispatcherDragTests, NoDragAndDropWhenMultiFingers) {
Arthur Hungb75c2aa2022-07-15 09:35:36 +000011215 // Ensure window could track pointerIds if it didn't support split touch.
11216 mWindow->setPreventSplitting(true);
11217
Arthur Hung54745652022-04-20 07:17:41 +000011218 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070011219 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
Arthur Hung54745652022-04-20 07:17:41 +000011220 {50, 50}))
11221 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
11222 mWindow->consumeMotionDown(ADISPLAY_ID_DEFAULT);
11223
11224 const MotionEvent secondFingerDownEvent =
11225 MotionEventBuilder(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
11226 .displayId(ADISPLAY_ID_DEFAULT)
11227 .eventTime(systemTime(SYSTEM_TIME_MONOTONIC))
Siarhei Vishniakou6d73f832022-07-21 17:27:03 -070011228 .pointer(PointerBuilder(/*id=*/0, ToolType::FINGER).x(50).y(50))
11229 .pointer(PointerBuilder(/*id=*/1, ToolType::FINGER).x(75).y(50))
Arthur Hung54745652022-04-20 07:17:41 +000011230 .build();
11231 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070011232 injectMotionEvent(*mDispatcher, secondFingerDownEvent, INJECT_EVENT_TIMEOUT,
Arthur Hung54745652022-04-20 07:17:41 +000011233 InputEventInjectionSync::WAIT_FOR_RESULT))
11234 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
Harry Cutts33476232023-01-30 19:57:29 +000011235 mWindow->consumeMotionPointerDown(/*pointerIndex=*/1);
Arthur Hung54745652022-04-20 07:17:41 +000011236
11237 // Should not perform drag and drop when window has multi fingers.
Arthur Hungb75c2aa2022-07-15 09:35:36 +000011238 ASSERT_FALSE(startDrag(false));
Arthur Hung54745652022-04-20 07:17:41 +000011239}
11240
11241TEST_F(InputDispatcherDragTests, DragAndDropWhenSplitTouch) {
11242 // First down on second window.
11243 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070011244 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
Arthur Hung54745652022-04-20 07:17:41 +000011245 {150, 50}))
11246 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
11247
11248 mSecondWindow->consumeMotionDown(ADISPLAY_ID_DEFAULT);
11249
11250 // Second down on first window.
11251 const MotionEvent secondFingerDownEvent =
11252 MotionEventBuilder(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
11253 .displayId(ADISPLAY_ID_DEFAULT)
11254 .eventTime(systemTime(SYSTEM_TIME_MONOTONIC))
Siarhei Vishniakou6d73f832022-07-21 17:27:03 -070011255 .pointer(PointerBuilder(/*id=*/0, ToolType::FINGER).x(150).y(50))
11256 .pointer(PointerBuilder(/*id=*/1, ToolType::FINGER).x(50).y(50))
Arthur Hung54745652022-04-20 07:17:41 +000011257 .build();
11258 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070011259 injectMotionEvent(*mDispatcher, secondFingerDownEvent, INJECT_EVENT_TIMEOUT,
Arthur Hung54745652022-04-20 07:17:41 +000011260 InputEventInjectionSync::WAIT_FOR_RESULT))
11261 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
11262 mWindow->consumeMotionDown(ADISPLAY_ID_DEFAULT);
Prabir Pradhan9d5f9ce2024-01-24 00:03:41 +000011263 mSecondWindow->consumeMotionMove(ADISPLAY_ID_DEFAULT);
Arthur Hung54745652022-04-20 07:17:41 +000011264
11265 // Perform drag and drop from first window.
Arthur Hungb75c2aa2022-07-15 09:35:36 +000011266 ASSERT_TRUE(startDrag(false));
Arthur Hung54745652022-04-20 07:17:41 +000011267
11268 // Move on window.
11269 const MotionEvent secondFingerMoveEvent =
11270 MotionEventBuilder(AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN)
11271 .eventTime(systemTime(SYSTEM_TIME_MONOTONIC))
Siarhei Vishniakou6d73f832022-07-21 17:27:03 -070011272 .pointer(PointerBuilder(/*id=*/0, ToolType::FINGER).x(150).y(50))
11273 .pointer(PointerBuilder(/*id=*/1, ToolType::FINGER).x(50).y(50))
Arthur Hung54745652022-04-20 07:17:41 +000011274 .build();
11275 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070011276 injectMotionEvent(*mDispatcher, secondFingerMoveEvent, INJECT_EVENT_TIMEOUT,
Arthur Hung54745652022-04-20 07:17:41 +000011277 InputEventInjectionSync::WAIT_FOR_RESULT));
Prabir Pradhan65455c72024-02-13 21:46:41 +000011278 mDragWindow->consumeMotionMove(ADISPLAY_ID_DEFAULT, AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
Arthur Hung54745652022-04-20 07:17:41 +000011279 mWindow->consumeDragEvent(false, 50, 50);
11280 mSecondWindow->consumeMotionMove();
11281
11282 // Release the drag pointer should perform drop.
11283 const MotionEvent secondFingerUpEvent =
11284 MotionEventBuilder(POINTER_1_UP, AINPUT_SOURCE_TOUCHSCREEN)
11285 .eventTime(systemTime(SYSTEM_TIME_MONOTONIC))
Siarhei Vishniakou6d73f832022-07-21 17:27:03 -070011286 .pointer(PointerBuilder(/*id=*/0, ToolType::FINGER).x(150).y(50))
11287 .pointer(PointerBuilder(/*id=*/1, ToolType::FINGER).x(50).y(50))
Arthur Hung54745652022-04-20 07:17:41 +000011288 .build();
11289 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070011290 injectMotionEvent(*mDispatcher, secondFingerUpEvent, INJECT_EVENT_TIMEOUT,
Arthur Hung54745652022-04-20 07:17:41 +000011291 InputEventInjectionSync::WAIT_FOR_RESULT));
Prabir Pradhan65455c72024-02-13 21:46:41 +000011292 mDragWindow->consumeMotionUp(ADISPLAY_ID_DEFAULT, AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
Siarhei Vishniakoua66d65e2023-06-16 10:32:51 -070011293 mFakePolicy->assertDropTargetEquals(*mDispatcher, mWindow->getToken());
Arthur Hung54745652022-04-20 07:17:41 +000011294 mWindow->assertNoEvents();
11295 mSecondWindow->consumeMotionMove();
11296}
11297
Arthur Hung3915c1f2022-05-31 07:17:17 +000011298TEST_F(InputDispatcherDragTests, DragAndDropWhenMultiDisplays) {
Arthur Hungb75c2aa2022-07-15 09:35:36 +000011299 startDrag();
Arthur Hung3915c1f2022-05-31 07:17:17 +000011300
11301 // Update window of second display.
11302 sp<FakeWindowHandle> windowInSecondary =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -070011303 sp<FakeWindowHandle>::make(mApp, mDispatcher, "D_2", SECOND_DISPLAY_ID);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070011304 mDispatcher->onWindowInfosChanged(
11305 {{*mDragWindow->getInfo(), *mSpyWindow->getInfo(), *mWindow->getInfo(),
11306 *mSecondWindow->getInfo(), *windowInSecondary->getInfo()},
11307 {},
11308 0,
11309 0});
Arthur Hung3915c1f2022-05-31 07:17:17 +000011310
11311 // Let second display has a touch state.
11312 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070011313 injectMotionEvent(*mDispatcher,
Arthur Hung3915c1f2022-05-31 07:17:17 +000011314 MotionEventBuilder(AMOTION_EVENT_ACTION_DOWN,
11315 AINPUT_SOURCE_TOUCHSCREEN)
11316 .displayId(SECOND_DISPLAY_ID)
Siarhei Vishniakou6d73f832022-07-21 17:27:03 -070011317 .pointer(PointerBuilder(0, ToolType::FINGER).x(100).y(100))
Arthur Hung3915c1f2022-05-31 07:17:17 +000011318 .build()));
Prabir Pradhan7662a8d2023-12-15 01:58:14 +000011319 windowInSecondary->consumeMotionDown(SECOND_DISPLAY_ID, /*expectedFlag=*/0);
Arthur Hung3915c1f2022-05-31 07:17:17 +000011320 // Update window again.
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070011321 mDispatcher->onWindowInfosChanged(
11322 {{*mDragWindow->getInfo(), *mSpyWindow->getInfo(), *mWindow->getInfo(),
11323 *mSecondWindow->getInfo(), *windowInSecondary->getInfo()},
11324 {},
11325 0,
11326 0});
Arthur Hung3915c1f2022-05-31 07:17:17 +000011327
11328 // Move on window.
11329 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070011330 injectMotionEvent(*mDispatcher, AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN,
Arthur Hung3915c1f2022-05-31 07:17:17 +000011331 ADISPLAY_ID_DEFAULT, {50, 50}))
11332 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
Prabir Pradhan65455c72024-02-13 21:46:41 +000011333 mDragWindow->consumeMotionMove(ADISPLAY_ID_DEFAULT, AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
Arthur Hung3915c1f2022-05-31 07:17:17 +000011334 mWindow->consumeDragEvent(false, 50, 50);
11335 mSecondWindow->assertNoEvents();
11336
11337 // Move to another window.
11338 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070011339 injectMotionEvent(*mDispatcher, AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN,
Arthur Hung3915c1f2022-05-31 07:17:17 +000011340 ADISPLAY_ID_DEFAULT, {150, 50}))
11341 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
Prabir Pradhan65455c72024-02-13 21:46:41 +000011342 mDragWindow->consumeMotionMove(ADISPLAY_ID_DEFAULT, AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
Arthur Hung3915c1f2022-05-31 07:17:17 +000011343 mWindow->consumeDragEvent(true, 150, 50);
11344 mSecondWindow->consumeDragEvent(false, 50, 50);
11345
11346 // drop to another window.
11347 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070011348 injectMotionUp(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
Arthur Hung3915c1f2022-05-31 07:17:17 +000011349 {150, 50}))
11350 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
Prabir Pradhan65455c72024-02-13 21:46:41 +000011351 mDragWindow->consumeMotionUp(ADISPLAY_ID_DEFAULT, AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
Siarhei Vishniakoua66d65e2023-06-16 10:32:51 -070011352 mFakePolicy->assertDropTargetEquals(*mDispatcher, mSecondWindow->getToken());
Arthur Hung3915c1f2022-05-31 07:17:17 +000011353 mWindow->assertNoEvents();
11354 mSecondWindow->assertNoEvents();
11355}
11356
Arthur Hungb75c2aa2022-07-15 09:35:36 +000011357TEST_F(InputDispatcherDragTests, MouseDragAndDrop) {
11358 startDrag(true, AINPUT_SOURCE_MOUSE);
11359 // Move on window.
11360 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070011361 injectMotionEvent(*mDispatcher,
Arthur Hungb75c2aa2022-07-15 09:35:36 +000011362 MotionEventBuilder(AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_MOUSE)
11363 .buttonState(AMOTION_EVENT_BUTTON_PRIMARY)
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070011364 .pointer(PointerBuilder(MOUSE_POINTER_ID, ToolType::MOUSE)
Arthur Hungb75c2aa2022-07-15 09:35:36 +000011365 .x(50)
11366 .y(50))
11367 .build()))
11368 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
Prabir Pradhan65455c72024-02-13 21:46:41 +000011369 mDragWindow->consumeMotionMove(ADISPLAY_ID_DEFAULT, AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
Arthur Hungb75c2aa2022-07-15 09:35:36 +000011370 mWindow->consumeDragEvent(false, 50, 50);
11371 mSecondWindow->assertNoEvents();
11372
11373 // Move to another window.
11374 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070011375 injectMotionEvent(*mDispatcher,
Arthur Hungb75c2aa2022-07-15 09:35:36 +000011376 MotionEventBuilder(AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_MOUSE)
11377 .buttonState(AMOTION_EVENT_BUTTON_PRIMARY)
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070011378 .pointer(PointerBuilder(MOUSE_POINTER_ID, ToolType::MOUSE)
Arthur Hungb75c2aa2022-07-15 09:35:36 +000011379 .x(150)
11380 .y(50))
11381 .build()))
11382 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
Prabir Pradhan65455c72024-02-13 21:46:41 +000011383 mDragWindow->consumeMotionMove(ADISPLAY_ID_DEFAULT, AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
Arthur Hungb75c2aa2022-07-15 09:35:36 +000011384 mWindow->consumeDragEvent(true, 150, 50);
11385 mSecondWindow->consumeDragEvent(false, 50, 50);
11386
11387 // drop to another window.
11388 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070011389 injectMotionEvent(*mDispatcher,
Arthur Hungb75c2aa2022-07-15 09:35:36 +000011390 MotionEventBuilder(AMOTION_EVENT_ACTION_UP, AINPUT_SOURCE_MOUSE)
11391 .buttonState(0)
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070011392 .pointer(PointerBuilder(MOUSE_POINTER_ID, ToolType::MOUSE)
Arthur Hungb75c2aa2022-07-15 09:35:36 +000011393 .x(150)
11394 .y(50))
11395 .build()))
11396 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
Prabir Pradhan65455c72024-02-13 21:46:41 +000011397 mDragWindow->consumeMotionUp(ADISPLAY_ID_DEFAULT, AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
Siarhei Vishniakoua66d65e2023-06-16 10:32:51 -070011398 mFakePolicy->assertDropTargetEquals(*mDispatcher, mSecondWindow->getToken());
Arthur Hungb75c2aa2022-07-15 09:35:36 +000011399 mWindow->assertNoEvents();
11400 mSecondWindow->assertNoEvents();
11401}
11402
Linnan Li5af92f92023-07-14 14:36:22 +080011403/**
11404 * Start drag and drop with a pointer whose id is not 0, cancel the current touch, and ensure drag
11405 * and drop is also canceled. Then inject a simple gesture, and ensure dispatcher does not crash.
11406 */
11407TEST_F(InputDispatcherDragTests, DragAndDropFinishedWhenCancelCurrentTouch) {
11408 // Down on second window
11409 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
11410 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
11411 {150, 50}))
11412 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
11413
11414 ASSERT_NO_FATAL_FAILURE(mSecondWindow->consumeMotionDown());
11415 ASSERT_NO_FATAL_FAILURE(mSpyWindow->consumeMotionDown());
11416
11417 // Down on first window
11418 const MotionEvent secondFingerDownEvent =
11419 MotionEventBuilder(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
11420 .displayId(ADISPLAY_ID_DEFAULT)
11421 .pointer(PointerBuilder(/*id=*/0, ToolType::FINGER).x(150).y(50))
11422 .pointer(PointerBuilder(/*id=*/1, ToolType::FINGER).x(50).y(50))
11423 .build();
11424 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
11425 injectMotionEvent(*mDispatcher, secondFingerDownEvent, INJECT_EVENT_TIMEOUT,
11426 InputEventInjectionSync::WAIT_FOR_RESULT))
11427 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
11428 ASSERT_NO_FATAL_FAILURE(mWindow->consumeMotionDown());
11429 ASSERT_NO_FATAL_FAILURE(mSecondWindow->consumeMotionMove());
11430 ASSERT_NO_FATAL_FAILURE(mSpyWindow->consumeMotionPointerDown(1));
11431
11432 // Start drag on first window
11433 ASSERT_TRUE(startDrag(/*sendDown=*/false, AINPUT_SOURCE_TOUCHSCREEN));
11434
11435 // Trigger cancel
11436 mDispatcher->cancelCurrentTouch();
11437 ASSERT_NO_FATAL_FAILURE(mSecondWindow->consumeMotionCancel());
Prabir Pradhan65455c72024-02-13 21:46:41 +000011438 ASSERT_NO_FATAL_FAILURE(mDragWindow->consumeMotionCancel(ADISPLAY_ID_DEFAULT,
11439 AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE));
Linnan Li5af92f92023-07-14 14:36:22 +080011440 ASSERT_NO_FATAL_FAILURE(mSpyWindow->consumeMotionCancel());
11441
11442 ASSERT_TRUE(mDispatcher->waitForIdle());
11443 // The D&D finished with nullptr
11444 mFakePolicy->assertDropTargetEquals(*mDispatcher, nullptr);
11445
11446 // Remove drag window
11447 mDispatcher->onWindowInfosChanged({{*mWindow->getInfo(), *mSecondWindow->getInfo()}, {}, 0, 0});
11448
11449 // Inject a simple gesture, ensure dispatcher not crashed
11450 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
11451 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
11452 PointF{50, 50}))
11453 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
11454 ASSERT_NO_FATAL_FAILURE(mWindow->consumeMotionDown());
11455
11456 const MotionEvent moveEvent =
11457 MotionEventBuilder(AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN)
11458 .displayId(ADISPLAY_ID_DEFAULT)
11459 .pointer(PointerBuilder(/*id=*/0, ToolType::FINGER).x(50).y(50))
11460 .build();
11461 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
11462 injectMotionEvent(*mDispatcher, moveEvent, INJECT_EVENT_TIMEOUT,
11463 InputEventInjectionSync::WAIT_FOR_RESULT))
11464 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
11465 ASSERT_NO_FATAL_FAILURE(mWindow->consumeMotionMove());
11466
11467 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
11468 injectMotionUp(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
11469 {50, 50}))
11470 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
11471 ASSERT_NO_FATAL_FAILURE(mWindow->consumeMotionUp());
11472}
11473
Prabir Pradhan9cd9eb62023-11-22 17:58:06 +000011474TEST_F(InputDispatcherDragTests, NoDragAndDropWithHoveringPointer) {
11475 // Start hovering over the window.
11476 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
11477 injectMotionEvent(*mDispatcher, ACTION_HOVER_ENTER, AINPUT_SOURCE_MOUSE,
11478 ADISPLAY_ID_DEFAULT, {50, 50}));
11479
11480 ASSERT_NO_FATAL_FAILURE(mWindow->consumeMotionEvent(WithMotionAction(ACTION_HOVER_ENTER)));
11481 ASSERT_NO_FATAL_FAILURE(mSpyWindow->consumeMotionEvent(WithMotionAction(ACTION_HOVER_ENTER)));
11482
11483 ASSERT_FALSE(startDrag(/*sendDown=*/false))
11484 << "Drag and drop should not work with a hovering pointer";
11485}
11486
Vishnu Nair062a8672021-09-03 16:07:44 -070011487class InputDispatcherDropInputFeatureTest : public InputDispatcherTest {};
11488
11489TEST_F(InputDispatcherDropInputFeatureTest, WindowDropsInput) {
11490 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -070011491 sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher,
11492 "Test window", ADISPLAY_ID_DEFAULT);
Prabir Pradhan51e7db02022-02-07 06:02:57 -080011493 window->setDropInput(true);
Vishnu Nair062a8672021-09-03 16:07:44 -070011494 mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application);
11495 window->setFocusable(true);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070011496 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Vishnu Nair062a8672021-09-03 16:07:44 -070011497 setFocusedWindow(window);
Harry Cutts33476232023-01-30 19:57:29 +000011498 window->consumeFocusEvent(/*hasFocus=*/true, /*inTouchMode=*/true);
Vishnu Nair062a8672021-09-03 16:07:44 -070011499
11500 // With the flag set, window should not get any input
Prabir Pradhan678438e2023-04-13 19:32:51 +000011501 mDispatcher->notifyKey(generateKeyArgs(AKEY_EVENT_ACTION_DOWN, ADISPLAY_ID_DEFAULT));
Vishnu Nair062a8672021-09-03 16:07:44 -070011502 window->assertNoEvents();
11503
Prabir Pradhan678438e2023-04-13 19:32:51 +000011504 mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_DOWN,
11505 AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT));
Siarhei Vishniakou5c02a712023-05-15 15:45:02 -070011506 mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN,
11507 ADISPLAY_ID_DEFAULT));
Siarhei Vishniakoud908f5a2023-11-16 10:25:12 -080011508 mDispatcher->waitForIdle();
Vishnu Nair062a8672021-09-03 16:07:44 -070011509 window->assertNoEvents();
11510
11511 // With the flag cleared, the window should get input
Prabir Pradhan51e7db02022-02-07 06:02:57 -080011512 window->setDropInput(false);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070011513 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Vishnu Nair062a8672021-09-03 16:07:44 -070011514
Prabir Pradhan678438e2023-04-13 19:32:51 +000011515 mDispatcher->notifyKey(generateKeyArgs(AKEY_EVENT_ACTION_UP, ADISPLAY_ID_DEFAULT));
Vishnu Nair062a8672021-09-03 16:07:44 -070011516 window->consumeKeyUp(ADISPLAY_ID_DEFAULT);
11517
Prabir Pradhan678438e2023-04-13 19:32:51 +000011518 mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_DOWN,
11519 AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT));
Vishnu Nair062a8672021-09-03 16:07:44 -070011520 window->consumeMotionDown(ADISPLAY_ID_DEFAULT);
11521 window->assertNoEvents();
11522}
11523
11524TEST_F(InputDispatcherDropInputFeatureTest, ObscuredWindowDropsInput) {
11525 std::shared_ptr<FakeApplicationHandle> obscuringApplication =
11526 std::make_shared<FakeApplicationHandle>();
11527 sp<FakeWindowHandle> obscuringWindow =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -070011528 sp<FakeWindowHandle>::make(obscuringApplication, mDispatcher, "obscuringWindow",
11529 ADISPLAY_ID_DEFAULT);
Vishnu Nair062a8672021-09-03 16:07:44 -070011530 obscuringWindow->setFrame(Rect(0, 0, 50, 50));
Prabir Pradhanaeebeb42023-06-13 19:53:03 +000011531 obscuringWindow->setOwnerInfo(gui::Pid{111}, gui::Uid{111});
Prabir Pradhan4d5c52f2022-01-31 08:52:10 -080011532 obscuringWindow->setTouchable(false);
Vishnu Nair062a8672021-09-03 16:07:44 -070011533 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -070011534 sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher,
11535 "Test window", ADISPLAY_ID_DEFAULT);
Prabir Pradhan51e7db02022-02-07 06:02:57 -080011536 window->setDropInputIfObscured(true);
Prabir Pradhanaeebeb42023-06-13 19:53:03 +000011537 window->setOwnerInfo(gui::Pid{222}, gui::Uid{222});
Vishnu Nair062a8672021-09-03 16:07:44 -070011538 mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application);
11539 window->setFocusable(true);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070011540 mDispatcher->onWindowInfosChanged(
11541 {{*obscuringWindow->getInfo(), *window->getInfo()}, {}, 0, 0});
Vishnu Nair062a8672021-09-03 16:07:44 -070011542 setFocusedWindow(window);
Harry Cutts33476232023-01-30 19:57:29 +000011543 window->consumeFocusEvent(/*hasFocus=*/true, /*inTouchMode=*/true);
Vishnu Nair062a8672021-09-03 16:07:44 -070011544
11545 // With the flag set, window should not get any input
Prabir Pradhan678438e2023-04-13 19:32:51 +000011546 mDispatcher->notifyKey(generateKeyArgs(AKEY_EVENT_ACTION_DOWN, ADISPLAY_ID_DEFAULT));
Vishnu Nair062a8672021-09-03 16:07:44 -070011547 window->assertNoEvents();
11548
Prabir Pradhan678438e2023-04-13 19:32:51 +000011549 mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_DOWN,
11550 AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT));
Siarhei Vishniakou5c02a712023-05-15 15:45:02 -070011551 mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN,
11552 ADISPLAY_ID_DEFAULT));
Vishnu Nair062a8672021-09-03 16:07:44 -070011553 window->assertNoEvents();
11554
11555 // With the flag cleared, the window should get input
Prabir Pradhan51e7db02022-02-07 06:02:57 -080011556 window->setDropInputIfObscured(false);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070011557 mDispatcher->onWindowInfosChanged(
11558 {{*obscuringWindow->getInfo(), *window->getInfo()}, {}, 0, 0});
Vishnu Nair062a8672021-09-03 16:07:44 -070011559
Prabir Pradhan678438e2023-04-13 19:32:51 +000011560 mDispatcher->notifyKey(generateKeyArgs(AKEY_EVENT_ACTION_UP, ADISPLAY_ID_DEFAULT));
Vishnu Nair062a8672021-09-03 16:07:44 -070011561 window->consumeKeyUp(ADISPLAY_ID_DEFAULT);
11562
Prabir Pradhan678438e2023-04-13 19:32:51 +000011563 mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_DOWN,
11564 AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT));
Vishnu Nair062a8672021-09-03 16:07:44 -070011565 window->consumeMotionDown(ADISPLAY_ID_DEFAULT, AMOTION_EVENT_FLAG_WINDOW_IS_PARTIALLY_OBSCURED);
11566 window->assertNoEvents();
11567}
11568
11569TEST_F(InputDispatcherDropInputFeatureTest, UnobscuredWindowGetsInput) {
11570 std::shared_ptr<FakeApplicationHandle> obscuringApplication =
11571 std::make_shared<FakeApplicationHandle>();
11572 sp<FakeWindowHandle> obscuringWindow =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -070011573 sp<FakeWindowHandle>::make(obscuringApplication, mDispatcher, "obscuringWindow",
11574 ADISPLAY_ID_DEFAULT);
Vishnu Nair062a8672021-09-03 16:07:44 -070011575 obscuringWindow->setFrame(Rect(0, 0, 50, 50));
Prabir Pradhanaeebeb42023-06-13 19:53:03 +000011576 obscuringWindow->setOwnerInfo(gui::Pid{111}, gui::Uid{111});
Prabir Pradhan4d5c52f2022-01-31 08:52:10 -080011577 obscuringWindow->setTouchable(false);
Vishnu Nair062a8672021-09-03 16:07:44 -070011578 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -070011579 sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher,
11580 "Test window", ADISPLAY_ID_DEFAULT);
Prabir Pradhan51e7db02022-02-07 06:02:57 -080011581 window->setDropInputIfObscured(true);
Prabir Pradhanaeebeb42023-06-13 19:53:03 +000011582 window->setOwnerInfo(gui::Pid{222}, gui::Uid{222});
Vishnu Nair062a8672021-09-03 16:07:44 -070011583 mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application);
11584 window->setFocusable(true);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070011585 mDispatcher->onWindowInfosChanged(
11586 {{*obscuringWindow->getInfo(), *window->getInfo()}, {}, 0, 0});
Vishnu Nair062a8672021-09-03 16:07:44 -070011587 setFocusedWindow(window);
Harry Cutts33476232023-01-30 19:57:29 +000011588 window->consumeFocusEvent(/*hasFocus=*/true, /*inTouchMode=*/true);
Vishnu Nair062a8672021-09-03 16:07:44 -070011589
11590 // With the flag set, window should not get any input
Prabir Pradhan678438e2023-04-13 19:32:51 +000011591 mDispatcher->notifyKey(generateKeyArgs(AKEY_EVENT_ACTION_DOWN, ADISPLAY_ID_DEFAULT));
Vishnu Nair062a8672021-09-03 16:07:44 -070011592 window->assertNoEvents();
11593
Prabir Pradhan678438e2023-04-13 19:32:51 +000011594 mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_DOWN,
11595 AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT));
Siarhei Vishniakou5c02a712023-05-15 15:45:02 -070011596 mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN,
11597 ADISPLAY_ID_DEFAULT));
Vishnu Nair062a8672021-09-03 16:07:44 -070011598 window->assertNoEvents();
11599
11600 // When the window is no longer obscured because it went on top, it should get input
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070011601 mDispatcher->onWindowInfosChanged(
11602 {{*window->getInfo(), *obscuringWindow->getInfo()}, {}, 0, 0});
Vishnu Nair062a8672021-09-03 16:07:44 -070011603
Prabir Pradhan678438e2023-04-13 19:32:51 +000011604 mDispatcher->notifyKey(generateKeyArgs(AKEY_EVENT_ACTION_UP, ADISPLAY_ID_DEFAULT));
Vishnu Nair062a8672021-09-03 16:07:44 -070011605 window->consumeKeyUp(ADISPLAY_ID_DEFAULT);
11606
Prabir Pradhan678438e2023-04-13 19:32:51 +000011607 mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_DOWN,
11608 AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT));
Vishnu Nair062a8672021-09-03 16:07:44 -070011609 window->consumeMotionDown(ADISPLAY_ID_DEFAULT);
11610 window->assertNoEvents();
11611}
11612
Antonio Kantekf16f2832021-09-28 04:39:20 +000011613class InputDispatcherTouchModeChangedTests : public InputDispatcherTest {
11614protected:
11615 std::shared_ptr<FakeApplicationHandle> mApp;
Antonio Kantek15beb512022-06-13 22:35:41 +000011616 std::shared_ptr<FakeApplicationHandle> mSecondaryApp;
Antonio Kantekf16f2832021-09-28 04:39:20 +000011617 sp<FakeWindowHandle> mWindow;
11618 sp<FakeWindowHandle> mSecondWindow;
Antonio Kantek15beb512022-06-13 22:35:41 +000011619 sp<FakeWindowHandle> mThirdWindow;
Antonio Kantekf16f2832021-09-28 04:39:20 +000011620
11621 void SetUp() override {
11622 InputDispatcherTest::SetUp();
11623
11624 mApp = std::make_shared<FakeApplicationHandle>();
Antonio Kantek15beb512022-06-13 22:35:41 +000011625 mSecondaryApp = std::make_shared<FakeApplicationHandle>();
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -070011626 mWindow = sp<FakeWindowHandle>::make(mApp, mDispatcher, "TestWindow", ADISPLAY_ID_DEFAULT);
Antonio Kantekf16f2832021-09-28 04:39:20 +000011627 mWindow->setFocusable(true);
Antonio Kantek26defcf2022-02-08 01:12:27 +000011628 setFocusedWindow(mWindow);
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -070011629 mSecondWindow =
11630 sp<FakeWindowHandle>::make(mApp, mDispatcher, "TestWindow2", ADISPLAY_ID_DEFAULT);
Antonio Kantekf16f2832021-09-28 04:39:20 +000011631 mSecondWindow->setFocusable(true);
Antonio Kantek15beb512022-06-13 22:35:41 +000011632 mThirdWindow =
11633 sp<FakeWindowHandle>::make(mSecondaryApp, mDispatcher,
11634 "TestWindow3_SecondaryDisplay", SECOND_DISPLAY_ID);
11635 mThirdWindow->setFocusable(true);
Antonio Kantekf16f2832021-09-28 04:39:20 +000011636
11637 mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, mApp);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070011638 mDispatcher->onWindowInfosChanged(
11639 {{*mWindow->getInfo(), *mSecondWindow->getInfo(), *mThirdWindow->getInfo()},
11640 {},
11641 0,
11642 0});
Antonio Kantek15beb512022-06-13 22:35:41 +000011643 mThirdWindow->setOwnerInfo(SECONDARY_WINDOW_PID, SECONDARY_WINDOW_UID);
Antonio Kantekf16f2832021-09-28 04:39:20 +000011644 mWindow->consumeFocusEvent(true);
Antonio Kantek26defcf2022-02-08 01:12:27 +000011645
Antonio Kantek15beb512022-06-13 22:35:41 +000011646 // Set main display initial touch mode to InputDispatcher::kDefaultInTouchMode.
Prabir Pradhan5735a322022-04-11 17:23:34 +000011647 if (mDispatcher->setInTouchMode(InputDispatcher::kDefaultInTouchMode, WINDOW_PID,
Harry Cutts33476232023-01-30 19:57:29 +000011648 WINDOW_UID, /*hasPermission=*/true, ADISPLAY_ID_DEFAULT)) {
Antonio Kantek48710e42022-03-24 14:19:30 -070011649 mWindow->consumeTouchModeEvent(InputDispatcher::kDefaultInTouchMode);
11650 mSecondWindow->consumeTouchModeEvent(InputDispatcher::kDefaultInTouchMode);
Antonio Kantek15beb512022-06-13 22:35:41 +000011651 mThirdWindow->assertNoEvents();
11652 }
11653
11654 // Set secondary display initial touch mode to InputDispatcher::kDefaultInTouchMode.
11655 if (mDispatcher->setInTouchMode(InputDispatcher::kDefaultInTouchMode, SECONDARY_WINDOW_PID,
Harry Cutts33476232023-01-30 19:57:29 +000011656 SECONDARY_WINDOW_UID, /*hasPermission=*/true,
Antonio Kantek15beb512022-06-13 22:35:41 +000011657 SECOND_DISPLAY_ID)) {
11658 mWindow->assertNoEvents();
11659 mSecondWindow->assertNoEvents();
11660 mThirdWindow->consumeTouchModeEvent(InputDispatcher::kDefaultInTouchMode);
Antonio Kantek48710e42022-03-24 14:19:30 -070011661 }
Antonio Kantekf16f2832021-09-28 04:39:20 +000011662 }
11663
Prabir Pradhanaeebeb42023-06-13 19:53:03 +000011664 void changeAndVerifyTouchModeInMainDisplayOnly(bool inTouchMode, gui::Pid pid, gui::Uid uid,
Antonio Kantek15beb512022-06-13 22:35:41 +000011665 bool hasPermission) {
Antonio Kanteka042c022022-07-06 16:51:07 -070011666 ASSERT_TRUE(mDispatcher->setInTouchMode(inTouchMode, pid, uid, hasPermission,
11667 ADISPLAY_ID_DEFAULT));
Antonio Kantekf16f2832021-09-28 04:39:20 +000011668 mWindow->consumeTouchModeEvent(inTouchMode);
11669 mSecondWindow->consumeTouchModeEvent(inTouchMode);
Antonio Kantek15beb512022-06-13 22:35:41 +000011670 mThirdWindow->assertNoEvents();
Antonio Kantekf16f2832021-09-28 04:39:20 +000011671 }
11672};
11673
Antonio Kantek26defcf2022-02-08 01:12:27 +000011674TEST_F(InputDispatcherTouchModeChangedTests, FocusedWindowCanChangeTouchMode) {
Antonio Kantekea47acb2021-12-23 12:41:25 -080011675 const WindowInfo& windowInfo = *mWindow->getInfo();
Antonio Kantek15beb512022-06-13 22:35:41 +000011676 changeAndVerifyTouchModeInMainDisplayOnly(!InputDispatcher::kDefaultInTouchMode,
11677 windowInfo.ownerPid, windowInfo.ownerUid,
Harry Cutts33476232023-01-30 19:57:29 +000011678 /* hasPermission=*/false);
Antonio Kantekf16f2832021-09-28 04:39:20 +000011679}
11680
Antonio Kantek26defcf2022-02-08 01:12:27 +000011681TEST_F(InputDispatcherTouchModeChangedTests, NonFocusedWindowOwnerCannotChangeTouchMode) {
11682 const WindowInfo& windowInfo = *mWindow->getInfo();
Prabir Pradhanaeebeb42023-06-13 19:53:03 +000011683 gui::Pid ownerPid = windowInfo.ownerPid;
Prabir Pradhan8a5c41d2023-06-08 19:13:46 +000011684 gui::Uid ownerUid = windowInfo.ownerUid;
Prabir Pradhanaeebeb42023-06-13 19:53:03 +000011685 mWindow->setOwnerInfo(gui::Pid::INVALID, gui::Uid::INVALID);
Antonio Kantek26defcf2022-02-08 01:12:27 +000011686 ASSERT_FALSE(mDispatcher->setInTouchMode(InputDispatcher::kDefaultInTouchMode, ownerPid,
Harry Cutts33476232023-01-30 19:57:29 +000011687 ownerUid, /*hasPermission=*/false,
Antonio Kanteka042c022022-07-06 16:51:07 -070011688 ADISPLAY_ID_DEFAULT));
Antonio Kantek26defcf2022-02-08 01:12:27 +000011689 mWindow->assertNoEvents();
11690 mSecondWindow->assertNoEvents();
11691}
11692
11693TEST_F(InputDispatcherTouchModeChangedTests, NonWindowOwnerMayChangeTouchModeOnPermissionGranted) {
11694 const WindowInfo& windowInfo = *mWindow->getInfo();
Prabir Pradhanaeebeb42023-06-13 19:53:03 +000011695 gui::Pid ownerPid = windowInfo.ownerPid;
Prabir Pradhan8a5c41d2023-06-08 19:13:46 +000011696 gui::Uid ownerUid = windowInfo.ownerUid;
Prabir Pradhanaeebeb42023-06-13 19:53:03 +000011697 mWindow->setOwnerInfo(gui::Pid::INVALID, gui::Uid::INVALID);
Antonio Kantek15beb512022-06-13 22:35:41 +000011698 changeAndVerifyTouchModeInMainDisplayOnly(!InputDispatcher::kDefaultInTouchMode, ownerPid,
Harry Cutts33476232023-01-30 19:57:29 +000011699 ownerUid, /*hasPermission=*/true);
Antonio Kantek26defcf2022-02-08 01:12:27 +000011700}
11701
Antonio Kantekf16f2832021-09-28 04:39:20 +000011702TEST_F(InputDispatcherTouchModeChangedTests, EventIsNotGeneratedIfNotChangingTouchMode) {
Antonio Kantekea47acb2021-12-23 12:41:25 -080011703 const WindowInfo& windowInfo = *mWindow->getInfo();
Antonio Kantek26defcf2022-02-08 01:12:27 +000011704 ASSERT_FALSE(mDispatcher->setInTouchMode(InputDispatcher::kDefaultInTouchMode,
11705 windowInfo.ownerPid, windowInfo.ownerUid,
Harry Cutts33476232023-01-30 19:57:29 +000011706 /*hasPermission=*/true, ADISPLAY_ID_DEFAULT));
Antonio Kantekf16f2832021-09-28 04:39:20 +000011707 mWindow->assertNoEvents();
11708 mSecondWindow->assertNoEvents();
11709}
11710
Antonio Kantek15beb512022-06-13 22:35:41 +000011711TEST_F(InputDispatcherTouchModeChangedTests, ChangeTouchOnSecondaryDisplayOnly) {
11712 const WindowInfo& windowInfo = *mThirdWindow->getInfo();
11713 ASSERT_TRUE(mDispatcher->setInTouchMode(!InputDispatcher::kDefaultInTouchMode,
11714 windowInfo.ownerPid, windowInfo.ownerUid,
Harry Cutts33476232023-01-30 19:57:29 +000011715 /*hasPermission=*/true, SECOND_DISPLAY_ID));
Antonio Kantek15beb512022-06-13 22:35:41 +000011716 mWindow->assertNoEvents();
11717 mSecondWindow->assertNoEvents();
11718 mThirdWindow->consumeTouchModeEvent(!InputDispatcher::kDefaultInTouchMode);
11719}
11720
Antonio Kantek48710e42022-03-24 14:19:30 -070011721TEST_F(InputDispatcherTouchModeChangedTests, CanChangeTouchModeWhenOwningLastInteractedWindow) {
11722 // Interact with the window first.
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070011723 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
11724 injectKeyDown(*mDispatcher, ADISPLAY_ID_DEFAULT))
Antonio Kantek48710e42022-03-24 14:19:30 -070011725 << "Inject key event should return InputEventInjectionResult::SUCCEEDED";
11726 mWindow->consumeKeyDown(ADISPLAY_ID_DEFAULT);
11727
11728 // Then remove focus.
11729 mWindow->setFocusable(false);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070011730 mDispatcher->onWindowInfosChanged({{*mWindow->getInfo()}, {}, 0, 0});
Antonio Kantek48710e42022-03-24 14:19:30 -070011731
11732 // Assert that caller can switch touch mode by owning one of the last interacted window.
11733 const WindowInfo& windowInfo = *mWindow->getInfo();
11734 ASSERT_TRUE(mDispatcher->setInTouchMode(!InputDispatcher::kDefaultInTouchMode,
11735 windowInfo.ownerPid, windowInfo.ownerUid,
Harry Cutts33476232023-01-30 19:57:29 +000011736 /*hasPermission=*/false, ADISPLAY_ID_DEFAULT));
Antonio Kantek48710e42022-03-24 14:19:30 -070011737}
11738
Prabir Pradhan07e05b62021-11-19 03:57:24 -080011739class InputDispatcherSpyWindowTest : public InputDispatcherTest {
11740public:
Prabir Pradhan4d5c52f2022-01-31 08:52:10 -080011741 sp<FakeWindowHandle> createSpy() {
Prabir Pradhan07e05b62021-11-19 03:57:24 -080011742 std::shared_ptr<FakeApplicationHandle> application =
11743 std::make_shared<FakeApplicationHandle>();
11744 std::string name = "Fake Spy ";
11745 name += std::to_string(mSpyCount++);
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -070011746 sp<FakeWindowHandle> spy = sp<FakeWindowHandle>::make(application, mDispatcher,
11747 name.c_str(), ADISPLAY_ID_DEFAULT);
Prabir Pradhan51e7db02022-02-07 06:02:57 -080011748 spy->setSpy(true);
Prabir Pradhan5c85e052021-12-22 02:27:12 -080011749 spy->setTrustedOverlay(true);
Prabir Pradhan07e05b62021-11-19 03:57:24 -080011750 return spy;
11751 }
11752
11753 sp<FakeWindowHandle> createForeground() {
11754 std::shared_ptr<FakeApplicationHandle> application =
11755 std::make_shared<FakeApplicationHandle>();
11756 sp<FakeWindowHandle> window =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -070011757 sp<FakeWindowHandle>::make(application, mDispatcher, "Fake Window",
11758 ADISPLAY_ID_DEFAULT);
Prabir Pradhan1376fcd2022-01-21 09:56:35 -080011759 window->setFocusable(true);
Prabir Pradhan07e05b62021-11-19 03:57:24 -080011760 return window;
11761 }
11762
11763private:
11764 int mSpyCount{0};
11765};
11766
Prabir Pradhana3ab87a2022-01-27 10:00:21 -080011767using InputDispatcherSpyWindowDeathTest = InputDispatcherSpyWindowTest;
Prabir Pradhan07e05b62021-11-19 03:57:24 -080011768/**
Prabir Pradhan5c85e052021-12-22 02:27:12 -080011769 * Adding a spy window that is not a trusted overlay causes Dispatcher to abort.
11770 */
Prabir Pradhana3ab87a2022-01-27 10:00:21 -080011771TEST_F(InputDispatcherSpyWindowDeathTest, UntrustedSpy_AbortsDispatcher) {
Siarhei Vishniakou21f77bd2023-07-18 17:51:35 -070011772 testing::GTEST_FLAG(death_test_style) = "threadsafe";
Prabir Pradhana3ab87a2022-01-27 10:00:21 -080011773 ScopedSilentDeath _silentDeath;
11774
Prabir Pradhan4d5c52f2022-01-31 08:52:10 -080011775 auto spy = createSpy();
Prabir Pradhan5c85e052021-12-22 02:27:12 -080011776 spy->setTrustedOverlay(false);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070011777 ASSERT_DEATH(mDispatcher->onWindowInfosChanged({{*spy->getInfo()}, {}, 0, 0}),
Prabir Pradhan5c85e052021-12-22 02:27:12 -080011778 ".* not a trusted overlay");
11779}
11780
11781/**
Prabir Pradhan07e05b62021-11-19 03:57:24 -080011782 * Input injection into a display with a spy window but no foreground windows should succeed.
11783 */
11784TEST_F(InputDispatcherSpyWindowTest, NoForegroundWindow) {
Prabir Pradhan4d5c52f2022-01-31 08:52:10 -080011785 auto spy = createSpy();
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070011786 mDispatcher->onWindowInfosChanged({{*spy->getInfo()}, {}, 0, 0});
Prabir Pradhan07e05b62021-11-19 03:57:24 -080011787
11788 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070011789 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT))
Prabir Pradhan07e05b62021-11-19 03:57:24 -080011790 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
11791 spy->consumeMotionDown(ADISPLAY_ID_DEFAULT);
11792}
11793
11794/**
11795 * Verify the order in which different input windows receive events. The touched foreground window
11796 * (if there is one) should always receive the event first. When there are multiple spy windows, the
11797 * spy windows will receive the event according to their Z-order, where the top-most spy window will
11798 * receive events before ones belows it.
11799 *
11800 * Here, we set up a scenario with four windows in the following Z order from the top:
11801 * spy1, spy2, window, spy3.
11802 * We then inject an event and verify that the foreground "window" receives it first, followed by
11803 * "spy1" and "spy2". The "spy3" does not receive the event because it is underneath the foreground
11804 * window.
11805 */
11806TEST_F(InputDispatcherSpyWindowTest, ReceivesInputInOrder) {
11807 auto window = createForeground();
Prabir Pradhan4d5c52f2022-01-31 08:52:10 -080011808 auto spy1 = createSpy();
11809 auto spy2 = createSpy();
11810 auto spy3 = createSpy();
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070011811 mDispatcher->onWindowInfosChanged(
11812 {{*spy1->getInfo(), *spy2->getInfo(), *window->getInfo(), *spy3->getInfo()}, {}, 0, 0});
Prabir Pradhan07e05b62021-11-19 03:57:24 -080011813 const std::vector<sp<FakeWindowHandle>> channels{spy1, spy2, window, spy3};
11814 const size_t numChannels = channels.size();
11815
Michael Wright8e9a8562022-02-09 13:44:29 +000011816 base::unique_fd epollFd(epoll_create1(EPOLL_CLOEXEC));
Prabir Pradhan07e05b62021-11-19 03:57:24 -080011817 if (!epollFd.ok()) {
11818 FAIL() << "Failed to create epoll fd";
11819 }
11820
11821 for (size_t i = 0; i < numChannels; i++) {
11822 struct epoll_event event = {.events = EPOLLIN, .data.u64 = i};
11823 if (epoll_ctl(epollFd.get(), EPOLL_CTL_ADD, channels[i]->getChannelFd(), &event) < 0) {
11824 FAIL() << "Failed to add fd to epoll";
11825 }
11826 }
11827
11828 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070011829 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT))
Prabir Pradhan07e05b62021-11-19 03:57:24 -080011830 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
11831
11832 std::vector<size_t> eventOrder;
11833 std::vector<struct epoll_event> events(numChannels);
11834 for (;;) {
11835 const int nFds = epoll_wait(epollFd.get(), events.data(), static_cast<int>(numChannels),
11836 (100ms).count());
11837 if (nFds < 0) {
11838 FAIL() << "Failed to call epoll_wait";
11839 }
11840 if (nFds == 0) {
11841 break; // epoll_wait timed out
11842 }
11843 for (int i = 0; i < nFds; i++) {
Colin Cross5b799302022-10-18 21:52:41 -070011844 ASSERT_EQ(static_cast<uint32_t>(EPOLLIN), events[i].events);
Siarhei Vishniakou31977182022-09-30 08:51:23 -070011845 eventOrder.push_back(static_cast<size_t>(events[i].data.u64));
Prabir Pradhan07e05b62021-11-19 03:57:24 -080011846 channels[i]->consumeMotionDown();
11847 }
11848 }
11849
11850 // Verify the order in which the events were received.
11851 EXPECT_EQ(3u, eventOrder.size());
11852 EXPECT_EQ(2u, eventOrder[0]); // index 2: window
11853 EXPECT_EQ(0u, eventOrder[1]); // index 0: spy1
11854 EXPECT_EQ(1u, eventOrder[2]); // index 1: spy2
11855}
11856
11857/**
11858 * A spy window using the NOT_TOUCHABLE flag does not receive events.
11859 */
11860TEST_F(InputDispatcherSpyWindowTest, NotTouchable) {
11861 auto window = createForeground();
Prabir Pradhan4d5c52f2022-01-31 08:52:10 -080011862 auto spy = createSpy();
11863 spy->setTouchable(false);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070011864 mDispatcher->onWindowInfosChanged({{*spy->getInfo(), *window->getInfo()}, {}, 0, 0});
Prabir Pradhan07e05b62021-11-19 03:57:24 -080011865
11866 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070011867 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT))
Prabir Pradhan07e05b62021-11-19 03:57:24 -080011868 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
11869 window->consumeMotionDown(ADISPLAY_ID_DEFAULT);
11870 spy->assertNoEvents();
11871}
11872
11873/**
11874 * A spy window will only receive gestures that originate within its touchable region. Gestures that
11875 * have their ACTION_DOWN outside of the touchable region of the spy window will not be dispatched
11876 * to the window.
11877 */
11878TEST_F(InputDispatcherSpyWindowTest, TouchableRegion) {
11879 auto window = createForeground();
Prabir Pradhan4d5c52f2022-01-31 08:52:10 -080011880 auto spy = createSpy();
Prabir Pradhan07e05b62021-11-19 03:57:24 -080011881 spy->setTouchableRegion(Region{{0, 0, 20, 20}});
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070011882 mDispatcher->onWindowInfosChanged({{*spy->getInfo(), *window->getInfo()}, {}, 0, 0});
Prabir Pradhan07e05b62021-11-19 03:57:24 -080011883
11884 // Inject an event outside the spy window's touchable region.
11885 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070011886 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT))
Prabir Pradhan07e05b62021-11-19 03:57:24 -080011887 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
11888 window->consumeMotionDown();
11889 spy->assertNoEvents();
11890 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070011891 injectMotionUp(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT))
Prabir Pradhan07e05b62021-11-19 03:57:24 -080011892 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
11893 window->consumeMotionUp();
11894 spy->assertNoEvents();
11895
11896 // Inject an event inside the spy window's touchable region.
11897 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070011898 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
Prabir Pradhan07e05b62021-11-19 03:57:24 -080011899 {5, 10}))
11900 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
11901 window->consumeMotionDown();
11902 spy->consumeMotionDown();
11903}
11904
11905/**
Prabir Pradhan07e05b62021-11-19 03:57:24 -080011906 * A spy window can listen for touches outside its touchable region using the WATCH_OUTSIDE_TOUCHES
Prabir Pradhandfabf8a2022-01-21 08:19:30 -080011907 * flag, but it will get zero-ed out coordinates if the foreground has a different owner.
Prabir Pradhan07e05b62021-11-19 03:57:24 -080011908 */
11909TEST_F(InputDispatcherSpyWindowTest, WatchOutsideTouches) {
11910 auto window = createForeground();
Prabir Pradhanaeebeb42023-06-13 19:53:03 +000011911 window->setOwnerInfo(gui::Pid{12}, gui::Uid{34});
Prabir Pradhan4d5c52f2022-01-31 08:52:10 -080011912 auto spy = createSpy();
11913 spy->setWatchOutsideTouch(true);
Prabir Pradhanaeebeb42023-06-13 19:53:03 +000011914 spy->setOwnerInfo(gui::Pid{56}, gui::Uid{78});
Prabir Pradhan07e05b62021-11-19 03:57:24 -080011915 spy->setFrame(Rect{0, 0, 20, 20});
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070011916 mDispatcher->onWindowInfosChanged({{*spy->getInfo(), *window->getInfo()}, {}, 0, 0});
Prabir Pradhan07e05b62021-11-19 03:57:24 -080011917
11918 // Inject an event outside the spy window's frame and touchable region.
11919 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070011920 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
Prabir Pradhandfabf8a2022-01-21 08:19:30 -080011921 {100, 200}))
Prabir Pradhan07e05b62021-11-19 03:57:24 -080011922 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
11923 window->consumeMotionDown();
Prabir Pradhandfabf8a2022-01-21 08:19:30 -080011924 spy->consumeMotionOutsideWithZeroedCoords();
Prabir Pradhan07e05b62021-11-19 03:57:24 -080011925}
11926
11927/**
Prabir Pradhan07e05b62021-11-19 03:57:24 -080011928 * Even when a spy window spans over multiple foreground windows, the spy should receive all
11929 * pointers that are down within its bounds.
11930 */
11931TEST_F(InputDispatcherSpyWindowTest, ReceivesMultiplePointers) {
11932 auto windowLeft = createForeground();
11933 windowLeft->setFrame({0, 0, 100, 200});
11934 auto windowRight = createForeground();
11935 windowRight->setFrame({100, 0, 200, 200});
Prabir Pradhan4d5c52f2022-01-31 08:52:10 -080011936 auto spy = createSpy();
Prabir Pradhan07e05b62021-11-19 03:57:24 -080011937 spy->setFrame({0, 0, 200, 200});
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070011938 mDispatcher->onWindowInfosChanged(
11939 {{*spy->getInfo(), *windowLeft->getInfo(), *windowRight->getInfo()}, {}, 0, 0});
Prabir Pradhan07e05b62021-11-19 03:57:24 -080011940
11941 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070011942 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
Prabir Pradhan07e05b62021-11-19 03:57:24 -080011943 {50, 50}))
11944 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
11945 windowLeft->consumeMotionDown();
11946 spy->consumeMotionDown();
11947
11948 const MotionEvent secondFingerDownEvent =
Siarhei Vishniakoua16e3a22022-03-02 15:26:40 -080011949 MotionEventBuilder(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
Prabir Pradhan07e05b62021-11-19 03:57:24 -080011950 .eventTime(systemTime(SYSTEM_TIME_MONOTONIC))
Siarhei Vishniakou6d73f832022-07-21 17:27:03 -070011951 .pointer(PointerBuilder(/*id=*/0, ToolType::FINGER).x(50).y(50))
11952 .pointer(PointerBuilder(/*id=*/1, ToolType::FINGER).x(150).y(50))
Prabir Pradhan07e05b62021-11-19 03:57:24 -080011953 .build();
11954 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070011955 injectMotionEvent(*mDispatcher, secondFingerDownEvent, INJECT_EVENT_TIMEOUT,
Prabir Pradhan07e05b62021-11-19 03:57:24 -080011956 InputEventInjectionSync::WAIT_FOR_RESULT))
11957 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
11958 windowRight->consumeMotionDown();
Harry Cutts33476232023-01-30 19:57:29 +000011959 spy->consumeMotionPointerDown(/*pointerIndex=*/1);
Prabir Pradhan07e05b62021-11-19 03:57:24 -080011960}
11961
11962/**
11963 * When the first pointer lands outside the spy window and the second pointer lands inside it, the
11964 * the spy should receive the second pointer with ACTION_DOWN.
11965 */
11966TEST_F(InputDispatcherSpyWindowTest, ReceivesSecondPointerAsDown) {
11967 auto window = createForeground();
11968 window->setFrame({0, 0, 200, 200});
Prabir Pradhan4d5c52f2022-01-31 08:52:10 -080011969 auto spyRight = createSpy();
Prabir Pradhan07e05b62021-11-19 03:57:24 -080011970 spyRight->setFrame({100, 0, 200, 200});
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070011971 mDispatcher->onWindowInfosChanged({{*spyRight->getInfo(), *window->getInfo()}, {}, 0, 0});
Prabir Pradhan07e05b62021-11-19 03:57:24 -080011972
11973 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070011974 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
Prabir Pradhan07e05b62021-11-19 03:57:24 -080011975 {50, 50}))
11976 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
11977 window->consumeMotionDown();
11978 spyRight->assertNoEvents();
11979
11980 const MotionEvent secondFingerDownEvent =
Siarhei Vishniakoua16e3a22022-03-02 15:26:40 -080011981 MotionEventBuilder(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
Prabir Pradhan07e05b62021-11-19 03:57:24 -080011982 .eventTime(systemTime(SYSTEM_TIME_MONOTONIC))
Siarhei Vishniakou6d73f832022-07-21 17:27:03 -070011983 .pointer(PointerBuilder(/*id=*/0, ToolType::FINGER).x(50).y(50))
11984 .pointer(PointerBuilder(/*id=*/1, ToolType::FINGER).x(150).y(50))
Prabir Pradhan07e05b62021-11-19 03:57:24 -080011985 .build();
11986 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070011987 injectMotionEvent(*mDispatcher, secondFingerDownEvent, INJECT_EVENT_TIMEOUT,
Prabir Pradhan07e05b62021-11-19 03:57:24 -080011988 InputEventInjectionSync::WAIT_FOR_RESULT))
11989 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
Harry Cutts33476232023-01-30 19:57:29 +000011990 window->consumeMotionPointerDown(/*pointerIndex=*/1);
Prabir Pradhan07e05b62021-11-19 03:57:24 -080011991 spyRight->consumeMotionDown();
11992}
11993
Prabir Pradhan1376fcd2022-01-21 09:56:35 -080011994/**
11995 * The spy window should not be able to affect whether or not touches are split. Only the foreground
11996 * windows should be allowed to control split touch.
11997 */
11998TEST_F(InputDispatcherSpyWindowTest, SplitIfNoForegroundWindowTouched) {
Prabir Pradhan76bdecb2022-01-31 11:14:15 -080011999 // This spy window prevents touch splitting. However, we still expect to split touches
Prabir Pradhan1376fcd2022-01-21 09:56:35 -080012000 // because a foreground window has not disabled splitting.
Prabir Pradhan4d5c52f2022-01-31 08:52:10 -080012001 auto spy = createSpy();
Prabir Pradhan76bdecb2022-01-31 11:14:15 -080012002 spy->setPreventSplitting(true);
Prabir Pradhan1376fcd2022-01-21 09:56:35 -080012003
Prabir Pradhan1376fcd2022-01-21 09:56:35 -080012004 auto window = createForeground();
12005 window->setFrame(Rect(0, 0, 100, 100));
Prabir Pradhan1376fcd2022-01-21 09:56:35 -080012006
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070012007 mDispatcher->onWindowInfosChanged({{*spy->getInfo(), *window->getInfo()}, {}, 0, 0});
Prabir Pradhan1376fcd2022-01-21 09:56:35 -080012008
12009 // First finger down, no window touched.
12010 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070012011 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
Prabir Pradhan1376fcd2022-01-21 09:56:35 -080012012 {100, 200}))
12013 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
12014 spy->consumeMotionDown(ADISPLAY_ID_DEFAULT);
12015 window->assertNoEvents();
12016
12017 // Second finger down on window, the window should receive touch down.
12018 const MotionEvent secondFingerDownEvent =
Siarhei Vishniakoua16e3a22022-03-02 15:26:40 -080012019 MotionEventBuilder(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
Prabir Pradhan1376fcd2022-01-21 09:56:35 -080012020 .displayId(ADISPLAY_ID_DEFAULT)
12021 .eventTime(systemTime(SYSTEM_TIME_MONOTONIC))
Siarhei Vishniakou6d73f832022-07-21 17:27:03 -070012022 .pointer(PointerBuilder(/*id=*/0, ToolType::FINGER).x(100).y(200))
12023 .pointer(PointerBuilder(/*id=*/1, ToolType::FINGER).x(50).y(50))
Prabir Pradhan1376fcd2022-01-21 09:56:35 -080012024 .build();
12025 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070012026 injectMotionEvent(*mDispatcher, secondFingerDownEvent, INJECT_EVENT_TIMEOUT,
Prabir Pradhan1376fcd2022-01-21 09:56:35 -080012027 InputEventInjectionSync::WAIT_FOR_RESULT))
12028 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
12029
12030 window->consumeMotionDown(ADISPLAY_ID_DEFAULT);
Harry Cutts33476232023-01-30 19:57:29 +000012031 spy->consumeMotionPointerDown(/*pointerIndex=*/1);
Prabir Pradhan1376fcd2022-01-21 09:56:35 -080012032}
12033
12034/**
12035 * A spy window will usually be implemented as an un-focusable window. Verify that these windows
12036 * do not receive key events.
12037 */
12038TEST_F(InputDispatcherSpyWindowTest, UnfocusableSpyDoesNotReceiveKeyEvents) {
Prabir Pradhan4d5c52f2022-01-31 08:52:10 -080012039 auto spy = createSpy();
Prabir Pradhan1376fcd2022-01-21 09:56:35 -080012040 spy->setFocusable(false);
12041
12042 auto window = createForeground();
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070012043 mDispatcher->onWindowInfosChanged({{*spy->getInfo(), *window->getInfo()}, {}, 0, 0});
Prabir Pradhan1376fcd2022-01-21 09:56:35 -080012044 setFocusedWindow(window);
12045 window->consumeFocusEvent(true);
12046
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070012047 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectKeyDown(*mDispatcher))
Prabir Pradhan1376fcd2022-01-21 09:56:35 -080012048 << "Inject key event should return InputEventInjectionResult::SUCCEEDED";
12049 window->consumeKeyDown(ADISPLAY_ID_NONE);
12050
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070012051 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectKeyUp(*mDispatcher))
Prabir Pradhan1376fcd2022-01-21 09:56:35 -080012052 << "Inject key event should return InputEventInjectionResult::SUCCEEDED";
12053 window->consumeKeyUp(ADISPLAY_ID_NONE);
12054
12055 spy->assertNoEvents();
12056}
12057
Vaibhav Devmurariff798f32022-05-09 23:45:04 +000012058using InputDispatcherPilferPointersTest = InputDispatcherSpyWindowTest;
12059
12060/**
12061 * A spy window can pilfer pointers. When this happens, touch gestures used by the spy window that
12062 * are currently sent to any other windows - including other spy windows - will also be cancelled.
12063 */
12064TEST_F(InputDispatcherPilferPointersTest, PilferPointers) {
12065 auto window = createForeground();
12066 auto spy1 = createSpy();
12067 auto spy2 = createSpy();
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070012068 mDispatcher->onWindowInfosChanged(
12069 {{*spy1->getInfo(), *spy2->getInfo(), *window->getInfo()}, {}, 0, 0});
Vaibhav Devmurariff798f32022-05-09 23:45:04 +000012070
12071 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070012072 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT))
Vaibhav Devmurariff798f32022-05-09 23:45:04 +000012073 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
12074 window->consumeMotionDown();
12075 spy1->consumeMotionDown();
12076 spy2->consumeMotionDown();
12077
12078 // Pilfer pointers from the second spy window.
12079 EXPECT_EQ(OK, mDispatcher->pilferPointers(spy2->getToken()));
12080 spy2->assertNoEvents();
12081 spy1->consumeMotionCancel();
12082 window->consumeMotionCancel();
12083
12084 // The rest of the gesture should only be sent to the second spy window.
12085 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070012086 injectMotionEvent(*mDispatcher, AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN,
Vaibhav Devmurariff798f32022-05-09 23:45:04 +000012087 ADISPLAY_ID_DEFAULT))
12088 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
12089 spy2->consumeMotionMove();
12090 spy1->assertNoEvents();
12091 window->assertNoEvents();
12092}
12093
12094/**
12095 * A spy window can pilfer pointers for a gesture even after the foreground window has been removed
12096 * in the middle of the gesture.
12097 */
12098TEST_F(InputDispatcherPilferPointersTest, CanPilferAfterWindowIsRemovedMidStream) {
12099 auto window = createForeground();
12100 auto spy = createSpy();
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070012101 mDispatcher->onWindowInfosChanged({{*spy->getInfo(), *window->getInfo()}, {}, 0, 0});
Vaibhav Devmurariff798f32022-05-09 23:45:04 +000012102
12103 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070012104 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT))
Vaibhav Devmurariff798f32022-05-09 23:45:04 +000012105 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
12106 window->consumeMotionDown(ADISPLAY_ID_DEFAULT);
12107 spy->consumeMotionDown(ADISPLAY_ID_DEFAULT);
12108
12109 window->releaseChannel();
12110
12111 EXPECT_EQ(OK, mDispatcher->pilferPointers(spy->getToken()));
12112
12113 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070012114 injectMotionUp(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT))
Vaibhav Devmurariff798f32022-05-09 23:45:04 +000012115 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
12116 spy->consumeMotionUp(ADISPLAY_ID_DEFAULT);
12117}
12118
12119/**
12120 * After a spy window pilfers pointers, new pointers that go down in its bounds should be sent to
12121 * the spy, but not to any other windows.
12122 */
12123TEST_F(InputDispatcherPilferPointersTest, ContinuesToReceiveGestureAfterPilfer) {
12124 auto spy = createSpy();
12125 auto window = createForeground();
12126
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070012127 mDispatcher->onWindowInfosChanged({{*spy->getInfo(), *window->getInfo()}, {}, 0, 0});
Vaibhav Devmurariff798f32022-05-09 23:45:04 +000012128
12129 // First finger down on the window and the spy.
12130 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070012131 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
Vaibhav Devmurariff798f32022-05-09 23:45:04 +000012132 {100, 200}))
12133 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
12134 spy->consumeMotionDown();
12135 window->consumeMotionDown();
12136
12137 // Spy window pilfers the pointers.
12138 EXPECT_EQ(OK, mDispatcher->pilferPointers(spy->getToken()));
12139 window->consumeMotionCancel();
12140
12141 // Second finger down on the window and spy, but the window should not receive the pointer down.
12142 const MotionEvent secondFingerDownEvent =
12143 MotionEventBuilder(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
12144 .displayId(ADISPLAY_ID_DEFAULT)
12145 .eventTime(systemTime(SYSTEM_TIME_MONOTONIC))
Siarhei Vishniakou6d73f832022-07-21 17:27:03 -070012146 .pointer(PointerBuilder(/*id=*/0, ToolType::FINGER).x(100).y(200))
12147 .pointer(PointerBuilder(/*id=*/1, ToolType::FINGER).x(50).y(50))
Vaibhav Devmurariff798f32022-05-09 23:45:04 +000012148 .build();
12149 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070012150 injectMotionEvent(*mDispatcher, secondFingerDownEvent, INJECT_EVENT_TIMEOUT,
Vaibhav Devmurariff798f32022-05-09 23:45:04 +000012151 InputEventInjectionSync::WAIT_FOR_RESULT))
12152 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
12153
Harry Cutts33476232023-01-30 19:57:29 +000012154 spy->consumeMotionPointerDown(/*pointerIndex=*/1);
Vaibhav Devmurariff798f32022-05-09 23:45:04 +000012155
12156 // Third finger goes down outside all windows, so injection should fail.
12157 const MotionEvent thirdFingerDownEvent =
12158 MotionEventBuilder(POINTER_2_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(100).y(200))
12162 .pointer(PointerBuilder(/*id=*/1, ToolType::FINGER).x(50).y(50))
12163 .pointer(PointerBuilder(/*id=*/2, ToolType::FINGER).x(-5).y(-5))
Vaibhav Devmurariff798f32022-05-09 23:45:04 +000012164 .build();
12165 ASSERT_EQ(InputEventInjectionResult::FAILED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070012166 injectMotionEvent(*mDispatcher, thirdFingerDownEvent, INJECT_EVENT_TIMEOUT,
Vaibhav Devmurariff798f32022-05-09 23:45:04 +000012167 InputEventInjectionSync::WAIT_FOR_RESULT))
Siarhei Vishniakou1ae72f12023-01-29 12:55:30 -080012168 << "Inject motion event should return InputEventInjectionResult::FAILED";
Vaibhav Devmurariff798f32022-05-09 23:45:04 +000012169
12170 spy->assertNoEvents();
12171 window->assertNoEvents();
12172}
12173
12174/**
12175 * After a spy window pilfers pointers, only the pointers used by the spy should be canceled
12176 */
12177TEST_F(InputDispatcherPilferPointersTest, PartiallyPilferRequiredPointers) {
12178 auto spy = createSpy();
12179 spy->setFrame(Rect(0, 0, 100, 100));
12180 auto window = createForeground();
12181 window->setFrame(Rect(0, 0, 200, 200));
12182
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070012183 mDispatcher->onWindowInfosChanged({{*spy->getInfo(), *window->getInfo()}, {}, 0, 0});
Vaibhav Devmurariff798f32022-05-09 23:45:04 +000012184
12185 // First finger down on the window only
12186 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070012187 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
Vaibhav Devmurariff798f32022-05-09 23:45:04 +000012188 {150, 150}))
12189 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
12190 window->consumeMotionDown();
12191
12192 // Second finger down on the spy and window
12193 const MotionEvent secondFingerDownEvent =
12194 MotionEventBuilder(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
12195 .displayId(ADISPLAY_ID_DEFAULT)
12196 .eventTime(systemTime(SYSTEM_TIME_MONOTONIC))
Siarhei Vishniakou6d73f832022-07-21 17:27:03 -070012197 .pointer(PointerBuilder(/*id=*/0, ToolType::FINGER).x(150).y(150))
12198 .pointer(PointerBuilder(/*id=*/1, ToolType::FINGER).x(10).y(10))
Vaibhav Devmurariff798f32022-05-09 23:45:04 +000012199 .build();
12200 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070012201 injectMotionEvent(*mDispatcher, secondFingerDownEvent, INJECT_EVENT_TIMEOUT,
Vaibhav Devmurariff798f32022-05-09 23:45:04 +000012202 InputEventInjectionSync::WAIT_FOR_RESULT))
12203 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
12204 spy->consumeMotionDown();
12205 window->consumeMotionPointerDown(1);
12206
12207 // Third finger down on the spy and window
12208 const MotionEvent thirdFingerDownEvent =
12209 MotionEventBuilder(POINTER_2_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
12210 .displayId(ADISPLAY_ID_DEFAULT)
12211 .eventTime(systemTime(SYSTEM_TIME_MONOTONIC))
Siarhei Vishniakou6d73f832022-07-21 17:27:03 -070012212 .pointer(PointerBuilder(/*id=*/0, ToolType::FINGER).x(150).y(150))
12213 .pointer(PointerBuilder(/*id=*/1, ToolType::FINGER).x(10).y(10))
12214 .pointer(PointerBuilder(/*id=*/2, ToolType::FINGER).x(50).y(50))
Vaibhav Devmurariff798f32022-05-09 23:45:04 +000012215 .build();
12216 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070012217 injectMotionEvent(*mDispatcher, thirdFingerDownEvent, INJECT_EVENT_TIMEOUT,
Vaibhav Devmurariff798f32022-05-09 23:45:04 +000012218 InputEventInjectionSync::WAIT_FOR_RESULT))
12219 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
12220 spy->consumeMotionPointerDown(1);
12221 window->consumeMotionPointerDown(2);
12222
12223 // Spy window pilfers the pointers.
12224 EXPECT_EQ(OK, mDispatcher->pilferPointers(spy->getToken()));
Harry Cutts101ee9b2023-07-06 18:04:14 +000012225 window->consumeMotionPointerUp(/*idx=*/2, ADISPLAY_ID_DEFAULT, AMOTION_EVENT_FLAG_CANCELED);
12226 window->consumeMotionPointerUp(/*idx=*/1, ADISPLAY_ID_DEFAULT, AMOTION_EVENT_FLAG_CANCELED);
Vaibhav Devmurariff798f32022-05-09 23:45:04 +000012227
12228 spy->assertNoEvents();
12229 window->assertNoEvents();
12230}
12231
12232/**
12233 * After a spy window pilfers pointers, all pilfered pointers that have already been dispatched to
12234 * other windows should be canceled. If this results in the cancellation of all pointers for some
12235 * window, then that window should receive ACTION_CANCEL.
12236 */
12237TEST_F(InputDispatcherPilferPointersTest, PilferAllRequiredPointers) {
12238 auto spy = createSpy();
12239 spy->setFrame(Rect(0, 0, 100, 100));
12240 auto window = createForeground();
12241 window->setFrame(Rect(0, 0, 200, 200));
12242
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070012243 mDispatcher->onWindowInfosChanged({{*spy->getInfo(), *window->getInfo()}, {}, 0, 0});
Vaibhav Devmurariff798f32022-05-09 23:45:04 +000012244
12245 // First finger down on both spy and window
12246 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070012247 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
Vaibhav Devmurariff798f32022-05-09 23:45:04 +000012248 {10, 10}))
12249 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
12250 window->consumeMotionDown();
12251 spy->consumeMotionDown();
12252
12253 // Second finger down on the spy and window
12254 const MotionEvent secondFingerDownEvent =
12255 MotionEventBuilder(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
12256 .displayId(ADISPLAY_ID_DEFAULT)
12257 .eventTime(systemTime(SYSTEM_TIME_MONOTONIC))
Siarhei Vishniakou6d73f832022-07-21 17:27:03 -070012258 .pointer(PointerBuilder(/*id=*/0, ToolType::FINGER).x(10).y(10))
12259 .pointer(PointerBuilder(/*id=*/1, ToolType::FINGER).x(50).y(50))
Vaibhav Devmurariff798f32022-05-09 23:45:04 +000012260 .build();
12261 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070012262 injectMotionEvent(*mDispatcher, secondFingerDownEvent, INJECT_EVENT_TIMEOUT,
Vaibhav Devmurariff798f32022-05-09 23:45:04 +000012263 InputEventInjectionSync::WAIT_FOR_RESULT))
12264 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
12265 spy->consumeMotionPointerDown(1);
12266 window->consumeMotionPointerDown(1);
12267
12268 // Spy window pilfers the pointers.
12269 EXPECT_EQ(OK, mDispatcher->pilferPointers(spy->getToken()));
12270 window->consumeMotionCancel();
12271
12272 spy->assertNoEvents();
12273 window->assertNoEvents();
12274}
12275
12276/**
12277 * After a spy window pilfers pointers, new pointers that are not touching the spy window can still
12278 * be sent to other windows
12279 */
12280TEST_F(InputDispatcherPilferPointersTest, CanReceivePointersAfterPilfer) {
12281 auto spy = createSpy();
12282 spy->setFrame(Rect(0, 0, 100, 100));
12283 auto window = createForeground();
12284 window->setFrame(Rect(0, 0, 200, 200));
12285
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070012286 mDispatcher->onWindowInfosChanged({{*spy->getInfo(), *window->getInfo()}, {}, 0, 0});
Vaibhav Devmurariff798f32022-05-09 23:45:04 +000012287
12288 // First finger down on both window and spy
12289 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070012290 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
Vaibhav Devmurariff798f32022-05-09 23:45:04 +000012291 {10, 10}))
12292 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
12293 window->consumeMotionDown();
12294 spy->consumeMotionDown();
12295
12296 // Spy window pilfers the pointers.
12297 EXPECT_EQ(OK, mDispatcher->pilferPointers(spy->getToken()));
12298 window->consumeMotionCancel();
12299
12300 // Second finger down on the window only
12301 const MotionEvent secondFingerDownEvent =
12302 MotionEventBuilder(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
12303 .displayId(ADISPLAY_ID_DEFAULT)
12304 .eventTime(systemTime(SYSTEM_TIME_MONOTONIC))
Siarhei Vishniakou6d73f832022-07-21 17:27:03 -070012305 .pointer(PointerBuilder(/*id=*/0, ToolType::FINGER).x(10).y(10))
12306 .pointer(PointerBuilder(/*id=*/1, ToolType::FINGER).x(150).y(150))
Vaibhav Devmurariff798f32022-05-09 23:45:04 +000012307 .build();
12308 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070012309 injectMotionEvent(*mDispatcher, secondFingerDownEvent, INJECT_EVENT_TIMEOUT,
Vaibhav Devmurariff798f32022-05-09 23:45:04 +000012310 InputEventInjectionSync::WAIT_FOR_RESULT))
12311 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
12312 window->consumeMotionDown();
12313 window->assertNoEvents();
12314
12315 // TODO(b/232530217): do not send the unnecessary MOVE event and delete the next line
12316 spy->consumeMotionMove();
12317 spy->assertNoEvents();
12318}
12319
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -070012320/**
12321 * A window on the left and a window on the right. Also, a spy window that's above all of the
12322 * windows, and spanning both left and right windows.
12323 * Send simultaneous motion streams from two different devices, one to the left window, and another
12324 * to the right window.
12325 * Pilfer from spy window.
12326 * Check that the pilfering only affects the pointers that are actually being received by the spy.
12327 */
Siarhei Vishniakoued89cbb2023-10-13 10:42:44 -070012328TEST_F(InputDispatcherPilferPointersTest, MultiDevicePilfer_legacy) {
12329 SCOPED_FLAG_OVERRIDE(enable_multi_device_same_window_stream, false);
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -070012330 sp<FakeWindowHandle> spy = createSpy();
12331 spy->setFrame(Rect(0, 0, 200, 200));
12332 sp<FakeWindowHandle> leftWindow = createForeground();
12333 leftWindow->setFrame(Rect(0, 0, 100, 100));
12334
12335 sp<FakeWindowHandle> rightWindow = createForeground();
12336 rightWindow->setFrame(Rect(100, 0, 200, 100));
12337
12338 constexpr int32_t stylusDeviceId = 1;
12339 constexpr int32_t touchDeviceId = 2;
12340
12341 mDispatcher->onWindowInfosChanged(
12342 {{*spy->getInfo(), *leftWindow->getInfo(), *rightWindow->getInfo()}, {}, 0, 0});
12343
12344 // Stylus down on left window and spy
12345 mDispatcher->notifyMotion(MotionArgsBuilder(AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_STYLUS)
12346 .deviceId(stylusDeviceId)
12347 .pointer(PointerBuilder(0, ToolType::STYLUS).x(50).y(50))
12348 .build());
12349 leftWindow->consumeMotionEvent(
12350 AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(stylusDeviceId)));
12351 spy->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(stylusDeviceId)));
12352
12353 // Finger down on right window and spy - but spy already has stylus
12354 mDispatcher->notifyMotion(
12355 MotionArgsBuilder(AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
12356 .deviceId(touchDeviceId)
12357 .pointer(PointerBuilder(0, ToolType::FINGER).x(150).y(50))
12358 .build());
12359 rightWindow->consumeMotionEvent(
12360 AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(touchDeviceId)));
Siarhei Vishniakou2899c552023-07-10 18:20:46 -070012361 spy->assertNoEvents();
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -070012362
12363 // Act: pilfer from spy. Spy is currently receiving touch events.
12364 EXPECT_EQ(OK, mDispatcher->pilferPointers(spy->getToken()));
Siarhei Vishniakou2899c552023-07-10 18:20:46 -070012365 leftWindow->consumeMotionEvent(
12366 AllOf(WithMotionAction(ACTION_CANCEL), WithDeviceId(stylusDeviceId)));
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -070012367 rightWindow->consumeMotionEvent(
12368 AllOf(WithMotionAction(ACTION_CANCEL), WithDeviceId(touchDeviceId)));
12369
12370 // Continue movements from both stylus and touch. Touch will be delivered to spy, but not stylus
12371 mDispatcher->notifyMotion(MotionArgsBuilder(AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_STYLUS)
12372 .deviceId(stylusDeviceId)
12373 .pointer(PointerBuilder(0, ToolType::STYLUS).x(51).y(52))
12374 .build());
12375 mDispatcher->notifyMotion(
12376 MotionArgsBuilder(AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN)
12377 .deviceId(touchDeviceId)
12378 .pointer(PointerBuilder(0, ToolType::FINGER).x(151).y(52))
12379 .build());
Siarhei Vishniakou2899c552023-07-10 18:20:46 -070012380 spy->consumeMotionEvent(AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(stylusDeviceId)));
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -070012381
12382 spy->assertNoEvents();
12383 leftWindow->assertNoEvents();
12384 rightWindow->assertNoEvents();
12385}
12386
Siarhei Vishniakoued89cbb2023-10-13 10:42:44 -070012387/**
12388 * A window on the left and a window on the right. Also, a spy window that's above all of the
12389 * windows, and spanning both left and right windows.
12390 * Send simultaneous motion streams from two different devices, one to the left window, and another
12391 * to the right window.
12392 * Pilfer from spy window.
12393 * Check that the pilfering affects all of the pointers that are actually being received by the spy.
12394 * The spy should receive both the touch and the stylus events after pilfer.
12395 */
12396TEST_F(InputDispatcherPilferPointersTest, MultiDevicePilfer) {
12397 SCOPED_FLAG_OVERRIDE(enable_multi_device_same_window_stream, true);
12398 sp<FakeWindowHandle> spy = createSpy();
12399 spy->setFrame(Rect(0, 0, 200, 200));
12400 sp<FakeWindowHandle> leftWindow = createForeground();
12401 leftWindow->setFrame(Rect(0, 0, 100, 100));
12402
12403 sp<FakeWindowHandle> rightWindow = createForeground();
12404 rightWindow->setFrame(Rect(100, 0, 200, 100));
12405
12406 constexpr int32_t stylusDeviceId = 1;
12407 constexpr int32_t touchDeviceId = 2;
12408
12409 mDispatcher->onWindowInfosChanged(
12410 {{*spy->getInfo(), *leftWindow->getInfo(), *rightWindow->getInfo()}, {}, 0, 0});
12411
12412 // Stylus down on left window and spy
12413 mDispatcher->notifyMotion(MotionArgsBuilder(AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_STYLUS)
12414 .deviceId(stylusDeviceId)
12415 .pointer(PointerBuilder(0, ToolType::STYLUS).x(50).y(50))
12416 .build());
12417 leftWindow->consumeMotionEvent(
12418 AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(stylusDeviceId)));
12419 spy->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(stylusDeviceId)));
12420
12421 // Finger down on right window and spy
12422 mDispatcher->notifyMotion(
12423 MotionArgsBuilder(AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
12424 .deviceId(touchDeviceId)
12425 .pointer(PointerBuilder(0, ToolType::FINGER).x(150).y(50))
12426 .build());
12427 rightWindow->consumeMotionEvent(
12428 AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(touchDeviceId)));
12429 spy->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(touchDeviceId)));
12430
12431 // Act: pilfer from spy. Spy is currently receiving touch events.
12432 EXPECT_EQ(OK, mDispatcher->pilferPointers(spy->getToken()));
12433 leftWindow->consumeMotionEvent(
12434 AllOf(WithMotionAction(ACTION_CANCEL), WithDeviceId(stylusDeviceId)));
12435 rightWindow->consumeMotionEvent(
12436 AllOf(WithMotionAction(ACTION_CANCEL), WithDeviceId(touchDeviceId)));
12437
12438 // Continue movements from both stylus and touch. Touch and stylus will be delivered to spy
Siarhei Vishniakou92bca1c2024-04-01 14:06:59 -070012439 // Instead of sending the two MOVE events for each input device together, and then receiving
12440 // them both, process them one at at time. InputConsumer is always in the batching mode, which
12441 // means that the two MOVE events will be initially put into a batch. Once the events are
12442 // batched, the 'consume' call may result in any of the MOVE events to be sent first (depending
12443 // on the implementation of InputConsumer), which would mean that the order of the received
12444 // events could be different depending on whether there are 1 or 2 events pending in the
12445 // InputChannel at the time the test calls 'consume'. To make assertions simpler here, and to
12446 // avoid this confusing behaviour, send and receive each MOVE event separately.
Siarhei Vishniakoued89cbb2023-10-13 10:42:44 -070012447 mDispatcher->notifyMotion(MotionArgsBuilder(AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_STYLUS)
12448 .deviceId(stylusDeviceId)
12449 .pointer(PointerBuilder(0, ToolType::STYLUS).x(51).y(52))
12450 .build());
Siarhei Vishniakou92bca1c2024-04-01 14:06:59 -070012451 spy->consumeMotionEvent(AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(stylusDeviceId)));
Siarhei Vishniakoued89cbb2023-10-13 10:42:44 -070012452 mDispatcher->notifyMotion(
12453 MotionArgsBuilder(AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN)
12454 .deviceId(touchDeviceId)
12455 .pointer(PointerBuilder(0, ToolType::FINGER).x(151).y(52))
12456 .build());
Siarhei Vishniakou92bca1c2024-04-01 14:06:59 -070012457 spy->consumeMotionEvent(AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(touchDeviceId)));
Siarhei Vishniakoued89cbb2023-10-13 10:42:44 -070012458
12459 spy->assertNoEvents();
12460 leftWindow->assertNoEvents();
12461 rightWindow->assertNoEvents();
12462}
12463
Prabir Pradhan9cd9eb62023-11-22 17:58:06 +000012464TEST_F(InputDispatcherPilferPointersTest, NoPilferingWithHoveringPointers) {
12465 auto window = createForeground();
12466 auto spy = createSpy();
12467 mDispatcher->onWindowInfosChanged({{*spy->getInfo(), *window->getInfo()}, {}, 0, 0});
12468
12469 mDispatcher->notifyMotion(
12470 MotionArgsBuilder(ACTION_HOVER_ENTER, AINPUT_SOURCE_MOUSE)
12471 .deviceId(1)
12472 .pointer(PointerBuilder(/*id=*/0, ToolType::MOUSE).x(100).y(200))
12473 .build());
12474 window->consumeMotionEvent(WithMotionAction(ACTION_HOVER_ENTER));
12475 spy->consumeMotionEvent(WithMotionAction(ACTION_HOVER_ENTER));
12476
12477 // Pilfer pointers from the spy window should fail.
12478 EXPECT_NE(OK, mDispatcher->pilferPointers(spy->getToken()));
12479 spy->assertNoEvents();
12480 window->assertNoEvents();
12481}
12482
Prabir Pradhand65552b2021-10-07 11:23:50 -070012483class InputDispatcherStylusInterceptorTest : public InputDispatcherTest {
12484public:
12485 std::pair<sp<FakeWindowHandle>, sp<FakeWindowHandle>> setupStylusOverlayScenario() {
12486 std::shared_ptr<FakeApplicationHandle> overlayApplication =
12487 std::make_shared<FakeApplicationHandle>();
12488 sp<FakeWindowHandle> overlay =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -070012489 sp<FakeWindowHandle>::make(overlayApplication, mDispatcher,
12490 "Stylus interceptor window", ADISPLAY_ID_DEFAULT);
Prabir Pradhand65552b2021-10-07 11:23:50 -070012491 overlay->setFocusable(false);
Prabir Pradhanaeebeb42023-06-13 19:53:03 +000012492 overlay->setOwnerInfo(gui::Pid{111}, gui::Uid{111});
Prabir Pradhan4d5c52f2022-01-31 08:52:10 -080012493 overlay->setTouchable(false);
Prabir Pradhan51e7db02022-02-07 06:02:57 -080012494 overlay->setInterceptsStylus(true);
Prabir Pradhand65552b2021-10-07 11:23:50 -070012495 overlay->setTrustedOverlay(true);
12496
12497 std::shared_ptr<FakeApplicationHandle> application =
12498 std::make_shared<FakeApplicationHandle>();
12499 sp<FakeWindowHandle> window =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -070012500 sp<FakeWindowHandle>::make(application, mDispatcher, "Application window",
12501 ADISPLAY_ID_DEFAULT);
Prabir Pradhand65552b2021-10-07 11:23:50 -070012502 window->setFocusable(true);
Prabir Pradhanaeebeb42023-06-13 19:53:03 +000012503 window->setOwnerInfo(gui::Pid{222}, gui::Uid{222});
Prabir Pradhand65552b2021-10-07 11:23:50 -070012504
12505 mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070012506 mDispatcher->onWindowInfosChanged({{*overlay->getInfo(), *window->getInfo()}, {}, 0, 0});
Prabir Pradhand65552b2021-10-07 11:23:50 -070012507 setFocusedWindow(window);
Harry Cutts33476232023-01-30 19:57:29 +000012508 window->consumeFocusEvent(/*hasFocus=*/true, /*inTouchMode=*/true);
Prabir Pradhand65552b2021-10-07 11:23:50 -070012509 return {std::move(overlay), std::move(window)};
12510 }
12511
12512 void sendFingerEvent(int32_t action) {
Prabir Pradhan678438e2023-04-13 19:32:51 +000012513 mDispatcher->notifyMotion(
Prabir Pradhand65552b2021-10-07 11:23:50 -070012514 generateMotionArgs(action, AINPUT_SOURCE_TOUCHSCREEN | AINPUT_SOURCE_STYLUS,
Prabir Pradhan678438e2023-04-13 19:32:51 +000012515 ADISPLAY_ID_DEFAULT, {PointF{20, 20}}));
Prabir Pradhand65552b2021-10-07 11:23:50 -070012516 }
12517
12518 void sendStylusEvent(int32_t action) {
12519 NotifyMotionArgs motionArgs =
12520 generateMotionArgs(action, AINPUT_SOURCE_TOUCHSCREEN | AINPUT_SOURCE_STYLUS,
12521 ADISPLAY_ID_DEFAULT, {PointF{30, 40}});
Siarhei Vishniakou6d73f832022-07-21 17:27:03 -070012522 motionArgs.pointerProperties[0].toolType = ToolType::STYLUS;
Prabir Pradhan678438e2023-04-13 19:32:51 +000012523 mDispatcher->notifyMotion(motionArgs);
Prabir Pradhand65552b2021-10-07 11:23:50 -070012524 }
12525};
12526
Prabir Pradhana3ab87a2022-01-27 10:00:21 -080012527using InputDispatcherStylusInterceptorDeathTest = InputDispatcherStylusInterceptorTest;
12528
12529TEST_F(InputDispatcherStylusInterceptorDeathTest, UntrustedOverlay_AbortsDispatcher) {
Siarhei Vishniakouad3b6822023-06-22 14:17:35 -070012530 testing::GTEST_FLAG(death_test_style) = "threadsafe";
Prabir Pradhana3ab87a2022-01-27 10:00:21 -080012531 ScopedSilentDeath _silentDeath;
12532
Prabir Pradhand65552b2021-10-07 11:23:50 -070012533 auto [overlay, window] = setupStylusOverlayScenario();
12534 overlay->setTrustedOverlay(false);
12535 // Configuring an untrusted overlay as a stylus interceptor should cause Dispatcher to abort.
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070012536 ASSERT_DEATH(mDispatcher->onWindowInfosChanged(
12537 {{*overlay->getInfo(), *window->getInfo()}, {}, 0, 0}),
Prabir Pradhand65552b2021-10-07 11:23:50 -070012538 ".* not a trusted overlay");
12539}
12540
12541TEST_F(InputDispatcherStylusInterceptorTest, ConsmesOnlyStylusEvents) {
12542 auto [overlay, window] = setupStylusOverlayScenario();
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070012543 mDispatcher->onWindowInfosChanged({{*overlay->getInfo(), *window->getInfo()}, {}, 0, 0});
Prabir Pradhand65552b2021-10-07 11:23:50 -070012544
12545 sendStylusEvent(AMOTION_EVENT_ACTION_DOWN);
12546 overlay->consumeMotionDown();
12547 sendStylusEvent(AMOTION_EVENT_ACTION_UP);
12548 overlay->consumeMotionUp();
12549
12550 sendFingerEvent(AMOTION_EVENT_ACTION_DOWN);
12551 window->consumeMotionDown();
12552 sendFingerEvent(AMOTION_EVENT_ACTION_UP);
12553 window->consumeMotionUp();
12554
12555 overlay->assertNoEvents();
12556 window->assertNoEvents();
12557}
12558
12559TEST_F(InputDispatcherStylusInterceptorTest, SpyWindowStylusInterceptor) {
12560 auto [overlay, window] = setupStylusOverlayScenario();
Prabir Pradhan51e7db02022-02-07 06:02:57 -080012561 overlay->setSpy(true);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070012562 mDispatcher->onWindowInfosChanged({{*overlay->getInfo(), *window->getInfo()}, {}, 0, 0});
Prabir Pradhand65552b2021-10-07 11:23:50 -070012563
12564 sendStylusEvent(AMOTION_EVENT_ACTION_DOWN);
12565 overlay->consumeMotionDown();
12566 window->consumeMotionDown();
12567 sendStylusEvent(AMOTION_EVENT_ACTION_UP);
12568 overlay->consumeMotionUp();
12569 window->consumeMotionUp();
12570
12571 sendFingerEvent(AMOTION_EVENT_ACTION_DOWN);
12572 window->consumeMotionDown();
12573 sendFingerEvent(AMOTION_EVENT_ACTION_UP);
12574 window->consumeMotionUp();
12575
12576 overlay->assertNoEvents();
12577 window->assertNoEvents();
12578}
12579
Prabir Pradhan6dfbf262022-03-14 15:24:30 +000012580/**
12581 * Set up a scenario to test the behavior used by the stylus handwriting detection feature.
12582 * The scenario is as follows:
12583 * - The stylus interceptor overlay is configured as a spy window.
12584 * - The stylus interceptor spy receives the start of a new stylus gesture.
12585 * - It pilfers pointers and then configures itself to no longer be a spy.
12586 * - The stylus interceptor continues to receive the rest of the gesture.
12587 */
12588TEST_F(InputDispatcherStylusInterceptorTest, StylusHandwritingScenario) {
12589 auto [overlay, window] = setupStylusOverlayScenario();
12590 overlay->setSpy(true);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070012591 mDispatcher->onWindowInfosChanged({{*overlay->getInfo(), *window->getInfo()}, {}, 0, 0});
Prabir Pradhan6dfbf262022-03-14 15:24:30 +000012592
12593 sendStylusEvent(AMOTION_EVENT_ACTION_DOWN);
12594 overlay->consumeMotionDown();
12595 window->consumeMotionDown();
12596
12597 // The interceptor pilfers the pointers.
12598 EXPECT_EQ(OK, mDispatcher->pilferPointers(overlay->getToken()));
12599 window->consumeMotionCancel();
12600
12601 // The interceptor configures itself so that it is no longer a spy.
12602 overlay->setSpy(false);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070012603 mDispatcher->onWindowInfosChanged({{*overlay->getInfo(), *window->getInfo()}, {}, 0, 0});
Prabir Pradhan6dfbf262022-03-14 15:24:30 +000012604
12605 // It continues to receive the rest of the stylus gesture.
12606 sendStylusEvent(AMOTION_EVENT_ACTION_MOVE);
12607 overlay->consumeMotionMove();
12608 sendStylusEvent(AMOTION_EVENT_ACTION_UP);
12609 overlay->consumeMotionUp();
12610
12611 window->assertNoEvents();
12612}
12613
Prabir Pradhan5735a322022-04-11 17:23:34 +000012614struct User {
Prabir Pradhanaeebeb42023-06-13 19:53:03 +000012615 gui::Pid mPid;
Prabir Pradhan8a5c41d2023-06-08 19:13:46 +000012616 gui::Uid mUid;
Prabir Pradhan5735a322022-04-11 17:23:34 +000012617 uint32_t mPolicyFlags{DEFAULT_POLICY_FLAGS};
12618 std::unique_ptr<InputDispatcher>& mDispatcher;
12619
Prabir Pradhanaeebeb42023-06-13 19:53:03 +000012620 User(std::unique_ptr<InputDispatcher>& dispatcher, gui::Pid pid, gui::Uid uid)
Prabir Pradhan5735a322022-04-11 17:23:34 +000012621 : mPid(pid), mUid(uid), mDispatcher(dispatcher) {}
12622
12623 InputEventInjectionResult injectTargetedMotion(int32_t action) const {
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070012624 return injectMotionEvent(*mDispatcher, action, AINPUT_SOURCE_TOUCHSCREEN,
Prabir Pradhan5735a322022-04-11 17:23:34 +000012625 ADISPLAY_ID_DEFAULT, {100, 200},
12626 {AMOTION_EVENT_INVALID_CURSOR_POSITION,
12627 AMOTION_EVENT_INVALID_CURSOR_POSITION},
12628 INJECT_EVENT_TIMEOUT, InputEventInjectionSync::WAIT_FOR_RESULT,
12629 systemTime(SYSTEM_TIME_MONOTONIC), {mUid}, mPolicyFlags);
12630 }
12631
12632 InputEventInjectionResult injectTargetedKey(int32_t action) const {
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070012633 return inputdispatcher::injectKey(*mDispatcher, action, /*repeatCount=*/0, ADISPLAY_ID_NONE,
Prabir Pradhan5735a322022-04-11 17:23:34 +000012634 InputEventInjectionSync::WAIT_FOR_RESULT,
Harry Cutts33476232023-01-30 19:57:29 +000012635 INJECT_EVENT_TIMEOUT, /*allowKeyRepeat=*/false, {mUid},
Prabir Pradhan5735a322022-04-11 17:23:34 +000012636 mPolicyFlags);
12637 }
12638
Siarhei Vishniakoue3ce4122023-08-23 10:26:46 -070012639 sp<FakeWindowHandle> createWindow(const char* name) const {
Prabir Pradhan5735a322022-04-11 17:23:34 +000012640 std::shared_ptr<FakeApplicationHandle> overlayApplication =
12641 std::make_shared<FakeApplicationHandle>();
Siarhei Vishniakoue3ce4122023-08-23 10:26:46 -070012642 sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(overlayApplication, mDispatcher,
12643 name, ADISPLAY_ID_DEFAULT);
Prabir Pradhan5735a322022-04-11 17:23:34 +000012644 window->setOwnerInfo(mPid, mUid);
12645 return window;
12646 }
12647};
12648
12649using InputDispatcherTargetedInjectionTest = InputDispatcherTest;
12650
12651TEST_F(InputDispatcherTargetedInjectionTest, CanInjectIntoOwnedWindow) {
Prabir Pradhanaeebeb42023-06-13 19:53:03 +000012652 auto owner = User(mDispatcher, gui::Pid{10}, gui::Uid{11});
Siarhei Vishniakoue3ce4122023-08-23 10:26:46 -070012653 auto window = owner.createWindow("Owned window");
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070012654 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Prabir Pradhan5735a322022-04-11 17:23:34 +000012655
12656 EXPECT_EQ(InputEventInjectionResult::SUCCEEDED,
12657 owner.injectTargetedMotion(AMOTION_EVENT_ACTION_DOWN));
12658 window->consumeMotionDown();
12659
12660 setFocusedWindow(window);
12661 window->consumeFocusEvent(true);
12662
12663 EXPECT_EQ(InputEventInjectionResult::SUCCEEDED,
12664 owner.injectTargetedKey(AKEY_EVENT_ACTION_DOWN));
12665 window->consumeKeyDown(ADISPLAY_ID_NONE);
12666}
12667
12668TEST_F(InputDispatcherTargetedInjectionTest, CannotInjectIntoUnownedWindow) {
Prabir Pradhanaeebeb42023-06-13 19:53:03 +000012669 auto owner = User(mDispatcher, gui::Pid{10}, gui::Uid{11});
Siarhei Vishniakoue3ce4122023-08-23 10:26:46 -070012670 auto window = owner.createWindow("Owned window");
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070012671 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Prabir Pradhan5735a322022-04-11 17:23:34 +000012672
Prabir Pradhanaeebeb42023-06-13 19:53:03 +000012673 auto rando = User(mDispatcher, gui::Pid{20}, gui::Uid{21});
Prabir Pradhan5735a322022-04-11 17:23:34 +000012674 EXPECT_EQ(InputEventInjectionResult::TARGET_MISMATCH,
12675 rando.injectTargetedMotion(AMOTION_EVENT_ACTION_DOWN));
12676
12677 setFocusedWindow(window);
12678 window->consumeFocusEvent(true);
12679
12680 EXPECT_EQ(InputEventInjectionResult::TARGET_MISMATCH,
12681 rando.injectTargetedKey(AKEY_EVENT_ACTION_DOWN));
12682 window->assertNoEvents();
12683}
12684
12685TEST_F(InputDispatcherTargetedInjectionTest, CanInjectIntoOwnedSpyWindow) {
Prabir Pradhanaeebeb42023-06-13 19:53:03 +000012686 auto owner = User(mDispatcher, gui::Pid{10}, gui::Uid{11});
Siarhei Vishniakoue3ce4122023-08-23 10:26:46 -070012687 auto window = owner.createWindow("Owned window");
12688 auto spy = owner.createWindow("Owned spy");
Prabir Pradhan5735a322022-04-11 17:23:34 +000012689 spy->setSpy(true);
12690 spy->setTrustedOverlay(true);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070012691 mDispatcher->onWindowInfosChanged({{*spy->getInfo(), *window->getInfo()}, {}, 0, 0});
Prabir Pradhan5735a322022-04-11 17:23:34 +000012692
12693 EXPECT_EQ(InputEventInjectionResult::SUCCEEDED,
12694 owner.injectTargetedMotion(AMOTION_EVENT_ACTION_DOWN));
12695 spy->consumeMotionDown();
12696 window->consumeMotionDown();
12697}
12698
12699TEST_F(InputDispatcherTargetedInjectionTest, CannotInjectIntoUnownedSpyWindow) {
Prabir Pradhanaeebeb42023-06-13 19:53:03 +000012700 auto owner = User(mDispatcher, gui::Pid{10}, gui::Uid{11});
Siarhei Vishniakoue3ce4122023-08-23 10:26:46 -070012701 auto window = owner.createWindow("Owned window");
Prabir Pradhan5735a322022-04-11 17:23:34 +000012702
Prabir Pradhanaeebeb42023-06-13 19:53:03 +000012703 auto rando = User(mDispatcher, gui::Pid{20}, gui::Uid{21});
Siarhei Vishniakoue3ce4122023-08-23 10:26:46 -070012704 auto randosSpy = rando.createWindow("Rando's spy");
Prabir Pradhan5735a322022-04-11 17:23:34 +000012705 randosSpy->setSpy(true);
12706 randosSpy->setTrustedOverlay(true);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070012707 mDispatcher->onWindowInfosChanged({{*randosSpy->getInfo(), *window->getInfo()}, {}, 0, 0});
Prabir Pradhan5735a322022-04-11 17:23:34 +000012708
12709 // The event is targeted at owner's window, so injection should succeed, but the spy should
12710 // not receive the event.
12711 EXPECT_EQ(InputEventInjectionResult::SUCCEEDED,
12712 owner.injectTargetedMotion(AMOTION_EVENT_ACTION_DOWN));
12713 randosSpy->assertNoEvents();
12714 window->consumeMotionDown();
12715}
12716
12717TEST_F(InputDispatcherTargetedInjectionTest, CanInjectIntoAnyWindowWhenNotTargeting) {
Prabir Pradhanaeebeb42023-06-13 19:53:03 +000012718 auto owner = User(mDispatcher, gui::Pid{10}, gui::Uid{11});
Siarhei Vishniakoue3ce4122023-08-23 10:26:46 -070012719 auto window = owner.createWindow("Owned window");
Prabir Pradhan5735a322022-04-11 17:23:34 +000012720
Prabir Pradhanaeebeb42023-06-13 19:53:03 +000012721 auto rando = User(mDispatcher, gui::Pid{20}, gui::Uid{21});
Siarhei Vishniakoue3ce4122023-08-23 10:26:46 -070012722 auto randosSpy = rando.createWindow("Rando's spy");
Prabir Pradhan5735a322022-04-11 17:23:34 +000012723 randosSpy->setSpy(true);
12724 randosSpy->setTrustedOverlay(true);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070012725 mDispatcher->onWindowInfosChanged({{*randosSpy->getInfo(), *window->getInfo()}, {}, 0, 0});
Prabir Pradhan5735a322022-04-11 17:23:34 +000012726
12727 // A user that has injection permission can inject into any window.
12728 EXPECT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070012729 injectMotionEvent(*mDispatcher, AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN,
Prabir Pradhan5735a322022-04-11 17:23:34 +000012730 ADISPLAY_ID_DEFAULT));
12731 randosSpy->consumeMotionDown();
12732 window->consumeMotionDown();
12733
12734 setFocusedWindow(randosSpy);
12735 randosSpy->consumeFocusEvent(true);
12736
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070012737 EXPECT_EQ(InputEventInjectionResult::SUCCEEDED, injectKeyDown(*mDispatcher));
Prabir Pradhan5735a322022-04-11 17:23:34 +000012738 randosSpy->consumeKeyDown(ADISPLAY_ID_NONE);
12739 window->assertNoEvents();
12740}
12741
Siarhei Vishniakou580fb3a2023-05-05 15:02:20 -070012742TEST_F(InputDispatcherTargetedInjectionTest, CannotGenerateActionOutsideToOtherUids) {
Prabir Pradhanaeebeb42023-06-13 19:53:03 +000012743 auto owner = User(mDispatcher, gui::Pid{10}, gui::Uid{11});
Siarhei Vishniakoue3ce4122023-08-23 10:26:46 -070012744 auto window = owner.createWindow("Owned window");
Prabir Pradhan5735a322022-04-11 17:23:34 +000012745
Prabir Pradhanaeebeb42023-06-13 19:53:03 +000012746 auto rando = User(mDispatcher, gui::Pid{20}, gui::Uid{21});
Siarhei Vishniakoue3ce4122023-08-23 10:26:46 -070012747 auto randosWindow = rando.createWindow("Rando's window");
Prabir Pradhan5735a322022-04-11 17:23:34 +000012748 randosWindow->setFrame(Rect{-10, -10, -5, -5});
12749 randosWindow->setWatchOutsideTouch(true);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070012750 mDispatcher->onWindowInfosChanged({{*randosWindow->getInfo(), *window->getInfo()}, {}, 0, 0});
Prabir Pradhan5735a322022-04-11 17:23:34 +000012751
Siarhei Vishniakou580fb3a2023-05-05 15:02:20 -070012752 // Do not allow generation of ACTION_OUTSIDE events into windows owned by different uids.
Prabir Pradhan5735a322022-04-11 17:23:34 +000012753 EXPECT_EQ(InputEventInjectionResult::SUCCEEDED,
12754 owner.injectTargetedMotion(AMOTION_EVENT_ACTION_DOWN));
12755 window->consumeMotionDown();
Siarhei Vishniakou580fb3a2023-05-05 15:02:20 -070012756 randosWindow->assertNoEvents();
Prabir Pradhan5735a322022-04-11 17:23:34 +000012757}
12758
Prabir Pradhan64f21d22023-11-28 21:19:42 +000012759using InputDispatcherPointerInWindowTest = InputDispatcherTest;
12760
12761TEST_F(InputDispatcherPointerInWindowTest, PointerInWindowWhenHovering) {
12762 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
12763
12764 sp<FakeWindowHandle> left = sp<FakeWindowHandle>::make(application, mDispatcher, "Left Window",
12765 ADISPLAY_ID_DEFAULT);
12766 left->setFrame(Rect(0, 0, 100, 100));
12767 sp<FakeWindowHandle> right = sp<FakeWindowHandle>::make(application, mDispatcher,
12768 "Right Window", ADISPLAY_ID_DEFAULT);
12769 right->setFrame(Rect(100, 0, 200, 100));
12770 sp<FakeWindowHandle> spy =
12771 sp<FakeWindowHandle>::make(application, mDispatcher, "Spy Window", ADISPLAY_ID_DEFAULT);
12772 spy->setFrame(Rect(0, 0, 200, 100));
12773 spy->setTrustedOverlay(true);
12774 spy->setSpy(true);
12775
12776 mDispatcher->onWindowInfosChanged(
12777 {{*spy->getInfo(), *left->getInfo(), *right->getInfo()}, {}, 0, 0});
12778
12779 // Hover into the left window.
12780 mDispatcher->notifyMotion(
12781 MotionArgsBuilder(ACTION_HOVER_ENTER, AINPUT_SOURCE_STYLUS)
12782 .pointer(PointerBuilder(/*id=*/0, ToolType::STYLUS).x(50).y(50))
12783 .build());
12784
12785 left->consumeMotionEvent(WithMotionAction(ACTION_HOVER_ENTER));
12786 spy->consumeMotionEvent(WithMotionAction(ACTION_HOVER_ENTER));
12787
12788 ASSERT_TRUE(mDispatcher->isPointerInWindow(left->getToken(), ADISPLAY_ID_DEFAULT, DEVICE_ID,
12789 /*pointerId=*/0));
12790 ASSERT_TRUE(mDispatcher->isPointerInWindow(spy->getToken(), ADISPLAY_ID_DEFAULT, DEVICE_ID,
12791 /*pointerId=*/0));
12792 ASSERT_FALSE(mDispatcher->isPointerInWindow(right->getToken(), ADISPLAY_ID_DEFAULT, DEVICE_ID,
12793 /*pointerId=*/0));
12794
12795 // Hover move to the right window.
12796 mDispatcher->notifyMotion(
12797 MotionArgsBuilder(ACTION_HOVER_MOVE, AINPUT_SOURCE_STYLUS)
12798 .pointer(PointerBuilder(/*id=*/0, ToolType::STYLUS).x(150).y(50))
12799 .build());
12800
12801 left->consumeMotionEvent(WithMotionAction(ACTION_HOVER_EXIT));
12802 right->consumeMotionEvent(WithMotionAction(ACTION_HOVER_ENTER));
12803 spy->consumeMotionEvent(WithMotionAction(ACTION_HOVER_MOVE));
12804
12805 ASSERT_FALSE(mDispatcher->isPointerInWindow(left->getToken(), ADISPLAY_ID_DEFAULT, DEVICE_ID,
12806 /*pointerId=*/0));
12807 ASSERT_TRUE(mDispatcher->isPointerInWindow(spy->getToken(), ADISPLAY_ID_DEFAULT, DEVICE_ID,
12808 /*pointerId=*/0));
12809 ASSERT_TRUE(mDispatcher->isPointerInWindow(right->getToken(), ADISPLAY_ID_DEFAULT, DEVICE_ID,
12810 /*pointerId=*/0));
12811
12812 // Stop hovering.
12813 mDispatcher->notifyMotion(
12814 MotionArgsBuilder(ACTION_HOVER_EXIT, AINPUT_SOURCE_STYLUS)
12815 .pointer(PointerBuilder(/*id=*/0, ToolType::STYLUS).x(150).y(50))
12816 .build());
12817
12818 right->consumeMotionEvent(WithMotionAction(ACTION_HOVER_EXIT));
12819 spy->consumeMotionEvent(WithMotionAction(ACTION_HOVER_EXIT));
12820
12821 ASSERT_FALSE(mDispatcher->isPointerInWindow(left->getToken(), ADISPLAY_ID_DEFAULT, DEVICE_ID,
12822 /*pointerId=*/0));
12823 ASSERT_FALSE(mDispatcher->isPointerInWindow(spy->getToken(), ADISPLAY_ID_DEFAULT, DEVICE_ID,
12824 /*pointerId=*/0));
12825 ASSERT_FALSE(mDispatcher->isPointerInWindow(right->getToken(), ADISPLAY_ID_DEFAULT, DEVICE_ID,
12826 /*pointerId=*/0));
12827}
12828
12829TEST_F(InputDispatcherPointerInWindowTest, PointerInWindowWithSplitTouch) {
12830 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
12831
12832 sp<FakeWindowHandle> left = sp<FakeWindowHandle>::make(application, mDispatcher, "Left Window",
12833 ADISPLAY_ID_DEFAULT);
12834 left->setFrame(Rect(0, 0, 100, 100));
12835 sp<FakeWindowHandle> right = sp<FakeWindowHandle>::make(application, mDispatcher,
12836 "Right Window", ADISPLAY_ID_DEFAULT);
12837 right->setFrame(Rect(100, 0, 200, 100));
12838 sp<FakeWindowHandle> spy =
12839 sp<FakeWindowHandle>::make(application, mDispatcher, "Spy Window", ADISPLAY_ID_DEFAULT);
12840 spy->setFrame(Rect(0, 0, 200, 100));
12841 spy->setTrustedOverlay(true);
12842 spy->setSpy(true);
12843
12844 mDispatcher->onWindowInfosChanged(
12845 {{*spy->getInfo(), *left->getInfo(), *right->getInfo()}, {}, 0, 0});
12846
12847 // First pointer down on left window.
12848 mDispatcher->notifyMotion(
12849 MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
12850 .pointer(PointerBuilder(/*id=*/0, ToolType::FINGER).x(50).y(50))
12851 .build());
12852
12853 left->consumeMotionDown();
12854 spy->consumeMotionDown();
12855
12856 ASSERT_TRUE(mDispatcher->isPointerInWindow(left->getToken(), ADISPLAY_ID_DEFAULT, DEVICE_ID,
12857 /*pointerId=*/0));
12858 ASSERT_TRUE(mDispatcher->isPointerInWindow(spy->getToken(), ADISPLAY_ID_DEFAULT, DEVICE_ID,
12859 /*pointerId=*/0));
12860 ASSERT_FALSE(mDispatcher->isPointerInWindow(right->getToken(), ADISPLAY_ID_DEFAULT, DEVICE_ID,
12861 /*pointerId=*/0));
12862
12863 // Second pointer down on right window.
12864 mDispatcher->notifyMotion(
12865 MotionArgsBuilder(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
12866 .pointer(PointerBuilder(/*id=*/0, ToolType::FINGER).x(50).y(50))
12867 .pointer(PointerBuilder(/*id=*/1, ToolType::FINGER).x(150).y(50))
12868 .build());
12869
12870 left->consumeMotionMove();
12871 right->consumeMotionDown();
12872 spy->consumeMotionEvent(WithMotionAction(POINTER_1_DOWN));
12873
12874 ASSERT_TRUE(mDispatcher->isPointerInWindow(left->getToken(), ADISPLAY_ID_DEFAULT, DEVICE_ID,
12875 /*pointerId=*/0));
12876 ASSERT_TRUE(mDispatcher->isPointerInWindow(spy->getToken(), ADISPLAY_ID_DEFAULT, DEVICE_ID,
12877 /*pointerId=*/0));
12878 ASSERT_FALSE(mDispatcher->isPointerInWindow(right->getToken(), ADISPLAY_ID_DEFAULT, DEVICE_ID,
12879 /*pointerId=*/0));
12880 ASSERT_FALSE(mDispatcher->isPointerInWindow(left->getToken(), ADISPLAY_ID_DEFAULT, DEVICE_ID,
12881 /*pointerId=*/1));
12882 ASSERT_TRUE(mDispatcher->isPointerInWindow(spy->getToken(), ADISPLAY_ID_DEFAULT, DEVICE_ID,
12883 /*pointerId=*/1));
12884 ASSERT_TRUE(mDispatcher->isPointerInWindow(right->getToken(), ADISPLAY_ID_DEFAULT, DEVICE_ID,
12885 /*pointerId=*/1));
12886
12887 // Second pointer up.
12888 mDispatcher->notifyMotion(
12889 MotionArgsBuilder(POINTER_1_UP, AINPUT_SOURCE_TOUCHSCREEN)
12890 .pointer(PointerBuilder(/*id=*/0, ToolType::FINGER).x(50).y(50))
12891 .pointer(PointerBuilder(/*id=*/1, ToolType::FINGER).x(150).y(50))
12892 .build());
12893
12894 left->consumeMotionMove();
12895 right->consumeMotionUp();
12896 spy->consumeMotionEvent(WithMotionAction(POINTER_1_UP));
12897
12898 ASSERT_TRUE(mDispatcher->isPointerInWindow(left->getToken(), ADISPLAY_ID_DEFAULT, DEVICE_ID,
12899 /*pointerId=*/0));
12900 ASSERT_TRUE(mDispatcher->isPointerInWindow(spy->getToken(), ADISPLAY_ID_DEFAULT, DEVICE_ID,
12901 /*pointerId=*/0));
12902 ASSERT_FALSE(mDispatcher->isPointerInWindow(right->getToken(), ADISPLAY_ID_DEFAULT, DEVICE_ID,
12903 /*pointerId=*/0));
12904 ASSERT_FALSE(mDispatcher->isPointerInWindow(left->getToken(), ADISPLAY_ID_DEFAULT, DEVICE_ID,
12905 /*pointerId=*/1));
12906 ASSERT_FALSE(mDispatcher->isPointerInWindow(spy->getToken(), ADISPLAY_ID_DEFAULT, DEVICE_ID,
12907 /*pointerId=*/1));
12908 ASSERT_FALSE(mDispatcher->isPointerInWindow(right->getToken(), ADISPLAY_ID_DEFAULT, DEVICE_ID,
12909 /*pointerId=*/1));
12910
12911 // First pointer up.
12912 mDispatcher->notifyMotion(
12913 MotionArgsBuilder(ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN)
12914 .pointer(PointerBuilder(/*id=*/0, ToolType::FINGER).x(50).y(50))
12915 .build());
12916
12917 left->consumeMotionUp();
12918 spy->consumeMotionUp();
12919
12920 ASSERT_FALSE(mDispatcher->isPointerInWindow(left->getToken(), ADISPLAY_ID_DEFAULT, DEVICE_ID,
12921 /*pointerId=*/0));
12922 ASSERT_FALSE(mDispatcher->isPointerInWindow(spy->getToken(), ADISPLAY_ID_DEFAULT, DEVICE_ID,
12923 /*pointerId=*/0));
12924 ASSERT_FALSE(mDispatcher->isPointerInWindow(right->getToken(), ADISPLAY_ID_DEFAULT, DEVICE_ID,
12925 /*pointerId=*/0));
12926}
12927
Siarhei Vishniakoued89cbb2023-10-13 10:42:44 -070012928TEST_F(InputDispatcherPointerInWindowTest, MultipleDevicesControllingOneMouse_legacy) {
12929 SCOPED_FLAG_OVERRIDE(enable_multi_device_same_window_stream, false);
Prabir Pradhan64f21d22023-11-28 21:19:42 +000012930 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
12931
12932 sp<FakeWindowHandle> left = sp<FakeWindowHandle>::make(application, mDispatcher, "Left Window",
12933 ADISPLAY_ID_DEFAULT);
12934 left->setFrame(Rect(0, 0, 100, 100));
12935 sp<FakeWindowHandle> right = sp<FakeWindowHandle>::make(application, mDispatcher,
12936 "Right Window", ADISPLAY_ID_DEFAULT);
12937 right->setFrame(Rect(100, 0, 200, 100));
12938
12939 mDispatcher->onWindowInfosChanged({{*left->getInfo(), *right->getInfo()}, {}, 0, 0});
12940
12941 ASSERT_FALSE(mDispatcher->isPointerInWindow(left->getToken(), ADISPLAY_ID_DEFAULT, DEVICE_ID,
12942 /*pointerId=*/0));
12943 ASSERT_FALSE(mDispatcher->isPointerInWindow(right->getToken(), ADISPLAY_ID_DEFAULT, DEVICE_ID,
12944 /*pointerId=*/0));
12945
12946 // Hover move into the window.
12947 mDispatcher->notifyMotion(
12948 MotionArgsBuilder(ACTION_HOVER_MOVE, AINPUT_SOURCE_MOUSE)
12949 .pointer(PointerBuilder(/*id=*/0, ToolType::MOUSE).x(50).y(50))
12950 .rawXCursorPosition(50)
12951 .rawYCursorPosition(50)
12952 .deviceId(DEVICE_ID)
12953 .build());
12954
12955 left->consumeMotionEvent(WithMotionAction(ACTION_HOVER_ENTER));
12956
12957 ASSERT_TRUE(mDispatcher->isPointerInWindow(left->getToken(), ADISPLAY_ID_DEFAULT, DEVICE_ID,
12958 /*pointerId=*/0));
12959
12960 // Move the mouse with another device. This cancels the hovering pointer from the first device.
12961 mDispatcher->notifyMotion(
12962 MotionArgsBuilder(ACTION_HOVER_MOVE, AINPUT_SOURCE_MOUSE)
12963 .pointer(PointerBuilder(/*id=*/0, ToolType::MOUSE).x(51).y(50))
12964 .rawXCursorPosition(51)
12965 .rawYCursorPosition(50)
12966 .deviceId(SECOND_DEVICE_ID)
12967 .build());
12968
12969 left->consumeMotionEvent(WithMotionAction(ACTION_HOVER_EXIT));
12970 left->consumeMotionEvent(WithMotionAction(ACTION_HOVER_ENTER));
12971
12972 // TODO(b/313689709): InputDispatcher's touch state is not updated, even though the window gets
12973 // a HOVER_EXIT from the first device.
12974 ASSERT_TRUE(mDispatcher->isPointerInWindow(left->getToken(), ADISPLAY_ID_DEFAULT, DEVICE_ID,
12975 /*pointerId=*/0));
12976 ASSERT_TRUE(mDispatcher->isPointerInWindow(left->getToken(), ADISPLAY_ID_DEFAULT,
12977 SECOND_DEVICE_ID,
12978 /*pointerId=*/0));
12979
12980 // Move the mouse outside the window. Document the current behavior, where the window does not
12981 // receive HOVER_EXIT even though the mouse left the window.
12982 mDispatcher->notifyMotion(
12983 MotionArgsBuilder(ACTION_HOVER_MOVE, AINPUT_SOURCE_MOUSE)
12984 .pointer(PointerBuilder(/*id=*/0, ToolType::MOUSE).x(150).y(50))
12985 .rawXCursorPosition(150)
12986 .rawYCursorPosition(50)
12987 .deviceId(SECOND_DEVICE_ID)
12988 .build());
12989
12990 left->consumeMotionEvent(WithMotionAction(ACTION_HOVER_EXIT));
12991 right->consumeMotionEvent(WithMotionAction(ACTION_HOVER_ENTER));
12992 ASSERT_TRUE(mDispatcher->isPointerInWindow(left->getToken(), ADISPLAY_ID_DEFAULT, DEVICE_ID,
12993 /*pointerId=*/0));
12994 ASSERT_FALSE(mDispatcher->isPointerInWindow(left->getToken(), ADISPLAY_ID_DEFAULT,
12995 SECOND_DEVICE_ID,
12996 /*pointerId=*/0));
12997}
12998
Siarhei Vishniakoued89cbb2023-10-13 10:42:44 -070012999/**
13000 * TODO(b/313689709) - correctly support multiple mouse devices, because they should be controlling
13001 * the same cursor, and therefore have a shared motion event stream.
13002 */
13003TEST_F(InputDispatcherPointerInWindowTest, MultipleDevicesControllingOneMouse) {
13004 SCOPED_FLAG_OVERRIDE(enable_multi_device_same_window_stream, true);
13005 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
13006
13007 sp<FakeWindowHandle> left = sp<FakeWindowHandle>::make(application, mDispatcher, "Left Window",
13008 ADISPLAY_ID_DEFAULT);
13009 left->setFrame(Rect(0, 0, 100, 100));
13010 sp<FakeWindowHandle> right = sp<FakeWindowHandle>::make(application, mDispatcher,
13011 "Right Window", ADISPLAY_ID_DEFAULT);
13012 right->setFrame(Rect(100, 0, 200, 100));
13013
13014 mDispatcher->onWindowInfosChanged({{*left->getInfo(), *right->getInfo()}, {}, 0, 0});
13015
13016 ASSERT_FALSE(mDispatcher->isPointerInWindow(left->getToken(), ADISPLAY_ID_DEFAULT, DEVICE_ID,
13017 /*pointerId=*/0));
13018 ASSERT_FALSE(mDispatcher->isPointerInWindow(right->getToken(), ADISPLAY_ID_DEFAULT, DEVICE_ID,
13019 /*pointerId=*/0));
13020
13021 // Hover move into the window.
13022 mDispatcher->notifyMotion(
13023 MotionArgsBuilder(ACTION_HOVER_MOVE, AINPUT_SOURCE_MOUSE)
13024 .pointer(PointerBuilder(/*id=*/0, ToolType::MOUSE).x(50).y(50))
13025 .rawXCursorPosition(50)
13026 .rawYCursorPosition(50)
13027 .deviceId(DEVICE_ID)
13028 .build());
13029
13030 left->consumeMotionEvent(WithMotionAction(ACTION_HOVER_ENTER));
13031
13032 ASSERT_TRUE(mDispatcher->isPointerInWindow(left->getToken(), ADISPLAY_ID_DEFAULT, DEVICE_ID,
13033 /*pointerId=*/0));
13034
13035 // Move the mouse with another device
13036 mDispatcher->notifyMotion(
13037 MotionArgsBuilder(ACTION_HOVER_MOVE, AINPUT_SOURCE_MOUSE)
13038 .pointer(PointerBuilder(/*id=*/0, ToolType::MOUSE).x(51).y(50))
13039 .rawXCursorPosition(51)
13040 .rawYCursorPosition(50)
13041 .deviceId(SECOND_DEVICE_ID)
13042 .build());
13043 left->consumeMotionEvent(WithMotionAction(ACTION_HOVER_ENTER));
13044
13045 // TODO(b/313689709): InputDispatcher's touch state is not updated, even though the window gets
13046 // a HOVER_EXIT from the first device.
13047 ASSERT_TRUE(mDispatcher->isPointerInWindow(left->getToken(), ADISPLAY_ID_DEFAULT, DEVICE_ID,
13048 /*pointerId=*/0));
13049 ASSERT_TRUE(mDispatcher->isPointerInWindow(left->getToken(), ADISPLAY_ID_DEFAULT,
13050 SECOND_DEVICE_ID,
13051 /*pointerId=*/0));
13052
13053 // Move the mouse outside the window. Document the current behavior, where the window does not
13054 // receive HOVER_EXIT even though the mouse left the window.
13055 mDispatcher->notifyMotion(
13056 MotionArgsBuilder(ACTION_HOVER_MOVE, AINPUT_SOURCE_MOUSE)
13057 .pointer(PointerBuilder(/*id=*/0, ToolType::MOUSE).x(150).y(50))
13058 .rawXCursorPosition(150)
13059 .rawYCursorPosition(50)
13060 .deviceId(SECOND_DEVICE_ID)
13061 .build());
13062
13063 right->consumeMotionEvent(WithMotionAction(ACTION_HOVER_ENTER));
13064 ASSERT_TRUE(mDispatcher->isPointerInWindow(left->getToken(), ADISPLAY_ID_DEFAULT, DEVICE_ID,
13065 /*pointerId=*/0));
13066 ASSERT_FALSE(mDispatcher->isPointerInWindow(left->getToken(), ADISPLAY_ID_DEFAULT,
13067 SECOND_DEVICE_ID,
13068 /*pointerId=*/0));
13069}
13070
Garfield Tane84e6f92019-08-29 17:28:41 -070013071} // namespace android::inputdispatcher