blob: ddf94bfa04ee3b51b0fd6922082d452edde54e3f [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.
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -070075constexpr ui::LogicalDisplayId DISPLAY_ID = ui::LogicalDisplayId::DEFAULT;
Linnan Li13bf76a2024-05-05 19:18:02 +080076constexpr ui::LogicalDisplayId SECOND_DISPLAY_ID = ui::LogicalDisplayId{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
Linnan Li72352222024-04-12 18:55:57 +0800120static constexpr int EXPECTED_WALLPAPER_FLAGS =
Arthur Hungc539dbb2022-12-08 07:45:36 +0000121 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
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -0700131 event.initialize(InputEvent::nextId(), DEVICE_ID, AINPUT_SOURCE_KEYBOARD,
132 ui::LogicalDisplayId::INVALID, INVALID_HMAC, AKEY_EVENT_ACTION_DOWN, 0,
133 AKEYCODE_A, KEY_A, AMETA_NONE, 0, ARBITRARY_TIME, ARBITRARY_TIME);
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);
Linnan Li13bf76a2024-05-05 19:18:02 +0800246 request.displayId = window->getInfo()->displayId.val();
Vishnu Nair958da932020-08-21 17:12:37 -0700247 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.
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -0700255 event.initialize(InputEvent::nextId(), DEVICE_ID, AINPUT_SOURCE_KEYBOARD,
256 ui::LogicalDisplayId::INVALID, 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.
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -0700265 event.initialize(InputEvent::nextId(), DEVICE_ID, AINPUT_SOURCE_KEYBOARD,
266 ui::LogicalDisplayId::INVALID, INVALID_HMAC, AKEY_EVENT_ACTION_MULTIPLE, 0,
267 AKEYCODE_A, KEY_A, AMETA_NONE, 0, ARBITRARY_TIME, ARBITRARY_TIME);
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 -0800414TEST_F(InputDispatcherTest, NotifySwitch_CallsPolicy) {
Prabir Pradhana8fe7c52023-12-14 22:07:23 +0000415 NotifySwitchArgs args(InputEvent::nextId(), /*eventTime=*/20, /*policyFlags=*/0,
416 /*switchValues=*/1,
Harry Cutts33476232023-01-30 19:57:29 +0000417 /*switchMask=*/2);
Prabir Pradhan678438e2023-04-13 19:32:51 +0000418 mDispatcher->notifySwitch(args);
Siarhei Vishniakou2bfa9052019-11-21 18:10:54 -0800419
420 // InputDispatcher adds POLICY_FLAG_TRUSTED because the event went through InputListener
421 args.policyFlags |= POLICY_FLAG_TRUSTED;
422 mFakePolicy->assertNotifySwitchWasCalled(args);
423}
424
Siarhei Vishniakouadeb6fa2023-05-26 09:11:06 -0700425namespace {
426
Siarhei Vishniakou097c3db2020-05-06 14:18:38 -0700427static constexpr std::chrono::duration INJECT_EVENT_TIMEOUT = 500ms;
Siarhei Vishniakou540dbae2020-05-05 18:17:17 -0700428
Prabir Pradhan112b1ad2023-09-21 09:53:53 +0000429class FakeMonitorReceiver {
430public:
Linnan Li13bf76a2024-05-05 19:18:02 +0800431 FakeMonitorReceiver(InputDispatcher& dispatcher, const std::string name,
432 ui::LogicalDisplayId displayId)
Siarhei Vishniakou2defec02023-06-08 17:24:44 -0700433 : mInputReceiver(*dispatcher.createInputMonitor(displayId, name, MONITOR_PID), name) {}
Prabir Pradhan112b1ad2023-09-21 09:53:53 +0000434
Siarhei Vishniakou2defec02023-06-08 17:24:44 -0700435 sp<IBinder> getToken() { return mInputReceiver.getToken(); }
Prabir Pradhan112b1ad2023-09-21 09:53:53 +0000436
Linnan Li13bf76a2024-05-05 19:18:02 +0800437 void consumeKeyDown(ui::LogicalDisplayId expectedDisplayId, int32_t expectedFlags = 0) {
Siarhei Vishniakou2defec02023-06-08 17:24:44 -0700438 mInputReceiver.consumeEvent(InputEventType::KEY, AKEY_EVENT_ACTION_DOWN, expectedDisplayId,
439 expectedFlags);
Prabir Pradhan112b1ad2023-09-21 09:53:53 +0000440 }
441
442 std::optional<int32_t> receiveEvent() {
Siarhei Vishniakoud3061ab2023-12-18 20:41:08 -0800443 const auto [sequenceNum, _] = mInputReceiver.receiveEvent(CONSUME_TIMEOUT_EVENT_EXPECTED);
444 return sequenceNum;
Prabir Pradhan112b1ad2023-09-21 09:53:53 +0000445 }
446
Siarhei Vishniakou2defec02023-06-08 17:24:44 -0700447 void finishEvent(uint32_t consumeSeq) { return mInputReceiver.finishEvent(consumeSeq); }
Prabir Pradhan112b1ad2023-09-21 09:53:53 +0000448
Linnan Li13bf76a2024-05-05 19:18:02 +0800449 void consumeMotionDown(ui::LogicalDisplayId expectedDisplayId, int32_t expectedFlags = 0) {
Siarhei Vishniakou2defec02023-06-08 17:24:44 -0700450 mInputReceiver.consumeEvent(InputEventType::MOTION, AMOTION_EVENT_ACTION_DOWN,
451 expectedDisplayId, expectedFlags);
Prabir Pradhan112b1ad2023-09-21 09:53:53 +0000452 }
453
Linnan Li13bf76a2024-05-05 19:18:02 +0800454 void consumeMotionMove(ui::LogicalDisplayId expectedDisplayId, int32_t expectedFlags = 0) {
Siarhei Vishniakou2defec02023-06-08 17:24:44 -0700455 mInputReceiver.consumeEvent(InputEventType::MOTION, AMOTION_EVENT_ACTION_MOVE,
456 expectedDisplayId, expectedFlags);
Prabir Pradhan112b1ad2023-09-21 09:53:53 +0000457 }
458
Linnan Li13bf76a2024-05-05 19:18:02 +0800459 void consumeMotionUp(ui::LogicalDisplayId expectedDisplayId, int32_t expectedFlags = 0) {
Siarhei Vishniakou2defec02023-06-08 17:24:44 -0700460 mInputReceiver.consumeEvent(InputEventType::MOTION, AMOTION_EVENT_ACTION_UP,
461 expectedDisplayId, expectedFlags);
Prabir Pradhan112b1ad2023-09-21 09:53:53 +0000462 }
463
Linnan Li13bf76a2024-05-05 19:18:02 +0800464 void consumeMotionCancel(ui::LogicalDisplayId expectedDisplayId, int32_t expectedFlags = 0) {
Siarhei Vishniakou2defec02023-06-08 17:24:44 -0700465 mInputReceiver.consumeMotionEvent(
Prabir Pradhan112b1ad2023-09-21 09:53:53 +0000466 AllOf(WithMotionAction(AMOTION_EVENT_ACTION_CANCEL),
467 WithDisplayId(expectedDisplayId),
468 WithFlags(expectedFlags | AMOTION_EVENT_FLAG_CANCELED)));
469 }
470
471 void consumeMotionPointerDown(int32_t pointerIdx) {
472 int32_t action = AMOTION_EVENT_ACTION_POINTER_DOWN |
473 (pointerIdx << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT);
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -0700474 mInputReceiver.consumeEvent(InputEventType::MOTION, action, ui::LogicalDisplayId::DEFAULT,
Siarhei Vishniakou2defec02023-06-08 17:24:44 -0700475 /*expectedFlags=*/0);
Prabir Pradhan112b1ad2023-09-21 09:53:53 +0000476 }
477
478 void consumeMotionEvent(const ::testing::Matcher<MotionEvent>& matcher) {
Siarhei Vishniakou2defec02023-06-08 17:24:44 -0700479 mInputReceiver.consumeMotionEvent(matcher);
Prabir Pradhan112b1ad2023-09-21 09:53:53 +0000480 }
481
Siarhei Vishniakoud3061ab2023-12-18 20:41:08 -0800482 std::unique_ptr<MotionEvent> consumeMotion() { return mInputReceiver.consumeMotion(); }
Prabir Pradhan112b1ad2023-09-21 09:53:53 +0000483
Siarhei Vishniakouef2b4502023-12-28 11:51:47 -0800484 void assertNoEvents() { mInputReceiver.assertNoEvents(CONSUME_TIMEOUT_NO_EVENT_EXPECTED); }
Prabir Pradhan112b1ad2023-09-21 09:53:53 +0000485
486private:
Siarhei Vishniakou2defec02023-06-08 17:24:44 -0700487 FakeInputReceiver mInputReceiver;
Prabir Pradhan112b1ad2023-09-21 09:53:53 +0000488};
489
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -0800490static InputEventInjectionResult injectKey(
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -0700491 InputDispatcher& dispatcher, int32_t action, int32_t repeatCount,
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -0700492 ui::LogicalDisplayId displayId = ui::LogicalDisplayId::INVALID,
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -0800493 InputEventInjectionSync syncMode = InputEventInjectionSync::WAIT_FOR_RESULT,
Prabir Pradhan93f342c2021-03-11 15:05:30 -0800494 std::chrono::milliseconds injectionTimeout = INJECT_EVENT_TIMEOUT,
Prabir Pradhan8a5c41d2023-06-08 19:13:46 +0000495 bool allowKeyRepeat = true, std::optional<gui::Uid> targetUid = {},
Prabir Pradhan5735a322022-04-11 17:23:34 +0000496 uint32_t policyFlags = DEFAULT_POLICY_FLAGS) {
Arthur Hungb92218b2018-08-14 12:00:21 +0800497 KeyEvent event;
498 nsecs_t currentTime = systemTime(SYSTEM_TIME_MONOTONIC);
499
500 // Define a valid key down event.
Garfield Tanfbe732e2020-01-24 11:26:14 -0800501 event.initialize(InputEvent::nextId(), DEVICE_ID, AINPUT_SOURCE_KEYBOARD, displayId,
Harry Cutts33476232023-01-30 19:57:29 +0000502 INVALID_HMAC, action, /*flags=*/0, AKEYCODE_A, KEY_A, AMETA_NONE, repeatCount,
503 currentTime, currentTime);
Arthur Hungb92218b2018-08-14 12:00:21 +0800504
Prabir Pradhan93f342c2021-03-11 15:05:30 -0800505 if (!allowKeyRepeat) {
506 policyFlags |= POLICY_FLAG_DISABLE_KEY_REPEAT;
507 }
Arthur Hungb92218b2018-08-14 12:00:21 +0800508 // Inject event until dispatch out.
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -0700509 return dispatcher.injectInputEvent(&event, targetUid, syncMode, injectionTimeout, policyFlags);
Arthur Hungb92218b2018-08-14 12:00:21 +0800510}
511
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -0700512static void assertInjectedKeyTimesOut(InputDispatcher& dispatcher) {
513 InputEventInjectionResult result =
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -0700514 injectKey(dispatcher, AKEY_EVENT_ACTION_DOWN, /*repeatCount=*/0,
515 ui::LogicalDisplayId::INVALID, InputEventInjectionSync::WAIT_FOR_RESULT,
516 CONSUME_TIMEOUT_NO_EVENT_EXPECTED);
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -0700517 if (result != InputEventInjectionResult::TIMED_OUT) {
518 FAIL() << "Injection should have timed out, but got " << ftl::enum_string(result);
519 }
520}
521
Linnan Li13bf76a2024-05-05 19:18:02 +0800522static InputEventInjectionResult injectKeyDown(
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -0700523 InputDispatcher& dispatcher,
524 ui::LogicalDisplayId displayId = ui::LogicalDisplayId::INVALID) {
Harry Cutts33476232023-01-30 19:57:29 +0000525 return injectKey(dispatcher, AKEY_EVENT_ACTION_DOWN, /*repeatCount=*/0, displayId);
Siarhei Vishniakou4cb50ca2020-05-26 21:43:02 -0700526}
527
Prabir Pradhan93f342c2021-03-11 15:05:30 -0800528// Inject a down event that has key repeat disabled. This allows InputDispatcher to idle without
529// sending a subsequent key up. When key repeat is enabled, the dispatcher cannot idle because it
530// has to be woken up to process the repeating key.
Linnan Li13bf76a2024-05-05 19:18:02 +0800531static InputEventInjectionResult injectKeyDownNoRepeat(
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -0700532 InputDispatcher& dispatcher,
533 ui::LogicalDisplayId displayId = ui::LogicalDisplayId::INVALID) {
Harry Cutts33476232023-01-30 19:57:29 +0000534 return injectKey(dispatcher, AKEY_EVENT_ACTION_DOWN, /*repeatCount=*/0, displayId,
Prabir Pradhan93f342c2021-03-11 15:05:30 -0800535 InputEventInjectionSync::WAIT_FOR_RESULT, INJECT_EVENT_TIMEOUT,
Harry Cutts33476232023-01-30 19:57:29 +0000536 /*allowKeyRepeat=*/false);
Prabir Pradhan93f342c2021-03-11 15:05:30 -0800537}
538
Linnan Li13bf76a2024-05-05 19:18:02 +0800539static InputEventInjectionResult injectKeyUp(
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -0700540 InputDispatcher& dispatcher,
541 ui::LogicalDisplayId displayId = ui::LogicalDisplayId::INVALID) {
Harry Cutts33476232023-01-30 19:57:29 +0000542 return injectKey(dispatcher, AKEY_EVENT_ACTION_UP, /*repeatCount=*/0, displayId);
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -0700543}
544
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -0800545static InputEventInjectionResult injectMotionEvent(
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -0700546 InputDispatcher& dispatcher, const MotionEvent& event,
Garfield Tandf26e862020-07-01 20:18:19 -0700547 std::chrono::milliseconds injectionTimeout = INJECT_EVENT_TIMEOUT,
Prabir Pradhan5735a322022-04-11 17:23:34 +0000548 InputEventInjectionSync injectionMode = InputEventInjectionSync::WAIT_FOR_RESULT,
Prabir Pradhan8a5c41d2023-06-08 19:13:46 +0000549 std::optional<gui::Uid> targetUid = {}, uint32_t policyFlags = DEFAULT_POLICY_FLAGS) {
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -0700550 return dispatcher.injectInputEvent(&event, targetUid, injectionMode, injectionTimeout,
551 policyFlags);
Garfield Tandf26e862020-07-01 20:18:19 -0700552}
553
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -0800554static InputEventInjectionResult injectMotionEvent(
Linnan Li13bf76a2024-05-05 19:18:02 +0800555 InputDispatcher& dispatcher, int32_t action, int32_t source, ui::LogicalDisplayId displayId,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -0700556 const PointF& position = {100, 200},
Siarhei Vishniakou4cb50ca2020-05-26 21:43:02 -0700557 const PointF& cursorPosition = {AMOTION_EVENT_INVALID_CURSOR_POSITION,
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -0700558 AMOTION_EVENT_INVALID_CURSOR_POSITION},
559 std::chrono::milliseconds injectionTimeout = INJECT_EVENT_TIMEOUT,
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -0800560 InputEventInjectionSync injectionMode = InputEventInjectionSync::WAIT_FOR_RESULT,
Prabir Pradhan5735a322022-04-11 17:23:34 +0000561 nsecs_t eventTime = systemTime(SYSTEM_TIME_MONOTONIC),
Prabir Pradhan8a5c41d2023-06-08 19:13:46 +0000562 std::optional<gui::Uid> targetUid = {}, uint32_t policyFlags = DEFAULT_POLICY_FLAGS) {
Siarhei Vishniakou90ee4782023-05-08 11:57:24 -0700563 MotionEventBuilder motionBuilder =
564 MotionEventBuilder(action, source)
565 .displayId(displayId)
566 .eventTime(eventTime)
567 .rawXCursorPosition(cursorPosition.x)
568 .rawYCursorPosition(cursorPosition.y)
569 .pointer(
570 PointerBuilder(/*id=*/0, ToolType::FINGER).x(position.x).y(position.y));
571 if (MotionEvent::getActionMasked(action) == ACTION_DOWN) {
572 motionBuilder.downTime(eventTime);
573 }
Arthur Hungb92218b2018-08-14 12:00:21 +0800574
575 // Inject event until dispatch out.
Siarhei Vishniakou90ee4782023-05-08 11:57:24 -0700576 return injectMotionEvent(dispatcher, motionBuilder.build(), injectionTimeout, injectionMode,
577 targetUid, policyFlags);
Arthur Hungb92218b2018-08-14 12:00:21 +0800578}
579
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -0700580static InputEventInjectionResult injectMotionDown(InputDispatcher& dispatcher, int32_t source,
Linnan Li13bf76a2024-05-05 19:18:02 +0800581 ui::LogicalDisplayId displayId,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -0700582 const PointF& location = {100, 200}) {
Siarhei Vishniakou4cb50ca2020-05-26 21:43:02 -0700583 return injectMotionEvent(dispatcher, AMOTION_EVENT_ACTION_DOWN, source, displayId, location);
Garfield Tan00f511d2019-06-12 16:55:40 -0700584}
585
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -0700586static InputEventInjectionResult injectMotionUp(InputDispatcher& dispatcher, int32_t source,
Linnan Li13bf76a2024-05-05 19:18:02 +0800587 ui::LogicalDisplayId displayId,
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -0800588 const PointF& location = {100, 200}) {
Siarhei Vishniakou4cb50ca2020-05-26 21:43:02 -0700589 return injectMotionEvent(dispatcher, AMOTION_EVENT_ACTION_UP, source, displayId, location);
Michael Wright3a240c42019-12-10 20:53:41 +0000590}
591
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -0700592static NotifyKeyArgs generateKeyArgs(
593 int32_t action, ui::LogicalDisplayId displayId = ui::LogicalDisplayId::INVALID) {
Jackal Guof9696682018-10-05 12:23:23 +0800594 nsecs_t currentTime = systemTime(SYSTEM_TIME_MONOTONIC);
595 // Define a valid key event.
Prabir Pradhana8fe7c52023-12-14 22:07:23 +0000596 NotifyKeyArgs args(InputEvent::nextId(), currentTime, /*readTime=*/0, DEVICE_ID,
597 AINPUT_SOURCE_KEYBOARD, displayId, POLICY_FLAG_PASS_TO_USER, action,
598 /*flags=*/0, AKEYCODE_A, KEY_A, AMETA_NONE, currentTime);
Jackal Guof9696682018-10-05 12:23:23 +0800599
600 return args;
601}
602
Prabir Pradhan678438e2023-04-13 19:32:51 +0000603[[nodiscard]] static NotifyMotionArgs generateMotionArgs(int32_t action, int32_t source,
Linnan Li13bf76a2024-05-05 19:18:02 +0800604 ui::LogicalDisplayId displayId,
Prabir Pradhan678438e2023-04-13 19:32:51 +0000605 const std::vector<PointF>& points) {
chaviwd1c23182019-12-20 18:44:56 -0800606 size_t pointerCount = points.size();
chaviwaf87b3e2019-10-01 16:59:28 -0700607 if (action == AMOTION_EVENT_ACTION_DOWN || action == AMOTION_EVENT_ACTION_UP) {
608 EXPECT_EQ(1U, pointerCount) << "Actions DOWN and UP can only contain a single pointer";
609 }
610
chaviwd1c23182019-12-20 18:44:56 -0800611 PointerProperties pointerProperties[pointerCount];
612 PointerCoords pointerCoords[pointerCount];
Jackal Guof9696682018-10-05 12:23:23 +0800613
chaviwd1c23182019-12-20 18:44:56 -0800614 for (size_t i = 0; i < pointerCount; i++) {
615 pointerProperties[i].clear();
616 pointerProperties[i].id = i;
Siarhei Vishniakou6d73f832022-07-21 17:27:03 -0700617 pointerProperties[i].toolType = ToolType::FINGER;
Jackal Guof9696682018-10-05 12:23:23 +0800618
chaviwd1c23182019-12-20 18:44:56 -0800619 pointerCoords[i].clear();
620 pointerCoords[i].setAxisValue(AMOTION_EVENT_AXIS_X, points[i].x);
621 pointerCoords[i].setAxisValue(AMOTION_EVENT_AXIS_Y, points[i].y);
622 }
Jackal Guof9696682018-10-05 12:23:23 +0800623
624 nsecs_t currentTime = systemTime(SYSTEM_TIME_MONOTONIC);
625 // Define a valid motion event.
Prabir Pradhana8fe7c52023-12-14 22:07:23 +0000626 NotifyMotionArgs args(InputEvent::nextId(), currentTime, /*readTime=*/0, DEVICE_ID, source,
627 displayId, POLICY_FLAG_PASS_TO_USER, action, /*actionButton=*/0,
628 /*flags=*/0, AMETA_NONE, /*buttonState=*/0, MotionClassification::NONE,
chaviwd1c23182019-12-20 18:44:56 -0800629 AMOTION_EVENT_EDGE_FLAG_NONE, pointerCount, pointerProperties,
Harry Cutts101ee9b2023-07-06 18:04:14 +0000630 pointerCoords, /*xPrecision=*/0, /*yPrecision=*/0,
Garfield Tan00f511d2019-06-12 16:55:40 -0700631 AMOTION_EVENT_INVALID_CURSOR_POSITION,
Harry Cutts101ee9b2023-07-06 18:04:14 +0000632 AMOTION_EVENT_INVALID_CURSOR_POSITION, currentTime, /*videoFrames=*/{});
Jackal Guof9696682018-10-05 12:23:23 +0800633
634 return args;
635}
636
Siarhei Vishniakoua16e3a22022-03-02 15:26:40 -0800637static NotifyMotionArgs generateTouchArgs(int32_t action, const std::vector<PointF>& points) {
638 return generateMotionArgs(action, AINPUT_SOURCE_TOUCHSCREEN, DISPLAY_ID, points);
639}
640
Linnan Li13bf76a2024-05-05 19:18:02 +0800641static NotifyMotionArgs generateMotionArgs(int32_t action, int32_t source,
642 ui::LogicalDisplayId displayId) {
chaviwd1c23182019-12-20 18:44:56 -0800643 return generateMotionArgs(action, source, displayId, {PointF{100, 200}});
644}
645
Prabir Pradhan5cc1a692021-08-06 14:01:18 +0000646static NotifyPointerCaptureChangedArgs generatePointerCaptureChangedArgs(
647 const PointerCaptureRequest& request) {
Prabir Pradhana8fe7c52023-12-14 22:07:23 +0000648 return NotifyPointerCaptureChangedArgs(InputEvent::nextId(), systemTime(SYSTEM_TIME_MONOTONIC),
649 request);
Prabir Pradhan99987712020-11-10 18:43:05 -0800650}
651
Siarhei Vishniakouadeb6fa2023-05-26 09:11:06 -0700652} // namespace
653
Siarhei Vishniakou7aa3e942021-11-18 09:49:11 -0800654/**
655 * When a window unexpectedly disposes of its input channel, policy should be notified about the
656 * broken channel.
657 */
658TEST_F(InputDispatcherTest, WhenInputChannelBreaks_PolicyIsNotified) {
659 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -0700660 sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher,
661 "Window that breaks its input channel",
662 ui::LogicalDisplayId::DEFAULT);
Siarhei Vishniakou7aa3e942021-11-18 09:49:11 -0800663
Siarhei Vishniakouc41de372023-07-20 13:14:26 -0700664 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Siarhei Vishniakou7aa3e942021-11-18 09:49:11 -0800665
666 // Window closes its channel, but the window remains.
667 window->destroyReceiver();
668 mFakePolicy->assertNotifyInputChannelBrokenWasCalled(window->getInfo()->token);
669}
670
Arthur Hungb92218b2018-08-14 12:00:21 +0800671TEST_F(InputDispatcherTest, SetInputWindow_SingleWindowTouch) {
Chris Yea209fde2020-07-22 13:54:51 -0700672 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -0700673 sp<FakeWindowHandle> window =
674 sp<FakeWindowHandle>::make(application, mDispatcher, "Fake Window",
675 ui::LogicalDisplayId::DEFAULT);
Arthur Hungb92218b2018-08-14 12:00:21 +0800676
Siarhei Vishniakouc41de372023-07-20 13:14:26 -0700677 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -0800678 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -0700679 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN,
680 ui::LogicalDisplayId::DEFAULT))
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -0800681 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
Arthur Hungb92218b2018-08-14 12:00:21 +0800682
683 // Window should receive motion event.
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -0700684 window->consumeMotionDown(ui::LogicalDisplayId::DEFAULT);
Arthur Hungb92218b2018-08-14 12:00:21 +0800685}
686
Siarhei Vishniakouaeed0da2024-01-09 08:57:13 -0800687using InputDispatcherDeathTest = InputDispatcherTest;
688
689/**
690 * When 'onWindowInfosChanged' arguments contain a duplicate entry for the same window, dispatcher
691 * should crash.
692 */
693TEST_F(InputDispatcherDeathTest, DuplicateWindowInfosAbortDispatcher) {
694 testing::GTEST_FLAG(death_test_style) = "threadsafe";
695 ScopedSilentDeath _silentDeath;
696
697 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -0700698 sp<FakeWindowHandle> window =
699 sp<FakeWindowHandle>::make(application, mDispatcher, "Fake Window",
700 ui::LogicalDisplayId::DEFAULT);
Siarhei Vishniakouaeed0da2024-01-09 08:57:13 -0800701 ASSERT_DEATH(mDispatcher->onWindowInfosChanged(
702 {{*window->getInfo(), *window->getInfo()}, {}, 0, 0}),
703 "Incorrect WindowInfosUpdate provided");
704}
705
Prabir Pradhanc44ce4d2021-10-05 05:26:29 -0700706TEST_F(InputDispatcherTest, WhenDisplayNotSpecified_InjectMotionToDefaultDisplay) {
707 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -0700708 sp<FakeWindowHandle> window =
709 sp<FakeWindowHandle>::make(application, mDispatcher, "Fake Window",
710 ui::LogicalDisplayId::DEFAULT);
Prabir Pradhanc44ce4d2021-10-05 05:26:29 -0700711
Siarhei Vishniakouc41de372023-07-20 13:14:26 -0700712 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Prabir Pradhanc44ce4d2021-10-05 05:26:29 -0700713 // Inject a MotionEvent to an unknown display.
714 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -0700715 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN,
716 ui::LogicalDisplayId::INVALID))
Prabir Pradhanc44ce4d2021-10-05 05:26:29 -0700717 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
718
719 // Window should receive motion event.
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -0700720 window->consumeMotionDown(ui::LogicalDisplayId::DEFAULT);
Prabir Pradhanc44ce4d2021-10-05 05:26:29 -0700721}
722
Siarhei Vishniakoufb9fcda2020-05-04 14:59:19 -0700723/**
Siarhei Vishniakouc41de372023-07-20 13:14:26 -0700724 * Calling onWindowInfosChanged once should not cause any issues.
725 * This test serves as a sanity check for the next test, where onWindowInfosChanged is
Siarhei Vishniakoufb9fcda2020-05-04 14:59:19 -0700726 * called twice.
727 */
Prabir Pradhan76bdecb2022-01-31 11:14:15 -0800728TEST_F(InputDispatcherTest, SetInputWindowOnceWithSingleTouchWindow) {
Chris Yea209fde2020-07-22 13:54:51 -0700729 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -0700730 sp<FakeWindowHandle> window =
731 sp<FakeWindowHandle>::make(application, mDispatcher, "Fake Window",
732 ui::LogicalDisplayId::DEFAULT);
Siarhei Vishniakoufb9fcda2020-05-04 14:59:19 -0700733 window->setFrame(Rect(0, 0, 100, 100));
Siarhei Vishniakoufb9fcda2020-05-04 14:59:19 -0700734
Siarhei Vishniakouc41de372023-07-20 13:14:26 -0700735 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -0800736 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -0700737 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN,
738 ui::LogicalDisplayId::DEFAULT, {50, 50}))
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -0800739 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
Siarhei Vishniakoufb9fcda2020-05-04 14:59:19 -0700740
741 // Window should receive motion event.
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -0700742 window->consumeMotionDown(ui::LogicalDisplayId::DEFAULT);
Siarhei Vishniakoufb9fcda2020-05-04 14:59:19 -0700743}
744
745/**
Siarhei Vishniakouc41de372023-07-20 13:14:26 -0700746 * Calling onWindowInfosChanged twice, with the same info, should not cause any issues.
Siarhei Vishniakoufb9fcda2020-05-04 14:59:19 -0700747 */
748TEST_F(InputDispatcherTest, SetInputWindowTwice_SingleWindowTouch) {
Chris Yea209fde2020-07-22 13:54:51 -0700749 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -0700750 sp<FakeWindowHandle> window =
751 sp<FakeWindowHandle>::make(application, mDispatcher, "Fake Window",
752 ui::LogicalDisplayId::DEFAULT);
Siarhei Vishniakoufb9fcda2020-05-04 14:59:19 -0700753 window->setFrame(Rect(0, 0, 100, 100));
Siarhei Vishniakoufb9fcda2020-05-04 14:59:19 -0700754
Siarhei Vishniakouc41de372023-07-20 13:14:26 -0700755 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
756 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -0800757 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -0700758 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN,
759 ui::LogicalDisplayId::DEFAULT, {50, 50}))
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -0800760 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
Siarhei Vishniakoufb9fcda2020-05-04 14:59:19 -0700761
762 // Window should receive motion event.
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -0700763 window->consumeMotionDown(ui::LogicalDisplayId::DEFAULT);
Siarhei Vishniakoufb9fcda2020-05-04 14:59:19 -0700764}
765
Arthur Hungb92218b2018-08-14 12:00:21 +0800766// The foreground window should receive the first touch down event.
767TEST_F(InputDispatcherTest, SetInputWindow_MultiWindowsTouch) {
Chris Yea209fde2020-07-22 13:54:51 -0700768 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -0700769 sp<FakeWindowHandle> windowTop = sp<FakeWindowHandle>::make(application, mDispatcher, "Top",
770 ui::LogicalDisplayId::DEFAULT);
Siarhei Vishniakou870ecec2020-12-09 08:07:46 -1000771 sp<FakeWindowHandle> windowSecond =
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -0700772 sp<FakeWindowHandle>::make(application, mDispatcher, "Second",
773 ui::LogicalDisplayId::DEFAULT);
Arthur Hungb92218b2018-08-14 12:00:21 +0800774
Siarhei Vishniakouc41de372023-07-20 13:14:26 -0700775 mDispatcher->onWindowInfosChanged(
776 {{*windowTop->getInfo(), *windowSecond->getInfo()}, {}, 0, 0});
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -0800777 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -0700778 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN,
779 ui::LogicalDisplayId::DEFAULT))
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -0800780 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
Arthur Hungb92218b2018-08-14 12:00:21 +0800781
782 // Top window should receive the touch down event. Second window should not receive anything.
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -0700783 windowTop->consumeMotionDown(ui::LogicalDisplayId::DEFAULT);
Arthur Hungb92218b2018-08-14 12:00:21 +0800784 windowSecond->assertNoEvents();
785}
786
Siarhei Vishniakouca205502021-07-16 21:31:58 +0000787/**
788 * Two windows: A top window, and a wallpaper behind the window.
789 * Touch goes to the top window, and then top window disappears. Ensure that wallpaper window
790 * gets ACTION_CANCEL.
Prabir Pradhan4d5c52f2022-01-31 08:52:10 -0800791 * 1. foregroundWindow <-- dup touch to wallpaper
792 * 2. wallpaperWindow <-- is wallpaper
Siarhei Vishniakouca205502021-07-16 21:31:58 +0000793 */
794TEST_F(InputDispatcherTest, WhenForegroundWindowDisappears_WallpaperTouchIsCanceled) {
795 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
796 sp<FakeWindowHandle> foregroundWindow =
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -0700797 sp<FakeWindowHandle>::make(application, mDispatcher, "Foreground",
798 ui::LogicalDisplayId::DEFAULT);
Prabir Pradhan4d5c52f2022-01-31 08:52:10 -0800799 foregroundWindow->setDupTouchToWallpaper(true);
Siarhei Vishniakouca205502021-07-16 21:31:58 +0000800 sp<FakeWindowHandle> wallpaperWindow =
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -0700801 sp<FakeWindowHandle>::make(application, mDispatcher, "Wallpaper",
802 ui::LogicalDisplayId::DEFAULT);
Prabir Pradhan4d5c52f2022-01-31 08:52:10 -0800803 wallpaperWindow->setIsWallpaper(true);
Siarhei Vishniakouca205502021-07-16 21:31:58 +0000804
Siarhei Vishniakouc41de372023-07-20 13:14:26 -0700805 mDispatcher->onWindowInfosChanged(
806 {{*foregroundWindow->getInfo(), *wallpaperWindow->getInfo()}, {}, 0, 0});
Siarhei Vishniakouca205502021-07-16 21:31:58 +0000807 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoud908f5a2023-11-16 10:25:12 -0800808 injectMotionEvent(*mDispatcher,
809 MotionEventBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
810 .pointer(PointerBuilder(0, ToolType::FINGER).x(100).y(200))
811 .build()))
Siarhei Vishniakouca205502021-07-16 21:31:58 +0000812 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
813
814 // Both foreground window and its wallpaper should receive the touch down
815 foregroundWindow->consumeMotionDown();
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -0700816 wallpaperWindow->consumeMotionDown(ui::LogicalDisplayId::DEFAULT, EXPECTED_WALLPAPER_FLAGS);
Siarhei Vishniakouca205502021-07-16 21:31:58 +0000817
818 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoud908f5a2023-11-16 10:25:12 -0800819 injectMotionEvent(*mDispatcher,
820 MotionEventBuilder(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN)
821 .pointer(PointerBuilder(0, ToolType::FINGER).x(110).y(200))
822 .build()))
Siarhei Vishniakouca205502021-07-16 21:31:58 +0000823 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
824
Siarhei Vishniakoud908f5a2023-11-16 10:25:12 -0800825 foregroundWindow->consumeMotionEvent(WithMotionAction(ACTION_MOVE));
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -0700826 wallpaperWindow->consumeMotionMove(ui::LogicalDisplayId::DEFAULT, EXPECTED_WALLPAPER_FLAGS);
Siarhei Vishniakouca205502021-07-16 21:31:58 +0000827
828 // Now the foreground window goes away, but the wallpaper stays
Siarhei Vishniakouc41de372023-07-20 13:14:26 -0700829 mDispatcher->onWindowInfosChanged({{*wallpaperWindow->getInfo()}, {}, 0, 0});
Siarhei Vishniakouca205502021-07-16 21:31:58 +0000830 foregroundWindow->consumeMotionCancel();
831 // Since the "parent" window of the wallpaper is gone, wallpaper should receive cancel, too.
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -0700832 wallpaperWindow->consumeMotionCancel(ui::LogicalDisplayId::DEFAULT, EXPECTED_WALLPAPER_FLAGS);
Siarhei Vishniakouca205502021-07-16 21:31:58 +0000833}
834
835/**
Siarhei Vishniakou82dc0422023-02-17 23:12:52 -0800836 * Two fingers down on the window, and lift off the first finger.
837 * Next, cancel the gesture to the window by removing the window. Make sure that the CANCEL event
838 * contains a single pointer.
839 */
840TEST_F(InputDispatcherTest, CancelAfterPointer0Up) {
841 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -0700842 sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher, "Window",
843 ui::LogicalDisplayId::DEFAULT);
Siarhei Vishniakou82dc0422023-02-17 23:12:52 -0800844
Siarhei Vishniakouc41de372023-07-20 13:14:26 -0700845 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Siarhei Vishniakou82dc0422023-02-17 23:12:52 -0800846 // First touch pointer down on right window
Prabir Pradhan678438e2023-04-13 19:32:51 +0000847 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
848 .pointer(PointerBuilder(0, ToolType::FINGER).x(100).y(100))
849 .build());
Siarhei Vishniakou82dc0422023-02-17 23:12:52 -0800850 // Second touch pointer down
Prabir Pradhan678438e2023-04-13 19:32:51 +0000851 mDispatcher->notifyMotion(MotionArgsBuilder(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
852 .pointer(PointerBuilder(0, ToolType::FINGER).x(100).y(100))
853 .pointer(PointerBuilder(1, ToolType::FINGER).x(110).y(100))
854 .build());
Siarhei Vishniakou82dc0422023-02-17 23:12:52 -0800855 // First touch pointer lifts. The second one remains down
Prabir Pradhan678438e2023-04-13 19:32:51 +0000856 mDispatcher->notifyMotion(MotionArgsBuilder(POINTER_0_UP, AINPUT_SOURCE_TOUCHSCREEN)
857 .pointer(PointerBuilder(0, ToolType::FINGER).x(100).y(100))
858 .pointer(PointerBuilder(1, ToolType::FINGER).x(110).y(100))
859 .build());
Siarhei Vishniakou82dc0422023-02-17 23:12:52 -0800860 window->consumeMotionEvent(WithMotionAction(ACTION_DOWN));
861 window->consumeMotionEvent(WithMotionAction(POINTER_1_DOWN));
862 window->consumeMotionEvent(WithMotionAction(POINTER_0_UP));
863
864 // Remove the window. The gesture should be canceled
Siarhei Vishniakouc41de372023-07-20 13:14:26 -0700865 mDispatcher->onWindowInfosChanged({{}, {}, 0, 0});
Siarhei Vishniakou82dc0422023-02-17 23:12:52 -0800866 const std::map<int32_t, PointF> expectedPointers{{1, PointF{110, 100}}};
867 window->consumeMotionEvent(
868 AllOf(WithMotionAction(ACTION_CANCEL), WithPointers(expectedPointers)));
869}
870
871/**
Siarhei Vishniakou2b030972021-11-18 10:01:27 -0800872 * Same test as WhenForegroundWindowDisappears_WallpaperTouchIsCanceled above,
873 * with the following differences:
874 * After ACTION_DOWN, Wallpaper window hangs up its channel, which forces the dispatcher to
875 * clean up the connection.
876 * This later may crash dispatcher during ACTION_CANCEL synthesis, if the dispatcher is not careful.
877 * Ensure that there's no crash in the dispatcher.
878 */
879TEST_F(InputDispatcherTest, WhenWallpaperDisappears_NoCrash) {
880 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
881 sp<FakeWindowHandle> foregroundWindow =
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -0700882 sp<FakeWindowHandle>::make(application, mDispatcher, "Foreground",
883 ui::LogicalDisplayId::DEFAULT);
Prabir Pradhan4d5c52f2022-01-31 08:52:10 -0800884 foregroundWindow->setDupTouchToWallpaper(true);
Siarhei Vishniakou2b030972021-11-18 10:01:27 -0800885 sp<FakeWindowHandle> wallpaperWindow =
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -0700886 sp<FakeWindowHandle>::make(application, mDispatcher, "Wallpaper",
887 ui::LogicalDisplayId::DEFAULT);
Prabir Pradhan4d5c52f2022-01-31 08:52:10 -0800888 wallpaperWindow->setIsWallpaper(true);
Siarhei Vishniakou2b030972021-11-18 10:01:27 -0800889
Siarhei Vishniakouc41de372023-07-20 13:14:26 -0700890 mDispatcher->onWindowInfosChanged(
891 {{*foregroundWindow->getInfo(), *wallpaperWindow->getInfo()}, {}, 0, 0});
Siarhei Vishniakou2b030972021-11-18 10:01:27 -0800892 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -0700893 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN,
894 ui::LogicalDisplayId::DEFAULT, {100, 200}))
Siarhei Vishniakou2b030972021-11-18 10:01:27 -0800895 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
896
897 // Both foreground window and its wallpaper should receive the touch down
898 foregroundWindow->consumeMotionDown();
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -0700899 wallpaperWindow->consumeMotionDown(ui::LogicalDisplayId::DEFAULT, EXPECTED_WALLPAPER_FLAGS);
Siarhei Vishniakou2b030972021-11-18 10:01:27 -0800900
901 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -0700902 injectMotionEvent(*mDispatcher, AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN,
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -0700903 ui::LogicalDisplayId::DEFAULT, {110, 200}))
Siarhei Vishniakou2b030972021-11-18 10:01:27 -0800904 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
905
906 foregroundWindow->consumeMotionMove();
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -0700907 wallpaperWindow->consumeMotionMove(ui::LogicalDisplayId::DEFAULT, EXPECTED_WALLPAPER_FLAGS);
Siarhei Vishniakou2b030972021-11-18 10:01:27 -0800908
909 // Wallpaper closes its channel, but the window remains.
910 wallpaperWindow->destroyReceiver();
911 mFakePolicy->assertNotifyInputChannelBrokenWasCalled(wallpaperWindow->getInfo()->token);
912
913 // Now the foreground window goes away, but the wallpaper stays, even though its channel
914 // is no longer valid.
Siarhei Vishniakouc41de372023-07-20 13:14:26 -0700915 mDispatcher->onWindowInfosChanged({{*wallpaperWindow->getInfo()}, {}, 0, 0});
Siarhei Vishniakou2b030972021-11-18 10:01:27 -0800916 foregroundWindow->consumeMotionCancel();
917}
918
Linnan Li72352222024-04-12 18:55:57 +0800919/**
920 * Two windows: left and right, and a separate wallpaper window underneath each. Device A sends a
921 * down event to the left window. Device B sends a down event to the right window. Next, the right
922 * window disappears. Both the right window and its wallpaper window should receive cancel event.
923 * The left window and its wallpaper window should not receive any events.
924 */
925TEST_F(InputDispatcherTest, MultiDeviceDisappearingWindowWithWallpaperWindows) {
926 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
927 sp<FakeWindowHandle> leftForegroundWindow =
928 sp<FakeWindowHandle>::make(application, mDispatcher, "Left foreground window",
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -0700929 ui::LogicalDisplayId::DEFAULT);
Linnan Li72352222024-04-12 18:55:57 +0800930 leftForegroundWindow->setFrame(Rect(0, 0, 100, 100));
931 leftForegroundWindow->setDupTouchToWallpaper(true);
932 sp<FakeWindowHandle> leftWallpaperWindow =
933 sp<FakeWindowHandle>::make(application, mDispatcher, "Left wallpaper window",
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -0700934 ui::LogicalDisplayId::DEFAULT);
Linnan Li72352222024-04-12 18:55:57 +0800935 leftWallpaperWindow->setFrame(Rect(0, 0, 100, 100));
936 leftWallpaperWindow->setIsWallpaper(true);
937
938 sp<FakeWindowHandle> rightForegroundWindow =
939 sp<FakeWindowHandle>::make(application, mDispatcher, "Right foreground window",
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -0700940 ui::LogicalDisplayId::DEFAULT);
Linnan Li72352222024-04-12 18:55:57 +0800941 rightForegroundWindow->setFrame(Rect(100, 0, 200, 100));
942 rightForegroundWindow->setDupTouchToWallpaper(true);
943 sp<FakeWindowHandle> rightWallpaperWindow =
944 sp<FakeWindowHandle>::make(application, mDispatcher, "Right wallpaper window",
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -0700945 ui::LogicalDisplayId::DEFAULT);
Linnan Li72352222024-04-12 18:55:57 +0800946 rightWallpaperWindow->setFrame(Rect(100, 0, 200, 100));
947 rightWallpaperWindow->setIsWallpaper(true);
948
949 mDispatcher->onWindowInfosChanged(
950 {{*leftForegroundWindow->getInfo(), *leftWallpaperWindow->getInfo(),
951 *rightForegroundWindow->getInfo(), *rightWallpaperWindow->getInfo()},
952 {},
953 0,
954 0});
955
956 const DeviceId deviceA = 9;
957 const DeviceId deviceB = 3;
958 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
959 .pointer(PointerBuilder(0, ToolType::FINGER).x(50).y(50))
960 .deviceId(deviceA)
961 .build());
962 leftForegroundWindow->consumeMotionEvent(
963 AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(deviceA)));
964 leftWallpaperWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN),
965 WithDeviceId(deviceA),
966 WithFlags(EXPECTED_WALLPAPER_FLAGS)));
967
968 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
969 .pointer(PointerBuilder(0, ToolType::FINGER).x(150).y(50))
970 .deviceId(deviceB)
971 .build());
972 rightForegroundWindow->consumeMotionEvent(
973 AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(deviceB)));
974 rightWallpaperWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN),
975 WithDeviceId(deviceB),
976 WithFlags(EXPECTED_WALLPAPER_FLAGS)));
977
978 // Now right foreground window disappears, but right wallpaper window remains.
979 mDispatcher->onWindowInfosChanged(
980 {{*leftForegroundWindow->getInfo(), *leftWallpaperWindow->getInfo(),
981 *rightWallpaperWindow->getInfo()},
982 {},
983 0,
984 0});
985
986 // Left foreground window and left wallpaper window still exist, and should not receive any
987 // events.
988 leftForegroundWindow->assertNoEvents();
989 leftWallpaperWindow->assertNoEvents();
990 // Since right foreground window disappeared, right wallpaper window and right foreground window
991 // should receive cancel events.
992 rightForegroundWindow->consumeMotionEvent(
993 AllOf(WithMotionAction(ACTION_CANCEL), WithDeviceId(deviceB)));
994 rightWallpaperWindow->consumeMotionEvent(
995 AllOf(WithMotionAction(ACTION_CANCEL), WithDeviceId(deviceB),
996 WithFlags(EXPECTED_WALLPAPER_FLAGS | AMOTION_EVENT_FLAG_CANCELED)));
997}
998
999/**
1000 * Three windows arranged horizontally and without any overlap. Every window has a
1001 * wallpaper window underneath. The middle window also has SLIPPERY flag.
1002 * Device A sends a down event to the left window. Device B sends a down event to the middle window.
1003 * Next, device B sends move event to the right window. Touch for device B should slip from the
1004 * middle window to the right window. Also, the right wallpaper window should receive a down event.
1005 * The middle window and its wallpaper window should receive a cancel event. The left window should
1006 * not receive any events. If device B continues to report events, the right window and its
1007 * wallpaper window should receive remaining events.
1008 */
1009TEST_F(InputDispatcherTest, MultiDeviceSlipperyTouchWithWallpaperWindow) {
1010 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
1011 sp<FakeWindowHandle> leftForegroundWindow =
1012 sp<FakeWindowHandle>::make(application, mDispatcher, "Left foreground window",
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07001013 ui::LogicalDisplayId::DEFAULT);
Linnan Li72352222024-04-12 18:55:57 +08001014 leftForegroundWindow->setFrame(Rect(0, 0, 100, 100));
1015 leftForegroundWindow->setDupTouchToWallpaper(true);
1016 sp<FakeWindowHandle> leftWallpaperWindow =
1017 sp<FakeWindowHandle>::make(application, mDispatcher, "Left wallpaper window",
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07001018 ui::LogicalDisplayId::DEFAULT);
Linnan Li72352222024-04-12 18:55:57 +08001019 leftWallpaperWindow->setFrame(Rect(0, 0, 100, 100));
1020 leftWallpaperWindow->setIsWallpaper(true);
1021
1022 sp<FakeWindowHandle> middleForegroundWindow =
1023 sp<FakeWindowHandle>::make(application, mDispatcher, "Middle foreground window",
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07001024 ui::LogicalDisplayId::DEFAULT);
Linnan Li72352222024-04-12 18:55:57 +08001025 middleForegroundWindow->setFrame(Rect(100, 0, 200, 100));
1026 middleForegroundWindow->setDupTouchToWallpaper(true);
1027 middleForegroundWindow->setSlippery(true);
1028 sp<FakeWindowHandle> middleWallpaperWindow =
1029 sp<FakeWindowHandle>::make(application, mDispatcher, "Middle wallpaper window",
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07001030 ui::LogicalDisplayId::DEFAULT);
Linnan Li72352222024-04-12 18:55:57 +08001031 middleWallpaperWindow->setFrame(Rect(100, 0, 200, 100));
1032 middleWallpaperWindow->setIsWallpaper(true);
1033
1034 sp<FakeWindowHandle> rightForegroundWindow =
1035 sp<FakeWindowHandle>::make(application, mDispatcher, "Right foreground window",
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07001036 ui::LogicalDisplayId::DEFAULT);
Linnan Li72352222024-04-12 18:55:57 +08001037 rightForegroundWindow->setFrame(Rect(200, 0, 300, 100));
1038 rightForegroundWindow->setDupTouchToWallpaper(true);
1039 sp<FakeWindowHandle> rightWallpaperWindow =
1040 sp<FakeWindowHandle>::make(application, mDispatcher, "Right wallpaper window",
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07001041 ui::LogicalDisplayId::DEFAULT);
Linnan Li72352222024-04-12 18:55:57 +08001042 rightWallpaperWindow->setFrame(Rect(200, 0, 300, 100));
1043 rightWallpaperWindow->setIsWallpaper(true);
1044
1045 mDispatcher->onWindowInfosChanged(
1046 {{*leftForegroundWindow->getInfo(), *leftWallpaperWindow->getInfo(),
1047 *middleForegroundWindow->getInfo(), *middleWallpaperWindow->getInfo(),
1048 *rightForegroundWindow->getInfo(), *rightWallpaperWindow->getInfo()},
1049 {},
1050 0,
1051 0});
1052
1053 const DeviceId deviceA = 9;
1054 const DeviceId deviceB = 3;
1055 // Device A sends a DOWN event to the left window
1056 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
1057 .pointer(PointerBuilder(0, ToolType::FINGER).x(50).y(50))
1058 .deviceId(deviceA)
1059 .build());
1060 leftForegroundWindow->consumeMotionEvent(
1061 AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(deviceA)));
1062 leftWallpaperWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN),
1063 WithDeviceId(deviceA),
1064 WithFlags(EXPECTED_WALLPAPER_FLAGS)));
1065 // Device B sends a DOWN event to the middle window
1066 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
1067 .pointer(PointerBuilder(0, ToolType::FINGER).x(150).y(50))
1068 .deviceId(deviceB)
1069 .build());
1070 middleForegroundWindow->consumeMotionEvent(
1071 AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(deviceB)));
1072 middleWallpaperWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN),
1073 WithDeviceId(deviceB),
1074 WithFlags(EXPECTED_WALLPAPER_FLAGS)));
1075 // Move the events of device B to the top of the right window.
1076 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN)
1077 .pointer(PointerBuilder(0, ToolType::FINGER).x(250).y(50))
1078 .deviceId(deviceB)
1079 .build());
1080 middleForegroundWindow->consumeMotionEvent(
1081 AllOf(WithMotionAction(ACTION_CANCEL), WithDeviceId(deviceB)));
1082 middleWallpaperWindow->consumeMotionEvent(
1083 AllOf(WithMotionAction(ACTION_CANCEL), WithDeviceId(deviceB),
1084 WithFlags(EXPECTED_WALLPAPER_FLAGS | AMOTION_EVENT_FLAG_CANCELED)));
1085 rightForegroundWindow->consumeMotionEvent(
1086 AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(deviceB)));
1087 rightWallpaperWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN),
1088 WithDeviceId(deviceB),
1089 WithFlags(EXPECTED_WALLPAPER_FLAGS)));
1090 // Make sure the window on the right can receive the remaining events.
1091 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN)
1092 .pointer(PointerBuilder(0, ToolType::FINGER).x(251).y(51))
1093 .deviceId(deviceB)
1094 .build());
1095 leftForegroundWindow->assertNoEvents();
1096 leftWallpaperWindow->assertNoEvents();
1097 middleForegroundWindow->assertNoEvents();
1098 middleWallpaperWindow->assertNoEvents();
1099 rightForegroundWindow->consumeMotionEvent(
1100 AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(deviceB)));
1101 rightWallpaperWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_MOVE),
1102 WithDeviceId(deviceB),
1103 WithFlags(EXPECTED_WALLPAPER_FLAGS)));
1104}
1105
1106/**
1107 * Similar to the test above, we have three windows, they are arranged horizontally and without any
1108 * overlap, and every window has a wallpaper window. The middle window is a simple window, without
1109 * any special flags. Device A reports a down event that lands in left window. Device B sends a down
1110 * event to the middle window and then touch is transferred from the middle window to the right
1111 * window. The right window and its wallpaper window should receive a down event. The middle window
1112 * and its wallpaper window should receive a cancel event. The left window should not receive any
1113 * events. Subsequent events reported by device B should go to the right window and its wallpaper.
1114 */
1115TEST_F(InputDispatcherTest, MultiDeviceTouchTransferWithWallpaperWindows) {
1116 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
1117 sp<FakeWindowHandle> leftForegroundWindow =
1118 sp<FakeWindowHandle>::make(application, mDispatcher, "Left foreground window",
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07001119 ui::LogicalDisplayId::DEFAULT);
Linnan Li72352222024-04-12 18:55:57 +08001120 leftForegroundWindow->setFrame(Rect(0, 0, 100, 100));
1121 leftForegroundWindow->setDupTouchToWallpaper(true);
1122 sp<FakeWindowHandle> leftWallpaperWindow =
1123 sp<FakeWindowHandle>::make(application, mDispatcher, "Left wallpaper window",
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07001124 ui::LogicalDisplayId::DEFAULT);
Linnan Li72352222024-04-12 18:55:57 +08001125 leftWallpaperWindow->setFrame(Rect(0, 0, 100, 100));
1126 leftWallpaperWindow->setIsWallpaper(true);
1127
1128 sp<FakeWindowHandle> middleForegroundWindow =
1129 sp<FakeWindowHandle>::make(application, mDispatcher, "Middle foreground window",
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07001130 ui::LogicalDisplayId::DEFAULT);
Linnan Li72352222024-04-12 18:55:57 +08001131 middleForegroundWindow->setFrame(Rect(100, 0, 200, 100));
1132 middleForegroundWindow->setDupTouchToWallpaper(true);
1133 sp<FakeWindowHandle> middleWallpaperWindow =
1134 sp<FakeWindowHandle>::make(application, mDispatcher, "Middle wallpaper window",
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07001135 ui::LogicalDisplayId::DEFAULT);
Linnan Li72352222024-04-12 18:55:57 +08001136 middleWallpaperWindow->setFrame(Rect(100, 0, 200, 100));
1137 middleWallpaperWindow->setIsWallpaper(true);
1138
1139 sp<FakeWindowHandle> rightForegroundWindow =
1140 sp<FakeWindowHandle>::make(application, mDispatcher, "Right foreground window",
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07001141 ui::LogicalDisplayId::DEFAULT);
Linnan Li72352222024-04-12 18:55:57 +08001142 rightForegroundWindow->setFrame(Rect(200, 0, 300, 100));
1143 rightForegroundWindow->setDupTouchToWallpaper(true);
1144 sp<FakeWindowHandle> rightWallpaperWindow =
1145 sp<FakeWindowHandle>::make(application, mDispatcher, "Right wallpaper window",
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07001146 ui::LogicalDisplayId::DEFAULT);
Linnan Li72352222024-04-12 18:55:57 +08001147 rightWallpaperWindow->setFrame(Rect(200, 0, 300, 100));
1148 rightWallpaperWindow->setIsWallpaper(true);
1149
1150 mDispatcher->onWindowInfosChanged(
1151 {{*leftForegroundWindow->getInfo(), *leftWallpaperWindow->getInfo(),
1152 *middleForegroundWindow->getInfo(), *middleWallpaperWindow->getInfo(),
1153 *rightForegroundWindow->getInfo(), *rightWallpaperWindow->getInfo()},
1154 {},
1155 0,
1156 0});
1157
1158 const DeviceId deviceA = 9;
1159 const DeviceId deviceB = 3;
1160 // Device A touch down on the left window
1161 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
1162 .pointer(PointerBuilder(0, ToolType::FINGER).x(50).y(50))
1163 .deviceId(deviceA)
1164 .build());
1165 leftForegroundWindow->consumeMotionEvent(
1166 AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(deviceA)));
1167 leftWallpaperWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN),
1168 WithDeviceId(deviceA),
1169 WithFlags(EXPECTED_WALLPAPER_FLAGS)));
1170 // Device B touch down on the middle window
1171 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
1172 .pointer(PointerBuilder(0, ToolType::FINGER).x(150).y(50))
1173 .deviceId(deviceB)
1174 .build());
1175 middleForegroundWindow->consumeMotionEvent(
1176 AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(deviceB)));
1177 middleWallpaperWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN),
1178 WithDeviceId(deviceB),
1179 WithFlags(EXPECTED_WALLPAPER_FLAGS)));
1180
1181 // Transfer touch from the middle window to the right window.
1182 ASSERT_TRUE(mDispatcher->transferTouchGesture(middleForegroundWindow->getToken(),
1183 rightForegroundWindow->getToken()));
1184
1185 middleForegroundWindow->consumeMotionEvent(
1186 AllOf(WithMotionAction(ACTION_CANCEL), WithDeviceId(deviceB)));
1187 middleWallpaperWindow->consumeMotionEvent(
1188 AllOf(WithMotionAction(ACTION_CANCEL), WithDeviceId(deviceB),
1189 WithFlags(EXPECTED_WALLPAPER_FLAGS | AMOTION_EVENT_FLAG_CANCELED)));
1190 rightForegroundWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN),
1191 WithDeviceId(deviceB),
1192 WithFlags(AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE)));
1193 rightWallpaperWindow->consumeMotionEvent(
1194 AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(deviceB),
1195 WithFlags(EXPECTED_WALLPAPER_FLAGS | AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE)));
1196
1197 // Make sure the right window can receive the remaining events.
1198 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN)
1199 .pointer(PointerBuilder(0, ToolType::FINGER).x(251).y(51))
1200 .deviceId(deviceB)
1201 .build());
1202 leftForegroundWindow->assertNoEvents();
1203 leftWallpaperWindow->assertNoEvents();
1204 middleForegroundWindow->assertNoEvents();
1205 middleWallpaperWindow->assertNoEvents();
1206 rightForegroundWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_MOVE),
1207 WithDeviceId(deviceB),
1208 WithFlags(AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE)));
1209 rightWallpaperWindow->consumeMotionEvent(
1210 AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(deviceB),
1211 WithFlags(EXPECTED_WALLPAPER_FLAGS | AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE)));
1212}
1213
Arthur Hungc539dbb2022-12-08 07:45:36 +00001214class ShouldSplitTouchFixture : public InputDispatcherTest,
1215 public ::testing::WithParamInterface<bool> {};
1216INSTANTIATE_TEST_SUITE_P(InputDispatcherTest, ShouldSplitTouchFixture,
1217 ::testing::Values(true, false));
Siarhei Vishniakou2b030972021-11-18 10:01:27 -08001218/**
Siarhei Vishniakouca205502021-07-16 21:31:58 +00001219 * A single window that receives touch (on top), and a wallpaper window underneath it.
1220 * The top window gets a multitouch gesture.
1221 * Ensure that wallpaper gets the same gesture.
1222 */
Arthur Hungc539dbb2022-12-08 07:45:36 +00001223TEST_P(ShouldSplitTouchFixture, WallpaperWindowReceivesMultiTouch) {
Siarhei Vishniakouca205502021-07-16 21:31:58 +00001224 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
Arthur Hungc539dbb2022-12-08 07:45:36 +00001225 sp<FakeWindowHandle> foregroundWindow =
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07001226 sp<FakeWindowHandle>::make(application, mDispatcher, "Foreground",
1227 ui::LogicalDisplayId::DEFAULT);
Arthur Hungc539dbb2022-12-08 07:45:36 +00001228 foregroundWindow->setDupTouchToWallpaper(true);
1229 foregroundWindow->setPreventSplitting(GetParam());
Siarhei Vishniakouca205502021-07-16 21:31:58 +00001230
1231 sp<FakeWindowHandle> wallpaperWindow =
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07001232 sp<FakeWindowHandle>::make(application, mDispatcher, "Wallpaper",
1233 ui::LogicalDisplayId::DEFAULT);
Prabir Pradhan4d5c52f2022-01-31 08:52:10 -08001234 wallpaperWindow->setIsWallpaper(true);
Siarhei Vishniakouca205502021-07-16 21:31:58 +00001235
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07001236 mDispatcher->onWindowInfosChanged(
1237 {{*foregroundWindow->getInfo(), *wallpaperWindow->getInfo()}, {}, 0, 0});
Siarhei Vishniakouca205502021-07-16 21:31:58 +00001238
1239 // Touch down on top window
1240 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07001241 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN,
1242 ui::LogicalDisplayId::DEFAULT, {100, 100}))
Siarhei Vishniakouca205502021-07-16 21:31:58 +00001243 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
1244
1245 // Both top window and its wallpaper should receive the touch down
Arthur Hungc539dbb2022-12-08 07:45:36 +00001246 foregroundWindow->consumeMotionDown();
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07001247 wallpaperWindow->consumeMotionDown(ui::LogicalDisplayId::DEFAULT, EXPECTED_WALLPAPER_FLAGS);
Siarhei Vishniakouca205502021-07-16 21:31:58 +00001248
1249 // Second finger down on the top window
1250 const MotionEvent secondFingerDownEvent =
Siarhei Vishniakoua16e3a22022-03-02 15:26:40 -08001251 MotionEventBuilder(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
Siarhei Vishniakouca205502021-07-16 21:31:58 +00001252 .eventTime(systemTime(SYSTEM_TIME_MONOTONIC))
Siarhei Vishniakou6d73f832022-07-21 17:27:03 -07001253 .pointer(PointerBuilder(/*id=*/0, ToolType::FINGER).x(100).y(100))
1254 .pointer(PointerBuilder(/*id=*/1, ToolType::FINGER).x(150).y(150))
Siarhei Vishniakouca205502021-07-16 21:31:58 +00001255 .build();
1256 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07001257 injectMotionEvent(*mDispatcher, secondFingerDownEvent, INJECT_EVENT_TIMEOUT,
Siarhei Vishniakouca205502021-07-16 21:31:58 +00001258 InputEventInjectionSync::WAIT_FOR_RESULT))
1259 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
Harry Cutts33476232023-01-30 19:57:29 +00001260 foregroundWindow->consumeMotionPointerDown(/*pointerIndex=*/1);
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07001261 wallpaperWindow->consumeMotionPointerDown(/*pointerIndex=*/1, ui::LogicalDisplayId::DEFAULT,
Linnan Li72352222024-04-12 18:55:57 +08001262 EXPECTED_WALLPAPER_FLAGS);
Arthur Hungc539dbb2022-12-08 07:45:36 +00001263
1264 const MotionEvent secondFingerUpEvent =
1265 MotionEventBuilder(POINTER_0_UP, AINPUT_SOURCE_TOUCHSCREEN)
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07001266 .displayId(ui::LogicalDisplayId::DEFAULT)
Arthur Hungc539dbb2022-12-08 07:45:36 +00001267 .eventTime(systemTime(SYSTEM_TIME_MONOTONIC))
Siarhei Vishniakou6d73f832022-07-21 17:27:03 -07001268 .pointer(PointerBuilder(/*id=*/0, ToolType::FINGER).x(100).y(100))
1269 .pointer(PointerBuilder(/*id=*/1, ToolType::FINGER).x(150).y(150))
Arthur Hungc539dbb2022-12-08 07:45:36 +00001270 .build();
1271 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07001272 injectMotionEvent(*mDispatcher, secondFingerUpEvent, INJECT_EVENT_TIMEOUT,
Arthur Hungc539dbb2022-12-08 07:45:36 +00001273 InputEventInjectionSync::WAIT_FOR_RESULT))
1274 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
Prabir Pradhan33cfc6d2024-06-11 20:17:44 +00001275 foregroundWindow->consumeMotionPointerUp(/*pointerIdx=*/0,
1276 WithDisplayId(ui::LogicalDisplayId::DEFAULT));
1277 wallpaperWindow->consumeMotionPointerUp(/*pointerIdx=*/0,
1278 AllOf(WithDisplayId(ui::LogicalDisplayId::DEFAULT),
1279 WithFlags(EXPECTED_WALLPAPER_FLAGS)));
Arthur Hungc539dbb2022-12-08 07:45:36 +00001280
1281 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07001282 injectMotionEvent(*mDispatcher,
Siarhei Vishniakou92c8fd52023-01-29 14:57:43 -08001283 MotionEventBuilder(AMOTION_EVENT_ACTION_UP,
1284 AINPUT_SOURCE_TOUCHSCREEN)
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07001285 .displayId(ui::LogicalDisplayId::DEFAULT)
Siarhei Vishniakou92c8fd52023-01-29 14:57:43 -08001286 .eventTime(systemTime(SYSTEM_TIME_MONOTONIC))
Harry Cutts101ee9b2023-07-06 18:04:14 +00001287 .pointer(PointerBuilder(/*id=*/1, ToolType::FINGER)
Siarhei Vishniakou92c8fd52023-01-29 14:57:43 -08001288 .x(100)
1289 .y(100))
1290 .build(),
1291 INJECT_EVENT_TIMEOUT, InputEventInjectionSync::WAIT_FOR_RESULT))
Arthur Hungc539dbb2022-12-08 07:45:36 +00001292 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07001293 foregroundWindow->consumeMotionUp(ui::LogicalDisplayId::DEFAULT);
1294 wallpaperWindow->consumeMotionUp(ui::LogicalDisplayId::DEFAULT, EXPECTED_WALLPAPER_FLAGS);
Siarhei Vishniakouca205502021-07-16 21:31:58 +00001295}
1296
1297/**
1298 * Two windows: a window on the left and window on the right.
1299 * A third window, wallpaper, is behind both windows, and spans both top windows.
1300 * The first touch down goes to the left window. A second pointer touches down on the right window.
1301 * The touch is split, so both left and right windows should receive ACTION_DOWN.
1302 * The wallpaper will get the full event, so it should receive ACTION_DOWN followed by
1303 * ACTION_POINTER_DOWN(1).
1304 */
1305TEST_F(InputDispatcherTest, TwoWindows_SplitWallpaperTouch) {
1306 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07001307 sp<FakeWindowHandle> leftWindow = sp<FakeWindowHandle>::make(application, mDispatcher, "Left",
1308 ui::LogicalDisplayId::DEFAULT);
Siarhei Vishniakouca205502021-07-16 21:31:58 +00001309 leftWindow->setFrame(Rect(0, 0, 200, 200));
Prabir Pradhan4d5c52f2022-01-31 08:52:10 -08001310 leftWindow->setDupTouchToWallpaper(true);
Siarhei Vishniakouca205502021-07-16 21:31:58 +00001311
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07001312 sp<FakeWindowHandle> rightWindow = sp<FakeWindowHandle>::make(application, mDispatcher, "Right",
1313 ui::LogicalDisplayId::DEFAULT);
Siarhei Vishniakouca205502021-07-16 21:31:58 +00001314 rightWindow->setFrame(Rect(200, 0, 400, 200));
Prabir Pradhan4d5c52f2022-01-31 08:52:10 -08001315 rightWindow->setDupTouchToWallpaper(true);
Siarhei Vishniakouca205502021-07-16 21:31:58 +00001316
1317 sp<FakeWindowHandle> wallpaperWindow =
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07001318 sp<FakeWindowHandle>::make(application, mDispatcher, "Wallpaper",
1319 ui::LogicalDisplayId::DEFAULT);
Siarhei Vishniakouca205502021-07-16 21:31:58 +00001320 wallpaperWindow->setFrame(Rect(0, 0, 400, 200));
Prabir Pradhan4d5c52f2022-01-31 08:52:10 -08001321 wallpaperWindow->setIsWallpaper(true);
Siarhei Vishniakouca205502021-07-16 21:31:58 +00001322
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07001323 mDispatcher->onWindowInfosChanged(
1324 {{*leftWindow->getInfo(), *rightWindow->getInfo(), *wallpaperWindow->getInfo()},
1325 {},
1326 0,
1327 0});
Siarhei Vishniakouca205502021-07-16 21:31:58 +00001328
1329 // Touch down on left window
1330 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07001331 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN,
1332 ui::LogicalDisplayId::DEFAULT, {100, 100}))
Siarhei Vishniakouca205502021-07-16 21:31:58 +00001333 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
1334
1335 // Both foreground window and its wallpaper should receive the touch down
1336 leftWindow->consumeMotionDown();
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07001337 wallpaperWindow->consumeMotionDown(ui::LogicalDisplayId::DEFAULT, EXPECTED_WALLPAPER_FLAGS);
Siarhei Vishniakouca205502021-07-16 21:31:58 +00001338
1339 // Second finger down on the right window
1340 const MotionEvent secondFingerDownEvent =
Siarhei Vishniakoua16e3a22022-03-02 15:26:40 -08001341 MotionEventBuilder(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
Siarhei Vishniakouca205502021-07-16 21:31:58 +00001342 .eventTime(systemTime(SYSTEM_TIME_MONOTONIC))
Siarhei Vishniakou6d73f832022-07-21 17:27:03 -07001343 .pointer(PointerBuilder(/*id=*/0, ToolType::FINGER).x(100).y(100))
1344 .pointer(PointerBuilder(/*id=*/1, ToolType::FINGER).x(300).y(100))
Siarhei Vishniakouca205502021-07-16 21:31:58 +00001345 .build();
1346 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07001347 injectMotionEvent(*mDispatcher, secondFingerDownEvent, INJECT_EVENT_TIMEOUT,
Siarhei Vishniakouca205502021-07-16 21:31:58 +00001348 InputEventInjectionSync::WAIT_FOR_RESULT))
1349 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
1350
1351 leftWindow->consumeMotionMove();
1352 // Since the touch is split, right window gets ACTION_DOWN
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07001353 rightWindow->consumeMotionDown(ui::LogicalDisplayId::DEFAULT);
1354 wallpaperWindow->consumeMotionPointerDown(/*pointerIndex=*/1, ui::LogicalDisplayId::DEFAULT,
Linnan Li72352222024-04-12 18:55:57 +08001355 EXPECTED_WALLPAPER_FLAGS);
Siarhei Vishniakouca205502021-07-16 21:31:58 +00001356
1357 // Now, leftWindow, which received the first finger, disappears.
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07001358 mDispatcher->onWindowInfosChanged(
1359 {{*rightWindow->getInfo(), *wallpaperWindow->getInfo()}, {}, 0, 0});
Siarhei Vishniakouca205502021-07-16 21:31:58 +00001360 leftWindow->consumeMotionCancel();
1361 // Since a "parent" window of the wallpaper is gone, wallpaper should receive cancel, too.
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07001362 wallpaperWindow->consumeMotionCancel(ui::LogicalDisplayId::DEFAULT, EXPECTED_WALLPAPER_FLAGS);
Siarhei Vishniakouca205502021-07-16 21:31:58 +00001363
1364 // The pointer that's still down on the right window moves, and goes to the right window only.
1365 // As far as the dispatcher's concerned though, both pointers are still present.
1366 const MotionEvent secondFingerMoveEvent =
1367 MotionEventBuilder(AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN)
1368 .eventTime(systemTime(SYSTEM_TIME_MONOTONIC))
Siarhei Vishniakou6d73f832022-07-21 17:27:03 -07001369 .pointer(PointerBuilder(/*id=*/0, ToolType::FINGER).x(100).y(100))
1370 .pointer(PointerBuilder(/*id=*/1, ToolType::FINGER).x(310).y(110))
Siarhei Vishniakouca205502021-07-16 21:31:58 +00001371 .build();
1372 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07001373 injectMotionEvent(*mDispatcher, secondFingerMoveEvent, INJECT_EVENT_TIMEOUT,
Siarhei Vishniakouca205502021-07-16 21:31:58 +00001374 InputEventInjectionSync::WAIT_FOR_RESULT));
1375 rightWindow->consumeMotionMove();
1376
1377 leftWindow->assertNoEvents();
1378 rightWindow->assertNoEvents();
1379 wallpaperWindow->assertNoEvents();
1380}
1381
Arthur Hungc539dbb2022-12-08 07:45:36 +00001382/**
1383 * Two windows: a window on the left with dup touch to wallpaper and window on the right without it.
1384 * The touch slips to the right window. so left window and wallpaper should receive ACTION_CANCEL
1385 * The right window should receive ACTION_DOWN.
1386 */
1387TEST_F(InputDispatcherTest, WallpaperWindowWhenSlippery) {
Arthur Hung74c248d2022-11-23 07:09:59 +00001388 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07001389 sp<FakeWindowHandle> leftWindow = sp<FakeWindowHandle>::make(application, mDispatcher, "Left",
1390 ui::LogicalDisplayId::DEFAULT);
Arthur Hungc539dbb2022-12-08 07:45:36 +00001391 leftWindow->setFrame(Rect(0, 0, 200, 200));
1392 leftWindow->setDupTouchToWallpaper(true);
1393 leftWindow->setSlippery(true);
1394
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07001395 sp<FakeWindowHandle> rightWindow = sp<FakeWindowHandle>::make(application, mDispatcher, "Right",
1396 ui::LogicalDisplayId::DEFAULT);
Arthur Hungc539dbb2022-12-08 07:45:36 +00001397 rightWindow->setFrame(Rect(200, 0, 400, 200));
Arthur Hung74c248d2022-11-23 07:09:59 +00001398
1399 sp<FakeWindowHandle> wallpaperWindow =
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07001400 sp<FakeWindowHandle>::make(application, mDispatcher, "Wallpaper",
1401 ui::LogicalDisplayId::DEFAULT);
Arthur Hung74c248d2022-11-23 07:09:59 +00001402 wallpaperWindow->setIsWallpaper(true);
Arthur Hung74c248d2022-11-23 07:09:59 +00001403
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07001404 mDispatcher->onWindowInfosChanged(
1405 {{*leftWindow->getInfo(), *rightWindow->getInfo(), *wallpaperWindow->getInfo()},
1406 {},
1407 0,
1408 0});
Arthur Hung74c248d2022-11-23 07:09:59 +00001409
Arthur Hungc539dbb2022-12-08 07:45:36 +00001410 // Touch down on left window
Arthur Hung74c248d2022-11-23 07:09:59 +00001411 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07001412 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN,
1413 ui::LogicalDisplayId::DEFAULT, {100, 100}))
Arthur Hung74c248d2022-11-23 07:09:59 +00001414 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
Arthur Hungc539dbb2022-12-08 07:45:36 +00001415
1416 // Both foreground window and its wallpaper should receive the touch down
1417 leftWindow->consumeMotionDown();
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07001418 wallpaperWindow->consumeMotionDown(ui::LogicalDisplayId::DEFAULT, EXPECTED_WALLPAPER_FLAGS);
Arthur Hung74c248d2022-11-23 07:09:59 +00001419
Arthur Hungc539dbb2022-12-08 07:45:36 +00001420 // Move to right window, the left window should receive cancel.
Arthur Hung74c248d2022-11-23 07:09:59 +00001421 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07001422 injectMotionEvent(*mDispatcher, AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN,
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07001423 ui::LogicalDisplayId::DEFAULT, {201, 100}))
Arthur Hung74c248d2022-11-23 07:09:59 +00001424 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
1425
Arthur Hungc539dbb2022-12-08 07:45:36 +00001426 leftWindow->consumeMotionCancel();
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07001427 rightWindow->consumeMotionDown(ui::LogicalDisplayId::DEFAULT);
1428 wallpaperWindow->consumeMotionCancel(ui::LogicalDisplayId::DEFAULT, EXPECTED_WALLPAPER_FLAGS);
Arthur Hung74c248d2022-11-23 07:09:59 +00001429}
1430
Siarhei Vishniakoua16e3a22022-03-02 15:26:40 -08001431/**
Siarhei Vishniakou5bf25d92023-02-08 15:43:38 -08001432 * The policy typically sets POLICY_FLAG_PASS_TO_USER to the events. But when the display is not
1433 * interactive, it might stop sending this flag.
1434 * In this test, we check that if the policy stops sending this flag mid-gesture, we still ensure
1435 * to have a consistent input stream.
1436 *
1437 * Test procedure:
1438 * DOWN -> POINTER_DOWN -> (stop sending POLICY_FLAG_PASS_TO_USER) -> CANCEL.
1439 * DOWN (new gesture).
1440 *
1441 * In the bad implementation, we could potentially drop the CANCEL event, and get an inconsistent
1442 * state in the dispatcher. This would cause the final DOWN event to not be delivered to the app.
1443 *
1444 * We technically just need a single window here, but we are using two windows (spy on top and a
1445 * regular window below) to emulate the actual situation where it happens on the device.
1446 */
1447TEST_F(InputDispatcherTest, TwoPointerCancelInconsistentPolicy) {
1448 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07001449 sp<FakeWindowHandle> spyWindow = sp<FakeWindowHandle>::make(application, mDispatcher, "Spy",
1450 ui::LogicalDisplayId::DEFAULT);
Siarhei Vishniakou5bf25d92023-02-08 15:43:38 -08001451 spyWindow->setFrame(Rect(0, 0, 200, 200));
1452 spyWindow->setTrustedOverlay(true);
1453 spyWindow->setSpy(true);
1454
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07001455 sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher, "Window",
1456 ui::LogicalDisplayId::DEFAULT);
Siarhei Vishniakou5bf25d92023-02-08 15:43:38 -08001457 window->setFrame(Rect(0, 0, 200, 200));
1458
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07001459 mDispatcher->onWindowInfosChanged({{*spyWindow->getInfo(), *window->getInfo()}, {}, 0, 0});
Siarhei Vishniakou5bf25d92023-02-08 15:43:38 -08001460 const int32_t touchDeviceId = 4;
Siarhei Vishniakou5bf25d92023-02-08 15:43:38 -08001461
1462 // Two pointers down
Prabir Pradhan678438e2023-04-13 19:32:51 +00001463 mDispatcher->notifyMotion(
1464 MotionArgsBuilder(AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
1465 .deviceId(touchDeviceId)
1466 .policyFlags(DEFAULT_POLICY_FLAGS)
1467 .pointer(PointerBuilder(0, ToolType::FINGER).x(100).y(100))
1468 .build());
Siarhei Vishniakou5bf25d92023-02-08 15:43:38 -08001469
Prabir Pradhan678438e2023-04-13 19:32:51 +00001470 mDispatcher->notifyMotion(MotionArgsBuilder(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
1471 .deviceId(touchDeviceId)
1472 .policyFlags(DEFAULT_POLICY_FLAGS)
1473 .pointer(PointerBuilder(0, ToolType::FINGER).x(100).y(100))
1474 .pointer(PointerBuilder(1, ToolType::FINGER).x(120).y(120))
1475 .build());
Siarhei Vishniakou5bf25d92023-02-08 15:43:38 -08001476 spyWindow->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_DOWN));
1477 spyWindow->consumeMotionEvent(WithMotionAction(POINTER_1_DOWN));
1478 window->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_DOWN));
1479 window->consumeMotionEvent(WithMotionAction(POINTER_1_DOWN));
1480
1481 // Cancel the current gesture. Send the cancel without the default policy flags.
Prabir Pradhan678438e2023-04-13 19:32:51 +00001482 mDispatcher->notifyMotion(
1483 MotionArgsBuilder(AMOTION_EVENT_ACTION_CANCEL, AINPUT_SOURCE_TOUCHSCREEN)
1484 .deviceId(touchDeviceId)
1485 .policyFlags(0)
1486 .pointer(PointerBuilder(0, ToolType::FINGER).x(100).y(100))
1487 .pointer(PointerBuilder(1, ToolType::FINGER).x(120).y(120))
1488 .build());
Siarhei Vishniakou5bf25d92023-02-08 15:43:38 -08001489 spyWindow->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_CANCEL));
1490 window->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_CANCEL));
1491
1492 // We don't need to reset the device to reproduce the issue, but the reset event typically
1493 // follows, so we keep it here to model the actual listener behaviour more closely.
Prabir Pradhan678438e2023-04-13 19:32:51 +00001494 mDispatcher->notifyDeviceReset({/*id=*/1, systemTime(SYSTEM_TIME_MONOTONIC), touchDeviceId});
Siarhei Vishniakou5bf25d92023-02-08 15:43:38 -08001495
1496 // Start new gesture
Prabir Pradhan678438e2023-04-13 19:32:51 +00001497 mDispatcher->notifyMotion(
1498 MotionArgsBuilder(AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
1499 .deviceId(touchDeviceId)
1500 .policyFlags(DEFAULT_POLICY_FLAGS)
1501 .pointer(PointerBuilder(0, ToolType::FINGER).x(100).y(100))
1502 .build());
Siarhei Vishniakou5bf25d92023-02-08 15:43:38 -08001503 spyWindow->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_DOWN));
1504 window->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_DOWN));
1505
1506 // No more events
1507 spyWindow->assertNoEvents();
1508 window->assertNoEvents();
1509}
1510
1511/**
Linnan Li907ae732023-09-05 17:14:21 +08001512 * Same as the above 'TwoPointerCancelInconsistentPolicy' test, but for hovers.
1513 * The policy typically sets POLICY_FLAG_PASS_TO_USER to the events. But when the display is not
1514 * interactive, it might stop sending this flag.
1515 * We've already ensured the consistency of the touch event in this case, and we should also ensure
1516 * the consistency of the hover event in this case.
1517 *
1518 * Test procedure:
1519 * HOVER_ENTER -> HOVER_MOVE -> (stop sending POLICY_FLAG_PASS_TO_USER) -> HOVER_EXIT
1520 * HOVER_ENTER -> HOVER_MOVE -> HOVER_EXIT
1521 *
1522 * We expect to receive two full streams of hover events.
1523 */
1524TEST_F(InputDispatcherTest, HoverEventInconsistentPolicy) {
1525 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
1526
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07001527 sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher, "Window",
1528 ui::LogicalDisplayId::DEFAULT);
Linnan Li907ae732023-09-05 17:14:21 +08001529 window->setFrame(Rect(0, 0, 300, 300));
1530
1531 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
1532
1533 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_ENTER, AINPUT_SOURCE_STYLUS)
1534 .policyFlags(DEFAULT_POLICY_FLAGS)
1535 .pointer(PointerBuilder(0, ToolType::STYLUS).x(100).y(101))
1536 .build());
1537 window->consumeMotionEvent(WithMotionAction(ACTION_HOVER_ENTER));
1538
1539 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_MOVE, AINPUT_SOURCE_STYLUS)
1540 .policyFlags(DEFAULT_POLICY_FLAGS)
1541 .pointer(PointerBuilder(0, ToolType::STYLUS).x(101).y(102))
1542 .build());
1543 window->consumeMotionEvent(WithMotionAction(ACTION_HOVER_MOVE));
1544
1545 // Send hover exit without the default policy flags.
1546 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_EXIT, AINPUT_SOURCE_STYLUS)
1547 .policyFlags(0)
1548 .pointer(PointerBuilder(0, ToolType::STYLUS).x(101).y(102))
1549 .build());
1550
1551 window->consumeMotionEvent(WithMotionAction(ACTION_HOVER_EXIT));
1552
1553 // Send a simple hover event stream, ensure dispatcher not crashed and window can receive
1554 // right event.
1555 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_ENTER, AINPUT_SOURCE_STYLUS)
1556 .policyFlags(DEFAULT_POLICY_FLAGS)
1557 .pointer(PointerBuilder(0, ToolType::STYLUS).x(200).y(201))
1558 .build());
1559 window->consumeMotionEvent(WithMotionAction(ACTION_HOVER_ENTER));
1560
1561 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_MOVE, AINPUT_SOURCE_STYLUS)
1562 .policyFlags(DEFAULT_POLICY_FLAGS)
1563 .pointer(PointerBuilder(0, ToolType::STYLUS).x(201).y(202))
1564 .build());
1565 window->consumeMotionEvent(WithMotionAction(ACTION_HOVER_MOVE));
1566
1567 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_EXIT, AINPUT_SOURCE_STYLUS)
1568 .policyFlags(DEFAULT_POLICY_FLAGS)
1569 .pointer(PointerBuilder(0, ToolType::STYLUS).x(201).y(202))
1570 .build());
1571 window->consumeMotionEvent(WithMotionAction(ACTION_HOVER_EXIT));
1572}
1573
1574/**
Siarhei Vishniakoue0431e42023-01-28 17:01:39 -08001575 * Two windows: a window on the left and a window on the right.
1576 * Mouse is hovered from the right window into the left window.
1577 * Next, we tap on the left window, where the cursor was last seen.
1578 * The second tap is done onto the right window.
1579 * The mouse and tap are from two different devices.
1580 * We technically don't need to set the downtime / eventtime for these events, but setting these
1581 * explicitly helps during debugging.
1582 * This test reproduces a crash where there is a mismatch between the downTime and eventTime.
1583 * In the buggy implementation, a tap on the right window would cause a crash.
1584 */
Siarhei Vishniakoued89cbb2023-10-13 10:42:44 -07001585TEST_F(InputDispatcherTest, HoverFromLeftToRightAndTap_legacy) {
1586 SCOPED_FLAG_OVERRIDE(enable_multi_device_same_window_stream, false);
1587
Siarhei Vishniakoue0431e42023-01-28 17:01:39 -08001588 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07001589 sp<FakeWindowHandle> leftWindow = sp<FakeWindowHandle>::make(application, mDispatcher, "Left",
1590 ui::LogicalDisplayId::DEFAULT);
Siarhei Vishniakoue0431e42023-01-28 17:01:39 -08001591 leftWindow->setFrame(Rect(0, 0, 200, 200));
1592
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07001593 sp<FakeWindowHandle> rightWindow = sp<FakeWindowHandle>::make(application, mDispatcher, "Right",
1594 ui::LogicalDisplayId::DEFAULT);
Siarhei Vishniakoue0431e42023-01-28 17:01:39 -08001595 rightWindow->setFrame(Rect(200, 0, 400, 200));
1596
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07001597 mDispatcher->onWindowInfosChanged(
1598 {{*leftWindow->getInfo(), *rightWindow->getInfo()}, {}, 0, 0});
Siarhei Vishniakoue0431e42023-01-28 17:01:39 -08001599 // All times need to start at the current time, otherwise the dispatcher will drop the events as
1600 // stale.
1601 const nsecs_t baseTime = systemTime(SYSTEM_TIME_MONOTONIC);
1602 const int32_t mouseDeviceId = 6;
1603 const int32_t touchDeviceId = 4;
1604 // Move the cursor from right
1605 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07001606 injectMotionEvent(*mDispatcher,
Siarhei Vishniakoue0431e42023-01-28 17:01:39 -08001607 MotionEventBuilder(AMOTION_EVENT_ACTION_HOVER_MOVE,
1608 AINPUT_SOURCE_MOUSE)
1609 .deviceId(mouseDeviceId)
1610 .downTime(baseTime + 10)
1611 .eventTime(baseTime + 20)
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07001612 .pointer(PointerBuilder(0, ToolType::MOUSE).x(300).y(100))
Siarhei Vishniakoue0431e42023-01-28 17:01:39 -08001613 .build()));
1614 rightWindow->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_ENTER));
1615
1616 // .. to the left window
1617 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07001618 injectMotionEvent(*mDispatcher,
Siarhei Vishniakoue0431e42023-01-28 17:01:39 -08001619 MotionEventBuilder(AMOTION_EVENT_ACTION_HOVER_MOVE,
1620 AINPUT_SOURCE_MOUSE)
1621 .deviceId(mouseDeviceId)
1622 .downTime(baseTime + 10)
1623 .eventTime(baseTime + 30)
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07001624 .pointer(PointerBuilder(0, ToolType::MOUSE).x(110).y(100))
Siarhei Vishniakoue0431e42023-01-28 17:01:39 -08001625 .build()));
1626 rightWindow->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_EXIT));
1627 leftWindow->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_ENTER));
1628 // Now tap the left window
1629 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07001630 injectMotionEvent(*mDispatcher,
Siarhei Vishniakoue0431e42023-01-28 17:01:39 -08001631 MotionEventBuilder(AMOTION_EVENT_ACTION_DOWN,
1632 AINPUT_SOURCE_TOUCHSCREEN)
1633 .deviceId(touchDeviceId)
1634 .downTime(baseTime + 40)
1635 .eventTime(baseTime + 40)
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07001636 .pointer(PointerBuilder(0, ToolType::FINGER).x(100).y(100))
Siarhei Vishniakoue0431e42023-01-28 17:01:39 -08001637 .build()));
1638 leftWindow->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_EXIT));
1639 leftWindow->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_DOWN));
1640
1641 // release tap
1642 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07001643 injectMotionEvent(*mDispatcher,
Siarhei Vishniakoue0431e42023-01-28 17:01:39 -08001644 MotionEventBuilder(AMOTION_EVENT_ACTION_UP,
1645 AINPUT_SOURCE_TOUCHSCREEN)
1646 .deviceId(touchDeviceId)
1647 .downTime(baseTime + 40)
1648 .eventTime(baseTime + 50)
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07001649 .pointer(PointerBuilder(0, ToolType::FINGER).x(100).y(100))
Siarhei Vishniakoue0431e42023-01-28 17:01:39 -08001650 .build()));
1651 leftWindow->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_UP));
1652
1653 // Tap the window on the right
1654 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07001655 injectMotionEvent(*mDispatcher,
Siarhei Vishniakoue0431e42023-01-28 17:01:39 -08001656 MotionEventBuilder(AMOTION_EVENT_ACTION_DOWN,
1657 AINPUT_SOURCE_TOUCHSCREEN)
1658 .deviceId(touchDeviceId)
1659 .downTime(baseTime + 60)
1660 .eventTime(baseTime + 60)
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07001661 .pointer(PointerBuilder(0, ToolType::FINGER).x(300).y(100))
Siarhei Vishniakoue0431e42023-01-28 17:01:39 -08001662 .build()));
1663 rightWindow->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_DOWN));
1664
1665 // release tap
1666 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07001667 injectMotionEvent(*mDispatcher,
Siarhei Vishniakoue0431e42023-01-28 17:01:39 -08001668 MotionEventBuilder(AMOTION_EVENT_ACTION_UP,
1669 AINPUT_SOURCE_TOUCHSCREEN)
1670 .deviceId(touchDeviceId)
1671 .downTime(baseTime + 60)
1672 .eventTime(baseTime + 70)
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07001673 .pointer(PointerBuilder(0, ToolType::FINGER).x(300).y(100))
Siarhei Vishniakoue0431e42023-01-28 17:01:39 -08001674 .build()));
1675 rightWindow->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_UP));
1676
1677 // No more events
1678 leftWindow->assertNoEvents();
1679 rightWindow->assertNoEvents();
1680}
1681
1682/**
Siarhei Vishniakoued89cbb2023-10-13 10:42:44 -07001683 * Two windows: a window on the left and a window on the right.
1684 * Mouse is hovered from the right window into the left window.
1685 * Next, we tap on the left window, where the cursor was last seen.
1686 * The second tap is done onto the right window.
1687 * The mouse and tap are from two different devices.
1688 * We technically don't need to set the downtime / eventtime for these events, but setting these
1689 * explicitly helps during debugging.
1690 * This test reproduces a crash where there is a mismatch between the downTime and eventTime.
1691 * In the buggy implementation, a tap on the right window would cause a crash.
1692 */
1693TEST_F(InputDispatcherTest, HoverFromLeftToRightAndTap) {
1694 SCOPED_FLAG_OVERRIDE(enable_multi_device_same_window_stream, true);
1695
1696 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07001697 sp<FakeWindowHandle> leftWindow = sp<FakeWindowHandle>::make(application, mDispatcher, "Left",
1698 ui::LogicalDisplayId::DEFAULT);
Siarhei Vishniakoued89cbb2023-10-13 10:42:44 -07001699 leftWindow->setFrame(Rect(0, 0, 200, 200));
1700
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07001701 sp<FakeWindowHandle> rightWindow = sp<FakeWindowHandle>::make(application, mDispatcher, "Right",
1702 ui::LogicalDisplayId::DEFAULT);
Siarhei Vishniakoued89cbb2023-10-13 10:42:44 -07001703 rightWindow->setFrame(Rect(200, 0, 400, 200));
1704
1705 mDispatcher->onWindowInfosChanged(
1706 {{*leftWindow->getInfo(), *rightWindow->getInfo()}, {}, 0, 0});
1707 // All times need to start at the current time, otherwise the dispatcher will drop the events as
1708 // stale.
1709 const nsecs_t baseTime = systemTime(SYSTEM_TIME_MONOTONIC);
1710 const int32_t mouseDeviceId = 6;
1711 const int32_t touchDeviceId = 4;
1712 // Move the cursor from right
1713 mDispatcher->notifyMotion(
1714 MotionArgsBuilder(AMOTION_EVENT_ACTION_HOVER_MOVE, AINPUT_SOURCE_MOUSE)
1715 .deviceId(mouseDeviceId)
1716 .downTime(baseTime + 10)
1717 .eventTime(baseTime + 20)
1718 .pointer(PointerBuilder(0, ToolType::MOUSE).x(300).y(100))
1719 .build());
1720 rightWindow->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_ENTER));
1721
1722 // .. to the left window
1723 mDispatcher->notifyMotion(
1724 MotionArgsBuilder(AMOTION_EVENT_ACTION_HOVER_MOVE, AINPUT_SOURCE_MOUSE)
1725 .deviceId(mouseDeviceId)
1726 .downTime(baseTime + 10)
1727 .eventTime(baseTime + 30)
1728 .pointer(PointerBuilder(0, ToolType::MOUSE).x(110).y(100))
1729 .build());
1730 rightWindow->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_EXIT));
1731 leftWindow->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_ENTER));
1732 // Now tap the left window
1733 mDispatcher->notifyMotion(
1734 MotionArgsBuilder(AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
1735 .deviceId(touchDeviceId)
1736 .downTime(baseTime + 40)
1737 .eventTime(baseTime + 40)
1738 .pointer(PointerBuilder(0, ToolType::FINGER).x(100).y(100))
1739 .build());
1740 leftWindow->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_DOWN));
1741
1742 // release tap
1743 mDispatcher->notifyMotion(MotionArgsBuilder(AMOTION_EVENT_ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN)
1744 .deviceId(touchDeviceId)
1745 .downTime(baseTime + 40)
1746 .eventTime(baseTime + 50)
1747 .pointer(PointerBuilder(0, ToolType::FINGER).x(100).y(100))
1748 .build());
1749 leftWindow->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_UP));
1750
1751 // Tap the window on the right
1752 mDispatcher->notifyMotion(
1753 MotionArgsBuilder(AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
1754 .deviceId(touchDeviceId)
1755 .downTime(baseTime + 60)
1756 .eventTime(baseTime + 60)
1757 .pointer(PointerBuilder(0, ToolType::FINGER).x(300).y(100))
1758 .build());
1759 rightWindow->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_DOWN));
1760
1761 // release tap
1762 mDispatcher->notifyMotion(MotionArgsBuilder(AMOTION_EVENT_ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN)
1763 .deviceId(touchDeviceId)
1764 .downTime(baseTime + 60)
1765 .eventTime(baseTime + 70)
1766 .pointer(PointerBuilder(0, ToolType::FINGER).x(300).y(100))
1767 .build());
1768 rightWindow->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_UP));
1769
1770 // No more events
1771 leftWindow->assertNoEvents();
1772 rightWindow->assertNoEvents();
1773}
1774
1775/**
Siarhei Vishniakoua235c042023-05-02 09:59:09 -07001776 * Start hovering in a window. While this hover is still active, make another window appear on top.
1777 * The top, obstructing window has no input channel, so it's not supposed to receive input.
1778 * While the top window is present, the hovering is stopped.
1779 * Later, hovering gets resumed again.
1780 * Ensure that new hover gesture is handled correctly.
1781 * This test reproduces a crash where the HOVER_EXIT event wasn't getting dispatched correctly
1782 * to the window that's currently being hovered over.
1783 */
1784TEST_F(InputDispatcherTest, HoverWhileWindowAppears) {
1785 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07001786 sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher, "Window",
1787 ui::LogicalDisplayId::DEFAULT);
Siarhei Vishniakoua235c042023-05-02 09:59:09 -07001788 window->setFrame(Rect(0, 0, 200, 200));
1789
1790 // Only a single window is present at first
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07001791 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Siarhei Vishniakoua235c042023-05-02 09:59:09 -07001792
1793 // Start hovering in the window
1794 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_ENTER, AINPUT_SOURCE_STYLUS)
1795 .pointer(PointerBuilder(0, ToolType::STYLUS).x(100).y(100))
1796 .build());
1797 window->consumeMotionEvent(WithMotionAction(ACTION_HOVER_ENTER));
1798
1799 // Now, an obscuring window appears!
1800 sp<FakeWindowHandle> obscuringWindow =
1801 sp<FakeWindowHandle>::make(application, mDispatcher, "Obscuring window",
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07001802 ui::LogicalDisplayId::DEFAULT,
Prabir Pradhane7cc69c2024-01-05 21:35:28 +00001803 /*createInputChannel=*/false);
Siarhei Vishniakoua235c042023-05-02 09:59:09 -07001804 obscuringWindow->setFrame(Rect(0, 0, 200, 200));
1805 obscuringWindow->setTouchOcclusionMode(TouchOcclusionMode::BLOCK_UNTRUSTED);
1806 obscuringWindow->setOwnerInfo(SECONDARY_WINDOW_PID, SECONDARY_WINDOW_UID);
1807 obscuringWindow->setNoInputChannel(true);
1808 obscuringWindow->setFocusable(false);
1809 obscuringWindow->setAlpha(1.0);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07001810 mDispatcher->onWindowInfosChanged(
1811 {{*obscuringWindow->getInfo(), *window->getInfo()}, {}, 0, 0});
Siarhei Vishniakoua235c042023-05-02 09:59:09 -07001812
1813 // While this new obscuring window is present, the hovering is stopped
1814 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_EXIT, AINPUT_SOURCE_STYLUS)
1815 .pointer(PointerBuilder(0, ToolType::STYLUS).x(100).y(100))
1816 .build());
1817 window->consumeMotionEvent(WithMotionAction(ACTION_HOVER_EXIT));
1818
1819 // Now the obscuring window goes away.
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07001820 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Siarhei Vishniakoua235c042023-05-02 09:59:09 -07001821
1822 // And a new hover gesture starts.
1823 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_ENTER, AINPUT_SOURCE_STYLUS)
1824 .pointer(PointerBuilder(0, ToolType::STYLUS).x(100).y(100))
1825 .build());
1826 window->consumeMotionEvent(WithMotionAction(ACTION_HOVER_ENTER));
1827}
1828
1829/**
1830 * Same test as 'HoverWhileWindowAppears' above, but here, we also send some HOVER_MOVE events to
1831 * the obscuring window.
1832 */
1833TEST_F(InputDispatcherTest, HoverMoveWhileWindowAppears) {
1834 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07001835 sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher, "Window",
1836 ui::LogicalDisplayId::DEFAULT);
Siarhei Vishniakoua235c042023-05-02 09:59:09 -07001837 window->setFrame(Rect(0, 0, 200, 200));
1838
1839 // Only a single window is present at first
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07001840 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Siarhei Vishniakoua235c042023-05-02 09:59:09 -07001841
1842 // Start hovering in the window
1843 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_ENTER, AINPUT_SOURCE_STYLUS)
1844 .pointer(PointerBuilder(0, ToolType::STYLUS).x(100).y(100))
1845 .build());
1846 window->consumeMotionEvent(WithMotionAction(ACTION_HOVER_ENTER));
1847
1848 // Now, an obscuring window appears!
1849 sp<FakeWindowHandle> obscuringWindow =
1850 sp<FakeWindowHandle>::make(application, mDispatcher, "Obscuring window",
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07001851 ui::LogicalDisplayId::DEFAULT,
Prabir Pradhane7cc69c2024-01-05 21:35:28 +00001852 /*createInputChannel=*/false);
Siarhei Vishniakoua235c042023-05-02 09:59:09 -07001853 obscuringWindow->setFrame(Rect(0, 0, 200, 200));
1854 obscuringWindow->setTouchOcclusionMode(TouchOcclusionMode::BLOCK_UNTRUSTED);
1855 obscuringWindow->setOwnerInfo(SECONDARY_WINDOW_PID, SECONDARY_WINDOW_UID);
1856 obscuringWindow->setNoInputChannel(true);
1857 obscuringWindow->setFocusable(false);
1858 obscuringWindow->setAlpha(1.0);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07001859 mDispatcher->onWindowInfosChanged(
1860 {{*obscuringWindow->getInfo(), *window->getInfo()}, {}, 0, 0});
Siarhei Vishniakoua235c042023-05-02 09:59:09 -07001861
1862 // While this new obscuring window is present, the hovering continues. The event can't go to the
1863 // bottom window due to obstructed touches, so it should generate HOVER_EXIT for that window.
1864 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_MOVE, AINPUT_SOURCE_STYLUS)
1865 .pointer(PointerBuilder(0, ToolType::STYLUS).x(100).y(100))
1866 .build());
1867 obscuringWindow->assertNoEvents();
1868 window->consumeMotionEvent(WithMotionAction(ACTION_HOVER_EXIT));
1869
1870 // Now the obscuring window goes away.
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07001871 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Siarhei Vishniakoua235c042023-05-02 09:59:09 -07001872
1873 // Hovering continues in the same position. The hovering pointer re-enters the bottom window,
1874 // so it should generate a HOVER_ENTER
1875 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_MOVE, AINPUT_SOURCE_STYLUS)
1876 .pointer(PointerBuilder(0, ToolType::STYLUS).x(100).y(100))
1877 .build());
1878 window->consumeMotionEvent(WithMotionAction(ACTION_HOVER_ENTER));
1879
1880 // Now the MOVE should be getting dispatched normally
1881 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_MOVE, AINPUT_SOURCE_STYLUS)
1882 .pointer(PointerBuilder(0, ToolType::STYLUS).x(110).y(110))
1883 .build());
1884 window->consumeMotionEvent(WithMotionAction(ACTION_HOVER_MOVE));
1885}
1886
1887/**
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -07001888 * Hover mouse over a window, and then send ACTION_SCROLL. Ensure both the hover and the scroll
1889 * events are delivered to the window.
1890 */
1891TEST_F(InputDispatcherTest, HoverMoveAndScroll) {
1892 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07001893 sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher, "Window",
1894 ui::LogicalDisplayId::DEFAULT);
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -07001895 window->setFrame(Rect(0, 0, 200, 200));
1896 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
1897
1898 // Start hovering in the window
1899 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_ENTER, AINPUT_SOURCE_MOUSE)
1900 .pointer(PointerBuilder(0, ToolType::MOUSE).x(100).y(110))
1901 .build());
1902 window->consumeMotionEvent(WithMotionAction(ACTION_HOVER_ENTER));
1903
1904 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_MOVE, AINPUT_SOURCE_MOUSE)
1905 .pointer(PointerBuilder(0, ToolType::MOUSE).x(110).y(120))
1906 .build());
1907 window->consumeMotionEvent(WithMotionAction(ACTION_HOVER_MOVE));
1908
1909 // Scroll with the mouse
1910 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_SCROLL, AINPUT_SOURCE_MOUSE)
1911 .pointer(PointerBuilder(0, ToolType::MOUSE).x(110).y(120))
1912 .build());
1913 window->consumeMotionEvent(WithMotionAction(ACTION_SCROLL));
1914}
1915
Siarhei Vishniakoub711e652024-08-12 12:00:28 -07001916/**
1917 * Two windows: a trusted overlay and a regular window underneath. Both windows are visible.
1918 * Mouse is hovered, and the hover event should only go to the overlay.
1919 * However, next, the touchable region of the trusted overlay shrinks. The mouse position hasn't
1920 * changed, but the cursor would now end up hovering above the regular window underneatch.
1921 * If the mouse is now clicked, this would generate an ACTION_DOWN event, which would go to the
1922 * regular window. However, the trusted overlay is also watching for outside touch.
1923 * The trusted overlay should get two events:
1924 * 1) The ACTION_OUTSIDE event, since the click is now not inside its touchable region
1925 * 2) The HOVER_EXIT event, since the mouse pointer is no longer hovering inside this window
1926 *
1927 * This test reproduces a crash where there is an overlap between dispatch modes for the trusted
1928 * overlay touch target, since the event is causing both an ACTION_OUTSIDE, and as a HOVER_EXIT.
1929 */
1930TEST_F(InputDispatcherTest, MouseClickUnderShrinkingTrustedOverlay) {
1931 std::shared_ptr<FakeApplicationHandle> app = std::make_shared<FakeApplicationHandle>();
1932 sp<FakeWindowHandle> overlay = sp<FakeWindowHandle>::make(app, mDispatcher, "Trusted overlay",
1933 ui::LogicalDisplayId::DEFAULT);
1934 overlay->setTrustedOverlay(true);
1935 overlay->setWatchOutsideTouch(true);
1936 overlay->setFrame(Rect(0, 0, 200, 200));
1937
1938 sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(app, mDispatcher, "Regular window",
1939 ui::LogicalDisplayId::DEFAULT);
1940 window->setFrame(Rect(0, 0, 200, 200));
1941
1942 mDispatcher->onWindowInfosChanged({{*overlay->getInfo(), *window->getInfo()}, {}, 0, 0});
1943 // Hover the mouse into the overlay
1944 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_MOVE, AINPUT_SOURCE_MOUSE)
1945 .pointer(PointerBuilder(0, ToolType::MOUSE).x(100).y(110))
1946 .build());
1947 overlay->consumeMotionEvent(WithMotionAction(ACTION_HOVER_ENTER));
1948
1949 // Now, shrink the touchable region of the overlay! This will cause the cursor to suddenly have
1950 // the regular window as the touch target
1951 overlay->setTouchableRegion(Region({0, 0, 0, 0}));
1952 mDispatcher->onWindowInfosChanged({{*overlay->getInfo(), *window->getInfo()}, {}, 0, 0});
1953
1954 // Now we can click with the mouse. The click should go into the regular window
1955 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_MOUSE)
1956 .pointer(PointerBuilder(0, ToolType::MOUSE).x(100).y(110))
1957 .build());
1958 overlay->consumeMotionEvent(WithMotionAction(ACTION_HOVER_EXIT));
1959 overlay->consumeMotionEvent(WithMotionAction(ACTION_OUTSIDE));
1960 window->consumeMotionEvent(WithMotionAction(ACTION_DOWN));
1961}
1962
1963/**
1964 * Similar to above, but also has a spy on top that also catches the HOVER
1965 * events. Also, instead of ACTION_DOWN, we are continuing to send the hovering
1966 * stream to ensure that the spy receives hover events correctly.
1967 */
1968TEST_F(InputDispatcherTest, MouseClickUnderShrinkingTrustedOverlayWithSpy) {
1969 std::shared_ptr<FakeApplicationHandle> app = std::make_shared<FakeApplicationHandle>();
1970 sp<FakeWindowHandle> spyWindow =
1971 sp<FakeWindowHandle>::make(app, mDispatcher, "Spy", ui::LogicalDisplayId::DEFAULT);
1972 spyWindow->setFrame(Rect(0, 0, 200, 200));
1973 spyWindow->setTrustedOverlay(true);
1974 spyWindow->setSpy(true);
1975 sp<FakeWindowHandle> overlay = sp<FakeWindowHandle>::make(app, mDispatcher, "Trusted overlay",
1976 ui::LogicalDisplayId::DEFAULT);
1977 overlay->setTrustedOverlay(true);
1978 overlay->setWatchOutsideTouch(true);
1979 overlay->setFrame(Rect(0, 0, 200, 200));
1980
1981 sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(app, mDispatcher, "Regular window",
1982 ui::LogicalDisplayId::DEFAULT);
1983 window->setFrame(Rect(0, 0, 200, 200));
1984
1985 mDispatcher->onWindowInfosChanged(
1986 {{*spyWindow->getInfo(), *overlay->getInfo(), *window->getInfo()}, {}, 0, 0});
1987 // Hover the mouse into the overlay
1988 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_MOVE, AINPUT_SOURCE_MOUSE)
1989 .pointer(PointerBuilder(0, ToolType::MOUSE).x(100).y(110))
1990 .build());
1991 spyWindow->consumeMotionEvent(WithMotionAction(ACTION_HOVER_ENTER));
1992 overlay->consumeMotionEvent(WithMotionAction(ACTION_HOVER_ENTER));
1993
1994 // Now, shrink the touchable region of the overlay! This will cause the cursor to suddenly have
1995 // the regular window as the touch target
1996 overlay->setTouchableRegion(Region({0, 0, 0, 0}));
1997 mDispatcher->onWindowInfosChanged(
1998 {{*spyWindow->getInfo(), *overlay->getInfo(), *window->getInfo()}, {}, 0, 0});
1999
2000 // Now we can click with the mouse. The click should go into the regular window
2001 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_MOVE, AINPUT_SOURCE_MOUSE)
2002 .pointer(PointerBuilder(0, ToolType::MOUSE).x(110).y(110))
2003 .build());
2004 spyWindow->consumeMotionEvent(WithMotionAction(ACTION_HOVER_MOVE));
2005 overlay->consumeMotionEvent(WithMotionAction(ACTION_HOVER_EXIT));
2006 window->consumeMotionEvent(WithMotionAction(ACTION_HOVER_ENTER));
2007}
2008
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -07002009using InputDispatcherMultiDeviceTest = InputDispatcherTest;
2010
2011/**
Siarhei Vishniakou2899c552023-07-10 18:20:46 -07002012 * One window. Stylus down on the window. Next, touch from another device goes down. Ensure that
2013 * touch is dropped, because stylus should be preferred over touch.
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -07002014 */
Siarhei Vishniakou2899c552023-07-10 18:20:46 -07002015TEST_F(InputDispatcherMultiDeviceTest, StylusDownBlocksTouchDown) {
Siarhei Vishniakoued89cbb2023-10-13 10:42:44 -07002016 SCOPED_FLAG_OVERRIDE(enable_multi_device_same_window_stream, false);
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -07002017 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07002018 sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher, "Window",
2019 ui::LogicalDisplayId::DEFAULT);
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -07002020 window->setFrame(Rect(0, 0, 200, 200));
2021
2022 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
2023
2024 constexpr int32_t touchDeviceId = 4;
2025 constexpr int32_t stylusDeviceId = 2;
2026
2027 // Stylus down
2028 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_STYLUS)
2029 .deviceId(stylusDeviceId)
2030 .pointer(PointerBuilder(0, ToolType::STYLUS).x(100).y(110))
2031 .build());
2032 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(stylusDeviceId)));
2033
2034 // Touch down
2035 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
2036 .deviceId(touchDeviceId)
2037 .pointer(PointerBuilder(0, ToolType::FINGER).x(140).y(145))
2038 .build());
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -07002039
2040 // Touch move
2041 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN)
2042 .deviceId(touchDeviceId)
2043 .pointer(PointerBuilder(0, ToolType::FINGER).x(141).y(146))
2044 .build());
Siarhei Vishniakou2899c552023-07-10 18:20:46 -07002045 // Touch is ignored because stylus is already down
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -07002046
Siarhei Vishniakou2899c552023-07-10 18:20:46 -07002047 // Subsequent stylus movements are delivered correctly
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -07002048 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_STYLUS)
2049 .deviceId(stylusDeviceId)
2050 .pointer(PointerBuilder(0, ToolType::STYLUS).x(101).y(111))
2051 .build());
Siarhei Vishniakou2899c552023-07-10 18:20:46 -07002052 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(stylusDeviceId),
2053 WithCoords(101, 111)));
2054
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -07002055 window->assertNoEvents();
2056}
2057
2058/**
Siarhei Vishniakoued89cbb2023-10-13 10:42:44 -07002059 * One window. Stylus down on the window. Next, touch from another device goes down. Ensure that
2060 * touch is not dropped, because multiple devices are allowed to be active in the same window.
2061 */
2062TEST_F(InputDispatcherMultiDeviceTest, StylusDownDoesNotBlockTouchDown) {
2063 SCOPED_FLAG_OVERRIDE(enable_multi_device_same_window_stream, true);
2064 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07002065 sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher, "Window",
2066 ui::LogicalDisplayId::DEFAULT);
Siarhei Vishniakoued89cbb2023-10-13 10:42:44 -07002067 window->setFrame(Rect(0, 0, 200, 200));
2068
2069 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
2070
2071 constexpr int32_t touchDeviceId = 4;
2072 constexpr int32_t stylusDeviceId = 2;
2073
2074 // Stylus down
2075 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_STYLUS)
2076 .deviceId(stylusDeviceId)
2077 .pointer(PointerBuilder(0, ToolType::STYLUS).x(100).y(110))
2078 .build());
2079 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(stylusDeviceId)));
2080
2081 // Touch down
2082 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
2083 .deviceId(touchDeviceId)
2084 .pointer(PointerBuilder(0, ToolType::FINGER).x(140).y(145))
2085 .build());
2086 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(touchDeviceId)));
2087
2088 // Touch move
2089 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN)
2090 .deviceId(touchDeviceId)
2091 .pointer(PointerBuilder(0, ToolType::FINGER).x(141).y(146))
2092 .build());
2093 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(touchDeviceId)));
2094
2095 // Stylus move
2096 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_STYLUS)
2097 .deviceId(stylusDeviceId)
2098 .pointer(PointerBuilder(0, ToolType::STYLUS).x(101).y(111))
2099 .build());
2100 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(stylusDeviceId),
2101 WithCoords(101, 111)));
2102
2103 window->assertNoEvents();
2104}
2105
2106/**
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -07002107 * One window and one spy window. Stylus down on the window. Next, touch from another device goes
Siarhei Vishniakou2899c552023-07-10 18:20:46 -07002108 * down. Ensure that touch is dropped, because stylus should be preferred over touch.
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -07002109 * Similar test as above, but with added SPY window.
2110 */
Siarhei Vishniakou2899c552023-07-10 18:20:46 -07002111TEST_F(InputDispatcherMultiDeviceTest, StylusDownWithSpyBlocksTouchDown) {
Siarhei Vishniakoued89cbb2023-10-13 10:42:44 -07002112 SCOPED_FLAG_OVERRIDE(enable_multi_device_same_window_stream, false);
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -07002113 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07002114 sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher, "Window",
2115 ui::LogicalDisplayId::DEFAULT);
2116 sp<FakeWindowHandle> spyWindow = sp<FakeWindowHandle>::make(application, mDispatcher, "Spy",
2117 ui::LogicalDisplayId::DEFAULT);
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -07002118 spyWindow->setFrame(Rect(0, 0, 200, 200));
2119 spyWindow->setTrustedOverlay(true);
2120 spyWindow->setSpy(true);
2121 window->setFrame(Rect(0, 0, 200, 200));
2122
2123 mDispatcher->onWindowInfosChanged({{*spyWindow->getInfo(), *window->getInfo()}, {}, 0, 0});
2124
2125 constexpr int32_t touchDeviceId = 4;
2126 constexpr int32_t stylusDeviceId = 2;
2127
2128 // Stylus down
2129 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_STYLUS)
2130 .deviceId(stylusDeviceId)
2131 .pointer(PointerBuilder(0, ToolType::STYLUS).x(100).y(110))
2132 .build());
2133 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(stylusDeviceId)));
2134 spyWindow->consumeMotionEvent(
2135 AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(stylusDeviceId)));
2136
2137 // Touch down
2138 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
2139 .deviceId(touchDeviceId)
2140 .pointer(PointerBuilder(0, ToolType::FINGER).x(140).y(145))
2141 .build());
2142
2143 // Touch move
2144 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN)
2145 .deviceId(touchDeviceId)
2146 .pointer(PointerBuilder(0, ToolType::FINGER).x(141).y(146))
2147 .build());
Siarhei Vishniakou2899c552023-07-10 18:20:46 -07002148
2149 // Touch is ignored because stylus is already down
2150
2151 // Subsequent stylus movements are delivered correctly
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -07002152 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_STYLUS)
2153 .deviceId(stylusDeviceId)
2154 .pointer(PointerBuilder(0, ToolType::STYLUS).x(101).y(111))
2155 .build());
Siarhei Vishniakou2899c552023-07-10 18:20:46 -07002156 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(stylusDeviceId),
2157 WithCoords(101, 111)));
2158 spyWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(stylusDeviceId),
2159 WithCoords(101, 111)));
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -07002160
2161 window->assertNoEvents();
2162 spyWindow->assertNoEvents();
2163}
2164
2165/**
Siarhei Vishniakoued89cbb2023-10-13 10:42:44 -07002166 * One window and one spy window. Stylus down on the window. Next, touch from another device goes
2167 * down. Ensure that touch is not dropped, because multiple devices can be active at the same time.
2168 * Similar test as above, but with added SPY window.
2169 */
2170TEST_F(InputDispatcherMultiDeviceTest, StylusDownWithSpyDoesNotBlockTouchDown) {
2171 SCOPED_FLAG_OVERRIDE(enable_multi_device_same_window_stream, true);
2172 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07002173 sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher, "Window",
2174 ui::LogicalDisplayId::DEFAULT);
2175 sp<FakeWindowHandle> spyWindow = sp<FakeWindowHandle>::make(application, mDispatcher, "Spy",
2176 ui::LogicalDisplayId::DEFAULT);
Siarhei Vishniakoued89cbb2023-10-13 10:42:44 -07002177 spyWindow->setFrame(Rect(0, 0, 200, 200));
2178 spyWindow->setTrustedOverlay(true);
2179 spyWindow->setSpy(true);
2180 window->setFrame(Rect(0, 0, 200, 200));
2181
2182 mDispatcher->onWindowInfosChanged({{*spyWindow->getInfo(), *window->getInfo()}, {}, 0, 0});
2183
2184 constexpr int32_t touchDeviceId = 4;
2185 constexpr int32_t stylusDeviceId = 2;
2186
2187 // Stylus down
2188 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_STYLUS)
2189 .deviceId(stylusDeviceId)
2190 .pointer(PointerBuilder(0, ToolType::STYLUS).x(100).y(110))
2191 .build());
2192 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(stylusDeviceId)));
2193 spyWindow->consumeMotionEvent(
2194 AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(stylusDeviceId)));
2195
2196 // Touch down
2197 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
2198 .deviceId(touchDeviceId)
2199 .pointer(PointerBuilder(0, ToolType::FINGER).x(140).y(145))
2200 .build());
2201 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(touchDeviceId)));
2202 spyWindow->consumeMotionEvent(
2203 AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(touchDeviceId)));
2204
2205 // Touch move
2206 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN)
2207 .deviceId(touchDeviceId)
2208 .pointer(PointerBuilder(0, ToolType::FINGER).x(141).y(146))
2209 .build());
2210 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(touchDeviceId)));
2211 spyWindow->consumeMotionEvent(
2212 AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(touchDeviceId)));
2213
2214 // Subsequent stylus movements are delivered correctly
2215 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_STYLUS)
2216 .deviceId(stylusDeviceId)
2217 .pointer(PointerBuilder(0, ToolType::STYLUS).x(101).y(111))
2218 .build());
2219 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(stylusDeviceId),
2220 WithCoords(101, 111)));
2221 spyWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(stylusDeviceId),
2222 WithCoords(101, 111)));
2223
2224 window->assertNoEvents();
2225 spyWindow->assertNoEvents();
2226}
2227
2228/**
Siarhei Vishniakou2899c552023-07-10 18:20:46 -07002229 * One window. Stylus hover on the window. Next, touch from another device goes down. Ensure that
Siarhei Vishniakou3ad54f52023-11-02 16:54:40 -07002230 * touch is dropped, because stylus hover takes precedence.
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -07002231 */
Siarhei Vishniakou3ad54f52023-11-02 16:54:40 -07002232TEST_F(InputDispatcherMultiDeviceTest, StylusHoverBlocksTouchDown) {
Siarhei Vishniakoued89cbb2023-10-13 10:42:44 -07002233 SCOPED_FLAG_OVERRIDE(enable_multi_device_same_window_stream, false);
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -07002234 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07002235 sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher, "Window",
2236 ui::LogicalDisplayId::DEFAULT);
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -07002237 window->setFrame(Rect(0, 0, 200, 200));
2238
2239 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
2240
2241 constexpr int32_t touchDeviceId = 4;
2242 constexpr int32_t stylusDeviceId = 2;
2243
2244 // Stylus down on the window
2245 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_ENTER, AINPUT_SOURCE_STYLUS)
2246 .deviceId(stylusDeviceId)
2247 .pointer(PointerBuilder(0, ToolType::STYLUS).x(100).y(110))
2248 .build());
2249 window->consumeMotionEvent(
2250 AllOf(WithMotionAction(ACTION_HOVER_ENTER), WithDeviceId(stylusDeviceId)));
2251
2252 // Touch down on window
2253 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
2254 .deviceId(touchDeviceId)
2255 .pointer(PointerBuilder(0, ToolType::FINGER).x(140).y(145))
2256 .build());
2257 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN)
2258 .deviceId(touchDeviceId)
2259 .pointer(PointerBuilder(0, ToolType::FINGER).x(141).y(146))
2260 .build());
Siarhei Vishniakou2899c552023-07-10 18:20:46 -07002261
Siarhei Vishniakou3ad54f52023-11-02 16:54:40 -07002262 // Touch is ignored because stylus is hovering
Siarhei Vishniakou2899c552023-07-10 18:20:46 -07002263
Siarhei Vishniakou3ad54f52023-11-02 16:54:40 -07002264 // Subsequent stylus movements are delivered correctly
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -07002265 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_MOVE, AINPUT_SOURCE_STYLUS)
2266 .deviceId(stylusDeviceId)
2267 .pointer(PointerBuilder(0, ToolType::STYLUS).x(101).y(111))
2268 .build());
Siarhei Vishniakou3ad54f52023-11-02 16:54:40 -07002269 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_HOVER_MOVE),
2270 WithDeviceId(stylusDeviceId), WithCoords(101, 111)));
Siarhei Vishniakou2899c552023-07-10 18:20:46 -07002271
Siarhei Vishniakou3ad54f52023-11-02 16:54:40 -07002272 // and subsequent touches continue to be ignored
Siarhei Vishniakou2899c552023-07-10 18:20:46 -07002273 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN)
2274 .deviceId(touchDeviceId)
2275 .pointer(PointerBuilder(0, ToolType::FINGER).x(142).y(147))
2276 .build());
Siarhei Vishniakou3ad54f52023-11-02 16:54:40 -07002277 window->assertNoEvents();
Siarhei Vishniakou2899c552023-07-10 18:20:46 -07002278}
2279
2280/**
Siarhei Vishniakoued89cbb2023-10-13 10:42:44 -07002281 * One window. Stylus hover on the window. Next, touch from another device goes down. Ensure that
2282 * touch is not dropped, because stylus hover and touch can be both active at the same time.
2283 */
2284TEST_F(InputDispatcherMultiDeviceTest, StylusHoverDoesNotBlockTouchDown) {
2285 SCOPED_FLAG_OVERRIDE(enable_multi_device_same_window_stream, true);
2286 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07002287 sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher, "Window",
2288 ui::LogicalDisplayId::DEFAULT);
Siarhei Vishniakoued89cbb2023-10-13 10:42:44 -07002289 window->setFrame(Rect(0, 0, 200, 200));
2290
2291 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
2292
2293 constexpr int32_t touchDeviceId = 4;
2294 constexpr int32_t stylusDeviceId = 2;
2295
2296 // Stylus down on the window
2297 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_ENTER, AINPUT_SOURCE_STYLUS)
2298 .deviceId(stylusDeviceId)
2299 .pointer(PointerBuilder(0, ToolType::STYLUS).x(100).y(110))
2300 .build());
2301 window->consumeMotionEvent(
2302 AllOf(WithMotionAction(ACTION_HOVER_ENTER), WithDeviceId(stylusDeviceId)));
2303
2304 // Touch down on window
2305 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
2306 .deviceId(touchDeviceId)
2307 .pointer(PointerBuilder(0, ToolType::FINGER).x(140).y(145))
2308 .build());
2309 // Touch move on window
2310 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(touchDeviceId)));
2311 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN)
2312 .deviceId(touchDeviceId)
2313 .pointer(PointerBuilder(0, ToolType::FINGER).x(141).y(146))
2314 .build());
2315 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(touchDeviceId)));
2316
2317 // Subsequent stylus movements are delivered correctly
2318 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_MOVE, AINPUT_SOURCE_STYLUS)
2319 .deviceId(stylusDeviceId)
2320 .pointer(PointerBuilder(0, ToolType::STYLUS).x(101).y(111))
2321 .build());
2322 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_HOVER_MOVE),
2323 WithDeviceId(stylusDeviceId), WithCoords(101, 111)));
2324
2325 // and subsequent touches continue to work
2326 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN)
2327 .deviceId(touchDeviceId)
2328 .pointer(PointerBuilder(0, ToolType::FINGER).x(142).y(147))
2329 .build());
2330 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(touchDeviceId)));
2331 window->assertNoEvents();
2332}
2333
2334/**
Siarhei Vishniakou2899c552023-07-10 18:20:46 -07002335 * One window. Touch down on the window. Then, stylus hover on the window from another device.
Siarhei Vishniakou3ad54f52023-11-02 16:54:40 -07002336 * Ensure that touch is canceled, because stylus hover should take precedence.
Siarhei Vishniakou2899c552023-07-10 18:20:46 -07002337 */
Siarhei Vishniakou3ad54f52023-11-02 16:54:40 -07002338TEST_F(InputDispatcherMultiDeviceTest, TouchIsCanceledByStylusHover) {
Siarhei Vishniakoued89cbb2023-10-13 10:42:44 -07002339 SCOPED_FLAG_OVERRIDE(enable_multi_device_same_window_stream, false);
Siarhei Vishniakou2899c552023-07-10 18:20:46 -07002340 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07002341 sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher, "Window",
2342 ui::LogicalDisplayId::DEFAULT);
Siarhei Vishniakou2899c552023-07-10 18:20:46 -07002343 window->setFrame(Rect(0, 0, 200, 200));
2344
2345 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
2346
2347 constexpr int32_t touchDeviceId = 4;
2348 constexpr int32_t stylusDeviceId = 2;
2349
2350 // Touch down on window
2351 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
2352 .deviceId(touchDeviceId)
2353 .pointer(PointerBuilder(0, ToolType::FINGER).x(140).y(145))
2354 .build());
2355 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN)
2356 .deviceId(touchDeviceId)
2357 .pointer(PointerBuilder(0, ToolType::FINGER).x(141).y(146))
2358 .build());
2359 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(touchDeviceId)));
2360 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(touchDeviceId)));
2361
2362 // Stylus hover on the window
2363 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_ENTER, AINPUT_SOURCE_STYLUS)
2364 .deviceId(stylusDeviceId)
2365 .pointer(PointerBuilder(0, ToolType::STYLUS).x(100).y(110))
2366 .build());
2367 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_MOVE, AINPUT_SOURCE_STYLUS)
2368 .deviceId(stylusDeviceId)
2369 .pointer(PointerBuilder(0, ToolType::STYLUS).x(101).y(111))
2370 .build());
Siarhei Vishniakou3ad54f52023-11-02 16:54:40 -07002371 // Stylus hover movement causes touch to be canceled
2372 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_CANCEL), WithDeviceId(touchDeviceId),
2373 WithCoords(141, 146)));
2374 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_HOVER_ENTER),
2375 WithDeviceId(stylusDeviceId), WithCoords(100, 110)));
2376 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_HOVER_MOVE),
2377 WithDeviceId(stylusDeviceId), WithCoords(101, 111)));
Siarhei Vishniakou2899c552023-07-10 18:20:46 -07002378
Siarhei Vishniakou3ad54f52023-11-02 16:54:40 -07002379 // Subsequent touch movements are ignored
Siarhei Vishniakou2899c552023-07-10 18:20:46 -07002380 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN)
2381 .deviceId(touchDeviceId)
2382 .pointer(PointerBuilder(0, ToolType::FINGER).x(142).y(147))
2383 .build());
Siarhei Vishniakou3ad54f52023-11-02 16:54:40 -07002384
2385 window->assertNoEvents();
Siarhei Vishniakou2899c552023-07-10 18:20:46 -07002386}
2387
2388/**
Siarhei Vishniakoued89cbb2023-10-13 10:42:44 -07002389 * One window. Touch down on the window. Then, stylus hover on the window from another device.
2390 * Ensure that touch is not canceled, because stylus hover can be active at the same time as touch.
2391 */
2392TEST_F(InputDispatcherMultiDeviceTest, TouchIsNotCanceledByStylusHover) {
2393 SCOPED_FLAG_OVERRIDE(enable_multi_device_same_window_stream, true);
2394 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07002395 sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher, "Window",
2396 ui::LogicalDisplayId::DEFAULT);
Siarhei Vishniakoued89cbb2023-10-13 10:42:44 -07002397 window->setFrame(Rect(0, 0, 200, 200));
2398
2399 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
2400
2401 constexpr int32_t touchDeviceId = 4;
2402 constexpr int32_t stylusDeviceId = 2;
2403
2404 // Touch down on window
2405 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
2406 .deviceId(touchDeviceId)
2407 .pointer(PointerBuilder(0, ToolType::FINGER).x(140).y(145))
2408 .build());
2409 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN)
2410 .deviceId(touchDeviceId)
2411 .pointer(PointerBuilder(0, ToolType::FINGER).x(141).y(146))
2412 .build());
2413 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(touchDeviceId)));
2414 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(touchDeviceId)));
2415
2416 // Stylus hover on the window
2417 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_ENTER, AINPUT_SOURCE_STYLUS)
2418 .deviceId(stylusDeviceId)
2419 .pointer(PointerBuilder(0, ToolType::STYLUS).x(100).y(110))
2420 .build());
2421 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_MOVE, AINPUT_SOURCE_STYLUS)
2422 .deviceId(stylusDeviceId)
2423 .pointer(PointerBuilder(0, ToolType::STYLUS).x(101).y(111))
2424 .build());
2425 // Stylus hover movement is received normally
2426 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_HOVER_ENTER),
2427 WithDeviceId(stylusDeviceId), WithCoords(100, 110)));
2428 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_HOVER_MOVE),
2429 WithDeviceId(stylusDeviceId), WithCoords(101, 111)));
2430
2431 // Subsequent touch movements also work
2432 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN)
2433 .deviceId(touchDeviceId)
2434 .pointer(PointerBuilder(0, ToolType::FINGER).x(142).y(147))
2435 .build());
2436 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(touchDeviceId),
2437 WithCoords(142, 147)));
2438
2439 window->assertNoEvents();
2440}
2441
2442/**
Siarhei Vishniakou2899c552023-07-10 18:20:46 -07002443 * One window. Stylus down on the window. Then, stylus from another device goes down. Ensure that
2444 * the latest stylus takes over. That is, old stylus should be canceled and the new stylus should
2445 * become active.
2446 */
2447TEST_F(InputDispatcherMultiDeviceTest, LatestStylusWins) {
Siarhei Vishniakoued89cbb2023-10-13 10:42:44 -07002448 SCOPED_FLAG_OVERRIDE(enable_multi_device_same_window_stream, false);
Siarhei Vishniakou2899c552023-07-10 18:20:46 -07002449 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07002450 sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher, "Window",
2451 ui::LogicalDisplayId::DEFAULT);
Siarhei Vishniakou2899c552023-07-10 18:20:46 -07002452 window->setFrame(Rect(0, 0, 200, 200));
2453
2454 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
2455
2456 constexpr int32_t stylusDeviceId1 = 3;
2457 constexpr int32_t stylusDeviceId2 = 5;
2458
2459 // Touch down on window
2460 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_STYLUS)
2461 .deviceId(stylusDeviceId1)
2462 .pointer(PointerBuilder(0, ToolType::STYLUS).x(99).y(100))
2463 .build());
2464 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_STYLUS)
2465 .deviceId(stylusDeviceId1)
2466 .pointer(PointerBuilder(0, ToolType::STYLUS).x(100).y(101))
2467 .build());
2468 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(stylusDeviceId1)));
2469 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(stylusDeviceId1)));
2470
2471 // Second stylus down
2472 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_STYLUS)
2473 .deviceId(stylusDeviceId2)
2474 .pointer(PointerBuilder(0, ToolType::STYLUS).x(9).y(10))
2475 .build());
2476 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_STYLUS)
2477 .deviceId(stylusDeviceId2)
2478 .pointer(PointerBuilder(0, ToolType::STYLUS).x(10).y(11))
2479 .build());
2480
2481 // First stylus is canceled, second one takes over.
2482 window->consumeMotionEvent(
2483 AllOf(WithMotionAction(ACTION_CANCEL), WithDeviceId(stylusDeviceId1)));
2484 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(stylusDeviceId2)));
2485 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(stylusDeviceId2)));
2486
2487 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_STYLUS)
2488 .deviceId(stylusDeviceId1)
2489 .pointer(PointerBuilder(0, ToolType::STYLUS).x(101).y(102))
2490 .build());
2491 // Subsequent stylus movements are delivered correctly
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -07002492 window->assertNoEvents();
2493}
2494
2495/**
Siarhei Vishniakoued89cbb2023-10-13 10:42:44 -07002496 * One window. Stylus down on the window. Then, stylus from another device goes down. Ensure that
2497 * both stylus devices can function simultaneously.
2498 */
2499TEST_F(InputDispatcherMultiDeviceTest, TwoStylusDevicesActiveAtTheSameTime) {
2500 SCOPED_FLAG_OVERRIDE(enable_multi_device_same_window_stream, true);
2501 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07002502 sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher, "Window",
2503 ui::LogicalDisplayId::DEFAULT);
Siarhei Vishniakoued89cbb2023-10-13 10:42:44 -07002504 window->setFrame(Rect(0, 0, 200, 200));
2505
2506 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
2507
2508 constexpr int32_t stylusDeviceId1 = 3;
2509 constexpr int32_t stylusDeviceId2 = 5;
2510
2511 // Touch down on window
2512 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_STYLUS)
2513 .deviceId(stylusDeviceId1)
2514 .pointer(PointerBuilder(0, ToolType::STYLUS).x(99).y(100))
2515 .build());
2516 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_STYLUS)
2517 .deviceId(stylusDeviceId1)
2518 .pointer(PointerBuilder(0, ToolType::STYLUS).x(100).y(101))
2519 .build());
2520 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(stylusDeviceId1)));
2521 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(stylusDeviceId1)));
2522
2523 // Second stylus down
2524 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_STYLUS)
2525 .deviceId(stylusDeviceId2)
2526 .pointer(PointerBuilder(0, ToolType::STYLUS).x(9).y(10))
2527 .build());
2528 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_STYLUS)
2529 .deviceId(stylusDeviceId2)
2530 .pointer(PointerBuilder(0, ToolType::STYLUS).x(10).y(11))
2531 .build());
2532 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(stylusDeviceId2)));
2533 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(stylusDeviceId2)));
2534
2535 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_STYLUS)
2536 .deviceId(stylusDeviceId1)
2537 .pointer(PointerBuilder(0, ToolType::STYLUS).x(101).y(102))
2538 .build());
2539 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(stylusDeviceId1)));
2540 window->assertNoEvents();
2541}
2542
2543/**
Siarhei Vishniakou2899c552023-07-10 18:20:46 -07002544 * One window. Touch down on the window. Then, stylus down on the window from another device.
2545 * Ensure that is canceled, because stylus down should be preferred over touch.
2546 */
2547TEST_F(InputDispatcherMultiDeviceTest, TouchIsCanceledByStylusDown) {
Siarhei Vishniakoued89cbb2023-10-13 10:42:44 -07002548 SCOPED_FLAG_OVERRIDE(enable_multi_device_same_window_stream, false);
Siarhei Vishniakou2899c552023-07-10 18:20:46 -07002549 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07002550 sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher, "Window",
2551 ui::LogicalDisplayId::DEFAULT);
Siarhei Vishniakou2899c552023-07-10 18:20:46 -07002552 window->setFrame(Rect(0, 0, 200, 200));
2553
2554 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
2555
2556 constexpr int32_t touchDeviceId = 4;
2557 constexpr int32_t stylusDeviceId = 2;
2558
2559 // Touch down on window
2560 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
2561 .deviceId(touchDeviceId)
2562 .pointer(PointerBuilder(0, ToolType::FINGER).x(140).y(145))
2563 .build());
2564 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN)
2565 .deviceId(touchDeviceId)
2566 .pointer(PointerBuilder(0, ToolType::FINGER).x(141).y(146))
2567 .build());
2568 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(touchDeviceId)));
2569 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(touchDeviceId)));
2570
2571 // Stylus down on the window
2572 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_STYLUS)
2573 .deviceId(stylusDeviceId)
2574 .pointer(PointerBuilder(0, ToolType::STYLUS).x(100).y(110))
2575 .build());
2576 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_CANCEL), WithDeviceId(touchDeviceId)));
2577 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(stylusDeviceId)));
2578
2579 // Subsequent stylus movements are delivered correctly
2580 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_STYLUS)
2581 .deviceId(stylusDeviceId)
2582 .pointer(PointerBuilder(0, ToolType::STYLUS).x(101).y(111))
2583 .build());
2584 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(stylusDeviceId),
2585 WithCoords(101, 111)));
2586}
2587
2588/**
Siarhei Vishniakoued89cbb2023-10-13 10:42:44 -07002589 * One window. Touch down on the window. Then, stylus down on the window from another device.
2590 * Ensure that both touch and stylus are functioning independently.
2591 */
2592TEST_F(InputDispatcherMultiDeviceTest, TouchIsNotCanceledByStylusDown) {
2593 SCOPED_FLAG_OVERRIDE(enable_multi_device_same_window_stream, true);
2594 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07002595 sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher, "Window",
2596 ui::LogicalDisplayId::DEFAULT);
Siarhei Vishniakoued89cbb2023-10-13 10:42:44 -07002597 window->setFrame(Rect(0, 0, 200, 200));
2598
2599 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
2600
2601 constexpr int32_t touchDeviceId = 4;
2602 constexpr int32_t stylusDeviceId = 2;
2603
2604 // Touch down on window
2605 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
2606 .deviceId(touchDeviceId)
2607 .pointer(PointerBuilder(0, ToolType::FINGER).x(140).y(145))
2608 .build());
2609 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN)
2610 .deviceId(touchDeviceId)
2611 .pointer(PointerBuilder(0, ToolType::FINGER).x(141).y(146))
2612 .build());
2613 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(touchDeviceId)));
2614 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(touchDeviceId)));
2615
2616 // Stylus down on the window
2617 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_STYLUS)
2618 .deviceId(stylusDeviceId)
2619 .pointer(PointerBuilder(0, ToolType::STYLUS).x(100).y(110))
2620 .build());
2621 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(stylusDeviceId)));
2622
2623 // Subsequent stylus movements are delivered correctly
2624 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_STYLUS)
2625 .deviceId(stylusDeviceId)
2626 .pointer(PointerBuilder(0, ToolType::STYLUS).x(101).y(111))
2627 .build());
2628 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(stylusDeviceId),
2629 WithCoords(101, 111)));
2630
2631 // Touch continues to work too
2632 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN)
2633 .deviceId(touchDeviceId)
2634 .pointer(PointerBuilder(0, ToolType::FINGER).x(148).y(149))
2635 .build());
2636 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(touchDeviceId)));
2637}
2638
2639/**
Siarhei Vishniakouf372b812023-02-14 18:06:51 -08002640 * Two windows: a window on the left and a window on the right.
2641 * Mouse is clicked on the left window and remains down. Touch is touched on the right and remains
2642 * down. Then, on the left window, also place second touch pointer down.
2643 * This test tries to reproduce a crash.
2644 * In the buggy implementation, second pointer down on the left window would cause a crash.
2645 */
Siarhei Vishniakoued89cbb2023-10-13 10:42:44 -07002646TEST_F(InputDispatcherMultiDeviceTest, MultiDeviceSplitTouch_legacy) {
2647 SCOPED_FLAG_OVERRIDE(enable_multi_device_same_window_stream, false);
Siarhei Vishniakouf372b812023-02-14 18:06:51 -08002648 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07002649 sp<FakeWindowHandle> leftWindow = sp<FakeWindowHandle>::make(application, mDispatcher, "Left",
2650 ui::LogicalDisplayId::DEFAULT);
Siarhei Vishniakouf372b812023-02-14 18:06:51 -08002651 leftWindow->setFrame(Rect(0, 0, 200, 200));
2652
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07002653 sp<FakeWindowHandle> rightWindow = sp<FakeWindowHandle>::make(application, mDispatcher, "Right",
2654 ui::LogicalDisplayId::DEFAULT);
Siarhei Vishniakouf372b812023-02-14 18:06:51 -08002655 rightWindow->setFrame(Rect(200, 0, 400, 200));
2656
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07002657 mDispatcher->onWindowInfosChanged(
2658 {{*leftWindow->getInfo(), *rightWindow->getInfo()}, {}, 0, 0});
Siarhei Vishniakouf372b812023-02-14 18:06:51 -08002659
2660 const int32_t touchDeviceId = 4;
2661 const int32_t mouseDeviceId = 6;
Siarhei Vishniakouf372b812023-02-14 18:06:51 -08002662
2663 // Start hovering over the left window
Prabir Pradhan678438e2023-04-13 19:32:51 +00002664 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_ENTER, AINPUT_SOURCE_MOUSE)
2665 .deviceId(mouseDeviceId)
2666 .pointer(PointerBuilder(0, ToolType::MOUSE).x(100).y(100))
2667 .build());
Siarhei Vishniakouf372b812023-02-14 18:06:51 -08002668 leftWindow->consumeMotionEvent(
2669 AllOf(WithMotionAction(ACTION_HOVER_ENTER), WithDeviceId(mouseDeviceId)));
2670
2671 // Mouse down on left window
Prabir Pradhan678438e2023-04-13 19:32:51 +00002672 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_MOUSE)
2673 .deviceId(mouseDeviceId)
2674 .buttonState(AMOTION_EVENT_BUTTON_PRIMARY)
2675 .pointer(PointerBuilder(0, ToolType::MOUSE).x(100).y(100))
2676 .build());
Siarhei Vishniakouf372b812023-02-14 18:06:51 -08002677
2678 leftWindow->consumeMotionEvent(
2679 AllOf(WithMotionAction(ACTION_HOVER_EXIT), WithDeviceId(mouseDeviceId)));
2680 leftWindow->consumeMotionEvent(
2681 AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(mouseDeviceId)));
2682
Prabir Pradhan678438e2023-04-13 19:32:51 +00002683 mDispatcher->notifyMotion(
2684 MotionArgsBuilder(AMOTION_EVENT_ACTION_BUTTON_PRESS, AINPUT_SOURCE_MOUSE)
2685 .deviceId(mouseDeviceId)
2686 .buttonState(AMOTION_EVENT_BUTTON_PRIMARY)
2687 .actionButton(AMOTION_EVENT_BUTTON_PRIMARY)
2688 .pointer(PointerBuilder(0, ToolType::MOUSE).x(100).y(100))
2689 .build());
Siarhei Vishniakouf372b812023-02-14 18:06:51 -08002690 leftWindow->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_BUTTON_PRESS));
2691
2692 // First touch pointer down on right window
Prabir Pradhan678438e2023-04-13 19:32:51 +00002693 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
2694 .deviceId(touchDeviceId)
2695 .pointer(PointerBuilder(0, ToolType::FINGER).x(300).y(100))
2696 .build());
Siarhei Vishniakou2899c552023-07-10 18:20:46 -07002697 leftWindow->assertNoEvents();
2698
Siarhei Vishniakouf372b812023-02-14 18:06:51 -08002699 rightWindow->consumeMotionEvent(WithMotionAction(ACTION_DOWN));
2700
2701 // Second touch pointer down on left window
Prabir Pradhan678438e2023-04-13 19:32:51 +00002702 mDispatcher->notifyMotion(MotionArgsBuilder(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
2703 .deviceId(touchDeviceId)
2704 .pointer(PointerBuilder(0, ToolType::FINGER).x(300).y(100))
2705 .pointer(PointerBuilder(1, ToolType::FINGER).x(100).y(100))
2706 .build());
Siarhei Vishniakou2899c552023-07-10 18:20:46 -07002707 // Since this is now a new splittable pointer going down on the left window, and it's coming
2708 // from a different device, the current gesture in the left window (pointer down) should first
2709 // be canceled.
2710 leftWindow->consumeMotionEvent(
2711 AllOf(WithMotionAction(ACTION_CANCEL), WithDeviceId(mouseDeviceId)));
Siarhei Vishniakouf372b812023-02-14 18:06:51 -08002712 leftWindow->consumeMotionEvent(
2713 AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(touchDeviceId)));
2714 // This MOVE event is not necessary (doesn't carry any new information), but it's there in the
2715 // current implementation.
2716 const std::map<int32_t, PointF> expectedPointers{{0, PointF{100, 100}}};
2717 rightWindow->consumeMotionEvent(
2718 AllOf(WithMotionAction(ACTION_MOVE), WithPointers(expectedPointers)));
2719
2720 leftWindow->assertNoEvents();
2721 rightWindow->assertNoEvents();
2722}
2723
2724/**
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -07002725 * Two windows: a window on the left and a window on the right.
Siarhei Vishniakoued89cbb2023-10-13 10:42:44 -07002726 * Mouse is clicked on the left window and remains down. Touch is touched on the right and remains
2727 * down. Then, on the left window, also place second touch pointer down.
2728 * This test tries to reproduce a crash.
2729 * In the buggy implementation, second pointer down on the left window would cause a crash.
2730 */
2731TEST_F(InputDispatcherMultiDeviceTest, MultiDeviceSplitTouch) {
2732 SCOPED_FLAG_OVERRIDE(enable_multi_device_same_window_stream, true);
2733 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07002734 sp<FakeWindowHandle> leftWindow = sp<FakeWindowHandle>::make(application, mDispatcher, "Left",
2735 ui::LogicalDisplayId::DEFAULT);
Siarhei Vishniakoued89cbb2023-10-13 10:42:44 -07002736 leftWindow->setFrame(Rect(0, 0, 200, 200));
2737
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07002738 sp<FakeWindowHandle> rightWindow = sp<FakeWindowHandle>::make(application, mDispatcher, "Right",
2739 ui::LogicalDisplayId::DEFAULT);
Siarhei Vishniakoued89cbb2023-10-13 10:42:44 -07002740 rightWindow->setFrame(Rect(200, 0, 400, 200));
2741
2742 mDispatcher->onWindowInfosChanged(
2743 {{*leftWindow->getInfo(), *rightWindow->getInfo()}, {}, 0, 0});
2744
2745 const int32_t touchDeviceId = 4;
2746 const int32_t mouseDeviceId = 6;
2747
2748 // Start hovering over the left window
2749 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_ENTER, AINPUT_SOURCE_MOUSE)
2750 .deviceId(mouseDeviceId)
2751 .pointer(PointerBuilder(0, ToolType::MOUSE).x(100).y(100))
2752 .build());
2753 leftWindow->consumeMotionEvent(
2754 AllOf(WithMotionAction(ACTION_HOVER_ENTER), WithDeviceId(mouseDeviceId)));
2755
2756 // Mouse down on left window
2757 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_MOUSE)
2758 .deviceId(mouseDeviceId)
2759 .buttonState(AMOTION_EVENT_BUTTON_PRIMARY)
2760 .pointer(PointerBuilder(0, ToolType::MOUSE).x(100).y(100))
2761 .build());
2762
2763 leftWindow->consumeMotionEvent(
2764 AllOf(WithMotionAction(ACTION_HOVER_EXIT), WithDeviceId(mouseDeviceId)));
2765 leftWindow->consumeMotionEvent(
2766 AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(mouseDeviceId)));
2767
2768 mDispatcher->notifyMotion(
2769 MotionArgsBuilder(AMOTION_EVENT_ACTION_BUTTON_PRESS, AINPUT_SOURCE_MOUSE)
2770 .deviceId(mouseDeviceId)
2771 .buttonState(AMOTION_EVENT_BUTTON_PRIMARY)
2772 .actionButton(AMOTION_EVENT_BUTTON_PRIMARY)
2773 .pointer(PointerBuilder(0, ToolType::MOUSE).x(100).y(100))
2774 .build());
2775 leftWindow->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_BUTTON_PRESS));
2776
2777 // First touch pointer down on right window
2778 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
2779 .deviceId(touchDeviceId)
2780 .pointer(PointerBuilder(0, ToolType::FINGER).x(300).y(100))
2781 .build());
2782 leftWindow->assertNoEvents();
2783
2784 rightWindow->consumeMotionEvent(WithMotionAction(ACTION_DOWN));
2785
2786 // Second touch pointer down on left window
2787 mDispatcher->notifyMotion(MotionArgsBuilder(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
2788 .deviceId(touchDeviceId)
2789 .pointer(PointerBuilder(0, ToolType::FINGER).x(300).y(100))
2790 .pointer(PointerBuilder(1, ToolType::FINGER).x(100).y(100))
2791 .build());
2792 // Since this is now a new splittable pointer going down on the left window, and it's coming
2793 // from a different device, it will be split and delivered to left window separately.
2794 leftWindow->consumeMotionEvent(
2795 AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(touchDeviceId)));
2796 // This MOVE event is not necessary (doesn't carry any new information), but it's there in the
2797 // current implementation.
2798 const std::map<int32_t, PointF> expectedPointers{{0, PointF{100, 100}}};
2799 rightWindow->consumeMotionEvent(
2800 AllOf(WithMotionAction(ACTION_MOVE), WithPointers(expectedPointers)));
2801
2802 leftWindow->assertNoEvents();
2803 rightWindow->assertNoEvents();
2804}
2805
2806/**
2807 * Two windows: a window on the left and a window on the right.
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -07002808 * Mouse is hovered on the left window and stylus is hovered on the right window.
2809 */
2810TEST_F(InputDispatcherMultiDeviceTest, MultiDeviceHover) {
2811 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07002812 sp<FakeWindowHandle> leftWindow = sp<FakeWindowHandle>::make(application, mDispatcher, "Left",
2813 ui::LogicalDisplayId::DEFAULT);
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -07002814 leftWindow->setFrame(Rect(0, 0, 200, 200));
2815
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07002816 sp<FakeWindowHandle> rightWindow = sp<FakeWindowHandle>::make(application, mDispatcher, "Right",
2817 ui::LogicalDisplayId::DEFAULT);
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -07002818 rightWindow->setFrame(Rect(200, 0, 400, 200));
2819
2820 mDispatcher->onWindowInfosChanged(
2821 {{*leftWindow->getInfo(), *rightWindow->getInfo()}, {}, 0, 0});
2822
2823 const int32_t stylusDeviceId = 3;
2824 const int32_t mouseDeviceId = 6;
2825
2826 // Start hovering over the left window
2827 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_ENTER, AINPUT_SOURCE_MOUSE)
2828 .deviceId(mouseDeviceId)
2829 .pointer(PointerBuilder(0, ToolType::MOUSE).x(100).y(110))
2830 .build());
2831 leftWindow->consumeMotionEvent(
2832 AllOf(WithMotionAction(ACTION_HOVER_ENTER), WithDeviceId(mouseDeviceId)));
2833
2834 // Stylus hovered on right window
2835 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_ENTER, AINPUT_SOURCE_STYLUS)
2836 .deviceId(stylusDeviceId)
2837 .pointer(PointerBuilder(0, ToolType::STYLUS).x(300).y(100))
2838 .build());
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -07002839 rightWindow->consumeMotionEvent(
2840 AllOf(WithMotionAction(ACTION_HOVER_ENTER), WithDeviceId(stylusDeviceId)));
2841
2842 // Subsequent HOVER_MOVE events are dispatched correctly.
2843 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_MOVE, AINPUT_SOURCE_MOUSE)
2844 .deviceId(mouseDeviceId)
2845 .pointer(PointerBuilder(0, ToolType::MOUSE).x(110).y(120))
2846 .build());
2847 leftWindow->consumeMotionEvent(
Siarhei Vishniakou2899c552023-07-10 18:20:46 -07002848 AllOf(WithMotionAction(ACTION_HOVER_MOVE), WithDeviceId(mouseDeviceId)));
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -07002849
2850 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_MOVE, AINPUT_SOURCE_STYLUS)
2851 .deviceId(stylusDeviceId)
2852 .pointer(PointerBuilder(0, ToolType::STYLUS).x(310).y(110))
2853 .build());
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -07002854 rightWindow->consumeMotionEvent(
Siarhei Vishniakou2899c552023-07-10 18:20:46 -07002855 AllOf(WithMotionAction(ACTION_HOVER_MOVE), WithDeviceId(stylusDeviceId)));
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -07002856
2857 leftWindow->assertNoEvents();
2858 rightWindow->assertNoEvents();
2859}
2860
2861/**
2862 * Three windows: a window on the left and a window on the right.
2863 * And a spy window that's positioned above all of them.
2864 * Stylus down on the left window and remains down. Touch goes down on the right and remains down.
2865 * Check the stream that's received by the spy.
2866 */
Siarhei Vishniakoued89cbb2023-10-13 10:42:44 -07002867TEST_F(InputDispatcherMultiDeviceTest, MultiDeviceWithSpy_legacy) {
2868 SCOPED_FLAG_OVERRIDE(enable_multi_device_same_window_stream, false);
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -07002869 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
2870
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07002871 sp<FakeWindowHandle> spyWindow = sp<FakeWindowHandle>::make(application, mDispatcher, "Spy",
2872 ui::LogicalDisplayId::DEFAULT);
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -07002873 spyWindow->setFrame(Rect(0, 0, 400, 400));
2874 spyWindow->setTrustedOverlay(true);
2875 spyWindow->setSpy(true);
2876
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07002877 sp<FakeWindowHandle> leftWindow = sp<FakeWindowHandle>::make(application, mDispatcher, "Left",
2878 ui::LogicalDisplayId::DEFAULT);
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -07002879 leftWindow->setFrame(Rect(0, 0, 200, 200));
2880
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07002881 sp<FakeWindowHandle> rightWindow = sp<FakeWindowHandle>::make(application, mDispatcher, "Right",
2882 ui::LogicalDisplayId::DEFAULT);
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -07002883
2884 rightWindow->setFrame(Rect(200, 0, 400, 200));
2885
2886 mDispatcher->onWindowInfosChanged(
2887 {{*spyWindow->getInfo(), *leftWindow->getInfo(), *rightWindow->getInfo()}, {}, 0, 0});
2888
2889 const int32_t stylusDeviceId = 1;
2890 const int32_t touchDeviceId = 2;
2891
2892 // Stylus down on the left window
2893 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_STYLUS)
2894 .deviceId(stylusDeviceId)
2895 .pointer(PointerBuilder(0, ToolType::STYLUS).x(100).y(100))
2896 .build());
2897 leftWindow->consumeMotionEvent(
2898 AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(stylusDeviceId)));
2899 spyWindow->consumeMotionEvent(
2900 AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(stylusDeviceId)));
2901
2902 // Touch down on the right window
2903 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
2904 .deviceId(touchDeviceId)
2905 .pointer(PointerBuilder(0, ToolType::FINGER).x(300).y(100))
2906 .build());
Siarhei Vishniakou2899c552023-07-10 18:20:46 -07002907 leftWindow->assertNoEvents();
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -07002908 rightWindow->consumeMotionEvent(
2909 AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(touchDeviceId)));
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -07002910
Siarhei Vishniakou2899c552023-07-10 18:20:46 -07002911 // Spy window does not receive touch events, because stylus events take precedence, and it
2912 // already has an active stylus gesture.
2913
2914 // Stylus movements continue. They should be delivered to the left window and to the spy window
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -07002915 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_STYLUS)
2916 .deviceId(stylusDeviceId)
2917 .pointer(PointerBuilder(0, ToolType::STYLUS).x(110).y(110))
2918 .build());
Siarhei Vishniakou2899c552023-07-10 18:20:46 -07002919 leftWindow->consumeMotionEvent(
2920 AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(stylusDeviceId)));
2921 spyWindow->consumeMotionEvent(
2922 AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(stylusDeviceId)));
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -07002923
Siarhei Vishniakou2899c552023-07-10 18:20:46 -07002924 // Further MOVE events keep going to the right window only
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -07002925 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN)
2926 .deviceId(touchDeviceId)
2927 .pointer(PointerBuilder(0, ToolType::FINGER).x(310).y(110))
2928 .build());
2929 rightWindow->consumeMotionEvent(
2930 AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(touchDeviceId)));
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -07002931
2932 spyWindow->assertNoEvents();
2933 leftWindow->assertNoEvents();
2934 rightWindow->assertNoEvents();
2935}
2936
2937/**
Siarhei Vishniakoued89cbb2023-10-13 10:42:44 -07002938 * Three windows: a window on the left and a window on the right.
2939 * And a spy window that's positioned above all of them.
2940 * Stylus down on the left window and remains down. Touch goes down on the right and remains down.
2941 * Check the stream that's received by the spy.
2942 */
2943TEST_F(InputDispatcherMultiDeviceTest, MultiDeviceWithSpy) {
2944 SCOPED_FLAG_OVERRIDE(enable_multi_device_same_window_stream, true);
2945 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
2946
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07002947 sp<FakeWindowHandle> spyWindow = sp<FakeWindowHandle>::make(application, mDispatcher, "Spy",
2948 ui::LogicalDisplayId::DEFAULT);
Siarhei Vishniakoued89cbb2023-10-13 10:42:44 -07002949 spyWindow->setFrame(Rect(0, 0, 400, 400));
2950 spyWindow->setTrustedOverlay(true);
2951 spyWindow->setSpy(true);
2952
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07002953 sp<FakeWindowHandle> leftWindow = sp<FakeWindowHandle>::make(application, mDispatcher, "Left",
2954 ui::LogicalDisplayId::DEFAULT);
Siarhei Vishniakoued89cbb2023-10-13 10:42:44 -07002955 leftWindow->setFrame(Rect(0, 0, 200, 200));
2956
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07002957 sp<FakeWindowHandle> rightWindow = sp<FakeWindowHandle>::make(application, mDispatcher, "Right",
2958 ui::LogicalDisplayId::DEFAULT);
Siarhei Vishniakoued89cbb2023-10-13 10:42:44 -07002959
2960 rightWindow->setFrame(Rect(200, 0, 400, 200));
2961
2962 mDispatcher->onWindowInfosChanged(
2963 {{*spyWindow->getInfo(), *leftWindow->getInfo(), *rightWindow->getInfo()}, {}, 0, 0});
2964
2965 const int32_t stylusDeviceId = 1;
2966 const int32_t touchDeviceId = 2;
2967
2968 // Stylus down on the left window
2969 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_STYLUS)
2970 .deviceId(stylusDeviceId)
2971 .pointer(PointerBuilder(0, ToolType::STYLUS).x(100).y(100))
2972 .build());
2973 leftWindow->consumeMotionEvent(
2974 AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(stylusDeviceId)));
2975 spyWindow->consumeMotionEvent(
2976 AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(stylusDeviceId)));
2977
2978 // Touch down on the right window
2979 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
2980 .deviceId(touchDeviceId)
2981 .pointer(PointerBuilder(0, ToolType::FINGER).x(300).y(100))
2982 .build());
2983 leftWindow->assertNoEvents();
2984 rightWindow->consumeMotionEvent(
2985 AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(touchDeviceId)));
2986 spyWindow->consumeMotionEvent(
2987 AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(touchDeviceId)));
2988
2989 // Stylus movements continue. They should be delivered to the left window and to the spy window
2990 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_STYLUS)
2991 .deviceId(stylusDeviceId)
2992 .pointer(PointerBuilder(0, ToolType::STYLUS).x(110).y(110))
2993 .build());
2994 leftWindow->consumeMotionEvent(
2995 AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(stylusDeviceId)));
2996 spyWindow->consumeMotionEvent(
2997 AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(stylusDeviceId)));
2998
2999 // Further touch MOVE events keep going to the right window and to the spy
3000 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN)
3001 .deviceId(touchDeviceId)
3002 .pointer(PointerBuilder(0, ToolType::FINGER).x(310).y(110))
3003 .build());
3004 rightWindow->consumeMotionEvent(
3005 AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(touchDeviceId)));
3006 spyWindow->consumeMotionEvent(
3007 AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(touchDeviceId)));
3008
3009 spyWindow->assertNoEvents();
3010 leftWindow->assertNoEvents();
3011 rightWindow->assertNoEvents();
3012}
3013
3014/**
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -07003015 * Three windows: a window on the left, a window on the right, and a spy window positioned above
3016 * both.
3017 * Check hover in left window and touch down in the right window.
Siarhei Vishniakou3ad54f52023-11-02 16:54:40 -07003018 * At first, spy should receive hover. Spy shouldn't receive touch while stylus is hovering.
Siarhei Vishniakou2899c552023-07-10 18:20:46 -07003019 * At the same time, left and right should be getting independent streams of hovering and touch,
3020 * respectively.
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -07003021 */
Siarhei Vishniakou3ad54f52023-11-02 16:54:40 -07003022TEST_F(InputDispatcherMultiDeviceTest, MultiDeviceHoverBlocksTouchWithSpy) {
Siarhei Vishniakoued89cbb2023-10-13 10:42:44 -07003023 SCOPED_FLAG_OVERRIDE(enable_multi_device_same_window_stream, false);
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -07003024 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
3025
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07003026 sp<FakeWindowHandle> spyWindow = sp<FakeWindowHandle>::make(application, mDispatcher, "Spy",
3027 ui::LogicalDisplayId::DEFAULT);
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -07003028 spyWindow->setFrame(Rect(0, 0, 400, 400));
3029 spyWindow->setTrustedOverlay(true);
3030 spyWindow->setSpy(true);
3031
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07003032 sp<FakeWindowHandle> leftWindow = sp<FakeWindowHandle>::make(application, mDispatcher, "Left",
3033 ui::LogicalDisplayId::DEFAULT);
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -07003034 leftWindow->setFrame(Rect(0, 0, 200, 200));
3035
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07003036 sp<FakeWindowHandle> rightWindow = sp<FakeWindowHandle>::make(application, mDispatcher, "Right",
3037 ui::LogicalDisplayId::DEFAULT);
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -07003038 rightWindow->setFrame(Rect(200, 0, 400, 200));
3039
3040 mDispatcher->onWindowInfosChanged(
3041 {{*spyWindow->getInfo(), *leftWindow->getInfo(), *rightWindow->getInfo()}, {}, 0, 0});
3042
3043 const int32_t stylusDeviceId = 1;
3044 const int32_t touchDeviceId = 2;
3045
3046 // Stylus hover on the left window
3047 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_ENTER, AINPUT_SOURCE_STYLUS)
3048 .deviceId(stylusDeviceId)
3049 .pointer(PointerBuilder(0, ToolType::STYLUS).x(100).y(100))
3050 .build());
3051 leftWindow->consumeMotionEvent(
3052 AllOf(WithMotionAction(ACTION_HOVER_ENTER), WithDeviceId(stylusDeviceId)));
3053 spyWindow->consumeMotionEvent(
3054 AllOf(WithMotionAction(ACTION_HOVER_ENTER), WithDeviceId(stylusDeviceId)));
3055
Siarhei Vishniakou2899c552023-07-10 18:20:46 -07003056 // Touch down on the right window. Spy doesn't receive this touch because it already has
3057 // stylus hovering there.
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -07003058 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
3059 .deviceId(touchDeviceId)
3060 .pointer(PointerBuilder(0, ToolType::FINGER).x(300).y(100))
3061 .build());
Siarhei Vishniakou2899c552023-07-10 18:20:46 -07003062 leftWindow->assertNoEvents();
Siarhei Vishniakou3ad54f52023-11-02 16:54:40 -07003063 spyWindow->assertNoEvents();
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -07003064 rightWindow->consumeMotionEvent(
3065 AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(touchDeviceId)));
3066
Siarhei Vishniakou3ad54f52023-11-02 16:54:40 -07003067 // Stylus movements continue. They should be delivered to the left window and the spy.
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -07003068 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_MOVE, AINPUT_SOURCE_STYLUS)
3069 .deviceId(stylusDeviceId)
3070 .pointer(PointerBuilder(0, ToolType::STYLUS).x(110).y(110))
3071 .build());
Siarhei Vishniakou2899c552023-07-10 18:20:46 -07003072 leftWindow->consumeMotionEvent(
3073 AllOf(WithMotionAction(ACTION_HOVER_MOVE), WithDeviceId(stylusDeviceId)));
Siarhei Vishniakou3ad54f52023-11-02 16:54:40 -07003074 spyWindow->consumeMotionEvent(
3075 AllOf(WithMotionAction(ACTION_HOVER_MOVE), WithDeviceId(stylusDeviceId)));
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -07003076
Siarhei Vishniakou3ad54f52023-11-02 16:54:40 -07003077 // Touch movements continue. They should be delivered to the right window only
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -07003078 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN)
3079 .deviceId(touchDeviceId)
3080 .pointer(PointerBuilder(0, ToolType::FINGER).x(301).y(101))
3081 .build());
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -07003082 rightWindow->consumeMotionEvent(
3083 AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(touchDeviceId)));
3084
3085 spyWindow->assertNoEvents();
3086 leftWindow->assertNoEvents();
3087 rightWindow->assertNoEvents();
3088}
3089
3090/**
Siarhei Vishniakoued89cbb2023-10-13 10:42:44 -07003091 * Three windows: a window on the left, a window on the right, and a spy window positioned above
3092 * both.
3093 * Check hover in left window and touch down in the right window.
3094 * At first, spy should receive hover. Next, spy should receive touch.
3095 * At the same time, left and right should be getting independent streams of hovering and touch,
3096 * respectively.
3097 */
3098TEST_F(InputDispatcherMultiDeviceTest, MultiDeviceHoverDoesNotBlockTouchWithSpy) {
3099 SCOPED_FLAG_OVERRIDE(enable_multi_device_same_window_stream, true);
3100 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
3101
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07003102 sp<FakeWindowHandle> spyWindow = sp<FakeWindowHandle>::make(application, mDispatcher, "Spy",
3103 ui::LogicalDisplayId::DEFAULT);
Siarhei Vishniakoued89cbb2023-10-13 10:42:44 -07003104 spyWindow->setFrame(Rect(0, 0, 400, 400));
3105 spyWindow->setTrustedOverlay(true);
3106 spyWindow->setSpy(true);
3107
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07003108 sp<FakeWindowHandle> leftWindow = sp<FakeWindowHandle>::make(application, mDispatcher, "Left",
3109 ui::LogicalDisplayId::DEFAULT);
Siarhei Vishniakoued89cbb2023-10-13 10:42:44 -07003110 leftWindow->setFrame(Rect(0, 0, 200, 200));
3111
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07003112 sp<FakeWindowHandle> rightWindow = sp<FakeWindowHandle>::make(application, mDispatcher, "Right",
3113 ui::LogicalDisplayId::DEFAULT);
Siarhei Vishniakoued89cbb2023-10-13 10:42:44 -07003114 rightWindow->setFrame(Rect(200, 0, 400, 200));
3115
3116 mDispatcher->onWindowInfosChanged(
3117 {{*spyWindow->getInfo(), *leftWindow->getInfo(), *rightWindow->getInfo()}, {}, 0, 0});
3118
3119 const int32_t stylusDeviceId = 1;
3120 const int32_t touchDeviceId = 2;
3121
3122 // Stylus hover on the left window
3123 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_ENTER, AINPUT_SOURCE_STYLUS)
3124 .deviceId(stylusDeviceId)
3125 .pointer(PointerBuilder(0, ToolType::STYLUS).x(100).y(100))
3126 .build());
3127 leftWindow->consumeMotionEvent(
3128 AllOf(WithMotionAction(ACTION_HOVER_ENTER), WithDeviceId(stylusDeviceId)));
3129 spyWindow->consumeMotionEvent(
3130 AllOf(WithMotionAction(ACTION_HOVER_ENTER), WithDeviceId(stylusDeviceId)));
3131
3132 // Touch down on the right window.
3133 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
3134 .deviceId(touchDeviceId)
3135 .pointer(PointerBuilder(0, ToolType::FINGER).x(300).y(100))
3136 .build());
3137 leftWindow->assertNoEvents();
3138 spyWindow->consumeMotionEvent(
3139 AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(touchDeviceId)));
3140 rightWindow->consumeMotionEvent(
3141 AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(touchDeviceId)));
3142
3143 // Stylus movements continue. They should be delivered to the left window and the spy.
3144 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_MOVE, AINPUT_SOURCE_STYLUS)
3145 .deviceId(stylusDeviceId)
3146 .pointer(PointerBuilder(0, ToolType::STYLUS).x(110).y(110))
3147 .build());
3148 leftWindow->consumeMotionEvent(
3149 AllOf(WithMotionAction(ACTION_HOVER_MOVE), WithDeviceId(stylusDeviceId)));
3150 spyWindow->consumeMotionEvent(
3151 AllOf(WithMotionAction(ACTION_HOVER_MOVE), WithDeviceId(stylusDeviceId)));
3152
3153 // Touch movements continue. They should be delivered to the right window and the spy
3154 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN)
3155 .deviceId(touchDeviceId)
3156 .pointer(PointerBuilder(0, ToolType::FINGER).x(301).y(101))
3157 .build());
3158 rightWindow->consumeMotionEvent(
3159 AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(touchDeviceId)));
3160 spyWindow->consumeMotionEvent(
3161 AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(touchDeviceId)));
3162
3163 spyWindow->assertNoEvents();
3164 leftWindow->assertNoEvents();
3165 rightWindow->assertNoEvents();
3166}
3167
3168/**
Siarhei Vishniakouf372b812023-02-14 18:06:51 -08003169 * On a single window, use two different devices: mouse and touch.
3170 * Touch happens first, with two pointers going down, and then the first pointer leaving.
3171 * Mouse is clicked next, which causes the touch stream to be aborted with ACTION_CANCEL.
3172 * Finally, a second touch pointer goes down again. Ensure the second touch pointer is ignored,
3173 * because the mouse is currently down, and a POINTER_DOWN event from the touchscreen does not
3174 * represent a new gesture.
3175 */
Siarhei Vishniakoued89cbb2023-10-13 10:42:44 -07003176TEST_F(InputDispatcherMultiDeviceTest, MixedTouchAndMouseWithPointerDown_legacy) {
3177 SCOPED_FLAG_OVERRIDE(enable_multi_device_same_window_stream, false);
Siarhei Vishniakouf372b812023-02-14 18:06:51 -08003178 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07003179 sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher, "Window",
3180 ui::LogicalDisplayId::DEFAULT);
Siarhei Vishniakouf372b812023-02-14 18:06:51 -08003181 window->setFrame(Rect(0, 0, 400, 400));
3182
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07003183 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Siarhei Vishniakouf372b812023-02-14 18:06:51 -08003184
3185 const int32_t touchDeviceId = 4;
3186 const int32_t mouseDeviceId = 6;
Siarhei Vishniakouf372b812023-02-14 18:06:51 -08003187
Siarhei Vishniakou4e1ffa52023-02-21 11:50:34 -08003188 // First touch pointer down
Prabir Pradhan678438e2023-04-13 19:32:51 +00003189 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
3190 .deviceId(touchDeviceId)
3191 .pointer(PointerBuilder(0, ToolType::FINGER).x(300).y(100))
3192 .build());
Siarhei Vishniakouf372b812023-02-14 18:06:51 -08003193 // Second touch pointer down
Prabir Pradhan678438e2023-04-13 19:32:51 +00003194 mDispatcher->notifyMotion(MotionArgsBuilder(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
3195 .deviceId(touchDeviceId)
3196 .pointer(PointerBuilder(0, ToolType::FINGER).x(300).y(100))
3197 .pointer(PointerBuilder(1, ToolType::FINGER).x(350).y(100))
3198 .build());
Siarhei Vishniakouf372b812023-02-14 18:06:51 -08003199 // First touch pointer lifts. The second one remains down
Prabir Pradhan678438e2023-04-13 19:32:51 +00003200 mDispatcher->notifyMotion(MotionArgsBuilder(POINTER_0_UP, AINPUT_SOURCE_TOUCHSCREEN)
3201 .deviceId(touchDeviceId)
3202 .pointer(PointerBuilder(0, ToolType::FINGER).x(300).y(100))
3203 .pointer(PointerBuilder(1, ToolType::FINGER).x(350).y(100))
3204 .build());
Siarhei Vishniakouf372b812023-02-14 18:06:51 -08003205 window->consumeMotionEvent(WithMotionAction(ACTION_DOWN));
3206 window->consumeMotionEvent(WithMotionAction(POINTER_1_DOWN));
3207 window->consumeMotionEvent(WithMotionAction(POINTER_0_UP));
3208
3209 // Mouse down. The touch should be canceled
Prabir Pradhan678438e2023-04-13 19:32:51 +00003210 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_MOUSE)
3211 .deviceId(mouseDeviceId)
3212 .buttonState(AMOTION_EVENT_BUTTON_PRIMARY)
3213 .pointer(PointerBuilder(0, ToolType::MOUSE).x(320).y(100))
3214 .build());
Siarhei Vishniakouf372b812023-02-14 18:06:51 -08003215
3216 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_CANCEL), WithDeviceId(touchDeviceId),
Siarhei Vishniakou82dc0422023-02-17 23:12:52 -08003217 WithPointerCount(1u)));
Siarhei Vishniakouf372b812023-02-14 18:06:51 -08003218 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(mouseDeviceId)));
3219
Prabir Pradhan678438e2023-04-13 19:32:51 +00003220 mDispatcher->notifyMotion(
3221 MotionArgsBuilder(AMOTION_EVENT_ACTION_BUTTON_PRESS, AINPUT_SOURCE_MOUSE)
3222 .deviceId(mouseDeviceId)
3223 .buttonState(AMOTION_EVENT_BUTTON_PRIMARY)
3224 .actionButton(AMOTION_EVENT_BUTTON_PRIMARY)
3225 .pointer(PointerBuilder(0, ToolType::MOUSE).x(320).y(100))
3226 .build());
Siarhei Vishniakouf372b812023-02-14 18:06:51 -08003227 window->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_BUTTON_PRESS));
3228
3229 // Second touch pointer down.
Prabir Pradhan678438e2023-04-13 19:32:51 +00003230 mDispatcher->notifyMotion(MotionArgsBuilder(POINTER_0_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
3231 .deviceId(touchDeviceId)
3232 .pointer(PointerBuilder(0, ToolType::FINGER).x(300).y(100))
3233 .pointer(PointerBuilder(1, ToolType::FINGER).x(350).y(100))
3234 .build());
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -07003235 // Since we already canceled this touch gesture, it will be ignored until a completely new
3236 // gesture is started. This is easier to implement than trying to keep track of the new pointer
3237 // and generating an ACTION_DOWN instead of ACTION_POINTER_DOWN.
3238 // However, mouse movements should continue to work.
3239 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_MOUSE)
3240 .deviceId(mouseDeviceId)
3241 .buttonState(AMOTION_EVENT_BUTTON_PRIMARY)
3242 .pointer(PointerBuilder(0, ToolType::MOUSE).x(330).y(110))
3243 .build());
3244 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(mouseDeviceId)));
3245
Siarhei Vishniakouf372b812023-02-14 18:06:51 -08003246 window->assertNoEvents();
3247}
3248
3249/**
Siarhei Vishniakoued89cbb2023-10-13 10:42:44 -07003250 * On a single window, use two different devices: mouse and touch.
3251 * Touch happens first, with two pointers going down, and then the first pointer leaving.
3252 * Mouse is clicked next, which should not interfere with the touch stream.
3253 * Finally, a second touch pointer goes down again. Ensure the second touch pointer is also
3254 * delivered correctly.
3255 */
3256TEST_F(InputDispatcherMultiDeviceTest, MixedTouchAndMouseWithPointerDown) {
3257 SCOPED_FLAG_OVERRIDE(enable_multi_device_same_window_stream, true);
3258 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07003259 sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher, "Window",
3260 ui::LogicalDisplayId::DEFAULT);
Siarhei Vishniakoued89cbb2023-10-13 10:42:44 -07003261 window->setFrame(Rect(0, 0, 400, 400));
3262
3263 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
3264
3265 const int32_t touchDeviceId = 4;
3266 const int32_t mouseDeviceId = 6;
3267
3268 // First touch pointer down
3269 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
3270 .deviceId(touchDeviceId)
3271 .pointer(PointerBuilder(0, ToolType::FINGER).x(300).y(100))
3272 .build());
3273 // Second touch pointer down
3274 mDispatcher->notifyMotion(MotionArgsBuilder(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
3275 .deviceId(touchDeviceId)
3276 .pointer(PointerBuilder(0, ToolType::FINGER).x(300).y(100))
3277 .pointer(PointerBuilder(1, ToolType::FINGER).x(350).y(100))
3278 .build());
3279 // First touch pointer lifts. The second one remains down
3280 mDispatcher->notifyMotion(MotionArgsBuilder(POINTER_0_UP, AINPUT_SOURCE_TOUCHSCREEN)
3281 .deviceId(touchDeviceId)
3282 .pointer(PointerBuilder(0, ToolType::FINGER).x(300).y(100))
3283 .pointer(PointerBuilder(1, ToolType::FINGER).x(350).y(100))
3284 .build());
3285 window->consumeMotionEvent(WithMotionAction(ACTION_DOWN));
3286 window->consumeMotionEvent(WithMotionAction(POINTER_1_DOWN));
3287 window->consumeMotionEvent(WithMotionAction(POINTER_0_UP));
3288
3289 // Mouse down
3290 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_MOUSE)
3291 .deviceId(mouseDeviceId)
3292 .buttonState(AMOTION_EVENT_BUTTON_PRIMARY)
3293 .pointer(PointerBuilder(0, ToolType::MOUSE).x(320).y(100))
3294 .build());
3295
3296 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(mouseDeviceId)));
3297
3298 mDispatcher->notifyMotion(
3299 MotionArgsBuilder(AMOTION_EVENT_ACTION_BUTTON_PRESS, AINPUT_SOURCE_MOUSE)
3300 .deviceId(mouseDeviceId)
3301 .buttonState(AMOTION_EVENT_BUTTON_PRIMARY)
3302 .actionButton(AMOTION_EVENT_BUTTON_PRIMARY)
3303 .pointer(PointerBuilder(0, ToolType::MOUSE).x(320).y(100))
3304 .build());
3305 window->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_BUTTON_PRESS));
3306
3307 // Second touch pointer down.
3308 mDispatcher->notifyMotion(MotionArgsBuilder(POINTER_0_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
3309 .deviceId(touchDeviceId)
3310 .pointer(PointerBuilder(0, ToolType::FINGER).x(300).y(100))
3311 .pointer(PointerBuilder(1, ToolType::FINGER).x(350).y(100))
3312 .build());
3313 window->consumeMotionEvent(AllOf(WithMotionAction(POINTER_0_DOWN), WithDeviceId(touchDeviceId),
3314 WithPointerCount(2u)));
3315
3316 // Mouse movements should continue to work
3317 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_MOUSE)
3318 .deviceId(mouseDeviceId)
3319 .buttonState(AMOTION_EVENT_BUTTON_PRIMARY)
3320 .pointer(PointerBuilder(0, ToolType::MOUSE).x(330).y(110))
3321 .build());
3322 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(mouseDeviceId)));
3323
3324 window->assertNoEvents();
3325}
3326
3327/**
Siarhei Vishniakou56e79092023-02-21 19:13:16 -08003328 * Inject a touch down and then send a new event via 'notifyMotion'. Ensure the new event cancels
3329 * the injected event.
3330 */
Siarhei Vishniakoued89cbb2023-10-13 10:42:44 -07003331TEST_F(InputDispatcherMultiDeviceTest, UnfinishedInjectedEvent_legacy) {
3332 SCOPED_FLAG_OVERRIDE(enable_multi_device_same_window_stream, false);
Siarhei Vishniakou56e79092023-02-21 19:13:16 -08003333 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07003334 sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher, "Window",
3335 ui::LogicalDisplayId::DEFAULT);
Siarhei Vishniakou56e79092023-02-21 19:13:16 -08003336 window->setFrame(Rect(0, 0, 400, 400));
3337
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07003338 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Siarhei Vishniakou56e79092023-02-21 19:13:16 -08003339
3340 const int32_t touchDeviceId = 4;
Siarhei Vishniakou56e79092023-02-21 19:13:16 -08003341 // Pretend a test injects an ACTION_DOWN mouse event, but forgets to lift up the touch after
3342 // completion.
3343 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07003344 injectMotionEvent(*mDispatcher,
Siarhei Vishniakou56e79092023-02-21 19:13:16 -08003345 MotionEventBuilder(ACTION_DOWN, AINPUT_SOURCE_MOUSE)
3346 .deviceId(ReservedInputDeviceId::VIRTUAL_KEYBOARD_ID)
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07003347 .pointer(PointerBuilder(0, ToolType::MOUSE).x(50).y(50))
Siarhei Vishniakou56e79092023-02-21 19:13:16 -08003348 .build()));
3349 window->consumeMotionEvent(
3350 AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(VIRTUAL_KEYBOARD_ID)));
3351
3352 // Now a real touch comes. Rather than crashing or dropping the real event, the injected pointer
3353 // should be canceled and the new gesture should take over.
Prabir Pradhan678438e2023-04-13 19:32:51 +00003354 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
3355 .deviceId(touchDeviceId)
3356 .pointer(PointerBuilder(0, ToolType::FINGER).x(300).y(100))
3357 .build());
Siarhei Vishniakou56e79092023-02-21 19:13:16 -08003358
3359 window->consumeMotionEvent(
3360 AllOf(WithMotionAction(ACTION_CANCEL), WithDeviceId(VIRTUAL_KEYBOARD_ID)));
3361 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(touchDeviceId)));
3362}
3363
3364/**
Siarhei Vishniakoued89cbb2023-10-13 10:42:44 -07003365 * Inject a touch down and then send a new event via 'notifyMotion'. Ensure the new event runs
3366 * parallel to the injected event.
3367 */
3368TEST_F(InputDispatcherMultiDeviceTest, UnfinishedInjectedEvent) {
3369 SCOPED_FLAG_OVERRIDE(enable_multi_device_same_window_stream, true);
3370 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07003371 sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher, "Window",
3372 ui::LogicalDisplayId::DEFAULT);
Siarhei Vishniakoued89cbb2023-10-13 10:42:44 -07003373 window->setFrame(Rect(0, 0, 400, 400));
3374
3375 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
3376
3377 const int32_t touchDeviceId = 4;
3378 // Pretend a test injects an ACTION_DOWN mouse event, but forgets to lift up the touch after
3379 // completion.
3380 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
3381 injectMotionEvent(*mDispatcher,
3382 MotionEventBuilder(ACTION_DOWN, AINPUT_SOURCE_MOUSE)
3383 .deviceId(ReservedInputDeviceId::VIRTUAL_KEYBOARD_ID)
3384 .pointer(PointerBuilder(0, ToolType::MOUSE).x(50).y(50))
3385 .build()));
3386 window->consumeMotionEvent(
3387 AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(VIRTUAL_KEYBOARD_ID)));
3388
3389 // Now a real touch comes. The injected pointer will remain, and the new gesture will also be
3390 // allowed through.
3391 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
3392 .deviceId(touchDeviceId)
3393 .pointer(PointerBuilder(0, ToolType::FINGER).x(300).y(100))
3394 .build());
3395 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(touchDeviceId)));
3396}
3397
3398/**
Siarhei Vishniakou6464e462023-02-06 18:57:59 -08003399 * This test is similar to the test above, but the sequence of injected events is different.
3400 *
3401 * Two windows: a window on the left and a window on the right.
3402 * Mouse is hovered over the left window.
3403 * Next, we tap on the left window, where the cursor was last seen.
3404 *
3405 * After that, we inject one finger down onto the right window, and then a second finger down onto
3406 * the left window.
3407 * The touch is split, so this last gesture should cause 2 ACTION_DOWN events, one in the right
3408 * window (first), and then another on the left window (second).
3409 * This test reproduces a crash where there is a mismatch between the downTime and eventTime.
3410 * In the buggy implementation, second finger down on the left window would cause a crash.
3411 */
Siarhei Vishniakoued89cbb2023-10-13 10:42:44 -07003412TEST_F(InputDispatcherMultiDeviceTest, HoverTapAndSplitTouch_legacy) {
3413 SCOPED_FLAG_OVERRIDE(enable_multi_device_same_window_stream, false);
Siarhei Vishniakou6464e462023-02-06 18:57:59 -08003414 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07003415 sp<FakeWindowHandle> leftWindow = sp<FakeWindowHandle>::make(application, mDispatcher, "Left",
3416 ui::LogicalDisplayId::DEFAULT);
Siarhei Vishniakou6464e462023-02-06 18:57:59 -08003417 leftWindow->setFrame(Rect(0, 0, 200, 200));
3418
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07003419 sp<FakeWindowHandle> rightWindow = sp<FakeWindowHandle>::make(application, mDispatcher, "Right",
3420 ui::LogicalDisplayId::DEFAULT);
Siarhei Vishniakou6464e462023-02-06 18:57:59 -08003421 rightWindow->setFrame(Rect(200, 0, 400, 200));
3422
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07003423 mDispatcher->onWindowInfosChanged(
3424 {{*leftWindow->getInfo(), *rightWindow->getInfo()}, {}, 0, 0});
Siarhei Vishniakou6464e462023-02-06 18:57:59 -08003425
3426 const int32_t mouseDeviceId = 6;
3427 const int32_t touchDeviceId = 4;
3428 // Hover over the left window. Keep the cursor there.
3429 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07003430 injectMotionEvent(*mDispatcher,
Siarhei Vishniakou6464e462023-02-06 18:57:59 -08003431 MotionEventBuilder(AMOTION_EVENT_ACTION_HOVER_ENTER,
3432 AINPUT_SOURCE_MOUSE)
3433 .deviceId(mouseDeviceId)
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07003434 .pointer(PointerBuilder(0, ToolType::MOUSE).x(50).y(50))
Siarhei Vishniakou6464e462023-02-06 18:57:59 -08003435 .build()));
3436 leftWindow->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_ENTER));
3437
3438 // Tap on left window
3439 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07003440 injectMotionEvent(*mDispatcher,
Siarhei Vishniakou6464e462023-02-06 18:57:59 -08003441 MotionEventBuilder(AMOTION_EVENT_ACTION_DOWN,
3442 AINPUT_SOURCE_TOUCHSCREEN)
3443 .deviceId(touchDeviceId)
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07003444 .pointer(PointerBuilder(0, ToolType::FINGER).x(100).y(100))
Siarhei Vishniakou6464e462023-02-06 18:57:59 -08003445 .build()));
3446
3447 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07003448 injectMotionEvent(*mDispatcher,
Siarhei Vishniakou6464e462023-02-06 18:57:59 -08003449 MotionEventBuilder(AMOTION_EVENT_ACTION_UP,
3450 AINPUT_SOURCE_TOUCHSCREEN)
3451 .deviceId(touchDeviceId)
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07003452 .pointer(PointerBuilder(0, ToolType::FINGER).x(100).y(100))
Siarhei Vishniakou6464e462023-02-06 18:57:59 -08003453 .build()));
3454 leftWindow->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_EXIT));
3455 leftWindow->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_DOWN));
3456 leftWindow->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_UP));
3457
3458 // First finger down on right window
3459 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07003460 injectMotionEvent(*mDispatcher,
Siarhei Vishniakou6464e462023-02-06 18:57:59 -08003461 MotionEventBuilder(AMOTION_EVENT_ACTION_DOWN,
3462 AINPUT_SOURCE_TOUCHSCREEN)
3463 .deviceId(touchDeviceId)
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07003464 .pointer(PointerBuilder(0, ToolType::FINGER).x(300).y(100))
Siarhei Vishniakou6464e462023-02-06 18:57:59 -08003465 .build()));
3466 rightWindow->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_DOWN));
3467
3468 // Second finger down on the left window
3469 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07003470 injectMotionEvent(*mDispatcher,
Siarhei Vishniakou6464e462023-02-06 18:57:59 -08003471 MotionEventBuilder(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
3472 .deviceId(touchDeviceId)
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07003473 .pointer(PointerBuilder(0, ToolType::FINGER).x(300).y(100))
3474 .pointer(PointerBuilder(1, ToolType::FINGER).x(100).y(100))
Siarhei Vishniakou6464e462023-02-06 18:57:59 -08003475 .build()));
3476 leftWindow->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_DOWN));
3477 rightWindow->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_MOVE));
3478
3479 // No more events
3480 leftWindow->assertNoEvents();
3481 rightWindow->assertNoEvents();
3482}
3483
3484/**
Siarhei Vishniakoued89cbb2023-10-13 10:42:44 -07003485 * This test is similar to the test above, but the sequence of injected events is different.
3486 *
3487 * Two windows: a window on the left and a window on the right.
3488 * Mouse is hovered over the left window.
3489 * Next, we tap on the left window, where the cursor was last seen.
3490 *
3491 * After that, we send one finger down onto the right window, and then a second finger down onto
3492 * the left window.
3493 * The touch is split, so this last gesture should cause 2 ACTION_DOWN events, one in the right
3494 * window (first), and then another on the left window (second).
3495 * This test reproduces a crash where there is a mismatch between the downTime and eventTime.
3496 * In the buggy implementation, second finger down on the left window would cause a crash.
3497 */
3498TEST_F(InputDispatcherMultiDeviceTest, HoverTapAndSplitTouch) {
3499 SCOPED_FLAG_OVERRIDE(enable_multi_device_same_window_stream, true);
3500 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07003501 sp<FakeWindowHandle> leftWindow = sp<FakeWindowHandle>::make(application, mDispatcher, "Left",
3502 ui::LogicalDisplayId::DEFAULT);
Siarhei Vishniakoued89cbb2023-10-13 10:42:44 -07003503 leftWindow->setFrame(Rect(0, 0, 200, 200));
3504
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07003505 sp<FakeWindowHandle> rightWindow = sp<FakeWindowHandle>::make(application, mDispatcher, "Right",
3506 ui::LogicalDisplayId::DEFAULT);
Siarhei Vishniakoued89cbb2023-10-13 10:42:44 -07003507 rightWindow->setFrame(Rect(200, 0, 400, 200));
3508
3509 mDispatcher->onWindowInfosChanged(
3510 {{*leftWindow->getInfo(), *rightWindow->getInfo()}, {}, 0, 0});
3511
3512 const int32_t mouseDeviceId = 6;
3513 const int32_t touchDeviceId = 4;
3514 // Hover over the left window. Keep the cursor there.
3515 mDispatcher->notifyMotion(
3516 MotionArgsBuilder(AMOTION_EVENT_ACTION_HOVER_ENTER, AINPUT_SOURCE_MOUSE)
3517 .deviceId(mouseDeviceId)
3518 .pointer(PointerBuilder(0, ToolType::MOUSE).x(50).y(50))
3519 .build());
3520 leftWindow->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_ENTER));
3521
3522 // Tap on left window
3523 mDispatcher->notifyMotion(
3524 MotionArgsBuilder(AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
3525 .deviceId(touchDeviceId)
3526 .pointer(PointerBuilder(0, ToolType::FINGER).x(100).y(100))
3527 .build());
3528
3529 mDispatcher->notifyMotion(MotionArgsBuilder(AMOTION_EVENT_ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN)
3530 .deviceId(touchDeviceId)
3531 .pointer(PointerBuilder(0, ToolType::FINGER).x(100).y(100))
3532 .build());
3533 leftWindow->consumeMotionEvent(
3534 AllOf(WithMotionAction(AMOTION_EVENT_ACTION_DOWN), WithDeviceId(touchDeviceId)));
3535 leftWindow->consumeMotionEvent(
3536 AllOf(WithMotionAction(AMOTION_EVENT_ACTION_UP), WithDeviceId(touchDeviceId)));
3537
3538 // First finger down on right window
3539 mDispatcher->notifyMotion(
3540 MotionArgsBuilder(AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
3541 .deviceId(touchDeviceId)
3542 .pointer(PointerBuilder(0, ToolType::FINGER).x(300).y(100))
3543 .build());
3544 rightWindow->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_DOWN));
3545
3546 // Second finger down on the left window
3547 mDispatcher->notifyMotion(MotionArgsBuilder(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
3548 .deviceId(touchDeviceId)
3549 .pointer(PointerBuilder(0, ToolType::FINGER).x(300).y(100))
3550 .pointer(PointerBuilder(1, ToolType::FINGER).x(100).y(100))
3551 .build());
3552 leftWindow->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_DOWN));
3553 rightWindow->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_MOVE));
3554
3555 // No more events
3556 leftWindow->assertNoEvents();
3557 rightWindow->assertNoEvents();
3558}
3559
3560/**
Siarhei Vishniakou2e3e4432023-02-09 18:34:11 -08003561 * Start hovering with a stylus device, and then tap with a touch device. Ensure no crash occurs.
3562 * While the touch is down, new hover events from the stylus device should be ignored. After the
3563 * touch is gone, stylus hovering should start working again.
3564 */
Siarhei Vishniakou3ad54f52023-11-02 16:54:40 -07003565TEST_F(InputDispatcherMultiDeviceTest, StylusHoverIgnoresTouchTap) {
Siarhei Vishniakoued89cbb2023-10-13 10:42:44 -07003566 SCOPED_FLAG_OVERRIDE(enable_multi_device_same_window_stream, false);
Siarhei Vishniakou2e3e4432023-02-09 18:34:11 -08003567 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07003568 sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher, "Window",
3569 ui::LogicalDisplayId::DEFAULT);
Siarhei Vishniakou2e3e4432023-02-09 18:34:11 -08003570 window->setFrame(Rect(0, 0, 200, 200));
3571
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07003572 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Siarhei Vishniakou2e3e4432023-02-09 18:34:11 -08003573
3574 const int32_t stylusDeviceId = 5;
3575 const int32_t touchDeviceId = 4;
3576 // Start hovering with stylus
3577 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07003578 injectMotionEvent(*mDispatcher,
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -07003579 MotionEventBuilder(ACTION_HOVER_ENTER, AINPUT_SOURCE_STYLUS)
Siarhei Vishniakou2e3e4432023-02-09 18:34:11 -08003580 .deviceId(stylusDeviceId)
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07003581 .pointer(PointerBuilder(0, ToolType::STYLUS).x(50).y(50))
Siarhei Vishniakou2e3e4432023-02-09 18:34:11 -08003582 .build()));
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -07003583 window->consumeMotionEvent(WithMotionAction(ACTION_HOVER_ENTER));
Siarhei Vishniakou2e3e4432023-02-09 18:34:11 -08003584
3585 // Finger down on the window
3586 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07003587 injectMotionEvent(*mDispatcher,
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -07003588 MotionEventBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
Siarhei Vishniakou2e3e4432023-02-09 18:34:11 -08003589 .deviceId(touchDeviceId)
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07003590 .pointer(PointerBuilder(0, ToolType::FINGER).x(100).y(100))
Siarhei Vishniakou2e3e4432023-02-09 18:34:11 -08003591 .build()));
Siarhei Vishniakou3ad54f52023-11-02 16:54:40 -07003592 // The touch device should be ignored!
Siarhei Vishniakou2e3e4432023-02-09 18:34:11 -08003593
Siarhei Vishniakou2899c552023-07-10 18:20:46 -07003594 // Continue hovering with stylus.
3595 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07003596 injectMotionEvent(*mDispatcher,
Siarhei Vishniakou2e3e4432023-02-09 18:34:11 -08003597 MotionEventBuilder(AMOTION_EVENT_ACTION_HOVER_MOVE,
3598 AINPUT_SOURCE_STYLUS)
3599 .deviceId(stylusDeviceId)
Siarhei Vishniakou25537f82023-07-18 14:35:47 -07003600 .pointer(PointerBuilder(0, ToolType::STYLUS).x(60).y(60))
Siarhei Vishniakou2e3e4432023-02-09 18:34:11 -08003601 .build()));
Siarhei Vishniakou3ad54f52023-11-02 16:54:40 -07003602 // Hovers continue to work
3603 window->consumeMotionEvent(
3604 AllOf(WithMotionAction(ACTION_HOVER_MOVE), WithDeviceId(stylusDeviceId)));
Siarhei Vishniakou2e3e4432023-02-09 18:34:11 -08003605
3606 // Lift up the finger
3607 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07003608 injectMotionEvent(*mDispatcher,
Siarhei Vishniakou2e3e4432023-02-09 18:34:11 -08003609 MotionEventBuilder(AMOTION_EVENT_ACTION_UP,
3610 AINPUT_SOURCE_TOUCHSCREEN)
3611 .deviceId(touchDeviceId)
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07003612 .pointer(PointerBuilder(0, ToolType::FINGER).x(100).y(100))
Siarhei Vishniakou2e3e4432023-02-09 18:34:11 -08003613 .build()));
Siarhei Vishniakou2e3e4432023-02-09 18:34:11 -08003614
Siarhei Vishniakou2e3e4432023-02-09 18:34:11 -08003615 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07003616 injectMotionEvent(*mDispatcher,
Siarhei Vishniakou2e3e4432023-02-09 18:34:11 -08003617 MotionEventBuilder(AMOTION_EVENT_ACTION_HOVER_MOVE,
3618 AINPUT_SOURCE_STYLUS)
3619 .deviceId(stylusDeviceId)
Siarhei Vishniakou25537f82023-07-18 14:35:47 -07003620 .pointer(PointerBuilder(0, ToolType::STYLUS).x(70).y(70))
Siarhei Vishniakou2e3e4432023-02-09 18:34:11 -08003621 .build()));
Siarhei Vishniakou3ad54f52023-11-02 16:54:40 -07003622 window->consumeMotionEvent(
3623 AllOf(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_MOVE), WithDeviceId(stylusDeviceId)));
Siarhei Vishniakou2e3e4432023-02-09 18:34:11 -08003624 window->assertNoEvents();
3625}
3626
3627/**
Siarhei Vishniakoued89cbb2023-10-13 10:42:44 -07003628 * Start hovering with a stylus device, and then tap with a touch device. Ensure no crash occurs.
3629 * While the touch is down, hovering from the stylus is not affected. After the touch is gone,
3630 * check that the stylus hovering continues to work.
3631 */
3632TEST_F(InputDispatcherMultiDeviceTest, StylusHoverWithTouchTap) {
3633 SCOPED_FLAG_OVERRIDE(enable_multi_device_same_window_stream, true);
3634 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07003635 sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher, "Window",
3636 ui::LogicalDisplayId::DEFAULT);
Siarhei Vishniakoued89cbb2023-10-13 10:42:44 -07003637 window->setFrame(Rect(0, 0, 200, 200));
3638
3639 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
3640
3641 const int32_t stylusDeviceId = 5;
3642 const int32_t touchDeviceId = 4;
3643 // Start hovering with stylus
3644 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_ENTER, AINPUT_SOURCE_STYLUS)
3645 .deviceId(stylusDeviceId)
3646 .pointer(PointerBuilder(0, ToolType::STYLUS).x(50).y(50))
3647 .build());
3648 window->consumeMotionEvent(WithMotionAction(ACTION_HOVER_ENTER));
3649
3650 // Finger down on the window
3651 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
3652 .deviceId(touchDeviceId)
3653 .pointer(PointerBuilder(0, ToolType::FINGER).x(100).y(100))
3654 .build());
3655 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(touchDeviceId)));
3656
3657 // Continue hovering with stylus.
3658 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_MOVE, AINPUT_SOURCE_STYLUS)
3659 .deviceId(stylusDeviceId)
3660 .pointer(PointerBuilder(0, ToolType::STYLUS).x(60).y(60))
3661 .build());
3662 // Hovers continue to work
3663 window->consumeMotionEvent(
3664 AllOf(WithMotionAction(ACTION_HOVER_MOVE), WithDeviceId(stylusDeviceId)));
3665
3666 // Lift up the finger
3667 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN)
3668 .deviceId(touchDeviceId)
3669 .pointer(PointerBuilder(0, ToolType::FINGER).x(100).y(100))
3670 .build());
3671 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_UP), WithDeviceId(touchDeviceId)));
3672
3673 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_MOVE, AINPUT_SOURCE_STYLUS)
3674 .deviceId(stylusDeviceId)
3675 .pointer(PointerBuilder(0, ToolType::STYLUS).x(70).y(70))
3676 .build());
3677 window->consumeMotionEvent(
3678 AllOf(WithMotionAction(ACTION_HOVER_MOVE), WithDeviceId(stylusDeviceId)));
3679 window->assertNoEvents();
3680}
3681
3682/**
Siarhei Vishniakouf77f60a2023-10-23 17:26:05 -07003683 * If stylus is down anywhere on the screen, then touches should not be delivered to windows that
3684 * have InputConfig::GLOBAL_STYLUS_BLOCKS_TOUCH.
3685 *
3686 * Two windows: one on the left and one on the right.
3687 * The window on the right has GLOBAL_STYLUS_BLOCKS_TOUCH config.
3688 * Stylus down on the left window, and then touch down on the right window.
3689 * Check that the right window doesn't get touches while the stylus is down on the left window.
3690 */
3691TEST_F(InputDispatcherMultiDeviceTest, GlobalStylusDownBlocksTouch) {
3692 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
3693 sp<FakeWindowHandle> leftWindow =
3694 sp<FakeWindowHandle>::make(application, mDispatcher, "Left window",
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07003695 ui::LogicalDisplayId::DEFAULT);
Siarhei Vishniakouf77f60a2023-10-23 17:26:05 -07003696 leftWindow->setFrame(Rect(0, 0, 100, 100));
3697
3698 sp<FakeWindowHandle> sbtRightWindow =
3699 sp<FakeWindowHandle>::make(application, mDispatcher,
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07003700 "Stylus blocks touch (right) window",
3701 ui::LogicalDisplayId::DEFAULT);
Siarhei Vishniakouf77f60a2023-10-23 17:26:05 -07003702 sbtRightWindow->setFrame(Rect(100, 100, 200, 200));
3703 sbtRightWindow->setGlobalStylusBlocksTouch(true);
3704
3705 mDispatcher->onWindowInfosChanged(
3706 {{*leftWindow->getInfo(), *sbtRightWindow->getInfo()}, {}, 0, 0});
3707
3708 const int32_t stylusDeviceId = 5;
3709 const int32_t touchDeviceId = 4;
3710
3711 // Stylus down in the left window
3712 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_STYLUS)
3713 .pointer(PointerBuilder(0, ToolType::STYLUS).x(50).y(52))
3714 .deviceId(stylusDeviceId)
3715 .build());
3716 leftWindow->consumeMotionEvent(
3717 AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(stylusDeviceId)));
3718
3719 // Finger tap on the right window
3720 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
3721 .pointer(PointerBuilder(0, ToolType::FINGER).x(150).y(151))
3722 .deviceId(touchDeviceId)
3723 .build());
3724 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN)
3725 .pointer(PointerBuilder(0, ToolType::FINGER).x(150).y(151))
3726 .deviceId(touchDeviceId)
3727 .build());
3728
3729 // The touch should be blocked, because stylus is down somewhere else on screen!
3730 sbtRightWindow->assertNoEvents();
3731
3732 // Continue stylus motion, and ensure it's not impacted.
3733 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_STYLUS)
3734 .pointer(PointerBuilder(0, ToolType::STYLUS).x(51).y(53))
3735 .deviceId(stylusDeviceId)
3736 .build());
3737 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_UP, AINPUT_SOURCE_STYLUS)
3738 .pointer(PointerBuilder(0, ToolType::STYLUS).x(51).y(53))
3739 .deviceId(stylusDeviceId)
3740 .build());
3741 leftWindow->consumeMotionEvent(
3742 AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(stylusDeviceId)));
3743 leftWindow->consumeMotionEvent(
3744 AllOf(WithMotionAction(ACTION_UP), WithDeviceId(stylusDeviceId)));
3745
3746 // Now that the stylus gesture is done, touches should be getting delivered correctly.
3747 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
3748 .pointer(PointerBuilder(0, ToolType::FINGER).x(151).y(153))
3749 .deviceId(touchDeviceId)
3750 .build());
3751 sbtRightWindow->consumeMotionEvent(
3752 AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(touchDeviceId)));
3753}
3754
3755/**
3756 * If stylus is hovering anywhere on the screen, then touches should not be delivered to windows
3757 * that have InputConfig::GLOBAL_STYLUS_BLOCKS_TOUCH.
3758 *
3759 * Two windows: one on the left and one on the right.
3760 * The window on the right has GLOBAL_STYLUS_BLOCKS_TOUCH config.
3761 * Stylus hover on the left window, and then touch down on the right window.
3762 * Check that the right window doesn't get touches while the stylus is hovering on the left window.
3763 */
3764TEST_F(InputDispatcherMultiDeviceTest, GlobalStylusHoverBlocksTouch) {
3765 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
3766 sp<FakeWindowHandle> leftWindow =
3767 sp<FakeWindowHandle>::make(application, mDispatcher, "Left window",
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07003768 ui::LogicalDisplayId::DEFAULT);
Siarhei Vishniakouf77f60a2023-10-23 17:26:05 -07003769 leftWindow->setFrame(Rect(0, 0, 100, 100));
3770
3771 sp<FakeWindowHandle> sbtRightWindow =
3772 sp<FakeWindowHandle>::make(application, mDispatcher,
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07003773 "Stylus blocks touch (right) window",
3774 ui::LogicalDisplayId::DEFAULT);
Siarhei Vishniakouf77f60a2023-10-23 17:26:05 -07003775 sbtRightWindow->setFrame(Rect(100, 100, 200, 200));
3776 sbtRightWindow->setGlobalStylusBlocksTouch(true);
3777
3778 mDispatcher->onWindowInfosChanged(
3779 {{*leftWindow->getInfo(), *sbtRightWindow->getInfo()}, {}, 0, 0});
3780
3781 const int32_t stylusDeviceId = 5;
3782 const int32_t touchDeviceId = 4;
3783
3784 // Stylus hover in the left window
3785 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_ENTER, AINPUT_SOURCE_STYLUS)
3786 .pointer(PointerBuilder(0, ToolType::STYLUS).x(50).y(52))
3787 .deviceId(stylusDeviceId)
3788 .build());
3789 leftWindow->consumeMotionEvent(
3790 AllOf(WithMotionAction(ACTION_HOVER_ENTER), WithDeviceId(stylusDeviceId)));
3791
3792 // Finger tap on the right window
3793 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
3794 .pointer(PointerBuilder(0, ToolType::FINGER).x(150).y(151))
3795 .deviceId(touchDeviceId)
3796 .build());
3797 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN)
3798 .pointer(PointerBuilder(0, ToolType::FINGER).x(150).y(151))
3799 .deviceId(touchDeviceId)
3800 .build());
3801
3802 // The touch should be blocked, because stylus is hovering somewhere else on screen!
3803 sbtRightWindow->assertNoEvents();
3804
3805 // Continue stylus motion, and ensure it's not impacted.
3806 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_MOVE, AINPUT_SOURCE_STYLUS)
3807 .pointer(PointerBuilder(0, ToolType::STYLUS).x(51).y(53))
3808 .deviceId(stylusDeviceId)
3809 .build());
3810 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_EXIT, AINPUT_SOURCE_STYLUS)
3811 .pointer(PointerBuilder(0, ToolType::STYLUS).x(51).y(53))
3812 .deviceId(stylusDeviceId)
3813 .build());
3814 leftWindow->consumeMotionEvent(
3815 AllOf(WithMotionAction(ACTION_HOVER_MOVE), WithDeviceId(stylusDeviceId)));
3816 leftWindow->consumeMotionEvent(
3817 AllOf(WithMotionAction(ACTION_HOVER_EXIT), WithDeviceId(stylusDeviceId)));
3818
3819 // Now that the stylus gesture is done, touches should be getting delivered correctly.
3820 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
3821 .pointer(PointerBuilder(0, ToolType::FINGER).x(151).y(153))
3822 .deviceId(touchDeviceId)
3823 .build());
3824 sbtRightWindow->consumeMotionEvent(
3825 AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(touchDeviceId)));
3826}
3827
3828/**
Siarhei Vishniakouf372b812023-02-14 18:06:51 -08003829 * A spy window above a window with no input channel.
3830 * Start hovering with a stylus device, and then tap with it.
3831 * Ensure spy window receives the entire sequence.
3832 */
3833TEST_F(InputDispatcherTest, StylusHoverAndDownNoInputChannel) {
3834 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07003835 sp<FakeWindowHandle> spyWindow = sp<FakeWindowHandle>::make(application, mDispatcher, "Spy",
3836 ui::LogicalDisplayId::DEFAULT);
Siarhei Vishniakouf372b812023-02-14 18:06:51 -08003837 spyWindow->setFrame(Rect(0, 0, 200, 200));
3838 spyWindow->setTrustedOverlay(true);
3839 spyWindow->setSpy(true);
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07003840 sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher, "Window",
3841 ui::LogicalDisplayId::DEFAULT);
Siarhei Vishniakouf372b812023-02-14 18:06:51 -08003842 window->setNoInputChannel(true);
3843 window->setFrame(Rect(0, 0, 200, 200));
3844
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07003845 mDispatcher->onWindowInfosChanged({{*spyWindow->getInfo(), *window->getInfo()}, {}, 0, 0});
Siarhei Vishniakouf372b812023-02-14 18:06:51 -08003846
Siarhei Vishniakouf372b812023-02-14 18:06:51 -08003847 // Start hovering with stylus
Prabir Pradhan678438e2023-04-13 19:32:51 +00003848 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_ENTER, AINPUT_SOURCE_STYLUS)
3849 .pointer(PointerBuilder(0, ToolType::STYLUS).x(50).y(50))
3850 .build());
Siarhei Vishniakouf372b812023-02-14 18:06:51 -08003851 spyWindow->consumeMotionEvent(WithMotionAction(ACTION_HOVER_ENTER));
3852 // Stop hovering
Prabir Pradhan678438e2023-04-13 19:32:51 +00003853 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_EXIT, AINPUT_SOURCE_STYLUS)
3854 .pointer(PointerBuilder(0, ToolType::STYLUS).x(50).y(50))
3855 .build());
Siarhei Vishniakouf372b812023-02-14 18:06:51 -08003856 spyWindow->consumeMotionEvent(WithMotionAction(ACTION_HOVER_EXIT));
3857
3858 // Stylus touches down
Prabir Pradhan678438e2023-04-13 19:32:51 +00003859 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_STYLUS)
3860 .pointer(PointerBuilder(0, ToolType::STYLUS).x(50).y(50))
3861 .build());
Siarhei Vishniakouf372b812023-02-14 18:06:51 -08003862 spyWindow->consumeMotionEvent(WithMotionAction(ACTION_DOWN));
3863
3864 // Stylus goes up
Prabir Pradhan678438e2023-04-13 19:32:51 +00003865 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_UP, AINPUT_SOURCE_STYLUS)
3866 .pointer(PointerBuilder(0, ToolType::STYLUS).x(50).y(50))
3867 .build());
Siarhei Vishniakouf372b812023-02-14 18:06:51 -08003868 spyWindow->consumeMotionEvent(WithMotionAction(ACTION_UP));
3869
3870 // Again hover
Prabir Pradhan678438e2023-04-13 19:32:51 +00003871 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_ENTER, AINPUT_SOURCE_STYLUS)
3872 .pointer(PointerBuilder(0, ToolType::STYLUS).x(50).y(50))
3873 .build());
Siarhei Vishniakouf372b812023-02-14 18:06:51 -08003874 spyWindow->consumeMotionEvent(WithMotionAction(ACTION_HOVER_ENTER));
3875 // Stop hovering
Prabir Pradhan678438e2023-04-13 19:32:51 +00003876 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_EXIT, AINPUT_SOURCE_STYLUS)
3877 .pointer(PointerBuilder(0, ToolType::STYLUS).x(50).y(50))
3878 .build());
Siarhei Vishniakouf372b812023-02-14 18:06:51 -08003879 spyWindow->consumeMotionEvent(WithMotionAction(ACTION_HOVER_EXIT));
3880
3881 // No more events
3882 spyWindow->assertNoEvents();
3883 window->assertNoEvents();
3884}
3885
3886/**
Siarhei Vishniakou6b71b632023-10-27 21:34:46 -07003887 * A stale stylus HOVER_EXIT event is injected. Since it's a stale event, it should generally be
3888 * rejected. But since we already have an ongoing gesture, this event should be processed.
3889 * This prevents inconsistent events being handled inside the dispatcher.
3890 */
3891TEST_F(InputDispatcherTest, StaleStylusHoverGestureIsComplete) {
3892 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
3893
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07003894 sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher, "Window",
3895 ui::LogicalDisplayId::DEFAULT);
Siarhei Vishniakou6b71b632023-10-27 21:34:46 -07003896 window->setFrame(Rect(0, 0, 200, 200));
3897
3898 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
3899
3900 // Start hovering with stylus
3901 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_ENTER, AINPUT_SOURCE_STYLUS)
3902 .pointer(PointerBuilder(0, ToolType::STYLUS).x(50).y(50))
3903 .build());
3904 window->consumeMotionEvent(WithMotionAction(ACTION_HOVER_ENTER));
3905
3906 NotifyMotionArgs hoverExit = MotionArgsBuilder(ACTION_HOVER_EXIT, AINPUT_SOURCE_STYLUS)
3907 .pointer(PointerBuilder(0, ToolType::STYLUS).x(50).y(50))
3908 .build();
3909 // Make this 'hoverExit' event stale
3910 mFakePolicy->setStaleEventTimeout(100ms);
3911 std::this_thread::sleep_for(100ms);
3912
3913 // It shouldn't be dropped by the dispatcher, even though it's stale.
3914 mDispatcher->notifyMotion(hoverExit);
3915 window->consumeMotionEvent(WithMotionAction(ACTION_HOVER_EXIT));
3916
3917 // Stylus starts hovering again! There should be no crash.
3918 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_ENTER, AINPUT_SOURCE_STYLUS)
3919 .pointer(PointerBuilder(0, ToolType::STYLUS).x(51).y(51))
3920 .build());
3921 window->consumeMotionEvent(WithMotionAction(ACTION_HOVER_ENTER));
3922}
3923
3924/**
Siarhei Vishniakouf372b812023-02-14 18:06:51 -08003925 * Start hovering with a mouse, and then tap with a touch device. Pilfer the touch stream.
3926 * Next, click with the mouse device. Both windows (spy and regular) should receive the new mouse
3927 * ACTION_DOWN event because that's a new gesture, and pilfering should no longer be active.
3928 * While the mouse is down, new move events from the touch device should be ignored.
3929 */
Siarhei Vishniakoued89cbb2023-10-13 10:42:44 -07003930TEST_F(InputDispatcherTest, TouchPilferAndMouseMove_legacy) {
3931 SCOPED_FLAG_OVERRIDE(enable_multi_device_same_window_stream, false);
Siarhei Vishniakouf372b812023-02-14 18:06:51 -08003932 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07003933 sp<FakeWindowHandle> spyWindow = sp<FakeWindowHandle>::make(application, mDispatcher, "Spy",
3934 ui::LogicalDisplayId::DEFAULT);
Siarhei Vishniakouf372b812023-02-14 18:06:51 -08003935 spyWindow->setFrame(Rect(0, 0, 200, 200));
3936 spyWindow->setTrustedOverlay(true);
3937 spyWindow->setSpy(true);
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07003938 sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher, "Window",
3939 ui::LogicalDisplayId::DEFAULT);
Siarhei Vishniakouf372b812023-02-14 18:06:51 -08003940 window->setFrame(Rect(0, 0, 200, 200));
3941
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07003942 mDispatcher->onWindowInfosChanged({{*spyWindow->getInfo(), *window->getInfo()}, {}, 0, 0});
Siarhei Vishniakouf372b812023-02-14 18:06:51 -08003943
3944 const int32_t mouseDeviceId = 7;
3945 const int32_t touchDeviceId = 4;
Siarhei Vishniakouf372b812023-02-14 18:06:51 -08003946
3947 // Hover a bit with mouse first
Prabir Pradhan678438e2023-04-13 19:32:51 +00003948 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_ENTER, AINPUT_SOURCE_MOUSE)
3949 .deviceId(mouseDeviceId)
3950 .pointer(PointerBuilder(0, ToolType::MOUSE).x(100).y(100))
3951 .build());
Siarhei Vishniakouf372b812023-02-14 18:06:51 -08003952 spyWindow->consumeMotionEvent(
3953 AllOf(WithMotionAction(ACTION_HOVER_ENTER), WithDeviceId(mouseDeviceId)));
3954 window->consumeMotionEvent(
3955 AllOf(WithMotionAction(ACTION_HOVER_ENTER), WithDeviceId(mouseDeviceId)));
3956
3957 // Start touching
Prabir Pradhan678438e2023-04-13 19:32:51 +00003958 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
3959 .deviceId(touchDeviceId)
3960 .pointer(PointerBuilder(0, ToolType::FINGER).x(50).y(50))
3961 .build());
Siarhei Vishniakouf372b812023-02-14 18:06:51 -08003962 spyWindow->consumeMotionEvent(WithMotionAction(ACTION_HOVER_EXIT));
3963 window->consumeMotionEvent(WithMotionAction(ACTION_HOVER_EXIT));
3964 spyWindow->consumeMotionEvent(WithMotionAction(ACTION_DOWN));
3965 window->consumeMotionEvent(WithMotionAction(ACTION_DOWN));
3966
Prabir Pradhan678438e2023-04-13 19:32:51 +00003967 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN)
3968 .deviceId(touchDeviceId)
3969 .pointer(PointerBuilder(0, ToolType::FINGER).x(55).y(55))
3970 .build());
Siarhei Vishniakouf372b812023-02-14 18:06:51 -08003971 spyWindow->consumeMotionEvent(WithMotionAction(ACTION_MOVE));
3972 window->consumeMotionEvent(WithMotionAction(ACTION_MOVE));
3973
3974 // Pilfer the stream
3975 EXPECT_EQ(OK, mDispatcher->pilferPointers(spyWindow->getToken()));
3976 window->consumeMotionEvent(WithMotionAction(ACTION_CANCEL));
3977
Prabir Pradhan678438e2023-04-13 19:32:51 +00003978 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN)
3979 .deviceId(touchDeviceId)
3980 .pointer(PointerBuilder(0, ToolType::FINGER).x(60).y(60))
3981 .build());
Siarhei Vishniakouf372b812023-02-14 18:06:51 -08003982 spyWindow->consumeMotionEvent(WithMotionAction(ACTION_MOVE));
3983
3984 // Mouse down
Prabir Pradhan678438e2023-04-13 19:32:51 +00003985 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_MOUSE)
3986 .deviceId(mouseDeviceId)
3987 .buttonState(AMOTION_EVENT_BUTTON_PRIMARY)
3988 .pointer(PointerBuilder(0, ToolType::MOUSE).x(100).y(100))
3989 .build());
Siarhei Vishniakouf372b812023-02-14 18:06:51 -08003990
3991 spyWindow->consumeMotionEvent(
3992 AllOf(WithMotionAction(ACTION_CANCEL), WithDeviceId(touchDeviceId)));
3993 spyWindow->consumeMotionEvent(
3994 AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(mouseDeviceId)));
3995 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(mouseDeviceId)));
3996
Prabir Pradhan678438e2023-04-13 19:32:51 +00003997 mDispatcher->notifyMotion(
3998 MotionArgsBuilder(AMOTION_EVENT_ACTION_BUTTON_PRESS, AINPUT_SOURCE_MOUSE)
3999 .deviceId(mouseDeviceId)
4000 .buttonState(AMOTION_EVENT_BUTTON_PRIMARY)
4001 .actionButton(AMOTION_EVENT_BUTTON_PRIMARY)
4002 .pointer(PointerBuilder(0, ToolType::MOUSE).x(100).y(100))
4003 .build());
Siarhei Vishniakouf372b812023-02-14 18:06:51 -08004004 spyWindow->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_BUTTON_PRESS));
4005 window->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_BUTTON_PRESS));
4006
4007 // Mouse move!
Prabir Pradhan678438e2023-04-13 19:32:51 +00004008 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_MOUSE)
4009 .deviceId(mouseDeviceId)
4010 .buttonState(AMOTION_EVENT_BUTTON_PRIMARY)
4011 .pointer(PointerBuilder(0, ToolType::MOUSE).x(110).y(110))
4012 .build());
Siarhei Vishniakouf372b812023-02-14 18:06:51 -08004013 spyWindow->consumeMotionEvent(WithMotionAction(ACTION_MOVE));
4014 window->consumeMotionEvent(WithMotionAction(ACTION_MOVE));
4015
4016 // Touch move!
Prabir Pradhan678438e2023-04-13 19:32:51 +00004017 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN)
4018 .deviceId(touchDeviceId)
4019 .pointer(PointerBuilder(0, ToolType::FINGER).x(65).y(65))
4020 .build());
Siarhei Vishniakouf372b812023-02-14 18:06:51 -08004021
4022 // No more events
4023 spyWindow->assertNoEvents();
4024 window->assertNoEvents();
4025}
4026
4027/**
Siarhei Vishniakoued89cbb2023-10-13 10:42:44 -07004028 * Start hovering with a mouse, and then tap with a touch device. Pilfer the touch stream.
4029 * Next, click with the mouse device. Both windows (spy and regular) should receive the new mouse
4030 * ACTION_DOWN event because that's a new gesture, and pilfering should no longer be active.
4031 * While the mouse is down, new move events from the touch device should continue to work.
4032 */
4033TEST_F(InputDispatcherTest, TouchPilferAndMouseMove) {
4034 SCOPED_FLAG_OVERRIDE(enable_multi_device_same_window_stream, true);
4035 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07004036 sp<FakeWindowHandle> spyWindow = sp<FakeWindowHandle>::make(application, mDispatcher, "Spy",
4037 ui::LogicalDisplayId::DEFAULT);
Siarhei Vishniakoued89cbb2023-10-13 10:42:44 -07004038 spyWindow->setFrame(Rect(0, 0, 200, 200));
4039 spyWindow->setTrustedOverlay(true);
4040 spyWindow->setSpy(true);
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07004041 sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher, "Window",
4042 ui::LogicalDisplayId::DEFAULT);
Siarhei Vishniakoued89cbb2023-10-13 10:42:44 -07004043 window->setFrame(Rect(0, 0, 200, 200));
4044
4045 mDispatcher->onWindowInfosChanged({{*spyWindow->getInfo(), *window->getInfo()}, {}, 0, 0});
4046
4047 const int32_t mouseDeviceId = 7;
4048 const int32_t touchDeviceId = 4;
4049
4050 // Hover a bit with mouse first
4051 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_ENTER, AINPUT_SOURCE_MOUSE)
4052 .deviceId(mouseDeviceId)
4053 .pointer(PointerBuilder(0, ToolType::MOUSE).x(100).y(100))
4054 .build());
4055 spyWindow->consumeMotionEvent(
4056 AllOf(WithMotionAction(ACTION_HOVER_ENTER), WithDeviceId(mouseDeviceId)));
4057 window->consumeMotionEvent(
4058 AllOf(WithMotionAction(ACTION_HOVER_ENTER), WithDeviceId(mouseDeviceId)));
4059
4060 // Start touching
4061 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
4062 .deviceId(touchDeviceId)
4063 .pointer(PointerBuilder(0, ToolType::FINGER).x(50).y(50))
4064 .build());
4065
4066 spyWindow->consumeMotionEvent(WithMotionAction(ACTION_DOWN));
4067 window->consumeMotionEvent(WithMotionAction(ACTION_DOWN));
4068
4069 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN)
4070 .deviceId(touchDeviceId)
4071 .pointer(PointerBuilder(0, ToolType::FINGER).x(55).y(55))
4072 .build());
4073 spyWindow->consumeMotionEvent(WithMotionAction(ACTION_MOVE));
4074 window->consumeMotionEvent(WithMotionAction(ACTION_MOVE));
4075
4076 // Pilfer the stream
4077 EXPECT_EQ(OK, mDispatcher->pilferPointers(spyWindow->getToken()));
4078 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_CANCEL), WithDeviceId(touchDeviceId)));
4079 // Hover is not pilfered! Only touch.
4080
4081 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN)
4082 .deviceId(touchDeviceId)
4083 .pointer(PointerBuilder(0, ToolType::FINGER).x(60).y(60))
4084 .build());
4085 spyWindow->consumeMotionEvent(WithMotionAction(ACTION_MOVE));
4086
4087 // Mouse down
4088 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_MOUSE)
4089 .deviceId(mouseDeviceId)
4090 .buttonState(AMOTION_EVENT_BUTTON_PRIMARY)
4091 .pointer(PointerBuilder(0, ToolType::MOUSE).x(100).y(100))
4092 .build());
4093
4094 spyWindow->consumeMotionEvent(
4095 AllOf(WithMotionAction(ACTION_HOVER_EXIT), WithDeviceId(mouseDeviceId)));
4096 spyWindow->consumeMotionEvent(
4097 AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(mouseDeviceId)));
4098 window->consumeMotionEvent(
4099 AllOf(WithMotionAction(ACTION_HOVER_EXIT), WithDeviceId(mouseDeviceId)));
4100 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(mouseDeviceId)));
4101
4102 mDispatcher->notifyMotion(
4103 MotionArgsBuilder(AMOTION_EVENT_ACTION_BUTTON_PRESS, AINPUT_SOURCE_MOUSE)
4104 .deviceId(mouseDeviceId)
4105 .buttonState(AMOTION_EVENT_BUTTON_PRIMARY)
4106 .actionButton(AMOTION_EVENT_BUTTON_PRIMARY)
4107 .pointer(PointerBuilder(0, ToolType::MOUSE).x(100).y(100))
4108 .build());
4109 spyWindow->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_BUTTON_PRESS));
4110 window->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_BUTTON_PRESS));
4111
4112 // Mouse move!
4113 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_MOUSE)
4114 .deviceId(mouseDeviceId)
4115 .buttonState(AMOTION_EVENT_BUTTON_PRIMARY)
4116 .pointer(PointerBuilder(0, ToolType::MOUSE).x(110).y(110))
4117 .build());
4118 spyWindow->consumeMotionEvent(
4119 AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(mouseDeviceId)));
4120 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(mouseDeviceId)));
4121
4122 // Touch move!
4123 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN)
4124 .deviceId(touchDeviceId)
4125 .pointer(PointerBuilder(0, ToolType::FINGER).x(65).y(65))
4126 .build());
4127 spyWindow->consumeMotionEvent(
4128 AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(touchDeviceId)));
4129
4130 // No more events
4131 spyWindow->assertNoEvents();
4132 window->assertNoEvents();
4133}
4134
4135/**
Siarhei Vishniakoua16e3a22022-03-02 15:26:40 -08004136 * On the display, have a single window, and also an area where there's no window.
4137 * First pointer touches the "no window" area of the screen. Second pointer touches the window.
4138 * Make sure that the window receives the second pointer, and first pointer is simply ignored.
4139 */
4140TEST_F(InputDispatcherTest, SplitWorksWhenEmptyAreaIsTouched) {
4141 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
4142 sp<FakeWindowHandle> window =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07004143 sp<FakeWindowHandle>::make(application, mDispatcher, "Window", DISPLAY_ID);
Siarhei Vishniakoua16e3a22022-03-02 15:26:40 -08004144
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07004145 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Siarhei Vishniakoua16e3a22022-03-02 15:26:40 -08004146
4147 // Touch down on the empty space
Prabir Pradhan678438e2023-04-13 19:32:51 +00004148 mDispatcher->notifyMotion(generateTouchArgs(AMOTION_EVENT_ACTION_DOWN, {{-1, -1}}));
Siarhei Vishniakoua16e3a22022-03-02 15:26:40 -08004149
4150 mDispatcher->waitForIdle();
4151 window->assertNoEvents();
4152
4153 // Now touch down on the window with another pointer
Prabir Pradhan678438e2023-04-13 19:32:51 +00004154 mDispatcher->notifyMotion(generateTouchArgs(POINTER_1_DOWN, {{-1, -1}, {10, 10}}));
Siarhei Vishniakoua16e3a22022-03-02 15:26:40 -08004155 mDispatcher->waitForIdle();
4156 window->consumeMotionDown();
4157}
4158
4159/**
4160 * Same test as above, but instead of touching the empty space, the first touch goes to
4161 * non-touchable window.
4162 */
4163TEST_F(InputDispatcherTest, SplitWorksWhenNonTouchableWindowIsTouched) {
4164 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
4165 sp<FakeWindowHandle> window1 =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07004166 sp<FakeWindowHandle>::make(application, mDispatcher, "Window1", DISPLAY_ID);
Siarhei Vishniakoua16e3a22022-03-02 15:26:40 -08004167 window1->setTouchableRegion(Region{{0, 0, 100, 100}});
4168 window1->setTouchable(false);
4169 sp<FakeWindowHandle> window2 =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07004170 sp<FakeWindowHandle>::make(application, mDispatcher, "Window2", DISPLAY_ID);
Siarhei Vishniakoua16e3a22022-03-02 15:26:40 -08004171 window2->setTouchableRegion(Region{{100, 0, 200, 100}});
4172
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07004173 mDispatcher->onWindowInfosChanged({{*window1->getInfo(), *window2->getInfo()}, {}, 0, 0});
Siarhei Vishniakoua16e3a22022-03-02 15:26:40 -08004174
Siarhei Vishniakoua16e3a22022-03-02 15:26:40 -08004175 // Touch down on the non-touchable window
Prabir Pradhan678438e2023-04-13 19:32:51 +00004176 mDispatcher->notifyMotion(generateTouchArgs(AMOTION_EVENT_ACTION_DOWN, {{50, 50}}));
Siarhei Vishniakoua16e3a22022-03-02 15:26:40 -08004177
4178 mDispatcher->waitForIdle();
4179 window1->assertNoEvents();
4180 window2->assertNoEvents();
4181
4182 // Now touch down on the window with another pointer
Prabir Pradhan678438e2023-04-13 19:32:51 +00004183 mDispatcher->notifyMotion(generateTouchArgs(POINTER_1_DOWN, {{50, 50}, {150, 50}}));
Siarhei Vishniakoua16e3a22022-03-02 15:26:40 -08004184 mDispatcher->waitForIdle();
4185 window2->consumeMotionDown();
4186}
4187
Vaibhav Devmurari882bd9b2022-06-23 14:54:54 +00004188/**
4189 * When splitting touch events the downTime should be adjusted such that the downTime corresponds
4190 * to the event time of the first ACTION_DOWN sent to the particular window.
4191 */
4192TEST_F(InputDispatcherTest, SplitTouchesSendCorrectActionDownTime) {
4193 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
4194 sp<FakeWindowHandle> window1 =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07004195 sp<FakeWindowHandle>::make(application, mDispatcher, "Window1", DISPLAY_ID);
Vaibhav Devmurari882bd9b2022-06-23 14:54:54 +00004196 window1->setTouchableRegion(Region{{0, 0, 100, 100}});
4197 sp<FakeWindowHandle> window2 =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07004198 sp<FakeWindowHandle>::make(application, mDispatcher, "Window2", DISPLAY_ID);
Vaibhav Devmurari882bd9b2022-06-23 14:54:54 +00004199 window2->setTouchableRegion(Region{{100, 0, 200, 100}});
4200
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07004201 mDispatcher->onWindowInfosChanged({{*window1->getInfo(), *window2->getInfo()}, {}, 0, 0});
Vaibhav Devmurari882bd9b2022-06-23 14:54:54 +00004202
Vaibhav Devmurari882bd9b2022-06-23 14:54:54 +00004203 // Touch down on the first window
Prabir Pradhan678438e2023-04-13 19:32:51 +00004204 mDispatcher->notifyMotion(generateTouchArgs(AMOTION_EVENT_ACTION_DOWN, {{50, 50}}));
Vaibhav Devmurari882bd9b2022-06-23 14:54:54 +00004205 mDispatcher->waitForIdle();
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07004206
Prabir Pradhan9d5f9ce2024-01-24 00:03:41 +00004207 const std::unique_ptr<MotionEvent> firstDown =
4208 window1->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN)));
4209 ASSERT_EQ(firstDown->getDownTime(), firstDown->getEventTime());
Vaibhav Devmurari882bd9b2022-06-23 14:54:54 +00004210 window2->assertNoEvents();
Vaibhav Devmurari882bd9b2022-06-23 14:54:54 +00004211
4212 // Now touch down on the window with another pointer
Prabir Pradhan678438e2023-04-13 19:32:51 +00004213 mDispatcher->notifyMotion(generateTouchArgs(POINTER_1_DOWN, {{50, 50}, {150, 50}}));
Vaibhav Devmurari882bd9b2022-06-23 14:54:54 +00004214 mDispatcher->waitForIdle();
Prabir Pradhan9d5f9ce2024-01-24 00:03:41 +00004215
4216 const std::unique_ptr<MotionEvent> secondDown =
4217 window2->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN)));
4218 ASSERT_EQ(secondDown->getDownTime(), secondDown->getEventTime());
4219 ASSERT_NE(firstDown->getDownTime(), secondDown->getDownTime());
4220 // We currently send MOVE events to all windows receiving a split touch when there is any change
4221 // in the touch state, even when none of the pointers in the split window actually moved.
4222 // Document this behavior in the test.
4223 window1->consumeMotionMove();
Vaibhav Devmurari882bd9b2022-06-23 14:54:54 +00004224
4225 // Now move the pointer on the second window
Prabir Pradhan678438e2023-04-13 19:32:51 +00004226 mDispatcher->notifyMotion(generateTouchArgs(AMOTION_EVENT_ACTION_MOVE, {{50, 50}, {151, 51}}));
Vaibhav Devmurari882bd9b2022-06-23 14:54:54 +00004227 mDispatcher->waitForIdle();
Prabir Pradhan9d5f9ce2024-01-24 00:03:41 +00004228
4229 window2->consumeMotionEvent(WithDownTime(secondDown->getDownTime()));
4230 window1->consumeMotionEvent(WithDownTime(firstDown->getDownTime()));
Vaibhav Devmurari882bd9b2022-06-23 14:54:54 +00004231
4232 // Now add new touch down on the second window
Prabir Pradhan678438e2023-04-13 19:32:51 +00004233 mDispatcher->notifyMotion(generateTouchArgs(POINTER_2_DOWN, {{50, 50}, {151, 51}, {150, 50}}));
Vaibhav Devmurari882bd9b2022-06-23 14:54:54 +00004234 mDispatcher->waitForIdle();
Vaibhav Devmurari882bd9b2022-06-23 14:54:54 +00004235
Prabir Pradhan9d5f9ce2024-01-24 00:03:41 +00004236 window2->consumeMotionEvent(
4237 AllOf(WithMotionAction(POINTER_1_DOWN), WithDownTime(secondDown->getDownTime())));
4238 window1->consumeMotionEvent(WithDownTime(firstDown->getDownTime()));
Vaibhav Devmurari882bd9b2022-06-23 14:54:54 +00004239
4240 // Now move the pointer on the first window
Prabir Pradhan678438e2023-04-13 19:32:51 +00004241 mDispatcher->notifyMotion(
4242 generateTouchArgs(AMOTION_EVENT_ACTION_MOVE, {{51, 51}, {151, 51}, {150, 50}}));
Vaibhav Devmurari882bd9b2022-06-23 14:54:54 +00004243 mDispatcher->waitForIdle();
Vaibhav Devmurari882bd9b2022-06-23 14:54:54 +00004244
Prabir Pradhan9d5f9ce2024-01-24 00:03:41 +00004245 window1->consumeMotionEvent(WithDownTime(firstDown->getDownTime()));
4246 window2->consumeMotionEvent(WithDownTime(secondDown->getDownTime()));
4247
4248 // Now add new touch down on the first window
Prabir Pradhan678438e2023-04-13 19:32:51 +00004249 mDispatcher->notifyMotion(
4250 generateTouchArgs(POINTER_3_DOWN, {{51, 51}, {151, 51}, {150, 50}, {50, 50}}));
Vaibhav Devmurari882bd9b2022-06-23 14:54:54 +00004251 mDispatcher->waitForIdle();
Prabir Pradhan9d5f9ce2024-01-24 00:03:41 +00004252
4253 window1->consumeMotionEvent(
4254 AllOf(WithMotionAction(POINTER_1_DOWN), WithDownTime(firstDown->getDownTime())));
4255 window2->consumeMotionEvent(WithDownTime(secondDown->getDownTime()));
Vaibhav Devmurari882bd9b2022-06-23 14:54:54 +00004256}
4257
Siarhei Vishniakouac42d242024-06-28 10:43:53 -07004258/**
4259 * When events are not split, the downTime should be adjusted such that the downTime corresponds
4260 * to the event time of the first ACTION_DOWN. If a new window appears, it should not affect
4261 * the event routing because the first window prevents splitting.
4262 */
4263TEST_F(InputDispatcherTest, SplitTouchesSendCorrectActionDownTimeForNewWindow) {
Siarhei Vishniakoua3fe6642024-07-18 11:58:25 -07004264 SCOPED_FLAG_OVERRIDE(split_all_touches, false);
Siarhei Vishniakouac42d242024-06-28 10:43:53 -07004265 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
4266 sp<FakeWindowHandle> window1 =
4267 sp<FakeWindowHandle>::make(application, mDispatcher, "Window1", DISPLAY_ID);
4268 window1->setTouchableRegion(Region{{0, 0, 100, 100}});
4269 window1->setPreventSplitting(true);
4270
4271 sp<FakeWindowHandle> window2 =
4272 sp<FakeWindowHandle>::make(application, mDispatcher, "Window2", DISPLAY_ID);
4273 window2->setTouchableRegion(Region{{100, 0, 200, 100}});
4274
4275 mDispatcher->onWindowInfosChanged({{*window1->getInfo()}, {}, 0, 0});
4276
4277 // Touch down on the first window
4278 NotifyMotionArgs downArgs = MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
4279 .pointer(PointerBuilder(0, ToolType::FINGER).x(50).y(50))
4280 .build();
4281 mDispatcher->notifyMotion(downArgs);
4282
4283 window1->consumeMotionEvent(
4284 AllOf(WithMotionAction(ACTION_DOWN), WithDownTime(downArgs.downTime)));
4285
4286 // Second window is added
4287 mDispatcher->onWindowInfosChanged({{*window1->getInfo(), *window2->getInfo()}, {}, 0, 0});
4288
4289 // Now touch down on the window with another pointer
4290 mDispatcher->notifyMotion(MotionArgsBuilder(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
4291 .pointer(PointerBuilder(0, ToolType::FINGER).x(50).y(50))
4292 .pointer(PointerBuilder(1, ToolType::FINGER).x(150).y(50))
4293 .downTime(downArgs.downTime)
4294 .build());
4295 window1->consumeMotionPointerDown(1, AllOf(WithDownTime(downArgs.downTime)));
4296
4297 // Finish the gesture
4298 mDispatcher->notifyMotion(MotionArgsBuilder(POINTER_1_UP, AINPUT_SOURCE_TOUCHSCREEN)
4299 .pointer(PointerBuilder(0, ToolType::FINGER).x(50).y(50))
4300 .pointer(PointerBuilder(1, ToolType::FINGER).x(150).y(50))
4301 .downTime(downArgs.downTime)
4302 .build());
4303 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN)
4304 .pointer(PointerBuilder(0, ToolType::FINGER).x(50).y(50))
4305 .downTime(downArgs.downTime)
4306 .build());
4307 window1->consumeMotionPointerUp(1, AllOf(WithDownTime(downArgs.downTime)));
4308 window1->consumeMotionEvent(
4309 AllOf(WithMotionAction(ACTION_UP), WithDownTime(downArgs.downTime)));
4310 window2->assertNoEvents();
4311}
4312
4313/**
4314 * When splitting touch events, the downTime should be adjusted such that the downTime corresponds
4315 * to the event time of the first ACTION_DOWN sent to the new window.
4316 * If a new window that does not support split appears on the screen and gets touched with the
4317 * second finger, it should not get any events because it doesn't want split touches. At the same
4318 * time, the first window should not get the pointer_down event because it supports split touches
4319 * (and the touch occurred outside of the bounds of window1).
4320 */
4321TEST_F(InputDispatcherTest, SplitTouchesDropsEventForNonSplittableSecondWindow) {
Siarhei Vishniakoua3fe6642024-07-18 11:58:25 -07004322 SCOPED_FLAG_OVERRIDE(split_all_touches, false);
Siarhei Vishniakouac42d242024-06-28 10:43:53 -07004323 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
4324 sp<FakeWindowHandle> window1 =
4325 sp<FakeWindowHandle>::make(application, mDispatcher, "Window1", DISPLAY_ID);
4326 window1->setTouchableRegion(Region{{0, 0, 100, 100}});
4327
4328 sp<FakeWindowHandle> window2 =
4329 sp<FakeWindowHandle>::make(application, mDispatcher, "Window2", DISPLAY_ID);
4330 window2->setTouchableRegion(Region{{100, 0, 200, 100}});
4331
4332 mDispatcher->onWindowInfosChanged({{*window1->getInfo()}, {}, 0, 0});
4333
4334 // Touch down on the first window
4335 NotifyMotionArgs downArgs = MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
4336 .pointer(PointerBuilder(0, ToolType::FINGER).x(50).y(50))
4337 .build();
4338 mDispatcher->notifyMotion(downArgs);
4339
4340 window1->consumeMotionEvent(
4341 AllOf(WithMotionAction(ACTION_DOWN), WithDownTime(downArgs.downTime)));
4342
4343 // Second window is added
4344 window2->setPreventSplitting(true);
4345 mDispatcher->onWindowInfosChanged({{*window1->getInfo(), *window2->getInfo()}, {}, 0, 0});
4346
4347 // Now touch down on the window with another pointer
4348 mDispatcher->notifyMotion(MotionArgsBuilder(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
4349 .pointer(PointerBuilder(0, ToolType::FINGER).x(50).y(50))
4350 .pointer(PointerBuilder(1, ToolType::FINGER).x(150).y(50))
4351 .downTime(downArgs.downTime)
4352 .build());
4353 // Event is dropped because window2 doesn't support split touch, and window1 does.
4354
4355 // Complete the gesture
4356 mDispatcher->notifyMotion(MotionArgsBuilder(POINTER_1_UP, AINPUT_SOURCE_TOUCHSCREEN)
4357 .pointer(PointerBuilder(0, ToolType::FINGER).x(50).y(50))
4358 .pointer(PointerBuilder(1, ToolType::FINGER).x(150).y(50))
4359 .downTime(downArgs.downTime)
4360 .build());
4361 // A redundant MOVE event is generated that doesn't carry any new information
4362 window1->consumeMotionEvent(
4363 AllOf(WithMotionAction(ACTION_MOVE), WithDownTime(downArgs.downTime)));
4364 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN)
4365 .pointer(PointerBuilder(0, ToolType::FINGER).x(50).y(50))
4366 .downTime(downArgs.downTime)
4367 .build());
4368
4369 window1->consumeMotionEvent(
4370 AllOf(WithMotionAction(ACTION_UP), WithDownTime(downArgs.downTime)));
4371 window1->assertNoEvents();
4372 window2->assertNoEvents();
4373}
4374
Garfield Tandf26e862020-07-01 20:18:19 -07004375TEST_F(InputDispatcherTest, HoverMoveEnterMouseClickAndHoverMoveExit) {
Chris Yea209fde2020-07-22 13:54:51 -07004376 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07004377 sp<FakeWindowHandle> windowLeft = sp<FakeWindowHandle>::make(application, mDispatcher, "Left",
4378 ui::LogicalDisplayId::DEFAULT);
Garfield Tandf26e862020-07-01 20:18:19 -07004379 windowLeft->setFrame(Rect(0, 0, 600, 800));
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07004380 sp<FakeWindowHandle> windowRight = sp<FakeWindowHandle>::make(application, mDispatcher, "Right",
4381 ui::LogicalDisplayId::DEFAULT);
Garfield Tandf26e862020-07-01 20:18:19 -07004382 windowRight->setFrame(Rect(600, 0, 1200, 800));
Garfield Tandf26e862020-07-01 20:18:19 -07004383
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07004384 mDispatcher->setFocusedApplication(ui::LogicalDisplayId::DEFAULT, application);
Garfield Tandf26e862020-07-01 20:18:19 -07004385
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07004386 mDispatcher->onWindowInfosChanged(
4387 {{*windowLeft->getInfo(), *windowRight->getInfo()}, {}, 0, 0});
Garfield Tandf26e862020-07-01 20:18:19 -07004388
4389 // Start cursor position in right window so that we can move the cursor to left window.
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08004390 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07004391 injectMotionEvent(*mDispatcher,
Garfield Tandf26e862020-07-01 20:18:19 -07004392 MotionEventBuilder(AMOTION_EVENT_ACTION_HOVER_MOVE,
4393 AINPUT_SOURCE_MOUSE)
Siarhei Vishniakou6d73f832022-07-21 17:27:03 -07004394 .pointer(PointerBuilder(0, ToolType::MOUSE).x(900).y(400))
Garfield Tandf26e862020-07-01 20:18:19 -07004395 .build()));
Siarhei Vishniakou5cee1e32022-11-29 12:35:39 -08004396 windowRight->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_ENTER));
Garfield Tandf26e862020-07-01 20:18:19 -07004397
4398 // Move cursor into left window
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08004399 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07004400 injectMotionEvent(*mDispatcher,
Garfield Tandf26e862020-07-01 20:18:19 -07004401 MotionEventBuilder(AMOTION_EVENT_ACTION_HOVER_MOVE,
4402 AINPUT_SOURCE_MOUSE)
Siarhei Vishniakou6d73f832022-07-21 17:27:03 -07004403 .pointer(PointerBuilder(0, ToolType::MOUSE).x(300).y(400))
Garfield Tandf26e862020-07-01 20:18:19 -07004404 .build()));
Siarhei Vishniakou5cee1e32022-11-29 12:35:39 -08004405 windowRight->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_EXIT));
4406 windowLeft->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_ENTER));
Garfield Tandf26e862020-07-01 20:18:19 -07004407
4408 // Inject a series of mouse events for a mouse click
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08004409 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07004410 injectMotionEvent(*mDispatcher,
Garfield Tandf26e862020-07-01 20:18:19 -07004411 MotionEventBuilder(AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_MOUSE)
4412 .buttonState(AMOTION_EVENT_BUTTON_PRIMARY)
Siarhei Vishniakou6d73f832022-07-21 17:27:03 -07004413 .pointer(PointerBuilder(0, ToolType::MOUSE).x(300).y(400))
Garfield Tandf26e862020-07-01 20:18:19 -07004414 .build()));
Siarhei Vishniakouf372b812023-02-14 18:06:51 -08004415 windowLeft->consumeMotionEvent(WithMotionAction(ACTION_HOVER_EXIT));
4416 windowLeft->consumeMotionEvent(WithMotionAction(ACTION_DOWN));
Garfield Tandf26e862020-07-01 20:18:19 -07004417
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08004418 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07004419 injectMotionEvent(*mDispatcher,
Garfield Tandf26e862020-07-01 20:18:19 -07004420 MotionEventBuilder(AMOTION_EVENT_ACTION_BUTTON_PRESS,
4421 AINPUT_SOURCE_MOUSE)
4422 .buttonState(AMOTION_EVENT_BUTTON_PRIMARY)
4423 .actionButton(AMOTION_EVENT_BUTTON_PRIMARY)
Siarhei Vishniakou6d73f832022-07-21 17:27:03 -07004424 .pointer(PointerBuilder(0, ToolType::MOUSE).x(300).y(400))
Garfield Tandf26e862020-07-01 20:18:19 -07004425 .build()));
Siarhei Vishniakou5cee1e32022-11-29 12:35:39 -08004426 windowLeft->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_BUTTON_PRESS));
Garfield Tandf26e862020-07-01 20:18:19 -07004427
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08004428 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07004429 injectMotionEvent(*mDispatcher,
Garfield Tandf26e862020-07-01 20:18:19 -07004430 MotionEventBuilder(AMOTION_EVENT_ACTION_BUTTON_RELEASE,
4431 AINPUT_SOURCE_MOUSE)
4432 .buttonState(0)
4433 .actionButton(AMOTION_EVENT_BUTTON_PRIMARY)
Siarhei Vishniakou6d73f832022-07-21 17:27:03 -07004434 .pointer(PointerBuilder(0, ToolType::MOUSE).x(300).y(400))
Garfield Tandf26e862020-07-01 20:18:19 -07004435 .build()));
Siarhei Vishniakou5cee1e32022-11-29 12:35:39 -08004436 windowLeft->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_BUTTON_RELEASE));
Garfield Tandf26e862020-07-01 20:18:19 -07004437
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08004438 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07004439 injectMotionEvent(*mDispatcher,
Garfield Tandf26e862020-07-01 20:18:19 -07004440 MotionEventBuilder(AMOTION_EVENT_ACTION_UP, AINPUT_SOURCE_MOUSE)
4441 .buttonState(0)
Siarhei Vishniakou6d73f832022-07-21 17:27:03 -07004442 .pointer(PointerBuilder(0, ToolType::MOUSE).x(300).y(400))
Garfield Tandf26e862020-07-01 20:18:19 -07004443 .build()));
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07004444 windowLeft->consumeMotionUp(ui::LogicalDisplayId::DEFAULT);
Garfield Tandf26e862020-07-01 20:18:19 -07004445
4446 // Move mouse cursor back to right window
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08004447 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07004448 injectMotionEvent(*mDispatcher,
Garfield Tandf26e862020-07-01 20:18:19 -07004449 MotionEventBuilder(AMOTION_EVENT_ACTION_HOVER_MOVE,
4450 AINPUT_SOURCE_MOUSE)
Siarhei Vishniakou6d73f832022-07-21 17:27:03 -07004451 .pointer(PointerBuilder(0, ToolType::MOUSE).x(900).y(400))
Garfield Tandf26e862020-07-01 20:18:19 -07004452 .build()));
Siarhei Vishniakou5cee1e32022-11-29 12:35:39 -08004453 windowRight->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_ENTER));
Siarhei Vishniakou5cee1e32022-11-29 12:35:39 -08004454
4455 // No more events
4456 windowLeft->assertNoEvents();
4457 windowRight->assertNoEvents();
4458}
4459
Siarhei Vishniakouf372b812023-02-14 18:06:51 -08004460/**
4461 * Put two fingers down (and don't release them) and click the mouse button.
4462 * The clicking of mouse is a new ACTION_DOWN event. Since it's from a different device, the
4463 * currently active gesture should be canceled, and the new one should proceed.
4464 */
Siarhei Vishniakoued89cbb2023-10-13 10:42:44 -07004465TEST_F(InputDispatcherTest, TwoPointersDownMouseClick_legacy) {
4466 SCOPED_FLAG_OVERRIDE(enable_multi_device_same_window_stream, false);
Siarhei Vishniakouf372b812023-02-14 18:06:51 -08004467 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07004468 sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher, "Window",
4469 ui::LogicalDisplayId::DEFAULT);
Siarhei Vishniakouf372b812023-02-14 18:06:51 -08004470 window->setFrame(Rect(0, 0, 600, 800));
4471
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07004472 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Siarhei Vishniakouf372b812023-02-14 18:06:51 -08004473
4474 const int32_t touchDeviceId = 4;
4475 const int32_t mouseDeviceId = 6;
Siarhei Vishniakouf372b812023-02-14 18:06:51 -08004476
4477 // Two pointers down
Prabir Pradhan678438e2023-04-13 19:32:51 +00004478 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
4479 .deviceId(touchDeviceId)
4480 .pointer(PointerBuilder(0, ToolType::FINGER).x(100).y(100))
4481 .build());
Siarhei Vishniakouf372b812023-02-14 18:06:51 -08004482
Prabir Pradhan678438e2023-04-13 19:32:51 +00004483 mDispatcher->notifyMotion(MotionArgsBuilder(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
4484 .deviceId(touchDeviceId)
4485 .pointer(PointerBuilder(0, ToolType::FINGER).x(100).y(100))
4486 .pointer(PointerBuilder(1, ToolType::FINGER).x(120).y(120))
4487 .build());
Siarhei Vishniakouf372b812023-02-14 18:06:51 -08004488 window->consumeMotionEvent(WithMotionAction(ACTION_DOWN));
4489 window->consumeMotionEvent(WithMotionAction(POINTER_1_DOWN));
4490
4491 // Inject a series of mouse events for a mouse click
Prabir Pradhan678438e2023-04-13 19:32:51 +00004492 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_MOUSE)
4493 .deviceId(mouseDeviceId)
4494 .buttonState(AMOTION_EVENT_BUTTON_PRIMARY)
4495 .pointer(PointerBuilder(0, ToolType::MOUSE).x(300).y(400))
4496 .build());
Siarhei Vishniakouf372b812023-02-14 18:06:51 -08004497 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_CANCEL), WithDeviceId(touchDeviceId),
4498 WithPointerCount(2u)));
4499 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(mouseDeviceId)));
4500
Prabir Pradhan678438e2023-04-13 19:32:51 +00004501 mDispatcher->notifyMotion(
4502 MotionArgsBuilder(AMOTION_EVENT_ACTION_BUTTON_PRESS, AINPUT_SOURCE_MOUSE)
4503 .deviceId(mouseDeviceId)
4504 .buttonState(AMOTION_EVENT_BUTTON_PRIMARY)
4505 .actionButton(AMOTION_EVENT_BUTTON_PRIMARY)
4506 .pointer(PointerBuilder(0, ToolType::MOUSE).x(300).y(400))
4507 .build());
Siarhei Vishniakouf372b812023-02-14 18:06:51 -08004508 window->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_BUTTON_PRESS));
4509
4510 // Try to send more touch events while the mouse is down. Since it's a continuation of an
4511 // already canceled gesture, it should be ignored.
Prabir Pradhan678438e2023-04-13 19:32:51 +00004512 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN)
4513 .deviceId(touchDeviceId)
4514 .pointer(PointerBuilder(0, ToolType::FINGER).x(101).y(101))
4515 .pointer(PointerBuilder(1, ToolType::FINGER).x(121).y(121))
4516 .build());
Siarhei Vishniakouf372b812023-02-14 18:06:51 -08004517 window->assertNoEvents();
4518}
4519
Siarhei Vishniakoued89cbb2023-10-13 10:42:44 -07004520/**
4521 * Put two fingers down (and don't release them) and click the mouse button.
4522 * The clicking of mouse is a new ACTION_DOWN event. Since it's from a different device, the
4523 * currently active gesture should not be canceled, and the new one should proceed in parallel.
4524 */
4525TEST_F(InputDispatcherTest, TwoPointersDownMouseClick) {
4526 SCOPED_FLAG_OVERRIDE(enable_multi_device_same_window_stream, true);
4527 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07004528 sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher, "Window",
4529 ui::LogicalDisplayId::DEFAULT);
Siarhei Vishniakoued89cbb2023-10-13 10:42:44 -07004530 window->setFrame(Rect(0, 0, 600, 800));
4531
4532 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
4533
4534 const int32_t touchDeviceId = 4;
4535 const int32_t mouseDeviceId = 6;
4536
4537 // Two pointers down
4538 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
4539 .deviceId(touchDeviceId)
4540 .pointer(PointerBuilder(0, ToolType::FINGER).x(100).y(100))
4541 .build());
4542
4543 mDispatcher->notifyMotion(MotionArgsBuilder(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
4544 .deviceId(touchDeviceId)
4545 .pointer(PointerBuilder(0, ToolType::FINGER).x(100).y(100))
4546 .pointer(PointerBuilder(1, ToolType::FINGER).x(120).y(120))
4547 .build());
4548 window->consumeMotionEvent(WithMotionAction(ACTION_DOWN));
4549 window->consumeMotionEvent(WithMotionAction(POINTER_1_DOWN));
4550
4551 // Send a series of mouse events for a mouse click
4552 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_MOUSE)
4553 .deviceId(mouseDeviceId)
4554 .buttonState(AMOTION_EVENT_BUTTON_PRIMARY)
4555 .pointer(PointerBuilder(0, ToolType::MOUSE).x(300).y(400))
4556 .build());
4557 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(mouseDeviceId)));
4558
4559 mDispatcher->notifyMotion(
4560 MotionArgsBuilder(AMOTION_EVENT_ACTION_BUTTON_PRESS, AINPUT_SOURCE_MOUSE)
4561 .deviceId(mouseDeviceId)
4562 .buttonState(AMOTION_EVENT_BUTTON_PRIMARY)
4563 .actionButton(AMOTION_EVENT_BUTTON_PRIMARY)
4564 .pointer(PointerBuilder(0, ToolType::MOUSE).x(300).y(400))
4565 .build());
4566 window->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_BUTTON_PRESS));
4567
4568 // Try to send more touch events while the mouse is down. Since it's a continuation of an
4569 // already active gesture, it should be sent normally.
4570 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN)
4571 .deviceId(touchDeviceId)
4572 .pointer(PointerBuilder(0, ToolType::FINGER).x(101).y(101))
4573 .pointer(PointerBuilder(1, ToolType::FINGER).x(121).y(121))
4574 .build());
4575 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(touchDeviceId)));
4576 window->assertNoEvents();
4577}
4578
Siarhei Vishniakou07cdda92024-07-01 16:45:08 -07004579/**
4580 * A spy window sits above a window with NO_INPUT_CHANNEL. Ensure that the spy receives events even
4581 * though the window underneath should not get any events.
4582 */
4583TEST_F(InputDispatcherTest, NonSplittableSpyAboveNoInputChannelWindowSinglePointer) {
4584 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
4585
4586 sp<FakeWindowHandle> spyWindow = sp<FakeWindowHandle>::make(application, mDispatcher, "Spy",
4587 ui::LogicalDisplayId::DEFAULT);
4588 spyWindow->setFrame(Rect(0, 0, 100, 100));
4589 spyWindow->setTrustedOverlay(true);
4590 spyWindow->setPreventSplitting(true);
4591 spyWindow->setSpy(true);
4592 // Another window below spy that has both NO_INPUT_CHANNEL and PREVENT_SPLITTING
4593 sp<FakeWindowHandle> inputSinkWindow =
4594 sp<FakeWindowHandle>::make(application, mDispatcher, "Input sink below spy",
4595 ui::LogicalDisplayId::DEFAULT);
4596 inputSinkWindow->setFrame(Rect(0, 0, 100, 100));
4597 inputSinkWindow->setTrustedOverlay(true);
4598 inputSinkWindow->setPreventSplitting(true);
4599 inputSinkWindow->setNoInputChannel(true);
4600
4601 mDispatcher->onWindowInfosChanged(
4602 {{*spyWindow->getInfo(), *inputSinkWindow->getInfo()}, {}, 0, 0});
4603
4604 // Tap the spy window
4605 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
4606 .pointer(PointerBuilder(0, ToolType::FINGER).x(50).y(51))
4607 .build());
4608 mDispatcher->notifyMotion(
4609 MotionArgsBuilder(ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN)
4610 .pointer(PointerBuilder(/*id=*/0, ToolType::FINGER).x(50).y(51))
4611 .build());
4612
4613 spyWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN)));
4614 spyWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_UP)));
4615 inputSinkWindow->assertNoEvents();
4616}
4617
4618/**
4619 * A spy window sits above a window with NO_INPUT_CHANNEL. Ensure that the spy receives events even
4620 * though the window underneath should not get any events.
4621 * Same test as above, but with two pointers touching instead of one.
4622 */
4623TEST_F(InputDispatcherTest, NonSplittableSpyAboveNoInputChannelWindowTwoPointers) {
4624 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
4625
4626 sp<FakeWindowHandle> spyWindow = sp<FakeWindowHandle>::make(application, mDispatcher, "Spy",
4627 ui::LogicalDisplayId::DEFAULT);
4628 spyWindow->setFrame(Rect(0, 0, 100, 100));
4629 spyWindow->setTrustedOverlay(true);
4630 spyWindow->setPreventSplitting(true);
4631 spyWindow->setSpy(true);
4632 // Another window below spy that would have both NO_INPUT_CHANNEL and PREVENT_SPLITTING
4633 sp<FakeWindowHandle> inputSinkWindow =
4634 sp<FakeWindowHandle>::make(application, mDispatcher, "Input sink below spy",
4635 ui::LogicalDisplayId::DEFAULT);
4636 inputSinkWindow->setFrame(Rect(0, 0, 100, 100));
4637 inputSinkWindow->setTrustedOverlay(true);
4638 inputSinkWindow->setPreventSplitting(true);
4639 inputSinkWindow->setNoInputChannel(true);
4640
4641 mDispatcher->onWindowInfosChanged(
4642 {{*spyWindow->getInfo(), *inputSinkWindow->getInfo()}, {}, 0, 0});
4643
4644 // Both fingers land into the spy window
4645 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
4646 .pointer(PointerBuilder(0, ToolType::FINGER).x(50).y(51))
4647 .build());
4648 mDispatcher->notifyMotion(
4649 MotionArgsBuilder(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
4650 .pointer(PointerBuilder(/*id=*/0, ToolType::FINGER).x(50).y(51))
4651 .pointer(PointerBuilder(/*id=*/1, ToolType::FINGER).x(10).y(11))
4652 .build());
4653 mDispatcher->notifyMotion(
4654 MotionArgsBuilder(POINTER_1_UP, AINPUT_SOURCE_TOUCHSCREEN)
4655 .pointer(PointerBuilder(/*id=*/0, ToolType::FINGER).x(50).y(51))
4656 .pointer(PointerBuilder(/*id=*/1, ToolType::FINGER).x(10).y(11))
4657 .build());
4658 mDispatcher->notifyMotion(
4659 MotionArgsBuilder(ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN)
4660 .pointer(PointerBuilder(/*id=*/0, ToolType::FINGER).x(50).y(51))
4661 .build());
4662
4663 spyWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN)));
4664 spyWindow->consumeMotionPointerDown(1, WithPointerCount(2));
4665 spyWindow->consumeMotionPointerUp(1, WithPointerCount(2));
4666 spyWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_UP)));
4667 inputSinkWindow->assertNoEvents();
4668}
4669
4670/** Check the behaviour for cases where input sink prevents or doesn't prevent splitting. */
4671class SpyThatPreventsSplittingWithApplicationFixture : public InputDispatcherTest,
4672 public ::testing::WithParamInterface<bool> {
4673};
4674
4675/**
4676 * Three windows:
4677 * - An application window (app window)
4678 * - A spy window that does not overlap the app window. Has PREVENT_SPLITTING flag
4679 * - A window below the spy that has NO_INPUT_CHANNEL (call it 'inputSink')
4680 *
4681 * The spy window is side-by-side with the app window. The inputSink is below the spy.
4682 * We first touch the area outside of the appWindow, but inside spyWindow.
4683 * Only the SPY window should get the DOWN event.
4684 * The spy pilfers after receiving the first DOWN event.
4685 * Next, we touch the app window.
4686 * The spy should receive POINTER_DOWN(1) (since spy is preventing splits).
4687 * Also, since the spy is already pilfering the first pointer, it will be sent the remaining new
4688 * pointers automatically, as well.
4689 * Next, the first pointer (from the spy) is lifted.
4690 * Spy should get POINTER_UP(0).
4691 * This event should not go to the app because the app never received this pointer to begin with.
4692 * Now, lift the remaining pointer and check that the spy receives UP event.
4693 *
4694 * Finally, send a new ACTION_DOWN event to the spy and check that it's received.
4695 * This test attempts to reproduce a crash in the dispatcher.
4696 */
4697TEST_P(SpyThatPreventsSplittingWithApplicationFixture, SpyThatPreventsSplittingWithApplication) {
Siarhei Vishniakoua3fe6642024-07-18 11:58:25 -07004698 SCOPED_FLAG_OVERRIDE(split_all_touches, false);
Siarhei Vishniakou07cdda92024-07-01 16:45:08 -07004699 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
4700
4701 sp<FakeWindowHandle> spyWindow = sp<FakeWindowHandle>::make(application, mDispatcher, "Spy",
4702 ui::LogicalDisplayId::DEFAULT);
4703 spyWindow->setFrame(Rect(100, 100, 200, 200));
4704 spyWindow->setTrustedOverlay(true);
4705 spyWindow->setPreventSplitting(true);
4706 spyWindow->setSpy(true);
4707 // Another window below spy that has both NO_INPUT_CHANNEL and PREVENT_SPLITTING
4708 sp<FakeWindowHandle> inputSinkWindow =
4709 sp<FakeWindowHandle>::make(application, mDispatcher, "Input sink below spy",
4710 ui::LogicalDisplayId::DEFAULT);
4711 inputSinkWindow->setFrame(Rect(100, 100, 200, 200)); // directly below the spy
4712 inputSinkWindow->setTrustedOverlay(true);
4713 inputSinkWindow->setPreventSplitting(GetParam());
4714 inputSinkWindow->setNoInputChannel(true);
4715
4716 sp<FakeWindowHandle> appWindow = sp<FakeWindowHandle>::make(application, mDispatcher, "App",
4717 ui::LogicalDisplayId::DEFAULT);
4718 appWindow->setFrame(Rect(0, 0, 100, 100));
4719
4720 mDispatcher->setFocusedApplication(ui::LogicalDisplayId::DEFAULT, application);
4721 mDispatcher->onWindowInfosChanged(
4722 {{*spyWindow->getInfo(), *inputSinkWindow->getInfo(), *appWindow->getInfo()},
4723 {},
4724 0,
4725 0});
4726
4727 // First finger lands outside of the appWindow, but inside of the spy window
4728 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
4729 .pointer(PointerBuilder(0, ToolType::FINGER).x(150).y(150))
4730 .build());
4731 spyWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN)));
4732
4733 mDispatcher->pilferPointers(spyWindow->getToken());
4734
4735 // Second finger lands in the app, and goes to the spy window. It doesn't go to the app because
4736 // the spy is already pilfering the first pointer, and this automatically grants the remaining
4737 // new pointers to the spy, as well.
4738 mDispatcher->notifyMotion(
4739 MotionArgsBuilder(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
4740 .pointer(PointerBuilder(/*id=*/0, ToolType::FINGER).x(150).y(150))
4741 .pointer(PointerBuilder(/*id=*/1, ToolType::FINGER).x(50).y(50))
4742 .build());
4743
4744 spyWindow->consumeMotionPointerDown(1, WithPointerCount(2));
4745
4746 // Now lift up the first pointer
4747 mDispatcher->notifyMotion(
4748 MotionArgsBuilder(POINTER_0_UP, AINPUT_SOURCE_TOUCHSCREEN)
4749 .pointer(PointerBuilder(/*id=*/0, ToolType::FINGER).x(150).y(150))
4750 .pointer(PointerBuilder(/*id=*/1, ToolType::FINGER).x(50).y(50))
4751 .build());
4752 spyWindow->consumeMotionPointerUp(0, WithPointerCount(2));
4753
4754 // And lift the remaining pointer!
4755 mDispatcher->notifyMotion(
4756 MotionArgsBuilder(ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN)
4757 .pointer(PointerBuilder(/*id=*/1, ToolType::FINGER).x(50).y(50))
4758 .build());
4759 spyWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_UP), WithPointerCount(1)));
4760
4761 // Now send a new DOWN, which should again go to spy.
4762 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
4763 .pointer(PointerBuilder(0, ToolType::FINGER).x(150).y(150))
4764 .build());
4765 spyWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN)));
4766 // The app window doesn't get any events this entire time because the spy received the events
4767 // first and pilfered, which makes all new pointers go to it as well.
4768 appWindow->assertNoEvents();
4769}
4770
4771// Behaviour should be the same regardless of whether inputSink supports splitting.
4772INSTANTIATE_TEST_SUITE_P(SpyThatPreventsSplittingWithApplication,
4773 SpyThatPreventsSplittingWithApplicationFixture, testing::Bool());
4774
Siarhei Vishniakou5cee1e32022-11-29 12:35:39 -08004775TEST_F(InputDispatcherTest, HoverWithSpyWindows) {
4776 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
4777
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07004778 sp<FakeWindowHandle> spyWindow = sp<FakeWindowHandle>::make(application, mDispatcher, "Spy",
4779 ui::LogicalDisplayId::DEFAULT);
Siarhei Vishniakou5cee1e32022-11-29 12:35:39 -08004780 spyWindow->setFrame(Rect(0, 0, 600, 800));
4781 spyWindow->setTrustedOverlay(true);
4782 spyWindow->setSpy(true);
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07004783 sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher, "Window",
4784 ui::LogicalDisplayId::DEFAULT);
Siarhei Vishniakou5cee1e32022-11-29 12:35:39 -08004785 window->setFrame(Rect(0, 0, 600, 800));
4786
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07004787 mDispatcher->setFocusedApplication(ui::LogicalDisplayId::DEFAULT, application);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07004788 mDispatcher->onWindowInfosChanged({{*spyWindow->getInfo(), *window->getInfo()}, {}, 0, 0});
Siarhei Vishniakou5cee1e32022-11-29 12:35:39 -08004789
4790 // Send mouse cursor to the window
4791 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07004792 injectMotionEvent(*mDispatcher,
Siarhei Vishniakou5cee1e32022-11-29 12:35:39 -08004793 MotionEventBuilder(AMOTION_EVENT_ACTION_HOVER_ENTER,
4794 AINPUT_SOURCE_MOUSE)
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07004795 .pointer(PointerBuilder(0, ToolType::MOUSE).x(100).y(100))
Siarhei Vishniakou5cee1e32022-11-29 12:35:39 -08004796 .build()));
4797
4798 window->consumeMotionEvent(AllOf(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_ENTER),
4799 WithSource(AINPUT_SOURCE_MOUSE)));
4800 spyWindow->consumeMotionEvent(AllOf(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_ENTER),
4801 WithSource(AINPUT_SOURCE_MOUSE)));
4802
4803 window->assertNoEvents();
4804 spyWindow->assertNoEvents();
Garfield Tandf26e862020-07-01 20:18:19 -07004805}
4806
Siarhei Vishniakoued89cbb2023-10-13 10:42:44 -07004807TEST_F(InputDispatcherTest, MouseAndTouchWithSpyWindows_legacy) {
4808 SCOPED_FLAG_OVERRIDE(enable_multi_device_same_window_stream, false);
Siarhei Vishniakou060f82b2023-01-27 06:39:14 -08004809 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
4810
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07004811 sp<FakeWindowHandle> spyWindow = sp<FakeWindowHandle>::make(application, mDispatcher, "Spy",
4812 ui::LogicalDisplayId::DEFAULT);
Siarhei Vishniakou060f82b2023-01-27 06:39:14 -08004813 spyWindow->setFrame(Rect(0, 0, 600, 800));
4814 spyWindow->setTrustedOverlay(true);
4815 spyWindow->setSpy(true);
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07004816 sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher, "Window",
4817 ui::LogicalDisplayId::DEFAULT);
Siarhei Vishniakou060f82b2023-01-27 06:39:14 -08004818 window->setFrame(Rect(0, 0, 600, 800));
4819
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07004820 mDispatcher->setFocusedApplication(ui::LogicalDisplayId::DEFAULT, application);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07004821 mDispatcher->onWindowInfosChanged({{*spyWindow->getInfo(), *window->getInfo()}, {}, 0, 0});
Siarhei Vishniakou060f82b2023-01-27 06:39:14 -08004822
4823 // Send mouse cursor to the window
4824 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07004825 injectMotionEvent(*mDispatcher,
Siarhei Vishniakou060f82b2023-01-27 06:39:14 -08004826 MotionEventBuilder(AMOTION_EVENT_ACTION_HOVER_ENTER,
4827 AINPUT_SOURCE_MOUSE)
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07004828 .pointer(PointerBuilder(0, ToolType::MOUSE).x(100).y(100))
Siarhei Vishniakou060f82b2023-01-27 06:39:14 -08004829 .build()));
4830
4831 // Move mouse cursor
4832 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07004833 injectMotionEvent(*mDispatcher,
Siarhei Vishniakou060f82b2023-01-27 06:39:14 -08004834 MotionEventBuilder(AMOTION_EVENT_ACTION_HOVER_MOVE,
4835 AINPUT_SOURCE_MOUSE)
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07004836 .pointer(PointerBuilder(0, ToolType::MOUSE).x(110).y(110))
Siarhei Vishniakou060f82b2023-01-27 06:39:14 -08004837 .build()));
4838
4839 window->consumeMotionEvent(AllOf(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_ENTER),
4840 WithSource(AINPUT_SOURCE_MOUSE)));
4841 spyWindow->consumeMotionEvent(AllOf(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_ENTER),
4842 WithSource(AINPUT_SOURCE_MOUSE)));
4843 window->consumeMotionEvent(AllOf(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_MOVE),
4844 WithSource(AINPUT_SOURCE_MOUSE)));
4845 spyWindow->consumeMotionEvent(AllOf(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_MOVE),
4846 WithSource(AINPUT_SOURCE_MOUSE)));
4847 // Touch down on the window
4848 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07004849 injectMotionEvent(*mDispatcher,
Siarhei Vishniakou060f82b2023-01-27 06:39:14 -08004850 MotionEventBuilder(AMOTION_EVENT_ACTION_DOWN,
4851 AINPUT_SOURCE_TOUCHSCREEN)
4852 .deviceId(SECOND_DEVICE_ID)
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07004853 .pointer(PointerBuilder(0, ToolType::FINGER).x(200).y(200))
Siarhei Vishniakou060f82b2023-01-27 06:39:14 -08004854 .build()));
4855 window->consumeMotionEvent(AllOf(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_EXIT),
4856 WithSource(AINPUT_SOURCE_MOUSE)));
4857 spyWindow->consumeMotionEvent(AllOf(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_EXIT),
4858 WithSource(AINPUT_SOURCE_MOUSE)));
4859 window->consumeMotionEvent(AllOf(WithMotionAction(AMOTION_EVENT_ACTION_DOWN),
4860 WithSource(AINPUT_SOURCE_TOUCHSCREEN)));
4861 spyWindow->consumeMotionEvent(AllOf(WithMotionAction(AMOTION_EVENT_ACTION_DOWN),
4862 WithSource(AINPUT_SOURCE_TOUCHSCREEN)));
4863
4864 // pilfer the motion, retaining the gesture on the spy window.
4865 EXPECT_EQ(OK, mDispatcher->pilferPointers(spyWindow->getToken()));
4866 window->consumeMotionEvent(AllOf(WithMotionAction(AMOTION_EVENT_ACTION_CANCEL),
4867 WithSource(AINPUT_SOURCE_TOUCHSCREEN)));
4868
4869 // Touch UP on the window
4870 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07004871 injectMotionEvent(*mDispatcher,
Siarhei Vishniakou060f82b2023-01-27 06:39:14 -08004872 MotionEventBuilder(AMOTION_EVENT_ACTION_UP,
4873 AINPUT_SOURCE_TOUCHSCREEN)
4874 .deviceId(SECOND_DEVICE_ID)
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07004875 .pointer(PointerBuilder(0, ToolType::FINGER).x(200).y(200))
Siarhei Vishniakou060f82b2023-01-27 06:39:14 -08004876 .build()));
4877 spyWindow->consumeMotionEvent(AllOf(WithMotionAction(AMOTION_EVENT_ACTION_UP),
4878 WithSource(AINPUT_SOURCE_TOUCHSCREEN)));
4879
4880 // Previously, a touch was pilfered. However, that gesture was just finished. Now, we are going
4881 // to send a new gesture. It should again go to both windows (spy and the window below), just
4882 // like the first gesture did, before pilfering. The window configuration has not changed.
4883
4884 // One more tap - DOWN
4885 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07004886 injectMotionEvent(*mDispatcher,
Siarhei Vishniakou060f82b2023-01-27 06:39:14 -08004887 MotionEventBuilder(AMOTION_EVENT_ACTION_DOWN,
4888 AINPUT_SOURCE_TOUCHSCREEN)
4889 .deviceId(SECOND_DEVICE_ID)
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07004890 .pointer(PointerBuilder(0, ToolType::FINGER).x(250).y(250))
Siarhei Vishniakou060f82b2023-01-27 06:39:14 -08004891 .build()));
4892 window->consumeMotionEvent(AllOf(WithMotionAction(AMOTION_EVENT_ACTION_DOWN),
4893 WithSource(AINPUT_SOURCE_TOUCHSCREEN)));
4894 spyWindow->consumeMotionEvent(AllOf(WithMotionAction(AMOTION_EVENT_ACTION_DOWN),
4895 WithSource(AINPUT_SOURCE_TOUCHSCREEN)));
4896
4897 // Touch UP on the window
4898 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07004899 injectMotionEvent(*mDispatcher,
Siarhei Vishniakou060f82b2023-01-27 06:39:14 -08004900 MotionEventBuilder(AMOTION_EVENT_ACTION_UP,
4901 AINPUT_SOURCE_TOUCHSCREEN)
4902 .deviceId(SECOND_DEVICE_ID)
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07004903 .pointer(PointerBuilder(0, ToolType::FINGER).x(250).y(250))
Siarhei Vishniakou060f82b2023-01-27 06:39:14 -08004904 .build()));
4905 window->consumeMotionEvent(AllOf(WithMotionAction(AMOTION_EVENT_ACTION_UP),
4906 WithSource(AINPUT_SOURCE_TOUCHSCREEN)));
4907 spyWindow->consumeMotionEvent(AllOf(WithMotionAction(AMOTION_EVENT_ACTION_UP),
4908 WithSource(AINPUT_SOURCE_TOUCHSCREEN)));
4909
4910 window->assertNoEvents();
4911 spyWindow->assertNoEvents();
4912}
4913
Siarhei Vishniakoued89cbb2023-10-13 10:42:44 -07004914TEST_F(InputDispatcherTest, MouseAndTouchWithSpyWindows) {
4915 SCOPED_FLAG_OVERRIDE(enable_multi_device_same_window_stream, true);
4916 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
4917
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07004918 sp<FakeWindowHandle> spyWindow = sp<FakeWindowHandle>::make(application, mDispatcher, "Spy",
4919 ui::LogicalDisplayId::DEFAULT);
Siarhei Vishniakoued89cbb2023-10-13 10:42:44 -07004920 spyWindow->setFrame(Rect(0, 0, 600, 800));
4921 spyWindow->setTrustedOverlay(true);
4922 spyWindow->setSpy(true);
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07004923 sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher, "Window",
4924 ui::LogicalDisplayId::DEFAULT);
Siarhei Vishniakoued89cbb2023-10-13 10:42:44 -07004925 window->setFrame(Rect(0, 0, 600, 800));
4926
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07004927 mDispatcher->setFocusedApplication(ui::LogicalDisplayId::DEFAULT, application);
Siarhei Vishniakoued89cbb2023-10-13 10:42:44 -07004928 mDispatcher->onWindowInfosChanged({{*spyWindow->getInfo(), *window->getInfo()}, {}, 0, 0});
4929
4930 // Send mouse cursor to the window
4931 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_ENTER, AINPUT_SOURCE_MOUSE)
4932 .pointer(PointerBuilder(0, ToolType::MOUSE).x(100).y(100))
4933 .build());
4934
4935 // Move mouse cursor
4936 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_MOVE, AINPUT_SOURCE_MOUSE)
4937 .pointer(PointerBuilder(0, ToolType::MOUSE).x(110).y(110))
4938 .build());
4939
4940 window->consumeMotionEvent(
4941 AllOf(WithMotionAction(ACTION_HOVER_ENTER), WithSource(AINPUT_SOURCE_MOUSE)));
4942 spyWindow->consumeMotionEvent(
4943 AllOf(WithMotionAction(ACTION_HOVER_ENTER), WithSource(AINPUT_SOURCE_MOUSE)));
4944 window->consumeMotionEvent(
4945 AllOf(WithMotionAction(ACTION_HOVER_MOVE), WithSource(AINPUT_SOURCE_MOUSE)));
4946 spyWindow->consumeMotionEvent(
4947 AllOf(WithMotionAction(ACTION_HOVER_MOVE), WithSource(AINPUT_SOURCE_MOUSE)));
4948 // Touch down on the window
4949 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
4950 .deviceId(SECOND_DEVICE_ID)
4951 .pointer(PointerBuilder(0, ToolType::FINGER).x(200).y(200))
4952 .build());
4953 window->consumeMotionEvent(
4954 AllOf(WithMotionAction(ACTION_DOWN), WithSource(AINPUT_SOURCE_TOUCHSCREEN)));
4955 spyWindow->consumeMotionEvent(
4956 AllOf(WithMotionAction(ACTION_DOWN), WithSource(AINPUT_SOURCE_TOUCHSCREEN)));
4957
4958 // pilfer the motion, retaining the gesture on the spy window.
4959 EXPECT_EQ(OK, mDispatcher->pilferPointers(spyWindow->getToken()));
4960 window->consumeMotionEvent(
4961 AllOf(WithMotionAction(ACTION_CANCEL), WithSource(AINPUT_SOURCE_TOUCHSCREEN)));
4962 // Mouse hover is not pilfered
4963
4964 // Touch UP on the window
4965 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN)
4966 .deviceId(SECOND_DEVICE_ID)
4967 .pointer(PointerBuilder(0, ToolType::FINGER).x(200).y(200))
4968 .build());
4969 spyWindow->consumeMotionEvent(
4970 AllOf(WithMotionAction(ACTION_UP), WithSource(AINPUT_SOURCE_TOUCHSCREEN)));
4971
4972 // Previously, a touch was pilfered. However, that gesture was just finished. Now, we are going
4973 // to send a new gesture. It should again go to both windows (spy and the window below), just
4974 // like the first gesture did, before pilfering. The window configuration has not changed.
4975
4976 // One more tap - DOWN
4977 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
4978 .deviceId(SECOND_DEVICE_ID)
4979 .pointer(PointerBuilder(0, ToolType::FINGER).x(250).y(250))
4980 .build());
4981 window->consumeMotionEvent(
4982 AllOf(WithMotionAction(ACTION_DOWN), WithSource(AINPUT_SOURCE_TOUCHSCREEN)));
4983 spyWindow->consumeMotionEvent(
4984 AllOf(WithMotionAction(ACTION_DOWN), WithSource(AINPUT_SOURCE_TOUCHSCREEN)));
4985
4986 // Touch UP on the window
4987 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN)
4988 .deviceId(SECOND_DEVICE_ID)
4989 .pointer(PointerBuilder(0, ToolType::FINGER).x(250).y(250))
4990 .build());
4991 window->consumeMotionEvent(
4992 AllOf(WithMotionAction(ACTION_UP), WithSource(AINPUT_SOURCE_TOUCHSCREEN)));
4993 spyWindow->consumeMotionEvent(
4994 AllOf(WithMotionAction(ACTION_UP), WithSource(AINPUT_SOURCE_TOUCHSCREEN)));
4995
4996 // Mouse movement continues normally as well
4997 // Move mouse cursor
4998 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_MOVE, AINPUT_SOURCE_MOUSE)
4999 .pointer(PointerBuilder(0, ToolType::MOUSE).x(120).y(130))
5000 .build());
5001 window->consumeMotionEvent(
5002 AllOf(WithMotionAction(ACTION_HOVER_MOVE), WithSource(AINPUT_SOURCE_MOUSE)));
5003 spyWindow->consumeMotionEvent(
5004 AllOf(WithMotionAction(ACTION_HOVER_MOVE), WithSource(AINPUT_SOURCE_MOUSE)));
5005
5006 window->assertNoEvents();
5007 spyWindow->assertNoEvents();
5008}
5009
Garfield Tandf26e862020-07-01 20:18:19 -07005010// This test is different from the test above that HOVER_ENTER and HOVER_EXIT events are injected
5011// directly in this test.
5012TEST_F(InputDispatcherTest, HoverEnterMouseClickAndHoverExit) {
Chris Yea209fde2020-07-22 13:54:51 -07005013 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07005014 sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher, "Window",
5015 ui::LogicalDisplayId::DEFAULT);
Garfield Tandf26e862020-07-01 20:18:19 -07005016 window->setFrame(Rect(0, 0, 1200, 800));
Garfield Tandf26e862020-07-01 20:18:19 -07005017
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07005018 mDispatcher->setFocusedApplication(ui::LogicalDisplayId::DEFAULT, application);
Garfield Tandf26e862020-07-01 20:18:19 -07005019
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07005020 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Garfield Tandf26e862020-07-01 20:18:19 -07005021
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08005022 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07005023 injectMotionEvent(*mDispatcher,
Garfield Tandf26e862020-07-01 20:18:19 -07005024 MotionEventBuilder(AMOTION_EVENT_ACTION_HOVER_ENTER,
5025 AINPUT_SOURCE_MOUSE)
Siarhei Vishniakou6d73f832022-07-21 17:27:03 -07005026 .pointer(PointerBuilder(0, ToolType::MOUSE).x(300).y(400))
Garfield Tandf26e862020-07-01 20:18:19 -07005027 .build()));
Siarhei Vishniakou5cee1e32022-11-29 12:35:39 -08005028 window->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_ENTER));
Garfield Tandf26e862020-07-01 20:18:19 -07005029 // Inject a series of mouse events for a mouse click
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08005030 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07005031 injectMotionEvent(*mDispatcher,
Garfield Tandf26e862020-07-01 20:18:19 -07005032 MotionEventBuilder(AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_MOUSE)
5033 .buttonState(AMOTION_EVENT_BUTTON_PRIMARY)
Siarhei Vishniakou6d73f832022-07-21 17:27:03 -07005034 .pointer(PointerBuilder(0, ToolType::MOUSE).x(300).y(400))
Garfield Tandf26e862020-07-01 20:18:19 -07005035 .build()));
Siarhei Vishniakouf372b812023-02-14 18:06:51 -08005036 window->consumeMotionEvent(WithMotionAction(ACTION_HOVER_EXIT));
5037 window->consumeMotionEvent(WithMotionAction(ACTION_DOWN));
Garfield Tandf26e862020-07-01 20:18:19 -07005038
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08005039 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07005040 injectMotionEvent(*mDispatcher,
Garfield Tandf26e862020-07-01 20:18:19 -07005041 MotionEventBuilder(AMOTION_EVENT_ACTION_BUTTON_PRESS,
5042 AINPUT_SOURCE_MOUSE)
5043 .buttonState(AMOTION_EVENT_BUTTON_PRIMARY)
5044 .actionButton(AMOTION_EVENT_BUTTON_PRIMARY)
Siarhei Vishniakou6d73f832022-07-21 17:27:03 -07005045 .pointer(PointerBuilder(0, ToolType::MOUSE).x(300).y(400))
Garfield Tandf26e862020-07-01 20:18:19 -07005046 .build()));
Siarhei Vishniakou5cee1e32022-11-29 12:35:39 -08005047 window->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_BUTTON_PRESS));
Garfield Tandf26e862020-07-01 20:18:19 -07005048
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08005049 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07005050 injectMotionEvent(*mDispatcher,
Garfield Tandf26e862020-07-01 20:18:19 -07005051 MotionEventBuilder(AMOTION_EVENT_ACTION_BUTTON_RELEASE,
5052 AINPUT_SOURCE_MOUSE)
5053 .buttonState(0)
5054 .actionButton(AMOTION_EVENT_BUTTON_PRIMARY)
Siarhei Vishniakou6d73f832022-07-21 17:27:03 -07005055 .pointer(PointerBuilder(0, ToolType::MOUSE).x(300).y(400))
Garfield Tandf26e862020-07-01 20:18:19 -07005056 .build()));
Siarhei Vishniakou5cee1e32022-11-29 12:35:39 -08005057 window->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_BUTTON_RELEASE));
Garfield Tandf26e862020-07-01 20:18:19 -07005058
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08005059 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07005060 injectMotionEvent(*mDispatcher,
Garfield Tandf26e862020-07-01 20:18:19 -07005061 MotionEventBuilder(AMOTION_EVENT_ACTION_UP, AINPUT_SOURCE_MOUSE)
5062 .buttonState(0)
Siarhei Vishniakou6d73f832022-07-21 17:27:03 -07005063 .pointer(PointerBuilder(0, ToolType::MOUSE).x(300).y(400))
Garfield Tandf26e862020-07-01 20:18:19 -07005064 .build()));
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07005065 window->consumeMotionUp(ui::LogicalDisplayId::DEFAULT);
Garfield Tandf26e862020-07-01 20:18:19 -07005066
Siarhei Vishniakoua235c042023-05-02 09:59:09 -07005067 // We already canceled the hovering implicitly by injecting the "DOWN" event without lifting the
5068 // hover first. Therefore, injection of HOVER_EXIT is inconsistent, and should fail.
5069 ASSERT_EQ(InputEventInjectionResult::FAILED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07005070 injectMotionEvent(*mDispatcher,
Garfield Tandf26e862020-07-01 20:18:19 -07005071 MotionEventBuilder(AMOTION_EVENT_ACTION_HOVER_EXIT,
5072 AINPUT_SOURCE_MOUSE)
Siarhei Vishniakou6d73f832022-07-21 17:27:03 -07005073 .pointer(PointerBuilder(0, ToolType::MOUSE).x(300).y(400))
Garfield Tandf26e862020-07-01 20:18:19 -07005074 .build()));
Siarhei Vishniakouf372b812023-02-14 18:06:51 -08005075 window->assertNoEvents();
Garfield Tandf26e862020-07-01 20:18:19 -07005076}
5077
Siarhei Vishniakou0b0374d2022-11-17 17:40:53 -08005078/**
Siarhei Vishniakoub581f7f2022-12-07 20:23:06 +00005079 * Hover over a window, and then remove that window. Make sure that HOVER_EXIT for that event
5080 * is generated.
5081 */
5082TEST_F(InputDispatcherTest, HoverExitIsSentToRemovedWindow) {
5083 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07005084 sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher, "Window",
5085 ui::LogicalDisplayId::DEFAULT);
Siarhei Vishniakoub581f7f2022-12-07 20:23:06 +00005086 window->setFrame(Rect(0, 0, 1200, 800));
5087
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07005088 mDispatcher->setFocusedApplication(ui::LogicalDisplayId::DEFAULT, application);
Siarhei Vishniakoub581f7f2022-12-07 20:23:06 +00005089
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07005090 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Siarhei Vishniakoub581f7f2022-12-07 20:23:06 +00005091
5092 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07005093 injectMotionEvent(*mDispatcher,
Siarhei Vishniakoub581f7f2022-12-07 20:23:06 +00005094 MotionEventBuilder(AMOTION_EVENT_ACTION_HOVER_ENTER,
5095 AINPUT_SOURCE_MOUSE)
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07005096 .pointer(PointerBuilder(0, ToolType::MOUSE).x(300).y(400))
Siarhei Vishniakoub581f7f2022-12-07 20:23:06 +00005097 .build()));
5098 window->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_ENTER));
5099
5100 // Remove the window, but keep the channel.
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07005101 mDispatcher->onWindowInfosChanged({{}, {}, 0, 0});
Siarhei Vishniakoub581f7f2022-12-07 20:23:06 +00005102 window->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_EXIT));
5103}
5104
5105/**
Daniel Norman7487dfa2023-08-02 16:39:45 -07005106 * Test that invalid HOVER events sent by accessibility do not cause a fatal crash.
5107 */
Ameer Armalycff4fa52023-10-04 23:45:11 +00005108TEST_F_WITH_FLAGS(InputDispatcherTest, InvalidA11yHoverStreamDoesNotCrash,
5109 REQUIRES_FLAGS_DISABLED(ACONFIG_FLAG(com::android::input::flags,
5110 a11y_crash_on_inconsistent_event_stream))) {
Daniel Norman7487dfa2023-08-02 16:39:45 -07005111 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07005112 sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher, "Window",
5113 ui::LogicalDisplayId::DEFAULT);
Daniel Norman7487dfa2023-08-02 16:39:45 -07005114 window->setFrame(Rect(0, 0, 1200, 800));
5115
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07005116 mDispatcher->setFocusedApplication(ui::LogicalDisplayId::DEFAULT, application);
Daniel Norman7487dfa2023-08-02 16:39:45 -07005117
5118 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
5119
5120 MotionEventBuilder hoverEnterBuilder =
5121 MotionEventBuilder(AMOTION_EVENT_ACTION_HOVER_ENTER, AINPUT_SOURCE_MOUSE)
5122 .pointer(PointerBuilder(0, ToolType::MOUSE).x(300).y(400))
5123 .addFlag(AMOTION_EVENT_FLAG_IS_ACCESSIBILITY_EVENT);
5124 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
5125 injectMotionEvent(*mDispatcher, hoverEnterBuilder.build()));
5126 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
5127 injectMotionEvent(*mDispatcher, hoverEnterBuilder.build()));
5128 window->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_ENTER));
5129 window->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_ENTER));
5130}
5131
5132/**
Siarhei Vishniakou9d0d65e2024-08-02 12:10:05 -07005133 * Invalid events injected by input filter are rejected.
5134 */
5135TEST_F(InputDispatcherTest, InvalidA11yEventsGetRejected) {
5136 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
5137 sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher, "Window",
5138 ui::LogicalDisplayId::DEFAULT);
5139
5140 mDispatcher->setFocusedApplication(ui::LogicalDisplayId::DEFAULT, application);
5141
5142 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
5143
5144 // a11y sets 'POLICY_FLAG_INJECTED_FROM_ACCESSIBILITY' policy flag during injection, so define
5145 // a custom injection function here for convenience.
5146 auto injectFromAccessibility = [&](int32_t action, float x, float y) {
5147 MotionEvent event = MotionEventBuilder(action, AINPUT_SOURCE_TOUCHSCREEN)
5148 .pointer(PointerBuilder(0, ToolType::FINGER).x(x).y(y))
5149 .addFlag(AMOTION_EVENT_FLAG_IS_ACCESSIBILITY_EVENT)
5150 .build();
5151 return injectMotionEvent(*mDispatcher, event, 100ms,
5152 InputEventInjectionSync::WAIT_FOR_RESULT, /*targetUid=*/{},
5153 POLICY_FLAG_PASS_TO_USER | POLICY_FLAG_FILTERED |
5154 POLICY_FLAG_INJECTED_FROM_ACCESSIBILITY);
5155 };
5156
5157 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
5158 injectFromAccessibility(ACTION_DOWN, /*x=*/300, /*y=*/400));
5159 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
5160 injectFromAccessibility(ACTION_MOVE, /*x=*/310, /*y=*/420));
5161 window->consumeMotionEvent(WithMotionAction(ACTION_DOWN));
5162 window->consumeMotionEvent(WithMotionAction(ACTION_MOVE));
5163 // finger is still down, so a new DOWN event should be rejected!
5164 ASSERT_EQ(InputEventInjectionResult::FAILED,
5165 injectFromAccessibility(ACTION_DOWN, /*x=*/340, /*y=*/410));
5166
5167 // if the gesture is correctly finished, new down event will succeed
5168 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
5169 injectFromAccessibility(ACTION_MOVE, /*x=*/320, /*y=*/430));
5170 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
5171 injectFromAccessibility(ACTION_UP, /*x=*/320, /*y=*/430));
5172 window->consumeMotionEvent(WithMotionAction(ACTION_MOVE));
5173 window->consumeMotionEvent(WithMotionAction(ACTION_UP));
5174
5175 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
5176 injectFromAccessibility(ACTION_DOWN, /*x=*/350, /*y=*/460));
5177 window->consumeMotionEvent(WithMotionAction(ACTION_DOWN));
5178}
5179
5180/**
Siarhei Vishniakou4e1ffa52023-02-21 11:50:34 -08005181 * If mouse is hovering when the touch goes down, the hovering should be stopped via HOVER_EXIT.
5182 */
Siarhei Vishniakoued89cbb2023-10-13 10:42:44 -07005183TEST_F(InputDispatcherTest, TouchDownAfterMouseHover_legacy) {
5184 SCOPED_FLAG_OVERRIDE(enable_multi_device_same_window_stream, false);
Siarhei Vishniakou4e1ffa52023-02-21 11:50:34 -08005185 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07005186 sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher, "Window",
5187 ui::LogicalDisplayId::DEFAULT);
Siarhei Vishniakou4e1ffa52023-02-21 11:50:34 -08005188 window->setFrame(Rect(0, 0, 100, 100));
5189
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07005190 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Siarhei Vishniakou4e1ffa52023-02-21 11:50:34 -08005191
5192 const int32_t mouseDeviceId = 7;
5193 const int32_t touchDeviceId = 4;
Siarhei Vishniakou4e1ffa52023-02-21 11:50:34 -08005194
5195 // Start hovering with the mouse
Prabir Pradhan678438e2023-04-13 19:32:51 +00005196 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_ENTER, AINPUT_SOURCE_MOUSE)
5197 .deviceId(mouseDeviceId)
5198 .pointer(PointerBuilder(0, ToolType::MOUSE).x(10).y(10))
5199 .build());
Siarhei Vishniakou4e1ffa52023-02-21 11:50:34 -08005200 window->consumeMotionEvent(
5201 AllOf(WithMotionAction(ACTION_HOVER_ENTER), WithDeviceId(mouseDeviceId)));
5202
5203 // Touch goes down
Prabir Pradhan678438e2023-04-13 19:32:51 +00005204 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
5205 .deviceId(touchDeviceId)
5206 .pointer(PointerBuilder(0, ToolType::FINGER).x(50).y(50))
5207 .build());
Siarhei Vishniakou4e1ffa52023-02-21 11:50:34 -08005208
5209 window->consumeMotionEvent(
5210 AllOf(WithMotionAction(ACTION_HOVER_EXIT), WithDeviceId(mouseDeviceId)));
5211 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(touchDeviceId)));
5212}
5213
5214/**
Siarhei Vishniakoued89cbb2023-10-13 10:42:44 -07005215 * If mouse is hovering when the touch goes down, the hovering should not be stopped.
5216 */
5217TEST_F(InputDispatcherTest, TouchDownAfterMouseHover) {
5218 SCOPED_FLAG_OVERRIDE(enable_multi_device_same_window_stream, true);
5219 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07005220 sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher, "Window",
5221 ui::LogicalDisplayId::DEFAULT);
Siarhei Vishniakoued89cbb2023-10-13 10:42:44 -07005222 window->setFrame(Rect(0, 0, 100, 100));
5223
5224 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
5225
5226 const int32_t mouseDeviceId = 7;
5227 const int32_t touchDeviceId = 4;
5228
5229 // Start hovering with the mouse
5230 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_ENTER, AINPUT_SOURCE_MOUSE)
5231 .deviceId(mouseDeviceId)
5232 .pointer(PointerBuilder(0, ToolType::MOUSE).x(10).y(10))
5233 .build());
5234 window->consumeMotionEvent(
5235 AllOf(WithMotionAction(ACTION_HOVER_ENTER), WithDeviceId(mouseDeviceId)));
5236
5237 // Touch goes down
5238 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
5239 .deviceId(touchDeviceId)
5240 .pointer(PointerBuilder(0, ToolType::FINGER).x(50).y(50))
5241 .build());
5242 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(touchDeviceId)));
5243}
5244
5245/**
Siarhei Vishniakou0b0374d2022-11-17 17:40:53 -08005246 * Inject a mouse hover event followed by a tap from touchscreen.
Siarhei Vishniakoub581f7f2022-12-07 20:23:06 +00005247 * The tap causes a HOVER_EXIT event to be generated because the current event
5248 * stream's source has been switched.
Siarhei Vishniakou0b0374d2022-11-17 17:40:53 -08005249 */
Siarhei Vishniakoued89cbb2023-10-13 10:42:44 -07005250TEST_F(InputDispatcherTest, MouseHoverAndTouchTap_legacy) {
5251 SCOPED_FLAG_OVERRIDE(enable_multi_device_same_window_stream, false);
Siarhei Vishniakou0b0374d2022-11-17 17:40:53 -08005252 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07005253 sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher, "Window",
5254 ui::LogicalDisplayId::DEFAULT);
Siarhei Vishniakou0b0374d2022-11-17 17:40:53 -08005255 window->setFrame(Rect(0, 0, 100, 100));
5256
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07005257 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -07005258 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_MOVE, AINPUT_SOURCE_MOUSE)
5259 .pointer(PointerBuilder(0, ToolType::MOUSE).x(50).y(50))
5260 .build());
Siarhei Vishniakou0b0374d2022-11-17 17:40:53 -08005261 ASSERT_NO_FATAL_FAILURE(
5262 window->consumeMotionEvent(AllOf(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_ENTER),
5263 WithSource(AINPUT_SOURCE_MOUSE))));
Siarhei Vishniakou0b0374d2022-11-17 17:40:53 -08005264
5265 // Tap on the window
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -07005266 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
5267 .pointer(PointerBuilder(0, ToolType::FINGER).x(10).y(10))
5268 .build());
Siarhei Vishniakou0b0374d2022-11-17 17:40:53 -08005269 ASSERT_NO_FATAL_FAILURE(
Siarhei Vishniakoub581f7f2022-12-07 20:23:06 +00005270 window->consumeMotionEvent(AllOf(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_EXIT),
5271 WithSource(AINPUT_SOURCE_MOUSE))));
5272
5273 ASSERT_NO_FATAL_FAILURE(
Siarhei Vishniakou0b0374d2022-11-17 17:40:53 -08005274 window->consumeMotionEvent(AllOf(WithMotionAction(AMOTION_EVENT_ACTION_DOWN),
5275 WithSource(AINPUT_SOURCE_TOUCHSCREEN))));
5276
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -07005277 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN)
5278 .pointer(PointerBuilder(0, ToolType::FINGER).x(10).y(10))
5279 .build());
Siarhei Vishniakou0b0374d2022-11-17 17:40:53 -08005280 ASSERT_NO_FATAL_FAILURE(
5281 window->consumeMotionEvent(AllOf(WithMotionAction(AMOTION_EVENT_ACTION_UP),
5282 WithSource(AINPUT_SOURCE_TOUCHSCREEN))));
5283}
5284
Siarhei Vishniakoued89cbb2023-10-13 10:42:44 -07005285/**
5286 * Send a mouse hover event followed by a tap from touchscreen.
5287 * The tap causes a HOVER_EXIT event to be generated because the current event
5288 * stream's source has been switched.
5289 */
5290TEST_F(InputDispatcherTest, MouseHoverAndTouchTap) {
5291 SCOPED_FLAG_OVERRIDE(enable_multi_device_same_window_stream, true);
5292 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07005293 sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher, "Window",
5294 ui::LogicalDisplayId::DEFAULT);
Siarhei Vishniakoued89cbb2023-10-13 10:42:44 -07005295 window->setFrame(Rect(0, 0, 100, 100));
5296
5297 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
5298 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_MOVE, AINPUT_SOURCE_MOUSE)
5299 .pointer(PointerBuilder(0, ToolType::MOUSE).x(50).y(50))
5300 .build());
5301
5302 window->consumeMotionEvent(AllOf(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_ENTER),
5303 WithSource(AINPUT_SOURCE_MOUSE)));
5304
5305 // Tap on the window
5306 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
5307 .pointer(PointerBuilder(0, ToolType::FINGER).x(10).y(10))
5308 .build());
5309
5310 window->consumeMotionEvent(AllOf(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_EXIT),
5311 WithSource(AINPUT_SOURCE_MOUSE)));
5312
5313 window->consumeMotionEvent(AllOf(WithMotionAction(AMOTION_EVENT_ACTION_DOWN),
5314 WithSource(AINPUT_SOURCE_TOUCHSCREEN)));
5315
5316 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN)
5317 .pointer(PointerBuilder(0, ToolType::FINGER).x(10).y(10))
5318 .build());
5319
5320 window->consumeMotionEvent(AllOf(WithMotionAction(AMOTION_EVENT_ACTION_UP),
5321 WithSource(AINPUT_SOURCE_TOUCHSCREEN)));
5322}
5323
Tommy Nordgrendae9dfc2022-10-13 11:25:57 +02005324TEST_F(InputDispatcherTest, HoverEnterMoveRemoveWindowsInSecondDisplay) {
5325 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
5326 sp<FakeWindowHandle> windowDefaultDisplay =
5327 sp<FakeWindowHandle>::make(application, mDispatcher, "DefaultDisplay",
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07005328 ui::LogicalDisplayId::DEFAULT);
Tommy Nordgrendae9dfc2022-10-13 11:25:57 +02005329 windowDefaultDisplay->setFrame(Rect(0, 0, 600, 800));
5330 sp<FakeWindowHandle> windowSecondDisplay =
5331 sp<FakeWindowHandle>::make(application, mDispatcher, "SecondDisplay",
5332 SECOND_DISPLAY_ID);
5333 windowSecondDisplay->setFrame(Rect(0, 0, 600, 800));
5334
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07005335 mDispatcher->onWindowInfosChanged(
5336 {{*windowDefaultDisplay->getInfo(), *windowSecondDisplay->getInfo()}, {}, 0, 0});
Tommy Nordgrendae9dfc2022-10-13 11:25:57 +02005337
5338 // Set cursor position in window in default display and check that hover enter and move
5339 // events are generated.
5340 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07005341 injectMotionEvent(*mDispatcher,
Tommy Nordgrendae9dfc2022-10-13 11:25:57 +02005342 MotionEventBuilder(AMOTION_EVENT_ACTION_HOVER_MOVE,
5343 AINPUT_SOURCE_MOUSE)
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07005344 .displayId(ui::LogicalDisplayId::DEFAULT)
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07005345 .pointer(PointerBuilder(0, ToolType::MOUSE).x(300).y(600))
Tommy Nordgrendae9dfc2022-10-13 11:25:57 +02005346 .build()));
Siarhei Vishniakou5cee1e32022-11-29 12:35:39 -08005347 windowDefaultDisplay->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_ENTER));
Tommy Nordgrendae9dfc2022-10-13 11:25:57 +02005348
5349 // Remove all windows in secondary display and check that no event happens on window in
5350 // primary display.
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07005351 mDispatcher->onWindowInfosChanged({{*windowDefaultDisplay->getInfo()}, {}, 0, 0});
5352
Tommy Nordgrendae9dfc2022-10-13 11:25:57 +02005353 windowDefaultDisplay->assertNoEvents();
5354
5355 // Move cursor position in window in default display and check that only hover move
5356 // event is generated and not hover enter event.
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07005357 mDispatcher->onWindowInfosChanged(
5358 {{*windowDefaultDisplay->getInfo(), *windowSecondDisplay->getInfo()}, {}, 0, 0});
Tommy Nordgrendae9dfc2022-10-13 11:25:57 +02005359 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07005360 injectMotionEvent(*mDispatcher,
Tommy Nordgrendae9dfc2022-10-13 11:25:57 +02005361 MotionEventBuilder(AMOTION_EVENT_ACTION_HOVER_MOVE,
5362 AINPUT_SOURCE_MOUSE)
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07005363 .displayId(ui::LogicalDisplayId::DEFAULT)
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07005364 .pointer(PointerBuilder(0, ToolType::MOUSE).x(400).y(700))
Tommy Nordgrendae9dfc2022-10-13 11:25:57 +02005365 .build()));
Siarhei Vishniakou5cee1e32022-11-29 12:35:39 -08005366 windowDefaultDisplay->consumeMotionEvent(
5367 AllOf(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_MOVE),
5368 WithSource(AINPUT_SOURCE_MOUSE)));
Tommy Nordgrendae9dfc2022-10-13 11:25:57 +02005369 windowDefaultDisplay->assertNoEvents();
5370}
5371
Garfield Tan00f511d2019-06-12 16:55:40 -07005372TEST_F(InputDispatcherTest, DispatchMouseEventsUnderCursor) {
Chris Yea209fde2020-07-22 13:54:51 -07005373 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
Garfield Tan00f511d2019-06-12 16:55:40 -07005374
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07005375 sp<FakeWindowHandle> windowLeft = sp<FakeWindowHandle>::make(application, mDispatcher, "Left",
5376 ui::LogicalDisplayId::DEFAULT);
Garfield Tan00f511d2019-06-12 16:55:40 -07005377 windowLeft->setFrame(Rect(0, 0, 600, 800));
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07005378 sp<FakeWindowHandle> windowRight = sp<FakeWindowHandle>::make(application, mDispatcher, "Right",
5379 ui::LogicalDisplayId::DEFAULT);
Garfield Tan00f511d2019-06-12 16:55:40 -07005380 windowRight->setFrame(Rect(600, 0, 1200, 800));
Garfield Tan00f511d2019-06-12 16:55:40 -07005381
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07005382 mDispatcher->setFocusedApplication(ui::LogicalDisplayId::DEFAULT, application);
Garfield Tan00f511d2019-06-12 16:55:40 -07005383
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07005384 mDispatcher->onWindowInfosChanged(
5385 {{*windowLeft->getInfo(), *windowRight->getInfo()}, {}, 0, 0});
Garfield Tan00f511d2019-06-12 16:55:40 -07005386
5387 // Inject an event with coordinate in the area of right window, with mouse cursor in the area of
5388 // left window. This event should be dispatched to the left window.
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08005389 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07005390 injectMotionEvent(*mDispatcher, AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_MOUSE,
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07005391 ui::LogicalDisplayId::DEFAULT, {610, 400}, {599, 400}));
5392 windowLeft->consumeMotionDown(ui::LogicalDisplayId::DEFAULT);
Garfield Tan00f511d2019-06-12 16:55:40 -07005393 windowRight->assertNoEvents();
5394}
5395
Siarhei Vishniakou2bfa9052019-11-21 18:10:54 -08005396TEST_F(InputDispatcherTest, NotifyDeviceReset_CancelsKeyStream) {
Chris Yea209fde2020-07-22 13:54:51 -07005397 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07005398 sp<FakeWindowHandle> window =
5399 sp<FakeWindowHandle>::make(application, mDispatcher, "Fake Window",
5400 ui::LogicalDisplayId::DEFAULT);
Vishnu Nair47074b82020-08-14 11:54:47 -07005401 window->setFocusable(true);
Siarhei Vishniakou2bfa9052019-11-21 18:10:54 -08005402
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07005403 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Vishnu Nair958da932020-08-21 17:12:37 -07005404 setFocusedWindow(window);
5405
Siarhei Vishniakouf1035d42019-09-20 16:32:01 +01005406 window->consumeFocusEvent(true);
Siarhei Vishniakou2bfa9052019-11-21 18:10:54 -08005407
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07005408 mDispatcher->notifyKey(generateKeyArgs(AKEY_EVENT_ACTION_DOWN, ui::LogicalDisplayId::DEFAULT));
Siarhei Vishniakou2bfa9052019-11-21 18:10:54 -08005409
5410 // Window should receive key down event.
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07005411 window->consumeKeyDown(ui::LogicalDisplayId::DEFAULT);
Siarhei Vishniakou2bfa9052019-11-21 18:10:54 -08005412
5413 // When device reset happens, that key stream should be terminated with FLAG_CANCELED
5414 // on the app side.
Prabir Pradhan678438e2023-04-13 19:32:51 +00005415 mDispatcher->notifyDeviceReset({/*id=*/10, /*eventTime=*/20, DEVICE_ID});
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07005416 window->consumeKeyUp(ui::LogicalDisplayId::DEFAULT, AKEY_EVENT_FLAG_CANCELED);
Siarhei Vishniakou2bfa9052019-11-21 18:10:54 -08005417}
5418
5419TEST_F(InputDispatcherTest, NotifyDeviceReset_CancelsMotionStream) {
Chris Yea209fde2020-07-22 13:54:51 -07005420 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07005421 sp<FakeWindowHandle> window =
5422 sp<FakeWindowHandle>::make(application, mDispatcher, "Fake Window",
5423 ui::LogicalDisplayId::DEFAULT);
Siarhei Vishniakou2bfa9052019-11-21 18:10:54 -08005424
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07005425 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Siarhei Vishniakou2bfa9052019-11-21 18:10:54 -08005426
Prabir Pradhan678438e2023-04-13 19:32:51 +00005427 mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_DOWN,
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07005428 AINPUT_SOURCE_TOUCHSCREEN,
5429 ui::LogicalDisplayId::DEFAULT));
Siarhei Vishniakou2bfa9052019-11-21 18:10:54 -08005430
5431 // Window should receive motion down event.
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07005432 window->consumeMotionDown(ui::LogicalDisplayId::DEFAULT);
Siarhei Vishniakou2bfa9052019-11-21 18:10:54 -08005433
5434 // When device reset happens, that motion stream should be terminated with ACTION_CANCEL
5435 // on the app side.
Prabir Pradhan678438e2023-04-13 19:32:51 +00005436 mDispatcher->notifyDeviceReset({/*id=*/10, /*eventTime=*/20, DEVICE_ID});
Siarhei Vishniakou1ae72f12023-01-29 12:55:30 -08005437 window->consumeMotionEvent(
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07005438 AllOf(WithMotionAction(ACTION_CANCEL), WithDisplayId(ui::LogicalDisplayId::DEFAULT)));
Siarhei Vishniakou2bfa9052019-11-21 18:10:54 -08005439}
5440
Siarhei Vishniakou0686f0c2023-05-02 11:56:15 -07005441TEST_F(InputDispatcherTest, NotifyDeviceResetCancelsHoveringStream) {
5442 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07005443 sp<FakeWindowHandle> window =
5444 sp<FakeWindowHandle>::make(application, mDispatcher, "Fake Window",
5445 ui::LogicalDisplayId::DEFAULT);
Siarhei Vishniakou0686f0c2023-05-02 11:56:15 -07005446
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07005447 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Siarhei Vishniakou0686f0c2023-05-02 11:56:15 -07005448
5449 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_ENTER, AINPUT_SOURCE_STYLUS)
5450 .pointer(PointerBuilder(0, ToolType::STYLUS).x(10).y(10))
5451 .build());
5452
5453 window->consumeMotionEvent(WithMotionAction(ACTION_HOVER_ENTER));
5454
5455 // When device reset happens, that hover stream should be terminated with ACTION_HOVER_EXIT
5456 mDispatcher->notifyDeviceReset({/*id=*/10, /*eventTime=*/20, DEVICE_ID});
5457 window->consumeMotionEvent(WithMotionAction(ACTION_HOVER_EXIT));
5458
5459 // After the device has been reset, a new hovering stream can be sent to the window
5460 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_ENTER, AINPUT_SOURCE_STYLUS)
5461 .pointer(PointerBuilder(0, ToolType::STYLUS).x(15).y(15))
5462 .build());
5463 window->consumeMotionEvent(WithMotionAction(ACTION_HOVER_ENTER));
5464}
5465
Arthur Hung2ee6d0b2022-03-03 20:19:38 +08005466TEST_F(InputDispatcherTest, InterceptKeyByPolicy) {
5467 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07005468 sp<FakeWindowHandle> window =
5469 sp<FakeWindowHandle>::make(application, mDispatcher, "Fake Window",
5470 ui::LogicalDisplayId::DEFAULT);
Arthur Hung2ee6d0b2022-03-03 20:19:38 +08005471 window->setFocusable(true);
5472
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07005473 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Arthur Hung2ee6d0b2022-03-03 20:19:38 +08005474 setFocusedWindow(window);
5475
5476 window->consumeFocusEvent(true);
5477
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07005478 const NotifyKeyArgs keyArgs =
5479 generateKeyArgs(AKEY_EVENT_ACTION_DOWN, ui::LogicalDisplayId::DEFAULT);
Arthur Hung2ee6d0b2022-03-03 20:19:38 +08005480 const std::chrono::milliseconds interceptKeyTimeout = 50ms;
5481 const nsecs_t injectTime = keyArgs.eventTime;
5482 mFakePolicy->setInterceptKeyTimeout(interceptKeyTimeout);
Prabir Pradhan678438e2023-04-13 19:32:51 +00005483 mDispatcher->notifyKey(keyArgs);
Arthur Hung2ee6d0b2022-03-03 20:19:38 +08005484 // The dispatching time should be always greater than or equal to intercept key timeout.
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07005485 window->consumeKeyDown(ui::LogicalDisplayId::DEFAULT);
Arthur Hung2ee6d0b2022-03-03 20:19:38 +08005486 ASSERT_TRUE((systemTime(SYSTEM_TIME_MONOTONIC) - injectTime) >=
5487 std::chrono::nanoseconds(interceptKeyTimeout).count());
5488}
5489
Siarhei Vishniakouf54d2ab2023-06-09 13:23:53 -07005490/**
5491 * Keys with ACTION_UP are delivered immediately, even if a long 'intercept key timeout' is set.
5492 */
Arthur Hung2ee6d0b2022-03-03 20:19:38 +08005493TEST_F(InputDispatcherTest, InterceptKeyIfKeyUp) {
5494 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07005495 sp<FakeWindowHandle> window =
5496 sp<FakeWindowHandle>::make(application, mDispatcher, "Fake Window",
5497 ui::LogicalDisplayId::DEFAULT);
Arthur Hung2ee6d0b2022-03-03 20:19:38 +08005498 window->setFocusable(true);
5499
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07005500 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Arthur Hung2ee6d0b2022-03-03 20:19:38 +08005501 setFocusedWindow(window);
5502
5503 window->consumeFocusEvent(true);
5504
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07005505 mDispatcher->notifyKey(generateKeyArgs(AKEY_EVENT_ACTION_DOWN, ui::LogicalDisplayId::DEFAULT));
5506 window->consumeKeyDown(ui::LogicalDisplayId::DEFAULT);
Siarhei Vishniakouf54d2ab2023-06-09 13:23:53 -07005507
5508 // Set a value that's significantly larger than the default consumption timeout. If the
5509 // implementation is correct, the actual value doesn't matter; it won't slow down the test.
5510 mFakePolicy->setInterceptKeyTimeout(600ms);
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07005511 mDispatcher->notifyKey(generateKeyArgs(AKEY_EVENT_ACTION_UP, ui::LogicalDisplayId::DEFAULT));
Siarhei Vishniakouf54d2ab2023-06-09 13:23:53 -07005512 // Window should receive key event immediately when same key up.
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07005513 window->consumeKeyUp(ui::LogicalDisplayId::DEFAULT);
Arthur Hung2ee6d0b2022-03-03 20:19:38 +08005514}
5515
Prabir Pradhanc44ce4d2021-10-05 05:26:29 -07005516/**
Siarhei Vishniakou487c49b2022-12-02 15:48:57 -08005517 * Two windows. First is a regular window. Second does not overlap with the first, and has
5518 * WATCH_OUTSIDE_TOUCH.
5519 * Both windows are owned by the same UID.
5520 * Tap first window. Make sure that the second window receives ACTION_OUTSIDE with correct, non-zero
5521 * coordinates. The coordinates are not zeroed out because both windows are owned by the same UID.
5522 */
5523TEST_F(InputDispatcherTest, ActionOutsideForOwnedWindowHasValidCoordinates) {
5524 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07005525 sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher, "Window",
5526 ui::LogicalDisplayId::DEFAULT);
Siarhei Vishniakou487c49b2022-12-02 15:48:57 -08005527 window->setFrame(Rect{0, 0, 100, 100});
5528
5529 sp<FakeWindowHandle> outsideWindow =
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -07005530 sp<FakeWindowHandle>::make(application, mDispatcher, "Outside Window",
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07005531 ui::LogicalDisplayId::DEFAULT);
Siarhei Vishniakou487c49b2022-12-02 15:48:57 -08005532 outsideWindow->setFrame(Rect{100, 100, 200, 200});
5533 outsideWindow->setWatchOutsideTouch(true);
5534 // outsideWindow must be above 'window' to receive ACTION_OUTSIDE events when 'window' is tapped
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07005535 mDispatcher->onWindowInfosChanged({{*outsideWindow->getInfo(), *window->getInfo()}, {}, 0, 0});
Siarhei Vishniakou487c49b2022-12-02 15:48:57 -08005536
5537 // Tap on first window.
Prabir Pradhan678438e2023-04-13 19:32:51 +00005538 mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_DOWN,
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07005539 AINPUT_SOURCE_TOUCHSCREEN,
5540 ui::LogicalDisplayId::DEFAULT, {PointF{50, 50}}));
Siarhei Vishniakou487c49b2022-12-02 15:48:57 -08005541 window->consumeMotionDown();
5542 // The coordinates of the tap in 'outsideWindow' are relative to its top left corner.
5543 // Therefore, we should offset them by (100, 100) relative to the screen's top left corner.
5544 outsideWindow->consumeMotionEvent(
5545 AllOf(WithMotionAction(ACTION_OUTSIDE), WithCoords(-50, -50)));
Prabir Pradhan502a7252023-12-01 16:11:24 +00005546
5547 // Ensure outsideWindow doesn't get any more events for the gesture.
5548 mDispatcher->notifyMotion(generateMotionArgs(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN,
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07005549 ui::LogicalDisplayId::DEFAULT, {PointF{51, 51}}));
Prabir Pradhan502a7252023-12-01 16:11:24 +00005550 window->consumeMotionMove();
5551 outsideWindow->assertNoEvents();
Siarhei Vishniakou487c49b2022-12-02 15:48:57 -08005552}
5553
5554/**
Linnan Liccf6ce32024-04-11 20:32:13 +08005555 * Three windows:
5556 * - Left window
5557 * - Right window
5558 * - Outside window(watch for ACTION_OUTSIDE events)
5559 * The windows "left" and "outside" share the same owner, the window "right" has a different owner,
5560 * In order to allow the outside window can receive the ACTION_OUTSIDE events, the outside window is
5561 * positioned above the "left" and "right" windows, and it doesn't overlap with them.
5562 *
5563 * First, device A report a down event landed in the right window, the outside window can receive
5564 * an ACTION_OUTSIDE event that with zeroed coordinates, the device B report a down event landed
5565 * in the left window, the outside window can receive an ACTION_OUTSIDE event the with valid
5566 * coordinates, after these, device A and device B continue report MOVE event, the right and left
5567 * window can receive it, but outside window event can't receive it.
5568 */
5569TEST_F(InputDispatcherTest, ActionOutsideForOwnedWindowHasValidCoordinatesWhenMultiDevice) {
5570 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
5571 sp<FakeWindowHandle> leftWindow =
5572 sp<FakeWindowHandle>::make(application, mDispatcher, "Left Window",
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07005573 ui::LogicalDisplayId::DEFAULT);
Linnan Liccf6ce32024-04-11 20:32:13 +08005574 leftWindow->setFrame(Rect{0, 0, 100, 100});
5575 leftWindow->setOwnerInfo(gui::Pid{1}, gui::Uid{101});
5576
5577 sp<FakeWindowHandle> outsideWindow =
5578 sp<FakeWindowHandle>::make(application, mDispatcher, "Outside Window",
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07005579 ui::LogicalDisplayId::DEFAULT);
Linnan Liccf6ce32024-04-11 20:32:13 +08005580 outsideWindow->setFrame(Rect{100, 100, 200, 200});
5581 outsideWindow->setOwnerInfo(gui::Pid{1}, gui::Uid{101});
5582 outsideWindow->setWatchOutsideTouch(true);
5583
5584 std::shared_ptr<FakeApplicationHandle> anotherApplication =
5585 std::make_shared<FakeApplicationHandle>();
5586 sp<FakeWindowHandle> rightWindow =
5587 sp<FakeWindowHandle>::make(anotherApplication, mDispatcher, "Right Window",
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07005588 ui::LogicalDisplayId::DEFAULT);
Linnan Liccf6ce32024-04-11 20:32:13 +08005589 rightWindow->setFrame(Rect{100, 0, 200, 100});
5590 rightWindow->setOwnerInfo(gui::Pid{2}, gui::Uid{202});
5591
5592 // OutsideWindow must be above left window and right window to receive ACTION_OUTSIDE events
5593 // when left window or right window is tapped
5594 mDispatcher->onWindowInfosChanged(
5595 {{*outsideWindow->getInfo(), *leftWindow->getInfo(), *rightWindow->getInfo()},
5596 {},
5597 0,
5598 0});
5599
5600 const DeviceId deviceA = 9;
5601 const DeviceId deviceB = 3;
5602
5603 // Tap on right window use device A
5604 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
5605 .pointer(PointerBuilder(0, ToolType::FINGER).x(150).y(50))
5606 .deviceId(deviceA)
5607 .build());
5608 leftWindow->assertNoEvents();
5609 rightWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(deviceA)));
5610 // Right window is belonged to another owner, so outsideWindow should receive ACTION_OUTSIDE
5611 // with zeroed coords.
5612 outsideWindow->consumeMotionEvent(
5613 AllOf(WithMotionAction(ACTION_OUTSIDE), WithDeviceId(deviceA), WithCoords(0, 0)));
5614
5615 // Tap on left window use device B
5616 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
5617 .pointer(PointerBuilder(0, ToolType::FINGER).x(50).y(50))
5618 .deviceId(deviceB)
5619 .build());
5620 leftWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(deviceB)));
5621 rightWindow->assertNoEvents();
5622 // Because new gesture down on the left window that has the same owner with outside Window, the
5623 // outside Window should receive the ACTION_OUTSIDE with coords.
5624 outsideWindow->consumeMotionEvent(
5625 AllOf(WithMotionAction(ACTION_OUTSIDE), WithDeviceId(deviceB), WithCoords(-50, -50)));
5626
5627 // Ensure that windows that can only accept outside do not receive remaining gestures
5628 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN)
5629 .pointer(PointerBuilder(0, ToolType::FINGER).x(151).y(51))
5630 .deviceId(deviceA)
5631 .build());
5632 leftWindow->assertNoEvents();
5633 rightWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(deviceA)));
5634
5635 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN)
5636 .pointer(PointerBuilder(0, ToolType::FINGER).x(51).y(51))
5637 .deviceId(deviceB)
5638 .build());
5639 leftWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(deviceB)));
5640 rightWindow->assertNoEvents();
5641 outsideWindow->assertNoEvents();
5642}
5643
5644/**
Prabir Pradhanb60b1dc2022-03-15 14:02:35 +00005645 * This test documents the behavior of WATCH_OUTSIDE_TOUCH. The window will get ACTION_OUTSIDE when
5646 * a another pointer causes ACTION_DOWN to be sent to another window for the first time. Only one
5647 * ACTION_OUTSIDE event is sent per gesture.
5648 */
5649TEST_F(InputDispatcherTest, ActionOutsideSentOnlyWhenAWindowIsTouched) {
5650 // There are three windows that do not overlap. `window` wants to WATCH_OUTSIDE_TOUCH.
5651 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07005652 sp<FakeWindowHandle> window =
5653 sp<FakeWindowHandle>::make(application, mDispatcher, "First Window",
5654 ui::LogicalDisplayId::DEFAULT);
Prabir Pradhanb60b1dc2022-03-15 14:02:35 +00005655 window->setWatchOutsideTouch(true);
5656 window->setFrame(Rect{0, 0, 100, 100});
5657 sp<FakeWindowHandle> secondWindow =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07005658 sp<FakeWindowHandle>::make(application, mDispatcher, "Second Window",
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07005659 ui::LogicalDisplayId::DEFAULT);
Prabir Pradhanb60b1dc2022-03-15 14:02:35 +00005660 secondWindow->setFrame(Rect{100, 100, 200, 200});
5661 sp<FakeWindowHandle> thirdWindow =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07005662 sp<FakeWindowHandle>::make(application, mDispatcher, "Third Window",
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07005663 ui::LogicalDisplayId::DEFAULT);
Prabir Pradhanb60b1dc2022-03-15 14:02:35 +00005664 thirdWindow->setFrame(Rect{200, 200, 300, 300});
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07005665 mDispatcher->onWindowInfosChanged(
5666 {{*window->getInfo(), *secondWindow->getInfo(), *thirdWindow->getInfo()}, {}, 0, 0});
Prabir Pradhanb60b1dc2022-03-15 14:02:35 +00005667
5668 // First pointer lands outside all windows. `window` does not get ACTION_OUTSIDE.
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07005669 mDispatcher->notifyMotion(
5670 generateMotionArgs(AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN,
5671 ui::LogicalDisplayId::DEFAULT, {PointF{-10, -10}}));
Prabir Pradhanb60b1dc2022-03-15 14:02:35 +00005672 window->assertNoEvents();
5673 secondWindow->assertNoEvents();
5674
5675 // The second pointer lands inside `secondWindow`, which should receive a DOWN event.
5676 // Now, `window` should get ACTION_OUTSIDE.
Prabir Pradhan678438e2023-04-13 19:32:51 +00005677 mDispatcher->notifyMotion(generateMotionArgs(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN,
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07005678 ui::LogicalDisplayId::DEFAULT,
Prabir Pradhan678438e2023-04-13 19:32:51 +00005679 {PointF{-10, -10}, PointF{105, 105}}));
Siarhei Vishniakou487c49b2022-12-02 15:48:57 -08005680 const std::map<int32_t, PointF> expectedPointers{{0, PointF{-10, -10}}, {1, PointF{105, 105}}};
5681 window->consumeMotionEvent(
5682 AllOf(WithMotionAction(ACTION_OUTSIDE), WithPointers(expectedPointers)));
Prabir Pradhanb60b1dc2022-03-15 14:02:35 +00005683 secondWindow->consumeMotionDown();
5684 thirdWindow->assertNoEvents();
5685
5686 // The third pointer lands inside `thirdWindow`, which should receive a DOWN event. There is
5687 // no ACTION_OUTSIDE sent to `window` because one has already been sent for this gesture.
Prabir Pradhan678438e2023-04-13 19:32:51 +00005688 mDispatcher->notifyMotion(
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07005689 generateMotionArgs(POINTER_2_DOWN, AINPUT_SOURCE_TOUCHSCREEN,
5690 ui::LogicalDisplayId::DEFAULT,
Prabir Pradhan678438e2023-04-13 19:32:51 +00005691 {PointF{-10, -10}, PointF{105, 105}, PointF{205, 205}}));
Prabir Pradhanb60b1dc2022-03-15 14:02:35 +00005692 window->assertNoEvents();
5693 secondWindow->consumeMotionMove();
5694 thirdWindow->consumeMotionDown();
5695}
5696
Prabir Pradhan814fe082022-07-22 20:22:18 +00005697TEST_F(InputDispatcherTest, OnWindowInfosChanged_RemoveAllWindowsOnDisplay) {
5698 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07005699 sp<FakeWindowHandle> window =
5700 sp<FakeWindowHandle>::make(application, mDispatcher, "Fake Window",
5701 ui::LogicalDisplayId::DEFAULT);
Prabir Pradhan814fe082022-07-22 20:22:18 +00005702 window->setFocusable(true);
5703
Patrick Williamsd828f302023-04-28 17:52:08 -05005704 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Prabir Pradhan814fe082022-07-22 20:22:18 +00005705 setFocusedWindow(window);
5706
5707 window->consumeFocusEvent(true);
5708
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07005709 const NotifyKeyArgs keyDown =
5710 generateKeyArgs(AKEY_EVENT_ACTION_DOWN, ui::LogicalDisplayId::DEFAULT);
5711 const NotifyKeyArgs keyUp =
5712 generateKeyArgs(AKEY_EVENT_ACTION_UP, ui::LogicalDisplayId::DEFAULT);
Prabir Pradhan678438e2023-04-13 19:32:51 +00005713 mDispatcher->notifyKey(keyDown);
5714 mDispatcher->notifyKey(keyUp);
Prabir Pradhan814fe082022-07-22 20:22:18 +00005715
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07005716 window->consumeKeyDown(ui::LogicalDisplayId::DEFAULT);
5717 window->consumeKeyUp(ui::LogicalDisplayId::DEFAULT);
Prabir Pradhan814fe082022-07-22 20:22:18 +00005718
5719 // All windows are removed from the display. Ensure that we can no longer dispatch to it.
Patrick Williamsd828f302023-04-28 17:52:08 -05005720 mDispatcher->onWindowInfosChanged({{}, {}, 0, 0});
Prabir Pradhan814fe082022-07-22 20:22:18 +00005721
5722 window->consumeFocusEvent(false);
5723
Prabir Pradhan678438e2023-04-13 19:32:51 +00005724 mDispatcher->notifyKey(keyDown);
5725 mDispatcher->notifyKey(keyUp);
Prabir Pradhan814fe082022-07-22 20:22:18 +00005726 window->assertNoEvents();
5727}
5728
Arthur Hung96483742022-11-15 03:30:48 +00005729TEST_F(InputDispatcherTest, NonSplitTouchableWindowReceivesMultiTouch) {
Siarhei Vishniakoua3fe6642024-07-18 11:58:25 -07005730 SCOPED_FLAG_OVERRIDE(split_all_touches, false);
Arthur Hung96483742022-11-15 03:30:48 +00005731 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07005732 sp<FakeWindowHandle> window =
5733 sp<FakeWindowHandle>::make(application, mDispatcher, "Fake Window",
5734 ui::LogicalDisplayId::DEFAULT);
Arthur Hung96483742022-11-15 03:30:48 +00005735 // Ensure window is non-split and have some transform.
5736 window->setPreventSplitting(true);
5737 window->setWindowOffset(20, 40);
Patrick Williamsd828f302023-04-28 17:52:08 -05005738 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Arthur Hung96483742022-11-15 03:30:48 +00005739
5740 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07005741 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN,
5742 ui::LogicalDisplayId::DEFAULT, {50, 50}))
Arthur Hung96483742022-11-15 03:30:48 +00005743 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07005744 window->consumeMotionDown(ui::LogicalDisplayId::DEFAULT);
Arthur Hung96483742022-11-15 03:30:48 +00005745
5746 const MotionEvent secondFingerDownEvent =
5747 MotionEventBuilder(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07005748 .displayId(ui::LogicalDisplayId::DEFAULT)
Arthur Hung96483742022-11-15 03:30:48 +00005749 .eventTime(systemTime(SYSTEM_TIME_MONOTONIC))
Siarhei Vishniakou6d73f832022-07-21 17:27:03 -07005750 .pointer(PointerBuilder(/*id=*/0, ToolType::FINGER).x(50).y(50))
5751 .pointer(PointerBuilder(/*id=*/1, ToolType::FINGER).x(-30).y(-50))
Arthur Hung96483742022-11-15 03:30:48 +00005752 .build();
5753 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07005754 injectMotionEvent(*mDispatcher, secondFingerDownEvent, INJECT_EVENT_TIMEOUT,
Arthur Hung96483742022-11-15 03:30:48 +00005755 InputEventInjectionSync::WAIT_FOR_RESULT))
5756 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
5757
Siarhei Vishniakoud3061ab2023-12-18 20:41:08 -08005758 std::unique_ptr<MotionEvent> event = window->consumeMotionEvent();
5759 ASSERT_NE(nullptr, event);
5760 EXPECT_EQ(POINTER_1_DOWN, event->getAction());
5761 EXPECT_EQ(70, event->getX(0)); // 50 + 20
5762 EXPECT_EQ(90, event->getY(0)); // 50 + 40
5763 EXPECT_EQ(-10, event->getX(1)); // -30 + 20
5764 EXPECT_EQ(-10, event->getY(1)); // -50 + 40
Arthur Hung96483742022-11-15 03:30:48 +00005765}
5766
Siarhei Vishniakou25537f82023-07-18 14:35:47 -07005767/**
5768 * Two windows: a splittable and a non-splittable.
5769 * The non-splittable window shouldn't receive any "incomplete" gestures.
5770 * Send the first pointer to the splittable window, and then touch the non-splittable window.
5771 * The second pointer should be dropped because the initial window is splittable, so it won't get
5772 * any pointers outside of it, and the second window is non-splittable, so it shouldn't get any
5773 * "incomplete" gestures.
5774 */
5775TEST_F(InputDispatcherTest, SplittableAndNonSplittableWindows) {
Siarhei Vishniakoua3fe6642024-07-18 11:58:25 -07005776 SCOPED_FLAG_OVERRIDE(split_all_touches, false);
Siarhei Vishniakou25537f82023-07-18 14:35:47 -07005777 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
5778 sp<FakeWindowHandle> leftWindow =
5779 sp<FakeWindowHandle>::make(application, mDispatcher, "Left splittable Window",
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07005780 ui::LogicalDisplayId::DEFAULT);
Siarhei Vishniakou25537f82023-07-18 14:35:47 -07005781 leftWindow->setPreventSplitting(false);
5782 leftWindow->setFrame(Rect(0, 0, 100, 100));
5783 sp<FakeWindowHandle> rightWindow =
5784 sp<FakeWindowHandle>::make(application, mDispatcher, "Right non-splittable Window",
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07005785 ui::LogicalDisplayId::DEFAULT);
Siarhei Vishniakou25537f82023-07-18 14:35:47 -07005786 rightWindow->setPreventSplitting(true);
5787 rightWindow->setFrame(Rect(100, 100, 200, 200));
5788 mDispatcher->onWindowInfosChanged(
5789 {{*leftWindow->getInfo(), *rightWindow->getInfo()}, {}, 0, 0});
5790
5791 // Touch down on left, splittable window
5792 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
5793 .pointer(PointerBuilder(0, ToolType::FINGER).x(50).y(50))
5794 .build());
5795 leftWindow->consumeMotionEvent(WithMotionAction(ACTION_DOWN));
5796
5797 mDispatcher->notifyMotion(
5798 MotionArgsBuilder(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
5799 .pointer(PointerBuilder(/*id=*/0, ToolType::FINGER).x(50).y(50))
5800 .pointer(PointerBuilder(/*id=*/1, ToolType::FINGER).x(150).y(150))
5801 .build());
5802 leftWindow->assertNoEvents();
5803 rightWindow->assertNoEvents();
5804}
5805
Siarhei Vishniakou96204462024-07-13 23:59:47 -07005806/**
Siarhei Vishniakoufe346982024-08-07 00:17:19 +00005807 * Three windows:
5808 * 1) A window on the left, with flag dup_to_wallpaper
5809 * 2) A window on the right, with flag slippery
5810 * 3) A wallpaper window under the left window
5811 * When touch slips from right window to left, the wallpaper should receive a similar slippery
5812 * enter event. Later on, when another device becomes active, the wallpaper should receive
5813 * consistent streams from the new device, and also from the old device.
5814 * This test attempts to reproduce a crash in the dispatcher where the wallpaper target's downTime
5815 * was not getting set during slippery entrance.
5816 */
5817TEST_F(InputDispatcherTest, WallpaperWindowWhenSlipperyAndMultiWindowMultiTouch) {
5818 SCOPED_FLAG_OVERRIDE(enable_multi_device_same_window_stream, true);
5819 std::shared_ptr<FakeApplicationHandle> application1 = std::make_shared<FakeApplicationHandle>();
5820 std::shared_ptr<FakeApplicationHandle> application2 = std::make_shared<FakeApplicationHandle>();
5821 std::shared_ptr<FakeApplicationHandle> application3 = std::make_shared<FakeApplicationHandle>();
5822 sp<FakeWindowHandle> wallpaper =
5823 sp<FakeWindowHandle>::make(application1, mDispatcher, "wallpaper",
5824 ui::LogicalDisplayId::DEFAULT);
5825 wallpaper->setIsWallpaper(true);
5826 wallpaper->setPreventSplitting(true);
5827 wallpaper->setTouchable(false);
5828
5829 sp<FakeWindowHandle> leftWindow = sp<FakeWindowHandle>::make(application2, mDispatcher, "Left",
5830 ui::LogicalDisplayId::DEFAULT);
5831 leftWindow->setTouchableRegion(Region{{0, 0, 100, 100}});
5832 leftWindow->setDupTouchToWallpaper(true);
5833
5834 sp<FakeWindowHandle> rightWindow =
5835 sp<FakeWindowHandle>::make(application3, mDispatcher, "Right",
5836 ui::LogicalDisplayId::DEFAULT);
5837 rightWindow->setTouchableRegion(Region{{100, 0, 200, 100}});
5838 rightWindow->setSlippery(true);
5839 rightWindow->setWatchOutsideTouch(true);
5840 rightWindow->setTrustedOverlay(true);
5841
5842 mDispatcher->onWindowInfosChanged(
5843 {{*rightWindow->getInfo(), *leftWindow->getInfo(), *wallpaper->getInfo()}, {}, 0, 0});
5844
5845 const DeviceId deviceA = 3;
5846 const DeviceId deviceB = 9;
5847
5848 // First finger from device A into right window
5849 NotifyMotionArgs deviceADownArgs =
5850 MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
5851 .pointer(PointerBuilder(0, ToolType::FINGER).x(150).y(50))
5852 .deviceId(deviceA)
5853 .build();
5854
5855 mDispatcher->notifyMotion(deviceADownArgs);
5856 rightWindow->consumeMotionEvent(WithMotionAction(ACTION_DOWN));
5857
5858 // Move the finger of device A from right window into left window. It should slip.
5859 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN)
5860 .pointer(PointerBuilder(0, ToolType::FINGER).x(80).y(50))
5861 .deviceId(deviceA)
5862 .downTime(deviceADownArgs.downTime)
5863 .build());
5864
5865 leftWindow->consumeMotionEvent(WithMotionAction(ACTION_DOWN));
5866 rightWindow->consumeMotionEvent(WithMotionAction(ACTION_CANCEL));
5867 wallpaper->consumeMotionEvent(WithMotionAction(ACTION_DOWN));
5868
5869 // Finger from device B down into left window
5870 NotifyMotionArgs deviceBDownArgs =
5871 MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
5872 .pointer(PointerBuilder(0, ToolType::FINGER).x(40).y(40))
5873 .deviceId(deviceB)
5874 .build();
5875 mDispatcher->notifyMotion(deviceBDownArgs);
5876 leftWindow->consumeMotionEvent(AllOf(WithDeviceId(deviceB), WithMotionAction(ACTION_DOWN)));
5877 wallpaper->consumeMotionEvent(AllOf(WithDeviceId(deviceB), WithMotionAction(ACTION_DOWN)));
5878
5879 rightWindow->consumeMotionEvent(AllOf(WithDeviceId(deviceB), WithMotionAction(ACTION_OUTSIDE)));
5880
5881 // Move finger from device B, still keeping it in the left window
5882 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN)
5883 .pointer(PointerBuilder(0, ToolType::FINGER).x(40).y(50))
5884 .deviceId(deviceB)
5885 .downTime(deviceBDownArgs.downTime)
5886 .build());
5887 leftWindow->consumeMotionEvent(AllOf(WithDeviceId(deviceB), WithMotionAction(ACTION_MOVE)));
5888 wallpaper->consumeMotionEvent(AllOf(WithDeviceId(deviceB), WithMotionAction(ACTION_MOVE)));
5889
5890 // Lift the finger from device B
5891 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN)
5892 .pointer(PointerBuilder(0, ToolType::FINGER).x(40).y(50))
5893 .deviceId(deviceB)
5894 .downTime(deviceBDownArgs.downTime)
5895 .build());
5896 leftWindow->consumeMotionEvent(AllOf(WithDeviceId(deviceB), WithMotionAction(ACTION_UP)));
5897 wallpaper->consumeMotionEvent(AllOf(WithDeviceId(deviceB), WithMotionAction(ACTION_UP)));
5898
5899 // Move the finger of device A, keeping it in the left window
5900 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN)
5901 .pointer(PointerBuilder(0, ToolType::FINGER).x(70).y(50))
5902 .deviceId(deviceA)
5903 .downTime(deviceADownArgs.downTime)
5904 .build());
5905
5906 leftWindow->consumeMotionEvent(AllOf(WithDeviceId(deviceA), WithMotionAction(ACTION_MOVE)));
5907 wallpaper->consumeMotionEvent(AllOf(WithDeviceId(deviceA), WithMotionAction(ACTION_MOVE)));
5908
5909 // Second finger down from device A, into the right window. It should be split into:
5910 // MOVE for the left window (due to existing implementation) + a DOWN into the right window
5911 // Wallpaper will not receive this new pointer, and it will only get the MOVE event.
5912 mDispatcher->notifyMotion(MotionArgsBuilder(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
5913 .pointer(PointerBuilder(0, ToolType::FINGER).x(70).y(50))
5914 .pointer(PointerBuilder(1, ToolType::FINGER).x(140).y(50))
5915 .deviceId(deviceA)
5916 .downTime(deviceADownArgs.downTime)
5917 .build());
5918 auto firstFingerMoveFromDeviceA = AllOf(WithDeviceId(deviceA), WithMotionAction(ACTION_MOVE),
5919 WithPointerCount(1), WithPointerId(0, 0));
5920 leftWindow->consumeMotionEvent(firstFingerMoveFromDeviceA);
5921 wallpaper->consumeMotionEvent(firstFingerMoveFromDeviceA);
5922 rightWindow->consumeMotionEvent(
5923 AllOf(WithDeviceId(deviceA), WithMotionAction(ACTION_DOWN), WithPointerId(0, 1)));
5924
5925 // Lift up the second finger.
5926 mDispatcher->notifyMotion(MotionArgsBuilder(POINTER_1_UP, AINPUT_SOURCE_TOUCHSCREEN)
5927 .pointer(PointerBuilder(0, ToolType::FINGER).x(70).y(50))
5928 .pointer(PointerBuilder(1, ToolType::FINGER).x(140).y(50))
5929 .deviceId(deviceA)
5930 .downTime(deviceADownArgs.downTime)
5931 .build());
5932
5933 rightWindow->consumeMotionEvent(AllOf(WithDeviceId(deviceA), WithMotionAction(ACTION_UP)));
5934 leftWindow->consumeMotionEvent(firstFingerMoveFromDeviceA);
5935 wallpaper->consumeMotionEvent(firstFingerMoveFromDeviceA);
5936
5937 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN)
5938 .pointer(PointerBuilder(0, ToolType::FINGER).x(70).y(50))
5939 .deviceId(deviceA)
5940 .downTime(deviceADownArgs.downTime)
5941 .build());
5942
5943 leftWindow->consumeMotionEvent(AllOf(WithDeviceId(deviceA), WithMotionAction(ACTION_UP)));
5944 wallpaper->consumeMotionEvent(AllOf(WithDeviceId(deviceA), WithMotionAction(ACTION_UP)));
5945 rightWindow->assertNoEvents();
5946}
5947
5948/**
5949 * Same test as above, but with enable_multi_device_same_window_stream flag set to false.
5950 */
5951TEST_F(InputDispatcherTest, WallpaperWindowWhenSlipperyAndMultiWindowMultiTouch_legacy) {
5952 SCOPED_FLAG_OVERRIDE(enable_multi_device_same_window_stream, false);
5953 std::shared_ptr<FakeApplicationHandle> application1 = std::make_shared<FakeApplicationHandle>();
5954 std::shared_ptr<FakeApplicationHandle> application2 = std::make_shared<FakeApplicationHandle>();
5955 std::shared_ptr<FakeApplicationHandle> application3 = std::make_shared<FakeApplicationHandle>();
5956 sp<FakeWindowHandle> wallpaper =
5957 sp<FakeWindowHandle>::make(application1, mDispatcher, "wallpaper",
5958 ui::LogicalDisplayId::DEFAULT);
5959 wallpaper->setIsWallpaper(true);
5960 wallpaper->setPreventSplitting(true);
5961 wallpaper->setTouchable(false);
5962
5963 sp<FakeWindowHandle> leftWindow = sp<FakeWindowHandle>::make(application2, mDispatcher, "Left",
5964 ui::LogicalDisplayId::DEFAULT);
5965 leftWindow->setTouchableRegion(Region{{0, 0, 100, 100}});
5966 leftWindow->setDupTouchToWallpaper(true);
5967
5968 sp<FakeWindowHandle> rightWindow =
5969 sp<FakeWindowHandle>::make(application3, mDispatcher, "Right",
5970 ui::LogicalDisplayId::DEFAULT);
5971 rightWindow->setTouchableRegion(Region{{100, 0, 200, 100}});
5972 rightWindow->setSlippery(true);
5973 rightWindow->setWatchOutsideTouch(true);
5974 rightWindow->setTrustedOverlay(true);
5975
5976 mDispatcher->onWindowInfosChanged(
5977 {{*rightWindow->getInfo(), *leftWindow->getInfo(), *wallpaper->getInfo()}, {}, 0, 0});
5978
5979 const DeviceId deviceA = 3;
5980 const DeviceId deviceB = 9;
5981
5982 // First finger from device A into right window
5983 NotifyMotionArgs deviceADownArgs =
5984 MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
5985 .pointer(PointerBuilder(0, ToolType::FINGER).x(150).y(50))
5986 .deviceId(deviceA)
5987 .build();
5988
5989 mDispatcher->notifyMotion(deviceADownArgs);
5990 rightWindow->consumeMotionEvent(WithMotionAction(ACTION_DOWN));
5991
5992 // Move the finger of device A from right window into left window. It should slip.
5993 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN)
5994 .pointer(PointerBuilder(0, ToolType::FINGER).x(80).y(50))
5995 .deviceId(deviceA)
5996 .downTime(deviceADownArgs.downTime)
5997 .build());
5998
5999 leftWindow->consumeMotionEvent(WithMotionAction(ACTION_DOWN));
6000 rightWindow->consumeMotionEvent(WithMotionAction(ACTION_CANCEL));
6001 wallpaper->consumeMotionEvent(WithMotionAction(ACTION_DOWN));
6002
6003 // Finger from device B down into left window
6004 NotifyMotionArgs deviceBDownArgs =
6005 MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
6006 .pointer(PointerBuilder(0, ToolType::FINGER).x(40).y(40))
6007 .deviceId(deviceB)
6008 .build();
6009 mDispatcher->notifyMotion(deviceBDownArgs);
6010 leftWindow->consumeMotionEvent(AllOf(WithDeviceId(deviceA), WithMotionAction(ACTION_CANCEL)));
6011 leftWindow->consumeMotionEvent(AllOf(WithDeviceId(deviceB), WithMotionAction(ACTION_DOWN)));
6012 wallpaper->consumeMotionEvent(AllOf(WithDeviceId(deviceA), WithMotionAction(ACTION_CANCEL)));
6013 wallpaper->consumeMotionEvent(AllOf(WithDeviceId(deviceB), WithMotionAction(ACTION_DOWN)));
6014
6015 rightWindow->consumeMotionEvent(AllOf(WithDeviceId(deviceB), WithMotionAction(ACTION_OUTSIDE)));
6016
6017 // Move finger from device B, still keeping it in the left window
6018 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN)
6019 .pointer(PointerBuilder(0, ToolType::FINGER).x(40).y(50))
6020 .deviceId(deviceB)
6021 .downTime(deviceBDownArgs.downTime)
6022 .build());
6023 leftWindow->consumeMotionEvent(AllOf(WithDeviceId(deviceB), WithMotionAction(ACTION_MOVE)));
6024 wallpaper->consumeMotionEvent(AllOf(WithDeviceId(deviceB), WithMotionAction(ACTION_MOVE)));
6025
6026 // Lift the finger from device B
6027 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN)
6028 .pointer(PointerBuilder(0, ToolType::FINGER).x(40).y(50))
6029 .deviceId(deviceB)
6030 .downTime(deviceBDownArgs.downTime)
6031 .build());
6032 leftWindow->consumeMotionEvent(AllOf(WithDeviceId(deviceB), WithMotionAction(ACTION_UP)));
6033 wallpaper->consumeMotionEvent(AllOf(WithDeviceId(deviceB), WithMotionAction(ACTION_UP)));
6034
6035 // Move the finger of device A, keeping it in the left window
6036 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN)
6037 .pointer(PointerBuilder(0, ToolType::FINGER).x(70).y(50))
6038 .deviceId(deviceA)
6039 .downTime(deviceADownArgs.downTime)
6040 .build());
6041 // This device was already canceled, so MOVE events will not be arriving to the windows from it.
6042
6043 // Second finger down from device A, into the right window. It should be split into:
6044 // MOVE for the left window (due to existing implementation) + a DOWN into the right window
6045 // Wallpaper will not receive this new pointer, and it will only get the MOVE event.
6046 mDispatcher->notifyMotion(MotionArgsBuilder(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
6047 .pointer(PointerBuilder(0, ToolType::FINGER).x(70).y(50))
6048 .pointer(PointerBuilder(1, ToolType::FINGER).x(140).y(50))
6049 .deviceId(deviceA)
6050 .downTime(deviceADownArgs.downTime)
6051 .build());
6052 rightWindow->consumeMotionEvent(
6053 AllOf(WithDeviceId(deviceA), WithMotionAction(ACTION_DOWN), WithPointerId(0, 1)));
6054
6055 // Lift up the second finger.
6056 mDispatcher->notifyMotion(MotionArgsBuilder(POINTER_1_UP, AINPUT_SOURCE_TOUCHSCREEN)
6057 .pointer(PointerBuilder(0, ToolType::FINGER).x(70).y(50))
6058 .pointer(PointerBuilder(1, ToolType::FINGER).x(140).y(50))
6059 .deviceId(deviceA)
6060 .downTime(deviceADownArgs.downTime)
6061 .build());
6062
6063 rightWindow->consumeMotionEvent(AllOf(WithDeviceId(deviceA), WithMotionAction(ACTION_UP)));
6064
6065 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN)
6066 .pointer(PointerBuilder(0, ToolType::FINGER).x(70).y(50))
6067 .deviceId(deviceA)
6068 .downTime(deviceADownArgs.downTime)
6069 .build());
6070 rightWindow->assertNoEvents();
6071}
6072
6073/**
Siarhei Vishniakou96204462024-07-13 23:59:47 -07006074 * Two windows: left and right. The left window has PREVENT_SPLITTING input config. Device A sends a
6075 * down event to the right window. Device B sends a down event to the left window, and then a
6076 * POINTER_DOWN event to the right window. However, since the left window prevents splitting, the
6077 * POINTER_DOWN event should only go to the left window, and not to the right window.
6078 * This test attempts to reproduce a crash.
6079 */
6080TEST_F(InputDispatcherTest, MultiDeviceTwoWindowsPreventSplitting) {
Siarhei Vishniakoua3fe6642024-07-18 11:58:25 -07006081 SCOPED_FLAG_OVERRIDE(split_all_touches, false);
Siarhei Vishniakou96204462024-07-13 23:59:47 -07006082 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
6083 sp<FakeWindowHandle> leftWindow =
6084 sp<FakeWindowHandle>::make(application, mDispatcher, "Left window (prevent splitting)",
6085 ui::LogicalDisplayId::DEFAULT);
6086 leftWindow->setFrame(Rect(0, 0, 100, 100));
6087 leftWindow->setPreventSplitting(true);
6088
6089 sp<FakeWindowHandle> rightWindow =
6090 sp<FakeWindowHandle>::make(application, mDispatcher, "Right window",
6091 ui::LogicalDisplayId::DEFAULT);
6092 rightWindow->setFrame(Rect(100, 0, 200, 100));
6093
6094 mDispatcher->onWindowInfosChanged(
6095 {{*leftWindow->getInfo(), *rightWindow->getInfo()}, {}, 0, 0});
6096
6097 const DeviceId deviceA = 9;
6098 const DeviceId deviceB = 3;
6099 // Touch the right window with device A
6100 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
6101 .pointer(PointerBuilder(0, ToolType::FINGER).x(150).y(50))
6102 .deviceId(deviceA)
6103 .build());
6104 rightWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(deviceA)));
6105 // Touch the left window with device B
6106 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
6107 .pointer(PointerBuilder(0, ToolType::FINGER).x(50).y(50))
6108 .deviceId(deviceB)
6109 .build());
6110 leftWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(deviceB)));
6111 // Send a second pointer from device B to the right window. It shouldn't go to the right window
6112 // because the left window prevents splitting.
6113 mDispatcher->notifyMotion(MotionArgsBuilder(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
6114 .deviceId(deviceB)
6115 .pointer(PointerBuilder(0, ToolType::FINGER).x(50).y(50))
6116 .pointer(PointerBuilder(1, ToolType::FINGER).x(120).y(120))
6117 .build());
6118 leftWindow->consumeMotionPointerDown(1, WithDeviceId(deviceB));
6119
6120 // Finish the gesture for both devices
6121 mDispatcher->notifyMotion(MotionArgsBuilder(POINTER_1_UP, AINPUT_SOURCE_TOUCHSCREEN)
6122 .deviceId(deviceB)
6123 .pointer(PointerBuilder(0, ToolType::FINGER).x(50).y(50))
6124 .pointer(PointerBuilder(1, ToolType::FINGER).x(120).y(120))
6125 .build());
6126 leftWindow->consumeMotionPointerUp(1, WithDeviceId(deviceB));
6127 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN)
6128 .pointer(PointerBuilder(0, ToolType::FINGER).x(50).y(50))
6129 .deviceId(deviceB)
6130 .build());
6131 leftWindow->consumeMotionEvent(
6132 AllOf(WithMotionAction(ACTION_UP), WithDeviceId(deviceB), WithPointerId(0, 0)));
6133 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN)
6134 .pointer(PointerBuilder(0, ToolType::FINGER).x(150).y(50))
6135 .deviceId(deviceA)
6136 .build());
6137 rightWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_UP), WithDeviceId(deviceA)));
6138}
6139
Harry Cuttsb166c002023-05-09 13:06:05 +00006140TEST_F(InputDispatcherTest, TouchpadThreeFingerSwipeOnlySentToTrustedOverlays) {
6141 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07006142 sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher, "Window",
6143 ui::LogicalDisplayId::DEFAULT);
Harry Cuttsb166c002023-05-09 13:06:05 +00006144 window->setFrame(Rect(0, 0, 400, 400));
6145 sp<FakeWindowHandle> trustedOverlay =
6146 sp<FakeWindowHandle>::make(application, mDispatcher, "Trusted Overlay",
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07006147 ui::LogicalDisplayId::DEFAULT);
Harry Cuttsb166c002023-05-09 13:06:05 +00006148 trustedOverlay->setSpy(true);
6149 trustedOverlay->setTrustedOverlay(true);
6150
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07006151 mDispatcher->onWindowInfosChanged({{*trustedOverlay->getInfo(), *window->getInfo()}, {}, 0, 0});
Harry Cuttsb166c002023-05-09 13:06:05 +00006152
6153 // Start a three-finger touchpad swipe
6154 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_MOUSE)
6155 .pointer(PointerBuilder(0, ToolType::FINGER).x(200).y(100))
6156 .classification(MotionClassification::MULTI_FINGER_SWIPE)
6157 .build());
6158 mDispatcher->notifyMotion(MotionArgsBuilder(POINTER_1_DOWN, AINPUT_SOURCE_MOUSE)
6159 .pointer(PointerBuilder(0, ToolType::FINGER).x(200).y(100))
6160 .pointer(PointerBuilder(1, ToolType::FINGER).x(250).y(100))
6161 .classification(MotionClassification::MULTI_FINGER_SWIPE)
6162 .build());
6163 mDispatcher->notifyMotion(MotionArgsBuilder(POINTER_2_DOWN, AINPUT_SOURCE_MOUSE)
6164 .pointer(PointerBuilder(0, ToolType::FINGER).x(200).y(100))
6165 .pointer(PointerBuilder(1, ToolType::FINGER).x(250).y(100))
6166 .pointer(PointerBuilder(2, ToolType::FINGER).x(300).y(100))
6167 .classification(MotionClassification::MULTI_FINGER_SWIPE)
6168 .build());
6169
6170 trustedOverlay->consumeMotionEvent(WithMotionAction(ACTION_DOWN));
6171 trustedOverlay->consumeMotionEvent(WithMotionAction(POINTER_1_DOWN));
6172 trustedOverlay->consumeMotionEvent(WithMotionAction(POINTER_2_DOWN));
6173
6174 // Move the swipe a bit
6175 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_MOUSE)
6176 .pointer(PointerBuilder(0, ToolType::FINGER).x(200).y(105))
6177 .pointer(PointerBuilder(1, ToolType::FINGER).x(250).y(105))
6178 .pointer(PointerBuilder(2, ToolType::FINGER).x(300).y(105))
6179 .classification(MotionClassification::MULTI_FINGER_SWIPE)
6180 .build());
6181
6182 trustedOverlay->consumeMotionEvent(WithMotionAction(ACTION_MOVE));
6183
6184 // End the swipe
6185 mDispatcher->notifyMotion(MotionArgsBuilder(POINTER_2_UP, AINPUT_SOURCE_MOUSE)
6186 .pointer(PointerBuilder(0, ToolType::FINGER).x(200).y(105))
6187 .pointer(PointerBuilder(1, ToolType::FINGER).x(250).y(105))
6188 .pointer(PointerBuilder(2, ToolType::FINGER).x(300).y(105))
6189 .classification(MotionClassification::MULTI_FINGER_SWIPE)
6190 .build());
6191 mDispatcher->notifyMotion(MotionArgsBuilder(POINTER_1_UP, AINPUT_SOURCE_MOUSE)
6192 .pointer(PointerBuilder(0, ToolType::FINGER).x(200).y(105))
6193 .pointer(PointerBuilder(1, ToolType::FINGER).x(250).y(105))
6194 .classification(MotionClassification::MULTI_FINGER_SWIPE)
6195 .build());
6196 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_UP, AINPUT_SOURCE_MOUSE)
6197 .pointer(PointerBuilder(0, ToolType::FINGER).x(200).y(105))
6198 .classification(MotionClassification::MULTI_FINGER_SWIPE)
6199 .build());
6200
6201 trustedOverlay->consumeMotionEvent(WithMotionAction(POINTER_2_UP));
6202 trustedOverlay->consumeMotionEvent(WithMotionAction(POINTER_1_UP));
6203 trustedOverlay->consumeMotionEvent(WithMotionAction(ACTION_UP));
6204
6205 window->assertNoEvents();
6206}
6207
6208TEST_F(InputDispatcherTest, TouchpadThreeFingerSwipeNotSentToSingleWindow) {
6209 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07006210 sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher, "Window",
6211 ui::LogicalDisplayId::DEFAULT);
Harry Cuttsb166c002023-05-09 13:06:05 +00006212 window->setFrame(Rect(0, 0, 400, 400));
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07006213 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Harry Cuttsb166c002023-05-09 13:06:05 +00006214
6215 // Start a three-finger touchpad swipe
6216 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_MOUSE)
6217 .pointer(PointerBuilder(0, ToolType::FINGER).x(200).y(100))
6218 .classification(MotionClassification::MULTI_FINGER_SWIPE)
6219 .build());
6220 mDispatcher->notifyMotion(MotionArgsBuilder(POINTER_1_DOWN, AINPUT_SOURCE_MOUSE)
6221 .pointer(PointerBuilder(0, ToolType::FINGER).x(200).y(100))
6222 .pointer(PointerBuilder(1, ToolType::FINGER).x(250).y(100))
6223 .classification(MotionClassification::MULTI_FINGER_SWIPE)
6224 .build());
6225 mDispatcher->notifyMotion(MotionArgsBuilder(POINTER_2_DOWN, AINPUT_SOURCE_MOUSE)
6226 .pointer(PointerBuilder(0, ToolType::FINGER).x(200).y(100))
6227 .pointer(PointerBuilder(1, ToolType::FINGER).x(250).y(100))
6228 .pointer(PointerBuilder(2, ToolType::FINGER).x(300).y(100))
6229 .classification(MotionClassification::MULTI_FINGER_SWIPE)
6230 .build());
6231
6232 // Move the swipe a bit
6233 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_MOUSE)
6234 .pointer(PointerBuilder(0, ToolType::FINGER).x(200).y(105))
6235 .pointer(PointerBuilder(1, ToolType::FINGER).x(250).y(105))
6236 .pointer(PointerBuilder(2, ToolType::FINGER).x(300).y(105))
6237 .classification(MotionClassification::MULTI_FINGER_SWIPE)
6238 .build());
6239
6240 // End the swipe
6241 mDispatcher->notifyMotion(MotionArgsBuilder(POINTER_2_UP, AINPUT_SOURCE_MOUSE)
6242 .pointer(PointerBuilder(0, ToolType::FINGER).x(200).y(105))
6243 .pointer(PointerBuilder(1, ToolType::FINGER).x(250).y(105))
6244 .pointer(PointerBuilder(2, ToolType::FINGER).x(300).y(105))
6245 .classification(MotionClassification::MULTI_FINGER_SWIPE)
6246 .build());
6247 mDispatcher->notifyMotion(MotionArgsBuilder(POINTER_1_UP, AINPUT_SOURCE_MOUSE)
6248 .pointer(PointerBuilder(0, ToolType::FINGER).x(200).y(105))
6249 .pointer(PointerBuilder(1, ToolType::FINGER).x(250).y(105))
6250 .classification(MotionClassification::MULTI_FINGER_SWIPE)
6251 .build());
6252 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_UP, AINPUT_SOURCE_MOUSE)
6253 .pointer(PointerBuilder(0, ToolType::FINGER).x(200).y(105))
6254 .classification(MotionClassification::MULTI_FINGER_SWIPE)
6255 .build());
6256
6257 window->assertNoEvents();
6258}
6259
Prabir Pradhanb60b1dc2022-03-15 14:02:35 +00006260/**
Siarhei Vishniakouadb9fc92023-05-26 10:46:09 -07006261 * Send a two-pointer gesture to a single window. The window's orientation changes in response to
6262 * the first pointer.
Prabir Pradhan69d00bf2023-06-23 19:55:18 +00006263 * Ensure that the second pointer and the subsequent gesture is correctly delivered to the window.
Siarhei Vishniakouadb9fc92023-05-26 10:46:09 -07006264 */
6265TEST_F(InputDispatcherTest, MultiplePointersWithRotatingWindow) {
6266 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07006267 sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher, "Window",
6268 ui::LogicalDisplayId::DEFAULT);
Siarhei Vishniakouadb9fc92023-05-26 10:46:09 -07006269 window->setFrame(Rect(0, 0, 400, 400));
Siarhei Vishniakou700424c2023-07-18 17:18:42 -07006270 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Siarhei Vishniakouadb9fc92023-05-26 10:46:09 -07006271
6272 const nsecs_t baseTime = systemTime(SYSTEM_TIME_MONOTONIC);
6273 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
6274 .downTime(baseTime + 10)
6275 .eventTime(baseTime + 10)
6276 .pointer(PointerBuilder(0, ToolType::FINGER).x(100).y(100))
6277 .build());
6278
6279 window->consumeMotionEvent(WithMotionAction(ACTION_DOWN));
6280
Siarhei Vishniakouadb9fc92023-05-26 10:46:09 -07006281 // Change the transform so that the orientation is now different from original.
Siarhei Vishniakou700424c2023-07-18 17:18:42 -07006282 window->setWindowTransform(0, -1, 1, 0);
Siarhei Vishniakouadb9fc92023-05-26 10:46:09 -07006283
Siarhei Vishniakou700424c2023-07-18 17:18:42 -07006284 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Siarhei Vishniakouadb9fc92023-05-26 10:46:09 -07006285
Siarhei Vishniakouadb9fc92023-05-26 10:46:09 -07006286 mDispatcher->notifyMotion(MotionArgsBuilder(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
6287 .downTime(baseTime + 10)
6288 .eventTime(baseTime + 30)
6289 .pointer(PointerBuilder(0, ToolType::FINGER).x(100).y(100))
6290 .pointer(PointerBuilder(1, ToolType::FINGER).x(200).y(200))
6291 .build());
6292
Prabir Pradhan69d00bf2023-06-23 19:55:18 +00006293 window->consumeMotionEvent(WithMotionAction(POINTER_1_DOWN));
6294
6295 // Finish the gesture and start a new one. Ensure all events are sent to the window.
Siarhei Vishniakouadb9fc92023-05-26 10:46:09 -07006296 mDispatcher->notifyMotion(MotionArgsBuilder(POINTER_1_UP, AINPUT_SOURCE_TOUCHSCREEN)
6297 .downTime(baseTime + 10)
6298 .eventTime(baseTime + 40)
6299 .pointer(PointerBuilder(0, ToolType::FINGER).x(100).y(100))
6300 .pointer(PointerBuilder(1, ToolType::FINGER).x(200).y(200))
6301 .build());
Prabir Pradhan69d00bf2023-06-23 19:55:18 +00006302
6303 window->consumeMotionEvent(WithMotionAction(POINTER_1_UP));
6304
Siarhei Vishniakouadb9fc92023-05-26 10:46:09 -07006305 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN)
6306 .downTime(baseTime + 10)
6307 .eventTime(baseTime + 50)
6308 .pointer(PointerBuilder(0, ToolType::FINGER).x(100).y(100))
6309 .build());
6310
Prabir Pradhan69d00bf2023-06-23 19:55:18 +00006311 window->consumeMotionEvent(WithMotionAction(ACTION_UP));
6312
Siarhei Vishniakouadb9fc92023-05-26 10:46:09 -07006313 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
6314 .downTime(baseTime + 60)
6315 .eventTime(baseTime + 60)
6316 .pointer(PointerBuilder(0, ToolType::FINGER).x(40).y(40))
6317 .build());
6318
Siarhei Vishniakou700424c2023-07-18 17:18:42 -07006319 window->consumeMotionEvent(WithMotionAction(ACTION_DOWN));
Siarhei Vishniakouadb9fc92023-05-26 10:46:09 -07006320}
6321
6322/**
Hu Guo771a7692023-09-17 20:51:08 +08006323 * When there are multiple screens, such as screen projection to TV or screen recording, if the
6324 * cancel event occurs, the coordinates of the cancel event should be sent to the target screen, and
6325 * its coordinates should be converted by the transform of the windows of target screen.
6326 */
6327TEST_F(InputDispatcherTest, WhenMultiDisplayWindowSameToken_DispatchCancelToTargetDisplay) {
6328 // This case will create a window and a spy window on the default display and mirror
6329 // window on the second display. cancel event is sent through spy window pilferPointers
6330 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
6331
6332 sp<FakeWindowHandle> spyWindowDefaultDisplay =
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07006333 sp<FakeWindowHandle>::make(application, mDispatcher, "Spy",
6334 ui::LogicalDisplayId::DEFAULT);
Hu Guo771a7692023-09-17 20:51:08 +08006335 spyWindowDefaultDisplay->setTrustedOverlay(true);
6336 spyWindowDefaultDisplay->setSpy(true);
6337
6338 sp<FakeWindowHandle> windowDefaultDisplay =
6339 sp<FakeWindowHandle>::make(application, mDispatcher, "DefaultDisplay",
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07006340 ui::LogicalDisplayId::DEFAULT);
Hu Guo771a7692023-09-17 20:51:08 +08006341 windowDefaultDisplay->setWindowTransform(1, 0, 0, 1);
6342
6343 sp<FakeWindowHandle> windowSecondDisplay = windowDefaultDisplay->clone(SECOND_DISPLAY_ID);
6344 windowSecondDisplay->setWindowTransform(2, 0, 0, 2);
6345
6346 // Add the windows to the dispatcher
6347 mDispatcher->onWindowInfosChanged(
6348 {{*spyWindowDefaultDisplay->getInfo(), *windowDefaultDisplay->getInfo(),
6349 *windowSecondDisplay->getInfo()},
6350 {},
6351 0,
6352 0});
6353
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07006354 // Send down to ui::LogicalDisplayId::DEFAULT
Hu Guo771a7692023-09-17 20:51:08 +08006355 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07006356 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN,
6357 ui::LogicalDisplayId::DEFAULT, {100, 100}))
Hu Guo771a7692023-09-17 20:51:08 +08006358 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
6359
6360 spyWindowDefaultDisplay->consumeMotionDown();
6361 windowDefaultDisplay->consumeMotionDown();
6362
6363 EXPECT_EQ(OK, mDispatcher->pilferPointers(spyWindowDefaultDisplay->getToken()));
6364
6365 // windowDefaultDisplay gets cancel
Siarhei Vishniakoud3061ab2023-12-18 20:41:08 -08006366 std::unique_ptr<MotionEvent> event = windowDefaultDisplay->consumeMotionEvent();
6367 ASSERT_NE(nullptr, event);
6368 EXPECT_EQ(AMOTION_EVENT_ACTION_CANCEL, event->getAction());
Hu Guo771a7692023-09-17 20:51:08 +08006369
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07006370 // The cancel event is sent to windowDefaultDisplay of the ui::LogicalDisplayId::DEFAULT
6371 // display, so the coordinates of the cancel are converted by windowDefaultDisplay's transform,
6372 // the x and y coordinates are both 100, otherwise if the cancel event is sent to
6373 // windowSecondDisplay of SECOND_DISPLAY_ID, the x and y coordinates are 200
Siarhei Vishniakoud3061ab2023-12-18 20:41:08 -08006374 EXPECT_EQ(100, event->getX(0));
6375 EXPECT_EQ(100, event->getY(0));
Hu Guo771a7692023-09-17 20:51:08 +08006376}
6377
6378/**
Prabir Pradhanc44ce4d2021-10-05 05:26:29 -07006379 * Ensure the correct coordinate spaces are used by InputDispatcher.
6380 *
6381 * InputDispatcher works in the display space, so its coordinate system is relative to the display
6382 * panel. Windows get events in the window space, and get raw coordinates in the logical display
6383 * space.
6384 */
6385class InputDispatcherDisplayProjectionTest : public InputDispatcherTest {
6386public:
6387 void SetUp() override {
6388 InputDispatcherTest::SetUp();
Prabir Pradhan33e3baa2022-12-06 20:30:22 +00006389 removeAllWindowsAndDisplays();
Prabir Pradhanc44ce4d2021-10-05 05:26:29 -07006390 }
6391
Linnan Li13bf76a2024-05-05 19:18:02 +08006392 void addDisplayInfo(ui::LogicalDisplayId displayId, const ui::Transform& transform) {
Prabir Pradhanc44ce4d2021-10-05 05:26:29 -07006393 gui::DisplayInfo info;
6394 info.displayId = displayId;
6395 info.transform = transform;
6396 mDisplayInfos.push_back(std::move(info));
Patrick Williamsd828f302023-04-28 17:52:08 -05006397 mDispatcher->onWindowInfosChanged({mWindowInfos, mDisplayInfos, 0, 0});
Prabir Pradhanc44ce4d2021-10-05 05:26:29 -07006398 }
6399
6400 void addWindow(const sp<WindowInfoHandle>& windowHandle) {
6401 mWindowInfos.push_back(*windowHandle->getInfo());
Patrick Williamsd828f302023-04-28 17:52:08 -05006402 mDispatcher->onWindowInfosChanged({mWindowInfos, mDisplayInfos, 0, 0});
Prabir Pradhanc44ce4d2021-10-05 05:26:29 -07006403 }
6404
Prabir Pradhan33e3baa2022-12-06 20:30:22 +00006405 void removeAllWindowsAndDisplays() {
6406 mDisplayInfos.clear();
6407 mWindowInfos.clear();
6408 }
6409
Prabir Pradhanc44ce4d2021-10-05 05:26:29 -07006410 // Set up a test scenario where the display has a scaled projection and there are two windows
6411 // on the display.
6412 std::pair<sp<FakeWindowHandle>, sp<FakeWindowHandle>> setupScaledDisplayScenario() {
6413 // The display has a projection that has a scale factor of 2 and 4 in the x and y directions
6414 // respectively.
6415 ui::Transform displayTransform;
6416 displayTransform.set(2, 0, 0, 4);
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07006417 addDisplayInfo(ui::LogicalDisplayId::DEFAULT, displayTransform);
Prabir Pradhanc44ce4d2021-10-05 05:26:29 -07006418
6419 std::shared_ptr<FakeApplicationHandle> application =
6420 std::make_shared<FakeApplicationHandle>();
6421
6422 // Add two windows to the display. Their frames are represented in the display space.
6423 sp<FakeWindowHandle> firstWindow =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07006424 sp<FakeWindowHandle>::make(application, mDispatcher, "First Window",
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07006425 ui::LogicalDisplayId::DEFAULT);
Prabir Pradhanc44ce4d2021-10-05 05:26:29 -07006426 firstWindow->setFrame(Rect(0, 0, 100, 200), displayTransform);
6427 addWindow(firstWindow);
6428
6429 sp<FakeWindowHandle> secondWindow =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07006430 sp<FakeWindowHandle>::make(application, mDispatcher, "Second Window",
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07006431 ui::LogicalDisplayId::DEFAULT);
Prabir Pradhanc44ce4d2021-10-05 05:26:29 -07006432 secondWindow->setFrame(Rect(100, 200, 200, 400), displayTransform);
6433 addWindow(secondWindow);
6434 return {std::move(firstWindow), std::move(secondWindow)};
6435 }
6436
6437private:
6438 std::vector<gui::DisplayInfo> mDisplayInfos;
6439 std::vector<gui::WindowInfo> mWindowInfos;
6440};
6441
Prabir Pradhan33e3baa2022-12-06 20:30:22 +00006442TEST_F(InputDispatcherDisplayProjectionTest, HitTestCoordinateSpaceConsistency) {
Prabir Pradhanc44ce4d2021-10-05 05:26:29 -07006443 auto [firstWindow, secondWindow] = setupScaledDisplayScenario();
6444 // Send down to the first window. The point is represented in the display space. The point is
Prabir Pradhan33e3baa2022-12-06 20:30:22 +00006445 // selected so that if the hit test was performed with the point and the bounds being in
6446 // different coordinate spaces, the event would end up in the incorrect window.
Prabir Pradhan678438e2023-04-13 19:32:51 +00006447 mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_DOWN,
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07006448 AINPUT_SOURCE_TOUCHSCREEN,
6449 ui::LogicalDisplayId::DEFAULT, {PointF{75, 55}}));
Prabir Pradhanc44ce4d2021-10-05 05:26:29 -07006450
6451 firstWindow->consumeMotionDown();
6452 secondWindow->assertNoEvents();
6453}
6454
6455// Ensure that when a MotionEvent is injected through the InputDispatcher::injectInputEvent() API,
6456// the event should be treated as being in the logical display space.
6457TEST_F(InputDispatcherDisplayProjectionTest, InjectionInLogicalDisplaySpace) {
6458 auto [firstWindow, secondWindow] = setupScaledDisplayScenario();
6459 // Send down to the first window. The point is represented in the logical display space. The
6460 // point is selected so that if the hit test was done in logical display space, then it would
6461 // end up in the incorrect window.
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07006462 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ui::LogicalDisplayId::DEFAULT,
Prabir Pradhanc44ce4d2021-10-05 05:26:29 -07006463 PointF{75 * 2, 55 * 4});
6464
6465 firstWindow->consumeMotionDown();
6466 secondWindow->assertNoEvents();
6467}
6468
Prabir Pradhandaa2f142021-12-10 09:30:08 +00006469// Ensure that when a MotionEvent that has a custom transform is injected, the post-transformed
6470// event should be treated as being in the logical display space.
6471TEST_F(InputDispatcherDisplayProjectionTest, InjectionWithTransformInLogicalDisplaySpace) {
6472 auto [firstWindow, secondWindow] = setupScaledDisplayScenario();
6473
6474 const std::array<float, 9> matrix = {1.1, 2.2, 3.3, 4.4, 5.5, 6.6, 0.0, 0.0, 1.0};
6475 ui::Transform injectedEventTransform;
6476 injectedEventTransform.set(matrix);
6477 const vec2 expectedPoint{75, 55}; // The injected point in the logical display space.
6478 const vec2 untransformedPoint = injectedEventTransform.inverse().transform(expectedPoint);
6479
6480 MotionEvent event = MotionEventBuilder(AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07006481 .displayId(ui::LogicalDisplayId::DEFAULT)
Prabir Pradhandaa2f142021-12-10 09:30:08 +00006482 .eventTime(systemTime(SYSTEM_TIME_MONOTONIC))
Siarhei Vishniakou6d73f832022-07-21 17:27:03 -07006483 .pointer(PointerBuilder(/*id=*/0, ToolType::FINGER)
Prabir Pradhandaa2f142021-12-10 09:30:08 +00006484 .x(untransformedPoint.x)
6485 .y(untransformedPoint.y))
6486 .build();
6487 event.transform(matrix);
6488
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07006489 injectMotionEvent(*mDispatcher, event, INJECT_EVENT_TIMEOUT,
Prabir Pradhandaa2f142021-12-10 09:30:08 +00006490 InputEventInjectionSync::WAIT_FOR_RESULT);
6491
6492 firstWindow->consumeMotionDown();
6493 secondWindow->assertNoEvents();
6494}
6495
Prabir Pradhanc44ce4d2021-10-05 05:26:29 -07006496TEST_F(InputDispatcherDisplayProjectionTest, WindowGetsEventsInCorrectCoordinateSpace) {
6497 auto [firstWindow, secondWindow] = setupScaledDisplayScenario();
6498
6499 // Send down to the second window.
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07006500 mDispatcher->notifyMotion(
6501 generateMotionArgs(AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN,
6502 ui::LogicalDisplayId::DEFAULT, {PointF{150, 220}}));
Prabir Pradhanc44ce4d2021-10-05 05:26:29 -07006503
6504 firstWindow->assertNoEvents();
Siarhei Vishniakoud3061ab2023-12-18 20:41:08 -08006505 std::unique_ptr<MotionEvent> event = secondWindow->consumeMotionEvent();
6506 ASSERT_NE(nullptr, event);
6507 EXPECT_EQ(AMOTION_EVENT_ACTION_DOWN, event->getAction());
Prabir Pradhanc44ce4d2021-10-05 05:26:29 -07006508
6509 // Ensure that the events from the "getRaw" API are in logical display coordinates.
Siarhei Vishniakoud3061ab2023-12-18 20:41:08 -08006510 EXPECT_EQ(300, event->getRawX(0));
6511 EXPECT_EQ(880, event->getRawY(0));
Prabir Pradhanc44ce4d2021-10-05 05:26:29 -07006512
6513 // Ensure that the x and y values are in the window's coordinate space.
6514 // The left-top of the second window is at (100, 200) in display space, which is (200, 800) in
6515 // the logical display space. This will be the origin of the window space.
Siarhei Vishniakoud3061ab2023-12-18 20:41:08 -08006516 EXPECT_EQ(100, event->getX(0));
6517 EXPECT_EQ(80, event->getY(0));
Prabir Pradhanc44ce4d2021-10-05 05:26:29 -07006518}
6519
Prabir Pradhan112b1ad2023-09-21 09:53:53 +00006520TEST_F(InputDispatcherDisplayProjectionTest, CancelMotionWithCorrectCoordinates) {
6521 auto [firstWindow, secondWindow] = setupScaledDisplayScenario();
6522 // The monitor will always receive events in the logical display's coordinate space, because
6523 // it does not have a window.
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07006524 FakeMonitorReceiver monitor{*mDispatcher, "Monitor", ui::LogicalDisplayId::DEFAULT};
Prabir Pradhan112b1ad2023-09-21 09:53:53 +00006525
6526 // Send down to the first window.
6527 mDispatcher->notifyMotion(generateMotionArgs(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN,
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07006528 ui::LogicalDisplayId::DEFAULT, {PointF{50, 100}}));
Prabir Pradhan112b1ad2023-09-21 09:53:53 +00006529 firstWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithCoords(100, 400)));
6530 monitor.consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithCoords(100, 400)));
6531
6532 // Second pointer goes down on second window.
6533 mDispatcher->notifyMotion(generateMotionArgs(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN,
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07006534 ui::LogicalDisplayId::DEFAULT,
Prabir Pradhan112b1ad2023-09-21 09:53:53 +00006535 {PointF{50, 100}, PointF{150, 220}}));
6536 secondWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithCoords(100, 80)));
6537 const std::map<int32_t, PointF> expectedMonitorPointers{{0, PointF{100, 400}},
6538 {1, PointF{300, 880}}};
6539 monitor.consumeMotionEvent(
6540 AllOf(WithMotionAction(POINTER_1_DOWN), WithPointers(expectedMonitorPointers)));
6541
6542 mDispatcher->cancelCurrentTouch();
6543
6544 firstWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_CANCEL), WithCoords(100, 400)));
6545 secondWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_CANCEL), WithCoords(100, 80)));
6546 monitor.consumeMotionEvent(
6547 AllOf(WithMotionAction(ACTION_CANCEL), WithPointers(expectedMonitorPointers)));
6548}
6549
Prabir Pradhan1c29a092023-09-21 10:29:29 +00006550TEST_F(InputDispatcherDisplayProjectionTest, SynthesizeDownWithCorrectCoordinates) {
6551 auto [firstWindow, secondWindow] = setupScaledDisplayScenario();
6552
6553 // Send down to the first window.
6554 mDispatcher->notifyMotion(generateMotionArgs(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN,
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07006555 ui::LogicalDisplayId::DEFAULT, {PointF{50, 100}}));
Prabir Pradhan1c29a092023-09-21 10:29:29 +00006556 firstWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithCoords(100, 400)));
6557
6558 // The pointer is transferred to the second window, and the second window receives it in the
6559 // correct coordinate space.
Prabir Pradhan367f3432024-02-13 23:05:58 +00006560 mDispatcher->transferTouchGesture(firstWindow->getToken(), secondWindow->getToken());
Prabir Pradhan1c29a092023-09-21 10:29:29 +00006561 firstWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_CANCEL), WithCoords(100, 400)));
6562 secondWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithCoords(-100, -400)));
6563}
6564
Prabir Pradhan0dfcac72023-10-05 20:04:21 +00006565TEST_F(InputDispatcherDisplayProjectionTest, SynthesizeHoverEnterExitWithCorrectCoordinates) {
6566 auto [firstWindow, secondWindow] = setupScaledDisplayScenario();
6567
6568 // Send hover move to the second window, and ensure it shows up as hover enter.
6569 mDispatcher->notifyMotion(generateMotionArgs(ACTION_HOVER_MOVE, AINPUT_SOURCE_STYLUS,
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07006570 ui::LogicalDisplayId::DEFAULT,
6571 {PointF{150, 220}}));
Prabir Pradhan0dfcac72023-10-05 20:04:21 +00006572 secondWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_HOVER_ENTER),
6573 WithCoords(100, 80), WithRawCoords(300, 880)));
6574
6575 // Touch down at the same location and ensure a hover exit is synthesized.
6576 mDispatcher->notifyMotion(generateMotionArgs(ACTION_DOWN, AINPUT_SOURCE_STYLUS,
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07006577 ui::LogicalDisplayId::DEFAULT,
6578 {PointF{150, 220}}));
Prabir Pradhan0dfcac72023-10-05 20:04:21 +00006579 secondWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_HOVER_EXIT), WithCoords(100, 80),
6580 WithRawCoords(300, 880)));
6581 secondWindow->consumeMotionEvent(
6582 AllOf(WithMotionAction(ACTION_DOWN), WithCoords(100, 80), WithRawCoords(300, 880)));
6583 secondWindow->assertNoEvents();
6584 firstWindow->assertNoEvents();
6585}
6586
Prabir Pradhan453ae732023-10-13 14:30:14 +00006587// Same as above, but while the window is being mirrored.
6588TEST_F(InputDispatcherDisplayProjectionTest,
6589 SynthesizeHoverEnterExitWithCorrectCoordinatesWhenMirrored) {
6590 auto [firstWindow, secondWindow] = setupScaledDisplayScenario();
6591
6592 const std::array<float, 9> matrix = {1.1, 2.2, 3.3, 4.4, 5.5, 6.6, 0.0, 0.0, 1.0};
6593 ui::Transform secondDisplayTransform;
6594 secondDisplayTransform.set(matrix);
6595 addDisplayInfo(SECOND_DISPLAY_ID, secondDisplayTransform);
6596
6597 sp<FakeWindowHandle> secondWindowClone = secondWindow->clone(SECOND_DISPLAY_ID);
6598 secondWindowClone->setWindowTransform(1.1, 2.2, 3.3, 4.4);
6599 addWindow(secondWindowClone);
6600
6601 // Send hover move to the second window, and ensure it shows up as hover enter.
6602 mDispatcher->notifyMotion(generateMotionArgs(ACTION_HOVER_MOVE, AINPUT_SOURCE_STYLUS,
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07006603 ui::LogicalDisplayId::DEFAULT,
6604 {PointF{150, 220}}));
Prabir Pradhan453ae732023-10-13 14:30:14 +00006605 secondWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_HOVER_ENTER),
6606 WithCoords(100, 80), WithRawCoords(300, 880)));
6607
6608 // Touch down at the same location and ensure a hover exit is synthesized for the correct
6609 // display.
6610 mDispatcher->notifyMotion(generateMotionArgs(ACTION_DOWN, AINPUT_SOURCE_STYLUS,
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07006611 ui::LogicalDisplayId::DEFAULT,
6612 {PointF{150, 220}}));
Prabir Pradhan453ae732023-10-13 14:30:14 +00006613 secondWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_HOVER_EXIT), WithCoords(100, 80),
6614 WithRawCoords(300, 880)));
6615 secondWindow->consumeMotionEvent(
6616 AllOf(WithMotionAction(ACTION_DOWN), WithCoords(100, 80), WithRawCoords(300, 880)));
6617 secondWindow->assertNoEvents();
6618 firstWindow->assertNoEvents();
6619}
6620
Prabir Pradhan0dfcac72023-10-05 20:04:21 +00006621TEST_F(InputDispatcherDisplayProjectionTest, SynthesizeHoverCancelationWithCorrectCoordinates) {
6622 auto [firstWindow, secondWindow] = setupScaledDisplayScenario();
6623
6624 // Send hover enter to second window
6625 mDispatcher->notifyMotion(generateMotionArgs(ACTION_HOVER_ENTER, AINPUT_SOURCE_STYLUS,
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07006626 ui::LogicalDisplayId::DEFAULT,
6627 {PointF{150, 220}}));
Prabir Pradhan0dfcac72023-10-05 20:04:21 +00006628 secondWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_HOVER_ENTER),
6629 WithCoords(100, 80), WithRawCoords(300, 880)));
6630
6631 mDispatcher->cancelCurrentTouch();
6632
6633 secondWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_HOVER_EXIT), WithCoords(100, 80),
6634 WithRawCoords(300, 880)));
6635 secondWindow->assertNoEvents();
6636 firstWindow->assertNoEvents();
6637}
6638
Prabir Pradhan453ae732023-10-13 14:30:14 +00006639// Same as above, but while the window is being mirrored.
Prabir Pradhan16463382023-10-12 23:03:19 +00006640TEST_F(InputDispatcherDisplayProjectionTest,
6641 SynthesizeHoverCancelationWithCorrectCoordinatesWhenMirrored) {
6642 auto [firstWindow, secondWindow] = setupScaledDisplayScenario();
6643
6644 const std::array<float, 9> matrix = {1.1, 2.2, 3.3, 4.4, 5.5, 6.6, 0.0, 0.0, 1.0};
6645 ui::Transform secondDisplayTransform;
6646 secondDisplayTransform.set(matrix);
6647 addDisplayInfo(SECOND_DISPLAY_ID, secondDisplayTransform);
6648
6649 sp<FakeWindowHandle> secondWindowClone = secondWindow->clone(SECOND_DISPLAY_ID);
6650 secondWindowClone->setWindowTransform(1.1, 2.2, 3.3, 4.4);
6651 addWindow(secondWindowClone);
6652
6653 // Send hover enter to second window
6654 mDispatcher->notifyMotion(generateMotionArgs(ACTION_HOVER_ENTER, AINPUT_SOURCE_STYLUS,
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07006655 ui::LogicalDisplayId::DEFAULT,
6656 {PointF{150, 220}}));
Prabir Pradhan16463382023-10-12 23:03:19 +00006657 secondWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_HOVER_ENTER),
6658 WithCoords(100, 80), WithRawCoords(300, 880),
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07006659 WithDisplayId(ui::LogicalDisplayId::DEFAULT)));
Prabir Pradhan16463382023-10-12 23:03:19 +00006660
6661 mDispatcher->cancelCurrentTouch();
6662
6663 // Ensure the cancelation happens with the correct displayId and the correct coordinates.
6664 secondWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_HOVER_EXIT), WithCoords(100, 80),
6665 WithRawCoords(300, 880),
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07006666 WithDisplayId(ui::LogicalDisplayId::DEFAULT)));
Prabir Pradhan16463382023-10-12 23:03:19 +00006667 secondWindow->assertNoEvents();
6668 firstWindow->assertNoEvents();
6669}
6670
Prabir Pradhan33e3baa2022-12-06 20:30:22 +00006671/** Ensure consistent behavior of InputDispatcher in all orientations. */
6672class InputDispatcherDisplayOrientationFixture
6673 : public InputDispatcherDisplayProjectionTest,
6674 public ::testing::WithParamInterface<ui::Rotation> {};
6675
6676// This test verifies the touchable region of a window for all rotations of the display by tapping
6677// in different locations on the display, specifically points close to the four corners of a
6678// window.
6679TEST_P(InputDispatcherDisplayOrientationFixture, HitTestInDifferentOrientations) {
6680 constexpr static int32_t displayWidth = 400;
6681 constexpr static int32_t displayHeight = 800;
6682
6683 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
6684
6685 const auto rotation = GetParam();
6686
6687 // Set up the display with the specified rotation.
6688 const bool isRotated = rotation == ui::ROTATION_90 || rotation == ui::ROTATION_270;
6689 const int32_t logicalDisplayWidth = isRotated ? displayHeight : displayWidth;
6690 const int32_t logicalDisplayHeight = isRotated ? displayWidth : displayHeight;
6691 const ui::Transform displayTransform(ui::Transform::toRotationFlags(rotation),
6692 logicalDisplayWidth, logicalDisplayHeight);
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07006693 addDisplayInfo(ui::LogicalDisplayId::DEFAULT, displayTransform);
Prabir Pradhan33e3baa2022-12-06 20:30:22 +00006694
6695 // Create a window with its bounds determined in the logical display.
6696 const Rect frameInLogicalDisplay(100, 100, 200, 300);
6697 const Rect frameInDisplay = displayTransform.inverse().transform(frameInLogicalDisplay);
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07006698 sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher, "Window",
6699 ui::LogicalDisplayId::DEFAULT);
Prabir Pradhan33e3baa2022-12-06 20:30:22 +00006700 window->setFrame(frameInDisplay, displayTransform);
6701 addWindow(window);
6702
6703 // The following points in logical display space should be inside the window.
6704 static const std::array<vec2, 4> insidePoints{
6705 {{100, 100}, {199.99, 100}, {100, 299.99}, {199.99, 299.99}}};
6706 for (const auto pointInsideWindow : insidePoints) {
6707 const vec2 p = displayTransform.inverse().transform(pointInsideWindow);
6708 const PointF pointInDisplaySpace{p.x, p.y};
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07006709 mDispatcher->notifyMotion(
6710 generateMotionArgs(AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN,
6711 ui::LogicalDisplayId::DEFAULT, {pointInDisplaySpace}));
Prabir Pradhan33e3baa2022-12-06 20:30:22 +00006712 window->consumeMotionDown();
6713
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07006714 mDispatcher->notifyMotion(
6715 generateMotionArgs(AMOTION_EVENT_ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN,
6716 ui::LogicalDisplayId::DEFAULT, {pointInDisplaySpace}));
Prabir Pradhan33e3baa2022-12-06 20:30:22 +00006717 window->consumeMotionUp();
6718 }
6719
6720 // The following points in logical display space should be outside the window.
6721 static const std::array<vec2, 5> outsidePoints{
6722 {{200, 100}, {100, 300}, {200, 300}, {100, 99.99}, {99.99, 100}}};
6723 for (const auto pointOutsideWindow : outsidePoints) {
6724 const vec2 p = displayTransform.inverse().transform(pointOutsideWindow);
6725 const PointF pointInDisplaySpace{p.x, p.y};
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07006726 mDispatcher->notifyMotion(
6727 generateMotionArgs(AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN,
6728 ui::LogicalDisplayId::DEFAULT, {pointInDisplaySpace}));
Prabir Pradhan33e3baa2022-12-06 20:30:22 +00006729
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07006730 mDispatcher->notifyMotion(
6731 generateMotionArgs(AMOTION_EVENT_ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN,
6732 ui::LogicalDisplayId::DEFAULT, {pointInDisplaySpace}));
Prabir Pradhan33e3baa2022-12-06 20:30:22 +00006733 }
6734 window->assertNoEvents();
6735}
6736
Linnan Li5e5645e2024-03-05 14:43:05 +00006737// This test verifies the occlusion detection for all rotations of the display by tapping
6738// in different locations on the display, specifically points close to the four corners of a
6739// window.
6740TEST_P(InputDispatcherDisplayOrientationFixture, BlockUntrustClickInDifferentOrientations) {
6741 constexpr static int32_t displayWidth = 400;
6742 constexpr static int32_t displayHeight = 800;
6743
6744 std::shared_ptr<FakeApplicationHandle> untrustedWindowApplication =
6745 std::make_shared<FakeApplicationHandle>();
6746 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
6747
6748 const auto rotation = GetParam();
6749
6750 // Set up the display with the specified rotation.
6751 const bool isRotated = rotation == ui::ROTATION_90 || rotation == ui::ROTATION_270;
6752 const int32_t logicalDisplayWidth = isRotated ? displayHeight : displayWidth;
6753 const int32_t logicalDisplayHeight = isRotated ? displayWidth : displayHeight;
6754 const ui::Transform displayTransform(ui::Transform::toRotationFlags(rotation),
6755 logicalDisplayWidth, logicalDisplayHeight);
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07006756 addDisplayInfo(ui::LogicalDisplayId::DEFAULT, displayTransform);
Linnan Li5e5645e2024-03-05 14:43:05 +00006757
6758 // Create a window that not trusted.
6759 const Rect untrustedWindowFrameInLogicalDisplay(100, 100, 200, 300);
6760
6761 const Rect untrustedWindowFrameInDisplay =
6762 displayTransform.inverse().transform(untrustedWindowFrameInLogicalDisplay);
6763
6764 sp<FakeWindowHandle> untrustedWindow =
6765 sp<FakeWindowHandle>::make(untrustedWindowApplication, mDispatcher, "UntrustedWindow",
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07006766 ui::LogicalDisplayId::DEFAULT);
Linnan Li5e5645e2024-03-05 14:43:05 +00006767 untrustedWindow->setFrame(untrustedWindowFrameInDisplay, displayTransform);
6768 untrustedWindow->setTrustedOverlay(false);
6769 untrustedWindow->setTouchOcclusionMode(TouchOcclusionMode::BLOCK_UNTRUSTED);
6770 untrustedWindow->setTouchable(false);
6771 untrustedWindow->setAlpha(1.0f);
6772 untrustedWindow->setOwnerInfo(gui::Pid{1}, gui::Uid{101});
6773 addWindow(untrustedWindow);
6774
6775 // Create a simple app window below the untrusted window.
6776 const Rect simpleAppWindowFrameInLogicalDisplay(0, 0, 300, 600);
6777 const Rect simpleAppWindowFrameInDisplay =
6778 displayTransform.inverse().transform(simpleAppWindowFrameInLogicalDisplay);
6779
6780 sp<FakeWindowHandle> simpleAppWindow =
6781 sp<FakeWindowHandle>::make(application, mDispatcher, "SimpleAppWindow",
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07006782 ui::LogicalDisplayId::DEFAULT);
Linnan Li5e5645e2024-03-05 14:43:05 +00006783 simpleAppWindow->setFrame(simpleAppWindowFrameInDisplay, displayTransform);
6784 simpleAppWindow->setOwnerInfo(gui::Pid{2}, gui::Uid{202});
6785 addWindow(simpleAppWindow);
6786
6787 // The following points in logical display space should be inside the untrusted window, so
6788 // the simple window could not receive events that coordinate is these point.
6789 static const std::array<vec2, 4> untrustedPoints{
6790 {{100, 100}, {199.99, 100}, {100, 299.99}, {199.99, 299.99}}};
6791
6792 for (const auto untrustedPoint : untrustedPoints) {
6793 const vec2 p = displayTransform.inverse().transform(untrustedPoint);
6794 const PointF pointInDisplaySpace{p.x, p.y};
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07006795 mDispatcher->notifyMotion(
6796 generateMotionArgs(AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN,
6797 ui::LogicalDisplayId::DEFAULT, {pointInDisplaySpace}));
6798 mDispatcher->notifyMotion(
6799 generateMotionArgs(AMOTION_EVENT_ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN,
6800 ui::LogicalDisplayId::DEFAULT, {pointInDisplaySpace}));
Linnan Li5e5645e2024-03-05 14:43:05 +00006801 }
6802 untrustedWindow->assertNoEvents();
6803 simpleAppWindow->assertNoEvents();
6804 // The following points in logical display space should be outside the untrusted window, so
6805 // the simple window should receive events that coordinate is these point.
6806 static const std::array<vec2, 5> trustedPoints{
6807 {{200, 100}, {100, 300}, {200, 300}, {100, 99.99}, {99.99, 100}}};
6808 for (const auto trustedPoint : trustedPoints) {
6809 const vec2 p = displayTransform.inverse().transform(trustedPoint);
6810 const PointF pointInDisplaySpace{p.x, p.y};
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07006811 mDispatcher->notifyMotion(
6812 generateMotionArgs(AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN,
6813 ui::LogicalDisplayId::DEFAULT, {pointInDisplaySpace}));
6814 simpleAppWindow->consumeMotionDown(ui::LogicalDisplayId::DEFAULT,
Linnan Li5e5645e2024-03-05 14:43:05 +00006815 AMOTION_EVENT_FLAG_WINDOW_IS_PARTIALLY_OBSCURED);
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07006816 mDispatcher->notifyMotion(
6817 generateMotionArgs(AMOTION_EVENT_ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN,
6818 ui::LogicalDisplayId::DEFAULT, {pointInDisplaySpace}));
6819 simpleAppWindow->consumeMotionUp(ui::LogicalDisplayId::DEFAULT,
Linnan Li5e5645e2024-03-05 14:43:05 +00006820 AMOTION_EVENT_FLAG_WINDOW_IS_PARTIALLY_OBSCURED);
6821 }
6822 untrustedWindow->assertNoEvents();
6823}
6824
Prabir Pradhan33e3baa2022-12-06 20:30:22 +00006825// Run the precision tests for all rotations.
6826INSTANTIATE_TEST_SUITE_P(InputDispatcherDisplayOrientationTests,
6827 InputDispatcherDisplayOrientationFixture,
6828 ::testing::Values(ui::ROTATION_0, ui::ROTATION_90, ui::ROTATION_180,
6829 ui::ROTATION_270),
6830 [](const testing::TestParamInfo<ui::Rotation>& testParamInfo) {
6831 return ftl::enum_string(testParamInfo.param);
6832 });
6833
Siarhei Vishniakou18050092021-09-01 13:32:49 -07006834using TransferFunction = std::function<bool(const std::unique_ptr<InputDispatcher>& dispatcher,
6835 sp<IBinder>, sp<IBinder>)>;
Siarhei Vishniakoud0c6bc82021-03-13 03:14:52 +00006836
6837class TransferTouchFixture : public InputDispatcherTest,
6838 public ::testing::WithParamInterface<TransferFunction> {};
6839
6840TEST_P(TransferTouchFixture, TransferTouch_OnePointer) {
Chris Yea209fde2020-07-22 13:54:51 -07006841 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
Svet Ganov5d3bc372020-01-26 23:11:07 -08006842
6843 // Create a couple of windows
Siarhei Vishniakou870ecec2020-12-09 08:07:46 -10006844 sp<FakeWindowHandle> firstWindow =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07006845 sp<FakeWindowHandle>::make(application, mDispatcher, "First Window",
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07006846 ui::LogicalDisplayId::DEFAULT);
Arthur Hungc539dbb2022-12-08 07:45:36 +00006847 firstWindow->setDupTouchToWallpaper(true);
Siarhei Vishniakou870ecec2020-12-09 08:07:46 -10006848 sp<FakeWindowHandle> secondWindow =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07006849 sp<FakeWindowHandle>::make(application, mDispatcher, "Second Window",
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07006850 ui::LogicalDisplayId::DEFAULT);
Arthur Hungc539dbb2022-12-08 07:45:36 +00006851 sp<FakeWindowHandle> wallpaper =
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07006852 sp<FakeWindowHandle>::make(application, mDispatcher, "Wallpaper",
6853 ui::LogicalDisplayId::DEFAULT);
Arthur Hungc539dbb2022-12-08 07:45:36 +00006854 wallpaper->setIsWallpaper(true);
Prabir Pradhan65455c72024-02-13 21:46:41 +00006855 // Add the windows to the dispatcher, and ensure the first window is focused
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07006856 mDispatcher->onWindowInfosChanged(
6857 {{*firstWindow->getInfo(), *secondWindow->getInfo(), *wallpaper->getInfo()}, {}, 0, 0});
Prabir Pradhan65455c72024-02-13 21:46:41 +00006858 setFocusedWindow(firstWindow);
6859 firstWindow->consumeFocusEvent(true);
Svet Ganov5d3bc372020-01-26 23:11:07 -08006860
6861 // Send down to the first window
Prabir Pradhan678438e2023-04-13 19:32:51 +00006862 mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_DOWN,
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07006863 AINPUT_SOURCE_TOUCHSCREEN,
6864 ui::LogicalDisplayId::DEFAULT));
Arthur Hungc539dbb2022-12-08 07:45:36 +00006865
Svet Ganov5d3bc372020-01-26 23:11:07 -08006866 // Only the first window should get the down event
6867 firstWindow->consumeMotionDown();
6868 secondWindow->assertNoEvents();
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07006869 wallpaper->consumeMotionDown(ui::LogicalDisplayId::DEFAULT, EXPECTED_WALLPAPER_FLAGS);
Prabir Pradhan65455c72024-02-13 21:46:41 +00006870 // Dispatcher reports pointer down outside focus for the wallpaper
6871 mFakePolicy->assertOnPointerDownEquals(wallpaper->getToken());
Svet Ganov5d3bc372020-01-26 23:11:07 -08006872
Siarhei Vishniakoud0c6bc82021-03-13 03:14:52 +00006873 // Transfer touch to the second window
6874 TransferFunction f = GetParam();
6875 const bool success = f(mDispatcher, firstWindow->getToken(), secondWindow->getToken());
6876 ASSERT_TRUE(success);
Svet Ganov5d3bc372020-01-26 23:11:07 -08006877 // The first window gets cancel and the second gets down
6878 firstWindow->consumeMotionCancel();
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07006879 secondWindow->consumeMotionDown(ui::LogicalDisplayId::DEFAULT,
6880 AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
6881 wallpaper->consumeMotionCancel(ui::LogicalDisplayId::DEFAULT, EXPECTED_WALLPAPER_FLAGS);
Prabir Pradhan65455c72024-02-13 21:46:41 +00006882 // There should not be any changes to the focused window when transferring touch
6883 ASSERT_NO_FATAL_FAILURE(mFakePolicy->assertOnPointerDownWasNotCalled());
Svet Ganov5d3bc372020-01-26 23:11:07 -08006884
6885 // Send up event to the second window
Prabir Pradhan678438e2023-04-13 19:32:51 +00006886 mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN,
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07006887 ui::LogicalDisplayId::DEFAULT));
Prabir Pradhan65455c72024-02-13 21:46:41 +00006888 // The first window gets no events and the second gets up
Svet Ganov5d3bc372020-01-26 23:11:07 -08006889 firstWindow->assertNoEvents();
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07006890 secondWindow->consumeMotionUp(ui::LogicalDisplayId::DEFAULT,
6891 AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
Arthur Hungc539dbb2022-12-08 07:45:36 +00006892 wallpaper->assertNoEvents();
Svet Ganov5d3bc372020-01-26 23:11:07 -08006893}
6894
Siarhei Vishniakou7ae7afd2022-03-31 15:26:13 -07006895/**
Prabir Pradhan367f3432024-02-13 23:05:58 +00006896 * When 'transferTouchGesture' API is invoked, dispatcher needs to find the "best" window to take
6897 * touch from. When we have spy windows, there are several windows to choose from: either spy, or
6898 * the 'real' (non-spy) window. Always prefer the 'real' window because that's what would be most
Siarhei Vishniakou7ae7afd2022-03-31 15:26:13 -07006899 * natural to the user.
6900 * In this test, we are sending a pointer to both spy window and first window. We then try to
6901 * transfer touch to the second window. The dispatcher should identify the first window as the
6902 * one that should lose the gesture, and therefore the action should be to move the gesture from
6903 * the first window to the second.
Prabir Pradhan367f3432024-02-13 23:05:58 +00006904 * The main goal here is to test the behaviour of 'transferTouchGesture' API, but it's still valid
6905 * to test the other API, as well.
Siarhei Vishniakou7ae7afd2022-03-31 15:26:13 -07006906 */
6907TEST_P(TransferTouchFixture, TransferTouch_MultipleWindowsWithSpy) {
6908 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
6909
6910 // Create a couple of windows + a spy window
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07006911 sp<FakeWindowHandle> spyWindow = sp<FakeWindowHandle>::make(application, mDispatcher, "Spy",
6912 ui::LogicalDisplayId::DEFAULT);
Siarhei Vishniakou7ae7afd2022-03-31 15:26:13 -07006913 spyWindow->setTrustedOverlay(true);
6914 spyWindow->setSpy(true);
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07006915 sp<FakeWindowHandle> firstWindow = sp<FakeWindowHandle>::make(application, mDispatcher, "First",
6916 ui::LogicalDisplayId::DEFAULT);
Siarhei Vishniakou7ae7afd2022-03-31 15:26:13 -07006917 sp<FakeWindowHandle> secondWindow =
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07006918 sp<FakeWindowHandle>::make(application, mDispatcher, "Second",
6919 ui::LogicalDisplayId::DEFAULT);
Siarhei Vishniakou7ae7afd2022-03-31 15:26:13 -07006920
6921 // Add the windows to the dispatcher
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07006922 mDispatcher->onWindowInfosChanged(
6923 {{*spyWindow->getInfo(), *firstWindow->getInfo(), *secondWindow->getInfo()}, {}, 0, 0});
Siarhei Vishniakou7ae7afd2022-03-31 15:26:13 -07006924
6925 // Send down to the first window
Prabir Pradhan678438e2023-04-13 19:32:51 +00006926 mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_DOWN,
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07006927 AINPUT_SOURCE_TOUCHSCREEN,
6928 ui::LogicalDisplayId::DEFAULT));
Siarhei Vishniakou7ae7afd2022-03-31 15:26:13 -07006929 // Only the first window and spy should get the down event
6930 spyWindow->consumeMotionDown();
6931 firstWindow->consumeMotionDown();
6932
6933 // Transfer touch to the second window. Non-spy window should be preferred over the spy window
Prabir Pradhan367f3432024-02-13 23:05:58 +00006934 // if f === 'transferTouchGesture'.
Siarhei Vishniakou7ae7afd2022-03-31 15:26:13 -07006935 TransferFunction f = GetParam();
6936 const bool success = f(mDispatcher, firstWindow->getToken(), secondWindow->getToken());
6937 ASSERT_TRUE(success);
6938 // The first window gets cancel and the second gets down
6939 firstWindow->consumeMotionCancel();
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07006940 secondWindow->consumeMotionDown(ui::LogicalDisplayId::DEFAULT,
6941 AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
Siarhei Vishniakou7ae7afd2022-03-31 15:26:13 -07006942
6943 // Send up event to the second window
Prabir Pradhan678438e2023-04-13 19:32:51 +00006944 mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN,
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07006945 ui::LogicalDisplayId::DEFAULT));
Siarhei Vishniakou7ae7afd2022-03-31 15:26:13 -07006946 // The first window gets no events and the second+spy get up
6947 firstWindow->assertNoEvents();
6948 spyWindow->consumeMotionUp();
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07006949 secondWindow->consumeMotionUp(ui::LogicalDisplayId::DEFAULT,
6950 AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
Siarhei Vishniakou7ae7afd2022-03-31 15:26:13 -07006951}
6952
Siarhei Vishniakoud0c6bc82021-03-13 03:14:52 +00006953TEST_P(TransferTouchFixture, TransferTouch_TwoPointersNonSplitTouch) {
Chris Yea209fde2020-07-22 13:54:51 -07006954 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
Svet Ganov5d3bc372020-01-26 23:11:07 -08006955
6956 PointF touchPoint = {10, 10};
6957
6958 // Create a couple of windows
Siarhei Vishniakou870ecec2020-12-09 08:07:46 -10006959 sp<FakeWindowHandle> firstWindow =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07006960 sp<FakeWindowHandle>::make(application, mDispatcher, "First Window",
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07006961 ui::LogicalDisplayId::DEFAULT);
Prabir Pradhan76bdecb2022-01-31 11:14:15 -08006962 firstWindow->setPreventSplitting(true);
Siarhei Vishniakou870ecec2020-12-09 08:07:46 -10006963 sp<FakeWindowHandle> secondWindow =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07006964 sp<FakeWindowHandle>::make(application, mDispatcher, "Second Window",
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07006965 ui::LogicalDisplayId::DEFAULT);
Prabir Pradhan76bdecb2022-01-31 11:14:15 -08006966 secondWindow->setPreventSplitting(true);
Svet Ganov5d3bc372020-01-26 23:11:07 -08006967
6968 // Add the windows to the dispatcher
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07006969 mDispatcher->onWindowInfosChanged(
6970 {{*firstWindow->getInfo(), *secondWindow->getInfo()}, {}, 0, 0});
Svet Ganov5d3bc372020-01-26 23:11:07 -08006971
6972 // Send down to the first window
Prabir Pradhan678438e2023-04-13 19:32:51 +00006973 mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_DOWN,
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07006974 AINPUT_SOURCE_TOUCHSCREEN,
6975 ui::LogicalDisplayId::DEFAULT, {touchPoint}));
Svet Ganov5d3bc372020-01-26 23:11:07 -08006976 // Only the first window should get the down event
6977 firstWindow->consumeMotionDown();
6978 secondWindow->assertNoEvents();
6979
6980 // Send pointer down to the first window
Prabir Pradhan678438e2023-04-13 19:32:51 +00006981 mDispatcher->notifyMotion(generateMotionArgs(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN,
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07006982 ui::LogicalDisplayId::DEFAULT,
6983 {touchPoint, touchPoint}));
Svet Ganov5d3bc372020-01-26 23:11:07 -08006984 // Only the first window should get the pointer down event
6985 firstWindow->consumeMotionPointerDown(1);
6986 secondWindow->assertNoEvents();
6987
6988 // Transfer touch focus to the second window
Siarhei Vishniakoud0c6bc82021-03-13 03:14:52 +00006989 TransferFunction f = GetParam();
6990 bool success = f(mDispatcher, firstWindow->getToken(), secondWindow->getToken());
6991 ASSERT_TRUE(success);
Svet Ganov5d3bc372020-01-26 23:11:07 -08006992 // The first window gets cancel and the second gets down and pointer down
6993 firstWindow->consumeMotionCancel();
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07006994 secondWindow->consumeMotionDown(ui::LogicalDisplayId::DEFAULT,
6995 AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
6996 secondWindow->consumeMotionPointerDown(1, ui::LogicalDisplayId::DEFAULT,
Prabir Pradhan65455c72024-02-13 21:46:41 +00006997 AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
Svet Ganov5d3bc372020-01-26 23:11:07 -08006998
6999 // Send pointer up to the second window
Prabir Pradhan678438e2023-04-13 19:32:51 +00007000 mDispatcher->notifyMotion(generateMotionArgs(POINTER_1_UP, AINPUT_SOURCE_TOUCHSCREEN,
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07007001 ui::LogicalDisplayId::DEFAULT,
7002 {touchPoint, touchPoint}));
Svet Ganov5d3bc372020-01-26 23:11:07 -08007003 // The first window gets nothing and the second gets pointer up
7004 firstWindow->assertNoEvents();
Prabir Pradhan33cfc6d2024-06-11 20:17:44 +00007005 secondWindow->consumeMotionPointerUp(/*pointerIdx=*/1,
7006 AllOf(WithDisplayId(ui::LogicalDisplayId::DEFAULT),
7007 WithFlags(AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE),
7008 WithPointerCount(2)));
Svet Ganov5d3bc372020-01-26 23:11:07 -08007009
7010 // Send up event to the second window
Prabir Pradhan678438e2023-04-13 19:32:51 +00007011 mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN,
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07007012 ui::LogicalDisplayId::DEFAULT));
Svet Ganov5d3bc372020-01-26 23:11:07 -08007013 // The first window gets nothing and the second gets up
7014 firstWindow->assertNoEvents();
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07007015 secondWindow->consumeMotionUp(ui::LogicalDisplayId::DEFAULT,
7016 AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
Svet Ganov5d3bc372020-01-26 23:11:07 -08007017}
7018
Arthur Hungc539dbb2022-12-08 07:45:36 +00007019TEST_P(TransferTouchFixture, TransferTouch_MultipleWallpapers) {
7020 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
7021
7022 // Create a couple of windows
7023 sp<FakeWindowHandle> firstWindow =
7024 sp<FakeWindowHandle>::make(application, mDispatcher, "First Window",
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07007025 ui::LogicalDisplayId::DEFAULT);
Arthur Hungc539dbb2022-12-08 07:45:36 +00007026 firstWindow->setDupTouchToWallpaper(true);
7027 sp<FakeWindowHandle> secondWindow =
7028 sp<FakeWindowHandle>::make(application, mDispatcher, "Second Window",
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07007029 ui::LogicalDisplayId::DEFAULT);
Arthur Hungc539dbb2022-12-08 07:45:36 +00007030 secondWindow->setDupTouchToWallpaper(true);
7031
7032 sp<FakeWindowHandle> wallpaper1 =
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07007033 sp<FakeWindowHandle>::make(application, mDispatcher, "Wallpaper1",
7034 ui::LogicalDisplayId::DEFAULT);
Arthur Hungc539dbb2022-12-08 07:45:36 +00007035 wallpaper1->setIsWallpaper(true);
7036
7037 sp<FakeWindowHandle> wallpaper2 =
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07007038 sp<FakeWindowHandle>::make(application, mDispatcher, "Wallpaper2",
7039 ui::LogicalDisplayId::DEFAULT);
Arthur Hungc539dbb2022-12-08 07:45:36 +00007040 wallpaper2->setIsWallpaper(true);
7041 // Add the windows to the dispatcher
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07007042 mDispatcher->onWindowInfosChanged({{*firstWindow->getInfo(), *wallpaper1->getInfo(),
7043 *secondWindow->getInfo(), *wallpaper2->getInfo()},
7044 {},
7045 0,
7046 0});
Arthur Hungc539dbb2022-12-08 07:45:36 +00007047
7048 // Send down to the first window
Prabir Pradhan678438e2023-04-13 19:32:51 +00007049 mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_DOWN,
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07007050 AINPUT_SOURCE_TOUCHSCREEN,
7051 ui::LogicalDisplayId::DEFAULT));
Arthur Hungc539dbb2022-12-08 07:45:36 +00007052
7053 // Only the first window should get the down event
7054 firstWindow->consumeMotionDown();
7055 secondWindow->assertNoEvents();
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07007056 wallpaper1->consumeMotionDown(ui::LogicalDisplayId::DEFAULT, EXPECTED_WALLPAPER_FLAGS);
Arthur Hungc539dbb2022-12-08 07:45:36 +00007057 wallpaper2->assertNoEvents();
7058
7059 // Transfer touch focus to the second window
7060 TransferFunction f = GetParam();
7061 bool success = f(mDispatcher, firstWindow->getToken(), secondWindow->getToken());
7062 ASSERT_TRUE(success);
7063
7064 // The first window gets cancel and the second gets down
7065 firstWindow->consumeMotionCancel();
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07007066 secondWindow->consumeMotionDown(ui::LogicalDisplayId::DEFAULT,
7067 AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
7068 wallpaper1->consumeMotionCancel(ui::LogicalDisplayId::DEFAULT, EXPECTED_WALLPAPER_FLAGS);
7069 wallpaper2->consumeMotionDown(ui::LogicalDisplayId::DEFAULT,
Linnan Li72352222024-04-12 18:55:57 +08007070 EXPECTED_WALLPAPER_FLAGS | AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
Arthur Hungc539dbb2022-12-08 07:45:36 +00007071
7072 // Send up event to the second window
Prabir Pradhan678438e2023-04-13 19:32:51 +00007073 mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN,
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07007074 ui::LogicalDisplayId::DEFAULT));
Arthur Hungc539dbb2022-12-08 07:45:36 +00007075 // The first window gets no events and the second gets up
7076 firstWindow->assertNoEvents();
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07007077 secondWindow->consumeMotionUp(ui::LogicalDisplayId::DEFAULT,
7078 AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
Arthur Hungc539dbb2022-12-08 07:45:36 +00007079 wallpaper1->assertNoEvents();
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07007080 wallpaper2->consumeMotionUp(ui::LogicalDisplayId::DEFAULT,
Linnan Li72352222024-04-12 18:55:57 +08007081 EXPECTED_WALLPAPER_FLAGS | AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
Arthur Hungc539dbb2022-12-08 07:45:36 +00007082}
7083
Siarhei Vishniakoud0c6bc82021-03-13 03:14:52 +00007084// For the cases of single pointer touch and two pointers non-split touch, the api's
Prabir Pradhan367f3432024-02-13 23:05:58 +00007085// 'transferTouchGesture' and 'transferTouchOnDisplay' are equivalent in behaviour. They only differ
Siarhei Vishniakoud0c6bc82021-03-13 03:14:52 +00007086// for the case where there are multiple pointers split across several windows.
Prabir Pradhan367f3432024-02-13 23:05:58 +00007087INSTANTIATE_TEST_SUITE_P(
7088 InputDispatcherTransferFunctionTests, TransferTouchFixture,
7089 ::testing::Values(
7090 [&](const std::unique_ptr<InputDispatcher>& dispatcher, sp<IBinder> /*ignored*/,
7091 sp<IBinder> destChannelToken) {
7092 return dispatcher->transferTouchOnDisplay(destChannelToken,
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07007093 ui::LogicalDisplayId::DEFAULT);
Prabir Pradhan367f3432024-02-13 23:05:58 +00007094 },
7095 [&](const std::unique_ptr<InputDispatcher>& dispatcher, sp<IBinder> from,
7096 sp<IBinder> to) {
7097 return dispatcher->transferTouchGesture(from, to,
7098 /*isDragAndDrop=*/false);
7099 }));
Siarhei Vishniakoud0c6bc82021-03-13 03:14:52 +00007100
Prabir Pradhan367f3432024-02-13 23:05:58 +00007101TEST_F(InputDispatcherTest, TransferTouch_TwoPointersSplitTouch) {
Chris Yea209fde2020-07-22 13:54:51 -07007102 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
Svet Ganov5d3bc372020-01-26 23:11:07 -08007103
Siarhei Vishniakou870ecec2020-12-09 08:07:46 -10007104 sp<FakeWindowHandle> firstWindow =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07007105 sp<FakeWindowHandle>::make(application, mDispatcher, "First Window",
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07007106 ui::LogicalDisplayId::DEFAULT);
Svet Ganov5d3bc372020-01-26 23:11:07 -08007107 firstWindow->setFrame(Rect(0, 0, 600, 400));
Svet Ganov5d3bc372020-01-26 23:11:07 -08007108
Siarhei Vishniakou870ecec2020-12-09 08:07:46 -10007109 sp<FakeWindowHandle> secondWindow =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07007110 sp<FakeWindowHandle>::make(application, mDispatcher, "Second Window",
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07007111 ui::LogicalDisplayId::DEFAULT);
Svet Ganov5d3bc372020-01-26 23:11:07 -08007112 secondWindow->setFrame(Rect(0, 400, 600, 800));
Svet Ganov5d3bc372020-01-26 23:11:07 -08007113
7114 // Add the windows to the dispatcher
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07007115 mDispatcher->onWindowInfosChanged(
7116 {{*firstWindow->getInfo(), *secondWindow->getInfo()}, {}, 0, 0});
Svet Ganov5d3bc372020-01-26 23:11:07 -08007117
7118 PointF pointInFirst = {300, 200};
7119 PointF pointInSecond = {300, 600};
7120
7121 // Send down to the first window
Prabir Pradhan678438e2023-04-13 19:32:51 +00007122 mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_DOWN,
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07007123 AINPUT_SOURCE_TOUCHSCREEN,
7124 ui::LogicalDisplayId::DEFAULT, {pointInFirst}));
Svet Ganov5d3bc372020-01-26 23:11:07 -08007125 // Only the first window should get the down event
7126 firstWindow->consumeMotionDown();
7127 secondWindow->assertNoEvents();
7128
7129 // Send down to the second window
Prabir Pradhan678438e2023-04-13 19:32:51 +00007130 mDispatcher->notifyMotion(generateMotionArgs(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN,
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07007131 ui::LogicalDisplayId::DEFAULT,
Prabir Pradhan678438e2023-04-13 19:32:51 +00007132 {pointInFirst, pointInSecond}));
Svet Ganov5d3bc372020-01-26 23:11:07 -08007133 // The first window gets a move and the second a down
7134 firstWindow->consumeMotionMove();
7135 secondWindow->consumeMotionDown();
7136
Prabir Pradhan367f3432024-02-13 23:05:58 +00007137 // Transfer touch to the second window
7138 mDispatcher->transferTouchGesture(firstWindow->getToken(), secondWindow->getToken());
Svet Ganov5d3bc372020-01-26 23:11:07 -08007139 // The first window gets cancel and the new gets pointer down (it already saw down)
7140 firstWindow->consumeMotionCancel();
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07007141 secondWindow->consumeMotionPointerDown(1, ui::LogicalDisplayId::DEFAULT,
Prabir Pradhan65455c72024-02-13 21:46:41 +00007142 AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
Svet Ganov5d3bc372020-01-26 23:11:07 -08007143
7144 // Send pointer up to the second window
Prabir Pradhan678438e2023-04-13 19:32:51 +00007145 mDispatcher->notifyMotion(generateMotionArgs(POINTER_1_UP, AINPUT_SOURCE_TOUCHSCREEN,
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07007146 ui::LogicalDisplayId::DEFAULT,
Prabir Pradhan678438e2023-04-13 19:32:51 +00007147 {pointInFirst, pointInSecond}));
Svet Ganov5d3bc372020-01-26 23:11:07 -08007148 // The first window gets nothing and the second gets pointer up
7149 firstWindow->assertNoEvents();
Prabir Pradhan33cfc6d2024-06-11 20:17:44 +00007150 secondWindow->consumeMotionPointerUp(/*pointerIdx=*/1,
7151 AllOf(WithDisplayId(ui::LogicalDisplayId::DEFAULT),
7152 WithFlags(AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE),
7153 WithPointerCount(2)));
Svet Ganov5d3bc372020-01-26 23:11:07 -08007154
7155 // Send up event to the second window
Prabir Pradhan678438e2023-04-13 19:32:51 +00007156 mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN,
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07007157 ui::LogicalDisplayId::DEFAULT));
Svet Ganov5d3bc372020-01-26 23:11:07 -08007158 // The first window gets nothing and the second gets up
7159 firstWindow->assertNoEvents();
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07007160 secondWindow->consumeMotionUp(ui::LogicalDisplayId::DEFAULT,
7161 AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
Svet Ganov5d3bc372020-01-26 23:11:07 -08007162}
7163
Prabir Pradhan367f3432024-02-13 23:05:58 +00007164// Same as TransferTouch_TwoPointersSplitTouch, but using 'transferTouchOnDisplay' api.
7165// Unlike 'transferTouchGesture', calling 'transferTouchOnDisplay' when there are two windows
7166// receiving touch is not supported, so the touch should continue on those windows and the
7167// transferred-to window should get nothing.
7168TEST_F(InputDispatcherTest, TransferTouchOnDisplay_TwoPointersSplitTouch) {
Siarhei Vishniakoud0c6bc82021-03-13 03:14:52 +00007169 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
7170
Siarhei Vishniakoud0c6bc82021-03-13 03:14:52 +00007171 sp<FakeWindowHandle> firstWindow =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07007172 sp<FakeWindowHandle>::make(application, mDispatcher, "First Window",
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07007173 ui::LogicalDisplayId::DEFAULT);
Siarhei Vishniakoud0c6bc82021-03-13 03:14:52 +00007174 firstWindow->setFrame(Rect(0, 0, 600, 400));
Siarhei Vishniakoud0c6bc82021-03-13 03:14:52 +00007175
Siarhei Vishniakoud0c6bc82021-03-13 03:14:52 +00007176 sp<FakeWindowHandle> secondWindow =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07007177 sp<FakeWindowHandle>::make(application, mDispatcher, "Second Window",
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07007178 ui::LogicalDisplayId::DEFAULT);
Siarhei Vishniakoud0c6bc82021-03-13 03:14:52 +00007179 secondWindow->setFrame(Rect(0, 400, 600, 800));
Siarhei Vishniakoud0c6bc82021-03-13 03:14:52 +00007180
7181 // Add the windows to the dispatcher
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07007182 mDispatcher->onWindowInfosChanged(
7183 {{*firstWindow->getInfo(), *secondWindow->getInfo()}, {}, 0, 0});
Siarhei Vishniakoud0c6bc82021-03-13 03:14:52 +00007184
7185 PointF pointInFirst = {300, 200};
7186 PointF pointInSecond = {300, 600};
7187
7188 // Send down to the first window
Prabir Pradhan678438e2023-04-13 19:32:51 +00007189 mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_DOWN,
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07007190 AINPUT_SOURCE_TOUCHSCREEN,
7191 ui::LogicalDisplayId::DEFAULT, {pointInFirst}));
Siarhei Vishniakoud0c6bc82021-03-13 03:14:52 +00007192 // Only the first window should get the down event
7193 firstWindow->consumeMotionDown();
7194 secondWindow->assertNoEvents();
7195
7196 // Send down to the second window
Prabir Pradhan678438e2023-04-13 19:32:51 +00007197 mDispatcher->notifyMotion(generateMotionArgs(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN,
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07007198 ui::LogicalDisplayId::DEFAULT,
Prabir Pradhan678438e2023-04-13 19:32:51 +00007199 {pointInFirst, pointInSecond}));
Siarhei Vishniakoud0c6bc82021-03-13 03:14:52 +00007200 // The first window gets a move and the second a down
7201 firstWindow->consumeMotionMove();
7202 secondWindow->consumeMotionDown();
7203
7204 // Transfer touch focus to the second window
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07007205 const bool transferred = mDispatcher->transferTouchOnDisplay(secondWindow->getToken(),
7206 ui::LogicalDisplayId::DEFAULT);
Prabir Pradhan367f3432024-02-13 23:05:58 +00007207 // The 'transferTouchOnDisplay' call should not succeed, because there are 2 touched windows
Siarhei Vishniakoud0c6bc82021-03-13 03:14:52 +00007208 ASSERT_FALSE(transferred);
7209 firstWindow->assertNoEvents();
7210 secondWindow->assertNoEvents();
7211
7212 // The rest of the dispatch should proceed as normal
7213 // Send pointer up to the second window
Prabir Pradhan678438e2023-04-13 19:32:51 +00007214 mDispatcher->notifyMotion(generateMotionArgs(POINTER_1_UP, AINPUT_SOURCE_TOUCHSCREEN,
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07007215 ui::LogicalDisplayId::DEFAULT,
Prabir Pradhan678438e2023-04-13 19:32:51 +00007216 {pointInFirst, pointInSecond}));
Siarhei Vishniakoud0c6bc82021-03-13 03:14:52 +00007217 // The first window gets MOVE and the second gets pointer up
7218 firstWindow->consumeMotionMove();
7219 secondWindow->consumeMotionUp();
7220
7221 // Send up event to the first window
Prabir Pradhan678438e2023-04-13 19:32:51 +00007222 mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN,
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07007223 ui::LogicalDisplayId::DEFAULT));
Siarhei Vishniakoud0c6bc82021-03-13 03:14:52 +00007224 // The first window gets nothing and the second gets up
7225 firstWindow->consumeMotionUp();
7226 secondWindow->assertNoEvents();
7227}
7228
Arthur Hungabbb9d82021-09-01 14:52:30 +00007229// This case will create two windows and one mirrored window on the default display and mirror
Prabir Pradhan367f3432024-02-13 23:05:58 +00007230// two windows on the second display. It will test if 'transferTouchGesture' works fine if we put
Arthur Hungabbb9d82021-09-01 14:52:30 +00007231// the windows info of second display before default display.
Prabir Pradhan367f3432024-02-13 23:05:58 +00007232TEST_F(InputDispatcherTest, TransferTouch_CloneSurface) {
Arthur Hungabbb9d82021-09-01 14:52:30 +00007233 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
7234 sp<FakeWindowHandle> firstWindowInPrimary =
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07007235 sp<FakeWindowHandle>::make(application, mDispatcher, "D_1_W1",
7236 ui::LogicalDisplayId::DEFAULT);
Arthur Hungabbb9d82021-09-01 14:52:30 +00007237 firstWindowInPrimary->setFrame(Rect(0, 0, 100, 100));
Arthur Hungabbb9d82021-09-01 14:52:30 +00007238 sp<FakeWindowHandle> secondWindowInPrimary =
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07007239 sp<FakeWindowHandle>::make(application, mDispatcher, "D_1_W2",
7240 ui::LogicalDisplayId::DEFAULT);
Arthur Hungabbb9d82021-09-01 14:52:30 +00007241 secondWindowInPrimary->setFrame(Rect(100, 0, 200, 100));
Arthur Hungabbb9d82021-09-01 14:52:30 +00007242
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07007243 sp<FakeWindowHandle> mirrorWindowInPrimary =
7244 firstWindowInPrimary->clone(ui::LogicalDisplayId::DEFAULT);
Arthur Hungabbb9d82021-09-01 14:52:30 +00007245 mirrorWindowInPrimary->setFrame(Rect(0, 100, 100, 200));
Arthur Hungabbb9d82021-09-01 14:52:30 +00007246
Siarhei Vishniakouadb9fc92023-05-26 10:46:09 -07007247 sp<FakeWindowHandle> firstWindowInSecondary = firstWindowInPrimary->clone(SECOND_DISPLAY_ID);
Arthur Hungabbb9d82021-09-01 14:52:30 +00007248 firstWindowInSecondary->setFrame(Rect(0, 0, 100, 100));
Arthur Hungabbb9d82021-09-01 14:52:30 +00007249
Siarhei Vishniakouadb9fc92023-05-26 10:46:09 -07007250 sp<FakeWindowHandle> secondWindowInSecondary = secondWindowInPrimary->clone(SECOND_DISPLAY_ID);
Arthur Hungabbb9d82021-09-01 14:52:30 +00007251 secondWindowInPrimary->setFrame(Rect(100, 0, 200, 100));
Arthur Hungabbb9d82021-09-01 14:52:30 +00007252
7253 // Update window info, let it find window handle of second display first.
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07007254 mDispatcher->onWindowInfosChanged(
7255 {{*firstWindowInSecondary->getInfo(), *secondWindowInSecondary->getInfo(),
7256 *mirrorWindowInPrimary->getInfo(), *firstWindowInPrimary->getInfo(),
7257 *secondWindowInPrimary->getInfo()},
7258 {},
7259 0,
7260 0});
Arthur Hungabbb9d82021-09-01 14:52:30 +00007261
7262 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07007263 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN,
7264 ui::LogicalDisplayId::DEFAULT, {50, 50}))
Arthur Hungabbb9d82021-09-01 14:52:30 +00007265 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
7266
7267 // Window should receive motion event.
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07007268 firstWindowInPrimary->consumeMotionDown(ui::LogicalDisplayId::DEFAULT);
Arthur Hungabbb9d82021-09-01 14:52:30 +00007269
Prabir Pradhan367f3432024-02-13 23:05:58 +00007270 // Transfer touch
7271 ASSERT_TRUE(mDispatcher->transferTouchGesture(firstWindowInPrimary->getToken(),
7272 secondWindowInPrimary->getToken()));
Arthur Hungabbb9d82021-09-01 14:52:30 +00007273 // The first window gets cancel.
7274 firstWindowInPrimary->consumeMotionCancel();
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07007275 secondWindowInPrimary->consumeMotionDown(ui::LogicalDisplayId::DEFAULT,
Prabir Pradhan65455c72024-02-13 21:46:41 +00007276 AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
Arthur Hungabbb9d82021-09-01 14:52:30 +00007277
7278 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07007279 injectMotionEvent(*mDispatcher, AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN,
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07007280 ui::LogicalDisplayId::DEFAULT, {150, 50}))
Arthur Hungabbb9d82021-09-01 14:52:30 +00007281 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
7282 firstWindowInPrimary->assertNoEvents();
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07007283 secondWindowInPrimary->consumeMotionMove(ui::LogicalDisplayId::DEFAULT,
Prabir Pradhan65455c72024-02-13 21:46:41 +00007284 AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
Arthur Hungabbb9d82021-09-01 14:52:30 +00007285
7286 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07007287 injectMotionUp(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ui::LogicalDisplayId::DEFAULT,
Arthur Hungabbb9d82021-09-01 14:52:30 +00007288 {150, 50}))
7289 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
7290 firstWindowInPrimary->assertNoEvents();
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07007291 secondWindowInPrimary->consumeMotionUp(ui::LogicalDisplayId::DEFAULT,
7292 AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
Arthur Hungabbb9d82021-09-01 14:52:30 +00007293}
7294
Prabir Pradhan367f3432024-02-13 23:05:58 +00007295// Same as TransferTouch_CloneSurface, but this touch on the secondary display and use
7296// 'transferTouchOnDisplay' api.
7297TEST_F(InputDispatcherTest, TransferTouchOnDisplay_CloneSurface) {
Arthur Hungabbb9d82021-09-01 14:52:30 +00007298 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
7299 sp<FakeWindowHandle> firstWindowInPrimary =
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07007300 sp<FakeWindowHandle>::make(application, mDispatcher, "D_1_W1",
7301 ui::LogicalDisplayId::DEFAULT);
Arthur Hungabbb9d82021-09-01 14:52:30 +00007302 firstWindowInPrimary->setFrame(Rect(0, 0, 100, 100));
Arthur Hungabbb9d82021-09-01 14:52:30 +00007303 sp<FakeWindowHandle> secondWindowInPrimary =
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07007304 sp<FakeWindowHandle>::make(application, mDispatcher, "D_1_W2",
7305 ui::LogicalDisplayId::DEFAULT);
Arthur Hungabbb9d82021-09-01 14:52:30 +00007306 secondWindowInPrimary->setFrame(Rect(100, 0, 200, 100));
Arthur Hungabbb9d82021-09-01 14:52:30 +00007307
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07007308 sp<FakeWindowHandle> mirrorWindowInPrimary =
7309 firstWindowInPrimary->clone(ui::LogicalDisplayId::DEFAULT);
Arthur Hungabbb9d82021-09-01 14:52:30 +00007310 mirrorWindowInPrimary->setFrame(Rect(0, 100, 100, 200));
Arthur Hungabbb9d82021-09-01 14:52:30 +00007311
Siarhei Vishniakouadb9fc92023-05-26 10:46:09 -07007312 sp<FakeWindowHandle> firstWindowInSecondary = firstWindowInPrimary->clone(SECOND_DISPLAY_ID);
Arthur Hungabbb9d82021-09-01 14:52:30 +00007313 firstWindowInSecondary->setFrame(Rect(0, 0, 100, 100));
Arthur Hungabbb9d82021-09-01 14:52:30 +00007314
Siarhei Vishniakouadb9fc92023-05-26 10:46:09 -07007315 sp<FakeWindowHandle> secondWindowInSecondary = secondWindowInPrimary->clone(SECOND_DISPLAY_ID);
Arthur Hungabbb9d82021-09-01 14:52:30 +00007316 secondWindowInPrimary->setFrame(Rect(100, 0, 200, 100));
Arthur Hungabbb9d82021-09-01 14:52:30 +00007317
7318 // Update window info, let it find window handle of second display first.
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07007319 mDispatcher->onWindowInfosChanged(
7320 {{*firstWindowInSecondary->getInfo(), *secondWindowInSecondary->getInfo(),
7321 *mirrorWindowInPrimary->getInfo(), *firstWindowInPrimary->getInfo(),
7322 *secondWindowInPrimary->getInfo()},
7323 {},
7324 0,
7325 0});
Arthur Hungabbb9d82021-09-01 14:52:30 +00007326
7327 // Touch on second display.
7328 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07007329 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, SECOND_DISPLAY_ID,
7330 {50, 50}))
Arthur Hungabbb9d82021-09-01 14:52:30 +00007331 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
7332
7333 // Window should receive motion event.
Prabir Pradhanbb3f1c02024-01-04 20:17:14 +00007334 firstWindowInSecondary->consumeMotionDown(SECOND_DISPLAY_ID);
Arthur Hungabbb9d82021-09-01 14:52:30 +00007335
7336 // Transfer touch focus
Prabir Pradhan367f3432024-02-13 23:05:58 +00007337 ASSERT_TRUE(mDispatcher->transferTouchOnDisplay(secondWindowInSecondary->getToken(),
7338 SECOND_DISPLAY_ID));
Arthur Hungabbb9d82021-09-01 14:52:30 +00007339
7340 // The first window gets cancel.
Prabir Pradhanbb3f1c02024-01-04 20:17:14 +00007341 firstWindowInSecondary->consumeMotionCancel(SECOND_DISPLAY_ID);
Prabir Pradhan65455c72024-02-13 21:46:41 +00007342 secondWindowInSecondary->consumeMotionDown(SECOND_DISPLAY_ID,
7343 AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
Arthur Hungabbb9d82021-09-01 14:52:30 +00007344
7345 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07007346 injectMotionEvent(*mDispatcher, AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN,
Arthur Hungabbb9d82021-09-01 14:52:30 +00007347 SECOND_DISPLAY_ID, {150, 50}))
7348 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
Prabir Pradhanbb3f1c02024-01-04 20:17:14 +00007349 firstWindowInSecondary->assertNoEvents();
Prabir Pradhan65455c72024-02-13 21:46:41 +00007350 secondWindowInSecondary->consumeMotionMove(SECOND_DISPLAY_ID,
7351 AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
Arthur Hungabbb9d82021-09-01 14:52:30 +00007352
7353 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07007354 injectMotionUp(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, SECOND_DISPLAY_ID, {150, 50}))
Arthur Hungabbb9d82021-09-01 14:52:30 +00007355 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
Prabir Pradhanbb3f1c02024-01-04 20:17:14 +00007356 firstWindowInSecondary->assertNoEvents();
Prabir Pradhan65455c72024-02-13 21:46:41 +00007357 secondWindowInSecondary->consumeMotionUp(SECOND_DISPLAY_ID, AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
Arthur Hungabbb9d82021-09-01 14:52:30 +00007358}
7359
Siarhei Vishniakouf1035d42019-09-20 16:32:01 +01007360TEST_F(InputDispatcherTest, FocusedWindow_ReceivesFocusEventAndKeyEvent) {
Chris Yea209fde2020-07-22 13:54:51 -07007361 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07007362 sp<FakeWindowHandle> window =
7363 sp<FakeWindowHandle>::make(application, mDispatcher, "Fake Window",
7364 ui::LogicalDisplayId::DEFAULT);
Siarhei Vishniakouf1035d42019-09-20 16:32:01 +01007365
Vishnu Nair47074b82020-08-14 11:54:47 -07007366 window->setFocusable(true);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07007367 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Vishnu Nair958da932020-08-21 17:12:37 -07007368 setFocusedWindow(window);
Siarhei Vishniakouf1035d42019-09-20 16:32:01 +01007369
7370 window->consumeFocusEvent(true);
7371
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07007372 mDispatcher->notifyKey(generateKeyArgs(AKEY_EVENT_ACTION_DOWN, ui::LogicalDisplayId::DEFAULT));
Siarhei Vishniakouf1035d42019-09-20 16:32:01 +01007373
7374 // Window should receive key down event.
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07007375 window->consumeKeyDown(ui::LogicalDisplayId::DEFAULT);
Josep del Riob3981622023-04-18 15:49:45 +00007376
7377 // Should have poked user activity
Siarhei Vishniakou4fd86732023-05-24 17:33:01 +00007378 mDispatcher->waitForIdle();
Josep del Riob3981622023-04-18 15:49:45 +00007379 mFakePolicy->assertUserActivityPoked();
7380}
7381
7382TEST_F(InputDispatcherTest, FocusedWindow_DisableUserActivity) {
7383 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07007384 sp<FakeWindowHandle> window =
7385 sp<FakeWindowHandle>::make(application, mDispatcher, "Fake Window",
7386 ui::LogicalDisplayId::DEFAULT);
Josep del Riob3981622023-04-18 15:49:45 +00007387
7388 window->setDisableUserActivity(true);
7389 window->setFocusable(true);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07007390 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Josep del Riob3981622023-04-18 15:49:45 +00007391 setFocusedWindow(window);
7392
7393 window->consumeFocusEvent(true);
7394
Josep del Rioc8fdedb2024-05-21 13:32:43 +00007395 mDispatcher->notifyKey(
7396 KeyArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_KEYBOARD).keyCode(AKEYCODE_A).build());
Josep del Riob3981622023-04-18 15:49:45 +00007397
7398 // Window should receive key down event.
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07007399 window->consumeKeyDown(ui::LogicalDisplayId::DEFAULT);
Josep del Riob3981622023-04-18 15:49:45 +00007400
Josep del Rioc8fdedb2024-05-21 13:32:43 +00007401 // Should have not poked user activity
Siarhei Vishniakou4fd86732023-05-24 17:33:01 +00007402 mDispatcher->waitForIdle();
Josep del Riob3981622023-04-18 15:49:45 +00007403 mFakePolicy->assertUserActivityNotPoked();
7404}
7405
Josep del Rioc8fdedb2024-05-21 13:32:43 +00007406TEST_F(InputDispatcherTest, FocusedWindow_DoesNotReceivePolicyConsumedKey) {
Josep del Riob3981622023-04-18 15:49:45 +00007407 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07007408 sp<FakeWindowHandle> window =
7409 sp<FakeWindowHandle>::make(application, mDispatcher, "Fake Window",
7410 ui::LogicalDisplayId::DEFAULT);
Josep del Riob3981622023-04-18 15:49:45 +00007411
7412 window->setFocusable(true);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07007413 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Josep del Riob3981622023-04-18 15:49:45 +00007414 setFocusedWindow(window);
7415
7416 window->consumeFocusEvent(true);
7417
Josep del Rioc8fdedb2024-05-21 13:32:43 +00007418 mFakePolicy->setConsumeKeyBeforeDispatching(true);
7419
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07007420 mDispatcher->notifyKey(
Josep del Rioc8fdedb2024-05-21 13:32:43 +00007421 KeyArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_KEYBOARD).keyCode(AKEYCODE_A).build());
Josep del Riob3981622023-04-18 15:49:45 +00007422 mDispatcher->waitForIdle();
7423
Josep del Rioc8fdedb2024-05-21 13:32:43 +00007424 // Key is not passed down
Josep del Riob3981622023-04-18 15:49:45 +00007425 window->assertNoEvents();
7426
7427 // Should have poked user activity
7428 mFakePolicy->assertUserActivityPoked();
7429}
7430
Josep del Rioc8fdedb2024-05-21 13:32:43 +00007431TEST_F(InputDispatcherTest, FocusedWindow_PolicyConsumedKeyIgnoresDisableUserActivity) {
Josep del Riob3981622023-04-18 15:49:45 +00007432 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07007433 sp<FakeWindowHandle> window =
7434 sp<FakeWindowHandle>::make(application, mDispatcher, "Fake Window",
7435 ui::LogicalDisplayId::DEFAULT);
Josep del Riob3981622023-04-18 15:49:45 +00007436
7437 window->setDisableUserActivity(true);
7438 window->setFocusable(true);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07007439 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Josep del Riob3981622023-04-18 15:49:45 +00007440 setFocusedWindow(window);
7441
7442 window->consumeFocusEvent(true);
7443
Josep del Rioc8fdedb2024-05-21 13:32:43 +00007444 mFakePolicy->setConsumeKeyBeforeDispatching(true);
7445
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07007446 mDispatcher->notifyKey(
Josep del Rioc8fdedb2024-05-21 13:32:43 +00007447 KeyArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_KEYBOARD).keyCode(AKEYCODE_A).build());
Josep del Riob3981622023-04-18 15:49:45 +00007448 mDispatcher->waitForIdle();
7449
7450 // System key is not passed down
7451 window->assertNoEvents();
7452
7453 // Should have poked user activity
7454 mFakePolicy->assertUserActivityPoked();
Siarhei Vishniakouf1035d42019-09-20 16:32:01 +01007455}
7456
Josep del Rioc8fdedb2024-05-21 13:32:43 +00007457class DisableUserActivityInputDispatcherTest : public InputDispatcherTest,
7458 public ::testing::WithParamInterface<bool> {};
7459
7460TEST_P(DisableUserActivityInputDispatcherTest, NotPassedToUserUserActivity) {
7461 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
7462 sp<FakeWindowHandle> window =
7463 sp<FakeWindowHandle>::make(application, mDispatcher, "Fake Window",
7464 ui::LogicalDisplayId::DEFAULT);
7465
7466 window->setDisableUserActivity(GetParam());
7467
7468 window->setFocusable(true);
7469 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
7470 setFocusedWindow(window);
7471
7472 window->consumeFocusEvent(true);
7473
7474 mDispatcher->notifyKey(KeyArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_KEYBOARD)
7475 .keyCode(AKEYCODE_A)
7476 .policyFlags(0)
7477 .build());
7478 mDispatcher->waitForIdle();
7479
7480 // Key is not passed down
7481 window->assertNoEvents();
7482
7483 // Should not have poked user activity
7484 mFakePolicy->assertUserActivityNotPoked();
7485}
7486
7487INSTANTIATE_TEST_CASE_P(DisableUserActivity, DisableUserActivityInputDispatcherTest,
7488 ::testing::Bool());
7489
Siarhei Vishniakou90ee4782023-05-08 11:57:24 -07007490TEST_F(InputDispatcherTest, InjectedTouchesPokeUserActivity) {
7491 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07007492 sp<FakeWindowHandle> window =
7493 sp<FakeWindowHandle>::make(application, mDispatcher, "Fake Window",
7494 ui::LogicalDisplayId::DEFAULT);
Siarhei Vishniakou90ee4782023-05-08 11:57:24 -07007495
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07007496 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Siarhei Vishniakou90ee4782023-05-08 11:57:24 -07007497
7498 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07007499 injectMotionEvent(*mDispatcher, AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN,
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07007500 ui::LogicalDisplayId::DEFAULT, {100, 100}))
Siarhei Vishniakou90ee4782023-05-08 11:57:24 -07007501 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
7502
7503 window->consumeMotionEvent(
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07007504 AllOf(WithMotionAction(ACTION_DOWN), WithDisplayId(ui::LogicalDisplayId::DEFAULT)));
Siarhei Vishniakou90ee4782023-05-08 11:57:24 -07007505
7506 // Should have poked user activity
Siarhei Vishniakou4fd86732023-05-24 17:33:01 +00007507 mDispatcher->waitForIdle();
Siarhei Vishniakou90ee4782023-05-08 11:57:24 -07007508 mFakePolicy->assertUserActivityPoked();
7509}
7510
Siarhei Vishniakouf1035d42019-09-20 16:32:01 +01007511TEST_F(InputDispatcherTest, UnfocusedWindow_DoesNotReceiveFocusEventOrKeyEvent) {
Chris Yea209fde2020-07-22 13:54:51 -07007512 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07007513 sp<FakeWindowHandle> window =
7514 sp<FakeWindowHandle>::make(application, mDispatcher, "Fake Window",
7515 ui::LogicalDisplayId::DEFAULT);
Siarhei Vishniakouf1035d42019-09-20 16:32:01 +01007516
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07007517 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Siarhei Vishniakouf1035d42019-09-20 16:32:01 +01007518
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07007519 mDispatcher->notifyKey(generateKeyArgs(AKEY_EVENT_ACTION_DOWN, ui::LogicalDisplayId::DEFAULT));
Siarhei Vishniakouf1035d42019-09-20 16:32:01 +01007520 mDispatcher->waitForIdle();
7521
7522 window->assertNoEvents();
7523}
7524
7525// If a window is touchable, but does not have focus, it should receive motion events, but not keys
7526TEST_F(InputDispatcherTest, UnfocusedWindow_ReceivesMotionsButNotKeys) {
Chris Yea209fde2020-07-22 13:54:51 -07007527 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07007528 sp<FakeWindowHandle> window =
7529 sp<FakeWindowHandle>::make(application, mDispatcher, "Fake Window",
7530 ui::LogicalDisplayId::DEFAULT);
Siarhei Vishniakouf1035d42019-09-20 16:32:01 +01007531
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07007532 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Siarhei Vishniakouf1035d42019-09-20 16:32:01 +01007533
7534 // Send key
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07007535 mDispatcher->notifyKey(generateKeyArgs(AKEY_EVENT_ACTION_DOWN, ui::LogicalDisplayId::DEFAULT));
Siarhei Vishniakouf1035d42019-09-20 16:32:01 +01007536 // Send motion
Prabir Pradhan678438e2023-04-13 19:32:51 +00007537 mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_DOWN,
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07007538 AINPUT_SOURCE_TOUCHSCREEN,
7539 ui::LogicalDisplayId::DEFAULT));
Siarhei Vishniakouf1035d42019-09-20 16:32:01 +01007540
7541 // Window should receive only the motion event
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07007542 window->consumeMotionDown(ui::LogicalDisplayId::DEFAULT);
Siarhei Vishniakouf1035d42019-09-20 16:32:01 +01007543 window->assertNoEvents(); // Key event or focus event will not be received
7544}
7545
arthurhungea3f4fc2020-12-21 23:18:53 +08007546TEST_F(InputDispatcherTest, PointerCancel_SendCancelWhenSplitTouch) {
7547 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
7548
arthurhungea3f4fc2020-12-21 23:18:53 +08007549 sp<FakeWindowHandle> firstWindow =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07007550 sp<FakeWindowHandle>::make(application, mDispatcher, "First Window",
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07007551 ui::LogicalDisplayId::DEFAULT);
arthurhungea3f4fc2020-12-21 23:18:53 +08007552 firstWindow->setFrame(Rect(0, 0, 600, 400));
arthurhungea3f4fc2020-12-21 23:18:53 +08007553
arthurhungea3f4fc2020-12-21 23:18:53 +08007554 sp<FakeWindowHandle> secondWindow =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07007555 sp<FakeWindowHandle>::make(application, mDispatcher, "Second Window",
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07007556 ui::LogicalDisplayId::DEFAULT);
arthurhungea3f4fc2020-12-21 23:18:53 +08007557 secondWindow->setFrame(Rect(0, 400, 600, 800));
arthurhungea3f4fc2020-12-21 23:18:53 +08007558
7559 // Add the windows to the dispatcher
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07007560 mDispatcher->onWindowInfosChanged(
7561 {{*firstWindow->getInfo(), *secondWindow->getInfo()}, {}, 0, 0});
arthurhungea3f4fc2020-12-21 23:18:53 +08007562
7563 PointF pointInFirst = {300, 200};
7564 PointF pointInSecond = {300, 600};
7565
7566 // Send down to the first window
Prabir Pradhan678438e2023-04-13 19:32:51 +00007567 mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_DOWN,
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07007568 AINPUT_SOURCE_TOUCHSCREEN,
7569 ui::LogicalDisplayId::DEFAULT, {pointInFirst}));
arthurhungea3f4fc2020-12-21 23:18:53 +08007570 // Only the first window should get the down event
7571 firstWindow->consumeMotionDown();
7572 secondWindow->assertNoEvents();
7573
7574 // Send down to the second window
Prabir Pradhan678438e2023-04-13 19:32:51 +00007575 mDispatcher->notifyMotion(generateMotionArgs(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN,
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07007576 ui::LogicalDisplayId::DEFAULT,
Prabir Pradhan678438e2023-04-13 19:32:51 +00007577 {pointInFirst, pointInSecond}));
arthurhungea3f4fc2020-12-21 23:18:53 +08007578 // The first window gets a move and the second a down
7579 firstWindow->consumeMotionMove();
7580 secondWindow->consumeMotionDown();
7581
7582 // Send pointer cancel to the second window
7583 NotifyMotionArgs pointerUpMotionArgs =
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07007584 generateMotionArgs(POINTER_1_UP, AINPUT_SOURCE_TOUCHSCREEN,
7585 ui::LogicalDisplayId::DEFAULT, {pointInFirst, pointInSecond});
arthurhungea3f4fc2020-12-21 23:18:53 +08007586 pointerUpMotionArgs.flags |= AMOTION_EVENT_FLAG_CANCELED;
Prabir Pradhan678438e2023-04-13 19:32:51 +00007587 mDispatcher->notifyMotion(pointerUpMotionArgs);
arthurhungea3f4fc2020-12-21 23:18:53 +08007588 // The first window gets move and the second gets cancel.
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07007589 firstWindow->consumeMotionMove(ui::LogicalDisplayId::DEFAULT, AMOTION_EVENT_FLAG_CANCELED);
7590 secondWindow->consumeMotionCancel(ui::LogicalDisplayId::DEFAULT, AMOTION_EVENT_FLAG_CANCELED);
arthurhungea3f4fc2020-12-21 23:18:53 +08007591
7592 // Send up event.
Prabir Pradhan678438e2023-04-13 19:32:51 +00007593 mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN,
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07007594 ui::LogicalDisplayId::DEFAULT));
arthurhungea3f4fc2020-12-21 23:18:53 +08007595 // The first window gets up and the second gets nothing.
7596 firstWindow->consumeMotionUp();
7597 secondWindow->assertNoEvents();
7598}
7599
Siarhei Vishniakouf94ae022021-02-04 01:23:17 +00007600TEST_F(InputDispatcherTest, SendTimeline_DoesNotCrashDispatcher) {
7601 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
7602
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07007603 sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher, "Window",
7604 ui::LogicalDisplayId::DEFAULT);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07007605 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Siarhei Vishniakouf94ae022021-02-04 01:23:17 +00007606 std::array<nsecs_t, GraphicsTimeline::SIZE> graphicsTimeline;
7607 graphicsTimeline[GraphicsTimeline::GPU_COMPLETED_TIME] = 2;
7608 graphicsTimeline[GraphicsTimeline::PRESENT_TIME] = 3;
7609
Harry Cutts33476232023-01-30 19:57:29 +00007610 window->sendTimeline(/*inputEventId=*/1, graphicsTimeline);
Siarhei Vishniakouf94ae022021-02-04 01:23:17 +00007611 window->assertNoEvents();
7612 mDispatcher->waitForIdle();
7613}
7614
Prabir Pradhan1376fcd2022-01-21 09:56:35 -08007615using InputDispatcherMonitorTest = InputDispatcherTest;
7616
Siarhei Vishniakouca205502021-07-16 21:31:58 +00007617/**
7618 * Two entities that receive touch: A window, and a global monitor.
7619 * The touch goes to the window, and then the window disappears.
7620 * The monitor does not get cancel right away. But if more events come in, the touch gets canceled
7621 * for the monitor, as well.
7622 * 1. foregroundWindow
7623 * 2. monitor <-- global monitor (doesn't observe z order, receives all events)
7624 */
Prabir Pradhan1376fcd2022-01-21 09:56:35 -08007625TEST_F(InputDispatcherMonitorTest, MonitorTouchIsCanceledWhenForegroundWindowDisappears) {
Siarhei Vishniakouca205502021-07-16 21:31:58 +00007626 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07007627 sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher, "Foreground",
7628 ui::LogicalDisplayId::DEFAULT);
Siarhei Vishniakouca205502021-07-16 21:31:58 +00007629
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07007630 FakeMonitorReceiver monitor =
7631 FakeMonitorReceiver(*mDispatcher, "M_1", ui::LogicalDisplayId::DEFAULT);
Siarhei Vishniakouca205502021-07-16 21:31:58 +00007632
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07007633 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Siarhei Vishniakouca205502021-07-16 21:31:58 +00007634 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07007635 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN,
7636 ui::LogicalDisplayId::DEFAULT, {100, 200}))
Siarhei Vishniakouca205502021-07-16 21:31:58 +00007637 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
7638
7639 // Both the foreground window and the global monitor should receive the touch down
7640 window->consumeMotionDown();
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07007641 monitor.consumeMotionDown(ui::LogicalDisplayId::DEFAULT);
Siarhei Vishniakouca205502021-07-16 21:31:58 +00007642
7643 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07007644 injectMotionEvent(*mDispatcher, AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN,
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07007645 ui::LogicalDisplayId::DEFAULT, {110, 200}))
Siarhei Vishniakouca205502021-07-16 21:31:58 +00007646 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
7647
7648 window->consumeMotionMove();
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07007649 monitor.consumeMotionMove(ui::LogicalDisplayId::DEFAULT);
Siarhei Vishniakouca205502021-07-16 21:31:58 +00007650
7651 // Now the foreground window goes away
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07007652 mDispatcher->onWindowInfosChanged({{}, {}, 0, 0});
Siarhei Vishniakouca205502021-07-16 21:31:58 +00007653 window->consumeMotionCancel();
7654 monitor.assertNoEvents(); // Global monitor does not get a cancel yet
7655
7656 // If more events come in, there will be no more foreground window to send them to. This will
7657 // cause a cancel for the monitor, as well.
7658 ASSERT_EQ(InputEventInjectionResult::FAILED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07007659 injectMotionEvent(*mDispatcher, AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN,
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07007660 ui::LogicalDisplayId::DEFAULT, {120, 200}))
Siarhei Vishniakouca205502021-07-16 21:31:58 +00007661 << "Injection should fail because the window was removed";
7662 window->assertNoEvents();
7663 // Global monitor now gets the cancel
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07007664 monitor.consumeMotionCancel(ui::LogicalDisplayId::DEFAULT);
Siarhei Vishniakouca205502021-07-16 21:31:58 +00007665}
7666
Prabir Pradhan1376fcd2022-01-21 09:56:35 -08007667TEST_F(InputDispatcherMonitorTest, ReceivesMotionEvents) {
Chris Yea209fde2020-07-22 13:54:51 -07007668 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07007669 sp<FakeWindowHandle> window =
7670 sp<FakeWindowHandle>::make(application, mDispatcher, "Fake Window",
7671 ui::LogicalDisplayId::DEFAULT);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07007672 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Michael Wright3a240c42019-12-10 20:53:41 +00007673
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07007674 FakeMonitorReceiver monitor =
7675 FakeMonitorReceiver(*mDispatcher, "M_1", ui::LogicalDisplayId::DEFAULT);
Michael Wright3a240c42019-12-10 20:53:41 +00007676
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08007677 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07007678 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN,
7679 ui::LogicalDisplayId::DEFAULT))
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08007680 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07007681 window->consumeMotionDown(ui::LogicalDisplayId::DEFAULT);
7682 monitor.consumeMotionDown(ui::LogicalDisplayId::DEFAULT);
Michael Wright3a240c42019-12-10 20:53:41 +00007683}
7684
Prabir Pradhan1376fcd2022-01-21 09:56:35 -08007685TEST_F(InputDispatcherMonitorTest, MonitorCannotPilferPointers) {
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07007686 FakeMonitorReceiver monitor =
7687 FakeMonitorReceiver(*mDispatcher, "M_1", ui::LogicalDisplayId::DEFAULT);
Michael Wright3a240c42019-12-10 20:53:41 +00007688
Chris Yea209fde2020-07-22 13:54:51 -07007689 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07007690 sp<FakeWindowHandle> window =
7691 sp<FakeWindowHandle>::make(application, mDispatcher, "Fake Window",
7692 ui::LogicalDisplayId::DEFAULT);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07007693 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Michael Wright3a240c42019-12-10 20:53:41 +00007694
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08007695 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07007696 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN,
7697 ui::LogicalDisplayId::DEFAULT))
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08007698 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07007699 monitor.consumeMotionDown(ui::LogicalDisplayId::DEFAULT);
7700 window->consumeMotionDown(ui::LogicalDisplayId::DEFAULT);
Michael Wright3a240c42019-12-10 20:53:41 +00007701
Prabir Pradhan1376fcd2022-01-21 09:56:35 -08007702 // Pilfer pointers from the monitor.
7703 // This should not do anything and the window should continue to receive events.
7704 EXPECT_NE(OK, mDispatcher->pilferPointers(monitor.getToken()));
Michael Wright3a240c42019-12-10 20:53:41 +00007705
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08007706 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07007707 injectMotionEvent(*mDispatcher, AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN,
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07007708 ui::LogicalDisplayId::DEFAULT))
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08007709 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
Prabir Pradhan1376fcd2022-01-21 09:56:35 -08007710
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07007711 monitor.consumeMotionMove(ui::LogicalDisplayId::DEFAULT);
7712 window->consumeMotionMove(ui::LogicalDisplayId::DEFAULT);
Michael Wright3a240c42019-12-10 20:53:41 +00007713}
7714
Prabir Pradhan1376fcd2022-01-21 09:56:35 -08007715TEST_F(InputDispatcherMonitorTest, NoWindowTransform) {
Evan Rosky84f07f02021-04-16 10:42:42 -07007716 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07007717 sp<FakeWindowHandle> window =
7718 sp<FakeWindowHandle>::make(application, mDispatcher, "Fake Window",
7719 ui::LogicalDisplayId::DEFAULT);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07007720 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Evan Rosky84f07f02021-04-16 10:42:42 -07007721 window->setWindowOffset(20, 40);
7722 window->setWindowTransform(0, 1, -1, 0);
7723
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07007724 FakeMonitorReceiver monitor =
7725 FakeMonitorReceiver(*mDispatcher, "M_1", ui::LogicalDisplayId::DEFAULT);
Evan Rosky84f07f02021-04-16 10:42:42 -07007726
7727 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07007728 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN,
7729 ui::LogicalDisplayId::DEFAULT))
Evan Rosky84f07f02021-04-16 10:42:42 -07007730 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07007731 window->consumeMotionDown(ui::LogicalDisplayId::DEFAULT);
Siarhei Vishniakoud3061ab2023-12-18 20:41:08 -08007732 std::unique_ptr<MotionEvent> event = monitor.consumeMotion();
7733 ASSERT_NE(nullptr, event);
Evan Rosky84f07f02021-04-16 10:42:42 -07007734 // Even though window has transform, gesture monitor must not.
7735 ASSERT_EQ(ui::Transform(), event->getTransform());
7736}
7737
Prabir Pradhan1376fcd2022-01-21 09:56:35 -08007738TEST_F(InputDispatcherMonitorTest, InjectionFailsWithNoWindow) {
Arthur Hungb3307ee2021-10-14 10:57:37 +00007739 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07007740 FakeMonitorReceiver monitor =
7741 FakeMonitorReceiver(*mDispatcher, "M_1", ui::LogicalDisplayId::DEFAULT);
Arthur Hungb3307ee2021-10-14 10:57:37 +00007742
Prabir Pradhan1376fcd2022-01-21 09:56:35 -08007743 ASSERT_EQ(InputEventInjectionResult::FAILED,
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07007744 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN,
7745 ui::LogicalDisplayId::DEFAULT))
Prabir Pradhan1376fcd2022-01-21 09:56:35 -08007746 << "Injection should fail if there is a monitor, but no touchable window";
7747 monitor.assertNoEvents();
Arthur Hungb3307ee2021-10-14 10:57:37 +00007748}
7749
Linnan Lid8150952024-01-26 18:07:17 +00007750/**
7751 * Two displays
7752 * The first monitor has a foreground window, a monitor
7753 * The second window has only one monitor.
7754 * We first inject a Down event into the first display, this injection should succeed and both
7755 * the foreground window and monitor should receive a down event, then inject a Down event into
7756 * the second display as well, this injection should fail, at this point, the first display
7757 * window and monitor should not receive a cancel or any other event.
7758 * Continue to inject Move and UP events to the first display, the events should be received
7759 * normally by the foreground window and monitor.
7760 */
7761TEST_F(InputDispatcherMonitorTest, MonitorTouchIsNotCanceledWhenAnotherEmptyDisplayReceiveEvents) {
7762 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07007763 sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher, "Foreground",
7764 ui::LogicalDisplayId::DEFAULT);
Linnan Lid8150952024-01-26 18:07:17 +00007765
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07007766 FakeMonitorReceiver monitor =
7767 FakeMonitorReceiver(*mDispatcher, "M_1", ui::LogicalDisplayId::DEFAULT);
Linnan Lid8150952024-01-26 18:07:17 +00007768 FakeMonitorReceiver secondMonitor = FakeMonitorReceiver(*mDispatcher, "M_2", SECOND_DISPLAY_ID);
7769
7770 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
7771 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07007772 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN,
7773 ui::LogicalDisplayId::DEFAULT, {100, 200}))
Linnan Lid8150952024-01-26 18:07:17 +00007774 << "The down event injected into the first display should succeed";
7775
7776 window->consumeMotionDown();
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07007777 monitor.consumeMotionDown(ui::LogicalDisplayId::DEFAULT);
Linnan Lid8150952024-01-26 18:07:17 +00007778
7779 ASSERT_EQ(InputEventInjectionResult::FAILED,
7780 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, SECOND_DISPLAY_ID,
7781 {100, 200}))
Prabir Pradhana0d43d42024-01-30 00:27:08 +00007782 << "The down event injected into the second display should fail since there's no "
7783 "touchable window";
Linnan Lid8150952024-01-26 18:07:17 +00007784
7785 // Continue to inject event to first display.
7786 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
7787 injectMotionEvent(*mDispatcher, AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN,
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07007788 ui::LogicalDisplayId::DEFAULT, {110, 220}))
Linnan Lid8150952024-01-26 18:07:17 +00007789 << "The move event injected into the first display should succeed";
7790
7791 window->consumeMotionMove();
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07007792 monitor.consumeMotionMove(ui::LogicalDisplayId::DEFAULT);
Linnan Lid8150952024-01-26 18:07:17 +00007793
7794 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07007795 injectMotionUp(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ui::LogicalDisplayId::DEFAULT,
Linnan Lid8150952024-01-26 18:07:17 +00007796 {110, 220}))
7797 << "The up event injected into the first display should succeed";
7798
7799 window->consumeMotionUp();
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07007800 monitor.consumeMotionUp(ui::LogicalDisplayId::DEFAULT);
Prabir Pradhana0d43d42024-01-30 00:27:08 +00007801
7802 window->assertNoEvents();
7803 monitor.assertNoEvents();
Linnan Lid8150952024-01-26 18:07:17 +00007804 secondMonitor.assertNoEvents();
7805}
7806
7807/**
7808 * Two displays
7809 * There is a monitor and foreground window on each display.
7810 * First, we inject down events into each of the two displays, at this point, the foreground windows
7811 * and monitors on both displays should receive down events.
7812 * At this point, the foreground window of the second display goes away, the gone window should
7813 * receive the cancel event, and the other windows and monitors should not receive any events.
7814 * Inject a move event into the second display. At this point, the injection should fail because
7815 * the second display no longer has a foreground window. At this point, the monitor on the second
7816 * display should receive a cancel event, and any windows or monitors on the first display should
7817 * not receive any events, and any subsequent injection of events into the second display should
7818 * also fail.
7819 * Continue to inject events into the first display, and the events should all be injected
7820 * successfully and received normally.
7821 */
7822TEST_F(InputDispatcherMonitorTest, MonitorTouchIsNotCancelWhenAnotherDisplayMonitorTouchCanceled) {
7823 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07007824 sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher, "Foreground",
7825 ui::LogicalDisplayId::DEFAULT);
Linnan Lid8150952024-01-26 18:07:17 +00007826 sp<FakeWindowHandle> secondWindow =
7827 sp<FakeWindowHandle>::make(application, mDispatcher, "SecondForeground",
7828 SECOND_DISPLAY_ID);
7829
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07007830 FakeMonitorReceiver monitor =
7831 FakeMonitorReceiver(*mDispatcher, "M_1", ui::LogicalDisplayId::DEFAULT);
Linnan Lid8150952024-01-26 18:07:17 +00007832 FakeMonitorReceiver secondMonitor = FakeMonitorReceiver(*mDispatcher, "M_2", SECOND_DISPLAY_ID);
7833
7834 // There is a foreground window on both displays.
7835 mDispatcher->onWindowInfosChanged({{*window->getInfo(), *secondWindow->getInfo()}, {}, 0, 0});
7836 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07007837 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN,
7838 ui::LogicalDisplayId::DEFAULT, {100, 200}))
Linnan Lid8150952024-01-26 18:07:17 +00007839 << "The down event injected into the first display should succeed";
7840
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07007841 window->consumeMotionDown(ui::LogicalDisplayId::DEFAULT);
7842 monitor.consumeMotionDown(ui::LogicalDisplayId::DEFAULT);
Linnan Lid8150952024-01-26 18:07:17 +00007843
7844 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
7845 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, SECOND_DISPLAY_ID,
7846 {100, 200}))
7847 << "The down event injected into the second display should succeed";
7848
Linnan Lid8150952024-01-26 18:07:17 +00007849 secondWindow->consumeMotionDown(SECOND_DISPLAY_ID);
7850 secondMonitor.consumeMotionDown(SECOND_DISPLAY_ID);
7851
7852 // Now second window is gone away.
7853 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
7854
7855 // The gone window should receive a cancel, and the monitor on the second display should not
7856 // receive any events.
Linnan Lid8150952024-01-26 18:07:17 +00007857 secondWindow->consumeMotionCancel(SECOND_DISPLAY_ID);
7858 secondMonitor.assertNoEvents();
7859
7860 ASSERT_EQ(InputEventInjectionResult::FAILED,
7861 injectMotionEvent(*mDispatcher, AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN,
7862 SECOND_DISPLAY_ID, {110, 220}))
Prabir Pradhana0d43d42024-01-30 00:27:08 +00007863 << "The move event injected into the second display should fail because there's no "
7864 "touchable window";
Linnan Lid8150952024-01-26 18:07:17 +00007865 // Now the monitor on the second display should receive a cancel event.
7866 secondMonitor.consumeMotionCancel(SECOND_DISPLAY_ID);
Linnan Lid8150952024-01-26 18:07:17 +00007867
7868 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
7869 injectMotionEvent(*mDispatcher, AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN,
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07007870 ui::LogicalDisplayId::DEFAULT, {110, 200}))
Linnan Lid8150952024-01-26 18:07:17 +00007871 << "The move event injected into the first display should succeed";
7872
7873 window->consumeMotionMove();
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07007874 monitor.consumeMotionMove(ui::LogicalDisplayId::DEFAULT);
Linnan Lid8150952024-01-26 18:07:17 +00007875
7876 ASSERT_EQ(InputEventInjectionResult::FAILED,
Prabir Pradhana0d43d42024-01-30 00:27:08 +00007877 injectMotionUp(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, SECOND_DISPLAY_ID,
7878 {110, 220}))
7879 << "The up event injected into the second display should fail because there's no "
7880 "touchable window";
Linnan Lid8150952024-01-26 18:07:17 +00007881
7882 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07007883 injectMotionUp(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ui::LogicalDisplayId::DEFAULT,
Linnan Lid8150952024-01-26 18:07:17 +00007884 {110, 220}))
7885 << "The up event injected into the first display should succeed";
7886
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07007887 window->consumeMotionUp(ui::LogicalDisplayId::DEFAULT);
7888 monitor.consumeMotionUp(ui::LogicalDisplayId::DEFAULT);
Prabir Pradhana0d43d42024-01-30 00:27:08 +00007889
Linnan Lid8150952024-01-26 18:07:17 +00007890 window->assertNoEvents();
7891 monitor.assertNoEvents();
Prabir Pradhana0d43d42024-01-30 00:27:08 +00007892 secondWindow->assertNoEvents();
7893 secondMonitor.assertNoEvents();
Linnan Lid8150952024-01-26 18:07:17 +00007894}
7895
7896/**
7897 * One display with transform
7898 * There is a foreground window and a monitor on the display
7899 * Inject down event and move event sequentially, the foreground window and monitor can receive down
7900 * event and move event, then let the foreground window go away, the foreground window receives
7901 * cancel event, inject move event again, the monitor receives cancel event, all the events received
7902 * by the monitor should be with the same transform as the display
7903 */
7904TEST_F(InputDispatcherMonitorTest, MonitorTouchCancelEventWithDisplayTransform) {
7905 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07007906 sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher, "Foreground",
7907 ui::LogicalDisplayId::DEFAULT);
7908 FakeMonitorReceiver monitor =
7909 FakeMonitorReceiver(*mDispatcher, "M_1", ui::LogicalDisplayId::DEFAULT);
Linnan Lid8150952024-01-26 18:07:17 +00007910
7911 ui::Transform transform;
7912 transform.set({1.1, 2.2, 3.3, 4.4, 5.5, 6.6, 0, 0, 1});
7913
7914 gui::DisplayInfo displayInfo;
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07007915 displayInfo.displayId = ui::LogicalDisplayId::DEFAULT;
Linnan Lid8150952024-01-26 18:07:17 +00007916 displayInfo.transform = transform;
7917
7918 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {displayInfo}, 0, 0});
7919
7920 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07007921 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN,
7922 ui::LogicalDisplayId::DEFAULT, {100, 200}))
Linnan Lid8150952024-01-26 18:07:17 +00007923 << "The down event injected should succeed";
7924
7925 window->consumeMotionDown();
7926 std::unique_ptr<MotionEvent> downMotionEvent = monitor.consumeMotion();
7927 EXPECT_EQ(transform, downMotionEvent->getTransform());
7928 EXPECT_EQ(AMOTION_EVENT_ACTION_DOWN, downMotionEvent->getAction());
7929
7930 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
7931 injectMotionEvent(*mDispatcher, AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN,
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07007932 ui::LogicalDisplayId::DEFAULT, {110, 220}))
Linnan Lid8150952024-01-26 18:07:17 +00007933 << "The move event injected should succeed";
7934
7935 window->consumeMotionMove();
7936 std::unique_ptr<MotionEvent> moveMotionEvent = monitor.consumeMotion();
7937 EXPECT_EQ(transform, moveMotionEvent->getTransform());
7938 EXPECT_EQ(AMOTION_EVENT_ACTION_MOVE, moveMotionEvent->getAction());
7939
7940 // Let foreground window gone
7941 mDispatcher->onWindowInfosChanged({{}, {displayInfo}, 0, 0});
7942
Prabir Pradhana0d43d42024-01-30 00:27:08 +00007943 // Foreground window should receive a cancel event, but not the monitor.
Linnan Lid8150952024-01-26 18:07:17 +00007944 window->consumeMotionCancel();
Linnan Lid8150952024-01-26 18:07:17 +00007945
7946 ASSERT_EQ(InputEventInjectionResult::FAILED,
7947 injectMotionEvent(*mDispatcher, AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN,
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07007948 ui::LogicalDisplayId::DEFAULT, {110, 220}))
Linnan Lid8150952024-01-26 18:07:17 +00007949 << "The move event injected should failed";
7950 // Now foreground should not receive any events, but monitor should receive a cancel event
7951 // with transform that same as display's display.
Linnan Lid8150952024-01-26 18:07:17 +00007952 std::unique_ptr<MotionEvent> cancelMotionEvent = monitor.consumeMotion();
7953 EXPECT_EQ(transform, cancelMotionEvent->getTransform());
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07007954 EXPECT_EQ(ui::LogicalDisplayId::DEFAULT, cancelMotionEvent->getDisplayId());
Linnan Lid8150952024-01-26 18:07:17 +00007955 EXPECT_EQ(AMOTION_EVENT_ACTION_CANCEL, cancelMotionEvent->getAction());
7956
7957 // Other event inject to this display should fail.
7958 ASSERT_EQ(InputEventInjectionResult::FAILED,
7959 injectMotionEvent(*mDispatcher, AMOTION_EVENT_ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN,
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07007960 ui::LogicalDisplayId::DEFAULT, {110, 220}))
Prabir Pradhana0d43d42024-01-30 00:27:08 +00007961 << "The up event injected should fail because the touched window was removed";
Linnan Lid8150952024-01-26 18:07:17 +00007962 window->assertNoEvents();
7963 monitor.assertNoEvents();
7964}
7965
chaviw81e2bb92019-12-18 15:03:51 -08007966TEST_F(InputDispatcherTest, TestMoveEvent) {
Chris Yea209fde2020-07-22 13:54:51 -07007967 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07007968 sp<FakeWindowHandle> window =
7969 sp<FakeWindowHandle>::make(application, mDispatcher, "Fake Window",
7970 ui::LogicalDisplayId::DEFAULT);
chaviw81e2bb92019-12-18 15:03:51 -08007971
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07007972 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
chaviw81e2bb92019-12-18 15:03:51 -08007973
7974 NotifyMotionArgs motionArgs =
7975 generateMotionArgs(AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN,
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07007976 ui::LogicalDisplayId::DEFAULT);
chaviw81e2bb92019-12-18 15:03:51 -08007977
Prabir Pradhan678438e2023-04-13 19:32:51 +00007978 mDispatcher->notifyMotion(motionArgs);
chaviw81e2bb92019-12-18 15:03:51 -08007979 // Window should receive motion down event.
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07007980 window->consumeMotionDown(ui::LogicalDisplayId::DEFAULT);
chaviw81e2bb92019-12-18 15:03:51 -08007981
7982 motionArgs.action = AMOTION_EVENT_ACTION_MOVE;
Garfield Tanc51d1ba2020-01-28 13:24:04 -08007983 motionArgs.id += 1;
chaviw81e2bb92019-12-18 15:03:51 -08007984 motionArgs.eventTime = systemTime(SYSTEM_TIME_MONOTONIC);
7985 motionArgs.pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_X,
7986 motionArgs.pointerCoords[0].getX() - 10);
7987
Prabir Pradhan678438e2023-04-13 19:32:51 +00007988 mDispatcher->notifyMotion(motionArgs);
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07007989 window->consumeMotionMove(ui::LogicalDisplayId::DEFAULT, /*expectedFlags=*/0);
chaviw81e2bb92019-12-18 15:03:51 -08007990}
7991
Siarhei Vishniakouf1035d42019-09-20 16:32:01 +01007992/**
7993 * Dispatcher has touch mode enabled by default. Typically, the policy overrides that value to
7994 * the device default right away. In the test scenario, we check both the default value,
7995 * and the action of enabling / disabling.
7996 */
7997TEST_F(InputDispatcherTest, TouchModeState_IsSentToApps) {
Chris Yea209fde2020-07-22 13:54:51 -07007998 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07007999 sp<FakeWindowHandle> window =
8000 sp<FakeWindowHandle>::make(application, mDispatcher, "Test window",
8001 ui::LogicalDisplayId::DEFAULT);
Antonio Kantekea47acb2021-12-23 12:41:25 -08008002 const WindowInfo& windowInfo = *window->getInfo();
Siarhei Vishniakouf1035d42019-09-20 16:32:01 +01008003
8004 // Set focused application.
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07008005 mDispatcher->setFocusedApplication(ui::LogicalDisplayId::DEFAULT, application);
Vishnu Nair47074b82020-08-14 11:54:47 -07008006 window->setFocusable(true);
Siarhei Vishniakouf1035d42019-09-20 16:32:01 +01008007
8008 SCOPED_TRACE("Check default value of touch mode");
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07008009 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Vishnu Nair958da932020-08-21 17:12:37 -07008010 setFocusedWindow(window);
Harry Cutts33476232023-01-30 19:57:29 +00008011 window->consumeFocusEvent(/*hasFocus=*/true, /*inTouchMode=*/true);
Siarhei Vishniakouf1035d42019-09-20 16:32:01 +01008012
8013 SCOPED_TRACE("Remove the window to trigger focus loss");
Vishnu Nair47074b82020-08-14 11:54:47 -07008014 window->setFocusable(false);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07008015 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Harry Cutts33476232023-01-30 19:57:29 +00008016 window->consumeFocusEvent(/*hasFocus=*/false, /*inTouchMode=*/true);
Siarhei Vishniakouf1035d42019-09-20 16:32:01 +01008017
8018 SCOPED_TRACE("Disable touch mode");
Antonio Kantekea47acb2021-12-23 12:41:25 -08008019 mDispatcher->setInTouchMode(false, windowInfo.ownerPid, windowInfo.ownerUid,
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07008020 /*hasPermission=*/true, ui::LogicalDisplayId::DEFAULT);
Antonio Kantekf16f2832021-09-28 04:39:20 +00008021 window->consumeTouchModeEvent(false);
Vishnu Nair47074b82020-08-14 11:54:47 -07008022 window->setFocusable(true);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07008023 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Vishnu Nair958da932020-08-21 17:12:37 -07008024 setFocusedWindow(window);
Harry Cutts33476232023-01-30 19:57:29 +00008025 window->consumeFocusEvent(/*hasFocus=*/true, /*inTouchMode=*/false);
Siarhei Vishniakouf1035d42019-09-20 16:32:01 +01008026
8027 SCOPED_TRACE("Remove the window to trigger focus loss");
Vishnu Nair47074b82020-08-14 11:54:47 -07008028 window->setFocusable(false);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07008029 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Harry Cutts33476232023-01-30 19:57:29 +00008030 window->consumeFocusEvent(/*hasFocus=*/false, /*inTouchMode=*/false);
Siarhei Vishniakouf1035d42019-09-20 16:32:01 +01008031
8032 SCOPED_TRACE("Enable touch mode again");
Antonio Kantekea47acb2021-12-23 12:41:25 -08008033 mDispatcher->setInTouchMode(true, windowInfo.ownerPid, windowInfo.ownerUid,
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07008034 /*hasPermission=*/true, ui::LogicalDisplayId::DEFAULT);
Antonio Kantekf16f2832021-09-28 04:39:20 +00008035 window->consumeTouchModeEvent(true);
Vishnu Nair47074b82020-08-14 11:54:47 -07008036 window->setFocusable(true);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07008037 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Vishnu Nair958da932020-08-21 17:12:37 -07008038 setFocusedWindow(window);
Harry Cutts33476232023-01-30 19:57:29 +00008039 window->consumeFocusEvent(/*hasFocus=*/true, /*inTouchMode=*/true);
Siarhei Vishniakouf1035d42019-09-20 16:32:01 +01008040
8041 window->assertNoEvents();
8042}
8043
Gang Wange9087892020-01-07 12:17:14 -05008044TEST_F(InputDispatcherTest, VerifyInputEvent_KeyEvent) {
Chris Yea209fde2020-07-22 13:54:51 -07008045 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07008046 sp<FakeWindowHandle> window =
8047 sp<FakeWindowHandle>::make(application, mDispatcher, "Test window",
8048 ui::LogicalDisplayId::DEFAULT);
Gang Wange9087892020-01-07 12:17:14 -05008049
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07008050 mDispatcher->setFocusedApplication(ui::LogicalDisplayId::DEFAULT, application);
Vishnu Nair47074b82020-08-14 11:54:47 -07008051 window->setFocusable(true);
Gang Wange9087892020-01-07 12:17:14 -05008052
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07008053 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Vishnu Nair958da932020-08-21 17:12:37 -07008054 setFocusedWindow(window);
8055
Harry Cutts33476232023-01-30 19:57:29 +00008056 window->consumeFocusEvent(/*hasFocus=*/true, /*inTouchMode=*/true);
Gang Wange9087892020-01-07 12:17:14 -05008057
Prabir Pradhan678438e2023-04-13 19:32:51 +00008058 const NotifyKeyArgs keyArgs = generateKeyArgs(AKEY_EVENT_ACTION_DOWN);
8059 mDispatcher->notifyKey(keyArgs);
Gang Wange9087892020-01-07 12:17:14 -05008060
Siarhei Vishniakoud3061ab2023-12-18 20:41:08 -08008061 std::unique_ptr<KeyEvent> event = window->consumeKey();
8062 ASSERT_NE(event, nullptr);
8063 std::unique_ptr<VerifiedInputEvent> verified = mDispatcher->verifyInputEvent(*event);
Gang Wange9087892020-01-07 12:17:14 -05008064 ASSERT_NE(verified, nullptr);
8065 ASSERT_EQ(verified->type, VerifiedInputEvent::Type::KEY);
8066
8067 ASSERT_EQ(keyArgs.eventTime, verified->eventTimeNanos);
8068 ASSERT_EQ(keyArgs.deviceId, verified->deviceId);
8069 ASSERT_EQ(keyArgs.source, verified->source);
8070 ASSERT_EQ(keyArgs.displayId, verified->displayId);
8071
8072 const VerifiedKeyEvent& verifiedKey = static_cast<const VerifiedKeyEvent&>(*verified);
8073
8074 ASSERT_EQ(keyArgs.action, verifiedKey.action);
Gang Wange9087892020-01-07 12:17:14 -05008075 ASSERT_EQ(keyArgs.flags & VERIFIED_KEY_EVENT_FLAGS, verifiedKey.flags);
Siarhei Vishniakouf355bf92021-12-09 10:43:21 -08008076 ASSERT_EQ(keyArgs.downTime, verifiedKey.downTimeNanos);
Gang Wange9087892020-01-07 12:17:14 -05008077 ASSERT_EQ(keyArgs.keyCode, verifiedKey.keyCode);
8078 ASSERT_EQ(keyArgs.scanCode, verifiedKey.scanCode);
8079 ASSERT_EQ(keyArgs.metaState, verifiedKey.metaState);
8080 ASSERT_EQ(0, verifiedKey.repeatCount);
8081}
8082
Siarhei Vishniakou47040bf2020-02-28 15:03:13 -08008083TEST_F(InputDispatcherTest, VerifyInputEvent_MotionEvent) {
Chris Yea209fde2020-07-22 13:54:51 -07008084 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07008085 sp<FakeWindowHandle> window =
8086 sp<FakeWindowHandle>::make(application, mDispatcher, "Test window",
8087 ui::LogicalDisplayId::DEFAULT);
Siarhei Vishniakou47040bf2020-02-28 15:03:13 -08008088
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07008089 mDispatcher->setFocusedApplication(ui::LogicalDisplayId::DEFAULT, application);
Siarhei Vishniakou47040bf2020-02-28 15:03:13 -08008090
Prabir Pradhanb5cb9572021-09-24 06:35:16 -07008091 ui::Transform transform;
8092 transform.set({1.1, 2.2, 3.3, 4.4, 5.5, 6.6, 0, 0, 1});
8093
8094 gui::DisplayInfo displayInfo;
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07008095 displayInfo.displayId = ui::LogicalDisplayId::DEFAULT;
Prabir Pradhanb5cb9572021-09-24 06:35:16 -07008096 displayInfo.transform = transform;
8097
Patrick Williamsd828f302023-04-28 17:52:08 -05008098 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {displayInfo}, 0, 0});
Siarhei Vishniakou47040bf2020-02-28 15:03:13 -08008099
Prabir Pradhan678438e2023-04-13 19:32:51 +00008100 const NotifyMotionArgs motionArgs =
Siarhei Vishniakou47040bf2020-02-28 15:03:13 -08008101 generateMotionArgs(AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN,
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07008102 ui::LogicalDisplayId::DEFAULT);
Prabir Pradhan678438e2023-04-13 19:32:51 +00008103 mDispatcher->notifyMotion(motionArgs);
Siarhei Vishniakou47040bf2020-02-28 15:03:13 -08008104
Siarhei Vishniakoud3061ab2023-12-18 20:41:08 -08008105 std::unique_ptr<MotionEvent> event = window->consumeMotionEvent();
8106 ASSERT_NE(nullptr, event);
8107 std::unique_ptr<VerifiedInputEvent> verified = mDispatcher->verifyInputEvent(*event);
Siarhei Vishniakou47040bf2020-02-28 15:03:13 -08008108 ASSERT_NE(verified, nullptr);
8109 ASSERT_EQ(verified->type, VerifiedInputEvent::Type::MOTION);
8110
8111 EXPECT_EQ(motionArgs.eventTime, verified->eventTimeNanos);
8112 EXPECT_EQ(motionArgs.deviceId, verified->deviceId);
8113 EXPECT_EQ(motionArgs.source, verified->source);
8114 EXPECT_EQ(motionArgs.displayId, verified->displayId);
8115
8116 const VerifiedMotionEvent& verifiedMotion = static_cast<const VerifiedMotionEvent&>(*verified);
8117
Prabir Pradhanb5cb9572021-09-24 06:35:16 -07008118 const vec2 rawXY =
8119 MotionEvent::calculateTransformedXY(motionArgs.source, transform,
8120 motionArgs.pointerCoords[0].getXYValue());
8121 EXPECT_EQ(rawXY.x, verifiedMotion.rawX);
8122 EXPECT_EQ(rawXY.y, verifiedMotion.rawY);
Siarhei Vishniakou47040bf2020-02-28 15:03:13 -08008123 EXPECT_EQ(motionArgs.action & AMOTION_EVENT_ACTION_MASK, verifiedMotion.actionMasked);
Siarhei Vishniakou47040bf2020-02-28 15:03:13 -08008124 EXPECT_EQ(motionArgs.flags & VERIFIED_MOTION_EVENT_FLAGS, verifiedMotion.flags);
Siarhei Vishniakouf355bf92021-12-09 10:43:21 -08008125 EXPECT_EQ(motionArgs.downTime, verifiedMotion.downTimeNanos);
Siarhei Vishniakou47040bf2020-02-28 15:03:13 -08008126 EXPECT_EQ(motionArgs.metaState, verifiedMotion.metaState);
8127 EXPECT_EQ(motionArgs.buttonState, verifiedMotion.buttonState);
8128}
8129
chaviw09c8d2d2020-08-24 15:48:26 -07008130/**
8131 * Ensure that separate calls to sign the same data are generating the same key.
8132 * We avoid asserting against INVALID_HMAC. Since the key is random, there is a non-zero chance
8133 * that a specific key and data combination would produce INVALID_HMAC, which would cause flaky
8134 * tests.
8135 */
8136TEST_F(InputDispatcherTest, GeneratedHmac_IsConsistent) {
8137 KeyEvent event = getTestKeyEvent();
8138 VerifiedKeyEvent verifiedEvent = verifiedKeyEventFromKeyEvent(event);
8139
8140 std::array<uint8_t, 32> hmac1 = mDispatcher->sign(verifiedEvent);
8141 std::array<uint8_t, 32> hmac2 = mDispatcher->sign(verifiedEvent);
8142 ASSERT_EQ(hmac1, hmac2);
8143}
8144
8145/**
8146 * Ensure that changes in VerifiedKeyEvent produce a different hmac.
8147 */
8148TEST_F(InputDispatcherTest, GeneratedHmac_ChangesWhenFieldsChange) {
8149 KeyEvent event = getTestKeyEvent();
8150 VerifiedKeyEvent verifiedEvent = verifiedKeyEventFromKeyEvent(event);
8151 std::array<uint8_t, 32> initialHmac = mDispatcher->sign(verifiedEvent);
8152
8153 verifiedEvent.deviceId += 1;
8154 ASSERT_NE(initialHmac, mDispatcher->sign(verifiedEvent));
8155
8156 verifiedEvent.source += 1;
8157 ASSERT_NE(initialHmac, mDispatcher->sign(verifiedEvent));
8158
8159 verifiedEvent.eventTimeNanos += 1;
8160 ASSERT_NE(initialHmac, mDispatcher->sign(verifiedEvent));
8161
Linnan Li13bf76a2024-05-05 19:18:02 +08008162 verifiedEvent.displayId = ui::LogicalDisplayId{verifiedEvent.displayId.val() + 1};
chaviw09c8d2d2020-08-24 15:48:26 -07008163 ASSERT_NE(initialHmac, mDispatcher->sign(verifiedEvent));
8164
8165 verifiedEvent.action += 1;
8166 ASSERT_NE(initialHmac, mDispatcher->sign(verifiedEvent));
8167
8168 verifiedEvent.downTimeNanos += 1;
8169 ASSERT_NE(initialHmac, mDispatcher->sign(verifiedEvent));
8170
8171 verifiedEvent.flags += 1;
8172 ASSERT_NE(initialHmac, mDispatcher->sign(verifiedEvent));
8173
8174 verifiedEvent.keyCode += 1;
8175 ASSERT_NE(initialHmac, mDispatcher->sign(verifiedEvent));
8176
8177 verifiedEvent.scanCode += 1;
8178 ASSERT_NE(initialHmac, mDispatcher->sign(verifiedEvent));
8179
8180 verifiedEvent.metaState += 1;
8181 ASSERT_NE(initialHmac, mDispatcher->sign(verifiedEvent));
8182
8183 verifiedEvent.repeatCount += 1;
8184 ASSERT_NE(initialHmac, mDispatcher->sign(verifiedEvent));
8185}
8186
Vishnu Nair958da932020-08-21 17:12:37 -07008187TEST_F(InputDispatcherTest, SetFocusedWindow) {
8188 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07008189 sp<FakeWindowHandle> windowTop = sp<FakeWindowHandle>::make(application, mDispatcher, "Top",
8190 ui::LogicalDisplayId::DEFAULT);
Vishnu Nair958da932020-08-21 17:12:37 -07008191 sp<FakeWindowHandle> windowSecond =
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07008192 sp<FakeWindowHandle>::make(application, mDispatcher, "Second",
8193 ui::LogicalDisplayId::DEFAULT);
8194 mDispatcher->setFocusedApplication(ui::LogicalDisplayId::DEFAULT, application);
Vishnu Nair958da932020-08-21 17:12:37 -07008195
8196 // Top window is also focusable but is not granted focus.
8197 windowTop->setFocusable(true);
8198 windowSecond->setFocusable(true);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07008199 mDispatcher->onWindowInfosChanged(
8200 {{*windowTop->getInfo(), *windowSecond->getInfo()}, {}, 0, 0});
Vishnu Nair958da932020-08-21 17:12:37 -07008201 setFocusedWindow(windowSecond);
8202
8203 windowSecond->consumeFocusEvent(true);
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07008204 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectKeyDown(*mDispatcher))
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08008205 << "Inject key event should return InputEventInjectionResult::SUCCEEDED";
Vishnu Nair958da932020-08-21 17:12:37 -07008206
8207 // Focused window should receive event.
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07008208 windowSecond->consumeKeyDown(ui::LogicalDisplayId::INVALID);
Vishnu Nair958da932020-08-21 17:12:37 -07008209 windowTop->assertNoEvents();
8210}
8211
8212TEST_F(InputDispatcherTest, SetFocusedWindow_DropRequestInvalidChannel) {
8213 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07008214 sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher, "TestWindow",
8215 ui::LogicalDisplayId::DEFAULT);
8216 mDispatcher->setFocusedApplication(ui::LogicalDisplayId::DEFAULT, application);
Vishnu Nair958da932020-08-21 17:12:37 -07008217
8218 window->setFocusable(true);
8219 // Release channel for window is no longer valid.
8220 window->releaseChannel();
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07008221 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Vishnu Nair958da932020-08-21 17:12:37 -07008222 setFocusedWindow(window);
8223
8224 // Test inject a key down, should timeout.
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07008225 ASSERT_NO_FATAL_FAILURE(assertInjectedKeyTimesOut(*mDispatcher));
Vishnu Nair958da932020-08-21 17:12:37 -07008226
8227 // window channel is invalid, so it should not receive any input event.
8228 window->assertNoEvents();
8229}
8230
8231TEST_F(InputDispatcherTest, SetFocusedWindow_DropRequestNoFocusableWindow) {
8232 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07008233 sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher, "TestWindow",
8234 ui::LogicalDisplayId::DEFAULT);
Prabir Pradhan76bdecb2022-01-31 11:14:15 -08008235 window->setFocusable(false);
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07008236 mDispatcher->setFocusedApplication(ui::LogicalDisplayId::DEFAULT, application);
Vishnu Nair958da932020-08-21 17:12:37 -07008237
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07008238 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Vishnu Nair958da932020-08-21 17:12:37 -07008239 setFocusedWindow(window);
8240
8241 // Test inject a key down, should timeout.
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07008242 ASSERT_NO_FATAL_FAILURE(assertInjectedKeyTimesOut(*mDispatcher));
Vishnu Nair958da932020-08-21 17:12:37 -07008243
Prabir Pradhan76bdecb2022-01-31 11:14:15 -08008244 // window is not focusable, so it should not receive any input event.
Vishnu Nair958da932020-08-21 17:12:37 -07008245 window->assertNoEvents();
8246}
8247
8248TEST_F(InputDispatcherTest, SetFocusedWindow_CheckFocusedToken) {
8249 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07008250 sp<FakeWindowHandle> windowTop = sp<FakeWindowHandle>::make(application, mDispatcher, "Top",
8251 ui::LogicalDisplayId::DEFAULT);
Vishnu Nair958da932020-08-21 17:12:37 -07008252 sp<FakeWindowHandle> windowSecond =
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07008253 sp<FakeWindowHandle>::make(application, mDispatcher, "Second",
8254 ui::LogicalDisplayId::DEFAULT);
8255 mDispatcher->setFocusedApplication(ui::LogicalDisplayId::DEFAULT, application);
Vishnu Nair958da932020-08-21 17:12:37 -07008256
8257 windowTop->setFocusable(true);
8258 windowSecond->setFocusable(true);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07008259 mDispatcher->onWindowInfosChanged(
8260 {{*windowTop->getInfo(), *windowSecond->getInfo()}, {}, 0, 0});
Vishnu Nair958da932020-08-21 17:12:37 -07008261 setFocusedWindow(windowTop);
8262 windowTop->consumeFocusEvent(true);
8263
Chavi Weingarten847e8512023-03-29 00:26:09 +00008264 windowTop->editInfo()->focusTransferTarget = windowSecond->getToken();
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07008265 mDispatcher->onWindowInfosChanged(
8266 {{*windowTop->getInfo(), *windowSecond->getInfo()}, {}, 0, 0});
Vishnu Nair958da932020-08-21 17:12:37 -07008267 windowSecond->consumeFocusEvent(true);
8268 windowTop->consumeFocusEvent(false);
8269
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07008270 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectKeyDown(*mDispatcher))
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08008271 << "Inject key event should return InputEventInjectionResult::SUCCEEDED";
Vishnu Nair958da932020-08-21 17:12:37 -07008272
8273 // Focused window should receive event.
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07008274 windowSecond->consumeKeyDown(ui::LogicalDisplayId::INVALID);
Vishnu Nair958da932020-08-21 17:12:37 -07008275}
8276
Chavi Weingarten847e8512023-03-29 00:26:09 +00008277TEST_F(InputDispatcherTest, SetFocusedWindow_TransferFocusTokenNotFocusable) {
Vishnu Nair958da932020-08-21 17:12:37 -07008278 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07008279 sp<FakeWindowHandle> windowTop = sp<FakeWindowHandle>::make(application, mDispatcher, "Top",
8280 ui::LogicalDisplayId::DEFAULT);
Vishnu Nair958da932020-08-21 17:12:37 -07008281 sp<FakeWindowHandle> windowSecond =
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07008282 sp<FakeWindowHandle>::make(application, mDispatcher, "Second",
8283 ui::LogicalDisplayId::DEFAULT);
8284 mDispatcher->setFocusedApplication(ui::LogicalDisplayId::DEFAULT, application);
Vishnu Nair958da932020-08-21 17:12:37 -07008285
8286 windowTop->setFocusable(true);
Chavi Weingarten847e8512023-03-29 00:26:09 +00008287 windowSecond->setFocusable(false);
8288 windowTop->editInfo()->focusTransferTarget = windowSecond->getToken();
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07008289 mDispatcher->onWindowInfosChanged(
8290 {{*windowTop->getInfo(), *windowSecond->getInfo()}, {}, 0, 0});
Chavi Weingarten847e8512023-03-29 00:26:09 +00008291 setFocusedWindow(windowTop);
8292 windowTop->consumeFocusEvent(true);
Vishnu Nair958da932020-08-21 17:12:37 -07008293
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07008294 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectKeyDown(*mDispatcher))
Chavi Weingarten847e8512023-03-29 00:26:09 +00008295 << "Inject key event should return InputEventInjectionResult::SUCCEEDED";
Vishnu Nair958da932020-08-21 17:12:37 -07008296
8297 // Event should be dropped.
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07008298 windowTop->consumeKeyDown(ui::LogicalDisplayId::INVALID);
Vishnu Nair958da932020-08-21 17:12:37 -07008299 windowSecond->assertNoEvents();
8300}
8301
8302TEST_F(InputDispatcherTest, SetFocusedWindow_DeferInvisibleWindow) {
8303 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07008304 sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher, "TestWindow",
8305 ui::LogicalDisplayId::DEFAULT);
Vishnu Nair958da932020-08-21 17:12:37 -07008306 sp<FakeWindowHandle> previousFocusedWindow =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07008307 sp<FakeWindowHandle>::make(application, mDispatcher, "previousFocusedWindow",
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07008308 ui::LogicalDisplayId::DEFAULT);
8309 mDispatcher->setFocusedApplication(ui::LogicalDisplayId::DEFAULT, application);
Vishnu Nair958da932020-08-21 17:12:37 -07008310
8311 window->setFocusable(true);
8312 previousFocusedWindow->setFocusable(true);
8313 window->setVisible(false);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07008314 mDispatcher->onWindowInfosChanged(
8315 {{*window->getInfo(), *previousFocusedWindow->getInfo()}, {}, 0, 0});
Vishnu Nair958da932020-08-21 17:12:37 -07008316 setFocusedWindow(previousFocusedWindow);
8317 previousFocusedWindow->consumeFocusEvent(true);
8318
8319 // Requesting focus on invisible window takes focus from currently focused window.
8320 setFocusedWindow(window);
8321 previousFocusedWindow->consumeFocusEvent(false);
8322
8323 // Injected key goes to pending queue.
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08008324 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07008325 injectKey(*mDispatcher, AKEY_EVENT_ACTION_DOWN, /*repeatCount=*/0,
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07008326 ui::LogicalDisplayId::DEFAULT, InputEventInjectionSync::NONE));
Vishnu Nair958da932020-08-21 17:12:37 -07008327
8328 // Window does not get focus event or key down.
8329 window->assertNoEvents();
8330
8331 // Window becomes visible.
8332 window->setVisible(true);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07008333 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Vishnu Nair958da932020-08-21 17:12:37 -07008334
8335 // Window receives focus event.
8336 window->consumeFocusEvent(true);
8337 // Focused window receives key down.
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07008338 window->consumeKeyDown(ui::LogicalDisplayId::DEFAULT);
Vishnu Nair958da932020-08-21 17:12:37 -07008339}
8340
Vishnu Nair599f1412021-06-21 10:39:58 -07008341TEST_F(InputDispatcherTest, DisplayRemoved) {
8342 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07008343 sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher, "window",
8344 ui::LogicalDisplayId::DEFAULT);
8345 mDispatcher->setFocusedApplication(ui::LogicalDisplayId::DEFAULT, application);
Vishnu Nair599f1412021-06-21 10:39:58 -07008346
8347 // window is granted focus.
8348 window->setFocusable(true);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07008349 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Vishnu Nair599f1412021-06-21 10:39:58 -07008350 setFocusedWindow(window);
8351 window->consumeFocusEvent(true);
8352
8353 // When a display is removed window loses focus.
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07008354 mDispatcher->displayRemoved(ui::LogicalDisplayId::DEFAULT);
Vishnu Nair599f1412021-06-21 10:39:58 -07008355 window->consumeFocusEvent(false);
8356}
8357
Siarhei Vishniakou870ecec2020-12-09 08:07:46 -10008358/**
8359 * Launch two windows, with different owners. One window (slipperyExitWindow) has Flag::SLIPPERY,
8360 * and overlaps the other window, slipperyEnterWindow. The window 'slipperyExitWindow' is on top
8361 * of the 'slipperyEnterWindow'.
8362 *
8363 * Inject touch down into the top window. Upon receipt of the DOWN event, move the window in such
8364 * a way so that the touched location is no longer covered by the top window.
8365 *
8366 * Next, inject a MOVE event. Because the top window already moved earlier, this event is now
8367 * positioned over the bottom (slipperyEnterWindow) only. And because the top window had
8368 * Flag::SLIPPERY, this will cause the top window to lose the touch event (it will receive
8369 * ACTION_CANCEL instead), and the bottom window will receive a newly generated gesture (starting
8370 * with ACTION_DOWN).
8371 * Thus, the touch has been transferred from the top window into the bottom window, because the top
8372 * window moved itself away from the touched location and had Flag::SLIPPERY.
8373 *
8374 * Even though the top window moved away from the touched location, it is still obscuring the bottom
8375 * window. It's just not obscuring it at the touched location. That means, FLAG_WINDOW_IS_PARTIALLY_
8376 * OBSCURED should be set for the MotionEvent that reaches the bottom window.
8377 *
8378 * In this test, we ensure that the event received by the bottom window has
8379 * FLAG_WINDOW_IS_PARTIALLY_OBSCURED.
8380 */
8381TEST_F(InputDispatcherTest, SlipperyWindow_SetsFlagPartiallyObscured) {
Prabir Pradhanaeebeb42023-06-13 19:53:03 +00008382 constexpr gui::Pid SLIPPERY_PID{WINDOW_PID.val() + 1};
Prabir Pradhan8a5c41d2023-06-08 19:13:46 +00008383 constexpr gui::Uid SLIPPERY_UID{WINDOW_UID.val() + 1};
Siarhei Vishniakou870ecec2020-12-09 08:07:46 -10008384
8385 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07008386 mDispatcher->setFocusedApplication(ui::LogicalDisplayId::DEFAULT, application);
Siarhei Vishniakou870ecec2020-12-09 08:07:46 -10008387
8388 sp<FakeWindowHandle> slipperyExitWindow =
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07008389 sp<FakeWindowHandle>::make(application, mDispatcher, "Top",
8390 ui::LogicalDisplayId::DEFAULT);
Prabir Pradhan4d5c52f2022-01-31 08:52:10 -08008391 slipperyExitWindow->setSlippery(true);
Siarhei Vishniakou870ecec2020-12-09 08:07:46 -10008392 // Make sure this one overlaps the bottom window
8393 slipperyExitWindow->setFrame(Rect(25, 25, 75, 75));
8394 // Change the owner uid/pid of the window so that it is considered to be occluding the bottom
8395 // one. Windows with the same owner are not considered to be occluding each other.
8396 slipperyExitWindow->setOwnerInfo(SLIPPERY_PID, SLIPPERY_UID);
8397
8398 sp<FakeWindowHandle> slipperyEnterWindow =
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07008399 sp<FakeWindowHandle>::make(application, mDispatcher, "Second",
8400 ui::LogicalDisplayId::DEFAULT);
Siarhei Vishniakou870ecec2020-12-09 08:07:46 -10008401 slipperyExitWindow->setFrame(Rect(0, 0, 100, 100));
8402
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07008403 mDispatcher->onWindowInfosChanged(
8404 {{*slipperyExitWindow->getInfo(), *slipperyEnterWindow->getInfo()}, {}, 0, 0});
Siarhei Vishniakou870ecec2020-12-09 08:07:46 -10008405
8406 // Use notifyMotion instead of injecting to avoid dealing with injection permissions
Prabir Pradhan678438e2023-04-13 19:32:51 +00008407 mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_DOWN,
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07008408 AINPUT_SOURCE_TOUCHSCREEN,
8409 ui::LogicalDisplayId::DEFAULT, {{50, 50}}));
Siarhei Vishniakou870ecec2020-12-09 08:07:46 -10008410 slipperyExitWindow->consumeMotionDown();
8411 slipperyExitWindow->setFrame(Rect(70, 70, 100, 100));
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07008412 mDispatcher->onWindowInfosChanged(
8413 {{*slipperyExitWindow->getInfo(), *slipperyEnterWindow->getInfo()}, {}, 0, 0});
Siarhei Vishniakou870ecec2020-12-09 08:07:46 -10008414
Prabir Pradhan678438e2023-04-13 19:32:51 +00008415 mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_MOVE,
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07008416 AINPUT_SOURCE_TOUCHSCREEN,
8417 ui::LogicalDisplayId::DEFAULT, {{51, 51}}));
Siarhei Vishniakou870ecec2020-12-09 08:07:46 -10008418
8419 slipperyExitWindow->consumeMotionCancel();
8420
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07008421 slipperyEnterWindow->consumeMotionDown(ui::LogicalDisplayId::DEFAULT,
Siarhei Vishniakou870ecec2020-12-09 08:07:46 -10008422 AMOTION_EVENT_FLAG_WINDOW_IS_PARTIALLY_OBSCURED);
8423}
8424
Siarhei Vishniakouafa08cc2023-05-08 22:35:50 -07008425/**
8426 * Two windows, one on the left and another on the right. The left window is slippery. The right
8427 * window isn't eligible to receive touch because it specifies InputConfig::DROP_INPUT. When the
8428 * touch moves from the left window into the right window, the gesture should continue to go to the
8429 * left window. Touch shouldn't slip because the right window can't receive touches. This test
8430 * reproduces a crash.
8431 */
8432TEST_F(InputDispatcherTest, TouchSlippingIntoWindowThatDropsTouches) {
8433 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
8434
8435 sp<FakeWindowHandle> leftSlipperyWindow =
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07008436 sp<FakeWindowHandle>::make(application, mDispatcher, "Left",
8437 ui::LogicalDisplayId::DEFAULT);
Siarhei Vishniakouafa08cc2023-05-08 22:35:50 -07008438 leftSlipperyWindow->setSlippery(true);
8439 leftSlipperyWindow->setFrame(Rect(0, 0, 100, 100));
8440
8441 sp<FakeWindowHandle> rightDropTouchesWindow =
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07008442 sp<FakeWindowHandle>::make(application, mDispatcher, "Right",
8443 ui::LogicalDisplayId::DEFAULT);
Siarhei Vishniakouafa08cc2023-05-08 22:35:50 -07008444 rightDropTouchesWindow->setFrame(Rect(100, 0, 200, 100));
8445 rightDropTouchesWindow->setDropInput(true);
8446
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07008447 mDispatcher->onWindowInfosChanged(
8448 {{*leftSlipperyWindow->getInfo(), *rightDropTouchesWindow->getInfo()}, {}, 0, 0});
Siarhei Vishniakouafa08cc2023-05-08 22:35:50 -07008449
8450 // Start touch in the left window
8451 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
8452 .pointer(PointerBuilder(0, ToolType::FINGER).x(50).y(50))
8453 .build());
8454 leftSlipperyWindow->consumeMotionDown();
8455
8456 // And move it into the right window
8457 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN)
8458 .pointer(PointerBuilder(0, ToolType::FINGER).x(150).y(50))
8459 .build());
8460
8461 // Since the right window isn't eligible to receive input, touch does not slip.
8462 // The left window continues to receive the gesture.
8463 leftSlipperyWindow->consumeMotionEvent(WithMotionAction(ACTION_MOVE));
8464 rightDropTouchesWindow->assertNoEvents();
8465}
8466
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -07008467/**
8468 * A single window is on screen first. Touch is injected into that window. Next, a second window
8469 * appears. Since the first window is slippery, touch will move from the first window to the second.
8470 */
8471TEST_F(InputDispatcherTest, InjectedTouchSlips) {
8472 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
8473 sp<FakeWindowHandle> originalWindow =
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07008474 sp<FakeWindowHandle>::make(application, mDispatcher, "Original",
8475 ui::LogicalDisplayId::DEFAULT);
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -07008476 originalWindow->setFrame(Rect(0, 0, 200, 200));
8477 originalWindow->setSlippery(true);
8478
8479 sp<FakeWindowHandle> appearingWindow =
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07008480 sp<FakeWindowHandle>::make(application, mDispatcher, "Appearing",
8481 ui::LogicalDisplayId::DEFAULT);
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -07008482 appearingWindow->setFrame(Rect(0, 0, 200, 200));
8483
8484 mDispatcher->onWindowInfosChanged({{*originalWindow->getInfo()}, {}, 0, 0});
8485
8486 // Touch down on the original window
8487 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
8488 injectMotionEvent(*mDispatcher,
8489 MotionEventBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
8490 .pointer(PointerBuilder(1, ToolType::FINGER).x(100).y(100))
8491 .build()));
8492 originalWindow->consumeMotionEvent(WithMotionAction(ACTION_DOWN));
8493
8494 // Now, a new window appears. This could be, for example, a notification shade that appears
8495 // after user starts to drag down on the launcher window.
8496 mDispatcher->onWindowInfosChanged(
8497 {{*appearingWindow->getInfo(), *originalWindow->getInfo()}, {}, 0, 0});
8498 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
8499 injectMotionEvent(*mDispatcher,
8500 MotionEventBuilder(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN)
8501 .pointer(PointerBuilder(1, ToolType::FINGER).x(110).y(110))
8502 .build()));
8503 originalWindow->consumeMotionEvent(WithMotionAction(ACTION_CANCEL));
8504 appearingWindow->consumeMotionEvent(WithMotionAction(ACTION_DOWN));
8505 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
8506 injectMotionEvent(*mDispatcher,
8507 MotionEventBuilder(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN)
8508 .pointer(PointerBuilder(1, ToolType::FINGER).x(120).y(120))
8509 .build()));
8510 appearingWindow->consumeMotionEvent(WithMotionAction(ACTION_MOVE));
8511
8512 originalWindow->assertNoEvents();
8513 appearingWindow->assertNoEvents();
8514}
8515
Linnan Li49b2b202024-04-12 12:46:40 +08008516/**
8517 * Three windows:
8518 * - left window, which has FLAG_SLIPPERY, so it supports slippery exit
8519 * - right window
8520 * - spy window
8521 * The three windows do not overlap.
8522 *
8523 * We have two devices reporting events:
8524 * - Device A reports ACTION_DOWN, which lands in the left window
8525 * - Device B reports ACTION_DOWN, which lands in the spy window.
8526 * - Now, device B reports ACTION_MOVE events which move to the right window.
8527 *
8528 * The right window should not receive any events because the spy window is not a foreground window,
8529 * and also it does not support slippery touches.
8530 */
8531TEST_F(InputDispatcherTest, MultiDeviceSpyWindowSlipTest) {
8532 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
8533 sp<FakeWindowHandle> leftWindow =
8534 sp<FakeWindowHandle>::make(application, mDispatcher, "Left window",
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07008535 ui::LogicalDisplayId::DEFAULT);
Linnan Li49b2b202024-04-12 12:46:40 +08008536 leftWindow->setFrame(Rect(0, 0, 100, 100));
8537 leftWindow->setSlippery(true);
8538
8539 sp<FakeWindowHandle> rightWindow =
8540 sp<FakeWindowHandle>::make(application, mDispatcher, "Right window",
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07008541 ui::LogicalDisplayId::DEFAULT);
Linnan Li49b2b202024-04-12 12:46:40 +08008542 rightWindow->setFrame(Rect(100, 0, 200, 100));
8543
8544 sp<FakeWindowHandle> spyWindow =
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07008545 sp<FakeWindowHandle>::make(application, mDispatcher, "Spy Window",
8546 ui::LogicalDisplayId::DEFAULT);
Linnan Li49b2b202024-04-12 12:46:40 +08008547 spyWindow->setFrame(Rect(200, 0, 300, 100));
8548 spyWindow->setSpy(true);
8549 spyWindow->setTrustedOverlay(true);
8550
8551 mDispatcher->onWindowInfosChanged(
8552 {{*leftWindow->getInfo(), *rightWindow->getInfo(), *spyWindow->getInfo()}, {}, 0, 0});
8553
8554 const DeviceId deviceA = 9;
8555 const DeviceId deviceB = 3;
8556
8557 // Tap on left window with device A
8558 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
8559 .pointer(PointerBuilder(0, ToolType::FINGER).x(50).y(50))
8560 .deviceId(deviceA)
8561 .build());
8562 leftWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(deviceA)));
8563
8564 // Tap on spy window with device B
8565 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
8566 .pointer(PointerBuilder(0, ToolType::FINGER).x(250).y(50))
8567 .deviceId(deviceB)
8568 .build());
8569 spyWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(deviceB)));
8570
8571 // Move to right window with device B. Touches should not slip to the right window, because spy
8572 // window is not a foreground window, and it does not have FLAG_SLIPPERY
8573 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN)
8574 .pointer(PointerBuilder(0, ToolType::FINGER).x(150).y(50))
8575 .deviceId(deviceB)
8576 .build());
8577 leftWindow->assertNoEvents();
8578 rightWindow->assertNoEvents();
8579 spyWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(deviceB)));
8580}
8581
8582/**
8583 * Three windows arranged horizontally and without any overlap.
8584 * The left and right windows have FLAG_SLIPPERY. The middle window does not have any special flags.
8585 *
8586 * We have two devices reporting events:
8587 * - Device A reports ACTION_DOWN which lands in the left window
8588 * - Device B reports ACTION_DOWN which lands in the right window
8589 * - Device B reports ACTION_MOVE that shifts to the middle window.
8590 * This should cause touches for Device B to slip from the right window to the middle window.
8591 * The right window should receive ACTION_CANCEL for device B and the
8592 * middle window should receive down event for Device B.
8593 * If device B reports more ACTION_MOVE events, the middle window should receive remaining events.
8594 */
8595TEST_F(InputDispatcherTest, MultiDeviceSlipperyWindowTest) {
Siarhei Vishniakoudd56df12024-05-20 14:56:38 -07008596 SCOPED_FLAG_OVERRIDE(enable_multi_device_same_window_stream, true);
Linnan Li49b2b202024-04-12 12:46:40 +08008597 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
8598 sp<FakeWindowHandle> leftWindow =
8599 sp<FakeWindowHandle>::make(application, mDispatcher, "Left window",
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07008600 ui::LogicalDisplayId::DEFAULT);
Linnan Li49b2b202024-04-12 12:46:40 +08008601 leftWindow->setFrame(Rect(0, 0, 100, 100));
8602 leftWindow->setSlippery(true);
8603
8604 sp<FakeWindowHandle> middleWindow =
8605 sp<FakeWindowHandle>::make(application, mDispatcher, "middle window",
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07008606 ui::LogicalDisplayId::DEFAULT);
Linnan Li49b2b202024-04-12 12:46:40 +08008607 middleWindow->setFrame(Rect(100, 0, 200, 100));
8608
8609 sp<FakeWindowHandle> rightWindow =
8610 sp<FakeWindowHandle>::make(application, mDispatcher, "Right window",
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07008611 ui::LogicalDisplayId::DEFAULT);
Linnan Li49b2b202024-04-12 12:46:40 +08008612 rightWindow->setFrame(Rect(200, 0, 300, 100));
8613 rightWindow->setSlippery(true);
8614
8615 mDispatcher->onWindowInfosChanged(
8616 {{*leftWindow->getInfo(), *middleWindow->getInfo(), *rightWindow->getInfo()},
8617 {},
8618 0,
8619 0});
8620
8621 const DeviceId deviceA = 9;
8622 const DeviceId deviceB = 3;
8623
8624 // Tap on left window with device A
8625 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
8626 .pointer(PointerBuilder(0, ToolType::FINGER).x(50).y(50))
8627 .deviceId(deviceA)
8628 .build());
8629 leftWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(deviceA)));
8630
8631 // Tap on right window with device B
8632 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
8633 .pointer(PointerBuilder(0, ToolType::FINGER).x(250).y(50))
8634 .deviceId(deviceB)
8635 .build());
8636 rightWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(deviceB)));
8637
8638 // Move to middle window with device B. Touches should slip to middle window, because right
8639 // window is a foreground window that's associated with device B and has FLAG_SLIPPERY.
8640 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN)
8641 .pointer(PointerBuilder(0, ToolType::FINGER).x(150).y(50))
8642 .deviceId(deviceB)
8643 .build());
8644 rightWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_CANCEL), WithDeviceId(deviceB)));
8645 middleWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(deviceB)));
8646
8647 // Move to middle window with device A. Touches should slip to middle window, because left
8648 // window is a foreground window that's associated with device A and has FLAG_SLIPPERY.
8649 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN)
8650 .pointer(PointerBuilder(0, ToolType::FINGER).x(150).y(50))
8651 .deviceId(deviceA)
8652 .build());
8653 leftWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_CANCEL), WithDeviceId(deviceA)));
8654 middleWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(deviceA)));
8655
8656 // Ensure that middle window can receive the remaining move events.
8657 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN)
8658 .pointer(PointerBuilder(0, ToolType::FINGER).x(151).y(51))
8659 .deviceId(deviceB)
8660 .build());
8661 leftWindow->assertNoEvents();
8662 middleWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(deviceB)));
8663 rightWindow->assertNoEvents();
8664}
8665
Prabir Pradhan8ede1d12023-05-08 19:37:44 +00008666TEST_F(InputDispatcherTest, NotifiesDeviceInteractionsWithMotions) {
Prabir Pradhan8a5c41d2023-06-08 19:13:46 +00008667 using Uid = gui::Uid;
Prabir Pradhan8ede1d12023-05-08 19:37:44 +00008668 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
8669
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07008670 sp<FakeWindowHandle> leftWindow = sp<FakeWindowHandle>::make(application, mDispatcher, "Left",
8671 ui::LogicalDisplayId::DEFAULT);
Prabir Pradhan8ede1d12023-05-08 19:37:44 +00008672 leftWindow->setFrame(Rect(0, 0, 100, 100));
Prabir Pradhanaeebeb42023-06-13 19:53:03 +00008673 leftWindow->setOwnerInfo(gui::Pid{1}, Uid{101});
Prabir Pradhan8ede1d12023-05-08 19:37:44 +00008674
8675 sp<FakeWindowHandle> rightSpy =
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07008676 sp<FakeWindowHandle>::make(application, mDispatcher, "Right spy",
8677 ui::LogicalDisplayId::DEFAULT);
Prabir Pradhan8ede1d12023-05-08 19:37:44 +00008678 rightSpy->setFrame(Rect(100, 0, 200, 100));
Prabir Pradhanaeebeb42023-06-13 19:53:03 +00008679 rightSpy->setOwnerInfo(gui::Pid{2}, Uid{102});
Prabir Pradhan8ede1d12023-05-08 19:37:44 +00008680 rightSpy->setSpy(true);
8681 rightSpy->setTrustedOverlay(true);
8682
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07008683 sp<FakeWindowHandle> rightWindow = sp<FakeWindowHandle>::make(application, mDispatcher, "Right",
8684 ui::LogicalDisplayId::DEFAULT);
Prabir Pradhan8ede1d12023-05-08 19:37:44 +00008685 rightWindow->setFrame(Rect(100, 0, 200, 100));
Prabir Pradhanaeebeb42023-06-13 19:53:03 +00008686 rightWindow->setOwnerInfo(gui::Pid{3}, Uid{103});
Prabir Pradhan8ede1d12023-05-08 19:37:44 +00008687
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07008688 mDispatcher->onWindowInfosChanged(
8689 {{*rightSpy->getInfo(), *rightWindow->getInfo(), *leftWindow->getInfo()}, {}, 0, 0});
Prabir Pradhan8ede1d12023-05-08 19:37:44 +00008690
8691 // Touch in the left window
8692 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
8693 .pointer(PointerBuilder(0, ToolType::FINGER).x(50).y(50))
8694 .build());
8695 ASSERT_NO_FATAL_FAILURE(leftWindow->consumeMotionDown());
8696 mDispatcher->waitForIdle();
Prabir Pradhan8a5c41d2023-06-08 19:13:46 +00008697 ASSERT_NO_FATAL_FAILURE(
8698 mFakePolicy->assertNotifyDeviceInteractionWasCalled(DEVICE_ID, {Uid{101}}));
Prabir Pradhan8ede1d12023-05-08 19:37:44 +00008699
8700 // Touch another finger over the right windows
8701 mDispatcher->notifyMotion(MotionArgsBuilder(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
8702 .pointer(PointerBuilder(0, ToolType::FINGER).x(50).y(50))
8703 .pointer(PointerBuilder(1, ToolType::FINGER).x(150).y(50))
8704 .build());
8705 ASSERT_NO_FATAL_FAILURE(rightSpy->consumeMotionDown());
8706 ASSERT_NO_FATAL_FAILURE(rightWindow->consumeMotionDown());
8707 ASSERT_NO_FATAL_FAILURE(leftWindow->consumeMotionMove());
8708 mDispatcher->waitForIdle();
8709 ASSERT_NO_FATAL_FAILURE(
Prabir Pradhan8a5c41d2023-06-08 19:13:46 +00008710 mFakePolicy->assertNotifyDeviceInteractionWasCalled(DEVICE_ID,
8711 {Uid{101}, Uid{102}, Uid{103}}));
Prabir Pradhan8ede1d12023-05-08 19:37:44 +00008712
8713 // Release finger over left window. The UP actions are not treated as device interaction.
8714 // The windows that did not receive the UP pointer will receive MOVE events, but since this
8715 // is part of the UP action, we do not treat this as device interaction.
8716 mDispatcher->notifyMotion(MotionArgsBuilder(POINTER_0_UP, AINPUT_SOURCE_TOUCHSCREEN)
8717 .pointer(PointerBuilder(0, ToolType::FINGER).x(50).y(50))
8718 .pointer(PointerBuilder(1, ToolType::FINGER).x(150).y(50))
8719 .build());
8720 ASSERT_NO_FATAL_FAILURE(leftWindow->consumeMotionUp());
8721 ASSERT_NO_FATAL_FAILURE(rightSpy->consumeMotionMove());
8722 ASSERT_NO_FATAL_FAILURE(rightWindow->consumeMotionMove());
8723 mDispatcher->waitForIdle();
8724 ASSERT_NO_FATAL_FAILURE(mFakePolicy->assertNotifyDeviceInteractionWasNotCalled());
8725
8726 // Move remaining finger
8727 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN)
8728 .pointer(PointerBuilder(1, ToolType::FINGER).x(150).y(50))
8729 .build());
8730 ASSERT_NO_FATAL_FAILURE(rightSpy->consumeMotionMove());
8731 ASSERT_NO_FATAL_FAILURE(rightWindow->consumeMotionMove());
8732 mDispatcher->waitForIdle();
8733 ASSERT_NO_FATAL_FAILURE(
Prabir Pradhan8a5c41d2023-06-08 19:13:46 +00008734 mFakePolicy->assertNotifyDeviceInteractionWasCalled(DEVICE_ID, {Uid{102}, Uid{103}}));
Prabir Pradhan8ede1d12023-05-08 19:37:44 +00008735
8736 // Release all fingers
8737 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN)
8738 .pointer(PointerBuilder(1, ToolType::FINGER).x(150).y(50))
8739 .build());
8740 ASSERT_NO_FATAL_FAILURE(rightSpy->consumeMotionUp());
8741 ASSERT_NO_FATAL_FAILURE(rightWindow->consumeMotionUp());
8742 mDispatcher->waitForIdle();
8743 ASSERT_NO_FATAL_FAILURE(mFakePolicy->assertNotifyDeviceInteractionWasNotCalled());
8744}
8745
8746TEST_F(InputDispatcherTest, NotifiesDeviceInteractionsWithKeys) {
8747 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
8748
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07008749 sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher, "Window",
8750 ui::LogicalDisplayId::DEFAULT);
Prabir Pradhan8ede1d12023-05-08 19:37:44 +00008751 window->setFrame(Rect(0, 0, 100, 100));
Prabir Pradhanaeebeb42023-06-13 19:53:03 +00008752 window->setOwnerInfo(gui::Pid{1}, gui::Uid{101});
Prabir Pradhan8ede1d12023-05-08 19:37:44 +00008753
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07008754 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Prabir Pradhan8ede1d12023-05-08 19:37:44 +00008755 setFocusedWindow(window);
8756 ASSERT_NO_FATAL_FAILURE(window->consumeFocusEvent(true));
8757
8758 mDispatcher->notifyKey(KeyArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_KEYBOARD).build());
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07008759 ASSERT_NO_FATAL_FAILURE(window->consumeKeyDown(ui::LogicalDisplayId::DEFAULT));
Prabir Pradhan8ede1d12023-05-08 19:37:44 +00008760 mDispatcher->waitForIdle();
Prabir Pradhan8a5c41d2023-06-08 19:13:46 +00008761 ASSERT_NO_FATAL_FAILURE(
8762 mFakePolicy->assertNotifyDeviceInteractionWasCalled(DEVICE_ID, {gui::Uid{101}}));
Prabir Pradhan8ede1d12023-05-08 19:37:44 +00008763
8764 // The UP actions are not treated as device interaction.
8765 mDispatcher->notifyKey(KeyArgsBuilder(ACTION_UP, AINPUT_SOURCE_KEYBOARD).build());
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07008766 ASSERT_NO_FATAL_FAILURE(window->consumeKeyUp(ui::LogicalDisplayId::DEFAULT));
Prabir Pradhan8ede1d12023-05-08 19:37:44 +00008767 mDispatcher->waitForIdle();
8768 ASSERT_NO_FATAL_FAILURE(mFakePolicy->assertNotifyDeviceInteractionWasNotCalled());
8769}
8770
Prabir Pradhan5893d362023-11-17 04:30:40 +00008771TEST_F(InputDispatcherTest, HoverEnterExitSynthesisUsesNewEventId) {
8772 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
8773
8774 sp<FakeWindowHandle> left = sp<FakeWindowHandle>::make(application, mDispatcher, "Left Window",
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07008775 ui::LogicalDisplayId::DEFAULT);
Prabir Pradhan5893d362023-11-17 04:30:40 +00008776 left->setFrame(Rect(0, 0, 100, 100));
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07008777 sp<FakeWindowHandle> right =
8778 sp<FakeWindowHandle>::make(application, mDispatcher, "Right Window",
8779 ui::LogicalDisplayId::DEFAULT);
Prabir Pradhan5893d362023-11-17 04:30:40 +00008780 right->setFrame(Rect(100, 0, 200, 100));
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07008781 sp<FakeWindowHandle> spy = sp<FakeWindowHandle>::make(application, mDispatcher, "Spy Window",
8782 ui::LogicalDisplayId::DEFAULT);
Prabir Pradhan5893d362023-11-17 04:30:40 +00008783 spy->setFrame(Rect(0, 0, 200, 100));
8784 spy->setTrustedOverlay(true);
8785 spy->setSpy(true);
8786
8787 mDispatcher->onWindowInfosChanged(
8788 {{*spy->getInfo(), *left->getInfo(), *right->getInfo()}, {}, 0, 0});
8789
8790 // Send hover move to the left window, and ensure hover enter is synthesized with a new eventId.
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07008791 NotifyMotionArgs notifyArgs =
8792 generateMotionArgs(ACTION_HOVER_MOVE, AINPUT_SOURCE_STYLUS,
8793 ui::LogicalDisplayId::DEFAULT, {PointF{50, 50}});
Prabir Pradhan5893d362023-11-17 04:30:40 +00008794 mDispatcher->notifyMotion(notifyArgs);
8795
Siarhei Vishniakoud3061ab2023-12-18 20:41:08 -08008796 std::unique_ptr<MotionEvent> leftEnter = left->consumeMotionEvent(
Prabir Pradhan5893d362023-11-17 04:30:40 +00008797 AllOf(WithMotionAction(ACTION_HOVER_ENTER), Not(WithEventId(notifyArgs.id)),
8798 WithEventIdSource(IdGenerator::Source::INPUT_DISPATCHER)));
Siarhei Vishniakoud3061ab2023-12-18 20:41:08 -08008799 ASSERT_NE(nullptr, leftEnter);
Prabir Pradhan5893d362023-11-17 04:30:40 +00008800 spy->consumeMotionEvent(AllOf(WithMotionAction(ACTION_HOVER_ENTER),
8801 Not(WithEventId(notifyArgs.id)),
Siarhei Vishniakoud3061ab2023-12-18 20:41:08 -08008802 Not(WithEventId(leftEnter->getId())),
Prabir Pradhan5893d362023-11-17 04:30:40 +00008803 WithEventIdSource(IdGenerator::Source::INPUT_DISPATCHER)));
8804
8805 // Send move to the right window, and ensure hover exit and enter are synthesized with new ids.
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07008806 notifyArgs = generateMotionArgs(ACTION_HOVER_MOVE, AINPUT_SOURCE_STYLUS,
8807 ui::LogicalDisplayId::DEFAULT, {PointF{150, 50}});
Prabir Pradhan5893d362023-11-17 04:30:40 +00008808 mDispatcher->notifyMotion(notifyArgs);
8809
Siarhei Vishniakoud3061ab2023-12-18 20:41:08 -08008810 std::unique_ptr<MotionEvent> leftExit = left->consumeMotionEvent(
Prabir Pradhan5893d362023-11-17 04:30:40 +00008811 AllOf(WithMotionAction(ACTION_HOVER_EXIT), Not(WithEventId(notifyArgs.id)),
8812 WithEventIdSource(IdGenerator::Source::INPUT_DISPATCHER)));
Siarhei Vishniakoud3061ab2023-12-18 20:41:08 -08008813 ASSERT_NE(nullptr, leftExit);
Prabir Pradhan5893d362023-11-17 04:30:40 +00008814 right->consumeMotionEvent(AllOf(WithMotionAction(ACTION_HOVER_ENTER),
8815 Not(WithEventId(notifyArgs.id)),
Siarhei Vishniakoud3061ab2023-12-18 20:41:08 -08008816 Not(WithEventId(leftExit->getId())),
Prabir Pradhan5893d362023-11-17 04:30:40 +00008817 WithEventIdSource(IdGenerator::Source::INPUT_DISPATCHER)));
8818
8819 spy->consumeMotionEvent(AllOf(WithMotionAction(ACTION_HOVER_MOVE), WithEventId(notifyArgs.id)));
8820}
8821
Linnan Liccf6ce32024-04-11 20:32:13 +08008822/**
8823 * When a device reports a DOWN event, which lands in a window that supports splits, and then the
8824 * device then reports a POINTER_DOWN, which lands in the location of a non-existing window, then
8825 * the previous window should receive this event and not be dropped.
8826 */
8827TEST_F(InputDispatcherMultiDeviceTest, SingleDevicePointerDownEventRetentionWithoutWindowTarget) {
Siarhei Vishniakoua3fe6642024-07-18 11:58:25 -07008828 SCOPED_FLAG_OVERRIDE(split_all_touches, false);
Linnan Liccf6ce32024-04-11 20:32:13 +08008829 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07008830 sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher, "Window",
8831 ui::LogicalDisplayId::DEFAULT);
Linnan Liccf6ce32024-04-11 20:32:13 +08008832 window->setFrame(Rect(0, 0, 100, 100));
8833 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
8834
8835 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
8836 .pointer(PointerBuilder(0, ToolType::FINGER).x(50).y(50))
8837 .build());
8838
8839 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN)));
8840
8841 mDispatcher->notifyMotion(MotionArgsBuilder(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
8842 .pointer(PointerBuilder(0, ToolType::FINGER).x(50).y(50))
8843 .pointer(PointerBuilder(1, ToolType::FINGER).x(200).y(200))
8844 .build());
8845
8846 window->consumeMotionEvent(AllOf(WithMotionAction(POINTER_1_DOWN)));
8847}
8848
8849/**
8850 * When deviceA reports a DOWN event, which lands in a window that supports splits, and then deviceB
8851 * also reports a DOWN event, which lands in the location of a non-existing window, then the
8852 * previous window should receive deviceB's event and it should be dropped.
8853 */
8854TEST_F(InputDispatcherMultiDeviceTest, SecondDeviceDownEventDroppedWithoutWindowTarget) {
8855 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07008856 sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher, "Window",
8857 ui::LogicalDisplayId::DEFAULT);
Linnan Liccf6ce32024-04-11 20:32:13 +08008858 window->setFrame(Rect(0, 0, 100, 100));
8859 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
8860
8861 const DeviceId deviceA = 9;
8862 const DeviceId deviceB = 3;
8863
8864 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
8865 .pointer(PointerBuilder(0, ToolType::FINGER).x(50).y(50))
8866 .deviceId(deviceA)
8867 .build());
8868 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(deviceA)));
8869
8870 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
8871 .pointer(PointerBuilder(0, ToolType::FINGER).x(200).y(200))
8872 .deviceId(deviceB)
8873 .build());
8874 window->assertNoEvents();
8875}
8876
Prabir Pradhanb0dad3a2023-11-02 20:52:47 +00008877class InputDispatcherFallbackKeyTest : public InputDispatcherTest {
8878protected:
8879 std::shared_ptr<FakeApplicationHandle> mApp;
8880 sp<FakeWindowHandle> mWindow;
8881
8882 virtual void SetUp() override {
8883 InputDispatcherTest::SetUp();
8884
8885 mApp = std::make_shared<FakeApplicationHandle>();
8886
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07008887 mWindow = sp<FakeWindowHandle>::make(mApp, mDispatcher, "Window",
8888 ui::LogicalDisplayId::DEFAULT);
Prabir Pradhanb0dad3a2023-11-02 20:52:47 +00008889 mWindow->setFrame(Rect(0, 0, 100, 100));
8890
8891 mDispatcher->onWindowInfosChanged({{*mWindow->getInfo()}, {}, 0, 0});
8892 setFocusedWindow(mWindow);
8893 ASSERT_NO_FATAL_FAILURE(mWindow->consumeFocusEvent(/*hasFocus=*/true));
8894 }
8895
8896 void setFallback(int32_t keycode) {
8897 mFakePolicy->setUnhandledKeyHandler([keycode](const KeyEvent& event) {
8898 return KeyEventBuilder(event).keyCode(keycode).build();
8899 });
8900 }
8901
8902 void consumeKey(bool handled, const ::testing::Matcher<KeyEvent>& matcher) {
Siarhei Vishniakoud3061ab2023-12-18 20:41:08 -08008903 std::unique_ptr<KeyEvent> event = mWindow->consumeKey(handled);
8904 ASSERT_NE(nullptr, event);
8905 ASSERT_THAT(*event, matcher);
Prabir Pradhanb0dad3a2023-11-02 20:52:47 +00008906 }
8907};
8908
8909TEST_F(InputDispatcherFallbackKeyTest, PolicyNotNotifiedForHandledKey) {
8910 mDispatcher->notifyKey(
8911 KeyArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_KEYBOARD).keyCode(AKEYCODE_A).build());
8912 consumeKey(/*handled=*/true, AllOf(WithKeyAction(ACTION_DOWN), WithKeyCode(AKEYCODE_A)));
8913 ASSERT_NO_FATAL_FAILURE(mFakePolicy->assertUnhandledKeyNotReported());
8914}
8915
8916TEST_F(InputDispatcherFallbackKeyTest, PolicyNotifiedForUnhandledKey) {
8917 mDispatcher->notifyKey(
8918 KeyArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_KEYBOARD).keyCode(AKEYCODE_A).build());
8919 consumeKey(/*handled=*/false, AllOf(WithKeyAction(ACTION_DOWN), WithKeyCode(AKEYCODE_A)));
8920 ASSERT_NO_FATAL_FAILURE(mFakePolicy->assertUnhandledKeyReported(AKEYCODE_A));
8921}
8922
8923TEST_F(InputDispatcherFallbackKeyTest, NoFallbackRequestedByPolicy) {
8924 mDispatcher->notifyKey(
8925 KeyArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_KEYBOARD).keyCode(AKEYCODE_A).build());
8926
8927 // Do not handle this key event.
8928 consumeKey(/*handled=*/false,
8929 AllOf(WithKeyAction(ACTION_DOWN), WithKeyCode(AKEYCODE_A), WithFlags(0)));
8930 ASSERT_NO_FATAL_FAILURE(mFakePolicy->assertUnhandledKeyReported(AKEYCODE_A));
8931
8932 // Since the policy did not request any fallback to be generated, ensure there are no events.
8933 ASSERT_NO_FATAL_FAILURE(mFakePolicy->assertUnhandledKeyNotReported());
8934}
8935
8936TEST_F(InputDispatcherFallbackKeyTest, FallbackDispatchForUnhandledKey) {
8937 setFallback(AKEYCODE_B);
8938 mDispatcher->notifyKey(
8939 KeyArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_KEYBOARD).keyCode(AKEYCODE_A).build());
8940
8941 // Do not handle this key event.
8942 consumeKey(/*handled=*/false,
8943 AllOf(WithKeyAction(ACTION_DOWN), WithKeyCode(AKEYCODE_A), WithFlags(0)));
8944
8945 // Since the key was not handled, ensure the fallback event was dispatched instead.
8946 ASSERT_NO_FATAL_FAILURE(mFakePolicy->assertUnhandledKeyReported(AKEYCODE_A));
8947 consumeKey(/*handled=*/true,
8948 AllOf(WithKeyAction(ACTION_DOWN), WithKeyCode(AKEYCODE_B),
8949 WithFlags(AKEY_EVENT_FLAG_FALLBACK)));
8950
8951 // Release the original key, and ensure the fallback key is also released.
8952 mDispatcher->notifyKey(
8953 KeyArgsBuilder(ACTION_UP, AINPUT_SOURCE_KEYBOARD).keyCode(AKEYCODE_A).build());
8954 consumeKey(/*handled=*/false,
8955 AllOf(WithKeyAction(ACTION_UP), WithKeyCode(AKEYCODE_A), WithFlags(0)));
8956 ASSERT_NO_FATAL_FAILURE(mFakePolicy->assertUnhandledKeyReported(AKEYCODE_A));
8957 consumeKey(/*handled=*/true,
8958 AllOf(WithKeyAction(ACTION_UP), WithKeyCode(AKEYCODE_B),
8959 WithFlags(AKEY_EVENT_FLAG_FALLBACK)));
8960
8961 ASSERT_NO_FATAL_FAILURE(mFakePolicy->assertUnhandledKeyNotReported());
8962 mWindow->assertNoEvents();
8963}
8964
8965TEST_F(InputDispatcherFallbackKeyTest, AppHandlesPreviouslyUnhandledKey) {
8966 setFallback(AKEYCODE_B);
8967 mDispatcher->notifyKey(
8968 KeyArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_KEYBOARD).keyCode(AKEYCODE_A).build());
8969
8970 // Do not handle this key event, but handle the fallback.
8971 consumeKey(/*handled=*/false,
8972 AllOf(WithKeyAction(ACTION_DOWN), WithKeyCode(AKEYCODE_A), WithFlags(0)));
8973 ASSERT_NO_FATAL_FAILURE(mFakePolicy->assertUnhandledKeyReported(AKEYCODE_A));
8974 consumeKey(/*handled=*/true,
8975 AllOf(WithKeyAction(ACTION_DOWN), WithKeyCode(AKEYCODE_B),
8976 WithFlags(AKEY_EVENT_FLAG_FALLBACK)));
8977
8978 // Release the original key, and ensure the fallback key is also released.
8979 mDispatcher->notifyKey(
8980 KeyArgsBuilder(ACTION_UP, AINPUT_SOURCE_KEYBOARD).keyCode(AKEYCODE_A).build());
8981 // But this time, the app handles the original key.
8982 consumeKey(/*handled=*/true,
8983 AllOf(WithKeyAction(ACTION_UP), WithKeyCode(AKEYCODE_A), WithFlags(0)));
8984 ASSERT_NO_FATAL_FAILURE(mFakePolicy->assertUnhandledKeyReported(AKEYCODE_A));
8985 // Ensure the fallback key is canceled.
8986 consumeKey(/*handled=*/true,
8987 AllOf(WithKeyAction(ACTION_UP), WithKeyCode(AKEYCODE_B),
8988 WithFlags(AKEY_EVENT_FLAG_FALLBACK | AKEY_EVENT_FLAG_CANCELED)));
8989
8990 ASSERT_NO_FATAL_FAILURE(mFakePolicy->assertUnhandledKeyNotReported());
8991 mWindow->assertNoEvents();
8992}
8993
8994TEST_F(InputDispatcherFallbackKeyTest, AppDoesNotHandleFallback) {
8995 setFallback(AKEYCODE_B);
8996 mDispatcher->notifyKey(
8997 KeyArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_KEYBOARD).keyCode(AKEYCODE_A).build());
8998
8999 // Do not handle this key event.
9000 consumeKey(/*handled=*/false,
9001 AllOf(WithKeyAction(ACTION_DOWN), WithKeyCode(AKEYCODE_A), WithFlags(0)));
9002 ASSERT_NO_FATAL_FAILURE(mFakePolicy->assertUnhandledKeyReported(AKEYCODE_A));
9003 // App does not handle the fallback either, so ensure another fallback is not generated.
9004 setFallback(AKEYCODE_C);
9005 consumeKey(/*handled=*/false,
9006 AllOf(WithKeyAction(ACTION_DOWN), WithKeyCode(AKEYCODE_B),
9007 WithFlags(AKEY_EVENT_FLAG_FALLBACK)));
9008
9009 // Release the original key, and ensure the fallback key is also released.
9010 setFallback(AKEYCODE_B);
9011 mDispatcher->notifyKey(
9012 KeyArgsBuilder(ACTION_UP, AINPUT_SOURCE_KEYBOARD).keyCode(AKEYCODE_A).build());
9013 consumeKey(/*handled=*/false,
9014 AllOf(WithKeyAction(ACTION_UP), WithKeyCode(AKEYCODE_A), WithFlags(0)));
9015 ASSERT_NO_FATAL_FAILURE(mFakePolicy->assertUnhandledKeyReported(AKEYCODE_A));
9016 consumeKey(/*handled=*/false,
9017 AllOf(WithKeyAction(ACTION_UP), WithKeyCode(AKEYCODE_B),
9018 WithFlags(AKEY_EVENT_FLAG_FALLBACK)));
9019
9020 ASSERT_NO_FATAL_FAILURE(mFakePolicy->assertUnhandledKeyNotReported());
9021 mWindow->assertNoEvents();
9022}
9023
9024TEST_F(InputDispatcherFallbackKeyTest, InconsistentPolicyCancelsFallback) {
9025 setFallback(AKEYCODE_B);
9026 mDispatcher->notifyKey(
9027 KeyArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_KEYBOARD).keyCode(AKEYCODE_A).build());
9028
9029 // Do not handle this key event, so fallback is generated.
9030 consumeKey(/*handled=*/false,
9031 AllOf(WithKeyAction(ACTION_DOWN), WithKeyCode(AKEYCODE_A), WithFlags(0)));
9032 ASSERT_NO_FATAL_FAILURE(mFakePolicy->assertUnhandledKeyReported(AKEYCODE_A));
9033 consumeKey(/*handled=*/true,
9034 AllOf(WithKeyAction(ACTION_DOWN), WithKeyCode(AKEYCODE_B),
9035 WithFlags(AKEY_EVENT_FLAG_FALLBACK)));
9036
9037 // Release the original key, but assume the policy is misbehaving and it
9038 // generates an inconsistent fallback to the one from the DOWN event.
9039 setFallback(AKEYCODE_C);
9040 mDispatcher->notifyKey(
9041 KeyArgsBuilder(ACTION_UP, AINPUT_SOURCE_KEYBOARD).keyCode(AKEYCODE_A).build());
9042 consumeKey(/*handled=*/false,
9043 AllOf(WithKeyAction(ACTION_UP), WithKeyCode(AKEYCODE_A), WithFlags(0)));
9044 ASSERT_NO_FATAL_FAILURE(mFakePolicy->assertUnhandledKeyReported(AKEYCODE_A));
9045 // Ensure the fallback key reported before as DOWN is canceled due to the inconsistency.
9046 consumeKey(/*handled=*/true,
9047 AllOf(WithKeyAction(ACTION_UP), WithKeyCode(AKEYCODE_B),
9048 WithFlags(AKEY_EVENT_FLAG_FALLBACK | AKEY_EVENT_FLAG_CANCELED)));
9049
9050 ASSERT_NO_FATAL_FAILURE(mFakePolicy->assertUnhandledKeyNotReported());
9051 mWindow->assertNoEvents();
9052}
9053
9054TEST_F(InputDispatcherFallbackKeyTest, CanceledKeyCancelsFallback) {
9055 setFallback(AKEYCODE_B);
9056 mDispatcher->notifyKey(
9057 KeyArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_KEYBOARD).keyCode(AKEYCODE_A).build());
9058
9059 // Do not handle this key event, so fallback is generated.
9060 consumeKey(/*handled=*/false,
9061 AllOf(WithKeyAction(ACTION_DOWN), WithKeyCode(AKEYCODE_A), WithFlags(0)));
9062 ASSERT_NO_FATAL_FAILURE(mFakePolicy->assertUnhandledKeyReported(AKEYCODE_A));
9063 consumeKey(/*handled=*/true,
9064 AllOf(WithKeyAction(ACTION_DOWN), WithKeyCode(AKEYCODE_B),
9065 WithFlags(AKEY_EVENT_FLAG_FALLBACK)));
9066
9067 // The original key is canceled.
9068 mDispatcher->notifyKey(KeyArgsBuilder(ACTION_UP, AINPUT_SOURCE_KEYBOARD)
9069 .keyCode(AKEYCODE_A)
9070 .addFlag(AKEY_EVENT_FLAG_CANCELED)
9071 .build());
9072 consumeKey(/*handled=*/false,
9073 AllOf(WithKeyAction(ACTION_UP), WithKeyCode(AKEYCODE_A),
9074 WithFlags(AKEY_EVENT_FLAG_CANCELED)));
9075 ASSERT_NO_FATAL_FAILURE(mFakePolicy->assertUnhandledKeyReported(AKEYCODE_A));
9076 // Ensure the fallback key is also canceled due to the original key being canceled.
9077 consumeKey(/*handled=*/true,
9078 AllOf(WithKeyAction(ACTION_UP), WithKeyCode(AKEYCODE_B),
9079 WithFlags(AKEY_EVENT_FLAG_FALLBACK | AKEY_EVENT_FLAG_CANCELED)));
9080
9081 ASSERT_NO_FATAL_FAILURE(mFakePolicy->assertUnhandledKeyNotReported());
9082 mWindow->assertNoEvents();
9083}
9084
Prabir Pradhanfa2c69f2024-02-01 20:31:34 +00009085TEST_F(InputDispatcherFallbackKeyTest, InputChannelRemovedDuringPolicyCall) {
Prabir Pradhanb13da8f2024-01-09 23:10:13 +00009086 setFallback(AKEYCODE_B);
9087 mDispatcher->notifyKey(
9088 KeyArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_KEYBOARD).keyCode(AKEYCODE_A).build());
9089
9090 // Do not handle this key event.
9091 consumeKey(/*handled=*/false,
9092 AllOf(WithKeyAction(ACTION_DOWN), WithKeyCode(AKEYCODE_A), WithFlags(0)));
9093 ASSERT_NO_FATAL_FAILURE(mFakePolicy->assertUnhandledKeyReported(AKEYCODE_A));
9094 consumeKey(/*handled=*/true,
9095 AllOf(WithKeyAction(ACTION_DOWN), WithKeyCode(AKEYCODE_B),
9096 WithFlags(AKEY_EVENT_FLAG_FALLBACK)));
9097
9098 mFakePolicy->setUnhandledKeyHandler([&](const KeyEvent& event) {
9099 // When the unhandled key is reported to the policy next, remove the input channel.
9100 mDispatcher->removeInputChannel(mWindow->getToken());
9101 return KeyEventBuilder(event).keyCode(AKEYCODE_B).build();
9102 });
9103 // Release the original key, and let the app now handle the previously unhandled key.
9104 // This should result in the previously generated fallback key to be cancelled.
9105 // Since the policy was notified of the unhandled DOWN event earlier, it will also be notified
9106 // of the UP event for consistency. The Dispatcher calls into the policy from its own thread
9107 // without holding the lock, because it need to synchronously fetch the fallback key. While in
9108 // the policy call, we will now remove the input channel. Once the policy call returns, the
9109 // Dispatcher will no longer have a channel to send cancellation events to. Ensure this does
9110 // not cause any crashes.
9111 mDispatcher->notifyKey(
9112 KeyArgsBuilder(ACTION_UP, AINPUT_SOURCE_KEYBOARD).keyCode(AKEYCODE_A).build());
9113 consumeKey(/*handled=*/true,
9114 AllOf(WithKeyAction(ACTION_UP), WithKeyCode(AKEYCODE_A), WithFlags(0)));
9115 ASSERT_NO_FATAL_FAILURE(mFakePolicy->assertUnhandledKeyReported(AKEYCODE_A));
9116}
9117
Prabir Pradhanfa2c69f2024-02-01 20:31:34 +00009118TEST_F(InputDispatcherFallbackKeyTest, WindowRemovedDuringPolicyCall) {
9119 setFallback(AKEYCODE_B);
9120 mDispatcher->notifyKey(
9121 KeyArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_KEYBOARD).keyCode(AKEYCODE_A).build());
9122
9123 // Do not handle this key event.
9124 consumeKey(/*handled=*/false,
9125 AllOf(WithKeyAction(ACTION_DOWN), WithKeyCode(AKEYCODE_A), WithFlags(0)));
9126 ASSERT_NO_FATAL_FAILURE(mFakePolicy->assertUnhandledKeyReported(AKEYCODE_A));
9127 consumeKey(/*handled=*/true,
9128 AllOf(WithKeyAction(ACTION_DOWN), WithKeyCode(AKEYCODE_B),
9129 WithFlags(AKEY_EVENT_FLAG_FALLBACK)));
9130
9131 mFakePolicy->setUnhandledKeyHandler([&](const KeyEvent& event) {
9132 // When the unhandled key is reported to the policy next, remove the window.
9133 mDispatcher->onWindowInfosChanged({{}, {}, 0, 0});
9134 return KeyEventBuilder(event).keyCode(AKEYCODE_B).build();
9135 });
9136 // Release the original key, which the app will not handle. When this unhandled key is reported
9137 // to the policy, the window will be removed.
9138 mDispatcher->notifyKey(
9139 KeyArgsBuilder(ACTION_UP, AINPUT_SOURCE_KEYBOARD).keyCode(AKEYCODE_A).build());
9140 consumeKey(/*handled=*/false,
9141 AllOf(WithKeyAction(ACTION_UP), WithKeyCode(AKEYCODE_A), WithFlags(0)));
9142 ASSERT_NO_FATAL_FAILURE(mFakePolicy->assertUnhandledKeyReported(AKEYCODE_A));
9143
9144 // Since the window was removed, it loses focus, and the channel state will be reset.
9145 consumeKey(/*handled=*/true,
9146 AllOf(WithKeyAction(ACTION_UP), WithKeyCode(AKEYCODE_B),
9147 WithFlags(AKEY_EVENT_FLAG_FALLBACK | AKEY_EVENT_FLAG_CANCELED)));
9148 mWindow->consumeFocusEvent(false);
9149 mWindow->assertNoEvents();
9150}
9151
9152TEST_F(InputDispatcherFallbackKeyTest, WindowRemovedWhileAwaitingFinishedSignal) {
9153 setFallback(AKEYCODE_B);
9154 mDispatcher->notifyKey(
9155 KeyArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_KEYBOARD).keyCode(AKEYCODE_A).build());
9156
9157 // Do not handle this key event.
9158 consumeKey(/*handled=*/false,
9159 AllOf(WithKeyAction(ACTION_DOWN), WithKeyCode(AKEYCODE_A), WithFlags(0)));
9160 ASSERT_NO_FATAL_FAILURE(mFakePolicy->assertUnhandledKeyReported(AKEYCODE_A));
9161 const auto [seq, event] = mWindow->receiveEvent();
9162 ASSERT_TRUE(seq.has_value() && event != nullptr) << "Failed to receive fallback event";
9163 ASSERT_EQ(event->getType(), InputEventType::KEY);
9164 ASSERT_THAT(static_cast<const KeyEvent&>(*event),
9165 AllOf(WithKeyAction(ACTION_DOWN), WithKeyCode(AKEYCODE_B),
9166 WithFlags(AKEY_EVENT_FLAG_FALLBACK)));
9167
9168 // Remove the window now, which should generate a cancellations and make the window lose focus.
9169 mDispatcher->onWindowInfosChanged({{}, {}, 0, 0});
9170 consumeKey(/*handled=*/true,
9171 AllOf(WithKeyAction(ACTION_UP), WithKeyCode(AKEYCODE_A),
9172 WithFlags(AKEY_EVENT_FLAG_CANCELED)));
9173 consumeKey(/*handled=*/true,
9174 AllOf(WithKeyAction(ACTION_UP), WithKeyCode(AKEYCODE_B),
9175 WithFlags(AKEY_EVENT_FLAG_FALLBACK | AKEY_EVENT_FLAG_CANCELED)));
9176 mWindow->consumeFocusEvent(false);
9177
9178 // Finish the event by reporting it as handled.
9179 mWindow->finishEvent(*seq);
9180 mWindow->assertNoEvents();
9181}
9182
Garfield Tan1c7bc862020-01-28 13:24:04 -08009183class InputDispatcherKeyRepeatTest : public InputDispatcherTest {
9184protected:
Siarhei Vishniakoufa2a0492023-11-14 13:13:18 -08009185 static constexpr std::chrono::nanoseconds KEY_REPEAT_TIMEOUT = 40ms;
9186 static constexpr std::chrono::nanoseconds KEY_REPEAT_DELAY = 40ms;
Garfield Tan1c7bc862020-01-28 13:24:04 -08009187
Chris Yea209fde2020-07-22 13:54:51 -07009188 std::shared_ptr<FakeApplicationHandle> mApp;
Garfield Tan1c7bc862020-01-28 13:24:04 -08009189 sp<FakeWindowHandle> mWindow;
9190
9191 virtual void SetUp() override {
Prabir Pradhandae52792023-12-15 07:36:40 +00009192 InputDispatcherTest::SetUp();
Garfield Tan1c7bc862020-01-28 13:24:04 -08009193
Prabir Pradhandae52792023-12-15 07:36:40 +00009194 mDispatcher->setKeyRepeatConfiguration(KEY_REPEAT_TIMEOUT, KEY_REPEAT_DELAY);
Garfield Tan1c7bc862020-01-28 13:24:04 -08009195 setUpWindow();
9196 }
9197
9198 void setUpWindow() {
Chris Yea209fde2020-07-22 13:54:51 -07009199 mApp = std::make_shared<FakeApplicationHandle>();
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07009200 mWindow = sp<FakeWindowHandle>::make(mApp, mDispatcher, "Fake Window",
9201 ui::LogicalDisplayId::DEFAULT);
Garfield Tan1c7bc862020-01-28 13:24:04 -08009202
Vishnu Nair47074b82020-08-14 11:54:47 -07009203 mWindow->setFocusable(true);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07009204 mDispatcher->onWindowInfosChanged({{*mWindow->getInfo()}, {}, 0, 0});
Vishnu Nair958da932020-08-21 17:12:37 -07009205 setFocusedWindow(mWindow);
Garfield Tan1c7bc862020-01-28 13:24:04 -08009206 mWindow->consumeFocusEvent(true);
9207 }
9208
Chris Ye2ad95392020-09-01 13:44:44 -07009209 void sendAndConsumeKeyDown(int32_t deviceId) {
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07009210 NotifyKeyArgs keyArgs =
9211 generateKeyArgs(AKEY_EVENT_ACTION_DOWN, ui::LogicalDisplayId::DEFAULT);
Chris Ye2ad95392020-09-01 13:44:44 -07009212 keyArgs.deviceId = deviceId;
Garfield Tan1c7bc862020-01-28 13:24:04 -08009213 keyArgs.policyFlags |= POLICY_FLAG_TRUSTED; // Otherwise it won't generate repeat event
Prabir Pradhan678438e2023-04-13 19:32:51 +00009214 mDispatcher->notifyKey(keyArgs);
Garfield Tan1c7bc862020-01-28 13:24:04 -08009215
9216 // Window should receive key down event.
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07009217 mWindow->consumeKeyDown(ui::LogicalDisplayId::DEFAULT);
Garfield Tan1c7bc862020-01-28 13:24:04 -08009218 }
9219
9220 void expectKeyRepeatOnce(int32_t repeatCount) {
9221 SCOPED_TRACE(StringPrintf("Checking event with repeat count %" PRId32, repeatCount));
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07009222 mWindow->consumeKeyEvent(
9223 AllOf(WithKeyAction(AKEY_EVENT_ACTION_DOWN), WithRepeatCount(repeatCount)));
Garfield Tan1c7bc862020-01-28 13:24:04 -08009224 }
9225
Chris Ye2ad95392020-09-01 13:44:44 -07009226 void sendAndConsumeKeyUp(int32_t deviceId) {
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07009227 NotifyKeyArgs keyArgs =
9228 generateKeyArgs(AKEY_EVENT_ACTION_UP, ui::LogicalDisplayId::DEFAULT);
Chris Ye2ad95392020-09-01 13:44:44 -07009229 keyArgs.deviceId = deviceId;
Garfield Tan1c7bc862020-01-28 13:24:04 -08009230 keyArgs.policyFlags |= POLICY_FLAG_TRUSTED; // Unless it won't generate repeat event
Prabir Pradhan678438e2023-04-13 19:32:51 +00009231 mDispatcher->notifyKey(keyArgs);
Garfield Tan1c7bc862020-01-28 13:24:04 -08009232
9233 // Window should receive key down event.
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07009234 mWindow->consumeKeyUp(ui::LogicalDisplayId::DEFAULT,
Harry Cutts33476232023-01-30 19:57:29 +00009235 /*expectedFlags=*/0);
Garfield Tan1c7bc862020-01-28 13:24:04 -08009236 }
Hu Guofe3c8f12023-09-22 17:20:15 +08009237
9238 void injectKeyRepeat(int32_t repeatCount) {
9239 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07009240 injectKey(*mDispatcher, AKEY_EVENT_ACTION_DOWN, repeatCount,
9241 ui::LogicalDisplayId::DEFAULT))
Hu Guofe3c8f12023-09-22 17:20:15 +08009242 << "Inject key event should return InputEventInjectionResult::SUCCEEDED";
9243 }
Garfield Tan1c7bc862020-01-28 13:24:04 -08009244};
9245
9246TEST_F(InputDispatcherKeyRepeatTest, FocusedWindow_ReceivesKeyRepeat) {
Harry Cutts33476232023-01-30 19:57:29 +00009247 sendAndConsumeKeyDown(/*deviceId=*/1);
Chris Ye2ad95392020-09-01 13:44:44 -07009248 for (int32_t repeatCount = 1; repeatCount <= 10; ++repeatCount) {
9249 expectKeyRepeatOnce(repeatCount);
9250 }
9251}
9252
9253TEST_F(InputDispatcherKeyRepeatTest, FocusedWindow_ReceivesKeyRepeatFromTwoDevices) {
Harry Cutts33476232023-01-30 19:57:29 +00009254 sendAndConsumeKeyDown(/*deviceId=*/1);
Chris Ye2ad95392020-09-01 13:44:44 -07009255 for (int32_t repeatCount = 1; repeatCount <= 10; ++repeatCount) {
9256 expectKeyRepeatOnce(repeatCount);
9257 }
Harry Cutts33476232023-01-30 19:57:29 +00009258 sendAndConsumeKeyDown(/*deviceId=*/2);
Chris Ye2ad95392020-09-01 13:44:44 -07009259 /* repeatCount will start from 1 for deviceId 2 */
Garfield Tan1c7bc862020-01-28 13:24:04 -08009260 for (int32_t repeatCount = 1; repeatCount <= 10; ++repeatCount) {
9261 expectKeyRepeatOnce(repeatCount);
9262 }
9263}
9264
9265TEST_F(InputDispatcherKeyRepeatTest, FocusedWindow_StopsKeyRepeatAfterUp) {
Harry Cutts33476232023-01-30 19:57:29 +00009266 sendAndConsumeKeyDown(/*deviceId=*/1);
9267 expectKeyRepeatOnce(/*repeatCount=*/1);
9268 sendAndConsumeKeyUp(/*deviceId=*/1);
Chris Ye2ad95392020-09-01 13:44:44 -07009269 mWindow->assertNoEvents();
9270}
9271
9272TEST_F(InputDispatcherKeyRepeatTest, FocusedWindow_KeyRepeatAfterStaleDeviceKeyUp) {
Harry Cutts33476232023-01-30 19:57:29 +00009273 sendAndConsumeKeyDown(/*deviceId=*/1);
9274 expectKeyRepeatOnce(/*repeatCount=*/1);
9275 sendAndConsumeKeyDown(/*deviceId=*/2);
9276 expectKeyRepeatOnce(/*repeatCount=*/1);
Chris Ye2ad95392020-09-01 13:44:44 -07009277 // Stale key up from device 1.
Harry Cutts33476232023-01-30 19:57:29 +00009278 sendAndConsumeKeyUp(/*deviceId=*/1);
Chris Ye2ad95392020-09-01 13:44:44 -07009279 // Device 2 is still down, keep repeating
Harry Cutts33476232023-01-30 19:57:29 +00009280 expectKeyRepeatOnce(/*repeatCount=*/2);
9281 expectKeyRepeatOnce(/*repeatCount=*/3);
Chris Ye2ad95392020-09-01 13:44:44 -07009282 // Device 2 key up
Harry Cutts33476232023-01-30 19:57:29 +00009283 sendAndConsumeKeyUp(/*deviceId=*/2);
Chris Ye2ad95392020-09-01 13:44:44 -07009284 mWindow->assertNoEvents();
9285}
9286
9287TEST_F(InputDispatcherKeyRepeatTest, FocusedWindow_KeyRepeatStopsAfterRepeatingKeyUp) {
Harry Cutts33476232023-01-30 19:57:29 +00009288 sendAndConsumeKeyDown(/*deviceId=*/1);
9289 expectKeyRepeatOnce(/*repeatCount=*/1);
9290 sendAndConsumeKeyDown(/*deviceId=*/2);
9291 expectKeyRepeatOnce(/*repeatCount=*/1);
Chris Ye2ad95392020-09-01 13:44:44 -07009292 // Device 2 which holds the key repeating goes up, expect the repeating to stop.
Harry Cutts33476232023-01-30 19:57:29 +00009293 sendAndConsumeKeyUp(/*deviceId=*/2);
Chris Ye2ad95392020-09-01 13:44:44 -07009294 // Device 1 still holds key down, but the repeating was already stopped
Garfield Tan1c7bc862020-01-28 13:24:04 -08009295 mWindow->assertNoEvents();
9296}
9297
liushenxiang42232912021-05-21 20:24:09 +08009298TEST_F(InputDispatcherKeyRepeatTest, FocusedWindow_StopsKeyRepeatAfterDisableInputDevice) {
9299 sendAndConsumeKeyDown(DEVICE_ID);
Harry Cutts33476232023-01-30 19:57:29 +00009300 expectKeyRepeatOnce(/*repeatCount=*/1);
Prabir Pradhan678438e2023-04-13 19:32:51 +00009301 mDispatcher->notifyDeviceReset({/*id=*/10, /*eventTime=*/20, DEVICE_ID});
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07009302 mWindow->consumeKeyUp(ui::LogicalDisplayId::DEFAULT,
liushenxiang42232912021-05-21 20:24:09 +08009303 AKEY_EVENT_FLAG_CANCELED | AKEY_EVENT_FLAG_LONG_PRESS);
9304 mWindow->assertNoEvents();
9305}
9306
Garfield Tan1c7bc862020-01-28 13:24:04 -08009307TEST_F(InputDispatcherKeyRepeatTest, FocusedWindow_RepeatKeyEventsUseEventIdFromInputDispatcher) {
Michael Wrighte1cbbd62023-02-22 19:32:13 +00009308 GTEST_SKIP() << "Flaky test (b/270393106)";
Harry Cutts33476232023-01-30 19:57:29 +00009309 sendAndConsumeKeyDown(/*deviceId=*/1);
Garfield Tan1c7bc862020-01-28 13:24:04 -08009310 for (int32_t repeatCount = 1; repeatCount <= 10; ++repeatCount) {
Siarhei Vishniakoud3061ab2023-12-18 20:41:08 -08009311 std::unique_ptr<KeyEvent> repeatEvent = mWindow->consumeKey();
9312 ASSERT_NE(nullptr, repeatEvent);
Garfield Tan1c7bc862020-01-28 13:24:04 -08009313 EXPECT_EQ(IdGenerator::Source::INPUT_DISPATCHER,
Siarhei Vishniakoud3061ab2023-12-18 20:41:08 -08009314 IdGenerator::getSource(repeatEvent->getId()));
Garfield Tan1c7bc862020-01-28 13:24:04 -08009315 }
9316}
9317
9318TEST_F(InputDispatcherKeyRepeatTest, FocusedWindow_RepeatKeyEventsUseUniqueEventId) {
Michael Wrighte1cbbd62023-02-22 19:32:13 +00009319 GTEST_SKIP() << "Flaky test (b/270393106)";
Harry Cutts33476232023-01-30 19:57:29 +00009320 sendAndConsumeKeyDown(/*deviceId=*/1);
Garfield Tan1c7bc862020-01-28 13:24:04 -08009321
9322 std::unordered_set<int32_t> idSet;
9323 for (int32_t repeatCount = 1; repeatCount <= 10; ++repeatCount) {
Siarhei Vishniakoud3061ab2023-12-18 20:41:08 -08009324 std::unique_ptr<KeyEvent> repeatEvent = mWindow->consumeKey();
9325 ASSERT_NE(nullptr, repeatEvent);
9326 int32_t id = repeatEvent->getId();
Garfield Tan1c7bc862020-01-28 13:24:04 -08009327 EXPECT_EQ(idSet.end(), idSet.find(id));
9328 idSet.insert(id);
9329 }
9330}
9331
Hu Guofe3c8f12023-09-22 17:20:15 +08009332TEST_F(InputDispatcherKeyRepeatTest, FocusedWindow_CorrectRepeatCountWhenInjectKeyRepeat) {
9333 injectKeyRepeat(0);
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07009334 mWindow->consumeKeyDown(ui::LogicalDisplayId::DEFAULT);
Hu Guofe3c8f12023-09-22 17:20:15 +08009335 for (int32_t repeatCount = 1; repeatCount <= 2; ++repeatCount) {
9336 expectKeyRepeatOnce(repeatCount);
9337 }
9338 injectKeyRepeat(1);
9339 // Expect repeatCount to be 3 instead of 1
9340 expectKeyRepeatOnce(3);
9341}
9342
Arthur Hung2fbf37f2018-09-13 18:16:41 +08009343/* Test InputDispatcher for MultiDisplay */
9344class InputDispatcherFocusOnTwoDisplaysTest : public InputDispatcherTest {
9345public:
Prabir Pradhan3608aad2019-10-02 17:08:26 -07009346 virtual void SetUp() override {
Arthur Hung2fbf37f2018-09-13 18:16:41 +08009347 InputDispatcherTest::SetUp();
Arthur Hungb92218b2018-08-14 12:00:21 +08009348
Chris Yea209fde2020-07-22 13:54:51 -07009349 application1 = std::make_shared<FakeApplicationHandle>();
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07009350 windowInPrimary = sp<FakeWindowHandle>::make(application1, mDispatcher, "D_1",
9351 ui::LogicalDisplayId::DEFAULT);
Siarhei Vishniakoub9b15352019-11-26 13:19:26 -08009352
Arthur Hung2fbf37f2018-09-13 18:16:41 +08009353 // Set focus window for primary display, but focused display would be second one.
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07009354 mDispatcher->setFocusedApplication(ui::LogicalDisplayId::DEFAULT, application1);
Vishnu Nair47074b82020-08-14 11:54:47 -07009355 windowInPrimary->setFocusable(true);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07009356 mDispatcher->onWindowInfosChanged({{*windowInPrimary->getInfo()}, {}, 0, 0});
9357
Vishnu Nair958da932020-08-21 17:12:37 -07009358 setFocusedWindow(windowInPrimary);
Siarhei Vishniakouf1035d42019-09-20 16:32:01 +01009359 windowInPrimary->consumeFocusEvent(true);
Arthur Hungb92218b2018-08-14 12:00:21 +08009360
Chris Yea209fde2020-07-22 13:54:51 -07009361 application2 = std::make_shared<FakeApplicationHandle>();
Siarhei Vishniakou870ecec2020-12-09 08:07:46 -10009362 windowInSecondary =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07009363 sp<FakeWindowHandle>::make(application2, mDispatcher, "D_2", SECOND_DISPLAY_ID);
Arthur Hung2fbf37f2018-09-13 18:16:41 +08009364 // Set focus to second display window.
Arthur Hung2fbf37f2018-09-13 18:16:41 +08009365 // Set focus display to second one.
9366 mDispatcher->setFocusedDisplay(SECOND_DISPLAY_ID);
Arpit Singhb65e2bd2024-06-03 09:48:16 +00009367 mFakePolicy->assertFocusedDisplayNotified(SECOND_DISPLAY_ID);
9368
Arthur Hung2fbf37f2018-09-13 18:16:41 +08009369 // Set focus window for second display.
9370 mDispatcher->setFocusedApplication(SECOND_DISPLAY_ID, application2);
Vishnu Nair47074b82020-08-14 11:54:47 -07009371 windowInSecondary->setFocusable(true);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07009372 mDispatcher->onWindowInfosChanged(
9373 {{*windowInPrimary->getInfo(), *windowInSecondary->getInfo()}, {}, 0, 0});
Vishnu Nair958da932020-08-21 17:12:37 -07009374 setFocusedWindow(windowInSecondary);
Siarhei Vishniakouf1035d42019-09-20 16:32:01 +01009375 windowInSecondary->consumeFocusEvent(true);
Arthur Hung2fbf37f2018-09-13 18:16:41 +08009376 }
9377
Prabir Pradhan3608aad2019-10-02 17:08:26 -07009378 virtual void TearDown() override {
Arthur Hung2fbf37f2018-09-13 18:16:41 +08009379 InputDispatcherTest::TearDown();
9380
Chris Yea209fde2020-07-22 13:54:51 -07009381 application1.reset();
Arthur Hung2fbf37f2018-09-13 18:16:41 +08009382 windowInPrimary.clear();
Chris Yea209fde2020-07-22 13:54:51 -07009383 application2.reset();
Arthur Hung2fbf37f2018-09-13 18:16:41 +08009384 windowInSecondary.clear();
9385 }
9386
9387protected:
Chris Yea209fde2020-07-22 13:54:51 -07009388 std::shared_ptr<FakeApplicationHandle> application1;
Arthur Hung2fbf37f2018-09-13 18:16:41 +08009389 sp<FakeWindowHandle> windowInPrimary;
Chris Yea209fde2020-07-22 13:54:51 -07009390 std::shared_ptr<FakeApplicationHandle> application2;
Arthur Hung2fbf37f2018-09-13 18:16:41 +08009391 sp<FakeWindowHandle> windowInSecondary;
9392};
9393
9394TEST_F(InputDispatcherFocusOnTwoDisplaysTest, SetInputWindow_MultiDisplayTouch) {
9395 // Test touch down on primary display.
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08009396 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07009397 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN,
9398 ui::LogicalDisplayId::DEFAULT))
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08009399 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07009400 windowInPrimary->consumeMotionDown(ui::LogicalDisplayId::DEFAULT);
Arthur Hungb92218b2018-08-14 12:00:21 +08009401 windowInSecondary->assertNoEvents();
9402
Arthur Hung2fbf37f2018-09-13 18:16:41 +08009403 // Test touch down on second display.
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08009404 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07009405 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, SECOND_DISPLAY_ID))
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08009406 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
Arthur Hungb92218b2018-08-14 12:00:21 +08009407 windowInPrimary->assertNoEvents();
Siarhei Vishniakouc5ca85c2019-11-15 17:20:00 -08009408 windowInSecondary->consumeMotionDown(SECOND_DISPLAY_ID);
Arthur Hungb92218b2018-08-14 12:00:21 +08009409}
9410
Arthur Hung2fbf37f2018-09-13 18:16:41 +08009411TEST_F(InputDispatcherFocusOnTwoDisplaysTest, SetInputWindow_MultiDisplayFocus) {
Tiger Huang721e26f2018-07-24 22:26:19 +08009412 // Test inject a key down with display id specified.
Prabir Pradhan93f342c2021-03-11 15:05:30 -08009413 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07009414 injectKeyDownNoRepeat(*mDispatcher, ui::LogicalDisplayId::DEFAULT))
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08009415 << "Inject key event should return InputEventInjectionResult::SUCCEEDED";
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07009416 windowInPrimary->consumeKeyDown(ui::LogicalDisplayId::DEFAULT);
Tiger Huang721e26f2018-07-24 22:26:19 +08009417 windowInSecondary->assertNoEvents();
9418
9419 // Test inject a key down without display id specified.
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07009420 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectKeyDownNoRepeat(*mDispatcher))
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08009421 << "Inject key event should return InputEventInjectionResult::SUCCEEDED";
Arthur Hungb92218b2018-08-14 12:00:21 +08009422 windowInPrimary->assertNoEvents();
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07009423 windowInSecondary->consumeKeyDown(ui::LogicalDisplayId::INVALID);
Arthur Hungb92218b2018-08-14 12:00:21 +08009424
Siarhei Vishniakoub9b15352019-11-26 13:19:26 -08009425 // Remove all windows in secondary display.
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07009426 mDispatcher->onWindowInfosChanged({{*windowInPrimary->getInfo()}, {}, 0, 0});
Arthur Hungb92218b2018-08-14 12:00:21 +08009427
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08009428 // Old focus should receive a cancel event.
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07009429 windowInSecondary->consumeKeyUp(ui::LogicalDisplayId::INVALID, AKEY_EVENT_FLAG_CANCELED);
Arthur Hungb92218b2018-08-14 12:00:21 +08009430
9431 // Test inject a key down, should timeout because of no target window.
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07009432 ASSERT_NO_FATAL_FAILURE(assertInjectedKeyTimesOut(*mDispatcher));
Arthur Hungb92218b2018-08-14 12:00:21 +08009433 windowInPrimary->assertNoEvents();
Siarhei Vishniakouf1035d42019-09-20 16:32:01 +01009434 windowInSecondary->consumeFocusEvent(false);
Arthur Hungb92218b2018-08-14 12:00:21 +08009435 windowInSecondary->assertNoEvents();
9436}
9437
Arthur Hung2fbf37f2018-09-13 18:16:41 +08009438// Test per-display input monitors for motion event.
9439TEST_F(InputDispatcherFocusOnTwoDisplaysTest, MonitorMotionEvent_MultiDisplay) {
chaviwd1c23182019-12-20 18:44:56 -08009440 FakeMonitorReceiver monitorInPrimary =
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07009441 FakeMonitorReceiver(*mDispatcher, "M_1", ui::LogicalDisplayId::DEFAULT);
chaviwd1c23182019-12-20 18:44:56 -08009442 FakeMonitorReceiver monitorInSecondary =
Prabir Pradhanfb549072023-10-05 19:17:36 +00009443 FakeMonitorReceiver(*mDispatcher, "M_2", SECOND_DISPLAY_ID);
Arthur Hung2fbf37f2018-09-13 18:16:41 +08009444
9445 // Test touch down on primary display.
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08009446 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07009447 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN,
9448 ui::LogicalDisplayId::DEFAULT))
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08009449 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07009450 windowInPrimary->consumeMotionDown(ui::LogicalDisplayId::DEFAULT);
9451 monitorInPrimary.consumeMotionDown(ui::LogicalDisplayId::DEFAULT);
Arthur Hung2fbf37f2018-09-13 18:16:41 +08009452 windowInSecondary->assertNoEvents();
chaviwd1c23182019-12-20 18:44:56 -08009453 monitorInSecondary.assertNoEvents();
Arthur Hung2fbf37f2018-09-13 18:16:41 +08009454
9455 // Test touch down on second display.
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08009456 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07009457 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, SECOND_DISPLAY_ID))
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08009458 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
Arthur Hung2fbf37f2018-09-13 18:16:41 +08009459 windowInPrimary->assertNoEvents();
chaviwd1c23182019-12-20 18:44:56 -08009460 monitorInPrimary.assertNoEvents();
Siarhei Vishniakouc5ca85c2019-11-15 17:20:00 -08009461 windowInSecondary->consumeMotionDown(SECOND_DISPLAY_ID);
chaviwd1c23182019-12-20 18:44:56 -08009462 monitorInSecondary.consumeMotionDown(SECOND_DISPLAY_ID);
Arthur Hung2fbf37f2018-09-13 18:16:41 +08009463
Siarhei Vishniakou92c8fd52023-01-29 14:57:43 -08009464 // Lift up the touch from the second display
9465 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07009466 injectMotionUp(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, SECOND_DISPLAY_ID))
Siarhei Vishniakou92c8fd52023-01-29 14:57:43 -08009467 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
9468 windowInSecondary->consumeMotionUp(SECOND_DISPLAY_ID);
9469 monitorInSecondary.consumeMotionUp(SECOND_DISPLAY_ID);
9470
Arthur Hung2fbf37f2018-09-13 18:16:41 +08009471 // Test inject a non-pointer motion event.
9472 // If specific a display, it will dispatch to the focused window of particular display,
9473 // or it will dispatch to the focused window of focused display.
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08009474 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07009475 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TRACKBALL,
9476 ui::LogicalDisplayId::INVALID))
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08009477 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
Arthur Hung2fbf37f2018-09-13 18:16:41 +08009478 windowInPrimary->assertNoEvents();
chaviwd1c23182019-12-20 18:44:56 -08009479 monitorInPrimary.assertNoEvents();
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07009480 windowInSecondary->consumeMotionDown(ui::LogicalDisplayId::INVALID);
9481 monitorInSecondary.consumeMotionDown(ui::LogicalDisplayId::INVALID);
Arthur Hung2fbf37f2018-09-13 18:16:41 +08009482}
9483
9484// Test per-display input monitors for key event.
9485TEST_F(InputDispatcherFocusOnTwoDisplaysTest, MonitorKeyEvent_MultiDisplay) {
Siarhei Vishniakou870ecec2020-12-09 08:07:46 -10009486 // Input monitor per display.
chaviwd1c23182019-12-20 18:44:56 -08009487 FakeMonitorReceiver monitorInPrimary =
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07009488 FakeMonitorReceiver(*mDispatcher, "M_1", ui::LogicalDisplayId::DEFAULT);
chaviwd1c23182019-12-20 18:44:56 -08009489 FakeMonitorReceiver monitorInSecondary =
Prabir Pradhanfb549072023-10-05 19:17:36 +00009490 FakeMonitorReceiver(*mDispatcher, "M_2", SECOND_DISPLAY_ID);
Arthur Hung2fbf37f2018-09-13 18:16:41 +08009491
9492 // Test inject a key down.
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07009493 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectKeyDown(*mDispatcher))
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08009494 << "Inject key event should return InputEventInjectionResult::SUCCEEDED";
Arthur Hung2fbf37f2018-09-13 18:16:41 +08009495 windowInPrimary->assertNoEvents();
chaviwd1c23182019-12-20 18:44:56 -08009496 monitorInPrimary.assertNoEvents();
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07009497 windowInSecondary->consumeKeyDown(ui::LogicalDisplayId::INVALID);
9498 monitorInSecondary.consumeKeyDown(ui::LogicalDisplayId::INVALID);
Arthur Hung2fbf37f2018-09-13 18:16:41 +08009499}
9500
Vishnu Nair958da932020-08-21 17:12:37 -07009501TEST_F(InputDispatcherFocusOnTwoDisplaysTest, CanFocusWindowOnUnfocusedDisplay) {
9502 sp<FakeWindowHandle> secondWindowInPrimary =
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07009503 sp<FakeWindowHandle>::make(application1, mDispatcher, "D_1_W2",
9504 ui::LogicalDisplayId::DEFAULT);
Vishnu Nair958da932020-08-21 17:12:37 -07009505 secondWindowInPrimary->setFocusable(true);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07009506 mDispatcher->onWindowInfosChanged(
9507 {{*windowInPrimary->getInfo(), *secondWindowInPrimary->getInfo(),
9508 *windowInSecondary->getInfo()},
9509 {},
9510 0,
9511 0});
Vishnu Nair958da932020-08-21 17:12:37 -07009512 setFocusedWindow(secondWindowInPrimary);
9513 windowInPrimary->consumeFocusEvent(false);
9514 secondWindowInPrimary->consumeFocusEvent(true);
9515
9516 // Test inject a key down.
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07009517 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07009518 injectKeyDown(*mDispatcher, ui::LogicalDisplayId::DEFAULT))
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08009519 << "Inject key event should return InputEventInjectionResult::SUCCEEDED";
Vishnu Nair958da932020-08-21 17:12:37 -07009520 windowInPrimary->assertNoEvents();
9521 windowInSecondary->assertNoEvents();
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07009522 secondWindowInPrimary->consumeKeyDown(ui::LogicalDisplayId::DEFAULT);
Vishnu Nair958da932020-08-21 17:12:37 -07009523}
9524
Arthur Hungdfd528e2021-12-08 13:23:04 +00009525TEST_F(InputDispatcherFocusOnTwoDisplaysTest, CancelTouch_MultiDisplay) {
9526 FakeMonitorReceiver monitorInPrimary =
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07009527 FakeMonitorReceiver(*mDispatcher, "M_1", ui::LogicalDisplayId::DEFAULT);
Arthur Hungdfd528e2021-12-08 13:23:04 +00009528 FakeMonitorReceiver monitorInSecondary =
Prabir Pradhanfb549072023-10-05 19:17:36 +00009529 FakeMonitorReceiver(*mDispatcher, "M_2", SECOND_DISPLAY_ID);
Arthur Hungdfd528e2021-12-08 13:23:04 +00009530
9531 // Test touch down on primary display.
9532 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07009533 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN,
9534 ui::LogicalDisplayId::DEFAULT))
Arthur Hungdfd528e2021-12-08 13:23:04 +00009535 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07009536 windowInPrimary->consumeMotionDown(ui::LogicalDisplayId::DEFAULT);
9537 monitorInPrimary.consumeMotionDown(ui::LogicalDisplayId::DEFAULT);
Arthur Hungdfd528e2021-12-08 13:23:04 +00009538
9539 // Test touch down on second display.
9540 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07009541 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, SECOND_DISPLAY_ID))
Arthur Hungdfd528e2021-12-08 13:23:04 +00009542 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
9543 windowInSecondary->consumeMotionDown(SECOND_DISPLAY_ID);
9544 monitorInSecondary.consumeMotionDown(SECOND_DISPLAY_ID);
9545
9546 // Trigger cancel touch.
9547 mDispatcher->cancelCurrentTouch();
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07009548 windowInPrimary->consumeMotionCancel(ui::LogicalDisplayId::DEFAULT);
9549 monitorInPrimary.consumeMotionCancel(ui::LogicalDisplayId::DEFAULT);
Arthur Hungdfd528e2021-12-08 13:23:04 +00009550 windowInSecondary->consumeMotionCancel(SECOND_DISPLAY_ID);
9551 monitorInSecondary.consumeMotionCancel(SECOND_DISPLAY_ID);
9552
9553 // Test inject a move motion event, no window/monitor should receive the event.
9554 ASSERT_EQ(InputEventInjectionResult::FAILED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07009555 injectMotionEvent(*mDispatcher, AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN,
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07009556 ui::LogicalDisplayId::DEFAULT, {110, 200}))
Arthur Hungdfd528e2021-12-08 13:23:04 +00009557 << "Inject motion event should return InputEventInjectionResult::FAILED";
9558 windowInPrimary->assertNoEvents();
9559 monitorInPrimary.assertNoEvents();
9560
9561 ASSERT_EQ(InputEventInjectionResult::FAILED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07009562 injectMotionEvent(*mDispatcher, AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN,
Arthur Hungdfd528e2021-12-08 13:23:04 +00009563 SECOND_DISPLAY_ID, {110, 200}))
9564 << "Inject motion event should return InputEventInjectionResult::FAILED";
9565 windowInSecondary->assertNoEvents();
9566 monitorInSecondary.assertNoEvents();
9567}
9568
Hu Guocb134f12023-12-23 13:42:44 +00009569/**
9570 * Send a key to the primary display and to the secondary display.
9571 * Then cause the key on the primary display to be canceled by sending in a stale key.
9572 * Ensure that the key on the primary display is canceled, and that the key on the secondary display
9573 * does not get canceled.
9574 */
9575TEST_F(InputDispatcherFocusOnTwoDisplaysTest, WhenDropKeyEvent_OnlyCancelCorrespondingKeyGesture) {
9576 // Send a key down on primary display
9577 mDispatcher->notifyKey(
9578 KeyArgsBuilder(AKEY_EVENT_ACTION_DOWN, AINPUT_SOURCE_KEYBOARD)
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07009579 .displayId(ui::LogicalDisplayId::DEFAULT)
Hu Guocb134f12023-12-23 13:42:44 +00009580 .policyFlags(DEFAULT_POLICY_FLAGS | POLICY_FLAG_DISABLE_KEY_REPEAT)
9581 .build());
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07009582 windowInPrimary->consumeKeyEvent(AllOf(WithKeyAction(AKEY_EVENT_ACTION_DOWN),
9583 WithDisplayId(ui::LogicalDisplayId::DEFAULT)));
Hu Guocb134f12023-12-23 13:42:44 +00009584 windowInSecondary->assertNoEvents();
9585
9586 // Send a key down on second display
9587 mDispatcher->notifyKey(
9588 KeyArgsBuilder(AKEY_EVENT_ACTION_DOWN, AINPUT_SOURCE_KEYBOARD)
9589 .displayId(SECOND_DISPLAY_ID)
9590 .policyFlags(DEFAULT_POLICY_FLAGS | POLICY_FLAG_DISABLE_KEY_REPEAT)
9591 .build());
9592 windowInSecondary->consumeKeyEvent(
9593 AllOf(WithKeyAction(AKEY_EVENT_ACTION_DOWN), WithDisplayId(SECOND_DISPLAY_ID)));
9594 windowInPrimary->assertNoEvents();
9595
9596 // Send a valid key up event on primary display that will be dropped because it is stale
9597 NotifyKeyArgs staleKeyUp =
9598 KeyArgsBuilder(AKEY_EVENT_ACTION_UP, AINPUT_SOURCE_KEYBOARD)
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07009599 .displayId(ui::LogicalDisplayId::DEFAULT)
Hu Guocb134f12023-12-23 13:42:44 +00009600 .policyFlags(DEFAULT_POLICY_FLAGS | POLICY_FLAG_DISABLE_KEY_REPEAT)
9601 .build();
9602 static constexpr std::chrono::duration STALE_EVENT_TIMEOUT = 10ms;
9603 mFakePolicy->setStaleEventTimeout(STALE_EVENT_TIMEOUT);
9604 std::this_thread::sleep_for(STALE_EVENT_TIMEOUT);
9605 mDispatcher->notifyKey(staleKeyUp);
9606
9607 // Only the key gesture corresponding to the dropped event should receive the cancel event.
9608 // Therefore, windowInPrimary should get the cancel event and windowInSecondary should not
9609 // receive any events.
9610 windowInPrimary->consumeKeyEvent(AllOf(WithKeyAction(AKEY_EVENT_ACTION_UP),
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07009611 WithDisplayId(ui::LogicalDisplayId::DEFAULT),
Hu Guocb134f12023-12-23 13:42:44 +00009612 WithFlags(AKEY_EVENT_FLAG_CANCELED)));
9613 windowInSecondary->assertNoEvents();
9614}
9615
9616/**
9617 * Similar to 'WhenDropKeyEvent_OnlyCancelCorrespondingKeyGesture' but for motion events.
9618 */
9619TEST_F(InputDispatcherFocusOnTwoDisplaysTest, WhenDropMotionEvent_OnlyCancelCorrespondingGesture) {
9620 // Send touch down on primary display.
9621 mDispatcher->notifyMotion(
9622 MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
9623 .pointer(PointerBuilder(/*id=*/0, ToolType::FINGER).x(100).y(200))
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07009624 .displayId(ui::LogicalDisplayId::DEFAULT)
Hu Guocb134f12023-12-23 13:42:44 +00009625 .build());
9626 windowInPrimary->consumeMotionEvent(
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07009627 AllOf(WithMotionAction(ACTION_DOWN), WithDisplayId(ui::LogicalDisplayId::DEFAULT)));
Hu Guocb134f12023-12-23 13:42:44 +00009628 windowInSecondary->assertNoEvents();
9629
9630 // Send touch down on second display.
9631 mDispatcher->notifyMotion(
9632 MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
9633 .pointer(PointerBuilder(/*id=*/0, ToolType::FINGER).x(100).y(200))
9634 .displayId(SECOND_DISPLAY_ID)
9635 .build());
9636 windowInPrimary->assertNoEvents();
9637 windowInSecondary->consumeMotionEvent(
9638 AllOf(WithMotionAction(ACTION_DOWN), WithDisplayId(SECOND_DISPLAY_ID)));
9639
9640 // inject a valid MotionEvent on primary display that will be stale when it arrives.
9641 NotifyMotionArgs staleMotionUp =
9642 MotionArgsBuilder(ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN)
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07009643 .displayId(ui::LogicalDisplayId::DEFAULT)
Hu Guocb134f12023-12-23 13:42:44 +00009644 .pointer(PointerBuilder(/*id=*/0, ToolType::FINGER).x(100).y(200))
9645 .build();
9646 static constexpr std::chrono::duration STALE_EVENT_TIMEOUT = 10ms;
9647 mFakePolicy->setStaleEventTimeout(STALE_EVENT_TIMEOUT);
9648 std::this_thread::sleep_for(STALE_EVENT_TIMEOUT);
9649 mDispatcher->notifyMotion(staleMotionUp);
9650
9651 // For stale motion events, we let the gesture to complete. This behaviour is different from key
9652 // events, where we would cancel the current keys instead.
9653 windowInPrimary->consumeMotionEvent(WithMotionAction(ACTION_UP));
9654 windowInSecondary->assertNoEvents();
9655}
9656
Jackal Guof9696682018-10-05 12:23:23 +08009657class InputFilterTest : public InputDispatcherTest {
9658protected:
Linnan Li13bf76a2024-05-05 19:18:02 +08009659 void testNotifyMotion(ui::LogicalDisplayId displayId, bool expectToBeFiltered,
Prabir Pradhan81420cc2021-09-06 10:28:50 -07009660 const ui::Transform& transform = ui::Transform()) {
Jackal Guof9696682018-10-05 12:23:23 +08009661 NotifyMotionArgs motionArgs;
9662
Siarhei Vishniakou870ecec2020-12-09 08:07:46 -10009663 motionArgs =
9664 generateMotionArgs(AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN, displayId);
Prabir Pradhan678438e2023-04-13 19:32:51 +00009665 mDispatcher->notifyMotion(motionArgs);
Siarhei Vishniakou870ecec2020-12-09 08:07:46 -10009666 motionArgs =
9667 generateMotionArgs(AMOTION_EVENT_ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN, displayId);
Prabir Pradhan678438e2023-04-13 19:32:51 +00009668 mDispatcher->notifyMotion(motionArgs);
Siarhei Vishniakou2bfa9052019-11-21 18:10:54 -08009669 ASSERT_TRUE(mDispatcher->waitForIdle());
Jackal Guof9696682018-10-05 12:23:23 +08009670 if (expectToBeFiltered) {
Siarhei Vishniakou3218fc02023-06-15 20:41:02 -07009671 const auto xy = transform.transform(motionArgs.pointerCoords[0].getXYValue());
Prabir Pradhan81420cc2021-09-06 10:28:50 -07009672 mFakePolicy->assertFilterInputEventWasCalled(motionArgs, xy);
Jackal Guof9696682018-10-05 12:23:23 +08009673 } else {
9674 mFakePolicy->assertFilterInputEventWasNotCalled();
9675 }
9676 }
9677
9678 void testNotifyKey(bool expectToBeFiltered) {
9679 NotifyKeyArgs keyArgs;
9680
9681 keyArgs = generateKeyArgs(AKEY_EVENT_ACTION_DOWN);
Prabir Pradhan678438e2023-04-13 19:32:51 +00009682 mDispatcher->notifyKey(keyArgs);
Jackal Guof9696682018-10-05 12:23:23 +08009683 keyArgs = generateKeyArgs(AKEY_EVENT_ACTION_UP);
Prabir Pradhan678438e2023-04-13 19:32:51 +00009684 mDispatcher->notifyKey(keyArgs);
Siarhei Vishniakou2bfa9052019-11-21 18:10:54 -08009685 ASSERT_TRUE(mDispatcher->waitForIdle());
Jackal Guof9696682018-10-05 12:23:23 +08009686
9687 if (expectToBeFiltered) {
Siarhei Vishniakou8935a802019-11-15 16:41:44 -08009688 mFakePolicy->assertFilterInputEventWasCalled(keyArgs);
Jackal Guof9696682018-10-05 12:23:23 +08009689 } else {
9690 mFakePolicy->assertFilterInputEventWasNotCalled();
9691 }
9692 }
9693};
9694
9695// Test InputFilter for MotionEvent
9696TEST_F(InputFilterTest, MotionEvent_InputFilter) {
9697 // Since the InputFilter is disabled by default, check if touch events aren't filtered.
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07009698 testNotifyMotion(ui::LogicalDisplayId::DEFAULT, /*expectToBeFiltered=*/false);
Harry Cutts101ee9b2023-07-06 18:04:14 +00009699 testNotifyMotion(SECOND_DISPLAY_ID, /*expectToBeFiltered=*/false);
Jackal Guof9696682018-10-05 12:23:23 +08009700
9701 // Enable InputFilter
9702 mDispatcher->setInputFilterEnabled(true);
9703 // Test touch on both primary and second display, and check if both events are filtered.
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07009704 testNotifyMotion(ui::LogicalDisplayId::DEFAULT, /*expectToBeFiltered=*/true);
Harry Cutts101ee9b2023-07-06 18:04:14 +00009705 testNotifyMotion(SECOND_DISPLAY_ID, /*expectToBeFiltered=*/true);
Jackal Guof9696682018-10-05 12:23:23 +08009706
9707 // Disable InputFilter
9708 mDispatcher->setInputFilterEnabled(false);
9709 // Test touch on both primary and second display, and check if both events aren't filtered.
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07009710 testNotifyMotion(ui::LogicalDisplayId::DEFAULT, /*expectToBeFiltered=*/false);
Harry Cutts101ee9b2023-07-06 18:04:14 +00009711 testNotifyMotion(SECOND_DISPLAY_ID, /*expectToBeFiltered=*/false);
Jackal Guof9696682018-10-05 12:23:23 +08009712}
9713
9714// Test InputFilter for KeyEvent
9715TEST_F(InputFilterTest, KeyEvent_InputFilter) {
9716 // Since the InputFilter is disabled by default, check if key event aren't filtered.
Harry Cutts101ee9b2023-07-06 18:04:14 +00009717 testNotifyKey(/*expectToBeFiltered=*/false);
Jackal Guof9696682018-10-05 12:23:23 +08009718
9719 // Enable InputFilter
9720 mDispatcher->setInputFilterEnabled(true);
9721 // Send a key event, and check if it is filtered.
Harry Cutts101ee9b2023-07-06 18:04:14 +00009722 testNotifyKey(/*expectToBeFiltered=*/true);
Jackal Guof9696682018-10-05 12:23:23 +08009723
9724 // Disable InputFilter
9725 mDispatcher->setInputFilterEnabled(false);
9726 // Send a key event, and check if it isn't filtered.
Harry Cutts101ee9b2023-07-06 18:04:14 +00009727 testNotifyKey(/*expectToBeFiltered=*/false);
Jackal Guof9696682018-10-05 12:23:23 +08009728}
9729
Prabir Pradhan81420cc2021-09-06 10:28:50 -07009730// Ensure that MotionEvents sent to the InputFilter through InputListener are converted to the
9731// logical display coordinate space.
9732TEST_F(InputFilterTest, MotionEvent_UsesLogicalDisplayCoordinates_notifyMotion) {
9733 ui::Transform firstDisplayTransform;
9734 firstDisplayTransform.set({1.1, 2.2, 3.3, 4.4, 5.5, 6.6, 0, 0, 1});
9735 ui::Transform secondDisplayTransform;
9736 secondDisplayTransform.set({-6.6, -5.5, -4.4, -3.3, -2.2, -1.1, 0, 0, 1});
9737
9738 std::vector<gui::DisplayInfo> displayInfos(2);
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07009739 displayInfos[0].displayId = ui::LogicalDisplayId::DEFAULT;
Prabir Pradhan81420cc2021-09-06 10:28:50 -07009740 displayInfos[0].transform = firstDisplayTransform;
9741 displayInfos[1].displayId = SECOND_DISPLAY_ID;
9742 displayInfos[1].transform = secondDisplayTransform;
9743
Patrick Williamsd828f302023-04-28 17:52:08 -05009744 mDispatcher->onWindowInfosChanged({{}, displayInfos, 0, 0});
Prabir Pradhan81420cc2021-09-06 10:28:50 -07009745
9746 // Enable InputFilter
9747 mDispatcher->setInputFilterEnabled(true);
9748
9749 // Ensure the correct transforms are used for the displays.
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07009750 testNotifyMotion(ui::LogicalDisplayId::DEFAULT, /*expectToBeFiltered=*/true,
9751 firstDisplayTransform);
Harry Cutts101ee9b2023-07-06 18:04:14 +00009752 testNotifyMotion(SECOND_DISPLAY_ID, /*expectToBeFiltered=*/true, secondDisplayTransform);
Prabir Pradhan81420cc2021-09-06 10:28:50 -07009753}
9754
Siarhei Vishniakou5d552c42021-05-21 05:02:22 +00009755class InputFilterInjectionPolicyTest : public InputDispatcherTest {
9756protected:
9757 virtual void SetUp() override {
9758 InputDispatcherTest::SetUp();
9759
9760 /**
9761 * We don't need to enable input filter to test the injected event policy, but we enabled it
9762 * here to make the tests more realistic, since this policy only matters when inputfilter is
9763 * on.
9764 */
9765 mDispatcher->setInputFilterEnabled(true);
9766
9767 std::shared_ptr<InputApplicationHandle> application =
9768 std::make_shared<FakeApplicationHandle>();
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07009769 mWindow = sp<FakeWindowHandle>::make(application, mDispatcher, "Test Window",
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07009770 ui::LogicalDisplayId::DEFAULT);
Siarhei Vishniakou5d552c42021-05-21 05:02:22 +00009771
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07009772 mDispatcher->setFocusedApplication(ui::LogicalDisplayId::DEFAULT, application);
Siarhei Vishniakou5d552c42021-05-21 05:02:22 +00009773 mWindow->setFocusable(true);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07009774 mDispatcher->onWindowInfosChanged({{*mWindow->getInfo()}, {}, 0, 0});
Siarhei Vishniakou5d552c42021-05-21 05:02:22 +00009775 setFocusedWindow(mWindow);
9776 mWindow->consumeFocusEvent(true);
9777 }
9778
Siarhei Vishniakouf00a4ec2021-06-16 03:55:32 +00009779 void testInjectedKey(int32_t policyFlags, int32_t injectedDeviceId, int32_t resolvedDeviceId,
9780 int32_t flags) {
Siarhei Vishniakou5d552c42021-05-21 05:02:22 +00009781 KeyEvent event;
9782
9783 const nsecs_t eventTime = systemTime(SYSTEM_TIME_MONOTONIC);
9784 event.initialize(InputEvent::nextId(), injectedDeviceId, AINPUT_SOURCE_KEYBOARD,
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07009785 ui::LogicalDisplayId::INVALID, INVALID_HMAC, AKEY_EVENT_ACTION_DOWN, 0,
9786 AKEYCODE_A, KEY_A, AMETA_NONE, /*repeatCount=*/0, eventTime, eventTime);
Siarhei Vishniakou5d552c42021-05-21 05:02:22 +00009787 const int32_t additionalPolicyFlags =
9788 POLICY_FLAG_PASS_TO_USER | POLICY_FLAG_DISABLE_KEY_REPEAT;
9789 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Harry Cutts33476232023-01-30 19:57:29 +00009790 mDispatcher->injectInputEvent(&event, /*targetUid=*/{},
Siarhei Vishniakou4648fea2023-06-27 01:00:12 +00009791 InputEventInjectionSync::WAIT_FOR_RESULT, 100ms,
Siarhei Vishniakou5d552c42021-05-21 05:02:22 +00009792 policyFlags | additionalPolicyFlags));
9793
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07009794 mWindow->consumeKeyEvent(AllOf(WithDeviceId(resolvedDeviceId), WithFlags(flags)));
Siarhei Vishniakouf00a4ec2021-06-16 03:55:32 +00009795 }
9796
9797 void testInjectedMotion(int32_t policyFlags, int32_t injectedDeviceId, int32_t resolvedDeviceId,
9798 int32_t flags) {
9799 MotionEvent event;
9800 PointerProperties pointerProperties[1];
9801 PointerCoords pointerCoords[1];
9802 pointerProperties[0].clear();
9803 pointerProperties[0].id = 0;
9804 pointerCoords[0].clear();
9805 pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_X, 300);
9806 pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_Y, 400);
9807
9808 ui::Transform identityTransform;
9809 const nsecs_t eventTime = systemTime(SYSTEM_TIME_MONOTONIC);
9810 event.initialize(InputEvent::nextId(), injectedDeviceId, AINPUT_SOURCE_TOUCHSCREEN,
9811 DISPLAY_ID, INVALID_HMAC, AMOTION_EVENT_ACTION_DOWN, 0, 0,
9812 AMOTION_EVENT_EDGE_FLAG_NONE, AMETA_NONE, 0, MotionClassification::NONE,
9813 identityTransform, 0, 0, AMOTION_EVENT_INVALID_CURSOR_POSITION,
Prabir Pradhanb9b18502021-08-26 12:30:32 -07009814 AMOTION_EVENT_INVALID_CURSOR_POSITION, identityTransform, eventTime,
Evan Rosky09576692021-07-01 12:22:09 -07009815 eventTime,
Harry Cutts101ee9b2023-07-06 18:04:14 +00009816 /*pointerCount=*/1, pointerProperties, pointerCoords);
Siarhei Vishniakouf00a4ec2021-06-16 03:55:32 +00009817
9818 const int32_t additionalPolicyFlags = POLICY_FLAG_PASS_TO_USER;
9819 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Harry Cutts33476232023-01-30 19:57:29 +00009820 mDispatcher->injectInputEvent(&event, /*targetUid=*/{},
Siarhei Vishniakou4648fea2023-06-27 01:00:12 +00009821 InputEventInjectionSync::WAIT_FOR_RESULT, 100ms,
Siarhei Vishniakouf00a4ec2021-06-16 03:55:32 +00009822 policyFlags | additionalPolicyFlags));
9823
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07009824 mWindow->consumeMotionEvent(AllOf(WithFlags(flags), WithDeviceId(resolvedDeviceId)));
Siarhei Vishniakou5d552c42021-05-21 05:02:22 +00009825 }
9826
9827private:
9828 sp<FakeWindowHandle> mWindow;
9829};
9830
9831TEST_F(InputFilterInjectionPolicyTest, TrustedFilteredEvents_KeepOriginalDeviceId) {
Siarhei Vishniakouf00a4ec2021-06-16 03:55:32 +00009832 // Must have POLICY_FLAG_FILTERED here to indicate that the event has gone through the input
9833 // filter. Without it, the event will no different from a regularly injected event, and the
9834 // injected device id will be overwritten.
Harry Cutts33476232023-01-30 19:57:29 +00009835 testInjectedKey(POLICY_FLAG_FILTERED, /*injectedDeviceId=*/3, /*resolvedDeviceId=*/3,
9836 /*flags=*/0);
Siarhei Vishniakou5d552c42021-05-21 05:02:22 +00009837}
9838
Siarhei Vishniakouf00a4ec2021-06-16 03:55:32 +00009839TEST_F(InputFilterInjectionPolicyTest, KeyEventsInjectedFromAccessibility_HaveAccessibilityFlag) {
Siarhei Vishniakou5d552c42021-05-21 05:02:22 +00009840 testInjectedKey(POLICY_FLAG_FILTERED | POLICY_FLAG_INJECTED_FROM_ACCESSIBILITY,
Harry Cutts33476232023-01-30 19:57:29 +00009841 /*injectedDeviceId=*/3, /*resolvedDeviceId=*/3,
Siarhei Vishniakouf00a4ec2021-06-16 03:55:32 +00009842 AKEY_EVENT_FLAG_IS_ACCESSIBILITY_EVENT);
9843}
9844
9845TEST_F(InputFilterInjectionPolicyTest,
9846 MotionEventsInjectedFromAccessibility_HaveAccessibilityFlag) {
9847 testInjectedMotion(POLICY_FLAG_FILTERED | POLICY_FLAG_INJECTED_FROM_ACCESSIBILITY,
Harry Cutts33476232023-01-30 19:57:29 +00009848 /*injectedDeviceId=*/3, /*resolvedDeviceId=*/3,
Siarhei Vishniakouf00a4ec2021-06-16 03:55:32 +00009849 AMOTION_EVENT_FLAG_IS_ACCESSIBILITY_EVENT);
Siarhei Vishniakou5d552c42021-05-21 05:02:22 +00009850}
9851
9852TEST_F(InputFilterInjectionPolicyTest, RegularInjectedEvents_ReceiveVirtualDeviceId) {
Harry Cutts33476232023-01-30 19:57:29 +00009853 testInjectedKey(/*policyFlags=*/0, /*injectedDeviceId=*/3,
9854 /*resolvedDeviceId=*/VIRTUAL_KEYBOARD_ID, /*flags=*/0);
Siarhei Vishniakou5d552c42021-05-21 05:02:22 +00009855}
9856
Yeabkal Wubshitb8aadfa2024-01-17 17:03:42 -08009857class InputDispatcherUserActivityPokeTests : public InputDispatcherTest {
9858protected:
9859 virtual void SetUp() override {
9860 InputDispatcherTest::SetUp();
9861
9862 std::shared_ptr<FakeApplicationHandle> application =
9863 std::make_shared<FakeApplicationHandle>();
9864 application->setDispatchingTimeout(100ms);
9865 mWindow = sp<FakeWindowHandle>::make(application, mDispatcher, "TestWindow",
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07009866 ui::LogicalDisplayId::DEFAULT);
Yeabkal Wubshit222d83d2024-01-24 18:00:09 +00009867 mWindow->setFrame(Rect(0, 0, 100, 100));
Yeabkal Wubshitb8aadfa2024-01-17 17:03:42 -08009868 mWindow->setDispatchingTimeout(100ms);
9869 mWindow->setFocusable(true);
9870
9871 // Set focused application.
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07009872 mDispatcher->setFocusedApplication(ui::LogicalDisplayId::DEFAULT, application);
Yeabkal Wubshitb8aadfa2024-01-17 17:03:42 -08009873
9874 mDispatcher->onWindowInfosChanged({{*mWindow->getInfo()}, {}, 0, 0});
9875 setFocusedWindow(mWindow);
9876 mWindow->consumeFocusEvent(true);
9877 }
9878
Linnan Li13bf76a2024-05-05 19:18:02 +08009879 void notifyAndConsumeMotion(int32_t action, uint32_t source, ui::LogicalDisplayId displayId,
Yeabkal Wubshitb8aadfa2024-01-17 17:03:42 -08009880 nsecs_t eventTime) {
9881 mDispatcher->notifyMotion(MotionArgsBuilder(action, source)
9882 .displayId(displayId)
9883 .eventTime(eventTime)
9884 .pointer(PointerBuilder(0, ToolType::FINGER).x(50).y(50))
9885 .build());
9886 mWindow->consumeMotionEvent(WithMotionAction(action));
9887 }
9888
9889private:
9890 sp<FakeWindowHandle> mWindow;
9891};
9892
9893TEST_F_WITH_FLAGS(
9894 InputDispatcherUserActivityPokeTests, MinPokeTimeObserved,
9895 REQUIRES_FLAGS_ENABLED(ACONFIG_FLAG(com::android::input::flags,
9896 rate_limit_user_activity_poke_in_dispatcher))) {
9897 mDispatcher->setMinTimeBetweenUserActivityPokes(50ms);
9898
9899 // First event of type TOUCH. Should poke.
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07009900 notifyAndConsumeMotion(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN, ui::LogicalDisplayId::DEFAULT,
Yeabkal Wubshitb8aadfa2024-01-17 17:03:42 -08009901 milliseconds_to_nanoseconds(50));
9902 mFakePolicy->assertUserActivityPoked(
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07009903 {{milliseconds_to_nanoseconds(50), USER_ACTIVITY_EVENT_TOUCH,
9904 ui::LogicalDisplayId::DEFAULT}});
Yeabkal Wubshitb8aadfa2024-01-17 17:03:42 -08009905
9906 // 80ns > 50ns has passed since previous TOUCH event. Should poke.
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07009907 notifyAndConsumeMotion(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN, ui::LogicalDisplayId::DEFAULT,
Yeabkal Wubshitb8aadfa2024-01-17 17:03:42 -08009908 milliseconds_to_nanoseconds(130));
9909 mFakePolicy->assertUserActivityPoked(
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07009910 {{milliseconds_to_nanoseconds(130), USER_ACTIVITY_EVENT_TOUCH,
9911 ui::LogicalDisplayId::DEFAULT}});
Yeabkal Wubshitb8aadfa2024-01-17 17:03:42 -08009912
9913 // First event of type OTHER. Should poke (despite being within 50ns of previous TOUCH event).
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07009914 notifyAndConsumeMotion(ACTION_SCROLL, AINPUT_SOURCE_ROTARY_ENCODER,
9915 ui::LogicalDisplayId::DEFAULT, milliseconds_to_nanoseconds(135));
Yeabkal Wubshitb8aadfa2024-01-17 17:03:42 -08009916 mFakePolicy->assertUserActivityPoked(
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07009917 {{milliseconds_to_nanoseconds(135), USER_ACTIVITY_EVENT_OTHER,
9918 ui::LogicalDisplayId::DEFAULT}});
Yeabkal Wubshitb8aadfa2024-01-17 17:03:42 -08009919
9920 // Within 50ns of previous TOUCH event. Should NOT poke.
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07009921 notifyAndConsumeMotion(ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN, ui::LogicalDisplayId::DEFAULT,
Yeabkal Wubshitb8aadfa2024-01-17 17:03:42 -08009922 milliseconds_to_nanoseconds(140));
9923 mFakePolicy->assertUserActivityNotPoked();
9924
9925 // Within 50ns of previous OTHER event. Should NOT poke.
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07009926 notifyAndConsumeMotion(ACTION_SCROLL, AINPUT_SOURCE_ROTARY_ENCODER,
9927 ui::LogicalDisplayId::DEFAULT, milliseconds_to_nanoseconds(150));
Yeabkal Wubshitb8aadfa2024-01-17 17:03:42 -08009928 mFakePolicy->assertUserActivityNotPoked();
9929
9930 // Within 50ns of previous TOUCH event (which was at time 130). Should NOT poke.
9931 // Note that STYLUS is mapped to TOUCH user activity, since it's a pointer-type source.
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07009932 notifyAndConsumeMotion(ACTION_DOWN, AINPUT_SOURCE_STYLUS, ui::LogicalDisplayId::DEFAULT,
Yeabkal Wubshitb8aadfa2024-01-17 17:03:42 -08009933 milliseconds_to_nanoseconds(160));
9934 mFakePolicy->assertUserActivityNotPoked();
9935
9936 // 65ns > 50ns has passed since previous OTHER event. Should poke.
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07009937 notifyAndConsumeMotion(ACTION_SCROLL, AINPUT_SOURCE_ROTARY_ENCODER,
9938 ui::LogicalDisplayId::DEFAULT, milliseconds_to_nanoseconds(200));
Yeabkal Wubshitb8aadfa2024-01-17 17:03:42 -08009939 mFakePolicy->assertUserActivityPoked(
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07009940 {{milliseconds_to_nanoseconds(200), USER_ACTIVITY_EVENT_OTHER,
9941 ui::LogicalDisplayId::DEFAULT}});
Yeabkal Wubshitb8aadfa2024-01-17 17:03:42 -08009942
9943 // 170ns > 50ns has passed since previous TOUCH event. Should poke.
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07009944 notifyAndConsumeMotion(ACTION_UP, AINPUT_SOURCE_STYLUS, ui::LogicalDisplayId::DEFAULT,
Yeabkal Wubshitb8aadfa2024-01-17 17:03:42 -08009945 milliseconds_to_nanoseconds(300));
9946 mFakePolicy->assertUserActivityPoked(
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07009947 {{milliseconds_to_nanoseconds(300), USER_ACTIVITY_EVENT_TOUCH,
9948 ui::LogicalDisplayId::DEFAULT}});
Yeabkal Wubshitb8aadfa2024-01-17 17:03:42 -08009949
9950 // Assert that there's no more user activity poke event.
9951 mFakePolicy->assertUserActivityNotPoked();
9952}
9953
9954TEST_F_WITH_FLAGS(
9955 InputDispatcherUserActivityPokeTests, DefaultMinPokeTimeOf100MsUsed,
9956 REQUIRES_FLAGS_ENABLED(ACONFIG_FLAG(com::android::input::flags,
9957 rate_limit_user_activity_poke_in_dispatcher))) {
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07009958 notifyAndConsumeMotion(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN, ui::LogicalDisplayId::DEFAULT,
Yeabkal Wubshitb8aadfa2024-01-17 17:03:42 -08009959 milliseconds_to_nanoseconds(200));
9960 mFakePolicy->assertUserActivityPoked(
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07009961 {{milliseconds_to_nanoseconds(200), USER_ACTIVITY_EVENT_TOUCH,
9962 ui::LogicalDisplayId::DEFAULT}});
Yeabkal Wubshitb8aadfa2024-01-17 17:03:42 -08009963
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07009964 notifyAndConsumeMotion(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN, ui::LogicalDisplayId::DEFAULT,
Yeabkal Wubshitb8aadfa2024-01-17 17:03:42 -08009965 milliseconds_to_nanoseconds(280));
9966 mFakePolicy->assertUserActivityNotPoked();
9967
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07009968 notifyAndConsumeMotion(ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN, ui::LogicalDisplayId::DEFAULT,
Yeabkal Wubshitb8aadfa2024-01-17 17:03:42 -08009969 milliseconds_to_nanoseconds(340));
9970 mFakePolicy->assertUserActivityPoked(
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07009971 {{milliseconds_to_nanoseconds(340), USER_ACTIVITY_EVENT_TOUCH,
9972 ui::LogicalDisplayId::DEFAULT}});
Yeabkal Wubshitb8aadfa2024-01-17 17:03:42 -08009973}
9974
9975TEST_F_WITH_FLAGS(
9976 InputDispatcherUserActivityPokeTests, ZeroMinPokeTimeDisablesRateLimiting,
9977 REQUIRES_FLAGS_ENABLED(ACONFIG_FLAG(com::android::input::flags,
9978 rate_limit_user_activity_poke_in_dispatcher))) {
9979 mDispatcher->setMinTimeBetweenUserActivityPokes(0ms);
9980
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07009981 notifyAndConsumeMotion(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN, ui::LogicalDisplayId::DEFAULT,
9982 20);
Yeabkal Wubshitb8aadfa2024-01-17 17:03:42 -08009983 mFakePolicy->assertUserActivityPoked();
9984
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07009985 notifyAndConsumeMotion(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN, ui::LogicalDisplayId::DEFAULT,
9986 30);
Yeabkal Wubshitb8aadfa2024-01-17 17:03:42 -08009987 mFakePolicy->assertUserActivityPoked();
9988}
9989
chaviwfd6d3512019-03-25 13:23:49 -07009990class InputDispatcherOnPointerDownOutsideFocus : public InputDispatcherTest {
Prabir Pradhan3608aad2019-10-02 17:08:26 -07009991 virtual void SetUp() override {
chaviwfd6d3512019-03-25 13:23:49 -07009992 InputDispatcherTest::SetUp();
9993
Chris Yea209fde2020-07-22 13:54:51 -07009994 std::shared_ptr<FakeApplicationHandle> application =
9995 std::make_shared<FakeApplicationHandle>();
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -07009996 mUnfocusedWindow = sp<FakeWindowHandle>::make(application, mDispatcher, "Top",
9997 ui::LogicalDisplayId::DEFAULT);
chaviwfd6d3512019-03-25 13:23:49 -07009998 mUnfocusedWindow->setFrame(Rect(0, 0, 30, 30));
chaviwfd6d3512019-03-25 13:23:49 -07009999
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -070010000 mFocusedWindow = sp<FakeWindowHandle>::make(application, mDispatcher, "Second",
10001 ui::LogicalDisplayId::DEFAULT);
Siarhei Vishniakoub9b15352019-11-26 13:19:26 -080010002 mFocusedWindow->setFrame(Rect(50, 50, 100, 100));
chaviwfd6d3512019-03-25 13:23:49 -070010003
10004 // Set focused application.
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -070010005 mDispatcher->setFocusedApplication(ui::LogicalDisplayId::DEFAULT, application);
Vishnu Nair47074b82020-08-14 11:54:47 -070010006 mFocusedWindow->setFocusable(true);
chaviwfd6d3512019-03-25 13:23:49 -070010007
10008 // Expect one focus window exist in display.
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070010009 mDispatcher->onWindowInfosChanged(
10010 {{*mUnfocusedWindow->getInfo(), *mFocusedWindow->getInfo()}, {}, 0, 0});
Vishnu Nair958da932020-08-21 17:12:37 -070010011 setFocusedWindow(mFocusedWindow);
Siarhei Vishniakouf1035d42019-09-20 16:32:01 +010010012 mFocusedWindow->consumeFocusEvent(true);
chaviwfd6d3512019-03-25 13:23:49 -070010013 }
10014
Prabir Pradhan3608aad2019-10-02 17:08:26 -070010015 virtual void TearDown() override {
chaviwfd6d3512019-03-25 13:23:49 -070010016 InputDispatcherTest::TearDown();
10017
10018 mUnfocusedWindow.clear();
Siarhei Vishniakoub9b15352019-11-26 13:19:26 -080010019 mFocusedWindow.clear();
chaviwfd6d3512019-03-25 13:23:49 -070010020 }
10021
10022protected:
10023 sp<FakeWindowHandle> mUnfocusedWindow;
Siarhei Vishniakoub9b15352019-11-26 13:19:26 -080010024 sp<FakeWindowHandle> mFocusedWindow;
Siarhei Vishniakoufb9fcda2020-05-04 14:59:19 -070010025 static constexpr PointF FOCUSED_WINDOW_TOUCH_POINT = {60, 60};
chaviwfd6d3512019-03-25 13:23:49 -070010026};
10027
10028// Have two windows, one with focus. Inject MotionEvent with source TOUCHSCREEN and action
10029// DOWN on the window that doesn't have focus. Ensure the window that didn't have focus received
10030// the onPointerDownOutsideFocus callback.
10031TEST_F(InputDispatcherOnPointerDownOutsideFocus, OnPointerDownOutsideFocus_Success) {
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -080010032 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -070010033 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN,
10034 ui::LogicalDisplayId::DEFAULT, {20, 20}))
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -080010035 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
Siarhei Vishniakou03aee2a2020-04-13 20:44:54 -070010036 mUnfocusedWindow->consumeMotionDown();
chaviwfd6d3512019-03-25 13:23:49 -070010037
Siarhei Vishniakou2bfa9052019-11-21 18:10:54 -080010038 ASSERT_TRUE(mDispatcher->waitForIdle());
chaviwfd6d3512019-03-25 13:23:49 -070010039 mFakePolicy->assertOnPointerDownEquals(mUnfocusedWindow->getToken());
10040}
10041
10042// Have two windows, one with focus. Inject MotionEvent with source TRACKBALL and action
10043// DOWN on the window that doesn't have focus. Ensure no window received the
10044// onPointerDownOutsideFocus callback.
10045TEST_F(InputDispatcherOnPointerDownOutsideFocus, OnPointerDownOutsideFocus_NonPointerSource) {
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -080010046 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -070010047 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TRACKBALL, ui::LogicalDisplayId::DEFAULT,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070010048 {20, 20}))
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -080010049 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
Siarhei Vishniakou03aee2a2020-04-13 20:44:54 -070010050 mFocusedWindow->consumeMotionDown();
chaviwfd6d3512019-03-25 13:23:49 -070010051
Siarhei Vishniakou2bfa9052019-11-21 18:10:54 -080010052 ASSERT_TRUE(mDispatcher->waitForIdle());
10053 mFakePolicy->assertOnPointerDownWasNotCalled();
chaviwfd6d3512019-03-25 13:23:49 -070010054}
10055
10056// Have two windows, one with focus. Inject KeyEvent with action DOWN on the window that doesn't
10057// have focus. Ensure no window received the onPointerDownOutsideFocus callback.
10058TEST_F(InputDispatcherOnPointerDownOutsideFocus, OnPointerDownOutsideFocus_NonMotionFailure) {
Prabir Pradhan93f342c2021-03-11 15:05:30 -080010059 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -070010060 injectKeyDownNoRepeat(*mDispatcher, ui::LogicalDisplayId::DEFAULT))
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -080010061 << "Inject key event should return InputEventInjectionResult::SUCCEEDED";
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -070010062 mFocusedWindow->consumeKeyDown(ui::LogicalDisplayId::DEFAULT);
chaviwfd6d3512019-03-25 13:23:49 -070010063
Siarhei Vishniakou2bfa9052019-11-21 18:10:54 -080010064 ASSERT_TRUE(mDispatcher->waitForIdle());
10065 mFakePolicy->assertOnPointerDownWasNotCalled();
chaviwfd6d3512019-03-25 13:23:49 -070010066}
10067
10068// Have two windows, one with focus. Inject MotionEvent with source TOUCHSCREEN and action
10069// DOWN on the window that already has focus. Ensure no window received the
10070// onPointerDownOutsideFocus callback.
Siarhei Vishniakou870ecec2020-12-09 08:07:46 -100010071TEST_F(InputDispatcherOnPointerDownOutsideFocus, OnPointerDownOutsideFocus_OnAlreadyFocusedWindow) {
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -080010072 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -070010073 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN,
10074 ui::LogicalDisplayId::DEFAULT, FOCUSED_WINDOW_TOUCH_POINT))
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -080010075 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
Siarhei Vishniakou03aee2a2020-04-13 20:44:54 -070010076 mFocusedWindow->consumeMotionDown();
chaviwfd6d3512019-03-25 13:23:49 -070010077
Siarhei Vishniakou2bfa9052019-11-21 18:10:54 -080010078 ASSERT_TRUE(mDispatcher->waitForIdle());
10079 mFakePolicy->assertOnPointerDownWasNotCalled();
chaviwfd6d3512019-03-25 13:23:49 -070010080}
10081
Prabir Pradhan47cf0a02021-03-11 20:30:57 -080010082// Have two windows, one with focus. Injecting a trusted DOWN MotionEvent with the flag
10083// NO_FOCUS_CHANGE on the unfocused window should not call the onPointerDownOutsideFocus callback.
10084TEST_F(InputDispatcherOnPointerDownOutsideFocus, NoFocusChangeFlag) {
10085 const MotionEvent event =
10086 MotionEventBuilder(AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_MOUSE)
10087 .eventTime(systemTime(SYSTEM_TIME_MONOTONIC))
Siarhei Vishniakou6d73f832022-07-21 17:27:03 -070010088 .pointer(PointerBuilder(/*id=*/0, ToolType::FINGER).x(20).y(20))
Prabir Pradhan47cf0a02021-03-11 20:30:57 -080010089 .addFlag(AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE)
10090 .build();
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070010091 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectMotionEvent(*mDispatcher, event))
Prabir Pradhan47cf0a02021-03-11 20:30:57 -080010092 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -070010093 mUnfocusedWindow->consumeAnyMotionDown(ui::LogicalDisplayId::DEFAULT,
10094 AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
Prabir Pradhan47cf0a02021-03-11 20:30:57 -080010095
10096 ASSERT_TRUE(mDispatcher->waitForIdle());
10097 mFakePolicy->assertOnPointerDownWasNotCalled();
10098 // Ensure that the unfocused window did not receive any FOCUS events.
10099 mUnfocusedWindow->assertNoEvents();
10100}
10101
chaviwaf87b3e2019-10-01 16:59:28 -070010102// These tests ensures we can send touch events to a single client when there are multiple input
10103// windows that point to the same client token.
10104class InputDispatcherMultiWindowSameTokenTests : public InputDispatcherTest {
10105 virtual void SetUp() override {
10106 InputDispatcherTest::SetUp();
10107
Chris Yea209fde2020-07-22 13:54:51 -070010108 std::shared_ptr<FakeApplicationHandle> application =
10109 std::make_shared<FakeApplicationHandle>();
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -070010110 mWindow1 = sp<FakeWindowHandle>::make(application, mDispatcher, "Fake Window 1",
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -070010111 ui::LogicalDisplayId::DEFAULT);
chaviwaf87b3e2019-10-01 16:59:28 -070010112 mWindow1->setFrame(Rect(0, 0, 100, 100));
10113
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -070010114 mWindow2 = mWindow1->clone(ui::LogicalDisplayId::DEFAULT);
chaviwaf87b3e2019-10-01 16:59:28 -070010115 mWindow2->setFrame(Rect(100, 100, 200, 200));
10116
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070010117 mDispatcher->onWindowInfosChanged({{*mWindow1->getInfo(), *mWindow2->getInfo()}, {}, 0, 0});
chaviwaf87b3e2019-10-01 16:59:28 -070010118 }
10119
10120protected:
10121 sp<FakeWindowHandle> mWindow1;
10122 sp<FakeWindowHandle> mWindow2;
10123
10124 // Helper function to convert the point from screen coordinates into the window's space
chaviw3277faf2021-05-19 16:45:23 -050010125 static PointF getPointInWindow(const WindowInfo* windowInfo, const PointF& point) {
chaviw1ff3d1e2020-07-01 15:53:47 -070010126 vec2 vals = windowInfo->transform.transform(point.x, point.y);
10127 return {vals.x, vals.y};
chaviwaf87b3e2019-10-01 16:59:28 -070010128 }
10129
10130 void consumeMotionEvent(const sp<FakeWindowHandle>& window, int32_t expectedAction,
10131 const std::vector<PointF>& points) {
Siarhei Vishniakouf1035d42019-09-20 16:32:01 +010010132 const std::string name = window->getName();
Siarhei Vishniakoud3061ab2023-12-18 20:41:08 -080010133 std::unique_ptr<MotionEvent> motionEvent =
Prabir Pradhan7662a8d2023-12-15 01:58:14 +000010134 window->consumeMotionEvent(WithMotionAction(expectedAction));
Siarhei Vishniakoud3061ab2023-12-18 20:41:08 -080010135 ASSERT_NE(nullptr, motionEvent);
10136 ASSERT_EQ(points.size(), motionEvent->getPointerCount());
chaviwaf87b3e2019-10-01 16:59:28 -070010137
10138 for (size_t i = 0; i < points.size(); i++) {
10139 float expectedX = points[i].x;
10140 float expectedY = points[i].y;
10141
Siarhei Vishniakoud3061ab2023-12-18 20:41:08 -080010142 EXPECT_EQ(expectedX, motionEvent->getX(i))
chaviwaf87b3e2019-10-01 16:59:28 -070010143 << "expected " << expectedX << " for x[" << i << "] coord of " << name.c_str()
Siarhei Vishniakoud3061ab2023-12-18 20:41:08 -080010144 << ", got " << motionEvent->getX(i);
10145 EXPECT_EQ(expectedY, motionEvent->getY(i))
chaviwaf87b3e2019-10-01 16:59:28 -070010146 << "expected " << expectedY << " for y[" << i << "] coord of " << name.c_str()
Siarhei Vishniakoud3061ab2023-12-18 20:41:08 -080010147 << ", got " << motionEvent->getY(i);
chaviwaf87b3e2019-10-01 16:59:28 -070010148 }
10149 }
chaviw9eaa22c2020-07-01 16:21:27 -070010150
Prabir Pradhanbb3f1c02024-01-04 20:17:14 +000010151 void touchAndAssertPositions(sp<FakeWindowHandle> touchedWindow, int32_t action,
10152 const std::vector<PointF>& touchedPoints,
chaviw9eaa22c2020-07-01 16:21:27 -070010153 std::vector<PointF> expectedPoints) {
Prabir Pradhan678438e2023-04-13 19:32:51 +000010154 mDispatcher->notifyMotion(generateMotionArgs(action, AINPUT_SOURCE_TOUCHSCREEN,
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -070010155 ui::LogicalDisplayId::DEFAULT, touchedPoints));
chaviw9eaa22c2020-07-01 16:21:27 -070010156
Prabir Pradhanbb3f1c02024-01-04 20:17:14 +000010157 consumeMotionEvent(touchedWindow, action, expectedPoints);
chaviw9eaa22c2020-07-01 16:21:27 -070010158 }
chaviwaf87b3e2019-10-01 16:59:28 -070010159};
10160
10161TEST_F(InputDispatcherMultiWindowSameTokenTests, SingleTouchSameScale) {
10162 // Touch Window 1
10163 PointF touchedPoint = {10, 10};
10164 PointF expectedPoint = getPointInWindow(mWindow1->getInfo(), touchedPoint);
Prabir Pradhanbb3f1c02024-01-04 20:17:14 +000010165 touchAndAssertPositions(mWindow1, AMOTION_EVENT_ACTION_DOWN, {touchedPoint}, {expectedPoint});
chaviwaf87b3e2019-10-01 16:59:28 -070010166
10167 // Release touch on Window 1
Prabir Pradhanbb3f1c02024-01-04 20:17:14 +000010168 touchAndAssertPositions(mWindow1, AMOTION_EVENT_ACTION_UP, {touchedPoint}, {expectedPoint});
chaviwaf87b3e2019-10-01 16:59:28 -070010169
10170 // Touch Window 2
10171 touchedPoint = {150, 150};
10172 expectedPoint = getPointInWindow(mWindow2->getInfo(), touchedPoint);
Prabir Pradhanbb3f1c02024-01-04 20:17:14 +000010173 touchAndAssertPositions(mWindow2, AMOTION_EVENT_ACTION_DOWN, {touchedPoint}, {expectedPoint});
chaviwaf87b3e2019-10-01 16:59:28 -070010174}
10175
chaviw9eaa22c2020-07-01 16:21:27 -070010176TEST_F(InputDispatcherMultiWindowSameTokenTests, SingleTouchDifferentTransform) {
10177 // Set scale value for window2
chaviwaf87b3e2019-10-01 16:59:28 -070010178 mWindow2->setWindowScale(0.5f, 0.5f);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070010179 mDispatcher->onWindowInfosChanged({{*mWindow1->getInfo(), *mWindow2->getInfo()}, {}, 0, 0});
chaviwaf87b3e2019-10-01 16:59:28 -070010180
10181 // Touch Window 1
10182 PointF touchedPoint = {10, 10};
10183 PointF expectedPoint = getPointInWindow(mWindow1->getInfo(), touchedPoint);
Prabir Pradhanbb3f1c02024-01-04 20:17:14 +000010184 touchAndAssertPositions(mWindow1, AMOTION_EVENT_ACTION_DOWN, {touchedPoint}, {expectedPoint});
chaviwaf87b3e2019-10-01 16:59:28 -070010185 // Release touch on Window 1
Prabir Pradhanbb3f1c02024-01-04 20:17:14 +000010186 touchAndAssertPositions(mWindow1, AMOTION_EVENT_ACTION_UP, {touchedPoint}, {expectedPoint});
chaviwaf87b3e2019-10-01 16:59:28 -070010187
10188 // Touch Window 2
10189 touchedPoint = {150, 150};
10190 expectedPoint = getPointInWindow(mWindow2->getInfo(), touchedPoint);
Prabir Pradhanbb3f1c02024-01-04 20:17:14 +000010191 touchAndAssertPositions(mWindow2, AMOTION_EVENT_ACTION_DOWN, {touchedPoint}, {expectedPoint});
10192 touchAndAssertPositions(mWindow2, AMOTION_EVENT_ACTION_UP, {touchedPoint}, {expectedPoint});
chaviwaf87b3e2019-10-01 16:59:28 -070010193
chaviw9eaa22c2020-07-01 16:21:27 -070010194 // Update the transform so rotation is set
10195 mWindow2->setWindowTransform(0, -1, 1, 0);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070010196 mDispatcher->onWindowInfosChanged({{*mWindow1->getInfo(), *mWindow2->getInfo()}, {}, 0, 0});
chaviw9eaa22c2020-07-01 16:21:27 -070010197 expectedPoint = getPointInWindow(mWindow2->getInfo(), touchedPoint);
Prabir Pradhanbb3f1c02024-01-04 20:17:14 +000010198 touchAndAssertPositions(mWindow2, AMOTION_EVENT_ACTION_DOWN, {touchedPoint}, {expectedPoint});
chaviwaf87b3e2019-10-01 16:59:28 -070010199}
10200
chaviw9eaa22c2020-07-01 16:21:27 -070010201TEST_F(InputDispatcherMultiWindowSameTokenTests, MultipleTouchDifferentTransform) {
Chavi Weingarten65f98b82020-01-16 18:56:50 +000010202 mWindow2->setWindowScale(0.5f, 0.5f);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070010203 mDispatcher->onWindowInfosChanged({{*mWindow1->getInfo(), *mWindow2->getInfo()}, {}, 0, 0});
Chavi Weingarten65f98b82020-01-16 18:56:50 +000010204
10205 // Touch Window 1
10206 std::vector<PointF> touchedPoints = {PointF{10, 10}};
10207 std::vector<PointF> expectedPoints = {getPointInWindow(mWindow1->getInfo(), touchedPoints[0])};
Prabir Pradhanbb3f1c02024-01-04 20:17:14 +000010208 touchAndAssertPositions(mWindow1, AMOTION_EVENT_ACTION_DOWN, touchedPoints, expectedPoints);
Chavi Weingarten65f98b82020-01-16 18:56:50 +000010209
10210 // Touch Window 2
Prabir Pradhanbb3f1c02024-01-04 20:17:14 +000010211 // Since this is part of the same touch gesture that has already been dispatched to Window 1,
10212 // the touch stream from Window 2 will be merged with the stream in Window 1. The merged stream
10213 // will continue to be dispatched through Window 1.
chaviw9eaa22c2020-07-01 16:21:27 -070010214 touchedPoints.push_back(PointF{150, 150});
10215 expectedPoints.push_back(getPointInWindow(mWindow2->getInfo(), touchedPoints[1]));
Prabir Pradhanbb3f1c02024-01-04 20:17:14 +000010216 touchAndAssertPositions(mWindow1, POINTER_1_DOWN, touchedPoints, expectedPoints);
Chavi Weingarten65f98b82020-01-16 18:56:50 +000010217
chaviw9eaa22c2020-07-01 16:21:27 -070010218 // Release Window 2
Prabir Pradhanbb3f1c02024-01-04 20:17:14 +000010219 touchAndAssertPositions(mWindow1, POINTER_1_UP, touchedPoints, expectedPoints);
chaviw9eaa22c2020-07-01 16:21:27 -070010220 expectedPoints.pop_back();
Chavi Weingarten65f98b82020-01-16 18:56:50 +000010221
chaviw9eaa22c2020-07-01 16:21:27 -070010222 // Update the transform so rotation is set for Window 2
10223 mWindow2->setWindowTransform(0, -1, 1, 0);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070010224 mDispatcher->onWindowInfosChanged({{*mWindow1->getInfo(), *mWindow2->getInfo()}, {}, 0, 0});
chaviw9eaa22c2020-07-01 16:21:27 -070010225 expectedPoints.push_back(getPointInWindow(mWindow2->getInfo(), touchedPoints[1]));
Prabir Pradhanbb3f1c02024-01-04 20:17:14 +000010226 touchAndAssertPositions(mWindow1, POINTER_1_DOWN, touchedPoints, expectedPoints);
Chavi Weingarten65f98b82020-01-16 18:56:50 +000010227}
10228
chaviw9eaa22c2020-07-01 16:21:27 -070010229TEST_F(InputDispatcherMultiWindowSameTokenTests, MultipleTouchMoveDifferentTransform) {
Chavi Weingarten65f98b82020-01-16 18:56:50 +000010230 mWindow2->setWindowScale(0.5f, 0.5f);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070010231 mDispatcher->onWindowInfosChanged({{*mWindow1->getInfo(), *mWindow2->getInfo()}, {}, 0, 0});
Chavi Weingarten65f98b82020-01-16 18:56:50 +000010232
10233 // Touch Window 1
10234 std::vector<PointF> touchedPoints = {PointF{10, 10}};
10235 std::vector<PointF> expectedPoints = {getPointInWindow(mWindow1->getInfo(), touchedPoints[0])};
Prabir Pradhanbb3f1c02024-01-04 20:17:14 +000010236 touchAndAssertPositions(mWindow1, AMOTION_EVENT_ACTION_DOWN, touchedPoints, expectedPoints);
Chavi Weingarten65f98b82020-01-16 18:56:50 +000010237
10238 // Touch Window 2
chaviw9eaa22c2020-07-01 16:21:27 -070010239 touchedPoints.push_back(PointF{150, 150});
10240 expectedPoints.push_back(getPointInWindow(mWindow2->getInfo(), touchedPoints[1]));
Chavi Weingarten65f98b82020-01-16 18:56:50 +000010241
Prabir Pradhanbb3f1c02024-01-04 20:17:14 +000010242 touchAndAssertPositions(mWindow1, POINTER_1_DOWN, touchedPoints, expectedPoints);
Chavi Weingarten65f98b82020-01-16 18:56:50 +000010243
10244 // Move both windows
10245 touchedPoints = {{20, 20}, {175, 175}};
10246 expectedPoints = {getPointInWindow(mWindow1->getInfo(), touchedPoints[0]),
10247 getPointInWindow(mWindow2->getInfo(), touchedPoints[1])};
10248
Prabir Pradhanbb3f1c02024-01-04 20:17:14 +000010249 touchAndAssertPositions(mWindow1, AMOTION_EVENT_ACTION_MOVE, touchedPoints, expectedPoints);
Chavi Weingarten65f98b82020-01-16 18:56:50 +000010250
chaviw9eaa22c2020-07-01 16:21:27 -070010251 // Release Window 2
Prabir Pradhanbb3f1c02024-01-04 20:17:14 +000010252 touchAndAssertPositions(mWindow1, POINTER_1_UP, touchedPoints, expectedPoints);
chaviw9eaa22c2020-07-01 16:21:27 -070010253 expectedPoints.pop_back();
10254
10255 // Touch Window 2
10256 mWindow2->setWindowTransform(0, -1, 1, 0);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070010257 mDispatcher->onWindowInfosChanged({{*mWindow1->getInfo(), *mWindow2->getInfo()}, {}, 0, 0});
chaviw9eaa22c2020-07-01 16:21:27 -070010258 expectedPoints.push_back(getPointInWindow(mWindow2->getInfo(), touchedPoints[1]));
Prabir Pradhanbb3f1c02024-01-04 20:17:14 +000010259 touchAndAssertPositions(mWindow1, POINTER_1_DOWN, touchedPoints, expectedPoints);
chaviw9eaa22c2020-07-01 16:21:27 -070010260
10261 // Move both windows
10262 touchedPoints = {{20, 20}, {175, 175}};
10263 expectedPoints = {getPointInWindow(mWindow1->getInfo(), touchedPoints[0]),
10264 getPointInWindow(mWindow2->getInfo(), touchedPoints[1])};
10265
Prabir Pradhanbb3f1c02024-01-04 20:17:14 +000010266 touchAndAssertPositions(mWindow1, AMOTION_EVENT_ACTION_MOVE, touchedPoints, expectedPoints);
Chavi Weingarten65f98b82020-01-16 18:56:50 +000010267}
10268
10269TEST_F(InputDispatcherMultiWindowSameTokenTests, MultipleWindowsFirstTouchWithScale) {
10270 mWindow1->setWindowScale(0.5f, 0.5f);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070010271 mDispatcher->onWindowInfosChanged({{*mWindow1->getInfo(), *mWindow2->getInfo()}, {}, 0, 0});
Chavi Weingarten65f98b82020-01-16 18:56:50 +000010272
10273 // Touch Window 1
10274 std::vector<PointF> touchedPoints = {PointF{10, 10}};
10275 std::vector<PointF> expectedPoints = {getPointInWindow(mWindow1->getInfo(), touchedPoints[0])};
Prabir Pradhanbb3f1c02024-01-04 20:17:14 +000010276 touchAndAssertPositions(mWindow1, AMOTION_EVENT_ACTION_DOWN, touchedPoints, expectedPoints);
Chavi Weingarten65f98b82020-01-16 18:56:50 +000010277
10278 // Touch Window 2
chaviw9eaa22c2020-07-01 16:21:27 -070010279 touchedPoints.push_back(PointF{150, 150});
10280 expectedPoints.push_back(getPointInWindow(mWindow2->getInfo(), touchedPoints[1]));
Chavi Weingarten65f98b82020-01-16 18:56:50 +000010281
Prabir Pradhanbb3f1c02024-01-04 20:17:14 +000010282 touchAndAssertPositions(mWindow1, POINTER_1_DOWN, touchedPoints, expectedPoints);
Chavi Weingarten65f98b82020-01-16 18:56:50 +000010283
10284 // Move both windows
10285 touchedPoints = {{20, 20}, {175, 175}};
10286 expectedPoints = {getPointInWindow(mWindow1->getInfo(), touchedPoints[0]),
10287 getPointInWindow(mWindow2->getInfo(), touchedPoints[1])};
10288
Prabir Pradhanbb3f1c02024-01-04 20:17:14 +000010289 touchAndAssertPositions(mWindow1, AMOTION_EVENT_ACTION_MOVE, touchedPoints, expectedPoints);
Chavi Weingarten65f98b82020-01-16 18:56:50 +000010290}
10291
Siarhei Vishniakou0f6558d2023-04-21 12:05:13 -070010292/**
10293 * When one of the windows is slippery, the touch should not slip into the other window with the
10294 * same input channel.
10295 */
10296TEST_F(InputDispatcherMultiWindowSameTokenTests, TouchDoesNotSlipEvenIfSlippery) {
10297 mWindow1->setSlippery(true);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070010298 mDispatcher->onWindowInfosChanged({{*mWindow1->getInfo(), *mWindow2->getInfo()}, {}, 0, 0});
Siarhei Vishniakou0f6558d2023-04-21 12:05:13 -070010299
10300 // Touch down in window 1
10301 mDispatcher->notifyMotion(generateMotionArgs(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN,
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -070010302 ui::LogicalDisplayId::DEFAULT, {{50, 50}}));
Siarhei Vishniakou0f6558d2023-04-21 12:05:13 -070010303 consumeMotionEvent(mWindow1, ACTION_DOWN, {{50, 50}});
10304
10305 // Move touch to be above window 2. Even though window 1 is slippery, touch should not slip.
10306 // That means the gesture should continue normally, without any ACTION_CANCEL or ACTION_DOWN
10307 // getting generated.
10308 mDispatcher->notifyMotion(generateMotionArgs(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN,
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -070010309 ui::LogicalDisplayId::DEFAULT, {{150, 150}}));
Siarhei Vishniakou0f6558d2023-04-21 12:05:13 -070010310
10311 consumeMotionEvent(mWindow1, ACTION_MOVE, {{150, 150}});
10312}
10313
Siarhei Vishniakoud5876ba2023-05-15 17:58:34 -070010314/**
10315 * When hover starts in one window and continues into the other, there should be a HOVER_EXIT and
10316 * a HOVER_ENTER generated, even if the windows have the same token. This is because the new window
10317 * that the pointer is hovering over may have a different transform.
10318 */
10319TEST_F(InputDispatcherMultiWindowSameTokenTests, HoverIntoClone) {
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070010320 mDispatcher->onWindowInfosChanged({{*mWindow1->getInfo(), *mWindow2->getInfo()}, {}, 0, 0});
Siarhei Vishniakoud5876ba2023-05-15 17:58:34 -070010321
10322 // Start hover in window 1
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -070010323 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_ENTER, AINPUT_SOURCE_TOUCHSCREEN)
10324 .pointer(PointerBuilder(0, ToolType::FINGER).x(50).y(50))
10325 .build());
Siarhei Vishniakoud5876ba2023-05-15 17:58:34 -070010326 consumeMotionEvent(mWindow1, ACTION_HOVER_ENTER,
10327 {getPointInWindow(mWindow1->getInfo(), PointF{50, 50})});
Siarhei Vishniakoud5876ba2023-05-15 17:58:34 -070010328 // Move hover to window 2.
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -070010329 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_MOVE, AINPUT_SOURCE_TOUCHSCREEN)
10330 .pointer(PointerBuilder(0, ToolType::FINGER).x(150).y(150))
10331 .build());
Siarhei Vishniakoud5876ba2023-05-15 17:58:34 -070010332 consumeMotionEvent(mWindow1, ACTION_HOVER_EXIT, {{50, 50}});
Prabir Pradhanbb3f1c02024-01-04 20:17:14 +000010333 consumeMotionEvent(mWindow2, ACTION_HOVER_ENTER,
Siarhei Vishniakoud5876ba2023-05-15 17:58:34 -070010334 {getPointInWindow(mWindow2->getInfo(), PointF{150, 150})});
10335}
10336
Siarhei Vishniakou4cb50ca2020-05-26 21:43:02 -070010337class InputDispatcherSingleWindowAnr : public InputDispatcherTest {
10338 virtual void SetUp() override {
10339 InputDispatcherTest::SetUp();
10340
Chris Yea209fde2020-07-22 13:54:51 -070010341 mApplication = std::make_shared<FakeApplicationHandle>();
Siarhei Vishniakouf83c6932023-07-07 17:48:10 -070010342 mApplication->setDispatchingTimeout(100ms);
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -070010343 mWindow = sp<FakeWindowHandle>::make(mApplication, mDispatcher, "TestWindow",
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -070010344 ui::LogicalDisplayId::DEFAULT);
Siarhei Vishniakou4cb50ca2020-05-26 21:43:02 -070010345 mWindow->setFrame(Rect(0, 0, 30, 30));
Siarhei Vishniakouf83c6932023-07-07 17:48:10 -070010346 mWindow->setDispatchingTimeout(100ms);
Vishnu Nair47074b82020-08-14 11:54:47 -070010347 mWindow->setFocusable(true);
Siarhei Vishniakou4cb50ca2020-05-26 21:43:02 -070010348
10349 // Set focused application.
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -070010350 mDispatcher->setFocusedApplication(ui::LogicalDisplayId::DEFAULT, mApplication);
Siarhei Vishniakou4cb50ca2020-05-26 21:43:02 -070010351
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070010352 mDispatcher->onWindowInfosChanged({{*mWindow->getInfo()}, {}, 0, 0});
Vishnu Nair958da932020-08-21 17:12:37 -070010353 setFocusedWindow(mWindow);
Siarhei Vishniakou4cb50ca2020-05-26 21:43:02 -070010354 mWindow->consumeFocusEvent(true);
10355 }
10356
10357 virtual void TearDown() override {
10358 InputDispatcherTest::TearDown();
10359 mWindow.clear();
10360 }
10361
10362protected:
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070010363 static constexpr std::chrono::duration SPY_TIMEOUT = 200ms;
Chris Yea209fde2020-07-22 13:54:51 -070010364 std::shared_ptr<FakeApplicationHandle> mApplication;
Siarhei Vishniakou4cb50ca2020-05-26 21:43:02 -070010365 sp<FakeWindowHandle> mWindow;
10366 static constexpr PointF WINDOW_LOCATION = {20, 20};
10367
10368 void tapOnWindow() {
Siarhei Vishniakou67bf2162023-11-16 13:29:50 -080010369 const auto touchingPointer = PointerBuilder(/*id=*/0, ToolType::FINGER)
10370 .x(WINDOW_LOCATION.x)
10371 .y(WINDOW_LOCATION.y);
10372 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
10373 .pointer(touchingPointer)
10374 .build());
10375 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN)
10376 .pointer(touchingPointer)
10377 .build());
Siarhei Vishniakou4cb50ca2020-05-26 21:43:02 -070010378 }
Prabir Pradhan1376fcd2022-01-21 09:56:35 -080010379
10380 sp<FakeWindowHandle> addSpyWindow() {
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -070010381 sp<FakeWindowHandle> spy = sp<FakeWindowHandle>::make(mApplication, mDispatcher, "Spy",
10382 ui::LogicalDisplayId::DEFAULT);
Prabir Pradhan1376fcd2022-01-21 09:56:35 -080010383 spy->setTrustedOverlay(true);
10384 spy->setFocusable(false);
Prabir Pradhan51e7db02022-02-07 06:02:57 -080010385 spy->setSpy(true);
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070010386 spy->setDispatchingTimeout(SPY_TIMEOUT);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070010387 mDispatcher->onWindowInfosChanged({{*spy->getInfo(), *mWindow->getInfo()}, {}, 0, 0});
Prabir Pradhan1376fcd2022-01-21 09:56:35 -080010388 return spy;
10389 }
Siarhei Vishniakou4cb50ca2020-05-26 21:43:02 -070010390};
10391
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -070010392// Send a tap and respond, which should not cause an ANR.
10393TEST_F(InputDispatcherSingleWindowAnr, WhenTouchIsConsumed_NoAnr) {
10394 tapOnWindow();
10395 mWindow->consumeMotionDown();
10396 mWindow->consumeMotionUp();
10397 ASSERT_TRUE(mDispatcher->waitForIdle());
10398 mFakePolicy->assertNotifyAnrWasNotCalled();
10399}
10400
10401// Send a regular key and respond, which should not cause an ANR.
10402TEST_F(InputDispatcherSingleWindowAnr, WhenKeyIsConsumed_NoAnr) {
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070010403 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectKeyDownNoRepeat(*mDispatcher));
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -070010404 mWindow->consumeKeyDown(ui::LogicalDisplayId::INVALID);
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -070010405 ASSERT_TRUE(mDispatcher->waitForIdle());
10406 mFakePolicy->assertNotifyAnrWasNotCalled();
10407}
10408
Siarhei Vishniakoue41c4512020-09-08 19:35:58 -050010409TEST_F(InputDispatcherSingleWindowAnr, WhenFocusedApplicationChanges_NoAnr) {
10410 mWindow->setFocusable(false);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070010411 mDispatcher->onWindowInfosChanged({{*mWindow->getInfo()}, {}, 0, 0});
Siarhei Vishniakoue41c4512020-09-08 19:35:58 -050010412 mWindow->consumeFocusEvent(false);
10413
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -080010414 InputEventInjectionResult result =
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -070010415 injectKey(*mDispatcher, AKEY_EVENT_ACTION_DOWN, /*repeatCount=*/0,
10416 ui::LogicalDisplayId::DEFAULT, InputEventInjectionSync::NONE,
10417 CONSUME_TIMEOUT_EVENT_EXPECTED,
Harry Cutts33476232023-01-30 19:57:29 +000010418 /*allowKeyRepeat=*/false);
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -080010419 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, result);
Siarhei Vishniakoue41c4512020-09-08 19:35:58 -050010420 // Key will not go to window because we have no focused window.
10421 // The 'no focused window' ANR timer should start instead.
10422
10423 // Now, the focused application goes away.
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -070010424 mDispatcher->setFocusedApplication(ui::LogicalDisplayId::DEFAULT, nullptr);
Siarhei Vishniakoue41c4512020-09-08 19:35:58 -050010425 // The key should get dropped and there should be no ANR.
10426
10427 ASSERT_TRUE(mDispatcher->waitForIdle());
10428 mFakePolicy->assertNotifyAnrWasNotCalled();
10429}
10430
Siarhei Vishniakou4cb50ca2020-05-26 21:43:02 -070010431// Send an event to the app and have the app not respond right away.
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -070010432// When ANR is raised, policy will tell the dispatcher to cancel the events for that window.
10433// So InputDispatcher will enqueue ACTION_CANCEL event as well.
Siarhei Vishniakou4cb50ca2020-05-26 21:43:02 -070010434TEST_F(InputDispatcherSingleWindowAnr, OnPointerDown_BasicAnr) {
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -080010435 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -070010436 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN,
10437 ui::LogicalDisplayId::DEFAULT, WINDOW_LOCATION));
Siarhei Vishniakou4cb50ca2020-05-26 21:43:02 -070010438
Siarhei Vishniakoud3061ab2023-12-18 20:41:08 -080010439 const auto [sequenceNum, _] = mWindow->receiveEvent(); // ACTION_DOWN
Siarhei Vishniakou4cb50ca2020-05-26 21:43:02 -070010440 ASSERT_TRUE(sequenceNum);
10441 const std::chrono::duration timeout = mWindow->getDispatchingTimeout(DISPATCHING_TIMEOUT);
Prabir Pradhanedd96402022-02-15 01:46:16 -080010442 mFakePolicy->assertNotifyWindowUnresponsiveWasCalled(timeout, mWindow);
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -070010443
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -070010444 mWindow->finishEvent(*sequenceNum);
Siarhei Vishniakou1ae72f12023-01-29 12:55:30 -080010445 mWindow->consumeMotionEvent(
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -070010446 AllOf(WithMotionAction(ACTION_CANCEL), WithDisplayId(ui::LogicalDisplayId::DEFAULT)));
Siarhei Vishniakou4cb50ca2020-05-26 21:43:02 -070010447 ASSERT_TRUE(mDispatcher->waitForIdle());
Prabir Pradhanedd96402022-02-15 01:46:16 -080010448 mFakePolicy->assertNotifyWindowResponsiveWasCalled(mWindow->getToken(), mWindow->getPid());
Siarhei Vishniakou4cb50ca2020-05-26 21:43:02 -070010449}
10450
10451// Send a key to the app and have the app not respond right away.
10452TEST_F(InputDispatcherSingleWindowAnr, OnKeyDown_BasicAnr) {
10453 // Inject a key, and don't respond - expect that ANR is called.
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070010454 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectKeyDownNoRepeat(*mDispatcher));
Siarhei Vishniakoud3061ab2023-12-18 20:41:08 -080010455 const auto [sequenceNum, _] = mWindow->receiveEvent();
Siarhei Vishniakou4cb50ca2020-05-26 21:43:02 -070010456 ASSERT_TRUE(sequenceNum);
Siarhei Vishniakou4cb50ca2020-05-26 21:43:02 -070010457 const std::chrono::duration timeout = mWindow->getDispatchingTimeout(DISPATCHING_TIMEOUT);
Prabir Pradhanedd96402022-02-15 01:46:16 -080010458 mFakePolicy->assertNotifyWindowUnresponsiveWasCalled(timeout, mWindow);
Siarhei Vishniakou4cb50ca2020-05-26 21:43:02 -070010459 ASSERT_TRUE(mDispatcher->waitForIdle());
10460}
10461
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -070010462// We have a focused application, but no focused window
10463TEST_F(InputDispatcherSingleWindowAnr, FocusedApplication_NoFocusedWindow) {
Vishnu Nair47074b82020-08-14 11:54:47 -070010464 mWindow->setFocusable(false);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070010465 mDispatcher->onWindowInfosChanged({{*mWindow->getInfo()}, {}, 0, 0});
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -070010466 mWindow->consumeFocusEvent(false);
10467
10468 // taps on the window work as normal
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -080010469 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -070010470 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN,
10471 ui::LogicalDisplayId::DEFAULT, WINDOW_LOCATION));
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -070010472 ASSERT_NO_FATAL_FAILURE(mWindow->consumeMotionDown());
10473 mDispatcher->waitForIdle();
10474 mFakePolicy->assertNotifyAnrWasNotCalled();
10475
10476 // Once a focused event arrives, we get an ANR for this application
10477 // We specify the injection timeout to be smaller than the application timeout, to ensure that
10478 // injection times out (instead of failing).
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -080010479 const InputEventInjectionResult result =
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -070010480 injectKey(*mDispatcher, AKEY_EVENT_ACTION_DOWN, /*repeatCount=*/0,
10481 ui::LogicalDisplayId::DEFAULT, InputEventInjectionSync::WAIT_FOR_RESULT, 50ms,
Linnan Li13bf76a2024-05-05 19:18:02 +080010482 /*allowKeyRepeat=*/false);
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -080010483 ASSERT_EQ(InputEventInjectionResult::TIMED_OUT, result);
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -070010484 const std::chrono::duration timeout = mApplication->getDispatchingTimeout(DISPATCHING_TIMEOUT);
Vishnu Naire4df8752022-09-08 09:17:55 -070010485 mFakePolicy->assertNotifyNoFocusedWindowAnrWasCalled(timeout, mApplication);
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -070010486 ASSERT_TRUE(mDispatcher->waitForIdle());
10487}
10488
Siarhei Vishniakou289e9242022-02-15 14:50:16 -080010489/**
10490 * Make sure the stale key is dropped before causing an ANR. So even if there's no focused window,
10491 * there will not be an ANR.
10492 */
10493TEST_F(InputDispatcherSingleWindowAnr, StaleKeyEventDoesNotAnr) {
10494 mWindow->setFocusable(false);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070010495 mDispatcher->onWindowInfosChanged({{*mWindow->getInfo()}, {}, 0, 0});
Siarhei Vishniakou289e9242022-02-15 14:50:16 -080010496 mWindow->consumeFocusEvent(false);
10497
10498 KeyEvent event;
Siarhei Vishniakoua7333112023-10-27 13:33:29 -070010499 static constexpr std::chrono::duration STALE_EVENT_TIMEOUT = 1000ms;
10500 mFakePolicy->setStaleEventTimeout(STALE_EVENT_TIMEOUT);
Siarhei Vishniakou289e9242022-02-15 14:50:16 -080010501 const nsecs_t eventTime = systemTime(SYSTEM_TIME_MONOTONIC) -
10502 std::chrono::nanoseconds(STALE_EVENT_TIMEOUT).count();
10503
10504 // Define a valid key down event that is stale (too old).
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -070010505 event.initialize(InputEvent::nextId(), DEVICE_ID, AINPUT_SOURCE_KEYBOARD,
10506 ui::LogicalDisplayId::INVALID, INVALID_HMAC, AKEY_EVENT_ACTION_DOWN,
10507 /*flags=*/0, AKEYCODE_A, KEY_A, AMETA_NONE, /*repeatCount=*/0, eventTime,
10508 eventTime);
Siarhei Vishniakou289e9242022-02-15 14:50:16 -080010509
Hu Guofe3c8f12023-09-22 17:20:15 +080010510 const int32_t policyFlags =
10511 POLICY_FLAG_FILTERED | POLICY_FLAG_PASS_TO_USER | POLICY_FLAG_DISABLE_KEY_REPEAT;
Siarhei Vishniakou289e9242022-02-15 14:50:16 -080010512
10513 InputEventInjectionResult result =
Harry Cutts33476232023-01-30 19:57:29 +000010514 mDispatcher->injectInputEvent(&event, /*targetUid=*/{},
Siarhei Vishniakou289e9242022-02-15 14:50:16 -080010515 InputEventInjectionSync::WAIT_FOR_RESULT,
10516 INJECT_EVENT_TIMEOUT, policyFlags);
10517 ASSERT_EQ(InputEventInjectionResult::FAILED, result)
10518 << "Injection should fail because the event is stale";
10519
10520 ASSERT_TRUE(mDispatcher->waitForIdle());
10521 mFakePolicy->assertNotifyAnrWasNotCalled();
10522 mWindow->assertNoEvents();
10523}
10524
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -070010525// We have a focused application, but no focused window
Siarhei Vishniakou234129c2020-10-22 22:28:12 -050010526// Make sure that we don't notify policy twice about the same ANR.
10527TEST_F(InputDispatcherSingleWindowAnr, NoFocusedWindow_DoesNotSendDuplicateAnr) {
Siarhei Vishniakou06405fc2023-09-22 13:40:51 -070010528 const std::chrono::duration appTimeout = 400ms;
10529 mApplication->setDispatchingTimeout(appTimeout);
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -070010530 mDispatcher->setFocusedApplication(ui::LogicalDisplayId::DEFAULT, mApplication);
Siarhei Vishniakou06405fc2023-09-22 13:40:51 -070010531
Vishnu Nair47074b82020-08-14 11:54:47 -070010532 mWindow->setFocusable(false);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070010533 mDispatcher->onWindowInfosChanged({{*mWindow->getInfo()}, {}, 0, 0});
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -070010534 mWindow->consumeFocusEvent(false);
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -070010535
10536 // Once a focused event arrives, we get an ANR for this application
10537 // We specify the injection timeout to be smaller than the application timeout, to ensure that
10538 // injection times out (instead of failing).
Siarhei Vishniakou06405fc2023-09-22 13:40:51 -070010539 const std::chrono::duration eventInjectionTimeout = 100ms;
10540 ASSERT_LT(eventInjectionTimeout, appTimeout);
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -080010541 const InputEventInjectionResult result =
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -070010542 injectKey(*mDispatcher, AKEY_EVENT_ACTION_DOWN, /*repeatCount=*/0,
10543 ui::LogicalDisplayId::DEFAULT, InputEventInjectionSync::WAIT_FOR_RESULT,
10544 eventInjectionTimeout,
Siarhei Vishniakou06405fc2023-09-22 13:40:51 -070010545 /*allowKeyRepeat=*/false);
10546 ASSERT_EQ(InputEventInjectionResult::TIMED_OUT, result)
10547 << "result=" << ftl::enum_string(result);
10548 // We already waited for 'eventInjectionTimeout`, because the countdown started when the event
10549 // was first injected. So now we have (appTimeout - eventInjectionTimeout) left to wait.
10550 std::chrono::duration remainingWaitTime = appTimeout - eventInjectionTimeout;
10551 mFakePolicy->assertNotifyNoFocusedWindowAnrWasCalled(remainingWaitTime, mApplication);
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -070010552
Vishnu Naire4df8752022-09-08 09:17:55 -070010553 std::this_thread::sleep_for(appTimeout);
Siarhei Vishniakou234129c2020-10-22 22:28:12 -050010554 // ANR should not be raised again. It is up to policy to do that if it desires.
10555 mFakePolicy->assertNotifyAnrWasNotCalled();
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -070010556
Siarhei Vishniakou234129c2020-10-22 22:28:12 -050010557 // If we now get a focused window, the ANR should stop, but the policy handles that via
10558 // 'notifyFocusChanged' callback. This is implemented in the policy so we can't test it here.
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -070010559 ASSERT_TRUE(mDispatcher->waitForIdle());
10560}
10561
10562// We have a focused application, but no focused window
10563TEST_F(InputDispatcherSingleWindowAnr, NoFocusedWindow_DropsFocusedEvents) {
Vishnu Nair47074b82020-08-14 11:54:47 -070010564 mWindow->setFocusable(false);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070010565 mDispatcher->onWindowInfosChanged({{*mWindow->getInfo()}, {}, 0, 0});
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -070010566 mWindow->consumeFocusEvent(false);
10567
10568 // Once a focused event arrives, we get an ANR for this application
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070010569 ASSERT_NO_FATAL_FAILURE(assertInjectedKeyTimesOut(*mDispatcher));
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -070010570
Vishnu Naire4df8752022-09-08 09:17:55 -070010571 const std::chrono::duration timeout = mApplication->getDispatchingTimeout(DISPATCHING_TIMEOUT);
10572 mFakePolicy->assertNotifyNoFocusedWindowAnrWasCalled(timeout, mApplication);
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -070010573
10574 // Future focused events get dropped right away
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070010575 ASSERT_EQ(InputEventInjectionResult::FAILED, injectKeyDown(*mDispatcher));
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -070010576 ASSERT_TRUE(mDispatcher->waitForIdle());
10577 mWindow->assertNoEvents();
10578}
10579
10580/**
10581 * Ensure that the implementation is valid. Since we are using multiset to keep track of the
10582 * ANR timeouts, we are allowing entries with identical timestamps in the same connection.
10583 * If we process 1 of the events, but ANR on the second event with the same timestamp,
10584 * the ANR mechanism should still work.
10585 *
10586 * In this test, we are injecting DOWN and UP events with the same timestamps, and acknowledging the
10587 * DOWN event, while not responding on the second one.
10588 */
10589TEST_F(InputDispatcherSingleWindowAnr, Anr_HandlesEventsWithIdenticalTimestamps) {
10590 nsecs_t currentTime = systemTime(SYSTEM_TIME_MONOTONIC);
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070010591 injectMotionEvent(*mDispatcher, AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN,
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -070010592 ui::LogicalDisplayId::DEFAULT, WINDOW_LOCATION,
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -070010593 {AMOTION_EVENT_INVALID_CURSOR_POSITION,
10594 AMOTION_EVENT_INVALID_CURSOR_POSITION},
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -080010595 500ms, InputEventInjectionSync::WAIT_FOR_RESULT, currentTime);
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -070010596
10597 // Now send ACTION_UP, with identical timestamp
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070010598 injectMotionEvent(*mDispatcher, AMOTION_EVENT_ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN,
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -070010599 ui::LogicalDisplayId::DEFAULT, WINDOW_LOCATION,
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -070010600 {AMOTION_EVENT_INVALID_CURSOR_POSITION,
10601 AMOTION_EVENT_INVALID_CURSOR_POSITION},
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -080010602 500ms, InputEventInjectionSync::WAIT_FOR_RESULT, currentTime);
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -070010603
10604 // We have now sent down and up. Let's consume first event and then ANR on the second.
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -070010605 mWindow->consumeMotionDown(ui::LogicalDisplayId::DEFAULT);
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -070010606 const std::chrono::duration timeout = mWindow->getDispatchingTimeout(DISPATCHING_TIMEOUT);
Prabir Pradhanedd96402022-02-15 01:46:16 -080010607 mFakePolicy->assertNotifyWindowUnresponsiveWasCalled(timeout, mWindow);
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -070010608}
10609
Prabir Pradhan1376fcd2022-01-21 09:56:35 -080010610// A spy window can receive an ANR
10611TEST_F(InputDispatcherSingleWindowAnr, SpyWindowAnr) {
10612 sp<FakeWindowHandle> spy = addSpyWindow();
10613
10614 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -070010615 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN,
10616 ui::LogicalDisplayId::DEFAULT, WINDOW_LOCATION));
Prabir Pradhan1376fcd2022-01-21 09:56:35 -080010617 mWindow->consumeMotionDown();
10618
Siarhei Vishniakoud3061ab2023-12-18 20:41:08 -080010619 const auto [sequenceNum, _] = spy->receiveEvent(); // ACTION_DOWN
Prabir Pradhan1376fcd2022-01-21 09:56:35 -080010620 ASSERT_TRUE(sequenceNum);
10621 const std::chrono::duration timeout = spy->getDispatchingTimeout(DISPATCHING_TIMEOUT);
Prabir Pradhanedd96402022-02-15 01:46:16 -080010622 mFakePolicy->assertNotifyWindowUnresponsiveWasCalled(timeout, spy);
Prabir Pradhan1376fcd2022-01-21 09:56:35 -080010623
10624 spy->finishEvent(*sequenceNum);
Siarhei Vishniakou1ae72f12023-01-29 12:55:30 -080010625 spy->consumeMotionEvent(
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -070010626 AllOf(WithMotionAction(ACTION_CANCEL), WithDisplayId(ui::LogicalDisplayId::DEFAULT)));
Prabir Pradhan1376fcd2022-01-21 09:56:35 -080010627 ASSERT_TRUE(mDispatcher->waitForIdle());
Prabir Pradhanedd96402022-02-15 01:46:16 -080010628 mFakePolicy->assertNotifyWindowResponsiveWasCalled(spy->getToken(), mWindow->getPid());
Prabir Pradhan1376fcd2022-01-21 09:56:35 -080010629}
10630
10631// If an app is not responding to a key event, spy windows should continue to receive
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -070010632// new motion events
Prabir Pradhan1376fcd2022-01-21 09:56:35 -080010633TEST_F(InputDispatcherSingleWindowAnr, SpyWindowReceivesEventsDuringAppAnrOnKey) {
10634 sp<FakeWindowHandle> spy = addSpyWindow();
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -070010635
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -080010636 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -070010637 injectKeyDown(*mDispatcher, ui::LogicalDisplayId::DEFAULT));
10638 mWindow->consumeKeyDown(ui::LogicalDisplayId::DEFAULT);
10639 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
10640 injectKeyUp(*mDispatcher, ui::LogicalDisplayId::DEFAULT));
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -070010641
10642 // Stuck on the ACTION_UP
10643 const std::chrono::duration timeout = mWindow->getDispatchingTimeout(DISPATCHING_TIMEOUT);
Prabir Pradhanedd96402022-02-15 01:46:16 -080010644 mFakePolicy->assertNotifyWindowUnresponsiveWasCalled(timeout, mWindow);
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -070010645
Prabir Pradhan1376fcd2022-01-21 09:56:35 -080010646 // New tap will go to the spy window, but not to the window
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -070010647 tapOnWindow();
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -070010648 spy->consumeMotionDown(ui::LogicalDisplayId::DEFAULT);
10649 spy->consumeMotionUp(ui::LogicalDisplayId::DEFAULT);
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -070010650
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -070010651 mWindow->consumeKeyUp(ui::LogicalDisplayId::DEFAULT); // still the previous motion
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -070010652 mDispatcher->waitForIdle();
Prabir Pradhanedd96402022-02-15 01:46:16 -080010653 mFakePolicy->assertNotifyWindowResponsiveWasCalled(mWindow->getToken(), mWindow->getPid());
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -070010654 mWindow->assertNoEvents();
Prabir Pradhan1376fcd2022-01-21 09:56:35 -080010655 spy->assertNoEvents();
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -070010656}
10657
Prabir Pradhan1376fcd2022-01-21 09:56:35 -080010658// If an app is not responding to a motion event, spy windows should continue to receive
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -070010659// new motion events
Prabir Pradhan1376fcd2022-01-21 09:56:35 -080010660TEST_F(InputDispatcherSingleWindowAnr, SpyWindowReceivesEventsDuringAppAnrOnMotion) {
10661 sp<FakeWindowHandle> spy = addSpyWindow();
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -070010662
10663 tapOnWindow();
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -070010664 spy->consumeMotionDown(ui::LogicalDisplayId::DEFAULT);
10665 spy->consumeMotionUp(ui::LogicalDisplayId::DEFAULT);
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -070010666
10667 mWindow->consumeMotionDown();
10668 // Stuck on the ACTION_UP
10669 const std::chrono::duration timeout = mWindow->getDispatchingTimeout(DISPATCHING_TIMEOUT);
Prabir Pradhanedd96402022-02-15 01:46:16 -080010670 mFakePolicy->assertNotifyWindowUnresponsiveWasCalled(timeout, mWindow);
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -070010671
Prabir Pradhan1376fcd2022-01-21 09:56:35 -080010672 // New tap will go to the spy window, but not to the window
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -070010673 tapOnWindow();
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -070010674 spy->consumeMotionDown(ui::LogicalDisplayId::DEFAULT);
10675 spy->consumeMotionUp(ui::LogicalDisplayId::DEFAULT);
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -070010676
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -070010677 mWindow->consumeMotionUp(ui::LogicalDisplayId::DEFAULT); // still the previous motion
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -070010678 mDispatcher->waitForIdle();
Prabir Pradhanedd96402022-02-15 01:46:16 -080010679 mFakePolicy->assertNotifyWindowResponsiveWasCalled(mWindow->getToken(), mWindow->getPid());
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -070010680 mWindow->assertNoEvents();
Prabir Pradhan1376fcd2022-01-21 09:56:35 -080010681 spy->assertNoEvents();
10682}
10683
10684TEST_F(InputDispatcherSingleWindowAnr, UnresponsiveMonitorAnr) {
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070010685 mDispatcher->setMonitorDispatchingTimeoutForTest(SPY_TIMEOUT);
Prabir Pradhan1376fcd2022-01-21 09:56:35 -080010686
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -070010687 FakeMonitorReceiver monitor =
10688 FakeMonitorReceiver(*mDispatcher, "M_1", ui::LogicalDisplayId::DEFAULT);
Prabir Pradhan1376fcd2022-01-21 09:56:35 -080010689
10690 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -070010691 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN,
10692 ui::LogicalDisplayId::DEFAULT, WINDOW_LOCATION));
Prabir Pradhan1376fcd2022-01-21 09:56:35 -080010693
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -070010694 mWindow->consumeMotionDown(ui::LogicalDisplayId::DEFAULT);
Prabir Pradhan1376fcd2022-01-21 09:56:35 -080010695 const std::optional<uint32_t> consumeSeq = monitor.receiveEvent();
10696 ASSERT_TRUE(consumeSeq);
10697
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070010698 mFakePolicy->assertNotifyWindowUnresponsiveWasCalled(SPY_TIMEOUT, monitor.getToken(),
10699 MONITOR_PID);
Prabir Pradhan1376fcd2022-01-21 09:56:35 -080010700
10701 monitor.finishEvent(*consumeSeq);
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -070010702 monitor.consumeMotionCancel(ui::LogicalDisplayId::DEFAULT);
Prabir Pradhan1376fcd2022-01-21 09:56:35 -080010703
10704 ASSERT_TRUE(mDispatcher->waitForIdle());
Prabir Pradhanedd96402022-02-15 01:46:16 -080010705 mFakePolicy->assertNotifyWindowResponsiveWasCalled(monitor.getToken(), MONITOR_PID);
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -070010706}
10707
10708// If a window is unresponsive, then you get anr. if the window later catches up and starts to
10709// process events, you don't get an anr. When the window later becomes unresponsive again, you
10710// get an ANR again.
10711// 1. tap -> block on ACTION_UP -> receive ANR
10712// 2. consume all pending events (= queue becomes healthy again)
10713// 3. tap again -> block on ACTION_UP again -> receive ANR second time
10714TEST_F(InputDispatcherSingleWindowAnr, SameWindow_CanReceiveAnrTwice) {
10715 tapOnWindow();
10716
10717 mWindow->consumeMotionDown();
10718 // Block on ACTION_UP
10719 const std::chrono::duration timeout = mWindow->getDispatchingTimeout(DISPATCHING_TIMEOUT);
Prabir Pradhanedd96402022-02-15 01:46:16 -080010720 mFakePolicy->assertNotifyWindowUnresponsiveWasCalled(timeout, mWindow);
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -070010721 mWindow->consumeMotionUp(); // Now the connection should be healthy again
10722 mDispatcher->waitForIdle();
Prabir Pradhanedd96402022-02-15 01:46:16 -080010723 mFakePolicy->assertNotifyWindowResponsiveWasCalled(mWindow->getToken(), mWindow->getPid());
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -070010724 mWindow->assertNoEvents();
10725
10726 tapOnWindow();
10727 mWindow->consumeMotionDown();
Prabir Pradhanedd96402022-02-15 01:46:16 -080010728 mFakePolicy->assertNotifyWindowUnresponsiveWasCalled(timeout, mWindow);
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -070010729 mWindow->consumeMotionUp();
10730
10731 mDispatcher->waitForIdle();
Prabir Pradhanedd96402022-02-15 01:46:16 -080010732 mFakePolicy->assertNotifyWindowResponsiveWasCalled(mWindow->getToken(), mWindow->getPid());
Siarhei Vishniakou234129c2020-10-22 22:28:12 -050010733 mFakePolicy->assertNotifyAnrWasNotCalled();
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -070010734 mWindow->assertNoEvents();
10735}
10736
Siarhei Vishniakou234129c2020-10-22 22:28:12 -050010737// If a connection remains unresponsive for a while, make sure policy is only notified once about
10738// it.
10739TEST_F(InputDispatcherSingleWindowAnr, Policy_DoesNotGetDuplicateAnr) {
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -080010740 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -070010741 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN,
10742 ui::LogicalDisplayId::DEFAULT, WINDOW_LOCATION));
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -070010743
10744 const std::chrono::duration windowTimeout = mWindow->getDispatchingTimeout(DISPATCHING_TIMEOUT);
Prabir Pradhanedd96402022-02-15 01:46:16 -080010745 mFakePolicy->assertNotifyWindowUnresponsiveWasCalled(windowTimeout, mWindow);
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -070010746 std::this_thread::sleep_for(windowTimeout);
Siarhei Vishniakou234129c2020-10-22 22:28:12 -050010747 // 'notifyConnectionUnresponsive' should only be called once per connection
10748 mFakePolicy->assertNotifyAnrWasNotCalled();
10749 // When the ANR happened, dispatcher should abort the current event stream via ACTION_CANCEL
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -070010750 mWindow->consumeMotionDown();
Siarhei Vishniakou1ae72f12023-01-29 12:55:30 -080010751 mWindow->consumeMotionEvent(
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -070010752 AllOf(WithMotionAction(ACTION_CANCEL), WithDisplayId(ui::LogicalDisplayId::DEFAULT)));
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -070010753 mWindow->assertNoEvents();
Siarhei Vishniakou234129c2020-10-22 22:28:12 -050010754 mDispatcher->waitForIdle();
Prabir Pradhanedd96402022-02-15 01:46:16 -080010755 mFakePolicy->assertNotifyWindowResponsiveWasCalled(mWindow->getToken(), mWindow->getPid());
Siarhei Vishniakou234129c2020-10-22 22:28:12 -050010756 mFakePolicy->assertNotifyAnrWasNotCalled();
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -070010757}
10758
10759/**
10760 * 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 -070010761 * not get delivered to the focused window until the motion is processed.
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -070010762 */
10763TEST_F(InputDispatcherSingleWindowAnr, Key_StaysPendingWhileMotionIsProcessed) {
Siarhei Vishniakouef2b4502023-12-28 11:51:47 -080010764 // The timeouts in this test are established by relying on the fact that the "key waiting for
10765 // events timeout" is equal to 500ms.
10766 ASSERT_EQ(mFakePolicy->getKeyWaitingForEventsTimeout(), 500ms);
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -070010767 mWindow->setDispatchingTimeout(2s); // Set a long ANR timeout to prevent it from triggering
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070010768 mDispatcher->onWindowInfosChanged({{*mWindow->getInfo()}, {}, 0, 0});
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -070010769
10770 tapOnWindow();
Siarhei Vishniakoud3061ab2023-12-18 20:41:08 -080010771 const auto& [downSequenceNum, downEvent] = mWindow->receiveEvent();
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -070010772 ASSERT_TRUE(downSequenceNum);
Siarhei Vishniakoud3061ab2023-12-18 20:41:08 -080010773 const auto& [upSequenceNum, upEvent] = mWindow->receiveEvent();
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -070010774 ASSERT_TRUE(upSequenceNum);
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -070010775
Siarhei Vishniakouef2b4502023-12-28 11:51:47 -080010776 // Don't finish the events yet, and send a key
10777 mDispatcher->notifyKey(
10778 KeyArgsBuilder(AKEY_EVENT_ACTION_DOWN, AINPUT_SOURCE_KEYBOARD)
10779 .policyFlags(DEFAULT_POLICY_FLAGS | POLICY_FLAG_DISABLE_KEY_REPEAT)
10780 .build());
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -070010781 // Key will not be sent to the window, yet, because the window is still processing events
10782 // and the key remains pending, waiting for the touch events to be processed
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070010783 // Make sure that `assertNoEvents` doesn't wait too long, because it could cause an ANR.
Siarhei Vishniakouef2b4502023-12-28 11:51:47 -080010784 mWindow->assertNoEvents(100ms);
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -070010785
Siarhei Vishniakouef2b4502023-12-28 11:51:47 -080010786 std::this_thread::sleep_for(400ms);
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -070010787 // if we wait long enough though, dispatcher will give up, and still send the key
10788 // to the focused window, even though we have not yet finished the motion event
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -070010789 mWindow->consumeKeyDown(ui::LogicalDisplayId::DEFAULT);
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -070010790 mWindow->finishEvent(*downSequenceNum);
10791 mWindow->finishEvent(*upSequenceNum);
10792}
10793
10794/**
10795 * If a window is processing a motion event, and then a key event comes in, the key event should
10796 * not go to the focused window until the motion is processed.
10797 * If then a new motion comes in, then the pending key event should be going to the currently
10798 * focused window right away.
10799 */
10800TEST_F(InputDispatcherSingleWindowAnr,
Siarhei Vishniakouef2b4502023-12-28 11:51:47 -080010801 PendingKey_IsDeliveredWhileMotionIsProcessingAndNewTouchComesIn) {
10802 // The timeouts in this test are established by relying on the fact that the "key waiting for
10803 // events timeout" is equal to 500ms.
10804 ASSERT_EQ(mFakePolicy->getKeyWaitingForEventsTimeout(), 500ms);
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -070010805 mWindow->setDispatchingTimeout(2s); // Set a long ANR timeout to prevent it from triggering
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070010806 mDispatcher->onWindowInfosChanged({{*mWindow->getInfo()}, {}, 0, 0});
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -070010807
10808 tapOnWindow();
Siarhei Vishniakoud3061ab2023-12-18 20:41:08 -080010809 const auto& [downSequenceNum, _] = mWindow->receiveEvent();
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -070010810 ASSERT_TRUE(downSequenceNum);
Siarhei Vishniakoud3061ab2023-12-18 20:41:08 -080010811 const auto& [upSequenceNum, upEvent] = mWindow->receiveEvent();
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -070010812 ASSERT_TRUE(upSequenceNum);
10813 // Don't finish the events yet, and send a key
Siarhei Vishniakou67bf2162023-11-16 13:29:50 -080010814 mDispatcher->notifyKey(
10815 KeyArgsBuilder(AKEY_EVENT_ACTION_DOWN, AINPUT_SOURCE_KEYBOARD)
10816 .policyFlags(DEFAULT_POLICY_FLAGS | POLICY_FLAG_DISABLE_KEY_REPEAT)
10817 .build());
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -070010818 // At this point, key is still pending, and should not be sent to the application yet.
Siarhei Vishniakouef2b4502023-12-28 11:51:47 -080010819 mWindow->assertNoEvents(100ms);
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -070010820
10821 // Now tap down again. It should cause the pending key to go to the focused window right away.
10822 tapOnWindow();
Siarhei Vishniakouef2b4502023-12-28 11:51:47 -080010823 // Now that we tapped, we should receive the key immediately.
10824 // Since there's still room for slowness, we use 200ms, which is much less than
10825 // the "key waiting for events' timeout of 500ms minus the already waited 100ms duration.
10826 std::unique_ptr<InputEvent> keyEvent = mWindow->consume(200ms);
10827 ASSERT_NE(nullptr, keyEvent);
10828 ASSERT_EQ(InputEventType::KEY, keyEvent->getType());
10829 ASSERT_THAT(static_cast<KeyEvent&>(*keyEvent), WithKeyAction(AKEY_EVENT_ACTION_DOWN));
10830 // it doesn't matter that we haven't ack'd the other events yet. We can finish events in any
10831 // order.
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -070010832 mWindow->finishEvent(*downSequenceNum); // first tap's ACTION_DOWN
10833 mWindow->finishEvent(*upSequenceNum); // first tap's ACTION_UP
Siarhei Vishniakou67bf2162023-11-16 13:29:50 -080010834 mWindow->consumeMotionEvent(WithMotionAction(ACTION_DOWN));
10835 mWindow->consumeMotionEvent(WithMotionAction(ACTION_UP));
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -070010836 mWindow->assertNoEvents();
10837}
10838
Siarhei Vishniakouadb9fc92023-05-26 10:46:09 -070010839/**
10840 * Send an event to the app and have the app not respond right away.
10841 * When ANR is raised, policy will tell the dispatcher to cancel the events for that window.
10842 * So InputDispatcher will enqueue ACTION_CANCEL event as well.
10843 * At some point, the window becomes responsive again.
10844 * Ensure that subsequent events get dropped, and the next gesture is delivered.
10845 */
10846TEST_F(InputDispatcherSingleWindowAnr, TwoGesturesWithAnr) {
10847 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
10848 .pointer(PointerBuilder(0, ToolType::FINGER).x(10).y(10))
10849 .build());
10850
Siarhei Vishniakoud3061ab2023-12-18 20:41:08 -080010851 const auto [sequenceNum, _] = mWindow->receiveEvent(); // ACTION_DOWN
Siarhei Vishniakouadb9fc92023-05-26 10:46:09 -070010852 ASSERT_TRUE(sequenceNum);
10853 const std::chrono::duration timeout = mWindow->getDispatchingTimeout(DISPATCHING_TIMEOUT);
10854 mFakePolicy->assertNotifyWindowUnresponsiveWasCalled(timeout, mWindow);
10855
10856 mWindow->finishEvent(*sequenceNum);
10857 mWindow->consumeMotionEvent(WithMotionAction(ACTION_CANCEL));
10858 ASSERT_TRUE(mDispatcher->waitForIdle());
10859 mFakePolicy->assertNotifyWindowResponsiveWasCalled(mWindow->getToken(), mWindow->getPid());
10860
10861 // Now that the window is responsive, let's continue the gesture.
10862 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN)
10863 .pointer(PointerBuilder(0, ToolType::FINGER).x(11).y(11))
10864 .build());
10865
10866 mDispatcher->notifyMotion(MotionArgsBuilder(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
10867 .pointer(PointerBuilder(0, ToolType::FINGER).x(11).y(11))
10868 .pointer(PointerBuilder(1, ToolType::FINGER).x(3).y(3))
10869 .build());
10870
10871 mDispatcher->notifyMotion(MotionArgsBuilder(POINTER_1_UP, AINPUT_SOURCE_TOUCHSCREEN)
10872 .pointer(PointerBuilder(0, ToolType::FINGER).x(11).y(11))
10873 .pointer(PointerBuilder(1, ToolType::FINGER).x(3).y(3))
10874 .build());
10875 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN)
10876 .pointer(PointerBuilder(0, ToolType::FINGER).x(11).y(11))
10877 .build());
10878 // We already canceled this pointer, so the window shouldn't get any new events.
10879 mWindow->assertNoEvents();
10880
10881 // Start another one.
10882 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
10883 .pointer(PointerBuilder(0, ToolType::FINGER).x(15).y(15))
10884 .build());
10885 mWindow->consumeMotionEvent(WithMotionAction(ACTION_DOWN));
10886}
10887
Prabir Pradhanfc364722024-02-08 17:51:20 +000010888// Send an event to the app and have the app not respond right away. Then remove the app window.
10889// When the window is removed, the dispatcher will cancel the events for that window.
10890// So InputDispatcher will enqueue ACTION_CANCEL event as well.
10891TEST_F(InputDispatcherSingleWindowAnr, AnrAfterWindowRemoval) {
10892 mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_DOWN,
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -070010893 AINPUT_SOURCE_TOUCHSCREEN,
10894 ui::LogicalDisplayId::DEFAULT, {WINDOW_LOCATION}));
Prabir Pradhanfc364722024-02-08 17:51:20 +000010895
10896 const auto [sequenceNum, _] = mWindow->receiveEvent(); // ACTION_DOWN
10897 ASSERT_TRUE(sequenceNum);
10898
10899 // Remove the window, but the input channel should remain alive.
10900 mDispatcher->onWindowInfosChanged({{}, {}, 0, 0});
10901
10902 const std::chrono::duration timeout = mWindow->getDispatchingTimeout(DISPATCHING_TIMEOUT);
10903 // Since the window was removed, Dispatcher does not know the PID associated with the window
10904 // anymore, so the policy is notified without the PID.
10905 mFakePolicy->assertNotifyWindowUnresponsiveWasCalled(timeout, mWindow->getToken(),
10906 /*pid=*/std::nullopt);
10907
10908 mWindow->finishEvent(*sequenceNum);
10909 // The cancellation was generated when the window was removed, along with the focus event.
10910 mWindow->consumeMotionEvent(
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -070010911 AllOf(WithMotionAction(ACTION_CANCEL), WithDisplayId(ui::LogicalDisplayId::DEFAULT)));
Prabir Pradhanfc364722024-02-08 17:51:20 +000010912 mWindow->consumeFocusEvent(false);
10913 ASSERT_TRUE(mDispatcher->waitForIdle());
10914 mFakePolicy->assertNotifyWindowResponsiveWasCalled(mWindow->getToken(), /*pid=*/std::nullopt);
10915}
10916
10917// Send an event to the app and have the app not respond right away. Wait for the policy to be
10918// notified of the unresponsive window, then remove the app window.
10919TEST_F(InputDispatcherSingleWindowAnr, AnrFollowedByWindowRemoval) {
10920 mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_DOWN,
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -070010921 AINPUT_SOURCE_TOUCHSCREEN,
10922 ui::LogicalDisplayId::DEFAULT, {WINDOW_LOCATION}));
Prabir Pradhanfc364722024-02-08 17:51:20 +000010923
10924 const auto [sequenceNum, _] = mWindow->receiveEvent(); // ACTION_DOWN
10925 ASSERT_TRUE(sequenceNum);
10926 const std::chrono::duration timeout = mWindow->getDispatchingTimeout(DISPATCHING_TIMEOUT);
10927 mFakePolicy->assertNotifyWindowUnresponsiveWasCalled(timeout, mWindow);
10928
10929 // Remove the window, but the input channel should remain alive.
10930 mDispatcher->onWindowInfosChanged({{}, {}, 0, 0});
10931
10932 mWindow->finishEvent(*sequenceNum);
10933 // The cancellation was generated during the ANR, and the window lost focus when it was removed.
10934 mWindow->consumeMotionEvent(
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -070010935 AllOf(WithMotionAction(ACTION_CANCEL), WithDisplayId(ui::LogicalDisplayId::DEFAULT)));
Prabir Pradhanfc364722024-02-08 17:51:20 +000010936 mWindow->consumeFocusEvent(false);
10937 ASSERT_TRUE(mDispatcher->waitForIdle());
10938 // Since the window was removed, Dispatcher does not know the PID associated with the window
10939 // becoming responsive, so the policy is notified without the PID.
10940 mFakePolicy->assertNotifyWindowResponsiveWasCalled(mWindow->getToken(), /*pid=*/std::nullopt);
10941}
10942
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -070010943class InputDispatcherMultiWindowAnr : public InputDispatcherTest {
10944 virtual void SetUp() override {
10945 InputDispatcherTest::SetUp();
10946
Chris Yea209fde2020-07-22 13:54:51 -070010947 mApplication = std::make_shared<FakeApplicationHandle>();
Siarhei Vishniakouf83c6932023-07-07 17:48:10 -070010948 mApplication->setDispatchingTimeout(100ms);
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -070010949 mUnfocusedWindow = sp<FakeWindowHandle>::make(mApplication, mDispatcher, "Unfocused",
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -070010950 ui::LogicalDisplayId::DEFAULT);
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -070010951 mUnfocusedWindow->setFrame(Rect(0, 0, 30, 30));
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -070010952 // Adding FLAG_WATCH_OUTSIDE_TOUCH to receive ACTION_OUTSIDE when another window is tapped
Prabir Pradhan4d5c52f2022-01-31 08:52:10 -080010953 mUnfocusedWindow->setWatchOutsideTouch(true);
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -070010954
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -070010955 mFocusedWindow = sp<FakeWindowHandle>::make(mApplication, mDispatcher, "Focused",
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -070010956 ui::LogicalDisplayId::DEFAULT);
Siarhei Vishniakouf83c6932023-07-07 17:48:10 -070010957 mFocusedWindow->setDispatchingTimeout(100ms);
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -070010958 mFocusedWindow->setFrame(Rect(50, 50, 100, 100));
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -070010959
10960 // Set focused application.
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -070010961 mDispatcher->setFocusedApplication(ui::LogicalDisplayId::DEFAULT, mApplication);
Vishnu Nair47074b82020-08-14 11:54:47 -070010962 mFocusedWindow->setFocusable(true);
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -070010963
10964 // Expect one focus window exist in display.
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070010965 mDispatcher->onWindowInfosChanged(
10966 {{*mUnfocusedWindow->getInfo(), *mFocusedWindow->getInfo()}, {}, 0, 0});
Vishnu Nair958da932020-08-21 17:12:37 -070010967 setFocusedWindow(mFocusedWindow);
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -070010968 mFocusedWindow->consumeFocusEvent(true);
10969 }
10970
10971 virtual void TearDown() override {
10972 InputDispatcherTest::TearDown();
10973
10974 mUnfocusedWindow.clear();
10975 mFocusedWindow.clear();
10976 }
10977
10978protected:
Chris Yea209fde2020-07-22 13:54:51 -070010979 std::shared_ptr<FakeApplicationHandle> mApplication;
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -070010980 sp<FakeWindowHandle> mUnfocusedWindow;
10981 sp<FakeWindowHandle> mFocusedWindow;
10982 static constexpr PointF UNFOCUSED_WINDOW_LOCATION = {20, 20};
10983 static constexpr PointF FOCUSED_WINDOW_LOCATION = {75, 75};
10984 static constexpr PointF LOCATION_OUTSIDE_ALL_WINDOWS = {40, 40};
10985
10986 void tapOnFocusedWindow() { tap(FOCUSED_WINDOW_LOCATION); }
10987
10988 void tapOnUnfocusedWindow() { tap(UNFOCUSED_WINDOW_LOCATION); }
10989
10990private:
10991 void tap(const PointF& location) {
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -080010992 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -070010993 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN,
10994 ui::LogicalDisplayId::DEFAULT, location));
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -080010995 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -070010996 injectMotionUp(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN,
10997 ui::LogicalDisplayId::DEFAULT, location));
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -070010998 }
10999};
11000
11001// If we have 2 windows that are both unresponsive, the one with the shortest timeout
11002// should be ANR'd first.
11003TEST_F(InputDispatcherMultiWindowAnr, TwoWindows_BothUnresponsive) {
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -080011004 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakou2899c552023-07-10 18:20:46 -070011005 injectMotionEvent(*mDispatcher,
11006 MotionEventBuilder(AMOTION_EVENT_ACTION_DOWN,
11007 AINPUT_SOURCE_TOUCHSCREEN)
11008 .pointer(PointerBuilder(0, ToolType::FINGER)
11009 .x(FOCUSED_WINDOW_LOCATION.x)
11010 .y(FOCUSED_WINDOW_LOCATION.y))
11011 .build()));
11012 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
11013 injectMotionEvent(*mDispatcher,
11014 MotionEventBuilder(AMOTION_EVENT_ACTION_UP,
11015 AINPUT_SOURCE_TOUCHSCREEN)
11016 .pointer(PointerBuilder(0, ToolType::FINGER)
11017 .x(FOCUSED_WINDOW_LOCATION.x)
11018 .y(FOCUSED_WINDOW_LOCATION.y))
11019 .build()));
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -070011020 mFocusedWindow->consumeMotionDown();
Siarhei Vishniakou2899c552023-07-10 18:20:46 -070011021 mFocusedWindow->consumeMotionUp();
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -070011022 mUnfocusedWindow->consumeMotionOutside(ui::LogicalDisplayId::DEFAULT, /*flags=*/0);
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -070011023 // We consumed all events, so no ANR
11024 ASSERT_TRUE(mDispatcher->waitForIdle());
11025 mFakePolicy->assertNotifyAnrWasNotCalled();
11026
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -080011027 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakou2899c552023-07-10 18:20:46 -070011028 injectMotionEvent(*mDispatcher,
11029 MotionEventBuilder(AMOTION_EVENT_ACTION_DOWN,
11030 AINPUT_SOURCE_TOUCHSCREEN)
11031 .pointer(PointerBuilder(0, ToolType::FINGER)
11032 .x(FOCUSED_WINDOW_LOCATION.x)
11033 .y(FOCUSED_WINDOW_LOCATION.y))
11034 .build()));
Siarhei Vishniakoud3061ab2023-12-18 20:41:08 -080011035 const auto [unfocusedSequenceNum, _] = mUnfocusedWindow->receiveEvent();
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -070011036 ASSERT_TRUE(unfocusedSequenceNum);
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -070011037
11038 const std::chrono::duration timeout =
11039 mFocusedWindow->getDispatchingTimeout(DISPATCHING_TIMEOUT);
Prabir Pradhanedd96402022-02-15 01:46:16 -080011040 mFakePolicy->assertNotifyWindowUnresponsiveWasCalled(timeout, mFocusedWindow);
Siarhei Vishniakou2899c552023-07-10 18:20:46 -070011041
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -070011042 mUnfocusedWindow->finishEvent(*unfocusedSequenceNum);
Siarhei Vishniakou234129c2020-10-22 22:28:12 -050011043 mFocusedWindow->consumeMotionDown();
11044 // This cancel is generated because the connection was unresponsive
11045 mFocusedWindow->consumeMotionCancel();
11046 mFocusedWindow->assertNoEvents();
11047 mUnfocusedWindow->assertNoEvents();
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -070011048 ASSERT_TRUE(mDispatcher->waitForIdle());
Prabir Pradhanedd96402022-02-15 01:46:16 -080011049 mFakePolicy->assertNotifyWindowResponsiveWasCalled(mFocusedWindow->getToken(),
11050 mFocusedWindow->getPid());
Siarhei Vishniakou234129c2020-10-22 22:28:12 -050011051 mFakePolicy->assertNotifyAnrWasNotCalled();
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -070011052}
11053
11054// If we have 2 windows with identical timeouts that are both unresponsive,
11055// it doesn't matter which order they should have ANR.
11056// But we should receive ANR for both.
11057TEST_F(InputDispatcherMultiWindowAnr, TwoWindows_BothUnresponsiveWithSameTimeout) {
11058 // Set the timeout for unfocused window to match the focused window
Siarhei Vishniakouf83c6932023-07-07 17:48:10 -070011059 mUnfocusedWindow->setDispatchingTimeout(
11060 mFocusedWindow->getDispatchingTimeout(DISPATCHING_TIMEOUT));
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070011061 mDispatcher->onWindowInfosChanged(
11062 {{*mUnfocusedWindow->getInfo(), *mFocusedWindow->getInfo()}, {}, 0, 0});
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -070011063
11064 tapOnFocusedWindow();
11065 // we should have ACTION_DOWN/ACTION_UP on focused window and ACTION_OUTSIDE on unfocused window
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -070011066 // We don't know which window will ANR first. But both of them should happen eventually.
Siarhei Vishniakouf83c6932023-07-07 17:48:10 -070011067 std::array<sp<IBinder>, 2> anrConnectionTokens = {mFakePolicy->getUnresponsiveWindowToken(
11068 mFocusedWindow->getDispatchingTimeout(
11069 DISPATCHING_TIMEOUT)),
11070 mFakePolicy->getUnresponsiveWindowToken(0ms)};
11071
11072 ASSERT_THAT(anrConnectionTokens,
11073 ::testing::UnorderedElementsAre(testing::Eq(mFocusedWindow->getToken()),
11074 testing::Eq(mUnfocusedWindow->getToken())));
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -070011075
11076 ASSERT_TRUE(mDispatcher->waitForIdle());
11077 mFakePolicy->assertNotifyAnrWasNotCalled();
Siarhei Vishniakou234129c2020-10-22 22:28:12 -050011078
11079 mFocusedWindow->consumeMotionDown();
11080 mFocusedWindow->consumeMotionUp();
11081 mUnfocusedWindow->consumeMotionOutside();
11082
Siarhei Vishniakouf83c6932023-07-07 17:48:10 -070011083 std::array<sp<IBinder>, 2> responsiveTokens = {mFakePolicy->getResponsiveWindowToken(),
11084 mFakePolicy->getResponsiveWindowToken()};
Siarhei Vishniakou234129c2020-10-22 22:28:12 -050011085
11086 // Both applications should be marked as responsive, in any order
Siarhei Vishniakouf83c6932023-07-07 17:48:10 -070011087 ASSERT_THAT(responsiveTokens,
11088 ::testing::UnorderedElementsAre(testing::Eq(mFocusedWindow->getToken()),
11089 testing::Eq(mUnfocusedWindow->getToken())));
Siarhei Vishniakou234129c2020-10-22 22:28:12 -050011090 mFakePolicy->assertNotifyAnrWasNotCalled();
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -070011091}
11092
11093// If a window is already not responding, the second tap on the same window should be ignored.
11094// We should also log an error to account for the dropped event (not tested here).
11095// At the same time, FLAG_WATCH_OUTSIDE_TOUCH targets should not receive any events.
11096TEST_F(InputDispatcherMultiWindowAnr, DuringAnr_SecondTapIsIgnored) {
11097 tapOnFocusedWindow();
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -070011098 mUnfocusedWindow->consumeMotionOutside(ui::LogicalDisplayId::DEFAULT, /*flags=*/0);
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -070011099 // Receive the events, but don't respond
Siarhei Vishniakoud3061ab2023-12-18 20:41:08 -080011100 const auto [downEventSequenceNum, downEvent] = mFocusedWindow->receiveEvent(); // ACTION_DOWN
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -070011101 ASSERT_TRUE(downEventSequenceNum);
Siarhei Vishniakoud3061ab2023-12-18 20:41:08 -080011102 const auto [upEventSequenceNum, upEvent] = mFocusedWindow->receiveEvent(); // ACTION_UP
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -070011103 ASSERT_TRUE(upEventSequenceNum);
11104 const std::chrono::duration timeout =
11105 mFocusedWindow->getDispatchingTimeout(DISPATCHING_TIMEOUT);
Prabir Pradhanedd96402022-02-15 01:46:16 -080011106 mFakePolicy->assertNotifyWindowUnresponsiveWasCalled(timeout, mFocusedWindow);
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -070011107
11108 // Tap once again
11109 // We cannot use "tapOnFocusedWindow" because it asserts the injection result to be success
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -080011110 ASSERT_EQ(InputEventInjectionResult::FAILED,
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -070011111 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN,
11112 ui::LogicalDisplayId::DEFAULT, FOCUSED_WINDOW_LOCATION));
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -080011113 ASSERT_EQ(InputEventInjectionResult::FAILED,
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -070011114 injectMotionUp(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ui::LogicalDisplayId::DEFAULT,
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -070011115 FOCUSED_WINDOW_LOCATION));
11116 // Unfocused window does not receive ACTION_OUTSIDE because the tapped window is not a
11117 // valid touch target
11118 mUnfocusedWindow->assertNoEvents();
11119
11120 // Consume the first tap
11121 mFocusedWindow->finishEvent(*downEventSequenceNum);
11122 mFocusedWindow->finishEvent(*upEventSequenceNum);
11123 ASSERT_TRUE(mDispatcher->waitForIdle());
11124 // The second tap did not go to the focused window
11125 mFocusedWindow->assertNoEvents();
Siarhei Vishniakou234129c2020-10-22 22:28:12 -050011126 // Since all events are finished, connection should be deemed healthy again
Prabir Pradhanedd96402022-02-15 01:46:16 -080011127 mFakePolicy->assertNotifyWindowResponsiveWasCalled(mFocusedWindow->getToken(),
11128 mFocusedWindow->getPid());
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -070011129 mFakePolicy->assertNotifyAnrWasNotCalled();
11130}
11131
11132// If you tap outside of all windows, there will not be ANR
11133TEST_F(InputDispatcherMultiWindowAnr, TapOutsideAllWindows_DoesNotAnr) {
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -080011134 ASSERT_EQ(InputEventInjectionResult::FAILED,
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -070011135 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN,
11136 ui::LogicalDisplayId::DEFAULT, LOCATION_OUTSIDE_ALL_WINDOWS));
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -070011137 ASSERT_TRUE(mDispatcher->waitForIdle());
11138 mFakePolicy->assertNotifyAnrWasNotCalled();
11139}
11140
11141// Since the focused window is paused, tapping on it should not produce any events
11142TEST_F(InputDispatcherMultiWindowAnr, Window_CanBePaused) {
11143 mFocusedWindow->setPaused(true);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070011144 mDispatcher->onWindowInfosChanged(
11145 {{*mUnfocusedWindow->getInfo(), *mFocusedWindow->getInfo()}, {}, 0, 0});
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -070011146
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -080011147 ASSERT_EQ(InputEventInjectionResult::FAILED,
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -070011148 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN,
11149 ui::LogicalDisplayId::DEFAULT, FOCUSED_WINDOW_LOCATION));
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -070011150
11151 std::this_thread::sleep_for(mFocusedWindow->getDispatchingTimeout(DISPATCHING_TIMEOUT));
11152 ASSERT_TRUE(mDispatcher->waitForIdle());
11153 // Should not ANR because the window is paused, and touches shouldn't go to it
11154 mFakePolicy->assertNotifyAnrWasNotCalled();
11155
11156 mFocusedWindow->assertNoEvents();
11157 mUnfocusedWindow->assertNoEvents();
11158}
11159
11160/**
11161 * 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 -070011162 * not get delivered to the focused window until the motion is processed.
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -070011163 * If a different window becomes focused at this time, the key should go to that window instead.
11164 *
11165 * Warning!!!
11166 * This test depends on the value of android::inputdispatcher::KEY_WAITING_FOR_MOTION_TIMEOUT
11167 * and the injection timeout that we specify when injecting the key.
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070011168 * We must have the injection timeout (100ms) be smaller than
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -070011169 * KEY_WAITING_FOR_MOTION_TIMEOUT (currently 500ms).
11170 *
11171 * If that value changes, this test should also change.
11172 */
11173TEST_F(InputDispatcherMultiWindowAnr, PendingKey_GoesToNewlyFocusedWindow) {
11174 // Set a long ANR timeout to prevent it from triggering
11175 mFocusedWindow->setDispatchingTimeout(2s);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070011176 mDispatcher->onWindowInfosChanged(
11177 {{*mFocusedWindow->getInfo(), *mUnfocusedWindow->getInfo()}, {}, 0, 0});
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -070011178
11179 tapOnUnfocusedWindow();
Siarhei Vishniakoud3061ab2023-12-18 20:41:08 -080011180 const auto [downSequenceNum, downEvent] = mUnfocusedWindow->receiveEvent();
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -070011181 ASSERT_TRUE(downSequenceNum);
Siarhei Vishniakoud3061ab2023-12-18 20:41:08 -080011182 const auto [upSequenceNum, upEvent] = mUnfocusedWindow->receiveEvent();
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -070011183 ASSERT_TRUE(upSequenceNum);
11184 // Don't finish the events yet, and send a key
11185 // Injection will succeed because we will eventually give up and send the key to the focused
11186 // window even if motions are still being processed.
11187
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -080011188 InputEventInjectionResult result =
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -070011189 injectKey(*mDispatcher, AKEY_EVENT_ACTION_DOWN, /*repeatCount=*/0,
11190 ui::LogicalDisplayId::DEFAULT, InputEventInjectionSync::NONE,
Linnan Li13bf76a2024-05-05 19:18:02 +080011191 /*injectionTimeout=*/100ms);
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -080011192 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, result);
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -070011193 // Key will not be sent to the window, yet, because the window is still processing events
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070011194 // and the key remains pending, waiting for the touch events to be processed.
11195 // Make sure `assertNoEvents` doesn't take too long. It uses CONSUME_TIMEOUT_NO_EVENT_EXPECTED
11196 // under the hood.
11197 static_assert(CONSUME_TIMEOUT_NO_EVENT_EXPECTED < 100ms);
11198 mFocusedWindow->assertNoEvents();
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -070011199
11200 // Switch the focus to the "unfocused" window that we tapped. Expect the key to go there
Vishnu Nair47074b82020-08-14 11:54:47 -070011201 mFocusedWindow->setFocusable(false);
11202 mUnfocusedWindow->setFocusable(true);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070011203 mDispatcher->onWindowInfosChanged(
11204 {{*mFocusedWindow->getInfo(), *mUnfocusedWindow->getInfo()}, {}, 0, 0});
Vishnu Nair958da932020-08-21 17:12:37 -070011205 setFocusedWindow(mUnfocusedWindow);
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -070011206
11207 // Focus events should precede the key events
11208 mUnfocusedWindow->consumeFocusEvent(true);
11209 mFocusedWindow->consumeFocusEvent(false);
11210
11211 // Finish the tap events, which should unblock dispatcher
11212 mUnfocusedWindow->finishEvent(*downSequenceNum);
11213 mUnfocusedWindow->finishEvent(*upSequenceNum);
11214
11215 // Now that all queues are cleared and no backlog in the connections, the key event
11216 // can finally go to the newly focused "mUnfocusedWindow".
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -070011217 mUnfocusedWindow->consumeKeyDown(ui::LogicalDisplayId::DEFAULT);
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -070011218 mFocusedWindow->assertNoEvents();
11219 mUnfocusedWindow->assertNoEvents();
Siarhei Vishniakou234129c2020-10-22 22:28:12 -050011220 mFakePolicy->assertNotifyAnrWasNotCalled();
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -070011221}
11222
11223// When the touch stream is split across 2 windows, and one of them does not respond,
11224// then ANR should be raised and the touch should be canceled for the unresponsive window.
11225// The other window should not be affected by that.
11226TEST_F(InputDispatcherMultiWindowAnr, SplitTouch_SingleWindowAnr) {
11227 // Touch Window 1
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -070011228 mDispatcher->notifyMotion(
11229 generateMotionArgs(AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN,
11230 ui::LogicalDisplayId::DEFAULT, {FOCUSED_WINDOW_LOCATION}));
11231 mUnfocusedWindow->consumeMotionOutside(ui::LogicalDisplayId::DEFAULT, /*flags=*/0);
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -070011232
11233 // Touch Window 2
Prabir Pradhan678438e2023-04-13 19:32:51 +000011234 mDispatcher->notifyMotion(
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -070011235 generateMotionArgs(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN,
11236 ui::LogicalDisplayId::DEFAULT,
Prabir Pradhan678438e2023-04-13 19:32:51 +000011237 {FOCUSED_WINDOW_LOCATION, UNFOCUSED_WINDOW_LOCATION}));
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -070011238
11239 const std::chrono::duration timeout =
11240 mFocusedWindow->getDispatchingTimeout(DISPATCHING_TIMEOUT);
Prabir Pradhanedd96402022-02-15 01:46:16 -080011241 mFakePolicy->assertNotifyWindowUnresponsiveWasCalled(timeout, mFocusedWindow);
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -070011242
11243 mUnfocusedWindow->consumeMotionDown();
11244 mFocusedWindow->consumeMotionDown();
11245 // Focused window may or may not receive ACTION_MOVE
11246 // But it should definitely receive ACTION_CANCEL due to the ANR
Siarhei Vishniakoud3061ab2023-12-18 20:41:08 -080011247 const auto [moveOrCancelSequenceNum, event] = mFocusedWindow->receiveEvent();
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -070011248 ASSERT_TRUE(moveOrCancelSequenceNum);
11249 mFocusedWindow->finishEvent(*moveOrCancelSequenceNum);
11250 ASSERT_NE(nullptr, event);
Siarhei Vishniakou63b63612023-04-12 11:00:23 -070011251 ASSERT_EQ(event->getType(), InputEventType::MOTION);
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -070011252 MotionEvent& motionEvent = static_cast<MotionEvent&>(*event);
11253 if (motionEvent.getAction() == AMOTION_EVENT_ACTION_MOVE) {
11254 mFocusedWindow->consumeMotionCancel();
11255 } else {
11256 ASSERT_EQ(AMOTION_EVENT_ACTION_CANCEL, motionEvent.getAction());
11257 }
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -070011258 ASSERT_TRUE(mDispatcher->waitForIdle());
Prabir Pradhanedd96402022-02-15 01:46:16 -080011259 mFakePolicy->assertNotifyWindowResponsiveWasCalled(mFocusedWindow->getToken(),
11260 mFocusedWindow->getPid());
Siarhei Vishniakou234129c2020-10-22 22:28:12 -050011261
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -070011262 mUnfocusedWindow->assertNoEvents();
11263 mFocusedWindow->assertNoEvents();
Siarhei Vishniakou234129c2020-10-22 22:28:12 -050011264 mFakePolicy->assertNotifyAnrWasNotCalled();
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -070011265}
11266
Siarhei Vishniakouf56b2692020-09-08 19:43:33 -050011267/**
11268 * If we have no focused window, and a key comes in, we start the ANR timer.
11269 * The focused application should add a focused window before the timer runs out to prevent ANR.
11270 *
11271 * If the user touches another application during this time, the key should be dropped.
11272 * Next, if a new focused window comes in, without toggling the focused application,
11273 * then no ANR should occur.
11274 *
11275 * Normally, we would expect the new focused window to be accompanied by 'setFocusedApplication',
11276 * but in some cases the policy may not update the focused application.
11277 */
11278TEST_F(InputDispatcherMultiWindowAnr, FocusedWindowWithoutSetFocusedApplication_NoAnr) {
11279 std::shared_ptr<FakeApplicationHandle> focusedApplication =
11280 std::make_shared<FakeApplicationHandle>();
Siarhei Vishniakouc033dfb2023-10-03 10:45:16 -070011281 focusedApplication->setDispatchingTimeout(300ms);
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -070011282 mDispatcher->setFocusedApplication(ui::LogicalDisplayId::DEFAULT, focusedApplication);
Siarhei Vishniakouf56b2692020-09-08 19:43:33 -050011283 // The application that owns 'mFocusedWindow' and 'mUnfocusedWindow' is not focused.
11284 mFocusedWindow->setFocusable(false);
11285
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070011286 mDispatcher->onWindowInfosChanged(
11287 {{*mFocusedWindow->getInfo(), *mUnfocusedWindow->getInfo()}, {}, 0, 0});
Siarhei Vishniakouf56b2692020-09-08 19:43:33 -050011288 mFocusedWindow->consumeFocusEvent(false);
11289
11290 // Send a key. The ANR timer should start because there is no focused window.
11291 // 'focusedApplication' will get blamed if this timer completes.
11292 // Key will not be sent anywhere because we have no focused window. It will remain pending.
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -080011293 InputEventInjectionResult result =
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -070011294 injectKey(*mDispatcher, AKEY_EVENT_ACTION_DOWN, /*repeatCount=*/0,
11295 ui::LogicalDisplayId::DEFAULT, InputEventInjectionSync::NONE,
Linnan Li13bf76a2024-05-05 19:18:02 +080011296 /*injectionTimeout=*/100ms,
Harry Cutts33476232023-01-30 19:57:29 +000011297 /*allowKeyRepeat=*/false);
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -080011298 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, result);
Siarhei Vishniakouf56b2692020-09-08 19:43:33 -050011299
11300 // Wait until dispatcher starts the "no focused window" timer. If we don't wait here,
11301 // then the injected touches won't cause the focused event to get dropped.
11302 // The dispatcher only checks for whether the queue should be pruned upon queueing.
11303 // If we inject the touch right away and the ANR timer hasn't started, the touch event would
11304 // simply be added to the queue without 'shouldPruneInboundQueueLocked' returning 'true'.
11305 // For this test, it means that the key would get delivered to the window once it becomes
11306 // focused.
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070011307 std::this_thread::sleep_for(100ms);
Siarhei Vishniakouf56b2692020-09-08 19:43:33 -050011308
11309 // Touch unfocused window. This should force the pending key to get dropped.
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -070011310 mDispatcher->notifyMotion(
11311 generateMotionArgs(AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN,
11312 ui::LogicalDisplayId::DEFAULT, {UNFOCUSED_WINDOW_LOCATION}));
Siarhei Vishniakouf56b2692020-09-08 19:43:33 -050011313
11314 // We do not consume the motion right away, because that would require dispatcher to first
11315 // process (== drop) the key event, and by that time, ANR will be raised.
11316 // Set the focused window first.
11317 mFocusedWindow->setFocusable(true);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070011318 mDispatcher->onWindowInfosChanged(
11319 {{*mFocusedWindow->getInfo(), *mUnfocusedWindow->getInfo()}, {}, 0, 0});
Siarhei Vishniakouf56b2692020-09-08 19:43:33 -050011320 setFocusedWindow(mFocusedWindow);
11321 mFocusedWindow->consumeFocusEvent(true);
11322 // We do not call "setFocusedApplication" here, even though the newly focused window belongs
11323 // to another application. This could be a bug / behaviour in the policy.
11324
11325 mUnfocusedWindow->consumeMotionDown();
11326
11327 ASSERT_TRUE(mDispatcher->waitForIdle());
11328 // Should not ANR because we actually have a focused window. It was just added too slowly.
11329 ASSERT_NO_FATAL_FAILURE(mFakePolicy->assertNotifyAnrWasNotCalled());
11330}
11331
Siarhei Vishniakou99e407b2023-12-26 18:09:32 -080011332/**
11333 * If we are pruning input queue, we should never drop pointer events. Otherwise, we risk having
11334 * an inconsistent event stream inside the dispatcher. In this test, we make sure that the
11335 * dispatcher doesn't prune pointer events incorrectly.
11336 *
11337 * This test reproduces a crash in InputDispatcher.
11338 * To reproduce the crash, we need to simulate the conditions for "pruning input queue" to occur.
11339 *
11340 * Keep the currently focused application (mApplication), and have no focused window.
11341 * We set up two additional windows:
11342 * 1) The navigation bar window. This simulates the system "NavigationBar", which is used in the
11343 * 3-button navigation mode. This window injects a BACK button when it's touched. 2) The application
11344 * window. This window is not focusable, but is touchable.
11345 *
11346 * We first touch the navigation bar, which causes it to inject a key. Since there's no focused
11347 * window, the dispatcher doesn't process this key, and all other events inside dispatcher are now
11348 * blocked. The dispatcher is waiting for 'mApplication' to add a focused window.
11349 *
11350 * Now, we touch "Another window". This window is owned by a different application than
11351 * 'mApplication'. This causes the dispatcher to stop waiting for 'mApplication' to add a focused
11352 * window. Now, the "pruning input queue" behaviour should kick in, and the dispatcher should start
11353 * dropping the events from its queue. Ensure that no crash occurs.
11354 *
11355 * In this test, we are setting long timeouts to prevent ANRs and events dropped due to being stale.
11356 * This does not affect the test running time.
11357 */
11358TEST_F(InputDispatcherMultiWindowAnr, PruningInputQueueShouldNotDropPointerEvents) {
11359 std::shared_ptr<FakeApplicationHandle> systemUiApplication =
11360 std::make_shared<FakeApplicationHandle>();
11361 systemUiApplication->setDispatchingTimeout(3000ms);
11362 mFakePolicy->setStaleEventTimeout(3000ms);
11363 sp<FakeWindowHandle> navigationBar =
11364 sp<FakeWindowHandle>::make(systemUiApplication, mDispatcher, "NavigationBar",
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -070011365 ui::LogicalDisplayId::DEFAULT);
Siarhei Vishniakou99e407b2023-12-26 18:09:32 -080011366 navigationBar->setFocusable(false);
11367 navigationBar->setWatchOutsideTouch(true);
11368 navigationBar->setFrame(Rect(0, 0, 100, 100));
11369
11370 mApplication->setDispatchingTimeout(3000ms);
11371 // 'mApplication' is already focused, but we call it again here to make it explicit.
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -070011372 mDispatcher->setFocusedApplication(ui::LogicalDisplayId::DEFAULT, mApplication);
Siarhei Vishniakou99e407b2023-12-26 18:09:32 -080011373
11374 std::shared_ptr<FakeApplicationHandle> anotherApplication =
11375 std::make_shared<FakeApplicationHandle>();
11376 sp<FakeWindowHandle> appWindow =
11377 sp<FakeWindowHandle>::make(anotherApplication, mDispatcher, "Another window",
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -070011378 ui::LogicalDisplayId::DEFAULT);
Siarhei Vishniakou99e407b2023-12-26 18:09:32 -080011379 appWindow->setFocusable(false);
11380 appWindow->setFrame(Rect(100, 100, 200, 200));
11381
11382 mDispatcher->onWindowInfosChanged(
11383 {{*navigationBar->getInfo(), *appWindow->getInfo()}, {}, 0, 0});
11384 // 'mFocusedWindow' is no longer in the dispatcher window list, and therefore loses focus
11385 mFocusedWindow->consumeFocusEvent(false);
11386
11387 // Touch down the navigation bar. It consumes the touch and injects a key into the dispatcher
11388 // in response.
11389 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
11390 .pointer(PointerBuilder(0, ToolType::FINGER).x(50).y(50))
11391 .build());
11392 navigationBar->consumeMotionEvent(WithMotionAction(ACTION_DOWN));
11393
11394 // Key will not be sent anywhere because we have no focused window. It will remain pending.
11395 // Pretend we are injecting KEYCODE_BACK, but it doesn't actually matter what key it is.
11396 InputEventInjectionResult result =
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -070011397 injectKey(*mDispatcher, AKEY_EVENT_ACTION_DOWN, /*repeatCount=*/0,
11398 ui::LogicalDisplayId::DEFAULT, InputEventInjectionSync::NONE,
Linnan Li13bf76a2024-05-05 19:18:02 +080011399 /*injectionTimeout=*/100ms,
Siarhei Vishniakou99e407b2023-12-26 18:09:32 -080011400 /*allowKeyRepeat=*/false);
11401 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, result);
11402
11403 // Finish the gesture - lift up finger and inject ACTION_UP key event
11404 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN)
11405 .pointer(PointerBuilder(0, ToolType::FINGER).x(50).y(50))
11406 .build());
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -070011407 result = injectKey(*mDispatcher, AKEY_EVENT_ACTION_UP, /*repeatCount=*/0,
11408 ui::LogicalDisplayId::DEFAULT, InputEventInjectionSync::NONE,
Linnan Li13bf76a2024-05-05 19:18:02 +080011409 /*injectionTimeout=*/100ms,
Siarhei Vishniakou99e407b2023-12-26 18:09:32 -080011410 /*allowKeyRepeat=*/false);
11411 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, result);
11412 // The key that was injected is blocking the dispatcher, so the navigation bar shouldn't be
11413 // getting any events yet.
11414 navigationBar->assertNoEvents();
11415
11416 // Now touch "Another window". This touch is going to a different application than the one we
11417 // are waiting for (which is 'mApplication').
11418 // This should cause the dispatcher to drop the pending focus-dispatched events (like the key
11419 // trying to be injected) and to continue processing the rest of the events in the original
11420 // order.
11421 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
11422 .pointer(PointerBuilder(0, ToolType::FINGER).x(150).y(150))
11423 .build());
11424 navigationBar->consumeMotionEvent(WithMotionAction(ACTION_UP));
11425 navigationBar->consumeMotionEvent(WithMotionAction(ACTION_OUTSIDE));
11426 appWindow->consumeMotionEvent(WithMotionAction(ACTION_DOWN));
11427
11428 appWindow->assertNoEvents();
11429 navigationBar->assertNoEvents();
11430}
11431
Siarhei Vishniakoua2862a02020-07-20 16:36:46 -050011432// These tests ensure we cannot send touch events to a window that's positioned behind a window
11433// that has feature NO_INPUT_CHANNEL.
11434// Layout:
11435// Top (closest to user)
11436// mNoInputWindow (above all windows)
11437// mBottomWindow
11438// Bottom (furthest from user)
11439class InputDispatcherMultiWindowOcclusionTests : public InputDispatcherTest {
11440 virtual void SetUp() override {
11441 InputDispatcherTest::SetUp();
11442
11443 mApplication = std::make_shared<FakeApplicationHandle>();
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -070011444 mNoInputWindow = sp<FakeWindowHandle>::make(mApplication, mDispatcher,
11445 "Window without input channel",
11446 ui::LogicalDisplayId::DEFAULT,
11447 /*createInputChannel=*/false);
Prabir Pradhan51e7db02022-02-07 06:02:57 -080011448 mNoInputWindow->setNoInputChannel(true);
Siarhei Vishniakoua2862a02020-07-20 16:36:46 -050011449 mNoInputWindow->setFrame(Rect(0, 0, 100, 100));
11450 // It's perfectly valid for this window to not have an associated input channel
11451
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -070011452 mBottomWindow = sp<FakeWindowHandle>::make(mApplication, mDispatcher, "Bottom window",
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -070011453 ui::LogicalDisplayId::DEFAULT);
Siarhei Vishniakoua2862a02020-07-20 16:36:46 -050011454 mBottomWindow->setFrame(Rect(0, 0, 100, 100));
11455
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070011456 mDispatcher->onWindowInfosChanged(
11457 {{*mNoInputWindow->getInfo(), *mBottomWindow->getInfo()}, {}, 0, 0});
Siarhei Vishniakoua2862a02020-07-20 16:36:46 -050011458 }
11459
11460protected:
11461 std::shared_ptr<FakeApplicationHandle> mApplication;
11462 sp<FakeWindowHandle> mNoInputWindow;
11463 sp<FakeWindowHandle> mBottomWindow;
11464};
11465
11466TEST_F(InputDispatcherMultiWindowOcclusionTests, NoInputChannelFeature_DropsTouches) {
11467 PointF touchedPoint = {10, 10};
11468
Prabir Pradhan678438e2023-04-13 19:32:51 +000011469 mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_DOWN,
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -070011470 AINPUT_SOURCE_TOUCHSCREEN,
11471 ui::LogicalDisplayId::DEFAULT, {touchedPoint}));
Siarhei Vishniakoua2862a02020-07-20 16:36:46 -050011472
11473 mNoInputWindow->assertNoEvents();
11474 // Even though the window 'mNoInputWindow' positioned above 'mBottomWindow' does not have
11475 // an input channel, it is not marked as FLAG_NOT_TOUCHABLE,
11476 // and therefore should prevent mBottomWindow from receiving touches
11477 mBottomWindow->assertNoEvents();
11478}
11479
11480/**
11481 * If a window has feature NO_INPUT_CHANNEL, and somehow (by mistake) still has an input channel,
11482 * ensure that this window does not receive any touches, and blocks touches to windows underneath.
11483 */
11484TEST_F(InputDispatcherMultiWindowOcclusionTests,
11485 NoInputChannelFeature_DropsTouchesWithValidChannel) {
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -070011486 mNoInputWindow = sp<FakeWindowHandle>::make(mApplication, mDispatcher,
11487 "Window with input channel and NO_INPUT_CHANNEL",
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -070011488 ui::LogicalDisplayId::DEFAULT);
Siarhei Vishniakoua2862a02020-07-20 16:36:46 -050011489
Prabir Pradhan51e7db02022-02-07 06:02:57 -080011490 mNoInputWindow->setNoInputChannel(true);
Siarhei Vishniakoua2862a02020-07-20 16:36:46 -050011491 mNoInputWindow->setFrame(Rect(0, 0, 100, 100));
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070011492 mDispatcher->onWindowInfosChanged(
11493 {{*mNoInputWindow->getInfo(), *mBottomWindow->getInfo()}, {}, 0, 0});
Siarhei Vishniakoua2862a02020-07-20 16:36:46 -050011494
11495 PointF touchedPoint = {10, 10};
11496
Prabir Pradhan678438e2023-04-13 19:32:51 +000011497 mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_DOWN,
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -070011498 AINPUT_SOURCE_TOUCHSCREEN,
11499 ui::LogicalDisplayId::DEFAULT, {touchedPoint}));
Siarhei Vishniakoua2862a02020-07-20 16:36:46 -050011500
11501 mNoInputWindow->assertNoEvents();
11502 mBottomWindow->assertNoEvents();
11503}
11504
Vishnu Nair958da932020-08-21 17:12:37 -070011505class InputDispatcherMirrorWindowFocusTests : public InputDispatcherTest {
11506protected:
11507 std::shared_ptr<FakeApplicationHandle> mApp;
11508 sp<FakeWindowHandle> mWindow;
11509 sp<FakeWindowHandle> mMirror;
11510
11511 virtual void SetUp() override {
11512 InputDispatcherTest::SetUp();
11513 mApp = std::make_shared<FakeApplicationHandle>();
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -070011514 mWindow = sp<FakeWindowHandle>::make(mApp, mDispatcher, "TestWindow",
11515 ui::LogicalDisplayId::DEFAULT);
11516 mMirror = mWindow->clone(ui::LogicalDisplayId::DEFAULT);
11517 mDispatcher->setFocusedApplication(ui::LogicalDisplayId::DEFAULT, mApp);
Vishnu Nair958da932020-08-21 17:12:37 -070011518 mWindow->setFocusable(true);
11519 mMirror->setFocusable(true);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070011520 mDispatcher->onWindowInfosChanged({{*mWindow->getInfo(), *mMirror->getInfo()}, {}, 0, 0});
Vishnu Nair958da932020-08-21 17:12:37 -070011521 }
11522};
11523
11524TEST_F(InputDispatcherMirrorWindowFocusTests, CanGetFocus) {
11525 // Request focus on a mirrored window
11526 setFocusedWindow(mMirror);
11527
11528 // window gets focused
11529 mWindow->consumeFocusEvent(true);
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070011530 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectKeyDown(*mDispatcher))
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -080011531 << "Inject key event should return InputEventInjectionResult::SUCCEEDED";
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -070011532 mWindow->consumeKeyDown(ui::LogicalDisplayId::INVALID);
Vishnu Nair958da932020-08-21 17:12:37 -070011533}
11534
11535// A focused & mirrored window remains focused only if the window and its mirror are both
11536// focusable.
11537TEST_F(InputDispatcherMirrorWindowFocusTests, FocusedIfAllWindowsFocusable) {
11538 setFocusedWindow(mMirror);
11539
Prabir Pradhanbb3f1c02024-01-04 20:17:14 +000011540 // window gets focused because it is above the mirror
Vishnu Nair958da932020-08-21 17:12:37 -070011541 mWindow->consumeFocusEvent(true);
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070011542 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectKeyDown(*mDispatcher))
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -080011543 << "Inject key event should return InputEventInjectionResult::SUCCEEDED";
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -070011544 mWindow->consumeKeyDown(ui::LogicalDisplayId::INVALID);
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070011545 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectKeyUp(*mDispatcher))
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -080011546 << "Inject key event should return InputEventInjectionResult::SUCCEEDED";
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -070011547 mWindow->consumeKeyUp(ui::LogicalDisplayId::INVALID);
Vishnu Nair958da932020-08-21 17:12:37 -070011548
11549 mMirror->setFocusable(false);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070011550 mDispatcher->onWindowInfosChanged({{*mWindow->getInfo(), *mMirror->getInfo()}, {}, 0, 0});
Vishnu Nair958da932020-08-21 17:12:37 -070011551
11552 // window loses focus since one of the windows associated with the token in not focusable
11553 mWindow->consumeFocusEvent(false);
11554
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070011555 ASSERT_EQ(InputEventInjectionResult::TIMED_OUT, injectKeyDown(*mDispatcher))
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -080011556 << "Inject key event should return InputEventInjectionResult::TIMED_OUT";
Vishnu Nair958da932020-08-21 17:12:37 -070011557 mWindow->assertNoEvents();
11558}
11559
11560// A focused & mirrored window remains focused until the window and its mirror both become
11561// invisible.
11562TEST_F(InputDispatcherMirrorWindowFocusTests, FocusedIfAnyWindowVisible) {
11563 setFocusedWindow(mMirror);
11564
11565 // window gets focused
11566 mWindow->consumeFocusEvent(true);
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070011567 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectKeyDown(*mDispatcher))
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -080011568 << "Inject key event should return InputEventInjectionResult::SUCCEEDED";
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -070011569 mWindow->consumeKeyDown(ui::LogicalDisplayId::INVALID);
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070011570 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectKeyUp(*mDispatcher))
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -080011571 << "Inject key event should return InputEventInjectionResult::SUCCEEDED";
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -070011572 mWindow->consumeKeyUp(ui::LogicalDisplayId::INVALID);
Vishnu Nair958da932020-08-21 17:12:37 -070011573
11574 mMirror->setVisible(false);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070011575 mDispatcher->onWindowInfosChanged({{*mWindow->getInfo(), *mMirror->getInfo()}, {}, 0, 0});
Vishnu Nair958da932020-08-21 17:12:37 -070011576
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070011577 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectKeyDown(*mDispatcher))
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -080011578 << "Inject key event should return InputEventInjectionResult::SUCCEEDED";
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -070011579 mWindow->consumeKeyDown(ui::LogicalDisplayId::INVALID);
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070011580 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectKeyUp(*mDispatcher))
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -080011581 << "Inject key event should return InputEventInjectionResult::SUCCEEDED";
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -070011582 mWindow->consumeKeyUp(ui::LogicalDisplayId::INVALID);
Vishnu Nair958da932020-08-21 17:12:37 -070011583
11584 mWindow->setVisible(false);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070011585 mDispatcher->onWindowInfosChanged({{*mWindow->getInfo(), *mMirror->getInfo()}, {}, 0, 0});
Vishnu Nair958da932020-08-21 17:12:37 -070011586
11587 // window loses focus only after all windows associated with the token become invisible.
11588 mWindow->consumeFocusEvent(false);
11589
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070011590 ASSERT_EQ(InputEventInjectionResult::TIMED_OUT, injectKeyDown(*mDispatcher))
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -080011591 << "Inject key event should return InputEventInjectionResult::TIMED_OUT";
Vishnu Nair958da932020-08-21 17:12:37 -070011592 mWindow->assertNoEvents();
11593}
11594
11595// A focused & mirrored window remains focused until both windows are removed.
11596TEST_F(InputDispatcherMirrorWindowFocusTests, FocusedWhileWindowsAlive) {
11597 setFocusedWindow(mMirror);
11598
11599 // window gets focused
11600 mWindow->consumeFocusEvent(true);
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070011601 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectKeyDown(*mDispatcher))
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -080011602 << "Inject key event should return InputEventInjectionResult::SUCCEEDED";
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -070011603 mWindow->consumeKeyDown(ui::LogicalDisplayId::INVALID);
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070011604 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectKeyUp(*mDispatcher))
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -080011605 << "Inject key event should return InputEventInjectionResult::SUCCEEDED";
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -070011606 mWindow->consumeKeyUp(ui::LogicalDisplayId::INVALID);
Vishnu Nair958da932020-08-21 17:12:37 -070011607
11608 // single window is removed but the window token remains focused
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070011609 mDispatcher->onWindowInfosChanged({{*mMirror->getInfo()}, {}, 0, 0});
Vishnu Nair958da932020-08-21 17:12:37 -070011610
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070011611 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectKeyDown(*mDispatcher))
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -080011612 << "Inject key event should return InputEventInjectionResult::SUCCEEDED";
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -070011613 mMirror->consumeKeyDown(ui::LogicalDisplayId::INVALID);
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070011614 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectKeyUp(*mDispatcher))
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -080011615 << "Inject key event should return InputEventInjectionResult::SUCCEEDED";
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -070011616 mMirror->consumeKeyUp(ui::LogicalDisplayId::INVALID);
Vishnu Nair958da932020-08-21 17:12:37 -070011617
11618 // Both windows are removed
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070011619 mDispatcher->onWindowInfosChanged({{}, {}, 0, 0});
Vishnu Nair958da932020-08-21 17:12:37 -070011620 mWindow->consumeFocusEvent(false);
11621
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070011622 ASSERT_EQ(InputEventInjectionResult::TIMED_OUT, injectKeyDown(*mDispatcher))
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -080011623 << "Inject key event should return InputEventInjectionResult::TIMED_OUT";
Vishnu Nair958da932020-08-21 17:12:37 -070011624 mWindow->assertNoEvents();
11625}
11626
11627// Focus request can be pending until one window becomes visible.
11628TEST_F(InputDispatcherMirrorWindowFocusTests, DeferFocusWhenInvisible) {
11629 // Request focus on an invisible mirror.
11630 mWindow->setVisible(false);
11631 mMirror->setVisible(false);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070011632 mDispatcher->onWindowInfosChanged({{*mWindow->getInfo(), *mMirror->getInfo()}, {}, 0, 0});
Vishnu Nair958da932020-08-21 17:12:37 -070011633 setFocusedWindow(mMirror);
11634
11635 // Injected key goes to pending queue.
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -080011636 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070011637 injectKey(*mDispatcher, AKEY_EVENT_ACTION_DOWN, /*repeatCount=*/0,
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -070011638 ui::LogicalDisplayId::DEFAULT, InputEventInjectionSync::NONE));
Vishnu Nair958da932020-08-21 17:12:37 -070011639
11640 mMirror->setVisible(true);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070011641 mDispatcher->onWindowInfosChanged({{*mWindow->getInfo(), *mMirror->getInfo()}, {}, 0, 0});
Vishnu Nair958da932020-08-21 17:12:37 -070011642
11643 // window gets focused
11644 mWindow->consumeFocusEvent(true);
11645 // window gets the pending key event
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -070011646 mWindow->consumeKeyDown(ui::LogicalDisplayId::DEFAULT);
Vishnu Nair958da932020-08-21 17:12:37 -070011647}
Prabir Pradhan99987712020-11-10 18:43:05 -080011648
11649class InputDispatcherPointerCaptureTests : public InputDispatcherTest {
11650protected:
11651 std::shared_ptr<FakeApplicationHandle> mApp;
11652 sp<FakeWindowHandle> mWindow;
11653 sp<FakeWindowHandle> mSecondWindow;
11654
11655 void SetUp() override {
11656 InputDispatcherTest::SetUp();
11657 mApp = std::make_shared<FakeApplicationHandle>();
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -070011658 mWindow = sp<FakeWindowHandle>::make(mApp, mDispatcher, "TestWindow",
11659 ui::LogicalDisplayId::DEFAULT);
Prabir Pradhan99987712020-11-10 18:43:05 -080011660 mWindow->setFocusable(true);
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -070011661 mSecondWindow = sp<FakeWindowHandle>::make(mApp, mDispatcher, "TestWindow2",
11662 ui::LogicalDisplayId::DEFAULT);
Prabir Pradhan99987712020-11-10 18:43:05 -080011663 mSecondWindow->setFocusable(true);
11664
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -070011665 mDispatcher->setFocusedApplication(ui::LogicalDisplayId::DEFAULT, mApp);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070011666 mDispatcher->onWindowInfosChanged(
11667 {{*mWindow->getInfo(), *mSecondWindow->getInfo()}, {}, 0, 0});
Prabir Pradhan99987712020-11-10 18:43:05 -080011668
11669 setFocusedWindow(mWindow);
11670 mWindow->consumeFocusEvent(true);
11671 }
11672
Prabir Pradhan5cc1a692021-08-06 14:01:18 +000011673 void notifyPointerCaptureChanged(const PointerCaptureRequest& request) {
Prabir Pradhan678438e2023-04-13 19:32:51 +000011674 mDispatcher->notifyPointerCaptureChanged(generatePointerCaptureChangedArgs(request));
Prabir Pradhan99987712020-11-10 18:43:05 -080011675 }
11676
Prabir Pradhan5cc1a692021-08-06 14:01:18 +000011677 PointerCaptureRequest requestAndVerifyPointerCapture(const sp<FakeWindowHandle>& window,
11678 bool enabled) {
Prabir Pradhan99987712020-11-10 18:43:05 -080011679 mDispatcher->requestPointerCapture(window->getToken(), enabled);
Hiroki Sato25040232024-02-22 17:21:22 +090011680 auto request = mFakePolicy->assertSetPointerCaptureCalled(window, enabled);
Prabir Pradhan5cc1a692021-08-06 14:01:18 +000011681 notifyPointerCaptureChanged(request);
Prabir Pradhan99987712020-11-10 18:43:05 -080011682 window->consumeCaptureEvent(enabled);
Prabir Pradhan5cc1a692021-08-06 14:01:18 +000011683 return request;
Prabir Pradhan99987712020-11-10 18:43:05 -080011684 }
11685};
11686
11687TEST_F(InputDispatcherPointerCaptureTests, EnablePointerCaptureWhenFocused) {
11688 // Ensure that capture cannot be obtained for unfocused windows.
11689 mDispatcher->requestPointerCapture(mSecondWindow->getToken(), true);
11690 mFakePolicy->assertSetPointerCaptureNotCalled();
11691 mSecondWindow->assertNoEvents();
11692
11693 // Ensure that capture can be enabled from the focus window.
11694 requestAndVerifyPointerCapture(mWindow, true);
11695
11696 // Ensure that capture cannot be disabled from a window that does not have capture.
11697 mDispatcher->requestPointerCapture(mSecondWindow->getToken(), false);
11698 mFakePolicy->assertSetPointerCaptureNotCalled();
11699
11700 // Ensure that capture can be disabled from the window with capture.
11701 requestAndVerifyPointerCapture(mWindow, false);
11702}
11703
11704TEST_F(InputDispatcherPointerCaptureTests, DisablesPointerCaptureAfterWindowLosesFocus) {
Prabir Pradhan5cc1a692021-08-06 14:01:18 +000011705 auto request = requestAndVerifyPointerCapture(mWindow, true);
Prabir Pradhan99987712020-11-10 18:43:05 -080011706
11707 setFocusedWindow(mSecondWindow);
11708
11709 // Ensure that the capture disabled event was sent first.
11710 mWindow->consumeCaptureEvent(false);
11711 mWindow->consumeFocusEvent(false);
11712 mSecondWindow->consumeFocusEvent(true);
Hiroki Sato25040232024-02-22 17:21:22 +090011713 mFakePolicy->assertSetPointerCaptureCalled(mWindow, false);
Prabir Pradhan99987712020-11-10 18:43:05 -080011714
11715 // Ensure that additional state changes from InputReader are not sent to the window.
Prabir Pradhan5cc1a692021-08-06 14:01:18 +000011716 notifyPointerCaptureChanged({});
11717 notifyPointerCaptureChanged(request);
11718 notifyPointerCaptureChanged({});
Prabir Pradhan99987712020-11-10 18:43:05 -080011719 mWindow->assertNoEvents();
11720 mSecondWindow->assertNoEvents();
11721 mFakePolicy->assertSetPointerCaptureNotCalled();
11722}
11723
11724TEST_F(InputDispatcherPointerCaptureTests, UnexpectedStateChangeDisablesPointerCapture) {
Prabir Pradhan5cc1a692021-08-06 14:01:18 +000011725 auto request = requestAndVerifyPointerCapture(mWindow, true);
Prabir Pradhan99987712020-11-10 18:43:05 -080011726
11727 // InputReader unexpectedly disables and enables pointer capture.
Prabir Pradhan5cc1a692021-08-06 14:01:18 +000011728 notifyPointerCaptureChanged({});
11729 notifyPointerCaptureChanged(request);
Prabir Pradhan99987712020-11-10 18:43:05 -080011730
11731 // Ensure that Pointer Capture is disabled.
Hiroki Sato25040232024-02-22 17:21:22 +090011732 mFakePolicy->assertSetPointerCaptureCalled(mWindow, false);
Prabir Pradhan99987712020-11-10 18:43:05 -080011733 mWindow->consumeCaptureEvent(false);
11734 mWindow->assertNoEvents();
11735}
11736
Prabir Pradhan167e6d92021-02-04 16:18:17 -080011737TEST_F(InputDispatcherPointerCaptureTests, OutOfOrderRequests) {
11738 requestAndVerifyPointerCapture(mWindow, true);
11739
11740 // The first window loses focus.
11741 setFocusedWindow(mSecondWindow);
Hiroki Sato25040232024-02-22 17:21:22 +090011742 mFakePolicy->assertSetPointerCaptureCalled(mWindow, false);
Prabir Pradhan167e6d92021-02-04 16:18:17 -080011743 mWindow->consumeCaptureEvent(false);
11744
11745 // Request Pointer Capture from the second window before the notification from InputReader
11746 // arrives.
11747 mDispatcher->requestPointerCapture(mSecondWindow->getToken(), true);
Hiroki Sato25040232024-02-22 17:21:22 +090011748 auto request = mFakePolicy->assertSetPointerCaptureCalled(mSecondWindow, true);
Prabir Pradhan167e6d92021-02-04 16:18:17 -080011749
11750 // InputReader notifies Pointer Capture was disabled (because of the focus change).
Prabir Pradhan5cc1a692021-08-06 14:01:18 +000011751 notifyPointerCaptureChanged({});
Prabir Pradhan167e6d92021-02-04 16:18:17 -080011752
11753 // InputReader notifies Pointer Capture was enabled (because of mSecondWindow's request).
Prabir Pradhan5cc1a692021-08-06 14:01:18 +000011754 notifyPointerCaptureChanged(request);
Prabir Pradhan167e6d92021-02-04 16:18:17 -080011755
11756 mSecondWindow->consumeFocusEvent(true);
11757 mSecondWindow->consumeCaptureEvent(true);
11758}
11759
Prabir Pradhan5cc1a692021-08-06 14:01:18 +000011760TEST_F(InputDispatcherPointerCaptureTests, EnableRequestFollowsSequenceNumbers) {
11761 // App repeatedly enables and disables capture.
11762 mDispatcher->requestPointerCapture(mWindow->getToken(), true);
Hiroki Sato25040232024-02-22 17:21:22 +090011763 auto firstRequest = mFakePolicy->assertSetPointerCaptureCalled(mWindow, true);
Prabir Pradhan5cc1a692021-08-06 14:01:18 +000011764 mDispatcher->requestPointerCapture(mWindow->getToken(), false);
Hiroki Sato25040232024-02-22 17:21:22 +090011765 mFakePolicy->assertSetPointerCaptureCalled(mWindow, false);
Prabir Pradhan5cc1a692021-08-06 14:01:18 +000011766 mDispatcher->requestPointerCapture(mWindow->getToken(), true);
Hiroki Sato25040232024-02-22 17:21:22 +090011767 auto secondRequest = mFakePolicy->assertSetPointerCaptureCalled(mWindow, true);
Prabir Pradhan5cc1a692021-08-06 14:01:18 +000011768
11769 // InputReader notifies that PointerCapture has been enabled for the first request. Since the
11770 // first request is now stale, this should do nothing.
11771 notifyPointerCaptureChanged(firstRequest);
11772 mWindow->assertNoEvents();
11773
11774 // InputReader notifies that the second request was enabled.
11775 notifyPointerCaptureChanged(secondRequest);
11776 mWindow->consumeCaptureEvent(true);
11777}
11778
Prabir Pradhan7092e262022-05-03 16:51:09 +000011779TEST_F(InputDispatcherPointerCaptureTests, RapidToggleRequests) {
11780 requestAndVerifyPointerCapture(mWindow, true);
11781
11782 // App toggles pointer capture off and on.
11783 mDispatcher->requestPointerCapture(mWindow->getToken(), false);
Hiroki Sato25040232024-02-22 17:21:22 +090011784 mFakePolicy->assertSetPointerCaptureCalled(mWindow, false);
Prabir Pradhan7092e262022-05-03 16:51:09 +000011785
11786 mDispatcher->requestPointerCapture(mWindow->getToken(), true);
Hiroki Sato25040232024-02-22 17:21:22 +090011787 auto enableRequest = mFakePolicy->assertSetPointerCaptureCalled(mWindow, true);
Prabir Pradhan7092e262022-05-03 16:51:09 +000011788
11789 // InputReader notifies that the latest "enable" request was processed, while skipping over the
11790 // preceding "disable" request.
11791 notifyPointerCaptureChanged(enableRequest);
11792
11793 // Since pointer capture was never disabled during the rapid toggle, the window does not receive
11794 // any notifications.
11795 mWindow->assertNoEvents();
11796}
11797
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -070011798/**
11799 * One window. Hover mouse in the window, and then start capture. Make sure that the relative
11800 * mouse movements don't affect the previous mouse hovering state.
11801 * When pointer capture is enabled, the incoming events are always ACTION_MOVE (there are no
11802 * HOVER_MOVE events).
11803 */
11804TEST_F(InputDispatcherPointerCaptureTests, MouseHoverAndPointerCapture) {
11805 // Mouse hover on the window
11806 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_ENTER, AINPUT_SOURCE_MOUSE)
11807 .pointer(PointerBuilder(0, ToolType::MOUSE).x(100).y(110))
11808 .build());
11809 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_MOVE, AINPUT_SOURCE_MOUSE)
11810 .pointer(PointerBuilder(0, ToolType::MOUSE).x(100).y(110))
11811 .build());
11812
11813 mWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_HOVER_ENTER)));
11814 mWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_HOVER_MOVE)));
11815
11816 // Start pointer capture
11817 requestAndVerifyPointerCapture(mWindow, true);
11818
11819 // Send some relative mouse movements and receive them in the window.
11820 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_MOUSE_RELATIVE)
11821 .pointer(PointerBuilder(0, ToolType::MOUSE).x(10).y(11))
11822 .build());
11823 mWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_MOVE), WithCoords(10, 11),
11824 WithSource(AINPUT_SOURCE_MOUSE_RELATIVE)));
11825
11826 // Stop pointer capture
11827 requestAndVerifyPointerCapture(mWindow, false);
11828
11829 // Continue hovering on the window
11830 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_MOVE, AINPUT_SOURCE_MOUSE)
11831 .pointer(PointerBuilder(0, ToolType::MOUSE).x(105).y(115))
11832 .build());
11833 mWindow->consumeMotionEvent(
11834 AllOf(WithMotionAction(ACTION_HOVER_MOVE), WithSource(AINPUT_SOURCE_MOUSE)));
11835
11836 mWindow->assertNoEvents();
11837}
11838
Prabir Pradhan9d3d5612024-06-06 20:34:26 +000011839TEST_F(InputDispatcherPointerCaptureTests, MultiDisplayPointerCapture) {
11840 // The default display is the focused display to begin with.
11841 requestAndVerifyPointerCapture(mWindow, true);
11842
11843 // Move the second window to a second display, make it the focused window on that display.
11844 mSecondWindow->editInfo()->displayId = SECOND_DISPLAY_ID;
11845 mDispatcher->onWindowInfosChanged({{*mWindow->getInfo(), *mSecondWindow->getInfo()}, {}, 0, 0});
11846 setFocusedWindow(mSecondWindow);
11847 mSecondWindow->consumeFocusEvent(true);
11848
11849 mWindow->assertNoEvents();
11850
11851 // The second window cannot gain capture because it is not on the focused display.
11852 mDispatcher->requestPointerCapture(mSecondWindow->getToken(), true);
11853 mFakePolicy->assertSetPointerCaptureNotCalled();
11854 mSecondWindow->assertNoEvents();
11855
11856 // Make the second display the focused display.
11857 mDispatcher->setFocusedDisplay(SECOND_DISPLAY_ID);
Arpit Singhb65e2bd2024-06-03 09:48:16 +000011858 mFakePolicy->assertFocusedDisplayNotified(SECOND_DISPLAY_ID);
Prabir Pradhan9d3d5612024-06-06 20:34:26 +000011859
11860 // This causes the first window to lose pointer capture, and it's unable to request capture.
11861 mWindow->consumeCaptureEvent(false);
11862 mFakePolicy->assertSetPointerCaptureCalled(mWindow, false);
11863
11864 mDispatcher->requestPointerCapture(mWindow->getToken(), true);
11865 mFakePolicy->assertSetPointerCaptureNotCalled();
11866
11867 // The second window is now able to gain pointer capture successfully.
11868 requestAndVerifyPointerCapture(mSecondWindow, true);
11869}
11870
Hiroki Sato25040232024-02-22 17:21:22 +090011871using InputDispatcherPointerCaptureDeathTest = InputDispatcherPointerCaptureTests;
11872
11873TEST_F(InputDispatcherPointerCaptureDeathTest,
11874 NotifyPointerCaptureChangedWithWrongTokenAbortsDispatcher) {
11875 testing::GTEST_FLAG(death_test_style) = "threadsafe";
11876 ScopedSilentDeath _silentDeath;
11877
11878 mDispatcher->requestPointerCapture(mWindow->getToken(), true);
11879 auto request = mFakePolicy->assertSetPointerCaptureCalled(mWindow, true);
11880
11881 // Dispatch a pointer changed event with a wrong token.
11882 request.window = mSecondWindow->getToken();
11883 ASSERT_DEATH(
11884 {
11885 notifyPointerCaptureChanged(request);
11886 mSecondWindow->consumeCaptureEvent(true);
11887 },
11888 "Unexpected requested window for Pointer Capture.");
11889}
11890
Bernardo Rufinoc3b7b8c2021-01-29 17:38:07 +000011891class InputDispatcherUntrustedTouchesTest : public InputDispatcherTest {
11892protected:
11893 constexpr static const float MAXIMUM_OBSCURING_OPACITY = 0.8;
Bernardo Rufino7393d172021-02-26 13:56:11 +000011894
11895 constexpr static const float OPACITY_ABOVE_THRESHOLD = 0.9;
11896 static_assert(OPACITY_ABOVE_THRESHOLD > MAXIMUM_OBSCURING_OPACITY);
11897
11898 constexpr static const float OPACITY_BELOW_THRESHOLD = 0.7;
11899 static_assert(OPACITY_BELOW_THRESHOLD < MAXIMUM_OBSCURING_OPACITY);
11900
11901 // When combined twice, ie 1 - (1 - 0.5)*(1 - 0.5) = 0.75 < 8, is still below the threshold
11902 constexpr static const float OPACITY_FAR_BELOW_THRESHOLD = 0.5;
11903 static_assert(OPACITY_FAR_BELOW_THRESHOLD < MAXIMUM_OBSCURING_OPACITY);
11904 static_assert(1 - (1 - OPACITY_FAR_BELOW_THRESHOLD) * (1 - OPACITY_FAR_BELOW_THRESHOLD) <
11905 MAXIMUM_OBSCURING_OPACITY);
11906
Prabir Pradhan8a5c41d2023-06-08 19:13:46 +000011907 static constexpr gui::Uid TOUCHED_APP_UID{10001};
11908 static constexpr gui::Uid APP_B_UID{10002};
11909 static constexpr gui::Uid APP_C_UID{10003};
Bernardo Rufinoc3b7b8c2021-01-29 17:38:07 +000011910
11911 sp<FakeWindowHandle> mTouchWindow;
11912
11913 virtual void SetUp() override {
11914 InputDispatcherTest::SetUp();
Bernardo Rufino6d52e542021-02-15 18:38:10 +000011915 mTouchWindow = getWindow(TOUCHED_APP_UID, "Touched");
Bernardo Rufinoc3b7b8c2021-01-29 17:38:07 +000011916 mDispatcher->setMaximumObscuringOpacityForTouch(MAXIMUM_OBSCURING_OPACITY);
11917 }
11918
11919 virtual void TearDown() override {
11920 InputDispatcherTest::TearDown();
11921 mTouchWindow.clear();
11922 }
11923
Prabir Pradhan8a5c41d2023-06-08 19:13:46 +000011924 sp<FakeWindowHandle> getOccludingWindow(gui::Uid uid, std::string name, TouchOcclusionMode mode,
chaviw3277faf2021-05-19 16:45:23 -050011925 float alpha = 1.0f) {
Bernardo Rufinoc3b7b8c2021-01-29 17:38:07 +000011926 sp<FakeWindowHandle> window = getWindow(uid, name);
Prabir Pradhan4d5c52f2022-01-31 08:52:10 -080011927 window->setTouchable(false);
Bernardo Rufinoc3b7b8c2021-01-29 17:38:07 +000011928 window->setTouchOcclusionMode(mode);
Bernardo Rufino1d0d1f22021-02-12 15:08:43 +000011929 window->setAlpha(alpha);
Bernardo Rufinoc3b7b8c2021-01-29 17:38:07 +000011930 return window;
11931 }
11932
Prabir Pradhan8a5c41d2023-06-08 19:13:46 +000011933 sp<FakeWindowHandle> getWindow(gui::Uid uid, std::string name) {
Bernardo Rufinoc3b7b8c2021-01-29 17:38:07 +000011934 std::shared_ptr<FakeApplicationHandle> app = std::make_shared<FakeApplicationHandle>();
11935 sp<FakeWindowHandle> window =
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -070011936 sp<FakeWindowHandle>::make(app, mDispatcher, name, ui::LogicalDisplayId::DEFAULT);
Bernardo Rufinoc3b7b8c2021-01-29 17:38:07 +000011937 // Generate an arbitrary PID based on the UID
Prabir Pradhanaeebeb42023-06-13 19:53:03 +000011938 window->setOwnerInfo(gui::Pid{static_cast<pid_t>(1777 + (uid.val() % 10000))}, uid);
Bernardo Rufinoc3b7b8c2021-01-29 17:38:07 +000011939 return window;
11940 }
11941
11942 void touch(const std::vector<PointF>& points = {PointF{100, 200}}) {
Prabir Pradhan678438e2023-04-13 19:32:51 +000011943 mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_DOWN,
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -070011944 AINPUT_SOURCE_TOUCHSCREEN,
11945 ui::LogicalDisplayId::DEFAULT, points));
Bernardo Rufinoc3b7b8c2021-01-29 17:38:07 +000011946 }
11947};
11948
11949TEST_F(InputDispatcherUntrustedTouchesTest, WindowWithBlockUntrustedOcclusionMode_BlocksTouch) {
Bernardo Rufino1d0d1f22021-02-12 15:08:43 +000011950 const sp<FakeWindowHandle>& w =
Bernardo Rufinoc3b7b8c2021-01-29 17:38:07 +000011951 getOccludingWindow(APP_B_UID, "B", TouchOcclusionMode::BLOCK_UNTRUSTED);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070011952 mDispatcher->onWindowInfosChanged({{*w->getInfo(), *mTouchWindow->getInfo()}, {}, 0, 0});
Bernardo Rufinoc3b7b8c2021-01-29 17:38:07 +000011953
11954 touch();
11955
11956 mTouchWindow->assertNoEvents();
11957}
11958
Bernardo Rufinoa43a5a42021-02-17 12:21:14 +000011959TEST_F(InputDispatcherUntrustedTouchesTest,
Bernardo Rufino7393d172021-02-26 13:56:11 +000011960 WindowWithBlockUntrustedOcclusionModeWithOpacityBelowThreshold_BlocksTouch) {
11961 const sp<FakeWindowHandle>& w =
11962 getOccludingWindow(APP_B_UID, "B", TouchOcclusionMode::BLOCK_UNTRUSTED, 0.7f);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070011963 mDispatcher->onWindowInfosChanged({{*w->getInfo(), *mTouchWindow->getInfo()}, {}, 0, 0});
Bernardo Rufino7393d172021-02-26 13:56:11 +000011964
11965 touch();
11966
11967 mTouchWindow->assertNoEvents();
11968}
11969
11970TEST_F(InputDispatcherUntrustedTouchesTest,
Bernardo Rufinoa43a5a42021-02-17 12:21:14 +000011971 WindowWithBlockUntrustedOcclusionMode_DoesNotReceiveTouch) {
11972 const sp<FakeWindowHandle>& w =
11973 getOccludingWindow(APP_B_UID, "B", TouchOcclusionMode::BLOCK_UNTRUSTED);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070011974 mDispatcher->onWindowInfosChanged({{*w->getInfo(), *mTouchWindow->getInfo()}, {}, 0, 0});
Bernardo Rufinoa43a5a42021-02-17 12:21:14 +000011975
11976 touch();
11977
11978 w->assertNoEvents();
11979}
11980
Bernardo Rufinoc3b7b8c2021-01-29 17:38:07 +000011981TEST_F(InputDispatcherUntrustedTouchesTest, WindowWithAllowOcclusionMode_AllowsTouch) {
Bernardo Rufino1d0d1f22021-02-12 15:08:43 +000011982 const sp<FakeWindowHandle>& w = getOccludingWindow(APP_B_UID, "B", TouchOcclusionMode::ALLOW);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070011983 mDispatcher->onWindowInfosChanged({{*w->getInfo(), *mTouchWindow->getInfo()}, {}, 0, 0});
Bernardo Rufinoc3b7b8c2021-01-29 17:38:07 +000011984
11985 touch();
11986
11987 mTouchWindow->consumeAnyMotionDown();
11988}
11989
11990TEST_F(InputDispatcherUntrustedTouchesTest, TouchOutsideOccludingWindow_AllowsTouch) {
Bernardo Rufino1d0d1f22021-02-12 15:08:43 +000011991 const sp<FakeWindowHandle>& w =
Bernardo Rufinoc3b7b8c2021-01-29 17:38:07 +000011992 getOccludingWindow(APP_B_UID, "B", TouchOcclusionMode::BLOCK_UNTRUSTED);
Bernardo Rufino1d0d1f22021-02-12 15:08:43 +000011993 w->setFrame(Rect(0, 0, 50, 50));
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070011994 mDispatcher->onWindowInfosChanged({{*w->getInfo(), *mTouchWindow->getInfo()}, {}, 0, 0});
Bernardo Rufinoc3b7b8c2021-01-29 17:38:07 +000011995
11996 touch({PointF{100, 100}});
11997
11998 mTouchWindow->consumeAnyMotionDown();
11999}
12000
12001TEST_F(InputDispatcherUntrustedTouchesTest, WindowFromSameUid_AllowsTouch) {
Bernardo Rufino1d0d1f22021-02-12 15:08:43 +000012002 const sp<FakeWindowHandle>& w =
Bernardo Rufino6d52e542021-02-15 18:38:10 +000012003 getOccludingWindow(TOUCHED_APP_UID, "A", TouchOcclusionMode::BLOCK_UNTRUSTED);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070012004 mDispatcher->onWindowInfosChanged({{*w->getInfo(), *mTouchWindow->getInfo()}, {}, 0, 0});
Bernardo Rufino1d0d1f22021-02-12 15:08:43 +000012005
12006 touch();
12007
12008 mTouchWindow->consumeAnyMotionDown();
12009}
12010
12011TEST_F(InputDispatcherUntrustedTouchesTest, WindowWithZeroOpacity_AllowsTouch) {
12012 const sp<FakeWindowHandle>& w =
12013 getOccludingWindow(APP_B_UID, "B", TouchOcclusionMode::BLOCK_UNTRUSTED, 0.0f);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070012014 mDispatcher->onWindowInfosChanged({{*w->getInfo(), *mTouchWindow->getInfo()}, {}, 0, 0});
Bernardo Rufinoc3b7b8c2021-01-29 17:38:07 +000012015
12016 touch();
12017
12018 mTouchWindow->consumeAnyMotionDown();
12019}
12020
Bernardo Rufinoa43a5a42021-02-17 12:21:14 +000012021TEST_F(InputDispatcherUntrustedTouchesTest, WindowWithZeroOpacity_DoesNotReceiveTouch) {
12022 const sp<FakeWindowHandle>& w =
12023 getOccludingWindow(APP_B_UID, "B", TouchOcclusionMode::BLOCK_UNTRUSTED, 0.0f);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070012024 mDispatcher->onWindowInfosChanged({{*w->getInfo(), *mTouchWindow->getInfo()}, {}, 0, 0});
Bernardo Rufinoa43a5a42021-02-17 12:21:14 +000012025
12026 touch();
12027
12028 w->assertNoEvents();
12029}
12030
12031/**
12032 * This is important to make sure apps can't indirectly learn the position of touches (outside vs
12033 * inside) while letting them pass-through. Note that even though touch passes through the occluding
12034 * window, the occluding window will still receive ACTION_OUTSIDE event.
12035 */
12036TEST_F(InputDispatcherUntrustedTouchesTest,
12037 WindowWithZeroOpacityAndWatchOutside_ReceivesOutsideEvent) {
12038 const sp<FakeWindowHandle>& w =
12039 getOccludingWindow(APP_B_UID, "B", TouchOcclusionMode::BLOCK_UNTRUSTED, 0.0f);
Prabir Pradhan4d5c52f2022-01-31 08:52:10 -080012040 w->setWatchOutsideTouch(true);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070012041 mDispatcher->onWindowInfosChanged({{*w->getInfo(), *mTouchWindow->getInfo()}, {}, 0, 0});
Bernardo Rufinoa43a5a42021-02-17 12:21:14 +000012042
12043 touch();
12044
12045 w->consumeMotionOutside();
12046}
12047
12048TEST_F(InputDispatcherUntrustedTouchesTest, OutsideEvent_HasZeroCoordinates) {
12049 const sp<FakeWindowHandle>& w =
12050 getOccludingWindow(APP_B_UID, "B", TouchOcclusionMode::BLOCK_UNTRUSTED, 0.0f);
Prabir Pradhan4d5c52f2022-01-31 08:52:10 -080012051 w->setWatchOutsideTouch(true);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070012052 mDispatcher->onWindowInfosChanged({{*w->getInfo(), *mTouchWindow->getInfo()}, {}, 0, 0});
Bernardo Rufinoa43a5a42021-02-17 12:21:14 +000012053
12054 touch();
12055
Prabir Pradhandfabf8a2022-01-21 08:19:30 -080012056 w->consumeMotionOutsideWithZeroedCoords();
Bernardo Rufinoa43a5a42021-02-17 12:21:14 +000012057}
12058
Bernardo Rufinoc3b7b8c2021-01-29 17:38:07 +000012059TEST_F(InputDispatcherUntrustedTouchesTest, WindowWithOpacityBelowThreshold_AllowsTouch) {
Bernardo Rufino1d0d1f22021-02-12 15:08:43 +000012060 const sp<FakeWindowHandle>& w =
Bernardo Rufino7393d172021-02-26 13:56:11 +000012061 getOccludingWindow(APP_B_UID, "B", TouchOcclusionMode::USE_OPACITY,
12062 OPACITY_BELOW_THRESHOLD);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070012063 mDispatcher->onWindowInfosChanged({{*w->getInfo(), *mTouchWindow->getInfo()}, {}, 0, 0});
Bernardo Rufino1d0d1f22021-02-12 15:08:43 +000012064
12065 touch();
12066
12067 mTouchWindow->consumeAnyMotionDown();
12068}
12069
12070TEST_F(InputDispatcherUntrustedTouchesTest, WindowWithOpacityAtThreshold_AllowsTouch) {
12071 const sp<FakeWindowHandle>& w =
12072 getOccludingWindow(APP_B_UID, "B", TouchOcclusionMode::USE_OPACITY,
12073 MAXIMUM_OBSCURING_OPACITY);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070012074 mDispatcher->onWindowInfosChanged({{*w->getInfo(), *mTouchWindow->getInfo()}, {}, 0, 0});
Bernardo Rufinoc3b7b8c2021-01-29 17:38:07 +000012075
12076 touch();
12077
12078 mTouchWindow->consumeAnyMotionDown();
12079}
12080
12081TEST_F(InputDispatcherUntrustedTouchesTest, WindowWithOpacityAboveThreshold_BlocksTouch) {
Bernardo Rufino1d0d1f22021-02-12 15:08:43 +000012082 const sp<FakeWindowHandle>& w =
Bernardo Rufino7393d172021-02-26 13:56:11 +000012083 getOccludingWindow(APP_B_UID, "B", TouchOcclusionMode::USE_OPACITY,
12084 OPACITY_ABOVE_THRESHOLD);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070012085 mDispatcher->onWindowInfosChanged({{*w->getInfo(), *mTouchWindow->getInfo()}, {}, 0, 0});
Bernardo Rufino1d0d1f22021-02-12 15:08:43 +000012086
12087 touch();
12088
12089 mTouchWindow->assertNoEvents();
12090}
12091
12092TEST_F(InputDispatcherUntrustedTouchesTest, WindowsWithCombinedOpacityAboveThreshold_BlocksTouch) {
12093 // Resulting opacity = 1 - (1 - 0.7)*(1 - 0.7) = .91
12094 const sp<FakeWindowHandle>& w1 =
Bernardo Rufino7393d172021-02-26 13:56:11 +000012095 getOccludingWindow(APP_B_UID, "B1", TouchOcclusionMode::USE_OPACITY,
12096 OPACITY_BELOW_THRESHOLD);
Bernardo Rufino1d0d1f22021-02-12 15:08:43 +000012097 const sp<FakeWindowHandle>& w2 =
Bernardo Rufino7393d172021-02-26 13:56:11 +000012098 getOccludingWindow(APP_B_UID, "B2", TouchOcclusionMode::USE_OPACITY,
12099 OPACITY_BELOW_THRESHOLD);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070012100 mDispatcher->onWindowInfosChanged(
12101 {{*w1->getInfo(), *w2->getInfo(), *mTouchWindow->getInfo()}, {}, 0, 0});
Bernardo Rufino1d0d1f22021-02-12 15:08:43 +000012102
12103 touch();
12104
12105 mTouchWindow->assertNoEvents();
12106}
12107
12108TEST_F(InputDispatcherUntrustedTouchesTest, WindowsWithCombinedOpacityBelowThreshold_AllowsTouch) {
12109 // Resulting opacity = 1 - (1 - 0.5)*(1 - 0.5) = .75
12110 const sp<FakeWindowHandle>& w1 =
Bernardo Rufino7393d172021-02-26 13:56:11 +000012111 getOccludingWindow(APP_B_UID, "B1", TouchOcclusionMode::USE_OPACITY,
12112 OPACITY_FAR_BELOW_THRESHOLD);
Bernardo Rufino1d0d1f22021-02-12 15:08:43 +000012113 const sp<FakeWindowHandle>& w2 =
Bernardo Rufino7393d172021-02-26 13:56:11 +000012114 getOccludingWindow(APP_B_UID, "B2", TouchOcclusionMode::USE_OPACITY,
12115 OPACITY_FAR_BELOW_THRESHOLD);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070012116 mDispatcher->onWindowInfosChanged(
12117 {{*w1->getInfo(), *w2->getInfo(), *mTouchWindow->getInfo()}, {}, 0, 0});
Bernardo Rufino1d0d1f22021-02-12 15:08:43 +000012118
12119 touch();
12120
12121 mTouchWindow->consumeAnyMotionDown();
12122}
12123
12124TEST_F(InputDispatcherUntrustedTouchesTest,
12125 WindowsFromDifferentAppsEachBelowThreshold_AllowsTouch) {
12126 const sp<FakeWindowHandle>& wB =
Bernardo Rufino7393d172021-02-26 13:56:11 +000012127 getOccludingWindow(APP_B_UID, "B", TouchOcclusionMode::USE_OPACITY,
12128 OPACITY_BELOW_THRESHOLD);
Bernardo Rufino1d0d1f22021-02-12 15:08:43 +000012129 const sp<FakeWindowHandle>& wC =
Bernardo Rufino7393d172021-02-26 13:56:11 +000012130 getOccludingWindow(APP_C_UID, "C", TouchOcclusionMode::USE_OPACITY,
12131 OPACITY_BELOW_THRESHOLD);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070012132 mDispatcher->onWindowInfosChanged(
12133 {{*wB->getInfo(), *wC->getInfo(), *mTouchWindow->getInfo()}, {}, 0, 0});
Bernardo Rufino1d0d1f22021-02-12 15:08:43 +000012134
12135 touch();
12136
12137 mTouchWindow->consumeAnyMotionDown();
12138}
12139
12140TEST_F(InputDispatcherUntrustedTouchesTest, WindowsFromDifferentAppsOneAboveThreshold_BlocksTouch) {
12141 const sp<FakeWindowHandle>& wB =
Bernardo Rufino7393d172021-02-26 13:56:11 +000012142 getOccludingWindow(APP_B_UID, "B", TouchOcclusionMode::USE_OPACITY,
12143 OPACITY_BELOW_THRESHOLD);
Bernardo Rufino1d0d1f22021-02-12 15:08:43 +000012144 const sp<FakeWindowHandle>& wC =
Bernardo Rufino7393d172021-02-26 13:56:11 +000012145 getOccludingWindow(APP_C_UID, "C", TouchOcclusionMode::USE_OPACITY,
12146 OPACITY_ABOVE_THRESHOLD);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070012147 mDispatcher->onWindowInfosChanged(
12148 {{*wB->getInfo(), *wC->getInfo(), *mTouchWindow->getInfo()}, {}, 0, 0});
Bernardo Rufinoc3b7b8c2021-01-29 17:38:07 +000012149
12150 touch();
12151
12152 mTouchWindow->assertNoEvents();
12153}
12154
Bernardo Rufino6d52e542021-02-15 18:38:10 +000012155TEST_F(InputDispatcherUntrustedTouchesTest,
12156 WindowWithOpacityAboveThresholdAndSelfWindow_BlocksTouch) {
12157 const sp<FakeWindowHandle>& wA =
Bernardo Rufino7393d172021-02-26 13:56:11 +000012158 getOccludingWindow(TOUCHED_APP_UID, "T", TouchOcclusionMode::USE_OPACITY,
12159 OPACITY_BELOW_THRESHOLD);
Bernardo Rufino6d52e542021-02-15 18:38:10 +000012160 const sp<FakeWindowHandle>& wB =
Bernardo Rufino7393d172021-02-26 13:56:11 +000012161 getOccludingWindow(APP_B_UID, "B", TouchOcclusionMode::USE_OPACITY,
12162 OPACITY_ABOVE_THRESHOLD);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070012163 mDispatcher->onWindowInfosChanged(
12164 {{*wA->getInfo(), *wB->getInfo(), *mTouchWindow->getInfo()}, {}, 0, 0});
Bernardo Rufino6d52e542021-02-15 18:38:10 +000012165
12166 touch();
12167
12168 mTouchWindow->assertNoEvents();
12169}
12170
12171TEST_F(InputDispatcherUntrustedTouchesTest,
12172 WindowWithOpacityBelowThresholdAndSelfWindow_AllowsTouch) {
12173 const sp<FakeWindowHandle>& wA =
Bernardo Rufino7393d172021-02-26 13:56:11 +000012174 getOccludingWindow(TOUCHED_APP_UID, "T", TouchOcclusionMode::USE_OPACITY,
12175 OPACITY_ABOVE_THRESHOLD);
Bernardo Rufino6d52e542021-02-15 18:38:10 +000012176 const sp<FakeWindowHandle>& wB =
Bernardo Rufino7393d172021-02-26 13:56:11 +000012177 getOccludingWindow(APP_B_UID, "B", TouchOcclusionMode::USE_OPACITY,
12178 OPACITY_BELOW_THRESHOLD);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070012179 mDispatcher->onWindowInfosChanged(
12180 {{*wA->getInfo(), *wB->getInfo(), *mTouchWindow->getInfo()}, {}, 0, 0});
Bernardo Rufino6d52e542021-02-15 18:38:10 +000012181
12182 touch();
12183
12184 mTouchWindow->consumeAnyMotionDown();
12185}
12186
12187TEST_F(InputDispatcherUntrustedTouchesTest, SelfWindowWithOpacityAboveThreshold_AllowsTouch) {
12188 const sp<FakeWindowHandle>& w =
Bernardo Rufino7393d172021-02-26 13:56:11 +000012189 getOccludingWindow(TOUCHED_APP_UID, "T", TouchOcclusionMode::USE_OPACITY,
12190 OPACITY_ABOVE_THRESHOLD);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070012191 mDispatcher->onWindowInfosChanged({{*w->getInfo(), *mTouchWindow->getInfo()}, {}, 0, 0});
Bernardo Rufino6d52e542021-02-15 18:38:10 +000012192
12193 touch();
12194
12195 mTouchWindow->consumeAnyMotionDown();
12196}
12197
12198TEST_F(InputDispatcherUntrustedTouchesTest, SelfWindowWithBlockUntrustedMode_AllowsTouch) {
12199 const sp<FakeWindowHandle>& w =
12200 getOccludingWindow(TOUCHED_APP_UID, "T", TouchOcclusionMode::BLOCK_UNTRUSTED);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070012201 mDispatcher->onWindowInfosChanged({{*w->getInfo(), *mTouchWindow->getInfo()}, {}, 0, 0});
Bernardo Rufino6d52e542021-02-15 18:38:10 +000012202
12203 touch();
12204
12205 mTouchWindow->consumeAnyMotionDown();
12206}
12207
Bernardo Rufinoccd3dd62021-02-15 18:47:42 +000012208TEST_F(InputDispatcherUntrustedTouchesTest,
12209 OpacityThresholdIs0AndWindowAboveThreshold_BlocksTouch) {
12210 mDispatcher->setMaximumObscuringOpacityForTouch(0.0f);
12211 const sp<FakeWindowHandle>& w =
12212 getOccludingWindow(APP_B_UID, "B", TouchOcclusionMode::USE_OPACITY, 0.1f);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070012213 mDispatcher->onWindowInfosChanged({{*w->getInfo(), *mTouchWindow->getInfo()}, {}, 0, 0});
Bernardo Rufinoccd3dd62021-02-15 18:47:42 +000012214
12215 touch();
12216
12217 mTouchWindow->assertNoEvents();
12218}
12219
12220TEST_F(InputDispatcherUntrustedTouchesTest, OpacityThresholdIs0AndWindowAtThreshold_AllowsTouch) {
12221 mDispatcher->setMaximumObscuringOpacityForTouch(0.0f);
12222 const sp<FakeWindowHandle>& w =
12223 getOccludingWindow(APP_B_UID, "B", TouchOcclusionMode::USE_OPACITY, 0.0f);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070012224 mDispatcher->onWindowInfosChanged({{*w->getInfo(), *mTouchWindow->getInfo()}, {}, 0, 0});
Bernardo Rufinoccd3dd62021-02-15 18:47:42 +000012225
12226 touch();
12227
12228 mTouchWindow->consumeAnyMotionDown();
12229}
12230
12231TEST_F(InputDispatcherUntrustedTouchesTest,
12232 OpacityThresholdIs1AndWindowBelowThreshold_AllowsTouch) {
12233 mDispatcher->setMaximumObscuringOpacityForTouch(1.0f);
12234 const sp<FakeWindowHandle>& w =
Bernardo Rufino7393d172021-02-26 13:56:11 +000012235 getOccludingWindow(APP_B_UID, "B", TouchOcclusionMode::USE_OPACITY,
12236 OPACITY_ABOVE_THRESHOLD);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070012237 mDispatcher->onWindowInfosChanged({{*w->getInfo(), *mTouchWindow->getInfo()}, {}, 0, 0});
Bernardo Rufino7393d172021-02-26 13:56:11 +000012238
12239 touch();
12240
12241 mTouchWindow->consumeAnyMotionDown();
12242}
12243
12244TEST_F(InputDispatcherUntrustedTouchesTest,
12245 WindowWithBlockUntrustedModeAndWindowWithOpacityBelowFromSameApp_BlocksTouch) {
12246 const sp<FakeWindowHandle>& w1 =
12247 getOccludingWindow(APP_B_UID, "B", TouchOcclusionMode::BLOCK_UNTRUSTED,
12248 OPACITY_BELOW_THRESHOLD);
12249 const sp<FakeWindowHandle>& w2 =
12250 getOccludingWindow(APP_B_UID, "B", TouchOcclusionMode::USE_OPACITY,
12251 OPACITY_BELOW_THRESHOLD);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070012252 mDispatcher->onWindowInfosChanged(
12253 {{*w1->getInfo(), *w2->getInfo(), *mTouchWindow->getInfo()}, {}, 0, 0});
Bernardo Rufino7393d172021-02-26 13:56:11 +000012254
12255 touch();
12256
12257 mTouchWindow->assertNoEvents();
12258}
12259
12260/**
12261 * Window B of BLOCK_UNTRUSTED occlusion mode is enough to block the touch, we're testing that the
12262 * addition of another window (C) of USE_OPACITY occlusion mode and opacity below the threshold
12263 * (which alone would result in allowing touches) does not affect the blocking behavior.
12264 */
12265TEST_F(InputDispatcherUntrustedTouchesTest,
12266 WindowWithBlockUntrustedModeAndWindowWithOpacityBelowFromDifferentApps_BlocksTouch) {
12267 const sp<FakeWindowHandle>& wB =
12268 getOccludingWindow(APP_B_UID, "B", TouchOcclusionMode::BLOCK_UNTRUSTED,
12269 OPACITY_BELOW_THRESHOLD);
12270 const sp<FakeWindowHandle>& wC =
12271 getOccludingWindow(APP_C_UID, "C", TouchOcclusionMode::USE_OPACITY,
12272 OPACITY_BELOW_THRESHOLD);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070012273 mDispatcher->onWindowInfosChanged(
12274 {{*wB->getInfo(), *wC->getInfo(), *mTouchWindow->getInfo()}, {}, 0, 0});
Bernardo Rufino7393d172021-02-26 13:56:11 +000012275
12276 touch();
12277
12278 mTouchWindow->assertNoEvents();
12279}
12280
12281/**
12282 * This test is testing that a window from a different UID but with same application token doesn't
12283 * block the touch. Apps can share the application token for close UI collaboration for example.
12284 */
12285TEST_F(InputDispatcherUntrustedTouchesTest,
12286 WindowWithSameApplicationTokenFromDifferentApp_AllowsTouch) {
12287 const sp<FakeWindowHandle>& w =
12288 getOccludingWindow(APP_B_UID, "B", TouchOcclusionMode::BLOCK_UNTRUSTED);
12289 w->setApplicationToken(mTouchWindow->getApplicationToken());
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070012290 mDispatcher->onWindowInfosChanged({{*w->getInfo(), *mTouchWindow->getInfo()}, {}, 0, 0});
Bernardo Rufinoccd3dd62021-02-15 18:47:42 +000012291
12292 touch();
12293
12294 mTouchWindow->consumeAnyMotionDown();
12295}
12296
arthurhungb89ccb02020-12-30 16:19:01 +080012297class InputDispatcherDragTests : public InputDispatcherTest {
12298protected:
12299 std::shared_ptr<FakeApplicationHandle> mApp;
12300 sp<FakeWindowHandle> mWindow;
12301 sp<FakeWindowHandle> mSecondWindow;
12302 sp<FakeWindowHandle> mDragWindow;
Vaibhav Devmurari6abcf8f2022-06-06 10:08:05 +000012303 sp<FakeWindowHandle> mSpyWindow;
Arthur Hungb75c2aa2022-07-15 09:35:36 +000012304 // Mouse would force no-split, set the id as non-zero to verify if drag state could track it.
12305 static constexpr int32_t MOUSE_POINTER_ID = 1;
arthurhungb89ccb02020-12-30 16:19:01 +080012306
12307 void SetUp() override {
12308 InputDispatcherTest::SetUp();
12309 mApp = std::make_shared<FakeApplicationHandle>();
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -070012310 mWindow = sp<FakeWindowHandle>::make(mApp, mDispatcher, "TestWindow",
12311 ui::LogicalDisplayId::DEFAULT);
arthurhungb89ccb02020-12-30 16:19:01 +080012312 mWindow->setFrame(Rect(0, 0, 100, 100));
arthurhungb89ccb02020-12-30 16:19:01 +080012313
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -070012314 mSecondWindow = sp<FakeWindowHandle>::make(mApp, mDispatcher, "TestWindow2",
12315 ui::LogicalDisplayId::DEFAULT);
arthurhungb89ccb02020-12-30 16:19:01 +080012316 mSecondWindow->setFrame(Rect(100, 0, 200, 100));
arthurhungb89ccb02020-12-30 16:19:01 +080012317
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -070012318 mSpyWindow = sp<FakeWindowHandle>::make(mApp, mDispatcher, "SpyWindow",
12319 ui::LogicalDisplayId::DEFAULT);
Vaibhav Devmurari6abcf8f2022-06-06 10:08:05 +000012320 mSpyWindow->setSpy(true);
12321 mSpyWindow->setTrustedOverlay(true);
12322 mSpyWindow->setFrame(Rect(0, 0, 200, 100));
12323
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -070012324 mDispatcher->setFocusedApplication(ui::LogicalDisplayId::DEFAULT, mApp);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070012325 mDispatcher->onWindowInfosChanged(
12326 {{*mSpyWindow->getInfo(), *mWindow->getInfo(), *mSecondWindow->getInfo()},
12327 {},
12328 0,
12329 0});
arthurhungb89ccb02020-12-30 16:19:01 +080012330 }
12331
Arthur Hungb75c2aa2022-07-15 09:35:36 +000012332 void injectDown(int fromSource = AINPUT_SOURCE_TOUCHSCREEN) {
12333 switch (fromSource) {
12334 case AINPUT_SOURCE_TOUCHSCREEN:
12335 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070012336 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN,
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -070012337 ui::LogicalDisplayId::DEFAULT, {50, 50}))
Arthur Hungb75c2aa2022-07-15 09:35:36 +000012338 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
12339 break;
12340 case AINPUT_SOURCE_STYLUS:
12341 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070012342 injectMotionEvent(*mDispatcher,
12343 MotionEventBuilder(AMOTION_EVENT_ACTION_DOWN,
12344 AINPUT_SOURCE_STYLUS)
12345 .buttonState(
12346 AMOTION_EVENT_BUTTON_STYLUS_PRIMARY)
12347 .pointer(PointerBuilder(0, ToolType::STYLUS)
12348 .x(50)
12349 .y(50))
12350 .build()));
Arthur Hungb75c2aa2022-07-15 09:35:36 +000012351 break;
12352 case AINPUT_SOURCE_MOUSE:
12353 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070012354 injectMotionEvent(*mDispatcher,
12355 MotionEventBuilder(AMOTION_EVENT_ACTION_DOWN,
12356 AINPUT_SOURCE_MOUSE)
12357 .buttonState(AMOTION_EVENT_BUTTON_PRIMARY)
12358 .pointer(PointerBuilder(MOUSE_POINTER_ID,
12359 ToolType::MOUSE)
12360 .x(50)
12361 .y(50))
12362 .build()));
Arthur Hungb75c2aa2022-07-15 09:35:36 +000012363 break;
12364 default:
12365 FAIL() << "Source " << fromSource << " doesn't support drag and drop";
12366 }
arthurhungb89ccb02020-12-30 16:19:01 +080012367
12368 // Window should receive motion event.
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -070012369 mWindow->consumeMotionDown(ui::LogicalDisplayId::DEFAULT);
Vaibhav Devmurari6abcf8f2022-06-06 10:08:05 +000012370 // Spy window should also receive motion event
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -070012371 mSpyWindow->consumeMotionDown(ui::LogicalDisplayId::DEFAULT);
Arthur Hung54745652022-04-20 07:17:41 +000012372 }
12373
12374 // Start performing drag, we will create a drag window and transfer touch to it.
12375 // @param sendDown : if true, send a motion down on first window before perform drag and drop.
12376 // Returns true on success.
Arthur Hungb75c2aa2022-07-15 09:35:36 +000012377 bool startDrag(bool sendDown = true, int fromSource = AINPUT_SOURCE_TOUCHSCREEN) {
Arthur Hung54745652022-04-20 07:17:41 +000012378 if (sendDown) {
Arthur Hungb75c2aa2022-07-15 09:35:36 +000012379 injectDown(fromSource);
Arthur Hung54745652022-04-20 07:17:41 +000012380 }
arthurhungb89ccb02020-12-30 16:19:01 +080012381
12382 // The drag window covers the entire display
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -070012383 mDragWindow = sp<FakeWindowHandle>::make(mApp, mDispatcher, "DragWindow",
12384 ui::LogicalDisplayId::DEFAULT);
Vaibhav Devmurari6abcf8f2022-06-06 10:08:05 +000012385 mDragWindow->setTouchableRegion(Region{{0, 0, 0, 0}});
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070012386 mDispatcher->onWindowInfosChanged({{*mDragWindow->getInfo(), *mSpyWindow->getInfo(),
12387 *mWindow->getInfo(), *mSecondWindow->getInfo()},
12388 {},
12389 0,
12390 0});
arthurhungb89ccb02020-12-30 16:19:01 +080012391
12392 // Transfer touch focus to the drag window
Arthur Hung54745652022-04-20 07:17:41 +000012393 bool transferred =
Prabir Pradhan367f3432024-02-13 23:05:58 +000012394 mDispatcher->transferTouchGesture(mWindow->getToken(), mDragWindow->getToken(),
12395 /*isDragDrop=*/true);
Arthur Hung54745652022-04-20 07:17:41 +000012396 if (transferred) {
12397 mWindow->consumeMotionCancel();
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -070012398 mDragWindow->consumeMotionDown(ui::LogicalDisplayId::DEFAULT,
12399 AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
Arthur Hung54745652022-04-20 07:17:41 +000012400 }
12401 return transferred;
arthurhungb89ccb02020-12-30 16:19:01 +080012402 }
12403};
12404
12405TEST_F(InputDispatcherDragTests, DragEnterAndDragExit) {
Arthur Hungb75c2aa2022-07-15 09:35:36 +000012406 startDrag();
arthurhungb89ccb02020-12-30 16:19:01 +080012407
12408 // Move on window.
12409 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070012410 injectMotionEvent(*mDispatcher, AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN,
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -070012411 ui::LogicalDisplayId::DEFAULT, {50, 50}))
arthurhungb89ccb02020-12-30 16:19:01 +080012412 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -070012413 mDragWindow->consumeMotionMove(ui::LogicalDisplayId::DEFAULT,
12414 AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
arthurhungb89ccb02020-12-30 16:19:01 +080012415 mWindow->consumeDragEvent(false, 50, 50);
12416 mSecondWindow->assertNoEvents();
12417
12418 // Move to another window.
12419 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070012420 injectMotionEvent(*mDispatcher, AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN,
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -070012421 ui::LogicalDisplayId::DEFAULT, {150, 50}))
arthurhungb89ccb02020-12-30 16:19:01 +080012422 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -070012423 mDragWindow->consumeMotionMove(ui::LogicalDisplayId::DEFAULT,
12424 AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
arthurhungb89ccb02020-12-30 16:19:01 +080012425 mWindow->consumeDragEvent(true, 150, 50);
12426 mSecondWindow->consumeDragEvent(false, 50, 50);
12427
12428 // Move back to original window.
12429 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070012430 injectMotionEvent(*mDispatcher, AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN,
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -070012431 ui::LogicalDisplayId::DEFAULT, {50, 50}))
arthurhungb89ccb02020-12-30 16:19:01 +080012432 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -070012433 mDragWindow->consumeMotionMove(ui::LogicalDisplayId::DEFAULT,
12434 AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
arthurhungb89ccb02020-12-30 16:19:01 +080012435 mWindow->consumeDragEvent(false, 50, 50);
12436 mSecondWindow->consumeDragEvent(true, -50, 50);
12437
12438 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -070012439 injectMotionUp(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ui::LogicalDisplayId::DEFAULT,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070012440 {50, 50}))
arthurhungb89ccb02020-12-30 16:19:01 +080012441 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -070012442 mDragWindow->consumeMotionUp(ui::LogicalDisplayId::DEFAULT, AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
arthurhungb89ccb02020-12-30 16:19:01 +080012443 mWindow->assertNoEvents();
12444 mSecondWindow->assertNoEvents();
12445}
12446
Vaibhav Devmurari6abcf8f2022-06-06 10:08:05 +000012447TEST_F(InputDispatcherDragTests, DragEnterAndPointerDownPilfersPointers) {
Arthur Hungb75c2aa2022-07-15 09:35:36 +000012448 startDrag();
Vaibhav Devmurari6abcf8f2022-06-06 10:08:05 +000012449
12450 // No cancel event after drag start
12451 mSpyWindow->assertNoEvents();
12452
12453 const MotionEvent secondFingerDownEvent =
12454 MotionEventBuilder(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
12455 .eventTime(systemTime(SYSTEM_TIME_MONOTONIC))
Siarhei Vishniakou6d73f832022-07-21 17:27:03 -070012456 .pointer(PointerBuilder(/*id=*/0, ToolType::FINGER).x(50).y(50))
12457 .pointer(PointerBuilder(/*id=*/1, ToolType::FINGER).x(60).y(60))
Vaibhav Devmurari6abcf8f2022-06-06 10:08:05 +000012458 .build();
12459 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070012460 injectMotionEvent(*mDispatcher, secondFingerDownEvent, INJECT_EVENT_TIMEOUT,
Vaibhav Devmurari6abcf8f2022-06-06 10:08:05 +000012461 InputEventInjectionSync::WAIT_FOR_RESULT))
12462 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
12463
12464 // Receives cancel for first pointer after next pointer down
12465 mSpyWindow->consumeMotionCancel();
12466 mSpyWindow->consumeMotionDown();
12467
12468 mSpyWindow->assertNoEvents();
12469}
12470
arthurhungf452d0b2021-01-06 00:19:52 +080012471TEST_F(InputDispatcherDragTests, DragAndDrop) {
Arthur Hungb75c2aa2022-07-15 09:35:36 +000012472 startDrag();
arthurhungf452d0b2021-01-06 00:19:52 +080012473
12474 // Move on window.
12475 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070012476 injectMotionEvent(*mDispatcher, AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN,
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -070012477 ui::LogicalDisplayId::DEFAULT, {50, 50}))
arthurhungf452d0b2021-01-06 00:19:52 +080012478 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -070012479 mDragWindow->consumeMotionMove(ui::LogicalDisplayId::DEFAULT,
12480 AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
arthurhungf452d0b2021-01-06 00:19:52 +080012481 mWindow->consumeDragEvent(false, 50, 50);
12482 mSecondWindow->assertNoEvents();
12483
12484 // Move to another window.
12485 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070012486 injectMotionEvent(*mDispatcher, AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN,
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -070012487 ui::LogicalDisplayId::DEFAULT, {150, 50}))
arthurhungf452d0b2021-01-06 00:19:52 +080012488 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -070012489 mDragWindow->consumeMotionMove(ui::LogicalDisplayId::DEFAULT,
12490 AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
arthurhungf452d0b2021-01-06 00:19:52 +080012491 mWindow->consumeDragEvent(true, 150, 50);
12492 mSecondWindow->consumeDragEvent(false, 50, 50);
12493
12494 // drop to another window.
12495 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -070012496 injectMotionUp(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ui::LogicalDisplayId::DEFAULT,
arthurhungf452d0b2021-01-06 00:19:52 +080012497 {150, 50}))
12498 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -070012499 mDragWindow->consumeMotionUp(ui::LogicalDisplayId::DEFAULT, AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
Siarhei Vishniakoua66d65e2023-06-16 10:32:51 -070012500 mFakePolicy->assertDropTargetEquals(*mDispatcher, mSecondWindow->getToken());
arthurhungf452d0b2021-01-06 00:19:52 +080012501 mWindow->assertNoEvents();
12502 mSecondWindow->assertNoEvents();
12503}
12504
Vaibhav Devmurari110ba322023-11-17 10:47:16 +000012505TEST_F(InputDispatcherDragTests, DragAndDropNotCancelledIfSomeOtherPointerIsPilfered) {
12506 startDrag();
12507
12508 // No cancel event after drag start
12509 mSpyWindow->assertNoEvents();
12510
12511 const MotionEvent secondFingerDownEvent =
12512 MotionEventBuilder(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
12513 .eventTime(systemTime(SYSTEM_TIME_MONOTONIC))
12514 .pointer(PointerBuilder(/*id=*/0, ToolType::FINGER).x(50).y(50))
12515 .pointer(PointerBuilder(/*id=*/1, ToolType::FINGER).x(60).y(60))
12516 .build();
12517 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
12518 injectMotionEvent(*mDispatcher, secondFingerDownEvent, INJECT_EVENT_TIMEOUT,
12519 InputEventInjectionSync::WAIT_FOR_RESULT))
12520 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
12521
12522 // Receives cancel for first pointer after next pointer down
12523 mSpyWindow->consumeMotionEvent(WithMotionAction(ACTION_CANCEL));
Siarhei Vishniakou1ff00cc2023-12-13 16:12:13 -080012524 mSpyWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithPointerIds({1})));
Vaibhav Devmurari110ba322023-11-17 10:47:16 +000012525 mDragWindow->consumeMotionEvent(WithMotionAction(ACTION_MOVE));
12526
12527 mSpyWindow->assertNoEvents();
12528
12529 // Spy window calls pilfer pointers
12530 EXPECT_EQ(OK, mDispatcher->pilferPointers(mSpyWindow->getToken()));
12531 mDragWindow->assertNoEvents();
12532
12533 const MotionEvent firstFingerMoveEvent =
Siarhei Vishniakou96a15572023-12-18 10:47:52 -080012534 MotionEventBuilder(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN)
Vaibhav Devmurari110ba322023-11-17 10:47:16 +000012535 .eventTime(systemTime(SYSTEM_TIME_MONOTONIC))
12536 .pointer(PointerBuilder(/*id=*/0, ToolType::FINGER).x(60).y(60))
12537 .pointer(PointerBuilder(/*id=*/1, ToolType::FINGER).x(60).y(60))
12538 .build();
12539 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakou96a15572023-12-18 10:47:52 -080012540 injectMotionEvent(*mDispatcher, firstFingerMoveEvent, INJECT_EVENT_TIMEOUT,
Vaibhav Devmurari110ba322023-11-17 10:47:16 +000012541 InputEventInjectionSync::WAIT_FOR_RESULT))
12542 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
12543
12544 // Drag window should still receive the new event
Prabir Pradhan65455c72024-02-13 21:46:41 +000012545 mDragWindow->consumeMotionEvent(
12546 AllOf(WithMotionAction(ACTION_MOVE), WithFlags(AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE)));
Vaibhav Devmurari110ba322023-11-17 10:47:16 +000012547 mDragWindow->assertNoEvents();
12548}
12549
arthurhung6d4bed92021-03-17 11:59:33 +080012550TEST_F(InputDispatcherDragTests, StylusDragAndDrop) {
Arthur Hungb75c2aa2022-07-15 09:35:36 +000012551 startDrag(true, AINPUT_SOURCE_STYLUS);
arthurhung6d4bed92021-03-17 11:59:33 +080012552
12553 // Move on window and keep button pressed.
12554 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070012555 injectMotionEvent(*mDispatcher,
arthurhung6d4bed92021-03-17 11:59:33 +080012556 MotionEventBuilder(AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_STYLUS)
12557 .buttonState(AMOTION_EVENT_BUTTON_STYLUS_PRIMARY)
Siarhei Vishniakou6d73f832022-07-21 17:27:03 -070012558 .pointer(PointerBuilder(0, ToolType::STYLUS).x(50).y(50))
arthurhung6d4bed92021-03-17 11:59:33 +080012559 .build()))
12560 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -070012561 mDragWindow->consumeMotionMove(ui::LogicalDisplayId::DEFAULT,
12562 AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
arthurhung6d4bed92021-03-17 11:59:33 +080012563 mWindow->consumeDragEvent(false, 50, 50);
12564 mSecondWindow->assertNoEvents();
12565
12566 // Move to another window and release button, expect to drop item.
12567 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070012568 injectMotionEvent(*mDispatcher,
arthurhung6d4bed92021-03-17 11:59:33 +080012569 MotionEventBuilder(AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_STYLUS)
12570 .buttonState(0)
Siarhei Vishniakou6d73f832022-07-21 17:27:03 -070012571 .pointer(PointerBuilder(0, ToolType::STYLUS).x(150).y(50))
arthurhung6d4bed92021-03-17 11:59:33 +080012572 .build()))
12573 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -070012574 mDragWindow->consumeMotionMove(ui::LogicalDisplayId::DEFAULT,
12575 AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
arthurhung6d4bed92021-03-17 11:59:33 +080012576 mWindow->assertNoEvents();
12577 mSecondWindow->assertNoEvents();
Siarhei Vishniakoua66d65e2023-06-16 10:32:51 -070012578 mFakePolicy->assertDropTargetEquals(*mDispatcher, mSecondWindow->getToken());
arthurhung6d4bed92021-03-17 11:59:33 +080012579
12580 // nothing to the window.
12581 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070012582 injectMotionEvent(*mDispatcher,
arthurhung6d4bed92021-03-17 11:59:33 +080012583 MotionEventBuilder(AMOTION_EVENT_ACTION_UP, AINPUT_SOURCE_STYLUS)
12584 .buttonState(0)
Siarhei Vishniakou6d73f832022-07-21 17:27:03 -070012585 .pointer(PointerBuilder(0, ToolType::STYLUS).x(150).y(50))
arthurhung6d4bed92021-03-17 11:59:33 +080012586 .build()))
12587 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -070012588 mDragWindow->consumeMotionUp(ui::LogicalDisplayId::DEFAULT, AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
arthurhung6d4bed92021-03-17 11:59:33 +080012589 mWindow->assertNoEvents();
12590 mSecondWindow->assertNoEvents();
12591}
12592
Arthur Hung54745652022-04-20 07:17:41 +000012593TEST_F(InputDispatcherDragTests, DragAndDropOnInvalidWindow) {
Arthur Hungb75c2aa2022-07-15 09:35:36 +000012594 startDrag();
Arthur Hung6d0571e2021-04-09 20:18:16 +080012595
12596 // Set second window invisible.
12597 mSecondWindow->setVisible(false);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070012598 mDispatcher->onWindowInfosChanged(
12599 {{*mDragWindow->getInfo(), *mWindow->getInfo(), *mSecondWindow->getInfo()}, {}, 0, 0});
Arthur Hung6d0571e2021-04-09 20:18:16 +080012600
12601 // Move on window.
12602 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070012603 injectMotionEvent(*mDispatcher, AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN,
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -070012604 ui::LogicalDisplayId::DEFAULT, {50, 50}))
Arthur Hung6d0571e2021-04-09 20:18:16 +080012605 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -070012606 mDragWindow->consumeMotionMove(ui::LogicalDisplayId::DEFAULT,
12607 AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
Arthur Hung6d0571e2021-04-09 20:18:16 +080012608 mWindow->consumeDragEvent(false, 50, 50);
12609 mSecondWindow->assertNoEvents();
12610
12611 // Move to another window.
12612 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070012613 injectMotionEvent(*mDispatcher, AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN,
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -070012614 ui::LogicalDisplayId::DEFAULT, {150, 50}))
Arthur Hung6d0571e2021-04-09 20:18:16 +080012615 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -070012616 mDragWindow->consumeMotionMove(ui::LogicalDisplayId::DEFAULT,
12617 AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
Arthur Hung6d0571e2021-04-09 20:18:16 +080012618 mWindow->consumeDragEvent(true, 150, 50);
12619 mSecondWindow->assertNoEvents();
12620
12621 // drop to another window.
12622 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -070012623 injectMotionUp(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ui::LogicalDisplayId::DEFAULT,
Arthur Hung6d0571e2021-04-09 20:18:16 +080012624 {150, 50}))
12625 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -070012626 mDragWindow->consumeMotionUp(ui::LogicalDisplayId::DEFAULT, AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
Siarhei Vishniakoua66d65e2023-06-16 10:32:51 -070012627 mFakePolicy->assertDropTargetEquals(*mDispatcher, nullptr);
Arthur Hung6d0571e2021-04-09 20:18:16 +080012628 mWindow->assertNoEvents();
12629 mSecondWindow->assertNoEvents();
12630}
12631
Arthur Hung54745652022-04-20 07:17:41 +000012632TEST_F(InputDispatcherDragTests, NoDragAndDropWhenMultiFingers) {
Arthur Hungb75c2aa2022-07-15 09:35:36 +000012633 // Ensure window could track pointerIds if it didn't support split touch.
12634 mWindow->setPreventSplitting(true);
12635
Arthur Hung54745652022-04-20 07:17:41 +000012636 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -070012637 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN,
12638 ui::LogicalDisplayId::DEFAULT, {50, 50}))
Arthur Hung54745652022-04-20 07:17:41 +000012639 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -070012640 mWindow->consumeMotionDown(ui::LogicalDisplayId::DEFAULT);
Arthur Hung54745652022-04-20 07:17:41 +000012641
12642 const MotionEvent secondFingerDownEvent =
12643 MotionEventBuilder(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -070012644 .displayId(ui::LogicalDisplayId::DEFAULT)
Arthur Hung54745652022-04-20 07:17:41 +000012645 .eventTime(systemTime(SYSTEM_TIME_MONOTONIC))
Siarhei Vishniakou6d73f832022-07-21 17:27:03 -070012646 .pointer(PointerBuilder(/*id=*/0, ToolType::FINGER).x(50).y(50))
12647 .pointer(PointerBuilder(/*id=*/1, ToolType::FINGER).x(75).y(50))
Arthur Hung54745652022-04-20 07:17:41 +000012648 .build();
12649 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070012650 injectMotionEvent(*mDispatcher, secondFingerDownEvent, INJECT_EVENT_TIMEOUT,
Arthur Hung54745652022-04-20 07:17:41 +000012651 InputEventInjectionSync::WAIT_FOR_RESULT))
12652 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
Harry Cutts33476232023-01-30 19:57:29 +000012653 mWindow->consumeMotionPointerDown(/*pointerIndex=*/1);
Arthur Hung54745652022-04-20 07:17:41 +000012654
12655 // Should not perform drag and drop when window has multi fingers.
Arthur Hungb75c2aa2022-07-15 09:35:36 +000012656 ASSERT_FALSE(startDrag(false));
Arthur Hung54745652022-04-20 07:17:41 +000012657}
12658
12659TEST_F(InputDispatcherDragTests, DragAndDropWhenSplitTouch) {
12660 // First down on second window.
12661 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -070012662 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN,
12663 ui::LogicalDisplayId::DEFAULT, {150, 50}))
Arthur Hung54745652022-04-20 07:17:41 +000012664 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
12665
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -070012666 mSecondWindow->consumeMotionDown(ui::LogicalDisplayId::DEFAULT);
Arthur Hung54745652022-04-20 07:17:41 +000012667
12668 // Second down on first window.
12669 const MotionEvent secondFingerDownEvent =
12670 MotionEventBuilder(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -070012671 .displayId(ui::LogicalDisplayId::DEFAULT)
Arthur Hung54745652022-04-20 07:17:41 +000012672 .eventTime(systemTime(SYSTEM_TIME_MONOTONIC))
Siarhei Vishniakou6d73f832022-07-21 17:27:03 -070012673 .pointer(PointerBuilder(/*id=*/0, ToolType::FINGER).x(150).y(50))
12674 .pointer(PointerBuilder(/*id=*/1, ToolType::FINGER).x(50).y(50))
Arthur Hung54745652022-04-20 07:17:41 +000012675 .build();
12676 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070012677 injectMotionEvent(*mDispatcher, secondFingerDownEvent, INJECT_EVENT_TIMEOUT,
Arthur Hung54745652022-04-20 07:17:41 +000012678 InputEventInjectionSync::WAIT_FOR_RESULT))
12679 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -070012680 mWindow->consumeMotionDown(ui::LogicalDisplayId::DEFAULT);
12681 mSecondWindow->consumeMotionMove(ui::LogicalDisplayId::DEFAULT);
Arthur Hung54745652022-04-20 07:17:41 +000012682
12683 // Perform drag and drop from first window.
Arthur Hungb75c2aa2022-07-15 09:35:36 +000012684 ASSERT_TRUE(startDrag(false));
Arthur Hung54745652022-04-20 07:17:41 +000012685
12686 // Move on window.
12687 const MotionEvent secondFingerMoveEvent =
12688 MotionEventBuilder(AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN)
12689 .eventTime(systemTime(SYSTEM_TIME_MONOTONIC))
Siarhei Vishniakou6d73f832022-07-21 17:27:03 -070012690 .pointer(PointerBuilder(/*id=*/0, ToolType::FINGER).x(150).y(50))
12691 .pointer(PointerBuilder(/*id=*/1, ToolType::FINGER).x(50).y(50))
Arthur Hung54745652022-04-20 07:17:41 +000012692 .build();
12693 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070012694 injectMotionEvent(*mDispatcher, secondFingerMoveEvent, INJECT_EVENT_TIMEOUT,
Arthur Hung54745652022-04-20 07:17:41 +000012695 InputEventInjectionSync::WAIT_FOR_RESULT));
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -070012696 mDragWindow->consumeMotionMove(ui::LogicalDisplayId::DEFAULT,
12697 AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
Arthur Hung54745652022-04-20 07:17:41 +000012698 mWindow->consumeDragEvent(false, 50, 50);
12699 mSecondWindow->consumeMotionMove();
12700
12701 // Release the drag pointer should perform drop.
12702 const MotionEvent secondFingerUpEvent =
12703 MotionEventBuilder(POINTER_1_UP, AINPUT_SOURCE_TOUCHSCREEN)
12704 .eventTime(systemTime(SYSTEM_TIME_MONOTONIC))
Siarhei Vishniakou6d73f832022-07-21 17:27:03 -070012705 .pointer(PointerBuilder(/*id=*/0, ToolType::FINGER).x(150).y(50))
12706 .pointer(PointerBuilder(/*id=*/1, ToolType::FINGER).x(50).y(50))
Arthur Hung54745652022-04-20 07:17:41 +000012707 .build();
12708 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070012709 injectMotionEvent(*mDispatcher, secondFingerUpEvent, INJECT_EVENT_TIMEOUT,
Arthur Hung54745652022-04-20 07:17:41 +000012710 InputEventInjectionSync::WAIT_FOR_RESULT));
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -070012711 mDragWindow->consumeMotionUp(ui::LogicalDisplayId::DEFAULT, AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
Siarhei Vishniakoua66d65e2023-06-16 10:32:51 -070012712 mFakePolicy->assertDropTargetEquals(*mDispatcher, mWindow->getToken());
Arthur Hung54745652022-04-20 07:17:41 +000012713 mWindow->assertNoEvents();
12714 mSecondWindow->consumeMotionMove();
12715}
12716
Arthur Hung3915c1f2022-05-31 07:17:17 +000012717TEST_F(InputDispatcherDragTests, DragAndDropWhenMultiDisplays) {
Arthur Hungb75c2aa2022-07-15 09:35:36 +000012718 startDrag();
Arthur Hung3915c1f2022-05-31 07:17:17 +000012719
12720 // Update window of second display.
12721 sp<FakeWindowHandle> windowInSecondary =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -070012722 sp<FakeWindowHandle>::make(mApp, mDispatcher, "D_2", SECOND_DISPLAY_ID);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070012723 mDispatcher->onWindowInfosChanged(
12724 {{*mDragWindow->getInfo(), *mSpyWindow->getInfo(), *mWindow->getInfo(),
12725 *mSecondWindow->getInfo(), *windowInSecondary->getInfo()},
12726 {},
12727 0,
12728 0});
Arthur Hung3915c1f2022-05-31 07:17:17 +000012729
12730 // Let second display has a touch state.
12731 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070012732 injectMotionEvent(*mDispatcher,
Arthur Hung3915c1f2022-05-31 07:17:17 +000012733 MotionEventBuilder(AMOTION_EVENT_ACTION_DOWN,
12734 AINPUT_SOURCE_TOUCHSCREEN)
12735 .displayId(SECOND_DISPLAY_ID)
Siarhei Vishniakou6d73f832022-07-21 17:27:03 -070012736 .pointer(PointerBuilder(0, ToolType::FINGER).x(100).y(100))
Arthur Hung3915c1f2022-05-31 07:17:17 +000012737 .build()));
Prabir Pradhan7662a8d2023-12-15 01:58:14 +000012738 windowInSecondary->consumeMotionDown(SECOND_DISPLAY_ID, /*expectedFlag=*/0);
Arthur Hung3915c1f2022-05-31 07:17:17 +000012739 // Update window again.
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070012740 mDispatcher->onWindowInfosChanged(
12741 {{*mDragWindow->getInfo(), *mSpyWindow->getInfo(), *mWindow->getInfo(),
12742 *mSecondWindow->getInfo(), *windowInSecondary->getInfo()},
12743 {},
12744 0,
12745 0});
Arthur Hung3915c1f2022-05-31 07:17:17 +000012746
12747 // Move on window.
12748 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070012749 injectMotionEvent(*mDispatcher, AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN,
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -070012750 ui::LogicalDisplayId::DEFAULT, {50, 50}))
Arthur Hung3915c1f2022-05-31 07:17:17 +000012751 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -070012752 mDragWindow->consumeMotionMove(ui::LogicalDisplayId::DEFAULT,
12753 AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
Arthur Hung3915c1f2022-05-31 07:17:17 +000012754 mWindow->consumeDragEvent(false, 50, 50);
12755 mSecondWindow->assertNoEvents();
12756
12757 // Move to another window.
12758 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070012759 injectMotionEvent(*mDispatcher, AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN,
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -070012760 ui::LogicalDisplayId::DEFAULT, {150, 50}))
Arthur Hung3915c1f2022-05-31 07:17:17 +000012761 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -070012762 mDragWindow->consumeMotionMove(ui::LogicalDisplayId::DEFAULT,
12763 AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
Arthur Hung3915c1f2022-05-31 07:17:17 +000012764 mWindow->consumeDragEvent(true, 150, 50);
12765 mSecondWindow->consumeDragEvent(false, 50, 50);
12766
12767 // drop to another window.
12768 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -070012769 injectMotionUp(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ui::LogicalDisplayId::DEFAULT,
Arthur Hung3915c1f2022-05-31 07:17:17 +000012770 {150, 50}))
12771 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -070012772 mDragWindow->consumeMotionUp(ui::LogicalDisplayId::DEFAULT, AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
Siarhei Vishniakoua66d65e2023-06-16 10:32:51 -070012773 mFakePolicy->assertDropTargetEquals(*mDispatcher, mSecondWindow->getToken());
Arthur Hung3915c1f2022-05-31 07:17:17 +000012774 mWindow->assertNoEvents();
12775 mSecondWindow->assertNoEvents();
12776}
12777
Arthur Hungb75c2aa2022-07-15 09:35:36 +000012778TEST_F(InputDispatcherDragTests, MouseDragAndDrop) {
12779 startDrag(true, AINPUT_SOURCE_MOUSE);
12780 // Move on window.
12781 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070012782 injectMotionEvent(*mDispatcher,
Arthur Hungb75c2aa2022-07-15 09:35:36 +000012783 MotionEventBuilder(AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_MOUSE)
12784 .buttonState(AMOTION_EVENT_BUTTON_PRIMARY)
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070012785 .pointer(PointerBuilder(MOUSE_POINTER_ID, ToolType::MOUSE)
Arthur Hungb75c2aa2022-07-15 09:35:36 +000012786 .x(50)
12787 .y(50))
12788 .build()))
12789 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -070012790 mDragWindow->consumeMotionMove(ui::LogicalDisplayId::DEFAULT,
12791 AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
Arthur Hungb75c2aa2022-07-15 09:35:36 +000012792 mWindow->consumeDragEvent(false, 50, 50);
12793 mSecondWindow->assertNoEvents();
12794
12795 // Move to another window.
12796 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070012797 injectMotionEvent(*mDispatcher,
Arthur Hungb75c2aa2022-07-15 09:35:36 +000012798 MotionEventBuilder(AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_MOUSE)
12799 .buttonState(AMOTION_EVENT_BUTTON_PRIMARY)
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070012800 .pointer(PointerBuilder(MOUSE_POINTER_ID, ToolType::MOUSE)
Arthur Hungb75c2aa2022-07-15 09:35:36 +000012801 .x(150)
12802 .y(50))
12803 .build()))
12804 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -070012805 mDragWindow->consumeMotionMove(ui::LogicalDisplayId::DEFAULT,
12806 AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
Arthur Hungb75c2aa2022-07-15 09:35:36 +000012807 mWindow->consumeDragEvent(true, 150, 50);
12808 mSecondWindow->consumeDragEvent(false, 50, 50);
12809
12810 // drop to another window.
12811 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070012812 injectMotionEvent(*mDispatcher,
Arthur Hungb75c2aa2022-07-15 09:35:36 +000012813 MotionEventBuilder(AMOTION_EVENT_ACTION_UP, AINPUT_SOURCE_MOUSE)
12814 .buttonState(0)
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070012815 .pointer(PointerBuilder(MOUSE_POINTER_ID, ToolType::MOUSE)
Arthur Hungb75c2aa2022-07-15 09:35:36 +000012816 .x(150)
12817 .y(50))
12818 .build()))
12819 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -070012820 mDragWindow->consumeMotionUp(ui::LogicalDisplayId::DEFAULT, AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
Siarhei Vishniakoua66d65e2023-06-16 10:32:51 -070012821 mFakePolicy->assertDropTargetEquals(*mDispatcher, mSecondWindow->getToken());
Arthur Hungb75c2aa2022-07-15 09:35:36 +000012822 mWindow->assertNoEvents();
12823 mSecondWindow->assertNoEvents();
12824}
12825
Linnan Li5af92f92023-07-14 14:36:22 +080012826/**
12827 * Start drag and drop with a pointer whose id is not 0, cancel the current touch, and ensure drag
12828 * and drop is also canceled. Then inject a simple gesture, and ensure dispatcher does not crash.
12829 */
12830TEST_F(InputDispatcherDragTests, DragAndDropFinishedWhenCancelCurrentTouch) {
12831 // Down on second window
12832 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -070012833 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN,
12834 ui::LogicalDisplayId::DEFAULT, {150, 50}))
Linnan Li5af92f92023-07-14 14:36:22 +080012835 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
12836
12837 ASSERT_NO_FATAL_FAILURE(mSecondWindow->consumeMotionDown());
12838 ASSERT_NO_FATAL_FAILURE(mSpyWindow->consumeMotionDown());
12839
12840 // Down on first window
12841 const MotionEvent secondFingerDownEvent =
12842 MotionEventBuilder(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -070012843 .displayId(ui::LogicalDisplayId::DEFAULT)
Linnan Li5af92f92023-07-14 14:36:22 +080012844 .pointer(PointerBuilder(/*id=*/0, ToolType::FINGER).x(150).y(50))
12845 .pointer(PointerBuilder(/*id=*/1, ToolType::FINGER).x(50).y(50))
12846 .build();
12847 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
12848 injectMotionEvent(*mDispatcher, secondFingerDownEvent, INJECT_EVENT_TIMEOUT,
12849 InputEventInjectionSync::WAIT_FOR_RESULT))
12850 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
12851 ASSERT_NO_FATAL_FAILURE(mWindow->consumeMotionDown());
12852 ASSERT_NO_FATAL_FAILURE(mSecondWindow->consumeMotionMove());
12853 ASSERT_NO_FATAL_FAILURE(mSpyWindow->consumeMotionPointerDown(1));
12854
12855 // Start drag on first window
12856 ASSERT_TRUE(startDrag(/*sendDown=*/false, AINPUT_SOURCE_TOUCHSCREEN));
12857
12858 // Trigger cancel
12859 mDispatcher->cancelCurrentTouch();
12860 ASSERT_NO_FATAL_FAILURE(mSecondWindow->consumeMotionCancel());
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -070012861 ASSERT_NO_FATAL_FAILURE(mDragWindow->consumeMotionCancel(ui::LogicalDisplayId::DEFAULT,
Prabir Pradhan65455c72024-02-13 21:46:41 +000012862 AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE));
Linnan Li5af92f92023-07-14 14:36:22 +080012863 ASSERT_NO_FATAL_FAILURE(mSpyWindow->consumeMotionCancel());
12864
12865 ASSERT_TRUE(mDispatcher->waitForIdle());
12866 // The D&D finished with nullptr
12867 mFakePolicy->assertDropTargetEquals(*mDispatcher, nullptr);
12868
12869 // Remove drag window
12870 mDispatcher->onWindowInfosChanged({{*mWindow->getInfo(), *mSecondWindow->getInfo()}, {}, 0, 0});
12871
12872 // Inject a simple gesture, ensure dispatcher not crashed
12873 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -070012874 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN,
12875 ui::LogicalDisplayId::DEFAULT, PointF{50, 50}))
Linnan Li5af92f92023-07-14 14:36:22 +080012876 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
12877 ASSERT_NO_FATAL_FAILURE(mWindow->consumeMotionDown());
12878
12879 const MotionEvent moveEvent =
12880 MotionEventBuilder(AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN)
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -070012881 .displayId(ui::LogicalDisplayId::DEFAULT)
Linnan Li5af92f92023-07-14 14:36:22 +080012882 .pointer(PointerBuilder(/*id=*/0, ToolType::FINGER).x(50).y(50))
12883 .build();
12884 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
12885 injectMotionEvent(*mDispatcher, moveEvent, INJECT_EVENT_TIMEOUT,
12886 InputEventInjectionSync::WAIT_FOR_RESULT))
12887 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
12888 ASSERT_NO_FATAL_FAILURE(mWindow->consumeMotionMove());
12889
12890 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -070012891 injectMotionUp(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ui::LogicalDisplayId::DEFAULT,
Linnan Li5af92f92023-07-14 14:36:22 +080012892 {50, 50}))
12893 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
12894 ASSERT_NO_FATAL_FAILURE(mWindow->consumeMotionUp());
12895}
12896
Prabir Pradhan9cd9eb62023-11-22 17:58:06 +000012897TEST_F(InputDispatcherDragTests, NoDragAndDropWithHoveringPointer) {
12898 // Start hovering over the window.
12899 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
12900 injectMotionEvent(*mDispatcher, ACTION_HOVER_ENTER, AINPUT_SOURCE_MOUSE,
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -070012901 ui::LogicalDisplayId::DEFAULT, {50, 50}));
Prabir Pradhan9cd9eb62023-11-22 17:58:06 +000012902
12903 ASSERT_NO_FATAL_FAILURE(mWindow->consumeMotionEvent(WithMotionAction(ACTION_HOVER_ENTER)));
12904 ASSERT_NO_FATAL_FAILURE(mSpyWindow->consumeMotionEvent(WithMotionAction(ACTION_HOVER_ENTER)));
12905
12906 ASSERT_FALSE(startDrag(/*sendDown=*/false))
12907 << "Drag and drop should not work with a hovering pointer";
12908}
12909
Vishnu Nair062a8672021-09-03 16:07:44 -070012910class InputDispatcherDropInputFeatureTest : public InputDispatcherTest {};
12911
12912TEST_F(InputDispatcherDropInputFeatureTest, WindowDropsInput) {
12913 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -070012914 sp<FakeWindowHandle> window =
12915 sp<FakeWindowHandle>::make(application, mDispatcher, "Test window",
12916 ui::LogicalDisplayId::DEFAULT);
Prabir Pradhan51e7db02022-02-07 06:02:57 -080012917 window->setDropInput(true);
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -070012918 mDispatcher->setFocusedApplication(ui::LogicalDisplayId::DEFAULT, application);
Vishnu Nair062a8672021-09-03 16:07:44 -070012919 window->setFocusable(true);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070012920 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Vishnu Nair062a8672021-09-03 16:07:44 -070012921 setFocusedWindow(window);
Harry Cutts33476232023-01-30 19:57:29 +000012922 window->consumeFocusEvent(/*hasFocus=*/true, /*inTouchMode=*/true);
Vishnu Nair062a8672021-09-03 16:07:44 -070012923
12924 // With the flag set, window should not get any input
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -070012925 mDispatcher->notifyKey(generateKeyArgs(AKEY_EVENT_ACTION_DOWN, ui::LogicalDisplayId::DEFAULT));
Vishnu Nair062a8672021-09-03 16:07:44 -070012926 window->assertNoEvents();
12927
Prabir Pradhan678438e2023-04-13 19:32:51 +000012928 mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_DOWN,
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -070012929 AINPUT_SOURCE_TOUCHSCREEN,
12930 ui::LogicalDisplayId::DEFAULT));
Siarhei Vishniakou5c02a712023-05-15 15:45:02 -070012931 mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN,
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -070012932 ui::LogicalDisplayId::DEFAULT));
Siarhei Vishniakoud908f5a2023-11-16 10:25:12 -080012933 mDispatcher->waitForIdle();
Vishnu Nair062a8672021-09-03 16:07:44 -070012934 window->assertNoEvents();
12935
12936 // With the flag cleared, the window should get input
Prabir Pradhan51e7db02022-02-07 06:02:57 -080012937 window->setDropInput(false);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070012938 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Vishnu Nair062a8672021-09-03 16:07:44 -070012939
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -070012940 mDispatcher->notifyKey(generateKeyArgs(AKEY_EVENT_ACTION_UP, ui::LogicalDisplayId::DEFAULT));
12941 window->consumeKeyUp(ui::LogicalDisplayId::DEFAULT);
Vishnu Nair062a8672021-09-03 16:07:44 -070012942
Prabir Pradhan678438e2023-04-13 19:32:51 +000012943 mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_DOWN,
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -070012944 AINPUT_SOURCE_TOUCHSCREEN,
12945 ui::LogicalDisplayId::DEFAULT));
12946 window->consumeMotionDown(ui::LogicalDisplayId::DEFAULT);
Vishnu Nair062a8672021-09-03 16:07:44 -070012947 window->assertNoEvents();
12948}
12949
12950TEST_F(InputDispatcherDropInputFeatureTest, ObscuredWindowDropsInput) {
12951 std::shared_ptr<FakeApplicationHandle> obscuringApplication =
12952 std::make_shared<FakeApplicationHandle>();
12953 sp<FakeWindowHandle> obscuringWindow =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -070012954 sp<FakeWindowHandle>::make(obscuringApplication, mDispatcher, "obscuringWindow",
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -070012955 ui::LogicalDisplayId::DEFAULT);
Vishnu Nair062a8672021-09-03 16:07:44 -070012956 obscuringWindow->setFrame(Rect(0, 0, 50, 50));
Prabir Pradhanaeebeb42023-06-13 19:53:03 +000012957 obscuringWindow->setOwnerInfo(gui::Pid{111}, gui::Uid{111});
Prabir Pradhan4d5c52f2022-01-31 08:52:10 -080012958 obscuringWindow->setTouchable(false);
Vishnu Nair062a8672021-09-03 16:07:44 -070012959 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -070012960 sp<FakeWindowHandle> window =
12961 sp<FakeWindowHandle>::make(application, mDispatcher, "Test window",
12962 ui::LogicalDisplayId::DEFAULT);
Prabir Pradhan51e7db02022-02-07 06:02:57 -080012963 window->setDropInputIfObscured(true);
Prabir Pradhanaeebeb42023-06-13 19:53:03 +000012964 window->setOwnerInfo(gui::Pid{222}, gui::Uid{222});
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -070012965 mDispatcher->setFocusedApplication(ui::LogicalDisplayId::DEFAULT, application);
Vishnu Nair062a8672021-09-03 16:07:44 -070012966 window->setFocusable(true);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070012967 mDispatcher->onWindowInfosChanged(
12968 {{*obscuringWindow->getInfo(), *window->getInfo()}, {}, 0, 0});
Vishnu Nair062a8672021-09-03 16:07:44 -070012969 setFocusedWindow(window);
Harry Cutts33476232023-01-30 19:57:29 +000012970 window->consumeFocusEvent(/*hasFocus=*/true, /*inTouchMode=*/true);
Vishnu Nair062a8672021-09-03 16:07:44 -070012971
12972 // With the flag set, window should not get any input
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -070012973 mDispatcher->notifyKey(generateKeyArgs(AKEY_EVENT_ACTION_DOWN, ui::LogicalDisplayId::DEFAULT));
Vishnu Nair062a8672021-09-03 16:07:44 -070012974 window->assertNoEvents();
12975
Prabir Pradhan678438e2023-04-13 19:32:51 +000012976 mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_DOWN,
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -070012977 AINPUT_SOURCE_TOUCHSCREEN,
12978 ui::LogicalDisplayId::DEFAULT));
Siarhei Vishniakou5c02a712023-05-15 15:45:02 -070012979 mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN,
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -070012980 ui::LogicalDisplayId::DEFAULT));
Vishnu Nair062a8672021-09-03 16:07:44 -070012981 window->assertNoEvents();
12982
12983 // With the flag cleared, the window should get input
Prabir Pradhan51e7db02022-02-07 06:02:57 -080012984 window->setDropInputIfObscured(false);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070012985 mDispatcher->onWindowInfosChanged(
12986 {{*obscuringWindow->getInfo(), *window->getInfo()}, {}, 0, 0});
Vishnu Nair062a8672021-09-03 16:07:44 -070012987
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -070012988 mDispatcher->notifyKey(generateKeyArgs(AKEY_EVENT_ACTION_UP, ui::LogicalDisplayId::DEFAULT));
12989 window->consumeKeyUp(ui::LogicalDisplayId::DEFAULT);
Vishnu Nair062a8672021-09-03 16:07:44 -070012990
Prabir Pradhan678438e2023-04-13 19:32:51 +000012991 mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_DOWN,
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -070012992 AINPUT_SOURCE_TOUCHSCREEN,
12993 ui::LogicalDisplayId::DEFAULT));
12994 window->consumeMotionDown(ui::LogicalDisplayId::DEFAULT,
12995 AMOTION_EVENT_FLAG_WINDOW_IS_PARTIALLY_OBSCURED);
Vishnu Nair062a8672021-09-03 16:07:44 -070012996 window->assertNoEvents();
12997}
12998
12999TEST_F(InputDispatcherDropInputFeatureTest, UnobscuredWindowGetsInput) {
13000 std::shared_ptr<FakeApplicationHandle> obscuringApplication =
13001 std::make_shared<FakeApplicationHandle>();
13002 sp<FakeWindowHandle> obscuringWindow =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -070013003 sp<FakeWindowHandle>::make(obscuringApplication, mDispatcher, "obscuringWindow",
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -070013004 ui::LogicalDisplayId::DEFAULT);
Vishnu Nair062a8672021-09-03 16:07:44 -070013005 obscuringWindow->setFrame(Rect(0, 0, 50, 50));
Prabir Pradhanaeebeb42023-06-13 19:53:03 +000013006 obscuringWindow->setOwnerInfo(gui::Pid{111}, gui::Uid{111});
Prabir Pradhan4d5c52f2022-01-31 08:52:10 -080013007 obscuringWindow->setTouchable(false);
Vishnu Nair062a8672021-09-03 16:07:44 -070013008 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -070013009 sp<FakeWindowHandle> window =
13010 sp<FakeWindowHandle>::make(application, mDispatcher, "Test window",
13011 ui::LogicalDisplayId::DEFAULT);
Prabir Pradhan51e7db02022-02-07 06:02:57 -080013012 window->setDropInputIfObscured(true);
Prabir Pradhanaeebeb42023-06-13 19:53:03 +000013013 window->setOwnerInfo(gui::Pid{222}, gui::Uid{222});
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -070013014 mDispatcher->setFocusedApplication(ui::LogicalDisplayId::DEFAULT, application);
Vishnu Nair062a8672021-09-03 16:07:44 -070013015 window->setFocusable(true);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070013016 mDispatcher->onWindowInfosChanged(
13017 {{*obscuringWindow->getInfo(), *window->getInfo()}, {}, 0, 0});
Vishnu Nair062a8672021-09-03 16:07:44 -070013018 setFocusedWindow(window);
Harry Cutts33476232023-01-30 19:57:29 +000013019 window->consumeFocusEvent(/*hasFocus=*/true, /*inTouchMode=*/true);
Vishnu Nair062a8672021-09-03 16:07:44 -070013020
13021 // With the flag set, window should not get any input
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -070013022 mDispatcher->notifyKey(generateKeyArgs(AKEY_EVENT_ACTION_DOWN, ui::LogicalDisplayId::DEFAULT));
Vishnu Nair062a8672021-09-03 16:07:44 -070013023 window->assertNoEvents();
13024
Prabir Pradhan678438e2023-04-13 19:32:51 +000013025 mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_DOWN,
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -070013026 AINPUT_SOURCE_TOUCHSCREEN,
13027 ui::LogicalDisplayId::DEFAULT));
Siarhei Vishniakou5c02a712023-05-15 15:45:02 -070013028 mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN,
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -070013029 ui::LogicalDisplayId::DEFAULT));
Vishnu Nair062a8672021-09-03 16:07:44 -070013030 window->assertNoEvents();
13031
13032 // When the window is no longer obscured because it went on top, it should get input
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070013033 mDispatcher->onWindowInfosChanged(
13034 {{*window->getInfo(), *obscuringWindow->getInfo()}, {}, 0, 0});
Vishnu Nair062a8672021-09-03 16:07:44 -070013035
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -070013036 mDispatcher->notifyKey(generateKeyArgs(AKEY_EVENT_ACTION_UP, ui::LogicalDisplayId::DEFAULT));
13037 window->consumeKeyUp(ui::LogicalDisplayId::DEFAULT);
Vishnu Nair062a8672021-09-03 16:07:44 -070013038
Prabir Pradhan678438e2023-04-13 19:32:51 +000013039 mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_DOWN,
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -070013040 AINPUT_SOURCE_TOUCHSCREEN,
13041 ui::LogicalDisplayId::DEFAULT));
13042 window->consumeMotionDown(ui::LogicalDisplayId::DEFAULT);
Vishnu Nair062a8672021-09-03 16:07:44 -070013043 window->assertNoEvents();
13044}
13045
Antonio Kantekf16f2832021-09-28 04:39:20 +000013046class InputDispatcherTouchModeChangedTests : public InputDispatcherTest {
13047protected:
13048 std::shared_ptr<FakeApplicationHandle> mApp;
Antonio Kantek15beb512022-06-13 22:35:41 +000013049 std::shared_ptr<FakeApplicationHandle> mSecondaryApp;
Antonio Kantekf16f2832021-09-28 04:39:20 +000013050 sp<FakeWindowHandle> mWindow;
13051 sp<FakeWindowHandle> mSecondWindow;
Antonio Kantek15beb512022-06-13 22:35:41 +000013052 sp<FakeWindowHandle> mThirdWindow;
Antonio Kantekf16f2832021-09-28 04:39:20 +000013053
13054 void SetUp() override {
13055 InputDispatcherTest::SetUp();
13056
13057 mApp = std::make_shared<FakeApplicationHandle>();
Antonio Kantek15beb512022-06-13 22:35:41 +000013058 mSecondaryApp = std::make_shared<FakeApplicationHandle>();
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -070013059 mWindow = sp<FakeWindowHandle>::make(mApp, mDispatcher, "TestWindow",
13060 ui::LogicalDisplayId::DEFAULT);
Antonio Kantekf16f2832021-09-28 04:39:20 +000013061 mWindow->setFocusable(true);
Antonio Kantek26defcf2022-02-08 01:12:27 +000013062 setFocusedWindow(mWindow);
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -070013063 mSecondWindow = sp<FakeWindowHandle>::make(mApp, mDispatcher, "TestWindow2",
13064 ui::LogicalDisplayId::DEFAULT);
Antonio Kantekf16f2832021-09-28 04:39:20 +000013065 mSecondWindow->setFocusable(true);
Antonio Kantek15beb512022-06-13 22:35:41 +000013066 mThirdWindow =
13067 sp<FakeWindowHandle>::make(mSecondaryApp, mDispatcher,
13068 "TestWindow3_SecondaryDisplay", SECOND_DISPLAY_ID);
13069 mThirdWindow->setFocusable(true);
Antonio Kantekf16f2832021-09-28 04:39:20 +000013070
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -070013071 mDispatcher->setFocusedApplication(ui::LogicalDisplayId::DEFAULT, mApp);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070013072 mDispatcher->onWindowInfosChanged(
13073 {{*mWindow->getInfo(), *mSecondWindow->getInfo(), *mThirdWindow->getInfo()},
13074 {},
13075 0,
13076 0});
Antonio Kantek15beb512022-06-13 22:35:41 +000013077 mThirdWindow->setOwnerInfo(SECONDARY_WINDOW_PID, SECONDARY_WINDOW_UID);
Antonio Kantekf16f2832021-09-28 04:39:20 +000013078 mWindow->consumeFocusEvent(true);
Antonio Kantek26defcf2022-02-08 01:12:27 +000013079
Antonio Kantek15beb512022-06-13 22:35:41 +000013080 // Set main display initial touch mode to InputDispatcher::kDefaultInTouchMode.
Prabir Pradhan5735a322022-04-11 17:23:34 +000013081 if (mDispatcher->setInTouchMode(InputDispatcher::kDefaultInTouchMode, WINDOW_PID,
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -070013082 WINDOW_UID, /*hasPermission=*/true,
13083 ui::LogicalDisplayId::DEFAULT)) {
Antonio Kantek48710e42022-03-24 14:19:30 -070013084 mWindow->consumeTouchModeEvent(InputDispatcher::kDefaultInTouchMode);
13085 mSecondWindow->consumeTouchModeEvent(InputDispatcher::kDefaultInTouchMode);
Antonio Kantek15beb512022-06-13 22:35:41 +000013086 mThirdWindow->assertNoEvents();
13087 }
13088
13089 // Set secondary display initial touch mode to InputDispatcher::kDefaultInTouchMode.
13090 if (mDispatcher->setInTouchMode(InputDispatcher::kDefaultInTouchMode, SECONDARY_WINDOW_PID,
Harry Cutts33476232023-01-30 19:57:29 +000013091 SECONDARY_WINDOW_UID, /*hasPermission=*/true,
Antonio Kantek15beb512022-06-13 22:35:41 +000013092 SECOND_DISPLAY_ID)) {
13093 mWindow->assertNoEvents();
13094 mSecondWindow->assertNoEvents();
13095 mThirdWindow->consumeTouchModeEvent(InputDispatcher::kDefaultInTouchMode);
Antonio Kantek48710e42022-03-24 14:19:30 -070013096 }
Antonio Kantekf16f2832021-09-28 04:39:20 +000013097 }
13098
Prabir Pradhanaeebeb42023-06-13 19:53:03 +000013099 void changeAndVerifyTouchModeInMainDisplayOnly(bool inTouchMode, gui::Pid pid, gui::Uid uid,
Antonio Kantek15beb512022-06-13 22:35:41 +000013100 bool hasPermission) {
Antonio Kanteka042c022022-07-06 16:51:07 -070013101 ASSERT_TRUE(mDispatcher->setInTouchMode(inTouchMode, pid, uid, hasPermission,
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -070013102 ui::LogicalDisplayId::DEFAULT));
Antonio Kantekf16f2832021-09-28 04:39:20 +000013103 mWindow->consumeTouchModeEvent(inTouchMode);
13104 mSecondWindow->consumeTouchModeEvent(inTouchMode);
Antonio Kantek15beb512022-06-13 22:35:41 +000013105 mThirdWindow->assertNoEvents();
Antonio Kantekf16f2832021-09-28 04:39:20 +000013106 }
13107};
13108
Antonio Kantek26defcf2022-02-08 01:12:27 +000013109TEST_F(InputDispatcherTouchModeChangedTests, FocusedWindowCanChangeTouchMode) {
Antonio Kantekea47acb2021-12-23 12:41:25 -080013110 const WindowInfo& windowInfo = *mWindow->getInfo();
Antonio Kantek15beb512022-06-13 22:35:41 +000013111 changeAndVerifyTouchModeInMainDisplayOnly(!InputDispatcher::kDefaultInTouchMode,
13112 windowInfo.ownerPid, windowInfo.ownerUid,
Harry Cutts33476232023-01-30 19:57:29 +000013113 /* hasPermission=*/false);
Antonio Kantekf16f2832021-09-28 04:39:20 +000013114}
13115
Antonio Kantek26defcf2022-02-08 01:12:27 +000013116TEST_F(InputDispatcherTouchModeChangedTests, NonFocusedWindowOwnerCannotChangeTouchMode) {
13117 const WindowInfo& windowInfo = *mWindow->getInfo();
Prabir Pradhanaeebeb42023-06-13 19:53:03 +000013118 gui::Pid ownerPid = windowInfo.ownerPid;
Prabir Pradhan8a5c41d2023-06-08 19:13:46 +000013119 gui::Uid ownerUid = windowInfo.ownerUid;
Prabir Pradhanaeebeb42023-06-13 19:53:03 +000013120 mWindow->setOwnerInfo(gui::Pid::INVALID, gui::Uid::INVALID);
Antonio Kantek26defcf2022-02-08 01:12:27 +000013121 ASSERT_FALSE(mDispatcher->setInTouchMode(InputDispatcher::kDefaultInTouchMode, ownerPid,
Harry Cutts33476232023-01-30 19:57:29 +000013122 ownerUid, /*hasPermission=*/false,
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -070013123 ui::LogicalDisplayId::DEFAULT));
Antonio Kantek26defcf2022-02-08 01:12:27 +000013124 mWindow->assertNoEvents();
13125 mSecondWindow->assertNoEvents();
13126}
13127
13128TEST_F(InputDispatcherTouchModeChangedTests, NonWindowOwnerMayChangeTouchModeOnPermissionGranted) {
13129 const WindowInfo& windowInfo = *mWindow->getInfo();
Prabir Pradhanaeebeb42023-06-13 19:53:03 +000013130 gui::Pid ownerPid = windowInfo.ownerPid;
Prabir Pradhan8a5c41d2023-06-08 19:13:46 +000013131 gui::Uid ownerUid = windowInfo.ownerUid;
Prabir Pradhanaeebeb42023-06-13 19:53:03 +000013132 mWindow->setOwnerInfo(gui::Pid::INVALID, gui::Uid::INVALID);
Antonio Kantek15beb512022-06-13 22:35:41 +000013133 changeAndVerifyTouchModeInMainDisplayOnly(!InputDispatcher::kDefaultInTouchMode, ownerPid,
Harry Cutts33476232023-01-30 19:57:29 +000013134 ownerUid, /*hasPermission=*/true);
Antonio Kantek26defcf2022-02-08 01:12:27 +000013135}
13136
Antonio Kantekf16f2832021-09-28 04:39:20 +000013137TEST_F(InputDispatcherTouchModeChangedTests, EventIsNotGeneratedIfNotChangingTouchMode) {
Antonio Kantekea47acb2021-12-23 12:41:25 -080013138 const WindowInfo& windowInfo = *mWindow->getInfo();
Antonio Kantek26defcf2022-02-08 01:12:27 +000013139 ASSERT_FALSE(mDispatcher->setInTouchMode(InputDispatcher::kDefaultInTouchMode,
13140 windowInfo.ownerPid, windowInfo.ownerUid,
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -070013141 /*hasPermission=*/true,
13142 ui::LogicalDisplayId::DEFAULT));
Antonio Kantekf16f2832021-09-28 04:39:20 +000013143 mWindow->assertNoEvents();
13144 mSecondWindow->assertNoEvents();
13145}
13146
Antonio Kantek15beb512022-06-13 22:35:41 +000013147TEST_F(InputDispatcherTouchModeChangedTests, ChangeTouchOnSecondaryDisplayOnly) {
13148 const WindowInfo& windowInfo = *mThirdWindow->getInfo();
13149 ASSERT_TRUE(mDispatcher->setInTouchMode(!InputDispatcher::kDefaultInTouchMode,
13150 windowInfo.ownerPid, windowInfo.ownerUid,
Harry Cutts33476232023-01-30 19:57:29 +000013151 /*hasPermission=*/true, SECOND_DISPLAY_ID));
Antonio Kantek15beb512022-06-13 22:35:41 +000013152 mWindow->assertNoEvents();
13153 mSecondWindow->assertNoEvents();
13154 mThirdWindow->consumeTouchModeEvent(!InputDispatcher::kDefaultInTouchMode);
13155}
13156
Antonio Kantek48710e42022-03-24 14:19:30 -070013157TEST_F(InputDispatcherTouchModeChangedTests, CanChangeTouchModeWhenOwningLastInteractedWindow) {
13158 // Interact with the window first.
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070013159 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -070013160 injectKeyDown(*mDispatcher, ui::LogicalDisplayId::DEFAULT))
Antonio Kantek48710e42022-03-24 14:19:30 -070013161 << "Inject key event should return InputEventInjectionResult::SUCCEEDED";
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -070013162 mWindow->consumeKeyDown(ui::LogicalDisplayId::DEFAULT);
Antonio Kantek48710e42022-03-24 14:19:30 -070013163
13164 // Then remove focus.
13165 mWindow->setFocusable(false);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070013166 mDispatcher->onWindowInfosChanged({{*mWindow->getInfo()}, {}, 0, 0});
Antonio Kantek48710e42022-03-24 14:19:30 -070013167
13168 // Assert that caller can switch touch mode by owning one of the last interacted window.
13169 const WindowInfo& windowInfo = *mWindow->getInfo();
13170 ASSERT_TRUE(mDispatcher->setInTouchMode(!InputDispatcher::kDefaultInTouchMode,
13171 windowInfo.ownerPid, windowInfo.ownerUid,
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -070013172 /*hasPermission=*/false,
13173 ui::LogicalDisplayId::DEFAULT));
Antonio Kantek48710e42022-03-24 14:19:30 -070013174}
13175
Prabir Pradhan07e05b62021-11-19 03:57:24 -080013176class InputDispatcherSpyWindowTest : public InputDispatcherTest {
13177public:
Prabir Pradhan4d5c52f2022-01-31 08:52:10 -080013178 sp<FakeWindowHandle> createSpy() {
Prabir Pradhan07e05b62021-11-19 03:57:24 -080013179 std::shared_ptr<FakeApplicationHandle> application =
13180 std::make_shared<FakeApplicationHandle>();
13181 std::string name = "Fake Spy ";
13182 name += std::to_string(mSpyCount++);
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -070013183 sp<FakeWindowHandle> spy =
13184 sp<FakeWindowHandle>::make(application, mDispatcher, name.c_str(),
13185 ui::LogicalDisplayId::DEFAULT);
Prabir Pradhan51e7db02022-02-07 06:02:57 -080013186 spy->setSpy(true);
Prabir Pradhan5c85e052021-12-22 02:27:12 -080013187 spy->setTrustedOverlay(true);
Prabir Pradhan07e05b62021-11-19 03:57:24 -080013188 return spy;
13189 }
13190
13191 sp<FakeWindowHandle> createForeground() {
13192 std::shared_ptr<FakeApplicationHandle> application =
13193 std::make_shared<FakeApplicationHandle>();
13194 sp<FakeWindowHandle> window =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -070013195 sp<FakeWindowHandle>::make(application, mDispatcher, "Fake Window",
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -070013196 ui::LogicalDisplayId::DEFAULT);
Prabir Pradhan1376fcd2022-01-21 09:56:35 -080013197 window->setFocusable(true);
Prabir Pradhan07e05b62021-11-19 03:57:24 -080013198 return window;
13199 }
13200
13201private:
13202 int mSpyCount{0};
13203};
13204
Prabir Pradhana3ab87a2022-01-27 10:00:21 -080013205using InputDispatcherSpyWindowDeathTest = InputDispatcherSpyWindowTest;
Prabir Pradhan07e05b62021-11-19 03:57:24 -080013206/**
Prabir Pradhan5c85e052021-12-22 02:27:12 -080013207 * Adding a spy window that is not a trusted overlay causes Dispatcher to abort.
13208 */
Prabir Pradhana3ab87a2022-01-27 10:00:21 -080013209TEST_F(InputDispatcherSpyWindowDeathTest, UntrustedSpy_AbortsDispatcher) {
Siarhei Vishniakou21f77bd2023-07-18 17:51:35 -070013210 testing::GTEST_FLAG(death_test_style) = "threadsafe";
Prabir Pradhana3ab87a2022-01-27 10:00:21 -080013211 ScopedSilentDeath _silentDeath;
13212
Prabir Pradhan4d5c52f2022-01-31 08:52:10 -080013213 auto spy = createSpy();
Prabir Pradhan5c85e052021-12-22 02:27:12 -080013214 spy->setTrustedOverlay(false);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070013215 ASSERT_DEATH(mDispatcher->onWindowInfosChanged({{*spy->getInfo()}, {}, 0, 0}),
Prabir Pradhan5c85e052021-12-22 02:27:12 -080013216 ".* not a trusted overlay");
13217}
13218
13219/**
Prabir Pradhan07e05b62021-11-19 03:57:24 -080013220 * Input injection into a display with a spy window but no foreground windows should succeed.
13221 */
13222TEST_F(InputDispatcherSpyWindowTest, NoForegroundWindow) {
Prabir Pradhan4d5c52f2022-01-31 08:52:10 -080013223 auto spy = createSpy();
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070013224 mDispatcher->onWindowInfosChanged({{*spy->getInfo()}, {}, 0, 0});
Prabir Pradhan07e05b62021-11-19 03:57:24 -080013225
13226 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -070013227 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN,
13228 ui::LogicalDisplayId::DEFAULT))
Prabir Pradhan07e05b62021-11-19 03:57:24 -080013229 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -070013230 spy->consumeMotionDown(ui::LogicalDisplayId::DEFAULT);
Prabir Pradhan07e05b62021-11-19 03:57:24 -080013231}
13232
13233/**
13234 * Verify the order in which different input windows receive events. The touched foreground window
13235 * (if there is one) should always receive the event first. When there are multiple spy windows, the
13236 * spy windows will receive the event according to their Z-order, where the top-most spy window will
13237 * receive events before ones belows it.
13238 *
13239 * Here, we set up a scenario with four windows in the following Z order from the top:
13240 * spy1, spy2, window, spy3.
13241 * We then inject an event and verify that the foreground "window" receives it first, followed by
13242 * "spy1" and "spy2". The "spy3" does not receive the event because it is underneath the foreground
13243 * window.
13244 */
13245TEST_F(InputDispatcherSpyWindowTest, ReceivesInputInOrder) {
13246 auto window = createForeground();
Prabir Pradhan4d5c52f2022-01-31 08:52:10 -080013247 auto spy1 = createSpy();
13248 auto spy2 = createSpy();
13249 auto spy3 = createSpy();
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070013250 mDispatcher->onWindowInfosChanged(
13251 {{*spy1->getInfo(), *spy2->getInfo(), *window->getInfo(), *spy3->getInfo()}, {}, 0, 0});
Prabir Pradhan07e05b62021-11-19 03:57:24 -080013252 const std::vector<sp<FakeWindowHandle>> channels{spy1, spy2, window, spy3};
13253 const size_t numChannels = channels.size();
13254
Michael Wright8e9a8562022-02-09 13:44:29 +000013255 base::unique_fd epollFd(epoll_create1(EPOLL_CLOEXEC));
Prabir Pradhan07e05b62021-11-19 03:57:24 -080013256 if (!epollFd.ok()) {
13257 FAIL() << "Failed to create epoll fd";
13258 }
13259
13260 for (size_t i = 0; i < numChannels; i++) {
13261 struct epoll_event event = {.events = EPOLLIN, .data.u64 = i};
13262 if (epoll_ctl(epollFd.get(), EPOLL_CTL_ADD, channels[i]->getChannelFd(), &event) < 0) {
13263 FAIL() << "Failed to add fd to epoll";
13264 }
13265 }
13266
13267 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -070013268 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN,
13269 ui::LogicalDisplayId::DEFAULT))
Prabir Pradhan07e05b62021-11-19 03:57:24 -080013270 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
13271
13272 std::vector<size_t> eventOrder;
13273 std::vector<struct epoll_event> events(numChannels);
13274 for (;;) {
13275 const int nFds = epoll_wait(epollFd.get(), events.data(), static_cast<int>(numChannels),
13276 (100ms).count());
13277 if (nFds < 0) {
13278 FAIL() << "Failed to call epoll_wait";
13279 }
13280 if (nFds == 0) {
13281 break; // epoll_wait timed out
13282 }
13283 for (int i = 0; i < nFds; i++) {
Colin Cross5b799302022-10-18 21:52:41 -070013284 ASSERT_EQ(static_cast<uint32_t>(EPOLLIN), events[i].events);
Siarhei Vishniakou31977182022-09-30 08:51:23 -070013285 eventOrder.push_back(static_cast<size_t>(events[i].data.u64));
Prabir Pradhan07e05b62021-11-19 03:57:24 -080013286 channels[i]->consumeMotionDown();
13287 }
13288 }
13289
13290 // Verify the order in which the events were received.
13291 EXPECT_EQ(3u, eventOrder.size());
13292 EXPECT_EQ(2u, eventOrder[0]); // index 2: window
13293 EXPECT_EQ(0u, eventOrder[1]); // index 0: spy1
13294 EXPECT_EQ(1u, eventOrder[2]); // index 1: spy2
13295}
13296
13297/**
13298 * A spy window using the NOT_TOUCHABLE flag does not receive events.
13299 */
13300TEST_F(InputDispatcherSpyWindowTest, NotTouchable) {
13301 auto window = createForeground();
Prabir Pradhan4d5c52f2022-01-31 08:52:10 -080013302 auto spy = createSpy();
13303 spy->setTouchable(false);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070013304 mDispatcher->onWindowInfosChanged({{*spy->getInfo(), *window->getInfo()}, {}, 0, 0});
Prabir Pradhan07e05b62021-11-19 03:57:24 -080013305
13306 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -070013307 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN,
13308 ui::LogicalDisplayId::DEFAULT))
Prabir Pradhan07e05b62021-11-19 03:57:24 -080013309 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -070013310 window->consumeMotionDown(ui::LogicalDisplayId::DEFAULT);
Prabir Pradhan07e05b62021-11-19 03:57:24 -080013311 spy->assertNoEvents();
13312}
13313
13314/**
13315 * A spy window will only receive gestures that originate within its touchable region. Gestures that
13316 * have their ACTION_DOWN outside of the touchable region of the spy window will not be dispatched
13317 * to the window.
13318 */
13319TEST_F(InputDispatcherSpyWindowTest, TouchableRegion) {
13320 auto window = createForeground();
Prabir Pradhan4d5c52f2022-01-31 08:52:10 -080013321 auto spy = createSpy();
Prabir Pradhan07e05b62021-11-19 03:57:24 -080013322 spy->setTouchableRegion(Region{{0, 0, 20, 20}});
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070013323 mDispatcher->onWindowInfosChanged({{*spy->getInfo(), *window->getInfo()}, {}, 0, 0});
Prabir Pradhan07e05b62021-11-19 03:57:24 -080013324
13325 // Inject an event outside the spy window's touchable region.
13326 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -070013327 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN,
13328 ui::LogicalDisplayId::DEFAULT))
Prabir Pradhan07e05b62021-11-19 03:57:24 -080013329 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
13330 window->consumeMotionDown();
13331 spy->assertNoEvents();
13332 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -070013333 injectMotionUp(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN,
13334 ui::LogicalDisplayId::DEFAULT))
Prabir Pradhan07e05b62021-11-19 03:57:24 -080013335 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
13336 window->consumeMotionUp();
13337 spy->assertNoEvents();
13338
13339 // Inject an event inside the spy window's touchable region.
13340 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -070013341 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN,
13342 ui::LogicalDisplayId::DEFAULT, {5, 10}))
Prabir Pradhan07e05b62021-11-19 03:57:24 -080013343 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
13344 window->consumeMotionDown();
13345 spy->consumeMotionDown();
13346}
13347
13348/**
Prabir Pradhan07e05b62021-11-19 03:57:24 -080013349 * A spy window can listen for touches outside its touchable region using the WATCH_OUTSIDE_TOUCHES
Prabir Pradhandfabf8a2022-01-21 08:19:30 -080013350 * flag, but it will get zero-ed out coordinates if the foreground has a different owner.
Prabir Pradhan07e05b62021-11-19 03:57:24 -080013351 */
13352TEST_F(InputDispatcherSpyWindowTest, WatchOutsideTouches) {
13353 auto window = createForeground();
Prabir Pradhanaeebeb42023-06-13 19:53:03 +000013354 window->setOwnerInfo(gui::Pid{12}, gui::Uid{34});
Prabir Pradhan4d5c52f2022-01-31 08:52:10 -080013355 auto spy = createSpy();
13356 spy->setWatchOutsideTouch(true);
Prabir Pradhanaeebeb42023-06-13 19:53:03 +000013357 spy->setOwnerInfo(gui::Pid{56}, gui::Uid{78});
Prabir Pradhan07e05b62021-11-19 03:57:24 -080013358 spy->setFrame(Rect{0, 0, 20, 20});
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070013359 mDispatcher->onWindowInfosChanged({{*spy->getInfo(), *window->getInfo()}, {}, 0, 0});
Prabir Pradhan07e05b62021-11-19 03:57:24 -080013360
13361 // Inject an event outside the spy window's frame and touchable region.
13362 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -070013363 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN,
13364 ui::LogicalDisplayId::DEFAULT, {100, 200}))
Prabir Pradhan07e05b62021-11-19 03:57:24 -080013365 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
13366 window->consumeMotionDown();
Prabir Pradhandfabf8a2022-01-21 08:19:30 -080013367 spy->consumeMotionOutsideWithZeroedCoords();
Prabir Pradhan07e05b62021-11-19 03:57:24 -080013368}
13369
13370/**
Prabir Pradhan07e05b62021-11-19 03:57:24 -080013371 * Even when a spy window spans over multiple foreground windows, the spy should receive all
13372 * pointers that are down within its bounds.
13373 */
13374TEST_F(InputDispatcherSpyWindowTest, ReceivesMultiplePointers) {
13375 auto windowLeft = createForeground();
13376 windowLeft->setFrame({0, 0, 100, 200});
13377 auto windowRight = createForeground();
13378 windowRight->setFrame({100, 0, 200, 200});
Prabir Pradhan4d5c52f2022-01-31 08:52:10 -080013379 auto spy = createSpy();
Prabir Pradhan07e05b62021-11-19 03:57:24 -080013380 spy->setFrame({0, 0, 200, 200});
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070013381 mDispatcher->onWindowInfosChanged(
13382 {{*spy->getInfo(), *windowLeft->getInfo(), *windowRight->getInfo()}, {}, 0, 0});
Prabir Pradhan07e05b62021-11-19 03:57:24 -080013383
13384 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -070013385 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN,
13386 ui::LogicalDisplayId::DEFAULT, {50, 50}))
Prabir Pradhan07e05b62021-11-19 03:57:24 -080013387 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
13388 windowLeft->consumeMotionDown();
13389 spy->consumeMotionDown();
13390
13391 const MotionEvent secondFingerDownEvent =
Siarhei Vishniakoua16e3a22022-03-02 15:26:40 -080013392 MotionEventBuilder(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
Prabir Pradhan07e05b62021-11-19 03:57:24 -080013393 .eventTime(systemTime(SYSTEM_TIME_MONOTONIC))
Siarhei Vishniakou6d73f832022-07-21 17:27:03 -070013394 .pointer(PointerBuilder(/*id=*/0, ToolType::FINGER).x(50).y(50))
13395 .pointer(PointerBuilder(/*id=*/1, ToolType::FINGER).x(150).y(50))
Prabir Pradhan07e05b62021-11-19 03:57:24 -080013396 .build();
13397 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070013398 injectMotionEvent(*mDispatcher, secondFingerDownEvent, INJECT_EVENT_TIMEOUT,
Prabir Pradhan07e05b62021-11-19 03:57:24 -080013399 InputEventInjectionSync::WAIT_FOR_RESULT))
13400 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
13401 windowRight->consumeMotionDown();
Harry Cutts33476232023-01-30 19:57:29 +000013402 spy->consumeMotionPointerDown(/*pointerIndex=*/1);
Prabir Pradhan07e05b62021-11-19 03:57:24 -080013403}
13404
13405/**
13406 * When the first pointer lands outside the spy window and the second pointer lands inside it, the
13407 * the spy should receive the second pointer with ACTION_DOWN.
13408 */
13409TEST_F(InputDispatcherSpyWindowTest, ReceivesSecondPointerAsDown) {
13410 auto window = createForeground();
13411 window->setFrame({0, 0, 200, 200});
Prabir Pradhan4d5c52f2022-01-31 08:52:10 -080013412 auto spyRight = createSpy();
Prabir Pradhan07e05b62021-11-19 03:57:24 -080013413 spyRight->setFrame({100, 0, 200, 200});
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070013414 mDispatcher->onWindowInfosChanged({{*spyRight->getInfo(), *window->getInfo()}, {}, 0, 0});
Prabir Pradhan07e05b62021-11-19 03:57:24 -080013415
13416 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -070013417 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN,
13418 ui::LogicalDisplayId::DEFAULT, {50, 50}))
Prabir Pradhan07e05b62021-11-19 03:57:24 -080013419 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
13420 window->consumeMotionDown();
13421 spyRight->assertNoEvents();
13422
13423 const MotionEvent secondFingerDownEvent =
Siarhei Vishniakoua16e3a22022-03-02 15:26:40 -080013424 MotionEventBuilder(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
Prabir Pradhan07e05b62021-11-19 03:57:24 -080013425 .eventTime(systemTime(SYSTEM_TIME_MONOTONIC))
Siarhei Vishniakou6d73f832022-07-21 17:27:03 -070013426 .pointer(PointerBuilder(/*id=*/0, ToolType::FINGER).x(50).y(50))
13427 .pointer(PointerBuilder(/*id=*/1, ToolType::FINGER).x(150).y(50))
Prabir Pradhan07e05b62021-11-19 03:57:24 -080013428 .build();
13429 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070013430 injectMotionEvent(*mDispatcher, secondFingerDownEvent, INJECT_EVENT_TIMEOUT,
Prabir Pradhan07e05b62021-11-19 03:57:24 -080013431 InputEventInjectionSync::WAIT_FOR_RESULT))
13432 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
Harry Cutts33476232023-01-30 19:57:29 +000013433 window->consumeMotionPointerDown(/*pointerIndex=*/1);
Prabir Pradhan07e05b62021-11-19 03:57:24 -080013434 spyRight->consumeMotionDown();
13435}
13436
Prabir Pradhan1376fcd2022-01-21 09:56:35 -080013437/**
13438 * The spy window should not be able to affect whether or not touches are split. Only the foreground
13439 * windows should be allowed to control split touch.
13440 */
13441TEST_F(InputDispatcherSpyWindowTest, SplitIfNoForegroundWindowTouched) {
Prabir Pradhan76bdecb2022-01-31 11:14:15 -080013442 // This spy window prevents touch splitting. However, we still expect to split touches
Prabir Pradhan1376fcd2022-01-21 09:56:35 -080013443 // because a foreground window has not disabled splitting.
Prabir Pradhan4d5c52f2022-01-31 08:52:10 -080013444 auto spy = createSpy();
Prabir Pradhan76bdecb2022-01-31 11:14:15 -080013445 spy->setPreventSplitting(true);
Prabir Pradhan1376fcd2022-01-21 09:56:35 -080013446
Prabir Pradhan1376fcd2022-01-21 09:56:35 -080013447 auto window = createForeground();
13448 window->setFrame(Rect(0, 0, 100, 100));
Prabir Pradhan1376fcd2022-01-21 09:56:35 -080013449
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070013450 mDispatcher->onWindowInfosChanged({{*spy->getInfo(), *window->getInfo()}, {}, 0, 0});
Prabir Pradhan1376fcd2022-01-21 09:56:35 -080013451
13452 // First finger down, no window touched.
13453 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -070013454 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN,
13455 ui::LogicalDisplayId::DEFAULT, {100, 200}))
Prabir Pradhan1376fcd2022-01-21 09:56:35 -080013456 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -070013457 spy->consumeMotionDown(ui::LogicalDisplayId::DEFAULT);
Prabir Pradhan1376fcd2022-01-21 09:56:35 -080013458 window->assertNoEvents();
13459
13460 // Second finger down on window, the window should receive touch down.
13461 const MotionEvent secondFingerDownEvent =
Siarhei Vishniakoua16e3a22022-03-02 15:26:40 -080013462 MotionEventBuilder(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -070013463 .displayId(ui::LogicalDisplayId::DEFAULT)
Prabir Pradhan1376fcd2022-01-21 09:56:35 -080013464 .eventTime(systemTime(SYSTEM_TIME_MONOTONIC))
Siarhei Vishniakou6d73f832022-07-21 17:27:03 -070013465 .pointer(PointerBuilder(/*id=*/0, ToolType::FINGER).x(100).y(200))
13466 .pointer(PointerBuilder(/*id=*/1, ToolType::FINGER).x(50).y(50))
Prabir Pradhan1376fcd2022-01-21 09:56:35 -080013467 .build();
13468 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070013469 injectMotionEvent(*mDispatcher, secondFingerDownEvent, INJECT_EVENT_TIMEOUT,
Prabir Pradhan1376fcd2022-01-21 09:56:35 -080013470 InputEventInjectionSync::WAIT_FOR_RESULT))
13471 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
13472
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -070013473 window->consumeMotionDown(ui::LogicalDisplayId::DEFAULT);
Harry Cutts33476232023-01-30 19:57:29 +000013474 spy->consumeMotionPointerDown(/*pointerIndex=*/1);
Prabir Pradhan1376fcd2022-01-21 09:56:35 -080013475}
13476
13477/**
13478 * A spy window will usually be implemented as an un-focusable window. Verify that these windows
13479 * do not receive key events.
13480 */
13481TEST_F(InputDispatcherSpyWindowTest, UnfocusableSpyDoesNotReceiveKeyEvents) {
Prabir Pradhan4d5c52f2022-01-31 08:52:10 -080013482 auto spy = createSpy();
Prabir Pradhan1376fcd2022-01-21 09:56:35 -080013483 spy->setFocusable(false);
13484
13485 auto window = createForeground();
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070013486 mDispatcher->onWindowInfosChanged({{*spy->getInfo(), *window->getInfo()}, {}, 0, 0});
Prabir Pradhan1376fcd2022-01-21 09:56:35 -080013487 setFocusedWindow(window);
13488 window->consumeFocusEvent(true);
13489
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070013490 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectKeyDown(*mDispatcher))
Prabir Pradhan1376fcd2022-01-21 09:56:35 -080013491 << "Inject key event should return InputEventInjectionResult::SUCCEEDED";
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -070013492 window->consumeKeyDown(ui::LogicalDisplayId::INVALID);
Prabir Pradhan1376fcd2022-01-21 09:56:35 -080013493
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070013494 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectKeyUp(*mDispatcher))
Prabir Pradhan1376fcd2022-01-21 09:56:35 -080013495 << "Inject key event should return InputEventInjectionResult::SUCCEEDED";
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -070013496 window->consumeKeyUp(ui::LogicalDisplayId::INVALID);
Prabir Pradhan1376fcd2022-01-21 09:56:35 -080013497
13498 spy->assertNoEvents();
13499}
13500
Vaibhav Devmurariff798f32022-05-09 23:45:04 +000013501using InputDispatcherPilferPointersTest = InputDispatcherSpyWindowTest;
13502
13503/**
13504 * A spy window can pilfer pointers. When this happens, touch gestures used by the spy window that
13505 * are currently sent to any other windows - including other spy windows - will also be cancelled.
13506 */
13507TEST_F(InputDispatcherPilferPointersTest, PilferPointers) {
13508 auto window = createForeground();
13509 auto spy1 = createSpy();
13510 auto spy2 = createSpy();
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070013511 mDispatcher->onWindowInfosChanged(
13512 {{*spy1->getInfo(), *spy2->getInfo(), *window->getInfo()}, {}, 0, 0});
Vaibhav Devmurariff798f32022-05-09 23:45:04 +000013513
13514 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -070013515 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN,
13516 ui::LogicalDisplayId::DEFAULT))
Vaibhav Devmurariff798f32022-05-09 23:45:04 +000013517 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
13518 window->consumeMotionDown();
13519 spy1->consumeMotionDown();
13520 spy2->consumeMotionDown();
13521
13522 // Pilfer pointers from the second spy window.
13523 EXPECT_EQ(OK, mDispatcher->pilferPointers(spy2->getToken()));
13524 spy2->assertNoEvents();
13525 spy1->consumeMotionCancel();
13526 window->consumeMotionCancel();
13527
13528 // The rest of the gesture should only be sent to the second spy window.
13529 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070013530 injectMotionEvent(*mDispatcher, AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN,
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -070013531 ui::LogicalDisplayId::DEFAULT))
Vaibhav Devmurariff798f32022-05-09 23:45:04 +000013532 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
13533 spy2->consumeMotionMove();
13534 spy1->assertNoEvents();
13535 window->assertNoEvents();
13536}
13537
13538/**
13539 * A spy window can pilfer pointers for a gesture even after the foreground window has been removed
13540 * in the middle of the gesture.
13541 */
13542TEST_F(InputDispatcherPilferPointersTest, CanPilferAfterWindowIsRemovedMidStream) {
13543 auto window = createForeground();
13544 auto spy = createSpy();
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070013545 mDispatcher->onWindowInfosChanged({{*spy->getInfo(), *window->getInfo()}, {}, 0, 0});
Vaibhav Devmurariff798f32022-05-09 23:45:04 +000013546
13547 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -070013548 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN,
13549 ui::LogicalDisplayId::DEFAULT))
Vaibhav Devmurariff798f32022-05-09 23:45:04 +000013550 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -070013551 window->consumeMotionDown(ui::LogicalDisplayId::DEFAULT);
13552 spy->consumeMotionDown(ui::LogicalDisplayId::DEFAULT);
Vaibhav Devmurariff798f32022-05-09 23:45:04 +000013553
13554 window->releaseChannel();
13555
13556 EXPECT_EQ(OK, mDispatcher->pilferPointers(spy->getToken()));
13557
13558 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -070013559 injectMotionUp(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN,
13560 ui::LogicalDisplayId::DEFAULT))
Vaibhav Devmurariff798f32022-05-09 23:45:04 +000013561 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -070013562 spy->consumeMotionUp(ui::LogicalDisplayId::DEFAULT);
Vaibhav Devmurariff798f32022-05-09 23:45:04 +000013563}
13564
13565/**
13566 * After a spy window pilfers pointers, new pointers that go down in its bounds should be sent to
13567 * the spy, but not to any other windows.
13568 */
13569TEST_F(InputDispatcherPilferPointersTest, ContinuesToReceiveGestureAfterPilfer) {
13570 auto spy = createSpy();
13571 auto window = createForeground();
13572
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070013573 mDispatcher->onWindowInfosChanged({{*spy->getInfo(), *window->getInfo()}, {}, 0, 0});
Vaibhav Devmurariff798f32022-05-09 23:45:04 +000013574
13575 // First finger down on the window and the spy.
13576 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -070013577 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN,
13578 ui::LogicalDisplayId::DEFAULT, {100, 200}))
Vaibhav Devmurariff798f32022-05-09 23:45:04 +000013579 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
13580 spy->consumeMotionDown();
13581 window->consumeMotionDown();
13582
13583 // Spy window pilfers the pointers.
13584 EXPECT_EQ(OK, mDispatcher->pilferPointers(spy->getToken()));
13585 window->consumeMotionCancel();
13586
13587 // Second finger down on the window and spy, but the window should not receive the pointer down.
13588 const MotionEvent secondFingerDownEvent =
13589 MotionEventBuilder(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -070013590 .displayId(ui::LogicalDisplayId::DEFAULT)
Vaibhav Devmurariff798f32022-05-09 23:45:04 +000013591 .eventTime(systemTime(SYSTEM_TIME_MONOTONIC))
Siarhei Vishniakou6d73f832022-07-21 17:27:03 -070013592 .pointer(PointerBuilder(/*id=*/0, ToolType::FINGER).x(100).y(200))
13593 .pointer(PointerBuilder(/*id=*/1, ToolType::FINGER).x(50).y(50))
Vaibhav Devmurariff798f32022-05-09 23:45:04 +000013594 .build();
13595 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070013596 injectMotionEvent(*mDispatcher, secondFingerDownEvent, INJECT_EVENT_TIMEOUT,
Vaibhav Devmurariff798f32022-05-09 23:45:04 +000013597 InputEventInjectionSync::WAIT_FOR_RESULT))
13598 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
13599
Harry Cutts33476232023-01-30 19:57:29 +000013600 spy->consumeMotionPointerDown(/*pointerIndex=*/1);
Vaibhav Devmurariff798f32022-05-09 23:45:04 +000013601
13602 // Third finger goes down outside all windows, so injection should fail.
13603 const MotionEvent thirdFingerDownEvent =
13604 MotionEventBuilder(POINTER_2_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -070013605 .displayId(ui::LogicalDisplayId::DEFAULT)
Vaibhav Devmurariff798f32022-05-09 23:45:04 +000013606 .eventTime(systemTime(SYSTEM_TIME_MONOTONIC))
Siarhei Vishniakou6d73f832022-07-21 17:27:03 -070013607 .pointer(PointerBuilder(/*id=*/0, ToolType::FINGER).x(100).y(200))
13608 .pointer(PointerBuilder(/*id=*/1, ToolType::FINGER).x(50).y(50))
13609 .pointer(PointerBuilder(/*id=*/2, ToolType::FINGER).x(-5).y(-5))
Vaibhav Devmurariff798f32022-05-09 23:45:04 +000013610 .build();
13611 ASSERT_EQ(InputEventInjectionResult::FAILED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070013612 injectMotionEvent(*mDispatcher, thirdFingerDownEvent, INJECT_EVENT_TIMEOUT,
Vaibhav Devmurariff798f32022-05-09 23:45:04 +000013613 InputEventInjectionSync::WAIT_FOR_RESULT))
Siarhei Vishniakou1ae72f12023-01-29 12:55:30 -080013614 << "Inject motion event should return InputEventInjectionResult::FAILED";
Vaibhav Devmurariff798f32022-05-09 23:45:04 +000013615
13616 spy->assertNoEvents();
13617 window->assertNoEvents();
13618}
13619
13620/**
13621 * After a spy window pilfers pointers, only the pointers used by the spy should be canceled
13622 */
13623TEST_F(InputDispatcherPilferPointersTest, PartiallyPilferRequiredPointers) {
13624 auto spy = createSpy();
13625 spy->setFrame(Rect(0, 0, 100, 100));
13626 auto window = createForeground();
13627 window->setFrame(Rect(0, 0, 200, 200));
13628
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070013629 mDispatcher->onWindowInfosChanged({{*spy->getInfo(), *window->getInfo()}, {}, 0, 0});
Vaibhav Devmurariff798f32022-05-09 23:45:04 +000013630
13631 // First finger down on the window only
13632 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -070013633 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN,
13634 ui::LogicalDisplayId::DEFAULT, {150, 150}))
Vaibhav Devmurariff798f32022-05-09 23:45:04 +000013635 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
13636 window->consumeMotionDown();
13637
13638 // Second finger down on the spy and window
13639 const MotionEvent secondFingerDownEvent =
13640 MotionEventBuilder(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -070013641 .displayId(ui::LogicalDisplayId::DEFAULT)
Vaibhav Devmurariff798f32022-05-09 23:45:04 +000013642 .eventTime(systemTime(SYSTEM_TIME_MONOTONIC))
Siarhei Vishniakou6d73f832022-07-21 17:27:03 -070013643 .pointer(PointerBuilder(/*id=*/0, ToolType::FINGER).x(150).y(150))
13644 .pointer(PointerBuilder(/*id=*/1, ToolType::FINGER).x(10).y(10))
Vaibhav Devmurariff798f32022-05-09 23:45:04 +000013645 .build();
13646 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070013647 injectMotionEvent(*mDispatcher, secondFingerDownEvent, INJECT_EVENT_TIMEOUT,
Vaibhav Devmurariff798f32022-05-09 23:45:04 +000013648 InputEventInjectionSync::WAIT_FOR_RESULT))
13649 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
13650 spy->consumeMotionDown();
13651 window->consumeMotionPointerDown(1);
13652
13653 // Third finger down on the spy and window
13654 const MotionEvent thirdFingerDownEvent =
13655 MotionEventBuilder(POINTER_2_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -070013656 .displayId(ui::LogicalDisplayId::DEFAULT)
Vaibhav Devmurariff798f32022-05-09 23:45:04 +000013657 .eventTime(systemTime(SYSTEM_TIME_MONOTONIC))
Siarhei Vishniakou6d73f832022-07-21 17:27:03 -070013658 .pointer(PointerBuilder(/*id=*/0, ToolType::FINGER).x(150).y(150))
13659 .pointer(PointerBuilder(/*id=*/1, ToolType::FINGER).x(10).y(10))
13660 .pointer(PointerBuilder(/*id=*/2, ToolType::FINGER).x(50).y(50))
Vaibhav Devmurariff798f32022-05-09 23:45:04 +000013661 .build();
13662 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070013663 injectMotionEvent(*mDispatcher, thirdFingerDownEvent, INJECT_EVENT_TIMEOUT,
Vaibhav Devmurariff798f32022-05-09 23:45:04 +000013664 InputEventInjectionSync::WAIT_FOR_RESULT))
13665 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
13666 spy->consumeMotionPointerDown(1);
13667 window->consumeMotionPointerDown(2);
13668
13669 // Spy window pilfers the pointers.
13670 EXPECT_EQ(OK, mDispatcher->pilferPointers(spy->getToken()));
Prabir Pradhan33cfc6d2024-06-11 20:17:44 +000013671 window->consumeMotionPointerUp(/*pointerIdx=*/2,
13672 AllOf(WithDisplayId(ui::LogicalDisplayId::DEFAULT),
13673 WithFlags(AMOTION_EVENT_FLAG_CANCELED),
13674 WithPointerCount(3)));
13675 window->consumeMotionPointerUp(/*pointerIdx=*/1,
13676 AllOf(WithDisplayId(ui::LogicalDisplayId::DEFAULT),
13677 WithFlags(AMOTION_EVENT_FLAG_CANCELED),
13678 WithPointerCount(2)));
Vaibhav Devmurariff798f32022-05-09 23:45:04 +000013679
13680 spy->assertNoEvents();
13681 window->assertNoEvents();
13682}
13683
13684/**
13685 * After a spy window pilfers pointers, all pilfered pointers that have already been dispatched to
13686 * other windows should be canceled. If this results in the cancellation of all pointers for some
13687 * window, then that window should receive ACTION_CANCEL.
13688 */
13689TEST_F(InputDispatcherPilferPointersTest, PilferAllRequiredPointers) {
13690 auto spy = createSpy();
13691 spy->setFrame(Rect(0, 0, 100, 100));
13692 auto window = createForeground();
13693 window->setFrame(Rect(0, 0, 200, 200));
13694
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070013695 mDispatcher->onWindowInfosChanged({{*spy->getInfo(), *window->getInfo()}, {}, 0, 0});
Vaibhav Devmurariff798f32022-05-09 23:45:04 +000013696
13697 // First finger down on both spy and window
13698 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -070013699 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN,
13700 ui::LogicalDisplayId::DEFAULT, {10, 10}))
Vaibhav Devmurariff798f32022-05-09 23:45:04 +000013701 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
13702 window->consumeMotionDown();
13703 spy->consumeMotionDown();
13704
13705 // Second finger down on the spy and window
13706 const MotionEvent secondFingerDownEvent =
13707 MotionEventBuilder(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -070013708 .displayId(ui::LogicalDisplayId::DEFAULT)
Vaibhav Devmurariff798f32022-05-09 23:45:04 +000013709 .eventTime(systemTime(SYSTEM_TIME_MONOTONIC))
Siarhei Vishniakou6d73f832022-07-21 17:27:03 -070013710 .pointer(PointerBuilder(/*id=*/0, ToolType::FINGER).x(10).y(10))
13711 .pointer(PointerBuilder(/*id=*/1, ToolType::FINGER).x(50).y(50))
Vaibhav Devmurariff798f32022-05-09 23:45:04 +000013712 .build();
13713 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070013714 injectMotionEvent(*mDispatcher, secondFingerDownEvent, INJECT_EVENT_TIMEOUT,
Vaibhav Devmurariff798f32022-05-09 23:45:04 +000013715 InputEventInjectionSync::WAIT_FOR_RESULT))
13716 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
13717 spy->consumeMotionPointerDown(1);
13718 window->consumeMotionPointerDown(1);
13719
13720 // Spy window pilfers the pointers.
13721 EXPECT_EQ(OK, mDispatcher->pilferPointers(spy->getToken()));
13722 window->consumeMotionCancel();
13723
13724 spy->assertNoEvents();
13725 window->assertNoEvents();
13726}
13727
13728/**
13729 * After a spy window pilfers pointers, new pointers that are not touching the spy window can still
13730 * be sent to other windows
13731 */
13732TEST_F(InputDispatcherPilferPointersTest, CanReceivePointersAfterPilfer) {
13733 auto spy = createSpy();
13734 spy->setFrame(Rect(0, 0, 100, 100));
13735 auto window = createForeground();
13736 window->setFrame(Rect(0, 0, 200, 200));
13737
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070013738 mDispatcher->onWindowInfosChanged({{*spy->getInfo(), *window->getInfo()}, {}, 0, 0});
Vaibhav Devmurariff798f32022-05-09 23:45:04 +000013739
13740 // First finger down on both window and spy
13741 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -070013742 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN,
13743 ui::LogicalDisplayId::DEFAULT, {10, 10}))
Vaibhav Devmurariff798f32022-05-09 23:45:04 +000013744 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
13745 window->consumeMotionDown();
13746 spy->consumeMotionDown();
13747
13748 // Spy window pilfers the pointers.
13749 EXPECT_EQ(OK, mDispatcher->pilferPointers(spy->getToken()));
13750 window->consumeMotionCancel();
13751
13752 // Second finger down on the window only
13753 const MotionEvent secondFingerDownEvent =
13754 MotionEventBuilder(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -070013755 .displayId(ui::LogicalDisplayId::DEFAULT)
Vaibhav Devmurariff798f32022-05-09 23:45:04 +000013756 .eventTime(systemTime(SYSTEM_TIME_MONOTONIC))
Siarhei Vishniakou6d73f832022-07-21 17:27:03 -070013757 .pointer(PointerBuilder(/*id=*/0, ToolType::FINGER).x(10).y(10))
13758 .pointer(PointerBuilder(/*id=*/1, ToolType::FINGER).x(150).y(150))
Vaibhav Devmurariff798f32022-05-09 23:45:04 +000013759 .build();
13760 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070013761 injectMotionEvent(*mDispatcher, secondFingerDownEvent, INJECT_EVENT_TIMEOUT,
Vaibhav Devmurariff798f32022-05-09 23:45:04 +000013762 InputEventInjectionSync::WAIT_FOR_RESULT))
13763 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
13764 window->consumeMotionDown();
13765 window->assertNoEvents();
13766
13767 // TODO(b/232530217): do not send the unnecessary MOVE event and delete the next line
13768 spy->consumeMotionMove();
13769 spy->assertNoEvents();
13770}
13771
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -070013772/**
13773 * A window on the left and a window on the right. Also, a spy window that's above all of the
13774 * windows, and spanning both left and right windows.
13775 * Send simultaneous motion streams from two different devices, one to the left window, and another
13776 * to the right window.
13777 * Pilfer from spy window.
13778 * Check that the pilfering only affects the pointers that are actually being received by the spy.
13779 */
Siarhei Vishniakoued89cbb2023-10-13 10:42:44 -070013780TEST_F(InputDispatcherPilferPointersTest, MultiDevicePilfer_legacy) {
13781 SCOPED_FLAG_OVERRIDE(enable_multi_device_same_window_stream, false);
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -070013782 sp<FakeWindowHandle> spy = createSpy();
13783 spy->setFrame(Rect(0, 0, 200, 200));
13784 sp<FakeWindowHandle> leftWindow = createForeground();
13785 leftWindow->setFrame(Rect(0, 0, 100, 100));
13786
13787 sp<FakeWindowHandle> rightWindow = createForeground();
13788 rightWindow->setFrame(Rect(100, 0, 200, 100));
13789
13790 constexpr int32_t stylusDeviceId = 1;
13791 constexpr int32_t touchDeviceId = 2;
13792
13793 mDispatcher->onWindowInfosChanged(
13794 {{*spy->getInfo(), *leftWindow->getInfo(), *rightWindow->getInfo()}, {}, 0, 0});
13795
13796 // Stylus down on left window and spy
13797 mDispatcher->notifyMotion(MotionArgsBuilder(AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_STYLUS)
13798 .deviceId(stylusDeviceId)
13799 .pointer(PointerBuilder(0, ToolType::STYLUS).x(50).y(50))
13800 .build());
13801 leftWindow->consumeMotionEvent(
13802 AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(stylusDeviceId)));
13803 spy->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(stylusDeviceId)));
13804
13805 // Finger down on right window and spy - but spy already has stylus
13806 mDispatcher->notifyMotion(
13807 MotionArgsBuilder(AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
13808 .deviceId(touchDeviceId)
13809 .pointer(PointerBuilder(0, ToolType::FINGER).x(150).y(50))
13810 .build());
13811 rightWindow->consumeMotionEvent(
13812 AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(touchDeviceId)));
Siarhei Vishniakou2899c552023-07-10 18:20:46 -070013813 spy->assertNoEvents();
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -070013814
13815 // Act: pilfer from spy. Spy is currently receiving touch events.
13816 EXPECT_EQ(OK, mDispatcher->pilferPointers(spy->getToken()));
Siarhei Vishniakou2899c552023-07-10 18:20:46 -070013817 leftWindow->consumeMotionEvent(
13818 AllOf(WithMotionAction(ACTION_CANCEL), WithDeviceId(stylusDeviceId)));
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -070013819 rightWindow->consumeMotionEvent(
13820 AllOf(WithMotionAction(ACTION_CANCEL), WithDeviceId(touchDeviceId)));
13821
13822 // Continue movements from both stylus and touch. Touch will be delivered to spy, but not stylus
13823 mDispatcher->notifyMotion(MotionArgsBuilder(AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_STYLUS)
13824 .deviceId(stylusDeviceId)
13825 .pointer(PointerBuilder(0, ToolType::STYLUS).x(51).y(52))
13826 .build());
13827 mDispatcher->notifyMotion(
13828 MotionArgsBuilder(AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN)
13829 .deviceId(touchDeviceId)
13830 .pointer(PointerBuilder(0, ToolType::FINGER).x(151).y(52))
13831 .build());
Siarhei Vishniakou2899c552023-07-10 18:20:46 -070013832 spy->consumeMotionEvent(AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(stylusDeviceId)));
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -070013833
13834 spy->assertNoEvents();
13835 leftWindow->assertNoEvents();
13836 rightWindow->assertNoEvents();
13837}
13838
Siarhei Vishniakoued89cbb2023-10-13 10:42:44 -070013839/**
13840 * A window on the left and a window on the right. Also, a spy window that's above all of the
13841 * windows, and spanning both left and right windows.
13842 * Send simultaneous motion streams from two different devices, one to the left window, and another
13843 * to the right window.
13844 * Pilfer from spy window.
13845 * Check that the pilfering affects all of the pointers that are actually being received by the spy.
13846 * The spy should receive both the touch and the stylus events after pilfer.
13847 */
13848TEST_F(InputDispatcherPilferPointersTest, MultiDevicePilfer) {
13849 SCOPED_FLAG_OVERRIDE(enable_multi_device_same_window_stream, true);
13850 sp<FakeWindowHandle> spy = createSpy();
13851 spy->setFrame(Rect(0, 0, 200, 200));
13852 sp<FakeWindowHandle> leftWindow = createForeground();
13853 leftWindow->setFrame(Rect(0, 0, 100, 100));
13854
13855 sp<FakeWindowHandle> rightWindow = createForeground();
13856 rightWindow->setFrame(Rect(100, 0, 200, 100));
13857
13858 constexpr int32_t stylusDeviceId = 1;
13859 constexpr int32_t touchDeviceId = 2;
13860
13861 mDispatcher->onWindowInfosChanged(
13862 {{*spy->getInfo(), *leftWindow->getInfo(), *rightWindow->getInfo()}, {}, 0, 0});
13863
13864 // Stylus down on left window and spy
13865 mDispatcher->notifyMotion(MotionArgsBuilder(AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_STYLUS)
13866 .deviceId(stylusDeviceId)
13867 .pointer(PointerBuilder(0, ToolType::STYLUS).x(50).y(50))
13868 .build());
13869 leftWindow->consumeMotionEvent(
13870 AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(stylusDeviceId)));
13871 spy->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(stylusDeviceId)));
13872
13873 // Finger down on right window and spy
13874 mDispatcher->notifyMotion(
13875 MotionArgsBuilder(AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
13876 .deviceId(touchDeviceId)
13877 .pointer(PointerBuilder(0, ToolType::FINGER).x(150).y(50))
13878 .build());
13879 rightWindow->consumeMotionEvent(
13880 AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(touchDeviceId)));
13881 spy->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(touchDeviceId)));
13882
13883 // Act: pilfer from spy. Spy is currently receiving touch events.
13884 EXPECT_EQ(OK, mDispatcher->pilferPointers(spy->getToken()));
13885 leftWindow->consumeMotionEvent(
13886 AllOf(WithMotionAction(ACTION_CANCEL), WithDeviceId(stylusDeviceId)));
13887 rightWindow->consumeMotionEvent(
13888 AllOf(WithMotionAction(ACTION_CANCEL), WithDeviceId(touchDeviceId)));
13889
13890 // Continue movements from both stylus and touch. Touch and stylus will be delivered to spy
Siarhei Vishniakou92bca1c2024-04-01 14:06:59 -070013891 // Instead of sending the two MOVE events for each input device together, and then receiving
13892 // them both, process them one at at time. InputConsumer is always in the batching mode, which
13893 // means that the two MOVE events will be initially put into a batch. Once the events are
13894 // batched, the 'consume' call may result in any of the MOVE events to be sent first (depending
13895 // on the implementation of InputConsumer), which would mean that the order of the received
13896 // events could be different depending on whether there are 1 or 2 events pending in the
13897 // InputChannel at the time the test calls 'consume'. To make assertions simpler here, and to
13898 // avoid this confusing behaviour, send and receive each MOVE event separately.
Siarhei Vishniakoued89cbb2023-10-13 10:42:44 -070013899 mDispatcher->notifyMotion(MotionArgsBuilder(AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_STYLUS)
13900 .deviceId(stylusDeviceId)
13901 .pointer(PointerBuilder(0, ToolType::STYLUS).x(51).y(52))
13902 .build());
Siarhei Vishniakou92bca1c2024-04-01 14:06:59 -070013903 spy->consumeMotionEvent(AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(stylusDeviceId)));
Siarhei Vishniakoued89cbb2023-10-13 10:42:44 -070013904 mDispatcher->notifyMotion(
13905 MotionArgsBuilder(AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN)
13906 .deviceId(touchDeviceId)
13907 .pointer(PointerBuilder(0, ToolType::FINGER).x(151).y(52))
13908 .build());
Siarhei Vishniakou92bca1c2024-04-01 14:06:59 -070013909 spy->consumeMotionEvent(AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(touchDeviceId)));
Siarhei Vishniakoued89cbb2023-10-13 10:42:44 -070013910
13911 spy->assertNoEvents();
13912 leftWindow->assertNoEvents();
13913 rightWindow->assertNoEvents();
13914}
13915
Prabir Pradhan9cd9eb62023-11-22 17:58:06 +000013916TEST_F(InputDispatcherPilferPointersTest, NoPilferingWithHoveringPointers) {
13917 auto window = createForeground();
13918 auto spy = createSpy();
13919 mDispatcher->onWindowInfosChanged({{*spy->getInfo(), *window->getInfo()}, {}, 0, 0});
13920
13921 mDispatcher->notifyMotion(
13922 MotionArgsBuilder(ACTION_HOVER_ENTER, AINPUT_SOURCE_MOUSE)
13923 .deviceId(1)
13924 .pointer(PointerBuilder(/*id=*/0, ToolType::MOUSE).x(100).y(200))
13925 .build());
13926 window->consumeMotionEvent(WithMotionAction(ACTION_HOVER_ENTER));
13927 spy->consumeMotionEvent(WithMotionAction(ACTION_HOVER_ENTER));
13928
13929 // Pilfer pointers from the spy window should fail.
13930 EXPECT_NE(OK, mDispatcher->pilferPointers(spy->getToken()));
13931 spy->assertNoEvents();
13932 window->assertNoEvents();
13933}
13934
Prabir Pradhand65552b2021-10-07 11:23:50 -070013935class InputDispatcherStylusInterceptorTest : public InputDispatcherTest {
13936public:
13937 std::pair<sp<FakeWindowHandle>, sp<FakeWindowHandle>> setupStylusOverlayScenario() {
13938 std::shared_ptr<FakeApplicationHandle> overlayApplication =
13939 std::make_shared<FakeApplicationHandle>();
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -070013940 sp<FakeWindowHandle> overlay = sp<FakeWindowHandle>::make(overlayApplication, mDispatcher,
13941 "Stylus interceptor window",
13942 ui::LogicalDisplayId::DEFAULT);
Prabir Pradhand65552b2021-10-07 11:23:50 -070013943 overlay->setFocusable(false);
Prabir Pradhanaeebeb42023-06-13 19:53:03 +000013944 overlay->setOwnerInfo(gui::Pid{111}, gui::Uid{111});
Prabir Pradhan4d5c52f2022-01-31 08:52:10 -080013945 overlay->setTouchable(false);
Prabir Pradhan51e7db02022-02-07 06:02:57 -080013946 overlay->setInterceptsStylus(true);
Prabir Pradhand65552b2021-10-07 11:23:50 -070013947 overlay->setTrustedOverlay(true);
13948
13949 std::shared_ptr<FakeApplicationHandle> application =
13950 std::make_shared<FakeApplicationHandle>();
13951 sp<FakeWindowHandle> window =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -070013952 sp<FakeWindowHandle>::make(application, mDispatcher, "Application window",
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -070013953 ui::LogicalDisplayId::DEFAULT);
Prabir Pradhand65552b2021-10-07 11:23:50 -070013954 window->setFocusable(true);
Prabir Pradhanaeebeb42023-06-13 19:53:03 +000013955 window->setOwnerInfo(gui::Pid{222}, gui::Uid{222});
Prabir Pradhand65552b2021-10-07 11:23:50 -070013956
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -070013957 mDispatcher->setFocusedApplication(ui::LogicalDisplayId::DEFAULT, application);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070013958 mDispatcher->onWindowInfosChanged({{*overlay->getInfo(), *window->getInfo()}, {}, 0, 0});
Prabir Pradhand65552b2021-10-07 11:23:50 -070013959 setFocusedWindow(window);
Harry Cutts33476232023-01-30 19:57:29 +000013960 window->consumeFocusEvent(/*hasFocus=*/true, /*inTouchMode=*/true);
Prabir Pradhand65552b2021-10-07 11:23:50 -070013961 return {std::move(overlay), std::move(window)};
13962 }
13963
13964 void sendFingerEvent(int32_t action) {
Prabir Pradhan678438e2023-04-13 19:32:51 +000013965 mDispatcher->notifyMotion(
Prabir Pradhand65552b2021-10-07 11:23:50 -070013966 generateMotionArgs(action, AINPUT_SOURCE_TOUCHSCREEN | AINPUT_SOURCE_STYLUS,
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -070013967 ui::LogicalDisplayId::DEFAULT, {PointF{20, 20}}));
Prabir Pradhand65552b2021-10-07 11:23:50 -070013968 }
13969
13970 void sendStylusEvent(int32_t action) {
13971 NotifyMotionArgs motionArgs =
13972 generateMotionArgs(action, AINPUT_SOURCE_TOUCHSCREEN | AINPUT_SOURCE_STYLUS,
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -070013973 ui::LogicalDisplayId::DEFAULT, {PointF{30, 40}});
Siarhei Vishniakou6d73f832022-07-21 17:27:03 -070013974 motionArgs.pointerProperties[0].toolType = ToolType::STYLUS;
Prabir Pradhan678438e2023-04-13 19:32:51 +000013975 mDispatcher->notifyMotion(motionArgs);
Prabir Pradhand65552b2021-10-07 11:23:50 -070013976 }
13977};
13978
Prabir Pradhana3ab87a2022-01-27 10:00:21 -080013979using InputDispatcherStylusInterceptorDeathTest = InputDispatcherStylusInterceptorTest;
13980
13981TEST_F(InputDispatcherStylusInterceptorDeathTest, UntrustedOverlay_AbortsDispatcher) {
Siarhei Vishniakouad3b6822023-06-22 14:17:35 -070013982 testing::GTEST_FLAG(death_test_style) = "threadsafe";
Prabir Pradhana3ab87a2022-01-27 10:00:21 -080013983 ScopedSilentDeath _silentDeath;
13984
Prabir Pradhand65552b2021-10-07 11:23:50 -070013985 auto [overlay, window] = setupStylusOverlayScenario();
13986 overlay->setTrustedOverlay(false);
13987 // Configuring an untrusted overlay as a stylus interceptor should cause Dispatcher to abort.
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070013988 ASSERT_DEATH(mDispatcher->onWindowInfosChanged(
13989 {{*overlay->getInfo(), *window->getInfo()}, {}, 0, 0}),
Prabir Pradhand65552b2021-10-07 11:23:50 -070013990 ".* not a trusted overlay");
13991}
13992
13993TEST_F(InputDispatcherStylusInterceptorTest, ConsmesOnlyStylusEvents) {
13994 auto [overlay, window] = setupStylusOverlayScenario();
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070013995 mDispatcher->onWindowInfosChanged({{*overlay->getInfo(), *window->getInfo()}, {}, 0, 0});
Prabir Pradhand65552b2021-10-07 11:23:50 -070013996
13997 sendStylusEvent(AMOTION_EVENT_ACTION_DOWN);
13998 overlay->consumeMotionDown();
13999 sendStylusEvent(AMOTION_EVENT_ACTION_UP);
14000 overlay->consumeMotionUp();
14001
14002 sendFingerEvent(AMOTION_EVENT_ACTION_DOWN);
14003 window->consumeMotionDown();
14004 sendFingerEvent(AMOTION_EVENT_ACTION_UP);
14005 window->consumeMotionUp();
14006
14007 overlay->assertNoEvents();
14008 window->assertNoEvents();
14009}
14010
14011TEST_F(InputDispatcherStylusInterceptorTest, SpyWindowStylusInterceptor) {
14012 auto [overlay, window] = setupStylusOverlayScenario();
Prabir Pradhan51e7db02022-02-07 06:02:57 -080014013 overlay->setSpy(true);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070014014 mDispatcher->onWindowInfosChanged({{*overlay->getInfo(), *window->getInfo()}, {}, 0, 0});
Prabir Pradhand65552b2021-10-07 11:23:50 -070014015
14016 sendStylusEvent(AMOTION_EVENT_ACTION_DOWN);
14017 overlay->consumeMotionDown();
14018 window->consumeMotionDown();
14019 sendStylusEvent(AMOTION_EVENT_ACTION_UP);
14020 overlay->consumeMotionUp();
14021 window->consumeMotionUp();
14022
14023 sendFingerEvent(AMOTION_EVENT_ACTION_DOWN);
14024 window->consumeMotionDown();
14025 sendFingerEvent(AMOTION_EVENT_ACTION_UP);
14026 window->consumeMotionUp();
14027
14028 overlay->assertNoEvents();
14029 window->assertNoEvents();
14030}
14031
Prabir Pradhan6dfbf262022-03-14 15:24:30 +000014032/**
14033 * Set up a scenario to test the behavior used by the stylus handwriting detection feature.
14034 * The scenario is as follows:
14035 * - The stylus interceptor overlay is configured as a spy window.
14036 * - The stylus interceptor spy receives the start of a new stylus gesture.
14037 * - It pilfers pointers and then configures itself to no longer be a spy.
14038 * - The stylus interceptor continues to receive the rest of the gesture.
14039 */
14040TEST_F(InputDispatcherStylusInterceptorTest, StylusHandwritingScenario) {
14041 auto [overlay, window] = setupStylusOverlayScenario();
14042 overlay->setSpy(true);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070014043 mDispatcher->onWindowInfosChanged({{*overlay->getInfo(), *window->getInfo()}, {}, 0, 0});
Prabir Pradhan6dfbf262022-03-14 15:24:30 +000014044
14045 sendStylusEvent(AMOTION_EVENT_ACTION_DOWN);
14046 overlay->consumeMotionDown();
14047 window->consumeMotionDown();
14048
14049 // The interceptor pilfers the pointers.
14050 EXPECT_EQ(OK, mDispatcher->pilferPointers(overlay->getToken()));
14051 window->consumeMotionCancel();
14052
14053 // The interceptor configures itself so that it is no longer a spy.
14054 overlay->setSpy(false);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070014055 mDispatcher->onWindowInfosChanged({{*overlay->getInfo(), *window->getInfo()}, {}, 0, 0});
Prabir Pradhan6dfbf262022-03-14 15:24:30 +000014056
14057 // It continues to receive the rest of the stylus gesture.
14058 sendStylusEvent(AMOTION_EVENT_ACTION_MOVE);
14059 overlay->consumeMotionMove();
14060 sendStylusEvent(AMOTION_EVENT_ACTION_UP);
14061 overlay->consumeMotionUp();
14062
14063 window->assertNoEvents();
14064}
14065
Prabir Pradhan5735a322022-04-11 17:23:34 +000014066struct User {
Prabir Pradhanaeebeb42023-06-13 19:53:03 +000014067 gui::Pid mPid;
Prabir Pradhan8a5c41d2023-06-08 19:13:46 +000014068 gui::Uid mUid;
Prabir Pradhan5735a322022-04-11 17:23:34 +000014069 uint32_t mPolicyFlags{DEFAULT_POLICY_FLAGS};
14070 std::unique_ptr<InputDispatcher>& mDispatcher;
14071
Prabir Pradhanaeebeb42023-06-13 19:53:03 +000014072 User(std::unique_ptr<InputDispatcher>& dispatcher, gui::Pid pid, gui::Uid uid)
Prabir Pradhan5735a322022-04-11 17:23:34 +000014073 : mPid(pid), mUid(uid), mDispatcher(dispatcher) {}
14074
14075 InputEventInjectionResult injectTargetedMotion(int32_t action) const {
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070014076 return injectMotionEvent(*mDispatcher, action, AINPUT_SOURCE_TOUCHSCREEN,
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -070014077 ui::LogicalDisplayId::DEFAULT, {100, 200},
Prabir Pradhan5735a322022-04-11 17:23:34 +000014078 {AMOTION_EVENT_INVALID_CURSOR_POSITION,
14079 AMOTION_EVENT_INVALID_CURSOR_POSITION},
14080 INJECT_EVENT_TIMEOUT, InputEventInjectionSync::WAIT_FOR_RESULT,
14081 systemTime(SYSTEM_TIME_MONOTONIC), {mUid}, mPolicyFlags);
14082 }
14083
14084 InputEventInjectionResult injectTargetedKey(int32_t action) const {
Linnan Li13bf76a2024-05-05 19:18:02 +080014085 return inputdispatcher::injectKey(*mDispatcher, action, /*repeatCount=*/0,
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -070014086 ui::LogicalDisplayId::INVALID,
Prabir Pradhan5735a322022-04-11 17:23:34 +000014087 InputEventInjectionSync::WAIT_FOR_RESULT,
Harry Cutts33476232023-01-30 19:57:29 +000014088 INJECT_EVENT_TIMEOUT, /*allowKeyRepeat=*/false, {mUid},
Prabir Pradhan5735a322022-04-11 17:23:34 +000014089 mPolicyFlags);
14090 }
14091
Siarhei Vishniakoue3ce4122023-08-23 10:26:46 -070014092 sp<FakeWindowHandle> createWindow(const char* name) const {
Prabir Pradhan5735a322022-04-11 17:23:34 +000014093 std::shared_ptr<FakeApplicationHandle> overlayApplication =
14094 std::make_shared<FakeApplicationHandle>();
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -070014095 sp<FakeWindowHandle> window =
14096 sp<FakeWindowHandle>::make(overlayApplication, mDispatcher, name,
14097 ui::LogicalDisplayId::DEFAULT);
Prabir Pradhan5735a322022-04-11 17:23:34 +000014098 window->setOwnerInfo(mPid, mUid);
14099 return window;
14100 }
14101};
14102
14103using InputDispatcherTargetedInjectionTest = InputDispatcherTest;
14104
14105TEST_F(InputDispatcherTargetedInjectionTest, CanInjectIntoOwnedWindow) {
Prabir Pradhanaeebeb42023-06-13 19:53:03 +000014106 auto owner = User(mDispatcher, gui::Pid{10}, gui::Uid{11});
Siarhei Vishniakoue3ce4122023-08-23 10:26:46 -070014107 auto window = owner.createWindow("Owned window");
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070014108 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Prabir Pradhan5735a322022-04-11 17:23:34 +000014109
14110 EXPECT_EQ(InputEventInjectionResult::SUCCEEDED,
14111 owner.injectTargetedMotion(AMOTION_EVENT_ACTION_DOWN));
14112 window->consumeMotionDown();
14113
14114 setFocusedWindow(window);
14115 window->consumeFocusEvent(true);
14116
14117 EXPECT_EQ(InputEventInjectionResult::SUCCEEDED,
14118 owner.injectTargetedKey(AKEY_EVENT_ACTION_DOWN));
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -070014119 window->consumeKeyDown(ui::LogicalDisplayId::INVALID);
Prabir Pradhan5735a322022-04-11 17:23:34 +000014120}
14121
14122TEST_F(InputDispatcherTargetedInjectionTest, CannotInjectIntoUnownedWindow) {
Prabir Pradhanaeebeb42023-06-13 19:53:03 +000014123 auto owner = User(mDispatcher, gui::Pid{10}, gui::Uid{11});
Siarhei Vishniakoue3ce4122023-08-23 10:26:46 -070014124 auto window = owner.createWindow("Owned window");
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070014125 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Prabir Pradhan5735a322022-04-11 17:23:34 +000014126
Prabir Pradhanaeebeb42023-06-13 19:53:03 +000014127 auto rando = User(mDispatcher, gui::Pid{20}, gui::Uid{21});
Prabir Pradhan5735a322022-04-11 17:23:34 +000014128 EXPECT_EQ(InputEventInjectionResult::TARGET_MISMATCH,
14129 rando.injectTargetedMotion(AMOTION_EVENT_ACTION_DOWN));
14130
14131 setFocusedWindow(window);
14132 window->consumeFocusEvent(true);
14133
14134 EXPECT_EQ(InputEventInjectionResult::TARGET_MISMATCH,
14135 rando.injectTargetedKey(AKEY_EVENT_ACTION_DOWN));
14136 window->assertNoEvents();
14137}
14138
14139TEST_F(InputDispatcherTargetedInjectionTest, CanInjectIntoOwnedSpyWindow) {
Prabir Pradhanaeebeb42023-06-13 19:53:03 +000014140 auto owner = User(mDispatcher, gui::Pid{10}, gui::Uid{11});
Siarhei Vishniakoue3ce4122023-08-23 10:26:46 -070014141 auto window = owner.createWindow("Owned window");
14142 auto spy = owner.createWindow("Owned spy");
Prabir Pradhan5735a322022-04-11 17:23:34 +000014143 spy->setSpy(true);
14144 spy->setTrustedOverlay(true);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070014145 mDispatcher->onWindowInfosChanged({{*spy->getInfo(), *window->getInfo()}, {}, 0, 0});
Prabir Pradhan5735a322022-04-11 17:23:34 +000014146
14147 EXPECT_EQ(InputEventInjectionResult::SUCCEEDED,
14148 owner.injectTargetedMotion(AMOTION_EVENT_ACTION_DOWN));
14149 spy->consumeMotionDown();
14150 window->consumeMotionDown();
14151}
14152
14153TEST_F(InputDispatcherTargetedInjectionTest, CannotInjectIntoUnownedSpyWindow) {
Prabir Pradhanaeebeb42023-06-13 19:53:03 +000014154 auto owner = User(mDispatcher, gui::Pid{10}, gui::Uid{11});
Siarhei Vishniakoue3ce4122023-08-23 10:26:46 -070014155 auto window = owner.createWindow("Owned window");
Prabir Pradhan5735a322022-04-11 17:23:34 +000014156
Prabir Pradhanaeebeb42023-06-13 19:53:03 +000014157 auto rando = User(mDispatcher, gui::Pid{20}, gui::Uid{21});
Siarhei Vishniakoue3ce4122023-08-23 10:26:46 -070014158 auto randosSpy = rando.createWindow("Rando's spy");
Prabir Pradhan5735a322022-04-11 17:23:34 +000014159 randosSpy->setSpy(true);
14160 randosSpy->setTrustedOverlay(true);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070014161 mDispatcher->onWindowInfosChanged({{*randosSpy->getInfo(), *window->getInfo()}, {}, 0, 0});
Prabir Pradhan5735a322022-04-11 17:23:34 +000014162
14163 // The event is targeted at owner's window, so injection should succeed, but the spy should
14164 // not receive the event.
14165 EXPECT_EQ(InputEventInjectionResult::SUCCEEDED,
14166 owner.injectTargetedMotion(AMOTION_EVENT_ACTION_DOWN));
14167 randosSpy->assertNoEvents();
14168 window->consumeMotionDown();
14169}
14170
14171TEST_F(InputDispatcherTargetedInjectionTest, CanInjectIntoAnyWindowWhenNotTargeting) {
Prabir Pradhanaeebeb42023-06-13 19:53:03 +000014172 auto owner = User(mDispatcher, gui::Pid{10}, gui::Uid{11});
Siarhei Vishniakoue3ce4122023-08-23 10:26:46 -070014173 auto window = owner.createWindow("Owned window");
Prabir Pradhan5735a322022-04-11 17:23:34 +000014174
Prabir Pradhanaeebeb42023-06-13 19:53:03 +000014175 auto rando = User(mDispatcher, gui::Pid{20}, gui::Uid{21});
Siarhei Vishniakoue3ce4122023-08-23 10:26:46 -070014176 auto randosSpy = rando.createWindow("Rando's spy");
Prabir Pradhan5735a322022-04-11 17:23:34 +000014177 randosSpy->setSpy(true);
14178 randosSpy->setTrustedOverlay(true);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070014179 mDispatcher->onWindowInfosChanged({{*randosSpy->getInfo(), *window->getInfo()}, {}, 0, 0});
Prabir Pradhan5735a322022-04-11 17:23:34 +000014180
14181 // A user that has injection permission can inject into any window.
14182 EXPECT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070014183 injectMotionEvent(*mDispatcher, AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN,
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -070014184 ui::LogicalDisplayId::DEFAULT));
Prabir Pradhan5735a322022-04-11 17:23:34 +000014185 randosSpy->consumeMotionDown();
14186 window->consumeMotionDown();
14187
14188 setFocusedWindow(randosSpy);
14189 randosSpy->consumeFocusEvent(true);
14190
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070014191 EXPECT_EQ(InputEventInjectionResult::SUCCEEDED, injectKeyDown(*mDispatcher));
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -070014192 randosSpy->consumeKeyDown(ui::LogicalDisplayId::INVALID);
Prabir Pradhan5735a322022-04-11 17:23:34 +000014193 window->assertNoEvents();
14194}
14195
Siarhei Vishniakou580fb3a2023-05-05 15:02:20 -070014196TEST_F(InputDispatcherTargetedInjectionTest, CannotGenerateActionOutsideToOtherUids) {
Prabir Pradhanaeebeb42023-06-13 19:53:03 +000014197 auto owner = User(mDispatcher, gui::Pid{10}, gui::Uid{11});
Siarhei Vishniakoue3ce4122023-08-23 10:26:46 -070014198 auto window = owner.createWindow("Owned window");
Prabir Pradhan5735a322022-04-11 17:23:34 +000014199
Prabir Pradhanaeebeb42023-06-13 19:53:03 +000014200 auto rando = User(mDispatcher, gui::Pid{20}, gui::Uid{21});
Siarhei Vishniakoue3ce4122023-08-23 10:26:46 -070014201 auto randosWindow = rando.createWindow("Rando's window");
Prabir Pradhan5735a322022-04-11 17:23:34 +000014202 randosWindow->setFrame(Rect{-10, -10, -5, -5});
14203 randosWindow->setWatchOutsideTouch(true);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070014204 mDispatcher->onWindowInfosChanged({{*randosWindow->getInfo(), *window->getInfo()}, {}, 0, 0});
Prabir Pradhan5735a322022-04-11 17:23:34 +000014205
Siarhei Vishniakou580fb3a2023-05-05 15:02:20 -070014206 // Do not allow generation of ACTION_OUTSIDE events into windows owned by different uids.
Prabir Pradhan5735a322022-04-11 17:23:34 +000014207 EXPECT_EQ(InputEventInjectionResult::SUCCEEDED,
14208 owner.injectTargetedMotion(AMOTION_EVENT_ACTION_DOWN));
14209 window->consumeMotionDown();
Siarhei Vishniakou580fb3a2023-05-05 15:02:20 -070014210 randosWindow->assertNoEvents();
Prabir Pradhan5735a322022-04-11 17:23:34 +000014211}
14212
Prabir Pradhan64f21d22023-11-28 21:19:42 +000014213using InputDispatcherPointerInWindowTest = InputDispatcherTest;
14214
14215TEST_F(InputDispatcherPointerInWindowTest, PointerInWindowWhenHovering) {
14216 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
14217
14218 sp<FakeWindowHandle> left = sp<FakeWindowHandle>::make(application, mDispatcher, "Left Window",
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -070014219 ui::LogicalDisplayId::DEFAULT);
Prabir Pradhan64f21d22023-11-28 21:19:42 +000014220 left->setFrame(Rect(0, 0, 100, 100));
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -070014221 sp<FakeWindowHandle> right =
14222 sp<FakeWindowHandle>::make(application, mDispatcher, "Right Window",
14223 ui::LogicalDisplayId::DEFAULT);
Prabir Pradhan64f21d22023-11-28 21:19:42 +000014224 right->setFrame(Rect(100, 0, 200, 100));
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -070014225 sp<FakeWindowHandle> spy = sp<FakeWindowHandle>::make(application, mDispatcher, "Spy Window",
14226 ui::LogicalDisplayId::DEFAULT);
Prabir Pradhan64f21d22023-11-28 21:19:42 +000014227 spy->setFrame(Rect(0, 0, 200, 100));
14228 spy->setTrustedOverlay(true);
14229 spy->setSpy(true);
14230
14231 mDispatcher->onWindowInfosChanged(
14232 {{*spy->getInfo(), *left->getInfo(), *right->getInfo()}, {}, 0, 0});
14233
14234 // Hover into the left window.
14235 mDispatcher->notifyMotion(
14236 MotionArgsBuilder(ACTION_HOVER_ENTER, AINPUT_SOURCE_STYLUS)
14237 .pointer(PointerBuilder(/*id=*/0, ToolType::STYLUS).x(50).y(50))
14238 .build());
14239
14240 left->consumeMotionEvent(WithMotionAction(ACTION_HOVER_ENTER));
14241 spy->consumeMotionEvent(WithMotionAction(ACTION_HOVER_ENTER));
14242
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -070014243 ASSERT_TRUE(mDispatcher->isPointerInWindow(left->getToken(), ui::LogicalDisplayId::DEFAULT,
14244 DEVICE_ID,
Prabir Pradhan64f21d22023-11-28 21:19:42 +000014245 /*pointerId=*/0));
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -070014246 ASSERT_TRUE(mDispatcher->isPointerInWindow(spy->getToken(), ui::LogicalDisplayId::DEFAULT,
14247 DEVICE_ID,
Prabir Pradhan64f21d22023-11-28 21:19:42 +000014248 /*pointerId=*/0));
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -070014249 ASSERT_FALSE(mDispatcher->isPointerInWindow(right->getToken(), ui::LogicalDisplayId::DEFAULT,
14250 DEVICE_ID,
Prabir Pradhan64f21d22023-11-28 21:19:42 +000014251 /*pointerId=*/0));
14252
14253 // Hover move to the right window.
14254 mDispatcher->notifyMotion(
14255 MotionArgsBuilder(ACTION_HOVER_MOVE, AINPUT_SOURCE_STYLUS)
14256 .pointer(PointerBuilder(/*id=*/0, ToolType::STYLUS).x(150).y(50))
14257 .build());
14258
14259 left->consumeMotionEvent(WithMotionAction(ACTION_HOVER_EXIT));
14260 right->consumeMotionEvent(WithMotionAction(ACTION_HOVER_ENTER));
14261 spy->consumeMotionEvent(WithMotionAction(ACTION_HOVER_MOVE));
14262
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -070014263 ASSERT_FALSE(mDispatcher->isPointerInWindow(left->getToken(), ui::LogicalDisplayId::DEFAULT,
14264 DEVICE_ID,
Prabir Pradhan64f21d22023-11-28 21:19:42 +000014265 /*pointerId=*/0));
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -070014266 ASSERT_TRUE(mDispatcher->isPointerInWindow(spy->getToken(), ui::LogicalDisplayId::DEFAULT,
14267 DEVICE_ID,
Prabir Pradhan64f21d22023-11-28 21:19:42 +000014268 /*pointerId=*/0));
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -070014269 ASSERT_TRUE(mDispatcher->isPointerInWindow(right->getToken(), ui::LogicalDisplayId::DEFAULT,
14270 DEVICE_ID,
Prabir Pradhan64f21d22023-11-28 21:19:42 +000014271 /*pointerId=*/0));
14272
14273 // Stop hovering.
14274 mDispatcher->notifyMotion(
14275 MotionArgsBuilder(ACTION_HOVER_EXIT, AINPUT_SOURCE_STYLUS)
14276 .pointer(PointerBuilder(/*id=*/0, ToolType::STYLUS).x(150).y(50))
14277 .build());
14278
14279 right->consumeMotionEvent(WithMotionAction(ACTION_HOVER_EXIT));
14280 spy->consumeMotionEvent(WithMotionAction(ACTION_HOVER_EXIT));
14281
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -070014282 ASSERT_FALSE(mDispatcher->isPointerInWindow(left->getToken(), ui::LogicalDisplayId::DEFAULT,
14283 DEVICE_ID,
Prabir Pradhan64f21d22023-11-28 21:19:42 +000014284 /*pointerId=*/0));
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -070014285 ASSERT_FALSE(mDispatcher->isPointerInWindow(spy->getToken(), ui::LogicalDisplayId::DEFAULT,
14286 DEVICE_ID,
Prabir Pradhan64f21d22023-11-28 21:19:42 +000014287 /*pointerId=*/0));
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -070014288 ASSERT_FALSE(mDispatcher->isPointerInWindow(right->getToken(), ui::LogicalDisplayId::DEFAULT,
14289 DEVICE_ID,
Prabir Pradhan64f21d22023-11-28 21:19:42 +000014290 /*pointerId=*/0));
14291}
14292
14293TEST_F(InputDispatcherPointerInWindowTest, PointerInWindowWithSplitTouch) {
14294 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
14295
14296 sp<FakeWindowHandle> left = sp<FakeWindowHandle>::make(application, mDispatcher, "Left Window",
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -070014297 ui::LogicalDisplayId::DEFAULT);
Prabir Pradhan64f21d22023-11-28 21:19:42 +000014298 left->setFrame(Rect(0, 0, 100, 100));
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -070014299 sp<FakeWindowHandle> right =
14300 sp<FakeWindowHandle>::make(application, mDispatcher, "Right Window",
14301 ui::LogicalDisplayId::DEFAULT);
Prabir Pradhan64f21d22023-11-28 21:19:42 +000014302 right->setFrame(Rect(100, 0, 200, 100));
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -070014303 sp<FakeWindowHandle> spy = sp<FakeWindowHandle>::make(application, mDispatcher, "Spy Window",
14304 ui::LogicalDisplayId::DEFAULT);
Prabir Pradhan64f21d22023-11-28 21:19:42 +000014305 spy->setFrame(Rect(0, 0, 200, 100));
14306 spy->setTrustedOverlay(true);
14307 spy->setSpy(true);
14308
14309 mDispatcher->onWindowInfosChanged(
14310 {{*spy->getInfo(), *left->getInfo(), *right->getInfo()}, {}, 0, 0});
14311
14312 // First pointer down on left window.
14313 mDispatcher->notifyMotion(
14314 MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
14315 .pointer(PointerBuilder(/*id=*/0, ToolType::FINGER).x(50).y(50))
14316 .build());
14317
14318 left->consumeMotionDown();
14319 spy->consumeMotionDown();
14320
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -070014321 ASSERT_TRUE(mDispatcher->isPointerInWindow(left->getToken(), ui::LogicalDisplayId::DEFAULT,
14322 DEVICE_ID,
Prabir Pradhan64f21d22023-11-28 21:19:42 +000014323 /*pointerId=*/0));
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -070014324 ASSERT_TRUE(mDispatcher->isPointerInWindow(spy->getToken(), ui::LogicalDisplayId::DEFAULT,
14325 DEVICE_ID,
Prabir Pradhan64f21d22023-11-28 21:19:42 +000014326 /*pointerId=*/0));
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -070014327 ASSERT_FALSE(mDispatcher->isPointerInWindow(right->getToken(), ui::LogicalDisplayId::DEFAULT,
14328 DEVICE_ID,
Prabir Pradhan64f21d22023-11-28 21:19:42 +000014329 /*pointerId=*/0));
14330
14331 // Second pointer down on right window.
14332 mDispatcher->notifyMotion(
14333 MotionArgsBuilder(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
14334 .pointer(PointerBuilder(/*id=*/0, ToolType::FINGER).x(50).y(50))
14335 .pointer(PointerBuilder(/*id=*/1, ToolType::FINGER).x(150).y(50))
14336 .build());
14337
14338 left->consumeMotionMove();
14339 right->consumeMotionDown();
14340 spy->consumeMotionEvent(WithMotionAction(POINTER_1_DOWN));
14341
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -070014342 ASSERT_TRUE(mDispatcher->isPointerInWindow(left->getToken(), ui::LogicalDisplayId::DEFAULT,
14343 DEVICE_ID,
Prabir Pradhan64f21d22023-11-28 21:19:42 +000014344 /*pointerId=*/0));
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -070014345 ASSERT_TRUE(mDispatcher->isPointerInWindow(spy->getToken(), ui::LogicalDisplayId::DEFAULT,
14346 DEVICE_ID,
Prabir Pradhan64f21d22023-11-28 21:19:42 +000014347 /*pointerId=*/0));
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -070014348 ASSERT_FALSE(mDispatcher->isPointerInWindow(right->getToken(), ui::LogicalDisplayId::DEFAULT,
14349 DEVICE_ID,
Prabir Pradhan64f21d22023-11-28 21:19:42 +000014350 /*pointerId=*/0));
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -070014351 ASSERT_FALSE(mDispatcher->isPointerInWindow(left->getToken(), ui::LogicalDisplayId::DEFAULT,
14352 DEVICE_ID,
Prabir Pradhan64f21d22023-11-28 21:19:42 +000014353 /*pointerId=*/1));
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -070014354 ASSERT_TRUE(mDispatcher->isPointerInWindow(spy->getToken(), ui::LogicalDisplayId::DEFAULT,
14355 DEVICE_ID,
Prabir Pradhan64f21d22023-11-28 21:19:42 +000014356 /*pointerId=*/1));
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -070014357 ASSERT_TRUE(mDispatcher->isPointerInWindow(right->getToken(), ui::LogicalDisplayId::DEFAULT,
14358 DEVICE_ID,
Prabir Pradhan64f21d22023-11-28 21:19:42 +000014359 /*pointerId=*/1));
14360
14361 // Second pointer up.
14362 mDispatcher->notifyMotion(
14363 MotionArgsBuilder(POINTER_1_UP, AINPUT_SOURCE_TOUCHSCREEN)
14364 .pointer(PointerBuilder(/*id=*/0, ToolType::FINGER).x(50).y(50))
14365 .pointer(PointerBuilder(/*id=*/1, ToolType::FINGER).x(150).y(50))
14366 .build());
14367
14368 left->consumeMotionMove();
14369 right->consumeMotionUp();
14370 spy->consumeMotionEvent(WithMotionAction(POINTER_1_UP));
14371
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -070014372 ASSERT_TRUE(mDispatcher->isPointerInWindow(left->getToken(), ui::LogicalDisplayId::DEFAULT,
14373 DEVICE_ID,
Prabir Pradhan64f21d22023-11-28 21:19:42 +000014374 /*pointerId=*/0));
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -070014375 ASSERT_TRUE(mDispatcher->isPointerInWindow(spy->getToken(), ui::LogicalDisplayId::DEFAULT,
14376 DEVICE_ID,
Prabir Pradhan64f21d22023-11-28 21:19:42 +000014377 /*pointerId=*/0));
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -070014378 ASSERT_FALSE(mDispatcher->isPointerInWindow(right->getToken(), ui::LogicalDisplayId::DEFAULT,
14379 DEVICE_ID,
Prabir Pradhan64f21d22023-11-28 21:19:42 +000014380 /*pointerId=*/0));
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -070014381 ASSERT_FALSE(mDispatcher->isPointerInWindow(left->getToken(), ui::LogicalDisplayId::DEFAULT,
14382 DEVICE_ID,
Prabir Pradhan64f21d22023-11-28 21:19:42 +000014383 /*pointerId=*/1));
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -070014384 ASSERT_FALSE(mDispatcher->isPointerInWindow(spy->getToken(), ui::LogicalDisplayId::DEFAULT,
14385 DEVICE_ID,
Prabir Pradhan64f21d22023-11-28 21:19:42 +000014386 /*pointerId=*/1));
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -070014387 ASSERT_FALSE(mDispatcher->isPointerInWindow(right->getToken(), ui::LogicalDisplayId::DEFAULT,
14388 DEVICE_ID,
Prabir Pradhan64f21d22023-11-28 21:19:42 +000014389 /*pointerId=*/1));
14390
14391 // First pointer up.
14392 mDispatcher->notifyMotion(
14393 MotionArgsBuilder(ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN)
14394 .pointer(PointerBuilder(/*id=*/0, ToolType::FINGER).x(50).y(50))
14395 .build());
14396
14397 left->consumeMotionUp();
14398 spy->consumeMotionUp();
14399
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -070014400 ASSERT_FALSE(mDispatcher->isPointerInWindow(left->getToken(), ui::LogicalDisplayId::DEFAULT,
14401 DEVICE_ID,
Prabir Pradhan64f21d22023-11-28 21:19:42 +000014402 /*pointerId=*/0));
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -070014403 ASSERT_FALSE(mDispatcher->isPointerInWindow(spy->getToken(), ui::LogicalDisplayId::DEFAULT,
14404 DEVICE_ID,
Prabir Pradhan64f21d22023-11-28 21:19:42 +000014405 /*pointerId=*/0));
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -070014406 ASSERT_FALSE(mDispatcher->isPointerInWindow(right->getToken(), ui::LogicalDisplayId::DEFAULT,
14407 DEVICE_ID,
Prabir Pradhan64f21d22023-11-28 21:19:42 +000014408 /*pointerId=*/0));
14409}
14410
Siarhei Vishniakoued89cbb2023-10-13 10:42:44 -070014411TEST_F(InputDispatcherPointerInWindowTest, MultipleDevicesControllingOneMouse_legacy) {
14412 SCOPED_FLAG_OVERRIDE(enable_multi_device_same_window_stream, false);
Prabir Pradhan64f21d22023-11-28 21:19:42 +000014413 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
14414
14415 sp<FakeWindowHandle> left = sp<FakeWindowHandle>::make(application, mDispatcher, "Left Window",
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -070014416 ui::LogicalDisplayId::DEFAULT);
Prabir Pradhan64f21d22023-11-28 21:19:42 +000014417 left->setFrame(Rect(0, 0, 100, 100));
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -070014418 sp<FakeWindowHandle> right =
14419 sp<FakeWindowHandle>::make(application, mDispatcher, "Right Window",
14420 ui::LogicalDisplayId::DEFAULT);
Prabir Pradhan64f21d22023-11-28 21:19:42 +000014421 right->setFrame(Rect(100, 0, 200, 100));
14422
14423 mDispatcher->onWindowInfosChanged({{*left->getInfo(), *right->getInfo()}, {}, 0, 0});
14424
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -070014425 ASSERT_FALSE(mDispatcher->isPointerInWindow(left->getToken(), ui::LogicalDisplayId::DEFAULT,
14426 DEVICE_ID,
Prabir Pradhan64f21d22023-11-28 21:19:42 +000014427 /*pointerId=*/0));
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -070014428 ASSERT_FALSE(mDispatcher->isPointerInWindow(right->getToken(), ui::LogicalDisplayId::DEFAULT,
14429 DEVICE_ID,
Prabir Pradhan64f21d22023-11-28 21:19:42 +000014430 /*pointerId=*/0));
14431
14432 // Hover move into the window.
14433 mDispatcher->notifyMotion(
14434 MotionArgsBuilder(ACTION_HOVER_MOVE, AINPUT_SOURCE_MOUSE)
14435 .pointer(PointerBuilder(/*id=*/0, ToolType::MOUSE).x(50).y(50))
14436 .rawXCursorPosition(50)
14437 .rawYCursorPosition(50)
14438 .deviceId(DEVICE_ID)
14439 .build());
14440
14441 left->consumeMotionEvent(WithMotionAction(ACTION_HOVER_ENTER));
14442
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -070014443 ASSERT_TRUE(mDispatcher->isPointerInWindow(left->getToken(), ui::LogicalDisplayId::DEFAULT,
14444 DEVICE_ID,
Prabir Pradhan64f21d22023-11-28 21:19:42 +000014445 /*pointerId=*/0));
14446
14447 // Move the mouse with another device. This cancels the hovering pointer from the first device.
14448 mDispatcher->notifyMotion(
14449 MotionArgsBuilder(ACTION_HOVER_MOVE, AINPUT_SOURCE_MOUSE)
14450 .pointer(PointerBuilder(/*id=*/0, ToolType::MOUSE).x(51).y(50))
14451 .rawXCursorPosition(51)
14452 .rawYCursorPosition(50)
14453 .deviceId(SECOND_DEVICE_ID)
14454 .build());
14455
14456 left->consumeMotionEvent(WithMotionAction(ACTION_HOVER_EXIT));
14457 left->consumeMotionEvent(WithMotionAction(ACTION_HOVER_ENTER));
14458
14459 // TODO(b/313689709): InputDispatcher's touch state is not updated, even though the window gets
14460 // a HOVER_EXIT from the first device.
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -070014461 ASSERT_TRUE(mDispatcher->isPointerInWindow(left->getToken(), ui::LogicalDisplayId::DEFAULT,
14462 DEVICE_ID,
Prabir Pradhan64f21d22023-11-28 21:19:42 +000014463 /*pointerId=*/0));
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -070014464 ASSERT_TRUE(mDispatcher->isPointerInWindow(left->getToken(), ui::LogicalDisplayId::DEFAULT,
Prabir Pradhan64f21d22023-11-28 21:19:42 +000014465 SECOND_DEVICE_ID,
14466 /*pointerId=*/0));
14467
14468 // Move the mouse outside the window. Document the current behavior, where the window does not
14469 // receive HOVER_EXIT even though the mouse left the window.
14470 mDispatcher->notifyMotion(
14471 MotionArgsBuilder(ACTION_HOVER_MOVE, AINPUT_SOURCE_MOUSE)
14472 .pointer(PointerBuilder(/*id=*/0, ToolType::MOUSE).x(150).y(50))
14473 .rawXCursorPosition(150)
14474 .rawYCursorPosition(50)
14475 .deviceId(SECOND_DEVICE_ID)
14476 .build());
14477
14478 left->consumeMotionEvent(WithMotionAction(ACTION_HOVER_EXIT));
14479 right->consumeMotionEvent(WithMotionAction(ACTION_HOVER_ENTER));
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -070014480 ASSERT_TRUE(mDispatcher->isPointerInWindow(left->getToken(), ui::LogicalDisplayId::DEFAULT,
14481 DEVICE_ID,
Prabir Pradhan64f21d22023-11-28 21:19:42 +000014482 /*pointerId=*/0));
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -070014483 ASSERT_FALSE(mDispatcher->isPointerInWindow(left->getToken(), ui::LogicalDisplayId::DEFAULT,
Prabir Pradhan64f21d22023-11-28 21:19:42 +000014484 SECOND_DEVICE_ID,
14485 /*pointerId=*/0));
14486}
14487
Siarhei Vishniakoued89cbb2023-10-13 10:42:44 -070014488/**
14489 * TODO(b/313689709) - correctly support multiple mouse devices, because they should be controlling
14490 * the same cursor, and therefore have a shared motion event stream.
14491 */
14492TEST_F(InputDispatcherPointerInWindowTest, MultipleDevicesControllingOneMouse) {
14493 SCOPED_FLAG_OVERRIDE(enable_multi_device_same_window_stream, true);
14494 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
14495
14496 sp<FakeWindowHandle> left = sp<FakeWindowHandle>::make(application, mDispatcher, "Left Window",
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -070014497 ui::LogicalDisplayId::DEFAULT);
Siarhei Vishniakoued89cbb2023-10-13 10:42:44 -070014498 left->setFrame(Rect(0, 0, 100, 100));
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -070014499 sp<FakeWindowHandle> right =
14500 sp<FakeWindowHandle>::make(application, mDispatcher, "Right Window",
14501 ui::LogicalDisplayId::DEFAULT);
Siarhei Vishniakoued89cbb2023-10-13 10:42:44 -070014502 right->setFrame(Rect(100, 0, 200, 100));
14503
14504 mDispatcher->onWindowInfosChanged({{*left->getInfo(), *right->getInfo()}, {}, 0, 0});
14505
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -070014506 ASSERT_FALSE(mDispatcher->isPointerInWindow(left->getToken(), ui::LogicalDisplayId::DEFAULT,
14507 DEVICE_ID,
Siarhei Vishniakoued89cbb2023-10-13 10:42:44 -070014508 /*pointerId=*/0));
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -070014509 ASSERT_FALSE(mDispatcher->isPointerInWindow(right->getToken(), ui::LogicalDisplayId::DEFAULT,
14510 DEVICE_ID,
Siarhei Vishniakoued89cbb2023-10-13 10:42:44 -070014511 /*pointerId=*/0));
14512
14513 // Hover move into the window.
14514 mDispatcher->notifyMotion(
14515 MotionArgsBuilder(ACTION_HOVER_MOVE, AINPUT_SOURCE_MOUSE)
14516 .pointer(PointerBuilder(/*id=*/0, ToolType::MOUSE).x(50).y(50))
14517 .rawXCursorPosition(50)
14518 .rawYCursorPosition(50)
14519 .deviceId(DEVICE_ID)
14520 .build());
14521
14522 left->consumeMotionEvent(WithMotionAction(ACTION_HOVER_ENTER));
14523
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -070014524 ASSERT_TRUE(mDispatcher->isPointerInWindow(left->getToken(), ui::LogicalDisplayId::DEFAULT,
14525 DEVICE_ID,
Siarhei Vishniakoued89cbb2023-10-13 10:42:44 -070014526 /*pointerId=*/0));
14527
14528 // Move the mouse with another device
14529 mDispatcher->notifyMotion(
14530 MotionArgsBuilder(ACTION_HOVER_MOVE, AINPUT_SOURCE_MOUSE)
14531 .pointer(PointerBuilder(/*id=*/0, ToolType::MOUSE).x(51).y(50))
14532 .rawXCursorPosition(51)
14533 .rawYCursorPosition(50)
14534 .deviceId(SECOND_DEVICE_ID)
14535 .build());
14536 left->consumeMotionEvent(WithMotionAction(ACTION_HOVER_ENTER));
14537
14538 // TODO(b/313689709): InputDispatcher's touch state is not updated, even though the window gets
14539 // a HOVER_EXIT from the first device.
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -070014540 ASSERT_TRUE(mDispatcher->isPointerInWindow(left->getToken(), ui::LogicalDisplayId::DEFAULT,
14541 DEVICE_ID,
Siarhei Vishniakoued89cbb2023-10-13 10:42:44 -070014542 /*pointerId=*/0));
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -070014543 ASSERT_TRUE(mDispatcher->isPointerInWindow(left->getToken(), ui::LogicalDisplayId::DEFAULT,
Siarhei Vishniakoued89cbb2023-10-13 10:42:44 -070014544 SECOND_DEVICE_ID,
14545 /*pointerId=*/0));
14546
14547 // Move the mouse outside the window. Document the current behavior, where the window does not
14548 // receive HOVER_EXIT even though the mouse left the window.
14549 mDispatcher->notifyMotion(
14550 MotionArgsBuilder(ACTION_HOVER_MOVE, AINPUT_SOURCE_MOUSE)
14551 .pointer(PointerBuilder(/*id=*/0, ToolType::MOUSE).x(150).y(50))
14552 .rawXCursorPosition(150)
14553 .rawYCursorPosition(50)
14554 .deviceId(SECOND_DEVICE_ID)
14555 .build());
14556
14557 right->consumeMotionEvent(WithMotionAction(ACTION_HOVER_ENTER));
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -070014558 ASSERT_TRUE(mDispatcher->isPointerInWindow(left->getToken(), ui::LogicalDisplayId::DEFAULT,
14559 DEVICE_ID,
Siarhei Vishniakoued89cbb2023-10-13 10:42:44 -070014560 /*pointerId=*/0));
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -070014561 ASSERT_FALSE(mDispatcher->isPointerInWindow(left->getToken(), ui::LogicalDisplayId::DEFAULT,
Siarhei Vishniakoued89cbb2023-10-13 10:42:44 -070014562 SECOND_DEVICE_ID,
14563 /*pointerId=*/0));
14564}
14565
Arpit Singhb65e2bd2024-06-03 09:48:16 +000014566TEST_F(InputDispatcherTest, FocusedDisplayChangeIsNotified) {
14567 mDispatcher->setFocusedDisplay(SECOND_DISPLAY_ID);
14568 mFakePolicy->assertFocusedDisplayNotified(SECOND_DISPLAY_ID);
14569}
14570
Garfield Tane84e6f92019-08-29 17:28:41 -070014571} // namespace android::inputdispatcher