blob: bc173b16ce2e7b2d12aa24346f07a6c1d75153aa [file] [log] [blame]
Michael Wrightd02c5b62014-02-10 15:10:22 -08001/*
2 * Copyright (C) 2010 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
Garfield Tan0fc2fa72019-08-29 17:22:15 -070017#include "../dispatcher/InputDispatcher.h"
Siarhei Vishniakou2defec02023-06-08 17:24:44 -070018#include "FakeApplicationHandle.h"
Prabir Pradhan81e89fe2024-03-20 21:17:09 +000019#include "FakeInputDispatcherPolicy.h"
Prabir Pradhandc3a2ad2024-02-05 19:03:51 +000020#include "FakeInputTracingBackend.h"
Prabir Pradhanc5340732024-03-20 22:53:52 +000021#include "FakeWindows.h"
Prabir Pradhane3b28dd2023-10-06 04:19:29 +000022#include "TestEventMatchers.h"
Michael Wrightd02c5b62014-02-10 15:10:22 -080023
Cody Heiner166a5af2023-07-07 12:25:00 -070024#include <NotifyArgsBuilders.h>
Prabir Pradhan5893d362023-11-17 04:30:40 +000025#include <android-base/logging.h>
Siarhei Vishniakou1c494c52021-08-11 20:25:01 -070026#include <android-base/properties.h>
Prabir Pradhana3ab87a2022-01-27 10:00:21 -080027#include <android-base/silent_death_test.h>
Garfield Tan1c7bc862020-01-28 13:24:04 -080028#include <android-base/stringprintf.h>
Siarhei Vishniakou4cb50ca2020-05-26 21:43:02 -070029#include <android-base/thread_annotations.h>
Robert Carr803535b2018-08-02 16:38:15 -070030#include <binder/Binder.h>
Ameer Armalycff4fa52023-10-04 23:45:11 +000031#include <com_android_input_flags.h>
Michael Wright8e9a8562022-02-09 13:44:29 +000032#include <fcntl.h>
Ameer Armalycff4fa52023-10-04 23:45:11 +000033#include <flag_macros.h>
Siarhei Vishniakou0b0374d2022-11-17 17:40:53 -080034#include <gmock/gmock.h>
Michael Wrightd02c5b62014-02-10 15:10:22 -080035#include <gtest/gtest.h>
Siarhei Vishniakou3782af62024-03-07 21:56:39 -080036#include <input/BlockingQueue.h>
Siarhei Vishniakou870ecec2020-12-09 08:07:46 -100037#include <input/Input.h>
Siarhei Vishniakou0438ca82024-03-12 14:27:25 -070038#include <input/InputConsumer.h>
Siarhei Vishniakouf4043212023-09-18 19:33:03 -070039#include <input/PrintTools.h>
Michael Wrightd02c5b62014-02-10 15:10:22 -080040#include <linux/input.h>
Prabir Pradhan07e05b62021-11-19 03:57:24 -080041#include <sys/epoll.h>
Siarhei Vishniakou870ecec2020-12-09 08:07:46 -100042
Garfield Tan1c7bc862020-01-28 13:24:04 -080043#include <cinttypes>
Siarhei Vishniakou487c49b2022-12-02 15:48:57 -080044#include <compare>
Siarhei Vishniakou4cb50ca2020-05-26 21:43:02 -070045#include <thread>
Garfield Tan1c7bc862020-01-28 13:24:04 -080046#include <unordered_set>
chaviwd1c23182019-12-20 18:44:56 -080047#include <vector>
Michael Wrightd02c5b62014-02-10 15:10:22 -080048
Garfield Tan1c7bc862020-01-28 13:24:04 -080049using android::base::StringPrintf;
chaviw3277faf2021-05-19 16:45:23 -050050using android::gui::FocusRequest;
51using android::gui::TouchOcclusionMode;
52using android::gui::WindowInfo;
53using android::gui::WindowInfoHandle;
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -080054using android::os::InputEventInjectionResult;
55using android::os::InputEventInjectionSync;
Garfield Tan1c7bc862020-01-28 13:24:04 -080056
Garfield Tane84e6f92019-08-29 17:28:41 -070057namespace android::inputdispatcher {
Michael Wrightd02c5b62014-02-10 15:10:22 -080058
Dominik Laskowski2f01d772022-03-23 16:01:29 -070059using namespace ftl::flag_operators;
Siarhei Vishniakou0b0374d2022-11-17 17:40:53 -080060using testing::AllOf;
Prabir Pradhan5893d362023-11-17 04:30:40 +000061using testing::Not;
Siarhei Vishniakou85eb5802024-04-01 11:40:59 -070062using testing::Pointee;
63using testing::UnorderedElementsAre;
Dominik Laskowski2f01d772022-03-23 16:01:29 -070064
Siarhei Vishniakouf4043212023-09-18 19:33:03 -070065namespace {
66
Michael Wrightd02c5b62014-02-10 15:10:22 -080067// An arbitrary time value.
Prabir Pradhan5735a322022-04-11 17:23:34 +000068static constexpr nsecs_t ARBITRARY_TIME = 1234;
Michael Wrightd02c5b62014-02-10 15:10:22 -080069
70// An arbitrary device id.
Prabir Pradhan9205e422023-05-16 20:06:13 +000071static constexpr int32_t DEVICE_ID = DEFAULT_DEVICE_ID;
Siarhei Vishniakou060f82b2023-01-27 06:39:14 -080072static constexpr int32_t SECOND_DEVICE_ID = 2;
Michael Wrightd02c5b62014-02-10 15:10:22 -080073
Jeff Brownf086ddb2014-02-11 14:28:48 -080074// An arbitrary display id.
Arthur Hungabbb9d82021-09-01 14:52:30 +000075static constexpr int32_t DISPLAY_ID = ADISPLAY_ID_DEFAULT;
76static constexpr int32_t SECOND_DISPLAY_ID = 1;
Jeff Brownf086ddb2014-02-11 14:28:48 -080077
Prabir Pradhan8ede1d12023-05-08 19:37:44 +000078// Ensure common actions are interchangeable between keys and motions for convenience.
79static_assert(AMOTION_EVENT_ACTION_DOWN == AKEY_EVENT_ACTION_DOWN);
80static_assert(AMOTION_EVENT_ACTION_UP == AKEY_EVENT_ACTION_UP);
Siarhei Vishniakouf372b812023-02-14 18:06:51 -080081static constexpr int32_t ACTION_DOWN = AMOTION_EVENT_ACTION_DOWN;
82static constexpr int32_t ACTION_MOVE = AMOTION_EVENT_ACTION_MOVE;
83static constexpr int32_t ACTION_UP = AMOTION_EVENT_ACTION_UP;
84static constexpr int32_t ACTION_HOVER_ENTER = AMOTION_EVENT_ACTION_HOVER_ENTER;
Siarhei Vishniakoua235c042023-05-02 09:59:09 -070085static constexpr int32_t ACTION_HOVER_MOVE = AMOTION_EVENT_ACTION_HOVER_MOVE;
Siarhei Vishniakouf372b812023-02-14 18:06:51 -080086static constexpr int32_t ACTION_HOVER_EXIT = AMOTION_EVENT_ACTION_HOVER_EXIT;
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -070087static constexpr int32_t ACTION_SCROLL = AMOTION_EVENT_ACTION_SCROLL;
Siarhei Vishniakou487c49b2022-12-02 15:48:57 -080088static constexpr int32_t ACTION_OUTSIDE = AMOTION_EVENT_ACTION_OUTSIDE;
Siarhei Vishniakou1ae72f12023-01-29 12:55:30 -080089static constexpr int32_t ACTION_CANCEL = AMOTION_EVENT_ACTION_CANCEL;
Siarhei Vishniakouf372b812023-02-14 18:06:51 -080090/**
91 * The POINTER_DOWN(0) is an unusual, but valid, action. It just means that the new pointer in the
92 * MotionEvent is at the index 0 rather than 1 (or later). That is, the pointer id=0 (which is at
93 * index 0) is the new pointer going down. The same pointer could have been placed at a different
94 * index, and the action would become POINTER_1_DOWN, 2, etc..; these would all be valid. In
95 * general, we try to place pointer id = 0 at the index 0. Of course, this is not possible if
96 * pointer id=0 leaves but the pointer id=1 remains.
97 */
98static constexpr int32_t POINTER_0_DOWN =
99 AMOTION_EVENT_ACTION_POINTER_DOWN | (0 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT);
Siarhei Vishniakoua16e3a22022-03-02 15:26:40 -0800100static constexpr int32_t POINTER_1_DOWN =
101 AMOTION_EVENT_ACTION_POINTER_DOWN | (1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT);
Prabir Pradhanb60b1dc2022-03-15 14:02:35 +0000102static constexpr int32_t POINTER_2_DOWN =
103 AMOTION_EVENT_ACTION_POINTER_DOWN | (2 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT);
Vaibhav Devmurari882bd9b2022-06-23 14:54:54 +0000104static constexpr int32_t POINTER_3_DOWN =
105 AMOTION_EVENT_ACTION_POINTER_DOWN | (3 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT);
Arthur Hungc539dbb2022-12-08 07:45:36 +0000106static constexpr int32_t POINTER_0_UP =
107 AMOTION_EVENT_ACTION_POINTER_UP | (0 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT);
Siarhei Vishniakoua16e3a22022-03-02 15:26:40 -0800108static constexpr int32_t POINTER_1_UP =
109 AMOTION_EVENT_ACTION_POINTER_UP | (1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT);
Harry Cuttsb166c002023-05-09 13:06:05 +0000110static constexpr int32_t POINTER_2_UP =
111 AMOTION_EVENT_ACTION_POINTER_UP | (2 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT);
Siarhei Vishniakoua16e3a22022-03-02 15:26:40 -0800112
Antonio Kantek15beb512022-06-13 22:35:41 +0000113// The default pid and uid for the windows created on the secondary display by the test.
Prabir Pradhanaeebeb42023-06-13 19:53:03 +0000114static constexpr gui::Pid SECONDARY_WINDOW_PID{1010};
Prabir Pradhan8a5c41d2023-06-08 19:13:46 +0000115static constexpr gui::Uid SECONDARY_WINDOW_UID{1012};
Antonio Kantek15beb512022-06-13 22:35:41 +0000116
Siarhei Vishniakou58cfc602020-12-14 23:21:30 +0000117// An arbitrary pid of the gesture monitor window
Prabir Pradhanaeebeb42023-06-13 19:53:03 +0000118static constexpr gui::Pid MONITOR_PID{2001};
Siarhei Vishniakou58cfc602020-12-14 23:21:30 +0000119
Arthur Hungc539dbb2022-12-08 07:45:36 +0000120static constexpr int expectedWallpaperFlags =
121 AMOTION_EVENT_FLAG_WINDOW_IS_OBSCURED | AMOTION_EVENT_FLAG_WINDOW_IS_PARTIALLY_OBSCURED;
122
Siarhei Vishniakou56e79092023-02-21 19:13:16 -0800123using ReservedInputDeviceId::VIRTUAL_KEYBOARD_ID;
124
Gang Wang342c9272020-01-13 13:15:04 -0500125/**
126 * Return a DOWN key event with KEYCODE_A.
127 */
128static KeyEvent getTestKeyEvent() {
129 KeyEvent event;
130
Garfield Tanfbe732e2020-01-24 11:26:14 -0800131 event.initialize(InputEvent::nextId(), DEVICE_ID, AINPUT_SOURCE_KEYBOARD, ADISPLAY_ID_NONE,
132 INVALID_HMAC, AKEY_EVENT_ACTION_DOWN, 0, AKEYCODE_A, KEY_A, AMETA_NONE, 0,
133 ARBITRARY_TIME, ARBITRARY_TIME);
Gang Wang342c9272020-01-13 13:15:04 -0500134 return event;
135}
136
Siarhei Vishniakoued89cbb2023-10-13 10:42:44 -0700137/**
138 * Provide a local override for a flag value. The value is restored when the object of this class
139 * goes out of scope.
140 * This class is not intended to be used directly, because its usage is cumbersome.
141 * Instead, a wrapper macro SCOPED_FLAG_OVERRIDE is provided.
142 */
143class ScopedFlagOverride {
144public:
145 ScopedFlagOverride(std::function<bool()> read, std::function<void(bool)> write, bool value)
146 : mInitialValue(read()), mWriteValue(write) {
147 mWriteValue(value);
148 }
149 ~ScopedFlagOverride() { mWriteValue(mInitialValue); }
150
151private:
152 const bool mInitialValue;
153 std::function<void(bool)> mWriteValue;
154};
155
156typedef bool (*readFlagValueFunction)();
157typedef void (*writeFlagValueFunction)(bool);
158
159/**
160 * Use this macro to locally override a flag value.
161 * Example usage:
162 * SCOPED_FLAG_OVERRIDE(enable_multi_device_same_window_stream, false);
163 * Note: this works by creating a local variable in your current scope. Don't call this twice for
164 * the same flag, because the variable names will clash!
165 */
166#define SCOPED_FLAG_OVERRIDE(NAME, VALUE) \
167 readFlagValueFunction read##NAME = com::android::input::flags::NAME; \
168 writeFlagValueFunction write##NAME = com::android::input::flags::NAME; \
169 ScopedFlagOverride override##NAME(read##NAME, write##NAME, (VALUE))
170
Siarhei Vishniakouf4043212023-09-18 19:33:03 -0700171} // namespace
Michael Wrightd02c5b62014-02-10 15:10:22 -0800172
Michael Wrightd02c5b62014-02-10 15:10:22 -0800173// --- InputDispatcherTest ---
174
175class InputDispatcherTest : public testing::Test {
176protected:
Prabir Pradhana41d2442023-04-20 21:30:40 +0000177 std::unique_ptr<FakeInputDispatcherPolicy> mFakePolicy;
Siarhei Vishniakou18050092021-09-01 13:32:49 -0700178 std::unique_ptr<InputDispatcher> mDispatcher;
Prabir Pradhanc5340732024-03-20 22:53:52 +0000179 std::shared_ptr<VerifyingTrace> mVerifyingTrace;
Michael Wrightd02c5b62014-02-10 15:10:22 -0800180
Siarhei Vishniakouf2652122021-03-05 21:39:46 +0000181 void SetUp() override {
Prabir Pradhanc5340732024-03-20 22:53:52 +0000182 mVerifyingTrace = std::make_shared<VerifyingTrace>();
183 FakeWindowHandle::sOnEventReceivedCallback = [this](const auto& _1, const auto& _2) {
184 handleEventReceivedByWindow(_1, _2);
185 };
186
Prabir Pradhana41d2442023-04-20 21:30:40 +0000187 mFakePolicy = std::make_unique<FakeInputDispatcherPolicy>();
Prabir Pradhandc3a2ad2024-02-05 19:03:51 +0000188 mDispatcher = std::make_unique<InputDispatcher>(*mFakePolicy,
189 std::make_unique<FakeInputTracingBackend>(
Prabir Pradhanc5340732024-03-20 22:53:52 +0000190 mVerifyingTrace));
Siarhei Vishniakoua7333112023-10-27 13:33:29 -0700191
Harry Cutts101ee9b2023-07-06 18:04:14 +0000192 mDispatcher->setInputDispatchMode(/*enabled=*/true, /*frozen=*/false);
Siarhei Vishniakou870ecec2020-12-09 08:07:46 -1000193 // Start InputDispatcher thread
Prabir Pradhan3608aad2019-10-02 17:08:26 -0700194 ASSERT_EQ(OK, mDispatcher->start());
Michael Wrightd02c5b62014-02-10 15:10:22 -0800195 }
196
Siarhei Vishniakouf2652122021-03-05 21:39:46 +0000197 void TearDown() override {
Prabir Pradhanc5340732024-03-20 22:53:52 +0000198 ASSERT_NO_FATAL_FAILURE(mVerifyingTrace->verifyExpectedEventsTraced());
199 FakeWindowHandle::sOnEventReceivedCallback = nullptr;
200
Prabir Pradhan3608aad2019-10-02 17:08:26 -0700201 ASSERT_EQ(OK, mDispatcher->stop());
Prabir Pradhana41d2442023-04-20 21:30:40 +0000202 mFakePolicy.reset();
Siarhei Vishniakou18050092021-09-01 13:32:49 -0700203 mDispatcher.reset();
Michael Wrightd02c5b62014-02-10 15:10:22 -0800204 }
Siarhei Vishniakou4cb50ca2020-05-26 21:43:02 -0700205
Prabir Pradhanc5340732024-03-20 22:53:52 +0000206 void handleEventReceivedByWindow(const std::unique_ptr<InputEvent>& event,
207 const gui::WindowInfo& info) {
208 if (!event) {
209 return;
210 }
211
212 switch (event->getType()) {
213 case InputEventType::KEY: {
214 mVerifyingTrace->expectKeyDispatchTraced(static_cast<KeyEvent&>(*event), info.id);
215 break;
216 }
217 case InputEventType::MOTION: {
218 mVerifyingTrace->expectMotionDispatchTraced(static_cast<MotionEvent&>(*event),
219 info.id);
220 break;
221 }
222 default:
223 break;
224 }
225 }
226
Siarhei Vishniakou4cb50ca2020-05-26 21:43:02 -0700227 /**
228 * Used for debugging when writing the test
229 */
230 void dumpDispatcherState() {
231 std::string dump;
232 mDispatcher->dump(dump);
233 std::stringstream ss(dump);
234 std::string to;
235
236 while (std::getline(ss, to, '\n')) {
237 ALOGE("%s", to.c_str());
238 }
239 }
Vishnu Nair958da932020-08-21 17:12:37 -0700240
Chavi Weingarten847e8512023-03-29 00:26:09 +0000241 void setFocusedWindow(const sp<WindowInfoHandle>& window) {
Vishnu Nair958da932020-08-21 17:12:37 -0700242 FocusRequest request;
243 request.token = window->getToken();
Siarhei Vishniakou5d552c42021-05-21 05:02:22 +0000244 request.windowName = window->getName();
Vishnu Nair958da932020-08-21 17:12:37 -0700245 request.timestamp = systemTime(SYSTEM_TIME_MONOTONIC);
246 request.displayId = window->getInfo()->displayId;
247 mDispatcher->setFocusedWindow(request);
248 }
Michael Wrightd02c5b62014-02-10 15:10:22 -0800249};
250
Michael Wrightd02c5b62014-02-10 15:10:22 -0800251TEST_F(InputDispatcherTest, InjectInputEvent_ValidatesKeyEvents) {
252 KeyEvent event;
253
254 // Rejects undefined key actions.
Garfield Tanfbe732e2020-01-24 11:26:14 -0800255 event.initialize(InputEvent::nextId(), DEVICE_ID, AINPUT_SOURCE_KEYBOARD, ADISPLAY_ID_NONE,
256 INVALID_HMAC,
Harry Cutts101ee9b2023-07-06 18:04:14 +0000257 /*action=*/-1, 0, AKEYCODE_A, KEY_A, AMETA_NONE, 0, ARBITRARY_TIME,
Siarhei Vishniakou9c858ac2020-01-23 14:20:11 -0600258 ARBITRARY_TIME);
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -0800259 ASSERT_EQ(InputEventInjectionResult::FAILED,
Harry Cutts33476232023-01-30 19:57:29 +0000260 mDispatcher->injectInputEvent(&event, /*targetUid=*/{}, InputEventInjectionSync::NONE,
Prabir Pradhan5735a322022-04-11 17:23:34 +0000261 0ms, 0))
Michael Wrightd02c5b62014-02-10 15:10:22 -0800262 << "Should reject key events with undefined action.";
263
264 // Rejects ACTION_MULTIPLE since it is not supported despite being defined in the API.
Garfield Tanfbe732e2020-01-24 11:26:14 -0800265 event.initialize(InputEvent::nextId(), DEVICE_ID, AINPUT_SOURCE_KEYBOARD, ADISPLAY_ID_NONE,
266 INVALID_HMAC, AKEY_EVENT_ACTION_MULTIPLE, 0, AKEYCODE_A, KEY_A, AMETA_NONE, 0,
Siarhei Vishniakou9c858ac2020-01-23 14:20:11 -0600267 ARBITRARY_TIME, ARBITRARY_TIME);
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -0800268 ASSERT_EQ(InputEventInjectionResult::FAILED,
Harry Cutts33476232023-01-30 19:57:29 +0000269 mDispatcher->injectInputEvent(&event, /*targetUid=*/{}, InputEventInjectionSync::NONE,
Prabir Pradhan5735a322022-04-11 17:23:34 +0000270 0ms, 0))
Michael Wrightd02c5b62014-02-10 15:10:22 -0800271 << "Should reject key events with ACTION_MULTIPLE.";
272}
273
274TEST_F(InputDispatcherTest, InjectInputEvent_ValidatesMotionEvents) {
275 MotionEvent event;
276 PointerProperties pointerProperties[MAX_POINTERS + 1];
277 PointerCoords pointerCoords[MAX_POINTERS + 1];
Siarhei Vishniakou01747382022-01-20 13:23:27 -0800278 for (size_t i = 0; i <= MAX_POINTERS; i++) {
Michael Wrightd02c5b62014-02-10 15:10:22 -0800279 pointerProperties[i].clear();
280 pointerProperties[i].id = i;
281 pointerCoords[i].clear();
282 }
283
Siarhei Vishniakou49e59222018-12-28 18:17:15 -0800284 // Some constants commonly used below
285 constexpr int32_t source = AINPUT_SOURCE_TOUCHSCREEN;
286 constexpr int32_t edgeFlags = AMOTION_EVENT_EDGE_FLAG_NONE;
287 constexpr int32_t metaState = AMETA_NONE;
288 constexpr MotionClassification classification = MotionClassification::NONE;
289
chaviw9eaa22c2020-07-01 16:21:27 -0700290 ui::Transform identityTransform;
Michael Wrightd02c5b62014-02-10 15:10:22 -0800291 // Rejects undefined motion actions.
Garfield Tanfbe732e2020-01-24 11:26:14 -0800292 event.initialize(InputEvent::nextId(), DEVICE_ID, source, DISPLAY_ID, INVALID_HMAC,
Harry Cutts101ee9b2023-07-06 18:04:14 +0000293 /*action=*/-1, 0, 0, edgeFlags, metaState, 0, classification,
chaviw9eaa22c2020-07-01 16:21:27 -0700294 identityTransform, 0, 0, AMOTION_EVENT_INVALID_CURSOR_POSITION,
Prabir Pradhanb9b18502021-08-26 12:30:32 -0700295 AMOTION_EVENT_INVALID_CURSOR_POSITION, identityTransform, ARBITRARY_TIME,
296 ARBITRARY_TIME,
Harry Cutts101ee9b2023-07-06 18:04:14 +0000297 /*pointerCount=*/1, pointerProperties, pointerCoords);
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -0800298 ASSERT_EQ(InputEventInjectionResult::FAILED,
Harry Cutts33476232023-01-30 19:57:29 +0000299 mDispatcher->injectInputEvent(&event, /*targetUid=*/{}, InputEventInjectionSync::NONE,
Prabir Pradhan5735a322022-04-11 17:23:34 +0000300 0ms, 0))
Michael Wrightd02c5b62014-02-10 15:10:22 -0800301 << "Should reject motion events with undefined action.";
302
303 // Rejects pointer down with invalid index.
Garfield Tanfbe732e2020-01-24 11:26:14 -0800304 event.initialize(InputEvent::nextId(), DEVICE_ID, source, DISPLAY_ID, INVALID_HMAC,
Siarhei Vishniakoua16e3a22022-03-02 15:26:40 -0800305 POINTER_1_DOWN, 0, 0, edgeFlags, metaState, 0, classification,
306 identityTransform, 0, 0, AMOTION_EVENT_INVALID_CURSOR_POSITION,
307 AMOTION_EVENT_INVALID_CURSOR_POSITION, identityTransform, ARBITRARY_TIME,
308 ARBITRARY_TIME,
Harry Cutts101ee9b2023-07-06 18:04:14 +0000309 /*pointerCount=*/1, pointerProperties, pointerCoords);
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -0800310 ASSERT_EQ(InputEventInjectionResult::FAILED,
Harry Cutts33476232023-01-30 19:57:29 +0000311 mDispatcher->injectInputEvent(&event, /*targetUid=*/{}, InputEventInjectionSync::NONE,
Prabir Pradhan5735a322022-04-11 17:23:34 +0000312 0ms, 0))
Michael Wrightd02c5b62014-02-10 15:10:22 -0800313 << "Should reject motion events with pointer down index too large.";
314
Garfield Tanfbe732e2020-01-24 11:26:14 -0800315 event.initialize(InputEvent::nextId(), DEVICE_ID, source, DISPLAY_ID, INVALID_HMAC,
Garfield Tan00f511d2019-06-12 16:55:40 -0700316 AMOTION_EVENT_ACTION_POINTER_DOWN |
317 (~0U << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT),
chaviw9eaa22c2020-07-01 16:21:27 -0700318 0, 0, edgeFlags, metaState, 0, classification, identityTransform, 0, 0,
319 AMOTION_EVENT_INVALID_CURSOR_POSITION, AMOTION_EVENT_INVALID_CURSOR_POSITION,
Prabir Pradhanb9b18502021-08-26 12:30:32 -0700320 identityTransform, ARBITRARY_TIME, ARBITRARY_TIME,
Harry Cutts101ee9b2023-07-06 18:04:14 +0000321 /*pointerCount=*/1, pointerProperties, pointerCoords);
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -0800322 ASSERT_EQ(InputEventInjectionResult::FAILED,
Harry Cutts33476232023-01-30 19:57:29 +0000323 mDispatcher->injectInputEvent(&event, /*targetUid=*/{}, InputEventInjectionSync::NONE,
Prabir Pradhan5735a322022-04-11 17:23:34 +0000324 0ms, 0))
Michael Wrightd02c5b62014-02-10 15:10:22 -0800325 << "Should reject motion events with pointer down index too small.";
326
327 // Rejects pointer up with invalid index.
Garfield Tanfbe732e2020-01-24 11:26:14 -0800328 event.initialize(InputEvent::nextId(), DEVICE_ID, source, DISPLAY_ID, INVALID_HMAC,
Siarhei Vishniakoua16e3a22022-03-02 15:26:40 -0800329 POINTER_1_UP, 0, 0, edgeFlags, metaState, 0, classification, identityTransform,
330 0, 0, AMOTION_EVENT_INVALID_CURSOR_POSITION,
331 AMOTION_EVENT_INVALID_CURSOR_POSITION, identityTransform, ARBITRARY_TIME,
332 ARBITRARY_TIME,
Harry Cutts101ee9b2023-07-06 18:04:14 +0000333 /*pointerCount=*/1, pointerProperties, pointerCoords);
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -0800334 ASSERT_EQ(InputEventInjectionResult::FAILED,
Harry Cutts33476232023-01-30 19:57:29 +0000335 mDispatcher->injectInputEvent(&event, /*targetUid=*/{}, InputEventInjectionSync::NONE,
Prabir Pradhan5735a322022-04-11 17:23:34 +0000336 0ms, 0))
Michael Wrightd02c5b62014-02-10 15:10:22 -0800337 << "Should reject motion events with pointer up index too large.";
338
Garfield Tanfbe732e2020-01-24 11:26:14 -0800339 event.initialize(InputEvent::nextId(), DEVICE_ID, source, DISPLAY_ID, INVALID_HMAC,
Garfield Tan00f511d2019-06-12 16:55:40 -0700340 AMOTION_EVENT_ACTION_POINTER_UP |
341 (~0U << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT),
chaviw9eaa22c2020-07-01 16:21:27 -0700342 0, 0, edgeFlags, metaState, 0, classification, identityTransform, 0, 0,
343 AMOTION_EVENT_INVALID_CURSOR_POSITION, AMOTION_EVENT_INVALID_CURSOR_POSITION,
Prabir Pradhanb9b18502021-08-26 12:30:32 -0700344 identityTransform, ARBITRARY_TIME, ARBITRARY_TIME,
Harry Cutts101ee9b2023-07-06 18:04:14 +0000345 /*pointerCount=*/1, pointerProperties, pointerCoords);
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -0800346 ASSERT_EQ(InputEventInjectionResult::FAILED,
Harry Cutts33476232023-01-30 19:57:29 +0000347 mDispatcher->injectInputEvent(&event, /*targetUid=*/{}, InputEventInjectionSync::NONE,
Prabir Pradhan5735a322022-04-11 17:23:34 +0000348 0ms, 0))
Michael Wrightd02c5b62014-02-10 15:10:22 -0800349 << "Should reject motion events with pointer up index too small.";
350
351 // Rejects motion events with invalid number of pointers.
Garfield Tanfbe732e2020-01-24 11:26:14 -0800352 event.initialize(InputEvent::nextId(), DEVICE_ID, source, DISPLAY_ID, INVALID_HMAC,
353 AMOTION_EVENT_ACTION_DOWN, 0, 0, edgeFlags, metaState, 0, classification,
chaviw9eaa22c2020-07-01 16:21:27 -0700354 identityTransform, 0, 0, AMOTION_EVENT_INVALID_CURSOR_POSITION,
Prabir Pradhanb9b18502021-08-26 12:30:32 -0700355 AMOTION_EVENT_INVALID_CURSOR_POSITION, identityTransform, ARBITRARY_TIME,
356 ARBITRARY_TIME,
Harry Cutts101ee9b2023-07-06 18:04:14 +0000357 /*pointerCount=*/0, pointerProperties, pointerCoords);
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -0800358 ASSERT_EQ(InputEventInjectionResult::FAILED,
Harry Cutts33476232023-01-30 19:57:29 +0000359 mDispatcher->injectInputEvent(&event, /*targetUid=*/{}, InputEventInjectionSync::NONE,
Prabir Pradhan5735a322022-04-11 17:23:34 +0000360 0ms, 0))
Michael Wrightd02c5b62014-02-10 15:10:22 -0800361 << "Should reject motion events with 0 pointers.";
362
Garfield Tanfbe732e2020-01-24 11:26:14 -0800363 event.initialize(InputEvent::nextId(), DEVICE_ID, source, DISPLAY_ID, INVALID_HMAC,
364 AMOTION_EVENT_ACTION_DOWN, 0, 0, edgeFlags, metaState, 0, classification,
chaviw9eaa22c2020-07-01 16:21:27 -0700365 identityTransform, 0, 0, AMOTION_EVENT_INVALID_CURSOR_POSITION,
Prabir Pradhanb9b18502021-08-26 12:30:32 -0700366 AMOTION_EVENT_INVALID_CURSOR_POSITION, identityTransform, ARBITRARY_TIME,
367 ARBITRARY_TIME,
Harry Cutts101ee9b2023-07-06 18:04:14 +0000368 /*pointerCount=*/MAX_POINTERS + 1, pointerProperties, pointerCoords);
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -0800369 ASSERT_EQ(InputEventInjectionResult::FAILED,
Harry Cutts33476232023-01-30 19:57:29 +0000370 mDispatcher->injectInputEvent(&event, /*targetUid=*/{}, InputEventInjectionSync::NONE,
Prabir Pradhan5735a322022-04-11 17:23:34 +0000371 0ms, 0))
Michael Wrightd02c5b62014-02-10 15:10:22 -0800372 << "Should reject motion events with more than MAX_POINTERS pointers.";
373
374 // Rejects motion events with invalid pointer ids.
375 pointerProperties[0].id = -1;
Garfield Tanfbe732e2020-01-24 11:26:14 -0800376 event.initialize(InputEvent::nextId(), DEVICE_ID, source, DISPLAY_ID, INVALID_HMAC,
377 AMOTION_EVENT_ACTION_DOWN, 0, 0, edgeFlags, metaState, 0, classification,
chaviw9eaa22c2020-07-01 16:21:27 -0700378 identityTransform, 0, 0, AMOTION_EVENT_INVALID_CURSOR_POSITION,
Prabir Pradhanb9b18502021-08-26 12:30:32 -0700379 AMOTION_EVENT_INVALID_CURSOR_POSITION, identityTransform, ARBITRARY_TIME,
380 ARBITRARY_TIME,
Harry Cutts101ee9b2023-07-06 18:04:14 +0000381 /*pointerCount=*/1, pointerProperties, pointerCoords);
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -0800382 ASSERT_EQ(InputEventInjectionResult::FAILED,
Harry Cutts33476232023-01-30 19:57:29 +0000383 mDispatcher->injectInputEvent(&event, /*targetUid=*/{}, InputEventInjectionSync::NONE,
Prabir Pradhan5735a322022-04-11 17:23:34 +0000384 0ms, 0))
Michael Wrightd02c5b62014-02-10 15:10:22 -0800385 << "Should reject motion events with pointer ids less than 0.";
386
387 pointerProperties[0].id = MAX_POINTER_ID + 1;
Garfield Tanfbe732e2020-01-24 11:26:14 -0800388 event.initialize(InputEvent::nextId(), DEVICE_ID, source, DISPLAY_ID, INVALID_HMAC,
389 AMOTION_EVENT_ACTION_DOWN, 0, 0, edgeFlags, metaState, 0, classification,
chaviw9eaa22c2020-07-01 16:21:27 -0700390 identityTransform, 0, 0, AMOTION_EVENT_INVALID_CURSOR_POSITION,
Prabir Pradhanb9b18502021-08-26 12:30:32 -0700391 AMOTION_EVENT_INVALID_CURSOR_POSITION, identityTransform, ARBITRARY_TIME,
392 ARBITRARY_TIME,
Harry Cutts101ee9b2023-07-06 18:04:14 +0000393 /*pointerCount=*/1, pointerProperties, pointerCoords);
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -0800394 ASSERT_EQ(InputEventInjectionResult::FAILED,
Harry Cutts33476232023-01-30 19:57:29 +0000395 mDispatcher->injectInputEvent(&event, /*targetUid=*/{}, InputEventInjectionSync::NONE,
Prabir Pradhan5735a322022-04-11 17:23:34 +0000396 0ms, 0))
Michael Wrightd02c5b62014-02-10 15:10:22 -0800397 << "Should reject motion events with pointer ids greater than MAX_POINTER_ID.";
398
399 // Rejects motion events with duplicate pointer ids.
400 pointerProperties[0].id = 1;
401 pointerProperties[1].id = 1;
Garfield Tanfbe732e2020-01-24 11:26:14 -0800402 event.initialize(InputEvent::nextId(), DEVICE_ID, source, DISPLAY_ID, INVALID_HMAC,
403 AMOTION_EVENT_ACTION_DOWN, 0, 0, edgeFlags, metaState, 0, classification,
chaviw9eaa22c2020-07-01 16:21:27 -0700404 identityTransform, 0, 0, AMOTION_EVENT_INVALID_CURSOR_POSITION,
Prabir Pradhanb9b18502021-08-26 12:30:32 -0700405 AMOTION_EVENT_INVALID_CURSOR_POSITION, identityTransform, ARBITRARY_TIME,
406 ARBITRARY_TIME,
Harry Cutts101ee9b2023-07-06 18:04:14 +0000407 /*pointerCount=*/2, pointerProperties, pointerCoords);
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -0800408 ASSERT_EQ(InputEventInjectionResult::FAILED,
Harry Cutts33476232023-01-30 19:57:29 +0000409 mDispatcher->injectInputEvent(&event, /*targetUid=*/{}, InputEventInjectionSync::NONE,
Prabir Pradhan5735a322022-04-11 17:23:34 +0000410 0ms, 0))
Michael Wrightd02c5b62014-02-10 15:10:22 -0800411 << "Should reject motion events with duplicate pointer ids.";
412}
413
Siarhei Vishniakou2bfa9052019-11-21 18:10:54 -0800414/* Test InputDispatcher for notifyConfigurationChanged and notifySwitch events */
415
416TEST_F(InputDispatcherTest, NotifyConfigurationChanged_CallsPolicy) {
417 constexpr nsecs_t eventTime = 20;
Prabir Pradhan678438e2023-04-13 19:32:51 +0000418 mDispatcher->notifyConfigurationChanged({/*id=*/10, eventTime});
Siarhei Vishniakou2bfa9052019-11-21 18:10:54 -0800419 ASSERT_TRUE(mDispatcher->waitForIdle());
420
421 mFakePolicy->assertNotifyConfigurationChangedWasCalled(eventTime);
422}
423
424TEST_F(InputDispatcherTest, NotifySwitch_CallsPolicy) {
Prabir Pradhana8fe7c52023-12-14 22:07:23 +0000425 NotifySwitchArgs args(InputEvent::nextId(), /*eventTime=*/20, /*policyFlags=*/0,
426 /*switchValues=*/1,
Harry Cutts33476232023-01-30 19:57:29 +0000427 /*switchMask=*/2);
Prabir Pradhan678438e2023-04-13 19:32:51 +0000428 mDispatcher->notifySwitch(args);
Siarhei Vishniakou2bfa9052019-11-21 18:10:54 -0800429
430 // InputDispatcher adds POLICY_FLAG_TRUSTED because the event went through InputListener
431 args.policyFlags |= POLICY_FLAG_TRUSTED;
432 mFakePolicy->assertNotifySwitchWasCalled(args);
433}
434
Siarhei Vishniakouadeb6fa2023-05-26 09:11:06 -0700435namespace {
436
Siarhei Vishniakou097c3db2020-05-06 14:18:38 -0700437static constexpr std::chrono::duration INJECT_EVENT_TIMEOUT = 500ms;
Siarhei Vishniakou540dbae2020-05-05 18:17:17 -0700438
Prabir Pradhan112b1ad2023-09-21 09:53:53 +0000439class FakeMonitorReceiver {
440public:
Siarhei Vishniakou2defec02023-06-08 17:24:44 -0700441 FakeMonitorReceiver(InputDispatcher& dispatcher, const std::string name, int32_t displayId)
442 : mInputReceiver(*dispatcher.createInputMonitor(displayId, name, MONITOR_PID), name) {}
Prabir Pradhan112b1ad2023-09-21 09:53:53 +0000443
Siarhei Vishniakou2defec02023-06-08 17:24:44 -0700444 sp<IBinder> getToken() { return mInputReceiver.getToken(); }
Prabir Pradhan112b1ad2023-09-21 09:53:53 +0000445
446 void consumeKeyDown(int32_t expectedDisplayId, int32_t expectedFlags = 0) {
Siarhei Vishniakou2defec02023-06-08 17:24:44 -0700447 mInputReceiver.consumeEvent(InputEventType::KEY, AKEY_EVENT_ACTION_DOWN, expectedDisplayId,
448 expectedFlags);
Prabir Pradhan112b1ad2023-09-21 09:53:53 +0000449 }
450
451 std::optional<int32_t> receiveEvent() {
Siarhei Vishniakoud3061ab2023-12-18 20:41:08 -0800452 const auto [sequenceNum, _] = mInputReceiver.receiveEvent(CONSUME_TIMEOUT_EVENT_EXPECTED);
453 return sequenceNum;
Prabir Pradhan112b1ad2023-09-21 09:53:53 +0000454 }
455
Siarhei Vishniakou2defec02023-06-08 17:24:44 -0700456 void finishEvent(uint32_t consumeSeq) { return mInputReceiver.finishEvent(consumeSeq); }
Prabir Pradhan112b1ad2023-09-21 09:53:53 +0000457
458 void consumeMotionDown(int32_t expectedDisplayId, int32_t expectedFlags = 0) {
Siarhei Vishniakou2defec02023-06-08 17:24:44 -0700459 mInputReceiver.consumeEvent(InputEventType::MOTION, AMOTION_EVENT_ACTION_DOWN,
460 expectedDisplayId, expectedFlags);
Prabir Pradhan112b1ad2023-09-21 09:53:53 +0000461 }
462
463 void consumeMotionMove(int32_t expectedDisplayId, int32_t expectedFlags = 0) {
Siarhei Vishniakou2defec02023-06-08 17:24:44 -0700464 mInputReceiver.consumeEvent(InputEventType::MOTION, AMOTION_EVENT_ACTION_MOVE,
465 expectedDisplayId, expectedFlags);
Prabir Pradhan112b1ad2023-09-21 09:53:53 +0000466 }
467
468 void consumeMotionUp(int32_t expectedDisplayId, int32_t expectedFlags = 0) {
Siarhei Vishniakou2defec02023-06-08 17:24:44 -0700469 mInputReceiver.consumeEvent(InputEventType::MOTION, AMOTION_EVENT_ACTION_UP,
470 expectedDisplayId, expectedFlags);
Prabir Pradhan112b1ad2023-09-21 09:53:53 +0000471 }
472
473 void consumeMotionCancel(int32_t expectedDisplayId, int32_t expectedFlags = 0) {
Siarhei Vishniakou2defec02023-06-08 17:24:44 -0700474 mInputReceiver.consumeMotionEvent(
Prabir Pradhan112b1ad2023-09-21 09:53:53 +0000475 AllOf(WithMotionAction(AMOTION_EVENT_ACTION_CANCEL),
476 WithDisplayId(expectedDisplayId),
477 WithFlags(expectedFlags | AMOTION_EVENT_FLAG_CANCELED)));
478 }
479
480 void consumeMotionPointerDown(int32_t pointerIdx) {
481 int32_t action = AMOTION_EVENT_ACTION_POINTER_DOWN |
482 (pointerIdx << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT);
Siarhei Vishniakou2defec02023-06-08 17:24:44 -0700483 mInputReceiver.consumeEvent(InputEventType::MOTION, action, ADISPLAY_ID_DEFAULT,
484 /*expectedFlags=*/0);
Prabir Pradhan112b1ad2023-09-21 09:53:53 +0000485 }
486
487 void consumeMotionEvent(const ::testing::Matcher<MotionEvent>& matcher) {
Siarhei Vishniakou2defec02023-06-08 17:24:44 -0700488 mInputReceiver.consumeMotionEvent(matcher);
Prabir Pradhan112b1ad2023-09-21 09:53:53 +0000489 }
490
Siarhei Vishniakoud3061ab2023-12-18 20:41:08 -0800491 std::unique_ptr<MotionEvent> consumeMotion() { return mInputReceiver.consumeMotion(); }
Prabir Pradhan112b1ad2023-09-21 09:53:53 +0000492
Siarhei Vishniakouef2b4502023-12-28 11:51:47 -0800493 void assertNoEvents() { mInputReceiver.assertNoEvents(CONSUME_TIMEOUT_NO_EVENT_EXPECTED); }
Prabir Pradhan112b1ad2023-09-21 09:53:53 +0000494
495private:
Siarhei Vishniakou2defec02023-06-08 17:24:44 -0700496 FakeInputReceiver mInputReceiver;
Prabir Pradhan112b1ad2023-09-21 09:53:53 +0000497};
498
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -0800499static InputEventInjectionResult injectKey(
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -0700500 InputDispatcher& dispatcher, int32_t action, int32_t repeatCount,
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -0800501 int32_t displayId = ADISPLAY_ID_NONE,
502 InputEventInjectionSync syncMode = InputEventInjectionSync::WAIT_FOR_RESULT,
Prabir Pradhan93f342c2021-03-11 15:05:30 -0800503 std::chrono::milliseconds injectionTimeout = INJECT_EVENT_TIMEOUT,
Prabir Pradhan8a5c41d2023-06-08 19:13:46 +0000504 bool allowKeyRepeat = true, std::optional<gui::Uid> targetUid = {},
Prabir Pradhan5735a322022-04-11 17:23:34 +0000505 uint32_t policyFlags = DEFAULT_POLICY_FLAGS) {
Arthur Hungb92218b2018-08-14 12:00:21 +0800506 KeyEvent event;
507 nsecs_t currentTime = systemTime(SYSTEM_TIME_MONOTONIC);
508
509 // Define a valid key down event.
Garfield Tanfbe732e2020-01-24 11:26:14 -0800510 event.initialize(InputEvent::nextId(), DEVICE_ID, AINPUT_SOURCE_KEYBOARD, displayId,
Harry Cutts33476232023-01-30 19:57:29 +0000511 INVALID_HMAC, action, /*flags=*/0, AKEYCODE_A, KEY_A, AMETA_NONE, repeatCount,
512 currentTime, currentTime);
Arthur Hungb92218b2018-08-14 12:00:21 +0800513
Prabir Pradhan93f342c2021-03-11 15:05:30 -0800514 if (!allowKeyRepeat) {
515 policyFlags |= POLICY_FLAG_DISABLE_KEY_REPEAT;
516 }
Arthur Hungb92218b2018-08-14 12:00:21 +0800517 // Inject event until dispatch out.
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -0700518 return dispatcher.injectInputEvent(&event, targetUid, syncMode, injectionTimeout, policyFlags);
Arthur Hungb92218b2018-08-14 12:00:21 +0800519}
520
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -0700521static void assertInjectedKeyTimesOut(InputDispatcher& dispatcher) {
522 InputEventInjectionResult result =
523 injectKey(dispatcher, AKEY_EVENT_ACTION_DOWN, /*repeatCount=*/0, ADISPLAY_ID_NONE,
524 InputEventInjectionSync::WAIT_FOR_RESULT, CONSUME_TIMEOUT_NO_EVENT_EXPECTED);
525 if (result != InputEventInjectionResult::TIMED_OUT) {
526 FAIL() << "Injection should have timed out, but got " << ftl::enum_string(result);
527 }
528}
529
530static InputEventInjectionResult injectKeyDown(InputDispatcher& dispatcher,
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -0800531 int32_t displayId = ADISPLAY_ID_NONE) {
Harry Cutts33476232023-01-30 19:57:29 +0000532 return injectKey(dispatcher, AKEY_EVENT_ACTION_DOWN, /*repeatCount=*/0, displayId);
Siarhei Vishniakou4cb50ca2020-05-26 21:43:02 -0700533}
534
Prabir Pradhan93f342c2021-03-11 15:05:30 -0800535// Inject a down event that has key repeat disabled. This allows InputDispatcher to idle without
536// sending a subsequent key up. When key repeat is enabled, the dispatcher cannot idle because it
537// has to be woken up to process the repeating key.
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -0700538static InputEventInjectionResult injectKeyDownNoRepeat(InputDispatcher& dispatcher,
539 int32_t displayId = ADISPLAY_ID_NONE) {
Harry Cutts33476232023-01-30 19:57:29 +0000540 return injectKey(dispatcher, AKEY_EVENT_ACTION_DOWN, /*repeatCount=*/0, displayId,
Prabir Pradhan93f342c2021-03-11 15:05:30 -0800541 InputEventInjectionSync::WAIT_FOR_RESULT, INJECT_EVENT_TIMEOUT,
Harry Cutts33476232023-01-30 19:57:29 +0000542 /*allowKeyRepeat=*/false);
Prabir Pradhan93f342c2021-03-11 15:05:30 -0800543}
544
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -0700545static InputEventInjectionResult injectKeyUp(InputDispatcher& dispatcher,
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -0800546 int32_t displayId = ADISPLAY_ID_NONE) {
Harry Cutts33476232023-01-30 19:57:29 +0000547 return injectKey(dispatcher, AKEY_EVENT_ACTION_UP, /*repeatCount=*/0, displayId);
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -0700548}
549
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -0800550static InputEventInjectionResult injectMotionEvent(
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -0700551 InputDispatcher& dispatcher, const MotionEvent& event,
Garfield Tandf26e862020-07-01 20:18:19 -0700552 std::chrono::milliseconds injectionTimeout = INJECT_EVENT_TIMEOUT,
Prabir Pradhan5735a322022-04-11 17:23:34 +0000553 InputEventInjectionSync injectionMode = InputEventInjectionSync::WAIT_FOR_RESULT,
Prabir Pradhan8a5c41d2023-06-08 19:13:46 +0000554 std::optional<gui::Uid> targetUid = {}, uint32_t policyFlags = DEFAULT_POLICY_FLAGS) {
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -0700555 return dispatcher.injectInputEvent(&event, targetUid, injectionMode, injectionTimeout,
556 policyFlags);
Garfield Tandf26e862020-07-01 20:18:19 -0700557}
558
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -0800559static InputEventInjectionResult injectMotionEvent(
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -0700560 InputDispatcher& dispatcher, int32_t action, int32_t source, int32_t displayId,
561 const PointF& position = {100, 200},
Siarhei Vishniakou4cb50ca2020-05-26 21:43:02 -0700562 const PointF& cursorPosition = {AMOTION_EVENT_INVALID_CURSOR_POSITION,
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -0700563 AMOTION_EVENT_INVALID_CURSOR_POSITION},
564 std::chrono::milliseconds injectionTimeout = INJECT_EVENT_TIMEOUT,
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -0800565 InputEventInjectionSync injectionMode = InputEventInjectionSync::WAIT_FOR_RESULT,
Prabir Pradhan5735a322022-04-11 17:23:34 +0000566 nsecs_t eventTime = systemTime(SYSTEM_TIME_MONOTONIC),
Prabir Pradhan8a5c41d2023-06-08 19:13:46 +0000567 std::optional<gui::Uid> targetUid = {}, uint32_t policyFlags = DEFAULT_POLICY_FLAGS) {
Siarhei Vishniakou90ee4782023-05-08 11:57:24 -0700568 MotionEventBuilder motionBuilder =
569 MotionEventBuilder(action, source)
570 .displayId(displayId)
571 .eventTime(eventTime)
572 .rawXCursorPosition(cursorPosition.x)
573 .rawYCursorPosition(cursorPosition.y)
574 .pointer(
575 PointerBuilder(/*id=*/0, ToolType::FINGER).x(position.x).y(position.y));
576 if (MotionEvent::getActionMasked(action) == ACTION_DOWN) {
577 motionBuilder.downTime(eventTime);
578 }
Arthur Hungb92218b2018-08-14 12:00:21 +0800579
580 // Inject event until dispatch out.
Siarhei Vishniakou90ee4782023-05-08 11:57:24 -0700581 return injectMotionEvent(dispatcher, motionBuilder.build(), injectionTimeout, injectionMode,
582 targetUid, policyFlags);
Arthur Hungb92218b2018-08-14 12:00:21 +0800583}
584
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -0700585static InputEventInjectionResult injectMotionDown(InputDispatcher& dispatcher, int32_t source,
586 int32_t displayId,
587 const PointF& location = {100, 200}) {
Siarhei Vishniakou4cb50ca2020-05-26 21:43:02 -0700588 return injectMotionEvent(dispatcher, AMOTION_EVENT_ACTION_DOWN, source, displayId, location);
Garfield Tan00f511d2019-06-12 16:55:40 -0700589}
590
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -0700591static InputEventInjectionResult injectMotionUp(InputDispatcher& dispatcher, int32_t source,
592 int32_t displayId,
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -0800593 const PointF& location = {100, 200}) {
Siarhei Vishniakou4cb50ca2020-05-26 21:43:02 -0700594 return injectMotionEvent(dispatcher, AMOTION_EVENT_ACTION_UP, source, displayId, location);
Michael Wright3a240c42019-12-10 20:53:41 +0000595}
596
Jackal Guof9696682018-10-05 12:23:23 +0800597static NotifyKeyArgs generateKeyArgs(int32_t action, int32_t displayId = ADISPLAY_ID_NONE) {
598 nsecs_t currentTime = systemTime(SYSTEM_TIME_MONOTONIC);
599 // Define a valid key event.
Prabir Pradhana8fe7c52023-12-14 22:07:23 +0000600 NotifyKeyArgs args(InputEvent::nextId(), currentTime, /*readTime=*/0, DEVICE_ID,
601 AINPUT_SOURCE_KEYBOARD, displayId, POLICY_FLAG_PASS_TO_USER, action,
602 /*flags=*/0, AKEYCODE_A, KEY_A, AMETA_NONE, currentTime);
Jackal Guof9696682018-10-05 12:23:23 +0800603
604 return args;
605}
606
Josep del Riob3981622023-04-18 15:49:45 +0000607static NotifyKeyArgs generateSystemShortcutArgs(int32_t action,
608 int32_t displayId = ADISPLAY_ID_NONE) {
609 nsecs_t currentTime = systemTime(SYSTEM_TIME_MONOTONIC);
610 // Define a valid key event.
Prabir Pradhana8fe7c52023-12-14 22:07:23 +0000611 NotifyKeyArgs args(InputEvent::nextId(), currentTime, /*readTime=*/0, DEVICE_ID,
612 AINPUT_SOURCE_KEYBOARD, displayId, 0, action, /*flags=*/0, AKEYCODE_C, KEY_C,
613 AMETA_META_ON, currentTime);
Josep del Riob3981622023-04-18 15:49:45 +0000614
615 return args;
616}
617
618static NotifyKeyArgs generateAssistantKeyArgs(int32_t action,
619 int32_t displayId = ADISPLAY_ID_NONE) {
620 nsecs_t currentTime = systemTime(SYSTEM_TIME_MONOTONIC);
621 // Define a valid key event.
Prabir Pradhana8fe7c52023-12-14 22:07:23 +0000622 NotifyKeyArgs args(InputEvent::nextId(), currentTime, /*readTime=*/0, DEVICE_ID,
623 AINPUT_SOURCE_KEYBOARD, displayId, 0, action, /*flags=*/0, AKEYCODE_ASSIST,
624 KEY_ASSISTANT, AMETA_NONE, currentTime);
Josep del Riob3981622023-04-18 15:49:45 +0000625
626 return args;
627}
628
Prabir Pradhan678438e2023-04-13 19:32:51 +0000629[[nodiscard]] static NotifyMotionArgs generateMotionArgs(int32_t action, int32_t source,
630 int32_t displayId,
631 const std::vector<PointF>& points) {
chaviwd1c23182019-12-20 18:44:56 -0800632 size_t pointerCount = points.size();
chaviwaf87b3e2019-10-01 16:59:28 -0700633 if (action == AMOTION_EVENT_ACTION_DOWN || action == AMOTION_EVENT_ACTION_UP) {
634 EXPECT_EQ(1U, pointerCount) << "Actions DOWN and UP can only contain a single pointer";
635 }
636
chaviwd1c23182019-12-20 18:44:56 -0800637 PointerProperties pointerProperties[pointerCount];
638 PointerCoords pointerCoords[pointerCount];
Jackal Guof9696682018-10-05 12:23:23 +0800639
chaviwd1c23182019-12-20 18:44:56 -0800640 for (size_t i = 0; i < pointerCount; i++) {
641 pointerProperties[i].clear();
642 pointerProperties[i].id = i;
Siarhei Vishniakou6d73f832022-07-21 17:27:03 -0700643 pointerProperties[i].toolType = ToolType::FINGER;
Jackal Guof9696682018-10-05 12:23:23 +0800644
chaviwd1c23182019-12-20 18:44:56 -0800645 pointerCoords[i].clear();
646 pointerCoords[i].setAxisValue(AMOTION_EVENT_AXIS_X, points[i].x);
647 pointerCoords[i].setAxisValue(AMOTION_EVENT_AXIS_Y, points[i].y);
648 }
Jackal Guof9696682018-10-05 12:23:23 +0800649
650 nsecs_t currentTime = systemTime(SYSTEM_TIME_MONOTONIC);
651 // Define a valid motion event.
Prabir Pradhana8fe7c52023-12-14 22:07:23 +0000652 NotifyMotionArgs args(InputEvent::nextId(), currentTime, /*readTime=*/0, DEVICE_ID, source,
653 displayId, POLICY_FLAG_PASS_TO_USER, action, /*actionButton=*/0,
654 /*flags=*/0, AMETA_NONE, /*buttonState=*/0, MotionClassification::NONE,
chaviwd1c23182019-12-20 18:44:56 -0800655 AMOTION_EVENT_EDGE_FLAG_NONE, pointerCount, pointerProperties,
Harry Cutts101ee9b2023-07-06 18:04:14 +0000656 pointerCoords, /*xPrecision=*/0, /*yPrecision=*/0,
Garfield Tan00f511d2019-06-12 16:55:40 -0700657 AMOTION_EVENT_INVALID_CURSOR_POSITION,
Harry Cutts101ee9b2023-07-06 18:04:14 +0000658 AMOTION_EVENT_INVALID_CURSOR_POSITION, currentTime, /*videoFrames=*/{});
Jackal Guof9696682018-10-05 12:23:23 +0800659
660 return args;
661}
662
Siarhei Vishniakoua16e3a22022-03-02 15:26:40 -0800663static NotifyMotionArgs generateTouchArgs(int32_t action, const std::vector<PointF>& points) {
664 return generateMotionArgs(action, AINPUT_SOURCE_TOUCHSCREEN, DISPLAY_ID, points);
665}
666
chaviwd1c23182019-12-20 18:44:56 -0800667static NotifyMotionArgs generateMotionArgs(int32_t action, int32_t source, int32_t displayId) {
668 return generateMotionArgs(action, source, displayId, {PointF{100, 200}});
669}
670
Prabir Pradhan5cc1a692021-08-06 14:01:18 +0000671static NotifyPointerCaptureChangedArgs generatePointerCaptureChangedArgs(
672 const PointerCaptureRequest& request) {
Prabir Pradhana8fe7c52023-12-14 22:07:23 +0000673 return NotifyPointerCaptureChangedArgs(InputEvent::nextId(), systemTime(SYSTEM_TIME_MONOTONIC),
674 request);
Prabir Pradhan99987712020-11-10 18:43:05 -0800675}
676
Siarhei Vishniakouadeb6fa2023-05-26 09:11:06 -0700677} // namespace
678
Siarhei Vishniakou7aa3e942021-11-18 09:49:11 -0800679/**
680 * When a window unexpectedly disposes of its input channel, policy should be notified about the
681 * broken channel.
682 */
683TEST_F(InputDispatcherTest, WhenInputChannelBreaks_PolicyIsNotified) {
684 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
685 sp<FakeWindowHandle> window =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -0700686 sp<FakeWindowHandle>::make(application, mDispatcher,
687 "Window that breaks its input channel", ADISPLAY_ID_DEFAULT);
Siarhei Vishniakou7aa3e942021-11-18 09:49:11 -0800688
Siarhei Vishniakouc41de372023-07-20 13:14:26 -0700689 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Siarhei Vishniakou7aa3e942021-11-18 09:49:11 -0800690
691 // Window closes its channel, but the window remains.
692 window->destroyReceiver();
693 mFakePolicy->assertNotifyInputChannelBrokenWasCalled(window->getInfo()->token);
694}
695
Arthur Hungb92218b2018-08-14 12:00:21 +0800696TEST_F(InputDispatcherTest, SetInputWindow_SingleWindowTouch) {
Chris Yea209fde2020-07-22 13:54:51 -0700697 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -0700698 sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher,
699 "Fake Window", ADISPLAY_ID_DEFAULT);
Arthur Hungb92218b2018-08-14 12:00:21 +0800700
Siarhei Vishniakouc41de372023-07-20 13:14:26 -0700701 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -0800702 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -0700703 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT))
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -0800704 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
Arthur Hungb92218b2018-08-14 12:00:21 +0800705
706 // Window should receive motion event.
Siarhei Vishniakouc5ca85c2019-11-15 17:20:00 -0800707 window->consumeMotionDown(ADISPLAY_ID_DEFAULT);
Arthur Hungb92218b2018-08-14 12:00:21 +0800708}
709
Siarhei Vishniakouaeed0da2024-01-09 08:57:13 -0800710using InputDispatcherDeathTest = InputDispatcherTest;
711
712/**
713 * When 'onWindowInfosChanged' arguments contain a duplicate entry for the same window, dispatcher
714 * should crash.
715 */
716TEST_F(InputDispatcherDeathTest, DuplicateWindowInfosAbortDispatcher) {
717 testing::GTEST_FLAG(death_test_style) = "threadsafe";
718 ScopedSilentDeath _silentDeath;
719
720 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
721 sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher,
722 "Fake Window", ADISPLAY_ID_DEFAULT);
723 ASSERT_DEATH(mDispatcher->onWindowInfosChanged(
724 {{*window->getInfo(), *window->getInfo()}, {}, 0, 0}),
725 "Incorrect WindowInfosUpdate provided");
726}
727
Prabir Pradhanc44ce4d2021-10-05 05:26:29 -0700728TEST_F(InputDispatcherTest, WhenDisplayNotSpecified_InjectMotionToDefaultDisplay) {
729 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -0700730 sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher,
731 "Fake Window", ADISPLAY_ID_DEFAULT);
Prabir Pradhanc44ce4d2021-10-05 05:26:29 -0700732
Siarhei Vishniakouc41de372023-07-20 13:14:26 -0700733 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Prabir Pradhanc44ce4d2021-10-05 05:26:29 -0700734 // Inject a MotionEvent to an unknown display.
735 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -0700736 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_NONE))
Prabir Pradhanc44ce4d2021-10-05 05:26:29 -0700737 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
738
739 // Window should receive motion event.
740 window->consumeMotionDown(ADISPLAY_ID_DEFAULT);
741}
742
Siarhei Vishniakoufb9fcda2020-05-04 14:59:19 -0700743/**
Siarhei Vishniakouc41de372023-07-20 13:14:26 -0700744 * Calling onWindowInfosChanged once should not cause any issues.
745 * This test serves as a sanity check for the next test, where onWindowInfosChanged is
Siarhei Vishniakoufb9fcda2020-05-04 14:59:19 -0700746 * called twice.
747 */
Prabir Pradhan76bdecb2022-01-31 11:14:15 -0800748TEST_F(InputDispatcherTest, SetInputWindowOnceWithSingleTouchWindow) {
Chris Yea209fde2020-07-22 13:54:51 -0700749 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -0700750 sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher,
751 "Fake Window", ADISPLAY_ID_DEFAULT);
Siarhei Vishniakoufb9fcda2020-05-04 14:59:19 -0700752 window->setFrame(Rect(0, 0, 100, 100));
Siarhei Vishniakoufb9fcda2020-05-04 14:59:19 -0700753
Siarhei Vishniakouc41de372023-07-20 13:14:26 -0700754 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -0800755 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -0700756 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
Siarhei Vishniakoufb9fcda2020-05-04 14:59:19 -0700757 {50, 50}))
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -0800758 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
Siarhei Vishniakoufb9fcda2020-05-04 14:59:19 -0700759
760 // Window should receive motion event.
761 window->consumeMotionDown(ADISPLAY_ID_DEFAULT);
762}
763
764/**
Siarhei Vishniakouc41de372023-07-20 13:14:26 -0700765 * Calling onWindowInfosChanged twice, with the same info, should not cause any issues.
Siarhei Vishniakoufb9fcda2020-05-04 14:59:19 -0700766 */
767TEST_F(InputDispatcherTest, SetInputWindowTwice_SingleWindowTouch) {
Chris Yea209fde2020-07-22 13:54:51 -0700768 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -0700769 sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher,
770 "Fake Window", ADISPLAY_ID_DEFAULT);
Siarhei Vishniakoufb9fcda2020-05-04 14:59:19 -0700771 window->setFrame(Rect(0, 0, 100, 100));
Siarhei Vishniakoufb9fcda2020-05-04 14:59:19 -0700772
Siarhei Vishniakouc41de372023-07-20 13:14:26 -0700773 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
774 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -0800775 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -0700776 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
Siarhei Vishniakoufb9fcda2020-05-04 14:59:19 -0700777 {50, 50}))
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -0800778 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
Siarhei Vishniakoufb9fcda2020-05-04 14:59:19 -0700779
780 // Window should receive motion event.
781 window->consumeMotionDown(ADISPLAY_ID_DEFAULT);
782}
783
Arthur Hungb92218b2018-08-14 12:00:21 +0800784// The foreground window should receive the first touch down event.
785TEST_F(InputDispatcherTest, SetInputWindow_MultiWindowsTouch) {
Chris Yea209fde2020-07-22 13:54:51 -0700786 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
Siarhei Vishniakou870ecec2020-12-09 08:07:46 -1000787 sp<FakeWindowHandle> windowTop =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -0700788 sp<FakeWindowHandle>::make(application, mDispatcher, "Top", ADISPLAY_ID_DEFAULT);
Siarhei Vishniakou870ecec2020-12-09 08:07:46 -1000789 sp<FakeWindowHandle> windowSecond =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -0700790 sp<FakeWindowHandle>::make(application, mDispatcher, "Second", ADISPLAY_ID_DEFAULT);
Arthur Hungb92218b2018-08-14 12:00:21 +0800791
Siarhei Vishniakouc41de372023-07-20 13:14:26 -0700792 mDispatcher->onWindowInfosChanged(
793 {{*windowTop->getInfo(), *windowSecond->getInfo()}, {}, 0, 0});
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -0800794 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -0700795 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT))
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -0800796 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
Arthur Hungb92218b2018-08-14 12:00:21 +0800797
798 // Top window should receive the touch down event. Second window should not receive anything.
Siarhei Vishniakouc5ca85c2019-11-15 17:20:00 -0800799 windowTop->consumeMotionDown(ADISPLAY_ID_DEFAULT);
Arthur Hungb92218b2018-08-14 12:00:21 +0800800 windowSecond->assertNoEvents();
801}
802
Siarhei Vishniakouca205502021-07-16 21:31:58 +0000803/**
804 * Two windows: A top window, and a wallpaper behind the window.
805 * Touch goes to the top window, and then top window disappears. Ensure that wallpaper window
806 * gets ACTION_CANCEL.
Prabir Pradhan4d5c52f2022-01-31 08:52:10 -0800807 * 1. foregroundWindow <-- dup touch to wallpaper
808 * 2. wallpaperWindow <-- is wallpaper
Siarhei Vishniakouca205502021-07-16 21:31:58 +0000809 */
810TEST_F(InputDispatcherTest, WhenForegroundWindowDisappears_WallpaperTouchIsCanceled) {
811 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
812 sp<FakeWindowHandle> foregroundWindow =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -0700813 sp<FakeWindowHandle>::make(application, mDispatcher, "Foreground", ADISPLAY_ID_DEFAULT);
Prabir Pradhan4d5c52f2022-01-31 08:52:10 -0800814 foregroundWindow->setDupTouchToWallpaper(true);
Siarhei Vishniakouca205502021-07-16 21:31:58 +0000815 sp<FakeWindowHandle> wallpaperWindow =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -0700816 sp<FakeWindowHandle>::make(application, mDispatcher, "Wallpaper", ADISPLAY_ID_DEFAULT);
Prabir Pradhan4d5c52f2022-01-31 08:52:10 -0800817 wallpaperWindow->setIsWallpaper(true);
Siarhei Vishniakouca205502021-07-16 21:31:58 +0000818
Siarhei Vishniakouc41de372023-07-20 13:14:26 -0700819 mDispatcher->onWindowInfosChanged(
820 {{*foregroundWindow->getInfo(), *wallpaperWindow->getInfo()}, {}, 0, 0});
Siarhei Vishniakouca205502021-07-16 21:31:58 +0000821 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoud908f5a2023-11-16 10:25:12 -0800822 injectMotionEvent(*mDispatcher,
823 MotionEventBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
824 .pointer(PointerBuilder(0, ToolType::FINGER).x(100).y(200))
825 .build()))
Siarhei Vishniakouca205502021-07-16 21:31:58 +0000826 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
827
828 // Both foreground window and its wallpaper should receive the touch down
829 foregroundWindow->consumeMotionDown();
830 wallpaperWindow->consumeMotionDown(ADISPLAY_ID_DEFAULT, expectedWallpaperFlags);
831
832 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoud908f5a2023-11-16 10:25:12 -0800833 injectMotionEvent(*mDispatcher,
834 MotionEventBuilder(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN)
835 .pointer(PointerBuilder(0, ToolType::FINGER).x(110).y(200))
836 .build()))
Siarhei Vishniakouca205502021-07-16 21:31:58 +0000837 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
838
Siarhei Vishniakoud908f5a2023-11-16 10:25:12 -0800839 foregroundWindow->consumeMotionEvent(WithMotionAction(ACTION_MOVE));
Siarhei Vishniakouca205502021-07-16 21:31:58 +0000840 wallpaperWindow->consumeMotionMove(ADISPLAY_ID_DEFAULT, expectedWallpaperFlags);
841
842 // Now the foreground window goes away, but the wallpaper stays
Siarhei Vishniakouc41de372023-07-20 13:14:26 -0700843 mDispatcher->onWindowInfosChanged({{*wallpaperWindow->getInfo()}, {}, 0, 0});
Siarhei Vishniakouca205502021-07-16 21:31:58 +0000844 foregroundWindow->consumeMotionCancel();
845 // Since the "parent" window of the wallpaper is gone, wallpaper should receive cancel, too.
846 wallpaperWindow->consumeMotionCancel(ADISPLAY_ID_DEFAULT, expectedWallpaperFlags);
847}
848
849/**
Siarhei Vishniakou82dc0422023-02-17 23:12:52 -0800850 * Two fingers down on the window, and lift off the first finger.
851 * Next, cancel the gesture to the window by removing the window. Make sure that the CANCEL event
852 * contains a single pointer.
853 */
854TEST_F(InputDispatcherTest, CancelAfterPointer0Up) {
855 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
856 sp<FakeWindowHandle> window =
857 sp<FakeWindowHandle>::make(application, mDispatcher, "Window", ADISPLAY_ID_DEFAULT);
858
Siarhei Vishniakouc41de372023-07-20 13:14:26 -0700859 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Siarhei Vishniakou82dc0422023-02-17 23:12:52 -0800860 // First touch pointer down on right window
Prabir Pradhan678438e2023-04-13 19:32:51 +0000861 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
862 .pointer(PointerBuilder(0, ToolType::FINGER).x(100).y(100))
863 .build());
Siarhei Vishniakou82dc0422023-02-17 23:12:52 -0800864 // Second touch pointer down
Prabir Pradhan678438e2023-04-13 19:32:51 +0000865 mDispatcher->notifyMotion(MotionArgsBuilder(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
866 .pointer(PointerBuilder(0, ToolType::FINGER).x(100).y(100))
867 .pointer(PointerBuilder(1, ToolType::FINGER).x(110).y(100))
868 .build());
Siarhei Vishniakou82dc0422023-02-17 23:12:52 -0800869 // First touch pointer lifts. The second one remains down
Prabir Pradhan678438e2023-04-13 19:32:51 +0000870 mDispatcher->notifyMotion(MotionArgsBuilder(POINTER_0_UP, AINPUT_SOURCE_TOUCHSCREEN)
871 .pointer(PointerBuilder(0, ToolType::FINGER).x(100).y(100))
872 .pointer(PointerBuilder(1, ToolType::FINGER).x(110).y(100))
873 .build());
Siarhei Vishniakou82dc0422023-02-17 23:12:52 -0800874 window->consumeMotionEvent(WithMotionAction(ACTION_DOWN));
875 window->consumeMotionEvent(WithMotionAction(POINTER_1_DOWN));
876 window->consumeMotionEvent(WithMotionAction(POINTER_0_UP));
877
878 // Remove the window. The gesture should be canceled
Siarhei Vishniakouc41de372023-07-20 13:14:26 -0700879 mDispatcher->onWindowInfosChanged({{}, {}, 0, 0});
Siarhei Vishniakou82dc0422023-02-17 23:12:52 -0800880 const std::map<int32_t, PointF> expectedPointers{{1, PointF{110, 100}}};
881 window->consumeMotionEvent(
882 AllOf(WithMotionAction(ACTION_CANCEL), WithPointers(expectedPointers)));
883}
884
885/**
Siarhei Vishniakou2b030972021-11-18 10:01:27 -0800886 * Same test as WhenForegroundWindowDisappears_WallpaperTouchIsCanceled above,
887 * with the following differences:
888 * After ACTION_DOWN, Wallpaper window hangs up its channel, which forces the dispatcher to
889 * clean up the connection.
890 * This later may crash dispatcher during ACTION_CANCEL synthesis, if the dispatcher is not careful.
891 * Ensure that there's no crash in the dispatcher.
892 */
893TEST_F(InputDispatcherTest, WhenWallpaperDisappears_NoCrash) {
894 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
895 sp<FakeWindowHandle> foregroundWindow =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -0700896 sp<FakeWindowHandle>::make(application, mDispatcher, "Foreground", ADISPLAY_ID_DEFAULT);
Prabir Pradhan4d5c52f2022-01-31 08:52:10 -0800897 foregroundWindow->setDupTouchToWallpaper(true);
Siarhei Vishniakou2b030972021-11-18 10:01:27 -0800898 sp<FakeWindowHandle> wallpaperWindow =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -0700899 sp<FakeWindowHandle>::make(application, mDispatcher, "Wallpaper", ADISPLAY_ID_DEFAULT);
Prabir Pradhan4d5c52f2022-01-31 08:52:10 -0800900 wallpaperWindow->setIsWallpaper(true);
Siarhei Vishniakou2b030972021-11-18 10:01:27 -0800901
Siarhei Vishniakouc41de372023-07-20 13:14:26 -0700902 mDispatcher->onWindowInfosChanged(
903 {{*foregroundWindow->getInfo(), *wallpaperWindow->getInfo()}, {}, 0, 0});
Siarhei Vishniakou2b030972021-11-18 10:01:27 -0800904 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -0700905 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
Siarhei Vishniakou2b030972021-11-18 10:01:27 -0800906 {100, 200}))
907 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
908
909 // Both foreground window and its wallpaper should receive the touch down
910 foregroundWindow->consumeMotionDown();
911 wallpaperWindow->consumeMotionDown(ADISPLAY_ID_DEFAULT, expectedWallpaperFlags);
912
913 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -0700914 injectMotionEvent(*mDispatcher, AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN,
Siarhei Vishniakou2b030972021-11-18 10:01:27 -0800915 ADISPLAY_ID_DEFAULT, {110, 200}))
916 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
917
918 foregroundWindow->consumeMotionMove();
919 wallpaperWindow->consumeMotionMove(ADISPLAY_ID_DEFAULT, expectedWallpaperFlags);
920
921 // Wallpaper closes its channel, but the window remains.
922 wallpaperWindow->destroyReceiver();
923 mFakePolicy->assertNotifyInputChannelBrokenWasCalled(wallpaperWindow->getInfo()->token);
924
925 // Now the foreground window goes away, but the wallpaper stays, even though its channel
926 // is no longer valid.
Siarhei Vishniakouc41de372023-07-20 13:14:26 -0700927 mDispatcher->onWindowInfosChanged({{*wallpaperWindow->getInfo()}, {}, 0, 0});
Siarhei Vishniakou2b030972021-11-18 10:01:27 -0800928 foregroundWindow->consumeMotionCancel();
929}
930
Arthur Hungc539dbb2022-12-08 07:45:36 +0000931class ShouldSplitTouchFixture : public InputDispatcherTest,
932 public ::testing::WithParamInterface<bool> {};
933INSTANTIATE_TEST_SUITE_P(InputDispatcherTest, ShouldSplitTouchFixture,
934 ::testing::Values(true, false));
Siarhei Vishniakou2b030972021-11-18 10:01:27 -0800935/**
Siarhei Vishniakouca205502021-07-16 21:31:58 +0000936 * A single window that receives touch (on top), and a wallpaper window underneath it.
937 * The top window gets a multitouch gesture.
938 * Ensure that wallpaper gets the same gesture.
939 */
Arthur Hungc539dbb2022-12-08 07:45:36 +0000940TEST_P(ShouldSplitTouchFixture, WallpaperWindowReceivesMultiTouch) {
Siarhei Vishniakouca205502021-07-16 21:31:58 +0000941 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
Arthur Hungc539dbb2022-12-08 07:45:36 +0000942 sp<FakeWindowHandle> foregroundWindow =
943 sp<FakeWindowHandle>::make(application, mDispatcher, "Foreground", ADISPLAY_ID_DEFAULT);
944 foregroundWindow->setDupTouchToWallpaper(true);
945 foregroundWindow->setPreventSplitting(GetParam());
Siarhei Vishniakouca205502021-07-16 21:31:58 +0000946
947 sp<FakeWindowHandle> wallpaperWindow =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -0700948 sp<FakeWindowHandle>::make(application, mDispatcher, "Wallpaper", ADISPLAY_ID_DEFAULT);
Prabir Pradhan4d5c52f2022-01-31 08:52:10 -0800949 wallpaperWindow->setIsWallpaper(true);
Siarhei Vishniakouca205502021-07-16 21:31:58 +0000950
Siarhei Vishniakouc41de372023-07-20 13:14:26 -0700951 mDispatcher->onWindowInfosChanged(
952 {{*foregroundWindow->getInfo(), *wallpaperWindow->getInfo()}, {}, 0, 0});
Siarhei Vishniakouca205502021-07-16 21:31:58 +0000953
954 // Touch down on top window
955 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -0700956 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
Siarhei Vishniakouca205502021-07-16 21:31:58 +0000957 {100, 100}))
958 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
959
960 // Both top window and its wallpaper should receive the touch down
Arthur Hungc539dbb2022-12-08 07:45:36 +0000961 foregroundWindow->consumeMotionDown();
Siarhei Vishniakouca205502021-07-16 21:31:58 +0000962 wallpaperWindow->consumeMotionDown(ADISPLAY_ID_DEFAULT, expectedWallpaperFlags);
963
964 // Second finger down on the top window
965 const MotionEvent secondFingerDownEvent =
Siarhei Vishniakoua16e3a22022-03-02 15:26:40 -0800966 MotionEventBuilder(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
Siarhei Vishniakouca205502021-07-16 21:31:58 +0000967 .eventTime(systemTime(SYSTEM_TIME_MONOTONIC))
Siarhei Vishniakou6d73f832022-07-21 17:27:03 -0700968 .pointer(PointerBuilder(/*id=*/0, ToolType::FINGER).x(100).y(100))
969 .pointer(PointerBuilder(/*id=*/1, ToolType::FINGER).x(150).y(150))
Siarhei Vishniakouca205502021-07-16 21:31:58 +0000970 .build();
971 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -0700972 injectMotionEvent(*mDispatcher, secondFingerDownEvent, INJECT_EVENT_TIMEOUT,
Siarhei Vishniakouca205502021-07-16 21:31:58 +0000973 InputEventInjectionSync::WAIT_FOR_RESULT))
974 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
975
Harry Cutts33476232023-01-30 19:57:29 +0000976 foregroundWindow->consumeMotionPointerDown(/*pointerIndex=*/1);
977 wallpaperWindow->consumeMotionPointerDown(/*pointerIndex=*/1, ADISPLAY_ID_DEFAULT,
Siarhei Vishniakouca205502021-07-16 21:31:58 +0000978 expectedWallpaperFlags);
Arthur Hungc539dbb2022-12-08 07:45:36 +0000979
980 const MotionEvent secondFingerUpEvent =
981 MotionEventBuilder(POINTER_0_UP, AINPUT_SOURCE_TOUCHSCREEN)
982 .displayId(ADISPLAY_ID_DEFAULT)
983 .eventTime(systemTime(SYSTEM_TIME_MONOTONIC))
Siarhei Vishniakou6d73f832022-07-21 17:27:03 -0700984 .pointer(PointerBuilder(/*id=*/0, ToolType::FINGER).x(100).y(100))
985 .pointer(PointerBuilder(/*id=*/1, ToolType::FINGER).x(150).y(150))
Arthur Hungc539dbb2022-12-08 07:45:36 +0000986 .build();
987 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -0700988 injectMotionEvent(*mDispatcher, secondFingerUpEvent, INJECT_EVENT_TIMEOUT,
Arthur Hungc539dbb2022-12-08 07:45:36 +0000989 InputEventInjectionSync::WAIT_FOR_RESULT))
990 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
991 foregroundWindow->consumeMotionPointerUp(0);
992 wallpaperWindow->consumeMotionPointerUp(0, ADISPLAY_ID_DEFAULT, expectedWallpaperFlags);
993
994 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -0700995 injectMotionEvent(*mDispatcher,
Siarhei Vishniakou92c8fd52023-01-29 14:57:43 -0800996 MotionEventBuilder(AMOTION_EVENT_ACTION_UP,
997 AINPUT_SOURCE_TOUCHSCREEN)
998 .displayId(ADISPLAY_ID_DEFAULT)
999 .eventTime(systemTime(SYSTEM_TIME_MONOTONIC))
Harry Cutts101ee9b2023-07-06 18:04:14 +00001000 .pointer(PointerBuilder(/*id=*/1, ToolType::FINGER)
Siarhei Vishniakou92c8fd52023-01-29 14:57:43 -08001001 .x(100)
1002 .y(100))
1003 .build(),
1004 INJECT_EVENT_TIMEOUT, InputEventInjectionSync::WAIT_FOR_RESULT))
Arthur Hungc539dbb2022-12-08 07:45:36 +00001005 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
1006 foregroundWindow->consumeMotionUp(ADISPLAY_ID_DEFAULT);
1007 wallpaperWindow->consumeMotionUp(ADISPLAY_ID_DEFAULT, expectedWallpaperFlags);
Siarhei Vishniakouca205502021-07-16 21:31:58 +00001008}
1009
1010/**
1011 * Two windows: a window on the left and window on the right.
1012 * A third window, wallpaper, is behind both windows, and spans both top windows.
1013 * The first touch down goes to the left window. A second pointer touches down on the right window.
1014 * The touch is split, so both left and right windows should receive ACTION_DOWN.
1015 * The wallpaper will get the full event, so it should receive ACTION_DOWN followed by
1016 * ACTION_POINTER_DOWN(1).
1017 */
1018TEST_F(InputDispatcherTest, TwoWindows_SplitWallpaperTouch) {
1019 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
1020 sp<FakeWindowHandle> leftWindow =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07001021 sp<FakeWindowHandle>::make(application, mDispatcher, "Left", ADISPLAY_ID_DEFAULT);
Siarhei Vishniakouca205502021-07-16 21:31:58 +00001022 leftWindow->setFrame(Rect(0, 0, 200, 200));
Prabir Pradhan4d5c52f2022-01-31 08:52:10 -08001023 leftWindow->setDupTouchToWallpaper(true);
Siarhei Vishniakouca205502021-07-16 21:31:58 +00001024
1025 sp<FakeWindowHandle> rightWindow =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07001026 sp<FakeWindowHandle>::make(application, mDispatcher, "Right", ADISPLAY_ID_DEFAULT);
Siarhei Vishniakouca205502021-07-16 21:31:58 +00001027 rightWindow->setFrame(Rect(200, 0, 400, 200));
Prabir Pradhan4d5c52f2022-01-31 08:52:10 -08001028 rightWindow->setDupTouchToWallpaper(true);
Siarhei Vishniakouca205502021-07-16 21:31:58 +00001029
1030 sp<FakeWindowHandle> wallpaperWindow =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07001031 sp<FakeWindowHandle>::make(application, mDispatcher, "Wallpaper", ADISPLAY_ID_DEFAULT);
Siarhei Vishniakouca205502021-07-16 21:31:58 +00001032 wallpaperWindow->setFrame(Rect(0, 0, 400, 200));
Prabir Pradhan4d5c52f2022-01-31 08:52:10 -08001033 wallpaperWindow->setIsWallpaper(true);
Siarhei Vishniakouca205502021-07-16 21:31:58 +00001034
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07001035 mDispatcher->onWindowInfosChanged(
1036 {{*leftWindow->getInfo(), *rightWindow->getInfo(), *wallpaperWindow->getInfo()},
1037 {},
1038 0,
1039 0});
Siarhei Vishniakouca205502021-07-16 21:31:58 +00001040
1041 // Touch down on left window
1042 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07001043 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
Siarhei Vishniakouca205502021-07-16 21:31:58 +00001044 {100, 100}))
1045 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
1046
1047 // Both foreground window and its wallpaper should receive the touch down
1048 leftWindow->consumeMotionDown();
1049 wallpaperWindow->consumeMotionDown(ADISPLAY_ID_DEFAULT, expectedWallpaperFlags);
1050
1051 // Second finger down on the right window
1052 const MotionEvent secondFingerDownEvent =
Siarhei Vishniakoua16e3a22022-03-02 15:26:40 -08001053 MotionEventBuilder(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
Siarhei Vishniakouca205502021-07-16 21:31:58 +00001054 .eventTime(systemTime(SYSTEM_TIME_MONOTONIC))
Siarhei Vishniakou6d73f832022-07-21 17:27:03 -07001055 .pointer(PointerBuilder(/*id=*/0, ToolType::FINGER).x(100).y(100))
1056 .pointer(PointerBuilder(/*id=*/1, ToolType::FINGER).x(300).y(100))
Siarhei Vishniakouca205502021-07-16 21:31:58 +00001057 .build();
1058 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07001059 injectMotionEvent(*mDispatcher, secondFingerDownEvent, INJECT_EVENT_TIMEOUT,
Siarhei Vishniakouca205502021-07-16 21:31:58 +00001060 InputEventInjectionSync::WAIT_FOR_RESULT))
1061 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
1062
1063 leftWindow->consumeMotionMove();
1064 // Since the touch is split, right window gets ACTION_DOWN
1065 rightWindow->consumeMotionDown(ADISPLAY_ID_DEFAULT);
Harry Cutts33476232023-01-30 19:57:29 +00001066 wallpaperWindow->consumeMotionPointerDown(/*pointerIndex=*/1, ADISPLAY_ID_DEFAULT,
Siarhei Vishniakouca205502021-07-16 21:31:58 +00001067 expectedWallpaperFlags);
1068
1069 // Now, leftWindow, which received the first finger, disappears.
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07001070 mDispatcher->onWindowInfosChanged(
1071 {{*rightWindow->getInfo(), *wallpaperWindow->getInfo()}, {}, 0, 0});
Siarhei Vishniakouca205502021-07-16 21:31:58 +00001072 leftWindow->consumeMotionCancel();
1073 // Since a "parent" window of the wallpaper is gone, wallpaper should receive cancel, too.
1074 wallpaperWindow->consumeMotionCancel(ADISPLAY_ID_DEFAULT, expectedWallpaperFlags);
1075
1076 // The pointer that's still down on the right window moves, and goes to the right window only.
1077 // As far as the dispatcher's concerned though, both pointers are still present.
1078 const MotionEvent secondFingerMoveEvent =
1079 MotionEventBuilder(AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN)
1080 .eventTime(systemTime(SYSTEM_TIME_MONOTONIC))
Siarhei Vishniakou6d73f832022-07-21 17:27:03 -07001081 .pointer(PointerBuilder(/*id=*/0, ToolType::FINGER).x(100).y(100))
1082 .pointer(PointerBuilder(/*id=*/1, ToolType::FINGER).x(310).y(110))
Siarhei Vishniakouca205502021-07-16 21:31:58 +00001083 .build();
1084 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07001085 injectMotionEvent(*mDispatcher, secondFingerMoveEvent, INJECT_EVENT_TIMEOUT,
Siarhei Vishniakouca205502021-07-16 21:31:58 +00001086 InputEventInjectionSync::WAIT_FOR_RESULT));
1087 rightWindow->consumeMotionMove();
1088
1089 leftWindow->assertNoEvents();
1090 rightWindow->assertNoEvents();
1091 wallpaperWindow->assertNoEvents();
1092}
1093
Arthur Hungc539dbb2022-12-08 07:45:36 +00001094/**
1095 * Two windows: a window on the left with dup touch to wallpaper and window on the right without it.
1096 * The touch slips to the right window. so left window and wallpaper should receive ACTION_CANCEL
1097 * The right window should receive ACTION_DOWN.
1098 */
1099TEST_F(InputDispatcherTest, WallpaperWindowWhenSlippery) {
Arthur Hung74c248d2022-11-23 07:09:59 +00001100 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
Arthur Hungc539dbb2022-12-08 07:45:36 +00001101 sp<FakeWindowHandle> leftWindow =
1102 sp<FakeWindowHandle>::make(application, mDispatcher, "Left", ADISPLAY_ID_DEFAULT);
1103 leftWindow->setFrame(Rect(0, 0, 200, 200));
1104 leftWindow->setDupTouchToWallpaper(true);
1105 leftWindow->setSlippery(true);
1106
1107 sp<FakeWindowHandle> rightWindow =
1108 sp<FakeWindowHandle>::make(application, mDispatcher, "Right", ADISPLAY_ID_DEFAULT);
1109 rightWindow->setFrame(Rect(200, 0, 400, 200));
Arthur Hung74c248d2022-11-23 07:09:59 +00001110
1111 sp<FakeWindowHandle> wallpaperWindow =
1112 sp<FakeWindowHandle>::make(application, mDispatcher, "Wallpaper", ADISPLAY_ID_DEFAULT);
1113 wallpaperWindow->setIsWallpaper(true);
Arthur Hung74c248d2022-11-23 07:09:59 +00001114
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07001115 mDispatcher->onWindowInfosChanged(
1116 {{*leftWindow->getInfo(), *rightWindow->getInfo(), *wallpaperWindow->getInfo()},
1117 {},
1118 0,
1119 0});
Arthur Hung74c248d2022-11-23 07:09:59 +00001120
Arthur Hungc539dbb2022-12-08 07:45:36 +00001121 // Touch down on left window
Arthur Hung74c248d2022-11-23 07:09:59 +00001122 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07001123 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
Arthur Hungc539dbb2022-12-08 07:45:36 +00001124 {100, 100}))
Arthur Hung74c248d2022-11-23 07:09:59 +00001125 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
Arthur Hungc539dbb2022-12-08 07:45:36 +00001126
1127 // Both foreground window and its wallpaper should receive the touch down
1128 leftWindow->consumeMotionDown();
Arthur Hung74c248d2022-11-23 07:09:59 +00001129 wallpaperWindow->consumeMotionDown(ADISPLAY_ID_DEFAULT, expectedWallpaperFlags);
1130
Arthur Hungc539dbb2022-12-08 07:45:36 +00001131 // Move to right window, the left window should receive cancel.
Arthur Hung74c248d2022-11-23 07:09:59 +00001132 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07001133 injectMotionEvent(*mDispatcher, AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN,
Arthur Hungc539dbb2022-12-08 07:45:36 +00001134 ADISPLAY_ID_DEFAULT, {201, 100}))
Arthur Hung74c248d2022-11-23 07:09:59 +00001135 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
1136
Arthur Hungc539dbb2022-12-08 07:45:36 +00001137 leftWindow->consumeMotionCancel();
1138 rightWindow->consumeMotionDown(ADISPLAY_ID_DEFAULT);
1139 wallpaperWindow->consumeMotionCancel(ADISPLAY_ID_DEFAULT, expectedWallpaperFlags);
Arthur Hung74c248d2022-11-23 07:09:59 +00001140}
1141
Siarhei Vishniakoua16e3a22022-03-02 15:26:40 -08001142/**
Siarhei Vishniakou5bf25d92023-02-08 15:43:38 -08001143 * The policy typically sets POLICY_FLAG_PASS_TO_USER to the events. But when the display is not
1144 * interactive, it might stop sending this flag.
1145 * In this test, we check that if the policy stops sending this flag mid-gesture, we still ensure
1146 * to have a consistent input stream.
1147 *
1148 * Test procedure:
1149 * DOWN -> POINTER_DOWN -> (stop sending POLICY_FLAG_PASS_TO_USER) -> CANCEL.
1150 * DOWN (new gesture).
1151 *
1152 * In the bad implementation, we could potentially drop the CANCEL event, and get an inconsistent
1153 * state in the dispatcher. This would cause the final DOWN event to not be delivered to the app.
1154 *
1155 * We technically just need a single window here, but we are using two windows (spy on top and a
1156 * regular window below) to emulate the actual situation where it happens on the device.
1157 */
1158TEST_F(InputDispatcherTest, TwoPointerCancelInconsistentPolicy) {
1159 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
1160 sp<FakeWindowHandle> spyWindow =
1161 sp<FakeWindowHandle>::make(application, mDispatcher, "Spy", ADISPLAY_ID_DEFAULT);
1162 spyWindow->setFrame(Rect(0, 0, 200, 200));
1163 spyWindow->setTrustedOverlay(true);
1164 spyWindow->setSpy(true);
1165
1166 sp<FakeWindowHandle> window =
1167 sp<FakeWindowHandle>::make(application, mDispatcher, "Window", ADISPLAY_ID_DEFAULT);
1168 window->setFrame(Rect(0, 0, 200, 200));
1169
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07001170 mDispatcher->onWindowInfosChanged({{*spyWindow->getInfo(), *window->getInfo()}, {}, 0, 0});
Siarhei Vishniakou5bf25d92023-02-08 15:43:38 -08001171 const int32_t touchDeviceId = 4;
Siarhei Vishniakou5bf25d92023-02-08 15:43:38 -08001172
1173 // Two pointers down
Prabir Pradhan678438e2023-04-13 19:32:51 +00001174 mDispatcher->notifyMotion(
1175 MotionArgsBuilder(AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
1176 .deviceId(touchDeviceId)
1177 .policyFlags(DEFAULT_POLICY_FLAGS)
1178 .pointer(PointerBuilder(0, ToolType::FINGER).x(100).y(100))
1179 .build());
Siarhei Vishniakou5bf25d92023-02-08 15:43:38 -08001180
Prabir Pradhan678438e2023-04-13 19:32:51 +00001181 mDispatcher->notifyMotion(MotionArgsBuilder(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
1182 .deviceId(touchDeviceId)
1183 .policyFlags(DEFAULT_POLICY_FLAGS)
1184 .pointer(PointerBuilder(0, ToolType::FINGER).x(100).y(100))
1185 .pointer(PointerBuilder(1, ToolType::FINGER).x(120).y(120))
1186 .build());
Siarhei Vishniakou5bf25d92023-02-08 15:43:38 -08001187 spyWindow->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_DOWN));
1188 spyWindow->consumeMotionEvent(WithMotionAction(POINTER_1_DOWN));
1189 window->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_DOWN));
1190 window->consumeMotionEvent(WithMotionAction(POINTER_1_DOWN));
1191
1192 // Cancel the current gesture. Send the cancel without the default policy flags.
Prabir Pradhan678438e2023-04-13 19:32:51 +00001193 mDispatcher->notifyMotion(
1194 MotionArgsBuilder(AMOTION_EVENT_ACTION_CANCEL, AINPUT_SOURCE_TOUCHSCREEN)
1195 .deviceId(touchDeviceId)
1196 .policyFlags(0)
1197 .pointer(PointerBuilder(0, ToolType::FINGER).x(100).y(100))
1198 .pointer(PointerBuilder(1, ToolType::FINGER).x(120).y(120))
1199 .build());
Siarhei Vishniakou5bf25d92023-02-08 15:43:38 -08001200 spyWindow->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_CANCEL));
1201 window->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_CANCEL));
1202
1203 // We don't need to reset the device to reproduce the issue, but the reset event typically
1204 // follows, so we keep it here to model the actual listener behaviour more closely.
Prabir Pradhan678438e2023-04-13 19:32:51 +00001205 mDispatcher->notifyDeviceReset({/*id=*/1, systemTime(SYSTEM_TIME_MONOTONIC), touchDeviceId});
Siarhei Vishniakou5bf25d92023-02-08 15:43:38 -08001206
1207 // Start new gesture
Prabir Pradhan678438e2023-04-13 19:32:51 +00001208 mDispatcher->notifyMotion(
1209 MotionArgsBuilder(AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
1210 .deviceId(touchDeviceId)
1211 .policyFlags(DEFAULT_POLICY_FLAGS)
1212 .pointer(PointerBuilder(0, ToolType::FINGER).x(100).y(100))
1213 .build());
Siarhei Vishniakou5bf25d92023-02-08 15:43:38 -08001214 spyWindow->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_DOWN));
1215 window->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_DOWN));
1216
1217 // No more events
1218 spyWindow->assertNoEvents();
1219 window->assertNoEvents();
1220}
1221
1222/**
Linnan Li907ae732023-09-05 17:14:21 +08001223 * Same as the above 'TwoPointerCancelInconsistentPolicy' test, but for hovers.
1224 * The policy typically sets POLICY_FLAG_PASS_TO_USER to the events. But when the display is not
1225 * interactive, it might stop sending this flag.
1226 * We've already ensured the consistency of the touch event in this case, and we should also ensure
1227 * the consistency of the hover event in this case.
1228 *
1229 * Test procedure:
1230 * HOVER_ENTER -> HOVER_MOVE -> (stop sending POLICY_FLAG_PASS_TO_USER) -> HOVER_EXIT
1231 * HOVER_ENTER -> HOVER_MOVE -> HOVER_EXIT
1232 *
1233 * We expect to receive two full streams of hover events.
1234 */
1235TEST_F(InputDispatcherTest, HoverEventInconsistentPolicy) {
1236 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
1237
1238 sp<FakeWindowHandle> window =
1239 sp<FakeWindowHandle>::make(application, mDispatcher, "Window", ADISPLAY_ID_DEFAULT);
1240 window->setFrame(Rect(0, 0, 300, 300));
1241
1242 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
1243
1244 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_ENTER, AINPUT_SOURCE_STYLUS)
1245 .policyFlags(DEFAULT_POLICY_FLAGS)
1246 .pointer(PointerBuilder(0, ToolType::STYLUS).x(100).y(101))
1247 .build());
1248 window->consumeMotionEvent(WithMotionAction(ACTION_HOVER_ENTER));
1249
1250 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_MOVE, AINPUT_SOURCE_STYLUS)
1251 .policyFlags(DEFAULT_POLICY_FLAGS)
1252 .pointer(PointerBuilder(0, ToolType::STYLUS).x(101).y(102))
1253 .build());
1254 window->consumeMotionEvent(WithMotionAction(ACTION_HOVER_MOVE));
1255
1256 // Send hover exit without the default policy flags.
1257 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_EXIT, AINPUT_SOURCE_STYLUS)
1258 .policyFlags(0)
1259 .pointer(PointerBuilder(0, ToolType::STYLUS).x(101).y(102))
1260 .build());
1261
1262 window->consumeMotionEvent(WithMotionAction(ACTION_HOVER_EXIT));
1263
1264 // Send a simple hover event stream, ensure dispatcher not crashed and window can receive
1265 // right event.
1266 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_ENTER, AINPUT_SOURCE_STYLUS)
1267 .policyFlags(DEFAULT_POLICY_FLAGS)
1268 .pointer(PointerBuilder(0, ToolType::STYLUS).x(200).y(201))
1269 .build());
1270 window->consumeMotionEvent(WithMotionAction(ACTION_HOVER_ENTER));
1271
1272 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_MOVE, AINPUT_SOURCE_STYLUS)
1273 .policyFlags(DEFAULT_POLICY_FLAGS)
1274 .pointer(PointerBuilder(0, ToolType::STYLUS).x(201).y(202))
1275 .build());
1276 window->consumeMotionEvent(WithMotionAction(ACTION_HOVER_MOVE));
1277
1278 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_EXIT, AINPUT_SOURCE_STYLUS)
1279 .policyFlags(DEFAULT_POLICY_FLAGS)
1280 .pointer(PointerBuilder(0, ToolType::STYLUS).x(201).y(202))
1281 .build());
1282 window->consumeMotionEvent(WithMotionAction(ACTION_HOVER_EXIT));
1283}
1284
1285/**
Siarhei Vishniakoue0431e42023-01-28 17:01:39 -08001286 * Two windows: a window on the left and a window on the right.
1287 * Mouse is hovered from the right window into the left window.
1288 * Next, we tap on the left window, where the cursor was last seen.
1289 * The second tap is done onto the right window.
1290 * The mouse and tap are from two different devices.
1291 * We technically don't need to set the downtime / eventtime for these events, but setting these
1292 * explicitly helps during debugging.
1293 * This test reproduces a crash where there is a mismatch between the downTime and eventTime.
1294 * In the buggy implementation, a tap on the right window would cause a crash.
1295 */
Siarhei Vishniakoued89cbb2023-10-13 10:42:44 -07001296TEST_F(InputDispatcherTest, HoverFromLeftToRightAndTap_legacy) {
1297 SCOPED_FLAG_OVERRIDE(enable_multi_device_same_window_stream, false);
1298
Siarhei Vishniakoue0431e42023-01-28 17:01:39 -08001299 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
1300 sp<FakeWindowHandle> leftWindow =
1301 sp<FakeWindowHandle>::make(application, mDispatcher, "Left", ADISPLAY_ID_DEFAULT);
1302 leftWindow->setFrame(Rect(0, 0, 200, 200));
1303
1304 sp<FakeWindowHandle> rightWindow =
1305 sp<FakeWindowHandle>::make(application, mDispatcher, "Right", ADISPLAY_ID_DEFAULT);
1306 rightWindow->setFrame(Rect(200, 0, 400, 200));
1307
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07001308 mDispatcher->onWindowInfosChanged(
1309 {{*leftWindow->getInfo(), *rightWindow->getInfo()}, {}, 0, 0});
Siarhei Vishniakoue0431e42023-01-28 17:01:39 -08001310 // All times need to start at the current time, otherwise the dispatcher will drop the events as
1311 // stale.
1312 const nsecs_t baseTime = systemTime(SYSTEM_TIME_MONOTONIC);
1313 const int32_t mouseDeviceId = 6;
1314 const int32_t touchDeviceId = 4;
1315 // Move the cursor from right
1316 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07001317 injectMotionEvent(*mDispatcher,
Siarhei Vishniakoue0431e42023-01-28 17:01:39 -08001318 MotionEventBuilder(AMOTION_EVENT_ACTION_HOVER_MOVE,
1319 AINPUT_SOURCE_MOUSE)
1320 .deviceId(mouseDeviceId)
1321 .downTime(baseTime + 10)
1322 .eventTime(baseTime + 20)
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07001323 .pointer(PointerBuilder(0, ToolType::MOUSE).x(300).y(100))
Siarhei Vishniakoue0431e42023-01-28 17:01:39 -08001324 .build()));
1325 rightWindow->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_ENTER));
1326
1327 // .. to the left window
1328 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07001329 injectMotionEvent(*mDispatcher,
Siarhei Vishniakoue0431e42023-01-28 17:01:39 -08001330 MotionEventBuilder(AMOTION_EVENT_ACTION_HOVER_MOVE,
1331 AINPUT_SOURCE_MOUSE)
1332 .deviceId(mouseDeviceId)
1333 .downTime(baseTime + 10)
1334 .eventTime(baseTime + 30)
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07001335 .pointer(PointerBuilder(0, ToolType::MOUSE).x(110).y(100))
Siarhei Vishniakoue0431e42023-01-28 17:01:39 -08001336 .build()));
1337 rightWindow->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_EXIT));
1338 leftWindow->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_ENTER));
1339 // Now tap the left window
1340 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07001341 injectMotionEvent(*mDispatcher,
Siarhei Vishniakoue0431e42023-01-28 17:01:39 -08001342 MotionEventBuilder(AMOTION_EVENT_ACTION_DOWN,
1343 AINPUT_SOURCE_TOUCHSCREEN)
1344 .deviceId(touchDeviceId)
1345 .downTime(baseTime + 40)
1346 .eventTime(baseTime + 40)
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07001347 .pointer(PointerBuilder(0, ToolType::FINGER).x(100).y(100))
Siarhei Vishniakoue0431e42023-01-28 17:01:39 -08001348 .build()));
1349 leftWindow->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_EXIT));
1350 leftWindow->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_DOWN));
1351
1352 // release tap
1353 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07001354 injectMotionEvent(*mDispatcher,
Siarhei Vishniakoue0431e42023-01-28 17:01:39 -08001355 MotionEventBuilder(AMOTION_EVENT_ACTION_UP,
1356 AINPUT_SOURCE_TOUCHSCREEN)
1357 .deviceId(touchDeviceId)
1358 .downTime(baseTime + 40)
1359 .eventTime(baseTime + 50)
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07001360 .pointer(PointerBuilder(0, ToolType::FINGER).x(100).y(100))
Siarhei Vishniakoue0431e42023-01-28 17:01:39 -08001361 .build()));
1362 leftWindow->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_UP));
1363
1364 // Tap the window on the right
1365 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07001366 injectMotionEvent(*mDispatcher,
Siarhei Vishniakoue0431e42023-01-28 17:01:39 -08001367 MotionEventBuilder(AMOTION_EVENT_ACTION_DOWN,
1368 AINPUT_SOURCE_TOUCHSCREEN)
1369 .deviceId(touchDeviceId)
1370 .downTime(baseTime + 60)
1371 .eventTime(baseTime + 60)
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07001372 .pointer(PointerBuilder(0, ToolType::FINGER).x(300).y(100))
Siarhei Vishniakoue0431e42023-01-28 17:01:39 -08001373 .build()));
1374 rightWindow->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_DOWN));
1375
1376 // release tap
1377 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07001378 injectMotionEvent(*mDispatcher,
Siarhei Vishniakoue0431e42023-01-28 17:01:39 -08001379 MotionEventBuilder(AMOTION_EVENT_ACTION_UP,
1380 AINPUT_SOURCE_TOUCHSCREEN)
1381 .deviceId(touchDeviceId)
1382 .downTime(baseTime + 60)
1383 .eventTime(baseTime + 70)
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07001384 .pointer(PointerBuilder(0, ToolType::FINGER).x(300).y(100))
Siarhei Vishniakoue0431e42023-01-28 17:01:39 -08001385 .build()));
1386 rightWindow->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_UP));
1387
1388 // No more events
1389 leftWindow->assertNoEvents();
1390 rightWindow->assertNoEvents();
1391}
1392
1393/**
Siarhei Vishniakoued89cbb2023-10-13 10:42:44 -07001394 * Two windows: a window on the left and a window on the right.
1395 * Mouse is hovered from the right window into the left window.
1396 * Next, we tap on the left window, where the cursor was last seen.
1397 * The second tap is done onto the right window.
1398 * The mouse and tap are from two different devices.
1399 * We technically don't need to set the downtime / eventtime for these events, but setting these
1400 * explicitly helps during debugging.
1401 * This test reproduces a crash where there is a mismatch between the downTime and eventTime.
1402 * In the buggy implementation, a tap on the right window would cause a crash.
1403 */
1404TEST_F(InputDispatcherTest, HoverFromLeftToRightAndTap) {
1405 SCOPED_FLAG_OVERRIDE(enable_multi_device_same_window_stream, true);
1406
1407 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
1408 sp<FakeWindowHandle> leftWindow =
1409 sp<FakeWindowHandle>::make(application, mDispatcher, "Left", ADISPLAY_ID_DEFAULT);
1410 leftWindow->setFrame(Rect(0, 0, 200, 200));
1411
1412 sp<FakeWindowHandle> rightWindow =
1413 sp<FakeWindowHandle>::make(application, mDispatcher, "Right", ADISPLAY_ID_DEFAULT);
1414 rightWindow->setFrame(Rect(200, 0, 400, 200));
1415
1416 mDispatcher->onWindowInfosChanged(
1417 {{*leftWindow->getInfo(), *rightWindow->getInfo()}, {}, 0, 0});
1418 // All times need to start at the current time, otherwise the dispatcher will drop the events as
1419 // stale.
1420 const nsecs_t baseTime = systemTime(SYSTEM_TIME_MONOTONIC);
1421 const int32_t mouseDeviceId = 6;
1422 const int32_t touchDeviceId = 4;
1423 // Move the cursor from right
1424 mDispatcher->notifyMotion(
1425 MotionArgsBuilder(AMOTION_EVENT_ACTION_HOVER_MOVE, AINPUT_SOURCE_MOUSE)
1426 .deviceId(mouseDeviceId)
1427 .downTime(baseTime + 10)
1428 .eventTime(baseTime + 20)
1429 .pointer(PointerBuilder(0, ToolType::MOUSE).x(300).y(100))
1430 .build());
1431 rightWindow->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_ENTER));
1432
1433 // .. to the left window
1434 mDispatcher->notifyMotion(
1435 MotionArgsBuilder(AMOTION_EVENT_ACTION_HOVER_MOVE, AINPUT_SOURCE_MOUSE)
1436 .deviceId(mouseDeviceId)
1437 .downTime(baseTime + 10)
1438 .eventTime(baseTime + 30)
1439 .pointer(PointerBuilder(0, ToolType::MOUSE).x(110).y(100))
1440 .build());
1441 rightWindow->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_EXIT));
1442 leftWindow->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_ENTER));
1443 // Now tap the left window
1444 mDispatcher->notifyMotion(
1445 MotionArgsBuilder(AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
1446 .deviceId(touchDeviceId)
1447 .downTime(baseTime + 40)
1448 .eventTime(baseTime + 40)
1449 .pointer(PointerBuilder(0, ToolType::FINGER).x(100).y(100))
1450 .build());
1451 leftWindow->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_DOWN));
1452
1453 // release tap
1454 mDispatcher->notifyMotion(MotionArgsBuilder(AMOTION_EVENT_ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN)
1455 .deviceId(touchDeviceId)
1456 .downTime(baseTime + 40)
1457 .eventTime(baseTime + 50)
1458 .pointer(PointerBuilder(0, ToolType::FINGER).x(100).y(100))
1459 .build());
1460 leftWindow->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_UP));
1461
1462 // Tap the window on the right
1463 mDispatcher->notifyMotion(
1464 MotionArgsBuilder(AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
1465 .deviceId(touchDeviceId)
1466 .downTime(baseTime + 60)
1467 .eventTime(baseTime + 60)
1468 .pointer(PointerBuilder(0, ToolType::FINGER).x(300).y(100))
1469 .build());
1470 rightWindow->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_DOWN));
1471
1472 // release tap
1473 mDispatcher->notifyMotion(MotionArgsBuilder(AMOTION_EVENT_ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN)
1474 .deviceId(touchDeviceId)
1475 .downTime(baseTime + 60)
1476 .eventTime(baseTime + 70)
1477 .pointer(PointerBuilder(0, ToolType::FINGER).x(300).y(100))
1478 .build());
1479 rightWindow->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_UP));
1480
1481 // No more events
1482 leftWindow->assertNoEvents();
1483 rightWindow->assertNoEvents();
1484}
1485
1486/**
Siarhei Vishniakoua235c042023-05-02 09:59:09 -07001487 * Start hovering in a window. While this hover is still active, make another window appear on top.
1488 * The top, obstructing window has no input channel, so it's not supposed to receive input.
1489 * While the top window is present, the hovering is stopped.
1490 * Later, hovering gets resumed again.
1491 * Ensure that new hover gesture is handled correctly.
1492 * This test reproduces a crash where the HOVER_EXIT event wasn't getting dispatched correctly
1493 * to the window that's currently being hovered over.
1494 */
1495TEST_F(InputDispatcherTest, HoverWhileWindowAppears) {
1496 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
1497 sp<FakeWindowHandle> window =
1498 sp<FakeWindowHandle>::make(application, mDispatcher, "Window", ADISPLAY_ID_DEFAULT);
1499 window->setFrame(Rect(0, 0, 200, 200));
1500
1501 // Only a single window is present at first
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07001502 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Siarhei Vishniakoua235c042023-05-02 09:59:09 -07001503
1504 // Start hovering in the window
1505 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_ENTER, AINPUT_SOURCE_STYLUS)
1506 .pointer(PointerBuilder(0, ToolType::STYLUS).x(100).y(100))
1507 .build());
1508 window->consumeMotionEvent(WithMotionAction(ACTION_HOVER_ENTER));
1509
1510 // Now, an obscuring window appears!
1511 sp<FakeWindowHandle> obscuringWindow =
1512 sp<FakeWindowHandle>::make(application, mDispatcher, "Obscuring window",
1513 ADISPLAY_ID_DEFAULT,
Prabir Pradhane7cc69c2024-01-05 21:35:28 +00001514 /*createInputChannel=*/false);
Siarhei Vishniakoua235c042023-05-02 09:59:09 -07001515 obscuringWindow->setFrame(Rect(0, 0, 200, 200));
1516 obscuringWindow->setTouchOcclusionMode(TouchOcclusionMode::BLOCK_UNTRUSTED);
1517 obscuringWindow->setOwnerInfo(SECONDARY_WINDOW_PID, SECONDARY_WINDOW_UID);
1518 obscuringWindow->setNoInputChannel(true);
1519 obscuringWindow->setFocusable(false);
1520 obscuringWindow->setAlpha(1.0);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07001521 mDispatcher->onWindowInfosChanged(
1522 {{*obscuringWindow->getInfo(), *window->getInfo()}, {}, 0, 0});
Siarhei Vishniakoua235c042023-05-02 09:59:09 -07001523
1524 // While this new obscuring window is present, the hovering is stopped
1525 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_EXIT, AINPUT_SOURCE_STYLUS)
1526 .pointer(PointerBuilder(0, ToolType::STYLUS).x(100).y(100))
1527 .build());
1528 window->consumeMotionEvent(WithMotionAction(ACTION_HOVER_EXIT));
1529
1530 // Now the obscuring window goes away.
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07001531 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Siarhei Vishniakoua235c042023-05-02 09:59:09 -07001532
1533 // And a new hover gesture starts.
1534 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_ENTER, AINPUT_SOURCE_STYLUS)
1535 .pointer(PointerBuilder(0, ToolType::STYLUS).x(100).y(100))
1536 .build());
1537 window->consumeMotionEvent(WithMotionAction(ACTION_HOVER_ENTER));
1538}
1539
1540/**
1541 * Same test as 'HoverWhileWindowAppears' above, but here, we also send some HOVER_MOVE events to
1542 * the obscuring window.
1543 */
1544TEST_F(InputDispatcherTest, HoverMoveWhileWindowAppears) {
1545 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
1546 sp<FakeWindowHandle> window =
1547 sp<FakeWindowHandle>::make(application, mDispatcher, "Window", ADISPLAY_ID_DEFAULT);
1548 window->setFrame(Rect(0, 0, 200, 200));
1549
1550 // Only a single window is present at first
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07001551 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Siarhei Vishniakoua235c042023-05-02 09:59:09 -07001552
1553 // Start hovering in the window
1554 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_ENTER, AINPUT_SOURCE_STYLUS)
1555 .pointer(PointerBuilder(0, ToolType::STYLUS).x(100).y(100))
1556 .build());
1557 window->consumeMotionEvent(WithMotionAction(ACTION_HOVER_ENTER));
1558
1559 // Now, an obscuring window appears!
1560 sp<FakeWindowHandle> obscuringWindow =
1561 sp<FakeWindowHandle>::make(application, mDispatcher, "Obscuring window",
1562 ADISPLAY_ID_DEFAULT,
Prabir Pradhane7cc69c2024-01-05 21:35:28 +00001563 /*createInputChannel=*/false);
Siarhei Vishniakoua235c042023-05-02 09:59:09 -07001564 obscuringWindow->setFrame(Rect(0, 0, 200, 200));
1565 obscuringWindow->setTouchOcclusionMode(TouchOcclusionMode::BLOCK_UNTRUSTED);
1566 obscuringWindow->setOwnerInfo(SECONDARY_WINDOW_PID, SECONDARY_WINDOW_UID);
1567 obscuringWindow->setNoInputChannel(true);
1568 obscuringWindow->setFocusable(false);
1569 obscuringWindow->setAlpha(1.0);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07001570 mDispatcher->onWindowInfosChanged(
1571 {{*obscuringWindow->getInfo(), *window->getInfo()}, {}, 0, 0});
Siarhei Vishniakoua235c042023-05-02 09:59:09 -07001572
1573 // While this new obscuring window is present, the hovering continues. The event can't go to the
1574 // bottom window due to obstructed touches, so it should generate HOVER_EXIT for that window.
1575 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_MOVE, AINPUT_SOURCE_STYLUS)
1576 .pointer(PointerBuilder(0, ToolType::STYLUS).x(100).y(100))
1577 .build());
1578 obscuringWindow->assertNoEvents();
1579 window->consumeMotionEvent(WithMotionAction(ACTION_HOVER_EXIT));
1580
1581 // Now the obscuring window goes away.
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07001582 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Siarhei Vishniakoua235c042023-05-02 09:59:09 -07001583
1584 // Hovering continues in the same position. The hovering pointer re-enters the bottom window,
1585 // so it should generate a HOVER_ENTER
1586 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_MOVE, AINPUT_SOURCE_STYLUS)
1587 .pointer(PointerBuilder(0, ToolType::STYLUS).x(100).y(100))
1588 .build());
1589 window->consumeMotionEvent(WithMotionAction(ACTION_HOVER_ENTER));
1590
1591 // Now the MOVE should be getting dispatched normally
1592 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_MOVE, AINPUT_SOURCE_STYLUS)
1593 .pointer(PointerBuilder(0, ToolType::STYLUS).x(110).y(110))
1594 .build());
1595 window->consumeMotionEvent(WithMotionAction(ACTION_HOVER_MOVE));
1596}
1597
1598/**
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -07001599 * Hover mouse over a window, and then send ACTION_SCROLL. Ensure both the hover and the scroll
1600 * events are delivered to the window.
1601 */
1602TEST_F(InputDispatcherTest, HoverMoveAndScroll) {
1603 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
1604 sp<FakeWindowHandle> window =
1605 sp<FakeWindowHandle>::make(application, mDispatcher, "Window", ADISPLAY_ID_DEFAULT);
1606 window->setFrame(Rect(0, 0, 200, 200));
1607 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
1608
1609 // Start hovering in the window
1610 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_ENTER, AINPUT_SOURCE_MOUSE)
1611 .pointer(PointerBuilder(0, ToolType::MOUSE).x(100).y(110))
1612 .build());
1613 window->consumeMotionEvent(WithMotionAction(ACTION_HOVER_ENTER));
1614
1615 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_MOVE, AINPUT_SOURCE_MOUSE)
1616 .pointer(PointerBuilder(0, ToolType::MOUSE).x(110).y(120))
1617 .build());
1618 window->consumeMotionEvent(WithMotionAction(ACTION_HOVER_MOVE));
1619
1620 // Scroll with the mouse
1621 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_SCROLL, AINPUT_SOURCE_MOUSE)
1622 .pointer(PointerBuilder(0, ToolType::MOUSE).x(110).y(120))
1623 .build());
1624 window->consumeMotionEvent(WithMotionAction(ACTION_SCROLL));
1625}
1626
1627using InputDispatcherMultiDeviceTest = InputDispatcherTest;
1628
1629/**
Siarhei Vishniakou2899c552023-07-10 18:20:46 -07001630 * One window. Stylus down on the window. Next, touch from another device goes down. Ensure that
1631 * touch is dropped, because stylus should be preferred over touch.
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -07001632 */
Siarhei Vishniakou2899c552023-07-10 18:20:46 -07001633TEST_F(InputDispatcherMultiDeviceTest, StylusDownBlocksTouchDown) {
Siarhei Vishniakoued89cbb2023-10-13 10:42:44 -07001634 SCOPED_FLAG_OVERRIDE(enable_multi_device_same_window_stream, false);
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -07001635 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
1636 sp<FakeWindowHandle> window =
1637 sp<FakeWindowHandle>::make(application, mDispatcher, "Window", ADISPLAY_ID_DEFAULT);
1638 window->setFrame(Rect(0, 0, 200, 200));
1639
1640 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
1641
1642 constexpr int32_t touchDeviceId = 4;
1643 constexpr int32_t stylusDeviceId = 2;
1644
1645 // Stylus down
1646 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_STYLUS)
1647 .deviceId(stylusDeviceId)
1648 .pointer(PointerBuilder(0, ToolType::STYLUS).x(100).y(110))
1649 .build());
1650 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(stylusDeviceId)));
1651
1652 // Touch down
1653 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
1654 .deviceId(touchDeviceId)
1655 .pointer(PointerBuilder(0, ToolType::FINGER).x(140).y(145))
1656 .build());
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -07001657
1658 // Touch move
1659 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN)
1660 .deviceId(touchDeviceId)
1661 .pointer(PointerBuilder(0, ToolType::FINGER).x(141).y(146))
1662 .build());
Siarhei Vishniakou2899c552023-07-10 18:20:46 -07001663 // Touch is ignored because stylus is already down
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -07001664
Siarhei Vishniakou2899c552023-07-10 18:20:46 -07001665 // Subsequent stylus movements are delivered correctly
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -07001666 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_STYLUS)
1667 .deviceId(stylusDeviceId)
1668 .pointer(PointerBuilder(0, ToolType::STYLUS).x(101).y(111))
1669 .build());
Siarhei Vishniakou2899c552023-07-10 18:20:46 -07001670 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(stylusDeviceId),
1671 WithCoords(101, 111)));
1672
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -07001673 window->assertNoEvents();
1674}
1675
1676/**
Siarhei Vishniakoued89cbb2023-10-13 10:42:44 -07001677 * One window. Stylus down on the window. Next, touch from another device goes down. Ensure that
1678 * touch is not dropped, because multiple devices are allowed to be active in the same window.
1679 */
1680TEST_F(InputDispatcherMultiDeviceTest, StylusDownDoesNotBlockTouchDown) {
1681 SCOPED_FLAG_OVERRIDE(enable_multi_device_same_window_stream, true);
1682 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
1683 sp<FakeWindowHandle> window =
1684 sp<FakeWindowHandle>::make(application, mDispatcher, "Window", ADISPLAY_ID_DEFAULT);
1685 window->setFrame(Rect(0, 0, 200, 200));
1686
1687 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
1688
1689 constexpr int32_t touchDeviceId = 4;
1690 constexpr int32_t stylusDeviceId = 2;
1691
1692 // Stylus down
1693 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_STYLUS)
1694 .deviceId(stylusDeviceId)
1695 .pointer(PointerBuilder(0, ToolType::STYLUS).x(100).y(110))
1696 .build());
1697 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(stylusDeviceId)));
1698
1699 // Touch down
1700 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
1701 .deviceId(touchDeviceId)
1702 .pointer(PointerBuilder(0, ToolType::FINGER).x(140).y(145))
1703 .build());
1704 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(touchDeviceId)));
1705
1706 // Touch move
1707 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN)
1708 .deviceId(touchDeviceId)
1709 .pointer(PointerBuilder(0, ToolType::FINGER).x(141).y(146))
1710 .build());
1711 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(touchDeviceId)));
1712
1713 // Stylus move
1714 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_STYLUS)
1715 .deviceId(stylusDeviceId)
1716 .pointer(PointerBuilder(0, ToolType::STYLUS).x(101).y(111))
1717 .build());
1718 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(stylusDeviceId),
1719 WithCoords(101, 111)));
1720
1721 window->assertNoEvents();
1722}
1723
1724/**
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -07001725 * One window and one spy window. Stylus down on the window. Next, touch from another device goes
Siarhei Vishniakou2899c552023-07-10 18:20:46 -07001726 * down. Ensure that touch is dropped, because stylus should be preferred over touch.
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -07001727 * Similar test as above, but with added SPY window.
1728 */
Siarhei Vishniakou2899c552023-07-10 18:20:46 -07001729TEST_F(InputDispatcherMultiDeviceTest, StylusDownWithSpyBlocksTouchDown) {
Siarhei Vishniakoued89cbb2023-10-13 10:42:44 -07001730 SCOPED_FLAG_OVERRIDE(enable_multi_device_same_window_stream, false);
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -07001731 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
1732 sp<FakeWindowHandle> window =
1733 sp<FakeWindowHandle>::make(application, mDispatcher, "Window", ADISPLAY_ID_DEFAULT);
1734 sp<FakeWindowHandle> spyWindow =
1735 sp<FakeWindowHandle>::make(application, mDispatcher, "Spy", ADISPLAY_ID_DEFAULT);
1736 spyWindow->setFrame(Rect(0, 0, 200, 200));
1737 spyWindow->setTrustedOverlay(true);
1738 spyWindow->setSpy(true);
1739 window->setFrame(Rect(0, 0, 200, 200));
1740
1741 mDispatcher->onWindowInfosChanged({{*spyWindow->getInfo(), *window->getInfo()}, {}, 0, 0});
1742
1743 constexpr int32_t touchDeviceId = 4;
1744 constexpr int32_t stylusDeviceId = 2;
1745
1746 // Stylus down
1747 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_STYLUS)
1748 .deviceId(stylusDeviceId)
1749 .pointer(PointerBuilder(0, ToolType::STYLUS).x(100).y(110))
1750 .build());
1751 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(stylusDeviceId)));
1752 spyWindow->consumeMotionEvent(
1753 AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(stylusDeviceId)));
1754
1755 // Touch down
1756 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
1757 .deviceId(touchDeviceId)
1758 .pointer(PointerBuilder(0, ToolType::FINGER).x(140).y(145))
1759 .build());
1760
1761 // Touch move
1762 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN)
1763 .deviceId(touchDeviceId)
1764 .pointer(PointerBuilder(0, ToolType::FINGER).x(141).y(146))
1765 .build());
Siarhei Vishniakou2899c552023-07-10 18:20:46 -07001766
1767 // Touch is ignored because stylus is already down
1768
1769 // Subsequent stylus movements are delivered correctly
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -07001770 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_STYLUS)
1771 .deviceId(stylusDeviceId)
1772 .pointer(PointerBuilder(0, ToolType::STYLUS).x(101).y(111))
1773 .build());
Siarhei Vishniakou2899c552023-07-10 18:20:46 -07001774 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(stylusDeviceId),
1775 WithCoords(101, 111)));
1776 spyWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(stylusDeviceId),
1777 WithCoords(101, 111)));
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -07001778
1779 window->assertNoEvents();
1780 spyWindow->assertNoEvents();
1781}
1782
1783/**
Siarhei Vishniakoued89cbb2023-10-13 10:42:44 -07001784 * One window and one spy window. Stylus down on the window. Next, touch from another device goes
1785 * down. Ensure that touch is not dropped, because multiple devices can be active at the same time.
1786 * Similar test as above, but with added SPY window.
1787 */
1788TEST_F(InputDispatcherMultiDeviceTest, StylusDownWithSpyDoesNotBlockTouchDown) {
1789 SCOPED_FLAG_OVERRIDE(enable_multi_device_same_window_stream, true);
1790 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
1791 sp<FakeWindowHandle> window =
1792 sp<FakeWindowHandle>::make(application, mDispatcher, "Window", ADISPLAY_ID_DEFAULT);
1793 sp<FakeWindowHandle> spyWindow =
1794 sp<FakeWindowHandle>::make(application, mDispatcher, "Spy", ADISPLAY_ID_DEFAULT);
1795 spyWindow->setFrame(Rect(0, 0, 200, 200));
1796 spyWindow->setTrustedOverlay(true);
1797 spyWindow->setSpy(true);
1798 window->setFrame(Rect(0, 0, 200, 200));
1799
1800 mDispatcher->onWindowInfosChanged({{*spyWindow->getInfo(), *window->getInfo()}, {}, 0, 0});
1801
1802 constexpr int32_t touchDeviceId = 4;
1803 constexpr int32_t stylusDeviceId = 2;
1804
1805 // Stylus down
1806 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_STYLUS)
1807 .deviceId(stylusDeviceId)
1808 .pointer(PointerBuilder(0, ToolType::STYLUS).x(100).y(110))
1809 .build());
1810 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(stylusDeviceId)));
1811 spyWindow->consumeMotionEvent(
1812 AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(stylusDeviceId)));
1813
1814 // Touch down
1815 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
1816 .deviceId(touchDeviceId)
1817 .pointer(PointerBuilder(0, ToolType::FINGER).x(140).y(145))
1818 .build());
1819 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(touchDeviceId)));
1820 spyWindow->consumeMotionEvent(
1821 AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(touchDeviceId)));
1822
1823 // Touch move
1824 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN)
1825 .deviceId(touchDeviceId)
1826 .pointer(PointerBuilder(0, ToolType::FINGER).x(141).y(146))
1827 .build());
1828 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(touchDeviceId)));
1829 spyWindow->consumeMotionEvent(
1830 AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(touchDeviceId)));
1831
1832 // Subsequent stylus movements are delivered correctly
1833 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_STYLUS)
1834 .deviceId(stylusDeviceId)
1835 .pointer(PointerBuilder(0, ToolType::STYLUS).x(101).y(111))
1836 .build());
1837 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(stylusDeviceId),
1838 WithCoords(101, 111)));
1839 spyWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(stylusDeviceId),
1840 WithCoords(101, 111)));
1841
1842 window->assertNoEvents();
1843 spyWindow->assertNoEvents();
1844}
1845
1846/**
Siarhei Vishniakou2899c552023-07-10 18:20:46 -07001847 * One window. Stylus hover on the window. Next, touch from another device goes down. Ensure that
Siarhei Vishniakou3ad54f52023-11-02 16:54:40 -07001848 * touch is dropped, because stylus hover takes precedence.
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -07001849 */
Siarhei Vishniakou3ad54f52023-11-02 16:54:40 -07001850TEST_F(InputDispatcherMultiDeviceTest, StylusHoverBlocksTouchDown) {
Siarhei Vishniakoued89cbb2023-10-13 10:42:44 -07001851 SCOPED_FLAG_OVERRIDE(enable_multi_device_same_window_stream, false);
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -07001852 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
1853 sp<FakeWindowHandle> window =
1854 sp<FakeWindowHandle>::make(application, mDispatcher, "Window", ADISPLAY_ID_DEFAULT);
1855 window->setFrame(Rect(0, 0, 200, 200));
1856
1857 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
1858
1859 constexpr int32_t touchDeviceId = 4;
1860 constexpr int32_t stylusDeviceId = 2;
1861
1862 // Stylus down on the window
1863 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_ENTER, AINPUT_SOURCE_STYLUS)
1864 .deviceId(stylusDeviceId)
1865 .pointer(PointerBuilder(0, ToolType::STYLUS).x(100).y(110))
1866 .build());
1867 window->consumeMotionEvent(
1868 AllOf(WithMotionAction(ACTION_HOVER_ENTER), WithDeviceId(stylusDeviceId)));
1869
1870 // Touch down on window
1871 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
1872 .deviceId(touchDeviceId)
1873 .pointer(PointerBuilder(0, ToolType::FINGER).x(140).y(145))
1874 .build());
1875 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN)
1876 .deviceId(touchDeviceId)
1877 .pointer(PointerBuilder(0, ToolType::FINGER).x(141).y(146))
1878 .build());
Siarhei Vishniakou2899c552023-07-10 18:20:46 -07001879
Siarhei Vishniakou3ad54f52023-11-02 16:54:40 -07001880 // Touch is ignored because stylus is hovering
Siarhei Vishniakou2899c552023-07-10 18:20:46 -07001881
Siarhei Vishniakou3ad54f52023-11-02 16:54:40 -07001882 // Subsequent stylus movements are delivered correctly
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -07001883 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_MOVE, AINPUT_SOURCE_STYLUS)
1884 .deviceId(stylusDeviceId)
1885 .pointer(PointerBuilder(0, ToolType::STYLUS).x(101).y(111))
1886 .build());
Siarhei Vishniakou3ad54f52023-11-02 16:54:40 -07001887 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_HOVER_MOVE),
1888 WithDeviceId(stylusDeviceId), WithCoords(101, 111)));
Siarhei Vishniakou2899c552023-07-10 18:20:46 -07001889
Siarhei Vishniakou3ad54f52023-11-02 16:54:40 -07001890 // and subsequent touches continue to be ignored
Siarhei Vishniakou2899c552023-07-10 18:20:46 -07001891 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN)
1892 .deviceId(touchDeviceId)
1893 .pointer(PointerBuilder(0, ToolType::FINGER).x(142).y(147))
1894 .build());
Siarhei Vishniakou3ad54f52023-11-02 16:54:40 -07001895 window->assertNoEvents();
Siarhei Vishniakou2899c552023-07-10 18:20:46 -07001896}
1897
1898/**
Siarhei Vishniakoued89cbb2023-10-13 10:42:44 -07001899 * One window. Stylus hover on the window. Next, touch from another device goes down. Ensure that
1900 * touch is not dropped, because stylus hover and touch can be both active at the same time.
1901 */
1902TEST_F(InputDispatcherMultiDeviceTest, StylusHoverDoesNotBlockTouchDown) {
1903 SCOPED_FLAG_OVERRIDE(enable_multi_device_same_window_stream, true);
1904 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
1905 sp<FakeWindowHandle> window =
1906 sp<FakeWindowHandle>::make(application, mDispatcher, "Window", ADISPLAY_ID_DEFAULT);
1907 window->setFrame(Rect(0, 0, 200, 200));
1908
1909 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
1910
1911 constexpr int32_t touchDeviceId = 4;
1912 constexpr int32_t stylusDeviceId = 2;
1913
1914 // Stylus down on the window
1915 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_ENTER, AINPUT_SOURCE_STYLUS)
1916 .deviceId(stylusDeviceId)
1917 .pointer(PointerBuilder(0, ToolType::STYLUS).x(100).y(110))
1918 .build());
1919 window->consumeMotionEvent(
1920 AllOf(WithMotionAction(ACTION_HOVER_ENTER), WithDeviceId(stylusDeviceId)));
1921
1922 // Touch down on window
1923 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
1924 .deviceId(touchDeviceId)
1925 .pointer(PointerBuilder(0, ToolType::FINGER).x(140).y(145))
1926 .build());
1927 // Touch move on window
1928 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(touchDeviceId)));
1929 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN)
1930 .deviceId(touchDeviceId)
1931 .pointer(PointerBuilder(0, ToolType::FINGER).x(141).y(146))
1932 .build());
1933 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(touchDeviceId)));
1934
1935 // Subsequent stylus movements are delivered correctly
1936 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_MOVE, AINPUT_SOURCE_STYLUS)
1937 .deviceId(stylusDeviceId)
1938 .pointer(PointerBuilder(0, ToolType::STYLUS).x(101).y(111))
1939 .build());
1940 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_HOVER_MOVE),
1941 WithDeviceId(stylusDeviceId), WithCoords(101, 111)));
1942
1943 // and subsequent touches continue to work
1944 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN)
1945 .deviceId(touchDeviceId)
1946 .pointer(PointerBuilder(0, ToolType::FINGER).x(142).y(147))
1947 .build());
1948 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(touchDeviceId)));
1949 window->assertNoEvents();
1950}
1951
1952/**
Siarhei Vishniakou2899c552023-07-10 18:20:46 -07001953 * One window. Touch down on the window. Then, stylus hover on the window from another device.
Siarhei Vishniakou3ad54f52023-11-02 16:54:40 -07001954 * Ensure that touch is canceled, because stylus hover should take precedence.
Siarhei Vishniakou2899c552023-07-10 18:20:46 -07001955 */
Siarhei Vishniakou3ad54f52023-11-02 16:54:40 -07001956TEST_F(InputDispatcherMultiDeviceTest, TouchIsCanceledByStylusHover) {
Siarhei Vishniakoued89cbb2023-10-13 10:42:44 -07001957 SCOPED_FLAG_OVERRIDE(enable_multi_device_same_window_stream, false);
Siarhei Vishniakou2899c552023-07-10 18:20:46 -07001958 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
1959 sp<FakeWindowHandle> window =
1960 sp<FakeWindowHandle>::make(application, mDispatcher, "Window", ADISPLAY_ID_DEFAULT);
1961 window->setFrame(Rect(0, 0, 200, 200));
1962
1963 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
1964
1965 constexpr int32_t touchDeviceId = 4;
1966 constexpr int32_t stylusDeviceId = 2;
1967
1968 // Touch down on window
1969 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
1970 .deviceId(touchDeviceId)
1971 .pointer(PointerBuilder(0, ToolType::FINGER).x(140).y(145))
1972 .build());
1973 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN)
1974 .deviceId(touchDeviceId)
1975 .pointer(PointerBuilder(0, ToolType::FINGER).x(141).y(146))
1976 .build());
1977 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(touchDeviceId)));
1978 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(touchDeviceId)));
1979
1980 // Stylus hover on the window
1981 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_ENTER, AINPUT_SOURCE_STYLUS)
1982 .deviceId(stylusDeviceId)
1983 .pointer(PointerBuilder(0, ToolType::STYLUS).x(100).y(110))
1984 .build());
1985 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_MOVE, AINPUT_SOURCE_STYLUS)
1986 .deviceId(stylusDeviceId)
1987 .pointer(PointerBuilder(0, ToolType::STYLUS).x(101).y(111))
1988 .build());
Siarhei Vishniakou3ad54f52023-11-02 16:54:40 -07001989 // Stylus hover movement causes touch to be canceled
1990 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_CANCEL), WithDeviceId(touchDeviceId),
1991 WithCoords(141, 146)));
1992 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_HOVER_ENTER),
1993 WithDeviceId(stylusDeviceId), WithCoords(100, 110)));
1994 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_HOVER_MOVE),
1995 WithDeviceId(stylusDeviceId), WithCoords(101, 111)));
Siarhei Vishniakou2899c552023-07-10 18:20:46 -07001996
Siarhei Vishniakou3ad54f52023-11-02 16:54:40 -07001997 // Subsequent touch movements are ignored
Siarhei Vishniakou2899c552023-07-10 18:20:46 -07001998 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN)
1999 .deviceId(touchDeviceId)
2000 .pointer(PointerBuilder(0, ToolType::FINGER).x(142).y(147))
2001 .build());
Siarhei Vishniakou3ad54f52023-11-02 16:54:40 -07002002
2003 window->assertNoEvents();
Siarhei Vishniakou2899c552023-07-10 18:20:46 -07002004}
2005
2006/**
Siarhei Vishniakoued89cbb2023-10-13 10:42:44 -07002007 * One window. Touch down on the window. Then, stylus hover on the window from another device.
2008 * Ensure that touch is not canceled, because stylus hover can be active at the same time as touch.
2009 */
2010TEST_F(InputDispatcherMultiDeviceTest, TouchIsNotCanceledByStylusHover) {
2011 SCOPED_FLAG_OVERRIDE(enable_multi_device_same_window_stream, true);
2012 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
2013 sp<FakeWindowHandle> window =
2014 sp<FakeWindowHandle>::make(application, mDispatcher, "Window", ADISPLAY_ID_DEFAULT);
2015 window->setFrame(Rect(0, 0, 200, 200));
2016
2017 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
2018
2019 constexpr int32_t touchDeviceId = 4;
2020 constexpr int32_t stylusDeviceId = 2;
2021
2022 // Touch down on window
2023 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
2024 .deviceId(touchDeviceId)
2025 .pointer(PointerBuilder(0, ToolType::FINGER).x(140).y(145))
2026 .build());
2027 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN)
2028 .deviceId(touchDeviceId)
2029 .pointer(PointerBuilder(0, ToolType::FINGER).x(141).y(146))
2030 .build());
2031 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(touchDeviceId)));
2032 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(touchDeviceId)));
2033
2034 // Stylus hover on the window
2035 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_ENTER, AINPUT_SOURCE_STYLUS)
2036 .deviceId(stylusDeviceId)
2037 .pointer(PointerBuilder(0, ToolType::STYLUS).x(100).y(110))
2038 .build());
2039 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_MOVE, AINPUT_SOURCE_STYLUS)
2040 .deviceId(stylusDeviceId)
2041 .pointer(PointerBuilder(0, ToolType::STYLUS).x(101).y(111))
2042 .build());
2043 // Stylus hover movement is received normally
2044 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_HOVER_ENTER),
2045 WithDeviceId(stylusDeviceId), WithCoords(100, 110)));
2046 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_HOVER_MOVE),
2047 WithDeviceId(stylusDeviceId), WithCoords(101, 111)));
2048
2049 // Subsequent touch movements also work
2050 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN)
2051 .deviceId(touchDeviceId)
2052 .pointer(PointerBuilder(0, ToolType::FINGER).x(142).y(147))
2053 .build());
2054 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(touchDeviceId),
2055 WithCoords(142, 147)));
2056
2057 window->assertNoEvents();
2058}
2059
2060/**
Siarhei Vishniakou2899c552023-07-10 18:20:46 -07002061 * One window. Stylus down on the window. Then, stylus from another device goes down. Ensure that
2062 * the latest stylus takes over. That is, old stylus should be canceled and the new stylus should
2063 * become active.
2064 */
2065TEST_F(InputDispatcherMultiDeviceTest, LatestStylusWins) {
Siarhei Vishniakoued89cbb2023-10-13 10:42:44 -07002066 SCOPED_FLAG_OVERRIDE(enable_multi_device_same_window_stream, false);
Siarhei Vishniakou2899c552023-07-10 18:20:46 -07002067 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
2068 sp<FakeWindowHandle> window =
2069 sp<FakeWindowHandle>::make(application, mDispatcher, "Window", ADISPLAY_ID_DEFAULT);
2070 window->setFrame(Rect(0, 0, 200, 200));
2071
2072 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
2073
2074 constexpr int32_t stylusDeviceId1 = 3;
2075 constexpr int32_t stylusDeviceId2 = 5;
2076
2077 // Touch down on window
2078 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_STYLUS)
2079 .deviceId(stylusDeviceId1)
2080 .pointer(PointerBuilder(0, ToolType::STYLUS).x(99).y(100))
2081 .build());
2082 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_STYLUS)
2083 .deviceId(stylusDeviceId1)
2084 .pointer(PointerBuilder(0, ToolType::STYLUS).x(100).y(101))
2085 .build());
2086 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(stylusDeviceId1)));
2087 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(stylusDeviceId1)));
2088
2089 // Second stylus down
2090 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_STYLUS)
2091 .deviceId(stylusDeviceId2)
2092 .pointer(PointerBuilder(0, ToolType::STYLUS).x(9).y(10))
2093 .build());
2094 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_STYLUS)
2095 .deviceId(stylusDeviceId2)
2096 .pointer(PointerBuilder(0, ToolType::STYLUS).x(10).y(11))
2097 .build());
2098
2099 // First stylus is canceled, second one takes over.
2100 window->consumeMotionEvent(
2101 AllOf(WithMotionAction(ACTION_CANCEL), WithDeviceId(stylusDeviceId1)));
2102 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(stylusDeviceId2)));
2103 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(stylusDeviceId2)));
2104
2105 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_STYLUS)
2106 .deviceId(stylusDeviceId1)
2107 .pointer(PointerBuilder(0, ToolType::STYLUS).x(101).y(102))
2108 .build());
2109 // Subsequent stylus movements are delivered correctly
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -07002110 window->assertNoEvents();
2111}
2112
2113/**
Siarhei Vishniakoued89cbb2023-10-13 10:42:44 -07002114 * One window. Stylus down on the window. Then, stylus from another device goes down. Ensure that
2115 * both stylus devices can function simultaneously.
2116 */
2117TEST_F(InputDispatcherMultiDeviceTest, TwoStylusDevicesActiveAtTheSameTime) {
2118 SCOPED_FLAG_OVERRIDE(enable_multi_device_same_window_stream, true);
2119 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
2120 sp<FakeWindowHandle> window =
2121 sp<FakeWindowHandle>::make(application, mDispatcher, "Window", ADISPLAY_ID_DEFAULT);
2122 window->setFrame(Rect(0, 0, 200, 200));
2123
2124 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
2125
2126 constexpr int32_t stylusDeviceId1 = 3;
2127 constexpr int32_t stylusDeviceId2 = 5;
2128
2129 // Touch down on window
2130 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_STYLUS)
2131 .deviceId(stylusDeviceId1)
2132 .pointer(PointerBuilder(0, ToolType::STYLUS).x(99).y(100))
2133 .build());
2134 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_STYLUS)
2135 .deviceId(stylusDeviceId1)
2136 .pointer(PointerBuilder(0, ToolType::STYLUS).x(100).y(101))
2137 .build());
2138 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(stylusDeviceId1)));
2139 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(stylusDeviceId1)));
2140
2141 // Second stylus down
2142 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_STYLUS)
2143 .deviceId(stylusDeviceId2)
2144 .pointer(PointerBuilder(0, ToolType::STYLUS).x(9).y(10))
2145 .build());
2146 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_STYLUS)
2147 .deviceId(stylusDeviceId2)
2148 .pointer(PointerBuilder(0, ToolType::STYLUS).x(10).y(11))
2149 .build());
2150 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(stylusDeviceId2)));
2151 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(stylusDeviceId2)));
2152
2153 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_STYLUS)
2154 .deviceId(stylusDeviceId1)
2155 .pointer(PointerBuilder(0, ToolType::STYLUS).x(101).y(102))
2156 .build());
2157 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(stylusDeviceId1)));
2158 window->assertNoEvents();
2159}
2160
2161/**
Siarhei Vishniakou2899c552023-07-10 18:20:46 -07002162 * One window. Touch down on the window. Then, stylus down on the window from another device.
2163 * Ensure that is canceled, because stylus down should be preferred over touch.
2164 */
2165TEST_F(InputDispatcherMultiDeviceTest, TouchIsCanceledByStylusDown) {
Siarhei Vishniakoued89cbb2023-10-13 10:42:44 -07002166 SCOPED_FLAG_OVERRIDE(enable_multi_device_same_window_stream, false);
Siarhei Vishniakou2899c552023-07-10 18:20:46 -07002167 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
2168 sp<FakeWindowHandle> window =
2169 sp<FakeWindowHandle>::make(application, mDispatcher, "Window", ADISPLAY_ID_DEFAULT);
2170 window->setFrame(Rect(0, 0, 200, 200));
2171
2172 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
2173
2174 constexpr int32_t touchDeviceId = 4;
2175 constexpr int32_t stylusDeviceId = 2;
2176
2177 // Touch down on window
2178 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
2179 .deviceId(touchDeviceId)
2180 .pointer(PointerBuilder(0, ToolType::FINGER).x(140).y(145))
2181 .build());
2182 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN)
2183 .deviceId(touchDeviceId)
2184 .pointer(PointerBuilder(0, ToolType::FINGER).x(141).y(146))
2185 .build());
2186 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(touchDeviceId)));
2187 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(touchDeviceId)));
2188
2189 // Stylus down on the window
2190 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_STYLUS)
2191 .deviceId(stylusDeviceId)
2192 .pointer(PointerBuilder(0, ToolType::STYLUS).x(100).y(110))
2193 .build());
2194 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_CANCEL), WithDeviceId(touchDeviceId)));
2195 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(stylusDeviceId)));
2196
2197 // Subsequent stylus movements are delivered correctly
2198 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_STYLUS)
2199 .deviceId(stylusDeviceId)
2200 .pointer(PointerBuilder(0, ToolType::STYLUS).x(101).y(111))
2201 .build());
2202 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(stylusDeviceId),
2203 WithCoords(101, 111)));
2204}
2205
2206/**
Siarhei Vishniakoued89cbb2023-10-13 10:42:44 -07002207 * One window. Touch down on the window. Then, stylus down on the window from another device.
2208 * Ensure that both touch and stylus are functioning independently.
2209 */
2210TEST_F(InputDispatcherMultiDeviceTest, TouchIsNotCanceledByStylusDown) {
2211 SCOPED_FLAG_OVERRIDE(enable_multi_device_same_window_stream, true);
2212 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
2213 sp<FakeWindowHandle> window =
2214 sp<FakeWindowHandle>::make(application, mDispatcher, "Window", ADISPLAY_ID_DEFAULT);
2215 window->setFrame(Rect(0, 0, 200, 200));
2216
2217 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
2218
2219 constexpr int32_t touchDeviceId = 4;
2220 constexpr int32_t stylusDeviceId = 2;
2221
2222 // Touch down on window
2223 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
2224 .deviceId(touchDeviceId)
2225 .pointer(PointerBuilder(0, ToolType::FINGER).x(140).y(145))
2226 .build());
2227 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN)
2228 .deviceId(touchDeviceId)
2229 .pointer(PointerBuilder(0, ToolType::FINGER).x(141).y(146))
2230 .build());
2231 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(touchDeviceId)));
2232 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(touchDeviceId)));
2233
2234 // Stylus down on the window
2235 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_STYLUS)
2236 .deviceId(stylusDeviceId)
2237 .pointer(PointerBuilder(0, ToolType::STYLUS).x(100).y(110))
2238 .build());
2239 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(stylusDeviceId)));
2240
2241 // Subsequent stylus movements are delivered correctly
2242 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_STYLUS)
2243 .deviceId(stylusDeviceId)
2244 .pointer(PointerBuilder(0, ToolType::STYLUS).x(101).y(111))
2245 .build());
2246 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(stylusDeviceId),
2247 WithCoords(101, 111)));
2248
2249 // Touch continues to work too
2250 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN)
2251 .deviceId(touchDeviceId)
2252 .pointer(PointerBuilder(0, ToolType::FINGER).x(148).y(149))
2253 .build());
2254 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(touchDeviceId)));
2255}
2256
2257/**
Siarhei Vishniakouf372b812023-02-14 18:06:51 -08002258 * Two windows: a window on the left and a window on the right.
2259 * Mouse is clicked on the left window and remains down. Touch is touched on the right and remains
2260 * down. Then, on the left window, also place second touch pointer down.
2261 * This test tries to reproduce a crash.
2262 * In the buggy implementation, second pointer down on the left window would cause a crash.
2263 */
Siarhei Vishniakoued89cbb2023-10-13 10:42:44 -07002264TEST_F(InputDispatcherMultiDeviceTest, MultiDeviceSplitTouch_legacy) {
2265 SCOPED_FLAG_OVERRIDE(enable_multi_device_same_window_stream, false);
Siarhei Vishniakouf372b812023-02-14 18:06:51 -08002266 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
2267 sp<FakeWindowHandle> leftWindow =
2268 sp<FakeWindowHandle>::make(application, mDispatcher, "Left", ADISPLAY_ID_DEFAULT);
2269 leftWindow->setFrame(Rect(0, 0, 200, 200));
2270
2271 sp<FakeWindowHandle> rightWindow =
2272 sp<FakeWindowHandle>::make(application, mDispatcher, "Right", ADISPLAY_ID_DEFAULT);
2273 rightWindow->setFrame(Rect(200, 0, 400, 200));
2274
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07002275 mDispatcher->onWindowInfosChanged(
2276 {{*leftWindow->getInfo(), *rightWindow->getInfo()}, {}, 0, 0});
Siarhei Vishniakouf372b812023-02-14 18:06:51 -08002277
2278 const int32_t touchDeviceId = 4;
2279 const int32_t mouseDeviceId = 6;
Siarhei Vishniakouf372b812023-02-14 18:06:51 -08002280
2281 // Start hovering over the left window
Prabir Pradhan678438e2023-04-13 19:32:51 +00002282 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_ENTER, AINPUT_SOURCE_MOUSE)
2283 .deviceId(mouseDeviceId)
2284 .pointer(PointerBuilder(0, ToolType::MOUSE).x(100).y(100))
2285 .build());
Siarhei Vishniakouf372b812023-02-14 18:06:51 -08002286 leftWindow->consumeMotionEvent(
2287 AllOf(WithMotionAction(ACTION_HOVER_ENTER), WithDeviceId(mouseDeviceId)));
2288
2289 // Mouse down on left window
Prabir Pradhan678438e2023-04-13 19:32:51 +00002290 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_MOUSE)
2291 .deviceId(mouseDeviceId)
2292 .buttonState(AMOTION_EVENT_BUTTON_PRIMARY)
2293 .pointer(PointerBuilder(0, ToolType::MOUSE).x(100).y(100))
2294 .build());
Siarhei Vishniakouf372b812023-02-14 18:06:51 -08002295
2296 leftWindow->consumeMotionEvent(
2297 AllOf(WithMotionAction(ACTION_HOVER_EXIT), WithDeviceId(mouseDeviceId)));
2298 leftWindow->consumeMotionEvent(
2299 AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(mouseDeviceId)));
2300
Prabir Pradhan678438e2023-04-13 19:32:51 +00002301 mDispatcher->notifyMotion(
2302 MotionArgsBuilder(AMOTION_EVENT_ACTION_BUTTON_PRESS, AINPUT_SOURCE_MOUSE)
2303 .deviceId(mouseDeviceId)
2304 .buttonState(AMOTION_EVENT_BUTTON_PRIMARY)
2305 .actionButton(AMOTION_EVENT_BUTTON_PRIMARY)
2306 .pointer(PointerBuilder(0, ToolType::MOUSE).x(100).y(100))
2307 .build());
Siarhei Vishniakouf372b812023-02-14 18:06:51 -08002308 leftWindow->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_BUTTON_PRESS));
2309
2310 // First touch pointer down on right window
Prabir Pradhan678438e2023-04-13 19:32:51 +00002311 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
2312 .deviceId(touchDeviceId)
2313 .pointer(PointerBuilder(0, ToolType::FINGER).x(300).y(100))
2314 .build());
Siarhei Vishniakou2899c552023-07-10 18:20:46 -07002315 leftWindow->assertNoEvents();
2316
Siarhei Vishniakouf372b812023-02-14 18:06:51 -08002317 rightWindow->consumeMotionEvent(WithMotionAction(ACTION_DOWN));
2318
2319 // Second touch pointer down on left window
Prabir Pradhan678438e2023-04-13 19:32:51 +00002320 mDispatcher->notifyMotion(MotionArgsBuilder(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
2321 .deviceId(touchDeviceId)
2322 .pointer(PointerBuilder(0, ToolType::FINGER).x(300).y(100))
2323 .pointer(PointerBuilder(1, ToolType::FINGER).x(100).y(100))
2324 .build());
Siarhei Vishniakou2899c552023-07-10 18:20:46 -07002325 // Since this is now a new splittable pointer going down on the left window, and it's coming
2326 // from a different device, the current gesture in the left window (pointer down) should first
2327 // be canceled.
2328 leftWindow->consumeMotionEvent(
2329 AllOf(WithMotionAction(ACTION_CANCEL), WithDeviceId(mouseDeviceId)));
Siarhei Vishniakouf372b812023-02-14 18:06:51 -08002330 leftWindow->consumeMotionEvent(
2331 AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(touchDeviceId)));
2332 // This MOVE event is not necessary (doesn't carry any new information), but it's there in the
2333 // current implementation.
2334 const std::map<int32_t, PointF> expectedPointers{{0, PointF{100, 100}}};
2335 rightWindow->consumeMotionEvent(
2336 AllOf(WithMotionAction(ACTION_MOVE), WithPointers(expectedPointers)));
2337
2338 leftWindow->assertNoEvents();
2339 rightWindow->assertNoEvents();
2340}
2341
2342/**
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -07002343 * Two windows: a window on the left and a window on the right.
Siarhei Vishniakoued89cbb2023-10-13 10:42:44 -07002344 * Mouse is clicked on the left window and remains down. Touch is touched on the right and remains
2345 * down. Then, on the left window, also place second touch pointer down.
2346 * This test tries to reproduce a crash.
2347 * In the buggy implementation, second pointer down on the left window would cause a crash.
2348 */
2349TEST_F(InputDispatcherMultiDeviceTest, MultiDeviceSplitTouch) {
2350 SCOPED_FLAG_OVERRIDE(enable_multi_device_same_window_stream, true);
2351 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
2352 sp<FakeWindowHandle> leftWindow =
2353 sp<FakeWindowHandle>::make(application, mDispatcher, "Left", ADISPLAY_ID_DEFAULT);
2354 leftWindow->setFrame(Rect(0, 0, 200, 200));
2355
2356 sp<FakeWindowHandle> rightWindow =
2357 sp<FakeWindowHandle>::make(application, mDispatcher, "Right", ADISPLAY_ID_DEFAULT);
2358 rightWindow->setFrame(Rect(200, 0, 400, 200));
2359
2360 mDispatcher->onWindowInfosChanged(
2361 {{*leftWindow->getInfo(), *rightWindow->getInfo()}, {}, 0, 0});
2362
2363 const int32_t touchDeviceId = 4;
2364 const int32_t mouseDeviceId = 6;
2365
2366 // Start hovering over the left window
2367 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_ENTER, AINPUT_SOURCE_MOUSE)
2368 .deviceId(mouseDeviceId)
2369 .pointer(PointerBuilder(0, ToolType::MOUSE).x(100).y(100))
2370 .build());
2371 leftWindow->consumeMotionEvent(
2372 AllOf(WithMotionAction(ACTION_HOVER_ENTER), WithDeviceId(mouseDeviceId)));
2373
2374 // Mouse down on left window
2375 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_MOUSE)
2376 .deviceId(mouseDeviceId)
2377 .buttonState(AMOTION_EVENT_BUTTON_PRIMARY)
2378 .pointer(PointerBuilder(0, ToolType::MOUSE).x(100).y(100))
2379 .build());
2380
2381 leftWindow->consumeMotionEvent(
2382 AllOf(WithMotionAction(ACTION_HOVER_EXIT), WithDeviceId(mouseDeviceId)));
2383 leftWindow->consumeMotionEvent(
2384 AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(mouseDeviceId)));
2385
2386 mDispatcher->notifyMotion(
2387 MotionArgsBuilder(AMOTION_EVENT_ACTION_BUTTON_PRESS, AINPUT_SOURCE_MOUSE)
2388 .deviceId(mouseDeviceId)
2389 .buttonState(AMOTION_EVENT_BUTTON_PRIMARY)
2390 .actionButton(AMOTION_EVENT_BUTTON_PRIMARY)
2391 .pointer(PointerBuilder(0, ToolType::MOUSE).x(100).y(100))
2392 .build());
2393 leftWindow->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_BUTTON_PRESS));
2394
2395 // First touch pointer down on right window
2396 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
2397 .deviceId(touchDeviceId)
2398 .pointer(PointerBuilder(0, ToolType::FINGER).x(300).y(100))
2399 .build());
2400 leftWindow->assertNoEvents();
2401
2402 rightWindow->consumeMotionEvent(WithMotionAction(ACTION_DOWN));
2403
2404 // Second touch pointer down on left window
2405 mDispatcher->notifyMotion(MotionArgsBuilder(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
2406 .deviceId(touchDeviceId)
2407 .pointer(PointerBuilder(0, ToolType::FINGER).x(300).y(100))
2408 .pointer(PointerBuilder(1, ToolType::FINGER).x(100).y(100))
2409 .build());
2410 // Since this is now a new splittable pointer going down on the left window, and it's coming
2411 // from a different device, it will be split and delivered to left window separately.
2412 leftWindow->consumeMotionEvent(
2413 AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(touchDeviceId)));
2414 // This MOVE event is not necessary (doesn't carry any new information), but it's there in the
2415 // current implementation.
2416 const std::map<int32_t, PointF> expectedPointers{{0, PointF{100, 100}}};
2417 rightWindow->consumeMotionEvent(
2418 AllOf(WithMotionAction(ACTION_MOVE), WithPointers(expectedPointers)));
2419
2420 leftWindow->assertNoEvents();
2421 rightWindow->assertNoEvents();
2422}
2423
2424/**
2425 * Two windows: a window on the left and a window on the right.
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -07002426 * Mouse is hovered on the left window and stylus is hovered on the right window.
2427 */
2428TEST_F(InputDispatcherMultiDeviceTest, MultiDeviceHover) {
2429 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
2430 sp<FakeWindowHandle> leftWindow =
2431 sp<FakeWindowHandle>::make(application, mDispatcher, "Left", ADISPLAY_ID_DEFAULT);
2432 leftWindow->setFrame(Rect(0, 0, 200, 200));
2433
2434 sp<FakeWindowHandle> rightWindow =
2435 sp<FakeWindowHandle>::make(application, mDispatcher, "Right", ADISPLAY_ID_DEFAULT);
2436 rightWindow->setFrame(Rect(200, 0, 400, 200));
2437
2438 mDispatcher->onWindowInfosChanged(
2439 {{*leftWindow->getInfo(), *rightWindow->getInfo()}, {}, 0, 0});
2440
2441 const int32_t stylusDeviceId = 3;
2442 const int32_t mouseDeviceId = 6;
2443
2444 // Start hovering over the left window
2445 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_ENTER, AINPUT_SOURCE_MOUSE)
2446 .deviceId(mouseDeviceId)
2447 .pointer(PointerBuilder(0, ToolType::MOUSE).x(100).y(110))
2448 .build());
2449 leftWindow->consumeMotionEvent(
2450 AllOf(WithMotionAction(ACTION_HOVER_ENTER), WithDeviceId(mouseDeviceId)));
2451
2452 // Stylus hovered on right window
2453 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_ENTER, AINPUT_SOURCE_STYLUS)
2454 .deviceId(stylusDeviceId)
2455 .pointer(PointerBuilder(0, ToolType::STYLUS).x(300).y(100))
2456 .build());
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -07002457 rightWindow->consumeMotionEvent(
2458 AllOf(WithMotionAction(ACTION_HOVER_ENTER), WithDeviceId(stylusDeviceId)));
2459
2460 // Subsequent HOVER_MOVE events are dispatched correctly.
2461 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_MOVE, AINPUT_SOURCE_MOUSE)
2462 .deviceId(mouseDeviceId)
2463 .pointer(PointerBuilder(0, ToolType::MOUSE).x(110).y(120))
2464 .build());
2465 leftWindow->consumeMotionEvent(
Siarhei Vishniakou2899c552023-07-10 18:20:46 -07002466 AllOf(WithMotionAction(ACTION_HOVER_MOVE), WithDeviceId(mouseDeviceId)));
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -07002467
2468 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_MOVE, AINPUT_SOURCE_STYLUS)
2469 .deviceId(stylusDeviceId)
2470 .pointer(PointerBuilder(0, ToolType::STYLUS).x(310).y(110))
2471 .build());
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -07002472 rightWindow->consumeMotionEvent(
Siarhei Vishniakou2899c552023-07-10 18:20:46 -07002473 AllOf(WithMotionAction(ACTION_HOVER_MOVE), WithDeviceId(stylusDeviceId)));
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -07002474
2475 leftWindow->assertNoEvents();
2476 rightWindow->assertNoEvents();
2477}
2478
2479/**
2480 * Three windows: a window on the left and a window on the right.
2481 * And a spy window that's positioned above all of them.
2482 * Stylus down on the left window and remains down. Touch goes down on the right and remains down.
2483 * Check the stream that's received by the spy.
2484 */
Siarhei Vishniakoued89cbb2023-10-13 10:42:44 -07002485TEST_F(InputDispatcherMultiDeviceTest, MultiDeviceWithSpy_legacy) {
2486 SCOPED_FLAG_OVERRIDE(enable_multi_device_same_window_stream, false);
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -07002487 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
2488
2489 sp<FakeWindowHandle> spyWindow =
2490 sp<FakeWindowHandle>::make(application, mDispatcher, "Spy", ADISPLAY_ID_DEFAULT);
2491 spyWindow->setFrame(Rect(0, 0, 400, 400));
2492 spyWindow->setTrustedOverlay(true);
2493 spyWindow->setSpy(true);
2494
2495 sp<FakeWindowHandle> leftWindow =
2496 sp<FakeWindowHandle>::make(application, mDispatcher, "Left", ADISPLAY_ID_DEFAULT);
2497 leftWindow->setFrame(Rect(0, 0, 200, 200));
2498
2499 sp<FakeWindowHandle> rightWindow =
2500 sp<FakeWindowHandle>::make(application, mDispatcher, "Right", ADISPLAY_ID_DEFAULT);
2501
2502 rightWindow->setFrame(Rect(200, 0, 400, 200));
2503
2504 mDispatcher->onWindowInfosChanged(
2505 {{*spyWindow->getInfo(), *leftWindow->getInfo(), *rightWindow->getInfo()}, {}, 0, 0});
2506
2507 const int32_t stylusDeviceId = 1;
2508 const int32_t touchDeviceId = 2;
2509
2510 // Stylus down on the left window
2511 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_STYLUS)
2512 .deviceId(stylusDeviceId)
2513 .pointer(PointerBuilder(0, ToolType::STYLUS).x(100).y(100))
2514 .build());
2515 leftWindow->consumeMotionEvent(
2516 AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(stylusDeviceId)));
2517 spyWindow->consumeMotionEvent(
2518 AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(stylusDeviceId)));
2519
2520 // Touch down on the right window
2521 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
2522 .deviceId(touchDeviceId)
2523 .pointer(PointerBuilder(0, ToolType::FINGER).x(300).y(100))
2524 .build());
Siarhei Vishniakou2899c552023-07-10 18:20:46 -07002525 leftWindow->assertNoEvents();
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -07002526 rightWindow->consumeMotionEvent(
2527 AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(touchDeviceId)));
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -07002528
Siarhei Vishniakou2899c552023-07-10 18:20:46 -07002529 // Spy window does not receive touch events, because stylus events take precedence, and it
2530 // already has an active stylus gesture.
2531
2532 // Stylus movements continue. They should be delivered to the left window and to the spy window
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -07002533 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_STYLUS)
2534 .deviceId(stylusDeviceId)
2535 .pointer(PointerBuilder(0, ToolType::STYLUS).x(110).y(110))
2536 .build());
Siarhei Vishniakou2899c552023-07-10 18:20:46 -07002537 leftWindow->consumeMotionEvent(
2538 AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(stylusDeviceId)));
2539 spyWindow->consumeMotionEvent(
2540 AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(stylusDeviceId)));
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -07002541
Siarhei Vishniakou2899c552023-07-10 18:20:46 -07002542 // Further MOVE events keep going to the right window only
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -07002543 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN)
2544 .deviceId(touchDeviceId)
2545 .pointer(PointerBuilder(0, ToolType::FINGER).x(310).y(110))
2546 .build());
2547 rightWindow->consumeMotionEvent(
2548 AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(touchDeviceId)));
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -07002549
2550 spyWindow->assertNoEvents();
2551 leftWindow->assertNoEvents();
2552 rightWindow->assertNoEvents();
2553}
2554
2555/**
Siarhei Vishniakoued89cbb2023-10-13 10:42:44 -07002556 * Three windows: a window on the left and a window on the right.
2557 * And a spy window that's positioned above all of them.
2558 * Stylus down on the left window and remains down. Touch goes down on the right and remains down.
2559 * Check the stream that's received by the spy.
2560 */
2561TEST_F(InputDispatcherMultiDeviceTest, MultiDeviceWithSpy) {
2562 SCOPED_FLAG_OVERRIDE(enable_multi_device_same_window_stream, true);
2563 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
2564
2565 sp<FakeWindowHandle> spyWindow =
2566 sp<FakeWindowHandle>::make(application, mDispatcher, "Spy", ADISPLAY_ID_DEFAULT);
2567 spyWindow->setFrame(Rect(0, 0, 400, 400));
2568 spyWindow->setTrustedOverlay(true);
2569 spyWindow->setSpy(true);
2570
2571 sp<FakeWindowHandle> leftWindow =
2572 sp<FakeWindowHandle>::make(application, mDispatcher, "Left", ADISPLAY_ID_DEFAULT);
2573 leftWindow->setFrame(Rect(0, 0, 200, 200));
2574
2575 sp<FakeWindowHandle> rightWindow =
2576 sp<FakeWindowHandle>::make(application, mDispatcher, "Right", ADISPLAY_ID_DEFAULT);
2577
2578 rightWindow->setFrame(Rect(200, 0, 400, 200));
2579
2580 mDispatcher->onWindowInfosChanged(
2581 {{*spyWindow->getInfo(), *leftWindow->getInfo(), *rightWindow->getInfo()}, {}, 0, 0});
2582
2583 const int32_t stylusDeviceId = 1;
2584 const int32_t touchDeviceId = 2;
2585
2586 // Stylus down on the left window
2587 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_STYLUS)
2588 .deviceId(stylusDeviceId)
2589 .pointer(PointerBuilder(0, ToolType::STYLUS).x(100).y(100))
2590 .build());
2591 leftWindow->consumeMotionEvent(
2592 AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(stylusDeviceId)));
2593 spyWindow->consumeMotionEvent(
2594 AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(stylusDeviceId)));
2595
2596 // Touch down on the right window
2597 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
2598 .deviceId(touchDeviceId)
2599 .pointer(PointerBuilder(0, ToolType::FINGER).x(300).y(100))
2600 .build());
2601 leftWindow->assertNoEvents();
2602 rightWindow->consumeMotionEvent(
2603 AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(touchDeviceId)));
2604 spyWindow->consumeMotionEvent(
2605 AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(touchDeviceId)));
2606
2607 // Stylus movements continue. They should be delivered to the left window and to the spy window
2608 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_STYLUS)
2609 .deviceId(stylusDeviceId)
2610 .pointer(PointerBuilder(0, ToolType::STYLUS).x(110).y(110))
2611 .build());
2612 leftWindow->consumeMotionEvent(
2613 AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(stylusDeviceId)));
2614 spyWindow->consumeMotionEvent(
2615 AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(stylusDeviceId)));
2616
2617 // Further touch MOVE events keep going to the right window and to the spy
2618 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN)
2619 .deviceId(touchDeviceId)
2620 .pointer(PointerBuilder(0, ToolType::FINGER).x(310).y(110))
2621 .build());
2622 rightWindow->consumeMotionEvent(
2623 AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(touchDeviceId)));
2624 spyWindow->consumeMotionEvent(
2625 AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(touchDeviceId)));
2626
2627 spyWindow->assertNoEvents();
2628 leftWindow->assertNoEvents();
2629 rightWindow->assertNoEvents();
2630}
2631
2632/**
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -07002633 * Three windows: a window on the left, a window on the right, and a spy window positioned above
2634 * both.
2635 * Check hover in left window and touch down in the right window.
Siarhei Vishniakou3ad54f52023-11-02 16:54:40 -07002636 * At first, spy should receive hover. Spy shouldn't receive touch while stylus is hovering.
Siarhei Vishniakou2899c552023-07-10 18:20:46 -07002637 * At the same time, left and right should be getting independent streams of hovering and touch,
2638 * respectively.
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -07002639 */
Siarhei Vishniakou3ad54f52023-11-02 16:54:40 -07002640TEST_F(InputDispatcherMultiDeviceTest, MultiDeviceHoverBlocksTouchWithSpy) {
Siarhei Vishniakoued89cbb2023-10-13 10:42:44 -07002641 SCOPED_FLAG_OVERRIDE(enable_multi_device_same_window_stream, false);
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -07002642 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
2643
2644 sp<FakeWindowHandle> spyWindow =
2645 sp<FakeWindowHandle>::make(application, mDispatcher, "Spy", ADISPLAY_ID_DEFAULT);
2646 spyWindow->setFrame(Rect(0, 0, 400, 400));
2647 spyWindow->setTrustedOverlay(true);
2648 spyWindow->setSpy(true);
2649
2650 sp<FakeWindowHandle> leftWindow =
2651 sp<FakeWindowHandle>::make(application, mDispatcher, "Left", ADISPLAY_ID_DEFAULT);
2652 leftWindow->setFrame(Rect(0, 0, 200, 200));
2653
2654 sp<FakeWindowHandle> rightWindow =
2655 sp<FakeWindowHandle>::make(application, mDispatcher, "Right", ADISPLAY_ID_DEFAULT);
2656 rightWindow->setFrame(Rect(200, 0, 400, 200));
2657
2658 mDispatcher->onWindowInfosChanged(
2659 {{*spyWindow->getInfo(), *leftWindow->getInfo(), *rightWindow->getInfo()}, {}, 0, 0});
2660
2661 const int32_t stylusDeviceId = 1;
2662 const int32_t touchDeviceId = 2;
2663
2664 // Stylus hover on the left window
2665 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_ENTER, AINPUT_SOURCE_STYLUS)
2666 .deviceId(stylusDeviceId)
2667 .pointer(PointerBuilder(0, ToolType::STYLUS).x(100).y(100))
2668 .build());
2669 leftWindow->consumeMotionEvent(
2670 AllOf(WithMotionAction(ACTION_HOVER_ENTER), WithDeviceId(stylusDeviceId)));
2671 spyWindow->consumeMotionEvent(
2672 AllOf(WithMotionAction(ACTION_HOVER_ENTER), WithDeviceId(stylusDeviceId)));
2673
Siarhei Vishniakou2899c552023-07-10 18:20:46 -07002674 // Touch down on the right window. Spy doesn't receive this touch because it already has
2675 // stylus hovering there.
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -07002676 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
2677 .deviceId(touchDeviceId)
2678 .pointer(PointerBuilder(0, ToolType::FINGER).x(300).y(100))
2679 .build());
Siarhei Vishniakou2899c552023-07-10 18:20:46 -07002680 leftWindow->assertNoEvents();
Siarhei Vishniakou3ad54f52023-11-02 16:54:40 -07002681 spyWindow->assertNoEvents();
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -07002682 rightWindow->consumeMotionEvent(
2683 AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(touchDeviceId)));
2684
Siarhei Vishniakou3ad54f52023-11-02 16:54:40 -07002685 // Stylus movements continue. They should be delivered to the left window and the spy.
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -07002686 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_MOVE, AINPUT_SOURCE_STYLUS)
2687 .deviceId(stylusDeviceId)
2688 .pointer(PointerBuilder(0, ToolType::STYLUS).x(110).y(110))
2689 .build());
Siarhei Vishniakou2899c552023-07-10 18:20:46 -07002690 leftWindow->consumeMotionEvent(
2691 AllOf(WithMotionAction(ACTION_HOVER_MOVE), WithDeviceId(stylusDeviceId)));
Siarhei Vishniakou3ad54f52023-11-02 16:54:40 -07002692 spyWindow->consumeMotionEvent(
2693 AllOf(WithMotionAction(ACTION_HOVER_MOVE), WithDeviceId(stylusDeviceId)));
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -07002694
Siarhei Vishniakou3ad54f52023-11-02 16:54:40 -07002695 // Touch movements continue. They should be delivered to the right window only
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -07002696 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN)
2697 .deviceId(touchDeviceId)
2698 .pointer(PointerBuilder(0, ToolType::FINGER).x(301).y(101))
2699 .build());
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -07002700 rightWindow->consumeMotionEvent(
2701 AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(touchDeviceId)));
2702
2703 spyWindow->assertNoEvents();
2704 leftWindow->assertNoEvents();
2705 rightWindow->assertNoEvents();
2706}
2707
2708/**
Siarhei Vishniakoued89cbb2023-10-13 10:42:44 -07002709 * Three windows: a window on the left, a window on the right, and a spy window positioned above
2710 * both.
2711 * Check hover in left window and touch down in the right window.
2712 * At first, spy should receive hover. Next, spy should receive touch.
2713 * At the same time, left and right should be getting independent streams of hovering and touch,
2714 * respectively.
2715 */
2716TEST_F(InputDispatcherMultiDeviceTest, MultiDeviceHoverDoesNotBlockTouchWithSpy) {
2717 SCOPED_FLAG_OVERRIDE(enable_multi_device_same_window_stream, true);
2718 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
2719
2720 sp<FakeWindowHandle> spyWindow =
2721 sp<FakeWindowHandle>::make(application, mDispatcher, "Spy", ADISPLAY_ID_DEFAULT);
2722 spyWindow->setFrame(Rect(0, 0, 400, 400));
2723 spyWindow->setTrustedOverlay(true);
2724 spyWindow->setSpy(true);
2725
2726 sp<FakeWindowHandle> leftWindow =
2727 sp<FakeWindowHandle>::make(application, mDispatcher, "Left", ADISPLAY_ID_DEFAULT);
2728 leftWindow->setFrame(Rect(0, 0, 200, 200));
2729
2730 sp<FakeWindowHandle> rightWindow =
2731 sp<FakeWindowHandle>::make(application, mDispatcher, "Right", ADISPLAY_ID_DEFAULT);
2732 rightWindow->setFrame(Rect(200, 0, 400, 200));
2733
2734 mDispatcher->onWindowInfosChanged(
2735 {{*spyWindow->getInfo(), *leftWindow->getInfo(), *rightWindow->getInfo()}, {}, 0, 0});
2736
2737 const int32_t stylusDeviceId = 1;
2738 const int32_t touchDeviceId = 2;
2739
2740 // Stylus hover on the left window
2741 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_ENTER, AINPUT_SOURCE_STYLUS)
2742 .deviceId(stylusDeviceId)
2743 .pointer(PointerBuilder(0, ToolType::STYLUS).x(100).y(100))
2744 .build());
2745 leftWindow->consumeMotionEvent(
2746 AllOf(WithMotionAction(ACTION_HOVER_ENTER), WithDeviceId(stylusDeviceId)));
2747 spyWindow->consumeMotionEvent(
2748 AllOf(WithMotionAction(ACTION_HOVER_ENTER), WithDeviceId(stylusDeviceId)));
2749
2750 // Touch down on the right window.
2751 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
2752 .deviceId(touchDeviceId)
2753 .pointer(PointerBuilder(0, ToolType::FINGER).x(300).y(100))
2754 .build());
2755 leftWindow->assertNoEvents();
2756 spyWindow->consumeMotionEvent(
2757 AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(touchDeviceId)));
2758 rightWindow->consumeMotionEvent(
2759 AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(touchDeviceId)));
2760
2761 // Stylus movements continue. They should be delivered to the left window and the spy.
2762 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_MOVE, AINPUT_SOURCE_STYLUS)
2763 .deviceId(stylusDeviceId)
2764 .pointer(PointerBuilder(0, ToolType::STYLUS).x(110).y(110))
2765 .build());
2766 leftWindow->consumeMotionEvent(
2767 AllOf(WithMotionAction(ACTION_HOVER_MOVE), WithDeviceId(stylusDeviceId)));
2768 spyWindow->consumeMotionEvent(
2769 AllOf(WithMotionAction(ACTION_HOVER_MOVE), WithDeviceId(stylusDeviceId)));
2770
2771 // Touch movements continue. They should be delivered to the right window and the spy
2772 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN)
2773 .deviceId(touchDeviceId)
2774 .pointer(PointerBuilder(0, ToolType::FINGER).x(301).y(101))
2775 .build());
2776 rightWindow->consumeMotionEvent(
2777 AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(touchDeviceId)));
2778 spyWindow->consumeMotionEvent(
2779 AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(touchDeviceId)));
2780
2781 spyWindow->assertNoEvents();
2782 leftWindow->assertNoEvents();
2783 rightWindow->assertNoEvents();
2784}
2785
2786/**
Siarhei Vishniakouf372b812023-02-14 18:06:51 -08002787 * On a single window, use two different devices: mouse and touch.
2788 * Touch happens first, with two pointers going down, and then the first pointer leaving.
2789 * Mouse is clicked next, which causes the touch stream to be aborted with ACTION_CANCEL.
2790 * Finally, a second touch pointer goes down again. Ensure the second touch pointer is ignored,
2791 * because the mouse is currently down, and a POINTER_DOWN event from the touchscreen does not
2792 * represent a new gesture.
2793 */
Siarhei Vishniakoued89cbb2023-10-13 10:42:44 -07002794TEST_F(InputDispatcherMultiDeviceTest, MixedTouchAndMouseWithPointerDown_legacy) {
2795 SCOPED_FLAG_OVERRIDE(enable_multi_device_same_window_stream, false);
Siarhei Vishniakouf372b812023-02-14 18:06:51 -08002796 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
2797 sp<FakeWindowHandle> window =
2798 sp<FakeWindowHandle>::make(application, mDispatcher, "Window", ADISPLAY_ID_DEFAULT);
2799 window->setFrame(Rect(0, 0, 400, 400));
2800
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07002801 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Siarhei Vishniakouf372b812023-02-14 18:06:51 -08002802
2803 const int32_t touchDeviceId = 4;
2804 const int32_t mouseDeviceId = 6;
Siarhei Vishniakouf372b812023-02-14 18:06:51 -08002805
Siarhei Vishniakou4e1ffa52023-02-21 11:50:34 -08002806 // First touch pointer down
Prabir Pradhan678438e2023-04-13 19:32:51 +00002807 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
2808 .deviceId(touchDeviceId)
2809 .pointer(PointerBuilder(0, ToolType::FINGER).x(300).y(100))
2810 .build());
Siarhei Vishniakouf372b812023-02-14 18:06:51 -08002811 // Second touch pointer down
Prabir Pradhan678438e2023-04-13 19:32:51 +00002812 mDispatcher->notifyMotion(MotionArgsBuilder(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
2813 .deviceId(touchDeviceId)
2814 .pointer(PointerBuilder(0, ToolType::FINGER).x(300).y(100))
2815 .pointer(PointerBuilder(1, ToolType::FINGER).x(350).y(100))
2816 .build());
Siarhei Vishniakouf372b812023-02-14 18:06:51 -08002817 // First touch pointer lifts. The second one remains down
Prabir Pradhan678438e2023-04-13 19:32:51 +00002818 mDispatcher->notifyMotion(MotionArgsBuilder(POINTER_0_UP, AINPUT_SOURCE_TOUCHSCREEN)
2819 .deviceId(touchDeviceId)
2820 .pointer(PointerBuilder(0, ToolType::FINGER).x(300).y(100))
2821 .pointer(PointerBuilder(1, ToolType::FINGER).x(350).y(100))
2822 .build());
Siarhei Vishniakouf372b812023-02-14 18:06:51 -08002823 window->consumeMotionEvent(WithMotionAction(ACTION_DOWN));
2824 window->consumeMotionEvent(WithMotionAction(POINTER_1_DOWN));
2825 window->consumeMotionEvent(WithMotionAction(POINTER_0_UP));
2826
2827 // Mouse down. The touch should be canceled
Prabir Pradhan678438e2023-04-13 19:32:51 +00002828 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_MOUSE)
2829 .deviceId(mouseDeviceId)
2830 .buttonState(AMOTION_EVENT_BUTTON_PRIMARY)
2831 .pointer(PointerBuilder(0, ToolType::MOUSE).x(320).y(100))
2832 .build());
Siarhei Vishniakouf372b812023-02-14 18:06:51 -08002833
2834 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_CANCEL), WithDeviceId(touchDeviceId),
Siarhei Vishniakou82dc0422023-02-17 23:12:52 -08002835 WithPointerCount(1u)));
Siarhei Vishniakouf372b812023-02-14 18:06:51 -08002836 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(mouseDeviceId)));
2837
Prabir Pradhan678438e2023-04-13 19:32:51 +00002838 mDispatcher->notifyMotion(
2839 MotionArgsBuilder(AMOTION_EVENT_ACTION_BUTTON_PRESS, AINPUT_SOURCE_MOUSE)
2840 .deviceId(mouseDeviceId)
2841 .buttonState(AMOTION_EVENT_BUTTON_PRIMARY)
2842 .actionButton(AMOTION_EVENT_BUTTON_PRIMARY)
2843 .pointer(PointerBuilder(0, ToolType::MOUSE).x(320).y(100))
2844 .build());
Siarhei Vishniakouf372b812023-02-14 18:06:51 -08002845 window->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_BUTTON_PRESS));
2846
2847 // Second touch pointer down.
Prabir Pradhan678438e2023-04-13 19:32:51 +00002848 mDispatcher->notifyMotion(MotionArgsBuilder(POINTER_0_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
2849 .deviceId(touchDeviceId)
2850 .pointer(PointerBuilder(0, ToolType::FINGER).x(300).y(100))
2851 .pointer(PointerBuilder(1, ToolType::FINGER).x(350).y(100))
2852 .build());
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -07002853 // Since we already canceled this touch gesture, it will be ignored until a completely new
2854 // gesture is started. This is easier to implement than trying to keep track of the new pointer
2855 // and generating an ACTION_DOWN instead of ACTION_POINTER_DOWN.
2856 // However, mouse movements should continue to work.
2857 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_MOUSE)
2858 .deviceId(mouseDeviceId)
2859 .buttonState(AMOTION_EVENT_BUTTON_PRIMARY)
2860 .pointer(PointerBuilder(0, ToolType::MOUSE).x(330).y(110))
2861 .build());
2862 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(mouseDeviceId)));
2863
Siarhei Vishniakouf372b812023-02-14 18:06:51 -08002864 window->assertNoEvents();
2865}
2866
2867/**
Siarhei Vishniakoued89cbb2023-10-13 10:42:44 -07002868 * On a single window, use two different devices: mouse and touch.
2869 * Touch happens first, with two pointers going down, and then the first pointer leaving.
2870 * Mouse is clicked next, which should not interfere with the touch stream.
2871 * Finally, a second touch pointer goes down again. Ensure the second touch pointer is also
2872 * delivered correctly.
2873 */
2874TEST_F(InputDispatcherMultiDeviceTest, MixedTouchAndMouseWithPointerDown) {
2875 SCOPED_FLAG_OVERRIDE(enable_multi_device_same_window_stream, true);
2876 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
2877 sp<FakeWindowHandle> window =
2878 sp<FakeWindowHandle>::make(application, mDispatcher, "Window", ADISPLAY_ID_DEFAULT);
2879 window->setFrame(Rect(0, 0, 400, 400));
2880
2881 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
2882
2883 const int32_t touchDeviceId = 4;
2884 const int32_t mouseDeviceId = 6;
2885
2886 // First touch pointer down
2887 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
2888 .deviceId(touchDeviceId)
2889 .pointer(PointerBuilder(0, ToolType::FINGER).x(300).y(100))
2890 .build());
2891 // Second touch pointer down
2892 mDispatcher->notifyMotion(MotionArgsBuilder(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
2893 .deviceId(touchDeviceId)
2894 .pointer(PointerBuilder(0, ToolType::FINGER).x(300).y(100))
2895 .pointer(PointerBuilder(1, ToolType::FINGER).x(350).y(100))
2896 .build());
2897 // First touch pointer lifts. The second one remains down
2898 mDispatcher->notifyMotion(MotionArgsBuilder(POINTER_0_UP, AINPUT_SOURCE_TOUCHSCREEN)
2899 .deviceId(touchDeviceId)
2900 .pointer(PointerBuilder(0, ToolType::FINGER).x(300).y(100))
2901 .pointer(PointerBuilder(1, ToolType::FINGER).x(350).y(100))
2902 .build());
2903 window->consumeMotionEvent(WithMotionAction(ACTION_DOWN));
2904 window->consumeMotionEvent(WithMotionAction(POINTER_1_DOWN));
2905 window->consumeMotionEvent(WithMotionAction(POINTER_0_UP));
2906
2907 // Mouse down
2908 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_MOUSE)
2909 .deviceId(mouseDeviceId)
2910 .buttonState(AMOTION_EVENT_BUTTON_PRIMARY)
2911 .pointer(PointerBuilder(0, ToolType::MOUSE).x(320).y(100))
2912 .build());
2913
2914 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(mouseDeviceId)));
2915
2916 mDispatcher->notifyMotion(
2917 MotionArgsBuilder(AMOTION_EVENT_ACTION_BUTTON_PRESS, AINPUT_SOURCE_MOUSE)
2918 .deviceId(mouseDeviceId)
2919 .buttonState(AMOTION_EVENT_BUTTON_PRIMARY)
2920 .actionButton(AMOTION_EVENT_BUTTON_PRIMARY)
2921 .pointer(PointerBuilder(0, ToolType::MOUSE).x(320).y(100))
2922 .build());
2923 window->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_BUTTON_PRESS));
2924
2925 // Second touch pointer down.
2926 mDispatcher->notifyMotion(MotionArgsBuilder(POINTER_0_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
2927 .deviceId(touchDeviceId)
2928 .pointer(PointerBuilder(0, ToolType::FINGER).x(300).y(100))
2929 .pointer(PointerBuilder(1, ToolType::FINGER).x(350).y(100))
2930 .build());
2931 window->consumeMotionEvent(AllOf(WithMotionAction(POINTER_0_DOWN), WithDeviceId(touchDeviceId),
2932 WithPointerCount(2u)));
2933
2934 // Mouse movements should continue to work
2935 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_MOUSE)
2936 .deviceId(mouseDeviceId)
2937 .buttonState(AMOTION_EVENT_BUTTON_PRIMARY)
2938 .pointer(PointerBuilder(0, ToolType::MOUSE).x(330).y(110))
2939 .build());
2940 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(mouseDeviceId)));
2941
2942 window->assertNoEvents();
2943}
2944
2945/**
Siarhei Vishniakou56e79092023-02-21 19:13:16 -08002946 * Inject a touch down and then send a new event via 'notifyMotion'. Ensure the new event cancels
2947 * the injected event.
2948 */
Siarhei Vishniakoued89cbb2023-10-13 10:42:44 -07002949TEST_F(InputDispatcherMultiDeviceTest, UnfinishedInjectedEvent_legacy) {
2950 SCOPED_FLAG_OVERRIDE(enable_multi_device_same_window_stream, false);
Siarhei Vishniakou56e79092023-02-21 19:13:16 -08002951 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
2952 sp<FakeWindowHandle> window =
2953 sp<FakeWindowHandle>::make(application, mDispatcher, "Window", ADISPLAY_ID_DEFAULT);
2954 window->setFrame(Rect(0, 0, 400, 400));
2955
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07002956 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Siarhei Vishniakou56e79092023-02-21 19:13:16 -08002957
2958 const int32_t touchDeviceId = 4;
Siarhei Vishniakou56e79092023-02-21 19:13:16 -08002959 // Pretend a test injects an ACTION_DOWN mouse event, but forgets to lift up the touch after
2960 // completion.
2961 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07002962 injectMotionEvent(*mDispatcher,
Siarhei Vishniakou56e79092023-02-21 19:13:16 -08002963 MotionEventBuilder(ACTION_DOWN, AINPUT_SOURCE_MOUSE)
2964 .deviceId(ReservedInputDeviceId::VIRTUAL_KEYBOARD_ID)
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07002965 .pointer(PointerBuilder(0, ToolType::MOUSE).x(50).y(50))
Siarhei Vishniakou56e79092023-02-21 19:13:16 -08002966 .build()));
2967 window->consumeMotionEvent(
2968 AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(VIRTUAL_KEYBOARD_ID)));
2969
2970 // Now a real touch comes. Rather than crashing or dropping the real event, the injected pointer
2971 // should be canceled and the new gesture should take over.
Prabir Pradhan678438e2023-04-13 19:32:51 +00002972 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
2973 .deviceId(touchDeviceId)
2974 .pointer(PointerBuilder(0, ToolType::FINGER).x(300).y(100))
2975 .build());
Siarhei Vishniakou56e79092023-02-21 19:13:16 -08002976
2977 window->consumeMotionEvent(
2978 AllOf(WithMotionAction(ACTION_CANCEL), WithDeviceId(VIRTUAL_KEYBOARD_ID)));
2979 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(touchDeviceId)));
2980}
2981
2982/**
Siarhei Vishniakoued89cbb2023-10-13 10:42:44 -07002983 * Inject a touch down and then send a new event via 'notifyMotion'. Ensure the new event runs
2984 * parallel to the injected event.
2985 */
2986TEST_F(InputDispatcherMultiDeviceTest, UnfinishedInjectedEvent) {
2987 SCOPED_FLAG_OVERRIDE(enable_multi_device_same_window_stream, true);
2988 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
2989 sp<FakeWindowHandle> window =
2990 sp<FakeWindowHandle>::make(application, mDispatcher, "Window", ADISPLAY_ID_DEFAULT);
2991 window->setFrame(Rect(0, 0, 400, 400));
2992
2993 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
2994
2995 const int32_t touchDeviceId = 4;
2996 // Pretend a test injects an ACTION_DOWN mouse event, but forgets to lift up the touch after
2997 // completion.
2998 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
2999 injectMotionEvent(*mDispatcher,
3000 MotionEventBuilder(ACTION_DOWN, AINPUT_SOURCE_MOUSE)
3001 .deviceId(ReservedInputDeviceId::VIRTUAL_KEYBOARD_ID)
3002 .pointer(PointerBuilder(0, ToolType::MOUSE).x(50).y(50))
3003 .build()));
3004 window->consumeMotionEvent(
3005 AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(VIRTUAL_KEYBOARD_ID)));
3006
3007 // Now a real touch comes. The injected pointer will remain, and the new gesture will also be
3008 // allowed through.
3009 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
3010 .deviceId(touchDeviceId)
3011 .pointer(PointerBuilder(0, ToolType::FINGER).x(300).y(100))
3012 .build());
3013 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(touchDeviceId)));
3014}
3015
3016/**
Siarhei Vishniakou6464e462023-02-06 18:57:59 -08003017 * This test is similar to the test above, but the sequence of injected events is different.
3018 *
3019 * Two windows: a window on the left and a window on the right.
3020 * Mouse is hovered over the left window.
3021 * Next, we tap on the left window, where the cursor was last seen.
3022 *
3023 * After that, we inject one finger down onto the right window, and then a second finger down onto
3024 * the left window.
3025 * The touch is split, so this last gesture should cause 2 ACTION_DOWN events, one in the right
3026 * window (first), and then another on the left window (second).
3027 * This test reproduces a crash where there is a mismatch between the downTime and eventTime.
3028 * In the buggy implementation, second finger down on the left window would cause a crash.
3029 */
Siarhei Vishniakoued89cbb2023-10-13 10:42:44 -07003030TEST_F(InputDispatcherMultiDeviceTest, HoverTapAndSplitTouch_legacy) {
3031 SCOPED_FLAG_OVERRIDE(enable_multi_device_same_window_stream, false);
Siarhei Vishniakou6464e462023-02-06 18:57:59 -08003032 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
3033 sp<FakeWindowHandle> leftWindow =
3034 sp<FakeWindowHandle>::make(application, mDispatcher, "Left", ADISPLAY_ID_DEFAULT);
3035 leftWindow->setFrame(Rect(0, 0, 200, 200));
3036
3037 sp<FakeWindowHandle> rightWindow =
3038 sp<FakeWindowHandle>::make(application, mDispatcher, "Right", ADISPLAY_ID_DEFAULT);
3039 rightWindow->setFrame(Rect(200, 0, 400, 200));
3040
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07003041 mDispatcher->onWindowInfosChanged(
3042 {{*leftWindow->getInfo(), *rightWindow->getInfo()}, {}, 0, 0});
Siarhei Vishniakou6464e462023-02-06 18:57:59 -08003043
3044 const int32_t mouseDeviceId = 6;
3045 const int32_t touchDeviceId = 4;
3046 // Hover over the left window. Keep the cursor there.
3047 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07003048 injectMotionEvent(*mDispatcher,
Siarhei Vishniakou6464e462023-02-06 18:57:59 -08003049 MotionEventBuilder(AMOTION_EVENT_ACTION_HOVER_ENTER,
3050 AINPUT_SOURCE_MOUSE)
3051 .deviceId(mouseDeviceId)
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07003052 .pointer(PointerBuilder(0, ToolType::MOUSE).x(50).y(50))
Siarhei Vishniakou6464e462023-02-06 18:57:59 -08003053 .build()));
3054 leftWindow->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_ENTER));
3055
3056 // Tap on left window
3057 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07003058 injectMotionEvent(*mDispatcher,
Siarhei Vishniakou6464e462023-02-06 18:57:59 -08003059 MotionEventBuilder(AMOTION_EVENT_ACTION_DOWN,
3060 AINPUT_SOURCE_TOUCHSCREEN)
3061 .deviceId(touchDeviceId)
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07003062 .pointer(PointerBuilder(0, ToolType::FINGER).x(100).y(100))
Siarhei Vishniakou6464e462023-02-06 18:57:59 -08003063 .build()));
3064
3065 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07003066 injectMotionEvent(*mDispatcher,
Siarhei Vishniakou6464e462023-02-06 18:57:59 -08003067 MotionEventBuilder(AMOTION_EVENT_ACTION_UP,
3068 AINPUT_SOURCE_TOUCHSCREEN)
3069 .deviceId(touchDeviceId)
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07003070 .pointer(PointerBuilder(0, ToolType::FINGER).x(100).y(100))
Siarhei Vishniakou6464e462023-02-06 18:57:59 -08003071 .build()));
3072 leftWindow->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_EXIT));
3073 leftWindow->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_DOWN));
3074 leftWindow->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_UP));
3075
3076 // First finger down on right window
3077 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07003078 injectMotionEvent(*mDispatcher,
Siarhei Vishniakou6464e462023-02-06 18:57:59 -08003079 MotionEventBuilder(AMOTION_EVENT_ACTION_DOWN,
3080 AINPUT_SOURCE_TOUCHSCREEN)
3081 .deviceId(touchDeviceId)
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07003082 .pointer(PointerBuilder(0, ToolType::FINGER).x(300).y(100))
Siarhei Vishniakou6464e462023-02-06 18:57:59 -08003083 .build()));
3084 rightWindow->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_DOWN));
3085
3086 // Second finger down on the left window
3087 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07003088 injectMotionEvent(*mDispatcher,
Siarhei Vishniakou6464e462023-02-06 18:57:59 -08003089 MotionEventBuilder(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
3090 .deviceId(touchDeviceId)
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07003091 .pointer(PointerBuilder(0, ToolType::FINGER).x(300).y(100))
3092 .pointer(PointerBuilder(1, ToolType::FINGER).x(100).y(100))
Siarhei Vishniakou6464e462023-02-06 18:57:59 -08003093 .build()));
3094 leftWindow->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_DOWN));
3095 rightWindow->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_MOVE));
3096
3097 // No more events
3098 leftWindow->assertNoEvents();
3099 rightWindow->assertNoEvents();
3100}
3101
3102/**
Siarhei Vishniakoued89cbb2023-10-13 10:42:44 -07003103 * This test is similar to the test above, but the sequence of injected events is different.
3104 *
3105 * Two windows: a window on the left and a window on the right.
3106 * Mouse is hovered over the left window.
3107 * Next, we tap on the left window, where the cursor was last seen.
3108 *
3109 * After that, we send one finger down onto the right window, and then a second finger down onto
3110 * the left window.
3111 * The touch is split, so this last gesture should cause 2 ACTION_DOWN events, one in the right
3112 * window (first), and then another on the left window (second).
3113 * This test reproduces a crash where there is a mismatch between the downTime and eventTime.
3114 * In the buggy implementation, second finger down on the left window would cause a crash.
3115 */
3116TEST_F(InputDispatcherMultiDeviceTest, HoverTapAndSplitTouch) {
3117 SCOPED_FLAG_OVERRIDE(enable_multi_device_same_window_stream, true);
3118 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
3119 sp<FakeWindowHandle> leftWindow =
3120 sp<FakeWindowHandle>::make(application, mDispatcher, "Left", ADISPLAY_ID_DEFAULT);
3121 leftWindow->setFrame(Rect(0, 0, 200, 200));
3122
3123 sp<FakeWindowHandle> rightWindow =
3124 sp<FakeWindowHandle>::make(application, mDispatcher, "Right", ADISPLAY_ID_DEFAULT);
3125 rightWindow->setFrame(Rect(200, 0, 400, 200));
3126
3127 mDispatcher->onWindowInfosChanged(
3128 {{*leftWindow->getInfo(), *rightWindow->getInfo()}, {}, 0, 0});
3129
3130 const int32_t mouseDeviceId = 6;
3131 const int32_t touchDeviceId = 4;
3132 // Hover over the left window. Keep the cursor there.
3133 mDispatcher->notifyMotion(
3134 MotionArgsBuilder(AMOTION_EVENT_ACTION_HOVER_ENTER, AINPUT_SOURCE_MOUSE)
3135 .deviceId(mouseDeviceId)
3136 .pointer(PointerBuilder(0, ToolType::MOUSE).x(50).y(50))
3137 .build());
3138 leftWindow->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_ENTER));
3139
3140 // Tap on left window
3141 mDispatcher->notifyMotion(
3142 MotionArgsBuilder(AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
3143 .deviceId(touchDeviceId)
3144 .pointer(PointerBuilder(0, ToolType::FINGER).x(100).y(100))
3145 .build());
3146
3147 mDispatcher->notifyMotion(MotionArgsBuilder(AMOTION_EVENT_ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN)
3148 .deviceId(touchDeviceId)
3149 .pointer(PointerBuilder(0, ToolType::FINGER).x(100).y(100))
3150 .build());
3151 leftWindow->consumeMotionEvent(
3152 AllOf(WithMotionAction(AMOTION_EVENT_ACTION_DOWN), WithDeviceId(touchDeviceId)));
3153 leftWindow->consumeMotionEvent(
3154 AllOf(WithMotionAction(AMOTION_EVENT_ACTION_UP), WithDeviceId(touchDeviceId)));
3155
3156 // First finger down on right window
3157 mDispatcher->notifyMotion(
3158 MotionArgsBuilder(AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
3159 .deviceId(touchDeviceId)
3160 .pointer(PointerBuilder(0, ToolType::FINGER).x(300).y(100))
3161 .build());
3162 rightWindow->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_DOWN));
3163
3164 // Second finger down on the left window
3165 mDispatcher->notifyMotion(MotionArgsBuilder(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
3166 .deviceId(touchDeviceId)
3167 .pointer(PointerBuilder(0, ToolType::FINGER).x(300).y(100))
3168 .pointer(PointerBuilder(1, ToolType::FINGER).x(100).y(100))
3169 .build());
3170 leftWindow->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_DOWN));
3171 rightWindow->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_MOVE));
3172
3173 // No more events
3174 leftWindow->assertNoEvents();
3175 rightWindow->assertNoEvents();
3176}
3177
3178/**
Siarhei Vishniakou2e3e4432023-02-09 18:34:11 -08003179 * Start hovering with a stylus device, and then tap with a touch device. Ensure no crash occurs.
3180 * While the touch is down, new hover events from the stylus device should be ignored. After the
3181 * touch is gone, stylus hovering should start working again.
3182 */
Siarhei Vishniakou3ad54f52023-11-02 16:54:40 -07003183TEST_F(InputDispatcherMultiDeviceTest, StylusHoverIgnoresTouchTap) {
Siarhei Vishniakoued89cbb2023-10-13 10:42:44 -07003184 SCOPED_FLAG_OVERRIDE(enable_multi_device_same_window_stream, false);
Siarhei Vishniakou2e3e4432023-02-09 18:34:11 -08003185 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
3186 sp<FakeWindowHandle> window =
3187 sp<FakeWindowHandle>::make(application, mDispatcher, "Window", ADISPLAY_ID_DEFAULT);
3188 window->setFrame(Rect(0, 0, 200, 200));
3189
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07003190 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Siarhei Vishniakou2e3e4432023-02-09 18:34:11 -08003191
3192 const int32_t stylusDeviceId = 5;
3193 const int32_t touchDeviceId = 4;
3194 // Start hovering with stylus
3195 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07003196 injectMotionEvent(*mDispatcher,
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -07003197 MotionEventBuilder(ACTION_HOVER_ENTER, AINPUT_SOURCE_STYLUS)
Siarhei Vishniakou2e3e4432023-02-09 18:34:11 -08003198 .deviceId(stylusDeviceId)
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07003199 .pointer(PointerBuilder(0, ToolType::STYLUS).x(50).y(50))
Siarhei Vishniakou2e3e4432023-02-09 18:34:11 -08003200 .build()));
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -07003201 window->consumeMotionEvent(WithMotionAction(ACTION_HOVER_ENTER));
Siarhei Vishniakou2e3e4432023-02-09 18:34:11 -08003202
3203 // Finger down on the window
3204 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07003205 injectMotionEvent(*mDispatcher,
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -07003206 MotionEventBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
Siarhei Vishniakou2e3e4432023-02-09 18:34:11 -08003207 .deviceId(touchDeviceId)
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07003208 .pointer(PointerBuilder(0, ToolType::FINGER).x(100).y(100))
Siarhei Vishniakou2e3e4432023-02-09 18:34:11 -08003209 .build()));
Siarhei Vishniakou3ad54f52023-11-02 16:54:40 -07003210 // The touch device should be ignored!
Siarhei Vishniakou2e3e4432023-02-09 18:34:11 -08003211
Siarhei Vishniakou2899c552023-07-10 18:20:46 -07003212 // Continue hovering with stylus.
3213 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07003214 injectMotionEvent(*mDispatcher,
Siarhei Vishniakou2e3e4432023-02-09 18:34:11 -08003215 MotionEventBuilder(AMOTION_EVENT_ACTION_HOVER_MOVE,
3216 AINPUT_SOURCE_STYLUS)
3217 .deviceId(stylusDeviceId)
Siarhei Vishniakou25537f82023-07-18 14:35:47 -07003218 .pointer(PointerBuilder(0, ToolType::STYLUS).x(60).y(60))
Siarhei Vishniakou2e3e4432023-02-09 18:34:11 -08003219 .build()));
Siarhei Vishniakou3ad54f52023-11-02 16:54:40 -07003220 // Hovers continue to work
3221 window->consumeMotionEvent(
3222 AllOf(WithMotionAction(ACTION_HOVER_MOVE), WithDeviceId(stylusDeviceId)));
Siarhei Vishniakou2e3e4432023-02-09 18:34:11 -08003223
3224 // Lift up the finger
3225 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07003226 injectMotionEvent(*mDispatcher,
Siarhei Vishniakou2e3e4432023-02-09 18:34:11 -08003227 MotionEventBuilder(AMOTION_EVENT_ACTION_UP,
3228 AINPUT_SOURCE_TOUCHSCREEN)
3229 .deviceId(touchDeviceId)
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07003230 .pointer(PointerBuilder(0, ToolType::FINGER).x(100).y(100))
Siarhei Vishniakou2e3e4432023-02-09 18:34:11 -08003231 .build()));
Siarhei Vishniakou2e3e4432023-02-09 18:34:11 -08003232
Siarhei Vishniakou2e3e4432023-02-09 18:34:11 -08003233 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07003234 injectMotionEvent(*mDispatcher,
Siarhei Vishniakou2e3e4432023-02-09 18:34:11 -08003235 MotionEventBuilder(AMOTION_EVENT_ACTION_HOVER_MOVE,
3236 AINPUT_SOURCE_STYLUS)
3237 .deviceId(stylusDeviceId)
Siarhei Vishniakou25537f82023-07-18 14:35:47 -07003238 .pointer(PointerBuilder(0, ToolType::STYLUS).x(70).y(70))
Siarhei Vishniakou2e3e4432023-02-09 18:34:11 -08003239 .build()));
Siarhei Vishniakou3ad54f52023-11-02 16:54:40 -07003240 window->consumeMotionEvent(
3241 AllOf(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_MOVE), WithDeviceId(stylusDeviceId)));
Siarhei Vishniakou2e3e4432023-02-09 18:34:11 -08003242 window->assertNoEvents();
3243}
3244
3245/**
Siarhei Vishniakoued89cbb2023-10-13 10:42:44 -07003246 * Start hovering with a stylus device, and then tap with a touch device. Ensure no crash occurs.
3247 * While the touch is down, hovering from the stylus is not affected. After the touch is gone,
3248 * check that the stylus hovering continues to work.
3249 */
3250TEST_F(InputDispatcherMultiDeviceTest, StylusHoverWithTouchTap) {
3251 SCOPED_FLAG_OVERRIDE(enable_multi_device_same_window_stream, true);
3252 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
3253 sp<FakeWindowHandle> window =
3254 sp<FakeWindowHandle>::make(application, mDispatcher, "Window", ADISPLAY_ID_DEFAULT);
3255 window->setFrame(Rect(0, 0, 200, 200));
3256
3257 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
3258
3259 const int32_t stylusDeviceId = 5;
3260 const int32_t touchDeviceId = 4;
3261 // Start hovering with stylus
3262 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_ENTER, AINPUT_SOURCE_STYLUS)
3263 .deviceId(stylusDeviceId)
3264 .pointer(PointerBuilder(0, ToolType::STYLUS).x(50).y(50))
3265 .build());
3266 window->consumeMotionEvent(WithMotionAction(ACTION_HOVER_ENTER));
3267
3268 // Finger down on the window
3269 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
3270 .deviceId(touchDeviceId)
3271 .pointer(PointerBuilder(0, ToolType::FINGER).x(100).y(100))
3272 .build());
3273 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(touchDeviceId)));
3274
3275 // Continue hovering with stylus.
3276 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_MOVE, AINPUT_SOURCE_STYLUS)
3277 .deviceId(stylusDeviceId)
3278 .pointer(PointerBuilder(0, ToolType::STYLUS).x(60).y(60))
3279 .build());
3280 // Hovers continue to work
3281 window->consumeMotionEvent(
3282 AllOf(WithMotionAction(ACTION_HOVER_MOVE), WithDeviceId(stylusDeviceId)));
3283
3284 // Lift up the finger
3285 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN)
3286 .deviceId(touchDeviceId)
3287 .pointer(PointerBuilder(0, ToolType::FINGER).x(100).y(100))
3288 .build());
3289 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_UP), WithDeviceId(touchDeviceId)));
3290
3291 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_MOVE, AINPUT_SOURCE_STYLUS)
3292 .deviceId(stylusDeviceId)
3293 .pointer(PointerBuilder(0, ToolType::STYLUS).x(70).y(70))
3294 .build());
3295 window->consumeMotionEvent(
3296 AllOf(WithMotionAction(ACTION_HOVER_MOVE), WithDeviceId(stylusDeviceId)));
3297 window->assertNoEvents();
3298}
3299
3300/**
Siarhei Vishniakouf77f60a2023-10-23 17:26:05 -07003301 * If stylus is down anywhere on the screen, then touches should not be delivered to windows that
3302 * have InputConfig::GLOBAL_STYLUS_BLOCKS_TOUCH.
3303 *
3304 * Two windows: one on the left and one on the right.
3305 * The window on the right has GLOBAL_STYLUS_BLOCKS_TOUCH config.
3306 * Stylus down on the left window, and then touch down on the right window.
3307 * Check that the right window doesn't get touches while the stylus is down on the left window.
3308 */
3309TEST_F(InputDispatcherMultiDeviceTest, GlobalStylusDownBlocksTouch) {
3310 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
3311 sp<FakeWindowHandle> leftWindow =
3312 sp<FakeWindowHandle>::make(application, mDispatcher, "Left window",
3313 ADISPLAY_ID_DEFAULT);
3314 leftWindow->setFrame(Rect(0, 0, 100, 100));
3315
3316 sp<FakeWindowHandle> sbtRightWindow =
3317 sp<FakeWindowHandle>::make(application, mDispatcher,
3318 "Stylus blocks touch (right) window", ADISPLAY_ID_DEFAULT);
3319 sbtRightWindow->setFrame(Rect(100, 100, 200, 200));
3320 sbtRightWindow->setGlobalStylusBlocksTouch(true);
3321
3322 mDispatcher->onWindowInfosChanged(
3323 {{*leftWindow->getInfo(), *sbtRightWindow->getInfo()}, {}, 0, 0});
3324
3325 const int32_t stylusDeviceId = 5;
3326 const int32_t touchDeviceId = 4;
3327
3328 // Stylus down in the left window
3329 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_STYLUS)
3330 .pointer(PointerBuilder(0, ToolType::STYLUS).x(50).y(52))
3331 .deviceId(stylusDeviceId)
3332 .build());
3333 leftWindow->consumeMotionEvent(
3334 AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(stylusDeviceId)));
3335
3336 // Finger tap on the right window
3337 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
3338 .pointer(PointerBuilder(0, ToolType::FINGER).x(150).y(151))
3339 .deviceId(touchDeviceId)
3340 .build());
3341 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN)
3342 .pointer(PointerBuilder(0, ToolType::FINGER).x(150).y(151))
3343 .deviceId(touchDeviceId)
3344 .build());
3345
3346 // The touch should be blocked, because stylus is down somewhere else on screen!
3347 sbtRightWindow->assertNoEvents();
3348
3349 // Continue stylus motion, and ensure it's not impacted.
3350 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_STYLUS)
3351 .pointer(PointerBuilder(0, ToolType::STYLUS).x(51).y(53))
3352 .deviceId(stylusDeviceId)
3353 .build());
3354 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_UP, AINPUT_SOURCE_STYLUS)
3355 .pointer(PointerBuilder(0, ToolType::STYLUS).x(51).y(53))
3356 .deviceId(stylusDeviceId)
3357 .build());
3358 leftWindow->consumeMotionEvent(
3359 AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(stylusDeviceId)));
3360 leftWindow->consumeMotionEvent(
3361 AllOf(WithMotionAction(ACTION_UP), WithDeviceId(stylusDeviceId)));
3362
3363 // Now that the stylus gesture is done, touches should be getting delivered correctly.
3364 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
3365 .pointer(PointerBuilder(0, ToolType::FINGER).x(151).y(153))
3366 .deviceId(touchDeviceId)
3367 .build());
3368 sbtRightWindow->consumeMotionEvent(
3369 AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(touchDeviceId)));
3370}
3371
3372/**
3373 * If stylus is hovering anywhere on the screen, then touches should not be delivered to windows
3374 * that have InputConfig::GLOBAL_STYLUS_BLOCKS_TOUCH.
3375 *
3376 * Two windows: one on the left and one on the right.
3377 * The window on the right has GLOBAL_STYLUS_BLOCKS_TOUCH config.
3378 * Stylus hover on the left window, and then touch down on the right window.
3379 * Check that the right window doesn't get touches while the stylus is hovering on the left window.
3380 */
3381TEST_F(InputDispatcherMultiDeviceTest, GlobalStylusHoverBlocksTouch) {
3382 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
3383 sp<FakeWindowHandle> leftWindow =
3384 sp<FakeWindowHandle>::make(application, mDispatcher, "Left window",
3385 ADISPLAY_ID_DEFAULT);
3386 leftWindow->setFrame(Rect(0, 0, 100, 100));
3387
3388 sp<FakeWindowHandle> sbtRightWindow =
3389 sp<FakeWindowHandle>::make(application, mDispatcher,
3390 "Stylus blocks touch (right) window", ADISPLAY_ID_DEFAULT);
3391 sbtRightWindow->setFrame(Rect(100, 100, 200, 200));
3392 sbtRightWindow->setGlobalStylusBlocksTouch(true);
3393
3394 mDispatcher->onWindowInfosChanged(
3395 {{*leftWindow->getInfo(), *sbtRightWindow->getInfo()}, {}, 0, 0});
3396
3397 const int32_t stylusDeviceId = 5;
3398 const int32_t touchDeviceId = 4;
3399
3400 // Stylus hover in the left window
3401 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_ENTER, AINPUT_SOURCE_STYLUS)
3402 .pointer(PointerBuilder(0, ToolType::STYLUS).x(50).y(52))
3403 .deviceId(stylusDeviceId)
3404 .build());
3405 leftWindow->consumeMotionEvent(
3406 AllOf(WithMotionAction(ACTION_HOVER_ENTER), WithDeviceId(stylusDeviceId)));
3407
3408 // Finger tap on the right window
3409 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
3410 .pointer(PointerBuilder(0, ToolType::FINGER).x(150).y(151))
3411 .deviceId(touchDeviceId)
3412 .build());
3413 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN)
3414 .pointer(PointerBuilder(0, ToolType::FINGER).x(150).y(151))
3415 .deviceId(touchDeviceId)
3416 .build());
3417
3418 // The touch should be blocked, because stylus is hovering somewhere else on screen!
3419 sbtRightWindow->assertNoEvents();
3420
3421 // Continue stylus motion, and ensure it's not impacted.
3422 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_MOVE, AINPUT_SOURCE_STYLUS)
3423 .pointer(PointerBuilder(0, ToolType::STYLUS).x(51).y(53))
3424 .deviceId(stylusDeviceId)
3425 .build());
3426 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_EXIT, AINPUT_SOURCE_STYLUS)
3427 .pointer(PointerBuilder(0, ToolType::STYLUS).x(51).y(53))
3428 .deviceId(stylusDeviceId)
3429 .build());
3430 leftWindow->consumeMotionEvent(
3431 AllOf(WithMotionAction(ACTION_HOVER_MOVE), WithDeviceId(stylusDeviceId)));
3432 leftWindow->consumeMotionEvent(
3433 AllOf(WithMotionAction(ACTION_HOVER_EXIT), WithDeviceId(stylusDeviceId)));
3434
3435 // Now that the stylus gesture is done, touches should be getting delivered correctly.
3436 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
3437 .pointer(PointerBuilder(0, ToolType::FINGER).x(151).y(153))
3438 .deviceId(touchDeviceId)
3439 .build());
3440 sbtRightWindow->consumeMotionEvent(
3441 AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(touchDeviceId)));
3442}
3443
3444/**
Siarhei Vishniakouf372b812023-02-14 18:06:51 -08003445 * A spy window above a window with no input channel.
3446 * Start hovering with a stylus device, and then tap with it.
3447 * Ensure spy window receives the entire sequence.
3448 */
3449TEST_F(InputDispatcherTest, StylusHoverAndDownNoInputChannel) {
3450 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
3451 sp<FakeWindowHandle> spyWindow =
3452 sp<FakeWindowHandle>::make(application, mDispatcher, "Spy", ADISPLAY_ID_DEFAULT);
3453 spyWindow->setFrame(Rect(0, 0, 200, 200));
3454 spyWindow->setTrustedOverlay(true);
3455 spyWindow->setSpy(true);
3456 sp<FakeWindowHandle> window =
3457 sp<FakeWindowHandle>::make(application, mDispatcher, "Window", ADISPLAY_ID_DEFAULT);
3458 window->setNoInputChannel(true);
3459 window->setFrame(Rect(0, 0, 200, 200));
3460
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07003461 mDispatcher->onWindowInfosChanged({{*spyWindow->getInfo(), *window->getInfo()}, {}, 0, 0});
Siarhei Vishniakouf372b812023-02-14 18:06:51 -08003462
Siarhei Vishniakouf372b812023-02-14 18:06:51 -08003463 // Start hovering with stylus
Prabir Pradhan678438e2023-04-13 19:32:51 +00003464 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_ENTER, AINPUT_SOURCE_STYLUS)
3465 .pointer(PointerBuilder(0, ToolType::STYLUS).x(50).y(50))
3466 .build());
Siarhei Vishniakouf372b812023-02-14 18:06:51 -08003467 spyWindow->consumeMotionEvent(WithMotionAction(ACTION_HOVER_ENTER));
3468 // Stop hovering
Prabir Pradhan678438e2023-04-13 19:32:51 +00003469 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_EXIT, AINPUT_SOURCE_STYLUS)
3470 .pointer(PointerBuilder(0, ToolType::STYLUS).x(50).y(50))
3471 .build());
Siarhei Vishniakouf372b812023-02-14 18:06:51 -08003472 spyWindow->consumeMotionEvent(WithMotionAction(ACTION_HOVER_EXIT));
3473
3474 // Stylus touches down
Prabir Pradhan678438e2023-04-13 19:32:51 +00003475 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_STYLUS)
3476 .pointer(PointerBuilder(0, ToolType::STYLUS).x(50).y(50))
3477 .build());
Siarhei Vishniakouf372b812023-02-14 18:06:51 -08003478 spyWindow->consumeMotionEvent(WithMotionAction(ACTION_DOWN));
3479
3480 // Stylus goes up
Prabir Pradhan678438e2023-04-13 19:32:51 +00003481 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_UP, AINPUT_SOURCE_STYLUS)
3482 .pointer(PointerBuilder(0, ToolType::STYLUS).x(50).y(50))
3483 .build());
Siarhei Vishniakouf372b812023-02-14 18:06:51 -08003484 spyWindow->consumeMotionEvent(WithMotionAction(ACTION_UP));
3485
3486 // Again hover
Prabir Pradhan678438e2023-04-13 19:32:51 +00003487 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_ENTER, AINPUT_SOURCE_STYLUS)
3488 .pointer(PointerBuilder(0, ToolType::STYLUS).x(50).y(50))
3489 .build());
Siarhei Vishniakouf372b812023-02-14 18:06:51 -08003490 spyWindow->consumeMotionEvent(WithMotionAction(ACTION_HOVER_ENTER));
3491 // Stop hovering
Prabir Pradhan678438e2023-04-13 19:32:51 +00003492 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_EXIT, AINPUT_SOURCE_STYLUS)
3493 .pointer(PointerBuilder(0, ToolType::STYLUS).x(50).y(50))
3494 .build());
Siarhei Vishniakouf372b812023-02-14 18:06:51 -08003495 spyWindow->consumeMotionEvent(WithMotionAction(ACTION_HOVER_EXIT));
3496
3497 // No more events
3498 spyWindow->assertNoEvents();
3499 window->assertNoEvents();
3500}
3501
3502/**
Siarhei Vishniakou6b71b632023-10-27 21:34:46 -07003503 * A stale stylus HOVER_EXIT event is injected. Since it's a stale event, it should generally be
3504 * rejected. But since we already have an ongoing gesture, this event should be processed.
3505 * This prevents inconsistent events being handled inside the dispatcher.
3506 */
3507TEST_F(InputDispatcherTest, StaleStylusHoverGestureIsComplete) {
3508 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
3509
3510 sp<FakeWindowHandle> window =
3511 sp<FakeWindowHandle>::make(application, mDispatcher, "Window", ADISPLAY_ID_DEFAULT);
3512 window->setFrame(Rect(0, 0, 200, 200));
3513
3514 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
3515
3516 // Start hovering with stylus
3517 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_ENTER, AINPUT_SOURCE_STYLUS)
3518 .pointer(PointerBuilder(0, ToolType::STYLUS).x(50).y(50))
3519 .build());
3520 window->consumeMotionEvent(WithMotionAction(ACTION_HOVER_ENTER));
3521
3522 NotifyMotionArgs hoverExit = MotionArgsBuilder(ACTION_HOVER_EXIT, AINPUT_SOURCE_STYLUS)
3523 .pointer(PointerBuilder(0, ToolType::STYLUS).x(50).y(50))
3524 .build();
3525 // Make this 'hoverExit' event stale
3526 mFakePolicy->setStaleEventTimeout(100ms);
3527 std::this_thread::sleep_for(100ms);
3528
3529 // It shouldn't be dropped by the dispatcher, even though it's stale.
3530 mDispatcher->notifyMotion(hoverExit);
3531 window->consumeMotionEvent(WithMotionAction(ACTION_HOVER_EXIT));
3532
3533 // Stylus starts hovering again! There should be no crash.
3534 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_ENTER, AINPUT_SOURCE_STYLUS)
3535 .pointer(PointerBuilder(0, ToolType::STYLUS).x(51).y(51))
3536 .build());
3537 window->consumeMotionEvent(WithMotionAction(ACTION_HOVER_ENTER));
3538}
3539
3540/**
Siarhei Vishniakouf372b812023-02-14 18:06:51 -08003541 * Start hovering with a mouse, and then tap with a touch device. Pilfer the touch stream.
3542 * Next, click with the mouse device. Both windows (spy and regular) should receive the new mouse
3543 * ACTION_DOWN event because that's a new gesture, and pilfering should no longer be active.
3544 * While the mouse is down, new move events from the touch device should be ignored.
3545 */
Siarhei Vishniakoued89cbb2023-10-13 10:42:44 -07003546TEST_F(InputDispatcherTest, TouchPilferAndMouseMove_legacy) {
3547 SCOPED_FLAG_OVERRIDE(enable_multi_device_same_window_stream, false);
Siarhei Vishniakouf372b812023-02-14 18:06:51 -08003548 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
3549 sp<FakeWindowHandle> spyWindow =
3550 sp<FakeWindowHandle>::make(application, mDispatcher, "Spy", ADISPLAY_ID_DEFAULT);
3551 spyWindow->setFrame(Rect(0, 0, 200, 200));
3552 spyWindow->setTrustedOverlay(true);
3553 spyWindow->setSpy(true);
3554 sp<FakeWindowHandle> window =
3555 sp<FakeWindowHandle>::make(application, mDispatcher, "Window", ADISPLAY_ID_DEFAULT);
3556 window->setFrame(Rect(0, 0, 200, 200));
3557
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07003558 mDispatcher->onWindowInfosChanged({{*spyWindow->getInfo(), *window->getInfo()}, {}, 0, 0});
Siarhei Vishniakouf372b812023-02-14 18:06:51 -08003559
3560 const int32_t mouseDeviceId = 7;
3561 const int32_t touchDeviceId = 4;
Siarhei Vishniakouf372b812023-02-14 18:06:51 -08003562
3563 // Hover a bit with mouse first
Prabir Pradhan678438e2023-04-13 19:32:51 +00003564 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_ENTER, AINPUT_SOURCE_MOUSE)
3565 .deviceId(mouseDeviceId)
3566 .pointer(PointerBuilder(0, ToolType::MOUSE).x(100).y(100))
3567 .build());
Siarhei Vishniakouf372b812023-02-14 18:06:51 -08003568 spyWindow->consumeMotionEvent(
3569 AllOf(WithMotionAction(ACTION_HOVER_ENTER), WithDeviceId(mouseDeviceId)));
3570 window->consumeMotionEvent(
3571 AllOf(WithMotionAction(ACTION_HOVER_ENTER), WithDeviceId(mouseDeviceId)));
3572
3573 // Start touching
Prabir Pradhan678438e2023-04-13 19:32:51 +00003574 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
3575 .deviceId(touchDeviceId)
3576 .pointer(PointerBuilder(0, ToolType::FINGER).x(50).y(50))
3577 .build());
Siarhei Vishniakouf372b812023-02-14 18:06:51 -08003578 spyWindow->consumeMotionEvent(WithMotionAction(ACTION_HOVER_EXIT));
3579 window->consumeMotionEvent(WithMotionAction(ACTION_HOVER_EXIT));
3580 spyWindow->consumeMotionEvent(WithMotionAction(ACTION_DOWN));
3581 window->consumeMotionEvent(WithMotionAction(ACTION_DOWN));
3582
Prabir Pradhan678438e2023-04-13 19:32:51 +00003583 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN)
3584 .deviceId(touchDeviceId)
3585 .pointer(PointerBuilder(0, ToolType::FINGER).x(55).y(55))
3586 .build());
Siarhei Vishniakouf372b812023-02-14 18:06:51 -08003587 spyWindow->consumeMotionEvent(WithMotionAction(ACTION_MOVE));
3588 window->consumeMotionEvent(WithMotionAction(ACTION_MOVE));
3589
3590 // Pilfer the stream
3591 EXPECT_EQ(OK, mDispatcher->pilferPointers(spyWindow->getToken()));
3592 window->consumeMotionEvent(WithMotionAction(ACTION_CANCEL));
3593
Prabir Pradhan678438e2023-04-13 19:32:51 +00003594 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN)
3595 .deviceId(touchDeviceId)
3596 .pointer(PointerBuilder(0, ToolType::FINGER).x(60).y(60))
3597 .build());
Siarhei Vishniakouf372b812023-02-14 18:06:51 -08003598 spyWindow->consumeMotionEvent(WithMotionAction(ACTION_MOVE));
3599
3600 // Mouse down
Prabir Pradhan678438e2023-04-13 19:32:51 +00003601 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_MOUSE)
3602 .deviceId(mouseDeviceId)
3603 .buttonState(AMOTION_EVENT_BUTTON_PRIMARY)
3604 .pointer(PointerBuilder(0, ToolType::MOUSE).x(100).y(100))
3605 .build());
Siarhei Vishniakouf372b812023-02-14 18:06:51 -08003606
3607 spyWindow->consumeMotionEvent(
3608 AllOf(WithMotionAction(ACTION_CANCEL), WithDeviceId(touchDeviceId)));
3609 spyWindow->consumeMotionEvent(
3610 AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(mouseDeviceId)));
3611 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(mouseDeviceId)));
3612
Prabir Pradhan678438e2023-04-13 19:32:51 +00003613 mDispatcher->notifyMotion(
3614 MotionArgsBuilder(AMOTION_EVENT_ACTION_BUTTON_PRESS, AINPUT_SOURCE_MOUSE)
3615 .deviceId(mouseDeviceId)
3616 .buttonState(AMOTION_EVENT_BUTTON_PRIMARY)
3617 .actionButton(AMOTION_EVENT_BUTTON_PRIMARY)
3618 .pointer(PointerBuilder(0, ToolType::MOUSE).x(100).y(100))
3619 .build());
Siarhei Vishniakouf372b812023-02-14 18:06:51 -08003620 spyWindow->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_BUTTON_PRESS));
3621 window->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_BUTTON_PRESS));
3622
3623 // Mouse move!
Prabir Pradhan678438e2023-04-13 19:32:51 +00003624 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_MOUSE)
3625 .deviceId(mouseDeviceId)
3626 .buttonState(AMOTION_EVENT_BUTTON_PRIMARY)
3627 .pointer(PointerBuilder(0, ToolType::MOUSE).x(110).y(110))
3628 .build());
Siarhei Vishniakouf372b812023-02-14 18:06:51 -08003629 spyWindow->consumeMotionEvent(WithMotionAction(ACTION_MOVE));
3630 window->consumeMotionEvent(WithMotionAction(ACTION_MOVE));
3631
3632 // Touch move!
Prabir Pradhan678438e2023-04-13 19:32:51 +00003633 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN)
3634 .deviceId(touchDeviceId)
3635 .pointer(PointerBuilder(0, ToolType::FINGER).x(65).y(65))
3636 .build());
Siarhei Vishniakouf372b812023-02-14 18:06:51 -08003637
3638 // No more events
3639 spyWindow->assertNoEvents();
3640 window->assertNoEvents();
3641}
3642
3643/**
Siarhei Vishniakoued89cbb2023-10-13 10:42:44 -07003644 * Start hovering with a mouse, and then tap with a touch device. Pilfer the touch stream.
3645 * Next, click with the mouse device. Both windows (spy and regular) should receive the new mouse
3646 * ACTION_DOWN event because that's a new gesture, and pilfering should no longer be active.
3647 * While the mouse is down, new move events from the touch device should continue to work.
3648 */
3649TEST_F(InputDispatcherTest, TouchPilferAndMouseMove) {
3650 SCOPED_FLAG_OVERRIDE(enable_multi_device_same_window_stream, true);
3651 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
3652 sp<FakeWindowHandle> spyWindow =
3653 sp<FakeWindowHandle>::make(application, mDispatcher, "Spy", ADISPLAY_ID_DEFAULT);
3654 spyWindow->setFrame(Rect(0, 0, 200, 200));
3655 spyWindow->setTrustedOverlay(true);
3656 spyWindow->setSpy(true);
3657 sp<FakeWindowHandle> window =
3658 sp<FakeWindowHandle>::make(application, mDispatcher, "Window", ADISPLAY_ID_DEFAULT);
3659 window->setFrame(Rect(0, 0, 200, 200));
3660
3661 mDispatcher->onWindowInfosChanged({{*spyWindow->getInfo(), *window->getInfo()}, {}, 0, 0});
3662
3663 const int32_t mouseDeviceId = 7;
3664 const int32_t touchDeviceId = 4;
3665
3666 // Hover a bit with mouse first
3667 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_ENTER, AINPUT_SOURCE_MOUSE)
3668 .deviceId(mouseDeviceId)
3669 .pointer(PointerBuilder(0, ToolType::MOUSE).x(100).y(100))
3670 .build());
3671 spyWindow->consumeMotionEvent(
3672 AllOf(WithMotionAction(ACTION_HOVER_ENTER), WithDeviceId(mouseDeviceId)));
3673 window->consumeMotionEvent(
3674 AllOf(WithMotionAction(ACTION_HOVER_ENTER), WithDeviceId(mouseDeviceId)));
3675
3676 // Start touching
3677 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
3678 .deviceId(touchDeviceId)
3679 .pointer(PointerBuilder(0, ToolType::FINGER).x(50).y(50))
3680 .build());
3681
3682 spyWindow->consumeMotionEvent(WithMotionAction(ACTION_DOWN));
3683 window->consumeMotionEvent(WithMotionAction(ACTION_DOWN));
3684
3685 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN)
3686 .deviceId(touchDeviceId)
3687 .pointer(PointerBuilder(0, ToolType::FINGER).x(55).y(55))
3688 .build());
3689 spyWindow->consumeMotionEvent(WithMotionAction(ACTION_MOVE));
3690 window->consumeMotionEvent(WithMotionAction(ACTION_MOVE));
3691
3692 // Pilfer the stream
3693 EXPECT_EQ(OK, mDispatcher->pilferPointers(spyWindow->getToken()));
3694 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_CANCEL), WithDeviceId(touchDeviceId)));
3695 // Hover is not pilfered! Only touch.
3696
3697 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN)
3698 .deviceId(touchDeviceId)
3699 .pointer(PointerBuilder(0, ToolType::FINGER).x(60).y(60))
3700 .build());
3701 spyWindow->consumeMotionEvent(WithMotionAction(ACTION_MOVE));
3702
3703 // Mouse down
3704 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_MOUSE)
3705 .deviceId(mouseDeviceId)
3706 .buttonState(AMOTION_EVENT_BUTTON_PRIMARY)
3707 .pointer(PointerBuilder(0, ToolType::MOUSE).x(100).y(100))
3708 .build());
3709
3710 spyWindow->consumeMotionEvent(
3711 AllOf(WithMotionAction(ACTION_HOVER_EXIT), WithDeviceId(mouseDeviceId)));
3712 spyWindow->consumeMotionEvent(
3713 AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(mouseDeviceId)));
3714 window->consumeMotionEvent(
3715 AllOf(WithMotionAction(ACTION_HOVER_EXIT), WithDeviceId(mouseDeviceId)));
3716 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(mouseDeviceId)));
3717
3718 mDispatcher->notifyMotion(
3719 MotionArgsBuilder(AMOTION_EVENT_ACTION_BUTTON_PRESS, AINPUT_SOURCE_MOUSE)
3720 .deviceId(mouseDeviceId)
3721 .buttonState(AMOTION_EVENT_BUTTON_PRIMARY)
3722 .actionButton(AMOTION_EVENT_BUTTON_PRIMARY)
3723 .pointer(PointerBuilder(0, ToolType::MOUSE).x(100).y(100))
3724 .build());
3725 spyWindow->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_BUTTON_PRESS));
3726 window->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_BUTTON_PRESS));
3727
3728 // Mouse move!
3729 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_MOUSE)
3730 .deviceId(mouseDeviceId)
3731 .buttonState(AMOTION_EVENT_BUTTON_PRIMARY)
3732 .pointer(PointerBuilder(0, ToolType::MOUSE).x(110).y(110))
3733 .build());
3734 spyWindow->consumeMotionEvent(
3735 AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(mouseDeviceId)));
3736 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(mouseDeviceId)));
3737
3738 // Touch move!
3739 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN)
3740 .deviceId(touchDeviceId)
3741 .pointer(PointerBuilder(0, ToolType::FINGER).x(65).y(65))
3742 .build());
3743 spyWindow->consumeMotionEvent(
3744 AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(touchDeviceId)));
3745
3746 // No more events
3747 spyWindow->assertNoEvents();
3748 window->assertNoEvents();
3749}
3750
3751/**
Siarhei Vishniakoua16e3a22022-03-02 15:26:40 -08003752 * On the display, have a single window, and also an area where there's no window.
3753 * First pointer touches the "no window" area of the screen. Second pointer touches the window.
3754 * Make sure that the window receives the second pointer, and first pointer is simply ignored.
3755 */
3756TEST_F(InputDispatcherTest, SplitWorksWhenEmptyAreaIsTouched) {
3757 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
3758 sp<FakeWindowHandle> window =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07003759 sp<FakeWindowHandle>::make(application, mDispatcher, "Window", DISPLAY_ID);
Siarhei Vishniakoua16e3a22022-03-02 15:26:40 -08003760
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07003761 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Siarhei Vishniakoua16e3a22022-03-02 15:26:40 -08003762
3763 // Touch down on the empty space
Prabir Pradhan678438e2023-04-13 19:32:51 +00003764 mDispatcher->notifyMotion(generateTouchArgs(AMOTION_EVENT_ACTION_DOWN, {{-1, -1}}));
Siarhei Vishniakoua16e3a22022-03-02 15:26:40 -08003765
3766 mDispatcher->waitForIdle();
3767 window->assertNoEvents();
3768
3769 // Now touch down on the window with another pointer
Prabir Pradhan678438e2023-04-13 19:32:51 +00003770 mDispatcher->notifyMotion(generateTouchArgs(POINTER_1_DOWN, {{-1, -1}, {10, 10}}));
Siarhei Vishniakoua16e3a22022-03-02 15:26:40 -08003771 mDispatcher->waitForIdle();
3772 window->consumeMotionDown();
3773}
3774
3775/**
3776 * Same test as above, but instead of touching the empty space, the first touch goes to
3777 * non-touchable window.
3778 */
3779TEST_F(InputDispatcherTest, SplitWorksWhenNonTouchableWindowIsTouched) {
3780 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
3781 sp<FakeWindowHandle> window1 =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07003782 sp<FakeWindowHandle>::make(application, mDispatcher, "Window1", DISPLAY_ID);
Siarhei Vishniakoua16e3a22022-03-02 15:26:40 -08003783 window1->setTouchableRegion(Region{{0, 0, 100, 100}});
3784 window1->setTouchable(false);
3785 sp<FakeWindowHandle> window2 =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07003786 sp<FakeWindowHandle>::make(application, mDispatcher, "Window2", DISPLAY_ID);
Siarhei Vishniakoua16e3a22022-03-02 15:26:40 -08003787 window2->setTouchableRegion(Region{{100, 0, 200, 100}});
3788
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07003789 mDispatcher->onWindowInfosChanged({{*window1->getInfo(), *window2->getInfo()}, {}, 0, 0});
Siarhei Vishniakoua16e3a22022-03-02 15:26:40 -08003790
Siarhei Vishniakoua16e3a22022-03-02 15:26:40 -08003791 // Touch down on the non-touchable window
Prabir Pradhan678438e2023-04-13 19:32:51 +00003792 mDispatcher->notifyMotion(generateTouchArgs(AMOTION_EVENT_ACTION_DOWN, {{50, 50}}));
Siarhei Vishniakoua16e3a22022-03-02 15:26:40 -08003793
3794 mDispatcher->waitForIdle();
3795 window1->assertNoEvents();
3796 window2->assertNoEvents();
3797
3798 // Now touch down on the window with another pointer
Prabir Pradhan678438e2023-04-13 19:32:51 +00003799 mDispatcher->notifyMotion(generateTouchArgs(POINTER_1_DOWN, {{50, 50}, {150, 50}}));
Siarhei Vishniakoua16e3a22022-03-02 15:26:40 -08003800 mDispatcher->waitForIdle();
3801 window2->consumeMotionDown();
3802}
3803
Vaibhav Devmurari882bd9b2022-06-23 14:54:54 +00003804/**
3805 * When splitting touch events the downTime should be adjusted such that the downTime corresponds
3806 * to the event time of the first ACTION_DOWN sent to the particular window.
3807 */
3808TEST_F(InputDispatcherTest, SplitTouchesSendCorrectActionDownTime) {
3809 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
3810 sp<FakeWindowHandle> window1 =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07003811 sp<FakeWindowHandle>::make(application, mDispatcher, "Window1", DISPLAY_ID);
Vaibhav Devmurari882bd9b2022-06-23 14:54:54 +00003812 window1->setTouchableRegion(Region{{0, 0, 100, 100}});
3813 sp<FakeWindowHandle> window2 =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07003814 sp<FakeWindowHandle>::make(application, mDispatcher, "Window2", DISPLAY_ID);
Vaibhav Devmurari882bd9b2022-06-23 14:54:54 +00003815 window2->setTouchableRegion(Region{{100, 0, 200, 100}});
3816
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07003817 mDispatcher->onWindowInfosChanged({{*window1->getInfo(), *window2->getInfo()}, {}, 0, 0});
Vaibhav Devmurari882bd9b2022-06-23 14:54:54 +00003818
Vaibhav Devmurari882bd9b2022-06-23 14:54:54 +00003819 // Touch down on the first window
Prabir Pradhan678438e2023-04-13 19:32:51 +00003820 mDispatcher->notifyMotion(generateTouchArgs(AMOTION_EVENT_ACTION_DOWN, {{50, 50}}));
Vaibhav Devmurari882bd9b2022-06-23 14:54:54 +00003821 mDispatcher->waitForIdle();
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07003822
Prabir Pradhan9d5f9ce2024-01-24 00:03:41 +00003823 const std::unique_ptr<MotionEvent> firstDown =
3824 window1->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN)));
3825 ASSERT_EQ(firstDown->getDownTime(), firstDown->getEventTime());
Vaibhav Devmurari882bd9b2022-06-23 14:54:54 +00003826 window2->assertNoEvents();
Vaibhav Devmurari882bd9b2022-06-23 14:54:54 +00003827
3828 // Now touch down on the window with another pointer
Prabir Pradhan678438e2023-04-13 19:32:51 +00003829 mDispatcher->notifyMotion(generateTouchArgs(POINTER_1_DOWN, {{50, 50}, {150, 50}}));
Vaibhav Devmurari882bd9b2022-06-23 14:54:54 +00003830 mDispatcher->waitForIdle();
Prabir Pradhan9d5f9ce2024-01-24 00:03:41 +00003831
3832 const std::unique_ptr<MotionEvent> secondDown =
3833 window2->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN)));
3834 ASSERT_EQ(secondDown->getDownTime(), secondDown->getEventTime());
3835 ASSERT_NE(firstDown->getDownTime(), secondDown->getDownTime());
3836 // We currently send MOVE events to all windows receiving a split touch when there is any change
3837 // in the touch state, even when none of the pointers in the split window actually moved.
3838 // Document this behavior in the test.
3839 window1->consumeMotionMove();
Vaibhav Devmurari882bd9b2022-06-23 14:54:54 +00003840
3841 // Now move the pointer on the second window
Prabir Pradhan678438e2023-04-13 19:32:51 +00003842 mDispatcher->notifyMotion(generateTouchArgs(AMOTION_EVENT_ACTION_MOVE, {{50, 50}, {151, 51}}));
Vaibhav Devmurari882bd9b2022-06-23 14:54:54 +00003843 mDispatcher->waitForIdle();
Prabir Pradhan9d5f9ce2024-01-24 00:03:41 +00003844
3845 window2->consumeMotionEvent(WithDownTime(secondDown->getDownTime()));
3846 window1->consumeMotionEvent(WithDownTime(firstDown->getDownTime()));
Vaibhav Devmurari882bd9b2022-06-23 14:54:54 +00003847
3848 // Now add new touch down on the second window
Prabir Pradhan678438e2023-04-13 19:32:51 +00003849 mDispatcher->notifyMotion(generateTouchArgs(POINTER_2_DOWN, {{50, 50}, {151, 51}, {150, 50}}));
Vaibhav Devmurari882bd9b2022-06-23 14:54:54 +00003850 mDispatcher->waitForIdle();
Vaibhav Devmurari882bd9b2022-06-23 14:54:54 +00003851
Prabir Pradhan9d5f9ce2024-01-24 00:03:41 +00003852 window2->consumeMotionEvent(
3853 AllOf(WithMotionAction(POINTER_1_DOWN), WithDownTime(secondDown->getDownTime())));
3854 window1->consumeMotionEvent(WithDownTime(firstDown->getDownTime()));
Vaibhav Devmurari882bd9b2022-06-23 14:54:54 +00003855
3856 // Now move the pointer on the first window
Prabir Pradhan678438e2023-04-13 19:32:51 +00003857 mDispatcher->notifyMotion(
3858 generateTouchArgs(AMOTION_EVENT_ACTION_MOVE, {{51, 51}, {151, 51}, {150, 50}}));
Vaibhav Devmurari882bd9b2022-06-23 14:54:54 +00003859 mDispatcher->waitForIdle();
Vaibhav Devmurari882bd9b2022-06-23 14:54:54 +00003860
Prabir Pradhan9d5f9ce2024-01-24 00:03:41 +00003861 window1->consumeMotionEvent(WithDownTime(firstDown->getDownTime()));
3862 window2->consumeMotionEvent(WithDownTime(secondDown->getDownTime()));
3863
3864 // Now add new touch down on the first window
Prabir Pradhan678438e2023-04-13 19:32:51 +00003865 mDispatcher->notifyMotion(
3866 generateTouchArgs(POINTER_3_DOWN, {{51, 51}, {151, 51}, {150, 50}, {50, 50}}));
Vaibhav Devmurari882bd9b2022-06-23 14:54:54 +00003867 mDispatcher->waitForIdle();
Prabir Pradhan9d5f9ce2024-01-24 00:03:41 +00003868
3869 window1->consumeMotionEvent(
3870 AllOf(WithMotionAction(POINTER_1_DOWN), WithDownTime(firstDown->getDownTime())));
3871 window2->consumeMotionEvent(WithDownTime(secondDown->getDownTime()));
Vaibhav Devmurari882bd9b2022-06-23 14:54:54 +00003872}
3873
Garfield Tandf26e862020-07-01 20:18:19 -07003874TEST_F(InputDispatcherTest, HoverMoveEnterMouseClickAndHoverMoveExit) {
Chris Yea209fde2020-07-22 13:54:51 -07003875 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
Garfield Tandf26e862020-07-01 20:18:19 -07003876 sp<FakeWindowHandle> windowLeft =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07003877 sp<FakeWindowHandle>::make(application, mDispatcher, "Left", ADISPLAY_ID_DEFAULT);
Garfield Tandf26e862020-07-01 20:18:19 -07003878 windowLeft->setFrame(Rect(0, 0, 600, 800));
Garfield Tandf26e862020-07-01 20:18:19 -07003879 sp<FakeWindowHandle> windowRight =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07003880 sp<FakeWindowHandle>::make(application, mDispatcher, "Right", ADISPLAY_ID_DEFAULT);
Garfield Tandf26e862020-07-01 20:18:19 -07003881 windowRight->setFrame(Rect(600, 0, 1200, 800));
Garfield Tandf26e862020-07-01 20:18:19 -07003882
3883 mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application);
3884
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07003885 mDispatcher->onWindowInfosChanged(
3886 {{*windowLeft->getInfo(), *windowRight->getInfo()}, {}, 0, 0});
Garfield Tandf26e862020-07-01 20:18:19 -07003887
3888 // Start cursor position in right window so that we can move the cursor to left window.
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08003889 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07003890 injectMotionEvent(*mDispatcher,
Garfield Tandf26e862020-07-01 20:18:19 -07003891 MotionEventBuilder(AMOTION_EVENT_ACTION_HOVER_MOVE,
3892 AINPUT_SOURCE_MOUSE)
Siarhei Vishniakou6d73f832022-07-21 17:27:03 -07003893 .pointer(PointerBuilder(0, ToolType::MOUSE).x(900).y(400))
Garfield Tandf26e862020-07-01 20:18:19 -07003894 .build()));
Siarhei Vishniakou5cee1e32022-11-29 12:35:39 -08003895 windowRight->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_ENTER));
Garfield Tandf26e862020-07-01 20:18:19 -07003896
3897 // Move cursor into left window
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08003898 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07003899 injectMotionEvent(*mDispatcher,
Garfield Tandf26e862020-07-01 20:18:19 -07003900 MotionEventBuilder(AMOTION_EVENT_ACTION_HOVER_MOVE,
3901 AINPUT_SOURCE_MOUSE)
Siarhei Vishniakou6d73f832022-07-21 17:27:03 -07003902 .pointer(PointerBuilder(0, ToolType::MOUSE).x(300).y(400))
Garfield Tandf26e862020-07-01 20:18:19 -07003903 .build()));
Siarhei Vishniakou5cee1e32022-11-29 12:35:39 -08003904 windowRight->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_EXIT));
3905 windowLeft->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_ENTER));
Garfield Tandf26e862020-07-01 20:18:19 -07003906
3907 // Inject a series of mouse events for a mouse click
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08003908 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07003909 injectMotionEvent(*mDispatcher,
Garfield Tandf26e862020-07-01 20:18:19 -07003910 MotionEventBuilder(AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_MOUSE)
3911 .buttonState(AMOTION_EVENT_BUTTON_PRIMARY)
Siarhei Vishniakou6d73f832022-07-21 17:27:03 -07003912 .pointer(PointerBuilder(0, ToolType::MOUSE).x(300).y(400))
Garfield Tandf26e862020-07-01 20:18:19 -07003913 .build()));
Siarhei Vishniakouf372b812023-02-14 18:06:51 -08003914 windowLeft->consumeMotionEvent(WithMotionAction(ACTION_HOVER_EXIT));
3915 windowLeft->consumeMotionEvent(WithMotionAction(ACTION_DOWN));
Garfield Tandf26e862020-07-01 20:18:19 -07003916
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08003917 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07003918 injectMotionEvent(*mDispatcher,
Garfield Tandf26e862020-07-01 20:18:19 -07003919 MotionEventBuilder(AMOTION_EVENT_ACTION_BUTTON_PRESS,
3920 AINPUT_SOURCE_MOUSE)
3921 .buttonState(AMOTION_EVENT_BUTTON_PRIMARY)
3922 .actionButton(AMOTION_EVENT_BUTTON_PRIMARY)
Siarhei Vishniakou6d73f832022-07-21 17:27:03 -07003923 .pointer(PointerBuilder(0, ToolType::MOUSE).x(300).y(400))
Garfield Tandf26e862020-07-01 20:18:19 -07003924 .build()));
Siarhei Vishniakou5cee1e32022-11-29 12:35:39 -08003925 windowLeft->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_BUTTON_PRESS));
Garfield Tandf26e862020-07-01 20:18:19 -07003926
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08003927 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07003928 injectMotionEvent(*mDispatcher,
Garfield Tandf26e862020-07-01 20:18:19 -07003929 MotionEventBuilder(AMOTION_EVENT_ACTION_BUTTON_RELEASE,
3930 AINPUT_SOURCE_MOUSE)
3931 .buttonState(0)
3932 .actionButton(AMOTION_EVENT_BUTTON_PRIMARY)
Siarhei Vishniakou6d73f832022-07-21 17:27:03 -07003933 .pointer(PointerBuilder(0, ToolType::MOUSE).x(300).y(400))
Garfield Tandf26e862020-07-01 20:18:19 -07003934 .build()));
Siarhei Vishniakou5cee1e32022-11-29 12:35:39 -08003935 windowLeft->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_BUTTON_RELEASE));
Garfield Tandf26e862020-07-01 20:18:19 -07003936
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08003937 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07003938 injectMotionEvent(*mDispatcher,
Garfield Tandf26e862020-07-01 20:18:19 -07003939 MotionEventBuilder(AMOTION_EVENT_ACTION_UP, AINPUT_SOURCE_MOUSE)
3940 .buttonState(0)
Siarhei Vishniakou6d73f832022-07-21 17:27:03 -07003941 .pointer(PointerBuilder(0, ToolType::MOUSE).x(300).y(400))
Garfield Tandf26e862020-07-01 20:18:19 -07003942 .build()));
3943 windowLeft->consumeMotionUp(ADISPLAY_ID_DEFAULT);
3944
3945 // Move mouse cursor back to right window
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08003946 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07003947 injectMotionEvent(*mDispatcher,
Garfield Tandf26e862020-07-01 20:18:19 -07003948 MotionEventBuilder(AMOTION_EVENT_ACTION_HOVER_MOVE,
3949 AINPUT_SOURCE_MOUSE)
Siarhei Vishniakou6d73f832022-07-21 17:27:03 -07003950 .pointer(PointerBuilder(0, ToolType::MOUSE).x(900).y(400))
Garfield Tandf26e862020-07-01 20:18:19 -07003951 .build()));
Siarhei Vishniakou5cee1e32022-11-29 12:35:39 -08003952 windowRight->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_ENTER));
Siarhei Vishniakou5cee1e32022-11-29 12:35:39 -08003953
3954 // No more events
3955 windowLeft->assertNoEvents();
3956 windowRight->assertNoEvents();
3957}
3958
Siarhei Vishniakouf372b812023-02-14 18:06:51 -08003959/**
3960 * Put two fingers down (and don't release them) and click the mouse button.
3961 * The clicking of mouse is a new ACTION_DOWN event. Since it's from a different device, the
3962 * currently active gesture should be canceled, and the new one should proceed.
3963 */
Siarhei Vishniakoued89cbb2023-10-13 10:42:44 -07003964TEST_F(InputDispatcherTest, TwoPointersDownMouseClick_legacy) {
3965 SCOPED_FLAG_OVERRIDE(enable_multi_device_same_window_stream, false);
Siarhei Vishniakouf372b812023-02-14 18:06:51 -08003966 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
3967 sp<FakeWindowHandle> window =
3968 sp<FakeWindowHandle>::make(application, mDispatcher, "Window", ADISPLAY_ID_DEFAULT);
3969 window->setFrame(Rect(0, 0, 600, 800));
3970
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07003971 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Siarhei Vishniakouf372b812023-02-14 18:06:51 -08003972
3973 const int32_t touchDeviceId = 4;
3974 const int32_t mouseDeviceId = 6;
Siarhei Vishniakouf372b812023-02-14 18:06:51 -08003975
3976 // Two pointers down
Prabir Pradhan678438e2023-04-13 19:32:51 +00003977 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
3978 .deviceId(touchDeviceId)
3979 .pointer(PointerBuilder(0, ToolType::FINGER).x(100).y(100))
3980 .build());
Siarhei Vishniakouf372b812023-02-14 18:06:51 -08003981
Prabir Pradhan678438e2023-04-13 19:32:51 +00003982 mDispatcher->notifyMotion(MotionArgsBuilder(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
3983 .deviceId(touchDeviceId)
3984 .pointer(PointerBuilder(0, ToolType::FINGER).x(100).y(100))
3985 .pointer(PointerBuilder(1, ToolType::FINGER).x(120).y(120))
3986 .build());
Siarhei Vishniakouf372b812023-02-14 18:06:51 -08003987 window->consumeMotionEvent(WithMotionAction(ACTION_DOWN));
3988 window->consumeMotionEvent(WithMotionAction(POINTER_1_DOWN));
3989
3990 // Inject a series of mouse events for a mouse click
Prabir Pradhan678438e2023-04-13 19:32:51 +00003991 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_MOUSE)
3992 .deviceId(mouseDeviceId)
3993 .buttonState(AMOTION_EVENT_BUTTON_PRIMARY)
3994 .pointer(PointerBuilder(0, ToolType::MOUSE).x(300).y(400))
3995 .build());
Siarhei Vishniakouf372b812023-02-14 18:06:51 -08003996 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_CANCEL), WithDeviceId(touchDeviceId),
3997 WithPointerCount(2u)));
3998 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(mouseDeviceId)));
3999
Prabir Pradhan678438e2023-04-13 19:32:51 +00004000 mDispatcher->notifyMotion(
4001 MotionArgsBuilder(AMOTION_EVENT_ACTION_BUTTON_PRESS, AINPUT_SOURCE_MOUSE)
4002 .deviceId(mouseDeviceId)
4003 .buttonState(AMOTION_EVENT_BUTTON_PRIMARY)
4004 .actionButton(AMOTION_EVENT_BUTTON_PRIMARY)
4005 .pointer(PointerBuilder(0, ToolType::MOUSE).x(300).y(400))
4006 .build());
Siarhei Vishniakouf372b812023-02-14 18:06:51 -08004007 window->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_BUTTON_PRESS));
4008
4009 // Try to send more touch events while the mouse is down. Since it's a continuation of an
4010 // already canceled gesture, it should be ignored.
Prabir Pradhan678438e2023-04-13 19:32:51 +00004011 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN)
4012 .deviceId(touchDeviceId)
4013 .pointer(PointerBuilder(0, ToolType::FINGER).x(101).y(101))
4014 .pointer(PointerBuilder(1, ToolType::FINGER).x(121).y(121))
4015 .build());
Siarhei Vishniakouf372b812023-02-14 18:06:51 -08004016 window->assertNoEvents();
4017}
4018
Siarhei Vishniakoued89cbb2023-10-13 10:42:44 -07004019/**
4020 * Put two fingers down (and don't release them) and click the mouse button.
4021 * The clicking of mouse is a new ACTION_DOWN event. Since it's from a different device, the
4022 * currently active gesture should not be canceled, and the new one should proceed in parallel.
4023 */
4024TEST_F(InputDispatcherTest, TwoPointersDownMouseClick) {
4025 SCOPED_FLAG_OVERRIDE(enable_multi_device_same_window_stream, true);
4026 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
4027 sp<FakeWindowHandle> window =
4028 sp<FakeWindowHandle>::make(application, mDispatcher, "Window", ADISPLAY_ID_DEFAULT);
4029 window->setFrame(Rect(0, 0, 600, 800));
4030
4031 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
4032
4033 const int32_t touchDeviceId = 4;
4034 const int32_t mouseDeviceId = 6;
4035
4036 // Two pointers down
4037 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
4038 .deviceId(touchDeviceId)
4039 .pointer(PointerBuilder(0, ToolType::FINGER).x(100).y(100))
4040 .build());
4041
4042 mDispatcher->notifyMotion(MotionArgsBuilder(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
4043 .deviceId(touchDeviceId)
4044 .pointer(PointerBuilder(0, ToolType::FINGER).x(100).y(100))
4045 .pointer(PointerBuilder(1, ToolType::FINGER).x(120).y(120))
4046 .build());
4047 window->consumeMotionEvent(WithMotionAction(ACTION_DOWN));
4048 window->consumeMotionEvent(WithMotionAction(POINTER_1_DOWN));
4049
4050 // Send a series of mouse events for a mouse click
4051 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_MOUSE)
4052 .deviceId(mouseDeviceId)
4053 .buttonState(AMOTION_EVENT_BUTTON_PRIMARY)
4054 .pointer(PointerBuilder(0, ToolType::MOUSE).x(300).y(400))
4055 .build());
4056 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(mouseDeviceId)));
4057
4058 mDispatcher->notifyMotion(
4059 MotionArgsBuilder(AMOTION_EVENT_ACTION_BUTTON_PRESS, AINPUT_SOURCE_MOUSE)
4060 .deviceId(mouseDeviceId)
4061 .buttonState(AMOTION_EVENT_BUTTON_PRIMARY)
4062 .actionButton(AMOTION_EVENT_BUTTON_PRIMARY)
4063 .pointer(PointerBuilder(0, ToolType::MOUSE).x(300).y(400))
4064 .build());
4065 window->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_BUTTON_PRESS));
4066
4067 // Try to send more touch events while the mouse is down. Since it's a continuation of an
4068 // already active gesture, it should be sent normally.
4069 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN)
4070 .deviceId(touchDeviceId)
4071 .pointer(PointerBuilder(0, ToolType::FINGER).x(101).y(101))
4072 .pointer(PointerBuilder(1, ToolType::FINGER).x(121).y(121))
4073 .build());
4074 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(touchDeviceId)));
4075 window->assertNoEvents();
4076}
4077
Siarhei Vishniakou5cee1e32022-11-29 12:35:39 -08004078TEST_F(InputDispatcherTest, HoverWithSpyWindows) {
4079 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
4080
4081 sp<FakeWindowHandle> spyWindow =
4082 sp<FakeWindowHandle>::make(application, mDispatcher, "Spy", ADISPLAY_ID_DEFAULT);
4083 spyWindow->setFrame(Rect(0, 0, 600, 800));
4084 spyWindow->setTrustedOverlay(true);
4085 spyWindow->setSpy(true);
4086 sp<FakeWindowHandle> window =
4087 sp<FakeWindowHandle>::make(application, mDispatcher, "Window", ADISPLAY_ID_DEFAULT);
4088 window->setFrame(Rect(0, 0, 600, 800));
4089
4090 mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07004091 mDispatcher->onWindowInfosChanged({{*spyWindow->getInfo(), *window->getInfo()}, {}, 0, 0});
Siarhei Vishniakou5cee1e32022-11-29 12:35:39 -08004092
4093 // Send mouse cursor to the window
4094 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07004095 injectMotionEvent(*mDispatcher,
Siarhei Vishniakou5cee1e32022-11-29 12:35:39 -08004096 MotionEventBuilder(AMOTION_EVENT_ACTION_HOVER_ENTER,
4097 AINPUT_SOURCE_MOUSE)
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07004098 .pointer(PointerBuilder(0, ToolType::MOUSE).x(100).y(100))
Siarhei Vishniakou5cee1e32022-11-29 12:35:39 -08004099 .build()));
4100
4101 window->consumeMotionEvent(AllOf(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_ENTER),
4102 WithSource(AINPUT_SOURCE_MOUSE)));
4103 spyWindow->consumeMotionEvent(AllOf(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_ENTER),
4104 WithSource(AINPUT_SOURCE_MOUSE)));
4105
4106 window->assertNoEvents();
4107 spyWindow->assertNoEvents();
Garfield Tandf26e862020-07-01 20:18:19 -07004108}
4109
Siarhei Vishniakoued89cbb2023-10-13 10:42:44 -07004110TEST_F(InputDispatcherTest, MouseAndTouchWithSpyWindows_legacy) {
4111 SCOPED_FLAG_OVERRIDE(enable_multi_device_same_window_stream, false);
Siarhei Vishniakou060f82b2023-01-27 06:39:14 -08004112 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
4113
4114 sp<FakeWindowHandle> spyWindow =
4115 sp<FakeWindowHandle>::make(application, mDispatcher, "Spy", ADISPLAY_ID_DEFAULT);
4116 spyWindow->setFrame(Rect(0, 0, 600, 800));
4117 spyWindow->setTrustedOverlay(true);
4118 spyWindow->setSpy(true);
4119 sp<FakeWindowHandle> window =
4120 sp<FakeWindowHandle>::make(application, mDispatcher, "Window", ADISPLAY_ID_DEFAULT);
4121 window->setFrame(Rect(0, 0, 600, 800));
4122
4123 mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07004124 mDispatcher->onWindowInfosChanged({{*spyWindow->getInfo(), *window->getInfo()}, {}, 0, 0});
Siarhei Vishniakou060f82b2023-01-27 06:39:14 -08004125
4126 // Send mouse cursor to the window
4127 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07004128 injectMotionEvent(*mDispatcher,
Siarhei Vishniakou060f82b2023-01-27 06:39:14 -08004129 MotionEventBuilder(AMOTION_EVENT_ACTION_HOVER_ENTER,
4130 AINPUT_SOURCE_MOUSE)
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07004131 .pointer(PointerBuilder(0, ToolType::MOUSE).x(100).y(100))
Siarhei Vishniakou060f82b2023-01-27 06:39:14 -08004132 .build()));
4133
4134 // Move mouse cursor
4135 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07004136 injectMotionEvent(*mDispatcher,
Siarhei Vishniakou060f82b2023-01-27 06:39:14 -08004137 MotionEventBuilder(AMOTION_EVENT_ACTION_HOVER_MOVE,
4138 AINPUT_SOURCE_MOUSE)
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07004139 .pointer(PointerBuilder(0, ToolType::MOUSE).x(110).y(110))
Siarhei Vishniakou060f82b2023-01-27 06:39:14 -08004140 .build()));
4141
4142 window->consumeMotionEvent(AllOf(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_ENTER),
4143 WithSource(AINPUT_SOURCE_MOUSE)));
4144 spyWindow->consumeMotionEvent(AllOf(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_ENTER),
4145 WithSource(AINPUT_SOURCE_MOUSE)));
4146 window->consumeMotionEvent(AllOf(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_MOVE),
4147 WithSource(AINPUT_SOURCE_MOUSE)));
4148 spyWindow->consumeMotionEvent(AllOf(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_MOVE),
4149 WithSource(AINPUT_SOURCE_MOUSE)));
4150 // Touch down on the window
4151 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07004152 injectMotionEvent(*mDispatcher,
Siarhei Vishniakou060f82b2023-01-27 06:39:14 -08004153 MotionEventBuilder(AMOTION_EVENT_ACTION_DOWN,
4154 AINPUT_SOURCE_TOUCHSCREEN)
4155 .deviceId(SECOND_DEVICE_ID)
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07004156 .pointer(PointerBuilder(0, ToolType::FINGER).x(200).y(200))
Siarhei Vishniakou060f82b2023-01-27 06:39:14 -08004157 .build()));
4158 window->consumeMotionEvent(AllOf(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_EXIT),
4159 WithSource(AINPUT_SOURCE_MOUSE)));
4160 spyWindow->consumeMotionEvent(AllOf(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_EXIT),
4161 WithSource(AINPUT_SOURCE_MOUSE)));
4162 window->consumeMotionEvent(AllOf(WithMotionAction(AMOTION_EVENT_ACTION_DOWN),
4163 WithSource(AINPUT_SOURCE_TOUCHSCREEN)));
4164 spyWindow->consumeMotionEvent(AllOf(WithMotionAction(AMOTION_EVENT_ACTION_DOWN),
4165 WithSource(AINPUT_SOURCE_TOUCHSCREEN)));
4166
4167 // pilfer the motion, retaining the gesture on the spy window.
4168 EXPECT_EQ(OK, mDispatcher->pilferPointers(spyWindow->getToken()));
4169 window->consumeMotionEvent(AllOf(WithMotionAction(AMOTION_EVENT_ACTION_CANCEL),
4170 WithSource(AINPUT_SOURCE_TOUCHSCREEN)));
4171
4172 // Touch UP on the window
4173 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07004174 injectMotionEvent(*mDispatcher,
Siarhei Vishniakou060f82b2023-01-27 06:39:14 -08004175 MotionEventBuilder(AMOTION_EVENT_ACTION_UP,
4176 AINPUT_SOURCE_TOUCHSCREEN)
4177 .deviceId(SECOND_DEVICE_ID)
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07004178 .pointer(PointerBuilder(0, ToolType::FINGER).x(200).y(200))
Siarhei Vishniakou060f82b2023-01-27 06:39:14 -08004179 .build()));
4180 spyWindow->consumeMotionEvent(AllOf(WithMotionAction(AMOTION_EVENT_ACTION_UP),
4181 WithSource(AINPUT_SOURCE_TOUCHSCREEN)));
4182
4183 // Previously, a touch was pilfered. However, that gesture was just finished. Now, we are going
4184 // to send a new gesture. It should again go to both windows (spy and the window below), just
4185 // like the first gesture did, before pilfering. The window configuration has not changed.
4186
4187 // One more tap - DOWN
4188 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07004189 injectMotionEvent(*mDispatcher,
Siarhei Vishniakou060f82b2023-01-27 06:39:14 -08004190 MotionEventBuilder(AMOTION_EVENT_ACTION_DOWN,
4191 AINPUT_SOURCE_TOUCHSCREEN)
4192 .deviceId(SECOND_DEVICE_ID)
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07004193 .pointer(PointerBuilder(0, ToolType::FINGER).x(250).y(250))
Siarhei Vishniakou060f82b2023-01-27 06:39:14 -08004194 .build()));
4195 window->consumeMotionEvent(AllOf(WithMotionAction(AMOTION_EVENT_ACTION_DOWN),
4196 WithSource(AINPUT_SOURCE_TOUCHSCREEN)));
4197 spyWindow->consumeMotionEvent(AllOf(WithMotionAction(AMOTION_EVENT_ACTION_DOWN),
4198 WithSource(AINPUT_SOURCE_TOUCHSCREEN)));
4199
4200 // Touch UP on the window
4201 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07004202 injectMotionEvent(*mDispatcher,
Siarhei Vishniakou060f82b2023-01-27 06:39:14 -08004203 MotionEventBuilder(AMOTION_EVENT_ACTION_UP,
4204 AINPUT_SOURCE_TOUCHSCREEN)
4205 .deviceId(SECOND_DEVICE_ID)
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07004206 .pointer(PointerBuilder(0, ToolType::FINGER).x(250).y(250))
Siarhei Vishniakou060f82b2023-01-27 06:39:14 -08004207 .build()));
4208 window->consumeMotionEvent(AllOf(WithMotionAction(AMOTION_EVENT_ACTION_UP),
4209 WithSource(AINPUT_SOURCE_TOUCHSCREEN)));
4210 spyWindow->consumeMotionEvent(AllOf(WithMotionAction(AMOTION_EVENT_ACTION_UP),
4211 WithSource(AINPUT_SOURCE_TOUCHSCREEN)));
4212
4213 window->assertNoEvents();
4214 spyWindow->assertNoEvents();
4215}
4216
Siarhei Vishniakoued89cbb2023-10-13 10:42:44 -07004217TEST_F(InputDispatcherTest, MouseAndTouchWithSpyWindows) {
4218 SCOPED_FLAG_OVERRIDE(enable_multi_device_same_window_stream, true);
4219 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
4220
4221 sp<FakeWindowHandle> spyWindow =
4222 sp<FakeWindowHandle>::make(application, mDispatcher, "Spy", ADISPLAY_ID_DEFAULT);
4223 spyWindow->setFrame(Rect(0, 0, 600, 800));
4224 spyWindow->setTrustedOverlay(true);
4225 spyWindow->setSpy(true);
4226 sp<FakeWindowHandle> window =
4227 sp<FakeWindowHandle>::make(application, mDispatcher, "Window", ADISPLAY_ID_DEFAULT);
4228 window->setFrame(Rect(0, 0, 600, 800));
4229
4230 mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application);
4231 mDispatcher->onWindowInfosChanged({{*spyWindow->getInfo(), *window->getInfo()}, {}, 0, 0});
4232
4233 // Send mouse cursor to the window
4234 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_ENTER, AINPUT_SOURCE_MOUSE)
4235 .pointer(PointerBuilder(0, ToolType::MOUSE).x(100).y(100))
4236 .build());
4237
4238 // Move mouse cursor
4239 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_MOVE, AINPUT_SOURCE_MOUSE)
4240 .pointer(PointerBuilder(0, ToolType::MOUSE).x(110).y(110))
4241 .build());
4242
4243 window->consumeMotionEvent(
4244 AllOf(WithMotionAction(ACTION_HOVER_ENTER), WithSource(AINPUT_SOURCE_MOUSE)));
4245 spyWindow->consumeMotionEvent(
4246 AllOf(WithMotionAction(ACTION_HOVER_ENTER), WithSource(AINPUT_SOURCE_MOUSE)));
4247 window->consumeMotionEvent(
4248 AllOf(WithMotionAction(ACTION_HOVER_MOVE), WithSource(AINPUT_SOURCE_MOUSE)));
4249 spyWindow->consumeMotionEvent(
4250 AllOf(WithMotionAction(ACTION_HOVER_MOVE), WithSource(AINPUT_SOURCE_MOUSE)));
4251 // Touch down on the window
4252 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
4253 .deviceId(SECOND_DEVICE_ID)
4254 .pointer(PointerBuilder(0, ToolType::FINGER).x(200).y(200))
4255 .build());
4256 window->consumeMotionEvent(
4257 AllOf(WithMotionAction(ACTION_DOWN), WithSource(AINPUT_SOURCE_TOUCHSCREEN)));
4258 spyWindow->consumeMotionEvent(
4259 AllOf(WithMotionAction(ACTION_DOWN), WithSource(AINPUT_SOURCE_TOUCHSCREEN)));
4260
4261 // pilfer the motion, retaining the gesture on the spy window.
4262 EXPECT_EQ(OK, mDispatcher->pilferPointers(spyWindow->getToken()));
4263 window->consumeMotionEvent(
4264 AllOf(WithMotionAction(ACTION_CANCEL), WithSource(AINPUT_SOURCE_TOUCHSCREEN)));
4265 // Mouse hover is not pilfered
4266
4267 // Touch UP on the window
4268 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN)
4269 .deviceId(SECOND_DEVICE_ID)
4270 .pointer(PointerBuilder(0, ToolType::FINGER).x(200).y(200))
4271 .build());
4272 spyWindow->consumeMotionEvent(
4273 AllOf(WithMotionAction(ACTION_UP), WithSource(AINPUT_SOURCE_TOUCHSCREEN)));
4274
4275 // Previously, a touch was pilfered. However, that gesture was just finished. Now, we are going
4276 // to send a new gesture. It should again go to both windows (spy and the window below), just
4277 // like the first gesture did, before pilfering. The window configuration has not changed.
4278
4279 // One more tap - DOWN
4280 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
4281 .deviceId(SECOND_DEVICE_ID)
4282 .pointer(PointerBuilder(0, ToolType::FINGER).x(250).y(250))
4283 .build());
4284 window->consumeMotionEvent(
4285 AllOf(WithMotionAction(ACTION_DOWN), WithSource(AINPUT_SOURCE_TOUCHSCREEN)));
4286 spyWindow->consumeMotionEvent(
4287 AllOf(WithMotionAction(ACTION_DOWN), WithSource(AINPUT_SOURCE_TOUCHSCREEN)));
4288
4289 // Touch UP on the window
4290 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN)
4291 .deviceId(SECOND_DEVICE_ID)
4292 .pointer(PointerBuilder(0, ToolType::FINGER).x(250).y(250))
4293 .build());
4294 window->consumeMotionEvent(
4295 AllOf(WithMotionAction(ACTION_UP), WithSource(AINPUT_SOURCE_TOUCHSCREEN)));
4296 spyWindow->consumeMotionEvent(
4297 AllOf(WithMotionAction(ACTION_UP), WithSource(AINPUT_SOURCE_TOUCHSCREEN)));
4298
4299 // Mouse movement continues normally as well
4300 // Move mouse cursor
4301 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_MOVE, AINPUT_SOURCE_MOUSE)
4302 .pointer(PointerBuilder(0, ToolType::MOUSE).x(120).y(130))
4303 .build());
4304 window->consumeMotionEvent(
4305 AllOf(WithMotionAction(ACTION_HOVER_MOVE), WithSource(AINPUT_SOURCE_MOUSE)));
4306 spyWindow->consumeMotionEvent(
4307 AllOf(WithMotionAction(ACTION_HOVER_MOVE), WithSource(AINPUT_SOURCE_MOUSE)));
4308
4309 window->assertNoEvents();
4310 spyWindow->assertNoEvents();
4311}
4312
Garfield Tandf26e862020-07-01 20:18:19 -07004313// This test is different from the test above that HOVER_ENTER and HOVER_EXIT events are injected
4314// directly in this test.
4315TEST_F(InputDispatcherTest, HoverEnterMouseClickAndHoverExit) {
Chris Yea209fde2020-07-22 13:54:51 -07004316 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
Garfield Tandf26e862020-07-01 20:18:19 -07004317 sp<FakeWindowHandle> window =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07004318 sp<FakeWindowHandle>::make(application, mDispatcher, "Window", ADISPLAY_ID_DEFAULT);
Garfield Tandf26e862020-07-01 20:18:19 -07004319 window->setFrame(Rect(0, 0, 1200, 800));
Garfield Tandf26e862020-07-01 20:18:19 -07004320
4321 mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application);
4322
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07004323 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Garfield Tandf26e862020-07-01 20:18:19 -07004324
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08004325 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07004326 injectMotionEvent(*mDispatcher,
Garfield Tandf26e862020-07-01 20:18:19 -07004327 MotionEventBuilder(AMOTION_EVENT_ACTION_HOVER_ENTER,
4328 AINPUT_SOURCE_MOUSE)
Siarhei Vishniakou6d73f832022-07-21 17:27:03 -07004329 .pointer(PointerBuilder(0, ToolType::MOUSE).x(300).y(400))
Garfield Tandf26e862020-07-01 20:18:19 -07004330 .build()));
Siarhei Vishniakou5cee1e32022-11-29 12:35:39 -08004331 window->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_ENTER));
Garfield Tandf26e862020-07-01 20:18:19 -07004332 // Inject a series of mouse events for a mouse click
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08004333 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07004334 injectMotionEvent(*mDispatcher,
Garfield Tandf26e862020-07-01 20:18:19 -07004335 MotionEventBuilder(AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_MOUSE)
4336 .buttonState(AMOTION_EVENT_BUTTON_PRIMARY)
Siarhei Vishniakou6d73f832022-07-21 17:27:03 -07004337 .pointer(PointerBuilder(0, ToolType::MOUSE).x(300).y(400))
Garfield Tandf26e862020-07-01 20:18:19 -07004338 .build()));
Siarhei Vishniakouf372b812023-02-14 18:06:51 -08004339 window->consumeMotionEvent(WithMotionAction(ACTION_HOVER_EXIT));
4340 window->consumeMotionEvent(WithMotionAction(ACTION_DOWN));
Garfield Tandf26e862020-07-01 20:18:19 -07004341
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08004342 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07004343 injectMotionEvent(*mDispatcher,
Garfield Tandf26e862020-07-01 20:18:19 -07004344 MotionEventBuilder(AMOTION_EVENT_ACTION_BUTTON_PRESS,
4345 AINPUT_SOURCE_MOUSE)
4346 .buttonState(AMOTION_EVENT_BUTTON_PRIMARY)
4347 .actionButton(AMOTION_EVENT_BUTTON_PRIMARY)
Siarhei Vishniakou6d73f832022-07-21 17:27:03 -07004348 .pointer(PointerBuilder(0, ToolType::MOUSE).x(300).y(400))
Garfield Tandf26e862020-07-01 20:18:19 -07004349 .build()));
Siarhei Vishniakou5cee1e32022-11-29 12:35:39 -08004350 window->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_BUTTON_PRESS));
Garfield Tandf26e862020-07-01 20:18:19 -07004351
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08004352 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07004353 injectMotionEvent(*mDispatcher,
Garfield Tandf26e862020-07-01 20:18:19 -07004354 MotionEventBuilder(AMOTION_EVENT_ACTION_BUTTON_RELEASE,
4355 AINPUT_SOURCE_MOUSE)
4356 .buttonState(0)
4357 .actionButton(AMOTION_EVENT_BUTTON_PRIMARY)
Siarhei Vishniakou6d73f832022-07-21 17:27:03 -07004358 .pointer(PointerBuilder(0, ToolType::MOUSE).x(300).y(400))
Garfield Tandf26e862020-07-01 20:18:19 -07004359 .build()));
Siarhei Vishniakou5cee1e32022-11-29 12:35:39 -08004360 window->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_BUTTON_RELEASE));
Garfield Tandf26e862020-07-01 20:18:19 -07004361
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08004362 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07004363 injectMotionEvent(*mDispatcher,
Garfield Tandf26e862020-07-01 20:18:19 -07004364 MotionEventBuilder(AMOTION_EVENT_ACTION_UP, AINPUT_SOURCE_MOUSE)
4365 .buttonState(0)
Siarhei Vishniakou6d73f832022-07-21 17:27:03 -07004366 .pointer(PointerBuilder(0, ToolType::MOUSE).x(300).y(400))
Garfield Tandf26e862020-07-01 20:18:19 -07004367 .build()));
4368 window->consumeMotionUp(ADISPLAY_ID_DEFAULT);
4369
Siarhei Vishniakoua235c042023-05-02 09:59:09 -07004370 // We already canceled the hovering implicitly by injecting the "DOWN" event without lifting the
4371 // hover first. Therefore, injection of HOVER_EXIT is inconsistent, and should fail.
4372 ASSERT_EQ(InputEventInjectionResult::FAILED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07004373 injectMotionEvent(*mDispatcher,
Garfield Tandf26e862020-07-01 20:18:19 -07004374 MotionEventBuilder(AMOTION_EVENT_ACTION_HOVER_EXIT,
4375 AINPUT_SOURCE_MOUSE)
Siarhei Vishniakou6d73f832022-07-21 17:27:03 -07004376 .pointer(PointerBuilder(0, ToolType::MOUSE).x(300).y(400))
Garfield Tandf26e862020-07-01 20:18:19 -07004377 .build()));
Siarhei Vishniakouf372b812023-02-14 18:06:51 -08004378 window->assertNoEvents();
Garfield Tandf26e862020-07-01 20:18:19 -07004379}
4380
Siarhei Vishniakou0b0374d2022-11-17 17:40:53 -08004381/**
Siarhei Vishniakoub581f7f2022-12-07 20:23:06 +00004382 * Hover over a window, and then remove that window. Make sure that HOVER_EXIT for that event
4383 * is generated.
4384 */
4385TEST_F(InputDispatcherTest, HoverExitIsSentToRemovedWindow) {
4386 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
4387 sp<FakeWindowHandle> window =
4388 sp<FakeWindowHandle>::make(application, mDispatcher, "Window", ADISPLAY_ID_DEFAULT);
4389 window->setFrame(Rect(0, 0, 1200, 800));
4390
4391 mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application);
4392
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07004393 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Siarhei Vishniakoub581f7f2022-12-07 20:23:06 +00004394
4395 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07004396 injectMotionEvent(*mDispatcher,
Siarhei Vishniakoub581f7f2022-12-07 20:23:06 +00004397 MotionEventBuilder(AMOTION_EVENT_ACTION_HOVER_ENTER,
4398 AINPUT_SOURCE_MOUSE)
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07004399 .pointer(PointerBuilder(0, ToolType::MOUSE).x(300).y(400))
Siarhei Vishniakoub581f7f2022-12-07 20:23:06 +00004400 .build()));
4401 window->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_ENTER));
4402
4403 // Remove the window, but keep the channel.
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07004404 mDispatcher->onWindowInfosChanged({{}, {}, 0, 0});
Siarhei Vishniakoub581f7f2022-12-07 20:23:06 +00004405 window->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_EXIT));
4406}
4407
4408/**
Daniel Norman7487dfa2023-08-02 16:39:45 -07004409 * Test that invalid HOVER events sent by accessibility do not cause a fatal crash.
4410 */
Ameer Armalycff4fa52023-10-04 23:45:11 +00004411TEST_F_WITH_FLAGS(InputDispatcherTest, InvalidA11yHoverStreamDoesNotCrash,
4412 REQUIRES_FLAGS_DISABLED(ACONFIG_FLAG(com::android::input::flags,
4413 a11y_crash_on_inconsistent_event_stream))) {
Daniel Norman7487dfa2023-08-02 16:39:45 -07004414 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
4415 sp<FakeWindowHandle> window =
4416 sp<FakeWindowHandle>::make(application, mDispatcher, "Window", ADISPLAY_ID_DEFAULT);
4417 window->setFrame(Rect(0, 0, 1200, 800));
4418
4419 mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application);
4420
4421 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
4422
4423 MotionEventBuilder hoverEnterBuilder =
4424 MotionEventBuilder(AMOTION_EVENT_ACTION_HOVER_ENTER, AINPUT_SOURCE_MOUSE)
4425 .pointer(PointerBuilder(0, ToolType::MOUSE).x(300).y(400))
4426 .addFlag(AMOTION_EVENT_FLAG_IS_ACCESSIBILITY_EVENT);
4427 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
4428 injectMotionEvent(*mDispatcher, hoverEnterBuilder.build()));
4429 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
4430 injectMotionEvent(*mDispatcher, hoverEnterBuilder.build()));
4431 window->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_ENTER));
4432 window->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_ENTER));
4433}
4434
4435/**
Siarhei Vishniakou4e1ffa52023-02-21 11:50:34 -08004436 * If mouse is hovering when the touch goes down, the hovering should be stopped via HOVER_EXIT.
4437 */
Siarhei Vishniakoued89cbb2023-10-13 10:42:44 -07004438TEST_F(InputDispatcherTest, TouchDownAfterMouseHover_legacy) {
4439 SCOPED_FLAG_OVERRIDE(enable_multi_device_same_window_stream, false);
Siarhei Vishniakou4e1ffa52023-02-21 11:50:34 -08004440 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
4441 sp<FakeWindowHandle> window =
4442 sp<FakeWindowHandle>::make(application, mDispatcher, "Window", ADISPLAY_ID_DEFAULT);
4443 window->setFrame(Rect(0, 0, 100, 100));
4444
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07004445 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Siarhei Vishniakou4e1ffa52023-02-21 11:50:34 -08004446
4447 const int32_t mouseDeviceId = 7;
4448 const int32_t touchDeviceId = 4;
Siarhei Vishniakou4e1ffa52023-02-21 11:50:34 -08004449
4450 // Start hovering with the mouse
Prabir Pradhan678438e2023-04-13 19:32:51 +00004451 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_ENTER, AINPUT_SOURCE_MOUSE)
4452 .deviceId(mouseDeviceId)
4453 .pointer(PointerBuilder(0, ToolType::MOUSE).x(10).y(10))
4454 .build());
Siarhei Vishniakou4e1ffa52023-02-21 11:50:34 -08004455 window->consumeMotionEvent(
4456 AllOf(WithMotionAction(ACTION_HOVER_ENTER), WithDeviceId(mouseDeviceId)));
4457
4458 // Touch goes down
Prabir Pradhan678438e2023-04-13 19:32:51 +00004459 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
4460 .deviceId(touchDeviceId)
4461 .pointer(PointerBuilder(0, ToolType::FINGER).x(50).y(50))
4462 .build());
Siarhei Vishniakou4e1ffa52023-02-21 11:50:34 -08004463
4464 window->consumeMotionEvent(
4465 AllOf(WithMotionAction(ACTION_HOVER_EXIT), WithDeviceId(mouseDeviceId)));
4466 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(touchDeviceId)));
4467}
4468
4469/**
Siarhei Vishniakoued89cbb2023-10-13 10:42:44 -07004470 * If mouse is hovering when the touch goes down, the hovering should not be stopped.
4471 */
4472TEST_F(InputDispatcherTest, TouchDownAfterMouseHover) {
4473 SCOPED_FLAG_OVERRIDE(enable_multi_device_same_window_stream, true);
4474 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
4475 sp<FakeWindowHandle> window =
4476 sp<FakeWindowHandle>::make(application, mDispatcher, "Window", ADISPLAY_ID_DEFAULT);
4477 window->setFrame(Rect(0, 0, 100, 100));
4478
4479 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
4480
4481 const int32_t mouseDeviceId = 7;
4482 const int32_t touchDeviceId = 4;
4483
4484 // Start hovering with the mouse
4485 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_ENTER, AINPUT_SOURCE_MOUSE)
4486 .deviceId(mouseDeviceId)
4487 .pointer(PointerBuilder(0, ToolType::MOUSE).x(10).y(10))
4488 .build());
4489 window->consumeMotionEvent(
4490 AllOf(WithMotionAction(ACTION_HOVER_ENTER), WithDeviceId(mouseDeviceId)));
4491
4492 // Touch goes down
4493 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
4494 .deviceId(touchDeviceId)
4495 .pointer(PointerBuilder(0, ToolType::FINGER).x(50).y(50))
4496 .build());
4497 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(touchDeviceId)));
4498}
4499
4500/**
Siarhei Vishniakou0b0374d2022-11-17 17:40:53 -08004501 * Inject a mouse hover event followed by a tap from touchscreen.
Siarhei Vishniakoub581f7f2022-12-07 20:23:06 +00004502 * The tap causes a HOVER_EXIT event to be generated because the current event
4503 * stream's source has been switched.
Siarhei Vishniakou0b0374d2022-11-17 17:40:53 -08004504 */
Siarhei Vishniakoued89cbb2023-10-13 10:42:44 -07004505TEST_F(InputDispatcherTest, MouseHoverAndTouchTap_legacy) {
4506 SCOPED_FLAG_OVERRIDE(enable_multi_device_same_window_stream, false);
Siarhei Vishniakou0b0374d2022-11-17 17:40:53 -08004507 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
4508 sp<FakeWindowHandle> window =
4509 sp<FakeWindowHandle>::make(application, mDispatcher, "Window", ADISPLAY_ID_DEFAULT);
4510 window->setFrame(Rect(0, 0, 100, 100));
4511
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07004512 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -07004513 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_MOVE, AINPUT_SOURCE_MOUSE)
4514 .pointer(PointerBuilder(0, ToolType::MOUSE).x(50).y(50))
4515 .build());
Siarhei Vishniakou0b0374d2022-11-17 17:40:53 -08004516 ASSERT_NO_FATAL_FAILURE(
4517 window->consumeMotionEvent(AllOf(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_ENTER),
4518 WithSource(AINPUT_SOURCE_MOUSE))));
Siarhei Vishniakou0b0374d2022-11-17 17:40:53 -08004519
4520 // Tap on the window
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -07004521 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
4522 .pointer(PointerBuilder(0, ToolType::FINGER).x(10).y(10))
4523 .build());
Siarhei Vishniakou0b0374d2022-11-17 17:40:53 -08004524 ASSERT_NO_FATAL_FAILURE(
Siarhei Vishniakoub581f7f2022-12-07 20:23:06 +00004525 window->consumeMotionEvent(AllOf(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_EXIT),
4526 WithSource(AINPUT_SOURCE_MOUSE))));
4527
4528 ASSERT_NO_FATAL_FAILURE(
Siarhei Vishniakou0b0374d2022-11-17 17:40:53 -08004529 window->consumeMotionEvent(AllOf(WithMotionAction(AMOTION_EVENT_ACTION_DOWN),
4530 WithSource(AINPUT_SOURCE_TOUCHSCREEN))));
4531
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -07004532 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN)
4533 .pointer(PointerBuilder(0, ToolType::FINGER).x(10).y(10))
4534 .build());
Siarhei Vishniakou0b0374d2022-11-17 17:40:53 -08004535 ASSERT_NO_FATAL_FAILURE(
4536 window->consumeMotionEvent(AllOf(WithMotionAction(AMOTION_EVENT_ACTION_UP),
4537 WithSource(AINPUT_SOURCE_TOUCHSCREEN))));
4538}
4539
Siarhei Vishniakoued89cbb2023-10-13 10:42:44 -07004540/**
4541 * Send a mouse hover event followed by a tap from touchscreen.
4542 * The tap causes a HOVER_EXIT event to be generated because the current event
4543 * stream's source has been switched.
4544 */
4545TEST_F(InputDispatcherTest, MouseHoverAndTouchTap) {
4546 SCOPED_FLAG_OVERRIDE(enable_multi_device_same_window_stream, true);
4547 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
4548 sp<FakeWindowHandle> window =
4549 sp<FakeWindowHandle>::make(application, mDispatcher, "Window", ADISPLAY_ID_DEFAULT);
4550 window->setFrame(Rect(0, 0, 100, 100));
4551
4552 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
4553 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_MOVE, AINPUT_SOURCE_MOUSE)
4554 .pointer(PointerBuilder(0, ToolType::MOUSE).x(50).y(50))
4555 .build());
4556
4557 window->consumeMotionEvent(AllOf(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_ENTER),
4558 WithSource(AINPUT_SOURCE_MOUSE)));
4559
4560 // Tap on the window
4561 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
4562 .pointer(PointerBuilder(0, ToolType::FINGER).x(10).y(10))
4563 .build());
4564
4565 window->consumeMotionEvent(AllOf(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_EXIT),
4566 WithSource(AINPUT_SOURCE_MOUSE)));
4567
4568 window->consumeMotionEvent(AllOf(WithMotionAction(AMOTION_EVENT_ACTION_DOWN),
4569 WithSource(AINPUT_SOURCE_TOUCHSCREEN)));
4570
4571 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN)
4572 .pointer(PointerBuilder(0, ToolType::FINGER).x(10).y(10))
4573 .build());
4574
4575 window->consumeMotionEvent(AllOf(WithMotionAction(AMOTION_EVENT_ACTION_UP),
4576 WithSource(AINPUT_SOURCE_TOUCHSCREEN)));
4577}
4578
Tommy Nordgrendae9dfc2022-10-13 11:25:57 +02004579TEST_F(InputDispatcherTest, HoverEnterMoveRemoveWindowsInSecondDisplay) {
4580 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
4581 sp<FakeWindowHandle> windowDefaultDisplay =
4582 sp<FakeWindowHandle>::make(application, mDispatcher, "DefaultDisplay",
4583 ADISPLAY_ID_DEFAULT);
4584 windowDefaultDisplay->setFrame(Rect(0, 0, 600, 800));
4585 sp<FakeWindowHandle> windowSecondDisplay =
4586 sp<FakeWindowHandle>::make(application, mDispatcher, "SecondDisplay",
4587 SECOND_DISPLAY_ID);
4588 windowSecondDisplay->setFrame(Rect(0, 0, 600, 800));
4589
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07004590 mDispatcher->onWindowInfosChanged(
4591 {{*windowDefaultDisplay->getInfo(), *windowSecondDisplay->getInfo()}, {}, 0, 0});
Tommy Nordgrendae9dfc2022-10-13 11:25:57 +02004592
4593 // Set cursor position in window in default display and check that hover enter and move
4594 // events are generated.
4595 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07004596 injectMotionEvent(*mDispatcher,
Tommy Nordgrendae9dfc2022-10-13 11:25:57 +02004597 MotionEventBuilder(AMOTION_EVENT_ACTION_HOVER_MOVE,
4598 AINPUT_SOURCE_MOUSE)
4599 .displayId(ADISPLAY_ID_DEFAULT)
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07004600 .pointer(PointerBuilder(0, ToolType::MOUSE).x(300).y(600))
Tommy Nordgrendae9dfc2022-10-13 11:25:57 +02004601 .build()));
Siarhei Vishniakou5cee1e32022-11-29 12:35:39 -08004602 windowDefaultDisplay->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_ENTER));
Tommy Nordgrendae9dfc2022-10-13 11:25:57 +02004603
4604 // Remove all windows in secondary display and check that no event happens on window in
4605 // primary display.
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07004606 mDispatcher->onWindowInfosChanged({{*windowDefaultDisplay->getInfo()}, {}, 0, 0});
4607
Tommy Nordgrendae9dfc2022-10-13 11:25:57 +02004608 windowDefaultDisplay->assertNoEvents();
4609
4610 // Move cursor position in window in default display and check that only hover move
4611 // event is generated and not hover enter event.
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07004612 mDispatcher->onWindowInfosChanged(
4613 {{*windowDefaultDisplay->getInfo(), *windowSecondDisplay->getInfo()}, {}, 0, 0});
Tommy Nordgrendae9dfc2022-10-13 11:25:57 +02004614 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07004615 injectMotionEvent(*mDispatcher,
Tommy Nordgrendae9dfc2022-10-13 11:25:57 +02004616 MotionEventBuilder(AMOTION_EVENT_ACTION_HOVER_MOVE,
4617 AINPUT_SOURCE_MOUSE)
4618 .displayId(ADISPLAY_ID_DEFAULT)
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07004619 .pointer(PointerBuilder(0, ToolType::MOUSE).x(400).y(700))
Tommy Nordgrendae9dfc2022-10-13 11:25:57 +02004620 .build()));
Siarhei Vishniakou5cee1e32022-11-29 12:35:39 -08004621 windowDefaultDisplay->consumeMotionEvent(
4622 AllOf(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_MOVE),
4623 WithSource(AINPUT_SOURCE_MOUSE)));
Tommy Nordgrendae9dfc2022-10-13 11:25:57 +02004624 windowDefaultDisplay->assertNoEvents();
4625}
4626
Garfield Tan00f511d2019-06-12 16:55:40 -07004627TEST_F(InputDispatcherTest, DispatchMouseEventsUnderCursor) {
Chris Yea209fde2020-07-22 13:54:51 -07004628 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
Garfield Tan00f511d2019-06-12 16:55:40 -07004629
4630 sp<FakeWindowHandle> windowLeft =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07004631 sp<FakeWindowHandle>::make(application, mDispatcher, "Left", ADISPLAY_ID_DEFAULT);
Garfield Tan00f511d2019-06-12 16:55:40 -07004632 windowLeft->setFrame(Rect(0, 0, 600, 800));
Garfield Tan00f511d2019-06-12 16:55:40 -07004633 sp<FakeWindowHandle> windowRight =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07004634 sp<FakeWindowHandle>::make(application, mDispatcher, "Right", ADISPLAY_ID_DEFAULT);
Garfield Tan00f511d2019-06-12 16:55:40 -07004635 windowRight->setFrame(Rect(600, 0, 1200, 800));
Garfield Tan00f511d2019-06-12 16:55:40 -07004636
4637 mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application);
4638
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07004639 mDispatcher->onWindowInfosChanged(
4640 {{*windowLeft->getInfo(), *windowRight->getInfo()}, {}, 0, 0});
Garfield Tan00f511d2019-06-12 16:55:40 -07004641
4642 // Inject an event with coordinate in the area of right window, with mouse cursor in the area of
4643 // left window. This event should be dispatched to the left window.
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08004644 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07004645 injectMotionEvent(*mDispatcher, AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_MOUSE,
Siarhei Vishniakou4cb50ca2020-05-26 21:43:02 -07004646 ADISPLAY_ID_DEFAULT, {610, 400}, {599, 400}));
Siarhei Vishniakouc5ca85c2019-11-15 17:20:00 -08004647 windowLeft->consumeMotionDown(ADISPLAY_ID_DEFAULT);
Garfield Tan00f511d2019-06-12 16:55:40 -07004648 windowRight->assertNoEvents();
4649}
4650
Siarhei Vishniakou2bfa9052019-11-21 18:10:54 -08004651TEST_F(InputDispatcherTest, NotifyDeviceReset_CancelsKeyStream) {
Chris Yea209fde2020-07-22 13:54:51 -07004652 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07004653 sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher,
4654 "Fake Window", ADISPLAY_ID_DEFAULT);
Vishnu Nair47074b82020-08-14 11:54:47 -07004655 window->setFocusable(true);
Siarhei Vishniakou2bfa9052019-11-21 18:10:54 -08004656
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07004657 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Vishnu Nair958da932020-08-21 17:12:37 -07004658 setFocusedWindow(window);
4659
Siarhei Vishniakouf1035d42019-09-20 16:32:01 +01004660 window->consumeFocusEvent(true);
Siarhei Vishniakou2bfa9052019-11-21 18:10:54 -08004661
Prabir Pradhan678438e2023-04-13 19:32:51 +00004662 mDispatcher->notifyKey(generateKeyArgs(AKEY_EVENT_ACTION_DOWN, ADISPLAY_ID_DEFAULT));
Siarhei Vishniakou2bfa9052019-11-21 18:10:54 -08004663
4664 // Window should receive key down event.
4665 window->consumeKeyDown(ADISPLAY_ID_DEFAULT);
4666
4667 // When device reset happens, that key stream should be terminated with FLAG_CANCELED
4668 // on the app side.
Prabir Pradhan678438e2023-04-13 19:32:51 +00004669 mDispatcher->notifyDeviceReset({/*id=*/10, /*eventTime=*/20, DEVICE_ID});
Prabir Pradhan7662a8d2023-12-15 01:58:14 +00004670 window->consumeKeyUp(ADISPLAY_ID_DEFAULT, AKEY_EVENT_FLAG_CANCELED);
Siarhei Vishniakou2bfa9052019-11-21 18:10:54 -08004671}
4672
4673TEST_F(InputDispatcherTest, NotifyDeviceReset_CancelsMotionStream) {
Chris Yea209fde2020-07-22 13:54:51 -07004674 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07004675 sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher,
4676 "Fake Window", ADISPLAY_ID_DEFAULT);
Siarhei Vishniakou2bfa9052019-11-21 18:10:54 -08004677
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07004678 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Siarhei Vishniakou2bfa9052019-11-21 18:10:54 -08004679
Prabir Pradhan678438e2023-04-13 19:32:51 +00004680 mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_DOWN,
4681 AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT));
Siarhei Vishniakou2bfa9052019-11-21 18:10:54 -08004682
4683 // Window should receive motion down event.
4684 window->consumeMotionDown(ADISPLAY_ID_DEFAULT);
4685
4686 // When device reset happens, that motion stream should be terminated with ACTION_CANCEL
4687 // on the app side.
Prabir Pradhan678438e2023-04-13 19:32:51 +00004688 mDispatcher->notifyDeviceReset({/*id=*/10, /*eventTime=*/20, DEVICE_ID});
Siarhei Vishniakou1ae72f12023-01-29 12:55:30 -08004689 window->consumeMotionEvent(
4690 AllOf(WithMotionAction(ACTION_CANCEL), WithDisplayId(ADISPLAY_ID_DEFAULT)));
Siarhei Vishniakou2bfa9052019-11-21 18:10:54 -08004691}
4692
Siarhei Vishniakou0686f0c2023-05-02 11:56:15 -07004693TEST_F(InputDispatcherTest, NotifyDeviceResetCancelsHoveringStream) {
4694 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
4695 sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher,
4696 "Fake Window", ADISPLAY_ID_DEFAULT);
4697
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07004698 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Siarhei Vishniakou0686f0c2023-05-02 11:56:15 -07004699
4700 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_ENTER, AINPUT_SOURCE_STYLUS)
4701 .pointer(PointerBuilder(0, ToolType::STYLUS).x(10).y(10))
4702 .build());
4703
4704 window->consumeMotionEvent(WithMotionAction(ACTION_HOVER_ENTER));
4705
4706 // When device reset happens, that hover stream should be terminated with ACTION_HOVER_EXIT
4707 mDispatcher->notifyDeviceReset({/*id=*/10, /*eventTime=*/20, DEVICE_ID});
4708 window->consumeMotionEvent(WithMotionAction(ACTION_HOVER_EXIT));
4709
4710 // After the device has been reset, a new hovering stream can be sent to the window
4711 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_ENTER, AINPUT_SOURCE_STYLUS)
4712 .pointer(PointerBuilder(0, ToolType::STYLUS).x(15).y(15))
4713 .build());
4714 window->consumeMotionEvent(WithMotionAction(ACTION_HOVER_ENTER));
4715}
4716
Arthur Hung2ee6d0b2022-03-03 20:19:38 +08004717TEST_F(InputDispatcherTest, InterceptKeyByPolicy) {
4718 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07004719 sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher,
4720 "Fake Window", ADISPLAY_ID_DEFAULT);
Arthur Hung2ee6d0b2022-03-03 20:19:38 +08004721 window->setFocusable(true);
4722
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07004723 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Arthur Hung2ee6d0b2022-03-03 20:19:38 +08004724 setFocusedWindow(window);
4725
4726 window->consumeFocusEvent(true);
4727
Prabir Pradhan678438e2023-04-13 19:32:51 +00004728 const NotifyKeyArgs keyArgs = generateKeyArgs(AKEY_EVENT_ACTION_DOWN, ADISPLAY_ID_DEFAULT);
Arthur Hung2ee6d0b2022-03-03 20:19:38 +08004729 const std::chrono::milliseconds interceptKeyTimeout = 50ms;
4730 const nsecs_t injectTime = keyArgs.eventTime;
4731 mFakePolicy->setInterceptKeyTimeout(interceptKeyTimeout);
Prabir Pradhan678438e2023-04-13 19:32:51 +00004732 mDispatcher->notifyKey(keyArgs);
Arthur Hung2ee6d0b2022-03-03 20:19:38 +08004733 // The dispatching time should be always greater than or equal to intercept key timeout.
4734 window->consumeKeyDown(ADISPLAY_ID_DEFAULT);
4735 ASSERT_TRUE((systemTime(SYSTEM_TIME_MONOTONIC) - injectTime) >=
4736 std::chrono::nanoseconds(interceptKeyTimeout).count());
4737}
4738
Siarhei Vishniakouf54d2ab2023-06-09 13:23:53 -07004739/**
4740 * Keys with ACTION_UP are delivered immediately, even if a long 'intercept key timeout' is set.
4741 */
Arthur Hung2ee6d0b2022-03-03 20:19:38 +08004742TEST_F(InputDispatcherTest, InterceptKeyIfKeyUp) {
4743 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07004744 sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher,
4745 "Fake Window", ADISPLAY_ID_DEFAULT);
Arthur Hung2ee6d0b2022-03-03 20:19:38 +08004746 window->setFocusable(true);
4747
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07004748 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Arthur Hung2ee6d0b2022-03-03 20:19:38 +08004749 setFocusedWindow(window);
4750
4751 window->consumeFocusEvent(true);
4752
Prabir Pradhan678438e2023-04-13 19:32:51 +00004753 mDispatcher->notifyKey(generateKeyArgs(AKEY_EVENT_ACTION_DOWN, ADISPLAY_ID_DEFAULT));
Arthur Hung2ee6d0b2022-03-03 20:19:38 +08004754 window->consumeKeyDown(ADISPLAY_ID_DEFAULT);
Siarhei Vishniakouf54d2ab2023-06-09 13:23:53 -07004755
4756 // Set a value that's significantly larger than the default consumption timeout. If the
4757 // implementation is correct, the actual value doesn't matter; it won't slow down the test.
4758 mFakePolicy->setInterceptKeyTimeout(600ms);
4759 mDispatcher->notifyKey(generateKeyArgs(AKEY_EVENT_ACTION_UP, ADISPLAY_ID_DEFAULT));
4760 // Window should receive key event immediately when same key up.
Arthur Hung2ee6d0b2022-03-03 20:19:38 +08004761 window->consumeKeyUp(ADISPLAY_ID_DEFAULT);
4762}
4763
Prabir Pradhanc44ce4d2021-10-05 05:26:29 -07004764/**
Siarhei Vishniakou487c49b2022-12-02 15:48:57 -08004765 * Two windows. First is a regular window. Second does not overlap with the first, and has
4766 * WATCH_OUTSIDE_TOUCH.
4767 * Both windows are owned by the same UID.
4768 * Tap first window. Make sure that the second window receives ACTION_OUTSIDE with correct, non-zero
4769 * coordinates. The coordinates are not zeroed out because both windows are owned by the same UID.
4770 */
4771TEST_F(InputDispatcherTest, ActionOutsideForOwnedWindowHasValidCoordinates) {
4772 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -07004773 sp<FakeWindowHandle> window =
4774 sp<FakeWindowHandle>::make(application, mDispatcher, "Window", ADISPLAY_ID_DEFAULT);
Siarhei Vishniakou487c49b2022-12-02 15:48:57 -08004775 window->setFrame(Rect{0, 0, 100, 100});
4776
4777 sp<FakeWindowHandle> outsideWindow =
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -07004778 sp<FakeWindowHandle>::make(application, mDispatcher, "Outside Window",
Siarhei Vishniakou487c49b2022-12-02 15:48:57 -08004779 ADISPLAY_ID_DEFAULT);
4780 outsideWindow->setFrame(Rect{100, 100, 200, 200});
4781 outsideWindow->setWatchOutsideTouch(true);
4782 // outsideWindow must be above 'window' to receive ACTION_OUTSIDE events when 'window' is tapped
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07004783 mDispatcher->onWindowInfosChanged({{*outsideWindow->getInfo(), *window->getInfo()}, {}, 0, 0});
Siarhei Vishniakou487c49b2022-12-02 15:48:57 -08004784
4785 // Tap on first window.
Prabir Pradhan678438e2023-04-13 19:32:51 +00004786 mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_DOWN,
4787 AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
4788 {PointF{50, 50}}));
Siarhei Vishniakou487c49b2022-12-02 15:48:57 -08004789 window->consumeMotionDown();
4790 // The coordinates of the tap in 'outsideWindow' are relative to its top left corner.
4791 // Therefore, we should offset them by (100, 100) relative to the screen's top left corner.
4792 outsideWindow->consumeMotionEvent(
4793 AllOf(WithMotionAction(ACTION_OUTSIDE), WithCoords(-50, -50)));
Prabir Pradhan502a7252023-12-01 16:11:24 +00004794
4795 // Ensure outsideWindow doesn't get any more events for the gesture.
4796 mDispatcher->notifyMotion(generateMotionArgs(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN,
4797 ADISPLAY_ID_DEFAULT, {PointF{51, 51}}));
4798 window->consumeMotionMove();
4799 outsideWindow->assertNoEvents();
Siarhei Vishniakou487c49b2022-12-02 15:48:57 -08004800}
4801
4802/**
Linnan Liccf6ce32024-04-11 20:32:13 +08004803 * Three windows:
4804 * - Left window
4805 * - Right window
4806 * - Outside window(watch for ACTION_OUTSIDE events)
4807 * The windows "left" and "outside" share the same owner, the window "right" has a different owner,
4808 * In order to allow the outside window can receive the ACTION_OUTSIDE events, the outside window is
4809 * positioned above the "left" and "right" windows, and it doesn't overlap with them.
4810 *
4811 * First, device A report a down event landed in the right window, the outside window can receive
4812 * an ACTION_OUTSIDE event that with zeroed coordinates, the device B report a down event landed
4813 * in the left window, the outside window can receive an ACTION_OUTSIDE event the with valid
4814 * coordinates, after these, device A and device B continue report MOVE event, the right and left
4815 * window can receive it, but outside window event can't receive it.
4816 */
4817TEST_F(InputDispatcherTest, ActionOutsideForOwnedWindowHasValidCoordinatesWhenMultiDevice) {
4818 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
4819 sp<FakeWindowHandle> leftWindow =
4820 sp<FakeWindowHandle>::make(application, mDispatcher, "Left Window",
4821 ADISPLAY_ID_DEFAULT);
4822 leftWindow->setFrame(Rect{0, 0, 100, 100});
4823 leftWindow->setOwnerInfo(gui::Pid{1}, gui::Uid{101});
4824
4825 sp<FakeWindowHandle> outsideWindow =
4826 sp<FakeWindowHandle>::make(application, mDispatcher, "Outside Window",
4827 ADISPLAY_ID_DEFAULT);
4828 outsideWindow->setFrame(Rect{100, 100, 200, 200});
4829 outsideWindow->setOwnerInfo(gui::Pid{1}, gui::Uid{101});
4830 outsideWindow->setWatchOutsideTouch(true);
4831
4832 std::shared_ptr<FakeApplicationHandle> anotherApplication =
4833 std::make_shared<FakeApplicationHandle>();
4834 sp<FakeWindowHandle> rightWindow =
4835 sp<FakeWindowHandle>::make(anotherApplication, mDispatcher, "Right Window",
4836 ADISPLAY_ID_DEFAULT);
4837 rightWindow->setFrame(Rect{100, 0, 200, 100});
4838 rightWindow->setOwnerInfo(gui::Pid{2}, gui::Uid{202});
4839
4840 // OutsideWindow must be above left window and right window to receive ACTION_OUTSIDE events
4841 // when left window or right window is tapped
4842 mDispatcher->onWindowInfosChanged(
4843 {{*outsideWindow->getInfo(), *leftWindow->getInfo(), *rightWindow->getInfo()},
4844 {},
4845 0,
4846 0});
4847
4848 const DeviceId deviceA = 9;
4849 const DeviceId deviceB = 3;
4850
4851 // Tap on right window use device A
4852 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
4853 .pointer(PointerBuilder(0, ToolType::FINGER).x(150).y(50))
4854 .deviceId(deviceA)
4855 .build());
4856 leftWindow->assertNoEvents();
4857 rightWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(deviceA)));
4858 // Right window is belonged to another owner, so outsideWindow should receive ACTION_OUTSIDE
4859 // with zeroed coords.
4860 outsideWindow->consumeMotionEvent(
4861 AllOf(WithMotionAction(ACTION_OUTSIDE), WithDeviceId(deviceA), WithCoords(0, 0)));
4862
4863 // Tap on left window use device B
4864 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
4865 .pointer(PointerBuilder(0, ToolType::FINGER).x(50).y(50))
4866 .deviceId(deviceB)
4867 .build());
4868 leftWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(deviceB)));
4869 rightWindow->assertNoEvents();
4870 // Because new gesture down on the left window that has the same owner with outside Window, the
4871 // outside Window should receive the ACTION_OUTSIDE with coords.
4872 outsideWindow->consumeMotionEvent(
4873 AllOf(WithMotionAction(ACTION_OUTSIDE), WithDeviceId(deviceB), WithCoords(-50, -50)));
4874
4875 // Ensure that windows that can only accept outside do not receive remaining gestures
4876 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN)
4877 .pointer(PointerBuilder(0, ToolType::FINGER).x(151).y(51))
4878 .deviceId(deviceA)
4879 .build());
4880 leftWindow->assertNoEvents();
4881 rightWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(deviceA)));
4882
4883 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN)
4884 .pointer(PointerBuilder(0, ToolType::FINGER).x(51).y(51))
4885 .deviceId(deviceB)
4886 .build());
4887 leftWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(deviceB)));
4888 rightWindow->assertNoEvents();
4889 outsideWindow->assertNoEvents();
4890}
4891
4892/**
Prabir Pradhanb60b1dc2022-03-15 14:02:35 +00004893 * This test documents the behavior of WATCH_OUTSIDE_TOUCH. The window will get ACTION_OUTSIDE when
4894 * a another pointer causes ACTION_DOWN to be sent to another window for the first time. Only one
4895 * ACTION_OUTSIDE event is sent per gesture.
4896 */
4897TEST_F(InputDispatcherTest, ActionOutsideSentOnlyWhenAWindowIsTouched) {
4898 // There are three windows that do not overlap. `window` wants to WATCH_OUTSIDE_TOUCH.
4899 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07004900 sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher,
4901 "First Window", ADISPLAY_ID_DEFAULT);
Prabir Pradhanb60b1dc2022-03-15 14:02:35 +00004902 window->setWatchOutsideTouch(true);
4903 window->setFrame(Rect{0, 0, 100, 100});
4904 sp<FakeWindowHandle> secondWindow =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07004905 sp<FakeWindowHandle>::make(application, mDispatcher, "Second Window",
4906 ADISPLAY_ID_DEFAULT);
Prabir Pradhanb60b1dc2022-03-15 14:02:35 +00004907 secondWindow->setFrame(Rect{100, 100, 200, 200});
4908 sp<FakeWindowHandle> thirdWindow =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07004909 sp<FakeWindowHandle>::make(application, mDispatcher, "Third Window",
4910 ADISPLAY_ID_DEFAULT);
Prabir Pradhanb60b1dc2022-03-15 14:02:35 +00004911 thirdWindow->setFrame(Rect{200, 200, 300, 300});
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07004912 mDispatcher->onWindowInfosChanged(
4913 {{*window->getInfo(), *secondWindow->getInfo(), *thirdWindow->getInfo()}, {}, 0, 0});
Prabir Pradhanb60b1dc2022-03-15 14:02:35 +00004914
4915 // First pointer lands outside all windows. `window` does not get ACTION_OUTSIDE.
Prabir Pradhan678438e2023-04-13 19:32:51 +00004916 mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_DOWN,
4917 AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
4918 {PointF{-10, -10}}));
Prabir Pradhanb60b1dc2022-03-15 14:02:35 +00004919 window->assertNoEvents();
4920 secondWindow->assertNoEvents();
4921
4922 // The second pointer lands inside `secondWindow`, which should receive a DOWN event.
4923 // Now, `window` should get ACTION_OUTSIDE.
Prabir Pradhan678438e2023-04-13 19:32:51 +00004924 mDispatcher->notifyMotion(generateMotionArgs(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN,
4925 ADISPLAY_ID_DEFAULT,
4926 {PointF{-10, -10}, PointF{105, 105}}));
Siarhei Vishniakou487c49b2022-12-02 15:48:57 -08004927 const std::map<int32_t, PointF> expectedPointers{{0, PointF{-10, -10}}, {1, PointF{105, 105}}};
4928 window->consumeMotionEvent(
4929 AllOf(WithMotionAction(ACTION_OUTSIDE), WithPointers(expectedPointers)));
Prabir Pradhanb60b1dc2022-03-15 14:02:35 +00004930 secondWindow->consumeMotionDown();
4931 thirdWindow->assertNoEvents();
4932
4933 // The third pointer lands inside `thirdWindow`, which should receive a DOWN event. There is
4934 // no ACTION_OUTSIDE sent to `window` because one has already been sent for this gesture.
Prabir Pradhan678438e2023-04-13 19:32:51 +00004935 mDispatcher->notifyMotion(
4936 generateMotionArgs(POINTER_2_DOWN, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
4937 {PointF{-10, -10}, PointF{105, 105}, PointF{205, 205}}));
Prabir Pradhanb60b1dc2022-03-15 14:02:35 +00004938 window->assertNoEvents();
4939 secondWindow->consumeMotionMove();
4940 thirdWindow->consumeMotionDown();
4941}
4942
Prabir Pradhan814fe082022-07-22 20:22:18 +00004943TEST_F(InputDispatcherTest, OnWindowInfosChanged_RemoveAllWindowsOnDisplay) {
4944 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07004945 sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher,
4946 "Fake Window", ADISPLAY_ID_DEFAULT);
Prabir Pradhan814fe082022-07-22 20:22:18 +00004947 window->setFocusable(true);
4948
Patrick Williamsd828f302023-04-28 17:52:08 -05004949 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Prabir Pradhan814fe082022-07-22 20:22:18 +00004950 setFocusedWindow(window);
4951
4952 window->consumeFocusEvent(true);
4953
Prabir Pradhan678438e2023-04-13 19:32:51 +00004954 const NotifyKeyArgs keyDown = generateKeyArgs(AKEY_EVENT_ACTION_DOWN, ADISPLAY_ID_DEFAULT);
4955 const NotifyKeyArgs keyUp = generateKeyArgs(AKEY_EVENT_ACTION_UP, ADISPLAY_ID_DEFAULT);
4956 mDispatcher->notifyKey(keyDown);
4957 mDispatcher->notifyKey(keyUp);
Prabir Pradhan814fe082022-07-22 20:22:18 +00004958
4959 window->consumeKeyDown(ADISPLAY_ID_DEFAULT);
4960 window->consumeKeyUp(ADISPLAY_ID_DEFAULT);
4961
4962 // All windows are removed from the display. Ensure that we can no longer dispatch to it.
Patrick Williamsd828f302023-04-28 17:52:08 -05004963 mDispatcher->onWindowInfosChanged({{}, {}, 0, 0});
Prabir Pradhan814fe082022-07-22 20:22:18 +00004964
4965 window->consumeFocusEvent(false);
4966
Prabir Pradhan678438e2023-04-13 19:32:51 +00004967 mDispatcher->notifyKey(keyDown);
4968 mDispatcher->notifyKey(keyUp);
Prabir Pradhan814fe082022-07-22 20:22:18 +00004969 window->assertNoEvents();
4970}
4971
Arthur Hung96483742022-11-15 03:30:48 +00004972TEST_F(InputDispatcherTest, NonSplitTouchableWindowReceivesMultiTouch) {
4973 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
4974 sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher,
4975 "Fake Window", ADISPLAY_ID_DEFAULT);
4976 // Ensure window is non-split and have some transform.
4977 window->setPreventSplitting(true);
4978 window->setWindowOffset(20, 40);
Patrick Williamsd828f302023-04-28 17:52:08 -05004979 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Arthur Hung96483742022-11-15 03:30:48 +00004980
4981 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07004982 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
Arthur Hung96483742022-11-15 03:30:48 +00004983 {50, 50}))
4984 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
4985 window->consumeMotionDown(ADISPLAY_ID_DEFAULT);
4986
4987 const MotionEvent secondFingerDownEvent =
4988 MotionEventBuilder(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
4989 .displayId(ADISPLAY_ID_DEFAULT)
4990 .eventTime(systemTime(SYSTEM_TIME_MONOTONIC))
Siarhei Vishniakou6d73f832022-07-21 17:27:03 -07004991 .pointer(PointerBuilder(/*id=*/0, ToolType::FINGER).x(50).y(50))
4992 .pointer(PointerBuilder(/*id=*/1, ToolType::FINGER).x(-30).y(-50))
Arthur Hung96483742022-11-15 03:30:48 +00004993 .build();
4994 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07004995 injectMotionEvent(*mDispatcher, secondFingerDownEvent, INJECT_EVENT_TIMEOUT,
Arthur Hung96483742022-11-15 03:30:48 +00004996 InputEventInjectionSync::WAIT_FOR_RESULT))
4997 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
4998
Siarhei Vishniakoud3061ab2023-12-18 20:41:08 -08004999 std::unique_ptr<MotionEvent> event = window->consumeMotionEvent();
5000 ASSERT_NE(nullptr, event);
5001 EXPECT_EQ(POINTER_1_DOWN, event->getAction());
5002 EXPECT_EQ(70, event->getX(0)); // 50 + 20
5003 EXPECT_EQ(90, event->getY(0)); // 50 + 40
5004 EXPECT_EQ(-10, event->getX(1)); // -30 + 20
5005 EXPECT_EQ(-10, event->getY(1)); // -50 + 40
Arthur Hung96483742022-11-15 03:30:48 +00005006}
5007
Siarhei Vishniakou25537f82023-07-18 14:35:47 -07005008/**
5009 * Two windows: a splittable and a non-splittable.
5010 * The non-splittable window shouldn't receive any "incomplete" gestures.
5011 * Send the first pointer to the splittable window, and then touch the non-splittable window.
5012 * The second pointer should be dropped because the initial window is splittable, so it won't get
5013 * any pointers outside of it, and the second window is non-splittable, so it shouldn't get any
5014 * "incomplete" gestures.
5015 */
5016TEST_F(InputDispatcherTest, SplittableAndNonSplittableWindows) {
5017 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
5018 sp<FakeWindowHandle> leftWindow =
5019 sp<FakeWindowHandle>::make(application, mDispatcher, "Left splittable Window",
5020 ADISPLAY_ID_DEFAULT);
5021 leftWindow->setPreventSplitting(false);
5022 leftWindow->setFrame(Rect(0, 0, 100, 100));
5023 sp<FakeWindowHandle> rightWindow =
5024 sp<FakeWindowHandle>::make(application, mDispatcher, "Right non-splittable Window",
5025 ADISPLAY_ID_DEFAULT);
5026 rightWindow->setPreventSplitting(true);
5027 rightWindow->setFrame(Rect(100, 100, 200, 200));
5028 mDispatcher->onWindowInfosChanged(
5029 {{*leftWindow->getInfo(), *rightWindow->getInfo()}, {}, 0, 0});
5030
5031 // Touch down on left, splittable window
5032 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
5033 .pointer(PointerBuilder(0, ToolType::FINGER).x(50).y(50))
5034 .build());
5035 leftWindow->consumeMotionEvent(WithMotionAction(ACTION_DOWN));
5036
5037 mDispatcher->notifyMotion(
5038 MotionArgsBuilder(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
5039 .pointer(PointerBuilder(/*id=*/0, ToolType::FINGER).x(50).y(50))
5040 .pointer(PointerBuilder(/*id=*/1, ToolType::FINGER).x(150).y(150))
5041 .build());
5042 leftWindow->assertNoEvents();
5043 rightWindow->assertNoEvents();
5044}
5045
Harry Cuttsb166c002023-05-09 13:06:05 +00005046TEST_F(InputDispatcherTest, TouchpadThreeFingerSwipeOnlySentToTrustedOverlays) {
5047 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
5048 sp<FakeWindowHandle> window =
5049 sp<FakeWindowHandle>::make(application, mDispatcher, "Window", ADISPLAY_ID_DEFAULT);
5050 window->setFrame(Rect(0, 0, 400, 400));
5051 sp<FakeWindowHandle> trustedOverlay =
5052 sp<FakeWindowHandle>::make(application, mDispatcher, "Trusted Overlay",
5053 ADISPLAY_ID_DEFAULT);
5054 trustedOverlay->setSpy(true);
5055 trustedOverlay->setTrustedOverlay(true);
5056
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07005057 mDispatcher->onWindowInfosChanged({{*trustedOverlay->getInfo(), *window->getInfo()}, {}, 0, 0});
Harry Cuttsb166c002023-05-09 13:06:05 +00005058
5059 // Start a three-finger touchpad swipe
5060 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_MOUSE)
5061 .pointer(PointerBuilder(0, ToolType::FINGER).x(200).y(100))
5062 .classification(MotionClassification::MULTI_FINGER_SWIPE)
5063 .build());
5064 mDispatcher->notifyMotion(MotionArgsBuilder(POINTER_1_DOWN, AINPUT_SOURCE_MOUSE)
5065 .pointer(PointerBuilder(0, ToolType::FINGER).x(200).y(100))
5066 .pointer(PointerBuilder(1, ToolType::FINGER).x(250).y(100))
5067 .classification(MotionClassification::MULTI_FINGER_SWIPE)
5068 .build());
5069 mDispatcher->notifyMotion(MotionArgsBuilder(POINTER_2_DOWN, AINPUT_SOURCE_MOUSE)
5070 .pointer(PointerBuilder(0, ToolType::FINGER).x(200).y(100))
5071 .pointer(PointerBuilder(1, ToolType::FINGER).x(250).y(100))
5072 .pointer(PointerBuilder(2, ToolType::FINGER).x(300).y(100))
5073 .classification(MotionClassification::MULTI_FINGER_SWIPE)
5074 .build());
5075
5076 trustedOverlay->consumeMotionEvent(WithMotionAction(ACTION_DOWN));
5077 trustedOverlay->consumeMotionEvent(WithMotionAction(POINTER_1_DOWN));
5078 trustedOverlay->consumeMotionEvent(WithMotionAction(POINTER_2_DOWN));
5079
5080 // Move the swipe a bit
5081 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_MOUSE)
5082 .pointer(PointerBuilder(0, ToolType::FINGER).x(200).y(105))
5083 .pointer(PointerBuilder(1, ToolType::FINGER).x(250).y(105))
5084 .pointer(PointerBuilder(2, ToolType::FINGER).x(300).y(105))
5085 .classification(MotionClassification::MULTI_FINGER_SWIPE)
5086 .build());
5087
5088 trustedOverlay->consumeMotionEvent(WithMotionAction(ACTION_MOVE));
5089
5090 // End the swipe
5091 mDispatcher->notifyMotion(MotionArgsBuilder(POINTER_2_UP, AINPUT_SOURCE_MOUSE)
5092 .pointer(PointerBuilder(0, ToolType::FINGER).x(200).y(105))
5093 .pointer(PointerBuilder(1, ToolType::FINGER).x(250).y(105))
5094 .pointer(PointerBuilder(2, ToolType::FINGER).x(300).y(105))
5095 .classification(MotionClassification::MULTI_FINGER_SWIPE)
5096 .build());
5097 mDispatcher->notifyMotion(MotionArgsBuilder(POINTER_1_UP, AINPUT_SOURCE_MOUSE)
5098 .pointer(PointerBuilder(0, ToolType::FINGER).x(200).y(105))
5099 .pointer(PointerBuilder(1, ToolType::FINGER).x(250).y(105))
5100 .classification(MotionClassification::MULTI_FINGER_SWIPE)
5101 .build());
5102 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_UP, AINPUT_SOURCE_MOUSE)
5103 .pointer(PointerBuilder(0, ToolType::FINGER).x(200).y(105))
5104 .classification(MotionClassification::MULTI_FINGER_SWIPE)
5105 .build());
5106
5107 trustedOverlay->consumeMotionEvent(WithMotionAction(POINTER_2_UP));
5108 trustedOverlay->consumeMotionEvent(WithMotionAction(POINTER_1_UP));
5109 trustedOverlay->consumeMotionEvent(WithMotionAction(ACTION_UP));
5110
5111 window->assertNoEvents();
5112}
5113
5114TEST_F(InputDispatcherTest, TouchpadThreeFingerSwipeNotSentToSingleWindow) {
5115 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
5116 sp<FakeWindowHandle> window =
5117 sp<FakeWindowHandle>::make(application, mDispatcher, "Window", ADISPLAY_ID_DEFAULT);
5118 window->setFrame(Rect(0, 0, 400, 400));
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07005119 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Harry Cuttsb166c002023-05-09 13:06:05 +00005120
5121 // Start a three-finger touchpad swipe
5122 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_MOUSE)
5123 .pointer(PointerBuilder(0, ToolType::FINGER).x(200).y(100))
5124 .classification(MotionClassification::MULTI_FINGER_SWIPE)
5125 .build());
5126 mDispatcher->notifyMotion(MotionArgsBuilder(POINTER_1_DOWN, AINPUT_SOURCE_MOUSE)
5127 .pointer(PointerBuilder(0, ToolType::FINGER).x(200).y(100))
5128 .pointer(PointerBuilder(1, ToolType::FINGER).x(250).y(100))
5129 .classification(MotionClassification::MULTI_FINGER_SWIPE)
5130 .build());
5131 mDispatcher->notifyMotion(MotionArgsBuilder(POINTER_2_DOWN, AINPUT_SOURCE_MOUSE)
5132 .pointer(PointerBuilder(0, ToolType::FINGER).x(200).y(100))
5133 .pointer(PointerBuilder(1, ToolType::FINGER).x(250).y(100))
5134 .pointer(PointerBuilder(2, ToolType::FINGER).x(300).y(100))
5135 .classification(MotionClassification::MULTI_FINGER_SWIPE)
5136 .build());
5137
5138 // Move the swipe a bit
5139 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_MOUSE)
5140 .pointer(PointerBuilder(0, ToolType::FINGER).x(200).y(105))
5141 .pointer(PointerBuilder(1, ToolType::FINGER).x(250).y(105))
5142 .pointer(PointerBuilder(2, ToolType::FINGER).x(300).y(105))
5143 .classification(MotionClassification::MULTI_FINGER_SWIPE)
5144 .build());
5145
5146 // End the swipe
5147 mDispatcher->notifyMotion(MotionArgsBuilder(POINTER_2_UP, AINPUT_SOURCE_MOUSE)
5148 .pointer(PointerBuilder(0, ToolType::FINGER).x(200).y(105))
5149 .pointer(PointerBuilder(1, ToolType::FINGER).x(250).y(105))
5150 .pointer(PointerBuilder(2, ToolType::FINGER).x(300).y(105))
5151 .classification(MotionClassification::MULTI_FINGER_SWIPE)
5152 .build());
5153 mDispatcher->notifyMotion(MotionArgsBuilder(POINTER_1_UP, AINPUT_SOURCE_MOUSE)
5154 .pointer(PointerBuilder(0, ToolType::FINGER).x(200).y(105))
5155 .pointer(PointerBuilder(1, ToolType::FINGER).x(250).y(105))
5156 .classification(MotionClassification::MULTI_FINGER_SWIPE)
5157 .build());
5158 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_UP, AINPUT_SOURCE_MOUSE)
5159 .pointer(PointerBuilder(0, ToolType::FINGER).x(200).y(105))
5160 .classification(MotionClassification::MULTI_FINGER_SWIPE)
5161 .build());
5162
5163 window->assertNoEvents();
5164}
5165
Prabir Pradhanb60b1dc2022-03-15 14:02:35 +00005166/**
Siarhei Vishniakouadb9fc92023-05-26 10:46:09 -07005167 * Send a two-pointer gesture to a single window. The window's orientation changes in response to
5168 * the first pointer.
Prabir Pradhan69d00bf2023-06-23 19:55:18 +00005169 * Ensure that the second pointer and the subsequent gesture is correctly delivered to the window.
Siarhei Vishniakouadb9fc92023-05-26 10:46:09 -07005170 */
5171TEST_F(InputDispatcherTest, MultiplePointersWithRotatingWindow) {
5172 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
5173 sp<FakeWindowHandle> window =
5174 sp<FakeWindowHandle>::make(application, mDispatcher, "Window", ADISPLAY_ID_DEFAULT);
5175 window->setFrame(Rect(0, 0, 400, 400));
Siarhei Vishniakou700424c2023-07-18 17:18:42 -07005176 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Siarhei Vishniakouadb9fc92023-05-26 10:46:09 -07005177
5178 const nsecs_t baseTime = systemTime(SYSTEM_TIME_MONOTONIC);
5179 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
5180 .downTime(baseTime + 10)
5181 .eventTime(baseTime + 10)
5182 .pointer(PointerBuilder(0, ToolType::FINGER).x(100).y(100))
5183 .build());
5184
5185 window->consumeMotionEvent(WithMotionAction(ACTION_DOWN));
5186
Siarhei Vishniakouadb9fc92023-05-26 10:46:09 -07005187 // Change the transform so that the orientation is now different from original.
Siarhei Vishniakou700424c2023-07-18 17:18:42 -07005188 window->setWindowTransform(0, -1, 1, 0);
Siarhei Vishniakouadb9fc92023-05-26 10:46:09 -07005189
Siarhei Vishniakou700424c2023-07-18 17:18:42 -07005190 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Siarhei Vishniakouadb9fc92023-05-26 10:46:09 -07005191
Siarhei Vishniakouadb9fc92023-05-26 10:46:09 -07005192 mDispatcher->notifyMotion(MotionArgsBuilder(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
5193 .downTime(baseTime + 10)
5194 .eventTime(baseTime + 30)
5195 .pointer(PointerBuilder(0, ToolType::FINGER).x(100).y(100))
5196 .pointer(PointerBuilder(1, ToolType::FINGER).x(200).y(200))
5197 .build());
5198
Prabir Pradhan69d00bf2023-06-23 19:55:18 +00005199 window->consumeMotionEvent(WithMotionAction(POINTER_1_DOWN));
5200
5201 // Finish the gesture and start a new one. Ensure all events are sent to the window.
Siarhei Vishniakouadb9fc92023-05-26 10:46:09 -07005202 mDispatcher->notifyMotion(MotionArgsBuilder(POINTER_1_UP, AINPUT_SOURCE_TOUCHSCREEN)
5203 .downTime(baseTime + 10)
5204 .eventTime(baseTime + 40)
5205 .pointer(PointerBuilder(0, ToolType::FINGER).x(100).y(100))
5206 .pointer(PointerBuilder(1, ToolType::FINGER).x(200).y(200))
5207 .build());
Prabir Pradhan69d00bf2023-06-23 19:55:18 +00005208
5209 window->consumeMotionEvent(WithMotionAction(POINTER_1_UP));
5210
Siarhei Vishniakouadb9fc92023-05-26 10:46:09 -07005211 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN)
5212 .downTime(baseTime + 10)
5213 .eventTime(baseTime + 50)
5214 .pointer(PointerBuilder(0, ToolType::FINGER).x(100).y(100))
5215 .build());
5216
Prabir Pradhan69d00bf2023-06-23 19:55:18 +00005217 window->consumeMotionEvent(WithMotionAction(ACTION_UP));
5218
Siarhei Vishniakouadb9fc92023-05-26 10:46:09 -07005219 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
5220 .downTime(baseTime + 60)
5221 .eventTime(baseTime + 60)
5222 .pointer(PointerBuilder(0, ToolType::FINGER).x(40).y(40))
5223 .build());
5224
Siarhei Vishniakou700424c2023-07-18 17:18:42 -07005225 window->consumeMotionEvent(WithMotionAction(ACTION_DOWN));
Siarhei Vishniakouadb9fc92023-05-26 10:46:09 -07005226}
5227
5228/**
Hu Guo771a7692023-09-17 20:51:08 +08005229 * When there are multiple screens, such as screen projection to TV or screen recording, if the
5230 * cancel event occurs, the coordinates of the cancel event should be sent to the target screen, and
5231 * its coordinates should be converted by the transform of the windows of target screen.
5232 */
5233TEST_F(InputDispatcherTest, WhenMultiDisplayWindowSameToken_DispatchCancelToTargetDisplay) {
5234 // This case will create a window and a spy window on the default display and mirror
5235 // window on the second display. cancel event is sent through spy window pilferPointers
5236 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
5237
5238 sp<FakeWindowHandle> spyWindowDefaultDisplay =
5239 sp<FakeWindowHandle>::make(application, mDispatcher, "Spy", ADISPLAY_ID_DEFAULT);
5240 spyWindowDefaultDisplay->setTrustedOverlay(true);
5241 spyWindowDefaultDisplay->setSpy(true);
5242
5243 sp<FakeWindowHandle> windowDefaultDisplay =
5244 sp<FakeWindowHandle>::make(application, mDispatcher, "DefaultDisplay",
5245 ADISPLAY_ID_DEFAULT);
5246 windowDefaultDisplay->setWindowTransform(1, 0, 0, 1);
5247
5248 sp<FakeWindowHandle> windowSecondDisplay = windowDefaultDisplay->clone(SECOND_DISPLAY_ID);
5249 windowSecondDisplay->setWindowTransform(2, 0, 0, 2);
5250
5251 // Add the windows to the dispatcher
5252 mDispatcher->onWindowInfosChanged(
5253 {{*spyWindowDefaultDisplay->getInfo(), *windowDefaultDisplay->getInfo(),
5254 *windowSecondDisplay->getInfo()},
5255 {},
5256 0,
5257 0});
5258
5259 // Send down to ADISPLAY_ID_DEFAULT
5260 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
5261 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
5262 {100, 100}))
5263 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
5264
5265 spyWindowDefaultDisplay->consumeMotionDown();
5266 windowDefaultDisplay->consumeMotionDown();
5267
5268 EXPECT_EQ(OK, mDispatcher->pilferPointers(spyWindowDefaultDisplay->getToken()));
5269
5270 // windowDefaultDisplay gets cancel
Siarhei Vishniakoud3061ab2023-12-18 20:41:08 -08005271 std::unique_ptr<MotionEvent> event = windowDefaultDisplay->consumeMotionEvent();
5272 ASSERT_NE(nullptr, event);
5273 EXPECT_EQ(AMOTION_EVENT_ACTION_CANCEL, event->getAction());
Hu Guo771a7692023-09-17 20:51:08 +08005274
5275 // The cancel event is sent to windowDefaultDisplay of the ADISPLAY_ID_DEFAULT display, so the
5276 // coordinates of the cancel are converted by windowDefaultDisplay's transform, the x and y
5277 // coordinates are both 100, otherwise if the cancel event is sent to windowSecondDisplay of
5278 // SECOND_DISPLAY_ID, the x and y coordinates are 200
Siarhei Vishniakoud3061ab2023-12-18 20:41:08 -08005279 EXPECT_EQ(100, event->getX(0));
5280 EXPECT_EQ(100, event->getY(0));
Hu Guo771a7692023-09-17 20:51:08 +08005281}
5282
5283/**
Prabir Pradhanc44ce4d2021-10-05 05:26:29 -07005284 * Ensure the correct coordinate spaces are used by InputDispatcher.
5285 *
5286 * InputDispatcher works in the display space, so its coordinate system is relative to the display
5287 * panel. Windows get events in the window space, and get raw coordinates in the logical display
5288 * space.
5289 */
5290class InputDispatcherDisplayProjectionTest : public InputDispatcherTest {
5291public:
5292 void SetUp() override {
5293 InputDispatcherTest::SetUp();
Prabir Pradhan33e3baa2022-12-06 20:30:22 +00005294 removeAllWindowsAndDisplays();
Prabir Pradhanc44ce4d2021-10-05 05:26:29 -07005295 }
5296
5297 void addDisplayInfo(int displayId, const ui::Transform& transform) {
5298 gui::DisplayInfo info;
5299 info.displayId = displayId;
5300 info.transform = transform;
5301 mDisplayInfos.push_back(std::move(info));
Patrick Williamsd828f302023-04-28 17:52:08 -05005302 mDispatcher->onWindowInfosChanged({mWindowInfos, mDisplayInfos, 0, 0});
Prabir Pradhanc44ce4d2021-10-05 05:26:29 -07005303 }
5304
5305 void addWindow(const sp<WindowInfoHandle>& windowHandle) {
5306 mWindowInfos.push_back(*windowHandle->getInfo());
Patrick Williamsd828f302023-04-28 17:52:08 -05005307 mDispatcher->onWindowInfosChanged({mWindowInfos, mDisplayInfos, 0, 0});
Prabir Pradhanc44ce4d2021-10-05 05:26:29 -07005308 }
5309
Prabir Pradhan33e3baa2022-12-06 20:30:22 +00005310 void removeAllWindowsAndDisplays() {
5311 mDisplayInfos.clear();
5312 mWindowInfos.clear();
5313 }
5314
Prabir Pradhanc44ce4d2021-10-05 05:26:29 -07005315 // Set up a test scenario where the display has a scaled projection and there are two windows
5316 // on the display.
5317 std::pair<sp<FakeWindowHandle>, sp<FakeWindowHandle>> setupScaledDisplayScenario() {
5318 // The display has a projection that has a scale factor of 2 and 4 in the x and y directions
5319 // respectively.
5320 ui::Transform displayTransform;
5321 displayTransform.set(2, 0, 0, 4);
5322 addDisplayInfo(ADISPLAY_ID_DEFAULT, displayTransform);
5323
5324 std::shared_ptr<FakeApplicationHandle> application =
5325 std::make_shared<FakeApplicationHandle>();
5326
5327 // Add two windows to the display. Their frames are represented in the display space.
5328 sp<FakeWindowHandle> firstWindow =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07005329 sp<FakeWindowHandle>::make(application, mDispatcher, "First Window",
5330 ADISPLAY_ID_DEFAULT);
Prabir Pradhanc44ce4d2021-10-05 05:26:29 -07005331 firstWindow->setFrame(Rect(0, 0, 100, 200), displayTransform);
5332 addWindow(firstWindow);
5333
5334 sp<FakeWindowHandle> secondWindow =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07005335 sp<FakeWindowHandle>::make(application, mDispatcher, "Second Window",
5336 ADISPLAY_ID_DEFAULT);
Prabir Pradhanc44ce4d2021-10-05 05:26:29 -07005337 secondWindow->setFrame(Rect(100, 200, 200, 400), displayTransform);
5338 addWindow(secondWindow);
5339 return {std::move(firstWindow), std::move(secondWindow)};
5340 }
5341
5342private:
5343 std::vector<gui::DisplayInfo> mDisplayInfos;
5344 std::vector<gui::WindowInfo> mWindowInfos;
5345};
5346
Prabir Pradhan33e3baa2022-12-06 20:30:22 +00005347TEST_F(InputDispatcherDisplayProjectionTest, HitTestCoordinateSpaceConsistency) {
Prabir Pradhanc44ce4d2021-10-05 05:26:29 -07005348 auto [firstWindow, secondWindow] = setupScaledDisplayScenario();
5349 // Send down to the first window. The point is represented in the display space. The point is
Prabir Pradhan33e3baa2022-12-06 20:30:22 +00005350 // selected so that if the hit test was performed with the point and the bounds being in
5351 // different coordinate spaces, the event would end up in the incorrect window.
Prabir Pradhan678438e2023-04-13 19:32:51 +00005352 mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_DOWN,
5353 AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
5354 {PointF{75, 55}}));
Prabir Pradhanc44ce4d2021-10-05 05:26:29 -07005355
5356 firstWindow->consumeMotionDown();
5357 secondWindow->assertNoEvents();
5358}
5359
5360// Ensure that when a MotionEvent is injected through the InputDispatcher::injectInputEvent() API,
5361// the event should be treated as being in the logical display space.
5362TEST_F(InputDispatcherDisplayProjectionTest, InjectionInLogicalDisplaySpace) {
5363 auto [firstWindow, secondWindow] = setupScaledDisplayScenario();
5364 // Send down to the first window. The point is represented in the logical display space. The
5365 // point is selected so that if the hit test was done in logical display space, then it would
5366 // end up in the incorrect window.
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07005367 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
Prabir Pradhanc44ce4d2021-10-05 05:26:29 -07005368 PointF{75 * 2, 55 * 4});
5369
5370 firstWindow->consumeMotionDown();
5371 secondWindow->assertNoEvents();
5372}
5373
Prabir Pradhandaa2f142021-12-10 09:30:08 +00005374// Ensure that when a MotionEvent that has a custom transform is injected, the post-transformed
5375// event should be treated as being in the logical display space.
5376TEST_F(InputDispatcherDisplayProjectionTest, InjectionWithTransformInLogicalDisplaySpace) {
5377 auto [firstWindow, secondWindow] = setupScaledDisplayScenario();
5378
5379 const std::array<float, 9> matrix = {1.1, 2.2, 3.3, 4.4, 5.5, 6.6, 0.0, 0.0, 1.0};
5380 ui::Transform injectedEventTransform;
5381 injectedEventTransform.set(matrix);
5382 const vec2 expectedPoint{75, 55}; // The injected point in the logical display space.
5383 const vec2 untransformedPoint = injectedEventTransform.inverse().transform(expectedPoint);
5384
5385 MotionEvent event = MotionEventBuilder(AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
5386 .displayId(ADISPLAY_ID_DEFAULT)
5387 .eventTime(systemTime(SYSTEM_TIME_MONOTONIC))
Siarhei Vishniakou6d73f832022-07-21 17:27:03 -07005388 .pointer(PointerBuilder(/*id=*/0, ToolType::FINGER)
Prabir Pradhandaa2f142021-12-10 09:30:08 +00005389 .x(untransformedPoint.x)
5390 .y(untransformedPoint.y))
5391 .build();
5392 event.transform(matrix);
5393
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07005394 injectMotionEvent(*mDispatcher, event, INJECT_EVENT_TIMEOUT,
Prabir Pradhandaa2f142021-12-10 09:30:08 +00005395 InputEventInjectionSync::WAIT_FOR_RESULT);
5396
5397 firstWindow->consumeMotionDown();
5398 secondWindow->assertNoEvents();
5399}
5400
Prabir Pradhanc44ce4d2021-10-05 05:26:29 -07005401TEST_F(InputDispatcherDisplayProjectionTest, WindowGetsEventsInCorrectCoordinateSpace) {
5402 auto [firstWindow, secondWindow] = setupScaledDisplayScenario();
5403
5404 // Send down to the second window.
Prabir Pradhan678438e2023-04-13 19:32:51 +00005405 mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_DOWN,
5406 AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
5407 {PointF{150, 220}}));
Prabir Pradhanc44ce4d2021-10-05 05:26:29 -07005408
5409 firstWindow->assertNoEvents();
Siarhei Vishniakoud3061ab2023-12-18 20:41:08 -08005410 std::unique_ptr<MotionEvent> event = secondWindow->consumeMotionEvent();
5411 ASSERT_NE(nullptr, event);
5412 EXPECT_EQ(AMOTION_EVENT_ACTION_DOWN, event->getAction());
Prabir Pradhanc44ce4d2021-10-05 05:26:29 -07005413
5414 // Ensure that the events from the "getRaw" API are in logical display coordinates.
Siarhei Vishniakoud3061ab2023-12-18 20:41:08 -08005415 EXPECT_EQ(300, event->getRawX(0));
5416 EXPECT_EQ(880, event->getRawY(0));
Prabir Pradhanc44ce4d2021-10-05 05:26:29 -07005417
5418 // Ensure that the x and y values are in the window's coordinate space.
5419 // The left-top of the second window is at (100, 200) in display space, which is (200, 800) in
5420 // the logical display space. This will be the origin of the window space.
Siarhei Vishniakoud3061ab2023-12-18 20:41:08 -08005421 EXPECT_EQ(100, event->getX(0));
5422 EXPECT_EQ(80, event->getY(0));
Prabir Pradhanc44ce4d2021-10-05 05:26:29 -07005423}
5424
Prabir Pradhan112b1ad2023-09-21 09:53:53 +00005425TEST_F(InputDispatcherDisplayProjectionTest, CancelMotionWithCorrectCoordinates) {
5426 auto [firstWindow, secondWindow] = setupScaledDisplayScenario();
5427 // The monitor will always receive events in the logical display's coordinate space, because
5428 // it does not have a window.
Prabir Pradhanfb549072023-10-05 19:17:36 +00005429 FakeMonitorReceiver monitor{*mDispatcher, "Monitor", ADISPLAY_ID_DEFAULT};
Prabir Pradhan112b1ad2023-09-21 09:53:53 +00005430
5431 // Send down to the first window.
5432 mDispatcher->notifyMotion(generateMotionArgs(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN,
5433 ADISPLAY_ID_DEFAULT, {PointF{50, 100}}));
5434 firstWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithCoords(100, 400)));
5435 monitor.consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithCoords(100, 400)));
5436
5437 // Second pointer goes down on second window.
5438 mDispatcher->notifyMotion(generateMotionArgs(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN,
5439 ADISPLAY_ID_DEFAULT,
5440 {PointF{50, 100}, PointF{150, 220}}));
5441 secondWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithCoords(100, 80)));
5442 const std::map<int32_t, PointF> expectedMonitorPointers{{0, PointF{100, 400}},
5443 {1, PointF{300, 880}}};
5444 monitor.consumeMotionEvent(
5445 AllOf(WithMotionAction(POINTER_1_DOWN), WithPointers(expectedMonitorPointers)));
5446
5447 mDispatcher->cancelCurrentTouch();
5448
5449 firstWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_CANCEL), WithCoords(100, 400)));
5450 secondWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_CANCEL), WithCoords(100, 80)));
5451 monitor.consumeMotionEvent(
5452 AllOf(WithMotionAction(ACTION_CANCEL), WithPointers(expectedMonitorPointers)));
5453}
5454
Prabir Pradhan1c29a092023-09-21 10:29:29 +00005455TEST_F(InputDispatcherDisplayProjectionTest, SynthesizeDownWithCorrectCoordinates) {
5456 auto [firstWindow, secondWindow] = setupScaledDisplayScenario();
5457
5458 // Send down to the first window.
5459 mDispatcher->notifyMotion(generateMotionArgs(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN,
5460 ADISPLAY_ID_DEFAULT, {PointF{50, 100}}));
5461 firstWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithCoords(100, 400)));
5462
5463 // The pointer is transferred to the second window, and the second window receives it in the
5464 // correct coordinate space.
Prabir Pradhan367f3432024-02-13 23:05:58 +00005465 mDispatcher->transferTouchGesture(firstWindow->getToken(), secondWindow->getToken());
Prabir Pradhan1c29a092023-09-21 10:29:29 +00005466 firstWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_CANCEL), WithCoords(100, 400)));
5467 secondWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithCoords(-100, -400)));
5468}
5469
Prabir Pradhan0dfcac72023-10-05 20:04:21 +00005470TEST_F(InputDispatcherDisplayProjectionTest, SynthesizeHoverEnterExitWithCorrectCoordinates) {
5471 auto [firstWindow, secondWindow] = setupScaledDisplayScenario();
5472
5473 // Send hover move to the second window, and ensure it shows up as hover enter.
5474 mDispatcher->notifyMotion(generateMotionArgs(ACTION_HOVER_MOVE, AINPUT_SOURCE_STYLUS,
5475 ADISPLAY_ID_DEFAULT, {PointF{150, 220}}));
5476 secondWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_HOVER_ENTER),
5477 WithCoords(100, 80), WithRawCoords(300, 880)));
5478
5479 // Touch down at the same location and ensure a hover exit is synthesized.
5480 mDispatcher->notifyMotion(generateMotionArgs(ACTION_DOWN, AINPUT_SOURCE_STYLUS,
5481 ADISPLAY_ID_DEFAULT, {PointF{150, 220}}));
5482 secondWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_HOVER_EXIT), WithCoords(100, 80),
5483 WithRawCoords(300, 880)));
5484 secondWindow->consumeMotionEvent(
5485 AllOf(WithMotionAction(ACTION_DOWN), WithCoords(100, 80), WithRawCoords(300, 880)));
5486 secondWindow->assertNoEvents();
5487 firstWindow->assertNoEvents();
5488}
5489
Prabir Pradhan453ae732023-10-13 14:30:14 +00005490// Same as above, but while the window is being mirrored.
5491TEST_F(InputDispatcherDisplayProjectionTest,
5492 SynthesizeHoverEnterExitWithCorrectCoordinatesWhenMirrored) {
5493 auto [firstWindow, secondWindow] = setupScaledDisplayScenario();
5494
5495 const std::array<float, 9> matrix = {1.1, 2.2, 3.3, 4.4, 5.5, 6.6, 0.0, 0.0, 1.0};
5496 ui::Transform secondDisplayTransform;
5497 secondDisplayTransform.set(matrix);
5498 addDisplayInfo(SECOND_DISPLAY_ID, secondDisplayTransform);
5499
5500 sp<FakeWindowHandle> secondWindowClone = secondWindow->clone(SECOND_DISPLAY_ID);
5501 secondWindowClone->setWindowTransform(1.1, 2.2, 3.3, 4.4);
5502 addWindow(secondWindowClone);
5503
5504 // Send hover move to the second window, and ensure it shows up as hover enter.
5505 mDispatcher->notifyMotion(generateMotionArgs(ACTION_HOVER_MOVE, AINPUT_SOURCE_STYLUS,
5506 ADISPLAY_ID_DEFAULT, {PointF{150, 220}}));
5507 secondWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_HOVER_ENTER),
5508 WithCoords(100, 80), WithRawCoords(300, 880)));
5509
5510 // Touch down at the same location and ensure a hover exit is synthesized for the correct
5511 // display.
5512 mDispatcher->notifyMotion(generateMotionArgs(ACTION_DOWN, AINPUT_SOURCE_STYLUS,
5513 ADISPLAY_ID_DEFAULT, {PointF{150, 220}}));
5514 secondWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_HOVER_EXIT), WithCoords(100, 80),
5515 WithRawCoords(300, 880)));
5516 secondWindow->consumeMotionEvent(
5517 AllOf(WithMotionAction(ACTION_DOWN), WithCoords(100, 80), WithRawCoords(300, 880)));
5518 secondWindow->assertNoEvents();
5519 firstWindow->assertNoEvents();
5520}
5521
Prabir Pradhan0dfcac72023-10-05 20:04:21 +00005522TEST_F(InputDispatcherDisplayProjectionTest, SynthesizeHoverCancelationWithCorrectCoordinates) {
5523 auto [firstWindow, secondWindow] = setupScaledDisplayScenario();
5524
5525 // Send hover enter to second window
5526 mDispatcher->notifyMotion(generateMotionArgs(ACTION_HOVER_ENTER, AINPUT_SOURCE_STYLUS,
5527 ADISPLAY_ID_DEFAULT, {PointF{150, 220}}));
5528 secondWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_HOVER_ENTER),
5529 WithCoords(100, 80), WithRawCoords(300, 880)));
5530
5531 mDispatcher->cancelCurrentTouch();
5532
5533 secondWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_HOVER_EXIT), WithCoords(100, 80),
5534 WithRawCoords(300, 880)));
5535 secondWindow->assertNoEvents();
5536 firstWindow->assertNoEvents();
5537}
5538
Prabir Pradhan453ae732023-10-13 14:30:14 +00005539// Same as above, but while the window is being mirrored.
Prabir Pradhan16463382023-10-12 23:03:19 +00005540TEST_F(InputDispatcherDisplayProjectionTest,
5541 SynthesizeHoverCancelationWithCorrectCoordinatesWhenMirrored) {
5542 auto [firstWindow, secondWindow] = setupScaledDisplayScenario();
5543
5544 const std::array<float, 9> matrix = {1.1, 2.2, 3.3, 4.4, 5.5, 6.6, 0.0, 0.0, 1.0};
5545 ui::Transform secondDisplayTransform;
5546 secondDisplayTransform.set(matrix);
5547 addDisplayInfo(SECOND_DISPLAY_ID, secondDisplayTransform);
5548
5549 sp<FakeWindowHandle> secondWindowClone = secondWindow->clone(SECOND_DISPLAY_ID);
5550 secondWindowClone->setWindowTransform(1.1, 2.2, 3.3, 4.4);
5551 addWindow(secondWindowClone);
5552
5553 // Send hover enter to second window
5554 mDispatcher->notifyMotion(generateMotionArgs(ACTION_HOVER_ENTER, AINPUT_SOURCE_STYLUS,
5555 ADISPLAY_ID_DEFAULT, {PointF{150, 220}}));
5556 secondWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_HOVER_ENTER),
5557 WithCoords(100, 80), WithRawCoords(300, 880),
5558 WithDisplayId(ADISPLAY_ID_DEFAULT)));
5559
5560 mDispatcher->cancelCurrentTouch();
5561
5562 // Ensure the cancelation happens with the correct displayId and the correct coordinates.
5563 secondWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_HOVER_EXIT), WithCoords(100, 80),
5564 WithRawCoords(300, 880),
5565 WithDisplayId(ADISPLAY_ID_DEFAULT)));
5566 secondWindow->assertNoEvents();
5567 firstWindow->assertNoEvents();
5568}
5569
Prabir Pradhan33e3baa2022-12-06 20:30:22 +00005570/** Ensure consistent behavior of InputDispatcher in all orientations. */
5571class InputDispatcherDisplayOrientationFixture
5572 : public InputDispatcherDisplayProjectionTest,
5573 public ::testing::WithParamInterface<ui::Rotation> {};
5574
5575// This test verifies the touchable region of a window for all rotations of the display by tapping
5576// in different locations on the display, specifically points close to the four corners of a
5577// window.
5578TEST_P(InputDispatcherDisplayOrientationFixture, HitTestInDifferentOrientations) {
5579 constexpr static int32_t displayWidth = 400;
5580 constexpr static int32_t displayHeight = 800;
5581
5582 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
5583
5584 const auto rotation = GetParam();
5585
5586 // Set up the display with the specified rotation.
5587 const bool isRotated = rotation == ui::ROTATION_90 || rotation == ui::ROTATION_270;
5588 const int32_t logicalDisplayWidth = isRotated ? displayHeight : displayWidth;
5589 const int32_t logicalDisplayHeight = isRotated ? displayWidth : displayHeight;
5590 const ui::Transform displayTransform(ui::Transform::toRotationFlags(rotation),
5591 logicalDisplayWidth, logicalDisplayHeight);
5592 addDisplayInfo(ADISPLAY_ID_DEFAULT, displayTransform);
5593
5594 // Create a window with its bounds determined in the logical display.
5595 const Rect frameInLogicalDisplay(100, 100, 200, 300);
5596 const Rect frameInDisplay = displayTransform.inverse().transform(frameInLogicalDisplay);
5597 sp<FakeWindowHandle> window =
5598 sp<FakeWindowHandle>::make(application, mDispatcher, "Window", ADISPLAY_ID_DEFAULT);
5599 window->setFrame(frameInDisplay, displayTransform);
5600 addWindow(window);
5601
5602 // The following points in logical display space should be inside the window.
5603 static const std::array<vec2, 4> insidePoints{
5604 {{100, 100}, {199.99, 100}, {100, 299.99}, {199.99, 299.99}}};
5605 for (const auto pointInsideWindow : insidePoints) {
5606 const vec2 p = displayTransform.inverse().transform(pointInsideWindow);
5607 const PointF pointInDisplaySpace{p.x, p.y};
Prabir Pradhan678438e2023-04-13 19:32:51 +00005608 mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_DOWN,
5609 AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
5610 {pointInDisplaySpace}));
Prabir Pradhan33e3baa2022-12-06 20:30:22 +00005611 window->consumeMotionDown();
5612
Prabir Pradhan678438e2023-04-13 19:32:51 +00005613 mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_UP,
5614 AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
5615 {pointInDisplaySpace}));
Prabir Pradhan33e3baa2022-12-06 20:30:22 +00005616 window->consumeMotionUp();
5617 }
5618
5619 // The following points in logical display space should be outside the window.
5620 static const std::array<vec2, 5> outsidePoints{
5621 {{200, 100}, {100, 300}, {200, 300}, {100, 99.99}, {99.99, 100}}};
5622 for (const auto pointOutsideWindow : outsidePoints) {
5623 const vec2 p = displayTransform.inverse().transform(pointOutsideWindow);
5624 const PointF pointInDisplaySpace{p.x, p.y};
Prabir Pradhan678438e2023-04-13 19:32:51 +00005625 mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_DOWN,
5626 AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
5627 {pointInDisplaySpace}));
Prabir Pradhan33e3baa2022-12-06 20:30:22 +00005628
Prabir Pradhan678438e2023-04-13 19:32:51 +00005629 mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_UP,
5630 AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
5631 {pointInDisplaySpace}));
Prabir Pradhan33e3baa2022-12-06 20:30:22 +00005632 }
5633 window->assertNoEvents();
5634}
5635
Linnan Li5e5645e2024-03-05 14:43:05 +00005636// This test verifies the occlusion detection for all rotations of the display by tapping
5637// in different locations on the display, specifically points close to the four corners of a
5638// window.
5639TEST_P(InputDispatcherDisplayOrientationFixture, BlockUntrustClickInDifferentOrientations) {
5640 constexpr static int32_t displayWidth = 400;
5641 constexpr static int32_t displayHeight = 800;
5642
5643 std::shared_ptr<FakeApplicationHandle> untrustedWindowApplication =
5644 std::make_shared<FakeApplicationHandle>();
5645 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
5646
5647 const auto rotation = GetParam();
5648
5649 // Set up the display with the specified rotation.
5650 const bool isRotated = rotation == ui::ROTATION_90 || rotation == ui::ROTATION_270;
5651 const int32_t logicalDisplayWidth = isRotated ? displayHeight : displayWidth;
5652 const int32_t logicalDisplayHeight = isRotated ? displayWidth : displayHeight;
5653 const ui::Transform displayTransform(ui::Transform::toRotationFlags(rotation),
5654 logicalDisplayWidth, logicalDisplayHeight);
5655 addDisplayInfo(ADISPLAY_ID_DEFAULT, displayTransform);
5656
5657 // Create a window that not trusted.
5658 const Rect untrustedWindowFrameInLogicalDisplay(100, 100, 200, 300);
5659
5660 const Rect untrustedWindowFrameInDisplay =
5661 displayTransform.inverse().transform(untrustedWindowFrameInLogicalDisplay);
5662
5663 sp<FakeWindowHandle> untrustedWindow =
5664 sp<FakeWindowHandle>::make(untrustedWindowApplication, mDispatcher, "UntrustedWindow",
5665 ADISPLAY_ID_DEFAULT);
5666 untrustedWindow->setFrame(untrustedWindowFrameInDisplay, displayTransform);
5667 untrustedWindow->setTrustedOverlay(false);
5668 untrustedWindow->setTouchOcclusionMode(TouchOcclusionMode::BLOCK_UNTRUSTED);
5669 untrustedWindow->setTouchable(false);
5670 untrustedWindow->setAlpha(1.0f);
5671 untrustedWindow->setOwnerInfo(gui::Pid{1}, gui::Uid{101});
5672 addWindow(untrustedWindow);
5673
5674 // Create a simple app window below the untrusted window.
5675 const Rect simpleAppWindowFrameInLogicalDisplay(0, 0, 300, 600);
5676 const Rect simpleAppWindowFrameInDisplay =
5677 displayTransform.inverse().transform(simpleAppWindowFrameInLogicalDisplay);
5678
5679 sp<FakeWindowHandle> simpleAppWindow =
5680 sp<FakeWindowHandle>::make(application, mDispatcher, "SimpleAppWindow",
5681 ADISPLAY_ID_DEFAULT);
5682 simpleAppWindow->setFrame(simpleAppWindowFrameInDisplay, displayTransform);
5683 simpleAppWindow->setOwnerInfo(gui::Pid{2}, gui::Uid{202});
5684 addWindow(simpleAppWindow);
5685
5686 // The following points in logical display space should be inside the untrusted window, so
5687 // the simple window could not receive events that coordinate is these point.
5688 static const std::array<vec2, 4> untrustedPoints{
5689 {{100, 100}, {199.99, 100}, {100, 299.99}, {199.99, 299.99}}};
5690
5691 for (const auto untrustedPoint : untrustedPoints) {
5692 const vec2 p = displayTransform.inverse().transform(untrustedPoint);
5693 const PointF pointInDisplaySpace{p.x, p.y};
5694 mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_DOWN,
5695 AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
5696 {pointInDisplaySpace}));
5697 mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_UP,
5698 AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
5699 {pointInDisplaySpace}));
5700 }
5701 untrustedWindow->assertNoEvents();
5702 simpleAppWindow->assertNoEvents();
5703 // The following points in logical display space should be outside the untrusted window, so
5704 // the simple window should receive events that coordinate is these point.
5705 static const std::array<vec2, 5> trustedPoints{
5706 {{200, 100}, {100, 300}, {200, 300}, {100, 99.99}, {99.99, 100}}};
5707 for (const auto trustedPoint : trustedPoints) {
5708 const vec2 p = displayTransform.inverse().transform(trustedPoint);
5709 const PointF pointInDisplaySpace{p.x, p.y};
5710 mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_DOWN,
5711 AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
5712 {pointInDisplaySpace}));
5713 simpleAppWindow->consumeMotionDown(ADISPLAY_ID_DEFAULT,
5714 AMOTION_EVENT_FLAG_WINDOW_IS_PARTIALLY_OBSCURED);
5715 mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_UP,
5716 AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
5717 {pointInDisplaySpace}));
5718 simpleAppWindow->consumeMotionUp(ADISPLAY_ID_DEFAULT,
5719 AMOTION_EVENT_FLAG_WINDOW_IS_PARTIALLY_OBSCURED);
5720 }
5721 untrustedWindow->assertNoEvents();
5722}
5723
Prabir Pradhan33e3baa2022-12-06 20:30:22 +00005724// Run the precision tests for all rotations.
5725INSTANTIATE_TEST_SUITE_P(InputDispatcherDisplayOrientationTests,
5726 InputDispatcherDisplayOrientationFixture,
5727 ::testing::Values(ui::ROTATION_0, ui::ROTATION_90, ui::ROTATION_180,
5728 ui::ROTATION_270),
5729 [](const testing::TestParamInfo<ui::Rotation>& testParamInfo) {
5730 return ftl::enum_string(testParamInfo.param);
5731 });
5732
Siarhei Vishniakou18050092021-09-01 13:32:49 -07005733using TransferFunction = std::function<bool(const std::unique_ptr<InputDispatcher>& dispatcher,
5734 sp<IBinder>, sp<IBinder>)>;
Siarhei Vishniakoud0c6bc82021-03-13 03:14:52 +00005735
5736class TransferTouchFixture : public InputDispatcherTest,
5737 public ::testing::WithParamInterface<TransferFunction> {};
5738
5739TEST_P(TransferTouchFixture, TransferTouch_OnePointer) {
Chris Yea209fde2020-07-22 13:54:51 -07005740 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
Svet Ganov5d3bc372020-01-26 23:11:07 -08005741
5742 // Create a couple of windows
Siarhei Vishniakou870ecec2020-12-09 08:07:46 -10005743 sp<FakeWindowHandle> firstWindow =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07005744 sp<FakeWindowHandle>::make(application, mDispatcher, "First Window",
5745 ADISPLAY_ID_DEFAULT);
Arthur Hungc539dbb2022-12-08 07:45:36 +00005746 firstWindow->setDupTouchToWallpaper(true);
Siarhei Vishniakou870ecec2020-12-09 08:07:46 -10005747 sp<FakeWindowHandle> secondWindow =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07005748 sp<FakeWindowHandle>::make(application, mDispatcher, "Second Window",
5749 ADISPLAY_ID_DEFAULT);
Arthur Hungc539dbb2022-12-08 07:45:36 +00005750 sp<FakeWindowHandle> wallpaper =
5751 sp<FakeWindowHandle>::make(application, mDispatcher, "Wallpaper", ADISPLAY_ID_DEFAULT);
5752 wallpaper->setIsWallpaper(true);
Prabir Pradhan65455c72024-02-13 21:46:41 +00005753 // Add the windows to the dispatcher, and ensure the first window is focused
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07005754 mDispatcher->onWindowInfosChanged(
5755 {{*firstWindow->getInfo(), *secondWindow->getInfo(), *wallpaper->getInfo()}, {}, 0, 0});
Prabir Pradhan65455c72024-02-13 21:46:41 +00005756 setFocusedWindow(firstWindow);
5757 firstWindow->consumeFocusEvent(true);
Svet Ganov5d3bc372020-01-26 23:11:07 -08005758
5759 // Send down to the first window
Prabir Pradhan678438e2023-04-13 19:32:51 +00005760 mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_DOWN,
5761 AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT));
Arthur Hungc539dbb2022-12-08 07:45:36 +00005762
Svet Ganov5d3bc372020-01-26 23:11:07 -08005763 // Only the first window should get the down event
5764 firstWindow->consumeMotionDown();
5765 secondWindow->assertNoEvents();
Arthur Hungc539dbb2022-12-08 07:45:36 +00005766 wallpaper->consumeMotionDown(ADISPLAY_ID_DEFAULT, expectedWallpaperFlags);
Prabir Pradhan65455c72024-02-13 21:46:41 +00005767 // Dispatcher reports pointer down outside focus for the wallpaper
5768 mFakePolicy->assertOnPointerDownEquals(wallpaper->getToken());
Svet Ganov5d3bc372020-01-26 23:11:07 -08005769
Siarhei Vishniakoud0c6bc82021-03-13 03:14:52 +00005770 // Transfer touch to the second window
5771 TransferFunction f = GetParam();
5772 const bool success = f(mDispatcher, firstWindow->getToken(), secondWindow->getToken());
5773 ASSERT_TRUE(success);
Svet Ganov5d3bc372020-01-26 23:11:07 -08005774 // The first window gets cancel and the second gets down
5775 firstWindow->consumeMotionCancel();
Prabir Pradhan65455c72024-02-13 21:46:41 +00005776 secondWindow->consumeMotionDown(ADISPLAY_ID_DEFAULT, AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
Arthur Hungc539dbb2022-12-08 07:45:36 +00005777 wallpaper->consumeMotionCancel(ADISPLAY_ID_DEFAULT, expectedWallpaperFlags);
Prabir Pradhan65455c72024-02-13 21:46:41 +00005778 // There should not be any changes to the focused window when transferring touch
5779 ASSERT_NO_FATAL_FAILURE(mFakePolicy->assertOnPointerDownWasNotCalled());
Svet Ganov5d3bc372020-01-26 23:11:07 -08005780
5781 // Send up event to the second window
Prabir Pradhan678438e2023-04-13 19:32:51 +00005782 mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN,
5783 ADISPLAY_ID_DEFAULT));
Prabir Pradhan65455c72024-02-13 21:46:41 +00005784 // The first window gets no events and the second gets up
Svet Ganov5d3bc372020-01-26 23:11:07 -08005785 firstWindow->assertNoEvents();
Prabir Pradhan65455c72024-02-13 21:46:41 +00005786 secondWindow->consumeMotionUp(ADISPLAY_ID_DEFAULT, AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
Arthur Hungc539dbb2022-12-08 07:45:36 +00005787 wallpaper->assertNoEvents();
Svet Ganov5d3bc372020-01-26 23:11:07 -08005788}
5789
Siarhei Vishniakou7ae7afd2022-03-31 15:26:13 -07005790/**
Prabir Pradhan367f3432024-02-13 23:05:58 +00005791 * When 'transferTouchGesture' API is invoked, dispatcher needs to find the "best" window to take
5792 * touch from. When we have spy windows, there are several windows to choose from: either spy, or
5793 * the 'real' (non-spy) window. Always prefer the 'real' window because that's what would be most
Siarhei Vishniakou7ae7afd2022-03-31 15:26:13 -07005794 * natural to the user.
5795 * In this test, we are sending a pointer to both spy window and first window. We then try to
5796 * transfer touch to the second window. The dispatcher should identify the first window as the
5797 * one that should lose the gesture, and therefore the action should be to move the gesture from
5798 * the first window to the second.
Prabir Pradhan367f3432024-02-13 23:05:58 +00005799 * The main goal here is to test the behaviour of 'transferTouchGesture' API, but it's still valid
5800 * to test the other API, as well.
Siarhei Vishniakou7ae7afd2022-03-31 15:26:13 -07005801 */
5802TEST_P(TransferTouchFixture, TransferTouch_MultipleWindowsWithSpy) {
5803 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
5804
5805 // Create a couple of windows + a spy window
5806 sp<FakeWindowHandle> spyWindow =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07005807 sp<FakeWindowHandle>::make(application, mDispatcher, "Spy", ADISPLAY_ID_DEFAULT);
Siarhei Vishniakou7ae7afd2022-03-31 15:26:13 -07005808 spyWindow->setTrustedOverlay(true);
5809 spyWindow->setSpy(true);
5810 sp<FakeWindowHandle> firstWindow =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07005811 sp<FakeWindowHandle>::make(application, mDispatcher, "First", ADISPLAY_ID_DEFAULT);
Siarhei Vishniakou7ae7afd2022-03-31 15:26:13 -07005812 sp<FakeWindowHandle> secondWindow =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07005813 sp<FakeWindowHandle>::make(application, mDispatcher, "Second", ADISPLAY_ID_DEFAULT);
Siarhei Vishniakou7ae7afd2022-03-31 15:26:13 -07005814
5815 // Add the windows to the dispatcher
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07005816 mDispatcher->onWindowInfosChanged(
5817 {{*spyWindow->getInfo(), *firstWindow->getInfo(), *secondWindow->getInfo()}, {}, 0, 0});
Siarhei Vishniakou7ae7afd2022-03-31 15:26:13 -07005818
5819 // Send down to the first window
Prabir Pradhan678438e2023-04-13 19:32:51 +00005820 mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_DOWN,
5821 AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT));
Siarhei Vishniakou7ae7afd2022-03-31 15:26:13 -07005822 // Only the first window and spy should get the down event
5823 spyWindow->consumeMotionDown();
5824 firstWindow->consumeMotionDown();
5825
5826 // Transfer touch to the second window. Non-spy window should be preferred over the spy window
Prabir Pradhan367f3432024-02-13 23:05:58 +00005827 // if f === 'transferTouchGesture'.
Siarhei Vishniakou7ae7afd2022-03-31 15:26:13 -07005828 TransferFunction f = GetParam();
5829 const bool success = f(mDispatcher, firstWindow->getToken(), secondWindow->getToken());
5830 ASSERT_TRUE(success);
5831 // The first window gets cancel and the second gets down
5832 firstWindow->consumeMotionCancel();
Prabir Pradhan65455c72024-02-13 21:46:41 +00005833 secondWindow->consumeMotionDown(ADISPLAY_ID_DEFAULT, AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
Siarhei Vishniakou7ae7afd2022-03-31 15:26:13 -07005834
5835 // Send up event to the second window
Prabir Pradhan678438e2023-04-13 19:32:51 +00005836 mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN,
5837 ADISPLAY_ID_DEFAULT));
Siarhei Vishniakou7ae7afd2022-03-31 15:26:13 -07005838 // The first window gets no events and the second+spy get up
5839 firstWindow->assertNoEvents();
5840 spyWindow->consumeMotionUp();
Prabir Pradhan65455c72024-02-13 21:46:41 +00005841 secondWindow->consumeMotionUp(ADISPLAY_ID_DEFAULT, AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
Siarhei Vishniakou7ae7afd2022-03-31 15:26:13 -07005842}
5843
Siarhei Vishniakoud0c6bc82021-03-13 03:14:52 +00005844TEST_P(TransferTouchFixture, TransferTouch_TwoPointersNonSplitTouch) {
Chris Yea209fde2020-07-22 13:54:51 -07005845 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
Svet Ganov5d3bc372020-01-26 23:11:07 -08005846
5847 PointF touchPoint = {10, 10};
5848
5849 // Create a couple of windows
Siarhei Vishniakou870ecec2020-12-09 08:07:46 -10005850 sp<FakeWindowHandle> firstWindow =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07005851 sp<FakeWindowHandle>::make(application, mDispatcher, "First Window",
5852 ADISPLAY_ID_DEFAULT);
Prabir Pradhan76bdecb2022-01-31 11:14:15 -08005853 firstWindow->setPreventSplitting(true);
Siarhei Vishniakou870ecec2020-12-09 08:07:46 -10005854 sp<FakeWindowHandle> secondWindow =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07005855 sp<FakeWindowHandle>::make(application, mDispatcher, "Second Window",
5856 ADISPLAY_ID_DEFAULT);
Prabir Pradhan76bdecb2022-01-31 11:14:15 -08005857 secondWindow->setPreventSplitting(true);
Svet Ganov5d3bc372020-01-26 23:11:07 -08005858
5859 // Add the windows to the dispatcher
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07005860 mDispatcher->onWindowInfosChanged(
5861 {{*firstWindow->getInfo(), *secondWindow->getInfo()}, {}, 0, 0});
Svet Ganov5d3bc372020-01-26 23:11:07 -08005862
5863 // Send down to the first window
Prabir Pradhan678438e2023-04-13 19:32:51 +00005864 mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_DOWN,
5865 AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
5866 {touchPoint}));
Svet Ganov5d3bc372020-01-26 23:11:07 -08005867 // Only the first window should get the down event
5868 firstWindow->consumeMotionDown();
5869 secondWindow->assertNoEvents();
5870
5871 // Send pointer down to the first window
Prabir Pradhan678438e2023-04-13 19:32:51 +00005872 mDispatcher->notifyMotion(generateMotionArgs(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN,
5873 ADISPLAY_ID_DEFAULT, {touchPoint, touchPoint}));
Svet Ganov5d3bc372020-01-26 23:11:07 -08005874 // Only the first window should get the pointer down event
5875 firstWindow->consumeMotionPointerDown(1);
5876 secondWindow->assertNoEvents();
5877
5878 // Transfer touch focus to the second window
Siarhei Vishniakoud0c6bc82021-03-13 03:14:52 +00005879 TransferFunction f = GetParam();
5880 bool success = f(mDispatcher, firstWindow->getToken(), secondWindow->getToken());
5881 ASSERT_TRUE(success);
Svet Ganov5d3bc372020-01-26 23:11:07 -08005882 // The first window gets cancel and the second gets down and pointer down
5883 firstWindow->consumeMotionCancel();
Prabir Pradhan65455c72024-02-13 21:46:41 +00005884 secondWindow->consumeMotionDown(ADISPLAY_ID_DEFAULT, AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
5885 secondWindow->consumeMotionPointerDown(1, ADISPLAY_ID_DEFAULT,
5886 AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
Svet Ganov5d3bc372020-01-26 23:11:07 -08005887
5888 // Send pointer up to the second window
Prabir Pradhan678438e2023-04-13 19:32:51 +00005889 mDispatcher->notifyMotion(generateMotionArgs(POINTER_1_UP, AINPUT_SOURCE_TOUCHSCREEN,
5890 ADISPLAY_ID_DEFAULT, {touchPoint, touchPoint}));
Svet Ganov5d3bc372020-01-26 23:11:07 -08005891 // The first window gets nothing and the second gets pointer up
5892 firstWindow->assertNoEvents();
Prabir Pradhan65455c72024-02-13 21:46:41 +00005893 secondWindow->consumeMotionPointerUp(1, ADISPLAY_ID_DEFAULT,
5894 AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
Svet Ganov5d3bc372020-01-26 23:11:07 -08005895
5896 // Send up event to the second window
Prabir Pradhan678438e2023-04-13 19:32:51 +00005897 mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN,
5898 ADISPLAY_ID_DEFAULT));
Svet Ganov5d3bc372020-01-26 23:11:07 -08005899 // The first window gets nothing and the second gets up
5900 firstWindow->assertNoEvents();
Prabir Pradhan65455c72024-02-13 21:46:41 +00005901 secondWindow->consumeMotionUp(ADISPLAY_ID_DEFAULT, AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
Svet Ganov5d3bc372020-01-26 23:11:07 -08005902}
5903
Arthur Hungc539dbb2022-12-08 07:45:36 +00005904TEST_P(TransferTouchFixture, TransferTouch_MultipleWallpapers) {
5905 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
5906
5907 // Create a couple of windows
5908 sp<FakeWindowHandle> firstWindow =
5909 sp<FakeWindowHandle>::make(application, mDispatcher, "First Window",
5910 ADISPLAY_ID_DEFAULT);
5911 firstWindow->setDupTouchToWallpaper(true);
5912 sp<FakeWindowHandle> secondWindow =
5913 sp<FakeWindowHandle>::make(application, mDispatcher, "Second Window",
5914 ADISPLAY_ID_DEFAULT);
5915 secondWindow->setDupTouchToWallpaper(true);
5916
5917 sp<FakeWindowHandle> wallpaper1 =
5918 sp<FakeWindowHandle>::make(application, mDispatcher, "Wallpaper1", ADISPLAY_ID_DEFAULT);
5919 wallpaper1->setIsWallpaper(true);
5920
5921 sp<FakeWindowHandle> wallpaper2 =
5922 sp<FakeWindowHandle>::make(application, mDispatcher, "Wallpaper2", ADISPLAY_ID_DEFAULT);
5923 wallpaper2->setIsWallpaper(true);
5924 // Add the windows to the dispatcher
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07005925 mDispatcher->onWindowInfosChanged({{*firstWindow->getInfo(), *wallpaper1->getInfo(),
5926 *secondWindow->getInfo(), *wallpaper2->getInfo()},
5927 {},
5928 0,
5929 0});
Arthur Hungc539dbb2022-12-08 07:45:36 +00005930
5931 // Send down to the first window
Prabir Pradhan678438e2023-04-13 19:32:51 +00005932 mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_DOWN,
5933 AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT));
Arthur Hungc539dbb2022-12-08 07:45:36 +00005934
5935 // Only the first window should get the down event
5936 firstWindow->consumeMotionDown();
5937 secondWindow->assertNoEvents();
5938 wallpaper1->consumeMotionDown(ADISPLAY_ID_DEFAULT, expectedWallpaperFlags);
5939 wallpaper2->assertNoEvents();
5940
5941 // Transfer touch focus to the second window
5942 TransferFunction f = GetParam();
5943 bool success = f(mDispatcher, firstWindow->getToken(), secondWindow->getToken());
5944 ASSERT_TRUE(success);
5945
5946 // The first window gets cancel and the second gets down
5947 firstWindow->consumeMotionCancel();
Prabir Pradhan65455c72024-02-13 21:46:41 +00005948 secondWindow->consumeMotionDown(ADISPLAY_ID_DEFAULT, AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
Arthur Hungc539dbb2022-12-08 07:45:36 +00005949 wallpaper1->consumeMotionCancel(ADISPLAY_ID_DEFAULT, expectedWallpaperFlags);
Prabir Pradhan65455c72024-02-13 21:46:41 +00005950 wallpaper2->consumeMotionDown(ADISPLAY_ID_DEFAULT,
5951 expectedWallpaperFlags | AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
Arthur Hungc539dbb2022-12-08 07:45:36 +00005952
5953 // Send up event to the second window
Prabir Pradhan678438e2023-04-13 19:32:51 +00005954 mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN,
5955 ADISPLAY_ID_DEFAULT));
Arthur Hungc539dbb2022-12-08 07:45:36 +00005956 // The first window gets no events and the second gets up
5957 firstWindow->assertNoEvents();
Prabir Pradhan65455c72024-02-13 21:46:41 +00005958 secondWindow->consumeMotionUp(ADISPLAY_ID_DEFAULT, AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
Arthur Hungc539dbb2022-12-08 07:45:36 +00005959 wallpaper1->assertNoEvents();
Prabir Pradhan65455c72024-02-13 21:46:41 +00005960 wallpaper2->consumeMotionUp(ADISPLAY_ID_DEFAULT,
5961 expectedWallpaperFlags | AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
Arthur Hungc539dbb2022-12-08 07:45:36 +00005962}
5963
Siarhei Vishniakoud0c6bc82021-03-13 03:14:52 +00005964// For the cases of single pointer touch and two pointers non-split touch, the api's
Prabir Pradhan367f3432024-02-13 23:05:58 +00005965// 'transferTouchGesture' and 'transferTouchOnDisplay' are equivalent in behaviour. They only differ
Siarhei Vishniakoud0c6bc82021-03-13 03:14:52 +00005966// for the case where there are multiple pointers split across several windows.
Prabir Pradhan367f3432024-02-13 23:05:58 +00005967INSTANTIATE_TEST_SUITE_P(
5968 InputDispatcherTransferFunctionTests, TransferTouchFixture,
5969 ::testing::Values(
5970 [&](const std::unique_ptr<InputDispatcher>& dispatcher, sp<IBinder> /*ignored*/,
5971 sp<IBinder> destChannelToken) {
5972 return dispatcher->transferTouchOnDisplay(destChannelToken,
5973 ADISPLAY_ID_DEFAULT);
5974 },
5975 [&](const std::unique_ptr<InputDispatcher>& dispatcher, sp<IBinder> from,
5976 sp<IBinder> to) {
5977 return dispatcher->transferTouchGesture(from, to,
5978 /*isDragAndDrop=*/false);
5979 }));
Siarhei Vishniakoud0c6bc82021-03-13 03:14:52 +00005980
Prabir Pradhan367f3432024-02-13 23:05:58 +00005981TEST_F(InputDispatcherTest, TransferTouch_TwoPointersSplitTouch) {
Chris Yea209fde2020-07-22 13:54:51 -07005982 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
Svet Ganov5d3bc372020-01-26 23:11:07 -08005983
Siarhei Vishniakou870ecec2020-12-09 08:07:46 -10005984 sp<FakeWindowHandle> firstWindow =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07005985 sp<FakeWindowHandle>::make(application, mDispatcher, "First Window",
5986 ADISPLAY_ID_DEFAULT);
Svet Ganov5d3bc372020-01-26 23:11:07 -08005987 firstWindow->setFrame(Rect(0, 0, 600, 400));
Svet Ganov5d3bc372020-01-26 23:11:07 -08005988
Siarhei Vishniakou870ecec2020-12-09 08:07:46 -10005989 sp<FakeWindowHandle> secondWindow =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07005990 sp<FakeWindowHandle>::make(application, mDispatcher, "Second Window",
5991 ADISPLAY_ID_DEFAULT);
Svet Ganov5d3bc372020-01-26 23:11:07 -08005992 secondWindow->setFrame(Rect(0, 400, 600, 800));
Svet Ganov5d3bc372020-01-26 23:11:07 -08005993
5994 // Add the windows to the dispatcher
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07005995 mDispatcher->onWindowInfosChanged(
5996 {{*firstWindow->getInfo(), *secondWindow->getInfo()}, {}, 0, 0});
Svet Ganov5d3bc372020-01-26 23:11:07 -08005997
5998 PointF pointInFirst = {300, 200};
5999 PointF pointInSecond = {300, 600};
6000
6001 // Send down to the first window
Prabir Pradhan678438e2023-04-13 19:32:51 +00006002 mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_DOWN,
6003 AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
6004 {pointInFirst}));
Svet Ganov5d3bc372020-01-26 23:11:07 -08006005 // Only the first window should get the down event
6006 firstWindow->consumeMotionDown();
6007 secondWindow->assertNoEvents();
6008
6009 // Send down to the second window
Prabir Pradhan678438e2023-04-13 19:32:51 +00006010 mDispatcher->notifyMotion(generateMotionArgs(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN,
6011 ADISPLAY_ID_DEFAULT,
6012 {pointInFirst, pointInSecond}));
Svet Ganov5d3bc372020-01-26 23:11:07 -08006013 // The first window gets a move and the second a down
6014 firstWindow->consumeMotionMove();
6015 secondWindow->consumeMotionDown();
6016
Prabir Pradhan367f3432024-02-13 23:05:58 +00006017 // Transfer touch to the second window
6018 mDispatcher->transferTouchGesture(firstWindow->getToken(), secondWindow->getToken());
Svet Ganov5d3bc372020-01-26 23:11:07 -08006019 // The first window gets cancel and the new gets pointer down (it already saw down)
6020 firstWindow->consumeMotionCancel();
Prabir Pradhan65455c72024-02-13 21:46:41 +00006021 secondWindow->consumeMotionPointerDown(1, ADISPLAY_ID_DEFAULT,
6022 AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
Svet Ganov5d3bc372020-01-26 23:11:07 -08006023
6024 // Send pointer up to the second window
Prabir Pradhan678438e2023-04-13 19:32:51 +00006025 mDispatcher->notifyMotion(generateMotionArgs(POINTER_1_UP, AINPUT_SOURCE_TOUCHSCREEN,
6026 ADISPLAY_ID_DEFAULT,
6027 {pointInFirst, pointInSecond}));
Svet Ganov5d3bc372020-01-26 23:11:07 -08006028 // The first window gets nothing and the second gets pointer up
6029 firstWindow->assertNoEvents();
Prabir Pradhan65455c72024-02-13 21:46:41 +00006030 secondWindow->consumeMotionPointerUp(1, ADISPLAY_ID_DEFAULT,
6031 AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
Svet Ganov5d3bc372020-01-26 23:11:07 -08006032
6033 // Send up event to the second window
Prabir Pradhan678438e2023-04-13 19:32:51 +00006034 mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN,
6035 ADISPLAY_ID_DEFAULT));
Svet Ganov5d3bc372020-01-26 23:11:07 -08006036 // The first window gets nothing and the second gets up
6037 firstWindow->assertNoEvents();
Prabir Pradhan65455c72024-02-13 21:46:41 +00006038 secondWindow->consumeMotionUp(ADISPLAY_ID_DEFAULT, AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
Svet Ganov5d3bc372020-01-26 23:11:07 -08006039}
6040
Prabir Pradhan367f3432024-02-13 23:05:58 +00006041// Same as TransferTouch_TwoPointersSplitTouch, but using 'transferTouchOnDisplay' api.
6042// Unlike 'transferTouchGesture', calling 'transferTouchOnDisplay' when there are two windows
6043// receiving touch is not supported, so the touch should continue on those windows and the
6044// transferred-to window should get nothing.
6045TEST_F(InputDispatcherTest, TransferTouchOnDisplay_TwoPointersSplitTouch) {
Siarhei Vishniakoud0c6bc82021-03-13 03:14:52 +00006046 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
6047
Siarhei Vishniakoud0c6bc82021-03-13 03:14:52 +00006048 sp<FakeWindowHandle> firstWindow =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07006049 sp<FakeWindowHandle>::make(application, mDispatcher, "First Window",
6050 ADISPLAY_ID_DEFAULT);
Siarhei Vishniakoud0c6bc82021-03-13 03:14:52 +00006051 firstWindow->setFrame(Rect(0, 0, 600, 400));
Siarhei Vishniakoud0c6bc82021-03-13 03:14:52 +00006052
Siarhei Vishniakoud0c6bc82021-03-13 03:14:52 +00006053 sp<FakeWindowHandle> secondWindow =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07006054 sp<FakeWindowHandle>::make(application, mDispatcher, "Second Window",
6055 ADISPLAY_ID_DEFAULT);
Siarhei Vishniakoud0c6bc82021-03-13 03:14:52 +00006056 secondWindow->setFrame(Rect(0, 400, 600, 800));
Siarhei Vishniakoud0c6bc82021-03-13 03:14:52 +00006057
6058 // Add the windows to the dispatcher
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07006059 mDispatcher->onWindowInfosChanged(
6060 {{*firstWindow->getInfo(), *secondWindow->getInfo()}, {}, 0, 0});
Siarhei Vishniakoud0c6bc82021-03-13 03:14:52 +00006061
6062 PointF pointInFirst = {300, 200};
6063 PointF pointInSecond = {300, 600};
6064
6065 // Send down to the first window
Prabir Pradhan678438e2023-04-13 19:32:51 +00006066 mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_DOWN,
6067 AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
6068 {pointInFirst}));
Siarhei Vishniakoud0c6bc82021-03-13 03:14:52 +00006069 // Only the first window should get the down event
6070 firstWindow->consumeMotionDown();
6071 secondWindow->assertNoEvents();
6072
6073 // Send down to the second window
Prabir Pradhan678438e2023-04-13 19:32:51 +00006074 mDispatcher->notifyMotion(generateMotionArgs(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN,
6075 ADISPLAY_ID_DEFAULT,
6076 {pointInFirst, pointInSecond}));
Siarhei Vishniakoud0c6bc82021-03-13 03:14:52 +00006077 // The first window gets a move and the second a down
6078 firstWindow->consumeMotionMove();
6079 secondWindow->consumeMotionDown();
6080
6081 // Transfer touch focus to the second window
Siarhei Vishniakou7ae7afd2022-03-31 15:26:13 -07006082 const bool transferred =
Prabir Pradhan367f3432024-02-13 23:05:58 +00006083 mDispatcher->transferTouchOnDisplay(secondWindow->getToken(), ADISPLAY_ID_DEFAULT);
6084 // The 'transferTouchOnDisplay' call should not succeed, because there are 2 touched windows
Siarhei Vishniakoud0c6bc82021-03-13 03:14:52 +00006085 ASSERT_FALSE(transferred);
6086 firstWindow->assertNoEvents();
6087 secondWindow->assertNoEvents();
6088
6089 // The rest of the dispatch should proceed as normal
6090 // Send pointer up to the second window
Prabir Pradhan678438e2023-04-13 19:32:51 +00006091 mDispatcher->notifyMotion(generateMotionArgs(POINTER_1_UP, AINPUT_SOURCE_TOUCHSCREEN,
6092 ADISPLAY_ID_DEFAULT,
6093 {pointInFirst, pointInSecond}));
Siarhei Vishniakoud0c6bc82021-03-13 03:14:52 +00006094 // The first window gets MOVE and the second gets pointer up
6095 firstWindow->consumeMotionMove();
6096 secondWindow->consumeMotionUp();
6097
6098 // Send up event to the first window
Prabir Pradhan678438e2023-04-13 19:32:51 +00006099 mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN,
6100 ADISPLAY_ID_DEFAULT));
Siarhei Vishniakoud0c6bc82021-03-13 03:14:52 +00006101 // The first window gets nothing and the second gets up
6102 firstWindow->consumeMotionUp();
6103 secondWindow->assertNoEvents();
6104}
6105
Arthur Hungabbb9d82021-09-01 14:52:30 +00006106// This case will create two windows and one mirrored window on the default display and mirror
Prabir Pradhan367f3432024-02-13 23:05:58 +00006107// two windows on the second display. It will test if 'transferTouchGesture' works fine if we put
Arthur Hungabbb9d82021-09-01 14:52:30 +00006108// the windows info of second display before default display.
Prabir Pradhan367f3432024-02-13 23:05:58 +00006109TEST_F(InputDispatcherTest, TransferTouch_CloneSurface) {
Arthur Hungabbb9d82021-09-01 14:52:30 +00006110 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
6111 sp<FakeWindowHandle> firstWindowInPrimary =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07006112 sp<FakeWindowHandle>::make(application, mDispatcher, "D_1_W1", ADISPLAY_ID_DEFAULT);
Arthur Hungabbb9d82021-09-01 14:52:30 +00006113 firstWindowInPrimary->setFrame(Rect(0, 0, 100, 100));
Arthur Hungabbb9d82021-09-01 14:52:30 +00006114 sp<FakeWindowHandle> secondWindowInPrimary =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07006115 sp<FakeWindowHandle>::make(application, mDispatcher, "D_1_W2", ADISPLAY_ID_DEFAULT);
Arthur Hungabbb9d82021-09-01 14:52:30 +00006116 secondWindowInPrimary->setFrame(Rect(100, 0, 200, 100));
Arthur Hungabbb9d82021-09-01 14:52:30 +00006117
Siarhei Vishniakouadb9fc92023-05-26 10:46:09 -07006118 sp<FakeWindowHandle> mirrorWindowInPrimary = firstWindowInPrimary->clone(ADISPLAY_ID_DEFAULT);
Arthur Hungabbb9d82021-09-01 14:52:30 +00006119 mirrorWindowInPrimary->setFrame(Rect(0, 100, 100, 200));
Arthur Hungabbb9d82021-09-01 14:52:30 +00006120
Siarhei Vishniakouadb9fc92023-05-26 10:46:09 -07006121 sp<FakeWindowHandle> firstWindowInSecondary = firstWindowInPrimary->clone(SECOND_DISPLAY_ID);
Arthur Hungabbb9d82021-09-01 14:52:30 +00006122 firstWindowInSecondary->setFrame(Rect(0, 0, 100, 100));
Arthur Hungabbb9d82021-09-01 14:52:30 +00006123
Siarhei Vishniakouadb9fc92023-05-26 10:46:09 -07006124 sp<FakeWindowHandle> secondWindowInSecondary = secondWindowInPrimary->clone(SECOND_DISPLAY_ID);
Arthur Hungabbb9d82021-09-01 14:52:30 +00006125 secondWindowInPrimary->setFrame(Rect(100, 0, 200, 100));
Arthur Hungabbb9d82021-09-01 14:52:30 +00006126
6127 // Update window info, let it find window handle of second display first.
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07006128 mDispatcher->onWindowInfosChanged(
6129 {{*firstWindowInSecondary->getInfo(), *secondWindowInSecondary->getInfo(),
6130 *mirrorWindowInPrimary->getInfo(), *firstWindowInPrimary->getInfo(),
6131 *secondWindowInPrimary->getInfo()},
6132 {},
6133 0,
6134 0});
Arthur Hungabbb9d82021-09-01 14:52:30 +00006135
6136 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07006137 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
Arthur Hungabbb9d82021-09-01 14:52:30 +00006138 {50, 50}))
6139 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
6140
6141 // Window should receive motion event.
6142 firstWindowInPrimary->consumeMotionDown(ADISPLAY_ID_DEFAULT);
6143
Prabir Pradhan367f3432024-02-13 23:05:58 +00006144 // Transfer touch
6145 ASSERT_TRUE(mDispatcher->transferTouchGesture(firstWindowInPrimary->getToken(),
6146 secondWindowInPrimary->getToken()));
Arthur Hungabbb9d82021-09-01 14:52:30 +00006147 // The first window gets cancel.
6148 firstWindowInPrimary->consumeMotionCancel();
Prabir Pradhan65455c72024-02-13 21:46:41 +00006149 secondWindowInPrimary->consumeMotionDown(ADISPLAY_ID_DEFAULT,
6150 AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
Arthur Hungabbb9d82021-09-01 14:52:30 +00006151
6152 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07006153 injectMotionEvent(*mDispatcher, AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN,
Arthur Hungabbb9d82021-09-01 14:52:30 +00006154 ADISPLAY_ID_DEFAULT, {150, 50}))
6155 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
6156 firstWindowInPrimary->assertNoEvents();
Prabir Pradhan65455c72024-02-13 21:46:41 +00006157 secondWindowInPrimary->consumeMotionMove(ADISPLAY_ID_DEFAULT,
6158 AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
Arthur Hungabbb9d82021-09-01 14:52:30 +00006159
6160 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07006161 injectMotionUp(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
Arthur Hungabbb9d82021-09-01 14:52:30 +00006162 {150, 50}))
6163 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
6164 firstWindowInPrimary->assertNoEvents();
Prabir Pradhan65455c72024-02-13 21:46:41 +00006165 secondWindowInPrimary->consumeMotionUp(ADISPLAY_ID_DEFAULT, AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
Arthur Hungabbb9d82021-09-01 14:52:30 +00006166}
6167
Prabir Pradhan367f3432024-02-13 23:05:58 +00006168// Same as TransferTouch_CloneSurface, but this touch on the secondary display and use
6169// 'transferTouchOnDisplay' api.
6170TEST_F(InputDispatcherTest, TransferTouchOnDisplay_CloneSurface) {
Arthur Hungabbb9d82021-09-01 14:52:30 +00006171 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
6172 sp<FakeWindowHandle> firstWindowInPrimary =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07006173 sp<FakeWindowHandle>::make(application, mDispatcher, "D_1_W1", ADISPLAY_ID_DEFAULT);
Arthur Hungabbb9d82021-09-01 14:52:30 +00006174 firstWindowInPrimary->setFrame(Rect(0, 0, 100, 100));
Arthur Hungabbb9d82021-09-01 14:52:30 +00006175 sp<FakeWindowHandle> secondWindowInPrimary =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07006176 sp<FakeWindowHandle>::make(application, mDispatcher, "D_1_W2", ADISPLAY_ID_DEFAULT);
Arthur Hungabbb9d82021-09-01 14:52:30 +00006177 secondWindowInPrimary->setFrame(Rect(100, 0, 200, 100));
Arthur Hungabbb9d82021-09-01 14:52:30 +00006178
Siarhei Vishniakouadb9fc92023-05-26 10:46:09 -07006179 sp<FakeWindowHandle> mirrorWindowInPrimary = firstWindowInPrimary->clone(ADISPLAY_ID_DEFAULT);
Arthur Hungabbb9d82021-09-01 14:52:30 +00006180 mirrorWindowInPrimary->setFrame(Rect(0, 100, 100, 200));
Arthur Hungabbb9d82021-09-01 14:52:30 +00006181
Siarhei Vishniakouadb9fc92023-05-26 10:46:09 -07006182 sp<FakeWindowHandle> firstWindowInSecondary = firstWindowInPrimary->clone(SECOND_DISPLAY_ID);
Arthur Hungabbb9d82021-09-01 14:52:30 +00006183 firstWindowInSecondary->setFrame(Rect(0, 0, 100, 100));
Arthur Hungabbb9d82021-09-01 14:52:30 +00006184
Siarhei Vishniakouadb9fc92023-05-26 10:46:09 -07006185 sp<FakeWindowHandle> secondWindowInSecondary = secondWindowInPrimary->clone(SECOND_DISPLAY_ID);
Arthur Hungabbb9d82021-09-01 14:52:30 +00006186 secondWindowInPrimary->setFrame(Rect(100, 0, 200, 100));
Arthur Hungabbb9d82021-09-01 14:52:30 +00006187
6188 // Update window info, let it find window handle of second display first.
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07006189 mDispatcher->onWindowInfosChanged(
6190 {{*firstWindowInSecondary->getInfo(), *secondWindowInSecondary->getInfo(),
6191 *mirrorWindowInPrimary->getInfo(), *firstWindowInPrimary->getInfo(),
6192 *secondWindowInPrimary->getInfo()},
6193 {},
6194 0,
6195 0});
Arthur Hungabbb9d82021-09-01 14:52:30 +00006196
6197 // Touch on second display.
6198 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07006199 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, SECOND_DISPLAY_ID,
6200 {50, 50}))
Arthur Hungabbb9d82021-09-01 14:52:30 +00006201 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
6202
6203 // Window should receive motion event.
Prabir Pradhanbb3f1c02024-01-04 20:17:14 +00006204 firstWindowInSecondary->consumeMotionDown(SECOND_DISPLAY_ID);
Arthur Hungabbb9d82021-09-01 14:52:30 +00006205
6206 // Transfer touch focus
Prabir Pradhan367f3432024-02-13 23:05:58 +00006207 ASSERT_TRUE(mDispatcher->transferTouchOnDisplay(secondWindowInSecondary->getToken(),
6208 SECOND_DISPLAY_ID));
Arthur Hungabbb9d82021-09-01 14:52:30 +00006209
6210 // The first window gets cancel.
Prabir Pradhanbb3f1c02024-01-04 20:17:14 +00006211 firstWindowInSecondary->consumeMotionCancel(SECOND_DISPLAY_ID);
Prabir Pradhan65455c72024-02-13 21:46:41 +00006212 secondWindowInSecondary->consumeMotionDown(SECOND_DISPLAY_ID,
6213 AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
Arthur Hungabbb9d82021-09-01 14:52:30 +00006214
6215 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07006216 injectMotionEvent(*mDispatcher, AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN,
Arthur Hungabbb9d82021-09-01 14:52:30 +00006217 SECOND_DISPLAY_ID, {150, 50}))
6218 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
Prabir Pradhanbb3f1c02024-01-04 20:17:14 +00006219 firstWindowInSecondary->assertNoEvents();
Prabir Pradhan65455c72024-02-13 21:46:41 +00006220 secondWindowInSecondary->consumeMotionMove(SECOND_DISPLAY_ID,
6221 AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
Arthur Hungabbb9d82021-09-01 14:52:30 +00006222
6223 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07006224 injectMotionUp(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, SECOND_DISPLAY_ID, {150, 50}))
Arthur Hungabbb9d82021-09-01 14:52:30 +00006225 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
Prabir Pradhanbb3f1c02024-01-04 20:17:14 +00006226 firstWindowInSecondary->assertNoEvents();
Prabir Pradhan65455c72024-02-13 21:46:41 +00006227 secondWindowInSecondary->consumeMotionUp(SECOND_DISPLAY_ID, AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
Arthur Hungabbb9d82021-09-01 14:52:30 +00006228}
6229
Siarhei Vishniakouf1035d42019-09-20 16:32:01 +01006230TEST_F(InputDispatcherTest, FocusedWindow_ReceivesFocusEventAndKeyEvent) {
Chris Yea209fde2020-07-22 13:54:51 -07006231 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07006232 sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher,
6233 "Fake Window", ADISPLAY_ID_DEFAULT);
Siarhei Vishniakouf1035d42019-09-20 16:32:01 +01006234
Vishnu Nair47074b82020-08-14 11:54:47 -07006235 window->setFocusable(true);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07006236 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Vishnu Nair958da932020-08-21 17:12:37 -07006237 setFocusedWindow(window);
Siarhei Vishniakouf1035d42019-09-20 16:32:01 +01006238
6239 window->consumeFocusEvent(true);
6240
Prabir Pradhan678438e2023-04-13 19:32:51 +00006241 mDispatcher->notifyKey(generateKeyArgs(AKEY_EVENT_ACTION_DOWN, ADISPLAY_ID_DEFAULT));
Siarhei Vishniakouf1035d42019-09-20 16:32:01 +01006242
6243 // Window should receive key down event.
6244 window->consumeKeyDown(ADISPLAY_ID_DEFAULT);
Josep del Riob3981622023-04-18 15:49:45 +00006245
6246 // Should have poked user activity
Siarhei Vishniakou4fd86732023-05-24 17:33:01 +00006247 mDispatcher->waitForIdle();
Josep del Riob3981622023-04-18 15:49:45 +00006248 mFakePolicy->assertUserActivityPoked();
6249}
6250
6251TEST_F(InputDispatcherTest, FocusedWindow_DisableUserActivity) {
6252 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
6253 sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher,
6254 "Fake Window", ADISPLAY_ID_DEFAULT);
6255
6256 window->setDisableUserActivity(true);
6257 window->setFocusable(true);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07006258 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Josep del Riob3981622023-04-18 15:49:45 +00006259 setFocusedWindow(window);
6260
6261 window->consumeFocusEvent(true);
6262
6263 mDispatcher->notifyKey(generateKeyArgs(AKEY_EVENT_ACTION_DOWN, ADISPLAY_ID_DEFAULT));
6264
6265 // Window should receive key down event.
6266 window->consumeKeyDown(ADISPLAY_ID_DEFAULT);
6267
6268 // Should have poked user activity
Siarhei Vishniakou4fd86732023-05-24 17:33:01 +00006269 mDispatcher->waitForIdle();
Josep del Riob3981622023-04-18 15:49:45 +00006270 mFakePolicy->assertUserActivityNotPoked();
6271}
6272
6273TEST_F(InputDispatcherTest, FocusedWindow_DoesNotReceiveSystemShortcut) {
6274 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
6275 sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher,
6276 "Fake Window", ADISPLAY_ID_DEFAULT);
6277
6278 window->setFocusable(true);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07006279 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Josep del Riob3981622023-04-18 15:49:45 +00006280 setFocusedWindow(window);
6281
6282 window->consumeFocusEvent(true);
6283
6284 mDispatcher->notifyKey(generateSystemShortcutArgs(AKEY_EVENT_ACTION_DOWN, ADISPLAY_ID_DEFAULT));
6285 mDispatcher->waitForIdle();
6286
6287 // System key is not passed down
6288 window->assertNoEvents();
6289
6290 // Should have poked user activity
6291 mFakePolicy->assertUserActivityPoked();
6292}
6293
6294TEST_F(InputDispatcherTest, FocusedWindow_DoesNotReceiveAssistantKey) {
6295 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
6296 sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher,
6297 "Fake Window", ADISPLAY_ID_DEFAULT);
6298
6299 window->setFocusable(true);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07006300 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Josep del Riob3981622023-04-18 15:49:45 +00006301 setFocusedWindow(window);
6302
6303 window->consumeFocusEvent(true);
6304
6305 mDispatcher->notifyKey(generateAssistantKeyArgs(AKEY_EVENT_ACTION_DOWN, ADISPLAY_ID_DEFAULT));
6306 mDispatcher->waitForIdle();
6307
6308 // System key is not passed down
6309 window->assertNoEvents();
6310
6311 // Should have poked user activity
6312 mFakePolicy->assertUserActivityPoked();
6313}
6314
6315TEST_F(InputDispatcherTest, FocusedWindow_SystemKeyIgnoresDisableUserActivity) {
6316 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
6317 sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher,
6318 "Fake Window", ADISPLAY_ID_DEFAULT);
6319
6320 window->setDisableUserActivity(true);
6321 window->setFocusable(true);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07006322 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Josep del Riob3981622023-04-18 15:49:45 +00006323 setFocusedWindow(window);
6324
6325 window->consumeFocusEvent(true);
6326
6327 mDispatcher->notifyKey(generateSystemShortcutArgs(AKEY_EVENT_ACTION_DOWN, ADISPLAY_ID_DEFAULT));
6328 mDispatcher->waitForIdle();
6329
6330 // System key is not passed down
6331 window->assertNoEvents();
6332
6333 // Should have poked user activity
6334 mFakePolicy->assertUserActivityPoked();
Siarhei Vishniakouf1035d42019-09-20 16:32:01 +01006335}
6336
Siarhei Vishniakou90ee4782023-05-08 11:57:24 -07006337TEST_F(InputDispatcherTest, InjectedTouchesPokeUserActivity) {
6338 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
6339 sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher,
6340 "Fake Window", ADISPLAY_ID_DEFAULT);
6341
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07006342 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Siarhei Vishniakou90ee4782023-05-08 11:57:24 -07006343
6344 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07006345 injectMotionEvent(*mDispatcher, AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN,
Siarhei Vishniakou90ee4782023-05-08 11:57:24 -07006346 ADISPLAY_ID_DEFAULT, {100, 100}))
6347 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
6348
6349 window->consumeMotionEvent(
6350 AllOf(WithMotionAction(ACTION_DOWN), WithDisplayId(ADISPLAY_ID_DEFAULT)));
6351
6352 // Should have poked user activity
Siarhei Vishniakou4fd86732023-05-24 17:33:01 +00006353 mDispatcher->waitForIdle();
Siarhei Vishniakou90ee4782023-05-08 11:57:24 -07006354 mFakePolicy->assertUserActivityPoked();
6355}
6356
Siarhei Vishniakouf1035d42019-09-20 16:32:01 +01006357TEST_F(InputDispatcherTest, UnfocusedWindow_DoesNotReceiveFocusEventOrKeyEvent) {
Chris Yea209fde2020-07-22 13:54:51 -07006358 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07006359 sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher,
6360 "Fake Window", ADISPLAY_ID_DEFAULT);
Siarhei Vishniakouf1035d42019-09-20 16:32:01 +01006361
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07006362 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Siarhei Vishniakouf1035d42019-09-20 16:32:01 +01006363
Prabir Pradhan678438e2023-04-13 19:32:51 +00006364 mDispatcher->notifyKey(generateKeyArgs(AKEY_EVENT_ACTION_DOWN, ADISPLAY_ID_DEFAULT));
Siarhei Vishniakouf1035d42019-09-20 16:32:01 +01006365 mDispatcher->waitForIdle();
6366
6367 window->assertNoEvents();
6368}
6369
6370// If a window is touchable, but does not have focus, it should receive motion events, but not keys
6371TEST_F(InputDispatcherTest, UnfocusedWindow_ReceivesMotionsButNotKeys) {
Chris Yea209fde2020-07-22 13:54:51 -07006372 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07006373 sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher,
6374 "Fake Window", ADISPLAY_ID_DEFAULT);
Siarhei Vishniakouf1035d42019-09-20 16:32:01 +01006375
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07006376 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Siarhei Vishniakouf1035d42019-09-20 16:32:01 +01006377
6378 // Send key
Prabir Pradhan678438e2023-04-13 19:32:51 +00006379 mDispatcher->notifyKey(generateKeyArgs(AKEY_EVENT_ACTION_DOWN, ADISPLAY_ID_DEFAULT));
Siarhei Vishniakouf1035d42019-09-20 16:32:01 +01006380 // Send motion
Prabir Pradhan678438e2023-04-13 19:32:51 +00006381 mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_DOWN,
6382 AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT));
Siarhei Vishniakouf1035d42019-09-20 16:32:01 +01006383
6384 // Window should receive only the motion event
6385 window->consumeMotionDown(ADISPLAY_ID_DEFAULT);
6386 window->assertNoEvents(); // Key event or focus event will not be received
6387}
6388
arthurhungea3f4fc2020-12-21 23:18:53 +08006389TEST_F(InputDispatcherTest, PointerCancel_SendCancelWhenSplitTouch) {
6390 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
6391
arthurhungea3f4fc2020-12-21 23:18:53 +08006392 sp<FakeWindowHandle> firstWindow =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07006393 sp<FakeWindowHandle>::make(application, mDispatcher, "First Window",
6394 ADISPLAY_ID_DEFAULT);
arthurhungea3f4fc2020-12-21 23:18:53 +08006395 firstWindow->setFrame(Rect(0, 0, 600, 400));
arthurhungea3f4fc2020-12-21 23:18:53 +08006396
arthurhungea3f4fc2020-12-21 23:18:53 +08006397 sp<FakeWindowHandle> secondWindow =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07006398 sp<FakeWindowHandle>::make(application, mDispatcher, "Second Window",
6399 ADISPLAY_ID_DEFAULT);
arthurhungea3f4fc2020-12-21 23:18:53 +08006400 secondWindow->setFrame(Rect(0, 400, 600, 800));
arthurhungea3f4fc2020-12-21 23:18:53 +08006401
6402 // Add the windows to the dispatcher
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07006403 mDispatcher->onWindowInfosChanged(
6404 {{*firstWindow->getInfo(), *secondWindow->getInfo()}, {}, 0, 0});
arthurhungea3f4fc2020-12-21 23:18:53 +08006405
6406 PointF pointInFirst = {300, 200};
6407 PointF pointInSecond = {300, 600};
6408
6409 // Send down to the first window
Prabir Pradhan678438e2023-04-13 19:32:51 +00006410 mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_DOWN,
6411 AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
6412 {pointInFirst}));
arthurhungea3f4fc2020-12-21 23:18:53 +08006413 // Only the first window should get the down event
6414 firstWindow->consumeMotionDown();
6415 secondWindow->assertNoEvents();
6416
6417 // Send down to the second window
Prabir Pradhan678438e2023-04-13 19:32:51 +00006418 mDispatcher->notifyMotion(generateMotionArgs(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN,
6419 ADISPLAY_ID_DEFAULT,
6420 {pointInFirst, pointInSecond}));
arthurhungea3f4fc2020-12-21 23:18:53 +08006421 // The first window gets a move and the second a down
6422 firstWindow->consumeMotionMove();
6423 secondWindow->consumeMotionDown();
6424
6425 // Send pointer cancel to the second window
6426 NotifyMotionArgs pointerUpMotionArgs =
Siarhei Vishniakoua16e3a22022-03-02 15:26:40 -08006427 generateMotionArgs(POINTER_1_UP, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
arthurhungea3f4fc2020-12-21 23:18:53 +08006428 {pointInFirst, pointInSecond});
6429 pointerUpMotionArgs.flags |= AMOTION_EVENT_FLAG_CANCELED;
Prabir Pradhan678438e2023-04-13 19:32:51 +00006430 mDispatcher->notifyMotion(pointerUpMotionArgs);
arthurhungea3f4fc2020-12-21 23:18:53 +08006431 // The first window gets move and the second gets cancel.
6432 firstWindow->consumeMotionMove(ADISPLAY_ID_DEFAULT, AMOTION_EVENT_FLAG_CANCELED);
6433 secondWindow->consumeMotionCancel(ADISPLAY_ID_DEFAULT, AMOTION_EVENT_FLAG_CANCELED);
6434
6435 // Send up event.
Prabir Pradhan678438e2023-04-13 19:32:51 +00006436 mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN,
6437 ADISPLAY_ID_DEFAULT));
arthurhungea3f4fc2020-12-21 23:18:53 +08006438 // The first window gets up and the second gets nothing.
6439 firstWindow->consumeMotionUp();
6440 secondWindow->assertNoEvents();
6441}
6442
Siarhei Vishniakouf94ae022021-02-04 01:23:17 +00006443TEST_F(InputDispatcherTest, SendTimeline_DoesNotCrashDispatcher) {
6444 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
6445
6446 sp<FakeWindowHandle> window =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07006447 sp<FakeWindowHandle>::make(application, mDispatcher, "Window", ADISPLAY_ID_DEFAULT);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07006448 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Siarhei Vishniakouf94ae022021-02-04 01:23:17 +00006449 std::array<nsecs_t, GraphicsTimeline::SIZE> graphicsTimeline;
6450 graphicsTimeline[GraphicsTimeline::GPU_COMPLETED_TIME] = 2;
6451 graphicsTimeline[GraphicsTimeline::PRESENT_TIME] = 3;
6452
Harry Cutts33476232023-01-30 19:57:29 +00006453 window->sendTimeline(/*inputEventId=*/1, graphicsTimeline);
Siarhei Vishniakouf94ae022021-02-04 01:23:17 +00006454 window->assertNoEvents();
6455 mDispatcher->waitForIdle();
6456}
6457
Prabir Pradhan1376fcd2022-01-21 09:56:35 -08006458using InputDispatcherMonitorTest = InputDispatcherTest;
6459
Siarhei Vishniakouca205502021-07-16 21:31:58 +00006460/**
6461 * Two entities that receive touch: A window, and a global monitor.
6462 * The touch goes to the window, and then the window disappears.
6463 * The monitor does not get cancel right away. But if more events come in, the touch gets canceled
6464 * for the monitor, as well.
6465 * 1. foregroundWindow
6466 * 2. monitor <-- global monitor (doesn't observe z order, receives all events)
6467 */
Prabir Pradhan1376fcd2022-01-21 09:56:35 -08006468TEST_F(InputDispatcherMonitorTest, MonitorTouchIsCanceledWhenForegroundWindowDisappears) {
Siarhei Vishniakouca205502021-07-16 21:31:58 +00006469 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
6470 sp<FakeWindowHandle> window =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07006471 sp<FakeWindowHandle>::make(application, mDispatcher, "Foreground", ADISPLAY_ID_DEFAULT);
Siarhei Vishniakouca205502021-07-16 21:31:58 +00006472
Prabir Pradhanfb549072023-10-05 19:17:36 +00006473 FakeMonitorReceiver monitor = FakeMonitorReceiver(*mDispatcher, "M_1", ADISPLAY_ID_DEFAULT);
Siarhei Vishniakouca205502021-07-16 21:31:58 +00006474
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07006475 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Siarhei Vishniakouca205502021-07-16 21:31:58 +00006476 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07006477 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
Siarhei Vishniakouca205502021-07-16 21:31:58 +00006478 {100, 200}))
6479 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
6480
6481 // Both the foreground window and the global monitor should receive the touch down
6482 window->consumeMotionDown();
6483 monitor.consumeMotionDown(ADISPLAY_ID_DEFAULT);
6484
6485 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07006486 injectMotionEvent(*mDispatcher, AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN,
Siarhei Vishniakouca205502021-07-16 21:31:58 +00006487 ADISPLAY_ID_DEFAULT, {110, 200}))
6488 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
6489
6490 window->consumeMotionMove();
6491 monitor.consumeMotionMove(ADISPLAY_ID_DEFAULT);
6492
6493 // Now the foreground window goes away
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07006494 mDispatcher->onWindowInfosChanged({{}, {}, 0, 0});
Siarhei Vishniakouca205502021-07-16 21:31:58 +00006495 window->consumeMotionCancel();
6496 monitor.assertNoEvents(); // Global monitor does not get a cancel yet
6497
6498 // If more events come in, there will be no more foreground window to send them to. This will
6499 // cause a cancel for the monitor, as well.
6500 ASSERT_EQ(InputEventInjectionResult::FAILED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07006501 injectMotionEvent(*mDispatcher, AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN,
Siarhei Vishniakouca205502021-07-16 21:31:58 +00006502 ADISPLAY_ID_DEFAULT, {120, 200}))
6503 << "Injection should fail because the window was removed";
6504 window->assertNoEvents();
6505 // Global monitor now gets the cancel
6506 monitor.consumeMotionCancel(ADISPLAY_ID_DEFAULT);
6507}
6508
Prabir Pradhan1376fcd2022-01-21 09:56:35 -08006509TEST_F(InputDispatcherMonitorTest, ReceivesMotionEvents) {
Chris Yea209fde2020-07-22 13:54:51 -07006510 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07006511 sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher,
6512 "Fake Window", ADISPLAY_ID_DEFAULT);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07006513 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Michael Wright3a240c42019-12-10 20:53:41 +00006514
Prabir Pradhanfb549072023-10-05 19:17:36 +00006515 FakeMonitorReceiver monitor = FakeMonitorReceiver(*mDispatcher, "M_1", ADISPLAY_ID_DEFAULT);
Michael Wright3a240c42019-12-10 20:53:41 +00006516
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08006517 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07006518 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT))
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08006519 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
Michael Wright3a240c42019-12-10 20:53:41 +00006520 window->consumeMotionDown(ADISPLAY_ID_DEFAULT);
chaviwd1c23182019-12-20 18:44:56 -08006521 monitor.consumeMotionDown(ADISPLAY_ID_DEFAULT);
Michael Wright3a240c42019-12-10 20:53:41 +00006522}
6523
Prabir Pradhan1376fcd2022-01-21 09:56:35 -08006524TEST_F(InputDispatcherMonitorTest, MonitorCannotPilferPointers) {
Prabir Pradhanfb549072023-10-05 19:17:36 +00006525 FakeMonitorReceiver monitor = FakeMonitorReceiver(*mDispatcher, "M_1", ADISPLAY_ID_DEFAULT);
Michael Wright3a240c42019-12-10 20:53:41 +00006526
Chris Yea209fde2020-07-22 13:54:51 -07006527 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07006528 sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher,
6529 "Fake Window", ADISPLAY_ID_DEFAULT);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07006530 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Michael Wright3a240c42019-12-10 20:53:41 +00006531
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08006532 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07006533 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT))
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08006534 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
chaviwd1c23182019-12-20 18:44:56 -08006535 monitor.consumeMotionDown(ADISPLAY_ID_DEFAULT);
Prabir Pradhan1376fcd2022-01-21 09:56:35 -08006536 window->consumeMotionDown(ADISPLAY_ID_DEFAULT);
Michael Wright3a240c42019-12-10 20:53:41 +00006537
Prabir Pradhan1376fcd2022-01-21 09:56:35 -08006538 // Pilfer pointers from the monitor.
6539 // This should not do anything and the window should continue to receive events.
6540 EXPECT_NE(OK, mDispatcher->pilferPointers(monitor.getToken()));
Michael Wright3a240c42019-12-10 20:53:41 +00006541
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08006542 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07006543 injectMotionEvent(*mDispatcher, AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN,
Prabir Pradhan1376fcd2022-01-21 09:56:35 -08006544 ADISPLAY_ID_DEFAULT))
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08006545 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
Prabir Pradhan1376fcd2022-01-21 09:56:35 -08006546
6547 monitor.consumeMotionMove(ADISPLAY_ID_DEFAULT);
6548 window->consumeMotionMove(ADISPLAY_ID_DEFAULT);
Michael Wright3a240c42019-12-10 20:53:41 +00006549}
6550
Prabir Pradhan1376fcd2022-01-21 09:56:35 -08006551TEST_F(InputDispatcherMonitorTest, NoWindowTransform) {
Evan Rosky84f07f02021-04-16 10:42:42 -07006552 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07006553 sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher,
6554 "Fake Window", ADISPLAY_ID_DEFAULT);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07006555 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Evan Rosky84f07f02021-04-16 10:42:42 -07006556 window->setWindowOffset(20, 40);
6557 window->setWindowTransform(0, 1, -1, 0);
6558
Prabir Pradhanfb549072023-10-05 19:17:36 +00006559 FakeMonitorReceiver monitor = FakeMonitorReceiver(*mDispatcher, "M_1", ADISPLAY_ID_DEFAULT);
Evan Rosky84f07f02021-04-16 10:42:42 -07006560
6561 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07006562 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT))
Evan Rosky84f07f02021-04-16 10:42:42 -07006563 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
6564 window->consumeMotionDown(ADISPLAY_ID_DEFAULT);
Siarhei Vishniakoud3061ab2023-12-18 20:41:08 -08006565 std::unique_ptr<MotionEvent> event = monitor.consumeMotion();
6566 ASSERT_NE(nullptr, event);
Evan Rosky84f07f02021-04-16 10:42:42 -07006567 // Even though window has transform, gesture monitor must not.
6568 ASSERT_EQ(ui::Transform(), event->getTransform());
6569}
6570
Prabir Pradhan1376fcd2022-01-21 09:56:35 -08006571TEST_F(InputDispatcherMonitorTest, InjectionFailsWithNoWindow) {
Arthur Hungb3307ee2021-10-14 10:57:37 +00006572 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
Prabir Pradhanfb549072023-10-05 19:17:36 +00006573 FakeMonitorReceiver monitor = FakeMonitorReceiver(*mDispatcher, "M_1", ADISPLAY_ID_DEFAULT);
Arthur Hungb3307ee2021-10-14 10:57:37 +00006574
Prabir Pradhan1376fcd2022-01-21 09:56:35 -08006575 ASSERT_EQ(InputEventInjectionResult::FAILED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07006576 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT))
Prabir Pradhan1376fcd2022-01-21 09:56:35 -08006577 << "Injection should fail if there is a monitor, but no touchable window";
6578 monitor.assertNoEvents();
Arthur Hungb3307ee2021-10-14 10:57:37 +00006579}
6580
Linnan Lid8150952024-01-26 18:07:17 +00006581/**
6582 * Two displays
6583 * The first monitor has a foreground window, a monitor
6584 * The second window has only one monitor.
6585 * We first inject a Down event into the first display, this injection should succeed and both
6586 * the foreground window and monitor should receive a down event, then inject a Down event into
6587 * the second display as well, this injection should fail, at this point, the first display
6588 * window and monitor should not receive a cancel or any other event.
6589 * Continue to inject Move and UP events to the first display, the events should be received
6590 * normally by the foreground window and monitor.
6591 */
6592TEST_F(InputDispatcherMonitorTest, MonitorTouchIsNotCanceledWhenAnotherEmptyDisplayReceiveEvents) {
6593 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
6594 sp<FakeWindowHandle> window =
6595 sp<FakeWindowHandle>::make(application, mDispatcher, "Foreground", ADISPLAY_ID_DEFAULT);
6596
6597 FakeMonitorReceiver monitor = FakeMonitorReceiver(*mDispatcher, "M_1", ADISPLAY_ID_DEFAULT);
6598 FakeMonitorReceiver secondMonitor = FakeMonitorReceiver(*mDispatcher, "M_2", SECOND_DISPLAY_ID);
6599
6600 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
6601 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
6602 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
6603 {100, 200}))
6604 << "The down event injected into the first display should succeed";
6605
6606 window->consumeMotionDown();
6607 monitor.consumeMotionDown(ADISPLAY_ID_DEFAULT);
Linnan Lid8150952024-01-26 18:07:17 +00006608
6609 ASSERT_EQ(InputEventInjectionResult::FAILED,
6610 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, SECOND_DISPLAY_ID,
6611 {100, 200}))
Prabir Pradhana0d43d42024-01-30 00:27:08 +00006612 << "The down event injected into the second display should fail since there's no "
6613 "touchable window";
Linnan Lid8150952024-01-26 18:07:17 +00006614
6615 // Continue to inject event to first display.
6616 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
6617 injectMotionEvent(*mDispatcher, AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN,
6618 ADISPLAY_ID_DEFAULT, {110, 220}))
6619 << "The move event injected into the first display should succeed";
6620
6621 window->consumeMotionMove();
6622 monitor.consumeMotionMove(ADISPLAY_ID_DEFAULT);
Linnan Lid8150952024-01-26 18:07:17 +00006623
6624 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
6625 injectMotionUp(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
6626 {110, 220}))
6627 << "The up event injected into the first display should succeed";
6628
6629 window->consumeMotionUp();
6630 monitor.consumeMotionUp(ADISPLAY_ID_DEFAULT);
Prabir Pradhana0d43d42024-01-30 00:27:08 +00006631
6632 window->assertNoEvents();
6633 monitor.assertNoEvents();
Linnan Lid8150952024-01-26 18:07:17 +00006634 secondMonitor.assertNoEvents();
6635}
6636
6637/**
6638 * Two displays
6639 * There is a monitor and foreground window on each display.
6640 * First, we inject down events into each of the two displays, at this point, the foreground windows
6641 * and monitors on both displays should receive down events.
6642 * At this point, the foreground window of the second display goes away, the gone window should
6643 * receive the cancel event, and the other windows and monitors should not receive any events.
6644 * Inject a move event into the second display. At this point, the injection should fail because
6645 * the second display no longer has a foreground window. At this point, the monitor on the second
6646 * display should receive a cancel event, and any windows or monitors on the first display should
6647 * not receive any events, and any subsequent injection of events into the second display should
6648 * also fail.
6649 * Continue to inject events into the first display, and the events should all be injected
6650 * successfully and received normally.
6651 */
6652TEST_F(InputDispatcherMonitorTest, MonitorTouchIsNotCancelWhenAnotherDisplayMonitorTouchCanceled) {
6653 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
6654 sp<FakeWindowHandle> window =
6655 sp<FakeWindowHandle>::make(application, mDispatcher, "Foreground", ADISPLAY_ID_DEFAULT);
6656 sp<FakeWindowHandle> secondWindow =
6657 sp<FakeWindowHandle>::make(application, mDispatcher, "SecondForeground",
6658 SECOND_DISPLAY_ID);
6659
6660 FakeMonitorReceiver monitor = FakeMonitorReceiver(*mDispatcher, "M_1", ADISPLAY_ID_DEFAULT);
6661 FakeMonitorReceiver secondMonitor = FakeMonitorReceiver(*mDispatcher, "M_2", SECOND_DISPLAY_ID);
6662
6663 // There is a foreground window on both displays.
6664 mDispatcher->onWindowInfosChanged({{*window->getInfo(), *secondWindow->getInfo()}, {}, 0, 0});
6665 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
6666 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
6667 {100, 200}))
6668 << "The down event injected into the first display should succeed";
6669
6670 window->consumeMotionDown(ADISPLAY_ID_DEFAULT);
6671 monitor.consumeMotionDown(ADISPLAY_ID_DEFAULT);
Linnan Lid8150952024-01-26 18:07:17 +00006672
6673 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
6674 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, SECOND_DISPLAY_ID,
6675 {100, 200}))
6676 << "The down event injected into the second display should succeed";
6677
Linnan Lid8150952024-01-26 18:07:17 +00006678 secondWindow->consumeMotionDown(SECOND_DISPLAY_ID);
6679 secondMonitor.consumeMotionDown(SECOND_DISPLAY_ID);
6680
6681 // Now second window is gone away.
6682 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
6683
6684 // The gone window should receive a cancel, and the monitor on the second display should not
6685 // receive any events.
Linnan Lid8150952024-01-26 18:07:17 +00006686 secondWindow->consumeMotionCancel(SECOND_DISPLAY_ID);
6687 secondMonitor.assertNoEvents();
6688
6689 ASSERT_EQ(InputEventInjectionResult::FAILED,
6690 injectMotionEvent(*mDispatcher, AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN,
6691 SECOND_DISPLAY_ID, {110, 220}))
Prabir Pradhana0d43d42024-01-30 00:27:08 +00006692 << "The move event injected into the second display should fail because there's no "
6693 "touchable window";
Linnan Lid8150952024-01-26 18:07:17 +00006694 // Now the monitor on the second display should receive a cancel event.
6695 secondMonitor.consumeMotionCancel(SECOND_DISPLAY_ID);
Linnan Lid8150952024-01-26 18:07:17 +00006696
6697 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
6698 injectMotionEvent(*mDispatcher, AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN,
6699 ADISPLAY_ID_DEFAULT, {110, 200}))
6700 << "The move event injected into the first display should succeed";
6701
6702 window->consumeMotionMove();
6703 monitor.consumeMotionMove(ADISPLAY_ID_DEFAULT);
Linnan Lid8150952024-01-26 18:07:17 +00006704
6705 ASSERT_EQ(InputEventInjectionResult::FAILED,
Prabir Pradhana0d43d42024-01-30 00:27:08 +00006706 injectMotionUp(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, SECOND_DISPLAY_ID,
6707 {110, 220}))
6708 << "The up event injected into the second display should fail because there's no "
6709 "touchable window";
Linnan Lid8150952024-01-26 18:07:17 +00006710
6711 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
6712 injectMotionUp(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
6713 {110, 220}))
6714 << "The up event injected into the first display should succeed";
6715
6716 window->consumeMotionUp(ADISPLAY_ID_DEFAULT);
6717 monitor.consumeMotionUp(ADISPLAY_ID_DEFAULT);
Prabir Pradhana0d43d42024-01-30 00:27:08 +00006718
Linnan Lid8150952024-01-26 18:07:17 +00006719 window->assertNoEvents();
6720 monitor.assertNoEvents();
Prabir Pradhana0d43d42024-01-30 00:27:08 +00006721 secondWindow->assertNoEvents();
6722 secondMonitor.assertNoEvents();
Linnan Lid8150952024-01-26 18:07:17 +00006723}
6724
6725/**
6726 * One display with transform
6727 * There is a foreground window and a monitor on the display
6728 * Inject down event and move event sequentially, the foreground window and monitor can receive down
6729 * event and move event, then let the foreground window go away, the foreground window receives
6730 * cancel event, inject move event again, the monitor receives cancel event, all the events received
6731 * by the monitor should be with the same transform as the display
6732 */
6733TEST_F(InputDispatcherMonitorTest, MonitorTouchCancelEventWithDisplayTransform) {
6734 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
6735 sp<FakeWindowHandle> window =
6736 sp<FakeWindowHandle>::make(application, mDispatcher, "Foreground", ADISPLAY_ID_DEFAULT);
6737 FakeMonitorReceiver monitor = FakeMonitorReceiver(*mDispatcher, "M_1", ADISPLAY_ID_DEFAULT);
6738
6739 ui::Transform transform;
6740 transform.set({1.1, 2.2, 3.3, 4.4, 5.5, 6.6, 0, 0, 1});
6741
6742 gui::DisplayInfo displayInfo;
6743 displayInfo.displayId = ADISPLAY_ID_DEFAULT;
6744 displayInfo.transform = transform;
6745
6746 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {displayInfo}, 0, 0});
6747
6748 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
6749 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
6750 {100, 200}))
6751 << "The down event injected should succeed";
6752
6753 window->consumeMotionDown();
6754 std::unique_ptr<MotionEvent> downMotionEvent = monitor.consumeMotion();
6755 EXPECT_EQ(transform, downMotionEvent->getTransform());
6756 EXPECT_EQ(AMOTION_EVENT_ACTION_DOWN, downMotionEvent->getAction());
6757
6758 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
6759 injectMotionEvent(*mDispatcher, AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN,
6760 ADISPLAY_ID_DEFAULT, {110, 220}))
6761 << "The move event injected should succeed";
6762
6763 window->consumeMotionMove();
6764 std::unique_ptr<MotionEvent> moveMotionEvent = monitor.consumeMotion();
6765 EXPECT_EQ(transform, moveMotionEvent->getTransform());
6766 EXPECT_EQ(AMOTION_EVENT_ACTION_MOVE, moveMotionEvent->getAction());
6767
6768 // Let foreground window gone
6769 mDispatcher->onWindowInfosChanged({{}, {displayInfo}, 0, 0});
6770
Prabir Pradhana0d43d42024-01-30 00:27:08 +00006771 // Foreground window should receive a cancel event, but not the monitor.
Linnan Lid8150952024-01-26 18:07:17 +00006772 window->consumeMotionCancel();
Linnan Lid8150952024-01-26 18:07:17 +00006773
6774 ASSERT_EQ(InputEventInjectionResult::FAILED,
6775 injectMotionEvent(*mDispatcher, AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN,
6776 ADISPLAY_ID_DEFAULT, {110, 220}))
6777 << "The move event injected should failed";
6778 // Now foreground should not receive any events, but monitor should receive a cancel event
6779 // with transform that same as display's display.
Linnan Lid8150952024-01-26 18:07:17 +00006780 std::unique_ptr<MotionEvent> cancelMotionEvent = monitor.consumeMotion();
6781 EXPECT_EQ(transform, cancelMotionEvent->getTransform());
6782 EXPECT_EQ(ADISPLAY_ID_DEFAULT, cancelMotionEvent->getDisplayId());
6783 EXPECT_EQ(AMOTION_EVENT_ACTION_CANCEL, cancelMotionEvent->getAction());
6784
6785 // Other event inject to this display should fail.
6786 ASSERT_EQ(InputEventInjectionResult::FAILED,
6787 injectMotionEvent(*mDispatcher, AMOTION_EVENT_ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN,
6788 ADISPLAY_ID_DEFAULT, {110, 220}))
Prabir Pradhana0d43d42024-01-30 00:27:08 +00006789 << "The up event injected should fail because the touched window was removed";
Linnan Lid8150952024-01-26 18:07:17 +00006790 window->assertNoEvents();
6791 monitor.assertNoEvents();
6792}
6793
chaviw81e2bb92019-12-18 15:03:51 -08006794TEST_F(InputDispatcherTest, TestMoveEvent) {
Chris Yea209fde2020-07-22 13:54:51 -07006795 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07006796 sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher,
6797 "Fake Window", ADISPLAY_ID_DEFAULT);
chaviw81e2bb92019-12-18 15:03:51 -08006798
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07006799 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
chaviw81e2bb92019-12-18 15:03:51 -08006800
6801 NotifyMotionArgs motionArgs =
6802 generateMotionArgs(AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN,
6803 ADISPLAY_ID_DEFAULT);
6804
Prabir Pradhan678438e2023-04-13 19:32:51 +00006805 mDispatcher->notifyMotion(motionArgs);
chaviw81e2bb92019-12-18 15:03:51 -08006806 // Window should receive motion down event.
6807 window->consumeMotionDown(ADISPLAY_ID_DEFAULT);
6808
6809 motionArgs.action = AMOTION_EVENT_ACTION_MOVE;
Garfield Tanc51d1ba2020-01-28 13:24:04 -08006810 motionArgs.id += 1;
chaviw81e2bb92019-12-18 15:03:51 -08006811 motionArgs.eventTime = systemTime(SYSTEM_TIME_MONOTONIC);
6812 motionArgs.pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_X,
6813 motionArgs.pointerCoords[0].getX() - 10);
6814
Prabir Pradhan678438e2023-04-13 19:32:51 +00006815 mDispatcher->notifyMotion(motionArgs);
Prabir Pradhan7662a8d2023-12-15 01:58:14 +00006816 window->consumeMotionMove(ADISPLAY_ID_DEFAULT, /*expectedFlags=*/0);
chaviw81e2bb92019-12-18 15:03:51 -08006817}
6818
Siarhei Vishniakouf1035d42019-09-20 16:32:01 +01006819/**
6820 * Dispatcher has touch mode enabled by default. Typically, the policy overrides that value to
6821 * the device default right away. In the test scenario, we check both the default value,
6822 * and the action of enabling / disabling.
6823 */
6824TEST_F(InputDispatcherTest, TouchModeState_IsSentToApps) {
Chris Yea209fde2020-07-22 13:54:51 -07006825 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07006826 sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher,
6827 "Test window", ADISPLAY_ID_DEFAULT);
Antonio Kantekea47acb2021-12-23 12:41:25 -08006828 const WindowInfo& windowInfo = *window->getInfo();
Siarhei Vishniakouf1035d42019-09-20 16:32:01 +01006829
6830 // Set focused application.
6831 mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application);
Vishnu Nair47074b82020-08-14 11:54:47 -07006832 window->setFocusable(true);
Siarhei Vishniakouf1035d42019-09-20 16:32:01 +01006833
6834 SCOPED_TRACE("Check default value of touch mode");
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07006835 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Vishnu Nair958da932020-08-21 17:12:37 -07006836 setFocusedWindow(window);
Harry Cutts33476232023-01-30 19:57:29 +00006837 window->consumeFocusEvent(/*hasFocus=*/true, /*inTouchMode=*/true);
Siarhei Vishniakouf1035d42019-09-20 16:32:01 +01006838
6839 SCOPED_TRACE("Remove the window to trigger focus loss");
Vishnu Nair47074b82020-08-14 11:54:47 -07006840 window->setFocusable(false);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07006841 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Harry Cutts33476232023-01-30 19:57:29 +00006842 window->consumeFocusEvent(/*hasFocus=*/false, /*inTouchMode=*/true);
Siarhei Vishniakouf1035d42019-09-20 16:32:01 +01006843
6844 SCOPED_TRACE("Disable touch mode");
Antonio Kantekea47acb2021-12-23 12:41:25 -08006845 mDispatcher->setInTouchMode(false, windowInfo.ownerPid, windowInfo.ownerUid,
Harry Cutts33476232023-01-30 19:57:29 +00006846 /*hasPermission=*/true, ADISPLAY_ID_DEFAULT);
Antonio Kantekf16f2832021-09-28 04:39:20 +00006847 window->consumeTouchModeEvent(false);
Vishnu Nair47074b82020-08-14 11:54:47 -07006848 window->setFocusable(true);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07006849 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Vishnu Nair958da932020-08-21 17:12:37 -07006850 setFocusedWindow(window);
Harry Cutts33476232023-01-30 19:57:29 +00006851 window->consumeFocusEvent(/*hasFocus=*/true, /*inTouchMode=*/false);
Siarhei Vishniakouf1035d42019-09-20 16:32:01 +01006852
6853 SCOPED_TRACE("Remove the window to trigger focus loss");
Vishnu Nair47074b82020-08-14 11:54:47 -07006854 window->setFocusable(false);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07006855 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Harry Cutts33476232023-01-30 19:57:29 +00006856 window->consumeFocusEvent(/*hasFocus=*/false, /*inTouchMode=*/false);
Siarhei Vishniakouf1035d42019-09-20 16:32:01 +01006857
6858 SCOPED_TRACE("Enable touch mode again");
Antonio Kantekea47acb2021-12-23 12:41:25 -08006859 mDispatcher->setInTouchMode(true, windowInfo.ownerPid, windowInfo.ownerUid,
Harry Cutts33476232023-01-30 19:57:29 +00006860 /*hasPermission=*/true, ADISPLAY_ID_DEFAULT);
Antonio Kantekf16f2832021-09-28 04:39:20 +00006861 window->consumeTouchModeEvent(true);
Vishnu Nair47074b82020-08-14 11:54:47 -07006862 window->setFocusable(true);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07006863 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Vishnu Nair958da932020-08-21 17:12:37 -07006864 setFocusedWindow(window);
Harry Cutts33476232023-01-30 19:57:29 +00006865 window->consumeFocusEvent(/*hasFocus=*/true, /*inTouchMode=*/true);
Siarhei Vishniakouf1035d42019-09-20 16:32:01 +01006866
6867 window->assertNoEvents();
6868}
6869
Gang Wange9087892020-01-07 12:17:14 -05006870TEST_F(InputDispatcherTest, VerifyInputEvent_KeyEvent) {
Chris Yea209fde2020-07-22 13:54:51 -07006871 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07006872 sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher,
6873 "Test window", ADISPLAY_ID_DEFAULT);
Gang Wange9087892020-01-07 12:17:14 -05006874
6875 mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application);
Vishnu Nair47074b82020-08-14 11:54:47 -07006876 window->setFocusable(true);
Gang Wange9087892020-01-07 12:17:14 -05006877
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07006878 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Vishnu Nair958da932020-08-21 17:12:37 -07006879 setFocusedWindow(window);
6880
Harry Cutts33476232023-01-30 19:57:29 +00006881 window->consumeFocusEvent(/*hasFocus=*/true, /*inTouchMode=*/true);
Gang Wange9087892020-01-07 12:17:14 -05006882
Prabir Pradhan678438e2023-04-13 19:32:51 +00006883 const NotifyKeyArgs keyArgs = generateKeyArgs(AKEY_EVENT_ACTION_DOWN);
6884 mDispatcher->notifyKey(keyArgs);
Gang Wange9087892020-01-07 12:17:14 -05006885
Siarhei Vishniakoud3061ab2023-12-18 20:41:08 -08006886 std::unique_ptr<KeyEvent> event = window->consumeKey();
6887 ASSERT_NE(event, nullptr);
6888 std::unique_ptr<VerifiedInputEvent> verified = mDispatcher->verifyInputEvent(*event);
Gang Wange9087892020-01-07 12:17:14 -05006889 ASSERT_NE(verified, nullptr);
6890 ASSERT_EQ(verified->type, VerifiedInputEvent::Type::KEY);
6891
6892 ASSERT_EQ(keyArgs.eventTime, verified->eventTimeNanos);
6893 ASSERT_EQ(keyArgs.deviceId, verified->deviceId);
6894 ASSERT_EQ(keyArgs.source, verified->source);
6895 ASSERT_EQ(keyArgs.displayId, verified->displayId);
6896
6897 const VerifiedKeyEvent& verifiedKey = static_cast<const VerifiedKeyEvent&>(*verified);
6898
6899 ASSERT_EQ(keyArgs.action, verifiedKey.action);
Gang Wange9087892020-01-07 12:17:14 -05006900 ASSERT_EQ(keyArgs.flags & VERIFIED_KEY_EVENT_FLAGS, verifiedKey.flags);
Siarhei Vishniakouf355bf92021-12-09 10:43:21 -08006901 ASSERT_EQ(keyArgs.downTime, verifiedKey.downTimeNanos);
Gang Wange9087892020-01-07 12:17:14 -05006902 ASSERT_EQ(keyArgs.keyCode, verifiedKey.keyCode);
6903 ASSERT_EQ(keyArgs.scanCode, verifiedKey.scanCode);
6904 ASSERT_EQ(keyArgs.metaState, verifiedKey.metaState);
6905 ASSERT_EQ(0, verifiedKey.repeatCount);
6906}
6907
Siarhei Vishniakou47040bf2020-02-28 15:03:13 -08006908TEST_F(InputDispatcherTest, VerifyInputEvent_MotionEvent) {
Chris Yea209fde2020-07-22 13:54:51 -07006909 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07006910 sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher,
6911 "Test window", ADISPLAY_ID_DEFAULT);
Siarhei Vishniakou47040bf2020-02-28 15:03:13 -08006912
6913 mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application);
6914
Prabir Pradhanb5cb9572021-09-24 06:35:16 -07006915 ui::Transform transform;
6916 transform.set({1.1, 2.2, 3.3, 4.4, 5.5, 6.6, 0, 0, 1});
6917
6918 gui::DisplayInfo displayInfo;
6919 displayInfo.displayId = ADISPLAY_ID_DEFAULT;
6920 displayInfo.transform = transform;
6921
Patrick Williamsd828f302023-04-28 17:52:08 -05006922 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {displayInfo}, 0, 0});
Siarhei Vishniakou47040bf2020-02-28 15:03:13 -08006923
Prabir Pradhan678438e2023-04-13 19:32:51 +00006924 const NotifyMotionArgs motionArgs =
Siarhei Vishniakou47040bf2020-02-28 15:03:13 -08006925 generateMotionArgs(AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN,
6926 ADISPLAY_ID_DEFAULT);
Prabir Pradhan678438e2023-04-13 19:32:51 +00006927 mDispatcher->notifyMotion(motionArgs);
Siarhei Vishniakou47040bf2020-02-28 15:03:13 -08006928
Siarhei Vishniakoud3061ab2023-12-18 20:41:08 -08006929 std::unique_ptr<MotionEvent> event = window->consumeMotionEvent();
6930 ASSERT_NE(nullptr, event);
6931 std::unique_ptr<VerifiedInputEvent> verified = mDispatcher->verifyInputEvent(*event);
Siarhei Vishniakou47040bf2020-02-28 15:03:13 -08006932 ASSERT_NE(verified, nullptr);
6933 ASSERT_EQ(verified->type, VerifiedInputEvent::Type::MOTION);
6934
6935 EXPECT_EQ(motionArgs.eventTime, verified->eventTimeNanos);
6936 EXPECT_EQ(motionArgs.deviceId, verified->deviceId);
6937 EXPECT_EQ(motionArgs.source, verified->source);
6938 EXPECT_EQ(motionArgs.displayId, verified->displayId);
6939
6940 const VerifiedMotionEvent& verifiedMotion = static_cast<const VerifiedMotionEvent&>(*verified);
6941
Prabir Pradhanb5cb9572021-09-24 06:35:16 -07006942 const vec2 rawXY =
6943 MotionEvent::calculateTransformedXY(motionArgs.source, transform,
6944 motionArgs.pointerCoords[0].getXYValue());
6945 EXPECT_EQ(rawXY.x, verifiedMotion.rawX);
6946 EXPECT_EQ(rawXY.y, verifiedMotion.rawY);
Siarhei Vishniakou47040bf2020-02-28 15:03:13 -08006947 EXPECT_EQ(motionArgs.action & AMOTION_EVENT_ACTION_MASK, verifiedMotion.actionMasked);
Siarhei Vishniakou47040bf2020-02-28 15:03:13 -08006948 EXPECT_EQ(motionArgs.flags & VERIFIED_MOTION_EVENT_FLAGS, verifiedMotion.flags);
Siarhei Vishniakouf355bf92021-12-09 10:43:21 -08006949 EXPECT_EQ(motionArgs.downTime, verifiedMotion.downTimeNanos);
Siarhei Vishniakou47040bf2020-02-28 15:03:13 -08006950 EXPECT_EQ(motionArgs.metaState, verifiedMotion.metaState);
6951 EXPECT_EQ(motionArgs.buttonState, verifiedMotion.buttonState);
6952}
6953
chaviw09c8d2d2020-08-24 15:48:26 -07006954/**
6955 * Ensure that separate calls to sign the same data are generating the same key.
6956 * We avoid asserting against INVALID_HMAC. Since the key is random, there is a non-zero chance
6957 * that a specific key and data combination would produce INVALID_HMAC, which would cause flaky
6958 * tests.
6959 */
6960TEST_F(InputDispatcherTest, GeneratedHmac_IsConsistent) {
6961 KeyEvent event = getTestKeyEvent();
6962 VerifiedKeyEvent verifiedEvent = verifiedKeyEventFromKeyEvent(event);
6963
6964 std::array<uint8_t, 32> hmac1 = mDispatcher->sign(verifiedEvent);
6965 std::array<uint8_t, 32> hmac2 = mDispatcher->sign(verifiedEvent);
6966 ASSERT_EQ(hmac1, hmac2);
6967}
6968
6969/**
6970 * Ensure that changes in VerifiedKeyEvent produce a different hmac.
6971 */
6972TEST_F(InputDispatcherTest, GeneratedHmac_ChangesWhenFieldsChange) {
6973 KeyEvent event = getTestKeyEvent();
6974 VerifiedKeyEvent verifiedEvent = verifiedKeyEventFromKeyEvent(event);
6975 std::array<uint8_t, 32> initialHmac = mDispatcher->sign(verifiedEvent);
6976
6977 verifiedEvent.deviceId += 1;
6978 ASSERT_NE(initialHmac, mDispatcher->sign(verifiedEvent));
6979
6980 verifiedEvent.source += 1;
6981 ASSERT_NE(initialHmac, mDispatcher->sign(verifiedEvent));
6982
6983 verifiedEvent.eventTimeNanos += 1;
6984 ASSERT_NE(initialHmac, mDispatcher->sign(verifiedEvent));
6985
6986 verifiedEvent.displayId += 1;
6987 ASSERT_NE(initialHmac, mDispatcher->sign(verifiedEvent));
6988
6989 verifiedEvent.action += 1;
6990 ASSERT_NE(initialHmac, mDispatcher->sign(verifiedEvent));
6991
6992 verifiedEvent.downTimeNanos += 1;
6993 ASSERT_NE(initialHmac, mDispatcher->sign(verifiedEvent));
6994
6995 verifiedEvent.flags += 1;
6996 ASSERT_NE(initialHmac, mDispatcher->sign(verifiedEvent));
6997
6998 verifiedEvent.keyCode += 1;
6999 ASSERT_NE(initialHmac, mDispatcher->sign(verifiedEvent));
7000
7001 verifiedEvent.scanCode += 1;
7002 ASSERT_NE(initialHmac, mDispatcher->sign(verifiedEvent));
7003
7004 verifiedEvent.metaState += 1;
7005 ASSERT_NE(initialHmac, mDispatcher->sign(verifiedEvent));
7006
7007 verifiedEvent.repeatCount += 1;
7008 ASSERT_NE(initialHmac, mDispatcher->sign(verifiedEvent));
7009}
7010
Vishnu Nair958da932020-08-21 17:12:37 -07007011TEST_F(InputDispatcherTest, SetFocusedWindow) {
7012 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
7013 sp<FakeWindowHandle> windowTop =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07007014 sp<FakeWindowHandle>::make(application, mDispatcher, "Top", ADISPLAY_ID_DEFAULT);
Vishnu Nair958da932020-08-21 17:12:37 -07007015 sp<FakeWindowHandle> windowSecond =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07007016 sp<FakeWindowHandle>::make(application, mDispatcher, "Second", ADISPLAY_ID_DEFAULT);
Vishnu Nair958da932020-08-21 17:12:37 -07007017 mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application);
7018
7019 // Top window is also focusable but is not granted focus.
7020 windowTop->setFocusable(true);
7021 windowSecond->setFocusable(true);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07007022 mDispatcher->onWindowInfosChanged(
7023 {{*windowTop->getInfo(), *windowSecond->getInfo()}, {}, 0, 0});
Vishnu Nair958da932020-08-21 17:12:37 -07007024 setFocusedWindow(windowSecond);
7025
7026 windowSecond->consumeFocusEvent(true);
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07007027 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectKeyDown(*mDispatcher))
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08007028 << "Inject key event should return InputEventInjectionResult::SUCCEEDED";
Vishnu Nair958da932020-08-21 17:12:37 -07007029
7030 // Focused window should receive event.
7031 windowSecond->consumeKeyDown(ADISPLAY_ID_NONE);
7032 windowTop->assertNoEvents();
7033}
7034
7035TEST_F(InputDispatcherTest, SetFocusedWindow_DropRequestInvalidChannel) {
7036 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
7037 sp<FakeWindowHandle> window =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07007038 sp<FakeWindowHandle>::make(application, mDispatcher, "TestWindow", ADISPLAY_ID_DEFAULT);
Vishnu Nair958da932020-08-21 17:12:37 -07007039 mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application);
7040
7041 window->setFocusable(true);
7042 // Release channel for window is no longer valid.
7043 window->releaseChannel();
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07007044 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Vishnu Nair958da932020-08-21 17:12:37 -07007045 setFocusedWindow(window);
7046
7047 // Test inject a key down, should timeout.
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07007048 ASSERT_NO_FATAL_FAILURE(assertInjectedKeyTimesOut(*mDispatcher));
Vishnu Nair958da932020-08-21 17:12:37 -07007049
7050 // window channel is invalid, so it should not receive any input event.
7051 window->assertNoEvents();
7052}
7053
7054TEST_F(InputDispatcherTest, SetFocusedWindow_DropRequestNoFocusableWindow) {
7055 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
7056 sp<FakeWindowHandle> window =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07007057 sp<FakeWindowHandle>::make(application, mDispatcher, "TestWindow", ADISPLAY_ID_DEFAULT);
Prabir Pradhan76bdecb2022-01-31 11:14:15 -08007058 window->setFocusable(false);
Vishnu Nair958da932020-08-21 17:12:37 -07007059 mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application);
7060
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07007061 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Vishnu Nair958da932020-08-21 17:12:37 -07007062 setFocusedWindow(window);
7063
7064 // Test inject a key down, should timeout.
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07007065 ASSERT_NO_FATAL_FAILURE(assertInjectedKeyTimesOut(*mDispatcher));
Vishnu Nair958da932020-08-21 17:12:37 -07007066
Prabir Pradhan76bdecb2022-01-31 11:14:15 -08007067 // window is not focusable, so it should not receive any input event.
Vishnu Nair958da932020-08-21 17:12:37 -07007068 window->assertNoEvents();
7069}
7070
7071TEST_F(InputDispatcherTest, SetFocusedWindow_CheckFocusedToken) {
7072 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
7073 sp<FakeWindowHandle> windowTop =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07007074 sp<FakeWindowHandle>::make(application, mDispatcher, "Top", ADISPLAY_ID_DEFAULT);
Vishnu Nair958da932020-08-21 17:12:37 -07007075 sp<FakeWindowHandle> windowSecond =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07007076 sp<FakeWindowHandle>::make(application, mDispatcher, "Second", ADISPLAY_ID_DEFAULT);
Vishnu Nair958da932020-08-21 17:12:37 -07007077 mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application);
7078
7079 windowTop->setFocusable(true);
7080 windowSecond->setFocusable(true);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07007081 mDispatcher->onWindowInfosChanged(
7082 {{*windowTop->getInfo(), *windowSecond->getInfo()}, {}, 0, 0});
Vishnu Nair958da932020-08-21 17:12:37 -07007083 setFocusedWindow(windowTop);
7084 windowTop->consumeFocusEvent(true);
7085
Chavi Weingarten847e8512023-03-29 00:26:09 +00007086 windowTop->editInfo()->focusTransferTarget = windowSecond->getToken();
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07007087 mDispatcher->onWindowInfosChanged(
7088 {{*windowTop->getInfo(), *windowSecond->getInfo()}, {}, 0, 0});
Vishnu Nair958da932020-08-21 17:12:37 -07007089 windowSecond->consumeFocusEvent(true);
7090 windowTop->consumeFocusEvent(false);
7091
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07007092 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectKeyDown(*mDispatcher))
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08007093 << "Inject key event should return InputEventInjectionResult::SUCCEEDED";
Vishnu Nair958da932020-08-21 17:12:37 -07007094
7095 // Focused window should receive event.
7096 windowSecond->consumeKeyDown(ADISPLAY_ID_NONE);
7097}
7098
Chavi Weingarten847e8512023-03-29 00:26:09 +00007099TEST_F(InputDispatcherTest, SetFocusedWindow_TransferFocusTokenNotFocusable) {
Vishnu Nair958da932020-08-21 17:12:37 -07007100 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
7101 sp<FakeWindowHandle> windowTop =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07007102 sp<FakeWindowHandle>::make(application, mDispatcher, "Top", ADISPLAY_ID_DEFAULT);
Vishnu Nair958da932020-08-21 17:12:37 -07007103 sp<FakeWindowHandle> windowSecond =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07007104 sp<FakeWindowHandle>::make(application, mDispatcher, "Second", ADISPLAY_ID_DEFAULT);
Vishnu Nair958da932020-08-21 17:12:37 -07007105 mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application);
7106
7107 windowTop->setFocusable(true);
Chavi Weingarten847e8512023-03-29 00:26:09 +00007108 windowSecond->setFocusable(false);
7109 windowTop->editInfo()->focusTransferTarget = windowSecond->getToken();
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07007110 mDispatcher->onWindowInfosChanged(
7111 {{*windowTop->getInfo(), *windowSecond->getInfo()}, {}, 0, 0});
Chavi Weingarten847e8512023-03-29 00:26:09 +00007112 setFocusedWindow(windowTop);
7113 windowTop->consumeFocusEvent(true);
Vishnu Nair958da932020-08-21 17:12:37 -07007114
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07007115 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectKeyDown(*mDispatcher))
Chavi Weingarten847e8512023-03-29 00:26:09 +00007116 << "Inject key event should return InputEventInjectionResult::SUCCEEDED";
Vishnu Nair958da932020-08-21 17:12:37 -07007117
7118 // Event should be dropped.
Chavi Weingarten847e8512023-03-29 00:26:09 +00007119 windowTop->consumeKeyDown(ADISPLAY_ID_NONE);
Vishnu Nair958da932020-08-21 17:12:37 -07007120 windowSecond->assertNoEvents();
7121}
7122
7123TEST_F(InputDispatcherTest, SetFocusedWindow_DeferInvisibleWindow) {
7124 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
7125 sp<FakeWindowHandle> window =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07007126 sp<FakeWindowHandle>::make(application, mDispatcher, "TestWindow", ADISPLAY_ID_DEFAULT);
Vishnu Nair958da932020-08-21 17:12:37 -07007127 sp<FakeWindowHandle> previousFocusedWindow =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07007128 sp<FakeWindowHandle>::make(application, mDispatcher, "previousFocusedWindow",
7129 ADISPLAY_ID_DEFAULT);
Vishnu Nair958da932020-08-21 17:12:37 -07007130 mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application);
7131
7132 window->setFocusable(true);
7133 previousFocusedWindow->setFocusable(true);
7134 window->setVisible(false);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07007135 mDispatcher->onWindowInfosChanged(
7136 {{*window->getInfo(), *previousFocusedWindow->getInfo()}, {}, 0, 0});
Vishnu Nair958da932020-08-21 17:12:37 -07007137 setFocusedWindow(previousFocusedWindow);
7138 previousFocusedWindow->consumeFocusEvent(true);
7139
7140 // Requesting focus on invisible window takes focus from currently focused window.
7141 setFocusedWindow(window);
7142 previousFocusedWindow->consumeFocusEvent(false);
7143
7144 // Injected key goes to pending queue.
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08007145 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07007146 injectKey(*mDispatcher, AKEY_EVENT_ACTION_DOWN, /*repeatCount=*/0,
7147 ADISPLAY_ID_DEFAULT, InputEventInjectionSync::NONE));
Vishnu Nair958da932020-08-21 17:12:37 -07007148
7149 // Window does not get focus event or key down.
7150 window->assertNoEvents();
7151
7152 // Window becomes visible.
7153 window->setVisible(true);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07007154 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Vishnu Nair958da932020-08-21 17:12:37 -07007155
7156 // Window receives focus event.
7157 window->consumeFocusEvent(true);
7158 // Focused window receives key down.
7159 window->consumeKeyDown(ADISPLAY_ID_DEFAULT);
7160}
7161
Vishnu Nair599f1412021-06-21 10:39:58 -07007162TEST_F(InputDispatcherTest, DisplayRemoved) {
7163 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
7164 sp<FakeWindowHandle> window =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07007165 sp<FakeWindowHandle>::make(application, mDispatcher, "window", ADISPLAY_ID_DEFAULT);
Vishnu Nair599f1412021-06-21 10:39:58 -07007166 mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application);
7167
7168 // window is granted focus.
7169 window->setFocusable(true);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07007170 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Vishnu Nair599f1412021-06-21 10:39:58 -07007171 setFocusedWindow(window);
7172 window->consumeFocusEvent(true);
7173
7174 // When a display is removed window loses focus.
7175 mDispatcher->displayRemoved(ADISPLAY_ID_DEFAULT);
7176 window->consumeFocusEvent(false);
7177}
7178
Siarhei Vishniakou870ecec2020-12-09 08:07:46 -10007179/**
7180 * Launch two windows, with different owners. One window (slipperyExitWindow) has Flag::SLIPPERY,
7181 * and overlaps the other window, slipperyEnterWindow. The window 'slipperyExitWindow' is on top
7182 * of the 'slipperyEnterWindow'.
7183 *
7184 * Inject touch down into the top window. Upon receipt of the DOWN event, move the window in such
7185 * a way so that the touched location is no longer covered by the top window.
7186 *
7187 * Next, inject a MOVE event. Because the top window already moved earlier, this event is now
7188 * positioned over the bottom (slipperyEnterWindow) only. And because the top window had
7189 * Flag::SLIPPERY, this will cause the top window to lose the touch event (it will receive
7190 * ACTION_CANCEL instead), and the bottom window will receive a newly generated gesture (starting
7191 * with ACTION_DOWN).
7192 * Thus, the touch has been transferred from the top window into the bottom window, because the top
7193 * window moved itself away from the touched location and had Flag::SLIPPERY.
7194 *
7195 * Even though the top window moved away from the touched location, it is still obscuring the bottom
7196 * window. It's just not obscuring it at the touched location. That means, FLAG_WINDOW_IS_PARTIALLY_
7197 * OBSCURED should be set for the MotionEvent that reaches the bottom window.
7198 *
7199 * In this test, we ensure that the event received by the bottom window has
7200 * FLAG_WINDOW_IS_PARTIALLY_OBSCURED.
7201 */
7202TEST_F(InputDispatcherTest, SlipperyWindow_SetsFlagPartiallyObscured) {
Prabir Pradhanaeebeb42023-06-13 19:53:03 +00007203 constexpr gui::Pid SLIPPERY_PID{WINDOW_PID.val() + 1};
Prabir Pradhan8a5c41d2023-06-08 19:13:46 +00007204 constexpr gui::Uid SLIPPERY_UID{WINDOW_UID.val() + 1};
Siarhei Vishniakou870ecec2020-12-09 08:07:46 -10007205
7206 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
7207 mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application);
7208
7209 sp<FakeWindowHandle> slipperyExitWindow =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07007210 sp<FakeWindowHandle>::make(application, mDispatcher, "Top", ADISPLAY_ID_DEFAULT);
Prabir Pradhan4d5c52f2022-01-31 08:52:10 -08007211 slipperyExitWindow->setSlippery(true);
Siarhei Vishniakou870ecec2020-12-09 08:07:46 -10007212 // Make sure this one overlaps the bottom window
7213 slipperyExitWindow->setFrame(Rect(25, 25, 75, 75));
7214 // Change the owner uid/pid of the window so that it is considered to be occluding the bottom
7215 // one. Windows with the same owner are not considered to be occluding each other.
7216 slipperyExitWindow->setOwnerInfo(SLIPPERY_PID, SLIPPERY_UID);
7217
7218 sp<FakeWindowHandle> slipperyEnterWindow =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07007219 sp<FakeWindowHandle>::make(application, mDispatcher, "Second", ADISPLAY_ID_DEFAULT);
Siarhei Vishniakou870ecec2020-12-09 08:07:46 -10007220 slipperyExitWindow->setFrame(Rect(0, 0, 100, 100));
7221
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07007222 mDispatcher->onWindowInfosChanged(
7223 {{*slipperyExitWindow->getInfo(), *slipperyEnterWindow->getInfo()}, {}, 0, 0});
Siarhei Vishniakou870ecec2020-12-09 08:07:46 -10007224
7225 // Use notifyMotion instead of injecting to avoid dealing with injection permissions
Prabir Pradhan678438e2023-04-13 19:32:51 +00007226 mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_DOWN,
7227 AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
7228 {{50, 50}}));
Siarhei Vishniakou870ecec2020-12-09 08:07:46 -10007229 slipperyExitWindow->consumeMotionDown();
7230 slipperyExitWindow->setFrame(Rect(70, 70, 100, 100));
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07007231 mDispatcher->onWindowInfosChanged(
7232 {{*slipperyExitWindow->getInfo(), *slipperyEnterWindow->getInfo()}, {}, 0, 0});
Siarhei Vishniakou870ecec2020-12-09 08:07:46 -10007233
Prabir Pradhan678438e2023-04-13 19:32:51 +00007234 mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_MOVE,
7235 AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
7236 {{51, 51}}));
Siarhei Vishniakou870ecec2020-12-09 08:07:46 -10007237
7238 slipperyExitWindow->consumeMotionCancel();
7239
7240 slipperyEnterWindow->consumeMotionDown(ADISPLAY_ID_DEFAULT,
7241 AMOTION_EVENT_FLAG_WINDOW_IS_PARTIALLY_OBSCURED);
7242}
7243
Siarhei Vishniakouafa08cc2023-05-08 22:35:50 -07007244/**
7245 * Two windows, one on the left and another on the right. The left window is slippery. The right
7246 * window isn't eligible to receive touch because it specifies InputConfig::DROP_INPUT. When the
7247 * touch moves from the left window into the right window, the gesture should continue to go to the
7248 * left window. Touch shouldn't slip because the right window can't receive touches. This test
7249 * reproduces a crash.
7250 */
7251TEST_F(InputDispatcherTest, TouchSlippingIntoWindowThatDropsTouches) {
7252 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
7253
7254 sp<FakeWindowHandle> leftSlipperyWindow =
7255 sp<FakeWindowHandle>::make(application, mDispatcher, "Left", ADISPLAY_ID_DEFAULT);
7256 leftSlipperyWindow->setSlippery(true);
7257 leftSlipperyWindow->setFrame(Rect(0, 0, 100, 100));
7258
7259 sp<FakeWindowHandle> rightDropTouchesWindow =
7260 sp<FakeWindowHandle>::make(application, mDispatcher, "Right", ADISPLAY_ID_DEFAULT);
7261 rightDropTouchesWindow->setFrame(Rect(100, 0, 200, 100));
7262 rightDropTouchesWindow->setDropInput(true);
7263
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07007264 mDispatcher->onWindowInfosChanged(
7265 {{*leftSlipperyWindow->getInfo(), *rightDropTouchesWindow->getInfo()}, {}, 0, 0});
Siarhei Vishniakouafa08cc2023-05-08 22:35:50 -07007266
7267 // Start touch in the left window
7268 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
7269 .pointer(PointerBuilder(0, ToolType::FINGER).x(50).y(50))
7270 .build());
7271 leftSlipperyWindow->consumeMotionDown();
7272
7273 // And move it into the right window
7274 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN)
7275 .pointer(PointerBuilder(0, ToolType::FINGER).x(150).y(50))
7276 .build());
7277
7278 // Since the right window isn't eligible to receive input, touch does not slip.
7279 // The left window continues to receive the gesture.
7280 leftSlipperyWindow->consumeMotionEvent(WithMotionAction(ACTION_MOVE));
7281 rightDropTouchesWindow->assertNoEvents();
7282}
7283
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -07007284/**
7285 * A single window is on screen first. Touch is injected into that window. Next, a second window
7286 * appears. Since the first window is slippery, touch will move from the first window to the second.
7287 */
7288TEST_F(InputDispatcherTest, InjectedTouchSlips) {
7289 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
7290 sp<FakeWindowHandle> originalWindow =
7291 sp<FakeWindowHandle>::make(application, mDispatcher, "Original", ADISPLAY_ID_DEFAULT);
7292 originalWindow->setFrame(Rect(0, 0, 200, 200));
7293 originalWindow->setSlippery(true);
7294
7295 sp<FakeWindowHandle> appearingWindow =
7296 sp<FakeWindowHandle>::make(application, mDispatcher, "Appearing", ADISPLAY_ID_DEFAULT);
7297 appearingWindow->setFrame(Rect(0, 0, 200, 200));
7298
7299 mDispatcher->onWindowInfosChanged({{*originalWindow->getInfo()}, {}, 0, 0});
7300
7301 // Touch down on the original window
7302 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
7303 injectMotionEvent(*mDispatcher,
7304 MotionEventBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
7305 .pointer(PointerBuilder(1, ToolType::FINGER).x(100).y(100))
7306 .build()));
7307 originalWindow->consumeMotionEvent(WithMotionAction(ACTION_DOWN));
7308
7309 // Now, a new window appears. This could be, for example, a notification shade that appears
7310 // after user starts to drag down on the launcher window.
7311 mDispatcher->onWindowInfosChanged(
7312 {{*appearingWindow->getInfo(), *originalWindow->getInfo()}, {}, 0, 0});
7313 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
7314 injectMotionEvent(*mDispatcher,
7315 MotionEventBuilder(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN)
7316 .pointer(PointerBuilder(1, ToolType::FINGER).x(110).y(110))
7317 .build()));
7318 originalWindow->consumeMotionEvent(WithMotionAction(ACTION_CANCEL));
7319 appearingWindow->consumeMotionEvent(WithMotionAction(ACTION_DOWN));
7320 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
7321 injectMotionEvent(*mDispatcher,
7322 MotionEventBuilder(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN)
7323 .pointer(PointerBuilder(1, ToolType::FINGER).x(120).y(120))
7324 .build()));
7325 appearingWindow->consumeMotionEvent(WithMotionAction(ACTION_MOVE));
7326
7327 originalWindow->assertNoEvents();
7328 appearingWindow->assertNoEvents();
7329}
7330
Linnan Li49b2b202024-04-12 12:46:40 +08007331/**
7332 * Three windows:
7333 * - left window, which has FLAG_SLIPPERY, so it supports slippery exit
7334 * - right window
7335 * - spy window
7336 * The three windows do not overlap.
7337 *
7338 * We have two devices reporting events:
7339 * - Device A reports ACTION_DOWN, which lands in the left window
7340 * - Device B reports ACTION_DOWN, which lands in the spy window.
7341 * - Now, device B reports ACTION_MOVE events which move to the right window.
7342 *
7343 * The right window should not receive any events because the spy window is not a foreground window,
7344 * and also it does not support slippery touches.
7345 */
7346TEST_F(InputDispatcherTest, MultiDeviceSpyWindowSlipTest) {
7347 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
7348 sp<FakeWindowHandle> leftWindow =
7349 sp<FakeWindowHandle>::make(application, mDispatcher, "Left window",
7350 ADISPLAY_ID_DEFAULT);
7351 leftWindow->setFrame(Rect(0, 0, 100, 100));
7352 leftWindow->setSlippery(true);
7353
7354 sp<FakeWindowHandle> rightWindow =
7355 sp<FakeWindowHandle>::make(application, mDispatcher, "Right window",
7356 ADISPLAY_ID_DEFAULT);
7357 rightWindow->setFrame(Rect(100, 0, 200, 100));
7358
7359 sp<FakeWindowHandle> spyWindow =
7360 sp<FakeWindowHandle>::make(application, mDispatcher, "Spy Window", ADISPLAY_ID_DEFAULT);
7361 spyWindow->setFrame(Rect(200, 0, 300, 100));
7362 spyWindow->setSpy(true);
7363 spyWindow->setTrustedOverlay(true);
7364
7365 mDispatcher->onWindowInfosChanged(
7366 {{*leftWindow->getInfo(), *rightWindow->getInfo(), *spyWindow->getInfo()}, {}, 0, 0});
7367
7368 const DeviceId deviceA = 9;
7369 const DeviceId deviceB = 3;
7370
7371 // Tap on left window with device A
7372 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
7373 .pointer(PointerBuilder(0, ToolType::FINGER).x(50).y(50))
7374 .deviceId(deviceA)
7375 .build());
7376 leftWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(deviceA)));
7377
7378 // Tap on spy window with device B
7379 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
7380 .pointer(PointerBuilder(0, ToolType::FINGER).x(250).y(50))
7381 .deviceId(deviceB)
7382 .build());
7383 spyWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(deviceB)));
7384
7385 // Move to right window with device B. Touches should not slip to the right window, because spy
7386 // window is not a foreground window, and it does not have FLAG_SLIPPERY
7387 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN)
7388 .pointer(PointerBuilder(0, ToolType::FINGER).x(150).y(50))
7389 .deviceId(deviceB)
7390 .build());
7391 leftWindow->assertNoEvents();
7392 rightWindow->assertNoEvents();
7393 spyWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(deviceB)));
7394}
7395
7396/**
7397 * Three windows arranged horizontally and without any overlap.
7398 * The left and right windows have FLAG_SLIPPERY. The middle window does not have any special flags.
7399 *
7400 * We have two devices reporting events:
7401 * - Device A reports ACTION_DOWN which lands in the left window
7402 * - Device B reports ACTION_DOWN which lands in the right window
7403 * - Device B reports ACTION_MOVE that shifts to the middle window.
7404 * This should cause touches for Device B to slip from the right window to the middle window.
7405 * The right window should receive ACTION_CANCEL for device B and the
7406 * middle window should receive down event for Device B.
7407 * If device B reports more ACTION_MOVE events, the middle window should receive remaining events.
7408 */
7409TEST_F(InputDispatcherTest, MultiDeviceSlipperyWindowTest) {
7410 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
7411 sp<FakeWindowHandle> leftWindow =
7412 sp<FakeWindowHandle>::make(application, mDispatcher, "Left window",
7413 ADISPLAY_ID_DEFAULT);
7414 leftWindow->setFrame(Rect(0, 0, 100, 100));
7415 leftWindow->setSlippery(true);
7416
7417 sp<FakeWindowHandle> middleWindow =
7418 sp<FakeWindowHandle>::make(application, mDispatcher, "middle window",
7419 ADISPLAY_ID_DEFAULT);
7420 middleWindow->setFrame(Rect(100, 0, 200, 100));
7421
7422 sp<FakeWindowHandle> rightWindow =
7423 sp<FakeWindowHandle>::make(application, mDispatcher, "Right window",
7424 ADISPLAY_ID_DEFAULT);
7425 rightWindow->setFrame(Rect(200, 0, 300, 100));
7426 rightWindow->setSlippery(true);
7427
7428 mDispatcher->onWindowInfosChanged(
7429 {{*leftWindow->getInfo(), *middleWindow->getInfo(), *rightWindow->getInfo()},
7430 {},
7431 0,
7432 0});
7433
7434 const DeviceId deviceA = 9;
7435 const DeviceId deviceB = 3;
7436
7437 // Tap on left window with device A
7438 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
7439 .pointer(PointerBuilder(0, ToolType::FINGER).x(50).y(50))
7440 .deviceId(deviceA)
7441 .build());
7442 leftWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(deviceA)));
7443
7444 // Tap on right window with device B
7445 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
7446 .pointer(PointerBuilder(0, ToolType::FINGER).x(250).y(50))
7447 .deviceId(deviceB)
7448 .build());
7449 rightWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(deviceB)));
7450
7451 // Move to middle window with device B. Touches should slip to middle window, because right
7452 // window is a foreground window that's associated with device B and has FLAG_SLIPPERY.
7453 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN)
7454 .pointer(PointerBuilder(0, ToolType::FINGER).x(150).y(50))
7455 .deviceId(deviceB)
7456 .build());
7457 rightWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_CANCEL), WithDeviceId(deviceB)));
7458 middleWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(deviceB)));
7459
7460 // Move to middle window with device A. Touches should slip to middle window, because left
7461 // window is a foreground window that's associated with device A and has FLAG_SLIPPERY.
7462 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN)
7463 .pointer(PointerBuilder(0, ToolType::FINGER).x(150).y(50))
7464 .deviceId(deviceA)
7465 .build());
7466 leftWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_CANCEL), WithDeviceId(deviceA)));
7467 middleWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(deviceA)));
7468
7469 // Ensure that middle window can receive the remaining move events.
7470 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN)
7471 .pointer(PointerBuilder(0, ToolType::FINGER).x(151).y(51))
7472 .deviceId(deviceB)
7473 .build());
7474 leftWindow->assertNoEvents();
7475 middleWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(deviceB)));
7476 rightWindow->assertNoEvents();
7477}
7478
Prabir Pradhan8ede1d12023-05-08 19:37:44 +00007479TEST_F(InputDispatcherTest, NotifiesDeviceInteractionsWithMotions) {
Prabir Pradhan8a5c41d2023-06-08 19:13:46 +00007480 using Uid = gui::Uid;
Prabir Pradhan8ede1d12023-05-08 19:37:44 +00007481 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
7482
7483 sp<FakeWindowHandle> leftWindow =
7484 sp<FakeWindowHandle>::make(application, mDispatcher, "Left", ADISPLAY_ID_DEFAULT);
7485 leftWindow->setFrame(Rect(0, 0, 100, 100));
Prabir Pradhanaeebeb42023-06-13 19:53:03 +00007486 leftWindow->setOwnerInfo(gui::Pid{1}, Uid{101});
Prabir Pradhan8ede1d12023-05-08 19:37:44 +00007487
7488 sp<FakeWindowHandle> rightSpy =
7489 sp<FakeWindowHandle>::make(application, mDispatcher, "Right spy", ADISPLAY_ID_DEFAULT);
7490 rightSpy->setFrame(Rect(100, 0, 200, 100));
Prabir Pradhanaeebeb42023-06-13 19:53:03 +00007491 rightSpy->setOwnerInfo(gui::Pid{2}, Uid{102});
Prabir Pradhan8ede1d12023-05-08 19:37:44 +00007492 rightSpy->setSpy(true);
7493 rightSpy->setTrustedOverlay(true);
7494
7495 sp<FakeWindowHandle> rightWindow =
7496 sp<FakeWindowHandle>::make(application, mDispatcher, "Right", ADISPLAY_ID_DEFAULT);
7497 rightWindow->setFrame(Rect(100, 0, 200, 100));
Prabir Pradhanaeebeb42023-06-13 19:53:03 +00007498 rightWindow->setOwnerInfo(gui::Pid{3}, Uid{103});
Prabir Pradhan8ede1d12023-05-08 19:37:44 +00007499
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07007500 mDispatcher->onWindowInfosChanged(
7501 {{*rightSpy->getInfo(), *rightWindow->getInfo(), *leftWindow->getInfo()}, {}, 0, 0});
Prabir Pradhan8ede1d12023-05-08 19:37:44 +00007502
7503 // Touch in the left window
7504 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
7505 .pointer(PointerBuilder(0, ToolType::FINGER).x(50).y(50))
7506 .build());
7507 ASSERT_NO_FATAL_FAILURE(leftWindow->consumeMotionDown());
7508 mDispatcher->waitForIdle();
Prabir Pradhan8a5c41d2023-06-08 19:13:46 +00007509 ASSERT_NO_FATAL_FAILURE(
7510 mFakePolicy->assertNotifyDeviceInteractionWasCalled(DEVICE_ID, {Uid{101}}));
Prabir Pradhan8ede1d12023-05-08 19:37:44 +00007511
7512 // Touch another finger over the right windows
7513 mDispatcher->notifyMotion(MotionArgsBuilder(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
7514 .pointer(PointerBuilder(0, ToolType::FINGER).x(50).y(50))
7515 .pointer(PointerBuilder(1, ToolType::FINGER).x(150).y(50))
7516 .build());
7517 ASSERT_NO_FATAL_FAILURE(rightSpy->consumeMotionDown());
7518 ASSERT_NO_FATAL_FAILURE(rightWindow->consumeMotionDown());
7519 ASSERT_NO_FATAL_FAILURE(leftWindow->consumeMotionMove());
7520 mDispatcher->waitForIdle();
7521 ASSERT_NO_FATAL_FAILURE(
Prabir Pradhan8a5c41d2023-06-08 19:13:46 +00007522 mFakePolicy->assertNotifyDeviceInteractionWasCalled(DEVICE_ID,
7523 {Uid{101}, Uid{102}, Uid{103}}));
Prabir Pradhan8ede1d12023-05-08 19:37:44 +00007524
7525 // Release finger over left window. The UP actions are not treated as device interaction.
7526 // The windows that did not receive the UP pointer will receive MOVE events, but since this
7527 // is part of the UP action, we do not treat this as device interaction.
7528 mDispatcher->notifyMotion(MotionArgsBuilder(POINTER_0_UP, AINPUT_SOURCE_TOUCHSCREEN)
7529 .pointer(PointerBuilder(0, ToolType::FINGER).x(50).y(50))
7530 .pointer(PointerBuilder(1, ToolType::FINGER).x(150).y(50))
7531 .build());
7532 ASSERT_NO_FATAL_FAILURE(leftWindow->consumeMotionUp());
7533 ASSERT_NO_FATAL_FAILURE(rightSpy->consumeMotionMove());
7534 ASSERT_NO_FATAL_FAILURE(rightWindow->consumeMotionMove());
7535 mDispatcher->waitForIdle();
7536 ASSERT_NO_FATAL_FAILURE(mFakePolicy->assertNotifyDeviceInteractionWasNotCalled());
7537
7538 // Move remaining finger
7539 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN)
7540 .pointer(PointerBuilder(1, ToolType::FINGER).x(150).y(50))
7541 .build());
7542 ASSERT_NO_FATAL_FAILURE(rightSpy->consumeMotionMove());
7543 ASSERT_NO_FATAL_FAILURE(rightWindow->consumeMotionMove());
7544 mDispatcher->waitForIdle();
7545 ASSERT_NO_FATAL_FAILURE(
Prabir Pradhan8a5c41d2023-06-08 19:13:46 +00007546 mFakePolicy->assertNotifyDeviceInteractionWasCalled(DEVICE_ID, {Uid{102}, Uid{103}}));
Prabir Pradhan8ede1d12023-05-08 19:37:44 +00007547
7548 // Release all fingers
7549 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN)
7550 .pointer(PointerBuilder(1, ToolType::FINGER).x(150).y(50))
7551 .build());
7552 ASSERT_NO_FATAL_FAILURE(rightSpy->consumeMotionUp());
7553 ASSERT_NO_FATAL_FAILURE(rightWindow->consumeMotionUp());
7554 mDispatcher->waitForIdle();
7555 ASSERT_NO_FATAL_FAILURE(mFakePolicy->assertNotifyDeviceInteractionWasNotCalled());
7556}
7557
7558TEST_F(InputDispatcherTest, NotifiesDeviceInteractionsWithKeys) {
7559 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
7560
7561 sp<FakeWindowHandle> window =
7562 sp<FakeWindowHandle>::make(application, mDispatcher, "Window", ADISPLAY_ID_DEFAULT);
7563 window->setFrame(Rect(0, 0, 100, 100));
Prabir Pradhanaeebeb42023-06-13 19:53:03 +00007564 window->setOwnerInfo(gui::Pid{1}, gui::Uid{101});
Prabir Pradhan8ede1d12023-05-08 19:37:44 +00007565
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07007566 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Prabir Pradhan8ede1d12023-05-08 19:37:44 +00007567 setFocusedWindow(window);
7568 ASSERT_NO_FATAL_FAILURE(window->consumeFocusEvent(true));
7569
7570 mDispatcher->notifyKey(KeyArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_KEYBOARD).build());
7571 ASSERT_NO_FATAL_FAILURE(window->consumeKeyDown(ADISPLAY_ID_DEFAULT));
7572 mDispatcher->waitForIdle();
Prabir Pradhan8a5c41d2023-06-08 19:13:46 +00007573 ASSERT_NO_FATAL_FAILURE(
7574 mFakePolicy->assertNotifyDeviceInteractionWasCalled(DEVICE_ID, {gui::Uid{101}}));
Prabir Pradhan8ede1d12023-05-08 19:37:44 +00007575
7576 // The UP actions are not treated as device interaction.
7577 mDispatcher->notifyKey(KeyArgsBuilder(ACTION_UP, AINPUT_SOURCE_KEYBOARD).build());
7578 ASSERT_NO_FATAL_FAILURE(window->consumeKeyUp(ADISPLAY_ID_DEFAULT));
7579 mDispatcher->waitForIdle();
7580 ASSERT_NO_FATAL_FAILURE(mFakePolicy->assertNotifyDeviceInteractionWasNotCalled());
7581}
7582
Prabir Pradhan5893d362023-11-17 04:30:40 +00007583TEST_F(InputDispatcherTest, HoverEnterExitSynthesisUsesNewEventId) {
7584 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
7585
7586 sp<FakeWindowHandle> left = sp<FakeWindowHandle>::make(application, mDispatcher, "Left Window",
7587 ADISPLAY_ID_DEFAULT);
7588 left->setFrame(Rect(0, 0, 100, 100));
7589 sp<FakeWindowHandle> right = sp<FakeWindowHandle>::make(application, mDispatcher,
7590 "Right Window", ADISPLAY_ID_DEFAULT);
7591 right->setFrame(Rect(100, 0, 200, 100));
7592 sp<FakeWindowHandle> spy =
7593 sp<FakeWindowHandle>::make(application, mDispatcher, "Spy Window", ADISPLAY_ID_DEFAULT);
7594 spy->setFrame(Rect(0, 0, 200, 100));
7595 spy->setTrustedOverlay(true);
7596 spy->setSpy(true);
7597
7598 mDispatcher->onWindowInfosChanged(
7599 {{*spy->getInfo(), *left->getInfo(), *right->getInfo()}, {}, 0, 0});
7600
7601 // Send hover move to the left window, and ensure hover enter is synthesized with a new eventId.
7602 NotifyMotionArgs notifyArgs = generateMotionArgs(ACTION_HOVER_MOVE, AINPUT_SOURCE_STYLUS,
7603 ADISPLAY_ID_DEFAULT, {PointF{50, 50}});
7604 mDispatcher->notifyMotion(notifyArgs);
7605
Siarhei Vishniakoud3061ab2023-12-18 20:41:08 -08007606 std::unique_ptr<MotionEvent> leftEnter = left->consumeMotionEvent(
Prabir Pradhan5893d362023-11-17 04:30:40 +00007607 AllOf(WithMotionAction(ACTION_HOVER_ENTER), Not(WithEventId(notifyArgs.id)),
7608 WithEventIdSource(IdGenerator::Source::INPUT_DISPATCHER)));
Siarhei Vishniakoud3061ab2023-12-18 20:41:08 -08007609 ASSERT_NE(nullptr, leftEnter);
Prabir Pradhan5893d362023-11-17 04:30:40 +00007610 spy->consumeMotionEvent(AllOf(WithMotionAction(ACTION_HOVER_ENTER),
7611 Not(WithEventId(notifyArgs.id)),
Siarhei Vishniakoud3061ab2023-12-18 20:41:08 -08007612 Not(WithEventId(leftEnter->getId())),
Prabir Pradhan5893d362023-11-17 04:30:40 +00007613 WithEventIdSource(IdGenerator::Source::INPUT_DISPATCHER)));
7614
7615 // Send move to the right window, and ensure hover exit and enter are synthesized with new ids.
7616 notifyArgs = generateMotionArgs(ACTION_HOVER_MOVE, AINPUT_SOURCE_STYLUS, ADISPLAY_ID_DEFAULT,
7617 {PointF{150, 50}});
7618 mDispatcher->notifyMotion(notifyArgs);
7619
Siarhei Vishniakoud3061ab2023-12-18 20:41:08 -08007620 std::unique_ptr<MotionEvent> leftExit = left->consumeMotionEvent(
Prabir Pradhan5893d362023-11-17 04:30:40 +00007621 AllOf(WithMotionAction(ACTION_HOVER_EXIT), Not(WithEventId(notifyArgs.id)),
7622 WithEventIdSource(IdGenerator::Source::INPUT_DISPATCHER)));
Siarhei Vishniakoud3061ab2023-12-18 20:41:08 -08007623 ASSERT_NE(nullptr, leftExit);
Prabir Pradhan5893d362023-11-17 04:30:40 +00007624 right->consumeMotionEvent(AllOf(WithMotionAction(ACTION_HOVER_ENTER),
7625 Not(WithEventId(notifyArgs.id)),
Siarhei Vishniakoud3061ab2023-12-18 20:41:08 -08007626 Not(WithEventId(leftExit->getId())),
Prabir Pradhan5893d362023-11-17 04:30:40 +00007627 WithEventIdSource(IdGenerator::Source::INPUT_DISPATCHER)));
7628
7629 spy->consumeMotionEvent(AllOf(WithMotionAction(ACTION_HOVER_MOVE), WithEventId(notifyArgs.id)));
7630}
7631
Linnan Liccf6ce32024-04-11 20:32:13 +08007632/**
7633 * When a device reports a DOWN event, which lands in a window that supports splits, and then the
7634 * device then reports a POINTER_DOWN, which lands in the location of a non-existing window, then
7635 * the previous window should receive this event and not be dropped.
7636 */
7637TEST_F(InputDispatcherMultiDeviceTest, SingleDevicePointerDownEventRetentionWithoutWindowTarget) {
7638 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
7639 sp<FakeWindowHandle> window =
7640 sp<FakeWindowHandle>::make(application, mDispatcher, "Window", ADISPLAY_ID_DEFAULT);
7641 window->setFrame(Rect(0, 0, 100, 100));
7642 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
7643
7644 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
7645 .pointer(PointerBuilder(0, ToolType::FINGER).x(50).y(50))
7646 .build());
7647
7648 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN)));
7649
7650 mDispatcher->notifyMotion(MotionArgsBuilder(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
7651 .pointer(PointerBuilder(0, ToolType::FINGER).x(50).y(50))
7652 .pointer(PointerBuilder(1, ToolType::FINGER).x(200).y(200))
7653 .build());
7654
7655 window->consumeMotionEvent(AllOf(WithMotionAction(POINTER_1_DOWN)));
7656}
7657
7658/**
7659 * When deviceA reports a DOWN event, which lands in a window that supports splits, and then deviceB
7660 * also reports a DOWN event, which lands in the location of a non-existing window, then the
7661 * previous window should receive deviceB's event and it should be dropped.
7662 */
7663TEST_F(InputDispatcherMultiDeviceTest, SecondDeviceDownEventDroppedWithoutWindowTarget) {
7664 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
7665 sp<FakeWindowHandle> window =
7666 sp<FakeWindowHandle>::make(application, mDispatcher, "Window", ADISPLAY_ID_DEFAULT);
7667 window->setFrame(Rect(0, 0, 100, 100));
7668 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
7669
7670 const DeviceId deviceA = 9;
7671 const DeviceId deviceB = 3;
7672
7673 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
7674 .pointer(PointerBuilder(0, ToolType::FINGER).x(50).y(50))
7675 .deviceId(deviceA)
7676 .build());
7677 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(deviceA)));
7678
7679 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
7680 .pointer(PointerBuilder(0, ToolType::FINGER).x(200).y(200))
7681 .deviceId(deviceB)
7682 .build());
7683 window->assertNoEvents();
7684}
7685
Prabir Pradhanb0dad3a2023-11-02 20:52:47 +00007686class InputDispatcherFallbackKeyTest : public InputDispatcherTest {
7687protected:
7688 std::shared_ptr<FakeApplicationHandle> mApp;
7689 sp<FakeWindowHandle> mWindow;
7690
7691 virtual void SetUp() override {
7692 InputDispatcherTest::SetUp();
7693
7694 mApp = std::make_shared<FakeApplicationHandle>();
7695
7696 mWindow = sp<FakeWindowHandle>::make(mApp, mDispatcher, "Window", ADISPLAY_ID_DEFAULT);
7697 mWindow->setFrame(Rect(0, 0, 100, 100));
7698
7699 mDispatcher->onWindowInfosChanged({{*mWindow->getInfo()}, {}, 0, 0});
7700 setFocusedWindow(mWindow);
7701 ASSERT_NO_FATAL_FAILURE(mWindow->consumeFocusEvent(/*hasFocus=*/true));
7702 }
7703
7704 void setFallback(int32_t keycode) {
7705 mFakePolicy->setUnhandledKeyHandler([keycode](const KeyEvent& event) {
7706 return KeyEventBuilder(event).keyCode(keycode).build();
7707 });
7708 }
7709
7710 void consumeKey(bool handled, const ::testing::Matcher<KeyEvent>& matcher) {
Siarhei Vishniakoud3061ab2023-12-18 20:41:08 -08007711 std::unique_ptr<KeyEvent> event = mWindow->consumeKey(handled);
7712 ASSERT_NE(nullptr, event);
7713 ASSERT_THAT(*event, matcher);
Prabir Pradhanb0dad3a2023-11-02 20:52:47 +00007714 }
7715};
7716
7717TEST_F(InputDispatcherFallbackKeyTest, PolicyNotNotifiedForHandledKey) {
7718 mDispatcher->notifyKey(
7719 KeyArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_KEYBOARD).keyCode(AKEYCODE_A).build());
7720 consumeKey(/*handled=*/true, AllOf(WithKeyAction(ACTION_DOWN), WithKeyCode(AKEYCODE_A)));
7721 ASSERT_NO_FATAL_FAILURE(mFakePolicy->assertUnhandledKeyNotReported());
7722}
7723
7724TEST_F(InputDispatcherFallbackKeyTest, PolicyNotifiedForUnhandledKey) {
7725 mDispatcher->notifyKey(
7726 KeyArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_KEYBOARD).keyCode(AKEYCODE_A).build());
7727 consumeKey(/*handled=*/false, AllOf(WithKeyAction(ACTION_DOWN), WithKeyCode(AKEYCODE_A)));
7728 ASSERT_NO_FATAL_FAILURE(mFakePolicy->assertUnhandledKeyReported(AKEYCODE_A));
7729}
7730
7731TEST_F(InputDispatcherFallbackKeyTest, NoFallbackRequestedByPolicy) {
7732 mDispatcher->notifyKey(
7733 KeyArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_KEYBOARD).keyCode(AKEYCODE_A).build());
7734
7735 // Do not handle this key event.
7736 consumeKey(/*handled=*/false,
7737 AllOf(WithKeyAction(ACTION_DOWN), WithKeyCode(AKEYCODE_A), WithFlags(0)));
7738 ASSERT_NO_FATAL_FAILURE(mFakePolicy->assertUnhandledKeyReported(AKEYCODE_A));
7739
7740 // Since the policy did not request any fallback to be generated, ensure there are no events.
7741 ASSERT_NO_FATAL_FAILURE(mFakePolicy->assertUnhandledKeyNotReported());
7742}
7743
7744TEST_F(InputDispatcherFallbackKeyTest, FallbackDispatchForUnhandledKey) {
7745 setFallback(AKEYCODE_B);
7746 mDispatcher->notifyKey(
7747 KeyArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_KEYBOARD).keyCode(AKEYCODE_A).build());
7748
7749 // Do not handle this key event.
7750 consumeKey(/*handled=*/false,
7751 AllOf(WithKeyAction(ACTION_DOWN), WithKeyCode(AKEYCODE_A), WithFlags(0)));
7752
7753 // Since the key was not handled, ensure the fallback event was dispatched instead.
7754 ASSERT_NO_FATAL_FAILURE(mFakePolicy->assertUnhandledKeyReported(AKEYCODE_A));
7755 consumeKey(/*handled=*/true,
7756 AllOf(WithKeyAction(ACTION_DOWN), WithKeyCode(AKEYCODE_B),
7757 WithFlags(AKEY_EVENT_FLAG_FALLBACK)));
7758
7759 // Release the original key, and ensure the fallback key is also released.
7760 mDispatcher->notifyKey(
7761 KeyArgsBuilder(ACTION_UP, AINPUT_SOURCE_KEYBOARD).keyCode(AKEYCODE_A).build());
7762 consumeKey(/*handled=*/false,
7763 AllOf(WithKeyAction(ACTION_UP), WithKeyCode(AKEYCODE_A), WithFlags(0)));
7764 ASSERT_NO_FATAL_FAILURE(mFakePolicy->assertUnhandledKeyReported(AKEYCODE_A));
7765 consumeKey(/*handled=*/true,
7766 AllOf(WithKeyAction(ACTION_UP), WithKeyCode(AKEYCODE_B),
7767 WithFlags(AKEY_EVENT_FLAG_FALLBACK)));
7768
7769 ASSERT_NO_FATAL_FAILURE(mFakePolicy->assertUnhandledKeyNotReported());
7770 mWindow->assertNoEvents();
7771}
7772
7773TEST_F(InputDispatcherFallbackKeyTest, AppHandlesPreviouslyUnhandledKey) {
7774 setFallback(AKEYCODE_B);
7775 mDispatcher->notifyKey(
7776 KeyArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_KEYBOARD).keyCode(AKEYCODE_A).build());
7777
7778 // Do not handle this key event, but handle the fallback.
7779 consumeKey(/*handled=*/false,
7780 AllOf(WithKeyAction(ACTION_DOWN), WithKeyCode(AKEYCODE_A), WithFlags(0)));
7781 ASSERT_NO_FATAL_FAILURE(mFakePolicy->assertUnhandledKeyReported(AKEYCODE_A));
7782 consumeKey(/*handled=*/true,
7783 AllOf(WithKeyAction(ACTION_DOWN), WithKeyCode(AKEYCODE_B),
7784 WithFlags(AKEY_EVENT_FLAG_FALLBACK)));
7785
7786 // Release the original key, and ensure the fallback key is also released.
7787 mDispatcher->notifyKey(
7788 KeyArgsBuilder(ACTION_UP, AINPUT_SOURCE_KEYBOARD).keyCode(AKEYCODE_A).build());
7789 // But this time, the app handles the original key.
7790 consumeKey(/*handled=*/true,
7791 AllOf(WithKeyAction(ACTION_UP), WithKeyCode(AKEYCODE_A), WithFlags(0)));
7792 ASSERT_NO_FATAL_FAILURE(mFakePolicy->assertUnhandledKeyReported(AKEYCODE_A));
7793 // Ensure the fallback key is canceled.
7794 consumeKey(/*handled=*/true,
7795 AllOf(WithKeyAction(ACTION_UP), WithKeyCode(AKEYCODE_B),
7796 WithFlags(AKEY_EVENT_FLAG_FALLBACK | AKEY_EVENT_FLAG_CANCELED)));
7797
7798 ASSERT_NO_FATAL_FAILURE(mFakePolicy->assertUnhandledKeyNotReported());
7799 mWindow->assertNoEvents();
7800}
7801
7802TEST_F(InputDispatcherFallbackKeyTest, AppDoesNotHandleFallback) {
7803 setFallback(AKEYCODE_B);
7804 mDispatcher->notifyKey(
7805 KeyArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_KEYBOARD).keyCode(AKEYCODE_A).build());
7806
7807 // Do not handle this key event.
7808 consumeKey(/*handled=*/false,
7809 AllOf(WithKeyAction(ACTION_DOWN), WithKeyCode(AKEYCODE_A), WithFlags(0)));
7810 ASSERT_NO_FATAL_FAILURE(mFakePolicy->assertUnhandledKeyReported(AKEYCODE_A));
7811 // App does not handle the fallback either, so ensure another fallback is not generated.
7812 setFallback(AKEYCODE_C);
7813 consumeKey(/*handled=*/false,
7814 AllOf(WithKeyAction(ACTION_DOWN), WithKeyCode(AKEYCODE_B),
7815 WithFlags(AKEY_EVENT_FLAG_FALLBACK)));
7816
7817 // Release the original key, and ensure the fallback key is also released.
7818 setFallback(AKEYCODE_B);
7819 mDispatcher->notifyKey(
7820 KeyArgsBuilder(ACTION_UP, AINPUT_SOURCE_KEYBOARD).keyCode(AKEYCODE_A).build());
7821 consumeKey(/*handled=*/false,
7822 AllOf(WithKeyAction(ACTION_UP), WithKeyCode(AKEYCODE_A), WithFlags(0)));
7823 ASSERT_NO_FATAL_FAILURE(mFakePolicy->assertUnhandledKeyReported(AKEYCODE_A));
7824 consumeKey(/*handled=*/false,
7825 AllOf(WithKeyAction(ACTION_UP), WithKeyCode(AKEYCODE_B),
7826 WithFlags(AKEY_EVENT_FLAG_FALLBACK)));
7827
7828 ASSERT_NO_FATAL_FAILURE(mFakePolicy->assertUnhandledKeyNotReported());
7829 mWindow->assertNoEvents();
7830}
7831
7832TEST_F(InputDispatcherFallbackKeyTest, InconsistentPolicyCancelsFallback) {
7833 setFallback(AKEYCODE_B);
7834 mDispatcher->notifyKey(
7835 KeyArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_KEYBOARD).keyCode(AKEYCODE_A).build());
7836
7837 // Do not handle this key event, so fallback is generated.
7838 consumeKey(/*handled=*/false,
7839 AllOf(WithKeyAction(ACTION_DOWN), WithKeyCode(AKEYCODE_A), WithFlags(0)));
7840 ASSERT_NO_FATAL_FAILURE(mFakePolicy->assertUnhandledKeyReported(AKEYCODE_A));
7841 consumeKey(/*handled=*/true,
7842 AllOf(WithKeyAction(ACTION_DOWN), WithKeyCode(AKEYCODE_B),
7843 WithFlags(AKEY_EVENT_FLAG_FALLBACK)));
7844
7845 // Release the original key, but assume the policy is misbehaving and it
7846 // generates an inconsistent fallback to the one from the DOWN event.
7847 setFallback(AKEYCODE_C);
7848 mDispatcher->notifyKey(
7849 KeyArgsBuilder(ACTION_UP, AINPUT_SOURCE_KEYBOARD).keyCode(AKEYCODE_A).build());
7850 consumeKey(/*handled=*/false,
7851 AllOf(WithKeyAction(ACTION_UP), WithKeyCode(AKEYCODE_A), WithFlags(0)));
7852 ASSERT_NO_FATAL_FAILURE(mFakePolicy->assertUnhandledKeyReported(AKEYCODE_A));
7853 // Ensure the fallback key reported before as DOWN is canceled due to the inconsistency.
7854 consumeKey(/*handled=*/true,
7855 AllOf(WithKeyAction(ACTION_UP), WithKeyCode(AKEYCODE_B),
7856 WithFlags(AKEY_EVENT_FLAG_FALLBACK | AKEY_EVENT_FLAG_CANCELED)));
7857
7858 ASSERT_NO_FATAL_FAILURE(mFakePolicy->assertUnhandledKeyNotReported());
7859 mWindow->assertNoEvents();
7860}
7861
7862TEST_F(InputDispatcherFallbackKeyTest, CanceledKeyCancelsFallback) {
7863 setFallback(AKEYCODE_B);
7864 mDispatcher->notifyKey(
7865 KeyArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_KEYBOARD).keyCode(AKEYCODE_A).build());
7866
7867 // Do not handle this key event, so fallback is generated.
7868 consumeKey(/*handled=*/false,
7869 AllOf(WithKeyAction(ACTION_DOWN), WithKeyCode(AKEYCODE_A), WithFlags(0)));
7870 ASSERT_NO_FATAL_FAILURE(mFakePolicy->assertUnhandledKeyReported(AKEYCODE_A));
7871 consumeKey(/*handled=*/true,
7872 AllOf(WithKeyAction(ACTION_DOWN), WithKeyCode(AKEYCODE_B),
7873 WithFlags(AKEY_EVENT_FLAG_FALLBACK)));
7874
7875 // The original key is canceled.
7876 mDispatcher->notifyKey(KeyArgsBuilder(ACTION_UP, AINPUT_SOURCE_KEYBOARD)
7877 .keyCode(AKEYCODE_A)
7878 .addFlag(AKEY_EVENT_FLAG_CANCELED)
7879 .build());
7880 consumeKey(/*handled=*/false,
7881 AllOf(WithKeyAction(ACTION_UP), WithKeyCode(AKEYCODE_A),
7882 WithFlags(AKEY_EVENT_FLAG_CANCELED)));
7883 ASSERT_NO_FATAL_FAILURE(mFakePolicy->assertUnhandledKeyReported(AKEYCODE_A));
7884 // Ensure the fallback key is also canceled due to the original key being canceled.
7885 consumeKey(/*handled=*/true,
7886 AllOf(WithKeyAction(ACTION_UP), WithKeyCode(AKEYCODE_B),
7887 WithFlags(AKEY_EVENT_FLAG_FALLBACK | AKEY_EVENT_FLAG_CANCELED)));
7888
7889 ASSERT_NO_FATAL_FAILURE(mFakePolicy->assertUnhandledKeyNotReported());
7890 mWindow->assertNoEvents();
7891}
7892
Prabir Pradhanfa2c69f2024-02-01 20:31:34 +00007893TEST_F(InputDispatcherFallbackKeyTest, InputChannelRemovedDuringPolicyCall) {
Prabir Pradhanb13da8f2024-01-09 23:10:13 +00007894 setFallback(AKEYCODE_B);
7895 mDispatcher->notifyKey(
7896 KeyArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_KEYBOARD).keyCode(AKEYCODE_A).build());
7897
7898 // Do not handle this key event.
7899 consumeKey(/*handled=*/false,
7900 AllOf(WithKeyAction(ACTION_DOWN), WithKeyCode(AKEYCODE_A), WithFlags(0)));
7901 ASSERT_NO_FATAL_FAILURE(mFakePolicy->assertUnhandledKeyReported(AKEYCODE_A));
7902 consumeKey(/*handled=*/true,
7903 AllOf(WithKeyAction(ACTION_DOWN), WithKeyCode(AKEYCODE_B),
7904 WithFlags(AKEY_EVENT_FLAG_FALLBACK)));
7905
7906 mFakePolicy->setUnhandledKeyHandler([&](const KeyEvent& event) {
7907 // When the unhandled key is reported to the policy next, remove the input channel.
7908 mDispatcher->removeInputChannel(mWindow->getToken());
7909 return KeyEventBuilder(event).keyCode(AKEYCODE_B).build();
7910 });
7911 // Release the original key, and let the app now handle the previously unhandled key.
7912 // This should result in the previously generated fallback key to be cancelled.
7913 // Since the policy was notified of the unhandled DOWN event earlier, it will also be notified
7914 // of the UP event for consistency. The Dispatcher calls into the policy from its own thread
7915 // without holding the lock, because it need to synchronously fetch the fallback key. While in
7916 // the policy call, we will now remove the input channel. Once the policy call returns, the
7917 // Dispatcher will no longer have a channel to send cancellation events to. Ensure this does
7918 // not cause any crashes.
7919 mDispatcher->notifyKey(
7920 KeyArgsBuilder(ACTION_UP, AINPUT_SOURCE_KEYBOARD).keyCode(AKEYCODE_A).build());
7921 consumeKey(/*handled=*/true,
7922 AllOf(WithKeyAction(ACTION_UP), WithKeyCode(AKEYCODE_A), WithFlags(0)));
7923 ASSERT_NO_FATAL_FAILURE(mFakePolicy->assertUnhandledKeyReported(AKEYCODE_A));
7924}
7925
Prabir Pradhanfa2c69f2024-02-01 20:31:34 +00007926TEST_F(InputDispatcherFallbackKeyTest, WindowRemovedDuringPolicyCall) {
7927 setFallback(AKEYCODE_B);
7928 mDispatcher->notifyKey(
7929 KeyArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_KEYBOARD).keyCode(AKEYCODE_A).build());
7930
7931 // Do not handle this key event.
7932 consumeKey(/*handled=*/false,
7933 AllOf(WithKeyAction(ACTION_DOWN), WithKeyCode(AKEYCODE_A), WithFlags(0)));
7934 ASSERT_NO_FATAL_FAILURE(mFakePolicy->assertUnhandledKeyReported(AKEYCODE_A));
7935 consumeKey(/*handled=*/true,
7936 AllOf(WithKeyAction(ACTION_DOWN), WithKeyCode(AKEYCODE_B),
7937 WithFlags(AKEY_EVENT_FLAG_FALLBACK)));
7938
7939 mFakePolicy->setUnhandledKeyHandler([&](const KeyEvent& event) {
7940 // When the unhandled key is reported to the policy next, remove the window.
7941 mDispatcher->onWindowInfosChanged({{}, {}, 0, 0});
7942 return KeyEventBuilder(event).keyCode(AKEYCODE_B).build();
7943 });
7944 // Release the original key, which the app will not handle. When this unhandled key is reported
7945 // to the policy, the window will be removed.
7946 mDispatcher->notifyKey(
7947 KeyArgsBuilder(ACTION_UP, AINPUT_SOURCE_KEYBOARD).keyCode(AKEYCODE_A).build());
7948 consumeKey(/*handled=*/false,
7949 AllOf(WithKeyAction(ACTION_UP), WithKeyCode(AKEYCODE_A), WithFlags(0)));
7950 ASSERT_NO_FATAL_FAILURE(mFakePolicy->assertUnhandledKeyReported(AKEYCODE_A));
7951
7952 // Since the window was removed, it loses focus, and the channel state will be reset.
7953 consumeKey(/*handled=*/true,
7954 AllOf(WithKeyAction(ACTION_UP), WithKeyCode(AKEYCODE_B),
7955 WithFlags(AKEY_EVENT_FLAG_FALLBACK | AKEY_EVENT_FLAG_CANCELED)));
7956 mWindow->consumeFocusEvent(false);
7957 mWindow->assertNoEvents();
7958}
7959
7960TEST_F(InputDispatcherFallbackKeyTest, WindowRemovedWhileAwaitingFinishedSignal) {
7961 setFallback(AKEYCODE_B);
7962 mDispatcher->notifyKey(
7963 KeyArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_KEYBOARD).keyCode(AKEYCODE_A).build());
7964
7965 // Do not handle this key event.
7966 consumeKey(/*handled=*/false,
7967 AllOf(WithKeyAction(ACTION_DOWN), WithKeyCode(AKEYCODE_A), WithFlags(0)));
7968 ASSERT_NO_FATAL_FAILURE(mFakePolicy->assertUnhandledKeyReported(AKEYCODE_A));
7969 const auto [seq, event] = mWindow->receiveEvent();
7970 ASSERT_TRUE(seq.has_value() && event != nullptr) << "Failed to receive fallback event";
7971 ASSERT_EQ(event->getType(), InputEventType::KEY);
7972 ASSERT_THAT(static_cast<const KeyEvent&>(*event),
7973 AllOf(WithKeyAction(ACTION_DOWN), WithKeyCode(AKEYCODE_B),
7974 WithFlags(AKEY_EVENT_FLAG_FALLBACK)));
7975
7976 // Remove the window now, which should generate a cancellations and make the window lose focus.
7977 mDispatcher->onWindowInfosChanged({{}, {}, 0, 0});
7978 consumeKey(/*handled=*/true,
7979 AllOf(WithKeyAction(ACTION_UP), WithKeyCode(AKEYCODE_A),
7980 WithFlags(AKEY_EVENT_FLAG_CANCELED)));
7981 consumeKey(/*handled=*/true,
7982 AllOf(WithKeyAction(ACTION_UP), WithKeyCode(AKEYCODE_B),
7983 WithFlags(AKEY_EVENT_FLAG_FALLBACK | AKEY_EVENT_FLAG_CANCELED)));
7984 mWindow->consumeFocusEvent(false);
7985
7986 // Finish the event by reporting it as handled.
7987 mWindow->finishEvent(*seq);
7988 mWindow->assertNoEvents();
7989}
7990
Garfield Tan1c7bc862020-01-28 13:24:04 -08007991class InputDispatcherKeyRepeatTest : public InputDispatcherTest {
7992protected:
Siarhei Vishniakoufa2a0492023-11-14 13:13:18 -08007993 static constexpr std::chrono::nanoseconds KEY_REPEAT_TIMEOUT = 40ms;
7994 static constexpr std::chrono::nanoseconds KEY_REPEAT_DELAY = 40ms;
Garfield Tan1c7bc862020-01-28 13:24:04 -08007995
Chris Yea209fde2020-07-22 13:54:51 -07007996 std::shared_ptr<FakeApplicationHandle> mApp;
Garfield Tan1c7bc862020-01-28 13:24:04 -08007997 sp<FakeWindowHandle> mWindow;
7998
7999 virtual void SetUp() override {
Prabir Pradhandae52792023-12-15 07:36:40 +00008000 InputDispatcherTest::SetUp();
Garfield Tan1c7bc862020-01-28 13:24:04 -08008001
Prabir Pradhandae52792023-12-15 07:36:40 +00008002 mDispatcher->setKeyRepeatConfiguration(KEY_REPEAT_TIMEOUT, KEY_REPEAT_DELAY);
Garfield Tan1c7bc862020-01-28 13:24:04 -08008003 setUpWindow();
8004 }
8005
8006 void setUpWindow() {
Chris Yea209fde2020-07-22 13:54:51 -07008007 mApp = std::make_shared<FakeApplicationHandle>();
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07008008 mWindow = sp<FakeWindowHandle>::make(mApp, mDispatcher, "Fake Window", ADISPLAY_ID_DEFAULT);
Garfield Tan1c7bc862020-01-28 13:24:04 -08008009
Vishnu Nair47074b82020-08-14 11:54:47 -07008010 mWindow->setFocusable(true);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07008011 mDispatcher->onWindowInfosChanged({{*mWindow->getInfo()}, {}, 0, 0});
Vishnu Nair958da932020-08-21 17:12:37 -07008012 setFocusedWindow(mWindow);
Garfield Tan1c7bc862020-01-28 13:24:04 -08008013 mWindow->consumeFocusEvent(true);
8014 }
8015
Chris Ye2ad95392020-09-01 13:44:44 -07008016 void sendAndConsumeKeyDown(int32_t deviceId) {
Garfield Tan1c7bc862020-01-28 13:24:04 -08008017 NotifyKeyArgs keyArgs = generateKeyArgs(AKEY_EVENT_ACTION_DOWN, ADISPLAY_ID_DEFAULT);
Chris Ye2ad95392020-09-01 13:44:44 -07008018 keyArgs.deviceId = deviceId;
Garfield Tan1c7bc862020-01-28 13:24:04 -08008019 keyArgs.policyFlags |= POLICY_FLAG_TRUSTED; // Otherwise it won't generate repeat event
Prabir Pradhan678438e2023-04-13 19:32:51 +00008020 mDispatcher->notifyKey(keyArgs);
Garfield Tan1c7bc862020-01-28 13:24:04 -08008021
8022 // Window should receive key down event.
8023 mWindow->consumeKeyDown(ADISPLAY_ID_DEFAULT);
8024 }
8025
8026 void expectKeyRepeatOnce(int32_t repeatCount) {
8027 SCOPED_TRACE(StringPrintf("Checking event with repeat count %" PRId32, repeatCount));
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07008028 mWindow->consumeKeyEvent(
8029 AllOf(WithKeyAction(AKEY_EVENT_ACTION_DOWN), WithRepeatCount(repeatCount)));
Garfield Tan1c7bc862020-01-28 13:24:04 -08008030 }
8031
Chris Ye2ad95392020-09-01 13:44:44 -07008032 void sendAndConsumeKeyUp(int32_t deviceId) {
Garfield Tan1c7bc862020-01-28 13:24:04 -08008033 NotifyKeyArgs keyArgs = generateKeyArgs(AKEY_EVENT_ACTION_UP, ADISPLAY_ID_DEFAULT);
Chris Ye2ad95392020-09-01 13:44:44 -07008034 keyArgs.deviceId = deviceId;
Garfield Tan1c7bc862020-01-28 13:24:04 -08008035 keyArgs.policyFlags |= POLICY_FLAG_TRUSTED; // Unless it won't generate repeat event
Prabir Pradhan678438e2023-04-13 19:32:51 +00008036 mDispatcher->notifyKey(keyArgs);
Garfield Tan1c7bc862020-01-28 13:24:04 -08008037
8038 // Window should receive key down event.
Prabir Pradhan7662a8d2023-12-15 01:58:14 +00008039 mWindow->consumeKeyUp(ADISPLAY_ID_DEFAULT,
Harry Cutts33476232023-01-30 19:57:29 +00008040 /*expectedFlags=*/0);
Garfield Tan1c7bc862020-01-28 13:24:04 -08008041 }
Hu Guofe3c8f12023-09-22 17:20:15 +08008042
8043 void injectKeyRepeat(int32_t repeatCount) {
8044 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
8045 injectKey(*mDispatcher, AKEY_EVENT_ACTION_DOWN, repeatCount, ADISPLAY_ID_DEFAULT))
8046 << "Inject key event should return InputEventInjectionResult::SUCCEEDED";
8047 }
Garfield Tan1c7bc862020-01-28 13:24:04 -08008048};
8049
8050TEST_F(InputDispatcherKeyRepeatTest, FocusedWindow_ReceivesKeyRepeat) {
Harry Cutts33476232023-01-30 19:57:29 +00008051 sendAndConsumeKeyDown(/*deviceId=*/1);
Chris Ye2ad95392020-09-01 13:44:44 -07008052 for (int32_t repeatCount = 1; repeatCount <= 10; ++repeatCount) {
8053 expectKeyRepeatOnce(repeatCount);
8054 }
8055}
8056
8057TEST_F(InputDispatcherKeyRepeatTest, FocusedWindow_ReceivesKeyRepeatFromTwoDevices) {
Harry Cutts33476232023-01-30 19:57:29 +00008058 sendAndConsumeKeyDown(/*deviceId=*/1);
Chris Ye2ad95392020-09-01 13:44:44 -07008059 for (int32_t repeatCount = 1; repeatCount <= 10; ++repeatCount) {
8060 expectKeyRepeatOnce(repeatCount);
8061 }
Harry Cutts33476232023-01-30 19:57:29 +00008062 sendAndConsumeKeyDown(/*deviceId=*/2);
Chris Ye2ad95392020-09-01 13:44:44 -07008063 /* repeatCount will start from 1 for deviceId 2 */
Garfield Tan1c7bc862020-01-28 13:24:04 -08008064 for (int32_t repeatCount = 1; repeatCount <= 10; ++repeatCount) {
8065 expectKeyRepeatOnce(repeatCount);
8066 }
8067}
8068
8069TEST_F(InputDispatcherKeyRepeatTest, FocusedWindow_StopsKeyRepeatAfterUp) {
Harry Cutts33476232023-01-30 19:57:29 +00008070 sendAndConsumeKeyDown(/*deviceId=*/1);
8071 expectKeyRepeatOnce(/*repeatCount=*/1);
8072 sendAndConsumeKeyUp(/*deviceId=*/1);
Chris Ye2ad95392020-09-01 13:44:44 -07008073 mWindow->assertNoEvents();
8074}
8075
8076TEST_F(InputDispatcherKeyRepeatTest, FocusedWindow_KeyRepeatAfterStaleDeviceKeyUp) {
Harry Cutts33476232023-01-30 19:57:29 +00008077 sendAndConsumeKeyDown(/*deviceId=*/1);
8078 expectKeyRepeatOnce(/*repeatCount=*/1);
8079 sendAndConsumeKeyDown(/*deviceId=*/2);
8080 expectKeyRepeatOnce(/*repeatCount=*/1);
Chris Ye2ad95392020-09-01 13:44:44 -07008081 // Stale key up from device 1.
Harry Cutts33476232023-01-30 19:57:29 +00008082 sendAndConsumeKeyUp(/*deviceId=*/1);
Chris Ye2ad95392020-09-01 13:44:44 -07008083 // Device 2 is still down, keep repeating
Harry Cutts33476232023-01-30 19:57:29 +00008084 expectKeyRepeatOnce(/*repeatCount=*/2);
8085 expectKeyRepeatOnce(/*repeatCount=*/3);
Chris Ye2ad95392020-09-01 13:44:44 -07008086 // Device 2 key up
Harry Cutts33476232023-01-30 19:57:29 +00008087 sendAndConsumeKeyUp(/*deviceId=*/2);
Chris Ye2ad95392020-09-01 13:44:44 -07008088 mWindow->assertNoEvents();
8089}
8090
8091TEST_F(InputDispatcherKeyRepeatTest, FocusedWindow_KeyRepeatStopsAfterRepeatingKeyUp) {
Harry Cutts33476232023-01-30 19:57:29 +00008092 sendAndConsumeKeyDown(/*deviceId=*/1);
8093 expectKeyRepeatOnce(/*repeatCount=*/1);
8094 sendAndConsumeKeyDown(/*deviceId=*/2);
8095 expectKeyRepeatOnce(/*repeatCount=*/1);
Chris Ye2ad95392020-09-01 13:44:44 -07008096 // Device 2 which holds the key repeating goes up, expect the repeating to stop.
Harry Cutts33476232023-01-30 19:57:29 +00008097 sendAndConsumeKeyUp(/*deviceId=*/2);
Chris Ye2ad95392020-09-01 13:44:44 -07008098 // Device 1 still holds key down, but the repeating was already stopped
Garfield Tan1c7bc862020-01-28 13:24:04 -08008099 mWindow->assertNoEvents();
8100}
8101
liushenxiang42232912021-05-21 20:24:09 +08008102TEST_F(InputDispatcherKeyRepeatTest, FocusedWindow_StopsKeyRepeatAfterDisableInputDevice) {
8103 sendAndConsumeKeyDown(DEVICE_ID);
Harry Cutts33476232023-01-30 19:57:29 +00008104 expectKeyRepeatOnce(/*repeatCount=*/1);
Prabir Pradhan678438e2023-04-13 19:32:51 +00008105 mDispatcher->notifyDeviceReset({/*id=*/10, /*eventTime=*/20, DEVICE_ID});
liushenxiang42232912021-05-21 20:24:09 +08008106 mWindow->consumeKeyUp(ADISPLAY_ID_DEFAULT,
8107 AKEY_EVENT_FLAG_CANCELED | AKEY_EVENT_FLAG_LONG_PRESS);
8108 mWindow->assertNoEvents();
8109}
8110
Garfield Tan1c7bc862020-01-28 13:24:04 -08008111TEST_F(InputDispatcherKeyRepeatTest, FocusedWindow_RepeatKeyEventsUseEventIdFromInputDispatcher) {
Michael Wrighte1cbbd62023-02-22 19:32:13 +00008112 GTEST_SKIP() << "Flaky test (b/270393106)";
Harry Cutts33476232023-01-30 19:57:29 +00008113 sendAndConsumeKeyDown(/*deviceId=*/1);
Garfield Tan1c7bc862020-01-28 13:24:04 -08008114 for (int32_t repeatCount = 1; repeatCount <= 10; ++repeatCount) {
Siarhei Vishniakoud3061ab2023-12-18 20:41:08 -08008115 std::unique_ptr<KeyEvent> repeatEvent = mWindow->consumeKey();
8116 ASSERT_NE(nullptr, repeatEvent);
Garfield Tan1c7bc862020-01-28 13:24:04 -08008117 EXPECT_EQ(IdGenerator::Source::INPUT_DISPATCHER,
Siarhei Vishniakoud3061ab2023-12-18 20:41:08 -08008118 IdGenerator::getSource(repeatEvent->getId()));
Garfield Tan1c7bc862020-01-28 13:24:04 -08008119 }
8120}
8121
8122TEST_F(InputDispatcherKeyRepeatTest, FocusedWindow_RepeatKeyEventsUseUniqueEventId) {
Michael Wrighte1cbbd62023-02-22 19:32:13 +00008123 GTEST_SKIP() << "Flaky test (b/270393106)";
Harry Cutts33476232023-01-30 19:57:29 +00008124 sendAndConsumeKeyDown(/*deviceId=*/1);
Garfield Tan1c7bc862020-01-28 13:24:04 -08008125
8126 std::unordered_set<int32_t> idSet;
8127 for (int32_t repeatCount = 1; repeatCount <= 10; ++repeatCount) {
Siarhei Vishniakoud3061ab2023-12-18 20:41:08 -08008128 std::unique_ptr<KeyEvent> repeatEvent = mWindow->consumeKey();
8129 ASSERT_NE(nullptr, repeatEvent);
8130 int32_t id = repeatEvent->getId();
Garfield Tan1c7bc862020-01-28 13:24:04 -08008131 EXPECT_EQ(idSet.end(), idSet.find(id));
8132 idSet.insert(id);
8133 }
8134}
8135
Hu Guofe3c8f12023-09-22 17:20:15 +08008136TEST_F(InputDispatcherKeyRepeatTest, FocusedWindow_CorrectRepeatCountWhenInjectKeyRepeat) {
8137 injectKeyRepeat(0);
8138 mWindow->consumeKeyDown(ADISPLAY_ID_DEFAULT);
8139 for (int32_t repeatCount = 1; repeatCount <= 2; ++repeatCount) {
8140 expectKeyRepeatOnce(repeatCount);
8141 }
8142 injectKeyRepeat(1);
8143 // Expect repeatCount to be 3 instead of 1
8144 expectKeyRepeatOnce(3);
8145}
8146
Arthur Hung2fbf37f2018-09-13 18:16:41 +08008147/* Test InputDispatcher for MultiDisplay */
8148class InputDispatcherFocusOnTwoDisplaysTest : public InputDispatcherTest {
8149public:
Prabir Pradhan3608aad2019-10-02 17:08:26 -07008150 virtual void SetUp() override {
Arthur Hung2fbf37f2018-09-13 18:16:41 +08008151 InputDispatcherTest::SetUp();
Arthur Hungb92218b2018-08-14 12:00:21 +08008152
Chris Yea209fde2020-07-22 13:54:51 -07008153 application1 = std::make_shared<FakeApplicationHandle>();
Siarhei Vishniakou870ecec2020-12-09 08:07:46 -10008154 windowInPrimary =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07008155 sp<FakeWindowHandle>::make(application1, mDispatcher, "D_1", ADISPLAY_ID_DEFAULT);
Siarhei Vishniakoub9b15352019-11-26 13:19:26 -08008156
Arthur Hung2fbf37f2018-09-13 18:16:41 +08008157 // Set focus window for primary display, but focused display would be second one.
8158 mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application1);
Vishnu Nair47074b82020-08-14 11:54:47 -07008159 windowInPrimary->setFocusable(true);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07008160 mDispatcher->onWindowInfosChanged({{*windowInPrimary->getInfo()}, {}, 0, 0});
8161
Vishnu Nair958da932020-08-21 17:12:37 -07008162 setFocusedWindow(windowInPrimary);
Siarhei Vishniakouf1035d42019-09-20 16:32:01 +01008163 windowInPrimary->consumeFocusEvent(true);
Arthur Hungb92218b2018-08-14 12:00:21 +08008164
Chris Yea209fde2020-07-22 13:54:51 -07008165 application2 = std::make_shared<FakeApplicationHandle>();
Siarhei Vishniakou870ecec2020-12-09 08:07:46 -10008166 windowInSecondary =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07008167 sp<FakeWindowHandle>::make(application2, mDispatcher, "D_2", SECOND_DISPLAY_ID);
Arthur Hung2fbf37f2018-09-13 18:16:41 +08008168 // Set focus to second display window.
Arthur Hung2fbf37f2018-09-13 18:16:41 +08008169 // Set focus display to second one.
8170 mDispatcher->setFocusedDisplay(SECOND_DISPLAY_ID);
8171 // Set focus window for second display.
8172 mDispatcher->setFocusedApplication(SECOND_DISPLAY_ID, application2);
Vishnu Nair47074b82020-08-14 11:54:47 -07008173 windowInSecondary->setFocusable(true);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07008174 mDispatcher->onWindowInfosChanged(
8175 {{*windowInPrimary->getInfo(), *windowInSecondary->getInfo()}, {}, 0, 0});
Vishnu Nair958da932020-08-21 17:12:37 -07008176 setFocusedWindow(windowInSecondary);
Siarhei Vishniakouf1035d42019-09-20 16:32:01 +01008177 windowInSecondary->consumeFocusEvent(true);
Arthur Hung2fbf37f2018-09-13 18:16:41 +08008178 }
8179
Prabir Pradhan3608aad2019-10-02 17:08:26 -07008180 virtual void TearDown() override {
Arthur Hung2fbf37f2018-09-13 18:16:41 +08008181 InputDispatcherTest::TearDown();
8182
Chris Yea209fde2020-07-22 13:54:51 -07008183 application1.reset();
Arthur Hung2fbf37f2018-09-13 18:16:41 +08008184 windowInPrimary.clear();
Chris Yea209fde2020-07-22 13:54:51 -07008185 application2.reset();
Arthur Hung2fbf37f2018-09-13 18:16:41 +08008186 windowInSecondary.clear();
8187 }
8188
8189protected:
Chris Yea209fde2020-07-22 13:54:51 -07008190 std::shared_ptr<FakeApplicationHandle> application1;
Arthur Hung2fbf37f2018-09-13 18:16:41 +08008191 sp<FakeWindowHandle> windowInPrimary;
Chris Yea209fde2020-07-22 13:54:51 -07008192 std::shared_ptr<FakeApplicationHandle> application2;
Arthur Hung2fbf37f2018-09-13 18:16:41 +08008193 sp<FakeWindowHandle> windowInSecondary;
8194};
8195
8196TEST_F(InputDispatcherFocusOnTwoDisplaysTest, SetInputWindow_MultiDisplayTouch) {
8197 // Test touch down on primary display.
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08008198 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07008199 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT))
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08008200 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
Siarhei Vishniakouc5ca85c2019-11-15 17:20:00 -08008201 windowInPrimary->consumeMotionDown(ADISPLAY_ID_DEFAULT);
Arthur Hungb92218b2018-08-14 12:00:21 +08008202 windowInSecondary->assertNoEvents();
8203
Arthur Hung2fbf37f2018-09-13 18:16:41 +08008204 // Test touch down on second display.
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08008205 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07008206 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, SECOND_DISPLAY_ID))
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08008207 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
Arthur Hungb92218b2018-08-14 12:00:21 +08008208 windowInPrimary->assertNoEvents();
Siarhei Vishniakouc5ca85c2019-11-15 17:20:00 -08008209 windowInSecondary->consumeMotionDown(SECOND_DISPLAY_ID);
Arthur Hungb92218b2018-08-14 12:00:21 +08008210}
8211
Arthur Hung2fbf37f2018-09-13 18:16:41 +08008212TEST_F(InputDispatcherFocusOnTwoDisplaysTest, SetInputWindow_MultiDisplayFocus) {
Tiger Huang721e26f2018-07-24 22:26:19 +08008213 // Test inject a key down with display id specified.
Prabir Pradhan93f342c2021-03-11 15:05:30 -08008214 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07008215 injectKeyDownNoRepeat(*mDispatcher, ADISPLAY_ID_DEFAULT))
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08008216 << "Inject key event should return InputEventInjectionResult::SUCCEEDED";
Siarhei Vishniakouc5ca85c2019-11-15 17:20:00 -08008217 windowInPrimary->consumeKeyDown(ADISPLAY_ID_DEFAULT);
Tiger Huang721e26f2018-07-24 22:26:19 +08008218 windowInSecondary->assertNoEvents();
8219
8220 // Test inject a key down without display id specified.
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07008221 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectKeyDownNoRepeat(*mDispatcher))
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08008222 << "Inject key event should return InputEventInjectionResult::SUCCEEDED";
Arthur Hungb92218b2018-08-14 12:00:21 +08008223 windowInPrimary->assertNoEvents();
Siarhei Vishniakouc5ca85c2019-11-15 17:20:00 -08008224 windowInSecondary->consumeKeyDown(ADISPLAY_ID_NONE);
Arthur Hungb92218b2018-08-14 12:00:21 +08008225
Siarhei Vishniakoub9b15352019-11-26 13:19:26 -08008226 // Remove all windows in secondary display.
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07008227 mDispatcher->onWindowInfosChanged({{*windowInPrimary->getInfo()}, {}, 0, 0});
Arthur Hungb92218b2018-08-14 12:00:21 +08008228
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08008229 // Old focus should receive a cancel event.
Prabir Pradhan7662a8d2023-12-15 01:58:14 +00008230 windowInSecondary->consumeKeyUp(ADISPLAY_ID_NONE, AKEY_EVENT_FLAG_CANCELED);
Arthur Hungb92218b2018-08-14 12:00:21 +08008231
8232 // Test inject a key down, should timeout because of no target window.
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07008233 ASSERT_NO_FATAL_FAILURE(assertInjectedKeyTimesOut(*mDispatcher));
Arthur Hungb92218b2018-08-14 12:00:21 +08008234 windowInPrimary->assertNoEvents();
Siarhei Vishniakouf1035d42019-09-20 16:32:01 +01008235 windowInSecondary->consumeFocusEvent(false);
Arthur Hungb92218b2018-08-14 12:00:21 +08008236 windowInSecondary->assertNoEvents();
8237}
8238
Arthur Hung2fbf37f2018-09-13 18:16:41 +08008239// Test per-display input monitors for motion event.
8240TEST_F(InputDispatcherFocusOnTwoDisplaysTest, MonitorMotionEvent_MultiDisplay) {
chaviwd1c23182019-12-20 18:44:56 -08008241 FakeMonitorReceiver monitorInPrimary =
Prabir Pradhanfb549072023-10-05 19:17:36 +00008242 FakeMonitorReceiver(*mDispatcher, "M_1", ADISPLAY_ID_DEFAULT);
chaviwd1c23182019-12-20 18:44:56 -08008243 FakeMonitorReceiver monitorInSecondary =
Prabir Pradhanfb549072023-10-05 19:17:36 +00008244 FakeMonitorReceiver(*mDispatcher, "M_2", SECOND_DISPLAY_ID);
Arthur Hung2fbf37f2018-09-13 18:16:41 +08008245
8246 // Test touch down on primary display.
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08008247 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07008248 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT))
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08008249 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
Siarhei Vishniakouc5ca85c2019-11-15 17:20:00 -08008250 windowInPrimary->consumeMotionDown(ADISPLAY_ID_DEFAULT);
chaviwd1c23182019-12-20 18:44:56 -08008251 monitorInPrimary.consumeMotionDown(ADISPLAY_ID_DEFAULT);
Arthur Hung2fbf37f2018-09-13 18:16:41 +08008252 windowInSecondary->assertNoEvents();
chaviwd1c23182019-12-20 18:44:56 -08008253 monitorInSecondary.assertNoEvents();
Arthur Hung2fbf37f2018-09-13 18:16:41 +08008254
8255 // Test touch down on second display.
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08008256 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07008257 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, SECOND_DISPLAY_ID))
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08008258 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
Arthur Hung2fbf37f2018-09-13 18:16:41 +08008259 windowInPrimary->assertNoEvents();
chaviwd1c23182019-12-20 18:44:56 -08008260 monitorInPrimary.assertNoEvents();
Siarhei Vishniakouc5ca85c2019-11-15 17:20:00 -08008261 windowInSecondary->consumeMotionDown(SECOND_DISPLAY_ID);
chaviwd1c23182019-12-20 18:44:56 -08008262 monitorInSecondary.consumeMotionDown(SECOND_DISPLAY_ID);
Arthur Hung2fbf37f2018-09-13 18:16:41 +08008263
Siarhei Vishniakou92c8fd52023-01-29 14:57:43 -08008264 // Lift up the touch from the second display
8265 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07008266 injectMotionUp(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, SECOND_DISPLAY_ID))
Siarhei Vishniakou92c8fd52023-01-29 14:57:43 -08008267 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
8268 windowInSecondary->consumeMotionUp(SECOND_DISPLAY_ID);
8269 monitorInSecondary.consumeMotionUp(SECOND_DISPLAY_ID);
8270
Arthur Hung2fbf37f2018-09-13 18:16:41 +08008271 // Test inject a non-pointer motion event.
8272 // If specific a display, it will dispatch to the focused window of particular display,
8273 // or it will dispatch to the focused window of focused display.
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08008274 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07008275 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TRACKBALL, ADISPLAY_ID_NONE))
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08008276 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
Arthur Hung2fbf37f2018-09-13 18:16:41 +08008277 windowInPrimary->assertNoEvents();
chaviwd1c23182019-12-20 18:44:56 -08008278 monitorInPrimary.assertNoEvents();
Siarhei Vishniakouc5ca85c2019-11-15 17:20:00 -08008279 windowInSecondary->consumeMotionDown(ADISPLAY_ID_NONE);
chaviwd1c23182019-12-20 18:44:56 -08008280 monitorInSecondary.consumeMotionDown(ADISPLAY_ID_NONE);
Arthur Hung2fbf37f2018-09-13 18:16:41 +08008281}
8282
8283// Test per-display input monitors for key event.
8284TEST_F(InputDispatcherFocusOnTwoDisplaysTest, MonitorKeyEvent_MultiDisplay) {
Siarhei Vishniakou870ecec2020-12-09 08:07:46 -10008285 // Input monitor per display.
chaviwd1c23182019-12-20 18:44:56 -08008286 FakeMonitorReceiver monitorInPrimary =
Prabir Pradhanfb549072023-10-05 19:17:36 +00008287 FakeMonitorReceiver(*mDispatcher, "M_1", ADISPLAY_ID_DEFAULT);
chaviwd1c23182019-12-20 18:44:56 -08008288 FakeMonitorReceiver monitorInSecondary =
Prabir Pradhanfb549072023-10-05 19:17:36 +00008289 FakeMonitorReceiver(*mDispatcher, "M_2", SECOND_DISPLAY_ID);
Arthur Hung2fbf37f2018-09-13 18:16:41 +08008290
8291 // Test inject a key down.
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07008292 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectKeyDown(*mDispatcher))
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08008293 << "Inject key event should return InputEventInjectionResult::SUCCEEDED";
Arthur Hung2fbf37f2018-09-13 18:16:41 +08008294 windowInPrimary->assertNoEvents();
chaviwd1c23182019-12-20 18:44:56 -08008295 monitorInPrimary.assertNoEvents();
Siarhei Vishniakouc5ca85c2019-11-15 17:20:00 -08008296 windowInSecondary->consumeKeyDown(ADISPLAY_ID_NONE);
chaviwd1c23182019-12-20 18:44:56 -08008297 monitorInSecondary.consumeKeyDown(ADISPLAY_ID_NONE);
Arthur Hung2fbf37f2018-09-13 18:16:41 +08008298}
8299
Vishnu Nair958da932020-08-21 17:12:37 -07008300TEST_F(InputDispatcherFocusOnTwoDisplaysTest, CanFocusWindowOnUnfocusedDisplay) {
8301 sp<FakeWindowHandle> secondWindowInPrimary =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07008302 sp<FakeWindowHandle>::make(application1, mDispatcher, "D_1_W2", ADISPLAY_ID_DEFAULT);
Vishnu Nair958da932020-08-21 17:12:37 -07008303 secondWindowInPrimary->setFocusable(true);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07008304 mDispatcher->onWindowInfosChanged(
8305 {{*windowInPrimary->getInfo(), *secondWindowInPrimary->getInfo(),
8306 *windowInSecondary->getInfo()},
8307 {},
8308 0,
8309 0});
Vishnu Nair958da932020-08-21 17:12:37 -07008310 setFocusedWindow(secondWindowInPrimary);
8311 windowInPrimary->consumeFocusEvent(false);
8312 secondWindowInPrimary->consumeFocusEvent(true);
8313
8314 // Test inject a key down.
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07008315 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
8316 injectKeyDown(*mDispatcher, ADISPLAY_ID_DEFAULT))
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08008317 << "Inject key event should return InputEventInjectionResult::SUCCEEDED";
Vishnu Nair958da932020-08-21 17:12:37 -07008318 windowInPrimary->assertNoEvents();
8319 windowInSecondary->assertNoEvents();
8320 secondWindowInPrimary->consumeKeyDown(ADISPLAY_ID_DEFAULT);
8321}
8322
Arthur Hungdfd528e2021-12-08 13:23:04 +00008323TEST_F(InputDispatcherFocusOnTwoDisplaysTest, CancelTouch_MultiDisplay) {
8324 FakeMonitorReceiver monitorInPrimary =
Prabir Pradhanfb549072023-10-05 19:17:36 +00008325 FakeMonitorReceiver(*mDispatcher, "M_1", ADISPLAY_ID_DEFAULT);
Arthur Hungdfd528e2021-12-08 13:23:04 +00008326 FakeMonitorReceiver monitorInSecondary =
Prabir Pradhanfb549072023-10-05 19:17:36 +00008327 FakeMonitorReceiver(*mDispatcher, "M_2", SECOND_DISPLAY_ID);
Arthur Hungdfd528e2021-12-08 13:23:04 +00008328
8329 // Test touch down on primary display.
8330 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07008331 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT))
Arthur Hungdfd528e2021-12-08 13:23:04 +00008332 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
8333 windowInPrimary->consumeMotionDown(ADISPLAY_ID_DEFAULT);
8334 monitorInPrimary.consumeMotionDown(ADISPLAY_ID_DEFAULT);
8335
8336 // Test touch down on second display.
8337 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07008338 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, SECOND_DISPLAY_ID))
Arthur Hungdfd528e2021-12-08 13:23:04 +00008339 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
8340 windowInSecondary->consumeMotionDown(SECOND_DISPLAY_ID);
8341 monitorInSecondary.consumeMotionDown(SECOND_DISPLAY_ID);
8342
8343 // Trigger cancel touch.
8344 mDispatcher->cancelCurrentTouch();
8345 windowInPrimary->consumeMotionCancel(ADISPLAY_ID_DEFAULT);
8346 monitorInPrimary.consumeMotionCancel(ADISPLAY_ID_DEFAULT);
8347 windowInSecondary->consumeMotionCancel(SECOND_DISPLAY_ID);
8348 monitorInSecondary.consumeMotionCancel(SECOND_DISPLAY_ID);
8349
8350 // Test inject a move motion event, no window/monitor should receive the event.
8351 ASSERT_EQ(InputEventInjectionResult::FAILED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07008352 injectMotionEvent(*mDispatcher, AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN,
Arthur Hungdfd528e2021-12-08 13:23:04 +00008353 ADISPLAY_ID_DEFAULT, {110, 200}))
8354 << "Inject motion event should return InputEventInjectionResult::FAILED";
8355 windowInPrimary->assertNoEvents();
8356 monitorInPrimary.assertNoEvents();
8357
8358 ASSERT_EQ(InputEventInjectionResult::FAILED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07008359 injectMotionEvent(*mDispatcher, AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN,
Arthur Hungdfd528e2021-12-08 13:23:04 +00008360 SECOND_DISPLAY_ID, {110, 200}))
8361 << "Inject motion event should return InputEventInjectionResult::FAILED";
8362 windowInSecondary->assertNoEvents();
8363 monitorInSecondary.assertNoEvents();
8364}
8365
Hu Guocb134f12023-12-23 13:42:44 +00008366/**
8367 * Send a key to the primary display and to the secondary display.
8368 * Then cause the key on the primary display to be canceled by sending in a stale key.
8369 * Ensure that the key on the primary display is canceled, and that the key on the secondary display
8370 * does not get canceled.
8371 */
8372TEST_F(InputDispatcherFocusOnTwoDisplaysTest, WhenDropKeyEvent_OnlyCancelCorrespondingKeyGesture) {
8373 // Send a key down on primary display
8374 mDispatcher->notifyKey(
8375 KeyArgsBuilder(AKEY_EVENT_ACTION_DOWN, AINPUT_SOURCE_KEYBOARD)
8376 .displayId(ADISPLAY_ID_DEFAULT)
8377 .policyFlags(DEFAULT_POLICY_FLAGS | POLICY_FLAG_DISABLE_KEY_REPEAT)
8378 .build());
8379 windowInPrimary->consumeKeyEvent(
8380 AllOf(WithKeyAction(AKEY_EVENT_ACTION_DOWN), WithDisplayId(ADISPLAY_ID_DEFAULT)));
8381 windowInSecondary->assertNoEvents();
8382
8383 // Send a key down on second display
8384 mDispatcher->notifyKey(
8385 KeyArgsBuilder(AKEY_EVENT_ACTION_DOWN, AINPUT_SOURCE_KEYBOARD)
8386 .displayId(SECOND_DISPLAY_ID)
8387 .policyFlags(DEFAULT_POLICY_FLAGS | POLICY_FLAG_DISABLE_KEY_REPEAT)
8388 .build());
8389 windowInSecondary->consumeKeyEvent(
8390 AllOf(WithKeyAction(AKEY_EVENT_ACTION_DOWN), WithDisplayId(SECOND_DISPLAY_ID)));
8391 windowInPrimary->assertNoEvents();
8392
8393 // Send a valid key up event on primary display that will be dropped because it is stale
8394 NotifyKeyArgs staleKeyUp =
8395 KeyArgsBuilder(AKEY_EVENT_ACTION_UP, AINPUT_SOURCE_KEYBOARD)
8396 .displayId(ADISPLAY_ID_DEFAULT)
8397 .policyFlags(DEFAULT_POLICY_FLAGS | POLICY_FLAG_DISABLE_KEY_REPEAT)
8398 .build();
8399 static constexpr std::chrono::duration STALE_EVENT_TIMEOUT = 10ms;
8400 mFakePolicy->setStaleEventTimeout(STALE_EVENT_TIMEOUT);
8401 std::this_thread::sleep_for(STALE_EVENT_TIMEOUT);
8402 mDispatcher->notifyKey(staleKeyUp);
8403
8404 // Only the key gesture corresponding to the dropped event should receive the cancel event.
8405 // Therefore, windowInPrimary should get the cancel event and windowInSecondary should not
8406 // receive any events.
8407 windowInPrimary->consumeKeyEvent(AllOf(WithKeyAction(AKEY_EVENT_ACTION_UP),
8408 WithDisplayId(ADISPLAY_ID_DEFAULT),
8409 WithFlags(AKEY_EVENT_FLAG_CANCELED)));
8410 windowInSecondary->assertNoEvents();
8411}
8412
8413/**
8414 * Similar to 'WhenDropKeyEvent_OnlyCancelCorrespondingKeyGesture' but for motion events.
8415 */
8416TEST_F(InputDispatcherFocusOnTwoDisplaysTest, WhenDropMotionEvent_OnlyCancelCorrespondingGesture) {
8417 // Send touch down on primary display.
8418 mDispatcher->notifyMotion(
8419 MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
8420 .pointer(PointerBuilder(/*id=*/0, ToolType::FINGER).x(100).y(200))
8421 .displayId(ADISPLAY_ID_DEFAULT)
8422 .build());
8423 windowInPrimary->consumeMotionEvent(
8424 AllOf(WithMotionAction(ACTION_DOWN), WithDisplayId(ADISPLAY_ID_DEFAULT)));
8425 windowInSecondary->assertNoEvents();
8426
8427 // Send touch down on second display.
8428 mDispatcher->notifyMotion(
8429 MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
8430 .pointer(PointerBuilder(/*id=*/0, ToolType::FINGER).x(100).y(200))
8431 .displayId(SECOND_DISPLAY_ID)
8432 .build());
8433 windowInPrimary->assertNoEvents();
8434 windowInSecondary->consumeMotionEvent(
8435 AllOf(WithMotionAction(ACTION_DOWN), WithDisplayId(SECOND_DISPLAY_ID)));
8436
8437 // inject a valid MotionEvent on primary display that will be stale when it arrives.
8438 NotifyMotionArgs staleMotionUp =
8439 MotionArgsBuilder(ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN)
8440 .displayId(ADISPLAY_ID_DEFAULT)
8441 .pointer(PointerBuilder(/*id=*/0, ToolType::FINGER).x(100).y(200))
8442 .build();
8443 static constexpr std::chrono::duration STALE_EVENT_TIMEOUT = 10ms;
8444 mFakePolicy->setStaleEventTimeout(STALE_EVENT_TIMEOUT);
8445 std::this_thread::sleep_for(STALE_EVENT_TIMEOUT);
8446 mDispatcher->notifyMotion(staleMotionUp);
8447
8448 // For stale motion events, we let the gesture to complete. This behaviour is different from key
8449 // events, where we would cancel the current keys instead.
8450 windowInPrimary->consumeMotionEvent(WithMotionAction(ACTION_UP));
8451 windowInSecondary->assertNoEvents();
8452}
8453
Jackal Guof9696682018-10-05 12:23:23 +08008454class InputFilterTest : public InputDispatcherTest {
8455protected:
Prabir Pradhan81420cc2021-09-06 10:28:50 -07008456 void testNotifyMotion(int32_t displayId, bool expectToBeFiltered,
8457 const ui::Transform& transform = ui::Transform()) {
Jackal Guof9696682018-10-05 12:23:23 +08008458 NotifyMotionArgs motionArgs;
8459
Siarhei Vishniakou870ecec2020-12-09 08:07:46 -10008460 motionArgs =
8461 generateMotionArgs(AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN, displayId);
Prabir Pradhan678438e2023-04-13 19:32:51 +00008462 mDispatcher->notifyMotion(motionArgs);
Siarhei Vishniakou870ecec2020-12-09 08:07:46 -10008463 motionArgs =
8464 generateMotionArgs(AMOTION_EVENT_ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN, displayId);
Prabir Pradhan678438e2023-04-13 19:32:51 +00008465 mDispatcher->notifyMotion(motionArgs);
Siarhei Vishniakou2bfa9052019-11-21 18:10:54 -08008466 ASSERT_TRUE(mDispatcher->waitForIdle());
Jackal Guof9696682018-10-05 12:23:23 +08008467 if (expectToBeFiltered) {
Siarhei Vishniakou3218fc02023-06-15 20:41:02 -07008468 const auto xy = transform.transform(motionArgs.pointerCoords[0].getXYValue());
Prabir Pradhan81420cc2021-09-06 10:28:50 -07008469 mFakePolicy->assertFilterInputEventWasCalled(motionArgs, xy);
Jackal Guof9696682018-10-05 12:23:23 +08008470 } else {
8471 mFakePolicy->assertFilterInputEventWasNotCalled();
8472 }
8473 }
8474
8475 void testNotifyKey(bool expectToBeFiltered) {
8476 NotifyKeyArgs keyArgs;
8477
8478 keyArgs = generateKeyArgs(AKEY_EVENT_ACTION_DOWN);
Prabir Pradhan678438e2023-04-13 19:32:51 +00008479 mDispatcher->notifyKey(keyArgs);
Jackal Guof9696682018-10-05 12:23:23 +08008480 keyArgs = generateKeyArgs(AKEY_EVENT_ACTION_UP);
Prabir Pradhan678438e2023-04-13 19:32:51 +00008481 mDispatcher->notifyKey(keyArgs);
Siarhei Vishniakou2bfa9052019-11-21 18:10:54 -08008482 ASSERT_TRUE(mDispatcher->waitForIdle());
Jackal Guof9696682018-10-05 12:23:23 +08008483
8484 if (expectToBeFiltered) {
Siarhei Vishniakou8935a802019-11-15 16:41:44 -08008485 mFakePolicy->assertFilterInputEventWasCalled(keyArgs);
Jackal Guof9696682018-10-05 12:23:23 +08008486 } else {
8487 mFakePolicy->assertFilterInputEventWasNotCalled();
8488 }
8489 }
8490};
8491
8492// Test InputFilter for MotionEvent
8493TEST_F(InputFilterTest, MotionEvent_InputFilter) {
8494 // Since the InputFilter is disabled by default, check if touch events aren't filtered.
Harry Cutts101ee9b2023-07-06 18:04:14 +00008495 testNotifyMotion(ADISPLAY_ID_DEFAULT, /*expectToBeFiltered=*/false);
8496 testNotifyMotion(SECOND_DISPLAY_ID, /*expectToBeFiltered=*/false);
Jackal Guof9696682018-10-05 12:23:23 +08008497
8498 // Enable InputFilter
8499 mDispatcher->setInputFilterEnabled(true);
8500 // Test touch on both primary and second display, and check if both events are filtered.
Harry Cutts101ee9b2023-07-06 18:04:14 +00008501 testNotifyMotion(ADISPLAY_ID_DEFAULT, /*expectToBeFiltered=*/true);
8502 testNotifyMotion(SECOND_DISPLAY_ID, /*expectToBeFiltered=*/true);
Jackal Guof9696682018-10-05 12:23:23 +08008503
8504 // Disable InputFilter
8505 mDispatcher->setInputFilterEnabled(false);
8506 // Test touch on both primary and second display, and check if both events aren't filtered.
Harry Cutts101ee9b2023-07-06 18:04:14 +00008507 testNotifyMotion(ADISPLAY_ID_DEFAULT, /*expectToBeFiltered=*/false);
8508 testNotifyMotion(SECOND_DISPLAY_ID, /*expectToBeFiltered=*/false);
Jackal Guof9696682018-10-05 12:23:23 +08008509}
8510
8511// Test InputFilter for KeyEvent
8512TEST_F(InputFilterTest, KeyEvent_InputFilter) {
8513 // Since the InputFilter is disabled by default, check if key event aren't filtered.
Harry Cutts101ee9b2023-07-06 18:04:14 +00008514 testNotifyKey(/*expectToBeFiltered=*/false);
Jackal Guof9696682018-10-05 12:23:23 +08008515
8516 // Enable InputFilter
8517 mDispatcher->setInputFilterEnabled(true);
8518 // Send a key event, and check if it is filtered.
Harry Cutts101ee9b2023-07-06 18:04:14 +00008519 testNotifyKey(/*expectToBeFiltered=*/true);
Jackal Guof9696682018-10-05 12:23:23 +08008520
8521 // Disable InputFilter
8522 mDispatcher->setInputFilterEnabled(false);
8523 // Send a key event, and check if it isn't filtered.
Harry Cutts101ee9b2023-07-06 18:04:14 +00008524 testNotifyKey(/*expectToBeFiltered=*/false);
Jackal Guof9696682018-10-05 12:23:23 +08008525}
8526
Prabir Pradhan81420cc2021-09-06 10:28:50 -07008527// Ensure that MotionEvents sent to the InputFilter through InputListener are converted to the
8528// logical display coordinate space.
8529TEST_F(InputFilterTest, MotionEvent_UsesLogicalDisplayCoordinates_notifyMotion) {
8530 ui::Transform firstDisplayTransform;
8531 firstDisplayTransform.set({1.1, 2.2, 3.3, 4.4, 5.5, 6.6, 0, 0, 1});
8532 ui::Transform secondDisplayTransform;
8533 secondDisplayTransform.set({-6.6, -5.5, -4.4, -3.3, -2.2, -1.1, 0, 0, 1});
8534
8535 std::vector<gui::DisplayInfo> displayInfos(2);
8536 displayInfos[0].displayId = ADISPLAY_ID_DEFAULT;
8537 displayInfos[0].transform = firstDisplayTransform;
8538 displayInfos[1].displayId = SECOND_DISPLAY_ID;
8539 displayInfos[1].transform = secondDisplayTransform;
8540
Patrick Williamsd828f302023-04-28 17:52:08 -05008541 mDispatcher->onWindowInfosChanged({{}, displayInfos, 0, 0});
Prabir Pradhan81420cc2021-09-06 10:28:50 -07008542
8543 // Enable InputFilter
8544 mDispatcher->setInputFilterEnabled(true);
8545
8546 // Ensure the correct transforms are used for the displays.
Harry Cutts101ee9b2023-07-06 18:04:14 +00008547 testNotifyMotion(ADISPLAY_ID_DEFAULT, /*expectToBeFiltered=*/true, firstDisplayTransform);
8548 testNotifyMotion(SECOND_DISPLAY_ID, /*expectToBeFiltered=*/true, secondDisplayTransform);
Prabir Pradhan81420cc2021-09-06 10:28:50 -07008549}
8550
Siarhei Vishniakou5d552c42021-05-21 05:02:22 +00008551class InputFilterInjectionPolicyTest : public InputDispatcherTest {
8552protected:
8553 virtual void SetUp() override {
8554 InputDispatcherTest::SetUp();
8555
8556 /**
8557 * We don't need to enable input filter to test the injected event policy, but we enabled it
8558 * here to make the tests more realistic, since this policy only matters when inputfilter is
8559 * on.
8560 */
8561 mDispatcher->setInputFilterEnabled(true);
8562
8563 std::shared_ptr<InputApplicationHandle> application =
8564 std::make_shared<FakeApplicationHandle>();
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07008565 mWindow = sp<FakeWindowHandle>::make(application, mDispatcher, "Test Window",
8566 ADISPLAY_ID_DEFAULT);
Siarhei Vishniakou5d552c42021-05-21 05:02:22 +00008567
8568 mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application);
8569 mWindow->setFocusable(true);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07008570 mDispatcher->onWindowInfosChanged({{*mWindow->getInfo()}, {}, 0, 0});
Siarhei Vishniakou5d552c42021-05-21 05:02:22 +00008571 setFocusedWindow(mWindow);
8572 mWindow->consumeFocusEvent(true);
8573 }
8574
Siarhei Vishniakouf00a4ec2021-06-16 03:55:32 +00008575 void testInjectedKey(int32_t policyFlags, int32_t injectedDeviceId, int32_t resolvedDeviceId,
8576 int32_t flags) {
Siarhei Vishniakou5d552c42021-05-21 05:02:22 +00008577 KeyEvent event;
8578
8579 const nsecs_t eventTime = systemTime(SYSTEM_TIME_MONOTONIC);
8580 event.initialize(InputEvent::nextId(), injectedDeviceId, AINPUT_SOURCE_KEYBOARD,
8581 ADISPLAY_ID_NONE, INVALID_HMAC, AKEY_EVENT_ACTION_DOWN, 0, AKEYCODE_A,
Harry Cutts33476232023-01-30 19:57:29 +00008582 KEY_A, AMETA_NONE, /*repeatCount=*/0, eventTime, eventTime);
Siarhei Vishniakou5d552c42021-05-21 05:02:22 +00008583 const int32_t additionalPolicyFlags =
8584 POLICY_FLAG_PASS_TO_USER | POLICY_FLAG_DISABLE_KEY_REPEAT;
8585 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Harry Cutts33476232023-01-30 19:57:29 +00008586 mDispatcher->injectInputEvent(&event, /*targetUid=*/{},
Siarhei Vishniakou4648fea2023-06-27 01:00:12 +00008587 InputEventInjectionSync::WAIT_FOR_RESULT, 100ms,
Siarhei Vishniakou5d552c42021-05-21 05:02:22 +00008588 policyFlags | additionalPolicyFlags));
8589
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07008590 mWindow->consumeKeyEvent(AllOf(WithDeviceId(resolvedDeviceId), WithFlags(flags)));
Siarhei Vishniakouf00a4ec2021-06-16 03:55:32 +00008591 }
8592
8593 void testInjectedMotion(int32_t policyFlags, int32_t injectedDeviceId, int32_t resolvedDeviceId,
8594 int32_t flags) {
8595 MotionEvent event;
8596 PointerProperties pointerProperties[1];
8597 PointerCoords pointerCoords[1];
8598 pointerProperties[0].clear();
8599 pointerProperties[0].id = 0;
8600 pointerCoords[0].clear();
8601 pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_X, 300);
8602 pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_Y, 400);
8603
8604 ui::Transform identityTransform;
8605 const nsecs_t eventTime = systemTime(SYSTEM_TIME_MONOTONIC);
8606 event.initialize(InputEvent::nextId(), injectedDeviceId, AINPUT_SOURCE_TOUCHSCREEN,
8607 DISPLAY_ID, INVALID_HMAC, AMOTION_EVENT_ACTION_DOWN, 0, 0,
8608 AMOTION_EVENT_EDGE_FLAG_NONE, AMETA_NONE, 0, MotionClassification::NONE,
8609 identityTransform, 0, 0, AMOTION_EVENT_INVALID_CURSOR_POSITION,
Prabir Pradhanb9b18502021-08-26 12:30:32 -07008610 AMOTION_EVENT_INVALID_CURSOR_POSITION, identityTransform, eventTime,
Evan Rosky09576692021-07-01 12:22:09 -07008611 eventTime,
Harry Cutts101ee9b2023-07-06 18:04:14 +00008612 /*pointerCount=*/1, pointerProperties, pointerCoords);
Siarhei Vishniakouf00a4ec2021-06-16 03:55:32 +00008613
8614 const int32_t additionalPolicyFlags = POLICY_FLAG_PASS_TO_USER;
8615 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Harry Cutts33476232023-01-30 19:57:29 +00008616 mDispatcher->injectInputEvent(&event, /*targetUid=*/{},
Siarhei Vishniakou4648fea2023-06-27 01:00:12 +00008617 InputEventInjectionSync::WAIT_FOR_RESULT, 100ms,
Siarhei Vishniakouf00a4ec2021-06-16 03:55:32 +00008618 policyFlags | additionalPolicyFlags));
8619
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07008620 mWindow->consumeMotionEvent(AllOf(WithFlags(flags), WithDeviceId(resolvedDeviceId)));
Siarhei Vishniakou5d552c42021-05-21 05:02:22 +00008621 }
8622
8623private:
8624 sp<FakeWindowHandle> mWindow;
8625};
8626
8627TEST_F(InputFilterInjectionPolicyTest, TrustedFilteredEvents_KeepOriginalDeviceId) {
Siarhei Vishniakouf00a4ec2021-06-16 03:55:32 +00008628 // Must have POLICY_FLAG_FILTERED here to indicate that the event has gone through the input
8629 // filter. Without it, the event will no different from a regularly injected event, and the
8630 // injected device id will be overwritten.
Harry Cutts33476232023-01-30 19:57:29 +00008631 testInjectedKey(POLICY_FLAG_FILTERED, /*injectedDeviceId=*/3, /*resolvedDeviceId=*/3,
8632 /*flags=*/0);
Siarhei Vishniakou5d552c42021-05-21 05:02:22 +00008633}
8634
Siarhei Vishniakouf00a4ec2021-06-16 03:55:32 +00008635TEST_F(InputFilterInjectionPolicyTest, KeyEventsInjectedFromAccessibility_HaveAccessibilityFlag) {
Siarhei Vishniakou5d552c42021-05-21 05:02:22 +00008636 testInjectedKey(POLICY_FLAG_FILTERED | POLICY_FLAG_INJECTED_FROM_ACCESSIBILITY,
Harry Cutts33476232023-01-30 19:57:29 +00008637 /*injectedDeviceId=*/3, /*resolvedDeviceId=*/3,
Siarhei Vishniakouf00a4ec2021-06-16 03:55:32 +00008638 AKEY_EVENT_FLAG_IS_ACCESSIBILITY_EVENT);
8639}
8640
8641TEST_F(InputFilterInjectionPolicyTest,
8642 MotionEventsInjectedFromAccessibility_HaveAccessibilityFlag) {
8643 testInjectedMotion(POLICY_FLAG_FILTERED | POLICY_FLAG_INJECTED_FROM_ACCESSIBILITY,
Harry Cutts33476232023-01-30 19:57:29 +00008644 /*injectedDeviceId=*/3, /*resolvedDeviceId=*/3,
Siarhei Vishniakouf00a4ec2021-06-16 03:55:32 +00008645 AMOTION_EVENT_FLAG_IS_ACCESSIBILITY_EVENT);
Siarhei Vishniakou5d552c42021-05-21 05:02:22 +00008646}
8647
8648TEST_F(InputFilterInjectionPolicyTest, RegularInjectedEvents_ReceiveVirtualDeviceId) {
Harry Cutts33476232023-01-30 19:57:29 +00008649 testInjectedKey(/*policyFlags=*/0, /*injectedDeviceId=*/3,
8650 /*resolvedDeviceId=*/VIRTUAL_KEYBOARD_ID, /*flags=*/0);
Siarhei Vishniakou5d552c42021-05-21 05:02:22 +00008651}
8652
Yeabkal Wubshitb8aadfa2024-01-17 17:03:42 -08008653class InputDispatcherUserActivityPokeTests : public InputDispatcherTest {
8654protected:
8655 virtual void SetUp() override {
8656 InputDispatcherTest::SetUp();
8657
8658 std::shared_ptr<FakeApplicationHandle> application =
8659 std::make_shared<FakeApplicationHandle>();
8660 application->setDispatchingTimeout(100ms);
8661 mWindow = sp<FakeWindowHandle>::make(application, mDispatcher, "TestWindow",
8662 ADISPLAY_ID_DEFAULT);
Yeabkal Wubshit222d83d2024-01-24 18:00:09 +00008663 mWindow->setFrame(Rect(0, 0, 100, 100));
Yeabkal Wubshitb8aadfa2024-01-17 17:03:42 -08008664 mWindow->setDispatchingTimeout(100ms);
8665 mWindow->setFocusable(true);
8666
8667 // Set focused application.
8668 mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application);
8669
8670 mDispatcher->onWindowInfosChanged({{*mWindow->getInfo()}, {}, 0, 0});
8671 setFocusedWindow(mWindow);
8672 mWindow->consumeFocusEvent(true);
8673 }
8674
8675 void notifyAndConsumeMotion(int32_t action, uint32_t source, int32_t displayId,
8676 nsecs_t eventTime) {
8677 mDispatcher->notifyMotion(MotionArgsBuilder(action, source)
8678 .displayId(displayId)
8679 .eventTime(eventTime)
8680 .pointer(PointerBuilder(0, ToolType::FINGER).x(50).y(50))
8681 .build());
8682 mWindow->consumeMotionEvent(WithMotionAction(action));
8683 }
8684
8685private:
8686 sp<FakeWindowHandle> mWindow;
8687};
8688
8689TEST_F_WITH_FLAGS(
8690 InputDispatcherUserActivityPokeTests, MinPokeTimeObserved,
8691 REQUIRES_FLAGS_ENABLED(ACONFIG_FLAG(com::android::input::flags,
8692 rate_limit_user_activity_poke_in_dispatcher))) {
8693 mDispatcher->setMinTimeBetweenUserActivityPokes(50ms);
8694
8695 // First event of type TOUCH. Should poke.
8696 notifyAndConsumeMotion(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
8697 milliseconds_to_nanoseconds(50));
8698 mFakePolicy->assertUserActivityPoked(
8699 {{milliseconds_to_nanoseconds(50), USER_ACTIVITY_EVENT_TOUCH, ADISPLAY_ID_DEFAULT}});
8700
8701 // 80ns > 50ns has passed since previous TOUCH event. Should poke.
8702 notifyAndConsumeMotion(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
8703 milliseconds_to_nanoseconds(130));
8704 mFakePolicy->assertUserActivityPoked(
8705 {{milliseconds_to_nanoseconds(130), USER_ACTIVITY_EVENT_TOUCH, ADISPLAY_ID_DEFAULT}});
8706
8707 // First event of type OTHER. Should poke (despite being within 50ns of previous TOUCH event).
8708 notifyAndConsumeMotion(ACTION_SCROLL, AINPUT_SOURCE_ROTARY_ENCODER, ADISPLAY_ID_DEFAULT,
8709 milliseconds_to_nanoseconds(135));
8710 mFakePolicy->assertUserActivityPoked(
8711 {{milliseconds_to_nanoseconds(135), USER_ACTIVITY_EVENT_OTHER, ADISPLAY_ID_DEFAULT}});
8712
8713 // Within 50ns of previous TOUCH event. Should NOT poke.
8714 notifyAndConsumeMotion(ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
8715 milliseconds_to_nanoseconds(140));
8716 mFakePolicy->assertUserActivityNotPoked();
8717
8718 // Within 50ns of previous OTHER event. Should NOT poke.
8719 notifyAndConsumeMotion(ACTION_SCROLL, AINPUT_SOURCE_ROTARY_ENCODER, ADISPLAY_ID_DEFAULT,
8720 milliseconds_to_nanoseconds(150));
8721 mFakePolicy->assertUserActivityNotPoked();
8722
8723 // Within 50ns of previous TOUCH event (which was at time 130). Should NOT poke.
8724 // Note that STYLUS is mapped to TOUCH user activity, since it's a pointer-type source.
8725 notifyAndConsumeMotion(ACTION_DOWN, AINPUT_SOURCE_STYLUS, ADISPLAY_ID_DEFAULT,
8726 milliseconds_to_nanoseconds(160));
8727 mFakePolicy->assertUserActivityNotPoked();
8728
8729 // 65ns > 50ns has passed since previous OTHER event. Should poke.
8730 notifyAndConsumeMotion(ACTION_SCROLL, AINPUT_SOURCE_ROTARY_ENCODER, ADISPLAY_ID_DEFAULT,
8731 milliseconds_to_nanoseconds(200));
8732 mFakePolicy->assertUserActivityPoked(
8733 {{milliseconds_to_nanoseconds(200), USER_ACTIVITY_EVENT_OTHER, ADISPLAY_ID_DEFAULT}});
8734
8735 // 170ns > 50ns has passed since previous TOUCH event. Should poke.
8736 notifyAndConsumeMotion(ACTION_UP, AINPUT_SOURCE_STYLUS, ADISPLAY_ID_DEFAULT,
8737 milliseconds_to_nanoseconds(300));
8738 mFakePolicy->assertUserActivityPoked(
8739 {{milliseconds_to_nanoseconds(300), USER_ACTIVITY_EVENT_TOUCH, ADISPLAY_ID_DEFAULT}});
8740
8741 // Assert that there's no more user activity poke event.
8742 mFakePolicy->assertUserActivityNotPoked();
8743}
8744
8745TEST_F_WITH_FLAGS(
8746 InputDispatcherUserActivityPokeTests, DefaultMinPokeTimeOf100MsUsed,
8747 REQUIRES_FLAGS_ENABLED(ACONFIG_FLAG(com::android::input::flags,
8748 rate_limit_user_activity_poke_in_dispatcher))) {
8749 notifyAndConsumeMotion(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
8750 milliseconds_to_nanoseconds(200));
8751 mFakePolicy->assertUserActivityPoked(
8752 {{milliseconds_to_nanoseconds(200), USER_ACTIVITY_EVENT_TOUCH, ADISPLAY_ID_DEFAULT}});
8753
8754 notifyAndConsumeMotion(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
8755 milliseconds_to_nanoseconds(280));
8756 mFakePolicy->assertUserActivityNotPoked();
8757
8758 notifyAndConsumeMotion(ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
8759 milliseconds_to_nanoseconds(340));
8760 mFakePolicy->assertUserActivityPoked(
8761 {{milliseconds_to_nanoseconds(340), USER_ACTIVITY_EVENT_TOUCH, ADISPLAY_ID_DEFAULT}});
8762}
8763
8764TEST_F_WITH_FLAGS(
8765 InputDispatcherUserActivityPokeTests, ZeroMinPokeTimeDisablesRateLimiting,
8766 REQUIRES_FLAGS_ENABLED(ACONFIG_FLAG(com::android::input::flags,
8767 rate_limit_user_activity_poke_in_dispatcher))) {
8768 mDispatcher->setMinTimeBetweenUserActivityPokes(0ms);
8769
8770 notifyAndConsumeMotion(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, 20);
8771 mFakePolicy->assertUserActivityPoked();
8772
8773 notifyAndConsumeMotion(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, 30);
8774 mFakePolicy->assertUserActivityPoked();
8775}
8776
chaviwfd6d3512019-03-25 13:23:49 -07008777class InputDispatcherOnPointerDownOutsideFocus : public InputDispatcherTest {
Prabir Pradhan3608aad2019-10-02 17:08:26 -07008778 virtual void SetUp() override {
chaviwfd6d3512019-03-25 13:23:49 -07008779 InputDispatcherTest::SetUp();
8780
Chris Yea209fde2020-07-22 13:54:51 -07008781 std::shared_ptr<FakeApplicationHandle> application =
8782 std::make_shared<FakeApplicationHandle>();
Siarhei Vishniakou870ecec2020-12-09 08:07:46 -10008783 mUnfocusedWindow =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07008784 sp<FakeWindowHandle>::make(application, mDispatcher, "Top", ADISPLAY_ID_DEFAULT);
chaviwfd6d3512019-03-25 13:23:49 -07008785 mUnfocusedWindow->setFrame(Rect(0, 0, 30, 30));
chaviwfd6d3512019-03-25 13:23:49 -07008786
Siarhei Vishniakoub9b15352019-11-26 13:19:26 -08008787 mFocusedWindow =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07008788 sp<FakeWindowHandle>::make(application, mDispatcher, "Second", ADISPLAY_ID_DEFAULT);
Siarhei Vishniakoub9b15352019-11-26 13:19:26 -08008789 mFocusedWindow->setFrame(Rect(50, 50, 100, 100));
chaviwfd6d3512019-03-25 13:23:49 -07008790
8791 // Set focused application.
8792 mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application);
Vishnu Nair47074b82020-08-14 11:54:47 -07008793 mFocusedWindow->setFocusable(true);
chaviwfd6d3512019-03-25 13:23:49 -07008794
8795 // Expect one focus window exist in display.
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07008796 mDispatcher->onWindowInfosChanged(
8797 {{*mUnfocusedWindow->getInfo(), *mFocusedWindow->getInfo()}, {}, 0, 0});
Vishnu Nair958da932020-08-21 17:12:37 -07008798 setFocusedWindow(mFocusedWindow);
Siarhei Vishniakouf1035d42019-09-20 16:32:01 +01008799 mFocusedWindow->consumeFocusEvent(true);
chaviwfd6d3512019-03-25 13:23:49 -07008800 }
8801
Prabir Pradhan3608aad2019-10-02 17:08:26 -07008802 virtual void TearDown() override {
chaviwfd6d3512019-03-25 13:23:49 -07008803 InputDispatcherTest::TearDown();
8804
8805 mUnfocusedWindow.clear();
Siarhei Vishniakoub9b15352019-11-26 13:19:26 -08008806 mFocusedWindow.clear();
chaviwfd6d3512019-03-25 13:23:49 -07008807 }
8808
8809protected:
8810 sp<FakeWindowHandle> mUnfocusedWindow;
Siarhei Vishniakoub9b15352019-11-26 13:19:26 -08008811 sp<FakeWindowHandle> mFocusedWindow;
Siarhei Vishniakoufb9fcda2020-05-04 14:59:19 -07008812 static constexpr PointF FOCUSED_WINDOW_TOUCH_POINT = {60, 60};
chaviwfd6d3512019-03-25 13:23:49 -07008813};
8814
8815// Have two windows, one with focus. Inject MotionEvent with source TOUCHSCREEN and action
8816// DOWN on the window that doesn't have focus. Ensure the window that didn't have focus received
8817// the onPointerDownOutsideFocus callback.
8818TEST_F(InputDispatcherOnPointerDownOutsideFocus, OnPointerDownOutsideFocus_Success) {
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08008819 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07008820 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
Siarhei Vishniakoufb9fcda2020-05-04 14:59:19 -07008821 {20, 20}))
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08008822 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
Siarhei Vishniakou03aee2a2020-04-13 20:44:54 -07008823 mUnfocusedWindow->consumeMotionDown();
chaviwfd6d3512019-03-25 13:23:49 -07008824
Siarhei Vishniakou2bfa9052019-11-21 18:10:54 -08008825 ASSERT_TRUE(mDispatcher->waitForIdle());
chaviwfd6d3512019-03-25 13:23:49 -07008826 mFakePolicy->assertOnPointerDownEquals(mUnfocusedWindow->getToken());
8827}
8828
8829// Have two windows, one with focus. Inject MotionEvent with source TRACKBALL and action
8830// DOWN on the window that doesn't have focus. Ensure no window received the
8831// onPointerDownOutsideFocus callback.
8832TEST_F(InputDispatcherOnPointerDownOutsideFocus, OnPointerDownOutsideFocus_NonPointerSource) {
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08008833 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07008834 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TRACKBALL, ADISPLAY_ID_DEFAULT,
8835 {20, 20}))
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08008836 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
Siarhei Vishniakou03aee2a2020-04-13 20:44:54 -07008837 mFocusedWindow->consumeMotionDown();
chaviwfd6d3512019-03-25 13:23:49 -07008838
Siarhei Vishniakou2bfa9052019-11-21 18:10:54 -08008839 ASSERT_TRUE(mDispatcher->waitForIdle());
8840 mFakePolicy->assertOnPointerDownWasNotCalled();
chaviwfd6d3512019-03-25 13:23:49 -07008841}
8842
8843// Have two windows, one with focus. Inject KeyEvent with action DOWN on the window that doesn't
8844// have focus. Ensure no window received the onPointerDownOutsideFocus callback.
8845TEST_F(InputDispatcherOnPointerDownOutsideFocus, OnPointerDownOutsideFocus_NonMotionFailure) {
Prabir Pradhan93f342c2021-03-11 15:05:30 -08008846 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07008847 injectKeyDownNoRepeat(*mDispatcher, ADISPLAY_ID_DEFAULT))
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08008848 << "Inject key event should return InputEventInjectionResult::SUCCEEDED";
Siarhei Vishniakou03aee2a2020-04-13 20:44:54 -07008849 mFocusedWindow->consumeKeyDown(ADISPLAY_ID_DEFAULT);
chaviwfd6d3512019-03-25 13:23:49 -07008850
Siarhei Vishniakou2bfa9052019-11-21 18:10:54 -08008851 ASSERT_TRUE(mDispatcher->waitForIdle());
8852 mFakePolicy->assertOnPointerDownWasNotCalled();
chaviwfd6d3512019-03-25 13:23:49 -07008853}
8854
8855// Have two windows, one with focus. Inject MotionEvent with source TOUCHSCREEN and action
8856// DOWN on the window that already has focus. Ensure no window received the
8857// onPointerDownOutsideFocus callback.
Siarhei Vishniakou870ecec2020-12-09 08:07:46 -10008858TEST_F(InputDispatcherOnPointerDownOutsideFocus, OnPointerDownOutsideFocus_OnAlreadyFocusedWindow) {
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08008859 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07008860 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
Siarhei Vishniakoufb9fcda2020-05-04 14:59:19 -07008861 FOCUSED_WINDOW_TOUCH_POINT))
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08008862 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
Siarhei Vishniakou03aee2a2020-04-13 20:44:54 -07008863 mFocusedWindow->consumeMotionDown();
chaviwfd6d3512019-03-25 13:23:49 -07008864
Siarhei Vishniakou2bfa9052019-11-21 18:10:54 -08008865 ASSERT_TRUE(mDispatcher->waitForIdle());
8866 mFakePolicy->assertOnPointerDownWasNotCalled();
chaviwfd6d3512019-03-25 13:23:49 -07008867}
8868
Prabir Pradhan47cf0a02021-03-11 20:30:57 -08008869// Have two windows, one with focus. Injecting a trusted DOWN MotionEvent with the flag
8870// NO_FOCUS_CHANGE on the unfocused window should not call the onPointerDownOutsideFocus callback.
8871TEST_F(InputDispatcherOnPointerDownOutsideFocus, NoFocusChangeFlag) {
8872 const MotionEvent event =
8873 MotionEventBuilder(AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_MOUSE)
8874 .eventTime(systemTime(SYSTEM_TIME_MONOTONIC))
Siarhei Vishniakou6d73f832022-07-21 17:27:03 -07008875 .pointer(PointerBuilder(/*id=*/0, ToolType::FINGER).x(20).y(20))
Prabir Pradhan47cf0a02021-03-11 20:30:57 -08008876 .addFlag(AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE)
8877 .build();
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07008878 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectMotionEvent(*mDispatcher, event))
Prabir Pradhan47cf0a02021-03-11 20:30:57 -08008879 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
8880 mUnfocusedWindow->consumeAnyMotionDown(ADISPLAY_ID_DEFAULT, AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
8881
8882 ASSERT_TRUE(mDispatcher->waitForIdle());
8883 mFakePolicy->assertOnPointerDownWasNotCalled();
8884 // Ensure that the unfocused window did not receive any FOCUS events.
8885 mUnfocusedWindow->assertNoEvents();
8886}
8887
chaviwaf87b3e2019-10-01 16:59:28 -07008888// These tests ensures we can send touch events to a single client when there are multiple input
8889// windows that point to the same client token.
8890class InputDispatcherMultiWindowSameTokenTests : public InputDispatcherTest {
8891 virtual void SetUp() override {
8892 InputDispatcherTest::SetUp();
8893
Chris Yea209fde2020-07-22 13:54:51 -07008894 std::shared_ptr<FakeApplicationHandle> application =
8895 std::make_shared<FakeApplicationHandle>();
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07008896 mWindow1 = sp<FakeWindowHandle>::make(application, mDispatcher, "Fake Window 1",
8897 ADISPLAY_ID_DEFAULT);
chaviwaf87b3e2019-10-01 16:59:28 -07008898 mWindow1->setFrame(Rect(0, 0, 100, 100));
8899
Prabir Pradhane7cc69c2024-01-05 21:35:28 +00008900 mWindow2 = mWindow1->clone(ADISPLAY_ID_DEFAULT);
chaviwaf87b3e2019-10-01 16:59:28 -07008901 mWindow2->setFrame(Rect(100, 100, 200, 200));
8902
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07008903 mDispatcher->onWindowInfosChanged({{*mWindow1->getInfo(), *mWindow2->getInfo()}, {}, 0, 0});
chaviwaf87b3e2019-10-01 16:59:28 -07008904 }
8905
8906protected:
8907 sp<FakeWindowHandle> mWindow1;
8908 sp<FakeWindowHandle> mWindow2;
8909
8910 // Helper function to convert the point from screen coordinates into the window's space
chaviw3277faf2021-05-19 16:45:23 -05008911 static PointF getPointInWindow(const WindowInfo* windowInfo, const PointF& point) {
chaviw1ff3d1e2020-07-01 15:53:47 -07008912 vec2 vals = windowInfo->transform.transform(point.x, point.y);
8913 return {vals.x, vals.y};
chaviwaf87b3e2019-10-01 16:59:28 -07008914 }
8915
8916 void consumeMotionEvent(const sp<FakeWindowHandle>& window, int32_t expectedAction,
8917 const std::vector<PointF>& points) {
Siarhei Vishniakouf1035d42019-09-20 16:32:01 +01008918 const std::string name = window->getName();
Siarhei Vishniakoud3061ab2023-12-18 20:41:08 -08008919 std::unique_ptr<MotionEvent> motionEvent =
Prabir Pradhan7662a8d2023-12-15 01:58:14 +00008920 window->consumeMotionEvent(WithMotionAction(expectedAction));
Siarhei Vishniakoud3061ab2023-12-18 20:41:08 -08008921 ASSERT_NE(nullptr, motionEvent);
8922 ASSERT_EQ(points.size(), motionEvent->getPointerCount());
chaviwaf87b3e2019-10-01 16:59:28 -07008923
8924 for (size_t i = 0; i < points.size(); i++) {
8925 float expectedX = points[i].x;
8926 float expectedY = points[i].y;
8927
Siarhei Vishniakoud3061ab2023-12-18 20:41:08 -08008928 EXPECT_EQ(expectedX, motionEvent->getX(i))
chaviwaf87b3e2019-10-01 16:59:28 -07008929 << "expected " << expectedX << " for x[" << i << "] coord of " << name.c_str()
Siarhei Vishniakoud3061ab2023-12-18 20:41:08 -08008930 << ", got " << motionEvent->getX(i);
8931 EXPECT_EQ(expectedY, motionEvent->getY(i))
chaviwaf87b3e2019-10-01 16:59:28 -07008932 << "expected " << expectedY << " for y[" << i << "] coord of " << name.c_str()
Siarhei Vishniakoud3061ab2023-12-18 20:41:08 -08008933 << ", got " << motionEvent->getY(i);
chaviwaf87b3e2019-10-01 16:59:28 -07008934 }
8935 }
chaviw9eaa22c2020-07-01 16:21:27 -07008936
Prabir Pradhanbb3f1c02024-01-04 20:17:14 +00008937 void touchAndAssertPositions(sp<FakeWindowHandle> touchedWindow, int32_t action,
8938 const std::vector<PointF>& touchedPoints,
chaviw9eaa22c2020-07-01 16:21:27 -07008939 std::vector<PointF> expectedPoints) {
Prabir Pradhan678438e2023-04-13 19:32:51 +00008940 mDispatcher->notifyMotion(generateMotionArgs(action, AINPUT_SOURCE_TOUCHSCREEN,
8941 ADISPLAY_ID_DEFAULT, touchedPoints));
chaviw9eaa22c2020-07-01 16:21:27 -07008942
Prabir Pradhanbb3f1c02024-01-04 20:17:14 +00008943 consumeMotionEvent(touchedWindow, action, expectedPoints);
chaviw9eaa22c2020-07-01 16:21:27 -07008944 }
chaviwaf87b3e2019-10-01 16:59:28 -07008945};
8946
8947TEST_F(InputDispatcherMultiWindowSameTokenTests, SingleTouchSameScale) {
8948 // Touch Window 1
8949 PointF touchedPoint = {10, 10};
8950 PointF expectedPoint = getPointInWindow(mWindow1->getInfo(), touchedPoint);
Prabir Pradhanbb3f1c02024-01-04 20:17:14 +00008951 touchAndAssertPositions(mWindow1, AMOTION_EVENT_ACTION_DOWN, {touchedPoint}, {expectedPoint});
chaviwaf87b3e2019-10-01 16:59:28 -07008952
8953 // Release touch on Window 1
Prabir Pradhanbb3f1c02024-01-04 20:17:14 +00008954 touchAndAssertPositions(mWindow1, AMOTION_EVENT_ACTION_UP, {touchedPoint}, {expectedPoint});
chaviwaf87b3e2019-10-01 16:59:28 -07008955
8956 // Touch Window 2
8957 touchedPoint = {150, 150};
8958 expectedPoint = getPointInWindow(mWindow2->getInfo(), touchedPoint);
Prabir Pradhanbb3f1c02024-01-04 20:17:14 +00008959 touchAndAssertPositions(mWindow2, AMOTION_EVENT_ACTION_DOWN, {touchedPoint}, {expectedPoint});
chaviwaf87b3e2019-10-01 16:59:28 -07008960}
8961
chaviw9eaa22c2020-07-01 16:21:27 -07008962TEST_F(InputDispatcherMultiWindowSameTokenTests, SingleTouchDifferentTransform) {
8963 // Set scale value for window2
chaviwaf87b3e2019-10-01 16:59:28 -07008964 mWindow2->setWindowScale(0.5f, 0.5f);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07008965 mDispatcher->onWindowInfosChanged({{*mWindow1->getInfo(), *mWindow2->getInfo()}, {}, 0, 0});
chaviwaf87b3e2019-10-01 16:59:28 -07008966
8967 // Touch Window 1
8968 PointF touchedPoint = {10, 10};
8969 PointF expectedPoint = getPointInWindow(mWindow1->getInfo(), touchedPoint);
Prabir Pradhanbb3f1c02024-01-04 20:17:14 +00008970 touchAndAssertPositions(mWindow1, AMOTION_EVENT_ACTION_DOWN, {touchedPoint}, {expectedPoint});
chaviwaf87b3e2019-10-01 16:59:28 -07008971 // Release touch on Window 1
Prabir Pradhanbb3f1c02024-01-04 20:17:14 +00008972 touchAndAssertPositions(mWindow1, AMOTION_EVENT_ACTION_UP, {touchedPoint}, {expectedPoint});
chaviwaf87b3e2019-10-01 16:59:28 -07008973
8974 // Touch Window 2
8975 touchedPoint = {150, 150};
8976 expectedPoint = getPointInWindow(mWindow2->getInfo(), touchedPoint);
Prabir Pradhanbb3f1c02024-01-04 20:17:14 +00008977 touchAndAssertPositions(mWindow2, AMOTION_EVENT_ACTION_DOWN, {touchedPoint}, {expectedPoint});
8978 touchAndAssertPositions(mWindow2, AMOTION_EVENT_ACTION_UP, {touchedPoint}, {expectedPoint});
chaviwaf87b3e2019-10-01 16:59:28 -07008979
chaviw9eaa22c2020-07-01 16:21:27 -07008980 // Update the transform so rotation is set
8981 mWindow2->setWindowTransform(0, -1, 1, 0);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07008982 mDispatcher->onWindowInfosChanged({{*mWindow1->getInfo(), *mWindow2->getInfo()}, {}, 0, 0});
chaviw9eaa22c2020-07-01 16:21:27 -07008983 expectedPoint = getPointInWindow(mWindow2->getInfo(), touchedPoint);
Prabir Pradhanbb3f1c02024-01-04 20:17:14 +00008984 touchAndAssertPositions(mWindow2, AMOTION_EVENT_ACTION_DOWN, {touchedPoint}, {expectedPoint});
chaviwaf87b3e2019-10-01 16:59:28 -07008985}
8986
chaviw9eaa22c2020-07-01 16:21:27 -07008987TEST_F(InputDispatcherMultiWindowSameTokenTests, MultipleTouchDifferentTransform) {
Chavi Weingarten65f98b82020-01-16 18:56:50 +00008988 mWindow2->setWindowScale(0.5f, 0.5f);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07008989 mDispatcher->onWindowInfosChanged({{*mWindow1->getInfo(), *mWindow2->getInfo()}, {}, 0, 0});
Chavi Weingarten65f98b82020-01-16 18:56:50 +00008990
8991 // Touch Window 1
8992 std::vector<PointF> touchedPoints = {PointF{10, 10}};
8993 std::vector<PointF> expectedPoints = {getPointInWindow(mWindow1->getInfo(), touchedPoints[0])};
Prabir Pradhanbb3f1c02024-01-04 20:17:14 +00008994 touchAndAssertPositions(mWindow1, AMOTION_EVENT_ACTION_DOWN, touchedPoints, expectedPoints);
Chavi Weingarten65f98b82020-01-16 18:56:50 +00008995
8996 // Touch Window 2
Prabir Pradhanbb3f1c02024-01-04 20:17:14 +00008997 // Since this is part of the same touch gesture that has already been dispatched to Window 1,
8998 // the touch stream from Window 2 will be merged with the stream in Window 1. The merged stream
8999 // will continue to be dispatched through Window 1.
chaviw9eaa22c2020-07-01 16:21:27 -07009000 touchedPoints.push_back(PointF{150, 150});
9001 expectedPoints.push_back(getPointInWindow(mWindow2->getInfo(), touchedPoints[1]));
Prabir Pradhanbb3f1c02024-01-04 20:17:14 +00009002 touchAndAssertPositions(mWindow1, POINTER_1_DOWN, touchedPoints, expectedPoints);
Chavi Weingarten65f98b82020-01-16 18:56:50 +00009003
chaviw9eaa22c2020-07-01 16:21:27 -07009004 // Release Window 2
Prabir Pradhanbb3f1c02024-01-04 20:17:14 +00009005 touchAndAssertPositions(mWindow1, POINTER_1_UP, touchedPoints, expectedPoints);
chaviw9eaa22c2020-07-01 16:21:27 -07009006 expectedPoints.pop_back();
Chavi Weingarten65f98b82020-01-16 18:56:50 +00009007
chaviw9eaa22c2020-07-01 16:21:27 -07009008 // Update the transform so rotation is set for Window 2
9009 mWindow2->setWindowTransform(0, -1, 1, 0);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07009010 mDispatcher->onWindowInfosChanged({{*mWindow1->getInfo(), *mWindow2->getInfo()}, {}, 0, 0});
chaviw9eaa22c2020-07-01 16:21:27 -07009011 expectedPoints.push_back(getPointInWindow(mWindow2->getInfo(), touchedPoints[1]));
Prabir Pradhanbb3f1c02024-01-04 20:17:14 +00009012 touchAndAssertPositions(mWindow1, POINTER_1_DOWN, touchedPoints, expectedPoints);
Chavi Weingarten65f98b82020-01-16 18:56:50 +00009013}
9014
chaviw9eaa22c2020-07-01 16:21:27 -07009015TEST_F(InputDispatcherMultiWindowSameTokenTests, MultipleTouchMoveDifferentTransform) {
Chavi Weingarten65f98b82020-01-16 18:56:50 +00009016 mWindow2->setWindowScale(0.5f, 0.5f);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07009017 mDispatcher->onWindowInfosChanged({{*mWindow1->getInfo(), *mWindow2->getInfo()}, {}, 0, 0});
Chavi Weingarten65f98b82020-01-16 18:56:50 +00009018
9019 // Touch Window 1
9020 std::vector<PointF> touchedPoints = {PointF{10, 10}};
9021 std::vector<PointF> expectedPoints = {getPointInWindow(mWindow1->getInfo(), touchedPoints[0])};
Prabir Pradhanbb3f1c02024-01-04 20:17:14 +00009022 touchAndAssertPositions(mWindow1, AMOTION_EVENT_ACTION_DOWN, touchedPoints, expectedPoints);
Chavi Weingarten65f98b82020-01-16 18:56:50 +00009023
9024 // Touch Window 2
chaviw9eaa22c2020-07-01 16:21:27 -07009025 touchedPoints.push_back(PointF{150, 150});
9026 expectedPoints.push_back(getPointInWindow(mWindow2->getInfo(), touchedPoints[1]));
Chavi Weingarten65f98b82020-01-16 18:56:50 +00009027
Prabir Pradhanbb3f1c02024-01-04 20:17:14 +00009028 touchAndAssertPositions(mWindow1, POINTER_1_DOWN, touchedPoints, expectedPoints);
Chavi Weingarten65f98b82020-01-16 18:56:50 +00009029
9030 // Move both windows
9031 touchedPoints = {{20, 20}, {175, 175}};
9032 expectedPoints = {getPointInWindow(mWindow1->getInfo(), touchedPoints[0]),
9033 getPointInWindow(mWindow2->getInfo(), touchedPoints[1])};
9034
Prabir Pradhanbb3f1c02024-01-04 20:17:14 +00009035 touchAndAssertPositions(mWindow1, AMOTION_EVENT_ACTION_MOVE, touchedPoints, expectedPoints);
Chavi Weingarten65f98b82020-01-16 18:56:50 +00009036
chaviw9eaa22c2020-07-01 16:21:27 -07009037 // Release Window 2
Prabir Pradhanbb3f1c02024-01-04 20:17:14 +00009038 touchAndAssertPositions(mWindow1, POINTER_1_UP, touchedPoints, expectedPoints);
chaviw9eaa22c2020-07-01 16:21:27 -07009039 expectedPoints.pop_back();
9040
9041 // Touch Window 2
9042 mWindow2->setWindowTransform(0, -1, 1, 0);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07009043 mDispatcher->onWindowInfosChanged({{*mWindow1->getInfo(), *mWindow2->getInfo()}, {}, 0, 0});
chaviw9eaa22c2020-07-01 16:21:27 -07009044 expectedPoints.push_back(getPointInWindow(mWindow2->getInfo(), touchedPoints[1]));
Prabir Pradhanbb3f1c02024-01-04 20:17:14 +00009045 touchAndAssertPositions(mWindow1, POINTER_1_DOWN, touchedPoints, expectedPoints);
chaviw9eaa22c2020-07-01 16:21:27 -07009046
9047 // Move both windows
9048 touchedPoints = {{20, 20}, {175, 175}};
9049 expectedPoints = {getPointInWindow(mWindow1->getInfo(), touchedPoints[0]),
9050 getPointInWindow(mWindow2->getInfo(), touchedPoints[1])};
9051
Prabir Pradhanbb3f1c02024-01-04 20:17:14 +00009052 touchAndAssertPositions(mWindow1, AMOTION_EVENT_ACTION_MOVE, touchedPoints, expectedPoints);
Chavi Weingarten65f98b82020-01-16 18:56:50 +00009053}
9054
9055TEST_F(InputDispatcherMultiWindowSameTokenTests, MultipleWindowsFirstTouchWithScale) {
9056 mWindow1->setWindowScale(0.5f, 0.5f);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07009057 mDispatcher->onWindowInfosChanged({{*mWindow1->getInfo(), *mWindow2->getInfo()}, {}, 0, 0});
Chavi Weingarten65f98b82020-01-16 18:56:50 +00009058
9059 // Touch Window 1
9060 std::vector<PointF> touchedPoints = {PointF{10, 10}};
9061 std::vector<PointF> expectedPoints = {getPointInWindow(mWindow1->getInfo(), touchedPoints[0])};
Prabir Pradhanbb3f1c02024-01-04 20:17:14 +00009062 touchAndAssertPositions(mWindow1, AMOTION_EVENT_ACTION_DOWN, touchedPoints, expectedPoints);
Chavi Weingarten65f98b82020-01-16 18:56:50 +00009063
9064 // Touch Window 2
chaviw9eaa22c2020-07-01 16:21:27 -07009065 touchedPoints.push_back(PointF{150, 150});
9066 expectedPoints.push_back(getPointInWindow(mWindow2->getInfo(), touchedPoints[1]));
Chavi Weingarten65f98b82020-01-16 18:56:50 +00009067
Prabir Pradhanbb3f1c02024-01-04 20:17:14 +00009068 touchAndAssertPositions(mWindow1, POINTER_1_DOWN, touchedPoints, expectedPoints);
Chavi Weingarten65f98b82020-01-16 18:56:50 +00009069
9070 // Move both windows
9071 touchedPoints = {{20, 20}, {175, 175}};
9072 expectedPoints = {getPointInWindow(mWindow1->getInfo(), touchedPoints[0]),
9073 getPointInWindow(mWindow2->getInfo(), touchedPoints[1])};
9074
Prabir Pradhanbb3f1c02024-01-04 20:17:14 +00009075 touchAndAssertPositions(mWindow1, AMOTION_EVENT_ACTION_MOVE, touchedPoints, expectedPoints);
Chavi Weingarten65f98b82020-01-16 18:56:50 +00009076}
9077
Siarhei Vishniakou0f6558d2023-04-21 12:05:13 -07009078/**
9079 * When one of the windows is slippery, the touch should not slip into the other window with the
9080 * same input channel.
9081 */
9082TEST_F(InputDispatcherMultiWindowSameTokenTests, TouchDoesNotSlipEvenIfSlippery) {
9083 mWindow1->setSlippery(true);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07009084 mDispatcher->onWindowInfosChanged({{*mWindow1->getInfo(), *mWindow2->getInfo()}, {}, 0, 0});
Siarhei Vishniakou0f6558d2023-04-21 12:05:13 -07009085
9086 // Touch down in window 1
9087 mDispatcher->notifyMotion(generateMotionArgs(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN,
9088 ADISPLAY_ID_DEFAULT, {{50, 50}}));
9089 consumeMotionEvent(mWindow1, ACTION_DOWN, {{50, 50}});
9090
9091 // Move touch to be above window 2. Even though window 1 is slippery, touch should not slip.
9092 // That means the gesture should continue normally, without any ACTION_CANCEL or ACTION_DOWN
9093 // getting generated.
9094 mDispatcher->notifyMotion(generateMotionArgs(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN,
9095 ADISPLAY_ID_DEFAULT, {{150, 150}}));
9096
9097 consumeMotionEvent(mWindow1, ACTION_MOVE, {{150, 150}});
9098}
9099
Siarhei Vishniakoud5876ba2023-05-15 17:58:34 -07009100/**
9101 * When hover starts in one window and continues into the other, there should be a HOVER_EXIT and
9102 * a HOVER_ENTER generated, even if the windows have the same token. This is because the new window
9103 * that the pointer is hovering over may have a different transform.
9104 */
9105TEST_F(InputDispatcherMultiWindowSameTokenTests, HoverIntoClone) {
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07009106 mDispatcher->onWindowInfosChanged({{*mWindow1->getInfo(), *mWindow2->getInfo()}, {}, 0, 0});
Siarhei Vishniakoud5876ba2023-05-15 17:58:34 -07009107
9108 // Start hover in window 1
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -07009109 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_ENTER, AINPUT_SOURCE_TOUCHSCREEN)
9110 .pointer(PointerBuilder(0, ToolType::FINGER).x(50).y(50))
9111 .build());
Siarhei Vishniakoud5876ba2023-05-15 17:58:34 -07009112 consumeMotionEvent(mWindow1, ACTION_HOVER_ENTER,
9113 {getPointInWindow(mWindow1->getInfo(), PointF{50, 50})});
Siarhei Vishniakoud5876ba2023-05-15 17:58:34 -07009114 // Move hover to window 2.
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -07009115 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_MOVE, AINPUT_SOURCE_TOUCHSCREEN)
9116 .pointer(PointerBuilder(0, ToolType::FINGER).x(150).y(150))
9117 .build());
Siarhei Vishniakoud5876ba2023-05-15 17:58:34 -07009118 consumeMotionEvent(mWindow1, ACTION_HOVER_EXIT, {{50, 50}});
Prabir Pradhanbb3f1c02024-01-04 20:17:14 +00009119 consumeMotionEvent(mWindow2, ACTION_HOVER_ENTER,
Siarhei Vishniakoud5876ba2023-05-15 17:58:34 -07009120 {getPointInWindow(mWindow2->getInfo(), PointF{150, 150})});
9121}
9122
Siarhei Vishniakou4cb50ca2020-05-26 21:43:02 -07009123class InputDispatcherSingleWindowAnr : public InputDispatcherTest {
9124 virtual void SetUp() override {
9125 InputDispatcherTest::SetUp();
9126
Chris Yea209fde2020-07-22 13:54:51 -07009127 mApplication = std::make_shared<FakeApplicationHandle>();
Siarhei Vishniakouf83c6932023-07-07 17:48:10 -07009128 mApplication->setDispatchingTimeout(100ms);
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07009129 mWindow = sp<FakeWindowHandle>::make(mApplication, mDispatcher, "TestWindow",
9130 ADISPLAY_ID_DEFAULT);
Siarhei Vishniakou4cb50ca2020-05-26 21:43:02 -07009131 mWindow->setFrame(Rect(0, 0, 30, 30));
Siarhei Vishniakouf83c6932023-07-07 17:48:10 -07009132 mWindow->setDispatchingTimeout(100ms);
Vishnu Nair47074b82020-08-14 11:54:47 -07009133 mWindow->setFocusable(true);
Siarhei Vishniakou4cb50ca2020-05-26 21:43:02 -07009134
9135 // Set focused application.
9136 mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, mApplication);
9137
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07009138 mDispatcher->onWindowInfosChanged({{*mWindow->getInfo()}, {}, 0, 0});
Vishnu Nair958da932020-08-21 17:12:37 -07009139 setFocusedWindow(mWindow);
Siarhei Vishniakou4cb50ca2020-05-26 21:43:02 -07009140 mWindow->consumeFocusEvent(true);
9141 }
9142
9143 virtual void TearDown() override {
9144 InputDispatcherTest::TearDown();
9145 mWindow.clear();
9146 }
9147
9148protected:
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07009149 static constexpr std::chrono::duration SPY_TIMEOUT = 200ms;
Chris Yea209fde2020-07-22 13:54:51 -07009150 std::shared_ptr<FakeApplicationHandle> mApplication;
Siarhei Vishniakou4cb50ca2020-05-26 21:43:02 -07009151 sp<FakeWindowHandle> mWindow;
9152 static constexpr PointF WINDOW_LOCATION = {20, 20};
9153
9154 void tapOnWindow() {
Siarhei Vishniakou67bf2162023-11-16 13:29:50 -08009155 const auto touchingPointer = PointerBuilder(/*id=*/0, ToolType::FINGER)
9156 .x(WINDOW_LOCATION.x)
9157 .y(WINDOW_LOCATION.y);
9158 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
9159 .pointer(touchingPointer)
9160 .build());
9161 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN)
9162 .pointer(touchingPointer)
9163 .build());
Siarhei Vishniakou4cb50ca2020-05-26 21:43:02 -07009164 }
Prabir Pradhan1376fcd2022-01-21 09:56:35 -08009165
9166 sp<FakeWindowHandle> addSpyWindow() {
9167 sp<FakeWindowHandle> spy =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07009168 sp<FakeWindowHandle>::make(mApplication, mDispatcher, "Spy", ADISPLAY_ID_DEFAULT);
Prabir Pradhan1376fcd2022-01-21 09:56:35 -08009169 spy->setTrustedOverlay(true);
9170 spy->setFocusable(false);
Prabir Pradhan51e7db02022-02-07 06:02:57 -08009171 spy->setSpy(true);
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07009172 spy->setDispatchingTimeout(SPY_TIMEOUT);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07009173 mDispatcher->onWindowInfosChanged({{*spy->getInfo(), *mWindow->getInfo()}, {}, 0, 0});
Prabir Pradhan1376fcd2022-01-21 09:56:35 -08009174 return spy;
9175 }
Siarhei Vishniakou4cb50ca2020-05-26 21:43:02 -07009176};
9177
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009178// Send a tap and respond, which should not cause an ANR.
9179TEST_F(InputDispatcherSingleWindowAnr, WhenTouchIsConsumed_NoAnr) {
9180 tapOnWindow();
9181 mWindow->consumeMotionDown();
9182 mWindow->consumeMotionUp();
9183 ASSERT_TRUE(mDispatcher->waitForIdle());
9184 mFakePolicy->assertNotifyAnrWasNotCalled();
9185}
9186
9187// Send a regular key and respond, which should not cause an ANR.
9188TEST_F(InputDispatcherSingleWindowAnr, WhenKeyIsConsumed_NoAnr) {
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07009189 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectKeyDownNoRepeat(*mDispatcher));
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009190 mWindow->consumeKeyDown(ADISPLAY_ID_NONE);
9191 ASSERT_TRUE(mDispatcher->waitForIdle());
9192 mFakePolicy->assertNotifyAnrWasNotCalled();
9193}
9194
Siarhei Vishniakoue41c4512020-09-08 19:35:58 -05009195TEST_F(InputDispatcherSingleWindowAnr, WhenFocusedApplicationChanges_NoAnr) {
9196 mWindow->setFocusable(false);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07009197 mDispatcher->onWindowInfosChanged({{*mWindow->getInfo()}, {}, 0, 0});
Siarhei Vishniakoue41c4512020-09-08 19:35:58 -05009198 mWindow->consumeFocusEvent(false);
9199
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08009200 InputEventInjectionResult result =
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07009201 injectKey(*mDispatcher, AKEY_EVENT_ACTION_DOWN, /*repeatCount=*/0, ADISPLAY_ID_DEFAULT,
9202 InputEventInjectionSync::NONE, CONSUME_TIMEOUT_EVENT_EXPECTED,
Harry Cutts33476232023-01-30 19:57:29 +00009203 /*allowKeyRepeat=*/false);
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08009204 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, result);
Siarhei Vishniakoue41c4512020-09-08 19:35:58 -05009205 // Key will not go to window because we have no focused window.
9206 // The 'no focused window' ANR timer should start instead.
9207
9208 // Now, the focused application goes away.
9209 mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, nullptr);
9210 // The key should get dropped and there should be no ANR.
9211
9212 ASSERT_TRUE(mDispatcher->waitForIdle());
9213 mFakePolicy->assertNotifyAnrWasNotCalled();
9214}
9215
Siarhei Vishniakou4cb50ca2020-05-26 21:43:02 -07009216// Send an event to the app and have the app not respond right away.
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009217// When ANR is raised, policy will tell the dispatcher to cancel the events for that window.
9218// So InputDispatcher will enqueue ACTION_CANCEL event as well.
Siarhei Vishniakou4cb50ca2020-05-26 21:43:02 -07009219TEST_F(InputDispatcherSingleWindowAnr, OnPointerDown_BasicAnr) {
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08009220 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07009221 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
Siarhei Vishniakou4cb50ca2020-05-26 21:43:02 -07009222 WINDOW_LOCATION));
9223
Siarhei Vishniakoud3061ab2023-12-18 20:41:08 -08009224 const auto [sequenceNum, _] = mWindow->receiveEvent(); // ACTION_DOWN
Siarhei Vishniakou4cb50ca2020-05-26 21:43:02 -07009225 ASSERT_TRUE(sequenceNum);
9226 const std::chrono::duration timeout = mWindow->getDispatchingTimeout(DISPATCHING_TIMEOUT);
Prabir Pradhanedd96402022-02-15 01:46:16 -08009227 mFakePolicy->assertNotifyWindowUnresponsiveWasCalled(timeout, mWindow);
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009228
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009229 mWindow->finishEvent(*sequenceNum);
Siarhei Vishniakou1ae72f12023-01-29 12:55:30 -08009230 mWindow->consumeMotionEvent(
9231 AllOf(WithMotionAction(ACTION_CANCEL), WithDisplayId(ADISPLAY_ID_DEFAULT)));
Siarhei Vishniakou4cb50ca2020-05-26 21:43:02 -07009232 ASSERT_TRUE(mDispatcher->waitForIdle());
Prabir Pradhanedd96402022-02-15 01:46:16 -08009233 mFakePolicy->assertNotifyWindowResponsiveWasCalled(mWindow->getToken(), mWindow->getPid());
Siarhei Vishniakou4cb50ca2020-05-26 21:43:02 -07009234}
9235
9236// Send a key to the app and have the app not respond right away.
9237TEST_F(InputDispatcherSingleWindowAnr, OnKeyDown_BasicAnr) {
9238 // Inject a key, and don't respond - expect that ANR is called.
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07009239 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectKeyDownNoRepeat(*mDispatcher));
Siarhei Vishniakoud3061ab2023-12-18 20:41:08 -08009240 const auto [sequenceNum, _] = mWindow->receiveEvent();
Siarhei Vishniakou4cb50ca2020-05-26 21:43:02 -07009241 ASSERT_TRUE(sequenceNum);
Siarhei Vishniakou4cb50ca2020-05-26 21:43:02 -07009242 const std::chrono::duration timeout = mWindow->getDispatchingTimeout(DISPATCHING_TIMEOUT);
Prabir Pradhanedd96402022-02-15 01:46:16 -08009243 mFakePolicy->assertNotifyWindowUnresponsiveWasCalled(timeout, mWindow);
Siarhei Vishniakou4cb50ca2020-05-26 21:43:02 -07009244 ASSERT_TRUE(mDispatcher->waitForIdle());
9245}
9246
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009247// We have a focused application, but no focused window
9248TEST_F(InputDispatcherSingleWindowAnr, FocusedApplication_NoFocusedWindow) {
Vishnu Nair47074b82020-08-14 11:54:47 -07009249 mWindow->setFocusable(false);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07009250 mDispatcher->onWindowInfosChanged({{*mWindow->getInfo()}, {}, 0, 0});
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009251 mWindow->consumeFocusEvent(false);
9252
9253 // taps on the window work as normal
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08009254 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07009255 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009256 WINDOW_LOCATION));
9257 ASSERT_NO_FATAL_FAILURE(mWindow->consumeMotionDown());
9258 mDispatcher->waitForIdle();
9259 mFakePolicy->assertNotifyAnrWasNotCalled();
9260
9261 // Once a focused event arrives, we get an ANR for this application
9262 // We specify the injection timeout to be smaller than the application timeout, to ensure that
9263 // injection times out (instead of failing).
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08009264 const InputEventInjectionResult result =
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07009265 injectKey(*mDispatcher, AKEY_EVENT_ACTION_DOWN, /*repeatCount=*/0, ADISPLAY_ID_DEFAULT,
Siarhei Vishniakouf83c6932023-07-07 17:48:10 -07009266 InputEventInjectionSync::WAIT_FOR_RESULT, 50ms, /*allowKeyRepeat=*/false);
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08009267 ASSERT_EQ(InputEventInjectionResult::TIMED_OUT, result);
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009268 const std::chrono::duration timeout = mApplication->getDispatchingTimeout(DISPATCHING_TIMEOUT);
Vishnu Naire4df8752022-09-08 09:17:55 -07009269 mFakePolicy->assertNotifyNoFocusedWindowAnrWasCalled(timeout, mApplication);
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009270 ASSERT_TRUE(mDispatcher->waitForIdle());
9271}
9272
Siarhei Vishniakou289e9242022-02-15 14:50:16 -08009273/**
9274 * Make sure the stale key is dropped before causing an ANR. So even if there's no focused window,
9275 * there will not be an ANR.
9276 */
9277TEST_F(InputDispatcherSingleWindowAnr, StaleKeyEventDoesNotAnr) {
9278 mWindow->setFocusable(false);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07009279 mDispatcher->onWindowInfosChanged({{*mWindow->getInfo()}, {}, 0, 0});
Siarhei Vishniakou289e9242022-02-15 14:50:16 -08009280 mWindow->consumeFocusEvent(false);
9281
9282 KeyEvent event;
Siarhei Vishniakoua7333112023-10-27 13:33:29 -07009283 static constexpr std::chrono::duration STALE_EVENT_TIMEOUT = 1000ms;
9284 mFakePolicy->setStaleEventTimeout(STALE_EVENT_TIMEOUT);
Siarhei Vishniakou289e9242022-02-15 14:50:16 -08009285 const nsecs_t eventTime = systemTime(SYSTEM_TIME_MONOTONIC) -
9286 std::chrono::nanoseconds(STALE_EVENT_TIMEOUT).count();
9287
9288 // Define a valid key down event that is stale (too old).
9289 event.initialize(InputEvent::nextId(), DEVICE_ID, AINPUT_SOURCE_KEYBOARD, ADISPLAY_ID_NONE,
Harry Cutts101ee9b2023-07-06 18:04:14 +00009290 INVALID_HMAC, AKEY_EVENT_ACTION_DOWN, /*flags=*/0, AKEYCODE_A, KEY_A,
Hu Guofe3c8f12023-09-22 17:20:15 +08009291 AMETA_NONE, /*repeatCount=*/0, eventTime, eventTime);
Siarhei Vishniakou289e9242022-02-15 14:50:16 -08009292
Hu Guofe3c8f12023-09-22 17:20:15 +08009293 const int32_t policyFlags =
9294 POLICY_FLAG_FILTERED | POLICY_FLAG_PASS_TO_USER | POLICY_FLAG_DISABLE_KEY_REPEAT;
Siarhei Vishniakou289e9242022-02-15 14:50:16 -08009295
9296 InputEventInjectionResult result =
Harry Cutts33476232023-01-30 19:57:29 +00009297 mDispatcher->injectInputEvent(&event, /*targetUid=*/{},
Siarhei Vishniakou289e9242022-02-15 14:50:16 -08009298 InputEventInjectionSync::WAIT_FOR_RESULT,
9299 INJECT_EVENT_TIMEOUT, policyFlags);
9300 ASSERT_EQ(InputEventInjectionResult::FAILED, result)
9301 << "Injection should fail because the event is stale";
9302
9303 ASSERT_TRUE(mDispatcher->waitForIdle());
9304 mFakePolicy->assertNotifyAnrWasNotCalled();
9305 mWindow->assertNoEvents();
9306}
9307
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009308// We have a focused application, but no focused window
Siarhei Vishniakou234129c2020-10-22 22:28:12 -05009309// Make sure that we don't notify policy twice about the same ANR.
9310TEST_F(InputDispatcherSingleWindowAnr, NoFocusedWindow_DoesNotSendDuplicateAnr) {
Siarhei Vishniakou06405fc2023-09-22 13:40:51 -07009311 const std::chrono::duration appTimeout = 400ms;
9312 mApplication->setDispatchingTimeout(appTimeout);
9313 mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, mApplication);
9314
Vishnu Nair47074b82020-08-14 11:54:47 -07009315 mWindow->setFocusable(false);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07009316 mDispatcher->onWindowInfosChanged({{*mWindow->getInfo()}, {}, 0, 0});
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009317 mWindow->consumeFocusEvent(false);
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009318
9319 // Once a focused event arrives, we get an ANR for this application
9320 // We specify the injection timeout to be smaller than the application timeout, to ensure that
9321 // injection times out (instead of failing).
Siarhei Vishniakou06405fc2023-09-22 13:40:51 -07009322 const std::chrono::duration eventInjectionTimeout = 100ms;
9323 ASSERT_LT(eventInjectionTimeout, appTimeout);
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08009324 const InputEventInjectionResult result =
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07009325 injectKey(*mDispatcher, AKEY_EVENT_ACTION_DOWN, /*repeatCount=*/0, ADISPLAY_ID_DEFAULT,
Siarhei Vishniakou06405fc2023-09-22 13:40:51 -07009326 InputEventInjectionSync::WAIT_FOR_RESULT, eventInjectionTimeout,
9327 /*allowKeyRepeat=*/false);
9328 ASSERT_EQ(InputEventInjectionResult::TIMED_OUT, result)
9329 << "result=" << ftl::enum_string(result);
9330 // We already waited for 'eventInjectionTimeout`, because the countdown started when the event
9331 // was first injected. So now we have (appTimeout - eventInjectionTimeout) left to wait.
9332 std::chrono::duration remainingWaitTime = appTimeout - eventInjectionTimeout;
9333 mFakePolicy->assertNotifyNoFocusedWindowAnrWasCalled(remainingWaitTime, mApplication);
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009334
Vishnu Naire4df8752022-09-08 09:17:55 -07009335 std::this_thread::sleep_for(appTimeout);
Siarhei Vishniakou234129c2020-10-22 22:28:12 -05009336 // ANR should not be raised again. It is up to policy to do that if it desires.
9337 mFakePolicy->assertNotifyAnrWasNotCalled();
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009338
Siarhei Vishniakou234129c2020-10-22 22:28:12 -05009339 // If we now get a focused window, the ANR should stop, but the policy handles that via
9340 // 'notifyFocusChanged' callback. This is implemented in the policy so we can't test it here.
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009341 ASSERT_TRUE(mDispatcher->waitForIdle());
9342}
9343
9344// We have a focused application, but no focused window
9345TEST_F(InputDispatcherSingleWindowAnr, NoFocusedWindow_DropsFocusedEvents) {
Vishnu Nair47074b82020-08-14 11:54:47 -07009346 mWindow->setFocusable(false);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07009347 mDispatcher->onWindowInfosChanged({{*mWindow->getInfo()}, {}, 0, 0});
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009348 mWindow->consumeFocusEvent(false);
9349
9350 // Once a focused event arrives, we get an ANR for this application
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07009351 ASSERT_NO_FATAL_FAILURE(assertInjectedKeyTimesOut(*mDispatcher));
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009352
Vishnu Naire4df8752022-09-08 09:17:55 -07009353 const std::chrono::duration timeout = mApplication->getDispatchingTimeout(DISPATCHING_TIMEOUT);
9354 mFakePolicy->assertNotifyNoFocusedWindowAnrWasCalled(timeout, mApplication);
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009355
9356 // Future focused events get dropped right away
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07009357 ASSERT_EQ(InputEventInjectionResult::FAILED, injectKeyDown(*mDispatcher));
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009358 ASSERT_TRUE(mDispatcher->waitForIdle());
9359 mWindow->assertNoEvents();
9360}
9361
9362/**
9363 * Ensure that the implementation is valid. Since we are using multiset to keep track of the
9364 * ANR timeouts, we are allowing entries with identical timestamps in the same connection.
9365 * If we process 1 of the events, but ANR on the second event with the same timestamp,
9366 * the ANR mechanism should still work.
9367 *
9368 * In this test, we are injecting DOWN and UP events with the same timestamps, and acknowledging the
9369 * DOWN event, while not responding on the second one.
9370 */
9371TEST_F(InputDispatcherSingleWindowAnr, Anr_HandlesEventsWithIdenticalTimestamps) {
9372 nsecs_t currentTime = systemTime(SYSTEM_TIME_MONOTONIC);
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07009373 injectMotionEvent(*mDispatcher, AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN,
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009374 ADISPLAY_ID_DEFAULT, WINDOW_LOCATION,
9375 {AMOTION_EVENT_INVALID_CURSOR_POSITION,
9376 AMOTION_EVENT_INVALID_CURSOR_POSITION},
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08009377 500ms, InputEventInjectionSync::WAIT_FOR_RESULT, currentTime);
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009378
9379 // Now send ACTION_UP, with identical timestamp
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07009380 injectMotionEvent(*mDispatcher, AMOTION_EVENT_ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN,
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009381 ADISPLAY_ID_DEFAULT, WINDOW_LOCATION,
9382 {AMOTION_EVENT_INVALID_CURSOR_POSITION,
9383 AMOTION_EVENT_INVALID_CURSOR_POSITION},
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08009384 500ms, InputEventInjectionSync::WAIT_FOR_RESULT, currentTime);
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009385
9386 // We have now sent down and up. Let's consume first event and then ANR on the second.
9387 mWindow->consumeMotionDown(ADISPLAY_ID_DEFAULT);
9388 const std::chrono::duration timeout = mWindow->getDispatchingTimeout(DISPATCHING_TIMEOUT);
Prabir Pradhanedd96402022-02-15 01:46:16 -08009389 mFakePolicy->assertNotifyWindowUnresponsiveWasCalled(timeout, mWindow);
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009390}
9391
Prabir Pradhan1376fcd2022-01-21 09:56:35 -08009392// A spy window can receive an ANR
9393TEST_F(InputDispatcherSingleWindowAnr, SpyWindowAnr) {
9394 sp<FakeWindowHandle> spy = addSpyWindow();
9395
9396 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07009397 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
Prabir Pradhan1376fcd2022-01-21 09:56:35 -08009398 WINDOW_LOCATION));
9399 mWindow->consumeMotionDown();
9400
Siarhei Vishniakoud3061ab2023-12-18 20:41:08 -08009401 const auto [sequenceNum, _] = spy->receiveEvent(); // ACTION_DOWN
Prabir Pradhan1376fcd2022-01-21 09:56:35 -08009402 ASSERT_TRUE(sequenceNum);
9403 const std::chrono::duration timeout = spy->getDispatchingTimeout(DISPATCHING_TIMEOUT);
Prabir Pradhanedd96402022-02-15 01:46:16 -08009404 mFakePolicy->assertNotifyWindowUnresponsiveWasCalled(timeout, spy);
Prabir Pradhan1376fcd2022-01-21 09:56:35 -08009405
9406 spy->finishEvent(*sequenceNum);
Siarhei Vishniakou1ae72f12023-01-29 12:55:30 -08009407 spy->consumeMotionEvent(
9408 AllOf(WithMotionAction(ACTION_CANCEL), WithDisplayId(ADISPLAY_ID_DEFAULT)));
Prabir Pradhan1376fcd2022-01-21 09:56:35 -08009409 ASSERT_TRUE(mDispatcher->waitForIdle());
Prabir Pradhanedd96402022-02-15 01:46:16 -08009410 mFakePolicy->assertNotifyWindowResponsiveWasCalled(spy->getToken(), mWindow->getPid());
Prabir Pradhan1376fcd2022-01-21 09:56:35 -08009411}
9412
9413// If an app is not responding to a key event, spy windows should continue to receive
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009414// new motion events
Prabir Pradhan1376fcd2022-01-21 09:56:35 -08009415TEST_F(InputDispatcherSingleWindowAnr, SpyWindowReceivesEventsDuringAppAnrOnKey) {
9416 sp<FakeWindowHandle> spy = addSpyWindow();
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009417
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08009418 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07009419 injectKeyDown(*mDispatcher, ADISPLAY_ID_DEFAULT));
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009420 mWindow->consumeKeyDown(ADISPLAY_ID_DEFAULT);
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07009421 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectKeyUp(*mDispatcher, ADISPLAY_ID_DEFAULT));
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009422
9423 // Stuck on the ACTION_UP
9424 const std::chrono::duration timeout = mWindow->getDispatchingTimeout(DISPATCHING_TIMEOUT);
Prabir Pradhanedd96402022-02-15 01:46:16 -08009425 mFakePolicy->assertNotifyWindowUnresponsiveWasCalled(timeout, mWindow);
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009426
Prabir Pradhan1376fcd2022-01-21 09:56:35 -08009427 // New tap will go to the spy window, but not to the window
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009428 tapOnWindow();
Prabir Pradhan1376fcd2022-01-21 09:56:35 -08009429 spy->consumeMotionDown(ADISPLAY_ID_DEFAULT);
9430 spy->consumeMotionUp(ADISPLAY_ID_DEFAULT);
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009431
9432 mWindow->consumeKeyUp(ADISPLAY_ID_DEFAULT); // still the previous motion
9433 mDispatcher->waitForIdle();
Prabir Pradhanedd96402022-02-15 01:46:16 -08009434 mFakePolicy->assertNotifyWindowResponsiveWasCalled(mWindow->getToken(), mWindow->getPid());
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009435 mWindow->assertNoEvents();
Prabir Pradhan1376fcd2022-01-21 09:56:35 -08009436 spy->assertNoEvents();
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009437}
9438
Prabir Pradhan1376fcd2022-01-21 09:56:35 -08009439// If an app is not responding to a motion event, spy windows should continue to receive
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009440// new motion events
Prabir Pradhan1376fcd2022-01-21 09:56:35 -08009441TEST_F(InputDispatcherSingleWindowAnr, SpyWindowReceivesEventsDuringAppAnrOnMotion) {
9442 sp<FakeWindowHandle> spy = addSpyWindow();
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009443
9444 tapOnWindow();
Prabir Pradhan1376fcd2022-01-21 09:56:35 -08009445 spy->consumeMotionDown(ADISPLAY_ID_DEFAULT);
9446 spy->consumeMotionUp(ADISPLAY_ID_DEFAULT);
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009447
9448 mWindow->consumeMotionDown();
9449 // Stuck on the ACTION_UP
9450 const std::chrono::duration timeout = mWindow->getDispatchingTimeout(DISPATCHING_TIMEOUT);
Prabir Pradhanedd96402022-02-15 01:46:16 -08009451 mFakePolicy->assertNotifyWindowUnresponsiveWasCalled(timeout, mWindow);
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009452
Prabir Pradhan1376fcd2022-01-21 09:56:35 -08009453 // New tap will go to the spy window, but not to the window
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009454 tapOnWindow();
Prabir Pradhan1376fcd2022-01-21 09:56:35 -08009455 spy->consumeMotionDown(ADISPLAY_ID_DEFAULT);
9456 spy->consumeMotionUp(ADISPLAY_ID_DEFAULT);
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009457
9458 mWindow->consumeMotionUp(ADISPLAY_ID_DEFAULT); // still the previous motion
9459 mDispatcher->waitForIdle();
Prabir Pradhanedd96402022-02-15 01:46:16 -08009460 mFakePolicy->assertNotifyWindowResponsiveWasCalled(mWindow->getToken(), mWindow->getPid());
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009461 mWindow->assertNoEvents();
Prabir Pradhan1376fcd2022-01-21 09:56:35 -08009462 spy->assertNoEvents();
9463}
9464
9465TEST_F(InputDispatcherSingleWindowAnr, UnresponsiveMonitorAnr) {
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07009466 mDispatcher->setMonitorDispatchingTimeoutForTest(SPY_TIMEOUT);
Prabir Pradhan1376fcd2022-01-21 09:56:35 -08009467
Prabir Pradhanfb549072023-10-05 19:17:36 +00009468 FakeMonitorReceiver monitor = FakeMonitorReceiver(*mDispatcher, "M_1", ADISPLAY_ID_DEFAULT);
Prabir Pradhan1376fcd2022-01-21 09:56:35 -08009469
9470 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07009471 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
Prabir Pradhan1376fcd2022-01-21 09:56:35 -08009472 WINDOW_LOCATION));
9473
9474 mWindow->consumeMotionDown(ADISPLAY_ID_DEFAULT);
9475 const std::optional<uint32_t> consumeSeq = monitor.receiveEvent();
9476 ASSERT_TRUE(consumeSeq);
9477
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07009478 mFakePolicy->assertNotifyWindowUnresponsiveWasCalled(SPY_TIMEOUT, monitor.getToken(),
9479 MONITOR_PID);
Prabir Pradhan1376fcd2022-01-21 09:56:35 -08009480
9481 monitor.finishEvent(*consumeSeq);
9482 monitor.consumeMotionCancel(ADISPLAY_ID_DEFAULT);
9483
9484 ASSERT_TRUE(mDispatcher->waitForIdle());
Prabir Pradhanedd96402022-02-15 01:46:16 -08009485 mFakePolicy->assertNotifyWindowResponsiveWasCalled(monitor.getToken(), MONITOR_PID);
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009486}
9487
9488// If a window is unresponsive, then you get anr. if the window later catches up and starts to
9489// process events, you don't get an anr. When the window later becomes unresponsive again, you
9490// get an ANR again.
9491// 1. tap -> block on ACTION_UP -> receive ANR
9492// 2. consume all pending events (= queue becomes healthy again)
9493// 3. tap again -> block on ACTION_UP again -> receive ANR second time
9494TEST_F(InputDispatcherSingleWindowAnr, SameWindow_CanReceiveAnrTwice) {
9495 tapOnWindow();
9496
9497 mWindow->consumeMotionDown();
9498 // Block on ACTION_UP
9499 const std::chrono::duration timeout = mWindow->getDispatchingTimeout(DISPATCHING_TIMEOUT);
Prabir Pradhanedd96402022-02-15 01:46:16 -08009500 mFakePolicy->assertNotifyWindowUnresponsiveWasCalled(timeout, mWindow);
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009501 mWindow->consumeMotionUp(); // Now the connection should be healthy again
9502 mDispatcher->waitForIdle();
Prabir Pradhanedd96402022-02-15 01:46:16 -08009503 mFakePolicy->assertNotifyWindowResponsiveWasCalled(mWindow->getToken(), mWindow->getPid());
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009504 mWindow->assertNoEvents();
9505
9506 tapOnWindow();
9507 mWindow->consumeMotionDown();
Prabir Pradhanedd96402022-02-15 01:46:16 -08009508 mFakePolicy->assertNotifyWindowUnresponsiveWasCalled(timeout, mWindow);
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009509 mWindow->consumeMotionUp();
9510
9511 mDispatcher->waitForIdle();
Prabir Pradhanedd96402022-02-15 01:46:16 -08009512 mFakePolicy->assertNotifyWindowResponsiveWasCalled(mWindow->getToken(), mWindow->getPid());
Siarhei Vishniakou234129c2020-10-22 22:28:12 -05009513 mFakePolicy->assertNotifyAnrWasNotCalled();
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009514 mWindow->assertNoEvents();
9515}
9516
Siarhei Vishniakou234129c2020-10-22 22:28:12 -05009517// If a connection remains unresponsive for a while, make sure policy is only notified once about
9518// it.
9519TEST_F(InputDispatcherSingleWindowAnr, Policy_DoesNotGetDuplicateAnr) {
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08009520 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07009521 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009522 WINDOW_LOCATION));
9523
9524 const std::chrono::duration windowTimeout = mWindow->getDispatchingTimeout(DISPATCHING_TIMEOUT);
Prabir Pradhanedd96402022-02-15 01:46:16 -08009525 mFakePolicy->assertNotifyWindowUnresponsiveWasCalled(windowTimeout, mWindow);
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009526 std::this_thread::sleep_for(windowTimeout);
Siarhei Vishniakou234129c2020-10-22 22:28:12 -05009527 // 'notifyConnectionUnresponsive' should only be called once per connection
9528 mFakePolicy->assertNotifyAnrWasNotCalled();
9529 // When the ANR happened, dispatcher should abort the current event stream via ACTION_CANCEL
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009530 mWindow->consumeMotionDown();
Siarhei Vishniakou1ae72f12023-01-29 12:55:30 -08009531 mWindow->consumeMotionEvent(
9532 AllOf(WithMotionAction(ACTION_CANCEL), WithDisplayId(ADISPLAY_ID_DEFAULT)));
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009533 mWindow->assertNoEvents();
Siarhei Vishniakou234129c2020-10-22 22:28:12 -05009534 mDispatcher->waitForIdle();
Prabir Pradhanedd96402022-02-15 01:46:16 -08009535 mFakePolicy->assertNotifyWindowResponsiveWasCalled(mWindow->getToken(), mWindow->getPid());
Siarhei Vishniakou234129c2020-10-22 22:28:12 -05009536 mFakePolicy->assertNotifyAnrWasNotCalled();
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009537}
9538
9539/**
9540 * 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 -07009541 * not get delivered to the focused window until the motion is processed.
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009542 */
9543TEST_F(InputDispatcherSingleWindowAnr, Key_StaysPendingWhileMotionIsProcessed) {
Siarhei Vishniakouef2b4502023-12-28 11:51:47 -08009544 // The timeouts in this test are established by relying on the fact that the "key waiting for
9545 // events timeout" is equal to 500ms.
9546 ASSERT_EQ(mFakePolicy->getKeyWaitingForEventsTimeout(), 500ms);
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009547 mWindow->setDispatchingTimeout(2s); // Set a long ANR timeout to prevent it from triggering
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07009548 mDispatcher->onWindowInfosChanged({{*mWindow->getInfo()}, {}, 0, 0});
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009549
9550 tapOnWindow();
Siarhei Vishniakoud3061ab2023-12-18 20:41:08 -08009551 const auto& [downSequenceNum, downEvent] = mWindow->receiveEvent();
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009552 ASSERT_TRUE(downSequenceNum);
Siarhei Vishniakoud3061ab2023-12-18 20:41:08 -08009553 const auto& [upSequenceNum, upEvent] = mWindow->receiveEvent();
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009554 ASSERT_TRUE(upSequenceNum);
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009555
Siarhei Vishniakouef2b4502023-12-28 11:51:47 -08009556 // Don't finish the events yet, and send a key
9557 mDispatcher->notifyKey(
9558 KeyArgsBuilder(AKEY_EVENT_ACTION_DOWN, AINPUT_SOURCE_KEYBOARD)
9559 .policyFlags(DEFAULT_POLICY_FLAGS | POLICY_FLAG_DISABLE_KEY_REPEAT)
9560 .build());
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009561 // Key will not be sent to the window, yet, because the window is still processing events
9562 // and the key remains pending, waiting for the touch events to be processed
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07009563 // Make sure that `assertNoEvents` doesn't wait too long, because it could cause an ANR.
Siarhei Vishniakouef2b4502023-12-28 11:51:47 -08009564 mWindow->assertNoEvents(100ms);
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009565
Siarhei Vishniakouef2b4502023-12-28 11:51:47 -08009566 std::this_thread::sleep_for(400ms);
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009567 // if we wait long enough though, dispatcher will give up, and still send the key
9568 // to the focused window, even though we have not yet finished the motion event
9569 mWindow->consumeKeyDown(ADISPLAY_ID_DEFAULT);
9570 mWindow->finishEvent(*downSequenceNum);
9571 mWindow->finishEvent(*upSequenceNum);
9572}
9573
9574/**
9575 * If a window is processing a motion event, and then a key event comes in, the key event should
9576 * not go to the focused window until the motion is processed.
9577 * If then a new motion comes in, then the pending key event should be going to the currently
9578 * focused window right away.
9579 */
9580TEST_F(InputDispatcherSingleWindowAnr,
Siarhei Vishniakouef2b4502023-12-28 11:51:47 -08009581 PendingKey_IsDeliveredWhileMotionIsProcessingAndNewTouchComesIn) {
9582 // The timeouts in this test are established by relying on the fact that the "key waiting for
9583 // events timeout" is equal to 500ms.
9584 ASSERT_EQ(mFakePolicy->getKeyWaitingForEventsTimeout(), 500ms);
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009585 mWindow->setDispatchingTimeout(2s); // Set a long ANR timeout to prevent it from triggering
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07009586 mDispatcher->onWindowInfosChanged({{*mWindow->getInfo()}, {}, 0, 0});
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009587
9588 tapOnWindow();
Siarhei Vishniakoud3061ab2023-12-18 20:41:08 -08009589 const auto& [downSequenceNum, _] = mWindow->receiveEvent();
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009590 ASSERT_TRUE(downSequenceNum);
Siarhei Vishniakoud3061ab2023-12-18 20:41:08 -08009591 const auto& [upSequenceNum, upEvent] = mWindow->receiveEvent();
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009592 ASSERT_TRUE(upSequenceNum);
9593 // Don't finish the events yet, and send a key
Siarhei Vishniakou67bf2162023-11-16 13:29:50 -08009594 mDispatcher->notifyKey(
9595 KeyArgsBuilder(AKEY_EVENT_ACTION_DOWN, AINPUT_SOURCE_KEYBOARD)
9596 .policyFlags(DEFAULT_POLICY_FLAGS | POLICY_FLAG_DISABLE_KEY_REPEAT)
9597 .build());
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009598 // At this point, key is still pending, and should not be sent to the application yet.
Siarhei Vishniakouef2b4502023-12-28 11:51:47 -08009599 mWindow->assertNoEvents(100ms);
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009600
9601 // Now tap down again. It should cause the pending key to go to the focused window right away.
9602 tapOnWindow();
Siarhei Vishniakouef2b4502023-12-28 11:51:47 -08009603 // Now that we tapped, we should receive the key immediately.
9604 // Since there's still room for slowness, we use 200ms, which is much less than
9605 // the "key waiting for events' timeout of 500ms minus the already waited 100ms duration.
9606 std::unique_ptr<InputEvent> keyEvent = mWindow->consume(200ms);
9607 ASSERT_NE(nullptr, keyEvent);
9608 ASSERT_EQ(InputEventType::KEY, keyEvent->getType());
9609 ASSERT_THAT(static_cast<KeyEvent&>(*keyEvent), WithKeyAction(AKEY_EVENT_ACTION_DOWN));
9610 // it doesn't matter that we haven't ack'd the other events yet. We can finish events in any
9611 // order.
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009612 mWindow->finishEvent(*downSequenceNum); // first tap's ACTION_DOWN
9613 mWindow->finishEvent(*upSequenceNum); // first tap's ACTION_UP
Siarhei Vishniakou67bf2162023-11-16 13:29:50 -08009614 mWindow->consumeMotionEvent(WithMotionAction(ACTION_DOWN));
9615 mWindow->consumeMotionEvent(WithMotionAction(ACTION_UP));
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009616 mWindow->assertNoEvents();
9617}
9618
Siarhei Vishniakouadb9fc92023-05-26 10:46:09 -07009619/**
9620 * Send an event to the app and have the app not respond right away.
9621 * When ANR is raised, policy will tell the dispatcher to cancel the events for that window.
9622 * So InputDispatcher will enqueue ACTION_CANCEL event as well.
9623 * At some point, the window becomes responsive again.
9624 * Ensure that subsequent events get dropped, and the next gesture is delivered.
9625 */
9626TEST_F(InputDispatcherSingleWindowAnr, TwoGesturesWithAnr) {
9627 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
9628 .pointer(PointerBuilder(0, ToolType::FINGER).x(10).y(10))
9629 .build());
9630
Siarhei Vishniakoud3061ab2023-12-18 20:41:08 -08009631 const auto [sequenceNum, _] = mWindow->receiveEvent(); // ACTION_DOWN
Siarhei Vishniakouadb9fc92023-05-26 10:46:09 -07009632 ASSERT_TRUE(sequenceNum);
9633 const std::chrono::duration timeout = mWindow->getDispatchingTimeout(DISPATCHING_TIMEOUT);
9634 mFakePolicy->assertNotifyWindowUnresponsiveWasCalled(timeout, mWindow);
9635
9636 mWindow->finishEvent(*sequenceNum);
9637 mWindow->consumeMotionEvent(WithMotionAction(ACTION_CANCEL));
9638 ASSERT_TRUE(mDispatcher->waitForIdle());
9639 mFakePolicy->assertNotifyWindowResponsiveWasCalled(mWindow->getToken(), mWindow->getPid());
9640
9641 // Now that the window is responsive, let's continue the gesture.
9642 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN)
9643 .pointer(PointerBuilder(0, ToolType::FINGER).x(11).y(11))
9644 .build());
9645
9646 mDispatcher->notifyMotion(MotionArgsBuilder(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
9647 .pointer(PointerBuilder(0, ToolType::FINGER).x(11).y(11))
9648 .pointer(PointerBuilder(1, ToolType::FINGER).x(3).y(3))
9649 .build());
9650
9651 mDispatcher->notifyMotion(MotionArgsBuilder(POINTER_1_UP, AINPUT_SOURCE_TOUCHSCREEN)
9652 .pointer(PointerBuilder(0, ToolType::FINGER).x(11).y(11))
9653 .pointer(PointerBuilder(1, ToolType::FINGER).x(3).y(3))
9654 .build());
9655 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN)
9656 .pointer(PointerBuilder(0, ToolType::FINGER).x(11).y(11))
9657 .build());
9658 // We already canceled this pointer, so the window shouldn't get any new events.
9659 mWindow->assertNoEvents();
9660
9661 // Start another one.
9662 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
9663 .pointer(PointerBuilder(0, ToolType::FINGER).x(15).y(15))
9664 .build());
9665 mWindow->consumeMotionEvent(WithMotionAction(ACTION_DOWN));
9666}
9667
Prabir Pradhanfc364722024-02-08 17:51:20 +00009668// Send an event to the app and have the app not respond right away. Then remove the app window.
9669// When the window is removed, the dispatcher will cancel the events for that window.
9670// So InputDispatcher will enqueue ACTION_CANCEL event as well.
9671TEST_F(InputDispatcherSingleWindowAnr, AnrAfterWindowRemoval) {
9672 mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_DOWN,
9673 AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
9674 {WINDOW_LOCATION}));
9675
9676 const auto [sequenceNum, _] = mWindow->receiveEvent(); // ACTION_DOWN
9677 ASSERT_TRUE(sequenceNum);
9678
9679 // Remove the window, but the input channel should remain alive.
9680 mDispatcher->onWindowInfosChanged({{}, {}, 0, 0});
9681
9682 const std::chrono::duration timeout = mWindow->getDispatchingTimeout(DISPATCHING_TIMEOUT);
9683 // Since the window was removed, Dispatcher does not know the PID associated with the window
9684 // anymore, so the policy is notified without the PID.
9685 mFakePolicy->assertNotifyWindowUnresponsiveWasCalled(timeout, mWindow->getToken(),
9686 /*pid=*/std::nullopt);
9687
9688 mWindow->finishEvent(*sequenceNum);
9689 // The cancellation was generated when the window was removed, along with the focus event.
9690 mWindow->consumeMotionEvent(
9691 AllOf(WithMotionAction(ACTION_CANCEL), WithDisplayId(ADISPLAY_ID_DEFAULT)));
9692 mWindow->consumeFocusEvent(false);
9693 ASSERT_TRUE(mDispatcher->waitForIdle());
9694 mFakePolicy->assertNotifyWindowResponsiveWasCalled(mWindow->getToken(), /*pid=*/std::nullopt);
9695}
9696
9697// Send an event to the app and have the app not respond right away. Wait for the policy to be
9698// notified of the unresponsive window, then remove the app window.
9699TEST_F(InputDispatcherSingleWindowAnr, AnrFollowedByWindowRemoval) {
9700 mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_DOWN,
9701 AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
9702 {WINDOW_LOCATION}));
9703
9704 const auto [sequenceNum, _] = mWindow->receiveEvent(); // ACTION_DOWN
9705 ASSERT_TRUE(sequenceNum);
9706 const std::chrono::duration timeout = mWindow->getDispatchingTimeout(DISPATCHING_TIMEOUT);
9707 mFakePolicy->assertNotifyWindowUnresponsiveWasCalled(timeout, mWindow);
9708
9709 // Remove the window, but the input channel should remain alive.
9710 mDispatcher->onWindowInfosChanged({{}, {}, 0, 0});
9711
9712 mWindow->finishEvent(*sequenceNum);
9713 // The cancellation was generated during the ANR, and the window lost focus when it was removed.
9714 mWindow->consumeMotionEvent(
9715 AllOf(WithMotionAction(ACTION_CANCEL), WithDisplayId(ADISPLAY_ID_DEFAULT)));
9716 mWindow->consumeFocusEvent(false);
9717 ASSERT_TRUE(mDispatcher->waitForIdle());
9718 // Since the window was removed, Dispatcher does not know the PID associated with the window
9719 // becoming responsive, so the policy is notified without the PID.
9720 mFakePolicy->assertNotifyWindowResponsiveWasCalled(mWindow->getToken(), /*pid=*/std::nullopt);
9721}
9722
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009723class InputDispatcherMultiWindowAnr : public InputDispatcherTest {
9724 virtual void SetUp() override {
9725 InputDispatcherTest::SetUp();
9726
Chris Yea209fde2020-07-22 13:54:51 -07009727 mApplication = std::make_shared<FakeApplicationHandle>();
Siarhei Vishniakouf83c6932023-07-07 17:48:10 -07009728 mApplication->setDispatchingTimeout(100ms);
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07009729 mUnfocusedWindow = sp<FakeWindowHandle>::make(mApplication, mDispatcher, "Unfocused",
9730 ADISPLAY_ID_DEFAULT);
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009731 mUnfocusedWindow->setFrame(Rect(0, 0, 30, 30));
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009732 // Adding FLAG_WATCH_OUTSIDE_TOUCH to receive ACTION_OUTSIDE when another window is tapped
Prabir Pradhan4d5c52f2022-01-31 08:52:10 -08009733 mUnfocusedWindow->setWatchOutsideTouch(true);
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009734
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07009735 mFocusedWindow = sp<FakeWindowHandle>::make(mApplication, mDispatcher, "Focused",
9736 ADISPLAY_ID_DEFAULT);
Siarhei Vishniakouf83c6932023-07-07 17:48:10 -07009737 mFocusedWindow->setDispatchingTimeout(100ms);
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009738 mFocusedWindow->setFrame(Rect(50, 50, 100, 100));
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009739
9740 // Set focused application.
9741 mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, mApplication);
Vishnu Nair47074b82020-08-14 11:54:47 -07009742 mFocusedWindow->setFocusable(true);
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009743
9744 // Expect one focus window exist in display.
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07009745 mDispatcher->onWindowInfosChanged(
9746 {{*mUnfocusedWindow->getInfo(), *mFocusedWindow->getInfo()}, {}, 0, 0});
Vishnu Nair958da932020-08-21 17:12:37 -07009747 setFocusedWindow(mFocusedWindow);
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009748 mFocusedWindow->consumeFocusEvent(true);
9749 }
9750
9751 virtual void TearDown() override {
9752 InputDispatcherTest::TearDown();
9753
9754 mUnfocusedWindow.clear();
9755 mFocusedWindow.clear();
9756 }
9757
9758protected:
Chris Yea209fde2020-07-22 13:54:51 -07009759 std::shared_ptr<FakeApplicationHandle> mApplication;
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009760 sp<FakeWindowHandle> mUnfocusedWindow;
9761 sp<FakeWindowHandle> mFocusedWindow;
9762 static constexpr PointF UNFOCUSED_WINDOW_LOCATION = {20, 20};
9763 static constexpr PointF FOCUSED_WINDOW_LOCATION = {75, 75};
9764 static constexpr PointF LOCATION_OUTSIDE_ALL_WINDOWS = {40, 40};
9765
9766 void tapOnFocusedWindow() { tap(FOCUSED_WINDOW_LOCATION); }
9767
9768 void tapOnUnfocusedWindow() { tap(UNFOCUSED_WINDOW_LOCATION); }
9769
9770private:
9771 void tap(const PointF& location) {
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08009772 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07009773 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009774 location));
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08009775 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07009776 injectMotionUp(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009777 location));
9778 }
9779};
9780
9781// If we have 2 windows that are both unresponsive, the one with the shortest timeout
9782// should be ANR'd first.
9783TEST_F(InputDispatcherMultiWindowAnr, TwoWindows_BothUnresponsive) {
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08009784 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakou2899c552023-07-10 18:20:46 -07009785 injectMotionEvent(*mDispatcher,
9786 MotionEventBuilder(AMOTION_EVENT_ACTION_DOWN,
9787 AINPUT_SOURCE_TOUCHSCREEN)
9788 .pointer(PointerBuilder(0, ToolType::FINGER)
9789 .x(FOCUSED_WINDOW_LOCATION.x)
9790 .y(FOCUSED_WINDOW_LOCATION.y))
9791 .build()));
9792 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
9793 injectMotionEvent(*mDispatcher,
9794 MotionEventBuilder(AMOTION_EVENT_ACTION_UP,
9795 AINPUT_SOURCE_TOUCHSCREEN)
9796 .pointer(PointerBuilder(0, ToolType::FINGER)
9797 .x(FOCUSED_WINDOW_LOCATION.x)
9798 .y(FOCUSED_WINDOW_LOCATION.y))
9799 .build()));
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009800 mFocusedWindow->consumeMotionDown();
Siarhei Vishniakou2899c552023-07-10 18:20:46 -07009801 mFocusedWindow->consumeMotionUp();
Prabir Pradhan7662a8d2023-12-15 01:58:14 +00009802 mUnfocusedWindow->consumeMotionOutside(ADISPLAY_ID_DEFAULT, /*flags=*/0);
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009803 // We consumed all events, so no ANR
9804 ASSERT_TRUE(mDispatcher->waitForIdle());
9805 mFakePolicy->assertNotifyAnrWasNotCalled();
9806
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08009807 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakou2899c552023-07-10 18:20:46 -07009808 injectMotionEvent(*mDispatcher,
9809 MotionEventBuilder(AMOTION_EVENT_ACTION_DOWN,
9810 AINPUT_SOURCE_TOUCHSCREEN)
9811 .pointer(PointerBuilder(0, ToolType::FINGER)
9812 .x(FOCUSED_WINDOW_LOCATION.x)
9813 .y(FOCUSED_WINDOW_LOCATION.y))
9814 .build()));
Siarhei Vishniakoud3061ab2023-12-18 20:41:08 -08009815 const auto [unfocusedSequenceNum, _] = mUnfocusedWindow->receiveEvent();
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009816 ASSERT_TRUE(unfocusedSequenceNum);
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009817
9818 const std::chrono::duration timeout =
9819 mFocusedWindow->getDispatchingTimeout(DISPATCHING_TIMEOUT);
Prabir Pradhanedd96402022-02-15 01:46:16 -08009820 mFakePolicy->assertNotifyWindowUnresponsiveWasCalled(timeout, mFocusedWindow);
Siarhei Vishniakou2899c552023-07-10 18:20:46 -07009821
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009822 mUnfocusedWindow->finishEvent(*unfocusedSequenceNum);
Siarhei Vishniakou234129c2020-10-22 22:28:12 -05009823 mFocusedWindow->consumeMotionDown();
9824 // This cancel is generated because the connection was unresponsive
9825 mFocusedWindow->consumeMotionCancel();
9826 mFocusedWindow->assertNoEvents();
9827 mUnfocusedWindow->assertNoEvents();
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009828 ASSERT_TRUE(mDispatcher->waitForIdle());
Prabir Pradhanedd96402022-02-15 01:46:16 -08009829 mFakePolicy->assertNotifyWindowResponsiveWasCalled(mFocusedWindow->getToken(),
9830 mFocusedWindow->getPid());
Siarhei Vishniakou234129c2020-10-22 22:28:12 -05009831 mFakePolicy->assertNotifyAnrWasNotCalled();
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009832}
9833
9834// If we have 2 windows with identical timeouts that are both unresponsive,
9835// it doesn't matter which order they should have ANR.
9836// But we should receive ANR for both.
9837TEST_F(InputDispatcherMultiWindowAnr, TwoWindows_BothUnresponsiveWithSameTimeout) {
9838 // Set the timeout for unfocused window to match the focused window
Siarhei Vishniakouf83c6932023-07-07 17:48:10 -07009839 mUnfocusedWindow->setDispatchingTimeout(
9840 mFocusedWindow->getDispatchingTimeout(DISPATCHING_TIMEOUT));
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07009841 mDispatcher->onWindowInfosChanged(
9842 {{*mUnfocusedWindow->getInfo(), *mFocusedWindow->getInfo()}, {}, 0, 0});
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009843
9844 tapOnFocusedWindow();
9845 // we should have ACTION_DOWN/ACTION_UP on focused window and ACTION_OUTSIDE on unfocused window
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009846 // We don't know which window will ANR first. But both of them should happen eventually.
Siarhei Vishniakouf83c6932023-07-07 17:48:10 -07009847 std::array<sp<IBinder>, 2> anrConnectionTokens = {mFakePolicy->getUnresponsiveWindowToken(
9848 mFocusedWindow->getDispatchingTimeout(
9849 DISPATCHING_TIMEOUT)),
9850 mFakePolicy->getUnresponsiveWindowToken(0ms)};
9851
9852 ASSERT_THAT(anrConnectionTokens,
9853 ::testing::UnorderedElementsAre(testing::Eq(mFocusedWindow->getToken()),
9854 testing::Eq(mUnfocusedWindow->getToken())));
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009855
9856 ASSERT_TRUE(mDispatcher->waitForIdle());
9857 mFakePolicy->assertNotifyAnrWasNotCalled();
Siarhei Vishniakou234129c2020-10-22 22:28:12 -05009858
9859 mFocusedWindow->consumeMotionDown();
9860 mFocusedWindow->consumeMotionUp();
9861 mUnfocusedWindow->consumeMotionOutside();
9862
Siarhei Vishniakouf83c6932023-07-07 17:48:10 -07009863 std::array<sp<IBinder>, 2> responsiveTokens = {mFakePolicy->getResponsiveWindowToken(),
9864 mFakePolicy->getResponsiveWindowToken()};
Siarhei Vishniakou234129c2020-10-22 22:28:12 -05009865
9866 // Both applications should be marked as responsive, in any order
Siarhei Vishniakouf83c6932023-07-07 17:48:10 -07009867 ASSERT_THAT(responsiveTokens,
9868 ::testing::UnorderedElementsAre(testing::Eq(mFocusedWindow->getToken()),
9869 testing::Eq(mUnfocusedWindow->getToken())));
Siarhei Vishniakou234129c2020-10-22 22:28:12 -05009870 mFakePolicy->assertNotifyAnrWasNotCalled();
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009871}
9872
9873// If a window is already not responding, the second tap on the same window should be ignored.
9874// We should also log an error to account for the dropped event (not tested here).
9875// At the same time, FLAG_WATCH_OUTSIDE_TOUCH targets should not receive any events.
9876TEST_F(InputDispatcherMultiWindowAnr, DuringAnr_SecondTapIsIgnored) {
9877 tapOnFocusedWindow();
Prabir Pradhan7662a8d2023-12-15 01:58:14 +00009878 mUnfocusedWindow->consumeMotionOutside(ADISPLAY_ID_DEFAULT, /*flags=*/0);
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009879 // Receive the events, but don't respond
Siarhei Vishniakoud3061ab2023-12-18 20:41:08 -08009880 const auto [downEventSequenceNum, downEvent] = mFocusedWindow->receiveEvent(); // ACTION_DOWN
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009881 ASSERT_TRUE(downEventSequenceNum);
Siarhei Vishniakoud3061ab2023-12-18 20:41:08 -08009882 const auto [upEventSequenceNum, upEvent] = mFocusedWindow->receiveEvent(); // ACTION_UP
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009883 ASSERT_TRUE(upEventSequenceNum);
9884 const std::chrono::duration timeout =
9885 mFocusedWindow->getDispatchingTimeout(DISPATCHING_TIMEOUT);
Prabir Pradhanedd96402022-02-15 01:46:16 -08009886 mFakePolicy->assertNotifyWindowUnresponsiveWasCalled(timeout, mFocusedWindow);
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009887
9888 // Tap once again
9889 // We cannot use "tapOnFocusedWindow" because it asserts the injection result to be success
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08009890 ASSERT_EQ(InputEventInjectionResult::FAILED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07009891 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009892 FOCUSED_WINDOW_LOCATION));
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08009893 ASSERT_EQ(InputEventInjectionResult::FAILED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07009894 injectMotionUp(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009895 FOCUSED_WINDOW_LOCATION));
9896 // Unfocused window does not receive ACTION_OUTSIDE because the tapped window is not a
9897 // valid touch target
9898 mUnfocusedWindow->assertNoEvents();
9899
9900 // Consume the first tap
9901 mFocusedWindow->finishEvent(*downEventSequenceNum);
9902 mFocusedWindow->finishEvent(*upEventSequenceNum);
9903 ASSERT_TRUE(mDispatcher->waitForIdle());
9904 // The second tap did not go to the focused window
9905 mFocusedWindow->assertNoEvents();
Siarhei Vishniakou234129c2020-10-22 22:28:12 -05009906 // Since all events are finished, connection should be deemed healthy again
Prabir Pradhanedd96402022-02-15 01:46:16 -08009907 mFakePolicy->assertNotifyWindowResponsiveWasCalled(mFocusedWindow->getToken(),
9908 mFocusedWindow->getPid());
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009909 mFakePolicy->assertNotifyAnrWasNotCalled();
9910}
9911
9912// If you tap outside of all windows, there will not be ANR
9913TEST_F(InputDispatcherMultiWindowAnr, TapOutsideAllWindows_DoesNotAnr) {
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08009914 ASSERT_EQ(InputEventInjectionResult::FAILED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07009915 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009916 LOCATION_OUTSIDE_ALL_WINDOWS));
9917 ASSERT_TRUE(mDispatcher->waitForIdle());
9918 mFakePolicy->assertNotifyAnrWasNotCalled();
9919}
9920
9921// Since the focused window is paused, tapping on it should not produce any events
9922TEST_F(InputDispatcherMultiWindowAnr, Window_CanBePaused) {
9923 mFocusedWindow->setPaused(true);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07009924 mDispatcher->onWindowInfosChanged(
9925 {{*mUnfocusedWindow->getInfo(), *mFocusedWindow->getInfo()}, {}, 0, 0});
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009926
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08009927 ASSERT_EQ(InputEventInjectionResult::FAILED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07009928 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009929 FOCUSED_WINDOW_LOCATION));
9930
9931 std::this_thread::sleep_for(mFocusedWindow->getDispatchingTimeout(DISPATCHING_TIMEOUT));
9932 ASSERT_TRUE(mDispatcher->waitForIdle());
9933 // Should not ANR because the window is paused, and touches shouldn't go to it
9934 mFakePolicy->assertNotifyAnrWasNotCalled();
9935
9936 mFocusedWindow->assertNoEvents();
9937 mUnfocusedWindow->assertNoEvents();
9938}
9939
9940/**
9941 * 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 -07009942 * not get delivered to the focused window until the motion is processed.
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009943 * If a different window becomes focused at this time, the key should go to that window instead.
9944 *
9945 * Warning!!!
9946 * This test depends on the value of android::inputdispatcher::KEY_WAITING_FOR_MOTION_TIMEOUT
9947 * and the injection timeout that we specify when injecting the key.
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07009948 * We must have the injection timeout (100ms) be smaller than
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009949 * KEY_WAITING_FOR_MOTION_TIMEOUT (currently 500ms).
9950 *
9951 * If that value changes, this test should also change.
9952 */
9953TEST_F(InputDispatcherMultiWindowAnr, PendingKey_GoesToNewlyFocusedWindow) {
9954 // Set a long ANR timeout to prevent it from triggering
9955 mFocusedWindow->setDispatchingTimeout(2s);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07009956 mDispatcher->onWindowInfosChanged(
9957 {{*mFocusedWindow->getInfo(), *mUnfocusedWindow->getInfo()}, {}, 0, 0});
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009958
9959 tapOnUnfocusedWindow();
Siarhei Vishniakoud3061ab2023-12-18 20:41:08 -08009960 const auto [downSequenceNum, downEvent] = mUnfocusedWindow->receiveEvent();
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009961 ASSERT_TRUE(downSequenceNum);
Siarhei Vishniakoud3061ab2023-12-18 20:41:08 -08009962 const auto [upSequenceNum, upEvent] = mUnfocusedWindow->receiveEvent();
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009963 ASSERT_TRUE(upSequenceNum);
9964 // Don't finish the events yet, and send a key
9965 // Injection will succeed because we will eventually give up and send the key to the focused
9966 // window even if motions are still being processed.
9967
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08009968 InputEventInjectionResult result =
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07009969 injectKey(*mDispatcher, AKEY_EVENT_ACTION_DOWN, /*repeatCount=*/0, ADISPLAY_ID_DEFAULT,
9970 InputEventInjectionSync::NONE, /*injectionTimeout=*/100ms);
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08009971 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, result);
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009972 // Key will not be sent to the window, yet, because the window is still processing events
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07009973 // and the key remains pending, waiting for the touch events to be processed.
9974 // Make sure `assertNoEvents` doesn't take too long. It uses CONSUME_TIMEOUT_NO_EVENT_EXPECTED
9975 // under the hood.
9976 static_assert(CONSUME_TIMEOUT_NO_EVENT_EXPECTED < 100ms);
9977 mFocusedWindow->assertNoEvents();
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009978
9979 // Switch the focus to the "unfocused" window that we tapped. Expect the key to go there
Vishnu Nair47074b82020-08-14 11:54:47 -07009980 mFocusedWindow->setFocusable(false);
9981 mUnfocusedWindow->setFocusable(true);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07009982 mDispatcher->onWindowInfosChanged(
9983 {{*mFocusedWindow->getInfo(), *mUnfocusedWindow->getInfo()}, {}, 0, 0});
Vishnu Nair958da932020-08-21 17:12:37 -07009984 setFocusedWindow(mUnfocusedWindow);
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009985
9986 // Focus events should precede the key events
9987 mUnfocusedWindow->consumeFocusEvent(true);
9988 mFocusedWindow->consumeFocusEvent(false);
9989
9990 // Finish the tap events, which should unblock dispatcher
9991 mUnfocusedWindow->finishEvent(*downSequenceNum);
9992 mUnfocusedWindow->finishEvent(*upSequenceNum);
9993
9994 // Now that all queues are cleared and no backlog in the connections, the key event
9995 // can finally go to the newly focused "mUnfocusedWindow".
9996 mUnfocusedWindow->consumeKeyDown(ADISPLAY_ID_DEFAULT);
9997 mFocusedWindow->assertNoEvents();
9998 mUnfocusedWindow->assertNoEvents();
Siarhei Vishniakou234129c2020-10-22 22:28:12 -05009999 mFakePolicy->assertNotifyAnrWasNotCalled();
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -070010000}
10001
10002// When the touch stream is split across 2 windows, and one of them does not respond,
10003// then ANR should be raised and the touch should be canceled for the unresponsive window.
10004// The other window should not be affected by that.
10005TEST_F(InputDispatcherMultiWindowAnr, SplitTouch_SingleWindowAnr) {
10006 // Touch Window 1
Prabir Pradhan678438e2023-04-13 19:32:51 +000010007 mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_DOWN,
10008 AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
10009 {FOCUSED_WINDOW_LOCATION}));
Prabir Pradhan7662a8d2023-12-15 01:58:14 +000010010 mUnfocusedWindow->consumeMotionOutside(ADISPLAY_ID_DEFAULT, /*flags=*/0);
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -070010011
10012 // Touch Window 2
Prabir Pradhan678438e2023-04-13 19:32:51 +000010013 mDispatcher->notifyMotion(
10014 generateMotionArgs(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
10015 {FOCUSED_WINDOW_LOCATION, UNFOCUSED_WINDOW_LOCATION}));
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -070010016
10017 const std::chrono::duration timeout =
10018 mFocusedWindow->getDispatchingTimeout(DISPATCHING_TIMEOUT);
Prabir Pradhanedd96402022-02-15 01:46:16 -080010019 mFakePolicy->assertNotifyWindowUnresponsiveWasCalled(timeout, mFocusedWindow);
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -070010020
10021 mUnfocusedWindow->consumeMotionDown();
10022 mFocusedWindow->consumeMotionDown();
10023 // Focused window may or may not receive ACTION_MOVE
10024 // But it should definitely receive ACTION_CANCEL due to the ANR
Siarhei Vishniakoud3061ab2023-12-18 20:41:08 -080010025 const auto [moveOrCancelSequenceNum, event] = mFocusedWindow->receiveEvent();
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -070010026 ASSERT_TRUE(moveOrCancelSequenceNum);
10027 mFocusedWindow->finishEvent(*moveOrCancelSequenceNum);
10028 ASSERT_NE(nullptr, event);
Siarhei Vishniakou63b63612023-04-12 11:00:23 -070010029 ASSERT_EQ(event->getType(), InputEventType::MOTION);
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -070010030 MotionEvent& motionEvent = static_cast<MotionEvent&>(*event);
10031 if (motionEvent.getAction() == AMOTION_EVENT_ACTION_MOVE) {
10032 mFocusedWindow->consumeMotionCancel();
10033 } else {
10034 ASSERT_EQ(AMOTION_EVENT_ACTION_CANCEL, motionEvent.getAction());
10035 }
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -070010036 ASSERT_TRUE(mDispatcher->waitForIdle());
Prabir Pradhanedd96402022-02-15 01:46:16 -080010037 mFakePolicy->assertNotifyWindowResponsiveWasCalled(mFocusedWindow->getToken(),
10038 mFocusedWindow->getPid());
Siarhei Vishniakou234129c2020-10-22 22:28:12 -050010039
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -070010040 mUnfocusedWindow->assertNoEvents();
10041 mFocusedWindow->assertNoEvents();
Siarhei Vishniakou234129c2020-10-22 22:28:12 -050010042 mFakePolicy->assertNotifyAnrWasNotCalled();
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -070010043}
10044
Siarhei Vishniakouf56b2692020-09-08 19:43:33 -050010045/**
10046 * If we have no focused window, and a key comes in, we start the ANR timer.
10047 * The focused application should add a focused window before the timer runs out to prevent ANR.
10048 *
10049 * If the user touches another application during this time, the key should be dropped.
10050 * Next, if a new focused window comes in, without toggling the focused application,
10051 * then no ANR should occur.
10052 *
10053 * Normally, we would expect the new focused window to be accompanied by 'setFocusedApplication',
10054 * but in some cases the policy may not update the focused application.
10055 */
10056TEST_F(InputDispatcherMultiWindowAnr, FocusedWindowWithoutSetFocusedApplication_NoAnr) {
10057 std::shared_ptr<FakeApplicationHandle> focusedApplication =
10058 std::make_shared<FakeApplicationHandle>();
Siarhei Vishniakouc033dfb2023-10-03 10:45:16 -070010059 focusedApplication->setDispatchingTimeout(300ms);
Siarhei Vishniakouf56b2692020-09-08 19:43:33 -050010060 mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, focusedApplication);
10061 // The application that owns 'mFocusedWindow' and 'mUnfocusedWindow' is not focused.
10062 mFocusedWindow->setFocusable(false);
10063
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070010064 mDispatcher->onWindowInfosChanged(
10065 {{*mFocusedWindow->getInfo(), *mUnfocusedWindow->getInfo()}, {}, 0, 0});
Siarhei Vishniakouf56b2692020-09-08 19:43:33 -050010066 mFocusedWindow->consumeFocusEvent(false);
10067
10068 // Send a key. The ANR timer should start because there is no focused window.
10069 // 'focusedApplication' will get blamed if this timer completes.
10070 // Key will not be sent anywhere because we have no focused window. It will remain pending.
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -080010071 InputEventInjectionResult result =
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070010072 injectKey(*mDispatcher, AKEY_EVENT_ACTION_DOWN, /*repeatCount=*/0, ADISPLAY_ID_DEFAULT,
10073 InputEventInjectionSync::NONE, /*injectionTimeout=*/100ms,
Harry Cutts33476232023-01-30 19:57:29 +000010074 /*allowKeyRepeat=*/false);
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -080010075 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, result);
Siarhei Vishniakouf56b2692020-09-08 19:43:33 -050010076
10077 // Wait until dispatcher starts the "no focused window" timer. If we don't wait here,
10078 // then the injected touches won't cause the focused event to get dropped.
10079 // The dispatcher only checks for whether the queue should be pruned upon queueing.
10080 // If we inject the touch right away and the ANR timer hasn't started, the touch event would
10081 // simply be added to the queue without 'shouldPruneInboundQueueLocked' returning 'true'.
10082 // For this test, it means that the key would get delivered to the window once it becomes
10083 // focused.
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070010084 std::this_thread::sleep_for(100ms);
Siarhei Vishniakouf56b2692020-09-08 19:43:33 -050010085
10086 // Touch unfocused window. This should force the pending key to get dropped.
Prabir Pradhan678438e2023-04-13 19:32:51 +000010087 mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_DOWN,
10088 AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
10089 {UNFOCUSED_WINDOW_LOCATION}));
Siarhei Vishniakouf56b2692020-09-08 19:43:33 -050010090
10091 // We do not consume the motion right away, because that would require dispatcher to first
10092 // process (== drop) the key event, and by that time, ANR will be raised.
10093 // Set the focused window first.
10094 mFocusedWindow->setFocusable(true);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070010095 mDispatcher->onWindowInfosChanged(
10096 {{*mFocusedWindow->getInfo(), *mUnfocusedWindow->getInfo()}, {}, 0, 0});
Siarhei Vishniakouf56b2692020-09-08 19:43:33 -050010097 setFocusedWindow(mFocusedWindow);
10098 mFocusedWindow->consumeFocusEvent(true);
10099 // We do not call "setFocusedApplication" here, even though the newly focused window belongs
10100 // to another application. This could be a bug / behaviour in the policy.
10101
10102 mUnfocusedWindow->consumeMotionDown();
10103
10104 ASSERT_TRUE(mDispatcher->waitForIdle());
10105 // Should not ANR because we actually have a focused window. It was just added too slowly.
10106 ASSERT_NO_FATAL_FAILURE(mFakePolicy->assertNotifyAnrWasNotCalled());
10107}
10108
Siarhei Vishniakou99e407b2023-12-26 18:09:32 -080010109/**
10110 * If we are pruning input queue, we should never drop pointer events. Otherwise, we risk having
10111 * an inconsistent event stream inside the dispatcher. In this test, we make sure that the
10112 * dispatcher doesn't prune pointer events incorrectly.
10113 *
10114 * This test reproduces a crash in InputDispatcher.
10115 * To reproduce the crash, we need to simulate the conditions for "pruning input queue" to occur.
10116 *
10117 * Keep the currently focused application (mApplication), and have no focused window.
10118 * We set up two additional windows:
10119 * 1) The navigation bar window. This simulates the system "NavigationBar", which is used in the
10120 * 3-button navigation mode. This window injects a BACK button when it's touched. 2) The application
10121 * window. This window is not focusable, but is touchable.
10122 *
10123 * We first touch the navigation bar, which causes it to inject a key. Since there's no focused
10124 * window, the dispatcher doesn't process this key, and all other events inside dispatcher are now
10125 * blocked. The dispatcher is waiting for 'mApplication' to add a focused window.
10126 *
10127 * Now, we touch "Another window". This window is owned by a different application than
10128 * 'mApplication'. This causes the dispatcher to stop waiting for 'mApplication' to add a focused
10129 * window. Now, the "pruning input queue" behaviour should kick in, and the dispatcher should start
10130 * dropping the events from its queue. Ensure that no crash occurs.
10131 *
10132 * In this test, we are setting long timeouts to prevent ANRs and events dropped due to being stale.
10133 * This does not affect the test running time.
10134 */
10135TEST_F(InputDispatcherMultiWindowAnr, PruningInputQueueShouldNotDropPointerEvents) {
10136 std::shared_ptr<FakeApplicationHandle> systemUiApplication =
10137 std::make_shared<FakeApplicationHandle>();
10138 systemUiApplication->setDispatchingTimeout(3000ms);
10139 mFakePolicy->setStaleEventTimeout(3000ms);
10140 sp<FakeWindowHandle> navigationBar =
10141 sp<FakeWindowHandle>::make(systemUiApplication, mDispatcher, "NavigationBar",
10142 ADISPLAY_ID_DEFAULT);
10143 navigationBar->setFocusable(false);
10144 navigationBar->setWatchOutsideTouch(true);
10145 navigationBar->setFrame(Rect(0, 0, 100, 100));
10146
10147 mApplication->setDispatchingTimeout(3000ms);
10148 // 'mApplication' is already focused, but we call it again here to make it explicit.
10149 mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, mApplication);
10150
10151 std::shared_ptr<FakeApplicationHandle> anotherApplication =
10152 std::make_shared<FakeApplicationHandle>();
10153 sp<FakeWindowHandle> appWindow =
10154 sp<FakeWindowHandle>::make(anotherApplication, mDispatcher, "Another window",
10155 ADISPLAY_ID_DEFAULT);
10156 appWindow->setFocusable(false);
10157 appWindow->setFrame(Rect(100, 100, 200, 200));
10158
10159 mDispatcher->onWindowInfosChanged(
10160 {{*navigationBar->getInfo(), *appWindow->getInfo()}, {}, 0, 0});
10161 // 'mFocusedWindow' is no longer in the dispatcher window list, and therefore loses focus
10162 mFocusedWindow->consumeFocusEvent(false);
10163
10164 // Touch down the navigation bar. It consumes the touch and injects a key into the dispatcher
10165 // in response.
10166 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
10167 .pointer(PointerBuilder(0, ToolType::FINGER).x(50).y(50))
10168 .build());
10169 navigationBar->consumeMotionEvent(WithMotionAction(ACTION_DOWN));
10170
10171 // Key will not be sent anywhere because we have no focused window. It will remain pending.
10172 // Pretend we are injecting KEYCODE_BACK, but it doesn't actually matter what key it is.
10173 InputEventInjectionResult result =
10174 injectKey(*mDispatcher, AKEY_EVENT_ACTION_DOWN, /*repeatCount=*/0, ADISPLAY_ID_DEFAULT,
10175 InputEventInjectionSync::NONE, /*injectionTimeout=*/100ms,
10176 /*allowKeyRepeat=*/false);
10177 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, result);
10178
10179 // Finish the gesture - lift up finger and inject ACTION_UP key event
10180 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN)
10181 .pointer(PointerBuilder(0, ToolType::FINGER).x(50).y(50))
10182 .build());
10183 result = injectKey(*mDispatcher, AKEY_EVENT_ACTION_UP, /*repeatCount=*/0, ADISPLAY_ID_DEFAULT,
10184 InputEventInjectionSync::NONE, /*injectionTimeout=*/100ms,
10185 /*allowKeyRepeat=*/false);
10186 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, result);
10187 // The key that was injected is blocking the dispatcher, so the navigation bar shouldn't be
10188 // getting any events yet.
10189 navigationBar->assertNoEvents();
10190
10191 // Now touch "Another window". This touch is going to a different application than the one we
10192 // are waiting for (which is 'mApplication').
10193 // This should cause the dispatcher to drop the pending focus-dispatched events (like the key
10194 // trying to be injected) and to continue processing the rest of the events in the original
10195 // order.
10196 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
10197 .pointer(PointerBuilder(0, ToolType::FINGER).x(150).y(150))
10198 .build());
10199 navigationBar->consumeMotionEvent(WithMotionAction(ACTION_UP));
10200 navigationBar->consumeMotionEvent(WithMotionAction(ACTION_OUTSIDE));
10201 appWindow->consumeMotionEvent(WithMotionAction(ACTION_DOWN));
10202
10203 appWindow->assertNoEvents();
10204 navigationBar->assertNoEvents();
10205}
10206
Siarhei Vishniakoua2862a02020-07-20 16:36:46 -050010207// These tests ensure we cannot send touch events to a window that's positioned behind a window
10208// that has feature NO_INPUT_CHANNEL.
10209// Layout:
10210// Top (closest to user)
10211// mNoInputWindow (above all windows)
10212// mBottomWindow
10213// Bottom (furthest from user)
10214class InputDispatcherMultiWindowOcclusionTests : public InputDispatcherTest {
10215 virtual void SetUp() override {
10216 InputDispatcherTest::SetUp();
10217
10218 mApplication = std::make_shared<FakeApplicationHandle>();
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -070010219 mNoInputWindow =
10220 sp<FakeWindowHandle>::make(mApplication, mDispatcher,
10221 "Window without input channel", ADISPLAY_ID_DEFAULT,
Prabir Pradhane7cc69c2024-01-05 21:35:28 +000010222 /*createInputChannel=*/false);
Prabir Pradhan51e7db02022-02-07 06:02:57 -080010223 mNoInputWindow->setNoInputChannel(true);
Siarhei Vishniakoua2862a02020-07-20 16:36:46 -050010224 mNoInputWindow->setFrame(Rect(0, 0, 100, 100));
10225 // It's perfectly valid for this window to not have an associated input channel
10226
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -070010227 mBottomWindow = sp<FakeWindowHandle>::make(mApplication, mDispatcher, "Bottom window",
10228 ADISPLAY_ID_DEFAULT);
Siarhei Vishniakoua2862a02020-07-20 16:36:46 -050010229 mBottomWindow->setFrame(Rect(0, 0, 100, 100));
10230
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070010231 mDispatcher->onWindowInfosChanged(
10232 {{*mNoInputWindow->getInfo(), *mBottomWindow->getInfo()}, {}, 0, 0});
Siarhei Vishniakoua2862a02020-07-20 16:36:46 -050010233 }
10234
10235protected:
10236 std::shared_ptr<FakeApplicationHandle> mApplication;
10237 sp<FakeWindowHandle> mNoInputWindow;
10238 sp<FakeWindowHandle> mBottomWindow;
10239};
10240
10241TEST_F(InputDispatcherMultiWindowOcclusionTests, NoInputChannelFeature_DropsTouches) {
10242 PointF touchedPoint = {10, 10};
10243
Prabir Pradhan678438e2023-04-13 19:32:51 +000010244 mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_DOWN,
10245 AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
10246 {touchedPoint}));
Siarhei Vishniakoua2862a02020-07-20 16:36:46 -050010247
10248 mNoInputWindow->assertNoEvents();
10249 // Even though the window 'mNoInputWindow' positioned above 'mBottomWindow' does not have
10250 // an input channel, it is not marked as FLAG_NOT_TOUCHABLE,
10251 // and therefore should prevent mBottomWindow from receiving touches
10252 mBottomWindow->assertNoEvents();
10253}
10254
10255/**
10256 * If a window has feature NO_INPUT_CHANNEL, and somehow (by mistake) still has an input channel,
10257 * ensure that this window does not receive any touches, and blocks touches to windows underneath.
10258 */
10259TEST_F(InputDispatcherMultiWindowOcclusionTests,
10260 NoInputChannelFeature_DropsTouchesWithValidChannel) {
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -070010261 mNoInputWindow = sp<FakeWindowHandle>::make(mApplication, mDispatcher,
10262 "Window with input channel and NO_INPUT_CHANNEL",
10263 ADISPLAY_ID_DEFAULT);
Siarhei Vishniakoua2862a02020-07-20 16:36:46 -050010264
Prabir Pradhan51e7db02022-02-07 06:02:57 -080010265 mNoInputWindow->setNoInputChannel(true);
Siarhei Vishniakoua2862a02020-07-20 16:36:46 -050010266 mNoInputWindow->setFrame(Rect(0, 0, 100, 100));
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070010267 mDispatcher->onWindowInfosChanged(
10268 {{*mNoInputWindow->getInfo(), *mBottomWindow->getInfo()}, {}, 0, 0});
Siarhei Vishniakoua2862a02020-07-20 16:36:46 -050010269
10270 PointF touchedPoint = {10, 10};
10271
Prabir Pradhan678438e2023-04-13 19:32:51 +000010272 mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_DOWN,
10273 AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
10274 {touchedPoint}));
Siarhei Vishniakoua2862a02020-07-20 16:36:46 -050010275
10276 mNoInputWindow->assertNoEvents();
10277 mBottomWindow->assertNoEvents();
10278}
10279
Vishnu Nair958da932020-08-21 17:12:37 -070010280class InputDispatcherMirrorWindowFocusTests : public InputDispatcherTest {
10281protected:
10282 std::shared_ptr<FakeApplicationHandle> mApp;
10283 sp<FakeWindowHandle> mWindow;
10284 sp<FakeWindowHandle> mMirror;
10285
10286 virtual void SetUp() override {
10287 InputDispatcherTest::SetUp();
10288 mApp = std::make_shared<FakeApplicationHandle>();
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -070010289 mWindow = sp<FakeWindowHandle>::make(mApp, mDispatcher, "TestWindow", ADISPLAY_ID_DEFAULT);
Prabir Pradhane7cc69c2024-01-05 21:35:28 +000010290 mMirror = mWindow->clone(ADISPLAY_ID_DEFAULT);
Vishnu Nair958da932020-08-21 17:12:37 -070010291 mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, mApp);
10292 mWindow->setFocusable(true);
10293 mMirror->setFocusable(true);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070010294 mDispatcher->onWindowInfosChanged({{*mWindow->getInfo(), *mMirror->getInfo()}, {}, 0, 0});
Vishnu Nair958da932020-08-21 17:12:37 -070010295 }
10296};
10297
10298TEST_F(InputDispatcherMirrorWindowFocusTests, CanGetFocus) {
10299 // Request focus on a mirrored window
10300 setFocusedWindow(mMirror);
10301
10302 // window gets focused
10303 mWindow->consumeFocusEvent(true);
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070010304 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectKeyDown(*mDispatcher))
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -080010305 << "Inject key event should return InputEventInjectionResult::SUCCEEDED";
Vishnu Nair958da932020-08-21 17:12:37 -070010306 mWindow->consumeKeyDown(ADISPLAY_ID_NONE);
10307}
10308
10309// A focused & mirrored window remains focused only if the window and its mirror are both
10310// focusable.
10311TEST_F(InputDispatcherMirrorWindowFocusTests, FocusedIfAllWindowsFocusable) {
10312 setFocusedWindow(mMirror);
10313
Prabir Pradhanbb3f1c02024-01-04 20:17:14 +000010314 // window gets focused because it is above the mirror
Vishnu Nair958da932020-08-21 17:12:37 -070010315 mWindow->consumeFocusEvent(true);
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070010316 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectKeyDown(*mDispatcher))
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -080010317 << "Inject key event should return InputEventInjectionResult::SUCCEEDED";
Vishnu Nair958da932020-08-21 17:12:37 -070010318 mWindow->consumeKeyDown(ADISPLAY_ID_NONE);
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070010319 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectKeyUp(*mDispatcher))
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -080010320 << "Inject key event should return InputEventInjectionResult::SUCCEEDED";
Vishnu Nair958da932020-08-21 17:12:37 -070010321 mWindow->consumeKeyUp(ADISPLAY_ID_NONE);
10322
10323 mMirror->setFocusable(false);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070010324 mDispatcher->onWindowInfosChanged({{*mWindow->getInfo(), *mMirror->getInfo()}, {}, 0, 0});
Vishnu Nair958da932020-08-21 17:12:37 -070010325
10326 // window loses focus since one of the windows associated with the token in not focusable
10327 mWindow->consumeFocusEvent(false);
10328
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070010329 ASSERT_EQ(InputEventInjectionResult::TIMED_OUT, injectKeyDown(*mDispatcher))
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -080010330 << "Inject key event should return InputEventInjectionResult::TIMED_OUT";
Vishnu Nair958da932020-08-21 17:12:37 -070010331 mWindow->assertNoEvents();
10332}
10333
10334// A focused & mirrored window remains focused until the window and its mirror both become
10335// invisible.
10336TEST_F(InputDispatcherMirrorWindowFocusTests, FocusedIfAnyWindowVisible) {
10337 setFocusedWindow(mMirror);
10338
10339 // window gets focused
10340 mWindow->consumeFocusEvent(true);
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070010341 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectKeyDown(*mDispatcher))
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -080010342 << "Inject key event should return InputEventInjectionResult::SUCCEEDED";
Vishnu Nair958da932020-08-21 17:12:37 -070010343 mWindow->consumeKeyDown(ADISPLAY_ID_NONE);
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070010344 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectKeyUp(*mDispatcher))
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -080010345 << "Inject key event should return InputEventInjectionResult::SUCCEEDED";
Vishnu Nair958da932020-08-21 17:12:37 -070010346 mWindow->consumeKeyUp(ADISPLAY_ID_NONE);
10347
10348 mMirror->setVisible(false);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070010349 mDispatcher->onWindowInfosChanged({{*mWindow->getInfo(), *mMirror->getInfo()}, {}, 0, 0});
Vishnu Nair958da932020-08-21 17:12:37 -070010350
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070010351 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectKeyDown(*mDispatcher))
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -080010352 << "Inject key event should return InputEventInjectionResult::SUCCEEDED";
Vishnu Nair958da932020-08-21 17:12:37 -070010353 mWindow->consumeKeyDown(ADISPLAY_ID_NONE);
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070010354 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectKeyUp(*mDispatcher))
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -080010355 << "Inject key event should return InputEventInjectionResult::SUCCEEDED";
Vishnu Nair958da932020-08-21 17:12:37 -070010356 mWindow->consumeKeyUp(ADISPLAY_ID_NONE);
10357
10358 mWindow->setVisible(false);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070010359 mDispatcher->onWindowInfosChanged({{*mWindow->getInfo(), *mMirror->getInfo()}, {}, 0, 0});
Vishnu Nair958da932020-08-21 17:12:37 -070010360
10361 // window loses focus only after all windows associated with the token become invisible.
10362 mWindow->consumeFocusEvent(false);
10363
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070010364 ASSERT_EQ(InputEventInjectionResult::TIMED_OUT, injectKeyDown(*mDispatcher))
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -080010365 << "Inject key event should return InputEventInjectionResult::TIMED_OUT";
Vishnu Nair958da932020-08-21 17:12:37 -070010366 mWindow->assertNoEvents();
10367}
10368
10369// A focused & mirrored window remains focused until both windows are removed.
10370TEST_F(InputDispatcherMirrorWindowFocusTests, FocusedWhileWindowsAlive) {
10371 setFocusedWindow(mMirror);
10372
10373 // window gets focused
10374 mWindow->consumeFocusEvent(true);
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070010375 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectKeyDown(*mDispatcher))
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -080010376 << "Inject key event should return InputEventInjectionResult::SUCCEEDED";
Vishnu Nair958da932020-08-21 17:12:37 -070010377 mWindow->consumeKeyDown(ADISPLAY_ID_NONE);
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070010378 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectKeyUp(*mDispatcher))
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -080010379 << "Inject key event should return InputEventInjectionResult::SUCCEEDED";
Vishnu Nair958da932020-08-21 17:12:37 -070010380 mWindow->consumeKeyUp(ADISPLAY_ID_NONE);
10381
10382 // single window is removed but the window token remains focused
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070010383 mDispatcher->onWindowInfosChanged({{*mMirror->getInfo()}, {}, 0, 0});
Vishnu Nair958da932020-08-21 17:12:37 -070010384
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070010385 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectKeyDown(*mDispatcher))
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -080010386 << "Inject key event should return InputEventInjectionResult::SUCCEEDED";
Prabir Pradhanbb3f1c02024-01-04 20:17:14 +000010387 mMirror->consumeKeyDown(ADISPLAY_ID_NONE);
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070010388 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectKeyUp(*mDispatcher))
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -080010389 << "Inject key event should return InputEventInjectionResult::SUCCEEDED";
Prabir Pradhanbb3f1c02024-01-04 20:17:14 +000010390 mMirror->consumeKeyUp(ADISPLAY_ID_NONE);
Vishnu Nair958da932020-08-21 17:12:37 -070010391
10392 // Both windows are removed
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070010393 mDispatcher->onWindowInfosChanged({{}, {}, 0, 0});
Vishnu Nair958da932020-08-21 17:12:37 -070010394 mWindow->consumeFocusEvent(false);
10395
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070010396 ASSERT_EQ(InputEventInjectionResult::TIMED_OUT, injectKeyDown(*mDispatcher))
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -080010397 << "Inject key event should return InputEventInjectionResult::TIMED_OUT";
Vishnu Nair958da932020-08-21 17:12:37 -070010398 mWindow->assertNoEvents();
10399}
10400
10401// Focus request can be pending until one window becomes visible.
10402TEST_F(InputDispatcherMirrorWindowFocusTests, DeferFocusWhenInvisible) {
10403 // Request focus on an invisible mirror.
10404 mWindow->setVisible(false);
10405 mMirror->setVisible(false);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070010406 mDispatcher->onWindowInfosChanged({{*mWindow->getInfo(), *mMirror->getInfo()}, {}, 0, 0});
Vishnu Nair958da932020-08-21 17:12:37 -070010407 setFocusedWindow(mMirror);
10408
10409 // Injected key goes to pending queue.
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -080010410 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070010411 injectKey(*mDispatcher, AKEY_EVENT_ACTION_DOWN, /*repeatCount=*/0,
10412 ADISPLAY_ID_DEFAULT, InputEventInjectionSync::NONE));
Vishnu Nair958da932020-08-21 17:12:37 -070010413
10414 mMirror->setVisible(true);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070010415 mDispatcher->onWindowInfosChanged({{*mWindow->getInfo(), *mMirror->getInfo()}, {}, 0, 0});
Vishnu Nair958da932020-08-21 17:12:37 -070010416
10417 // window gets focused
10418 mWindow->consumeFocusEvent(true);
10419 // window gets the pending key event
10420 mWindow->consumeKeyDown(ADISPLAY_ID_DEFAULT);
10421}
Prabir Pradhan99987712020-11-10 18:43:05 -080010422
10423class InputDispatcherPointerCaptureTests : public InputDispatcherTest {
10424protected:
10425 std::shared_ptr<FakeApplicationHandle> mApp;
10426 sp<FakeWindowHandle> mWindow;
10427 sp<FakeWindowHandle> mSecondWindow;
10428
10429 void SetUp() override {
10430 InputDispatcherTest::SetUp();
10431 mApp = std::make_shared<FakeApplicationHandle>();
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -070010432 mWindow = sp<FakeWindowHandle>::make(mApp, mDispatcher, "TestWindow", ADISPLAY_ID_DEFAULT);
Prabir Pradhan99987712020-11-10 18:43:05 -080010433 mWindow->setFocusable(true);
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -070010434 mSecondWindow =
10435 sp<FakeWindowHandle>::make(mApp, mDispatcher, "TestWindow2", ADISPLAY_ID_DEFAULT);
Prabir Pradhan99987712020-11-10 18:43:05 -080010436 mSecondWindow->setFocusable(true);
10437
10438 mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, mApp);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070010439 mDispatcher->onWindowInfosChanged(
10440 {{*mWindow->getInfo(), *mSecondWindow->getInfo()}, {}, 0, 0});
Prabir Pradhan99987712020-11-10 18:43:05 -080010441
10442 setFocusedWindow(mWindow);
10443 mWindow->consumeFocusEvent(true);
10444 }
10445
Prabir Pradhan5cc1a692021-08-06 14:01:18 +000010446 void notifyPointerCaptureChanged(const PointerCaptureRequest& request) {
Prabir Pradhan678438e2023-04-13 19:32:51 +000010447 mDispatcher->notifyPointerCaptureChanged(generatePointerCaptureChangedArgs(request));
Prabir Pradhan99987712020-11-10 18:43:05 -080010448 }
10449
Prabir Pradhan5cc1a692021-08-06 14:01:18 +000010450 PointerCaptureRequest requestAndVerifyPointerCapture(const sp<FakeWindowHandle>& window,
10451 bool enabled) {
Prabir Pradhan99987712020-11-10 18:43:05 -080010452 mDispatcher->requestPointerCapture(window->getToken(), enabled);
Hiroki Sato25040232024-02-22 17:21:22 +090010453 auto request = mFakePolicy->assertSetPointerCaptureCalled(window, enabled);
Prabir Pradhan5cc1a692021-08-06 14:01:18 +000010454 notifyPointerCaptureChanged(request);
Prabir Pradhan99987712020-11-10 18:43:05 -080010455 window->consumeCaptureEvent(enabled);
Prabir Pradhan5cc1a692021-08-06 14:01:18 +000010456 return request;
Prabir Pradhan99987712020-11-10 18:43:05 -080010457 }
10458};
10459
10460TEST_F(InputDispatcherPointerCaptureTests, EnablePointerCaptureWhenFocused) {
10461 // Ensure that capture cannot be obtained for unfocused windows.
10462 mDispatcher->requestPointerCapture(mSecondWindow->getToken(), true);
10463 mFakePolicy->assertSetPointerCaptureNotCalled();
10464 mSecondWindow->assertNoEvents();
10465
10466 // Ensure that capture can be enabled from the focus window.
10467 requestAndVerifyPointerCapture(mWindow, true);
10468
10469 // Ensure that capture cannot be disabled from a window that does not have capture.
10470 mDispatcher->requestPointerCapture(mSecondWindow->getToken(), false);
10471 mFakePolicy->assertSetPointerCaptureNotCalled();
10472
10473 // Ensure that capture can be disabled from the window with capture.
10474 requestAndVerifyPointerCapture(mWindow, false);
10475}
10476
10477TEST_F(InputDispatcherPointerCaptureTests, DisablesPointerCaptureAfterWindowLosesFocus) {
Prabir Pradhan5cc1a692021-08-06 14:01:18 +000010478 auto request = requestAndVerifyPointerCapture(mWindow, true);
Prabir Pradhan99987712020-11-10 18:43:05 -080010479
10480 setFocusedWindow(mSecondWindow);
10481
10482 // Ensure that the capture disabled event was sent first.
10483 mWindow->consumeCaptureEvent(false);
10484 mWindow->consumeFocusEvent(false);
10485 mSecondWindow->consumeFocusEvent(true);
Hiroki Sato25040232024-02-22 17:21:22 +090010486 mFakePolicy->assertSetPointerCaptureCalled(mWindow, false);
Prabir Pradhan99987712020-11-10 18:43:05 -080010487
10488 // Ensure that additional state changes from InputReader are not sent to the window.
Prabir Pradhan5cc1a692021-08-06 14:01:18 +000010489 notifyPointerCaptureChanged({});
10490 notifyPointerCaptureChanged(request);
10491 notifyPointerCaptureChanged({});
Prabir Pradhan99987712020-11-10 18:43:05 -080010492 mWindow->assertNoEvents();
10493 mSecondWindow->assertNoEvents();
10494 mFakePolicy->assertSetPointerCaptureNotCalled();
10495}
10496
10497TEST_F(InputDispatcherPointerCaptureTests, UnexpectedStateChangeDisablesPointerCapture) {
Prabir Pradhan5cc1a692021-08-06 14:01:18 +000010498 auto request = requestAndVerifyPointerCapture(mWindow, true);
Prabir Pradhan99987712020-11-10 18:43:05 -080010499
10500 // InputReader unexpectedly disables and enables pointer capture.
Prabir Pradhan5cc1a692021-08-06 14:01:18 +000010501 notifyPointerCaptureChanged({});
10502 notifyPointerCaptureChanged(request);
Prabir Pradhan99987712020-11-10 18:43:05 -080010503
10504 // Ensure that Pointer Capture is disabled.
Hiroki Sato25040232024-02-22 17:21:22 +090010505 mFakePolicy->assertSetPointerCaptureCalled(mWindow, false);
Prabir Pradhan99987712020-11-10 18:43:05 -080010506 mWindow->consumeCaptureEvent(false);
10507 mWindow->assertNoEvents();
10508}
10509
Prabir Pradhan167e6d92021-02-04 16:18:17 -080010510TEST_F(InputDispatcherPointerCaptureTests, OutOfOrderRequests) {
10511 requestAndVerifyPointerCapture(mWindow, true);
10512
10513 // The first window loses focus.
10514 setFocusedWindow(mSecondWindow);
Hiroki Sato25040232024-02-22 17:21:22 +090010515 mFakePolicy->assertSetPointerCaptureCalled(mWindow, false);
Prabir Pradhan167e6d92021-02-04 16:18:17 -080010516 mWindow->consumeCaptureEvent(false);
10517
10518 // Request Pointer Capture from the second window before the notification from InputReader
10519 // arrives.
10520 mDispatcher->requestPointerCapture(mSecondWindow->getToken(), true);
Hiroki Sato25040232024-02-22 17:21:22 +090010521 auto request = mFakePolicy->assertSetPointerCaptureCalled(mSecondWindow, true);
Prabir Pradhan167e6d92021-02-04 16:18:17 -080010522
10523 // InputReader notifies Pointer Capture was disabled (because of the focus change).
Prabir Pradhan5cc1a692021-08-06 14:01:18 +000010524 notifyPointerCaptureChanged({});
Prabir Pradhan167e6d92021-02-04 16:18:17 -080010525
10526 // InputReader notifies Pointer Capture was enabled (because of mSecondWindow's request).
Prabir Pradhan5cc1a692021-08-06 14:01:18 +000010527 notifyPointerCaptureChanged(request);
Prabir Pradhan167e6d92021-02-04 16:18:17 -080010528
10529 mSecondWindow->consumeFocusEvent(true);
10530 mSecondWindow->consumeCaptureEvent(true);
10531}
10532
Prabir Pradhan5cc1a692021-08-06 14:01:18 +000010533TEST_F(InputDispatcherPointerCaptureTests, EnableRequestFollowsSequenceNumbers) {
10534 // App repeatedly enables and disables capture.
10535 mDispatcher->requestPointerCapture(mWindow->getToken(), true);
Hiroki Sato25040232024-02-22 17:21:22 +090010536 auto firstRequest = mFakePolicy->assertSetPointerCaptureCalled(mWindow, true);
Prabir Pradhan5cc1a692021-08-06 14:01:18 +000010537 mDispatcher->requestPointerCapture(mWindow->getToken(), false);
Hiroki Sato25040232024-02-22 17:21:22 +090010538 mFakePolicy->assertSetPointerCaptureCalled(mWindow, false);
Prabir Pradhan5cc1a692021-08-06 14:01:18 +000010539 mDispatcher->requestPointerCapture(mWindow->getToken(), true);
Hiroki Sato25040232024-02-22 17:21:22 +090010540 auto secondRequest = mFakePolicy->assertSetPointerCaptureCalled(mWindow, true);
Prabir Pradhan5cc1a692021-08-06 14:01:18 +000010541
10542 // InputReader notifies that PointerCapture has been enabled for the first request. Since the
10543 // first request is now stale, this should do nothing.
10544 notifyPointerCaptureChanged(firstRequest);
10545 mWindow->assertNoEvents();
10546
10547 // InputReader notifies that the second request was enabled.
10548 notifyPointerCaptureChanged(secondRequest);
10549 mWindow->consumeCaptureEvent(true);
10550}
10551
Prabir Pradhan7092e262022-05-03 16:51:09 +000010552TEST_F(InputDispatcherPointerCaptureTests, RapidToggleRequests) {
10553 requestAndVerifyPointerCapture(mWindow, true);
10554
10555 // App toggles pointer capture off and on.
10556 mDispatcher->requestPointerCapture(mWindow->getToken(), false);
Hiroki Sato25040232024-02-22 17:21:22 +090010557 mFakePolicy->assertSetPointerCaptureCalled(mWindow, false);
Prabir Pradhan7092e262022-05-03 16:51:09 +000010558
10559 mDispatcher->requestPointerCapture(mWindow->getToken(), true);
Hiroki Sato25040232024-02-22 17:21:22 +090010560 auto enableRequest = mFakePolicy->assertSetPointerCaptureCalled(mWindow, true);
Prabir Pradhan7092e262022-05-03 16:51:09 +000010561
10562 // InputReader notifies that the latest "enable" request was processed, while skipping over the
10563 // preceding "disable" request.
10564 notifyPointerCaptureChanged(enableRequest);
10565
10566 // Since pointer capture was never disabled during the rapid toggle, the window does not receive
10567 // any notifications.
10568 mWindow->assertNoEvents();
10569}
10570
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -070010571/**
10572 * One window. Hover mouse in the window, and then start capture. Make sure that the relative
10573 * mouse movements don't affect the previous mouse hovering state.
10574 * When pointer capture is enabled, the incoming events are always ACTION_MOVE (there are no
10575 * HOVER_MOVE events).
10576 */
10577TEST_F(InputDispatcherPointerCaptureTests, MouseHoverAndPointerCapture) {
10578 // Mouse hover on the window
10579 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_ENTER, AINPUT_SOURCE_MOUSE)
10580 .pointer(PointerBuilder(0, ToolType::MOUSE).x(100).y(110))
10581 .build());
10582 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_MOVE, AINPUT_SOURCE_MOUSE)
10583 .pointer(PointerBuilder(0, ToolType::MOUSE).x(100).y(110))
10584 .build());
10585
10586 mWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_HOVER_ENTER)));
10587 mWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_HOVER_MOVE)));
10588
10589 // Start pointer capture
10590 requestAndVerifyPointerCapture(mWindow, true);
10591
10592 // Send some relative mouse movements and receive them in the window.
10593 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_MOUSE_RELATIVE)
10594 .pointer(PointerBuilder(0, ToolType::MOUSE).x(10).y(11))
10595 .build());
10596 mWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_MOVE), WithCoords(10, 11),
10597 WithSource(AINPUT_SOURCE_MOUSE_RELATIVE)));
10598
10599 // Stop pointer capture
10600 requestAndVerifyPointerCapture(mWindow, false);
10601
10602 // Continue hovering on the window
10603 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_MOVE, AINPUT_SOURCE_MOUSE)
10604 .pointer(PointerBuilder(0, ToolType::MOUSE).x(105).y(115))
10605 .build());
10606 mWindow->consumeMotionEvent(
10607 AllOf(WithMotionAction(ACTION_HOVER_MOVE), WithSource(AINPUT_SOURCE_MOUSE)));
10608
10609 mWindow->assertNoEvents();
10610}
10611
Hiroki Sato25040232024-02-22 17:21:22 +090010612using InputDispatcherPointerCaptureDeathTest = InputDispatcherPointerCaptureTests;
10613
10614TEST_F(InputDispatcherPointerCaptureDeathTest,
10615 NotifyPointerCaptureChangedWithWrongTokenAbortsDispatcher) {
10616 testing::GTEST_FLAG(death_test_style) = "threadsafe";
10617 ScopedSilentDeath _silentDeath;
10618
10619 mDispatcher->requestPointerCapture(mWindow->getToken(), true);
10620 auto request = mFakePolicy->assertSetPointerCaptureCalled(mWindow, true);
10621
10622 // Dispatch a pointer changed event with a wrong token.
10623 request.window = mSecondWindow->getToken();
10624 ASSERT_DEATH(
10625 {
10626 notifyPointerCaptureChanged(request);
10627 mSecondWindow->consumeCaptureEvent(true);
10628 },
10629 "Unexpected requested window for Pointer Capture.");
10630}
10631
Bernardo Rufinoc3b7b8c2021-01-29 17:38:07 +000010632class InputDispatcherUntrustedTouchesTest : public InputDispatcherTest {
10633protected:
10634 constexpr static const float MAXIMUM_OBSCURING_OPACITY = 0.8;
Bernardo Rufino7393d172021-02-26 13:56:11 +000010635
10636 constexpr static const float OPACITY_ABOVE_THRESHOLD = 0.9;
10637 static_assert(OPACITY_ABOVE_THRESHOLD > MAXIMUM_OBSCURING_OPACITY);
10638
10639 constexpr static const float OPACITY_BELOW_THRESHOLD = 0.7;
10640 static_assert(OPACITY_BELOW_THRESHOLD < MAXIMUM_OBSCURING_OPACITY);
10641
10642 // When combined twice, ie 1 - (1 - 0.5)*(1 - 0.5) = 0.75 < 8, is still below the threshold
10643 constexpr static const float OPACITY_FAR_BELOW_THRESHOLD = 0.5;
10644 static_assert(OPACITY_FAR_BELOW_THRESHOLD < MAXIMUM_OBSCURING_OPACITY);
10645 static_assert(1 - (1 - OPACITY_FAR_BELOW_THRESHOLD) * (1 - OPACITY_FAR_BELOW_THRESHOLD) <
10646 MAXIMUM_OBSCURING_OPACITY);
10647
Prabir Pradhan8a5c41d2023-06-08 19:13:46 +000010648 static constexpr gui::Uid TOUCHED_APP_UID{10001};
10649 static constexpr gui::Uid APP_B_UID{10002};
10650 static constexpr gui::Uid APP_C_UID{10003};
Bernardo Rufinoc3b7b8c2021-01-29 17:38:07 +000010651
10652 sp<FakeWindowHandle> mTouchWindow;
10653
10654 virtual void SetUp() override {
10655 InputDispatcherTest::SetUp();
Bernardo Rufino6d52e542021-02-15 18:38:10 +000010656 mTouchWindow = getWindow(TOUCHED_APP_UID, "Touched");
Bernardo Rufinoc3b7b8c2021-01-29 17:38:07 +000010657 mDispatcher->setMaximumObscuringOpacityForTouch(MAXIMUM_OBSCURING_OPACITY);
10658 }
10659
10660 virtual void TearDown() override {
10661 InputDispatcherTest::TearDown();
10662 mTouchWindow.clear();
10663 }
10664
Prabir Pradhan8a5c41d2023-06-08 19:13:46 +000010665 sp<FakeWindowHandle> getOccludingWindow(gui::Uid uid, std::string name, TouchOcclusionMode mode,
chaviw3277faf2021-05-19 16:45:23 -050010666 float alpha = 1.0f) {
Bernardo Rufinoc3b7b8c2021-01-29 17:38:07 +000010667 sp<FakeWindowHandle> window = getWindow(uid, name);
Prabir Pradhan4d5c52f2022-01-31 08:52:10 -080010668 window->setTouchable(false);
Bernardo Rufinoc3b7b8c2021-01-29 17:38:07 +000010669 window->setTouchOcclusionMode(mode);
Bernardo Rufino1d0d1f22021-02-12 15:08:43 +000010670 window->setAlpha(alpha);
Bernardo Rufinoc3b7b8c2021-01-29 17:38:07 +000010671 return window;
10672 }
10673
Prabir Pradhan8a5c41d2023-06-08 19:13:46 +000010674 sp<FakeWindowHandle> getWindow(gui::Uid uid, std::string name) {
Bernardo Rufinoc3b7b8c2021-01-29 17:38:07 +000010675 std::shared_ptr<FakeApplicationHandle> app = std::make_shared<FakeApplicationHandle>();
10676 sp<FakeWindowHandle> window =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -070010677 sp<FakeWindowHandle>::make(app, mDispatcher, name, ADISPLAY_ID_DEFAULT);
Bernardo Rufinoc3b7b8c2021-01-29 17:38:07 +000010678 // Generate an arbitrary PID based on the UID
Prabir Pradhanaeebeb42023-06-13 19:53:03 +000010679 window->setOwnerInfo(gui::Pid{static_cast<pid_t>(1777 + (uid.val() % 10000))}, uid);
Bernardo Rufinoc3b7b8c2021-01-29 17:38:07 +000010680 return window;
10681 }
10682
10683 void touch(const std::vector<PointF>& points = {PointF{100, 200}}) {
Prabir Pradhan678438e2023-04-13 19:32:51 +000010684 mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_DOWN,
10685 AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
10686 points));
Bernardo Rufinoc3b7b8c2021-01-29 17:38:07 +000010687 }
10688};
10689
10690TEST_F(InputDispatcherUntrustedTouchesTest, WindowWithBlockUntrustedOcclusionMode_BlocksTouch) {
Bernardo Rufino1d0d1f22021-02-12 15:08:43 +000010691 const sp<FakeWindowHandle>& w =
Bernardo Rufinoc3b7b8c2021-01-29 17:38:07 +000010692 getOccludingWindow(APP_B_UID, "B", TouchOcclusionMode::BLOCK_UNTRUSTED);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070010693 mDispatcher->onWindowInfosChanged({{*w->getInfo(), *mTouchWindow->getInfo()}, {}, 0, 0});
Bernardo Rufinoc3b7b8c2021-01-29 17:38:07 +000010694
10695 touch();
10696
10697 mTouchWindow->assertNoEvents();
10698}
10699
Bernardo Rufinoa43a5a42021-02-17 12:21:14 +000010700TEST_F(InputDispatcherUntrustedTouchesTest,
Bernardo Rufino7393d172021-02-26 13:56:11 +000010701 WindowWithBlockUntrustedOcclusionModeWithOpacityBelowThreshold_BlocksTouch) {
10702 const sp<FakeWindowHandle>& w =
10703 getOccludingWindow(APP_B_UID, "B", TouchOcclusionMode::BLOCK_UNTRUSTED, 0.7f);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070010704 mDispatcher->onWindowInfosChanged({{*w->getInfo(), *mTouchWindow->getInfo()}, {}, 0, 0});
Bernardo Rufino7393d172021-02-26 13:56:11 +000010705
10706 touch();
10707
10708 mTouchWindow->assertNoEvents();
10709}
10710
10711TEST_F(InputDispatcherUntrustedTouchesTest,
Bernardo Rufinoa43a5a42021-02-17 12:21:14 +000010712 WindowWithBlockUntrustedOcclusionMode_DoesNotReceiveTouch) {
10713 const sp<FakeWindowHandle>& w =
10714 getOccludingWindow(APP_B_UID, "B", TouchOcclusionMode::BLOCK_UNTRUSTED);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070010715 mDispatcher->onWindowInfosChanged({{*w->getInfo(), *mTouchWindow->getInfo()}, {}, 0, 0});
Bernardo Rufinoa43a5a42021-02-17 12:21:14 +000010716
10717 touch();
10718
10719 w->assertNoEvents();
10720}
10721
Bernardo Rufinoc3b7b8c2021-01-29 17:38:07 +000010722TEST_F(InputDispatcherUntrustedTouchesTest, WindowWithAllowOcclusionMode_AllowsTouch) {
Bernardo Rufino1d0d1f22021-02-12 15:08:43 +000010723 const sp<FakeWindowHandle>& w = getOccludingWindow(APP_B_UID, "B", TouchOcclusionMode::ALLOW);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070010724 mDispatcher->onWindowInfosChanged({{*w->getInfo(), *mTouchWindow->getInfo()}, {}, 0, 0});
Bernardo Rufinoc3b7b8c2021-01-29 17:38:07 +000010725
10726 touch();
10727
10728 mTouchWindow->consumeAnyMotionDown();
10729}
10730
10731TEST_F(InputDispatcherUntrustedTouchesTest, TouchOutsideOccludingWindow_AllowsTouch) {
Bernardo Rufino1d0d1f22021-02-12 15:08:43 +000010732 const sp<FakeWindowHandle>& w =
Bernardo Rufinoc3b7b8c2021-01-29 17:38:07 +000010733 getOccludingWindow(APP_B_UID, "B", TouchOcclusionMode::BLOCK_UNTRUSTED);
Bernardo Rufino1d0d1f22021-02-12 15:08:43 +000010734 w->setFrame(Rect(0, 0, 50, 50));
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070010735 mDispatcher->onWindowInfosChanged({{*w->getInfo(), *mTouchWindow->getInfo()}, {}, 0, 0});
Bernardo Rufinoc3b7b8c2021-01-29 17:38:07 +000010736
10737 touch({PointF{100, 100}});
10738
10739 mTouchWindow->consumeAnyMotionDown();
10740}
10741
10742TEST_F(InputDispatcherUntrustedTouchesTest, WindowFromSameUid_AllowsTouch) {
Bernardo Rufino1d0d1f22021-02-12 15:08:43 +000010743 const sp<FakeWindowHandle>& w =
Bernardo Rufino6d52e542021-02-15 18:38:10 +000010744 getOccludingWindow(TOUCHED_APP_UID, "A", TouchOcclusionMode::BLOCK_UNTRUSTED);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070010745 mDispatcher->onWindowInfosChanged({{*w->getInfo(), *mTouchWindow->getInfo()}, {}, 0, 0});
Bernardo Rufino1d0d1f22021-02-12 15:08:43 +000010746
10747 touch();
10748
10749 mTouchWindow->consumeAnyMotionDown();
10750}
10751
10752TEST_F(InputDispatcherUntrustedTouchesTest, WindowWithZeroOpacity_AllowsTouch) {
10753 const sp<FakeWindowHandle>& w =
10754 getOccludingWindow(APP_B_UID, "B", TouchOcclusionMode::BLOCK_UNTRUSTED, 0.0f);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070010755 mDispatcher->onWindowInfosChanged({{*w->getInfo(), *mTouchWindow->getInfo()}, {}, 0, 0});
Bernardo Rufinoc3b7b8c2021-01-29 17:38:07 +000010756
10757 touch();
10758
10759 mTouchWindow->consumeAnyMotionDown();
10760}
10761
Bernardo Rufinoa43a5a42021-02-17 12:21:14 +000010762TEST_F(InputDispatcherUntrustedTouchesTest, WindowWithZeroOpacity_DoesNotReceiveTouch) {
10763 const sp<FakeWindowHandle>& w =
10764 getOccludingWindow(APP_B_UID, "B", TouchOcclusionMode::BLOCK_UNTRUSTED, 0.0f);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070010765 mDispatcher->onWindowInfosChanged({{*w->getInfo(), *mTouchWindow->getInfo()}, {}, 0, 0});
Bernardo Rufinoa43a5a42021-02-17 12:21:14 +000010766
10767 touch();
10768
10769 w->assertNoEvents();
10770}
10771
10772/**
10773 * This is important to make sure apps can't indirectly learn the position of touches (outside vs
10774 * inside) while letting them pass-through. Note that even though touch passes through the occluding
10775 * window, the occluding window will still receive ACTION_OUTSIDE event.
10776 */
10777TEST_F(InputDispatcherUntrustedTouchesTest,
10778 WindowWithZeroOpacityAndWatchOutside_ReceivesOutsideEvent) {
10779 const sp<FakeWindowHandle>& w =
10780 getOccludingWindow(APP_B_UID, "B", TouchOcclusionMode::BLOCK_UNTRUSTED, 0.0f);
Prabir Pradhan4d5c52f2022-01-31 08:52:10 -080010781 w->setWatchOutsideTouch(true);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070010782 mDispatcher->onWindowInfosChanged({{*w->getInfo(), *mTouchWindow->getInfo()}, {}, 0, 0});
Bernardo Rufinoa43a5a42021-02-17 12:21:14 +000010783
10784 touch();
10785
10786 w->consumeMotionOutside();
10787}
10788
10789TEST_F(InputDispatcherUntrustedTouchesTest, OutsideEvent_HasZeroCoordinates) {
10790 const sp<FakeWindowHandle>& w =
10791 getOccludingWindow(APP_B_UID, "B", TouchOcclusionMode::BLOCK_UNTRUSTED, 0.0f);
Prabir Pradhan4d5c52f2022-01-31 08:52:10 -080010792 w->setWatchOutsideTouch(true);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070010793 mDispatcher->onWindowInfosChanged({{*w->getInfo(), *mTouchWindow->getInfo()}, {}, 0, 0});
Bernardo Rufinoa43a5a42021-02-17 12:21:14 +000010794
10795 touch();
10796
Prabir Pradhandfabf8a2022-01-21 08:19:30 -080010797 w->consumeMotionOutsideWithZeroedCoords();
Bernardo Rufinoa43a5a42021-02-17 12:21:14 +000010798}
10799
Bernardo Rufinoc3b7b8c2021-01-29 17:38:07 +000010800TEST_F(InputDispatcherUntrustedTouchesTest, WindowWithOpacityBelowThreshold_AllowsTouch) {
Bernardo Rufino1d0d1f22021-02-12 15:08:43 +000010801 const sp<FakeWindowHandle>& w =
Bernardo Rufino7393d172021-02-26 13:56:11 +000010802 getOccludingWindow(APP_B_UID, "B", TouchOcclusionMode::USE_OPACITY,
10803 OPACITY_BELOW_THRESHOLD);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070010804 mDispatcher->onWindowInfosChanged({{*w->getInfo(), *mTouchWindow->getInfo()}, {}, 0, 0});
Bernardo Rufino1d0d1f22021-02-12 15:08:43 +000010805
10806 touch();
10807
10808 mTouchWindow->consumeAnyMotionDown();
10809}
10810
10811TEST_F(InputDispatcherUntrustedTouchesTest, WindowWithOpacityAtThreshold_AllowsTouch) {
10812 const sp<FakeWindowHandle>& w =
10813 getOccludingWindow(APP_B_UID, "B", TouchOcclusionMode::USE_OPACITY,
10814 MAXIMUM_OBSCURING_OPACITY);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070010815 mDispatcher->onWindowInfosChanged({{*w->getInfo(), *mTouchWindow->getInfo()}, {}, 0, 0});
Bernardo Rufinoc3b7b8c2021-01-29 17:38:07 +000010816
10817 touch();
10818
10819 mTouchWindow->consumeAnyMotionDown();
10820}
10821
10822TEST_F(InputDispatcherUntrustedTouchesTest, WindowWithOpacityAboveThreshold_BlocksTouch) {
Bernardo Rufino1d0d1f22021-02-12 15:08:43 +000010823 const sp<FakeWindowHandle>& w =
Bernardo Rufino7393d172021-02-26 13:56:11 +000010824 getOccludingWindow(APP_B_UID, "B", TouchOcclusionMode::USE_OPACITY,
10825 OPACITY_ABOVE_THRESHOLD);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070010826 mDispatcher->onWindowInfosChanged({{*w->getInfo(), *mTouchWindow->getInfo()}, {}, 0, 0});
Bernardo Rufino1d0d1f22021-02-12 15:08:43 +000010827
10828 touch();
10829
10830 mTouchWindow->assertNoEvents();
10831}
10832
10833TEST_F(InputDispatcherUntrustedTouchesTest, WindowsWithCombinedOpacityAboveThreshold_BlocksTouch) {
10834 // Resulting opacity = 1 - (1 - 0.7)*(1 - 0.7) = .91
10835 const sp<FakeWindowHandle>& w1 =
Bernardo Rufino7393d172021-02-26 13:56:11 +000010836 getOccludingWindow(APP_B_UID, "B1", TouchOcclusionMode::USE_OPACITY,
10837 OPACITY_BELOW_THRESHOLD);
Bernardo Rufino1d0d1f22021-02-12 15:08:43 +000010838 const sp<FakeWindowHandle>& w2 =
Bernardo Rufino7393d172021-02-26 13:56:11 +000010839 getOccludingWindow(APP_B_UID, "B2", TouchOcclusionMode::USE_OPACITY,
10840 OPACITY_BELOW_THRESHOLD);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070010841 mDispatcher->onWindowInfosChanged(
10842 {{*w1->getInfo(), *w2->getInfo(), *mTouchWindow->getInfo()}, {}, 0, 0});
Bernardo Rufino1d0d1f22021-02-12 15:08:43 +000010843
10844 touch();
10845
10846 mTouchWindow->assertNoEvents();
10847}
10848
10849TEST_F(InputDispatcherUntrustedTouchesTest, WindowsWithCombinedOpacityBelowThreshold_AllowsTouch) {
10850 // Resulting opacity = 1 - (1 - 0.5)*(1 - 0.5) = .75
10851 const sp<FakeWindowHandle>& w1 =
Bernardo Rufino7393d172021-02-26 13:56:11 +000010852 getOccludingWindow(APP_B_UID, "B1", TouchOcclusionMode::USE_OPACITY,
10853 OPACITY_FAR_BELOW_THRESHOLD);
Bernardo Rufino1d0d1f22021-02-12 15:08:43 +000010854 const sp<FakeWindowHandle>& w2 =
Bernardo Rufino7393d172021-02-26 13:56:11 +000010855 getOccludingWindow(APP_B_UID, "B2", TouchOcclusionMode::USE_OPACITY,
10856 OPACITY_FAR_BELOW_THRESHOLD);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070010857 mDispatcher->onWindowInfosChanged(
10858 {{*w1->getInfo(), *w2->getInfo(), *mTouchWindow->getInfo()}, {}, 0, 0});
Bernardo Rufino1d0d1f22021-02-12 15:08:43 +000010859
10860 touch();
10861
10862 mTouchWindow->consumeAnyMotionDown();
10863}
10864
10865TEST_F(InputDispatcherUntrustedTouchesTest,
10866 WindowsFromDifferentAppsEachBelowThreshold_AllowsTouch) {
10867 const sp<FakeWindowHandle>& wB =
Bernardo Rufino7393d172021-02-26 13:56:11 +000010868 getOccludingWindow(APP_B_UID, "B", TouchOcclusionMode::USE_OPACITY,
10869 OPACITY_BELOW_THRESHOLD);
Bernardo Rufino1d0d1f22021-02-12 15:08:43 +000010870 const sp<FakeWindowHandle>& wC =
Bernardo Rufino7393d172021-02-26 13:56:11 +000010871 getOccludingWindow(APP_C_UID, "C", TouchOcclusionMode::USE_OPACITY,
10872 OPACITY_BELOW_THRESHOLD);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070010873 mDispatcher->onWindowInfosChanged(
10874 {{*wB->getInfo(), *wC->getInfo(), *mTouchWindow->getInfo()}, {}, 0, 0});
Bernardo Rufino1d0d1f22021-02-12 15:08:43 +000010875
10876 touch();
10877
10878 mTouchWindow->consumeAnyMotionDown();
10879}
10880
10881TEST_F(InputDispatcherUntrustedTouchesTest, WindowsFromDifferentAppsOneAboveThreshold_BlocksTouch) {
10882 const sp<FakeWindowHandle>& wB =
Bernardo Rufino7393d172021-02-26 13:56:11 +000010883 getOccludingWindow(APP_B_UID, "B", TouchOcclusionMode::USE_OPACITY,
10884 OPACITY_BELOW_THRESHOLD);
Bernardo Rufino1d0d1f22021-02-12 15:08:43 +000010885 const sp<FakeWindowHandle>& wC =
Bernardo Rufino7393d172021-02-26 13:56:11 +000010886 getOccludingWindow(APP_C_UID, "C", TouchOcclusionMode::USE_OPACITY,
10887 OPACITY_ABOVE_THRESHOLD);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070010888 mDispatcher->onWindowInfosChanged(
10889 {{*wB->getInfo(), *wC->getInfo(), *mTouchWindow->getInfo()}, {}, 0, 0});
Bernardo Rufinoc3b7b8c2021-01-29 17:38:07 +000010890
10891 touch();
10892
10893 mTouchWindow->assertNoEvents();
10894}
10895
Bernardo Rufino6d52e542021-02-15 18:38:10 +000010896TEST_F(InputDispatcherUntrustedTouchesTest,
10897 WindowWithOpacityAboveThresholdAndSelfWindow_BlocksTouch) {
10898 const sp<FakeWindowHandle>& wA =
Bernardo Rufino7393d172021-02-26 13:56:11 +000010899 getOccludingWindow(TOUCHED_APP_UID, "T", TouchOcclusionMode::USE_OPACITY,
10900 OPACITY_BELOW_THRESHOLD);
Bernardo Rufino6d52e542021-02-15 18:38:10 +000010901 const sp<FakeWindowHandle>& wB =
Bernardo Rufino7393d172021-02-26 13:56:11 +000010902 getOccludingWindow(APP_B_UID, "B", TouchOcclusionMode::USE_OPACITY,
10903 OPACITY_ABOVE_THRESHOLD);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070010904 mDispatcher->onWindowInfosChanged(
10905 {{*wA->getInfo(), *wB->getInfo(), *mTouchWindow->getInfo()}, {}, 0, 0});
Bernardo Rufino6d52e542021-02-15 18:38:10 +000010906
10907 touch();
10908
10909 mTouchWindow->assertNoEvents();
10910}
10911
10912TEST_F(InputDispatcherUntrustedTouchesTest,
10913 WindowWithOpacityBelowThresholdAndSelfWindow_AllowsTouch) {
10914 const sp<FakeWindowHandle>& wA =
Bernardo Rufino7393d172021-02-26 13:56:11 +000010915 getOccludingWindow(TOUCHED_APP_UID, "T", TouchOcclusionMode::USE_OPACITY,
10916 OPACITY_ABOVE_THRESHOLD);
Bernardo Rufino6d52e542021-02-15 18:38:10 +000010917 const sp<FakeWindowHandle>& wB =
Bernardo Rufino7393d172021-02-26 13:56:11 +000010918 getOccludingWindow(APP_B_UID, "B", TouchOcclusionMode::USE_OPACITY,
10919 OPACITY_BELOW_THRESHOLD);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070010920 mDispatcher->onWindowInfosChanged(
10921 {{*wA->getInfo(), *wB->getInfo(), *mTouchWindow->getInfo()}, {}, 0, 0});
Bernardo Rufino6d52e542021-02-15 18:38:10 +000010922
10923 touch();
10924
10925 mTouchWindow->consumeAnyMotionDown();
10926}
10927
10928TEST_F(InputDispatcherUntrustedTouchesTest, SelfWindowWithOpacityAboveThreshold_AllowsTouch) {
10929 const sp<FakeWindowHandle>& w =
Bernardo Rufino7393d172021-02-26 13:56:11 +000010930 getOccludingWindow(TOUCHED_APP_UID, "T", TouchOcclusionMode::USE_OPACITY,
10931 OPACITY_ABOVE_THRESHOLD);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070010932 mDispatcher->onWindowInfosChanged({{*w->getInfo(), *mTouchWindow->getInfo()}, {}, 0, 0});
Bernardo Rufino6d52e542021-02-15 18:38:10 +000010933
10934 touch();
10935
10936 mTouchWindow->consumeAnyMotionDown();
10937}
10938
10939TEST_F(InputDispatcherUntrustedTouchesTest, SelfWindowWithBlockUntrustedMode_AllowsTouch) {
10940 const sp<FakeWindowHandle>& w =
10941 getOccludingWindow(TOUCHED_APP_UID, "T", TouchOcclusionMode::BLOCK_UNTRUSTED);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070010942 mDispatcher->onWindowInfosChanged({{*w->getInfo(), *mTouchWindow->getInfo()}, {}, 0, 0});
Bernardo Rufino6d52e542021-02-15 18:38:10 +000010943
10944 touch();
10945
10946 mTouchWindow->consumeAnyMotionDown();
10947}
10948
Bernardo Rufinoccd3dd62021-02-15 18:47:42 +000010949TEST_F(InputDispatcherUntrustedTouchesTest,
10950 OpacityThresholdIs0AndWindowAboveThreshold_BlocksTouch) {
10951 mDispatcher->setMaximumObscuringOpacityForTouch(0.0f);
10952 const sp<FakeWindowHandle>& w =
10953 getOccludingWindow(APP_B_UID, "B", TouchOcclusionMode::USE_OPACITY, 0.1f);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070010954 mDispatcher->onWindowInfosChanged({{*w->getInfo(), *mTouchWindow->getInfo()}, {}, 0, 0});
Bernardo Rufinoccd3dd62021-02-15 18:47:42 +000010955
10956 touch();
10957
10958 mTouchWindow->assertNoEvents();
10959}
10960
10961TEST_F(InputDispatcherUntrustedTouchesTest, OpacityThresholdIs0AndWindowAtThreshold_AllowsTouch) {
10962 mDispatcher->setMaximumObscuringOpacityForTouch(0.0f);
10963 const sp<FakeWindowHandle>& w =
10964 getOccludingWindow(APP_B_UID, "B", TouchOcclusionMode::USE_OPACITY, 0.0f);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070010965 mDispatcher->onWindowInfosChanged({{*w->getInfo(), *mTouchWindow->getInfo()}, {}, 0, 0});
Bernardo Rufinoccd3dd62021-02-15 18:47:42 +000010966
10967 touch();
10968
10969 mTouchWindow->consumeAnyMotionDown();
10970}
10971
10972TEST_F(InputDispatcherUntrustedTouchesTest,
10973 OpacityThresholdIs1AndWindowBelowThreshold_AllowsTouch) {
10974 mDispatcher->setMaximumObscuringOpacityForTouch(1.0f);
10975 const sp<FakeWindowHandle>& w =
Bernardo Rufino7393d172021-02-26 13:56:11 +000010976 getOccludingWindow(APP_B_UID, "B", TouchOcclusionMode::USE_OPACITY,
10977 OPACITY_ABOVE_THRESHOLD);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070010978 mDispatcher->onWindowInfosChanged({{*w->getInfo(), *mTouchWindow->getInfo()}, {}, 0, 0});
Bernardo Rufino7393d172021-02-26 13:56:11 +000010979
10980 touch();
10981
10982 mTouchWindow->consumeAnyMotionDown();
10983}
10984
10985TEST_F(InputDispatcherUntrustedTouchesTest,
10986 WindowWithBlockUntrustedModeAndWindowWithOpacityBelowFromSameApp_BlocksTouch) {
10987 const sp<FakeWindowHandle>& w1 =
10988 getOccludingWindow(APP_B_UID, "B", TouchOcclusionMode::BLOCK_UNTRUSTED,
10989 OPACITY_BELOW_THRESHOLD);
10990 const sp<FakeWindowHandle>& w2 =
10991 getOccludingWindow(APP_B_UID, "B", TouchOcclusionMode::USE_OPACITY,
10992 OPACITY_BELOW_THRESHOLD);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070010993 mDispatcher->onWindowInfosChanged(
10994 {{*w1->getInfo(), *w2->getInfo(), *mTouchWindow->getInfo()}, {}, 0, 0});
Bernardo Rufino7393d172021-02-26 13:56:11 +000010995
10996 touch();
10997
10998 mTouchWindow->assertNoEvents();
10999}
11000
11001/**
11002 * Window B of BLOCK_UNTRUSTED occlusion mode is enough to block the touch, we're testing that the
11003 * addition of another window (C) of USE_OPACITY occlusion mode and opacity below the threshold
11004 * (which alone would result in allowing touches) does not affect the blocking behavior.
11005 */
11006TEST_F(InputDispatcherUntrustedTouchesTest,
11007 WindowWithBlockUntrustedModeAndWindowWithOpacityBelowFromDifferentApps_BlocksTouch) {
11008 const sp<FakeWindowHandle>& wB =
11009 getOccludingWindow(APP_B_UID, "B", TouchOcclusionMode::BLOCK_UNTRUSTED,
11010 OPACITY_BELOW_THRESHOLD);
11011 const sp<FakeWindowHandle>& wC =
11012 getOccludingWindow(APP_C_UID, "C", TouchOcclusionMode::USE_OPACITY,
11013 OPACITY_BELOW_THRESHOLD);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070011014 mDispatcher->onWindowInfosChanged(
11015 {{*wB->getInfo(), *wC->getInfo(), *mTouchWindow->getInfo()}, {}, 0, 0});
Bernardo Rufino7393d172021-02-26 13:56:11 +000011016
11017 touch();
11018
11019 mTouchWindow->assertNoEvents();
11020}
11021
11022/**
11023 * This test is testing that a window from a different UID but with same application token doesn't
11024 * block the touch. Apps can share the application token for close UI collaboration for example.
11025 */
11026TEST_F(InputDispatcherUntrustedTouchesTest,
11027 WindowWithSameApplicationTokenFromDifferentApp_AllowsTouch) {
11028 const sp<FakeWindowHandle>& w =
11029 getOccludingWindow(APP_B_UID, "B", TouchOcclusionMode::BLOCK_UNTRUSTED);
11030 w->setApplicationToken(mTouchWindow->getApplicationToken());
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070011031 mDispatcher->onWindowInfosChanged({{*w->getInfo(), *mTouchWindow->getInfo()}, {}, 0, 0});
Bernardo Rufinoccd3dd62021-02-15 18:47:42 +000011032
11033 touch();
11034
11035 mTouchWindow->consumeAnyMotionDown();
11036}
11037
arthurhungb89ccb02020-12-30 16:19:01 +080011038class InputDispatcherDragTests : public InputDispatcherTest {
11039protected:
11040 std::shared_ptr<FakeApplicationHandle> mApp;
11041 sp<FakeWindowHandle> mWindow;
11042 sp<FakeWindowHandle> mSecondWindow;
11043 sp<FakeWindowHandle> mDragWindow;
Vaibhav Devmurari6abcf8f2022-06-06 10:08:05 +000011044 sp<FakeWindowHandle> mSpyWindow;
Arthur Hungb75c2aa2022-07-15 09:35:36 +000011045 // Mouse would force no-split, set the id as non-zero to verify if drag state could track it.
11046 static constexpr int32_t MOUSE_POINTER_ID = 1;
arthurhungb89ccb02020-12-30 16:19:01 +080011047
11048 void SetUp() override {
11049 InputDispatcherTest::SetUp();
11050 mApp = std::make_shared<FakeApplicationHandle>();
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -070011051 mWindow = sp<FakeWindowHandle>::make(mApp, mDispatcher, "TestWindow", ADISPLAY_ID_DEFAULT);
arthurhungb89ccb02020-12-30 16:19:01 +080011052 mWindow->setFrame(Rect(0, 0, 100, 100));
arthurhungb89ccb02020-12-30 16:19:01 +080011053
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -070011054 mSecondWindow =
11055 sp<FakeWindowHandle>::make(mApp, mDispatcher, "TestWindow2", ADISPLAY_ID_DEFAULT);
arthurhungb89ccb02020-12-30 16:19:01 +080011056 mSecondWindow->setFrame(Rect(100, 0, 200, 100));
arthurhungb89ccb02020-12-30 16:19:01 +080011057
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -070011058 mSpyWindow =
11059 sp<FakeWindowHandle>::make(mApp, mDispatcher, "SpyWindow", ADISPLAY_ID_DEFAULT);
Vaibhav Devmurari6abcf8f2022-06-06 10:08:05 +000011060 mSpyWindow->setSpy(true);
11061 mSpyWindow->setTrustedOverlay(true);
11062 mSpyWindow->setFrame(Rect(0, 0, 200, 100));
11063
arthurhungb89ccb02020-12-30 16:19:01 +080011064 mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, mApp);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070011065 mDispatcher->onWindowInfosChanged(
11066 {{*mSpyWindow->getInfo(), *mWindow->getInfo(), *mSecondWindow->getInfo()},
11067 {},
11068 0,
11069 0});
arthurhungb89ccb02020-12-30 16:19:01 +080011070 }
11071
Arthur Hungb75c2aa2022-07-15 09:35:36 +000011072 void injectDown(int fromSource = AINPUT_SOURCE_TOUCHSCREEN) {
11073 switch (fromSource) {
11074 case AINPUT_SOURCE_TOUCHSCREEN:
11075 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070011076 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN,
Arthur Hungb75c2aa2022-07-15 09:35:36 +000011077 ADISPLAY_ID_DEFAULT, {50, 50}))
11078 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
11079 break;
11080 case AINPUT_SOURCE_STYLUS:
11081 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070011082 injectMotionEvent(*mDispatcher,
11083 MotionEventBuilder(AMOTION_EVENT_ACTION_DOWN,
11084 AINPUT_SOURCE_STYLUS)
11085 .buttonState(
11086 AMOTION_EVENT_BUTTON_STYLUS_PRIMARY)
11087 .pointer(PointerBuilder(0, ToolType::STYLUS)
11088 .x(50)
11089 .y(50))
11090 .build()));
Arthur Hungb75c2aa2022-07-15 09:35:36 +000011091 break;
11092 case AINPUT_SOURCE_MOUSE:
11093 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070011094 injectMotionEvent(*mDispatcher,
11095 MotionEventBuilder(AMOTION_EVENT_ACTION_DOWN,
11096 AINPUT_SOURCE_MOUSE)
11097 .buttonState(AMOTION_EVENT_BUTTON_PRIMARY)
11098 .pointer(PointerBuilder(MOUSE_POINTER_ID,
11099 ToolType::MOUSE)
11100 .x(50)
11101 .y(50))
11102 .build()));
Arthur Hungb75c2aa2022-07-15 09:35:36 +000011103 break;
11104 default:
11105 FAIL() << "Source " << fromSource << " doesn't support drag and drop";
11106 }
arthurhungb89ccb02020-12-30 16:19:01 +080011107
11108 // Window should receive motion event.
11109 mWindow->consumeMotionDown(ADISPLAY_ID_DEFAULT);
Vaibhav Devmurari6abcf8f2022-06-06 10:08:05 +000011110 // Spy window should also receive motion event
11111 mSpyWindow->consumeMotionDown(ADISPLAY_ID_DEFAULT);
Arthur Hung54745652022-04-20 07:17:41 +000011112 }
11113
11114 // Start performing drag, we will create a drag window and transfer touch to it.
11115 // @param sendDown : if true, send a motion down on first window before perform drag and drop.
11116 // Returns true on success.
Arthur Hungb75c2aa2022-07-15 09:35:36 +000011117 bool startDrag(bool sendDown = true, int fromSource = AINPUT_SOURCE_TOUCHSCREEN) {
Arthur Hung54745652022-04-20 07:17:41 +000011118 if (sendDown) {
Arthur Hungb75c2aa2022-07-15 09:35:36 +000011119 injectDown(fromSource);
Arthur Hung54745652022-04-20 07:17:41 +000011120 }
arthurhungb89ccb02020-12-30 16:19:01 +080011121
11122 // The drag window covers the entire display
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -070011123 mDragWindow =
11124 sp<FakeWindowHandle>::make(mApp, mDispatcher, "DragWindow", ADISPLAY_ID_DEFAULT);
Vaibhav Devmurari6abcf8f2022-06-06 10:08:05 +000011125 mDragWindow->setTouchableRegion(Region{{0, 0, 0, 0}});
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070011126 mDispatcher->onWindowInfosChanged({{*mDragWindow->getInfo(), *mSpyWindow->getInfo(),
11127 *mWindow->getInfo(), *mSecondWindow->getInfo()},
11128 {},
11129 0,
11130 0});
arthurhungb89ccb02020-12-30 16:19:01 +080011131
11132 // Transfer touch focus to the drag window
Arthur Hung54745652022-04-20 07:17:41 +000011133 bool transferred =
Prabir Pradhan367f3432024-02-13 23:05:58 +000011134 mDispatcher->transferTouchGesture(mWindow->getToken(), mDragWindow->getToken(),
11135 /*isDragDrop=*/true);
Arthur Hung54745652022-04-20 07:17:41 +000011136 if (transferred) {
11137 mWindow->consumeMotionCancel();
Prabir Pradhan65455c72024-02-13 21:46:41 +000011138 mDragWindow->consumeMotionDown(ADISPLAY_ID_DEFAULT, AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
Arthur Hung54745652022-04-20 07:17:41 +000011139 }
11140 return transferred;
arthurhungb89ccb02020-12-30 16:19:01 +080011141 }
11142};
11143
11144TEST_F(InputDispatcherDragTests, DragEnterAndDragExit) {
Arthur Hungb75c2aa2022-07-15 09:35:36 +000011145 startDrag();
arthurhungb89ccb02020-12-30 16:19:01 +080011146
11147 // Move on window.
11148 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070011149 injectMotionEvent(*mDispatcher, AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN,
arthurhungb89ccb02020-12-30 16:19:01 +080011150 ADISPLAY_ID_DEFAULT, {50, 50}))
11151 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
Prabir Pradhan65455c72024-02-13 21:46:41 +000011152 mDragWindow->consumeMotionMove(ADISPLAY_ID_DEFAULT, AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
arthurhungb89ccb02020-12-30 16:19:01 +080011153 mWindow->consumeDragEvent(false, 50, 50);
11154 mSecondWindow->assertNoEvents();
11155
11156 // Move to another window.
11157 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070011158 injectMotionEvent(*mDispatcher, AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN,
arthurhungb89ccb02020-12-30 16:19:01 +080011159 ADISPLAY_ID_DEFAULT, {150, 50}))
11160 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
Prabir Pradhan65455c72024-02-13 21:46:41 +000011161 mDragWindow->consumeMotionMove(ADISPLAY_ID_DEFAULT, AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
arthurhungb89ccb02020-12-30 16:19:01 +080011162 mWindow->consumeDragEvent(true, 150, 50);
11163 mSecondWindow->consumeDragEvent(false, 50, 50);
11164
11165 // Move back to original window.
11166 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070011167 injectMotionEvent(*mDispatcher, AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN,
arthurhungb89ccb02020-12-30 16:19:01 +080011168 ADISPLAY_ID_DEFAULT, {50, 50}))
11169 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
Prabir Pradhan65455c72024-02-13 21:46:41 +000011170 mDragWindow->consumeMotionMove(ADISPLAY_ID_DEFAULT, AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
arthurhungb89ccb02020-12-30 16:19:01 +080011171 mWindow->consumeDragEvent(false, 50, 50);
11172 mSecondWindow->consumeDragEvent(true, -50, 50);
11173
11174 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070011175 injectMotionUp(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
11176 {50, 50}))
arthurhungb89ccb02020-12-30 16:19:01 +080011177 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
Prabir Pradhan65455c72024-02-13 21:46:41 +000011178 mDragWindow->consumeMotionUp(ADISPLAY_ID_DEFAULT, AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
arthurhungb89ccb02020-12-30 16:19:01 +080011179 mWindow->assertNoEvents();
11180 mSecondWindow->assertNoEvents();
11181}
11182
Vaibhav Devmurari6abcf8f2022-06-06 10:08:05 +000011183TEST_F(InputDispatcherDragTests, DragEnterAndPointerDownPilfersPointers) {
Arthur Hungb75c2aa2022-07-15 09:35:36 +000011184 startDrag();
Vaibhav Devmurari6abcf8f2022-06-06 10:08:05 +000011185
11186 // No cancel event after drag start
11187 mSpyWindow->assertNoEvents();
11188
11189 const MotionEvent secondFingerDownEvent =
11190 MotionEventBuilder(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
11191 .eventTime(systemTime(SYSTEM_TIME_MONOTONIC))
Siarhei Vishniakou6d73f832022-07-21 17:27:03 -070011192 .pointer(PointerBuilder(/*id=*/0, ToolType::FINGER).x(50).y(50))
11193 .pointer(PointerBuilder(/*id=*/1, ToolType::FINGER).x(60).y(60))
Vaibhav Devmurari6abcf8f2022-06-06 10:08:05 +000011194 .build();
11195 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070011196 injectMotionEvent(*mDispatcher, secondFingerDownEvent, INJECT_EVENT_TIMEOUT,
Vaibhav Devmurari6abcf8f2022-06-06 10:08:05 +000011197 InputEventInjectionSync::WAIT_FOR_RESULT))
11198 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
11199
11200 // Receives cancel for first pointer after next pointer down
11201 mSpyWindow->consumeMotionCancel();
11202 mSpyWindow->consumeMotionDown();
11203
11204 mSpyWindow->assertNoEvents();
11205}
11206
arthurhungf452d0b2021-01-06 00:19:52 +080011207TEST_F(InputDispatcherDragTests, DragAndDrop) {
Arthur Hungb75c2aa2022-07-15 09:35:36 +000011208 startDrag();
arthurhungf452d0b2021-01-06 00:19:52 +080011209
11210 // Move on window.
11211 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070011212 injectMotionEvent(*mDispatcher, AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN,
arthurhungf452d0b2021-01-06 00:19:52 +080011213 ADISPLAY_ID_DEFAULT, {50, 50}))
11214 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
Prabir Pradhan65455c72024-02-13 21:46:41 +000011215 mDragWindow->consumeMotionMove(ADISPLAY_ID_DEFAULT, AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
arthurhungf452d0b2021-01-06 00:19:52 +080011216 mWindow->consumeDragEvent(false, 50, 50);
11217 mSecondWindow->assertNoEvents();
11218
11219 // Move to another window.
11220 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070011221 injectMotionEvent(*mDispatcher, AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN,
arthurhungf452d0b2021-01-06 00:19:52 +080011222 ADISPLAY_ID_DEFAULT, {150, 50}))
11223 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
Prabir Pradhan65455c72024-02-13 21:46:41 +000011224 mDragWindow->consumeMotionMove(ADISPLAY_ID_DEFAULT, AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
arthurhungf452d0b2021-01-06 00:19:52 +080011225 mWindow->consumeDragEvent(true, 150, 50);
11226 mSecondWindow->consumeDragEvent(false, 50, 50);
11227
11228 // drop to another window.
11229 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070011230 injectMotionUp(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
arthurhungf452d0b2021-01-06 00:19:52 +080011231 {150, 50}))
11232 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
Prabir Pradhan65455c72024-02-13 21:46:41 +000011233 mDragWindow->consumeMotionUp(ADISPLAY_ID_DEFAULT, AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
Siarhei Vishniakoua66d65e2023-06-16 10:32:51 -070011234 mFakePolicy->assertDropTargetEquals(*mDispatcher, mSecondWindow->getToken());
arthurhungf452d0b2021-01-06 00:19:52 +080011235 mWindow->assertNoEvents();
11236 mSecondWindow->assertNoEvents();
11237}
11238
Vaibhav Devmurari110ba322023-11-17 10:47:16 +000011239TEST_F(InputDispatcherDragTests, DragAndDropNotCancelledIfSomeOtherPointerIsPilfered) {
11240 startDrag();
11241
11242 // No cancel event after drag start
11243 mSpyWindow->assertNoEvents();
11244
11245 const MotionEvent secondFingerDownEvent =
11246 MotionEventBuilder(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
11247 .eventTime(systemTime(SYSTEM_TIME_MONOTONIC))
11248 .pointer(PointerBuilder(/*id=*/0, ToolType::FINGER).x(50).y(50))
11249 .pointer(PointerBuilder(/*id=*/1, ToolType::FINGER).x(60).y(60))
11250 .build();
11251 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
11252 injectMotionEvent(*mDispatcher, secondFingerDownEvent, INJECT_EVENT_TIMEOUT,
11253 InputEventInjectionSync::WAIT_FOR_RESULT))
11254 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
11255
11256 // Receives cancel for first pointer after next pointer down
11257 mSpyWindow->consumeMotionEvent(WithMotionAction(ACTION_CANCEL));
Siarhei Vishniakou1ff00cc2023-12-13 16:12:13 -080011258 mSpyWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithPointerIds({1})));
Vaibhav Devmurari110ba322023-11-17 10:47:16 +000011259 mDragWindow->consumeMotionEvent(WithMotionAction(ACTION_MOVE));
11260
11261 mSpyWindow->assertNoEvents();
11262
11263 // Spy window calls pilfer pointers
11264 EXPECT_EQ(OK, mDispatcher->pilferPointers(mSpyWindow->getToken()));
11265 mDragWindow->assertNoEvents();
11266
11267 const MotionEvent firstFingerMoveEvent =
Siarhei Vishniakou96a15572023-12-18 10:47:52 -080011268 MotionEventBuilder(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN)
Vaibhav Devmurari110ba322023-11-17 10:47:16 +000011269 .eventTime(systemTime(SYSTEM_TIME_MONOTONIC))
11270 .pointer(PointerBuilder(/*id=*/0, ToolType::FINGER).x(60).y(60))
11271 .pointer(PointerBuilder(/*id=*/1, ToolType::FINGER).x(60).y(60))
11272 .build();
11273 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakou96a15572023-12-18 10:47:52 -080011274 injectMotionEvent(*mDispatcher, firstFingerMoveEvent, INJECT_EVENT_TIMEOUT,
Vaibhav Devmurari110ba322023-11-17 10:47:16 +000011275 InputEventInjectionSync::WAIT_FOR_RESULT))
11276 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
11277
11278 // Drag window should still receive the new event
Prabir Pradhan65455c72024-02-13 21:46:41 +000011279 mDragWindow->consumeMotionEvent(
11280 AllOf(WithMotionAction(ACTION_MOVE), WithFlags(AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE)));
Vaibhav Devmurari110ba322023-11-17 10:47:16 +000011281 mDragWindow->assertNoEvents();
11282}
11283
arthurhung6d4bed92021-03-17 11:59:33 +080011284TEST_F(InputDispatcherDragTests, StylusDragAndDrop) {
Arthur Hungb75c2aa2022-07-15 09:35:36 +000011285 startDrag(true, AINPUT_SOURCE_STYLUS);
arthurhung6d4bed92021-03-17 11:59:33 +080011286
11287 // Move on window and keep button pressed.
11288 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070011289 injectMotionEvent(*mDispatcher,
arthurhung6d4bed92021-03-17 11:59:33 +080011290 MotionEventBuilder(AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_STYLUS)
11291 .buttonState(AMOTION_EVENT_BUTTON_STYLUS_PRIMARY)
Siarhei Vishniakou6d73f832022-07-21 17:27:03 -070011292 .pointer(PointerBuilder(0, ToolType::STYLUS).x(50).y(50))
arthurhung6d4bed92021-03-17 11:59:33 +080011293 .build()))
11294 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
Prabir Pradhan65455c72024-02-13 21:46:41 +000011295 mDragWindow->consumeMotionMove(ADISPLAY_ID_DEFAULT, AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
arthurhung6d4bed92021-03-17 11:59:33 +080011296 mWindow->consumeDragEvent(false, 50, 50);
11297 mSecondWindow->assertNoEvents();
11298
11299 // Move to another window and release button, expect to drop item.
11300 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070011301 injectMotionEvent(*mDispatcher,
arthurhung6d4bed92021-03-17 11:59:33 +080011302 MotionEventBuilder(AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_STYLUS)
11303 .buttonState(0)
Siarhei Vishniakou6d73f832022-07-21 17:27:03 -070011304 .pointer(PointerBuilder(0, ToolType::STYLUS).x(150).y(50))
arthurhung6d4bed92021-03-17 11:59:33 +080011305 .build()))
11306 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
Prabir Pradhan65455c72024-02-13 21:46:41 +000011307 mDragWindow->consumeMotionMove(ADISPLAY_ID_DEFAULT, AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
arthurhung6d4bed92021-03-17 11:59:33 +080011308 mWindow->assertNoEvents();
11309 mSecondWindow->assertNoEvents();
Siarhei Vishniakoua66d65e2023-06-16 10:32:51 -070011310 mFakePolicy->assertDropTargetEquals(*mDispatcher, mSecondWindow->getToken());
arthurhung6d4bed92021-03-17 11:59:33 +080011311
11312 // nothing to the window.
11313 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070011314 injectMotionEvent(*mDispatcher,
arthurhung6d4bed92021-03-17 11:59:33 +080011315 MotionEventBuilder(AMOTION_EVENT_ACTION_UP, AINPUT_SOURCE_STYLUS)
11316 .buttonState(0)
Siarhei Vishniakou6d73f832022-07-21 17:27:03 -070011317 .pointer(PointerBuilder(0, ToolType::STYLUS).x(150).y(50))
arthurhung6d4bed92021-03-17 11:59:33 +080011318 .build()))
11319 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
Prabir Pradhan65455c72024-02-13 21:46:41 +000011320 mDragWindow->consumeMotionUp(ADISPLAY_ID_DEFAULT, AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
arthurhung6d4bed92021-03-17 11:59:33 +080011321 mWindow->assertNoEvents();
11322 mSecondWindow->assertNoEvents();
11323}
11324
Arthur Hung54745652022-04-20 07:17:41 +000011325TEST_F(InputDispatcherDragTests, DragAndDropOnInvalidWindow) {
Arthur Hungb75c2aa2022-07-15 09:35:36 +000011326 startDrag();
Arthur Hung6d0571e2021-04-09 20:18:16 +080011327
11328 // Set second window invisible.
11329 mSecondWindow->setVisible(false);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070011330 mDispatcher->onWindowInfosChanged(
11331 {{*mDragWindow->getInfo(), *mWindow->getInfo(), *mSecondWindow->getInfo()}, {}, 0, 0});
Arthur Hung6d0571e2021-04-09 20:18:16 +080011332
11333 // Move on window.
11334 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070011335 injectMotionEvent(*mDispatcher, AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN,
Arthur Hung6d0571e2021-04-09 20:18:16 +080011336 ADISPLAY_ID_DEFAULT, {50, 50}))
11337 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
Prabir Pradhan65455c72024-02-13 21:46:41 +000011338 mDragWindow->consumeMotionMove(ADISPLAY_ID_DEFAULT, AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
Arthur Hung6d0571e2021-04-09 20:18:16 +080011339 mWindow->consumeDragEvent(false, 50, 50);
11340 mSecondWindow->assertNoEvents();
11341
11342 // Move to another window.
11343 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070011344 injectMotionEvent(*mDispatcher, AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN,
Arthur Hung6d0571e2021-04-09 20:18:16 +080011345 ADISPLAY_ID_DEFAULT, {150, 50}))
11346 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
Prabir Pradhan65455c72024-02-13 21:46:41 +000011347 mDragWindow->consumeMotionMove(ADISPLAY_ID_DEFAULT, AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
Arthur Hung6d0571e2021-04-09 20:18:16 +080011348 mWindow->consumeDragEvent(true, 150, 50);
11349 mSecondWindow->assertNoEvents();
11350
11351 // drop to another window.
11352 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070011353 injectMotionUp(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
Arthur Hung6d0571e2021-04-09 20:18:16 +080011354 {150, 50}))
11355 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
Prabir Pradhan65455c72024-02-13 21:46:41 +000011356 mDragWindow->consumeMotionUp(ADISPLAY_ID_DEFAULT, AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
Siarhei Vishniakoua66d65e2023-06-16 10:32:51 -070011357 mFakePolicy->assertDropTargetEquals(*mDispatcher, nullptr);
Arthur Hung6d0571e2021-04-09 20:18:16 +080011358 mWindow->assertNoEvents();
11359 mSecondWindow->assertNoEvents();
11360}
11361
Arthur Hung54745652022-04-20 07:17:41 +000011362TEST_F(InputDispatcherDragTests, NoDragAndDropWhenMultiFingers) {
Arthur Hungb75c2aa2022-07-15 09:35:36 +000011363 // Ensure window could track pointerIds if it didn't support split touch.
11364 mWindow->setPreventSplitting(true);
11365
Arthur Hung54745652022-04-20 07:17:41 +000011366 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070011367 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
Arthur Hung54745652022-04-20 07:17:41 +000011368 {50, 50}))
11369 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
11370 mWindow->consumeMotionDown(ADISPLAY_ID_DEFAULT);
11371
11372 const MotionEvent secondFingerDownEvent =
11373 MotionEventBuilder(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
11374 .displayId(ADISPLAY_ID_DEFAULT)
11375 .eventTime(systemTime(SYSTEM_TIME_MONOTONIC))
Siarhei Vishniakou6d73f832022-07-21 17:27:03 -070011376 .pointer(PointerBuilder(/*id=*/0, ToolType::FINGER).x(50).y(50))
11377 .pointer(PointerBuilder(/*id=*/1, ToolType::FINGER).x(75).y(50))
Arthur Hung54745652022-04-20 07:17:41 +000011378 .build();
11379 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070011380 injectMotionEvent(*mDispatcher, secondFingerDownEvent, INJECT_EVENT_TIMEOUT,
Arthur Hung54745652022-04-20 07:17:41 +000011381 InputEventInjectionSync::WAIT_FOR_RESULT))
11382 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
Harry Cutts33476232023-01-30 19:57:29 +000011383 mWindow->consumeMotionPointerDown(/*pointerIndex=*/1);
Arthur Hung54745652022-04-20 07:17:41 +000011384
11385 // Should not perform drag and drop when window has multi fingers.
Arthur Hungb75c2aa2022-07-15 09:35:36 +000011386 ASSERT_FALSE(startDrag(false));
Arthur Hung54745652022-04-20 07:17:41 +000011387}
11388
11389TEST_F(InputDispatcherDragTests, DragAndDropWhenSplitTouch) {
11390 // First down on second window.
11391 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070011392 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
Arthur Hung54745652022-04-20 07:17:41 +000011393 {150, 50}))
11394 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
11395
11396 mSecondWindow->consumeMotionDown(ADISPLAY_ID_DEFAULT);
11397
11398 // Second down on first window.
11399 const MotionEvent secondFingerDownEvent =
11400 MotionEventBuilder(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
11401 .displayId(ADISPLAY_ID_DEFAULT)
11402 .eventTime(systemTime(SYSTEM_TIME_MONOTONIC))
Siarhei Vishniakou6d73f832022-07-21 17:27:03 -070011403 .pointer(PointerBuilder(/*id=*/0, ToolType::FINGER).x(150).y(50))
11404 .pointer(PointerBuilder(/*id=*/1, ToolType::FINGER).x(50).y(50))
Arthur Hung54745652022-04-20 07:17:41 +000011405 .build();
11406 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070011407 injectMotionEvent(*mDispatcher, secondFingerDownEvent, INJECT_EVENT_TIMEOUT,
Arthur Hung54745652022-04-20 07:17:41 +000011408 InputEventInjectionSync::WAIT_FOR_RESULT))
11409 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
11410 mWindow->consumeMotionDown(ADISPLAY_ID_DEFAULT);
Prabir Pradhan9d5f9ce2024-01-24 00:03:41 +000011411 mSecondWindow->consumeMotionMove(ADISPLAY_ID_DEFAULT);
Arthur Hung54745652022-04-20 07:17:41 +000011412
11413 // Perform drag and drop from first window.
Arthur Hungb75c2aa2022-07-15 09:35:36 +000011414 ASSERT_TRUE(startDrag(false));
Arthur Hung54745652022-04-20 07:17:41 +000011415
11416 // Move on window.
11417 const MotionEvent secondFingerMoveEvent =
11418 MotionEventBuilder(AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN)
11419 .eventTime(systemTime(SYSTEM_TIME_MONOTONIC))
Siarhei Vishniakou6d73f832022-07-21 17:27:03 -070011420 .pointer(PointerBuilder(/*id=*/0, ToolType::FINGER).x(150).y(50))
11421 .pointer(PointerBuilder(/*id=*/1, ToolType::FINGER).x(50).y(50))
Arthur Hung54745652022-04-20 07:17:41 +000011422 .build();
11423 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070011424 injectMotionEvent(*mDispatcher, secondFingerMoveEvent, INJECT_EVENT_TIMEOUT,
Arthur Hung54745652022-04-20 07:17:41 +000011425 InputEventInjectionSync::WAIT_FOR_RESULT));
Prabir Pradhan65455c72024-02-13 21:46:41 +000011426 mDragWindow->consumeMotionMove(ADISPLAY_ID_DEFAULT, AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
Arthur Hung54745652022-04-20 07:17:41 +000011427 mWindow->consumeDragEvent(false, 50, 50);
11428 mSecondWindow->consumeMotionMove();
11429
11430 // Release the drag pointer should perform drop.
11431 const MotionEvent secondFingerUpEvent =
11432 MotionEventBuilder(POINTER_1_UP, AINPUT_SOURCE_TOUCHSCREEN)
11433 .eventTime(systemTime(SYSTEM_TIME_MONOTONIC))
Siarhei Vishniakou6d73f832022-07-21 17:27:03 -070011434 .pointer(PointerBuilder(/*id=*/0, ToolType::FINGER).x(150).y(50))
11435 .pointer(PointerBuilder(/*id=*/1, ToolType::FINGER).x(50).y(50))
Arthur Hung54745652022-04-20 07:17:41 +000011436 .build();
11437 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070011438 injectMotionEvent(*mDispatcher, secondFingerUpEvent, INJECT_EVENT_TIMEOUT,
Arthur Hung54745652022-04-20 07:17:41 +000011439 InputEventInjectionSync::WAIT_FOR_RESULT));
Prabir Pradhan65455c72024-02-13 21:46:41 +000011440 mDragWindow->consumeMotionUp(ADISPLAY_ID_DEFAULT, AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
Siarhei Vishniakoua66d65e2023-06-16 10:32:51 -070011441 mFakePolicy->assertDropTargetEquals(*mDispatcher, mWindow->getToken());
Arthur Hung54745652022-04-20 07:17:41 +000011442 mWindow->assertNoEvents();
11443 mSecondWindow->consumeMotionMove();
11444}
11445
Arthur Hung3915c1f2022-05-31 07:17:17 +000011446TEST_F(InputDispatcherDragTests, DragAndDropWhenMultiDisplays) {
Arthur Hungb75c2aa2022-07-15 09:35:36 +000011447 startDrag();
Arthur Hung3915c1f2022-05-31 07:17:17 +000011448
11449 // Update window of second display.
11450 sp<FakeWindowHandle> windowInSecondary =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -070011451 sp<FakeWindowHandle>::make(mApp, mDispatcher, "D_2", SECOND_DISPLAY_ID);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070011452 mDispatcher->onWindowInfosChanged(
11453 {{*mDragWindow->getInfo(), *mSpyWindow->getInfo(), *mWindow->getInfo(),
11454 *mSecondWindow->getInfo(), *windowInSecondary->getInfo()},
11455 {},
11456 0,
11457 0});
Arthur Hung3915c1f2022-05-31 07:17:17 +000011458
11459 // Let second display has a touch state.
11460 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070011461 injectMotionEvent(*mDispatcher,
Arthur Hung3915c1f2022-05-31 07:17:17 +000011462 MotionEventBuilder(AMOTION_EVENT_ACTION_DOWN,
11463 AINPUT_SOURCE_TOUCHSCREEN)
11464 .displayId(SECOND_DISPLAY_ID)
Siarhei Vishniakou6d73f832022-07-21 17:27:03 -070011465 .pointer(PointerBuilder(0, ToolType::FINGER).x(100).y(100))
Arthur Hung3915c1f2022-05-31 07:17:17 +000011466 .build()));
Prabir Pradhan7662a8d2023-12-15 01:58:14 +000011467 windowInSecondary->consumeMotionDown(SECOND_DISPLAY_ID, /*expectedFlag=*/0);
Arthur Hung3915c1f2022-05-31 07:17:17 +000011468 // Update window again.
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070011469 mDispatcher->onWindowInfosChanged(
11470 {{*mDragWindow->getInfo(), *mSpyWindow->getInfo(), *mWindow->getInfo(),
11471 *mSecondWindow->getInfo(), *windowInSecondary->getInfo()},
11472 {},
11473 0,
11474 0});
Arthur Hung3915c1f2022-05-31 07:17:17 +000011475
11476 // Move on window.
11477 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070011478 injectMotionEvent(*mDispatcher, AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN,
Arthur Hung3915c1f2022-05-31 07:17:17 +000011479 ADISPLAY_ID_DEFAULT, {50, 50}))
11480 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
Prabir Pradhan65455c72024-02-13 21:46:41 +000011481 mDragWindow->consumeMotionMove(ADISPLAY_ID_DEFAULT, AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
Arthur Hung3915c1f2022-05-31 07:17:17 +000011482 mWindow->consumeDragEvent(false, 50, 50);
11483 mSecondWindow->assertNoEvents();
11484
11485 // Move to another window.
11486 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070011487 injectMotionEvent(*mDispatcher, AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN,
Arthur Hung3915c1f2022-05-31 07:17:17 +000011488 ADISPLAY_ID_DEFAULT, {150, 50}))
11489 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
Prabir Pradhan65455c72024-02-13 21:46:41 +000011490 mDragWindow->consumeMotionMove(ADISPLAY_ID_DEFAULT, AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
Arthur Hung3915c1f2022-05-31 07:17:17 +000011491 mWindow->consumeDragEvent(true, 150, 50);
11492 mSecondWindow->consumeDragEvent(false, 50, 50);
11493
11494 // drop to another window.
11495 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070011496 injectMotionUp(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
Arthur Hung3915c1f2022-05-31 07:17:17 +000011497 {150, 50}))
11498 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
Prabir Pradhan65455c72024-02-13 21:46:41 +000011499 mDragWindow->consumeMotionUp(ADISPLAY_ID_DEFAULT, AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
Siarhei Vishniakoua66d65e2023-06-16 10:32:51 -070011500 mFakePolicy->assertDropTargetEquals(*mDispatcher, mSecondWindow->getToken());
Arthur Hung3915c1f2022-05-31 07:17:17 +000011501 mWindow->assertNoEvents();
11502 mSecondWindow->assertNoEvents();
11503}
11504
Arthur Hungb75c2aa2022-07-15 09:35:36 +000011505TEST_F(InputDispatcherDragTests, MouseDragAndDrop) {
11506 startDrag(true, AINPUT_SOURCE_MOUSE);
11507 // Move on window.
11508 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070011509 injectMotionEvent(*mDispatcher,
Arthur Hungb75c2aa2022-07-15 09:35:36 +000011510 MotionEventBuilder(AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_MOUSE)
11511 .buttonState(AMOTION_EVENT_BUTTON_PRIMARY)
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070011512 .pointer(PointerBuilder(MOUSE_POINTER_ID, ToolType::MOUSE)
Arthur Hungb75c2aa2022-07-15 09:35:36 +000011513 .x(50)
11514 .y(50))
11515 .build()))
11516 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
Prabir Pradhan65455c72024-02-13 21:46:41 +000011517 mDragWindow->consumeMotionMove(ADISPLAY_ID_DEFAULT, AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
Arthur Hungb75c2aa2022-07-15 09:35:36 +000011518 mWindow->consumeDragEvent(false, 50, 50);
11519 mSecondWindow->assertNoEvents();
11520
11521 // Move to another window.
11522 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070011523 injectMotionEvent(*mDispatcher,
Arthur Hungb75c2aa2022-07-15 09:35:36 +000011524 MotionEventBuilder(AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_MOUSE)
11525 .buttonState(AMOTION_EVENT_BUTTON_PRIMARY)
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070011526 .pointer(PointerBuilder(MOUSE_POINTER_ID, ToolType::MOUSE)
Arthur Hungb75c2aa2022-07-15 09:35:36 +000011527 .x(150)
11528 .y(50))
11529 .build()))
11530 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
Prabir Pradhan65455c72024-02-13 21:46:41 +000011531 mDragWindow->consumeMotionMove(ADISPLAY_ID_DEFAULT, AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
Arthur Hungb75c2aa2022-07-15 09:35:36 +000011532 mWindow->consumeDragEvent(true, 150, 50);
11533 mSecondWindow->consumeDragEvent(false, 50, 50);
11534
11535 // drop to another window.
11536 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070011537 injectMotionEvent(*mDispatcher,
Arthur Hungb75c2aa2022-07-15 09:35:36 +000011538 MotionEventBuilder(AMOTION_EVENT_ACTION_UP, AINPUT_SOURCE_MOUSE)
11539 .buttonState(0)
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070011540 .pointer(PointerBuilder(MOUSE_POINTER_ID, ToolType::MOUSE)
Arthur Hungb75c2aa2022-07-15 09:35:36 +000011541 .x(150)
11542 .y(50))
11543 .build()))
11544 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
Prabir Pradhan65455c72024-02-13 21:46:41 +000011545 mDragWindow->consumeMotionUp(ADISPLAY_ID_DEFAULT, AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
Siarhei Vishniakoua66d65e2023-06-16 10:32:51 -070011546 mFakePolicy->assertDropTargetEquals(*mDispatcher, mSecondWindow->getToken());
Arthur Hungb75c2aa2022-07-15 09:35:36 +000011547 mWindow->assertNoEvents();
11548 mSecondWindow->assertNoEvents();
11549}
11550
Linnan Li5af92f92023-07-14 14:36:22 +080011551/**
11552 * Start drag and drop with a pointer whose id is not 0, cancel the current touch, and ensure drag
11553 * and drop is also canceled. Then inject a simple gesture, and ensure dispatcher does not crash.
11554 */
11555TEST_F(InputDispatcherDragTests, DragAndDropFinishedWhenCancelCurrentTouch) {
11556 // Down on second window
11557 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
11558 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
11559 {150, 50}))
11560 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
11561
11562 ASSERT_NO_FATAL_FAILURE(mSecondWindow->consumeMotionDown());
11563 ASSERT_NO_FATAL_FAILURE(mSpyWindow->consumeMotionDown());
11564
11565 // Down on first window
11566 const MotionEvent secondFingerDownEvent =
11567 MotionEventBuilder(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
11568 .displayId(ADISPLAY_ID_DEFAULT)
11569 .pointer(PointerBuilder(/*id=*/0, ToolType::FINGER).x(150).y(50))
11570 .pointer(PointerBuilder(/*id=*/1, ToolType::FINGER).x(50).y(50))
11571 .build();
11572 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
11573 injectMotionEvent(*mDispatcher, secondFingerDownEvent, INJECT_EVENT_TIMEOUT,
11574 InputEventInjectionSync::WAIT_FOR_RESULT))
11575 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
11576 ASSERT_NO_FATAL_FAILURE(mWindow->consumeMotionDown());
11577 ASSERT_NO_FATAL_FAILURE(mSecondWindow->consumeMotionMove());
11578 ASSERT_NO_FATAL_FAILURE(mSpyWindow->consumeMotionPointerDown(1));
11579
11580 // Start drag on first window
11581 ASSERT_TRUE(startDrag(/*sendDown=*/false, AINPUT_SOURCE_TOUCHSCREEN));
11582
11583 // Trigger cancel
11584 mDispatcher->cancelCurrentTouch();
11585 ASSERT_NO_FATAL_FAILURE(mSecondWindow->consumeMotionCancel());
Prabir Pradhan65455c72024-02-13 21:46:41 +000011586 ASSERT_NO_FATAL_FAILURE(mDragWindow->consumeMotionCancel(ADISPLAY_ID_DEFAULT,
11587 AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE));
Linnan Li5af92f92023-07-14 14:36:22 +080011588 ASSERT_NO_FATAL_FAILURE(mSpyWindow->consumeMotionCancel());
11589
11590 ASSERT_TRUE(mDispatcher->waitForIdle());
11591 // The D&D finished with nullptr
11592 mFakePolicy->assertDropTargetEquals(*mDispatcher, nullptr);
11593
11594 // Remove drag window
11595 mDispatcher->onWindowInfosChanged({{*mWindow->getInfo(), *mSecondWindow->getInfo()}, {}, 0, 0});
11596
11597 // Inject a simple gesture, ensure dispatcher not crashed
11598 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
11599 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
11600 PointF{50, 50}))
11601 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
11602 ASSERT_NO_FATAL_FAILURE(mWindow->consumeMotionDown());
11603
11604 const MotionEvent moveEvent =
11605 MotionEventBuilder(AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN)
11606 .displayId(ADISPLAY_ID_DEFAULT)
11607 .pointer(PointerBuilder(/*id=*/0, ToolType::FINGER).x(50).y(50))
11608 .build();
11609 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
11610 injectMotionEvent(*mDispatcher, moveEvent, INJECT_EVENT_TIMEOUT,
11611 InputEventInjectionSync::WAIT_FOR_RESULT))
11612 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
11613 ASSERT_NO_FATAL_FAILURE(mWindow->consumeMotionMove());
11614
11615 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
11616 injectMotionUp(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
11617 {50, 50}))
11618 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
11619 ASSERT_NO_FATAL_FAILURE(mWindow->consumeMotionUp());
11620}
11621
Prabir Pradhan9cd9eb62023-11-22 17:58:06 +000011622TEST_F(InputDispatcherDragTests, NoDragAndDropWithHoveringPointer) {
11623 // Start hovering over the window.
11624 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
11625 injectMotionEvent(*mDispatcher, ACTION_HOVER_ENTER, AINPUT_SOURCE_MOUSE,
11626 ADISPLAY_ID_DEFAULT, {50, 50}));
11627
11628 ASSERT_NO_FATAL_FAILURE(mWindow->consumeMotionEvent(WithMotionAction(ACTION_HOVER_ENTER)));
11629 ASSERT_NO_FATAL_FAILURE(mSpyWindow->consumeMotionEvent(WithMotionAction(ACTION_HOVER_ENTER)));
11630
11631 ASSERT_FALSE(startDrag(/*sendDown=*/false))
11632 << "Drag and drop should not work with a hovering pointer";
11633}
11634
Vishnu Nair062a8672021-09-03 16:07:44 -070011635class InputDispatcherDropInputFeatureTest : public InputDispatcherTest {};
11636
11637TEST_F(InputDispatcherDropInputFeatureTest, WindowDropsInput) {
11638 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -070011639 sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher,
11640 "Test window", ADISPLAY_ID_DEFAULT);
Prabir Pradhan51e7db02022-02-07 06:02:57 -080011641 window->setDropInput(true);
Vishnu Nair062a8672021-09-03 16:07:44 -070011642 mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application);
11643 window->setFocusable(true);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070011644 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Vishnu Nair062a8672021-09-03 16:07:44 -070011645 setFocusedWindow(window);
Harry Cutts33476232023-01-30 19:57:29 +000011646 window->consumeFocusEvent(/*hasFocus=*/true, /*inTouchMode=*/true);
Vishnu Nair062a8672021-09-03 16:07:44 -070011647
11648 // With the flag set, window should not get any input
Prabir Pradhan678438e2023-04-13 19:32:51 +000011649 mDispatcher->notifyKey(generateKeyArgs(AKEY_EVENT_ACTION_DOWN, ADISPLAY_ID_DEFAULT));
Vishnu Nair062a8672021-09-03 16:07:44 -070011650 window->assertNoEvents();
11651
Prabir Pradhan678438e2023-04-13 19:32:51 +000011652 mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_DOWN,
11653 AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT));
Siarhei Vishniakou5c02a712023-05-15 15:45:02 -070011654 mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN,
11655 ADISPLAY_ID_DEFAULT));
Siarhei Vishniakoud908f5a2023-11-16 10:25:12 -080011656 mDispatcher->waitForIdle();
Vishnu Nair062a8672021-09-03 16:07:44 -070011657 window->assertNoEvents();
11658
11659 // With the flag cleared, the window should get input
Prabir Pradhan51e7db02022-02-07 06:02:57 -080011660 window->setDropInput(false);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070011661 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Vishnu Nair062a8672021-09-03 16:07:44 -070011662
Prabir Pradhan678438e2023-04-13 19:32:51 +000011663 mDispatcher->notifyKey(generateKeyArgs(AKEY_EVENT_ACTION_UP, ADISPLAY_ID_DEFAULT));
Vishnu Nair062a8672021-09-03 16:07:44 -070011664 window->consumeKeyUp(ADISPLAY_ID_DEFAULT);
11665
Prabir Pradhan678438e2023-04-13 19:32:51 +000011666 mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_DOWN,
11667 AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT));
Vishnu Nair062a8672021-09-03 16:07:44 -070011668 window->consumeMotionDown(ADISPLAY_ID_DEFAULT);
11669 window->assertNoEvents();
11670}
11671
11672TEST_F(InputDispatcherDropInputFeatureTest, ObscuredWindowDropsInput) {
11673 std::shared_ptr<FakeApplicationHandle> obscuringApplication =
11674 std::make_shared<FakeApplicationHandle>();
11675 sp<FakeWindowHandle> obscuringWindow =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -070011676 sp<FakeWindowHandle>::make(obscuringApplication, mDispatcher, "obscuringWindow",
11677 ADISPLAY_ID_DEFAULT);
Vishnu Nair062a8672021-09-03 16:07:44 -070011678 obscuringWindow->setFrame(Rect(0, 0, 50, 50));
Prabir Pradhanaeebeb42023-06-13 19:53:03 +000011679 obscuringWindow->setOwnerInfo(gui::Pid{111}, gui::Uid{111});
Prabir Pradhan4d5c52f2022-01-31 08:52:10 -080011680 obscuringWindow->setTouchable(false);
Vishnu Nair062a8672021-09-03 16:07:44 -070011681 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -070011682 sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher,
11683 "Test window", ADISPLAY_ID_DEFAULT);
Prabir Pradhan51e7db02022-02-07 06:02:57 -080011684 window->setDropInputIfObscured(true);
Prabir Pradhanaeebeb42023-06-13 19:53:03 +000011685 window->setOwnerInfo(gui::Pid{222}, gui::Uid{222});
Vishnu Nair062a8672021-09-03 16:07:44 -070011686 mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application);
11687 window->setFocusable(true);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070011688 mDispatcher->onWindowInfosChanged(
11689 {{*obscuringWindow->getInfo(), *window->getInfo()}, {}, 0, 0});
Vishnu Nair062a8672021-09-03 16:07:44 -070011690 setFocusedWindow(window);
Harry Cutts33476232023-01-30 19:57:29 +000011691 window->consumeFocusEvent(/*hasFocus=*/true, /*inTouchMode=*/true);
Vishnu Nair062a8672021-09-03 16:07:44 -070011692
11693 // With the flag set, window should not get any input
Prabir Pradhan678438e2023-04-13 19:32:51 +000011694 mDispatcher->notifyKey(generateKeyArgs(AKEY_EVENT_ACTION_DOWN, ADISPLAY_ID_DEFAULT));
Vishnu Nair062a8672021-09-03 16:07:44 -070011695 window->assertNoEvents();
11696
Prabir Pradhan678438e2023-04-13 19:32:51 +000011697 mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_DOWN,
11698 AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT));
Siarhei Vishniakou5c02a712023-05-15 15:45:02 -070011699 mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN,
11700 ADISPLAY_ID_DEFAULT));
Vishnu Nair062a8672021-09-03 16:07:44 -070011701 window->assertNoEvents();
11702
11703 // With the flag cleared, the window should get input
Prabir Pradhan51e7db02022-02-07 06:02:57 -080011704 window->setDropInputIfObscured(false);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070011705 mDispatcher->onWindowInfosChanged(
11706 {{*obscuringWindow->getInfo(), *window->getInfo()}, {}, 0, 0});
Vishnu Nair062a8672021-09-03 16:07:44 -070011707
Prabir Pradhan678438e2023-04-13 19:32:51 +000011708 mDispatcher->notifyKey(generateKeyArgs(AKEY_EVENT_ACTION_UP, ADISPLAY_ID_DEFAULT));
Vishnu Nair062a8672021-09-03 16:07:44 -070011709 window->consumeKeyUp(ADISPLAY_ID_DEFAULT);
11710
Prabir Pradhan678438e2023-04-13 19:32:51 +000011711 mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_DOWN,
11712 AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT));
Vishnu Nair062a8672021-09-03 16:07:44 -070011713 window->consumeMotionDown(ADISPLAY_ID_DEFAULT, AMOTION_EVENT_FLAG_WINDOW_IS_PARTIALLY_OBSCURED);
11714 window->assertNoEvents();
11715}
11716
11717TEST_F(InputDispatcherDropInputFeatureTest, UnobscuredWindowGetsInput) {
11718 std::shared_ptr<FakeApplicationHandle> obscuringApplication =
11719 std::make_shared<FakeApplicationHandle>();
11720 sp<FakeWindowHandle> obscuringWindow =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -070011721 sp<FakeWindowHandle>::make(obscuringApplication, mDispatcher, "obscuringWindow",
11722 ADISPLAY_ID_DEFAULT);
Vishnu Nair062a8672021-09-03 16:07:44 -070011723 obscuringWindow->setFrame(Rect(0, 0, 50, 50));
Prabir Pradhanaeebeb42023-06-13 19:53:03 +000011724 obscuringWindow->setOwnerInfo(gui::Pid{111}, gui::Uid{111});
Prabir Pradhan4d5c52f2022-01-31 08:52:10 -080011725 obscuringWindow->setTouchable(false);
Vishnu Nair062a8672021-09-03 16:07:44 -070011726 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -070011727 sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher,
11728 "Test window", ADISPLAY_ID_DEFAULT);
Prabir Pradhan51e7db02022-02-07 06:02:57 -080011729 window->setDropInputIfObscured(true);
Prabir Pradhanaeebeb42023-06-13 19:53:03 +000011730 window->setOwnerInfo(gui::Pid{222}, gui::Uid{222});
Vishnu Nair062a8672021-09-03 16:07:44 -070011731 mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application);
11732 window->setFocusable(true);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070011733 mDispatcher->onWindowInfosChanged(
11734 {{*obscuringWindow->getInfo(), *window->getInfo()}, {}, 0, 0});
Vishnu Nair062a8672021-09-03 16:07:44 -070011735 setFocusedWindow(window);
Harry Cutts33476232023-01-30 19:57:29 +000011736 window->consumeFocusEvent(/*hasFocus=*/true, /*inTouchMode=*/true);
Vishnu Nair062a8672021-09-03 16:07:44 -070011737
11738 // With the flag set, window should not get any input
Prabir Pradhan678438e2023-04-13 19:32:51 +000011739 mDispatcher->notifyKey(generateKeyArgs(AKEY_EVENT_ACTION_DOWN, ADISPLAY_ID_DEFAULT));
Vishnu Nair062a8672021-09-03 16:07:44 -070011740 window->assertNoEvents();
11741
Prabir Pradhan678438e2023-04-13 19:32:51 +000011742 mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_DOWN,
11743 AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT));
Siarhei Vishniakou5c02a712023-05-15 15:45:02 -070011744 mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN,
11745 ADISPLAY_ID_DEFAULT));
Vishnu Nair062a8672021-09-03 16:07:44 -070011746 window->assertNoEvents();
11747
11748 // When the window is no longer obscured because it went on top, it should get input
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070011749 mDispatcher->onWindowInfosChanged(
11750 {{*window->getInfo(), *obscuringWindow->getInfo()}, {}, 0, 0});
Vishnu Nair062a8672021-09-03 16:07:44 -070011751
Prabir Pradhan678438e2023-04-13 19:32:51 +000011752 mDispatcher->notifyKey(generateKeyArgs(AKEY_EVENT_ACTION_UP, ADISPLAY_ID_DEFAULT));
Vishnu Nair062a8672021-09-03 16:07:44 -070011753 window->consumeKeyUp(ADISPLAY_ID_DEFAULT);
11754
Prabir Pradhan678438e2023-04-13 19:32:51 +000011755 mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_DOWN,
11756 AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT));
Vishnu Nair062a8672021-09-03 16:07:44 -070011757 window->consumeMotionDown(ADISPLAY_ID_DEFAULT);
11758 window->assertNoEvents();
11759}
11760
Antonio Kantekf16f2832021-09-28 04:39:20 +000011761class InputDispatcherTouchModeChangedTests : public InputDispatcherTest {
11762protected:
11763 std::shared_ptr<FakeApplicationHandle> mApp;
Antonio Kantek15beb512022-06-13 22:35:41 +000011764 std::shared_ptr<FakeApplicationHandle> mSecondaryApp;
Antonio Kantekf16f2832021-09-28 04:39:20 +000011765 sp<FakeWindowHandle> mWindow;
11766 sp<FakeWindowHandle> mSecondWindow;
Antonio Kantek15beb512022-06-13 22:35:41 +000011767 sp<FakeWindowHandle> mThirdWindow;
Antonio Kantekf16f2832021-09-28 04:39:20 +000011768
11769 void SetUp() override {
11770 InputDispatcherTest::SetUp();
11771
11772 mApp = std::make_shared<FakeApplicationHandle>();
Antonio Kantek15beb512022-06-13 22:35:41 +000011773 mSecondaryApp = std::make_shared<FakeApplicationHandle>();
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -070011774 mWindow = sp<FakeWindowHandle>::make(mApp, mDispatcher, "TestWindow", ADISPLAY_ID_DEFAULT);
Antonio Kantekf16f2832021-09-28 04:39:20 +000011775 mWindow->setFocusable(true);
Antonio Kantek26defcf2022-02-08 01:12:27 +000011776 setFocusedWindow(mWindow);
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -070011777 mSecondWindow =
11778 sp<FakeWindowHandle>::make(mApp, mDispatcher, "TestWindow2", ADISPLAY_ID_DEFAULT);
Antonio Kantekf16f2832021-09-28 04:39:20 +000011779 mSecondWindow->setFocusable(true);
Antonio Kantek15beb512022-06-13 22:35:41 +000011780 mThirdWindow =
11781 sp<FakeWindowHandle>::make(mSecondaryApp, mDispatcher,
11782 "TestWindow3_SecondaryDisplay", SECOND_DISPLAY_ID);
11783 mThirdWindow->setFocusable(true);
Antonio Kantekf16f2832021-09-28 04:39:20 +000011784
11785 mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, mApp);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070011786 mDispatcher->onWindowInfosChanged(
11787 {{*mWindow->getInfo(), *mSecondWindow->getInfo(), *mThirdWindow->getInfo()},
11788 {},
11789 0,
11790 0});
Antonio Kantek15beb512022-06-13 22:35:41 +000011791 mThirdWindow->setOwnerInfo(SECONDARY_WINDOW_PID, SECONDARY_WINDOW_UID);
Antonio Kantekf16f2832021-09-28 04:39:20 +000011792 mWindow->consumeFocusEvent(true);
Antonio Kantek26defcf2022-02-08 01:12:27 +000011793
Antonio Kantek15beb512022-06-13 22:35:41 +000011794 // Set main display initial touch mode to InputDispatcher::kDefaultInTouchMode.
Prabir Pradhan5735a322022-04-11 17:23:34 +000011795 if (mDispatcher->setInTouchMode(InputDispatcher::kDefaultInTouchMode, WINDOW_PID,
Harry Cutts33476232023-01-30 19:57:29 +000011796 WINDOW_UID, /*hasPermission=*/true, ADISPLAY_ID_DEFAULT)) {
Antonio Kantek48710e42022-03-24 14:19:30 -070011797 mWindow->consumeTouchModeEvent(InputDispatcher::kDefaultInTouchMode);
11798 mSecondWindow->consumeTouchModeEvent(InputDispatcher::kDefaultInTouchMode);
Antonio Kantek15beb512022-06-13 22:35:41 +000011799 mThirdWindow->assertNoEvents();
11800 }
11801
11802 // Set secondary display initial touch mode to InputDispatcher::kDefaultInTouchMode.
11803 if (mDispatcher->setInTouchMode(InputDispatcher::kDefaultInTouchMode, SECONDARY_WINDOW_PID,
Harry Cutts33476232023-01-30 19:57:29 +000011804 SECONDARY_WINDOW_UID, /*hasPermission=*/true,
Antonio Kantek15beb512022-06-13 22:35:41 +000011805 SECOND_DISPLAY_ID)) {
11806 mWindow->assertNoEvents();
11807 mSecondWindow->assertNoEvents();
11808 mThirdWindow->consumeTouchModeEvent(InputDispatcher::kDefaultInTouchMode);
Antonio Kantek48710e42022-03-24 14:19:30 -070011809 }
Antonio Kantekf16f2832021-09-28 04:39:20 +000011810 }
11811
Prabir Pradhanaeebeb42023-06-13 19:53:03 +000011812 void changeAndVerifyTouchModeInMainDisplayOnly(bool inTouchMode, gui::Pid pid, gui::Uid uid,
Antonio Kantek15beb512022-06-13 22:35:41 +000011813 bool hasPermission) {
Antonio Kanteka042c022022-07-06 16:51:07 -070011814 ASSERT_TRUE(mDispatcher->setInTouchMode(inTouchMode, pid, uid, hasPermission,
11815 ADISPLAY_ID_DEFAULT));
Antonio Kantekf16f2832021-09-28 04:39:20 +000011816 mWindow->consumeTouchModeEvent(inTouchMode);
11817 mSecondWindow->consumeTouchModeEvent(inTouchMode);
Antonio Kantek15beb512022-06-13 22:35:41 +000011818 mThirdWindow->assertNoEvents();
Antonio Kantekf16f2832021-09-28 04:39:20 +000011819 }
11820};
11821
Antonio Kantek26defcf2022-02-08 01:12:27 +000011822TEST_F(InputDispatcherTouchModeChangedTests, FocusedWindowCanChangeTouchMode) {
Antonio Kantekea47acb2021-12-23 12:41:25 -080011823 const WindowInfo& windowInfo = *mWindow->getInfo();
Antonio Kantek15beb512022-06-13 22:35:41 +000011824 changeAndVerifyTouchModeInMainDisplayOnly(!InputDispatcher::kDefaultInTouchMode,
11825 windowInfo.ownerPid, windowInfo.ownerUid,
Harry Cutts33476232023-01-30 19:57:29 +000011826 /* hasPermission=*/false);
Antonio Kantekf16f2832021-09-28 04:39:20 +000011827}
11828
Antonio Kantek26defcf2022-02-08 01:12:27 +000011829TEST_F(InputDispatcherTouchModeChangedTests, NonFocusedWindowOwnerCannotChangeTouchMode) {
11830 const WindowInfo& windowInfo = *mWindow->getInfo();
Prabir Pradhanaeebeb42023-06-13 19:53:03 +000011831 gui::Pid ownerPid = windowInfo.ownerPid;
Prabir Pradhan8a5c41d2023-06-08 19:13:46 +000011832 gui::Uid ownerUid = windowInfo.ownerUid;
Prabir Pradhanaeebeb42023-06-13 19:53:03 +000011833 mWindow->setOwnerInfo(gui::Pid::INVALID, gui::Uid::INVALID);
Antonio Kantek26defcf2022-02-08 01:12:27 +000011834 ASSERT_FALSE(mDispatcher->setInTouchMode(InputDispatcher::kDefaultInTouchMode, ownerPid,
Harry Cutts33476232023-01-30 19:57:29 +000011835 ownerUid, /*hasPermission=*/false,
Antonio Kanteka042c022022-07-06 16:51:07 -070011836 ADISPLAY_ID_DEFAULT));
Antonio Kantek26defcf2022-02-08 01:12:27 +000011837 mWindow->assertNoEvents();
11838 mSecondWindow->assertNoEvents();
11839}
11840
11841TEST_F(InputDispatcherTouchModeChangedTests, NonWindowOwnerMayChangeTouchModeOnPermissionGranted) {
11842 const WindowInfo& windowInfo = *mWindow->getInfo();
Prabir Pradhanaeebeb42023-06-13 19:53:03 +000011843 gui::Pid ownerPid = windowInfo.ownerPid;
Prabir Pradhan8a5c41d2023-06-08 19:13:46 +000011844 gui::Uid ownerUid = windowInfo.ownerUid;
Prabir Pradhanaeebeb42023-06-13 19:53:03 +000011845 mWindow->setOwnerInfo(gui::Pid::INVALID, gui::Uid::INVALID);
Antonio Kantek15beb512022-06-13 22:35:41 +000011846 changeAndVerifyTouchModeInMainDisplayOnly(!InputDispatcher::kDefaultInTouchMode, ownerPid,
Harry Cutts33476232023-01-30 19:57:29 +000011847 ownerUid, /*hasPermission=*/true);
Antonio Kantek26defcf2022-02-08 01:12:27 +000011848}
11849
Antonio Kantekf16f2832021-09-28 04:39:20 +000011850TEST_F(InputDispatcherTouchModeChangedTests, EventIsNotGeneratedIfNotChangingTouchMode) {
Antonio Kantekea47acb2021-12-23 12:41:25 -080011851 const WindowInfo& windowInfo = *mWindow->getInfo();
Antonio Kantek26defcf2022-02-08 01:12:27 +000011852 ASSERT_FALSE(mDispatcher->setInTouchMode(InputDispatcher::kDefaultInTouchMode,
11853 windowInfo.ownerPid, windowInfo.ownerUid,
Harry Cutts33476232023-01-30 19:57:29 +000011854 /*hasPermission=*/true, ADISPLAY_ID_DEFAULT));
Antonio Kantekf16f2832021-09-28 04:39:20 +000011855 mWindow->assertNoEvents();
11856 mSecondWindow->assertNoEvents();
11857}
11858
Antonio Kantek15beb512022-06-13 22:35:41 +000011859TEST_F(InputDispatcherTouchModeChangedTests, ChangeTouchOnSecondaryDisplayOnly) {
11860 const WindowInfo& windowInfo = *mThirdWindow->getInfo();
11861 ASSERT_TRUE(mDispatcher->setInTouchMode(!InputDispatcher::kDefaultInTouchMode,
11862 windowInfo.ownerPid, windowInfo.ownerUid,
Harry Cutts33476232023-01-30 19:57:29 +000011863 /*hasPermission=*/true, SECOND_DISPLAY_ID));
Antonio Kantek15beb512022-06-13 22:35:41 +000011864 mWindow->assertNoEvents();
11865 mSecondWindow->assertNoEvents();
11866 mThirdWindow->consumeTouchModeEvent(!InputDispatcher::kDefaultInTouchMode);
11867}
11868
Antonio Kantek48710e42022-03-24 14:19:30 -070011869TEST_F(InputDispatcherTouchModeChangedTests, CanChangeTouchModeWhenOwningLastInteractedWindow) {
11870 // Interact with the window first.
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070011871 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
11872 injectKeyDown(*mDispatcher, ADISPLAY_ID_DEFAULT))
Antonio Kantek48710e42022-03-24 14:19:30 -070011873 << "Inject key event should return InputEventInjectionResult::SUCCEEDED";
11874 mWindow->consumeKeyDown(ADISPLAY_ID_DEFAULT);
11875
11876 // Then remove focus.
11877 mWindow->setFocusable(false);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070011878 mDispatcher->onWindowInfosChanged({{*mWindow->getInfo()}, {}, 0, 0});
Antonio Kantek48710e42022-03-24 14:19:30 -070011879
11880 // Assert that caller can switch touch mode by owning one of the last interacted window.
11881 const WindowInfo& windowInfo = *mWindow->getInfo();
11882 ASSERT_TRUE(mDispatcher->setInTouchMode(!InputDispatcher::kDefaultInTouchMode,
11883 windowInfo.ownerPid, windowInfo.ownerUid,
Harry Cutts33476232023-01-30 19:57:29 +000011884 /*hasPermission=*/false, ADISPLAY_ID_DEFAULT));
Antonio Kantek48710e42022-03-24 14:19:30 -070011885}
11886
Prabir Pradhan07e05b62021-11-19 03:57:24 -080011887class InputDispatcherSpyWindowTest : public InputDispatcherTest {
11888public:
Prabir Pradhan4d5c52f2022-01-31 08:52:10 -080011889 sp<FakeWindowHandle> createSpy() {
Prabir Pradhan07e05b62021-11-19 03:57:24 -080011890 std::shared_ptr<FakeApplicationHandle> application =
11891 std::make_shared<FakeApplicationHandle>();
11892 std::string name = "Fake Spy ";
11893 name += std::to_string(mSpyCount++);
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -070011894 sp<FakeWindowHandle> spy = sp<FakeWindowHandle>::make(application, mDispatcher,
11895 name.c_str(), ADISPLAY_ID_DEFAULT);
Prabir Pradhan51e7db02022-02-07 06:02:57 -080011896 spy->setSpy(true);
Prabir Pradhan5c85e052021-12-22 02:27:12 -080011897 spy->setTrustedOverlay(true);
Prabir Pradhan07e05b62021-11-19 03:57:24 -080011898 return spy;
11899 }
11900
11901 sp<FakeWindowHandle> createForeground() {
11902 std::shared_ptr<FakeApplicationHandle> application =
11903 std::make_shared<FakeApplicationHandle>();
11904 sp<FakeWindowHandle> window =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -070011905 sp<FakeWindowHandle>::make(application, mDispatcher, "Fake Window",
11906 ADISPLAY_ID_DEFAULT);
Prabir Pradhan1376fcd2022-01-21 09:56:35 -080011907 window->setFocusable(true);
Prabir Pradhan07e05b62021-11-19 03:57:24 -080011908 return window;
11909 }
11910
11911private:
11912 int mSpyCount{0};
11913};
11914
Prabir Pradhana3ab87a2022-01-27 10:00:21 -080011915using InputDispatcherSpyWindowDeathTest = InputDispatcherSpyWindowTest;
Prabir Pradhan07e05b62021-11-19 03:57:24 -080011916/**
Prabir Pradhan5c85e052021-12-22 02:27:12 -080011917 * Adding a spy window that is not a trusted overlay causes Dispatcher to abort.
11918 */
Prabir Pradhana3ab87a2022-01-27 10:00:21 -080011919TEST_F(InputDispatcherSpyWindowDeathTest, UntrustedSpy_AbortsDispatcher) {
Siarhei Vishniakou21f77bd2023-07-18 17:51:35 -070011920 testing::GTEST_FLAG(death_test_style) = "threadsafe";
Prabir Pradhana3ab87a2022-01-27 10:00:21 -080011921 ScopedSilentDeath _silentDeath;
11922
Prabir Pradhan4d5c52f2022-01-31 08:52:10 -080011923 auto spy = createSpy();
Prabir Pradhan5c85e052021-12-22 02:27:12 -080011924 spy->setTrustedOverlay(false);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070011925 ASSERT_DEATH(mDispatcher->onWindowInfosChanged({{*spy->getInfo()}, {}, 0, 0}),
Prabir Pradhan5c85e052021-12-22 02:27:12 -080011926 ".* not a trusted overlay");
11927}
11928
11929/**
Prabir Pradhan07e05b62021-11-19 03:57:24 -080011930 * Input injection into a display with a spy window but no foreground windows should succeed.
11931 */
11932TEST_F(InputDispatcherSpyWindowTest, NoForegroundWindow) {
Prabir Pradhan4d5c52f2022-01-31 08:52:10 -080011933 auto spy = createSpy();
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070011934 mDispatcher->onWindowInfosChanged({{*spy->getInfo()}, {}, 0, 0});
Prabir Pradhan07e05b62021-11-19 03:57:24 -080011935
11936 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070011937 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT))
Prabir Pradhan07e05b62021-11-19 03:57:24 -080011938 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
11939 spy->consumeMotionDown(ADISPLAY_ID_DEFAULT);
11940}
11941
11942/**
11943 * Verify the order in which different input windows receive events. The touched foreground window
11944 * (if there is one) should always receive the event first. When there are multiple spy windows, the
11945 * spy windows will receive the event according to their Z-order, where the top-most spy window will
11946 * receive events before ones belows it.
11947 *
11948 * Here, we set up a scenario with four windows in the following Z order from the top:
11949 * spy1, spy2, window, spy3.
11950 * We then inject an event and verify that the foreground "window" receives it first, followed by
11951 * "spy1" and "spy2". The "spy3" does not receive the event because it is underneath the foreground
11952 * window.
11953 */
11954TEST_F(InputDispatcherSpyWindowTest, ReceivesInputInOrder) {
11955 auto window = createForeground();
Prabir Pradhan4d5c52f2022-01-31 08:52:10 -080011956 auto spy1 = createSpy();
11957 auto spy2 = createSpy();
11958 auto spy3 = createSpy();
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070011959 mDispatcher->onWindowInfosChanged(
11960 {{*spy1->getInfo(), *spy2->getInfo(), *window->getInfo(), *spy3->getInfo()}, {}, 0, 0});
Prabir Pradhan07e05b62021-11-19 03:57:24 -080011961 const std::vector<sp<FakeWindowHandle>> channels{spy1, spy2, window, spy3};
11962 const size_t numChannels = channels.size();
11963
Michael Wright8e9a8562022-02-09 13:44:29 +000011964 base::unique_fd epollFd(epoll_create1(EPOLL_CLOEXEC));
Prabir Pradhan07e05b62021-11-19 03:57:24 -080011965 if (!epollFd.ok()) {
11966 FAIL() << "Failed to create epoll fd";
11967 }
11968
11969 for (size_t i = 0; i < numChannels; i++) {
11970 struct epoll_event event = {.events = EPOLLIN, .data.u64 = i};
11971 if (epoll_ctl(epollFd.get(), EPOLL_CTL_ADD, channels[i]->getChannelFd(), &event) < 0) {
11972 FAIL() << "Failed to add fd to epoll";
11973 }
11974 }
11975
11976 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070011977 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT))
Prabir Pradhan07e05b62021-11-19 03:57:24 -080011978 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
11979
11980 std::vector<size_t> eventOrder;
11981 std::vector<struct epoll_event> events(numChannels);
11982 for (;;) {
11983 const int nFds = epoll_wait(epollFd.get(), events.data(), static_cast<int>(numChannels),
11984 (100ms).count());
11985 if (nFds < 0) {
11986 FAIL() << "Failed to call epoll_wait";
11987 }
11988 if (nFds == 0) {
11989 break; // epoll_wait timed out
11990 }
11991 for (int i = 0; i < nFds; i++) {
Colin Cross5b799302022-10-18 21:52:41 -070011992 ASSERT_EQ(static_cast<uint32_t>(EPOLLIN), events[i].events);
Siarhei Vishniakou31977182022-09-30 08:51:23 -070011993 eventOrder.push_back(static_cast<size_t>(events[i].data.u64));
Prabir Pradhan07e05b62021-11-19 03:57:24 -080011994 channels[i]->consumeMotionDown();
11995 }
11996 }
11997
11998 // Verify the order in which the events were received.
11999 EXPECT_EQ(3u, eventOrder.size());
12000 EXPECT_EQ(2u, eventOrder[0]); // index 2: window
12001 EXPECT_EQ(0u, eventOrder[1]); // index 0: spy1
12002 EXPECT_EQ(1u, eventOrder[2]); // index 1: spy2
12003}
12004
12005/**
12006 * A spy window using the NOT_TOUCHABLE flag does not receive events.
12007 */
12008TEST_F(InputDispatcherSpyWindowTest, NotTouchable) {
12009 auto window = createForeground();
Prabir Pradhan4d5c52f2022-01-31 08:52:10 -080012010 auto spy = createSpy();
12011 spy->setTouchable(false);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070012012 mDispatcher->onWindowInfosChanged({{*spy->getInfo(), *window->getInfo()}, {}, 0, 0});
Prabir Pradhan07e05b62021-11-19 03:57:24 -080012013
12014 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070012015 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT))
Prabir Pradhan07e05b62021-11-19 03:57:24 -080012016 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
12017 window->consumeMotionDown(ADISPLAY_ID_DEFAULT);
12018 spy->assertNoEvents();
12019}
12020
12021/**
12022 * A spy window will only receive gestures that originate within its touchable region. Gestures that
12023 * have their ACTION_DOWN outside of the touchable region of the spy window will not be dispatched
12024 * to the window.
12025 */
12026TEST_F(InputDispatcherSpyWindowTest, TouchableRegion) {
12027 auto window = createForeground();
Prabir Pradhan4d5c52f2022-01-31 08:52:10 -080012028 auto spy = createSpy();
Prabir Pradhan07e05b62021-11-19 03:57:24 -080012029 spy->setTouchableRegion(Region{{0, 0, 20, 20}});
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070012030 mDispatcher->onWindowInfosChanged({{*spy->getInfo(), *window->getInfo()}, {}, 0, 0});
Prabir Pradhan07e05b62021-11-19 03:57:24 -080012031
12032 // Inject an event outside the spy window's touchable region.
12033 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070012034 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT))
Prabir Pradhan07e05b62021-11-19 03:57:24 -080012035 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
12036 window->consumeMotionDown();
12037 spy->assertNoEvents();
12038 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070012039 injectMotionUp(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT))
Prabir Pradhan07e05b62021-11-19 03:57:24 -080012040 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
12041 window->consumeMotionUp();
12042 spy->assertNoEvents();
12043
12044 // Inject an event inside the spy window's touchable region.
12045 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070012046 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
Prabir Pradhan07e05b62021-11-19 03:57:24 -080012047 {5, 10}))
12048 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
12049 window->consumeMotionDown();
12050 spy->consumeMotionDown();
12051}
12052
12053/**
Prabir Pradhan07e05b62021-11-19 03:57:24 -080012054 * A spy window can listen for touches outside its touchable region using the WATCH_OUTSIDE_TOUCHES
Prabir Pradhandfabf8a2022-01-21 08:19:30 -080012055 * flag, but it will get zero-ed out coordinates if the foreground has a different owner.
Prabir Pradhan07e05b62021-11-19 03:57:24 -080012056 */
12057TEST_F(InputDispatcherSpyWindowTest, WatchOutsideTouches) {
12058 auto window = createForeground();
Prabir Pradhanaeebeb42023-06-13 19:53:03 +000012059 window->setOwnerInfo(gui::Pid{12}, gui::Uid{34});
Prabir Pradhan4d5c52f2022-01-31 08:52:10 -080012060 auto spy = createSpy();
12061 spy->setWatchOutsideTouch(true);
Prabir Pradhanaeebeb42023-06-13 19:53:03 +000012062 spy->setOwnerInfo(gui::Pid{56}, gui::Uid{78});
Prabir Pradhan07e05b62021-11-19 03:57:24 -080012063 spy->setFrame(Rect{0, 0, 20, 20});
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070012064 mDispatcher->onWindowInfosChanged({{*spy->getInfo(), *window->getInfo()}, {}, 0, 0});
Prabir Pradhan07e05b62021-11-19 03:57:24 -080012065
12066 // Inject an event outside the spy window's frame and touchable region.
12067 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070012068 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
Prabir Pradhandfabf8a2022-01-21 08:19:30 -080012069 {100, 200}))
Prabir Pradhan07e05b62021-11-19 03:57:24 -080012070 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
12071 window->consumeMotionDown();
Prabir Pradhandfabf8a2022-01-21 08:19:30 -080012072 spy->consumeMotionOutsideWithZeroedCoords();
Prabir Pradhan07e05b62021-11-19 03:57:24 -080012073}
12074
12075/**
Prabir Pradhan07e05b62021-11-19 03:57:24 -080012076 * Even when a spy window spans over multiple foreground windows, the spy should receive all
12077 * pointers that are down within its bounds.
12078 */
12079TEST_F(InputDispatcherSpyWindowTest, ReceivesMultiplePointers) {
12080 auto windowLeft = createForeground();
12081 windowLeft->setFrame({0, 0, 100, 200});
12082 auto windowRight = createForeground();
12083 windowRight->setFrame({100, 0, 200, 200});
Prabir Pradhan4d5c52f2022-01-31 08:52:10 -080012084 auto spy = createSpy();
Prabir Pradhan07e05b62021-11-19 03:57:24 -080012085 spy->setFrame({0, 0, 200, 200});
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070012086 mDispatcher->onWindowInfosChanged(
12087 {{*spy->getInfo(), *windowLeft->getInfo(), *windowRight->getInfo()}, {}, 0, 0});
Prabir Pradhan07e05b62021-11-19 03:57:24 -080012088
12089 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070012090 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
Prabir Pradhan07e05b62021-11-19 03:57:24 -080012091 {50, 50}))
12092 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
12093 windowLeft->consumeMotionDown();
12094 spy->consumeMotionDown();
12095
12096 const MotionEvent secondFingerDownEvent =
Siarhei Vishniakoua16e3a22022-03-02 15:26:40 -080012097 MotionEventBuilder(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
Prabir Pradhan07e05b62021-11-19 03:57:24 -080012098 .eventTime(systemTime(SYSTEM_TIME_MONOTONIC))
Siarhei Vishniakou6d73f832022-07-21 17:27:03 -070012099 .pointer(PointerBuilder(/*id=*/0, ToolType::FINGER).x(50).y(50))
12100 .pointer(PointerBuilder(/*id=*/1, ToolType::FINGER).x(150).y(50))
Prabir Pradhan07e05b62021-11-19 03:57:24 -080012101 .build();
12102 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070012103 injectMotionEvent(*mDispatcher, secondFingerDownEvent, INJECT_EVENT_TIMEOUT,
Prabir Pradhan07e05b62021-11-19 03:57:24 -080012104 InputEventInjectionSync::WAIT_FOR_RESULT))
12105 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
12106 windowRight->consumeMotionDown();
Harry Cutts33476232023-01-30 19:57:29 +000012107 spy->consumeMotionPointerDown(/*pointerIndex=*/1);
Prabir Pradhan07e05b62021-11-19 03:57:24 -080012108}
12109
12110/**
12111 * When the first pointer lands outside the spy window and the second pointer lands inside it, the
12112 * the spy should receive the second pointer with ACTION_DOWN.
12113 */
12114TEST_F(InputDispatcherSpyWindowTest, ReceivesSecondPointerAsDown) {
12115 auto window = createForeground();
12116 window->setFrame({0, 0, 200, 200});
Prabir Pradhan4d5c52f2022-01-31 08:52:10 -080012117 auto spyRight = createSpy();
Prabir Pradhan07e05b62021-11-19 03:57:24 -080012118 spyRight->setFrame({100, 0, 200, 200});
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070012119 mDispatcher->onWindowInfosChanged({{*spyRight->getInfo(), *window->getInfo()}, {}, 0, 0});
Prabir Pradhan07e05b62021-11-19 03:57:24 -080012120
12121 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070012122 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
Prabir Pradhan07e05b62021-11-19 03:57:24 -080012123 {50, 50}))
12124 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
12125 window->consumeMotionDown();
12126 spyRight->assertNoEvents();
12127
12128 const MotionEvent secondFingerDownEvent =
Siarhei Vishniakoua16e3a22022-03-02 15:26:40 -080012129 MotionEventBuilder(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
Prabir Pradhan07e05b62021-11-19 03:57:24 -080012130 .eventTime(systemTime(SYSTEM_TIME_MONOTONIC))
Siarhei Vishniakou6d73f832022-07-21 17:27:03 -070012131 .pointer(PointerBuilder(/*id=*/0, ToolType::FINGER).x(50).y(50))
12132 .pointer(PointerBuilder(/*id=*/1, ToolType::FINGER).x(150).y(50))
Prabir Pradhan07e05b62021-11-19 03:57:24 -080012133 .build();
12134 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070012135 injectMotionEvent(*mDispatcher, secondFingerDownEvent, INJECT_EVENT_TIMEOUT,
Prabir Pradhan07e05b62021-11-19 03:57:24 -080012136 InputEventInjectionSync::WAIT_FOR_RESULT))
12137 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
Harry Cutts33476232023-01-30 19:57:29 +000012138 window->consumeMotionPointerDown(/*pointerIndex=*/1);
Prabir Pradhan07e05b62021-11-19 03:57:24 -080012139 spyRight->consumeMotionDown();
12140}
12141
Prabir Pradhan1376fcd2022-01-21 09:56:35 -080012142/**
12143 * The spy window should not be able to affect whether or not touches are split. Only the foreground
12144 * windows should be allowed to control split touch.
12145 */
12146TEST_F(InputDispatcherSpyWindowTest, SplitIfNoForegroundWindowTouched) {
Prabir Pradhan76bdecb2022-01-31 11:14:15 -080012147 // This spy window prevents touch splitting. However, we still expect to split touches
Prabir Pradhan1376fcd2022-01-21 09:56:35 -080012148 // because a foreground window has not disabled splitting.
Prabir Pradhan4d5c52f2022-01-31 08:52:10 -080012149 auto spy = createSpy();
Prabir Pradhan76bdecb2022-01-31 11:14:15 -080012150 spy->setPreventSplitting(true);
Prabir Pradhan1376fcd2022-01-21 09:56:35 -080012151
Prabir Pradhan1376fcd2022-01-21 09:56:35 -080012152 auto window = createForeground();
12153 window->setFrame(Rect(0, 0, 100, 100));
Prabir Pradhan1376fcd2022-01-21 09:56:35 -080012154
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070012155 mDispatcher->onWindowInfosChanged({{*spy->getInfo(), *window->getInfo()}, {}, 0, 0});
Prabir Pradhan1376fcd2022-01-21 09:56:35 -080012156
12157 // First finger down, no window touched.
12158 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070012159 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
Prabir Pradhan1376fcd2022-01-21 09:56:35 -080012160 {100, 200}))
12161 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
12162 spy->consumeMotionDown(ADISPLAY_ID_DEFAULT);
12163 window->assertNoEvents();
12164
12165 // Second finger down on window, the window should receive touch down.
12166 const MotionEvent secondFingerDownEvent =
Siarhei Vishniakoua16e3a22022-03-02 15:26:40 -080012167 MotionEventBuilder(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
Prabir Pradhan1376fcd2022-01-21 09:56:35 -080012168 .displayId(ADISPLAY_ID_DEFAULT)
12169 .eventTime(systemTime(SYSTEM_TIME_MONOTONIC))
Siarhei Vishniakou6d73f832022-07-21 17:27:03 -070012170 .pointer(PointerBuilder(/*id=*/0, ToolType::FINGER).x(100).y(200))
12171 .pointer(PointerBuilder(/*id=*/1, ToolType::FINGER).x(50).y(50))
Prabir Pradhan1376fcd2022-01-21 09:56:35 -080012172 .build();
12173 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070012174 injectMotionEvent(*mDispatcher, secondFingerDownEvent, INJECT_EVENT_TIMEOUT,
Prabir Pradhan1376fcd2022-01-21 09:56:35 -080012175 InputEventInjectionSync::WAIT_FOR_RESULT))
12176 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
12177
12178 window->consumeMotionDown(ADISPLAY_ID_DEFAULT);
Harry Cutts33476232023-01-30 19:57:29 +000012179 spy->consumeMotionPointerDown(/*pointerIndex=*/1);
Prabir Pradhan1376fcd2022-01-21 09:56:35 -080012180}
12181
12182/**
12183 * A spy window will usually be implemented as an un-focusable window. Verify that these windows
12184 * do not receive key events.
12185 */
12186TEST_F(InputDispatcherSpyWindowTest, UnfocusableSpyDoesNotReceiveKeyEvents) {
Prabir Pradhan4d5c52f2022-01-31 08:52:10 -080012187 auto spy = createSpy();
Prabir Pradhan1376fcd2022-01-21 09:56:35 -080012188 spy->setFocusable(false);
12189
12190 auto window = createForeground();
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070012191 mDispatcher->onWindowInfosChanged({{*spy->getInfo(), *window->getInfo()}, {}, 0, 0});
Prabir Pradhan1376fcd2022-01-21 09:56:35 -080012192 setFocusedWindow(window);
12193 window->consumeFocusEvent(true);
12194
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070012195 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectKeyDown(*mDispatcher))
Prabir Pradhan1376fcd2022-01-21 09:56:35 -080012196 << "Inject key event should return InputEventInjectionResult::SUCCEEDED";
12197 window->consumeKeyDown(ADISPLAY_ID_NONE);
12198
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070012199 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectKeyUp(*mDispatcher))
Prabir Pradhan1376fcd2022-01-21 09:56:35 -080012200 << "Inject key event should return InputEventInjectionResult::SUCCEEDED";
12201 window->consumeKeyUp(ADISPLAY_ID_NONE);
12202
12203 spy->assertNoEvents();
12204}
12205
Vaibhav Devmurariff798f32022-05-09 23:45:04 +000012206using InputDispatcherPilferPointersTest = InputDispatcherSpyWindowTest;
12207
12208/**
12209 * A spy window can pilfer pointers. When this happens, touch gestures used by the spy window that
12210 * are currently sent to any other windows - including other spy windows - will also be cancelled.
12211 */
12212TEST_F(InputDispatcherPilferPointersTest, PilferPointers) {
12213 auto window = createForeground();
12214 auto spy1 = createSpy();
12215 auto spy2 = createSpy();
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070012216 mDispatcher->onWindowInfosChanged(
12217 {{*spy1->getInfo(), *spy2->getInfo(), *window->getInfo()}, {}, 0, 0});
Vaibhav Devmurariff798f32022-05-09 23:45:04 +000012218
12219 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070012220 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT))
Vaibhav Devmurariff798f32022-05-09 23:45:04 +000012221 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
12222 window->consumeMotionDown();
12223 spy1->consumeMotionDown();
12224 spy2->consumeMotionDown();
12225
12226 // Pilfer pointers from the second spy window.
12227 EXPECT_EQ(OK, mDispatcher->pilferPointers(spy2->getToken()));
12228 spy2->assertNoEvents();
12229 spy1->consumeMotionCancel();
12230 window->consumeMotionCancel();
12231
12232 // The rest of the gesture should only be sent to the second spy window.
12233 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070012234 injectMotionEvent(*mDispatcher, AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN,
Vaibhav Devmurariff798f32022-05-09 23:45:04 +000012235 ADISPLAY_ID_DEFAULT))
12236 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
12237 spy2->consumeMotionMove();
12238 spy1->assertNoEvents();
12239 window->assertNoEvents();
12240}
12241
12242/**
12243 * A spy window can pilfer pointers for a gesture even after the foreground window has been removed
12244 * in the middle of the gesture.
12245 */
12246TEST_F(InputDispatcherPilferPointersTest, CanPilferAfterWindowIsRemovedMidStream) {
12247 auto window = createForeground();
12248 auto spy = createSpy();
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070012249 mDispatcher->onWindowInfosChanged({{*spy->getInfo(), *window->getInfo()}, {}, 0, 0});
Vaibhav Devmurariff798f32022-05-09 23:45:04 +000012250
12251 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070012252 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT))
Vaibhav Devmurariff798f32022-05-09 23:45:04 +000012253 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
12254 window->consumeMotionDown(ADISPLAY_ID_DEFAULT);
12255 spy->consumeMotionDown(ADISPLAY_ID_DEFAULT);
12256
12257 window->releaseChannel();
12258
12259 EXPECT_EQ(OK, mDispatcher->pilferPointers(spy->getToken()));
12260
12261 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070012262 injectMotionUp(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT))
Vaibhav Devmurariff798f32022-05-09 23:45:04 +000012263 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
12264 spy->consumeMotionUp(ADISPLAY_ID_DEFAULT);
12265}
12266
12267/**
12268 * After a spy window pilfers pointers, new pointers that go down in its bounds should be sent to
12269 * the spy, but not to any other windows.
12270 */
12271TEST_F(InputDispatcherPilferPointersTest, ContinuesToReceiveGestureAfterPilfer) {
12272 auto spy = createSpy();
12273 auto window = createForeground();
12274
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070012275 mDispatcher->onWindowInfosChanged({{*spy->getInfo(), *window->getInfo()}, {}, 0, 0});
Vaibhav Devmurariff798f32022-05-09 23:45:04 +000012276
12277 // First finger down on the window and the spy.
12278 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070012279 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
Vaibhav Devmurariff798f32022-05-09 23:45:04 +000012280 {100, 200}))
12281 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
12282 spy->consumeMotionDown();
12283 window->consumeMotionDown();
12284
12285 // Spy window pilfers the pointers.
12286 EXPECT_EQ(OK, mDispatcher->pilferPointers(spy->getToken()));
12287 window->consumeMotionCancel();
12288
12289 // Second finger down on the window and spy, but the window should not receive the pointer down.
12290 const MotionEvent secondFingerDownEvent =
12291 MotionEventBuilder(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
12292 .displayId(ADISPLAY_ID_DEFAULT)
12293 .eventTime(systemTime(SYSTEM_TIME_MONOTONIC))
Siarhei Vishniakou6d73f832022-07-21 17:27:03 -070012294 .pointer(PointerBuilder(/*id=*/0, ToolType::FINGER).x(100).y(200))
12295 .pointer(PointerBuilder(/*id=*/1, ToolType::FINGER).x(50).y(50))
Vaibhav Devmurariff798f32022-05-09 23:45:04 +000012296 .build();
12297 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070012298 injectMotionEvent(*mDispatcher, secondFingerDownEvent, INJECT_EVENT_TIMEOUT,
Vaibhav Devmurariff798f32022-05-09 23:45:04 +000012299 InputEventInjectionSync::WAIT_FOR_RESULT))
12300 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
12301
Harry Cutts33476232023-01-30 19:57:29 +000012302 spy->consumeMotionPointerDown(/*pointerIndex=*/1);
Vaibhav Devmurariff798f32022-05-09 23:45:04 +000012303
12304 // Third finger goes down outside all windows, so injection should fail.
12305 const MotionEvent thirdFingerDownEvent =
12306 MotionEventBuilder(POINTER_2_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
12307 .displayId(ADISPLAY_ID_DEFAULT)
12308 .eventTime(systemTime(SYSTEM_TIME_MONOTONIC))
Siarhei Vishniakou6d73f832022-07-21 17:27:03 -070012309 .pointer(PointerBuilder(/*id=*/0, ToolType::FINGER).x(100).y(200))
12310 .pointer(PointerBuilder(/*id=*/1, ToolType::FINGER).x(50).y(50))
12311 .pointer(PointerBuilder(/*id=*/2, ToolType::FINGER).x(-5).y(-5))
Vaibhav Devmurariff798f32022-05-09 23:45:04 +000012312 .build();
12313 ASSERT_EQ(InputEventInjectionResult::FAILED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070012314 injectMotionEvent(*mDispatcher, thirdFingerDownEvent, INJECT_EVENT_TIMEOUT,
Vaibhav Devmurariff798f32022-05-09 23:45:04 +000012315 InputEventInjectionSync::WAIT_FOR_RESULT))
Siarhei Vishniakou1ae72f12023-01-29 12:55:30 -080012316 << "Inject motion event should return InputEventInjectionResult::FAILED";
Vaibhav Devmurariff798f32022-05-09 23:45:04 +000012317
12318 spy->assertNoEvents();
12319 window->assertNoEvents();
12320}
12321
12322/**
12323 * After a spy window pilfers pointers, only the pointers used by the spy should be canceled
12324 */
12325TEST_F(InputDispatcherPilferPointersTest, PartiallyPilferRequiredPointers) {
12326 auto spy = createSpy();
12327 spy->setFrame(Rect(0, 0, 100, 100));
12328 auto window = createForeground();
12329 window->setFrame(Rect(0, 0, 200, 200));
12330
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070012331 mDispatcher->onWindowInfosChanged({{*spy->getInfo(), *window->getInfo()}, {}, 0, 0});
Vaibhav Devmurariff798f32022-05-09 23:45:04 +000012332
12333 // First finger down on the window only
12334 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070012335 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
Vaibhav Devmurariff798f32022-05-09 23:45:04 +000012336 {150, 150}))
12337 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
12338 window->consumeMotionDown();
12339
12340 // Second finger down on the spy and window
12341 const MotionEvent secondFingerDownEvent =
12342 MotionEventBuilder(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
12343 .displayId(ADISPLAY_ID_DEFAULT)
12344 .eventTime(systemTime(SYSTEM_TIME_MONOTONIC))
Siarhei Vishniakou6d73f832022-07-21 17:27:03 -070012345 .pointer(PointerBuilder(/*id=*/0, ToolType::FINGER).x(150).y(150))
12346 .pointer(PointerBuilder(/*id=*/1, ToolType::FINGER).x(10).y(10))
Vaibhav Devmurariff798f32022-05-09 23:45:04 +000012347 .build();
12348 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070012349 injectMotionEvent(*mDispatcher, secondFingerDownEvent, INJECT_EVENT_TIMEOUT,
Vaibhav Devmurariff798f32022-05-09 23:45:04 +000012350 InputEventInjectionSync::WAIT_FOR_RESULT))
12351 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
12352 spy->consumeMotionDown();
12353 window->consumeMotionPointerDown(1);
12354
12355 // Third finger down on the spy and window
12356 const MotionEvent thirdFingerDownEvent =
12357 MotionEventBuilder(POINTER_2_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
12358 .displayId(ADISPLAY_ID_DEFAULT)
12359 .eventTime(systemTime(SYSTEM_TIME_MONOTONIC))
Siarhei Vishniakou6d73f832022-07-21 17:27:03 -070012360 .pointer(PointerBuilder(/*id=*/0, ToolType::FINGER).x(150).y(150))
12361 .pointer(PointerBuilder(/*id=*/1, ToolType::FINGER).x(10).y(10))
12362 .pointer(PointerBuilder(/*id=*/2, ToolType::FINGER).x(50).y(50))
Vaibhav Devmurariff798f32022-05-09 23:45:04 +000012363 .build();
12364 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070012365 injectMotionEvent(*mDispatcher, thirdFingerDownEvent, INJECT_EVENT_TIMEOUT,
Vaibhav Devmurariff798f32022-05-09 23:45:04 +000012366 InputEventInjectionSync::WAIT_FOR_RESULT))
12367 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
12368 spy->consumeMotionPointerDown(1);
12369 window->consumeMotionPointerDown(2);
12370
12371 // Spy window pilfers the pointers.
12372 EXPECT_EQ(OK, mDispatcher->pilferPointers(spy->getToken()));
Harry Cutts101ee9b2023-07-06 18:04:14 +000012373 window->consumeMotionPointerUp(/*idx=*/2, ADISPLAY_ID_DEFAULT, AMOTION_EVENT_FLAG_CANCELED);
12374 window->consumeMotionPointerUp(/*idx=*/1, ADISPLAY_ID_DEFAULT, AMOTION_EVENT_FLAG_CANCELED);
Vaibhav Devmurariff798f32022-05-09 23:45:04 +000012375
12376 spy->assertNoEvents();
12377 window->assertNoEvents();
12378}
12379
12380/**
12381 * After a spy window pilfers pointers, all pilfered pointers that have already been dispatched to
12382 * other windows should be canceled. If this results in the cancellation of all pointers for some
12383 * window, then that window should receive ACTION_CANCEL.
12384 */
12385TEST_F(InputDispatcherPilferPointersTest, PilferAllRequiredPointers) {
12386 auto spy = createSpy();
12387 spy->setFrame(Rect(0, 0, 100, 100));
12388 auto window = createForeground();
12389 window->setFrame(Rect(0, 0, 200, 200));
12390
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070012391 mDispatcher->onWindowInfosChanged({{*spy->getInfo(), *window->getInfo()}, {}, 0, 0});
Vaibhav Devmurariff798f32022-05-09 23:45:04 +000012392
12393 // First finger down on both spy and window
12394 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070012395 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
Vaibhav Devmurariff798f32022-05-09 23:45:04 +000012396 {10, 10}))
12397 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
12398 window->consumeMotionDown();
12399 spy->consumeMotionDown();
12400
12401 // Second finger down on the spy and window
12402 const MotionEvent secondFingerDownEvent =
12403 MotionEventBuilder(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
12404 .displayId(ADISPLAY_ID_DEFAULT)
12405 .eventTime(systemTime(SYSTEM_TIME_MONOTONIC))
Siarhei Vishniakou6d73f832022-07-21 17:27:03 -070012406 .pointer(PointerBuilder(/*id=*/0, ToolType::FINGER).x(10).y(10))
12407 .pointer(PointerBuilder(/*id=*/1, ToolType::FINGER).x(50).y(50))
Vaibhav Devmurariff798f32022-05-09 23:45:04 +000012408 .build();
12409 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070012410 injectMotionEvent(*mDispatcher, secondFingerDownEvent, INJECT_EVENT_TIMEOUT,
Vaibhav Devmurariff798f32022-05-09 23:45:04 +000012411 InputEventInjectionSync::WAIT_FOR_RESULT))
12412 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
12413 spy->consumeMotionPointerDown(1);
12414 window->consumeMotionPointerDown(1);
12415
12416 // Spy window pilfers the pointers.
12417 EXPECT_EQ(OK, mDispatcher->pilferPointers(spy->getToken()));
12418 window->consumeMotionCancel();
12419
12420 spy->assertNoEvents();
12421 window->assertNoEvents();
12422}
12423
12424/**
12425 * After a spy window pilfers pointers, new pointers that are not touching the spy window can still
12426 * be sent to other windows
12427 */
12428TEST_F(InputDispatcherPilferPointersTest, CanReceivePointersAfterPilfer) {
12429 auto spy = createSpy();
12430 spy->setFrame(Rect(0, 0, 100, 100));
12431 auto window = createForeground();
12432 window->setFrame(Rect(0, 0, 200, 200));
12433
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070012434 mDispatcher->onWindowInfosChanged({{*spy->getInfo(), *window->getInfo()}, {}, 0, 0});
Vaibhav Devmurariff798f32022-05-09 23:45:04 +000012435
12436 // First finger down on both window and spy
12437 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070012438 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
Vaibhav Devmurariff798f32022-05-09 23:45:04 +000012439 {10, 10}))
12440 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
12441 window->consumeMotionDown();
12442 spy->consumeMotionDown();
12443
12444 // Spy window pilfers the pointers.
12445 EXPECT_EQ(OK, mDispatcher->pilferPointers(spy->getToken()));
12446 window->consumeMotionCancel();
12447
12448 // Second finger down on the window only
12449 const MotionEvent secondFingerDownEvent =
12450 MotionEventBuilder(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
12451 .displayId(ADISPLAY_ID_DEFAULT)
12452 .eventTime(systemTime(SYSTEM_TIME_MONOTONIC))
Siarhei Vishniakou6d73f832022-07-21 17:27:03 -070012453 .pointer(PointerBuilder(/*id=*/0, ToolType::FINGER).x(10).y(10))
12454 .pointer(PointerBuilder(/*id=*/1, ToolType::FINGER).x(150).y(150))
Vaibhav Devmurariff798f32022-05-09 23:45:04 +000012455 .build();
12456 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070012457 injectMotionEvent(*mDispatcher, secondFingerDownEvent, INJECT_EVENT_TIMEOUT,
Vaibhav Devmurariff798f32022-05-09 23:45:04 +000012458 InputEventInjectionSync::WAIT_FOR_RESULT))
12459 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
12460 window->consumeMotionDown();
12461 window->assertNoEvents();
12462
12463 // TODO(b/232530217): do not send the unnecessary MOVE event and delete the next line
12464 spy->consumeMotionMove();
12465 spy->assertNoEvents();
12466}
12467
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -070012468/**
12469 * A window on the left and a window on the right. Also, a spy window that's above all of the
12470 * windows, and spanning both left and right windows.
12471 * Send simultaneous motion streams from two different devices, one to the left window, and another
12472 * to the right window.
12473 * Pilfer from spy window.
12474 * Check that the pilfering only affects the pointers that are actually being received by the spy.
12475 */
Siarhei Vishniakoued89cbb2023-10-13 10:42:44 -070012476TEST_F(InputDispatcherPilferPointersTest, MultiDevicePilfer_legacy) {
12477 SCOPED_FLAG_OVERRIDE(enable_multi_device_same_window_stream, false);
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -070012478 sp<FakeWindowHandle> spy = createSpy();
12479 spy->setFrame(Rect(0, 0, 200, 200));
12480 sp<FakeWindowHandle> leftWindow = createForeground();
12481 leftWindow->setFrame(Rect(0, 0, 100, 100));
12482
12483 sp<FakeWindowHandle> rightWindow = createForeground();
12484 rightWindow->setFrame(Rect(100, 0, 200, 100));
12485
12486 constexpr int32_t stylusDeviceId = 1;
12487 constexpr int32_t touchDeviceId = 2;
12488
12489 mDispatcher->onWindowInfosChanged(
12490 {{*spy->getInfo(), *leftWindow->getInfo(), *rightWindow->getInfo()}, {}, 0, 0});
12491
12492 // Stylus down on left window and spy
12493 mDispatcher->notifyMotion(MotionArgsBuilder(AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_STYLUS)
12494 .deviceId(stylusDeviceId)
12495 .pointer(PointerBuilder(0, ToolType::STYLUS).x(50).y(50))
12496 .build());
12497 leftWindow->consumeMotionEvent(
12498 AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(stylusDeviceId)));
12499 spy->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(stylusDeviceId)));
12500
12501 // Finger down on right window and spy - but spy already has stylus
12502 mDispatcher->notifyMotion(
12503 MotionArgsBuilder(AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
12504 .deviceId(touchDeviceId)
12505 .pointer(PointerBuilder(0, ToolType::FINGER).x(150).y(50))
12506 .build());
12507 rightWindow->consumeMotionEvent(
12508 AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(touchDeviceId)));
Siarhei Vishniakou2899c552023-07-10 18:20:46 -070012509 spy->assertNoEvents();
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -070012510
12511 // Act: pilfer from spy. Spy is currently receiving touch events.
12512 EXPECT_EQ(OK, mDispatcher->pilferPointers(spy->getToken()));
Siarhei Vishniakou2899c552023-07-10 18:20:46 -070012513 leftWindow->consumeMotionEvent(
12514 AllOf(WithMotionAction(ACTION_CANCEL), WithDeviceId(stylusDeviceId)));
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -070012515 rightWindow->consumeMotionEvent(
12516 AllOf(WithMotionAction(ACTION_CANCEL), WithDeviceId(touchDeviceId)));
12517
12518 // Continue movements from both stylus and touch. Touch will be delivered to spy, but not stylus
12519 mDispatcher->notifyMotion(MotionArgsBuilder(AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_STYLUS)
12520 .deviceId(stylusDeviceId)
12521 .pointer(PointerBuilder(0, ToolType::STYLUS).x(51).y(52))
12522 .build());
12523 mDispatcher->notifyMotion(
12524 MotionArgsBuilder(AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN)
12525 .deviceId(touchDeviceId)
12526 .pointer(PointerBuilder(0, ToolType::FINGER).x(151).y(52))
12527 .build());
Siarhei Vishniakou2899c552023-07-10 18:20:46 -070012528 spy->consumeMotionEvent(AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(stylusDeviceId)));
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -070012529
12530 spy->assertNoEvents();
12531 leftWindow->assertNoEvents();
12532 rightWindow->assertNoEvents();
12533}
12534
Siarhei Vishniakoued89cbb2023-10-13 10:42:44 -070012535/**
12536 * A window on the left and a window on the right. Also, a spy window that's above all of the
12537 * windows, and spanning both left and right windows.
12538 * Send simultaneous motion streams from two different devices, one to the left window, and another
12539 * to the right window.
12540 * Pilfer from spy window.
12541 * Check that the pilfering affects all of the pointers that are actually being received by the spy.
12542 * The spy should receive both the touch and the stylus events after pilfer.
12543 */
12544TEST_F(InputDispatcherPilferPointersTest, MultiDevicePilfer) {
12545 SCOPED_FLAG_OVERRIDE(enable_multi_device_same_window_stream, true);
12546 sp<FakeWindowHandle> spy = createSpy();
12547 spy->setFrame(Rect(0, 0, 200, 200));
12548 sp<FakeWindowHandle> leftWindow = createForeground();
12549 leftWindow->setFrame(Rect(0, 0, 100, 100));
12550
12551 sp<FakeWindowHandle> rightWindow = createForeground();
12552 rightWindow->setFrame(Rect(100, 0, 200, 100));
12553
12554 constexpr int32_t stylusDeviceId = 1;
12555 constexpr int32_t touchDeviceId = 2;
12556
12557 mDispatcher->onWindowInfosChanged(
12558 {{*spy->getInfo(), *leftWindow->getInfo(), *rightWindow->getInfo()}, {}, 0, 0});
12559
12560 // Stylus down on left window and spy
12561 mDispatcher->notifyMotion(MotionArgsBuilder(AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_STYLUS)
12562 .deviceId(stylusDeviceId)
12563 .pointer(PointerBuilder(0, ToolType::STYLUS).x(50).y(50))
12564 .build());
12565 leftWindow->consumeMotionEvent(
12566 AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(stylusDeviceId)));
12567 spy->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(stylusDeviceId)));
12568
12569 // Finger down on right window and spy
12570 mDispatcher->notifyMotion(
12571 MotionArgsBuilder(AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
12572 .deviceId(touchDeviceId)
12573 .pointer(PointerBuilder(0, ToolType::FINGER).x(150).y(50))
12574 .build());
12575 rightWindow->consumeMotionEvent(
12576 AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(touchDeviceId)));
12577 spy->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(touchDeviceId)));
12578
12579 // Act: pilfer from spy. Spy is currently receiving touch events.
12580 EXPECT_EQ(OK, mDispatcher->pilferPointers(spy->getToken()));
12581 leftWindow->consumeMotionEvent(
12582 AllOf(WithMotionAction(ACTION_CANCEL), WithDeviceId(stylusDeviceId)));
12583 rightWindow->consumeMotionEvent(
12584 AllOf(WithMotionAction(ACTION_CANCEL), WithDeviceId(touchDeviceId)));
12585
12586 // Continue movements from both stylus and touch. Touch and stylus will be delivered to spy
Siarhei Vishniakou92bca1c2024-04-01 14:06:59 -070012587 // Instead of sending the two MOVE events for each input device together, and then receiving
12588 // them both, process them one at at time. InputConsumer is always in the batching mode, which
12589 // means that the two MOVE events will be initially put into a batch. Once the events are
12590 // batched, the 'consume' call may result in any of the MOVE events to be sent first (depending
12591 // on the implementation of InputConsumer), which would mean that the order of the received
12592 // events could be different depending on whether there are 1 or 2 events pending in the
12593 // InputChannel at the time the test calls 'consume'. To make assertions simpler here, and to
12594 // avoid this confusing behaviour, send and receive each MOVE event separately.
Siarhei Vishniakoued89cbb2023-10-13 10:42:44 -070012595 mDispatcher->notifyMotion(MotionArgsBuilder(AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_STYLUS)
12596 .deviceId(stylusDeviceId)
12597 .pointer(PointerBuilder(0, ToolType::STYLUS).x(51).y(52))
12598 .build());
Siarhei Vishniakou92bca1c2024-04-01 14:06:59 -070012599 spy->consumeMotionEvent(AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(stylusDeviceId)));
Siarhei Vishniakoued89cbb2023-10-13 10:42:44 -070012600 mDispatcher->notifyMotion(
12601 MotionArgsBuilder(AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN)
12602 .deviceId(touchDeviceId)
12603 .pointer(PointerBuilder(0, ToolType::FINGER).x(151).y(52))
12604 .build());
Siarhei Vishniakou92bca1c2024-04-01 14:06:59 -070012605 spy->consumeMotionEvent(AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(touchDeviceId)));
Siarhei Vishniakoued89cbb2023-10-13 10:42:44 -070012606
12607 spy->assertNoEvents();
12608 leftWindow->assertNoEvents();
12609 rightWindow->assertNoEvents();
12610}
12611
Prabir Pradhan9cd9eb62023-11-22 17:58:06 +000012612TEST_F(InputDispatcherPilferPointersTest, NoPilferingWithHoveringPointers) {
12613 auto window = createForeground();
12614 auto spy = createSpy();
12615 mDispatcher->onWindowInfosChanged({{*spy->getInfo(), *window->getInfo()}, {}, 0, 0});
12616
12617 mDispatcher->notifyMotion(
12618 MotionArgsBuilder(ACTION_HOVER_ENTER, AINPUT_SOURCE_MOUSE)
12619 .deviceId(1)
12620 .pointer(PointerBuilder(/*id=*/0, ToolType::MOUSE).x(100).y(200))
12621 .build());
12622 window->consumeMotionEvent(WithMotionAction(ACTION_HOVER_ENTER));
12623 spy->consumeMotionEvent(WithMotionAction(ACTION_HOVER_ENTER));
12624
12625 // Pilfer pointers from the spy window should fail.
12626 EXPECT_NE(OK, mDispatcher->pilferPointers(spy->getToken()));
12627 spy->assertNoEvents();
12628 window->assertNoEvents();
12629}
12630
Prabir Pradhand65552b2021-10-07 11:23:50 -070012631class InputDispatcherStylusInterceptorTest : public InputDispatcherTest {
12632public:
12633 std::pair<sp<FakeWindowHandle>, sp<FakeWindowHandle>> setupStylusOverlayScenario() {
12634 std::shared_ptr<FakeApplicationHandle> overlayApplication =
12635 std::make_shared<FakeApplicationHandle>();
12636 sp<FakeWindowHandle> overlay =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -070012637 sp<FakeWindowHandle>::make(overlayApplication, mDispatcher,
12638 "Stylus interceptor window", ADISPLAY_ID_DEFAULT);
Prabir Pradhand65552b2021-10-07 11:23:50 -070012639 overlay->setFocusable(false);
Prabir Pradhanaeebeb42023-06-13 19:53:03 +000012640 overlay->setOwnerInfo(gui::Pid{111}, gui::Uid{111});
Prabir Pradhan4d5c52f2022-01-31 08:52:10 -080012641 overlay->setTouchable(false);
Prabir Pradhan51e7db02022-02-07 06:02:57 -080012642 overlay->setInterceptsStylus(true);
Prabir Pradhand65552b2021-10-07 11:23:50 -070012643 overlay->setTrustedOverlay(true);
12644
12645 std::shared_ptr<FakeApplicationHandle> application =
12646 std::make_shared<FakeApplicationHandle>();
12647 sp<FakeWindowHandle> window =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -070012648 sp<FakeWindowHandle>::make(application, mDispatcher, "Application window",
12649 ADISPLAY_ID_DEFAULT);
Prabir Pradhand65552b2021-10-07 11:23:50 -070012650 window->setFocusable(true);
Prabir Pradhanaeebeb42023-06-13 19:53:03 +000012651 window->setOwnerInfo(gui::Pid{222}, gui::Uid{222});
Prabir Pradhand65552b2021-10-07 11:23:50 -070012652
12653 mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070012654 mDispatcher->onWindowInfosChanged({{*overlay->getInfo(), *window->getInfo()}, {}, 0, 0});
Prabir Pradhand65552b2021-10-07 11:23:50 -070012655 setFocusedWindow(window);
Harry Cutts33476232023-01-30 19:57:29 +000012656 window->consumeFocusEvent(/*hasFocus=*/true, /*inTouchMode=*/true);
Prabir Pradhand65552b2021-10-07 11:23:50 -070012657 return {std::move(overlay), std::move(window)};
12658 }
12659
12660 void sendFingerEvent(int32_t action) {
Prabir Pradhan678438e2023-04-13 19:32:51 +000012661 mDispatcher->notifyMotion(
Prabir Pradhand65552b2021-10-07 11:23:50 -070012662 generateMotionArgs(action, AINPUT_SOURCE_TOUCHSCREEN | AINPUT_SOURCE_STYLUS,
Prabir Pradhan678438e2023-04-13 19:32:51 +000012663 ADISPLAY_ID_DEFAULT, {PointF{20, 20}}));
Prabir Pradhand65552b2021-10-07 11:23:50 -070012664 }
12665
12666 void sendStylusEvent(int32_t action) {
12667 NotifyMotionArgs motionArgs =
12668 generateMotionArgs(action, AINPUT_SOURCE_TOUCHSCREEN | AINPUT_SOURCE_STYLUS,
12669 ADISPLAY_ID_DEFAULT, {PointF{30, 40}});
Siarhei Vishniakou6d73f832022-07-21 17:27:03 -070012670 motionArgs.pointerProperties[0].toolType = ToolType::STYLUS;
Prabir Pradhan678438e2023-04-13 19:32:51 +000012671 mDispatcher->notifyMotion(motionArgs);
Prabir Pradhand65552b2021-10-07 11:23:50 -070012672 }
12673};
12674
Prabir Pradhana3ab87a2022-01-27 10:00:21 -080012675using InputDispatcherStylusInterceptorDeathTest = InputDispatcherStylusInterceptorTest;
12676
12677TEST_F(InputDispatcherStylusInterceptorDeathTest, UntrustedOverlay_AbortsDispatcher) {
Siarhei Vishniakouad3b6822023-06-22 14:17:35 -070012678 testing::GTEST_FLAG(death_test_style) = "threadsafe";
Prabir Pradhana3ab87a2022-01-27 10:00:21 -080012679 ScopedSilentDeath _silentDeath;
12680
Prabir Pradhand65552b2021-10-07 11:23:50 -070012681 auto [overlay, window] = setupStylusOverlayScenario();
12682 overlay->setTrustedOverlay(false);
12683 // Configuring an untrusted overlay as a stylus interceptor should cause Dispatcher to abort.
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070012684 ASSERT_DEATH(mDispatcher->onWindowInfosChanged(
12685 {{*overlay->getInfo(), *window->getInfo()}, {}, 0, 0}),
Prabir Pradhand65552b2021-10-07 11:23:50 -070012686 ".* not a trusted overlay");
12687}
12688
12689TEST_F(InputDispatcherStylusInterceptorTest, ConsmesOnlyStylusEvents) {
12690 auto [overlay, window] = setupStylusOverlayScenario();
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070012691 mDispatcher->onWindowInfosChanged({{*overlay->getInfo(), *window->getInfo()}, {}, 0, 0});
Prabir Pradhand65552b2021-10-07 11:23:50 -070012692
12693 sendStylusEvent(AMOTION_EVENT_ACTION_DOWN);
12694 overlay->consumeMotionDown();
12695 sendStylusEvent(AMOTION_EVENT_ACTION_UP);
12696 overlay->consumeMotionUp();
12697
12698 sendFingerEvent(AMOTION_EVENT_ACTION_DOWN);
12699 window->consumeMotionDown();
12700 sendFingerEvent(AMOTION_EVENT_ACTION_UP);
12701 window->consumeMotionUp();
12702
12703 overlay->assertNoEvents();
12704 window->assertNoEvents();
12705}
12706
12707TEST_F(InputDispatcherStylusInterceptorTest, SpyWindowStylusInterceptor) {
12708 auto [overlay, window] = setupStylusOverlayScenario();
Prabir Pradhan51e7db02022-02-07 06:02:57 -080012709 overlay->setSpy(true);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070012710 mDispatcher->onWindowInfosChanged({{*overlay->getInfo(), *window->getInfo()}, {}, 0, 0});
Prabir Pradhand65552b2021-10-07 11:23:50 -070012711
12712 sendStylusEvent(AMOTION_EVENT_ACTION_DOWN);
12713 overlay->consumeMotionDown();
12714 window->consumeMotionDown();
12715 sendStylusEvent(AMOTION_EVENT_ACTION_UP);
12716 overlay->consumeMotionUp();
12717 window->consumeMotionUp();
12718
12719 sendFingerEvent(AMOTION_EVENT_ACTION_DOWN);
12720 window->consumeMotionDown();
12721 sendFingerEvent(AMOTION_EVENT_ACTION_UP);
12722 window->consumeMotionUp();
12723
12724 overlay->assertNoEvents();
12725 window->assertNoEvents();
12726}
12727
Prabir Pradhan6dfbf262022-03-14 15:24:30 +000012728/**
12729 * Set up a scenario to test the behavior used by the stylus handwriting detection feature.
12730 * The scenario is as follows:
12731 * - The stylus interceptor overlay is configured as a spy window.
12732 * - The stylus interceptor spy receives the start of a new stylus gesture.
12733 * - It pilfers pointers and then configures itself to no longer be a spy.
12734 * - The stylus interceptor continues to receive the rest of the gesture.
12735 */
12736TEST_F(InputDispatcherStylusInterceptorTest, StylusHandwritingScenario) {
12737 auto [overlay, window] = setupStylusOverlayScenario();
12738 overlay->setSpy(true);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070012739 mDispatcher->onWindowInfosChanged({{*overlay->getInfo(), *window->getInfo()}, {}, 0, 0});
Prabir Pradhan6dfbf262022-03-14 15:24:30 +000012740
12741 sendStylusEvent(AMOTION_EVENT_ACTION_DOWN);
12742 overlay->consumeMotionDown();
12743 window->consumeMotionDown();
12744
12745 // The interceptor pilfers the pointers.
12746 EXPECT_EQ(OK, mDispatcher->pilferPointers(overlay->getToken()));
12747 window->consumeMotionCancel();
12748
12749 // The interceptor configures itself so that it is no longer a spy.
12750 overlay->setSpy(false);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070012751 mDispatcher->onWindowInfosChanged({{*overlay->getInfo(), *window->getInfo()}, {}, 0, 0});
Prabir Pradhan6dfbf262022-03-14 15:24:30 +000012752
12753 // It continues to receive the rest of the stylus gesture.
12754 sendStylusEvent(AMOTION_EVENT_ACTION_MOVE);
12755 overlay->consumeMotionMove();
12756 sendStylusEvent(AMOTION_EVENT_ACTION_UP);
12757 overlay->consumeMotionUp();
12758
12759 window->assertNoEvents();
12760}
12761
Prabir Pradhan5735a322022-04-11 17:23:34 +000012762struct User {
Prabir Pradhanaeebeb42023-06-13 19:53:03 +000012763 gui::Pid mPid;
Prabir Pradhan8a5c41d2023-06-08 19:13:46 +000012764 gui::Uid mUid;
Prabir Pradhan5735a322022-04-11 17:23:34 +000012765 uint32_t mPolicyFlags{DEFAULT_POLICY_FLAGS};
12766 std::unique_ptr<InputDispatcher>& mDispatcher;
12767
Prabir Pradhanaeebeb42023-06-13 19:53:03 +000012768 User(std::unique_ptr<InputDispatcher>& dispatcher, gui::Pid pid, gui::Uid uid)
Prabir Pradhan5735a322022-04-11 17:23:34 +000012769 : mPid(pid), mUid(uid), mDispatcher(dispatcher) {}
12770
12771 InputEventInjectionResult injectTargetedMotion(int32_t action) const {
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070012772 return injectMotionEvent(*mDispatcher, action, AINPUT_SOURCE_TOUCHSCREEN,
Prabir Pradhan5735a322022-04-11 17:23:34 +000012773 ADISPLAY_ID_DEFAULT, {100, 200},
12774 {AMOTION_EVENT_INVALID_CURSOR_POSITION,
12775 AMOTION_EVENT_INVALID_CURSOR_POSITION},
12776 INJECT_EVENT_TIMEOUT, InputEventInjectionSync::WAIT_FOR_RESULT,
12777 systemTime(SYSTEM_TIME_MONOTONIC), {mUid}, mPolicyFlags);
12778 }
12779
12780 InputEventInjectionResult injectTargetedKey(int32_t action) const {
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070012781 return inputdispatcher::injectKey(*mDispatcher, action, /*repeatCount=*/0, ADISPLAY_ID_NONE,
Prabir Pradhan5735a322022-04-11 17:23:34 +000012782 InputEventInjectionSync::WAIT_FOR_RESULT,
Harry Cutts33476232023-01-30 19:57:29 +000012783 INJECT_EVENT_TIMEOUT, /*allowKeyRepeat=*/false, {mUid},
Prabir Pradhan5735a322022-04-11 17:23:34 +000012784 mPolicyFlags);
12785 }
12786
Siarhei Vishniakoue3ce4122023-08-23 10:26:46 -070012787 sp<FakeWindowHandle> createWindow(const char* name) const {
Prabir Pradhan5735a322022-04-11 17:23:34 +000012788 std::shared_ptr<FakeApplicationHandle> overlayApplication =
12789 std::make_shared<FakeApplicationHandle>();
Siarhei Vishniakoue3ce4122023-08-23 10:26:46 -070012790 sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(overlayApplication, mDispatcher,
12791 name, ADISPLAY_ID_DEFAULT);
Prabir Pradhan5735a322022-04-11 17:23:34 +000012792 window->setOwnerInfo(mPid, mUid);
12793 return window;
12794 }
12795};
12796
12797using InputDispatcherTargetedInjectionTest = InputDispatcherTest;
12798
12799TEST_F(InputDispatcherTargetedInjectionTest, CanInjectIntoOwnedWindow) {
Prabir Pradhanaeebeb42023-06-13 19:53:03 +000012800 auto owner = User(mDispatcher, gui::Pid{10}, gui::Uid{11});
Siarhei Vishniakoue3ce4122023-08-23 10:26:46 -070012801 auto window = owner.createWindow("Owned window");
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070012802 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Prabir Pradhan5735a322022-04-11 17:23:34 +000012803
12804 EXPECT_EQ(InputEventInjectionResult::SUCCEEDED,
12805 owner.injectTargetedMotion(AMOTION_EVENT_ACTION_DOWN));
12806 window->consumeMotionDown();
12807
12808 setFocusedWindow(window);
12809 window->consumeFocusEvent(true);
12810
12811 EXPECT_EQ(InputEventInjectionResult::SUCCEEDED,
12812 owner.injectTargetedKey(AKEY_EVENT_ACTION_DOWN));
12813 window->consumeKeyDown(ADISPLAY_ID_NONE);
12814}
12815
12816TEST_F(InputDispatcherTargetedInjectionTest, CannotInjectIntoUnownedWindow) {
Prabir Pradhanaeebeb42023-06-13 19:53:03 +000012817 auto owner = User(mDispatcher, gui::Pid{10}, gui::Uid{11});
Siarhei Vishniakoue3ce4122023-08-23 10:26:46 -070012818 auto window = owner.createWindow("Owned window");
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070012819 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Prabir Pradhan5735a322022-04-11 17:23:34 +000012820
Prabir Pradhanaeebeb42023-06-13 19:53:03 +000012821 auto rando = User(mDispatcher, gui::Pid{20}, gui::Uid{21});
Prabir Pradhan5735a322022-04-11 17:23:34 +000012822 EXPECT_EQ(InputEventInjectionResult::TARGET_MISMATCH,
12823 rando.injectTargetedMotion(AMOTION_EVENT_ACTION_DOWN));
12824
12825 setFocusedWindow(window);
12826 window->consumeFocusEvent(true);
12827
12828 EXPECT_EQ(InputEventInjectionResult::TARGET_MISMATCH,
12829 rando.injectTargetedKey(AKEY_EVENT_ACTION_DOWN));
12830 window->assertNoEvents();
12831}
12832
12833TEST_F(InputDispatcherTargetedInjectionTest, CanInjectIntoOwnedSpyWindow) {
Prabir Pradhanaeebeb42023-06-13 19:53:03 +000012834 auto owner = User(mDispatcher, gui::Pid{10}, gui::Uid{11});
Siarhei Vishniakoue3ce4122023-08-23 10:26:46 -070012835 auto window = owner.createWindow("Owned window");
12836 auto spy = owner.createWindow("Owned spy");
Prabir Pradhan5735a322022-04-11 17:23:34 +000012837 spy->setSpy(true);
12838 spy->setTrustedOverlay(true);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070012839 mDispatcher->onWindowInfosChanged({{*spy->getInfo(), *window->getInfo()}, {}, 0, 0});
Prabir Pradhan5735a322022-04-11 17:23:34 +000012840
12841 EXPECT_EQ(InputEventInjectionResult::SUCCEEDED,
12842 owner.injectTargetedMotion(AMOTION_EVENT_ACTION_DOWN));
12843 spy->consumeMotionDown();
12844 window->consumeMotionDown();
12845}
12846
12847TEST_F(InputDispatcherTargetedInjectionTest, CannotInjectIntoUnownedSpyWindow) {
Prabir Pradhanaeebeb42023-06-13 19:53:03 +000012848 auto owner = User(mDispatcher, gui::Pid{10}, gui::Uid{11});
Siarhei Vishniakoue3ce4122023-08-23 10:26:46 -070012849 auto window = owner.createWindow("Owned window");
Prabir Pradhan5735a322022-04-11 17:23:34 +000012850
Prabir Pradhanaeebeb42023-06-13 19:53:03 +000012851 auto rando = User(mDispatcher, gui::Pid{20}, gui::Uid{21});
Siarhei Vishniakoue3ce4122023-08-23 10:26:46 -070012852 auto randosSpy = rando.createWindow("Rando's spy");
Prabir Pradhan5735a322022-04-11 17:23:34 +000012853 randosSpy->setSpy(true);
12854 randosSpy->setTrustedOverlay(true);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070012855 mDispatcher->onWindowInfosChanged({{*randosSpy->getInfo(), *window->getInfo()}, {}, 0, 0});
Prabir Pradhan5735a322022-04-11 17:23:34 +000012856
12857 // The event is targeted at owner's window, so injection should succeed, but the spy should
12858 // not receive the event.
12859 EXPECT_EQ(InputEventInjectionResult::SUCCEEDED,
12860 owner.injectTargetedMotion(AMOTION_EVENT_ACTION_DOWN));
12861 randosSpy->assertNoEvents();
12862 window->consumeMotionDown();
12863}
12864
12865TEST_F(InputDispatcherTargetedInjectionTest, CanInjectIntoAnyWindowWhenNotTargeting) {
Prabir Pradhanaeebeb42023-06-13 19:53:03 +000012866 auto owner = User(mDispatcher, gui::Pid{10}, gui::Uid{11});
Siarhei Vishniakoue3ce4122023-08-23 10:26:46 -070012867 auto window = owner.createWindow("Owned window");
Prabir Pradhan5735a322022-04-11 17:23:34 +000012868
Prabir Pradhanaeebeb42023-06-13 19:53:03 +000012869 auto rando = User(mDispatcher, gui::Pid{20}, gui::Uid{21});
Siarhei Vishniakoue3ce4122023-08-23 10:26:46 -070012870 auto randosSpy = rando.createWindow("Rando's spy");
Prabir Pradhan5735a322022-04-11 17:23:34 +000012871 randosSpy->setSpy(true);
12872 randosSpy->setTrustedOverlay(true);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070012873 mDispatcher->onWindowInfosChanged({{*randosSpy->getInfo(), *window->getInfo()}, {}, 0, 0});
Prabir Pradhan5735a322022-04-11 17:23:34 +000012874
12875 // A user that has injection permission can inject into any window.
12876 EXPECT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070012877 injectMotionEvent(*mDispatcher, AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN,
Prabir Pradhan5735a322022-04-11 17:23:34 +000012878 ADISPLAY_ID_DEFAULT));
12879 randosSpy->consumeMotionDown();
12880 window->consumeMotionDown();
12881
12882 setFocusedWindow(randosSpy);
12883 randosSpy->consumeFocusEvent(true);
12884
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070012885 EXPECT_EQ(InputEventInjectionResult::SUCCEEDED, injectKeyDown(*mDispatcher));
Prabir Pradhan5735a322022-04-11 17:23:34 +000012886 randosSpy->consumeKeyDown(ADISPLAY_ID_NONE);
12887 window->assertNoEvents();
12888}
12889
Siarhei Vishniakou580fb3a2023-05-05 15:02:20 -070012890TEST_F(InputDispatcherTargetedInjectionTest, CannotGenerateActionOutsideToOtherUids) {
Prabir Pradhanaeebeb42023-06-13 19:53:03 +000012891 auto owner = User(mDispatcher, gui::Pid{10}, gui::Uid{11});
Siarhei Vishniakoue3ce4122023-08-23 10:26:46 -070012892 auto window = owner.createWindow("Owned window");
Prabir Pradhan5735a322022-04-11 17:23:34 +000012893
Prabir Pradhanaeebeb42023-06-13 19:53:03 +000012894 auto rando = User(mDispatcher, gui::Pid{20}, gui::Uid{21});
Siarhei Vishniakoue3ce4122023-08-23 10:26:46 -070012895 auto randosWindow = rando.createWindow("Rando's window");
Prabir Pradhan5735a322022-04-11 17:23:34 +000012896 randosWindow->setFrame(Rect{-10, -10, -5, -5});
12897 randosWindow->setWatchOutsideTouch(true);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070012898 mDispatcher->onWindowInfosChanged({{*randosWindow->getInfo(), *window->getInfo()}, {}, 0, 0});
Prabir Pradhan5735a322022-04-11 17:23:34 +000012899
Siarhei Vishniakou580fb3a2023-05-05 15:02:20 -070012900 // Do not allow generation of ACTION_OUTSIDE events into windows owned by different uids.
Prabir Pradhan5735a322022-04-11 17:23:34 +000012901 EXPECT_EQ(InputEventInjectionResult::SUCCEEDED,
12902 owner.injectTargetedMotion(AMOTION_EVENT_ACTION_DOWN));
12903 window->consumeMotionDown();
Siarhei Vishniakou580fb3a2023-05-05 15:02:20 -070012904 randosWindow->assertNoEvents();
Prabir Pradhan5735a322022-04-11 17:23:34 +000012905}
12906
Prabir Pradhan64f21d22023-11-28 21:19:42 +000012907using InputDispatcherPointerInWindowTest = InputDispatcherTest;
12908
12909TEST_F(InputDispatcherPointerInWindowTest, PointerInWindowWhenHovering) {
12910 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
12911
12912 sp<FakeWindowHandle> left = sp<FakeWindowHandle>::make(application, mDispatcher, "Left Window",
12913 ADISPLAY_ID_DEFAULT);
12914 left->setFrame(Rect(0, 0, 100, 100));
12915 sp<FakeWindowHandle> right = sp<FakeWindowHandle>::make(application, mDispatcher,
12916 "Right Window", ADISPLAY_ID_DEFAULT);
12917 right->setFrame(Rect(100, 0, 200, 100));
12918 sp<FakeWindowHandle> spy =
12919 sp<FakeWindowHandle>::make(application, mDispatcher, "Spy Window", ADISPLAY_ID_DEFAULT);
12920 spy->setFrame(Rect(0, 0, 200, 100));
12921 spy->setTrustedOverlay(true);
12922 spy->setSpy(true);
12923
12924 mDispatcher->onWindowInfosChanged(
12925 {{*spy->getInfo(), *left->getInfo(), *right->getInfo()}, {}, 0, 0});
12926
12927 // Hover into the left window.
12928 mDispatcher->notifyMotion(
12929 MotionArgsBuilder(ACTION_HOVER_ENTER, AINPUT_SOURCE_STYLUS)
12930 .pointer(PointerBuilder(/*id=*/0, ToolType::STYLUS).x(50).y(50))
12931 .build());
12932
12933 left->consumeMotionEvent(WithMotionAction(ACTION_HOVER_ENTER));
12934 spy->consumeMotionEvent(WithMotionAction(ACTION_HOVER_ENTER));
12935
12936 ASSERT_TRUE(mDispatcher->isPointerInWindow(left->getToken(), ADISPLAY_ID_DEFAULT, DEVICE_ID,
12937 /*pointerId=*/0));
12938 ASSERT_TRUE(mDispatcher->isPointerInWindow(spy->getToken(), ADISPLAY_ID_DEFAULT, DEVICE_ID,
12939 /*pointerId=*/0));
12940 ASSERT_FALSE(mDispatcher->isPointerInWindow(right->getToken(), ADISPLAY_ID_DEFAULT, DEVICE_ID,
12941 /*pointerId=*/0));
12942
12943 // Hover move to the right window.
12944 mDispatcher->notifyMotion(
12945 MotionArgsBuilder(ACTION_HOVER_MOVE, AINPUT_SOURCE_STYLUS)
12946 .pointer(PointerBuilder(/*id=*/0, ToolType::STYLUS).x(150).y(50))
12947 .build());
12948
12949 left->consumeMotionEvent(WithMotionAction(ACTION_HOVER_EXIT));
12950 right->consumeMotionEvent(WithMotionAction(ACTION_HOVER_ENTER));
12951 spy->consumeMotionEvent(WithMotionAction(ACTION_HOVER_MOVE));
12952
12953 ASSERT_FALSE(mDispatcher->isPointerInWindow(left->getToken(), ADISPLAY_ID_DEFAULT, DEVICE_ID,
12954 /*pointerId=*/0));
12955 ASSERT_TRUE(mDispatcher->isPointerInWindow(spy->getToken(), ADISPLAY_ID_DEFAULT, DEVICE_ID,
12956 /*pointerId=*/0));
12957 ASSERT_TRUE(mDispatcher->isPointerInWindow(right->getToken(), ADISPLAY_ID_DEFAULT, DEVICE_ID,
12958 /*pointerId=*/0));
12959
12960 // Stop hovering.
12961 mDispatcher->notifyMotion(
12962 MotionArgsBuilder(ACTION_HOVER_EXIT, AINPUT_SOURCE_STYLUS)
12963 .pointer(PointerBuilder(/*id=*/0, ToolType::STYLUS).x(150).y(50))
12964 .build());
12965
12966 right->consumeMotionEvent(WithMotionAction(ACTION_HOVER_EXIT));
12967 spy->consumeMotionEvent(WithMotionAction(ACTION_HOVER_EXIT));
12968
12969 ASSERT_FALSE(mDispatcher->isPointerInWindow(left->getToken(), ADISPLAY_ID_DEFAULT, DEVICE_ID,
12970 /*pointerId=*/0));
12971 ASSERT_FALSE(mDispatcher->isPointerInWindow(spy->getToken(), ADISPLAY_ID_DEFAULT, DEVICE_ID,
12972 /*pointerId=*/0));
12973 ASSERT_FALSE(mDispatcher->isPointerInWindow(right->getToken(), ADISPLAY_ID_DEFAULT, DEVICE_ID,
12974 /*pointerId=*/0));
12975}
12976
12977TEST_F(InputDispatcherPointerInWindowTest, PointerInWindowWithSplitTouch) {
12978 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
12979
12980 sp<FakeWindowHandle> left = sp<FakeWindowHandle>::make(application, mDispatcher, "Left Window",
12981 ADISPLAY_ID_DEFAULT);
12982 left->setFrame(Rect(0, 0, 100, 100));
12983 sp<FakeWindowHandle> right = sp<FakeWindowHandle>::make(application, mDispatcher,
12984 "Right Window", ADISPLAY_ID_DEFAULT);
12985 right->setFrame(Rect(100, 0, 200, 100));
12986 sp<FakeWindowHandle> spy =
12987 sp<FakeWindowHandle>::make(application, mDispatcher, "Spy Window", ADISPLAY_ID_DEFAULT);
12988 spy->setFrame(Rect(0, 0, 200, 100));
12989 spy->setTrustedOverlay(true);
12990 spy->setSpy(true);
12991
12992 mDispatcher->onWindowInfosChanged(
12993 {{*spy->getInfo(), *left->getInfo(), *right->getInfo()}, {}, 0, 0});
12994
12995 // First pointer down on left window.
12996 mDispatcher->notifyMotion(
12997 MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
12998 .pointer(PointerBuilder(/*id=*/0, ToolType::FINGER).x(50).y(50))
12999 .build());
13000
13001 left->consumeMotionDown();
13002 spy->consumeMotionDown();
13003
13004 ASSERT_TRUE(mDispatcher->isPointerInWindow(left->getToken(), ADISPLAY_ID_DEFAULT, DEVICE_ID,
13005 /*pointerId=*/0));
13006 ASSERT_TRUE(mDispatcher->isPointerInWindow(spy->getToken(), ADISPLAY_ID_DEFAULT, DEVICE_ID,
13007 /*pointerId=*/0));
13008 ASSERT_FALSE(mDispatcher->isPointerInWindow(right->getToken(), ADISPLAY_ID_DEFAULT, DEVICE_ID,
13009 /*pointerId=*/0));
13010
13011 // Second pointer down on right window.
13012 mDispatcher->notifyMotion(
13013 MotionArgsBuilder(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
13014 .pointer(PointerBuilder(/*id=*/0, ToolType::FINGER).x(50).y(50))
13015 .pointer(PointerBuilder(/*id=*/1, ToolType::FINGER).x(150).y(50))
13016 .build());
13017
13018 left->consumeMotionMove();
13019 right->consumeMotionDown();
13020 spy->consumeMotionEvent(WithMotionAction(POINTER_1_DOWN));
13021
13022 ASSERT_TRUE(mDispatcher->isPointerInWindow(left->getToken(), ADISPLAY_ID_DEFAULT, DEVICE_ID,
13023 /*pointerId=*/0));
13024 ASSERT_TRUE(mDispatcher->isPointerInWindow(spy->getToken(), ADISPLAY_ID_DEFAULT, DEVICE_ID,
13025 /*pointerId=*/0));
13026 ASSERT_FALSE(mDispatcher->isPointerInWindow(right->getToken(), ADISPLAY_ID_DEFAULT, DEVICE_ID,
13027 /*pointerId=*/0));
13028 ASSERT_FALSE(mDispatcher->isPointerInWindow(left->getToken(), ADISPLAY_ID_DEFAULT, DEVICE_ID,
13029 /*pointerId=*/1));
13030 ASSERT_TRUE(mDispatcher->isPointerInWindow(spy->getToken(), ADISPLAY_ID_DEFAULT, DEVICE_ID,
13031 /*pointerId=*/1));
13032 ASSERT_TRUE(mDispatcher->isPointerInWindow(right->getToken(), ADISPLAY_ID_DEFAULT, DEVICE_ID,
13033 /*pointerId=*/1));
13034
13035 // Second pointer up.
13036 mDispatcher->notifyMotion(
13037 MotionArgsBuilder(POINTER_1_UP, AINPUT_SOURCE_TOUCHSCREEN)
13038 .pointer(PointerBuilder(/*id=*/0, ToolType::FINGER).x(50).y(50))
13039 .pointer(PointerBuilder(/*id=*/1, ToolType::FINGER).x(150).y(50))
13040 .build());
13041
13042 left->consumeMotionMove();
13043 right->consumeMotionUp();
13044 spy->consumeMotionEvent(WithMotionAction(POINTER_1_UP));
13045
13046 ASSERT_TRUE(mDispatcher->isPointerInWindow(left->getToken(), ADISPLAY_ID_DEFAULT, DEVICE_ID,
13047 /*pointerId=*/0));
13048 ASSERT_TRUE(mDispatcher->isPointerInWindow(spy->getToken(), ADISPLAY_ID_DEFAULT, DEVICE_ID,
13049 /*pointerId=*/0));
13050 ASSERT_FALSE(mDispatcher->isPointerInWindow(right->getToken(), ADISPLAY_ID_DEFAULT, DEVICE_ID,
13051 /*pointerId=*/0));
13052 ASSERT_FALSE(mDispatcher->isPointerInWindow(left->getToken(), ADISPLAY_ID_DEFAULT, DEVICE_ID,
13053 /*pointerId=*/1));
13054 ASSERT_FALSE(mDispatcher->isPointerInWindow(spy->getToken(), ADISPLAY_ID_DEFAULT, DEVICE_ID,
13055 /*pointerId=*/1));
13056 ASSERT_FALSE(mDispatcher->isPointerInWindow(right->getToken(), ADISPLAY_ID_DEFAULT, DEVICE_ID,
13057 /*pointerId=*/1));
13058
13059 // First pointer up.
13060 mDispatcher->notifyMotion(
13061 MotionArgsBuilder(ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN)
13062 .pointer(PointerBuilder(/*id=*/0, ToolType::FINGER).x(50).y(50))
13063 .build());
13064
13065 left->consumeMotionUp();
13066 spy->consumeMotionUp();
13067
13068 ASSERT_FALSE(mDispatcher->isPointerInWindow(left->getToken(), ADISPLAY_ID_DEFAULT, DEVICE_ID,
13069 /*pointerId=*/0));
13070 ASSERT_FALSE(mDispatcher->isPointerInWindow(spy->getToken(), ADISPLAY_ID_DEFAULT, DEVICE_ID,
13071 /*pointerId=*/0));
13072 ASSERT_FALSE(mDispatcher->isPointerInWindow(right->getToken(), ADISPLAY_ID_DEFAULT, DEVICE_ID,
13073 /*pointerId=*/0));
13074}
13075
Siarhei Vishniakoued89cbb2023-10-13 10:42:44 -070013076TEST_F(InputDispatcherPointerInWindowTest, MultipleDevicesControllingOneMouse_legacy) {
13077 SCOPED_FLAG_OVERRIDE(enable_multi_device_same_window_stream, false);
Prabir Pradhan64f21d22023-11-28 21:19:42 +000013078 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
13079
13080 sp<FakeWindowHandle> left = sp<FakeWindowHandle>::make(application, mDispatcher, "Left Window",
13081 ADISPLAY_ID_DEFAULT);
13082 left->setFrame(Rect(0, 0, 100, 100));
13083 sp<FakeWindowHandle> right = sp<FakeWindowHandle>::make(application, mDispatcher,
13084 "Right Window", ADISPLAY_ID_DEFAULT);
13085 right->setFrame(Rect(100, 0, 200, 100));
13086
13087 mDispatcher->onWindowInfosChanged({{*left->getInfo(), *right->getInfo()}, {}, 0, 0});
13088
13089 ASSERT_FALSE(mDispatcher->isPointerInWindow(left->getToken(), ADISPLAY_ID_DEFAULT, DEVICE_ID,
13090 /*pointerId=*/0));
13091 ASSERT_FALSE(mDispatcher->isPointerInWindow(right->getToken(), ADISPLAY_ID_DEFAULT, DEVICE_ID,
13092 /*pointerId=*/0));
13093
13094 // Hover move into the window.
13095 mDispatcher->notifyMotion(
13096 MotionArgsBuilder(ACTION_HOVER_MOVE, AINPUT_SOURCE_MOUSE)
13097 .pointer(PointerBuilder(/*id=*/0, ToolType::MOUSE).x(50).y(50))
13098 .rawXCursorPosition(50)
13099 .rawYCursorPosition(50)
13100 .deviceId(DEVICE_ID)
13101 .build());
13102
13103 left->consumeMotionEvent(WithMotionAction(ACTION_HOVER_ENTER));
13104
13105 ASSERT_TRUE(mDispatcher->isPointerInWindow(left->getToken(), ADISPLAY_ID_DEFAULT, DEVICE_ID,
13106 /*pointerId=*/0));
13107
13108 // Move the mouse with another device. This cancels the hovering pointer from the first device.
13109 mDispatcher->notifyMotion(
13110 MotionArgsBuilder(ACTION_HOVER_MOVE, AINPUT_SOURCE_MOUSE)
13111 .pointer(PointerBuilder(/*id=*/0, ToolType::MOUSE).x(51).y(50))
13112 .rawXCursorPosition(51)
13113 .rawYCursorPosition(50)
13114 .deviceId(SECOND_DEVICE_ID)
13115 .build());
13116
13117 left->consumeMotionEvent(WithMotionAction(ACTION_HOVER_EXIT));
13118 left->consumeMotionEvent(WithMotionAction(ACTION_HOVER_ENTER));
13119
13120 // TODO(b/313689709): InputDispatcher's touch state is not updated, even though the window gets
13121 // a HOVER_EXIT from the first device.
13122 ASSERT_TRUE(mDispatcher->isPointerInWindow(left->getToken(), ADISPLAY_ID_DEFAULT, DEVICE_ID,
13123 /*pointerId=*/0));
13124 ASSERT_TRUE(mDispatcher->isPointerInWindow(left->getToken(), ADISPLAY_ID_DEFAULT,
13125 SECOND_DEVICE_ID,
13126 /*pointerId=*/0));
13127
13128 // Move the mouse outside the window. Document the current behavior, where the window does not
13129 // receive HOVER_EXIT even though the mouse left the window.
13130 mDispatcher->notifyMotion(
13131 MotionArgsBuilder(ACTION_HOVER_MOVE, AINPUT_SOURCE_MOUSE)
13132 .pointer(PointerBuilder(/*id=*/0, ToolType::MOUSE).x(150).y(50))
13133 .rawXCursorPosition(150)
13134 .rawYCursorPosition(50)
13135 .deviceId(SECOND_DEVICE_ID)
13136 .build());
13137
13138 left->consumeMotionEvent(WithMotionAction(ACTION_HOVER_EXIT));
13139 right->consumeMotionEvent(WithMotionAction(ACTION_HOVER_ENTER));
13140 ASSERT_TRUE(mDispatcher->isPointerInWindow(left->getToken(), ADISPLAY_ID_DEFAULT, DEVICE_ID,
13141 /*pointerId=*/0));
13142 ASSERT_FALSE(mDispatcher->isPointerInWindow(left->getToken(), ADISPLAY_ID_DEFAULT,
13143 SECOND_DEVICE_ID,
13144 /*pointerId=*/0));
13145}
13146
Siarhei Vishniakoued89cbb2023-10-13 10:42:44 -070013147/**
13148 * TODO(b/313689709) - correctly support multiple mouse devices, because they should be controlling
13149 * the same cursor, and therefore have a shared motion event stream.
13150 */
13151TEST_F(InputDispatcherPointerInWindowTest, MultipleDevicesControllingOneMouse) {
13152 SCOPED_FLAG_OVERRIDE(enable_multi_device_same_window_stream, true);
13153 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
13154
13155 sp<FakeWindowHandle> left = sp<FakeWindowHandle>::make(application, mDispatcher, "Left Window",
13156 ADISPLAY_ID_DEFAULT);
13157 left->setFrame(Rect(0, 0, 100, 100));
13158 sp<FakeWindowHandle> right = sp<FakeWindowHandle>::make(application, mDispatcher,
13159 "Right Window", ADISPLAY_ID_DEFAULT);
13160 right->setFrame(Rect(100, 0, 200, 100));
13161
13162 mDispatcher->onWindowInfosChanged({{*left->getInfo(), *right->getInfo()}, {}, 0, 0});
13163
13164 ASSERT_FALSE(mDispatcher->isPointerInWindow(left->getToken(), ADISPLAY_ID_DEFAULT, DEVICE_ID,
13165 /*pointerId=*/0));
13166 ASSERT_FALSE(mDispatcher->isPointerInWindow(right->getToken(), ADISPLAY_ID_DEFAULT, DEVICE_ID,
13167 /*pointerId=*/0));
13168
13169 // Hover move into the window.
13170 mDispatcher->notifyMotion(
13171 MotionArgsBuilder(ACTION_HOVER_MOVE, AINPUT_SOURCE_MOUSE)
13172 .pointer(PointerBuilder(/*id=*/0, ToolType::MOUSE).x(50).y(50))
13173 .rawXCursorPosition(50)
13174 .rawYCursorPosition(50)
13175 .deviceId(DEVICE_ID)
13176 .build());
13177
13178 left->consumeMotionEvent(WithMotionAction(ACTION_HOVER_ENTER));
13179
13180 ASSERT_TRUE(mDispatcher->isPointerInWindow(left->getToken(), ADISPLAY_ID_DEFAULT, DEVICE_ID,
13181 /*pointerId=*/0));
13182
13183 // Move the mouse with another device
13184 mDispatcher->notifyMotion(
13185 MotionArgsBuilder(ACTION_HOVER_MOVE, AINPUT_SOURCE_MOUSE)
13186 .pointer(PointerBuilder(/*id=*/0, ToolType::MOUSE).x(51).y(50))
13187 .rawXCursorPosition(51)
13188 .rawYCursorPosition(50)
13189 .deviceId(SECOND_DEVICE_ID)
13190 .build());
13191 left->consumeMotionEvent(WithMotionAction(ACTION_HOVER_ENTER));
13192
13193 // TODO(b/313689709): InputDispatcher's touch state is not updated, even though the window gets
13194 // a HOVER_EXIT from the first device.
13195 ASSERT_TRUE(mDispatcher->isPointerInWindow(left->getToken(), ADISPLAY_ID_DEFAULT, DEVICE_ID,
13196 /*pointerId=*/0));
13197 ASSERT_TRUE(mDispatcher->isPointerInWindow(left->getToken(), ADISPLAY_ID_DEFAULT,
13198 SECOND_DEVICE_ID,
13199 /*pointerId=*/0));
13200
13201 // Move the mouse outside the window. Document the current behavior, where the window does not
13202 // receive HOVER_EXIT even though the mouse left the window.
13203 mDispatcher->notifyMotion(
13204 MotionArgsBuilder(ACTION_HOVER_MOVE, AINPUT_SOURCE_MOUSE)
13205 .pointer(PointerBuilder(/*id=*/0, ToolType::MOUSE).x(150).y(50))
13206 .rawXCursorPosition(150)
13207 .rawYCursorPosition(50)
13208 .deviceId(SECOND_DEVICE_ID)
13209 .build());
13210
13211 right->consumeMotionEvent(WithMotionAction(ACTION_HOVER_ENTER));
13212 ASSERT_TRUE(mDispatcher->isPointerInWindow(left->getToken(), ADISPLAY_ID_DEFAULT, DEVICE_ID,
13213 /*pointerId=*/0));
13214 ASSERT_FALSE(mDispatcher->isPointerInWindow(left->getToken(), ADISPLAY_ID_DEFAULT,
13215 SECOND_DEVICE_ID,
13216 /*pointerId=*/0));
13217}
13218
Garfield Tane84e6f92019-08-29 17:28:41 -070013219} // namespace android::inputdispatcher