blob: 09b358afe5c40bfa005ad4b26bda55cc8fc596ad [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
Linnan Li72352222024-04-12 18:55:57 +0800120static constexpr int EXPECTED_WALLPAPER_FLAGS =
Arthur Hungc539dbb2022-12-08 07:45:36 +0000121 AMOTION_EVENT_FLAG_WINDOW_IS_OBSCURED | AMOTION_EVENT_FLAG_WINDOW_IS_PARTIALLY_OBSCURED;
122
Siarhei Vishniakou56e79092023-02-21 19:13:16 -0800123using ReservedInputDeviceId::VIRTUAL_KEYBOARD_ID;
124
Gang Wang342c9272020-01-13 13:15:04 -0500125/**
126 * Return a DOWN key event with KEYCODE_A.
127 */
128static KeyEvent getTestKeyEvent() {
129 KeyEvent event;
130
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();
Linnan Li72352222024-04-12 18:55:57 +0800830 wallpaperWindow->consumeMotionDown(ADISPLAY_ID_DEFAULT, EXPECTED_WALLPAPER_FLAGS);
Siarhei Vishniakouca205502021-07-16 21:31:58 +0000831
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));
Linnan Li72352222024-04-12 18:55:57 +0800840 wallpaperWindow->consumeMotionMove(ADISPLAY_ID_DEFAULT, EXPECTED_WALLPAPER_FLAGS);
Siarhei Vishniakouca205502021-07-16 21:31:58 +0000841
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.
Linnan Li72352222024-04-12 18:55:57 +0800846 wallpaperWindow->consumeMotionCancel(ADISPLAY_ID_DEFAULT, EXPECTED_WALLPAPER_FLAGS);
Siarhei Vishniakouca205502021-07-16 21:31:58 +0000847}
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();
Linnan Li72352222024-04-12 18:55:57 +0800911 wallpaperWindow->consumeMotionDown(ADISPLAY_ID_DEFAULT, EXPECTED_WALLPAPER_FLAGS);
Siarhei Vishniakou2b030972021-11-18 10:01:27 -0800912
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();
Linnan Li72352222024-04-12 18:55:57 +0800919 wallpaperWindow->consumeMotionMove(ADISPLAY_ID_DEFAULT, EXPECTED_WALLPAPER_FLAGS);
Siarhei Vishniakou2b030972021-11-18 10:01:27 -0800920
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
Linnan Li72352222024-04-12 18:55:57 +0800931/**
932 * Two windows: left and right, and a separate wallpaper window underneath each. Device A sends a
933 * down event to the left window. Device B sends a down event to the right window. Next, the right
934 * window disappears. Both the right window and its wallpaper window should receive cancel event.
935 * The left window and its wallpaper window should not receive any events.
936 */
937TEST_F(InputDispatcherTest, MultiDeviceDisappearingWindowWithWallpaperWindows) {
938 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
939 sp<FakeWindowHandle> leftForegroundWindow =
940 sp<FakeWindowHandle>::make(application, mDispatcher, "Left foreground window",
941 ADISPLAY_ID_DEFAULT);
942 leftForegroundWindow->setFrame(Rect(0, 0, 100, 100));
943 leftForegroundWindow->setDupTouchToWallpaper(true);
944 sp<FakeWindowHandle> leftWallpaperWindow =
945 sp<FakeWindowHandle>::make(application, mDispatcher, "Left wallpaper window",
946 ADISPLAY_ID_DEFAULT);
947 leftWallpaperWindow->setFrame(Rect(0, 0, 100, 100));
948 leftWallpaperWindow->setIsWallpaper(true);
949
950 sp<FakeWindowHandle> rightForegroundWindow =
951 sp<FakeWindowHandle>::make(application, mDispatcher, "Right foreground window",
952 ADISPLAY_ID_DEFAULT);
953 rightForegroundWindow->setFrame(Rect(100, 0, 200, 100));
954 rightForegroundWindow->setDupTouchToWallpaper(true);
955 sp<FakeWindowHandle> rightWallpaperWindow =
956 sp<FakeWindowHandle>::make(application, mDispatcher, "Right wallpaper window",
957 ADISPLAY_ID_DEFAULT);
958 rightWallpaperWindow->setFrame(Rect(100, 0, 200, 100));
959 rightWallpaperWindow->setIsWallpaper(true);
960
961 mDispatcher->onWindowInfosChanged(
962 {{*leftForegroundWindow->getInfo(), *leftWallpaperWindow->getInfo(),
963 *rightForegroundWindow->getInfo(), *rightWallpaperWindow->getInfo()},
964 {},
965 0,
966 0});
967
968 const DeviceId deviceA = 9;
969 const DeviceId deviceB = 3;
970 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
971 .pointer(PointerBuilder(0, ToolType::FINGER).x(50).y(50))
972 .deviceId(deviceA)
973 .build());
974 leftForegroundWindow->consumeMotionEvent(
975 AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(deviceA)));
976 leftWallpaperWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN),
977 WithDeviceId(deviceA),
978 WithFlags(EXPECTED_WALLPAPER_FLAGS)));
979
980 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
981 .pointer(PointerBuilder(0, ToolType::FINGER).x(150).y(50))
982 .deviceId(deviceB)
983 .build());
984 rightForegroundWindow->consumeMotionEvent(
985 AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(deviceB)));
986 rightWallpaperWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN),
987 WithDeviceId(deviceB),
988 WithFlags(EXPECTED_WALLPAPER_FLAGS)));
989
990 // Now right foreground window disappears, but right wallpaper window remains.
991 mDispatcher->onWindowInfosChanged(
992 {{*leftForegroundWindow->getInfo(), *leftWallpaperWindow->getInfo(),
993 *rightWallpaperWindow->getInfo()},
994 {},
995 0,
996 0});
997
998 // Left foreground window and left wallpaper window still exist, and should not receive any
999 // events.
1000 leftForegroundWindow->assertNoEvents();
1001 leftWallpaperWindow->assertNoEvents();
1002 // Since right foreground window disappeared, right wallpaper window and right foreground window
1003 // should receive cancel events.
1004 rightForegroundWindow->consumeMotionEvent(
1005 AllOf(WithMotionAction(ACTION_CANCEL), WithDeviceId(deviceB)));
1006 rightWallpaperWindow->consumeMotionEvent(
1007 AllOf(WithMotionAction(ACTION_CANCEL), WithDeviceId(deviceB),
1008 WithFlags(EXPECTED_WALLPAPER_FLAGS | AMOTION_EVENT_FLAG_CANCELED)));
1009}
1010
1011/**
1012 * Three windows arranged horizontally and without any overlap. Every window has a
1013 * wallpaper window underneath. The middle window also has SLIPPERY flag.
1014 * Device A sends a down event to the left window. Device B sends a down event to the middle window.
1015 * Next, device B sends move event to the right window. Touch for device B should slip from the
1016 * middle window to the right window. Also, the right wallpaper window should receive a down event.
1017 * The middle window and its wallpaper window should receive a cancel event. The left window should
1018 * not receive any events. If device B continues to report events, the right window and its
1019 * wallpaper window should receive remaining events.
1020 */
1021TEST_F(InputDispatcherTest, MultiDeviceSlipperyTouchWithWallpaperWindow) {
1022 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
1023 sp<FakeWindowHandle> leftForegroundWindow =
1024 sp<FakeWindowHandle>::make(application, mDispatcher, "Left foreground window",
1025 ADISPLAY_ID_DEFAULT);
1026 leftForegroundWindow->setFrame(Rect(0, 0, 100, 100));
1027 leftForegroundWindow->setDupTouchToWallpaper(true);
1028 sp<FakeWindowHandle> leftWallpaperWindow =
1029 sp<FakeWindowHandle>::make(application, mDispatcher, "Left wallpaper window",
1030 ADISPLAY_ID_DEFAULT);
1031 leftWallpaperWindow->setFrame(Rect(0, 0, 100, 100));
1032 leftWallpaperWindow->setIsWallpaper(true);
1033
1034 sp<FakeWindowHandle> middleForegroundWindow =
1035 sp<FakeWindowHandle>::make(application, mDispatcher, "Middle foreground window",
1036 ADISPLAY_ID_DEFAULT);
1037 middleForegroundWindow->setFrame(Rect(100, 0, 200, 100));
1038 middleForegroundWindow->setDupTouchToWallpaper(true);
1039 middleForegroundWindow->setSlippery(true);
1040 sp<FakeWindowHandle> middleWallpaperWindow =
1041 sp<FakeWindowHandle>::make(application, mDispatcher, "Middle wallpaper window",
1042 ADISPLAY_ID_DEFAULT);
1043 middleWallpaperWindow->setFrame(Rect(100, 0, 200, 100));
1044 middleWallpaperWindow->setIsWallpaper(true);
1045
1046 sp<FakeWindowHandle> rightForegroundWindow =
1047 sp<FakeWindowHandle>::make(application, mDispatcher, "Right foreground window",
1048 ADISPLAY_ID_DEFAULT);
1049 rightForegroundWindow->setFrame(Rect(200, 0, 300, 100));
1050 rightForegroundWindow->setDupTouchToWallpaper(true);
1051 sp<FakeWindowHandle> rightWallpaperWindow =
1052 sp<FakeWindowHandle>::make(application, mDispatcher, "Right wallpaper window",
1053 ADISPLAY_ID_DEFAULT);
1054 rightWallpaperWindow->setFrame(Rect(200, 0, 300, 100));
1055 rightWallpaperWindow->setIsWallpaper(true);
1056
1057 mDispatcher->onWindowInfosChanged(
1058 {{*leftForegroundWindow->getInfo(), *leftWallpaperWindow->getInfo(),
1059 *middleForegroundWindow->getInfo(), *middleWallpaperWindow->getInfo(),
1060 *rightForegroundWindow->getInfo(), *rightWallpaperWindow->getInfo()},
1061 {},
1062 0,
1063 0});
1064
1065 const DeviceId deviceA = 9;
1066 const DeviceId deviceB = 3;
1067 // Device A sends a DOWN event to the left window
1068 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
1069 .pointer(PointerBuilder(0, ToolType::FINGER).x(50).y(50))
1070 .deviceId(deviceA)
1071 .build());
1072 leftForegroundWindow->consumeMotionEvent(
1073 AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(deviceA)));
1074 leftWallpaperWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN),
1075 WithDeviceId(deviceA),
1076 WithFlags(EXPECTED_WALLPAPER_FLAGS)));
1077 // Device B sends a DOWN event to the middle window
1078 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
1079 .pointer(PointerBuilder(0, ToolType::FINGER).x(150).y(50))
1080 .deviceId(deviceB)
1081 .build());
1082 middleForegroundWindow->consumeMotionEvent(
1083 AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(deviceB)));
1084 middleWallpaperWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN),
1085 WithDeviceId(deviceB),
1086 WithFlags(EXPECTED_WALLPAPER_FLAGS)));
1087 // Move the events of device B to the top of the right window.
1088 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN)
1089 .pointer(PointerBuilder(0, ToolType::FINGER).x(250).y(50))
1090 .deviceId(deviceB)
1091 .build());
1092 middleForegroundWindow->consumeMotionEvent(
1093 AllOf(WithMotionAction(ACTION_CANCEL), WithDeviceId(deviceB)));
1094 middleWallpaperWindow->consumeMotionEvent(
1095 AllOf(WithMotionAction(ACTION_CANCEL), WithDeviceId(deviceB),
1096 WithFlags(EXPECTED_WALLPAPER_FLAGS | AMOTION_EVENT_FLAG_CANCELED)));
1097 rightForegroundWindow->consumeMotionEvent(
1098 AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(deviceB)));
1099 rightWallpaperWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN),
1100 WithDeviceId(deviceB),
1101 WithFlags(EXPECTED_WALLPAPER_FLAGS)));
1102 // Make sure the window on the right can receive the remaining events.
1103 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN)
1104 .pointer(PointerBuilder(0, ToolType::FINGER).x(251).y(51))
1105 .deviceId(deviceB)
1106 .build());
1107 leftForegroundWindow->assertNoEvents();
1108 leftWallpaperWindow->assertNoEvents();
1109 middleForegroundWindow->assertNoEvents();
1110 middleWallpaperWindow->assertNoEvents();
1111 rightForegroundWindow->consumeMotionEvent(
1112 AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(deviceB)));
1113 rightWallpaperWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_MOVE),
1114 WithDeviceId(deviceB),
1115 WithFlags(EXPECTED_WALLPAPER_FLAGS)));
1116}
1117
1118/**
1119 * Similar to the test above, we have three windows, they are arranged horizontally and without any
1120 * overlap, and every window has a wallpaper window. The middle window is a simple window, without
1121 * any special flags. Device A reports a down event that lands in left window. Device B sends a down
1122 * event to the middle window and then touch is transferred from the middle window to the right
1123 * window. The right window and its wallpaper window should receive a down event. The middle window
1124 * and its wallpaper window should receive a cancel event. The left window should not receive any
1125 * events. Subsequent events reported by device B should go to the right window and its wallpaper.
1126 */
1127TEST_F(InputDispatcherTest, MultiDeviceTouchTransferWithWallpaperWindows) {
1128 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
1129 sp<FakeWindowHandle> leftForegroundWindow =
1130 sp<FakeWindowHandle>::make(application, mDispatcher, "Left foreground window",
1131 ADISPLAY_ID_DEFAULT);
1132 leftForegroundWindow->setFrame(Rect(0, 0, 100, 100));
1133 leftForegroundWindow->setDupTouchToWallpaper(true);
1134 sp<FakeWindowHandle> leftWallpaperWindow =
1135 sp<FakeWindowHandle>::make(application, mDispatcher, "Left wallpaper window",
1136 ADISPLAY_ID_DEFAULT);
1137 leftWallpaperWindow->setFrame(Rect(0, 0, 100, 100));
1138 leftWallpaperWindow->setIsWallpaper(true);
1139
1140 sp<FakeWindowHandle> middleForegroundWindow =
1141 sp<FakeWindowHandle>::make(application, mDispatcher, "Middle foreground window",
1142 ADISPLAY_ID_DEFAULT);
1143 middleForegroundWindow->setFrame(Rect(100, 0, 200, 100));
1144 middleForegroundWindow->setDupTouchToWallpaper(true);
1145 sp<FakeWindowHandle> middleWallpaperWindow =
1146 sp<FakeWindowHandle>::make(application, mDispatcher, "Middle wallpaper window",
1147 ADISPLAY_ID_DEFAULT);
1148 middleWallpaperWindow->setFrame(Rect(100, 0, 200, 100));
1149 middleWallpaperWindow->setIsWallpaper(true);
1150
1151 sp<FakeWindowHandle> rightForegroundWindow =
1152 sp<FakeWindowHandle>::make(application, mDispatcher, "Right foreground window",
1153 ADISPLAY_ID_DEFAULT);
1154 rightForegroundWindow->setFrame(Rect(200, 0, 300, 100));
1155 rightForegroundWindow->setDupTouchToWallpaper(true);
1156 sp<FakeWindowHandle> rightWallpaperWindow =
1157 sp<FakeWindowHandle>::make(application, mDispatcher, "Right wallpaper window",
1158 ADISPLAY_ID_DEFAULT);
1159 rightWallpaperWindow->setFrame(Rect(200, 0, 300, 100));
1160 rightWallpaperWindow->setIsWallpaper(true);
1161
1162 mDispatcher->onWindowInfosChanged(
1163 {{*leftForegroundWindow->getInfo(), *leftWallpaperWindow->getInfo(),
1164 *middleForegroundWindow->getInfo(), *middleWallpaperWindow->getInfo(),
1165 *rightForegroundWindow->getInfo(), *rightWallpaperWindow->getInfo()},
1166 {},
1167 0,
1168 0});
1169
1170 const DeviceId deviceA = 9;
1171 const DeviceId deviceB = 3;
1172 // Device A touch down on the left window
1173 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
1174 .pointer(PointerBuilder(0, ToolType::FINGER).x(50).y(50))
1175 .deviceId(deviceA)
1176 .build());
1177 leftForegroundWindow->consumeMotionEvent(
1178 AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(deviceA)));
1179 leftWallpaperWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN),
1180 WithDeviceId(deviceA),
1181 WithFlags(EXPECTED_WALLPAPER_FLAGS)));
1182 // Device B touch down on the middle window
1183 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
1184 .pointer(PointerBuilder(0, ToolType::FINGER).x(150).y(50))
1185 .deviceId(deviceB)
1186 .build());
1187 middleForegroundWindow->consumeMotionEvent(
1188 AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(deviceB)));
1189 middleWallpaperWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN),
1190 WithDeviceId(deviceB),
1191 WithFlags(EXPECTED_WALLPAPER_FLAGS)));
1192
1193 // Transfer touch from the middle window to the right window.
1194 ASSERT_TRUE(mDispatcher->transferTouchGesture(middleForegroundWindow->getToken(),
1195 rightForegroundWindow->getToken()));
1196
1197 middleForegroundWindow->consumeMotionEvent(
1198 AllOf(WithMotionAction(ACTION_CANCEL), WithDeviceId(deviceB)));
1199 middleWallpaperWindow->consumeMotionEvent(
1200 AllOf(WithMotionAction(ACTION_CANCEL), WithDeviceId(deviceB),
1201 WithFlags(EXPECTED_WALLPAPER_FLAGS | AMOTION_EVENT_FLAG_CANCELED)));
1202 rightForegroundWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN),
1203 WithDeviceId(deviceB),
1204 WithFlags(AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE)));
1205 rightWallpaperWindow->consumeMotionEvent(
1206 AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(deviceB),
1207 WithFlags(EXPECTED_WALLPAPER_FLAGS | AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE)));
1208
1209 // Make sure the right window can receive the remaining events.
1210 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN)
1211 .pointer(PointerBuilder(0, ToolType::FINGER).x(251).y(51))
1212 .deviceId(deviceB)
1213 .build());
1214 leftForegroundWindow->assertNoEvents();
1215 leftWallpaperWindow->assertNoEvents();
1216 middleForegroundWindow->assertNoEvents();
1217 middleWallpaperWindow->assertNoEvents();
1218 rightForegroundWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_MOVE),
1219 WithDeviceId(deviceB),
1220 WithFlags(AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE)));
1221 rightWallpaperWindow->consumeMotionEvent(
1222 AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(deviceB),
1223 WithFlags(EXPECTED_WALLPAPER_FLAGS | AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE)));
1224}
1225
Arthur Hungc539dbb2022-12-08 07:45:36 +00001226class ShouldSplitTouchFixture : public InputDispatcherTest,
1227 public ::testing::WithParamInterface<bool> {};
1228INSTANTIATE_TEST_SUITE_P(InputDispatcherTest, ShouldSplitTouchFixture,
1229 ::testing::Values(true, false));
Siarhei Vishniakou2b030972021-11-18 10:01:27 -08001230/**
Siarhei Vishniakouca205502021-07-16 21:31:58 +00001231 * A single window that receives touch (on top), and a wallpaper window underneath it.
1232 * The top window gets a multitouch gesture.
1233 * Ensure that wallpaper gets the same gesture.
1234 */
Arthur Hungc539dbb2022-12-08 07:45:36 +00001235TEST_P(ShouldSplitTouchFixture, WallpaperWindowReceivesMultiTouch) {
Siarhei Vishniakouca205502021-07-16 21:31:58 +00001236 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
Arthur Hungc539dbb2022-12-08 07:45:36 +00001237 sp<FakeWindowHandle> foregroundWindow =
1238 sp<FakeWindowHandle>::make(application, mDispatcher, "Foreground", ADISPLAY_ID_DEFAULT);
1239 foregroundWindow->setDupTouchToWallpaper(true);
1240 foregroundWindow->setPreventSplitting(GetParam());
Siarhei Vishniakouca205502021-07-16 21:31:58 +00001241
1242 sp<FakeWindowHandle> wallpaperWindow =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07001243 sp<FakeWindowHandle>::make(application, mDispatcher, "Wallpaper", ADISPLAY_ID_DEFAULT);
Prabir Pradhan4d5c52f2022-01-31 08:52:10 -08001244 wallpaperWindow->setIsWallpaper(true);
Siarhei Vishniakouca205502021-07-16 21:31:58 +00001245
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07001246 mDispatcher->onWindowInfosChanged(
1247 {{*foregroundWindow->getInfo(), *wallpaperWindow->getInfo()}, {}, 0, 0});
Siarhei Vishniakouca205502021-07-16 21:31:58 +00001248
1249 // Touch down on top window
1250 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07001251 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
Siarhei Vishniakouca205502021-07-16 21:31:58 +00001252 {100, 100}))
1253 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
1254
1255 // Both top window and its wallpaper should receive the touch down
Arthur Hungc539dbb2022-12-08 07:45:36 +00001256 foregroundWindow->consumeMotionDown();
Linnan Li72352222024-04-12 18:55:57 +08001257 wallpaperWindow->consumeMotionDown(ADISPLAY_ID_DEFAULT, EXPECTED_WALLPAPER_FLAGS);
Siarhei Vishniakouca205502021-07-16 21:31:58 +00001258
1259 // Second finger down on the top window
1260 const MotionEvent secondFingerDownEvent =
Siarhei Vishniakoua16e3a22022-03-02 15:26:40 -08001261 MotionEventBuilder(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
Siarhei Vishniakouca205502021-07-16 21:31:58 +00001262 .eventTime(systemTime(SYSTEM_TIME_MONOTONIC))
Siarhei Vishniakou6d73f832022-07-21 17:27:03 -07001263 .pointer(PointerBuilder(/*id=*/0, ToolType::FINGER).x(100).y(100))
1264 .pointer(PointerBuilder(/*id=*/1, ToolType::FINGER).x(150).y(150))
Siarhei Vishniakouca205502021-07-16 21:31:58 +00001265 .build();
1266 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07001267 injectMotionEvent(*mDispatcher, secondFingerDownEvent, INJECT_EVENT_TIMEOUT,
Siarhei Vishniakouca205502021-07-16 21:31:58 +00001268 InputEventInjectionSync::WAIT_FOR_RESULT))
1269 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
1270
Harry Cutts33476232023-01-30 19:57:29 +00001271 foregroundWindow->consumeMotionPointerDown(/*pointerIndex=*/1);
1272 wallpaperWindow->consumeMotionPointerDown(/*pointerIndex=*/1, ADISPLAY_ID_DEFAULT,
Linnan Li72352222024-04-12 18:55:57 +08001273 EXPECTED_WALLPAPER_FLAGS);
Arthur Hungc539dbb2022-12-08 07:45:36 +00001274
1275 const MotionEvent secondFingerUpEvent =
1276 MotionEventBuilder(POINTER_0_UP, AINPUT_SOURCE_TOUCHSCREEN)
1277 .displayId(ADISPLAY_ID_DEFAULT)
1278 .eventTime(systemTime(SYSTEM_TIME_MONOTONIC))
Siarhei Vishniakou6d73f832022-07-21 17:27:03 -07001279 .pointer(PointerBuilder(/*id=*/0, ToolType::FINGER).x(100).y(100))
1280 .pointer(PointerBuilder(/*id=*/1, ToolType::FINGER).x(150).y(150))
Arthur Hungc539dbb2022-12-08 07:45:36 +00001281 .build();
1282 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07001283 injectMotionEvent(*mDispatcher, secondFingerUpEvent, INJECT_EVENT_TIMEOUT,
Arthur Hungc539dbb2022-12-08 07:45:36 +00001284 InputEventInjectionSync::WAIT_FOR_RESULT))
1285 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
1286 foregroundWindow->consumeMotionPointerUp(0);
Linnan Li72352222024-04-12 18:55:57 +08001287 wallpaperWindow->consumeMotionPointerUp(0, ADISPLAY_ID_DEFAULT, EXPECTED_WALLPAPER_FLAGS);
Arthur Hungc539dbb2022-12-08 07:45:36 +00001288
1289 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07001290 injectMotionEvent(*mDispatcher,
Siarhei Vishniakou92c8fd52023-01-29 14:57:43 -08001291 MotionEventBuilder(AMOTION_EVENT_ACTION_UP,
1292 AINPUT_SOURCE_TOUCHSCREEN)
1293 .displayId(ADISPLAY_ID_DEFAULT)
1294 .eventTime(systemTime(SYSTEM_TIME_MONOTONIC))
Harry Cutts101ee9b2023-07-06 18:04:14 +00001295 .pointer(PointerBuilder(/*id=*/1, ToolType::FINGER)
Siarhei Vishniakou92c8fd52023-01-29 14:57:43 -08001296 .x(100)
1297 .y(100))
1298 .build(),
1299 INJECT_EVENT_TIMEOUT, InputEventInjectionSync::WAIT_FOR_RESULT))
Arthur Hungc539dbb2022-12-08 07:45:36 +00001300 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
1301 foregroundWindow->consumeMotionUp(ADISPLAY_ID_DEFAULT);
Linnan Li72352222024-04-12 18:55:57 +08001302 wallpaperWindow->consumeMotionUp(ADISPLAY_ID_DEFAULT, EXPECTED_WALLPAPER_FLAGS);
Siarhei Vishniakouca205502021-07-16 21:31:58 +00001303}
1304
1305/**
1306 * Two windows: a window on the left and window on the right.
1307 * A third window, wallpaper, is behind both windows, and spans both top windows.
1308 * The first touch down goes to the left window. A second pointer touches down on the right window.
1309 * The touch is split, so both left and right windows should receive ACTION_DOWN.
1310 * The wallpaper will get the full event, so it should receive ACTION_DOWN followed by
1311 * ACTION_POINTER_DOWN(1).
1312 */
1313TEST_F(InputDispatcherTest, TwoWindows_SplitWallpaperTouch) {
1314 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
1315 sp<FakeWindowHandle> leftWindow =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07001316 sp<FakeWindowHandle>::make(application, mDispatcher, "Left", ADISPLAY_ID_DEFAULT);
Siarhei Vishniakouca205502021-07-16 21:31:58 +00001317 leftWindow->setFrame(Rect(0, 0, 200, 200));
Prabir Pradhan4d5c52f2022-01-31 08:52:10 -08001318 leftWindow->setDupTouchToWallpaper(true);
Siarhei Vishniakouca205502021-07-16 21:31:58 +00001319
1320 sp<FakeWindowHandle> rightWindow =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07001321 sp<FakeWindowHandle>::make(application, mDispatcher, "Right", ADISPLAY_ID_DEFAULT);
Siarhei Vishniakouca205502021-07-16 21:31:58 +00001322 rightWindow->setFrame(Rect(200, 0, 400, 200));
Prabir Pradhan4d5c52f2022-01-31 08:52:10 -08001323 rightWindow->setDupTouchToWallpaper(true);
Siarhei Vishniakouca205502021-07-16 21:31:58 +00001324
1325 sp<FakeWindowHandle> wallpaperWindow =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07001326 sp<FakeWindowHandle>::make(application, mDispatcher, "Wallpaper", ADISPLAY_ID_DEFAULT);
Siarhei Vishniakouca205502021-07-16 21:31:58 +00001327 wallpaperWindow->setFrame(Rect(0, 0, 400, 200));
Prabir Pradhan4d5c52f2022-01-31 08:52:10 -08001328 wallpaperWindow->setIsWallpaper(true);
Siarhei Vishniakouca205502021-07-16 21:31:58 +00001329
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07001330 mDispatcher->onWindowInfosChanged(
1331 {{*leftWindow->getInfo(), *rightWindow->getInfo(), *wallpaperWindow->getInfo()},
1332 {},
1333 0,
1334 0});
Siarhei Vishniakouca205502021-07-16 21:31:58 +00001335
1336 // Touch down on left window
1337 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07001338 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
Siarhei Vishniakouca205502021-07-16 21:31:58 +00001339 {100, 100}))
1340 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
1341
1342 // Both foreground window and its wallpaper should receive the touch down
1343 leftWindow->consumeMotionDown();
Linnan Li72352222024-04-12 18:55:57 +08001344 wallpaperWindow->consumeMotionDown(ADISPLAY_ID_DEFAULT, EXPECTED_WALLPAPER_FLAGS);
Siarhei Vishniakouca205502021-07-16 21:31:58 +00001345
1346 // Second finger down on the right window
1347 const MotionEvent secondFingerDownEvent =
Siarhei Vishniakoua16e3a22022-03-02 15:26:40 -08001348 MotionEventBuilder(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
Siarhei Vishniakouca205502021-07-16 21:31:58 +00001349 .eventTime(systemTime(SYSTEM_TIME_MONOTONIC))
Siarhei Vishniakou6d73f832022-07-21 17:27:03 -07001350 .pointer(PointerBuilder(/*id=*/0, ToolType::FINGER).x(100).y(100))
1351 .pointer(PointerBuilder(/*id=*/1, ToolType::FINGER).x(300).y(100))
Siarhei Vishniakouca205502021-07-16 21:31:58 +00001352 .build();
1353 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07001354 injectMotionEvent(*mDispatcher, secondFingerDownEvent, INJECT_EVENT_TIMEOUT,
Siarhei Vishniakouca205502021-07-16 21:31:58 +00001355 InputEventInjectionSync::WAIT_FOR_RESULT))
1356 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
1357
1358 leftWindow->consumeMotionMove();
1359 // Since the touch is split, right window gets ACTION_DOWN
1360 rightWindow->consumeMotionDown(ADISPLAY_ID_DEFAULT);
Harry Cutts33476232023-01-30 19:57:29 +00001361 wallpaperWindow->consumeMotionPointerDown(/*pointerIndex=*/1, ADISPLAY_ID_DEFAULT,
Linnan Li72352222024-04-12 18:55:57 +08001362 EXPECTED_WALLPAPER_FLAGS);
Siarhei Vishniakouca205502021-07-16 21:31:58 +00001363
1364 // Now, leftWindow, which received the first finger, disappears.
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07001365 mDispatcher->onWindowInfosChanged(
1366 {{*rightWindow->getInfo(), *wallpaperWindow->getInfo()}, {}, 0, 0});
Siarhei Vishniakouca205502021-07-16 21:31:58 +00001367 leftWindow->consumeMotionCancel();
1368 // Since a "parent" window of the wallpaper is gone, wallpaper should receive cancel, too.
Linnan Li72352222024-04-12 18:55:57 +08001369 wallpaperWindow->consumeMotionCancel(ADISPLAY_ID_DEFAULT, EXPECTED_WALLPAPER_FLAGS);
Siarhei Vishniakouca205502021-07-16 21:31:58 +00001370
1371 // The pointer that's still down on the right window moves, and goes to the right window only.
1372 // As far as the dispatcher's concerned though, both pointers are still present.
1373 const MotionEvent secondFingerMoveEvent =
1374 MotionEventBuilder(AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN)
1375 .eventTime(systemTime(SYSTEM_TIME_MONOTONIC))
Siarhei Vishniakou6d73f832022-07-21 17:27:03 -07001376 .pointer(PointerBuilder(/*id=*/0, ToolType::FINGER).x(100).y(100))
1377 .pointer(PointerBuilder(/*id=*/1, ToolType::FINGER).x(310).y(110))
Siarhei Vishniakouca205502021-07-16 21:31:58 +00001378 .build();
1379 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07001380 injectMotionEvent(*mDispatcher, secondFingerMoveEvent, INJECT_EVENT_TIMEOUT,
Siarhei Vishniakouca205502021-07-16 21:31:58 +00001381 InputEventInjectionSync::WAIT_FOR_RESULT));
1382 rightWindow->consumeMotionMove();
1383
1384 leftWindow->assertNoEvents();
1385 rightWindow->assertNoEvents();
1386 wallpaperWindow->assertNoEvents();
1387}
1388
Arthur Hungc539dbb2022-12-08 07:45:36 +00001389/**
1390 * Two windows: a window on the left with dup touch to wallpaper and window on the right without it.
1391 * The touch slips to the right window. so left window and wallpaper should receive ACTION_CANCEL
1392 * The right window should receive ACTION_DOWN.
1393 */
1394TEST_F(InputDispatcherTest, WallpaperWindowWhenSlippery) {
Arthur Hung74c248d2022-11-23 07:09:59 +00001395 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
Arthur Hungc539dbb2022-12-08 07:45:36 +00001396 sp<FakeWindowHandle> leftWindow =
1397 sp<FakeWindowHandle>::make(application, mDispatcher, "Left", ADISPLAY_ID_DEFAULT);
1398 leftWindow->setFrame(Rect(0, 0, 200, 200));
1399 leftWindow->setDupTouchToWallpaper(true);
1400 leftWindow->setSlippery(true);
1401
1402 sp<FakeWindowHandle> rightWindow =
1403 sp<FakeWindowHandle>::make(application, mDispatcher, "Right", ADISPLAY_ID_DEFAULT);
1404 rightWindow->setFrame(Rect(200, 0, 400, 200));
Arthur Hung74c248d2022-11-23 07:09:59 +00001405
1406 sp<FakeWindowHandle> wallpaperWindow =
1407 sp<FakeWindowHandle>::make(application, mDispatcher, "Wallpaper", ADISPLAY_ID_DEFAULT);
1408 wallpaperWindow->setIsWallpaper(true);
Arthur Hung74c248d2022-11-23 07:09:59 +00001409
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07001410 mDispatcher->onWindowInfosChanged(
1411 {{*leftWindow->getInfo(), *rightWindow->getInfo(), *wallpaperWindow->getInfo()},
1412 {},
1413 0,
1414 0});
Arthur Hung74c248d2022-11-23 07:09:59 +00001415
Arthur Hungc539dbb2022-12-08 07:45:36 +00001416 // Touch down on left window
Arthur Hung74c248d2022-11-23 07:09:59 +00001417 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07001418 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
Arthur Hungc539dbb2022-12-08 07:45:36 +00001419 {100, 100}))
Arthur Hung74c248d2022-11-23 07:09:59 +00001420 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
Arthur Hungc539dbb2022-12-08 07:45:36 +00001421
1422 // Both foreground window and its wallpaper should receive the touch down
1423 leftWindow->consumeMotionDown();
Linnan Li72352222024-04-12 18:55:57 +08001424 wallpaperWindow->consumeMotionDown(ADISPLAY_ID_DEFAULT, EXPECTED_WALLPAPER_FLAGS);
Arthur Hung74c248d2022-11-23 07:09:59 +00001425
Arthur Hungc539dbb2022-12-08 07:45:36 +00001426 // Move to right window, the left window should receive cancel.
Arthur Hung74c248d2022-11-23 07:09:59 +00001427 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07001428 injectMotionEvent(*mDispatcher, AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN,
Arthur Hungc539dbb2022-12-08 07:45:36 +00001429 ADISPLAY_ID_DEFAULT, {201, 100}))
Arthur Hung74c248d2022-11-23 07:09:59 +00001430 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
1431
Arthur Hungc539dbb2022-12-08 07:45:36 +00001432 leftWindow->consumeMotionCancel();
1433 rightWindow->consumeMotionDown(ADISPLAY_ID_DEFAULT);
Linnan Li72352222024-04-12 18:55:57 +08001434 wallpaperWindow->consumeMotionCancel(ADISPLAY_ID_DEFAULT, EXPECTED_WALLPAPER_FLAGS);
Arthur Hung74c248d2022-11-23 07:09:59 +00001435}
1436
Siarhei Vishniakoua16e3a22022-03-02 15:26:40 -08001437/**
Siarhei Vishniakou5bf25d92023-02-08 15:43:38 -08001438 * The policy typically sets POLICY_FLAG_PASS_TO_USER to the events. But when the display is not
1439 * interactive, it might stop sending this flag.
1440 * In this test, we check that if the policy stops sending this flag mid-gesture, we still ensure
1441 * to have a consistent input stream.
1442 *
1443 * Test procedure:
1444 * DOWN -> POINTER_DOWN -> (stop sending POLICY_FLAG_PASS_TO_USER) -> CANCEL.
1445 * DOWN (new gesture).
1446 *
1447 * In the bad implementation, we could potentially drop the CANCEL event, and get an inconsistent
1448 * state in the dispatcher. This would cause the final DOWN event to not be delivered to the app.
1449 *
1450 * We technically just need a single window here, but we are using two windows (spy on top and a
1451 * regular window below) to emulate the actual situation where it happens on the device.
1452 */
1453TEST_F(InputDispatcherTest, TwoPointerCancelInconsistentPolicy) {
1454 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
1455 sp<FakeWindowHandle> spyWindow =
1456 sp<FakeWindowHandle>::make(application, mDispatcher, "Spy", ADISPLAY_ID_DEFAULT);
1457 spyWindow->setFrame(Rect(0, 0, 200, 200));
1458 spyWindow->setTrustedOverlay(true);
1459 spyWindow->setSpy(true);
1460
1461 sp<FakeWindowHandle> window =
1462 sp<FakeWindowHandle>::make(application, mDispatcher, "Window", ADISPLAY_ID_DEFAULT);
1463 window->setFrame(Rect(0, 0, 200, 200));
1464
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07001465 mDispatcher->onWindowInfosChanged({{*spyWindow->getInfo(), *window->getInfo()}, {}, 0, 0});
Siarhei Vishniakou5bf25d92023-02-08 15:43:38 -08001466 const int32_t touchDeviceId = 4;
Siarhei Vishniakou5bf25d92023-02-08 15:43:38 -08001467
1468 // Two pointers down
Prabir Pradhan678438e2023-04-13 19:32:51 +00001469 mDispatcher->notifyMotion(
1470 MotionArgsBuilder(AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
1471 .deviceId(touchDeviceId)
1472 .policyFlags(DEFAULT_POLICY_FLAGS)
1473 .pointer(PointerBuilder(0, ToolType::FINGER).x(100).y(100))
1474 .build());
Siarhei Vishniakou5bf25d92023-02-08 15:43:38 -08001475
Prabir Pradhan678438e2023-04-13 19:32:51 +00001476 mDispatcher->notifyMotion(MotionArgsBuilder(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
1477 .deviceId(touchDeviceId)
1478 .policyFlags(DEFAULT_POLICY_FLAGS)
1479 .pointer(PointerBuilder(0, ToolType::FINGER).x(100).y(100))
1480 .pointer(PointerBuilder(1, ToolType::FINGER).x(120).y(120))
1481 .build());
Siarhei Vishniakou5bf25d92023-02-08 15:43:38 -08001482 spyWindow->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_DOWN));
1483 spyWindow->consumeMotionEvent(WithMotionAction(POINTER_1_DOWN));
1484 window->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_DOWN));
1485 window->consumeMotionEvent(WithMotionAction(POINTER_1_DOWN));
1486
1487 // Cancel the current gesture. Send the cancel without the default policy flags.
Prabir Pradhan678438e2023-04-13 19:32:51 +00001488 mDispatcher->notifyMotion(
1489 MotionArgsBuilder(AMOTION_EVENT_ACTION_CANCEL, AINPUT_SOURCE_TOUCHSCREEN)
1490 .deviceId(touchDeviceId)
1491 .policyFlags(0)
1492 .pointer(PointerBuilder(0, ToolType::FINGER).x(100).y(100))
1493 .pointer(PointerBuilder(1, ToolType::FINGER).x(120).y(120))
1494 .build());
Siarhei Vishniakou5bf25d92023-02-08 15:43:38 -08001495 spyWindow->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_CANCEL));
1496 window->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_CANCEL));
1497
1498 // We don't need to reset the device to reproduce the issue, but the reset event typically
1499 // follows, so we keep it here to model the actual listener behaviour more closely.
Prabir Pradhan678438e2023-04-13 19:32:51 +00001500 mDispatcher->notifyDeviceReset({/*id=*/1, systemTime(SYSTEM_TIME_MONOTONIC), touchDeviceId});
Siarhei Vishniakou5bf25d92023-02-08 15:43:38 -08001501
1502 // Start new gesture
Prabir Pradhan678438e2023-04-13 19:32:51 +00001503 mDispatcher->notifyMotion(
1504 MotionArgsBuilder(AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
1505 .deviceId(touchDeviceId)
1506 .policyFlags(DEFAULT_POLICY_FLAGS)
1507 .pointer(PointerBuilder(0, ToolType::FINGER).x(100).y(100))
1508 .build());
Siarhei Vishniakou5bf25d92023-02-08 15:43:38 -08001509 spyWindow->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_DOWN));
1510 window->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_DOWN));
1511
1512 // No more events
1513 spyWindow->assertNoEvents();
1514 window->assertNoEvents();
1515}
1516
1517/**
Linnan Li907ae732023-09-05 17:14:21 +08001518 * Same as the above 'TwoPointerCancelInconsistentPolicy' test, but for hovers.
1519 * The policy typically sets POLICY_FLAG_PASS_TO_USER to the events. But when the display is not
1520 * interactive, it might stop sending this flag.
1521 * We've already ensured the consistency of the touch event in this case, and we should also ensure
1522 * the consistency of the hover event in this case.
1523 *
1524 * Test procedure:
1525 * HOVER_ENTER -> HOVER_MOVE -> (stop sending POLICY_FLAG_PASS_TO_USER) -> HOVER_EXIT
1526 * HOVER_ENTER -> HOVER_MOVE -> HOVER_EXIT
1527 *
1528 * We expect to receive two full streams of hover events.
1529 */
1530TEST_F(InputDispatcherTest, HoverEventInconsistentPolicy) {
1531 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
1532
1533 sp<FakeWindowHandle> window =
1534 sp<FakeWindowHandle>::make(application, mDispatcher, "Window", ADISPLAY_ID_DEFAULT);
1535 window->setFrame(Rect(0, 0, 300, 300));
1536
1537 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
1538
1539 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_ENTER, AINPUT_SOURCE_STYLUS)
1540 .policyFlags(DEFAULT_POLICY_FLAGS)
1541 .pointer(PointerBuilder(0, ToolType::STYLUS).x(100).y(101))
1542 .build());
1543 window->consumeMotionEvent(WithMotionAction(ACTION_HOVER_ENTER));
1544
1545 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_MOVE, AINPUT_SOURCE_STYLUS)
1546 .policyFlags(DEFAULT_POLICY_FLAGS)
1547 .pointer(PointerBuilder(0, ToolType::STYLUS).x(101).y(102))
1548 .build());
1549 window->consumeMotionEvent(WithMotionAction(ACTION_HOVER_MOVE));
1550
1551 // Send hover exit without the default policy flags.
1552 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_EXIT, AINPUT_SOURCE_STYLUS)
1553 .policyFlags(0)
1554 .pointer(PointerBuilder(0, ToolType::STYLUS).x(101).y(102))
1555 .build());
1556
1557 window->consumeMotionEvent(WithMotionAction(ACTION_HOVER_EXIT));
1558
1559 // Send a simple hover event stream, ensure dispatcher not crashed and window can receive
1560 // right event.
1561 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_ENTER, AINPUT_SOURCE_STYLUS)
1562 .policyFlags(DEFAULT_POLICY_FLAGS)
1563 .pointer(PointerBuilder(0, ToolType::STYLUS).x(200).y(201))
1564 .build());
1565 window->consumeMotionEvent(WithMotionAction(ACTION_HOVER_ENTER));
1566
1567 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_MOVE, AINPUT_SOURCE_STYLUS)
1568 .policyFlags(DEFAULT_POLICY_FLAGS)
1569 .pointer(PointerBuilder(0, ToolType::STYLUS).x(201).y(202))
1570 .build());
1571 window->consumeMotionEvent(WithMotionAction(ACTION_HOVER_MOVE));
1572
1573 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_EXIT, AINPUT_SOURCE_STYLUS)
1574 .policyFlags(DEFAULT_POLICY_FLAGS)
1575 .pointer(PointerBuilder(0, ToolType::STYLUS).x(201).y(202))
1576 .build());
1577 window->consumeMotionEvent(WithMotionAction(ACTION_HOVER_EXIT));
1578}
1579
1580/**
Siarhei Vishniakoue0431e42023-01-28 17:01:39 -08001581 * Two windows: a window on the left and a window on the right.
1582 * Mouse is hovered from the right window into the left window.
1583 * Next, we tap on the left window, where the cursor was last seen.
1584 * The second tap is done onto the right window.
1585 * The mouse and tap are from two different devices.
1586 * We technically don't need to set the downtime / eventtime for these events, but setting these
1587 * explicitly helps during debugging.
1588 * This test reproduces a crash where there is a mismatch between the downTime and eventTime.
1589 * In the buggy implementation, a tap on the right window would cause a crash.
1590 */
Siarhei Vishniakoued89cbb2023-10-13 10:42:44 -07001591TEST_F(InputDispatcherTest, HoverFromLeftToRightAndTap_legacy) {
1592 SCOPED_FLAG_OVERRIDE(enable_multi_device_same_window_stream, false);
1593
Siarhei Vishniakoue0431e42023-01-28 17:01:39 -08001594 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
1595 sp<FakeWindowHandle> leftWindow =
1596 sp<FakeWindowHandle>::make(application, mDispatcher, "Left", ADISPLAY_ID_DEFAULT);
1597 leftWindow->setFrame(Rect(0, 0, 200, 200));
1598
1599 sp<FakeWindowHandle> rightWindow =
1600 sp<FakeWindowHandle>::make(application, mDispatcher, "Right", ADISPLAY_ID_DEFAULT);
1601 rightWindow->setFrame(Rect(200, 0, 400, 200));
1602
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07001603 mDispatcher->onWindowInfosChanged(
1604 {{*leftWindow->getInfo(), *rightWindow->getInfo()}, {}, 0, 0});
Siarhei Vishniakoue0431e42023-01-28 17:01:39 -08001605 // All times need to start at the current time, otherwise the dispatcher will drop the events as
1606 // stale.
1607 const nsecs_t baseTime = systemTime(SYSTEM_TIME_MONOTONIC);
1608 const int32_t mouseDeviceId = 6;
1609 const int32_t touchDeviceId = 4;
1610 // Move the cursor from right
1611 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07001612 injectMotionEvent(*mDispatcher,
Siarhei Vishniakoue0431e42023-01-28 17:01:39 -08001613 MotionEventBuilder(AMOTION_EVENT_ACTION_HOVER_MOVE,
1614 AINPUT_SOURCE_MOUSE)
1615 .deviceId(mouseDeviceId)
1616 .downTime(baseTime + 10)
1617 .eventTime(baseTime + 20)
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07001618 .pointer(PointerBuilder(0, ToolType::MOUSE).x(300).y(100))
Siarhei Vishniakoue0431e42023-01-28 17:01:39 -08001619 .build()));
1620 rightWindow->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_ENTER));
1621
1622 // .. to the left window
1623 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07001624 injectMotionEvent(*mDispatcher,
Siarhei Vishniakoue0431e42023-01-28 17:01:39 -08001625 MotionEventBuilder(AMOTION_EVENT_ACTION_HOVER_MOVE,
1626 AINPUT_SOURCE_MOUSE)
1627 .deviceId(mouseDeviceId)
1628 .downTime(baseTime + 10)
1629 .eventTime(baseTime + 30)
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07001630 .pointer(PointerBuilder(0, ToolType::MOUSE).x(110).y(100))
Siarhei Vishniakoue0431e42023-01-28 17:01:39 -08001631 .build()));
1632 rightWindow->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_EXIT));
1633 leftWindow->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_ENTER));
1634 // Now tap the left window
1635 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07001636 injectMotionEvent(*mDispatcher,
Siarhei Vishniakoue0431e42023-01-28 17:01:39 -08001637 MotionEventBuilder(AMOTION_EVENT_ACTION_DOWN,
1638 AINPUT_SOURCE_TOUCHSCREEN)
1639 .deviceId(touchDeviceId)
1640 .downTime(baseTime + 40)
1641 .eventTime(baseTime + 40)
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07001642 .pointer(PointerBuilder(0, ToolType::FINGER).x(100).y(100))
Siarhei Vishniakoue0431e42023-01-28 17:01:39 -08001643 .build()));
1644 leftWindow->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_EXIT));
1645 leftWindow->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_DOWN));
1646
1647 // release tap
1648 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07001649 injectMotionEvent(*mDispatcher,
Siarhei Vishniakoue0431e42023-01-28 17:01:39 -08001650 MotionEventBuilder(AMOTION_EVENT_ACTION_UP,
1651 AINPUT_SOURCE_TOUCHSCREEN)
1652 .deviceId(touchDeviceId)
1653 .downTime(baseTime + 40)
1654 .eventTime(baseTime + 50)
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07001655 .pointer(PointerBuilder(0, ToolType::FINGER).x(100).y(100))
Siarhei Vishniakoue0431e42023-01-28 17:01:39 -08001656 .build()));
1657 leftWindow->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_UP));
1658
1659 // Tap the window on the right
1660 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07001661 injectMotionEvent(*mDispatcher,
Siarhei Vishniakoue0431e42023-01-28 17:01:39 -08001662 MotionEventBuilder(AMOTION_EVENT_ACTION_DOWN,
1663 AINPUT_SOURCE_TOUCHSCREEN)
1664 .deviceId(touchDeviceId)
1665 .downTime(baseTime + 60)
1666 .eventTime(baseTime + 60)
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07001667 .pointer(PointerBuilder(0, ToolType::FINGER).x(300).y(100))
Siarhei Vishniakoue0431e42023-01-28 17:01:39 -08001668 .build()));
1669 rightWindow->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_DOWN));
1670
1671 // release tap
1672 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07001673 injectMotionEvent(*mDispatcher,
Siarhei Vishniakoue0431e42023-01-28 17:01:39 -08001674 MotionEventBuilder(AMOTION_EVENT_ACTION_UP,
1675 AINPUT_SOURCE_TOUCHSCREEN)
1676 .deviceId(touchDeviceId)
1677 .downTime(baseTime + 60)
1678 .eventTime(baseTime + 70)
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07001679 .pointer(PointerBuilder(0, ToolType::FINGER).x(300).y(100))
Siarhei Vishniakoue0431e42023-01-28 17:01:39 -08001680 .build()));
1681 rightWindow->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_UP));
1682
1683 // No more events
1684 leftWindow->assertNoEvents();
1685 rightWindow->assertNoEvents();
1686}
1687
1688/**
Siarhei Vishniakoued89cbb2023-10-13 10:42:44 -07001689 * Two windows: a window on the left and a window on the right.
1690 * Mouse is hovered from the right window into the left window.
1691 * Next, we tap on the left window, where the cursor was last seen.
1692 * The second tap is done onto the right window.
1693 * The mouse and tap are from two different devices.
1694 * We technically don't need to set the downtime / eventtime for these events, but setting these
1695 * explicitly helps during debugging.
1696 * This test reproduces a crash where there is a mismatch between the downTime and eventTime.
1697 * In the buggy implementation, a tap on the right window would cause a crash.
1698 */
1699TEST_F(InputDispatcherTest, HoverFromLeftToRightAndTap) {
1700 SCOPED_FLAG_OVERRIDE(enable_multi_device_same_window_stream, true);
1701
1702 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
1703 sp<FakeWindowHandle> leftWindow =
1704 sp<FakeWindowHandle>::make(application, mDispatcher, "Left", ADISPLAY_ID_DEFAULT);
1705 leftWindow->setFrame(Rect(0, 0, 200, 200));
1706
1707 sp<FakeWindowHandle> rightWindow =
1708 sp<FakeWindowHandle>::make(application, mDispatcher, "Right", ADISPLAY_ID_DEFAULT);
1709 rightWindow->setFrame(Rect(200, 0, 400, 200));
1710
1711 mDispatcher->onWindowInfosChanged(
1712 {{*leftWindow->getInfo(), *rightWindow->getInfo()}, {}, 0, 0});
1713 // All times need to start at the current time, otherwise the dispatcher will drop the events as
1714 // stale.
1715 const nsecs_t baseTime = systemTime(SYSTEM_TIME_MONOTONIC);
1716 const int32_t mouseDeviceId = 6;
1717 const int32_t touchDeviceId = 4;
1718 // Move the cursor from right
1719 mDispatcher->notifyMotion(
1720 MotionArgsBuilder(AMOTION_EVENT_ACTION_HOVER_MOVE, AINPUT_SOURCE_MOUSE)
1721 .deviceId(mouseDeviceId)
1722 .downTime(baseTime + 10)
1723 .eventTime(baseTime + 20)
1724 .pointer(PointerBuilder(0, ToolType::MOUSE).x(300).y(100))
1725 .build());
1726 rightWindow->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_ENTER));
1727
1728 // .. to the left window
1729 mDispatcher->notifyMotion(
1730 MotionArgsBuilder(AMOTION_EVENT_ACTION_HOVER_MOVE, AINPUT_SOURCE_MOUSE)
1731 .deviceId(mouseDeviceId)
1732 .downTime(baseTime + 10)
1733 .eventTime(baseTime + 30)
1734 .pointer(PointerBuilder(0, ToolType::MOUSE).x(110).y(100))
1735 .build());
1736 rightWindow->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_EXIT));
1737 leftWindow->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_ENTER));
1738 // Now tap the left window
1739 mDispatcher->notifyMotion(
1740 MotionArgsBuilder(AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
1741 .deviceId(touchDeviceId)
1742 .downTime(baseTime + 40)
1743 .eventTime(baseTime + 40)
1744 .pointer(PointerBuilder(0, ToolType::FINGER).x(100).y(100))
1745 .build());
1746 leftWindow->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_DOWN));
1747
1748 // release tap
1749 mDispatcher->notifyMotion(MotionArgsBuilder(AMOTION_EVENT_ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN)
1750 .deviceId(touchDeviceId)
1751 .downTime(baseTime + 40)
1752 .eventTime(baseTime + 50)
1753 .pointer(PointerBuilder(0, ToolType::FINGER).x(100).y(100))
1754 .build());
1755 leftWindow->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_UP));
1756
1757 // Tap the window on the right
1758 mDispatcher->notifyMotion(
1759 MotionArgsBuilder(AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
1760 .deviceId(touchDeviceId)
1761 .downTime(baseTime + 60)
1762 .eventTime(baseTime + 60)
1763 .pointer(PointerBuilder(0, ToolType::FINGER).x(300).y(100))
1764 .build());
1765 rightWindow->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_DOWN));
1766
1767 // release tap
1768 mDispatcher->notifyMotion(MotionArgsBuilder(AMOTION_EVENT_ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN)
1769 .deviceId(touchDeviceId)
1770 .downTime(baseTime + 60)
1771 .eventTime(baseTime + 70)
1772 .pointer(PointerBuilder(0, ToolType::FINGER).x(300).y(100))
1773 .build());
1774 rightWindow->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_UP));
1775
1776 // No more events
1777 leftWindow->assertNoEvents();
1778 rightWindow->assertNoEvents();
1779}
1780
1781/**
Siarhei Vishniakoua235c042023-05-02 09:59:09 -07001782 * Start hovering in a window. While this hover is still active, make another window appear on top.
1783 * The top, obstructing window has no input channel, so it's not supposed to receive input.
1784 * While the top window is present, the hovering is stopped.
1785 * Later, hovering gets resumed again.
1786 * Ensure that new hover gesture is handled correctly.
1787 * This test reproduces a crash where the HOVER_EXIT event wasn't getting dispatched correctly
1788 * to the window that's currently being hovered over.
1789 */
1790TEST_F(InputDispatcherTest, HoverWhileWindowAppears) {
1791 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
1792 sp<FakeWindowHandle> window =
1793 sp<FakeWindowHandle>::make(application, mDispatcher, "Window", ADISPLAY_ID_DEFAULT);
1794 window->setFrame(Rect(0, 0, 200, 200));
1795
1796 // Only a single window is present at first
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07001797 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Siarhei Vishniakoua235c042023-05-02 09:59:09 -07001798
1799 // Start hovering in the window
1800 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_ENTER, AINPUT_SOURCE_STYLUS)
1801 .pointer(PointerBuilder(0, ToolType::STYLUS).x(100).y(100))
1802 .build());
1803 window->consumeMotionEvent(WithMotionAction(ACTION_HOVER_ENTER));
1804
1805 // Now, an obscuring window appears!
1806 sp<FakeWindowHandle> obscuringWindow =
1807 sp<FakeWindowHandle>::make(application, mDispatcher, "Obscuring window",
1808 ADISPLAY_ID_DEFAULT,
Prabir Pradhane7cc69c2024-01-05 21:35:28 +00001809 /*createInputChannel=*/false);
Siarhei Vishniakoua235c042023-05-02 09:59:09 -07001810 obscuringWindow->setFrame(Rect(0, 0, 200, 200));
1811 obscuringWindow->setTouchOcclusionMode(TouchOcclusionMode::BLOCK_UNTRUSTED);
1812 obscuringWindow->setOwnerInfo(SECONDARY_WINDOW_PID, SECONDARY_WINDOW_UID);
1813 obscuringWindow->setNoInputChannel(true);
1814 obscuringWindow->setFocusable(false);
1815 obscuringWindow->setAlpha(1.0);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07001816 mDispatcher->onWindowInfosChanged(
1817 {{*obscuringWindow->getInfo(), *window->getInfo()}, {}, 0, 0});
Siarhei Vishniakoua235c042023-05-02 09:59:09 -07001818
1819 // While this new obscuring window is present, the hovering is stopped
1820 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_EXIT, AINPUT_SOURCE_STYLUS)
1821 .pointer(PointerBuilder(0, ToolType::STYLUS).x(100).y(100))
1822 .build());
1823 window->consumeMotionEvent(WithMotionAction(ACTION_HOVER_EXIT));
1824
1825 // Now the obscuring window goes away.
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07001826 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Siarhei Vishniakoua235c042023-05-02 09:59:09 -07001827
1828 // And a new hover gesture starts.
1829 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_ENTER, AINPUT_SOURCE_STYLUS)
1830 .pointer(PointerBuilder(0, ToolType::STYLUS).x(100).y(100))
1831 .build());
1832 window->consumeMotionEvent(WithMotionAction(ACTION_HOVER_ENTER));
1833}
1834
1835/**
1836 * Same test as 'HoverWhileWindowAppears' above, but here, we also send some HOVER_MOVE events to
1837 * the obscuring window.
1838 */
1839TEST_F(InputDispatcherTest, HoverMoveWhileWindowAppears) {
1840 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
1841 sp<FakeWindowHandle> window =
1842 sp<FakeWindowHandle>::make(application, mDispatcher, "Window", ADISPLAY_ID_DEFAULT);
1843 window->setFrame(Rect(0, 0, 200, 200));
1844
1845 // Only a single window is present at first
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07001846 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Siarhei Vishniakoua235c042023-05-02 09:59:09 -07001847
1848 // Start hovering in the window
1849 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_ENTER, AINPUT_SOURCE_STYLUS)
1850 .pointer(PointerBuilder(0, ToolType::STYLUS).x(100).y(100))
1851 .build());
1852 window->consumeMotionEvent(WithMotionAction(ACTION_HOVER_ENTER));
1853
1854 // Now, an obscuring window appears!
1855 sp<FakeWindowHandle> obscuringWindow =
1856 sp<FakeWindowHandle>::make(application, mDispatcher, "Obscuring window",
1857 ADISPLAY_ID_DEFAULT,
Prabir Pradhane7cc69c2024-01-05 21:35:28 +00001858 /*createInputChannel=*/false);
Siarhei Vishniakoua235c042023-05-02 09:59:09 -07001859 obscuringWindow->setFrame(Rect(0, 0, 200, 200));
1860 obscuringWindow->setTouchOcclusionMode(TouchOcclusionMode::BLOCK_UNTRUSTED);
1861 obscuringWindow->setOwnerInfo(SECONDARY_WINDOW_PID, SECONDARY_WINDOW_UID);
1862 obscuringWindow->setNoInputChannel(true);
1863 obscuringWindow->setFocusable(false);
1864 obscuringWindow->setAlpha(1.0);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07001865 mDispatcher->onWindowInfosChanged(
1866 {{*obscuringWindow->getInfo(), *window->getInfo()}, {}, 0, 0});
Siarhei Vishniakoua235c042023-05-02 09:59:09 -07001867
1868 // While this new obscuring window is present, the hovering continues. The event can't go to the
1869 // bottom window due to obstructed touches, so it should generate HOVER_EXIT for that window.
1870 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_MOVE, AINPUT_SOURCE_STYLUS)
1871 .pointer(PointerBuilder(0, ToolType::STYLUS).x(100).y(100))
1872 .build());
1873 obscuringWindow->assertNoEvents();
1874 window->consumeMotionEvent(WithMotionAction(ACTION_HOVER_EXIT));
1875
1876 // Now the obscuring window goes away.
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07001877 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Siarhei Vishniakoua235c042023-05-02 09:59:09 -07001878
1879 // Hovering continues in the same position. The hovering pointer re-enters the bottom window,
1880 // so it should generate a HOVER_ENTER
1881 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_MOVE, AINPUT_SOURCE_STYLUS)
1882 .pointer(PointerBuilder(0, ToolType::STYLUS).x(100).y(100))
1883 .build());
1884 window->consumeMotionEvent(WithMotionAction(ACTION_HOVER_ENTER));
1885
1886 // Now the MOVE should be getting dispatched normally
1887 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_MOVE, AINPUT_SOURCE_STYLUS)
1888 .pointer(PointerBuilder(0, ToolType::STYLUS).x(110).y(110))
1889 .build());
1890 window->consumeMotionEvent(WithMotionAction(ACTION_HOVER_MOVE));
1891}
1892
1893/**
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -07001894 * Hover mouse over a window, and then send ACTION_SCROLL. Ensure both the hover and the scroll
1895 * events are delivered to the window.
1896 */
1897TEST_F(InputDispatcherTest, HoverMoveAndScroll) {
1898 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
1899 sp<FakeWindowHandle> window =
1900 sp<FakeWindowHandle>::make(application, mDispatcher, "Window", ADISPLAY_ID_DEFAULT);
1901 window->setFrame(Rect(0, 0, 200, 200));
1902 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
1903
1904 // Start hovering in the window
1905 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_ENTER, AINPUT_SOURCE_MOUSE)
1906 .pointer(PointerBuilder(0, ToolType::MOUSE).x(100).y(110))
1907 .build());
1908 window->consumeMotionEvent(WithMotionAction(ACTION_HOVER_ENTER));
1909
1910 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_MOVE, AINPUT_SOURCE_MOUSE)
1911 .pointer(PointerBuilder(0, ToolType::MOUSE).x(110).y(120))
1912 .build());
1913 window->consumeMotionEvent(WithMotionAction(ACTION_HOVER_MOVE));
1914
1915 // Scroll with the mouse
1916 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_SCROLL, AINPUT_SOURCE_MOUSE)
1917 .pointer(PointerBuilder(0, ToolType::MOUSE).x(110).y(120))
1918 .build());
1919 window->consumeMotionEvent(WithMotionAction(ACTION_SCROLL));
1920}
1921
1922using InputDispatcherMultiDeviceTest = InputDispatcherTest;
1923
1924/**
Siarhei Vishniakou2899c552023-07-10 18:20:46 -07001925 * One window. Stylus down on the window. Next, touch from another device goes down. Ensure that
1926 * touch is dropped, because stylus should be preferred over touch.
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -07001927 */
Siarhei Vishniakou2899c552023-07-10 18:20:46 -07001928TEST_F(InputDispatcherMultiDeviceTest, StylusDownBlocksTouchDown) {
Siarhei Vishniakoued89cbb2023-10-13 10:42:44 -07001929 SCOPED_FLAG_OVERRIDE(enable_multi_device_same_window_stream, false);
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -07001930 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
1931 sp<FakeWindowHandle> window =
1932 sp<FakeWindowHandle>::make(application, mDispatcher, "Window", ADISPLAY_ID_DEFAULT);
1933 window->setFrame(Rect(0, 0, 200, 200));
1934
1935 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
1936
1937 constexpr int32_t touchDeviceId = 4;
1938 constexpr int32_t stylusDeviceId = 2;
1939
1940 // Stylus down
1941 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_STYLUS)
1942 .deviceId(stylusDeviceId)
1943 .pointer(PointerBuilder(0, ToolType::STYLUS).x(100).y(110))
1944 .build());
1945 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(stylusDeviceId)));
1946
1947 // Touch down
1948 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
1949 .deviceId(touchDeviceId)
1950 .pointer(PointerBuilder(0, ToolType::FINGER).x(140).y(145))
1951 .build());
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -07001952
1953 // Touch move
1954 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN)
1955 .deviceId(touchDeviceId)
1956 .pointer(PointerBuilder(0, ToolType::FINGER).x(141).y(146))
1957 .build());
Siarhei Vishniakou2899c552023-07-10 18:20:46 -07001958 // Touch is ignored because stylus is already down
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -07001959
Siarhei Vishniakou2899c552023-07-10 18:20:46 -07001960 // Subsequent stylus movements are delivered correctly
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -07001961 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_STYLUS)
1962 .deviceId(stylusDeviceId)
1963 .pointer(PointerBuilder(0, ToolType::STYLUS).x(101).y(111))
1964 .build());
Siarhei Vishniakou2899c552023-07-10 18:20:46 -07001965 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(stylusDeviceId),
1966 WithCoords(101, 111)));
1967
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -07001968 window->assertNoEvents();
1969}
1970
1971/**
Siarhei Vishniakoued89cbb2023-10-13 10:42:44 -07001972 * One window. Stylus down on the window. Next, touch from another device goes down. Ensure that
1973 * touch is not dropped, because multiple devices are allowed to be active in the same window.
1974 */
1975TEST_F(InputDispatcherMultiDeviceTest, StylusDownDoesNotBlockTouchDown) {
1976 SCOPED_FLAG_OVERRIDE(enable_multi_device_same_window_stream, true);
1977 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
1978 sp<FakeWindowHandle> window =
1979 sp<FakeWindowHandle>::make(application, mDispatcher, "Window", ADISPLAY_ID_DEFAULT);
1980 window->setFrame(Rect(0, 0, 200, 200));
1981
1982 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
1983
1984 constexpr int32_t touchDeviceId = 4;
1985 constexpr int32_t stylusDeviceId = 2;
1986
1987 // Stylus down
1988 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_STYLUS)
1989 .deviceId(stylusDeviceId)
1990 .pointer(PointerBuilder(0, ToolType::STYLUS).x(100).y(110))
1991 .build());
1992 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(stylusDeviceId)));
1993
1994 // Touch down
1995 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
1996 .deviceId(touchDeviceId)
1997 .pointer(PointerBuilder(0, ToolType::FINGER).x(140).y(145))
1998 .build());
1999 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(touchDeviceId)));
2000
2001 // Touch move
2002 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN)
2003 .deviceId(touchDeviceId)
2004 .pointer(PointerBuilder(0, ToolType::FINGER).x(141).y(146))
2005 .build());
2006 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(touchDeviceId)));
2007
2008 // Stylus move
2009 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_STYLUS)
2010 .deviceId(stylusDeviceId)
2011 .pointer(PointerBuilder(0, ToolType::STYLUS).x(101).y(111))
2012 .build());
2013 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(stylusDeviceId),
2014 WithCoords(101, 111)));
2015
2016 window->assertNoEvents();
2017}
2018
2019/**
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -07002020 * One window and one spy window. Stylus down on the window. Next, touch from another device goes
Siarhei Vishniakou2899c552023-07-10 18:20:46 -07002021 * down. Ensure that touch is dropped, because stylus should be preferred over touch.
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -07002022 * Similar test as above, but with added SPY window.
2023 */
Siarhei Vishniakou2899c552023-07-10 18:20:46 -07002024TEST_F(InputDispatcherMultiDeviceTest, StylusDownWithSpyBlocksTouchDown) {
Siarhei Vishniakoued89cbb2023-10-13 10:42:44 -07002025 SCOPED_FLAG_OVERRIDE(enable_multi_device_same_window_stream, false);
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -07002026 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
2027 sp<FakeWindowHandle> window =
2028 sp<FakeWindowHandle>::make(application, mDispatcher, "Window", ADISPLAY_ID_DEFAULT);
2029 sp<FakeWindowHandle> spyWindow =
2030 sp<FakeWindowHandle>::make(application, mDispatcher, "Spy", ADISPLAY_ID_DEFAULT);
2031 spyWindow->setFrame(Rect(0, 0, 200, 200));
2032 spyWindow->setTrustedOverlay(true);
2033 spyWindow->setSpy(true);
2034 window->setFrame(Rect(0, 0, 200, 200));
2035
2036 mDispatcher->onWindowInfosChanged({{*spyWindow->getInfo(), *window->getInfo()}, {}, 0, 0});
2037
2038 constexpr int32_t touchDeviceId = 4;
2039 constexpr int32_t stylusDeviceId = 2;
2040
2041 // Stylus down
2042 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_STYLUS)
2043 .deviceId(stylusDeviceId)
2044 .pointer(PointerBuilder(0, ToolType::STYLUS).x(100).y(110))
2045 .build());
2046 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(stylusDeviceId)));
2047 spyWindow->consumeMotionEvent(
2048 AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(stylusDeviceId)));
2049
2050 // Touch down
2051 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
2052 .deviceId(touchDeviceId)
2053 .pointer(PointerBuilder(0, ToolType::FINGER).x(140).y(145))
2054 .build());
2055
2056 // Touch move
2057 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN)
2058 .deviceId(touchDeviceId)
2059 .pointer(PointerBuilder(0, ToolType::FINGER).x(141).y(146))
2060 .build());
Siarhei Vishniakou2899c552023-07-10 18:20:46 -07002061
2062 // Touch is ignored because stylus is already down
2063
2064 // Subsequent stylus movements are delivered correctly
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -07002065 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_STYLUS)
2066 .deviceId(stylusDeviceId)
2067 .pointer(PointerBuilder(0, ToolType::STYLUS).x(101).y(111))
2068 .build());
Siarhei Vishniakou2899c552023-07-10 18:20:46 -07002069 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(stylusDeviceId),
2070 WithCoords(101, 111)));
2071 spyWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(stylusDeviceId),
2072 WithCoords(101, 111)));
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -07002073
2074 window->assertNoEvents();
2075 spyWindow->assertNoEvents();
2076}
2077
2078/**
Siarhei Vishniakoued89cbb2023-10-13 10:42:44 -07002079 * One window and one spy window. Stylus down on the window. Next, touch from another device goes
2080 * down. Ensure that touch is not dropped, because multiple devices can be active at the same time.
2081 * Similar test as above, but with added SPY window.
2082 */
2083TEST_F(InputDispatcherMultiDeviceTest, StylusDownWithSpyDoesNotBlockTouchDown) {
2084 SCOPED_FLAG_OVERRIDE(enable_multi_device_same_window_stream, true);
2085 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
2086 sp<FakeWindowHandle> window =
2087 sp<FakeWindowHandle>::make(application, mDispatcher, "Window", ADISPLAY_ID_DEFAULT);
2088 sp<FakeWindowHandle> spyWindow =
2089 sp<FakeWindowHandle>::make(application, mDispatcher, "Spy", ADISPLAY_ID_DEFAULT);
2090 spyWindow->setFrame(Rect(0, 0, 200, 200));
2091 spyWindow->setTrustedOverlay(true);
2092 spyWindow->setSpy(true);
2093 window->setFrame(Rect(0, 0, 200, 200));
2094
2095 mDispatcher->onWindowInfosChanged({{*spyWindow->getInfo(), *window->getInfo()}, {}, 0, 0});
2096
2097 constexpr int32_t touchDeviceId = 4;
2098 constexpr int32_t stylusDeviceId = 2;
2099
2100 // Stylus down
2101 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_STYLUS)
2102 .deviceId(stylusDeviceId)
2103 .pointer(PointerBuilder(0, ToolType::STYLUS).x(100).y(110))
2104 .build());
2105 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(stylusDeviceId)));
2106 spyWindow->consumeMotionEvent(
2107 AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(stylusDeviceId)));
2108
2109 // Touch down
2110 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
2111 .deviceId(touchDeviceId)
2112 .pointer(PointerBuilder(0, ToolType::FINGER).x(140).y(145))
2113 .build());
2114 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(touchDeviceId)));
2115 spyWindow->consumeMotionEvent(
2116 AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(touchDeviceId)));
2117
2118 // Touch move
2119 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN)
2120 .deviceId(touchDeviceId)
2121 .pointer(PointerBuilder(0, ToolType::FINGER).x(141).y(146))
2122 .build());
2123 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(touchDeviceId)));
2124 spyWindow->consumeMotionEvent(
2125 AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(touchDeviceId)));
2126
2127 // Subsequent stylus movements are delivered correctly
2128 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_STYLUS)
2129 .deviceId(stylusDeviceId)
2130 .pointer(PointerBuilder(0, ToolType::STYLUS).x(101).y(111))
2131 .build());
2132 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(stylusDeviceId),
2133 WithCoords(101, 111)));
2134 spyWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(stylusDeviceId),
2135 WithCoords(101, 111)));
2136
2137 window->assertNoEvents();
2138 spyWindow->assertNoEvents();
2139}
2140
2141/**
Siarhei Vishniakou2899c552023-07-10 18:20:46 -07002142 * One window. Stylus hover on the window. Next, touch from another device goes down. Ensure that
Siarhei Vishniakou3ad54f52023-11-02 16:54:40 -07002143 * touch is dropped, because stylus hover takes precedence.
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -07002144 */
Siarhei Vishniakou3ad54f52023-11-02 16:54:40 -07002145TEST_F(InputDispatcherMultiDeviceTest, StylusHoverBlocksTouchDown) {
Siarhei Vishniakoued89cbb2023-10-13 10:42:44 -07002146 SCOPED_FLAG_OVERRIDE(enable_multi_device_same_window_stream, false);
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -07002147 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
2148 sp<FakeWindowHandle> window =
2149 sp<FakeWindowHandle>::make(application, mDispatcher, "Window", ADISPLAY_ID_DEFAULT);
2150 window->setFrame(Rect(0, 0, 200, 200));
2151
2152 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
2153
2154 constexpr int32_t touchDeviceId = 4;
2155 constexpr int32_t stylusDeviceId = 2;
2156
2157 // Stylus down on the window
2158 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_ENTER, AINPUT_SOURCE_STYLUS)
2159 .deviceId(stylusDeviceId)
2160 .pointer(PointerBuilder(0, ToolType::STYLUS).x(100).y(110))
2161 .build());
2162 window->consumeMotionEvent(
2163 AllOf(WithMotionAction(ACTION_HOVER_ENTER), WithDeviceId(stylusDeviceId)));
2164
2165 // Touch down on window
2166 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
2167 .deviceId(touchDeviceId)
2168 .pointer(PointerBuilder(0, ToolType::FINGER).x(140).y(145))
2169 .build());
2170 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN)
2171 .deviceId(touchDeviceId)
2172 .pointer(PointerBuilder(0, ToolType::FINGER).x(141).y(146))
2173 .build());
Siarhei Vishniakou2899c552023-07-10 18:20:46 -07002174
Siarhei Vishniakou3ad54f52023-11-02 16:54:40 -07002175 // Touch is ignored because stylus is hovering
Siarhei Vishniakou2899c552023-07-10 18:20:46 -07002176
Siarhei Vishniakou3ad54f52023-11-02 16:54:40 -07002177 // Subsequent stylus movements are delivered correctly
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -07002178 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_MOVE, AINPUT_SOURCE_STYLUS)
2179 .deviceId(stylusDeviceId)
2180 .pointer(PointerBuilder(0, ToolType::STYLUS).x(101).y(111))
2181 .build());
Siarhei Vishniakou3ad54f52023-11-02 16:54:40 -07002182 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_HOVER_MOVE),
2183 WithDeviceId(stylusDeviceId), WithCoords(101, 111)));
Siarhei Vishniakou2899c552023-07-10 18:20:46 -07002184
Siarhei Vishniakou3ad54f52023-11-02 16:54:40 -07002185 // and subsequent touches continue to be ignored
Siarhei Vishniakou2899c552023-07-10 18:20:46 -07002186 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN)
2187 .deviceId(touchDeviceId)
2188 .pointer(PointerBuilder(0, ToolType::FINGER).x(142).y(147))
2189 .build());
Siarhei Vishniakou3ad54f52023-11-02 16:54:40 -07002190 window->assertNoEvents();
Siarhei Vishniakou2899c552023-07-10 18:20:46 -07002191}
2192
2193/**
Siarhei Vishniakoued89cbb2023-10-13 10:42:44 -07002194 * One window. Stylus hover on the window. Next, touch from another device goes down. Ensure that
2195 * touch is not dropped, because stylus hover and touch can be both active at the same time.
2196 */
2197TEST_F(InputDispatcherMultiDeviceTest, StylusHoverDoesNotBlockTouchDown) {
2198 SCOPED_FLAG_OVERRIDE(enable_multi_device_same_window_stream, true);
2199 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
2200 sp<FakeWindowHandle> window =
2201 sp<FakeWindowHandle>::make(application, mDispatcher, "Window", ADISPLAY_ID_DEFAULT);
2202 window->setFrame(Rect(0, 0, 200, 200));
2203
2204 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
2205
2206 constexpr int32_t touchDeviceId = 4;
2207 constexpr int32_t stylusDeviceId = 2;
2208
2209 // Stylus down on the window
2210 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_ENTER, AINPUT_SOURCE_STYLUS)
2211 .deviceId(stylusDeviceId)
2212 .pointer(PointerBuilder(0, ToolType::STYLUS).x(100).y(110))
2213 .build());
2214 window->consumeMotionEvent(
2215 AllOf(WithMotionAction(ACTION_HOVER_ENTER), WithDeviceId(stylusDeviceId)));
2216
2217 // Touch down on window
2218 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
2219 .deviceId(touchDeviceId)
2220 .pointer(PointerBuilder(0, ToolType::FINGER).x(140).y(145))
2221 .build());
2222 // Touch move on window
2223 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(touchDeviceId)));
2224 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN)
2225 .deviceId(touchDeviceId)
2226 .pointer(PointerBuilder(0, ToolType::FINGER).x(141).y(146))
2227 .build());
2228 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(touchDeviceId)));
2229
2230 // Subsequent stylus movements are delivered correctly
2231 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_MOVE, AINPUT_SOURCE_STYLUS)
2232 .deviceId(stylusDeviceId)
2233 .pointer(PointerBuilder(0, ToolType::STYLUS).x(101).y(111))
2234 .build());
2235 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_HOVER_MOVE),
2236 WithDeviceId(stylusDeviceId), WithCoords(101, 111)));
2237
2238 // and subsequent touches continue to work
2239 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN)
2240 .deviceId(touchDeviceId)
2241 .pointer(PointerBuilder(0, ToolType::FINGER).x(142).y(147))
2242 .build());
2243 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(touchDeviceId)));
2244 window->assertNoEvents();
2245}
2246
2247/**
Siarhei Vishniakou2899c552023-07-10 18:20:46 -07002248 * One window. Touch down on the window. Then, stylus hover on the window from another device.
Siarhei Vishniakou3ad54f52023-11-02 16:54:40 -07002249 * Ensure that touch is canceled, because stylus hover should take precedence.
Siarhei Vishniakou2899c552023-07-10 18:20:46 -07002250 */
Siarhei Vishniakou3ad54f52023-11-02 16:54:40 -07002251TEST_F(InputDispatcherMultiDeviceTest, TouchIsCanceledByStylusHover) {
Siarhei Vishniakoued89cbb2023-10-13 10:42:44 -07002252 SCOPED_FLAG_OVERRIDE(enable_multi_device_same_window_stream, false);
Siarhei Vishniakou2899c552023-07-10 18:20:46 -07002253 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
2254 sp<FakeWindowHandle> window =
2255 sp<FakeWindowHandle>::make(application, mDispatcher, "Window", ADISPLAY_ID_DEFAULT);
2256 window->setFrame(Rect(0, 0, 200, 200));
2257
2258 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
2259
2260 constexpr int32_t touchDeviceId = 4;
2261 constexpr int32_t stylusDeviceId = 2;
2262
2263 // Touch down on window
2264 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
2265 .deviceId(touchDeviceId)
2266 .pointer(PointerBuilder(0, ToolType::FINGER).x(140).y(145))
2267 .build());
2268 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN)
2269 .deviceId(touchDeviceId)
2270 .pointer(PointerBuilder(0, ToolType::FINGER).x(141).y(146))
2271 .build());
2272 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(touchDeviceId)));
2273 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(touchDeviceId)));
2274
2275 // Stylus hover on the window
2276 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_ENTER, AINPUT_SOURCE_STYLUS)
2277 .deviceId(stylusDeviceId)
2278 .pointer(PointerBuilder(0, ToolType::STYLUS).x(100).y(110))
2279 .build());
2280 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_MOVE, AINPUT_SOURCE_STYLUS)
2281 .deviceId(stylusDeviceId)
2282 .pointer(PointerBuilder(0, ToolType::STYLUS).x(101).y(111))
2283 .build());
Siarhei Vishniakou3ad54f52023-11-02 16:54:40 -07002284 // Stylus hover movement causes touch to be canceled
2285 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_CANCEL), WithDeviceId(touchDeviceId),
2286 WithCoords(141, 146)));
2287 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_HOVER_ENTER),
2288 WithDeviceId(stylusDeviceId), WithCoords(100, 110)));
2289 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_HOVER_MOVE),
2290 WithDeviceId(stylusDeviceId), WithCoords(101, 111)));
Siarhei Vishniakou2899c552023-07-10 18:20:46 -07002291
Siarhei Vishniakou3ad54f52023-11-02 16:54:40 -07002292 // Subsequent touch movements are ignored
Siarhei Vishniakou2899c552023-07-10 18:20:46 -07002293 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN)
2294 .deviceId(touchDeviceId)
2295 .pointer(PointerBuilder(0, ToolType::FINGER).x(142).y(147))
2296 .build());
Siarhei Vishniakou3ad54f52023-11-02 16:54:40 -07002297
2298 window->assertNoEvents();
Siarhei Vishniakou2899c552023-07-10 18:20:46 -07002299}
2300
2301/**
Siarhei Vishniakoued89cbb2023-10-13 10:42:44 -07002302 * One window. Touch down on the window. Then, stylus hover on the window from another device.
2303 * Ensure that touch is not canceled, because stylus hover can be active at the same time as touch.
2304 */
2305TEST_F(InputDispatcherMultiDeviceTest, TouchIsNotCanceledByStylusHover) {
2306 SCOPED_FLAG_OVERRIDE(enable_multi_device_same_window_stream, true);
2307 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
2308 sp<FakeWindowHandle> window =
2309 sp<FakeWindowHandle>::make(application, mDispatcher, "Window", ADISPLAY_ID_DEFAULT);
2310 window->setFrame(Rect(0, 0, 200, 200));
2311
2312 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
2313
2314 constexpr int32_t touchDeviceId = 4;
2315 constexpr int32_t stylusDeviceId = 2;
2316
2317 // Touch down on window
2318 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
2319 .deviceId(touchDeviceId)
2320 .pointer(PointerBuilder(0, ToolType::FINGER).x(140).y(145))
2321 .build());
2322 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN)
2323 .deviceId(touchDeviceId)
2324 .pointer(PointerBuilder(0, ToolType::FINGER).x(141).y(146))
2325 .build());
2326 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(touchDeviceId)));
2327 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(touchDeviceId)));
2328
2329 // Stylus hover on the window
2330 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_ENTER, AINPUT_SOURCE_STYLUS)
2331 .deviceId(stylusDeviceId)
2332 .pointer(PointerBuilder(0, ToolType::STYLUS).x(100).y(110))
2333 .build());
2334 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_MOVE, AINPUT_SOURCE_STYLUS)
2335 .deviceId(stylusDeviceId)
2336 .pointer(PointerBuilder(0, ToolType::STYLUS).x(101).y(111))
2337 .build());
2338 // Stylus hover movement is received normally
2339 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_HOVER_ENTER),
2340 WithDeviceId(stylusDeviceId), WithCoords(100, 110)));
2341 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_HOVER_MOVE),
2342 WithDeviceId(stylusDeviceId), WithCoords(101, 111)));
2343
2344 // Subsequent touch movements also work
2345 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN)
2346 .deviceId(touchDeviceId)
2347 .pointer(PointerBuilder(0, ToolType::FINGER).x(142).y(147))
2348 .build());
2349 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(touchDeviceId),
2350 WithCoords(142, 147)));
2351
2352 window->assertNoEvents();
2353}
2354
2355/**
Siarhei Vishniakou2899c552023-07-10 18:20:46 -07002356 * One window. Stylus down on the window. Then, stylus from another device goes down. Ensure that
2357 * the latest stylus takes over. That is, old stylus should be canceled and the new stylus should
2358 * become active.
2359 */
2360TEST_F(InputDispatcherMultiDeviceTest, LatestStylusWins) {
Siarhei Vishniakoued89cbb2023-10-13 10:42:44 -07002361 SCOPED_FLAG_OVERRIDE(enable_multi_device_same_window_stream, false);
Siarhei Vishniakou2899c552023-07-10 18:20:46 -07002362 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
2363 sp<FakeWindowHandle> window =
2364 sp<FakeWindowHandle>::make(application, mDispatcher, "Window", ADISPLAY_ID_DEFAULT);
2365 window->setFrame(Rect(0, 0, 200, 200));
2366
2367 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
2368
2369 constexpr int32_t stylusDeviceId1 = 3;
2370 constexpr int32_t stylusDeviceId2 = 5;
2371
2372 // Touch down on window
2373 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_STYLUS)
2374 .deviceId(stylusDeviceId1)
2375 .pointer(PointerBuilder(0, ToolType::STYLUS).x(99).y(100))
2376 .build());
2377 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_STYLUS)
2378 .deviceId(stylusDeviceId1)
2379 .pointer(PointerBuilder(0, ToolType::STYLUS).x(100).y(101))
2380 .build());
2381 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(stylusDeviceId1)));
2382 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(stylusDeviceId1)));
2383
2384 // Second stylus down
2385 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_STYLUS)
2386 .deviceId(stylusDeviceId2)
2387 .pointer(PointerBuilder(0, ToolType::STYLUS).x(9).y(10))
2388 .build());
2389 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_STYLUS)
2390 .deviceId(stylusDeviceId2)
2391 .pointer(PointerBuilder(0, ToolType::STYLUS).x(10).y(11))
2392 .build());
2393
2394 // First stylus is canceled, second one takes over.
2395 window->consumeMotionEvent(
2396 AllOf(WithMotionAction(ACTION_CANCEL), WithDeviceId(stylusDeviceId1)));
2397 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(stylusDeviceId2)));
2398 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(stylusDeviceId2)));
2399
2400 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_STYLUS)
2401 .deviceId(stylusDeviceId1)
2402 .pointer(PointerBuilder(0, ToolType::STYLUS).x(101).y(102))
2403 .build());
2404 // Subsequent stylus movements are delivered correctly
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -07002405 window->assertNoEvents();
2406}
2407
2408/**
Siarhei Vishniakoued89cbb2023-10-13 10:42:44 -07002409 * One window. Stylus down on the window. Then, stylus from another device goes down. Ensure that
2410 * both stylus devices can function simultaneously.
2411 */
2412TEST_F(InputDispatcherMultiDeviceTest, TwoStylusDevicesActiveAtTheSameTime) {
2413 SCOPED_FLAG_OVERRIDE(enable_multi_device_same_window_stream, true);
2414 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
2415 sp<FakeWindowHandle> window =
2416 sp<FakeWindowHandle>::make(application, mDispatcher, "Window", ADISPLAY_ID_DEFAULT);
2417 window->setFrame(Rect(0, 0, 200, 200));
2418
2419 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
2420
2421 constexpr int32_t stylusDeviceId1 = 3;
2422 constexpr int32_t stylusDeviceId2 = 5;
2423
2424 // Touch down on window
2425 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_STYLUS)
2426 .deviceId(stylusDeviceId1)
2427 .pointer(PointerBuilder(0, ToolType::STYLUS).x(99).y(100))
2428 .build());
2429 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_STYLUS)
2430 .deviceId(stylusDeviceId1)
2431 .pointer(PointerBuilder(0, ToolType::STYLUS).x(100).y(101))
2432 .build());
2433 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(stylusDeviceId1)));
2434 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(stylusDeviceId1)));
2435
2436 // Second stylus down
2437 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_STYLUS)
2438 .deviceId(stylusDeviceId2)
2439 .pointer(PointerBuilder(0, ToolType::STYLUS).x(9).y(10))
2440 .build());
2441 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_STYLUS)
2442 .deviceId(stylusDeviceId2)
2443 .pointer(PointerBuilder(0, ToolType::STYLUS).x(10).y(11))
2444 .build());
2445 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(stylusDeviceId2)));
2446 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(stylusDeviceId2)));
2447
2448 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_STYLUS)
2449 .deviceId(stylusDeviceId1)
2450 .pointer(PointerBuilder(0, ToolType::STYLUS).x(101).y(102))
2451 .build());
2452 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(stylusDeviceId1)));
2453 window->assertNoEvents();
2454}
2455
2456/**
Siarhei Vishniakou2899c552023-07-10 18:20:46 -07002457 * One window. Touch down on the window. Then, stylus down on the window from another device.
2458 * Ensure that is canceled, because stylus down should be preferred over touch.
2459 */
2460TEST_F(InputDispatcherMultiDeviceTest, TouchIsCanceledByStylusDown) {
Siarhei Vishniakoued89cbb2023-10-13 10:42:44 -07002461 SCOPED_FLAG_OVERRIDE(enable_multi_device_same_window_stream, false);
Siarhei Vishniakou2899c552023-07-10 18:20:46 -07002462 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
2463 sp<FakeWindowHandle> window =
2464 sp<FakeWindowHandle>::make(application, mDispatcher, "Window", ADISPLAY_ID_DEFAULT);
2465 window->setFrame(Rect(0, 0, 200, 200));
2466
2467 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
2468
2469 constexpr int32_t touchDeviceId = 4;
2470 constexpr int32_t stylusDeviceId = 2;
2471
2472 // Touch down on window
2473 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
2474 .deviceId(touchDeviceId)
2475 .pointer(PointerBuilder(0, ToolType::FINGER).x(140).y(145))
2476 .build());
2477 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN)
2478 .deviceId(touchDeviceId)
2479 .pointer(PointerBuilder(0, ToolType::FINGER).x(141).y(146))
2480 .build());
2481 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(touchDeviceId)));
2482 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(touchDeviceId)));
2483
2484 // Stylus down on the window
2485 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_STYLUS)
2486 .deviceId(stylusDeviceId)
2487 .pointer(PointerBuilder(0, ToolType::STYLUS).x(100).y(110))
2488 .build());
2489 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_CANCEL), WithDeviceId(touchDeviceId)));
2490 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(stylusDeviceId)));
2491
2492 // Subsequent stylus movements are delivered correctly
2493 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_STYLUS)
2494 .deviceId(stylusDeviceId)
2495 .pointer(PointerBuilder(0, ToolType::STYLUS).x(101).y(111))
2496 .build());
2497 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(stylusDeviceId),
2498 WithCoords(101, 111)));
2499}
2500
2501/**
Siarhei Vishniakoued89cbb2023-10-13 10:42:44 -07002502 * One window. Touch down on the window. Then, stylus down on the window from another device.
2503 * Ensure that both touch and stylus are functioning independently.
2504 */
2505TEST_F(InputDispatcherMultiDeviceTest, TouchIsNotCanceledByStylusDown) {
2506 SCOPED_FLAG_OVERRIDE(enable_multi_device_same_window_stream, true);
2507 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
2508 sp<FakeWindowHandle> window =
2509 sp<FakeWindowHandle>::make(application, mDispatcher, "Window", ADISPLAY_ID_DEFAULT);
2510 window->setFrame(Rect(0, 0, 200, 200));
2511
2512 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
2513
2514 constexpr int32_t touchDeviceId = 4;
2515 constexpr int32_t stylusDeviceId = 2;
2516
2517 // Touch down on window
2518 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
2519 .deviceId(touchDeviceId)
2520 .pointer(PointerBuilder(0, ToolType::FINGER).x(140).y(145))
2521 .build());
2522 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN)
2523 .deviceId(touchDeviceId)
2524 .pointer(PointerBuilder(0, ToolType::FINGER).x(141).y(146))
2525 .build());
2526 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(touchDeviceId)));
2527 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(touchDeviceId)));
2528
2529 // Stylus down on the window
2530 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_STYLUS)
2531 .deviceId(stylusDeviceId)
2532 .pointer(PointerBuilder(0, ToolType::STYLUS).x(100).y(110))
2533 .build());
2534 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(stylusDeviceId)));
2535
2536 // Subsequent stylus movements are delivered correctly
2537 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_STYLUS)
2538 .deviceId(stylusDeviceId)
2539 .pointer(PointerBuilder(0, ToolType::STYLUS).x(101).y(111))
2540 .build());
2541 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(stylusDeviceId),
2542 WithCoords(101, 111)));
2543
2544 // Touch continues to work too
2545 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN)
2546 .deviceId(touchDeviceId)
2547 .pointer(PointerBuilder(0, ToolType::FINGER).x(148).y(149))
2548 .build());
2549 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(touchDeviceId)));
2550}
2551
2552/**
Siarhei Vishniakouf372b812023-02-14 18:06:51 -08002553 * Two windows: a window on the left and a window on the right.
2554 * Mouse is clicked on the left window and remains down. Touch is touched on the right and remains
2555 * down. Then, on the left window, also place second touch pointer down.
2556 * This test tries to reproduce a crash.
2557 * In the buggy implementation, second pointer down on the left window would cause a crash.
2558 */
Siarhei Vishniakoued89cbb2023-10-13 10:42:44 -07002559TEST_F(InputDispatcherMultiDeviceTest, MultiDeviceSplitTouch_legacy) {
2560 SCOPED_FLAG_OVERRIDE(enable_multi_device_same_window_stream, false);
Siarhei Vishniakouf372b812023-02-14 18:06:51 -08002561 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
2562 sp<FakeWindowHandle> leftWindow =
2563 sp<FakeWindowHandle>::make(application, mDispatcher, "Left", ADISPLAY_ID_DEFAULT);
2564 leftWindow->setFrame(Rect(0, 0, 200, 200));
2565
2566 sp<FakeWindowHandle> rightWindow =
2567 sp<FakeWindowHandle>::make(application, mDispatcher, "Right", ADISPLAY_ID_DEFAULT);
2568 rightWindow->setFrame(Rect(200, 0, 400, 200));
2569
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07002570 mDispatcher->onWindowInfosChanged(
2571 {{*leftWindow->getInfo(), *rightWindow->getInfo()}, {}, 0, 0});
Siarhei Vishniakouf372b812023-02-14 18:06:51 -08002572
2573 const int32_t touchDeviceId = 4;
2574 const int32_t mouseDeviceId = 6;
Siarhei Vishniakouf372b812023-02-14 18:06:51 -08002575
2576 // Start hovering over the left window
Prabir Pradhan678438e2023-04-13 19:32:51 +00002577 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_ENTER, AINPUT_SOURCE_MOUSE)
2578 .deviceId(mouseDeviceId)
2579 .pointer(PointerBuilder(0, ToolType::MOUSE).x(100).y(100))
2580 .build());
Siarhei Vishniakouf372b812023-02-14 18:06:51 -08002581 leftWindow->consumeMotionEvent(
2582 AllOf(WithMotionAction(ACTION_HOVER_ENTER), WithDeviceId(mouseDeviceId)));
2583
2584 // Mouse down on left window
Prabir Pradhan678438e2023-04-13 19:32:51 +00002585 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_MOUSE)
2586 .deviceId(mouseDeviceId)
2587 .buttonState(AMOTION_EVENT_BUTTON_PRIMARY)
2588 .pointer(PointerBuilder(0, ToolType::MOUSE).x(100).y(100))
2589 .build());
Siarhei Vishniakouf372b812023-02-14 18:06:51 -08002590
2591 leftWindow->consumeMotionEvent(
2592 AllOf(WithMotionAction(ACTION_HOVER_EXIT), WithDeviceId(mouseDeviceId)));
2593 leftWindow->consumeMotionEvent(
2594 AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(mouseDeviceId)));
2595
Prabir Pradhan678438e2023-04-13 19:32:51 +00002596 mDispatcher->notifyMotion(
2597 MotionArgsBuilder(AMOTION_EVENT_ACTION_BUTTON_PRESS, AINPUT_SOURCE_MOUSE)
2598 .deviceId(mouseDeviceId)
2599 .buttonState(AMOTION_EVENT_BUTTON_PRIMARY)
2600 .actionButton(AMOTION_EVENT_BUTTON_PRIMARY)
2601 .pointer(PointerBuilder(0, ToolType::MOUSE).x(100).y(100))
2602 .build());
Siarhei Vishniakouf372b812023-02-14 18:06:51 -08002603 leftWindow->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_BUTTON_PRESS));
2604
2605 // First touch pointer down on right window
Prabir Pradhan678438e2023-04-13 19:32:51 +00002606 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
2607 .deviceId(touchDeviceId)
2608 .pointer(PointerBuilder(0, ToolType::FINGER).x(300).y(100))
2609 .build());
Siarhei Vishniakou2899c552023-07-10 18:20:46 -07002610 leftWindow->assertNoEvents();
2611
Siarhei Vishniakouf372b812023-02-14 18:06:51 -08002612 rightWindow->consumeMotionEvent(WithMotionAction(ACTION_DOWN));
2613
2614 // Second touch pointer down on left window
Prabir Pradhan678438e2023-04-13 19:32:51 +00002615 mDispatcher->notifyMotion(MotionArgsBuilder(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
2616 .deviceId(touchDeviceId)
2617 .pointer(PointerBuilder(0, ToolType::FINGER).x(300).y(100))
2618 .pointer(PointerBuilder(1, ToolType::FINGER).x(100).y(100))
2619 .build());
Siarhei Vishniakou2899c552023-07-10 18:20:46 -07002620 // Since this is now a new splittable pointer going down on the left window, and it's coming
2621 // from a different device, the current gesture in the left window (pointer down) should first
2622 // be canceled.
2623 leftWindow->consumeMotionEvent(
2624 AllOf(WithMotionAction(ACTION_CANCEL), WithDeviceId(mouseDeviceId)));
Siarhei Vishniakouf372b812023-02-14 18:06:51 -08002625 leftWindow->consumeMotionEvent(
2626 AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(touchDeviceId)));
2627 // This MOVE event is not necessary (doesn't carry any new information), but it's there in the
2628 // current implementation.
2629 const std::map<int32_t, PointF> expectedPointers{{0, PointF{100, 100}}};
2630 rightWindow->consumeMotionEvent(
2631 AllOf(WithMotionAction(ACTION_MOVE), WithPointers(expectedPointers)));
2632
2633 leftWindow->assertNoEvents();
2634 rightWindow->assertNoEvents();
2635}
2636
2637/**
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -07002638 * Two windows: a window on the left and a window on the right.
Siarhei Vishniakoued89cbb2023-10-13 10:42:44 -07002639 * Mouse is clicked on the left window and remains down. Touch is touched on the right and remains
2640 * down. Then, on the left window, also place second touch pointer down.
2641 * This test tries to reproduce a crash.
2642 * In the buggy implementation, second pointer down on the left window would cause a crash.
2643 */
2644TEST_F(InputDispatcherMultiDeviceTest, MultiDeviceSplitTouch) {
2645 SCOPED_FLAG_OVERRIDE(enable_multi_device_same_window_stream, true);
2646 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
2647 sp<FakeWindowHandle> leftWindow =
2648 sp<FakeWindowHandle>::make(application, mDispatcher, "Left", ADISPLAY_ID_DEFAULT);
2649 leftWindow->setFrame(Rect(0, 0, 200, 200));
2650
2651 sp<FakeWindowHandle> rightWindow =
2652 sp<FakeWindowHandle>::make(application, mDispatcher, "Right", ADISPLAY_ID_DEFAULT);
2653 rightWindow->setFrame(Rect(200, 0, 400, 200));
2654
2655 mDispatcher->onWindowInfosChanged(
2656 {{*leftWindow->getInfo(), *rightWindow->getInfo()}, {}, 0, 0});
2657
2658 const int32_t touchDeviceId = 4;
2659 const int32_t mouseDeviceId = 6;
2660
2661 // Start hovering over the left window
2662 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_ENTER, AINPUT_SOURCE_MOUSE)
2663 .deviceId(mouseDeviceId)
2664 .pointer(PointerBuilder(0, ToolType::MOUSE).x(100).y(100))
2665 .build());
2666 leftWindow->consumeMotionEvent(
2667 AllOf(WithMotionAction(ACTION_HOVER_ENTER), WithDeviceId(mouseDeviceId)));
2668
2669 // Mouse down on left window
2670 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_MOUSE)
2671 .deviceId(mouseDeviceId)
2672 .buttonState(AMOTION_EVENT_BUTTON_PRIMARY)
2673 .pointer(PointerBuilder(0, ToolType::MOUSE).x(100).y(100))
2674 .build());
2675
2676 leftWindow->consumeMotionEvent(
2677 AllOf(WithMotionAction(ACTION_HOVER_EXIT), WithDeviceId(mouseDeviceId)));
2678 leftWindow->consumeMotionEvent(
2679 AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(mouseDeviceId)));
2680
2681 mDispatcher->notifyMotion(
2682 MotionArgsBuilder(AMOTION_EVENT_ACTION_BUTTON_PRESS, AINPUT_SOURCE_MOUSE)
2683 .deviceId(mouseDeviceId)
2684 .buttonState(AMOTION_EVENT_BUTTON_PRIMARY)
2685 .actionButton(AMOTION_EVENT_BUTTON_PRIMARY)
2686 .pointer(PointerBuilder(0, ToolType::MOUSE).x(100).y(100))
2687 .build());
2688 leftWindow->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_BUTTON_PRESS));
2689
2690 // First touch pointer down on right window
2691 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
2692 .deviceId(touchDeviceId)
2693 .pointer(PointerBuilder(0, ToolType::FINGER).x(300).y(100))
2694 .build());
2695 leftWindow->assertNoEvents();
2696
2697 rightWindow->consumeMotionEvent(WithMotionAction(ACTION_DOWN));
2698
2699 // Second touch pointer down on left window
2700 mDispatcher->notifyMotion(MotionArgsBuilder(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
2701 .deviceId(touchDeviceId)
2702 .pointer(PointerBuilder(0, ToolType::FINGER).x(300).y(100))
2703 .pointer(PointerBuilder(1, ToolType::FINGER).x(100).y(100))
2704 .build());
2705 // Since this is now a new splittable pointer going down on the left window, and it's coming
2706 // from a different device, it will be split and delivered to left window separately.
2707 leftWindow->consumeMotionEvent(
2708 AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(touchDeviceId)));
2709 // This MOVE event is not necessary (doesn't carry any new information), but it's there in the
2710 // current implementation.
2711 const std::map<int32_t, PointF> expectedPointers{{0, PointF{100, 100}}};
2712 rightWindow->consumeMotionEvent(
2713 AllOf(WithMotionAction(ACTION_MOVE), WithPointers(expectedPointers)));
2714
2715 leftWindow->assertNoEvents();
2716 rightWindow->assertNoEvents();
2717}
2718
2719/**
2720 * Two windows: a window on the left and a window on the right.
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -07002721 * Mouse is hovered on the left window and stylus is hovered on the right window.
2722 */
2723TEST_F(InputDispatcherMultiDeviceTest, MultiDeviceHover) {
2724 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
2725 sp<FakeWindowHandle> leftWindow =
2726 sp<FakeWindowHandle>::make(application, mDispatcher, "Left", ADISPLAY_ID_DEFAULT);
2727 leftWindow->setFrame(Rect(0, 0, 200, 200));
2728
2729 sp<FakeWindowHandle> rightWindow =
2730 sp<FakeWindowHandle>::make(application, mDispatcher, "Right", ADISPLAY_ID_DEFAULT);
2731 rightWindow->setFrame(Rect(200, 0, 400, 200));
2732
2733 mDispatcher->onWindowInfosChanged(
2734 {{*leftWindow->getInfo(), *rightWindow->getInfo()}, {}, 0, 0});
2735
2736 const int32_t stylusDeviceId = 3;
2737 const int32_t mouseDeviceId = 6;
2738
2739 // Start hovering over the left window
2740 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_ENTER, AINPUT_SOURCE_MOUSE)
2741 .deviceId(mouseDeviceId)
2742 .pointer(PointerBuilder(0, ToolType::MOUSE).x(100).y(110))
2743 .build());
2744 leftWindow->consumeMotionEvent(
2745 AllOf(WithMotionAction(ACTION_HOVER_ENTER), WithDeviceId(mouseDeviceId)));
2746
2747 // Stylus hovered on right window
2748 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_ENTER, AINPUT_SOURCE_STYLUS)
2749 .deviceId(stylusDeviceId)
2750 .pointer(PointerBuilder(0, ToolType::STYLUS).x(300).y(100))
2751 .build());
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -07002752 rightWindow->consumeMotionEvent(
2753 AllOf(WithMotionAction(ACTION_HOVER_ENTER), WithDeviceId(stylusDeviceId)));
2754
2755 // Subsequent HOVER_MOVE events are dispatched correctly.
2756 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_MOVE, AINPUT_SOURCE_MOUSE)
2757 .deviceId(mouseDeviceId)
2758 .pointer(PointerBuilder(0, ToolType::MOUSE).x(110).y(120))
2759 .build());
2760 leftWindow->consumeMotionEvent(
Siarhei Vishniakou2899c552023-07-10 18:20:46 -07002761 AllOf(WithMotionAction(ACTION_HOVER_MOVE), WithDeviceId(mouseDeviceId)));
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -07002762
2763 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_MOVE, AINPUT_SOURCE_STYLUS)
2764 .deviceId(stylusDeviceId)
2765 .pointer(PointerBuilder(0, ToolType::STYLUS).x(310).y(110))
2766 .build());
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -07002767 rightWindow->consumeMotionEvent(
Siarhei Vishniakou2899c552023-07-10 18:20:46 -07002768 AllOf(WithMotionAction(ACTION_HOVER_MOVE), WithDeviceId(stylusDeviceId)));
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -07002769
2770 leftWindow->assertNoEvents();
2771 rightWindow->assertNoEvents();
2772}
2773
2774/**
2775 * Three windows: a window on the left and a window on the right.
2776 * And a spy window that's positioned above all of them.
2777 * Stylus down on the left window and remains down. Touch goes down on the right and remains down.
2778 * Check the stream that's received by the spy.
2779 */
Siarhei Vishniakoued89cbb2023-10-13 10:42:44 -07002780TEST_F(InputDispatcherMultiDeviceTest, MultiDeviceWithSpy_legacy) {
2781 SCOPED_FLAG_OVERRIDE(enable_multi_device_same_window_stream, false);
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -07002782 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
2783
2784 sp<FakeWindowHandle> spyWindow =
2785 sp<FakeWindowHandle>::make(application, mDispatcher, "Spy", ADISPLAY_ID_DEFAULT);
2786 spyWindow->setFrame(Rect(0, 0, 400, 400));
2787 spyWindow->setTrustedOverlay(true);
2788 spyWindow->setSpy(true);
2789
2790 sp<FakeWindowHandle> leftWindow =
2791 sp<FakeWindowHandle>::make(application, mDispatcher, "Left", ADISPLAY_ID_DEFAULT);
2792 leftWindow->setFrame(Rect(0, 0, 200, 200));
2793
2794 sp<FakeWindowHandle> rightWindow =
2795 sp<FakeWindowHandle>::make(application, mDispatcher, "Right", ADISPLAY_ID_DEFAULT);
2796
2797 rightWindow->setFrame(Rect(200, 0, 400, 200));
2798
2799 mDispatcher->onWindowInfosChanged(
2800 {{*spyWindow->getInfo(), *leftWindow->getInfo(), *rightWindow->getInfo()}, {}, 0, 0});
2801
2802 const int32_t stylusDeviceId = 1;
2803 const int32_t touchDeviceId = 2;
2804
2805 // Stylus down on the left window
2806 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_STYLUS)
2807 .deviceId(stylusDeviceId)
2808 .pointer(PointerBuilder(0, ToolType::STYLUS).x(100).y(100))
2809 .build());
2810 leftWindow->consumeMotionEvent(
2811 AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(stylusDeviceId)));
2812 spyWindow->consumeMotionEvent(
2813 AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(stylusDeviceId)));
2814
2815 // Touch down on the right window
2816 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
2817 .deviceId(touchDeviceId)
2818 .pointer(PointerBuilder(0, ToolType::FINGER).x(300).y(100))
2819 .build());
Siarhei Vishniakou2899c552023-07-10 18:20:46 -07002820 leftWindow->assertNoEvents();
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -07002821 rightWindow->consumeMotionEvent(
2822 AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(touchDeviceId)));
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -07002823
Siarhei Vishniakou2899c552023-07-10 18:20:46 -07002824 // Spy window does not receive touch events, because stylus events take precedence, and it
2825 // already has an active stylus gesture.
2826
2827 // Stylus movements continue. They should be delivered to the left window and to the spy window
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -07002828 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_STYLUS)
2829 .deviceId(stylusDeviceId)
2830 .pointer(PointerBuilder(0, ToolType::STYLUS).x(110).y(110))
2831 .build());
Siarhei Vishniakou2899c552023-07-10 18:20:46 -07002832 leftWindow->consumeMotionEvent(
2833 AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(stylusDeviceId)));
2834 spyWindow->consumeMotionEvent(
2835 AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(stylusDeviceId)));
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -07002836
Siarhei Vishniakou2899c552023-07-10 18:20:46 -07002837 // Further MOVE events keep going to the right window only
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -07002838 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN)
2839 .deviceId(touchDeviceId)
2840 .pointer(PointerBuilder(0, ToolType::FINGER).x(310).y(110))
2841 .build());
2842 rightWindow->consumeMotionEvent(
2843 AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(touchDeviceId)));
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -07002844
2845 spyWindow->assertNoEvents();
2846 leftWindow->assertNoEvents();
2847 rightWindow->assertNoEvents();
2848}
2849
2850/**
Siarhei Vishniakoued89cbb2023-10-13 10:42:44 -07002851 * Three windows: a window on the left and a window on the right.
2852 * And a spy window that's positioned above all of them.
2853 * Stylus down on the left window and remains down. Touch goes down on the right and remains down.
2854 * Check the stream that's received by the spy.
2855 */
2856TEST_F(InputDispatcherMultiDeviceTest, MultiDeviceWithSpy) {
2857 SCOPED_FLAG_OVERRIDE(enable_multi_device_same_window_stream, true);
2858 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
2859
2860 sp<FakeWindowHandle> spyWindow =
2861 sp<FakeWindowHandle>::make(application, mDispatcher, "Spy", ADISPLAY_ID_DEFAULT);
2862 spyWindow->setFrame(Rect(0, 0, 400, 400));
2863 spyWindow->setTrustedOverlay(true);
2864 spyWindow->setSpy(true);
2865
2866 sp<FakeWindowHandle> leftWindow =
2867 sp<FakeWindowHandle>::make(application, mDispatcher, "Left", ADISPLAY_ID_DEFAULT);
2868 leftWindow->setFrame(Rect(0, 0, 200, 200));
2869
2870 sp<FakeWindowHandle> rightWindow =
2871 sp<FakeWindowHandle>::make(application, mDispatcher, "Right", ADISPLAY_ID_DEFAULT);
2872
2873 rightWindow->setFrame(Rect(200, 0, 400, 200));
2874
2875 mDispatcher->onWindowInfosChanged(
2876 {{*spyWindow->getInfo(), *leftWindow->getInfo(), *rightWindow->getInfo()}, {}, 0, 0});
2877
2878 const int32_t stylusDeviceId = 1;
2879 const int32_t touchDeviceId = 2;
2880
2881 // Stylus down on the left window
2882 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_STYLUS)
2883 .deviceId(stylusDeviceId)
2884 .pointer(PointerBuilder(0, ToolType::STYLUS).x(100).y(100))
2885 .build());
2886 leftWindow->consumeMotionEvent(
2887 AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(stylusDeviceId)));
2888 spyWindow->consumeMotionEvent(
2889 AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(stylusDeviceId)));
2890
2891 // Touch down on the right window
2892 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
2893 .deviceId(touchDeviceId)
2894 .pointer(PointerBuilder(0, ToolType::FINGER).x(300).y(100))
2895 .build());
2896 leftWindow->assertNoEvents();
2897 rightWindow->consumeMotionEvent(
2898 AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(touchDeviceId)));
2899 spyWindow->consumeMotionEvent(
2900 AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(touchDeviceId)));
2901
2902 // Stylus movements continue. They should be delivered to the left window and to the spy window
2903 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_STYLUS)
2904 .deviceId(stylusDeviceId)
2905 .pointer(PointerBuilder(0, ToolType::STYLUS).x(110).y(110))
2906 .build());
2907 leftWindow->consumeMotionEvent(
2908 AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(stylusDeviceId)));
2909 spyWindow->consumeMotionEvent(
2910 AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(stylusDeviceId)));
2911
2912 // Further touch MOVE events keep going to the right window and to the spy
2913 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN)
2914 .deviceId(touchDeviceId)
2915 .pointer(PointerBuilder(0, ToolType::FINGER).x(310).y(110))
2916 .build());
2917 rightWindow->consumeMotionEvent(
2918 AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(touchDeviceId)));
2919 spyWindow->consumeMotionEvent(
2920 AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(touchDeviceId)));
2921
2922 spyWindow->assertNoEvents();
2923 leftWindow->assertNoEvents();
2924 rightWindow->assertNoEvents();
2925}
2926
2927/**
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -07002928 * Three windows: a window on the left, a window on the right, and a spy window positioned above
2929 * both.
2930 * Check hover in left window and touch down in the right window.
Siarhei Vishniakou3ad54f52023-11-02 16:54:40 -07002931 * At first, spy should receive hover. Spy shouldn't receive touch while stylus is hovering.
Siarhei Vishniakou2899c552023-07-10 18:20:46 -07002932 * At the same time, left and right should be getting independent streams of hovering and touch,
2933 * respectively.
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -07002934 */
Siarhei Vishniakou3ad54f52023-11-02 16:54:40 -07002935TEST_F(InputDispatcherMultiDeviceTest, MultiDeviceHoverBlocksTouchWithSpy) {
Siarhei Vishniakoued89cbb2023-10-13 10:42:44 -07002936 SCOPED_FLAG_OVERRIDE(enable_multi_device_same_window_stream, false);
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -07002937 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
2938
2939 sp<FakeWindowHandle> spyWindow =
2940 sp<FakeWindowHandle>::make(application, mDispatcher, "Spy", ADISPLAY_ID_DEFAULT);
2941 spyWindow->setFrame(Rect(0, 0, 400, 400));
2942 spyWindow->setTrustedOverlay(true);
2943 spyWindow->setSpy(true);
2944
2945 sp<FakeWindowHandle> leftWindow =
2946 sp<FakeWindowHandle>::make(application, mDispatcher, "Left", ADISPLAY_ID_DEFAULT);
2947 leftWindow->setFrame(Rect(0, 0, 200, 200));
2948
2949 sp<FakeWindowHandle> rightWindow =
2950 sp<FakeWindowHandle>::make(application, mDispatcher, "Right", ADISPLAY_ID_DEFAULT);
2951 rightWindow->setFrame(Rect(200, 0, 400, 200));
2952
2953 mDispatcher->onWindowInfosChanged(
2954 {{*spyWindow->getInfo(), *leftWindow->getInfo(), *rightWindow->getInfo()}, {}, 0, 0});
2955
2956 const int32_t stylusDeviceId = 1;
2957 const int32_t touchDeviceId = 2;
2958
2959 // Stylus hover on the left window
2960 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_ENTER, AINPUT_SOURCE_STYLUS)
2961 .deviceId(stylusDeviceId)
2962 .pointer(PointerBuilder(0, ToolType::STYLUS).x(100).y(100))
2963 .build());
2964 leftWindow->consumeMotionEvent(
2965 AllOf(WithMotionAction(ACTION_HOVER_ENTER), WithDeviceId(stylusDeviceId)));
2966 spyWindow->consumeMotionEvent(
2967 AllOf(WithMotionAction(ACTION_HOVER_ENTER), WithDeviceId(stylusDeviceId)));
2968
Siarhei Vishniakou2899c552023-07-10 18:20:46 -07002969 // Touch down on the right window. Spy doesn't receive this touch because it already has
2970 // stylus hovering there.
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -07002971 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
2972 .deviceId(touchDeviceId)
2973 .pointer(PointerBuilder(0, ToolType::FINGER).x(300).y(100))
2974 .build());
Siarhei Vishniakou2899c552023-07-10 18:20:46 -07002975 leftWindow->assertNoEvents();
Siarhei Vishniakou3ad54f52023-11-02 16:54:40 -07002976 spyWindow->assertNoEvents();
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -07002977 rightWindow->consumeMotionEvent(
2978 AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(touchDeviceId)));
2979
Siarhei Vishniakou3ad54f52023-11-02 16:54:40 -07002980 // Stylus movements continue. They should be delivered to the left window and the spy.
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -07002981 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_MOVE, AINPUT_SOURCE_STYLUS)
2982 .deviceId(stylusDeviceId)
2983 .pointer(PointerBuilder(0, ToolType::STYLUS).x(110).y(110))
2984 .build());
Siarhei Vishniakou2899c552023-07-10 18:20:46 -07002985 leftWindow->consumeMotionEvent(
2986 AllOf(WithMotionAction(ACTION_HOVER_MOVE), WithDeviceId(stylusDeviceId)));
Siarhei Vishniakou3ad54f52023-11-02 16:54:40 -07002987 spyWindow->consumeMotionEvent(
2988 AllOf(WithMotionAction(ACTION_HOVER_MOVE), WithDeviceId(stylusDeviceId)));
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -07002989
Siarhei Vishniakou3ad54f52023-11-02 16:54:40 -07002990 // Touch movements continue. They should be delivered to the right window only
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -07002991 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN)
2992 .deviceId(touchDeviceId)
2993 .pointer(PointerBuilder(0, ToolType::FINGER).x(301).y(101))
2994 .build());
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -07002995 rightWindow->consumeMotionEvent(
2996 AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(touchDeviceId)));
2997
2998 spyWindow->assertNoEvents();
2999 leftWindow->assertNoEvents();
3000 rightWindow->assertNoEvents();
3001}
3002
3003/**
Siarhei Vishniakoued89cbb2023-10-13 10:42:44 -07003004 * Three windows: a window on the left, a window on the right, and a spy window positioned above
3005 * both.
3006 * Check hover in left window and touch down in the right window.
3007 * At first, spy should receive hover. Next, spy should receive touch.
3008 * At the same time, left and right should be getting independent streams of hovering and touch,
3009 * respectively.
3010 */
3011TEST_F(InputDispatcherMultiDeviceTest, MultiDeviceHoverDoesNotBlockTouchWithSpy) {
3012 SCOPED_FLAG_OVERRIDE(enable_multi_device_same_window_stream, true);
3013 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
3014
3015 sp<FakeWindowHandle> spyWindow =
3016 sp<FakeWindowHandle>::make(application, mDispatcher, "Spy", ADISPLAY_ID_DEFAULT);
3017 spyWindow->setFrame(Rect(0, 0, 400, 400));
3018 spyWindow->setTrustedOverlay(true);
3019 spyWindow->setSpy(true);
3020
3021 sp<FakeWindowHandle> leftWindow =
3022 sp<FakeWindowHandle>::make(application, mDispatcher, "Left", ADISPLAY_ID_DEFAULT);
3023 leftWindow->setFrame(Rect(0, 0, 200, 200));
3024
3025 sp<FakeWindowHandle> rightWindow =
3026 sp<FakeWindowHandle>::make(application, mDispatcher, "Right", ADISPLAY_ID_DEFAULT);
3027 rightWindow->setFrame(Rect(200, 0, 400, 200));
3028
3029 mDispatcher->onWindowInfosChanged(
3030 {{*spyWindow->getInfo(), *leftWindow->getInfo(), *rightWindow->getInfo()}, {}, 0, 0});
3031
3032 const int32_t stylusDeviceId = 1;
3033 const int32_t touchDeviceId = 2;
3034
3035 // Stylus hover on the left window
3036 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_ENTER, AINPUT_SOURCE_STYLUS)
3037 .deviceId(stylusDeviceId)
3038 .pointer(PointerBuilder(0, ToolType::STYLUS).x(100).y(100))
3039 .build());
3040 leftWindow->consumeMotionEvent(
3041 AllOf(WithMotionAction(ACTION_HOVER_ENTER), WithDeviceId(stylusDeviceId)));
3042 spyWindow->consumeMotionEvent(
3043 AllOf(WithMotionAction(ACTION_HOVER_ENTER), WithDeviceId(stylusDeviceId)));
3044
3045 // Touch down on the right window.
3046 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
3047 .deviceId(touchDeviceId)
3048 .pointer(PointerBuilder(0, ToolType::FINGER).x(300).y(100))
3049 .build());
3050 leftWindow->assertNoEvents();
3051 spyWindow->consumeMotionEvent(
3052 AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(touchDeviceId)));
3053 rightWindow->consumeMotionEvent(
3054 AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(touchDeviceId)));
3055
3056 // Stylus movements continue. They should be delivered to the left window and the spy.
3057 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_MOVE, AINPUT_SOURCE_STYLUS)
3058 .deviceId(stylusDeviceId)
3059 .pointer(PointerBuilder(0, ToolType::STYLUS).x(110).y(110))
3060 .build());
3061 leftWindow->consumeMotionEvent(
3062 AllOf(WithMotionAction(ACTION_HOVER_MOVE), WithDeviceId(stylusDeviceId)));
3063 spyWindow->consumeMotionEvent(
3064 AllOf(WithMotionAction(ACTION_HOVER_MOVE), WithDeviceId(stylusDeviceId)));
3065
3066 // Touch movements continue. They should be delivered to the right window and the spy
3067 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN)
3068 .deviceId(touchDeviceId)
3069 .pointer(PointerBuilder(0, ToolType::FINGER).x(301).y(101))
3070 .build());
3071 rightWindow->consumeMotionEvent(
3072 AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(touchDeviceId)));
3073 spyWindow->consumeMotionEvent(
3074 AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(touchDeviceId)));
3075
3076 spyWindow->assertNoEvents();
3077 leftWindow->assertNoEvents();
3078 rightWindow->assertNoEvents();
3079}
3080
3081/**
Siarhei Vishniakouf372b812023-02-14 18:06:51 -08003082 * On a single window, use two different devices: mouse and touch.
3083 * Touch happens first, with two pointers going down, and then the first pointer leaving.
3084 * Mouse is clicked next, which causes the touch stream to be aborted with ACTION_CANCEL.
3085 * Finally, a second touch pointer goes down again. Ensure the second touch pointer is ignored,
3086 * because the mouse is currently down, and a POINTER_DOWN event from the touchscreen does not
3087 * represent a new gesture.
3088 */
Siarhei Vishniakoued89cbb2023-10-13 10:42:44 -07003089TEST_F(InputDispatcherMultiDeviceTest, MixedTouchAndMouseWithPointerDown_legacy) {
3090 SCOPED_FLAG_OVERRIDE(enable_multi_device_same_window_stream, false);
Siarhei Vishniakouf372b812023-02-14 18:06:51 -08003091 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
3092 sp<FakeWindowHandle> window =
3093 sp<FakeWindowHandle>::make(application, mDispatcher, "Window", ADISPLAY_ID_DEFAULT);
3094 window->setFrame(Rect(0, 0, 400, 400));
3095
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07003096 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Siarhei Vishniakouf372b812023-02-14 18:06:51 -08003097
3098 const int32_t touchDeviceId = 4;
3099 const int32_t mouseDeviceId = 6;
Siarhei Vishniakouf372b812023-02-14 18:06:51 -08003100
Siarhei Vishniakou4e1ffa52023-02-21 11:50:34 -08003101 // First touch pointer down
Prabir Pradhan678438e2023-04-13 19:32:51 +00003102 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
3103 .deviceId(touchDeviceId)
3104 .pointer(PointerBuilder(0, ToolType::FINGER).x(300).y(100))
3105 .build());
Siarhei Vishniakouf372b812023-02-14 18:06:51 -08003106 // Second touch pointer down
Prabir Pradhan678438e2023-04-13 19:32:51 +00003107 mDispatcher->notifyMotion(MotionArgsBuilder(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
3108 .deviceId(touchDeviceId)
3109 .pointer(PointerBuilder(0, ToolType::FINGER).x(300).y(100))
3110 .pointer(PointerBuilder(1, ToolType::FINGER).x(350).y(100))
3111 .build());
Siarhei Vishniakouf372b812023-02-14 18:06:51 -08003112 // First touch pointer lifts. The second one remains down
Prabir Pradhan678438e2023-04-13 19:32:51 +00003113 mDispatcher->notifyMotion(MotionArgsBuilder(POINTER_0_UP, AINPUT_SOURCE_TOUCHSCREEN)
3114 .deviceId(touchDeviceId)
3115 .pointer(PointerBuilder(0, ToolType::FINGER).x(300).y(100))
3116 .pointer(PointerBuilder(1, ToolType::FINGER).x(350).y(100))
3117 .build());
Siarhei Vishniakouf372b812023-02-14 18:06:51 -08003118 window->consumeMotionEvent(WithMotionAction(ACTION_DOWN));
3119 window->consumeMotionEvent(WithMotionAction(POINTER_1_DOWN));
3120 window->consumeMotionEvent(WithMotionAction(POINTER_0_UP));
3121
3122 // Mouse down. The touch should be canceled
Prabir Pradhan678438e2023-04-13 19:32:51 +00003123 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_MOUSE)
3124 .deviceId(mouseDeviceId)
3125 .buttonState(AMOTION_EVENT_BUTTON_PRIMARY)
3126 .pointer(PointerBuilder(0, ToolType::MOUSE).x(320).y(100))
3127 .build());
Siarhei Vishniakouf372b812023-02-14 18:06:51 -08003128
3129 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_CANCEL), WithDeviceId(touchDeviceId),
Siarhei Vishniakou82dc0422023-02-17 23:12:52 -08003130 WithPointerCount(1u)));
Siarhei Vishniakouf372b812023-02-14 18:06:51 -08003131 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(mouseDeviceId)));
3132
Prabir Pradhan678438e2023-04-13 19:32:51 +00003133 mDispatcher->notifyMotion(
3134 MotionArgsBuilder(AMOTION_EVENT_ACTION_BUTTON_PRESS, AINPUT_SOURCE_MOUSE)
3135 .deviceId(mouseDeviceId)
3136 .buttonState(AMOTION_EVENT_BUTTON_PRIMARY)
3137 .actionButton(AMOTION_EVENT_BUTTON_PRIMARY)
3138 .pointer(PointerBuilder(0, ToolType::MOUSE).x(320).y(100))
3139 .build());
Siarhei Vishniakouf372b812023-02-14 18:06:51 -08003140 window->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_BUTTON_PRESS));
3141
3142 // Second touch pointer down.
Prabir Pradhan678438e2023-04-13 19:32:51 +00003143 mDispatcher->notifyMotion(MotionArgsBuilder(POINTER_0_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
3144 .deviceId(touchDeviceId)
3145 .pointer(PointerBuilder(0, ToolType::FINGER).x(300).y(100))
3146 .pointer(PointerBuilder(1, ToolType::FINGER).x(350).y(100))
3147 .build());
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -07003148 // Since we already canceled this touch gesture, it will be ignored until a completely new
3149 // gesture is started. This is easier to implement than trying to keep track of the new pointer
3150 // and generating an ACTION_DOWN instead of ACTION_POINTER_DOWN.
3151 // However, mouse movements should continue to work.
3152 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_MOUSE)
3153 .deviceId(mouseDeviceId)
3154 .buttonState(AMOTION_EVENT_BUTTON_PRIMARY)
3155 .pointer(PointerBuilder(0, ToolType::MOUSE).x(330).y(110))
3156 .build());
3157 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(mouseDeviceId)));
3158
Siarhei Vishniakouf372b812023-02-14 18:06:51 -08003159 window->assertNoEvents();
3160}
3161
3162/**
Siarhei Vishniakoued89cbb2023-10-13 10:42:44 -07003163 * On a single window, use two different devices: mouse and touch.
3164 * Touch happens first, with two pointers going down, and then the first pointer leaving.
3165 * Mouse is clicked next, which should not interfere with the touch stream.
3166 * Finally, a second touch pointer goes down again. Ensure the second touch pointer is also
3167 * delivered correctly.
3168 */
3169TEST_F(InputDispatcherMultiDeviceTest, MixedTouchAndMouseWithPointerDown) {
3170 SCOPED_FLAG_OVERRIDE(enable_multi_device_same_window_stream, true);
3171 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
3172 sp<FakeWindowHandle> window =
3173 sp<FakeWindowHandle>::make(application, mDispatcher, "Window", ADISPLAY_ID_DEFAULT);
3174 window->setFrame(Rect(0, 0, 400, 400));
3175
3176 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
3177
3178 const int32_t touchDeviceId = 4;
3179 const int32_t mouseDeviceId = 6;
3180
3181 // First touch pointer down
3182 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
3183 .deviceId(touchDeviceId)
3184 .pointer(PointerBuilder(0, ToolType::FINGER).x(300).y(100))
3185 .build());
3186 // Second touch pointer down
3187 mDispatcher->notifyMotion(MotionArgsBuilder(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
3188 .deviceId(touchDeviceId)
3189 .pointer(PointerBuilder(0, ToolType::FINGER).x(300).y(100))
3190 .pointer(PointerBuilder(1, ToolType::FINGER).x(350).y(100))
3191 .build());
3192 // First touch pointer lifts. The second one remains down
3193 mDispatcher->notifyMotion(MotionArgsBuilder(POINTER_0_UP, AINPUT_SOURCE_TOUCHSCREEN)
3194 .deviceId(touchDeviceId)
3195 .pointer(PointerBuilder(0, ToolType::FINGER).x(300).y(100))
3196 .pointer(PointerBuilder(1, ToolType::FINGER).x(350).y(100))
3197 .build());
3198 window->consumeMotionEvent(WithMotionAction(ACTION_DOWN));
3199 window->consumeMotionEvent(WithMotionAction(POINTER_1_DOWN));
3200 window->consumeMotionEvent(WithMotionAction(POINTER_0_UP));
3201
3202 // Mouse down
3203 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_MOUSE)
3204 .deviceId(mouseDeviceId)
3205 .buttonState(AMOTION_EVENT_BUTTON_PRIMARY)
3206 .pointer(PointerBuilder(0, ToolType::MOUSE).x(320).y(100))
3207 .build());
3208
3209 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(mouseDeviceId)));
3210
3211 mDispatcher->notifyMotion(
3212 MotionArgsBuilder(AMOTION_EVENT_ACTION_BUTTON_PRESS, AINPUT_SOURCE_MOUSE)
3213 .deviceId(mouseDeviceId)
3214 .buttonState(AMOTION_EVENT_BUTTON_PRIMARY)
3215 .actionButton(AMOTION_EVENT_BUTTON_PRIMARY)
3216 .pointer(PointerBuilder(0, ToolType::MOUSE).x(320).y(100))
3217 .build());
3218 window->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_BUTTON_PRESS));
3219
3220 // Second touch pointer down.
3221 mDispatcher->notifyMotion(MotionArgsBuilder(POINTER_0_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
3222 .deviceId(touchDeviceId)
3223 .pointer(PointerBuilder(0, ToolType::FINGER).x(300).y(100))
3224 .pointer(PointerBuilder(1, ToolType::FINGER).x(350).y(100))
3225 .build());
3226 window->consumeMotionEvent(AllOf(WithMotionAction(POINTER_0_DOWN), WithDeviceId(touchDeviceId),
3227 WithPointerCount(2u)));
3228
3229 // Mouse movements should continue to work
3230 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_MOUSE)
3231 .deviceId(mouseDeviceId)
3232 .buttonState(AMOTION_EVENT_BUTTON_PRIMARY)
3233 .pointer(PointerBuilder(0, ToolType::MOUSE).x(330).y(110))
3234 .build());
3235 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(mouseDeviceId)));
3236
3237 window->assertNoEvents();
3238}
3239
3240/**
Siarhei Vishniakou56e79092023-02-21 19:13:16 -08003241 * Inject a touch down and then send a new event via 'notifyMotion'. Ensure the new event cancels
3242 * the injected event.
3243 */
Siarhei Vishniakoued89cbb2023-10-13 10:42:44 -07003244TEST_F(InputDispatcherMultiDeviceTest, UnfinishedInjectedEvent_legacy) {
3245 SCOPED_FLAG_OVERRIDE(enable_multi_device_same_window_stream, false);
Siarhei Vishniakou56e79092023-02-21 19:13:16 -08003246 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
3247 sp<FakeWindowHandle> window =
3248 sp<FakeWindowHandle>::make(application, mDispatcher, "Window", ADISPLAY_ID_DEFAULT);
3249 window->setFrame(Rect(0, 0, 400, 400));
3250
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07003251 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Siarhei Vishniakou56e79092023-02-21 19:13:16 -08003252
3253 const int32_t touchDeviceId = 4;
Siarhei Vishniakou56e79092023-02-21 19:13:16 -08003254 // Pretend a test injects an ACTION_DOWN mouse event, but forgets to lift up the touch after
3255 // completion.
3256 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07003257 injectMotionEvent(*mDispatcher,
Siarhei Vishniakou56e79092023-02-21 19:13:16 -08003258 MotionEventBuilder(ACTION_DOWN, AINPUT_SOURCE_MOUSE)
3259 .deviceId(ReservedInputDeviceId::VIRTUAL_KEYBOARD_ID)
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07003260 .pointer(PointerBuilder(0, ToolType::MOUSE).x(50).y(50))
Siarhei Vishniakou56e79092023-02-21 19:13:16 -08003261 .build()));
3262 window->consumeMotionEvent(
3263 AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(VIRTUAL_KEYBOARD_ID)));
3264
3265 // Now a real touch comes. Rather than crashing or dropping the real event, the injected pointer
3266 // should be canceled and the new gesture should take over.
Prabir Pradhan678438e2023-04-13 19:32:51 +00003267 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
3268 .deviceId(touchDeviceId)
3269 .pointer(PointerBuilder(0, ToolType::FINGER).x(300).y(100))
3270 .build());
Siarhei Vishniakou56e79092023-02-21 19:13:16 -08003271
3272 window->consumeMotionEvent(
3273 AllOf(WithMotionAction(ACTION_CANCEL), WithDeviceId(VIRTUAL_KEYBOARD_ID)));
3274 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(touchDeviceId)));
3275}
3276
3277/**
Siarhei Vishniakoued89cbb2023-10-13 10:42:44 -07003278 * Inject a touch down and then send a new event via 'notifyMotion'. Ensure the new event runs
3279 * parallel to the injected event.
3280 */
3281TEST_F(InputDispatcherMultiDeviceTest, UnfinishedInjectedEvent) {
3282 SCOPED_FLAG_OVERRIDE(enable_multi_device_same_window_stream, true);
3283 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
3284 sp<FakeWindowHandle> window =
3285 sp<FakeWindowHandle>::make(application, mDispatcher, "Window", ADISPLAY_ID_DEFAULT);
3286 window->setFrame(Rect(0, 0, 400, 400));
3287
3288 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
3289
3290 const int32_t touchDeviceId = 4;
3291 // Pretend a test injects an ACTION_DOWN mouse event, but forgets to lift up the touch after
3292 // completion.
3293 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
3294 injectMotionEvent(*mDispatcher,
3295 MotionEventBuilder(ACTION_DOWN, AINPUT_SOURCE_MOUSE)
3296 .deviceId(ReservedInputDeviceId::VIRTUAL_KEYBOARD_ID)
3297 .pointer(PointerBuilder(0, ToolType::MOUSE).x(50).y(50))
3298 .build()));
3299 window->consumeMotionEvent(
3300 AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(VIRTUAL_KEYBOARD_ID)));
3301
3302 // Now a real touch comes. The injected pointer will remain, and the new gesture will also be
3303 // allowed through.
3304 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
3305 .deviceId(touchDeviceId)
3306 .pointer(PointerBuilder(0, ToolType::FINGER).x(300).y(100))
3307 .build());
3308 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(touchDeviceId)));
3309}
3310
3311/**
Siarhei Vishniakou6464e462023-02-06 18:57:59 -08003312 * This test is similar to the test above, but the sequence of injected events is different.
3313 *
3314 * Two windows: a window on the left and a window on the right.
3315 * Mouse is hovered over the left window.
3316 * Next, we tap on the left window, where the cursor was last seen.
3317 *
3318 * After that, we inject one finger down onto the right window, and then a second finger down onto
3319 * the left window.
3320 * The touch is split, so this last gesture should cause 2 ACTION_DOWN events, one in the right
3321 * window (first), and then another on the left window (second).
3322 * This test reproduces a crash where there is a mismatch between the downTime and eventTime.
3323 * In the buggy implementation, second finger down on the left window would cause a crash.
3324 */
Siarhei Vishniakoued89cbb2023-10-13 10:42:44 -07003325TEST_F(InputDispatcherMultiDeviceTest, HoverTapAndSplitTouch_legacy) {
3326 SCOPED_FLAG_OVERRIDE(enable_multi_device_same_window_stream, false);
Siarhei Vishniakou6464e462023-02-06 18:57:59 -08003327 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
3328 sp<FakeWindowHandle> leftWindow =
3329 sp<FakeWindowHandle>::make(application, mDispatcher, "Left", ADISPLAY_ID_DEFAULT);
3330 leftWindow->setFrame(Rect(0, 0, 200, 200));
3331
3332 sp<FakeWindowHandle> rightWindow =
3333 sp<FakeWindowHandle>::make(application, mDispatcher, "Right", ADISPLAY_ID_DEFAULT);
3334 rightWindow->setFrame(Rect(200, 0, 400, 200));
3335
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07003336 mDispatcher->onWindowInfosChanged(
3337 {{*leftWindow->getInfo(), *rightWindow->getInfo()}, {}, 0, 0});
Siarhei Vishniakou6464e462023-02-06 18:57:59 -08003338
3339 const int32_t mouseDeviceId = 6;
3340 const int32_t touchDeviceId = 4;
3341 // Hover over the left window. Keep the cursor there.
3342 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07003343 injectMotionEvent(*mDispatcher,
Siarhei Vishniakou6464e462023-02-06 18:57:59 -08003344 MotionEventBuilder(AMOTION_EVENT_ACTION_HOVER_ENTER,
3345 AINPUT_SOURCE_MOUSE)
3346 .deviceId(mouseDeviceId)
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07003347 .pointer(PointerBuilder(0, ToolType::MOUSE).x(50).y(50))
Siarhei Vishniakou6464e462023-02-06 18:57:59 -08003348 .build()));
3349 leftWindow->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_ENTER));
3350
3351 // Tap on left window
3352 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07003353 injectMotionEvent(*mDispatcher,
Siarhei Vishniakou6464e462023-02-06 18:57:59 -08003354 MotionEventBuilder(AMOTION_EVENT_ACTION_DOWN,
3355 AINPUT_SOURCE_TOUCHSCREEN)
3356 .deviceId(touchDeviceId)
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07003357 .pointer(PointerBuilder(0, ToolType::FINGER).x(100).y(100))
Siarhei Vishniakou6464e462023-02-06 18:57:59 -08003358 .build()));
3359
3360 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07003361 injectMotionEvent(*mDispatcher,
Siarhei Vishniakou6464e462023-02-06 18:57:59 -08003362 MotionEventBuilder(AMOTION_EVENT_ACTION_UP,
3363 AINPUT_SOURCE_TOUCHSCREEN)
3364 .deviceId(touchDeviceId)
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07003365 .pointer(PointerBuilder(0, ToolType::FINGER).x(100).y(100))
Siarhei Vishniakou6464e462023-02-06 18:57:59 -08003366 .build()));
3367 leftWindow->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_EXIT));
3368 leftWindow->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_DOWN));
3369 leftWindow->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_UP));
3370
3371 // First finger down on right window
3372 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07003373 injectMotionEvent(*mDispatcher,
Siarhei Vishniakou6464e462023-02-06 18:57:59 -08003374 MotionEventBuilder(AMOTION_EVENT_ACTION_DOWN,
3375 AINPUT_SOURCE_TOUCHSCREEN)
3376 .deviceId(touchDeviceId)
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07003377 .pointer(PointerBuilder(0, ToolType::FINGER).x(300).y(100))
Siarhei Vishniakou6464e462023-02-06 18:57:59 -08003378 .build()));
3379 rightWindow->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_DOWN));
3380
3381 // Second finger down on the left window
3382 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07003383 injectMotionEvent(*mDispatcher,
Siarhei Vishniakou6464e462023-02-06 18:57:59 -08003384 MotionEventBuilder(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
3385 .deviceId(touchDeviceId)
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07003386 .pointer(PointerBuilder(0, ToolType::FINGER).x(300).y(100))
3387 .pointer(PointerBuilder(1, ToolType::FINGER).x(100).y(100))
Siarhei Vishniakou6464e462023-02-06 18:57:59 -08003388 .build()));
3389 leftWindow->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_DOWN));
3390 rightWindow->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_MOVE));
3391
3392 // No more events
3393 leftWindow->assertNoEvents();
3394 rightWindow->assertNoEvents();
3395}
3396
3397/**
Siarhei Vishniakoued89cbb2023-10-13 10:42:44 -07003398 * This test is similar to the test above, but the sequence of injected events is different.
3399 *
3400 * Two windows: a window on the left and a window on the right.
3401 * Mouse is hovered over the left window.
3402 * Next, we tap on the left window, where the cursor was last seen.
3403 *
3404 * After that, we send one finger down onto the right window, and then a second finger down onto
3405 * the left window.
3406 * The touch is split, so this last gesture should cause 2 ACTION_DOWN events, one in the right
3407 * window (first), and then another on the left window (second).
3408 * This test reproduces a crash where there is a mismatch between the downTime and eventTime.
3409 * In the buggy implementation, second finger down on the left window would cause a crash.
3410 */
3411TEST_F(InputDispatcherMultiDeviceTest, HoverTapAndSplitTouch) {
3412 SCOPED_FLAG_OVERRIDE(enable_multi_device_same_window_stream, true);
3413 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
3414 sp<FakeWindowHandle> leftWindow =
3415 sp<FakeWindowHandle>::make(application, mDispatcher, "Left", ADISPLAY_ID_DEFAULT);
3416 leftWindow->setFrame(Rect(0, 0, 200, 200));
3417
3418 sp<FakeWindowHandle> rightWindow =
3419 sp<FakeWindowHandle>::make(application, mDispatcher, "Right", ADISPLAY_ID_DEFAULT);
3420 rightWindow->setFrame(Rect(200, 0, 400, 200));
3421
3422 mDispatcher->onWindowInfosChanged(
3423 {{*leftWindow->getInfo(), *rightWindow->getInfo()}, {}, 0, 0});
3424
3425 const int32_t mouseDeviceId = 6;
3426 const int32_t touchDeviceId = 4;
3427 // Hover over the left window. Keep the cursor there.
3428 mDispatcher->notifyMotion(
3429 MotionArgsBuilder(AMOTION_EVENT_ACTION_HOVER_ENTER, AINPUT_SOURCE_MOUSE)
3430 .deviceId(mouseDeviceId)
3431 .pointer(PointerBuilder(0, ToolType::MOUSE).x(50).y(50))
3432 .build());
3433 leftWindow->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_ENTER));
3434
3435 // Tap on left window
3436 mDispatcher->notifyMotion(
3437 MotionArgsBuilder(AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
3438 .deviceId(touchDeviceId)
3439 .pointer(PointerBuilder(0, ToolType::FINGER).x(100).y(100))
3440 .build());
3441
3442 mDispatcher->notifyMotion(MotionArgsBuilder(AMOTION_EVENT_ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN)
3443 .deviceId(touchDeviceId)
3444 .pointer(PointerBuilder(0, ToolType::FINGER).x(100).y(100))
3445 .build());
3446 leftWindow->consumeMotionEvent(
3447 AllOf(WithMotionAction(AMOTION_EVENT_ACTION_DOWN), WithDeviceId(touchDeviceId)));
3448 leftWindow->consumeMotionEvent(
3449 AllOf(WithMotionAction(AMOTION_EVENT_ACTION_UP), WithDeviceId(touchDeviceId)));
3450
3451 // First finger down on right window
3452 mDispatcher->notifyMotion(
3453 MotionArgsBuilder(AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
3454 .deviceId(touchDeviceId)
3455 .pointer(PointerBuilder(0, ToolType::FINGER).x(300).y(100))
3456 .build());
3457 rightWindow->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_DOWN));
3458
3459 // Second finger down on the left window
3460 mDispatcher->notifyMotion(MotionArgsBuilder(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
3461 .deviceId(touchDeviceId)
3462 .pointer(PointerBuilder(0, ToolType::FINGER).x(300).y(100))
3463 .pointer(PointerBuilder(1, ToolType::FINGER).x(100).y(100))
3464 .build());
3465 leftWindow->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_DOWN));
3466 rightWindow->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_MOVE));
3467
3468 // No more events
3469 leftWindow->assertNoEvents();
3470 rightWindow->assertNoEvents();
3471}
3472
3473/**
Siarhei Vishniakou2e3e4432023-02-09 18:34:11 -08003474 * Start hovering with a stylus device, and then tap with a touch device. Ensure no crash occurs.
3475 * While the touch is down, new hover events from the stylus device should be ignored. After the
3476 * touch is gone, stylus hovering should start working again.
3477 */
Siarhei Vishniakou3ad54f52023-11-02 16:54:40 -07003478TEST_F(InputDispatcherMultiDeviceTest, StylusHoverIgnoresTouchTap) {
Siarhei Vishniakoued89cbb2023-10-13 10:42:44 -07003479 SCOPED_FLAG_OVERRIDE(enable_multi_device_same_window_stream, false);
Siarhei Vishniakou2e3e4432023-02-09 18:34:11 -08003480 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
3481 sp<FakeWindowHandle> window =
3482 sp<FakeWindowHandle>::make(application, mDispatcher, "Window", ADISPLAY_ID_DEFAULT);
3483 window->setFrame(Rect(0, 0, 200, 200));
3484
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07003485 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Siarhei Vishniakou2e3e4432023-02-09 18:34:11 -08003486
3487 const int32_t stylusDeviceId = 5;
3488 const int32_t touchDeviceId = 4;
3489 // Start hovering with stylus
3490 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07003491 injectMotionEvent(*mDispatcher,
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -07003492 MotionEventBuilder(ACTION_HOVER_ENTER, AINPUT_SOURCE_STYLUS)
Siarhei Vishniakou2e3e4432023-02-09 18:34:11 -08003493 .deviceId(stylusDeviceId)
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07003494 .pointer(PointerBuilder(0, ToolType::STYLUS).x(50).y(50))
Siarhei Vishniakou2e3e4432023-02-09 18:34:11 -08003495 .build()));
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -07003496 window->consumeMotionEvent(WithMotionAction(ACTION_HOVER_ENTER));
Siarhei Vishniakou2e3e4432023-02-09 18:34:11 -08003497
3498 // Finger down on the window
3499 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07003500 injectMotionEvent(*mDispatcher,
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -07003501 MotionEventBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
Siarhei Vishniakou2e3e4432023-02-09 18:34:11 -08003502 .deviceId(touchDeviceId)
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07003503 .pointer(PointerBuilder(0, ToolType::FINGER).x(100).y(100))
Siarhei Vishniakou2e3e4432023-02-09 18:34:11 -08003504 .build()));
Siarhei Vishniakou3ad54f52023-11-02 16:54:40 -07003505 // The touch device should be ignored!
Siarhei Vishniakou2e3e4432023-02-09 18:34:11 -08003506
Siarhei Vishniakou2899c552023-07-10 18:20:46 -07003507 // Continue hovering with stylus.
3508 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07003509 injectMotionEvent(*mDispatcher,
Siarhei Vishniakou2e3e4432023-02-09 18:34:11 -08003510 MotionEventBuilder(AMOTION_EVENT_ACTION_HOVER_MOVE,
3511 AINPUT_SOURCE_STYLUS)
3512 .deviceId(stylusDeviceId)
Siarhei Vishniakou25537f82023-07-18 14:35:47 -07003513 .pointer(PointerBuilder(0, ToolType::STYLUS).x(60).y(60))
Siarhei Vishniakou2e3e4432023-02-09 18:34:11 -08003514 .build()));
Siarhei Vishniakou3ad54f52023-11-02 16:54:40 -07003515 // Hovers continue to work
3516 window->consumeMotionEvent(
3517 AllOf(WithMotionAction(ACTION_HOVER_MOVE), WithDeviceId(stylusDeviceId)));
Siarhei Vishniakou2e3e4432023-02-09 18:34:11 -08003518
3519 // Lift up the finger
3520 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07003521 injectMotionEvent(*mDispatcher,
Siarhei Vishniakou2e3e4432023-02-09 18:34:11 -08003522 MotionEventBuilder(AMOTION_EVENT_ACTION_UP,
3523 AINPUT_SOURCE_TOUCHSCREEN)
3524 .deviceId(touchDeviceId)
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07003525 .pointer(PointerBuilder(0, ToolType::FINGER).x(100).y(100))
Siarhei Vishniakou2e3e4432023-02-09 18:34:11 -08003526 .build()));
Siarhei Vishniakou2e3e4432023-02-09 18:34:11 -08003527
Siarhei Vishniakou2e3e4432023-02-09 18:34:11 -08003528 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07003529 injectMotionEvent(*mDispatcher,
Siarhei Vishniakou2e3e4432023-02-09 18:34:11 -08003530 MotionEventBuilder(AMOTION_EVENT_ACTION_HOVER_MOVE,
3531 AINPUT_SOURCE_STYLUS)
3532 .deviceId(stylusDeviceId)
Siarhei Vishniakou25537f82023-07-18 14:35:47 -07003533 .pointer(PointerBuilder(0, ToolType::STYLUS).x(70).y(70))
Siarhei Vishniakou2e3e4432023-02-09 18:34:11 -08003534 .build()));
Siarhei Vishniakou3ad54f52023-11-02 16:54:40 -07003535 window->consumeMotionEvent(
3536 AllOf(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_MOVE), WithDeviceId(stylusDeviceId)));
Siarhei Vishniakou2e3e4432023-02-09 18:34:11 -08003537 window->assertNoEvents();
3538}
3539
3540/**
Siarhei Vishniakoued89cbb2023-10-13 10:42:44 -07003541 * Start hovering with a stylus device, and then tap with a touch device. Ensure no crash occurs.
3542 * While the touch is down, hovering from the stylus is not affected. After the touch is gone,
3543 * check that the stylus hovering continues to work.
3544 */
3545TEST_F(InputDispatcherMultiDeviceTest, StylusHoverWithTouchTap) {
3546 SCOPED_FLAG_OVERRIDE(enable_multi_device_same_window_stream, true);
3547 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
3548 sp<FakeWindowHandle> window =
3549 sp<FakeWindowHandle>::make(application, mDispatcher, "Window", ADISPLAY_ID_DEFAULT);
3550 window->setFrame(Rect(0, 0, 200, 200));
3551
3552 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
3553
3554 const int32_t stylusDeviceId = 5;
3555 const int32_t touchDeviceId = 4;
3556 // Start hovering with stylus
3557 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_ENTER, AINPUT_SOURCE_STYLUS)
3558 .deviceId(stylusDeviceId)
3559 .pointer(PointerBuilder(0, ToolType::STYLUS).x(50).y(50))
3560 .build());
3561 window->consumeMotionEvent(WithMotionAction(ACTION_HOVER_ENTER));
3562
3563 // Finger down on the window
3564 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
3565 .deviceId(touchDeviceId)
3566 .pointer(PointerBuilder(0, ToolType::FINGER).x(100).y(100))
3567 .build());
3568 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(touchDeviceId)));
3569
3570 // Continue hovering with stylus.
3571 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_MOVE, AINPUT_SOURCE_STYLUS)
3572 .deviceId(stylusDeviceId)
3573 .pointer(PointerBuilder(0, ToolType::STYLUS).x(60).y(60))
3574 .build());
3575 // Hovers continue to work
3576 window->consumeMotionEvent(
3577 AllOf(WithMotionAction(ACTION_HOVER_MOVE), WithDeviceId(stylusDeviceId)));
3578
3579 // Lift up the finger
3580 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN)
3581 .deviceId(touchDeviceId)
3582 .pointer(PointerBuilder(0, ToolType::FINGER).x(100).y(100))
3583 .build());
3584 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_UP), WithDeviceId(touchDeviceId)));
3585
3586 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_MOVE, AINPUT_SOURCE_STYLUS)
3587 .deviceId(stylusDeviceId)
3588 .pointer(PointerBuilder(0, ToolType::STYLUS).x(70).y(70))
3589 .build());
3590 window->consumeMotionEvent(
3591 AllOf(WithMotionAction(ACTION_HOVER_MOVE), WithDeviceId(stylusDeviceId)));
3592 window->assertNoEvents();
3593}
3594
3595/**
Siarhei Vishniakouf77f60a2023-10-23 17:26:05 -07003596 * If stylus is down anywhere on the screen, then touches should not be delivered to windows that
3597 * have InputConfig::GLOBAL_STYLUS_BLOCKS_TOUCH.
3598 *
3599 * Two windows: one on the left and one on the right.
3600 * The window on the right has GLOBAL_STYLUS_BLOCKS_TOUCH config.
3601 * Stylus down on the left window, and then touch down on the right window.
3602 * Check that the right window doesn't get touches while the stylus is down on the left window.
3603 */
3604TEST_F(InputDispatcherMultiDeviceTest, GlobalStylusDownBlocksTouch) {
3605 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
3606 sp<FakeWindowHandle> leftWindow =
3607 sp<FakeWindowHandle>::make(application, mDispatcher, "Left window",
3608 ADISPLAY_ID_DEFAULT);
3609 leftWindow->setFrame(Rect(0, 0, 100, 100));
3610
3611 sp<FakeWindowHandle> sbtRightWindow =
3612 sp<FakeWindowHandle>::make(application, mDispatcher,
3613 "Stylus blocks touch (right) window", ADISPLAY_ID_DEFAULT);
3614 sbtRightWindow->setFrame(Rect(100, 100, 200, 200));
3615 sbtRightWindow->setGlobalStylusBlocksTouch(true);
3616
3617 mDispatcher->onWindowInfosChanged(
3618 {{*leftWindow->getInfo(), *sbtRightWindow->getInfo()}, {}, 0, 0});
3619
3620 const int32_t stylusDeviceId = 5;
3621 const int32_t touchDeviceId = 4;
3622
3623 // Stylus down in the left window
3624 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_STYLUS)
3625 .pointer(PointerBuilder(0, ToolType::STYLUS).x(50).y(52))
3626 .deviceId(stylusDeviceId)
3627 .build());
3628 leftWindow->consumeMotionEvent(
3629 AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(stylusDeviceId)));
3630
3631 // Finger tap on the right window
3632 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
3633 .pointer(PointerBuilder(0, ToolType::FINGER).x(150).y(151))
3634 .deviceId(touchDeviceId)
3635 .build());
3636 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN)
3637 .pointer(PointerBuilder(0, ToolType::FINGER).x(150).y(151))
3638 .deviceId(touchDeviceId)
3639 .build());
3640
3641 // The touch should be blocked, because stylus is down somewhere else on screen!
3642 sbtRightWindow->assertNoEvents();
3643
3644 // Continue stylus motion, and ensure it's not impacted.
3645 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_STYLUS)
3646 .pointer(PointerBuilder(0, ToolType::STYLUS).x(51).y(53))
3647 .deviceId(stylusDeviceId)
3648 .build());
3649 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_UP, AINPUT_SOURCE_STYLUS)
3650 .pointer(PointerBuilder(0, ToolType::STYLUS).x(51).y(53))
3651 .deviceId(stylusDeviceId)
3652 .build());
3653 leftWindow->consumeMotionEvent(
3654 AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(stylusDeviceId)));
3655 leftWindow->consumeMotionEvent(
3656 AllOf(WithMotionAction(ACTION_UP), WithDeviceId(stylusDeviceId)));
3657
3658 // Now that the stylus gesture is done, touches should be getting delivered correctly.
3659 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
3660 .pointer(PointerBuilder(0, ToolType::FINGER).x(151).y(153))
3661 .deviceId(touchDeviceId)
3662 .build());
3663 sbtRightWindow->consumeMotionEvent(
3664 AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(touchDeviceId)));
3665}
3666
3667/**
3668 * If stylus is hovering anywhere on the screen, then touches should not be delivered to windows
3669 * that have InputConfig::GLOBAL_STYLUS_BLOCKS_TOUCH.
3670 *
3671 * Two windows: one on the left and one on the right.
3672 * The window on the right has GLOBAL_STYLUS_BLOCKS_TOUCH config.
3673 * Stylus hover on the left window, and then touch down on the right window.
3674 * Check that the right window doesn't get touches while the stylus is hovering on the left window.
3675 */
3676TEST_F(InputDispatcherMultiDeviceTest, GlobalStylusHoverBlocksTouch) {
3677 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
3678 sp<FakeWindowHandle> leftWindow =
3679 sp<FakeWindowHandle>::make(application, mDispatcher, "Left window",
3680 ADISPLAY_ID_DEFAULT);
3681 leftWindow->setFrame(Rect(0, 0, 100, 100));
3682
3683 sp<FakeWindowHandle> sbtRightWindow =
3684 sp<FakeWindowHandle>::make(application, mDispatcher,
3685 "Stylus blocks touch (right) window", ADISPLAY_ID_DEFAULT);
3686 sbtRightWindow->setFrame(Rect(100, 100, 200, 200));
3687 sbtRightWindow->setGlobalStylusBlocksTouch(true);
3688
3689 mDispatcher->onWindowInfosChanged(
3690 {{*leftWindow->getInfo(), *sbtRightWindow->getInfo()}, {}, 0, 0});
3691
3692 const int32_t stylusDeviceId = 5;
3693 const int32_t touchDeviceId = 4;
3694
3695 // Stylus hover in the left window
3696 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_ENTER, AINPUT_SOURCE_STYLUS)
3697 .pointer(PointerBuilder(0, ToolType::STYLUS).x(50).y(52))
3698 .deviceId(stylusDeviceId)
3699 .build());
3700 leftWindow->consumeMotionEvent(
3701 AllOf(WithMotionAction(ACTION_HOVER_ENTER), WithDeviceId(stylusDeviceId)));
3702
3703 // Finger tap on the right window
3704 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
3705 .pointer(PointerBuilder(0, ToolType::FINGER).x(150).y(151))
3706 .deviceId(touchDeviceId)
3707 .build());
3708 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN)
3709 .pointer(PointerBuilder(0, ToolType::FINGER).x(150).y(151))
3710 .deviceId(touchDeviceId)
3711 .build());
3712
3713 // The touch should be blocked, because stylus is hovering somewhere else on screen!
3714 sbtRightWindow->assertNoEvents();
3715
3716 // Continue stylus motion, and ensure it's not impacted.
3717 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_MOVE, AINPUT_SOURCE_STYLUS)
3718 .pointer(PointerBuilder(0, ToolType::STYLUS).x(51).y(53))
3719 .deviceId(stylusDeviceId)
3720 .build());
3721 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_EXIT, AINPUT_SOURCE_STYLUS)
3722 .pointer(PointerBuilder(0, ToolType::STYLUS).x(51).y(53))
3723 .deviceId(stylusDeviceId)
3724 .build());
3725 leftWindow->consumeMotionEvent(
3726 AllOf(WithMotionAction(ACTION_HOVER_MOVE), WithDeviceId(stylusDeviceId)));
3727 leftWindow->consumeMotionEvent(
3728 AllOf(WithMotionAction(ACTION_HOVER_EXIT), WithDeviceId(stylusDeviceId)));
3729
3730 // Now that the stylus gesture is done, touches should be getting delivered correctly.
3731 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
3732 .pointer(PointerBuilder(0, ToolType::FINGER).x(151).y(153))
3733 .deviceId(touchDeviceId)
3734 .build());
3735 sbtRightWindow->consumeMotionEvent(
3736 AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(touchDeviceId)));
3737}
3738
3739/**
Siarhei Vishniakouf372b812023-02-14 18:06:51 -08003740 * A spy window above a window with no input channel.
3741 * Start hovering with a stylus device, and then tap with it.
3742 * Ensure spy window receives the entire sequence.
3743 */
3744TEST_F(InputDispatcherTest, StylusHoverAndDownNoInputChannel) {
3745 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
3746 sp<FakeWindowHandle> spyWindow =
3747 sp<FakeWindowHandle>::make(application, mDispatcher, "Spy", ADISPLAY_ID_DEFAULT);
3748 spyWindow->setFrame(Rect(0, 0, 200, 200));
3749 spyWindow->setTrustedOverlay(true);
3750 spyWindow->setSpy(true);
3751 sp<FakeWindowHandle> window =
3752 sp<FakeWindowHandle>::make(application, mDispatcher, "Window", ADISPLAY_ID_DEFAULT);
3753 window->setNoInputChannel(true);
3754 window->setFrame(Rect(0, 0, 200, 200));
3755
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07003756 mDispatcher->onWindowInfosChanged({{*spyWindow->getInfo(), *window->getInfo()}, {}, 0, 0});
Siarhei Vishniakouf372b812023-02-14 18:06:51 -08003757
Siarhei Vishniakouf372b812023-02-14 18:06:51 -08003758 // Start hovering with stylus
Prabir Pradhan678438e2023-04-13 19:32:51 +00003759 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_ENTER, AINPUT_SOURCE_STYLUS)
3760 .pointer(PointerBuilder(0, ToolType::STYLUS).x(50).y(50))
3761 .build());
Siarhei Vishniakouf372b812023-02-14 18:06:51 -08003762 spyWindow->consumeMotionEvent(WithMotionAction(ACTION_HOVER_ENTER));
3763 // Stop hovering
Prabir Pradhan678438e2023-04-13 19:32:51 +00003764 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_EXIT, AINPUT_SOURCE_STYLUS)
3765 .pointer(PointerBuilder(0, ToolType::STYLUS).x(50).y(50))
3766 .build());
Siarhei Vishniakouf372b812023-02-14 18:06:51 -08003767 spyWindow->consumeMotionEvent(WithMotionAction(ACTION_HOVER_EXIT));
3768
3769 // Stylus touches down
Prabir Pradhan678438e2023-04-13 19:32:51 +00003770 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_STYLUS)
3771 .pointer(PointerBuilder(0, ToolType::STYLUS).x(50).y(50))
3772 .build());
Siarhei Vishniakouf372b812023-02-14 18:06:51 -08003773 spyWindow->consumeMotionEvent(WithMotionAction(ACTION_DOWN));
3774
3775 // Stylus goes up
Prabir Pradhan678438e2023-04-13 19:32:51 +00003776 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_UP, AINPUT_SOURCE_STYLUS)
3777 .pointer(PointerBuilder(0, ToolType::STYLUS).x(50).y(50))
3778 .build());
Siarhei Vishniakouf372b812023-02-14 18:06:51 -08003779 spyWindow->consumeMotionEvent(WithMotionAction(ACTION_UP));
3780
3781 // Again hover
Prabir Pradhan678438e2023-04-13 19:32:51 +00003782 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_ENTER, AINPUT_SOURCE_STYLUS)
3783 .pointer(PointerBuilder(0, ToolType::STYLUS).x(50).y(50))
3784 .build());
Siarhei Vishniakouf372b812023-02-14 18:06:51 -08003785 spyWindow->consumeMotionEvent(WithMotionAction(ACTION_HOVER_ENTER));
3786 // Stop hovering
Prabir Pradhan678438e2023-04-13 19:32:51 +00003787 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_EXIT, AINPUT_SOURCE_STYLUS)
3788 .pointer(PointerBuilder(0, ToolType::STYLUS).x(50).y(50))
3789 .build());
Siarhei Vishniakouf372b812023-02-14 18:06:51 -08003790 spyWindow->consumeMotionEvent(WithMotionAction(ACTION_HOVER_EXIT));
3791
3792 // No more events
3793 spyWindow->assertNoEvents();
3794 window->assertNoEvents();
3795}
3796
3797/**
Siarhei Vishniakou6b71b632023-10-27 21:34:46 -07003798 * A stale stylus HOVER_EXIT event is injected. Since it's a stale event, it should generally be
3799 * rejected. But since we already have an ongoing gesture, this event should be processed.
3800 * This prevents inconsistent events being handled inside the dispatcher.
3801 */
3802TEST_F(InputDispatcherTest, StaleStylusHoverGestureIsComplete) {
3803 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
3804
3805 sp<FakeWindowHandle> window =
3806 sp<FakeWindowHandle>::make(application, mDispatcher, "Window", ADISPLAY_ID_DEFAULT);
3807 window->setFrame(Rect(0, 0, 200, 200));
3808
3809 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
3810
3811 // Start hovering with stylus
3812 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_ENTER, AINPUT_SOURCE_STYLUS)
3813 .pointer(PointerBuilder(0, ToolType::STYLUS).x(50).y(50))
3814 .build());
3815 window->consumeMotionEvent(WithMotionAction(ACTION_HOVER_ENTER));
3816
3817 NotifyMotionArgs hoverExit = MotionArgsBuilder(ACTION_HOVER_EXIT, AINPUT_SOURCE_STYLUS)
3818 .pointer(PointerBuilder(0, ToolType::STYLUS).x(50).y(50))
3819 .build();
3820 // Make this 'hoverExit' event stale
3821 mFakePolicy->setStaleEventTimeout(100ms);
3822 std::this_thread::sleep_for(100ms);
3823
3824 // It shouldn't be dropped by the dispatcher, even though it's stale.
3825 mDispatcher->notifyMotion(hoverExit);
3826 window->consumeMotionEvent(WithMotionAction(ACTION_HOVER_EXIT));
3827
3828 // Stylus starts hovering again! There should be no crash.
3829 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_ENTER, AINPUT_SOURCE_STYLUS)
3830 .pointer(PointerBuilder(0, ToolType::STYLUS).x(51).y(51))
3831 .build());
3832 window->consumeMotionEvent(WithMotionAction(ACTION_HOVER_ENTER));
3833}
3834
3835/**
Siarhei Vishniakouf372b812023-02-14 18:06:51 -08003836 * Start hovering with a mouse, and then tap with a touch device. Pilfer the touch stream.
3837 * Next, click with the mouse device. Both windows (spy and regular) should receive the new mouse
3838 * ACTION_DOWN event because that's a new gesture, and pilfering should no longer be active.
3839 * While the mouse is down, new move events from the touch device should be ignored.
3840 */
Siarhei Vishniakoued89cbb2023-10-13 10:42:44 -07003841TEST_F(InputDispatcherTest, TouchPilferAndMouseMove_legacy) {
3842 SCOPED_FLAG_OVERRIDE(enable_multi_device_same_window_stream, false);
Siarhei Vishniakouf372b812023-02-14 18:06:51 -08003843 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
3844 sp<FakeWindowHandle> spyWindow =
3845 sp<FakeWindowHandle>::make(application, mDispatcher, "Spy", ADISPLAY_ID_DEFAULT);
3846 spyWindow->setFrame(Rect(0, 0, 200, 200));
3847 spyWindow->setTrustedOverlay(true);
3848 spyWindow->setSpy(true);
3849 sp<FakeWindowHandle> window =
3850 sp<FakeWindowHandle>::make(application, mDispatcher, "Window", ADISPLAY_ID_DEFAULT);
3851 window->setFrame(Rect(0, 0, 200, 200));
3852
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07003853 mDispatcher->onWindowInfosChanged({{*spyWindow->getInfo(), *window->getInfo()}, {}, 0, 0});
Siarhei Vishniakouf372b812023-02-14 18:06:51 -08003854
3855 const int32_t mouseDeviceId = 7;
3856 const int32_t touchDeviceId = 4;
Siarhei Vishniakouf372b812023-02-14 18:06:51 -08003857
3858 // Hover a bit with mouse first
Prabir Pradhan678438e2023-04-13 19:32:51 +00003859 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_ENTER, AINPUT_SOURCE_MOUSE)
3860 .deviceId(mouseDeviceId)
3861 .pointer(PointerBuilder(0, ToolType::MOUSE).x(100).y(100))
3862 .build());
Siarhei Vishniakouf372b812023-02-14 18:06:51 -08003863 spyWindow->consumeMotionEvent(
3864 AllOf(WithMotionAction(ACTION_HOVER_ENTER), WithDeviceId(mouseDeviceId)));
3865 window->consumeMotionEvent(
3866 AllOf(WithMotionAction(ACTION_HOVER_ENTER), WithDeviceId(mouseDeviceId)));
3867
3868 // Start touching
Prabir Pradhan678438e2023-04-13 19:32:51 +00003869 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
3870 .deviceId(touchDeviceId)
3871 .pointer(PointerBuilder(0, ToolType::FINGER).x(50).y(50))
3872 .build());
Siarhei Vishniakouf372b812023-02-14 18:06:51 -08003873 spyWindow->consumeMotionEvent(WithMotionAction(ACTION_HOVER_EXIT));
3874 window->consumeMotionEvent(WithMotionAction(ACTION_HOVER_EXIT));
3875 spyWindow->consumeMotionEvent(WithMotionAction(ACTION_DOWN));
3876 window->consumeMotionEvent(WithMotionAction(ACTION_DOWN));
3877
Prabir Pradhan678438e2023-04-13 19:32:51 +00003878 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN)
3879 .deviceId(touchDeviceId)
3880 .pointer(PointerBuilder(0, ToolType::FINGER).x(55).y(55))
3881 .build());
Siarhei Vishniakouf372b812023-02-14 18:06:51 -08003882 spyWindow->consumeMotionEvent(WithMotionAction(ACTION_MOVE));
3883 window->consumeMotionEvent(WithMotionAction(ACTION_MOVE));
3884
3885 // Pilfer the stream
3886 EXPECT_EQ(OK, mDispatcher->pilferPointers(spyWindow->getToken()));
3887 window->consumeMotionEvent(WithMotionAction(ACTION_CANCEL));
3888
Prabir Pradhan678438e2023-04-13 19:32:51 +00003889 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN)
3890 .deviceId(touchDeviceId)
3891 .pointer(PointerBuilder(0, ToolType::FINGER).x(60).y(60))
3892 .build());
Siarhei Vishniakouf372b812023-02-14 18:06:51 -08003893 spyWindow->consumeMotionEvent(WithMotionAction(ACTION_MOVE));
3894
3895 // Mouse down
Prabir Pradhan678438e2023-04-13 19:32:51 +00003896 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_MOUSE)
3897 .deviceId(mouseDeviceId)
3898 .buttonState(AMOTION_EVENT_BUTTON_PRIMARY)
3899 .pointer(PointerBuilder(0, ToolType::MOUSE).x(100).y(100))
3900 .build());
Siarhei Vishniakouf372b812023-02-14 18:06:51 -08003901
3902 spyWindow->consumeMotionEvent(
3903 AllOf(WithMotionAction(ACTION_CANCEL), WithDeviceId(touchDeviceId)));
3904 spyWindow->consumeMotionEvent(
3905 AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(mouseDeviceId)));
3906 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(mouseDeviceId)));
3907
Prabir Pradhan678438e2023-04-13 19:32:51 +00003908 mDispatcher->notifyMotion(
3909 MotionArgsBuilder(AMOTION_EVENT_ACTION_BUTTON_PRESS, AINPUT_SOURCE_MOUSE)
3910 .deviceId(mouseDeviceId)
3911 .buttonState(AMOTION_EVENT_BUTTON_PRIMARY)
3912 .actionButton(AMOTION_EVENT_BUTTON_PRIMARY)
3913 .pointer(PointerBuilder(0, ToolType::MOUSE).x(100).y(100))
3914 .build());
Siarhei Vishniakouf372b812023-02-14 18:06:51 -08003915 spyWindow->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_BUTTON_PRESS));
3916 window->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_BUTTON_PRESS));
3917
3918 // Mouse move!
Prabir Pradhan678438e2023-04-13 19:32:51 +00003919 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_MOUSE)
3920 .deviceId(mouseDeviceId)
3921 .buttonState(AMOTION_EVENT_BUTTON_PRIMARY)
3922 .pointer(PointerBuilder(0, ToolType::MOUSE).x(110).y(110))
3923 .build());
Siarhei Vishniakouf372b812023-02-14 18:06:51 -08003924 spyWindow->consumeMotionEvent(WithMotionAction(ACTION_MOVE));
3925 window->consumeMotionEvent(WithMotionAction(ACTION_MOVE));
3926
3927 // Touch move!
Prabir Pradhan678438e2023-04-13 19:32:51 +00003928 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN)
3929 .deviceId(touchDeviceId)
3930 .pointer(PointerBuilder(0, ToolType::FINGER).x(65).y(65))
3931 .build());
Siarhei Vishniakouf372b812023-02-14 18:06:51 -08003932
3933 // No more events
3934 spyWindow->assertNoEvents();
3935 window->assertNoEvents();
3936}
3937
3938/**
Siarhei Vishniakoued89cbb2023-10-13 10:42:44 -07003939 * Start hovering with a mouse, and then tap with a touch device. Pilfer the touch stream.
3940 * Next, click with the mouse device. Both windows (spy and regular) should receive the new mouse
3941 * ACTION_DOWN event because that's a new gesture, and pilfering should no longer be active.
3942 * While the mouse is down, new move events from the touch device should continue to work.
3943 */
3944TEST_F(InputDispatcherTest, TouchPilferAndMouseMove) {
3945 SCOPED_FLAG_OVERRIDE(enable_multi_device_same_window_stream, true);
3946 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
3947 sp<FakeWindowHandle> spyWindow =
3948 sp<FakeWindowHandle>::make(application, mDispatcher, "Spy", ADISPLAY_ID_DEFAULT);
3949 spyWindow->setFrame(Rect(0, 0, 200, 200));
3950 spyWindow->setTrustedOverlay(true);
3951 spyWindow->setSpy(true);
3952 sp<FakeWindowHandle> window =
3953 sp<FakeWindowHandle>::make(application, mDispatcher, "Window", ADISPLAY_ID_DEFAULT);
3954 window->setFrame(Rect(0, 0, 200, 200));
3955
3956 mDispatcher->onWindowInfosChanged({{*spyWindow->getInfo(), *window->getInfo()}, {}, 0, 0});
3957
3958 const int32_t mouseDeviceId = 7;
3959 const int32_t touchDeviceId = 4;
3960
3961 // Hover a bit with mouse first
3962 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_ENTER, AINPUT_SOURCE_MOUSE)
3963 .deviceId(mouseDeviceId)
3964 .pointer(PointerBuilder(0, ToolType::MOUSE).x(100).y(100))
3965 .build());
3966 spyWindow->consumeMotionEvent(
3967 AllOf(WithMotionAction(ACTION_HOVER_ENTER), WithDeviceId(mouseDeviceId)));
3968 window->consumeMotionEvent(
3969 AllOf(WithMotionAction(ACTION_HOVER_ENTER), WithDeviceId(mouseDeviceId)));
3970
3971 // Start touching
3972 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
3973 .deviceId(touchDeviceId)
3974 .pointer(PointerBuilder(0, ToolType::FINGER).x(50).y(50))
3975 .build());
3976
3977 spyWindow->consumeMotionEvent(WithMotionAction(ACTION_DOWN));
3978 window->consumeMotionEvent(WithMotionAction(ACTION_DOWN));
3979
3980 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN)
3981 .deviceId(touchDeviceId)
3982 .pointer(PointerBuilder(0, ToolType::FINGER).x(55).y(55))
3983 .build());
3984 spyWindow->consumeMotionEvent(WithMotionAction(ACTION_MOVE));
3985 window->consumeMotionEvent(WithMotionAction(ACTION_MOVE));
3986
3987 // Pilfer the stream
3988 EXPECT_EQ(OK, mDispatcher->pilferPointers(spyWindow->getToken()));
3989 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_CANCEL), WithDeviceId(touchDeviceId)));
3990 // Hover is not pilfered! Only touch.
3991
3992 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN)
3993 .deviceId(touchDeviceId)
3994 .pointer(PointerBuilder(0, ToolType::FINGER).x(60).y(60))
3995 .build());
3996 spyWindow->consumeMotionEvent(WithMotionAction(ACTION_MOVE));
3997
3998 // Mouse down
3999 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_MOUSE)
4000 .deviceId(mouseDeviceId)
4001 .buttonState(AMOTION_EVENT_BUTTON_PRIMARY)
4002 .pointer(PointerBuilder(0, ToolType::MOUSE).x(100).y(100))
4003 .build());
4004
4005 spyWindow->consumeMotionEvent(
4006 AllOf(WithMotionAction(ACTION_HOVER_EXIT), WithDeviceId(mouseDeviceId)));
4007 spyWindow->consumeMotionEvent(
4008 AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(mouseDeviceId)));
4009 window->consumeMotionEvent(
4010 AllOf(WithMotionAction(ACTION_HOVER_EXIT), WithDeviceId(mouseDeviceId)));
4011 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(mouseDeviceId)));
4012
4013 mDispatcher->notifyMotion(
4014 MotionArgsBuilder(AMOTION_EVENT_ACTION_BUTTON_PRESS, AINPUT_SOURCE_MOUSE)
4015 .deviceId(mouseDeviceId)
4016 .buttonState(AMOTION_EVENT_BUTTON_PRIMARY)
4017 .actionButton(AMOTION_EVENT_BUTTON_PRIMARY)
4018 .pointer(PointerBuilder(0, ToolType::MOUSE).x(100).y(100))
4019 .build());
4020 spyWindow->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_BUTTON_PRESS));
4021 window->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_BUTTON_PRESS));
4022
4023 // Mouse move!
4024 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_MOUSE)
4025 .deviceId(mouseDeviceId)
4026 .buttonState(AMOTION_EVENT_BUTTON_PRIMARY)
4027 .pointer(PointerBuilder(0, ToolType::MOUSE).x(110).y(110))
4028 .build());
4029 spyWindow->consumeMotionEvent(
4030 AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(mouseDeviceId)));
4031 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(mouseDeviceId)));
4032
4033 // Touch move!
4034 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN)
4035 .deviceId(touchDeviceId)
4036 .pointer(PointerBuilder(0, ToolType::FINGER).x(65).y(65))
4037 .build());
4038 spyWindow->consumeMotionEvent(
4039 AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(touchDeviceId)));
4040
4041 // No more events
4042 spyWindow->assertNoEvents();
4043 window->assertNoEvents();
4044}
4045
4046/**
Siarhei Vishniakoua16e3a22022-03-02 15:26:40 -08004047 * On the display, have a single window, and also an area where there's no window.
4048 * First pointer touches the "no window" area of the screen. Second pointer touches the window.
4049 * Make sure that the window receives the second pointer, and first pointer is simply ignored.
4050 */
4051TEST_F(InputDispatcherTest, SplitWorksWhenEmptyAreaIsTouched) {
4052 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
4053 sp<FakeWindowHandle> window =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07004054 sp<FakeWindowHandle>::make(application, mDispatcher, "Window", DISPLAY_ID);
Siarhei Vishniakoua16e3a22022-03-02 15:26:40 -08004055
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07004056 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Siarhei Vishniakoua16e3a22022-03-02 15:26:40 -08004057
4058 // Touch down on the empty space
Prabir Pradhan678438e2023-04-13 19:32:51 +00004059 mDispatcher->notifyMotion(generateTouchArgs(AMOTION_EVENT_ACTION_DOWN, {{-1, -1}}));
Siarhei Vishniakoua16e3a22022-03-02 15:26:40 -08004060
4061 mDispatcher->waitForIdle();
4062 window->assertNoEvents();
4063
4064 // Now touch down on the window with another pointer
Prabir Pradhan678438e2023-04-13 19:32:51 +00004065 mDispatcher->notifyMotion(generateTouchArgs(POINTER_1_DOWN, {{-1, -1}, {10, 10}}));
Siarhei Vishniakoua16e3a22022-03-02 15:26:40 -08004066 mDispatcher->waitForIdle();
4067 window->consumeMotionDown();
4068}
4069
4070/**
4071 * Same test as above, but instead of touching the empty space, the first touch goes to
4072 * non-touchable window.
4073 */
4074TEST_F(InputDispatcherTest, SplitWorksWhenNonTouchableWindowIsTouched) {
4075 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
4076 sp<FakeWindowHandle> window1 =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07004077 sp<FakeWindowHandle>::make(application, mDispatcher, "Window1", DISPLAY_ID);
Siarhei Vishniakoua16e3a22022-03-02 15:26:40 -08004078 window1->setTouchableRegion(Region{{0, 0, 100, 100}});
4079 window1->setTouchable(false);
4080 sp<FakeWindowHandle> window2 =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07004081 sp<FakeWindowHandle>::make(application, mDispatcher, "Window2", DISPLAY_ID);
Siarhei Vishniakoua16e3a22022-03-02 15:26:40 -08004082 window2->setTouchableRegion(Region{{100, 0, 200, 100}});
4083
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07004084 mDispatcher->onWindowInfosChanged({{*window1->getInfo(), *window2->getInfo()}, {}, 0, 0});
Siarhei Vishniakoua16e3a22022-03-02 15:26:40 -08004085
Siarhei Vishniakoua16e3a22022-03-02 15:26:40 -08004086 // Touch down on the non-touchable window
Prabir Pradhan678438e2023-04-13 19:32:51 +00004087 mDispatcher->notifyMotion(generateTouchArgs(AMOTION_EVENT_ACTION_DOWN, {{50, 50}}));
Siarhei Vishniakoua16e3a22022-03-02 15:26:40 -08004088
4089 mDispatcher->waitForIdle();
4090 window1->assertNoEvents();
4091 window2->assertNoEvents();
4092
4093 // Now touch down on the window with another pointer
Prabir Pradhan678438e2023-04-13 19:32:51 +00004094 mDispatcher->notifyMotion(generateTouchArgs(POINTER_1_DOWN, {{50, 50}, {150, 50}}));
Siarhei Vishniakoua16e3a22022-03-02 15:26:40 -08004095 mDispatcher->waitForIdle();
4096 window2->consumeMotionDown();
4097}
4098
Vaibhav Devmurari882bd9b2022-06-23 14:54:54 +00004099/**
4100 * When splitting touch events the downTime should be adjusted such that the downTime corresponds
4101 * to the event time of the first ACTION_DOWN sent to the particular window.
4102 */
4103TEST_F(InputDispatcherTest, SplitTouchesSendCorrectActionDownTime) {
4104 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
4105 sp<FakeWindowHandle> window1 =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07004106 sp<FakeWindowHandle>::make(application, mDispatcher, "Window1", DISPLAY_ID);
Vaibhav Devmurari882bd9b2022-06-23 14:54:54 +00004107 window1->setTouchableRegion(Region{{0, 0, 100, 100}});
4108 sp<FakeWindowHandle> window2 =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07004109 sp<FakeWindowHandle>::make(application, mDispatcher, "Window2", DISPLAY_ID);
Vaibhav Devmurari882bd9b2022-06-23 14:54:54 +00004110 window2->setTouchableRegion(Region{{100, 0, 200, 100}});
4111
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07004112 mDispatcher->onWindowInfosChanged({{*window1->getInfo(), *window2->getInfo()}, {}, 0, 0});
Vaibhav Devmurari882bd9b2022-06-23 14:54:54 +00004113
Vaibhav Devmurari882bd9b2022-06-23 14:54:54 +00004114 // Touch down on the first window
Prabir Pradhan678438e2023-04-13 19:32:51 +00004115 mDispatcher->notifyMotion(generateTouchArgs(AMOTION_EVENT_ACTION_DOWN, {{50, 50}}));
Vaibhav Devmurari882bd9b2022-06-23 14:54:54 +00004116 mDispatcher->waitForIdle();
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07004117
Prabir Pradhan9d5f9ce2024-01-24 00:03:41 +00004118 const std::unique_ptr<MotionEvent> firstDown =
4119 window1->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN)));
4120 ASSERT_EQ(firstDown->getDownTime(), firstDown->getEventTime());
Vaibhav Devmurari882bd9b2022-06-23 14:54:54 +00004121 window2->assertNoEvents();
Vaibhav Devmurari882bd9b2022-06-23 14:54:54 +00004122
4123 // Now touch down on the window with another pointer
Prabir Pradhan678438e2023-04-13 19:32:51 +00004124 mDispatcher->notifyMotion(generateTouchArgs(POINTER_1_DOWN, {{50, 50}, {150, 50}}));
Vaibhav Devmurari882bd9b2022-06-23 14:54:54 +00004125 mDispatcher->waitForIdle();
Prabir Pradhan9d5f9ce2024-01-24 00:03:41 +00004126
4127 const std::unique_ptr<MotionEvent> secondDown =
4128 window2->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN)));
4129 ASSERT_EQ(secondDown->getDownTime(), secondDown->getEventTime());
4130 ASSERT_NE(firstDown->getDownTime(), secondDown->getDownTime());
4131 // We currently send MOVE events to all windows receiving a split touch when there is any change
4132 // in the touch state, even when none of the pointers in the split window actually moved.
4133 // Document this behavior in the test.
4134 window1->consumeMotionMove();
Vaibhav Devmurari882bd9b2022-06-23 14:54:54 +00004135
4136 // Now move the pointer on the second window
Prabir Pradhan678438e2023-04-13 19:32:51 +00004137 mDispatcher->notifyMotion(generateTouchArgs(AMOTION_EVENT_ACTION_MOVE, {{50, 50}, {151, 51}}));
Vaibhav Devmurari882bd9b2022-06-23 14:54:54 +00004138 mDispatcher->waitForIdle();
Prabir Pradhan9d5f9ce2024-01-24 00:03:41 +00004139
4140 window2->consumeMotionEvent(WithDownTime(secondDown->getDownTime()));
4141 window1->consumeMotionEvent(WithDownTime(firstDown->getDownTime()));
Vaibhav Devmurari882bd9b2022-06-23 14:54:54 +00004142
4143 // Now add new touch down on the second window
Prabir Pradhan678438e2023-04-13 19:32:51 +00004144 mDispatcher->notifyMotion(generateTouchArgs(POINTER_2_DOWN, {{50, 50}, {151, 51}, {150, 50}}));
Vaibhav Devmurari882bd9b2022-06-23 14:54:54 +00004145 mDispatcher->waitForIdle();
Vaibhav Devmurari882bd9b2022-06-23 14:54:54 +00004146
Prabir Pradhan9d5f9ce2024-01-24 00:03:41 +00004147 window2->consumeMotionEvent(
4148 AllOf(WithMotionAction(POINTER_1_DOWN), WithDownTime(secondDown->getDownTime())));
4149 window1->consumeMotionEvent(WithDownTime(firstDown->getDownTime()));
Vaibhav Devmurari882bd9b2022-06-23 14:54:54 +00004150
4151 // Now move the pointer on the first window
Prabir Pradhan678438e2023-04-13 19:32:51 +00004152 mDispatcher->notifyMotion(
4153 generateTouchArgs(AMOTION_EVENT_ACTION_MOVE, {{51, 51}, {151, 51}, {150, 50}}));
Vaibhav Devmurari882bd9b2022-06-23 14:54:54 +00004154 mDispatcher->waitForIdle();
Vaibhav Devmurari882bd9b2022-06-23 14:54:54 +00004155
Prabir Pradhan9d5f9ce2024-01-24 00:03:41 +00004156 window1->consumeMotionEvent(WithDownTime(firstDown->getDownTime()));
4157 window2->consumeMotionEvent(WithDownTime(secondDown->getDownTime()));
4158
4159 // Now add new touch down on the first window
Prabir Pradhan678438e2023-04-13 19:32:51 +00004160 mDispatcher->notifyMotion(
4161 generateTouchArgs(POINTER_3_DOWN, {{51, 51}, {151, 51}, {150, 50}, {50, 50}}));
Vaibhav Devmurari882bd9b2022-06-23 14:54:54 +00004162 mDispatcher->waitForIdle();
Prabir Pradhan9d5f9ce2024-01-24 00:03:41 +00004163
4164 window1->consumeMotionEvent(
4165 AllOf(WithMotionAction(POINTER_1_DOWN), WithDownTime(firstDown->getDownTime())));
4166 window2->consumeMotionEvent(WithDownTime(secondDown->getDownTime()));
Vaibhav Devmurari882bd9b2022-06-23 14:54:54 +00004167}
4168
Garfield Tandf26e862020-07-01 20:18:19 -07004169TEST_F(InputDispatcherTest, HoverMoveEnterMouseClickAndHoverMoveExit) {
Chris Yea209fde2020-07-22 13:54:51 -07004170 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
Garfield Tandf26e862020-07-01 20:18:19 -07004171 sp<FakeWindowHandle> windowLeft =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07004172 sp<FakeWindowHandle>::make(application, mDispatcher, "Left", ADISPLAY_ID_DEFAULT);
Garfield Tandf26e862020-07-01 20:18:19 -07004173 windowLeft->setFrame(Rect(0, 0, 600, 800));
Garfield Tandf26e862020-07-01 20:18:19 -07004174 sp<FakeWindowHandle> windowRight =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07004175 sp<FakeWindowHandle>::make(application, mDispatcher, "Right", ADISPLAY_ID_DEFAULT);
Garfield Tandf26e862020-07-01 20:18:19 -07004176 windowRight->setFrame(Rect(600, 0, 1200, 800));
Garfield Tandf26e862020-07-01 20:18:19 -07004177
4178 mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application);
4179
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07004180 mDispatcher->onWindowInfosChanged(
4181 {{*windowLeft->getInfo(), *windowRight->getInfo()}, {}, 0, 0});
Garfield Tandf26e862020-07-01 20:18:19 -07004182
4183 // Start cursor position in right window so that we can move the cursor to left window.
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08004184 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07004185 injectMotionEvent(*mDispatcher,
Garfield Tandf26e862020-07-01 20:18:19 -07004186 MotionEventBuilder(AMOTION_EVENT_ACTION_HOVER_MOVE,
4187 AINPUT_SOURCE_MOUSE)
Siarhei Vishniakou6d73f832022-07-21 17:27:03 -07004188 .pointer(PointerBuilder(0, ToolType::MOUSE).x(900).y(400))
Garfield Tandf26e862020-07-01 20:18:19 -07004189 .build()));
Siarhei Vishniakou5cee1e32022-11-29 12:35:39 -08004190 windowRight->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_ENTER));
Garfield Tandf26e862020-07-01 20:18:19 -07004191
4192 // Move cursor into left window
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08004193 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07004194 injectMotionEvent(*mDispatcher,
Garfield Tandf26e862020-07-01 20:18:19 -07004195 MotionEventBuilder(AMOTION_EVENT_ACTION_HOVER_MOVE,
4196 AINPUT_SOURCE_MOUSE)
Siarhei Vishniakou6d73f832022-07-21 17:27:03 -07004197 .pointer(PointerBuilder(0, ToolType::MOUSE).x(300).y(400))
Garfield Tandf26e862020-07-01 20:18:19 -07004198 .build()));
Siarhei Vishniakou5cee1e32022-11-29 12:35:39 -08004199 windowRight->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_EXIT));
4200 windowLeft->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_ENTER));
Garfield Tandf26e862020-07-01 20:18:19 -07004201
4202 // Inject a series of mouse events for a mouse click
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08004203 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07004204 injectMotionEvent(*mDispatcher,
Garfield Tandf26e862020-07-01 20:18:19 -07004205 MotionEventBuilder(AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_MOUSE)
4206 .buttonState(AMOTION_EVENT_BUTTON_PRIMARY)
Siarhei Vishniakou6d73f832022-07-21 17:27:03 -07004207 .pointer(PointerBuilder(0, ToolType::MOUSE).x(300).y(400))
Garfield Tandf26e862020-07-01 20:18:19 -07004208 .build()));
Siarhei Vishniakouf372b812023-02-14 18:06:51 -08004209 windowLeft->consumeMotionEvent(WithMotionAction(ACTION_HOVER_EXIT));
4210 windowLeft->consumeMotionEvent(WithMotionAction(ACTION_DOWN));
Garfield Tandf26e862020-07-01 20:18:19 -07004211
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08004212 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07004213 injectMotionEvent(*mDispatcher,
Garfield Tandf26e862020-07-01 20:18:19 -07004214 MotionEventBuilder(AMOTION_EVENT_ACTION_BUTTON_PRESS,
4215 AINPUT_SOURCE_MOUSE)
4216 .buttonState(AMOTION_EVENT_BUTTON_PRIMARY)
4217 .actionButton(AMOTION_EVENT_BUTTON_PRIMARY)
Siarhei Vishniakou6d73f832022-07-21 17:27:03 -07004218 .pointer(PointerBuilder(0, ToolType::MOUSE).x(300).y(400))
Garfield Tandf26e862020-07-01 20:18:19 -07004219 .build()));
Siarhei Vishniakou5cee1e32022-11-29 12:35:39 -08004220 windowLeft->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_BUTTON_PRESS));
Garfield Tandf26e862020-07-01 20:18:19 -07004221
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08004222 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07004223 injectMotionEvent(*mDispatcher,
Garfield Tandf26e862020-07-01 20:18:19 -07004224 MotionEventBuilder(AMOTION_EVENT_ACTION_BUTTON_RELEASE,
4225 AINPUT_SOURCE_MOUSE)
4226 .buttonState(0)
4227 .actionButton(AMOTION_EVENT_BUTTON_PRIMARY)
Siarhei Vishniakou6d73f832022-07-21 17:27:03 -07004228 .pointer(PointerBuilder(0, ToolType::MOUSE).x(300).y(400))
Garfield Tandf26e862020-07-01 20:18:19 -07004229 .build()));
Siarhei Vishniakou5cee1e32022-11-29 12:35:39 -08004230 windowLeft->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_BUTTON_RELEASE));
Garfield Tandf26e862020-07-01 20:18:19 -07004231
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08004232 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07004233 injectMotionEvent(*mDispatcher,
Garfield Tandf26e862020-07-01 20:18:19 -07004234 MotionEventBuilder(AMOTION_EVENT_ACTION_UP, AINPUT_SOURCE_MOUSE)
4235 .buttonState(0)
Siarhei Vishniakou6d73f832022-07-21 17:27:03 -07004236 .pointer(PointerBuilder(0, ToolType::MOUSE).x(300).y(400))
Garfield Tandf26e862020-07-01 20:18:19 -07004237 .build()));
4238 windowLeft->consumeMotionUp(ADISPLAY_ID_DEFAULT);
4239
4240 // Move mouse cursor back to right window
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08004241 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07004242 injectMotionEvent(*mDispatcher,
Garfield Tandf26e862020-07-01 20:18:19 -07004243 MotionEventBuilder(AMOTION_EVENT_ACTION_HOVER_MOVE,
4244 AINPUT_SOURCE_MOUSE)
Siarhei Vishniakou6d73f832022-07-21 17:27:03 -07004245 .pointer(PointerBuilder(0, ToolType::MOUSE).x(900).y(400))
Garfield Tandf26e862020-07-01 20:18:19 -07004246 .build()));
Siarhei Vishniakou5cee1e32022-11-29 12:35:39 -08004247 windowRight->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_ENTER));
Siarhei Vishniakou5cee1e32022-11-29 12:35:39 -08004248
4249 // No more events
4250 windowLeft->assertNoEvents();
4251 windowRight->assertNoEvents();
4252}
4253
Siarhei Vishniakouf372b812023-02-14 18:06:51 -08004254/**
4255 * Put two fingers down (and don't release them) and click the mouse button.
4256 * The clicking of mouse is a new ACTION_DOWN event. Since it's from a different device, the
4257 * currently active gesture should be canceled, and the new one should proceed.
4258 */
Siarhei Vishniakoued89cbb2023-10-13 10:42:44 -07004259TEST_F(InputDispatcherTest, TwoPointersDownMouseClick_legacy) {
4260 SCOPED_FLAG_OVERRIDE(enable_multi_device_same_window_stream, false);
Siarhei Vishniakouf372b812023-02-14 18:06:51 -08004261 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
4262 sp<FakeWindowHandle> window =
4263 sp<FakeWindowHandle>::make(application, mDispatcher, "Window", ADISPLAY_ID_DEFAULT);
4264 window->setFrame(Rect(0, 0, 600, 800));
4265
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07004266 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Siarhei Vishniakouf372b812023-02-14 18:06:51 -08004267
4268 const int32_t touchDeviceId = 4;
4269 const int32_t mouseDeviceId = 6;
Siarhei Vishniakouf372b812023-02-14 18:06:51 -08004270
4271 // Two pointers down
Prabir Pradhan678438e2023-04-13 19:32:51 +00004272 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
4273 .deviceId(touchDeviceId)
4274 .pointer(PointerBuilder(0, ToolType::FINGER).x(100).y(100))
4275 .build());
Siarhei Vishniakouf372b812023-02-14 18:06:51 -08004276
Prabir Pradhan678438e2023-04-13 19:32:51 +00004277 mDispatcher->notifyMotion(MotionArgsBuilder(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
4278 .deviceId(touchDeviceId)
4279 .pointer(PointerBuilder(0, ToolType::FINGER).x(100).y(100))
4280 .pointer(PointerBuilder(1, ToolType::FINGER).x(120).y(120))
4281 .build());
Siarhei Vishniakouf372b812023-02-14 18:06:51 -08004282 window->consumeMotionEvent(WithMotionAction(ACTION_DOWN));
4283 window->consumeMotionEvent(WithMotionAction(POINTER_1_DOWN));
4284
4285 // Inject a series of mouse events for a mouse click
Prabir Pradhan678438e2023-04-13 19:32:51 +00004286 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_MOUSE)
4287 .deviceId(mouseDeviceId)
4288 .buttonState(AMOTION_EVENT_BUTTON_PRIMARY)
4289 .pointer(PointerBuilder(0, ToolType::MOUSE).x(300).y(400))
4290 .build());
Siarhei Vishniakouf372b812023-02-14 18:06:51 -08004291 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_CANCEL), WithDeviceId(touchDeviceId),
4292 WithPointerCount(2u)));
4293 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(mouseDeviceId)));
4294
Prabir Pradhan678438e2023-04-13 19:32:51 +00004295 mDispatcher->notifyMotion(
4296 MotionArgsBuilder(AMOTION_EVENT_ACTION_BUTTON_PRESS, AINPUT_SOURCE_MOUSE)
4297 .deviceId(mouseDeviceId)
4298 .buttonState(AMOTION_EVENT_BUTTON_PRIMARY)
4299 .actionButton(AMOTION_EVENT_BUTTON_PRIMARY)
4300 .pointer(PointerBuilder(0, ToolType::MOUSE).x(300).y(400))
4301 .build());
Siarhei Vishniakouf372b812023-02-14 18:06:51 -08004302 window->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_BUTTON_PRESS));
4303
4304 // Try to send more touch events while the mouse is down. Since it's a continuation of an
4305 // already canceled gesture, it should be ignored.
Prabir Pradhan678438e2023-04-13 19:32:51 +00004306 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN)
4307 .deviceId(touchDeviceId)
4308 .pointer(PointerBuilder(0, ToolType::FINGER).x(101).y(101))
4309 .pointer(PointerBuilder(1, ToolType::FINGER).x(121).y(121))
4310 .build());
Siarhei Vishniakouf372b812023-02-14 18:06:51 -08004311 window->assertNoEvents();
4312}
4313
Siarhei Vishniakoued89cbb2023-10-13 10:42:44 -07004314/**
4315 * Put two fingers down (and don't release them) and click the mouse button.
4316 * The clicking of mouse is a new ACTION_DOWN event. Since it's from a different device, the
4317 * currently active gesture should not be canceled, and the new one should proceed in parallel.
4318 */
4319TEST_F(InputDispatcherTest, TwoPointersDownMouseClick) {
4320 SCOPED_FLAG_OVERRIDE(enable_multi_device_same_window_stream, true);
4321 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
4322 sp<FakeWindowHandle> window =
4323 sp<FakeWindowHandle>::make(application, mDispatcher, "Window", ADISPLAY_ID_DEFAULT);
4324 window->setFrame(Rect(0, 0, 600, 800));
4325
4326 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
4327
4328 const int32_t touchDeviceId = 4;
4329 const int32_t mouseDeviceId = 6;
4330
4331 // Two pointers down
4332 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
4333 .deviceId(touchDeviceId)
4334 .pointer(PointerBuilder(0, ToolType::FINGER).x(100).y(100))
4335 .build());
4336
4337 mDispatcher->notifyMotion(MotionArgsBuilder(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
4338 .deviceId(touchDeviceId)
4339 .pointer(PointerBuilder(0, ToolType::FINGER).x(100).y(100))
4340 .pointer(PointerBuilder(1, ToolType::FINGER).x(120).y(120))
4341 .build());
4342 window->consumeMotionEvent(WithMotionAction(ACTION_DOWN));
4343 window->consumeMotionEvent(WithMotionAction(POINTER_1_DOWN));
4344
4345 // Send a series of mouse events for a mouse click
4346 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_MOUSE)
4347 .deviceId(mouseDeviceId)
4348 .buttonState(AMOTION_EVENT_BUTTON_PRIMARY)
4349 .pointer(PointerBuilder(0, ToolType::MOUSE).x(300).y(400))
4350 .build());
4351 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(mouseDeviceId)));
4352
4353 mDispatcher->notifyMotion(
4354 MotionArgsBuilder(AMOTION_EVENT_ACTION_BUTTON_PRESS, AINPUT_SOURCE_MOUSE)
4355 .deviceId(mouseDeviceId)
4356 .buttonState(AMOTION_EVENT_BUTTON_PRIMARY)
4357 .actionButton(AMOTION_EVENT_BUTTON_PRIMARY)
4358 .pointer(PointerBuilder(0, ToolType::MOUSE).x(300).y(400))
4359 .build());
4360 window->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_BUTTON_PRESS));
4361
4362 // Try to send more touch events while the mouse is down. Since it's a continuation of an
4363 // already active gesture, it should be sent normally.
4364 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN)
4365 .deviceId(touchDeviceId)
4366 .pointer(PointerBuilder(0, ToolType::FINGER).x(101).y(101))
4367 .pointer(PointerBuilder(1, ToolType::FINGER).x(121).y(121))
4368 .build());
4369 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(touchDeviceId)));
4370 window->assertNoEvents();
4371}
4372
Siarhei Vishniakou5cee1e32022-11-29 12:35:39 -08004373TEST_F(InputDispatcherTest, HoverWithSpyWindows) {
4374 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
4375
4376 sp<FakeWindowHandle> spyWindow =
4377 sp<FakeWindowHandle>::make(application, mDispatcher, "Spy", ADISPLAY_ID_DEFAULT);
4378 spyWindow->setFrame(Rect(0, 0, 600, 800));
4379 spyWindow->setTrustedOverlay(true);
4380 spyWindow->setSpy(true);
4381 sp<FakeWindowHandle> window =
4382 sp<FakeWindowHandle>::make(application, mDispatcher, "Window", ADISPLAY_ID_DEFAULT);
4383 window->setFrame(Rect(0, 0, 600, 800));
4384
4385 mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07004386 mDispatcher->onWindowInfosChanged({{*spyWindow->getInfo(), *window->getInfo()}, {}, 0, 0});
Siarhei Vishniakou5cee1e32022-11-29 12:35:39 -08004387
4388 // Send mouse cursor to the window
4389 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07004390 injectMotionEvent(*mDispatcher,
Siarhei Vishniakou5cee1e32022-11-29 12:35:39 -08004391 MotionEventBuilder(AMOTION_EVENT_ACTION_HOVER_ENTER,
4392 AINPUT_SOURCE_MOUSE)
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07004393 .pointer(PointerBuilder(0, ToolType::MOUSE).x(100).y(100))
Siarhei Vishniakou5cee1e32022-11-29 12:35:39 -08004394 .build()));
4395
4396 window->consumeMotionEvent(AllOf(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_ENTER),
4397 WithSource(AINPUT_SOURCE_MOUSE)));
4398 spyWindow->consumeMotionEvent(AllOf(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_ENTER),
4399 WithSource(AINPUT_SOURCE_MOUSE)));
4400
4401 window->assertNoEvents();
4402 spyWindow->assertNoEvents();
Garfield Tandf26e862020-07-01 20:18:19 -07004403}
4404
Siarhei Vishniakoued89cbb2023-10-13 10:42:44 -07004405TEST_F(InputDispatcherTest, MouseAndTouchWithSpyWindows_legacy) {
4406 SCOPED_FLAG_OVERRIDE(enable_multi_device_same_window_stream, false);
Siarhei Vishniakou060f82b2023-01-27 06:39:14 -08004407 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
4408
4409 sp<FakeWindowHandle> spyWindow =
4410 sp<FakeWindowHandle>::make(application, mDispatcher, "Spy", ADISPLAY_ID_DEFAULT);
4411 spyWindow->setFrame(Rect(0, 0, 600, 800));
4412 spyWindow->setTrustedOverlay(true);
4413 spyWindow->setSpy(true);
4414 sp<FakeWindowHandle> window =
4415 sp<FakeWindowHandle>::make(application, mDispatcher, "Window", ADISPLAY_ID_DEFAULT);
4416 window->setFrame(Rect(0, 0, 600, 800));
4417
4418 mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07004419 mDispatcher->onWindowInfosChanged({{*spyWindow->getInfo(), *window->getInfo()}, {}, 0, 0});
Siarhei Vishniakou060f82b2023-01-27 06:39:14 -08004420
4421 // Send mouse cursor to the window
4422 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07004423 injectMotionEvent(*mDispatcher,
Siarhei Vishniakou060f82b2023-01-27 06:39:14 -08004424 MotionEventBuilder(AMOTION_EVENT_ACTION_HOVER_ENTER,
4425 AINPUT_SOURCE_MOUSE)
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07004426 .pointer(PointerBuilder(0, ToolType::MOUSE).x(100).y(100))
Siarhei Vishniakou060f82b2023-01-27 06:39:14 -08004427 .build()));
4428
4429 // Move mouse cursor
4430 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07004431 injectMotionEvent(*mDispatcher,
Siarhei Vishniakou060f82b2023-01-27 06:39:14 -08004432 MotionEventBuilder(AMOTION_EVENT_ACTION_HOVER_MOVE,
4433 AINPUT_SOURCE_MOUSE)
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07004434 .pointer(PointerBuilder(0, ToolType::MOUSE).x(110).y(110))
Siarhei Vishniakou060f82b2023-01-27 06:39:14 -08004435 .build()));
4436
4437 window->consumeMotionEvent(AllOf(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_ENTER),
4438 WithSource(AINPUT_SOURCE_MOUSE)));
4439 spyWindow->consumeMotionEvent(AllOf(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_ENTER),
4440 WithSource(AINPUT_SOURCE_MOUSE)));
4441 window->consumeMotionEvent(AllOf(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_MOVE),
4442 WithSource(AINPUT_SOURCE_MOUSE)));
4443 spyWindow->consumeMotionEvent(AllOf(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_MOVE),
4444 WithSource(AINPUT_SOURCE_MOUSE)));
4445 // Touch down on the window
4446 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07004447 injectMotionEvent(*mDispatcher,
Siarhei Vishniakou060f82b2023-01-27 06:39:14 -08004448 MotionEventBuilder(AMOTION_EVENT_ACTION_DOWN,
4449 AINPUT_SOURCE_TOUCHSCREEN)
4450 .deviceId(SECOND_DEVICE_ID)
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07004451 .pointer(PointerBuilder(0, ToolType::FINGER).x(200).y(200))
Siarhei Vishniakou060f82b2023-01-27 06:39:14 -08004452 .build()));
4453 window->consumeMotionEvent(AllOf(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_EXIT),
4454 WithSource(AINPUT_SOURCE_MOUSE)));
4455 spyWindow->consumeMotionEvent(AllOf(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_EXIT),
4456 WithSource(AINPUT_SOURCE_MOUSE)));
4457 window->consumeMotionEvent(AllOf(WithMotionAction(AMOTION_EVENT_ACTION_DOWN),
4458 WithSource(AINPUT_SOURCE_TOUCHSCREEN)));
4459 spyWindow->consumeMotionEvent(AllOf(WithMotionAction(AMOTION_EVENT_ACTION_DOWN),
4460 WithSource(AINPUT_SOURCE_TOUCHSCREEN)));
4461
4462 // pilfer the motion, retaining the gesture on the spy window.
4463 EXPECT_EQ(OK, mDispatcher->pilferPointers(spyWindow->getToken()));
4464 window->consumeMotionEvent(AllOf(WithMotionAction(AMOTION_EVENT_ACTION_CANCEL),
4465 WithSource(AINPUT_SOURCE_TOUCHSCREEN)));
4466
4467 // Touch UP on the window
4468 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07004469 injectMotionEvent(*mDispatcher,
Siarhei Vishniakou060f82b2023-01-27 06:39:14 -08004470 MotionEventBuilder(AMOTION_EVENT_ACTION_UP,
4471 AINPUT_SOURCE_TOUCHSCREEN)
4472 .deviceId(SECOND_DEVICE_ID)
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07004473 .pointer(PointerBuilder(0, ToolType::FINGER).x(200).y(200))
Siarhei Vishniakou060f82b2023-01-27 06:39:14 -08004474 .build()));
4475 spyWindow->consumeMotionEvent(AllOf(WithMotionAction(AMOTION_EVENT_ACTION_UP),
4476 WithSource(AINPUT_SOURCE_TOUCHSCREEN)));
4477
4478 // Previously, a touch was pilfered. However, that gesture was just finished. Now, we are going
4479 // to send a new gesture. It should again go to both windows (spy and the window below), just
4480 // like the first gesture did, before pilfering. The window configuration has not changed.
4481
4482 // One more tap - DOWN
4483 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07004484 injectMotionEvent(*mDispatcher,
Siarhei Vishniakou060f82b2023-01-27 06:39:14 -08004485 MotionEventBuilder(AMOTION_EVENT_ACTION_DOWN,
4486 AINPUT_SOURCE_TOUCHSCREEN)
4487 .deviceId(SECOND_DEVICE_ID)
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07004488 .pointer(PointerBuilder(0, ToolType::FINGER).x(250).y(250))
Siarhei Vishniakou060f82b2023-01-27 06:39:14 -08004489 .build()));
4490 window->consumeMotionEvent(AllOf(WithMotionAction(AMOTION_EVENT_ACTION_DOWN),
4491 WithSource(AINPUT_SOURCE_TOUCHSCREEN)));
4492 spyWindow->consumeMotionEvent(AllOf(WithMotionAction(AMOTION_EVENT_ACTION_DOWN),
4493 WithSource(AINPUT_SOURCE_TOUCHSCREEN)));
4494
4495 // Touch UP on the window
4496 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07004497 injectMotionEvent(*mDispatcher,
Siarhei Vishniakou060f82b2023-01-27 06:39:14 -08004498 MotionEventBuilder(AMOTION_EVENT_ACTION_UP,
4499 AINPUT_SOURCE_TOUCHSCREEN)
4500 .deviceId(SECOND_DEVICE_ID)
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07004501 .pointer(PointerBuilder(0, ToolType::FINGER).x(250).y(250))
Siarhei Vishniakou060f82b2023-01-27 06:39:14 -08004502 .build()));
4503 window->consumeMotionEvent(AllOf(WithMotionAction(AMOTION_EVENT_ACTION_UP),
4504 WithSource(AINPUT_SOURCE_TOUCHSCREEN)));
4505 spyWindow->consumeMotionEvent(AllOf(WithMotionAction(AMOTION_EVENT_ACTION_UP),
4506 WithSource(AINPUT_SOURCE_TOUCHSCREEN)));
4507
4508 window->assertNoEvents();
4509 spyWindow->assertNoEvents();
4510}
4511
Siarhei Vishniakoued89cbb2023-10-13 10:42:44 -07004512TEST_F(InputDispatcherTest, MouseAndTouchWithSpyWindows) {
4513 SCOPED_FLAG_OVERRIDE(enable_multi_device_same_window_stream, true);
4514 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
4515
4516 sp<FakeWindowHandle> spyWindow =
4517 sp<FakeWindowHandle>::make(application, mDispatcher, "Spy", ADISPLAY_ID_DEFAULT);
4518 spyWindow->setFrame(Rect(0, 0, 600, 800));
4519 spyWindow->setTrustedOverlay(true);
4520 spyWindow->setSpy(true);
4521 sp<FakeWindowHandle> window =
4522 sp<FakeWindowHandle>::make(application, mDispatcher, "Window", ADISPLAY_ID_DEFAULT);
4523 window->setFrame(Rect(0, 0, 600, 800));
4524
4525 mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application);
4526 mDispatcher->onWindowInfosChanged({{*spyWindow->getInfo(), *window->getInfo()}, {}, 0, 0});
4527
4528 // Send mouse cursor to the window
4529 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_ENTER, AINPUT_SOURCE_MOUSE)
4530 .pointer(PointerBuilder(0, ToolType::MOUSE).x(100).y(100))
4531 .build());
4532
4533 // Move mouse cursor
4534 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_MOVE, AINPUT_SOURCE_MOUSE)
4535 .pointer(PointerBuilder(0, ToolType::MOUSE).x(110).y(110))
4536 .build());
4537
4538 window->consumeMotionEvent(
4539 AllOf(WithMotionAction(ACTION_HOVER_ENTER), WithSource(AINPUT_SOURCE_MOUSE)));
4540 spyWindow->consumeMotionEvent(
4541 AllOf(WithMotionAction(ACTION_HOVER_ENTER), WithSource(AINPUT_SOURCE_MOUSE)));
4542 window->consumeMotionEvent(
4543 AllOf(WithMotionAction(ACTION_HOVER_MOVE), WithSource(AINPUT_SOURCE_MOUSE)));
4544 spyWindow->consumeMotionEvent(
4545 AllOf(WithMotionAction(ACTION_HOVER_MOVE), WithSource(AINPUT_SOURCE_MOUSE)));
4546 // Touch down on the window
4547 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
4548 .deviceId(SECOND_DEVICE_ID)
4549 .pointer(PointerBuilder(0, ToolType::FINGER).x(200).y(200))
4550 .build());
4551 window->consumeMotionEvent(
4552 AllOf(WithMotionAction(ACTION_DOWN), WithSource(AINPUT_SOURCE_TOUCHSCREEN)));
4553 spyWindow->consumeMotionEvent(
4554 AllOf(WithMotionAction(ACTION_DOWN), WithSource(AINPUT_SOURCE_TOUCHSCREEN)));
4555
4556 // pilfer the motion, retaining the gesture on the spy window.
4557 EXPECT_EQ(OK, mDispatcher->pilferPointers(spyWindow->getToken()));
4558 window->consumeMotionEvent(
4559 AllOf(WithMotionAction(ACTION_CANCEL), WithSource(AINPUT_SOURCE_TOUCHSCREEN)));
4560 // Mouse hover is not pilfered
4561
4562 // Touch UP on the window
4563 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN)
4564 .deviceId(SECOND_DEVICE_ID)
4565 .pointer(PointerBuilder(0, ToolType::FINGER).x(200).y(200))
4566 .build());
4567 spyWindow->consumeMotionEvent(
4568 AllOf(WithMotionAction(ACTION_UP), WithSource(AINPUT_SOURCE_TOUCHSCREEN)));
4569
4570 // Previously, a touch was pilfered. However, that gesture was just finished. Now, we are going
4571 // to send a new gesture. It should again go to both windows (spy and the window below), just
4572 // like the first gesture did, before pilfering. The window configuration has not changed.
4573
4574 // One more tap - DOWN
4575 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
4576 .deviceId(SECOND_DEVICE_ID)
4577 .pointer(PointerBuilder(0, ToolType::FINGER).x(250).y(250))
4578 .build());
4579 window->consumeMotionEvent(
4580 AllOf(WithMotionAction(ACTION_DOWN), WithSource(AINPUT_SOURCE_TOUCHSCREEN)));
4581 spyWindow->consumeMotionEvent(
4582 AllOf(WithMotionAction(ACTION_DOWN), WithSource(AINPUT_SOURCE_TOUCHSCREEN)));
4583
4584 // Touch UP on the window
4585 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN)
4586 .deviceId(SECOND_DEVICE_ID)
4587 .pointer(PointerBuilder(0, ToolType::FINGER).x(250).y(250))
4588 .build());
4589 window->consumeMotionEvent(
4590 AllOf(WithMotionAction(ACTION_UP), WithSource(AINPUT_SOURCE_TOUCHSCREEN)));
4591 spyWindow->consumeMotionEvent(
4592 AllOf(WithMotionAction(ACTION_UP), WithSource(AINPUT_SOURCE_TOUCHSCREEN)));
4593
4594 // Mouse movement continues normally as well
4595 // Move mouse cursor
4596 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_MOVE, AINPUT_SOURCE_MOUSE)
4597 .pointer(PointerBuilder(0, ToolType::MOUSE).x(120).y(130))
4598 .build());
4599 window->consumeMotionEvent(
4600 AllOf(WithMotionAction(ACTION_HOVER_MOVE), WithSource(AINPUT_SOURCE_MOUSE)));
4601 spyWindow->consumeMotionEvent(
4602 AllOf(WithMotionAction(ACTION_HOVER_MOVE), WithSource(AINPUT_SOURCE_MOUSE)));
4603
4604 window->assertNoEvents();
4605 spyWindow->assertNoEvents();
4606}
4607
Garfield Tandf26e862020-07-01 20:18:19 -07004608// This test is different from the test above that HOVER_ENTER and HOVER_EXIT events are injected
4609// directly in this test.
4610TEST_F(InputDispatcherTest, HoverEnterMouseClickAndHoverExit) {
Chris Yea209fde2020-07-22 13:54:51 -07004611 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
Garfield Tandf26e862020-07-01 20:18:19 -07004612 sp<FakeWindowHandle> window =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07004613 sp<FakeWindowHandle>::make(application, mDispatcher, "Window", ADISPLAY_ID_DEFAULT);
Garfield Tandf26e862020-07-01 20:18:19 -07004614 window->setFrame(Rect(0, 0, 1200, 800));
Garfield Tandf26e862020-07-01 20:18:19 -07004615
4616 mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application);
4617
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07004618 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Garfield Tandf26e862020-07-01 20:18:19 -07004619
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08004620 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07004621 injectMotionEvent(*mDispatcher,
Garfield Tandf26e862020-07-01 20:18:19 -07004622 MotionEventBuilder(AMOTION_EVENT_ACTION_HOVER_ENTER,
4623 AINPUT_SOURCE_MOUSE)
Siarhei Vishniakou6d73f832022-07-21 17:27:03 -07004624 .pointer(PointerBuilder(0, ToolType::MOUSE).x(300).y(400))
Garfield Tandf26e862020-07-01 20:18:19 -07004625 .build()));
Siarhei Vishniakou5cee1e32022-11-29 12:35:39 -08004626 window->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_ENTER));
Garfield Tandf26e862020-07-01 20:18:19 -07004627 // Inject a series of mouse events for a mouse click
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08004628 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07004629 injectMotionEvent(*mDispatcher,
Garfield Tandf26e862020-07-01 20:18:19 -07004630 MotionEventBuilder(AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_MOUSE)
4631 .buttonState(AMOTION_EVENT_BUTTON_PRIMARY)
Siarhei Vishniakou6d73f832022-07-21 17:27:03 -07004632 .pointer(PointerBuilder(0, ToolType::MOUSE).x(300).y(400))
Garfield Tandf26e862020-07-01 20:18:19 -07004633 .build()));
Siarhei Vishniakouf372b812023-02-14 18:06:51 -08004634 window->consumeMotionEvent(WithMotionAction(ACTION_HOVER_EXIT));
4635 window->consumeMotionEvent(WithMotionAction(ACTION_DOWN));
Garfield Tandf26e862020-07-01 20:18:19 -07004636
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08004637 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07004638 injectMotionEvent(*mDispatcher,
Garfield Tandf26e862020-07-01 20:18:19 -07004639 MotionEventBuilder(AMOTION_EVENT_ACTION_BUTTON_PRESS,
4640 AINPUT_SOURCE_MOUSE)
4641 .buttonState(AMOTION_EVENT_BUTTON_PRIMARY)
4642 .actionButton(AMOTION_EVENT_BUTTON_PRIMARY)
Siarhei Vishniakou6d73f832022-07-21 17:27:03 -07004643 .pointer(PointerBuilder(0, ToolType::MOUSE).x(300).y(400))
Garfield Tandf26e862020-07-01 20:18:19 -07004644 .build()));
Siarhei Vishniakou5cee1e32022-11-29 12:35:39 -08004645 window->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_BUTTON_PRESS));
Garfield Tandf26e862020-07-01 20:18:19 -07004646
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08004647 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07004648 injectMotionEvent(*mDispatcher,
Garfield Tandf26e862020-07-01 20:18:19 -07004649 MotionEventBuilder(AMOTION_EVENT_ACTION_BUTTON_RELEASE,
4650 AINPUT_SOURCE_MOUSE)
4651 .buttonState(0)
4652 .actionButton(AMOTION_EVENT_BUTTON_PRIMARY)
Siarhei Vishniakou6d73f832022-07-21 17:27:03 -07004653 .pointer(PointerBuilder(0, ToolType::MOUSE).x(300).y(400))
Garfield Tandf26e862020-07-01 20:18:19 -07004654 .build()));
Siarhei Vishniakou5cee1e32022-11-29 12:35:39 -08004655 window->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_BUTTON_RELEASE));
Garfield Tandf26e862020-07-01 20:18:19 -07004656
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08004657 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07004658 injectMotionEvent(*mDispatcher,
Garfield Tandf26e862020-07-01 20:18:19 -07004659 MotionEventBuilder(AMOTION_EVENT_ACTION_UP, AINPUT_SOURCE_MOUSE)
4660 .buttonState(0)
Siarhei Vishniakou6d73f832022-07-21 17:27:03 -07004661 .pointer(PointerBuilder(0, ToolType::MOUSE).x(300).y(400))
Garfield Tandf26e862020-07-01 20:18:19 -07004662 .build()));
4663 window->consumeMotionUp(ADISPLAY_ID_DEFAULT);
4664
Siarhei Vishniakoua235c042023-05-02 09:59:09 -07004665 // We already canceled the hovering implicitly by injecting the "DOWN" event without lifting the
4666 // hover first. Therefore, injection of HOVER_EXIT is inconsistent, and should fail.
4667 ASSERT_EQ(InputEventInjectionResult::FAILED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07004668 injectMotionEvent(*mDispatcher,
Garfield Tandf26e862020-07-01 20:18:19 -07004669 MotionEventBuilder(AMOTION_EVENT_ACTION_HOVER_EXIT,
4670 AINPUT_SOURCE_MOUSE)
Siarhei Vishniakou6d73f832022-07-21 17:27:03 -07004671 .pointer(PointerBuilder(0, ToolType::MOUSE).x(300).y(400))
Garfield Tandf26e862020-07-01 20:18:19 -07004672 .build()));
Siarhei Vishniakouf372b812023-02-14 18:06:51 -08004673 window->assertNoEvents();
Garfield Tandf26e862020-07-01 20:18:19 -07004674}
4675
Siarhei Vishniakou0b0374d2022-11-17 17:40:53 -08004676/**
Siarhei Vishniakoub581f7f2022-12-07 20:23:06 +00004677 * Hover over a window, and then remove that window. Make sure that HOVER_EXIT for that event
4678 * is generated.
4679 */
4680TEST_F(InputDispatcherTest, HoverExitIsSentToRemovedWindow) {
4681 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
4682 sp<FakeWindowHandle> window =
4683 sp<FakeWindowHandle>::make(application, mDispatcher, "Window", ADISPLAY_ID_DEFAULT);
4684 window->setFrame(Rect(0, 0, 1200, 800));
4685
4686 mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application);
4687
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07004688 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Siarhei Vishniakoub581f7f2022-12-07 20:23:06 +00004689
4690 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07004691 injectMotionEvent(*mDispatcher,
Siarhei Vishniakoub581f7f2022-12-07 20:23:06 +00004692 MotionEventBuilder(AMOTION_EVENT_ACTION_HOVER_ENTER,
4693 AINPUT_SOURCE_MOUSE)
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07004694 .pointer(PointerBuilder(0, ToolType::MOUSE).x(300).y(400))
Siarhei Vishniakoub581f7f2022-12-07 20:23:06 +00004695 .build()));
4696 window->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_ENTER));
4697
4698 // Remove the window, but keep the channel.
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07004699 mDispatcher->onWindowInfosChanged({{}, {}, 0, 0});
Siarhei Vishniakoub581f7f2022-12-07 20:23:06 +00004700 window->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_EXIT));
4701}
4702
4703/**
Daniel Norman7487dfa2023-08-02 16:39:45 -07004704 * Test that invalid HOVER events sent by accessibility do not cause a fatal crash.
4705 */
Ameer Armalycff4fa52023-10-04 23:45:11 +00004706TEST_F_WITH_FLAGS(InputDispatcherTest, InvalidA11yHoverStreamDoesNotCrash,
4707 REQUIRES_FLAGS_DISABLED(ACONFIG_FLAG(com::android::input::flags,
4708 a11y_crash_on_inconsistent_event_stream))) {
Daniel Norman7487dfa2023-08-02 16:39:45 -07004709 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
4710 sp<FakeWindowHandle> window =
4711 sp<FakeWindowHandle>::make(application, mDispatcher, "Window", ADISPLAY_ID_DEFAULT);
4712 window->setFrame(Rect(0, 0, 1200, 800));
4713
4714 mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application);
4715
4716 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
4717
4718 MotionEventBuilder hoverEnterBuilder =
4719 MotionEventBuilder(AMOTION_EVENT_ACTION_HOVER_ENTER, AINPUT_SOURCE_MOUSE)
4720 .pointer(PointerBuilder(0, ToolType::MOUSE).x(300).y(400))
4721 .addFlag(AMOTION_EVENT_FLAG_IS_ACCESSIBILITY_EVENT);
4722 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
4723 injectMotionEvent(*mDispatcher, hoverEnterBuilder.build()));
4724 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
4725 injectMotionEvent(*mDispatcher, hoverEnterBuilder.build()));
4726 window->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_ENTER));
4727 window->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_ENTER));
4728}
4729
4730/**
Siarhei Vishniakou4e1ffa52023-02-21 11:50:34 -08004731 * If mouse is hovering when the touch goes down, the hovering should be stopped via HOVER_EXIT.
4732 */
Siarhei Vishniakoued89cbb2023-10-13 10:42:44 -07004733TEST_F(InputDispatcherTest, TouchDownAfterMouseHover_legacy) {
4734 SCOPED_FLAG_OVERRIDE(enable_multi_device_same_window_stream, false);
Siarhei Vishniakou4e1ffa52023-02-21 11:50:34 -08004735 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
4736 sp<FakeWindowHandle> window =
4737 sp<FakeWindowHandle>::make(application, mDispatcher, "Window", ADISPLAY_ID_DEFAULT);
4738 window->setFrame(Rect(0, 0, 100, 100));
4739
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07004740 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Siarhei Vishniakou4e1ffa52023-02-21 11:50:34 -08004741
4742 const int32_t mouseDeviceId = 7;
4743 const int32_t touchDeviceId = 4;
Siarhei Vishniakou4e1ffa52023-02-21 11:50:34 -08004744
4745 // Start hovering with the mouse
Prabir Pradhan678438e2023-04-13 19:32:51 +00004746 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_ENTER, AINPUT_SOURCE_MOUSE)
4747 .deviceId(mouseDeviceId)
4748 .pointer(PointerBuilder(0, ToolType::MOUSE).x(10).y(10))
4749 .build());
Siarhei Vishniakou4e1ffa52023-02-21 11:50:34 -08004750 window->consumeMotionEvent(
4751 AllOf(WithMotionAction(ACTION_HOVER_ENTER), WithDeviceId(mouseDeviceId)));
4752
4753 // Touch goes down
Prabir Pradhan678438e2023-04-13 19:32:51 +00004754 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
4755 .deviceId(touchDeviceId)
4756 .pointer(PointerBuilder(0, ToolType::FINGER).x(50).y(50))
4757 .build());
Siarhei Vishniakou4e1ffa52023-02-21 11:50:34 -08004758
4759 window->consumeMotionEvent(
4760 AllOf(WithMotionAction(ACTION_HOVER_EXIT), WithDeviceId(mouseDeviceId)));
4761 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(touchDeviceId)));
4762}
4763
4764/**
Siarhei Vishniakoued89cbb2023-10-13 10:42:44 -07004765 * If mouse is hovering when the touch goes down, the hovering should not be stopped.
4766 */
4767TEST_F(InputDispatcherTest, TouchDownAfterMouseHover) {
4768 SCOPED_FLAG_OVERRIDE(enable_multi_device_same_window_stream, true);
4769 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
4770 sp<FakeWindowHandle> window =
4771 sp<FakeWindowHandle>::make(application, mDispatcher, "Window", ADISPLAY_ID_DEFAULT);
4772 window->setFrame(Rect(0, 0, 100, 100));
4773
4774 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
4775
4776 const int32_t mouseDeviceId = 7;
4777 const int32_t touchDeviceId = 4;
4778
4779 // Start hovering with the mouse
4780 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_ENTER, AINPUT_SOURCE_MOUSE)
4781 .deviceId(mouseDeviceId)
4782 .pointer(PointerBuilder(0, ToolType::MOUSE).x(10).y(10))
4783 .build());
4784 window->consumeMotionEvent(
4785 AllOf(WithMotionAction(ACTION_HOVER_ENTER), WithDeviceId(mouseDeviceId)));
4786
4787 // Touch goes down
4788 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
4789 .deviceId(touchDeviceId)
4790 .pointer(PointerBuilder(0, ToolType::FINGER).x(50).y(50))
4791 .build());
4792 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(touchDeviceId)));
4793}
4794
4795/**
Siarhei Vishniakou0b0374d2022-11-17 17:40:53 -08004796 * Inject a mouse hover event followed by a tap from touchscreen.
Siarhei Vishniakoub581f7f2022-12-07 20:23:06 +00004797 * The tap causes a HOVER_EXIT event to be generated because the current event
4798 * stream's source has been switched.
Siarhei Vishniakou0b0374d2022-11-17 17:40:53 -08004799 */
Siarhei Vishniakoued89cbb2023-10-13 10:42:44 -07004800TEST_F(InputDispatcherTest, MouseHoverAndTouchTap_legacy) {
4801 SCOPED_FLAG_OVERRIDE(enable_multi_device_same_window_stream, false);
Siarhei Vishniakou0b0374d2022-11-17 17:40:53 -08004802 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
4803 sp<FakeWindowHandle> window =
4804 sp<FakeWindowHandle>::make(application, mDispatcher, "Window", ADISPLAY_ID_DEFAULT);
4805 window->setFrame(Rect(0, 0, 100, 100));
4806
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07004807 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -07004808 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_MOVE, AINPUT_SOURCE_MOUSE)
4809 .pointer(PointerBuilder(0, ToolType::MOUSE).x(50).y(50))
4810 .build());
Siarhei Vishniakou0b0374d2022-11-17 17:40:53 -08004811 ASSERT_NO_FATAL_FAILURE(
4812 window->consumeMotionEvent(AllOf(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_ENTER),
4813 WithSource(AINPUT_SOURCE_MOUSE))));
Siarhei Vishniakou0b0374d2022-11-17 17:40:53 -08004814
4815 // Tap on the window
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -07004816 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
4817 .pointer(PointerBuilder(0, ToolType::FINGER).x(10).y(10))
4818 .build());
Siarhei Vishniakou0b0374d2022-11-17 17:40:53 -08004819 ASSERT_NO_FATAL_FAILURE(
Siarhei Vishniakoub581f7f2022-12-07 20:23:06 +00004820 window->consumeMotionEvent(AllOf(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_EXIT),
4821 WithSource(AINPUT_SOURCE_MOUSE))));
4822
4823 ASSERT_NO_FATAL_FAILURE(
Siarhei Vishniakou0b0374d2022-11-17 17:40:53 -08004824 window->consumeMotionEvent(AllOf(WithMotionAction(AMOTION_EVENT_ACTION_DOWN),
4825 WithSource(AINPUT_SOURCE_TOUCHSCREEN))));
4826
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -07004827 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN)
4828 .pointer(PointerBuilder(0, ToolType::FINGER).x(10).y(10))
4829 .build());
Siarhei Vishniakou0b0374d2022-11-17 17:40:53 -08004830 ASSERT_NO_FATAL_FAILURE(
4831 window->consumeMotionEvent(AllOf(WithMotionAction(AMOTION_EVENT_ACTION_UP),
4832 WithSource(AINPUT_SOURCE_TOUCHSCREEN))));
4833}
4834
Siarhei Vishniakoued89cbb2023-10-13 10:42:44 -07004835/**
4836 * Send a mouse hover event followed by a tap from touchscreen.
4837 * The tap causes a HOVER_EXIT event to be generated because the current event
4838 * stream's source has been switched.
4839 */
4840TEST_F(InputDispatcherTest, MouseHoverAndTouchTap) {
4841 SCOPED_FLAG_OVERRIDE(enable_multi_device_same_window_stream, true);
4842 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
4843 sp<FakeWindowHandle> window =
4844 sp<FakeWindowHandle>::make(application, mDispatcher, "Window", ADISPLAY_ID_DEFAULT);
4845 window->setFrame(Rect(0, 0, 100, 100));
4846
4847 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
4848 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_MOVE, AINPUT_SOURCE_MOUSE)
4849 .pointer(PointerBuilder(0, ToolType::MOUSE).x(50).y(50))
4850 .build());
4851
4852 window->consumeMotionEvent(AllOf(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_ENTER),
4853 WithSource(AINPUT_SOURCE_MOUSE)));
4854
4855 // Tap on the window
4856 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
4857 .pointer(PointerBuilder(0, ToolType::FINGER).x(10).y(10))
4858 .build());
4859
4860 window->consumeMotionEvent(AllOf(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_EXIT),
4861 WithSource(AINPUT_SOURCE_MOUSE)));
4862
4863 window->consumeMotionEvent(AllOf(WithMotionAction(AMOTION_EVENT_ACTION_DOWN),
4864 WithSource(AINPUT_SOURCE_TOUCHSCREEN)));
4865
4866 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN)
4867 .pointer(PointerBuilder(0, ToolType::FINGER).x(10).y(10))
4868 .build());
4869
4870 window->consumeMotionEvent(AllOf(WithMotionAction(AMOTION_EVENT_ACTION_UP),
4871 WithSource(AINPUT_SOURCE_TOUCHSCREEN)));
4872}
4873
Tommy Nordgrendae9dfc2022-10-13 11:25:57 +02004874TEST_F(InputDispatcherTest, HoverEnterMoveRemoveWindowsInSecondDisplay) {
4875 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
4876 sp<FakeWindowHandle> windowDefaultDisplay =
4877 sp<FakeWindowHandle>::make(application, mDispatcher, "DefaultDisplay",
4878 ADISPLAY_ID_DEFAULT);
4879 windowDefaultDisplay->setFrame(Rect(0, 0, 600, 800));
4880 sp<FakeWindowHandle> windowSecondDisplay =
4881 sp<FakeWindowHandle>::make(application, mDispatcher, "SecondDisplay",
4882 SECOND_DISPLAY_ID);
4883 windowSecondDisplay->setFrame(Rect(0, 0, 600, 800));
4884
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07004885 mDispatcher->onWindowInfosChanged(
4886 {{*windowDefaultDisplay->getInfo(), *windowSecondDisplay->getInfo()}, {}, 0, 0});
Tommy Nordgrendae9dfc2022-10-13 11:25:57 +02004887
4888 // Set cursor position in window in default display and check that hover enter and move
4889 // events are generated.
4890 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07004891 injectMotionEvent(*mDispatcher,
Tommy Nordgrendae9dfc2022-10-13 11:25:57 +02004892 MotionEventBuilder(AMOTION_EVENT_ACTION_HOVER_MOVE,
4893 AINPUT_SOURCE_MOUSE)
4894 .displayId(ADISPLAY_ID_DEFAULT)
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07004895 .pointer(PointerBuilder(0, ToolType::MOUSE).x(300).y(600))
Tommy Nordgrendae9dfc2022-10-13 11:25:57 +02004896 .build()));
Siarhei Vishniakou5cee1e32022-11-29 12:35:39 -08004897 windowDefaultDisplay->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_ENTER));
Tommy Nordgrendae9dfc2022-10-13 11:25:57 +02004898
4899 // Remove all windows in secondary display and check that no event happens on window in
4900 // primary display.
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07004901 mDispatcher->onWindowInfosChanged({{*windowDefaultDisplay->getInfo()}, {}, 0, 0});
4902
Tommy Nordgrendae9dfc2022-10-13 11:25:57 +02004903 windowDefaultDisplay->assertNoEvents();
4904
4905 // Move cursor position in window in default display and check that only hover move
4906 // event is generated and not hover enter event.
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07004907 mDispatcher->onWindowInfosChanged(
4908 {{*windowDefaultDisplay->getInfo(), *windowSecondDisplay->getInfo()}, {}, 0, 0});
Tommy Nordgrendae9dfc2022-10-13 11:25:57 +02004909 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07004910 injectMotionEvent(*mDispatcher,
Tommy Nordgrendae9dfc2022-10-13 11:25:57 +02004911 MotionEventBuilder(AMOTION_EVENT_ACTION_HOVER_MOVE,
4912 AINPUT_SOURCE_MOUSE)
4913 .displayId(ADISPLAY_ID_DEFAULT)
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07004914 .pointer(PointerBuilder(0, ToolType::MOUSE).x(400).y(700))
Tommy Nordgrendae9dfc2022-10-13 11:25:57 +02004915 .build()));
Siarhei Vishniakou5cee1e32022-11-29 12:35:39 -08004916 windowDefaultDisplay->consumeMotionEvent(
4917 AllOf(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_MOVE),
4918 WithSource(AINPUT_SOURCE_MOUSE)));
Tommy Nordgrendae9dfc2022-10-13 11:25:57 +02004919 windowDefaultDisplay->assertNoEvents();
4920}
4921
Garfield Tan00f511d2019-06-12 16:55:40 -07004922TEST_F(InputDispatcherTest, DispatchMouseEventsUnderCursor) {
Chris Yea209fde2020-07-22 13:54:51 -07004923 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
Garfield Tan00f511d2019-06-12 16:55:40 -07004924
4925 sp<FakeWindowHandle> windowLeft =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07004926 sp<FakeWindowHandle>::make(application, mDispatcher, "Left", ADISPLAY_ID_DEFAULT);
Garfield Tan00f511d2019-06-12 16:55:40 -07004927 windowLeft->setFrame(Rect(0, 0, 600, 800));
Garfield Tan00f511d2019-06-12 16:55:40 -07004928 sp<FakeWindowHandle> windowRight =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07004929 sp<FakeWindowHandle>::make(application, mDispatcher, "Right", ADISPLAY_ID_DEFAULT);
Garfield Tan00f511d2019-06-12 16:55:40 -07004930 windowRight->setFrame(Rect(600, 0, 1200, 800));
Garfield Tan00f511d2019-06-12 16:55:40 -07004931
4932 mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application);
4933
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07004934 mDispatcher->onWindowInfosChanged(
4935 {{*windowLeft->getInfo(), *windowRight->getInfo()}, {}, 0, 0});
Garfield Tan00f511d2019-06-12 16:55:40 -07004936
4937 // Inject an event with coordinate in the area of right window, with mouse cursor in the area of
4938 // left window. This event should be dispatched to the left window.
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08004939 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07004940 injectMotionEvent(*mDispatcher, AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_MOUSE,
Siarhei Vishniakou4cb50ca2020-05-26 21:43:02 -07004941 ADISPLAY_ID_DEFAULT, {610, 400}, {599, 400}));
Siarhei Vishniakouc5ca85c2019-11-15 17:20:00 -08004942 windowLeft->consumeMotionDown(ADISPLAY_ID_DEFAULT);
Garfield Tan00f511d2019-06-12 16:55:40 -07004943 windowRight->assertNoEvents();
4944}
4945
Siarhei Vishniakou2bfa9052019-11-21 18:10:54 -08004946TEST_F(InputDispatcherTest, NotifyDeviceReset_CancelsKeyStream) {
Chris Yea209fde2020-07-22 13:54:51 -07004947 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07004948 sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher,
4949 "Fake Window", ADISPLAY_ID_DEFAULT);
Vishnu Nair47074b82020-08-14 11:54:47 -07004950 window->setFocusable(true);
Siarhei Vishniakou2bfa9052019-11-21 18:10:54 -08004951
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07004952 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Vishnu Nair958da932020-08-21 17:12:37 -07004953 setFocusedWindow(window);
4954
Siarhei Vishniakouf1035d42019-09-20 16:32:01 +01004955 window->consumeFocusEvent(true);
Siarhei Vishniakou2bfa9052019-11-21 18:10:54 -08004956
Prabir Pradhan678438e2023-04-13 19:32:51 +00004957 mDispatcher->notifyKey(generateKeyArgs(AKEY_EVENT_ACTION_DOWN, ADISPLAY_ID_DEFAULT));
Siarhei Vishniakou2bfa9052019-11-21 18:10:54 -08004958
4959 // Window should receive key down event.
4960 window->consumeKeyDown(ADISPLAY_ID_DEFAULT);
4961
4962 // When device reset happens, that key stream should be terminated with FLAG_CANCELED
4963 // on the app side.
Prabir Pradhan678438e2023-04-13 19:32:51 +00004964 mDispatcher->notifyDeviceReset({/*id=*/10, /*eventTime=*/20, DEVICE_ID});
Prabir Pradhan7662a8d2023-12-15 01:58:14 +00004965 window->consumeKeyUp(ADISPLAY_ID_DEFAULT, AKEY_EVENT_FLAG_CANCELED);
Siarhei Vishniakou2bfa9052019-11-21 18:10:54 -08004966}
4967
4968TEST_F(InputDispatcherTest, NotifyDeviceReset_CancelsMotionStream) {
Chris Yea209fde2020-07-22 13:54:51 -07004969 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07004970 sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher,
4971 "Fake Window", ADISPLAY_ID_DEFAULT);
Siarhei Vishniakou2bfa9052019-11-21 18:10:54 -08004972
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07004973 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Siarhei Vishniakou2bfa9052019-11-21 18:10:54 -08004974
Prabir Pradhan678438e2023-04-13 19:32:51 +00004975 mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_DOWN,
4976 AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT));
Siarhei Vishniakou2bfa9052019-11-21 18:10:54 -08004977
4978 // Window should receive motion down event.
4979 window->consumeMotionDown(ADISPLAY_ID_DEFAULT);
4980
4981 // When device reset happens, that motion stream should be terminated with ACTION_CANCEL
4982 // on the app side.
Prabir Pradhan678438e2023-04-13 19:32:51 +00004983 mDispatcher->notifyDeviceReset({/*id=*/10, /*eventTime=*/20, DEVICE_ID});
Siarhei Vishniakou1ae72f12023-01-29 12:55:30 -08004984 window->consumeMotionEvent(
4985 AllOf(WithMotionAction(ACTION_CANCEL), WithDisplayId(ADISPLAY_ID_DEFAULT)));
Siarhei Vishniakou2bfa9052019-11-21 18:10:54 -08004986}
4987
Siarhei Vishniakou0686f0c2023-05-02 11:56:15 -07004988TEST_F(InputDispatcherTest, NotifyDeviceResetCancelsHoveringStream) {
4989 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
4990 sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher,
4991 "Fake Window", ADISPLAY_ID_DEFAULT);
4992
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07004993 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Siarhei Vishniakou0686f0c2023-05-02 11:56:15 -07004994
4995 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_ENTER, AINPUT_SOURCE_STYLUS)
4996 .pointer(PointerBuilder(0, ToolType::STYLUS).x(10).y(10))
4997 .build());
4998
4999 window->consumeMotionEvent(WithMotionAction(ACTION_HOVER_ENTER));
5000
5001 // When device reset happens, that hover stream should be terminated with ACTION_HOVER_EXIT
5002 mDispatcher->notifyDeviceReset({/*id=*/10, /*eventTime=*/20, DEVICE_ID});
5003 window->consumeMotionEvent(WithMotionAction(ACTION_HOVER_EXIT));
5004
5005 // After the device has been reset, a new hovering stream can be sent to the window
5006 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_ENTER, AINPUT_SOURCE_STYLUS)
5007 .pointer(PointerBuilder(0, ToolType::STYLUS).x(15).y(15))
5008 .build());
5009 window->consumeMotionEvent(WithMotionAction(ACTION_HOVER_ENTER));
5010}
5011
Arthur Hung2ee6d0b2022-03-03 20:19:38 +08005012TEST_F(InputDispatcherTest, InterceptKeyByPolicy) {
5013 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07005014 sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher,
5015 "Fake Window", ADISPLAY_ID_DEFAULT);
Arthur Hung2ee6d0b2022-03-03 20:19:38 +08005016 window->setFocusable(true);
5017
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07005018 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Arthur Hung2ee6d0b2022-03-03 20:19:38 +08005019 setFocusedWindow(window);
5020
5021 window->consumeFocusEvent(true);
5022
Prabir Pradhan678438e2023-04-13 19:32:51 +00005023 const NotifyKeyArgs keyArgs = generateKeyArgs(AKEY_EVENT_ACTION_DOWN, ADISPLAY_ID_DEFAULT);
Arthur Hung2ee6d0b2022-03-03 20:19:38 +08005024 const std::chrono::milliseconds interceptKeyTimeout = 50ms;
5025 const nsecs_t injectTime = keyArgs.eventTime;
5026 mFakePolicy->setInterceptKeyTimeout(interceptKeyTimeout);
Prabir Pradhan678438e2023-04-13 19:32:51 +00005027 mDispatcher->notifyKey(keyArgs);
Arthur Hung2ee6d0b2022-03-03 20:19:38 +08005028 // The dispatching time should be always greater than or equal to intercept key timeout.
5029 window->consumeKeyDown(ADISPLAY_ID_DEFAULT);
5030 ASSERT_TRUE((systemTime(SYSTEM_TIME_MONOTONIC) - injectTime) >=
5031 std::chrono::nanoseconds(interceptKeyTimeout).count());
5032}
5033
Siarhei Vishniakouf54d2ab2023-06-09 13:23:53 -07005034/**
5035 * Keys with ACTION_UP are delivered immediately, even if a long 'intercept key timeout' is set.
5036 */
Arthur Hung2ee6d0b2022-03-03 20:19:38 +08005037TEST_F(InputDispatcherTest, InterceptKeyIfKeyUp) {
5038 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07005039 sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher,
5040 "Fake Window", ADISPLAY_ID_DEFAULT);
Arthur Hung2ee6d0b2022-03-03 20:19:38 +08005041 window->setFocusable(true);
5042
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07005043 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Arthur Hung2ee6d0b2022-03-03 20:19:38 +08005044 setFocusedWindow(window);
5045
5046 window->consumeFocusEvent(true);
5047
Prabir Pradhan678438e2023-04-13 19:32:51 +00005048 mDispatcher->notifyKey(generateKeyArgs(AKEY_EVENT_ACTION_DOWN, ADISPLAY_ID_DEFAULT));
Arthur Hung2ee6d0b2022-03-03 20:19:38 +08005049 window->consumeKeyDown(ADISPLAY_ID_DEFAULT);
Siarhei Vishniakouf54d2ab2023-06-09 13:23:53 -07005050
5051 // Set a value that's significantly larger than the default consumption timeout. If the
5052 // implementation is correct, the actual value doesn't matter; it won't slow down the test.
5053 mFakePolicy->setInterceptKeyTimeout(600ms);
5054 mDispatcher->notifyKey(generateKeyArgs(AKEY_EVENT_ACTION_UP, ADISPLAY_ID_DEFAULT));
5055 // Window should receive key event immediately when same key up.
Arthur Hung2ee6d0b2022-03-03 20:19:38 +08005056 window->consumeKeyUp(ADISPLAY_ID_DEFAULT);
5057}
5058
Prabir Pradhanc44ce4d2021-10-05 05:26:29 -07005059/**
Siarhei Vishniakou487c49b2022-12-02 15:48:57 -08005060 * Two windows. First is a regular window. Second does not overlap with the first, and has
5061 * WATCH_OUTSIDE_TOUCH.
5062 * Both windows are owned by the same UID.
5063 * Tap first window. Make sure that the second window receives ACTION_OUTSIDE with correct, non-zero
5064 * coordinates. The coordinates are not zeroed out because both windows are owned by the same UID.
5065 */
5066TEST_F(InputDispatcherTest, ActionOutsideForOwnedWindowHasValidCoordinates) {
5067 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -07005068 sp<FakeWindowHandle> window =
5069 sp<FakeWindowHandle>::make(application, mDispatcher, "Window", ADISPLAY_ID_DEFAULT);
Siarhei Vishniakou487c49b2022-12-02 15:48:57 -08005070 window->setFrame(Rect{0, 0, 100, 100});
5071
5072 sp<FakeWindowHandle> outsideWindow =
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -07005073 sp<FakeWindowHandle>::make(application, mDispatcher, "Outside Window",
Siarhei Vishniakou487c49b2022-12-02 15:48:57 -08005074 ADISPLAY_ID_DEFAULT);
5075 outsideWindow->setFrame(Rect{100, 100, 200, 200});
5076 outsideWindow->setWatchOutsideTouch(true);
5077 // outsideWindow must be above 'window' to receive ACTION_OUTSIDE events when 'window' is tapped
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07005078 mDispatcher->onWindowInfosChanged({{*outsideWindow->getInfo(), *window->getInfo()}, {}, 0, 0});
Siarhei Vishniakou487c49b2022-12-02 15:48:57 -08005079
5080 // Tap on first window.
Prabir Pradhan678438e2023-04-13 19:32:51 +00005081 mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_DOWN,
5082 AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
5083 {PointF{50, 50}}));
Siarhei Vishniakou487c49b2022-12-02 15:48:57 -08005084 window->consumeMotionDown();
5085 // The coordinates of the tap in 'outsideWindow' are relative to its top left corner.
5086 // Therefore, we should offset them by (100, 100) relative to the screen's top left corner.
5087 outsideWindow->consumeMotionEvent(
5088 AllOf(WithMotionAction(ACTION_OUTSIDE), WithCoords(-50, -50)));
Prabir Pradhan502a7252023-12-01 16:11:24 +00005089
5090 // Ensure outsideWindow doesn't get any more events for the gesture.
5091 mDispatcher->notifyMotion(generateMotionArgs(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN,
5092 ADISPLAY_ID_DEFAULT, {PointF{51, 51}}));
5093 window->consumeMotionMove();
5094 outsideWindow->assertNoEvents();
Siarhei Vishniakou487c49b2022-12-02 15:48:57 -08005095}
5096
5097/**
Linnan Liccf6ce32024-04-11 20:32:13 +08005098 * Three windows:
5099 * - Left window
5100 * - Right window
5101 * - Outside window(watch for ACTION_OUTSIDE events)
5102 * The windows "left" and "outside" share the same owner, the window "right" has a different owner,
5103 * In order to allow the outside window can receive the ACTION_OUTSIDE events, the outside window is
5104 * positioned above the "left" and "right" windows, and it doesn't overlap with them.
5105 *
5106 * First, device A report a down event landed in the right window, the outside window can receive
5107 * an ACTION_OUTSIDE event that with zeroed coordinates, the device B report a down event landed
5108 * in the left window, the outside window can receive an ACTION_OUTSIDE event the with valid
5109 * coordinates, after these, device A and device B continue report MOVE event, the right and left
5110 * window can receive it, but outside window event can't receive it.
5111 */
5112TEST_F(InputDispatcherTest, ActionOutsideForOwnedWindowHasValidCoordinatesWhenMultiDevice) {
5113 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
5114 sp<FakeWindowHandle> leftWindow =
5115 sp<FakeWindowHandle>::make(application, mDispatcher, "Left Window",
5116 ADISPLAY_ID_DEFAULT);
5117 leftWindow->setFrame(Rect{0, 0, 100, 100});
5118 leftWindow->setOwnerInfo(gui::Pid{1}, gui::Uid{101});
5119
5120 sp<FakeWindowHandle> outsideWindow =
5121 sp<FakeWindowHandle>::make(application, mDispatcher, "Outside Window",
5122 ADISPLAY_ID_DEFAULT);
5123 outsideWindow->setFrame(Rect{100, 100, 200, 200});
5124 outsideWindow->setOwnerInfo(gui::Pid{1}, gui::Uid{101});
5125 outsideWindow->setWatchOutsideTouch(true);
5126
5127 std::shared_ptr<FakeApplicationHandle> anotherApplication =
5128 std::make_shared<FakeApplicationHandle>();
5129 sp<FakeWindowHandle> rightWindow =
5130 sp<FakeWindowHandle>::make(anotherApplication, mDispatcher, "Right Window",
5131 ADISPLAY_ID_DEFAULT);
5132 rightWindow->setFrame(Rect{100, 0, 200, 100});
5133 rightWindow->setOwnerInfo(gui::Pid{2}, gui::Uid{202});
5134
5135 // OutsideWindow must be above left window and right window to receive ACTION_OUTSIDE events
5136 // when left window or right window is tapped
5137 mDispatcher->onWindowInfosChanged(
5138 {{*outsideWindow->getInfo(), *leftWindow->getInfo(), *rightWindow->getInfo()},
5139 {},
5140 0,
5141 0});
5142
5143 const DeviceId deviceA = 9;
5144 const DeviceId deviceB = 3;
5145
5146 // Tap on right window use device A
5147 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
5148 .pointer(PointerBuilder(0, ToolType::FINGER).x(150).y(50))
5149 .deviceId(deviceA)
5150 .build());
5151 leftWindow->assertNoEvents();
5152 rightWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(deviceA)));
5153 // Right window is belonged to another owner, so outsideWindow should receive ACTION_OUTSIDE
5154 // with zeroed coords.
5155 outsideWindow->consumeMotionEvent(
5156 AllOf(WithMotionAction(ACTION_OUTSIDE), WithDeviceId(deviceA), WithCoords(0, 0)));
5157
5158 // Tap on left window use device B
5159 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
5160 .pointer(PointerBuilder(0, ToolType::FINGER).x(50).y(50))
5161 .deviceId(deviceB)
5162 .build());
5163 leftWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(deviceB)));
5164 rightWindow->assertNoEvents();
5165 // Because new gesture down on the left window that has the same owner with outside Window, the
5166 // outside Window should receive the ACTION_OUTSIDE with coords.
5167 outsideWindow->consumeMotionEvent(
5168 AllOf(WithMotionAction(ACTION_OUTSIDE), WithDeviceId(deviceB), WithCoords(-50, -50)));
5169
5170 // Ensure that windows that can only accept outside do not receive remaining gestures
5171 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN)
5172 .pointer(PointerBuilder(0, ToolType::FINGER).x(151).y(51))
5173 .deviceId(deviceA)
5174 .build());
5175 leftWindow->assertNoEvents();
5176 rightWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(deviceA)));
5177
5178 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN)
5179 .pointer(PointerBuilder(0, ToolType::FINGER).x(51).y(51))
5180 .deviceId(deviceB)
5181 .build());
5182 leftWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(deviceB)));
5183 rightWindow->assertNoEvents();
5184 outsideWindow->assertNoEvents();
5185}
5186
5187/**
Prabir Pradhanb60b1dc2022-03-15 14:02:35 +00005188 * This test documents the behavior of WATCH_OUTSIDE_TOUCH. The window will get ACTION_OUTSIDE when
5189 * a another pointer causes ACTION_DOWN to be sent to another window for the first time. Only one
5190 * ACTION_OUTSIDE event is sent per gesture.
5191 */
5192TEST_F(InputDispatcherTest, ActionOutsideSentOnlyWhenAWindowIsTouched) {
5193 // There are three windows that do not overlap. `window` wants to WATCH_OUTSIDE_TOUCH.
5194 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07005195 sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher,
5196 "First Window", ADISPLAY_ID_DEFAULT);
Prabir Pradhanb60b1dc2022-03-15 14:02:35 +00005197 window->setWatchOutsideTouch(true);
5198 window->setFrame(Rect{0, 0, 100, 100});
5199 sp<FakeWindowHandle> secondWindow =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07005200 sp<FakeWindowHandle>::make(application, mDispatcher, "Second Window",
5201 ADISPLAY_ID_DEFAULT);
Prabir Pradhanb60b1dc2022-03-15 14:02:35 +00005202 secondWindow->setFrame(Rect{100, 100, 200, 200});
5203 sp<FakeWindowHandle> thirdWindow =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07005204 sp<FakeWindowHandle>::make(application, mDispatcher, "Third Window",
5205 ADISPLAY_ID_DEFAULT);
Prabir Pradhanb60b1dc2022-03-15 14:02:35 +00005206 thirdWindow->setFrame(Rect{200, 200, 300, 300});
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07005207 mDispatcher->onWindowInfosChanged(
5208 {{*window->getInfo(), *secondWindow->getInfo(), *thirdWindow->getInfo()}, {}, 0, 0});
Prabir Pradhanb60b1dc2022-03-15 14:02:35 +00005209
5210 // First pointer lands outside all windows. `window` does not get ACTION_OUTSIDE.
Prabir Pradhan678438e2023-04-13 19:32:51 +00005211 mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_DOWN,
5212 AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
5213 {PointF{-10, -10}}));
Prabir Pradhanb60b1dc2022-03-15 14:02:35 +00005214 window->assertNoEvents();
5215 secondWindow->assertNoEvents();
5216
5217 // The second pointer lands inside `secondWindow`, which should receive a DOWN event.
5218 // Now, `window` should get ACTION_OUTSIDE.
Prabir Pradhan678438e2023-04-13 19:32:51 +00005219 mDispatcher->notifyMotion(generateMotionArgs(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN,
5220 ADISPLAY_ID_DEFAULT,
5221 {PointF{-10, -10}, PointF{105, 105}}));
Siarhei Vishniakou487c49b2022-12-02 15:48:57 -08005222 const std::map<int32_t, PointF> expectedPointers{{0, PointF{-10, -10}}, {1, PointF{105, 105}}};
5223 window->consumeMotionEvent(
5224 AllOf(WithMotionAction(ACTION_OUTSIDE), WithPointers(expectedPointers)));
Prabir Pradhanb60b1dc2022-03-15 14:02:35 +00005225 secondWindow->consumeMotionDown();
5226 thirdWindow->assertNoEvents();
5227
5228 // The third pointer lands inside `thirdWindow`, which should receive a DOWN event. There is
5229 // no ACTION_OUTSIDE sent to `window` because one has already been sent for this gesture.
Prabir Pradhan678438e2023-04-13 19:32:51 +00005230 mDispatcher->notifyMotion(
5231 generateMotionArgs(POINTER_2_DOWN, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
5232 {PointF{-10, -10}, PointF{105, 105}, PointF{205, 205}}));
Prabir Pradhanb60b1dc2022-03-15 14:02:35 +00005233 window->assertNoEvents();
5234 secondWindow->consumeMotionMove();
5235 thirdWindow->consumeMotionDown();
5236}
5237
Prabir Pradhan814fe082022-07-22 20:22:18 +00005238TEST_F(InputDispatcherTest, OnWindowInfosChanged_RemoveAllWindowsOnDisplay) {
5239 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07005240 sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher,
5241 "Fake Window", ADISPLAY_ID_DEFAULT);
Prabir Pradhan814fe082022-07-22 20:22:18 +00005242 window->setFocusable(true);
5243
Patrick Williamsd828f302023-04-28 17:52:08 -05005244 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Prabir Pradhan814fe082022-07-22 20:22:18 +00005245 setFocusedWindow(window);
5246
5247 window->consumeFocusEvent(true);
5248
Prabir Pradhan678438e2023-04-13 19:32:51 +00005249 const NotifyKeyArgs keyDown = generateKeyArgs(AKEY_EVENT_ACTION_DOWN, ADISPLAY_ID_DEFAULT);
5250 const NotifyKeyArgs keyUp = generateKeyArgs(AKEY_EVENT_ACTION_UP, ADISPLAY_ID_DEFAULT);
5251 mDispatcher->notifyKey(keyDown);
5252 mDispatcher->notifyKey(keyUp);
Prabir Pradhan814fe082022-07-22 20:22:18 +00005253
5254 window->consumeKeyDown(ADISPLAY_ID_DEFAULT);
5255 window->consumeKeyUp(ADISPLAY_ID_DEFAULT);
5256
5257 // All windows are removed from the display. Ensure that we can no longer dispatch to it.
Patrick Williamsd828f302023-04-28 17:52:08 -05005258 mDispatcher->onWindowInfosChanged({{}, {}, 0, 0});
Prabir Pradhan814fe082022-07-22 20:22:18 +00005259
5260 window->consumeFocusEvent(false);
5261
Prabir Pradhan678438e2023-04-13 19:32:51 +00005262 mDispatcher->notifyKey(keyDown);
5263 mDispatcher->notifyKey(keyUp);
Prabir Pradhan814fe082022-07-22 20:22:18 +00005264 window->assertNoEvents();
5265}
5266
Arthur Hung96483742022-11-15 03:30:48 +00005267TEST_F(InputDispatcherTest, NonSplitTouchableWindowReceivesMultiTouch) {
5268 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
5269 sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher,
5270 "Fake Window", ADISPLAY_ID_DEFAULT);
5271 // Ensure window is non-split and have some transform.
5272 window->setPreventSplitting(true);
5273 window->setWindowOffset(20, 40);
Patrick Williamsd828f302023-04-28 17:52:08 -05005274 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Arthur Hung96483742022-11-15 03:30:48 +00005275
5276 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07005277 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
Arthur Hung96483742022-11-15 03:30:48 +00005278 {50, 50}))
5279 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
5280 window->consumeMotionDown(ADISPLAY_ID_DEFAULT);
5281
5282 const MotionEvent secondFingerDownEvent =
5283 MotionEventBuilder(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
5284 .displayId(ADISPLAY_ID_DEFAULT)
5285 .eventTime(systemTime(SYSTEM_TIME_MONOTONIC))
Siarhei Vishniakou6d73f832022-07-21 17:27:03 -07005286 .pointer(PointerBuilder(/*id=*/0, ToolType::FINGER).x(50).y(50))
5287 .pointer(PointerBuilder(/*id=*/1, ToolType::FINGER).x(-30).y(-50))
Arthur Hung96483742022-11-15 03:30:48 +00005288 .build();
5289 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07005290 injectMotionEvent(*mDispatcher, secondFingerDownEvent, INJECT_EVENT_TIMEOUT,
Arthur Hung96483742022-11-15 03:30:48 +00005291 InputEventInjectionSync::WAIT_FOR_RESULT))
5292 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
5293
Siarhei Vishniakoud3061ab2023-12-18 20:41:08 -08005294 std::unique_ptr<MotionEvent> event = window->consumeMotionEvent();
5295 ASSERT_NE(nullptr, event);
5296 EXPECT_EQ(POINTER_1_DOWN, event->getAction());
5297 EXPECT_EQ(70, event->getX(0)); // 50 + 20
5298 EXPECT_EQ(90, event->getY(0)); // 50 + 40
5299 EXPECT_EQ(-10, event->getX(1)); // -30 + 20
5300 EXPECT_EQ(-10, event->getY(1)); // -50 + 40
Arthur Hung96483742022-11-15 03:30:48 +00005301}
5302
Siarhei Vishniakou25537f82023-07-18 14:35:47 -07005303/**
5304 * Two windows: a splittable and a non-splittable.
5305 * The non-splittable window shouldn't receive any "incomplete" gestures.
5306 * Send the first pointer to the splittable window, and then touch the non-splittable window.
5307 * The second pointer should be dropped because the initial window is splittable, so it won't get
5308 * any pointers outside of it, and the second window is non-splittable, so it shouldn't get any
5309 * "incomplete" gestures.
5310 */
5311TEST_F(InputDispatcherTest, SplittableAndNonSplittableWindows) {
5312 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
5313 sp<FakeWindowHandle> leftWindow =
5314 sp<FakeWindowHandle>::make(application, mDispatcher, "Left splittable Window",
5315 ADISPLAY_ID_DEFAULT);
5316 leftWindow->setPreventSplitting(false);
5317 leftWindow->setFrame(Rect(0, 0, 100, 100));
5318 sp<FakeWindowHandle> rightWindow =
5319 sp<FakeWindowHandle>::make(application, mDispatcher, "Right non-splittable Window",
5320 ADISPLAY_ID_DEFAULT);
5321 rightWindow->setPreventSplitting(true);
5322 rightWindow->setFrame(Rect(100, 100, 200, 200));
5323 mDispatcher->onWindowInfosChanged(
5324 {{*leftWindow->getInfo(), *rightWindow->getInfo()}, {}, 0, 0});
5325
5326 // Touch down on left, splittable window
5327 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
5328 .pointer(PointerBuilder(0, ToolType::FINGER).x(50).y(50))
5329 .build());
5330 leftWindow->consumeMotionEvent(WithMotionAction(ACTION_DOWN));
5331
5332 mDispatcher->notifyMotion(
5333 MotionArgsBuilder(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
5334 .pointer(PointerBuilder(/*id=*/0, ToolType::FINGER).x(50).y(50))
5335 .pointer(PointerBuilder(/*id=*/1, ToolType::FINGER).x(150).y(150))
5336 .build());
5337 leftWindow->assertNoEvents();
5338 rightWindow->assertNoEvents();
5339}
5340
Harry Cuttsb166c002023-05-09 13:06:05 +00005341TEST_F(InputDispatcherTest, TouchpadThreeFingerSwipeOnlySentToTrustedOverlays) {
5342 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
5343 sp<FakeWindowHandle> window =
5344 sp<FakeWindowHandle>::make(application, mDispatcher, "Window", ADISPLAY_ID_DEFAULT);
5345 window->setFrame(Rect(0, 0, 400, 400));
5346 sp<FakeWindowHandle> trustedOverlay =
5347 sp<FakeWindowHandle>::make(application, mDispatcher, "Trusted Overlay",
5348 ADISPLAY_ID_DEFAULT);
5349 trustedOverlay->setSpy(true);
5350 trustedOverlay->setTrustedOverlay(true);
5351
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07005352 mDispatcher->onWindowInfosChanged({{*trustedOverlay->getInfo(), *window->getInfo()}, {}, 0, 0});
Harry Cuttsb166c002023-05-09 13:06:05 +00005353
5354 // Start a three-finger touchpad swipe
5355 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_MOUSE)
5356 .pointer(PointerBuilder(0, ToolType::FINGER).x(200).y(100))
5357 .classification(MotionClassification::MULTI_FINGER_SWIPE)
5358 .build());
5359 mDispatcher->notifyMotion(MotionArgsBuilder(POINTER_1_DOWN, AINPUT_SOURCE_MOUSE)
5360 .pointer(PointerBuilder(0, ToolType::FINGER).x(200).y(100))
5361 .pointer(PointerBuilder(1, ToolType::FINGER).x(250).y(100))
5362 .classification(MotionClassification::MULTI_FINGER_SWIPE)
5363 .build());
5364 mDispatcher->notifyMotion(MotionArgsBuilder(POINTER_2_DOWN, AINPUT_SOURCE_MOUSE)
5365 .pointer(PointerBuilder(0, ToolType::FINGER).x(200).y(100))
5366 .pointer(PointerBuilder(1, ToolType::FINGER).x(250).y(100))
5367 .pointer(PointerBuilder(2, ToolType::FINGER).x(300).y(100))
5368 .classification(MotionClassification::MULTI_FINGER_SWIPE)
5369 .build());
5370
5371 trustedOverlay->consumeMotionEvent(WithMotionAction(ACTION_DOWN));
5372 trustedOverlay->consumeMotionEvent(WithMotionAction(POINTER_1_DOWN));
5373 trustedOverlay->consumeMotionEvent(WithMotionAction(POINTER_2_DOWN));
5374
5375 // Move the swipe a bit
5376 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_MOUSE)
5377 .pointer(PointerBuilder(0, ToolType::FINGER).x(200).y(105))
5378 .pointer(PointerBuilder(1, ToolType::FINGER).x(250).y(105))
5379 .pointer(PointerBuilder(2, ToolType::FINGER).x(300).y(105))
5380 .classification(MotionClassification::MULTI_FINGER_SWIPE)
5381 .build());
5382
5383 trustedOverlay->consumeMotionEvent(WithMotionAction(ACTION_MOVE));
5384
5385 // End the swipe
5386 mDispatcher->notifyMotion(MotionArgsBuilder(POINTER_2_UP, AINPUT_SOURCE_MOUSE)
5387 .pointer(PointerBuilder(0, ToolType::FINGER).x(200).y(105))
5388 .pointer(PointerBuilder(1, ToolType::FINGER).x(250).y(105))
5389 .pointer(PointerBuilder(2, ToolType::FINGER).x(300).y(105))
5390 .classification(MotionClassification::MULTI_FINGER_SWIPE)
5391 .build());
5392 mDispatcher->notifyMotion(MotionArgsBuilder(POINTER_1_UP, AINPUT_SOURCE_MOUSE)
5393 .pointer(PointerBuilder(0, ToolType::FINGER).x(200).y(105))
5394 .pointer(PointerBuilder(1, ToolType::FINGER).x(250).y(105))
5395 .classification(MotionClassification::MULTI_FINGER_SWIPE)
5396 .build());
5397 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_UP, AINPUT_SOURCE_MOUSE)
5398 .pointer(PointerBuilder(0, ToolType::FINGER).x(200).y(105))
5399 .classification(MotionClassification::MULTI_FINGER_SWIPE)
5400 .build());
5401
5402 trustedOverlay->consumeMotionEvent(WithMotionAction(POINTER_2_UP));
5403 trustedOverlay->consumeMotionEvent(WithMotionAction(POINTER_1_UP));
5404 trustedOverlay->consumeMotionEvent(WithMotionAction(ACTION_UP));
5405
5406 window->assertNoEvents();
5407}
5408
5409TEST_F(InputDispatcherTest, TouchpadThreeFingerSwipeNotSentToSingleWindow) {
5410 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
5411 sp<FakeWindowHandle> window =
5412 sp<FakeWindowHandle>::make(application, mDispatcher, "Window", ADISPLAY_ID_DEFAULT);
5413 window->setFrame(Rect(0, 0, 400, 400));
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07005414 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Harry Cuttsb166c002023-05-09 13:06:05 +00005415
5416 // Start a three-finger touchpad swipe
5417 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_MOUSE)
5418 .pointer(PointerBuilder(0, ToolType::FINGER).x(200).y(100))
5419 .classification(MotionClassification::MULTI_FINGER_SWIPE)
5420 .build());
5421 mDispatcher->notifyMotion(MotionArgsBuilder(POINTER_1_DOWN, AINPUT_SOURCE_MOUSE)
5422 .pointer(PointerBuilder(0, ToolType::FINGER).x(200).y(100))
5423 .pointer(PointerBuilder(1, ToolType::FINGER).x(250).y(100))
5424 .classification(MotionClassification::MULTI_FINGER_SWIPE)
5425 .build());
5426 mDispatcher->notifyMotion(MotionArgsBuilder(POINTER_2_DOWN, AINPUT_SOURCE_MOUSE)
5427 .pointer(PointerBuilder(0, ToolType::FINGER).x(200).y(100))
5428 .pointer(PointerBuilder(1, ToolType::FINGER).x(250).y(100))
5429 .pointer(PointerBuilder(2, ToolType::FINGER).x(300).y(100))
5430 .classification(MotionClassification::MULTI_FINGER_SWIPE)
5431 .build());
5432
5433 // Move the swipe a bit
5434 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_MOUSE)
5435 .pointer(PointerBuilder(0, ToolType::FINGER).x(200).y(105))
5436 .pointer(PointerBuilder(1, ToolType::FINGER).x(250).y(105))
5437 .pointer(PointerBuilder(2, ToolType::FINGER).x(300).y(105))
5438 .classification(MotionClassification::MULTI_FINGER_SWIPE)
5439 .build());
5440
5441 // End the swipe
5442 mDispatcher->notifyMotion(MotionArgsBuilder(POINTER_2_UP, AINPUT_SOURCE_MOUSE)
5443 .pointer(PointerBuilder(0, ToolType::FINGER).x(200).y(105))
5444 .pointer(PointerBuilder(1, ToolType::FINGER).x(250).y(105))
5445 .pointer(PointerBuilder(2, ToolType::FINGER).x(300).y(105))
5446 .classification(MotionClassification::MULTI_FINGER_SWIPE)
5447 .build());
5448 mDispatcher->notifyMotion(MotionArgsBuilder(POINTER_1_UP, AINPUT_SOURCE_MOUSE)
5449 .pointer(PointerBuilder(0, ToolType::FINGER).x(200).y(105))
5450 .pointer(PointerBuilder(1, ToolType::FINGER).x(250).y(105))
5451 .classification(MotionClassification::MULTI_FINGER_SWIPE)
5452 .build());
5453 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_UP, AINPUT_SOURCE_MOUSE)
5454 .pointer(PointerBuilder(0, ToolType::FINGER).x(200).y(105))
5455 .classification(MotionClassification::MULTI_FINGER_SWIPE)
5456 .build());
5457
5458 window->assertNoEvents();
5459}
5460
Prabir Pradhanb60b1dc2022-03-15 14:02:35 +00005461/**
Siarhei Vishniakouadb9fc92023-05-26 10:46:09 -07005462 * Send a two-pointer gesture to a single window. The window's orientation changes in response to
5463 * the first pointer.
Prabir Pradhan69d00bf2023-06-23 19:55:18 +00005464 * Ensure that the second pointer and the subsequent gesture is correctly delivered to the window.
Siarhei Vishniakouadb9fc92023-05-26 10:46:09 -07005465 */
5466TEST_F(InputDispatcherTest, MultiplePointersWithRotatingWindow) {
5467 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
5468 sp<FakeWindowHandle> window =
5469 sp<FakeWindowHandle>::make(application, mDispatcher, "Window", ADISPLAY_ID_DEFAULT);
5470 window->setFrame(Rect(0, 0, 400, 400));
Siarhei Vishniakou700424c2023-07-18 17:18:42 -07005471 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Siarhei Vishniakouadb9fc92023-05-26 10:46:09 -07005472
5473 const nsecs_t baseTime = systemTime(SYSTEM_TIME_MONOTONIC);
5474 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
5475 .downTime(baseTime + 10)
5476 .eventTime(baseTime + 10)
5477 .pointer(PointerBuilder(0, ToolType::FINGER).x(100).y(100))
5478 .build());
5479
5480 window->consumeMotionEvent(WithMotionAction(ACTION_DOWN));
5481
Siarhei Vishniakouadb9fc92023-05-26 10:46:09 -07005482 // Change the transform so that the orientation is now different from original.
Siarhei Vishniakou700424c2023-07-18 17:18:42 -07005483 window->setWindowTransform(0, -1, 1, 0);
Siarhei Vishniakouadb9fc92023-05-26 10:46:09 -07005484
Siarhei Vishniakou700424c2023-07-18 17:18:42 -07005485 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Siarhei Vishniakouadb9fc92023-05-26 10:46:09 -07005486
Siarhei Vishniakouadb9fc92023-05-26 10:46:09 -07005487 mDispatcher->notifyMotion(MotionArgsBuilder(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
5488 .downTime(baseTime + 10)
5489 .eventTime(baseTime + 30)
5490 .pointer(PointerBuilder(0, ToolType::FINGER).x(100).y(100))
5491 .pointer(PointerBuilder(1, ToolType::FINGER).x(200).y(200))
5492 .build());
5493
Prabir Pradhan69d00bf2023-06-23 19:55:18 +00005494 window->consumeMotionEvent(WithMotionAction(POINTER_1_DOWN));
5495
5496 // Finish the gesture and start a new one. Ensure all events are sent to the window.
Siarhei Vishniakouadb9fc92023-05-26 10:46:09 -07005497 mDispatcher->notifyMotion(MotionArgsBuilder(POINTER_1_UP, AINPUT_SOURCE_TOUCHSCREEN)
5498 .downTime(baseTime + 10)
5499 .eventTime(baseTime + 40)
5500 .pointer(PointerBuilder(0, ToolType::FINGER).x(100).y(100))
5501 .pointer(PointerBuilder(1, ToolType::FINGER).x(200).y(200))
5502 .build());
Prabir Pradhan69d00bf2023-06-23 19:55:18 +00005503
5504 window->consumeMotionEvent(WithMotionAction(POINTER_1_UP));
5505
Siarhei Vishniakouadb9fc92023-05-26 10:46:09 -07005506 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN)
5507 .downTime(baseTime + 10)
5508 .eventTime(baseTime + 50)
5509 .pointer(PointerBuilder(0, ToolType::FINGER).x(100).y(100))
5510 .build());
5511
Prabir Pradhan69d00bf2023-06-23 19:55:18 +00005512 window->consumeMotionEvent(WithMotionAction(ACTION_UP));
5513
Siarhei Vishniakouadb9fc92023-05-26 10:46:09 -07005514 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
5515 .downTime(baseTime + 60)
5516 .eventTime(baseTime + 60)
5517 .pointer(PointerBuilder(0, ToolType::FINGER).x(40).y(40))
5518 .build());
5519
Siarhei Vishniakou700424c2023-07-18 17:18:42 -07005520 window->consumeMotionEvent(WithMotionAction(ACTION_DOWN));
Siarhei Vishniakouadb9fc92023-05-26 10:46:09 -07005521}
5522
5523/**
Hu Guo771a7692023-09-17 20:51:08 +08005524 * When there are multiple screens, such as screen projection to TV or screen recording, if the
5525 * cancel event occurs, the coordinates of the cancel event should be sent to the target screen, and
5526 * its coordinates should be converted by the transform of the windows of target screen.
5527 */
5528TEST_F(InputDispatcherTest, WhenMultiDisplayWindowSameToken_DispatchCancelToTargetDisplay) {
5529 // This case will create a window and a spy window on the default display and mirror
5530 // window on the second display. cancel event is sent through spy window pilferPointers
5531 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
5532
5533 sp<FakeWindowHandle> spyWindowDefaultDisplay =
5534 sp<FakeWindowHandle>::make(application, mDispatcher, "Spy", ADISPLAY_ID_DEFAULT);
5535 spyWindowDefaultDisplay->setTrustedOverlay(true);
5536 spyWindowDefaultDisplay->setSpy(true);
5537
5538 sp<FakeWindowHandle> windowDefaultDisplay =
5539 sp<FakeWindowHandle>::make(application, mDispatcher, "DefaultDisplay",
5540 ADISPLAY_ID_DEFAULT);
5541 windowDefaultDisplay->setWindowTransform(1, 0, 0, 1);
5542
5543 sp<FakeWindowHandle> windowSecondDisplay = windowDefaultDisplay->clone(SECOND_DISPLAY_ID);
5544 windowSecondDisplay->setWindowTransform(2, 0, 0, 2);
5545
5546 // Add the windows to the dispatcher
5547 mDispatcher->onWindowInfosChanged(
5548 {{*spyWindowDefaultDisplay->getInfo(), *windowDefaultDisplay->getInfo(),
5549 *windowSecondDisplay->getInfo()},
5550 {},
5551 0,
5552 0});
5553
5554 // Send down to ADISPLAY_ID_DEFAULT
5555 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
5556 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
5557 {100, 100}))
5558 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
5559
5560 spyWindowDefaultDisplay->consumeMotionDown();
5561 windowDefaultDisplay->consumeMotionDown();
5562
5563 EXPECT_EQ(OK, mDispatcher->pilferPointers(spyWindowDefaultDisplay->getToken()));
5564
5565 // windowDefaultDisplay gets cancel
Siarhei Vishniakoud3061ab2023-12-18 20:41:08 -08005566 std::unique_ptr<MotionEvent> event = windowDefaultDisplay->consumeMotionEvent();
5567 ASSERT_NE(nullptr, event);
5568 EXPECT_EQ(AMOTION_EVENT_ACTION_CANCEL, event->getAction());
Hu Guo771a7692023-09-17 20:51:08 +08005569
5570 // The cancel event is sent to windowDefaultDisplay of the ADISPLAY_ID_DEFAULT display, so the
5571 // coordinates of the cancel are converted by windowDefaultDisplay's transform, the x and y
5572 // coordinates are both 100, otherwise if the cancel event is sent to windowSecondDisplay of
5573 // SECOND_DISPLAY_ID, the x and y coordinates are 200
Siarhei Vishniakoud3061ab2023-12-18 20:41:08 -08005574 EXPECT_EQ(100, event->getX(0));
5575 EXPECT_EQ(100, event->getY(0));
Hu Guo771a7692023-09-17 20:51:08 +08005576}
5577
5578/**
Prabir Pradhanc44ce4d2021-10-05 05:26:29 -07005579 * Ensure the correct coordinate spaces are used by InputDispatcher.
5580 *
5581 * InputDispatcher works in the display space, so its coordinate system is relative to the display
5582 * panel. Windows get events in the window space, and get raw coordinates in the logical display
5583 * space.
5584 */
5585class InputDispatcherDisplayProjectionTest : public InputDispatcherTest {
5586public:
5587 void SetUp() override {
5588 InputDispatcherTest::SetUp();
Prabir Pradhan33e3baa2022-12-06 20:30:22 +00005589 removeAllWindowsAndDisplays();
Prabir Pradhanc44ce4d2021-10-05 05:26:29 -07005590 }
5591
5592 void addDisplayInfo(int displayId, const ui::Transform& transform) {
5593 gui::DisplayInfo info;
5594 info.displayId = displayId;
5595 info.transform = transform;
5596 mDisplayInfos.push_back(std::move(info));
Patrick Williamsd828f302023-04-28 17:52:08 -05005597 mDispatcher->onWindowInfosChanged({mWindowInfos, mDisplayInfos, 0, 0});
Prabir Pradhanc44ce4d2021-10-05 05:26:29 -07005598 }
5599
5600 void addWindow(const sp<WindowInfoHandle>& windowHandle) {
5601 mWindowInfos.push_back(*windowHandle->getInfo());
Patrick Williamsd828f302023-04-28 17:52:08 -05005602 mDispatcher->onWindowInfosChanged({mWindowInfos, mDisplayInfos, 0, 0});
Prabir Pradhanc44ce4d2021-10-05 05:26:29 -07005603 }
5604
Prabir Pradhan33e3baa2022-12-06 20:30:22 +00005605 void removeAllWindowsAndDisplays() {
5606 mDisplayInfos.clear();
5607 mWindowInfos.clear();
5608 }
5609
Prabir Pradhanc44ce4d2021-10-05 05:26:29 -07005610 // Set up a test scenario where the display has a scaled projection and there are two windows
5611 // on the display.
5612 std::pair<sp<FakeWindowHandle>, sp<FakeWindowHandle>> setupScaledDisplayScenario() {
5613 // The display has a projection that has a scale factor of 2 and 4 in the x and y directions
5614 // respectively.
5615 ui::Transform displayTransform;
5616 displayTransform.set(2, 0, 0, 4);
5617 addDisplayInfo(ADISPLAY_ID_DEFAULT, displayTransform);
5618
5619 std::shared_ptr<FakeApplicationHandle> application =
5620 std::make_shared<FakeApplicationHandle>();
5621
5622 // Add two windows to the display. Their frames are represented in the display space.
5623 sp<FakeWindowHandle> firstWindow =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07005624 sp<FakeWindowHandle>::make(application, mDispatcher, "First Window",
5625 ADISPLAY_ID_DEFAULT);
Prabir Pradhanc44ce4d2021-10-05 05:26:29 -07005626 firstWindow->setFrame(Rect(0, 0, 100, 200), displayTransform);
5627 addWindow(firstWindow);
5628
5629 sp<FakeWindowHandle> secondWindow =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07005630 sp<FakeWindowHandle>::make(application, mDispatcher, "Second Window",
5631 ADISPLAY_ID_DEFAULT);
Prabir Pradhanc44ce4d2021-10-05 05:26:29 -07005632 secondWindow->setFrame(Rect(100, 200, 200, 400), displayTransform);
5633 addWindow(secondWindow);
5634 return {std::move(firstWindow), std::move(secondWindow)};
5635 }
5636
5637private:
5638 std::vector<gui::DisplayInfo> mDisplayInfos;
5639 std::vector<gui::WindowInfo> mWindowInfos;
5640};
5641
Prabir Pradhan33e3baa2022-12-06 20:30:22 +00005642TEST_F(InputDispatcherDisplayProjectionTest, HitTestCoordinateSpaceConsistency) {
Prabir Pradhanc44ce4d2021-10-05 05:26:29 -07005643 auto [firstWindow, secondWindow] = setupScaledDisplayScenario();
5644 // Send down to the first window. The point is represented in the display space. The point is
Prabir Pradhan33e3baa2022-12-06 20:30:22 +00005645 // selected so that if the hit test was performed with the point and the bounds being in
5646 // different coordinate spaces, the event would end up in the incorrect window.
Prabir Pradhan678438e2023-04-13 19:32:51 +00005647 mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_DOWN,
5648 AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
5649 {PointF{75, 55}}));
Prabir Pradhanc44ce4d2021-10-05 05:26:29 -07005650
5651 firstWindow->consumeMotionDown();
5652 secondWindow->assertNoEvents();
5653}
5654
5655// Ensure that when a MotionEvent is injected through the InputDispatcher::injectInputEvent() API,
5656// the event should be treated as being in the logical display space.
5657TEST_F(InputDispatcherDisplayProjectionTest, InjectionInLogicalDisplaySpace) {
5658 auto [firstWindow, secondWindow] = setupScaledDisplayScenario();
5659 // Send down to the first window. The point is represented in the logical display space. The
5660 // point is selected so that if the hit test was done in logical display space, then it would
5661 // end up in the incorrect window.
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07005662 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
Prabir Pradhanc44ce4d2021-10-05 05:26:29 -07005663 PointF{75 * 2, 55 * 4});
5664
5665 firstWindow->consumeMotionDown();
5666 secondWindow->assertNoEvents();
5667}
5668
Prabir Pradhandaa2f142021-12-10 09:30:08 +00005669// Ensure that when a MotionEvent that has a custom transform is injected, the post-transformed
5670// event should be treated as being in the logical display space.
5671TEST_F(InputDispatcherDisplayProjectionTest, InjectionWithTransformInLogicalDisplaySpace) {
5672 auto [firstWindow, secondWindow] = setupScaledDisplayScenario();
5673
5674 const std::array<float, 9> matrix = {1.1, 2.2, 3.3, 4.4, 5.5, 6.6, 0.0, 0.0, 1.0};
5675 ui::Transform injectedEventTransform;
5676 injectedEventTransform.set(matrix);
5677 const vec2 expectedPoint{75, 55}; // The injected point in the logical display space.
5678 const vec2 untransformedPoint = injectedEventTransform.inverse().transform(expectedPoint);
5679
5680 MotionEvent event = MotionEventBuilder(AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
5681 .displayId(ADISPLAY_ID_DEFAULT)
5682 .eventTime(systemTime(SYSTEM_TIME_MONOTONIC))
Siarhei Vishniakou6d73f832022-07-21 17:27:03 -07005683 .pointer(PointerBuilder(/*id=*/0, ToolType::FINGER)
Prabir Pradhandaa2f142021-12-10 09:30:08 +00005684 .x(untransformedPoint.x)
5685 .y(untransformedPoint.y))
5686 .build();
5687 event.transform(matrix);
5688
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07005689 injectMotionEvent(*mDispatcher, event, INJECT_EVENT_TIMEOUT,
Prabir Pradhandaa2f142021-12-10 09:30:08 +00005690 InputEventInjectionSync::WAIT_FOR_RESULT);
5691
5692 firstWindow->consumeMotionDown();
5693 secondWindow->assertNoEvents();
5694}
5695
Prabir Pradhanc44ce4d2021-10-05 05:26:29 -07005696TEST_F(InputDispatcherDisplayProjectionTest, WindowGetsEventsInCorrectCoordinateSpace) {
5697 auto [firstWindow, secondWindow] = setupScaledDisplayScenario();
5698
5699 // Send down to the second window.
Prabir Pradhan678438e2023-04-13 19:32:51 +00005700 mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_DOWN,
5701 AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
5702 {PointF{150, 220}}));
Prabir Pradhanc44ce4d2021-10-05 05:26:29 -07005703
5704 firstWindow->assertNoEvents();
Siarhei Vishniakoud3061ab2023-12-18 20:41:08 -08005705 std::unique_ptr<MotionEvent> event = secondWindow->consumeMotionEvent();
5706 ASSERT_NE(nullptr, event);
5707 EXPECT_EQ(AMOTION_EVENT_ACTION_DOWN, event->getAction());
Prabir Pradhanc44ce4d2021-10-05 05:26:29 -07005708
5709 // Ensure that the events from the "getRaw" API are in logical display coordinates.
Siarhei Vishniakoud3061ab2023-12-18 20:41:08 -08005710 EXPECT_EQ(300, event->getRawX(0));
5711 EXPECT_EQ(880, event->getRawY(0));
Prabir Pradhanc44ce4d2021-10-05 05:26:29 -07005712
5713 // Ensure that the x and y values are in the window's coordinate space.
5714 // The left-top of the second window is at (100, 200) in display space, which is (200, 800) in
5715 // the logical display space. This will be the origin of the window space.
Siarhei Vishniakoud3061ab2023-12-18 20:41:08 -08005716 EXPECT_EQ(100, event->getX(0));
5717 EXPECT_EQ(80, event->getY(0));
Prabir Pradhanc44ce4d2021-10-05 05:26:29 -07005718}
5719
Prabir Pradhan112b1ad2023-09-21 09:53:53 +00005720TEST_F(InputDispatcherDisplayProjectionTest, CancelMotionWithCorrectCoordinates) {
5721 auto [firstWindow, secondWindow] = setupScaledDisplayScenario();
5722 // The monitor will always receive events in the logical display's coordinate space, because
5723 // it does not have a window.
Prabir Pradhanfb549072023-10-05 19:17:36 +00005724 FakeMonitorReceiver monitor{*mDispatcher, "Monitor", ADISPLAY_ID_DEFAULT};
Prabir Pradhan112b1ad2023-09-21 09:53:53 +00005725
5726 // Send down to the first window.
5727 mDispatcher->notifyMotion(generateMotionArgs(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN,
5728 ADISPLAY_ID_DEFAULT, {PointF{50, 100}}));
5729 firstWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithCoords(100, 400)));
5730 monitor.consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithCoords(100, 400)));
5731
5732 // Second pointer goes down on second window.
5733 mDispatcher->notifyMotion(generateMotionArgs(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN,
5734 ADISPLAY_ID_DEFAULT,
5735 {PointF{50, 100}, PointF{150, 220}}));
5736 secondWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithCoords(100, 80)));
5737 const std::map<int32_t, PointF> expectedMonitorPointers{{0, PointF{100, 400}},
5738 {1, PointF{300, 880}}};
5739 monitor.consumeMotionEvent(
5740 AllOf(WithMotionAction(POINTER_1_DOWN), WithPointers(expectedMonitorPointers)));
5741
5742 mDispatcher->cancelCurrentTouch();
5743
5744 firstWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_CANCEL), WithCoords(100, 400)));
5745 secondWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_CANCEL), WithCoords(100, 80)));
5746 monitor.consumeMotionEvent(
5747 AllOf(WithMotionAction(ACTION_CANCEL), WithPointers(expectedMonitorPointers)));
5748}
5749
Prabir Pradhan1c29a092023-09-21 10:29:29 +00005750TEST_F(InputDispatcherDisplayProjectionTest, SynthesizeDownWithCorrectCoordinates) {
5751 auto [firstWindow, secondWindow] = setupScaledDisplayScenario();
5752
5753 // Send down to the first window.
5754 mDispatcher->notifyMotion(generateMotionArgs(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN,
5755 ADISPLAY_ID_DEFAULT, {PointF{50, 100}}));
5756 firstWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithCoords(100, 400)));
5757
5758 // The pointer is transferred to the second window, and the second window receives it in the
5759 // correct coordinate space.
Prabir Pradhan367f3432024-02-13 23:05:58 +00005760 mDispatcher->transferTouchGesture(firstWindow->getToken(), secondWindow->getToken());
Prabir Pradhan1c29a092023-09-21 10:29:29 +00005761 firstWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_CANCEL), WithCoords(100, 400)));
5762 secondWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithCoords(-100, -400)));
5763}
5764
Prabir Pradhan0dfcac72023-10-05 20:04:21 +00005765TEST_F(InputDispatcherDisplayProjectionTest, SynthesizeHoverEnterExitWithCorrectCoordinates) {
5766 auto [firstWindow, secondWindow] = setupScaledDisplayScenario();
5767
5768 // Send hover move to the second window, and ensure it shows up as hover enter.
5769 mDispatcher->notifyMotion(generateMotionArgs(ACTION_HOVER_MOVE, AINPUT_SOURCE_STYLUS,
5770 ADISPLAY_ID_DEFAULT, {PointF{150, 220}}));
5771 secondWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_HOVER_ENTER),
5772 WithCoords(100, 80), WithRawCoords(300, 880)));
5773
5774 // Touch down at the same location and ensure a hover exit is synthesized.
5775 mDispatcher->notifyMotion(generateMotionArgs(ACTION_DOWN, AINPUT_SOURCE_STYLUS,
5776 ADISPLAY_ID_DEFAULT, {PointF{150, 220}}));
5777 secondWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_HOVER_EXIT), WithCoords(100, 80),
5778 WithRawCoords(300, 880)));
5779 secondWindow->consumeMotionEvent(
5780 AllOf(WithMotionAction(ACTION_DOWN), WithCoords(100, 80), WithRawCoords(300, 880)));
5781 secondWindow->assertNoEvents();
5782 firstWindow->assertNoEvents();
5783}
5784
Prabir Pradhan453ae732023-10-13 14:30:14 +00005785// Same as above, but while the window is being mirrored.
5786TEST_F(InputDispatcherDisplayProjectionTest,
5787 SynthesizeHoverEnterExitWithCorrectCoordinatesWhenMirrored) {
5788 auto [firstWindow, secondWindow] = setupScaledDisplayScenario();
5789
5790 const std::array<float, 9> matrix = {1.1, 2.2, 3.3, 4.4, 5.5, 6.6, 0.0, 0.0, 1.0};
5791 ui::Transform secondDisplayTransform;
5792 secondDisplayTransform.set(matrix);
5793 addDisplayInfo(SECOND_DISPLAY_ID, secondDisplayTransform);
5794
5795 sp<FakeWindowHandle> secondWindowClone = secondWindow->clone(SECOND_DISPLAY_ID);
5796 secondWindowClone->setWindowTransform(1.1, 2.2, 3.3, 4.4);
5797 addWindow(secondWindowClone);
5798
5799 // Send hover move to the second window, and ensure it shows up as hover enter.
5800 mDispatcher->notifyMotion(generateMotionArgs(ACTION_HOVER_MOVE, AINPUT_SOURCE_STYLUS,
5801 ADISPLAY_ID_DEFAULT, {PointF{150, 220}}));
5802 secondWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_HOVER_ENTER),
5803 WithCoords(100, 80), WithRawCoords(300, 880)));
5804
5805 // Touch down at the same location and ensure a hover exit is synthesized for the correct
5806 // display.
5807 mDispatcher->notifyMotion(generateMotionArgs(ACTION_DOWN, AINPUT_SOURCE_STYLUS,
5808 ADISPLAY_ID_DEFAULT, {PointF{150, 220}}));
5809 secondWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_HOVER_EXIT), WithCoords(100, 80),
5810 WithRawCoords(300, 880)));
5811 secondWindow->consumeMotionEvent(
5812 AllOf(WithMotionAction(ACTION_DOWN), WithCoords(100, 80), WithRawCoords(300, 880)));
5813 secondWindow->assertNoEvents();
5814 firstWindow->assertNoEvents();
5815}
5816
Prabir Pradhan0dfcac72023-10-05 20:04:21 +00005817TEST_F(InputDispatcherDisplayProjectionTest, SynthesizeHoverCancelationWithCorrectCoordinates) {
5818 auto [firstWindow, secondWindow] = setupScaledDisplayScenario();
5819
5820 // Send hover enter to second window
5821 mDispatcher->notifyMotion(generateMotionArgs(ACTION_HOVER_ENTER, AINPUT_SOURCE_STYLUS,
5822 ADISPLAY_ID_DEFAULT, {PointF{150, 220}}));
5823 secondWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_HOVER_ENTER),
5824 WithCoords(100, 80), WithRawCoords(300, 880)));
5825
5826 mDispatcher->cancelCurrentTouch();
5827
5828 secondWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_HOVER_EXIT), WithCoords(100, 80),
5829 WithRawCoords(300, 880)));
5830 secondWindow->assertNoEvents();
5831 firstWindow->assertNoEvents();
5832}
5833
Prabir Pradhan453ae732023-10-13 14:30:14 +00005834// Same as above, but while the window is being mirrored.
Prabir Pradhan16463382023-10-12 23:03:19 +00005835TEST_F(InputDispatcherDisplayProjectionTest,
5836 SynthesizeHoverCancelationWithCorrectCoordinatesWhenMirrored) {
5837 auto [firstWindow, secondWindow] = setupScaledDisplayScenario();
5838
5839 const std::array<float, 9> matrix = {1.1, 2.2, 3.3, 4.4, 5.5, 6.6, 0.0, 0.0, 1.0};
5840 ui::Transform secondDisplayTransform;
5841 secondDisplayTransform.set(matrix);
5842 addDisplayInfo(SECOND_DISPLAY_ID, secondDisplayTransform);
5843
5844 sp<FakeWindowHandle> secondWindowClone = secondWindow->clone(SECOND_DISPLAY_ID);
5845 secondWindowClone->setWindowTransform(1.1, 2.2, 3.3, 4.4);
5846 addWindow(secondWindowClone);
5847
5848 // Send hover enter to second window
5849 mDispatcher->notifyMotion(generateMotionArgs(ACTION_HOVER_ENTER, AINPUT_SOURCE_STYLUS,
5850 ADISPLAY_ID_DEFAULT, {PointF{150, 220}}));
5851 secondWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_HOVER_ENTER),
5852 WithCoords(100, 80), WithRawCoords(300, 880),
5853 WithDisplayId(ADISPLAY_ID_DEFAULT)));
5854
5855 mDispatcher->cancelCurrentTouch();
5856
5857 // Ensure the cancelation happens with the correct displayId and the correct coordinates.
5858 secondWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_HOVER_EXIT), WithCoords(100, 80),
5859 WithRawCoords(300, 880),
5860 WithDisplayId(ADISPLAY_ID_DEFAULT)));
5861 secondWindow->assertNoEvents();
5862 firstWindow->assertNoEvents();
5863}
5864
Prabir Pradhan33e3baa2022-12-06 20:30:22 +00005865/** Ensure consistent behavior of InputDispatcher in all orientations. */
5866class InputDispatcherDisplayOrientationFixture
5867 : public InputDispatcherDisplayProjectionTest,
5868 public ::testing::WithParamInterface<ui::Rotation> {};
5869
5870// This test verifies the touchable region of a window for all rotations of the display by tapping
5871// in different locations on the display, specifically points close to the four corners of a
5872// window.
5873TEST_P(InputDispatcherDisplayOrientationFixture, HitTestInDifferentOrientations) {
5874 constexpr static int32_t displayWidth = 400;
5875 constexpr static int32_t displayHeight = 800;
5876
5877 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
5878
5879 const auto rotation = GetParam();
5880
5881 // Set up the display with the specified rotation.
5882 const bool isRotated = rotation == ui::ROTATION_90 || rotation == ui::ROTATION_270;
5883 const int32_t logicalDisplayWidth = isRotated ? displayHeight : displayWidth;
5884 const int32_t logicalDisplayHeight = isRotated ? displayWidth : displayHeight;
5885 const ui::Transform displayTransform(ui::Transform::toRotationFlags(rotation),
5886 logicalDisplayWidth, logicalDisplayHeight);
5887 addDisplayInfo(ADISPLAY_ID_DEFAULT, displayTransform);
5888
5889 // Create a window with its bounds determined in the logical display.
5890 const Rect frameInLogicalDisplay(100, 100, 200, 300);
5891 const Rect frameInDisplay = displayTransform.inverse().transform(frameInLogicalDisplay);
5892 sp<FakeWindowHandle> window =
5893 sp<FakeWindowHandle>::make(application, mDispatcher, "Window", ADISPLAY_ID_DEFAULT);
5894 window->setFrame(frameInDisplay, displayTransform);
5895 addWindow(window);
5896
5897 // The following points in logical display space should be inside the window.
5898 static const std::array<vec2, 4> insidePoints{
5899 {{100, 100}, {199.99, 100}, {100, 299.99}, {199.99, 299.99}}};
5900 for (const auto pointInsideWindow : insidePoints) {
5901 const vec2 p = displayTransform.inverse().transform(pointInsideWindow);
5902 const PointF pointInDisplaySpace{p.x, p.y};
Prabir Pradhan678438e2023-04-13 19:32:51 +00005903 mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_DOWN,
5904 AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
5905 {pointInDisplaySpace}));
Prabir Pradhan33e3baa2022-12-06 20:30:22 +00005906 window->consumeMotionDown();
5907
Prabir Pradhan678438e2023-04-13 19:32:51 +00005908 mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_UP,
5909 AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
5910 {pointInDisplaySpace}));
Prabir Pradhan33e3baa2022-12-06 20:30:22 +00005911 window->consumeMotionUp();
5912 }
5913
5914 // The following points in logical display space should be outside the window.
5915 static const std::array<vec2, 5> outsidePoints{
5916 {{200, 100}, {100, 300}, {200, 300}, {100, 99.99}, {99.99, 100}}};
5917 for (const auto pointOutsideWindow : outsidePoints) {
5918 const vec2 p = displayTransform.inverse().transform(pointOutsideWindow);
5919 const PointF pointInDisplaySpace{p.x, p.y};
Prabir Pradhan678438e2023-04-13 19:32:51 +00005920 mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_DOWN,
5921 AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
5922 {pointInDisplaySpace}));
Prabir Pradhan33e3baa2022-12-06 20:30:22 +00005923
Prabir Pradhan678438e2023-04-13 19:32:51 +00005924 mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_UP,
5925 AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
5926 {pointInDisplaySpace}));
Prabir Pradhan33e3baa2022-12-06 20:30:22 +00005927 }
5928 window->assertNoEvents();
5929}
5930
Linnan Li5e5645e2024-03-05 14:43:05 +00005931// This test verifies the occlusion detection for all rotations of the display by tapping
5932// in different locations on the display, specifically points close to the four corners of a
5933// window.
5934TEST_P(InputDispatcherDisplayOrientationFixture, BlockUntrustClickInDifferentOrientations) {
5935 constexpr static int32_t displayWidth = 400;
5936 constexpr static int32_t displayHeight = 800;
5937
5938 std::shared_ptr<FakeApplicationHandle> untrustedWindowApplication =
5939 std::make_shared<FakeApplicationHandle>();
5940 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
5941
5942 const auto rotation = GetParam();
5943
5944 // Set up the display with the specified rotation.
5945 const bool isRotated = rotation == ui::ROTATION_90 || rotation == ui::ROTATION_270;
5946 const int32_t logicalDisplayWidth = isRotated ? displayHeight : displayWidth;
5947 const int32_t logicalDisplayHeight = isRotated ? displayWidth : displayHeight;
5948 const ui::Transform displayTransform(ui::Transform::toRotationFlags(rotation),
5949 logicalDisplayWidth, logicalDisplayHeight);
5950 addDisplayInfo(ADISPLAY_ID_DEFAULT, displayTransform);
5951
5952 // Create a window that not trusted.
5953 const Rect untrustedWindowFrameInLogicalDisplay(100, 100, 200, 300);
5954
5955 const Rect untrustedWindowFrameInDisplay =
5956 displayTransform.inverse().transform(untrustedWindowFrameInLogicalDisplay);
5957
5958 sp<FakeWindowHandle> untrustedWindow =
5959 sp<FakeWindowHandle>::make(untrustedWindowApplication, mDispatcher, "UntrustedWindow",
5960 ADISPLAY_ID_DEFAULT);
5961 untrustedWindow->setFrame(untrustedWindowFrameInDisplay, displayTransform);
5962 untrustedWindow->setTrustedOverlay(false);
5963 untrustedWindow->setTouchOcclusionMode(TouchOcclusionMode::BLOCK_UNTRUSTED);
5964 untrustedWindow->setTouchable(false);
5965 untrustedWindow->setAlpha(1.0f);
5966 untrustedWindow->setOwnerInfo(gui::Pid{1}, gui::Uid{101});
5967 addWindow(untrustedWindow);
5968
5969 // Create a simple app window below the untrusted window.
5970 const Rect simpleAppWindowFrameInLogicalDisplay(0, 0, 300, 600);
5971 const Rect simpleAppWindowFrameInDisplay =
5972 displayTransform.inverse().transform(simpleAppWindowFrameInLogicalDisplay);
5973
5974 sp<FakeWindowHandle> simpleAppWindow =
5975 sp<FakeWindowHandle>::make(application, mDispatcher, "SimpleAppWindow",
5976 ADISPLAY_ID_DEFAULT);
5977 simpleAppWindow->setFrame(simpleAppWindowFrameInDisplay, displayTransform);
5978 simpleAppWindow->setOwnerInfo(gui::Pid{2}, gui::Uid{202});
5979 addWindow(simpleAppWindow);
5980
5981 // The following points in logical display space should be inside the untrusted window, so
5982 // the simple window could not receive events that coordinate is these point.
5983 static const std::array<vec2, 4> untrustedPoints{
5984 {{100, 100}, {199.99, 100}, {100, 299.99}, {199.99, 299.99}}};
5985
5986 for (const auto untrustedPoint : untrustedPoints) {
5987 const vec2 p = displayTransform.inverse().transform(untrustedPoint);
5988 const PointF pointInDisplaySpace{p.x, p.y};
5989 mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_DOWN,
5990 AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
5991 {pointInDisplaySpace}));
5992 mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_UP,
5993 AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
5994 {pointInDisplaySpace}));
5995 }
5996 untrustedWindow->assertNoEvents();
5997 simpleAppWindow->assertNoEvents();
5998 // The following points in logical display space should be outside the untrusted window, so
5999 // the simple window should receive events that coordinate is these point.
6000 static const std::array<vec2, 5> trustedPoints{
6001 {{200, 100}, {100, 300}, {200, 300}, {100, 99.99}, {99.99, 100}}};
6002 for (const auto trustedPoint : trustedPoints) {
6003 const vec2 p = displayTransform.inverse().transform(trustedPoint);
6004 const PointF pointInDisplaySpace{p.x, p.y};
6005 mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_DOWN,
6006 AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
6007 {pointInDisplaySpace}));
6008 simpleAppWindow->consumeMotionDown(ADISPLAY_ID_DEFAULT,
6009 AMOTION_EVENT_FLAG_WINDOW_IS_PARTIALLY_OBSCURED);
6010 mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_UP,
6011 AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
6012 {pointInDisplaySpace}));
6013 simpleAppWindow->consumeMotionUp(ADISPLAY_ID_DEFAULT,
6014 AMOTION_EVENT_FLAG_WINDOW_IS_PARTIALLY_OBSCURED);
6015 }
6016 untrustedWindow->assertNoEvents();
6017}
6018
Prabir Pradhan33e3baa2022-12-06 20:30:22 +00006019// Run the precision tests for all rotations.
6020INSTANTIATE_TEST_SUITE_P(InputDispatcherDisplayOrientationTests,
6021 InputDispatcherDisplayOrientationFixture,
6022 ::testing::Values(ui::ROTATION_0, ui::ROTATION_90, ui::ROTATION_180,
6023 ui::ROTATION_270),
6024 [](const testing::TestParamInfo<ui::Rotation>& testParamInfo) {
6025 return ftl::enum_string(testParamInfo.param);
6026 });
6027
Siarhei Vishniakou18050092021-09-01 13:32:49 -07006028using TransferFunction = std::function<bool(const std::unique_ptr<InputDispatcher>& dispatcher,
6029 sp<IBinder>, sp<IBinder>)>;
Siarhei Vishniakoud0c6bc82021-03-13 03:14:52 +00006030
6031class TransferTouchFixture : public InputDispatcherTest,
6032 public ::testing::WithParamInterface<TransferFunction> {};
6033
6034TEST_P(TransferTouchFixture, TransferTouch_OnePointer) {
Chris Yea209fde2020-07-22 13:54:51 -07006035 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
Svet Ganov5d3bc372020-01-26 23:11:07 -08006036
6037 // Create a couple of windows
Siarhei Vishniakou870ecec2020-12-09 08:07:46 -10006038 sp<FakeWindowHandle> firstWindow =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07006039 sp<FakeWindowHandle>::make(application, mDispatcher, "First Window",
6040 ADISPLAY_ID_DEFAULT);
Arthur Hungc539dbb2022-12-08 07:45:36 +00006041 firstWindow->setDupTouchToWallpaper(true);
Siarhei Vishniakou870ecec2020-12-09 08:07:46 -10006042 sp<FakeWindowHandle> secondWindow =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07006043 sp<FakeWindowHandle>::make(application, mDispatcher, "Second Window",
6044 ADISPLAY_ID_DEFAULT);
Arthur Hungc539dbb2022-12-08 07:45:36 +00006045 sp<FakeWindowHandle> wallpaper =
6046 sp<FakeWindowHandle>::make(application, mDispatcher, "Wallpaper", ADISPLAY_ID_DEFAULT);
6047 wallpaper->setIsWallpaper(true);
Prabir Pradhan65455c72024-02-13 21:46:41 +00006048 // Add the windows to the dispatcher, and ensure the first window is focused
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07006049 mDispatcher->onWindowInfosChanged(
6050 {{*firstWindow->getInfo(), *secondWindow->getInfo(), *wallpaper->getInfo()}, {}, 0, 0});
Prabir Pradhan65455c72024-02-13 21:46:41 +00006051 setFocusedWindow(firstWindow);
6052 firstWindow->consumeFocusEvent(true);
Svet Ganov5d3bc372020-01-26 23:11:07 -08006053
6054 // Send down to the first window
Prabir Pradhan678438e2023-04-13 19:32:51 +00006055 mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_DOWN,
6056 AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT));
Arthur Hungc539dbb2022-12-08 07:45:36 +00006057
Svet Ganov5d3bc372020-01-26 23:11:07 -08006058 // Only the first window should get the down event
6059 firstWindow->consumeMotionDown();
6060 secondWindow->assertNoEvents();
Linnan Li72352222024-04-12 18:55:57 +08006061 wallpaper->consumeMotionDown(ADISPLAY_ID_DEFAULT, EXPECTED_WALLPAPER_FLAGS);
Prabir Pradhan65455c72024-02-13 21:46:41 +00006062 // Dispatcher reports pointer down outside focus for the wallpaper
6063 mFakePolicy->assertOnPointerDownEquals(wallpaper->getToken());
Svet Ganov5d3bc372020-01-26 23:11:07 -08006064
Siarhei Vishniakoud0c6bc82021-03-13 03:14:52 +00006065 // Transfer touch to the second window
6066 TransferFunction f = GetParam();
6067 const bool success = f(mDispatcher, firstWindow->getToken(), secondWindow->getToken());
6068 ASSERT_TRUE(success);
Svet Ganov5d3bc372020-01-26 23:11:07 -08006069 // The first window gets cancel and the second gets down
6070 firstWindow->consumeMotionCancel();
Prabir Pradhan65455c72024-02-13 21:46:41 +00006071 secondWindow->consumeMotionDown(ADISPLAY_ID_DEFAULT, AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
Linnan Li72352222024-04-12 18:55:57 +08006072 wallpaper->consumeMotionCancel(ADISPLAY_ID_DEFAULT, EXPECTED_WALLPAPER_FLAGS);
Prabir Pradhan65455c72024-02-13 21:46:41 +00006073 // There should not be any changes to the focused window when transferring touch
6074 ASSERT_NO_FATAL_FAILURE(mFakePolicy->assertOnPointerDownWasNotCalled());
Svet Ganov5d3bc372020-01-26 23:11:07 -08006075
6076 // Send up event to the second window
Prabir Pradhan678438e2023-04-13 19:32:51 +00006077 mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN,
6078 ADISPLAY_ID_DEFAULT));
Prabir Pradhan65455c72024-02-13 21:46:41 +00006079 // The first window gets no events and the second gets up
Svet Ganov5d3bc372020-01-26 23:11:07 -08006080 firstWindow->assertNoEvents();
Prabir Pradhan65455c72024-02-13 21:46:41 +00006081 secondWindow->consumeMotionUp(ADISPLAY_ID_DEFAULT, AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
Arthur Hungc539dbb2022-12-08 07:45:36 +00006082 wallpaper->assertNoEvents();
Svet Ganov5d3bc372020-01-26 23:11:07 -08006083}
6084
Siarhei Vishniakou7ae7afd2022-03-31 15:26:13 -07006085/**
Prabir Pradhan367f3432024-02-13 23:05:58 +00006086 * When 'transferTouchGesture' API is invoked, dispatcher needs to find the "best" window to take
6087 * touch from. When we have spy windows, there are several windows to choose from: either spy, or
6088 * the 'real' (non-spy) window. Always prefer the 'real' window because that's what would be most
Siarhei Vishniakou7ae7afd2022-03-31 15:26:13 -07006089 * natural to the user.
6090 * In this test, we are sending a pointer to both spy window and first window. We then try to
6091 * transfer touch to the second window. The dispatcher should identify the first window as the
6092 * one that should lose the gesture, and therefore the action should be to move the gesture from
6093 * the first window to the second.
Prabir Pradhan367f3432024-02-13 23:05:58 +00006094 * The main goal here is to test the behaviour of 'transferTouchGesture' API, but it's still valid
6095 * to test the other API, as well.
Siarhei Vishniakou7ae7afd2022-03-31 15:26:13 -07006096 */
6097TEST_P(TransferTouchFixture, TransferTouch_MultipleWindowsWithSpy) {
6098 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
6099
6100 // Create a couple of windows + a spy window
6101 sp<FakeWindowHandle> spyWindow =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07006102 sp<FakeWindowHandle>::make(application, mDispatcher, "Spy", ADISPLAY_ID_DEFAULT);
Siarhei Vishniakou7ae7afd2022-03-31 15:26:13 -07006103 spyWindow->setTrustedOverlay(true);
6104 spyWindow->setSpy(true);
6105 sp<FakeWindowHandle> firstWindow =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07006106 sp<FakeWindowHandle>::make(application, mDispatcher, "First", ADISPLAY_ID_DEFAULT);
Siarhei Vishniakou7ae7afd2022-03-31 15:26:13 -07006107 sp<FakeWindowHandle> secondWindow =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07006108 sp<FakeWindowHandle>::make(application, mDispatcher, "Second", ADISPLAY_ID_DEFAULT);
Siarhei Vishniakou7ae7afd2022-03-31 15:26:13 -07006109
6110 // Add the windows to the dispatcher
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07006111 mDispatcher->onWindowInfosChanged(
6112 {{*spyWindow->getInfo(), *firstWindow->getInfo(), *secondWindow->getInfo()}, {}, 0, 0});
Siarhei Vishniakou7ae7afd2022-03-31 15:26:13 -07006113
6114 // Send down to the first window
Prabir Pradhan678438e2023-04-13 19:32:51 +00006115 mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_DOWN,
6116 AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT));
Siarhei Vishniakou7ae7afd2022-03-31 15:26:13 -07006117 // Only the first window and spy should get the down event
6118 spyWindow->consumeMotionDown();
6119 firstWindow->consumeMotionDown();
6120
6121 // Transfer touch to the second window. Non-spy window should be preferred over the spy window
Prabir Pradhan367f3432024-02-13 23:05:58 +00006122 // if f === 'transferTouchGesture'.
Siarhei Vishniakou7ae7afd2022-03-31 15:26:13 -07006123 TransferFunction f = GetParam();
6124 const bool success = f(mDispatcher, firstWindow->getToken(), secondWindow->getToken());
6125 ASSERT_TRUE(success);
6126 // The first window gets cancel and the second gets down
6127 firstWindow->consumeMotionCancel();
Prabir Pradhan65455c72024-02-13 21:46:41 +00006128 secondWindow->consumeMotionDown(ADISPLAY_ID_DEFAULT, AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
Siarhei Vishniakou7ae7afd2022-03-31 15:26:13 -07006129
6130 // Send up event to the second window
Prabir Pradhan678438e2023-04-13 19:32:51 +00006131 mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN,
6132 ADISPLAY_ID_DEFAULT));
Siarhei Vishniakou7ae7afd2022-03-31 15:26:13 -07006133 // The first window gets no events and the second+spy get up
6134 firstWindow->assertNoEvents();
6135 spyWindow->consumeMotionUp();
Prabir Pradhan65455c72024-02-13 21:46:41 +00006136 secondWindow->consumeMotionUp(ADISPLAY_ID_DEFAULT, AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
Siarhei Vishniakou7ae7afd2022-03-31 15:26:13 -07006137}
6138
Siarhei Vishniakoud0c6bc82021-03-13 03:14:52 +00006139TEST_P(TransferTouchFixture, TransferTouch_TwoPointersNonSplitTouch) {
Chris Yea209fde2020-07-22 13:54:51 -07006140 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
Svet Ganov5d3bc372020-01-26 23:11:07 -08006141
6142 PointF touchPoint = {10, 10};
6143
6144 // Create a couple of windows
Siarhei Vishniakou870ecec2020-12-09 08:07:46 -10006145 sp<FakeWindowHandle> firstWindow =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07006146 sp<FakeWindowHandle>::make(application, mDispatcher, "First Window",
6147 ADISPLAY_ID_DEFAULT);
Prabir Pradhan76bdecb2022-01-31 11:14:15 -08006148 firstWindow->setPreventSplitting(true);
Siarhei Vishniakou870ecec2020-12-09 08:07:46 -10006149 sp<FakeWindowHandle> secondWindow =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07006150 sp<FakeWindowHandle>::make(application, mDispatcher, "Second Window",
6151 ADISPLAY_ID_DEFAULT);
Prabir Pradhan76bdecb2022-01-31 11:14:15 -08006152 secondWindow->setPreventSplitting(true);
Svet Ganov5d3bc372020-01-26 23:11:07 -08006153
6154 // Add the windows to the dispatcher
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07006155 mDispatcher->onWindowInfosChanged(
6156 {{*firstWindow->getInfo(), *secondWindow->getInfo()}, {}, 0, 0});
Svet Ganov5d3bc372020-01-26 23:11:07 -08006157
6158 // Send down to the first window
Prabir Pradhan678438e2023-04-13 19:32:51 +00006159 mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_DOWN,
6160 AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
6161 {touchPoint}));
Svet Ganov5d3bc372020-01-26 23:11:07 -08006162 // Only the first window should get the down event
6163 firstWindow->consumeMotionDown();
6164 secondWindow->assertNoEvents();
6165
6166 // Send pointer down to the first window
Prabir Pradhan678438e2023-04-13 19:32:51 +00006167 mDispatcher->notifyMotion(generateMotionArgs(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN,
6168 ADISPLAY_ID_DEFAULT, {touchPoint, touchPoint}));
Svet Ganov5d3bc372020-01-26 23:11:07 -08006169 // Only the first window should get the pointer down event
6170 firstWindow->consumeMotionPointerDown(1);
6171 secondWindow->assertNoEvents();
6172
6173 // Transfer touch focus to the second window
Siarhei Vishniakoud0c6bc82021-03-13 03:14:52 +00006174 TransferFunction f = GetParam();
6175 bool success = f(mDispatcher, firstWindow->getToken(), secondWindow->getToken());
6176 ASSERT_TRUE(success);
Svet Ganov5d3bc372020-01-26 23:11:07 -08006177 // The first window gets cancel and the second gets down and pointer down
6178 firstWindow->consumeMotionCancel();
Prabir Pradhan65455c72024-02-13 21:46:41 +00006179 secondWindow->consumeMotionDown(ADISPLAY_ID_DEFAULT, AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
6180 secondWindow->consumeMotionPointerDown(1, ADISPLAY_ID_DEFAULT,
6181 AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
Svet Ganov5d3bc372020-01-26 23:11:07 -08006182
6183 // Send pointer up to the second window
Prabir Pradhan678438e2023-04-13 19:32:51 +00006184 mDispatcher->notifyMotion(generateMotionArgs(POINTER_1_UP, AINPUT_SOURCE_TOUCHSCREEN,
6185 ADISPLAY_ID_DEFAULT, {touchPoint, touchPoint}));
Svet Ganov5d3bc372020-01-26 23:11:07 -08006186 // The first window gets nothing and the second gets pointer up
6187 firstWindow->assertNoEvents();
Prabir Pradhan65455c72024-02-13 21:46:41 +00006188 secondWindow->consumeMotionPointerUp(1, ADISPLAY_ID_DEFAULT,
6189 AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
Svet Ganov5d3bc372020-01-26 23:11:07 -08006190
6191 // Send up event to the second window
Prabir Pradhan678438e2023-04-13 19:32:51 +00006192 mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN,
6193 ADISPLAY_ID_DEFAULT));
Svet Ganov5d3bc372020-01-26 23:11:07 -08006194 // The first window gets nothing and the second gets up
6195 firstWindow->assertNoEvents();
Prabir Pradhan65455c72024-02-13 21:46:41 +00006196 secondWindow->consumeMotionUp(ADISPLAY_ID_DEFAULT, AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
Svet Ganov5d3bc372020-01-26 23:11:07 -08006197}
6198
Arthur Hungc539dbb2022-12-08 07:45:36 +00006199TEST_P(TransferTouchFixture, TransferTouch_MultipleWallpapers) {
6200 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
6201
6202 // Create a couple of windows
6203 sp<FakeWindowHandle> firstWindow =
6204 sp<FakeWindowHandle>::make(application, mDispatcher, "First Window",
6205 ADISPLAY_ID_DEFAULT);
6206 firstWindow->setDupTouchToWallpaper(true);
6207 sp<FakeWindowHandle> secondWindow =
6208 sp<FakeWindowHandle>::make(application, mDispatcher, "Second Window",
6209 ADISPLAY_ID_DEFAULT);
6210 secondWindow->setDupTouchToWallpaper(true);
6211
6212 sp<FakeWindowHandle> wallpaper1 =
6213 sp<FakeWindowHandle>::make(application, mDispatcher, "Wallpaper1", ADISPLAY_ID_DEFAULT);
6214 wallpaper1->setIsWallpaper(true);
6215
6216 sp<FakeWindowHandle> wallpaper2 =
6217 sp<FakeWindowHandle>::make(application, mDispatcher, "Wallpaper2", ADISPLAY_ID_DEFAULT);
6218 wallpaper2->setIsWallpaper(true);
6219 // Add the windows to the dispatcher
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07006220 mDispatcher->onWindowInfosChanged({{*firstWindow->getInfo(), *wallpaper1->getInfo(),
6221 *secondWindow->getInfo(), *wallpaper2->getInfo()},
6222 {},
6223 0,
6224 0});
Arthur Hungc539dbb2022-12-08 07:45:36 +00006225
6226 // Send down to the first window
Prabir Pradhan678438e2023-04-13 19:32:51 +00006227 mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_DOWN,
6228 AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT));
Arthur Hungc539dbb2022-12-08 07:45:36 +00006229
6230 // Only the first window should get the down event
6231 firstWindow->consumeMotionDown();
6232 secondWindow->assertNoEvents();
Linnan Li72352222024-04-12 18:55:57 +08006233 wallpaper1->consumeMotionDown(ADISPLAY_ID_DEFAULT, EXPECTED_WALLPAPER_FLAGS);
Arthur Hungc539dbb2022-12-08 07:45:36 +00006234 wallpaper2->assertNoEvents();
6235
6236 // Transfer touch focus to the second window
6237 TransferFunction f = GetParam();
6238 bool success = f(mDispatcher, firstWindow->getToken(), secondWindow->getToken());
6239 ASSERT_TRUE(success);
6240
6241 // The first window gets cancel and the second gets down
6242 firstWindow->consumeMotionCancel();
Prabir Pradhan65455c72024-02-13 21:46:41 +00006243 secondWindow->consumeMotionDown(ADISPLAY_ID_DEFAULT, AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
Linnan Li72352222024-04-12 18:55:57 +08006244 wallpaper1->consumeMotionCancel(ADISPLAY_ID_DEFAULT, EXPECTED_WALLPAPER_FLAGS);
Prabir Pradhan65455c72024-02-13 21:46:41 +00006245 wallpaper2->consumeMotionDown(ADISPLAY_ID_DEFAULT,
Linnan Li72352222024-04-12 18:55:57 +08006246 EXPECTED_WALLPAPER_FLAGS | AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
Arthur Hungc539dbb2022-12-08 07:45:36 +00006247
6248 // Send up event to the second window
Prabir Pradhan678438e2023-04-13 19:32:51 +00006249 mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN,
6250 ADISPLAY_ID_DEFAULT));
Arthur Hungc539dbb2022-12-08 07:45:36 +00006251 // The first window gets no events and the second gets up
6252 firstWindow->assertNoEvents();
Prabir Pradhan65455c72024-02-13 21:46:41 +00006253 secondWindow->consumeMotionUp(ADISPLAY_ID_DEFAULT, AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
Arthur Hungc539dbb2022-12-08 07:45:36 +00006254 wallpaper1->assertNoEvents();
Prabir Pradhan65455c72024-02-13 21:46:41 +00006255 wallpaper2->consumeMotionUp(ADISPLAY_ID_DEFAULT,
Linnan Li72352222024-04-12 18:55:57 +08006256 EXPECTED_WALLPAPER_FLAGS | AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
Arthur Hungc539dbb2022-12-08 07:45:36 +00006257}
6258
Siarhei Vishniakoud0c6bc82021-03-13 03:14:52 +00006259// For the cases of single pointer touch and two pointers non-split touch, the api's
Prabir Pradhan367f3432024-02-13 23:05:58 +00006260// 'transferTouchGesture' and 'transferTouchOnDisplay' are equivalent in behaviour. They only differ
Siarhei Vishniakoud0c6bc82021-03-13 03:14:52 +00006261// for the case where there are multiple pointers split across several windows.
Prabir Pradhan367f3432024-02-13 23:05:58 +00006262INSTANTIATE_TEST_SUITE_P(
6263 InputDispatcherTransferFunctionTests, TransferTouchFixture,
6264 ::testing::Values(
6265 [&](const std::unique_ptr<InputDispatcher>& dispatcher, sp<IBinder> /*ignored*/,
6266 sp<IBinder> destChannelToken) {
6267 return dispatcher->transferTouchOnDisplay(destChannelToken,
6268 ADISPLAY_ID_DEFAULT);
6269 },
6270 [&](const std::unique_ptr<InputDispatcher>& dispatcher, sp<IBinder> from,
6271 sp<IBinder> to) {
6272 return dispatcher->transferTouchGesture(from, to,
6273 /*isDragAndDrop=*/false);
6274 }));
Siarhei Vishniakoud0c6bc82021-03-13 03:14:52 +00006275
Prabir Pradhan367f3432024-02-13 23:05:58 +00006276TEST_F(InputDispatcherTest, TransferTouch_TwoPointersSplitTouch) {
Chris Yea209fde2020-07-22 13:54:51 -07006277 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
Svet Ganov5d3bc372020-01-26 23:11:07 -08006278
Siarhei Vishniakou870ecec2020-12-09 08:07:46 -10006279 sp<FakeWindowHandle> firstWindow =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07006280 sp<FakeWindowHandle>::make(application, mDispatcher, "First Window",
6281 ADISPLAY_ID_DEFAULT);
Svet Ganov5d3bc372020-01-26 23:11:07 -08006282 firstWindow->setFrame(Rect(0, 0, 600, 400));
Svet Ganov5d3bc372020-01-26 23:11:07 -08006283
Siarhei Vishniakou870ecec2020-12-09 08:07:46 -10006284 sp<FakeWindowHandle> secondWindow =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07006285 sp<FakeWindowHandle>::make(application, mDispatcher, "Second Window",
6286 ADISPLAY_ID_DEFAULT);
Svet Ganov5d3bc372020-01-26 23:11:07 -08006287 secondWindow->setFrame(Rect(0, 400, 600, 800));
Svet Ganov5d3bc372020-01-26 23:11:07 -08006288
6289 // Add the windows to the dispatcher
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07006290 mDispatcher->onWindowInfosChanged(
6291 {{*firstWindow->getInfo(), *secondWindow->getInfo()}, {}, 0, 0});
Svet Ganov5d3bc372020-01-26 23:11:07 -08006292
6293 PointF pointInFirst = {300, 200};
6294 PointF pointInSecond = {300, 600};
6295
6296 // Send down to the first window
Prabir Pradhan678438e2023-04-13 19:32:51 +00006297 mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_DOWN,
6298 AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
6299 {pointInFirst}));
Svet Ganov5d3bc372020-01-26 23:11:07 -08006300 // Only the first window should get the down event
6301 firstWindow->consumeMotionDown();
6302 secondWindow->assertNoEvents();
6303
6304 // Send down to the second window
Prabir Pradhan678438e2023-04-13 19:32:51 +00006305 mDispatcher->notifyMotion(generateMotionArgs(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN,
6306 ADISPLAY_ID_DEFAULT,
6307 {pointInFirst, pointInSecond}));
Svet Ganov5d3bc372020-01-26 23:11:07 -08006308 // The first window gets a move and the second a down
6309 firstWindow->consumeMotionMove();
6310 secondWindow->consumeMotionDown();
6311
Prabir Pradhan367f3432024-02-13 23:05:58 +00006312 // Transfer touch to the second window
6313 mDispatcher->transferTouchGesture(firstWindow->getToken(), secondWindow->getToken());
Svet Ganov5d3bc372020-01-26 23:11:07 -08006314 // The first window gets cancel and the new gets pointer down (it already saw down)
6315 firstWindow->consumeMotionCancel();
Prabir Pradhan65455c72024-02-13 21:46:41 +00006316 secondWindow->consumeMotionPointerDown(1, ADISPLAY_ID_DEFAULT,
6317 AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
Svet Ganov5d3bc372020-01-26 23:11:07 -08006318
6319 // Send pointer up to the second window
Prabir Pradhan678438e2023-04-13 19:32:51 +00006320 mDispatcher->notifyMotion(generateMotionArgs(POINTER_1_UP, AINPUT_SOURCE_TOUCHSCREEN,
6321 ADISPLAY_ID_DEFAULT,
6322 {pointInFirst, pointInSecond}));
Svet Ganov5d3bc372020-01-26 23:11:07 -08006323 // The first window gets nothing and the second gets pointer up
6324 firstWindow->assertNoEvents();
Prabir Pradhan65455c72024-02-13 21:46:41 +00006325 secondWindow->consumeMotionPointerUp(1, ADISPLAY_ID_DEFAULT,
6326 AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
Svet Ganov5d3bc372020-01-26 23:11:07 -08006327
6328 // Send up event to the second window
Prabir Pradhan678438e2023-04-13 19:32:51 +00006329 mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN,
6330 ADISPLAY_ID_DEFAULT));
Svet Ganov5d3bc372020-01-26 23:11:07 -08006331 // The first window gets nothing and the second gets up
6332 firstWindow->assertNoEvents();
Prabir Pradhan65455c72024-02-13 21:46:41 +00006333 secondWindow->consumeMotionUp(ADISPLAY_ID_DEFAULT, AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
Svet Ganov5d3bc372020-01-26 23:11:07 -08006334}
6335
Prabir Pradhan367f3432024-02-13 23:05:58 +00006336// Same as TransferTouch_TwoPointersSplitTouch, but using 'transferTouchOnDisplay' api.
6337// Unlike 'transferTouchGesture', calling 'transferTouchOnDisplay' when there are two windows
6338// receiving touch is not supported, so the touch should continue on those windows and the
6339// transferred-to window should get nothing.
6340TEST_F(InputDispatcherTest, TransferTouchOnDisplay_TwoPointersSplitTouch) {
Siarhei Vishniakoud0c6bc82021-03-13 03:14:52 +00006341 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
6342
Siarhei Vishniakoud0c6bc82021-03-13 03:14:52 +00006343 sp<FakeWindowHandle> firstWindow =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07006344 sp<FakeWindowHandle>::make(application, mDispatcher, "First Window",
6345 ADISPLAY_ID_DEFAULT);
Siarhei Vishniakoud0c6bc82021-03-13 03:14:52 +00006346 firstWindow->setFrame(Rect(0, 0, 600, 400));
Siarhei Vishniakoud0c6bc82021-03-13 03:14:52 +00006347
Siarhei Vishniakoud0c6bc82021-03-13 03:14:52 +00006348 sp<FakeWindowHandle> secondWindow =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07006349 sp<FakeWindowHandle>::make(application, mDispatcher, "Second Window",
6350 ADISPLAY_ID_DEFAULT);
Siarhei Vishniakoud0c6bc82021-03-13 03:14:52 +00006351 secondWindow->setFrame(Rect(0, 400, 600, 800));
Siarhei Vishniakoud0c6bc82021-03-13 03:14:52 +00006352
6353 // Add the windows to the dispatcher
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07006354 mDispatcher->onWindowInfosChanged(
6355 {{*firstWindow->getInfo(), *secondWindow->getInfo()}, {}, 0, 0});
Siarhei Vishniakoud0c6bc82021-03-13 03:14:52 +00006356
6357 PointF pointInFirst = {300, 200};
6358 PointF pointInSecond = {300, 600};
6359
6360 // Send down to the first window
Prabir Pradhan678438e2023-04-13 19:32:51 +00006361 mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_DOWN,
6362 AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
6363 {pointInFirst}));
Siarhei Vishniakoud0c6bc82021-03-13 03:14:52 +00006364 // Only the first window should get the down event
6365 firstWindow->consumeMotionDown();
6366 secondWindow->assertNoEvents();
6367
6368 // Send down to the second window
Prabir Pradhan678438e2023-04-13 19:32:51 +00006369 mDispatcher->notifyMotion(generateMotionArgs(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN,
6370 ADISPLAY_ID_DEFAULT,
6371 {pointInFirst, pointInSecond}));
Siarhei Vishniakoud0c6bc82021-03-13 03:14:52 +00006372 // The first window gets a move and the second a down
6373 firstWindow->consumeMotionMove();
6374 secondWindow->consumeMotionDown();
6375
6376 // Transfer touch focus to the second window
Siarhei Vishniakou7ae7afd2022-03-31 15:26:13 -07006377 const bool transferred =
Prabir Pradhan367f3432024-02-13 23:05:58 +00006378 mDispatcher->transferTouchOnDisplay(secondWindow->getToken(), ADISPLAY_ID_DEFAULT);
6379 // The 'transferTouchOnDisplay' call should not succeed, because there are 2 touched windows
Siarhei Vishniakoud0c6bc82021-03-13 03:14:52 +00006380 ASSERT_FALSE(transferred);
6381 firstWindow->assertNoEvents();
6382 secondWindow->assertNoEvents();
6383
6384 // The rest of the dispatch should proceed as normal
6385 // Send pointer up to the second window
Prabir Pradhan678438e2023-04-13 19:32:51 +00006386 mDispatcher->notifyMotion(generateMotionArgs(POINTER_1_UP, AINPUT_SOURCE_TOUCHSCREEN,
6387 ADISPLAY_ID_DEFAULT,
6388 {pointInFirst, pointInSecond}));
Siarhei Vishniakoud0c6bc82021-03-13 03:14:52 +00006389 // The first window gets MOVE and the second gets pointer up
6390 firstWindow->consumeMotionMove();
6391 secondWindow->consumeMotionUp();
6392
6393 // Send up event to the first window
Prabir Pradhan678438e2023-04-13 19:32:51 +00006394 mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN,
6395 ADISPLAY_ID_DEFAULT));
Siarhei Vishniakoud0c6bc82021-03-13 03:14:52 +00006396 // The first window gets nothing and the second gets up
6397 firstWindow->consumeMotionUp();
6398 secondWindow->assertNoEvents();
6399}
6400
Arthur Hungabbb9d82021-09-01 14:52:30 +00006401// This case will create two windows and one mirrored window on the default display and mirror
Prabir Pradhan367f3432024-02-13 23:05:58 +00006402// two windows on the second display. It will test if 'transferTouchGesture' works fine if we put
Arthur Hungabbb9d82021-09-01 14:52:30 +00006403// the windows info of second display before default display.
Prabir Pradhan367f3432024-02-13 23:05:58 +00006404TEST_F(InputDispatcherTest, TransferTouch_CloneSurface) {
Arthur Hungabbb9d82021-09-01 14:52:30 +00006405 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
6406 sp<FakeWindowHandle> firstWindowInPrimary =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07006407 sp<FakeWindowHandle>::make(application, mDispatcher, "D_1_W1", ADISPLAY_ID_DEFAULT);
Arthur Hungabbb9d82021-09-01 14:52:30 +00006408 firstWindowInPrimary->setFrame(Rect(0, 0, 100, 100));
Arthur Hungabbb9d82021-09-01 14:52:30 +00006409 sp<FakeWindowHandle> secondWindowInPrimary =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07006410 sp<FakeWindowHandle>::make(application, mDispatcher, "D_1_W2", ADISPLAY_ID_DEFAULT);
Arthur Hungabbb9d82021-09-01 14:52:30 +00006411 secondWindowInPrimary->setFrame(Rect(100, 0, 200, 100));
Arthur Hungabbb9d82021-09-01 14:52:30 +00006412
Siarhei Vishniakouadb9fc92023-05-26 10:46:09 -07006413 sp<FakeWindowHandle> mirrorWindowInPrimary = firstWindowInPrimary->clone(ADISPLAY_ID_DEFAULT);
Arthur Hungabbb9d82021-09-01 14:52:30 +00006414 mirrorWindowInPrimary->setFrame(Rect(0, 100, 100, 200));
Arthur Hungabbb9d82021-09-01 14:52:30 +00006415
Siarhei Vishniakouadb9fc92023-05-26 10:46:09 -07006416 sp<FakeWindowHandle> firstWindowInSecondary = firstWindowInPrimary->clone(SECOND_DISPLAY_ID);
Arthur Hungabbb9d82021-09-01 14:52:30 +00006417 firstWindowInSecondary->setFrame(Rect(0, 0, 100, 100));
Arthur Hungabbb9d82021-09-01 14:52:30 +00006418
Siarhei Vishniakouadb9fc92023-05-26 10:46:09 -07006419 sp<FakeWindowHandle> secondWindowInSecondary = secondWindowInPrimary->clone(SECOND_DISPLAY_ID);
Arthur Hungabbb9d82021-09-01 14:52:30 +00006420 secondWindowInPrimary->setFrame(Rect(100, 0, 200, 100));
Arthur Hungabbb9d82021-09-01 14:52:30 +00006421
6422 // Update window info, let it find window handle of second display first.
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07006423 mDispatcher->onWindowInfosChanged(
6424 {{*firstWindowInSecondary->getInfo(), *secondWindowInSecondary->getInfo(),
6425 *mirrorWindowInPrimary->getInfo(), *firstWindowInPrimary->getInfo(),
6426 *secondWindowInPrimary->getInfo()},
6427 {},
6428 0,
6429 0});
Arthur Hungabbb9d82021-09-01 14:52:30 +00006430
6431 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07006432 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
Arthur Hungabbb9d82021-09-01 14:52:30 +00006433 {50, 50}))
6434 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
6435
6436 // Window should receive motion event.
6437 firstWindowInPrimary->consumeMotionDown(ADISPLAY_ID_DEFAULT);
6438
Prabir Pradhan367f3432024-02-13 23:05:58 +00006439 // Transfer touch
6440 ASSERT_TRUE(mDispatcher->transferTouchGesture(firstWindowInPrimary->getToken(),
6441 secondWindowInPrimary->getToken()));
Arthur Hungabbb9d82021-09-01 14:52:30 +00006442 // The first window gets cancel.
6443 firstWindowInPrimary->consumeMotionCancel();
Prabir Pradhan65455c72024-02-13 21:46:41 +00006444 secondWindowInPrimary->consumeMotionDown(ADISPLAY_ID_DEFAULT,
6445 AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
Arthur Hungabbb9d82021-09-01 14:52:30 +00006446
6447 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07006448 injectMotionEvent(*mDispatcher, AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN,
Arthur Hungabbb9d82021-09-01 14:52:30 +00006449 ADISPLAY_ID_DEFAULT, {150, 50}))
6450 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
6451 firstWindowInPrimary->assertNoEvents();
Prabir Pradhan65455c72024-02-13 21:46:41 +00006452 secondWindowInPrimary->consumeMotionMove(ADISPLAY_ID_DEFAULT,
6453 AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
Arthur Hungabbb9d82021-09-01 14:52:30 +00006454
6455 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07006456 injectMotionUp(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
Arthur Hungabbb9d82021-09-01 14:52:30 +00006457 {150, 50}))
6458 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
6459 firstWindowInPrimary->assertNoEvents();
Prabir Pradhan65455c72024-02-13 21:46:41 +00006460 secondWindowInPrimary->consumeMotionUp(ADISPLAY_ID_DEFAULT, AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
Arthur Hungabbb9d82021-09-01 14:52:30 +00006461}
6462
Prabir Pradhan367f3432024-02-13 23:05:58 +00006463// Same as TransferTouch_CloneSurface, but this touch on the secondary display and use
6464// 'transferTouchOnDisplay' api.
6465TEST_F(InputDispatcherTest, TransferTouchOnDisplay_CloneSurface) {
Arthur Hungabbb9d82021-09-01 14:52:30 +00006466 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
6467 sp<FakeWindowHandle> firstWindowInPrimary =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07006468 sp<FakeWindowHandle>::make(application, mDispatcher, "D_1_W1", ADISPLAY_ID_DEFAULT);
Arthur Hungabbb9d82021-09-01 14:52:30 +00006469 firstWindowInPrimary->setFrame(Rect(0, 0, 100, 100));
Arthur Hungabbb9d82021-09-01 14:52:30 +00006470 sp<FakeWindowHandle> secondWindowInPrimary =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07006471 sp<FakeWindowHandle>::make(application, mDispatcher, "D_1_W2", ADISPLAY_ID_DEFAULT);
Arthur Hungabbb9d82021-09-01 14:52:30 +00006472 secondWindowInPrimary->setFrame(Rect(100, 0, 200, 100));
Arthur Hungabbb9d82021-09-01 14:52:30 +00006473
Siarhei Vishniakouadb9fc92023-05-26 10:46:09 -07006474 sp<FakeWindowHandle> mirrorWindowInPrimary = firstWindowInPrimary->clone(ADISPLAY_ID_DEFAULT);
Arthur Hungabbb9d82021-09-01 14:52:30 +00006475 mirrorWindowInPrimary->setFrame(Rect(0, 100, 100, 200));
Arthur Hungabbb9d82021-09-01 14:52:30 +00006476
Siarhei Vishniakouadb9fc92023-05-26 10:46:09 -07006477 sp<FakeWindowHandle> firstWindowInSecondary = firstWindowInPrimary->clone(SECOND_DISPLAY_ID);
Arthur Hungabbb9d82021-09-01 14:52:30 +00006478 firstWindowInSecondary->setFrame(Rect(0, 0, 100, 100));
Arthur Hungabbb9d82021-09-01 14:52:30 +00006479
Siarhei Vishniakouadb9fc92023-05-26 10:46:09 -07006480 sp<FakeWindowHandle> secondWindowInSecondary = secondWindowInPrimary->clone(SECOND_DISPLAY_ID);
Arthur Hungabbb9d82021-09-01 14:52:30 +00006481 secondWindowInPrimary->setFrame(Rect(100, 0, 200, 100));
Arthur Hungabbb9d82021-09-01 14:52:30 +00006482
6483 // Update window info, let it find window handle of second display first.
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07006484 mDispatcher->onWindowInfosChanged(
6485 {{*firstWindowInSecondary->getInfo(), *secondWindowInSecondary->getInfo(),
6486 *mirrorWindowInPrimary->getInfo(), *firstWindowInPrimary->getInfo(),
6487 *secondWindowInPrimary->getInfo()},
6488 {},
6489 0,
6490 0});
Arthur Hungabbb9d82021-09-01 14:52:30 +00006491
6492 // Touch on second display.
6493 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07006494 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, SECOND_DISPLAY_ID,
6495 {50, 50}))
Arthur Hungabbb9d82021-09-01 14:52:30 +00006496 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
6497
6498 // Window should receive motion event.
Prabir Pradhanbb3f1c02024-01-04 20:17:14 +00006499 firstWindowInSecondary->consumeMotionDown(SECOND_DISPLAY_ID);
Arthur Hungabbb9d82021-09-01 14:52:30 +00006500
6501 // Transfer touch focus
Prabir Pradhan367f3432024-02-13 23:05:58 +00006502 ASSERT_TRUE(mDispatcher->transferTouchOnDisplay(secondWindowInSecondary->getToken(),
6503 SECOND_DISPLAY_ID));
Arthur Hungabbb9d82021-09-01 14:52:30 +00006504
6505 // The first window gets cancel.
Prabir Pradhanbb3f1c02024-01-04 20:17:14 +00006506 firstWindowInSecondary->consumeMotionCancel(SECOND_DISPLAY_ID);
Prabir Pradhan65455c72024-02-13 21:46:41 +00006507 secondWindowInSecondary->consumeMotionDown(SECOND_DISPLAY_ID,
6508 AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
Arthur Hungabbb9d82021-09-01 14:52:30 +00006509
6510 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07006511 injectMotionEvent(*mDispatcher, AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN,
Arthur Hungabbb9d82021-09-01 14:52:30 +00006512 SECOND_DISPLAY_ID, {150, 50}))
6513 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
Prabir Pradhanbb3f1c02024-01-04 20:17:14 +00006514 firstWindowInSecondary->assertNoEvents();
Prabir Pradhan65455c72024-02-13 21:46:41 +00006515 secondWindowInSecondary->consumeMotionMove(SECOND_DISPLAY_ID,
6516 AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
Arthur Hungabbb9d82021-09-01 14:52:30 +00006517
6518 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07006519 injectMotionUp(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, SECOND_DISPLAY_ID, {150, 50}))
Arthur Hungabbb9d82021-09-01 14:52:30 +00006520 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
Prabir Pradhanbb3f1c02024-01-04 20:17:14 +00006521 firstWindowInSecondary->assertNoEvents();
Prabir Pradhan65455c72024-02-13 21:46:41 +00006522 secondWindowInSecondary->consumeMotionUp(SECOND_DISPLAY_ID, AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
Arthur Hungabbb9d82021-09-01 14:52:30 +00006523}
6524
Siarhei Vishniakouf1035d42019-09-20 16:32:01 +01006525TEST_F(InputDispatcherTest, FocusedWindow_ReceivesFocusEventAndKeyEvent) {
Chris Yea209fde2020-07-22 13:54:51 -07006526 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07006527 sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher,
6528 "Fake Window", ADISPLAY_ID_DEFAULT);
Siarhei Vishniakouf1035d42019-09-20 16:32:01 +01006529
Vishnu Nair47074b82020-08-14 11:54:47 -07006530 window->setFocusable(true);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07006531 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Vishnu Nair958da932020-08-21 17:12:37 -07006532 setFocusedWindow(window);
Siarhei Vishniakouf1035d42019-09-20 16:32:01 +01006533
6534 window->consumeFocusEvent(true);
6535
Prabir Pradhan678438e2023-04-13 19:32:51 +00006536 mDispatcher->notifyKey(generateKeyArgs(AKEY_EVENT_ACTION_DOWN, ADISPLAY_ID_DEFAULT));
Siarhei Vishniakouf1035d42019-09-20 16:32:01 +01006537
6538 // Window should receive key down event.
6539 window->consumeKeyDown(ADISPLAY_ID_DEFAULT);
Josep del Riob3981622023-04-18 15:49:45 +00006540
6541 // Should have poked user activity
Siarhei Vishniakou4fd86732023-05-24 17:33:01 +00006542 mDispatcher->waitForIdle();
Josep del Riob3981622023-04-18 15:49:45 +00006543 mFakePolicy->assertUserActivityPoked();
6544}
6545
6546TEST_F(InputDispatcherTest, FocusedWindow_DisableUserActivity) {
6547 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
6548 sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher,
6549 "Fake Window", ADISPLAY_ID_DEFAULT);
6550
6551 window->setDisableUserActivity(true);
6552 window->setFocusable(true);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07006553 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Josep del Riob3981622023-04-18 15:49:45 +00006554 setFocusedWindow(window);
6555
6556 window->consumeFocusEvent(true);
6557
6558 mDispatcher->notifyKey(generateKeyArgs(AKEY_EVENT_ACTION_DOWN, ADISPLAY_ID_DEFAULT));
6559
6560 // Window should receive key down event.
6561 window->consumeKeyDown(ADISPLAY_ID_DEFAULT);
6562
6563 // Should have poked user activity
Siarhei Vishniakou4fd86732023-05-24 17:33:01 +00006564 mDispatcher->waitForIdle();
Josep del Riob3981622023-04-18 15:49:45 +00006565 mFakePolicy->assertUserActivityNotPoked();
6566}
6567
6568TEST_F(InputDispatcherTest, FocusedWindow_DoesNotReceiveSystemShortcut) {
6569 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
6570 sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher,
6571 "Fake Window", ADISPLAY_ID_DEFAULT);
6572
6573 window->setFocusable(true);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07006574 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Josep del Riob3981622023-04-18 15:49:45 +00006575 setFocusedWindow(window);
6576
6577 window->consumeFocusEvent(true);
6578
6579 mDispatcher->notifyKey(generateSystemShortcutArgs(AKEY_EVENT_ACTION_DOWN, ADISPLAY_ID_DEFAULT));
6580 mDispatcher->waitForIdle();
6581
6582 // System key is not passed down
6583 window->assertNoEvents();
6584
6585 // Should have poked user activity
6586 mFakePolicy->assertUserActivityPoked();
6587}
6588
6589TEST_F(InputDispatcherTest, FocusedWindow_DoesNotReceiveAssistantKey) {
6590 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
6591 sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher,
6592 "Fake Window", ADISPLAY_ID_DEFAULT);
6593
6594 window->setFocusable(true);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07006595 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Josep del Riob3981622023-04-18 15:49:45 +00006596 setFocusedWindow(window);
6597
6598 window->consumeFocusEvent(true);
6599
6600 mDispatcher->notifyKey(generateAssistantKeyArgs(AKEY_EVENT_ACTION_DOWN, ADISPLAY_ID_DEFAULT));
6601 mDispatcher->waitForIdle();
6602
6603 // System key is not passed down
6604 window->assertNoEvents();
6605
6606 // Should have poked user activity
6607 mFakePolicy->assertUserActivityPoked();
6608}
6609
6610TEST_F(InputDispatcherTest, FocusedWindow_SystemKeyIgnoresDisableUserActivity) {
6611 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
6612 sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher,
6613 "Fake Window", ADISPLAY_ID_DEFAULT);
6614
6615 window->setDisableUserActivity(true);
6616 window->setFocusable(true);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07006617 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Josep del Riob3981622023-04-18 15:49:45 +00006618 setFocusedWindow(window);
6619
6620 window->consumeFocusEvent(true);
6621
6622 mDispatcher->notifyKey(generateSystemShortcutArgs(AKEY_EVENT_ACTION_DOWN, ADISPLAY_ID_DEFAULT));
6623 mDispatcher->waitForIdle();
6624
6625 // System key is not passed down
6626 window->assertNoEvents();
6627
6628 // Should have poked user activity
6629 mFakePolicy->assertUserActivityPoked();
Siarhei Vishniakouf1035d42019-09-20 16:32:01 +01006630}
6631
Siarhei Vishniakou90ee4782023-05-08 11:57:24 -07006632TEST_F(InputDispatcherTest, InjectedTouchesPokeUserActivity) {
6633 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
6634 sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher,
6635 "Fake Window", ADISPLAY_ID_DEFAULT);
6636
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07006637 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Siarhei Vishniakou90ee4782023-05-08 11:57:24 -07006638
6639 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07006640 injectMotionEvent(*mDispatcher, AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN,
Siarhei Vishniakou90ee4782023-05-08 11:57:24 -07006641 ADISPLAY_ID_DEFAULT, {100, 100}))
6642 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
6643
6644 window->consumeMotionEvent(
6645 AllOf(WithMotionAction(ACTION_DOWN), WithDisplayId(ADISPLAY_ID_DEFAULT)));
6646
6647 // Should have poked user activity
Siarhei Vishniakou4fd86732023-05-24 17:33:01 +00006648 mDispatcher->waitForIdle();
Siarhei Vishniakou90ee4782023-05-08 11:57:24 -07006649 mFakePolicy->assertUserActivityPoked();
6650}
6651
Siarhei Vishniakouf1035d42019-09-20 16:32:01 +01006652TEST_F(InputDispatcherTest, UnfocusedWindow_DoesNotReceiveFocusEventOrKeyEvent) {
Chris Yea209fde2020-07-22 13:54:51 -07006653 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07006654 sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher,
6655 "Fake Window", ADISPLAY_ID_DEFAULT);
Siarhei Vishniakouf1035d42019-09-20 16:32:01 +01006656
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07006657 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Siarhei Vishniakouf1035d42019-09-20 16:32:01 +01006658
Prabir Pradhan678438e2023-04-13 19:32:51 +00006659 mDispatcher->notifyKey(generateKeyArgs(AKEY_EVENT_ACTION_DOWN, ADISPLAY_ID_DEFAULT));
Siarhei Vishniakouf1035d42019-09-20 16:32:01 +01006660 mDispatcher->waitForIdle();
6661
6662 window->assertNoEvents();
6663}
6664
6665// If a window is touchable, but does not have focus, it should receive motion events, but not keys
6666TEST_F(InputDispatcherTest, UnfocusedWindow_ReceivesMotionsButNotKeys) {
Chris Yea209fde2020-07-22 13:54:51 -07006667 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07006668 sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher,
6669 "Fake Window", ADISPLAY_ID_DEFAULT);
Siarhei Vishniakouf1035d42019-09-20 16:32:01 +01006670
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07006671 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Siarhei Vishniakouf1035d42019-09-20 16:32:01 +01006672
6673 // Send key
Prabir Pradhan678438e2023-04-13 19:32:51 +00006674 mDispatcher->notifyKey(generateKeyArgs(AKEY_EVENT_ACTION_DOWN, ADISPLAY_ID_DEFAULT));
Siarhei Vishniakouf1035d42019-09-20 16:32:01 +01006675 // Send motion
Prabir Pradhan678438e2023-04-13 19:32:51 +00006676 mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_DOWN,
6677 AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT));
Siarhei Vishniakouf1035d42019-09-20 16:32:01 +01006678
6679 // Window should receive only the motion event
6680 window->consumeMotionDown(ADISPLAY_ID_DEFAULT);
6681 window->assertNoEvents(); // Key event or focus event will not be received
6682}
6683
arthurhungea3f4fc2020-12-21 23:18:53 +08006684TEST_F(InputDispatcherTest, PointerCancel_SendCancelWhenSplitTouch) {
6685 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
6686
arthurhungea3f4fc2020-12-21 23:18:53 +08006687 sp<FakeWindowHandle> firstWindow =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07006688 sp<FakeWindowHandle>::make(application, mDispatcher, "First Window",
6689 ADISPLAY_ID_DEFAULT);
arthurhungea3f4fc2020-12-21 23:18:53 +08006690 firstWindow->setFrame(Rect(0, 0, 600, 400));
arthurhungea3f4fc2020-12-21 23:18:53 +08006691
arthurhungea3f4fc2020-12-21 23:18:53 +08006692 sp<FakeWindowHandle> secondWindow =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07006693 sp<FakeWindowHandle>::make(application, mDispatcher, "Second Window",
6694 ADISPLAY_ID_DEFAULT);
arthurhungea3f4fc2020-12-21 23:18:53 +08006695 secondWindow->setFrame(Rect(0, 400, 600, 800));
arthurhungea3f4fc2020-12-21 23:18:53 +08006696
6697 // Add the windows to the dispatcher
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07006698 mDispatcher->onWindowInfosChanged(
6699 {{*firstWindow->getInfo(), *secondWindow->getInfo()}, {}, 0, 0});
arthurhungea3f4fc2020-12-21 23:18:53 +08006700
6701 PointF pointInFirst = {300, 200};
6702 PointF pointInSecond = {300, 600};
6703
6704 // Send down to the first window
Prabir Pradhan678438e2023-04-13 19:32:51 +00006705 mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_DOWN,
6706 AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
6707 {pointInFirst}));
arthurhungea3f4fc2020-12-21 23:18:53 +08006708 // Only the first window should get the down event
6709 firstWindow->consumeMotionDown();
6710 secondWindow->assertNoEvents();
6711
6712 // Send down to the second window
Prabir Pradhan678438e2023-04-13 19:32:51 +00006713 mDispatcher->notifyMotion(generateMotionArgs(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN,
6714 ADISPLAY_ID_DEFAULT,
6715 {pointInFirst, pointInSecond}));
arthurhungea3f4fc2020-12-21 23:18:53 +08006716 // The first window gets a move and the second a down
6717 firstWindow->consumeMotionMove();
6718 secondWindow->consumeMotionDown();
6719
6720 // Send pointer cancel to the second window
6721 NotifyMotionArgs pointerUpMotionArgs =
Siarhei Vishniakoua16e3a22022-03-02 15:26:40 -08006722 generateMotionArgs(POINTER_1_UP, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
arthurhungea3f4fc2020-12-21 23:18:53 +08006723 {pointInFirst, pointInSecond});
6724 pointerUpMotionArgs.flags |= AMOTION_EVENT_FLAG_CANCELED;
Prabir Pradhan678438e2023-04-13 19:32:51 +00006725 mDispatcher->notifyMotion(pointerUpMotionArgs);
arthurhungea3f4fc2020-12-21 23:18:53 +08006726 // The first window gets move and the second gets cancel.
6727 firstWindow->consumeMotionMove(ADISPLAY_ID_DEFAULT, AMOTION_EVENT_FLAG_CANCELED);
6728 secondWindow->consumeMotionCancel(ADISPLAY_ID_DEFAULT, AMOTION_EVENT_FLAG_CANCELED);
6729
6730 // Send up event.
Prabir Pradhan678438e2023-04-13 19:32:51 +00006731 mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN,
6732 ADISPLAY_ID_DEFAULT));
arthurhungea3f4fc2020-12-21 23:18:53 +08006733 // The first window gets up and the second gets nothing.
6734 firstWindow->consumeMotionUp();
6735 secondWindow->assertNoEvents();
6736}
6737
Siarhei Vishniakouf94ae022021-02-04 01:23:17 +00006738TEST_F(InputDispatcherTest, SendTimeline_DoesNotCrashDispatcher) {
6739 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
6740
6741 sp<FakeWindowHandle> window =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07006742 sp<FakeWindowHandle>::make(application, mDispatcher, "Window", ADISPLAY_ID_DEFAULT);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07006743 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Siarhei Vishniakouf94ae022021-02-04 01:23:17 +00006744 std::array<nsecs_t, GraphicsTimeline::SIZE> graphicsTimeline;
6745 graphicsTimeline[GraphicsTimeline::GPU_COMPLETED_TIME] = 2;
6746 graphicsTimeline[GraphicsTimeline::PRESENT_TIME] = 3;
6747
Harry Cutts33476232023-01-30 19:57:29 +00006748 window->sendTimeline(/*inputEventId=*/1, graphicsTimeline);
Siarhei Vishniakouf94ae022021-02-04 01:23:17 +00006749 window->assertNoEvents();
6750 mDispatcher->waitForIdle();
6751}
6752
Prabir Pradhan1376fcd2022-01-21 09:56:35 -08006753using InputDispatcherMonitorTest = InputDispatcherTest;
6754
Siarhei Vishniakouca205502021-07-16 21:31:58 +00006755/**
6756 * Two entities that receive touch: A window, and a global monitor.
6757 * The touch goes to the window, and then the window disappears.
6758 * The monitor does not get cancel right away. But if more events come in, the touch gets canceled
6759 * for the monitor, as well.
6760 * 1. foregroundWindow
6761 * 2. monitor <-- global monitor (doesn't observe z order, receives all events)
6762 */
Prabir Pradhan1376fcd2022-01-21 09:56:35 -08006763TEST_F(InputDispatcherMonitorTest, MonitorTouchIsCanceledWhenForegroundWindowDisappears) {
Siarhei Vishniakouca205502021-07-16 21:31:58 +00006764 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
6765 sp<FakeWindowHandle> window =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07006766 sp<FakeWindowHandle>::make(application, mDispatcher, "Foreground", ADISPLAY_ID_DEFAULT);
Siarhei Vishniakouca205502021-07-16 21:31:58 +00006767
Prabir Pradhanfb549072023-10-05 19:17:36 +00006768 FakeMonitorReceiver monitor = FakeMonitorReceiver(*mDispatcher, "M_1", ADISPLAY_ID_DEFAULT);
Siarhei Vishniakouca205502021-07-16 21:31:58 +00006769
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07006770 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Siarhei Vishniakouca205502021-07-16 21:31:58 +00006771 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07006772 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
Siarhei Vishniakouca205502021-07-16 21:31:58 +00006773 {100, 200}))
6774 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
6775
6776 // Both the foreground window and the global monitor should receive the touch down
6777 window->consumeMotionDown();
6778 monitor.consumeMotionDown(ADISPLAY_ID_DEFAULT);
6779
6780 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07006781 injectMotionEvent(*mDispatcher, AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN,
Siarhei Vishniakouca205502021-07-16 21:31:58 +00006782 ADISPLAY_ID_DEFAULT, {110, 200}))
6783 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
6784
6785 window->consumeMotionMove();
6786 monitor.consumeMotionMove(ADISPLAY_ID_DEFAULT);
6787
6788 // Now the foreground window goes away
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07006789 mDispatcher->onWindowInfosChanged({{}, {}, 0, 0});
Siarhei Vishniakouca205502021-07-16 21:31:58 +00006790 window->consumeMotionCancel();
6791 monitor.assertNoEvents(); // Global monitor does not get a cancel yet
6792
6793 // If more events come in, there will be no more foreground window to send them to. This will
6794 // cause a cancel for the monitor, as well.
6795 ASSERT_EQ(InputEventInjectionResult::FAILED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07006796 injectMotionEvent(*mDispatcher, AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN,
Siarhei Vishniakouca205502021-07-16 21:31:58 +00006797 ADISPLAY_ID_DEFAULT, {120, 200}))
6798 << "Injection should fail because the window was removed";
6799 window->assertNoEvents();
6800 // Global monitor now gets the cancel
6801 monitor.consumeMotionCancel(ADISPLAY_ID_DEFAULT);
6802}
6803
Prabir Pradhan1376fcd2022-01-21 09:56:35 -08006804TEST_F(InputDispatcherMonitorTest, ReceivesMotionEvents) {
Chris Yea209fde2020-07-22 13:54:51 -07006805 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07006806 sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher,
6807 "Fake Window", ADISPLAY_ID_DEFAULT);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07006808 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Michael Wright3a240c42019-12-10 20:53:41 +00006809
Prabir Pradhanfb549072023-10-05 19:17:36 +00006810 FakeMonitorReceiver monitor = FakeMonitorReceiver(*mDispatcher, "M_1", ADISPLAY_ID_DEFAULT);
Michael Wright3a240c42019-12-10 20:53:41 +00006811
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08006812 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07006813 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT))
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08006814 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
Michael Wright3a240c42019-12-10 20:53:41 +00006815 window->consumeMotionDown(ADISPLAY_ID_DEFAULT);
chaviwd1c23182019-12-20 18:44:56 -08006816 monitor.consumeMotionDown(ADISPLAY_ID_DEFAULT);
Michael Wright3a240c42019-12-10 20:53:41 +00006817}
6818
Prabir Pradhan1376fcd2022-01-21 09:56:35 -08006819TEST_F(InputDispatcherMonitorTest, MonitorCannotPilferPointers) {
Prabir Pradhanfb549072023-10-05 19:17:36 +00006820 FakeMonitorReceiver monitor = FakeMonitorReceiver(*mDispatcher, "M_1", ADISPLAY_ID_DEFAULT);
Michael Wright3a240c42019-12-10 20:53:41 +00006821
Chris Yea209fde2020-07-22 13:54:51 -07006822 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07006823 sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher,
6824 "Fake Window", ADISPLAY_ID_DEFAULT);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07006825 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Michael Wright3a240c42019-12-10 20:53:41 +00006826
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08006827 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07006828 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT))
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08006829 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
chaviwd1c23182019-12-20 18:44:56 -08006830 monitor.consumeMotionDown(ADISPLAY_ID_DEFAULT);
Prabir Pradhan1376fcd2022-01-21 09:56:35 -08006831 window->consumeMotionDown(ADISPLAY_ID_DEFAULT);
Michael Wright3a240c42019-12-10 20:53:41 +00006832
Prabir Pradhan1376fcd2022-01-21 09:56:35 -08006833 // Pilfer pointers from the monitor.
6834 // This should not do anything and the window should continue to receive events.
6835 EXPECT_NE(OK, mDispatcher->pilferPointers(monitor.getToken()));
Michael Wright3a240c42019-12-10 20:53:41 +00006836
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08006837 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07006838 injectMotionEvent(*mDispatcher, AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN,
Prabir Pradhan1376fcd2022-01-21 09:56:35 -08006839 ADISPLAY_ID_DEFAULT))
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08006840 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
Prabir Pradhan1376fcd2022-01-21 09:56:35 -08006841
6842 monitor.consumeMotionMove(ADISPLAY_ID_DEFAULT);
6843 window->consumeMotionMove(ADISPLAY_ID_DEFAULT);
Michael Wright3a240c42019-12-10 20:53:41 +00006844}
6845
Prabir Pradhan1376fcd2022-01-21 09:56:35 -08006846TEST_F(InputDispatcherMonitorTest, NoWindowTransform) {
Evan Rosky84f07f02021-04-16 10:42:42 -07006847 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07006848 sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher,
6849 "Fake Window", ADISPLAY_ID_DEFAULT);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07006850 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Evan Rosky84f07f02021-04-16 10:42:42 -07006851 window->setWindowOffset(20, 40);
6852 window->setWindowTransform(0, 1, -1, 0);
6853
Prabir Pradhanfb549072023-10-05 19:17:36 +00006854 FakeMonitorReceiver monitor = FakeMonitorReceiver(*mDispatcher, "M_1", ADISPLAY_ID_DEFAULT);
Evan Rosky84f07f02021-04-16 10:42:42 -07006855
6856 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07006857 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT))
Evan Rosky84f07f02021-04-16 10:42:42 -07006858 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
6859 window->consumeMotionDown(ADISPLAY_ID_DEFAULT);
Siarhei Vishniakoud3061ab2023-12-18 20:41:08 -08006860 std::unique_ptr<MotionEvent> event = monitor.consumeMotion();
6861 ASSERT_NE(nullptr, event);
Evan Rosky84f07f02021-04-16 10:42:42 -07006862 // Even though window has transform, gesture monitor must not.
6863 ASSERT_EQ(ui::Transform(), event->getTransform());
6864}
6865
Prabir Pradhan1376fcd2022-01-21 09:56:35 -08006866TEST_F(InputDispatcherMonitorTest, InjectionFailsWithNoWindow) {
Arthur Hungb3307ee2021-10-14 10:57:37 +00006867 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
Prabir Pradhanfb549072023-10-05 19:17:36 +00006868 FakeMonitorReceiver monitor = FakeMonitorReceiver(*mDispatcher, "M_1", ADISPLAY_ID_DEFAULT);
Arthur Hungb3307ee2021-10-14 10:57:37 +00006869
Prabir Pradhan1376fcd2022-01-21 09:56:35 -08006870 ASSERT_EQ(InputEventInjectionResult::FAILED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07006871 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT))
Prabir Pradhan1376fcd2022-01-21 09:56:35 -08006872 << "Injection should fail if there is a monitor, but no touchable window";
6873 monitor.assertNoEvents();
Arthur Hungb3307ee2021-10-14 10:57:37 +00006874}
6875
Linnan Lid8150952024-01-26 18:07:17 +00006876/**
6877 * Two displays
6878 * The first monitor has a foreground window, a monitor
6879 * The second window has only one monitor.
6880 * We first inject a Down event into the first display, this injection should succeed and both
6881 * the foreground window and monitor should receive a down event, then inject a Down event into
6882 * the second display as well, this injection should fail, at this point, the first display
6883 * window and monitor should not receive a cancel or any other event.
6884 * Continue to inject Move and UP events to the first display, the events should be received
6885 * normally by the foreground window and monitor.
6886 */
6887TEST_F(InputDispatcherMonitorTest, MonitorTouchIsNotCanceledWhenAnotherEmptyDisplayReceiveEvents) {
6888 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
6889 sp<FakeWindowHandle> window =
6890 sp<FakeWindowHandle>::make(application, mDispatcher, "Foreground", ADISPLAY_ID_DEFAULT);
6891
6892 FakeMonitorReceiver monitor = FakeMonitorReceiver(*mDispatcher, "M_1", ADISPLAY_ID_DEFAULT);
6893 FakeMonitorReceiver secondMonitor = FakeMonitorReceiver(*mDispatcher, "M_2", SECOND_DISPLAY_ID);
6894
6895 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
6896 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
6897 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
6898 {100, 200}))
6899 << "The down event injected into the first display should succeed";
6900
6901 window->consumeMotionDown();
6902 monitor.consumeMotionDown(ADISPLAY_ID_DEFAULT);
Linnan Lid8150952024-01-26 18:07:17 +00006903
6904 ASSERT_EQ(InputEventInjectionResult::FAILED,
6905 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, SECOND_DISPLAY_ID,
6906 {100, 200}))
Prabir Pradhana0d43d42024-01-30 00:27:08 +00006907 << "The down event injected into the second display should fail since there's no "
6908 "touchable window";
Linnan Lid8150952024-01-26 18:07:17 +00006909
6910 // Continue to inject event to first display.
6911 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
6912 injectMotionEvent(*mDispatcher, AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN,
6913 ADISPLAY_ID_DEFAULT, {110, 220}))
6914 << "The move event injected into the first display should succeed";
6915
6916 window->consumeMotionMove();
6917 monitor.consumeMotionMove(ADISPLAY_ID_DEFAULT);
Linnan Lid8150952024-01-26 18:07:17 +00006918
6919 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
6920 injectMotionUp(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
6921 {110, 220}))
6922 << "The up event injected into the first display should succeed";
6923
6924 window->consumeMotionUp();
6925 monitor.consumeMotionUp(ADISPLAY_ID_DEFAULT);
Prabir Pradhana0d43d42024-01-30 00:27:08 +00006926
6927 window->assertNoEvents();
6928 monitor.assertNoEvents();
Linnan Lid8150952024-01-26 18:07:17 +00006929 secondMonitor.assertNoEvents();
6930}
6931
6932/**
6933 * Two displays
6934 * There is a monitor and foreground window on each display.
6935 * First, we inject down events into each of the two displays, at this point, the foreground windows
6936 * and monitors on both displays should receive down events.
6937 * At this point, the foreground window of the second display goes away, the gone window should
6938 * receive the cancel event, and the other windows and monitors should not receive any events.
6939 * Inject a move event into the second display. At this point, the injection should fail because
6940 * the second display no longer has a foreground window. At this point, the monitor on the second
6941 * display should receive a cancel event, and any windows or monitors on the first display should
6942 * not receive any events, and any subsequent injection of events into the second display should
6943 * also fail.
6944 * Continue to inject events into the first display, and the events should all be injected
6945 * successfully and received normally.
6946 */
6947TEST_F(InputDispatcherMonitorTest, MonitorTouchIsNotCancelWhenAnotherDisplayMonitorTouchCanceled) {
6948 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
6949 sp<FakeWindowHandle> window =
6950 sp<FakeWindowHandle>::make(application, mDispatcher, "Foreground", ADISPLAY_ID_DEFAULT);
6951 sp<FakeWindowHandle> secondWindow =
6952 sp<FakeWindowHandle>::make(application, mDispatcher, "SecondForeground",
6953 SECOND_DISPLAY_ID);
6954
6955 FakeMonitorReceiver monitor = FakeMonitorReceiver(*mDispatcher, "M_1", ADISPLAY_ID_DEFAULT);
6956 FakeMonitorReceiver secondMonitor = FakeMonitorReceiver(*mDispatcher, "M_2", SECOND_DISPLAY_ID);
6957
6958 // There is a foreground window on both displays.
6959 mDispatcher->onWindowInfosChanged({{*window->getInfo(), *secondWindow->getInfo()}, {}, 0, 0});
6960 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
6961 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
6962 {100, 200}))
6963 << "The down event injected into the first display should succeed";
6964
6965 window->consumeMotionDown(ADISPLAY_ID_DEFAULT);
6966 monitor.consumeMotionDown(ADISPLAY_ID_DEFAULT);
Linnan Lid8150952024-01-26 18:07:17 +00006967
6968 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
6969 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, SECOND_DISPLAY_ID,
6970 {100, 200}))
6971 << "The down event injected into the second display should succeed";
6972
Linnan Lid8150952024-01-26 18:07:17 +00006973 secondWindow->consumeMotionDown(SECOND_DISPLAY_ID);
6974 secondMonitor.consumeMotionDown(SECOND_DISPLAY_ID);
6975
6976 // Now second window is gone away.
6977 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
6978
6979 // The gone window should receive a cancel, and the monitor on the second display should not
6980 // receive any events.
Linnan Lid8150952024-01-26 18:07:17 +00006981 secondWindow->consumeMotionCancel(SECOND_DISPLAY_ID);
6982 secondMonitor.assertNoEvents();
6983
6984 ASSERT_EQ(InputEventInjectionResult::FAILED,
6985 injectMotionEvent(*mDispatcher, AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN,
6986 SECOND_DISPLAY_ID, {110, 220}))
Prabir Pradhana0d43d42024-01-30 00:27:08 +00006987 << "The move event injected into the second display should fail because there's no "
6988 "touchable window";
Linnan Lid8150952024-01-26 18:07:17 +00006989 // Now the monitor on the second display should receive a cancel event.
6990 secondMonitor.consumeMotionCancel(SECOND_DISPLAY_ID);
Linnan Lid8150952024-01-26 18:07:17 +00006991
6992 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
6993 injectMotionEvent(*mDispatcher, AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN,
6994 ADISPLAY_ID_DEFAULT, {110, 200}))
6995 << "The move event injected into the first display should succeed";
6996
6997 window->consumeMotionMove();
6998 monitor.consumeMotionMove(ADISPLAY_ID_DEFAULT);
Linnan Lid8150952024-01-26 18:07:17 +00006999
7000 ASSERT_EQ(InputEventInjectionResult::FAILED,
Prabir Pradhana0d43d42024-01-30 00:27:08 +00007001 injectMotionUp(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, SECOND_DISPLAY_ID,
7002 {110, 220}))
7003 << "The up event injected into the second display should fail because there's no "
7004 "touchable window";
Linnan Lid8150952024-01-26 18:07:17 +00007005
7006 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
7007 injectMotionUp(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
7008 {110, 220}))
7009 << "The up event injected into the first display should succeed";
7010
7011 window->consumeMotionUp(ADISPLAY_ID_DEFAULT);
7012 monitor.consumeMotionUp(ADISPLAY_ID_DEFAULT);
Prabir Pradhana0d43d42024-01-30 00:27:08 +00007013
Linnan Lid8150952024-01-26 18:07:17 +00007014 window->assertNoEvents();
7015 monitor.assertNoEvents();
Prabir Pradhana0d43d42024-01-30 00:27:08 +00007016 secondWindow->assertNoEvents();
7017 secondMonitor.assertNoEvents();
Linnan Lid8150952024-01-26 18:07:17 +00007018}
7019
7020/**
7021 * One display with transform
7022 * There is a foreground window and a monitor on the display
7023 * Inject down event and move event sequentially, the foreground window and monitor can receive down
7024 * event and move event, then let the foreground window go away, the foreground window receives
7025 * cancel event, inject move event again, the monitor receives cancel event, all the events received
7026 * by the monitor should be with the same transform as the display
7027 */
7028TEST_F(InputDispatcherMonitorTest, MonitorTouchCancelEventWithDisplayTransform) {
7029 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
7030 sp<FakeWindowHandle> window =
7031 sp<FakeWindowHandle>::make(application, mDispatcher, "Foreground", ADISPLAY_ID_DEFAULT);
7032 FakeMonitorReceiver monitor = FakeMonitorReceiver(*mDispatcher, "M_1", ADISPLAY_ID_DEFAULT);
7033
7034 ui::Transform transform;
7035 transform.set({1.1, 2.2, 3.3, 4.4, 5.5, 6.6, 0, 0, 1});
7036
7037 gui::DisplayInfo displayInfo;
7038 displayInfo.displayId = ADISPLAY_ID_DEFAULT;
7039 displayInfo.transform = transform;
7040
7041 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {displayInfo}, 0, 0});
7042
7043 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
7044 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
7045 {100, 200}))
7046 << "The down event injected should succeed";
7047
7048 window->consumeMotionDown();
7049 std::unique_ptr<MotionEvent> downMotionEvent = monitor.consumeMotion();
7050 EXPECT_EQ(transform, downMotionEvent->getTransform());
7051 EXPECT_EQ(AMOTION_EVENT_ACTION_DOWN, downMotionEvent->getAction());
7052
7053 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
7054 injectMotionEvent(*mDispatcher, AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN,
7055 ADISPLAY_ID_DEFAULT, {110, 220}))
7056 << "The move event injected should succeed";
7057
7058 window->consumeMotionMove();
7059 std::unique_ptr<MotionEvent> moveMotionEvent = monitor.consumeMotion();
7060 EXPECT_EQ(transform, moveMotionEvent->getTransform());
7061 EXPECT_EQ(AMOTION_EVENT_ACTION_MOVE, moveMotionEvent->getAction());
7062
7063 // Let foreground window gone
7064 mDispatcher->onWindowInfosChanged({{}, {displayInfo}, 0, 0});
7065
Prabir Pradhana0d43d42024-01-30 00:27:08 +00007066 // Foreground window should receive a cancel event, but not the monitor.
Linnan Lid8150952024-01-26 18:07:17 +00007067 window->consumeMotionCancel();
Linnan Lid8150952024-01-26 18:07:17 +00007068
7069 ASSERT_EQ(InputEventInjectionResult::FAILED,
7070 injectMotionEvent(*mDispatcher, AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN,
7071 ADISPLAY_ID_DEFAULT, {110, 220}))
7072 << "The move event injected should failed";
7073 // Now foreground should not receive any events, but monitor should receive a cancel event
7074 // with transform that same as display's display.
Linnan Lid8150952024-01-26 18:07:17 +00007075 std::unique_ptr<MotionEvent> cancelMotionEvent = monitor.consumeMotion();
7076 EXPECT_EQ(transform, cancelMotionEvent->getTransform());
7077 EXPECT_EQ(ADISPLAY_ID_DEFAULT, cancelMotionEvent->getDisplayId());
7078 EXPECT_EQ(AMOTION_EVENT_ACTION_CANCEL, cancelMotionEvent->getAction());
7079
7080 // Other event inject to this display should fail.
7081 ASSERT_EQ(InputEventInjectionResult::FAILED,
7082 injectMotionEvent(*mDispatcher, AMOTION_EVENT_ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN,
7083 ADISPLAY_ID_DEFAULT, {110, 220}))
Prabir Pradhana0d43d42024-01-30 00:27:08 +00007084 << "The up event injected should fail because the touched window was removed";
Linnan Lid8150952024-01-26 18:07:17 +00007085 window->assertNoEvents();
7086 monitor.assertNoEvents();
7087}
7088
chaviw81e2bb92019-12-18 15:03:51 -08007089TEST_F(InputDispatcherTest, TestMoveEvent) {
Chris Yea209fde2020-07-22 13:54:51 -07007090 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07007091 sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher,
7092 "Fake Window", ADISPLAY_ID_DEFAULT);
chaviw81e2bb92019-12-18 15:03:51 -08007093
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07007094 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
chaviw81e2bb92019-12-18 15:03:51 -08007095
7096 NotifyMotionArgs motionArgs =
7097 generateMotionArgs(AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN,
7098 ADISPLAY_ID_DEFAULT);
7099
Prabir Pradhan678438e2023-04-13 19:32:51 +00007100 mDispatcher->notifyMotion(motionArgs);
chaviw81e2bb92019-12-18 15:03:51 -08007101 // Window should receive motion down event.
7102 window->consumeMotionDown(ADISPLAY_ID_DEFAULT);
7103
7104 motionArgs.action = AMOTION_EVENT_ACTION_MOVE;
Garfield Tanc51d1ba2020-01-28 13:24:04 -08007105 motionArgs.id += 1;
chaviw81e2bb92019-12-18 15:03:51 -08007106 motionArgs.eventTime = systemTime(SYSTEM_TIME_MONOTONIC);
7107 motionArgs.pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_X,
7108 motionArgs.pointerCoords[0].getX() - 10);
7109
Prabir Pradhan678438e2023-04-13 19:32:51 +00007110 mDispatcher->notifyMotion(motionArgs);
Prabir Pradhan7662a8d2023-12-15 01:58:14 +00007111 window->consumeMotionMove(ADISPLAY_ID_DEFAULT, /*expectedFlags=*/0);
chaviw81e2bb92019-12-18 15:03:51 -08007112}
7113
Siarhei Vishniakouf1035d42019-09-20 16:32:01 +01007114/**
7115 * Dispatcher has touch mode enabled by default. Typically, the policy overrides that value to
7116 * the device default right away. In the test scenario, we check both the default value,
7117 * and the action of enabling / disabling.
7118 */
7119TEST_F(InputDispatcherTest, TouchModeState_IsSentToApps) {
Chris Yea209fde2020-07-22 13:54:51 -07007120 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07007121 sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher,
7122 "Test window", ADISPLAY_ID_DEFAULT);
Antonio Kantekea47acb2021-12-23 12:41:25 -08007123 const WindowInfo& windowInfo = *window->getInfo();
Siarhei Vishniakouf1035d42019-09-20 16:32:01 +01007124
7125 // Set focused application.
7126 mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application);
Vishnu Nair47074b82020-08-14 11:54:47 -07007127 window->setFocusable(true);
Siarhei Vishniakouf1035d42019-09-20 16:32:01 +01007128
7129 SCOPED_TRACE("Check default value of touch mode");
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07007130 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Vishnu Nair958da932020-08-21 17:12:37 -07007131 setFocusedWindow(window);
Harry Cutts33476232023-01-30 19:57:29 +00007132 window->consumeFocusEvent(/*hasFocus=*/true, /*inTouchMode=*/true);
Siarhei Vishniakouf1035d42019-09-20 16:32:01 +01007133
7134 SCOPED_TRACE("Remove the window to trigger focus loss");
Vishnu Nair47074b82020-08-14 11:54:47 -07007135 window->setFocusable(false);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07007136 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Harry Cutts33476232023-01-30 19:57:29 +00007137 window->consumeFocusEvent(/*hasFocus=*/false, /*inTouchMode=*/true);
Siarhei Vishniakouf1035d42019-09-20 16:32:01 +01007138
7139 SCOPED_TRACE("Disable touch mode");
Antonio Kantekea47acb2021-12-23 12:41:25 -08007140 mDispatcher->setInTouchMode(false, windowInfo.ownerPid, windowInfo.ownerUid,
Harry Cutts33476232023-01-30 19:57:29 +00007141 /*hasPermission=*/true, ADISPLAY_ID_DEFAULT);
Antonio Kantekf16f2832021-09-28 04:39:20 +00007142 window->consumeTouchModeEvent(false);
Vishnu Nair47074b82020-08-14 11:54:47 -07007143 window->setFocusable(true);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07007144 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Vishnu Nair958da932020-08-21 17:12:37 -07007145 setFocusedWindow(window);
Harry Cutts33476232023-01-30 19:57:29 +00007146 window->consumeFocusEvent(/*hasFocus=*/true, /*inTouchMode=*/false);
Siarhei Vishniakouf1035d42019-09-20 16:32:01 +01007147
7148 SCOPED_TRACE("Remove the window to trigger focus loss");
Vishnu Nair47074b82020-08-14 11:54:47 -07007149 window->setFocusable(false);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07007150 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Harry Cutts33476232023-01-30 19:57:29 +00007151 window->consumeFocusEvent(/*hasFocus=*/false, /*inTouchMode=*/false);
Siarhei Vishniakouf1035d42019-09-20 16:32:01 +01007152
7153 SCOPED_TRACE("Enable touch mode again");
Antonio Kantekea47acb2021-12-23 12:41:25 -08007154 mDispatcher->setInTouchMode(true, windowInfo.ownerPid, windowInfo.ownerUid,
Harry Cutts33476232023-01-30 19:57:29 +00007155 /*hasPermission=*/true, ADISPLAY_ID_DEFAULT);
Antonio Kantekf16f2832021-09-28 04:39:20 +00007156 window->consumeTouchModeEvent(true);
Vishnu Nair47074b82020-08-14 11:54:47 -07007157 window->setFocusable(true);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07007158 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Vishnu Nair958da932020-08-21 17:12:37 -07007159 setFocusedWindow(window);
Harry Cutts33476232023-01-30 19:57:29 +00007160 window->consumeFocusEvent(/*hasFocus=*/true, /*inTouchMode=*/true);
Siarhei Vishniakouf1035d42019-09-20 16:32:01 +01007161
7162 window->assertNoEvents();
7163}
7164
Gang Wange9087892020-01-07 12:17:14 -05007165TEST_F(InputDispatcherTest, VerifyInputEvent_KeyEvent) {
Chris Yea209fde2020-07-22 13:54:51 -07007166 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07007167 sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher,
7168 "Test window", ADISPLAY_ID_DEFAULT);
Gang Wange9087892020-01-07 12:17:14 -05007169
7170 mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application);
Vishnu Nair47074b82020-08-14 11:54:47 -07007171 window->setFocusable(true);
Gang Wange9087892020-01-07 12:17:14 -05007172
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07007173 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Vishnu Nair958da932020-08-21 17:12:37 -07007174 setFocusedWindow(window);
7175
Harry Cutts33476232023-01-30 19:57:29 +00007176 window->consumeFocusEvent(/*hasFocus=*/true, /*inTouchMode=*/true);
Gang Wange9087892020-01-07 12:17:14 -05007177
Prabir Pradhan678438e2023-04-13 19:32:51 +00007178 const NotifyKeyArgs keyArgs = generateKeyArgs(AKEY_EVENT_ACTION_DOWN);
7179 mDispatcher->notifyKey(keyArgs);
Gang Wange9087892020-01-07 12:17:14 -05007180
Siarhei Vishniakoud3061ab2023-12-18 20:41:08 -08007181 std::unique_ptr<KeyEvent> event = window->consumeKey();
7182 ASSERT_NE(event, nullptr);
7183 std::unique_ptr<VerifiedInputEvent> verified = mDispatcher->verifyInputEvent(*event);
Gang Wange9087892020-01-07 12:17:14 -05007184 ASSERT_NE(verified, nullptr);
7185 ASSERT_EQ(verified->type, VerifiedInputEvent::Type::KEY);
7186
7187 ASSERT_EQ(keyArgs.eventTime, verified->eventTimeNanos);
7188 ASSERT_EQ(keyArgs.deviceId, verified->deviceId);
7189 ASSERT_EQ(keyArgs.source, verified->source);
7190 ASSERT_EQ(keyArgs.displayId, verified->displayId);
7191
7192 const VerifiedKeyEvent& verifiedKey = static_cast<const VerifiedKeyEvent&>(*verified);
7193
7194 ASSERT_EQ(keyArgs.action, verifiedKey.action);
Gang Wange9087892020-01-07 12:17:14 -05007195 ASSERT_EQ(keyArgs.flags & VERIFIED_KEY_EVENT_FLAGS, verifiedKey.flags);
Siarhei Vishniakouf355bf92021-12-09 10:43:21 -08007196 ASSERT_EQ(keyArgs.downTime, verifiedKey.downTimeNanos);
Gang Wange9087892020-01-07 12:17:14 -05007197 ASSERT_EQ(keyArgs.keyCode, verifiedKey.keyCode);
7198 ASSERT_EQ(keyArgs.scanCode, verifiedKey.scanCode);
7199 ASSERT_EQ(keyArgs.metaState, verifiedKey.metaState);
7200 ASSERT_EQ(0, verifiedKey.repeatCount);
7201}
7202
Siarhei Vishniakou47040bf2020-02-28 15:03:13 -08007203TEST_F(InputDispatcherTest, VerifyInputEvent_MotionEvent) {
Chris Yea209fde2020-07-22 13:54:51 -07007204 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07007205 sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher,
7206 "Test window", ADISPLAY_ID_DEFAULT);
Siarhei Vishniakou47040bf2020-02-28 15:03:13 -08007207
7208 mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application);
7209
Prabir Pradhanb5cb9572021-09-24 06:35:16 -07007210 ui::Transform transform;
7211 transform.set({1.1, 2.2, 3.3, 4.4, 5.5, 6.6, 0, 0, 1});
7212
7213 gui::DisplayInfo displayInfo;
7214 displayInfo.displayId = ADISPLAY_ID_DEFAULT;
7215 displayInfo.transform = transform;
7216
Patrick Williamsd828f302023-04-28 17:52:08 -05007217 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {displayInfo}, 0, 0});
Siarhei Vishniakou47040bf2020-02-28 15:03:13 -08007218
Prabir Pradhan678438e2023-04-13 19:32:51 +00007219 const NotifyMotionArgs motionArgs =
Siarhei Vishniakou47040bf2020-02-28 15:03:13 -08007220 generateMotionArgs(AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN,
7221 ADISPLAY_ID_DEFAULT);
Prabir Pradhan678438e2023-04-13 19:32:51 +00007222 mDispatcher->notifyMotion(motionArgs);
Siarhei Vishniakou47040bf2020-02-28 15:03:13 -08007223
Siarhei Vishniakoud3061ab2023-12-18 20:41:08 -08007224 std::unique_ptr<MotionEvent> event = window->consumeMotionEvent();
7225 ASSERT_NE(nullptr, event);
7226 std::unique_ptr<VerifiedInputEvent> verified = mDispatcher->verifyInputEvent(*event);
Siarhei Vishniakou47040bf2020-02-28 15:03:13 -08007227 ASSERT_NE(verified, nullptr);
7228 ASSERT_EQ(verified->type, VerifiedInputEvent::Type::MOTION);
7229
7230 EXPECT_EQ(motionArgs.eventTime, verified->eventTimeNanos);
7231 EXPECT_EQ(motionArgs.deviceId, verified->deviceId);
7232 EXPECT_EQ(motionArgs.source, verified->source);
7233 EXPECT_EQ(motionArgs.displayId, verified->displayId);
7234
7235 const VerifiedMotionEvent& verifiedMotion = static_cast<const VerifiedMotionEvent&>(*verified);
7236
Prabir Pradhanb5cb9572021-09-24 06:35:16 -07007237 const vec2 rawXY =
7238 MotionEvent::calculateTransformedXY(motionArgs.source, transform,
7239 motionArgs.pointerCoords[0].getXYValue());
7240 EXPECT_EQ(rawXY.x, verifiedMotion.rawX);
7241 EXPECT_EQ(rawXY.y, verifiedMotion.rawY);
Siarhei Vishniakou47040bf2020-02-28 15:03:13 -08007242 EXPECT_EQ(motionArgs.action & AMOTION_EVENT_ACTION_MASK, verifiedMotion.actionMasked);
Siarhei Vishniakou47040bf2020-02-28 15:03:13 -08007243 EXPECT_EQ(motionArgs.flags & VERIFIED_MOTION_EVENT_FLAGS, verifiedMotion.flags);
Siarhei Vishniakouf355bf92021-12-09 10:43:21 -08007244 EXPECT_EQ(motionArgs.downTime, verifiedMotion.downTimeNanos);
Siarhei Vishniakou47040bf2020-02-28 15:03:13 -08007245 EXPECT_EQ(motionArgs.metaState, verifiedMotion.metaState);
7246 EXPECT_EQ(motionArgs.buttonState, verifiedMotion.buttonState);
7247}
7248
chaviw09c8d2d2020-08-24 15:48:26 -07007249/**
7250 * Ensure that separate calls to sign the same data are generating the same key.
7251 * We avoid asserting against INVALID_HMAC. Since the key is random, there is a non-zero chance
7252 * that a specific key and data combination would produce INVALID_HMAC, which would cause flaky
7253 * tests.
7254 */
7255TEST_F(InputDispatcherTest, GeneratedHmac_IsConsistent) {
7256 KeyEvent event = getTestKeyEvent();
7257 VerifiedKeyEvent verifiedEvent = verifiedKeyEventFromKeyEvent(event);
7258
7259 std::array<uint8_t, 32> hmac1 = mDispatcher->sign(verifiedEvent);
7260 std::array<uint8_t, 32> hmac2 = mDispatcher->sign(verifiedEvent);
7261 ASSERT_EQ(hmac1, hmac2);
7262}
7263
7264/**
7265 * Ensure that changes in VerifiedKeyEvent produce a different hmac.
7266 */
7267TEST_F(InputDispatcherTest, GeneratedHmac_ChangesWhenFieldsChange) {
7268 KeyEvent event = getTestKeyEvent();
7269 VerifiedKeyEvent verifiedEvent = verifiedKeyEventFromKeyEvent(event);
7270 std::array<uint8_t, 32> initialHmac = mDispatcher->sign(verifiedEvent);
7271
7272 verifiedEvent.deviceId += 1;
7273 ASSERT_NE(initialHmac, mDispatcher->sign(verifiedEvent));
7274
7275 verifiedEvent.source += 1;
7276 ASSERT_NE(initialHmac, mDispatcher->sign(verifiedEvent));
7277
7278 verifiedEvent.eventTimeNanos += 1;
7279 ASSERT_NE(initialHmac, mDispatcher->sign(verifiedEvent));
7280
7281 verifiedEvent.displayId += 1;
7282 ASSERT_NE(initialHmac, mDispatcher->sign(verifiedEvent));
7283
7284 verifiedEvent.action += 1;
7285 ASSERT_NE(initialHmac, mDispatcher->sign(verifiedEvent));
7286
7287 verifiedEvent.downTimeNanos += 1;
7288 ASSERT_NE(initialHmac, mDispatcher->sign(verifiedEvent));
7289
7290 verifiedEvent.flags += 1;
7291 ASSERT_NE(initialHmac, mDispatcher->sign(verifiedEvent));
7292
7293 verifiedEvent.keyCode += 1;
7294 ASSERT_NE(initialHmac, mDispatcher->sign(verifiedEvent));
7295
7296 verifiedEvent.scanCode += 1;
7297 ASSERT_NE(initialHmac, mDispatcher->sign(verifiedEvent));
7298
7299 verifiedEvent.metaState += 1;
7300 ASSERT_NE(initialHmac, mDispatcher->sign(verifiedEvent));
7301
7302 verifiedEvent.repeatCount += 1;
7303 ASSERT_NE(initialHmac, mDispatcher->sign(verifiedEvent));
7304}
7305
Vishnu Nair958da932020-08-21 17:12:37 -07007306TEST_F(InputDispatcherTest, SetFocusedWindow) {
7307 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
7308 sp<FakeWindowHandle> windowTop =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07007309 sp<FakeWindowHandle>::make(application, mDispatcher, "Top", ADISPLAY_ID_DEFAULT);
Vishnu Nair958da932020-08-21 17:12:37 -07007310 sp<FakeWindowHandle> windowSecond =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07007311 sp<FakeWindowHandle>::make(application, mDispatcher, "Second", ADISPLAY_ID_DEFAULT);
Vishnu Nair958da932020-08-21 17:12:37 -07007312 mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application);
7313
7314 // Top window is also focusable but is not granted focus.
7315 windowTop->setFocusable(true);
7316 windowSecond->setFocusable(true);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07007317 mDispatcher->onWindowInfosChanged(
7318 {{*windowTop->getInfo(), *windowSecond->getInfo()}, {}, 0, 0});
Vishnu Nair958da932020-08-21 17:12:37 -07007319 setFocusedWindow(windowSecond);
7320
7321 windowSecond->consumeFocusEvent(true);
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07007322 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectKeyDown(*mDispatcher))
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08007323 << "Inject key event should return InputEventInjectionResult::SUCCEEDED";
Vishnu Nair958da932020-08-21 17:12:37 -07007324
7325 // Focused window should receive event.
7326 windowSecond->consumeKeyDown(ADISPLAY_ID_NONE);
7327 windowTop->assertNoEvents();
7328}
7329
7330TEST_F(InputDispatcherTest, SetFocusedWindow_DropRequestInvalidChannel) {
7331 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
7332 sp<FakeWindowHandle> window =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07007333 sp<FakeWindowHandle>::make(application, mDispatcher, "TestWindow", ADISPLAY_ID_DEFAULT);
Vishnu Nair958da932020-08-21 17:12:37 -07007334 mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application);
7335
7336 window->setFocusable(true);
7337 // Release channel for window is no longer valid.
7338 window->releaseChannel();
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07007339 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Vishnu Nair958da932020-08-21 17:12:37 -07007340 setFocusedWindow(window);
7341
7342 // Test inject a key down, should timeout.
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07007343 ASSERT_NO_FATAL_FAILURE(assertInjectedKeyTimesOut(*mDispatcher));
Vishnu Nair958da932020-08-21 17:12:37 -07007344
7345 // window channel is invalid, so it should not receive any input event.
7346 window->assertNoEvents();
7347}
7348
7349TEST_F(InputDispatcherTest, SetFocusedWindow_DropRequestNoFocusableWindow) {
7350 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
7351 sp<FakeWindowHandle> window =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07007352 sp<FakeWindowHandle>::make(application, mDispatcher, "TestWindow", ADISPLAY_ID_DEFAULT);
Prabir Pradhan76bdecb2022-01-31 11:14:15 -08007353 window->setFocusable(false);
Vishnu Nair958da932020-08-21 17:12:37 -07007354 mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application);
7355
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07007356 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Vishnu Nair958da932020-08-21 17:12:37 -07007357 setFocusedWindow(window);
7358
7359 // Test inject a key down, should timeout.
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07007360 ASSERT_NO_FATAL_FAILURE(assertInjectedKeyTimesOut(*mDispatcher));
Vishnu Nair958da932020-08-21 17:12:37 -07007361
Prabir Pradhan76bdecb2022-01-31 11:14:15 -08007362 // window is not focusable, so it should not receive any input event.
Vishnu Nair958da932020-08-21 17:12:37 -07007363 window->assertNoEvents();
7364}
7365
7366TEST_F(InputDispatcherTest, SetFocusedWindow_CheckFocusedToken) {
7367 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
7368 sp<FakeWindowHandle> windowTop =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07007369 sp<FakeWindowHandle>::make(application, mDispatcher, "Top", ADISPLAY_ID_DEFAULT);
Vishnu Nair958da932020-08-21 17:12:37 -07007370 sp<FakeWindowHandle> windowSecond =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07007371 sp<FakeWindowHandle>::make(application, mDispatcher, "Second", ADISPLAY_ID_DEFAULT);
Vishnu Nair958da932020-08-21 17:12:37 -07007372 mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application);
7373
7374 windowTop->setFocusable(true);
7375 windowSecond->setFocusable(true);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07007376 mDispatcher->onWindowInfosChanged(
7377 {{*windowTop->getInfo(), *windowSecond->getInfo()}, {}, 0, 0});
Vishnu Nair958da932020-08-21 17:12:37 -07007378 setFocusedWindow(windowTop);
7379 windowTop->consumeFocusEvent(true);
7380
Chavi Weingarten847e8512023-03-29 00:26:09 +00007381 windowTop->editInfo()->focusTransferTarget = windowSecond->getToken();
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07007382 mDispatcher->onWindowInfosChanged(
7383 {{*windowTop->getInfo(), *windowSecond->getInfo()}, {}, 0, 0});
Vishnu Nair958da932020-08-21 17:12:37 -07007384 windowSecond->consumeFocusEvent(true);
7385 windowTop->consumeFocusEvent(false);
7386
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07007387 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectKeyDown(*mDispatcher))
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08007388 << "Inject key event should return InputEventInjectionResult::SUCCEEDED";
Vishnu Nair958da932020-08-21 17:12:37 -07007389
7390 // Focused window should receive event.
7391 windowSecond->consumeKeyDown(ADISPLAY_ID_NONE);
7392}
7393
Chavi Weingarten847e8512023-03-29 00:26:09 +00007394TEST_F(InputDispatcherTest, SetFocusedWindow_TransferFocusTokenNotFocusable) {
Vishnu Nair958da932020-08-21 17:12:37 -07007395 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
7396 sp<FakeWindowHandle> windowTop =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07007397 sp<FakeWindowHandle>::make(application, mDispatcher, "Top", ADISPLAY_ID_DEFAULT);
Vishnu Nair958da932020-08-21 17:12:37 -07007398 sp<FakeWindowHandle> windowSecond =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07007399 sp<FakeWindowHandle>::make(application, mDispatcher, "Second", ADISPLAY_ID_DEFAULT);
Vishnu Nair958da932020-08-21 17:12:37 -07007400 mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application);
7401
7402 windowTop->setFocusable(true);
Chavi Weingarten847e8512023-03-29 00:26:09 +00007403 windowSecond->setFocusable(false);
7404 windowTop->editInfo()->focusTransferTarget = windowSecond->getToken();
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07007405 mDispatcher->onWindowInfosChanged(
7406 {{*windowTop->getInfo(), *windowSecond->getInfo()}, {}, 0, 0});
Chavi Weingarten847e8512023-03-29 00:26:09 +00007407 setFocusedWindow(windowTop);
7408 windowTop->consumeFocusEvent(true);
Vishnu Nair958da932020-08-21 17:12:37 -07007409
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07007410 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectKeyDown(*mDispatcher))
Chavi Weingarten847e8512023-03-29 00:26:09 +00007411 << "Inject key event should return InputEventInjectionResult::SUCCEEDED";
Vishnu Nair958da932020-08-21 17:12:37 -07007412
7413 // Event should be dropped.
Chavi Weingarten847e8512023-03-29 00:26:09 +00007414 windowTop->consumeKeyDown(ADISPLAY_ID_NONE);
Vishnu Nair958da932020-08-21 17:12:37 -07007415 windowSecond->assertNoEvents();
7416}
7417
7418TEST_F(InputDispatcherTest, SetFocusedWindow_DeferInvisibleWindow) {
7419 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
7420 sp<FakeWindowHandle> window =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07007421 sp<FakeWindowHandle>::make(application, mDispatcher, "TestWindow", ADISPLAY_ID_DEFAULT);
Vishnu Nair958da932020-08-21 17:12:37 -07007422 sp<FakeWindowHandle> previousFocusedWindow =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07007423 sp<FakeWindowHandle>::make(application, mDispatcher, "previousFocusedWindow",
7424 ADISPLAY_ID_DEFAULT);
Vishnu Nair958da932020-08-21 17:12:37 -07007425 mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application);
7426
7427 window->setFocusable(true);
7428 previousFocusedWindow->setFocusable(true);
7429 window->setVisible(false);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07007430 mDispatcher->onWindowInfosChanged(
7431 {{*window->getInfo(), *previousFocusedWindow->getInfo()}, {}, 0, 0});
Vishnu Nair958da932020-08-21 17:12:37 -07007432 setFocusedWindow(previousFocusedWindow);
7433 previousFocusedWindow->consumeFocusEvent(true);
7434
7435 // Requesting focus on invisible window takes focus from currently focused window.
7436 setFocusedWindow(window);
7437 previousFocusedWindow->consumeFocusEvent(false);
7438
7439 // Injected key goes to pending queue.
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08007440 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07007441 injectKey(*mDispatcher, AKEY_EVENT_ACTION_DOWN, /*repeatCount=*/0,
7442 ADISPLAY_ID_DEFAULT, InputEventInjectionSync::NONE));
Vishnu Nair958da932020-08-21 17:12:37 -07007443
7444 // Window does not get focus event or key down.
7445 window->assertNoEvents();
7446
7447 // Window becomes visible.
7448 window->setVisible(true);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07007449 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Vishnu Nair958da932020-08-21 17:12:37 -07007450
7451 // Window receives focus event.
7452 window->consumeFocusEvent(true);
7453 // Focused window receives key down.
7454 window->consumeKeyDown(ADISPLAY_ID_DEFAULT);
7455}
7456
Vishnu Nair599f1412021-06-21 10:39:58 -07007457TEST_F(InputDispatcherTest, DisplayRemoved) {
7458 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
7459 sp<FakeWindowHandle> window =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07007460 sp<FakeWindowHandle>::make(application, mDispatcher, "window", ADISPLAY_ID_DEFAULT);
Vishnu Nair599f1412021-06-21 10:39:58 -07007461 mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application);
7462
7463 // window is granted focus.
7464 window->setFocusable(true);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07007465 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Vishnu Nair599f1412021-06-21 10:39:58 -07007466 setFocusedWindow(window);
7467 window->consumeFocusEvent(true);
7468
7469 // When a display is removed window loses focus.
7470 mDispatcher->displayRemoved(ADISPLAY_ID_DEFAULT);
7471 window->consumeFocusEvent(false);
7472}
7473
Siarhei Vishniakou870ecec2020-12-09 08:07:46 -10007474/**
7475 * Launch two windows, with different owners. One window (slipperyExitWindow) has Flag::SLIPPERY,
7476 * and overlaps the other window, slipperyEnterWindow. The window 'slipperyExitWindow' is on top
7477 * of the 'slipperyEnterWindow'.
7478 *
7479 * Inject touch down into the top window. Upon receipt of the DOWN event, move the window in such
7480 * a way so that the touched location is no longer covered by the top window.
7481 *
7482 * Next, inject a MOVE event. Because the top window already moved earlier, this event is now
7483 * positioned over the bottom (slipperyEnterWindow) only. And because the top window had
7484 * Flag::SLIPPERY, this will cause the top window to lose the touch event (it will receive
7485 * ACTION_CANCEL instead), and the bottom window will receive a newly generated gesture (starting
7486 * with ACTION_DOWN).
7487 * Thus, the touch has been transferred from the top window into the bottom window, because the top
7488 * window moved itself away from the touched location and had Flag::SLIPPERY.
7489 *
7490 * Even though the top window moved away from the touched location, it is still obscuring the bottom
7491 * window. It's just not obscuring it at the touched location. That means, FLAG_WINDOW_IS_PARTIALLY_
7492 * OBSCURED should be set for the MotionEvent that reaches the bottom window.
7493 *
7494 * In this test, we ensure that the event received by the bottom window has
7495 * FLAG_WINDOW_IS_PARTIALLY_OBSCURED.
7496 */
7497TEST_F(InputDispatcherTest, SlipperyWindow_SetsFlagPartiallyObscured) {
Prabir Pradhanaeebeb42023-06-13 19:53:03 +00007498 constexpr gui::Pid SLIPPERY_PID{WINDOW_PID.val() + 1};
Prabir Pradhan8a5c41d2023-06-08 19:13:46 +00007499 constexpr gui::Uid SLIPPERY_UID{WINDOW_UID.val() + 1};
Siarhei Vishniakou870ecec2020-12-09 08:07:46 -10007500
7501 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
7502 mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application);
7503
7504 sp<FakeWindowHandle> slipperyExitWindow =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07007505 sp<FakeWindowHandle>::make(application, mDispatcher, "Top", ADISPLAY_ID_DEFAULT);
Prabir Pradhan4d5c52f2022-01-31 08:52:10 -08007506 slipperyExitWindow->setSlippery(true);
Siarhei Vishniakou870ecec2020-12-09 08:07:46 -10007507 // Make sure this one overlaps the bottom window
7508 slipperyExitWindow->setFrame(Rect(25, 25, 75, 75));
7509 // Change the owner uid/pid of the window so that it is considered to be occluding the bottom
7510 // one. Windows with the same owner are not considered to be occluding each other.
7511 slipperyExitWindow->setOwnerInfo(SLIPPERY_PID, SLIPPERY_UID);
7512
7513 sp<FakeWindowHandle> slipperyEnterWindow =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07007514 sp<FakeWindowHandle>::make(application, mDispatcher, "Second", ADISPLAY_ID_DEFAULT);
Siarhei Vishniakou870ecec2020-12-09 08:07:46 -10007515 slipperyExitWindow->setFrame(Rect(0, 0, 100, 100));
7516
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07007517 mDispatcher->onWindowInfosChanged(
7518 {{*slipperyExitWindow->getInfo(), *slipperyEnterWindow->getInfo()}, {}, 0, 0});
Siarhei Vishniakou870ecec2020-12-09 08:07:46 -10007519
7520 // Use notifyMotion instead of injecting to avoid dealing with injection permissions
Prabir Pradhan678438e2023-04-13 19:32:51 +00007521 mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_DOWN,
7522 AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
7523 {{50, 50}}));
Siarhei Vishniakou870ecec2020-12-09 08:07:46 -10007524 slipperyExitWindow->consumeMotionDown();
7525 slipperyExitWindow->setFrame(Rect(70, 70, 100, 100));
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07007526 mDispatcher->onWindowInfosChanged(
7527 {{*slipperyExitWindow->getInfo(), *slipperyEnterWindow->getInfo()}, {}, 0, 0});
Siarhei Vishniakou870ecec2020-12-09 08:07:46 -10007528
Prabir Pradhan678438e2023-04-13 19:32:51 +00007529 mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_MOVE,
7530 AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
7531 {{51, 51}}));
Siarhei Vishniakou870ecec2020-12-09 08:07:46 -10007532
7533 slipperyExitWindow->consumeMotionCancel();
7534
7535 slipperyEnterWindow->consumeMotionDown(ADISPLAY_ID_DEFAULT,
7536 AMOTION_EVENT_FLAG_WINDOW_IS_PARTIALLY_OBSCURED);
7537}
7538
Siarhei Vishniakouafa08cc2023-05-08 22:35:50 -07007539/**
7540 * Two windows, one on the left and another on the right. The left window is slippery. The right
7541 * window isn't eligible to receive touch because it specifies InputConfig::DROP_INPUT. When the
7542 * touch moves from the left window into the right window, the gesture should continue to go to the
7543 * left window. Touch shouldn't slip because the right window can't receive touches. This test
7544 * reproduces a crash.
7545 */
7546TEST_F(InputDispatcherTest, TouchSlippingIntoWindowThatDropsTouches) {
7547 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
7548
7549 sp<FakeWindowHandle> leftSlipperyWindow =
7550 sp<FakeWindowHandle>::make(application, mDispatcher, "Left", ADISPLAY_ID_DEFAULT);
7551 leftSlipperyWindow->setSlippery(true);
7552 leftSlipperyWindow->setFrame(Rect(0, 0, 100, 100));
7553
7554 sp<FakeWindowHandle> rightDropTouchesWindow =
7555 sp<FakeWindowHandle>::make(application, mDispatcher, "Right", ADISPLAY_ID_DEFAULT);
7556 rightDropTouchesWindow->setFrame(Rect(100, 0, 200, 100));
7557 rightDropTouchesWindow->setDropInput(true);
7558
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07007559 mDispatcher->onWindowInfosChanged(
7560 {{*leftSlipperyWindow->getInfo(), *rightDropTouchesWindow->getInfo()}, {}, 0, 0});
Siarhei Vishniakouafa08cc2023-05-08 22:35:50 -07007561
7562 // Start touch in the left window
7563 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
7564 .pointer(PointerBuilder(0, ToolType::FINGER).x(50).y(50))
7565 .build());
7566 leftSlipperyWindow->consumeMotionDown();
7567
7568 // And move it into the right window
7569 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN)
7570 .pointer(PointerBuilder(0, ToolType::FINGER).x(150).y(50))
7571 .build());
7572
7573 // Since the right window isn't eligible to receive input, touch does not slip.
7574 // The left window continues to receive the gesture.
7575 leftSlipperyWindow->consumeMotionEvent(WithMotionAction(ACTION_MOVE));
7576 rightDropTouchesWindow->assertNoEvents();
7577}
7578
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -07007579/**
7580 * A single window is on screen first. Touch is injected into that window. Next, a second window
7581 * appears. Since the first window is slippery, touch will move from the first window to the second.
7582 */
7583TEST_F(InputDispatcherTest, InjectedTouchSlips) {
7584 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
7585 sp<FakeWindowHandle> originalWindow =
7586 sp<FakeWindowHandle>::make(application, mDispatcher, "Original", ADISPLAY_ID_DEFAULT);
7587 originalWindow->setFrame(Rect(0, 0, 200, 200));
7588 originalWindow->setSlippery(true);
7589
7590 sp<FakeWindowHandle> appearingWindow =
7591 sp<FakeWindowHandle>::make(application, mDispatcher, "Appearing", ADISPLAY_ID_DEFAULT);
7592 appearingWindow->setFrame(Rect(0, 0, 200, 200));
7593
7594 mDispatcher->onWindowInfosChanged({{*originalWindow->getInfo()}, {}, 0, 0});
7595
7596 // Touch down on the original window
7597 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
7598 injectMotionEvent(*mDispatcher,
7599 MotionEventBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
7600 .pointer(PointerBuilder(1, ToolType::FINGER).x(100).y(100))
7601 .build()));
7602 originalWindow->consumeMotionEvent(WithMotionAction(ACTION_DOWN));
7603
7604 // Now, a new window appears. This could be, for example, a notification shade that appears
7605 // after user starts to drag down on the launcher window.
7606 mDispatcher->onWindowInfosChanged(
7607 {{*appearingWindow->getInfo(), *originalWindow->getInfo()}, {}, 0, 0});
7608 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
7609 injectMotionEvent(*mDispatcher,
7610 MotionEventBuilder(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN)
7611 .pointer(PointerBuilder(1, ToolType::FINGER).x(110).y(110))
7612 .build()));
7613 originalWindow->consumeMotionEvent(WithMotionAction(ACTION_CANCEL));
7614 appearingWindow->consumeMotionEvent(WithMotionAction(ACTION_DOWN));
7615 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
7616 injectMotionEvent(*mDispatcher,
7617 MotionEventBuilder(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN)
7618 .pointer(PointerBuilder(1, ToolType::FINGER).x(120).y(120))
7619 .build()));
7620 appearingWindow->consumeMotionEvent(WithMotionAction(ACTION_MOVE));
7621
7622 originalWindow->assertNoEvents();
7623 appearingWindow->assertNoEvents();
7624}
7625
Linnan Li49b2b202024-04-12 12:46:40 +08007626/**
7627 * Three windows:
7628 * - left window, which has FLAG_SLIPPERY, so it supports slippery exit
7629 * - right window
7630 * - spy window
7631 * The three windows do not overlap.
7632 *
7633 * We have two devices reporting events:
7634 * - Device A reports ACTION_DOWN, which lands in the left window
7635 * - Device B reports ACTION_DOWN, which lands in the spy window.
7636 * - Now, device B reports ACTION_MOVE events which move to the right window.
7637 *
7638 * The right window should not receive any events because the spy window is not a foreground window,
7639 * and also it does not support slippery touches.
7640 */
7641TEST_F(InputDispatcherTest, MultiDeviceSpyWindowSlipTest) {
7642 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
7643 sp<FakeWindowHandle> leftWindow =
7644 sp<FakeWindowHandle>::make(application, mDispatcher, "Left window",
7645 ADISPLAY_ID_DEFAULT);
7646 leftWindow->setFrame(Rect(0, 0, 100, 100));
7647 leftWindow->setSlippery(true);
7648
7649 sp<FakeWindowHandle> rightWindow =
7650 sp<FakeWindowHandle>::make(application, mDispatcher, "Right window",
7651 ADISPLAY_ID_DEFAULT);
7652 rightWindow->setFrame(Rect(100, 0, 200, 100));
7653
7654 sp<FakeWindowHandle> spyWindow =
7655 sp<FakeWindowHandle>::make(application, mDispatcher, "Spy Window", ADISPLAY_ID_DEFAULT);
7656 spyWindow->setFrame(Rect(200, 0, 300, 100));
7657 spyWindow->setSpy(true);
7658 spyWindow->setTrustedOverlay(true);
7659
7660 mDispatcher->onWindowInfosChanged(
7661 {{*leftWindow->getInfo(), *rightWindow->getInfo(), *spyWindow->getInfo()}, {}, 0, 0});
7662
7663 const DeviceId deviceA = 9;
7664 const DeviceId deviceB = 3;
7665
7666 // Tap on left window with device A
7667 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
7668 .pointer(PointerBuilder(0, ToolType::FINGER).x(50).y(50))
7669 .deviceId(deviceA)
7670 .build());
7671 leftWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(deviceA)));
7672
7673 // Tap on spy window with device B
7674 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
7675 .pointer(PointerBuilder(0, ToolType::FINGER).x(250).y(50))
7676 .deviceId(deviceB)
7677 .build());
7678 spyWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(deviceB)));
7679
7680 // Move to right window with device B. Touches should not slip to the right window, because spy
7681 // window is not a foreground window, and it does not have FLAG_SLIPPERY
7682 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN)
7683 .pointer(PointerBuilder(0, ToolType::FINGER).x(150).y(50))
7684 .deviceId(deviceB)
7685 .build());
7686 leftWindow->assertNoEvents();
7687 rightWindow->assertNoEvents();
7688 spyWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(deviceB)));
7689}
7690
7691/**
7692 * Three windows arranged horizontally and without any overlap.
7693 * The left and right windows have FLAG_SLIPPERY. The middle window does not have any special flags.
7694 *
7695 * We have two devices reporting events:
7696 * - Device A reports ACTION_DOWN which lands in the left window
7697 * - Device B reports ACTION_DOWN which lands in the right window
7698 * - Device B reports ACTION_MOVE that shifts to the middle window.
7699 * This should cause touches for Device B to slip from the right window to the middle window.
7700 * The right window should receive ACTION_CANCEL for device B and the
7701 * middle window should receive down event for Device B.
7702 * If device B reports more ACTION_MOVE events, the middle window should receive remaining events.
7703 */
7704TEST_F(InputDispatcherTest, MultiDeviceSlipperyWindowTest) {
7705 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
7706 sp<FakeWindowHandle> leftWindow =
7707 sp<FakeWindowHandle>::make(application, mDispatcher, "Left window",
7708 ADISPLAY_ID_DEFAULT);
7709 leftWindow->setFrame(Rect(0, 0, 100, 100));
7710 leftWindow->setSlippery(true);
7711
7712 sp<FakeWindowHandle> middleWindow =
7713 sp<FakeWindowHandle>::make(application, mDispatcher, "middle window",
7714 ADISPLAY_ID_DEFAULT);
7715 middleWindow->setFrame(Rect(100, 0, 200, 100));
7716
7717 sp<FakeWindowHandle> rightWindow =
7718 sp<FakeWindowHandle>::make(application, mDispatcher, "Right window",
7719 ADISPLAY_ID_DEFAULT);
7720 rightWindow->setFrame(Rect(200, 0, 300, 100));
7721 rightWindow->setSlippery(true);
7722
7723 mDispatcher->onWindowInfosChanged(
7724 {{*leftWindow->getInfo(), *middleWindow->getInfo(), *rightWindow->getInfo()},
7725 {},
7726 0,
7727 0});
7728
7729 const DeviceId deviceA = 9;
7730 const DeviceId deviceB = 3;
7731
7732 // Tap on left window with device A
7733 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
7734 .pointer(PointerBuilder(0, ToolType::FINGER).x(50).y(50))
7735 .deviceId(deviceA)
7736 .build());
7737 leftWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(deviceA)));
7738
7739 // Tap on right window with device B
7740 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
7741 .pointer(PointerBuilder(0, ToolType::FINGER).x(250).y(50))
7742 .deviceId(deviceB)
7743 .build());
7744 rightWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(deviceB)));
7745
7746 // Move to middle window with device B. Touches should slip to middle window, because right
7747 // window is a foreground window that's associated with device B and has FLAG_SLIPPERY.
7748 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN)
7749 .pointer(PointerBuilder(0, ToolType::FINGER).x(150).y(50))
7750 .deviceId(deviceB)
7751 .build());
7752 rightWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_CANCEL), WithDeviceId(deviceB)));
7753 middleWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(deviceB)));
7754
7755 // Move to middle window with device A. Touches should slip to middle window, because left
7756 // window is a foreground window that's associated with device A and has FLAG_SLIPPERY.
7757 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN)
7758 .pointer(PointerBuilder(0, ToolType::FINGER).x(150).y(50))
7759 .deviceId(deviceA)
7760 .build());
7761 leftWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_CANCEL), WithDeviceId(deviceA)));
7762 middleWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(deviceA)));
7763
7764 // Ensure that middle window can receive the remaining move events.
7765 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN)
7766 .pointer(PointerBuilder(0, ToolType::FINGER).x(151).y(51))
7767 .deviceId(deviceB)
7768 .build());
7769 leftWindow->assertNoEvents();
7770 middleWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(deviceB)));
7771 rightWindow->assertNoEvents();
7772}
7773
Prabir Pradhan8ede1d12023-05-08 19:37:44 +00007774TEST_F(InputDispatcherTest, NotifiesDeviceInteractionsWithMotions) {
Prabir Pradhan8a5c41d2023-06-08 19:13:46 +00007775 using Uid = gui::Uid;
Prabir Pradhan8ede1d12023-05-08 19:37:44 +00007776 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
7777
7778 sp<FakeWindowHandle> leftWindow =
7779 sp<FakeWindowHandle>::make(application, mDispatcher, "Left", ADISPLAY_ID_DEFAULT);
7780 leftWindow->setFrame(Rect(0, 0, 100, 100));
Prabir Pradhanaeebeb42023-06-13 19:53:03 +00007781 leftWindow->setOwnerInfo(gui::Pid{1}, Uid{101});
Prabir Pradhan8ede1d12023-05-08 19:37:44 +00007782
7783 sp<FakeWindowHandle> rightSpy =
7784 sp<FakeWindowHandle>::make(application, mDispatcher, "Right spy", ADISPLAY_ID_DEFAULT);
7785 rightSpy->setFrame(Rect(100, 0, 200, 100));
Prabir Pradhanaeebeb42023-06-13 19:53:03 +00007786 rightSpy->setOwnerInfo(gui::Pid{2}, Uid{102});
Prabir Pradhan8ede1d12023-05-08 19:37:44 +00007787 rightSpy->setSpy(true);
7788 rightSpy->setTrustedOverlay(true);
7789
7790 sp<FakeWindowHandle> rightWindow =
7791 sp<FakeWindowHandle>::make(application, mDispatcher, "Right", ADISPLAY_ID_DEFAULT);
7792 rightWindow->setFrame(Rect(100, 0, 200, 100));
Prabir Pradhanaeebeb42023-06-13 19:53:03 +00007793 rightWindow->setOwnerInfo(gui::Pid{3}, Uid{103});
Prabir Pradhan8ede1d12023-05-08 19:37:44 +00007794
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07007795 mDispatcher->onWindowInfosChanged(
7796 {{*rightSpy->getInfo(), *rightWindow->getInfo(), *leftWindow->getInfo()}, {}, 0, 0});
Prabir Pradhan8ede1d12023-05-08 19:37:44 +00007797
7798 // Touch in the left window
7799 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
7800 .pointer(PointerBuilder(0, ToolType::FINGER).x(50).y(50))
7801 .build());
7802 ASSERT_NO_FATAL_FAILURE(leftWindow->consumeMotionDown());
7803 mDispatcher->waitForIdle();
Prabir Pradhan8a5c41d2023-06-08 19:13:46 +00007804 ASSERT_NO_FATAL_FAILURE(
7805 mFakePolicy->assertNotifyDeviceInteractionWasCalled(DEVICE_ID, {Uid{101}}));
Prabir Pradhan8ede1d12023-05-08 19:37:44 +00007806
7807 // Touch another finger over the right windows
7808 mDispatcher->notifyMotion(MotionArgsBuilder(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
7809 .pointer(PointerBuilder(0, ToolType::FINGER).x(50).y(50))
7810 .pointer(PointerBuilder(1, ToolType::FINGER).x(150).y(50))
7811 .build());
7812 ASSERT_NO_FATAL_FAILURE(rightSpy->consumeMotionDown());
7813 ASSERT_NO_FATAL_FAILURE(rightWindow->consumeMotionDown());
7814 ASSERT_NO_FATAL_FAILURE(leftWindow->consumeMotionMove());
7815 mDispatcher->waitForIdle();
7816 ASSERT_NO_FATAL_FAILURE(
Prabir Pradhan8a5c41d2023-06-08 19:13:46 +00007817 mFakePolicy->assertNotifyDeviceInteractionWasCalled(DEVICE_ID,
7818 {Uid{101}, Uid{102}, Uid{103}}));
Prabir Pradhan8ede1d12023-05-08 19:37:44 +00007819
7820 // Release finger over left window. The UP actions are not treated as device interaction.
7821 // The windows that did not receive the UP pointer will receive MOVE events, but since this
7822 // is part of the UP action, we do not treat this as device interaction.
7823 mDispatcher->notifyMotion(MotionArgsBuilder(POINTER_0_UP, AINPUT_SOURCE_TOUCHSCREEN)
7824 .pointer(PointerBuilder(0, ToolType::FINGER).x(50).y(50))
7825 .pointer(PointerBuilder(1, ToolType::FINGER).x(150).y(50))
7826 .build());
7827 ASSERT_NO_FATAL_FAILURE(leftWindow->consumeMotionUp());
7828 ASSERT_NO_FATAL_FAILURE(rightSpy->consumeMotionMove());
7829 ASSERT_NO_FATAL_FAILURE(rightWindow->consumeMotionMove());
7830 mDispatcher->waitForIdle();
7831 ASSERT_NO_FATAL_FAILURE(mFakePolicy->assertNotifyDeviceInteractionWasNotCalled());
7832
7833 // Move remaining finger
7834 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN)
7835 .pointer(PointerBuilder(1, ToolType::FINGER).x(150).y(50))
7836 .build());
7837 ASSERT_NO_FATAL_FAILURE(rightSpy->consumeMotionMove());
7838 ASSERT_NO_FATAL_FAILURE(rightWindow->consumeMotionMove());
7839 mDispatcher->waitForIdle();
7840 ASSERT_NO_FATAL_FAILURE(
Prabir Pradhan8a5c41d2023-06-08 19:13:46 +00007841 mFakePolicy->assertNotifyDeviceInteractionWasCalled(DEVICE_ID, {Uid{102}, Uid{103}}));
Prabir Pradhan8ede1d12023-05-08 19:37:44 +00007842
7843 // Release all fingers
7844 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN)
7845 .pointer(PointerBuilder(1, ToolType::FINGER).x(150).y(50))
7846 .build());
7847 ASSERT_NO_FATAL_FAILURE(rightSpy->consumeMotionUp());
7848 ASSERT_NO_FATAL_FAILURE(rightWindow->consumeMotionUp());
7849 mDispatcher->waitForIdle();
7850 ASSERT_NO_FATAL_FAILURE(mFakePolicy->assertNotifyDeviceInteractionWasNotCalled());
7851}
7852
7853TEST_F(InputDispatcherTest, NotifiesDeviceInteractionsWithKeys) {
7854 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
7855
7856 sp<FakeWindowHandle> window =
7857 sp<FakeWindowHandle>::make(application, mDispatcher, "Window", ADISPLAY_ID_DEFAULT);
7858 window->setFrame(Rect(0, 0, 100, 100));
Prabir Pradhanaeebeb42023-06-13 19:53:03 +00007859 window->setOwnerInfo(gui::Pid{1}, gui::Uid{101});
Prabir Pradhan8ede1d12023-05-08 19:37:44 +00007860
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07007861 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Prabir Pradhan8ede1d12023-05-08 19:37:44 +00007862 setFocusedWindow(window);
7863 ASSERT_NO_FATAL_FAILURE(window->consumeFocusEvent(true));
7864
7865 mDispatcher->notifyKey(KeyArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_KEYBOARD).build());
7866 ASSERT_NO_FATAL_FAILURE(window->consumeKeyDown(ADISPLAY_ID_DEFAULT));
7867 mDispatcher->waitForIdle();
Prabir Pradhan8a5c41d2023-06-08 19:13:46 +00007868 ASSERT_NO_FATAL_FAILURE(
7869 mFakePolicy->assertNotifyDeviceInteractionWasCalled(DEVICE_ID, {gui::Uid{101}}));
Prabir Pradhan8ede1d12023-05-08 19:37:44 +00007870
7871 // The UP actions are not treated as device interaction.
7872 mDispatcher->notifyKey(KeyArgsBuilder(ACTION_UP, AINPUT_SOURCE_KEYBOARD).build());
7873 ASSERT_NO_FATAL_FAILURE(window->consumeKeyUp(ADISPLAY_ID_DEFAULT));
7874 mDispatcher->waitForIdle();
7875 ASSERT_NO_FATAL_FAILURE(mFakePolicy->assertNotifyDeviceInteractionWasNotCalled());
7876}
7877
Prabir Pradhan5893d362023-11-17 04:30:40 +00007878TEST_F(InputDispatcherTest, HoverEnterExitSynthesisUsesNewEventId) {
7879 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
7880
7881 sp<FakeWindowHandle> left = sp<FakeWindowHandle>::make(application, mDispatcher, "Left Window",
7882 ADISPLAY_ID_DEFAULT);
7883 left->setFrame(Rect(0, 0, 100, 100));
7884 sp<FakeWindowHandle> right = sp<FakeWindowHandle>::make(application, mDispatcher,
7885 "Right Window", ADISPLAY_ID_DEFAULT);
7886 right->setFrame(Rect(100, 0, 200, 100));
7887 sp<FakeWindowHandle> spy =
7888 sp<FakeWindowHandle>::make(application, mDispatcher, "Spy Window", ADISPLAY_ID_DEFAULT);
7889 spy->setFrame(Rect(0, 0, 200, 100));
7890 spy->setTrustedOverlay(true);
7891 spy->setSpy(true);
7892
7893 mDispatcher->onWindowInfosChanged(
7894 {{*spy->getInfo(), *left->getInfo(), *right->getInfo()}, {}, 0, 0});
7895
7896 // Send hover move to the left window, and ensure hover enter is synthesized with a new eventId.
7897 NotifyMotionArgs notifyArgs = generateMotionArgs(ACTION_HOVER_MOVE, AINPUT_SOURCE_STYLUS,
7898 ADISPLAY_ID_DEFAULT, {PointF{50, 50}});
7899 mDispatcher->notifyMotion(notifyArgs);
7900
Siarhei Vishniakoud3061ab2023-12-18 20:41:08 -08007901 std::unique_ptr<MotionEvent> leftEnter = left->consumeMotionEvent(
Prabir Pradhan5893d362023-11-17 04:30:40 +00007902 AllOf(WithMotionAction(ACTION_HOVER_ENTER), Not(WithEventId(notifyArgs.id)),
7903 WithEventIdSource(IdGenerator::Source::INPUT_DISPATCHER)));
Siarhei Vishniakoud3061ab2023-12-18 20:41:08 -08007904 ASSERT_NE(nullptr, leftEnter);
Prabir Pradhan5893d362023-11-17 04:30:40 +00007905 spy->consumeMotionEvent(AllOf(WithMotionAction(ACTION_HOVER_ENTER),
7906 Not(WithEventId(notifyArgs.id)),
Siarhei Vishniakoud3061ab2023-12-18 20:41:08 -08007907 Not(WithEventId(leftEnter->getId())),
Prabir Pradhan5893d362023-11-17 04:30:40 +00007908 WithEventIdSource(IdGenerator::Source::INPUT_DISPATCHER)));
7909
7910 // Send move to the right window, and ensure hover exit and enter are synthesized with new ids.
7911 notifyArgs = generateMotionArgs(ACTION_HOVER_MOVE, AINPUT_SOURCE_STYLUS, ADISPLAY_ID_DEFAULT,
7912 {PointF{150, 50}});
7913 mDispatcher->notifyMotion(notifyArgs);
7914
Siarhei Vishniakoud3061ab2023-12-18 20:41:08 -08007915 std::unique_ptr<MotionEvent> leftExit = left->consumeMotionEvent(
Prabir Pradhan5893d362023-11-17 04:30:40 +00007916 AllOf(WithMotionAction(ACTION_HOVER_EXIT), Not(WithEventId(notifyArgs.id)),
7917 WithEventIdSource(IdGenerator::Source::INPUT_DISPATCHER)));
Siarhei Vishniakoud3061ab2023-12-18 20:41:08 -08007918 ASSERT_NE(nullptr, leftExit);
Prabir Pradhan5893d362023-11-17 04:30:40 +00007919 right->consumeMotionEvent(AllOf(WithMotionAction(ACTION_HOVER_ENTER),
7920 Not(WithEventId(notifyArgs.id)),
Siarhei Vishniakoud3061ab2023-12-18 20:41:08 -08007921 Not(WithEventId(leftExit->getId())),
Prabir Pradhan5893d362023-11-17 04:30:40 +00007922 WithEventIdSource(IdGenerator::Source::INPUT_DISPATCHER)));
7923
7924 spy->consumeMotionEvent(AllOf(WithMotionAction(ACTION_HOVER_MOVE), WithEventId(notifyArgs.id)));
7925}
7926
Linnan Liccf6ce32024-04-11 20:32:13 +08007927/**
7928 * When a device reports a DOWN event, which lands in a window that supports splits, and then the
7929 * device then reports a POINTER_DOWN, which lands in the location of a non-existing window, then
7930 * the previous window should receive this event and not be dropped.
7931 */
7932TEST_F(InputDispatcherMultiDeviceTest, SingleDevicePointerDownEventRetentionWithoutWindowTarget) {
7933 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
7934 sp<FakeWindowHandle> window =
7935 sp<FakeWindowHandle>::make(application, mDispatcher, "Window", ADISPLAY_ID_DEFAULT);
7936 window->setFrame(Rect(0, 0, 100, 100));
7937 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
7938
7939 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
7940 .pointer(PointerBuilder(0, ToolType::FINGER).x(50).y(50))
7941 .build());
7942
7943 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN)));
7944
7945 mDispatcher->notifyMotion(MotionArgsBuilder(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
7946 .pointer(PointerBuilder(0, ToolType::FINGER).x(50).y(50))
7947 .pointer(PointerBuilder(1, ToolType::FINGER).x(200).y(200))
7948 .build());
7949
7950 window->consumeMotionEvent(AllOf(WithMotionAction(POINTER_1_DOWN)));
7951}
7952
7953/**
7954 * When deviceA reports a DOWN event, which lands in a window that supports splits, and then deviceB
7955 * also reports a DOWN event, which lands in the location of a non-existing window, then the
7956 * previous window should receive deviceB's event and it should be dropped.
7957 */
7958TEST_F(InputDispatcherMultiDeviceTest, SecondDeviceDownEventDroppedWithoutWindowTarget) {
7959 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
7960 sp<FakeWindowHandle> window =
7961 sp<FakeWindowHandle>::make(application, mDispatcher, "Window", ADISPLAY_ID_DEFAULT);
7962 window->setFrame(Rect(0, 0, 100, 100));
7963 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
7964
7965 const DeviceId deviceA = 9;
7966 const DeviceId deviceB = 3;
7967
7968 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
7969 .pointer(PointerBuilder(0, ToolType::FINGER).x(50).y(50))
7970 .deviceId(deviceA)
7971 .build());
7972 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(deviceA)));
7973
7974 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
7975 .pointer(PointerBuilder(0, ToolType::FINGER).x(200).y(200))
7976 .deviceId(deviceB)
7977 .build());
7978 window->assertNoEvents();
7979}
7980
Prabir Pradhanb0dad3a2023-11-02 20:52:47 +00007981class InputDispatcherFallbackKeyTest : public InputDispatcherTest {
7982protected:
7983 std::shared_ptr<FakeApplicationHandle> mApp;
7984 sp<FakeWindowHandle> mWindow;
7985
7986 virtual void SetUp() override {
7987 InputDispatcherTest::SetUp();
7988
7989 mApp = std::make_shared<FakeApplicationHandle>();
7990
7991 mWindow = sp<FakeWindowHandle>::make(mApp, mDispatcher, "Window", ADISPLAY_ID_DEFAULT);
7992 mWindow->setFrame(Rect(0, 0, 100, 100));
7993
7994 mDispatcher->onWindowInfosChanged({{*mWindow->getInfo()}, {}, 0, 0});
7995 setFocusedWindow(mWindow);
7996 ASSERT_NO_FATAL_FAILURE(mWindow->consumeFocusEvent(/*hasFocus=*/true));
7997 }
7998
7999 void setFallback(int32_t keycode) {
8000 mFakePolicy->setUnhandledKeyHandler([keycode](const KeyEvent& event) {
8001 return KeyEventBuilder(event).keyCode(keycode).build();
8002 });
8003 }
8004
8005 void consumeKey(bool handled, const ::testing::Matcher<KeyEvent>& matcher) {
Siarhei Vishniakoud3061ab2023-12-18 20:41:08 -08008006 std::unique_ptr<KeyEvent> event = mWindow->consumeKey(handled);
8007 ASSERT_NE(nullptr, event);
8008 ASSERT_THAT(*event, matcher);
Prabir Pradhanb0dad3a2023-11-02 20:52:47 +00008009 }
8010};
8011
8012TEST_F(InputDispatcherFallbackKeyTest, PolicyNotNotifiedForHandledKey) {
8013 mDispatcher->notifyKey(
8014 KeyArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_KEYBOARD).keyCode(AKEYCODE_A).build());
8015 consumeKey(/*handled=*/true, AllOf(WithKeyAction(ACTION_DOWN), WithKeyCode(AKEYCODE_A)));
8016 ASSERT_NO_FATAL_FAILURE(mFakePolicy->assertUnhandledKeyNotReported());
8017}
8018
8019TEST_F(InputDispatcherFallbackKeyTest, PolicyNotifiedForUnhandledKey) {
8020 mDispatcher->notifyKey(
8021 KeyArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_KEYBOARD).keyCode(AKEYCODE_A).build());
8022 consumeKey(/*handled=*/false, AllOf(WithKeyAction(ACTION_DOWN), WithKeyCode(AKEYCODE_A)));
8023 ASSERT_NO_FATAL_FAILURE(mFakePolicy->assertUnhandledKeyReported(AKEYCODE_A));
8024}
8025
8026TEST_F(InputDispatcherFallbackKeyTest, NoFallbackRequestedByPolicy) {
8027 mDispatcher->notifyKey(
8028 KeyArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_KEYBOARD).keyCode(AKEYCODE_A).build());
8029
8030 // Do not handle this key event.
8031 consumeKey(/*handled=*/false,
8032 AllOf(WithKeyAction(ACTION_DOWN), WithKeyCode(AKEYCODE_A), WithFlags(0)));
8033 ASSERT_NO_FATAL_FAILURE(mFakePolicy->assertUnhandledKeyReported(AKEYCODE_A));
8034
8035 // Since the policy did not request any fallback to be generated, ensure there are no events.
8036 ASSERT_NO_FATAL_FAILURE(mFakePolicy->assertUnhandledKeyNotReported());
8037}
8038
8039TEST_F(InputDispatcherFallbackKeyTest, FallbackDispatchForUnhandledKey) {
8040 setFallback(AKEYCODE_B);
8041 mDispatcher->notifyKey(
8042 KeyArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_KEYBOARD).keyCode(AKEYCODE_A).build());
8043
8044 // Do not handle this key event.
8045 consumeKey(/*handled=*/false,
8046 AllOf(WithKeyAction(ACTION_DOWN), WithKeyCode(AKEYCODE_A), WithFlags(0)));
8047
8048 // Since the key was not handled, ensure the fallback event was dispatched instead.
8049 ASSERT_NO_FATAL_FAILURE(mFakePolicy->assertUnhandledKeyReported(AKEYCODE_A));
8050 consumeKey(/*handled=*/true,
8051 AllOf(WithKeyAction(ACTION_DOWN), WithKeyCode(AKEYCODE_B),
8052 WithFlags(AKEY_EVENT_FLAG_FALLBACK)));
8053
8054 // Release the original key, and ensure the fallback key is also released.
8055 mDispatcher->notifyKey(
8056 KeyArgsBuilder(ACTION_UP, AINPUT_SOURCE_KEYBOARD).keyCode(AKEYCODE_A).build());
8057 consumeKey(/*handled=*/false,
8058 AllOf(WithKeyAction(ACTION_UP), WithKeyCode(AKEYCODE_A), WithFlags(0)));
8059 ASSERT_NO_FATAL_FAILURE(mFakePolicy->assertUnhandledKeyReported(AKEYCODE_A));
8060 consumeKey(/*handled=*/true,
8061 AllOf(WithKeyAction(ACTION_UP), WithKeyCode(AKEYCODE_B),
8062 WithFlags(AKEY_EVENT_FLAG_FALLBACK)));
8063
8064 ASSERT_NO_FATAL_FAILURE(mFakePolicy->assertUnhandledKeyNotReported());
8065 mWindow->assertNoEvents();
8066}
8067
8068TEST_F(InputDispatcherFallbackKeyTest, AppHandlesPreviouslyUnhandledKey) {
8069 setFallback(AKEYCODE_B);
8070 mDispatcher->notifyKey(
8071 KeyArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_KEYBOARD).keyCode(AKEYCODE_A).build());
8072
8073 // Do not handle this key event, but handle the fallback.
8074 consumeKey(/*handled=*/false,
8075 AllOf(WithKeyAction(ACTION_DOWN), WithKeyCode(AKEYCODE_A), WithFlags(0)));
8076 ASSERT_NO_FATAL_FAILURE(mFakePolicy->assertUnhandledKeyReported(AKEYCODE_A));
8077 consumeKey(/*handled=*/true,
8078 AllOf(WithKeyAction(ACTION_DOWN), WithKeyCode(AKEYCODE_B),
8079 WithFlags(AKEY_EVENT_FLAG_FALLBACK)));
8080
8081 // Release the original key, and ensure the fallback key is also released.
8082 mDispatcher->notifyKey(
8083 KeyArgsBuilder(ACTION_UP, AINPUT_SOURCE_KEYBOARD).keyCode(AKEYCODE_A).build());
8084 // But this time, the app handles the original key.
8085 consumeKey(/*handled=*/true,
8086 AllOf(WithKeyAction(ACTION_UP), WithKeyCode(AKEYCODE_A), WithFlags(0)));
8087 ASSERT_NO_FATAL_FAILURE(mFakePolicy->assertUnhandledKeyReported(AKEYCODE_A));
8088 // Ensure the fallback key is canceled.
8089 consumeKey(/*handled=*/true,
8090 AllOf(WithKeyAction(ACTION_UP), WithKeyCode(AKEYCODE_B),
8091 WithFlags(AKEY_EVENT_FLAG_FALLBACK | AKEY_EVENT_FLAG_CANCELED)));
8092
8093 ASSERT_NO_FATAL_FAILURE(mFakePolicy->assertUnhandledKeyNotReported());
8094 mWindow->assertNoEvents();
8095}
8096
8097TEST_F(InputDispatcherFallbackKeyTest, AppDoesNotHandleFallback) {
8098 setFallback(AKEYCODE_B);
8099 mDispatcher->notifyKey(
8100 KeyArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_KEYBOARD).keyCode(AKEYCODE_A).build());
8101
8102 // Do not handle this key event.
8103 consumeKey(/*handled=*/false,
8104 AllOf(WithKeyAction(ACTION_DOWN), WithKeyCode(AKEYCODE_A), WithFlags(0)));
8105 ASSERT_NO_FATAL_FAILURE(mFakePolicy->assertUnhandledKeyReported(AKEYCODE_A));
8106 // App does not handle the fallback either, so ensure another fallback is not generated.
8107 setFallback(AKEYCODE_C);
8108 consumeKey(/*handled=*/false,
8109 AllOf(WithKeyAction(ACTION_DOWN), WithKeyCode(AKEYCODE_B),
8110 WithFlags(AKEY_EVENT_FLAG_FALLBACK)));
8111
8112 // Release the original key, and ensure the fallback key is also released.
8113 setFallback(AKEYCODE_B);
8114 mDispatcher->notifyKey(
8115 KeyArgsBuilder(ACTION_UP, AINPUT_SOURCE_KEYBOARD).keyCode(AKEYCODE_A).build());
8116 consumeKey(/*handled=*/false,
8117 AllOf(WithKeyAction(ACTION_UP), WithKeyCode(AKEYCODE_A), WithFlags(0)));
8118 ASSERT_NO_FATAL_FAILURE(mFakePolicy->assertUnhandledKeyReported(AKEYCODE_A));
8119 consumeKey(/*handled=*/false,
8120 AllOf(WithKeyAction(ACTION_UP), WithKeyCode(AKEYCODE_B),
8121 WithFlags(AKEY_EVENT_FLAG_FALLBACK)));
8122
8123 ASSERT_NO_FATAL_FAILURE(mFakePolicy->assertUnhandledKeyNotReported());
8124 mWindow->assertNoEvents();
8125}
8126
8127TEST_F(InputDispatcherFallbackKeyTest, InconsistentPolicyCancelsFallback) {
8128 setFallback(AKEYCODE_B);
8129 mDispatcher->notifyKey(
8130 KeyArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_KEYBOARD).keyCode(AKEYCODE_A).build());
8131
8132 // Do not handle this key event, so fallback is generated.
8133 consumeKey(/*handled=*/false,
8134 AllOf(WithKeyAction(ACTION_DOWN), WithKeyCode(AKEYCODE_A), WithFlags(0)));
8135 ASSERT_NO_FATAL_FAILURE(mFakePolicy->assertUnhandledKeyReported(AKEYCODE_A));
8136 consumeKey(/*handled=*/true,
8137 AllOf(WithKeyAction(ACTION_DOWN), WithKeyCode(AKEYCODE_B),
8138 WithFlags(AKEY_EVENT_FLAG_FALLBACK)));
8139
8140 // Release the original key, but assume the policy is misbehaving and it
8141 // generates an inconsistent fallback to the one from the DOWN event.
8142 setFallback(AKEYCODE_C);
8143 mDispatcher->notifyKey(
8144 KeyArgsBuilder(ACTION_UP, AINPUT_SOURCE_KEYBOARD).keyCode(AKEYCODE_A).build());
8145 consumeKey(/*handled=*/false,
8146 AllOf(WithKeyAction(ACTION_UP), WithKeyCode(AKEYCODE_A), WithFlags(0)));
8147 ASSERT_NO_FATAL_FAILURE(mFakePolicy->assertUnhandledKeyReported(AKEYCODE_A));
8148 // Ensure the fallback key reported before as DOWN is canceled due to the inconsistency.
8149 consumeKey(/*handled=*/true,
8150 AllOf(WithKeyAction(ACTION_UP), WithKeyCode(AKEYCODE_B),
8151 WithFlags(AKEY_EVENT_FLAG_FALLBACK | AKEY_EVENT_FLAG_CANCELED)));
8152
8153 ASSERT_NO_FATAL_FAILURE(mFakePolicy->assertUnhandledKeyNotReported());
8154 mWindow->assertNoEvents();
8155}
8156
8157TEST_F(InputDispatcherFallbackKeyTest, CanceledKeyCancelsFallback) {
8158 setFallback(AKEYCODE_B);
8159 mDispatcher->notifyKey(
8160 KeyArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_KEYBOARD).keyCode(AKEYCODE_A).build());
8161
8162 // Do not handle this key event, so fallback is generated.
8163 consumeKey(/*handled=*/false,
8164 AllOf(WithKeyAction(ACTION_DOWN), WithKeyCode(AKEYCODE_A), WithFlags(0)));
8165 ASSERT_NO_FATAL_FAILURE(mFakePolicy->assertUnhandledKeyReported(AKEYCODE_A));
8166 consumeKey(/*handled=*/true,
8167 AllOf(WithKeyAction(ACTION_DOWN), WithKeyCode(AKEYCODE_B),
8168 WithFlags(AKEY_EVENT_FLAG_FALLBACK)));
8169
8170 // The original key is canceled.
8171 mDispatcher->notifyKey(KeyArgsBuilder(ACTION_UP, AINPUT_SOURCE_KEYBOARD)
8172 .keyCode(AKEYCODE_A)
8173 .addFlag(AKEY_EVENT_FLAG_CANCELED)
8174 .build());
8175 consumeKey(/*handled=*/false,
8176 AllOf(WithKeyAction(ACTION_UP), WithKeyCode(AKEYCODE_A),
8177 WithFlags(AKEY_EVENT_FLAG_CANCELED)));
8178 ASSERT_NO_FATAL_FAILURE(mFakePolicy->assertUnhandledKeyReported(AKEYCODE_A));
8179 // Ensure the fallback key is also canceled due to the original key being canceled.
8180 consumeKey(/*handled=*/true,
8181 AllOf(WithKeyAction(ACTION_UP), WithKeyCode(AKEYCODE_B),
8182 WithFlags(AKEY_EVENT_FLAG_FALLBACK | AKEY_EVENT_FLAG_CANCELED)));
8183
8184 ASSERT_NO_FATAL_FAILURE(mFakePolicy->assertUnhandledKeyNotReported());
8185 mWindow->assertNoEvents();
8186}
8187
Prabir Pradhanfa2c69f2024-02-01 20:31:34 +00008188TEST_F(InputDispatcherFallbackKeyTest, InputChannelRemovedDuringPolicyCall) {
Prabir Pradhanb13da8f2024-01-09 23:10:13 +00008189 setFallback(AKEYCODE_B);
8190 mDispatcher->notifyKey(
8191 KeyArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_KEYBOARD).keyCode(AKEYCODE_A).build());
8192
8193 // Do not handle this key event.
8194 consumeKey(/*handled=*/false,
8195 AllOf(WithKeyAction(ACTION_DOWN), WithKeyCode(AKEYCODE_A), WithFlags(0)));
8196 ASSERT_NO_FATAL_FAILURE(mFakePolicy->assertUnhandledKeyReported(AKEYCODE_A));
8197 consumeKey(/*handled=*/true,
8198 AllOf(WithKeyAction(ACTION_DOWN), WithKeyCode(AKEYCODE_B),
8199 WithFlags(AKEY_EVENT_FLAG_FALLBACK)));
8200
8201 mFakePolicy->setUnhandledKeyHandler([&](const KeyEvent& event) {
8202 // When the unhandled key is reported to the policy next, remove the input channel.
8203 mDispatcher->removeInputChannel(mWindow->getToken());
8204 return KeyEventBuilder(event).keyCode(AKEYCODE_B).build();
8205 });
8206 // Release the original key, and let the app now handle the previously unhandled key.
8207 // This should result in the previously generated fallback key to be cancelled.
8208 // Since the policy was notified of the unhandled DOWN event earlier, it will also be notified
8209 // of the UP event for consistency. The Dispatcher calls into the policy from its own thread
8210 // without holding the lock, because it need to synchronously fetch the fallback key. While in
8211 // the policy call, we will now remove the input channel. Once the policy call returns, the
8212 // Dispatcher will no longer have a channel to send cancellation events to. Ensure this does
8213 // not cause any crashes.
8214 mDispatcher->notifyKey(
8215 KeyArgsBuilder(ACTION_UP, AINPUT_SOURCE_KEYBOARD).keyCode(AKEYCODE_A).build());
8216 consumeKey(/*handled=*/true,
8217 AllOf(WithKeyAction(ACTION_UP), WithKeyCode(AKEYCODE_A), WithFlags(0)));
8218 ASSERT_NO_FATAL_FAILURE(mFakePolicy->assertUnhandledKeyReported(AKEYCODE_A));
8219}
8220
Prabir Pradhanfa2c69f2024-02-01 20:31:34 +00008221TEST_F(InputDispatcherFallbackKeyTest, WindowRemovedDuringPolicyCall) {
8222 setFallback(AKEYCODE_B);
8223 mDispatcher->notifyKey(
8224 KeyArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_KEYBOARD).keyCode(AKEYCODE_A).build());
8225
8226 // Do not handle this key event.
8227 consumeKey(/*handled=*/false,
8228 AllOf(WithKeyAction(ACTION_DOWN), WithKeyCode(AKEYCODE_A), WithFlags(0)));
8229 ASSERT_NO_FATAL_FAILURE(mFakePolicy->assertUnhandledKeyReported(AKEYCODE_A));
8230 consumeKey(/*handled=*/true,
8231 AllOf(WithKeyAction(ACTION_DOWN), WithKeyCode(AKEYCODE_B),
8232 WithFlags(AKEY_EVENT_FLAG_FALLBACK)));
8233
8234 mFakePolicy->setUnhandledKeyHandler([&](const KeyEvent& event) {
8235 // When the unhandled key is reported to the policy next, remove the window.
8236 mDispatcher->onWindowInfosChanged({{}, {}, 0, 0});
8237 return KeyEventBuilder(event).keyCode(AKEYCODE_B).build();
8238 });
8239 // Release the original key, which the app will not handle. When this unhandled key is reported
8240 // to the policy, the window will be removed.
8241 mDispatcher->notifyKey(
8242 KeyArgsBuilder(ACTION_UP, AINPUT_SOURCE_KEYBOARD).keyCode(AKEYCODE_A).build());
8243 consumeKey(/*handled=*/false,
8244 AllOf(WithKeyAction(ACTION_UP), WithKeyCode(AKEYCODE_A), WithFlags(0)));
8245 ASSERT_NO_FATAL_FAILURE(mFakePolicy->assertUnhandledKeyReported(AKEYCODE_A));
8246
8247 // Since the window was removed, it loses focus, and the channel state will be reset.
8248 consumeKey(/*handled=*/true,
8249 AllOf(WithKeyAction(ACTION_UP), WithKeyCode(AKEYCODE_B),
8250 WithFlags(AKEY_EVENT_FLAG_FALLBACK | AKEY_EVENT_FLAG_CANCELED)));
8251 mWindow->consumeFocusEvent(false);
8252 mWindow->assertNoEvents();
8253}
8254
8255TEST_F(InputDispatcherFallbackKeyTest, WindowRemovedWhileAwaitingFinishedSignal) {
8256 setFallback(AKEYCODE_B);
8257 mDispatcher->notifyKey(
8258 KeyArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_KEYBOARD).keyCode(AKEYCODE_A).build());
8259
8260 // Do not handle this key event.
8261 consumeKey(/*handled=*/false,
8262 AllOf(WithKeyAction(ACTION_DOWN), WithKeyCode(AKEYCODE_A), WithFlags(0)));
8263 ASSERT_NO_FATAL_FAILURE(mFakePolicy->assertUnhandledKeyReported(AKEYCODE_A));
8264 const auto [seq, event] = mWindow->receiveEvent();
8265 ASSERT_TRUE(seq.has_value() && event != nullptr) << "Failed to receive fallback event";
8266 ASSERT_EQ(event->getType(), InputEventType::KEY);
8267 ASSERT_THAT(static_cast<const KeyEvent&>(*event),
8268 AllOf(WithKeyAction(ACTION_DOWN), WithKeyCode(AKEYCODE_B),
8269 WithFlags(AKEY_EVENT_FLAG_FALLBACK)));
8270
8271 // Remove the window now, which should generate a cancellations and make the window lose focus.
8272 mDispatcher->onWindowInfosChanged({{}, {}, 0, 0});
8273 consumeKey(/*handled=*/true,
8274 AllOf(WithKeyAction(ACTION_UP), WithKeyCode(AKEYCODE_A),
8275 WithFlags(AKEY_EVENT_FLAG_CANCELED)));
8276 consumeKey(/*handled=*/true,
8277 AllOf(WithKeyAction(ACTION_UP), WithKeyCode(AKEYCODE_B),
8278 WithFlags(AKEY_EVENT_FLAG_FALLBACK | AKEY_EVENT_FLAG_CANCELED)));
8279 mWindow->consumeFocusEvent(false);
8280
8281 // Finish the event by reporting it as handled.
8282 mWindow->finishEvent(*seq);
8283 mWindow->assertNoEvents();
8284}
8285
Garfield Tan1c7bc862020-01-28 13:24:04 -08008286class InputDispatcherKeyRepeatTest : public InputDispatcherTest {
8287protected:
Siarhei Vishniakoufa2a0492023-11-14 13:13:18 -08008288 static constexpr std::chrono::nanoseconds KEY_REPEAT_TIMEOUT = 40ms;
8289 static constexpr std::chrono::nanoseconds KEY_REPEAT_DELAY = 40ms;
Garfield Tan1c7bc862020-01-28 13:24:04 -08008290
Chris Yea209fde2020-07-22 13:54:51 -07008291 std::shared_ptr<FakeApplicationHandle> mApp;
Garfield Tan1c7bc862020-01-28 13:24:04 -08008292 sp<FakeWindowHandle> mWindow;
8293
8294 virtual void SetUp() override {
Prabir Pradhandae52792023-12-15 07:36:40 +00008295 InputDispatcherTest::SetUp();
Garfield Tan1c7bc862020-01-28 13:24:04 -08008296
Prabir Pradhandae52792023-12-15 07:36:40 +00008297 mDispatcher->setKeyRepeatConfiguration(KEY_REPEAT_TIMEOUT, KEY_REPEAT_DELAY);
Garfield Tan1c7bc862020-01-28 13:24:04 -08008298 setUpWindow();
8299 }
8300
8301 void setUpWindow() {
Chris Yea209fde2020-07-22 13:54:51 -07008302 mApp = std::make_shared<FakeApplicationHandle>();
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07008303 mWindow = sp<FakeWindowHandle>::make(mApp, mDispatcher, "Fake Window", ADISPLAY_ID_DEFAULT);
Garfield Tan1c7bc862020-01-28 13:24:04 -08008304
Vishnu Nair47074b82020-08-14 11:54:47 -07008305 mWindow->setFocusable(true);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07008306 mDispatcher->onWindowInfosChanged({{*mWindow->getInfo()}, {}, 0, 0});
Vishnu Nair958da932020-08-21 17:12:37 -07008307 setFocusedWindow(mWindow);
Garfield Tan1c7bc862020-01-28 13:24:04 -08008308 mWindow->consumeFocusEvent(true);
8309 }
8310
Chris Ye2ad95392020-09-01 13:44:44 -07008311 void sendAndConsumeKeyDown(int32_t deviceId) {
Garfield Tan1c7bc862020-01-28 13:24:04 -08008312 NotifyKeyArgs keyArgs = generateKeyArgs(AKEY_EVENT_ACTION_DOWN, ADISPLAY_ID_DEFAULT);
Chris Ye2ad95392020-09-01 13:44:44 -07008313 keyArgs.deviceId = deviceId;
Garfield Tan1c7bc862020-01-28 13:24:04 -08008314 keyArgs.policyFlags |= POLICY_FLAG_TRUSTED; // Otherwise it won't generate repeat event
Prabir Pradhan678438e2023-04-13 19:32:51 +00008315 mDispatcher->notifyKey(keyArgs);
Garfield Tan1c7bc862020-01-28 13:24:04 -08008316
8317 // Window should receive key down event.
8318 mWindow->consumeKeyDown(ADISPLAY_ID_DEFAULT);
8319 }
8320
8321 void expectKeyRepeatOnce(int32_t repeatCount) {
8322 SCOPED_TRACE(StringPrintf("Checking event with repeat count %" PRId32, repeatCount));
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07008323 mWindow->consumeKeyEvent(
8324 AllOf(WithKeyAction(AKEY_EVENT_ACTION_DOWN), WithRepeatCount(repeatCount)));
Garfield Tan1c7bc862020-01-28 13:24:04 -08008325 }
8326
Chris Ye2ad95392020-09-01 13:44:44 -07008327 void sendAndConsumeKeyUp(int32_t deviceId) {
Garfield Tan1c7bc862020-01-28 13:24:04 -08008328 NotifyKeyArgs keyArgs = generateKeyArgs(AKEY_EVENT_ACTION_UP, ADISPLAY_ID_DEFAULT);
Chris Ye2ad95392020-09-01 13:44:44 -07008329 keyArgs.deviceId = deviceId;
Garfield Tan1c7bc862020-01-28 13:24:04 -08008330 keyArgs.policyFlags |= POLICY_FLAG_TRUSTED; // Unless it won't generate repeat event
Prabir Pradhan678438e2023-04-13 19:32:51 +00008331 mDispatcher->notifyKey(keyArgs);
Garfield Tan1c7bc862020-01-28 13:24:04 -08008332
8333 // Window should receive key down event.
Prabir Pradhan7662a8d2023-12-15 01:58:14 +00008334 mWindow->consumeKeyUp(ADISPLAY_ID_DEFAULT,
Harry Cutts33476232023-01-30 19:57:29 +00008335 /*expectedFlags=*/0);
Garfield Tan1c7bc862020-01-28 13:24:04 -08008336 }
Hu Guofe3c8f12023-09-22 17:20:15 +08008337
8338 void injectKeyRepeat(int32_t repeatCount) {
8339 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
8340 injectKey(*mDispatcher, AKEY_EVENT_ACTION_DOWN, repeatCount, ADISPLAY_ID_DEFAULT))
8341 << "Inject key event should return InputEventInjectionResult::SUCCEEDED";
8342 }
Garfield Tan1c7bc862020-01-28 13:24:04 -08008343};
8344
8345TEST_F(InputDispatcherKeyRepeatTest, FocusedWindow_ReceivesKeyRepeat) {
Harry Cutts33476232023-01-30 19:57:29 +00008346 sendAndConsumeKeyDown(/*deviceId=*/1);
Chris Ye2ad95392020-09-01 13:44:44 -07008347 for (int32_t repeatCount = 1; repeatCount <= 10; ++repeatCount) {
8348 expectKeyRepeatOnce(repeatCount);
8349 }
8350}
8351
8352TEST_F(InputDispatcherKeyRepeatTest, FocusedWindow_ReceivesKeyRepeatFromTwoDevices) {
Harry Cutts33476232023-01-30 19:57:29 +00008353 sendAndConsumeKeyDown(/*deviceId=*/1);
Chris Ye2ad95392020-09-01 13:44:44 -07008354 for (int32_t repeatCount = 1; repeatCount <= 10; ++repeatCount) {
8355 expectKeyRepeatOnce(repeatCount);
8356 }
Harry Cutts33476232023-01-30 19:57:29 +00008357 sendAndConsumeKeyDown(/*deviceId=*/2);
Chris Ye2ad95392020-09-01 13:44:44 -07008358 /* repeatCount will start from 1 for deviceId 2 */
Garfield Tan1c7bc862020-01-28 13:24:04 -08008359 for (int32_t repeatCount = 1; repeatCount <= 10; ++repeatCount) {
8360 expectKeyRepeatOnce(repeatCount);
8361 }
8362}
8363
8364TEST_F(InputDispatcherKeyRepeatTest, FocusedWindow_StopsKeyRepeatAfterUp) {
Harry Cutts33476232023-01-30 19:57:29 +00008365 sendAndConsumeKeyDown(/*deviceId=*/1);
8366 expectKeyRepeatOnce(/*repeatCount=*/1);
8367 sendAndConsumeKeyUp(/*deviceId=*/1);
Chris Ye2ad95392020-09-01 13:44:44 -07008368 mWindow->assertNoEvents();
8369}
8370
8371TEST_F(InputDispatcherKeyRepeatTest, FocusedWindow_KeyRepeatAfterStaleDeviceKeyUp) {
Harry Cutts33476232023-01-30 19:57:29 +00008372 sendAndConsumeKeyDown(/*deviceId=*/1);
8373 expectKeyRepeatOnce(/*repeatCount=*/1);
8374 sendAndConsumeKeyDown(/*deviceId=*/2);
8375 expectKeyRepeatOnce(/*repeatCount=*/1);
Chris Ye2ad95392020-09-01 13:44:44 -07008376 // Stale key up from device 1.
Harry Cutts33476232023-01-30 19:57:29 +00008377 sendAndConsumeKeyUp(/*deviceId=*/1);
Chris Ye2ad95392020-09-01 13:44:44 -07008378 // Device 2 is still down, keep repeating
Harry Cutts33476232023-01-30 19:57:29 +00008379 expectKeyRepeatOnce(/*repeatCount=*/2);
8380 expectKeyRepeatOnce(/*repeatCount=*/3);
Chris Ye2ad95392020-09-01 13:44:44 -07008381 // Device 2 key up
Harry Cutts33476232023-01-30 19:57:29 +00008382 sendAndConsumeKeyUp(/*deviceId=*/2);
Chris Ye2ad95392020-09-01 13:44:44 -07008383 mWindow->assertNoEvents();
8384}
8385
8386TEST_F(InputDispatcherKeyRepeatTest, FocusedWindow_KeyRepeatStopsAfterRepeatingKeyUp) {
Harry Cutts33476232023-01-30 19:57:29 +00008387 sendAndConsumeKeyDown(/*deviceId=*/1);
8388 expectKeyRepeatOnce(/*repeatCount=*/1);
8389 sendAndConsumeKeyDown(/*deviceId=*/2);
8390 expectKeyRepeatOnce(/*repeatCount=*/1);
Chris Ye2ad95392020-09-01 13:44:44 -07008391 // Device 2 which holds the key repeating goes up, expect the repeating to stop.
Harry Cutts33476232023-01-30 19:57:29 +00008392 sendAndConsumeKeyUp(/*deviceId=*/2);
Chris Ye2ad95392020-09-01 13:44:44 -07008393 // Device 1 still holds key down, but the repeating was already stopped
Garfield Tan1c7bc862020-01-28 13:24:04 -08008394 mWindow->assertNoEvents();
8395}
8396
liushenxiang42232912021-05-21 20:24:09 +08008397TEST_F(InputDispatcherKeyRepeatTest, FocusedWindow_StopsKeyRepeatAfterDisableInputDevice) {
8398 sendAndConsumeKeyDown(DEVICE_ID);
Harry Cutts33476232023-01-30 19:57:29 +00008399 expectKeyRepeatOnce(/*repeatCount=*/1);
Prabir Pradhan678438e2023-04-13 19:32:51 +00008400 mDispatcher->notifyDeviceReset({/*id=*/10, /*eventTime=*/20, DEVICE_ID});
liushenxiang42232912021-05-21 20:24:09 +08008401 mWindow->consumeKeyUp(ADISPLAY_ID_DEFAULT,
8402 AKEY_EVENT_FLAG_CANCELED | AKEY_EVENT_FLAG_LONG_PRESS);
8403 mWindow->assertNoEvents();
8404}
8405
Garfield Tan1c7bc862020-01-28 13:24:04 -08008406TEST_F(InputDispatcherKeyRepeatTest, FocusedWindow_RepeatKeyEventsUseEventIdFromInputDispatcher) {
Michael Wrighte1cbbd62023-02-22 19:32:13 +00008407 GTEST_SKIP() << "Flaky test (b/270393106)";
Harry Cutts33476232023-01-30 19:57:29 +00008408 sendAndConsumeKeyDown(/*deviceId=*/1);
Garfield Tan1c7bc862020-01-28 13:24:04 -08008409 for (int32_t repeatCount = 1; repeatCount <= 10; ++repeatCount) {
Siarhei Vishniakoud3061ab2023-12-18 20:41:08 -08008410 std::unique_ptr<KeyEvent> repeatEvent = mWindow->consumeKey();
8411 ASSERT_NE(nullptr, repeatEvent);
Garfield Tan1c7bc862020-01-28 13:24:04 -08008412 EXPECT_EQ(IdGenerator::Source::INPUT_DISPATCHER,
Siarhei Vishniakoud3061ab2023-12-18 20:41:08 -08008413 IdGenerator::getSource(repeatEvent->getId()));
Garfield Tan1c7bc862020-01-28 13:24:04 -08008414 }
8415}
8416
8417TEST_F(InputDispatcherKeyRepeatTest, FocusedWindow_RepeatKeyEventsUseUniqueEventId) {
Michael Wrighte1cbbd62023-02-22 19:32:13 +00008418 GTEST_SKIP() << "Flaky test (b/270393106)";
Harry Cutts33476232023-01-30 19:57:29 +00008419 sendAndConsumeKeyDown(/*deviceId=*/1);
Garfield Tan1c7bc862020-01-28 13:24:04 -08008420
8421 std::unordered_set<int32_t> idSet;
8422 for (int32_t repeatCount = 1; repeatCount <= 10; ++repeatCount) {
Siarhei Vishniakoud3061ab2023-12-18 20:41:08 -08008423 std::unique_ptr<KeyEvent> repeatEvent = mWindow->consumeKey();
8424 ASSERT_NE(nullptr, repeatEvent);
8425 int32_t id = repeatEvent->getId();
Garfield Tan1c7bc862020-01-28 13:24:04 -08008426 EXPECT_EQ(idSet.end(), idSet.find(id));
8427 idSet.insert(id);
8428 }
8429}
8430
Hu Guofe3c8f12023-09-22 17:20:15 +08008431TEST_F(InputDispatcherKeyRepeatTest, FocusedWindow_CorrectRepeatCountWhenInjectKeyRepeat) {
8432 injectKeyRepeat(0);
8433 mWindow->consumeKeyDown(ADISPLAY_ID_DEFAULT);
8434 for (int32_t repeatCount = 1; repeatCount <= 2; ++repeatCount) {
8435 expectKeyRepeatOnce(repeatCount);
8436 }
8437 injectKeyRepeat(1);
8438 // Expect repeatCount to be 3 instead of 1
8439 expectKeyRepeatOnce(3);
8440}
8441
Arthur Hung2fbf37f2018-09-13 18:16:41 +08008442/* Test InputDispatcher for MultiDisplay */
8443class InputDispatcherFocusOnTwoDisplaysTest : public InputDispatcherTest {
8444public:
Prabir Pradhan3608aad2019-10-02 17:08:26 -07008445 virtual void SetUp() override {
Arthur Hung2fbf37f2018-09-13 18:16:41 +08008446 InputDispatcherTest::SetUp();
Arthur Hungb92218b2018-08-14 12:00:21 +08008447
Chris Yea209fde2020-07-22 13:54:51 -07008448 application1 = std::make_shared<FakeApplicationHandle>();
Siarhei Vishniakou870ecec2020-12-09 08:07:46 -10008449 windowInPrimary =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07008450 sp<FakeWindowHandle>::make(application1, mDispatcher, "D_1", ADISPLAY_ID_DEFAULT);
Siarhei Vishniakoub9b15352019-11-26 13:19:26 -08008451
Arthur Hung2fbf37f2018-09-13 18:16:41 +08008452 // Set focus window for primary display, but focused display would be second one.
8453 mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application1);
Vishnu Nair47074b82020-08-14 11:54:47 -07008454 windowInPrimary->setFocusable(true);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07008455 mDispatcher->onWindowInfosChanged({{*windowInPrimary->getInfo()}, {}, 0, 0});
8456
Vishnu Nair958da932020-08-21 17:12:37 -07008457 setFocusedWindow(windowInPrimary);
Siarhei Vishniakouf1035d42019-09-20 16:32:01 +01008458 windowInPrimary->consumeFocusEvent(true);
Arthur Hungb92218b2018-08-14 12:00:21 +08008459
Chris Yea209fde2020-07-22 13:54:51 -07008460 application2 = std::make_shared<FakeApplicationHandle>();
Siarhei Vishniakou870ecec2020-12-09 08:07:46 -10008461 windowInSecondary =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07008462 sp<FakeWindowHandle>::make(application2, mDispatcher, "D_2", SECOND_DISPLAY_ID);
Arthur Hung2fbf37f2018-09-13 18:16:41 +08008463 // Set focus to second display window.
Arthur Hung2fbf37f2018-09-13 18:16:41 +08008464 // Set focus display to second one.
8465 mDispatcher->setFocusedDisplay(SECOND_DISPLAY_ID);
8466 // Set focus window for second display.
8467 mDispatcher->setFocusedApplication(SECOND_DISPLAY_ID, application2);
Vishnu Nair47074b82020-08-14 11:54:47 -07008468 windowInSecondary->setFocusable(true);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07008469 mDispatcher->onWindowInfosChanged(
8470 {{*windowInPrimary->getInfo(), *windowInSecondary->getInfo()}, {}, 0, 0});
Vishnu Nair958da932020-08-21 17:12:37 -07008471 setFocusedWindow(windowInSecondary);
Siarhei Vishniakouf1035d42019-09-20 16:32:01 +01008472 windowInSecondary->consumeFocusEvent(true);
Arthur Hung2fbf37f2018-09-13 18:16:41 +08008473 }
8474
Prabir Pradhan3608aad2019-10-02 17:08:26 -07008475 virtual void TearDown() override {
Arthur Hung2fbf37f2018-09-13 18:16:41 +08008476 InputDispatcherTest::TearDown();
8477
Chris Yea209fde2020-07-22 13:54:51 -07008478 application1.reset();
Arthur Hung2fbf37f2018-09-13 18:16:41 +08008479 windowInPrimary.clear();
Chris Yea209fde2020-07-22 13:54:51 -07008480 application2.reset();
Arthur Hung2fbf37f2018-09-13 18:16:41 +08008481 windowInSecondary.clear();
8482 }
8483
8484protected:
Chris Yea209fde2020-07-22 13:54:51 -07008485 std::shared_ptr<FakeApplicationHandle> application1;
Arthur Hung2fbf37f2018-09-13 18:16:41 +08008486 sp<FakeWindowHandle> windowInPrimary;
Chris Yea209fde2020-07-22 13:54:51 -07008487 std::shared_ptr<FakeApplicationHandle> application2;
Arthur Hung2fbf37f2018-09-13 18:16:41 +08008488 sp<FakeWindowHandle> windowInSecondary;
8489};
8490
8491TEST_F(InputDispatcherFocusOnTwoDisplaysTest, SetInputWindow_MultiDisplayTouch) {
8492 // Test touch down on primary display.
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08008493 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07008494 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT))
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08008495 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
Siarhei Vishniakouc5ca85c2019-11-15 17:20:00 -08008496 windowInPrimary->consumeMotionDown(ADISPLAY_ID_DEFAULT);
Arthur Hungb92218b2018-08-14 12:00:21 +08008497 windowInSecondary->assertNoEvents();
8498
Arthur Hung2fbf37f2018-09-13 18:16:41 +08008499 // Test touch down on second display.
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08008500 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07008501 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, SECOND_DISPLAY_ID))
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08008502 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
Arthur Hungb92218b2018-08-14 12:00:21 +08008503 windowInPrimary->assertNoEvents();
Siarhei Vishniakouc5ca85c2019-11-15 17:20:00 -08008504 windowInSecondary->consumeMotionDown(SECOND_DISPLAY_ID);
Arthur Hungb92218b2018-08-14 12:00:21 +08008505}
8506
Arthur Hung2fbf37f2018-09-13 18:16:41 +08008507TEST_F(InputDispatcherFocusOnTwoDisplaysTest, SetInputWindow_MultiDisplayFocus) {
Tiger Huang721e26f2018-07-24 22:26:19 +08008508 // Test inject a key down with display id specified.
Prabir Pradhan93f342c2021-03-11 15:05:30 -08008509 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07008510 injectKeyDownNoRepeat(*mDispatcher, ADISPLAY_ID_DEFAULT))
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08008511 << "Inject key event should return InputEventInjectionResult::SUCCEEDED";
Siarhei Vishniakouc5ca85c2019-11-15 17:20:00 -08008512 windowInPrimary->consumeKeyDown(ADISPLAY_ID_DEFAULT);
Tiger Huang721e26f2018-07-24 22:26:19 +08008513 windowInSecondary->assertNoEvents();
8514
8515 // Test inject a key down without display id specified.
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07008516 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectKeyDownNoRepeat(*mDispatcher))
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08008517 << "Inject key event should return InputEventInjectionResult::SUCCEEDED";
Arthur Hungb92218b2018-08-14 12:00:21 +08008518 windowInPrimary->assertNoEvents();
Siarhei Vishniakouc5ca85c2019-11-15 17:20:00 -08008519 windowInSecondary->consumeKeyDown(ADISPLAY_ID_NONE);
Arthur Hungb92218b2018-08-14 12:00:21 +08008520
Siarhei Vishniakoub9b15352019-11-26 13:19:26 -08008521 // Remove all windows in secondary display.
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07008522 mDispatcher->onWindowInfosChanged({{*windowInPrimary->getInfo()}, {}, 0, 0});
Arthur Hungb92218b2018-08-14 12:00:21 +08008523
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08008524 // Old focus should receive a cancel event.
Prabir Pradhan7662a8d2023-12-15 01:58:14 +00008525 windowInSecondary->consumeKeyUp(ADISPLAY_ID_NONE, AKEY_EVENT_FLAG_CANCELED);
Arthur Hungb92218b2018-08-14 12:00:21 +08008526
8527 // Test inject a key down, should timeout because of no target window.
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07008528 ASSERT_NO_FATAL_FAILURE(assertInjectedKeyTimesOut(*mDispatcher));
Arthur Hungb92218b2018-08-14 12:00:21 +08008529 windowInPrimary->assertNoEvents();
Siarhei Vishniakouf1035d42019-09-20 16:32:01 +01008530 windowInSecondary->consumeFocusEvent(false);
Arthur Hungb92218b2018-08-14 12:00:21 +08008531 windowInSecondary->assertNoEvents();
8532}
8533
Arthur Hung2fbf37f2018-09-13 18:16:41 +08008534// Test per-display input monitors for motion event.
8535TEST_F(InputDispatcherFocusOnTwoDisplaysTest, MonitorMotionEvent_MultiDisplay) {
chaviwd1c23182019-12-20 18:44:56 -08008536 FakeMonitorReceiver monitorInPrimary =
Prabir Pradhanfb549072023-10-05 19:17:36 +00008537 FakeMonitorReceiver(*mDispatcher, "M_1", ADISPLAY_ID_DEFAULT);
chaviwd1c23182019-12-20 18:44:56 -08008538 FakeMonitorReceiver monitorInSecondary =
Prabir Pradhanfb549072023-10-05 19:17:36 +00008539 FakeMonitorReceiver(*mDispatcher, "M_2", SECOND_DISPLAY_ID);
Arthur Hung2fbf37f2018-09-13 18:16:41 +08008540
8541 // Test touch down on primary display.
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08008542 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07008543 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT))
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08008544 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
Siarhei Vishniakouc5ca85c2019-11-15 17:20:00 -08008545 windowInPrimary->consumeMotionDown(ADISPLAY_ID_DEFAULT);
chaviwd1c23182019-12-20 18:44:56 -08008546 monitorInPrimary.consumeMotionDown(ADISPLAY_ID_DEFAULT);
Arthur Hung2fbf37f2018-09-13 18:16:41 +08008547 windowInSecondary->assertNoEvents();
chaviwd1c23182019-12-20 18:44:56 -08008548 monitorInSecondary.assertNoEvents();
Arthur Hung2fbf37f2018-09-13 18:16:41 +08008549
8550 // Test touch down on second display.
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08008551 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07008552 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, SECOND_DISPLAY_ID))
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08008553 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
Arthur Hung2fbf37f2018-09-13 18:16:41 +08008554 windowInPrimary->assertNoEvents();
chaviwd1c23182019-12-20 18:44:56 -08008555 monitorInPrimary.assertNoEvents();
Siarhei Vishniakouc5ca85c2019-11-15 17:20:00 -08008556 windowInSecondary->consumeMotionDown(SECOND_DISPLAY_ID);
chaviwd1c23182019-12-20 18:44:56 -08008557 monitorInSecondary.consumeMotionDown(SECOND_DISPLAY_ID);
Arthur Hung2fbf37f2018-09-13 18:16:41 +08008558
Siarhei Vishniakou92c8fd52023-01-29 14:57:43 -08008559 // Lift up the touch from the second display
8560 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07008561 injectMotionUp(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, SECOND_DISPLAY_ID))
Siarhei Vishniakou92c8fd52023-01-29 14:57:43 -08008562 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
8563 windowInSecondary->consumeMotionUp(SECOND_DISPLAY_ID);
8564 monitorInSecondary.consumeMotionUp(SECOND_DISPLAY_ID);
8565
Arthur Hung2fbf37f2018-09-13 18:16:41 +08008566 // Test inject a non-pointer motion event.
8567 // If specific a display, it will dispatch to the focused window of particular display,
8568 // or it will dispatch to the focused window of focused display.
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08008569 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07008570 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TRACKBALL, ADISPLAY_ID_NONE))
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08008571 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
Arthur Hung2fbf37f2018-09-13 18:16:41 +08008572 windowInPrimary->assertNoEvents();
chaviwd1c23182019-12-20 18:44:56 -08008573 monitorInPrimary.assertNoEvents();
Siarhei Vishniakouc5ca85c2019-11-15 17:20:00 -08008574 windowInSecondary->consumeMotionDown(ADISPLAY_ID_NONE);
chaviwd1c23182019-12-20 18:44:56 -08008575 monitorInSecondary.consumeMotionDown(ADISPLAY_ID_NONE);
Arthur Hung2fbf37f2018-09-13 18:16:41 +08008576}
8577
8578// Test per-display input monitors for key event.
8579TEST_F(InputDispatcherFocusOnTwoDisplaysTest, MonitorKeyEvent_MultiDisplay) {
Siarhei Vishniakou870ecec2020-12-09 08:07:46 -10008580 // Input monitor per display.
chaviwd1c23182019-12-20 18:44:56 -08008581 FakeMonitorReceiver monitorInPrimary =
Prabir Pradhanfb549072023-10-05 19:17:36 +00008582 FakeMonitorReceiver(*mDispatcher, "M_1", ADISPLAY_ID_DEFAULT);
chaviwd1c23182019-12-20 18:44:56 -08008583 FakeMonitorReceiver monitorInSecondary =
Prabir Pradhanfb549072023-10-05 19:17:36 +00008584 FakeMonitorReceiver(*mDispatcher, "M_2", SECOND_DISPLAY_ID);
Arthur Hung2fbf37f2018-09-13 18:16:41 +08008585
8586 // Test inject a key down.
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07008587 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectKeyDown(*mDispatcher))
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08008588 << "Inject key event should return InputEventInjectionResult::SUCCEEDED";
Arthur Hung2fbf37f2018-09-13 18:16:41 +08008589 windowInPrimary->assertNoEvents();
chaviwd1c23182019-12-20 18:44:56 -08008590 monitorInPrimary.assertNoEvents();
Siarhei Vishniakouc5ca85c2019-11-15 17:20:00 -08008591 windowInSecondary->consumeKeyDown(ADISPLAY_ID_NONE);
chaviwd1c23182019-12-20 18:44:56 -08008592 monitorInSecondary.consumeKeyDown(ADISPLAY_ID_NONE);
Arthur Hung2fbf37f2018-09-13 18:16:41 +08008593}
8594
Vishnu Nair958da932020-08-21 17:12:37 -07008595TEST_F(InputDispatcherFocusOnTwoDisplaysTest, CanFocusWindowOnUnfocusedDisplay) {
8596 sp<FakeWindowHandle> secondWindowInPrimary =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07008597 sp<FakeWindowHandle>::make(application1, mDispatcher, "D_1_W2", ADISPLAY_ID_DEFAULT);
Vishnu Nair958da932020-08-21 17:12:37 -07008598 secondWindowInPrimary->setFocusable(true);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07008599 mDispatcher->onWindowInfosChanged(
8600 {{*windowInPrimary->getInfo(), *secondWindowInPrimary->getInfo(),
8601 *windowInSecondary->getInfo()},
8602 {},
8603 0,
8604 0});
Vishnu Nair958da932020-08-21 17:12:37 -07008605 setFocusedWindow(secondWindowInPrimary);
8606 windowInPrimary->consumeFocusEvent(false);
8607 secondWindowInPrimary->consumeFocusEvent(true);
8608
8609 // Test inject a key down.
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07008610 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
8611 injectKeyDown(*mDispatcher, ADISPLAY_ID_DEFAULT))
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08008612 << "Inject key event should return InputEventInjectionResult::SUCCEEDED";
Vishnu Nair958da932020-08-21 17:12:37 -07008613 windowInPrimary->assertNoEvents();
8614 windowInSecondary->assertNoEvents();
8615 secondWindowInPrimary->consumeKeyDown(ADISPLAY_ID_DEFAULT);
8616}
8617
Arthur Hungdfd528e2021-12-08 13:23:04 +00008618TEST_F(InputDispatcherFocusOnTwoDisplaysTest, CancelTouch_MultiDisplay) {
8619 FakeMonitorReceiver monitorInPrimary =
Prabir Pradhanfb549072023-10-05 19:17:36 +00008620 FakeMonitorReceiver(*mDispatcher, "M_1", ADISPLAY_ID_DEFAULT);
Arthur Hungdfd528e2021-12-08 13:23:04 +00008621 FakeMonitorReceiver monitorInSecondary =
Prabir Pradhanfb549072023-10-05 19:17:36 +00008622 FakeMonitorReceiver(*mDispatcher, "M_2", SECOND_DISPLAY_ID);
Arthur Hungdfd528e2021-12-08 13:23:04 +00008623
8624 // Test touch down on primary display.
8625 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07008626 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT))
Arthur Hungdfd528e2021-12-08 13:23:04 +00008627 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
8628 windowInPrimary->consumeMotionDown(ADISPLAY_ID_DEFAULT);
8629 monitorInPrimary.consumeMotionDown(ADISPLAY_ID_DEFAULT);
8630
8631 // Test touch down on second display.
8632 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07008633 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, SECOND_DISPLAY_ID))
Arthur Hungdfd528e2021-12-08 13:23:04 +00008634 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
8635 windowInSecondary->consumeMotionDown(SECOND_DISPLAY_ID);
8636 monitorInSecondary.consumeMotionDown(SECOND_DISPLAY_ID);
8637
8638 // Trigger cancel touch.
8639 mDispatcher->cancelCurrentTouch();
8640 windowInPrimary->consumeMotionCancel(ADISPLAY_ID_DEFAULT);
8641 monitorInPrimary.consumeMotionCancel(ADISPLAY_ID_DEFAULT);
8642 windowInSecondary->consumeMotionCancel(SECOND_DISPLAY_ID);
8643 monitorInSecondary.consumeMotionCancel(SECOND_DISPLAY_ID);
8644
8645 // Test inject a move motion event, no window/monitor should receive the event.
8646 ASSERT_EQ(InputEventInjectionResult::FAILED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07008647 injectMotionEvent(*mDispatcher, AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN,
Arthur Hungdfd528e2021-12-08 13:23:04 +00008648 ADISPLAY_ID_DEFAULT, {110, 200}))
8649 << "Inject motion event should return InputEventInjectionResult::FAILED";
8650 windowInPrimary->assertNoEvents();
8651 monitorInPrimary.assertNoEvents();
8652
8653 ASSERT_EQ(InputEventInjectionResult::FAILED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07008654 injectMotionEvent(*mDispatcher, AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN,
Arthur Hungdfd528e2021-12-08 13:23:04 +00008655 SECOND_DISPLAY_ID, {110, 200}))
8656 << "Inject motion event should return InputEventInjectionResult::FAILED";
8657 windowInSecondary->assertNoEvents();
8658 monitorInSecondary.assertNoEvents();
8659}
8660
Hu Guocb134f12023-12-23 13:42:44 +00008661/**
8662 * Send a key to the primary display and to the secondary display.
8663 * Then cause the key on the primary display to be canceled by sending in a stale key.
8664 * Ensure that the key on the primary display is canceled, and that the key on the secondary display
8665 * does not get canceled.
8666 */
8667TEST_F(InputDispatcherFocusOnTwoDisplaysTest, WhenDropKeyEvent_OnlyCancelCorrespondingKeyGesture) {
8668 // Send a key down on primary display
8669 mDispatcher->notifyKey(
8670 KeyArgsBuilder(AKEY_EVENT_ACTION_DOWN, AINPUT_SOURCE_KEYBOARD)
8671 .displayId(ADISPLAY_ID_DEFAULT)
8672 .policyFlags(DEFAULT_POLICY_FLAGS | POLICY_FLAG_DISABLE_KEY_REPEAT)
8673 .build());
8674 windowInPrimary->consumeKeyEvent(
8675 AllOf(WithKeyAction(AKEY_EVENT_ACTION_DOWN), WithDisplayId(ADISPLAY_ID_DEFAULT)));
8676 windowInSecondary->assertNoEvents();
8677
8678 // Send a key down on second display
8679 mDispatcher->notifyKey(
8680 KeyArgsBuilder(AKEY_EVENT_ACTION_DOWN, AINPUT_SOURCE_KEYBOARD)
8681 .displayId(SECOND_DISPLAY_ID)
8682 .policyFlags(DEFAULT_POLICY_FLAGS | POLICY_FLAG_DISABLE_KEY_REPEAT)
8683 .build());
8684 windowInSecondary->consumeKeyEvent(
8685 AllOf(WithKeyAction(AKEY_EVENT_ACTION_DOWN), WithDisplayId(SECOND_DISPLAY_ID)));
8686 windowInPrimary->assertNoEvents();
8687
8688 // Send a valid key up event on primary display that will be dropped because it is stale
8689 NotifyKeyArgs staleKeyUp =
8690 KeyArgsBuilder(AKEY_EVENT_ACTION_UP, AINPUT_SOURCE_KEYBOARD)
8691 .displayId(ADISPLAY_ID_DEFAULT)
8692 .policyFlags(DEFAULT_POLICY_FLAGS | POLICY_FLAG_DISABLE_KEY_REPEAT)
8693 .build();
8694 static constexpr std::chrono::duration STALE_EVENT_TIMEOUT = 10ms;
8695 mFakePolicy->setStaleEventTimeout(STALE_EVENT_TIMEOUT);
8696 std::this_thread::sleep_for(STALE_EVENT_TIMEOUT);
8697 mDispatcher->notifyKey(staleKeyUp);
8698
8699 // Only the key gesture corresponding to the dropped event should receive the cancel event.
8700 // Therefore, windowInPrimary should get the cancel event and windowInSecondary should not
8701 // receive any events.
8702 windowInPrimary->consumeKeyEvent(AllOf(WithKeyAction(AKEY_EVENT_ACTION_UP),
8703 WithDisplayId(ADISPLAY_ID_DEFAULT),
8704 WithFlags(AKEY_EVENT_FLAG_CANCELED)));
8705 windowInSecondary->assertNoEvents();
8706}
8707
8708/**
8709 * Similar to 'WhenDropKeyEvent_OnlyCancelCorrespondingKeyGesture' but for motion events.
8710 */
8711TEST_F(InputDispatcherFocusOnTwoDisplaysTest, WhenDropMotionEvent_OnlyCancelCorrespondingGesture) {
8712 // Send touch down on primary display.
8713 mDispatcher->notifyMotion(
8714 MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
8715 .pointer(PointerBuilder(/*id=*/0, ToolType::FINGER).x(100).y(200))
8716 .displayId(ADISPLAY_ID_DEFAULT)
8717 .build());
8718 windowInPrimary->consumeMotionEvent(
8719 AllOf(WithMotionAction(ACTION_DOWN), WithDisplayId(ADISPLAY_ID_DEFAULT)));
8720 windowInSecondary->assertNoEvents();
8721
8722 // Send touch down on second display.
8723 mDispatcher->notifyMotion(
8724 MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
8725 .pointer(PointerBuilder(/*id=*/0, ToolType::FINGER).x(100).y(200))
8726 .displayId(SECOND_DISPLAY_ID)
8727 .build());
8728 windowInPrimary->assertNoEvents();
8729 windowInSecondary->consumeMotionEvent(
8730 AllOf(WithMotionAction(ACTION_DOWN), WithDisplayId(SECOND_DISPLAY_ID)));
8731
8732 // inject a valid MotionEvent on primary display that will be stale when it arrives.
8733 NotifyMotionArgs staleMotionUp =
8734 MotionArgsBuilder(ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN)
8735 .displayId(ADISPLAY_ID_DEFAULT)
8736 .pointer(PointerBuilder(/*id=*/0, ToolType::FINGER).x(100).y(200))
8737 .build();
8738 static constexpr std::chrono::duration STALE_EVENT_TIMEOUT = 10ms;
8739 mFakePolicy->setStaleEventTimeout(STALE_EVENT_TIMEOUT);
8740 std::this_thread::sleep_for(STALE_EVENT_TIMEOUT);
8741 mDispatcher->notifyMotion(staleMotionUp);
8742
8743 // For stale motion events, we let the gesture to complete. This behaviour is different from key
8744 // events, where we would cancel the current keys instead.
8745 windowInPrimary->consumeMotionEvent(WithMotionAction(ACTION_UP));
8746 windowInSecondary->assertNoEvents();
8747}
8748
Jackal Guof9696682018-10-05 12:23:23 +08008749class InputFilterTest : public InputDispatcherTest {
8750protected:
Prabir Pradhan81420cc2021-09-06 10:28:50 -07008751 void testNotifyMotion(int32_t displayId, bool expectToBeFiltered,
8752 const ui::Transform& transform = ui::Transform()) {
Jackal Guof9696682018-10-05 12:23:23 +08008753 NotifyMotionArgs motionArgs;
8754
Siarhei Vishniakou870ecec2020-12-09 08:07:46 -10008755 motionArgs =
8756 generateMotionArgs(AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN, displayId);
Prabir Pradhan678438e2023-04-13 19:32:51 +00008757 mDispatcher->notifyMotion(motionArgs);
Siarhei Vishniakou870ecec2020-12-09 08:07:46 -10008758 motionArgs =
8759 generateMotionArgs(AMOTION_EVENT_ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN, displayId);
Prabir Pradhan678438e2023-04-13 19:32:51 +00008760 mDispatcher->notifyMotion(motionArgs);
Siarhei Vishniakou2bfa9052019-11-21 18:10:54 -08008761 ASSERT_TRUE(mDispatcher->waitForIdle());
Jackal Guof9696682018-10-05 12:23:23 +08008762 if (expectToBeFiltered) {
Siarhei Vishniakou3218fc02023-06-15 20:41:02 -07008763 const auto xy = transform.transform(motionArgs.pointerCoords[0].getXYValue());
Prabir Pradhan81420cc2021-09-06 10:28:50 -07008764 mFakePolicy->assertFilterInputEventWasCalled(motionArgs, xy);
Jackal Guof9696682018-10-05 12:23:23 +08008765 } else {
8766 mFakePolicy->assertFilterInputEventWasNotCalled();
8767 }
8768 }
8769
8770 void testNotifyKey(bool expectToBeFiltered) {
8771 NotifyKeyArgs keyArgs;
8772
8773 keyArgs = generateKeyArgs(AKEY_EVENT_ACTION_DOWN);
Prabir Pradhan678438e2023-04-13 19:32:51 +00008774 mDispatcher->notifyKey(keyArgs);
Jackal Guof9696682018-10-05 12:23:23 +08008775 keyArgs = generateKeyArgs(AKEY_EVENT_ACTION_UP);
Prabir Pradhan678438e2023-04-13 19:32:51 +00008776 mDispatcher->notifyKey(keyArgs);
Siarhei Vishniakou2bfa9052019-11-21 18:10:54 -08008777 ASSERT_TRUE(mDispatcher->waitForIdle());
Jackal Guof9696682018-10-05 12:23:23 +08008778
8779 if (expectToBeFiltered) {
Siarhei Vishniakou8935a802019-11-15 16:41:44 -08008780 mFakePolicy->assertFilterInputEventWasCalled(keyArgs);
Jackal Guof9696682018-10-05 12:23:23 +08008781 } else {
8782 mFakePolicy->assertFilterInputEventWasNotCalled();
8783 }
8784 }
8785};
8786
8787// Test InputFilter for MotionEvent
8788TEST_F(InputFilterTest, MotionEvent_InputFilter) {
8789 // Since the InputFilter is disabled by default, check if touch events aren't filtered.
Harry Cutts101ee9b2023-07-06 18:04:14 +00008790 testNotifyMotion(ADISPLAY_ID_DEFAULT, /*expectToBeFiltered=*/false);
8791 testNotifyMotion(SECOND_DISPLAY_ID, /*expectToBeFiltered=*/false);
Jackal Guof9696682018-10-05 12:23:23 +08008792
8793 // Enable InputFilter
8794 mDispatcher->setInputFilterEnabled(true);
8795 // Test touch on both primary and second display, and check if both events are filtered.
Harry Cutts101ee9b2023-07-06 18:04:14 +00008796 testNotifyMotion(ADISPLAY_ID_DEFAULT, /*expectToBeFiltered=*/true);
8797 testNotifyMotion(SECOND_DISPLAY_ID, /*expectToBeFiltered=*/true);
Jackal Guof9696682018-10-05 12:23:23 +08008798
8799 // Disable InputFilter
8800 mDispatcher->setInputFilterEnabled(false);
8801 // Test touch on both primary and second display, and check if both events aren't filtered.
Harry Cutts101ee9b2023-07-06 18:04:14 +00008802 testNotifyMotion(ADISPLAY_ID_DEFAULT, /*expectToBeFiltered=*/false);
8803 testNotifyMotion(SECOND_DISPLAY_ID, /*expectToBeFiltered=*/false);
Jackal Guof9696682018-10-05 12:23:23 +08008804}
8805
8806// Test InputFilter for KeyEvent
8807TEST_F(InputFilterTest, KeyEvent_InputFilter) {
8808 // Since the InputFilter is disabled by default, check if key event aren't filtered.
Harry Cutts101ee9b2023-07-06 18:04:14 +00008809 testNotifyKey(/*expectToBeFiltered=*/false);
Jackal Guof9696682018-10-05 12:23:23 +08008810
8811 // Enable InputFilter
8812 mDispatcher->setInputFilterEnabled(true);
8813 // Send a key event, and check if it is filtered.
Harry Cutts101ee9b2023-07-06 18:04:14 +00008814 testNotifyKey(/*expectToBeFiltered=*/true);
Jackal Guof9696682018-10-05 12:23:23 +08008815
8816 // Disable InputFilter
8817 mDispatcher->setInputFilterEnabled(false);
8818 // Send a key event, and check if it isn't filtered.
Harry Cutts101ee9b2023-07-06 18:04:14 +00008819 testNotifyKey(/*expectToBeFiltered=*/false);
Jackal Guof9696682018-10-05 12:23:23 +08008820}
8821
Prabir Pradhan81420cc2021-09-06 10:28:50 -07008822// Ensure that MotionEvents sent to the InputFilter through InputListener are converted to the
8823// logical display coordinate space.
8824TEST_F(InputFilterTest, MotionEvent_UsesLogicalDisplayCoordinates_notifyMotion) {
8825 ui::Transform firstDisplayTransform;
8826 firstDisplayTransform.set({1.1, 2.2, 3.3, 4.4, 5.5, 6.6, 0, 0, 1});
8827 ui::Transform secondDisplayTransform;
8828 secondDisplayTransform.set({-6.6, -5.5, -4.4, -3.3, -2.2, -1.1, 0, 0, 1});
8829
8830 std::vector<gui::DisplayInfo> displayInfos(2);
8831 displayInfos[0].displayId = ADISPLAY_ID_DEFAULT;
8832 displayInfos[0].transform = firstDisplayTransform;
8833 displayInfos[1].displayId = SECOND_DISPLAY_ID;
8834 displayInfos[1].transform = secondDisplayTransform;
8835
Patrick Williamsd828f302023-04-28 17:52:08 -05008836 mDispatcher->onWindowInfosChanged({{}, displayInfos, 0, 0});
Prabir Pradhan81420cc2021-09-06 10:28:50 -07008837
8838 // Enable InputFilter
8839 mDispatcher->setInputFilterEnabled(true);
8840
8841 // Ensure the correct transforms are used for the displays.
Harry Cutts101ee9b2023-07-06 18:04:14 +00008842 testNotifyMotion(ADISPLAY_ID_DEFAULT, /*expectToBeFiltered=*/true, firstDisplayTransform);
8843 testNotifyMotion(SECOND_DISPLAY_ID, /*expectToBeFiltered=*/true, secondDisplayTransform);
Prabir Pradhan81420cc2021-09-06 10:28:50 -07008844}
8845
Siarhei Vishniakou5d552c42021-05-21 05:02:22 +00008846class InputFilterInjectionPolicyTest : public InputDispatcherTest {
8847protected:
8848 virtual void SetUp() override {
8849 InputDispatcherTest::SetUp();
8850
8851 /**
8852 * We don't need to enable input filter to test the injected event policy, but we enabled it
8853 * here to make the tests more realistic, since this policy only matters when inputfilter is
8854 * on.
8855 */
8856 mDispatcher->setInputFilterEnabled(true);
8857
8858 std::shared_ptr<InputApplicationHandle> application =
8859 std::make_shared<FakeApplicationHandle>();
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07008860 mWindow = sp<FakeWindowHandle>::make(application, mDispatcher, "Test Window",
8861 ADISPLAY_ID_DEFAULT);
Siarhei Vishniakou5d552c42021-05-21 05:02:22 +00008862
8863 mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application);
8864 mWindow->setFocusable(true);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07008865 mDispatcher->onWindowInfosChanged({{*mWindow->getInfo()}, {}, 0, 0});
Siarhei Vishniakou5d552c42021-05-21 05:02:22 +00008866 setFocusedWindow(mWindow);
8867 mWindow->consumeFocusEvent(true);
8868 }
8869
Siarhei Vishniakouf00a4ec2021-06-16 03:55:32 +00008870 void testInjectedKey(int32_t policyFlags, int32_t injectedDeviceId, int32_t resolvedDeviceId,
8871 int32_t flags) {
Siarhei Vishniakou5d552c42021-05-21 05:02:22 +00008872 KeyEvent event;
8873
8874 const nsecs_t eventTime = systemTime(SYSTEM_TIME_MONOTONIC);
8875 event.initialize(InputEvent::nextId(), injectedDeviceId, AINPUT_SOURCE_KEYBOARD,
8876 ADISPLAY_ID_NONE, INVALID_HMAC, AKEY_EVENT_ACTION_DOWN, 0, AKEYCODE_A,
Harry Cutts33476232023-01-30 19:57:29 +00008877 KEY_A, AMETA_NONE, /*repeatCount=*/0, eventTime, eventTime);
Siarhei Vishniakou5d552c42021-05-21 05:02:22 +00008878 const int32_t additionalPolicyFlags =
8879 POLICY_FLAG_PASS_TO_USER | POLICY_FLAG_DISABLE_KEY_REPEAT;
8880 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Harry Cutts33476232023-01-30 19:57:29 +00008881 mDispatcher->injectInputEvent(&event, /*targetUid=*/{},
Siarhei Vishniakou4648fea2023-06-27 01:00:12 +00008882 InputEventInjectionSync::WAIT_FOR_RESULT, 100ms,
Siarhei Vishniakou5d552c42021-05-21 05:02:22 +00008883 policyFlags | additionalPolicyFlags));
8884
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07008885 mWindow->consumeKeyEvent(AllOf(WithDeviceId(resolvedDeviceId), WithFlags(flags)));
Siarhei Vishniakouf00a4ec2021-06-16 03:55:32 +00008886 }
8887
8888 void testInjectedMotion(int32_t policyFlags, int32_t injectedDeviceId, int32_t resolvedDeviceId,
8889 int32_t flags) {
8890 MotionEvent event;
8891 PointerProperties pointerProperties[1];
8892 PointerCoords pointerCoords[1];
8893 pointerProperties[0].clear();
8894 pointerProperties[0].id = 0;
8895 pointerCoords[0].clear();
8896 pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_X, 300);
8897 pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_Y, 400);
8898
8899 ui::Transform identityTransform;
8900 const nsecs_t eventTime = systemTime(SYSTEM_TIME_MONOTONIC);
8901 event.initialize(InputEvent::nextId(), injectedDeviceId, AINPUT_SOURCE_TOUCHSCREEN,
8902 DISPLAY_ID, INVALID_HMAC, AMOTION_EVENT_ACTION_DOWN, 0, 0,
8903 AMOTION_EVENT_EDGE_FLAG_NONE, AMETA_NONE, 0, MotionClassification::NONE,
8904 identityTransform, 0, 0, AMOTION_EVENT_INVALID_CURSOR_POSITION,
Prabir Pradhanb9b18502021-08-26 12:30:32 -07008905 AMOTION_EVENT_INVALID_CURSOR_POSITION, identityTransform, eventTime,
Evan Rosky09576692021-07-01 12:22:09 -07008906 eventTime,
Harry Cutts101ee9b2023-07-06 18:04:14 +00008907 /*pointerCount=*/1, pointerProperties, pointerCoords);
Siarhei Vishniakouf00a4ec2021-06-16 03:55:32 +00008908
8909 const int32_t additionalPolicyFlags = POLICY_FLAG_PASS_TO_USER;
8910 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Harry Cutts33476232023-01-30 19:57:29 +00008911 mDispatcher->injectInputEvent(&event, /*targetUid=*/{},
Siarhei Vishniakou4648fea2023-06-27 01:00:12 +00008912 InputEventInjectionSync::WAIT_FOR_RESULT, 100ms,
Siarhei Vishniakouf00a4ec2021-06-16 03:55:32 +00008913 policyFlags | additionalPolicyFlags));
8914
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07008915 mWindow->consumeMotionEvent(AllOf(WithFlags(flags), WithDeviceId(resolvedDeviceId)));
Siarhei Vishniakou5d552c42021-05-21 05:02:22 +00008916 }
8917
8918private:
8919 sp<FakeWindowHandle> mWindow;
8920};
8921
8922TEST_F(InputFilterInjectionPolicyTest, TrustedFilteredEvents_KeepOriginalDeviceId) {
Siarhei Vishniakouf00a4ec2021-06-16 03:55:32 +00008923 // Must have POLICY_FLAG_FILTERED here to indicate that the event has gone through the input
8924 // filter. Without it, the event will no different from a regularly injected event, and the
8925 // injected device id will be overwritten.
Harry Cutts33476232023-01-30 19:57:29 +00008926 testInjectedKey(POLICY_FLAG_FILTERED, /*injectedDeviceId=*/3, /*resolvedDeviceId=*/3,
8927 /*flags=*/0);
Siarhei Vishniakou5d552c42021-05-21 05:02:22 +00008928}
8929
Siarhei Vishniakouf00a4ec2021-06-16 03:55:32 +00008930TEST_F(InputFilterInjectionPolicyTest, KeyEventsInjectedFromAccessibility_HaveAccessibilityFlag) {
Siarhei Vishniakou5d552c42021-05-21 05:02:22 +00008931 testInjectedKey(POLICY_FLAG_FILTERED | POLICY_FLAG_INJECTED_FROM_ACCESSIBILITY,
Harry Cutts33476232023-01-30 19:57:29 +00008932 /*injectedDeviceId=*/3, /*resolvedDeviceId=*/3,
Siarhei Vishniakouf00a4ec2021-06-16 03:55:32 +00008933 AKEY_EVENT_FLAG_IS_ACCESSIBILITY_EVENT);
8934}
8935
8936TEST_F(InputFilterInjectionPolicyTest,
8937 MotionEventsInjectedFromAccessibility_HaveAccessibilityFlag) {
8938 testInjectedMotion(POLICY_FLAG_FILTERED | POLICY_FLAG_INJECTED_FROM_ACCESSIBILITY,
Harry Cutts33476232023-01-30 19:57:29 +00008939 /*injectedDeviceId=*/3, /*resolvedDeviceId=*/3,
Siarhei Vishniakouf00a4ec2021-06-16 03:55:32 +00008940 AMOTION_EVENT_FLAG_IS_ACCESSIBILITY_EVENT);
Siarhei Vishniakou5d552c42021-05-21 05:02:22 +00008941}
8942
8943TEST_F(InputFilterInjectionPolicyTest, RegularInjectedEvents_ReceiveVirtualDeviceId) {
Harry Cutts33476232023-01-30 19:57:29 +00008944 testInjectedKey(/*policyFlags=*/0, /*injectedDeviceId=*/3,
8945 /*resolvedDeviceId=*/VIRTUAL_KEYBOARD_ID, /*flags=*/0);
Siarhei Vishniakou5d552c42021-05-21 05:02:22 +00008946}
8947
Yeabkal Wubshitb8aadfa2024-01-17 17:03:42 -08008948class InputDispatcherUserActivityPokeTests : public InputDispatcherTest {
8949protected:
8950 virtual void SetUp() override {
8951 InputDispatcherTest::SetUp();
8952
8953 std::shared_ptr<FakeApplicationHandle> application =
8954 std::make_shared<FakeApplicationHandle>();
8955 application->setDispatchingTimeout(100ms);
8956 mWindow = sp<FakeWindowHandle>::make(application, mDispatcher, "TestWindow",
8957 ADISPLAY_ID_DEFAULT);
Yeabkal Wubshit222d83d2024-01-24 18:00:09 +00008958 mWindow->setFrame(Rect(0, 0, 100, 100));
Yeabkal Wubshitb8aadfa2024-01-17 17:03:42 -08008959 mWindow->setDispatchingTimeout(100ms);
8960 mWindow->setFocusable(true);
8961
8962 // Set focused application.
8963 mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application);
8964
8965 mDispatcher->onWindowInfosChanged({{*mWindow->getInfo()}, {}, 0, 0});
8966 setFocusedWindow(mWindow);
8967 mWindow->consumeFocusEvent(true);
8968 }
8969
8970 void notifyAndConsumeMotion(int32_t action, uint32_t source, int32_t displayId,
8971 nsecs_t eventTime) {
8972 mDispatcher->notifyMotion(MotionArgsBuilder(action, source)
8973 .displayId(displayId)
8974 .eventTime(eventTime)
8975 .pointer(PointerBuilder(0, ToolType::FINGER).x(50).y(50))
8976 .build());
8977 mWindow->consumeMotionEvent(WithMotionAction(action));
8978 }
8979
8980private:
8981 sp<FakeWindowHandle> mWindow;
8982};
8983
8984TEST_F_WITH_FLAGS(
8985 InputDispatcherUserActivityPokeTests, MinPokeTimeObserved,
8986 REQUIRES_FLAGS_ENABLED(ACONFIG_FLAG(com::android::input::flags,
8987 rate_limit_user_activity_poke_in_dispatcher))) {
8988 mDispatcher->setMinTimeBetweenUserActivityPokes(50ms);
8989
8990 // First event of type TOUCH. Should poke.
8991 notifyAndConsumeMotion(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
8992 milliseconds_to_nanoseconds(50));
8993 mFakePolicy->assertUserActivityPoked(
8994 {{milliseconds_to_nanoseconds(50), USER_ACTIVITY_EVENT_TOUCH, ADISPLAY_ID_DEFAULT}});
8995
8996 // 80ns > 50ns has passed since previous TOUCH event. Should poke.
8997 notifyAndConsumeMotion(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
8998 milliseconds_to_nanoseconds(130));
8999 mFakePolicy->assertUserActivityPoked(
9000 {{milliseconds_to_nanoseconds(130), USER_ACTIVITY_EVENT_TOUCH, ADISPLAY_ID_DEFAULT}});
9001
9002 // First event of type OTHER. Should poke (despite being within 50ns of previous TOUCH event).
9003 notifyAndConsumeMotion(ACTION_SCROLL, AINPUT_SOURCE_ROTARY_ENCODER, ADISPLAY_ID_DEFAULT,
9004 milliseconds_to_nanoseconds(135));
9005 mFakePolicy->assertUserActivityPoked(
9006 {{milliseconds_to_nanoseconds(135), USER_ACTIVITY_EVENT_OTHER, ADISPLAY_ID_DEFAULT}});
9007
9008 // Within 50ns of previous TOUCH event. Should NOT poke.
9009 notifyAndConsumeMotion(ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
9010 milliseconds_to_nanoseconds(140));
9011 mFakePolicy->assertUserActivityNotPoked();
9012
9013 // Within 50ns of previous OTHER event. Should NOT poke.
9014 notifyAndConsumeMotion(ACTION_SCROLL, AINPUT_SOURCE_ROTARY_ENCODER, ADISPLAY_ID_DEFAULT,
9015 milliseconds_to_nanoseconds(150));
9016 mFakePolicy->assertUserActivityNotPoked();
9017
9018 // Within 50ns of previous TOUCH event (which was at time 130). Should NOT poke.
9019 // Note that STYLUS is mapped to TOUCH user activity, since it's a pointer-type source.
9020 notifyAndConsumeMotion(ACTION_DOWN, AINPUT_SOURCE_STYLUS, ADISPLAY_ID_DEFAULT,
9021 milliseconds_to_nanoseconds(160));
9022 mFakePolicy->assertUserActivityNotPoked();
9023
9024 // 65ns > 50ns has passed since previous OTHER event. Should poke.
9025 notifyAndConsumeMotion(ACTION_SCROLL, AINPUT_SOURCE_ROTARY_ENCODER, ADISPLAY_ID_DEFAULT,
9026 milliseconds_to_nanoseconds(200));
9027 mFakePolicy->assertUserActivityPoked(
9028 {{milliseconds_to_nanoseconds(200), USER_ACTIVITY_EVENT_OTHER, ADISPLAY_ID_DEFAULT}});
9029
9030 // 170ns > 50ns has passed since previous TOUCH event. Should poke.
9031 notifyAndConsumeMotion(ACTION_UP, AINPUT_SOURCE_STYLUS, ADISPLAY_ID_DEFAULT,
9032 milliseconds_to_nanoseconds(300));
9033 mFakePolicy->assertUserActivityPoked(
9034 {{milliseconds_to_nanoseconds(300), USER_ACTIVITY_EVENT_TOUCH, ADISPLAY_ID_DEFAULT}});
9035
9036 // Assert that there's no more user activity poke event.
9037 mFakePolicy->assertUserActivityNotPoked();
9038}
9039
9040TEST_F_WITH_FLAGS(
9041 InputDispatcherUserActivityPokeTests, DefaultMinPokeTimeOf100MsUsed,
9042 REQUIRES_FLAGS_ENABLED(ACONFIG_FLAG(com::android::input::flags,
9043 rate_limit_user_activity_poke_in_dispatcher))) {
9044 notifyAndConsumeMotion(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
9045 milliseconds_to_nanoseconds(200));
9046 mFakePolicy->assertUserActivityPoked(
9047 {{milliseconds_to_nanoseconds(200), USER_ACTIVITY_EVENT_TOUCH, ADISPLAY_ID_DEFAULT}});
9048
9049 notifyAndConsumeMotion(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
9050 milliseconds_to_nanoseconds(280));
9051 mFakePolicy->assertUserActivityNotPoked();
9052
9053 notifyAndConsumeMotion(ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
9054 milliseconds_to_nanoseconds(340));
9055 mFakePolicy->assertUserActivityPoked(
9056 {{milliseconds_to_nanoseconds(340), USER_ACTIVITY_EVENT_TOUCH, ADISPLAY_ID_DEFAULT}});
9057}
9058
9059TEST_F_WITH_FLAGS(
9060 InputDispatcherUserActivityPokeTests, ZeroMinPokeTimeDisablesRateLimiting,
9061 REQUIRES_FLAGS_ENABLED(ACONFIG_FLAG(com::android::input::flags,
9062 rate_limit_user_activity_poke_in_dispatcher))) {
9063 mDispatcher->setMinTimeBetweenUserActivityPokes(0ms);
9064
9065 notifyAndConsumeMotion(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, 20);
9066 mFakePolicy->assertUserActivityPoked();
9067
9068 notifyAndConsumeMotion(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, 30);
9069 mFakePolicy->assertUserActivityPoked();
9070}
9071
chaviwfd6d3512019-03-25 13:23:49 -07009072class InputDispatcherOnPointerDownOutsideFocus : public InputDispatcherTest {
Prabir Pradhan3608aad2019-10-02 17:08:26 -07009073 virtual void SetUp() override {
chaviwfd6d3512019-03-25 13:23:49 -07009074 InputDispatcherTest::SetUp();
9075
Chris Yea209fde2020-07-22 13:54:51 -07009076 std::shared_ptr<FakeApplicationHandle> application =
9077 std::make_shared<FakeApplicationHandle>();
Siarhei Vishniakou870ecec2020-12-09 08:07:46 -10009078 mUnfocusedWindow =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07009079 sp<FakeWindowHandle>::make(application, mDispatcher, "Top", ADISPLAY_ID_DEFAULT);
chaviwfd6d3512019-03-25 13:23:49 -07009080 mUnfocusedWindow->setFrame(Rect(0, 0, 30, 30));
chaviwfd6d3512019-03-25 13:23:49 -07009081
Siarhei Vishniakoub9b15352019-11-26 13:19:26 -08009082 mFocusedWindow =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07009083 sp<FakeWindowHandle>::make(application, mDispatcher, "Second", ADISPLAY_ID_DEFAULT);
Siarhei Vishniakoub9b15352019-11-26 13:19:26 -08009084 mFocusedWindow->setFrame(Rect(50, 50, 100, 100));
chaviwfd6d3512019-03-25 13:23:49 -07009085
9086 // Set focused application.
9087 mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application);
Vishnu Nair47074b82020-08-14 11:54:47 -07009088 mFocusedWindow->setFocusable(true);
chaviwfd6d3512019-03-25 13:23:49 -07009089
9090 // Expect one focus window exist in display.
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07009091 mDispatcher->onWindowInfosChanged(
9092 {{*mUnfocusedWindow->getInfo(), *mFocusedWindow->getInfo()}, {}, 0, 0});
Vishnu Nair958da932020-08-21 17:12:37 -07009093 setFocusedWindow(mFocusedWindow);
Siarhei Vishniakouf1035d42019-09-20 16:32:01 +01009094 mFocusedWindow->consumeFocusEvent(true);
chaviwfd6d3512019-03-25 13:23:49 -07009095 }
9096
Prabir Pradhan3608aad2019-10-02 17:08:26 -07009097 virtual void TearDown() override {
chaviwfd6d3512019-03-25 13:23:49 -07009098 InputDispatcherTest::TearDown();
9099
9100 mUnfocusedWindow.clear();
Siarhei Vishniakoub9b15352019-11-26 13:19:26 -08009101 mFocusedWindow.clear();
chaviwfd6d3512019-03-25 13:23:49 -07009102 }
9103
9104protected:
9105 sp<FakeWindowHandle> mUnfocusedWindow;
Siarhei Vishniakoub9b15352019-11-26 13:19:26 -08009106 sp<FakeWindowHandle> mFocusedWindow;
Siarhei Vishniakoufb9fcda2020-05-04 14:59:19 -07009107 static constexpr PointF FOCUSED_WINDOW_TOUCH_POINT = {60, 60};
chaviwfd6d3512019-03-25 13:23:49 -07009108};
9109
9110// Have two windows, one with focus. Inject MotionEvent with source TOUCHSCREEN and action
9111// DOWN on the window that doesn't have focus. Ensure the window that didn't have focus received
9112// the onPointerDownOutsideFocus callback.
9113TEST_F(InputDispatcherOnPointerDownOutsideFocus, OnPointerDownOutsideFocus_Success) {
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08009114 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07009115 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
Siarhei Vishniakoufb9fcda2020-05-04 14:59:19 -07009116 {20, 20}))
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08009117 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
Siarhei Vishniakou03aee2a2020-04-13 20:44:54 -07009118 mUnfocusedWindow->consumeMotionDown();
chaviwfd6d3512019-03-25 13:23:49 -07009119
Siarhei Vishniakou2bfa9052019-11-21 18:10:54 -08009120 ASSERT_TRUE(mDispatcher->waitForIdle());
chaviwfd6d3512019-03-25 13:23:49 -07009121 mFakePolicy->assertOnPointerDownEquals(mUnfocusedWindow->getToken());
9122}
9123
9124// Have two windows, one with focus. Inject MotionEvent with source TRACKBALL and action
9125// DOWN on the window that doesn't have focus. Ensure no window received the
9126// onPointerDownOutsideFocus callback.
9127TEST_F(InputDispatcherOnPointerDownOutsideFocus, OnPointerDownOutsideFocus_NonPointerSource) {
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08009128 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07009129 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TRACKBALL, ADISPLAY_ID_DEFAULT,
9130 {20, 20}))
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08009131 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
Siarhei Vishniakou03aee2a2020-04-13 20:44:54 -07009132 mFocusedWindow->consumeMotionDown();
chaviwfd6d3512019-03-25 13:23:49 -07009133
Siarhei Vishniakou2bfa9052019-11-21 18:10:54 -08009134 ASSERT_TRUE(mDispatcher->waitForIdle());
9135 mFakePolicy->assertOnPointerDownWasNotCalled();
chaviwfd6d3512019-03-25 13:23:49 -07009136}
9137
9138// Have two windows, one with focus. Inject KeyEvent with action DOWN on the window that doesn't
9139// have focus. Ensure no window received the onPointerDownOutsideFocus callback.
9140TEST_F(InputDispatcherOnPointerDownOutsideFocus, OnPointerDownOutsideFocus_NonMotionFailure) {
Prabir Pradhan93f342c2021-03-11 15:05:30 -08009141 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07009142 injectKeyDownNoRepeat(*mDispatcher, ADISPLAY_ID_DEFAULT))
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08009143 << "Inject key event should return InputEventInjectionResult::SUCCEEDED";
Siarhei Vishniakou03aee2a2020-04-13 20:44:54 -07009144 mFocusedWindow->consumeKeyDown(ADISPLAY_ID_DEFAULT);
chaviwfd6d3512019-03-25 13:23:49 -07009145
Siarhei Vishniakou2bfa9052019-11-21 18:10:54 -08009146 ASSERT_TRUE(mDispatcher->waitForIdle());
9147 mFakePolicy->assertOnPointerDownWasNotCalled();
chaviwfd6d3512019-03-25 13:23:49 -07009148}
9149
9150// Have two windows, one with focus. Inject MotionEvent with source TOUCHSCREEN and action
9151// DOWN on the window that already has focus. Ensure no window received the
9152// onPointerDownOutsideFocus callback.
Siarhei Vishniakou870ecec2020-12-09 08:07:46 -10009153TEST_F(InputDispatcherOnPointerDownOutsideFocus, OnPointerDownOutsideFocus_OnAlreadyFocusedWindow) {
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08009154 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07009155 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
Siarhei Vishniakoufb9fcda2020-05-04 14:59:19 -07009156 FOCUSED_WINDOW_TOUCH_POINT))
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08009157 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
Siarhei Vishniakou03aee2a2020-04-13 20:44:54 -07009158 mFocusedWindow->consumeMotionDown();
chaviwfd6d3512019-03-25 13:23:49 -07009159
Siarhei Vishniakou2bfa9052019-11-21 18:10:54 -08009160 ASSERT_TRUE(mDispatcher->waitForIdle());
9161 mFakePolicy->assertOnPointerDownWasNotCalled();
chaviwfd6d3512019-03-25 13:23:49 -07009162}
9163
Prabir Pradhan47cf0a02021-03-11 20:30:57 -08009164// Have two windows, one with focus. Injecting a trusted DOWN MotionEvent with the flag
9165// NO_FOCUS_CHANGE on the unfocused window should not call the onPointerDownOutsideFocus callback.
9166TEST_F(InputDispatcherOnPointerDownOutsideFocus, NoFocusChangeFlag) {
9167 const MotionEvent event =
9168 MotionEventBuilder(AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_MOUSE)
9169 .eventTime(systemTime(SYSTEM_TIME_MONOTONIC))
Siarhei Vishniakou6d73f832022-07-21 17:27:03 -07009170 .pointer(PointerBuilder(/*id=*/0, ToolType::FINGER).x(20).y(20))
Prabir Pradhan47cf0a02021-03-11 20:30:57 -08009171 .addFlag(AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE)
9172 .build();
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07009173 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectMotionEvent(*mDispatcher, event))
Prabir Pradhan47cf0a02021-03-11 20:30:57 -08009174 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
9175 mUnfocusedWindow->consumeAnyMotionDown(ADISPLAY_ID_DEFAULT, AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
9176
9177 ASSERT_TRUE(mDispatcher->waitForIdle());
9178 mFakePolicy->assertOnPointerDownWasNotCalled();
9179 // Ensure that the unfocused window did not receive any FOCUS events.
9180 mUnfocusedWindow->assertNoEvents();
9181}
9182
chaviwaf87b3e2019-10-01 16:59:28 -07009183// These tests ensures we can send touch events to a single client when there are multiple input
9184// windows that point to the same client token.
9185class InputDispatcherMultiWindowSameTokenTests : public InputDispatcherTest {
9186 virtual void SetUp() override {
9187 InputDispatcherTest::SetUp();
9188
Chris Yea209fde2020-07-22 13:54:51 -07009189 std::shared_ptr<FakeApplicationHandle> application =
9190 std::make_shared<FakeApplicationHandle>();
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07009191 mWindow1 = sp<FakeWindowHandle>::make(application, mDispatcher, "Fake Window 1",
9192 ADISPLAY_ID_DEFAULT);
chaviwaf87b3e2019-10-01 16:59:28 -07009193 mWindow1->setFrame(Rect(0, 0, 100, 100));
9194
Prabir Pradhane7cc69c2024-01-05 21:35:28 +00009195 mWindow2 = mWindow1->clone(ADISPLAY_ID_DEFAULT);
chaviwaf87b3e2019-10-01 16:59:28 -07009196 mWindow2->setFrame(Rect(100, 100, 200, 200));
9197
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07009198 mDispatcher->onWindowInfosChanged({{*mWindow1->getInfo(), *mWindow2->getInfo()}, {}, 0, 0});
chaviwaf87b3e2019-10-01 16:59:28 -07009199 }
9200
9201protected:
9202 sp<FakeWindowHandle> mWindow1;
9203 sp<FakeWindowHandle> mWindow2;
9204
9205 // Helper function to convert the point from screen coordinates into the window's space
chaviw3277faf2021-05-19 16:45:23 -05009206 static PointF getPointInWindow(const WindowInfo* windowInfo, const PointF& point) {
chaviw1ff3d1e2020-07-01 15:53:47 -07009207 vec2 vals = windowInfo->transform.transform(point.x, point.y);
9208 return {vals.x, vals.y};
chaviwaf87b3e2019-10-01 16:59:28 -07009209 }
9210
9211 void consumeMotionEvent(const sp<FakeWindowHandle>& window, int32_t expectedAction,
9212 const std::vector<PointF>& points) {
Siarhei Vishniakouf1035d42019-09-20 16:32:01 +01009213 const std::string name = window->getName();
Siarhei Vishniakoud3061ab2023-12-18 20:41:08 -08009214 std::unique_ptr<MotionEvent> motionEvent =
Prabir Pradhan7662a8d2023-12-15 01:58:14 +00009215 window->consumeMotionEvent(WithMotionAction(expectedAction));
Siarhei Vishniakoud3061ab2023-12-18 20:41:08 -08009216 ASSERT_NE(nullptr, motionEvent);
9217 ASSERT_EQ(points.size(), motionEvent->getPointerCount());
chaviwaf87b3e2019-10-01 16:59:28 -07009218
9219 for (size_t i = 0; i < points.size(); i++) {
9220 float expectedX = points[i].x;
9221 float expectedY = points[i].y;
9222
Siarhei Vishniakoud3061ab2023-12-18 20:41:08 -08009223 EXPECT_EQ(expectedX, motionEvent->getX(i))
chaviwaf87b3e2019-10-01 16:59:28 -07009224 << "expected " << expectedX << " for x[" << i << "] coord of " << name.c_str()
Siarhei Vishniakoud3061ab2023-12-18 20:41:08 -08009225 << ", got " << motionEvent->getX(i);
9226 EXPECT_EQ(expectedY, motionEvent->getY(i))
chaviwaf87b3e2019-10-01 16:59:28 -07009227 << "expected " << expectedY << " for y[" << i << "] coord of " << name.c_str()
Siarhei Vishniakoud3061ab2023-12-18 20:41:08 -08009228 << ", got " << motionEvent->getY(i);
chaviwaf87b3e2019-10-01 16:59:28 -07009229 }
9230 }
chaviw9eaa22c2020-07-01 16:21:27 -07009231
Prabir Pradhanbb3f1c02024-01-04 20:17:14 +00009232 void touchAndAssertPositions(sp<FakeWindowHandle> touchedWindow, int32_t action,
9233 const std::vector<PointF>& touchedPoints,
chaviw9eaa22c2020-07-01 16:21:27 -07009234 std::vector<PointF> expectedPoints) {
Prabir Pradhan678438e2023-04-13 19:32:51 +00009235 mDispatcher->notifyMotion(generateMotionArgs(action, AINPUT_SOURCE_TOUCHSCREEN,
9236 ADISPLAY_ID_DEFAULT, touchedPoints));
chaviw9eaa22c2020-07-01 16:21:27 -07009237
Prabir Pradhanbb3f1c02024-01-04 20:17:14 +00009238 consumeMotionEvent(touchedWindow, action, expectedPoints);
chaviw9eaa22c2020-07-01 16:21:27 -07009239 }
chaviwaf87b3e2019-10-01 16:59:28 -07009240};
9241
9242TEST_F(InputDispatcherMultiWindowSameTokenTests, SingleTouchSameScale) {
9243 // Touch Window 1
9244 PointF touchedPoint = {10, 10};
9245 PointF expectedPoint = getPointInWindow(mWindow1->getInfo(), touchedPoint);
Prabir Pradhanbb3f1c02024-01-04 20:17:14 +00009246 touchAndAssertPositions(mWindow1, AMOTION_EVENT_ACTION_DOWN, {touchedPoint}, {expectedPoint});
chaviwaf87b3e2019-10-01 16:59:28 -07009247
9248 // Release touch on Window 1
Prabir Pradhanbb3f1c02024-01-04 20:17:14 +00009249 touchAndAssertPositions(mWindow1, AMOTION_EVENT_ACTION_UP, {touchedPoint}, {expectedPoint});
chaviwaf87b3e2019-10-01 16:59:28 -07009250
9251 // Touch Window 2
9252 touchedPoint = {150, 150};
9253 expectedPoint = getPointInWindow(mWindow2->getInfo(), touchedPoint);
Prabir Pradhanbb3f1c02024-01-04 20:17:14 +00009254 touchAndAssertPositions(mWindow2, AMOTION_EVENT_ACTION_DOWN, {touchedPoint}, {expectedPoint});
chaviwaf87b3e2019-10-01 16:59:28 -07009255}
9256
chaviw9eaa22c2020-07-01 16:21:27 -07009257TEST_F(InputDispatcherMultiWindowSameTokenTests, SingleTouchDifferentTransform) {
9258 // Set scale value for window2
chaviwaf87b3e2019-10-01 16:59:28 -07009259 mWindow2->setWindowScale(0.5f, 0.5f);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07009260 mDispatcher->onWindowInfosChanged({{*mWindow1->getInfo(), *mWindow2->getInfo()}, {}, 0, 0});
chaviwaf87b3e2019-10-01 16:59:28 -07009261
9262 // Touch Window 1
9263 PointF touchedPoint = {10, 10};
9264 PointF expectedPoint = getPointInWindow(mWindow1->getInfo(), touchedPoint);
Prabir Pradhanbb3f1c02024-01-04 20:17:14 +00009265 touchAndAssertPositions(mWindow1, AMOTION_EVENT_ACTION_DOWN, {touchedPoint}, {expectedPoint});
chaviwaf87b3e2019-10-01 16:59:28 -07009266 // Release touch on Window 1
Prabir Pradhanbb3f1c02024-01-04 20:17:14 +00009267 touchAndAssertPositions(mWindow1, AMOTION_EVENT_ACTION_UP, {touchedPoint}, {expectedPoint});
chaviwaf87b3e2019-10-01 16:59:28 -07009268
9269 // Touch Window 2
9270 touchedPoint = {150, 150};
9271 expectedPoint = getPointInWindow(mWindow2->getInfo(), touchedPoint);
Prabir Pradhanbb3f1c02024-01-04 20:17:14 +00009272 touchAndAssertPositions(mWindow2, AMOTION_EVENT_ACTION_DOWN, {touchedPoint}, {expectedPoint});
9273 touchAndAssertPositions(mWindow2, AMOTION_EVENT_ACTION_UP, {touchedPoint}, {expectedPoint});
chaviwaf87b3e2019-10-01 16:59:28 -07009274
chaviw9eaa22c2020-07-01 16:21:27 -07009275 // Update the transform so rotation is set
9276 mWindow2->setWindowTransform(0, -1, 1, 0);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07009277 mDispatcher->onWindowInfosChanged({{*mWindow1->getInfo(), *mWindow2->getInfo()}, {}, 0, 0});
chaviw9eaa22c2020-07-01 16:21:27 -07009278 expectedPoint = getPointInWindow(mWindow2->getInfo(), touchedPoint);
Prabir Pradhanbb3f1c02024-01-04 20:17:14 +00009279 touchAndAssertPositions(mWindow2, AMOTION_EVENT_ACTION_DOWN, {touchedPoint}, {expectedPoint});
chaviwaf87b3e2019-10-01 16:59:28 -07009280}
9281
chaviw9eaa22c2020-07-01 16:21:27 -07009282TEST_F(InputDispatcherMultiWindowSameTokenTests, MultipleTouchDifferentTransform) {
Chavi Weingarten65f98b82020-01-16 18:56:50 +00009283 mWindow2->setWindowScale(0.5f, 0.5f);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07009284 mDispatcher->onWindowInfosChanged({{*mWindow1->getInfo(), *mWindow2->getInfo()}, {}, 0, 0});
Chavi Weingarten65f98b82020-01-16 18:56:50 +00009285
9286 // Touch Window 1
9287 std::vector<PointF> touchedPoints = {PointF{10, 10}};
9288 std::vector<PointF> expectedPoints = {getPointInWindow(mWindow1->getInfo(), touchedPoints[0])};
Prabir Pradhanbb3f1c02024-01-04 20:17:14 +00009289 touchAndAssertPositions(mWindow1, AMOTION_EVENT_ACTION_DOWN, touchedPoints, expectedPoints);
Chavi Weingarten65f98b82020-01-16 18:56:50 +00009290
9291 // Touch Window 2
Prabir Pradhanbb3f1c02024-01-04 20:17:14 +00009292 // Since this is part of the same touch gesture that has already been dispatched to Window 1,
9293 // the touch stream from Window 2 will be merged with the stream in Window 1. The merged stream
9294 // will continue to be dispatched through Window 1.
chaviw9eaa22c2020-07-01 16:21:27 -07009295 touchedPoints.push_back(PointF{150, 150});
9296 expectedPoints.push_back(getPointInWindow(mWindow2->getInfo(), touchedPoints[1]));
Prabir Pradhanbb3f1c02024-01-04 20:17:14 +00009297 touchAndAssertPositions(mWindow1, POINTER_1_DOWN, touchedPoints, expectedPoints);
Chavi Weingarten65f98b82020-01-16 18:56:50 +00009298
chaviw9eaa22c2020-07-01 16:21:27 -07009299 // Release Window 2
Prabir Pradhanbb3f1c02024-01-04 20:17:14 +00009300 touchAndAssertPositions(mWindow1, POINTER_1_UP, touchedPoints, expectedPoints);
chaviw9eaa22c2020-07-01 16:21:27 -07009301 expectedPoints.pop_back();
Chavi Weingarten65f98b82020-01-16 18:56:50 +00009302
chaviw9eaa22c2020-07-01 16:21:27 -07009303 // Update the transform so rotation is set for Window 2
9304 mWindow2->setWindowTransform(0, -1, 1, 0);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07009305 mDispatcher->onWindowInfosChanged({{*mWindow1->getInfo(), *mWindow2->getInfo()}, {}, 0, 0});
chaviw9eaa22c2020-07-01 16:21:27 -07009306 expectedPoints.push_back(getPointInWindow(mWindow2->getInfo(), touchedPoints[1]));
Prabir Pradhanbb3f1c02024-01-04 20:17:14 +00009307 touchAndAssertPositions(mWindow1, POINTER_1_DOWN, touchedPoints, expectedPoints);
Chavi Weingarten65f98b82020-01-16 18:56:50 +00009308}
9309
chaviw9eaa22c2020-07-01 16:21:27 -07009310TEST_F(InputDispatcherMultiWindowSameTokenTests, MultipleTouchMoveDifferentTransform) {
Chavi Weingarten65f98b82020-01-16 18:56:50 +00009311 mWindow2->setWindowScale(0.5f, 0.5f);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07009312 mDispatcher->onWindowInfosChanged({{*mWindow1->getInfo(), *mWindow2->getInfo()}, {}, 0, 0});
Chavi Weingarten65f98b82020-01-16 18:56:50 +00009313
9314 // Touch Window 1
9315 std::vector<PointF> touchedPoints = {PointF{10, 10}};
9316 std::vector<PointF> expectedPoints = {getPointInWindow(mWindow1->getInfo(), touchedPoints[0])};
Prabir Pradhanbb3f1c02024-01-04 20:17:14 +00009317 touchAndAssertPositions(mWindow1, AMOTION_EVENT_ACTION_DOWN, touchedPoints, expectedPoints);
Chavi Weingarten65f98b82020-01-16 18:56:50 +00009318
9319 // Touch Window 2
chaviw9eaa22c2020-07-01 16:21:27 -07009320 touchedPoints.push_back(PointF{150, 150});
9321 expectedPoints.push_back(getPointInWindow(mWindow2->getInfo(), touchedPoints[1]));
Chavi Weingarten65f98b82020-01-16 18:56:50 +00009322
Prabir Pradhanbb3f1c02024-01-04 20:17:14 +00009323 touchAndAssertPositions(mWindow1, POINTER_1_DOWN, touchedPoints, expectedPoints);
Chavi Weingarten65f98b82020-01-16 18:56:50 +00009324
9325 // Move both windows
9326 touchedPoints = {{20, 20}, {175, 175}};
9327 expectedPoints = {getPointInWindow(mWindow1->getInfo(), touchedPoints[0]),
9328 getPointInWindow(mWindow2->getInfo(), touchedPoints[1])};
9329
Prabir Pradhanbb3f1c02024-01-04 20:17:14 +00009330 touchAndAssertPositions(mWindow1, AMOTION_EVENT_ACTION_MOVE, touchedPoints, expectedPoints);
Chavi Weingarten65f98b82020-01-16 18:56:50 +00009331
chaviw9eaa22c2020-07-01 16:21:27 -07009332 // Release Window 2
Prabir Pradhanbb3f1c02024-01-04 20:17:14 +00009333 touchAndAssertPositions(mWindow1, POINTER_1_UP, touchedPoints, expectedPoints);
chaviw9eaa22c2020-07-01 16:21:27 -07009334 expectedPoints.pop_back();
9335
9336 // Touch Window 2
9337 mWindow2->setWindowTransform(0, -1, 1, 0);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07009338 mDispatcher->onWindowInfosChanged({{*mWindow1->getInfo(), *mWindow2->getInfo()}, {}, 0, 0});
chaviw9eaa22c2020-07-01 16:21:27 -07009339 expectedPoints.push_back(getPointInWindow(mWindow2->getInfo(), touchedPoints[1]));
Prabir Pradhanbb3f1c02024-01-04 20:17:14 +00009340 touchAndAssertPositions(mWindow1, POINTER_1_DOWN, touchedPoints, expectedPoints);
chaviw9eaa22c2020-07-01 16:21:27 -07009341
9342 // Move both windows
9343 touchedPoints = {{20, 20}, {175, 175}};
9344 expectedPoints = {getPointInWindow(mWindow1->getInfo(), touchedPoints[0]),
9345 getPointInWindow(mWindow2->getInfo(), touchedPoints[1])};
9346
Prabir Pradhanbb3f1c02024-01-04 20:17:14 +00009347 touchAndAssertPositions(mWindow1, AMOTION_EVENT_ACTION_MOVE, touchedPoints, expectedPoints);
Chavi Weingarten65f98b82020-01-16 18:56:50 +00009348}
9349
9350TEST_F(InputDispatcherMultiWindowSameTokenTests, MultipleWindowsFirstTouchWithScale) {
9351 mWindow1->setWindowScale(0.5f, 0.5f);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07009352 mDispatcher->onWindowInfosChanged({{*mWindow1->getInfo(), *mWindow2->getInfo()}, {}, 0, 0});
Chavi Weingarten65f98b82020-01-16 18:56:50 +00009353
9354 // Touch Window 1
9355 std::vector<PointF> touchedPoints = {PointF{10, 10}};
9356 std::vector<PointF> expectedPoints = {getPointInWindow(mWindow1->getInfo(), touchedPoints[0])};
Prabir Pradhanbb3f1c02024-01-04 20:17:14 +00009357 touchAndAssertPositions(mWindow1, AMOTION_EVENT_ACTION_DOWN, touchedPoints, expectedPoints);
Chavi Weingarten65f98b82020-01-16 18:56:50 +00009358
9359 // Touch Window 2
chaviw9eaa22c2020-07-01 16:21:27 -07009360 touchedPoints.push_back(PointF{150, 150});
9361 expectedPoints.push_back(getPointInWindow(mWindow2->getInfo(), touchedPoints[1]));
Chavi Weingarten65f98b82020-01-16 18:56:50 +00009362
Prabir Pradhanbb3f1c02024-01-04 20:17:14 +00009363 touchAndAssertPositions(mWindow1, POINTER_1_DOWN, touchedPoints, expectedPoints);
Chavi Weingarten65f98b82020-01-16 18:56:50 +00009364
9365 // Move both windows
9366 touchedPoints = {{20, 20}, {175, 175}};
9367 expectedPoints = {getPointInWindow(mWindow1->getInfo(), touchedPoints[0]),
9368 getPointInWindow(mWindow2->getInfo(), touchedPoints[1])};
9369
Prabir Pradhanbb3f1c02024-01-04 20:17:14 +00009370 touchAndAssertPositions(mWindow1, AMOTION_EVENT_ACTION_MOVE, touchedPoints, expectedPoints);
Chavi Weingarten65f98b82020-01-16 18:56:50 +00009371}
9372
Siarhei Vishniakou0f6558d2023-04-21 12:05:13 -07009373/**
9374 * When one of the windows is slippery, the touch should not slip into the other window with the
9375 * same input channel.
9376 */
9377TEST_F(InputDispatcherMultiWindowSameTokenTests, TouchDoesNotSlipEvenIfSlippery) {
9378 mWindow1->setSlippery(true);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07009379 mDispatcher->onWindowInfosChanged({{*mWindow1->getInfo(), *mWindow2->getInfo()}, {}, 0, 0});
Siarhei Vishniakou0f6558d2023-04-21 12:05:13 -07009380
9381 // Touch down in window 1
9382 mDispatcher->notifyMotion(generateMotionArgs(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN,
9383 ADISPLAY_ID_DEFAULT, {{50, 50}}));
9384 consumeMotionEvent(mWindow1, ACTION_DOWN, {{50, 50}});
9385
9386 // Move touch to be above window 2. Even though window 1 is slippery, touch should not slip.
9387 // That means the gesture should continue normally, without any ACTION_CANCEL or ACTION_DOWN
9388 // getting generated.
9389 mDispatcher->notifyMotion(generateMotionArgs(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN,
9390 ADISPLAY_ID_DEFAULT, {{150, 150}}));
9391
9392 consumeMotionEvent(mWindow1, ACTION_MOVE, {{150, 150}});
9393}
9394
Siarhei Vishniakoud5876ba2023-05-15 17:58:34 -07009395/**
9396 * When hover starts in one window and continues into the other, there should be a HOVER_EXIT and
9397 * a HOVER_ENTER generated, even if the windows have the same token. This is because the new window
9398 * that the pointer is hovering over may have a different transform.
9399 */
9400TEST_F(InputDispatcherMultiWindowSameTokenTests, HoverIntoClone) {
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07009401 mDispatcher->onWindowInfosChanged({{*mWindow1->getInfo(), *mWindow2->getInfo()}, {}, 0, 0});
Siarhei Vishniakoud5876ba2023-05-15 17:58:34 -07009402
9403 // Start hover in window 1
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -07009404 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_ENTER, AINPUT_SOURCE_TOUCHSCREEN)
9405 .pointer(PointerBuilder(0, ToolType::FINGER).x(50).y(50))
9406 .build());
Siarhei Vishniakoud5876ba2023-05-15 17:58:34 -07009407 consumeMotionEvent(mWindow1, ACTION_HOVER_ENTER,
9408 {getPointInWindow(mWindow1->getInfo(), PointF{50, 50})});
Siarhei Vishniakoud5876ba2023-05-15 17:58:34 -07009409 // Move hover to window 2.
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -07009410 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_MOVE, AINPUT_SOURCE_TOUCHSCREEN)
9411 .pointer(PointerBuilder(0, ToolType::FINGER).x(150).y(150))
9412 .build());
Siarhei Vishniakoud5876ba2023-05-15 17:58:34 -07009413 consumeMotionEvent(mWindow1, ACTION_HOVER_EXIT, {{50, 50}});
Prabir Pradhanbb3f1c02024-01-04 20:17:14 +00009414 consumeMotionEvent(mWindow2, ACTION_HOVER_ENTER,
Siarhei Vishniakoud5876ba2023-05-15 17:58:34 -07009415 {getPointInWindow(mWindow2->getInfo(), PointF{150, 150})});
9416}
9417
Siarhei Vishniakou4cb50ca2020-05-26 21:43:02 -07009418class InputDispatcherSingleWindowAnr : public InputDispatcherTest {
9419 virtual void SetUp() override {
9420 InputDispatcherTest::SetUp();
9421
Chris Yea209fde2020-07-22 13:54:51 -07009422 mApplication = std::make_shared<FakeApplicationHandle>();
Siarhei Vishniakouf83c6932023-07-07 17:48:10 -07009423 mApplication->setDispatchingTimeout(100ms);
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07009424 mWindow = sp<FakeWindowHandle>::make(mApplication, mDispatcher, "TestWindow",
9425 ADISPLAY_ID_DEFAULT);
Siarhei Vishniakou4cb50ca2020-05-26 21:43:02 -07009426 mWindow->setFrame(Rect(0, 0, 30, 30));
Siarhei Vishniakouf83c6932023-07-07 17:48:10 -07009427 mWindow->setDispatchingTimeout(100ms);
Vishnu Nair47074b82020-08-14 11:54:47 -07009428 mWindow->setFocusable(true);
Siarhei Vishniakou4cb50ca2020-05-26 21:43:02 -07009429
9430 // Set focused application.
9431 mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, mApplication);
9432
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07009433 mDispatcher->onWindowInfosChanged({{*mWindow->getInfo()}, {}, 0, 0});
Vishnu Nair958da932020-08-21 17:12:37 -07009434 setFocusedWindow(mWindow);
Siarhei Vishniakou4cb50ca2020-05-26 21:43:02 -07009435 mWindow->consumeFocusEvent(true);
9436 }
9437
9438 virtual void TearDown() override {
9439 InputDispatcherTest::TearDown();
9440 mWindow.clear();
9441 }
9442
9443protected:
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07009444 static constexpr std::chrono::duration SPY_TIMEOUT = 200ms;
Chris Yea209fde2020-07-22 13:54:51 -07009445 std::shared_ptr<FakeApplicationHandle> mApplication;
Siarhei Vishniakou4cb50ca2020-05-26 21:43:02 -07009446 sp<FakeWindowHandle> mWindow;
9447 static constexpr PointF WINDOW_LOCATION = {20, 20};
9448
9449 void tapOnWindow() {
Siarhei Vishniakou67bf2162023-11-16 13:29:50 -08009450 const auto touchingPointer = PointerBuilder(/*id=*/0, ToolType::FINGER)
9451 .x(WINDOW_LOCATION.x)
9452 .y(WINDOW_LOCATION.y);
9453 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
9454 .pointer(touchingPointer)
9455 .build());
9456 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN)
9457 .pointer(touchingPointer)
9458 .build());
Siarhei Vishniakou4cb50ca2020-05-26 21:43:02 -07009459 }
Prabir Pradhan1376fcd2022-01-21 09:56:35 -08009460
9461 sp<FakeWindowHandle> addSpyWindow() {
9462 sp<FakeWindowHandle> spy =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07009463 sp<FakeWindowHandle>::make(mApplication, mDispatcher, "Spy", ADISPLAY_ID_DEFAULT);
Prabir Pradhan1376fcd2022-01-21 09:56:35 -08009464 spy->setTrustedOverlay(true);
9465 spy->setFocusable(false);
Prabir Pradhan51e7db02022-02-07 06:02:57 -08009466 spy->setSpy(true);
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07009467 spy->setDispatchingTimeout(SPY_TIMEOUT);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07009468 mDispatcher->onWindowInfosChanged({{*spy->getInfo(), *mWindow->getInfo()}, {}, 0, 0});
Prabir Pradhan1376fcd2022-01-21 09:56:35 -08009469 return spy;
9470 }
Siarhei Vishniakou4cb50ca2020-05-26 21:43:02 -07009471};
9472
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009473// Send a tap and respond, which should not cause an ANR.
9474TEST_F(InputDispatcherSingleWindowAnr, WhenTouchIsConsumed_NoAnr) {
9475 tapOnWindow();
9476 mWindow->consumeMotionDown();
9477 mWindow->consumeMotionUp();
9478 ASSERT_TRUE(mDispatcher->waitForIdle());
9479 mFakePolicy->assertNotifyAnrWasNotCalled();
9480}
9481
9482// Send a regular key and respond, which should not cause an ANR.
9483TEST_F(InputDispatcherSingleWindowAnr, WhenKeyIsConsumed_NoAnr) {
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07009484 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectKeyDownNoRepeat(*mDispatcher));
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009485 mWindow->consumeKeyDown(ADISPLAY_ID_NONE);
9486 ASSERT_TRUE(mDispatcher->waitForIdle());
9487 mFakePolicy->assertNotifyAnrWasNotCalled();
9488}
9489
Siarhei Vishniakoue41c4512020-09-08 19:35:58 -05009490TEST_F(InputDispatcherSingleWindowAnr, WhenFocusedApplicationChanges_NoAnr) {
9491 mWindow->setFocusable(false);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07009492 mDispatcher->onWindowInfosChanged({{*mWindow->getInfo()}, {}, 0, 0});
Siarhei Vishniakoue41c4512020-09-08 19:35:58 -05009493 mWindow->consumeFocusEvent(false);
9494
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08009495 InputEventInjectionResult result =
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07009496 injectKey(*mDispatcher, AKEY_EVENT_ACTION_DOWN, /*repeatCount=*/0, ADISPLAY_ID_DEFAULT,
9497 InputEventInjectionSync::NONE, CONSUME_TIMEOUT_EVENT_EXPECTED,
Harry Cutts33476232023-01-30 19:57:29 +00009498 /*allowKeyRepeat=*/false);
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08009499 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, result);
Siarhei Vishniakoue41c4512020-09-08 19:35:58 -05009500 // Key will not go to window because we have no focused window.
9501 // The 'no focused window' ANR timer should start instead.
9502
9503 // Now, the focused application goes away.
9504 mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, nullptr);
9505 // The key should get dropped and there should be no ANR.
9506
9507 ASSERT_TRUE(mDispatcher->waitForIdle());
9508 mFakePolicy->assertNotifyAnrWasNotCalled();
9509}
9510
Siarhei Vishniakou4cb50ca2020-05-26 21:43:02 -07009511// Send an event to the app and have the app not respond right away.
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009512// When ANR is raised, policy will tell the dispatcher to cancel the events for that window.
9513// So InputDispatcher will enqueue ACTION_CANCEL event as well.
Siarhei Vishniakou4cb50ca2020-05-26 21:43:02 -07009514TEST_F(InputDispatcherSingleWindowAnr, OnPointerDown_BasicAnr) {
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08009515 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07009516 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
Siarhei Vishniakou4cb50ca2020-05-26 21:43:02 -07009517 WINDOW_LOCATION));
9518
Siarhei Vishniakoud3061ab2023-12-18 20:41:08 -08009519 const auto [sequenceNum, _] = mWindow->receiveEvent(); // ACTION_DOWN
Siarhei Vishniakou4cb50ca2020-05-26 21:43:02 -07009520 ASSERT_TRUE(sequenceNum);
9521 const std::chrono::duration timeout = mWindow->getDispatchingTimeout(DISPATCHING_TIMEOUT);
Prabir Pradhanedd96402022-02-15 01:46:16 -08009522 mFakePolicy->assertNotifyWindowUnresponsiveWasCalled(timeout, mWindow);
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009523
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009524 mWindow->finishEvent(*sequenceNum);
Siarhei Vishniakou1ae72f12023-01-29 12:55:30 -08009525 mWindow->consumeMotionEvent(
9526 AllOf(WithMotionAction(ACTION_CANCEL), WithDisplayId(ADISPLAY_ID_DEFAULT)));
Siarhei Vishniakou4cb50ca2020-05-26 21:43:02 -07009527 ASSERT_TRUE(mDispatcher->waitForIdle());
Prabir Pradhanedd96402022-02-15 01:46:16 -08009528 mFakePolicy->assertNotifyWindowResponsiveWasCalled(mWindow->getToken(), mWindow->getPid());
Siarhei Vishniakou4cb50ca2020-05-26 21:43:02 -07009529}
9530
9531// Send a key to the app and have the app not respond right away.
9532TEST_F(InputDispatcherSingleWindowAnr, OnKeyDown_BasicAnr) {
9533 // Inject a key, and don't respond - expect that ANR is called.
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07009534 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectKeyDownNoRepeat(*mDispatcher));
Siarhei Vishniakoud3061ab2023-12-18 20:41:08 -08009535 const auto [sequenceNum, _] = mWindow->receiveEvent();
Siarhei Vishniakou4cb50ca2020-05-26 21:43:02 -07009536 ASSERT_TRUE(sequenceNum);
Siarhei Vishniakou4cb50ca2020-05-26 21:43:02 -07009537 const std::chrono::duration timeout = mWindow->getDispatchingTimeout(DISPATCHING_TIMEOUT);
Prabir Pradhanedd96402022-02-15 01:46:16 -08009538 mFakePolicy->assertNotifyWindowUnresponsiveWasCalled(timeout, mWindow);
Siarhei Vishniakou4cb50ca2020-05-26 21:43:02 -07009539 ASSERT_TRUE(mDispatcher->waitForIdle());
9540}
9541
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009542// We have a focused application, but no focused window
9543TEST_F(InputDispatcherSingleWindowAnr, FocusedApplication_NoFocusedWindow) {
Vishnu Nair47074b82020-08-14 11:54:47 -07009544 mWindow->setFocusable(false);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07009545 mDispatcher->onWindowInfosChanged({{*mWindow->getInfo()}, {}, 0, 0});
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009546 mWindow->consumeFocusEvent(false);
9547
9548 // taps on the window work as normal
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08009549 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07009550 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009551 WINDOW_LOCATION));
9552 ASSERT_NO_FATAL_FAILURE(mWindow->consumeMotionDown());
9553 mDispatcher->waitForIdle();
9554 mFakePolicy->assertNotifyAnrWasNotCalled();
9555
9556 // Once a focused event arrives, we get an ANR for this application
9557 // We specify the injection timeout to be smaller than the application timeout, to ensure that
9558 // injection times out (instead of failing).
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08009559 const InputEventInjectionResult result =
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07009560 injectKey(*mDispatcher, AKEY_EVENT_ACTION_DOWN, /*repeatCount=*/0, ADISPLAY_ID_DEFAULT,
Siarhei Vishniakouf83c6932023-07-07 17:48:10 -07009561 InputEventInjectionSync::WAIT_FOR_RESULT, 50ms, /*allowKeyRepeat=*/false);
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08009562 ASSERT_EQ(InputEventInjectionResult::TIMED_OUT, result);
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009563 const std::chrono::duration timeout = mApplication->getDispatchingTimeout(DISPATCHING_TIMEOUT);
Vishnu Naire4df8752022-09-08 09:17:55 -07009564 mFakePolicy->assertNotifyNoFocusedWindowAnrWasCalled(timeout, mApplication);
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009565 ASSERT_TRUE(mDispatcher->waitForIdle());
9566}
9567
Siarhei Vishniakou289e9242022-02-15 14:50:16 -08009568/**
9569 * Make sure the stale key is dropped before causing an ANR. So even if there's no focused window,
9570 * there will not be an ANR.
9571 */
9572TEST_F(InputDispatcherSingleWindowAnr, StaleKeyEventDoesNotAnr) {
9573 mWindow->setFocusable(false);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07009574 mDispatcher->onWindowInfosChanged({{*mWindow->getInfo()}, {}, 0, 0});
Siarhei Vishniakou289e9242022-02-15 14:50:16 -08009575 mWindow->consumeFocusEvent(false);
9576
9577 KeyEvent event;
Siarhei Vishniakoua7333112023-10-27 13:33:29 -07009578 static constexpr std::chrono::duration STALE_EVENT_TIMEOUT = 1000ms;
9579 mFakePolicy->setStaleEventTimeout(STALE_EVENT_TIMEOUT);
Siarhei Vishniakou289e9242022-02-15 14:50:16 -08009580 const nsecs_t eventTime = systemTime(SYSTEM_TIME_MONOTONIC) -
9581 std::chrono::nanoseconds(STALE_EVENT_TIMEOUT).count();
9582
9583 // Define a valid key down event that is stale (too old).
9584 event.initialize(InputEvent::nextId(), DEVICE_ID, AINPUT_SOURCE_KEYBOARD, ADISPLAY_ID_NONE,
Harry Cutts101ee9b2023-07-06 18:04:14 +00009585 INVALID_HMAC, AKEY_EVENT_ACTION_DOWN, /*flags=*/0, AKEYCODE_A, KEY_A,
Hu Guofe3c8f12023-09-22 17:20:15 +08009586 AMETA_NONE, /*repeatCount=*/0, eventTime, eventTime);
Siarhei Vishniakou289e9242022-02-15 14:50:16 -08009587
Hu Guofe3c8f12023-09-22 17:20:15 +08009588 const int32_t policyFlags =
9589 POLICY_FLAG_FILTERED | POLICY_FLAG_PASS_TO_USER | POLICY_FLAG_DISABLE_KEY_REPEAT;
Siarhei Vishniakou289e9242022-02-15 14:50:16 -08009590
9591 InputEventInjectionResult result =
Harry Cutts33476232023-01-30 19:57:29 +00009592 mDispatcher->injectInputEvent(&event, /*targetUid=*/{},
Siarhei Vishniakou289e9242022-02-15 14:50:16 -08009593 InputEventInjectionSync::WAIT_FOR_RESULT,
9594 INJECT_EVENT_TIMEOUT, policyFlags);
9595 ASSERT_EQ(InputEventInjectionResult::FAILED, result)
9596 << "Injection should fail because the event is stale";
9597
9598 ASSERT_TRUE(mDispatcher->waitForIdle());
9599 mFakePolicy->assertNotifyAnrWasNotCalled();
9600 mWindow->assertNoEvents();
9601}
9602
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009603// We have a focused application, but no focused window
Siarhei Vishniakou234129c2020-10-22 22:28:12 -05009604// Make sure that we don't notify policy twice about the same ANR.
9605TEST_F(InputDispatcherSingleWindowAnr, NoFocusedWindow_DoesNotSendDuplicateAnr) {
Siarhei Vishniakou06405fc2023-09-22 13:40:51 -07009606 const std::chrono::duration appTimeout = 400ms;
9607 mApplication->setDispatchingTimeout(appTimeout);
9608 mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, mApplication);
9609
Vishnu Nair47074b82020-08-14 11:54:47 -07009610 mWindow->setFocusable(false);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07009611 mDispatcher->onWindowInfosChanged({{*mWindow->getInfo()}, {}, 0, 0});
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009612 mWindow->consumeFocusEvent(false);
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009613
9614 // Once a focused event arrives, we get an ANR for this application
9615 // We specify the injection timeout to be smaller than the application timeout, to ensure that
9616 // injection times out (instead of failing).
Siarhei Vishniakou06405fc2023-09-22 13:40:51 -07009617 const std::chrono::duration eventInjectionTimeout = 100ms;
9618 ASSERT_LT(eventInjectionTimeout, appTimeout);
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08009619 const InputEventInjectionResult result =
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07009620 injectKey(*mDispatcher, AKEY_EVENT_ACTION_DOWN, /*repeatCount=*/0, ADISPLAY_ID_DEFAULT,
Siarhei Vishniakou06405fc2023-09-22 13:40:51 -07009621 InputEventInjectionSync::WAIT_FOR_RESULT, eventInjectionTimeout,
9622 /*allowKeyRepeat=*/false);
9623 ASSERT_EQ(InputEventInjectionResult::TIMED_OUT, result)
9624 << "result=" << ftl::enum_string(result);
9625 // We already waited for 'eventInjectionTimeout`, because the countdown started when the event
9626 // was first injected. So now we have (appTimeout - eventInjectionTimeout) left to wait.
9627 std::chrono::duration remainingWaitTime = appTimeout - eventInjectionTimeout;
9628 mFakePolicy->assertNotifyNoFocusedWindowAnrWasCalled(remainingWaitTime, mApplication);
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009629
Vishnu Naire4df8752022-09-08 09:17:55 -07009630 std::this_thread::sleep_for(appTimeout);
Siarhei Vishniakou234129c2020-10-22 22:28:12 -05009631 // ANR should not be raised again. It is up to policy to do that if it desires.
9632 mFakePolicy->assertNotifyAnrWasNotCalled();
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009633
Siarhei Vishniakou234129c2020-10-22 22:28:12 -05009634 // If we now get a focused window, the ANR should stop, but the policy handles that via
9635 // 'notifyFocusChanged' callback. This is implemented in the policy so we can't test it here.
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009636 ASSERT_TRUE(mDispatcher->waitForIdle());
9637}
9638
9639// We have a focused application, but no focused window
9640TEST_F(InputDispatcherSingleWindowAnr, NoFocusedWindow_DropsFocusedEvents) {
Vishnu Nair47074b82020-08-14 11:54:47 -07009641 mWindow->setFocusable(false);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07009642 mDispatcher->onWindowInfosChanged({{*mWindow->getInfo()}, {}, 0, 0});
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009643 mWindow->consumeFocusEvent(false);
9644
9645 // Once a focused event arrives, we get an ANR for this application
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07009646 ASSERT_NO_FATAL_FAILURE(assertInjectedKeyTimesOut(*mDispatcher));
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009647
Vishnu Naire4df8752022-09-08 09:17:55 -07009648 const std::chrono::duration timeout = mApplication->getDispatchingTimeout(DISPATCHING_TIMEOUT);
9649 mFakePolicy->assertNotifyNoFocusedWindowAnrWasCalled(timeout, mApplication);
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009650
9651 // Future focused events get dropped right away
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07009652 ASSERT_EQ(InputEventInjectionResult::FAILED, injectKeyDown(*mDispatcher));
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009653 ASSERT_TRUE(mDispatcher->waitForIdle());
9654 mWindow->assertNoEvents();
9655}
9656
9657/**
9658 * Ensure that the implementation is valid. Since we are using multiset to keep track of the
9659 * ANR timeouts, we are allowing entries with identical timestamps in the same connection.
9660 * If we process 1 of the events, but ANR on the second event with the same timestamp,
9661 * the ANR mechanism should still work.
9662 *
9663 * In this test, we are injecting DOWN and UP events with the same timestamps, and acknowledging the
9664 * DOWN event, while not responding on the second one.
9665 */
9666TEST_F(InputDispatcherSingleWindowAnr, Anr_HandlesEventsWithIdenticalTimestamps) {
9667 nsecs_t currentTime = systemTime(SYSTEM_TIME_MONOTONIC);
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07009668 injectMotionEvent(*mDispatcher, AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN,
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009669 ADISPLAY_ID_DEFAULT, WINDOW_LOCATION,
9670 {AMOTION_EVENT_INVALID_CURSOR_POSITION,
9671 AMOTION_EVENT_INVALID_CURSOR_POSITION},
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08009672 500ms, InputEventInjectionSync::WAIT_FOR_RESULT, currentTime);
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009673
9674 // Now send ACTION_UP, with identical timestamp
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07009675 injectMotionEvent(*mDispatcher, AMOTION_EVENT_ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN,
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009676 ADISPLAY_ID_DEFAULT, WINDOW_LOCATION,
9677 {AMOTION_EVENT_INVALID_CURSOR_POSITION,
9678 AMOTION_EVENT_INVALID_CURSOR_POSITION},
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08009679 500ms, InputEventInjectionSync::WAIT_FOR_RESULT, currentTime);
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009680
9681 // We have now sent down and up. Let's consume first event and then ANR on the second.
9682 mWindow->consumeMotionDown(ADISPLAY_ID_DEFAULT);
9683 const std::chrono::duration timeout = mWindow->getDispatchingTimeout(DISPATCHING_TIMEOUT);
Prabir Pradhanedd96402022-02-15 01:46:16 -08009684 mFakePolicy->assertNotifyWindowUnresponsiveWasCalled(timeout, mWindow);
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009685}
9686
Prabir Pradhan1376fcd2022-01-21 09:56:35 -08009687// A spy window can receive an ANR
9688TEST_F(InputDispatcherSingleWindowAnr, SpyWindowAnr) {
9689 sp<FakeWindowHandle> spy = addSpyWindow();
9690
9691 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07009692 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
Prabir Pradhan1376fcd2022-01-21 09:56:35 -08009693 WINDOW_LOCATION));
9694 mWindow->consumeMotionDown();
9695
Siarhei Vishniakoud3061ab2023-12-18 20:41:08 -08009696 const auto [sequenceNum, _] = spy->receiveEvent(); // ACTION_DOWN
Prabir Pradhan1376fcd2022-01-21 09:56:35 -08009697 ASSERT_TRUE(sequenceNum);
9698 const std::chrono::duration timeout = spy->getDispatchingTimeout(DISPATCHING_TIMEOUT);
Prabir Pradhanedd96402022-02-15 01:46:16 -08009699 mFakePolicy->assertNotifyWindowUnresponsiveWasCalled(timeout, spy);
Prabir Pradhan1376fcd2022-01-21 09:56:35 -08009700
9701 spy->finishEvent(*sequenceNum);
Siarhei Vishniakou1ae72f12023-01-29 12:55:30 -08009702 spy->consumeMotionEvent(
9703 AllOf(WithMotionAction(ACTION_CANCEL), WithDisplayId(ADISPLAY_ID_DEFAULT)));
Prabir Pradhan1376fcd2022-01-21 09:56:35 -08009704 ASSERT_TRUE(mDispatcher->waitForIdle());
Prabir Pradhanedd96402022-02-15 01:46:16 -08009705 mFakePolicy->assertNotifyWindowResponsiveWasCalled(spy->getToken(), mWindow->getPid());
Prabir Pradhan1376fcd2022-01-21 09:56:35 -08009706}
9707
9708// If an app is not responding to a key event, spy windows should continue to receive
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009709// new motion events
Prabir Pradhan1376fcd2022-01-21 09:56:35 -08009710TEST_F(InputDispatcherSingleWindowAnr, SpyWindowReceivesEventsDuringAppAnrOnKey) {
9711 sp<FakeWindowHandle> spy = addSpyWindow();
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009712
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08009713 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07009714 injectKeyDown(*mDispatcher, ADISPLAY_ID_DEFAULT));
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009715 mWindow->consumeKeyDown(ADISPLAY_ID_DEFAULT);
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07009716 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectKeyUp(*mDispatcher, ADISPLAY_ID_DEFAULT));
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009717
9718 // Stuck on the ACTION_UP
9719 const std::chrono::duration timeout = mWindow->getDispatchingTimeout(DISPATCHING_TIMEOUT);
Prabir Pradhanedd96402022-02-15 01:46:16 -08009720 mFakePolicy->assertNotifyWindowUnresponsiveWasCalled(timeout, mWindow);
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009721
Prabir Pradhan1376fcd2022-01-21 09:56:35 -08009722 // New tap will go to the spy window, but not to the window
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009723 tapOnWindow();
Prabir Pradhan1376fcd2022-01-21 09:56:35 -08009724 spy->consumeMotionDown(ADISPLAY_ID_DEFAULT);
9725 spy->consumeMotionUp(ADISPLAY_ID_DEFAULT);
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009726
9727 mWindow->consumeKeyUp(ADISPLAY_ID_DEFAULT); // still the previous motion
9728 mDispatcher->waitForIdle();
Prabir Pradhanedd96402022-02-15 01:46:16 -08009729 mFakePolicy->assertNotifyWindowResponsiveWasCalled(mWindow->getToken(), mWindow->getPid());
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009730 mWindow->assertNoEvents();
Prabir Pradhan1376fcd2022-01-21 09:56:35 -08009731 spy->assertNoEvents();
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009732}
9733
Prabir Pradhan1376fcd2022-01-21 09:56:35 -08009734// If an app is not responding to a motion event, spy windows should continue to receive
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009735// new motion events
Prabir Pradhan1376fcd2022-01-21 09:56:35 -08009736TEST_F(InputDispatcherSingleWindowAnr, SpyWindowReceivesEventsDuringAppAnrOnMotion) {
9737 sp<FakeWindowHandle> spy = addSpyWindow();
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009738
9739 tapOnWindow();
Prabir Pradhan1376fcd2022-01-21 09:56:35 -08009740 spy->consumeMotionDown(ADISPLAY_ID_DEFAULT);
9741 spy->consumeMotionUp(ADISPLAY_ID_DEFAULT);
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009742
9743 mWindow->consumeMotionDown();
9744 // Stuck on the ACTION_UP
9745 const std::chrono::duration timeout = mWindow->getDispatchingTimeout(DISPATCHING_TIMEOUT);
Prabir Pradhanedd96402022-02-15 01:46:16 -08009746 mFakePolicy->assertNotifyWindowUnresponsiveWasCalled(timeout, mWindow);
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009747
Prabir Pradhan1376fcd2022-01-21 09:56:35 -08009748 // New tap will go to the spy window, but not to the window
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009749 tapOnWindow();
Prabir Pradhan1376fcd2022-01-21 09:56:35 -08009750 spy->consumeMotionDown(ADISPLAY_ID_DEFAULT);
9751 spy->consumeMotionUp(ADISPLAY_ID_DEFAULT);
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009752
9753 mWindow->consumeMotionUp(ADISPLAY_ID_DEFAULT); // still the previous motion
9754 mDispatcher->waitForIdle();
Prabir Pradhanedd96402022-02-15 01:46:16 -08009755 mFakePolicy->assertNotifyWindowResponsiveWasCalled(mWindow->getToken(), mWindow->getPid());
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009756 mWindow->assertNoEvents();
Prabir Pradhan1376fcd2022-01-21 09:56:35 -08009757 spy->assertNoEvents();
9758}
9759
9760TEST_F(InputDispatcherSingleWindowAnr, UnresponsiveMonitorAnr) {
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07009761 mDispatcher->setMonitorDispatchingTimeoutForTest(SPY_TIMEOUT);
Prabir Pradhan1376fcd2022-01-21 09:56:35 -08009762
Prabir Pradhanfb549072023-10-05 19:17:36 +00009763 FakeMonitorReceiver monitor = FakeMonitorReceiver(*mDispatcher, "M_1", ADISPLAY_ID_DEFAULT);
Prabir Pradhan1376fcd2022-01-21 09:56:35 -08009764
9765 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07009766 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
Prabir Pradhan1376fcd2022-01-21 09:56:35 -08009767 WINDOW_LOCATION));
9768
9769 mWindow->consumeMotionDown(ADISPLAY_ID_DEFAULT);
9770 const std::optional<uint32_t> consumeSeq = monitor.receiveEvent();
9771 ASSERT_TRUE(consumeSeq);
9772
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07009773 mFakePolicy->assertNotifyWindowUnresponsiveWasCalled(SPY_TIMEOUT, monitor.getToken(),
9774 MONITOR_PID);
Prabir Pradhan1376fcd2022-01-21 09:56:35 -08009775
9776 monitor.finishEvent(*consumeSeq);
9777 monitor.consumeMotionCancel(ADISPLAY_ID_DEFAULT);
9778
9779 ASSERT_TRUE(mDispatcher->waitForIdle());
Prabir Pradhanedd96402022-02-15 01:46:16 -08009780 mFakePolicy->assertNotifyWindowResponsiveWasCalled(monitor.getToken(), MONITOR_PID);
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009781}
9782
9783// If a window is unresponsive, then you get anr. if the window later catches up and starts to
9784// process events, you don't get an anr. When the window later becomes unresponsive again, you
9785// get an ANR again.
9786// 1. tap -> block on ACTION_UP -> receive ANR
9787// 2. consume all pending events (= queue becomes healthy again)
9788// 3. tap again -> block on ACTION_UP again -> receive ANR second time
9789TEST_F(InputDispatcherSingleWindowAnr, SameWindow_CanReceiveAnrTwice) {
9790 tapOnWindow();
9791
9792 mWindow->consumeMotionDown();
9793 // Block on ACTION_UP
9794 const std::chrono::duration timeout = mWindow->getDispatchingTimeout(DISPATCHING_TIMEOUT);
Prabir Pradhanedd96402022-02-15 01:46:16 -08009795 mFakePolicy->assertNotifyWindowUnresponsiveWasCalled(timeout, mWindow);
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009796 mWindow->consumeMotionUp(); // Now the connection should be healthy again
9797 mDispatcher->waitForIdle();
Prabir Pradhanedd96402022-02-15 01:46:16 -08009798 mFakePolicy->assertNotifyWindowResponsiveWasCalled(mWindow->getToken(), mWindow->getPid());
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009799 mWindow->assertNoEvents();
9800
9801 tapOnWindow();
9802 mWindow->consumeMotionDown();
Prabir Pradhanedd96402022-02-15 01:46:16 -08009803 mFakePolicy->assertNotifyWindowUnresponsiveWasCalled(timeout, mWindow);
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009804 mWindow->consumeMotionUp();
9805
9806 mDispatcher->waitForIdle();
Prabir Pradhanedd96402022-02-15 01:46:16 -08009807 mFakePolicy->assertNotifyWindowResponsiveWasCalled(mWindow->getToken(), mWindow->getPid());
Siarhei Vishniakou234129c2020-10-22 22:28:12 -05009808 mFakePolicy->assertNotifyAnrWasNotCalled();
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009809 mWindow->assertNoEvents();
9810}
9811
Siarhei Vishniakou234129c2020-10-22 22:28:12 -05009812// If a connection remains unresponsive for a while, make sure policy is only notified once about
9813// it.
9814TEST_F(InputDispatcherSingleWindowAnr, Policy_DoesNotGetDuplicateAnr) {
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08009815 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07009816 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009817 WINDOW_LOCATION));
9818
9819 const std::chrono::duration windowTimeout = mWindow->getDispatchingTimeout(DISPATCHING_TIMEOUT);
Prabir Pradhanedd96402022-02-15 01:46:16 -08009820 mFakePolicy->assertNotifyWindowUnresponsiveWasCalled(windowTimeout, mWindow);
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009821 std::this_thread::sleep_for(windowTimeout);
Siarhei Vishniakou234129c2020-10-22 22:28:12 -05009822 // 'notifyConnectionUnresponsive' should only be called once per connection
9823 mFakePolicy->assertNotifyAnrWasNotCalled();
9824 // When the ANR happened, dispatcher should abort the current event stream via ACTION_CANCEL
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009825 mWindow->consumeMotionDown();
Siarhei Vishniakou1ae72f12023-01-29 12:55:30 -08009826 mWindow->consumeMotionEvent(
9827 AllOf(WithMotionAction(ACTION_CANCEL), WithDisplayId(ADISPLAY_ID_DEFAULT)));
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009828 mWindow->assertNoEvents();
Siarhei Vishniakou234129c2020-10-22 22:28:12 -05009829 mDispatcher->waitForIdle();
Prabir Pradhanedd96402022-02-15 01:46:16 -08009830 mFakePolicy->assertNotifyWindowResponsiveWasCalled(mWindow->getToken(), mWindow->getPid());
Siarhei Vishniakou234129c2020-10-22 22:28:12 -05009831 mFakePolicy->assertNotifyAnrWasNotCalled();
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009832}
9833
9834/**
9835 * 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 -07009836 * not get delivered to the focused window until the motion is processed.
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009837 */
9838TEST_F(InputDispatcherSingleWindowAnr, Key_StaysPendingWhileMotionIsProcessed) {
Siarhei Vishniakouef2b4502023-12-28 11:51:47 -08009839 // The timeouts in this test are established by relying on the fact that the "key waiting for
9840 // events timeout" is equal to 500ms.
9841 ASSERT_EQ(mFakePolicy->getKeyWaitingForEventsTimeout(), 500ms);
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009842 mWindow->setDispatchingTimeout(2s); // Set a long ANR timeout to prevent it from triggering
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07009843 mDispatcher->onWindowInfosChanged({{*mWindow->getInfo()}, {}, 0, 0});
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009844
9845 tapOnWindow();
Siarhei Vishniakoud3061ab2023-12-18 20:41:08 -08009846 const auto& [downSequenceNum, downEvent] = mWindow->receiveEvent();
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009847 ASSERT_TRUE(downSequenceNum);
Siarhei Vishniakoud3061ab2023-12-18 20:41:08 -08009848 const auto& [upSequenceNum, upEvent] = mWindow->receiveEvent();
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009849 ASSERT_TRUE(upSequenceNum);
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009850
Siarhei Vishniakouef2b4502023-12-28 11:51:47 -08009851 // Don't finish the events yet, and send a key
9852 mDispatcher->notifyKey(
9853 KeyArgsBuilder(AKEY_EVENT_ACTION_DOWN, AINPUT_SOURCE_KEYBOARD)
9854 .policyFlags(DEFAULT_POLICY_FLAGS | POLICY_FLAG_DISABLE_KEY_REPEAT)
9855 .build());
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009856 // Key will not be sent to the window, yet, because the window is still processing events
9857 // and the key remains pending, waiting for the touch events to be processed
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07009858 // Make sure that `assertNoEvents` doesn't wait too long, because it could cause an ANR.
Siarhei Vishniakouef2b4502023-12-28 11:51:47 -08009859 mWindow->assertNoEvents(100ms);
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009860
Siarhei Vishniakouef2b4502023-12-28 11:51:47 -08009861 std::this_thread::sleep_for(400ms);
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009862 // if we wait long enough though, dispatcher will give up, and still send the key
9863 // to the focused window, even though we have not yet finished the motion event
9864 mWindow->consumeKeyDown(ADISPLAY_ID_DEFAULT);
9865 mWindow->finishEvent(*downSequenceNum);
9866 mWindow->finishEvent(*upSequenceNum);
9867}
9868
9869/**
9870 * If a window is processing a motion event, and then a key event comes in, the key event should
9871 * not go to the focused window until the motion is processed.
9872 * If then a new motion comes in, then the pending key event should be going to the currently
9873 * focused window right away.
9874 */
9875TEST_F(InputDispatcherSingleWindowAnr,
Siarhei Vishniakouef2b4502023-12-28 11:51:47 -08009876 PendingKey_IsDeliveredWhileMotionIsProcessingAndNewTouchComesIn) {
9877 // The timeouts in this test are established by relying on the fact that the "key waiting for
9878 // events timeout" is equal to 500ms.
9879 ASSERT_EQ(mFakePolicy->getKeyWaitingForEventsTimeout(), 500ms);
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009880 mWindow->setDispatchingTimeout(2s); // Set a long ANR timeout to prevent it from triggering
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07009881 mDispatcher->onWindowInfosChanged({{*mWindow->getInfo()}, {}, 0, 0});
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009882
9883 tapOnWindow();
Siarhei Vishniakoud3061ab2023-12-18 20:41:08 -08009884 const auto& [downSequenceNum, _] = mWindow->receiveEvent();
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009885 ASSERT_TRUE(downSequenceNum);
Siarhei Vishniakoud3061ab2023-12-18 20:41:08 -08009886 const auto& [upSequenceNum, upEvent] = mWindow->receiveEvent();
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009887 ASSERT_TRUE(upSequenceNum);
9888 // Don't finish the events yet, and send a key
Siarhei Vishniakou67bf2162023-11-16 13:29:50 -08009889 mDispatcher->notifyKey(
9890 KeyArgsBuilder(AKEY_EVENT_ACTION_DOWN, AINPUT_SOURCE_KEYBOARD)
9891 .policyFlags(DEFAULT_POLICY_FLAGS | POLICY_FLAG_DISABLE_KEY_REPEAT)
9892 .build());
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009893 // At this point, key is still pending, and should not be sent to the application yet.
Siarhei Vishniakouef2b4502023-12-28 11:51:47 -08009894 mWindow->assertNoEvents(100ms);
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009895
9896 // Now tap down again. It should cause the pending key to go to the focused window right away.
9897 tapOnWindow();
Siarhei Vishniakouef2b4502023-12-28 11:51:47 -08009898 // Now that we tapped, we should receive the key immediately.
9899 // Since there's still room for slowness, we use 200ms, which is much less than
9900 // the "key waiting for events' timeout of 500ms minus the already waited 100ms duration.
9901 std::unique_ptr<InputEvent> keyEvent = mWindow->consume(200ms);
9902 ASSERT_NE(nullptr, keyEvent);
9903 ASSERT_EQ(InputEventType::KEY, keyEvent->getType());
9904 ASSERT_THAT(static_cast<KeyEvent&>(*keyEvent), WithKeyAction(AKEY_EVENT_ACTION_DOWN));
9905 // it doesn't matter that we haven't ack'd the other events yet. We can finish events in any
9906 // order.
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009907 mWindow->finishEvent(*downSequenceNum); // first tap's ACTION_DOWN
9908 mWindow->finishEvent(*upSequenceNum); // first tap's ACTION_UP
Siarhei Vishniakou67bf2162023-11-16 13:29:50 -08009909 mWindow->consumeMotionEvent(WithMotionAction(ACTION_DOWN));
9910 mWindow->consumeMotionEvent(WithMotionAction(ACTION_UP));
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009911 mWindow->assertNoEvents();
9912}
9913
Siarhei Vishniakouadb9fc92023-05-26 10:46:09 -07009914/**
9915 * Send an event to the app and have the app not respond right away.
9916 * When ANR is raised, policy will tell the dispatcher to cancel the events for that window.
9917 * So InputDispatcher will enqueue ACTION_CANCEL event as well.
9918 * At some point, the window becomes responsive again.
9919 * Ensure that subsequent events get dropped, and the next gesture is delivered.
9920 */
9921TEST_F(InputDispatcherSingleWindowAnr, TwoGesturesWithAnr) {
9922 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
9923 .pointer(PointerBuilder(0, ToolType::FINGER).x(10).y(10))
9924 .build());
9925
Siarhei Vishniakoud3061ab2023-12-18 20:41:08 -08009926 const auto [sequenceNum, _] = mWindow->receiveEvent(); // ACTION_DOWN
Siarhei Vishniakouadb9fc92023-05-26 10:46:09 -07009927 ASSERT_TRUE(sequenceNum);
9928 const std::chrono::duration timeout = mWindow->getDispatchingTimeout(DISPATCHING_TIMEOUT);
9929 mFakePolicy->assertNotifyWindowUnresponsiveWasCalled(timeout, mWindow);
9930
9931 mWindow->finishEvent(*sequenceNum);
9932 mWindow->consumeMotionEvent(WithMotionAction(ACTION_CANCEL));
9933 ASSERT_TRUE(mDispatcher->waitForIdle());
9934 mFakePolicy->assertNotifyWindowResponsiveWasCalled(mWindow->getToken(), mWindow->getPid());
9935
9936 // Now that the window is responsive, let's continue the gesture.
9937 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN)
9938 .pointer(PointerBuilder(0, ToolType::FINGER).x(11).y(11))
9939 .build());
9940
9941 mDispatcher->notifyMotion(MotionArgsBuilder(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
9942 .pointer(PointerBuilder(0, ToolType::FINGER).x(11).y(11))
9943 .pointer(PointerBuilder(1, ToolType::FINGER).x(3).y(3))
9944 .build());
9945
9946 mDispatcher->notifyMotion(MotionArgsBuilder(POINTER_1_UP, AINPUT_SOURCE_TOUCHSCREEN)
9947 .pointer(PointerBuilder(0, ToolType::FINGER).x(11).y(11))
9948 .pointer(PointerBuilder(1, ToolType::FINGER).x(3).y(3))
9949 .build());
9950 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN)
9951 .pointer(PointerBuilder(0, ToolType::FINGER).x(11).y(11))
9952 .build());
9953 // We already canceled this pointer, so the window shouldn't get any new events.
9954 mWindow->assertNoEvents();
9955
9956 // Start another one.
9957 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
9958 .pointer(PointerBuilder(0, ToolType::FINGER).x(15).y(15))
9959 .build());
9960 mWindow->consumeMotionEvent(WithMotionAction(ACTION_DOWN));
9961}
9962
Prabir Pradhanfc364722024-02-08 17:51:20 +00009963// Send an event to the app and have the app not respond right away. Then remove the app window.
9964// When the window is removed, the dispatcher will cancel the events for that window.
9965// So InputDispatcher will enqueue ACTION_CANCEL event as well.
9966TEST_F(InputDispatcherSingleWindowAnr, AnrAfterWindowRemoval) {
9967 mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_DOWN,
9968 AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
9969 {WINDOW_LOCATION}));
9970
9971 const auto [sequenceNum, _] = mWindow->receiveEvent(); // ACTION_DOWN
9972 ASSERT_TRUE(sequenceNum);
9973
9974 // Remove the window, but the input channel should remain alive.
9975 mDispatcher->onWindowInfosChanged({{}, {}, 0, 0});
9976
9977 const std::chrono::duration timeout = mWindow->getDispatchingTimeout(DISPATCHING_TIMEOUT);
9978 // Since the window was removed, Dispatcher does not know the PID associated with the window
9979 // anymore, so the policy is notified without the PID.
9980 mFakePolicy->assertNotifyWindowUnresponsiveWasCalled(timeout, mWindow->getToken(),
9981 /*pid=*/std::nullopt);
9982
9983 mWindow->finishEvent(*sequenceNum);
9984 // The cancellation was generated when the window was removed, along with the focus event.
9985 mWindow->consumeMotionEvent(
9986 AllOf(WithMotionAction(ACTION_CANCEL), WithDisplayId(ADISPLAY_ID_DEFAULT)));
9987 mWindow->consumeFocusEvent(false);
9988 ASSERT_TRUE(mDispatcher->waitForIdle());
9989 mFakePolicy->assertNotifyWindowResponsiveWasCalled(mWindow->getToken(), /*pid=*/std::nullopt);
9990}
9991
9992// Send an event to the app and have the app not respond right away. Wait for the policy to be
9993// notified of the unresponsive window, then remove the app window.
9994TEST_F(InputDispatcherSingleWindowAnr, AnrFollowedByWindowRemoval) {
9995 mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_DOWN,
9996 AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
9997 {WINDOW_LOCATION}));
9998
9999 const auto [sequenceNum, _] = mWindow->receiveEvent(); // ACTION_DOWN
10000 ASSERT_TRUE(sequenceNum);
10001 const std::chrono::duration timeout = mWindow->getDispatchingTimeout(DISPATCHING_TIMEOUT);
10002 mFakePolicy->assertNotifyWindowUnresponsiveWasCalled(timeout, mWindow);
10003
10004 // Remove the window, but the input channel should remain alive.
10005 mDispatcher->onWindowInfosChanged({{}, {}, 0, 0});
10006
10007 mWindow->finishEvent(*sequenceNum);
10008 // The cancellation was generated during the ANR, and the window lost focus when it was removed.
10009 mWindow->consumeMotionEvent(
10010 AllOf(WithMotionAction(ACTION_CANCEL), WithDisplayId(ADISPLAY_ID_DEFAULT)));
10011 mWindow->consumeFocusEvent(false);
10012 ASSERT_TRUE(mDispatcher->waitForIdle());
10013 // Since the window was removed, Dispatcher does not know the PID associated with the window
10014 // becoming responsive, so the policy is notified without the PID.
10015 mFakePolicy->assertNotifyWindowResponsiveWasCalled(mWindow->getToken(), /*pid=*/std::nullopt);
10016}
10017
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -070010018class InputDispatcherMultiWindowAnr : public InputDispatcherTest {
10019 virtual void SetUp() override {
10020 InputDispatcherTest::SetUp();
10021
Chris Yea209fde2020-07-22 13:54:51 -070010022 mApplication = std::make_shared<FakeApplicationHandle>();
Siarhei Vishniakouf83c6932023-07-07 17:48:10 -070010023 mApplication->setDispatchingTimeout(100ms);
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -070010024 mUnfocusedWindow = sp<FakeWindowHandle>::make(mApplication, mDispatcher, "Unfocused",
10025 ADISPLAY_ID_DEFAULT);
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -070010026 mUnfocusedWindow->setFrame(Rect(0, 0, 30, 30));
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -070010027 // Adding FLAG_WATCH_OUTSIDE_TOUCH to receive ACTION_OUTSIDE when another window is tapped
Prabir Pradhan4d5c52f2022-01-31 08:52:10 -080010028 mUnfocusedWindow->setWatchOutsideTouch(true);
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -070010029
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -070010030 mFocusedWindow = sp<FakeWindowHandle>::make(mApplication, mDispatcher, "Focused",
10031 ADISPLAY_ID_DEFAULT);
Siarhei Vishniakouf83c6932023-07-07 17:48:10 -070010032 mFocusedWindow->setDispatchingTimeout(100ms);
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -070010033 mFocusedWindow->setFrame(Rect(50, 50, 100, 100));
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -070010034
10035 // Set focused application.
10036 mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, mApplication);
Vishnu Nair47074b82020-08-14 11:54:47 -070010037 mFocusedWindow->setFocusable(true);
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -070010038
10039 // Expect one focus window exist in display.
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070010040 mDispatcher->onWindowInfosChanged(
10041 {{*mUnfocusedWindow->getInfo(), *mFocusedWindow->getInfo()}, {}, 0, 0});
Vishnu Nair958da932020-08-21 17:12:37 -070010042 setFocusedWindow(mFocusedWindow);
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -070010043 mFocusedWindow->consumeFocusEvent(true);
10044 }
10045
10046 virtual void TearDown() override {
10047 InputDispatcherTest::TearDown();
10048
10049 mUnfocusedWindow.clear();
10050 mFocusedWindow.clear();
10051 }
10052
10053protected:
Chris Yea209fde2020-07-22 13:54:51 -070010054 std::shared_ptr<FakeApplicationHandle> mApplication;
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -070010055 sp<FakeWindowHandle> mUnfocusedWindow;
10056 sp<FakeWindowHandle> mFocusedWindow;
10057 static constexpr PointF UNFOCUSED_WINDOW_LOCATION = {20, 20};
10058 static constexpr PointF FOCUSED_WINDOW_LOCATION = {75, 75};
10059 static constexpr PointF LOCATION_OUTSIDE_ALL_WINDOWS = {40, 40};
10060
10061 void tapOnFocusedWindow() { tap(FOCUSED_WINDOW_LOCATION); }
10062
10063 void tapOnUnfocusedWindow() { tap(UNFOCUSED_WINDOW_LOCATION); }
10064
10065private:
10066 void tap(const PointF& location) {
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -080010067 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070010068 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -070010069 location));
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -080010070 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070010071 injectMotionUp(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -070010072 location));
10073 }
10074};
10075
10076// If we have 2 windows that are both unresponsive, the one with the shortest timeout
10077// should be ANR'd first.
10078TEST_F(InputDispatcherMultiWindowAnr, TwoWindows_BothUnresponsive) {
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -080010079 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakou2899c552023-07-10 18:20:46 -070010080 injectMotionEvent(*mDispatcher,
10081 MotionEventBuilder(AMOTION_EVENT_ACTION_DOWN,
10082 AINPUT_SOURCE_TOUCHSCREEN)
10083 .pointer(PointerBuilder(0, ToolType::FINGER)
10084 .x(FOCUSED_WINDOW_LOCATION.x)
10085 .y(FOCUSED_WINDOW_LOCATION.y))
10086 .build()));
10087 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
10088 injectMotionEvent(*mDispatcher,
10089 MotionEventBuilder(AMOTION_EVENT_ACTION_UP,
10090 AINPUT_SOURCE_TOUCHSCREEN)
10091 .pointer(PointerBuilder(0, ToolType::FINGER)
10092 .x(FOCUSED_WINDOW_LOCATION.x)
10093 .y(FOCUSED_WINDOW_LOCATION.y))
10094 .build()));
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -070010095 mFocusedWindow->consumeMotionDown();
Siarhei Vishniakou2899c552023-07-10 18:20:46 -070010096 mFocusedWindow->consumeMotionUp();
Prabir Pradhan7662a8d2023-12-15 01:58:14 +000010097 mUnfocusedWindow->consumeMotionOutside(ADISPLAY_ID_DEFAULT, /*flags=*/0);
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -070010098 // We consumed all events, so no ANR
10099 ASSERT_TRUE(mDispatcher->waitForIdle());
10100 mFakePolicy->assertNotifyAnrWasNotCalled();
10101
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -080010102 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakou2899c552023-07-10 18:20:46 -070010103 injectMotionEvent(*mDispatcher,
10104 MotionEventBuilder(AMOTION_EVENT_ACTION_DOWN,
10105 AINPUT_SOURCE_TOUCHSCREEN)
10106 .pointer(PointerBuilder(0, ToolType::FINGER)
10107 .x(FOCUSED_WINDOW_LOCATION.x)
10108 .y(FOCUSED_WINDOW_LOCATION.y))
10109 .build()));
Siarhei Vishniakoud3061ab2023-12-18 20:41:08 -080010110 const auto [unfocusedSequenceNum, _] = mUnfocusedWindow->receiveEvent();
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -070010111 ASSERT_TRUE(unfocusedSequenceNum);
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -070010112
10113 const std::chrono::duration timeout =
10114 mFocusedWindow->getDispatchingTimeout(DISPATCHING_TIMEOUT);
Prabir Pradhanedd96402022-02-15 01:46:16 -080010115 mFakePolicy->assertNotifyWindowUnresponsiveWasCalled(timeout, mFocusedWindow);
Siarhei Vishniakou2899c552023-07-10 18:20:46 -070010116
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -070010117 mUnfocusedWindow->finishEvent(*unfocusedSequenceNum);
Siarhei Vishniakou234129c2020-10-22 22:28:12 -050010118 mFocusedWindow->consumeMotionDown();
10119 // This cancel is generated because the connection was unresponsive
10120 mFocusedWindow->consumeMotionCancel();
10121 mFocusedWindow->assertNoEvents();
10122 mUnfocusedWindow->assertNoEvents();
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -070010123 ASSERT_TRUE(mDispatcher->waitForIdle());
Prabir Pradhanedd96402022-02-15 01:46:16 -080010124 mFakePolicy->assertNotifyWindowResponsiveWasCalled(mFocusedWindow->getToken(),
10125 mFocusedWindow->getPid());
Siarhei Vishniakou234129c2020-10-22 22:28:12 -050010126 mFakePolicy->assertNotifyAnrWasNotCalled();
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -070010127}
10128
10129// If we have 2 windows with identical timeouts that are both unresponsive,
10130// it doesn't matter which order they should have ANR.
10131// But we should receive ANR for both.
10132TEST_F(InputDispatcherMultiWindowAnr, TwoWindows_BothUnresponsiveWithSameTimeout) {
10133 // Set the timeout for unfocused window to match the focused window
Siarhei Vishniakouf83c6932023-07-07 17:48:10 -070010134 mUnfocusedWindow->setDispatchingTimeout(
10135 mFocusedWindow->getDispatchingTimeout(DISPATCHING_TIMEOUT));
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070010136 mDispatcher->onWindowInfosChanged(
10137 {{*mUnfocusedWindow->getInfo(), *mFocusedWindow->getInfo()}, {}, 0, 0});
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -070010138
10139 tapOnFocusedWindow();
10140 // we should have ACTION_DOWN/ACTION_UP on focused window and ACTION_OUTSIDE on unfocused window
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -070010141 // We don't know which window will ANR first. But both of them should happen eventually.
Siarhei Vishniakouf83c6932023-07-07 17:48:10 -070010142 std::array<sp<IBinder>, 2> anrConnectionTokens = {mFakePolicy->getUnresponsiveWindowToken(
10143 mFocusedWindow->getDispatchingTimeout(
10144 DISPATCHING_TIMEOUT)),
10145 mFakePolicy->getUnresponsiveWindowToken(0ms)};
10146
10147 ASSERT_THAT(anrConnectionTokens,
10148 ::testing::UnorderedElementsAre(testing::Eq(mFocusedWindow->getToken()),
10149 testing::Eq(mUnfocusedWindow->getToken())));
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -070010150
10151 ASSERT_TRUE(mDispatcher->waitForIdle());
10152 mFakePolicy->assertNotifyAnrWasNotCalled();
Siarhei Vishniakou234129c2020-10-22 22:28:12 -050010153
10154 mFocusedWindow->consumeMotionDown();
10155 mFocusedWindow->consumeMotionUp();
10156 mUnfocusedWindow->consumeMotionOutside();
10157
Siarhei Vishniakouf83c6932023-07-07 17:48:10 -070010158 std::array<sp<IBinder>, 2> responsiveTokens = {mFakePolicy->getResponsiveWindowToken(),
10159 mFakePolicy->getResponsiveWindowToken()};
Siarhei Vishniakou234129c2020-10-22 22:28:12 -050010160
10161 // Both applications should be marked as responsive, in any order
Siarhei Vishniakouf83c6932023-07-07 17:48:10 -070010162 ASSERT_THAT(responsiveTokens,
10163 ::testing::UnorderedElementsAre(testing::Eq(mFocusedWindow->getToken()),
10164 testing::Eq(mUnfocusedWindow->getToken())));
Siarhei Vishniakou234129c2020-10-22 22:28:12 -050010165 mFakePolicy->assertNotifyAnrWasNotCalled();
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -070010166}
10167
10168// If a window is already not responding, the second tap on the same window should be ignored.
10169// We should also log an error to account for the dropped event (not tested here).
10170// At the same time, FLAG_WATCH_OUTSIDE_TOUCH targets should not receive any events.
10171TEST_F(InputDispatcherMultiWindowAnr, DuringAnr_SecondTapIsIgnored) {
10172 tapOnFocusedWindow();
Prabir Pradhan7662a8d2023-12-15 01:58:14 +000010173 mUnfocusedWindow->consumeMotionOutside(ADISPLAY_ID_DEFAULT, /*flags=*/0);
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -070010174 // Receive the events, but don't respond
Siarhei Vishniakoud3061ab2023-12-18 20:41:08 -080010175 const auto [downEventSequenceNum, downEvent] = mFocusedWindow->receiveEvent(); // ACTION_DOWN
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -070010176 ASSERT_TRUE(downEventSequenceNum);
Siarhei Vishniakoud3061ab2023-12-18 20:41:08 -080010177 const auto [upEventSequenceNum, upEvent] = mFocusedWindow->receiveEvent(); // ACTION_UP
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -070010178 ASSERT_TRUE(upEventSequenceNum);
10179 const std::chrono::duration timeout =
10180 mFocusedWindow->getDispatchingTimeout(DISPATCHING_TIMEOUT);
Prabir Pradhanedd96402022-02-15 01:46:16 -080010181 mFakePolicy->assertNotifyWindowUnresponsiveWasCalled(timeout, mFocusedWindow);
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -070010182
10183 // Tap once again
10184 // We cannot use "tapOnFocusedWindow" because it asserts the injection result to be success
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -080010185 ASSERT_EQ(InputEventInjectionResult::FAILED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070010186 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -070010187 FOCUSED_WINDOW_LOCATION));
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -080010188 ASSERT_EQ(InputEventInjectionResult::FAILED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070010189 injectMotionUp(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -070010190 FOCUSED_WINDOW_LOCATION));
10191 // Unfocused window does not receive ACTION_OUTSIDE because the tapped window is not a
10192 // valid touch target
10193 mUnfocusedWindow->assertNoEvents();
10194
10195 // Consume the first tap
10196 mFocusedWindow->finishEvent(*downEventSequenceNum);
10197 mFocusedWindow->finishEvent(*upEventSequenceNum);
10198 ASSERT_TRUE(mDispatcher->waitForIdle());
10199 // The second tap did not go to the focused window
10200 mFocusedWindow->assertNoEvents();
Siarhei Vishniakou234129c2020-10-22 22:28:12 -050010201 // Since all events are finished, connection should be deemed healthy again
Prabir Pradhanedd96402022-02-15 01:46:16 -080010202 mFakePolicy->assertNotifyWindowResponsiveWasCalled(mFocusedWindow->getToken(),
10203 mFocusedWindow->getPid());
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -070010204 mFakePolicy->assertNotifyAnrWasNotCalled();
10205}
10206
10207// If you tap outside of all windows, there will not be ANR
10208TEST_F(InputDispatcherMultiWindowAnr, TapOutsideAllWindows_DoesNotAnr) {
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -080010209 ASSERT_EQ(InputEventInjectionResult::FAILED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070010210 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -070010211 LOCATION_OUTSIDE_ALL_WINDOWS));
10212 ASSERT_TRUE(mDispatcher->waitForIdle());
10213 mFakePolicy->assertNotifyAnrWasNotCalled();
10214}
10215
10216// Since the focused window is paused, tapping on it should not produce any events
10217TEST_F(InputDispatcherMultiWindowAnr, Window_CanBePaused) {
10218 mFocusedWindow->setPaused(true);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070010219 mDispatcher->onWindowInfosChanged(
10220 {{*mUnfocusedWindow->getInfo(), *mFocusedWindow->getInfo()}, {}, 0, 0});
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -070010221
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -080010222 ASSERT_EQ(InputEventInjectionResult::FAILED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070010223 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -070010224 FOCUSED_WINDOW_LOCATION));
10225
10226 std::this_thread::sleep_for(mFocusedWindow->getDispatchingTimeout(DISPATCHING_TIMEOUT));
10227 ASSERT_TRUE(mDispatcher->waitForIdle());
10228 // Should not ANR because the window is paused, and touches shouldn't go to it
10229 mFakePolicy->assertNotifyAnrWasNotCalled();
10230
10231 mFocusedWindow->assertNoEvents();
10232 mUnfocusedWindow->assertNoEvents();
10233}
10234
10235/**
10236 * 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 -070010237 * not get delivered to the focused window until the motion is processed.
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -070010238 * If a different window becomes focused at this time, the key should go to that window instead.
10239 *
10240 * Warning!!!
10241 * This test depends on the value of android::inputdispatcher::KEY_WAITING_FOR_MOTION_TIMEOUT
10242 * and the injection timeout that we specify when injecting the key.
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070010243 * We must have the injection timeout (100ms) be smaller than
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -070010244 * KEY_WAITING_FOR_MOTION_TIMEOUT (currently 500ms).
10245 *
10246 * If that value changes, this test should also change.
10247 */
10248TEST_F(InputDispatcherMultiWindowAnr, PendingKey_GoesToNewlyFocusedWindow) {
10249 // Set a long ANR timeout to prevent it from triggering
10250 mFocusedWindow->setDispatchingTimeout(2s);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070010251 mDispatcher->onWindowInfosChanged(
10252 {{*mFocusedWindow->getInfo(), *mUnfocusedWindow->getInfo()}, {}, 0, 0});
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -070010253
10254 tapOnUnfocusedWindow();
Siarhei Vishniakoud3061ab2023-12-18 20:41:08 -080010255 const auto [downSequenceNum, downEvent] = mUnfocusedWindow->receiveEvent();
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -070010256 ASSERT_TRUE(downSequenceNum);
Siarhei Vishniakoud3061ab2023-12-18 20:41:08 -080010257 const auto [upSequenceNum, upEvent] = mUnfocusedWindow->receiveEvent();
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -070010258 ASSERT_TRUE(upSequenceNum);
10259 // Don't finish the events yet, and send a key
10260 // Injection will succeed because we will eventually give up and send the key to the focused
10261 // window even if motions are still being processed.
10262
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -080010263 InputEventInjectionResult result =
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070010264 injectKey(*mDispatcher, AKEY_EVENT_ACTION_DOWN, /*repeatCount=*/0, ADISPLAY_ID_DEFAULT,
10265 InputEventInjectionSync::NONE, /*injectionTimeout=*/100ms);
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -080010266 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, result);
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -070010267 // Key will not be sent to the window, yet, because the window is still processing events
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070010268 // and the key remains pending, waiting for the touch events to be processed.
10269 // Make sure `assertNoEvents` doesn't take too long. It uses CONSUME_TIMEOUT_NO_EVENT_EXPECTED
10270 // under the hood.
10271 static_assert(CONSUME_TIMEOUT_NO_EVENT_EXPECTED < 100ms);
10272 mFocusedWindow->assertNoEvents();
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -070010273
10274 // Switch the focus to the "unfocused" window that we tapped. Expect the key to go there
Vishnu Nair47074b82020-08-14 11:54:47 -070010275 mFocusedWindow->setFocusable(false);
10276 mUnfocusedWindow->setFocusable(true);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070010277 mDispatcher->onWindowInfosChanged(
10278 {{*mFocusedWindow->getInfo(), *mUnfocusedWindow->getInfo()}, {}, 0, 0});
Vishnu Nair958da932020-08-21 17:12:37 -070010279 setFocusedWindow(mUnfocusedWindow);
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -070010280
10281 // Focus events should precede the key events
10282 mUnfocusedWindow->consumeFocusEvent(true);
10283 mFocusedWindow->consumeFocusEvent(false);
10284
10285 // Finish the tap events, which should unblock dispatcher
10286 mUnfocusedWindow->finishEvent(*downSequenceNum);
10287 mUnfocusedWindow->finishEvent(*upSequenceNum);
10288
10289 // Now that all queues are cleared and no backlog in the connections, the key event
10290 // can finally go to the newly focused "mUnfocusedWindow".
10291 mUnfocusedWindow->consumeKeyDown(ADISPLAY_ID_DEFAULT);
10292 mFocusedWindow->assertNoEvents();
10293 mUnfocusedWindow->assertNoEvents();
Siarhei Vishniakou234129c2020-10-22 22:28:12 -050010294 mFakePolicy->assertNotifyAnrWasNotCalled();
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -070010295}
10296
10297// When the touch stream is split across 2 windows, and one of them does not respond,
10298// then ANR should be raised and the touch should be canceled for the unresponsive window.
10299// The other window should not be affected by that.
10300TEST_F(InputDispatcherMultiWindowAnr, SplitTouch_SingleWindowAnr) {
10301 // Touch Window 1
Prabir Pradhan678438e2023-04-13 19:32:51 +000010302 mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_DOWN,
10303 AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
10304 {FOCUSED_WINDOW_LOCATION}));
Prabir Pradhan7662a8d2023-12-15 01:58:14 +000010305 mUnfocusedWindow->consumeMotionOutside(ADISPLAY_ID_DEFAULT, /*flags=*/0);
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -070010306
10307 // Touch Window 2
Prabir Pradhan678438e2023-04-13 19:32:51 +000010308 mDispatcher->notifyMotion(
10309 generateMotionArgs(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
10310 {FOCUSED_WINDOW_LOCATION, UNFOCUSED_WINDOW_LOCATION}));
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -070010311
10312 const std::chrono::duration timeout =
10313 mFocusedWindow->getDispatchingTimeout(DISPATCHING_TIMEOUT);
Prabir Pradhanedd96402022-02-15 01:46:16 -080010314 mFakePolicy->assertNotifyWindowUnresponsiveWasCalled(timeout, mFocusedWindow);
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -070010315
10316 mUnfocusedWindow->consumeMotionDown();
10317 mFocusedWindow->consumeMotionDown();
10318 // Focused window may or may not receive ACTION_MOVE
10319 // But it should definitely receive ACTION_CANCEL due to the ANR
Siarhei Vishniakoud3061ab2023-12-18 20:41:08 -080010320 const auto [moveOrCancelSequenceNum, event] = mFocusedWindow->receiveEvent();
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -070010321 ASSERT_TRUE(moveOrCancelSequenceNum);
10322 mFocusedWindow->finishEvent(*moveOrCancelSequenceNum);
10323 ASSERT_NE(nullptr, event);
Siarhei Vishniakou63b63612023-04-12 11:00:23 -070010324 ASSERT_EQ(event->getType(), InputEventType::MOTION);
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -070010325 MotionEvent& motionEvent = static_cast<MotionEvent&>(*event);
10326 if (motionEvent.getAction() == AMOTION_EVENT_ACTION_MOVE) {
10327 mFocusedWindow->consumeMotionCancel();
10328 } else {
10329 ASSERT_EQ(AMOTION_EVENT_ACTION_CANCEL, motionEvent.getAction());
10330 }
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -070010331 ASSERT_TRUE(mDispatcher->waitForIdle());
Prabir Pradhanedd96402022-02-15 01:46:16 -080010332 mFakePolicy->assertNotifyWindowResponsiveWasCalled(mFocusedWindow->getToken(),
10333 mFocusedWindow->getPid());
Siarhei Vishniakou234129c2020-10-22 22:28:12 -050010334
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -070010335 mUnfocusedWindow->assertNoEvents();
10336 mFocusedWindow->assertNoEvents();
Siarhei Vishniakou234129c2020-10-22 22:28:12 -050010337 mFakePolicy->assertNotifyAnrWasNotCalled();
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -070010338}
10339
Siarhei Vishniakouf56b2692020-09-08 19:43:33 -050010340/**
10341 * If we have no focused window, and a key comes in, we start the ANR timer.
10342 * The focused application should add a focused window before the timer runs out to prevent ANR.
10343 *
10344 * If the user touches another application during this time, the key should be dropped.
10345 * Next, if a new focused window comes in, without toggling the focused application,
10346 * then no ANR should occur.
10347 *
10348 * Normally, we would expect the new focused window to be accompanied by 'setFocusedApplication',
10349 * but in some cases the policy may not update the focused application.
10350 */
10351TEST_F(InputDispatcherMultiWindowAnr, FocusedWindowWithoutSetFocusedApplication_NoAnr) {
10352 std::shared_ptr<FakeApplicationHandle> focusedApplication =
10353 std::make_shared<FakeApplicationHandle>();
Siarhei Vishniakouc033dfb2023-10-03 10:45:16 -070010354 focusedApplication->setDispatchingTimeout(300ms);
Siarhei Vishniakouf56b2692020-09-08 19:43:33 -050010355 mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, focusedApplication);
10356 // The application that owns 'mFocusedWindow' and 'mUnfocusedWindow' is not focused.
10357 mFocusedWindow->setFocusable(false);
10358
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070010359 mDispatcher->onWindowInfosChanged(
10360 {{*mFocusedWindow->getInfo(), *mUnfocusedWindow->getInfo()}, {}, 0, 0});
Siarhei Vishniakouf56b2692020-09-08 19:43:33 -050010361 mFocusedWindow->consumeFocusEvent(false);
10362
10363 // Send a key. The ANR timer should start because there is no focused window.
10364 // 'focusedApplication' will get blamed if this timer completes.
10365 // Key will not be sent anywhere because we have no focused window. It will remain pending.
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -080010366 InputEventInjectionResult result =
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070010367 injectKey(*mDispatcher, AKEY_EVENT_ACTION_DOWN, /*repeatCount=*/0, ADISPLAY_ID_DEFAULT,
10368 InputEventInjectionSync::NONE, /*injectionTimeout=*/100ms,
Harry Cutts33476232023-01-30 19:57:29 +000010369 /*allowKeyRepeat=*/false);
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -080010370 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, result);
Siarhei Vishniakouf56b2692020-09-08 19:43:33 -050010371
10372 // Wait until dispatcher starts the "no focused window" timer. If we don't wait here,
10373 // then the injected touches won't cause the focused event to get dropped.
10374 // The dispatcher only checks for whether the queue should be pruned upon queueing.
10375 // If we inject the touch right away and the ANR timer hasn't started, the touch event would
10376 // simply be added to the queue without 'shouldPruneInboundQueueLocked' returning 'true'.
10377 // For this test, it means that the key would get delivered to the window once it becomes
10378 // focused.
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070010379 std::this_thread::sleep_for(100ms);
Siarhei Vishniakouf56b2692020-09-08 19:43:33 -050010380
10381 // Touch unfocused window. This should force the pending key to get dropped.
Prabir Pradhan678438e2023-04-13 19:32:51 +000010382 mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_DOWN,
10383 AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
10384 {UNFOCUSED_WINDOW_LOCATION}));
Siarhei Vishniakouf56b2692020-09-08 19:43:33 -050010385
10386 // We do not consume the motion right away, because that would require dispatcher to first
10387 // process (== drop) the key event, and by that time, ANR will be raised.
10388 // Set the focused window first.
10389 mFocusedWindow->setFocusable(true);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070010390 mDispatcher->onWindowInfosChanged(
10391 {{*mFocusedWindow->getInfo(), *mUnfocusedWindow->getInfo()}, {}, 0, 0});
Siarhei Vishniakouf56b2692020-09-08 19:43:33 -050010392 setFocusedWindow(mFocusedWindow);
10393 mFocusedWindow->consumeFocusEvent(true);
10394 // We do not call "setFocusedApplication" here, even though the newly focused window belongs
10395 // to another application. This could be a bug / behaviour in the policy.
10396
10397 mUnfocusedWindow->consumeMotionDown();
10398
10399 ASSERT_TRUE(mDispatcher->waitForIdle());
10400 // Should not ANR because we actually have a focused window. It was just added too slowly.
10401 ASSERT_NO_FATAL_FAILURE(mFakePolicy->assertNotifyAnrWasNotCalled());
10402}
10403
Siarhei Vishniakou99e407b2023-12-26 18:09:32 -080010404/**
10405 * If we are pruning input queue, we should never drop pointer events. Otherwise, we risk having
10406 * an inconsistent event stream inside the dispatcher. In this test, we make sure that the
10407 * dispatcher doesn't prune pointer events incorrectly.
10408 *
10409 * This test reproduces a crash in InputDispatcher.
10410 * To reproduce the crash, we need to simulate the conditions for "pruning input queue" to occur.
10411 *
10412 * Keep the currently focused application (mApplication), and have no focused window.
10413 * We set up two additional windows:
10414 * 1) The navigation bar window. This simulates the system "NavigationBar", which is used in the
10415 * 3-button navigation mode. This window injects a BACK button when it's touched. 2) The application
10416 * window. This window is not focusable, but is touchable.
10417 *
10418 * We first touch the navigation bar, which causes it to inject a key. Since there's no focused
10419 * window, the dispatcher doesn't process this key, and all other events inside dispatcher are now
10420 * blocked. The dispatcher is waiting for 'mApplication' to add a focused window.
10421 *
10422 * Now, we touch "Another window". This window is owned by a different application than
10423 * 'mApplication'. This causes the dispatcher to stop waiting for 'mApplication' to add a focused
10424 * window. Now, the "pruning input queue" behaviour should kick in, and the dispatcher should start
10425 * dropping the events from its queue. Ensure that no crash occurs.
10426 *
10427 * In this test, we are setting long timeouts to prevent ANRs and events dropped due to being stale.
10428 * This does not affect the test running time.
10429 */
10430TEST_F(InputDispatcherMultiWindowAnr, PruningInputQueueShouldNotDropPointerEvents) {
10431 std::shared_ptr<FakeApplicationHandle> systemUiApplication =
10432 std::make_shared<FakeApplicationHandle>();
10433 systemUiApplication->setDispatchingTimeout(3000ms);
10434 mFakePolicy->setStaleEventTimeout(3000ms);
10435 sp<FakeWindowHandle> navigationBar =
10436 sp<FakeWindowHandle>::make(systemUiApplication, mDispatcher, "NavigationBar",
10437 ADISPLAY_ID_DEFAULT);
10438 navigationBar->setFocusable(false);
10439 navigationBar->setWatchOutsideTouch(true);
10440 navigationBar->setFrame(Rect(0, 0, 100, 100));
10441
10442 mApplication->setDispatchingTimeout(3000ms);
10443 // 'mApplication' is already focused, but we call it again here to make it explicit.
10444 mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, mApplication);
10445
10446 std::shared_ptr<FakeApplicationHandle> anotherApplication =
10447 std::make_shared<FakeApplicationHandle>();
10448 sp<FakeWindowHandle> appWindow =
10449 sp<FakeWindowHandle>::make(anotherApplication, mDispatcher, "Another window",
10450 ADISPLAY_ID_DEFAULT);
10451 appWindow->setFocusable(false);
10452 appWindow->setFrame(Rect(100, 100, 200, 200));
10453
10454 mDispatcher->onWindowInfosChanged(
10455 {{*navigationBar->getInfo(), *appWindow->getInfo()}, {}, 0, 0});
10456 // 'mFocusedWindow' is no longer in the dispatcher window list, and therefore loses focus
10457 mFocusedWindow->consumeFocusEvent(false);
10458
10459 // Touch down the navigation bar. It consumes the touch and injects a key into the dispatcher
10460 // in response.
10461 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
10462 .pointer(PointerBuilder(0, ToolType::FINGER).x(50).y(50))
10463 .build());
10464 navigationBar->consumeMotionEvent(WithMotionAction(ACTION_DOWN));
10465
10466 // Key will not be sent anywhere because we have no focused window. It will remain pending.
10467 // Pretend we are injecting KEYCODE_BACK, but it doesn't actually matter what key it is.
10468 InputEventInjectionResult result =
10469 injectKey(*mDispatcher, AKEY_EVENT_ACTION_DOWN, /*repeatCount=*/0, ADISPLAY_ID_DEFAULT,
10470 InputEventInjectionSync::NONE, /*injectionTimeout=*/100ms,
10471 /*allowKeyRepeat=*/false);
10472 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, result);
10473
10474 // Finish the gesture - lift up finger and inject ACTION_UP key event
10475 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN)
10476 .pointer(PointerBuilder(0, ToolType::FINGER).x(50).y(50))
10477 .build());
10478 result = injectKey(*mDispatcher, AKEY_EVENT_ACTION_UP, /*repeatCount=*/0, ADISPLAY_ID_DEFAULT,
10479 InputEventInjectionSync::NONE, /*injectionTimeout=*/100ms,
10480 /*allowKeyRepeat=*/false);
10481 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, result);
10482 // The key that was injected is blocking the dispatcher, so the navigation bar shouldn't be
10483 // getting any events yet.
10484 navigationBar->assertNoEvents();
10485
10486 // Now touch "Another window". This touch is going to a different application than the one we
10487 // are waiting for (which is 'mApplication').
10488 // This should cause the dispatcher to drop the pending focus-dispatched events (like the key
10489 // trying to be injected) and to continue processing the rest of the events in the original
10490 // order.
10491 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
10492 .pointer(PointerBuilder(0, ToolType::FINGER).x(150).y(150))
10493 .build());
10494 navigationBar->consumeMotionEvent(WithMotionAction(ACTION_UP));
10495 navigationBar->consumeMotionEvent(WithMotionAction(ACTION_OUTSIDE));
10496 appWindow->consumeMotionEvent(WithMotionAction(ACTION_DOWN));
10497
10498 appWindow->assertNoEvents();
10499 navigationBar->assertNoEvents();
10500}
10501
Siarhei Vishniakoua2862a02020-07-20 16:36:46 -050010502// These tests ensure we cannot send touch events to a window that's positioned behind a window
10503// that has feature NO_INPUT_CHANNEL.
10504// Layout:
10505// Top (closest to user)
10506// mNoInputWindow (above all windows)
10507// mBottomWindow
10508// Bottom (furthest from user)
10509class InputDispatcherMultiWindowOcclusionTests : public InputDispatcherTest {
10510 virtual void SetUp() override {
10511 InputDispatcherTest::SetUp();
10512
10513 mApplication = std::make_shared<FakeApplicationHandle>();
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -070010514 mNoInputWindow =
10515 sp<FakeWindowHandle>::make(mApplication, mDispatcher,
10516 "Window without input channel", ADISPLAY_ID_DEFAULT,
Prabir Pradhane7cc69c2024-01-05 21:35:28 +000010517 /*createInputChannel=*/false);
Prabir Pradhan51e7db02022-02-07 06:02:57 -080010518 mNoInputWindow->setNoInputChannel(true);
Siarhei Vishniakoua2862a02020-07-20 16:36:46 -050010519 mNoInputWindow->setFrame(Rect(0, 0, 100, 100));
10520 // It's perfectly valid for this window to not have an associated input channel
10521
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -070010522 mBottomWindow = sp<FakeWindowHandle>::make(mApplication, mDispatcher, "Bottom window",
10523 ADISPLAY_ID_DEFAULT);
Siarhei Vishniakoua2862a02020-07-20 16:36:46 -050010524 mBottomWindow->setFrame(Rect(0, 0, 100, 100));
10525
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070010526 mDispatcher->onWindowInfosChanged(
10527 {{*mNoInputWindow->getInfo(), *mBottomWindow->getInfo()}, {}, 0, 0});
Siarhei Vishniakoua2862a02020-07-20 16:36:46 -050010528 }
10529
10530protected:
10531 std::shared_ptr<FakeApplicationHandle> mApplication;
10532 sp<FakeWindowHandle> mNoInputWindow;
10533 sp<FakeWindowHandle> mBottomWindow;
10534};
10535
10536TEST_F(InputDispatcherMultiWindowOcclusionTests, NoInputChannelFeature_DropsTouches) {
10537 PointF touchedPoint = {10, 10};
10538
Prabir Pradhan678438e2023-04-13 19:32:51 +000010539 mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_DOWN,
10540 AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
10541 {touchedPoint}));
Siarhei Vishniakoua2862a02020-07-20 16:36:46 -050010542
10543 mNoInputWindow->assertNoEvents();
10544 // Even though the window 'mNoInputWindow' positioned above 'mBottomWindow' does not have
10545 // an input channel, it is not marked as FLAG_NOT_TOUCHABLE,
10546 // and therefore should prevent mBottomWindow from receiving touches
10547 mBottomWindow->assertNoEvents();
10548}
10549
10550/**
10551 * If a window has feature NO_INPUT_CHANNEL, and somehow (by mistake) still has an input channel,
10552 * ensure that this window does not receive any touches, and blocks touches to windows underneath.
10553 */
10554TEST_F(InputDispatcherMultiWindowOcclusionTests,
10555 NoInputChannelFeature_DropsTouchesWithValidChannel) {
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -070010556 mNoInputWindow = sp<FakeWindowHandle>::make(mApplication, mDispatcher,
10557 "Window with input channel and NO_INPUT_CHANNEL",
10558 ADISPLAY_ID_DEFAULT);
Siarhei Vishniakoua2862a02020-07-20 16:36:46 -050010559
Prabir Pradhan51e7db02022-02-07 06:02:57 -080010560 mNoInputWindow->setNoInputChannel(true);
Siarhei Vishniakoua2862a02020-07-20 16:36:46 -050010561 mNoInputWindow->setFrame(Rect(0, 0, 100, 100));
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070010562 mDispatcher->onWindowInfosChanged(
10563 {{*mNoInputWindow->getInfo(), *mBottomWindow->getInfo()}, {}, 0, 0});
Siarhei Vishniakoua2862a02020-07-20 16:36:46 -050010564
10565 PointF touchedPoint = {10, 10};
10566
Prabir Pradhan678438e2023-04-13 19:32:51 +000010567 mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_DOWN,
10568 AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
10569 {touchedPoint}));
Siarhei Vishniakoua2862a02020-07-20 16:36:46 -050010570
10571 mNoInputWindow->assertNoEvents();
10572 mBottomWindow->assertNoEvents();
10573}
10574
Vishnu Nair958da932020-08-21 17:12:37 -070010575class InputDispatcherMirrorWindowFocusTests : public InputDispatcherTest {
10576protected:
10577 std::shared_ptr<FakeApplicationHandle> mApp;
10578 sp<FakeWindowHandle> mWindow;
10579 sp<FakeWindowHandle> mMirror;
10580
10581 virtual void SetUp() override {
10582 InputDispatcherTest::SetUp();
10583 mApp = std::make_shared<FakeApplicationHandle>();
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -070010584 mWindow = sp<FakeWindowHandle>::make(mApp, mDispatcher, "TestWindow", ADISPLAY_ID_DEFAULT);
Prabir Pradhane7cc69c2024-01-05 21:35:28 +000010585 mMirror = mWindow->clone(ADISPLAY_ID_DEFAULT);
Vishnu Nair958da932020-08-21 17:12:37 -070010586 mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, mApp);
10587 mWindow->setFocusable(true);
10588 mMirror->setFocusable(true);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070010589 mDispatcher->onWindowInfosChanged({{*mWindow->getInfo(), *mMirror->getInfo()}, {}, 0, 0});
Vishnu Nair958da932020-08-21 17:12:37 -070010590 }
10591};
10592
10593TEST_F(InputDispatcherMirrorWindowFocusTests, CanGetFocus) {
10594 // Request focus on a mirrored window
10595 setFocusedWindow(mMirror);
10596
10597 // window gets focused
10598 mWindow->consumeFocusEvent(true);
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070010599 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectKeyDown(*mDispatcher))
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -080010600 << "Inject key event should return InputEventInjectionResult::SUCCEEDED";
Vishnu Nair958da932020-08-21 17:12:37 -070010601 mWindow->consumeKeyDown(ADISPLAY_ID_NONE);
10602}
10603
10604// A focused & mirrored window remains focused only if the window and its mirror are both
10605// focusable.
10606TEST_F(InputDispatcherMirrorWindowFocusTests, FocusedIfAllWindowsFocusable) {
10607 setFocusedWindow(mMirror);
10608
Prabir Pradhanbb3f1c02024-01-04 20:17:14 +000010609 // window gets focused because it is above the mirror
Vishnu Nair958da932020-08-21 17:12:37 -070010610 mWindow->consumeFocusEvent(true);
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070010611 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectKeyDown(*mDispatcher))
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -080010612 << "Inject key event should return InputEventInjectionResult::SUCCEEDED";
Vishnu Nair958da932020-08-21 17:12:37 -070010613 mWindow->consumeKeyDown(ADISPLAY_ID_NONE);
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070010614 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectKeyUp(*mDispatcher))
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -080010615 << "Inject key event should return InputEventInjectionResult::SUCCEEDED";
Vishnu Nair958da932020-08-21 17:12:37 -070010616 mWindow->consumeKeyUp(ADISPLAY_ID_NONE);
10617
10618 mMirror->setFocusable(false);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070010619 mDispatcher->onWindowInfosChanged({{*mWindow->getInfo(), *mMirror->getInfo()}, {}, 0, 0});
Vishnu Nair958da932020-08-21 17:12:37 -070010620
10621 // window loses focus since one of the windows associated with the token in not focusable
10622 mWindow->consumeFocusEvent(false);
10623
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070010624 ASSERT_EQ(InputEventInjectionResult::TIMED_OUT, injectKeyDown(*mDispatcher))
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -080010625 << "Inject key event should return InputEventInjectionResult::TIMED_OUT";
Vishnu Nair958da932020-08-21 17:12:37 -070010626 mWindow->assertNoEvents();
10627}
10628
10629// A focused & mirrored window remains focused until the window and its mirror both become
10630// invisible.
10631TEST_F(InputDispatcherMirrorWindowFocusTests, FocusedIfAnyWindowVisible) {
10632 setFocusedWindow(mMirror);
10633
10634 // window gets focused
10635 mWindow->consumeFocusEvent(true);
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070010636 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectKeyDown(*mDispatcher))
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -080010637 << "Inject key event should return InputEventInjectionResult::SUCCEEDED";
Vishnu Nair958da932020-08-21 17:12:37 -070010638 mWindow->consumeKeyDown(ADISPLAY_ID_NONE);
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070010639 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectKeyUp(*mDispatcher))
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -080010640 << "Inject key event should return InputEventInjectionResult::SUCCEEDED";
Vishnu Nair958da932020-08-21 17:12:37 -070010641 mWindow->consumeKeyUp(ADISPLAY_ID_NONE);
10642
10643 mMirror->setVisible(false);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070010644 mDispatcher->onWindowInfosChanged({{*mWindow->getInfo(), *mMirror->getInfo()}, {}, 0, 0});
Vishnu Nair958da932020-08-21 17:12:37 -070010645
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070010646 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectKeyDown(*mDispatcher))
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -080010647 << "Inject key event should return InputEventInjectionResult::SUCCEEDED";
Vishnu Nair958da932020-08-21 17:12:37 -070010648 mWindow->consumeKeyDown(ADISPLAY_ID_NONE);
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070010649 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectKeyUp(*mDispatcher))
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -080010650 << "Inject key event should return InputEventInjectionResult::SUCCEEDED";
Vishnu Nair958da932020-08-21 17:12:37 -070010651 mWindow->consumeKeyUp(ADISPLAY_ID_NONE);
10652
10653 mWindow->setVisible(false);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070010654 mDispatcher->onWindowInfosChanged({{*mWindow->getInfo(), *mMirror->getInfo()}, {}, 0, 0});
Vishnu Nair958da932020-08-21 17:12:37 -070010655
10656 // window loses focus only after all windows associated with the token become invisible.
10657 mWindow->consumeFocusEvent(false);
10658
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070010659 ASSERT_EQ(InputEventInjectionResult::TIMED_OUT, injectKeyDown(*mDispatcher))
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -080010660 << "Inject key event should return InputEventInjectionResult::TIMED_OUT";
Vishnu Nair958da932020-08-21 17:12:37 -070010661 mWindow->assertNoEvents();
10662}
10663
10664// A focused & mirrored window remains focused until both windows are removed.
10665TEST_F(InputDispatcherMirrorWindowFocusTests, FocusedWhileWindowsAlive) {
10666 setFocusedWindow(mMirror);
10667
10668 // window gets focused
10669 mWindow->consumeFocusEvent(true);
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070010670 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectKeyDown(*mDispatcher))
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -080010671 << "Inject key event should return InputEventInjectionResult::SUCCEEDED";
Vishnu Nair958da932020-08-21 17:12:37 -070010672 mWindow->consumeKeyDown(ADISPLAY_ID_NONE);
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070010673 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectKeyUp(*mDispatcher))
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -080010674 << "Inject key event should return InputEventInjectionResult::SUCCEEDED";
Vishnu Nair958da932020-08-21 17:12:37 -070010675 mWindow->consumeKeyUp(ADISPLAY_ID_NONE);
10676
10677 // single window is removed but the window token remains focused
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070010678 mDispatcher->onWindowInfosChanged({{*mMirror->getInfo()}, {}, 0, 0});
Vishnu Nair958da932020-08-21 17:12:37 -070010679
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070010680 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectKeyDown(*mDispatcher))
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -080010681 << "Inject key event should return InputEventInjectionResult::SUCCEEDED";
Prabir Pradhanbb3f1c02024-01-04 20:17:14 +000010682 mMirror->consumeKeyDown(ADISPLAY_ID_NONE);
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070010683 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectKeyUp(*mDispatcher))
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -080010684 << "Inject key event should return InputEventInjectionResult::SUCCEEDED";
Prabir Pradhanbb3f1c02024-01-04 20:17:14 +000010685 mMirror->consumeKeyUp(ADISPLAY_ID_NONE);
Vishnu Nair958da932020-08-21 17:12:37 -070010686
10687 // Both windows are removed
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070010688 mDispatcher->onWindowInfosChanged({{}, {}, 0, 0});
Vishnu Nair958da932020-08-21 17:12:37 -070010689 mWindow->consumeFocusEvent(false);
10690
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070010691 ASSERT_EQ(InputEventInjectionResult::TIMED_OUT, injectKeyDown(*mDispatcher))
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -080010692 << "Inject key event should return InputEventInjectionResult::TIMED_OUT";
Vishnu Nair958da932020-08-21 17:12:37 -070010693 mWindow->assertNoEvents();
10694}
10695
10696// Focus request can be pending until one window becomes visible.
10697TEST_F(InputDispatcherMirrorWindowFocusTests, DeferFocusWhenInvisible) {
10698 // Request focus on an invisible mirror.
10699 mWindow->setVisible(false);
10700 mMirror->setVisible(false);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070010701 mDispatcher->onWindowInfosChanged({{*mWindow->getInfo(), *mMirror->getInfo()}, {}, 0, 0});
Vishnu Nair958da932020-08-21 17:12:37 -070010702 setFocusedWindow(mMirror);
10703
10704 // Injected key goes to pending queue.
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -080010705 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070010706 injectKey(*mDispatcher, AKEY_EVENT_ACTION_DOWN, /*repeatCount=*/0,
10707 ADISPLAY_ID_DEFAULT, InputEventInjectionSync::NONE));
Vishnu Nair958da932020-08-21 17:12:37 -070010708
10709 mMirror->setVisible(true);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070010710 mDispatcher->onWindowInfosChanged({{*mWindow->getInfo(), *mMirror->getInfo()}, {}, 0, 0});
Vishnu Nair958da932020-08-21 17:12:37 -070010711
10712 // window gets focused
10713 mWindow->consumeFocusEvent(true);
10714 // window gets the pending key event
10715 mWindow->consumeKeyDown(ADISPLAY_ID_DEFAULT);
10716}
Prabir Pradhan99987712020-11-10 18:43:05 -080010717
10718class InputDispatcherPointerCaptureTests : public InputDispatcherTest {
10719protected:
10720 std::shared_ptr<FakeApplicationHandle> mApp;
10721 sp<FakeWindowHandle> mWindow;
10722 sp<FakeWindowHandle> mSecondWindow;
10723
10724 void SetUp() override {
10725 InputDispatcherTest::SetUp();
10726 mApp = std::make_shared<FakeApplicationHandle>();
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -070010727 mWindow = sp<FakeWindowHandle>::make(mApp, mDispatcher, "TestWindow", ADISPLAY_ID_DEFAULT);
Prabir Pradhan99987712020-11-10 18:43:05 -080010728 mWindow->setFocusable(true);
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -070010729 mSecondWindow =
10730 sp<FakeWindowHandle>::make(mApp, mDispatcher, "TestWindow2", ADISPLAY_ID_DEFAULT);
Prabir Pradhan99987712020-11-10 18:43:05 -080010731 mSecondWindow->setFocusable(true);
10732
10733 mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, mApp);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070010734 mDispatcher->onWindowInfosChanged(
10735 {{*mWindow->getInfo(), *mSecondWindow->getInfo()}, {}, 0, 0});
Prabir Pradhan99987712020-11-10 18:43:05 -080010736
10737 setFocusedWindow(mWindow);
10738 mWindow->consumeFocusEvent(true);
10739 }
10740
Prabir Pradhan5cc1a692021-08-06 14:01:18 +000010741 void notifyPointerCaptureChanged(const PointerCaptureRequest& request) {
Prabir Pradhan678438e2023-04-13 19:32:51 +000010742 mDispatcher->notifyPointerCaptureChanged(generatePointerCaptureChangedArgs(request));
Prabir Pradhan99987712020-11-10 18:43:05 -080010743 }
10744
Prabir Pradhan5cc1a692021-08-06 14:01:18 +000010745 PointerCaptureRequest requestAndVerifyPointerCapture(const sp<FakeWindowHandle>& window,
10746 bool enabled) {
Prabir Pradhan99987712020-11-10 18:43:05 -080010747 mDispatcher->requestPointerCapture(window->getToken(), enabled);
Hiroki Sato25040232024-02-22 17:21:22 +090010748 auto request = mFakePolicy->assertSetPointerCaptureCalled(window, enabled);
Prabir Pradhan5cc1a692021-08-06 14:01:18 +000010749 notifyPointerCaptureChanged(request);
Prabir Pradhan99987712020-11-10 18:43:05 -080010750 window->consumeCaptureEvent(enabled);
Prabir Pradhan5cc1a692021-08-06 14:01:18 +000010751 return request;
Prabir Pradhan99987712020-11-10 18:43:05 -080010752 }
10753};
10754
10755TEST_F(InputDispatcherPointerCaptureTests, EnablePointerCaptureWhenFocused) {
10756 // Ensure that capture cannot be obtained for unfocused windows.
10757 mDispatcher->requestPointerCapture(mSecondWindow->getToken(), true);
10758 mFakePolicy->assertSetPointerCaptureNotCalled();
10759 mSecondWindow->assertNoEvents();
10760
10761 // Ensure that capture can be enabled from the focus window.
10762 requestAndVerifyPointerCapture(mWindow, true);
10763
10764 // Ensure that capture cannot be disabled from a window that does not have capture.
10765 mDispatcher->requestPointerCapture(mSecondWindow->getToken(), false);
10766 mFakePolicy->assertSetPointerCaptureNotCalled();
10767
10768 // Ensure that capture can be disabled from the window with capture.
10769 requestAndVerifyPointerCapture(mWindow, false);
10770}
10771
10772TEST_F(InputDispatcherPointerCaptureTests, DisablesPointerCaptureAfterWindowLosesFocus) {
Prabir Pradhan5cc1a692021-08-06 14:01:18 +000010773 auto request = requestAndVerifyPointerCapture(mWindow, true);
Prabir Pradhan99987712020-11-10 18:43:05 -080010774
10775 setFocusedWindow(mSecondWindow);
10776
10777 // Ensure that the capture disabled event was sent first.
10778 mWindow->consumeCaptureEvent(false);
10779 mWindow->consumeFocusEvent(false);
10780 mSecondWindow->consumeFocusEvent(true);
Hiroki Sato25040232024-02-22 17:21:22 +090010781 mFakePolicy->assertSetPointerCaptureCalled(mWindow, false);
Prabir Pradhan99987712020-11-10 18:43:05 -080010782
10783 // Ensure that additional state changes from InputReader are not sent to the window.
Prabir Pradhan5cc1a692021-08-06 14:01:18 +000010784 notifyPointerCaptureChanged({});
10785 notifyPointerCaptureChanged(request);
10786 notifyPointerCaptureChanged({});
Prabir Pradhan99987712020-11-10 18:43:05 -080010787 mWindow->assertNoEvents();
10788 mSecondWindow->assertNoEvents();
10789 mFakePolicy->assertSetPointerCaptureNotCalled();
10790}
10791
10792TEST_F(InputDispatcherPointerCaptureTests, UnexpectedStateChangeDisablesPointerCapture) {
Prabir Pradhan5cc1a692021-08-06 14:01:18 +000010793 auto request = requestAndVerifyPointerCapture(mWindow, true);
Prabir Pradhan99987712020-11-10 18:43:05 -080010794
10795 // InputReader unexpectedly disables and enables pointer capture.
Prabir Pradhan5cc1a692021-08-06 14:01:18 +000010796 notifyPointerCaptureChanged({});
10797 notifyPointerCaptureChanged(request);
Prabir Pradhan99987712020-11-10 18:43:05 -080010798
10799 // Ensure that Pointer Capture is disabled.
Hiroki Sato25040232024-02-22 17:21:22 +090010800 mFakePolicy->assertSetPointerCaptureCalled(mWindow, false);
Prabir Pradhan99987712020-11-10 18:43:05 -080010801 mWindow->consumeCaptureEvent(false);
10802 mWindow->assertNoEvents();
10803}
10804
Prabir Pradhan167e6d92021-02-04 16:18:17 -080010805TEST_F(InputDispatcherPointerCaptureTests, OutOfOrderRequests) {
10806 requestAndVerifyPointerCapture(mWindow, true);
10807
10808 // The first window loses focus.
10809 setFocusedWindow(mSecondWindow);
Hiroki Sato25040232024-02-22 17:21:22 +090010810 mFakePolicy->assertSetPointerCaptureCalled(mWindow, false);
Prabir Pradhan167e6d92021-02-04 16:18:17 -080010811 mWindow->consumeCaptureEvent(false);
10812
10813 // Request Pointer Capture from the second window before the notification from InputReader
10814 // arrives.
10815 mDispatcher->requestPointerCapture(mSecondWindow->getToken(), true);
Hiroki Sato25040232024-02-22 17:21:22 +090010816 auto request = mFakePolicy->assertSetPointerCaptureCalled(mSecondWindow, true);
Prabir Pradhan167e6d92021-02-04 16:18:17 -080010817
10818 // InputReader notifies Pointer Capture was disabled (because of the focus change).
Prabir Pradhan5cc1a692021-08-06 14:01:18 +000010819 notifyPointerCaptureChanged({});
Prabir Pradhan167e6d92021-02-04 16:18:17 -080010820
10821 // InputReader notifies Pointer Capture was enabled (because of mSecondWindow's request).
Prabir Pradhan5cc1a692021-08-06 14:01:18 +000010822 notifyPointerCaptureChanged(request);
Prabir Pradhan167e6d92021-02-04 16:18:17 -080010823
10824 mSecondWindow->consumeFocusEvent(true);
10825 mSecondWindow->consumeCaptureEvent(true);
10826}
10827
Prabir Pradhan5cc1a692021-08-06 14:01:18 +000010828TEST_F(InputDispatcherPointerCaptureTests, EnableRequestFollowsSequenceNumbers) {
10829 // App repeatedly enables and disables capture.
10830 mDispatcher->requestPointerCapture(mWindow->getToken(), true);
Hiroki Sato25040232024-02-22 17:21:22 +090010831 auto firstRequest = mFakePolicy->assertSetPointerCaptureCalled(mWindow, true);
Prabir Pradhan5cc1a692021-08-06 14:01:18 +000010832 mDispatcher->requestPointerCapture(mWindow->getToken(), false);
Hiroki Sato25040232024-02-22 17:21:22 +090010833 mFakePolicy->assertSetPointerCaptureCalled(mWindow, false);
Prabir Pradhan5cc1a692021-08-06 14:01:18 +000010834 mDispatcher->requestPointerCapture(mWindow->getToken(), true);
Hiroki Sato25040232024-02-22 17:21:22 +090010835 auto secondRequest = mFakePolicy->assertSetPointerCaptureCalled(mWindow, true);
Prabir Pradhan5cc1a692021-08-06 14:01:18 +000010836
10837 // InputReader notifies that PointerCapture has been enabled for the first request. Since the
10838 // first request is now stale, this should do nothing.
10839 notifyPointerCaptureChanged(firstRequest);
10840 mWindow->assertNoEvents();
10841
10842 // InputReader notifies that the second request was enabled.
10843 notifyPointerCaptureChanged(secondRequest);
10844 mWindow->consumeCaptureEvent(true);
10845}
10846
Prabir Pradhan7092e262022-05-03 16:51:09 +000010847TEST_F(InputDispatcherPointerCaptureTests, RapidToggleRequests) {
10848 requestAndVerifyPointerCapture(mWindow, true);
10849
10850 // App toggles pointer capture off and on.
10851 mDispatcher->requestPointerCapture(mWindow->getToken(), false);
Hiroki Sato25040232024-02-22 17:21:22 +090010852 mFakePolicy->assertSetPointerCaptureCalled(mWindow, false);
Prabir Pradhan7092e262022-05-03 16:51:09 +000010853
10854 mDispatcher->requestPointerCapture(mWindow->getToken(), true);
Hiroki Sato25040232024-02-22 17:21:22 +090010855 auto enableRequest = mFakePolicy->assertSetPointerCaptureCalled(mWindow, true);
Prabir Pradhan7092e262022-05-03 16:51:09 +000010856
10857 // InputReader notifies that the latest "enable" request was processed, while skipping over the
10858 // preceding "disable" request.
10859 notifyPointerCaptureChanged(enableRequest);
10860
10861 // Since pointer capture was never disabled during the rapid toggle, the window does not receive
10862 // any notifications.
10863 mWindow->assertNoEvents();
10864}
10865
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -070010866/**
10867 * One window. Hover mouse in the window, and then start capture. Make sure that the relative
10868 * mouse movements don't affect the previous mouse hovering state.
10869 * When pointer capture is enabled, the incoming events are always ACTION_MOVE (there are no
10870 * HOVER_MOVE events).
10871 */
10872TEST_F(InputDispatcherPointerCaptureTests, MouseHoverAndPointerCapture) {
10873 // Mouse hover on the window
10874 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_ENTER, AINPUT_SOURCE_MOUSE)
10875 .pointer(PointerBuilder(0, ToolType::MOUSE).x(100).y(110))
10876 .build());
10877 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_MOVE, AINPUT_SOURCE_MOUSE)
10878 .pointer(PointerBuilder(0, ToolType::MOUSE).x(100).y(110))
10879 .build());
10880
10881 mWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_HOVER_ENTER)));
10882 mWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_HOVER_MOVE)));
10883
10884 // Start pointer capture
10885 requestAndVerifyPointerCapture(mWindow, true);
10886
10887 // Send some relative mouse movements and receive them in the window.
10888 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_MOUSE_RELATIVE)
10889 .pointer(PointerBuilder(0, ToolType::MOUSE).x(10).y(11))
10890 .build());
10891 mWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_MOVE), WithCoords(10, 11),
10892 WithSource(AINPUT_SOURCE_MOUSE_RELATIVE)));
10893
10894 // Stop pointer capture
10895 requestAndVerifyPointerCapture(mWindow, false);
10896
10897 // Continue hovering on the window
10898 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_MOVE, AINPUT_SOURCE_MOUSE)
10899 .pointer(PointerBuilder(0, ToolType::MOUSE).x(105).y(115))
10900 .build());
10901 mWindow->consumeMotionEvent(
10902 AllOf(WithMotionAction(ACTION_HOVER_MOVE), WithSource(AINPUT_SOURCE_MOUSE)));
10903
10904 mWindow->assertNoEvents();
10905}
10906
Hiroki Sato25040232024-02-22 17:21:22 +090010907using InputDispatcherPointerCaptureDeathTest = InputDispatcherPointerCaptureTests;
10908
10909TEST_F(InputDispatcherPointerCaptureDeathTest,
10910 NotifyPointerCaptureChangedWithWrongTokenAbortsDispatcher) {
10911 testing::GTEST_FLAG(death_test_style) = "threadsafe";
10912 ScopedSilentDeath _silentDeath;
10913
10914 mDispatcher->requestPointerCapture(mWindow->getToken(), true);
10915 auto request = mFakePolicy->assertSetPointerCaptureCalled(mWindow, true);
10916
10917 // Dispatch a pointer changed event with a wrong token.
10918 request.window = mSecondWindow->getToken();
10919 ASSERT_DEATH(
10920 {
10921 notifyPointerCaptureChanged(request);
10922 mSecondWindow->consumeCaptureEvent(true);
10923 },
10924 "Unexpected requested window for Pointer Capture.");
10925}
10926
Bernardo Rufinoc3b7b8c2021-01-29 17:38:07 +000010927class InputDispatcherUntrustedTouchesTest : public InputDispatcherTest {
10928protected:
10929 constexpr static const float MAXIMUM_OBSCURING_OPACITY = 0.8;
Bernardo Rufino7393d172021-02-26 13:56:11 +000010930
10931 constexpr static const float OPACITY_ABOVE_THRESHOLD = 0.9;
10932 static_assert(OPACITY_ABOVE_THRESHOLD > MAXIMUM_OBSCURING_OPACITY);
10933
10934 constexpr static const float OPACITY_BELOW_THRESHOLD = 0.7;
10935 static_assert(OPACITY_BELOW_THRESHOLD < MAXIMUM_OBSCURING_OPACITY);
10936
10937 // When combined twice, ie 1 - (1 - 0.5)*(1 - 0.5) = 0.75 < 8, is still below the threshold
10938 constexpr static const float OPACITY_FAR_BELOW_THRESHOLD = 0.5;
10939 static_assert(OPACITY_FAR_BELOW_THRESHOLD < MAXIMUM_OBSCURING_OPACITY);
10940 static_assert(1 - (1 - OPACITY_FAR_BELOW_THRESHOLD) * (1 - OPACITY_FAR_BELOW_THRESHOLD) <
10941 MAXIMUM_OBSCURING_OPACITY);
10942
Prabir Pradhan8a5c41d2023-06-08 19:13:46 +000010943 static constexpr gui::Uid TOUCHED_APP_UID{10001};
10944 static constexpr gui::Uid APP_B_UID{10002};
10945 static constexpr gui::Uid APP_C_UID{10003};
Bernardo Rufinoc3b7b8c2021-01-29 17:38:07 +000010946
10947 sp<FakeWindowHandle> mTouchWindow;
10948
10949 virtual void SetUp() override {
10950 InputDispatcherTest::SetUp();
Bernardo Rufino6d52e542021-02-15 18:38:10 +000010951 mTouchWindow = getWindow(TOUCHED_APP_UID, "Touched");
Bernardo Rufinoc3b7b8c2021-01-29 17:38:07 +000010952 mDispatcher->setMaximumObscuringOpacityForTouch(MAXIMUM_OBSCURING_OPACITY);
10953 }
10954
10955 virtual void TearDown() override {
10956 InputDispatcherTest::TearDown();
10957 mTouchWindow.clear();
10958 }
10959
Prabir Pradhan8a5c41d2023-06-08 19:13:46 +000010960 sp<FakeWindowHandle> getOccludingWindow(gui::Uid uid, std::string name, TouchOcclusionMode mode,
chaviw3277faf2021-05-19 16:45:23 -050010961 float alpha = 1.0f) {
Bernardo Rufinoc3b7b8c2021-01-29 17:38:07 +000010962 sp<FakeWindowHandle> window = getWindow(uid, name);
Prabir Pradhan4d5c52f2022-01-31 08:52:10 -080010963 window->setTouchable(false);
Bernardo Rufinoc3b7b8c2021-01-29 17:38:07 +000010964 window->setTouchOcclusionMode(mode);
Bernardo Rufino1d0d1f22021-02-12 15:08:43 +000010965 window->setAlpha(alpha);
Bernardo Rufinoc3b7b8c2021-01-29 17:38:07 +000010966 return window;
10967 }
10968
Prabir Pradhan8a5c41d2023-06-08 19:13:46 +000010969 sp<FakeWindowHandle> getWindow(gui::Uid uid, std::string name) {
Bernardo Rufinoc3b7b8c2021-01-29 17:38:07 +000010970 std::shared_ptr<FakeApplicationHandle> app = std::make_shared<FakeApplicationHandle>();
10971 sp<FakeWindowHandle> window =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -070010972 sp<FakeWindowHandle>::make(app, mDispatcher, name, ADISPLAY_ID_DEFAULT);
Bernardo Rufinoc3b7b8c2021-01-29 17:38:07 +000010973 // Generate an arbitrary PID based on the UID
Prabir Pradhanaeebeb42023-06-13 19:53:03 +000010974 window->setOwnerInfo(gui::Pid{static_cast<pid_t>(1777 + (uid.val() % 10000))}, uid);
Bernardo Rufinoc3b7b8c2021-01-29 17:38:07 +000010975 return window;
10976 }
10977
10978 void touch(const std::vector<PointF>& points = {PointF{100, 200}}) {
Prabir Pradhan678438e2023-04-13 19:32:51 +000010979 mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_DOWN,
10980 AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
10981 points));
Bernardo Rufinoc3b7b8c2021-01-29 17:38:07 +000010982 }
10983};
10984
10985TEST_F(InputDispatcherUntrustedTouchesTest, WindowWithBlockUntrustedOcclusionMode_BlocksTouch) {
Bernardo Rufino1d0d1f22021-02-12 15:08:43 +000010986 const sp<FakeWindowHandle>& w =
Bernardo Rufinoc3b7b8c2021-01-29 17:38:07 +000010987 getOccludingWindow(APP_B_UID, "B", TouchOcclusionMode::BLOCK_UNTRUSTED);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070010988 mDispatcher->onWindowInfosChanged({{*w->getInfo(), *mTouchWindow->getInfo()}, {}, 0, 0});
Bernardo Rufinoc3b7b8c2021-01-29 17:38:07 +000010989
10990 touch();
10991
10992 mTouchWindow->assertNoEvents();
10993}
10994
Bernardo Rufinoa43a5a42021-02-17 12:21:14 +000010995TEST_F(InputDispatcherUntrustedTouchesTest,
Bernardo Rufino7393d172021-02-26 13:56:11 +000010996 WindowWithBlockUntrustedOcclusionModeWithOpacityBelowThreshold_BlocksTouch) {
10997 const sp<FakeWindowHandle>& w =
10998 getOccludingWindow(APP_B_UID, "B", TouchOcclusionMode::BLOCK_UNTRUSTED, 0.7f);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070010999 mDispatcher->onWindowInfosChanged({{*w->getInfo(), *mTouchWindow->getInfo()}, {}, 0, 0});
Bernardo Rufino7393d172021-02-26 13:56:11 +000011000
11001 touch();
11002
11003 mTouchWindow->assertNoEvents();
11004}
11005
11006TEST_F(InputDispatcherUntrustedTouchesTest,
Bernardo Rufinoa43a5a42021-02-17 12:21:14 +000011007 WindowWithBlockUntrustedOcclusionMode_DoesNotReceiveTouch) {
11008 const sp<FakeWindowHandle>& w =
11009 getOccludingWindow(APP_B_UID, "B", TouchOcclusionMode::BLOCK_UNTRUSTED);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070011010 mDispatcher->onWindowInfosChanged({{*w->getInfo(), *mTouchWindow->getInfo()}, {}, 0, 0});
Bernardo Rufinoa43a5a42021-02-17 12:21:14 +000011011
11012 touch();
11013
11014 w->assertNoEvents();
11015}
11016
Bernardo Rufinoc3b7b8c2021-01-29 17:38:07 +000011017TEST_F(InputDispatcherUntrustedTouchesTest, WindowWithAllowOcclusionMode_AllowsTouch) {
Bernardo Rufino1d0d1f22021-02-12 15:08:43 +000011018 const sp<FakeWindowHandle>& w = getOccludingWindow(APP_B_UID, "B", TouchOcclusionMode::ALLOW);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070011019 mDispatcher->onWindowInfosChanged({{*w->getInfo(), *mTouchWindow->getInfo()}, {}, 0, 0});
Bernardo Rufinoc3b7b8c2021-01-29 17:38:07 +000011020
11021 touch();
11022
11023 mTouchWindow->consumeAnyMotionDown();
11024}
11025
11026TEST_F(InputDispatcherUntrustedTouchesTest, TouchOutsideOccludingWindow_AllowsTouch) {
Bernardo Rufino1d0d1f22021-02-12 15:08:43 +000011027 const sp<FakeWindowHandle>& w =
Bernardo Rufinoc3b7b8c2021-01-29 17:38:07 +000011028 getOccludingWindow(APP_B_UID, "B", TouchOcclusionMode::BLOCK_UNTRUSTED);
Bernardo Rufino1d0d1f22021-02-12 15:08:43 +000011029 w->setFrame(Rect(0, 0, 50, 50));
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070011030 mDispatcher->onWindowInfosChanged({{*w->getInfo(), *mTouchWindow->getInfo()}, {}, 0, 0});
Bernardo Rufinoc3b7b8c2021-01-29 17:38:07 +000011031
11032 touch({PointF{100, 100}});
11033
11034 mTouchWindow->consumeAnyMotionDown();
11035}
11036
11037TEST_F(InputDispatcherUntrustedTouchesTest, WindowFromSameUid_AllowsTouch) {
Bernardo Rufino1d0d1f22021-02-12 15:08:43 +000011038 const sp<FakeWindowHandle>& w =
Bernardo Rufino6d52e542021-02-15 18:38:10 +000011039 getOccludingWindow(TOUCHED_APP_UID, "A", TouchOcclusionMode::BLOCK_UNTRUSTED);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070011040 mDispatcher->onWindowInfosChanged({{*w->getInfo(), *mTouchWindow->getInfo()}, {}, 0, 0});
Bernardo Rufino1d0d1f22021-02-12 15:08:43 +000011041
11042 touch();
11043
11044 mTouchWindow->consumeAnyMotionDown();
11045}
11046
11047TEST_F(InputDispatcherUntrustedTouchesTest, WindowWithZeroOpacity_AllowsTouch) {
11048 const sp<FakeWindowHandle>& w =
11049 getOccludingWindow(APP_B_UID, "B", TouchOcclusionMode::BLOCK_UNTRUSTED, 0.0f);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070011050 mDispatcher->onWindowInfosChanged({{*w->getInfo(), *mTouchWindow->getInfo()}, {}, 0, 0});
Bernardo Rufinoc3b7b8c2021-01-29 17:38:07 +000011051
11052 touch();
11053
11054 mTouchWindow->consumeAnyMotionDown();
11055}
11056
Bernardo Rufinoa43a5a42021-02-17 12:21:14 +000011057TEST_F(InputDispatcherUntrustedTouchesTest, WindowWithZeroOpacity_DoesNotReceiveTouch) {
11058 const sp<FakeWindowHandle>& w =
11059 getOccludingWindow(APP_B_UID, "B", TouchOcclusionMode::BLOCK_UNTRUSTED, 0.0f);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070011060 mDispatcher->onWindowInfosChanged({{*w->getInfo(), *mTouchWindow->getInfo()}, {}, 0, 0});
Bernardo Rufinoa43a5a42021-02-17 12:21:14 +000011061
11062 touch();
11063
11064 w->assertNoEvents();
11065}
11066
11067/**
11068 * This is important to make sure apps can't indirectly learn the position of touches (outside vs
11069 * inside) while letting them pass-through. Note that even though touch passes through the occluding
11070 * window, the occluding window will still receive ACTION_OUTSIDE event.
11071 */
11072TEST_F(InputDispatcherUntrustedTouchesTest,
11073 WindowWithZeroOpacityAndWatchOutside_ReceivesOutsideEvent) {
11074 const sp<FakeWindowHandle>& w =
11075 getOccludingWindow(APP_B_UID, "B", TouchOcclusionMode::BLOCK_UNTRUSTED, 0.0f);
Prabir Pradhan4d5c52f2022-01-31 08:52:10 -080011076 w->setWatchOutsideTouch(true);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070011077 mDispatcher->onWindowInfosChanged({{*w->getInfo(), *mTouchWindow->getInfo()}, {}, 0, 0});
Bernardo Rufinoa43a5a42021-02-17 12:21:14 +000011078
11079 touch();
11080
11081 w->consumeMotionOutside();
11082}
11083
11084TEST_F(InputDispatcherUntrustedTouchesTest, OutsideEvent_HasZeroCoordinates) {
11085 const sp<FakeWindowHandle>& w =
11086 getOccludingWindow(APP_B_UID, "B", TouchOcclusionMode::BLOCK_UNTRUSTED, 0.0f);
Prabir Pradhan4d5c52f2022-01-31 08:52:10 -080011087 w->setWatchOutsideTouch(true);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070011088 mDispatcher->onWindowInfosChanged({{*w->getInfo(), *mTouchWindow->getInfo()}, {}, 0, 0});
Bernardo Rufinoa43a5a42021-02-17 12:21:14 +000011089
11090 touch();
11091
Prabir Pradhandfabf8a2022-01-21 08:19:30 -080011092 w->consumeMotionOutsideWithZeroedCoords();
Bernardo Rufinoa43a5a42021-02-17 12:21:14 +000011093}
11094
Bernardo Rufinoc3b7b8c2021-01-29 17:38:07 +000011095TEST_F(InputDispatcherUntrustedTouchesTest, WindowWithOpacityBelowThreshold_AllowsTouch) {
Bernardo Rufino1d0d1f22021-02-12 15:08:43 +000011096 const sp<FakeWindowHandle>& w =
Bernardo Rufino7393d172021-02-26 13:56:11 +000011097 getOccludingWindow(APP_B_UID, "B", TouchOcclusionMode::USE_OPACITY,
11098 OPACITY_BELOW_THRESHOLD);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070011099 mDispatcher->onWindowInfosChanged({{*w->getInfo(), *mTouchWindow->getInfo()}, {}, 0, 0});
Bernardo Rufino1d0d1f22021-02-12 15:08:43 +000011100
11101 touch();
11102
11103 mTouchWindow->consumeAnyMotionDown();
11104}
11105
11106TEST_F(InputDispatcherUntrustedTouchesTest, WindowWithOpacityAtThreshold_AllowsTouch) {
11107 const sp<FakeWindowHandle>& w =
11108 getOccludingWindow(APP_B_UID, "B", TouchOcclusionMode::USE_OPACITY,
11109 MAXIMUM_OBSCURING_OPACITY);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070011110 mDispatcher->onWindowInfosChanged({{*w->getInfo(), *mTouchWindow->getInfo()}, {}, 0, 0});
Bernardo Rufinoc3b7b8c2021-01-29 17:38:07 +000011111
11112 touch();
11113
11114 mTouchWindow->consumeAnyMotionDown();
11115}
11116
11117TEST_F(InputDispatcherUntrustedTouchesTest, WindowWithOpacityAboveThreshold_BlocksTouch) {
Bernardo Rufino1d0d1f22021-02-12 15:08:43 +000011118 const sp<FakeWindowHandle>& w =
Bernardo Rufino7393d172021-02-26 13:56:11 +000011119 getOccludingWindow(APP_B_UID, "B", TouchOcclusionMode::USE_OPACITY,
11120 OPACITY_ABOVE_THRESHOLD);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070011121 mDispatcher->onWindowInfosChanged({{*w->getInfo(), *mTouchWindow->getInfo()}, {}, 0, 0});
Bernardo Rufino1d0d1f22021-02-12 15:08:43 +000011122
11123 touch();
11124
11125 mTouchWindow->assertNoEvents();
11126}
11127
11128TEST_F(InputDispatcherUntrustedTouchesTest, WindowsWithCombinedOpacityAboveThreshold_BlocksTouch) {
11129 // Resulting opacity = 1 - (1 - 0.7)*(1 - 0.7) = .91
11130 const sp<FakeWindowHandle>& w1 =
Bernardo Rufino7393d172021-02-26 13:56:11 +000011131 getOccludingWindow(APP_B_UID, "B1", TouchOcclusionMode::USE_OPACITY,
11132 OPACITY_BELOW_THRESHOLD);
Bernardo Rufino1d0d1f22021-02-12 15:08:43 +000011133 const sp<FakeWindowHandle>& w2 =
Bernardo Rufino7393d172021-02-26 13:56:11 +000011134 getOccludingWindow(APP_B_UID, "B2", TouchOcclusionMode::USE_OPACITY,
11135 OPACITY_BELOW_THRESHOLD);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070011136 mDispatcher->onWindowInfosChanged(
11137 {{*w1->getInfo(), *w2->getInfo(), *mTouchWindow->getInfo()}, {}, 0, 0});
Bernardo Rufino1d0d1f22021-02-12 15:08:43 +000011138
11139 touch();
11140
11141 mTouchWindow->assertNoEvents();
11142}
11143
11144TEST_F(InputDispatcherUntrustedTouchesTest, WindowsWithCombinedOpacityBelowThreshold_AllowsTouch) {
11145 // Resulting opacity = 1 - (1 - 0.5)*(1 - 0.5) = .75
11146 const sp<FakeWindowHandle>& w1 =
Bernardo Rufino7393d172021-02-26 13:56:11 +000011147 getOccludingWindow(APP_B_UID, "B1", TouchOcclusionMode::USE_OPACITY,
11148 OPACITY_FAR_BELOW_THRESHOLD);
Bernardo Rufino1d0d1f22021-02-12 15:08:43 +000011149 const sp<FakeWindowHandle>& w2 =
Bernardo Rufino7393d172021-02-26 13:56:11 +000011150 getOccludingWindow(APP_B_UID, "B2", TouchOcclusionMode::USE_OPACITY,
11151 OPACITY_FAR_BELOW_THRESHOLD);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070011152 mDispatcher->onWindowInfosChanged(
11153 {{*w1->getInfo(), *w2->getInfo(), *mTouchWindow->getInfo()}, {}, 0, 0});
Bernardo Rufino1d0d1f22021-02-12 15:08:43 +000011154
11155 touch();
11156
11157 mTouchWindow->consumeAnyMotionDown();
11158}
11159
11160TEST_F(InputDispatcherUntrustedTouchesTest,
11161 WindowsFromDifferentAppsEachBelowThreshold_AllowsTouch) {
11162 const sp<FakeWindowHandle>& wB =
Bernardo Rufino7393d172021-02-26 13:56:11 +000011163 getOccludingWindow(APP_B_UID, "B", TouchOcclusionMode::USE_OPACITY,
11164 OPACITY_BELOW_THRESHOLD);
Bernardo Rufino1d0d1f22021-02-12 15:08:43 +000011165 const sp<FakeWindowHandle>& wC =
Bernardo Rufino7393d172021-02-26 13:56:11 +000011166 getOccludingWindow(APP_C_UID, "C", TouchOcclusionMode::USE_OPACITY,
11167 OPACITY_BELOW_THRESHOLD);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070011168 mDispatcher->onWindowInfosChanged(
11169 {{*wB->getInfo(), *wC->getInfo(), *mTouchWindow->getInfo()}, {}, 0, 0});
Bernardo Rufino1d0d1f22021-02-12 15:08:43 +000011170
11171 touch();
11172
11173 mTouchWindow->consumeAnyMotionDown();
11174}
11175
11176TEST_F(InputDispatcherUntrustedTouchesTest, WindowsFromDifferentAppsOneAboveThreshold_BlocksTouch) {
11177 const sp<FakeWindowHandle>& wB =
Bernardo Rufino7393d172021-02-26 13:56:11 +000011178 getOccludingWindow(APP_B_UID, "B", TouchOcclusionMode::USE_OPACITY,
11179 OPACITY_BELOW_THRESHOLD);
Bernardo Rufino1d0d1f22021-02-12 15:08:43 +000011180 const sp<FakeWindowHandle>& wC =
Bernardo Rufino7393d172021-02-26 13:56:11 +000011181 getOccludingWindow(APP_C_UID, "C", TouchOcclusionMode::USE_OPACITY,
11182 OPACITY_ABOVE_THRESHOLD);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070011183 mDispatcher->onWindowInfosChanged(
11184 {{*wB->getInfo(), *wC->getInfo(), *mTouchWindow->getInfo()}, {}, 0, 0});
Bernardo Rufinoc3b7b8c2021-01-29 17:38:07 +000011185
11186 touch();
11187
11188 mTouchWindow->assertNoEvents();
11189}
11190
Bernardo Rufino6d52e542021-02-15 18:38:10 +000011191TEST_F(InputDispatcherUntrustedTouchesTest,
11192 WindowWithOpacityAboveThresholdAndSelfWindow_BlocksTouch) {
11193 const sp<FakeWindowHandle>& wA =
Bernardo Rufino7393d172021-02-26 13:56:11 +000011194 getOccludingWindow(TOUCHED_APP_UID, "T", TouchOcclusionMode::USE_OPACITY,
11195 OPACITY_BELOW_THRESHOLD);
Bernardo Rufino6d52e542021-02-15 18:38:10 +000011196 const sp<FakeWindowHandle>& wB =
Bernardo Rufino7393d172021-02-26 13:56:11 +000011197 getOccludingWindow(APP_B_UID, "B", TouchOcclusionMode::USE_OPACITY,
11198 OPACITY_ABOVE_THRESHOLD);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070011199 mDispatcher->onWindowInfosChanged(
11200 {{*wA->getInfo(), *wB->getInfo(), *mTouchWindow->getInfo()}, {}, 0, 0});
Bernardo Rufino6d52e542021-02-15 18:38:10 +000011201
11202 touch();
11203
11204 mTouchWindow->assertNoEvents();
11205}
11206
11207TEST_F(InputDispatcherUntrustedTouchesTest,
11208 WindowWithOpacityBelowThresholdAndSelfWindow_AllowsTouch) {
11209 const sp<FakeWindowHandle>& wA =
Bernardo Rufino7393d172021-02-26 13:56:11 +000011210 getOccludingWindow(TOUCHED_APP_UID, "T", TouchOcclusionMode::USE_OPACITY,
11211 OPACITY_ABOVE_THRESHOLD);
Bernardo Rufino6d52e542021-02-15 18:38:10 +000011212 const sp<FakeWindowHandle>& wB =
Bernardo Rufino7393d172021-02-26 13:56:11 +000011213 getOccludingWindow(APP_B_UID, "B", TouchOcclusionMode::USE_OPACITY,
11214 OPACITY_BELOW_THRESHOLD);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070011215 mDispatcher->onWindowInfosChanged(
11216 {{*wA->getInfo(), *wB->getInfo(), *mTouchWindow->getInfo()}, {}, 0, 0});
Bernardo Rufino6d52e542021-02-15 18:38:10 +000011217
11218 touch();
11219
11220 mTouchWindow->consumeAnyMotionDown();
11221}
11222
11223TEST_F(InputDispatcherUntrustedTouchesTest, SelfWindowWithOpacityAboveThreshold_AllowsTouch) {
11224 const sp<FakeWindowHandle>& w =
Bernardo Rufino7393d172021-02-26 13:56:11 +000011225 getOccludingWindow(TOUCHED_APP_UID, "T", TouchOcclusionMode::USE_OPACITY,
11226 OPACITY_ABOVE_THRESHOLD);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070011227 mDispatcher->onWindowInfosChanged({{*w->getInfo(), *mTouchWindow->getInfo()}, {}, 0, 0});
Bernardo Rufino6d52e542021-02-15 18:38:10 +000011228
11229 touch();
11230
11231 mTouchWindow->consumeAnyMotionDown();
11232}
11233
11234TEST_F(InputDispatcherUntrustedTouchesTest, SelfWindowWithBlockUntrustedMode_AllowsTouch) {
11235 const sp<FakeWindowHandle>& w =
11236 getOccludingWindow(TOUCHED_APP_UID, "T", TouchOcclusionMode::BLOCK_UNTRUSTED);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070011237 mDispatcher->onWindowInfosChanged({{*w->getInfo(), *mTouchWindow->getInfo()}, {}, 0, 0});
Bernardo Rufino6d52e542021-02-15 18:38:10 +000011238
11239 touch();
11240
11241 mTouchWindow->consumeAnyMotionDown();
11242}
11243
Bernardo Rufinoccd3dd62021-02-15 18:47:42 +000011244TEST_F(InputDispatcherUntrustedTouchesTest,
11245 OpacityThresholdIs0AndWindowAboveThreshold_BlocksTouch) {
11246 mDispatcher->setMaximumObscuringOpacityForTouch(0.0f);
11247 const sp<FakeWindowHandle>& w =
11248 getOccludingWindow(APP_B_UID, "B", TouchOcclusionMode::USE_OPACITY, 0.1f);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070011249 mDispatcher->onWindowInfosChanged({{*w->getInfo(), *mTouchWindow->getInfo()}, {}, 0, 0});
Bernardo Rufinoccd3dd62021-02-15 18:47:42 +000011250
11251 touch();
11252
11253 mTouchWindow->assertNoEvents();
11254}
11255
11256TEST_F(InputDispatcherUntrustedTouchesTest, OpacityThresholdIs0AndWindowAtThreshold_AllowsTouch) {
11257 mDispatcher->setMaximumObscuringOpacityForTouch(0.0f);
11258 const sp<FakeWindowHandle>& w =
11259 getOccludingWindow(APP_B_UID, "B", TouchOcclusionMode::USE_OPACITY, 0.0f);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070011260 mDispatcher->onWindowInfosChanged({{*w->getInfo(), *mTouchWindow->getInfo()}, {}, 0, 0});
Bernardo Rufinoccd3dd62021-02-15 18:47:42 +000011261
11262 touch();
11263
11264 mTouchWindow->consumeAnyMotionDown();
11265}
11266
11267TEST_F(InputDispatcherUntrustedTouchesTest,
11268 OpacityThresholdIs1AndWindowBelowThreshold_AllowsTouch) {
11269 mDispatcher->setMaximumObscuringOpacityForTouch(1.0f);
11270 const sp<FakeWindowHandle>& w =
Bernardo Rufino7393d172021-02-26 13:56:11 +000011271 getOccludingWindow(APP_B_UID, "B", TouchOcclusionMode::USE_OPACITY,
11272 OPACITY_ABOVE_THRESHOLD);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070011273 mDispatcher->onWindowInfosChanged({{*w->getInfo(), *mTouchWindow->getInfo()}, {}, 0, 0});
Bernardo Rufino7393d172021-02-26 13:56:11 +000011274
11275 touch();
11276
11277 mTouchWindow->consumeAnyMotionDown();
11278}
11279
11280TEST_F(InputDispatcherUntrustedTouchesTest,
11281 WindowWithBlockUntrustedModeAndWindowWithOpacityBelowFromSameApp_BlocksTouch) {
11282 const sp<FakeWindowHandle>& w1 =
11283 getOccludingWindow(APP_B_UID, "B", TouchOcclusionMode::BLOCK_UNTRUSTED,
11284 OPACITY_BELOW_THRESHOLD);
11285 const sp<FakeWindowHandle>& w2 =
11286 getOccludingWindow(APP_B_UID, "B", TouchOcclusionMode::USE_OPACITY,
11287 OPACITY_BELOW_THRESHOLD);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070011288 mDispatcher->onWindowInfosChanged(
11289 {{*w1->getInfo(), *w2->getInfo(), *mTouchWindow->getInfo()}, {}, 0, 0});
Bernardo Rufino7393d172021-02-26 13:56:11 +000011290
11291 touch();
11292
11293 mTouchWindow->assertNoEvents();
11294}
11295
11296/**
11297 * Window B of BLOCK_UNTRUSTED occlusion mode is enough to block the touch, we're testing that the
11298 * addition of another window (C) of USE_OPACITY occlusion mode and opacity below the threshold
11299 * (which alone would result in allowing touches) does not affect the blocking behavior.
11300 */
11301TEST_F(InputDispatcherUntrustedTouchesTest,
11302 WindowWithBlockUntrustedModeAndWindowWithOpacityBelowFromDifferentApps_BlocksTouch) {
11303 const sp<FakeWindowHandle>& wB =
11304 getOccludingWindow(APP_B_UID, "B", TouchOcclusionMode::BLOCK_UNTRUSTED,
11305 OPACITY_BELOW_THRESHOLD);
11306 const sp<FakeWindowHandle>& wC =
11307 getOccludingWindow(APP_C_UID, "C", TouchOcclusionMode::USE_OPACITY,
11308 OPACITY_BELOW_THRESHOLD);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070011309 mDispatcher->onWindowInfosChanged(
11310 {{*wB->getInfo(), *wC->getInfo(), *mTouchWindow->getInfo()}, {}, 0, 0});
Bernardo Rufino7393d172021-02-26 13:56:11 +000011311
11312 touch();
11313
11314 mTouchWindow->assertNoEvents();
11315}
11316
11317/**
11318 * This test is testing that a window from a different UID but with same application token doesn't
11319 * block the touch. Apps can share the application token for close UI collaboration for example.
11320 */
11321TEST_F(InputDispatcherUntrustedTouchesTest,
11322 WindowWithSameApplicationTokenFromDifferentApp_AllowsTouch) {
11323 const sp<FakeWindowHandle>& w =
11324 getOccludingWindow(APP_B_UID, "B", TouchOcclusionMode::BLOCK_UNTRUSTED);
11325 w->setApplicationToken(mTouchWindow->getApplicationToken());
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070011326 mDispatcher->onWindowInfosChanged({{*w->getInfo(), *mTouchWindow->getInfo()}, {}, 0, 0});
Bernardo Rufinoccd3dd62021-02-15 18:47:42 +000011327
11328 touch();
11329
11330 mTouchWindow->consumeAnyMotionDown();
11331}
11332
arthurhungb89ccb02020-12-30 16:19:01 +080011333class InputDispatcherDragTests : public InputDispatcherTest {
11334protected:
11335 std::shared_ptr<FakeApplicationHandle> mApp;
11336 sp<FakeWindowHandle> mWindow;
11337 sp<FakeWindowHandle> mSecondWindow;
11338 sp<FakeWindowHandle> mDragWindow;
Vaibhav Devmurari6abcf8f2022-06-06 10:08:05 +000011339 sp<FakeWindowHandle> mSpyWindow;
Arthur Hungb75c2aa2022-07-15 09:35:36 +000011340 // Mouse would force no-split, set the id as non-zero to verify if drag state could track it.
11341 static constexpr int32_t MOUSE_POINTER_ID = 1;
arthurhungb89ccb02020-12-30 16:19:01 +080011342
11343 void SetUp() override {
11344 InputDispatcherTest::SetUp();
11345 mApp = std::make_shared<FakeApplicationHandle>();
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -070011346 mWindow = sp<FakeWindowHandle>::make(mApp, mDispatcher, "TestWindow", ADISPLAY_ID_DEFAULT);
arthurhungb89ccb02020-12-30 16:19:01 +080011347 mWindow->setFrame(Rect(0, 0, 100, 100));
arthurhungb89ccb02020-12-30 16:19:01 +080011348
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -070011349 mSecondWindow =
11350 sp<FakeWindowHandle>::make(mApp, mDispatcher, "TestWindow2", ADISPLAY_ID_DEFAULT);
arthurhungb89ccb02020-12-30 16:19:01 +080011351 mSecondWindow->setFrame(Rect(100, 0, 200, 100));
arthurhungb89ccb02020-12-30 16:19:01 +080011352
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -070011353 mSpyWindow =
11354 sp<FakeWindowHandle>::make(mApp, mDispatcher, "SpyWindow", ADISPLAY_ID_DEFAULT);
Vaibhav Devmurari6abcf8f2022-06-06 10:08:05 +000011355 mSpyWindow->setSpy(true);
11356 mSpyWindow->setTrustedOverlay(true);
11357 mSpyWindow->setFrame(Rect(0, 0, 200, 100));
11358
arthurhungb89ccb02020-12-30 16:19:01 +080011359 mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, mApp);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070011360 mDispatcher->onWindowInfosChanged(
11361 {{*mSpyWindow->getInfo(), *mWindow->getInfo(), *mSecondWindow->getInfo()},
11362 {},
11363 0,
11364 0});
arthurhungb89ccb02020-12-30 16:19:01 +080011365 }
11366
Arthur Hungb75c2aa2022-07-15 09:35:36 +000011367 void injectDown(int fromSource = AINPUT_SOURCE_TOUCHSCREEN) {
11368 switch (fromSource) {
11369 case AINPUT_SOURCE_TOUCHSCREEN:
11370 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070011371 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN,
Arthur Hungb75c2aa2022-07-15 09:35:36 +000011372 ADISPLAY_ID_DEFAULT, {50, 50}))
11373 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
11374 break;
11375 case AINPUT_SOURCE_STYLUS:
11376 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070011377 injectMotionEvent(*mDispatcher,
11378 MotionEventBuilder(AMOTION_EVENT_ACTION_DOWN,
11379 AINPUT_SOURCE_STYLUS)
11380 .buttonState(
11381 AMOTION_EVENT_BUTTON_STYLUS_PRIMARY)
11382 .pointer(PointerBuilder(0, ToolType::STYLUS)
11383 .x(50)
11384 .y(50))
11385 .build()));
Arthur Hungb75c2aa2022-07-15 09:35:36 +000011386 break;
11387 case AINPUT_SOURCE_MOUSE:
11388 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070011389 injectMotionEvent(*mDispatcher,
11390 MotionEventBuilder(AMOTION_EVENT_ACTION_DOWN,
11391 AINPUT_SOURCE_MOUSE)
11392 .buttonState(AMOTION_EVENT_BUTTON_PRIMARY)
11393 .pointer(PointerBuilder(MOUSE_POINTER_ID,
11394 ToolType::MOUSE)
11395 .x(50)
11396 .y(50))
11397 .build()));
Arthur Hungb75c2aa2022-07-15 09:35:36 +000011398 break;
11399 default:
11400 FAIL() << "Source " << fromSource << " doesn't support drag and drop";
11401 }
arthurhungb89ccb02020-12-30 16:19:01 +080011402
11403 // Window should receive motion event.
11404 mWindow->consumeMotionDown(ADISPLAY_ID_DEFAULT);
Vaibhav Devmurari6abcf8f2022-06-06 10:08:05 +000011405 // Spy window should also receive motion event
11406 mSpyWindow->consumeMotionDown(ADISPLAY_ID_DEFAULT);
Arthur Hung54745652022-04-20 07:17:41 +000011407 }
11408
11409 // Start performing drag, we will create a drag window and transfer touch to it.
11410 // @param sendDown : if true, send a motion down on first window before perform drag and drop.
11411 // Returns true on success.
Arthur Hungb75c2aa2022-07-15 09:35:36 +000011412 bool startDrag(bool sendDown = true, int fromSource = AINPUT_SOURCE_TOUCHSCREEN) {
Arthur Hung54745652022-04-20 07:17:41 +000011413 if (sendDown) {
Arthur Hungb75c2aa2022-07-15 09:35:36 +000011414 injectDown(fromSource);
Arthur Hung54745652022-04-20 07:17:41 +000011415 }
arthurhungb89ccb02020-12-30 16:19:01 +080011416
11417 // The drag window covers the entire display
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -070011418 mDragWindow =
11419 sp<FakeWindowHandle>::make(mApp, mDispatcher, "DragWindow", ADISPLAY_ID_DEFAULT);
Vaibhav Devmurari6abcf8f2022-06-06 10:08:05 +000011420 mDragWindow->setTouchableRegion(Region{{0, 0, 0, 0}});
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070011421 mDispatcher->onWindowInfosChanged({{*mDragWindow->getInfo(), *mSpyWindow->getInfo(),
11422 *mWindow->getInfo(), *mSecondWindow->getInfo()},
11423 {},
11424 0,
11425 0});
arthurhungb89ccb02020-12-30 16:19:01 +080011426
11427 // Transfer touch focus to the drag window
Arthur Hung54745652022-04-20 07:17:41 +000011428 bool transferred =
Prabir Pradhan367f3432024-02-13 23:05:58 +000011429 mDispatcher->transferTouchGesture(mWindow->getToken(), mDragWindow->getToken(),
11430 /*isDragDrop=*/true);
Arthur Hung54745652022-04-20 07:17:41 +000011431 if (transferred) {
11432 mWindow->consumeMotionCancel();
Prabir Pradhan65455c72024-02-13 21:46:41 +000011433 mDragWindow->consumeMotionDown(ADISPLAY_ID_DEFAULT, AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
Arthur Hung54745652022-04-20 07:17:41 +000011434 }
11435 return transferred;
arthurhungb89ccb02020-12-30 16:19:01 +080011436 }
11437};
11438
11439TEST_F(InputDispatcherDragTests, DragEnterAndDragExit) {
Arthur Hungb75c2aa2022-07-15 09:35:36 +000011440 startDrag();
arthurhungb89ccb02020-12-30 16:19:01 +080011441
11442 // Move on window.
11443 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070011444 injectMotionEvent(*mDispatcher, AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN,
arthurhungb89ccb02020-12-30 16:19:01 +080011445 ADISPLAY_ID_DEFAULT, {50, 50}))
11446 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
Prabir Pradhan65455c72024-02-13 21:46:41 +000011447 mDragWindow->consumeMotionMove(ADISPLAY_ID_DEFAULT, AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
arthurhungb89ccb02020-12-30 16:19:01 +080011448 mWindow->consumeDragEvent(false, 50, 50);
11449 mSecondWindow->assertNoEvents();
11450
11451 // Move to another window.
11452 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070011453 injectMotionEvent(*mDispatcher, AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN,
arthurhungb89ccb02020-12-30 16:19:01 +080011454 ADISPLAY_ID_DEFAULT, {150, 50}))
11455 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
Prabir Pradhan65455c72024-02-13 21:46:41 +000011456 mDragWindow->consumeMotionMove(ADISPLAY_ID_DEFAULT, AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
arthurhungb89ccb02020-12-30 16:19:01 +080011457 mWindow->consumeDragEvent(true, 150, 50);
11458 mSecondWindow->consumeDragEvent(false, 50, 50);
11459
11460 // Move back to original window.
11461 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070011462 injectMotionEvent(*mDispatcher, AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN,
arthurhungb89ccb02020-12-30 16:19:01 +080011463 ADISPLAY_ID_DEFAULT, {50, 50}))
11464 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
Prabir Pradhan65455c72024-02-13 21:46:41 +000011465 mDragWindow->consumeMotionMove(ADISPLAY_ID_DEFAULT, AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
arthurhungb89ccb02020-12-30 16:19:01 +080011466 mWindow->consumeDragEvent(false, 50, 50);
11467 mSecondWindow->consumeDragEvent(true, -50, 50);
11468
11469 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070011470 injectMotionUp(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
11471 {50, 50}))
arthurhungb89ccb02020-12-30 16:19:01 +080011472 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
Prabir Pradhan65455c72024-02-13 21:46:41 +000011473 mDragWindow->consumeMotionUp(ADISPLAY_ID_DEFAULT, AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
arthurhungb89ccb02020-12-30 16:19:01 +080011474 mWindow->assertNoEvents();
11475 mSecondWindow->assertNoEvents();
11476}
11477
Vaibhav Devmurari6abcf8f2022-06-06 10:08:05 +000011478TEST_F(InputDispatcherDragTests, DragEnterAndPointerDownPilfersPointers) {
Arthur Hungb75c2aa2022-07-15 09:35:36 +000011479 startDrag();
Vaibhav Devmurari6abcf8f2022-06-06 10:08:05 +000011480
11481 // No cancel event after drag start
11482 mSpyWindow->assertNoEvents();
11483
11484 const MotionEvent secondFingerDownEvent =
11485 MotionEventBuilder(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
11486 .eventTime(systemTime(SYSTEM_TIME_MONOTONIC))
Siarhei Vishniakou6d73f832022-07-21 17:27:03 -070011487 .pointer(PointerBuilder(/*id=*/0, ToolType::FINGER).x(50).y(50))
11488 .pointer(PointerBuilder(/*id=*/1, ToolType::FINGER).x(60).y(60))
Vaibhav Devmurari6abcf8f2022-06-06 10:08:05 +000011489 .build();
11490 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070011491 injectMotionEvent(*mDispatcher, secondFingerDownEvent, INJECT_EVENT_TIMEOUT,
Vaibhav Devmurari6abcf8f2022-06-06 10:08:05 +000011492 InputEventInjectionSync::WAIT_FOR_RESULT))
11493 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
11494
11495 // Receives cancel for first pointer after next pointer down
11496 mSpyWindow->consumeMotionCancel();
11497 mSpyWindow->consumeMotionDown();
11498
11499 mSpyWindow->assertNoEvents();
11500}
11501
arthurhungf452d0b2021-01-06 00:19:52 +080011502TEST_F(InputDispatcherDragTests, DragAndDrop) {
Arthur Hungb75c2aa2022-07-15 09:35:36 +000011503 startDrag();
arthurhungf452d0b2021-01-06 00:19:52 +080011504
11505 // Move on window.
11506 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070011507 injectMotionEvent(*mDispatcher, AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN,
arthurhungf452d0b2021-01-06 00:19:52 +080011508 ADISPLAY_ID_DEFAULT, {50, 50}))
11509 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
Prabir Pradhan65455c72024-02-13 21:46:41 +000011510 mDragWindow->consumeMotionMove(ADISPLAY_ID_DEFAULT, AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
arthurhungf452d0b2021-01-06 00:19:52 +080011511 mWindow->consumeDragEvent(false, 50, 50);
11512 mSecondWindow->assertNoEvents();
11513
11514 // Move to another window.
11515 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070011516 injectMotionEvent(*mDispatcher, AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN,
arthurhungf452d0b2021-01-06 00:19:52 +080011517 ADISPLAY_ID_DEFAULT, {150, 50}))
11518 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
Prabir Pradhan65455c72024-02-13 21:46:41 +000011519 mDragWindow->consumeMotionMove(ADISPLAY_ID_DEFAULT, AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
arthurhungf452d0b2021-01-06 00:19:52 +080011520 mWindow->consumeDragEvent(true, 150, 50);
11521 mSecondWindow->consumeDragEvent(false, 50, 50);
11522
11523 // drop to another window.
11524 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070011525 injectMotionUp(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
arthurhungf452d0b2021-01-06 00:19:52 +080011526 {150, 50}))
11527 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
Prabir Pradhan65455c72024-02-13 21:46:41 +000011528 mDragWindow->consumeMotionUp(ADISPLAY_ID_DEFAULT, AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
Siarhei Vishniakoua66d65e2023-06-16 10:32:51 -070011529 mFakePolicy->assertDropTargetEquals(*mDispatcher, mSecondWindow->getToken());
arthurhungf452d0b2021-01-06 00:19:52 +080011530 mWindow->assertNoEvents();
11531 mSecondWindow->assertNoEvents();
11532}
11533
Vaibhav Devmurari110ba322023-11-17 10:47:16 +000011534TEST_F(InputDispatcherDragTests, DragAndDropNotCancelledIfSomeOtherPointerIsPilfered) {
11535 startDrag();
11536
11537 // No cancel event after drag start
11538 mSpyWindow->assertNoEvents();
11539
11540 const MotionEvent secondFingerDownEvent =
11541 MotionEventBuilder(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
11542 .eventTime(systemTime(SYSTEM_TIME_MONOTONIC))
11543 .pointer(PointerBuilder(/*id=*/0, ToolType::FINGER).x(50).y(50))
11544 .pointer(PointerBuilder(/*id=*/1, ToolType::FINGER).x(60).y(60))
11545 .build();
11546 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
11547 injectMotionEvent(*mDispatcher, secondFingerDownEvent, INJECT_EVENT_TIMEOUT,
11548 InputEventInjectionSync::WAIT_FOR_RESULT))
11549 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
11550
11551 // Receives cancel for first pointer after next pointer down
11552 mSpyWindow->consumeMotionEvent(WithMotionAction(ACTION_CANCEL));
Siarhei Vishniakou1ff00cc2023-12-13 16:12:13 -080011553 mSpyWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithPointerIds({1})));
Vaibhav Devmurari110ba322023-11-17 10:47:16 +000011554 mDragWindow->consumeMotionEvent(WithMotionAction(ACTION_MOVE));
11555
11556 mSpyWindow->assertNoEvents();
11557
11558 // Spy window calls pilfer pointers
11559 EXPECT_EQ(OK, mDispatcher->pilferPointers(mSpyWindow->getToken()));
11560 mDragWindow->assertNoEvents();
11561
11562 const MotionEvent firstFingerMoveEvent =
Siarhei Vishniakou96a15572023-12-18 10:47:52 -080011563 MotionEventBuilder(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN)
Vaibhav Devmurari110ba322023-11-17 10:47:16 +000011564 .eventTime(systemTime(SYSTEM_TIME_MONOTONIC))
11565 .pointer(PointerBuilder(/*id=*/0, ToolType::FINGER).x(60).y(60))
11566 .pointer(PointerBuilder(/*id=*/1, ToolType::FINGER).x(60).y(60))
11567 .build();
11568 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakou96a15572023-12-18 10:47:52 -080011569 injectMotionEvent(*mDispatcher, firstFingerMoveEvent, INJECT_EVENT_TIMEOUT,
Vaibhav Devmurari110ba322023-11-17 10:47:16 +000011570 InputEventInjectionSync::WAIT_FOR_RESULT))
11571 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
11572
11573 // Drag window should still receive the new event
Prabir Pradhan65455c72024-02-13 21:46:41 +000011574 mDragWindow->consumeMotionEvent(
11575 AllOf(WithMotionAction(ACTION_MOVE), WithFlags(AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE)));
Vaibhav Devmurari110ba322023-11-17 10:47:16 +000011576 mDragWindow->assertNoEvents();
11577}
11578
arthurhung6d4bed92021-03-17 11:59:33 +080011579TEST_F(InputDispatcherDragTests, StylusDragAndDrop) {
Arthur Hungb75c2aa2022-07-15 09:35:36 +000011580 startDrag(true, AINPUT_SOURCE_STYLUS);
arthurhung6d4bed92021-03-17 11:59:33 +080011581
11582 // Move on window and keep button pressed.
11583 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070011584 injectMotionEvent(*mDispatcher,
arthurhung6d4bed92021-03-17 11:59:33 +080011585 MotionEventBuilder(AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_STYLUS)
11586 .buttonState(AMOTION_EVENT_BUTTON_STYLUS_PRIMARY)
Siarhei Vishniakou6d73f832022-07-21 17:27:03 -070011587 .pointer(PointerBuilder(0, ToolType::STYLUS).x(50).y(50))
arthurhung6d4bed92021-03-17 11:59:33 +080011588 .build()))
11589 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
Prabir Pradhan65455c72024-02-13 21:46:41 +000011590 mDragWindow->consumeMotionMove(ADISPLAY_ID_DEFAULT, AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
arthurhung6d4bed92021-03-17 11:59:33 +080011591 mWindow->consumeDragEvent(false, 50, 50);
11592 mSecondWindow->assertNoEvents();
11593
11594 // Move to another window and release button, expect to drop item.
11595 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070011596 injectMotionEvent(*mDispatcher,
arthurhung6d4bed92021-03-17 11:59:33 +080011597 MotionEventBuilder(AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_STYLUS)
11598 .buttonState(0)
Siarhei Vishniakou6d73f832022-07-21 17:27:03 -070011599 .pointer(PointerBuilder(0, ToolType::STYLUS).x(150).y(50))
arthurhung6d4bed92021-03-17 11:59:33 +080011600 .build()))
11601 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
Prabir Pradhan65455c72024-02-13 21:46:41 +000011602 mDragWindow->consumeMotionMove(ADISPLAY_ID_DEFAULT, AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
arthurhung6d4bed92021-03-17 11:59:33 +080011603 mWindow->assertNoEvents();
11604 mSecondWindow->assertNoEvents();
Siarhei Vishniakoua66d65e2023-06-16 10:32:51 -070011605 mFakePolicy->assertDropTargetEquals(*mDispatcher, mSecondWindow->getToken());
arthurhung6d4bed92021-03-17 11:59:33 +080011606
11607 // nothing to the window.
11608 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070011609 injectMotionEvent(*mDispatcher,
arthurhung6d4bed92021-03-17 11:59:33 +080011610 MotionEventBuilder(AMOTION_EVENT_ACTION_UP, AINPUT_SOURCE_STYLUS)
11611 .buttonState(0)
Siarhei Vishniakou6d73f832022-07-21 17:27:03 -070011612 .pointer(PointerBuilder(0, ToolType::STYLUS).x(150).y(50))
arthurhung6d4bed92021-03-17 11:59:33 +080011613 .build()))
11614 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
Prabir Pradhan65455c72024-02-13 21:46:41 +000011615 mDragWindow->consumeMotionUp(ADISPLAY_ID_DEFAULT, AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
arthurhung6d4bed92021-03-17 11:59:33 +080011616 mWindow->assertNoEvents();
11617 mSecondWindow->assertNoEvents();
11618}
11619
Arthur Hung54745652022-04-20 07:17:41 +000011620TEST_F(InputDispatcherDragTests, DragAndDropOnInvalidWindow) {
Arthur Hungb75c2aa2022-07-15 09:35:36 +000011621 startDrag();
Arthur Hung6d0571e2021-04-09 20:18:16 +080011622
11623 // Set second window invisible.
11624 mSecondWindow->setVisible(false);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070011625 mDispatcher->onWindowInfosChanged(
11626 {{*mDragWindow->getInfo(), *mWindow->getInfo(), *mSecondWindow->getInfo()}, {}, 0, 0});
Arthur Hung6d0571e2021-04-09 20:18:16 +080011627
11628 // Move on window.
11629 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070011630 injectMotionEvent(*mDispatcher, AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN,
Arthur Hung6d0571e2021-04-09 20:18:16 +080011631 ADISPLAY_ID_DEFAULT, {50, 50}))
11632 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
Prabir Pradhan65455c72024-02-13 21:46:41 +000011633 mDragWindow->consumeMotionMove(ADISPLAY_ID_DEFAULT, AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
Arthur Hung6d0571e2021-04-09 20:18:16 +080011634 mWindow->consumeDragEvent(false, 50, 50);
11635 mSecondWindow->assertNoEvents();
11636
11637 // Move to another window.
11638 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070011639 injectMotionEvent(*mDispatcher, AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN,
Arthur Hung6d0571e2021-04-09 20:18:16 +080011640 ADISPLAY_ID_DEFAULT, {150, 50}))
11641 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
Prabir Pradhan65455c72024-02-13 21:46:41 +000011642 mDragWindow->consumeMotionMove(ADISPLAY_ID_DEFAULT, AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
Arthur Hung6d0571e2021-04-09 20:18:16 +080011643 mWindow->consumeDragEvent(true, 150, 50);
11644 mSecondWindow->assertNoEvents();
11645
11646 // drop to another window.
11647 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070011648 injectMotionUp(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
Arthur Hung6d0571e2021-04-09 20:18:16 +080011649 {150, 50}))
11650 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
Prabir Pradhan65455c72024-02-13 21:46:41 +000011651 mDragWindow->consumeMotionUp(ADISPLAY_ID_DEFAULT, AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
Siarhei Vishniakoua66d65e2023-06-16 10:32:51 -070011652 mFakePolicy->assertDropTargetEquals(*mDispatcher, nullptr);
Arthur Hung6d0571e2021-04-09 20:18:16 +080011653 mWindow->assertNoEvents();
11654 mSecondWindow->assertNoEvents();
11655}
11656
Arthur Hung54745652022-04-20 07:17:41 +000011657TEST_F(InputDispatcherDragTests, NoDragAndDropWhenMultiFingers) {
Arthur Hungb75c2aa2022-07-15 09:35:36 +000011658 // Ensure window could track pointerIds if it didn't support split touch.
11659 mWindow->setPreventSplitting(true);
11660
Arthur Hung54745652022-04-20 07:17:41 +000011661 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070011662 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
Arthur Hung54745652022-04-20 07:17:41 +000011663 {50, 50}))
11664 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
11665 mWindow->consumeMotionDown(ADISPLAY_ID_DEFAULT);
11666
11667 const MotionEvent secondFingerDownEvent =
11668 MotionEventBuilder(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
11669 .displayId(ADISPLAY_ID_DEFAULT)
11670 .eventTime(systemTime(SYSTEM_TIME_MONOTONIC))
Siarhei Vishniakou6d73f832022-07-21 17:27:03 -070011671 .pointer(PointerBuilder(/*id=*/0, ToolType::FINGER).x(50).y(50))
11672 .pointer(PointerBuilder(/*id=*/1, ToolType::FINGER).x(75).y(50))
Arthur Hung54745652022-04-20 07:17:41 +000011673 .build();
11674 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070011675 injectMotionEvent(*mDispatcher, secondFingerDownEvent, INJECT_EVENT_TIMEOUT,
Arthur Hung54745652022-04-20 07:17:41 +000011676 InputEventInjectionSync::WAIT_FOR_RESULT))
11677 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
Harry Cutts33476232023-01-30 19:57:29 +000011678 mWindow->consumeMotionPointerDown(/*pointerIndex=*/1);
Arthur Hung54745652022-04-20 07:17:41 +000011679
11680 // Should not perform drag and drop when window has multi fingers.
Arthur Hungb75c2aa2022-07-15 09:35:36 +000011681 ASSERT_FALSE(startDrag(false));
Arthur Hung54745652022-04-20 07:17:41 +000011682}
11683
11684TEST_F(InputDispatcherDragTests, DragAndDropWhenSplitTouch) {
11685 // First down on second window.
11686 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070011687 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
Arthur Hung54745652022-04-20 07:17:41 +000011688 {150, 50}))
11689 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
11690
11691 mSecondWindow->consumeMotionDown(ADISPLAY_ID_DEFAULT);
11692
11693 // Second down on first window.
11694 const MotionEvent secondFingerDownEvent =
11695 MotionEventBuilder(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
11696 .displayId(ADISPLAY_ID_DEFAULT)
11697 .eventTime(systemTime(SYSTEM_TIME_MONOTONIC))
Siarhei Vishniakou6d73f832022-07-21 17:27:03 -070011698 .pointer(PointerBuilder(/*id=*/0, ToolType::FINGER).x(150).y(50))
11699 .pointer(PointerBuilder(/*id=*/1, ToolType::FINGER).x(50).y(50))
Arthur Hung54745652022-04-20 07:17:41 +000011700 .build();
11701 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070011702 injectMotionEvent(*mDispatcher, secondFingerDownEvent, INJECT_EVENT_TIMEOUT,
Arthur Hung54745652022-04-20 07:17:41 +000011703 InputEventInjectionSync::WAIT_FOR_RESULT))
11704 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
11705 mWindow->consumeMotionDown(ADISPLAY_ID_DEFAULT);
Prabir Pradhan9d5f9ce2024-01-24 00:03:41 +000011706 mSecondWindow->consumeMotionMove(ADISPLAY_ID_DEFAULT);
Arthur Hung54745652022-04-20 07:17:41 +000011707
11708 // Perform drag and drop from first window.
Arthur Hungb75c2aa2022-07-15 09:35:36 +000011709 ASSERT_TRUE(startDrag(false));
Arthur Hung54745652022-04-20 07:17:41 +000011710
11711 // Move on window.
11712 const MotionEvent secondFingerMoveEvent =
11713 MotionEventBuilder(AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN)
11714 .eventTime(systemTime(SYSTEM_TIME_MONOTONIC))
Siarhei Vishniakou6d73f832022-07-21 17:27:03 -070011715 .pointer(PointerBuilder(/*id=*/0, ToolType::FINGER).x(150).y(50))
11716 .pointer(PointerBuilder(/*id=*/1, ToolType::FINGER).x(50).y(50))
Arthur Hung54745652022-04-20 07:17:41 +000011717 .build();
11718 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070011719 injectMotionEvent(*mDispatcher, secondFingerMoveEvent, INJECT_EVENT_TIMEOUT,
Arthur Hung54745652022-04-20 07:17:41 +000011720 InputEventInjectionSync::WAIT_FOR_RESULT));
Prabir Pradhan65455c72024-02-13 21:46:41 +000011721 mDragWindow->consumeMotionMove(ADISPLAY_ID_DEFAULT, AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
Arthur Hung54745652022-04-20 07:17:41 +000011722 mWindow->consumeDragEvent(false, 50, 50);
11723 mSecondWindow->consumeMotionMove();
11724
11725 // Release the drag pointer should perform drop.
11726 const MotionEvent secondFingerUpEvent =
11727 MotionEventBuilder(POINTER_1_UP, AINPUT_SOURCE_TOUCHSCREEN)
11728 .eventTime(systemTime(SYSTEM_TIME_MONOTONIC))
Siarhei Vishniakou6d73f832022-07-21 17:27:03 -070011729 .pointer(PointerBuilder(/*id=*/0, ToolType::FINGER).x(150).y(50))
11730 .pointer(PointerBuilder(/*id=*/1, ToolType::FINGER).x(50).y(50))
Arthur Hung54745652022-04-20 07:17:41 +000011731 .build();
11732 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070011733 injectMotionEvent(*mDispatcher, secondFingerUpEvent, INJECT_EVENT_TIMEOUT,
Arthur Hung54745652022-04-20 07:17:41 +000011734 InputEventInjectionSync::WAIT_FOR_RESULT));
Prabir Pradhan65455c72024-02-13 21:46:41 +000011735 mDragWindow->consumeMotionUp(ADISPLAY_ID_DEFAULT, AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
Siarhei Vishniakoua66d65e2023-06-16 10:32:51 -070011736 mFakePolicy->assertDropTargetEquals(*mDispatcher, mWindow->getToken());
Arthur Hung54745652022-04-20 07:17:41 +000011737 mWindow->assertNoEvents();
11738 mSecondWindow->consumeMotionMove();
11739}
11740
Arthur Hung3915c1f2022-05-31 07:17:17 +000011741TEST_F(InputDispatcherDragTests, DragAndDropWhenMultiDisplays) {
Arthur Hungb75c2aa2022-07-15 09:35:36 +000011742 startDrag();
Arthur Hung3915c1f2022-05-31 07:17:17 +000011743
11744 // Update window of second display.
11745 sp<FakeWindowHandle> windowInSecondary =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -070011746 sp<FakeWindowHandle>::make(mApp, mDispatcher, "D_2", SECOND_DISPLAY_ID);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070011747 mDispatcher->onWindowInfosChanged(
11748 {{*mDragWindow->getInfo(), *mSpyWindow->getInfo(), *mWindow->getInfo(),
11749 *mSecondWindow->getInfo(), *windowInSecondary->getInfo()},
11750 {},
11751 0,
11752 0});
Arthur Hung3915c1f2022-05-31 07:17:17 +000011753
11754 // Let second display has a touch state.
11755 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070011756 injectMotionEvent(*mDispatcher,
Arthur Hung3915c1f2022-05-31 07:17:17 +000011757 MotionEventBuilder(AMOTION_EVENT_ACTION_DOWN,
11758 AINPUT_SOURCE_TOUCHSCREEN)
11759 .displayId(SECOND_DISPLAY_ID)
Siarhei Vishniakou6d73f832022-07-21 17:27:03 -070011760 .pointer(PointerBuilder(0, ToolType::FINGER).x(100).y(100))
Arthur Hung3915c1f2022-05-31 07:17:17 +000011761 .build()));
Prabir Pradhan7662a8d2023-12-15 01:58:14 +000011762 windowInSecondary->consumeMotionDown(SECOND_DISPLAY_ID, /*expectedFlag=*/0);
Arthur Hung3915c1f2022-05-31 07:17:17 +000011763 // Update window again.
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070011764 mDispatcher->onWindowInfosChanged(
11765 {{*mDragWindow->getInfo(), *mSpyWindow->getInfo(), *mWindow->getInfo(),
11766 *mSecondWindow->getInfo(), *windowInSecondary->getInfo()},
11767 {},
11768 0,
11769 0});
Arthur Hung3915c1f2022-05-31 07:17:17 +000011770
11771 // Move on window.
11772 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070011773 injectMotionEvent(*mDispatcher, AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN,
Arthur Hung3915c1f2022-05-31 07:17:17 +000011774 ADISPLAY_ID_DEFAULT, {50, 50}))
11775 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
Prabir Pradhan65455c72024-02-13 21:46:41 +000011776 mDragWindow->consumeMotionMove(ADISPLAY_ID_DEFAULT, AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
Arthur Hung3915c1f2022-05-31 07:17:17 +000011777 mWindow->consumeDragEvent(false, 50, 50);
11778 mSecondWindow->assertNoEvents();
11779
11780 // Move to another window.
11781 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070011782 injectMotionEvent(*mDispatcher, AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN,
Arthur Hung3915c1f2022-05-31 07:17:17 +000011783 ADISPLAY_ID_DEFAULT, {150, 50}))
11784 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
Prabir Pradhan65455c72024-02-13 21:46:41 +000011785 mDragWindow->consumeMotionMove(ADISPLAY_ID_DEFAULT, AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
Arthur Hung3915c1f2022-05-31 07:17:17 +000011786 mWindow->consumeDragEvent(true, 150, 50);
11787 mSecondWindow->consumeDragEvent(false, 50, 50);
11788
11789 // drop to another window.
11790 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070011791 injectMotionUp(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
Arthur Hung3915c1f2022-05-31 07:17:17 +000011792 {150, 50}))
11793 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
Prabir Pradhan65455c72024-02-13 21:46:41 +000011794 mDragWindow->consumeMotionUp(ADISPLAY_ID_DEFAULT, AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
Siarhei Vishniakoua66d65e2023-06-16 10:32:51 -070011795 mFakePolicy->assertDropTargetEquals(*mDispatcher, mSecondWindow->getToken());
Arthur Hung3915c1f2022-05-31 07:17:17 +000011796 mWindow->assertNoEvents();
11797 mSecondWindow->assertNoEvents();
11798}
11799
Arthur Hungb75c2aa2022-07-15 09:35:36 +000011800TEST_F(InputDispatcherDragTests, MouseDragAndDrop) {
11801 startDrag(true, AINPUT_SOURCE_MOUSE);
11802 // Move on window.
11803 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070011804 injectMotionEvent(*mDispatcher,
Arthur Hungb75c2aa2022-07-15 09:35:36 +000011805 MotionEventBuilder(AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_MOUSE)
11806 .buttonState(AMOTION_EVENT_BUTTON_PRIMARY)
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070011807 .pointer(PointerBuilder(MOUSE_POINTER_ID, ToolType::MOUSE)
Arthur Hungb75c2aa2022-07-15 09:35:36 +000011808 .x(50)
11809 .y(50))
11810 .build()))
11811 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
Prabir Pradhan65455c72024-02-13 21:46:41 +000011812 mDragWindow->consumeMotionMove(ADISPLAY_ID_DEFAULT, AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
Arthur Hungb75c2aa2022-07-15 09:35:36 +000011813 mWindow->consumeDragEvent(false, 50, 50);
11814 mSecondWindow->assertNoEvents();
11815
11816 // Move to another window.
11817 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070011818 injectMotionEvent(*mDispatcher,
Arthur Hungb75c2aa2022-07-15 09:35:36 +000011819 MotionEventBuilder(AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_MOUSE)
11820 .buttonState(AMOTION_EVENT_BUTTON_PRIMARY)
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070011821 .pointer(PointerBuilder(MOUSE_POINTER_ID, ToolType::MOUSE)
Arthur Hungb75c2aa2022-07-15 09:35:36 +000011822 .x(150)
11823 .y(50))
11824 .build()))
11825 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
Prabir Pradhan65455c72024-02-13 21:46:41 +000011826 mDragWindow->consumeMotionMove(ADISPLAY_ID_DEFAULT, AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
Arthur Hungb75c2aa2022-07-15 09:35:36 +000011827 mWindow->consumeDragEvent(true, 150, 50);
11828 mSecondWindow->consumeDragEvent(false, 50, 50);
11829
11830 // drop to another window.
11831 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070011832 injectMotionEvent(*mDispatcher,
Arthur Hungb75c2aa2022-07-15 09:35:36 +000011833 MotionEventBuilder(AMOTION_EVENT_ACTION_UP, AINPUT_SOURCE_MOUSE)
11834 .buttonState(0)
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070011835 .pointer(PointerBuilder(MOUSE_POINTER_ID, ToolType::MOUSE)
Arthur Hungb75c2aa2022-07-15 09:35:36 +000011836 .x(150)
11837 .y(50))
11838 .build()))
11839 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
Prabir Pradhan65455c72024-02-13 21:46:41 +000011840 mDragWindow->consumeMotionUp(ADISPLAY_ID_DEFAULT, AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
Siarhei Vishniakoua66d65e2023-06-16 10:32:51 -070011841 mFakePolicy->assertDropTargetEquals(*mDispatcher, mSecondWindow->getToken());
Arthur Hungb75c2aa2022-07-15 09:35:36 +000011842 mWindow->assertNoEvents();
11843 mSecondWindow->assertNoEvents();
11844}
11845
Linnan Li5af92f92023-07-14 14:36:22 +080011846/**
11847 * Start drag and drop with a pointer whose id is not 0, cancel the current touch, and ensure drag
11848 * and drop is also canceled. Then inject a simple gesture, and ensure dispatcher does not crash.
11849 */
11850TEST_F(InputDispatcherDragTests, DragAndDropFinishedWhenCancelCurrentTouch) {
11851 // Down on second window
11852 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
11853 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
11854 {150, 50}))
11855 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
11856
11857 ASSERT_NO_FATAL_FAILURE(mSecondWindow->consumeMotionDown());
11858 ASSERT_NO_FATAL_FAILURE(mSpyWindow->consumeMotionDown());
11859
11860 // Down on first window
11861 const MotionEvent secondFingerDownEvent =
11862 MotionEventBuilder(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
11863 .displayId(ADISPLAY_ID_DEFAULT)
11864 .pointer(PointerBuilder(/*id=*/0, ToolType::FINGER).x(150).y(50))
11865 .pointer(PointerBuilder(/*id=*/1, ToolType::FINGER).x(50).y(50))
11866 .build();
11867 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
11868 injectMotionEvent(*mDispatcher, secondFingerDownEvent, INJECT_EVENT_TIMEOUT,
11869 InputEventInjectionSync::WAIT_FOR_RESULT))
11870 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
11871 ASSERT_NO_FATAL_FAILURE(mWindow->consumeMotionDown());
11872 ASSERT_NO_FATAL_FAILURE(mSecondWindow->consumeMotionMove());
11873 ASSERT_NO_FATAL_FAILURE(mSpyWindow->consumeMotionPointerDown(1));
11874
11875 // Start drag on first window
11876 ASSERT_TRUE(startDrag(/*sendDown=*/false, AINPUT_SOURCE_TOUCHSCREEN));
11877
11878 // Trigger cancel
11879 mDispatcher->cancelCurrentTouch();
11880 ASSERT_NO_FATAL_FAILURE(mSecondWindow->consumeMotionCancel());
Prabir Pradhan65455c72024-02-13 21:46:41 +000011881 ASSERT_NO_FATAL_FAILURE(mDragWindow->consumeMotionCancel(ADISPLAY_ID_DEFAULT,
11882 AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE));
Linnan Li5af92f92023-07-14 14:36:22 +080011883 ASSERT_NO_FATAL_FAILURE(mSpyWindow->consumeMotionCancel());
11884
11885 ASSERT_TRUE(mDispatcher->waitForIdle());
11886 // The D&D finished with nullptr
11887 mFakePolicy->assertDropTargetEquals(*mDispatcher, nullptr);
11888
11889 // Remove drag window
11890 mDispatcher->onWindowInfosChanged({{*mWindow->getInfo(), *mSecondWindow->getInfo()}, {}, 0, 0});
11891
11892 // Inject a simple gesture, ensure dispatcher not crashed
11893 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
11894 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
11895 PointF{50, 50}))
11896 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
11897 ASSERT_NO_FATAL_FAILURE(mWindow->consumeMotionDown());
11898
11899 const MotionEvent moveEvent =
11900 MotionEventBuilder(AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN)
11901 .displayId(ADISPLAY_ID_DEFAULT)
11902 .pointer(PointerBuilder(/*id=*/0, ToolType::FINGER).x(50).y(50))
11903 .build();
11904 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
11905 injectMotionEvent(*mDispatcher, moveEvent, INJECT_EVENT_TIMEOUT,
11906 InputEventInjectionSync::WAIT_FOR_RESULT))
11907 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
11908 ASSERT_NO_FATAL_FAILURE(mWindow->consumeMotionMove());
11909
11910 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
11911 injectMotionUp(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
11912 {50, 50}))
11913 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
11914 ASSERT_NO_FATAL_FAILURE(mWindow->consumeMotionUp());
11915}
11916
Prabir Pradhan9cd9eb62023-11-22 17:58:06 +000011917TEST_F(InputDispatcherDragTests, NoDragAndDropWithHoveringPointer) {
11918 // Start hovering over the window.
11919 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
11920 injectMotionEvent(*mDispatcher, ACTION_HOVER_ENTER, AINPUT_SOURCE_MOUSE,
11921 ADISPLAY_ID_DEFAULT, {50, 50}));
11922
11923 ASSERT_NO_FATAL_FAILURE(mWindow->consumeMotionEvent(WithMotionAction(ACTION_HOVER_ENTER)));
11924 ASSERT_NO_FATAL_FAILURE(mSpyWindow->consumeMotionEvent(WithMotionAction(ACTION_HOVER_ENTER)));
11925
11926 ASSERT_FALSE(startDrag(/*sendDown=*/false))
11927 << "Drag and drop should not work with a hovering pointer";
11928}
11929
Vishnu Nair062a8672021-09-03 16:07:44 -070011930class InputDispatcherDropInputFeatureTest : public InputDispatcherTest {};
11931
11932TEST_F(InputDispatcherDropInputFeatureTest, WindowDropsInput) {
11933 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -070011934 sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher,
11935 "Test window", ADISPLAY_ID_DEFAULT);
Prabir Pradhan51e7db02022-02-07 06:02:57 -080011936 window->setDropInput(true);
Vishnu Nair062a8672021-09-03 16:07:44 -070011937 mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application);
11938 window->setFocusable(true);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070011939 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Vishnu Nair062a8672021-09-03 16:07:44 -070011940 setFocusedWindow(window);
Harry Cutts33476232023-01-30 19:57:29 +000011941 window->consumeFocusEvent(/*hasFocus=*/true, /*inTouchMode=*/true);
Vishnu Nair062a8672021-09-03 16:07:44 -070011942
11943 // With the flag set, window should not get any input
Prabir Pradhan678438e2023-04-13 19:32:51 +000011944 mDispatcher->notifyKey(generateKeyArgs(AKEY_EVENT_ACTION_DOWN, ADISPLAY_ID_DEFAULT));
Vishnu Nair062a8672021-09-03 16:07:44 -070011945 window->assertNoEvents();
11946
Prabir Pradhan678438e2023-04-13 19:32:51 +000011947 mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_DOWN,
11948 AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT));
Siarhei Vishniakou5c02a712023-05-15 15:45:02 -070011949 mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN,
11950 ADISPLAY_ID_DEFAULT));
Siarhei Vishniakoud908f5a2023-11-16 10:25:12 -080011951 mDispatcher->waitForIdle();
Vishnu Nair062a8672021-09-03 16:07:44 -070011952 window->assertNoEvents();
11953
11954 // With the flag cleared, the window should get input
Prabir Pradhan51e7db02022-02-07 06:02:57 -080011955 window->setDropInput(false);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070011956 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Vishnu Nair062a8672021-09-03 16:07:44 -070011957
Prabir Pradhan678438e2023-04-13 19:32:51 +000011958 mDispatcher->notifyKey(generateKeyArgs(AKEY_EVENT_ACTION_UP, ADISPLAY_ID_DEFAULT));
Vishnu Nair062a8672021-09-03 16:07:44 -070011959 window->consumeKeyUp(ADISPLAY_ID_DEFAULT);
11960
Prabir Pradhan678438e2023-04-13 19:32:51 +000011961 mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_DOWN,
11962 AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT));
Vishnu Nair062a8672021-09-03 16:07:44 -070011963 window->consumeMotionDown(ADISPLAY_ID_DEFAULT);
11964 window->assertNoEvents();
11965}
11966
11967TEST_F(InputDispatcherDropInputFeatureTest, ObscuredWindowDropsInput) {
11968 std::shared_ptr<FakeApplicationHandle> obscuringApplication =
11969 std::make_shared<FakeApplicationHandle>();
11970 sp<FakeWindowHandle> obscuringWindow =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -070011971 sp<FakeWindowHandle>::make(obscuringApplication, mDispatcher, "obscuringWindow",
11972 ADISPLAY_ID_DEFAULT);
Vishnu Nair062a8672021-09-03 16:07:44 -070011973 obscuringWindow->setFrame(Rect(0, 0, 50, 50));
Prabir Pradhanaeebeb42023-06-13 19:53:03 +000011974 obscuringWindow->setOwnerInfo(gui::Pid{111}, gui::Uid{111});
Prabir Pradhan4d5c52f2022-01-31 08:52:10 -080011975 obscuringWindow->setTouchable(false);
Vishnu Nair062a8672021-09-03 16:07:44 -070011976 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -070011977 sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher,
11978 "Test window", ADISPLAY_ID_DEFAULT);
Prabir Pradhan51e7db02022-02-07 06:02:57 -080011979 window->setDropInputIfObscured(true);
Prabir Pradhanaeebeb42023-06-13 19:53:03 +000011980 window->setOwnerInfo(gui::Pid{222}, gui::Uid{222});
Vishnu Nair062a8672021-09-03 16:07:44 -070011981 mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application);
11982 window->setFocusable(true);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070011983 mDispatcher->onWindowInfosChanged(
11984 {{*obscuringWindow->getInfo(), *window->getInfo()}, {}, 0, 0});
Vishnu Nair062a8672021-09-03 16:07:44 -070011985 setFocusedWindow(window);
Harry Cutts33476232023-01-30 19:57:29 +000011986 window->consumeFocusEvent(/*hasFocus=*/true, /*inTouchMode=*/true);
Vishnu Nair062a8672021-09-03 16:07:44 -070011987
11988 // With the flag set, window should not get any input
Prabir Pradhan678438e2023-04-13 19:32:51 +000011989 mDispatcher->notifyKey(generateKeyArgs(AKEY_EVENT_ACTION_DOWN, ADISPLAY_ID_DEFAULT));
Vishnu Nair062a8672021-09-03 16:07:44 -070011990 window->assertNoEvents();
11991
Prabir Pradhan678438e2023-04-13 19:32:51 +000011992 mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_DOWN,
11993 AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT));
Siarhei Vishniakou5c02a712023-05-15 15:45:02 -070011994 mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN,
11995 ADISPLAY_ID_DEFAULT));
Vishnu Nair062a8672021-09-03 16:07:44 -070011996 window->assertNoEvents();
11997
11998 // With the flag cleared, the window should get input
Prabir Pradhan51e7db02022-02-07 06:02:57 -080011999 window->setDropInputIfObscured(false);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070012000 mDispatcher->onWindowInfosChanged(
12001 {{*obscuringWindow->getInfo(), *window->getInfo()}, {}, 0, 0});
Vishnu Nair062a8672021-09-03 16:07:44 -070012002
Prabir Pradhan678438e2023-04-13 19:32:51 +000012003 mDispatcher->notifyKey(generateKeyArgs(AKEY_EVENT_ACTION_UP, ADISPLAY_ID_DEFAULT));
Vishnu Nair062a8672021-09-03 16:07:44 -070012004 window->consumeKeyUp(ADISPLAY_ID_DEFAULT);
12005
Prabir Pradhan678438e2023-04-13 19:32:51 +000012006 mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_DOWN,
12007 AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT));
Vishnu Nair062a8672021-09-03 16:07:44 -070012008 window->consumeMotionDown(ADISPLAY_ID_DEFAULT, AMOTION_EVENT_FLAG_WINDOW_IS_PARTIALLY_OBSCURED);
12009 window->assertNoEvents();
12010}
12011
12012TEST_F(InputDispatcherDropInputFeatureTest, UnobscuredWindowGetsInput) {
12013 std::shared_ptr<FakeApplicationHandle> obscuringApplication =
12014 std::make_shared<FakeApplicationHandle>();
12015 sp<FakeWindowHandle> obscuringWindow =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -070012016 sp<FakeWindowHandle>::make(obscuringApplication, mDispatcher, "obscuringWindow",
12017 ADISPLAY_ID_DEFAULT);
Vishnu Nair062a8672021-09-03 16:07:44 -070012018 obscuringWindow->setFrame(Rect(0, 0, 50, 50));
Prabir Pradhanaeebeb42023-06-13 19:53:03 +000012019 obscuringWindow->setOwnerInfo(gui::Pid{111}, gui::Uid{111});
Prabir Pradhan4d5c52f2022-01-31 08:52:10 -080012020 obscuringWindow->setTouchable(false);
Vishnu Nair062a8672021-09-03 16:07:44 -070012021 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -070012022 sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher,
12023 "Test window", ADISPLAY_ID_DEFAULT);
Prabir Pradhan51e7db02022-02-07 06:02:57 -080012024 window->setDropInputIfObscured(true);
Prabir Pradhanaeebeb42023-06-13 19:53:03 +000012025 window->setOwnerInfo(gui::Pid{222}, gui::Uid{222});
Vishnu Nair062a8672021-09-03 16:07:44 -070012026 mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application);
12027 window->setFocusable(true);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070012028 mDispatcher->onWindowInfosChanged(
12029 {{*obscuringWindow->getInfo(), *window->getInfo()}, {}, 0, 0});
Vishnu Nair062a8672021-09-03 16:07:44 -070012030 setFocusedWindow(window);
Harry Cutts33476232023-01-30 19:57:29 +000012031 window->consumeFocusEvent(/*hasFocus=*/true, /*inTouchMode=*/true);
Vishnu Nair062a8672021-09-03 16:07:44 -070012032
12033 // With the flag set, window should not get any input
Prabir Pradhan678438e2023-04-13 19:32:51 +000012034 mDispatcher->notifyKey(generateKeyArgs(AKEY_EVENT_ACTION_DOWN, ADISPLAY_ID_DEFAULT));
Vishnu Nair062a8672021-09-03 16:07:44 -070012035 window->assertNoEvents();
12036
Prabir Pradhan678438e2023-04-13 19:32:51 +000012037 mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_DOWN,
12038 AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT));
Siarhei Vishniakou5c02a712023-05-15 15:45:02 -070012039 mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN,
12040 ADISPLAY_ID_DEFAULT));
Vishnu Nair062a8672021-09-03 16:07:44 -070012041 window->assertNoEvents();
12042
12043 // When the window is no longer obscured because it went on top, it should get input
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070012044 mDispatcher->onWindowInfosChanged(
12045 {{*window->getInfo(), *obscuringWindow->getInfo()}, {}, 0, 0});
Vishnu Nair062a8672021-09-03 16:07:44 -070012046
Prabir Pradhan678438e2023-04-13 19:32:51 +000012047 mDispatcher->notifyKey(generateKeyArgs(AKEY_EVENT_ACTION_UP, ADISPLAY_ID_DEFAULT));
Vishnu Nair062a8672021-09-03 16:07:44 -070012048 window->consumeKeyUp(ADISPLAY_ID_DEFAULT);
12049
Prabir Pradhan678438e2023-04-13 19:32:51 +000012050 mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_DOWN,
12051 AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT));
Vishnu Nair062a8672021-09-03 16:07:44 -070012052 window->consumeMotionDown(ADISPLAY_ID_DEFAULT);
12053 window->assertNoEvents();
12054}
12055
Antonio Kantekf16f2832021-09-28 04:39:20 +000012056class InputDispatcherTouchModeChangedTests : public InputDispatcherTest {
12057protected:
12058 std::shared_ptr<FakeApplicationHandle> mApp;
Antonio Kantek15beb512022-06-13 22:35:41 +000012059 std::shared_ptr<FakeApplicationHandle> mSecondaryApp;
Antonio Kantekf16f2832021-09-28 04:39:20 +000012060 sp<FakeWindowHandle> mWindow;
12061 sp<FakeWindowHandle> mSecondWindow;
Antonio Kantek15beb512022-06-13 22:35:41 +000012062 sp<FakeWindowHandle> mThirdWindow;
Antonio Kantekf16f2832021-09-28 04:39:20 +000012063
12064 void SetUp() override {
12065 InputDispatcherTest::SetUp();
12066
12067 mApp = std::make_shared<FakeApplicationHandle>();
Antonio Kantek15beb512022-06-13 22:35:41 +000012068 mSecondaryApp = std::make_shared<FakeApplicationHandle>();
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -070012069 mWindow = sp<FakeWindowHandle>::make(mApp, mDispatcher, "TestWindow", ADISPLAY_ID_DEFAULT);
Antonio Kantekf16f2832021-09-28 04:39:20 +000012070 mWindow->setFocusable(true);
Antonio Kantek26defcf2022-02-08 01:12:27 +000012071 setFocusedWindow(mWindow);
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -070012072 mSecondWindow =
12073 sp<FakeWindowHandle>::make(mApp, mDispatcher, "TestWindow2", ADISPLAY_ID_DEFAULT);
Antonio Kantekf16f2832021-09-28 04:39:20 +000012074 mSecondWindow->setFocusable(true);
Antonio Kantek15beb512022-06-13 22:35:41 +000012075 mThirdWindow =
12076 sp<FakeWindowHandle>::make(mSecondaryApp, mDispatcher,
12077 "TestWindow3_SecondaryDisplay", SECOND_DISPLAY_ID);
12078 mThirdWindow->setFocusable(true);
Antonio Kantekf16f2832021-09-28 04:39:20 +000012079
12080 mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, mApp);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070012081 mDispatcher->onWindowInfosChanged(
12082 {{*mWindow->getInfo(), *mSecondWindow->getInfo(), *mThirdWindow->getInfo()},
12083 {},
12084 0,
12085 0});
Antonio Kantek15beb512022-06-13 22:35:41 +000012086 mThirdWindow->setOwnerInfo(SECONDARY_WINDOW_PID, SECONDARY_WINDOW_UID);
Antonio Kantekf16f2832021-09-28 04:39:20 +000012087 mWindow->consumeFocusEvent(true);
Antonio Kantek26defcf2022-02-08 01:12:27 +000012088
Antonio Kantek15beb512022-06-13 22:35:41 +000012089 // Set main display initial touch mode to InputDispatcher::kDefaultInTouchMode.
Prabir Pradhan5735a322022-04-11 17:23:34 +000012090 if (mDispatcher->setInTouchMode(InputDispatcher::kDefaultInTouchMode, WINDOW_PID,
Harry Cutts33476232023-01-30 19:57:29 +000012091 WINDOW_UID, /*hasPermission=*/true, ADISPLAY_ID_DEFAULT)) {
Antonio Kantek48710e42022-03-24 14:19:30 -070012092 mWindow->consumeTouchModeEvent(InputDispatcher::kDefaultInTouchMode);
12093 mSecondWindow->consumeTouchModeEvent(InputDispatcher::kDefaultInTouchMode);
Antonio Kantek15beb512022-06-13 22:35:41 +000012094 mThirdWindow->assertNoEvents();
12095 }
12096
12097 // Set secondary display initial touch mode to InputDispatcher::kDefaultInTouchMode.
12098 if (mDispatcher->setInTouchMode(InputDispatcher::kDefaultInTouchMode, SECONDARY_WINDOW_PID,
Harry Cutts33476232023-01-30 19:57:29 +000012099 SECONDARY_WINDOW_UID, /*hasPermission=*/true,
Antonio Kantek15beb512022-06-13 22:35:41 +000012100 SECOND_DISPLAY_ID)) {
12101 mWindow->assertNoEvents();
12102 mSecondWindow->assertNoEvents();
12103 mThirdWindow->consumeTouchModeEvent(InputDispatcher::kDefaultInTouchMode);
Antonio Kantek48710e42022-03-24 14:19:30 -070012104 }
Antonio Kantekf16f2832021-09-28 04:39:20 +000012105 }
12106
Prabir Pradhanaeebeb42023-06-13 19:53:03 +000012107 void changeAndVerifyTouchModeInMainDisplayOnly(bool inTouchMode, gui::Pid pid, gui::Uid uid,
Antonio Kantek15beb512022-06-13 22:35:41 +000012108 bool hasPermission) {
Antonio Kanteka042c022022-07-06 16:51:07 -070012109 ASSERT_TRUE(mDispatcher->setInTouchMode(inTouchMode, pid, uid, hasPermission,
12110 ADISPLAY_ID_DEFAULT));
Antonio Kantekf16f2832021-09-28 04:39:20 +000012111 mWindow->consumeTouchModeEvent(inTouchMode);
12112 mSecondWindow->consumeTouchModeEvent(inTouchMode);
Antonio Kantek15beb512022-06-13 22:35:41 +000012113 mThirdWindow->assertNoEvents();
Antonio Kantekf16f2832021-09-28 04:39:20 +000012114 }
12115};
12116
Antonio Kantek26defcf2022-02-08 01:12:27 +000012117TEST_F(InputDispatcherTouchModeChangedTests, FocusedWindowCanChangeTouchMode) {
Antonio Kantekea47acb2021-12-23 12:41:25 -080012118 const WindowInfo& windowInfo = *mWindow->getInfo();
Antonio Kantek15beb512022-06-13 22:35:41 +000012119 changeAndVerifyTouchModeInMainDisplayOnly(!InputDispatcher::kDefaultInTouchMode,
12120 windowInfo.ownerPid, windowInfo.ownerUid,
Harry Cutts33476232023-01-30 19:57:29 +000012121 /* hasPermission=*/false);
Antonio Kantekf16f2832021-09-28 04:39:20 +000012122}
12123
Antonio Kantek26defcf2022-02-08 01:12:27 +000012124TEST_F(InputDispatcherTouchModeChangedTests, NonFocusedWindowOwnerCannotChangeTouchMode) {
12125 const WindowInfo& windowInfo = *mWindow->getInfo();
Prabir Pradhanaeebeb42023-06-13 19:53:03 +000012126 gui::Pid ownerPid = windowInfo.ownerPid;
Prabir Pradhan8a5c41d2023-06-08 19:13:46 +000012127 gui::Uid ownerUid = windowInfo.ownerUid;
Prabir Pradhanaeebeb42023-06-13 19:53:03 +000012128 mWindow->setOwnerInfo(gui::Pid::INVALID, gui::Uid::INVALID);
Antonio Kantek26defcf2022-02-08 01:12:27 +000012129 ASSERT_FALSE(mDispatcher->setInTouchMode(InputDispatcher::kDefaultInTouchMode, ownerPid,
Harry Cutts33476232023-01-30 19:57:29 +000012130 ownerUid, /*hasPermission=*/false,
Antonio Kanteka042c022022-07-06 16:51:07 -070012131 ADISPLAY_ID_DEFAULT));
Antonio Kantek26defcf2022-02-08 01:12:27 +000012132 mWindow->assertNoEvents();
12133 mSecondWindow->assertNoEvents();
12134}
12135
12136TEST_F(InputDispatcherTouchModeChangedTests, NonWindowOwnerMayChangeTouchModeOnPermissionGranted) {
12137 const WindowInfo& windowInfo = *mWindow->getInfo();
Prabir Pradhanaeebeb42023-06-13 19:53:03 +000012138 gui::Pid ownerPid = windowInfo.ownerPid;
Prabir Pradhan8a5c41d2023-06-08 19:13:46 +000012139 gui::Uid ownerUid = windowInfo.ownerUid;
Prabir Pradhanaeebeb42023-06-13 19:53:03 +000012140 mWindow->setOwnerInfo(gui::Pid::INVALID, gui::Uid::INVALID);
Antonio Kantek15beb512022-06-13 22:35:41 +000012141 changeAndVerifyTouchModeInMainDisplayOnly(!InputDispatcher::kDefaultInTouchMode, ownerPid,
Harry Cutts33476232023-01-30 19:57:29 +000012142 ownerUid, /*hasPermission=*/true);
Antonio Kantek26defcf2022-02-08 01:12:27 +000012143}
12144
Antonio Kantekf16f2832021-09-28 04:39:20 +000012145TEST_F(InputDispatcherTouchModeChangedTests, EventIsNotGeneratedIfNotChangingTouchMode) {
Antonio Kantekea47acb2021-12-23 12:41:25 -080012146 const WindowInfo& windowInfo = *mWindow->getInfo();
Antonio Kantek26defcf2022-02-08 01:12:27 +000012147 ASSERT_FALSE(mDispatcher->setInTouchMode(InputDispatcher::kDefaultInTouchMode,
12148 windowInfo.ownerPid, windowInfo.ownerUid,
Harry Cutts33476232023-01-30 19:57:29 +000012149 /*hasPermission=*/true, ADISPLAY_ID_DEFAULT));
Antonio Kantekf16f2832021-09-28 04:39:20 +000012150 mWindow->assertNoEvents();
12151 mSecondWindow->assertNoEvents();
12152}
12153
Antonio Kantek15beb512022-06-13 22:35:41 +000012154TEST_F(InputDispatcherTouchModeChangedTests, ChangeTouchOnSecondaryDisplayOnly) {
12155 const WindowInfo& windowInfo = *mThirdWindow->getInfo();
12156 ASSERT_TRUE(mDispatcher->setInTouchMode(!InputDispatcher::kDefaultInTouchMode,
12157 windowInfo.ownerPid, windowInfo.ownerUid,
Harry Cutts33476232023-01-30 19:57:29 +000012158 /*hasPermission=*/true, SECOND_DISPLAY_ID));
Antonio Kantek15beb512022-06-13 22:35:41 +000012159 mWindow->assertNoEvents();
12160 mSecondWindow->assertNoEvents();
12161 mThirdWindow->consumeTouchModeEvent(!InputDispatcher::kDefaultInTouchMode);
12162}
12163
Antonio Kantek48710e42022-03-24 14:19:30 -070012164TEST_F(InputDispatcherTouchModeChangedTests, CanChangeTouchModeWhenOwningLastInteractedWindow) {
12165 // Interact with the window first.
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070012166 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
12167 injectKeyDown(*mDispatcher, ADISPLAY_ID_DEFAULT))
Antonio Kantek48710e42022-03-24 14:19:30 -070012168 << "Inject key event should return InputEventInjectionResult::SUCCEEDED";
12169 mWindow->consumeKeyDown(ADISPLAY_ID_DEFAULT);
12170
12171 // Then remove focus.
12172 mWindow->setFocusable(false);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070012173 mDispatcher->onWindowInfosChanged({{*mWindow->getInfo()}, {}, 0, 0});
Antonio Kantek48710e42022-03-24 14:19:30 -070012174
12175 // Assert that caller can switch touch mode by owning one of the last interacted window.
12176 const WindowInfo& windowInfo = *mWindow->getInfo();
12177 ASSERT_TRUE(mDispatcher->setInTouchMode(!InputDispatcher::kDefaultInTouchMode,
12178 windowInfo.ownerPid, windowInfo.ownerUid,
Harry Cutts33476232023-01-30 19:57:29 +000012179 /*hasPermission=*/false, ADISPLAY_ID_DEFAULT));
Antonio Kantek48710e42022-03-24 14:19:30 -070012180}
12181
Prabir Pradhan07e05b62021-11-19 03:57:24 -080012182class InputDispatcherSpyWindowTest : public InputDispatcherTest {
12183public:
Prabir Pradhan4d5c52f2022-01-31 08:52:10 -080012184 sp<FakeWindowHandle> createSpy() {
Prabir Pradhan07e05b62021-11-19 03:57:24 -080012185 std::shared_ptr<FakeApplicationHandle> application =
12186 std::make_shared<FakeApplicationHandle>();
12187 std::string name = "Fake Spy ";
12188 name += std::to_string(mSpyCount++);
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -070012189 sp<FakeWindowHandle> spy = sp<FakeWindowHandle>::make(application, mDispatcher,
12190 name.c_str(), ADISPLAY_ID_DEFAULT);
Prabir Pradhan51e7db02022-02-07 06:02:57 -080012191 spy->setSpy(true);
Prabir Pradhan5c85e052021-12-22 02:27:12 -080012192 spy->setTrustedOverlay(true);
Prabir Pradhan07e05b62021-11-19 03:57:24 -080012193 return spy;
12194 }
12195
12196 sp<FakeWindowHandle> createForeground() {
12197 std::shared_ptr<FakeApplicationHandle> application =
12198 std::make_shared<FakeApplicationHandle>();
12199 sp<FakeWindowHandle> window =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -070012200 sp<FakeWindowHandle>::make(application, mDispatcher, "Fake Window",
12201 ADISPLAY_ID_DEFAULT);
Prabir Pradhan1376fcd2022-01-21 09:56:35 -080012202 window->setFocusable(true);
Prabir Pradhan07e05b62021-11-19 03:57:24 -080012203 return window;
12204 }
12205
12206private:
12207 int mSpyCount{0};
12208};
12209
Prabir Pradhana3ab87a2022-01-27 10:00:21 -080012210using InputDispatcherSpyWindowDeathTest = InputDispatcherSpyWindowTest;
Prabir Pradhan07e05b62021-11-19 03:57:24 -080012211/**
Prabir Pradhan5c85e052021-12-22 02:27:12 -080012212 * Adding a spy window that is not a trusted overlay causes Dispatcher to abort.
12213 */
Prabir Pradhana3ab87a2022-01-27 10:00:21 -080012214TEST_F(InputDispatcherSpyWindowDeathTest, UntrustedSpy_AbortsDispatcher) {
Siarhei Vishniakou21f77bd2023-07-18 17:51:35 -070012215 testing::GTEST_FLAG(death_test_style) = "threadsafe";
Prabir Pradhana3ab87a2022-01-27 10:00:21 -080012216 ScopedSilentDeath _silentDeath;
12217
Prabir Pradhan4d5c52f2022-01-31 08:52:10 -080012218 auto spy = createSpy();
Prabir Pradhan5c85e052021-12-22 02:27:12 -080012219 spy->setTrustedOverlay(false);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070012220 ASSERT_DEATH(mDispatcher->onWindowInfosChanged({{*spy->getInfo()}, {}, 0, 0}),
Prabir Pradhan5c85e052021-12-22 02:27:12 -080012221 ".* not a trusted overlay");
12222}
12223
12224/**
Prabir Pradhan07e05b62021-11-19 03:57:24 -080012225 * Input injection into a display with a spy window but no foreground windows should succeed.
12226 */
12227TEST_F(InputDispatcherSpyWindowTest, NoForegroundWindow) {
Prabir Pradhan4d5c52f2022-01-31 08:52:10 -080012228 auto spy = createSpy();
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070012229 mDispatcher->onWindowInfosChanged({{*spy->getInfo()}, {}, 0, 0});
Prabir Pradhan07e05b62021-11-19 03:57:24 -080012230
12231 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070012232 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT))
Prabir Pradhan07e05b62021-11-19 03:57:24 -080012233 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
12234 spy->consumeMotionDown(ADISPLAY_ID_DEFAULT);
12235}
12236
12237/**
12238 * Verify the order in which different input windows receive events. The touched foreground window
12239 * (if there is one) should always receive the event first. When there are multiple spy windows, the
12240 * spy windows will receive the event according to their Z-order, where the top-most spy window will
12241 * receive events before ones belows it.
12242 *
12243 * Here, we set up a scenario with four windows in the following Z order from the top:
12244 * spy1, spy2, window, spy3.
12245 * We then inject an event and verify that the foreground "window" receives it first, followed by
12246 * "spy1" and "spy2". The "spy3" does not receive the event because it is underneath the foreground
12247 * window.
12248 */
12249TEST_F(InputDispatcherSpyWindowTest, ReceivesInputInOrder) {
12250 auto window = createForeground();
Prabir Pradhan4d5c52f2022-01-31 08:52:10 -080012251 auto spy1 = createSpy();
12252 auto spy2 = createSpy();
12253 auto spy3 = createSpy();
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070012254 mDispatcher->onWindowInfosChanged(
12255 {{*spy1->getInfo(), *spy2->getInfo(), *window->getInfo(), *spy3->getInfo()}, {}, 0, 0});
Prabir Pradhan07e05b62021-11-19 03:57:24 -080012256 const std::vector<sp<FakeWindowHandle>> channels{spy1, spy2, window, spy3};
12257 const size_t numChannels = channels.size();
12258
Michael Wright8e9a8562022-02-09 13:44:29 +000012259 base::unique_fd epollFd(epoll_create1(EPOLL_CLOEXEC));
Prabir Pradhan07e05b62021-11-19 03:57:24 -080012260 if (!epollFd.ok()) {
12261 FAIL() << "Failed to create epoll fd";
12262 }
12263
12264 for (size_t i = 0; i < numChannels; i++) {
12265 struct epoll_event event = {.events = EPOLLIN, .data.u64 = i};
12266 if (epoll_ctl(epollFd.get(), EPOLL_CTL_ADD, channels[i]->getChannelFd(), &event) < 0) {
12267 FAIL() << "Failed to add fd to epoll";
12268 }
12269 }
12270
12271 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070012272 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT))
Prabir Pradhan07e05b62021-11-19 03:57:24 -080012273 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
12274
12275 std::vector<size_t> eventOrder;
12276 std::vector<struct epoll_event> events(numChannels);
12277 for (;;) {
12278 const int nFds = epoll_wait(epollFd.get(), events.data(), static_cast<int>(numChannels),
12279 (100ms).count());
12280 if (nFds < 0) {
12281 FAIL() << "Failed to call epoll_wait";
12282 }
12283 if (nFds == 0) {
12284 break; // epoll_wait timed out
12285 }
12286 for (int i = 0; i < nFds; i++) {
Colin Cross5b799302022-10-18 21:52:41 -070012287 ASSERT_EQ(static_cast<uint32_t>(EPOLLIN), events[i].events);
Siarhei Vishniakou31977182022-09-30 08:51:23 -070012288 eventOrder.push_back(static_cast<size_t>(events[i].data.u64));
Prabir Pradhan07e05b62021-11-19 03:57:24 -080012289 channels[i]->consumeMotionDown();
12290 }
12291 }
12292
12293 // Verify the order in which the events were received.
12294 EXPECT_EQ(3u, eventOrder.size());
12295 EXPECT_EQ(2u, eventOrder[0]); // index 2: window
12296 EXPECT_EQ(0u, eventOrder[1]); // index 0: spy1
12297 EXPECT_EQ(1u, eventOrder[2]); // index 1: spy2
12298}
12299
12300/**
12301 * A spy window using the NOT_TOUCHABLE flag does not receive events.
12302 */
12303TEST_F(InputDispatcherSpyWindowTest, NotTouchable) {
12304 auto window = createForeground();
Prabir Pradhan4d5c52f2022-01-31 08:52:10 -080012305 auto spy = createSpy();
12306 spy->setTouchable(false);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070012307 mDispatcher->onWindowInfosChanged({{*spy->getInfo(), *window->getInfo()}, {}, 0, 0});
Prabir Pradhan07e05b62021-11-19 03:57:24 -080012308
12309 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070012310 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT))
Prabir Pradhan07e05b62021-11-19 03:57:24 -080012311 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
12312 window->consumeMotionDown(ADISPLAY_ID_DEFAULT);
12313 spy->assertNoEvents();
12314}
12315
12316/**
12317 * A spy window will only receive gestures that originate within its touchable region. Gestures that
12318 * have their ACTION_DOWN outside of the touchable region of the spy window will not be dispatched
12319 * to the window.
12320 */
12321TEST_F(InputDispatcherSpyWindowTest, TouchableRegion) {
12322 auto window = createForeground();
Prabir Pradhan4d5c52f2022-01-31 08:52:10 -080012323 auto spy = createSpy();
Prabir Pradhan07e05b62021-11-19 03:57:24 -080012324 spy->setTouchableRegion(Region{{0, 0, 20, 20}});
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070012325 mDispatcher->onWindowInfosChanged({{*spy->getInfo(), *window->getInfo()}, {}, 0, 0});
Prabir Pradhan07e05b62021-11-19 03:57:24 -080012326
12327 // Inject an event outside the spy window's touchable region.
12328 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070012329 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT))
Prabir Pradhan07e05b62021-11-19 03:57:24 -080012330 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
12331 window->consumeMotionDown();
12332 spy->assertNoEvents();
12333 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070012334 injectMotionUp(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT))
Prabir Pradhan07e05b62021-11-19 03:57:24 -080012335 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
12336 window->consumeMotionUp();
12337 spy->assertNoEvents();
12338
12339 // Inject an event inside the spy window's touchable region.
12340 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070012341 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
Prabir Pradhan07e05b62021-11-19 03:57:24 -080012342 {5, 10}))
12343 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
12344 window->consumeMotionDown();
12345 spy->consumeMotionDown();
12346}
12347
12348/**
Prabir Pradhan07e05b62021-11-19 03:57:24 -080012349 * A spy window can listen for touches outside its touchable region using the WATCH_OUTSIDE_TOUCHES
Prabir Pradhandfabf8a2022-01-21 08:19:30 -080012350 * flag, but it will get zero-ed out coordinates if the foreground has a different owner.
Prabir Pradhan07e05b62021-11-19 03:57:24 -080012351 */
12352TEST_F(InputDispatcherSpyWindowTest, WatchOutsideTouches) {
12353 auto window = createForeground();
Prabir Pradhanaeebeb42023-06-13 19:53:03 +000012354 window->setOwnerInfo(gui::Pid{12}, gui::Uid{34});
Prabir Pradhan4d5c52f2022-01-31 08:52:10 -080012355 auto spy = createSpy();
12356 spy->setWatchOutsideTouch(true);
Prabir Pradhanaeebeb42023-06-13 19:53:03 +000012357 spy->setOwnerInfo(gui::Pid{56}, gui::Uid{78});
Prabir Pradhan07e05b62021-11-19 03:57:24 -080012358 spy->setFrame(Rect{0, 0, 20, 20});
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070012359 mDispatcher->onWindowInfosChanged({{*spy->getInfo(), *window->getInfo()}, {}, 0, 0});
Prabir Pradhan07e05b62021-11-19 03:57:24 -080012360
12361 // Inject an event outside the spy window's frame and touchable region.
12362 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070012363 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
Prabir Pradhandfabf8a2022-01-21 08:19:30 -080012364 {100, 200}))
Prabir Pradhan07e05b62021-11-19 03:57:24 -080012365 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
12366 window->consumeMotionDown();
Prabir Pradhandfabf8a2022-01-21 08:19:30 -080012367 spy->consumeMotionOutsideWithZeroedCoords();
Prabir Pradhan07e05b62021-11-19 03:57:24 -080012368}
12369
12370/**
Prabir Pradhan07e05b62021-11-19 03:57:24 -080012371 * Even when a spy window spans over multiple foreground windows, the spy should receive all
12372 * pointers that are down within its bounds.
12373 */
12374TEST_F(InputDispatcherSpyWindowTest, ReceivesMultiplePointers) {
12375 auto windowLeft = createForeground();
12376 windowLeft->setFrame({0, 0, 100, 200});
12377 auto windowRight = createForeground();
12378 windowRight->setFrame({100, 0, 200, 200});
Prabir Pradhan4d5c52f2022-01-31 08:52:10 -080012379 auto spy = createSpy();
Prabir Pradhan07e05b62021-11-19 03:57:24 -080012380 spy->setFrame({0, 0, 200, 200});
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070012381 mDispatcher->onWindowInfosChanged(
12382 {{*spy->getInfo(), *windowLeft->getInfo(), *windowRight->getInfo()}, {}, 0, 0});
Prabir Pradhan07e05b62021-11-19 03:57:24 -080012383
12384 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070012385 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
Prabir Pradhan07e05b62021-11-19 03:57:24 -080012386 {50, 50}))
12387 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
12388 windowLeft->consumeMotionDown();
12389 spy->consumeMotionDown();
12390
12391 const MotionEvent secondFingerDownEvent =
Siarhei Vishniakoua16e3a22022-03-02 15:26:40 -080012392 MotionEventBuilder(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
Prabir Pradhan07e05b62021-11-19 03:57:24 -080012393 .eventTime(systemTime(SYSTEM_TIME_MONOTONIC))
Siarhei Vishniakou6d73f832022-07-21 17:27:03 -070012394 .pointer(PointerBuilder(/*id=*/0, ToolType::FINGER).x(50).y(50))
12395 .pointer(PointerBuilder(/*id=*/1, ToolType::FINGER).x(150).y(50))
Prabir Pradhan07e05b62021-11-19 03:57:24 -080012396 .build();
12397 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070012398 injectMotionEvent(*mDispatcher, secondFingerDownEvent, INJECT_EVENT_TIMEOUT,
Prabir Pradhan07e05b62021-11-19 03:57:24 -080012399 InputEventInjectionSync::WAIT_FOR_RESULT))
12400 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
12401 windowRight->consumeMotionDown();
Harry Cutts33476232023-01-30 19:57:29 +000012402 spy->consumeMotionPointerDown(/*pointerIndex=*/1);
Prabir Pradhan07e05b62021-11-19 03:57:24 -080012403}
12404
12405/**
12406 * When the first pointer lands outside the spy window and the second pointer lands inside it, the
12407 * the spy should receive the second pointer with ACTION_DOWN.
12408 */
12409TEST_F(InputDispatcherSpyWindowTest, ReceivesSecondPointerAsDown) {
12410 auto window = createForeground();
12411 window->setFrame({0, 0, 200, 200});
Prabir Pradhan4d5c52f2022-01-31 08:52:10 -080012412 auto spyRight = createSpy();
Prabir Pradhan07e05b62021-11-19 03:57:24 -080012413 spyRight->setFrame({100, 0, 200, 200});
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070012414 mDispatcher->onWindowInfosChanged({{*spyRight->getInfo(), *window->getInfo()}, {}, 0, 0});
Prabir Pradhan07e05b62021-11-19 03:57:24 -080012415
12416 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070012417 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
Prabir Pradhan07e05b62021-11-19 03:57:24 -080012418 {50, 50}))
12419 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
12420 window->consumeMotionDown();
12421 spyRight->assertNoEvents();
12422
12423 const MotionEvent secondFingerDownEvent =
Siarhei Vishniakoua16e3a22022-03-02 15:26:40 -080012424 MotionEventBuilder(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
Prabir Pradhan07e05b62021-11-19 03:57:24 -080012425 .eventTime(systemTime(SYSTEM_TIME_MONOTONIC))
Siarhei Vishniakou6d73f832022-07-21 17:27:03 -070012426 .pointer(PointerBuilder(/*id=*/0, ToolType::FINGER).x(50).y(50))
12427 .pointer(PointerBuilder(/*id=*/1, ToolType::FINGER).x(150).y(50))
Prabir Pradhan07e05b62021-11-19 03:57:24 -080012428 .build();
12429 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070012430 injectMotionEvent(*mDispatcher, secondFingerDownEvent, INJECT_EVENT_TIMEOUT,
Prabir Pradhan07e05b62021-11-19 03:57:24 -080012431 InputEventInjectionSync::WAIT_FOR_RESULT))
12432 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
Harry Cutts33476232023-01-30 19:57:29 +000012433 window->consumeMotionPointerDown(/*pointerIndex=*/1);
Prabir Pradhan07e05b62021-11-19 03:57:24 -080012434 spyRight->consumeMotionDown();
12435}
12436
Prabir Pradhan1376fcd2022-01-21 09:56:35 -080012437/**
12438 * The spy window should not be able to affect whether or not touches are split. Only the foreground
12439 * windows should be allowed to control split touch.
12440 */
12441TEST_F(InputDispatcherSpyWindowTest, SplitIfNoForegroundWindowTouched) {
Prabir Pradhan76bdecb2022-01-31 11:14:15 -080012442 // This spy window prevents touch splitting. However, we still expect to split touches
Prabir Pradhan1376fcd2022-01-21 09:56:35 -080012443 // because a foreground window has not disabled splitting.
Prabir Pradhan4d5c52f2022-01-31 08:52:10 -080012444 auto spy = createSpy();
Prabir Pradhan76bdecb2022-01-31 11:14:15 -080012445 spy->setPreventSplitting(true);
Prabir Pradhan1376fcd2022-01-21 09:56:35 -080012446
Prabir Pradhan1376fcd2022-01-21 09:56:35 -080012447 auto window = createForeground();
12448 window->setFrame(Rect(0, 0, 100, 100));
Prabir Pradhan1376fcd2022-01-21 09:56:35 -080012449
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070012450 mDispatcher->onWindowInfosChanged({{*spy->getInfo(), *window->getInfo()}, {}, 0, 0});
Prabir Pradhan1376fcd2022-01-21 09:56:35 -080012451
12452 // First finger down, no window touched.
12453 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070012454 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
Prabir Pradhan1376fcd2022-01-21 09:56:35 -080012455 {100, 200}))
12456 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
12457 spy->consumeMotionDown(ADISPLAY_ID_DEFAULT);
12458 window->assertNoEvents();
12459
12460 // Second finger down on window, the window should receive touch down.
12461 const MotionEvent secondFingerDownEvent =
Siarhei Vishniakoua16e3a22022-03-02 15:26:40 -080012462 MotionEventBuilder(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
Prabir Pradhan1376fcd2022-01-21 09:56:35 -080012463 .displayId(ADISPLAY_ID_DEFAULT)
12464 .eventTime(systemTime(SYSTEM_TIME_MONOTONIC))
Siarhei Vishniakou6d73f832022-07-21 17:27:03 -070012465 .pointer(PointerBuilder(/*id=*/0, ToolType::FINGER).x(100).y(200))
12466 .pointer(PointerBuilder(/*id=*/1, ToolType::FINGER).x(50).y(50))
Prabir Pradhan1376fcd2022-01-21 09:56:35 -080012467 .build();
12468 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070012469 injectMotionEvent(*mDispatcher, secondFingerDownEvent, INJECT_EVENT_TIMEOUT,
Prabir Pradhan1376fcd2022-01-21 09:56:35 -080012470 InputEventInjectionSync::WAIT_FOR_RESULT))
12471 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
12472
12473 window->consumeMotionDown(ADISPLAY_ID_DEFAULT);
Harry Cutts33476232023-01-30 19:57:29 +000012474 spy->consumeMotionPointerDown(/*pointerIndex=*/1);
Prabir Pradhan1376fcd2022-01-21 09:56:35 -080012475}
12476
12477/**
12478 * A spy window will usually be implemented as an un-focusable window. Verify that these windows
12479 * do not receive key events.
12480 */
12481TEST_F(InputDispatcherSpyWindowTest, UnfocusableSpyDoesNotReceiveKeyEvents) {
Prabir Pradhan4d5c52f2022-01-31 08:52:10 -080012482 auto spy = createSpy();
Prabir Pradhan1376fcd2022-01-21 09:56:35 -080012483 spy->setFocusable(false);
12484
12485 auto window = createForeground();
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070012486 mDispatcher->onWindowInfosChanged({{*spy->getInfo(), *window->getInfo()}, {}, 0, 0});
Prabir Pradhan1376fcd2022-01-21 09:56:35 -080012487 setFocusedWindow(window);
12488 window->consumeFocusEvent(true);
12489
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070012490 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectKeyDown(*mDispatcher))
Prabir Pradhan1376fcd2022-01-21 09:56:35 -080012491 << "Inject key event should return InputEventInjectionResult::SUCCEEDED";
12492 window->consumeKeyDown(ADISPLAY_ID_NONE);
12493
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070012494 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectKeyUp(*mDispatcher))
Prabir Pradhan1376fcd2022-01-21 09:56:35 -080012495 << "Inject key event should return InputEventInjectionResult::SUCCEEDED";
12496 window->consumeKeyUp(ADISPLAY_ID_NONE);
12497
12498 spy->assertNoEvents();
12499}
12500
Vaibhav Devmurariff798f32022-05-09 23:45:04 +000012501using InputDispatcherPilferPointersTest = InputDispatcherSpyWindowTest;
12502
12503/**
12504 * A spy window can pilfer pointers. When this happens, touch gestures used by the spy window that
12505 * are currently sent to any other windows - including other spy windows - will also be cancelled.
12506 */
12507TEST_F(InputDispatcherPilferPointersTest, PilferPointers) {
12508 auto window = createForeground();
12509 auto spy1 = createSpy();
12510 auto spy2 = createSpy();
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070012511 mDispatcher->onWindowInfosChanged(
12512 {{*spy1->getInfo(), *spy2->getInfo(), *window->getInfo()}, {}, 0, 0});
Vaibhav Devmurariff798f32022-05-09 23:45:04 +000012513
12514 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070012515 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT))
Vaibhav Devmurariff798f32022-05-09 23:45:04 +000012516 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
12517 window->consumeMotionDown();
12518 spy1->consumeMotionDown();
12519 spy2->consumeMotionDown();
12520
12521 // Pilfer pointers from the second spy window.
12522 EXPECT_EQ(OK, mDispatcher->pilferPointers(spy2->getToken()));
12523 spy2->assertNoEvents();
12524 spy1->consumeMotionCancel();
12525 window->consumeMotionCancel();
12526
12527 // The rest of the gesture should only be sent to the second spy window.
12528 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070012529 injectMotionEvent(*mDispatcher, AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN,
Vaibhav Devmurariff798f32022-05-09 23:45:04 +000012530 ADISPLAY_ID_DEFAULT))
12531 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
12532 spy2->consumeMotionMove();
12533 spy1->assertNoEvents();
12534 window->assertNoEvents();
12535}
12536
12537/**
12538 * A spy window can pilfer pointers for a gesture even after the foreground window has been removed
12539 * in the middle of the gesture.
12540 */
12541TEST_F(InputDispatcherPilferPointersTest, CanPilferAfterWindowIsRemovedMidStream) {
12542 auto window = createForeground();
12543 auto spy = createSpy();
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070012544 mDispatcher->onWindowInfosChanged({{*spy->getInfo(), *window->getInfo()}, {}, 0, 0});
Vaibhav Devmurariff798f32022-05-09 23:45:04 +000012545
12546 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070012547 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT))
Vaibhav Devmurariff798f32022-05-09 23:45:04 +000012548 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
12549 window->consumeMotionDown(ADISPLAY_ID_DEFAULT);
12550 spy->consumeMotionDown(ADISPLAY_ID_DEFAULT);
12551
12552 window->releaseChannel();
12553
12554 EXPECT_EQ(OK, mDispatcher->pilferPointers(spy->getToken()));
12555
12556 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070012557 injectMotionUp(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT))
Vaibhav Devmurariff798f32022-05-09 23:45:04 +000012558 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
12559 spy->consumeMotionUp(ADISPLAY_ID_DEFAULT);
12560}
12561
12562/**
12563 * After a spy window pilfers pointers, new pointers that go down in its bounds should be sent to
12564 * the spy, but not to any other windows.
12565 */
12566TEST_F(InputDispatcherPilferPointersTest, ContinuesToReceiveGestureAfterPilfer) {
12567 auto spy = createSpy();
12568 auto window = createForeground();
12569
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070012570 mDispatcher->onWindowInfosChanged({{*spy->getInfo(), *window->getInfo()}, {}, 0, 0});
Vaibhav Devmurariff798f32022-05-09 23:45:04 +000012571
12572 // First finger down on the window and the spy.
12573 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070012574 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
Vaibhav Devmurariff798f32022-05-09 23:45:04 +000012575 {100, 200}))
12576 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
12577 spy->consumeMotionDown();
12578 window->consumeMotionDown();
12579
12580 // Spy window pilfers the pointers.
12581 EXPECT_EQ(OK, mDispatcher->pilferPointers(spy->getToken()));
12582 window->consumeMotionCancel();
12583
12584 // Second finger down on the window and spy, but the window should not receive the pointer down.
12585 const MotionEvent secondFingerDownEvent =
12586 MotionEventBuilder(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
12587 .displayId(ADISPLAY_ID_DEFAULT)
12588 .eventTime(systemTime(SYSTEM_TIME_MONOTONIC))
Siarhei Vishniakou6d73f832022-07-21 17:27:03 -070012589 .pointer(PointerBuilder(/*id=*/0, ToolType::FINGER).x(100).y(200))
12590 .pointer(PointerBuilder(/*id=*/1, ToolType::FINGER).x(50).y(50))
Vaibhav Devmurariff798f32022-05-09 23:45:04 +000012591 .build();
12592 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070012593 injectMotionEvent(*mDispatcher, secondFingerDownEvent, INJECT_EVENT_TIMEOUT,
Vaibhav Devmurariff798f32022-05-09 23:45:04 +000012594 InputEventInjectionSync::WAIT_FOR_RESULT))
12595 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
12596
Harry Cutts33476232023-01-30 19:57:29 +000012597 spy->consumeMotionPointerDown(/*pointerIndex=*/1);
Vaibhav Devmurariff798f32022-05-09 23:45:04 +000012598
12599 // Third finger goes down outside all windows, so injection should fail.
12600 const MotionEvent thirdFingerDownEvent =
12601 MotionEventBuilder(POINTER_2_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
12602 .displayId(ADISPLAY_ID_DEFAULT)
12603 .eventTime(systemTime(SYSTEM_TIME_MONOTONIC))
Siarhei Vishniakou6d73f832022-07-21 17:27:03 -070012604 .pointer(PointerBuilder(/*id=*/0, ToolType::FINGER).x(100).y(200))
12605 .pointer(PointerBuilder(/*id=*/1, ToolType::FINGER).x(50).y(50))
12606 .pointer(PointerBuilder(/*id=*/2, ToolType::FINGER).x(-5).y(-5))
Vaibhav Devmurariff798f32022-05-09 23:45:04 +000012607 .build();
12608 ASSERT_EQ(InputEventInjectionResult::FAILED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070012609 injectMotionEvent(*mDispatcher, thirdFingerDownEvent, INJECT_EVENT_TIMEOUT,
Vaibhav Devmurariff798f32022-05-09 23:45:04 +000012610 InputEventInjectionSync::WAIT_FOR_RESULT))
Siarhei Vishniakou1ae72f12023-01-29 12:55:30 -080012611 << "Inject motion event should return InputEventInjectionResult::FAILED";
Vaibhav Devmurariff798f32022-05-09 23:45:04 +000012612
12613 spy->assertNoEvents();
12614 window->assertNoEvents();
12615}
12616
12617/**
12618 * After a spy window pilfers pointers, only the pointers used by the spy should be canceled
12619 */
12620TEST_F(InputDispatcherPilferPointersTest, PartiallyPilferRequiredPointers) {
12621 auto spy = createSpy();
12622 spy->setFrame(Rect(0, 0, 100, 100));
12623 auto window = createForeground();
12624 window->setFrame(Rect(0, 0, 200, 200));
12625
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070012626 mDispatcher->onWindowInfosChanged({{*spy->getInfo(), *window->getInfo()}, {}, 0, 0});
Vaibhav Devmurariff798f32022-05-09 23:45:04 +000012627
12628 // First finger down on the window only
12629 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070012630 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
Vaibhav Devmurariff798f32022-05-09 23:45:04 +000012631 {150, 150}))
12632 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
12633 window->consumeMotionDown();
12634
12635 // Second finger down on the spy and window
12636 const MotionEvent secondFingerDownEvent =
12637 MotionEventBuilder(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
12638 .displayId(ADISPLAY_ID_DEFAULT)
12639 .eventTime(systemTime(SYSTEM_TIME_MONOTONIC))
Siarhei Vishniakou6d73f832022-07-21 17:27:03 -070012640 .pointer(PointerBuilder(/*id=*/0, ToolType::FINGER).x(150).y(150))
12641 .pointer(PointerBuilder(/*id=*/1, ToolType::FINGER).x(10).y(10))
Vaibhav Devmurariff798f32022-05-09 23:45:04 +000012642 .build();
12643 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070012644 injectMotionEvent(*mDispatcher, secondFingerDownEvent, INJECT_EVENT_TIMEOUT,
Vaibhav Devmurariff798f32022-05-09 23:45:04 +000012645 InputEventInjectionSync::WAIT_FOR_RESULT))
12646 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
12647 spy->consumeMotionDown();
12648 window->consumeMotionPointerDown(1);
12649
12650 // Third finger down on the spy and window
12651 const MotionEvent thirdFingerDownEvent =
12652 MotionEventBuilder(POINTER_2_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
12653 .displayId(ADISPLAY_ID_DEFAULT)
12654 .eventTime(systemTime(SYSTEM_TIME_MONOTONIC))
Siarhei Vishniakou6d73f832022-07-21 17:27:03 -070012655 .pointer(PointerBuilder(/*id=*/0, ToolType::FINGER).x(150).y(150))
12656 .pointer(PointerBuilder(/*id=*/1, ToolType::FINGER).x(10).y(10))
12657 .pointer(PointerBuilder(/*id=*/2, ToolType::FINGER).x(50).y(50))
Vaibhav Devmurariff798f32022-05-09 23:45:04 +000012658 .build();
12659 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070012660 injectMotionEvent(*mDispatcher, thirdFingerDownEvent, INJECT_EVENT_TIMEOUT,
Vaibhav Devmurariff798f32022-05-09 23:45:04 +000012661 InputEventInjectionSync::WAIT_FOR_RESULT))
12662 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
12663 spy->consumeMotionPointerDown(1);
12664 window->consumeMotionPointerDown(2);
12665
12666 // Spy window pilfers the pointers.
12667 EXPECT_EQ(OK, mDispatcher->pilferPointers(spy->getToken()));
Harry Cutts101ee9b2023-07-06 18:04:14 +000012668 window->consumeMotionPointerUp(/*idx=*/2, ADISPLAY_ID_DEFAULT, AMOTION_EVENT_FLAG_CANCELED);
12669 window->consumeMotionPointerUp(/*idx=*/1, ADISPLAY_ID_DEFAULT, AMOTION_EVENT_FLAG_CANCELED);
Vaibhav Devmurariff798f32022-05-09 23:45:04 +000012670
12671 spy->assertNoEvents();
12672 window->assertNoEvents();
12673}
12674
12675/**
12676 * After a spy window pilfers pointers, all pilfered pointers that have already been dispatched to
12677 * other windows should be canceled. If this results in the cancellation of all pointers for some
12678 * window, then that window should receive ACTION_CANCEL.
12679 */
12680TEST_F(InputDispatcherPilferPointersTest, PilferAllRequiredPointers) {
12681 auto spy = createSpy();
12682 spy->setFrame(Rect(0, 0, 100, 100));
12683 auto window = createForeground();
12684 window->setFrame(Rect(0, 0, 200, 200));
12685
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070012686 mDispatcher->onWindowInfosChanged({{*spy->getInfo(), *window->getInfo()}, {}, 0, 0});
Vaibhav Devmurariff798f32022-05-09 23:45:04 +000012687
12688 // First finger down on both spy and window
12689 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070012690 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
Vaibhav Devmurariff798f32022-05-09 23:45:04 +000012691 {10, 10}))
12692 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
12693 window->consumeMotionDown();
12694 spy->consumeMotionDown();
12695
12696 // Second finger down on the spy and window
12697 const MotionEvent secondFingerDownEvent =
12698 MotionEventBuilder(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
12699 .displayId(ADISPLAY_ID_DEFAULT)
12700 .eventTime(systemTime(SYSTEM_TIME_MONOTONIC))
Siarhei Vishniakou6d73f832022-07-21 17:27:03 -070012701 .pointer(PointerBuilder(/*id=*/0, ToolType::FINGER).x(10).y(10))
12702 .pointer(PointerBuilder(/*id=*/1, ToolType::FINGER).x(50).y(50))
Vaibhav Devmurariff798f32022-05-09 23:45:04 +000012703 .build();
12704 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070012705 injectMotionEvent(*mDispatcher, secondFingerDownEvent, INJECT_EVENT_TIMEOUT,
Vaibhav Devmurariff798f32022-05-09 23:45:04 +000012706 InputEventInjectionSync::WAIT_FOR_RESULT))
12707 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
12708 spy->consumeMotionPointerDown(1);
12709 window->consumeMotionPointerDown(1);
12710
12711 // Spy window pilfers the pointers.
12712 EXPECT_EQ(OK, mDispatcher->pilferPointers(spy->getToken()));
12713 window->consumeMotionCancel();
12714
12715 spy->assertNoEvents();
12716 window->assertNoEvents();
12717}
12718
12719/**
12720 * After a spy window pilfers pointers, new pointers that are not touching the spy window can still
12721 * be sent to other windows
12722 */
12723TEST_F(InputDispatcherPilferPointersTest, CanReceivePointersAfterPilfer) {
12724 auto spy = createSpy();
12725 spy->setFrame(Rect(0, 0, 100, 100));
12726 auto window = createForeground();
12727 window->setFrame(Rect(0, 0, 200, 200));
12728
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070012729 mDispatcher->onWindowInfosChanged({{*spy->getInfo(), *window->getInfo()}, {}, 0, 0});
Vaibhav Devmurariff798f32022-05-09 23:45:04 +000012730
12731 // First finger down on both window and spy
12732 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070012733 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
Vaibhav Devmurariff798f32022-05-09 23:45:04 +000012734 {10, 10}))
12735 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
12736 window->consumeMotionDown();
12737 spy->consumeMotionDown();
12738
12739 // Spy window pilfers the pointers.
12740 EXPECT_EQ(OK, mDispatcher->pilferPointers(spy->getToken()));
12741 window->consumeMotionCancel();
12742
12743 // Second finger down on the window only
12744 const MotionEvent secondFingerDownEvent =
12745 MotionEventBuilder(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
12746 .displayId(ADISPLAY_ID_DEFAULT)
12747 .eventTime(systemTime(SYSTEM_TIME_MONOTONIC))
Siarhei Vishniakou6d73f832022-07-21 17:27:03 -070012748 .pointer(PointerBuilder(/*id=*/0, ToolType::FINGER).x(10).y(10))
12749 .pointer(PointerBuilder(/*id=*/1, ToolType::FINGER).x(150).y(150))
Vaibhav Devmurariff798f32022-05-09 23:45:04 +000012750 .build();
12751 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070012752 injectMotionEvent(*mDispatcher, secondFingerDownEvent, INJECT_EVENT_TIMEOUT,
Vaibhav Devmurariff798f32022-05-09 23:45:04 +000012753 InputEventInjectionSync::WAIT_FOR_RESULT))
12754 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
12755 window->consumeMotionDown();
12756 window->assertNoEvents();
12757
12758 // TODO(b/232530217): do not send the unnecessary MOVE event and delete the next line
12759 spy->consumeMotionMove();
12760 spy->assertNoEvents();
12761}
12762
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -070012763/**
12764 * A window on the left and a window on the right. Also, a spy window that's above all of the
12765 * windows, and spanning both left and right windows.
12766 * Send simultaneous motion streams from two different devices, one to the left window, and another
12767 * to the right window.
12768 * Pilfer from spy window.
12769 * Check that the pilfering only affects the pointers that are actually being received by the spy.
12770 */
Siarhei Vishniakoued89cbb2023-10-13 10:42:44 -070012771TEST_F(InputDispatcherPilferPointersTest, MultiDevicePilfer_legacy) {
12772 SCOPED_FLAG_OVERRIDE(enable_multi_device_same_window_stream, false);
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -070012773 sp<FakeWindowHandle> spy = createSpy();
12774 spy->setFrame(Rect(0, 0, 200, 200));
12775 sp<FakeWindowHandle> leftWindow = createForeground();
12776 leftWindow->setFrame(Rect(0, 0, 100, 100));
12777
12778 sp<FakeWindowHandle> rightWindow = createForeground();
12779 rightWindow->setFrame(Rect(100, 0, 200, 100));
12780
12781 constexpr int32_t stylusDeviceId = 1;
12782 constexpr int32_t touchDeviceId = 2;
12783
12784 mDispatcher->onWindowInfosChanged(
12785 {{*spy->getInfo(), *leftWindow->getInfo(), *rightWindow->getInfo()}, {}, 0, 0});
12786
12787 // Stylus down on left window and spy
12788 mDispatcher->notifyMotion(MotionArgsBuilder(AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_STYLUS)
12789 .deviceId(stylusDeviceId)
12790 .pointer(PointerBuilder(0, ToolType::STYLUS).x(50).y(50))
12791 .build());
12792 leftWindow->consumeMotionEvent(
12793 AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(stylusDeviceId)));
12794 spy->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(stylusDeviceId)));
12795
12796 // Finger down on right window and spy - but spy already has stylus
12797 mDispatcher->notifyMotion(
12798 MotionArgsBuilder(AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
12799 .deviceId(touchDeviceId)
12800 .pointer(PointerBuilder(0, ToolType::FINGER).x(150).y(50))
12801 .build());
12802 rightWindow->consumeMotionEvent(
12803 AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(touchDeviceId)));
Siarhei Vishniakou2899c552023-07-10 18:20:46 -070012804 spy->assertNoEvents();
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -070012805
12806 // Act: pilfer from spy. Spy is currently receiving touch events.
12807 EXPECT_EQ(OK, mDispatcher->pilferPointers(spy->getToken()));
Siarhei Vishniakou2899c552023-07-10 18:20:46 -070012808 leftWindow->consumeMotionEvent(
12809 AllOf(WithMotionAction(ACTION_CANCEL), WithDeviceId(stylusDeviceId)));
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -070012810 rightWindow->consumeMotionEvent(
12811 AllOf(WithMotionAction(ACTION_CANCEL), WithDeviceId(touchDeviceId)));
12812
12813 // Continue movements from both stylus and touch. Touch will be delivered to spy, but not stylus
12814 mDispatcher->notifyMotion(MotionArgsBuilder(AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_STYLUS)
12815 .deviceId(stylusDeviceId)
12816 .pointer(PointerBuilder(0, ToolType::STYLUS).x(51).y(52))
12817 .build());
12818 mDispatcher->notifyMotion(
12819 MotionArgsBuilder(AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN)
12820 .deviceId(touchDeviceId)
12821 .pointer(PointerBuilder(0, ToolType::FINGER).x(151).y(52))
12822 .build());
Siarhei Vishniakou2899c552023-07-10 18:20:46 -070012823 spy->consumeMotionEvent(AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(stylusDeviceId)));
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -070012824
12825 spy->assertNoEvents();
12826 leftWindow->assertNoEvents();
12827 rightWindow->assertNoEvents();
12828}
12829
Siarhei Vishniakoued89cbb2023-10-13 10:42:44 -070012830/**
12831 * A window on the left and a window on the right. Also, a spy window that's above all of the
12832 * windows, and spanning both left and right windows.
12833 * Send simultaneous motion streams from two different devices, one to the left window, and another
12834 * to the right window.
12835 * Pilfer from spy window.
12836 * Check that the pilfering affects all of the pointers that are actually being received by the spy.
12837 * The spy should receive both the touch and the stylus events after pilfer.
12838 */
12839TEST_F(InputDispatcherPilferPointersTest, MultiDevicePilfer) {
12840 SCOPED_FLAG_OVERRIDE(enable_multi_device_same_window_stream, true);
12841 sp<FakeWindowHandle> spy = createSpy();
12842 spy->setFrame(Rect(0, 0, 200, 200));
12843 sp<FakeWindowHandle> leftWindow = createForeground();
12844 leftWindow->setFrame(Rect(0, 0, 100, 100));
12845
12846 sp<FakeWindowHandle> rightWindow = createForeground();
12847 rightWindow->setFrame(Rect(100, 0, 200, 100));
12848
12849 constexpr int32_t stylusDeviceId = 1;
12850 constexpr int32_t touchDeviceId = 2;
12851
12852 mDispatcher->onWindowInfosChanged(
12853 {{*spy->getInfo(), *leftWindow->getInfo(), *rightWindow->getInfo()}, {}, 0, 0});
12854
12855 // Stylus down on left window and spy
12856 mDispatcher->notifyMotion(MotionArgsBuilder(AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_STYLUS)
12857 .deviceId(stylusDeviceId)
12858 .pointer(PointerBuilder(0, ToolType::STYLUS).x(50).y(50))
12859 .build());
12860 leftWindow->consumeMotionEvent(
12861 AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(stylusDeviceId)));
12862 spy->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(stylusDeviceId)));
12863
12864 // Finger down on right window and spy
12865 mDispatcher->notifyMotion(
12866 MotionArgsBuilder(AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
12867 .deviceId(touchDeviceId)
12868 .pointer(PointerBuilder(0, ToolType::FINGER).x(150).y(50))
12869 .build());
12870 rightWindow->consumeMotionEvent(
12871 AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(touchDeviceId)));
12872 spy->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(touchDeviceId)));
12873
12874 // Act: pilfer from spy. Spy is currently receiving touch events.
12875 EXPECT_EQ(OK, mDispatcher->pilferPointers(spy->getToken()));
12876 leftWindow->consumeMotionEvent(
12877 AllOf(WithMotionAction(ACTION_CANCEL), WithDeviceId(stylusDeviceId)));
12878 rightWindow->consumeMotionEvent(
12879 AllOf(WithMotionAction(ACTION_CANCEL), WithDeviceId(touchDeviceId)));
12880
12881 // Continue movements from both stylus and touch. Touch and stylus will be delivered to spy
Siarhei Vishniakou92bca1c2024-04-01 14:06:59 -070012882 // Instead of sending the two MOVE events for each input device together, and then receiving
12883 // them both, process them one at at time. InputConsumer is always in the batching mode, which
12884 // means that the two MOVE events will be initially put into a batch. Once the events are
12885 // batched, the 'consume' call may result in any of the MOVE events to be sent first (depending
12886 // on the implementation of InputConsumer), which would mean that the order of the received
12887 // events could be different depending on whether there are 1 or 2 events pending in the
12888 // InputChannel at the time the test calls 'consume'. To make assertions simpler here, and to
12889 // avoid this confusing behaviour, send and receive each MOVE event separately.
Siarhei Vishniakoued89cbb2023-10-13 10:42:44 -070012890 mDispatcher->notifyMotion(MotionArgsBuilder(AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_STYLUS)
12891 .deviceId(stylusDeviceId)
12892 .pointer(PointerBuilder(0, ToolType::STYLUS).x(51).y(52))
12893 .build());
Siarhei Vishniakou92bca1c2024-04-01 14:06:59 -070012894 spy->consumeMotionEvent(AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(stylusDeviceId)));
Siarhei Vishniakoued89cbb2023-10-13 10:42:44 -070012895 mDispatcher->notifyMotion(
12896 MotionArgsBuilder(AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN)
12897 .deviceId(touchDeviceId)
12898 .pointer(PointerBuilder(0, ToolType::FINGER).x(151).y(52))
12899 .build());
Siarhei Vishniakou92bca1c2024-04-01 14:06:59 -070012900 spy->consumeMotionEvent(AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(touchDeviceId)));
Siarhei Vishniakoued89cbb2023-10-13 10:42:44 -070012901
12902 spy->assertNoEvents();
12903 leftWindow->assertNoEvents();
12904 rightWindow->assertNoEvents();
12905}
12906
Prabir Pradhan9cd9eb62023-11-22 17:58:06 +000012907TEST_F(InputDispatcherPilferPointersTest, NoPilferingWithHoveringPointers) {
12908 auto window = createForeground();
12909 auto spy = createSpy();
12910 mDispatcher->onWindowInfosChanged({{*spy->getInfo(), *window->getInfo()}, {}, 0, 0});
12911
12912 mDispatcher->notifyMotion(
12913 MotionArgsBuilder(ACTION_HOVER_ENTER, AINPUT_SOURCE_MOUSE)
12914 .deviceId(1)
12915 .pointer(PointerBuilder(/*id=*/0, ToolType::MOUSE).x(100).y(200))
12916 .build());
12917 window->consumeMotionEvent(WithMotionAction(ACTION_HOVER_ENTER));
12918 spy->consumeMotionEvent(WithMotionAction(ACTION_HOVER_ENTER));
12919
12920 // Pilfer pointers from the spy window should fail.
12921 EXPECT_NE(OK, mDispatcher->pilferPointers(spy->getToken()));
12922 spy->assertNoEvents();
12923 window->assertNoEvents();
12924}
12925
Prabir Pradhand65552b2021-10-07 11:23:50 -070012926class InputDispatcherStylusInterceptorTest : public InputDispatcherTest {
12927public:
12928 std::pair<sp<FakeWindowHandle>, sp<FakeWindowHandle>> setupStylusOverlayScenario() {
12929 std::shared_ptr<FakeApplicationHandle> overlayApplication =
12930 std::make_shared<FakeApplicationHandle>();
12931 sp<FakeWindowHandle> overlay =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -070012932 sp<FakeWindowHandle>::make(overlayApplication, mDispatcher,
12933 "Stylus interceptor window", ADISPLAY_ID_DEFAULT);
Prabir Pradhand65552b2021-10-07 11:23:50 -070012934 overlay->setFocusable(false);
Prabir Pradhanaeebeb42023-06-13 19:53:03 +000012935 overlay->setOwnerInfo(gui::Pid{111}, gui::Uid{111});
Prabir Pradhan4d5c52f2022-01-31 08:52:10 -080012936 overlay->setTouchable(false);
Prabir Pradhan51e7db02022-02-07 06:02:57 -080012937 overlay->setInterceptsStylus(true);
Prabir Pradhand65552b2021-10-07 11:23:50 -070012938 overlay->setTrustedOverlay(true);
12939
12940 std::shared_ptr<FakeApplicationHandle> application =
12941 std::make_shared<FakeApplicationHandle>();
12942 sp<FakeWindowHandle> window =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -070012943 sp<FakeWindowHandle>::make(application, mDispatcher, "Application window",
12944 ADISPLAY_ID_DEFAULT);
Prabir Pradhand65552b2021-10-07 11:23:50 -070012945 window->setFocusable(true);
Prabir Pradhanaeebeb42023-06-13 19:53:03 +000012946 window->setOwnerInfo(gui::Pid{222}, gui::Uid{222});
Prabir Pradhand65552b2021-10-07 11:23:50 -070012947
12948 mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070012949 mDispatcher->onWindowInfosChanged({{*overlay->getInfo(), *window->getInfo()}, {}, 0, 0});
Prabir Pradhand65552b2021-10-07 11:23:50 -070012950 setFocusedWindow(window);
Harry Cutts33476232023-01-30 19:57:29 +000012951 window->consumeFocusEvent(/*hasFocus=*/true, /*inTouchMode=*/true);
Prabir Pradhand65552b2021-10-07 11:23:50 -070012952 return {std::move(overlay), std::move(window)};
12953 }
12954
12955 void sendFingerEvent(int32_t action) {
Prabir Pradhan678438e2023-04-13 19:32:51 +000012956 mDispatcher->notifyMotion(
Prabir Pradhand65552b2021-10-07 11:23:50 -070012957 generateMotionArgs(action, AINPUT_SOURCE_TOUCHSCREEN | AINPUT_SOURCE_STYLUS,
Prabir Pradhan678438e2023-04-13 19:32:51 +000012958 ADISPLAY_ID_DEFAULT, {PointF{20, 20}}));
Prabir Pradhand65552b2021-10-07 11:23:50 -070012959 }
12960
12961 void sendStylusEvent(int32_t action) {
12962 NotifyMotionArgs motionArgs =
12963 generateMotionArgs(action, AINPUT_SOURCE_TOUCHSCREEN | AINPUT_SOURCE_STYLUS,
12964 ADISPLAY_ID_DEFAULT, {PointF{30, 40}});
Siarhei Vishniakou6d73f832022-07-21 17:27:03 -070012965 motionArgs.pointerProperties[0].toolType = ToolType::STYLUS;
Prabir Pradhan678438e2023-04-13 19:32:51 +000012966 mDispatcher->notifyMotion(motionArgs);
Prabir Pradhand65552b2021-10-07 11:23:50 -070012967 }
12968};
12969
Prabir Pradhana3ab87a2022-01-27 10:00:21 -080012970using InputDispatcherStylusInterceptorDeathTest = InputDispatcherStylusInterceptorTest;
12971
12972TEST_F(InputDispatcherStylusInterceptorDeathTest, UntrustedOverlay_AbortsDispatcher) {
Siarhei Vishniakouad3b6822023-06-22 14:17:35 -070012973 testing::GTEST_FLAG(death_test_style) = "threadsafe";
Prabir Pradhana3ab87a2022-01-27 10:00:21 -080012974 ScopedSilentDeath _silentDeath;
12975
Prabir Pradhand65552b2021-10-07 11:23:50 -070012976 auto [overlay, window] = setupStylusOverlayScenario();
12977 overlay->setTrustedOverlay(false);
12978 // Configuring an untrusted overlay as a stylus interceptor should cause Dispatcher to abort.
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070012979 ASSERT_DEATH(mDispatcher->onWindowInfosChanged(
12980 {{*overlay->getInfo(), *window->getInfo()}, {}, 0, 0}),
Prabir Pradhand65552b2021-10-07 11:23:50 -070012981 ".* not a trusted overlay");
12982}
12983
12984TEST_F(InputDispatcherStylusInterceptorTest, ConsmesOnlyStylusEvents) {
12985 auto [overlay, window] = setupStylusOverlayScenario();
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070012986 mDispatcher->onWindowInfosChanged({{*overlay->getInfo(), *window->getInfo()}, {}, 0, 0});
Prabir Pradhand65552b2021-10-07 11:23:50 -070012987
12988 sendStylusEvent(AMOTION_EVENT_ACTION_DOWN);
12989 overlay->consumeMotionDown();
12990 sendStylusEvent(AMOTION_EVENT_ACTION_UP);
12991 overlay->consumeMotionUp();
12992
12993 sendFingerEvent(AMOTION_EVENT_ACTION_DOWN);
12994 window->consumeMotionDown();
12995 sendFingerEvent(AMOTION_EVENT_ACTION_UP);
12996 window->consumeMotionUp();
12997
12998 overlay->assertNoEvents();
12999 window->assertNoEvents();
13000}
13001
13002TEST_F(InputDispatcherStylusInterceptorTest, SpyWindowStylusInterceptor) {
13003 auto [overlay, window] = setupStylusOverlayScenario();
Prabir Pradhan51e7db02022-02-07 06:02:57 -080013004 overlay->setSpy(true);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070013005 mDispatcher->onWindowInfosChanged({{*overlay->getInfo(), *window->getInfo()}, {}, 0, 0});
Prabir Pradhand65552b2021-10-07 11:23:50 -070013006
13007 sendStylusEvent(AMOTION_EVENT_ACTION_DOWN);
13008 overlay->consumeMotionDown();
13009 window->consumeMotionDown();
13010 sendStylusEvent(AMOTION_EVENT_ACTION_UP);
13011 overlay->consumeMotionUp();
13012 window->consumeMotionUp();
13013
13014 sendFingerEvent(AMOTION_EVENT_ACTION_DOWN);
13015 window->consumeMotionDown();
13016 sendFingerEvent(AMOTION_EVENT_ACTION_UP);
13017 window->consumeMotionUp();
13018
13019 overlay->assertNoEvents();
13020 window->assertNoEvents();
13021}
13022
Prabir Pradhan6dfbf262022-03-14 15:24:30 +000013023/**
13024 * Set up a scenario to test the behavior used by the stylus handwriting detection feature.
13025 * The scenario is as follows:
13026 * - The stylus interceptor overlay is configured as a spy window.
13027 * - The stylus interceptor spy receives the start of a new stylus gesture.
13028 * - It pilfers pointers and then configures itself to no longer be a spy.
13029 * - The stylus interceptor continues to receive the rest of the gesture.
13030 */
13031TEST_F(InputDispatcherStylusInterceptorTest, StylusHandwritingScenario) {
13032 auto [overlay, window] = setupStylusOverlayScenario();
13033 overlay->setSpy(true);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070013034 mDispatcher->onWindowInfosChanged({{*overlay->getInfo(), *window->getInfo()}, {}, 0, 0});
Prabir Pradhan6dfbf262022-03-14 15:24:30 +000013035
13036 sendStylusEvent(AMOTION_EVENT_ACTION_DOWN);
13037 overlay->consumeMotionDown();
13038 window->consumeMotionDown();
13039
13040 // The interceptor pilfers the pointers.
13041 EXPECT_EQ(OK, mDispatcher->pilferPointers(overlay->getToken()));
13042 window->consumeMotionCancel();
13043
13044 // The interceptor configures itself so that it is no longer a spy.
13045 overlay->setSpy(false);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070013046 mDispatcher->onWindowInfosChanged({{*overlay->getInfo(), *window->getInfo()}, {}, 0, 0});
Prabir Pradhan6dfbf262022-03-14 15:24:30 +000013047
13048 // It continues to receive the rest of the stylus gesture.
13049 sendStylusEvent(AMOTION_EVENT_ACTION_MOVE);
13050 overlay->consumeMotionMove();
13051 sendStylusEvent(AMOTION_EVENT_ACTION_UP);
13052 overlay->consumeMotionUp();
13053
13054 window->assertNoEvents();
13055}
13056
Prabir Pradhan5735a322022-04-11 17:23:34 +000013057struct User {
Prabir Pradhanaeebeb42023-06-13 19:53:03 +000013058 gui::Pid mPid;
Prabir Pradhan8a5c41d2023-06-08 19:13:46 +000013059 gui::Uid mUid;
Prabir Pradhan5735a322022-04-11 17:23:34 +000013060 uint32_t mPolicyFlags{DEFAULT_POLICY_FLAGS};
13061 std::unique_ptr<InputDispatcher>& mDispatcher;
13062
Prabir Pradhanaeebeb42023-06-13 19:53:03 +000013063 User(std::unique_ptr<InputDispatcher>& dispatcher, gui::Pid pid, gui::Uid uid)
Prabir Pradhan5735a322022-04-11 17:23:34 +000013064 : mPid(pid), mUid(uid), mDispatcher(dispatcher) {}
13065
13066 InputEventInjectionResult injectTargetedMotion(int32_t action) const {
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070013067 return injectMotionEvent(*mDispatcher, action, AINPUT_SOURCE_TOUCHSCREEN,
Prabir Pradhan5735a322022-04-11 17:23:34 +000013068 ADISPLAY_ID_DEFAULT, {100, 200},
13069 {AMOTION_EVENT_INVALID_CURSOR_POSITION,
13070 AMOTION_EVENT_INVALID_CURSOR_POSITION},
13071 INJECT_EVENT_TIMEOUT, InputEventInjectionSync::WAIT_FOR_RESULT,
13072 systemTime(SYSTEM_TIME_MONOTONIC), {mUid}, mPolicyFlags);
13073 }
13074
13075 InputEventInjectionResult injectTargetedKey(int32_t action) const {
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070013076 return inputdispatcher::injectKey(*mDispatcher, action, /*repeatCount=*/0, ADISPLAY_ID_NONE,
Prabir Pradhan5735a322022-04-11 17:23:34 +000013077 InputEventInjectionSync::WAIT_FOR_RESULT,
Harry Cutts33476232023-01-30 19:57:29 +000013078 INJECT_EVENT_TIMEOUT, /*allowKeyRepeat=*/false, {mUid},
Prabir Pradhan5735a322022-04-11 17:23:34 +000013079 mPolicyFlags);
13080 }
13081
Siarhei Vishniakoue3ce4122023-08-23 10:26:46 -070013082 sp<FakeWindowHandle> createWindow(const char* name) const {
Prabir Pradhan5735a322022-04-11 17:23:34 +000013083 std::shared_ptr<FakeApplicationHandle> overlayApplication =
13084 std::make_shared<FakeApplicationHandle>();
Siarhei Vishniakoue3ce4122023-08-23 10:26:46 -070013085 sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(overlayApplication, mDispatcher,
13086 name, ADISPLAY_ID_DEFAULT);
Prabir Pradhan5735a322022-04-11 17:23:34 +000013087 window->setOwnerInfo(mPid, mUid);
13088 return window;
13089 }
13090};
13091
13092using InputDispatcherTargetedInjectionTest = InputDispatcherTest;
13093
13094TEST_F(InputDispatcherTargetedInjectionTest, CanInjectIntoOwnedWindow) {
Prabir Pradhanaeebeb42023-06-13 19:53:03 +000013095 auto owner = User(mDispatcher, gui::Pid{10}, gui::Uid{11});
Siarhei Vishniakoue3ce4122023-08-23 10:26:46 -070013096 auto window = owner.createWindow("Owned window");
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070013097 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Prabir Pradhan5735a322022-04-11 17:23:34 +000013098
13099 EXPECT_EQ(InputEventInjectionResult::SUCCEEDED,
13100 owner.injectTargetedMotion(AMOTION_EVENT_ACTION_DOWN));
13101 window->consumeMotionDown();
13102
13103 setFocusedWindow(window);
13104 window->consumeFocusEvent(true);
13105
13106 EXPECT_EQ(InputEventInjectionResult::SUCCEEDED,
13107 owner.injectTargetedKey(AKEY_EVENT_ACTION_DOWN));
13108 window->consumeKeyDown(ADISPLAY_ID_NONE);
13109}
13110
13111TEST_F(InputDispatcherTargetedInjectionTest, CannotInjectIntoUnownedWindow) {
Prabir Pradhanaeebeb42023-06-13 19:53:03 +000013112 auto owner = User(mDispatcher, gui::Pid{10}, gui::Uid{11});
Siarhei Vishniakoue3ce4122023-08-23 10:26:46 -070013113 auto window = owner.createWindow("Owned window");
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070013114 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Prabir Pradhan5735a322022-04-11 17:23:34 +000013115
Prabir Pradhanaeebeb42023-06-13 19:53:03 +000013116 auto rando = User(mDispatcher, gui::Pid{20}, gui::Uid{21});
Prabir Pradhan5735a322022-04-11 17:23:34 +000013117 EXPECT_EQ(InputEventInjectionResult::TARGET_MISMATCH,
13118 rando.injectTargetedMotion(AMOTION_EVENT_ACTION_DOWN));
13119
13120 setFocusedWindow(window);
13121 window->consumeFocusEvent(true);
13122
13123 EXPECT_EQ(InputEventInjectionResult::TARGET_MISMATCH,
13124 rando.injectTargetedKey(AKEY_EVENT_ACTION_DOWN));
13125 window->assertNoEvents();
13126}
13127
13128TEST_F(InputDispatcherTargetedInjectionTest, CanInjectIntoOwnedSpyWindow) {
Prabir Pradhanaeebeb42023-06-13 19:53:03 +000013129 auto owner = User(mDispatcher, gui::Pid{10}, gui::Uid{11});
Siarhei Vishniakoue3ce4122023-08-23 10:26:46 -070013130 auto window = owner.createWindow("Owned window");
13131 auto spy = owner.createWindow("Owned spy");
Prabir Pradhan5735a322022-04-11 17:23:34 +000013132 spy->setSpy(true);
13133 spy->setTrustedOverlay(true);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070013134 mDispatcher->onWindowInfosChanged({{*spy->getInfo(), *window->getInfo()}, {}, 0, 0});
Prabir Pradhan5735a322022-04-11 17:23:34 +000013135
13136 EXPECT_EQ(InputEventInjectionResult::SUCCEEDED,
13137 owner.injectTargetedMotion(AMOTION_EVENT_ACTION_DOWN));
13138 spy->consumeMotionDown();
13139 window->consumeMotionDown();
13140}
13141
13142TEST_F(InputDispatcherTargetedInjectionTest, CannotInjectIntoUnownedSpyWindow) {
Prabir Pradhanaeebeb42023-06-13 19:53:03 +000013143 auto owner = User(mDispatcher, gui::Pid{10}, gui::Uid{11});
Siarhei Vishniakoue3ce4122023-08-23 10:26:46 -070013144 auto window = owner.createWindow("Owned window");
Prabir Pradhan5735a322022-04-11 17:23:34 +000013145
Prabir Pradhanaeebeb42023-06-13 19:53:03 +000013146 auto rando = User(mDispatcher, gui::Pid{20}, gui::Uid{21});
Siarhei Vishniakoue3ce4122023-08-23 10:26:46 -070013147 auto randosSpy = rando.createWindow("Rando's spy");
Prabir Pradhan5735a322022-04-11 17:23:34 +000013148 randosSpy->setSpy(true);
13149 randosSpy->setTrustedOverlay(true);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070013150 mDispatcher->onWindowInfosChanged({{*randosSpy->getInfo(), *window->getInfo()}, {}, 0, 0});
Prabir Pradhan5735a322022-04-11 17:23:34 +000013151
13152 // The event is targeted at owner's window, so injection should succeed, but the spy should
13153 // not receive the event.
13154 EXPECT_EQ(InputEventInjectionResult::SUCCEEDED,
13155 owner.injectTargetedMotion(AMOTION_EVENT_ACTION_DOWN));
13156 randosSpy->assertNoEvents();
13157 window->consumeMotionDown();
13158}
13159
13160TEST_F(InputDispatcherTargetedInjectionTest, CanInjectIntoAnyWindowWhenNotTargeting) {
Prabir Pradhanaeebeb42023-06-13 19:53:03 +000013161 auto owner = User(mDispatcher, gui::Pid{10}, gui::Uid{11});
Siarhei Vishniakoue3ce4122023-08-23 10:26:46 -070013162 auto window = owner.createWindow("Owned window");
Prabir Pradhan5735a322022-04-11 17:23:34 +000013163
Prabir Pradhanaeebeb42023-06-13 19:53:03 +000013164 auto rando = User(mDispatcher, gui::Pid{20}, gui::Uid{21});
Siarhei Vishniakoue3ce4122023-08-23 10:26:46 -070013165 auto randosSpy = rando.createWindow("Rando's spy");
Prabir Pradhan5735a322022-04-11 17:23:34 +000013166 randosSpy->setSpy(true);
13167 randosSpy->setTrustedOverlay(true);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070013168 mDispatcher->onWindowInfosChanged({{*randosSpy->getInfo(), *window->getInfo()}, {}, 0, 0});
Prabir Pradhan5735a322022-04-11 17:23:34 +000013169
13170 // A user that has injection permission can inject into any window.
13171 EXPECT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070013172 injectMotionEvent(*mDispatcher, AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN,
Prabir Pradhan5735a322022-04-11 17:23:34 +000013173 ADISPLAY_ID_DEFAULT));
13174 randosSpy->consumeMotionDown();
13175 window->consumeMotionDown();
13176
13177 setFocusedWindow(randosSpy);
13178 randosSpy->consumeFocusEvent(true);
13179
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070013180 EXPECT_EQ(InputEventInjectionResult::SUCCEEDED, injectKeyDown(*mDispatcher));
Prabir Pradhan5735a322022-04-11 17:23:34 +000013181 randosSpy->consumeKeyDown(ADISPLAY_ID_NONE);
13182 window->assertNoEvents();
13183}
13184
Siarhei Vishniakou580fb3a2023-05-05 15:02:20 -070013185TEST_F(InputDispatcherTargetedInjectionTest, CannotGenerateActionOutsideToOtherUids) {
Prabir Pradhanaeebeb42023-06-13 19:53:03 +000013186 auto owner = User(mDispatcher, gui::Pid{10}, gui::Uid{11});
Siarhei Vishniakoue3ce4122023-08-23 10:26:46 -070013187 auto window = owner.createWindow("Owned window");
Prabir Pradhan5735a322022-04-11 17:23:34 +000013188
Prabir Pradhanaeebeb42023-06-13 19:53:03 +000013189 auto rando = User(mDispatcher, gui::Pid{20}, gui::Uid{21});
Siarhei Vishniakoue3ce4122023-08-23 10:26:46 -070013190 auto randosWindow = rando.createWindow("Rando's window");
Prabir Pradhan5735a322022-04-11 17:23:34 +000013191 randosWindow->setFrame(Rect{-10, -10, -5, -5});
13192 randosWindow->setWatchOutsideTouch(true);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070013193 mDispatcher->onWindowInfosChanged({{*randosWindow->getInfo(), *window->getInfo()}, {}, 0, 0});
Prabir Pradhan5735a322022-04-11 17:23:34 +000013194
Siarhei Vishniakou580fb3a2023-05-05 15:02:20 -070013195 // Do not allow generation of ACTION_OUTSIDE events into windows owned by different uids.
Prabir Pradhan5735a322022-04-11 17:23:34 +000013196 EXPECT_EQ(InputEventInjectionResult::SUCCEEDED,
13197 owner.injectTargetedMotion(AMOTION_EVENT_ACTION_DOWN));
13198 window->consumeMotionDown();
Siarhei Vishniakou580fb3a2023-05-05 15:02:20 -070013199 randosWindow->assertNoEvents();
Prabir Pradhan5735a322022-04-11 17:23:34 +000013200}
13201
Prabir Pradhan64f21d22023-11-28 21:19:42 +000013202using InputDispatcherPointerInWindowTest = InputDispatcherTest;
13203
13204TEST_F(InputDispatcherPointerInWindowTest, PointerInWindowWhenHovering) {
13205 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
13206
13207 sp<FakeWindowHandle> left = sp<FakeWindowHandle>::make(application, mDispatcher, "Left Window",
13208 ADISPLAY_ID_DEFAULT);
13209 left->setFrame(Rect(0, 0, 100, 100));
13210 sp<FakeWindowHandle> right = sp<FakeWindowHandle>::make(application, mDispatcher,
13211 "Right Window", ADISPLAY_ID_DEFAULT);
13212 right->setFrame(Rect(100, 0, 200, 100));
13213 sp<FakeWindowHandle> spy =
13214 sp<FakeWindowHandle>::make(application, mDispatcher, "Spy Window", ADISPLAY_ID_DEFAULT);
13215 spy->setFrame(Rect(0, 0, 200, 100));
13216 spy->setTrustedOverlay(true);
13217 spy->setSpy(true);
13218
13219 mDispatcher->onWindowInfosChanged(
13220 {{*spy->getInfo(), *left->getInfo(), *right->getInfo()}, {}, 0, 0});
13221
13222 // Hover into the left window.
13223 mDispatcher->notifyMotion(
13224 MotionArgsBuilder(ACTION_HOVER_ENTER, AINPUT_SOURCE_STYLUS)
13225 .pointer(PointerBuilder(/*id=*/0, ToolType::STYLUS).x(50).y(50))
13226 .build());
13227
13228 left->consumeMotionEvent(WithMotionAction(ACTION_HOVER_ENTER));
13229 spy->consumeMotionEvent(WithMotionAction(ACTION_HOVER_ENTER));
13230
13231 ASSERT_TRUE(mDispatcher->isPointerInWindow(left->getToken(), ADISPLAY_ID_DEFAULT, DEVICE_ID,
13232 /*pointerId=*/0));
13233 ASSERT_TRUE(mDispatcher->isPointerInWindow(spy->getToken(), ADISPLAY_ID_DEFAULT, DEVICE_ID,
13234 /*pointerId=*/0));
13235 ASSERT_FALSE(mDispatcher->isPointerInWindow(right->getToken(), ADISPLAY_ID_DEFAULT, DEVICE_ID,
13236 /*pointerId=*/0));
13237
13238 // Hover move to the right window.
13239 mDispatcher->notifyMotion(
13240 MotionArgsBuilder(ACTION_HOVER_MOVE, AINPUT_SOURCE_STYLUS)
13241 .pointer(PointerBuilder(/*id=*/0, ToolType::STYLUS).x(150).y(50))
13242 .build());
13243
13244 left->consumeMotionEvent(WithMotionAction(ACTION_HOVER_EXIT));
13245 right->consumeMotionEvent(WithMotionAction(ACTION_HOVER_ENTER));
13246 spy->consumeMotionEvent(WithMotionAction(ACTION_HOVER_MOVE));
13247
13248 ASSERT_FALSE(mDispatcher->isPointerInWindow(left->getToken(), ADISPLAY_ID_DEFAULT, DEVICE_ID,
13249 /*pointerId=*/0));
13250 ASSERT_TRUE(mDispatcher->isPointerInWindow(spy->getToken(), ADISPLAY_ID_DEFAULT, DEVICE_ID,
13251 /*pointerId=*/0));
13252 ASSERT_TRUE(mDispatcher->isPointerInWindow(right->getToken(), ADISPLAY_ID_DEFAULT, DEVICE_ID,
13253 /*pointerId=*/0));
13254
13255 // Stop hovering.
13256 mDispatcher->notifyMotion(
13257 MotionArgsBuilder(ACTION_HOVER_EXIT, AINPUT_SOURCE_STYLUS)
13258 .pointer(PointerBuilder(/*id=*/0, ToolType::STYLUS).x(150).y(50))
13259 .build());
13260
13261 right->consumeMotionEvent(WithMotionAction(ACTION_HOVER_EXIT));
13262 spy->consumeMotionEvent(WithMotionAction(ACTION_HOVER_EXIT));
13263
13264 ASSERT_FALSE(mDispatcher->isPointerInWindow(left->getToken(), ADISPLAY_ID_DEFAULT, DEVICE_ID,
13265 /*pointerId=*/0));
13266 ASSERT_FALSE(mDispatcher->isPointerInWindow(spy->getToken(), ADISPLAY_ID_DEFAULT, DEVICE_ID,
13267 /*pointerId=*/0));
13268 ASSERT_FALSE(mDispatcher->isPointerInWindow(right->getToken(), ADISPLAY_ID_DEFAULT, DEVICE_ID,
13269 /*pointerId=*/0));
13270}
13271
13272TEST_F(InputDispatcherPointerInWindowTest, PointerInWindowWithSplitTouch) {
13273 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
13274
13275 sp<FakeWindowHandle> left = sp<FakeWindowHandle>::make(application, mDispatcher, "Left Window",
13276 ADISPLAY_ID_DEFAULT);
13277 left->setFrame(Rect(0, 0, 100, 100));
13278 sp<FakeWindowHandle> right = sp<FakeWindowHandle>::make(application, mDispatcher,
13279 "Right Window", ADISPLAY_ID_DEFAULT);
13280 right->setFrame(Rect(100, 0, 200, 100));
13281 sp<FakeWindowHandle> spy =
13282 sp<FakeWindowHandle>::make(application, mDispatcher, "Spy Window", ADISPLAY_ID_DEFAULT);
13283 spy->setFrame(Rect(0, 0, 200, 100));
13284 spy->setTrustedOverlay(true);
13285 spy->setSpy(true);
13286
13287 mDispatcher->onWindowInfosChanged(
13288 {{*spy->getInfo(), *left->getInfo(), *right->getInfo()}, {}, 0, 0});
13289
13290 // First pointer down on left window.
13291 mDispatcher->notifyMotion(
13292 MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
13293 .pointer(PointerBuilder(/*id=*/0, ToolType::FINGER).x(50).y(50))
13294 .build());
13295
13296 left->consumeMotionDown();
13297 spy->consumeMotionDown();
13298
13299 ASSERT_TRUE(mDispatcher->isPointerInWindow(left->getToken(), ADISPLAY_ID_DEFAULT, DEVICE_ID,
13300 /*pointerId=*/0));
13301 ASSERT_TRUE(mDispatcher->isPointerInWindow(spy->getToken(), ADISPLAY_ID_DEFAULT, DEVICE_ID,
13302 /*pointerId=*/0));
13303 ASSERT_FALSE(mDispatcher->isPointerInWindow(right->getToken(), ADISPLAY_ID_DEFAULT, DEVICE_ID,
13304 /*pointerId=*/0));
13305
13306 // Second pointer down on right window.
13307 mDispatcher->notifyMotion(
13308 MotionArgsBuilder(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
13309 .pointer(PointerBuilder(/*id=*/0, ToolType::FINGER).x(50).y(50))
13310 .pointer(PointerBuilder(/*id=*/1, ToolType::FINGER).x(150).y(50))
13311 .build());
13312
13313 left->consumeMotionMove();
13314 right->consumeMotionDown();
13315 spy->consumeMotionEvent(WithMotionAction(POINTER_1_DOWN));
13316
13317 ASSERT_TRUE(mDispatcher->isPointerInWindow(left->getToken(), ADISPLAY_ID_DEFAULT, DEVICE_ID,
13318 /*pointerId=*/0));
13319 ASSERT_TRUE(mDispatcher->isPointerInWindow(spy->getToken(), ADISPLAY_ID_DEFAULT, DEVICE_ID,
13320 /*pointerId=*/0));
13321 ASSERT_FALSE(mDispatcher->isPointerInWindow(right->getToken(), ADISPLAY_ID_DEFAULT, DEVICE_ID,
13322 /*pointerId=*/0));
13323 ASSERT_FALSE(mDispatcher->isPointerInWindow(left->getToken(), ADISPLAY_ID_DEFAULT, DEVICE_ID,
13324 /*pointerId=*/1));
13325 ASSERT_TRUE(mDispatcher->isPointerInWindow(spy->getToken(), ADISPLAY_ID_DEFAULT, DEVICE_ID,
13326 /*pointerId=*/1));
13327 ASSERT_TRUE(mDispatcher->isPointerInWindow(right->getToken(), ADISPLAY_ID_DEFAULT, DEVICE_ID,
13328 /*pointerId=*/1));
13329
13330 // Second pointer up.
13331 mDispatcher->notifyMotion(
13332 MotionArgsBuilder(POINTER_1_UP, AINPUT_SOURCE_TOUCHSCREEN)
13333 .pointer(PointerBuilder(/*id=*/0, ToolType::FINGER).x(50).y(50))
13334 .pointer(PointerBuilder(/*id=*/1, ToolType::FINGER).x(150).y(50))
13335 .build());
13336
13337 left->consumeMotionMove();
13338 right->consumeMotionUp();
13339 spy->consumeMotionEvent(WithMotionAction(POINTER_1_UP));
13340
13341 ASSERT_TRUE(mDispatcher->isPointerInWindow(left->getToken(), ADISPLAY_ID_DEFAULT, DEVICE_ID,
13342 /*pointerId=*/0));
13343 ASSERT_TRUE(mDispatcher->isPointerInWindow(spy->getToken(), ADISPLAY_ID_DEFAULT, DEVICE_ID,
13344 /*pointerId=*/0));
13345 ASSERT_FALSE(mDispatcher->isPointerInWindow(right->getToken(), ADISPLAY_ID_DEFAULT, DEVICE_ID,
13346 /*pointerId=*/0));
13347 ASSERT_FALSE(mDispatcher->isPointerInWindow(left->getToken(), ADISPLAY_ID_DEFAULT, DEVICE_ID,
13348 /*pointerId=*/1));
13349 ASSERT_FALSE(mDispatcher->isPointerInWindow(spy->getToken(), ADISPLAY_ID_DEFAULT, DEVICE_ID,
13350 /*pointerId=*/1));
13351 ASSERT_FALSE(mDispatcher->isPointerInWindow(right->getToken(), ADISPLAY_ID_DEFAULT, DEVICE_ID,
13352 /*pointerId=*/1));
13353
13354 // First pointer up.
13355 mDispatcher->notifyMotion(
13356 MotionArgsBuilder(ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN)
13357 .pointer(PointerBuilder(/*id=*/0, ToolType::FINGER).x(50).y(50))
13358 .build());
13359
13360 left->consumeMotionUp();
13361 spy->consumeMotionUp();
13362
13363 ASSERT_FALSE(mDispatcher->isPointerInWindow(left->getToken(), ADISPLAY_ID_DEFAULT, DEVICE_ID,
13364 /*pointerId=*/0));
13365 ASSERT_FALSE(mDispatcher->isPointerInWindow(spy->getToken(), ADISPLAY_ID_DEFAULT, DEVICE_ID,
13366 /*pointerId=*/0));
13367 ASSERT_FALSE(mDispatcher->isPointerInWindow(right->getToken(), ADISPLAY_ID_DEFAULT, DEVICE_ID,
13368 /*pointerId=*/0));
13369}
13370
Siarhei Vishniakoued89cbb2023-10-13 10:42:44 -070013371TEST_F(InputDispatcherPointerInWindowTest, MultipleDevicesControllingOneMouse_legacy) {
13372 SCOPED_FLAG_OVERRIDE(enable_multi_device_same_window_stream, false);
Prabir Pradhan64f21d22023-11-28 21:19:42 +000013373 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
13374
13375 sp<FakeWindowHandle> left = sp<FakeWindowHandle>::make(application, mDispatcher, "Left Window",
13376 ADISPLAY_ID_DEFAULT);
13377 left->setFrame(Rect(0, 0, 100, 100));
13378 sp<FakeWindowHandle> right = sp<FakeWindowHandle>::make(application, mDispatcher,
13379 "Right Window", ADISPLAY_ID_DEFAULT);
13380 right->setFrame(Rect(100, 0, 200, 100));
13381
13382 mDispatcher->onWindowInfosChanged({{*left->getInfo(), *right->getInfo()}, {}, 0, 0});
13383
13384 ASSERT_FALSE(mDispatcher->isPointerInWindow(left->getToken(), ADISPLAY_ID_DEFAULT, DEVICE_ID,
13385 /*pointerId=*/0));
13386 ASSERT_FALSE(mDispatcher->isPointerInWindow(right->getToken(), ADISPLAY_ID_DEFAULT, DEVICE_ID,
13387 /*pointerId=*/0));
13388
13389 // Hover move into the window.
13390 mDispatcher->notifyMotion(
13391 MotionArgsBuilder(ACTION_HOVER_MOVE, AINPUT_SOURCE_MOUSE)
13392 .pointer(PointerBuilder(/*id=*/0, ToolType::MOUSE).x(50).y(50))
13393 .rawXCursorPosition(50)
13394 .rawYCursorPosition(50)
13395 .deviceId(DEVICE_ID)
13396 .build());
13397
13398 left->consumeMotionEvent(WithMotionAction(ACTION_HOVER_ENTER));
13399
13400 ASSERT_TRUE(mDispatcher->isPointerInWindow(left->getToken(), ADISPLAY_ID_DEFAULT, DEVICE_ID,
13401 /*pointerId=*/0));
13402
13403 // Move the mouse with another device. This cancels the hovering pointer from the first device.
13404 mDispatcher->notifyMotion(
13405 MotionArgsBuilder(ACTION_HOVER_MOVE, AINPUT_SOURCE_MOUSE)
13406 .pointer(PointerBuilder(/*id=*/0, ToolType::MOUSE).x(51).y(50))
13407 .rawXCursorPosition(51)
13408 .rawYCursorPosition(50)
13409 .deviceId(SECOND_DEVICE_ID)
13410 .build());
13411
13412 left->consumeMotionEvent(WithMotionAction(ACTION_HOVER_EXIT));
13413 left->consumeMotionEvent(WithMotionAction(ACTION_HOVER_ENTER));
13414
13415 // TODO(b/313689709): InputDispatcher's touch state is not updated, even though the window gets
13416 // a HOVER_EXIT from the first device.
13417 ASSERT_TRUE(mDispatcher->isPointerInWindow(left->getToken(), ADISPLAY_ID_DEFAULT, DEVICE_ID,
13418 /*pointerId=*/0));
13419 ASSERT_TRUE(mDispatcher->isPointerInWindow(left->getToken(), ADISPLAY_ID_DEFAULT,
13420 SECOND_DEVICE_ID,
13421 /*pointerId=*/0));
13422
13423 // Move the mouse outside the window. Document the current behavior, where the window does not
13424 // receive HOVER_EXIT even though the mouse left the window.
13425 mDispatcher->notifyMotion(
13426 MotionArgsBuilder(ACTION_HOVER_MOVE, AINPUT_SOURCE_MOUSE)
13427 .pointer(PointerBuilder(/*id=*/0, ToolType::MOUSE).x(150).y(50))
13428 .rawXCursorPosition(150)
13429 .rawYCursorPosition(50)
13430 .deviceId(SECOND_DEVICE_ID)
13431 .build());
13432
13433 left->consumeMotionEvent(WithMotionAction(ACTION_HOVER_EXIT));
13434 right->consumeMotionEvent(WithMotionAction(ACTION_HOVER_ENTER));
13435 ASSERT_TRUE(mDispatcher->isPointerInWindow(left->getToken(), ADISPLAY_ID_DEFAULT, DEVICE_ID,
13436 /*pointerId=*/0));
13437 ASSERT_FALSE(mDispatcher->isPointerInWindow(left->getToken(), ADISPLAY_ID_DEFAULT,
13438 SECOND_DEVICE_ID,
13439 /*pointerId=*/0));
13440}
13441
Siarhei Vishniakoued89cbb2023-10-13 10:42:44 -070013442/**
13443 * TODO(b/313689709) - correctly support multiple mouse devices, because they should be controlling
13444 * the same cursor, and therefore have a shared motion event stream.
13445 */
13446TEST_F(InputDispatcherPointerInWindowTest, MultipleDevicesControllingOneMouse) {
13447 SCOPED_FLAG_OVERRIDE(enable_multi_device_same_window_stream, true);
13448 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
13449
13450 sp<FakeWindowHandle> left = sp<FakeWindowHandle>::make(application, mDispatcher, "Left Window",
13451 ADISPLAY_ID_DEFAULT);
13452 left->setFrame(Rect(0, 0, 100, 100));
13453 sp<FakeWindowHandle> right = sp<FakeWindowHandle>::make(application, mDispatcher,
13454 "Right Window", ADISPLAY_ID_DEFAULT);
13455 right->setFrame(Rect(100, 0, 200, 100));
13456
13457 mDispatcher->onWindowInfosChanged({{*left->getInfo(), *right->getInfo()}, {}, 0, 0});
13458
13459 ASSERT_FALSE(mDispatcher->isPointerInWindow(left->getToken(), ADISPLAY_ID_DEFAULT, DEVICE_ID,
13460 /*pointerId=*/0));
13461 ASSERT_FALSE(mDispatcher->isPointerInWindow(right->getToken(), ADISPLAY_ID_DEFAULT, DEVICE_ID,
13462 /*pointerId=*/0));
13463
13464 // Hover move into the window.
13465 mDispatcher->notifyMotion(
13466 MotionArgsBuilder(ACTION_HOVER_MOVE, AINPUT_SOURCE_MOUSE)
13467 .pointer(PointerBuilder(/*id=*/0, ToolType::MOUSE).x(50).y(50))
13468 .rawXCursorPosition(50)
13469 .rawYCursorPosition(50)
13470 .deviceId(DEVICE_ID)
13471 .build());
13472
13473 left->consumeMotionEvent(WithMotionAction(ACTION_HOVER_ENTER));
13474
13475 ASSERT_TRUE(mDispatcher->isPointerInWindow(left->getToken(), ADISPLAY_ID_DEFAULT, DEVICE_ID,
13476 /*pointerId=*/0));
13477
13478 // Move the mouse with another device
13479 mDispatcher->notifyMotion(
13480 MotionArgsBuilder(ACTION_HOVER_MOVE, AINPUT_SOURCE_MOUSE)
13481 .pointer(PointerBuilder(/*id=*/0, ToolType::MOUSE).x(51).y(50))
13482 .rawXCursorPosition(51)
13483 .rawYCursorPosition(50)
13484 .deviceId(SECOND_DEVICE_ID)
13485 .build());
13486 left->consumeMotionEvent(WithMotionAction(ACTION_HOVER_ENTER));
13487
13488 // TODO(b/313689709): InputDispatcher's touch state is not updated, even though the window gets
13489 // a HOVER_EXIT from the first device.
13490 ASSERT_TRUE(mDispatcher->isPointerInWindow(left->getToken(), ADISPLAY_ID_DEFAULT, DEVICE_ID,
13491 /*pointerId=*/0));
13492 ASSERT_TRUE(mDispatcher->isPointerInWindow(left->getToken(), ADISPLAY_ID_DEFAULT,
13493 SECOND_DEVICE_ID,
13494 /*pointerId=*/0));
13495
13496 // Move the mouse outside the window. Document the current behavior, where the window does not
13497 // receive HOVER_EXIT even though the mouse left the window.
13498 mDispatcher->notifyMotion(
13499 MotionArgsBuilder(ACTION_HOVER_MOVE, AINPUT_SOURCE_MOUSE)
13500 .pointer(PointerBuilder(/*id=*/0, ToolType::MOUSE).x(150).y(50))
13501 .rawXCursorPosition(150)
13502 .rawYCursorPosition(50)
13503 .deviceId(SECOND_DEVICE_ID)
13504 .build());
13505
13506 right->consumeMotionEvent(WithMotionAction(ACTION_HOVER_ENTER));
13507 ASSERT_TRUE(mDispatcher->isPointerInWindow(left->getToken(), ADISPLAY_ID_DEFAULT, DEVICE_ID,
13508 /*pointerId=*/0));
13509 ASSERT_FALSE(mDispatcher->isPointerInWindow(left->getToken(), ADISPLAY_ID_DEFAULT,
13510 SECOND_DEVICE_ID,
13511 /*pointerId=*/0));
13512}
13513
Garfield Tane84e6f92019-08-29 17:28:41 -070013514} // namespace android::inputdispatcher