blob: 184659df0dc9575d78ee67a06a6f5ef62f5ee631 [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;
Linnan Li13bf76a2024-05-05 19:18:02 +080056using android::ui::ADISPLAY_ID_DEFAULT;
Garfield Tan1c7bc862020-01-28 13:24:04 -080057
Garfield Tane84e6f92019-08-29 17:28:41 -070058namespace android::inputdispatcher {
Michael Wrightd02c5b62014-02-10 15:10:22 -080059
Dominik Laskowski2f01d772022-03-23 16:01:29 -070060using namespace ftl::flag_operators;
Siarhei Vishniakou0b0374d2022-11-17 17:40:53 -080061using testing::AllOf;
Prabir Pradhan5893d362023-11-17 04:30:40 +000062using testing::Not;
Siarhei Vishniakou85eb5802024-04-01 11:40:59 -070063using testing::Pointee;
64using testing::UnorderedElementsAre;
Dominik Laskowski2f01d772022-03-23 16:01:29 -070065
Siarhei Vishniakouf4043212023-09-18 19:33:03 -070066namespace {
67
Michael Wrightd02c5b62014-02-10 15:10:22 -080068// An arbitrary time value.
Prabir Pradhan5735a322022-04-11 17:23:34 +000069static constexpr nsecs_t ARBITRARY_TIME = 1234;
Michael Wrightd02c5b62014-02-10 15:10:22 -080070
71// An arbitrary device id.
Prabir Pradhan9205e422023-05-16 20:06:13 +000072static constexpr int32_t DEVICE_ID = DEFAULT_DEVICE_ID;
Siarhei Vishniakou060f82b2023-01-27 06:39:14 -080073static constexpr int32_t SECOND_DEVICE_ID = 2;
Michael Wrightd02c5b62014-02-10 15:10:22 -080074
Jeff Brownf086ddb2014-02-11 14:28:48 -080075// An arbitrary display id.
Linnan Li13bf76a2024-05-05 19:18:02 +080076constexpr ui::LogicalDisplayId DISPLAY_ID = ADISPLAY_ID_DEFAULT;
77constexpr ui::LogicalDisplayId SECOND_DISPLAY_ID = ui::LogicalDisplayId{1};
Jeff Brownf086ddb2014-02-11 14:28:48 -080078
Prabir Pradhan8ede1d12023-05-08 19:37:44 +000079// Ensure common actions are interchangeable between keys and motions for convenience.
80static_assert(AMOTION_EVENT_ACTION_DOWN == AKEY_EVENT_ACTION_DOWN);
81static_assert(AMOTION_EVENT_ACTION_UP == AKEY_EVENT_ACTION_UP);
Siarhei Vishniakouf372b812023-02-14 18:06:51 -080082static constexpr int32_t ACTION_DOWN = AMOTION_EVENT_ACTION_DOWN;
83static constexpr int32_t ACTION_MOVE = AMOTION_EVENT_ACTION_MOVE;
84static constexpr int32_t ACTION_UP = AMOTION_EVENT_ACTION_UP;
85static constexpr int32_t ACTION_HOVER_ENTER = AMOTION_EVENT_ACTION_HOVER_ENTER;
Siarhei Vishniakoua235c042023-05-02 09:59:09 -070086static constexpr int32_t ACTION_HOVER_MOVE = AMOTION_EVENT_ACTION_HOVER_MOVE;
Siarhei Vishniakouf372b812023-02-14 18:06:51 -080087static constexpr int32_t ACTION_HOVER_EXIT = AMOTION_EVENT_ACTION_HOVER_EXIT;
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -070088static constexpr int32_t ACTION_SCROLL = AMOTION_EVENT_ACTION_SCROLL;
Siarhei Vishniakou487c49b2022-12-02 15:48:57 -080089static constexpr int32_t ACTION_OUTSIDE = AMOTION_EVENT_ACTION_OUTSIDE;
Siarhei Vishniakou1ae72f12023-01-29 12:55:30 -080090static constexpr int32_t ACTION_CANCEL = AMOTION_EVENT_ACTION_CANCEL;
Siarhei Vishniakouf372b812023-02-14 18:06:51 -080091/**
92 * The POINTER_DOWN(0) is an unusual, but valid, action. It just means that the new pointer in the
93 * MotionEvent is at the index 0 rather than 1 (or later). That is, the pointer id=0 (which is at
94 * index 0) is the new pointer going down. The same pointer could have been placed at a different
95 * index, and the action would become POINTER_1_DOWN, 2, etc..; these would all be valid. In
96 * general, we try to place pointer id = 0 at the index 0. Of course, this is not possible if
97 * pointer id=0 leaves but the pointer id=1 remains.
98 */
99static constexpr int32_t POINTER_0_DOWN =
100 AMOTION_EVENT_ACTION_POINTER_DOWN | (0 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT);
Siarhei Vishniakoua16e3a22022-03-02 15:26:40 -0800101static constexpr int32_t POINTER_1_DOWN =
102 AMOTION_EVENT_ACTION_POINTER_DOWN | (1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT);
Prabir Pradhanb60b1dc2022-03-15 14:02:35 +0000103static constexpr int32_t POINTER_2_DOWN =
104 AMOTION_EVENT_ACTION_POINTER_DOWN | (2 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT);
Vaibhav Devmurari882bd9b2022-06-23 14:54:54 +0000105static constexpr int32_t POINTER_3_DOWN =
106 AMOTION_EVENT_ACTION_POINTER_DOWN | (3 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT);
Arthur Hungc539dbb2022-12-08 07:45:36 +0000107static constexpr int32_t POINTER_0_UP =
108 AMOTION_EVENT_ACTION_POINTER_UP | (0 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT);
Siarhei Vishniakoua16e3a22022-03-02 15:26:40 -0800109static constexpr int32_t POINTER_1_UP =
110 AMOTION_EVENT_ACTION_POINTER_UP | (1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT);
Harry Cuttsb166c002023-05-09 13:06:05 +0000111static constexpr int32_t POINTER_2_UP =
112 AMOTION_EVENT_ACTION_POINTER_UP | (2 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT);
Siarhei Vishniakoua16e3a22022-03-02 15:26:40 -0800113
Antonio Kantek15beb512022-06-13 22:35:41 +0000114// The default pid and uid for the windows created on the secondary display by the test.
Prabir Pradhanaeebeb42023-06-13 19:53:03 +0000115static constexpr gui::Pid SECONDARY_WINDOW_PID{1010};
Prabir Pradhan8a5c41d2023-06-08 19:13:46 +0000116static constexpr gui::Uid SECONDARY_WINDOW_UID{1012};
Antonio Kantek15beb512022-06-13 22:35:41 +0000117
Siarhei Vishniakou58cfc602020-12-14 23:21:30 +0000118// An arbitrary pid of the gesture monitor window
Prabir Pradhanaeebeb42023-06-13 19:53:03 +0000119static constexpr gui::Pid MONITOR_PID{2001};
Siarhei Vishniakou58cfc602020-12-14 23:21:30 +0000120
Linnan Li72352222024-04-12 18:55:57 +0800121static constexpr int EXPECTED_WALLPAPER_FLAGS =
Arthur Hungc539dbb2022-12-08 07:45:36 +0000122 AMOTION_EVENT_FLAG_WINDOW_IS_OBSCURED | AMOTION_EVENT_FLAG_WINDOW_IS_PARTIALLY_OBSCURED;
123
Siarhei Vishniakou56e79092023-02-21 19:13:16 -0800124using ReservedInputDeviceId::VIRTUAL_KEYBOARD_ID;
125
Gang Wang342c9272020-01-13 13:15:04 -0500126/**
127 * Return a DOWN key event with KEYCODE_A.
128 */
129static KeyEvent getTestKeyEvent() {
130 KeyEvent event;
131
Linnan Li13bf76a2024-05-05 19:18:02 +0800132 event.initialize(InputEvent::nextId(), DEVICE_ID, AINPUT_SOURCE_KEYBOARD, ui::ADISPLAY_ID_NONE,
Garfield Tanfbe732e2020-01-24 11:26:14 -0800133 INVALID_HMAC, AKEY_EVENT_ACTION_DOWN, 0, AKEYCODE_A, KEY_A, AMETA_NONE, 0,
134 ARBITRARY_TIME, ARBITRARY_TIME);
Gang Wang342c9272020-01-13 13:15:04 -0500135 return event;
136}
137
Siarhei Vishniakoued89cbb2023-10-13 10:42:44 -0700138/**
139 * Provide a local override for a flag value. The value is restored when the object of this class
140 * goes out of scope.
141 * This class is not intended to be used directly, because its usage is cumbersome.
142 * Instead, a wrapper macro SCOPED_FLAG_OVERRIDE is provided.
143 */
144class ScopedFlagOverride {
145public:
146 ScopedFlagOverride(std::function<bool()> read, std::function<void(bool)> write, bool value)
147 : mInitialValue(read()), mWriteValue(write) {
148 mWriteValue(value);
149 }
150 ~ScopedFlagOverride() { mWriteValue(mInitialValue); }
151
152private:
153 const bool mInitialValue;
154 std::function<void(bool)> mWriteValue;
155};
156
157typedef bool (*readFlagValueFunction)();
158typedef void (*writeFlagValueFunction)(bool);
159
160/**
161 * Use this macro to locally override a flag value.
162 * Example usage:
163 * SCOPED_FLAG_OVERRIDE(enable_multi_device_same_window_stream, false);
164 * Note: this works by creating a local variable in your current scope. Don't call this twice for
165 * the same flag, because the variable names will clash!
166 */
167#define SCOPED_FLAG_OVERRIDE(NAME, VALUE) \
168 readFlagValueFunction read##NAME = com::android::input::flags::NAME; \
169 writeFlagValueFunction write##NAME = com::android::input::flags::NAME; \
170 ScopedFlagOverride override##NAME(read##NAME, write##NAME, (VALUE))
171
Siarhei Vishniakouf4043212023-09-18 19:33:03 -0700172} // namespace
Michael Wrightd02c5b62014-02-10 15:10:22 -0800173
Michael Wrightd02c5b62014-02-10 15:10:22 -0800174// --- InputDispatcherTest ---
175
176class InputDispatcherTest : public testing::Test {
177protected:
Prabir Pradhana41d2442023-04-20 21:30:40 +0000178 std::unique_ptr<FakeInputDispatcherPolicy> mFakePolicy;
Siarhei Vishniakou18050092021-09-01 13:32:49 -0700179 std::unique_ptr<InputDispatcher> mDispatcher;
Prabir Pradhanc5340732024-03-20 22:53:52 +0000180 std::shared_ptr<VerifyingTrace> mVerifyingTrace;
Michael Wrightd02c5b62014-02-10 15:10:22 -0800181
Siarhei Vishniakouf2652122021-03-05 21:39:46 +0000182 void SetUp() override {
Prabir Pradhanc5340732024-03-20 22:53:52 +0000183 mVerifyingTrace = std::make_shared<VerifyingTrace>();
184 FakeWindowHandle::sOnEventReceivedCallback = [this](const auto& _1, const auto& _2) {
185 handleEventReceivedByWindow(_1, _2);
186 };
187
Prabir Pradhana41d2442023-04-20 21:30:40 +0000188 mFakePolicy = std::make_unique<FakeInputDispatcherPolicy>();
Prabir Pradhandc3a2ad2024-02-05 19:03:51 +0000189 mDispatcher = std::make_unique<InputDispatcher>(*mFakePolicy,
190 std::make_unique<FakeInputTracingBackend>(
Prabir Pradhanc5340732024-03-20 22:53:52 +0000191 mVerifyingTrace));
Siarhei Vishniakoua7333112023-10-27 13:33:29 -0700192
Harry Cutts101ee9b2023-07-06 18:04:14 +0000193 mDispatcher->setInputDispatchMode(/*enabled=*/true, /*frozen=*/false);
Siarhei Vishniakou870ecec2020-12-09 08:07:46 -1000194 // Start InputDispatcher thread
Prabir Pradhan3608aad2019-10-02 17:08:26 -0700195 ASSERT_EQ(OK, mDispatcher->start());
Michael Wrightd02c5b62014-02-10 15:10:22 -0800196 }
197
Siarhei Vishniakouf2652122021-03-05 21:39:46 +0000198 void TearDown() override {
Prabir Pradhanc5340732024-03-20 22:53:52 +0000199 ASSERT_NO_FATAL_FAILURE(mVerifyingTrace->verifyExpectedEventsTraced());
200 FakeWindowHandle::sOnEventReceivedCallback = nullptr;
201
Prabir Pradhan3608aad2019-10-02 17:08:26 -0700202 ASSERT_EQ(OK, mDispatcher->stop());
Prabir Pradhana41d2442023-04-20 21:30:40 +0000203 mFakePolicy.reset();
Siarhei Vishniakou18050092021-09-01 13:32:49 -0700204 mDispatcher.reset();
Michael Wrightd02c5b62014-02-10 15:10:22 -0800205 }
Siarhei Vishniakou4cb50ca2020-05-26 21:43:02 -0700206
Prabir Pradhanc5340732024-03-20 22:53:52 +0000207 void handleEventReceivedByWindow(const std::unique_ptr<InputEvent>& event,
208 const gui::WindowInfo& info) {
209 if (!event) {
210 return;
211 }
212
213 switch (event->getType()) {
214 case InputEventType::KEY: {
215 mVerifyingTrace->expectKeyDispatchTraced(static_cast<KeyEvent&>(*event), info.id);
216 break;
217 }
218 case InputEventType::MOTION: {
219 mVerifyingTrace->expectMotionDispatchTraced(static_cast<MotionEvent&>(*event),
220 info.id);
221 break;
222 }
223 default:
224 break;
225 }
226 }
227
Siarhei Vishniakou4cb50ca2020-05-26 21:43:02 -0700228 /**
229 * Used for debugging when writing the test
230 */
231 void dumpDispatcherState() {
232 std::string dump;
233 mDispatcher->dump(dump);
234 std::stringstream ss(dump);
235 std::string to;
236
237 while (std::getline(ss, to, '\n')) {
238 ALOGE("%s", to.c_str());
239 }
240 }
Vishnu Nair958da932020-08-21 17:12:37 -0700241
Chavi Weingarten847e8512023-03-29 00:26:09 +0000242 void setFocusedWindow(const sp<WindowInfoHandle>& window) {
Vishnu Nair958da932020-08-21 17:12:37 -0700243 FocusRequest request;
244 request.token = window->getToken();
Siarhei Vishniakou5d552c42021-05-21 05:02:22 +0000245 request.windowName = window->getName();
Vishnu Nair958da932020-08-21 17:12:37 -0700246 request.timestamp = systemTime(SYSTEM_TIME_MONOTONIC);
Linnan Li13bf76a2024-05-05 19:18:02 +0800247 request.displayId = window->getInfo()->displayId.val();
Vishnu Nair958da932020-08-21 17:12:37 -0700248 mDispatcher->setFocusedWindow(request);
249 }
Michael Wrightd02c5b62014-02-10 15:10:22 -0800250};
251
Michael Wrightd02c5b62014-02-10 15:10:22 -0800252TEST_F(InputDispatcherTest, InjectInputEvent_ValidatesKeyEvents) {
253 KeyEvent event;
254
255 // Rejects undefined key actions.
Linnan Li13bf76a2024-05-05 19:18:02 +0800256 event.initialize(InputEvent::nextId(), DEVICE_ID, AINPUT_SOURCE_KEYBOARD, ui::ADISPLAY_ID_NONE,
Garfield Tanfbe732e2020-01-24 11:26:14 -0800257 INVALID_HMAC,
Harry Cutts101ee9b2023-07-06 18:04:14 +0000258 /*action=*/-1, 0, AKEYCODE_A, KEY_A, AMETA_NONE, 0, ARBITRARY_TIME,
Siarhei Vishniakou9c858ac2020-01-23 14:20:11 -0600259 ARBITRARY_TIME);
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -0800260 ASSERT_EQ(InputEventInjectionResult::FAILED,
Harry Cutts33476232023-01-30 19:57:29 +0000261 mDispatcher->injectInputEvent(&event, /*targetUid=*/{}, InputEventInjectionSync::NONE,
Prabir Pradhan5735a322022-04-11 17:23:34 +0000262 0ms, 0))
Michael Wrightd02c5b62014-02-10 15:10:22 -0800263 << "Should reject key events with undefined action.";
264
265 // Rejects ACTION_MULTIPLE since it is not supported despite being defined in the API.
Linnan Li13bf76a2024-05-05 19:18:02 +0800266 event.initialize(InputEvent::nextId(), DEVICE_ID, AINPUT_SOURCE_KEYBOARD, ui::ADISPLAY_ID_NONE,
Garfield Tanfbe732e2020-01-24 11:26:14 -0800267 INVALID_HMAC, AKEY_EVENT_ACTION_MULTIPLE, 0, AKEYCODE_A, KEY_A, AMETA_NONE, 0,
Siarhei Vishniakou9c858ac2020-01-23 14:20:11 -0600268 ARBITRARY_TIME, ARBITRARY_TIME);
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -0800269 ASSERT_EQ(InputEventInjectionResult::FAILED,
Harry Cutts33476232023-01-30 19:57:29 +0000270 mDispatcher->injectInputEvent(&event, /*targetUid=*/{}, InputEventInjectionSync::NONE,
Prabir Pradhan5735a322022-04-11 17:23:34 +0000271 0ms, 0))
Michael Wrightd02c5b62014-02-10 15:10:22 -0800272 << "Should reject key events with ACTION_MULTIPLE.";
273}
274
275TEST_F(InputDispatcherTest, InjectInputEvent_ValidatesMotionEvents) {
276 MotionEvent event;
277 PointerProperties pointerProperties[MAX_POINTERS + 1];
278 PointerCoords pointerCoords[MAX_POINTERS + 1];
Siarhei Vishniakou01747382022-01-20 13:23:27 -0800279 for (size_t i = 0; i <= MAX_POINTERS; i++) {
Michael Wrightd02c5b62014-02-10 15:10:22 -0800280 pointerProperties[i].clear();
281 pointerProperties[i].id = i;
282 pointerCoords[i].clear();
283 }
284
Siarhei Vishniakou49e59222018-12-28 18:17:15 -0800285 // Some constants commonly used below
286 constexpr int32_t source = AINPUT_SOURCE_TOUCHSCREEN;
287 constexpr int32_t edgeFlags = AMOTION_EVENT_EDGE_FLAG_NONE;
288 constexpr int32_t metaState = AMETA_NONE;
289 constexpr MotionClassification classification = MotionClassification::NONE;
290
chaviw9eaa22c2020-07-01 16:21:27 -0700291 ui::Transform identityTransform;
Michael Wrightd02c5b62014-02-10 15:10:22 -0800292 // Rejects undefined motion actions.
Garfield Tanfbe732e2020-01-24 11:26:14 -0800293 event.initialize(InputEvent::nextId(), DEVICE_ID, source, DISPLAY_ID, INVALID_HMAC,
Harry Cutts101ee9b2023-07-06 18:04:14 +0000294 /*action=*/-1, 0, 0, edgeFlags, metaState, 0, classification,
chaviw9eaa22c2020-07-01 16:21:27 -0700295 identityTransform, 0, 0, AMOTION_EVENT_INVALID_CURSOR_POSITION,
Prabir Pradhanb9b18502021-08-26 12:30:32 -0700296 AMOTION_EVENT_INVALID_CURSOR_POSITION, identityTransform, ARBITRARY_TIME,
297 ARBITRARY_TIME,
Harry Cutts101ee9b2023-07-06 18:04:14 +0000298 /*pointerCount=*/1, pointerProperties, pointerCoords);
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -0800299 ASSERT_EQ(InputEventInjectionResult::FAILED,
Harry Cutts33476232023-01-30 19:57:29 +0000300 mDispatcher->injectInputEvent(&event, /*targetUid=*/{}, InputEventInjectionSync::NONE,
Prabir Pradhan5735a322022-04-11 17:23:34 +0000301 0ms, 0))
Michael Wrightd02c5b62014-02-10 15:10:22 -0800302 << "Should reject motion events with undefined action.";
303
304 // Rejects pointer down with invalid index.
Garfield Tanfbe732e2020-01-24 11:26:14 -0800305 event.initialize(InputEvent::nextId(), DEVICE_ID, source, DISPLAY_ID, INVALID_HMAC,
Siarhei Vishniakoua16e3a22022-03-02 15:26:40 -0800306 POINTER_1_DOWN, 0, 0, edgeFlags, metaState, 0, classification,
307 identityTransform, 0, 0, AMOTION_EVENT_INVALID_CURSOR_POSITION,
308 AMOTION_EVENT_INVALID_CURSOR_POSITION, identityTransform, ARBITRARY_TIME,
309 ARBITRARY_TIME,
Harry Cutts101ee9b2023-07-06 18:04:14 +0000310 /*pointerCount=*/1, pointerProperties, pointerCoords);
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -0800311 ASSERT_EQ(InputEventInjectionResult::FAILED,
Harry Cutts33476232023-01-30 19:57:29 +0000312 mDispatcher->injectInputEvent(&event, /*targetUid=*/{}, InputEventInjectionSync::NONE,
Prabir Pradhan5735a322022-04-11 17:23:34 +0000313 0ms, 0))
Michael Wrightd02c5b62014-02-10 15:10:22 -0800314 << "Should reject motion events with pointer down index too large.";
315
Garfield Tanfbe732e2020-01-24 11:26:14 -0800316 event.initialize(InputEvent::nextId(), DEVICE_ID, source, DISPLAY_ID, INVALID_HMAC,
Garfield Tan00f511d2019-06-12 16:55:40 -0700317 AMOTION_EVENT_ACTION_POINTER_DOWN |
318 (~0U << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT),
chaviw9eaa22c2020-07-01 16:21:27 -0700319 0, 0, edgeFlags, metaState, 0, classification, identityTransform, 0, 0,
320 AMOTION_EVENT_INVALID_CURSOR_POSITION, AMOTION_EVENT_INVALID_CURSOR_POSITION,
Prabir Pradhanb9b18502021-08-26 12:30:32 -0700321 identityTransform, ARBITRARY_TIME, ARBITRARY_TIME,
Harry Cutts101ee9b2023-07-06 18:04:14 +0000322 /*pointerCount=*/1, pointerProperties, pointerCoords);
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -0800323 ASSERT_EQ(InputEventInjectionResult::FAILED,
Harry Cutts33476232023-01-30 19:57:29 +0000324 mDispatcher->injectInputEvent(&event, /*targetUid=*/{}, InputEventInjectionSync::NONE,
Prabir Pradhan5735a322022-04-11 17:23:34 +0000325 0ms, 0))
Michael Wrightd02c5b62014-02-10 15:10:22 -0800326 << "Should reject motion events with pointer down index too small.";
327
328 // Rejects pointer up with invalid index.
Garfield Tanfbe732e2020-01-24 11:26:14 -0800329 event.initialize(InputEvent::nextId(), DEVICE_ID, source, DISPLAY_ID, INVALID_HMAC,
Siarhei Vishniakoua16e3a22022-03-02 15:26:40 -0800330 POINTER_1_UP, 0, 0, edgeFlags, metaState, 0, classification, identityTransform,
331 0, 0, AMOTION_EVENT_INVALID_CURSOR_POSITION,
332 AMOTION_EVENT_INVALID_CURSOR_POSITION, identityTransform, ARBITRARY_TIME,
333 ARBITRARY_TIME,
Harry Cutts101ee9b2023-07-06 18:04:14 +0000334 /*pointerCount=*/1, pointerProperties, pointerCoords);
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -0800335 ASSERT_EQ(InputEventInjectionResult::FAILED,
Harry Cutts33476232023-01-30 19:57:29 +0000336 mDispatcher->injectInputEvent(&event, /*targetUid=*/{}, InputEventInjectionSync::NONE,
Prabir Pradhan5735a322022-04-11 17:23:34 +0000337 0ms, 0))
Michael Wrightd02c5b62014-02-10 15:10:22 -0800338 << "Should reject motion events with pointer up index too large.";
339
Garfield Tanfbe732e2020-01-24 11:26:14 -0800340 event.initialize(InputEvent::nextId(), DEVICE_ID, source, DISPLAY_ID, INVALID_HMAC,
Garfield Tan00f511d2019-06-12 16:55:40 -0700341 AMOTION_EVENT_ACTION_POINTER_UP |
342 (~0U << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT),
chaviw9eaa22c2020-07-01 16:21:27 -0700343 0, 0, edgeFlags, metaState, 0, classification, identityTransform, 0, 0,
344 AMOTION_EVENT_INVALID_CURSOR_POSITION, AMOTION_EVENT_INVALID_CURSOR_POSITION,
Prabir Pradhanb9b18502021-08-26 12:30:32 -0700345 identityTransform, ARBITRARY_TIME, ARBITRARY_TIME,
Harry Cutts101ee9b2023-07-06 18:04:14 +0000346 /*pointerCount=*/1, pointerProperties, pointerCoords);
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -0800347 ASSERT_EQ(InputEventInjectionResult::FAILED,
Harry Cutts33476232023-01-30 19:57:29 +0000348 mDispatcher->injectInputEvent(&event, /*targetUid=*/{}, InputEventInjectionSync::NONE,
Prabir Pradhan5735a322022-04-11 17:23:34 +0000349 0ms, 0))
Michael Wrightd02c5b62014-02-10 15:10:22 -0800350 << "Should reject motion events with pointer up index too small.";
351
352 // Rejects motion events with invalid number of pointers.
Garfield Tanfbe732e2020-01-24 11:26:14 -0800353 event.initialize(InputEvent::nextId(), DEVICE_ID, source, DISPLAY_ID, INVALID_HMAC,
354 AMOTION_EVENT_ACTION_DOWN, 0, 0, edgeFlags, metaState, 0, classification,
chaviw9eaa22c2020-07-01 16:21:27 -0700355 identityTransform, 0, 0, AMOTION_EVENT_INVALID_CURSOR_POSITION,
Prabir Pradhanb9b18502021-08-26 12:30:32 -0700356 AMOTION_EVENT_INVALID_CURSOR_POSITION, identityTransform, ARBITRARY_TIME,
357 ARBITRARY_TIME,
Harry Cutts101ee9b2023-07-06 18:04:14 +0000358 /*pointerCount=*/0, pointerProperties, pointerCoords);
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -0800359 ASSERT_EQ(InputEventInjectionResult::FAILED,
Harry Cutts33476232023-01-30 19:57:29 +0000360 mDispatcher->injectInputEvent(&event, /*targetUid=*/{}, InputEventInjectionSync::NONE,
Prabir Pradhan5735a322022-04-11 17:23:34 +0000361 0ms, 0))
Michael Wrightd02c5b62014-02-10 15:10:22 -0800362 << "Should reject motion events with 0 pointers.";
363
Garfield Tanfbe732e2020-01-24 11:26:14 -0800364 event.initialize(InputEvent::nextId(), DEVICE_ID, source, DISPLAY_ID, INVALID_HMAC,
365 AMOTION_EVENT_ACTION_DOWN, 0, 0, edgeFlags, metaState, 0, classification,
chaviw9eaa22c2020-07-01 16:21:27 -0700366 identityTransform, 0, 0, AMOTION_EVENT_INVALID_CURSOR_POSITION,
Prabir Pradhanb9b18502021-08-26 12:30:32 -0700367 AMOTION_EVENT_INVALID_CURSOR_POSITION, identityTransform, ARBITRARY_TIME,
368 ARBITRARY_TIME,
Harry Cutts101ee9b2023-07-06 18:04:14 +0000369 /*pointerCount=*/MAX_POINTERS + 1, pointerProperties, pointerCoords);
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -0800370 ASSERT_EQ(InputEventInjectionResult::FAILED,
Harry Cutts33476232023-01-30 19:57:29 +0000371 mDispatcher->injectInputEvent(&event, /*targetUid=*/{}, InputEventInjectionSync::NONE,
Prabir Pradhan5735a322022-04-11 17:23:34 +0000372 0ms, 0))
Michael Wrightd02c5b62014-02-10 15:10:22 -0800373 << "Should reject motion events with more than MAX_POINTERS pointers.";
374
375 // Rejects motion events with invalid pointer ids.
376 pointerProperties[0].id = -1;
Garfield Tanfbe732e2020-01-24 11:26:14 -0800377 event.initialize(InputEvent::nextId(), DEVICE_ID, source, DISPLAY_ID, INVALID_HMAC,
378 AMOTION_EVENT_ACTION_DOWN, 0, 0, edgeFlags, metaState, 0, classification,
chaviw9eaa22c2020-07-01 16:21:27 -0700379 identityTransform, 0, 0, AMOTION_EVENT_INVALID_CURSOR_POSITION,
Prabir Pradhanb9b18502021-08-26 12:30:32 -0700380 AMOTION_EVENT_INVALID_CURSOR_POSITION, identityTransform, ARBITRARY_TIME,
381 ARBITRARY_TIME,
Harry Cutts101ee9b2023-07-06 18:04:14 +0000382 /*pointerCount=*/1, pointerProperties, pointerCoords);
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -0800383 ASSERT_EQ(InputEventInjectionResult::FAILED,
Harry Cutts33476232023-01-30 19:57:29 +0000384 mDispatcher->injectInputEvent(&event, /*targetUid=*/{}, InputEventInjectionSync::NONE,
Prabir Pradhan5735a322022-04-11 17:23:34 +0000385 0ms, 0))
Michael Wrightd02c5b62014-02-10 15:10:22 -0800386 << "Should reject motion events with pointer ids less than 0.";
387
388 pointerProperties[0].id = MAX_POINTER_ID + 1;
Garfield Tanfbe732e2020-01-24 11:26:14 -0800389 event.initialize(InputEvent::nextId(), DEVICE_ID, source, DISPLAY_ID, INVALID_HMAC,
390 AMOTION_EVENT_ACTION_DOWN, 0, 0, edgeFlags, metaState, 0, classification,
chaviw9eaa22c2020-07-01 16:21:27 -0700391 identityTransform, 0, 0, AMOTION_EVENT_INVALID_CURSOR_POSITION,
Prabir Pradhanb9b18502021-08-26 12:30:32 -0700392 AMOTION_EVENT_INVALID_CURSOR_POSITION, identityTransform, ARBITRARY_TIME,
393 ARBITRARY_TIME,
Harry Cutts101ee9b2023-07-06 18:04:14 +0000394 /*pointerCount=*/1, pointerProperties, pointerCoords);
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -0800395 ASSERT_EQ(InputEventInjectionResult::FAILED,
Harry Cutts33476232023-01-30 19:57:29 +0000396 mDispatcher->injectInputEvent(&event, /*targetUid=*/{}, InputEventInjectionSync::NONE,
Prabir Pradhan5735a322022-04-11 17:23:34 +0000397 0ms, 0))
Michael Wrightd02c5b62014-02-10 15:10:22 -0800398 << "Should reject motion events with pointer ids greater than MAX_POINTER_ID.";
399
400 // Rejects motion events with duplicate pointer ids.
401 pointerProperties[0].id = 1;
402 pointerProperties[1].id = 1;
Garfield Tanfbe732e2020-01-24 11:26:14 -0800403 event.initialize(InputEvent::nextId(), DEVICE_ID, source, DISPLAY_ID, INVALID_HMAC,
404 AMOTION_EVENT_ACTION_DOWN, 0, 0, edgeFlags, metaState, 0, classification,
chaviw9eaa22c2020-07-01 16:21:27 -0700405 identityTransform, 0, 0, AMOTION_EVENT_INVALID_CURSOR_POSITION,
Prabir Pradhanb9b18502021-08-26 12:30:32 -0700406 AMOTION_EVENT_INVALID_CURSOR_POSITION, identityTransform, ARBITRARY_TIME,
407 ARBITRARY_TIME,
Harry Cutts101ee9b2023-07-06 18:04:14 +0000408 /*pointerCount=*/2, pointerProperties, pointerCoords);
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -0800409 ASSERT_EQ(InputEventInjectionResult::FAILED,
Harry Cutts33476232023-01-30 19:57:29 +0000410 mDispatcher->injectInputEvent(&event, /*targetUid=*/{}, InputEventInjectionSync::NONE,
Prabir Pradhan5735a322022-04-11 17:23:34 +0000411 0ms, 0))
Michael Wrightd02c5b62014-02-10 15:10:22 -0800412 << "Should reject motion events with duplicate pointer ids.";
413}
414
Siarhei Vishniakou2bfa9052019-11-21 18:10:54 -0800415/* Test InputDispatcher for notifyConfigurationChanged and notifySwitch events */
416
417TEST_F(InputDispatcherTest, NotifyConfigurationChanged_CallsPolicy) {
418 constexpr nsecs_t eventTime = 20;
Prabir Pradhan678438e2023-04-13 19:32:51 +0000419 mDispatcher->notifyConfigurationChanged({/*id=*/10, eventTime});
Siarhei Vishniakou2bfa9052019-11-21 18:10:54 -0800420 ASSERT_TRUE(mDispatcher->waitForIdle());
421
422 mFakePolicy->assertNotifyConfigurationChangedWasCalled(eventTime);
423}
424
425TEST_F(InputDispatcherTest, NotifySwitch_CallsPolicy) {
Prabir Pradhana8fe7c52023-12-14 22:07:23 +0000426 NotifySwitchArgs args(InputEvent::nextId(), /*eventTime=*/20, /*policyFlags=*/0,
427 /*switchValues=*/1,
Harry Cutts33476232023-01-30 19:57:29 +0000428 /*switchMask=*/2);
Prabir Pradhan678438e2023-04-13 19:32:51 +0000429 mDispatcher->notifySwitch(args);
Siarhei Vishniakou2bfa9052019-11-21 18:10:54 -0800430
431 // InputDispatcher adds POLICY_FLAG_TRUSTED because the event went through InputListener
432 args.policyFlags |= POLICY_FLAG_TRUSTED;
433 mFakePolicy->assertNotifySwitchWasCalled(args);
434}
435
Siarhei Vishniakouadeb6fa2023-05-26 09:11:06 -0700436namespace {
437
Siarhei Vishniakou097c3db2020-05-06 14:18:38 -0700438static constexpr std::chrono::duration INJECT_EVENT_TIMEOUT = 500ms;
Siarhei Vishniakou540dbae2020-05-05 18:17:17 -0700439
Prabir Pradhan112b1ad2023-09-21 09:53:53 +0000440class FakeMonitorReceiver {
441public:
Linnan Li13bf76a2024-05-05 19:18:02 +0800442 FakeMonitorReceiver(InputDispatcher& dispatcher, const std::string name,
443 ui::LogicalDisplayId displayId)
Siarhei Vishniakou2defec02023-06-08 17:24:44 -0700444 : mInputReceiver(*dispatcher.createInputMonitor(displayId, name, MONITOR_PID), name) {}
Prabir Pradhan112b1ad2023-09-21 09:53:53 +0000445
Siarhei Vishniakou2defec02023-06-08 17:24:44 -0700446 sp<IBinder> getToken() { return mInputReceiver.getToken(); }
Prabir Pradhan112b1ad2023-09-21 09:53:53 +0000447
Linnan Li13bf76a2024-05-05 19:18:02 +0800448 void consumeKeyDown(ui::LogicalDisplayId expectedDisplayId, int32_t expectedFlags = 0) {
Siarhei Vishniakou2defec02023-06-08 17:24:44 -0700449 mInputReceiver.consumeEvent(InputEventType::KEY, AKEY_EVENT_ACTION_DOWN, expectedDisplayId,
450 expectedFlags);
Prabir Pradhan112b1ad2023-09-21 09:53:53 +0000451 }
452
453 std::optional<int32_t> receiveEvent() {
Siarhei Vishniakoud3061ab2023-12-18 20:41:08 -0800454 const auto [sequenceNum, _] = mInputReceiver.receiveEvent(CONSUME_TIMEOUT_EVENT_EXPECTED);
455 return sequenceNum;
Prabir Pradhan112b1ad2023-09-21 09:53:53 +0000456 }
457
Siarhei Vishniakou2defec02023-06-08 17:24:44 -0700458 void finishEvent(uint32_t consumeSeq) { return mInputReceiver.finishEvent(consumeSeq); }
Prabir Pradhan112b1ad2023-09-21 09:53:53 +0000459
Linnan Li13bf76a2024-05-05 19:18:02 +0800460 void consumeMotionDown(ui::LogicalDisplayId expectedDisplayId, int32_t expectedFlags = 0) {
Siarhei Vishniakou2defec02023-06-08 17:24:44 -0700461 mInputReceiver.consumeEvent(InputEventType::MOTION, AMOTION_EVENT_ACTION_DOWN,
462 expectedDisplayId, expectedFlags);
Prabir Pradhan112b1ad2023-09-21 09:53:53 +0000463 }
464
Linnan Li13bf76a2024-05-05 19:18:02 +0800465 void consumeMotionMove(ui::LogicalDisplayId expectedDisplayId, int32_t expectedFlags = 0) {
Siarhei Vishniakou2defec02023-06-08 17:24:44 -0700466 mInputReceiver.consumeEvent(InputEventType::MOTION, AMOTION_EVENT_ACTION_MOVE,
467 expectedDisplayId, expectedFlags);
Prabir Pradhan112b1ad2023-09-21 09:53:53 +0000468 }
469
Linnan Li13bf76a2024-05-05 19:18:02 +0800470 void consumeMotionUp(ui::LogicalDisplayId expectedDisplayId, int32_t expectedFlags = 0) {
Siarhei Vishniakou2defec02023-06-08 17:24:44 -0700471 mInputReceiver.consumeEvent(InputEventType::MOTION, AMOTION_EVENT_ACTION_UP,
472 expectedDisplayId, expectedFlags);
Prabir Pradhan112b1ad2023-09-21 09:53:53 +0000473 }
474
Linnan Li13bf76a2024-05-05 19:18:02 +0800475 void consumeMotionCancel(ui::LogicalDisplayId expectedDisplayId, int32_t expectedFlags = 0) {
Siarhei Vishniakou2defec02023-06-08 17:24:44 -0700476 mInputReceiver.consumeMotionEvent(
Prabir Pradhan112b1ad2023-09-21 09:53:53 +0000477 AllOf(WithMotionAction(AMOTION_EVENT_ACTION_CANCEL),
478 WithDisplayId(expectedDisplayId),
479 WithFlags(expectedFlags | AMOTION_EVENT_FLAG_CANCELED)));
480 }
481
482 void consumeMotionPointerDown(int32_t pointerIdx) {
483 int32_t action = AMOTION_EVENT_ACTION_POINTER_DOWN |
484 (pointerIdx << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT);
Siarhei Vishniakou2defec02023-06-08 17:24:44 -0700485 mInputReceiver.consumeEvent(InputEventType::MOTION, action, ADISPLAY_ID_DEFAULT,
486 /*expectedFlags=*/0);
Prabir Pradhan112b1ad2023-09-21 09:53:53 +0000487 }
488
489 void consumeMotionEvent(const ::testing::Matcher<MotionEvent>& matcher) {
Siarhei Vishniakou2defec02023-06-08 17:24:44 -0700490 mInputReceiver.consumeMotionEvent(matcher);
Prabir Pradhan112b1ad2023-09-21 09:53:53 +0000491 }
492
Siarhei Vishniakoud3061ab2023-12-18 20:41:08 -0800493 std::unique_ptr<MotionEvent> consumeMotion() { return mInputReceiver.consumeMotion(); }
Prabir Pradhan112b1ad2023-09-21 09:53:53 +0000494
Siarhei Vishniakouef2b4502023-12-28 11:51:47 -0800495 void assertNoEvents() { mInputReceiver.assertNoEvents(CONSUME_TIMEOUT_NO_EVENT_EXPECTED); }
Prabir Pradhan112b1ad2023-09-21 09:53:53 +0000496
497private:
Siarhei Vishniakou2defec02023-06-08 17:24:44 -0700498 FakeInputReceiver mInputReceiver;
Prabir Pradhan112b1ad2023-09-21 09:53:53 +0000499};
500
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -0800501static InputEventInjectionResult injectKey(
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -0700502 InputDispatcher& dispatcher, int32_t action, int32_t repeatCount,
Linnan Li13bf76a2024-05-05 19:18:02 +0800503 ui::LogicalDisplayId displayId = ui::ADISPLAY_ID_NONE,
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -0800504 InputEventInjectionSync syncMode = InputEventInjectionSync::WAIT_FOR_RESULT,
Prabir Pradhan93f342c2021-03-11 15:05:30 -0800505 std::chrono::milliseconds injectionTimeout = INJECT_EVENT_TIMEOUT,
Prabir Pradhan8a5c41d2023-06-08 19:13:46 +0000506 bool allowKeyRepeat = true, std::optional<gui::Uid> targetUid = {},
Prabir Pradhan5735a322022-04-11 17:23:34 +0000507 uint32_t policyFlags = DEFAULT_POLICY_FLAGS) {
Arthur Hungb92218b2018-08-14 12:00:21 +0800508 KeyEvent event;
509 nsecs_t currentTime = systemTime(SYSTEM_TIME_MONOTONIC);
510
511 // Define a valid key down event.
Garfield Tanfbe732e2020-01-24 11:26:14 -0800512 event.initialize(InputEvent::nextId(), DEVICE_ID, AINPUT_SOURCE_KEYBOARD, displayId,
Harry Cutts33476232023-01-30 19:57:29 +0000513 INVALID_HMAC, action, /*flags=*/0, AKEYCODE_A, KEY_A, AMETA_NONE, repeatCount,
514 currentTime, currentTime);
Arthur Hungb92218b2018-08-14 12:00:21 +0800515
Prabir Pradhan93f342c2021-03-11 15:05:30 -0800516 if (!allowKeyRepeat) {
517 policyFlags |= POLICY_FLAG_DISABLE_KEY_REPEAT;
518 }
Arthur Hungb92218b2018-08-14 12:00:21 +0800519 // Inject event until dispatch out.
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -0700520 return dispatcher.injectInputEvent(&event, targetUid, syncMode, injectionTimeout, policyFlags);
Arthur Hungb92218b2018-08-14 12:00:21 +0800521}
522
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -0700523static void assertInjectedKeyTimesOut(InputDispatcher& dispatcher) {
524 InputEventInjectionResult result =
Linnan Li13bf76a2024-05-05 19:18:02 +0800525 injectKey(dispatcher, AKEY_EVENT_ACTION_DOWN, /*repeatCount=*/0, ui::ADISPLAY_ID_NONE,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -0700526 InputEventInjectionSync::WAIT_FOR_RESULT, CONSUME_TIMEOUT_NO_EVENT_EXPECTED);
527 if (result != InputEventInjectionResult::TIMED_OUT) {
528 FAIL() << "Injection should have timed out, but got " << ftl::enum_string(result);
529 }
530}
531
Linnan Li13bf76a2024-05-05 19:18:02 +0800532static InputEventInjectionResult injectKeyDown(
533 InputDispatcher& dispatcher, ui::LogicalDisplayId displayId = ui::ADISPLAY_ID_NONE) {
Harry Cutts33476232023-01-30 19:57:29 +0000534 return injectKey(dispatcher, AKEY_EVENT_ACTION_DOWN, /*repeatCount=*/0, displayId);
Siarhei Vishniakou4cb50ca2020-05-26 21:43:02 -0700535}
536
Prabir Pradhan93f342c2021-03-11 15:05:30 -0800537// Inject a down event that has key repeat disabled. This allows InputDispatcher to idle without
538// sending a subsequent key up. When key repeat is enabled, the dispatcher cannot idle because it
539// has to be woken up to process the repeating key.
Linnan Li13bf76a2024-05-05 19:18:02 +0800540static InputEventInjectionResult injectKeyDownNoRepeat(
541 InputDispatcher& dispatcher, ui::LogicalDisplayId displayId = ui::ADISPLAY_ID_NONE) {
Harry Cutts33476232023-01-30 19:57:29 +0000542 return injectKey(dispatcher, AKEY_EVENT_ACTION_DOWN, /*repeatCount=*/0, displayId,
Prabir Pradhan93f342c2021-03-11 15:05:30 -0800543 InputEventInjectionSync::WAIT_FOR_RESULT, INJECT_EVENT_TIMEOUT,
Harry Cutts33476232023-01-30 19:57:29 +0000544 /*allowKeyRepeat=*/false);
Prabir Pradhan93f342c2021-03-11 15:05:30 -0800545}
546
Linnan Li13bf76a2024-05-05 19:18:02 +0800547static InputEventInjectionResult injectKeyUp(
548 InputDispatcher& dispatcher, ui::LogicalDisplayId displayId = ui::ADISPLAY_ID_NONE) {
Harry Cutts33476232023-01-30 19:57:29 +0000549 return injectKey(dispatcher, AKEY_EVENT_ACTION_UP, /*repeatCount=*/0, displayId);
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -0700550}
551
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -0800552static InputEventInjectionResult injectMotionEvent(
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -0700553 InputDispatcher& dispatcher, const MotionEvent& event,
Garfield Tandf26e862020-07-01 20:18:19 -0700554 std::chrono::milliseconds injectionTimeout = INJECT_EVENT_TIMEOUT,
Prabir Pradhan5735a322022-04-11 17:23:34 +0000555 InputEventInjectionSync injectionMode = InputEventInjectionSync::WAIT_FOR_RESULT,
Prabir Pradhan8a5c41d2023-06-08 19:13:46 +0000556 std::optional<gui::Uid> targetUid = {}, uint32_t policyFlags = DEFAULT_POLICY_FLAGS) {
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -0700557 return dispatcher.injectInputEvent(&event, targetUid, injectionMode, injectionTimeout,
558 policyFlags);
Garfield Tandf26e862020-07-01 20:18:19 -0700559}
560
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -0800561static InputEventInjectionResult injectMotionEvent(
Linnan Li13bf76a2024-05-05 19:18:02 +0800562 InputDispatcher& dispatcher, int32_t action, int32_t source, ui::LogicalDisplayId displayId,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -0700563 const PointF& position = {100, 200},
Siarhei Vishniakou4cb50ca2020-05-26 21:43:02 -0700564 const PointF& cursorPosition = {AMOTION_EVENT_INVALID_CURSOR_POSITION,
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -0700565 AMOTION_EVENT_INVALID_CURSOR_POSITION},
566 std::chrono::milliseconds injectionTimeout = INJECT_EVENT_TIMEOUT,
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -0800567 InputEventInjectionSync injectionMode = InputEventInjectionSync::WAIT_FOR_RESULT,
Prabir Pradhan5735a322022-04-11 17:23:34 +0000568 nsecs_t eventTime = systemTime(SYSTEM_TIME_MONOTONIC),
Prabir Pradhan8a5c41d2023-06-08 19:13:46 +0000569 std::optional<gui::Uid> targetUid = {}, uint32_t policyFlags = DEFAULT_POLICY_FLAGS) {
Siarhei Vishniakou90ee4782023-05-08 11:57:24 -0700570 MotionEventBuilder motionBuilder =
571 MotionEventBuilder(action, source)
572 .displayId(displayId)
573 .eventTime(eventTime)
574 .rawXCursorPosition(cursorPosition.x)
575 .rawYCursorPosition(cursorPosition.y)
576 .pointer(
577 PointerBuilder(/*id=*/0, ToolType::FINGER).x(position.x).y(position.y));
578 if (MotionEvent::getActionMasked(action) == ACTION_DOWN) {
579 motionBuilder.downTime(eventTime);
580 }
Arthur Hungb92218b2018-08-14 12:00:21 +0800581
582 // Inject event until dispatch out.
Siarhei Vishniakou90ee4782023-05-08 11:57:24 -0700583 return injectMotionEvent(dispatcher, motionBuilder.build(), injectionTimeout, injectionMode,
584 targetUid, policyFlags);
Arthur Hungb92218b2018-08-14 12:00:21 +0800585}
586
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -0700587static InputEventInjectionResult injectMotionDown(InputDispatcher& dispatcher, int32_t source,
Linnan Li13bf76a2024-05-05 19:18:02 +0800588 ui::LogicalDisplayId displayId,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -0700589 const PointF& location = {100, 200}) {
Siarhei Vishniakou4cb50ca2020-05-26 21:43:02 -0700590 return injectMotionEvent(dispatcher, AMOTION_EVENT_ACTION_DOWN, source, displayId, location);
Garfield Tan00f511d2019-06-12 16:55:40 -0700591}
592
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -0700593static InputEventInjectionResult injectMotionUp(InputDispatcher& dispatcher, int32_t source,
Linnan Li13bf76a2024-05-05 19:18:02 +0800594 ui::LogicalDisplayId displayId,
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -0800595 const PointF& location = {100, 200}) {
Siarhei Vishniakou4cb50ca2020-05-26 21:43:02 -0700596 return injectMotionEvent(dispatcher, AMOTION_EVENT_ACTION_UP, source, displayId, location);
Michael Wright3a240c42019-12-10 20:53:41 +0000597}
598
Linnan Li13bf76a2024-05-05 19:18:02 +0800599static NotifyKeyArgs generateKeyArgs(int32_t action,
600 ui::LogicalDisplayId displayId = ui::ADISPLAY_ID_NONE) {
Jackal Guof9696682018-10-05 12:23:23 +0800601 nsecs_t currentTime = systemTime(SYSTEM_TIME_MONOTONIC);
602 // Define a valid key event.
Prabir Pradhana8fe7c52023-12-14 22:07:23 +0000603 NotifyKeyArgs args(InputEvent::nextId(), currentTime, /*readTime=*/0, DEVICE_ID,
604 AINPUT_SOURCE_KEYBOARD, displayId, POLICY_FLAG_PASS_TO_USER, action,
605 /*flags=*/0, AKEYCODE_A, KEY_A, AMETA_NONE, currentTime);
Jackal Guof9696682018-10-05 12:23:23 +0800606
607 return args;
608}
609
Linnan Li13bf76a2024-05-05 19:18:02 +0800610static NotifyKeyArgs generateSystemShortcutArgs(
611 int32_t action, ui::LogicalDisplayId displayId = ui::ADISPLAY_ID_NONE) {
Josep del Riob3981622023-04-18 15:49:45 +0000612 nsecs_t currentTime = systemTime(SYSTEM_TIME_MONOTONIC);
613 // Define a valid key event.
Prabir Pradhana8fe7c52023-12-14 22:07:23 +0000614 NotifyKeyArgs args(InputEvent::nextId(), currentTime, /*readTime=*/0, DEVICE_ID,
615 AINPUT_SOURCE_KEYBOARD, displayId, 0, action, /*flags=*/0, AKEYCODE_C, KEY_C,
616 AMETA_META_ON, currentTime);
Josep del Riob3981622023-04-18 15:49:45 +0000617
618 return args;
619}
620
Linnan Li13bf76a2024-05-05 19:18:02 +0800621static NotifyKeyArgs generateAssistantKeyArgs(
622 int32_t action, ui::LogicalDisplayId displayId = ui::ADISPLAY_ID_NONE) {
Josep del Riob3981622023-04-18 15:49:45 +0000623 nsecs_t currentTime = systemTime(SYSTEM_TIME_MONOTONIC);
624 // Define a valid key event.
Prabir Pradhana8fe7c52023-12-14 22:07:23 +0000625 NotifyKeyArgs args(InputEvent::nextId(), currentTime, /*readTime=*/0, DEVICE_ID,
626 AINPUT_SOURCE_KEYBOARD, displayId, 0, action, /*flags=*/0, AKEYCODE_ASSIST,
627 KEY_ASSISTANT, AMETA_NONE, currentTime);
Josep del Riob3981622023-04-18 15:49:45 +0000628
629 return args;
630}
631
Prabir Pradhan678438e2023-04-13 19:32:51 +0000632[[nodiscard]] static NotifyMotionArgs generateMotionArgs(int32_t action, int32_t source,
Linnan Li13bf76a2024-05-05 19:18:02 +0800633 ui::LogicalDisplayId displayId,
Prabir Pradhan678438e2023-04-13 19:32:51 +0000634 const std::vector<PointF>& points) {
chaviwd1c23182019-12-20 18:44:56 -0800635 size_t pointerCount = points.size();
chaviwaf87b3e2019-10-01 16:59:28 -0700636 if (action == AMOTION_EVENT_ACTION_DOWN || action == AMOTION_EVENT_ACTION_UP) {
637 EXPECT_EQ(1U, pointerCount) << "Actions DOWN and UP can only contain a single pointer";
638 }
639
chaviwd1c23182019-12-20 18:44:56 -0800640 PointerProperties pointerProperties[pointerCount];
641 PointerCoords pointerCoords[pointerCount];
Jackal Guof9696682018-10-05 12:23:23 +0800642
chaviwd1c23182019-12-20 18:44:56 -0800643 for (size_t i = 0; i < pointerCount; i++) {
644 pointerProperties[i].clear();
645 pointerProperties[i].id = i;
Siarhei Vishniakou6d73f832022-07-21 17:27:03 -0700646 pointerProperties[i].toolType = ToolType::FINGER;
Jackal Guof9696682018-10-05 12:23:23 +0800647
chaviwd1c23182019-12-20 18:44:56 -0800648 pointerCoords[i].clear();
649 pointerCoords[i].setAxisValue(AMOTION_EVENT_AXIS_X, points[i].x);
650 pointerCoords[i].setAxisValue(AMOTION_EVENT_AXIS_Y, points[i].y);
651 }
Jackal Guof9696682018-10-05 12:23:23 +0800652
653 nsecs_t currentTime = systemTime(SYSTEM_TIME_MONOTONIC);
654 // Define a valid motion event.
Prabir Pradhana8fe7c52023-12-14 22:07:23 +0000655 NotifyMotionArgs args(InputEvent::nextId(), currentTime, /*readTime=*/0, DEVICE_ID, source,
656 displayId, POLICY_FLAG_PASS_TO_USER, action, /*actionButton=*/0,
657 /*flags=*/0, AMETA_NONE, /*buttonState=*/0, MotionClassification::NONE,
chaviwd1c23182019-12-20 18:44:56 -0800658 AMOTION_EVENT_EDGE_FLAG_NONE, pointerCount, pointerProperties,
Harry Cutts101ee9b2023-07-06 18:04:14 +0000659 pointerCoords, /*xPrecision=*/0, /*yPrecision=*/0,
Garfield Tan00f511d2019-06-12 16:55:40 -0700660 AMOTION_EVENT_INVALID_CURSOR_POSITION,
Harry Cutts101ee9b2023-07-06 18:04:14 +0000661 AMOTION_EVENT_INVALID_CURSOR_POSITION, currentTime, /*videoFrames=*/{});
Jackal Guof9696682018-10-05 12:23:23 +0800662
663 return args;
664}
665
Siarhei Vishniakoua16e3a22022-03-02 15:26:40 -0800666static NotifyMotionArgs generateTouchArgs(int32_t action, const std::vector<PointF>& points) {
667 return generateMotionArgs(action, AINPUT_SOURCE_TOUCHSCREEN, DISPLAY_ID, points);
668}
669
Linnan Li13bf76a2024-05-05 19:18:02 +0800670static NotifyMotionArgs generateMotionArgs(int32_t action, int32_t source,
671 ui::LogicalDisplayId displayId) {
chaviwd1c23182019-12-20 18:44:56 -0800672 return generateMotionArgs(action, source, displayId, {PointF{100, 200}});
673}
674
Prabir Pradhan5cc1a692021-08-06 14:01:18 +0000675static NotifyPointerCaptureChangedArgs generatePointerCaptureChangedArgs(
676 const PointerCaptureRequest& request) {
Prabir Pradhana8fe7c52023-12-14 22:07:23 +0000677 return NotifyPointerCaptureChangedArgs(InputEvent::nextId(), systemTime(SYSTEM_TIME_MONOTONIC),
678 request);
Prabir Pradhan99987712020-11-10 18:43:05 -0800679}
680
Siarhei Vishniakouadeb6fa2023-05-26 09:11:06 -0700681} // namespace
682
Siarhei Vishniakou7aa3e942021-11-18 09:49:11 -0800683/**
684 * When a window unexpectedly disposes of its input channel, policy should be notified about the
685 * broken channel.
686 */
687TEST_F(InputDispatcherTest, WhenInputChannelBreaks_PolicyIsNotified) {
688 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
689 sp<FakeWindowHandle> window =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -0700690 sp<FakeWindowHandle>::make(application, mDispatcher,
691 "Window that breaks its input channel", ADISPLAY_ID_DEFAULT);
Siarhei Vishniakou7aa3e942021-11-18 09:49:11 -0800692
Siarhei Vishniakouc41de372023-07-20 13:14:26 -0700693 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Siarhei Vishniakou7aa3e942021-11-18 09:49:11 -0800694
695 // Window closes its channel, but the window remains.
696 window->destroyReceiver();
697 mFakePolicy->assertNotifyInputChannelBrokenWasCalled(window->getInfo()->token);
698}
699
Arthur Hungb92218b2018-08-14 12:00:21 +0800700TEST_F(InputDispatcherTest, SetInputWindow_SingleWindowTouch) {
Chris Yea209fde2020-07-22 13:54:51 -0700701 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -0700702 sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher,
703 "Fake Window", ADISPLAY_ID_DEFAULT);
Arthur Hungb92218b2018-08-14 12:00:21 +0800704
Siarhei Vishniakouc41de372023-07-20 13:14:26 -0700705 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -0800706 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -0700707 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT))
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -0800708 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
Arthur Hungb92218b2018-08-14 12:00:21 +0800709
710 // Window should receive motion event.
Siarhei Vishniakouc5ca85c2019-11-15 17:20:00 -0800711 window->consumeMotionDown(ADISPLAY_ID_DEFAULT);
Arthur Hungb92218b2018-08-14 12:00:21 +0800712}
713
Siarhei Vishniakouaeed0da2024-01-09 08:57:13 -0800714using InputDispatcherDeathTest = InputDispatcherTest;
715
716/**
717 * When 'onWindowInfosChanged' arguments contain a duplicate entry for the same window, dispatcher
718 * should crash.
719 */
720TEST_F(InputDispatcherDeathTest, DuplicateWindowInfosAbortDispatcher) {
721 testing::GTEST_FLAG(death_test_style) = "threadsafe";
722 ScopedSilentDeath _silentDeath;
723
724 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
725 sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher,
726 "Fake Window", ADISPLAY_ID_DEFAULT);
727 ASSERT_DEATH(mDispatcher->onWindowInfosChanged(
728 {{*window->getInfo(), *window->getInfo()}, {}, 0, 0}),
729 "Incorrect WindowInfosUpdate provided");
730}
731
Prabir Pradhanc44ce4d2021-10-05 05:26:29 -0700732TEST_F(InputDispatcherTest, WhenDisplayNotSpecified_InjectMotionToDefaultDisplay) {
733 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -0700734 sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher,
735 "Fake Window", ADISPLAY_ID_DEFAULT);
Prabir Pradhanc44ce4d2021-10-05 05:26:29 -0700736
Siarhei Vishniakouc41de372023-07-20 13:14:26 -0700737 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Prabir Pradhanc44ce4d2021-10-05 05:26:29 -0700738 // Inject a MotionEvent to an unknown display.
739 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Linnan Li13bf76a2024-05-05 19:18:02 +0800740 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ui::ADISPLAY_ID_NONE))
Prabir Pradhanc44ce4d2021-10-05 05:26:29 -0700741 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
742
743 // Window should receive motion event.
744 window->consumeMotionDown(ADISPLAY_ID_DEFAULT);
745}
746
Siarhei Vishniakoufb9fcda2020-05-04 14:59:19 -0700747/**
Siarhei Vishniakouc41de372023-07-20 13:14:26 -0700748 * Calling onWindowInfosChanged once should not cause any issues.
749 * This test serves as a sanity check for the next test, where onWindowInfosChanged is
Siarhei Vishniakoufb9fcda2020-05-04 14:59:19 -0700750 * called twice.
751 */
Prabir Pradhan76bdecb2022-01-31 11:14:15 -0800752TEST_F(InputDispatcherTest, SetInputWindowOnceWithSingleTouchWindow) {
Chris Yea209fde2020-07-22 13:54:51 -0700753 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -0700754 sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher,
755 "Fake Window", ADISPLAY_ID_DEFAULT);
Siarhei Vishniakoufb9fcda2020-05-04 14:59:19 -0700756 window->setFrame(Rect(0, 0, 100, 100));
Siarhei Vishniakoufb9fcda2020-05-04 14:59:19 -0700757
Siarhei Vishniakouc41de372023-07-20 13:14:26 -0700758 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -0800759 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -0700760 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
Siarhei Vishniakoufb9fcda2020-05-04 14:59:19 -0700761 {50, 50}))
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -0800762 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
Siarhei Vishniakoufb9fcda2020-05-04 14:59:19 -0700763
764 // Window should receive motion event.
765 window->consumeMotionDown(ADISPLAY_ID_DEFAULT);
766}
767
768/**
Siarhei Vishniakouc41de372023-07-20 13:14:26 -0700769 * Calling onWindowInfosChanged twice, with the same info, should not cause any issues.
Siarhei Vishniakoufb9fcda2020-05-04 14:59:19 -0700770 */
771TEST_F(InputDispatcherTest, SetInputWindowTwice_SingleWindowTouch) {
Chris Yea209fde2020-07-22 13:54:51 -0700772 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -0700773 sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher,
774 "Fake Window", ADISPLAY_ID_DEFAULT);
Siarhei Vishniakoufb9fcda2020-05-04 14:59:19 -0700775 window->setFrame(Rect(0, 0, 100, 100));
Siarhei Vishniakoufb9fcda2020-05-04 14:59:19 -0700776
Siarhei Vishniakouc41de372023-07-20 13:14:26 -0700777 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
778 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -0800779 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -0700780 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
Siarhei Vishniakoufb9fcda2020-05-04 14:59:19 -0700781 {50, 50}))
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -0800782 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
Siarhei Vishniakoufb9fcda2020-05-04 14:59:19 -0700783
784 // Window should receive motion event.
785 window->consumeMotionDown(ADISPLAY_ID_DEFAULT);
786}
787
Arthur Hungb92218b2018-08-14 12:00:21 +0800788// The foreground window should receive the first touch down event.
789TEST_F(InputDispatcherTest, SetInputWindow_MultiWindowsTouch) {
Chris Yea209fde2020-07-22 13:54:51 -0700790 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
Siarhei Vishniakou870ecec2020-12-09 08:07:46 -1000791 sp<FakeWindowHandle> windowTop =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -0700792 sp<FakeWindowHandle>::make(application, mDispatcher, "Top", ADISPLAY_ID_DEFAULT);
Siarhei Vishniakou870ecec2020-12-09 08:07:46 -1000793 sp<FakeWindowHandle> windowSecond =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -0700794 sp<FakeWindowHandle>::make(application, mDispatcher, "Second", ADISPLAY_ID_DEFAULT);
Arthur Hungb92218b2018-08-14 12:00:21 +0800795
Siarhei Vishniakouc41de372023-07-20 13:14:26 -0700796 mDispatcher->onWindowInfosChanged(
797 {{*windowTop->getInfo(), *windowSecond->getInfo()}, {}, 0, 0});
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -0800798 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -0700799 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT))
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -0800800 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
Arthur Hungb92218b2018-08-14 12:00:21 +0800801
802 // Top window should receive the touch down event. Second window should not receive anything.
Siarhei Vishniakouc5ca85c2019-11-15 17:20:00 -0800803 windowTop->consumeMotionDown(ADISPLAY_ID_DEFAULT);
Arthur Hungb92218b2018-08-14 12:00:21 +0800804 windowSecond->assertNoEvents();
805}
806
Siarhei Vishniakouca205502021-07-16 21:31:58 +0000807/**
808 * Two windows: A top window, and a wallpaper behind the window.
809 * Touch goes to the top window, and then top window disappears. Ensure that wallpaper window
810 * gets ACTION_CANCEL.
Prabir Pradhan4d5c52f2022-01-31 08:52:10 -0800811 * 1. foregroundWindow <-- dup touch to wallpaper
812 * 2. wallpaperWindow <-- is wallpaper
Siarhei Vishniakouca205502021-07-16 21:31:58 +0000813 */
814TEST_F(InputDispatcherTest, WhenForegroundWindowDisappears_WallpaperTouchIsCanceled) {
815 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
816 sp<FakeWindowHandle> foregroundWindow =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -0700817 sp<FakeWindowHandle>::make(application, mDispatcher, "Foreground", ADISPLAY_ID_DEFAULT);
Prabir Pradhan4d5c52f2022-01-31 08:52:10 -0800818 foregroundWindow->setDupTouchToWallpaper(true);
Siarhei Vishniakouca205502021-07-16 21:31:58 +0000819 sp<FakeWindowHandle> wallpaperWindow =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -0700820 sp<FakeWindowHandle>::make(application, mDispatcher, "Wallpaper", ADISPLAY_ID_DEFAULT);
Prabir Pradhan4d5c52f2022-01-31 08:52:10 -0800821 wallpaperWindow->setIsWallpaper(true);
Siarhei Vishniakouca205502021-07-16 21:31:58 +0000822
Siarhei Vishniakouc41de372023-07-20 13:14:26 -0700823 mDispatcher->onWindowInfosChanged(
824 {{*foregroundWindow->getInfo(), *wallpaperWindow->getInfo()}, {}, 0, 0});
Siarhei Vishniakouca205502021-07-16 21:31:58 +0000825 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoud908f5a2023-11-16 10:25:12 -0800826 injectMotionEvent(*mDispatcher,
827 MotionEventBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
828 .pointer(PointerBuilder(0, ToolType::FINGER).x(100).y(200))
829 .build()))
Siarhei Vishniakouca205502021-07-16 21:31:58 +0000830 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
831
832 // Both foreground window and its wallpaper should receive the touch down
833 foregroundWindow->consumeMotionDown();
Linnan Li72352222024-04-12 18:55:57 +0800834 wallpaperWindow->consumeMotionDown(ADISPLAY_ID_DEFAULT, EXPECTED_WALLPAPER_FLAGS);
Siarhei Vishniakouca205502021-07-16 21:31:58 +0000835
836 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoud908f5a2023-11-16 10:25:12 -0800837 injectMotionEvent(*mDispatcher,
838 MotionEventBuilder(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN)
839 .pointer(PointerBuilder(0, ToolType::FINGER).x(110).y(200))
840 .build()))
Siarhei Vishniakouca205502021-07-16 21:31:58 +0000841 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
842
Siarhei Vishniakoud908f5a2023-11-16 10:25:12 -0800843 foregroundWindow->consumeMotionEvent(WithMotionAction(ACTION_MOVE));
Linnan Li72352222024-04-12 18:55:57 +0800844 wallpaperWindow->consumeMotionMove(ADISPLAY_ID_DEFAULT, EXPECTED_WALLPAPER_FLAGS);
Siarhei Vishniakouca205502021-07-16 21:31:58 +0000845
846 // Now the foreground window goes away, but the wallpaper stays
Siarhei Vishniakouc41de372023-07-20 13:14:26 -0700847 mDispatcher->onWindowInfosChanged({{*wallpaperWindow->getInfo()}, {}, 0, 0});
Siarhei Vishniakouca205502021-07-16 21:31:58 +0000848 foregroundWindow->consumeMotionCancel();
849 // Since the "parent" window of the wallpaper is gone, wallpaper should receive cancel, too.
Linnan Li72352222024-04-12 18:55:57 +0800850 wallpaperWindow->consumeMotionCancel(ADISPLAY_ID_DEFAULT, EXPECTED_WALLPAPER_FLAGS);
Siarhei Vishniakouca205502021-07-16 21:31:58 +0000851}
852
853/**
Siarhei Vishniakou82dc0422023-02-17 23:12:52 -0800854 * Two fingers down on the window, and lift off the first finger.
855 * Next, cancel the gesture to the window by removing the window. Make sure that the CANCEL event
856 * contains a single pointer.
857 */
858TEST_F(InputDispatcherTest, CancelAfterPointer0Up) {
859 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
860 sp<FakeWindowHandle> window =
861 sp<FakeWindowHandle>::make(application, mDispatcher, "Window", ADISPLAY_ID_DEFAULT);
862
Siarhei Vishniakouc41de372023-07-20 13:14:26 -0700863 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Siarhei Vishniakou82dc0422023-02-17 23:12:52 -0800864 // First touch pointer down on right window
Prabir Pradhan678438e2023-04-13 19:32:51 +0000865 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
866 .pointer(PointerBuilder(0, ToolType::FINGER).x(100).y(100))
867 .build());
Siarhei Vishniakou82dc0422023-02-17 23:12:52 -0800868 // Second touch pointer down
Prabir Pradhan678438e2023-04-13 19:32:51 +0000869 mDispatcher->notifyMotion(MotionArgsBuilder(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
870 .pointer(PointerBuilder(0, ToolType::FINGER).x(100).y(100))
871 .pointer(PointerBuilder(1, ToolType::FINGER).x(110).y(100))
872 .build());
Siarhei Vishniakou82dc0422023-02-17 23:12:52 -0800873 // First touch pointer lifts. The second one remains down
Prabir Pradhan678438e2023-04-13 19:32:51 +0000874 mDispatcher->notifyMotion(MotionArgsBuilder(POINTER_0_UP, AINPUT_SOURCE_TOUCHSCREEN)
875 .pointer(PointerBuilder(0, ToolType::FINGER).x(100).y(100))
876 .pointer(PointerBuilder(1, ToolType::FINGER).x(110).y(100))
877 .build());
Siarhei Vishniakou82dc0422023-02-17 23:12:52 -0800878 window->consumeMotionEvent(WithMotionAction(ACTION_DOWN));
879 window->consumeMotionEvent(WithMotionAction(POINTER_1_DOWN));
880 window->consumeMotionEvent(WithMotionAction(POINTER_0_UP));
881
882 // Remove the window. The gesture should be canceled
Siarhei Vishniakouc41de372023-07-20 13:14:26 -0700883 mDispatcher->onWindowInfosChanged({{}, {}, 0, 0});
Siarhei Vishniakou82dc0422023-02-17 23:12:52 -0800884 const std::map<int32_t, PointF> expectedPointers{{1, PointF{110, 100}}};
885 window->consumeMotionEvent(
886 AllOf(WithMotionAction(ACTION_CANCEL), WithPointers(expectedPointers)));
887}
888
889/**
Siarhei Vishniakou2b030972021-11-18 10:01:27 -0800890 * Same test as WhenForegroundWindowDisappears_WallpaperTouchIsCanceled above,
891 * with the following differences:
892 * After ACTION_DOWN, Wallpaper window hangs up its channel, which forces the dispatcher to
893 * clean up the connection.
894 * This later may crash dispatcher during ACTION_CANCEL synthesis, if the dispatcher is not careful.
895 * Ensure that there's no crash in the dispatcher.
896 */
897TEST_F(InputDispatcherTest, WhenWallpaperDisappears_NoCrash) {
898 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
899 sp<FakeWindowHandle> foregroundWindow =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -0700900 sp<FakeWindowHandle>::make(application, mDispatcher, "Foreground", ADISPLAY_ID_DEFAULT);
Prabir Pradhan4d5c52f2022-01-31 08:52:10 -0800901 foregroundWindow->setDupTouchToWallpaper(true);
Siarhei Vishniakou2b030972021-11-18 10:01:27 -0800902 sp<FakeWindowHandle> wallpaperWindow =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -0700903 sp<FakeWindowHandle>::make(application, mDispatcher, "Wallpaper", ADISPLAY_ID_DEFAULT);
Prabir Pradhan4d5c52f2022-01-31 08:52:10 -0800904 wallpaperWindow->setIsWallpaper(true);
Siarhei Vishniakou2b030972021-11-18 10:01:27 -0800905
Siarhei Vishniakouc41de372023-07-20 13:14:26 -0700906 mDispatcher->onWindowInfosChanged(
907 {{*foregroundWindow->getInfo(), *wallpaperWindow->getInfo()}, {}, 0, 0});
Siarhei Vishniakou2b030972021-11-18 10:01:27 -0800908 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -0700909 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
Siarhei Vishniakou2b030972021-11-18 10:01:27 -0800910 {100, 200}))
911 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
912
913 // Both foreground window and its wallpaper should receive the touch down
914 foregroundWindow->consumeMotionDown();
Linnan Li72352222024-04-12 18:55:57 +0800915 wallpaperWindow->consumeMotionDown(ADISPLAY_ID_DEFAULT, EXPECTED_WALLPAPER_FLAGS);
Siarhei Vishniakou2b030972021-11-18 10:01:27 -0800916
917 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -0700918 injectMotionEvent(*mDispatcher, AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN,
Siarhei Vishniakou2b030972021-11-18 10:01:27 -0800919 ADISPLAY_ID_DEFAULT, {110, 200}))
920 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
921
922 foregroundWindow->consumeMotionMove();
Linnan Li72352222024-04-12 18:55:57 +0800923 wallpaperWindow->consumeMotionMove(ADISPLAY_ID_DEFAULT, EXPECTED_WALLPAPER_FLAGS);
Siarhei Vishniakou2b030972021-11-18 10:01:27 -0800924
925 // Wallpaper closes its channel, but the window remains.
926 wallpaperWindow->destroyReceiver();
927 mFakePolicy->assertNotifyInputChannelBrokenWasCalled(wallpaperWindow->getInfo()->token);
928
929 // Now the foreground window goes away, but the wallpaper stays, even though its channel
930 // is no longer valid.
Siarhei Vishniakouc41de372023-07-20 13:14:26 -0700931 mDispatcher->onWindowInfosChanged({{*wallpaperWindow->getInfo()}, {}, 0, 0});
Siarhei Vishniakou2b030972021-11-18 10:01:27 -0800932 foregroundWindow->consumeMotionCancel();
933}
934
Linnan Li72352222024-04-12 18:55:57 +0800935/**
936 * Two windows: left and right, and a separate wallpaper window underneath each. Device A sends a
937 * down event to the left window. Device B sends a down event to the right window. Next, the right
938 * window disappears. Both the right window and its wallpaper window should receive cancel event.
939 * The left window and its wallpaper window should not receive any events.
940 */
941TEST_F(InputDispatcherTest, MultiDeviceDisappearingWindowWithWallpaperWindows) {
942 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
943 sp<FakeWindowHandle> leftForegroundWindow =
944 sp<FakeWindowHandle>::make(application, mDispatcher, "Left foreground window",
945 ADISPLAY_ID_DEFAULT);
946 leftForegroundWindow->setFrame(Rect(0, 0, 100, 100));
947 leftForegroundWindow->setDupTouchToWallpaper(true);
948 sp<FakeWindowHandle> leftWallpaperWindow =
949 sp<FakeWindowHandle>::make(application, mDispatcher, "Left wallpaper window",
950 ADISPLAY_ID_DEFAULT);
951 leftWallpaperWindow->setFrame(Rect(0, 0, 100, 100));
952 leftWallpaperWindow->setIsWallpaper(true);
953
954 sp<FakeWindowHandle> rightForegroundWindow =
955 sp<FakeWindowHandle>::make(application, mDispatcher, "Right foreground window",
956 ADISPLAY_ID_DEFAULT);
957 rightForegroundWindow->setFrame(Rect(100, 0, 200, 100));
958 rightForegroundWindow->setDupTouchToWallpaper(true);
959 sp<FakeWindowHandle> rightWallpaperWindow =
960 sp<FakeWindowHandle>::make(application, mDispatcher, "Right wallpaper window",
961 ADISPLAY_ID_DEFAULT);
962 rightWallpaperWindow->setFrame(Rect(100, 0, 200, 100));
963 rightWallpaperWindow->setIsWallpaper(true);
964
965 mDispatcher->onWindowInfosChanged(
966 {{*leftForegroundWindow->getInfo(), *leftWallpaperWindow->getInfo(),
967 *rightForegroundWindow->getInfo(), *rightWallpaperWindow->getInfo()},
968 {},
969 0,
970 0});
971
972 const DeviceId deviceA = 9;
973 const DeviceId deviceB = 3;
974 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
975 .pointer(PointerBuilder(0, ToolType::FINGER).x(50).y(50))
976 .deviceId(deviceA)
977 .build());
978 leftForegroundWindow->consumeMotionEvent(
979 AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(deviceA)));
980 leftWallpaperWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN),
981 WithDeviceId(deviceA),
982 WithFlags(EXPECTED_WALLPAPER_FLAGS)));
983
984 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
985 .pointer(PointerBuilder(0, ToolType::FINGER).x(150).y(50))
986 .deviceId(deviceB)
987 .build());
988 rightForegroundWindow->consumeMotionEvent(
989 AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(deviceB)));
990 rightWallpaperWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN),
991 WithDeviceId(deviceB),
992 WithFlags(EXPECTED_WALLPAPER_FLAGS)));
993
994 // Now right foreground window disappears, but right wallpaper window remains.
995 mDispatcher->onWindowInfosChanged(
996 {{*leftForegroundWindow->getInfo(), *leftWallpaperWindow->getInfo(),
997 *rightWallpaperWindow->getInfo()},
998 {},
999 0,
1000 0});
1001
1002 // Left foreground window and left wallpaper window still exist, and should not receive any
1003 // events.
1004 leftForegroundWindow->assertNoEvents();
1005 leftWallpaperWindow->assertNoEvents();
1006 // Since right foreground window disappeared, right wallpaper window and right foreground window
1007 // should receive cancel events.
1008 rightForegroundWindow->consumeMotionEvent(
1009 AllOf(WithMotionAction(ACTION_CANCEL), WithDeviceId(deviceB)));
1010 rightWallpaperWindow->consumeMotionEvent(
1011 AllOf(WithMotionAction(ACTION_CANCEL), WithDeviceId(deviceB),
1012 WithFlags(EXPECTED_WALLPAPER_FLAGS | AMOTION_EVENT_FLAG_CANCELED)));
1013}
1014
1015/**
1016 * Three windows arranged horizontally and without any overlap. Every window has a
1017 * wallpaper window underneath. The middle window also has SLIPPERY flag.
1018 * Device A sends a down event to the left window. Device B sends a down event to the middle window.
1019 * Next, device B sends move event to the right window. Touch for device B should slip from the
1020 * middle window to the right window. Also, the right wallpaper window should receive a down event.
1021 * The middle window and its wallpaper window should receive a cancel event. The left window should
1022 * not receive any events. If device B continues to report events, the right window and its
1023 * wallpaper window should receive remaining events.
1024 */
1025TEST_F(InputDispatcherTest, MultiDeviceSlipperyTouchWithWallpaperWindow) {
1026 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
1027 sp<FakeWindowHandle> leftForegroundWindow =
1028 sp<FakeWindowHandle>::make(application, mDispatcher, "Left foreground window",
1029 ADISPLAY_ID_DEFAULT);
1030 leftForegroundWindow->setFrame(Rect(0, 0, 100, 100));
1031 leftForegroundWindow->setDupTouchToWallpaper(true);
1032 sp<FakeWindowHandle> leftWallpaperWindow =
1033 sp<FakeWindowHandle>::make(application, mDispatcher, "Left wallpaper window",
1034 ADISPLAY_ID_DEFAULT);
1035 leftWallpaperWindow->setFrame(Rect(0, 0, 100, 100));
1036 leftWallpaperWindow->setIsWallpaper(true);
1037
1038 sp<FakeWindowHandle> middleForegroundWindow =
1039 sp<FakeWindowHandle>::make(application, mDispatcher, "Middle foreground window",
1040 ADISPLAY_ID_DEFAULT);
1041 middleForegroundWindow->setFrame(Rect(100, 0, 200, 100));
1042 middleForegroundWindow->setDupTouchToWallpaper(true);
1043 middleForegroundWindow->setSlippery(true);
1044 sp<FakeWindowHandle> middleWallpaperWindow =
1045 sp<FakeWindowHandle>::make(application, mDispatcher, "Middle wallpaper window",
1046 ADISPLAY_ID_DEFAULT);
1047 middleWallpaperWindow->setFrame(Rect(100, 0, 200, 100));
1048 middleWallpaperWindow->setIsWallpaper(true);
1049
1050 sp<FakeWindowHandle> rightForegroundWindow =
1051 sp<FakeWindowHandle>::make(application, mDispatcher, "Right foreground window",
1052 ADISPLAY_ID_DEFAULT);
1053 rightForegroundWindow->setFrame(Rect(200, 0, 300, 100));
1054 rightForegroundWindow->setDupTouchToWallpaper(true);
1055 sp<FakeWindowHandle> rightWallpaperWindow =
1056 sp<FakeWindowHandle>::make(application, mDispatcher, "Right wallpaper window",
1057 ADISPLAY_ID_DEFAULT);
1058 rightWallpaperWindow->setFrame(Rect(200, 0, 300, 100));
1059 rightWallpaperWindow->setIsWallpaper(true);
1060
1061 mDispatcher->onWindowInfosChanged(
1062 {{*leftForegroundWindow->getInfo(), *leftWallpaperWindow->getInfo(),
1063 *middleForegroundWindow->getInfo(), *middleWallpaperWindow->getInfo(),
1064 *rightForegroundWindow->getInfo(), *rightWallpaperWindow->getInfo()},
1065 {},
1066 0,
1067 0});
1068
1069 const DeviceId deviceA = 9;
1070 const DeviceId deviceB = 3;
1071 // Device A sends a DOWN event to the left window
1072 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
1073 .pointer(PointerBuilder(0, ToolType::FINGER).x(50).y(50))
1074 .deviceId(deviceA)
1075 .build());
1076 leftForegroundWindow->consumeMotionEvent(
1077 AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(deviceA)));
1078 leftWallpaperWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN),
1079 WithDeviceId(deviceA),
1080 WithFlags(EXPECTED_WALLPAPER_FLAGS)));
1081 // Device B sends a DOWN event to the middle window
1082 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
1083 .pointer(PointerBuilder(0, ToolType::FINGER).x(150).y(50))
1084 .deviceId(deviceB)
1085 .build());
1086 middleForegroundWindow->consumeMotionEvent(
1087 AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(deviceB)));
1088 middleWallpaperWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN),
1089 WithDeviceId(deviceB),
1090 WithFlags(EXPECTED_WALLPAPER_FLAGS)));
1091 // Move the events of device B to the top of the right window.
1092 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN)
1093 .pointer(PointerBuilder(0, ToolType::FINGER).x(250).y(50))
1094 .deviceId(deviceB)
1095 .build());
1096 middleForegroundWindow->consumeMotionEvent(
1097 AllOf(WithMotionAction(ACTION_CANCEL), WithDeviceId(deviceB)));
1098 middleWallpaperWindow->consumeMotionEvent(
1099 AllOf(WithMotionAction(ACTION_CANCEL), WithDeviceId(deviceB),
1100 WithFlags(EXPECTED_WALLPAPER_FLAGS | AMOTION_EVENT_FLAG_CANCELED)));
1101 rightForegroundWindow->consumeMotionEvent(
1102 AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(deviceB)));
1103 rightWallpaperWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN),
1104 WithDeviceId(deviceB),
1105 WithFlags(EXPECTED_WALLPAPER_FLAGS)));
1106 // Make sure the window on the right can receive the remaining events.
1107 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN)
1108 .pointer(PointerBuilder(0, ToolType::FINGER).x(251).y(51))
1109 .deviceId(deviceB)
1110 .build());
1111 leftForegroundWindow->assertNoEvents();
1112 leftWallpaperWindow->assertNoEvents();
1113 middleForegroundWindow->assertNoEvents();
1114 middleWallpaperWindow->assertNoEvents();
1115 rightForegroundWindow->consumeMotionEvent(
1116 AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(deviceB)));
1117 rightWallpaperWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_MOVE),
1118 WithDeviceId(deviceB),
1119 WithFlags(EXPECTED_WALLPAPER_FLAGS)));
1120}
1121
1122/**
1123 * Similar to the test above, we have three windows, they are arranged horizontally and without any
1124 * overlap, and every window has a wallpaper window. The middle window is a simple window, without
1125 * any special flags. Device A reports a down event that lands in left window. Device B sends a down
1126 * event to the middle window and then touch is transferred from the middle window to the right
1127 * window. The right window and its wallpaper window should receive a down event. The middle window
1128 * and its wallpaper window should receive a cancel event. The left window should not receive any
1129 * events. Subsequent events reported by device B should go to the right window and its wallpaper.
1130 */
1131TEST_F(InputDispatcherTest, MultiDeviceTouchTransferWithWallpaperWindows) {
1132 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
1133 sp<FakeWindowHandle> leftForegroundWindow =
1134 sp<FakeWindowHandle>::make(application, mDispatcher, "Left foreground window",
1135 ADISPLAY_ID_DEFAULT);
1136 leftForegroundWindow->setFrame(Rect(0, 0, 100, 100));
1137 leftForegroundWindow->setDupTouchToWallpaper(true);
1138 sp<FakeWindowHandle> leftWallpaperWindow =
1139 sp<FakeWindowHandle>::make(application, mDispatcher, "Left wallpaper window",
1140 ADISPLAY_ID_DEFAULT);
1141 leftWallpaperWindow->setFrame(Rect(0, 0, 100, 100));
1142 leftWallpaperWindow->setIsWallpaper(true);
1143
1144 sp<FakeWindowHandle> middleForegroundWindow =
1145 sp<FakeWindowHandle>::make(application, mDispatcher, "Middle foreground window",
1146 ADISPLAY_ID_DEFAULT);
1147 middleForegroundWindow->setFrame(Rect(100, 0, 200, 100));
1148 middleForegroundWindow->setDupTouchToWallpaper(true);
1149 sp<FakeWindowHandle> middleWallpaperWindow =
1150 sp<FakeWindowHandle>::make(application, mDispatcher, "Middle wallpaper window",
1151 ADISPLAY_ID_DEFAULT);
1152 middleWallpaperWindow->setFrame(Rect(100, 0, 200, 100));
1153 middleWallpaperWindow->setIsWallpaper(true);
1154
1155 sp<FakeWindowHandle> rightForegroundWindow =
1156 sp<FakeWindowHandle>::make(application, mDispatcher, "Right foreground window",
1157 ADISPLAY_ID_DEFAULT);
1158 rightForegroundWindow->setFrame(Rect(200, 0, 300, 100));
1159 rightForegroundWindow->setDupTouchToWallpaper(true);
1160 sp<FakeWindowHandle> rightWallpaperWindow =
1161 sp<FakeWindowHandle>::make(application, mDispatcher, "Right wallpaper window",
1162 ADISPLAY_ID_DEFAULT);
1163 rightWallpaperWindow->setFrame(Rect(200, 0, 300, 100));
1164 rightWallpaperWindow->setIsWallpaper(true);
1165
1166 mDispatcher->onWindowInfosChanged(
1167 {{*leftForegroundWindow->getInfo(), *leftWallpaperWindow->getInfo(),
1168 *middleForegroundWindow->getInfo(), *middleWallpaperWindow->getInfo(),
1169 *rightForegroundWindow->getInfo(), *rightWallpaperWindow->getInfo()},
1170 {},
1171 0,
1172 0});
1173
1174 const DeviceId deviceA = 9;
1175 const DeviceId deviceB = 3;
1176 // Device A touch down on the left window
1177 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
1178 .pointer(PointerBuilder(0, ToolType::FINGER).x(50).y(50))
1179 .deviceId(deviceA)
1180 .build());
1181 leftForegroundWindow->consumeMotionEvent(
1182 AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(deviceA)));
1183 leftWallpaperWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN),
1184 WithDeviceId(deviceA),
1185 WithFlags(EXPECTED_WALLPAPER_FLAGS)));
1186 // Device B touch down on the middle window
1187 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
1188 .pointer(PointerBuilder(0, ToolType::FINGER).x(150).y(50))
1189 .deviceId(deviceB)
1190 .build());
1191 middleForegroundWindow->consumeMotionEvent(
1192 AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(deviceB)));
1193 middleWallpaperWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN),
1194 WithDeviceId(deviceB),
1195 WithFlags(EXPECTED_WALLPAPER_FLAGS)));
1196
1197 // Transfer touch from the middle window to the right window.
1198 ASSERT_TRUE(mDispatcher->transferTouchGesture(middleForegroundWindow->getToken(),
1199 rightForegroundWindow->getToken()));
1200
1201 middleForegroundWindow->consumeMotionEvent(
1202 AllOf(WithMotionAction(ACTION_CANCEL), WithDeviceId(deviceB)));
1203 middleWallpaperWindow->consumeMotionEvent(
1204 AllOf(WithMotionAction(ACTION_CANCEL), WithDeviceId(deviceB),
1205 WithFlags(EXPECTED_WALLPAPER_FLAGS | AMOTION_EVENT_FLAG_CANCELED)));
1206 rightForegroundWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN),
1207 WithDeviceId(deviceB),
1208 WithFlags(AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE)));
1209 rightWallpaperWindow->consumeMotionEvent(
1210 AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(deviceB),
1211 WithFlags(EXPECTED_WALLPAPER_FLAGS | AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE)));
1212
1213 // Make sure the right window can receive the remaining events.
1214 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN)
1215 .pointer(PointerBuilder(0, ToolType::FINGER).x(251).y(51))
1216 .deviceId(deviceB)
1217 .build());
1218 leftForegroundWindow->assertNoEvents();
1219 leftWallpaperWindow->assertNoEvents();
1220 middleForegroundWindow->assertNoEvents();
1221 middleWallpaperWindow->assertNoEvents();
1222 rightForegroundWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_MOVE),
1223 WithDeviceId(deviceB),
1224 WithFlags(AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE)));
1225 rightWallpaperWindow->consumeMotionEvent(
1226 AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(deviceB),
1227 WithFlags(EXPECTED_WALLPAPER_FLAGS | AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE)));
1228}
1229
Arthur Hungc539dbb2022-12-08 07:45:36 +00001230class ShouldSplitTouchFixture : public InputDispatcherTest,
1231 public ::testing::WithParamInterface<bool> {};
1232INSTANTIATE_TEST_SUITE_P(InputDispatcherTest, ShouldSplitTouchFixture,
1233 ::testing::Values(true, false));
Siarhei Vishniakou2b030972021-11-18 10:01:27 -08001234/**
Siarhei Vishniakouca205502021-07-16 21:31:58 +00001235 * A single window that receives touch (on top), and a wallpaper window underneath it.
1236 * The top window gets a multitouch gesture.
1237 * Ensure that wallpaper gets the same gesture.
1238 */
Arthur Hungc539dbb2022-12-08 07:45:36 +00001239TEST_P(ShouldSplitTouchFixture, WallpaperWindowReceivesMultiTouch) {
Siarhei Vishniakouca205502021-07-16 21:31:58 +00001240 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
Arthur Hungc539dbb2022-12-08 07:45:36 +00001241 sp<FakeWindowHandle> foregroundWindow =
1242 sp<FakeWindowHandle>::make(application, mDispatcher, "Foreground", ADISPLAY_ID_DEFAULT);
1243 foregroundWindow->setDupTouchToWallpaper(true);
1244 foregroundWindow->setPreventSplitting(GetParam());
Siarhei Vishniakouca205502021-07-16 21:31:58 +00001245
1246 sp<FakeWindowHandle> wallpaperWindow =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07001247 sp<FakeWindowHandle>::make(application, mDispatcher, "Wallpaper", ADISPLAY_ID_DEFAULT);
Prabir Pradhan4d5c52f2022-01-31 08:52:10 -08001248 wallpaperWindow->setIsWallpaper(true);
Siarhei Vishniakouca205502021-07-16 21:31:58 +00001249
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07001250 mDispatcher->onWindowInfosChanged(
1251 {{*foregroundWindow->getInfo(), *wallpaperWindow->getInfo()}, {}, 0, 0});
Siarhei Vishniakouca205502021-07-16 21:31:58 +00001252
1253 // Touch down on top window
1254 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07001255 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
Siarhei Vishniakouca205502021-07-16 21:31:58 +00001256 {100, 100}))
1257 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
1258
1259 // Both top window and its wallpaper should receive the touch down
Arthur Hungc539dbb2022-12-08 07:45:36 +00001260 foregroundWindow->consumeMotionDown();
Linnan Li72352222024-04-12 18:55:57 +08001261 wallpaperWindow->consumeMotionDown(ADISPLAY_ID_DEFAULT, EXPECTED_WALLPAPER_FLAGS);
Siarhei Vishniakouca205502021-07-16 21:31:58 +00001262
1263 // Second finger down on the top window
1264 const MotionEvent secondFingerDownEvent =
Siarhei Vishniakoua16e3a22022-03-02 15:26:40 -08001265 MotionEventBuilder(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
Siarhei Vishniakouca205502021-07-16 21:31:58 +00001266 .eventTime(systemTime(SYSTEM_TIME_MONOTONIC))
Siarhei Vishniakou6d73f832022-07-21 17:27:03 -07001267 .pointer(PointerBuilder(/*id=*/0, ToolType::FINGER).x(100).y(100))
1268 .pointer(PointerBuilder(/*id=*/1, ToolType::FINGER).x(150).y(150))
Siarhei Vishniakouca205502021-07-16 21:31:58 +00001269 .build();
1270 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07001271 injectMotionEvent(*mDispatcher, secondFingerDownEvent, INJECT_EVENT_TIMEOUT,
Siarhei Vishniakouca205502021-07-16 21:31:58 +00001272 InputEventInjectionSync::WAIT_FOR_RESULT))
1273 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
Harry Cutts33476232023-01-30 19:57:29 +00001274 foregroundWindow->consumeMotionPointerDown(/*pointerIndex=*/1);
1275 wallpaperWindow->consumeMotionPointerDown(/*pointerIndex=*/1, ADISPLAY_ID_DEFAULT,
Linnan Li72352222024-04-12 18:55:57 +08001276 EXPECTED_WALLPAPER_FLAGS);
Arthur Hungc539dbb2022-12-08 07:45:36 +00001277
1278 const MotionEvent secondFingerUpEvent =
1279 MotionEventBuilder(POINTER_0_UP, AINPUT_SOURCE_TOUCHSCREEN)
1280 .displayId(ADISPLAY_ID_DEFAULT)
1281 .eventTime(systemTime(SYSTEM_TIME_MONOTONIC))
Siarhei Vishniakou6d73f832022-07-21 17:27:03 -07001282 .pointer(PointerBuilder(/*id=*/0, ToolType::FINGER).x(100).y(100))
1283 .pointer(PointerBuilder(/*id=*/1, ToolType::FINGER).x(150).y(150))
Arthur Hungc539dbb2022-12-08 07:45:36 +00001284 .build();
1285 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07001286 injectMotionEvent(*mDispatcher, secondFingerUpEvent, INJECT_EVENT_TIMEOUT,
Arthur Hungc539dbb2022-12-08 07:45:36 +00001287 InputEventInjectionSync::WAIT_FOR_RESULT))
1288 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
1289 foregroundWindow->consumeMotionPointerUp(0);
Linnan Li72352222024-04-12 18:55:57 +08001290 wallpaperWindow->consumeMotionPointerUp(0, ADISPLAY_ID_DEFAULT, EXPECTED_WALLPAPER_FLAGS);
Arthur Hungc539dbb2022-12-08 07:45:36 +00001291
1292 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07001293 injectMotionEvent(*mDispatcher,
Siarhei Vishniakou92c8fd52023-01-29 14:57:43 -08001294 MotionEventBuilder(AMOTION_EVENT_ACTION_UP,
1295 AINPUT_SOURCE_TOUCHSCREEN)
1296 .displayId(ADISPLAY_ID_DEFAULT)
1297 .eventTime(systemTime(SYSTEM_TIME_MONOTONIC))
Harry Cutts101ee9b2023-07-06 18:04:14 +00001298 .pointer(PointerBuilder(/*id=*/1, ToolType::FINGER)
Siarhei Vishniakou92c8fd52023-01-29 14:57:43 -08001299 .x(100)
1300 .y(100))
1301 .build(),
1302 INJECT_EVENT_TIMEOUT, InputEventInjectionSync::WAIT_FOR_RESULT))
Arthur Hungc539dbb2022-12-08 07:45:36 +00001303 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
1304 foregroundWindow->consumeMotionUp(ADISPLAY_ID_DEFAULT);
Linnan Li72352222024-04-12 18:55:57 +08001305 wallpaperWindow->consumeMotionUp(ADISPLAY_ID_DEFAULT, EXPECTED_WALLPAPER_FLAGS);
Siarhei Vishniakouca205502021-07-16 21:31:58 +00001306}
1307
1308/**
1309 * Two windows: a window on the left and window on the right.
1310 * A third window, wallpaper, is behind both windows, and spans both top windows.
1311 * The first touch down goes to the left window. A second pointer touches down on the right window.
1312 * The touch is split, so both left and right windows should receive ACTION_DOWN.
1313 * The wallpaper will get the full event, so it should receive ACTION_DOWN followed by
1314 * ACTION_POINTER_DOWN(1).
1315 */
1316TEST_F(InputDispatcherTest, TwoWindows_SplitWallpaperTouch) {
1317 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
1318 sp<FakeWindowHandle> leftWindow =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07001319 sp<FakeWindowHandle>::make(application, mDispatcher, "Left", ADISPLAY_ID_DEFAULT);
Siarhei Vishniakouca205502021-07-16 21:31:58 +00001320 leftWindow->setFrame(Rect(0, 0, 200, 200));
Prabir Pradhan4d5c52f2022-01-31 08:52:10 -08001321 leftWindow->setDupTouchToWallpaper(true);
Siarhei Vishniakouca205502021-07-16 21:31:58 +00001322
1323 sp<FakeWindowHandle> rightWindow =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07001324 sp<FakeWindowHandle>::make(application, mDispatcher, "Right", ADISPLAY_ID_DEFAULT);
Siarhei Vishniakouca205502021-07-16 21:31:58 +00001325 rightWindow->setFrame(Rect(200, 0, 400, 200));
Prabir Pradhan4d5c52f2022-01-31 08:52:10 -08001326 rightWindow->setDupTouchToWallpaper(true);
Siarhei Vishniakouca205502021-07-16 21:31:58 +00001327
1328 sp<FakeWindowHandle> wallpaperWindow =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07001329 sp<FakeWindowHandle>::make(application, mDispatcher, "Wallpaper", ADISPLAY_ID_DEFAULT);
Siarhei Vishniakouca205502021-07-16 21:31:58 +00001330 wallpaperWindow->setFrame(Rect(0, 0, 400, 200));
Prabir Pradhan4d5c52f2022-01-31 08:52:10 -08001331 wallpaperWindow->setIsWallpaper(true);
Siarhei Vishniakouca205502021-07-16 21:31:58 +00001332
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07001333 mDispatcher->onWindowInfosChanged(
1334 {{*leftWindow->getInfo(), *rightWindow->getInfo(), *wallpaperWindow->getInfo()},
1335 {},
1336 0,
1337 0});
Siarhei Vishniakouca205502021-07-16 21:31:58 +00001338
1339 // Touch down on left window
1340 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07001341 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
Siarhei Vishniakouca205502021-07-16 21:31:58 +00001342 {100, 100}))
1343 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
1344
1345 // Both foreground window and its wallpaper should receive the touch down
1346 leftWindow->consumeMotionDown();
Linnan Li72352222024-04-12 18:55:57 +08001347 wallpaperWindow->consumeMotionDown(ADISPLAY_ID_DEFAULT, EXPECTED_WALLPAPER_FLAGS);
Siarhei Vishniakouca205502021-07-16 21:31:58 +00001348
1349 // Second finger down on the right window
1350 const MotionEvent secondFingerDownEvent =
Siarhei Vishniakoua16e3a22022-03-02 15:26:40 -08001351 MotionEventBuilder(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
Siarhei Vishniakouca205502021-07-16 21:31:58 +00001352 .eventTime(systemTime(SYSTEM_TIME_MONOTONIC))
Siarhei Vishniakou6d73f832022-07-21 17:27:03 -07001353 .pointer(PointerBuilder(/*id=*/0, ToolType::FINGER).x(100).y(100))
1354 .pointer(PointerBuilder(/*id=*/1, ToolType::FINGER).x(300).y(100))
Siarhei Vishniakouca205502021-07-16 21:31:58 +00001355 .build();
1356 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07001357 injectMotionEvent(*mDispatcher, secondFingerDownEvent, INJECT_EVENT_TIMEOUT,
Siarhei Vishniakouca205502021-07-16 21:31:58 +00001358 InputEventInjectionSync::WAIT_FOR_RESULT))
1359 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
1360
1361 leftWindow->consumeMotionMove();
1362 // Since the touch is split, right window gets ACTION_DOWN
1363 rightWindow->consumeMotionDown(ADISPLAY_ID_DEFAULT);
Harry Cutts33476232023-01-30 19:57:29 +00001364 wallpaperWindow->consumeMotionPointerDown(/*pointerIndex=*/1, ADISPLAY_ID_DEFAULT,
Linnan Li72352222024-04-12 18:55:57 +08001365 EXPECTED_WALLPAPER_FLAGS);
Siarhei Vishniakouca205502021-07-16 21:31:58 +00001366
1367 // Now, leftWindow, which received the first finger, disappears.
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07001368 mDispatcher->onWindowInfosChanged(
1369 {{*rightWindow->getInfo(), *wallpaperWindow->getInfo()}, {}, 0, 0});
Siarhei Vishniakouca205502021-07-16 21:31:58 +00001370 leftWindow->consumeMotionCancel();
1371 // Since a "parent" window of the wallpaper is gone, wallpaper should receive cancel, too.
Linnan Li72352222024-04-12 18:55:57 +08001372 wallpaperWindow->consumeMotionCancel(ADISPLAY_ID_DEFAULT, EXPECTED_WALLPAPER_FLAGS);
Siarhei Vishniakouca205502021-07-16 21:31:58 +00001373
1374 // The pointer that's still down on the right window moves, and goes to the right window only.
1375 // As far as the dispatcher's concerned though, both pointers are still present.
1376 const MotionEvent secondFingerMoveEvent =
1377 MotionEventBuilder(AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN)
1378 .eventTime(systemTime(SYSTEM_TIME_MONOTONIC))
Siarhei Vishniakou6d73f832022-07-21 17:27:03 -07001379 .pointer(PointerBuilder(/*id=*/0, ToolType::FINGER).x(100).y(100))
1380 .pointer(PointerBuilder(/*id=*/1, ToolType::FINGER).x(310).y(110))
Siarhei Vishniakouca205502021-07-16 21:31:58 +00001381 .build();
1382 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07001383 injectMotionEvent(*mDispatcher, secondFingerMoveEvent, INJECT_EVENT_TIMEOUT,
Siarhei Vishniakouca205502021-07-16 21:31:58 +00001384 InputEventInjectionSync::WAIT_FOR_RESULT));
1385 rightWindow->consumeMotionMove();
1386
1387 leftWindow->assertNoEvents();
1388 rightWindow->assertNoEvents();
1389 wallpaperWindow->assertNoEvents();
1390}
1391
Arthur Hungc539dbb2022-12-08 07:45:36 +00001392/**
1393 * Two windows: a window on the left with dup touch to wallpaper and window on the right without it.
1394 * The touch slips to the right window. so left window and wallpaper should receive ACTION_CANCEL
1395 * The right window should receive ACTION_DOWN.
1396 */
1397TEST_F(InputDispatcherTest, WallpaperWindowWhenSlippery) {
Arthur Hung74c248d2022-11-23 07:09:59 +00001398 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
Arthur Hungc539dbb2022-12-08 07:45:36 +00001399 sp<FakeWindowHandle> leftWindow =
1400 sp<FakeWindowHandle>::make(application, mDispatcher, "Left", ADISPLAY_ID_DEFAULT);
1401 leftWindow->setFrame(Rect(0, 0, 200, 200));
1402 leftWindow->setDupTouchToWallpaper(true);
1403 leftWindow->setSlippery(true);
1404
1405 sp<FakeWindowHandle> rightWindow =
1406 sp<FakeWindowHandle>::make(application, mDispatcher, "Right", ADISPLAY_ID_DEFAULT);
1407 rightWindow->setFrame(Rect(200, 0, 400, 200));
Arthur Hung74c248d2022-11-23 07:09:59 +00001408
1409 sp<FakeWindowHandle> wallpaperWindow =
1410 sp<FakeWindowHandle>::make(application, mDispatcher, "Wallpaper", ADISPLAY_ID_DEFAULT);
1411 wallpaperWindow->setIsWallpaper(true);
Arthur Hung74c248d2022-11-23 07:09:59 +00001412
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07001413 mDispatcher->onWindowInfosChanged(
1414 {{*leftWindow->getInfo(), *rightWindow->getInfo(), *wallpaperWindow->getInfo()},
1415 {},
1416 0,
1417 0});
Arthur Hung74c248d2022-11-23 07:09:59 +00001418
Arthur Hungc539dbb2022-12-08 07:45:36 +00001419 // Touch down on left window
Arthur Hung74c248d2022-11-23 07:09:59 +00001420 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07001421 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
Arthur Hungc539dbb2022-12-08 07:45:36 +00001422 {100, 100}))
Arthur Hung74c248d2022-11-23 07:09:59 +00001423 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
Arthur Hungc539dbb2022-12-08 07:45:36 +00001424
1425 // Both foreground window and its wallpaper should receive the touch down
1426 leftWindow->consumeMotionDown();
Linnan Li72352222024-04-12 18:55:57 +08001427 wallpaperWindow->consumeMotionDown(ADISPLAY_ID_DEFAULT, EXPECTED_WALLPAPER_FLAGS);
Arthur Hung74c248d2022-11-23 07:09:59 +00001428
Arthur Hungc539dbb2022-12-08 07:45:36 +00001429 // Move to right window, the left window should receive cancel.
Arthur Hung74c248d2022-11-23 07:09:59 +00001430 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07001431 injectMotionEvent(*mDispatcher, AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN,
Arthur Hungc539dbb2022-12-08 07:45:36 +00001432 ADISPLAY_ID_DEFAULT, {201, 100}))
Arthur Hung74c248d2022-11-23 07:09:59 +00001433 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
1434
Arthur Hungc539dbb2022-12-08 07:45:36 +00001435 leftWindow->consumeMotionCancel();
1436 rightWindow->consumeMotionDown(ADISPLAY_ID_DEFAULT);
Linnan Li72352222024-04-12 18:55:57 +08001437 wallpaperWindow->consumeMotionCancel(ADISPLAY_ID_DEFAULT, EXPECTED_WALLPAPER_FLAGS);
Arthur Hung74c248d2022-11-23 07:09:59 +00001438}
1439
Siarhei Vishniakoua16e3a22022-03-02 15:26:40 -08001440/**
Siarhei Vishniakou5bf25d92023-02-08 15:43:38 -08001441 * The policy typically sets POLICY_FLAG_PASS_TO_USER to the events. But when the display is not
1442 * interactive, it might stop sending this flag.
1443 * In this test, we check that if the policy stops sending this flag mid-gesture, we still ensure
1444 * to have a consistent input stream.
1445 *
1446 * Test procedure:
1447 * DOWN -> POINTER_DOWN -> (stop sending POLICY_FLAG_PASS_TO_USER) -> CANCEL.
1448 * DOWN (new gesture).
1449 *
1450 * In the bad implementation, we could potentially drop the CANCEL event, and get an inconsistent
1451 * state in the dispatcher. This would cause the final DOWN event to not be delivered to the app.
1452 *
1453 * We technically just need a single window here, but we are using two windows (spy on top and a
1454 * regular window below) to emulate the actual situation where it happens on the device.
1455 */
1456TEST_F(InputDispatcherTest, TwoPointerCancelInconsistentPolicy) {
1457 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
1458 sp<FakeWindowHandle> spyWindow =
1459 sp<FakeWindowHandle>::make(application, mDispatcher, "Spy", ADISPLAY_ID_DEFAULT);
1460 spyWindow->setFrame(Rect(0, 0, 200, 200));
1461 spyWindow->setTrustedOverlay(true);
1462 spyWindow->setSpy(true);
1463
1464 sp<FakeWindowHandle> window =
1465 sp<FakeWindowHandle>::make(application, mDispatcher, "Window", ADISPLAY_ID_DEFAULT);
1466 window->setFrame(Rect(0, 0, 200, 200));
1467
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07001468 mDispatcher->onWindowInfosChanged({{*spyWindow->getInfo(), *window->getInfo()}, {}, 0, 0});
Siarhei Vishniakou5bf25d92023-02-08 15:43:38 -08001469 const int32_t touchDeviceId = 4;
Siarhei Vishniakou5bf25d92023-02-08 15:43:38 -08001470
1471 // Two pointers down
Prabir Pradhan678438e2023-04-13 19:32:51 +00001472 mDispatcher->notifyMotion(
1473 MotionArgsBuilder(AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
1474 .deviceId(touchDeviceId)
1475 .policyFlags(DEFAULT_POLICY_FLAGS)
1476 .pointer(PointerBuilder(0, ToolType::FINGER).x(100).y(100))
1477 .build());
Siarhei Vishniakou5bf25d92023-02-08 15:43:38 -08001478
Prabir Pradhan678438e2023-04-13 19:32:51 +00001479 mDispatcher->notifyMotion(MotionArgsBuilder(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
1480 .deviceId(touchDeviceId)
1481 .policyFlags(DEFAULT_POLICY_FLAGS)
1482 .pointer(PointerBuilder(0, ToolType::FINGER).x(100).y(100))
1483 .pointer(PointerBuilder(1, ToolType::FINGER).x(120).y(120))
1484 .build());
Siarhei Vishniakou5bf25d92023-02-08 15:43:38 -08001485 spyWindow->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_DOWN));
1486 spyWindow->consumeMotionEvent(WithMotionAction(POINTER_1_DOWN));
1487 window->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_DOWN));
1488 window->consumeMotionEvent(WithMotionAction(POINTER_1_DOWN));
1489
1490 // Cancel the current gesture. Send the cancel without the default policy flags.
Prabir Pradhan678438e2023-04-13 19:32:51 +00001491 mDispatcher->notifyMotion(
1492 MotionArgsBuilder(AMOTION_EVENT_ACTION_CANCEL, AINPUT_SOURCE_TOUCHSCREEN)
1493 .deviceId(touchDeviceId)
1494 .policyFlags(0)
1495 .pointer(PointerBuilder(0, ToolType::FINGER).x(100).y(100))
1496 .pointer(PointerBuilder(1, ToolType::FINGER).x(120).y(120))
1497 .build());
Siarhei Vishniakou5bf25d92023-02-08 15:43:38 -08001498 spyWindow->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_CANCEL));
1499 window->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_CANCEL));
1500
1501 // We don't need to reset the device to reproduce the issue, but the reset event typically
1502 // follows, so we keep it here to model the actual listener behaviour more closely.
Prabir Pradhan678438e2023-04-13 19:32:51 +00001503 mDispatcher->notifyDeviceReset({/*id=*/1, systemTime(SYSTEM_TIME_MONOTONIC), touchDeviceId});
Siarhei Vishniakou5bf25d92023-02-08 15:43:38 -08001504
1505 // Start new gesture
Prabir Pradhan678438e2023-04-13 19:32:51 +00001506 mDispatcher->notifyMotion(
1507 MotionArgsBuilder(AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
1508 .deviceId(touchDeviceId)
1509 .policyFlags(DEFAULT_POLICY_FLAGS)
1510 .pointer(PointerBuilder(0, ToolType::FINGER).x(100).y(100))
1511 .build());
Siarhei Vishniakou5bf25d92023-02-08 15:43:38 -08001512 spyWindow->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_DOWN));
1513 window->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_DOWN));
1514
1515 // No more events
1516 spyWindow->assertNoEvents();
1517 window->assertNoEvents();
1518}
1519
1520/**
Linnan Li907ae732023-09-05 17:14:21 +08001521 * Same as the above 'TwoPointerCancelInconsistentPolicy' test, but for hovers.
1522 * The policy typically sets POLICY_FLAG_PASS_TO_USER to the events. But when the display is not
1523 * interactive, it might stop sending this flag.
1524 * We've already ensured the consistency of the touch event in this case, and we should also ensure
1525 * the consistency of the hover event in this case.
1526 *
1527 * Test procedure:
1528 * HOVER_ENTER -> HOVER_MOVE -> (stop sending POLICY_FLAG_PASS_TO_USER) -> HOVER_EXIT
1529 * HOVER_ENTER -> HOVER_MOVE -> HOVER_EXIT
1530 *
1531 * We expect to receive two full streams of hover events.
1532 */
1533TEST_F(InputDispatcherTest, HoverEventInconsistentPolicy) {
1534 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
1535
1536 sp<FakeWindowHandle> window =
1537 sp<FakeWindowHandle>::make(application, mDispatcher, "Window", ADISPLAY_ID_DEFAULT);
1538 window->setFrame(Rect(0, 0, 300, 300));
1539
1540 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
1541
1542 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_ENTER, AINPUT_SOURCE_STYLUS)
1543 .policyFlags(DEFAULT_POLICY_FLAGS)
1544 .pointer(PointerBuilder(0, ToolType::STYLUS).x(100).y(101))
1545 .build());
1546 window->consumeMotionEvent(WithMotionAction(ACTION_HOVER_ENTER));
1547
1548 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_MOVE, AINPUT_SOURCE_STYLUS)
1549 .policyFlags(DEFAULT_POLICY_FLAGS)
1550 .pointer(PointerBuilder(0, ToolType::STYLUS).x(101).y(102))
1551 .build());
1552 window->consumeMotionEvent(WithMotionAction(ACTION_HOVER_MOVE));
1553
1554 // Send hover exit without the default policy flags.
1555 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_EXIT, AINPUT_SOURCE_STYLUS)
1556 .policyFlags(0)
1557 .pointer(PointerBuilder(0, ToolType::STYLUS).x(101).y(102))
1558 .build());
1559
1560 window->consumeMotionEvent(WithMotionAction(ACTION_HOVER_EXIT));
1561
1562 // Send a simple hover event stream, ensure dispatcher not crashed and window can receive
1563 // right event.
1564 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_ENTER, AINPUT_SOURCE_STYLUS)
1565 .policyFlags(DEFAULT_POLICY_FLAGS)
1566 .pointer(PointerBuilder(0, ToolType::STYLUS).x(200).y(201))
1567 .build());
1568 window->consumeMotionEvent(WithMotionAction(ACTION_HOVER_ENTER));
1569
1570 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_MOVE, AINPUT_SOURCE_STYLUS)
1571 .policyFlags(DEFAULT_POLICY_FLAGS)
1572 .pointer(PointerBuilder(0, ToolType::STYLUS).x(201).y(202))
1573 .build());
1574 window->consumeMotionEvent(WithMotionAction(ACTION_HOVER_MOVE));
1575
1576 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_EXIT, AINPUT_SOURCE_STYLUS)
1577 .policyFlags(DEFAULT_POLICY_FLAGS)
1578 .pointer(PointerBuilder(0, ToolType::STYLUS).x(201).y(202))
1579 .build());
1580 window->consumeMotionEvent(WithMotionAction(ACTION_HOVER_EXIT));
1581}
1582
1583/**
Siarhei Vishniakoue0431e42023-01-28 17:01:39 -08001584 * Two windows: a window on the left and a window on the right.
1585 * Mouse is hovered from the right window into the left window.
1586 * Next, we tap on the left window, where the cursor was last seen.
1587 * The second tap is done onto the right window.
1588 * The mouse and tap are from two different devices.
1589 * We technically don't need to set the downtime / eventtime for these events, but setting these
1590 * explicitly helps during debugging.
1591 * This test reproduces a crash where there is a mismatch between the downTime and eventTime.
1592 * In the buggy implementation, a tap on the right window would cause a crash.
1593 */
Siarhei Vishniakoued89cbb2023-10-13 10:42:44 -07001594TEST_F(InputDispatcherTest, HoverFromLeftToRightAndTap_legacy) {
1595 SCOPED_FLAG_OVERRIDE(enable_multi_device_same_window_stream, false);
1596
Siarhei Vishniakoue0431e42023-01-28 17:01:39 -08001597 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
1598 sp<FakeWindowHandle> leftWindow =
1599 sp<FakeWindowHandle>::make(application, mDispatcher, "Left", ADISPLAY_ID_DEFAULT);
1600 leftWindow->setFrame(Rect(0, 0, 200, 200));
1601
1602 sp<FakeWindowHandle> rightWindow =
1603 sp<FakeWindowHandle>::make(application, mDispatcher, "Right", ADISPLAY_ID_DEFAULT);
1604 rightWindow->setFrame(Rect(200, 0, 400, 200));
1605
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07001606 mDispatcher->onWindowInfosChanged(
1607 {{*leftWindow->getInfo(), *rightWindow->getInfo()}, {}, 0, 0});
Siarhei Vishniakoue0431e42023-01-28 17:01:39 -08001608 // All times need to start at the current time, otherwise the dispatcher will drop the events as
1609 // stale.
1610 const nsecs_t baseTime = systemTime(SYSTEM_TIME_MONOTONIC);
1611 const int32_t mouseDeviceId = 6;
1612 const int32_t touchDeviceId = 4;
1613 // Move the cursor from right
1614 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07001615 injectMotionEvent(*mDispatcher,
Siarhei Vishniakoue0431e42023-01-28 17:01:39 -08001616 MotionEventBuilder(AMOTION_EVENT_ACTION_HOVER_MOVE,
1617 AINPUT_SOURCE_MOUSE)
1618 .deviceId(mouseDeviceId)
1619 .downTime(baseTime + 10)
1620 .eventTime(baseTime + 20)
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07001621 .pointer(PointerBuilder(0, ToolType::MOUSE).x(300).y(100))
Siarhei Vishniakoue0431e42023-01-28 17:01:39 -08001622 .build()));
1623 rightWindow->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_ENTER));
1624
1625 // .. to the left window
1626 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07001627 injectMotionEvent(*mDispatcher,
Siarhei Vishniakoue0431e42023-01-28 17:01:39 -08001628 MotionEventBuilder(AMOTION_EVENT_ACTION_HOVER_MOVE,
1629 AINPUT_SOURCE_MOUSE)
1630 .deviceId(mouseDeviceId)
1631 .downTime(baseTime + 10)
1632 .eventTime(baseTime + 30)
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07001633 .pointer(PointerBuilder(0, ToolType::MOUSE).x(110).y(100))
Siarhei Vishniakoue0431e42023-01-28 17:01:39 -08001634 .build()));
1635 rightWindow->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_EXIT));
1636 leftWindow->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_ENTER));
1637 // Now tap the left window
1638 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07001639 injectMotionEvent(*mDispatcher,
Siarhei Vishniakoue0431e42023-01-28 17:01:39 -08001640 MotionEventBuilder(AMOTION_EVENT_ACTION_DOWN,
1641 AINPUT_SOURCE_TOUCHSCREEN)
1642 .deviceId(touchDeviceId)
1643 .downTime(baseTime + 40)
1644 .eventTime(baseTime + 40)
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07001645 .pointer(PointerBuilder(0, ToolType::FINGER).x(100).y(100))
Siarhei Vishniakoue0431e42023-01-28 17:01:39 -08001646 .build()));
1647 leftWindow->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_EXIT));
1648 leftWindow->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_DOWN));
1649
1650 // release tap
1651 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07001652 injectMotionEvent(*mDispatcher,
Siarhei Vishniakoue0431e42023-01-28 17:01:39 -08001653 MotionEventBuilder(AMOTION_EVENT_ACTION_UP,
1654 AINPUT_SOURCE_TOUCHSCREEN)
1655 .deviceId(touchDeviceId)
1656 .downTime(baseTime + 40)
1657 .eventTime(baseTime + 50)
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07001658 .pointer(PointerBuilder(0, ToolType::FINGER).x(100).y(100))
Siarhei Vishniakoue0431e42023-01-28 17:01:39 -08001659 .build()));
1660 leftWindow->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_UP));
1661
1662 // Tap the window on the right
1663 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07001664 injectMotionEvent(*mDispatcher,
Siarhei Vishniakoue0431e42023-01-28 17:01:39 -08001665 MotionEventBuilder(AMOTION_EVENT_ACTION_DOWN,
1666 AINPUT_SOURCE_TOUCHSCREEN)
1667 .deviceId(touchDeviceId)
1668 .downTime(baseTime + 60)
1669 .eventTime(baseTime + 60)
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07001670 .pointer(PointerBuilder(0, ToolType::FINGER).x(300).y(100))
Siarhei Vishniakoue0431e42023-01-28 17:01:39 -08001671 .build()));
1672 rightWindow->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_DOWN));
1673
1674 // release tap
1675 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07001676 injectMotionEvent(*mDispatcher,
Siarhei Vishniakoue0431e42023-01-28 17:01:39 -08001677 MotionEventBuilder(AMOTION_EVENT_ACTION_UP,
1678 AINPUT_SOURCE_TOUCHSCREEN)
1679 .deviceId(touchDeviceId)
1680 .downTime(baseTime + 60)
1681 .eventTime(baseTime + 70)
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07001682 .pointer(PointerBuilder(0, ToolType::FINGER).x(300).y(100))
Siarhei Vishniakoue0431e42023-01-28 17:01:39 -08001683 .build()));
1684 rightWindow->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_UP));
1685
1686 // No more events
1687 leftWindow->assertNoEvents();
1688 rightWindow->assertNoEvents();
1689}
1690
1691/**
Siarhei Vishniakoued89cbb2023-10-13 10:42:44 -07001692 * Two windows: a window on the left and a window on the right.
1693 * Mouse is hovered from the right window into the left window.
1694 * Next, we tap on the left window, where the cursor was last seen.
1695 * The second tap is done onto the right window.
1696 * The mouse and tap are from two different devices.
1697 * We technically don't need to set the downtime / eventtime for these events, but setting these
1698 * explicitly helps during debugging.
1699 * This test reproduces a crash where there is a mismatch between the downTime and eventTime.
1700 * In the buggy implementation, a tap on the right window would cause a crash.
1701 */
1702TEST_F(InputDispatcherTest, HoverFromLeftToRightAndTap) {
1703 SCOPED_FLAG_OVERRIDE(enable_multi_device_same_window_stream, true);
1704
1705 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
1706 sp<FakeWindowHandle> leftWindow =
1707 sp<FakeWindowHandle>::make(application, mDispatcher, "Left", ADISPLAY_ID_DEFAULT);
1708 leftWindow->setFrame(Rect(0, 0, 200, 200));
1709
1710 sp<FakeWindowHandle> rightWindow =
1711 sp<FakeWindowHandle>::make(application, mDispatcher, "Right", ADISPLAY_ID_DEFAULT);
1712 rightWindow->setFrame(Rect(200, 0, 400, 200));
1713
1714 mDispatcher->onWindowInfosChanged(
1715 {{*leftWindow->getInfo(), *rightWindow->getInfo()}, {}, 0, 0});
1716 // All times need to start at the current time, otherwise the dispatcher will drop the events as
1717 // stale.
1718 const nsecs_t baseTime = systemTime(SYSTEM_TIME_MONOTONIC);
1719 const int32_t mouseDeviceId = 6;
1720 const int32_t touchDeviceId = 4;
1721 // Move the cursor from right
1722 mDispatcher->notifyMotion(
1723 MotionArgsBuilder(AMOTION_EVENT_ACTION_HOVER_MOVE, AINPUT_SOURCE_MOUSE)
1724 .deviceId(mouseDeviceId)
1725 .downTime(baseTime + 10)
1726 .eventTime(baseTime + 20)
1727 .pointer(PointerBuilder(0, ToolType::MOUSE).x(300).y(100))
1728 .build());
1729 rightWindow->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_ENTER));
1730
1731 // .. to the left window
1732 mDispatcher->notifyMotion(
1733 MotionArgsBuilder(AMOTION_EVENT_ACTION_HOVER_MOVE, AINPUT_SOURCE_MOUSE)
1734 .deviceId(mouseDeviceId)
1735 .downTime(baseTime + 10)
1736 .eventTime(baseTime + 30)
1737 .pointer(PointerBuilder(0, ToolType::MOUSE).x(110).y(100))
1738 .build());
1739 rightWindow->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_EXIT));
1740 leftWindow->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_ENTER));
1741 // Now tap the left window
1742 mDispatcher->notifyMotion(
1743 MotionArgsBuilder(AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
1744 .deviceId(touchDeviceId)
1745 .downTime(baseTime + 40)
1746 .eventTime(baseTime + 40)
1747 .pointer(PointerBuilder(0, ToolType::FINGER).x(100).y(100))
1748 .build());
1749 leftWindow->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_DOWN));
1750
1751 // release tap
1752 mDispatcher->notifyMotion(MotionArgsBuilder(AMOTION_EVENT_ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN)
1753 .deviceId(touchDeviceId)
1754 .downTime(baseTime + 40)
1755 .eventTime(baseTime + 50)
1756 .pointer(PointerBuilder(0, ToolType::FINGER).x(100).y(100))
1757 .build());
1758 leftWindow->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_UP));
1759
1760 // Tap the window on the right
1761 mDispatcher->notifyMotion(
1762 MotionArgsBuilder(AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
1763 .deviceId(touchDeviceId)
1764 .downTime(baseTime + 60)
1765 .eventTime(baseTime + 60)
1766 .pointer(PointerBuilder(0, ToolType::FINGER).x(300).y(100))
1767 .build());
1768 rightWindow->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_DOWN));
1769
1770 // release tap
1771 mDispatcher->notifyMotion(MotionArgsBuilder(AMOTION_EVENT_ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN)
1772 .deviceId(touchDeviceId)
1773 .downTime(baseTime + 60)
1774 .eventTime(baseTime + 70)
1775 .pointer(PointerBuilder(0, ToolType::FINGER).x(300).y(100))
1776 .build());
1777 rightWindow->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_UP));
1778
1779 // No more events
1780 leftWindow->assertNoEvents();
1781 rightWindow->assertNoEvents();
1782}
1783
1784/**
Siarhei Vishniakoua235c042023-05-02 09:59:09 -07001785 * Start hovering in a window. While this hover is still active, make another window appear on top.
1786 * The top, obstructing window has no input channel, so it's not supposed to receive input.
1787 * While the top window is present, the hovering is stopped.
1788 * Later, hovering gets resumed again.
1789 * Ensure that new hover gesture is handled correctly.
1790 * This test reproduces a crash where the HOVER_EXIT event wasn't getting dispatched correctly
1791 * to the window that's currently being hovered over.
1792 */
1793TEST_F(InputDispatcherTest, HoverWhileWindowAppears) {
1794 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
1795 sp<FakeWindowHandle> window =
1796 sp<FakeWindowHandle>::make(application, mDispatcher, "Window", ADISPLAY_ID_DEFAULT);
1797 window->setFrame(Rect(0, 0, 200, 200));
1798
1799 // Only a single window is present at first
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07001800 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Siarhei Vishniakoua235c042023-05-02 09:59:09 -07001801
1802 // Start hovering in the window
1803 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_ENTER, AINPUT_SOURCE_STYLUS)
1804 .pointer(PointerBuilder(0, ToolType::STYLUS).x(100).y(100))
1805 .build());
1806 window->consumeMotionEvent(WithMotionAction(ACTION_HOVER_ENTER));
1807
1808 // Now, an obscuring window appears!
1809 sp<FakeWindowHandle> obscuringWindow =
1810 sp<FakeWindowHandle>::make(application, mDispatcher, "Obscuring window",
1811 ADISPLAY_ID_DEFAULT,
Prabir Pradhane7cc69c2024-01-05 21:35:28 +00001812 /*createInputChannel=*/false);
Siarhei Vishniakoua235c042023-05-02 09:59:09 -07001813 obscuringWindow->setFrame(Rect(0, 0, 200, 200));
1814 obscuringWindow->setTouchOcclusionMode(TouchOcclusionMode::BLOCK_UNTRUSTED);
1815 obscuringWindow->setOwnerInfo(SECONDARY_WINDOW_PID, SECONDARY_WINDOW_UID);
1816 obscuringWindow->setNoInputChannel(true);
1817 obscuringWindow->setFocusable(false);
1818 obscuringWindow->setAlpha(1.0);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07001819 mDispatcher->onWindowInfosChanged(
1820 {{*obscuringWindow->getInfo(), *window->getInfo()}, {}, 0, 0});
Siarhei Vishniakoua235c042023-05-02 09:59:09 -07001821
1822 // While this new obscuring window is present, the hovering is stopped
1823 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_EXIT, AINPUT_SOURCE_STYLUS)
1824 .pointer(PointerBuilder(0, ToolType::STYLUS).x(100).y(100))
1825 .build());
1826 window->consumeMotionEvent(WithMotionAction(ACTION_HOVER_EXIT));
1827
1828 // Now the obscuring window goes away.
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07001829 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Siarhei Vishniakoua235c042023-05-02 09:59:09 -07001830
1831 // And a new hover gesture starts.
1832 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_ENTER, AINPUT_SOURCE_STYLUS)
1833 .pointer(PointerBuilder(0, ToolType::STYLUS).x(100).y(100))
1834 .build());
1835 window->consumeMotionEvent(WithMotionAction(ACTION_HOVER_ENTER));
1836}
1837
1838/**
1839 * Same test as 'HoverWhileWindowAppears' above, but here, we also send some HOVER_MOVE events to
1840 * the obscuring window.
1841 */
1842TEST_F(InputDispatcherTest, HoverMoveWhileWindowAppears) {
1843 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
1844 sp<FakeWindowHandle> window =
1845 sp<FakeWindowHandle>::make(application, mDispatcher, "Window", ADISPLAY_ID_DEFAULT);
1846 window->setFrame(Rect(0, 0, 200, 200));
1847
1848 // Only a single window is present at first
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07001849 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Siarhei Vishniakoua235c042023-05-02 09:59:09 -07001850
1851 // Start hovering in the window
1852 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_ENTER, AINPUT_SOURCE_STYLUS)
1853 .pointer(PointerBuilder(0, ToolType::STYLUS).x(100).y(100))
1854 .build());
1855 window->consumeMotionEvent(WithMotionAction(ACTION_HOVER_ENTER));
1856
1857 // Now, an obscuring window appears!
1858 sp<FakeWindowHandle> obscuringWindow =
1859 sp<FakeWindowHandle>::make(application, mDispatcher, "Obscuring window",
1860 ADISPLAY_ID_DEFAULT,
Prabir Pradhane7cc69c2024-01-05 21:35:28 +00001861 /*createInputChannel=*/false);
Siarhei Vishniakoua235c042023-05-02 09:59:09 -07001862 obscuringWindow->setFrame(Rect(0, 0, 200, 200));
1863 obscuringWindow->setTouchOcclusionMode(TouchOcclusionMode::BLOCK_UNTRUSTED);
1864 obscuringWindow->setOwnerInfo(SECONDARY_WINDOW_PID, SECONDARY_WINDOW_UID);
1865 obscuringWindow->setNoInputChannel(true);
1866 obscuringWindow->setFocusable(false);
1867 obscuringWindow->setAlpha(1.0);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07001868 mDispatcher->onWindowInfosChanged(
1869 {{*obscuringWindow->getInfo(), *window->getInfo()}, {}, 0, 0});
Siarhei Vishniakoua235c042023-05-02 09:59:09 -07001870
1871 // While this new obscuring window is present, the hovering continues. The event can't go to the
1872 // bottom window due to obstructed touches, so it should generate HOVER_EXIT for that window.
1873 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_MOVE, AINPUT_SOURCE_STYLUS)
1874 .pointer(PointerBuilder(0, ToolType::STYLUS).x(100).y(100))
1875 .build());
1876 obscuringWindow->assertNoEvents();
1877 window->consumeMotionEvent(WithMotionAction(ACTION_HOVER_EXIT));
1878
1879 // Now the obscuring window goes away.
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07001880 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Siarhei Vishniakoua235c042023-05-02 09:59:09 -07001881
1882 // Hovering continues in the same position. The hovering pointer re-enters the bottom window,
1883 // so it should generate a HOVER_ENTER
1884 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_MOVE, AINPUT_SOURCE_STYLUS)
1885 .pointer(PointerBuilder(0, ToolType::STYLUS).x(100).y(100))
1886 .build());
1887 window->consumeMotionEvent(WithMotionAction(ACTION_HOVER_ENTER));
1888
1889 // Now the MOVE should be getting dispatched normally
1890 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_MOVE, AINPUT_SOURCE_STYLUS)
1891 .pointer(PointerBuilder(0, ToolType::STYLUS).x(110).y(110))
1892 .build());
1893 window->consumeMotionEvent(WithMotionAction(ACTION_HOVER_MOVE));
1894}
1895
1896/**
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -07001897 * Hover mouse over a window, and then send ACTION_SCROLL. Ensure both the hover and the scroll
1898 * events are delivered to the window.
1899 */
1900TEST_F(InputDispatcherTest, HoverMoveAndScroll) {
1901 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
1902 sp<FakeWindowHandle> window =
1903 sp<FakeWindowHandle>::make(application, mDispatcher, "Window", ADISPLAY_ID_DEFAULT);
1904 window->setFrame(Rect(0, 0, 200, 200));
1905 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
1906
1907 // Start hovering in the window
1908 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_ENTER, AINPUT_SOURCE_MOUSE)
1909 .pointer(PointerBuilder(0, ToolType::MOUSE).x(100).y(110))
1910 .build());
1911 window->consumeMotionEvent(WithMotionAction(ACTION_HOVER_ENTER));
1912
1913 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_MOVE, AINPUT_SOURCE_MOUSE)
1914 .pointer(PointerBuilder(0, ToolType::MOUSE).x(110).y(120))
1915 .build());
1916 window->consumeMotionEvent(WithMotionAction(ACTION_HOVER_MOVE));
1917
1918 // Scroll with the mouse
1919 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_SCROLL, AINPUT_SOURCE_MOUSE)
1920 .pointer(PointerBuilder(0, ToolType::MOUSE).x(110).y(120))
1921 .build());
1922 window->consumeMotionEvent(WithMotionAction(ACTION_SCROLL));
1923}
1924
1925using InputDispatcherMultiDeviceTest = InputDispatcherTest;
1926
1927/**
Siarhei Vishniakou2899c552023-07-10 18:20:46 -07001928 * One window. Stylus down on the window. Next, touch from another device goes down. Ensure that
1929 * touch is dropped, because stylus should be preferred over touch.
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -07001930 */
Siarhei Vishniakou2899c552023-07-10 18:20:46 -07001931TEST_F(InputDispatcherMultiDeviceTest, StylusDownBlocksTouchDown) {
Siarhei Vishniakoued89cbb2023-10-13 10:42:44 -07001932 SCOPED_FLAG_OVERRIDE(enable_multi_device_same_window_stream, false);
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -07001933 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
1934 sp<FakeWindowHandle> window =
1935 sp<FakeWindowHandle>::make(application, mDispatcher, "Window", ADISPLAY_ID_DEFAULT);
1936 window->setFrame(Rect(0, 0, 200, 200));
1937
1938 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
1939
1940 constexpr int32_t touchDeviceId = 4;
1941 constexpr int32_t stylusDeviceId = 2;
1942
1943 // Stylus down
1944 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_STYLUS)
1945 .deviceId(stylusDeviceId)
1946 .pointer(PointerBuilder(0, ToolType::STYLUS).x(100).y(110))
1947 .build());
1948 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(stylusDeviceId)));
1949
1950 // Touch down
1951 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
1952 .deviceId(touchDeviceId)
1953 .pointer(PointerBuilder(0, ToolType::FINGER).x(140).y(145))
1954 .build());
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -07001955
1956 // Touch move
1957 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN)
1958 .deviceId(touchDeviceId)
1959 .pointer(PointerBuilder(0, ToolType::FINGER).x(141).y(146))
1960 .build());
Siarhei Vishniakou2899c552023-07-10 18:20:46 -07001961 // Touch is ignored because stylus is already down
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -07001962
Siarhei Vishniakou2899c552023-07-10 18:20:46 -07001963 // Subsequent stylus movements are delivered correctly
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -07001964 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_STYLUS)
1965 .deviceId(stylusDeviceId)
1966 .pointer(PointerBuilder(0, ToolType::STYLUS).x(101).y(111))
1967 .build());
Siarhei Vishniakou2899c552023-07-10 18:20:46 -07001968 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(stylusDeviceId),
1969 WithCoords(101, 111)));
1970
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -07001971 window->assertNoEvents();
1972}
1973
1974/**
Siarhei Vishniakoued89cbb2023-10-13 10:42:44 -07001975 * One window. Stylus down on the window. Next, touch from another device goes down. Ensure that
1976 * touch is not dropped, because multiple devices are allowed to be active in the same window.
1977 */
1978TEST_F(InputDispatcherMultiDeviceTest, StylusDownDoesNotBlockTouchDown) {
1979 SCOPED_FLAG_OVERRIDE(enable_multi_device_same_window_stream, true);
1980 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
1981 sp<FakeWindowHandle> window =
1982 sp<FakeWindowHandle>::make(application, mDispatcher, "Window", ADISPLAY_ID_DEFAULT);
1983 window->setFrame(Rect(0, 0, 200, 200));
1984
1985 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
1986
1987 constexpr int32_t touchDeviceId = 4;
1988 constexpr int32_t stylusDeviceId = 2;
1989
1990 // Stylus down
1991 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_STYLUS)
1992 .deviceId(stylusDeviceId)
1993 .pointer(PointerBuilder(0, ToolType::STYLUS).x(100).y(110))
1994 .build());
1995 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(stylusDeviceId)));
1996
1997 // Touch down
1998 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
1999 .deviceId(touchDeviceId)
2000 .pointer(PointerBuilder(0, ToolType::FINGER).x(140).y(145))
2001 .build());
2002 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(touchDeviceId)));
2003
2004 // Touch move
2005 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN)
2006 .deviceId(touchDeviceId)
2007 .pointer(PointerBuilder(0, ToolType::FINGER).x(141).y(146))
2008 .build());
2009 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(touchDeviceId)));
2010
2011 // Stylus move
2012 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_STYLUS)
2013 .deviceId(stylusDeviceId)
2014 .pointer(PointerBuilder(0, ToolType::STYLUS).x(101).y(111))
2015 .build());
2016 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(stylusDeviceId),
2017 WithCoords(101, 111)));
2018
2019 window->assertNoEvents();
2020}
2021
2022/**
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -07002023 * One window and one spy window. Stylus down on the window. Next, touch from another device goes
Siarhei Vishniakou2899c552023-07-10 18:20:46 -07002024 * down. Ensure that touch is dropped, because stylus should be preferred over touch.
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -07002025 * Similar test as above, but with added SPY window.
2026 */
Siarhei Vishniakou2899c552023-07-10 18:20:46 -07002027TEST_F(InputDispatcherMultiDeviceTest, StylusDownWithSpyBlocksTouchDown) {
Siarhei Vishniakoued89cbb2023-10-13 10:42:44 -07002028 SCOPED_FLAG_OVERRIDE(enable_multi_device_same_window_stream, false);
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -07002029 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
2030 sp<FakeWindowHandle> window =
2031 sp<FakeWindowHandle>::make(application, mDispatcher, "Window", ADISPLAY_ID_DEFAULT);
2032 sp<FakeWindowHandle> spyWindow =
2033 sp<FakeWindowHandle>::make(application, mDispatcher, "Spy", ADISPLAY_ID_DEFAULT);
2034 spyWindow->setFrame(Rect(0, 0, 200, 200));
2035 spyWindow->setTrustedOverlay(true);
2036 spyWindow->setSpy(true);
2037 window->setFrame(Rect(0, 0, 200, 200));
2038
2039 mDispatcher->onWindowInfosChanged({{*spyWindow->getInfo(), *window->getInfo()}, {}, 0, 0});
2040
2041 constexpr int32_t touchDeviceId = 4;
2042 constexpr int32_t stylusDeviceId = 2;
2043
2044 // Stylus down
2045 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_STYLUS)
2046 .deviceId(stylusDeviceId)
2047 .pointer(PointerBuilder(0, ToolType::STYLUS).x(100).y(110))
2048 .build());
2049 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(stylusDeviceId)));
2050 spyWindow->consumeMotionEvent(
2051 AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(stylusDeviceId)));
2052
2053 // Touch down
2054 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
2055 .deviceId(touchDeviceId)
2056 .pointer(PointerBuilder(0, ToolType::FINGER).x(140).y(145))
2057 .build());
2058
2059 // Touch move
2060 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN)
2061 .deviceId(touchDeviceId)
2062 .pointer(PointerBuilder(0, ToolType::FINGER).x(141).y(146))
2063 .build());
Siarhei Vishniakou2899c552023-07-10 18:20:46 -07002064
2065 // Touch is ignored because stylus is already down
2066
2067 // Subsequent stylus movements are delivered correctly
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -07002068 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_STYLUS)
2069 .deviceId(stylusDeviceId)
2070 .pointer(PointerBuilder(0, ToolType::STYLUS).x(101).y(111))
2071 .build());
Siarhei Vishniakou2899c552023-07-10 18:20:46 -07002072 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(stylusDeviceId),
2073 WithCoords(101, 111)));
2074 spyWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(stylusDeviceId),
2075 WithCoords(101, 111)));
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -07002076
2077 window->assertNoEvents();
2078 spyWindow->assertNoEvents();
2079}
2080
2081/**
Siarhei Vishniakoued89cbb2023-10-13 10:42:44 -07002082 * One window and one spy window. Stylus down on the window. Next, touch from another device goes
2083 * down. Ensure that touch is not dropped, because multiple devices can be active at the same time.
2084 * Similar test as above, but with added SPY window.
2085 */
2086TEST_F(InputDispatcherMultiDeviceTest, StylusDownWithSpyDoesNotBlockTouchDown) {
2087 SCOPED_FLAG_OVERRIDE(enable_multi_device_same_window_stream, true);
2088 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
2089 sp<FakeWindowHandle> window =
2090 sp<FakeWindowHandle>::make(application, mDispatcher, "Window", ADISPLAY_ID_DEFAULT);
2091 sp<FakeWindowHandle> spyWindow =
2092 sp<FakeWindowHandle>::make(application, mDispatcher, "Spy", ADISPLAY_ID_DEFAULT);
2093 spyWindow->setFrame(Rect(0, 0, 200, 200));
2094 spyWindow->setTrustedOverlay(true);
2095 spyWindow->setSpy(true);
2096 window->setFrame(Rect(0, 0, 200, 200));
2097
2098 mDispatcher->onWindowInfosChanged({{*spyWindow->getInfo(), *window->getInfo()}, {}, 0, 0});
2099
2100 constexpr int32_t touchDeviceId = 4;
2101 constexpr int32_t stylusDeviceId = 2;
2102
2103 // Stylus down
2104 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_STYLUS)
2105 .deviceId(stylusDeviceId)
2106 .pointer(PointerBuilder(0, ToolType::STYLUS).x(100).y(110))
2107 .build());
2108 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(stylusDeviceId)));
2109 spyWindow->consumeMotionEvent(
2110 AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(stylusDeviceId)));
2111
2112 // Touch down
2113 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
2114 .deviceId(touchDeviceId)
2115 .pointer(PointerBuilder(0, ToolType::FINGER).x(140).y(145))
2116 .build());
2117 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(touchDeviceId)));
2118 spyWindow->consumeMotionEvent(
2119 AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(touchDeviceId)));
2120
2121 // Touch move
2122 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN)
2123 .deviceId(touchDeviceId)
2124 .pointer(PointerBuilder(0, ToolType::FINGER).x(141).y(146))
2125 .build());
2126 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(touchDeviceId)));
2127 spyWindow->consumeMotionEvent(
2128 AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(touchDeviceId)));
2129
2130 // Subsequent stylus movements are delivered correctly
2131 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_STYLUS)
2132 .deviceId(stylusDeviceId)
2133 .pointer(PointerBuilder(0, ToolType::STYLUS).x(101).y(111))
2134 .build());
2135 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(stylusDeviceId),
2136 WithCoords(101, 111)));
2137 spyWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(stylusDeviceId),
2138 WithCoords(101, 111)));
2139
2140 window->assertNoEvents();
2141 spyWindow->assertNoEvents();
2142}
2143
2144/**
Siarhei Vishniakou2899c552023-07-10 18:20:46 -07002145 * One window. Stylus hover on the window. Next, touch from another device goes down. Ensure that
Siarhei Vishniakou3ad54f52023-11-02 16:54:40 -07002146 * touch is dropped, because stylus hover takes precedence.
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -07002147 */
Siarhei Vishniakou3ad54f52023-11-02 16:54:40 -07002148TEST_F(InputDispatcherMultiDeviceTest, StylusHoverBlocksTouchDown) {
Siarhei Vishniakoued89cbb2023-10-13 10:42:44 -07002149 SCOPED_FLAG_OVERRIDE(enable_multi_device_same_window_stream, false);
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -07002150 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
2151 sp<FakeWindowHandle> window =
2152 sp<FakeWindowHandle>::make(application, mDispatcher, "Window", ADISPLAY_ID_DEFAULT);
2153 window->setFrame(Rect(0, 0, 200, 200));
2154
2155 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
2156
2157 constexpr int32_t touchDeviceId = 4;
2158 constexpr int32_t stylusDeviceId = 2;
2159
2160 // Stylus down on the window
2161 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_ENTER, AINPUT_SOURCE_STYLUS)
2162 .deviceId(stylusDeviceId)
2163 .pointer(PointerBuilder(0, ToolType::STYLUS).x(100).y(110))
2164 .build());
2165 window->consumeMotionEvent(
2166 AllOf(WithMotionAction(ACTION_HOVER_ENTER), WithDeviceId(stylusDeviceId)));
2167
2168 // Touch down on window
2169 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
2170 .deviceId(touchDeviceId)
2171 .pointer(PointerBuilder(0, ToolType::FINGER).x(140).y(145))
2172 .build());
2173 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN)
2174 .deviceId(touchDeviceId)
2175 .pointer(PointerBuilder(0, ToolType::FINGER).x(141).y(146))
2176 .build());
Siarhei Vishniakou2899c552023-07-10 18:20:46 -07002177
Siarhei Vishniakou3ad54f52023-11-02 16:54:40 -07002178 // Touch is ignored because stylus is hovering
Siarhei Vishniakou2899c552023-07-10 18:20:46 -07002179
Siarhei Vishniakou3ad54f52023-11-02 16:54:40 -07002180 // Subsequent stylus movements are delivered correctly
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -07002181 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_MOVE, AINPUT_SOURCE_STYLUS)
2182 .deviceId(stylusDeviceId)
2183 .pointer(PointerBuilder(0, ToolType::STYLUS).x(101).y(111))
2184 .build());
Siarhei Vishniakou3ad54f52023-11-02 16:54:40 -07002185 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_HOVER_MOVE),
2186 WithDeviceId(stylusDeviceId), WithCoords(101, 111)));
Siarhei Vishniakou2899c552023-07-10 18:20:46 -07002187
Siarhei Vishniakou3ad54f52023-11-02 16:54:40 -07002188 // and subsequent touches continue to be ignored
Siarhei Vishniakou2899c552023-07-10 18:20:46 -07002189 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN)
2190 .deviceId(touchDeviceId)
2191 .pointer(PointerBuilder(0, ToolType::FINGER).x(142).y(147))
2192 .build());
Siarhei Vishniakou3ad54f52023-11-02 16:54:40 -07002193 window->assertNoEvents();
Siarhei Vishniakou2899c552023-07-10 18:20:46 -07002194}
2195
2196/**
Siarhei Vishniakoued89cbb2023-10-13 10:42:44 -07002197 * One window. Stylus hover on the window. Next, touch from another device goes down. Ensure that
2198 * touch is not dropped, because stylus hover and touch can be both active at the same time.
2199 */
2200TEST_F(InputDispatcherMultiDeviceTest, StylusHoverDoesNotBlockTouchDown) {
2201 SCOPED_FLAG_OVERRIDE(enable_multi_device_same_window_stream, true);
2202 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
2203 sp<FakeWindowHandle> window =
2204 sp<FakeWindowHandle>::make(application, mDispatcher, "Window", ADISPLAY_ID_DEFAULT);
2205 window->setFrame(Rect(0, 0, 200, 200));
2206
2207 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
2208
2209 constexpr int32_t touchDeviceId = 4;
2210 constexpr int32_t stylusDeviceId = 2;
2211
2212 // Stylus down on the window
2213 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_ENTER, AINPUT_SOURCE_STYLUS)
2214 .deviceId(stylusDeviceId)
2215 .pointer(PointerBuilder(0, ToolType::STYLUS).x(100).y(110))
2216 .build());
2217 window->consumeMotionEvent(
2218 AllOf(WithMotionAction(ACTION_HOVER_ENTER), WithDeviceId(stylusDeviceId)));
2219
2220 // Touch down on window
2221 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
2222 .deviceId(touchDeviceId)
2223 .pointer(PointerBuilder(0, ToolType::FINGER).x(140).y(145))
2224 .build());
2225 // Touch move on window
2226 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(touchDeviceId)));
2227 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN)
2228 .deviceId(touchDeviceId)
2229 .pointer(PointerBuilder(0, ToolType::FINGER).x(141).y(146))
2230 .build());
2231 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(touchDeviceId)));
2232
2233 // Subsequent stylus movements are delivered correctly
2234 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_MOVE, AINPUT_SOURCE_STYLUS)
2235 .deviceId(stylusDeviceId)
2236 .pointer(PointerBuilder(0, ToolType::STYLUS).x(101).y(111))
2237 .build());
2238 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_HOVER_MOVE),
2239 WithDeviceId(stylusDeviceId), WithCoords(101, 111)));
2240
2241 // and subsequent touches continue to work
2242 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN)
2243 .deviceId(touchDeviceId)
2244 .pointer(PointerBuilder(0, ToolType::FINGER).x(142).y(147))
2245 .build());
2246 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(touchDeviceId)));
2247 window->assertNoEvents();
2248}
2249
2250/**
Siarhei Vishniakou2899c552023-07-10 18:20:46 -07002251 * One window. Touch down on the window. Then, stylus hover on the window from another device.
Siarhei Vishniakou3ad54f52023-11-02 16:54:40 -07002252 * Ensure that touch is canceled, because stylus hover should take precedence.
Siarhei Vishniakou2899c552023-07-10 18:20:46 -07002253 */
Siarhei Vishniakou3ad54f52023-11-02 16:54:40 -07002254TEST_F(InputDispatcherMultiDeviceTest, TouchIsCanceledByStylusHover) {
Siarhei Vishniakoued89cbb2023-10-13 10:42:44 -07002255 SCOPED_FLAG_OVERRIDE(enable_multi_device_same_window_stream, false);
Siarhei Vishniakou2899c552023-07-10 18:20:46 -07002256 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
2257 sp<FakeWindowHandle> window =
2258 sp<FakeWindowHandle>::make(application, mDispatcher, "Window", ADISPLAY_ID_DEFAULT);
2259 window->setFrame(Rect(0, 0, 200, 200));
2260
2261 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
2262
2263 constexpr int32_t touchDeviceId = 4;
2264 constexpr int32_t stylusDeviceId = 2;
2265
2266 // Touch down on window
2267 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
2268 .deviceId(touchDeviceId)
2269 .pointer(PointerBuilder(0, ToolType::FINGER).x(140).y(145))
2270 .build());
2271 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN)
2272 .deviceId(touchDeviceId)
2273 .pointer(PointerBuilder(0, ToolType::FINGER).x(141).y(146))
2274 .build());
2275 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(touchDeviceId)));
2276 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(touchDeviceId)));
2277
2278 // Stylus hover on the window
2279 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_ENTER, AINPUT_SOURCE_STYLUS)
2280 .deviceId(stylusDeviceId)
2281 .pointer(PointerBuilder(0, ToolType::STYLUS).x(100).y(110))
2282 .build());
2283 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_MOVE, AINPUT_SOURCE_STYLUS)
2284 .deviceId(stylusDeviceId)
2285 .pointer(PointerBuilder(0, ToolType::STYLUS).x(101).y(111))
2286 .build());
Siarhei Vishniakou3ad54f52023-11-02 16:54:40 -07002287 // Stylus hover movement causes touch to be canceled
2288 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_CANCEL), WithDeviceId(touchDeviceId),
2289 WithCoords(141, 146)));
2290 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_HOVER_ENTER),
2291 WithDeviceId(stylusDeviceId), WithCoords(100, 110)));
2292 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_HOVER_MOVE),
2293 WithDeviceId(stylusDeviceId), WithCoords(101, 111)));
Siarhei Vishniakou2899c552023-07-10 18:20:46 -07002294
Siarhei Vishniakou3ad54f52023-11-02 16:54:40 -07002295 // Subsequent touch movements are ignored
Siarhei Vishniakou2899c552023-07-10 18:20:46 -07002296 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN)
2297 .deviceId(touchDeviceId)
2298 .pointer(PointerBuilder(0, ToolType::FINGER).x(142).y(147))
2299 .build());
Siarhei Vishniakou3ad54f52023-11-02 16:54:40 -07002300
2301 window->assertNoEvents();
Siarhei Vishniakou2899c552023-07-10 18:20:46 -07002302}
2303
2304/**
Siarhei Vishniakoued89cbb2023-10-13 10:42:44 -07002305 * One window. Touch down on the window. Then, stylus hover on the window from another device.
2306 * Ensure that touch is not canceled, because stylus hover can be active at the same time as touch.
2307 */
2308TEST_F(InputDispatcherMultiDeviceTest, TouchIsNotCanceledByStylusHover) {
2309 SCOPED_FLAG_OVERRIDE(enable_multi_device_same_window_stream, true);
2310 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
2311 sp<FakeWindowHandle> window =
2312 sp<FakeWindowHandle>::make(application, mDispatcher, "Window", ADISPLAY_ID_DEFAULT);
2313 window->setFrame(Rect(0, 0, 200, 200));
2314
2315 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
2316
2317 constexpr int32_t touchDeviceId = 4;
2318 constexpr int32_t stylusDeviceId = 2;
2319
2320 // Touch down on window
2321 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
2322 .deviceId(touchDeviceId)
2323 .pointer(PointerBuilder(0, ToolType::FINGER).x(140).y(145))
2324 .build());
2325 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN)
2326 .deviceId(touchDeviceId)
2327 .pointer(PointerBuilder(0, ToolType::FINGER).x(141).y(146))
2328 .build());
2329 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(touchDeviceId)));
2330 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(touchDeviceId)));
2331
2332 // Stylus hover on the window
2333 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_ENTER, AINPUT_SOURCE_STYLUS)
2334 .deviceId(stylusDeviceId)
2335 .pointer(PointerBuilder(0, ToolType::STYLUS).x(100).y(110))
2336 .build());
2337 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_MOVE, AINPUT_SOURCE_STYLUS)
2338 .deviceId(stylusDeviceId)
2339 .pointer(PointerBuilder(0, ToolType::STYLUS).x(101).y(111))
2340 .build());
2341 // Stylus hover movement is received normally
2342 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_HOVER_ENTER),
2343 WithDeviceId(stylusDeviceId), WithCoords(100, 110)));
2344 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_HOVER_MOVE),
2345 WithDeviceId(stylusDeviceId), WithCoords(101, 111)));
2346
2347 // Subsequent touch movements also work
2348 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN)
2349 .deviceId(touchDeviceId)
2350 .pointer(PointerBuilder(0, ToolType::FINGER).x(142).y(147))
2351 .build());
2352 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(touchDeviceId),
2353 WithCoords(142, 147)));
2354
2355 window->assertNoEvents();
2356}
2357
2358/**
Siarhei Vishniakou2899c552023-07-10 18:20:46 -07002359 * One window. Stylus down on the window. Then, stylus from another device goes down. Ensure that
2360 * the latest stylus takes over. That is, old stylus should be canceled and the new stylus should
2361 * become active.
2362 */
2363TEST_F(InputDispatcherMultiDeviceTest, LatestStylusWins) {
Siarhei Vishniakoued89cbb2023-10-13 10:42:44 -07002364 SCOPED_FLAG_OVERRIDE(enable_multi_device_same_window_stream, false);
Siarhei Vishniakou2899c552023-07-10 18:20:46 -07002365 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
2366 sp<FakeWindowHandle> window =
2367 sp<FakeWindowHandle>::make(application, mDispatcher, "Window", ADISPLAY_ID_DEFAULT);
2368 window->setFrame(Rect(0, 0, 200, 200));
2369
2370 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
2371
2372 constexpr int32_t stylusDeviceId1 = 3;
2373 constexpr int32_t stylusDeviceId2 = 5;
2374
2375 // Touch down on window
2376 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_STYLUS)
2377 .deviceId(stylusDeviceId1)
2378 .pointer(PointerBuilder(0, ToolType::STYLUS).x(99).y(100))
2379 .build());
2380 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_STYLUS)
2381 .deviceId(stylusDeviceId1)
2382 .pointer(PointerBuilder(0, ToolType::STYLUS).x(100).y(101))
2383 .build());
2384 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(stylusDeviceId1)));
2385 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(stylusDeviceId1)));
2386
2387 // Second stylus down
2388 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_STYLUS)
2389 .deviceId(stylusDeviceId2)
2390 .pointer(PointerBuilder(0, ToolType::STYLUS).x(9).y(10))
2391 .build());
2392 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_STYLUS)
2393 .deviceId(stylusDeviceId2)
2394 .pointer(PointerBuilder(0, ToolType::STYLUS).x(10).y(11))
2395 .build());
2396
2397 // First stylus is canceled, second one takes over.
2398 window->consumeMotionEvent(
2399 AllOf(WithMotionAction(ACTION_CANCEL), WithDeviceId(stylusDeviceId1)));
2400 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(stylusDeviceId2)));
2401 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(stylusDeviceId2)));
2402
2403 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_STYLUS)
2404 .deviceId(stylusDeviceId1)
2405 .pointer(PointerBuilder(0, ToolType::STYLUS).x(101).y(102))
2406 .build());
2407 // Subsequent stylus movements are delivered correctly
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -07002408 window->assertNoEvents();
2409}
2410
2411/**
Siarhei Vishniakoued89cbb2023-10-13 10:42:44 -07002412 * One window. Stylus down on the window. Then, stylus from another device goes down. Ensure that
2413 * both stylus devices can function simultaneously.
2414 */
2415TEST_F(InputDispatcherMultiDeviceTest, TwoStylusDevicesActiveAtTheSameTime) {
2416 SCOPED_FLAG_OVERRIDE(enable_multi_device_same_window_stream, true);
2417 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
2418 sp<FakeWindowHandle> window =
2419 sp<FakeWindowHandle>::make(application, mDispatcher, "Window", ADISPLAY_ID_DEFAULT);
2420 window->setFrame(Rect(0, 0, 200, 200));
2421
2422 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
2423
2424 constexpr int32_t stylusDeviceId1 = 3;
2425 constexpr int32_t stylusDeviceId2 = 5;
2426
2427 // Touch down on window
2428 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_STYLUS)
2429 .deviceId(stylusDeviceId1)
2430 .pointer(PointerBuilder(0, ToolType::STYLUS).x(99).y(100))
2431 .build());
2432 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_STYLUS)
2433 .deviceId(stylusDeviceId1)
2434 .pointer(PointerBuilder(0, ToolType::STYLUS).x(100).y(101))
2435 .build());
2436 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(stylusDeviceId1)));
2437 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(stylusDeviceId1)));
2438
2439 // Second stylus down
2440 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_STYLUS)
2441 .deviceId(stylusDeviceId2)
2442 .pointer(PointerBuilder(0, ToolType::STYLUS).x(9).y(10))
2443 .build());
2444 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_STYLUS)
2445 .deviceId(stylusDeviceId2)
2446 .pointer(PointerBuilder(0, ToolType::STYLUS).x(10).y(11))
2447 .build());
2448 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(stylusDeviceId2)));
2449 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(stylusDeviceId2)));
2450
2451 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_STYLUS)
2452 .deviceId(stylusDeviceId1)
2453 .pointer(PointerBuilder(0, ToolType::STYLUS).x(101).y(102))
2454 .build());
2455 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(stylusDeviceId1)));
2456 window->assertNoEvents();
2457}
2458
2459/**
Siarhei Vishniakou2899c552023-07-10 18:20:46 -07002460 * One window. Touch down on the window. Then, stylus down on the window from another device.
2461 * Ensure that is canceled, because stylus down should be preferred over touch.
2462 */
2463TEST_F(InputDispatcherMultiDeviceTest, TouchIsCanceledByStylusDown) {
Siarhei Vishniakoued89cbb2023-10-13 10:42:44 -07002464 SCOPED_FLAG_OVERRIDE(enable_multi_device_same_window_stream, false);
Siarhei Vishniakou2899c552023-07-10 18:20:46 -07002465 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
2466 sp<FakeWindowHandle> window =
2467 sp<FakeWindowHandle>::make(application, mDispatcher, "Window", ADISPLAY_ID_DEFAULT);
2468 window->setFrame(Rect(0, 0, 200, 200));
2469
2470 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
2471
2472 constexpr int32_t touchDeviceId = 4;
2473 constexpr int32_t stylusDeviceId = 2;
2474
2475 // Touch down on window
2476 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
2477 .deviceId(touchDeviceId)
2478 .pointer(PointerBuilder(0, ToolType::FINGER).x(140).y(145))
2479 .build());
2480 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN)
2481 .deviceId(touchDeviceId)
2482 .pointer(PointerBuilder(0, ToolType::FINGER).x(141).y(146))
2483 .build());
2484 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(touchDeviceId)));
2485 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(touchDeviceId)));
2486
2487 // Stylus down on the window
2488 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_STYLUS)
2489 .deviceId(stylusDeviceId)
2490 .pointer(PointerBuilder(0, ToolType::STYLUS).x(100).y(110))
2491 .build());
2492 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_CANCEL), WithDeviceId(touchDeviceId)));
2493 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(stylusDeviceId)));
2494
2495 // Subsequent stylus movements are delivered correctly
2496 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_STYLUS)
2497 .deviceId(stylusDeviceId)
2498 .pointer(PointerBuilder(0, ToolType::STYLUS).x(101).y(111))
2499 .build());
2500 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(stylusDeviceId),
2501 WithCoords(101, 111)));
2502}
2503
2504/**
Siarhei Vishniakoued89cbb2023-10-13 10:42:44 -07002505 * One window. Touch down on the window. Then, stylus down on the window from another device.
2506 * Ensure that both touch and stylus are functioning independently.
2507 */
2508TEST_F(InputDispatcherMultiDeviceTest, TouchIsNotCanceledByStylusDown) {
2509 SCOPED_FLAG_OVERRIDE(enable_multi_device_same_window_stream, true);
2510 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
2511 sp<FakeWindowHandle> window =
2512 sp<FakeWindowHandle>::make(application, mDispatcher, "Window", ADISPLAY_ID_DEFAULT);
2513 window->setFrame(Rect(0, 0, 200, 200));
2514
2515 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
2516
2517 constexpr int32_t touchDeviceId = 4;
2518 constexpr int32_t stylusDeviceId = 2;
2519
2520 // Touch down on window
2521 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
2522 .deviceId(touchDeviceId)
2523 .pointer(PointerBuilder(0, ToolType::FINGER).x(140).y(145))
2524 .build());
2525 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN)
2526 .deviceId(touchDeviceId)
2527 .pointer(PointerBuilder(0, ToolType::FINGER).x(141).y(146))
2528 .build());
2529 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(touchDeviceId)));
2530 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(touchDeviceId)));
2531
2532 // Stylus down on the window
2533 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_STYLUS)
2534 .deviceId(stylusDeviceId)
2535 .pointer(PointerBuilder(0, ToolType::STYLUS).x(100).y(110))
2536 .build());
2537 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(stylusDeviceId)));
2538
2539 // Subsequent stylus movements are delivered correctly
2540 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_STYLUS)
2541 .deviceId(stylusDeviceId)
2542 .pointer(PointerBuilder(0, ToolType::STYLUS).x(101).y(111))
2543 .build());
2544 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(stylusDeviceId),
2545 WithCoords(101, 111)));
2546
2547 // Touch continues to work too
2548 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN)
2549 .deviceId(touchDeviceId)
2550 .pointer(PointerBuilder(0, ToolType::FINGER).x(148).y(149))
2551 .build());
2552 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(touchDeviceId)));
2553}
2554
2555/**
Siarhei Vishniakouf372b812023-02-14 18:06:51 -08002556 * Two windows: a window on the left and a window on the right.
2557 * Mouse is clicked on the left window and remains down. Touch is touched on the right and remains
2558 * down. Then, on the left window, also place second touch pointer down.
2559 * This test tries to reproduce a crash.
2560 * In the buggy implementation, second pointer down on the left window would cause a crash.
2561 */
Siarhei Vishniakoued89cbb2023-10-13 10:42:44 -07002562TEST_F(InputDispatcherMultiDeviceTest, MultiDeviceSplitTouch_legacy) {
2563 SCOPED_FLAG_OVERRIDE(enable_multi_device_same_window_stream, false);
Siarhei Vishniakouf372b812023-02-14 18:06:51 -08002564 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
2565 sp<FakeWindowHandle> leftWindow =
2566 sp<FakeWindowHandle>::make(application, mDispatcher, "Left", ADISPLAY_ID_DEFAULT);
2567 leftWindow->setFrame(Rect(0, 0, 200, 200));
2568
2569 sp<FakeWindowHandle> rightWindow =
2570 sp<FakeWindowHandle>::make(application, mDispatcher, "Right", ADISPLAY_ID_DEFAULT);
2571 rightWindow->setFrame(Rect(200, 0, 400, 200));
2572
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07002573 mDispatcher->onWindowInfosChanged(
2574 {{*leftWindow->getInfo(), *rightWindow->getInfo()}, {}, 0, 0});
Siarhei Vishniakouf372b812023-02-14 18:06:51 -08002575
2576 const int32_t touchDeviceId = 4;
2577 const int32_t mouseDeviceId = 6;
Siarhei Vishniakouf372b812023-02-14 18:06:51 -08002578
2579 // Start hovering over the left window
Prabir Pradhan678438e2023-04-13 19:32:51 +00002580 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_ENTER, AINPUT_SOURCE_MOUSE)
2581 .deviceId(mouseDeviceId)
2582 .pointer(PointerBuilder(0, ToolType::MOUSE).x(100).y(100))
2583 .build());
Siarhei Vishniakouf372b812023-02-14 18:06:51 -08002584 leftWindow->consumeMotionEvent(
2585 AllOf(WithMotionAction(ACTION_HOVER_ENTER), WithDeviceId(mouseDeviceId)));
2586
2587 // Mouse down on left window
Prabir Pradhan678438e2023-04-13 19:32:51 +00002588 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_MOUSE)
2589 .deviceId(mouseDeviceId)
2590 .buttonState(AMOTION_EVENT_BUTTON_PRIMARY)
2591 .pointer(PointerBuilder(0, ToolType::MOUSE).x(100).y(100))
2592 .build());
Siarhei Vishniakouf372b812023-02-14 18:06:51 -08002593
2594 leftWindow->consumeMotionEvent(
2595 AllOf(WithMotionAction(ACTION_HOVER_EXIT), WithDeviceId(mouseDeviceId)));
2596 leftWindow->consumeMotionEvent(
2597 AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(mouseDeviceId)));
2598
Prabir Pradhan678438e2023-04-13 19:32:51 +00002599 mDispatcher->notifyMotion(
2600 MotionArgsBuilder(AMOTION_EVENT_ACTION_BUTTON_PRESS, AINPUT_SOURCE_MOUSE)
2601 .deviceId(mouseDeviceId)
2602 .buttonState(AMOTION_EVENT_BUTTON_PRIMARY)
2603 .actionButton(AMOTION_EVENT_BUTTON_PRIMARY)
2604 .pointer(PointerBuilder(0, ToolType::MOUSE).x(100).y(100))
2605 .build());
Siarhei Vishniakouf372b812023-02-14 18:06:51 -08002606 leftWindow->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_BUTTON_PRESS));
2607
2608 // First touch pointer down on right window
Prabir Pradhan678438e2023-04-13 19:32:51 +00002609 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
2610 .deviceId(touchDeviceId)
2611 .pointer(PointerBuilder(0, ToolType::FINGER).x(300).y(100))
2612 .build());
Siarhei Vishniakou2899c552023-07-10 18:20:46 -07002613 leftWindow->assertNoEvents();
2614
Siarhei Vishniakouf372b812023-02-14 18:06:51 -08002615 rightWindow->consumeMotionEvent(WithMotionAction(ACTION_DOWN));
2616
2617 // Second touch pointer down on left window
Prabir Pradhan678438e2023-04-13 19:32:51 +00002618 mDispatcher->notifyMotion(MotionArgsBuilder(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
2619 .deviceId(touchDeviceId)
2620 .pointer(PointerBuilder(0, ToolType::FINGER).x(300).y(100))
2621 .pointer(PointerBuilder(1, ToolType::FINGER).x(100).y(100))
2622 .build());
Siarhei Vishniakou2899c552023-07-10 18:20:46 -07002623 // Since this is now a new splittable pointer going down on the left window, and it's coming
2624 // from a different device, the current gesture in the left window (pointer down) should first
2625 // be canceled.
2626 leftWindow->consumeMotionEvent(
2627 AllOf(WithMotionAction(ACTION_CANCEL), WithDeviceId(mouseDeviceId)));
Siarhei Vishniakouf372b812023-02-14 18:06:51 -08002628 leftWindow->consumeMotionEvent(
2629 AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(touchDeviceId)));
2630 // This MOVE event is not necessary (doesn't carry any new information), but it's there in the
2631 // current implementation.
2632 const std::map<int32_t, PointF> expectedPointers{{0, PointF{100, 100}}};
2633 rightWindow->consumeMotionEvent(
2634 AllOf(WithMotionAction(ACTION_MOVE), WithPointers(expectedPointers)));
2635
2636 leftWindow->assertNoEvents();
2637 rightWindow->assertNoEvents();
2638}
2639
2640/**
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -07002641 * Two windows: a window on the left and a window on the right.
Siarhei Vishniakoued89cbb2023-10-13 10:42:44 -07002642 * Mouse is clicked on the left window and remains down. Touch is touched on the right and remains
2643 * down. Then, on the left window, also place second touch pointer down.
2644 * This test tries to reproduce a crash.
2645 * In the buggy implementation, second pointer down on the left window would cause a crash.
2646 */
2647TEST_F(InputDispatcherMultiDeviceTest, MultiDeviceSplitTouch) {
2648 SCOPED_FLAG_OVERRIDE(enable_multi_device_same_window_stream, true);
2649 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
2650 sp<FakeWindowHandle> leftWindow =
2651 sp<FakeWindowHandle>::make(application, mDispatcher, "Left", ADISPLAY_ID_DEFAULT);
2652 leftWindow->setFrame(Rect(0, 0, 200, 200));
2653
2654 sp<FakeWindowHandle> rightWindow =
2655 sp<FakeWindowHandle>::make(application, mDispatcher, "Right", ADISPLAY_ID_DEFAULT);
2656 rightWindow->setFrame(Rect(200, 0, 400, 200));
2657
2658 mDispatcher->onWindowInfosChanged(
2659 {{*leftWindow->getInfo(), *rightWindow->getInfo()}, {}, 0, 0});
2660
2661 const int32_t touchDeviceId = 4;
2662 const int32_t mouseDeviceId = 6;
2663
2664 // Start hovering over the left window
2665 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_ENTER, AINPUT_SOURCE_MOUSE)
2666 .deviceId(mouseDeviceId)
2667 .pointer(PointerBuilder(0, ToolType::MOUSE).x(100).y(100))
2668 .build());
2669 leftWindow->consumeMotionEvent(
2670 AllOf(WithMotionAction(ACTION_HOVER_ENTER), WithDeviceId(mouseDeviceId)));
2671
2672 // Mouse down on left window
2673 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_MOUSE)
2674 .deviceId(mouseDeviceId)
2675 .buttonState(AMOTION_EVENT_BUTTON_PRIMARY)
2676 .pointer(PointerBuilder(0, ToolType::MOUSE).x(100).y(100))
2677 .build());
2678
2679 leftWindow->consumeMotionEvent(
2680 AllOf(WithMotionAction(ACTION_HOVER_EXIT), WithDeviceId(mouseDeviceId)));
2681 leftWindow->consumeMotionEvent(
2682 AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(mouseDeviceId)));
2683
2684 mDispatcher->notifyMotion(
2685 MotionArgsBuilder(AMOTION_EVENT_ACTION_BUTTON_PRESS, AINPUT_SOURCE_MOUSE)
2686 .deviceId(mouseDeviceId)
2687 .buttonState(AMOTION_EVENT_BUTTON_PRIMARY)
2688 .actionButton(AMOTION_EVENT_BUTTON_PRIMARY)
2689 .pointer(PointerBuilder(0, ToolType::MOUSE).x(100).y(100))
2690 .build());
2691 leftWindow->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_BUTTON_PRESS));
2692
2693 // First touch pointer down on right window
2694 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
2695 .deviceId(touchDeviceId)
2696 .pointer(PointerBuilder(0, ToolType::FINGER).x(300).y(100))
2697 .build());
2698 leftWindow->assertNoEvents();
2699
2700 rightWindow->consumeMotionEvent(WithMotionAction(ACTION_DOWN));
2701
2702 // Second touch pointer down on left window
2703 mDispatcher->notifyMotion(MotionArgsBuilder(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
2704 .deviceId(touchDeviceId)
2705 .pointer(PointerBuilder(0, ToolType::FINGER).x(300).y(100))
2706 .pointer(PointerBuilder(1, ToolType::FINGER).x(100).y(100))
2707 .build());
2708 // Since this is now a new splittable pointer going down on the left window, and it's coming
2709 // from a different device, it will be split and delivered to left window separately.
2710 leftWindow->consumeMotionEvent(
2711 AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(touchDeviceId)));
2712 // This MOVE event is not necessary (doesn't carry any new information), but it's there in the
2713 // current implementation.
2714 const std::map<int32_t, PointF> expectedPointers{{0, PointF{100, 100}}};
2715 rightWindow->consumeMotionEvent(
2716 AllOf(WithMotionAction(ACTION_MOVE), WithPointers(expectedPointers)));
2717
2718 leftWindow->assertNoEvents();
2719 rightWindow->assertNoEvents();
2720}
2721
2722/**
2723 * Two windows: a window on the left and a window on the right.
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -07002724 * Mouse is hovered on the left window and stylus is hovered on the right window.
2725 */
2726TEST_F(InputDispatcherMultiDeviceTest, MultiDeviceHover) {
2727 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
2728 sp<FakeWindowHandle> leftWindow =
2729 sp<FakeWindowHandle>::make(application, mDispatcher, "Left", ADISPLAY_ID_DEFAULT);
2730 leftWindow->setFrame(Rect(0, 0, 200, 200));
2731
2732 sp<FakeWindowHandle> rightWindow =
2733 sp<FakeWindowHandle>::make(application, mDispatcher, "Right", ADISPLAY_ID_DEFAULT);
2734 rightWindow->setFrame(Rect(200, 0, 400, 200));
2735
2736 mDispatcher->onWindowInfosChanged(
2737 {{*leftWindow->getInfo(), *rightWindow->getInfo()}, {}, 0, 0});
2738
2739 const int32_t stylusDeviceId = 3;
2740 const int32_t mouseDeviceId = 6;
2741
2742 // Start hovering over the left window
2743 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_ENTER, AINPUT_SOURCE_MOUSE)
2744 .deviceId(mouseDeviceId)
2745 .pointer(PointerBuilder(0, ToolType::MOUSE).x(100).y(110))
2746 .build());
2747 leftWindow->consumeMotionEvent(
2748 AllOf(WithMotionAction(ACTION_HOVER_ENTER), WithDeviceId(mouseDeviceId)));
2749
2750 // Stylus hovered on right window
2751 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_ENTER, AINPUT_SOURCE_STYLUS)
2752 .deviceId(stylusDeviceId)
2753 .pointer(PointerBuilder(0, ToolType::STYLUS).x(300).y(100))
2754 .build());
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -07002755 rightWindow->consumeMotionEvent(
2756 AllOf(WithMotionAction(ACTION_HOVER_ENTER), WithDeviceId(stylusDeviceId)));
2757
2758 // Subsequent HOVER_MOVE events are dispatched correctly.
2759 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_MOVE, AINPUT_SOURCE_MOUSE)
2760 .deviceId(mouseDeviceId)
2761 .pointer(PointerBuilder(0, ToolType::MOUSE).x(110).y(120))
2762 .build());
2763 leftWindow->consumeMotionEvent(
Siarhei Vishniakou2899c552023-07-10 18:20:46 -07002764 AllOf(WithMotionAction(ACTION_HOVER_MOVE), WithDeviceId(mouseDeviceId)));
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -07002765
2766 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_MOVE, AINPUT_SOURCE_STYLUS)
2767 .deviceId(stylusDeviceId)
2768 .pointer(PointerBuilder(0, ToolType::STYLUS).x(310).y(110))
2769 .build());
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -07002770 rightWindow->consumeMotionEvent(
Siarhei Vishniakou2899c552023-07-10 18:20:46 -07002771 AllOf(WithMotionAction(ACTION_HOVER_MOVE), WithDeviceId(stylusDeviceId)));
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -07002772
2773 leftWindow->assertNoEvents();
2774 rightWindow->assertNoEvents();
2775}
2776
2777/**
2778 * Three windows: a window on the left and a window on the right.
2779 * And a spy window that's positioned above all of them.
2780 * Stylus down on the left window and remains down. Touch goes down on the right and remains down.
2781 * Check the stream that's received by the spy.
2782 */
Siarhei Vishniakoued89cbb2023-10-13 10:42:44 -07002783TEST_F(InputDispatcherMultiDeviceTest, MultiDeviceWithSpy_legacy) {
2784 SCOPED_FLAG_OVERRIDE(enable_multi_device_same_window_stream, false);
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -07002785 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
2786
2787 sp<FakeWindowHandle> spyWindow =
2788 sp<FakeWindowHandle>::make(application, mDispatcher, "Spy", ADISPLAY_ID_DEFAULT);
2789 spyWindow->setFrame(Rect(0, 0, 400, 400));
2790 spyWindow->setTrustedOverlay(true);
2791 spyWindow->setSpy(true);
2792
2793 sp<FakeWindowHandle> leftWindow =
2794 sp<FakeWindowHandle>::make(application, mDispatcher, "Left", ADISPLAY_ID_DEFAULT);
2795 leftWindow->setFrame(Rect(0, 0, 200, 200));
2796
2797 sp<FakeWindowHandle> rightWindow =
2798 sp<FakeWindowHandle>::make(application, mDispatcher, "Right", ADISPLAY_ID_DEFAULT);
2799
2800 rightWindow->setFrame(Rect(200, 0, 400, 200));
2801
2802 mDispatcher->onWindowInfosChanged(
2803 {{*spyWindow->getInfo(), *leftWindow->getInfo(), *rightWindow->getInfo()}, {}, 0, 0});
2804
2805 const int32_t stylusDeviceId = 1;
2806 const int32_t touchDeviceId = 2;
2807
2808 // Stylus down on the left window
2809 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_STYLUS)
2810 .deviceId(stylusDeviceId)
2811 .pointer(PointerBuilder(0, ToolType::STYLUS).x(100).y(100))
2812 .build());
2813 leftWindow->consumeMotionEvent(
2814 AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(stylusDeviceId)));
2815 spyWindow->consumeMotionEvent(
2816 AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(stylusDeviceId)));
2817
2818 // Touch down on the right window
2819 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
2820 .deviceId(touchDeviceId)
2821 .pointer(PointerBuilder(0, ToolType::FINGER).x(300).y(100))
2822 .build());
Siarhei Vishniakou2899c552023-07-10 18:20:46 -07002823 leftWindow->assertNoEvents();
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -07002824 rightWindow->consumeMotionEvent(
2825 AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(touchDeviceId)));
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -07002826
Siarhei Vishniakou2899c552023-07-10 18:20:46 -07002827 // Spy window does not receive touch events, because stylus events take precedence, and it
2828 // already has an active stylus gesture.
2829
2830 // Stylus movements continue. They should be delivered to the left window and to the spy window
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -07002831 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_STYLUS)
2832 .deviceId(stylusDeviceId)
2833 .pointer(PointerBuilder(0, ToolType::STYLUS).x(110).y(110))
2834 .build());
Siarhei Vishniakou2899c552023-07-10 18:20:46 -07002835 leftWindow->consumeMotionEvent(
2836 AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(stylusDeviceId)));
2837 spyWindow->consumeMotionEvent(
2838 AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(stylusDeviceId)));
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -07002839
Siarhei Vishniakou2899c552023-07-10 18:20:46 -07002840 // Further MOVE events keep going to the right window only
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -07002841 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN)
2842 .deviceId(touchDeviceId)
2843 .pointer(PointerBuilder(0, ToolType::FINGER).x(310).y(110))
2844 .build());
2845 rightWindow->consumeMotionEvent(
2846 AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(touchDeviceId)));
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -07002847
2848 spyWindow->assertNoEvents();
2849 leftWindow->assertNoEvents();
2850 rightWindow->assertNoEvents();
2851}
2852
2853/**
Siarhei Vishniakoued89cbb2023-10-13 10:42:44 -07002854 * Three windows: a window on the left and a window on the right.
2855 * And a spy window that's positioned above all of them.
2856 * Stylus down on the left window and remains down. Touch goes down on the right and remains down.
2857 * Check the stream that's received by the spy.
2858 */
2859TEST_F(InputDispatcherMultiDeviceTest, MultiDeviceWithSpy) {
2860 SCOPED_FLAG_OVERRIDE(enable_multi_device_same_window_stream, true);
2861 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
2862
2863 sp<FakeWindowHandle> spyWindow =
2864 sp<FakeWindowHandle>::make(application, mDispatcher, "Spy", ADISPLAY_ID_DEFAULT);
2865 spyWindow->setFrame(Rect(0, 0, 400, 400));
2866 spyWindow->setTrustedOverlay(true);
2867 spyWindow->setSpy(true);
2868
2869 sp<FakeWindowHandle> leftWindow =
2870 sp<FakeWindowHandle>::make(application, mDispatcher, "Left", ADISPLAY_ID_DEFAULT);
2871 leftWindow->setFrame(Rect(0, 0, 200, 200));
2872
2873 sp<FakeWindowHandle> rightWindow =
2874 sp<FakeWindowHandle>::make(application, mDispatcher, "Right", ADISPLAY_ID_DEFAULT);
2875
2876 rightWindow->setFrame(Rect(200, 0, 400, 200));
2877
2878 mDispatcher->onWindowInfosChanged(
2879 {{*spyWindow->getInfo(), *leftWindow->getInfo(), *rightWindow->getInfo()}, {}, 0, 0});
2880
2881 const int32_t stylusDeviceId = 1;
2882 const int32_t touchDeviceId = 2;
2883
2884 // Stylus down on the left window
2885 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_STYLUS)
2886 .deviceId(stylusDeviceId)
2887 .pointer(PointerBuilder(0, ToolType::STYLUS).x(100).y(100))
2888 .build());
2889 leftWindow->consumeMotionEvent(
2890 AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(stylusDeviceId)));
2891 spyWindow->consumeMotionEvent(
2892 AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(stylusDeviceId)));
2893
2894 // Touch down on the right window
2895 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
2896 .deviceId(touchDeviceId)
2897 .pointer(PointerBuilder(0, ToolType::FINGER).x(300).y(100))
2898 .build());
2899 leftWindow->assertNoEvents();
2900 rightWindow->consumeMotionEvent(
2901 AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(touchDeviceId)));
2902 spyWindow->consumeMotionEvent(
2903 AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(touchDeviceId)));
2904
2905 // Stylus movements continue. They should be delivered to the left window and to the spy window
2906 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_STYLUS)
2907 .deviceId(stylusDeviceId)
2908 .pointer(PointerBuilder(0, ToolType::STYLUS).x(110).y(110))
2909 .build());
2910 leftWindow->consumeMotionEvent(
2911 AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(stylusDeviceId)));
2912 spyWindow->consumeMotionEvent(
2913 AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(stylusDeviceId)));
2914
2915 // Further touch MOVE events keep going to the right window and to the spy
2916 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN)
2917 .deviceId(touchDeviceId)
2918 .pointer(PointerBuilder(0, ToolType::FINGER).x(310).y(110))
2919 .build());
2920 rightWindow->consumeMotionEvent(
2921 AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(touchDeviceId)));
2922 spyWindow->consumeMotionEvent(
2923 AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(touchDeviceId)));
2924
2925 spyWindow->assertNoEvents();
2926 leftWindow->assertNoEvents();
2927 rightWindow->assertNoEvents();
2928}
2929
2930/**
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -07002931 * Three windows: a window on the left, a window on the right, and a spy window positioned above
2932 * both.
2933 * Check hover in left window and touch down in the right window.
Siarhei Vishniakou3ad54f52023-11-02 16:54:40 -07002934 * At first, spy should receive hover. Spy shouldn't receive touch while stylus is hovering.
Siarhei Vishniakou2899c552023-07-10 18:20:46 -07002935 * At the same time, left and right should be getting independent streams of hovering and touch,
2936 * respectively.
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -07002937 */
Siarhei Vishniakou3ad54f52023-11-02 16:54:40 -07002938TEST_F(InputDispatcherMultiDeviceTest, MultiDeviceHoverBlocksTouchWithSpy) {
Siarhei Vishniakoued89cbb2023-10-13 10:42:44 -07002939 SCOPED_FLAG_OVERRIDE(enable_multi_device_same_window_stream, false);
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -07002940 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
2941
2942 sp<FakeWindowHandle> spyWindow =
2943 sp<FakeWindowHandle>::make(application, mDispatcher, "Spy", ADISPLAY_ID_DEFAULT);
2944 spyWindow->setFrame(Rect(0, 0, 400, 400));
2945 spyWindow->setTrustedOverlay(true);
2946 spyWindow->setSpy(true);
2947
2948 sp<FakeWindowHandle> leftWindow =
2949 sp<FakeWindowHandle>::make(application, mDispatcher, "Left", ADISPLAY_ID_DEFAULT);
2950 leftWindow->setFrame(Rect(0, 0, 200, 200));
2951
2952 sp<FakeWindowHandle> rightWindow =
2953 sp<FakeWindowHandle>::make(application, mDispatcher, "Right", ADISPLAY_ID_DEFAULT);
2954 rightWindow->setFrame(Rect(200, 0, 400, 200));
2955
2956 mDispatcher->onWindowInfosChanged(
2957 {{*spyWindow->getInfo(), *leftWindow->getInfo(), *rightWindow->getInfo()}, {}, 0, 0});
2958
2959 const int32_t stylusDeviceId = 1;
2960 const int32_t touchDeviceId = 2;
2961
2962 // Stylus hover on the left window
2963 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_ENTER, AINPUT_SOURCE_STYLUS)
2964 .deviceId(stylusDeviceId)
2965 .pointer(PointerBuilder(0, ToolType::STYLUS).x(100).y(100))
2966 .build());
2967 leftWindow->consumeMotionEvent(
2968 AllOf(WithMotionAction(ACTION_HOVER_ENTER), WithDeviceId(stylusDeviceId)));
2969 spyWindow->consumeMotionEvent(
2970 AllOf(WithMotionAction(ACTION_HOVER_ENTER), WithDeviceId(stylusDeviceId)));
2971
Siarhei Vishniakou2899c552023-07-10 18:20:46 -07002972 // Touch down on the right window. Spy doesn't receive this touch because it already has
2973 // stylus hovering there.
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -07002974 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
2975 .deviceId(touchDeviceId)
2976 .pointer(PointerBuilder(0, ToolType::FINGER).x(300).y(100))
2977 .build());
Siarhei Vishniakou2899c552023-07-10 18:20:46 -07002978 leftWindow->assertNoEvents();
Siarhei Vishniakou3ad54f52023-11-02 16:54:40 -07002979 spyWindow->assertNoEvents();
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -07002980 rightWindow->consumeMotionEvent(
2981 AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(touchDeviceId)));
2982
Siarhei Vishniakou3ad54f52023-11-02 16:54:40 -07002983 // Stylus movements continue. They should be delivered to the left window and the spy.
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -07002984 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_MOVE, AINPUT_SOURCE_STYLUS)
2985 .deviceId(stylusDeviceId)
2986 .pointer(PointerBuilder(0, ToolType::STYLUS).x(110).y(110))
2987 .build());
Siarhei Vishniakou2899c552023-07-10 18:20:46 -07002988 leftWindow->consumeMotionEvent(
2989 AllOf(WithMotionAction(ACTION_HOVER_MOVE), WithDeviceId(stylusDeviceId)));
Siarhei Vishniakou3ad54f52023-11-02 16:54:40 -07002990 spyWindow->consumeMotionEvent(
2991 AllOf(WithMotionAction(ACTION_HOVER_MOVE), WithDeviceId(stylusDeviceId)));
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -07002992
Siarhei Vishniakou3ad54f52023-11-02 16:54:40 -07002993 // Touch movements continue. They should be delivered to the right window only
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -07002994 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN)
2995 .deviceId(touchDeviceId)
2996 .pointer(PointerBuilder(0, ToolType::FINGER).x(301).y(101))
2997 .build());
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -07002998 rightWindow->consumeMotionEvent(
2999 AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(touchDeviceId)));
3000
3001 spyWindow->assertNoEvents();
3002 leftWindow->assertNoEvents();
3003 rightWindow->assertNoEvents();
3004}
3005
3006/**
Siarhei Vishniakoued89cbb2023-10-13 10:42:44 -07003007 * Three windows: a window on the left, a window on the right, and a spy window positioned above
3008 * both.
3009 * Check hover in left window and touch down in the right window.
3010 * At first, spy should receive hover. Next, spy should receive touch.
3011 * At the same time, left and right should be getting independent streams of hovering and touch,
3012 * respectively.
3013 */
3014TEST_F(InputDispatcherMultiDeviceTest, MultiDeviceHoverDoesNotBlockTouchWithSpy) {
3015 SCOPED_FLAG_OVERRIDE(enable_multi_device_same_window_stream, true);
3016 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
3017
3018 sp<FakeWindowHandle> spyWindow =
3019 sp<FakeWindowHandle>::make(application, mDispatcher, "Spy", ADISPLAY_ID_DEFAULT);
3020 spyWindow->setFrame(Rect(0, 0, 400, 400));
3021 spyWindow->setTrustedOverlay(true);
3022 spyWindow->setSpy(true);
3023
3024 sp<FakeWindowHandle> leftWindow =
3025 sp<FakeWindowHandle>::make(application, mDispatcher, "Left", ADISPLAY_ID_DEFAULT);
3026 leftWindow->setFrame(Rect(0, 0, 200, 200));
3027
3028 sp<FakeWindowHandle> rightWindow =
3029 sp<FakeWindowHandle>::make(application, mDispatcher, "Right", ADISPLAY_ID_DEFAULT);
3030 rightWindow->setFrame(Rect(200, 0, 400, 200));
3031
3032 mDispatcher->onWindowInfosChanged(
3033 {{*spyWindow->getInfo(), *leftWindow->getInfo(), *rightWindow->getInfo()}, {}, 0, 0});
3034
3035 const int32_t stylusDeviceId = 1;
3036 const int32_t touchDeviceId = 2;
3037
3038 // Stylus hover on the left window
3039 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_ENTER, AINPUT_SOURCE_STYLUS)
3040 .deviceId(stylusDeviceId)
3041 .pointer(PointerBuilder(0, ToolType::STYLUS).x(100).y(100))
3042 .build());
3043 leftWindow->consumeMotionEvent(
3044 AllOf(WithMotionAction(ACTION_HOVER_ENTER), WithDeviceId(stylusDeviceId)));
3045 spyWindow->consumeMotionEvent(
3046 AllOf(WithMotionAction(ACTION_HOVER_ENTER), WithDeviceId(stylusDeviceId)));
3047
3048 // Touch down on the right window.
3049 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
3050 .deviceId(touchDeviceId)
3051 .pointer(PointerBuilder(0, ToolType::FINGER).x(300).y(100))
3052 .build());
3053 leftWindow->assertNoEvents();
3054 spyWindow->consumeMotionEvent(
3055 AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(touchDeviceId)));
3056 rightWindow->consumeMotionEvent(
3057 AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(touchDeviceId)));
3058
3059 // Stylus movements continue. They should be delivered to the left window and the spy.
3060 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_MOVE, AINPUT_SOURCE_STYLUS)
3061 .deviceId(stylusDeviceId)
3062 .pointer(PointerBuilder(0, ToolType::STYLUS).x(110).y(110))
3063 .build());
3064 leftWindow->consumeMotionEvent(
3065 AllOf(WithMotionAction(ACTION_HOVER_MOVE), WithDeviceId(stylusDeviceId)));
3066 spyWindow->consumeMotionEvent(
3067 AllOf(WithMotionAction(ACTION_HOVER_MOVE), WithDeviceId(stylusDeviceId)));
3068
3069 // Touch movements continue. They should be delivered to the right window and the spy
3070 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN)
3071 .deviceId(touchDeviceId)
3072 .pointer(PointerBuilder(0, ToolType::FINGER).x(301).y(101))
3073 .build());
3074 rightWindow->consumeMotionEvent(
3075 AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(touchDeviceId)));
3076 spyWindow->consumeMotionEvent(
3077 AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(touchDeviceId)));
3078
3079 spyWindow->assertNoEvents();
3080 leftWindow->assertNoEvents();
3081 rightWindow->assertNoEvents();
3082}
3083
3084/**
Siarhei Vishniakouf372b812023-02-14 18:06:51 -08003085 * On a single window, use two different devices: mouse and touch.
3086 * Touch happens first, with two pointers going down, and then the first pointer leaving.
3087 * Mouse is clicked next, which causes the touch stream to be aborted with ACTION_CANCEL.
3088 * Finally, a second touch pointer goes down again. Ensure the second touch pointer is ignored,
3089 * because the mouse is currently down, and a POINTER_DOWN event from the touchscreen does not
3090 * represent a new gesture.
3091 */
Siarhei Vishniakoued89cbb2023-10-13 10:42:44 -07003092TEST_F(InputDispatcherMultiDeviceTest, MixedTouchAndMouseWithPointerDown_legacy) {
3093 SCOPED_FLAG_OVERRIDE(enable_multi_device_same_window_stream, false);
Siarhei Vishniakouf372b812023-02-14 18:06:51 -08003094 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
3095 sp<FakeWindowHandle> window =
3096 sp<FakeWindowHandle>::make(application, mDispatcher, "Window", ADISPLAY_ID_DEFAULT);
3097 window->setFrame(Rect(0, 0, 400, 400));
3098
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07003099 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Siarhei Vishniakouf372b812023-02-14 18:06:51 -08003100
3101 const int32_t touchDeviceId = 4;
3102 const int32_t mouseDeviceId = 6;
Siarhei Vishniakouf372b812023-02-14 18:06:51 -08003103
Siarhei Vishniakou4e1ffa52023-02-21 11:50:34 -08003104 // First touch pointer down
Prabir Pradhan678438e2023-04-13 19:32:51 +00003105 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
3106 .deviceId(touchDeviceId)
3107 .pointer(PointerBuilder(0, ToolType::FINGER).x(300).y(100))
3108 .build());
Siarhei Vishniakouf372b812023-02-14 18:06:51 -08003109 // Second touch pointer down
Prabir Pradhan678438e2023-04-13 19:32:51 +00003110 mDispatcher->notifyMotion(MotionArgsBuilder(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
3111 .deviceId(touchDeviceId)
3112 .pointer(PointerBuilder(0, ToolType::FINGER).x(300).y(100))
3113 .pointer(PointerBuilder(1, ToolType::FINGER).x(350).y(100))
3114 .build());
Siarhei Vishniakouf372b812023-02-14 18:06:51 -08003115 // First touch pointer lifts. The second one remains down
Prabir Pradhan678438e2023-04-13 19:32:51 +00003116 mDispatcher->notifyMotion(MotionArgsBuilder(POINTER_0_UP, AINPUT_SOURCE_TOUCHSCREEN)
3117 .deviceId(touchDeviceId)
3118 .pointer(PointerBuilder(0, ToolType::FINGER).x(300).y(100))
3119 .pointer(PointerBuilder(1, ToolType::FINGER).x(350).y(100))
3120 .build());
Siarhei Vishniakouf372b812023-02-14 18:06:51 -08003121 window->consumeMotionEvent(WithMotionAction(ACTION_DOWN));
3122 window->consumeMotionEvent(WithMotionAction(POINTER_1_DOWN));
3123 window->consumeMotionEvent(WithMotionAction(POINTER_0_UP));
3124
3125 // Mouse down. The touch should be canceled
Prabir Pradhan678438e2023-04-13 19:32:51 +00003126 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_MOUSE)
3127 .deviceId(mouseDeviceId)
3128 .buttonState(AMOTION_EVENT_BUTTON_PRIMARY)
3129 .pointer(PointerBuilder(0, ToolType::MOUSE).x(320).y(100))
3130 .build());
Siarhei Vishniakouf372b812023-02-14 18:06:51 -08003131
3132 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_CANCEL), WithDeviceId(touchDeviceId),
Siarhei Vishniakou82dc0422023-02-17 23:12:52 -08003133 WithPointerCount(1u)));
Siarhei Vishniakouf372b812023-02-14 18:06:51 -08003134 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(mouseDeviceId)));
3135
Prabir Pradhan678438e2023-04-13 19:32:51 +00003136 mDispatcher->notifyMotion(
3137 MotionArgsBuilder(AMOTION_EVENT_ACTION_BUTTON_PRESS, AINPUT_SOURCE_MOUSE)
3138 .deviceId(mouseDeviceId)
3139 .buttonState(AMOTION_EVENT_BUTTON_PRIMARY)
3140 .actionButton(AMOTION_EVENT_BUTTON_PRIMARY)
3141 .pointer(PointerBuilder(0, ToolType::MOUSE).x(320).y(100))
3142 .build());
Siarhei Vishniakouf372b812023-02-14 18:06:51 -08003143 window->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_BUTTON_PRESS));
3144
3145 // Second touch pointer down.
Prabir Pradhan678438e2023-04-13 19:32:51 +00003146 mDispatcher->notifyMotion(MotionArgsBuilder(POINTER_0_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
3147 .deviceId(touchDeviceId)
3148 .pointer(PointerBuilder(0, ToolType::FINGER).x(300).y(100))
3149 .pointer(PointerBuilder(1, ToolType::FINGER).x(350).y(100))
3150 .build());
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -07003151 // Since we already canceled this touch gesture, it will be ignored until a completely new
3152 // gesture is started. This is easier to implement than trying to keep track of the new pointer
3153 // and generating an ACTION_DOWN instead of ACTION_POINTER_DOWN.
3154 // However, mouse movements should continue to work.
3155 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_MOUSE)
3156 .deviceId(mouseDeviceId)
3157 .buttonState(AMOTION_EVENT_BUTTON_PRIMARY)
3158 .pointer(PointerBuilder(0, ToolType::MOUSE).x(330).y(110))
3159 .build());
3160 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(mouseDeviceId)));
3161
Siarhei Vishniakouf372b812023-02-14 18:06:51 -08003162 window->assertNoEvents();
3163}
3164
3165/**
Siarhei Vishniakoued89cbb2023-10-13 10:42:44 -07003166 * On a single window, use two different devices: mouse and touch.
3167 * Touch happens first, with two pointers going down, and then the first pointer leaving.
3168 * Mouse is clicked next, which should not interfere with the touch stream.
3169 * Finally, a second touch pointer goes down again. Ensure the second touch pointer is also
3170 * delivered correctly.
3171 */
3172TEST_F(InputDispatcherMultiDeviceTest, MixedTouchAndMouseWithPointerDown) {
3173 SCOPED_FLAG_OVERRIDE(enable_multi_device_same_window_stream, true);
3174 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
3175 sp<FakeWindowHandle> window =
3176 sp<FakeWindowHandle>::make(application, mDispatcher, "Window", ADISPLAY_ID_DEFAULT);
3177 window->setFrame(Rect(0, 0, 400, 400));
3178
3179 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
3180
3181 const int32_t touchDeviceId = 4;
3182 const int32_t mouseDeviceId = 6;
3183
3184 // First touch pointer down
3185 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
3186 .deviceId(touchDeviceId)
3187 .pointer(PointerBuilder(0, ToolType::FINGER).x(300).y(100))
3188 .build());
3189 // Second touch pointer down
3190 mDispatcher->notifyMotion(MotionArgsBuilder(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
3191 .deviceId(touchDeviceId)
3192 .pointer(PointerBuilder(0, ToolType::FINGER).x(300).y(100))
3193 .pointer(PointerBuilder(1, ToolType::FINGER).x(350).y(100))
3194 .build());
3195 // First touch pointer lifts. The second one remains down
3196 mDispatcher->notifyMotion(MotionArgsBuilder(POINTER_0_UP, AINPUT_SOURCE_TOUCHSCREEN)
3197 .deviceId(touchDeviceId)
3198 .pointer(PointerBuilder(0, ToolType::FINGER).x(300).y(100))
3199 .pointer(PointerBuilder(1, ToolType::FINGER).x(350).y(100))
3200 .build());
3201 window->consumeMotionEvent(WithMotionAction(ACTION_DOWN));
3202 window->consumeMotionEvent(WithMotionAction(POINTER_1_DOWN));
3203 window->consumeMotionEvent(WithMotionAction(POINTER_0_UP));
3204
3205 // Mouse down
3206 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_MOUSE)
3207 .deviceId(mouseDeviceId)
3208 .buttonState(AMOTION_EVENT_BUTTON_PRIMARY)
3209 .pointer(PointerBuilder(0, ToolType::MOUSE).x(320).y(100))
3210 .build());
3211
3212 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(mouseDeviceId)));
3213
3214 mDispatcher->notifyMotion(
3215 MotionArgsBuilder(AMOTION_EVENT_ACTION_BUTTON_PRESS, AINPUT_SOURCE_MOUSE)
3216 .deviceId(mouseDeviceId)
3217 .buttonState(AMOTION_EVENT_BUTTON_PRIMARY)
3218 .actionButton(AMOTION_EVENT_BUTTON_PRIMARY)
3219 .pointer(PointerBuilder(0, ToolType::MOUSE).x(320).y(100))
3220 .build());
3221 window->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_BUTTON_PRESS));
3222
3223 // Second touch pointer down.
3224 mDispatcher->notifyMotion(MotionArgsBuilder(POINTER_0_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
3225 .deviceId(touchDeviceId)
3226 .pointer(PointerBuilder(0, ToolType::FINGER).x(300).y(100))
3227 .pointer(PointerBuilder(1, ToolType::FINGER).x(350).y(100))
3228 .build());
3229 window->consumeMotionEvent(AllOf(WithMotionAction(POINTER_0_DOWN), WithDeviceId(touchDeviceId),
3230 WithPointerCount(2u)));
3231
3232 // Mouse movements should continue to work
3233 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_MOUSE)
3234 .deviceId(mouseDeviceId)
3235 .buttonState(AMOTION_EVENT_BUTTON_PRIMARY)
3236 .pointer(PointerBuilder(0, ToolType::MOUSE).x(330).y(110))
3237 .build());
3238 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(mouseDeviceId)));
3239
3240 window->assertNoEvents();
3241}
3242
3243/**
Siarhei Vishniakou56e79092023-02-21 19:13:16 -08003244 * Inject a touch down and then send a new event via 'notifyMotion'. Ensure the new event cancels
3245 * the injected event.
3246 */
Siarhei Vishniakoued89cbb2023-10-13 10:42:44 -07003247TEST_F(InputDispatcherMultiDeviceTest, UnfinishedInjectedEvent_legacy) {
3248 SCOPED_FLAG_OVERRIDE(enable_multi_device_same_window_stream, false);
Siarhei Vishniakou56e79092023-02-21 19:13:16 -08003249 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
3250 sp<FakeWindowHandle> window =
3251 sp<FakeWindowHandle>::make(application, mDispatcher, "Window", ADISPLAY_ID_DEFAULT);
3252 window->setFrame(Rect(0, 0, 400, 400));
3253
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07003254 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Siarhei Vishniakou56e79092023-02-21 19:13:16 -08003255
3256 const int32_t touchDeviceId = 4;
Siarhei Vishniakou56e79092023-02-21 19:13:16 -08003257 // Pretend a test injects an ACTION_DOWN mouse event, but forgets to lift up the touch after
3258 // completion.
3259 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07003260 injectMotionEvent(*mDispatcher,
Siarhei Vishniakou56e79092023-02-21 19:13:16 -08003261 MotionEventBuilder(ACTION_DOWN, AINPUT_SOURCE_MOUSE)
3262 .deviceId(ReservedInputDeviceId::VIRTUAL_KEYBOARD_ID)
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07003263 .pointer(PointerBuilder(0, ToolType::MOUSE).x(50).y(50))
Siarhei Vishniakou56e79092023-02-21 19:13:16 -08003264 .build()));
3265 window->consumeMotionEvent(
3266 AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(VIRTUAL_KEYBOARD_ID)));
3267
3268 // Now a real touch comes. Rather than crashing or dropping the real event, the injected pointer
3269 // should be canceled and the new gesture should take over.
Prabir Pradhan678438e2023-04-13 19:32:51 +00003270 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
3271 .deviceId(touchDeviceId)
3272 .pointer(PointerBuilder(0, ToolType::FINGER).x(300).y(100))
3273 .build());
Siarhei Vishniakou56e79092023-02-21 19:13:16 -08003274
3275 window->consumeMotionEvent(
3276 AllOf(WithMotionAction(ACTION_CANCEL), WithDeviceId(VIRTUAL_KEYBOARD_ID)));
3277 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(touchDeviceId)));
3278}
3279
3280/**
Siarhei Vishniakoued89cbb2023-10-13 10:42:44 -07003281 * Inject a touch down and then send a new event via 'notifyMotion'. Ensure the new event runs
3282 * parallel to the injected event.
3283 */
3284TEST_F(InputDispatcherMultiDeviceTest, UnfinishedInjectedEvent) {
3285 SCOPED_FLAG_OVERRIDE(enable_multi_device_same_window_stream, true);
3286 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
3287 sp<FakeWindowHandle> window =
3288 sp<FakeWindowHandle>::make(application, mDispatcher, "Window", ADISPLAY_ID_DEFAULT);
3289 window->setFrame(Rect(0, 0, 400, 400));
3290
3291 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
3292
3293 const int32_t touchDeviceId = 4;
3294 // Pretend a test injects an ACTION_DOWN mouse event, but forgets to lift up the touch after
3295 // completion.
3296 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
3297 injectMotionEvent(*mDispatcher,
3298 MotionEventBuilder(ACTION_DOWN, AINPUT_SOURCE_MOUSE)
3299 .deviceId(ReservedInputDeviceId::VIRTUAL_KEYBOARD_ID)
3300 .pointer(PointerBuilder(0, ToolType::MOUSE).x(50).y(50))
3301 .build()));
3302 window->consumeMotionEvent(
3303 AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(VIRTUAL_KEYBOARD_ID)));
3304
3305 // Now a real touch comes. The injected pointer will remain, and the new gesture will also be
3306 // allowed through.
3307 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
3308 .deviceId(touchDeviceId)
3309 .pointer(PointerBuilder(0, ToolType::FINGER).x(300).y(100))
3310 .build());
3311 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(touchDeviceId)));
3312}
3313
3314/**
Siarhei Vishniakou6464e462023-02-06 18:57:59 -08003315 * This test is similar to the test above, but the sequence of injected events is different.
3316 *
3317 * Two windows: a window on the left and a window on the right.
3318 * Mouse is hovered over the left window.
3319 * Next, we tap on the left window, where the cursor was last seen.
3320 *
3321 * After that, we inject one finger down onto the right window, and then a second finger down onto
3322 * the left window.
3323 * The touch is split, so this last gesture should cause 2 ACTION_DOWN events, one in the right
3324 * window (first), and then another on the left window (second).
3325 * This test reproduces a crash where there is a mismatch between the downTime and eventTime.
3326 * In the buggy implementation, second finger down on the left window would cause a crash.
3327 */
Siarhei Vishniakoued89cbb2023-10-13 10:42:44 -07003328TEST_F(InputDispatcherMultiDeviceTest, HoverTapAndSplitTouch_legacy) {
3329 SCOPED_FLAG_OVERRIDE(enable_multi_device_same_window_stream, false);
Siarhei Vishniakou6464e462023-02-06 18:57:59 -08003330 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
3331 sp<FakeWindowHandle> leftWindow =
3332 sp<FakeWindowHandle>::make(application, mDispatcher, "Left", ADISPLAY_ID_DEFAULT);
3333 leftWindow->setFrame(Rect(0, 0, 200, 200));
3334
3335 sp<FakeWindowHandle> rightWindow =
3336 sp<FakeWindowHandle>::make(application, mDispatcher, "Right", ADISPLAY_ID_DEFAULT);
3337 rightWindow->setFrame(Rect(200, 0, 400, 200));
3338
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07003339 mDispatcher->onWindowInfosChanged(
3340 {{*leftWindow->getInfo(), *rightWindow->getInfo()}, {}, 0, 0});
Siarhei Vishniakou6464e462023-02-06 18:57:59 -08003341
3342 const int32_t mouseDeviceId = 6;
3343 const int32_t touchDeviceId = 4;
3344 // Hover over the left window. Keep the cursor there.
3345 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07003346 injectMotionEvent(*mDispatcher,
Siarhei Vishniakou6464e462023-02-06 18:57:59 -08003347 MotionEventBuilder(AMOTION_EVENT_ACTION_HOVER_ENTER,
3348 AINPUT_SOURCE_MOUSE)
3349 .deviceId(mouseDeviceId)
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07003350 .pointer(PointerBuilder(0, ToolType::MOUSE).x(50).y(50))
Siarhei Vishniakou6464e462023-02-06 18:57:59 -08003351 .build()));
3352 leftWindow->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_ENTER));
3353
3354 // Tap on left window
3355 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07003356 injectMotionEvent(*mDispatcher,
Siarhei Vishniakou6464e462023-02-06 18:57:59 -08003357 MotionEventBuilder(AMOTION_EVENT_ACTION_DOWN,
3358 AINPUT_SOURCE_TOUCHSCREEN)
3359 .deviceId(touchDeviceId)
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07003360 .pointer(PointerBuilder(0, ToolType::FINGER).x(100).y(100))
Siarhei Vishniakou6464e462023-02-06 18:57:59 -08003361 .build()));
3362
3363 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07003364 injectMotionEvent(*mDispatcher,
Siarhei Vishniakou6464e462023-02-06 18:57:59 -08003365 MotionEventBuilder(AMOTION_EVENT_ACTION_UP,
3366 AINPUT_SOURCE_TOUCHSCREEN)
3367 .deviceId(touchDeviceId)
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07003368 .pointer(PointerBuilder(0, ToolType::FINGER).x(100).y(100))
Siarhei Vishniakou6464e462023-02-06 18:57:59 -08003369 .build()));
3370 leftWindow->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_EXIT));
3371 leftWindow->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_DOWN));
3372 leftWindow->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_UP));
3373
3374 // First finger down on right window
3375 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07003376 injectMotionEvent(*mDispatcher,
Siarhei Vishniakou6464e462023-02-06 18:57:59 -08003377 MotionEventBuilder(AMOTION_EVENT_ACTION_DOWN,
3378 AINPUT_SOURCE_TOUCHSCREEN)
3379 .deviceId(touchDeviceId)
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07003380 .pointer(PointerBuilder(0, ToolType::FINGER).x(300).y(100))
Siarhei Vishniakou6464e462023-02-06 18:57:59 -08003381 .build()));
3382 rightWindow->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_DOWN));
3383
3384 // Second finger down on the left window
3385 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07003386 injectMotionEvent(*mDispatcher,
Siarhei Vishniakou6464e462023-02-06 18:57:59 -08003387 MotionEventBuilder(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
3388 .deviceId(touchDeviceId)
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07003389 .pointer(PointerBuilder(0, ToolType::FINGER).x(300).y(100))
3390 .pointer(PointerBuilder(1, ToolType::FINGER).x(100).y(100))
Siarhei Vishniakou6464e462023-02-06 18:57:59 -08003391 .build()));
3392 leftWindow->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_DOWN));
3393 rightWindow->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_MOVE));
3394
3395 // No more events
3396 leftWindow->assertNoEvents();
3397 rightWindow->assertNoEvents();
3398}
3399
3400/**
Siarhei Vishniakoued89cbb2023-10-13 10:42:44 -07003401 * This test is similar to the test above, but the sequence of injected events is different.
3402 *
3403 * Two windows: a window on the left and a window on the right.
3404 * Mouse is hovered over the left window.
3405 * Next, we tap on the left window, where the cursor was last seen.
3406 *
3407 * After that, we send one finger down onto the right window, and then a second finger down onto
3408 * the left window.
3409 * The touch is split, so this last gesture should cause 2 ACTION_DOWN events, one in the right
3410 * window (first), and then another on the left window (second).
3411 * This test reproduces a crash where there is a mismatch between the downTime and eventTime.
3412 * In the buggy implementation, second finger down on the left window would cause a crash.
3413 */
3414TEST_F(InputDispatcherMultiDeviceTest, HoverTapAndSplitTouch) {
3415 SCOPED_FLAG_OVERRIDE(enable_multi_device_same_window_stream, true);
3416 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
3417 sp<FakeWindowHandle> leftWindow =
3418 sp<FakeWindowHandle>::make(application, mDispatcher, "Left", ADISPLAY_ID_DEFAULT);
3419 leftWindow->setFrame(Rect(0, 0, 200, 200));
3420
3421 sp<FakeWindowHandle> rightWindow =
3422 sp<FakeWindowHandle>::make(application, mDispatcher, "Right", ADISPLAY_ID_DEFAULT);
3423 rightWindow->setFrame(Rect(200, 0, 400, 200));
3424
3425 mDispatcher->onWindowInfosChanged(
3426 {{*leftWindow->getInfo(), *rightWindow->getInfo()}, {}, 0, 0});
3427
3428 const int32_t mouseDeviceId = 6;
3429 const int32_t touchDeviceId = 4;
3430 // Hover over the left window. Keep the cursor there.
3431 mDispatcher->notifyMotion(
3432 MotionArgsBuilder(AMOTION_EVENT_ACTION_HOVER_ENTER, AINPUT_SOURCE_MOUSE)
3433 .deviceId(mouseDeviceId)
3434 .pointer(PointerBuilder(0, ToolType::MOUSE).x(50).y(50))
3435 .build());
3436 leftWindow->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_ENTER));
3437
3438 // Tap on left window
3439 mDispatcher->notifyMotion(
3440 MotionArgsBuilder(AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
3441 .deviceId(touchDeviceId)
3442 .pointer(PointerBuilder(0, ToolType::FINGER).x(100).y(100))
3443 .build());
3444
3445 mDispatcher->notifyMotion(MotionArgsBuilder(AMOTION_EVENT_ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN)
3446 .deviceId(touchDeviceId)
3447 .pointer(PointerBuilder(0, ToolType::FINGER).x(100).y(100))
3448 .build());
3449 leftWindow->consumeMotionEvent(
3450 AllOf(WithMotionAction(AMOTION_EVENT_ACTION_DOWN), WithDeviceId(touchDeviceId)));
3451 leftWindow->consumeMotionEvent(
3452 AllOf(WithMotionAction(AMOTION_EVENT_ACTION_UP), WithDeviceId(touchDeviceId)));
3453
3454 // First finger down on right window
3455 mDispatcher->notifyMotion(
3456 MotionArgsBuilder(AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
3457 .deviceId(touchDeviceId)
3458 .pointer(PointerBuilder(0, ToolType::FINGER).x(300).y(100))
3459 .build());
3460 rightWindow->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_DOWN));
3461
3462 // Second finger down on the left window
3463 mDispatcher->notifyMotion(MotionArgsBuilder(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
3464 .deviceId(touchDeviceId)
3465 .pointer(PointerBuilder(0, ToolType::FINGER).x(300).y(100))
3466 .pointer(PointerBuilder(1, ToolType::FINGER).x(100).y(100))
3467 .build());
3468 leftWindow->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_DOWN));
3469 rightWindow->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_MOVE));
3470
3471 // No more events
3472 leftWindow->assertNoEvents();
3473 rightWindow->assertNoEvents();
3474}
3475
3476/**
Siarhei Vishniakou2e3e4432023-02-09 18:34:11 -08003477 * Start hovering with a stylus device, and then tap with a touch device. Ensure no crash occurs.
3478 * While the touch is down, new hover events from the stylus device should be ignored. After the
3479 * touch is gone, stylus hovering should start working again.
3480 */
Siarhei Vishniakou3ad54f52023-11-02 16:54:40 -07003481TEST_F(InputDispatcherMultiDeviceTest, StylusHoverIgnoresTouchTap) {
Siarhei Vishniakoued89cbb2023-10-13 10:42:44 -07003482 SCOPED_FLAG_OVERRIDE(enable_multi_device_same_window_stream, false);
Siarhei Vishniakou2e3e4432023-02-09 18:34:11 -08003483 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
3484 sp<FakeWindowHandle> window =
3485 sp<FakeWindowHandle>::make(application, mDispatcher, "Window", ADISPLAY_ID_DEFAULT);
3486 window->setFrame(Rect(0, 0, 200, 200));
3487
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07003488 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Siarhei Vishniakou2e3e4432023-02-09 18:34:11 -08003489
3490 const int32_t stylusDeviceId = 5;
3491 const int32_t touchDeviceId = 4;
3492 // Start hovering with stylus
3493 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07003494 injectMotionEvent(*mDispatcher,
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -07003495 MotionEventBuilder(ACTION_HOVER_ENTER, AINPUT_SOURCE_STYLUS)
Siarhei Vishniakou2e3e4432023-02-09 18:34:11 -08003496 .deviceId(stylusDeviceId)
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07003497 .pointer(PointerBuilder(0, ToolType::STYLUS).x(50).y(50))
Siarhei Vishniakou2e3e4432023-02-09 18:34:11 -08003498 .build()));
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -07003499 window->consumeMotionEvent(WithMotionAction(ACTION_HOVER_ENTER));
Siarhei Vishniakou2e3e4432023-02-09 18:34:11 -08003500
3501 // Finger down on the window
3502 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07003503 injectMotionEvent(*mDispatcher,
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -07003504 MotionEventBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
Siarhei Vishniakou2e3e4432023-02-09 18:34:11 -08003505 .deviceId(touchDeviceId)
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07003506 .pointer(PointerBuilder(0, ToolType::FINGER).x(100).y(100))
Siarhei Vishniakou2e3e4432023-02-09 18:34:11 -08003507 .build()));
Siarhei Vishniakou3ad54f52023-11-02 16:54:40 -07003508 // The touch device should be ignored!
Siarhei Vishniakou2e3e4432023-02-09 18:34:11 -08003509
Siarhei Vishniakou2899c552023-07-10 18:20:46 -07003510 // Continue hovering with stylus.
3511 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07003512 injectMotionEvent(*mDispatcher,
Siarhei Vishniakou2e3e4432023-02-09 18:34:11 -08003513 MotionEventBuilder(AMOTION_EVENT_ACTION_HOVER_MOVE,
3514 AINPUT_SOURCE_STYLUS)
3515 .deviceId(stylusDeviceId)
Siarhei Vishniakou25537f82023-07-18 14:35:47 -07003516 .pointer(PointerBuilder(0, ToolType::STYLUS).x(60).y(60))
Siarhei Vishniakou2e3e4432023-02-09 18:34:11 -08003517 .build()));
Siarhei Vishniakou3ad54f52023-11-02 16:54:40 -07003518 // Hovers continue to work
3519 window->consumeMotionEvent(
3520 AllOf(WithMotionAction(ACTION_HOVER_MOVE), WithDeviceId(stylusDeviceId)));
Siarhei Vishniakou2e3e4432023-02-09 18:34:11 -08003521
3522 // Lift up the finger
3523 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07003524 injectMotionEvent(*mDispatcher,
Siarhei Vishniakou2e3e4432023-02-09 18:34:11 -08003525 MotionEventBuilder(AMOTION_EVENT_ACTION_UP,
3526 AINPUT_SOURCE_TOUCHSCREEN)
3527 .deviceId(touchDeviceId)
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07003528 .pointer(PointerBuilder(0, ToolType::FINGER).x(100).y(100))
Siarhei Vishniakou2e3e4432023-02-09 18:34:11 -08003529 .build()));
Siarhei Vishniakou2e3e4432023-02-09 18:34:11 -08003530
Siarhei Vishniakou2e3e4432023-02-09 18:34:11 -08003531 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07003532 injectMotionEvent(*mDispatcher,
Siarhei Vishniakou2e3e4432023-02-09 18:34:11 -08003533 MotionEventBuilder(AMOTION_EVENT_ACTION_HOVER_MOVE,
3534 AINPUT_SOURCE_STYLUS)
3535 .deviceId(stylusDeviceId)
Siarhei Vishniakou25537f82023-07-18 14:35:47 -07003536 .pointer(PointerBuilder(0, ToolType::STYLUS).x(70).y(70))
Siarhei Vishniakou2e3e4432023-02-09 18:34:11 -08003537 .build()));
Siarhei Vishniakou3ad54f52023-11-02 16:54:40 -07003538 window->consumeMotionEvent(
3539 AllOf(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_MOVE), WithDeviceId(stylusDeviceId)));
Siarhei Vishniakou2e3e4432023-02-09 18:34:11 -08003540 window->assertNoEvents();
3541}
3542
3543/**
Siarhei Vishniakoued89cbb2023-10-13 10:42:44 -07003544 * Start hovering with a stylus device, and then tap with a touch device. Ensure no crash occurs.
3545 * While the touch is down, hovering from the stylus is not affected. After the touch is gone,
3546 * check that the stylus hovering continues to work.
3547 */
3548TEST_F(InputDispatcherMultiDeviceTest, StylusHoverWithTouchTap) {
3549 SCOPED_FLAG_OVERRIDE(enable_multi_device_same_window_stream, true);
3550 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
3551 sp<FakeWindowHandle> window =
3552 sp<FakeWindowHandle>::make(application, mDispatcher, "Window", ADISPLAY_ID_DEFAULT);
3553 window->setFrame(Rect(0, 0, 200, 200));
3554
3555 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
3556
3557 const int32_t stylusDeviceId = 5;
3558 const int32_t touchDeviceId = 4;
3559 // Start hovering with stylus
3560 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_ENTER, AINPUT_SOURCE_STYLUS)
3561 .deviceId(stylusDeviceId)
3562 .pointer(PointerBuilder(0, ToolType::STYLUS).x(50).y(50))
3563 .build());
3564 window->consumeMotionEvent(WithMotionAction(ACTION_HOVER_ENTER));
3565
3566 // Finger down on the window
3567 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
3568 .deviceId(touchDeviceId)
3569 .pointer(PointerBuilder(0, ToolType::FINGER).x(100).y(100))
3570 .build());
3571 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(touchDeviceId)));
3572
3573 // Continue hovering with stylus.
3574 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_MOVE, AINPUT_SOURCE_STYLUS)
3575 .deviceId(stylusDeviceId)
3576 .pointer(PointerBuilder(0, ToolType::STYLUS).x(60).y(60))
3577 .build());
3578 // Hovers continue to work
3579 window->consumeMotionEvent(
3580 AllOf(WithMotionAction(ACTION_HOVER_MOVE), WithDeviceId(stylusDeviceId)));
3581
3582 // Lift up the finger
3583 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN)
3584 .deviceId(touchDeviceId)
3585 .pointer(PointerBuilder(0, ToolType::FINGER).x(100).y(100))
3586 .build());
3587 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_UP), WithDeviceId(touchDeviceId)));
3588
3589 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_MOVE, AINPUT_SOURCE_STYLUS)
3590 .deviceId(stylusDeviceId)
3591 .pointer(PointerBuilder(0, ToolType::STYLUS).x(70).y(70))
3592 .build());
3593 window->consumeMotionEvent(
3594 AllOf(WithMotionAction(ACTION_HOVER_MOVE), WithDeviceId(stylusDeviceId)));
3595 window->assertNoEvents();
3596}
3597
3598/**
Siarhei Vishniakouf77f60a2023-10-23 17:26:05 -07003599 * If stylus is down anywhere on the screen, then touches should not be delivered to windows that
3600 * have InputConfig::GLOBAL_STYLUS_BLOCKS_TOUCH.
3601 *
3602 * Two windows: one on the left and one on the right.
3603 * The window on the right has GLOBAL_STYLUS_BLOCKS_TOUCH config.
3604 * Stylus down on the left window, and then touch down on the right window.
3605 * Check that the right window doesn't get touches while the stylus is down on the left window.
3606 */
3607TEST_F(InputDispatcherMultiDeviceTest, GlobalStylusDownBlocksTouch) {
3608 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
3609 sp<FakeWindowHandle> leftWindow =
3610 sp<FakeWindowHandle>::make(application, mDispatcher, "Left window",
3611 ADISPLAY_ID_DEFAULT);
3612 leftWindow->setFrame(Rect(0, 0, 100, 100));
3613
3614 sp<FakeWindowHandle> sbtRightWindow =
3615 sp<FakeWindowHandle>::make(application, mDispatcher,
3616 "Stylus blocks touch (right) window", ADISPLAY_ID_DEFAULT);
3617 sbtRightWindow->setFrame(Rect(100, 100, 200, 200));
3618 sbtRightWindow->setGlobalStylusBlocksTouch(true);
3619
3620 mDispatcher->onWindowInfosChanged(
3621 {{*leftWindow->getInfo(), *sbtRightWindow->getInfo()}, {}, 0, 0});
3622
3623 const int32_t stylusDeviceId = 5;
3624 const int32_t touchDeviceId = 4;
3625
3626 // Stylus down in the left window
3627 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_STYLUS)
3628 .pointer(PointerBuilder(0, ToolType::STYLUS).x(50).y(52))
3629 .deviceId(stylusDeviceId)
3630 .build());
3631 leftWindow->consumeMotionEvent(
3632 AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(stylusDeviceId)));
3633
3634 // Finger tap on the right window
3635 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
3636 .pointer(PointerBuilder(0, ToolType::FINGER).x(150).y(151))
3637 .deviceId(touchDeviceId)
3638 .build());
3639 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN)
3640 .pointer(PointerBuilder(0, ToolType::FINGER).x(150).y(151))
3641 .deviceId(touchDeviceId)
3642 .build());
3643
3644 // The touch should be blocked, because stylus is down somewhere else on screen!
3645 sbtRightWindow->assertNoEvents();
3646
3647 // Continue stylus motion, and ensure it's not impacted.
3648 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_STYLUS)
3649 .pointer(PointerBuilder(0, ToolType::STYLUS).x(51).y(53))
3650 .deviceId(stylusDeviceId)
3651 .build());
3652 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_UP, AINPUT_SOURCE_STYLUS)
3653 .pointer(PointerBuilder(0, ToolType::STYLUS).x(51).y(53))
3654 .deviceId(stylusDeviceId)
3655 .build());
3656 leftWindow->consumeMotionEvent(
3657 AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(stylusDeviceId)));
3658 leftWindow->consumeMotionEvent(
3659 AllOf(WithMotionAction(ACTION_UP), WithDeviceId(stylusDeviceId)));
3660
3661 // Now that the stylus gesture is done, touches should be getting delivered correctly.
3662 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
3663 .pointer(PointerBuilder(0, ToolType::FINGER).x(151).y(153))
3664 .deviceId(touchDeviceId)
3665 .build());
3666 sbtRightWindow->consumeMotionEvent(
3667 AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(touchDeviceId)));
3668}
3669
3670/**
3671 * If stylus is hovering anywhere on the screen, then touches should not be delivered to windows
3672 * that have InputConfig::GLOBAL_STYLUS_BLOCKS_TOUCH.
3673 *
3674 * Two windows: one on the left and one on the right.
3675 * The window on the right has GLOBAL_STYLUS_BLOCKS_TOUCH config.
3676 * Stylus hover on the left window, and then touch down on the right window.
3677 * Check that the right window doesn't get touches while the stylus is hovering on the left window.
3678 */
3679TEST_F(InputDispatcherMultiDeviceTest, GlobalStylusHoverBlocksTouch) {
3680 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
3681 sp<FakeWindowHandle> leftWindow =
3682 sp<FakeWindowHandle>::make(application, mDispatcher, "Left window",
3683 ADISPLAY_ID_DEFAULT);
3684 leftWindow->setFrame(Rect(0, 0, 100, 100));
3685
3686 sp<FakeWindowHandle> sbtRightWindow =
3687 sp<FakeWindowHandle>::make(application, mDispatcher,
3688 "Stylus blocks touch (right) window", ADISPLAY_ID_DEFAULT);
3689 sbtRightWindow->setFrame(Rect(100, 100, 200, 200));
3690 sbtRightWindow->setGlobalStylusBlocksTouch(true);
3691
3692 mDispatcher->onWindowInfosChanged(
3693 {{*leftWindow->getInfo(), *sbtRightWindow->getInfo()}, {}, 0, 0});
3694
3695 const int32_t stylusDeviceId = 5;
3696 const int32_t touchDeviceId = 4;
3697
3698 // Stylus hover in the left window
3699 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_ENTER, AINPUT_SOURCE_STYLUS)
3700 .pointer(PointerBuilder(0, ToolType::STYLUS).x(50).y(52))
3701 .deviceId(stylusDeviceId)
3702 .build());
3703 leftWindow->consumeMotionEvent(
3704 AllOf(WithMotionAction(ACTION_HOVER_ENTER), WithDeviceId(stylusDeviceId)));
3705
3706 // Finger tap on the right window
3707 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
3708 .pointer(PointerBuilder(0, ToolType::FINGER).x(150).y(151))
3709 .deviceId(touchDeviceId)
3710 .build());
3711 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN)
3712 .pointer(PointerBuilder(0, ToolType::FINGER).x(150).y(151))
3713 .deviceId(touchDeviceId)
3714 .build());
3715
3716 // The touch should be blocked, because stylus is hovering somewhere else on screen!
3717 sbtRightWindow->assertNoEvents();
3718
3719 // Continue stylus motion, and ensure it's not impacted.
3720 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_MOVE, AINPUT_SOURCE_STYLUS)
3721 .pointer(PointerBuilder(0, ToolType::STYLUS).x(51).y(53))
3722 .deviceId(stylusDeviceId)
3723 .build());
3724 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_EXIT, AINPUT_SOURCE_STYLUS)
3725 .pointer(PointerBuilder(0, ToolType::STYLUS).x(51).y(53))
3726 .deviceId(stylusDeviceId)
3727 .build());
3728 leftWindow->consumeMotionEvent(
3729 AllOf(WithMotionAction(ACTION_HOVER_MOVE), WithDeviceId(stylusDeviceId)));
3730 leftWindow->consumeMotionEvent(
3731 AllOf(WithMotionAction(ACTION_HOVER_EXIT), WithDeviceId(stylusDeviceId)));
3732
3733 // Now that the stylus gesture is done, touches should be getting delivered correctly.
3734 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
3735 .pointer(PointerBuilder(0, ToolType::FINGER).x(151).y(153))
3736 .deviceId(touchDeviceId)
3737 .build());
3738 sbtRightWindow->consumeMotionEvent(
3739 AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(touchDeviceId)));
3740}
3741
3742/**
Siarhei Vishniakouf372b812023-02-14 18:06:51 -08003743 * A spy window above a window with no input channel.
3744 * Start hovering with a stylus device, and then tap with it.
3745 * Ensure spy window receives the entire sequence.
3746 */
3747TEST_F(InputDispatcherTest, StylusHoverAndDownNoInputChannel) {
3748 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
3749 sp<FakeWindowHandle> spyWindow =
3750 sp<FakeWindowHandle>::make(application, mDispatcher, "Spy", ADISPLAY_ID_DEFAULT);
3751 spyWindow->setFrame(Rect(0, 0, 200, 200));
3752 spyWindow->setTrustedOverlay(true);
3753 spyWindow->setSpy(true);
3754 sp<FakeWindowHandle> window =
3755 sp<FakeWindowHandle>::make(application, mDispatcher, "Window", ADISPLAY_ID_DEFAULT);
3756 window->setNoInputChannel(true);
3757 window->setFrame(Rect(0, 0, 200, 200));
3758
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07003759 mDispatcher->onWindowInfosChanged({{*spyWindow->getInfo(), *window->getInfo()}, {}, 0, 0});
Siarhei Vishniakouf372b812023-02-14 18:06:51 -08003760
Siarhei Vishniakouf372b812023-02-14 18:06:51 -08003761 // Start hovering with stylus
Prabir Pradhan678438e2023-04-13 19:32:51 +00003762 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_ENTER, AINPUT_SOURCE_STYLUS)
3763 .pointer(PointerBuilder(0, ToolType::STYLUS).x(50).y(50))
3764 .build());
Siarhei Vishniakouf372b812023-02-14 18:06:51 -08003765 spyWindow->consumeMotionEvent(WithMotionAction(ACTION_HOVER_ENTER));
3766 // Stop hovering
Prabir Pradhan678438e2023-04-13 19:32:51 +00003767 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_EXIT, AINPUT_SOURCE_STYLUS)
3768 .pointer(PointerBuilder(0, ToolType::STYLUS).x(50).y(50))
3769 .build());
Siarhei Vishniakouf372b812023-02-14 18:06:51 -08003770 spyWindow->consumeMotionEvent(WithMotionAction(ACTION_HOVER_EXIT));
3771
3772 // Stylus touches down
Prabir Pradhan678438e2023-04-13 19:32:51 +00003773 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_STYLUS)
3774 .pointer(PointerBuilder(0, ToolType::STYLUS).x(50).y(50))
3775 .build());
Siarhei Vishniakouf372b812023-02-14 18:06:51 -08003776 spyWindow->consumeMotionEvent(WithMotionAction(ACTION_DOWN));
3777
3778 // Stylus goes up
Prabir Pradhan678438e2023-04-13 19:32:51 +00003779 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_UP, AINPUT_SOURCE_STYLUS)
3780 .pointer(PointerBuilder(0, ToolType::STYLUS).x(50).y(50))
3781 .build());
Siarhei Vishniakouf372b812023-02-14 18:06:51 -08003782 spyWindow->consumeMotionEvent(WithMotionAction(ACTION_UP));
3783
3784 // Again hover
Prabir Pradhan678438e2023-04-13 19:32:51 +00003785 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_ENTER, AINPUT_SOURCE_STYLUS)
3786 .pointer(PointerBuilder(0, ToolType::STYLUS).x(50).y(50))
3787 .build());
Siarhei Vishniakouf372b812023-02-14 18:06:51 -08003788 spyWindow->consumeMotionEvent(WithMotionAction(ACTION_HOVER_ENTER));
3789 // Stop hovering
Prabir Pradhan678438e2023-04-13 19:32:51 +00003790 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_EXIT, AINPUT_SOURCE_STYLUS)
3791 .pointer(PointerBuilder(0, ToolType::STYLUS).x(50).y(50))
3792 .build());
Siarhei Vishniakouf372b812023-02-14 18:06:51 -08003793 spyWindow->consumeMotionEvent(WithMotionAction(ACTION_HOVER_EXIT));
3794
3795 // No more events
3796 spyWindow->assertNoEvents();
3797 window->assertNoEvents();
3798}
3799
3800/**
Siarhei Vishniakou6b71b632023-10-27 21:34:46 -07003801 * A stale stylus HOVER_EXIT event is injected. Since it's a stale event, it should generally be
3802 * rejected. But since we already have an ongoing gesture, this event should be processed.
3803 * This prevents inconsistent events being handled inside the dispatcher.
3804 */
3805TEST_F(InputDispatcherTest, StaleStylusHoverGestureIsComplete) {
3806 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
3807
3808 sp<FakeWindowHandle> window =
3809 sp<FakeWindowHandle>::make(application, mDispatcher, "Window", ADISPLAY_ID_DEFAULT);
3810 window->setFrame(Rect(0, 0, 200, 200));
3811
3812 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
3813
3814 // Start hovering with stylus
3815 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_ENTER, AINPUT_SOURCE_STYLUS)
3816 .pointer(PointerBuilder(0, ToolType::STYLUS).x(50).y(50))
3817 .build());
3818 window->consumeMotionEvent(WithMotionAction(ACTION_HOVER_ENTER));
3819
3820 NotifyMotionArgs hoverExit = MotionArgsBuilder(ACTION_HOVER_EXIT, AINPUT_SOURCE_STYLUS)
3821 .pointer(PointerBuilder(0, ToolType::STYLUS).x(50).y(50))
3822 .build();
3823 // Make this 'hoverExit' event stale
3824 mFakePolicy->setStaleEventTimeout(100ms);
3825 std::this_thread::sleep_for(100ms);
3826
3827 // It shouldn't be dropped by the dispatcher, even though it's stale.
3828 mDispatcher->notifyMotion(hoverExit);
3829 window->consumeMotionEvent(WithMotionAction(ACTION_HOVER_EXIT));
3830
3831 // Stylus starts hovering again! There should be no crash.
3832 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_ENTER, AINPUT_SOURCE_STYLUS)
3833 .pointer(PointerBuilder(0, ToolType::STYLUS).x(51).y(51))
3834 .build());
3835 window->consumeMotionEvent(WithMotionAction(ACTION_HOVER_ENTER));
3836}
3837
3838/**
Siarhei Vishniakouf372b812023-02-14 18:06:51 -08003839 * Start hovering with a mouse, and then tap with a touch device. Pilfer the touch stream.
3840 * Next, click with the mouse device. Both windows (spy and regular) should receive the new mouse
3841 * ACTION_DOWN event because that's a new gesture, and pilfering should no longer be active.
3842 * While the mouse is down, new move events from the touch device should be ignored.
3843 */
Siarhei Vishniakoued89cbb2023-10-13 10:42:44 -07003844TEST_F(InputDispatcherTest, TouchPilferAndMouseMove_legacy) {
3845 SCOPED_FLAG_OVERRIDE(enable_multi_device_same_window_stream, false);
Siarhei Vishniakouf372b812023-02-14 18:06:51 -08003846 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
3847 sp<FakeWindowHandle> spyWindow =
3848 sp<FakeWindowHandle>::make(application, mDispatcher, "Spy", ADISPLAY_ID_DEFAULT);
3849 spyWindow->setFrame(Rect(0, 0, 200, 200));
3850 spyWindow->setTrustedOverlay(true);
3851 spyWindow->setSpy(true);
3852 sp<FakeWindowHandle> window =
3853 sp<FakeWindowHandle>::make(application, mDispatcher, "Window", ADISPLAY_ID_DEFAULT);
3854 window->setFrame(Rect(0, 0, 200, 200));
3855
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07003856 mDispatcher->onWindowInfosChanged({{*spyWindow->getInfo(), *window->getInfo()}, {}, 0, 0});
Siarhei Vishniakouf372b812023-02-14 18:06:51 -08003857
3858 const int32_t mouseDeviceId = 7;
3859 const int32_t touchDeviceId = 4;
Siarhei Vishniakouf372b812023-02-14 18:06:51 -08003860
3861 // Hover a bit with mouse first
Prabir Pradhan678438e2023-04-13 19:32:51 +00003862 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_ENTER, AINPUT_SOURCE_MOUSE)
3863 .deviceId(mouseDeviceId)
3864 .pointer(PointerBuilder(0, ToolType::MOUSE).x(100).y(100))
3865 .build());
Siarhei Vishniakouf372b812023-02-14 18:06:51 -08003866 spyWindow->consumeMotionEvent(
3867 AllOf(WithMotionAction(ACTION_HOVER_ENTER), WithDeviceId(mouseDeviceId)));
3868 window->consumeMotionEvent(
3869 AllOf(WithMotionAction(ACTION_HOVER_ENTER), WithDeviceId(mouseDeviceId)));
3870
3871 // Start touching
Prabir Pradhan678438e2023-04-13 19:32:51 +00003872 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
3873 .deviceId(touchDeviceId)
3874 .pointer(PointerBuilder(0, ToolType::FINGER).x(50).y(50))
3875 .build());
Siarhei Vishniakouf372b812023-02-14 18:06:51 -08003876 spyWindow->consumeMotionEvent(WithMotionAction(ACTION_HOVER_EXIT));
3877 window->consumeMotionEvent(WithMotionAction(ACTION_HOVER_EXIT));
3878 spyWindow->consumeMotionEvent(WithMotionAction(ACTION_DOWN));
3879 window->consumeMotionEvent(WithMotionAction(ACTION_DOWN));
3880
Prabir Pradhan678438e2023-04-13 19:32:51 +00003881 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN)
3882 .deviceId(touchDeviceId)
3883 .pointer(PointerBuilder(0, ToolType::FINGER).x(55).y(55))
3884 .build());
Siarhei Vishniakouf372b812023-02-14 18:06:51 -08003885 spyWindow->consumeMotionEvent(WithMotionAction(ACTION_MOVE));
3886 window->consumeMotionEvent(WithMotionAction(ACTION_MOVE));
3887
3888 // Pilfer the stream
3889 EXPECT_EQ(OK, mDispatcher->pilferPointers(spyWindow->getToken()));
3890 window->consumeMotionEvent(WithMotionAction(ACTION_CANCEL));
3891
Prabir Pradhan678438e2023-04-13 19:32:51 +00003892 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN)
3893 .deviceId(touchDeviceId)
3894 .pointer(PointerBuilder(0, ToolType::FINGER).x(60).y(60))
3895 .build());
Siarhei Vishniakouf372b812023-02-14 18:06:51 -08003896 spyWindow->consumeMotionEvent(WithMotionAction(ACTION_MOVE));
3897
3898 // Mouse down
Prabir Pradhan678438e2023-04-13 19:32:51 +00003899 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_MOUSE)
3900 .deviceId(mouseDeviceId)
3901 .buttonState(AMOTION_EVENT_BUTTON_PRIMARY)
3902 .pointer(PointerBuilder(0, ToolType::MOUSE).x(100).y(100))
3903 .build());
Siarhei Vishniakouf372b812023-02-14 18:06:51 -08003904
3905 spyWindow->consumeMotionEvent(
3906 AllOf(WithMotionAction(ACTION_CANCEL), WithDeviceId(touchDeviceId)));
3907 spyWindow->consumeMotionEvent(
3908 AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(mouseDeviceId)));
3909 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(mouseDeviceId)));
3910
Prabir Pradhan678438e2023-04-13 19:32:51 +00003911 mDispatcher->notifyMotion(
3912 MotionArgsBuilder(AMOTION_EVENT_ACTION_BUTTON_PRESS, AINPUT_SOURCE_MOUSE)
3913 .deviceId(mouseDeviceId)
3914 .buttonState(AMOTION_EVENT_BUTTON_PRIMARY)
3915 .actionButton(AMOTION_EVENT_BUTTON_PRIMARY)
3916 .pointer(PointerBuilder(0, ToolType::MOUSE).x(100).y(100))
3917 .build());
Siarhei Vishniakouf372b812023-02-14 18:06:51 -08003918 spyWindow->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_BUTTON_PRESS));
3919 window->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_BUTTON_PRESS));
3920
3921 // Mouse move!
Prabir Pradhan678438e2023-04-13 19:32:51 +00003922 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_MOUSE)
3923 .deviceId(mouseDeviceId)
3924 .buttonState(AMOTION_EVENT_BUTTON_PRIMARY)
3925 .pointer(PointerBuilder(0, ToolType::MOUSE).x(110).y(110))
3926 .build());
Siarhei Vishniakouf372b812023-02-14 18:06:51 -08003927 spyWindow->consumeMotionEvent(WithMotionAction(ACTION_MOVE));
3928 window->consumeMotionEvent(WithMotionAction(ACTION_MOVE));
3929
3930 // Touch move!
Prabir Pradhan678438e2023-04-13 19:32:51 +00003931 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN)
3932 .deviceId(touchDeviceId)
3933 .pointer(PointerBuilder(0, ToolType::FINGER).x(65).y(65))
3934 .build());
Siarhei Vishniakouf372b812023-02-14 18:06:51 -08003935
3936 // No more events
3937 spyWindow->assertNoEvents();
3938 window->assertNoEvents();
3939}
3940
3941/**
Siarhei Vishniakoued89cbb2023-10-13 10:42:44 -07003942 * Start hovering with a mouse, and then tap with a touch device. Pilfer the touch stream.
3943 * Next, click with the mouse device. Both windows (spy and regular) should receive the new mouse
3944 * ACTION_DOWN event because that's a new gesture, and pilfering should no longer be active.
3945 * While the mouse is down, new move events from the touch device should continue to work.
3946 */
3947TEST_F(InputDispatcherTest, TouchPilferAndMouseMove) {
3948 SCOPED_FLAG_OVERRIDE(enable_multi_device_same_window_stream, true);
3949 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
3950 sp<FakeWindowHandle> spyWindow =
3951 sp<FakeWindowHandle>::make(application, mDispatcher, "Spy", ADISPLAY_ID_DEFAULT);
3952 spyWindow->setFrame(Rect(0, 0, 200, 200));
3953 spyWindow->setTrustedOverlay(true);
3954 spyWindow->setSpy(true);
3955 sp<FakeWindowHandle> window =
3956 sp<FakeWindowHandle>::make(application, mDispatcher, "Window", ADISPLAY_ID_DEFAULT);
3957 window->setFrame(Rect(0, 0, 200, 200));
3958
3959 mDispatcher->onWindowInfosChanged({{*spyWindow->getInfo(), *window->getInfo()}, {}, 0, 0});
3960
3961 const int32_t mouseDeviceId = 7;
3962 const int32_t touchDeviceId = 4;
3963
3964 // Hover a bit with mouse first
3965 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_ENTER, AINPUT_SOURCE_MOUSE)
3966 .deviceId(mouseDeviceId)
3967 .pointer(PointerBuilder(0, ToolType::MOUSE).x(100).y(100))
3968 .build());
3969 spyWindow->consumeMotionEvent(
3970 AllOf(WithMotionAction(ACTION_HOVER_ENTER), WithDeviceId(mouseDeviceId)));
3971 window->consumeMotionEvent(
3972 AllOf(WithMotionAction(ACTION_HOVER_ENTER), WithDeviceId(mouseDeviceId)));
3973
3974 // Start touching
3975 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
3976 .deviceId(touchDeviceId)
3977 .pointer(PointerBuilder(0, ToolType::FINGER).x(50).y(50))
3978 .build());
3979
3980 spyWindow->consumeMotionEvent(WithMotionAction(ACTION_DOWN));
3981 window->consumeMotionEvent(WithMotionAction(ACTION_DOWN));
3982
3983 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN)
3984 .deviceId(touchDeviceId)
3985 .pointer(PointerBuilder(0, ToolType::FINGER).x(55).y(55))
3986 .build());
3987 spyWindow->consumeMotionEvent(WithMotionAction(ACTION_MOVE));
3988 window->consumeMotionEvent(WithMotionAction(ACTION_MOVE));
3989
3990 // Pilfer the stream
3991 EXPECT_EQ(OK, mDispatcher->pilferPointers(spyWindow->getToken()));
3992 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_CANCEL), WithDeviceId(touchDeviceId)));
3993 // Hover is not pilfered! Only touch.
3994
3995 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN)
3996 .deviceId(touchDeviceId)
3997 .pointer(PointerBuilder(0, ToolType::FINGER).x(60).y(60))
3998 .build());
3999 spyWindow->consumeMotionEvent(WithMotionAction(ACTION_MOVE));
4000
4001 // Mouse down
4002 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_MOUSE)
4003 .deviceId(mouseDeviceId)
4004 .buttonState(AMOTION_EVENT_BUTTON_PRIMARY)
4005 .pointer(PointerBuilder(0, ToolType::MOUSE).x(100).y(100))
4006 .build());
4007
4008 spyWindow->consumeMotionEvent(
4009 AllOf(WithMotionAction(ACTION_HOVER_EXIT), WithDeviceId(mouseDeviceId)));
4010 spyWindow->consumeMotionEvent(
4011 AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(mouseDeviceId)));
4012 window->consumeMotionEvent(
4013 AllOf(WithMotionAction(ACTION_HOVER_EXIT), WithDeviceId(mouseDeviceId)));
4014 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(mouseDeviceId)));
4015
4016 mDispatcher->notifyMotion(
4017 MotionArgsBuilder(AMOTION_EVENT_ACTION_BUTTON_PRESS, AINPUT_SOURCE_MOUSE)
4018 .deviceId(mouseDeviceId)
4019 .buttonState(AMOTION_EVENT_BUTTON_PRIMARY)
4020 .actionButton(AMOTION_EVENT_BUTTON_PRIMARY)
4021 .pointer(PointerBuilder(0, ToolType::MOUSE).x(100).y(100))
4022 .build());
4023 spyWindow->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_BUTTON_PRESS));
4024 window->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_BUTTON_PRESS));
4025
4026 // Mouse move!
4027 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_MOUSE)
4028 .deviceId(mouseDeviceId)
4029 .buttonState(AMOTION_EVENT_BUTTON_PRIMARY)
4030 .pointer(PointerBuilder(0, ToolType::MOUSE).x(110).y(110))
4031 .build());
4032 spyWindow->consumeMotionEvent(
4033 AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(mouseDeviceId)));
4034 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(mouseDeviceId)));
4035
4036 // Touch move!
4037 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN)
4038 .deviceId(touchDeviceId)
4039 .pointer(PointerBuilder(0, ToolType::FINGER).x(65).y(65))
4040 .build());
4041 spyWindow->consumeMotionEvent(
4042 AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(touchDeviceId)));
4043
4044 // No more events
4045 spyWindow->assertNoEvents();
4046 window->assertNoEvents();
4047}
4048
4049/**
Siarhei Vishniakoua16e3a22022-03-02 15:26:40 -08004050 * On the display, have a single window, and also an area where there's no window.
4051 * First pointer touches the "no window" area of the screen. Second pointer touches the window.
4052 * Make sure that the window receives the second pointer, and first pointer is simply ignored.
4053 */
4054TEST_F(InputDispatcherTest, SplitWorksWhenEmptyAreaIsTouched) {
4055 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
4056 sp<FakeWindowHandle> window =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07004057 sp<FakeWindowHandle>::make(application, mDispatcher, "Window", DISPLAY_ID);
Siarhei Vishniakoua16e3a22022-03-02 15:26:40 -08004058
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07004059 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Siarhei Vishniakoua16e3a22022-03-02 15:26:40 -08004060
4061 // Touch down on the empty space
Prabir Pradhan678438e2023-04-13 19:32:51 +00004062 mDispatcher->notifyMotion(generateTouchArgs(AMOTION_EVENT_ACTION_DOWN, {{-1, -1}}));
Siarhei Vishniakoua16e3a22022-03-02 15:26:40 -08004063
4064 mDispatcher->waitForIdle();
4065 window->assertNoEvents();
4066
4067 // Now touch down on the window with another pointer
Prabir Pradhan678438e2023-04-13 19:32:51 +00004068 mDispatcher->notifyMotion(generateTouchArgs(POINTER_1_DOWN, {{-1, -1}, {10, 10}}));
Siarhei Vishniakoua16e3a22022-03-02 15:26:40 -08004069 mDispatcher->waitForIdle();
4070 window->consumeMotionDown();
4071}
4072
4073/**
4074 * Same test as above, but instead of touching the empty space, the first touch goes to
4075 * non-touchable window.
4076 */
4077TEST_F(InputDispatcherTest, SplitWorksWhenNonTouchableWindowIsTouched) {
4078 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
4079 sp<FakeWindowHandle> window1 =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07004080 sp<FakeWindowHandle>::make(application, mDispatcher, "Window1", DISPLAY_ID);
Siarhei Vishniakoua16e3a22022-03-02 15:26:40 -08004081 window1->setTouchableRegion(Region{{0, 0, 100, 100}});
4082 window1->setTouchable(false);
4083 sp<FakeWindowHandle> window2 =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07004084 sp<FakeWindowHandle>::make(application, mDispatcher, "Window2", DISPLAY_ID);
Siarhei Vishniakoua16e3a22022-03-02 15:26:40 -08004085 window2->setTouchableRegion(Region{{100, 0, 200, 100}});
4086
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07004087 mDispatcher->onWindowInfosChanged({{*window1->getInfo(), *window2->getInfo()}, {}, 0, 0});
Siarhei Vishniakoua16e3a22022-03-02 15:26:40 -08004088
Siarhei Vishniakoua16e3a22022-03-02 15:26:40 -08004089 // Touch down on the non-touchable window
Prabir Pradhan678438e2023-04-13 19:32:51 +00004090 mDispatcher->notifyMotion(generateTouchArgs(AMOTION_EVENT_ACTION_DOWN, {{50, 50}}));
Siarhei Vishniakoua16e3a22022-03-02 15:26:40 -08004091
4092 mDispatcher->waitForIdle();
4093 window1->assertNoEvents();
4094 window2->assertNoEvents();
4095
4096 // Now touch down on the window with another pointer
Prabir Pradhan678438e2023-04-13 19:32:51 +00004097 mDispatcher->notifyMotion(generateTouchArgs(POINTER_1_DOWN, {{50, 50}, {150, 50}}));
Siarhei Vishniakoua16e3a22022-03-02 15:26:40 -08004098 mDispatcher->waitForIdle();
4099 window2->consumeMotionDown();
4100}
4101
Vaibhav Devmurari882bd9b2022-06-23 14:54:54 +00004102/**
4103 * When splitting touch events the downTime should be adjusted such that the downTime corresponds
4104 * to the event time of the first ACTION_DOWN sent to the particular window.
4105 */
4106TEST_F(InputDispatcherTest, SplitTouchesSendCorrectActionDownTime) {
4107 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
4108 sp<FakeWindowHandle> window1 =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07004109 sp<FakeWindowHandle>::make(application, mDispatcher, "Window1", DISPLAY_ID);
Vaibhav Devmurari882bd9b2022-06-23 14:54:54 +00004110 window1->setTouchableRegion(Region{{0, 0, 100, 100}});
4111 sp<FakeWindowHandle> window2 =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07004112 sp<FakeWindowHandle>::make(application, mDispatcher, "Window2", DISPLAY_ID);
Vaibhav Devmurari882bd9b2022-06-23 14:54:54 +00004113 window2->setTouchableRegion(Region{{100, 0, 200, 100}});
4114
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07004115 mDispatcher->onWindowInfosChanged({{*window1->getInfo(), *window2->getInfo()}, {}, 0, 0});
Vaibhav Devmurari882bd9b2022-06-23 14:54:54 +00004116
Vaibhav Devmurari882bd9b2022-06-23 14:54:54 +00004117 // Touch down on the first window
Prabir Pradhan678438e2023-04-13 19:32:51 +00004118 mDispatcher->notifyMotion(generateTouchArgs(AMOTION_EVENT_ACTION_DOWN, {{50, 50}}));
Vaibhav Devmurari882bd9b2022-06-23 14:54:54 +00004119 mDispatcher->waitForIdle();
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07004120
Prabir Pradhan9d5f9ce2024-01-24 00:03:41 +00004121 const std::unique_ptr<MotionEvent> firstDown =
4122 window1->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN)));
4123 ASSERT_EQ(firstDown->getDownTime(), firstDown->getEventTime());
Vaibhav Devmurari882bd9b2022-06-23 14:54:54 +00004124 window2->assertNoEvents();
Vaibhav Devmurari882bd9b2022-06-23 14:54:54 +00004125
4126 // Now touch down on the window with another pointer
Prabir Pradhan678438e2023-04-13 19:32:51 +00004127 mDispatcher->notifyMotion(generateTouchArgs(POINTER_1_DOWN, {{50, 50}, {150, 50}}));
Vaibhav Devmurari882bd9b2022-06-23 14:54:54 +00004128 mDispatcher->waitForIdle();
Prabir Pradhan9d5f9ce2024-01-24 00:03:41 +00004129
4130 const std::unique_ptr<MotionEvent> secondDown =
4131 window2->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN)));
4132 ASSERT_EQ(secondDown->getDownTime(), secondDown->getEventTime());
4133 ASSERT_NE(firstDown->getDownTime(), secondDown->getDownTime());
4134 // We currently send MOVE events to all windows receiving a split touch when there is any change
4135 // in the touch state, even when none of the pointers in the split window actually moved.
4136 // Document this behavior in the test.
4137 window1->consumeMotionMove();
Vaibhav Devmurari882bd9b2022-06-23 14:54:54 +00004138
4139 // Now move the pointer on the second window
Prabir Pradhan678438e2023-04-13 19:32:51 +00004140 mDispatcher->notifyMotion(generateTouchArgs(AMOTION_EVENT_ACTION_MOVE, {{50, 50}, {151, 51}}));
Vaibhav Devmurari882bd9b2022-06-23 14:54:54 +00004141 mDispatcher->waitForIdle();
Prabir Pradhan9d5f9ce2024-01-24 00:03:41 +00004142
4143 window2->consumeMotionEvent(WithDownTime(secondDown->getDownTime()));
4144 window1->consumeMotionEvent(WithDownTime(firstDown->getDownTime()));
Vaibhav Devmurari882bd9b2022-06-23 14:54:54 +00004145
4146 // Now add new touch down on the second window
Prabir Pradhan678438e2023-04-13 19:32:51 +00004147 mDispatcher->notifyMotion(generateTouchArgs(POINTER_2_DOWN, {{50, 50}, {151, 51}, {150, 50}}));
Vaibhav Devmurari882bd9b2022-06-23 14:54:54 +00004148 mDispatcher->waitForIdle();
Vaibhav Devmurari882bd9b2022-06-23 14:54:54 +00004149
Prabir Pradhan9d5f9ce2024-01-24 00:03:41 +00004150 window2->consumeMotionEvent(
4151 AllOf(WithMotionAction(POINTER_1_DOWN), WithDownTime(secondDown->getDownTime())));
4152 window1->consumeMotionEvent(WithDownTime(firstDown->getDownTime()));
Vaibhav Devmurari882bd9b2022-06-23 14:54:54 +00004153
4154 // Now move the pointer on the first window
Prabir Pradhan678438e2023-04-13 19:32:51 +00004155 mDispatcher->notifyMotion(
4156 generateTouchArgs(AMOTION_EVENT_ACTION_MOVE, {{51, 51}, {151, 51}, {150, 50}}));
Vaibhav Devmurari882bd9b2022-06-23 14:54:54 +00004157 mDispatcher->waitForIdle();
Vaibhav Devmurari882bd9b2022-06-23 14:54:54 +00004158
Prabir Pradhan9d5f9ce2024-01-24 00:03:41 +00004159 window1->consumeMotionEvent(WithDownTime(firstDown->getDownTime()));
4160 window2->consumeMotionEvent(WithDownTime(secondDown->getDownTime()));
4161
4162 // Now add new touch down on the first window
Prabir Pradhan678438e2023-04-13 19:32:51 +00004163 mDispatcher->notifyMotion(
4164 generateTouchArgs(POINTER_3_DOWN, {{51, 51}, {151, 51}, {150, 50}, {50, 50}}));
Vaibhav Devmurari882bd9b2022-06-23 14:54:54 +00004165 mDispatcher->waitForIdle();
Prabir Pradhan9d5f9ce2024-01-24 00:03:41 +00004166
4167 window1->consumeMotionEvent(
4168 AllOf(WithMotionAction(POINTER_1_DOWN), WithDownTime(firstDown->getDownTime())));
4169 window2->consumeMotionEvent(WithDownTime(secondDown->getDownTime()));
Vaibhav Devmurari882bd9b2022-06-23 14:54:54 +00004170}
4171
Garfield Tandf26e862020-07-01 20:18:19 -07004172TEST_F(InputDispatcherTest, HoverMoveEnterMouseClickAndHoverMoveExit) {
Chris Yea209fde2020-07-22 13:54:51 -07004173 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
Garfield Tandf26e862020-07-01 20:18:19 -07004174 sp<FakeWindowHandle> windowLeft =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07004175 sp<FakeWindowHandle>::make(application, mDispatcher, "Left", ADISPLAY_ID_DEFAULT);
Garfield Tandf26e862020-07-01 20:18:19 -07004176 windowLeft->setFrame(Rect(0, 0, 600, 800));
Garfield Tandf26e862020-07-01 20:18:19 -07004177 sp<FakeWindowHandle> windowRight =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07004178 sp<FakeWindowHandle>::make(application, mDispatcher, "Right", ADISPLAY_ID_DEFAULT);
Garfield Tandf26e862020-07-01 20:18:19 -07004179 windowRight->setFrame(Rect(600, 0, 1200, 800));
Garfield Tandf26e862020-07-01 20:18:19 -07004180
4181 mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application);
4182
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07004183 mDispatcher->onWindowInfosChanged(
4184 {{*windowLeft->getInfo(), *windowRight->getInfo()}, {}, 0, 0});
Garfield Tandf26e862020-07-01 20:18:19 -07004185
4186 // Start cursor position in right window so that we can move the cursor to left window.
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08004187 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07004188 injectMotionEvent(*mDispatcher,
Garfield Tandf26e862020-07-01 20:18:19 -07004189 MotionEventBuilder(AMOTION_EVENT_ACTION_HOVER_MOVE,
4190 AINPUT_SOURCE_MOUSE)
Siarhei Vishniakou6d73f832022-07-21 17:27:03 -07004191 .pointer(PointerBuilder(0, ToolType::MOUSE).x(900).y(400))
Garfield Tandf26e862020-07-01 20:18:19 -07004192 .build()));
Siarhei Vishniakou5cee1e32022-11-29 12:35:39 -08004193 windowRight->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_ENTER));
Garfield Tandf26e862020-07-01 20:18:19 -07004194
4195 // Move cursor into left window
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08004196 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07004197 injectMotionEvent(*mDispatcher,
Garfield Tandf26e862020-07-01 20:18:19 -07004198 MotionEventBuilder(AMOTION_EVENT_ACTION_HOVER_MOVE,
4199 AINPUT_SOURCE_MOUSE)
Siarhei Vishniakou6d73f832022-07-21 17:27:03 -07004200 .pointer(PointerBuilder(0, ToolType::MOUSE).x(300).y(400))
Garfield Tandf26e862020-07-01 20:18:19 -07004201 .build()));
Siarhei Vishniakou5cee1e32022-11-29 12:35:39 -08004202 windowRight->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_EXIT));
4203 windowLeft->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_ENTER));
Garfield Tandf26e862020-07-01 20:18:19 -07004204
4205 // Inject a series of mouse events for a mouse click
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08004206 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07004207 injectMotionEvent(*mDispatcher,
Garfield Tandf26e862020-07-01 20:18:19 -07004208 MotionEventBuilder(AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_MOUSE)
4209 .buttonState(AMOTION_EVENT_BUTTON_PRIMARY)
Siarhei Vishniakou6d73f832022-07-21 17:27:03 -07004210 .pointer(PointerBuilder(0, ToolType::MOUSE).x(300).y(400))
Garfield Tandf26e862020-07-01 20:18:19 -07004211 .build()));
Siarhei Vishniakouf372b812023-02-14 18:06:51 -08004212 windowLeft->consumeMotionEvent(WithMotionAction(ACTION_HOVER_EXIT));
4213 windowLeft->consumeMotionEvent(WithMotionAction(ACTION_DOWN));
Garfield Tandf26e862020-07-01 20:18:19 -07004214
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08004215 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07004216 injectMotionEvent(*mDispatcher,
Garfield Tandf26e862020-07-01 20:18:19 -07004217 MotionEventBuilder(AMOTION_EVENT_ACTION_BUTTON_PRESS,
4218 AINPUT_SOURCE_MOUSE)
4219 .buttonState(AMOTION_EVENT_BUTTON_PRIMARY)
4220 .actionButton(AMOTION_EVENT_BUTTON_PRIMARY)
Siarhei Vishniakou6d73f832022-07-21 17:27:03 -07004221 .pointer(PointerBuilder(0, ToolType::MOUSE).x(300).y(400))
Garfield Tandf26e862020-07-01 20:18:19 -07004222 .build()));
Siarhei Vishniakou5cee1e32022-11-29 12:35:39 -08004223 windowLeft->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_BUTTON_PRESS));
Garfield Tandf26e862020-07-01 20:18:19 -07004224
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08004225 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07004226 injectMotionEvent(*mDispatcher,
Garfield Tandf26e862020-07-01 20:18:19 -07004227 MotionEventBuilder(AMOTION_EVENT_ACTION_BUTTON_RELEASE,
4228 AINPUT_SOURCE_MOUSE)
4229 .buttonState(0)
4230 .actionButton(AMOTION_EVENT_BUTTON_PRIMARY)
Siarhei Vishniakou6d73f832022-07-21 17:27:03 -07004231 .pointer(PointerBuilder(0, ToolType::MOUSE).x(300).y(400))
Garfield Tandf26e862020-07-01 20:18:19 -07004232 .build()));
Siarhei Vishniakou5cee1e32022-11-29 12:35:39 -08004233 windowLeft->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_BUTTON_RELEASE));
Garfield Tandf26e862020-07-01 20:18:19 -07004234
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08004235 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07004236 injectMotionEvent(*mDispatcher,
Garfield Tandf26e862020-07-01 20:18:19 -07004237 MotionEventBuilder(AMOTION_EVENT_ACTION_UP, AINPUT_SOURCE_MOUSE)
4238 .buttonState(0)
Siarhei Vishniakou6d73f832022-07-21 17:27:03 -07004239 .pointer(PointerBuilder(0, ToolType::MOUSE).x(300).y(400))
Garfield Tandf26e862020-07-01 20:18:19 -07004240 .build()));
4241 windowLeft->consumeMotionUp(ADISPLAY_ID_DEFAULT);
4242
4243 // Move mouse cursor back to right window
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08004244 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07004245 injectMotionEvent(*mDispatcher,
Garfield Tandf26e862020-07-01 20:18:19 -07004246 MotionEventBuilder(AMOTION_EVENT_ACTION_HOVER_MOVE,
4247 AINPUT_SOURCE_MOUSE)
Siarhei Vishniakou6d73f832022-07-21 17:27:03 -07004248 .pointer(PointerBuilder(0, ToolType::MOUSE).x(900).y(400))
Garfield Tandf26e862020-07-01 20:18:19 -07004249 .build()));
Siarhei Vishniakou5cee1e32022-11-29 12:35:39 -08004250 windowRight->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_ENTER));
Siarhei Vishniakou5cee1e32022-11-29 12:35:39 -08004251
4252 // No more events
4253 windowLeft->assertNoEvents();
4254 windowRight->assertNoEvents();
4255}
4256
Siarhei Vishniakouf372b812023-02-14 18:06:51 -08004257/**
4258 * Put two fingers down (and don't release them) and click the mouse button.
4259 * The clicking of mouse is a new ACTION_DOWN event. Since it's from a different device, the
4260 * currently active gesture should be canceled, and the new one should proceed.
4261 */
Siarhei Vishniakoued89cbb2023-10-13 10:42:44 -07004262TEST_F(InputDispatcherTest, TwoPointersDownMouseClick_legacy) {
4263 SCOPED_FLAG_OVERRIDE(enable_multi_device_same_window_stream, false);
Siarhei Vishniakouf372b812023-02-14 18:06:51 -08004264 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
4265 sp<FakeWindowHandle> window =
4266 sp<FakeWindowHandle>::make(application, mDispatcher, "Window", ADISPLAY_ID_DEFAULT);
4267 window->setFrame(Rect(0, 0, 600, 800));
4268
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07004269 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Siarhei Vishniakouf372b812023-02-14 18:06:51 -08004270
4271 const int32_t touchDeviceId = 4;
4272 const int32_t mouseDeviceId = 6;
Siarhei Vishniakouf372b812023-02-14 18:06:51 -08004273
4274 // Two pointers down
Prabir Pradhan678438e2023-04-13 19:32:51 +00004275 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
4276 .deviceId(touchDeviceId)
4277 .pointer(PointerBuilder(0, ToolType::FINGER).x(100).y(100))
4278 .build());
Siarhei Vishniakouf372b812023-02-14 18:06:51 -08004279
Prabir Pradhan678438e2023-04-13 19:32:51 +00004280 mDispatcher->notifyMotion(MotionArgsBuilder(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
4281 .deviceId(touchDeviceId)
4282 .pointer(PointerBuilder(0, ToolType::FINGER).x(100).y(100))
4283 .pointer(PointerBuilder(1, ToolType::FINGER).x(120).y(120))
4284 .build());
Siarhei Vishniakouf372b812023-02-14 18:06:51 -08004285 window->consumeMotionEvent(WithMotionAction(ACTION_DOWN));
4286 window->consumeMotionEvent(WithMotionAction(POINTER_1_DOWN));
4287
4288 // Inject a series of mouse events for a mouse click
Prabir Pradhan678438e2023-04-13 19:32:51 +00004289 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_MOUSE)
4290 .deviceId(mouseDeviceId)
4291 .buttonState(AMOTION_EVENT_BUTTON_PRIMARY)
4292 .pointer(PointerBuilder(0, ToolType::MOUSE).x(300).y(400))
4293 .build());
Siarhei Vishniakouf372b812023-02-14 18:06:51 -08004294 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_CANCEL), WithDeviceId(touchDeviceId),
4295 WithPointerCount(2u)));
4296 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(mouseDeviceId)));
4297
Prabir Pradhan678438e2023-04-13 19:32:51 +00004298 mDispatcher->notifyMotion(
4299 MotionArgsBuilder(AMOTION_EVENT_ACTION_BUTTON_PRESS, AINPUT_SOURCE_MOUSE)
4300 .deviceId(mouseDeviceId)
4301 .buttonState(AMOTION_EVENT_BUTTON_PRIMARY)
4302 .actionButton(AMOTION_EVENT_BUTTON_PRIMARY)
4303 .pointer(PointerBuilder(0, ToolType::MOUSE).x(300).y(400))
4304 .build());
Siarhei Vishniakouf372b812023-02-14 18:06:51 -08004305 window->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_BUTTON_PRESS));
4306
4307 // Try to send more touch events while the mouse is down. Since it's a continuation of an
4308 // already canceled gesture, it should be ignored.
Prabir Pradhan678438e2023-04-13 19:32:51 +00004309 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN)
4310 .deviceId(touchDeviceId)
4311 .pointer(PointerBuilder(0, ToolType::FINGER).x(101).y(101))
4312 .pointer(PointerBuilder(1, ToolType::FINGER).x(121).y(121))
4313 .build());
Siarhei Vishniakouf372b812023-02-14 18:06:51 -08004314 window->assertNoEvents();
4315}
4316
Siarhei Vishniakoued89cbb2023-10-13 10:42:44 -07004317/**
4318 * Put two fingers down (and don't release them) and click the mouse button.
4319 * The clicking of mouse is a new ACTION_DOWN event. Since it's from a different device, the
4320 * currently active gesture should not be canceled, and the new one should proceed in parallel.
4321 */
4322TEST_F(InputDispatcherTest, TwoPointersDownMouseClick) {
4323 SCOPED_FLAG_OVERRIDE(enable_multi_device_same_window_stream, true);
4324 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
4325 sp<FakeWindowHandle> window =
4326 sp<FakeWindowHandle>::make(application, mDispatcher, "Window", ADISPLAY_ID_DEFAULT);
4327 window->setFrame(Rect(0, 0, 600, 800));
4328
4329 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
4330
4331 const int32_t touchDeviceId = 4;
4332 const int32_t mouseDeviceId = 6;
4333
4334 // Two pointers down
4335 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
4336 .deviceId(touchDeviceId)
4337 .pointer(PointerBuilder(0, ToolType::FINGER).x(100).y(100))
4338 .build());
4339
4340 mDispatcher->notifyMotion(MotionArgsBuilder(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
4341 .deviceId(touchDeviceId)
4342 .pointer(PointerBuilder(0, ToolType::FINGER).x(100).y(100))
4343 .pointer(PointerBuilder(1, ToolType::FINGER).x(120).y(120))
4344 .build());
4345 window->consumeMotionEvent(WithMotionAction(ACTION_DOWN));
4346 window->consumeMotionEvent(WithMotionAction(POINTER_1_DOWN));
4347
4348 // Send a series of mouse events for a mouse click
4349 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_MOUSE)
4350 .deviceId(mouseDeviceId)
4351 .buttonState(AMOTION_EVENT_BUTTON_PRIMARY)
4352 .pointer(PointerBuilder(0, ToolType::MOUSE).x(300).y(400))
4353 .build());
4354 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(mouseDeviceId)));
4355
4356 mDispatcher->notifyMotion(
4357 MotionArgsBuilder(AMOTION_EVENT_ACTION_BUTTON_PRESS, AINPUT_SOURCE_MOUSE)
4358 .deviceId(mouseDeviceId)
4359 .buttonState(AMOTION_EVENT_BUTTON_PRIMARY)
4360 .actionButton(AMOTION_EVENT_BUTTON_PRIMARY)
4361 .pointer(PointerBuilder(0, ToolType::MOUSE).x(300).y(400))
4362 .build());
4363 window->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_BUTTON_PRESS));
4364
4365 // Try to send more touch events while the mouse is down. Since it's a continuation of an
4366 // already active gesture, it should be sent normally.
4367 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN)
4368 .deviceId(touchDeviceId)
4369 .pointer(PointerBuilder(0, ToolType::FINGER).x(101).y(101))
4370 .pointer(PointerBuilder(1, ToolType::FINGER).x(121).y(121))
4371 .build());
4372 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(touchDeviceId)));
4373 window->assertNoEvents();
4374}
4375
Siarhei Vishniakou5cee1e32022-11-29 12:35:39 -08004376TEST_F(InputDispatcherTest, HoverWithSpyWindows) {
4377 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
4378
4379 sp<FakeWindowHandle> spyWindow =
4380 sp<FakeWindowHandle>::make(application, mDispatcher, "Spy", ADISPLAY_ID_DEFAULT);
4381 spyWindow->setFrame(Rect(0, 0, 600, 800));
4382 spyWindow->setTrustedOverlay(true);
4383 spyWindow->setSpy(true);
4384 sp<FakeWindowHandle> window =
4385 sp<FakeWindowHandle>::make(application, mDispatcher, "Window", ADISPLAY_ID_DEFAULT);
4386 window->setFrame(Rect(0, 0, 600, 800));
4387
4388 mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07004389 mDispatcher->onWindowInfosChanged({{*spyWindow->getInfo(), *window->getInfo()}, {}, 0, 0});
Siarhei Vishniakou5cee1e32022-11-29 12:35:39 -08004390
4391 // Send mouse cursor to the window
4392 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07004393 injectMotionEvent(*mDispatcher,
Siarhei Vishniakou5cee1e32022-11-29 12:35:39 -08004394 MotionEventBuilder(AMOTION_EVENT_ACTION_HOVER_ENTER,
4395 AINPUT_SOURCE_MOUSE)
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07004396 .pointer(PointerBuilder(0, ToolType::MOUSE).x(100).y(100))
Siarhei Vishniakou5cee1e32022-11-29 12:35:39 -08004397 .build()));
4398
4399 window->consumeMotionEvent(AllOf(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_ENTER),
4400 WithSource(AINPUT_SOURCE_MOUSE)));
4401 spyWindow->consumeMotionEvent(AllOf(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_ENTER),
4402 WithSource(AINPUT_SOURCE_MOUSE)));
4403
4404 window->assertNoEvents();
4405 spyWindow->assertNoEvents();
Garfield Tandf26e862020-07-01 20:18:19 -07004406}
4407
Siarhei Vishniakoued89cbb2023-10-13 10:42:44 -07004408TEST_F(InputDispatcherTest, MouseAndTouchWithSpyWindows_legacy) {
4409 SCOPED_FLAG_OVERRIDE(enable_multi_device_same_window_stream, false);
Siarhei Vishniakou060f82b2023-01-27 06:39:14 -08004410 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
4411
4412 sp<FakeWindowHandle> spyWindow =
4413 sp<FakeWindowHandle>::make(application, mDispatcher, "Spy", ADISPLAY_ID_DEFAULT);
4414 spyWindow->setFrame(Rect(0, 0, 600, 800));
4415 spyWindow->setTrustedOverlay(true);
4416 spyWindow->setSpy(true);
4417 sp<FakeWindowHandle> window =
4418 sp<FakeWindowHandle>::make(application, mDispatcher, "Window", ADISPLAY_ID_DEFAULT);
4419 window->setFrame(Rect(0, 0, 600, 800));
4420
4421 mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07004422 mDispatcher->onWindowInfosChanged({{*spyWindow->getInfo(), *window->getInfo()}, {}, 0, 0});
Siarhei Vishniakou060f82b2023-01-27 06:39:14 -08004423
4424 // Send mouse cursor to the window
4425 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07004426 injectMotionEvent(*mDispatcher,
Siarhei Vishniakou060f82b2023-01-27 06:39:14 -08004427 MotionEventBuilder(AMOTION_EVENT_ACTION_HOVER_ENTER,
4428 AINPUT_SOURCE_MOUSE)
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07004429 .pointer(PointerBuilder(0, ToolType::MOUSE).x(100).y(100))
Siarhei Vishniakou060f82b2023-01-27 06:39:14 -08004430 .build()));
4431
4432 // Move mouse cursor
4433 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07004434 injectMotionEvent(*mDispatcher,
Siarhei Vishniakou060f82b2023-01-27 06:39:14 -08004435 MotionEventBuilder(AMOTION_EVENT_ACTION_HOVER_MOVE,
4436 AINPUT_SOURCE_MOUSE)
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07004437 .pointer(PointerBuilder(0, ToolType::MOUSE).x(110).y(110))
Siarhei Vishniakou060f82b2023-01-27 06:39:14 -08004438 .build()));
4439
4440 window->consumeMotionEvent(AllOf(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_ENTER),
4441 WithSource(AINPUT_SOURCE_MOUSE)));
4442 spyWindow->consumeMotionEvent(AllOf(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_ENTER),
4443 WithSource(AINPUT_SOURCE_MOUSE)));
4444 window->consumeMotionEvent(AllOf(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_MOVE),
4445 WithSource(AINPUT_SOURCE_MOUSE)));
4446 spyWindow->consumeMotionEvent(AllOf(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_MOVE),
4447 WithSource(AINPUT_SOURCE_MOUSE)));
4448 // Touch down on the window
4449 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07004450 injectMotionEvent(*mDispatcher,
Siarhei Vishniakou060f82b2023-01-27 06:39:14 -08004451 MotionEventBuilder(AMOTION_EVENT_ACTION_DOWN,
4452 AINPUT_SOURCE_TOUCHSCREEN)
4453 .deviceId(SECOND_DEVICE_ID)
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07004454 .pointer(PointerBuilder(0, ToolType::FINGER).x(200).y(200))
Siarhei Vishniakou060f82b2023-01-27 06:39:14 -08004455 .build()));
4456 window->consumeMotionEvent(AllOf(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_EXIT),
4457 WithSource(AINPUT_SOURCE_MOUSE)));
4458 spyWindow->consumeMotionEvent(AllOf(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_EXIT),
4459 WithSource(AINPUT_SOURCE_MOUSE)));
4460 window->consumeMotionEvent(AllOf(WithMotionAction(AMOTION_EVENT_ACTION_DOWN),
4461 WithSource(AINPUT_SOURCE_TOUCHSCREEN)));
4462 spyWindow->consumeMotionEvent(AllOf(WithMotionAction(AMOTION_EVENT_ACTION_DOWN),
4463 WithSource(AINPUT_SOURCE_TOUCHSCREEN)));
4464
4465 // pilfer the motion, retaining the gesture on the spy window.
4466 EXPECT_EQ(OK, mDispatcher->pilferPointers(spyWindow->getToken()));
4467 window->consumeMotionEvent(AllOf(WithMotionAction(AMOTION_EVENT_ACTION_CANCEL),
4468 WithSource(AINPUT_SOURCE_TOUCHSCREEN)));
4469
4470 // Touch UP on the window
4471 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07004472 injectMotionEvent(*mDispatcher,
Siarhei Vishniakou060f82b2023-01-27 06:39:14 -08004473 MotionEventBuilder(AMOTION_EVENT_ACTION_UP,
4474 AINPUT_SOURCE_TOUCHSCREEN)
4475 .deviceId(SECOND_DEVICE_ID)
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07004476 .pointer(PointerBuilder(0, ToolType::FINGER).x(200).y(200))
Siarhei Vishniakou060f82b2023-01-27 06:39:14 -08004477 .build()));
4478 spyWindow->consumeMotionEvent(AllOf(WithMotionAction(AMOTION_EVENT_ACTION_UP),
4479 WithSource(AINPUT_SOURCE_TOUCHSCREEN)));
4480
4481 // Previously, a touch was pilfered. However, that gesture was just finished. Now, we are going
4482 // to send a new gesture. It should again go to both windows (spy and the window below), just
4483 // like the first gesture did, before pilfering. The window configuration has not changed.
4484
4485 // One more tap - DOWN
4486 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07004487 injectMotionEvent(*mDispatcher,
Siarhei Vishniakou060f82b2023-01-27 06:39:14 -08004488 MotionEventBuilder(AMOTION_EVENT_ACTION_DOWN,
4489 AINPUT_SOURCE_TOUCHSCREEN)
4490 .deviceId(SECOND_DEVICE_ID)
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07004491 .pointer(PointerBuilder(0, ToolType::FINGER).x(250).y(250))
Siarhei Vishniakou060f82b2023-01-27 06:39:14 -08004492 .build()));
4493 window->consumeMotionEvent(AllOf(WithMotionAction(AMOTION_EVENT_ACTION_DOWN),
4494 WithSource(AINPUT_SOURCE_TOUCHSCREEN)));
4495 spyWindow->consumeMotionEvent(AllOf(WithMotionAction(AMOTION_EVENT_ACTION_DOWN),
4496 WithSource(AINPUT_SOURCE_TOUCHSCREEN)));
4497
4498 // Touch UP on the window
4499 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07004500 injectMotionEvent(*mDispatcher,
Siarhei Vishniakou060f82b2023-01-27 06:39:14 -08004501 MotionEventBuilder(AMOTION_EVENT_ACTION_UP,
4502 AINPUT_SOURCE_TOUCHSCREEN)
4503 .deviceId(SECOND_DEVICE_ID)
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07004504 .pointer(PointerBuilder(0, ToolType::FINGER).x(250).y(250))
Siarhei Vishniakou060f82b2023-01-27 06:39:14 -08004505 .build()));
4506 window->consumeMotionEvent(AllOf(WithMotionAction(AMOTION_EVENT_ACTION_UP),
4507 WithSource(AINPUT_SOURCE_TOUCHSCREEN)));
4508 spyWindow->consumeMotionEvent(AllOf(WithMotionAction(AMOTION_EVENT_ACTION_UP),
4509 WithSource(AINPUT_SOURCE_TOUCHSCREEN)));
4510
4511 window->assertNoEvents();
4512 spyWindow->assertNoEvents();
4513}
4514
Siarhei Vishniakoued89cbb2023-10-13 10:42:44 -07004515TEST_F(InputDispatcherTest, MouseAndTouchWithSpyWindows) {
4516 SCOPED_FLAG_OVERRIDE(enable_multi_device_same_window_stream, true);
4517 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
4518
4519 sp<FakeWindowHandle> spyWindow =
4520 sp<FakeWindowHandle>::make(application, mDispatcher, "Spy", ADISPLAY_ID_DEFAULT);
4521 spyWindow->setFrame(Rect(0, 0, 600, 800));
4522 spyWindow->setTrustedOverlay(true);
4523 spyWindow->setSpy(true);
4524 sp<FakeWindowHandle> window =
4525 sp<FakeWindowHandle>::make(application, mDispatcher, "Window", ADISPLAY_ID_DEFAULT);
4526 window->setFrame(Rect(0, 0, 600, 800));
4527
4528 mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application);
4529 mDispatcher->onWindowInfosChanged({{*spyWindow->getInfo(), *window->getInfo()}, {}, 0, 0});
4530
4531 // Send mouse cursor to the window
4532 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_ENTER, AINPUT_SOURCE_MOUSE)
4533 .pointer(PointerBuilder(0, ToolType::MOUSE).x(100).y(100))
4534 .build());
4535
4536 // Move mouse cursor
4537 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_MOVE, AINPUT_SOURCE_MOUSE)
4538 .pointer(PointerBuilder(0, ToolType::MOUSE).x(110).y(110))
4539 .build());
4540
4541 window->consumeMotionEvent(
4542 AllOf(WithMotionAction(ACTION_HOVER_ENTER), WithSource(AINPUT_SOURCE_MOUSE)));
4543 spyWindow->consumeMotionEvent(
4544 AllOf(WithMotionAction(ACTION_HOVER_ENTER), WithSource(AINPUT_SOURCE_MOUSE)));
4545 window->consumeMotionEvent(
4546 AllOf(WithMotionAction(ACTION_HOVER_MOVE), WithSource(AINPUT_SOURCE_MOUSE)));
4547 spyWindow->consumeMotionEvent(
4548 AllOf(WithMotionAction(ACTION_HOVER_MOVE), WithSource(AINPUT_SOURCE_MOUSE)));
4549 // Touch down on the window
4550 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
4551 .deviceId(SECOND_DEVICE_ID)
4552 .pointer(PointerBuilder(0, ToolType::FINGER).x(200).y(200))
4553 .build());
4554 window->consumeMotionEvent(
4555 AllOf(WithMotionAction(ACTION_DOWN), WithSource(AINPUT_SOURCE_TOUCHSCREEN)));
4556 spyWindow->consumeMotionEvent(
4557 AllOf(WithMotionAction(ACTION_DOWN), WithSource(AINPUT_SOURCE_TOUCHSCREEN)));
4558
4559 // pilfer the motion, retaining the gesture on the spy window.
4560 EXPECT_EQ(OK, mDispatcher->pilferPointers(spyWindow->getToken()));
4561 window->consumeMotionEvent(
4562 AllOf(WithMotionAction(ACTION_CANCEL), WithSource(AINPUT_SOURCE_TOUCHSCREEN)));
4563 // Mouse hover is not pilfered
4564
4565 // Touch UP on the window
4566 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN)
4567 .deviceId(SECOND_DEVICE_ID)
4568 .pointer(PointerBuilder(0, ToolType::FINGER).x(200).y(200))
4569 .build());
4570 spyWindow->consumeMotionEvent(
4571 AllOf(WithMotionAction(ACTION_UP), WithSource(AINPUT_SOURCE_TOUCHSCREEN)));
4572
4573 // Previously, a touch was pilfered. However, that gesture was just finished. Now, we are going
4574 // to send a new gesture. It should again go to both windows (spy and the window below), just
4575 // like the first gesture did, before pilfering. The window configuration has not changed.
4576
4577 // One more tap - DOWN
4578 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
4579 .deviceId(SECOND_DEVICE_ID)
4580 .pointer(PointerBuilder(0, ToolType::FINGER).x(250).y(250))
4581 .build());
4582 window->consumeMotionEvent(
4583 AllOf(WithMotionAction(ACTION_DOWN), WithSource(AINPUT_SOURCE_TOUCHSCREEN)));
4584 spyWindow->consumeMotionEvent(
4585 AllOf(WithMotionAction(ACTION_DOWN), WithSource(AINPUT_SOURCE_TOUCHSCREEN)));
4586
4587 // Touch UP on the window
4588 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN)
4589 .deviceId(SECOND_DEVICE_ID)
4590 .pointer(PointerBuilder(0, ToolType::FINGER).x(250).y(250))
4591 .build());
4592 window->consumeMotionEvent(
4593 AllOf(WithMotionAction(ACTION_UP), WithSource(AINPUT_SOURCE_TOUCHSCREEN)));
4594 spyWindow->consumeMotionEvent(
4595 AllOf(WithMotionAction(ACTION_UP), WithSource(AINPUT_SOURCE_TOUCHSCREEN)));
4596
4597 // Mouse movement continues normally as well
4598 // Move mouse cursor
4599 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_MOVE, AINPUT_SOURCE_MOUSE)
4600 .pointer(PointerBuilder(0, ToolType::MOUSE).x(120).y(130))
4601 .build());
4602 window->consumeMotionEvent(
4603 AllOf(WithMotionAction(ACTION_HOVER_MOVE), WithSource(AINPUT_SOURCE_MOUSE)));
4604 spyWindow->consumeMotionEvent(
4605 AllOf(WithMotionAction(ACTION_HOVER_MOVE), WithSource(AINPUT_SOURCE_MOUSE)));
4606
4607 window->assertNoEvents();
4608 spyWindow->assertNoEvents();
4609}
4610
Garfield Tandf26e862020-07-01 20:18:19 -07004611// This test is different from the test above that HOVER_ENTER and HOVER_EXIT events are injected
4612// directly in this test.
4613TEST_F(InputDispatcherTest, HoverEnterMouseClickAndHoverExit) {
Chris Yea209fde2020-07-22 13:54:51 -07004614 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
Garfield Tandf26e862020-07-01 20:18:19 -07004615 sp<FakeWindowHandle> window =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07004616 sp<FakeWindowHandle>::make(application, mDispatcher, "Window", ADISPLAY_ID_DEFAULT);
Garfield Tandf26e862020-07-01 20:18:19 -07004617 window->setFrame(Rect(0, 0, 1200, 800));
Garfield Tandf26e862020-07-01 20:18:19 -07004618
4619 mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application);
4620
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07004621 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Garfield Tandf26e862020-07-01 20:18:19 -07004622
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08004623 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07004624 injectMotionEvent(*mDispatcher,
Garfield Tandf26e862020-07-01 20:18:19 -07004625 MotionEventBuilder(AMOTION_EVENT_ACTION_HOVER_ENTER,
4626 AINPUT_SOURCE_MOUSE)
Siarhei Vishniakou6d73f832022-07-21 17:27:03 -07004627 .pointer(PointerBuilder(0, ToolType::MOUSE).x(300).y(400))
Garfield Tandf26e862020-07-01 20:18:19 -07004628 .build()));
Siarhei Vishniakou5cee1e32022-11-29 12:35:39 -08004629 window->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_ENTER));
Garfield Tandf26e862020-07-01 20:18:19 -07004630 // Inject a series of mouse events for a mouse click
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08004631 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07004632 injectMotionEvent(*mDispatcher,
Garfield Tandf26e862020-07-01 20:18:19 -07004633 MotionEventBuilder(AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_MOUSE)
4634 .buttonState(AMOTION_EVENT_BUTTON_PRIMARY)
Siarhei Vishniakou6d73f832022-07-21 17:27:03 -07004635 .pointer(PointerBuilder(0, ToolType::MOUSE).x(300).y(400))
Garfield Tandf26e862020-07-01 20:18:19 -07004636 .build()));
Siarhei Vishniakouf372b812023-02-14 18:06:51 -08004637 window->consumeMotionEvent(WithMotionAction(ACTION_HOVER_EXIT));
4638 window->consumeMotionEvent(WithMotionAction(ACTION_DOWN));
Garfield Tandf26e862020-07-01 20:18:19 -07004639
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08004640 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07004641 injectMotionEvent(*mDispatcher,
Garfield Tandf26e862020-07-01 20:18:19 -07004642 MotionEventBuilder(AMOTION_EVENT_ACTION_BUTTON_PRESS,
4643 AINPUT_SOURCE_MOUSE)
4644 .buttonState(AMOTION_EVENT_BUTTON_PRIMARY)
4645 .actionButton(AMOTION_EVENT_BUTTON_PRIMARY)
Siarhei Vishniakou6d73f832022-07-21 17:27:03 -07004646 .pointer(PointerBuilder(0, ToolType::MOUSE).x(300).y(400))
Garfield Tandf26e862020-07-01 20:18:19 -07004647 .build()));
Siarhei Vishniakou5cee1e32022-11-29 12:35:39 -08004648 window->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_BUTTON_PRESS));
Garfield Tandf26e862020-07-01 20:18:19 -07004649
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08004650 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07004651 injectMotionEvent(*mDispatcher,
Garfield Tandf26e862020-07-01 20:18:19 -07004652 MotionEventBuilder(AMOTION_EVENT_ACTION_BUTTON_RELEASE,
4653 AINPUT_SOURCE_MOUSE)
4654 .buttonState(0)
4655 .actionButton(AMOTION_EVENT_BUTTON_PRIMARY)
Siarhei Vishniakou6d73f832022-07-21 17:27:03 -07004656 .pointer(PointerBuilder(0, ToolType::MOUSE).x(300).y(400))
Garfield Tandf26e862020-07-01 20:18:19 -07004657 .build()));
Siarhei Vishniakou5cee1e32022-11-29 12:35:39 -08004658 window->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_BUTTON_RELEASE));
Garfield Tandf26e862020-07-01 20:18:19 -07004659
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08004660 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07004661 injectMotionEvent(*mDispatcher,
Garfield Tandf26e862020-07-01 20:18:19 -07004662 MotionEventBuilder(AMOTION_EVENT_ACTION_UP, AINPUT_SOURCE_MOUSE)
4663 .buttonState(0)
Siarhei Vishniakou6d73f832022-07-21 17:27:03 -07004664 .pointer(PointerBuilder(0, ToolType::MOUSE).x(300).y(400))
Garfield Tandf26e862020-07-01 20:18:19 -07004665 .build()));
4666 window->consumeMotionUp(ADISPLAY_ID_DEFAULT);
4667
Siarhei Vishniakoua235c042023-05-02 09:59:09 -07004668 // We already canceled the hovering implicitly by injecting the "DOWN" event without lifting the
4669 // hover first. Therefore, injection of HOVER_EXIT is inconsistent, and should fail.
4670 ASSERT_EQ(InputEventInjectionResult::FAILED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07004671 injectMotionEvent(*mDispatcher,
Garfield Tandf26e862020-07-01 20:18:19 -07004672 MotionEventBuilder(AMOTION_EVENT_ACTION_HOVER_EXIT,
4673 AINPUT_SOURCE_MOUSE)
Siarhei Vishniakou6d73f832022-07-21 17:27:03 -07004674 .pointer(PointerBuilder(0, ToolType::MOUSE).x(300).y(400))
Garfield Tandf26e862020-07-01 20:18:19 -07004675 .build()));
Siarhei Vishniakouf372b812023-02-14 18:06:51 -08004676 window->assertNoEvents();
Garfield Tandf26e862020-07-01 20:18:19 -07004677}
4678
Siarhei Vishniakou0b0374d2022-11-17 17:40:53 -08004679/**
Siarhei Vishniakoub581f7f2022-12-07 20:23:06 +00004680 * Hover over a window, and then remove that window. Make sure that HOVER_EXIT for that event
4681 * is generated.
4682 */
4683TEST_F(InputDispatcherTest, HoverExitIsSentToRemovedWindow) {
4684 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
4685 sp<FakeWindowHandle> window =
4686 sp<FakeWindowHandle>::make(application, mDispatcher, "Window", ADISPLAY_ID_DEFAULT);
4687 window->setFrame(Rect(0, 0, 1200, 800));
4688
4689 mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application);
4690
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07004691 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Siarhei Vishniakoub581f7f2022-12-07 20:23:06 +00004692
4693 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07004694 injectMotionEvent(*mDispatcher,
Siarhei Vishniakoub581f7f2022-12-07 20:23:06 +00004695 MotionEventBuilder(AMOTION_EVENT_ACTION_HOVER_ENTER,
4696 AINPUT_SOURCE_MOUSE)
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07004697 .pointer(PointerBuilder(0, ToolType::MOUSE).x(300).y(400))
Siarhei Vishniakoub581f7f2022-12-07 20:23:06 +00004698 .build()));
4699 window->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_ENTER));
4700
4701 // Remove the window, but keep the channel.
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07004702 mDispatcher->onWindowInfosChanged({{}, {}, 0, 0});
Siarhei Vishniakoub581f7f2022-12-07 20:23:06 +00004703 window->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_EXIT));
4704}
4705
4706/**
Daniel Norman7487dfa2023-08-02 16:39:45 -07004707 * Test that invalid HOVER events sent by accessibility do not cause a fatal crash.
4708 */
Ameer Armalycff4fa52023-10-04 23:45:11 +00004709TEST_F_WITH_FLAGS(InputDispatcherTest, InvalidA11yHoverStreamDoesNotCrash,
4710 REQUIRES_FLAGS_DISABLED(ACONFIG_FLAG(com::android::input::flags,
4711 a11y_crash_on_inconsistent_event_stream))) {
Daniel Norman7487dfa2023-08-02 16:39:45 -07004712 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
4713 sp<FakeWindowHandle> window =
4714 sp<FakeWindowHandle>::make(application, mDispatcher, "Window", ADISPLAY_ID_DEFAULT);
4715 window->setFrame(Rect(0, 0, 1200, 800));
4716
4717 mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application);
4718
4719 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
4720
4721 MotionEventBuilder hoverEnterBuilder =
4722 MotionEventBuilder(AMOTION_EVENT_ACTION_HOVER_ENTER, AINPUT_SOURCE_MOUSE)
4723 .pointer(PointerBuilder(0, ToolType::MOUSE).x(300).y(400))
4724 .addFlag(AMOTION_EVENT_FLAG_IS_ACCESSIBILITY_EVENT);
4725 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
4726 injectMotionEvent(*mDispatcher, hoverEnterBuilder.build()));
4727 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
4728 injectMotionEvent(*mDispatcher, hoverEnterBuilder.build()));
4729 window->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_ENTER));
4730 window->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_ENTER));
4731}
4732
4733/**
Siarhei Vishniakou4e1ffa52023-02-21 11:50:34 -08004734 * If mouse is hovering when the touch goes down, the hovering should be stopped via HOVER_EXIT.
4735 */
Siarhei Vishniakoued89cbb2023-10-13 10:42:44 -07004736TEST_F(InputDispatcherTest, TouchDownAfterMouseHover_legacy) {
4737 SCOPED_FLAG_OVERRIDE(enable_multi_device_same_window_stream, false);
Siarhei Vishniakou4e1ffa52023-02-21 11:50:34 -08004738 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
4739 sp<FakeWindowHandle> window =
4740 sp<FakeWindowHandle>::make(application, mDispatcher, "Window", ADISPLAY_ID_DEFAULT);
4741 window->setFrame(Rect(0, 0, 100, 100));
4742
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07004743 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Siarhei Vishniakou4e1ffa52023-02-21 11:50:34 -08004744
4745 const int32_t mouseDeviceId = 7;
4746 const int32_t touchDeviceId = 4;
Siarhei Vishniakou4e1ffa52023-02-21 11:50:34 -08004747
4748 // Start hovering with the mouse
Prabir Pradhan678438e2023-04-13 19:32:51 +00004749 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_ENTER, AINPUT_SOURCE_MOUSE)
4750 .deviceId(mouseDeviceId)
4751 .pointer(PointerBuilder(0, ToolType::MOUSE).x(10).y(10))
4752 .build());
Siarhei Vishniakou4e1ffa52023-02-21 11:50:34 -08004753 window->consumeMotionEvent(
4754 AllOf(WithMotionAction(ACTION_HOVER_ENTER), WithDeviceId(mouseDeviceId)));
4755
4756 // Touch goes down
Prabir Pradhan678438e2023-04-13 19:32:51 +00004757 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
4758 .deviceId(touchDeviceId)
4759 .pointer(PointerBuilder(0, ToolType::FINGER).x(50).y(50))
4760 .build());
Siarhei Vishniakou4e1ffa52023-02-21 11:50:34 -08004761
4762 window->consumeMotionEvent(
4763 AllOf(WithMotionAction(ACTION_HOVER_EXIT), WithDeviceId(mouseDeviceId)));
4764 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(touchDeviceId)));
4765}
4766
4767/**
Siarhei Vishniakoued89cbb2023-10-13 10:42:44 -07004768 * If mouse is hovering when the touch goes down, the hovering should not be stopped.
4769 */
4770TEST_F(InputDispatcherTest, TouchDownAfterMouseHover) {
4771 SCOPED_FLAG_OVERRIDE(enable_multi_device_same_window_stream, true);
4772 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
4773 sp<FakeWindowHandle> window =
4774 sp<FakeWindowHandle>::make(application, mDispatcher, "Window", ADISPLAY_ID_DEFAULT);
4775 window->setFrame(Rect(0, 0, 100, 100));
4776
4777 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
4778
4779 const int32_t mouseDeviceId = 7;
4780 const int32_t touchDeviceId = 4;
4781
4782 // Start hovering with the mouse
4783 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_ENTER, AINPUT_SOURCE_MOUSE)
4784 .deviceId(mouseDeviceId)
4785 .pointer(PointerBuilder(0, ToolType::MOUSE).x(10).y(10))
4786 .build());
4787 window->consumeMotionEvent(
4788 AllOf(WithMotionAction(ACTION_HOVER_ENTER), WithDeviceId(mouseDeviceId)));
4789
4790 // Touch goes down
4791 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
4792 .deviceId(touchDeviceId)
4793 .pointer(PointerBuilder(0, ToolType::FINGER).x(50).y(50))
4794 .build());
4795 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(touchDeviceId)));
4796}
4797
4798/**
Siarhei Vishniakou0b0374d2022-11-17 17:40:53 -08004799 * Inject a mouse hover event followed by a tap from touchscreen.
Siarhei Vishniakoub581f7f2022-12-07 20:23:06 +00004800 * The tap causes a HOVER_EXIT event to be generated because the current event
4801 * stream's source has been switched.
Siarhei Vishniakou0b0374d2022-11-17 17:40:53 -08004802 */
Siarhei Vishniakoued89cbb2023-10-13 10:42:44 -07004803TEST_F(InputDispatcherTest, MouseHoverAndTouchTap_legacy) {
4804 SCOPED_FLAG_OVERRIDE(enable_multi_device_same_window_stream, false);
Siarhei Vishniakou0b0374d2022-11-17 17:40:53 -08004805 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
4806 sp<FakeWindowHandle> window =
4807 sp<FakeWindowHandle>::make(application, mDispatcher, "Window", ADISPLAY_ID_DEFAULT);
4808 window->setFrame(Rect(0, 0, 100, 100));
4809
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07004810 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -07004811 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_MOVE, AINPUT_SOURCE_MOUSE)
4812 .pointer(PointerBuilder(0, ToolType::MOUSE).x(50).y(50))
4813 .build());
Siarhei Vishniakou0b0374d2022-11-17 17:40:53 -08004814 ASSERT_NO_FATAL_FAILURE(
4815 window->consumeMotionEvent(AllOf(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_ENTER),
4816 WithSource(AINPUT_SOURCE_MOUSE))));
Siarhei Vishniakou0b0374d2022-11-17 17:40:53 -08004817
4818 // Tap on the window
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -07004819 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
4820 .pointer(PointerBuilder(0, ToolType::FINGER).x(10).y(10))
4821 .build());
Siarhei Vishniakou0b0374d2022-11-17 17:40:53 -08004822 ASSERT_NO_FATAL_FAILURE(
Siarhei Vishniakoub581f7f2022-12-07 20:23:06 +00004823 window->consumeMotionEvent(AllOf(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_EXIT),
4824 WithSource(AINPUT_SOURCE_MOUSE))));
4825
4826 ASSERT_NO_FATAL_FAILURE(
Siarhei Vishniakou0b0374d2022-11-17 17:40:53 -08004827 window->consumeMotionEvent(AllOf(WithMotionAction(AMOTION_EVENT_ACTION_DOWN),
4828 WithSource(AINPUT_SOURCE_TOUCHSCREEN))));
4829
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -07004830 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN)
4831 .pointer(PointerBuilder(0, ToolType::FINGER).x(10).y(10))
4832 .build());
Siarhei Vishniakou0b0374d2022-11-17 17:40:53 -08004833 ASSERT_NO_FATAL_FAILURE(
4834 window->consumeMotionEvent(AllOf(WithMotionAction(AMOTION_EVENT_ACTION_UP),
4835 WithSource(AINPUT_SOURCE_TOUCHSCREEN))));
4836}
4837
Siarhei Vishniakoued89cbb2023-10-13 10:42:44 -07004838/**
4839 * Send a mouse hover event followed by a tap from touchscreen.
4840 * The tap causes a HOVER_EXIT event to be generated because the current event
4841 * stream's source has been switched.
4842 */
4843TEST_F(InputDispatcherTest, MouseHoverAndTouchTap) {
4844 SCOPED_FLAG_OVERRIDE(enable_multi_device_same_window_stream, true);
4845 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
4846 sp<FakeWindowHandle> window =
4847 sp<FakeWindowHandle>::make(application, mDispatcher, "Window", ADISPLAY_ID_DEFAULT);
4848 window->setFrame(Rect(0, 0, 100, 100));
4849
4850 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
4851 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_MOVE, AINPUT_SOURCE_MOUSE)
4852 .pointer(PointerBuilder(0, ToolType::MOUSE).x(50).y(50))
4853 .build());
4854
4855 window->consumeMotionEvent(AllOf(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_ENTER),
4856 WithSource(AINPUT_SOURCE_MOUSE)));
4857
4858 // Tap on the window
4859 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
4860 .pointer(PointerBuilder(0, ToolType::FINGER).x(10).y(10))
4861 .build());
4862
4863 window->consumeMotionEvent(AllOf(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_EXIT),
4864 WithSource(AINPUT_SOURCE_MOUSE)));
4865
4866 window->consumeMotionEvent(AllOf(WithMotionAction(AMOTION_EVENT_ACTION_DOWN),
4867 WithSource(AINPUT_SOURCE_TOUCHSCREEN)));
4868
4869 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN)
4870 .pointer(PointerBuilder(0, ToolType::FINGER).x(10).y(10))
4871 .build());
4872
4873 window->consumeMotionEvent(AllOf(WithMotionAction(AMOTION_EVENT_ACTION_UP),
4874 WithSource(AINPUT_SOURCE_TOUCHSCREEN)));
4875}
4876
Tommy Nordgrendae9dfc2022-10-13 11:25:57 +02004877TEST_F(InputDispatcherTest, HoverEnterMoveRemoveWindowsInSecondDisplay) {
4878 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
4879 sp<FakeWindowHandle> windowDefaultDisplay =
4880 sp<FakeWindowHandle>::make(application, mDispatcher, "DefaultDisplay",
4881 ADISPLAY_ID_DEFAULT);
4882 windowDefaultDisplay->setFrame(Rect(0, 0, 600, 800));
4883 sp<FakeWindowHandle> windowSecondDisplay =
4884 sp<FakeWindowHandle>::make(application, mDispatcher, "SecondDisplay",
4885 SECOND_DISPLAY_ID);
4886 windowSecondDisplay->setFrame(Rect(0, 0, 600, 800));
4887
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07004888 mDispatcher->onWindowInfosChanged(
4889 {{*windowDefaultDisplay->getInfo(), *windowSecondDisplay->getInfo()}, {}, 0, 0});
Tommy Nordgrendae9dfc2022-10-13 11:25:57 +02004890
4891 // Set cursor position in window in default display and check that hover enter and move
4892 // events are generated.
4893 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07004894 injectMotionEvent(*mDispatcher,
Tommy Nordgrendae9dfc2022-10-13 11:25:57 +02004895 MotionEventBuilder(AMOTION_EVENT_ACTION_HOVER_MOVE,
4896 AINPUT_SOURCE_MOUSE)
4897 .displayId(ADISPLAY_ID_DEFAULT)
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07004898 .pointer(PointerBuilder(0, ToolType::MOUSE).x(300).y(600))
Tommy Nordgrendae9dfc2022-10-13 11:25:57 +02004899 .build()));
Siarhei Vishniakou5cee1e32022-11-29 12:35:39 -08004900 windowDefaultDisplay->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_ENTER));
Tommy Nordgrendae9dfc2022-10-13 11:25:57 +02004901
4902 // Remove all windows in secondary display and check that no event happens on window in
4903 // primary display.
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07004904 mDispatcher->onWindowInfosChanged({{*windowDefaultDisplay->getInfo()}, {}, 0, 0});
4905
Tommy Nordgrendae9dfc2022-10-13 11:25:57 +02004906 windowDefaultDisplay->assertNoEvents();
4907
4908 // Move cursor position in window in default display and check that only hover move
4909 // event is generated and not hover enter event.
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07004910 mDispatcher->onWindowInfosChanged(
4911 {{*windowDefaultDisplay->getInfo(), *windowSecondDisplay->getInfo()}, {}, 0, 0});
Tommy Nordgrendae9dfc2022-10-13 11:25:57 +02004912 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07004913 injectMotionEvent(*mDispatcher,
Tommy Nordgrendae9dfc2022-10-13 11:25:57 +02004914 MotionEventBuilder(AMOTION_EVENT_ACTION_HOVER_MOVE,
4915 AINPUT_SOURCE_MOUSE)
4916 .displayId(ADISPLAY_ID_DEFAULT)
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07004917 .pointer(PointerBuilder(0, ToolType::MOUSE).x(400).y(700))
Tommy Nordgrendae9dfc2022-10-13 11:25:57 +02004918 .build()));
Siarhei Vishniakou5cee1e32022-11-29 12:35:39 -08004919 windowDefaultDisplay->consumeMotionEvent(
4920 AllOf(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_MOVE),
4921 WithSource(AINPUT_SOURCE_MOUSE)));
Tommy Nordgrendae9dfc2022-10-13 11:25:57 +02004922 windowDefaultDisplay->assertNoEvents();
4923}
4924
Garfield Tan00f511d2019-06-12 16:55:40 -07004925TEST_F(InputDispatcherTest, DispatchMouseEventsUnderCursor) {
Chris Yea209fde2020-07-22 13:54:51 -07004926 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
Garfield Tan00f511d2019-06-12 16:55:40 -07004927
4928 sp<FakeWindowHandle> windowLeft =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07004929 sp<FakeWindowHandle>::make(application, mDispatcher, "Left", ADISPLAY_ID_DEFAULT);
Garfield Tan00f511d2019-06-12 16:55:40 -07004930 windowLeft->setFrame(Rect(0, 0, 600, 800));
Garfield Tan00f511d2019-06-12 16:55:40 -07004931 sp<FakeWindowHandle> windowRight =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07004932 sp<FakeWindowHandle>::make(application, mDispatcher, "Right", ADISPLAY_ID_DEFAULT);
Garfield Tan00f511d2019-06-12 16:55:40 -07004933 windowRight->setFrame(Rect(600, 0, 1200, 800));
Garfield Tan00f511d2019-06-12 16:55:40 -07004934
4935 mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application);
4936
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07004937 mDispatcher->onWindowInfosChanged(
4938 {{*windowLeft->getInfo(), *windowRight->getInfo()}, {}, 0, 0});
Garfield Tan00f511d2019-06-12 16:55:40 -07004939
4940 // Inject an event with coordinate in the area of right window, with mouse cursor in the area of
4941 // left window. This event should be dispatched to the left window.
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08004942 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07004943 injectMotionEvent(*mDispatcher, AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_MOUSE,
Siarhei Vishniakou4cb50ca2020-05-26 21:43:02 -07004944 ADISPLAY_ID_DEFAULT, {610, 400}, {599, 400}));
Siarhei Vishniakouc5ca85c2019-11-15 17:20:00 -08004945 windowLeft->consumeMotionDown(ADISPLAY_ID_DEFAULT);
Garfield Tan00f511d2019-06-12 16:55:40 -07004946 windowRight->assertNoEvents();
4947}
4948
Siarhei Vishniakou2bfa9052019-11-21 18:10:54 -08004949TEST_F(InputDispatcherTest, NotifyDeviceReset_CancelsKeyStream) {
Chris Yea209fde2020-07-22 13:54:51 -07004950 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07004951 sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher,
4952 "Fake Window", ADISPLAY_ID_DEFAULT);
Vishnu Nair47074b82020-08-14 11:54:47 -07004953 window->setFocusable(true);
Siarhei Vishniakou2bfa9052019-11-21 18:10:54 -08004954
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07004955 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Vishnu Nair958da932020-08-21 17:12:37 -07004956 setFocusedWindow(window);
4957
Siarhei Vishniakouf1035d42019-09-20 16:32:01 +01004958 window->consumeFocusEvent(true);
Siarhei Vishniakou2bfa9052019-11-21 18:10:54 -08004959
Prabir Pradhan678438e2023-04-13 19:32:51 +00004960 mDispatcher->notifyKey(generateKeyArgs(AKEY_EVENT_ACTION_DOWN, ADISPLAY_ID_DEFAULT));
Siarhei Vishniakou2bfa9052019-11-21 18:10:54 -08004961
4962 // Window should receive key down event.
4963 window->consumeKeyDown(ADISPLAY_ID_DEFAULT);
4964
4965 // When device reset happens, that key stream should be terminated with FLAG_CANCELED
4966 // on the app side.
Prabir Pradhan678438e2023-04-13 19:32:51 +00004967 mDispatcher->notifyDeviceReset({/*id=*/10, /*eventTime=*/20, DEVICE_ID});
Prabir Pradhan7662a8d2023-12-15 01:58:14 +00004968 window->consumeKeyUp(ADISPLAY_ID_DEFAULT, AKEY_EVENT_FLAG_CANCELED);
Siarhei Vishniakou2bfa9052019-11-21 18:10:54 -08004969}
4970
4971TEST_F(InputDispatcherTest, NotifyDeviceReset_CancelsMotionStream) {
Chris Yea209fde2020-07-22 13:54:51 -07004972 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07004973 sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher,
4974 "Fake Window", ADISPLAY_ID_DEFAULT);
Siarhei Vishniakou2bfa9052019-11-21 18:10:54 -08004975
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07004976 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Siarhei Vishniakou2bfa9052019-11-21 18:10:54 -08004977
Prabir Pradhan678438e2023-04-13 19:32:51 +00004978 mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_DOWN,
4979 AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT));
Siarhei Vishniakou2bfa9052019-11-21 18:10:54 -08004980
4981 // Window should receive motion down event.
4982 window->consumeMotionDown(ADISPLAY_ID_DEFAULT);
4983
4984 // When device reset happens, that motion stream should be terminated with ACTION_CANCEL
4985 // on the app side.
Prabir Pradhan678438e2023-04-13 19:32:51 +00004986 mDispatcher->notifyDeviceReset({/*id=*/10, /*eventTime=*/20, DEVICE_ID});
Siarhei Vishniakou1ae72f12023-01-29 12:55:30 -08004987 window->consumeMotionEvent(
4988 AllOf(WithMotionAction(ACTION_CANCEL), WithDisplayId(ADISPLAY_ID_DEFAULT)));
Siarhei Vishniakou2bfa9052019-11-21 18:10:54 -08004989}
4990
Siarhei Vishniakou0686f0c2023-05-02 11:56:15 -07004991TEST_F(InputDispatcherTest, NotifyDeviceResetCancelsHoveringStream) {
4992 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
4993 sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher,
4994 "Fake Window", ADISPLAY_ID_DEFAULT);
4995
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07004996 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Siarhei Vishniakou0686f0c2023-05-02 11:56:15 -07004997
4998 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_ENTER, AINPUT_SOURCE_STYLUS)
4999 .pointer(PointerBuilder(0, ToolType::STYLUS).x(10).y(10))
5000 .build());
5001
5002 window->consumeMotionEvent(WithMotionAction(ACTION_HOVER_ENTER));
5003
5004 // When device reset happens, that hover stream should be terminated with ACTION_HOVER_EXIT
5005 mDispatcher->notifyDeviceReset({/*id=*/10, /*eventTime=*/20, DEVICE_ID});
5006 window->consumeMotionEvent(WithMotionAction(ACTION_HOVER_EXIT));
5007
5008 // After the device has been reset, a new hovering stream can be sent to the window
5009 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_ENTER, AINPUT_SOURCE_STYLUS)
5010 .pointer(PointerBuilder(0, ToolType::STYLUS).x(15).y(15))
5011 .build());
5012 window->consumeMotionEvent(WithMotionAction(ACTION_HOVER_ENTER));
5013}
5014
Arthur Hung2ee6d0b2022-03-03 20:19:38 +08005015TEST_F(InputDispatcherTest, InterceptKeyByPolicy) {
5016 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07005017 sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher,
5018 "Fake Window", ADISPLAY_ID_DEFAULT);
Arthur Hung2ee6d0b2022-03-03 20:19:38 +08005019 window->setFocusable(true);
5020
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07005021 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Arthur Hung2ee6d0b2022-03-03 20:19:38 +08005022 setFocusedWindow(window);
5023
5024 window->consumeFocusEvent(true);
5025
Prabir Pradhan678438e2023-04-13 19:32:51 +00005026 const NotifyKeyArgs keyArgs = generateKeyArgs(AKEY_EVENT_ACTION_DOWN, ADISPLAY_ID_DEFAULT);
Arthur Hung2ee6d0b2022-03-03 20:19:38 +08005027 const std::chrono::milliseconds interceptKeyTimeout = 50ms;
5028 const nsecs_t injectTime = keyArgs.eventTime;
5029 mFakePolicy->setInterceptKeyTimeout(interceptKeyTimeout);
Prabir Pradhan678438e2023-04-13 19:32:51 +00005030 mDispatcher->notifyKey(keyArgs);
Arthur Hung2ee6d0b2022-03-03 20:19:38 +08005031 // The dispatching time should be always greater than or equal to intercept key timeout.
5032 window->consumeKeyDown(ADISPLAY_ID_DEFAULT);
5033 ASSERT_TRUE((systemTime(SYSTEM_TIME_MONOTONIC) - injectTime) >=
5034 std::chrono::nanoseconds(interceptKeyTimeout).count());
5035}
5036
Siarhei Vishniakouf54d2ab2023-06-09 13:23:53 -07005037/**
5038 * Keys with ACTION_UP are delivered immediately, even if a long 'intercept key timeout' is set.
5039 */
Arthur Hung2ee6d0b2022-03-03 20:19:38 +08005040TEST_F(InputDispatcherTest, InterceptKeyIfKeyUp) {
5041 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07005042 sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher,
5043 "Fake Window", ADISPLAY_ID_DEFAULT);
Arthur Hung2ee6d0b2022-03-03 20:19:38 +08005044 window->setFocusable(true);
5045
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07005046 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Arthur Hung2ee6d0b2022-03-03 20:19:38 +08005047 setFocusedWindow(window);
5048
5049 window->consumeFocusEvent(true);
5050
Prabir Pradhan678438e2023-04-13 19:32:51 +00005051 mDispatcher->notifyKey(generateKeyArgs(AKEY_EVENT_ACTION_DOWN, ADISPLAY_ID_DEFAULT));
Arthur Hung2ee6d0b2022-03-03 20:19:38 +08005052 window->consumeKeyDown(ADISPLAY_ID_DEFAULT);
Siarhei Vishniakouf54d2ab2023-06-09 13:23:53 -07005053
5054 // Set a value that's significantly larger than the default consumption timeout. If the
5055 // implementation is correct, the actual value doesn't matter; it won't slow down the test.
5056 mFakePolicy->setInterceptKeyTimeout(600ms);
5057 mDispatcher->notifyKey(generateKeyArgs(AKEY_EVENT_ACTION_UP, ADISPLAY_ID_DEFAULT));
5058 // Window should receive key event immediately when same key up.
Arthur Hung2ee6d0b2022-03-03 20:19:38 +08005059 window->consumeKeyUp(ADISPLAY_ID_DEFAULT);
5060}
5061
Prabir Pradhanc44ce4d2021-10-05 05:26:29 -07005062/**
Siarhei Vishniakou487c49b2022-12-02 15:48:57 -08005063 * Two windows. First is a regular window. Second does not overlap with the first, and has
5064 * WATCH_OUTSIDE_TOUCH.
5065 * Both windows are owned by the same UID.
5066 * Tap first window. Make sure that the second window receives ACTION_OUTSIDE with correct, non-zero
5067 * coordinates. The coordinates are not zeroed out because both windows are owned by the same UID.
5068 */
5069TEST_F(InputDispatcherTest, ActionOutsideForOwnedWindowHasValidCoordinates) {
5070 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -07005071 sp<FakeWindowHandle> window =
5072 sp<FakeWindowHandle>::make(application, mDispatcher, "Window", ADISPLAY_ID_DEFAULT);
Siarhei Vishniakou487c49b2022-12-02 15:48:57 -08005073 window->setFrame(Rect{0, 0, 100, 100});
5074
5075 sp<FakeWindowHandle> outsideWindow =
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -07005076 sp<FakeWindowHandle>::make(application, mDispatcher, "Outside Window",
Siarhei Vishniakou487c49b2022-12-02 15:48:57 -08005077 ADISPLAY_ID_DEFAULT);
5078 outsideWindow->setFrame(Rect{100, 100, 200, 200});
5079 outsideWindow->setWatchOutsideTouch(true);
5080 // outsideWindow must be above 'window' to receive ACTION_OUTSIDE events when 'window' is tapped
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07005081 mDispatcher->onWindowInfosChanged({{*outsideWindow->getInfo(), *window->getInfo()}, {}, 0, 0});
Siarhei Vishniakou487c49b2022-12-02 15:48:57 -08005082
5083 // Tap on first window.
Prabir Pradhan678438e2023-04-13 19:32:51 +00005084 mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_DOWN,
5085 AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
5086 {PointF{50, 50}}));
Siarhei Vishniakou487c49b2022-12-02 15:48:57 -08005087 window->consumeMotionDown();
5088 // The coordinates of the tap in 'outsideWindow' are relative to its top left corner.
5089 // Therefore, we should offset them by (100, 100) relative to the screen's top left corner.
5090 outsideWindow->consumeMotionEvent(
5091 AllOf(WithMotionAction(ACTION_OUTSIDE), WithCoords(-50, -50)));
Prabir Pradhan502a7252023-12-01 16:11:24 +00005092
5093 // Ensure outsideWindow doesn't get any more events for the gesture.
5094 mDispatcher->notifyMotion(generateMotionArgs(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN,
5095 ADISPLAY_ID_DEFAULT, {PointF{51, 51}}));
5096 window->consumeMotionMove();
5097 outsideWindow->assertNoEvents();
Siarhei Vishniakou487c49b2022-12-02 15:48:57 -08005098}
5099
5100/**
Linnan Liccf6ce32024-04-11 20:32:13 +08005101 * Three windows:
5102 * - Left window
5103 * - Right window
5104 * - Outside window(watch for ACTION_OUTSIDE events)
5105 * The windows "left" and "outside" share the same owner, the window "right" has a different owner,
5106 * In order to allow the outside window can receive the ACTION_OUTSIDE events, the outside window is
5107 * positioned above the "left" and "right" windows, and it doesn't overlap with them.
5108 *
5109 * First, device A report a down event landed in the right window, the outside window can receive
5110 * an ACTION_OUTSIDE event that with zeroed coordinates, the device B report a down event landed
5111 * in the left window, the outside window can receive an ACTION_OUTSIDE event the with valid
5112 * coordinates, after these, device A and device B continue report MOVE event, the right and left
5113 * window can receive it, but outside window event can't receive it.
5114 */
5115TEST_F(InputDispatcherTest, ActionOutsideForOwnedWindowHasValidCoordinatesWhenMultiDevice) {
5116 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
5117 sp<FakeWindowHandle> leftWindow =
5118 sp<FakeWindowHandle>::make(application, mDispatcher, "Left Window",
5119 ADISPLAY_ID_DEFAULT);
5120 leftWindow->setFrame(Rect{0, 0, 100, 100});
5121 leftWindow->setOwnerInfo(gui::Pid{1}, gui::Uid{101});
5122
5123 sp<FakeWindowHandle> outsideWindow =
5124 sp<FakeWindowHandle>::make(application, mDispatcher, "Outside Window",
5125 ADISPLAY_ID_DEFAULT);
5126 outsideWindow->setFrame(Rect{100, 100, 200, 200});
5127 outsideWindow->setOwnerInfo(gui::Pid{1}, gui::Uid{101});
5128 outsideWindow->setWatchOutsideTouch(true);
5129
5130 std::shared_ptr<FakeApplicationHandle> anotherApplication =
5131 std::make_shared<FakeApplicationHandle>();
5132 sp<FakeWindowHandle> rightWindow =
5133 sp<FakeWindowHandle>::make(anotherApplication, mDispatcher, "Right Window",
5134 ADISPLAY_ID_DEFAULT);
5135 rightWindow->setFrame(Rect{100, 0, 200, 100});
5136 rightWindow->setOwnerInfo(gui::Pid{2}, gui::Uid{202});
5137
5138 // OutsideWindow must be above left window and right window to receive ACTION_OUTSIDE events
5139 // when left window or right window is tapped
5140 mDispatcher->onWindowInfosChanged(
5141 {{*outsideWindow->getInfo(), *leftWindow->getInfo(), *rightWindow->getInfo()},
5142 {},
5143 0,
5144 0});
5145
5146 const DeviceId deviceA = 9;
5147 const DeviceId deviceB = 3;
5148
5149 // Tap on right window use device A
5150 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
5151 .pointer(PointerBuilder(0, ToolType::FINGER).x(150).y(50))
5152 .deviceId(deviceA)
5153 .build());
5154 leftWindow->assertNoEvents();
5155 rightWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(deviceA)));
5156 // Right window is belonged to another owner, so outsideWindow should receive ACTION_OUTSIDE
5157 // with zeroed coords.
5158 outsideWindow->consumeMotionEvent(
5159 AllOf(WithMotionAction(ACTION_OUTSIDE), WithDeviceId(deviceA), WithCoords(0, 0)));
5160
5161 // Tap on left window use device B
5162 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
5163 .pointer(PointerBuilder(0, ToolType::FINGER).x(50).y(50))
5164 .deviceId(deviceB)
5165 .build());
5166 leftWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(deviceB)));
5167 rightWindow->assertNoEvents();
5168 // Because new gesture down on the left window that has the same owner with outside Window, the
5169 // outside Window should receive the ACTION_OUTSIDE with coords.
5170 outsideWindow->consumeMotionEvent(
5171 AllOf(WithMotionAction(ACTION_OUTSIDE), WithDeviceId(deviceB), WithCoords(-50, -50)));
5172
5173 // Ensure that windows that can only accept outside do not receive remaining gestures
5174 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN)
5175 .pointer(PointerBuilder(0, ToolType::FINGER).x(151).y(51))
5176 .deviceId(deviceA)
5177 .build());
5178 leftWindow->assertNoEvents();
5179 rightWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(deviceA)));
5180
5181 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN)
5182 .pointer(PointerBuilder(0, ToolType::FINGER).x(51).y(51))
5183 .deviceId(deviceB)
5184 .build());
5185 leftWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(deviceB)));
5186 rightWindow->assertNoEvents();
5187 outsideWindow->assertNoEvents();
5188}
5189
5190/**
Prabir Pradhanb60b1dc2022-03-15 14:02:35 +00005191 * This test documents the behavior of WATCH_OUTSIDE_TOUCH. The window will get ACTION_OUTSIDE when
5192 * a another pointer causes ACTION_DOWN to be sent to another window for the first time. Only one
5193 * ACTION_OUTSIDE event is sent per gesture.
5194 */
5195TEST_F(InputDispatcherTest, ActionOutsideSentOnlyWhenAWindowIsTouched) {
5196 // There are three windows that do not overlap. `window` wants to WATCH_OUTSIDE_TOUCH.
5197 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07005198 sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher,
5199 "First Window", ADISPLAY_ID_DEFAULT);
Prabir Pradhanb60b1dc2022-03-15 14:02:35 +00005200 window->setWatchOutsideTouch(true);
5201 window->setFrame(Rect{0, 0, 100, 100});
5202 sp<FakeWindowHandle> secondWindow =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07005203 sp<FakeWindowHandle>::make(application, mDispatcher, "Second Window",
5204 ADISPLAY_ID_DEFAULT);
Prabir Pradhanb60b1dc2022-03-15 14:02:35 +00005205 secondWindow->setFrame(Rect{100, 100, 200, 200});
5206 sp<FakeWindowHandle> thirdWindow =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07005207 sp<FakeWindowHandle>::make(application, mDispatcher, "Third Window",
5208 ADISPLAY_ID_DEFAULT);
Prabir Pradhanb60b1dc2022-03-15 14:02:35 +00005209 thirdWindow->setFrame(Rect{200, 200, 300, 300});
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07005210 mDispatcher->onWindowInfosChanged(
5211 {{*window->getInfo(), *secondWindow->getInfo(), *thirdWindow->getInfo()}, {}, 0, 0});
Prabir Pradhanb60b1dc2022-03-15 14:02:35 +00005212
5213 // First pointer lands outside all windows. `window` does not get ACTION_OUTSIDE.
Prabir Pradhan678438e2023-04-13 19:32:51 +00005214 mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_DOWN,
5215 AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
5216 {PointF{-10, -10}}));
Prabir Pradhanb60b1dc2022-03-15 14:02:35 +00005217 window->assertNoEvents();
5218 secondWindow->assertNoEvents();
5219
5220 // The second pointer lands inside `secondWindow`, which should receive a DOWN event.
5221 // Now, `window` should get ACTION_OUTSIDE.
Prabir Pradhan678438e2023-04-13 19:32:51 +00005222 mDispatcher->notifyMotion(generateMotionArgs(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN,
5223 ADISPLAY_ID_DEFAULT,
5224 {PointF{-10, -10}, PointF{105, 105}}));
Siarhei Vishniakou487c49b2022-12-02 15:48:57 -08005225 const std::map<int32_t, PointF> expectedPointers{{0, PointF{-10, -10}}, {1, PointF{105, 105}}};
5226 window->consumeMotionEvent(
5227 AllOf(WithMotionAction(ACTION_OUTSIDE), WithPointers(expectedPointers)));
Prabir Pradhanb60b1dc2022-03-15 14:02:35 +00005228 secondWindow->consumeMotionDown();
5229 thirdWindow->assertNoEvents();
5230
5231 // The third pointer lands inside `thirdWindow`, which should receive a DOWN event. There is
5232 // no ACTION_OUTSIDE sent to `window` because one has already been sent for this gesture.
Prabir Pradhan678438e2023-04-13 19:32:51 +00005233 mDispatcher->notifyMotion(
5234 generateMotionArgs(POINTER_2_DOWN, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
5235 {PointF{-10, -10}, PointF{105, 105}, PointF{205, 205}}));
Prabir Pradhanb60b1dc2022-03-15 14:02:35 +00005236 window->assertNoEvents();
5237 secondWindow->consumeMotionMove();
5238 thirdWindow->consumeMotionDown();
5239}
5240
Prabir Pradhan814fe082022-07-22 20:22:18 +00005241TEST_F(InputDispatcherTest, OnWindowInfosChanged_RemoveAllWindowsOnDisplay) {
5242 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07005243 sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher,
5244 "Fake Window", ADISPLAY_ID_DEFAULT);
Prabir Pradhan814fe082022-07-22 20:22:18 +00005245 window->setFocusable(true);
5246
Patrick Williamsd828f302023-04-28 17:52:08 -05005247 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Prabir Pradhan814fe082022-07-22 20:22:18 +00005248 setFocusedWindow(window);
5249
5250 window->consumeFocusEvent(true);
5251
Prabir Pradhan678438e2023-04-13 19:32:51 +00005252 const NotifyKeyArgs keyDown = generateKeyArgs(AKEY_EVENT_ACTION_DOWN, ADISPLAY_ID_DEFAULT);
5253 const NotifyKeyArgs keyUp = generateKeyArgs(AKEY_EVENT_ACTION_UP, ADISPLAY_ID_DEFAULT);
5254 mDispatcher->notifyKey(keyDown);
5255 mDispatcher->notifyKey(keyUp);
Prabir Pradhan814fe082022-07-22 20:22:18 +00005256
5257 window->consumeKeyDown(ADISPLAY_ID_DEFAULT);
5258 window->consumeKeyUp(ADISPLAY_ID_DEFAULT);
5259
5260 // All windows are removed from the display. Ensure that we can no longer dispatch to it.
Patrick Williamsd828f302023-04-28 17:52:08 -05005261 mDispatcher->onWindowInfosChanged({{}, {}, 0, 0});
Prabir Pradhan814fe082022-07-22 20:22:18 +00005262
5263 window->consumeFocusEvent(false);
5264
Prabir Pradhan678438e2023-04-13 19:32:51 +00005265 mDispatcher->notifyKey(keyDown);
5266 mDispatcher->notifyKey(keyUp);
Prabir Pradhan814fe082022-07-22 20:22:18 +00005267 window->assertNoEvents();
5268}
5269
Arthur Hung96483742022-11-15 03:30:48 +00005270TEST_F(InputDispatcherTest, NonSplitTouchableWindowReceivesMultiTouch) {
5271 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
5272 sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher,
5273 "Fake Window", ADISPLAY_ID_DEFAULT);
5274 // Ensure window is non-split and have some transform.
5275 window->setPreventSplitting(true);
5276 window->setWindowOffset(20, 40);
Patrick Williamsd828f302023-04-28 17:52:08 -05005277 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Arthur Hung96483742022-11-15 03:30:48 +00005278
5279 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07005280 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
Arthur Hung96483742022-11-15 03:30:48 +00005281 {50, 50}))
5282 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
5283 window->consumeMotionDown(ADISPLAY_ID_DEFAULT);
5284
5285 const MotionEvent secondFingerDownEvent =
5286 MotionEventBuilder(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
5287 .displayId(ADISPLAY_ID_DEFAULT)
5288 .eventTime(systemTime(SYSTEM_TIME_MONOTONIC))
Siarhei Vishniakou6d73f832022-07-21 17:27:03 -07005289 .pointer(PointerBuilder(/*id=*/0, ToolType::FINGER).x(50).y(50))
5290 .pointer(PointerBuilder(/*id=*/1, ToolType::FINGER).x(-30).y(-50))
Arthur Hung96483742022-11-15 03:30:48 +00005291 .build();
5292 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07005293 injectMotionEvent(*mDispatcher, secondFingerDownEvent, INJECT_EVENT_TIMEOUT,
Arthur Hung96483742022-11-15 03:30:48 +00005294 InputEventInjectionSync::WAIT_FOR_RESULT))
5295 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
5296
Siarhei Vishniakoud3061ab2023-12-18 20:41:08 -08005297 std::unique_ptr<MotionEvent> event = window->consumeMotionEvent();
5298 ASSERT_NE(nullptr, event);
5299 EXPECT_EQ(POINTER_1_DOWN, event->getAction());
5300 EXPECT_EQ(70, event->getX(0)); // 50 + 20
5301 EXPECT_EQ(90, event->getY(0)); // 50 + 40
5302 EXPECT_EQ(-10, event->getX(1)); // -30 + 20
5303 EXPECT_EQ(-10, event->getY(1)); // -50 + 40
Arthur Hung96483742022-11-15 03:30:48 +00005304}
5305
Siarhei Vishniakou25537f82023-07-18 14:35:47 -07005306/**
5307 * Two windows: a splittable and a non-splittable.
5308 * The non-splittable window shouldn't receive any "incomplete" gestures.
5309 * Send the first pointer to the splittable window, and then touch the non-splittable window.
5310 * The second pointer should be dropped because the initial window is splittable, so it won't get
5311 * any pointers outside of it, and the second window is non-splittable, so it shouldn't get any
5312 * "incomplete" gestures.
5313 */
5314TEST_F(InputDispatcherTest, SplittableAndNonSplittableWindows) {
5315 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
5316 sp<FakeWindowHandle> leftWindow =
5317 sp<FakeWindowHandle>::make(application, mDispatcher, "Left splittable Window",
5318 ADISPLAY_ID_DEFAULT);
5319 leftWindow->setPreventSplitting(false);
5320 leftWindow->setFrame(Rect(0, 0, 100, 100));
5321 sp<FakeWindowHandle> rightWindow =
5322 sp<FakeWindowHandle>::make(application, mDispatcher, "Right non-splittable Window",
5323 ADISPLAY_ID_DEFAULT);
5324 rightWindow->setPreventSplitting(true);
5325 rightWindow->setFrame(Rect(100, 100, 200, 200));
5326 mDispatcher->onWindowInfosChanged(
5327 {{*leftWindow->getInfo(), *rightWindow->getInfo()}, {}, 0, 0});
5328
5329 // Touch down on left, splittable window
5330 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
5331 .pointer(PointerBuilder(0, ToolType::FINGER).x(50).y(50))
5332 .build());
5333 leftWindow->consumeMotionEvent(WithMotionAction(ACTION_DOWN));
5334
5335 mDispatcher->notifyMotion(
5336 MotionArgsBuilder(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
5337 .pointer(PointerBuilder(/*id=*/0, ToolType::FINGER).x(50).y(50))
5338 .pointer(PointerBuilder(/*id=*/1, ToolType::FINGER).x(150).y(150))
5339 .build());
5340 leftWindow->assertNoEvents();
5341 rightWindow->assertNoEvents();
5342}
5343
Harry Cuttsb166c002023-05-09 13:06:05 +00005344TEST_F(InputDispatcherTest, TouchpadThreeFingerSwipeOnlySentToTrustedOverlays) {
5345 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
5346 sp<FakeWindowHandle> window =
5347 sp<FakeWindowHandle>::make(application, mDispatcher, "Window", ADISPLAY_ID_DEFAULT);
5348 window->setFrame(Rect(0, 0, 400, 400));
5349 sp<FakeWindowHandle> trustedOverlay =
5350 sp<FakeWindowHandle>::make(application, mDispatcher, "Trusted Overlay",
5351 ADISPLAY_ID_DEFAULT);
5352 trustedOverlay->setSpy(true);
5353 trustedOverlay->setTrustedOverlay(true);
5354
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07005355 mDispatcher->onWindowInfosChanged({{*trustedOverlay->getInfo(), *window->getInfo()}, {}, 0, 0});
Harry Cuttsb166c002023-05-09 13:06:05 +00005356
5357 // Start a three-finger touchpad swipe
5358 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_MOUSE)
5359 .pointer(PointerBuilder(0, ToolType::FINGER).x(200).y(100))
5360 .classification(MotionClassification::MULTI_FINGER_SWIPE)
5361 .build());
5362 mDispatcher->notifyMotion(MotionArgsBuilder(POINTER_1_DOWN, AINPUT_SOURCE_MOUSE)
5363 .pointer(PointerBuilder(0, ToolType::FINGER).x(200).y(100))
5364 .pointer(PointerBuilder(1, ToolType::FINGER).x(250).y(100))
5365 .classification(MotionClassification::MULTI_FINGER_SWIPE)
5366 .build());
5367 mDispatcher->notifyMotion(MotionArgsBuilder(POINTER_2_DOWN, AINPUT_SOURCE_MOUSE)
5368 .pointer(PointerBuilder(0, ToolType::FINGER).x(200).y(100))
5369 .pointer(PointerBuilder(1, ToolType::FINGER).x(250).y(100))
5370 .pointer(PointerBuilder(2, ToolType::FINGER).x(300).y(100))
5371 .classification(MotionClassification::MULTI_FINGER_SWIPE)
5372 .build());
5373
5374 trustedOverlay->consumeMotionEvent(WithMotionAction(ACTION_DOWN));
5375 trustedOverlay->consumeMotionEvent(WithMotionAction(POINTER_1_DOWN));
5376 trustedOverlay->consumeMotionEvent(WithMotionAction(POINTER_2_DOWN));
5377
5378 // Move the swipe a bit
5379 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_MOUSE)
5380 .pointer(PointerBuilder(0, ToolType::FINGER).x(200).y(105))
5381 .pointer(PointerBuilder(1, ToolType::FINGER).x(250).y(105))
5382 .pointer(PointerBuilder(2, ToolType::FINGER).x(300).y(105))
5383 .classification(MotionClassification::MULTI_FINGER_SWIPE)
5384 .build());
5385
5386 trustedOverlay->consumeMotionEvent(WithMotionAction(ACTION_MOVE));
5387
5388 // End the swipe
5389 mDispatcher->notifyMotion(MotionArgsBuilder(POINTER_2_UP, AINPUT_SOURCE_MOUSE)
5390 .pointer(PointerBuilder(0, ToolType::FINGER).x(200).y(105))
5391 .pointer(PointerBuilder(1, ToolType::FINGER).x(250).y(105))
5392 .pointer(PointerBuilder(2, ToolType::FINGER).x(300).y(105))
5393 .classification(MotionClassification::MULTI_FINGER_SWIPE)
5394 .build());
5395 mDispatcher->notifyMotion(MotionArgsBuilder(POINTER_1_UP, AINPUT_SOURCE_MOUSE)
5396 .pointer(PointerBuilder(0, ToolType::FINGER).x(200).y(105))
5397 .pointer(PointerBuilder(1, ToolType::FINGER).x(250).y(105))
5398 .classification(MotionClassification::MULTI_FINGER_SWIPE)
5399 .build());
5400 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_UP, AINPUT_SOURCE_MOUSE)
5401 .pointer(PointerBuilder(0, ToolType::FINGER).x(200).y(105))
5402 .classification(MotionClassification::MULTI_FINGER_SWIPE)
5403 .build());
5404
5405 trustedOverlay->consumeMotionEvent(WithMotionAction(POINTER_2_UP));
5406 trustedOverlay->consumeMotionEvent(WithMotionAction(POINTER_1_UP));
5407 trustedOverlay->consumeMotionEvent(WithMotionAction(ACTION_UP));
5408
5409 window->assertNoEvents();
5410}
5411
5412TEST_F(InputDispatcherTest, TouchpadThreeFingerSwipeNotSentToSingleWindow) {
5413 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
5414 sp<FakeWindowHandle> window =
5415 sp<FakeWindowHandle>::make(application, mDispatcher, "Window", ADISPLAY_ID_DEFAULT);
5416 window->setFrame(Rect(0, 0, 400, 400));
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07005417 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Harry Cuttsb166c002023-05-09 13:06:05 +00005418
5419 // Start a three-finger touchpad swipe
5420 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_MOUSE)
5421 .pointer(PointerBuilder(0, ToolType::FINGER).x(200).y(100))
5422 .classification(MotionClassification::MULTI_FINGER_SWIPE)
5423 .build());
5424 mDispatcher->notifyMotion(MotionArgsBuilder(POINTER_1_DOWN, AINPUT_SOURCE_MOUSE)
5425 .pointer(PointerBuilder(0, ToolType::FINGER).x(200).y(100))
5426 .pointer(PointerBuilder(1, ToolType::FINGER).x(250).y(100))
5427 .classification(MotionClassification::MULTI_FINGER_SWIPE)
5428 .build());
5429 mDispatcher->notifyMotion(MotionArgsBuilder(POINTER_2_DOWN, AINPUT_SOURCE_MOUSE)
5430 .pointer(PointerBuilder(0, ToolType::FINGER).x(200).y(100))
5431 .pointer(PointerBuilder(1, ToolType::FINGER).x(250).y(100))
5432 .pointer(PointerBuilder(2, ToolType::FINGER).x(300).y(100))
5433 .classification(MotionClassification::MULTI_FINGER_SWIPE)
5434 .build());
5435
5436 // Move the swipe a bit
5437 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_MOUSE)
5438 .pointer(PointerBuilder(0, ToolType::FINGER).x(200).y(105))
5439 .pointer(PointerBuilder(1, ToolType::FINGER).x(250).y(105))
5440 .pointer(PointerBuilder(2, ToolType::FINGER).x(300).y(105))
5441 .classification(MotionClassification::MULTI_FINGER_SWIPE)
5442 .build());
5443
5444 // End the swipe
5445 mDispatcher->notifyMotion(MotionArgsBuilder(POINTER_2_UP, AINPUT_SOURCE_MOUSE)
5446 .pointer(PointerBuilder(0, ToolType::FINGER).x(200).y(105))
5447 .pointer(PointerBuilder(1, ToolType::FINGER).x(250).y(105))
5448 .pointer(PointerBuilder(2, ToolType::FINGER).x(300).y(105))
5449 .classification(MotionClassification::MULTI_FINGER_SWIPE)
5450 .build());
5451 mDispatcher->notifyMotion(MotionArgsBuilder(POINTER_1_UP, AINPUT_SOURCE_MOUSE)
5452 .pointer(PointerBuilder(0, ToolType::FINGER).x(200).y(105))
5453 .pointer(PointerBuilder(1, ToolType::FINGER).x(250).y(105))
5454 .classification(MotionClassification::MULTI_FINGER_SWIPE)
5455 .build());
5456 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_UP, AINPUT_SOURCE_MOUSE)
5457 .pointer(PointerBuilder(0, ToolType::FINGER).x(200).y(105))
5458 .classification(MotionClassification::MULTI_FINGER_SWIPE)
5459 .build());
5460
5461 window->assertNoEvents();
5462}
5463
Prabir Pradhanb60b1dc2022-03-15 14:02:35 +00005464/**
Siarhei Vishniakouadb9fc92023-05-26 10:46:09 -07005465 * Send a two-pointer gesture to a single window. The window's orientation changes in response to
5466 * the first pointer.
Prabir Pradhan69d00bf2023-06-23 19:55:18 +00005467 * Ensure that the second pointer and the subsequent gesture is correctly delivered to the window.
Siarhei Vishniakouadb9fc92023-05-26 10:46:09 -07005468 */
5469TEST_F(InputDispatcherTest, MultiplePointersWithRotatingWindow) {
5470 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
5471 sp<FakeWindowHandle> window =
5472 sp<FakeWindowHandle>::make(application, mDispatcher, "Window", ADISPLAY_ID_DEFAULT);
5473 window->setFrame(Rect(0, 0, 400, 400));
Siarhei Vishniakou700424c2023-07-18 17:18:42 -07005474 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Siarhei Vishniakouadb9fc92023-05-26 10:46:09 -07005475
5476 const nsecs_t baseTime = systemTime(SYSTEM_TIME_MONOTONIC);
5477 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
5478 .downTime(baseTime + 10)
5479 .eventTime(baseTime + 10)
5480 .pointer(PointerBuilder(0, ToolType::FINGER).x(100).y(100))
5481 .build());
5482
5483 window->consumeMotionEvent(WithMotionAction(ACTION_DOWN));
5484
Siarhei Vishniakouadb9fc92023-05-26 10:46:09 -07005485 // Change the transform so that the orientation is now different from original.
Siarhei Vishniakou700424c2023-07-18 17:18:42 -07005486 window->setWindowTransform(0, -1, 1, 0);
Siarhei Vishniakouadb9fc92023-05-26 10:46:09 -07005487
Siarhei Vishniakou700424c2023-07-18 17:18:42 -07005488 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Siarhei Vishniakouadb9fc92023-05-26 10:46:09 -07005489
Siarhei Vishniakouadb9fc92023-05-26 10:46:09 -07005490 mDispatcher->notifyMotion(MotionArgsBuilder(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
5491 .downTime(baseTime + 10)
5492 .eventTime(baseTime + 30)
5493 .pointer(PointerBuilder(0, ToolType::FINGER).x(100).y(100))
5494 .pointer(PointerBuilder(1, ToolType::FINGER).x(200).y(200))
5495 .build());
5496
Prabir Pradhan69d00bf2023-06-23 19:55:18 +00005497 window->consumeMotionEvent(WithMotionAction(POINTER_1_DOWN));
5498
5499 // Finish the gesture and start a new one. Ensure all events are sent to the window.
Siarhei Vishniakouadb9fc92023-05-26 10:46:09 -07005500 mDispatcher->notifyMotion(MotionArgsBuilder(POINTER_1_UP, AINPUT_SOURCE_TOUCHSCREEN)
5501 .downTime(baseTime + 10)
5502 .eventTime(baseTime + 40)
5503 .pointer(PointerBuilder(0, ToolType::FINGER).x(100).y(100))
5504 .pointer(PointerBuilder(1, ToolType::FINGER).x(200).y(200))
5505 .build());
Prabir Pradhan69d00bf2023-06-23 19:55:18 +00005506
5507 window->consumeMotionEvent(WithMotionAction(POINTER_1_UP));
5508
Siarhei Vishniakouadb9fc92023-05-26 10:46:09 -07005509 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN)
5510 .downTime(baseTime + 10)
5511 .eventTime(baseTime + 50)
5512 .pointer(PointerBuilder(0, ToolType::FINGER).x(100).y(100))
5513 .build());
5514
Prabir Pradhan69d00bf2023-06-23 19:55:18 +00005515 window->consumeMotionEvent(WithMotionAction(ACTION_UP));
5516
Siarhei Vishniakouadb9fc92023-05-26 10:46:09 -07005517 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
5518 .downTime(baseTime + 60)
5519 .eventTime(baseTime + 60)
5520 .pointer(PointerBuilder(0, ToolType::FINGER).x(40).y(40))
5521 .build());
5522
Siarhei Vishniakou700424c2023-07-18 17:18:42 -07005523 window->consumeMotionEvent(WithMotionAction(ACTION_DOWN));
Siarhei Vishniakouadb9fc92023-05-26 10:46:09 -07005524}
5525
5526/**
Hu Guo771a7692023-09-17 20:51:08 +08005527 * When there are multiple screens, such as screen projection to TV or screen recording, if the
5528 * cancel event occurs, the coordinates of the cancel event should be sent to the target screen, and
5529 * its coordinates should be converted by the transform of the windows of target screen.
5530 */
5531TEST_F(InputDispatcherTest, WhenMultiDisplayWindowSameToken_DispatchCancelToTargetDisplay) {
5532 // This case will create a window and a spy window on the default display and mirror
5533 // window on the second display. cancel event is sent through spy window pilferPointers
5534 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
5535
5536 sp<FakeWindowHandle> spyWindowDefaultDisplay =
5537 sp<FakeWindowHandle>::make(application, mDispatcher, "Spy", ADISPLAY_ID_DEFAULT);
5538 spyWindowDefaultDisplay->setTrustedOverlay(true);
5539 spyWindowDefaultDisplay->setSpy(true);
5540
5541 sp<FakeWindowHandle> windowDefaultDisplay =
5542 sp<FakeWindowHandle>::make(application, mDispatcher, "DefaultDisplay",
5543 ADISPLAY_ID_DEFAULT);
5544 windowDefaultDisplay->setWindowTransform(1, 0, 0, 1);
5545
5546 sp<FakeWindowHandle> windowSecondDisplay = windowDefaultDisplay->clone(SECOND_DISPLAY_ID);
5547 windowSecondDisplay->setWindowTransform(2, 0, 0, 2);
5548
5549 // Add the windows to the dispatcher
5550 mDispatcher->onWindowInfosChanged(
5551 {{*spyWindowDefaultDisplay->getInfo(), *windowDefaultDisplay->getInfo(),
5552 *windowSecondDisplay->getInfo()},
5553 {},
5554 0,
5555 0});
5556
5557 // Send down to ADISPLAY_ID_DEFAULT
5558 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
5559 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
5560 {100, 100}))
5561 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
5562
5563 spyWindowDefaultDisplay->consumeMotionDown();
5564 windowDefaultDisplay->consumeMotionDown();
5565
5566 EXPECT_EQ(OK, mDispatcher->pilferPointers(spyWindowDefaultDisplay->getToken()));
5567
5568 // windowDefaultDisplay gets cancel
Siarhei Vishniakoud3061ab2023-12-18 20:41:08 -08005569 std::unique_ptr<MotionEvent> event = windowDefaultDisplay->consumeMotionEvent();
5570 ASSERT_NE(nullptr, event);
5571 EXPECT_EQ(AMOTION_EVENT_ACTION_CANCEL, event->getAction());
Hu Guo771a7692023-09-17 20:51:08 +08005572
Linnan Li13bf76a2024-05-05 19:18:02 +08005573 // The cancel event is sent to windowDefaultDisplay of the ADISPLAY_ID_DEFAULT display, so
5574 // the coordinates of the cancel are converted by windowDefaultDisplay's transform, the x and y
Hu Guo771a7692023-09-17 20:51:08 +08005575 // coordinates are both 100, otherwise if the cancel event is sent to windowSecondDisplay of
5576 // SECOND_DISPLAY_ID, the x and y coordinates are 200
Siarhei Vishniakoud3061ab2023-12-18 20:41:08 -08005577 EXPECT_EQ(100, event->getX(0));
5578 EXPECT_EQ(100, event->getY(0));
Hu Guo771a7692023-09-17 20:51:08 +08005579}
5580
5581/**
Prabir Pradhanc44ce4d2021-10-05 05:26:29 -07005582 * Ensure the correct coordinate spaces are used by InputDispatcher.
5583 *
5584 * InputDispatcher works in the display space, so its coordinate system is relative to the display
5585 * panel. Windows get events in the window space, and get raw coordinates in the logical display
5586 * space.
5587 */
5588class InputDispatcherDisplayProjectionTest : public InputDispatcherTest {
5589public:
5590 void SetUp() override {
5591 InputDispatcherTest::SetUp();
Prabir Pradhan33e3baa2022-12-06 20:30:22 +00005592 removeAllWindowsAndDisplays();
Prabir Pradhanc44ce4d2021-10-05 05:26:29 -07005593 }
5594
Linnan Li13bf76a2024-05-05 19:18:02 +08005595 void addDisplayInfo(ui::LogicalDisplayId displayId, const ui::Transform& transform) {
Prabir Pradhanc44ce4d2021-10-05 05:26:29 -07005596 gui::DisplayInfo info;
5597 info.displayId = displayId;
5598 info.transform = transform;
5599 mDisplayInfos.push_back(std::move(info));
Patrick Williamsd828f302023-04-28 17:52:08 -05005600 mDispatcher->onWindowInfosChanged({mWindowInfos, mDisplayInfos, 0, 0});
Prabir Pradhanc44ce4d2021-10-05 05:26:29 -07005601 }
5602
5603 void addWindow(const sp<WindowInfoHandle>& windowHandle) {
5604 mWindowInfos.push_back(*windowHandle->getInfo());
Patrick Williamsd828f302023-04-28 17:52:08 -05005605 mDispatcher->onWindowInfosChanged({mWindowInfos, mDisplayInfos, 0, 0});
Prabir Pradhanc44ce4d2021-10-05 05:26:29 -07005606 }
5607
Prabir Pradhan33e3baa2022-12-06 20:30:22 +00005608 void removeAllWindowsAndDisplays() {
5609 mDisplayInfos.clear();
5610 mWindowInfos.clear();
5611 }
5612
Prabir Pradhanc44ce4d2021-10-05 05:26:29 -07005613 // Set up a test scenario where the display has a scaled projection and there are two windows
5614 // on the display.
5615 std::pair<sp<FakeWindowHandle>, sp<FakeWindowHandle>> setupScaledDisplayScenario() {
5616 // The display has a projection that has a scale factor of 2 and 4 in the x and y directions
5617 // respectively.
5618 ui::Transform displayTransform;
5619 displayTransform.set(2, 0, 0, 4);
5620 addDisplayInfo(ADISPLAY_ID_DEFAULT, displayTransform);
5621
5622 std::shared_ptr<FakeApplicationHandle> application =
5623 std::make_shared<FakeApplicationHandle>();
5624
5625 // Add two windows to the display. Their frames are represented in the display space.
5626 sp<FakeWindowHandle> firstWindow =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07005627 sp<FakeWindowHandle>::make(application, mDispatcher, "First Window",
5628 ADISPLAY_ID_DEFAULT);
Prabir Pradhanc44ce4d2021-10-05 05:26:29 -07005629 firstWindow->setFrame(Rect(0, 0, 100, 200), displayTransform);
5630 addWindow(firstWindow);
5631
5632 sp<FakeWindowHandle> secondWindow =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07005633 sp<FakeWindowHandle>::make(application, mDispatcher, "Second Window",
5634 ADISPLAY_ID_DEFAULT);
Prabir Pradhanc44ce4d2021-10-05 05:26:29 -07005635 secondWindow->setFrame(Rect(100, 200, 200, 400), displayTransform);
5636 addWindow(secondWindow);
5637 return {std::move(firstWindow), std::move(secondWindow)};
5638 }
5639
5640private:
5641 std::vector<gui::DisplayInfo> mDisplayInfos;
5642 std::vector<gui::WindowInfo> mWindowInfos;
5643};
5644
Prabir Pradhan33e3baa2022-12-06 20:30:22 +00005645TEST_F(InputDispatcherDisplayProjectionTest, HitTestCoordinateSpaceConsistency) {
Prabir Pradhanc44ce4d2021-10-05 05:26:29 -07005646 auto [firstWindow, secondWindow] = setupScaledDisplayScenario();
5647 // Send down to the first window. The point is represented in the display space. The point is
Prabir Pradhan33e3baa2022-12-06 20:30:22 +00005648 // selected so that if the hit test was performed with the point and the bounds being in
5649 // different coordinate spaces, the event would end up in the incorrect window.
Prabir Pradhan678438e2023-04-13 19:32:51 +00005650 mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_DOWN,
5651 AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
5652 {PointF{75, 55}}));
Prabir Pradhanc44ce4d2021-10-05 05:26:29 -07005653
5654 firstWindow->consumeMotionDown();
5655 secondWindow->assertNoEvents();
5656}
5657
5658// Ensure that when a MotionEvent is injected through the InputDispatcher::injectInputEvent() API,
5659// the event should be treated as being in the logical display space.
5660TEST_F(InputDispatcherDisplayProjectionTest, InjectionInLogicalDisplaySpace) {
5661 auto [firstWindow, secondWindow] = setupScaledDisplayScenario();
5662 // Send down to the first window. The point is represented in the logical display space. The
5663 // point is selected so that if the hit test was done in logical display space, then it would
5664 // end up in the incorrect window.
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07005665 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
Prabir Pradhanc44ce4d2021-10-05 05:26:29 -07005666 PointF{75 * 2, 55 * 4});
5667
5668 firstWindow->consumeMotionDown();
5669 secondWindow->assertNoEvents();
5670}
5671
Prabir Pradhandaa2f142021-12-10 09:30:08 +00005672// Ensure that when a MotionEvent that has a custom transform is injected, the post-transformed
5673// event should be treated as being in the logical display space.
5674TEST_F(InputDispatcherDisplayProjectionTest, InjectionWithTransformInLogicalDisplaySpace) {
5675 auto [firstWindow, secondWindow] = setupScaledDisplayScenario();
5676
5677 const std::array<float, 9> matrix = {1.1, 2.2, 3.3, 4.4, 5.5, 6.6, 0.0, 0.0, 1.0};
5678 ui::Transform injectedEventTransform;
5679 injectedEventTransform.set(matrix);
5680 const vec2 expectedPoint{75, 55}; // The injected point in the logical display space.
5681 const vec2 untransformedPoint = injectedEventTransform.inverse().transform(expectedPoint);
5682
5683 MotionEvent event = MotionEventBuilder(AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
5684 .displayId(ADISPLAY_ID_DEFAULT)
5685 .eventTime(systemTime(SYSTEM_TIME_MONOTONIC))
Siarhei Vishniakou6d73f832022-07-21 17:27:03 -07005686 .pointer(PointerBuilder(/*id=*/0, ToolType::FINGER)
Prabir Pradhandaa2f142021-12-10 09:30:08 +00005687 .x(untransformedPoint.x)
5688 .y(untransformedPoint.y))
5689 .build();
5690 event.transform(matrix);
5691
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07005692 injectMotionEvent(*mDispatcher, event, INJECT_EVENT_TIMEOUT,
Prabir Pradhandaa2f142021-12-10 09:30:08 +00005693 InputEventInjectionSync::WAIT_FOR_RESULT);
5694
5695 firstWindow->consumeMotionDown();
5696 secondWindow->assertNoEvents();
5697}
5698
Prabir Pradhanc44ce4d2021-10-05 05:26:29 -07005699TEST_F(InputDispatcherDisplayProjectionTest, WindowGetsEventsInCorrectCoordinateSpace) {
5700 auto [firstWindow, secondWindow] = setupScaledDisplayScenario();
5701
5702 // Send down to the second window.
Prabir Pradhan678438e2023-04-13 19:32:51 +00005703 mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_DOWN,
5704 AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
5705 {PointF{150, 220}}));
Prabir Pradhanc44ce4d2021-10-05 05:26:29 -07005706
5707 firstWindow->assertNoEvents();
Siarhei Vishniakoud3061ab2023-12-18 20:41:08 -08005708 std::unique_ptr<MotionEvent> event = secondWindow->consumeMotionEvent();
5709 ASSERT_NE(nullptr, event);
5710 EXPECT_EQ(AMOTION_EVENT_ACTION_DOWN, event->getAction());
Prabir Pradhanc44ce4d2021-10-05 05:26:29 -07005711
5712 // Ensure that the events from the "getRaw" API are in logical display coordinates.
Siarhei Vishniakoud3061ab2023-12-18 20:41:08 -08005713 EXPECT_EQ(300, event->getRawX(0));
5714 EXPECT_EQ(880, event->getRawY(0));
Prabir Pradhanc44ce4d2021-10-05 05:26:29 -07005715
5716 // Ensure that the x and y values are in the window's coordinate space.
5717 // The left-top of the second window is at (100, 200) in display space, which is (200, 800) in
5718 // the logical display space. This will be the origin of the window space.
Siarhei Vishniakoud3061ab2023-12-18 20:41:08 -08005719 EXPECT_EQ(100, event->getX(0));
5720 EXPECT_EQ(80, event->getY(0));
Prabir Pradhanc44ce4d2021-10-05 05:26:29 -07005721}
5722
Prabir Pradhan112b1ad2023-09-21 09:53:53 +00005723TEST_F(InputDispatcherDisplayProjectionTest, CancelMotionWithCorrectCoordinates) {
5724 auto [firstWindow, secondWindow] = setupScaledDisplayScenario();
5725 // The monitor will always receive events in the logical display's coordinate space, because
5726 // it does not have a window.
Prabir Pradhanfb549072023-10-05 19:17:36 +00005727 FakeMonitorReceiver monitor{*mDispatcher, "Monitor", ADISPLAY_ID_DEFAULT};
Prabir Pradhan112b1ad2023-09-21 09:53:53 +00005728
5729 // Send down to the first window.
5730 mDispatcher->notifyMotion(generateMotionArgs(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN,
5731 ADISPLAY_ID_DEFAULT, {PointF{50, 100}}));
5732 firstWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithCoords(100, 400)));
5733 monitor.consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithCoords(100, 400)));
5734
5735 // Second pointer goes down on second window.
5736 mDispatcher->notifyMotion(generateMotionArgs(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN,
5737 ADISPLAY_ID_DEFAULT,
5738 {PointF{50, 100}, PointF{150, 220}}));
5739 secondWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithCoords(100, 80)));
5740 const std::map<int32_t, PointF> expectedMonitorPointers{{0, PointF{100, 400}},
5741 {1, PointF{300, 880}}};
5742 monitor.consumeMotionEvent(
5743 AllOf(WithMotionAction(POINTER_1_DOWN), WithPointers(expectedMonitorPointers)));
5744
5745 mDispatcher->cancelCurrentTouch();
5746
5747 firstWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_CANCEL), WithCoords(100, 400)));
5748 secondWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_CANCEL), WithCoords(100, 80)));
5749 monitor.consumeMotionEvent(
5750 AllOf(WithMotionAction(ACTION_CANCEL), WithPointers(expectedMonitorPointers)));
5751}
5752
Prabir Pradhan1c29a092023-09-21 10:29:29 +00005753TEST_F(InputDispatcherDisplayProjectionTest, SynthesizeDownWithCorrectCoordinates) {
5754 auto [firstWindow, secondWindow] = setupScaledDisplayScenario();
5755
5756 // Send down to the first window.
5757 mDispatcher->notifyMotion(generateMotionArgs(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN,
5758 ADISPLAY_ID_DEFAULT, {PointF{50, 100}}));
5759 firstWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithCoords(100, 400)));
5760
5761 // The pointer is transferred to the second window, and the second window receives it in the
5762 // correct coordinate space.
Prabir Pradhan367f3432024-02-13 23:05:58 +00005763 mDispatcher->transferTouchGesture(firstWindow->getToken(), secondWindow->getToken());
Prabir Pradhan1c29a092023-09-21 10:29:29 +00005764 firstWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_CANCEL), WithCoords(100, 400)));
5765 secondWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithCoords(-100, -400)));
5766}
5767
Prabir Pradhan0dfcac72023-10-05 20:04:21 +00005768TEST_F(InputDispatcherDisplayProjectionTest, SynthesizeHoverEnterExitWithCorrectCoordinates) {
5769 auto [firstWindow, secondWindow] = setupScaledDisplayScenario();
5770
5771 // Send hover move to the second window, and ensure it shows up as hover enter.
5772 mDispatcher->notifyMotion(generateMotionArgs(ACTION_HOVER_MOVE, AINPUT_SOURCE_STYLUS,
5773 ADISPLAY_ID_DEFAULT, {PointF{150, 220}}));
5774 secondWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_HOVER_ENTER),
5775 WithCoords(100, 80), WithRawCoords(300, 880)));
5776
5777 // Touch down at the same location and ensure a hover exit is synthesized.
5778 mDispatcher->notifyMotion(generateMotionArgs(ACTION_DOWN, AINPUT_SOURCE_STYLUS,
5779 ADISPLAY_ID_DEFAULT, {PointF{150, 220}}));
5780 secondWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_HOVER_EXIT), WithCoords(100, 80),
5781 WithRawCoords(300, 880)));
5782 secondWindow->consumeMotionEvent(
5783 AllOf(WithMotionAction(ACTION_DOWN), WithCoords(100, 80), WithRawCoords(300, 880)));
5784 secondWindow->assertNoEvents();
5785 firstWindow->assertNoEvents();
5786}
5787
Prabir Pradhan453ae732023-10-13 14:30:14 +00005788// Same as above, but while the window is being mirrored.
5789TEST_F(InputDispatcherDisplayProjectionTest,
5790 SynthesizeHoverEnterExitWithCorrectCoordinatesWhenMirrored) {
5791 auto [firstWindow, secondWindow] = setupScaledDisplayScenario();
5792
5793 const std::array<float, 9> matrix = {1.1, 2.2, 3.3, 4.4, 5.5, 6.6, 0.0, 0.0, 1.0};
5794 ui::Transform secondDisplayTransform;
5795 secondDisplayTransform.set(matrix);
5796 addDisplayInfo(SECOND_DISPLAY_ID, secondDisplayTransform);
5797
5798 sp<FakeWindowHandle> secondWindowClone = secondWindow->clone(SECOND_DISPLAY_ID);
5799 secondWindowClone->setWindowTransform(1.1, 2.2, 3.3, 4.4);
5800 addWindow(secondWindowClone);
5801
5802 // Send hover move to the second window, and ensure it shows up as hover enter.
5803 mDispatcher->notifyMotion(generateMotionArgs(ACTION_HOVER_MOVE, AINPUT_SOURCE_STYLUS,
5804 ADISPLAY_ID_DEFAULT, {PointF{150, 220}}));
5805 secondWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_HOVER_ENTER),
5806 WithCoords(100, 80), WithRawCoords(300, 880)));
5807
5808 // Touch down at the same location and ensure a hover exit is synthesized for the correct
5809 // display.
5810 mDispatcher->notifyMotion(generateMotionArgs(ACTION_DOWN, AINPUT_SOURCE_STYLUS,
5811 ADISPLAY_ID_DEFAULT, {PointF{150, 220}}));
5812 secondWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_HOVER_EXIT), WithCoords(100, 80),
5813 WithRawCoords(300, 880)));
5814 secondWindow->consumeMotionEvent(
5815 AllOf(WithMotionAction(ACTION_DOWN), WithCoords(100, 80), WithRawCoords(300, 880)));
5816 secondWindow->assertNoEvents();
5817 firstWindow->assertNoEvents();
5818}
5819
Prabir Pradhan0dfcac72023-10-05 20:04:21 +00005820TEST_F(InputDispatcherDisplayProjectionTest, SynthesizeHoverCancelationWithCorrectCoordinates) {
5821 auto [firstWindow, secondWindow] = setupScaledDisplayScenario();
5822
5823 // Send hover enter to second window
5824 mDispatcher->notifyMotion(generateMotionArgs(ACTION_HOVER_ENTER, AINPUT_SOURCE_STYLUS,
5825 ADISPLAY_ID_DEFAULT, {PointF{150, 220}}));
5826 secondWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_HOVER_ENTER),
5827 WithCoords(100, 80), WithRawCoords(300, 880)));
5828
5829 mDispatcher->cancelCurrentTouch();
5830
5831 secondWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_HOVER_EXIT), WithCoords(100, 80),
5832 WithRawCoords(300, 880)));
5833 secondWindow->assertNoEvents();
5834 firstWindow->assertNoEvents();
5835}
5836
Prabir Pradhan453ae732023-10-13 14:30:14 +00005837// Same as above, but while the window is being mirrored.
Prabir Pradhan16463382023-10-12 23:03:19 +00005838TEST_F(InputDispatcherDisplayProjectionTest,
5839 SynthesizeHoverCancelationWithCorrectCoordinatesWhenMirrored) {
5840 auto [firstWindow, secondWindow] = setupScaledDisplayScenario();
5841
5842 const std::array<float, 9> matrix = {1.1, 2.2, 3.3, 4.4, 5.5, 6.6, 0.0, 0.0, 1.0};
5843 ui::Transform secondDisplayTransform;
5844 secondDisplayTransform.set(matrix);
5845 addDisplayInfo(SECOND_DISPLAY_ID, secondDisplayTransform);
5846
5847 sp<FakeWindowHandle> secondWindowClone = secondWindow->clone(SECOND_DISPLAY_ID);
5848 secondWindowClone->setWindowTransform(1.1, 2.2, 3.3, 4.4);
5849 addWindow(secondWindowClone);
5850
5851 // Send hover enter to second window
5852 mDispatcher->notifyMotion(generateMotionArgs(ACTION_HOVER_ENTER, AINPUT_SOURCE_STYLUS,
5853 ADISPLAY_ID_DEFAULT, {PointF{150, 220}}));
5854 secondWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_HOVER_ENTER),
5855 WithCoords(100, 80), WithRawCoords(300, 880),
5856 WithDisplayId(ADISPLAY_ID_DEFAULT)));
5857
5858 mDispatcher->cancelCurrentTouch();
5859
5860 // Ensure the cancelation happens with the correct displayId and the correct coordinates.
5861 secondWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_HOVER_EXIT), WithCoords(100, 80),
5862 WithRawCoords(300, 880),
5863 WithDisplayId(ADISPLAY_ID_DEFAULT)));
5864 secondWindow->assertNoEvents();
5865 firstWindow->assertNoEvents();
5866}
5867
Prabir Pradhan33e3baa2022-12-06 20:30:22 +00005868/** Ensure consistent behavior of InputDispatcher in all orientations. */
5869class InputDispatcherDisplayOrientationFixture
5870 : public InputDispatcherDisplayProjectionTest,
5871 public ::testing::WithParamInterface<ui::Rotation> {};
5872
5873// This test verifies the touchable region of a window for all rotations of the display by tapping
5874// in different locations on the display, specifically points close to the four corners of a
5875// window.
5876TEST_P(InputDispatcherDisplayOrientationFixture, HitTestInDifferentOrientations) {
5877 constexpr static int32_t displayWidth = 400;
5878 constexpr static int32_t displayHeight = 800;
5879
5880 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
5881
5882 const auto rotation = GetParam();
5883
5884 // Set up the display with the specified rotation.
5885 const bool isRotated = rotation == ui::ROTATION_90 || rotation == ui::ROTATION_270;
5886 const int32_t logicalDisplayWidth = isRotated ? displayHeight : displayWidth;
5887 const int32_t logicalDisplayHeight = isRotated ? displayWidth : displayHeight;
5888 const ui::Transform displayTransform(ui::Transform::toRotationFlags(rotation),
5889 logicalDisplayWidth, logicalDisplayHeight);
5890 addDisplayInfo(ADISPLAY_ID_DEFAULT, displayTransform);
5891
5892 // Create a window with its bounds determined in the logical display.
5893 const Rect frameInLogicalDisplay(100, 100, 200, 300);
5894 const Rect frameInDisplay = displayTransform.inverse().transform(frameInLogicalDisplay);
5895 sp<FakeWindowHandle> window =
5896 sp<FakeWindowHandle>::make(application, mDispatcher, "Window", ADISPLAY_ID_DEFAULT);
5897 window->setFrame(frameInDisplay, displayTransform);
5898 addWindow(window);
5899
5900 // The following points in logical display space should be inside the window.
5901 static const std::array<vec2, 4> insidePoints{
5902 {{100, 100}, {199.99, 100}, {100, 299.99}, {199.99, 299.99}}};
5903 for (const auto pointInsideWindow : insidePoints) {
5904 const vec2 p = displayTransform.inverse().transform(pointInsideWindow);
5905 const PointF pointInDisplaySpace{p.x, p.y};
Prabir Pradhan678438e2023-04-13 19:32:51 +00005906 mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_DOWN,
5907 AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
5908 {pointInDisplaySpace}));
Prabir Pradhan33e3baa2022-12-06 20:30:22 +00005909 window->consumeMotionDown();
5910
Prabir Pradhan678438e2023-04-13 19:32:51 +00005911 mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_UP,
5912 AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
5913 {pointInDisplaySpace}));
Prabir Pradhan33e3baa2022-12-06 20:30:22 +00005914 window->consumeMotionUp();
5915 }
5916
5917 // The following points in logical display space should be outside the window.
5918 static const std::array<vec2, 5> outsidePoints{
5919 {{200, 100}, {100, 300}, {200, 300}, {100, 99.99}, {99.99, 100}}};
5920 for (const auto pointOutsideWindow : outsidePoints) {
5921 const vec2 p = displayTransform.inverse().transform(pointOutsideWindow);
5922 const PointF pointInDisplaySpace{p.x, p.y};
Prabir Pradhan678438e2023-04-13 19:32:51 +00005923 mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_DOWN,
5924 AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
5925 {pointInDisplaySpace}));
Prabir Pradhan33e3baa2022-12-06 20:30:22 +00005926
Prabir Pradhan678438e2023-04-13 19:32:51 +00005927 mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_UP,
5928 AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
5929 {pointInDisplaySpace}));
Prabir Pradhan33e3baa2022-12-06 20:30:22 +00005930 }
5931 window->assertNoEvents();
5932}
5933
Linnan Li5e5645e2024-03-05 14:43:05 +00005934// This test verifies the occlusion detection for all rotations of the display by tapping
5935// in different locations on the display, specifically points close to the four corners of a
5936// window.
5937TEST_P(InputDispatcherDisplayOrientationFixture, BlockUntrustClickInDifferentOrientations) {
5938 constexpr static int32_t displayWidth = 400;
5939 constexpr static int32_t displayHeight = 800;
5940
5941 std::shared_ptr<FakeApplicationHandle> untrustedWindowApplication =
5942 std::make_shared<FakeApplicationHandle>();
5943 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
5944
5945 const auto rotation = GetParam();
5946
5947 // Set up the display with the specified rotation.
5948 const bool isRotated = rotation == ui::ROTATION_90 || rotation == ui::ROTATION_270;
5949 const int32_t logicalDisplayWidth = isRotated ? displayHeight : displayWidth;
5950 const int32_t logicalDisplayHeight = isRotated ? displayWidth : displayHeight;
5951 const ui::Transform displayTransform(ui::Transform::toRotationFlags(rotation),
5952 logicalDisplayWidth, logicalDisplayHeight);
5953 addDisplayInfo(ADISPLAY_ID_DEFAULT, displayTransform);
5954
5955 // Create a window that not trusted.
5956 const Rect untrustedWindowFrameInLogicalDisplay(100, 100, 200, 300);
5957
5958 const Rect untrustedWindowFrameInDisplay =
5959 displayTransform.inverse().transform(untrustedWindowFrameInLogicalDisplay);
5960
5961 sp<FakeWindowHandle> untrustedWindow =
5962 sp<FakeWindowHandle>::make(untrustedWindowApplication, mDispatcher, "UntrustedWindow",
5963 ADISPLAY_ID_DEFAULT);
5964 untrustedWindow->setFrame(untrustedWindowFrameInDisplay, displayTransform);
5965 untrustedWindow->setTrustedOverlay(false);
5966 untrustedWindow->setTouchOcclusionMode(TouchOcclusionMode::BLOCK_UNTRUSTED);
5967 untrustedWindow->setTouchable(false);
5968 untrustedWindow->setAlpha(1.0f);
5969 untrustedWindow->setOwnerInfo(gui::Pid{1}, gui::Uid{101});
5970 addWindow(untrustedWindow);
5971
5972 // Create a simple app window below the untrusted window.
5973 const Rect simpleAppWindowFrameInLogicalDisplay(0, 0, 300, 600);
5974 const Rect simpleAppWindowFrameInDisplay =
5975 displayTransform.inverse().transform(simpleAppWindowFrameInLogicalDisplay);
5976
5977 sp<FakeWindowHandle> simpleAppWindow =
5978 sp<FakeWindowHandle>::make(application, mDispatcher, "SimpleAppWindow",
5979 ADISPLAY_ID_DEFAULT);
5980 simpleAppWindow->setFrame(simpleAppWindowFrameInDisplay, displayTransform);
5981 simpleAppWindow->setOwnerInfo(gui::Pid{2}, gui::Uid{202});
5982 addWindow(simpleAppWindow);
5983
5984 // The following points in logical display space should be inside the untrusted window, so
5985 // the simple window could not receive events that coordinate is these point.
5986 static const std::array<vec2, 4> untrustedPoints{
5987 {{100, 100}, {199.99, 100}, {100, 299.99}, {199.99, 299.99}}};
5988
5989 for (const auto untrustedPoint : untrustedPoints) {
5990 const vec2 p = displayTransform.inverse().transform(untrustedPoint);
5991 const PointF pointInDisplaySpace{p.x, p.y};
5992 mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_DOWN,
5993 AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
5994 {pointInDisplaySpace}));
5995 mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_UP,
5996 AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
5997 {pointInDisplaySpace}));
5998 }
5999 untrustedWindow->assertNoEvents();
6000 simpleAppWindow->assertNoEvents();
6001 // The following points in logical display space should be outside the untrusted window, so
6002 // the simple window should receive events that coordinate is these point.
6003 static const std::array<vec2, 5> trustedPoints{
6004 {{200, 100}, {100, 300}, {200, 300}, {100, 99.99}, {99.99, 100}}};
6005 for (const auto trustedPoint : trustedPoints) {
6006 const vec2 p = displayTransform.inverse().transform(trustedPoint);
6007 const PointF pointInDisplaySpace{p.x, p.y};
6008 mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_DOWN,
6009 AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
6010 {pointInDisplaySpace}));
6011 simpleAppWindow->consumeMotionDown(ADISPLAY_ID_DEFAULT,
6012 AMOTION_EVENT_FLAG_WINDOW_IS_PARTIALLY_OBSCURED);
6013 mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_UP,
6014 AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
6015 {pointInDisplaySpace}));
6016 simpleAppWindow->consumeMotionUp(ADISPLAY_ID_DEFAULT,
6017 AMOTION_EVENT_FLAG_WINDOW_IS_PARTIALLY_OBSCURED);
6018 }
6019 untrustedWindow->assertNoEvents();
6020}
6021
Prabir Pradhan33e3baa2022-12-06 20:30:22 +00006022// Run the precision tests for all rotations.
6023INSTANTIATE_TEST_SUITE_P(InputDispatcherDisplayOrientationTests,
6024 InputDispatcherDisplayOrientationFixture,
6025 ::testing::Values(ui::ROTATION_0, ui::ROTATION_90, ui::ROTATION_180,
6026 ui::ROTATION_270),
6027 [](const testing::TestParamInfo<ui::Rotation>& testParamInfo) {
6028 return ftl::enum_string(testParamInfo.param);
6029 });
6030
Siarhei Vishniakou18050092021-09-01 13:32:49 -07006031using TransferFunction = std::function<bool(const std::unique_ptr<InputDispatcher>& dispatcher,
6032 sp<IBinder>, sp<IBinder>)>;
Siarhei Vishniakoud0c6bc82021-03-13 03:14:52 +00006033
6034class TransferTouchFixture : public InputDispatcherTest,
6035 public ::testing::WithParamInterface<TransferFunction> {};
6036
6037TEST_P(TransferTouchFixture, TransferTouch_OnePointer) {
Chris Yea209fde2020-07-22 13:54:51 -07006038 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
Svet Ganov5d3bc372020-01-26 23:11:07 -08006039
6040 // Create a couple of windows
Siarhei Vishniakou870ecec2020-12-09 08:07:46 -10006041 sp<FakeWindowHandle> firstWindow =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07006042 sp<FakeWindowHandle>::make(application, mDispatcher, "First Window",
6043 ADISPLAY_ID_DEFAULT);
Arthur Hungc539dbb2022-12-08 07:45:36 +00006044 firstWindow->setDupTouchToWallpaper(true);
Siarhei Vishniakou870ecec2020-12-09 08:07:46 -10006045 sp<FakeWindowHandle> secondWindow =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07006046 sp<FakeWindowHandle>::make(application, mDispatcher, "Second Window",
6047 ADISPLAY_ID_DEFAULT);
Arthur Hungc539dbb2022-12-08 07:45:36 +00006048 sp<FakeWindowHandle> wallpaper =
6049 sp<FakeWindowHandle>::make(application, mDispatcher, "Wallpaper", ADISPLAY_ID_DEFAULT);
6050 wallpaper->setIsWallpaper(true);
Prabir Pradhan65455c72024-02-13 21:46:41 +00006051 // Add the windows to the dispatcher, and ensure the first window is focused
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07006052 mDispatcher->onWindowInfosChanged(
6053 {{*firstWindow->getInfo(), *secondWindow->getInfo(), *wallpaper->getInfo()}, {}, 0, 0});
Prabir Pradhan65455c72024-02-13 21:46:41 +00006054 setFocusedWindow(firstWindow);
6055 firstWindow->consumeFocusEvent(true);
Svet Ganov5d3bc372020-01-26 23:11:07 -08006056
6057 // Send down to the first window
Prabir Pradhan678438e2023-04-13 19:32:51 +00006058 mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_DOWN,
6059 AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT));
Arthur Hungc539dbb2022-12-08 07:45:36 +00006060
Svet Ganov5d3bc372020-01-26 23:11:07 -08006061 // Only the first window should get the down event
6062 firstWindow->consumeMotionDown();
6063 secondWindow->assertNoEvents();
Linnan Li72352222024-04-12 18:55:57 +08006064 wallpaper->consumeMotionDown(ADISPLAY_ID_DEFAULT, EXPECTED_WALLPAPER_FLAGS);
Prabir Pradhan65455c72024-02-13 21:46:41 +00006065 // Dispatcher reports pointer down outside focus for the wallpaper
6066 mFakePolicy->assertOnPointerDownEquals(wallpaper->getToken());
Svet Ganov5d3bc372020-01-26 23:11:07 -08006067
Siarhei Vishniakoud0c6bc82021-03-13 03:14:52 +00006068 // Transfer touch to the second window
6069 TransferFunction f = GetParam();
6070 const bool success = f(mDispatcher, firstWindow->getToken(), secondWindow->getToken());
6071 ASSERT_TRUE(success);
Svet Ganov5d3bc372020-01-26 23:11:07 -08006072 // The first window gets cancel and the second gets down
6073 firstWindow->consumeMotionCancel();
Prabir Pradhan65455c72024-02-13 21:46:41 +00006074 secondWindow->consumeMotionDown(ADISPLAY_ID_DEFAULT, AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
Linnan Li72352222024-04-12 18:55:57 +08006075 wallpaper->consumeMotionCancel(ADISPLAY_ID_DEFAULT, EXPECTED_WALLPAPER_FLAGS);
Prabir Pradhan65455c72024-02-13 21:46:41 +00006076 // There should not be any changes to the focused window when transferring touch
6077 ASSERT_NO_FATAL_FAILURE(mFakePolicy->assertOnPointerDownWasNotCalled());
Svet Ganov5d3bc372020-01-26 23:11:07 -08006078
6079 // Send up event to the second window
Prabir Pradhan678438e2023-04-13 19:32:51 +00006080 mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN,
6081 ADISPLAY_ID_DEFAULT));
Prabir Pradhan65455c72024-02-13 21:46:41 +00006082 // The first window gets no events and the second gets up
Svet Ganov5d3bc372020-01-26 23:11:07 -08006083 firstWindow->assertNoEvents();
Prabir Pradhan65455c72024-02-13 21:46:41 +00006084 secondWindow->consumeMotionUp(ADISPLAY_ID_DEFAULT, AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
Arthur Hungc539dbb2022-12-08 07:45:36 +00006085 wallpaper->assertNoEvents();
Svet Ganov5d3bc372020-01-26 23:11:07 -08006086}
6087
Siarhei Vishniakou7ae7afd2022-03-31 15:26:13 -07006088/**
Prabir Pradhan367f3432024-02-13 23:05:58 +00006089 * When 'transferTouchGesture' API is invoked, dispatcher needs to find the "best" window to take
6090 * touch from. When we have spy windows, there are several windows to choose from: either spy, or
6091 * the 'real' (non-spy) window. Always prefer the 'real' window because that's what would be most
Siarhei Vishniakou7ae7afd2022-03-31 15:26:13 -07006092 * natural to the user.
6093 * In this test, we are sending a pointer to both spy window and first window. We then try to
6094 * transfer touch to the second window. The dispatcher should identify the first window as the
6095 * one that should lose the gesture, and therefore the action should be to move the gesture from
6096 * the first window to the second.
Prabir Pradhan367f3432024-02-13 23:05:58 +00006097 * The main goal here is to test the behaviour of 'transferTouchGesture' API, but it's still valid
6098 * to test the other API, as well.
Siarhei Vishniakou7ae7afd2022-03-31 15:26:13 -07006099 */
6100TEST_P(TransferTouchFixture, TransferTouch_MultipleWindowsWithSpy) {
6101 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
6102
6103 // Create a couple of windows + a spy window
6104 sp<FakeWindowHandle> spyWindow =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07006105 sp<FakeWindowHandle>::make(application, mDispatcher, "Spy", ADISPLAY_ID_DEFAULT);
Siarhei Vishniakou7ae7afd2022-03-31 15:26:13 -07006106 spyWindow->setTrustedOverlay(true);
6107 spyWindow->setSpy(true);
6108 sp<FakeWindowHandle> firstWindow =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07006109 sp<FakeWindowHandle>::make(application, mDispatcher, "First", ADISPLAY_ID_DEFAULT);
Siarhei Vishniakou7ae7afd2022-03-31 15:26:13 -07006110 sp<FakeWindowHandle> secondWindow =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07006111 sp<FakeWindowHandle>::make(application, mDispatcher, "Second", ADISPLAY_ID_DEFAULT);
Siarhei Vishniakou7ae7afd2022-03-31 15:26:13 -07006112
6113 // Add the windows to the dispatcher
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07006114 mDispatcher->onWindowInfosChanged(
6115 {{*spyWindow->getInfo(), *firstWindow->getInfo(), *secondWindow->getInfo()}, {}, 0, 0});
Siarhei Vishniakou7ae7afd2022-03-31 15:26:13 -07006116
6117 // Send down to the first window
Prabir Pradhan678438e2023-04-13 19:32:51 +00006118 mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_DOWN,
6119 AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT));
Siarhei Vishniakou7ae7afd2022-03-31 15:26:13 -07006120 // Only the first window and spy should get the down event
6121 spyWindow->consumeMotionDown();
6122 firstWindow->consumeMotionDown();
6123
6124 // Transfer touch to the second window. Non-spy window should be preferred over the spy window
Prabir Pradhan367f3432024-02-13 23:05:58 +00006125 // if f === 'transferTouchGesture'.
Siarhei Vishniakou7ae7afd2022-03-31 15:26:13 -07006126 TransferFunction f = GetParam();
6127 const bool success = f(mDispatcher, firstWindow->getToken(), secondWindow->getToken());
6128 ASSERT_TRUE(success);
6129 // The first window gets cancel and the second gets down
6130 firstWindow->consumeMotionCancel();
Prabir Pradhan65455c72024-02-13 21:46:41 +00006131 secondWindow->consumeMotionDown(ADISPLAY_ID_DEFAULT, AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
Siarhei Vishniakou7ae7afd2022-03-31 15:26:13 -07006132
6133 // Send up event to the second window
Prabir Pradhan678438e2023-04-13 19:32:51 +00006134 mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN,
6135 ADISPLAY_ID_DEFAULT));
Siarhei Vishniakou7ae7afd2022-03-31 15:26:13 -07006136 // The first window gets no events and the second+spy get up
6137 firstWindow->assertNoEvents();
6138 spyWindow->consumeMotionUp();
Prabir Pradhan65455c72024-02-13 21:46:41 +00006139 secondWindow->consumeMotionUp(ADISPLAY_ID_DEFAULT, AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
Siarhei Vishniakou7ae7afd2022-03-31 15:26:13 -07006140}
6141
Siarhei Vishniakoud0c6bc82021-03-13 03:14:52 +00006142TEST_P(TransferTouchFixture, TransferTouch_TwoPointersNonSplitTouch) {
Chris Yea209fde2020-07-22 13:54:51 -07006143 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
Svet Ganov5d3bc372020-01-26 23:11:07 -08006144
6145 PointF touchPoint = {10, 10};
6146
6147 // Create a couple of windows
Siarhei Vishniakou870ecec2020-12-09 08:07:46 -10006148 sp<FakeWindowHandle> firstWindow =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07006149 sp<FakeWindowHandle>::make(application, mDispatcher, "First Window",
6150 ADISPLAY_ID_DEFAULT);
Prabir Pradhan76bdecb2022-01-31 11:14:15 -08006151 firstWindow->setPreventSplitting(true);
Siarhei Vishniakou870ecec2020-12-09 08:07:46 -10006152 sp<FakeWindowHandle> secondWindow =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07006153 sp<FakeWindowHandle>::make(application, mDispatcher, "Second Window",
6154 ADISPLAY_ID_DEFAULT);
Prabir Pradhan76bdecb2022-01-31 11:14:15 -08006155 secondWindow->setPreventSplitting(true);
Svet Ganov5d3bc372020-01-26 23:11:07 -08006156
6157 // Add the windows to the dispatcher
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07006158 mDispatcher->onWindowInfosChanged(
6159 {{*firstWindow->getInfo(), *secondWindow->getInfo()}, {}, 0, 0});
Svet Ganov5d3bc372020-01-26 23:11:07 -08006160
6161 // Send down to the first window
Prabir Pradhan678438e2023-04-13 19:32:51 +00006162 mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_DOWN,
6163 AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
6164 {touchPoint}));
Svet Ganov5d3bc372020-01-26 23:11:07 -08006165 // Only the first window should get the down event
6166 firstWindow->consumeMotionDown();
6167 secondWindow->assertNoEvents();
6168
6169 // Send pointer down to the first window
Prabir Pradhan678438e2023-04-13 19:32:51 +00006170 mDispatcher->notifyMotion(generateMotionArgs(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN,
6171 ADISPLAY_ID_DEFAULT, {touchPoint, touchPoint}));
Svet Ganov5d3bc372020-01-26 23:11:07 -08006172 // Only the first window should get the pointer down event
6173 firstWindow->consumeMotionPointerDown(1);
6174 secondWindow->assertNoEvents();
6175
6176 // Transfer touch focus to the second window
Siarhei Vishniakoud0c6bc82021-03-13 03:14:52 +00006177 TransferFunction f = GetParam();
6178 bool success = f(mDispatcher, firstWindow->getToken(), secondWindow->getToken());
6179 ASSERT_TRUE(success);
Svet Ganov5d3bc372020-01-26 23:11:07 -08006180 // The first window gets cancel and the second gets down and pointer down
6181 firstWindow->consumeMotionCancel();
Prabir Pradhan65455c72024-02-13 21:46:41 +00006182 secondWindow->consumeMotionDown(ADISPLAY_ID_DEFAULT, AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
6183 secondWindow->consumeMotionPointerDown(1, ADISPLAY_ID_DEFAULT,
6184 AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
Svet Ganov5d3bc372020-01-26 23:11:07 -08006185
6186 // Send pointer up to the second window
Prabir Pradhan678438e2023-04-13 19:32:51 +00006187 mDispatcher->notifyMotion(generateMotionArgs(POINTER_1_UP, AINPUT_SOURCE_TOUCHSCREEN,
6188 ADISPLAY_ID_DEFAULT, {touchPoint, touchPoint}));
Svet Ganov5d3bc372020-01-26 23:11:07 -08006189 // The first window gets nothing and the second gets pointer up
6190 firstWindow->assertNoEvents();
Prabir Pradhan65455c72024-02-13 21:46:41 +00006191 secondWindow->consumeMotionPointerUp(1, ADISPLAY_ID_DEFAULT,
6192 AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
Svet Ganov5d3bc372020-01-26 23:11:07 -08006193
6194 // Send up event to the second window
Prabir Pradhan678438e2023-04-13 19:32:51 +00006195 mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN,
6196 ADISPLAY_ID_DEFAULT));
Svet Ganov5d3bc372020-01-26 23:11:07 -08006197 // The first window gets nothing and the second gets up
6198 firstWindow->assertNoEvents();
Prabir Pradhan65455c72024-02-13 21:46:41 +00006199 secondWindow->consumeMotionUp(ADISPLAY_ID_DEFAULT, AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
Svet Ganov5d3bc372020-01-26 23:11:07 -08006200}
6201
Arthur Hungc539dbb2022-12-08 07:45:36 +00006202TEST_P(TransferTouchFixture, TransferTouch_MultipleWallpapers) {
6203 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
6204
6205 // Create a couple of windows
6206 sp<FakeWindowHandle> firstWindow =
6207 sp<FakeWindowHandle>::make(application, mDispatcher, "First Window",
6208 ADISPLAY_ID_DEFAULT);
6209 firstWindow->setDupTouchToWallpaper(true);
6210 sp<FakeWindowHandle> secondWindow =
6211 sp<FakeWindowHandle>::make(application, mDispatcher, "Second Window",
6212 ADISPLAY_ID_DEFAULT);
6213 secondWindow->setDupTouchToWallpaper(true);
6214
6215 sp<FakeWindowHandle> wallpaper1 =
6216 sp<FakeWindowHandle>::make(application, mDispatcher, "Wallpaper1", ADISPLAY_ID_DEFAULT);
6217 wallpaper1->setIsWallpaper(true);
6218
6219 sp<FakeWindowHandle> wallpaper2 =
6220 sp<FakeWindowHandle>::make(application, mDispatcher, "Wallpaper2", ADISPLAY_ID_DEFAULT);
6221 wallpaper2->setIsWallpaper(true);
6222 // Add the windows to the dispatcher
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07006223 mDispatcher->onWindowInfosChanged({{*firstWindow->getInfo(), *wallpaper1->getInfo(),
6224 *secondWindow->getInfo(), *wallpaper2->getInfo()},
6225 {},
6226 0,
6227 0});
Arthur Hungc539dbb2022-12-08 07:45:36 +00006228
6229 // Send down to the first window
Prabir Pradhan678438e2023-04-13 19:32:51 +00006230 mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_DOWN,
6231 AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT));
Arthur Hungc539dbb2022-12-08 07:45:36 +00006232
6233 // Only the first window should get the down event
6234 firstWindow->consumeMotionDown();
6235 secondWindow->assertNoEvents();
Linnan Li72352222024-04-12 18:55:57 +08006236 wallpaper1->consumeMotionDown(ADISPLAY_ID_DEFAULT, EXPECTED_WALLPAPER_FLAGS);
Arthur Hungc539dbb2022-12-08 07:45:36 +00006237 wallpaper2->assertNoEvents();
6238
6239 // Transfer touch focus to the second window
6240 TransferFunction f = GetParam();
6241 bool success = f(mDispatcher, firstWindow->getToken(), secondWindow->getToken());
6242 ASSERT_TRUE(success);
6243
6244 // The first window gets cancel and the second gets down
6245 firstWindow->consumeMotionCancel();
Prabir Pradhan65455c72024-02-13 21:46:41 +00006246 secondWindow->consumeMotionDown(ADISPLAY_ID_DEFAULT, AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
Linnan Li72352222024-04-12 18:55:57 +08006247 wallpaper1->consumeMotionCancel(ADISPLAY_ID_DEFAULT, EXPECTED_WALLPAPER_FLAGS);
Prabir Pradhan65455c72024-02-13 21:46:41 +00006248 wallpaper2->consumeMotionDown(ADISPLAY_ID_DEFAULT,
Linnan Li72352222024-04-12 18:55:57 +08006249 EXPECTED_WALLPAPER_FLAGS | AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
Arthur Hungc539dbb2022-12-08 07:45:36 +00006250
6251 // Send up event to the second window
Prabir Pradhan678438e2023-04-13 19:32:51 +00006252 mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN,
6253 ADISPLAY_ID_DEFAULT));
Arthur Hungc539dbb2022-12-08 07:45:36 +00006254 // The first window gets no events and the second gets up
6255 firstWindow->assertNoEvents();
Prabir Pradhan65455c72024-02-13 21:46:41 +00006256 secondWindow->consumeMotionUp(ADISPLAY_ID_DEFAULT, AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
Arthur Hungc539dbb2022-12-08 07:45:36 +00006257 wallpaper1->assertNoEvents();
Prabir Pradhan65455c72024-02-13 21:46:41 +00006258 wallpaper2->consumeMotionUp(ADISPLAY_ID_DEFAULT,
Linnan Li72352222024-04-12 18:55:57 +08006259 EXPECTED_WALLPAPER_FLAGS | AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
Arthur Hungc539dbb2022-12-08 07:45:36 +00006260}
6261
Siarhei Vishniakoud0c6bc82021-03-13 03:14:52 +00006262// For the cases of single pointer touch and two pointers non-split touch, the api's
Prabir Pradhan367f3432024-02-13 23:05:58 +00006263// 'transferTouchGesture' and 'transferTouchOnDisplay' are equivalent in behaviour. They only differ
Siarhei Vishniakoud0c6bc82021-03-13 03:14:52 +00006264// for the case where there are multiple pointers split across several windows.
Prabir Pradhan367f3432024-02-13 23:05:58 +00006265INSTANTIATE_TEST_SUITE_P(
6266 InputDispatcherTransferFunctionTests, TransferTouchFixture,
6267 ::testing::Values(
6268 [&](const std::unique_ptr<InputDispatcher>& dispatcher, sp<IBinder> /*ignored*/,
6269 sp<IBinder> destChannelToken) {
6270 return dispatcher->transferTouchOnDisplay(destChannelToken,
6271 ADISPLAY_ID_DEFAULT);
6272 },
6273 [&](const std::unique_ptr<InputDispatcher>& dispatcher, sp<IBinder> from,
6274 sp<IBinder> to) {
6275 return dispatcher->transferTouchGesture(from, to,
6276 /*isDragAndDrop=*/false);
6277 }));
Siarhei Vishniakoud0c6bc82021-03-13 03:14:52 +00006278
Prabir Pradhan367f3432024-02-13 23:05:58 +00006279TEST_F(InputDispatcherTest, TransferTouch_TwoPointersSplitTouch) {
Chris Yea209fde2020-07-22 13:54:51 -07006280 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
Svet Ganov5d3bc372020-01-26 23:11:07 -08006281
Siarhei Vishniakou870ecec2020-12-09 08:07:46 -10006282 sp<FakeWindowHandle> firstWindow =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07006283 sp<FakeWindowHandle>::make(application, mDispatcher, "First Window",
6284 ADISPLAY_ID_DEFAULT);
Svet Ganov5d3bc372020-01-26 23:11:07 -08006285 firstWindow->setFrame(Rect(0, 0, 600, 400));
Svet Ganov5d3bc372020-01-26 23:11:07 -08006286
Siarhei Vishniakou870ecec2020-12-09 08:07:46 -10006287 sp<FakeWindowHandle> secondWindow =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07006288 sp<FakeWindowHandle>::make(application, mDispatcher, "Second Window",
6289 ADISPLAY_ID_DEFAULT);
Svet Ganov5d3bc372020-01-26 23:11:07 -08006290 secondWindow->setFrame(Rect(0, 400, 600, 800));
Svet Ganov5d3bc372020-01-26 23:11:07 -08006291
6292 // Add the windows to the dispatcher
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07006293 mDispatcher->onWindowInfosChanged(
6294 {{*firstWindow->getInfo(), *secondWindow->getInfo()}, {}, 0, 0});
Svet Ganov5d3bc372020-01-26 23:11:07 -08006295
6296 PointF pointInFirst = {300, 200};
6297 PointF pointInSecond = {300, 600};
6298
6299 // Send down to the first window
Prabir Pradhan678438e2023-04-13 19:32:51 +00006300 mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_DOWN,
6301 AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
6302 {pointInFirst}));
Svet Ganov5d3bc372020-01-26 23:11:07 -08006303 // Only the first window should get the down event
6304 firstWindow->consumeMotionDown();
6305 secondWindow->assertNoEvents();
6306
6307 // Send down to the second window
Prabir Pradhan678438e2023-04-13 19:32:51 +00006308 mDispatcher->notifyMotion(generateMotionArgs(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN,
6309 ADISPLAY_ID_DEFAULT,
6310 {pointInFirst, pointInSecond}));
Svet Ganov5d3bc372020-01-26 23:11:07 -08006311 // The first window gets a move and the second a down
6312 firstWindow->consumeMotionMove();
6313 secondWindow->consumeMotionDown();
6314
Prabir Pradhan367f3432024-02-13 23:05:58 +00006315 // Transfer touch to the second window
6316 mDispatcher->transferTouchGesture(firstWindow->getToken(), secondWindow->getToken());
Svet Ganov5d3bc372020-01-26 23:11:07 -08006317 // The first window gets cancel and the new gets pointer down (it already saw down)
6318 firstWindow->consumeMotionCancel();
Prabir Pradhan65455c72024-02-13 21:46:41 +00006319 secondWindow->consumeMotionPointerDown(1, ADISPLAY_ID_DEFAULT,
6320 AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
Svet Ganov5d3bc372020-01-26 23:11:07 -08006321
6322 // Send pointer up to the second window
Prabir Pradhan678438e2023-04-13 19:32:51 +00006323 mDispatcher->notifyMotion(generateMotionArgs(POINTER_1_UP, AINPUT_SOURCE_TOUCHSCREEN,
6324 ADISPLAY_ID_DEFAULT,
6325 {pointInFirst, pointInSecond}));
Svet Ganov5d3bc372020-01-26 23:11:07 -08006326 // The first window gets nothing and the second gets pointer up
6327 firstWindow->assertNoEvents();
Prabir Pradhan65455c72024-02-13 21:46:41 +00006328 secondWindow->consumeMotionPointerUp(1, ADISPLAY_ID_DEFAULT,
6329 AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
Svet Ganov5d3bc372020-01-26 23:11:07 -08006330
6331 // Send up event to the second window
Prabir Pradhan678438e2023-04-13 19:32:51 +00006332 mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN,
6333 ADISPLAY_ID_DEFAULT));
Svet Ganov5d3bc372020-01-26 23:11:07 -08006334 // The first window gets nothing and the second gets up
6335 firstWindow->assertNoEvents();
Prabir Pradhan65455c72024-02-13 21:46:41 +00006336 secondWindow->consumeMotionUp(ADISPLAY_ID_DEFAULT, AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
Svet Ganov5d3bc372020-01-26 23:11:07 -08006337}
6338
Prabir Pradhan367f3432024-02-13 23:05:58 +00006339// Same as TransferTouch_TwoPointersSplitTouch, but using 'transferTouchOnDisplay' api.
6340// Unlike 'transferTouchGesture', calling 'transferTouchOnDisplay' when there are two windows
6341// receiving touch is not supported, so the touch should continue on those windows and the
6342// transferred-to window should get nothing.
6343TEST_F(InputDispatcherTest, TransferTouchOnDisplay_TwoPointersSplitTouch) {
Siarhei Vishniakoud0c6bc82021-03-13 03:14:52 +00006344 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
6345
Siarhei Vishniakoud0c6bc82021-03-13 03:14:52 +00006346 sp<FakeWindowHandle> firstWindow =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07006347 sp<FakeWindowHandle>::make(application, mDispatcher, "First Window",
6348 ADISPLAY_ID_DEFAULT);
Siarhei Vishniakoud0c6bc82021-03-13 03:14:52 +00006349 firstWindow->setFrame(Rect(0, 0, 600, 400));
Siarhei Vishniakoud0c6bc82021-03-13 03:14:52 +00006350
Siarhei Vishniakoud0c6bc82021-03-13 03:14:52 +00006351 sp<FakeWindowHandle> secondWindow =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07006352 sp<FakeWindowHandle>::make(application, mDispatcher, "Second Window",
6353 ADISPLAY_ID_DEFAULT);
Siarhei Vishniakoud0c6bc82021-03-13 03:14:52 +00006354 secondWindow->setFrame(Rect(0, 400, 600, 800));
Siarhei Vishniakoud0c6bc82021-03-13 03:14:52 +00006355
6356 // Add the windows to the dispatcher
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07006357 mDispatcher->onWindowInfosChanged(
6358 {{*firstWindow->getInfo(), *secondWindow->getInfo()}, {}, 0, 0});
Siarhei Vishniakoud0c6bc82021-03-13 03:14:52 +00006359
6360 PointF pointInFirst = {300, 200};
6361 PointF pointInSecond = {300, 600};
6362
6363 // Send down to the first window
Prabir Pradhan678438e2023-04-13 19:32:51 +00006364 mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_DOWN,
6365 AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
6366 {pointInFirst}));
Siarhei Vishniakoud0c6bc82021-03-13 03:14:52 +00006367 // Only the first window should get the down event
6368 firstWindow->consumeMotionDown();
6369 secondWindow->assertNoEvents();
6370
6371 // Send down to the second window
Prabir Pradhan678438e2023-04-13 19:32:51 +00006372 mDispatcher->notifyMotion(generateMotionArgs(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN,
6373 ADISPLAY_ID_DEFAULT,
6374 {pointInFirst, pointInSecond}));
Siarhei Vishniakoud0c6bc82021-03-13 03:14:52 +00006375 // The first window gets a move and the second a down
6376 firstWindow->consumeMotionMove();
6377 secondWindow->consumeMotionDown();
6378
6379 // Transfer touch focus to the second window
Siarhei Vishniakou7ae7afd2022-03-31 15:26:13 -07006380 const bool transferred =
Prabir Pradhan367f3432024-02-13 23:05:58 +00006381 mDispatcher->transferTouchOnDisplay(secondWindow->getToken(), ADISPLAY_ID_DEFAULT);
6382 // The 'transferTouchOnDisplay' call should not succeed, because there are 2 touched windows
Siarhei Vishniakoud0c6bc82021-03-13 03:14:52 +00006383 ASSERT_FALSE(transferred);
6384 firstWindow->assertNoEvents();
6385 secondWindow->assertNoEvents();
6386
6387 // The rest of the dispatch should proceed as normal
6388 // Send pointer up to the second window
Prabir Pradhan678438e2023-04-13 19:32:51 +00006389 mDispatcher->notifyMotion(generateMotionArgs(POINTER_1_UP, AINPUT_SOURCE_TOUCHSCREEN,
6390 ADISPLAY_ID_DEFAULT,
6391 {pointInFirst, pointInSecond}));
Siarhei Vishniakoud0c6bc82021-03-13 03:14:52 +00006392 // The first window gets MOVE and the second gets pointer up
6393 firstWindow->consumeMotionMove();
6394 secondWindow->consumeMotionUp();
6395
6396 // Send up event to the first window
Prabir Pradhan678438e2023-04-13 19:32:51 +00006397 mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN,
6398 ADISPLAY_ID_DEFAULT));
Siarhei Vishniakoud0c6bc82021-03-13 03:14:52 +00006399 // The first window gets nothing and the second gets up
6400 firstWindow->consumeMotionUp();
6401 secondWindow->assertNoEvents();
6402}
6403
Arthur Hungabbb9d82021-09-01 14:52:30 +00006404// This case will create two windows and one mirrored window on the default display and mirror
Prabir Pradhan367f3432024-02-13 23:05:58 +00006405// two windows on the second display. It will test if 'transferTouchGesture' works fine if we put
Arthur Hungabbb9d82021-09-01 14:52:30 +00006406// the windows info of second display before default display.
Prabir Pradhan367f3432024-02-13 23:05:58 +00006407TEST_F(InputDispatcherTest, TransferTouch_CloneSurface) {
Arthur Hungabbb9d82021-09-01 14:52:30 +00006408 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
6409 sp<FakeWindowHandle> firstWindowInPrimary =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07006410 sp<FakeWindowHandle>::make(application, mDispatcher, "D_1_W1", ADISPLAY_ID_DEFAULT);
Arthur Hungabbb9d82021-09-01 14:52:30 +00006411 firstWindowInPrimary->setFrame(Rect(0, 0, 100, 100));
Arthur Hungabbb9d82021-09-01 14:52:30 +00006412 sp<FakeWindowHandle> secondWindowInPrimary =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07006413 sp<FakeWindowHandle>::make(application, mDispatcher, "D_1_W2", ADISPLAY_ID_DEFAULT);
Arthur Hungabbb9d82021-09-01 14:52:30 +00006414 secondWindowInPrimary->setFrame(Rect(100, 0, 200, 100));
Arthur Hungabbb9d82021-09-01 14:52:30 +00006415
Siarhei Vishniakouadb9fc92023-05-26 10:46:09 -07006416 sp<FakeWindowHandle> mirrorWindowInPrimary = firstWindowInPrimary->clone(ADISPLAY_ID_DEFAULT);
Arthur Hungabbb9d82021-09-01 14:52:30 +00006417 mirrorWindowInPrimary->setFrame(Rect(0, 100, 100, 200));
Arthur Hungabbb9d82021-09-01 14:52:30 +00006418
Siarhei Vishniakouadb9fc92023-05-26 10:46:09 -07006419 sp<FakeWindowHandle> firstWindowInSecondary = firstWindowInPrimary->clone(SECOND_DISPLAY_ID);
Arthur Hungabbb9d82021-09-01 14:52:30 +00006420 firstWindowInSecondary->setFrame(Rect(0, 0, 100, 100));
Arthur Hungabbb9d82021-09-01 14:52:30 +00006421
Siarhei Vishniakouadb9fc92023-05-26 10:46:09 -07006422 sp<FakeWindowHandle> secondWindowInSecondary = secondWindowInPrimary->clone(SECOND_DISPLAY_ID);
Arthur Hungabbb9d82021-09-01 14:52:30 +00006423 secondWindowInPrimary->setFrame(Rect(100, 0, 200, 100));
Arthur Hungabbb9d82021-09-01 14:52:30 +00006424
6425 // Update window info, let it find window handle of second display first.
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07006426 mDispatcher->onWindowInfosChanged(
6427 {{*firstWindowInSecondary->getInfo(), *secondWindowInSecondary->getInfo(),
6428 *mirrorWindowInPrimary->getInfo(), *firstWindowInPrimary->getInfo(),
6429 *secondWindowInPrimary->getInfo()},
6430 {},
6431 0,
6432 0});
Arthur Hungabbb9d82021-09-01 14:52:30 +00006433
6434 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07006435 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
Arthur Hungabbb9d82021-09-01 14:52:30 +00006436 {50, 50}))
6437 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
6438
6439 // Window should receive motion event.
6440 firstWindowInPrimary->consumeMotionDown(ADISPLAY_ID_DEFAULT);
6441
Prabir Pradhan367f3432024-02-13 23:05:58 +00006442 // Transfer touch
6443 ASSERT_TRUE(mDispatcher->transferTouchGesture(firstWindowInPrimary->getToken(),
6444 secondWindowInPrimary->getToken()));
Arthur Hungabbb9d82021-09-01 14:52:30 +00006445 // The first window gets cancel.
6446 firstWindowInPrimary->consumeMotionCancel();
Prabir Pradhan65455c72024-02-13 21:46:41 +00006447 secondWindowInPrimary->consumeMotionDown(ADISPLAY_ID_DEFAULT,
6448 AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
Arthur Hungabbb9d82021-09-01 14:52:30 +00006449
6450 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07006451 injectMotionEvent(*mDispatcher, AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN,
Arthur Hungabbb9d82021-09-01 14:52:30 +00006452 ADISPLAY_ID_DEFAULT, {150, 50}))
6453 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
6454 firstWindowInPrimary->assertNoEvents();
Prabir Pradhan65455c72024-02-13 21:46:41 +00006455 secondWindowInPrimary->consumeMotionMove(ADISPLAY_ID_DEFAULT,
6456 AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
Arthur Hungabbb9d82021-09-01 14:52:30 +00006457
6458 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07006459 injectMotionUp(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
Arthur Hungabbb9d82021-09-01 14:52:30 +00006460 {150, 50}))
6461 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
6462 firstWindowInPrimary->assertNoEvents();
Prabir Pradhan65455c72024-02-13 21:46:41 +00006463 secondWindowInPrimary->consumeMotionUp(ADISPLAY_ID_DEFAULT, AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
Arthur Hungabbb9d82021-09-01 14:52:30 +00006464}
6465
Prabir Pradhan367f3432024-02-13 23:05:58 +00006466// Same as TransferTouch_CloneSurface, but this touch on the secondary display and use
6467// 'transferTouchOnDisplay' api.
6468TEST_F(InputDispatcherTest, TransferTouchOnDisplay_CloneSurface) {
Arthur Hungabbb9d82021-09-01 14:52:30 +00006469 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
6470 sp<FakeWindowHandle> firstWindowInPrimary =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07006471 sp<FakeWindowHandle>::make(application, mDispatcher, "D_1_W1", ADISPLAY_ID_DEFAULT);
Arthur Hungabbb9d82021-09-01 14:52:30 +00006472 firstWindowInPrimary->setFrame(Rect(0, 0, 100, 100));
Arthur Hungabbb9d82021-09-01 14:52:30 +00006473 sp<FakeWindowHandle> secondWindowInPrimary =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07006474 sp<FakeWindowHandle>::make(application, mDispatcher, "D_1_W2", ADISPLAY_ID_DEFAULT);
Arthur Hungabbb9d82021-09-01 14:52:30 +00006475 secondWindowInPrimary->setFrame(Rect(100, 0, 200, 100));
Arthur Hungabbb9d82021-09-01 14:52:30 +00006476
Siarhei Vishniakouadb9fc92023-05-26 10:46:09 -07006477 sp<FakeWindowHandle> mirrorWindowInPrimary = firstWindowInPrimary->clone(ADISPLAY_ID_DEFAULT);
Arthur Hungabbb9d82021-09-01 14:52:30 +00006478 mirrorWindowInPrimary->setFrame(Rect(0, 100, 100, 200));
Arthur Hungabbb9d82021-09-01 14:52:30 +00006479
Siarhei Vishniakouadb9fc92023-05-26 10:46:09 -07006480 sp<FakeWindowHandle> firstWindowInSecondary = firstWindowInPrimary->clone(SECOND_DISPLAY_ID);
Arthur Hungabbb9d82021-09-01 14:52:30 +00006481 firstWindowInSecondary->setFrame(Rect(0, 0, 100, 100));
Arthur Hungabbb9d82021-09-01 14:52:30 +00006482
Siarhei Vishniakouadb9fc92023-05-26 10:46:09 -07006483 sp<FakeWindowHandle> secondWindowInSecondary = secondWindowInPrimary->clone(SECOND_DISPLAY_ID);
Arthur Hungabbb9d82021-09-01 14:52:30 +00006484 secondWindowInPrimary->setFrame(Rect(100, 0, 200, 100));
Arthur Hungabbb9d82021-09-01 14:52:30 +00006485
6486 // Update window info, let it find window handle of second display first.
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07006487 mDispatcher->onWindowInfosChanged(
6488 {{*firstWindowInSecondary->getInfo(), *secondWindowInSecondary->getInfo(),
6489 *mirrorWindowInPrimary->getInfo(), *firstWindowInPrimary->getInfo(),
6490 *secondWindowInPrimary->getInfo()},
6491 {},
6492 0,
6493 0});
Arthur Hungabbb9d82021-09-01 14:52:30 +00006494
6495 // Touch on second display.
6496 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07006497 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, SECOND_DISPLAY_ID,
6498 {50, 50}))
Arthur Hungabbb9d82021-09-01 14:52:30 +00006499 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
6500
6501 // Window should receive motion event.
Prabir Pradhanbb3f1c02024-01-04 20:17:14 +00006502 firstWindowInSecondary->consumeMotionDown(SECOND_DISPLAY_ID);
Arthur Hungabbb9d82021-09-01 14:52:30 +00006503
6504 // Transfer touch focus
Prabir Pradhan367f3432024-02-13 23:05:58 +00006505 ASSERT_TRUE(mDispatcher->transferTouchOnDisplay(secondWindowInSecondary->getToken(),
6506 SECOND_DISPLAY_ID));
Arthur Hungabbb9d82021-09-01 14:52:30 +00006507
6508 // The first window gets cancel.
Prabir Pradhanbb3f1c02024-01-04 20:17:14 +00006509 firstWindowInSecondary->consumeMotionCancel(SECOND_DISPLAY_ID);
Prabir Pradhan65455c72024-02-13 21:46:41 +00006510 secondWindowInSecondary->consumeMotionDown(SECOND_DISPLAY_ID,
6511 AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
Arthur Hungabbb9d82021-09-01 14:52:30 +00006512
6513 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07006514 injectMotionEvent(*mDispatcher, AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN,
Arthur Hungabbb9d82021-09-01 14:52:30 +00006515 SECOND_DISPLAY_ID, {150, 50}))
6516 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
Prabir Pradhanbb3f1c02024-01-04 20:17:14 +00006517 firstWindowInSecondary->assertNoEvents();
Prabir Pradhan65455c72024-02-13 21:46:41 +00006518 secondWindowInSecondary->consumeMotionMove(SECOND_DISPLAY_ID,
6519 AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
Arthur Hungabbb9d82021-09-01 14:52:30 +00006520
6521 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07006522 injectMotionUp(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, SECOND_DISPLAY_ID, {150, 50}))
Arthur Hungabbb9d82021-09-01 14:52:30 +00006523 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
Prabir Pradhanbb3f1c02024-01-04 20:17:14 +00006524 firstWindowInSecondary->assertNoEvents();
Prabir Pradhan65455c72024-02-13 21:46:41 +00006525 secondWindowInSecondary->consumeMotionUp(SECOND_DISPLAY_ID, AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
Arthur Hungabbb9d82021-09-01 14:52:30 +00006526}
6527
Siarhei Vishniakouf1035d42019-09-20 16:32:01 +01006528TEST_F(InputDispatcherTest, FocusedWindow_ReceivesFocusEventAndKeyEvent) {
Chris Yea209fde2020-07-22 13:54:51 -07006529 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07006530 sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher,
6531 "Fake Window", ADISPLAY_ID_DEFAULT);
Siarhei Vishniakouf1035d42019-09-20 16:32:01 +01006532
Vishnu Nair47074b82020-08-14 11:54:47 -07006533 window->setFocusable(true);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07006534 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Vishnu Nair958da932020-08-21 17:12:37 -07006535 setFocusedWindow(window);
Siarhei Vishniakouf1035d42019-09-20 16:32:01 +01006536
6537 window->consumeFocusEvent(true);
6538
Prabir Pradhan678438e2023-04-13 19:32:51 +00006539 mDispatcher->notifyKey(generateKeyArgs(AKEY_EVENT_ACTION_DOWN, ADISPLAY_ID_DEFAULT));
Siarhei Vishniakouf1035d42019-09-20 16:32:01 +01006540
6541 // Window should receive key down event.
6542 window->consumeKeyDown(ADISPLAY_ID_DEFAULT);
Josep del Riob3981622023-04-18 15:49:45 +00006543
6544 // Should have poked user activity
Siarhei Vishniakou4fd86732023-05-24 17:33:01 +00006545 mDispatcher->waitForIdle();
Josep del Riob3981622023-04-18 15:49:45 +00006546 mFakePolicy->assertUserActivityPoked();
6547}
6548
6549TEST_F(InputDispatcherTest, FocusedWindow_DisableUserActivity) {
6550 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
6551 sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher,
6552 "Fake Window", ADISPLAY_ID_DEFAULT);
6553
6554 window->setDisableUserActivity(true);
6555 window->setFocusable(true);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07006556 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Josep del Riob3981622023-04-18 15:49:45 +00006557 setFocusedWindow(window);
6558
6559 window->consumeFocusEvent(true);
6560
6561 mDispatcher->notifyKey(generateKeyArgs(AKEY_EVENT_ACTION_DOWN, ADISPLAY_ID_DEFAULT));
6562
6563 // Window should receive key down event.
6564 window->consumeKeyDown(ADISPLAY_ID_DEFAULT);
6565
6566 // Should have poked user activity
Siarhei Vishniakou4fd86732023-05-24 17:33:01 +00006567 mDispatcher->waitForIdle();
Josep del Riob3981622023-04-18 15:49:45 +00006568 mFakePolicy->assertUserActivityNotPoked();
6569}
6570
6571TEST_F(InputDispatcherTest, FocusedWindow_DoesNotReceiveSystemShortcut) {
6572 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
6573 sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher,
6574 "Fake Window", ADISPLAY_ID_DEFAULT);
6575
6576 window->setFocusable(true);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07006577 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Josep del Riob3981622023-04-18 15:49:45 +00006578 setFocusedWindow(window);
6579
6580 window->consumeFocusEvent(true);
6581
6582 mDispatcher->notifyKey(generateSystemShortcutArgs(AKEY_EVENT_ACTION_DOWN, ADISPLAY_ID_DEFAULT));
6583 mDispatcher->waitForIdle();
6584
6585 // System key is not passed down
6586 window->assertNoEvents();
6587
6588 // Should have poked user activity
6589 mFakePolicy->assertUserActivityPoked();
6590}
6591
6592TEST_F(InputDispatcherTest, FocusedWindow_DoesNotReceiveAssistantKey) {
6593 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
6594 sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher,
6595 "Fake Window", ADISPLAY_ID_DEFAULT);
6596
6597 window->setFocusable(true);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07006598 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Josep del Riob3981622023-04-18 15:49:45 +00006599 setFocusedWindow(window);
6600
6601 window->consumeFocusEvent(true);
6602
6603 mDispatcher->notifyKey(generateAssistantKeyArgs(AKEY_EVENT_ACTION_DOWN, ADISPLAY_ID_DEFAULT));
6604 mDispatcher->waitForIdle();
6605
6606 // System key is not passed down
6607 window->assertNoEvents();
6608
6609 // Should have poked user activity
6610 mFakePolicy->assertUserActivityPoked();
6611}
6612
6613TEST_F(InputDispatcherTest, FocusedWindow_SystemKeyIgnoresDisableUserActivity) {
6614 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
6615 sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher,
6616 "Fake Window", ADISPLAY_ID_DEFAULT);
6617
6618 window->setDisableUserActivity(true);
6619 window->setFocusable(true);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07006620 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Josep del Riob3981622023-04-18 15:49:45 +00006621 setFocusedWindow(window);
6622
6623 window->consumeFocusEvent(true);
6624
6625 mDispatcher->notifyKey(generateSystemShortcutArgs(AKEY_EVENT_ACTION_DOWN, ADISPLAY_ID_DEFAULT));
6626 mDispatcher->waitForIdle();
6627
6628 // System key is not passed down
6629 window->assertNoEvents();
6630
6631 // Should have poked user activity
6632 mFakePolicy->assertUserActivityPoked();
Siarhei Vishniakouf1035d42019-09-20 16:32:01 +01006633}
6634
Siarhei Vishniakou90ee4782023-05-08 11:57:24 -07006635TEST_F(InputDispatcherTest, InjectedTouchesPokeUserActivity) {
6636 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
6637 sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher,
6638 "Fake Window", ADISPLAY_ID_DEFAULT);
6639
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07006640 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Siarhei Vishniakou90ee4782023-05-08 11:57:24 -07006641
6642 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07006643 injectMotionEvent(*mDispatcher, AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN,
Siarhei Vishniakou90ee4782023-05-08 11:57:24 -07006644 ADISPLAY_ID_DEFAULT, {100, 100}))
6645 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
6646
6647 window->consumeMotionEvent(
6648 AllOf(WithMotionAction(ACTION_DOWN), WithDisplayId(ADISPLAY_ID_DEFAULT)));
6649
6650 // Should have poked user activity
Siarhei Vishniakou4fd86732023-05-24 17:33:01 +00006651 mDispatcher->waitForIdle();
Siarhei Vishniakou90ee4782023-05-08 11:57:24 -07006652 mFakePolicy->assertUserActivityPoked();
6653}
6654
Siarhei Vishniakouf1035d42019-09-20 16:32:01 +01006655TEST_F(InputDispatcherTest, UnfocusedWindow_DoesNotReceiveFocusEventOrKeyEvent) {
Chris Yea209fde2020-07-22 13:54:51 -07006656 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07006657 sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher,
6658 "Fake Window", ADISPLAY_ID_DEFAULT);
Siarhei Vishniakouf1035d42019-09-20 16:32:01 +01006659
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07006660 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Siarhei Vishniakouf1035d42019-09-20 16:32:01 +01006661
Prabir Pradhan678438e2023-04-13 19:32:51 +00006662 mDispatcher->notifyKey(generateKeyArgs(AKEY_EVENT_ACTION_DOWN, ADISPLAY_ID_DEFAULT));
Siarhei Vishniakouf1035d42019-09-20 16:32:01 +01006663 mDispatcher->waitForIdle();
6664
6665 window->assertNoEvents();
6666}
6667
6668// If a window is touchable, but does not have focus, it should receive motion events, but not keys
6669TEST_F(InputDispatcherTest, UnfocusedWindow_ReceivesMotionsButNotKeys) {
Chris Yea209fde2020-07-22 13:54:51 -07006670 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07006671 sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher,
6672 "Fake Window", ADISPLAY_ID_DEFAULT);
Siarhei Vishniakouf1035d42019-09-20 16:32:01 +01006673
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07006674 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Siarhei Vishniakouf1035d42019-09-20 16:32:01 +01006675
6676 // Send key
Prabir Pradhan678438e2023-04-13 19:32:51 +00006677 mDispatcher->notifyKey(generateKeyArgs(AKEY_EVENT_ACTION_DOWN, ADISPLAY_ID_DEFAULT));
Siarhei Vishniakouf1035d42019-09-20 16:32:01 +01006678 // Send motion
Prabir Pradhan678438e2023-04-13 19:32:51 +00006679 mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_DOWN,
6680 AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT));
Siarhei Vishniakouf1035d42019-09-20 16:32:01 +01006681
6682 // Window should receive only the motion event
6683 window->consumeMotionDown(ADISPLAY_ID_DEFAULT);
6684 window->assertNoEvents(); // Key event or focus event will not be received
6685}
6686
arthurhungea3f4fc2020-12-21 23:18:53 +08006687TEST_F(InputDispatcherTest, PointerCancel_SendCancelWhenSplitTouch) {
6688 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
6689
arthurhungea3f4fc2020-12-21 23:18:53 +08006690 sp<FakeWindowHandle> firstWindow =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07006691 sp<FakeWindowHandle>::make(application, mDispatcher, "First Window",
6692 ADISPLAY_ID_DEFAULT);
arthurhungea3f4fc2020-12-21 23:18:53 +08006693 firstWindow->setFrame(Rect(0, 0, 600, 400));
arthurhungea3f4fc2020-12-21 23:18:53 +08006694
arthurhungea3f4fc2020-12-21 23:18:53 +08006695 sp<FakeWindowHandle> secondWindow =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07006696 sp<FakeWindowHandle>::make(application, mDispatcher, "Second Window",
6697 ADISPLAY_ID_DEFAULT);
arthurhungea3f4fc2020-12-21 23:18:53 +08006698 secondWindow->setFrame(Rect(0, 400, 600, 800));
arthurhungea3f4fc2020-12-21 23:18:53 +08006699
6700 // Add the windows to the dispatcher
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07006701 mDispatcher->onWindowInfosChanged(
6702 {{*firstWindow->getInfo(), *secondWindow->getInfo()}, {}, 0, 0});
arthurhungea3f4fc2020-12-21 23:18:53 +08006703
6704 PointF pointInFirst = {300, 200};
6705 PointF pointInSecond = {300, 600};
6706
6707 // Send down to the first window
Prabir Pradhan678438e2023-04-13 19:32:51 +00006708 mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_DOWN,
6709 AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
6710 {pointInFirst}));
arthurhungea3f4fc2020-12-21 23:18:53 +08006711 // Only the first window should get the down event
6712 firstWindow->consumeMotionDown();
6713 secondWindow->assertNoEvents();
6714
6715 // Send down to the second window
Prabir Pradhan678438e2023-04-13 19:32:51 +00006716 mDispatcher->notifyMotion(generateMotionArgs(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN,
6717 ADISPLAY_ID_DEFAULT,
6718 {pointInFirst, pointInSecond}));
arthurhungea3f4fc2020-12-21 23:18:53 +08006719 // The first window gets a move and the second a down
6720 firstWindow->consumeMotionMove();
6721 secondWindow->consumeMotionDown();
6722
6723 // Send pointer cancel to the second window
6724 NotifyMotionArgs pointerUpMotionArgs =
Siarhei Vishniakoua16e3a22022-03-02 15:26:40 -08006725 generateMotionArgs(POINTER_1_UP, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
arthurhungea3f4fc2020-12-21 23:18:53 +08006726 {pointInFirst, pointInSecond});
6727 pointerUpMotionArgs.flags |= AMOTION_EVENT_FLAG_CANCELED;
Prabir Pradhan678438e2023-04-13 19:32:51 +00006728 mDispatcher->notifyMotion(pointerUpMotionArgs);
arthurhungea3f4fc2020-12-21 23:18:53 +08006729 // The first window gets move and the second gets cancel.
6730 firstWindow->consumeMotionMove(ADISPLAY_ID_DEFAULT, AMOTION_EVENT_FLAG_CANCELED);
6731 secondWindow->consumeMotionCancel(ADISPLAY_ID_DEFAULT, AMOTION_EVENT_FLAG_CANCELED);
6732
6733 // Send up event.
Prabir Pradhan678438e2023-04-13 19:32:51 +00006734 mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN,
6735 ADISPLAY_ID_DEFAULT));
arthurhungea3f4fc2020-12-21 23:18:53 +08006736 // The first window gets up and the second gets nothing.
6737 firstWindow->consumeMotionUp();
6738 secondWindow->assertNoEvents();
6739}
6740
Siarhei Vishniakouf94ae022021-02-04 01:23:17 +00006741TEST_F(InputDispatcherTest, SendTimeline_DoesNotCrashDispatcher) {
6742 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
6743
6744 sp<FakeWindowHandle> window =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07006745 sp<FakeWindowHandle>::make(application, mDispatcher, "Window", ADISPLAY_ID_DEFAULT);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07006746 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Siarhei Vishniakouf94ae022021-02-04 01:23:17 +00006747 std::array<nsecs_t, GraphicsTimeline::SIZE> graphicsTimeline;
6748 graphicsTimeline[GraphicsTimeline::GPU_COMPLETED_TIME] = 2;
6749 graphicsTimeline[GraphicsTimeline::PRESENT_TIME] = 3;
6750
Harry Cutts33476232023-01-30 19:57:29 +00006751 window->sendTimeline(/*inputEventId=*/1, graphicsTimeline);
Siarhei Vishniakouf94ae022021-02-04 01:23:17 +00006752 window->assertNoEvents();
6753 mDispatcher->waitForIdle();
6754}
6755
Prabir Pradhan1376fcd2022-01-21 09:56:35 -08006756using InputDispatcherMonitorTest = InputDispatcherTest;
6757
Siarhei Vishniakouca205502021-07-16 21:31:58 +00006758/**
6759 * Two entities that receive touch: A window, and a global monitor.
6760 * The touch goes to the window, and then the window disappears.
6761 * The monitor does not get cancel right away. But if more events come in, the touch gets canceled
6762 * for the monitor, as well.
6763 * 1. foregroundWindow
6764 * 2. monitor <-- global monitor (doesn't observe z order, receives all events)
6765 */
Prabir Pradhan1376fcd2022-01-21 09:56:35 -08006766TEST_F(InputDispatcherMonitorTest, MonitorTouchIsCanceledWhenForegroundWindowDisappears) {
Siarhei Vishniakouca205502021-07-16 21:31:58 +00006767 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
6768 sp<FakeWindowHandle> window =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07006769 sp<FakeWindowHandle>::make(application, mDispatcher, "Foreground", ADISPLAY_ID_DEFAULT);
Siarhei Vishniakouca205502021-07-16 21:31:58 +00006770
Prabir Pradhanfb549072023-10-05 19:17:36 +00006771 FakeMonitorReceiver monitor = FakeMonitorReceiver(*mDispatcher, "M_1", ADISPLAY_ID_DEFAULT);
Siarhei Vishniakouca205502021-07-16 21:31:58 +00006772
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07006773 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Siarhei Vishniakouca205502021-07-16 21:31:58 +00006774 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07006775 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
Siarhei Vishniakouca205502021-07-16 21:31:58 +00006776 {100, 200}))
6777 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
6778
6779 // Both the foreground window and the global monitor should receive the touch down
6780 window->consumeMotionDown();
6781 monitor.consumeMotionDown(ADISPLAY_ID_DEFAULT);
6782
6783 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07006784 injectMotionEvent(*mDispatcher, AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN,
Siarhei Vishniakouca205502021-07-16 21:31:58 +00006785 ADISPLAY_ID_DEFAULT, {110, 200}))
6786 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
6787
6788 window->consumeMotionMove();
6789 monitor.consumeMotionMove(ADISPLAY_ID_DEFAULT);
6790
6791 // Now the foreground window goes away
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07006792 mDispatcher->onWindowInfosChanged({{}, {}, 0, 0});
Siarhei Vishniakouca205502021-07-16 21:31:58 +00006793 window->consumeMotionCancel();
6794 monitor.assertNoEvents(); // Global monitor does not get a cancel yet
6795
6796 // If more events come in, there will be no more foreground window to send them to. This will
6797 // cause a cancel for the monitor, as well.
6798 ASSERT_EQ(InputEventInjectionResult::FAILED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07006799 injectMotionEvent(*mDispatcher, AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN,
Siarhei Vishniakouca205502021-07-16 21:31:58 +00006800 ADISPLAY_ID_DEFAULT, {120, 200}))
6801 << "Injection should fail because the window was removed";
6802 window->assertNoEvents();
6803 // Global monitor now gets the cancel
6804 monitor.consumeMotionCancel(ADISPLAY_ID_DEFAULT);
6805}
6806
Prabir Pradhan1376fcd2022-01-21 09:56:35 -08006807TEST_F(InputDispatcherMonitorTest, ReceivesMotionEvents) {
Chris Yea209fde2020-07-22 13:54:51 -07006808 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07006809 sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher,
6810 "Fake Window", ADISPLAY_ID_DEFAULT);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07006811 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Michael Wright3a240c42019-12-10 20:53:41 +00006812
Prabir Pradhanfb549072023-10-05 19:17:36 +00006813 FakeMonitorReceiver monitor = FakeMonitorReceiver(*mDispatcher, "M_1", ADISPLAY_ID_DEFAULT);
Michael Wright3a240c42019-12-10 20:53:41 +00006814
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08006815 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07006816 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT))
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08006817 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
Michael Wright3a240c42019-12-10 20:53:41 +00006818 window->consumeMotionDown(ADISPLAY_ID_DEFAULT);
chaviwd1c23182019-12-20 18:44:56 -08006819 monitor.consumeMotionDown(ADISPLAY_ID_DEFAULT);
Michael Wright3a240c42019-12-10 20:53:41 +00006820}
6821
Prabir Pradhan1376fcd2022-01-21 09:56:35 -08006822TEST_F(InputDispatcherMonitorTest, MonitorCannotPilferPointers) {
Prabir Pradhanfb549072023-10-05 19:17:36 +00006823 FakeMonitorReceiver monitor = FakeMonitorReceiver(*mDispatcher, "M_1", ADISPLAY_ID_DEFAULT);
Michael Wright3a240c42019-12-10 20:53:41 +00006824
Chris Yea209fde2020-07-22 13:54:51 -07006825 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07006826 sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher,
6827 "Fake Window", ADISPLAY_ID_DEFAULT);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07006828 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Michael Wright3a240c42019-12-10 20:53:41 +00006829
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08006830 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07006831 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT))
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08006832 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
chaviwd1c23182019-12-20 18:44:56 -08006833 monitor.consumeMotionDown(ADISPLAY_ID_DEFAULT);
Prabir Pradhan1376fcd2022-01-21 09:56:35 -08006834 window->consumeMotionDown(ADISPLAY_ID_DEFAULT);
Michael Wright3a240c42019-12-10 20:53:41 +00006835
Prabir Pradhan1376fcd2022-01-21 09:56:35 -08006836 // Pilfer pointers from the monitor.
6837 // This should not do anything and the window should continue to receive events.
6838 EXPECT_NE(OK, mDispatcher->pilferPointers(monitor.getToken()));
Michael Wright3a240c42019-12-10 20:53:41 +00006839
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08006840 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07006841 injectMotionEvent(*mDispatcher, AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN,
Prabir Pradhan1376fcd2022-01-21 09:56:35 -08006842 ADISPLAY_ID_DEFAULT))
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08006843 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
Prabir Pradhan1376fcd2022-01-21 09:56:35 -08006844
6845 monitor.consumeMotionMove(ADISPLAY_ID_DEFAULT);
6846 window->consumeMotionMove(ADISPLAY_ID_DEFAULT);
Michael Wright3a240c42019-12-10 20:53:41 +00006847}
6848
Prabir Pradhan1376fcd2022-01-21 09:56:35 -08006849TEST_F(InputDispatcherMonitorTest, NoWindowTransform) {
Evan Rosky84f07f02021-04-16 10:42:42 -07006850 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07006851 sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher,
6852 "Fake Window", ADISPLAY_ID_DEFAULT);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07006853 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Evan Rosky84f07f02021-04-16 10:42:42 -07006854 window->setWindowOffset(20, 40);
6855 window->setWindowTransform(0, 1, -1, 0);
6856
Prabir Pradhanfb549072023-10-05 19:17:36 +00006857 FakeMonitorReceiver monitor = FakeMonitorReceiver(*mDispatcher, "M_1", ADISPLAY_ID_DEFAULT);
Evan Rosky84f07f02021-04-16 10:42:42 -07006858
6859 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07006860 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT))
Evan Rosky84f07f02021-04-16 10:42:42 -07006861 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
6862 window->consumeMotionDown(ADISPLAY_ID_DEFAULT);
Siarhei Vishniakoud3061ab2023-12-18 20:41:08 -08006863 std::unique_ptr<MotionEvent> event = monitor.consumeMotion();
6864 ASSERT_NE(nullptr, event);
Evan Rosky84f07f02021-04-16 10:42:42 -07006865 // Even though window has transform, gesture monitor must not.
6866 ASSERT_EQ(ui::Transform(), event->getTransform());
6867}
6868
Prabir Pradhan1376fcd2022-01-21 09:56:35 -08006869TEST_F(InputDispatcherMonitorTest, InjectionFailsWithNoWindow) {
Arthur Hungb3307ee2021-10-14 10:57:37 +00006870 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
Prabir Pradhanfb549072023-10-05 19:17:36 +00006871 FakeMonitorReceiver monitor = FakeMonitorReceiver(*mDispatcher, "M_1", ADISPLAY_ID_DEFAULT);
Arthur Hungb3307ee2021-10-14 10:57:37 +00006872
Prabir Pradhan1376fcd2022-01-21 09:56:35 -08006873 ASSERT_EQ(InputEventInjectionResult::FAILED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07006874 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT))
Prabir Pradhan1376fcd2022-01-21 09:56:35 -08006875 << "Injection should fail if there is a monitor, but no touchable window";
6876 monitor.assertNoEvents();
Arthur Hungb3307ee2021-10-14 10:57:37 +00006877}
6878
Linnan Lid8150952024-01-26 18:07:17 +00006879/**
6880 * Two displays
6881 * The first monitor has a foreground window, a monitor
6882 * The second window has only one monitor.
6883 * We first inject a Down event into the first display, this injection should succeed and both
6884 * the foreground window and monitor should receive a down event, then inject a Down event into
6885 * the second display as well, this injection should fail, at this point, the first display
6886 * window and monitor should not receive a cancel or any other event.
6887 * Continue to inject Move and UP events to the first display, the events should be received
6888 * normally by the foreground window and monitor.
6889 */
6890TEST_F(InputDispatcherMonitorTest, MonitorTouchIsNotCanceledWhenAnotherEmptyDisplayReceiveEvents) {
6891 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
6892 sp<FakeWindowHandle> window =
6893 sp<FakeWindowHandle>::make(application, mDispatcher, "Foreground", ADISPLAY_ID_DEFAULT);
6894
6895 FakeMonitorReceiver monitor = FakeMonitorReceiver(*mDispatcher, "M_1", ADISPLAY_ID_DEFAULT);
6896 FakeMonitorReceiver secondMonitor = FakeMonitorReceiver(*mDispatcher, "M_2", SECOND_DISPLAY_ID);
6897
6898 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
6899 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
6900 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
6901 {100, 200}))
6902 << "The down event injected into the first display should succeed";
6903
6904 window->consumeMotionDown();
6905 monitor.consumeMotionDown(ADISPLAY_ID_DEFAULT);
Linnan Lid8150952024-01-26 18:07:17 +00006906
6907 ASSERT_EQ(InputEventInjectionResult::FAILED,
6908 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, SECOND_DISPLAY_ID,
6909 {100, 200}))
Prabir Pradhana0d43d42024-01-30 00:27:08 +00006910 << "The down event injected into the second display should fail since there's no "
6911 "touchable window";
Linnan Lid8150952024-01-26 18:07:17 +00006912
6913 // Continue to inject event to first display.
6914 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
6915 injectMotionEvent(*mDispatcher, AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN,
6916 ADISPLAY_ID_DEFAULT, {110, 220}))
6917 << "The move event injected into the first display should succeed";
6918
6919 window->consumeMotionMove();
6920 monitor.consumeMotionMove(ADISPLAY_ID_DEFAULT);
Linnan Lid8150952024-01-26 18:07:17 +00006921
6922 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
6923 injectMotionUp(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
6924 {110, 220}))
6925 << "The up event injected into the first display should succeed";
6926
6927 window->consumeMotionUp();
6928 monitor.consumeMotionUp(ADISPLAY_ID_DEFAULT);
Prabir Pradhana0d43d42024-01-30 00:27:08 +00006929
6930 window->assertNoEvents();
6931 monitor.assertNoEvents();
Linnan Lid8150952024-01-26 18:07:17 +00006932 secondMonitor.assertNoEvents();
6933}
6934
6935/**
6936 * Two displays
6937 * There is a monitor and foreground window on each display.
6938 * First, we inject down events into each of the two displays, at this point, the foreground windows
6939 * and monitors on both displays should receive down events.
6940 * At this point, the foreground window of the second display goes away, the gone window should
6941 * receive the cancel event, and the other windows and monitors should not receive any events.
6942 * Inject a move event into the second display. At this point, the injection should fail because
6943 * the second display no longer has a foreground window. At this point, the monitor on the second
6944 * display should receive a cancel event, and any windows or monitors on the first display should
6945 * not receive any events, and any subsequent injection of events into the second display should
6946 * also fail.
6947 * Continue to inject events into the first display, and the events should all be injected
6948 * successfully and received normally.
6949 */
6950TEST_F(InputDispatcherMonitorTest, MonitorTouchIsNotCancelWhenAnotherDisplayMonitorTouchCanceled) {
6951 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
6952 sp<FakeWindowHandle> window =
6953 sp<FakeWindowHandle>::make(application, mDispatcher, "Foreground", ADISPLAY_ID_DEFAULT);
6954 sp<FakeWindowHandle> secondWindow =
6955 sp<FakeWindowHandle>::make(application, mDispatcher, "SecondForeground",
6956 SECOND_DISPLAY_ID);
6957
6958 FakeMonitorReceiver monitor = FakeMonitorReceiver(*mDispatcher, "M_1", ADISPLAY_ID_DEFAULT);
6959 FakeMonitorReceiver secondMonitor = FakeMonitorReceiver(*mDispatcher, "M_2", SECOND_DISPLAY_ID);
6960
6961 // There is a foreground window on both displays.
6962 mDispatcher->onWindowInfosChanged({{*window->getInfo(), *secondWindow->getInfo()}, {}, 0, 0});
6963 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
6964 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
6965 {100, 200}))
6966 << "The down event injected into the first display should succeed";
6967
6968 window->consumeMotionDown(ADISPLAY_ID_DEFAULT);
6969 monitor.consumeMotionDown(ADISPLAY_ID_DEFAULT);
Linnan Lid8150952024-01-26 18:07:17 +00006970
6971 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
6972 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, SECOND_DISPLAY_ID,
6973 {100, 200}))
6974 << "The down event injected into the second display should succeed";
6975
Linnan Lid8150952024-01-26 18:07:17 +00006976 secondWindow->consumeMotionDown(SECOND_DISPLAY_ID);
6977 secondMonitor.consumeMotionDown(SECOND_DISPLAY_ID);
6978
6979 // Now second window is gone away.
6980 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
6981
6982 // The gone window should receive a cancel, and the monitor on the second display should not
6983 // receive any events.
Linnan Lid8150952024-01-26 18:07:17 +00006984 secondWindow->consumeMotionCancel(SECOND_DISPLAY_ID);
6985 secondMonitor.assertNoEvents();
6986
6987 ASSERT_EQ(InputEventInjectionResult::FAILED,
6988 injectMotionEvent(*mDispatcher, AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN,
6989 SECOND_DISPLAY_ID, {110, 220}))
Prabir Pradhana0d43d42024-01-30 00:27:08 +00006990 << "The move event injected into the second display should fail because there's no "
6991 "touchable window";
Linnan Lid8150952024-01-26 18:07:17 +00006992 // Now the monitor on the second display should receive a cancel event.
6993 secondMonitor.consumeMotionCancel(SECOND_DISPLAY_ID);
Linnan Lid8150952024-01-26 18:07:17 +00006994
6995 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
6996 injectMotionEvent(*mDispatcher, AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN,
6997 ADISPLAY_ID_DEFAULT, {110, 200}))
6998 << "The move event injected into the first display should succeed";
6999
7000 window->consumeMotionMove();
7001 monitor.consumeMotionMove(ADISPLAY_ID_DEFAULT);
Linnan Lid8150952024-01-26 18:07:17 +00007002
7003 ASSERT_EQ(InputEventInjectionResult::FAILED,
Prabir Pradhana0d43d42024-01-30 00:27:08 +00007004 injectMotionUp(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, SECOND_DISPLAY_ID,
7005 {110, 220}))
7006 << "The up event injected into the second display should fail because there's no "
7007 "touchable window";
Linnan Lid8150952024-01-26 18:07:17 +00007008
7009 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
7010 injectMotionUp(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
7011 {110, 220}))
7012 << "The up event injected into the first display should succeed";
7013
7014 window->consumeMotionUp(ADISPLAY_ID_DEFAULT);
7015 monitor.consumeMotionUp(ADISPLAY_ID_DEFAULT);
Prabir Pradhana0d43d42024-01-30 00:27:08 +00007016
Linnan Lid8150952024-01-26 18:07:17 +00007017 window->assertNoEvents();
7018 monitor.assertNoEvents();
Prabir Pradhana0d43d42024-01-30 00:27:08 +00007019 secondWindow->assertNoEvents();
7020 secondMonitor.assertNoEvents();
Linnan Lid8150952024-01-26 18:07:17 +00007021}
7022
7023/**
7024 * One display with transform
7025 * There is a foreground window and a monitor on the display
7026 * Inject down event and move event sequentially, the foreground window and monitor can receive down
7027 * event and move event, then let the foreground window go away, the foreground window receives
7028 * cancel event, inject move event again, the monitor receives cancel event, all the events received
7029 * by the monitor should be with the same transform as the display
7030 */
7031TEST_F(InputDispatcherMonitorTest, MonitorTouchCancelEventWithDisplayTransform) {
7032 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
7033 sp<FakeWindowHandle> window =
7034 sp<FakeWindowHandle>::make(application, mDispatcher, "Foreground", ADISPLAY_ID_DEFAULT);
7035 FakeMonitorReceiver monitor = FakeMonitorReceiver(*mDispatcher, "M_1", ADISPLAY_ID_DEFAULT);
7036
7037 ui::Transform transform;
7038 transform.set({1.1, 2.2, 3.3, 4.4, 5.5, 6.6, 0, 0, 1});
7039
7040 gui::DisplayInfo displayInfo;
7041 displayInfo.displayId = ADISPLAY_ID_DEFAULT;
7042 displayInfo.transform = transform;
7043
7044 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {displayInfo}, 0, 0});
7045
7046 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
7047 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
7048 {100, 200}))
7049 << "The down event injected should succeed";
7050
7051 window->consumeMotionDown();
7052 std::unique_ptr<MotionEvent> downMotionEvent = monitor.consumeMotion();
7053 EXPECT_EQ(transform, downMotionEvent->getTransform());
7054 EXPECT_EQ(AMOTION_EVENT_ACTION_DOWN, downMotionEvent->getAction());
7055
7056 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
7057 injectMotionEvent(*mDispatcher, AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN,
7058 ADISPLAY_ID_DEFAULT, {110, 220}))
7059 << "The move event injected should succeed";
7060
7061 window->consumeMotionMove();
7062 std::unique_ptr<MotionEvent> moveMotionEvent = monitor.consumeMotion();
7063 EXPECT_EQ(transform, moveMotionEvent->getTransform());
7064 EXPECT_EQ(AMOTION_EVENT_ACTION_MOVE, moveMotionEvent->getAction());
7065
7066 // Let foreground window gone
7067 mDispatcher->onWindowInfosChanged({{}, {displayInfo}, 0, 0});
7068
Prabir Pradhana0d43d42024-01-30 00:27:08 +00007069 // Foreground window should receive a cancel event, but not the monitor.
Linnan Lid8150952024-01-26 18:07:17 +00007070 window->consumeMotionCancel();
Linnan Lid8150952024-01-26 18:07:17 +00007071
7072 ASSERT_EQ(InputEventInjectionResult::FAILED,
7073 injectMotionEvent(*mDispatcher, AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN,
7074 ADISPLAY_ID_DEFAULT, {110, 220}))
7075 << "The move event injected should failed";
7076 // Now foreground should not receive any events, but monitor should receive a cancel event
7077 // with transform that same as display's display.
Linnan Lid8150952024-01-26 18:07:17 +00007078 std::unique_ptr<MotionEvent> cancelMotionEvent = monitor.consumeMotion();
7079 EXPECT_EQ(transform, cancelMotionEvent->getTransform());
7080 EXPECT_EQ(ADISPLAY_ID_DEFAULT, cancelMotionEvent->getDisplayId());
7081 EXPECT_EQ(AMOTION_EVENT_ACTION_CANCEL, cancelMotionEvent->getAction());
7082
7083 // Other event inject to this display should fail.
7084 ASSERT_EQ(InputEventInjectionResult::FAILED,
7085 injectMotionEvent(*mDispatcher, AMOTION_EVENT_ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN,
7086 ADISPLAY_ID_DEFAULT, {110, 220}))
Prabir Pradhana0d43d42024-01-30 00:27:08 +00007087 << "The up event injected should fail because the touched window was removed";
Linnan Lid8150952024-01-26 18:07:17 +00007088 window->assertNoEvents();
7089 monitor.assertNoEvents();
7090}
7091
chaviw81e2bb92019-12-18 15:03:51 -08007092TEST_F(InputDispatcherTest, TestMoveEvent) {
Chris Yea209fde2020-07-22 13:54:51 -07007093 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07007094 sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher,
7095 "Fake Window", ADISPLAY_ID_DEFAULT);
chaviw81e2bb92019-12-18 15:03:51 -08007096
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07007097 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
chaviw81e2bb92019-12-18 15:03:51 -08007098
7099 NotifyMotionArgs motionArgs =
7100 generateMotionArgs(AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN,
7101 ADISPLAY_ID_DEFAULT);
7102
Prabir Pradhan678438e2023-04-13 19:32:51 +00007103 mDispatcher->notifyMotion(motionArgs);
chaviw81e2bb92019-12-18 15:03:51 -08007104 // Window should receive motion down event.
7105 window->consumeMotionDown(ADISPLAY_ID_DEFAULT);
7106
7107 motionArgs.action = AMOTION_EVENT_ACTION_MOVE;
Garfield Tanc51d1ba2020-01-28 13:24:04 -08007108 motionArgs.id += 1;
chaviw81e2bb92019-12-18 15:03:51 -08007109 motionArgs.eventTime = systemTime(SYSTEM_TIME_MONOTONIC);
7110 motionArgs.pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_X,
7111 motionArgs.pointerCoords[0].getX() - 10);
7112
Prabir Pradhan678438e2023-04-13 19:32:51 +00007113 mDispatcher->notifyMotion(motionArgs);
Prabir Pradhan7662a8d2023-12-15 01:58:14 +00007114 window->consumeMotionMove(ADISPLAY_ID_DEFAULT, /*expectedFlags=*/0);
chaviw81e2bb92019-12-18 15:03:51 -08007115}
7116
Siarhei Vishniakouf1035d42019-09-20 16:32:01 +01007117/**
7118 * Dispatcher has touch mode enabled by default. Typically, the policy overrides that value to
7119 * the device default right away. In the test scenario, we check both the default value,
7120 * and the action of enabling / disabling.
7121 */
7122TEST_F(InputDispatcherTest, TouchModeState_IsSentToApps) {
Chris Yea209fde2020-07-22 13:54:51 -07007123 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07007124 sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher,
7125 "Test window", ADISPLAY_ID_DEFAULT);
Antonio Kantekea47acb2021-12-23 12:41:25 -08007126 const WindowInfo& windowInfo = *window->getInfo();
Siarhei Vishniakouf1035d42019-09-20 16:32:01 +01007127
7128 // Set focused application.
7129 mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application);
Vishnu Nair47074b82020-08-14 11:54:47 -07007130 window->setFocusable(true);
Siarhei Vishniakouf1035d42019-09-20 16:32:01 +01007131
7132 SCOPED_TRACE("Check default value of touch mode");
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07007133 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Vishnu Nair958da932020-08-21 17:12:37 -07007134 setFocusedWindow(window);
Harry Cutts33476232023-01-30 19:57:29 +00007135 window->consumeFocusEvent(/*hasFocus=*/true, /*inTouchMode=*/true);
Siarhei Vishniakouf1035d42019-09-20 16:32:01 +01007136
7137 SCOPED_TRACE("Remove the window to trigger focus loss");
Vishnu Nair47074b82020-08-14 11:54:47 -07007138 window->setFocusable(false);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07007139 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Harry Cutts33476232023-01-30 19:57:29 +00007140 window->consumeFocusEvent(/*hasFocus=*/false, /*inTouchMode=*/true);
Siarhei Vishniakouf1035d42019-09-20 16:32:01 +01007141
7142 SCOPED_TRACE("Disable touch mode");
Antonio Kantekea47acb2021-12-23 12:41:25 -08007143 mDispatcher->setInTouchMode(false, windowInfo.ownerPid, windowInfo.ownerUid,
Harry Cutts33476232023-01-30 19:57:29 +00007144 /*hasPermission=*/true, ADISPLAY_ID_DEFAULT);
Antonio Kantekf16f2832021-09-28 04:39:20 +00007145 window->consumeTouchModeEvent(false);
Vishnu Nair47074b82020-08-14 11:54:47 -07007146 window->setFocusable(true);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07007147 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Vishnu Nair958da932020-08-21 17:12:37 -07007148 setFocusedWindow(window);
Harry Cutts33476232023-01-30 19:57:29 +00007149 window->consumeFocusEvent(/*hasFocus=*/true, /*inTouchMode=*/false);
Siarhei Vishniakouf1035d42019-09-20 16:32:01 +01007150
7151 SCOPED_TRACE("Remove the window to trigger focus loss");
Vishnu Nair47074b82020-08-14 11:54:47 -07007152 window->setFocusable(false);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07007153 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Harry Cutts33476232023-01-30 19:57:29 +00007154 window->consumeFocusEvent(/*hasFocus=*/false, /*inTouchMode=*/false);
Siarhei Vishniakouf1035d42019-09-20 16:32:01 +01007155
7156 SCOPED_TRACE("Enable touch mode again");
Antonio Kantekea47acb2021-12-23 12:41:25 -08007157 mDispatcher->setInTouchMode(true, windowInfo.ownerPid, windowInfo.ownerUid,
Harry Cutts33476232023-01-30 19:57:29 +00007158 /*hasPermission=*/true, ADISPLAY_ID_DEFAULT);
Antonio Kantekf16f2832021-09-28 04:39:20 +00007159 window->consumeTouchModeEvent(true);
Vishnu Nair47074b82020-08-14 11:54:47 -07007160 window->setFocusable(true);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07007161 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Vishnu Nair958da932020-08-21 17:12:37 -07007162 setFocusedWindow(window);
Harry Cutts33476232023-01-30 19:57:29 +00007163 window->consumeFocusEvent(/*hasFocus=*/true, /*inTouchMode=*/true);
Siarhei Vishniakouf1035d42019-09-20 16:32:01 +01007164
7165 window->assertNoEvents();
7166}
7167
Gang Wange9087892020-01-07 12:17:14 -05007168TEST_F(InputDispatcherTest, VerifyInputEvent_KeyEvent) {
Chris Yea209fde2020-07-22 13:54:51 -07007169 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07007170 sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher,
7171 "Test window", ADISPLAY_ID_DEFAULT);
Gang Wange9087892020-01-07 12:17:14 -05007172
7173 mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application);
Vishnu Nair47074b82020-08-14 11:54:47 -07007174 window->setFocusable(true);
Gang Wange9087892020-01-07 12:17:14 -05007175
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07007176 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Vishnu Nair958da932020-08-21 17:12:37 -07007177 setFocusedWindow(window);
7178
Harry Cutts33476232023-01-30 19:57:29 +00007179 window->consumeFocusEvent(/*hasFocus=*/true, /*inTouchMode=*/true);
Gang Wange9087892020-01-07 12:17:14 -05007180
Prabir Pradhan678438e2023-04-13 19:32:51 +00007181 const NotifyKeyArgs keyArgs = generateKeyArgs(AKEY_EVENT_ACTION_DOWN);
7182 mDispatcher->notifyKey(keyArgs);
Gang Wange9087892020-01-07 12:17:14 -05007183
Siarhei Vishniakoud3061ab2023-12-18 20:41:08 -08007184 std::unique_ptr<KeyEvent> event = window->consumeKey();
7185 ASSERT_NE(event, nullptr);
7186 std::unique_ptr<VerifiedInputEvent> verified = mDispatcher->verifyInputEvent(*event);
Gang Wange9087892020-01-07 12:17:14 -05007187 ASSERT_NE(verified, nullptr);
7188 ASSERT_EQ(verified->type, VerifiedInputEvent::Type::KEY);
7189
7190 ASSERT_EQ(keyArgs.eventTime, verified->eventTimeNanos);
7191 ASSERT_EQ(keyArgs.deviceId, verified->deviceId);
7192 ASSERT_EQ(keyArgs.source, verified->source);
7193 ASSERT_EQ(keyArgs.displayId, verified->displayId);
7194
7195 const VerifiedKeyEvent& verifiedKey = static_cast<const VerifiedKeyEvent&>(*verified);
7196
7197 ASSERT_EQ(keyArgs.action, verifiedKey.action);
Gang Wange9087892020-01-07 12:17:14 -05007198 ASSERT_EQ(keyArgs.flags & VERIFIED_KEY_EVENT_FLAGS, verifiedKey.flags);
Siarhei Vishniakouf355bf92021-12-09 10:43:21 -08007199 ASSERT_EQ(keyArgs.downTime, verifiedKey.downTimeNanos);
Gang Wange9087892020-01-07 12:17:14 -05007200 ASSERT_EQ(keyArgs.keyCode, verifiedKey.keyCode);
7201 ASSERT_EQ(keyArgs.scanCode, verifiedKey.scanCode);
7202 ASSERT_EQ(keyArgs.metaState, verifiedKey.metaState);
7203 ASSERT_EQ(0, verifiedKey.repeatCount);
7204}
7205
Siarhei Vishniakou47040bf2020-02-28 15:03:13 -08007206TEST_F(InputDispatcherTest, VerifyInputEvent_MotionEvent) {
Chris Yea209fde2020-07-22 13:54:51 -07007207 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07007208 sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher,
7209 "Test window", ADISPLAY_ID_DEFAULT);
Siarhei Vishniakou47040bf2020-02-28 15:03:13 -08007210
7211 mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application);
7212
Prabir Pradhanb5cb9572021-09-24 06:35:16 -07007213 ui::Transform transform;
7214 transform.set({1.1, 2.2, 3.3, 4.4, 5.5, 6.6, 0, 0, 1});
7215
7216 gui::DisplayInfo displayInfo;
7217 displayInfo.displayId = ADISPLAY_ID_DEFAULT;
7218 displayInfo.transform = transform;
7219
Patrick Williamsd828f302023-04-28 17:52:08 -05007220 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {displayInfo}, 0, 0});
Siarhei Vishniakou47040bf2020-02-28 15:03:13 -08007221
Prabir Pradhan678438e2023-04-13 19:32:51 +00007222 const NotifyMotionArgs motionArgs =
Siarhei Vishniakou47040bf2020-02-28 15:03:13 -08007223 generateMotionArgs(AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN,
7224 ADISPLAY_ID_DEFAULT);
Prabir Pradhan678438e2023-04-13 19:32:51 +00007225 mDispatcher->notifyMotion(motionArgs);
Siarhei Vishniakou47040bf2020-02-28 15:03:13 -08007226
Siarhei Vishniakoud3061ab2023-12-18 20:41:08 -08007227 std::unique_ptr<MotionEvent> event = window->consumeMotionEvent();
7228 ASSERT_NE(nullptr, event);
7229 std::unique_ptr<VerifiedInputEvent> verified = mDispatcher->verifyInputEvent(*event);
Siarhei Vishniakou47040bf2020-02-28 15:03:13 -08007230 ASSERT_NE(verified, nullptr);
7231 ASSERT_EQ(verified->type, VerifiedInputEvent::Type::MOTION);
7232
7233 EXPECT_EQ(motionArgs.eventTime, verified->eventTimeNanos);
7234 EXPECT_EQ(motionArgs.deviceId, verified->deviceId);
7235 EXPECT_EQ(motionArgs.source, verified->source);
7236 EXPECT_EQ(motionArgs.displayId, verified->displayId);
7237
7238 const VerifiedMotionEvent& verifiedMotion = static_cast<const VerifiedMotionEvent&>(*verified);
7239
Prabir Pradhanb5cb9572021-09-24 06:35:16 -07007240 const vec2 rawXY =
7241 MotionEvent::calculateTransformedXY(motionArgs.source, transform,
7242 motionArgs.pointerCoords[0].getXYValue());
7243 EXPECT_EQ(rawXY.x, verifiedMotion.rawX);
7244 EXPECT_EQ(rawXY.y, verifiedMotion.rawY);
Siarhei Vishniakou47040bf2020-02-28 15:03:13 -08007245 EXPECT_EQ(motionArgs.action & AMOTION_EVENT_ACTION_MASK, verifiedMotion.actionMasked);
Siarhei Vishniakou47040bf2020-02-28 15:03:13 -08007246 EXPECT_EQ(motionArgs.flags & VERIFIED_MOTION_EVENT_FLAGS, verifiedMotion.flags);
Siarhei Vishniakouf355bf92021-12-09 10:43:21 -08007247 EXPECT_EQ(motionArgs.downTime, verifiedMotion.downTimeNanos);
Siarhei Vishniakou47040bf2020-02-28 15:03:13 -08007248 EXPECT_EQ(motionArgs.metaState, verifiedMotion.metaState);
7249 EXPECT_EQ(motionArgs.buttonState, verifiedMotion.buttonState);
7250}
7251
chaviw09c8d2d2020-08-24 15:48:26 -07007252/**
7253 * Ensure that separate calls to sign the same data are generating the same key.
7254 * We avoid asserting against INVALID_HMAC. Since the key is random, there is a non-zero chance
7255 * that a specific key and data combination would produce INVALID_HMAC, which would cause flaky
7256 * tests.
7257 */
7258TEST_F(InputDispatcherTest, GeneratedHmac_IsConsistent) {
7259 KeyEvent event = getTestKeyEvent();
7260 VerifiedKeyEvent verifiedEvent = verifiedKeyEventFromKeyEvent(event);
7261
7262 std::array<uint8_t, 32> hmac1 = mDispatcher->sign(verifiedEvent);
7263 std::array<uint8_t, 32> hmac2 = mDispatcher->sign(verifiedEvent);
7264 ASSERT_EQ(hmac1, hmac2);
7265}
7266
7267/**
7268 * Ensure that changes in VerifiedKeyEvent produce a different hmac.
7269 */
7270TEST_F(InputDispatcherTest, GeneratedHmac_ChangesWhenFieldsChange) {
7271 KeyEvent event = getTestKeyEvent();
7272 VerifiedKeyEvent verifiedEvent = verifiedKeyEventFromKeyEvent(event);
7273 std::array<uint8_t, 32> initialHmac = mDispatcher->sign(verifiedEvent);
7274
7275 verifiedEvent.deviceId += 1;
7276 ASSERT_NE(initialHmac, mDispatcher->sign(verifiedEvent));
7277
7278 verifiedEvent.source += 1;
7279 ASSERT_NE(initialHmac, mDispatcher->sign(verifiedEvent));
7280
7281 verifiedEvent.eventTimeNanos += 1;
7282 ASSERT_NE(initialHmac, mDispatcher->sign(verifiedEvent));
7283
Linnan Li13bf76a2024-05-05 19:18:02 +08007284 verifiedEvent.displayId = ui::LogicalDisplayId{verifiedEvent.displayId.val() + 1};
chaviw09c8d2d2020-08-24 15:48:26 -07007285 ASSERT_NE(initialHmac, mDispatcher->sign(verifiedEvent));
7286
7287 verifiedEvent.action += 1;
7288 ASSERT_NE(initialHmac, mDispatcher->sign(verifiedEvent));
7289
7290 verifiedEvent.downTimeNanos += 1;
7291 ASSERT_NE(initialHmac, mDispatcher->sign(verifiedEvent));
7292
7293 verifiedEvent.flags += 1;
7294 ASSERT_NE(initialHmac, mDispatcher->sign(verifiedEvent));
7295
7296 verifiedEvent.keyCode += 1;
7297 ASSERT_NE(initialHmac, mDispatcher->sign(verifiedEvent));
7298
7299 verifiedEvent.scanCode += 1;
7300 ASSERT_NE(initialHmac, mDispatcher->sign(verifiedEvent));
7301
7302 verifiedEvent.metaState += 1;
7303 ASSERT_NE(initialHmac, mDispatcher->sign(verifiedEvent));
7304
7305 verifiedEvent.repeatCount += 1;
7306 ASSERT_NE(initialHmac, mDispatcher->sign(verifiedEvent));
7307}
7308
Vishnu Nair958da932020-08-21 17:12:37 -07007309TEST_F(InputDispatcherTest, SetFocusedWindow) {
7310 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
7311 sp<FakeWindowHandle> windowTop =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07007312 sp<FakeWindowHandle>::make(application, mDispatcher, "Top", ADISPLAY_ID_DEFAULT);
Vishnu Nair958da932020-08-21 17:12:37 -07007313 sp<FakeWindowHandle> windowSecond =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07007314 sp<FakeWindowHandle>::make(application, mDispatcher, "Second", ADISPLAY_ID_DEFAULT);
Vishnu Nair958da932020-08-21 17:12:37 -07007315 mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application);
7316
7317 // Top window is also focusable but is not granted focus.
7318 windowTop->setFocusable(true);
7319 windowSecond->setFocusable(true);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07007320 mDispatcher->onWindowInfosChanged(
7321 {{*windowTop->getInfo(), *windowSecond->getInfo()}, {}, 0, 0});
Vishnu Nair958da932020-08-21 17:12:37 -07007322 setFocusedWindow(windowSecond);
7323
7324 windowSecond->consumeFocusEvent(true);
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07007325 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectKeyDown(*mDispatcher))
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08007326 << "Inject key event should return InputEventInjectionResult::SUCCEEDED";
Vishnu Nair958da932020-08-21 17:12:37 -07007327
7328 // Focused window should receive event.
Linnan Li13bf76a2024-05-05 19:18:02 +08007329 windowSecond->consumeKeyDown(ui::ADISPLAY_ID_NONE);
Vishnu Nair958da932020-08-21 17:12:37 -07007330 windowTop->assertNoEvents();
7331}
7332
7333TEST_F(InputDispatcherTest, SetFocusedWindow_DropRequestInvalidChannel) {
7334 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
7335 sp<FakeWindowHandle> window =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07007336 sp<FakeWindowHandle>::make(application, mDispatcher, "TestWindow", ADISPLAY_ID_DEFAULT);
Vishnu Nair958da932020-08-21 17:12:37 -07007337 mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application);
7338
7339 window->setFocusable(true);
7340 // Release channel for window is no longer valid.
7341 window->releaseChannel();
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07007342 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Vishnu Nair958da932020-08-21 17:12:37 -07007343 setFocusedWindow(window);
7344
7345 // Test inject a key down, should timeout.
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07007346 ASSERT_NO_FATAL_FAILURE(assertInjectedKeyTimesOut(*mDispatcher));
Vishnu Nair958da932020-08-21 17:12:37 -07007347
7348 // window channel is invalid, so it should not receive any input event.
7349 window->assertNoEvents();
7350}
7351
7352TEST_F(InputDispatcherTest, SetFocusedWindow_DropRequestNoFocusableWindow) {
7353 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
7354 sp<FakeWindowHandle> window =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07007355 sp<FakeWindowHandle>::make(application, mDispatcher, "TestWindow", ADISPLAY_ID_DEFAULT);
Prabir Pradhan76bdecb2022-01-31 11:14:15 -08007356 window->setFocusable(false);
Vishnu Nair958da932020-08-21 17:12:37 -07007357 mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application);
7358
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07007359 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Vishnu Nair958da932020-08-21 17:12:37 -07007360 setFocusedWindow(window);
7361
7362 // Test inject a key down, should timeout.
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07007363 ASSERT_NO_FATAL_FAILURE(assertInjectedKeyTimesOut(*mDispatcher));
Vishnu Nair958da932020-08-21 17:12:37 -07007364
Prabir Pradhan76bdecb2022-01-31 11:14:15 -08007365 // window is not focusable, so it should not receive any input event.
Vishnu Nair958da932020-08-21 17:12:37 -07007366 window->assertNoEvents();
7367}
7368
7369TEST_F(InputDispatcherTest, SetFocusedWindow_CheckFocusedToken) {
7370 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
7371 sp<FakeWindowHandle> windowTop =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07007372 sp<FakeWindowHandle>::make(application, mDispatcher, "Top", ADISPLAY_ID_DEFAULT);
Vishnu Nair958da932020-08-21 17:12:37 -07007373 sp<FakeWindowHandle> windowSecond =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07007374 sp<FakeWindowHandle>::make(application, mDispatcher, "Second", ADISPLAY_ID_DEFAULT);
Vishnu Nair958da932020-08-21 17:12:37 -07007375 mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application);
7376
7377 windowTop->setFocusable(true);
7378 windowSecond->setFocusable(true);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07007379 mDispatcher->onWindowInfosChanged(
7380 {{*windowTop->getInfo(), *windowSecond->getInfo()}, {}, 0, 0});
Vishnu Nair958da932020-08-21 17:12:37 -07007381 setFocusedWindow(windowTop);
7382 windowTop->consumeFocusEvent(true);
7383
Chavi Weingarten847e8512023-03-29 00:26:09 +00007384 windowTop->editInfo()->focusTransferTarget = windowSecond->getToken();
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07007385 mDispatcher->onWindowInfosChanged(
7386 {{*windowTop->getInfo(), *windowSecond->getInfo()}, {}, 0, 0});
Vishnu Nair958da932020-08-21 17:12:37 -07007387 windowSecond->consumeFocusEvent(true);
7388 windowTop->consumeFocusEvent(false);
7389
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07007390 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectKeyDown(*mDispatcher))
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08007391 << "Inject key event should return InputEventInjectionResult::SUCCEEDED";
Vishnu Nair958da932020-08-21 17:12:37 -07007392
7393 // Focused window should receive event.
Linnan Li13bf76a2024-05-05 19:18:02 +08007394 windowSecond->consumeKeyDown(ui::ADISPLAY_ID_NONE);
Vishnu Nair958da932020-08-21 17:12:37 -07007395}
7396
Chavi Weingarten847e8512023-03-29 00:26:09 +00007397TEST_F(InputDispatcherTest, SetFocusedWindow_TransferFocusTokenNotFocusable) {
Vishnu Nair958da932020-08-21 17:12:37 -07007398 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
7399 sp<FakeWindowHandle> windowTop =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07007400 sp<FakeWindowHandle>::make(application, mDispatcher, "Top", ADISPLAY_ID_DEFAULT);
Vishnu Nair958da932020-08-21 17:12:37 -07007401 sp<FakeWindowHandle> windowSecond =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07007402 sp<FakeWindowHandle>::make(application, mDispatcher, "Second", ADISPLAY_ID_DEFAULT);
Vishnu Nair958da932020-08-21 17:12:37 -07007403 mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application);
7404
7405 windowTop->setFocusable(true);
Chavi Weingarten847e8512023-03-29 00:26:09 +00007406 windowSecond->setFocusable(false);
7407 windowTop->editInfo()->focusTransferTarget = windowSecond->getToken();
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07007408 mDispatcher->onWindowInfosChanged(
7409 {{*windowTop->getInfo(), *windowSecond->getInfo()}, {}, 0, 0});
Chavi Weingarten847e8512023-03-29 00:26:09 +00007410 setFocusedWindow(windowTop);
7411 windowTop->consumeFocusEvent(true);
Vishnu Nair958da932020-08-21 17:12:37 -07007412
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07007413 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectKeyDown(*mDispatcher))
Chavi Weingarten847e8512023-03-29 00:26:09 +00007414 << "Inject key event should return InputEventInjectionResult::SUCCEEDED";
Vishnu Nair958da932020-08-21 17:12:37 -07007415
7416 // Event should be dropped.
Linnan Li13bf76a2024-05-05 19:18:02 +08007417 windowTop->consumeKeyDown(ui::ADISPLAY_ID_NONE);
Vishnu Nair958da932020-08-21 17:12:37 -07007418 windowSecond->assertNoEvents();
7419}
7420
7421TEST_F(InputDispatcherTest, SetFocusedWindow_DeferInvisibleWindow) {
7422 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
7423 sp<FakeWindowHandle> window =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07007424 sp<FakeWindowHandle>::make(application, mDispatcher, "TestWindow", ADISPLAY_ID_DEFAULT);
Vishnu Nair958da932020-08-21 17:12:37 -07007425 sp<FakeWindowHandle> previousFocusedWindow =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07007426 sp<FakeWindowHandle>::make(application, mDispatcher, "previousFocusedWindow",
7427 ADISPLAY_ID_DEFAULT);
Vishnu Nair958da932020-08-21 17:12:37 -07007428 mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application);
7429
7430 window->setFocusable(true);
7431 previousFocusedWindow->setFocusable(true);
7432 window->setVisible(false);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07007433 mDispatcher->onWindowInfosChanged(
7434 {{*window->getInfo(), *previousFocusedWindow->getInfo()}, {}, 0, 0});
Vishnu Nair958da932020-08-21 17:12:37 -07007435 setFocusedWindow(previousFocusedWindow);
7436 previousFocusedWindow->consumeFocusEvent(true);
7437
7438 // Requesting focus on invisible window takes focus from currently focused window.
7439 setFocusedWindow(window);
7440 previousFocusedWindow->consumeFocusEvent(false);
7441
7442 // Injected key goes to pending queue.
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08007443 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07007444 injectKey(*mDispatcher, AKEY_EVENT_ACTION_DOWN, /*repeatCount=*/0,
7445 ADISPLAY_ID_DEFAULT, InputEventInjectionSync::NONE));
Vishnu Nair958da932020-08-21 17:12:37 -07007446
7447 // Window does not get focus event or key down.
7448 window->assertNoEvents();
7449
7450 // Window becomes visible.
7451 window->setVisible(true);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07007452 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Vishnu Nair958da932020-08-21 17:12:37 -07007453
7454 // Window receives focus event.
7455 window->consumeFocusEvent(true);
7456 // Focused window receives key down.
7457 window->consumeKeyDown(ADISPLAY_ID_DEFAULT);
7458}
7459
Vishnu Nair599f1412021-06-21 10:39:58 -07007460TEST_F(InputDispatcherTest, DisplayRemoved) {
7461 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
7462 sp<FakeWindowHandle> window =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07007463 sp<FakeWindowHandle>::make(application, mDispatcher, "window", ADISPLAY_ID_DEFAULT);
Vishnu Nair599f1412021-06-21 10:39:58 -07007464 mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application);
7465
7466 // window is granted focus.
7467 window->setFocusable(true);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07007468 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Vishnu Nair599f1412021-06-21 10:39:58 -07007469 setFocusedWindow(window);
7470 window->consumeFocusEvent(true);
7471
7472 // When a display is removed window loses focus.
7473 mDispatcher->displayRemoved(ADISPLAY_ID_DEFAULT);
7474 window->consumeFocusEvent(false);
7475}
7476
Siarhei Vishniakou870ecec2020-12-09 08:07:46 -10007477/**
7478 * Launch two windows, with different owners. One window (slipperyExitWindow) has Flag::SLIPPERY,
7479 * and overlaps the other window, slipperyEnterWindow. The window 'slipperyExitWindow' is on top
7480 * of the 'slipperyEnterWindow'.
7481 *
7482 * Inject touch down into the top window. Upon receipt of the DOWN event, move the window in such
7483 * a way so that the touched location is no longer covered by the top window.
7484 *
7485 * Next, inject a MOVE event. Because the top window already moved earlier, this event is now
7486 * positioned over the bottom (slipperyEnterWindow) only. And because the top window had
7487 * Flag::SLIPPERY, this will cause the top window to lose the touch event (it will receive
7488 * ACTION_CANCEL instead), and the bottom window will receive a newly generated gesture (starting
7489 * with ACTION_DOWN).
7490 * Thus, the touch has been transferred from the top window into the bottom window, because the top
7491 * window moved itself away from the touched location and had Flag::SLIPPERY.
7492 *
7493 * Even though the top window moved away from the touched location, it is still obscuring the bottom
7494 * window. It's just not obscuring it at the touched location. That means, FLAG_WINDOW_IS_PARTIALLY_
7495 * OBSCURED should be set for the MotionEvent that reaches the bottom window.
7496 *
7497 * In this test, we ensure that the event received by the bottom window has
7498 * FLAG_WINDOW_IS_PARTIALLY_OBSCURED.
7499 */
7500TEST_F(InputDispatcherTest, SlipperyWindow_SetsFlagPartiallyObscured) {
Prabir Pradhanaeebeb42023-06-13 19:53:03 +00007501 constexpr gui::Pid SLIPPERY_PID{WINDOW_PID.val() + 1};
Prabir Pradhan8a5c41d2023-06-08 19:13:46 +00007502 constexpr gui::Uid SLIPPERY_UID{WINDOW_UID.val() + 1};
Siarhei Vishniakou870ecec2020-12-09 08:07:46 -10007503
7504 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
7505 mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application);
7506
7507 sp<FakeWindowHandle> slipperyExitWindow =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07007508 sp<FakeWindowHandle>::make(application, mDispatcher, "Top", ADISPLAY_ID_DEFAULT);
Prabir Pradhan4d5c52f2022-01-31 08:52:10 -08007509 slipperyExitWindow->setSlippery(true);
Siarhei Vishniakou870ecec2020-12-09 08:07:46 -10007510 // Make sure this one overlaps the bottom window
7511 slipperyExitWindow->setFrame(Rect(25, 25, 75, 75));
7512 // Change the owner uid/pid of the window so that it is considered to be occluding the bottom
7513 // one. Windows with the same owner are not considered to be occluding each other.
7514 slipperyExitWindow->setOwnerInfo(SLIPPERY_PID, SLIPPERY_UID);
7515
7516 sp<FakeWindowHandle> slipperyEnterWindow =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07007517 sp<FakeWindowHandle>::make(application, mDispatcher, "Second", ADISPLAY_ID_DEFAULT);
Siarhei Vishniakou870ecec2020-12-09 08:07:46 -10007518 slipperyExitWindow->setFrame(Rect(0, 0, 100, 100));
7519
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07007520 mDispatcher->onWindowInfosChanged(
7521 {{*slipperyExitWindow->getInfo(), *slipperyEnterWindow->getInfo()}, {}, 0, 0});
Siarhei Vishniakou870ecec2020-12-09 08:07:46 -10007522
7523 // Use notifyMotion instead of injecting to avoid dealing with injection permissions
Prabir Pradhan678438e2023-04-13 19:32:51 +00007524 mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_DOWN,
7525 AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
7526 {{50, 50}}));
Siarhei Vishniakou870ecec2020-12-09 08:07:46 -10007527 slipperyExitWindow->consumeMotionDown();
7528 slipperyExitWindow->setFrame(Rect(70, 70, 100, 100));
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07007529 mDispatcher->onWindowInfosChanged(
7530 {{*slipperyExitWindow->getInfo(), *slipperyEnterWindow->getInfo()}, {}, 0, 0});
Siarhei Vishniakou870ecec2020-12-09 08:07:46 -10007531
Prabir Pradhan678438e2023-04-13 19:32:51 +00007532 mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_MOVE,
7533 AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
7534 {{51, 51}}));
Siarhei Vishniakou870ecec2020-12-09 08:07:46 -10007535
7536 slipperyExitWindow->consumeMotionCancel();
7537
7538 slipperyEnterWindow->consumeMotionDown(ADISPLAY_ID_DEFAULT,
7539 AMOTION_EVENT_FLAG_WINDOW_IS_PARTIALLY_OBSCURED);
7540}
7541
Siarhei Vishniakouafa08cc2023-05-08 22:35:50 -07007542/**
7543 * Two windows, one on the left and another on the right. The left window is slippery. The right
7544 * window isn't eligible to receive touch because it specifies InputConfig::DROP_INPUT. When the
7545 * touch moves from the left window into the right window, the gesture should continue to go to the
7546 * left window. Touch shouldn't slip because the right window can't receive touches. This test
7547 * reproduces a crash.
7548 */
7549TEST_F(InputDispatcherTest, TouchSlippingIntoWindowThatDropsTouches) {
7550 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
7551
7552 sp<FakeWindowHandle> leftSlipperyWindow =
7553 sp<FakeWindowHandle>::make(application, mDispatcher, "Left", ADISPLAY_ID_DEFAULT);
7554 leftSlipperyWindow->setSlippery(true);
7555 leftSlipperyWindow->setFrame(Rect(0, 0, 100, 100));
7556
7557 sp<FakeWindowHandle> rightDropTouchesWindow =
7558 sp<FakeWindowHandle>::make(application, mDispatcher, "Right", ADISPLAY_ID_DEFAULT);
7559 rightDropTouchesWindow->setFrame(Rect(100, 0, 200, 100));
7560 rightDropTouchesWindow->setDropInput(true);
7561
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07007562 mDispatcher->onWindowInfosChanged(
7563 {{*leftSlipperyWindow->getInfo(), *rightDropTouchesWindow->getInfo()}, {}, 0, 0});
Siarhei Vishniakouafa08cc2023-05-08 22:35:50 -07007564
7565 // Start touch in the left window
7566 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
7567 .pointer(PointerBuilder(0, ToolType::FINGER).x(50).y(50))
7568 .build());
7569 leftSlipperyWindow->consumeMotionDown();
7570
7571 // And move it into the right window
7572 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN)
7573 .pointer(PointerBuilder(0, ToolType::FINGER).x(150).y(50))
7574 .build());
7575
7576 // Since the right window isn't eligible to receive input, touch does not slip.
7577 // The left window continues to receive the gesture.
7578 leftSlipperyWindow->consumeMotionEvent(WithMotionAction(ACTION_MOVE));
7579 rightDropTouchesWindow->assertNoEvents();
7580}
7581
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -07007582/**
7583 * A single window is on screen first. Touch is injected into that window. Next, a second window
7584 * appears. Since the first window is slippery, touch will move from the first window to the second.
7585 */
7586TEST_F(InputDispatcherTest, InjectedTouchSlips) {
7587 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
7588 sp<FakeWindowHandle> originalWindow =
7589 sp<FakeWindowHandle>::make(application, mDispatcher, "Original", ADISPLAY_ID_DEFAULT);
7590 originalWindow->setFrame(Rect(0, 0, 200, 200));
7591 originalWindow->setSlippery(true);
7592
7593 sp<FakeWindowHandle> appearingWindow =
7594 sp<FakeWindowHandle>::make(application, mDispatcher, "Appearing", ADISPLAY_ID_DEFAULT);
7595 appearingWindow->setFrame(Rect(0, 0, 200, 200));
7596
7597 mDispatcher->onWindowInfosChanged({{*originalWindow->getInfo()}, {}, 0, 0});
7598
7599 // Touch down on the original window
7600 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
7601 injectMotionEvent(*mDispatcher,
7602 MotionEventBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
7603 .pointer(PointerBuilder(1, ToolType::FINGER).x(100).y(100))
7604 .build()));
7605 originalWindow->consumeMotionEvent(WithMotionAction(ACTION_DOWN));
7606
7607 // Now, a new window appears. This could be, for example, a notification shade that appears
7608 // after user starts to drag down on the launcher window.
7609 mDispatcher->onWindowInfosChanged(
7610 {{*appearingWindow->getInfo(), *originalWindow->getInfo()}, {}, 0, 0});
7611 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
7612 injectMotionEvent(*mDispatcher,
7613 MotionEventBuilder(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN)
7614 .pointer(PointerBuilder(1, ToolType::FINGER).x(110).y(110))
7615 .build()));
7616 originalWindow->consumeMotionEvent(WithMotionAction(ACTION_CANCEL));
7617 appearingWindow->consumeMotionEvent(WithMotionAction(ACTION_DOWN));
7618 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
7619 injectMotionEvent(*mDispatcher,
7620 MotionEventBuilder(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN)
7621 .pointer(PointerBuilder(1, ToolType::FINGER).x(120).y(120))
7622 .build()));
7623 appearingWindow->consumeMotionEvent(WithMotionAction(ACTION_MOVE));
7624
7625 originalWindow->assertNoEvents();
7626 appearingWindow->assertNoEvents();
7627}
7628
Linnan Li49b2b202024-04-12 12:46:40 +08007629/**
7630 * Three windows:
7631 * - left window, which has FLAG_SLIPPERY, so it supports slippery exit
7632 * - right window
7633 * - spy window
7634 * The three windows do not overlap.
7635 *
7636 * We have two devices reporting events:
7637 * - Device A reports ACTION_DOWN, which lands in the left window
7638 * - Device B reports ACTION_DOWN, which lands in the spy window.
7639 * - Now, device B reports ACTION_MOVE events which move to the right window.
7640 *
7641 * The right window should not receive any events because the spy window is not a foreground window,
7642 * and also it does not support slippery touches.
7643 */
7644TEST_F(InputDispatcherTest, MultiDeviceSpyWindowSlipTest) {
7645 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
7646 sp<FakeWindowHandle> leftWindow =
7647 sp<FakeWindowHandle>::make(application, mDispatcher, "Left window",
7648 ADISPLAY_ID_DEFAULT);
7649 leftWindow->setFrame(Rect(0, 0, 100, 100));
7650 leftWindow->setSlippery(true);
7651
7652 sp<FakeWindowHandle> rightWindow =
7653 sp<FakeWindowHandle>::make(application, mDispatcher, "Right window",
7654 ADISPLAY_ID_DEFAULT);
7655 rightWindow->setFrame(Rect(100, 0, 200, 100));
7656
7657 sp<FakeWindowHandle> spyWindow =
7658 sp<FakeWindowHandle>::make(application, mDispatcher, "Spy Window", ADISPLAY_ID_DEFAULT);
7659 spyWindow->setFrame(Rect(200, 0, 300, 100));
7660 spyWindow->setSpy(true);
7661 spyWindow->setTrustedOverlay(true);
7662
7663 mDispatcher->onWindowInfosChanged(
7664 {{*leftWindow->getInfo(), *rightWindow->getInfo(), *spyWindow->getInfo()}, {}, 0, 0});
7665
7666 const DeviceId deviceA = 9;
7667 const DeviceId deviceB = 3;
7668
7669 // Tap on left window with device A
7670 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
7671 .pointer(PointerBuilder(0, ToolType::FINGER).x(50).y(50))
7672 .deviceId(deviceA)
7673 .build());
7674 leftWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(deviceA)));
7675
7676 // Tap on spy window with device B
7677 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
7678 .pointer(PointerBuilder(0, ToolType::FINGER).x(250).y(50))
7679 .deviceId(deviceB)
7680 .build());
7681 spyWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(deviceB)));
7682
7683 // Move to right window with device B. Touches should not slip to the right window, because spy
7684 // window is not a foreground window, and it does not have FLAG_SLIPPERY
7685 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN)
7686 .pointer(PointerBuilder(0, ToolType::FINGER).x(150).y(50))
7687 .deviceId(deviceB)
7688 .build());
7689 leftWindow->assertNoEvents();
7690 rightWindow->assertNoEvents();
7691 spyWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(deviceB)));
7692}
7693
7694/**
7695 * Three windows arranged horizontally and without any overlap.
7696 * The left and right windows have FLAG_SLIPPERY. The middle window does not have any special flags.
7697 *
7698 * We have two devices reporting events:
7699 * - Device A reports ACTION_DOWN which lands in the left window
7700 * - Device B reports ACTION_DOWN which lands in the right window
7701 * - Device B reports ACTION_MOVE that shifts to the middle window.
7702 * This should cause touches for Device B to slip from the right window to the middle window.
7703 * The right window should receive ACTION_CANCEL for device B and the
7704 * middle window should receive down event for Device B.
7705 * If device B reports more ACTION_MOVE events, the middle window should receive remaining events.
7706 */
7707TEST_F(InputDispatcherTest, MultiDeviceSlipperyWindowTest) {
7708 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
7709 sp<FakeWindowHandle> leftWindow =
7710 sp<FakeWindowHandle>::make(application, mDispatcher, "Left window",
7711 ADISPLAY_ID_DEFAULT);
7712 leftWindow->setFrame(Rect(0, 0, 100, 100));
7713 leftWindow->setSlippery(true);
7714
7715 sp<FakeWindowHandle> middleWindow =
7716 sp<FakeWindowHandle>::make(application, mDispatcher, "middle window",
7717 ADISPLAY_ID_DEFAULT);
7718 middleWindow->setFrame(Rect(100, 0, 200, 100));
7719
7720 sp<FakeWindowHandle> rightWindow =
7721 sp<FakeWindowHandle>::make(application, mDispatcher, "Right window",
7722 ADISPLAY_ID_DEFAULT);
7723 rightWindow->setFrame(Rect(200, 0, 300, 100));
7724 rightWindow->setSlippery(true);
7725
7726 mDispatcher->onWindowInfosChanged(
7727 {{*leftWindow->getInfo(), *middleWindow->getInfo(), *rightWindow->getInfo()},
7728 {},
7729 0,
7730 0});
7731
7732 const DeviceId deviceA = 9;
7733 const DeviceId deviceB = 3;
7734
7735 // Tap on left window with device A
7736 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
7737 .pointer(PointerBuilder(0, ToolType::FINGER).x(50).y(50))
7738 .deviceId(deviceA)
7739 .build());
7740 leftWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(deviceA)));
7741
7742 // Tap on right window with device B
7743 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
7744 .pointer(PointerBuilder(0, ToolType::FINGER).x(250).y(50))
7745 .deviceId(deviceB)
7746 .build());
7747 rightWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(deviceB)));
7748
7749 // Move to middle window with device B. Touches should slip to middle window, because right
7750 // window is a foreground window that's associated with device B and has FLAG_SLIPPERY.
7751 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN)
7752 .pointer(PointerBuilder(0, ToolType::FINGER).x(150).y(50))
7753 .deviceId(deviceB)
7754 .build());
7755 rightWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_CANCEL), WithDeviceId(deviceB)));
7756 middleWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(deviceB)));
7757
7758 // Move to middle window with device A. Touches should slip to middle window, because left
7759 // window is a foreground window that's associated with device A and has FLAG_SLIPPERY.
7760 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN)
7761 .pointer(PointerBuilder(0, ToolType::FINGER).x(150).y(50))
7762 .deviceId(deviceA)
7763 .build());
7764 leftWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_CANCEL), WithDeviceId(deviceA)));
7765 middleWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(deviceA)));
7766
7767 // Ensure that middle window can receive the remaining move events.
7768 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN)
7769 .pointer(PointerBuilder(0, ToolType::FINGER).x(151).y(51))
7770 .deviceId(deviceB)
7771 .build());
7772 leftWindow->assertNoEvents();
7773 middleWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(deviceB)));
7774 rightWindow->assertNoEvents();
7775}
7776
Prabir Pradhan8ede1d12023-05-08 19:37:44 +00007777TEST_F(InputDispatcherTest, NotifiesDeviceInteractionsWithMotions) {
Prabir Pradhan8a5c41d2023-06-08 19:13:46 +00007778 using Uid = gui::Uid;
Prabir Pradhan8ede1d12023-05-08 19:37:44 +00007779 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
7780
7781 sp<FakeWindowHandle> leftWindow =
7782 sp<FakeWindowHandle>::make(application, mDispatcher, "Left", ADISPLAY_ID_DEFAULT);
7783 leftWindow->setFrame(Rect(0, 0, 100, 100));
Prabir Pradhanaeebeb42023-06-13 19:53:03 +00007784 leftWindow->setOwnerInfo(gui::Pid{1}, Uid{101});
Prabir Pradhan8ede1d12023-05-08 19:37:44 +00007785
7786 sp<FakeWindowHandle> rightSpy =
7787 sp<FakeWindowHandle>::make(application, mDispatcher, "Right spy", ADISPLAY_ID_DEFAULT);
7788 rightSpy->setFrame(Rect(100, 0, 200, 100));
Prabir Pradhanaeebeb42023-06-13 19:53:03 +00007789 rightSpy->setOwnerInfo(gui::Pid{2}, Uid{102});
Prabir Pradhan8ede1d12023-05-08 19:37:44 +00007790 rightSpy->setSpy(true);
7791 rightSpy->setTrustedOverlay(true);
7792
7793 sp<FakeWindowHandle> rightWindow =
7794 sp<FakeWindowHandle>::make(application, mDispatcher, "Right", ADISPLAY_ID_DEFAULT);
7795 rightWindow->setFrame(Rect(100, 0, 200, 100));
Prabir Pradhanaeebeb42023-06-13 19:53:03 +00007796 rightWindow->setOwnerInfo(gui::Pid{3}, Uid{103});
Prabir Pradhan8ede1d12023-05-08 19:37:44 +00007797
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07007798 mDispatcher->onWindowInfosChanged(
7799 {{*rightSpy->getInfo(), *rightWindow->getInfo(), *leftWindow->getInfo()}, {}, 0, 0});
Prabir Pradhan8ede1d12023-05-08 19:37:44 +00007800
7801 // Touch in the left window
7802 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
7803 .pointer(PointerBuilder(0, ToolType::FINGER).x(50).y(50))
7804 .build());
7805 ASSERT_NO_FATAL_FAILURE(leftWindow->consumeMotionDown());
7806 mDispatcher->waitForIdle();
Prabir Pradhan8a5c41d2023-06-08 19:13:46 +00007807 ASSERT_NO_FATAL_FAILURE(
7808 mFakePolicy->assertNotifyDeviceInteractionWasCalled(DEVICE_ID, {Uid{101}}));
Prabir Pradhan8ede1d12023-05-08 19:37:44 +00007809
7810 // Touch another finger over the right windows
7811 mDispatcher->notifyMotion(MotionArgsBuilder(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
7812 .pointer(PointerBuilder(0, ToolType::FINGER).x(50).y(50))
7813 .pointer(PointerBuilder(1, ToolType::FINGER).x(150).y(50))
7814 .build());
7815 ASSERT_NO_FATAL_FAILURE(rightSpy->consumeMotionDown());
7816 ASSERT_NO_FATAL_FAILURE(rightWindow->consumeMotionDown());
7817 ASSERT_NO_FATAL_FAILURE(leftWindow->consumeMotionMove());
7818 mDispatcher->waitForIdle();
7819 ASSERT_NO_FATAL_FAILURE(
Prabir Pradhan8a5c41d2023-06-08 19:13:46 +00007820 mFakePolicy->assertNotifyDeviceInteractionWasCalled(DEVICE_ID,
7821 {Uid{101}, Uid{102}, Uid{103}}));
Prabir Pradhan8ede1d12023-05-08 19:37:44 +00007822
7823 // Release finger over left window. The UP actions are not treated as device interaction.
7824 // The windows that did not receive the UP pointer will receive MOVE events, but since this
7825 // is part of the UP action, we do not treat this as device interaction.
7826 mDispatcher->notifyMotion(MotionArgsBuilder(POINTER_0_UP, AINPUT_SOURCE_TOUCHSCREEN)
7827 .pointer(PointerBuilder(0, ToolType::FINGER).x(50).y(50))
7828 .pointer(PointerBuilder(1, ToolType::FINGER).x(150).y(50))
7829 .build());
7830 ASSERT_NO_FATAL_FAILURE(leftWindow->consumeMotionUp());
7831 ASSERT_NO_FATAL_FAILURE(rightSpy->consumeMotionMove());
7832 ASSERT_NO_FATAL_FAILURE(rightWindow->consumeMotionMove());
7833 mDispatcher->waitForIdle();
7834 ASSERT_NO_FATAL_FAILURE(mFakePolicy->assertNotifyDeviceInteractionWasNotCalled());
7835
7836 // Move remaining finger
7837 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN)
7838 .pointer(PointerBuilder(1, ToolType::FINGER).x(150).y(50))
7839 .build());
7840 ASSERT_NO_FATAL_FAILURE(rightSpy->consumeMotionMove());
7841 ASSERT_NO_FATAL_FAILURE(rightWindow->consumeMotionMove());
7842 mDispatcher->waitForIdle();
7843 ASSERT_NO_FATAL_FAILURE(
Prabir Pradhan8a5c41d2023-06-08 19:13:46 +00007844 mFakePolicy->assertNotifyDeviceInteractionWasCalled(DEVICE_ID, {Uid{102}, Uid{103}}));
Prabir Pradhan8ede1d12023-05-08 19:37:44 +00007845
7846 // Release all fingers
7847 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN)
7848 .pointer(PointerBuilder(1, ToolType::FINGER).x(150).y(50))
7849 .build());
7850 ASSERT_NO_FATAL_FAILURE(rightSpy->consumeMotionUp());
7851 ASSERT_NO_FATAL_FAILURE(rightWindow->consumeMotionUp());
7852 mDispatcher->waitForIdle();
7853 ASSERT_NO_FATAL_FAILURE(mFakePolicy->assertNotifyDeviceInteractionWasNotCalled());
7854}
7855
7856TEST_F(InputDispatcherTest, NotifiesDeviceInteractionsWithKeys) {
7857 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
7858
7859 sp<FakeWindowHandle> window =
7860 sp<FakeWindowHandle>::make(application, mDispatcher, "Window", ADISPLAY_ID_DEFAULT);
7861 window->setFrame(Rect(0, 0, 100, 100));
Prabir Pradhanaeebeb42023-06-13 19:53:03 +00007862 window->setOwnerInfo(gui::Pid{1}, gui::Uid{101});
Prabir Pradhan8ede1d12023-05-08 19:37:44 +00007863
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07007864 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Prabir Pradhan8ede1d12023-05-08 19:37:44 +00007865 setFocusedWindow(window);
7866 ASSERT_NO_FATAL_FAILURE(window->consumeFocusEvent(true));
7867
7868 mDispatcher->notifyKey(KeyArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_KEYBOARD).build());
7869 ASSERT_NO_FATAL_FAILURE(window->consumeKeyDown(ADISPLAY_ID_DEFAULT));
7870 mDispatcher->waitForIdle();
Prabir Pradhan8a5c41d2023-06-08 19:13:46 +00007871 ASSERT_NO_FATAL_FAILURE(
7872 mFakePolicy->assertNotifyDeviceInteractionWasCalled(DEVICE_ID, {gui::Uid{101}}));
Prabir Pradhan8ede1d12023-05-08 19:37:44 +00007873
7874 // The UP actions are not treated as device interaction.
7875 mDispatcher->notifyKey(KeyArgsBuilder(ACTION_UP, AINPUT_SOURCE_KEYBOARD).build());
7876 ASSERT_NO_FATAL_FAILURE(window->consumeKeyUp(ADISPLAY_ID_DEFAULT));
7877 mDispatcher->waitForIdle();
7878 ASSERT_NO_FATAL_FAILURE(mFakePolicy->assertNotifyDeviceInteractionWasNotCalled());
7879}
7880
Prabir Pradhan5893d362023-11-17 04:30:40 +00007881TEST_F(InputDispatcherTest, HoverEnterExitSynthesisUsesNewEventId) {
7882 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
7883
7884 sp<FakeWindowHandle> left = sp<FakeWindowHandle>::make(application, mDispatcher, "Left Window",
7885 ADISPLAY_ID_DEFAULT);
7886 left->setFrame(Rect(0, 0, 100, 100));
7887 sp<FakeWindowHandle> right = sp<FakeWindowHandle>::make(application, mDispatcher,
7888 "Right Window", ADISPLAY_ID_DEFAULT);
7889 right->setFrame(Rect(100, 0, 200, 100));
7890 sp<FakeWindowHandle> spy =
7891 sp<FakeWindowHandle>::make(application, mDispatcher, "Spy Window", ADISPLAY_ID_DEFAULT);
7892 spy->setFrame(Rect(0, 0, 200, 100));
7893 spy->setTrustedOverlay(true);
7894 spy->setSpy(true);
7895
7896 mDispatcher->onWindowInfosChanged(
7897 {{*spy->getInfo(), *left->getInfo(), *right->getInfo()}, {}, 0, 0});
7898
7899 // Send hover move to the left window, and ensure hover enter is synthesized with a new eventId.
7900 NotifyMotionArgs notifyArgs = generateMotionArgs(ACTION_HOVER_MOVE, AINPUT_SOURCE_STYLUS,
7901 ADISPLAY_ID_DEFAULT, {PointF{50, 50}});
7902 mDispatcher->notifyMotion(notifyArgs);
7903
Siarhei Vishniakoud3061ab2023-12-18 20:41:08 -08007904 std::unique_ptr<MotionEvent> leftEnter = left->consumeMotionEvent(
Prabir Pradhan5893d362023-11-17 04:30:40 +00007905 AllOf(WithMotionAction(ACTION_HOVER_ENTER), Not(WithEventId(notifyArgs.id)),
7906 WithEventIdSource(IdGenerator::Source::INPUT_DISPATCHER)));
Siarhei Vishniakoud3061ab2023-12-18 20:41:08 -08007907 ASSERT_NE(nullptr, leftEnter);
Prabir Pradhan5893d362023-11-17 04:30:40 +00007908 spy->consumeMotionEvent(AllOf(WithMotionAction(ACTION_HOVER_ENTER),
7909 Not(WithEventId(notifyArgs.id)),
Siarhei Vishniakoud3061ab2023-12-18 20:41:08 -08007910 Not(WithEventId(leftEnter->getId())),
Prabir Pradhan5893d362023-11-17 04:30:40 +00007911 WithEventIdSource(IdGenerator::Source::INPUT_DISPATCHER)));
7912
7913 // Send move to the right window, and ensure hover exit and enter are synthesized with new ids.
7914 notifyArgs = generateMotionArgs(ACTION_HOVER_MOVE, AINPUT_SOURCE_STYLUS, ADISPLAY_ID_DEFAULT,
7915 {PointF{150, 50}});
7916 mDispatcher->notifyMotion(notifyArgs);
7917
Siarhei Vishniakoud3061ab2023-12-18 20:41:08 -08007918 std::unique_ptr<MotionEvent> leftExit = left->consumeMotionEvent(
Prabir Pradhan5893d362023-11-17 04:30:40 +00007919 AllOf(WithMotionAction(ACTION_HOVER_EXIT), Not(WithEventId(notifyArgs.id)),
7920 WithEventIdSource(IdGenerator::Source::INPUT_DISPATCHER)));
Siarhei Vishniakoud3061ab2023-12-18 20:41:08 -08007921 ASSERT_NE(nullptr, leftExit);
Prabir Pradhan5893d362023-11-17 04:30:40 +00007922 right->consumeMotionEvent(AllOf(WithMotionAction(ACTION_HOVER_ENTER),
7923 Not(WithEventId(notifyArgs.id)),
Siarhei Vishniakoud3061ab2023-12-18 20:41:08 -08007924 Not(WithEventId(leftExit->getId())),
Prabir Pradhan5893d362023-11-17 04:30:40 +00007925 WithEventIdSource(IdGenerator::Source::INPUT_DISPATCHER)));
7926
7927 spy->consumeMotionEvent(AllOf(WithMotionAction(ACTION_HOVER_MOVE), WithEventId(notifyArgs.id)));
7928}
7929
Linnan Liccf6ce32024-04-11 20:32:13 +08007930/**
7931 * When a device reports a DOWN event, which lands in a window that supports splits, and then the
7932 * device then reports a POINTER_DOWN, which lands in the location of a non-existing window, then
7933 * the previous window should receive this event and not be dropped.
7934 */
7935TEST_F(InputDispatcherMultiDeviceTest, SingleDevicePointerDownEventRetentionWithoutWindowTarget) {
7936 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
7937 sp<FakeWindowHandle> window =
7938 sp<FakeWindowHandle>::make(application, mDispatcher, "Window", ADISPLAY_ID_DEFAULT);
7939 window->setFrame(Rect(0, 0, 100, 100));
7940 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
7941
7942 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
7943 .pointer(PointerBuilder(0, ToolType::FINGER).x(50).y(50))
7944 .build());
7945
7946 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN)));
7947
7948 mDispatcher->notifyMotion(MotionArgsBuilder(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
7949 .pointer(PointerBuilder(0, ToolType::FINGER).x(50).y(50))
7950 .pointer(PointerBuilder(1, ToolType::FINGER).x(200).y(200))
7951 .build());
7952
7953 window->consumeMotionEvent(AllOf(WithMotionAction(POINTER_1_DOWN)));
7954}
7955
7956/**
7957 * When deviceA reports a DOWN event, which lands in a window that supports splits, and then deviceB
7958 * also reports a DOWN event, which lands in the location of a non-existing window, then the
7959 * previous window should receive deviceB's event and it should be dropped.
7960 */
7961TEST_F(InputDispatcherMultiDeviceTest, SecondDeviceDownEventDroppedWithoutWindowTarget) {
7962 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
7963 sp<FakeWindowHandle> window =
7964 sp<FakeWindowHandle>::make(application, mDispatcher, "Window", ADISPLAY_ID_DEFAULT);
7965 window->setFrame(Rect(0, 0, 100, 100));
7966 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
7967
7968 const DeviceId deviceA = 9;
7969 const DeviceId deviceB = 3;
7970
7971 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
7972 .pointer(PointerBuilder(0, ToolType::FINGER).x(50).y(50))
7973 .deviceId(deviceA)
7974 .build());
7975 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(deviceA)));
7976
7977 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
7978 .pointer(PointerBuilder(0, ToolType::FINGER).x(200).y(200))
7979 .deviceId(deviceB)
7980 .build());
7981 window->assertNoEvents();
7982}
7983
Prabir Pradhanb0dad3a2023-11-02 20:52:47 +00007984class InputDispatcherFallbackKeyTest : public InputDispatcherTest {
7985protected:
7986 std::shared_ptr<FakeApplicationHandle> mApp;
7987 sp<FakeWindowHandle> mWindow;
7988
7989 virtual void SetUp() override {
7990 InputDispatcherTest::SetUp();
7991
7992 mApp = std::make_shared<FakeApplicationHandle>();
7993
7994 mWindow = sp<FakeWindowHandle>::make(mApp, mDispatcher, "Window", ADISPLAY_ID_DEFAULT);
7995 mWindow->setFrame(Rect(0, 0, 100, 100));
7996
7997 mDispatcher->onWindowInfosChanged({{*mWindow->getInfo()}, {}, 0, 0});
7998 setFocusedWindow(mWindow);
7999 ASSERT_NO_FATAL_FAILURE(mWindow->consumeFocusEvent(/*hasFocus=*/true));
8000 }
8001
8002 void setFallback(int32_t keycode) {
8003 mFakePolicy->setUnhandledKeyHandler([keycode](const KeyEvent& event) {
8004 return KeyEventBuilder(event).keyCode(keycode).build();
8005 });
8006 }
8007
8008 void consumeKey(bool handled, const ::testing::Matcher<KeyEvent>& matcher) {
Siarhei Vishniakoud3061ab2023-12-18 20:41:08 -08008009 std::unique_ptr<KeyEvent> event = mWindow->consumeKey(handled);
8010 ASSERT_NE(nullptr, event);
8011 ASSERT_THAT(*event, matcher);
Prabir Pradhanb0dad3a2023-11-02 20:52:47 +00008012 }
8013};
8014
8015TEST_F(InputDispatcherFallbackKeyTest, PolicyNotNotifiedForHandledKey) {
8016 mDispatcher->notifyKey(
8017 KeyArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_KEYBOARD).keyCode(AKEYCODE_A).build());
8018 consumeKey(/*handled=*/true, AllOf(WithKeyAction(ACTION_DOWN), WithKeyCode(AKEYCODE_A)));
8019 ASSERT_NO_FATAL_FAILURE(mFakePolicy->assertUnhandledKeyNotReported());
8020}
8021
8022TEST_F(InputDispatcherFallbackKeyTest, PolicyNotifiedForUnhandledKey) {
8023 mDispatcher->notifyKey(
8024 KeyArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_KEYBOARD).keyCode(AKEYCODE_A).build());
8025 consumeKey(/*handled=*/false, AllOf(WithKeyAction(ACTION_DOWN), WithKeyCode(AKEYCODE_A)));
8026 ASSERT_NO_FATAL_FAILURE(mFakePolicy->assertUnhandledKeyReported(AKEYCODE_A));
8027}
8028
8029TEST_F(InputDispatcherFallbackKeyTest, NoFallbackRequestedByPolicy) {
8030 mDispatcher->notifyKey(
8031 KeyArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_KEYBOARD).keyCode(AKEYCODE_A).build());
8032
8033 // Do not handle this key event.
8034 consumeKey(/*handled=*/false,
8035 AllOf(WithKeyAction(ACTION_DOWN), WithKeyCode(AKEYCODE_A), WithFlags(0)));
8036 ASSERT_NO_FATAL_FAILURE(mFakePolicy->assertUnhandledKeyReported(AKEYCODE_A));
8037
8038 // Since the policy did not request any fallback to be generated, ensure there are no events.
8039 ASSERT_NO_FATAL_FAILURE(mFakePolicy->assertUnhandledKeyNotReported());
8040}
8041
8042TEST_F(InputDispatcherFallbackKeyTest, FallbackDispatchForUnhandledKey) {
8043 setFallback(AKEYCODE_B);
8044 mDispatcher->notifyKey(
8045 KeyArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_KEYBOARD).keyCode(AKEYCODE_A).build());
8046
8047 // Do not handle this key event.
8048 consumeKey(/*handled=*/false,
8049 AllOf(WithKeyAction(ACTION_DOWN), WithKeyCode(AKEYCODE_A), WithFlags(0)));
8050
8051 // Since the key was not handled, ensure the fallback event was dispatched instead.
8052 ASSERT_NO_FATAL_FAILURE(mFakePolicy->assertUnhandledKeyReported(AKEYCODE_A));
8053 consumeKey(/*handled=*/true,
8054 AllOf(WithKeyAction(ACTION_DOWN), WithKeyCode(AKEYCODE_B),
8055 WithFlags(AKEY_EVENT_FLAG_FALLBACK)));
8056
8057 // Release the original key, and ensure the fallback key is also released.
8058 mDispatcher->notifyKey(
8059 KeyArgsBuilder(ACTION_UP, AINPUT_SOURCE_KEYBOARD).keyCode(AKEYCODE_A).build());
8060 consumeKey(/*handled=*/false,
8061 AllOf(WithKeyAction(ACTION_UP), WithKeyCode(AKEYCODE_A), WithFlags(0)));
8062 ASSERT_NO_FATAL_FAILURE(mFakePolicy->assertUnhandledKeyReported(AKEYCODE_A));
8063 consumeKey(/*handled=*/true,
8064 AllOf(WithKeyAction(ACTION_UP), WithKeyCode(AKEYCODE_B),
8065 WithFlags(AKEY_EVENT_FLAG_FALLBACK)));
8066
8067 ASSERT_NO_FATAL_FAILURE(mFakePolicy->assertUnhandledKeyNotReported());
8068 mWindow->assertNoEvents();
8069}
8070
8071TEST_F(InputDispatcherFallbackKeyTest, AppHandlesPreviouslyUnhandledKey) {
8072 setFallback(AKEYCODE_B);
8073 mDispatcher->notifyKey(
8074 KeyArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_KEYBOARD).keyCode(AKEYCODE_A).build());
8075
8076 // Do not handle this key event, but handle the fallback.
8077 consumeKey(/*handled=*/false,
8078 AllOf(WithKeyAction(ACTION_DOWN), WithKeyCode(AKEYCODE_A), WithFlags(0)));
8079 ASSERT_NO_FATAL_FAILURE(mFakePolicy->assertUnhandledKeyReported(AKEYCODE_A));
8080 consumeKey(/*handled=*/true,
8081 AllOf(WithKeyAction(ACTION_DOWN), WithKeyCode(AKEYCODE_B),
8082 WithFlags(AKEY_EVENT_FLAG_FALLBACK)));
8083
8084 // Release the original key, and ensure the fallback key is also released.
8085 mDispatcher->notifyKey(
8086 KeyArgsBuilder(ACTION_UP, AINPUT_SOURCE_KEYBOARD).keyCode(AKEYCODE_A).build());
8087 // But this time, the app handles the original key.
8088 consumeKey(/*handled=*/true,
8089 AllOf(WithKeyAction(ACTION_UP), WithKeyCode(AKEYCODE_A), WithFlags(0)));
8090 ASSERT_NO_FATAL_FAILURE(mFakePolicy->assertUnhandledKeyReported(AKEYCODE_A));
8091 // Ensure the fallback key is canceled.
8092 consumeKey(/*handled=*/true,
8093 AllOf(WithKeyAction(ACTION_UP), WithKeyCode(AKEYCODE_B),
8094 WithFlags(AKEY_EVENT_FLAG_FALLBACK | AKEY_EVENT_FLAG_CANCELED)));
8095
8096 ASSERT_NO_FATAL_FAILURE(mFakePolicy->assertUnhandledKeyNotReported());
8097 mWindow->assertNoEvents();
8098}
8099
8100TEST_F(InputDispatcherFallbackKeyTest, AppDoesNotHandleFallback) {
8101 setFallback(AKEYCODE_B);
8102 mDispatcher->notifyKey(
8103 KeyArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_KEYBOARD).keyCode(AKEYCODE_A).build());
8104
8105 // Do not handle this key event.
8106 consumeKey(/*handled=*/false,
8107 AllOf(WithKeyAction(ACTION_DOWN), WithKeyCode(AKEYCODE_A), WithFlags(0)));
8108 ASSERT_NO_FATAL_FAILURE(mFakePolicy->assertUnhandledKeyReported(AKEYCODE_A));
8109 // App does not handle the fallback either, so ensure another fallback is not generated.
8110 setFallback(AKEYCODE_C);
8111 consumeKey(/*handled=*/false,
8112 AllOf(WithKeyAction(ACTION_DOWN), WithKeyCode(AKEYCODE_B),
8113 WithFlags(AKEY_EVENT_FLAG_FALLBACK)));
8114
8115 // Release the original key, and ensure the fallback key is also released.
8116 setFallback(AKEYCODE_B);
8117 mDispatcher->notifyKey(
8118 KeyArgsBuilder(ACTION_UP, AINPUT_SOURCE_KEYBOARD).keyCode(AKEYCODE_A).build());
8119 consumeKey(/*handled=*/false,
8120 AllOf(WithKeyAction(ACTION_UP), WithKeyCode(AKEYCODE_A), WithFlags(0)));
8121 ASSERT_NO_FATAL_FAILURE(mFakePolicy->assertUnhandledKeyReported(AKEYCODE_A));
8122 consumeKey(/*handled=*/false,
8123 AllOf(WithKeyAction(ACTION_UP), WithKeyCode(AKEYCODE_B),
8124 WithFlags(AKEY_EVENT_FLAG_FALLBACK)));
8125
8126 ASSERT_NO_FATAL_FAILURE(mFakePolicy->assertUnhandledKeyNotReported());
8127 mWindow->assertNoEvents();
8128}
8129
8130TEST_F(InputDispatcherFallbackKeyTest, InconsistentPolicyCancelsFallback) {
8131 setFallback(AKEYCODE_B);
8132 mDispatcher->notifyKey(
8133 KeyArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_KEYBOARD).keyCode(AKEYCODE_A).build());
8134
8135 // Do not handle this key event, so fallback is generated.
8136 consumeKey(/*handled=*/false,
8137 AllOf(WithKeyAction(ACTION_DOWN), WithKeyCode(AKEYCODE_A), WithFlags(0)));
8138 ASSERT_NO_FATAL_FAILURE(mFakePolicy->assertUnhandledKeyReported(AKEYCODE_A));
8139 consumeKey(/*handled=*/true,
8140 AllOf(WithKeyAction(ACTION_DOWN), WithKeyCode(AKEYCODE_B),
8141 WithFlags(AKEY_EVENT_FLAG_FALLBACK)));
8142
8143 // Release the original key, but assume the policy is misbehaving and it
8144 // generates an inconsistent fallback to the one from the DOWN event.
8145 setFallback(AKEYCODE_C);
8146 mDispatcher->notifyKey(
8147 KeyArgsBuilder(ACTION_UP, AINPUT_SOURCE_KEYBOARD).keyCode(AKEYCODE_A).build());
8148 consumeKey(/*handled=*/false,
8149 AllOf(WithKeyAction(ACTION_UP), WithKeyCode(AKEYCODE_A), WithFlags(0)));
8150 ASSERT_NO_FATAL_FAILURE(mFakePolicy->assertUnhandledKeyReported(AKEYCODE_A));
8151 // Ensure the fallback key reported before as DOWN is canceled due to the inconsistency.
8152 consumeKey(/*handled=*/true,
8153 AllOf(WithKeyAction(ACTION_UP), WithKeyCode(AKEYCODE_B),
8154 WithFlags(AKEY_EVENT_FLAG_FALLBACK | AKEY_EVENT_FLAG_CANCELED)));
8155
8156 ASSERT_NO_FATAL_FAILURE(mFakePolicy->assertUnhandledKeyNotReported());
8157 mWindow->assertNoEvents();
8158}
8159
8160TEST_F(InputDispatcherFallbackKeyTest, CanceledKeyCancelsFallback) {
8161 setFallback(AKEYCODE_B);
8162 mDispatcher->notifyKey(
8163 KeyArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_KEYBOARD).keyCode(AKEYCODE_A).build());
8164
8165 // Do not handle this key event, so fallback is generated.
8166 consumeKey(/*handled=*/false,
8167 AllOf(WithKeyAction(ACTION_DOWN), WithKeyCode(AKEYCODE_A), WithFlags(0)));
8168 ASSERT_NO_FATAL_FAILURE(mFakePolicy->assertUnhandledKeyReported(AKEYCODE_A));
8169 consumeKey(/*handled=*/true,
8170 AllOf(WithKeyAction(ACTION_DOWN), WithKeyCode(AKEYCODE_B),
8171 WithFlags(AKEY_EVENT_FLAG_FALLBACK)));
8172
8173 // The original key is canceled.
8174 mDispatcher->notifyKey(KeyArgsBuilder(ACTION_UP, AINPUT_SOURCE_KEYBOARD)
8175 .keyCode(AKEYCODE_A)
8176 .addFlag(AKEY_EVENT_FLAG_CANCELED)
8177 .build());
8178 consumeKey(/*handled=*/false,
8179 AllOf(WithKeyAction(ACTION_UP), WithKeyCode(AKEYCODE_A),
8180 WithFlags(AKEY_EVENT_FLAG_CANCELED)));
8181 ASSERT_NO_FATAL_FAILURE(mFakePolicy->assertUnhandledKeyReported(AKEYCODE_A));
8182 // Ensure the fallback key is also canceled due to the original key being canceled.
8183 consumeKey(/*handled=*/true,
8184 AllOf(WithKeyAction(ACTION_UP), WithKeyCode(AKEYCODE_B),
8185 WithFlags(AKEY_EVENT_FLAG_FALLBACK | AKEY_EVENT_FLAG_CANCELED)));
8186
8187 ASSERT_NO_FATAL_FAILURE(mFakePolicy->assertUnhandledKeyNotReported());
8188 mWindow->assertNoEvents();
8189}
8190
Prabir Pradhanfa2c69f2024-02-01 20:31:34 +00008191TEST_F(InputDispatcherFallbackKeyTest, InputChannelRemovedDuringPolicyCall) {
Prabir Pradhanb13da8f2024-01-09 23:10:13 +00008192 setFallback(AKEYCODE_B);
8193 mDispatcher->notifyKey(
8194 KeyArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_KEYBOARD).keyCode(AKEYCODE_A).build());
8195
8196 // Do not handle this key event.
8197 consumeKey(/*handled=*/false,
8198 AllOf(WithKeyAction(ACTION_DOWN), WithKeyCode(AKEYCODE_A), WithFlags(0)));
8199 ASSERT_NO_FATAL_FAILURE(mFakePolicy->assertUnhandledKeyReported(AKEYCODE_A));
8200 consumeKey(/*handled=*/true,
8201 AllOf(WithKeyAction(ACTION_DOWN), WithKeyCode(AKEYCODE_B),
8202 WithFlags(AKEY_EVENT_FLAG_FALLBACK)));
8203
8204 mFakePolicy->setUnhandledKeyHandler([&](const KeyEvent& event) {
8205 // When the unhandled key is reported to the policy next, remove the input channel.
8206 mDispatcher->removeInputChannel(mWindow->getToken());
8207 return KeyEventBuilder(event).keyCode(AKEYCODE_B).build();
8208 });
8209 // Release the original key, and let the app now handle the previously unhandled key.
8210 // This should result in the previously generated fallback key to be cancelled.
8211 // Since the policy was notified of the unhandled DOWN event earlier, it will also be notified
8212 // of the UP event for consistency. The Dispatcher calls into the policy from its own thread
8213 // without holding the lock, because it need to synchronously fetch the fallback key. While in
8214 // the policy call, we will now remove the input channel. Once the policy call returns, the
8215 // Dispatcher will no longer have a channel to send cancellation events to. Ensure this does
8216 // not cause any crashes.
8217 mDispatcher->notifyKey(
8218 KeyArgsBuilder(ACTION_UP, AINPUT_SOURCE_KEYBOARD).keyCode(AKEYCODE_A).build());
8219 consumeKey(/*handled=*/true,
8220 AllOf(WithKeyAction(ACTION_UP), WithKeyCode(AKEYCODE_A), WithFlags(0)));
8221 ASSERT_NO_FATAL_FAILURE(mFakePolicy->assertUnhandledKeyReported(AKEYCODE_A));
8222}
8223
Prabir Pradhanfa2c69f2024-02-01 20:31:34 +00008224TEST_F(InputDispatcherFallbackKeyTest, WindowRemovedDuringPolicyCall) {
8225 setFallback(AKEYCODE_B);
8226 mDispatcher->notifyKey(
8227 KeyArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_KEYBOARD).keyCode(AKEYCODE_A).build());
8228
8229 // Do not handle this key event.
8230 consumeKey(/*handled=*/false,
8231 AllOf(WithKeyAction(ACTION_DOWN), WithKeyCode(AKEYCODE_A), WithFlags(0)));
8232 ASSERT_NO_FATAL_FAILURE(mFakePolicy->assertUnhandledKeyReported(AKEYCODE_A));
8233 consumeKey(/*handled=*/true,
8234 AllOf(WithKeyAction(ACTION_DOWN), WithKeyCode(AKEYCODE_B),
8235 WithFlags(AKEY_EVENT_FLAG_FALLBACK)));
8236
8237 mFakePolicy->setUnhandledKeyHandler([&](const KeyEvent& event) {
8238 // When the unhandled key is reported to the policy next, remove the window.
8239 mDispatcher->onWindowInfosChanged({{}, {}, 0, 0});
8240 return KeyEventBuilder(event).keyCode(AKEYCODE_B).build();
8241 });
8242 // Release the original key, which the app will not handle. When this unhandled key is reported
8243 // to the policy, the window will be removed.
8244 mDispatcher->notifyKey(
8245 KeyArgsBuilder(ACTION_UP, AINPUT_SOURCE_KEYBOARD).keyCode(AKEYCODE_A).build());
8246 consumeKey(/*handled=*/false,
8247 AllOf(WithKeyAction(ACTION_UP), WithKeyCode(AKEYCODE_A), WithFlags(0)));
8248 ASSERT_NO_FATAL_FAILURE(mFakePolicy->assertUnhandledKeyReported(AKEYCODE_A));
8249
8250 // Since the window was removed, it loses focus, and the channel state will be reset.
8251 consumeKey(/*handled=*/true,
8252 AllOf(WithKeyAction(ACTION_UP), WithKeyCode(AKEYCODE_B),
8253 WithFlags(AKEY_EVENT_FLAG_FALLBACK | AKEY_EVENT_FLAG_CANCELED)));
8254 mWindow->consumeFocusEvent(false);
8255 mWindow->assertNoEvents();
8256}
8257
8258TEST_F(InputDispatcherFallbackKeyTest, WindowRemovedWhileAwaitingFinishedSignal) {
8259 setFallback(AKEYCODE_B);
8260 mDispatcher->notifyKey(
8261 KeyArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_KEYBOARD).keyCode(AKEYCODE_A).build());
8262
8263 // Do not handle this key event.
8264 consumeKey(/*handled=*/false,
8265 AllOf(WithKeyAction(ACTION_DOWN), WithKeyCode(AKEYCODE_A), WithFlags(0)));
8266 ASSERT_NO_FATAL_FAILURE(mFakePolicy->assertUnhandledKeyReported(AKEYCODE_A));
8267 const auto [seq, event] = mWindow->receiveEvent();
8268 ASSERT_TRUE(seq.has_value() && event != nullptr) << "Failed to receive fallback event";
8269 ASSERT_EQ(event->getType(), InputEventType::KEY);
8270 ASSERT_THAT(static_cast<const KeyEvent&>(*event),
8271 AllOf(WithKeyAction(ACTION_DOWN), WithKeyCode(AKEYCODE_B),
8272 WithFlags(AKEY_EVENT_FLAG_FALLBACK)));
8273
8274 // Remove the window now, which should generate a cancellations and make the window lose focus.
8275 mDispatcher->onWindowInfosChanged({{}, {}, 0, 0});
8276 consumeKey(/*handled=*/true,
8277 AllOf(WithKeyAction(ACTION_UP), WithKeyCode(AKEYCODE_A),
8278 WithFlags(AKEY_EVENT_FLAG_CANCELED)));
8279 consumeKey(/*handled=*/true,
8280 AllOf(WithKeyAction(ACTION_UP), WithKeyCode(AKEYCODE_B),
8281 WithFlags(AKEY_EVENT_FLAG_FALLBACK | AKEY_EVENT_FLAG_CANCELED)));
8282 mWindow->consumeFocusEvent(false);
8283
8284 // Finish the event by reporting it as handled.
8285 mWindow->finishEvent(*seq);
8286 mWindow->assertNoEvents();
8287}
8288
Garfield Tan1c7bc862020-01-28 13:24:04 -08008289class InputDispatcherKeyRepeatTest : public InputDispatcherTest {
8290protected:
Siarhei Vishniakoufa2a0492023-11-14 13:13:18 -08008291 static constexpr std::chrono::nanoseconds KEY_REPEAT_TIMEOUT = 40ms;
8292 static constexpr std::chrono::nanoseconds KEY_REPEAT_DELAY = 40ms;
Garfield Tan1c7bc862020-01-28 13:24:04 -08008293
Chris Yea209fde2020-07-22 13:54:51 -07008294 std::shared_ptr<FakeApplicationHandle> mApp;
Garfield Tan1c7bc862020-01-28 13:24:04 -08008295 sp<FakeWindowHandle> mWindow;
8296
8297 virtual void SetUp() override {
Prabir Pradhandae52792023-12-15 07:36:40 +00008298 InputDispatcherTest::SetUp();
Garfield Tan1c7bc862020-01-28 13:24:04 -08008299
Prabir Pradhandae52792023-12-15 07:36:40 +00008300 mDispatcher->setKeyRepeatConfiguration(KEY_REPEAT_TIMEOUT, KEY_REPEAT_DELAY);
Garfield Tan1c7bc862020-01-28 13:24:04 -08008301 setUpWindow();
8302 }
8303
8304 void setUpWindow() {
Chris Yea209fde2020-07-22 13:54:51 -07008305 mApp = std::make_shared<FakeApplicationHandle>();
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07008306 mWindow = sp<FakeWindowHandle>::make(mApp, mDispatcher, "Fake Window", ADISPLAY_ID_DEFAULT);
Garfield Tan1c7bc862020-01-28 13:24:04 -08008307
Vishnu Nair47074b82020-08-14 11:54:47 -07008308 mWindow->setFocusable(true);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07008309 mDispatcher->onWindowInfosChanged({{*mWindow->getInfo()}, {}, 0, 0});
Vishnu Nair958da932020-08-21 17:12:37 -07008310 setFocusedWindow(mWindow);
Garfield Tan1c7bc862020-01-28 13:24:04 -08008311 mWindow->consumeFocusEvent(true);
8312 }
8313
Chris Ye2ad95392020-09-01 13:44:44 -07008314 void sendAndConsumeKeyDown(int32_t deviceId) {
Garfield Tan1c7bc862020-01-28 13:24:04 -08008315 NotifyKeyArgs keyArgs = generateKeyArgs(AKEY_EVENT_ACTION_DOWN, ADISPLAY_ID_DEFAULT);
Chris Ye2ad95392020-09-01 13:44:44 -07008316 keyArgs.deviceId = deviceId;
Garfield Tan1c7bc862020-01-28 13:24:04 -08008317 keyArgs.policyFlags |= POLICY_FLAG_TRUSTED; // Otherwise it won't generate repeat event
Prabir Pradhan678438e2023-04-13 19:32:51 +00008318 mDispatcher->notifyKey(keyArgs);
Garfield Tan1c7bc862020-01-28 13:24:04 -08008319
8320 // Window should receive key down event.
8321 mWindow->consumeKeyDown(ADISPLAY_ID_DEFAULT);
8322 }
8323
8324 void expectKeyRepeatOnce(int32_t repeatCount) {
8325 SCOPED_TRACE(StringPrintf("Checking event with repeat count %" PRId32, repeatCount));
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07008326 mWindow->consumeKeyEvent(
8327 AllOf(WithKeyAction(AKEY_EVENT_ACTION_DOWN), WithRepeatCount(repeatCount)));
Garfield Tan1c7bc862020-01-28 13:24:04 -08008328 }
8329
Chris Ye2ad95392020-09-01 13:44:44 -07008330 void sendAndConsumeKeyUp(int32_t deviceId) {
Garfield Tan1c7bc862020-01-28 13:24:04 -08008331 NotifyKeyArgs keyArgs = generateKeyArgs(AKEY_EVENT_ACTION_UP, ADISPLAY_ID_DEFAULT);
Chris Ye2ad95392020-09-01 13:44:44 -07008332 keyArgs.deviceId = deviceId;
Garfield Tan1c7bc862020-01-28 13:24:04 -08008333 keyArgs.policyFlags |= POLICY_FLAG_TRUSTED; // Unless it won't generate repeat event
Prabir Pradhan678438e2023-04-13 19:32:51 +00008334 mDispatcher->notifyKey(keyArgs);
Garfield Tan1c7bc862020-01-28 13:24:04 -08008335
8336 // Window should receive key down event.
Prabir Pradhan7662a8d2023-12-15 01:58:14 +00008337 mWindow->consumeKeyUp(ADISPLAY_ID_DEFAULT,
Harry Cutts33476232023-01-30 19:57:29 +00008338 /*expectedFlags=*/0);
Garfield Tan1c7bc862020-01-28 13:24:04 -08008339 }
Hu Guofe3c8f12023-09-22 17:20:15 +08008340
8341 void injectKeyRepeat(int32_t repeatCount) {
8342 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
8343 injectKey(*mDispatcher, AKEY_EVENT_ACTION_DOWN, repeatCount, ADISPLAY_ID_DEFAULT))
8344 << "Inject key event should return InputEventInjectionResult::SUCCEEDED";
8345 }
Garfield Tan1c7bc862020-01-28 13:24:04 -08008346};
8347
8348TEST_F(InputDispatcherKeyRepeatTest, FocusedWindow_ReceivesKeyRepeat) {
Harry Cutts33476232023-01-30 19:57:29 +00008349 sendAndConsumeKeyDown(/*deviceId=*/1);
Chris Ye2ad95392020-09-01 13:44:44 -07008350 for (int32_t repeatCount = 1; repeatCount <= 10; ++repeatCount) {
8351 expectKeyRepeatOnce(repeatCount);
8352 }
8353}
8354
8355TEST_F(InputDispatcherKeyRepeatTest, FocusedWindow_ReceivesKeyRepeatFromTwoDevices) {
Harry Cutts33476232023-01-30 19:57:29 +00008356 sendAndConsumeKeyDown(/*deviceId=*/1);
Chris Ye2ad95392020-09-01 13:44:44 -07008357 for (int32_t repeatCount = 1; repeatCount <= 10; ++repeatCount) {
8358 expectKeyRepeatOnce(repeatCount);
8359 }
Harry Cutts33476232023-01-30 19:57:29 +00008360 sendAndConsumeKeyDown(/*deviceId=*/2);
Chris Ye2ad95392020-09-01 13:44:44 -07008361 /* repeatCount will start from 1 for deviceId 2 */
Garfield Tan1c7bc862020-01-28 13:24:04 -08008362 for (int32_t repeatCount = 1; repeatCount <= 10; ++repeatCount) {
8363 expectKeyRepeatOnce(repeatCount);
8364 }
8365}
8366
8367TEST_F(InputDispatcherKeyRepeatTest, FocusedWindow_StopsKeyRepeatAfterUp) {
Harry Cutts33476232023-01-30 19:57:29 +00008368 sendAndConsumeKeyDown(/*deviceId=*/1);
8369 expectKeyRepeatOnce(/*repeatCount=*/1);
8370 sendAndConsumeKeyUp(/*deviceId=*/1);
Chris Ye2ad95392020-09-01 13:44:44 -07008371 mWindow->assertNoEvents();
8372}
8373
8374TEST_F(InputDispatcherKeyRepeatTest, FocusedWindow_KeyRepeatAfterStaleDeviceKeyUp) {
Harry Cutts33476232023-01-30 19:57:29 +00008375 sendAndConsumeKeyDown(/*deviceId=*/1);
8376 expectKeyRepeatOnce(/*repeatCount=*/1);
8377 sendAndConsumeKeyDown(/*deviceId=*/2);
8378 expectKeyRepeatOnce(/*repeatCount=*/1);
Chris Ye2ad95392020-09-01 13:44:44 -07008379 // Stale key up from device 1.
Harry Cutts33476232023-01-30 19:57:29 +00008380 sendAndConsumeKeyUp(/*deviceId=*/1);
Chris Ye2ad95392020-09-01 13:44:44 -07008381 // Device 2 is still down, keep repeating
Harry Cutts33476232023-01-30 19:57:29 +00008382 expectKeyRepeatOnce(/*repeatCount=*/2);
8383 expectKeyRepeatOnce(/*repeatCount=*/3);
Chris Ye2ad95392020-09-01 13:44:44 -07008384 // Device 2 key up
Harry Cutts33476232023-01-30 19:57:29 +00008385 sendAndConsumeKeyUp(/*deviceId=*/2);
Chris Ye2ad95392020-09-01 13:44:44 -07008386 mWindow->assertNoEvents();
8387}
8388
8389TEST_F(InputDispatcherKeyRepeatTest, FocusedWindow_KeyRepeatStopsAfterRepeatingKeyUp) {
Harry Cutts33476232023-01-30 19:57:29 +00008390 sendAndConsumeKeyDown(/*deviceId=*/1);
8391 expectKeyRepeatOnce(/*repeatCount=*/1);
8392 sendAndConsumeKeyDown(/*deviceId=*/2);
8393 expectKeyRepeatOnce(/*repeatCount=*/1);
Chris Ye2ad95392020-09-01 13:44:44 -07008394 // Device 2 which holds the key repeating goes up, expect the repeating to stop.
Harry Cutts33476232023-01-30 19:57:29 +00008395 sendAndConsumeKeyUp(/*deviceId=*/2);
Chris Ye2ad95392020-09-01 13:44:44 -07008396 // Device 1 still holds key down, but the repeating was already stopped
Garfield Tan1c7bc862020-01-28 13:24:04 -08008397 mWindow->assertNoEvents();
8398}
8399
liushenxiang42232912021-05-21 20:24:09 +08008400TEST_F(InputDispatcherKeyRepeatTest, FocusedWindow_StopsKeyRepeatAfterDisableInputDevice) {
8401 sendAndConsumeKeyDown(DEVICE_ID);
Harry Cutts33476232023-01-30 19:57:29 +00008402 expectKeyRepeatOnce(/*repeatCount=*/1);
Prabir Pradhan678438e2023-04-13 19:32:51 +00008403 mDispatcher->notifyDeviceReset({/*id=*/10, /*eventTime=*/20, DEVICE_ID});
liushenxiang42232912021-05-21 20:24:09 +08008404 mWindow->consumeKeyUp(ADISPLAY_ID_DEFAULT,
8405 AKEY_EVENT_FLAG_CANCELED | AKEY_EVENT_FLAG_LONG_PRESS);
8406 mWindow->assertNoEvents();
8407}
8408
Garfield Tan1c7bc862020-01-28 13:24:04 -08008409TEST_F(InputDispatcherKeyRepeatTest, FocusedWindow_RepeatKeyEventsUseEventIdFromInputDispatcher) {
Michael Wrighte1cbbd62023-02-22 19:32:13 +00008410 GTEST_SKIP() << "Flaky test (b/270393106)";
Harry Cutts33476232023-01-30 19:57:29 +00008411 sendAndConsumeKeyDown(/*deviceId=*/1);
Garfield Tan1c7bc862020-01-28 13:24:04 -08008412 for (int32_t repeatCount = 1; repeatCount <= 10; ++repeatCount) {
Siarhei Vishniakoud3061ab2023-12-18 20:41:08 -08008413 std::unique_ptr<KeyEvent> repeatEvent = mWindow->consumeKey();
8414 ASSERT_NE(nullptr, repeatEvent);
Garfield Tan1c7bc862020-01-28 13:24:04 -08008415 EXPECT_EQ(IdGenerator::Source::INPUT_DISPATCHER,
Siarhei Vishniakoud3061ab2023-12-18 20:41:08 -08008416 IdGenerator::getSource(repeatEvent->getId()));
Garfield Tan1c7bc862020-01-28 13:24:04 -08008417 }
8418}
8419
8420TEST_F(InputDispatcherKeyRepeatTest, FocusedWindow_RepeatKeyEventsUseUniqueEventId) {
Michael Wrighte1cbbd62023-02-22 19:32:13 +00008421 GTEST_SKIP() << "Flaky test (b/270393106)";
Harry Cutts33476232023-01-30 19:57:29 +00008422 sendAndConsumeKeyDown(/*deviceId=*/1);
Garfield Tan1c7bc862020-01-28 13:24:04 -08008423
8424 std::unordered_set<int32_t> idSet;
8425 for (int32_t repeatCount = 1; repeatCount <= 10; ++repeatCount) {
Siarhei Vishniakoud3061ab2023-12-18 20:41:08 -08008426 std::unique_ptr<KeyEvent> repeatEvent = mWindow->consumeKey();
8427 ASSERT_NE(nullptr, repeatEvent);
8428 int32_t id = repeatEvent->getId();
Garfield Tan1c7bc862020-01-28 13:24:04 -08008429 EXPECT_EQ(idSet.end(), idSet.find(id));
8430 idSet.insert(id);
8431 }
8432}
8433
Hu Guofe3c8f12023-09-22 17:20:15 +08008434TEST_F(InputDispatcherKeyRepeatTest, FocusedWindow_CorrectRepeatCountWhenInjectKeyRepeat) {
8435 injectKeyRepeat(0);
8436 mWindow->consumeKeyDown(ADISPLAY_ID_DEFAULT);
8437 for (int32_t repeatCount = 1; repeatCount <= 2; ++repeatCount) {
8438 expectKeyRepeatOnce(repeatCount);
8439 }
8440 injectKeyRepeat(1);
8441 // Expect repeatCount to be 3 instead of 1
8442 expectKeyRepeatOnce(3);
8443}
8444
Arthur Hung2fbf37f2018-09-13 18:16:41 +08008445/* Test InputDispatcher for MultiDisplay */
8446class InputDispatcherFocusOnTwoDisplaysTest : public InputDispatcherTest {
8447public:
Prabir Pradhan3608aad2019-10-02 17:08:26 -07008448 virtual void SetUp() override {
Arthur Hung2fbf37f2018-09-13 18:16:41 +08008449 InputDispatcherTest::SetUp();
Arthur Hungb92218b2018-08-14 12:00:21 +08008450
Chris Yea209fde2020-07-22 13:54:51 -07008451 application1 = std::make_shared<FakeApplicationHandle>();
Siarhei Vishniakou870ecec2020-12-09 08:07:46 -10008452 windowInPrimary =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07008453 sp<FakeWindowHandle>::make(application1, mDispatcher, "D_1", ADISPLAY_ID_DEFAULT);
Siarhei Vishniakoub9b15352019-11-26 13:19:26 -08008454
Arthur Hung2fbf37f2018-09-13 18:16:41 +08008455 // Set focus window for primary display, but focused display would be second one.
8456 mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application1);
Vishnu Nair47074b82020-08-14 11:54:47 -07008457 windowInPrimary->setFocusable(true);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07008458 mDispatcher->onWindowInfosChanged({{*windowInPrimary->getInfo()}, {}, 0, 0});
8459
Vishnu Nair958da932020-08-21 17:12:37 -07008460 setFocusedWindow(windowInPrimary);
Siarhei Vishniakouf1035d42019-09-20 16:32:01 +01008461 windowInPrimary->consumeFocusEvent(true);
Arthur Hungb92218b2018-08-14 12:00:21 +08008462
Chris Yea209fde2020-07-22 13:54:51 -07008463 application2 = std::make_shared<FakeApplicationHandle>();
Siarhei Vishniakou870ecec2020-12-09 08:07:46 -10008464 windowInSecondary =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07008465 sp<FakeWindowHandle>::make(application2, mDispatcher, "D_2", SECOND_DISPLAY_ID);
Arthur Hung2fbf37f2018-09-13 18:16:41 +08008466 // Set focus to second display window.
Arthur Hung2fbf37f2018-09-13 18:16:41 +08008467 // Set focus display to second one.
8468 mDispatcher->setFocusedDisplay(SECOND_DISPLAY_ID);
8469 // Set focus window for second display.
8470 mDispatcher->setFocusedApplication(SECOND_DISPLAY_ID, application2);
Vishnu Nair47074b82020-08-14 11:54:47 -07008471 windowInSecondary->setFocusable(true);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07008472 mDispatcher->onWindowInfosChanged(
8473 {{*windowInPrimary->getInfo(), *windowInSecondary->getInfo()}, {}, 0, 0});
Vishnu Nair958da932020-08-21 17:12:37 -07008474 setFocusedWindow(windowInSecondary);
Siarhei Vishniakouf1035d42019-09-20 16:32:01 +01008475 windowInSecondary->consumeFocusEvent(true);
Arthur Hung2fbf37f2018-09-13 18:16:41 +08008476 }
8477
Prabir Pradhan3608aad2019-10-02 17:08:26 -07008478 virtual void TearDown() override {
Arthur Hung2fbf37f2018-09-13 18:16:41 +08008479 InputDispatcherTest::TearDown();
8480
Chris Yea209fde2020-07-22 13:54:51 -07008481 application1.reset();
Arthur Hung2fbf37f2018-09-13 18:16:41 +08008482 windowInPrimary.clear();
Chris Yea209fde2020-07-22 13:54:51 -07008483 application2.reset();
Arthur Hung2fbf37f2018-09-13 18:16:41 +08008484 windowInSecondary.clear();
8485 }
8486
8487protected:
Chris Yea209fde2020-07-22 13:54:51 -07008488 std::shared_ptr<FakeApplicationHandle> application1;
Arthur Hung2fbf37f2018-09-13 18:16:41 +08008489 sp<FakeWindowHandle> windowInPrimary;
Chris Yea209fde2020-07-22 13:54:51 -07008490 std::shared_ptr<FakeApplicationHandle> application2;
Arthur Hung2fbf37f2018-09-13 18:16:41 +08008491 sp<FakeWindowHandle> windowInSecondary;
8492};
8493
8494TEST_F(InputDispatcherFocusOnTwoDisplaysTest, SetInputWindow_MultiDisplayTouch) {
8495 // Test touch down on primary display.
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08008496 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07008497 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT))
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08008498 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
Siarhei Vishniakouc5ca85c2019-11-15 17:20:00 -08008499 windowInPrimary->consumeMotionDown(ADISPLAY_ID_DEFAULT);
Arthur Hungb92218b2018-08-14 12:00:21 +08008500 windowInSecondary->assertNoEvents();
8501
Arthur Hung2fbf37f2018-09-13 18:16:41 +08008502 // Test touch down on second display.
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08008503 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07008504 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, SECOND_DISPLAY_ID))
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08008505 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
Arthur Hungb92218b2018-08-14 12:00:21 +08008506 windowInPrimary->assertNoEvents();
Siarhei Vishniakouc5ca85c2019-11-15 17:20:00 -08008507 windowInSecondary->consumeMotionDown(SECOND_DISPLAY_ID);
Arthur Hungb92218b2018-08-14 12:00:21 +08008508}
8509
Arthur Hung2fbf37f2018-09-13 18:16:41 +08008510TEST_F(InputDispatcherFocusOnTwoDisplaysTest, SetInputWindow_MultiDisplayFocus) {
Tiger Huang721e26f2018-07-24 22:26:19 +08008511 // Test inject a key down with display id specified.
Prabir Pradhan93f342c2021-03-11 15:05:30 -08008512 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07008513 injectKeyDownNoRepeat(*mDispatcher, ADISPLAY_ID_DEFAULT))
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08008514 << "Inject key event should return InputEventInjectionResult::SUCCEEDED";
Siarhei Vishniakouc5ca85c2019-11-15 17:20:00 -08008515 windowInPrimary->consumeKeyDown(ADISPLAY_ID_DEFAULT);
Tiger Huang721e26f2018-07-24 22:26:19 +08008516 windowInSecondary->assertNoEvents();
8517
8518 // Test inject a key down without display id specified.
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07008519 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectKeyDownNoRepeat(*mDispatcher))
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08008520 << "Inject key event should return InputEventInjectionResult::SUCCEEDED";
Arthur Hungb92218b2018-08-14 12:00:21 +08008521 windowInPrimary->assertNoEvents();
Linnan Li13bf76a2024-05-05 19:18:02 +08008522 windowInSecondary->consumeKeyDown(ui::ADISPLAY_ID_NONE);
Arthur Hungb92218b2018-08-14 12:00:21 +08008523
Siarhei Vishniakoub9b15352019-11-26 13:19:26 -08008524 // Remove all windows in secondary display.
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07008525 mDispatcher->onWindowInfosChanged({{*windowInPrimary->getInfo()}, {}, 0, 0});
Arthur Hungb92218b2018-08-14 12:00:21 +08008526
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08008527 // Old focus should receive a cancel event.
Linnan Li13bf76a2024-05-05 19:18:02 +08008528 windowInSecondary->consumeKeyUp(ui::ADISPLAY_ID_NONE, AKEY_EVENT_FLAG_CANCELED);
Arthur Hungb92218b2018-08-14 12:00:21 +08008529
8530 // Test inject a key down, should timeout because of no target window.
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07008531 ASSERT_NO_FATAL_FAILURE(assertInjectedKeyTimesOut(*mDispatcher));
Arthur Hungb92218b2018-08-14 12:00:21 +08008532 windowInPrimary->assertNoEvents();
Siarhei Vishniakouf1035d42019-09-20 16:32:01 +01008533 windowInSecondary->consumeFocusEvent(false);
Arthur Hungb92218b2018-08-14 12:00:21 +08008534 windowInSecondary->assertNoEvents();
8535}
8536
Arthur Hung2fbf37f2018-09-13 18:16:41 +08008537// Test per-display input monitors for motion event.
8538TEST_F(InputDispatcherFocusOnTwoDisplaysTest, MonitorMotionEvent_MultiDisplay) {
chaviwd1c23182019-12-20 18:44:56 -08008539 FakeMonitorReceiver monitorInPrimary =
Prabir Pradhanfb549072023-10-05 19:17:36 +00008540 FakeMonitorReceiver(*mDispatcher, "M_1", ADISPLAY_ID_DEFAULT);
chaviwd1c23182019-12-20 18:44:56 -08008541 FakeMonitorReceiver monitorInSecondary =
Prabir Pradhanfb549072023-10-05 19:17:36 +00008542 FakeMonitorReceiver(*mDispatcher, "M_2", SECOND_DISPLAY_ID);
Arthur Hung2fbf37f2018-09-13 18:16:41 +08008543
8544 // Test touch down on primary display.
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08008545 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07008546 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT))
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08008547 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
Siarhei Vishniakouc5ca85c2019-11-15 17:20:00 -08008548 windowInPrimary->consumeMotionDown(ADISPLAY_ID_DEFAULT);
chaviwd1c23182019-12-20 18:44:56 -08008549 monitorInPrimary.consumeMotionDown(ADISPLAY_ID_DEFAULT);
Arthur Hung2fbf37f2018-09-13 18:16:41 +08008550 windowInSecondary->assertNoEvents();
chaviwd1c23182019-12-20 18:44:56 -08008551 monitorInSecondary.assertNoEvents();
Arthur Hung2fbf37f2018-09-13 18:16:41 +08008552
8553 // Test touch down on second display.
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08008554 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07008555 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, SECOND_DISPLAY_ID))
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08008556 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
Arthur Hung2fbf37f2018-09-13 18:16:41 +08008557 windowInPrimary->assertNoEvents();
chaviwd1c23182019-12-20 18:44:56 -08008558 monitorInPrimary.assertNoEvents();
Siarhei Vishniakouc5ca85c2019-11-15 17:20:00 -08008559 windowInSecondary->consumeMotionDown(SECOND_DISPLAY_ID);
chaviwd1c23182019-12-20 18:44:56 -08008560 monitorInSecondary.consumeMotionDown(SECOND_DISPLAY_ID);
Arthur Hung2fbf37f2018-09-13 18:16:41 +08008561
Siarhei Vishniakou92c8fd52023-01-29 14:57:43 -08008562 // Lift up the touch from the second display
8563 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07008564 injectMotionUp(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, SECOND_DISPLAY_ID))
Siarhei Vishniakou92c8fd52023-01-29 14:57:43 -08008565 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
8566 windowInSecondary->consumeMotionUp(SECOND_DISPLAY_ID);
8567 monitorInSecondary.consumeMotionUp(SECOND_DISPLAY_ID);
8568
Arthur Hung2fbf37f2018-09-13 18:16:41 +08008569 // Test inject a non-pointer motion event.
8570 // If specific a display, it will dispatch to the focused window of particular display,
8571 // or it will dispatch to the focused window of focused display.
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08008572 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Linnan Li13bf76a2024-05-05 19:18:02 +08008573 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TRACKBALL, ui::ADISPLAY_ID_NONE))
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08008574 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
Arthur Hung2fbf37f2018-09-13 18:16:41 +08008575 windowInPrimary->assertNoEvents();
chaviwd1c23182019-12-20 18:44:56 -08008576 monitorInPrimary.assertNoEvents();
Linnan Li13bf76a2024-05-05 19:18:02 +08008577 windowInSecondary->consumeMotionDown(ui::ADISPLAY_ID_NONE);
8578 monitorInSecondary.consumeMotionDown(ui::ADISPLAY_ID_NONE);
Arthur Hung2fbf37f2018-09-13 18:16:41 +08008579}
8580
8581// Test per-display input monitors for key event.
8582TEST_F(InputDispatcherFocusOnTwoDisplaysTest, MonitorKeyEvent_MultiDisplay) {
Siarhei Vishniakou870ecec2020-12-09 08:07:46 -10008583 // Input monitor per display.
chaviwd1c23182019-12-20 18:44:56 -08008584 FakeMonitorReceiver monitorInPrimary =
Prabir Pradhanfb549072023-10-05 19:17:36 +00008585 FakeMonitorReceiver(*mDispatcher, "M_1", ADISPLAY_ID_DEFAULT);
chaviwd1c23182019-12-20 18:44:56 -08008586 FakeMonitorReceiver monitorInSecondary =
Prabir Pradhanfb549072023-10-05 19:17:36 +00008587 FakeMonitorReceiver(*mDispatcher, "M_2", SECOND_DISPLAY_ID);
Arthur Hung2fbf37f2018-09-13 18:16:41 +08008588
8589 // Test inject a key down.
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07008590 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectKeyDown(*mDispatcher))
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08008591 << "Inject key event should return InputEventInjectionResult::SUCCEEDED";
Arthur Hung2fbf37f2018-09-13 18:16:41 +08008592 windowInPrimary->assertNoEvents();
chaviwd1c23182019-12-20 18:44:56 -08008593 monitorInPrimary.assertNoEvents();
Linnan Li13bf76a2024-05-05 19:18:02 +08008594 windowInSecondary->consumeKeyDown(ui::ADISPLAY_ID_NONE);
8595 monitorInSecondary.consumeKeyDown(ui::ADISPLAY_ID_NONE);
Arthur Hung2fbf37f2018-09-13 18:16:41 +08008596}
8597
Vishnu Nair958da932020-08-21 17:12:37 -07008598TEST_F(InputDispatcherFocusOnTwoDisplaysTest, CanFocusWindowOnUnfocusedDisplay) {
8599 sp<FakeWindowHandle> secondWindowInPrimary =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07008600 sp<FakeWindowHandle>::make(application1, mDispatcher, "D_1_W2", ADISPLAY_ID_DEFAULT);
Vishnu Nair958da932020-08-21 17:12:37 -07008601 secondWindowInPrimary->setFocusable(true);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07008602 mDispatcher->onWindowInfosChanged(
8603 {{*windowInPrimary->getInfo(), *secondWindowInPrimary->getInfo(),
8604 *windowInSecondary->getInfo()},
8605 {},
8606 0,
8607 0});
Vishnu Nair958da932020-08-21 17:12:37 -07008608 setFocusedWindow(secondWindowInPrimary);
8609 windowInPrimary->consumeFocusEvent(false);
8610 secondWindowInPrimary->consumeFocusEvent(true);
8611
8612 // Test inject a key down.
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07008613 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
8614 injectKeyDown(*mDispatcher, ADISPLAY_ID_DEFAULT))
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08008615 << "Inject key event should return InputEventInjectionResult::SUCCEEDED";
Vishnu Nair958da932020-08-21 17:12:37 -07008616 windowInPrimary->assertNoEvents();
8617 windowInSecondary->assertNoEvents();
8618 secondWindowInPrimary->consumeKeyDown(ADISPLAY_ID_DEFAULT);
8619}
8620
Arthur Hungdfd528e2021-12-08 13:23:04 +00008621TEST_F(InputDispatcherFocusOnTwoDisplaysTest, CancelTouch_MultiDisplay) {
8622 FakeMonitorReceiver monitorInPrimary =
Prabir Pradhanfb549072023-10-05 19:17:36 +00008623 FakeMonitorReceiver(*mDispatcher, "M_1", ADISPLAY_ID_DEFAULT);
Arthur Hungdfd528e2021-12-08 13:23:04 +00008624 FakeMonitorReceiver monitorInSecondary =
Prabir Pradhanfb549072023-10-05 19:17:36 +00008625 FakeMonitorReceiver(*mDispatcher, "M_2", SECOND_DISPLAY_ID);
Arthur Hungdfd528e2021-12-08 13:23:04 +00008626
8627 // Test touch down on primary display.
8628 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07008629 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT))
Arthur Hungdfd528e2021-12-08 13:23:04 +00008630 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
8631 windowInPrimary->consumeMotionDown(ADISPLAY_ID_DEFAULT);
8632 monitorInPrimary.consumeMotionDown(ADISPLAY_ID_DEFAULT);
8633
8634 // Test touch down on second display.
8635 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07008636 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, SECOND_DISPLAY_ID))
Arthur Hungdfd528e2021-12-08 13:23:04 +00008637 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
8638 windowInSecondary->consumeMotionDown(SECOND_DISPLAY_ID);
8639 monitorInSecondary.consumeMotionDown(SECOND_DISPLAY_ID);
8640
8641 // Trigger cancel touch.
8642 mDispatcher->cancelCurrentTouch();
8643 windowInPrimary->consumeMotionCancel(ADISPLAY_ID_DEFAULT);
8644 monitorInPrimary.consumeMotionCancel(ADISPLAY_ID_DEFAULT);
8645 windowInSecondary->consumeMotionCancel(SECOND_DISPLAY_ID);
8646 monitorInSecondary.consumeMotionCancel(SECOND_DISPLAY_ID);
8647
8648 // Test inject a move motion event, no window/monitor should receive the event.
8649 ASSERT_EQ(InputEventInjectionResult::FAILED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07008650 injectMotionEvent(*mDispatcher, AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN,
Arthur Hungdfd528e2021-12-08 13:23:04 +00008651 ADISPLAY_ID_DEFAULT, {110, 200}))
8652 << "Inject motion event should return InputEventInjectionResult::FAILED";
8653 windowInPrimary->assertNoEvents();
8654 monitorInPrimary.assertNoEvents();
8655
8656 ASSERT_EQ(InputEventInjectionResult::FAILED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07008657 injectMotionEvent(*mDispatcher, AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN,
Arthur Hungdfd528e2021-12-08 13:23:04 +00008658 SECOND_DISPLAY_ID, {110, 200}))
8659 << "Inject motion event should return InputEventInjectionResult::FAILED";
8660 windowInSecondary->assertNoEvents();
8661 monitorInSecondary.assertNoEvents();
8662}
8663
Hu Guocb134f12023-12-23 13:42:44 +00008664/**
8665 * Send a key to the primary display and to the secondary display.
8666 * Then cause the key on the primary display to be canceled by sending in a stale key.
8667 * Ensure that the key on the primary display is canceled, and that the key on the secondary display
8668 * does not get canceled.
8669 */
8670TEST_F(InputDispatcherFocusOnTwoDisplaysTest, WhenDropKeyEvent_OnlyCancelCorrespondingKeyGesture) {
8671 // Send a key down on primary display
8672 mDispatcher->notifyKey(
8673 KeyArgsBuilder(AKEY_EVENT_ACTION_DOWN, AINPUT_SOURCE_KEYBOARD)
8674 .displayId(ADISPLAY_ID_DEFAULT)
8675 .policyFlags(DEFAULT_POLICY_FLAGS | POLICY_FLAG_DISABLE_KEY_REPEAT)
8676 .build());
8677 windowInPrimary->consumeKeyEvent(
8678 AllOf(WithKeyAction(AKEY_EVENT_ACTION_DOWN), WithDisplayId(ADISPLAY_ID_DEFAULT)));
8679 windowInSecondary->assertNoEvents();
8680
8681 // Send a key down on second display
8682 mDispatcher->notifyKey(
8683 KeyArgsBuilder(AKEY_EVENT_ACTION_DOWN, AINPUT_SOURCE_KEYBOARD)
8684 .displayId(SECOND_DISPLAY_ID)
8685 .policyFlags(DEFAULT_POLICY_FLAGS | POLICY_FLAG_DISABLE_KEY_REPEAT)
8686 .build());
8687 windowInSecondary->consumeKeyEvent(
8688 AllOf(WithKeyAction(AKEY_EVENT_ACTION_DOWN), WithDisplayId(SECOND_DISPLAY_ID)));
8689 windowInPrimary->assertNoEvents();
8690
8691 // Send a valid key up event on primary display that will be dropped because it is stale
8692 NotifyKeyArgs staleKeyUp =
8693 KeyArgsBuilder(AKEY_EVENT_ACTION_UP, AINPUT_SOURCE_KEYBOARD)
8694 .displayId(ADISPLAY_ID_DEFAULT)
8695 .policyFlags(DEFAULT_POLICY_FLAGS | POLICY_FLAG_DISABLE_KEY_REPEAT)
8696 .build();
8697 static constexpr std::chrono::duration STALE_EVENT_TIMEOUT = 10ms;
8698 mFakePolicy->setStaleEventTimeout(STALE_EVENT_TIMEOUT);
8699 std::this_thread::sleep_for(STALE_EVENT_TIMEOUT);
8700 mDispatcher->notifyKey(staleKeyUp);
8701
8702 // Only the key gesture corresponding to the dropped event should receive the cancel event.
8703 // Therefore, windowInPrimary should get the cancel event and windowInSecondary should not
8704 // receive any events.
8705 windowInPrimary->consumeKeyEvent(AllOf(WithKeyAction(AKEY_EVENT_ACTION_UP),
8706 WithDisplayId(ADISPLAY_ID_DEFAULT),
8707 WithFlags(AKEY_EVENT_FLAG_CANCELED)));
8708 windowInSecondary->assertNoEvents();
8709}
8710
8711/**
8712 * Similar to 'WhenDropKeyEvent_OnlyCancelCorrespondingKeyGesture' but for motion events.
8713 */
8714TEST_F(InputDispatcherFocusOnTwoDisplaysTest, WhenDropMotionEvent_OnlyCancelCorrespondingGesture) {
8715 // Send touch down on primary display.
8716 mDispatcher->notifyMotion(
8717 MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
8718 .pointer(PointerBuilder(/*id=*/0, ToolType::FINGER).x(100).y(200))
8719 .displayId(ADISPLAY_ID_DEFAULT)
8720 .build());
8721 windowInPrimary->consumeMotionEvent(
8722 AllOf(WithMotionAction(ACTION_DOWN), WithDisplayId(ADISPLAY_ID_DEFAULT)));
8723 windowInSecondary->assertNoEvents();
8724
8725 // Send touch down on second display.
8726 mDispatcher->notifyMotion(
8727 MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
8728 .pointer(PointerBuilder(/*id=*/0, ToolType::FINGER).x(100).y(200))
8729 .displayId(SECOND_DISPLAY_ID)
8730 .build());
8731 windowInPrimary->assertNoEvents();
8732 windowInSecondary->consumeMotionEvent(
8733 AllOf(WithMotionAction(ACTION_DOWN), WithDisplayId(SECOND_DISPLAY_ID)));
8734
8735 // inject a valid MotionEvent on primary display that will be stale when it arrives.
8736 NotifyMotionArgs staleMotionUp =
8737 MotionArgsBuilder(ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN)
8738 .displayId(ADISPLAY_ID_DEFAULT)
8739 .pointer(PointerBuilder(/*id=*/0, ToolType::FINGER).x(100).y(200))
8740 .build();
8741 static constexpr std::chrono::duration STALE_EVENT_TIMEOUT = 10ms;
8742 mFakePolicy->setStaleEventTimeout(STALE_EVENT_TIMEOUT);
8743 std::this_thread::sleep_for(STALE_EVENT_TIMEOUT);
8744 mDispatcher->notifyMotion(staleMotionUp);
8745
8746 // For stale motion events, we let the gesture to complete. This behaviour is different from key
8747 // events, where we would cancel the current keys instead.
8748 windowInPrimary->consumeMotionEvent(WithMotionAction(ACTION_UP));
8749 windowInSecondary->assertNoEvents();
8750}
8751
Jackal Guof9696682018-10-05 12:23:23 +08008752class InputFilterTest : public InputDispatcherTest {
8753protected:
Linnan Li13bf76a2024-05-05 19:18:02 +08008754 void testNotifyMotion(ui::LogicalDisplayId displayId, bool expectToBeFiltered,
Prabir Pradhan81420cc2021-09-06 10:28:50 -07008755 const ui::Transform& transform = ui::Transform()) {
Jackal Guof9696682018-10-05 12:23:23 +08008756 NotifyMotionArgs motionArgs;
8757
Siarhei Vishniakou870ecec2020-12-09 08:07:46 -10008758 motionArgs =
8759 generateMotionArgs(AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN, displayId);
Prabir Pradhan678438e2023-04-13 19:32:51 +00008760 mDispatcher->notifyMotion(motionArgs);
Siarhei Vishniakou870ecec2020-12-09 08:07:46 -10008761 motionArgs =
8762 generateMotionArgs(AMOTION_EVENT_ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN, displayId);
Prabir Pradhan678438e2023-04-13 19:32:51 +00008763 mDispatcher->notifyMotion(motionArgs);
Siarhei Vishniakou2bfa9052019-11-21 18:10:54 -08008764 ASSERT_TRUE(mDispatcher->waitForIdle());
Jackal Guof9696682018-10-05 12:23:23 +08008765 if (expectToBeFiltered) {
Siarhei Vishniakou3218fc02023-06-15 20:41:02 -07008766 const auto xy = transform.transform(motionArgs.pointerCoords[0].getXYValue());
Prabir Pradhan81420cc2021-09-06 10:28:50 -07008767 mFakePolicy->assertFilterInputEventWasCalled(motionArgs, xy);
Jackal Guof9696682018-10-05 12:23:23 +08008768 } else {
8769 mFakePolicy->assertFilterInputEventWasNotCalled();
8770 }
8771 }
8772
8773 void testNotifyKey(bool expectToBeFiltered) {
8774 NotifyKeyArgs keyArgs;
8775
8776 keyArgs = generateKeyArgs(AKEY_EVENT_ACTION_DOWN);
Prabir Pradhan678438e2023-04-13 19:32:51 +00008777 mDispatcher->notifyKey(keyArgs);
Jackal Guof9696682018-10-05 12:23:23 +08008778 keyArgs = generateKeyArgs(AKEY_EVENT_ACTION_UP);
Prabir Pradhan678438e2023-04-13 19:32:51 +00008779 mDispatcher->notifyKey(keyArgs);
Siarhei Vishniakou2bfa9052019-11-21 18:10:54 -08008780 ASSERT_TRUE(mDispatcher->waitForIdle());
Jackal Guof9696682018-10-05 12:23:23 +08008781
8782 if (expectToBeFiltered) {
Siarhei Vishniakou8935a802019-11-15 16:41:44 -08008783 mFakePolicy->assertFilterInputEventWasCalled(keyArgs);
Jackal Guof9696682018-10-05 12:23:23 +08008784 } else {
8785 mFakePolicy->assertFilterInputEventWasNotCalled();
8786 }
8787 }
8788};
8789
8790// Test InputFilter for MotionEvent
8791TEST_F(InputFilterTest, MotionEvent_InputFilter) {
8792 // Since the InputFilter is disabled by default, check if touch events aren't filtered.
Harry Cutts101ee9b2023-07-06 18:04:14 +00008793 testNotifyMotion(ADISPLAY_ID_DEFAULT, /*expectToBeFiltered=*/false);
8794 testNotifyMotion(SECOND_DISPLAY_ID, /*expectToBeFiltered=*/false);
Jackal Guof9696682018-10-05 12:23:23 +08008795
8796 // Enable InputFilter
8797 mDispatcher->setInputFilterEnabled(true);
8798 // Test touch on both primary and second display, and check if both events are filtered.
Harry Cutts101ee9b2023-07-06 18:04:14 +00008799 testNotifyMotion(ADISPLAY_ID_DEFAULT, /*expectToBeFiltered=*/true);
8800 testNotifyMotion(SECOND_DISPLAY_ID, /*expectToBeFiltered=*/true);
Jackal Guof9696682018-10-05 12:23:23 +08008801
8802 // Disable InputFilter
8803 mDispatcher->setInputFilterEnabled(false);
8804 // Test touch on both primary and second display, and check if both events aren't filtered.
Harry Cutts101ee9b2023-07-06 18:04:14 +00008805 testNotifyMotion(ADISPLAY_ID_DEFAULT, /*expectToBeFiltered=*/false);
8806 testNotifyMotion(SECOND_DISPLAY_ID, /*expectToBeFiltered=*/false);
Jackal Guof9696682018-10-05 12:23:23 +08008807}
8808
8809// Test InputFilter for KeyEvent
8810TEST_F(InputFilterTest, KeyEvent_InputFilter) {
8811 // Since the InputFilter is disabled by default, check if key event aren't filtered.
Harry Cutts101ee9b2023-07-06 18:04:14 +00008812 testNotifyKey(/*expectToBeFiltered=*/false);
Jackal Guof9696682018-10-05 12:23:23 +08008813
8814 // Enable InputFilter
8815 mDispatcher->setInputFilterEnabled(true);
8816 // Send a key event, and check if it is filtered.
Harry Cutts101ee9b2023-07-06 18:04:14 +00008817 testNotifyKey(/*expectToBeFiltered=*/true);
Jackal Guof9696682018-10-05 12:23:23 +08008818
8819 // Disable InputFilter
8820 mDispatcher->setInputFilterEnabled(false);
8821 // Send a key event, and check if it isn't filtered.
Harry Cutts101ee9b2023-07-06 18:04:14 +00008822 testNotifyKey(/*expectToBeFiltered=*/false);
Jackal Guof9696682018-10-05 12:23:23 +08008823}
8824
Prabir Pradhan81420cc2021-09-06 10:28:50 -07008825// Ensure that MotionEvents sent to the InputFilter through InputListener are converted to the
8826// logical display coordinate space.
8827TEST_F(InputFilterTest, MotionEvent_UsesLogicalDisplayCoordinates_notifyMotion) {
8828 ui::Transform firstDisplayTransform;
8829 firstDisplayTransform.set({1.1, 2.2, 3.3, 4.4, 5.5, 6.6, 0, 0, 1});
8830 ui::Transform secondDisplayTransform;
8831 secondDisplayTransform.set({-6.6, -5.5, -4.4, -3.3, -2.2, -1.1, 0, 0, 1});
8832
8833 std::vector<gui::DisplayInfo> displayInfos(2);
8834 displayInfos[0].displayId = ADISPLAY_ID_DEFAULT;
8835 displayInfos[0].transform = firstDisplayTransform;
8836 displayInfos[1].displayId = SECOND_DISPLAY_ID;
8837 displayInfos[1].transform = secondDisplayTransform;
8838
Patrick Williamsd828f302023-04-28 17:52:08 -05008839 mDispatcher->onWindowInfosChanged({{}, displayInfos, 0, 0});
Prabir Pradhan81420cc2021-09-06 10:28:50 -07008840
8841 // Enable InputFilter
8842 mDispatcher->setInputFilterEnabled(true);
8843
8844 // Ensure the correct transforms are used for the displays.
Harry Cutts101ee9b2023-07-06 18:04:14 +00008845 testNotifyMotion(ADISPLAY_ID_DEFAULT, /*expectToBeFiltered=*/true, firstDisplayTransform);
8846 testNotifyMotion(SECOND_DISPLAY_ID, /*expectToBeFiltered=*/true, secondDisplayTransform);
Prabir Pradhan81420cc2021-09-06 10:28:50 -07008847}
8848
Siarhei Vishniakou5d552c42021-05-21 05:02:22 +00008849class InputFilterInjectionPolicyTest : public InputDispatcherTest {
8850protected:
8851 virtual void SetUp() override {
8852 InputDispatcherTest::SetUp();
8853
8854 /**
8855 * We don't need to enable input filter to test the injected event policy, but we enabled it
8856 * here to make the tests more realistic, since this policy only matters when inputfilter is
8857 * on.
8858 */
8859 mDispatcher->setInputFilterEnabled(true);
8860
8861 std::shared_ptr<InputApplicationHandle> application =
8862 std::make_shared<FakeApplicationHandle>();
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07008863 mWindow = sp<FakeWindowHandle>::make(application, mDispatcher, "Test Window",
8864 ADISPLAY_ID_DEFAULT);
Siarhei Vishniakou5d552c42021-05-21 05:02:22 +00008865
8866 mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application);
8867 mWindow->setFocusable(true);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07008868 mDispatcher->onWindowInfosChanged({{*mWindow->getInfo()}, {}, 0, 0});
Siarhei Vishniakou5d552c42021-05-21 05:02:22 +00008869 setFocusedWindow(mWindow);
8870 mWindow->consumeFocusEvent(true);
8871 }
8872
Siarhei Vishniakouf00a4ec2021-06-16 03:55:32 +00008873 void testInjectedKey(int32_t policyFlags, int32_t injectedDeviceId, int32_t resolvedDeviceId,
8874 int32_t flags) {
Siarhei Vishniakou5d552c42021-05-21 05:02:22 +00008875 KeyEvent event;
8876
8877 const nsecs_t eventTime = systemTime(SYSTEM_TIME_MONOTONIC);
8878 event.initialize(InputEvent::nextId(), injectedDeviceId, AINPUT_SOURCE_KEYBOARD,
Linnan Li13bf76a2024-05-05 19:18:02 +08008879 ui::ADISPLAY_ID_NONE, INVALID_HMAC, AKEY_EVENT_ACTION_DOWN, 0, AKEYCODE_A,
Harry Cutts33476232023-01-30 19:57:29 +00008880 KEY_A, AMETA_NONE, /*repeatCount=*/0, eventTime, eventTime);
Siarhei Vishniakou5d552c42021-05-21 05:02:22 +00008881 const int32_t additionalPolicyFlags =
8882 POLICY_FLAG_PASS_TO_USER | POLICY_FLAG_DISABLE_KEY_REPEAT;
8883 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Harry Cutts33476232023-01-30 19:57:29 +00008884 mDispatcher->injectInputEvent(&event, /*targetUid=*/{},
Siarhei Vishniakou4648fea2023-06-27 01:00:12 +00008885 InputEventInjectionSync::WAIT_FOR_RESULT, 100ms,
Siarhei Vishniakou5d552c42021-05-21 05:02:22 +00008886 policyFlags | additionalPolicyFlags));
8887
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07008888 mWindow->consumeKeyEvent(AllOf(WithDeviceId(resolvedDeviceId), WithFlags(flags)));
Siarhei Vishniakouf00a4ec2021-06-16 03:55:32 +00008889 }
8890
8891 void testInjectedMotion(int32_t policyFlags, int32_t injectedDeviceId, int32_t resolvedDeviceId,
8892 int32_t flags) {
8893 MotionEvent event;
8894 PointerProperties pointerProperties[1];
8895 PointerCoords pointerCoords[1];
8896 pointerProperties[0].clear();
8897 pointerProperties[0].id = 0;
8898 pointerCoords[0].clear();
8899 pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_X, 300);
8900 pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_Y, 400);
8901
8902 ui::Transform identityTransform;
8903 const nsecs_t eventTime = systemTime(SYSTEM_TIME_MONOTONIC);
8904 event.initialize(InputEvent::nextId(), injectedDeviceId, AINPUT_SOURCE_TOUCHSCREEN,
8905 DISPLAY_ID, INVALID_HMAC, AMOTION_EVENT_ACTION_DOWN, 0, 0,
8906 AMOTION_EVENT_EDGE_FLAG_NONE, AMETA_NONE, 0, MotionClassification::NONE,
8907 identityTransform, 0, 0, AMOTION_EVENT_INVALID_CURSOR_POSITION,
Prabir Pradhanb9b18502021-08-26 12:30:32 -07008908 AMOTION_EVENT_INVALID_CURSOR_POSITION, identityTransform, eventTime,
Evan Rosky09576692021-07-01 12:22:09 -07008909 eventTime,
Harry Cutts101ee9b2023-07-06 18:04:14 +00008910 /*pointerCount=*/1, pointerProperties, pointerCoords);
Siarhei Vishniakouf00a4ec2021-06-16 03:55:32 +00008911
8912 const int32_t additionalPolicyFlags = POLICY_FLAG_PASS_TO_USER;
8913 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Harry Cutts33476232023-01-30 19:57:29 +00008914 mDispatcher->injectInputEvent(&event, /*targetUid=*/{},
Siarhei Vishniakou4648fea2023-06-27 01:00:12 +00008915 InputEventInjectionSync::WAIT_FOR_RESULT, 100ms,
Siarhei Vishniakouf00a4ec2021-06-16 03:55:32 +00008916 policyFlags | additionalPolicyFlags));
8917
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07008918 mWindow->consumeMotionEvent(AllOf(WithFlags(flags), WithDeviceId(resolvedDeviceId)));
Siarhei Vishniakou5d552c42021-05-21 05:02:22 +00008919 }
8920
8921private:
8922 sp<FakeWindowHandle> mWindow;
8923};
8924
8925TEST_F(InputFilterInjectionPolicyTest, TrustedFilteredEvents_KeepOriginalDeviceId) {
Siarhei Vishniakouf00a4ec2021-06-16 03:55:32 +00008926 // Must have POLICY_FLAG_FILTERED here to indicate that the event has gone through the input
8927 // filter. Without it, the event will no different from a regularly injected event, and the
8928 // injected device id will be overwritten.
Harry Cutts33476232023-01-30 19:57:29 +00008929 testInjectedKey(POLICY_FLAG_FILTERED, /*injectedDeviceId=*/3, /*resolvedDeviceId=*/3,
8930 /*flags=*/0);
Siarhei Vishniakou5d552c42021-05-21 05:02:22 +00008931}
8932
Siarhei Vishniakouf00a4ec2021-06-16 03:55:32 +00008933TEST_F(InputFilterInjectionPolicyTest, KeyEventsInjectedFromAccessibility_HaveAccessibilityFlag) {
Siarhei Vishniakou5d552c42021-05-21 05:02:22 +00008934 testInjectedKey(POLICY_FLAG_FILTERED | POLICY_FLAG_INJECTED_FROM_ACCESSIBILITY,
Harry Cutts33476232023-01-30 19:57:29 +00008935 /*injectedDeviceId=*/3, /*resolvedDeviceId=*/3,
Siarhei Vishniakouf00a4ec2021-06-16 03:55:32 +00008936 AKEY_EVENT_FLAG_IS_ACCESSIBILITY_EVENT);
8937}
8938
8939TEST_F(InputFilterInjectionPolicyTest,
8940 MotionEventsInjectedFromAccessibility_HaveAccessibilityFlag) {
8941 testInjectedMotion(POLICY_FLAG_FILTERED | POLICY_FLAG_INJECTED_FROM_ACCESSIBILITY,
Harry Cutts33476232023-01-30 19:57:29 +00008942 /*injectedDeviceId=*/3, /*resolvedDeviceId=*/3,
Siarhei Vishniakouf00a4ec2021-06-16 03:55:32 +00008943 AMOTION_EVENT_FLAG_IS_ACCESSIBILITY_EVENT);
Siarhei Vishniakou5d552c42021-05-21 05:02:22 +00008944}
8945
8946TEST_F(InputFilterInjectionPolicyTest, RegularInjectedEvents_ReceiveVirtualDeviceId) {
Harry Cutts33476232023-01-30 19:57:29 +00008947 testInjectedKey(/*policyFlags=*/0, /*injectedDeviceId=*/3,
8948 /*resolvedDeviceId=*/VIRTUAL_KEYBOARD_ID, /*flags=*/0);
Siarhei Vishniakou5d552c42021-05-21 05:02:22 +00008949}
8950
Yeabkal Wubshitb8aadfa2024-01-17 17:03:42 -08008951class InputDispatcherUserActivityPokeTests : public InputDispatcherTest {
8952protected:
8953 virtual void SetUp() override {
8954 InputDispatcherTest::SetUp();
8955
8956 std::shared_ptr<FakeApplicationHandle> application =
8957 std::make_shared<FakeApplicationHandle>();
8958 application->setDispatchingTimeout(100ms);
8959 mWindow = sp<FakeWindowHandle>::make(application, mDispatcher, "TestWindow",
8960 ADISPLAY_ID_DEFAULT);
Yeabkal Wubshit222d83d2024-01-24 18:00:09 +00008961 mWindow->setFrame(Rect(0, 0, 100, 100));
Yeabkal Wubshitb8aadfa2024-01-17 17:03:42 -08008962 mWindow->setDispatchingTimeout(100ms);
8963 mWindow->setFocusable(true);
8964
8965 // Set focused application.
8966 mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application);
8967
8968 mDispatcher->onWindowInfosChanged({{*mWindow->getInfo()}, {}, 0, 0});
8969 setFocusedWindow(mWindow);
8970 mWindow->consumeFocusEvent(true);
8971 }
8972
Linnan Li13bf76a2024-05-05 19:18:02 +08008973 void notifyAndConsumeMotion(int32_t action, uint32_t source, ui::LogicalDisplayId displayId,
Yeabkal Wubshitb8aadfa2024-01-17 17:03:42 -08008974 nsecs_t eventTime) {
8975 mDispatcher->notifyMotion(MotionArgsBuilder(action, source)
8976 .displayId(displayId)
8977 .eventTime(eventTime)
8978 .pointer(PointerBuilder(0, ToolType::FINGER).x(50).y(50))
8979 .build());
8980 mWindow->consumeMotionEvent(WithMotionAction(action));
8981 }
8982
8983private:
8984 sp<FakeWindowHandle> mWindow;
8985};
8986
8987TEST_F_WITH_FLAGS(
8988 InputDispatcherUserActivityPokeTests, MinPokeTimeObserved,
8989 REQUIRES_FLAGS_ENABLED(ACONFIG_FLAG(com::android::input::flags,
8990 rate_limit_user_activity_poke_in_dispatcher))) {
8991 mDispatcher->setMinTimeBetweenUserActivityPokes(50ms);
8992
8993 // First event of type TOUCH. Should poke.
8994 notifyAndConsumeMotion(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
8995 milliseconds_to_nanoseconds(50));
8996 mFakePolicy->assertUserActivityPoked(
8997 {{milliseconds_to_nanoseconds(50), USER_ACTIVITY_EVENT_TOUCH, ADISPLAY_ID_DEFAULT}});
8998
8999 // 80ns > 50ns has passed since previous TOUCH event. Should poke.
9000 notifyAndConsumeMotion(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
9001 milliseconds_to_nanoseconds(130));
9002 mFakePolicy->assertUserActivityPoked(
9003 {{milliseconds_to_nanoseconds(130), USER_ACTIVITY_EVENT_TOUCH, ADISPLAY_ID_DEFAULT}});
9004
9005 // First event of type OTHER. Should poke (despite being within 50ns of previous TOUCH event).
9006 notifyAndConsumeMotion(ACTION_SCROLL, AINPUT_SOURCE_ROTARY_ENCODER, ADISPLAY_ID_DEFAULT,
9007 milliseconds_to_nanoseconds(135));
9008 mFakePolicy->assertUserActivityPoked(
9009 {{milliseconds_to_nanoseconds(135), USER_ACTIVITY_EVENT_OTHER, ADISPLAY_ID_DEFAULT}});
9010
9011 // Within 50ns of previous TOUCH event. Should NOT poke.
9012 notifyAndConsumeMotion(ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
9013 milliseconds_to_nanoseconds(140));
9014 mFakePolicy->assertUserActivityNotPoked();
9015
9016 // Within 50ns of previous OTHER event. Should NOT poke.
9017 notifyAndConsumeMotion(ACTION_SCROLL, AINPUT_SOURCE_ROTARY_ENCODER, ADISPLAY_ID_DEFAULT,
9018 milliseconds_to_nanoseconds(150));
9019 mFakePolicy->assertUserActivityNotPoked();
9020
9021 // Within 50ns of previous TOUCH event (which was at time 130). Should NOT poke.
9022 // Note that STYLUS is mapped to TOUCH user activity, since it's a pointer-type source.
9023 notifyAndConsumeMotion(ACTION_DOWN, AINPUT_SOURCE_STYLUS, ADISPLAY_ID_DEFAULT,
9024 milliseconds_to_nanoseconds(160));
9025 mFakePolicy->assertUserActivityNotPoked();
9026
9027 // 65ns > 50ns has passed since previous OTHER event. Should poke.
9028 notifyAndConsumeMotion(ACTION_SCROLL, AINPUT_SOURCE_ROTARY_ENCODER, ADISPLAY_ID_DEFAULT,
9029 milliseconds_to_nanoseconds(200));
9030 mFakePolicy->assertUserActivityPoked(
9031 {{milliseconds_to_nanoseconds(200), USER_ACTIVITY_EVENT_OTHER, ADISPLAY_ID_DEFAULT}});
9032
9033 // 170ns > 50ns has passed since previous TOUCH event. Should poke.
9034 notifyAndConsumeMotion(ACTION_UP, AINPUT_SOURCE_STYLUS, ADISPLAY_ID_DEFAULT,
9035 milliseconds_to_nanoseconds(300));
9036 mFakePolicy->assertUserActivityPoked(
9037 {{milliseconds_to_nanoseconds(300), USER_ACTIVITY_EVENT_TOUCH, ADISPLAY_ID_DEFAULT}});
9038
9039 // Assert that there's no more user activity poke event.
9040 mFakePolicy->assertUserActivityNotPoked();
9041}
9042
9043TEST_F_WITH_FLAGS(
9044 InputDispatcherUserActivityPokeTests, DefaultMinPokeTimeOf100MsUsed,
9045 REQUIRES_FLAGS_ENABLED(ACONFIG_FLAG(com::android::input::flags,
9046 rate_limit_user_activity_poke_in_dispatcher))) {
9047 notifyAndConsumeMotion(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
9048 milliseconds_to_nanoseconds(200));
9049 mFakePolicy->assertUserActivityPoked(
9050 {{milliseconds_to_nanoseconds(200), USER_ACTIVITY_EVENT_TOUCH, ADISPLAY_ID_DEFAULT}});
9051
9052 notifyAndConsumeMotion(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
9053 milliseconds_to_nanoseconds(280));
9054 mFakePolicy->assertUserActivityNotPoked();
9055
9056 notifyAndConsumeMotion(ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
9057 milliseconds_to_nanoseconds(340));
9058 mFakePolicy->assertUserActivityPoked(
9059 {{milliseconds_to_nanoseconds(340), USER_ACTIVITY_EVENT_TOUCH, ADISPLAY_ID_DEFAULT}});
9060}
9061
9062TEST_F_WITH_FLAGS(
9063 InputDispatcherUserActivityPokeTests, ZeroMinPokeTimeDisablesRateLimiting,
9064 REQUIRES_FLAGS_ENABLED(ACONFIG_FLAG(com::android::input::flags,
9065 rate_limit_user_activity_poke_in_dispatcher))) {
9066 mDispatcher->setMinTimeBetweenUserActivityPokes(0ms);
9067
9068 notifyAndConsumeMotion(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, 20);
9069 mFakePolicy->assertUserActivityPoked();
9070
9071 notifyAndConsumeMotion(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, 30);
9072 mFakePolicy->assertUserActivityPoked();
9073}
9074
chaviwfd6d3512019-03-25 13:23:49 -07009075class InputDispatcherOnPointerDownOutsideFocus : public InputDispatcherTest {
Prabir Pradhan3608aad2019-10-02 17:08:26 -07009076 virtual void SetUp() override {
chaviwfd6d3512019-03-25 13:23:49 -07009077 InputDispatcherTest::SetUp();
9078
Chris Yea209fde2020-07-22 13:54:51 -07009079 std::shared_ptr<FakeApplicationHandle> application =
9080 std::make_shared<FakeApplicationHandle>();
Siarhei Vishniakou870ecec2020-12-09 08:07:46 -10009081 mUnfocusedWindow =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07009082 sp<FakeWindowHandle>::make(application, mDispatcher, "Top", ADISPLAY_ID_DEFAULT);
chaviwfd6d3512019-03-25 13:23:49 -07009083 mUnfocusedWindow->setFrame(Rect(0, 0, 30, 30));
chaviwfd6d3512019-03-25 13:23:49 -07009084
Siarhei Vishniakoub9b15352019-11-26 13:19:26 -08009085 mFocusedWindow =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07009086 sp<FakeWindowHandle>::make(application, mDispatcher, "Second", ADISPLAY_ID_DEFAULT);
Siarhei Vishniakoub9b15352019-11-26 13:19:26 -08009087 mFocusedWindow->setFrame(Rect(50, 50, 100, 100));
chaviwfd6d3512019-03-25 13:23:49 -07009088
9089 // Set focused application.
9090 mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application);
Vishnu Nair47074b82020-08-14 11:54:47 -07009091 mFocusedWindow->setFocusable(true);
chaviwfd6d3512019-03-25 13:23:49 -07009092
9093 // Expect one focus window exist in display.
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07009094 mDispatcher->onWindowInfosChanged(
9095 {{*mUnfocusedWindow->getInfo(), *mFocusedWindow->getInfo()}, {}, 0, 0});
Vishnu Nair958da932020-08-21 17:12:37 -07009096 setFocusedWindow(mFocusedWindow);
Siarhei Vishniakouf1035d42019-09-20 16:32:01 +01009097 mFocusedWindow->consumeFocusEvent(true);
chaviwfd6d3512019-03-25 13:23:49 -07009098 }
9099
Prabir Pradhan3608aad2019-10-02 17:08:26 -07009100 virtual void TearDown() override {
chaviwfd6d3512019-03-25 13:23:49 -07009101 InputDispatcherTest::TearDown();
9102
9103 mUnfocusedWindow.clear();
Siarhei Vishniakoub9b15352019-11-26 13:19:26 -08009104 mFocusedWindow.clear();
chaviwfd6d3512019-03-25 13:23:49 -07009105 }
9106
9107protected:
9108 sp<FakeWindowHandle> mUnfocusedWindow;
Siarhei Vishniakoub9b15352019-11-26 13:19:26 -08009109 sp<FakeWindowHandle> mFocusedWindow;
Siarhei Vishniakoufb9fcda2020-05-04 14:59:19 -07009110 static constexpr PointF FOCUSED_WINDOW_TOUCH_POINT = {60, 60};
chaviwfd6d3512019-03-25 13:23:49 -07009111};
9112
9113// Have two windows, one with focus. Inject MotionEvent with source TOUCHSCREEN and action
9114// DOWN on the window that doesn't have focus. Ensure the window that didn't have focus received
9115// the onPointerDownOutsideFocus callback.
9116TEST_F(InputDispatcherOnPointerDownOutsideFocus, OnPointerDownOutsideFocus_Success) {
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08009117 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07009118 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
Siarhei Vishniakoufb9fcda2020-05-04 14:59:19 -07009119 {20, 20}))
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08009120 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
Siarhei Vishniakou03aee2a2020-04-13 20:44:54 -07009121 mUnfocusedWindow->consumeMotionDown();
chaviwfd6d3512019-03-25 13:23:49 -07009122
Siarhei Vishniakou2bfa9052019-11-21 18:10:54 -08009123 ASSERT_TRUE(mDispatcher->waitForIdle());
chaviwfd6d3512019-03-25 13:23:49 -07009124 mFakePolicy->assertOnPointerDownEquals(mUnfocusedWindow->getToken());
9125}
9126
9127// Have two windows, one with focus. Inject MotionEvent with source TRACKBALL and action
9128// DOWN on the window that doesn't have focus. Ensure no window received the
9129// onPointerDownOutsideFocus callback.
9130TEST_F(InputDispatcherOnPointerDownOutsideFocus, OnPointerDownOutsideFocus_NonPointerSource) {
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08009131 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07009132 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TRACKBALL, ADISPLAY_ID_DEFAULT,
9133 {20, 20}))
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08009134 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
Siarhei Vishniakou03aee2a2020-04-13 20:44:54 -07009135 mFocusedWindow->consumeMotionDown();
chaviwfd6d3512019-03-25 13:23:49 -07009136
Siarhei Vishniakou2bfa9052019-11-21 18:10:54 -08009137 ASSERT_TRUE(mDispatcher->waitForIdle());
9138 mFakePolicy->assertOnPointerDownWasNotCalled();
chaviwfd6d3512019-03-25 13:23:49 -07009139}
9140
9141// Have two windows, one with focus. Inject KeyEvent with action DOWN on the window that doesn't
9142// have focus. Ensure no window received the onPointerDownOutsideFocus callback.
9143TEST_F(InputDispatcherOnPointerDownOutsideFocus, OnPointerDownOutsideFocus_NonMotionFailure) {
Prabir Pradhan93f342c2021-03-11 15:05:30 -08009144 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07009145 injectKeyDownNoRepeat(*mDispatcher, ADISPLAY_ID_DEFAULT))
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08009146 << "Inject key event should return InputEventInjectionResult::SUCCEEDED";
Siarhei Vishniakou03aee2a2020-04-13 20:44:54 -07009147 mFocusedWindow->consumeKeyDown(ADISPLAY_ID_DEFAULT);
chaviwfd6d3512019-03-25 13:23:49 -07009148
Siarhei Vishniakou2bfa9052019-11-21 18:10:54 -08009149 ASSERT_TRUE(mDispatcher->waitForIdle());
9150 mFakePolicy->assertOnPointerDownWasNotCalled();
chaviwfd6d3512019-03-25 13:23:49 -07009151}
9152
9153// Have two windows, one with focus. Inject MotionEvent with source TOUCHSCREEN and action
9154// DOWN on the window that already has focus. Ensure no window received the
9155// onPointerDownOutsideFocus callback.
Siarhei Vishniakou870ecec2020-12-09 08:07:46 -10009156TEST_F(InputDispatcherOnPointerDownOutsideFocus, OnPointerDownOutsideFocus_OnAlreadyFocusedWindow) {
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08009157 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07009158 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
Siarhei Vishniakoufb9fcda2020-05-04 14:59:19 -07009159 FOCUSED_WINDOW_TOUCH_POINT))
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08009160 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
Siarhei Vishniakou03aee2a2020-04-13 20:44:54 -07009161 mFocusedWindow->consumeMotionDown();
chaviwfd6d3512019-03-25 13:23:49 -07009162
Siarhei Vishniakou2bfa9052019-11-21 18:10:54 -08009163 ASSERT_TRUE(mDispatcher->waitForIdle());
9164 mFakePolicy->assertOnPointerDownWasNotCalled();
chaviwfd6d3512019-03-25 13:23:49 -07009165}
9166
Prabir Pradhan47cf0a02021-03-11 20:30:57 -08009167// Have two windows, one with focus. Injecting a trusted DOWN MotionEvent with the flag
9168// NO_FOCUS_CHANGE on the unfocused window should not call the onPointerDownOutsideFocus callback.
9169TEST_F(InputDispatcherOnPointerDownOutsideFocus, NoFocusChangeFlag) {
9170 const MotionEvent event =
9171 MotionEventBuilder(AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_MOUSE)
9172 .eventTime(systemTime(SYSTEM_TIME_MONOTONIC))
Siarhei Vishniakou6d73f832022-07-21 17:27:03 -07009173 .pointer(PointerBuilder(/*id=*/0, ToolType::FINGER).x(20).y(20))
Prabir Pradhan47cf0a02021-03-11 20:30:57 -08009174 .addFlag(AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE)
9175 .build();
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07009176 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectMotionEvent(*mDispatcher, event))
Prabir Pradhan47cf0a02021-03-11 20:30:57 -08009177 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
9178 mUnfocusedWindow->consumeAnyMotionDown(ADISPLAY_ID_DEFAULT, AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
9179
9180 ASSERT_TRUE(mDispatcher->waitForIdle());
9181 mFakePolicy->assertOnPointerDownWasNotCalled();
9182 // Ensure that the unfocused window did not receive any FOCUS events.
9183 mUnfocusedWindow->assertNoEvents();
9184}
9185
chaviwaf87b3e2019-10-01 16:59:28 -07009186// These tests ensures we can send touch events to a single client when there are multiple input
9187// windows that point to the same client token.
9188class InputDispatcherMultiWindowSameTokenTests : public InputDispatcherTest {
9189 virtual void SetUp() override {
9190 InputDispatcherTest::SetUp();
9191
Chris Yea209fde2020-07-22 13:54:51 -07009192 std::shared_ptr<FakeApplicationHandle> application =
9193 std::make_shared<FakeApplicationHandle>();
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07009194 mWindow1 = sp<FakeWindowHandle>::make(application, mDispatcher, "Fake Window 1",
9195 ADISPLAY_ID_DEFAULT);
chaviwaf87b3e2019-10-01 16:59:28 -07009196 mWindow1->setFrame(Rect(0, 0, 100, 100));
9197
Prabir Pradhane7cc69c2024-01-05 21:35:28 +00009198 mWindow2 = mWindow1->clone(ADISPLAY_ID_DEFAULT);
chaviwaf87b3e2019-10-01 16:59:28 -07009199 mWindow2->setFrame(Rect(100, 100, 200, 200));
9200
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07009201 mDispatcher->onWindowInfosChanged({{*mWindow1->getInfo(), *mWindow2->getInfo()}, {}, 0, 0});
chaviwaf87b3e2019-10-01 16:59:28 -07009202 }
9203
9204protected:
9205 sp<FakeWindowHandle> mWindow1;
9206 sp<FakeWindowHandle> mWindow2;
9207
9208 // Helper function to convert the point from screen coordinates into the window's space
chaviw3277faf2021-05-19 16:45:23 -05009209 static PointF getPointInWindow(const WindowInfo* windowInfo, const PointF& point) {
chaviw1ff3d1e2020-07-01 15:53:47 -07009210 vec2 vals = windowInfo->transform.transform(point.x, point.y);
9211 return {vals.x, vals.y};
chaviwaf87b3e2019-10-01 16:59:28 -07009212 }
9213
9214 void consumeMotionEvent(const sp<FakeWindowHandle>& window, int32_t expectedAction,
9215 const std::vector<PointF>& points) {
Siarhei Vishniakouf1035d42019-09-20 16:32:01 +01009216 const std::string name = window->getName();
Siarhei Vishniakoud3061ab2023-12-18 20:41:08 -08009217 std::unique_ptr<MotionEvent> motionEvent =
Prabir Pradhan7662a8d2023-12-15 01:58:14 +00009218 window->consumeMotionEvent(WithMotionAction(expectedAction));
Siarhei Vishniakoud3061ab2023-12-18 20:41:08 -08009219 ASSERT_NE(nullptr, motionEvent);
9220 ASSERT_EQ(points.size(), motionEvent->getPointerCount());
chaviwaf87b3e2019-10-01 16:59:28 -07009221
9222 for (size_t i = 0; i < points.size(); i++) {
9223 float expectedX = points[i].x;
9224 float expectedY = points[i].y;
9225
Siarhei Vishniakoud3061ab2023-12-18 20:41:08 -08009226 EXPECT_EQ(expectedX, motionEvent->getX(i))
chaviwaf87b3e2019-10-01 16:59:28 -07009227 << "expected " << expectedX << " for x[" << i << "] coord of " << name.c_str()
Siarhei Vishniakoud3061ab2023-12-18 20:41:08 -08009228 << ", got " << motionEvent->getX(i);
9229 EXPECT_EQ(expectedY, motionEvent->getY(i))
chaviwaf87b3e2019-10-01 16:59:28 -07009230 << "expected " << expectedY << " for y[" << i << "] coord of " << name.c_str()
Siarhei Vishniakoud3061ab2023-12-18 20:41:08 -08009231 << ", got " << motionEvent->getY(i);
chaviwaf87b3e2019-10-01 16:59:28 -07009232 }
9233 }
chaviw9eaa22c2020-07-01 16:21:27 -07009234
Prabir Pradhanbb3f1c02024-01-04 20:17:14 +00009235 void touchAndAssertPositions(sp<FakeWindowHandle> touchedWindow, int32_t action,
9236 const std::vector<PointF>& touchedPoints,
chaviw9eaa22c2020-07-01 16:21:27 -07009237 std::vector<PointF> expectedPoints) {
Prabir Pradhan678438e2023-04-13 19:32:51 +00009238 mDispatcher->notifyMotion(generateMotionArgs(action, AINPUT_SOURCE_TOUCHSCREEN,
9239 ADISPLAY_ID_DEFAULT, touchedPoints));
chaviw9eaa22c2020-07-01 16:21:27 -07009240
Prabir Pradhanbb3f1c02024-01-04 20:17:14 +00009241 consumeMotionEvent(touchedWindow, action, expectedPoints);
chaviw9eaa22c2020-07-01 16:21:27 -07009242 }
chaviwaf87b3e2019-10-01 16:59:28 -07009243};
9244
9245TEST_F(InputDispatcherMultiWindowSameTokenTests, SingleTouchSameScale) {
9246 // Touch Window 1
9247 PointF touchedPoint = {10, 10};
9248 PointF expectedPoint = getPointInWindow(mWindow1->getInfo(), touchedPoint);
Prabir Pradhanbb3f1c02024-01-04 20:17:14 +00009249 touchAndAssertPositions(mWindow1, AMOTION_EVENT_ACTION_DOWN, {touchedPoint}, {expectedPoint});
chaviwaf87b3e2019-10-01 16:59:28 -07009250
9251 // Release touch on Window 1
Prabir Pradhanbb3f1c02024-01-04 20:17:14 +00009252 touchAndAssertPositions(mWindow1, AMOTION_EVENT_ACTION_UP, {touchedPoint}, {expectedPoint});
chaviwaf87b3e2019-10-01 16:59:28 -07009253
9254 // Touch Window 2
9255 touchedPoint = {150, 150};
9256 expectedPoint = getPointInWindow(mWindow2->getInfo(), touchedPoint);
Prabir Pradhanbb3f1c02024-01-04 20:17:14 +00009257 touchAndAssertPositions(mWindow2, AMOTION_EVENT_ACTION_DOWN, {touchedPoint}, {expectedPoint});
chaviwaf87b3e2019-10-01 16:59:28 -07009258}
9259
chaviw9eaa22c2020-07-01 16:21:27 -07009260TEST_F(InputDispatcherMultiWindowSameTokenTests, SingleTouchDifferentTransform) {
9261 // Set scale value for window2
chaviwaf87b3e2019-10-01 16:59:28 -07009262 mWindow2->setWindowScale(0.5f, 0.5f);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07009263 mDispatcher->onWindowInfosChanged({{*mWindow1->getInfo(), *mWindow2->getInfo()}, {}, 0, 0});
chaviwaf87b3e2019-10-01 16:59:28 -07009264
9265 // Touch Window 1
9266 PointF touchedPoint = {10, 10};
9267 PointF expectedPoint = getPointInWindow(mWindow1->getInfo(), touchedPoint);
Prabir Pradhanbb3f1c02024-01-04 20:17:14 +00009268 touchAndAssertPositions(mWindow1, AMOTION_EVENT_ACTION_DOWN, {touchedPoint}, {expectedPoint});
chaviwaf87b3e2019-10-01 16:59:28 -07009269 // Release touch on Window 1
Prabir Pradhanbb3f1c02024-01-04 20:17:14 +00009270 touchAndAssertPositions(mWindow1, AMOTION_EVENT_ACTION_UP, {touchedPoint}, {expectedPoint});
chaviwaf87b3e2019-10-01 16:59:28 -07009271
9272 // Touch Window 2
9273 touchedPoint = {150, 150};
9274 expectedPoint = getPointInWindow(mWindow2->getInfo(), touchedPoint);
Prabir Pradhanbb3f1c02024-01-04 20:17:14 +00009275 touchAndAssertPositions(mWindow2, AMOTION_EVENT_ACTION_DOWN, {touchedPoint}, {expectedPoint});
9276 touchAndAssertPositions(mWindow2, AMOTION_EVENT_ACTION_UP, {touchedPoint}, {expectedPoint});
chaviwaf87b3e2019-10-01 16:59:28 -07009277
chaviw9eaa22c2020-07-01 16:21:27 -07009278 // Update the transform so rotation is set
9279 mWindow2->setWindowTransform(0, -1, 1, 0);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07009280 mDispatcher->onWindowInfosChanged({{*mWindow1->getInfo(), *mWindow2->getInfo()}, {}, 0, 0});
chaviw9eaa22c2020-07-01 16:21:27 -07009281 expectedPoint = getPointInWindow(mWindow2->getInfo(), touchedPoint);
Prabir Pradhanbb3f1c02024-01-04 20:17:14 +00009282 touchAndAssertPositions(mWindow2, AMOTION_EVENT_ACTION_DOWN, {touchedPoint}, {expectedPoint});
chaviwaf87b3e2019-10-01 16:59:28 -07009283}
9284
chaviw9eaa22c2020-07-01 16:21:27 -07009285TEST_F(InputDispatcherMultiWindowSameTokenTests, MultipleTouchDifferentTransform) {
Chavi Weingarten65f98b82020-01-16 18:56:50 +00009286 mWindow2->setWindowScale(0.5f, 0.5f);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07009287 mDispatcher->onWindowInfosChanged({{*mWindow1->getInfo(), *mWindow2->getInfo()}, {}, 0, 0});
Chavi Weingarten65f98b82020-01-16 18:56:50 +00009288
9289 // Touch Window 1
9290 std::vector<PointF> touchedPoints = {PointF{10, 10}};
9291 std::vector<PointF> expectedPoints = {getPointInWindow(mWindow1->getInfo(), touchedPoints[0])};
Prabir Pradhanbb3f1c02024-01-04 20:17:14 +00009292 touchAndAssertPositions(mWindow1, AMOTION_EVENT_ACTION_DOWN, touchedPoints, expectedPoints);
Chavi Weingarten65f98b82020-01-16 18:56:50 +00009293
9294 // Touch Window 2
Prabir Pradhanbb3f1c02024-01-04 20:17:14 +00009295 // Since this is part of the same touch gesture that has already been dispatched to Window 1,
9296 // the touch stream from Window 2 will be merged with the stream in Window 1. The merged stream
9297 // will continue to be dispatched through Window 1.
chaviw9eaa22c2020-07-01 16:21:27 -07009298 touchedPoints.push_back(PointF{150, 150});
9299 expectedPoints.push_back(getPointInWindow(mWindow2->getInfo(), touchedPoints[1]));
Prabir Pradhanbb3f1c02024-01-04 20:17:14 +00009300 touchAndAssertPositions(mWindow1, POINTER_1_DOWN, touchedPoints, expectedPoints);
Chavi Weingarten65f98b82020-01-16 18:56:50 +00009301
chaviw9eaa22c2020-07-01 16:21:27 -07009302 // Release Window 2
Prabir Pradhanbb3f1c02024-01-04 20:17:14 +00009303 touchAndAssertPositions(mWindow1, POINTER_1_UP, touchedPoints, expectedPoints);
chaviw9eaa22c2020-07-01 16:21:27 -07009304 expectedPoints.pop_back();
Chavi Weingarten65f98b82020-01-16 18:56:50 +00009305
chaviw9eaa22c2020-07-01 16:21:27 -07009306 // Update the transform so rotation is set for Window 2
9307 mWindow2->setWindowTransform(0, -1, 1, 0);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07009308 mDispatcher->onWindowInfosChanged({{*mWindow1->getInfo(), *mWindow2->getInfo()}, {}, 0, 0});
chaviw9eaa22c2020-07-01 16:21:27 -07009309 expectedPoints.push_back(getPointInWindow(mWindow2->getInfo(), touchedPoints[1]));
Prabir Pradhanbb3f1c02024-01-04 20:17:14 +00009310 touchAndAssertPositions(mWindow1, POINTER_1_DOWN, touchedPoints, expectedPoints);
Chavi Weingarten65f98b82020-01-16 18:56:50 +00009311}
9312
chaviw9eaa22c2020-07-01 16:21:27 -07009313TEST_F(InputDispatcherMultiWindowSameTokenTests, MultipleTouchMoveDifferentTransform) {
Chavi Weingarten65f98b82020-01-16 18:56:50 +00009314 mWindow2->setWindowScale(0.5f, 0.5f);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07009315 mDispatcher->onWindowInfosChanged({{*mWindow1->getInfo(), *mWindow2->getInfo()}, {}, 0, 0});
Chavi Weingarten65f98b82020-01-16 18:56:50 +00009316
9317 // Touch Window 1
9318 std::vector<PointF> touchedPoints = {PointF{10, 10}};
9319 std::vector<PointF> expectedPoints = {getPointInWindow(mWindow1->getInfo(), touchedPoints[0])};
Prabir Pradhanbb3f1c02024-01-04 20:17:14 +00009320 touchAndAssertPositions(mWindow1, AMOTION_EVENT_ACTION_DOWN, touchedPoints, expectedPoints);
Chavi Weingarten65f98b82020-01-16 18:56:50 +00009321
9322 // Touch Window 2
chaviw9eaa22c2020-07-01 16:21:27 -07009323 touchedPoints.push_back(PointF{150, 150});
9324 expectedPoints.push_back(getPointInWindow(mWindow2->getInfo(), touchedPoints[1]));
Chavi Weingarten65f98b82020-01-16 18:56:50 +00009325
Prabir Pradhanbb3f1c02024-01-04 20:17:14 +00009326 touchAndAssertPositions(mWindow1, POINTER_1_DOWN, touchedPoints, expectedPoints);
Chavi Weingarten65f98b82020-01-16 18:56:50 +00009327
9328 // Move both windows
9329 touchedPoints = {{20, 20}, {175, 175}};
9330 expectedPoints = {getPointInWindow(mWindow1->getInfo(), touchedPoints[0]),
9331 getPointInWindow(mWindow2->getInfo(), touchedPoints[1])};
9332
Prabir Pradhanbb3f1c02024-01-04 20:17:14 +00009333 touchAndAssertPositions(mWindow1, AMOTION_EVENT_ACTION_MOVE, touchedPoints, expectedPoints);
Chavi Weingarten65f98b82020-01-16 18:56:50 +00009334
chaviw9eaa22c2020-07-01 16:21:27 -07009335 // Release Window 2
Prabir Pradhanbb3f1c02024-01-04 20:17:14 +00009336 touchAndAssertPositions(mWindow1, POINTER_1_UP, touchedPoints, expectedPoints);
chaviw9eaa22c2020-07-01 16:21:27 -07009337 expectedPoints.pop_back();
9338
9339 // Touch Window 2
9340 mWindow2->setWindowTransform(0, -1, 1, 0);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07009341 mDispatcher->onWindowInfosChanged({{*mWindow1->getInfo(), *mWindow2->getInfo()}, {}, 0, 0});
chaviw9eaa22c2020-07-01 16:21:27 -07009342 expectedPoints.push_back(getPointInWindow(mWindow2->getInfo(), touchedPoints[1]));
Prabir Pradhanbb3f1c02024-01-04 20:17:14 +00009343 touchAndAssertPositions(mWindow1, POINTER_1_DOWN, touchedPoints, expectedPoints);
chaviw9eaa22c2020-07-01 16:21:27 -07009344
9345 // Move both windows
9346 touchedPoints = {{20, 20}, {175, 175}};
9347 expectedPoints = {getPointInWindow(mWindow1->getInfo(), touchedPoints[0]),
9348 getPointInWindow(mWindow2->getInfo(), touchedPoints[1])};
9349
Prabir Pradhanbb3f1c02024-01-04 20:17:14 +00009350 touchAndAssertPositions(mWindow1, AMOTION_EVENT_ACTION_MOVE, touchedPoints, expectedPoints);
Chavi Weingarten65f98b82020-01-16 18:56:50 +00009351}
9352
9353TEST_F(InputDispatcherMultiWindowSameTokenTests, MultipleWindowsFirstTouchWithScale) {
9354 mWindow1->setWindowScale(0.5f, 0.5f);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07009355 mDispatcher->onWindowInfosChanged({{*mWindow1->getInfo(), *mWindow2->getInfo()}, {}, 0, 0});
Chavi Weingarten65f98b82020-01-16 18:56:50 +00009356
9357 // Touch Window 1
9358 std::vector<PointF> touchedPoints = {PointF{10, 10}};
9359 std::vector<PointF> expectedPoints = {getPointInWindow(mWindow1->getInfo(), touchedPoints[0])};
Prabir Pradhanbb3f1c02024-01-04 20:17:14 +00009360 touchAndAssertPositions(mWindow1, AMOTION_EVENT_ACTION_DOWN, touchedPoints, expectedPoints);
Chavi Weingarten65f98b82020-01-16 18:56:50 +00009361
9362 // Touch Window 2
chaviw9eaa22c2020-07-01 16:21:27 -07009363 touchedPoints.push_back(PointF{150, 150});
9364 expectedPoints.push_back(getPointInWindow(mWindow2->getInfo(), touchedPoints[1]));
Chavi Weingarten65f98b82020-01-16 18:56:50 +00009365
Prabir Pradhanbb3f1c02024-01-04 20:17:14 +00009366 touchAndAssertPositions(mWindow1, POINTER_1_DOWN, touchedPoints, expectedPoints);
Chavi Weingarten65f98b82020-01-16 18:56:50 +00009367
9368 // Move both windows
9369 touchedPoints = {{20, 20}, {175, 175}};
9370 expectedPoints = {getPointInWindow(mWindow1->getInfo(), touchedPoints[0]),
9371 getPointInWindow(mWindow2->getInfo(), touchedPoints[1])};
9372
Prabir Pradhanbb3f1c02024-01-04 20:17:14 +00009373 touchAndAssertPositions(mWindow1, AMOTION_EVENT_ACTION_MOVE, touchedPoints, expectedPoints);
Chavi Weingarten65f98b82020-01-16 18:56:50 +00009374}
9375
Siarhei Vishniakou0f6558d2023-04-21 12:05:13 -07009376/**
9377 * When one of the windows is slippery, the touch should not slip into the other window with the
9378 * same input channel.
9379 */
9380TEST_F(InputDispatcherMultiWindowSameTokenTests, TouchDoesNotSlipEvenIfSlippery) {
9381 mWindow1->setSlippery(true);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07009382 mDispatcher->onWindowInfosChanged({{*mWindow1->getInfo(), *mWindow2->getInfo()}, {}, 0, 0});
Siarhei Vishniakou0f6558d2023-04-21 12:05:13 -07009383
9384 // Touch down in window 1
9385 mDispatcher->notifyMotion(generateMotionArgs(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN,
9386 ADISPLAY_ID_DEFAULT, {{50, 50}}));
9387 consumeMotionEvent(mWindow1, ACTION_DOWN, {{50, 50}});
9388
9389 // Move touch to be above window 2. Even though window 1 is slippery, touch should not slip.
9390 // That means the gesture should continue normally, without any ACTION_CANCEL or ACTION_DOWN
9391 // getting generated.
9392 mDispatcher->notifyMotion(generateMotionArgs(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN,
9393 ADISPLAY_ID_DEFAULT, {{150, 150}}));
9394
9395 consumeMotionEvent(mWindow1, ACTION_MOVE, {{150, 150}});
9396}
9397
Siarhei Vishniakoud5876ba2023-05-15 17:58:34 -07009398/**
9399 * When hover starts in one window and continues into the other, there should be a HOVER_EXIT and
9400 * a HOVER_ENTER generated, even if the windows have the same token. This is because the new window
9401 * that the pointer is hovering over may have a different transform.
9402 */
9403TEST_F(InputDispatcherMultiWindowSameTokenTests, HoverIntoClone) {
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07009404 mDispatcher->onWindowInfosChanged({{*mWindow1->getInfo(), *mWindow2->getInfo()}, {}, 0, 0});
Siarhei Vishniakoud5876ba2023-05-15 17:58:34 -07009405
9406 // Start hover in window 1
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -07009407 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_ENTER, AINPUT_SOURCE_TOUCHSCREEN)
9408 .pointer(PointerBuilder(0, ToolType::FINGER).x(50).y(50))
9409 .build());
Siarhei Vishniakoud5876ba2023-05-15 17:58:34 -07009410 consumeMotionEvent(mWindow1, ACTION_HOVER_ENTER,
9411 {getPointInWindow(mWindow1->getInfo(), PointF{50, 50})});
Siarhei Vishniakoud5876ba2023-05-15 17:58:34 -07009412 // Move hover to window 2.
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -07009413 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_MOVE, AINPUT_SOURCE_TOUCHSCREEN)
9414 .pointer(PointerBuilder(0, ToolType::FINGER).x(150).y(150))
9415 .build());
Siarhei Vishniakoud5876ba2023-05-15 17:58:34 -07009416 consumeMotionEvent(mWindow1, ACTION_HOVER_EXIT, {{50, 50}});
Prabir Pradhanbb3f1c02024-01-04 20:17:14 +00009417 consumeMotionEvent(mWindow2, ACTION_HOVER_ENTER,
Siarhei Vishniakoud5876ba2023-05-15 17:58:34 -07009418 {getPointInWindow(mWindow2->getInfo(), PointF{150, 150})});
9419}
9420
Siarhei Vishniakou4cb50ca2020-05-26 21:43:02 -07009421class InputDispatcherSingleWindowAnr : public InputDispatcherTest {
9422 virtual void SetUp() override {
9423 InputDispatcherTest::SetUp();
9424
Chris Yea209fde2020-07-22 13:54:51 -07009425 mApplication = std::make_shared<FakeApplicationHandle>();
Siarhei Vishniakouf83c6932023-07-07 17:48:10 -07009426 mApplication->setDispatchingTimeout(100ms);
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07009427 mWindow = sp<FakeWindowHandle>::make(mApplication, mDispatcher, "TestWindow",
9428 ADISPLAY_ID_DEFAULT);
Siarhei Vishniakou4cb50ca2020-05-26 21:43:02 -07009429 mWindow->setFrame(Rect(0, 0, 30, 30));
Siarhei Vishniakouf83c6932023-07-07 17:48:10 -07009430 mWindow->setDispatchingTimeout(100ms);
Vishnu Nair47074b82020-08-14 11:54:47 -07009431 mWindow->setFocusable(true);
Siarhei Vishniakou4cb50ca2020-05-26 21:43:02 -07009432
9433 // Set focused application.
9434 mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, mApplication);
9435
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07009436 mDispatcher->onWindowInfosChanged({{*mWindow->getInfo()}, {}, 0, 0});
Vishnu Nair958da932020-08-21 17:12:37 -07009437 setFocusedWindow(mWindow);
Siarhei Vishniakou4cb50ca2020-05-26 21:43:02 -07009438 mWindow->consumeFocusEvent(true);
9439 }
9440
9441 virtual void TearDown() override {
9442 InputDispatcherTest::TearDown();
9443 mWindow.clear();
9444 }
9445
9446protected:
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07009447 static constexpr std::chrono::duration SPY_TIMEOUT = 200ms;
Chris Yea209fde2020-07-22 13:54:51 -07009448 std::shared_ptr<FakeApplicationHandle> mApplication;
Siarhei Vishniakou4cb50ca2020-05-26 21:43:02 -07009449 sp<FakeWindowHandle> mWindow;
9450 static constexpr PointF WINDOW_LOCATION = {20, 20};
9451
9452 void tapOnWindow() {
Siarhei Vishniakou67bf2162023-11-16 13:29:50 -08009453 const auto touchingPointer = PointerBuilder(/*id=*/0, ToolType::FINGER)
9454 .x(WINDOW_LOCATION.x)
9455 .y(WINDOW_LOCATION.y);
9456 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
9457 .pointer(touchingPointer)
9458 .build());
9459 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN)
9460 .pointer(touchingPointer)
9461 .build());
Siarhei Vishniakou4cb50ca2020-05-26 21:43:02 -07009462 }
Prabir Pradhan1376fcd2022-01-21 09:56:35 -08009463
9464 sp<FakeWindowHandle> addSpyWindow() {
9465 sp<FakeWindowHandle> spy =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07009466 sp<FakeWindowHandle>::make(mApplication, mDispatcher, "Spy", ADISPLAY_ID_DEFAULT);
Prabir Pradhan1376fcd2022-01-21 09:56:35 -08009467 spy->setTrustedOverlay(true);
9468 spy->setFocusable(false);
Prabir Pradhan51e7db02022-02-07 06:02:57 -08009469 spy->setSpy(true);
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07009470 spy->setDispatchingTimeout(SPY_TIMEOUT);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07009471 mDispatcher->onWindowInfosChanged({{*spy->getInfo(), *mWindow->getInfo()}, {}, 0, 0});
Prabir Pradhan1376fcd2022-01-21 09:56:35 -08009472 return spy;
9473 }
Siarhei Vishniakou4cb50ca2020-05-26 21:43:02 -07009474};
9475
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009476// Send a tap and respond, which should not cause an ANR.
9477TEST_F(InputDispatcherSingleWindowAnr, WhenTouchIsConsumed_NoAnr) {
9478 tapOnWindow();
9479 mWindow->consumeMotionDown();
9480 mWindow->consumeMotionUp();
9481 ASSERT_TRUE(mDispatcher->waitForIdle());
9482 mFakePolicy->assertNotifyAnrWasNotCalled();
9483}
9484
9485// Send a regular key and respond, which should not cause an ANR.
9486TEST_F(InputDispatcherSingleWindowAnr, WhenKeyIsConsumed_NoAnr) {
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07009487 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectKeyDownNoRepeat(*mDispatcher));
Linnan Li13bf76a2024-05-05 19:18:02 +08009488 mWindow->consumeKeyDown(ui::ADISPLAY_ID_NONE);
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009489 ASSERT_TRUE(mDispatcher->waitForIdle());
9490 mFakePolicy->assertNotifyAnrWasNotCalled();
9491}
9492
Siarhei Vishniakoue41c4512020-09-08 19:35:58 -05009493TEST_F(InputDispatcherSingleWindowAnr, WhenFocusedApplicationChanges_NoAnr) {
9494 mWindow->setFocusable(false);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07009495 mDispatcher->onWindowInfosChanged({{*mWindow->getInfo()}, {}, 0, 0});
Siarhei Vishniakoue41c4512020-09-08 19:35:58 -05009496 mWindow->consumeFocusEvent(false);
9497
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08009498 InputEventInjectionResult result =
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07009499 injectKey(*mDispatcher, AKEY_EVENT_ACTION_DOWN, /*repeatCount=*/0, ADISPLAY_ID_DEFAULT,
9500 InputEventInjectionSync::NONE, CONSUME_TIMEOUT_EVENT_EXPECTED,
Harry Cutts33476232023-01-30 19:57:29 +00009501 /*allowKeyRepeat=*/false);
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08009502 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, result);
Siarhei Vishniakoue41c4512020-09-08 19:35:58 -05009503 // Key will not go to window because we have no focused window.
9504 // The 'no focused window' ANR timer should start instead.
9505
9506 // Now, the focused application goes away.
9507 mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, nullptr);
9508 // The key should get dropped and there should be no ANR.
9509
9510 ASSERT_TRUE(mDispatcher->waitForIdle());
9511 mFakePolicy->assertNotifyAnrWasNotCalled();
9512}
9513
Siarhei Vishniakou4cb50ca2020-05-26 21:43:02 -07009514// Send an event to the app and have the app not respond right away.
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009515// When ANR is raised, policy will tell the dispatcher to cancel the events for that window.
9516// So InputDispatcher will enqueue ACTION_CANCEL event as well.
Siarhei Vishniakou4cb50ca2020-05-26 21:43:02 -07009517TEST_F(InputDispatcherSingleWindowAnr, OnPointerDown_BasicAnr) {
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08009518 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07009519 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
Siarhei Vishniakou4cb50ca2020-05-26 21:43:02 -07009520 WINDOW_LOCATION));
9521
Siarhei Vishniakoud3061ab2023-12-18 20:41:08 -08009522 const auto [sequenceNum, _] = mWindow->receiveEvent(); // ACTION_DOWN
Siarhei Vishniakou4cb50ca2020-05-26 21:43:02 -07009523 ASSERT_TRUE(sequenceNum);
9524 const std::chrono::duration timeout = mWindow->getDispatchingTimeout(DISPATCHING_TIMEOUT);
Prabir Pradhanedd96402022-02-15 01:46:16 -08009525 mFakePolicy->assertNotifyWindowUnresponsiveWasCalled(timeout, mWindow);
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009526
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009527 mWindow->finishEvent(*sequenceNum);
Siarhei Vishniakou1ae72f12023-01-29 12:55:30 -08009528 mWindow->consumeMotionEvent(
9529 AllOf(WithMotionAction(ACTION_CANCEL), WithDisplayId(ADISPLAY_ID_DEFAULT)));
Siarhei Vishniakou4cb50ca2020-05-26 21:43:02 -07009530 ASSERT_TRUE(mDispatcher->waitForIdle());
Prabir Pradhanedd96402022-02-15 01:46:16 -08009531 mFakePolicy->assertNotifyWindowResponsiveWasCalled(mWindow->getToken(), mWindow->getPid());
Siarhei Vishniakou4cb50ca2020-05-26 21:43:02 -07009532}
9533
9534// Send a key to the app and have the app not respond right away.
9535TEST_F(InputDispatcherSingleWindowAnr, OnKeyDown_BasicAnr) {
9536 // Inject a key, and don't respond - expect that ANR is called.
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07009537 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectKeyDownNoRepeat(*mDispatcher));
Siarhei Vishniakoud3061ab2023-12-18 20:41:08 -08009538 const auto [sequenceNum, _] = mWindow->receiveEvent();
Siarhei Vishniakou4cb50ca2020-05-26 21:43:02 -07009539 ASSERT_TRUE(sequenceNum);
Siarhei Vishniakou4cb50ca2020-05-26 21:43:02 -07009540 const std::chrono::duration timeout = mWindow->getDispatchingTimeout(DISPATCHING_TIMEOUT);
Prabir Pradhanedd96402022-02-15 01:46:16 -08009541 mFakePolicy->assertNotifyWindowUnresponsiveWasCalled(timeout, mWindow);
Siarhei Vishniakou4cb50ca2020-05-26 21:43:02 -07009542 ASSERT_TRUE(mDispatcher->waitForIdle());
9543}
9544
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009545// We have a focused application, but no focused window
9546TEST_F(InputDispatcherSingleWindowAnr, FocusedApplication_NoFocusedWindow) {
Vishnu Nair47074b82020-08-14 11:54:47 -07009547 mWindow->setFocusable(false);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07009548 mDispatcher->onWindowInfosChanged({{*mWindow->getInfo()}, {}, 0, 0});
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009549 mWindow->consumeFocusEvent(false);
9550
9551 // taps on the window work as normal
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08009552 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07009553 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009554 WINDOW_LOCATION));
9555 ASSERT_NO_FATAL_FAILURE(mWindow->consumeMotionDown());
9556 mDispatcher->waitForIdle();
9557 mFakePolicy->assertNotifyAnrWasNotCalled();
9558
9559 // Once a focused event arrives, we get an ANR for this application
9560 // We specify the injection timeout to be smaller than the application timeout, to ensure that
9561 // injection times out (instead of failing).
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08009562 const InputEventInjectionResult result =
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07009563 injectKey(*mDispatcher, AKEY_EVENT_ACTION_DOWN, /*repeatCount=*/0, ADISPLAY_ID_DEFAULT,
Linnan Li13bf76a2024-05-05 19:18:02 +08009564 InputEventInjectionSync::WAIT_FOR_RESULT, 50ms,
9565 /*allowKeyRepeat=*/false);
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08009566 ASSERT_EQ(InputEventInjectionResult::TIMED_OUT, result);
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009567 const std::chrono::duration timeout = mApplication->getDispatchingTimeout(DISPATCHING_TIMEOUT);
Vishnu Naire4df8752022-09-08 09:17:55 -07009568 mFakePolicy->assertNotifyNoFocusedWindowAnrWasCalled(timeout, mApplication);
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009569 ASSERT_TRUE(mDispatcher->waitForIdle());
9570}
9571
Siarhei Vishniakou289e9242022-02-15 14:50:16 -08009572/**
9573 * Make sure the stale key is dropped before causing an ANR. So even if there's no focused window,
9574 * there will not be an ANR.
9575 */
9576TEST_F(InputDispatcherSingleWindowAnr, StaleKeyEventDoesNotAnr) {
9577 mWindow->setFocusable(false);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07009578 mDispatcher->onWindowInfosChanged({{*mWindow->getInfo()}, {}, 0, 0});
Siarhei Vishniakou289e9242022-02-15 14:50:16 -08009579 mWindow->consumeFocusEvent(false);
9580
9581 KeyEvent event;
Siarhei Vishniakoua7333112023-10-27 13:33:29 -07009582 static constexpr std::chrono::duration STALE_EVENT_TIMEOUT = 1000ms;
9583 mFakePolicy->setStaleEventTimeout(STALE_EVENT_TIMEOUT);
Siarhei Vishniakou289e9242022-02-15 14:50:16 -08009584 const nsecs_t eventTime = systemTime(SYSTEM_TIME_MONOTONIC) -
9585 std::chrono::nanoseconds(STALE_EVENT_TIMEOUT).count();
9586
9587 // Define a valid key down event that is stale (too old).
Linnan Li13bf76a2024-05-05 19:18:02 +08009588 event.initialize(InputEvent::nextId(), DEVICE_ID, AINPUT_SOURCE_KEYBOARD, ui::ADISPLAY_ID_NONE,
Harry Cutts101ee9b2023-07-06 18:04:14 +00009589 INVALID_HMAC, AKEY_EVENT_ACTION_DOWN, /*flags=*/0, AKEYCODE_A, KEY_A,
Hu Guofe3c8f12023-09-22 17:20:15 +08009590 AMETA_NONE, /*repeatCount=*/0, eventTime, eventTime);
Siarhei Vishniakou289e9242022-02-15 14:50:16 -08009591
Hu Guofe3c8f12023-09-22 17:20:15 +08009592 const int32_t policyFlags =
9593 POLICY_FLAG_FILTERED | POLICY_FLAG_PASS_TO_USER | POLICY_FLAG_DISABLE_KEY_REPEAT;
Siarhei Vishniakou289e9242022-02-15 14:50:16 -08009594
9595 InputEventInjectionResult result =
Harry Cutts33476232023-01-30 19:57:29 +00009596 mDispatcher->injectInputEvent(&event, /*targetUid=*/{},
Siarhei Vishniakou289e9242022-02-15 14:50:16 -08009597 InputEventInjectionSync::WAIT_FOR_RESULT,
9598 INJECT_EVENT_TIMEOUT, policyFlags);
9599 ASSERT_EQ(InputEventInjectionResult::FAILED, result)
9600 << "Injection should fail because the event is stale";
9601
9602 ASSERT_TRUE(mDispatcher->waitForIdle());
9603 mFakePolicy->assertNotifyAnrWasNotCalled();
9604 mWindow->assertNoEvents();
9605}
9606
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009607// We have a focused application, but no focused window
Siarhei Vishniakou234129c2020-10-22 22:28:12 -05009608// Make sure that we don't notify policy twice about the same ANR.
9609TEST_F(InputDispatcherSingleWindowAnr, NoFocusedWindow_DoesNotSendDuplicateAnr) {
Siarhei Vishniakou06405fc2023-09-22 13:40:51 -07009610 const std::chrono::duration appTimeout = 400ms;
9611 mApplication->setDispatchingTimeout(appTimeout);
9612 mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, mApplication);
9613
Vishnu Nair47074b82020-08-14 11:54:47 -07009614 mWindow->setFocusable(false);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07009615 mDispatcher->onWindowInfosChanged({{*mWindow->getInfo()}, {}, 0, 0});
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009616 mWindow->consumeFocusEvent(false);
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009617
9618 // Once a focused event arrives, we get an ANR for this application
9619 // We specify the injection timeout to be smaller than the application timeout, to ensure that
9620 // injection times out (instead of failing).
Siarhei Vishniakou06405fc2023-09-22 13:40:51 -07009621 const std::chrono::duration eventInjectionTimeout = 100ms;
9622 ASSERT_LT(eventInjectionTimeout, appTimeout);
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08009623 const InputEventInjectionResult result =
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07009624 injectKey(*mDispatcher, AKEY_EVENT_ACTION_DOWN, /*repeatCount=*/0, ADISPLAY_ID_DEFAULT,
Siarhei Vishniakou06405fc2023-09-22 13:40:51 -07009625 InputEventInjectionSync::WAIT_FOR_RESULT, eventInjectionTimeout,
9626 /*allowKeyRepeat=*/false);
9627 ASSERT_EQ(InputEventInjectionResult::TIMED_OUT, result)
9628 << "result=" << ftl::enum_string(result);
9629 // We already waited for 'eventInjectionTimeout`, because the countdown started when the event
9630 // was first injected. So now we have (appTimeout - eventInjectionTimeout) left to wait.
9631 std::chrono::duration remainingWaitTime = appTimeout - eventInjectionTimeout;
9632 mFakePolicy->assertNotifyNoFocusedWindowAnrWasCalled(remainingWaitTime, mApplication);
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009633
Vishnu Naire4df8752022-09-08 09:17:55 -07009634 std::this_thread::sleep_for(appTimeout);
Siarhei Vishniakou234129c2020-10-22 22:28:12 -05009635 // ANR should not be raised again. It is up to policy to do that if it desires.
9636 mFakePolicy->assertNotifyAnrWasNotCalled();
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009637
Siarhei Vishniakou234129c2020-10-22 22:28:12 -05009638 // If we now get a focused window, the ANR should stop, but the policy handles that via
9639 // 'notifyFocusChanged' callback. This is implemented in the policy so we can't test it here.
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009640 ASSERT_TRUE(mDispatcher->waitForIdle());
9641}
9642
9643// We have a focused application, but no focused window
9644TEST_F(InputDispatcherSingleWindowAnr, NoFocusedWindow_DropsFocusedEvents) {
Vishnu Nair47074b82020-08-14 11:54:47 -07009645 mWindow->setFocusable(false);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07009646 mDispatcher->onWindowInfosChanged({{*mWindow->getInfo()}, {}, 0, 0});
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009647 mWindow->consumeFocusEvent(false);
9648
9649 // Once a focused event arrives, we get an ANR for this application
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07009650 ASSERT_NO_FATAL_FAILURE(assertInjectedKeyTimesOut(*mDispatcher));
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009651
Vishnu Naire4df8752022-09-08 09:17:55 -07009652 const std::chrono::duration timeout = mApplication->getDispatchingTimeout(DISPATCHING_TIMEOUT);
9653 mFakePolicy->assertNotifyNoFocusedWindowAnrWasCalled(timeout, mApplication);
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009654
9655 // Future focused events get dropped right away
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07009656 ASSERT_EQ(InputEventInjectionResult::FAILED, injectKeyDown(*mDispatcher));
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009657 ASSERT_TRUE(mDispatcher->waitForIdle());
9658 mWindow->assertNoEvents();
9659}
9660
9661/**
9662 * Ensure that the implementation is valid. Since we are using multiset to keep track of the
9663 * ANR timeouts, we are allowing entries with identical timestamps in the same connection.
9664 * If we process 1 of the events, but ANR on the second event with the same timestamp,
9665 * the ANR mechanism should still work.
9666 *
9667 * In this test, we are injecting DOWN and UP events with the same timestamps, and acknowledging the
9668 * DOWN event, while not responding on the second one.
9669 */
9670TEST_F(InputDispatcherSingleWindowAnr, Anr_HandlesEventsWithIdenticalTimestamps) {
9671 nsecs_t currentTime = systemTime(SYSTEM_TIME_MONOTONIC);
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07009672 injectMotionEvent(*mDispatcher, AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN,
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009673 ADISPLAY_ID_DEFAULT, WINDOW_LOCATION,
9674 {AMOTION_EVENT_INVALID_CURSOR_POSITION,
9675 AMOTION_EVENT_INVALID_CURSOR_POSITION},
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08009676 500ms, InputEventInjectionSync::WAIT_FOR_RESULT, currentTime);
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009677
9678 // Now send ACTION_UP, with identical timestamp
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07009679 injectMotionEvent(*mDispatcher, AMOTION_EVENT_ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN,
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009680 ADISPLAY_ID_DEFAULT, WINDOW_LOCATION,
9681 {AMOTION_EVENT_INVALID_CURSOR_POSITION,
9682 AMOTION_EVENT_INVALID_CURSOR_POSITION},
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08009683 500ms, InputEventInjectionSync::WAIT_FOR_RESULT, currentTime);
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009684
9685 // We have now sent down and up. Let's consume first event and then ANR on the second.
9686 mWindow->consumeMotionDown(ADISPLAY_ID_DEFAULT);
9687 const std::chrono::duration timeout = mWindow->getDispatchingTimeout(DISPATCHING_TIMEOUT);
Prabir Pradhanedd96402022-02-15 01:46:16 -08009688 mFakePolicy->assertNotifyWindowUnresponsiveWasCalled(timeout, mWindow);
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009689}
9690
Prabir Pradhan1376fcd2022-01-21 09:56:35 -08009691// A spy window can receive an ANR
9692TEST_F(InputDispatcherSingleWindowAnr, SpyWindowAnr) {
9693 sp<FakeWindowHandle> spy = addSpyWindow();
9694
9695 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07009696 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
Prabir Pradhan1376fcd2022-01-21 09:56:35 -08009697 WINDOW_LOCATION));
9698 mWindow->consumeMotionDown();
9699
Siarhei Vishniakoud3061ab2023-12-18 20:41:08 -08009700 const auto [sequenceNum, _] = spy->receiveEvent(); // ACTION_DOWN
Prabir Pradhan1376fcd2022-01-21 09:56:35 -08009701 ASSERT_TRUE(sequenceNum);
9702 const std::chrono::duration timeout = spy->getDispatchingTimeout(DISPATCHING_TIMEOUT);
Prabir Pradhanedd96402022-02-15 01:46:16 -08009703 mFakePolicy->assertNotifyWindowUnresponsiveWasCalled(timeout, spy);
Prabir Pradhan1376fcd2022-01-21 09:56:35 -08009704
9705 spy->finishEvent(*sequenceNum);
Siarhei Vishniakou1ae72f12023-01-29 12:55:30 -08009706 spy->consumeMotionEvent(
9707 AllOf(WithMotionAction(ACTION_CANCEL), WithDisplayId(ADISPLAY_ID_DEFAULT)));
Prabir Pradhan1376fcd2022-01-21 09:56:35 -08009708 ASSERT_TRUE(mDispatcher->waitForIdle());
Prabir Pradhanedd96402022-02-15 01:46:16 -08009709 mFakePolicy->assertNotifyWindowResponsiveWasCalled(spy->getToken(), mWindow->getPid());
Prabir Pradhan1376fcd2022-01-21 09:56:35 -08009710}
9711
9712// If an app is not responding to a key event, spy windows should continue to receive
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009713// new motion events
Prabir Pradhan1376fcd2022-01-21 09:56:35 -08009714TEST_F(InputDispatcherSingleWindowAnr, SpyWindowReceivesEventsDuringAppAnrOnKey) {
9715 sp<FakeWindowHandle> spy = addSpyWindow();
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009716
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08009717 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07009718 injectKeyDown(*mDispatcher, ADISPLAY_ID_DEFAULT));
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009719 mWindow->consumeKeyDown(ADISPLAY_ID_DEFAULT);
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07009720 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectKeyUp(*mDispatcher, ADISPLAY_ID_DEFAULT));
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009721
9722 // Stuck on the ACTION_UP
9723 const std::chrono::duration timeout = mWindow->getDispatchingTimeout(DISPATCHING_TIMEOUT);
Prabir Pradhanedd96402022-02-15 01:46:16 -08009724 mFakePolicy->assertNotifyWindowUnresponsiveWasCalled(timeout, mWindow);
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009725
Prabir Pradhan1376fcd2022-01-21 09:56:35 -08009726 // New tap will go to the spy window, but not to the window
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009727 tapOnWindow();
Prabir Pradhan1376fcd2022-01-21 09:56:35 -08009728 spy->consumeMotionDown(ADISPLAY_ID_DEFAULT);
9729 spy->consumeMotionUp(ADISPLAY_ID_DEFAULT);
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009730
9731 mWindow->consumeKeyUp(ADISPLAY_ID_DEFAULT); // still the previous motion
9732 mDispatcher->waitForIdle();
Prabir Pradhanedd96402022-02-15 01:46:16 -08009733 mFakePolicy->assertNotifyWindowResponsiveWasCalled(mWindow->getToken(), mWindow->getPid());
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009734 mWindow->assertNoEvents();
Prabir Pradhan1376fcd2022-01-21 09:56:35 -08009735 spy->assertNoEvents();
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009736}
9737
Prabir Pradhan1376fcd2022-01-21 09:56:35 -08009738// If an app is not responding to a motion event, spy windows should continue to receive
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009739// new motion events
Prabir Pradhan1376fcd2022-01-21 09:56:35 -08009740TEST_F(InputDispatcherSingleWindowAnr, SpyWindowReceivesEventsDuringAppAnrOnMotion) {
9741 sp<FakeWindowHandle> spy = addSpyWindow();
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009742
9743 tapOnWindow();
Prabir Pradhan1376fcd2022-01-21 09:56:35 -08009744 spy->consumeMotionDown(ADISPLAY_ID_DEFAULT);
9745 spy->consumeMotionUp(ADISPLAY_ID_DEFAULT);
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009746
9747 mWindow->consumeMotionDown();
9748 // Stuck on the ACTION_UP
9749 const std::chrono::duration timeout = mWindow->getDispatchingTimeout(DISPATCHING_TIMEOUT);
Prabir Pradhanedd96402022-02-15 01:46:16 -08009750 mFakePolicy->assertNotifyWindowUnresponsiveWasCalled(timeout, mWindow);
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009751
Prabir Pradhan1376fcd2022-01-21 09:56:35 -08009752 // New tap will go to the spy window, but not to the window
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009753 tapOnWindow();
Prabir Pradhan1376fcd2022-01-21 09:56:35 -08009754 spy->consumeMotionDown(ADISPLAY_ID_DEFAULT);
9755 spy->consumeMotionUp(ADISPLAY_ID_DEFAULT);
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009756
9757 mWindow->consumeMotionUp(ADISPLAY_ID_DEFAULT); // still the previous motion
9758 mDispatcher->waitForIdle();
Prabir Pradhanedd96402022-02-15 01:46:16 -08009759 mFakePolicy->assertNotifyWindowResponsiveWasCalled(mWindow->getToken(), mWindow->getPid());
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009760 mWindow->assertNoEvents();
Prabir Pradhan1376fcd2022-01-21 09:56:35 -08009761 spy->assertNoEvents();
9762}
9763
9764TEST_F(InputDispatcherSingleWindowAnr, UnresponsiveMonitorAnr) {
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07009765 mDispatcher->setMonitorDispatchingTimeoutForTest(SPY_TIMEOUT);
Prabir Pradhan1376fcd2022-01-21 09:56:35 -08009766
Prabir Pradhanfb549072023-10-05 19:17:36 +00009767 FakeMonitorReceiver monitor = FakeMonitorReceiver(*mDispatcher, "M_1", ADISPLAY_ID_DEFAULT);
Prabir Pradhan1376fcd2022-01-21 09:56:35 -08009768
9769 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07009770 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
Prabir Pradhan1376fcd2022-01-21 09:56:35 -08009771 WINDOW_LOCATION));
9772
9773 mWindow->consumeMotionDown(ADISPLAY_ID_DEFAULT);
9774 const std::optional<uint32_t> consumeSeq = monitor.receiveEvent();
9775 ASSERT_TRUE(consumeSeq);
9776
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07009777 mFakePolicy->assertNotifyWindowUnresponsiveWasCalled(SPY_TIMEOUT, monitor.getToken(),
9778 MONITOR_PID);
Prabir Pradhan1376fcd2022-01-21 09:56:35 -08009779
9780 monitor.finishEvent(*consumeSeq);
9781 monitor.consumeMotionCancel(ADISPLAY_ID_DEFAULT);
9782
9783 ASSERT_TRUE(mDispatcher->waitForIdle());
Prabir Pradhanedd96402022-02-15 01:46:16 -08009784 mFakePolicy->assertNotifyWindowResponsiveWasCalled(monitor.getToken(), MONITOR_PID);
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009785}
9786
9787// If a window is unresponsive, then you get anr. if the window later catches up and starts to
9788// process events, you don't get an anr. When the window later becomes unresponsive again, you
9789// get an ANR again.
9790// 1. tap -> block on ACTION_UP -> receive ANR
9791// 2. consume all pending events (= queue becomes healthy again)
9792// 3. tap again -> block on ACTION_UP again -> receive ANR second time
9793TEST_F(InputDispatcherSingleWindowAnr, SameWindow_CanReceiveAnrTwice) {
9794 tapOnWindow();
9795
9796 mWindow->consumeMotionDown();
9797 // Block on ACTION_UP
9798 const std::chrono::duration timeout = mWindow->getDispatchingTimeout(DISPATCHING_TIMEOUT);
Prabir Pradhanedd96402022-02-15 01:46:16 -08009799 mFakePolicy->assertNotifyWindowUnresponsiveWasCalled(timeout, mWindow);
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009800 mWindow->consumeMotionUp(); // Now the connection should be healthy again
9801 mDispatcher->waitForIdle();
Prabir Pradhanedd96402022-02-15 01:46:16 -08009802 mFakePolicy->assertNotifyWindowResponsiveWasCalled(mWindow->getToken(), mWindow->getPid());
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009803 mWindow->assertNoEvents();
9804
9805 tapOnWindow();
9806 mWindow->consumeMotionDown();
Prabir Pradhanedd96402022-02-15 01:46:16 -08009807 mFakePolicy->assertNotifyWindowUnresponsiveWasCalled(timeout, mWindow);
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009808 mWindow->consumeMotionUp();
9809
9810 mDispatcher->waitForIdle();
Prabir Pradhanedd96402022-02-15 01:46:16 -08009811 mFakePolicy->assertNotifyWindowResponsiveWasCalled(mWindow->getToken(), mWindow->getPid());
Siarhei Vishniakou234129c2020-10-22 22:28:12 -05009812 mFakePolicy->assertNotifyAnrWasNotCalled();
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009813 mWindow->assertNoEvents();
9814}
9815
Siarhei Vishniakou234129c2020-10-22 22:28:12 -05009816// If a connection remains unresponsive for a while, make sure policy is only notified once about
9817// it.
9818TEST_F(InputDispatcherSingleWindowAnr, Policy_DoesNotGetDuplicateAnr) {
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08009819 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07009820 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009821 WINDOW_LOCATION));
9822
9823 const std::chrono::duration windowTimeout = mWindow->getDispatchingTimeout(DISPATCHING_TIMEOUT);
Prabir Pradhanedd96402022-02-15 01:46:16 -08009824 mFakePolicy->assertNotifyWindowUnresponsiveWasCalled(windowTimeout, mWindow);
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009825 std::this_thread::sleep_for(windowTimeout);
Siarhei Vishniakou234129c2020-10-22 22:28:12 -05009826 // 'notifyConnectionUnresponsive' should only be called once per connection
9827 mFakePolicy->assertNotifyAnrWasNotCalled();
9828 // When the ANR happened, dispatcher should abort the current event stream via ACTION_CANCEL
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009829 mWindow->consumeMotionDown();
Siarhei Vishniakou1ae72f12023-01-29 12:55:30 -08009830 mWindow->consumeMotionEvent(
9831 AllOf(WithMotionAction(ACTION_CANCEL), WithDisplayId(ADISPLAY_ID_DEFAULT)));
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009832 mWindow->assertNoEvents();
Siarhei Vishniakou234129c2020-10-22 22:28:12 -05009833 mDispatcher->waitForIdle();
Prabir Pradhanedd96402022-02-15 01:46:16 -08009834 mFakePolicy->assertNotifyWindowResponsiveWasCalled(mWindow->getToken(), mWindow->getPid());
Siarhei Vishniakou234129c2020-10-22 22:28:12 -05009835 mFakePolicy->assertNotifyAnrWasNotCalled();
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009836}
9837
9838/**
9839 * 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 -07009840 * not get delivered to the focused window until the motion is processed.
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009841 */
9842TEST_F(InputDispatcherSingleWindowAnr, Key_StaysPendingWhileMotionIsProcessed) {
Siarhei Vishniakouef2b4502023-12-28 11:51:47 -08009843 // The timeouts in this test are established by relying on the fact that the "key waiting for
9844 // events timeout" is equal to 500ms.
9845 ASSERT_EQ(mFakePolicy->getKeyWaitingForEventsTimeout(), 500ms);
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009846 mWindow->setDispatchingTimeout(2s); // Set a long ANR timeout to prevent it from triggering
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07009847 mDispatcher->onWindowInfosChanged({{*mWindow->getInfo()}, {}, 0, 0});
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009848
9849 tapOnWindow();
Siarhei Vishniakoud3061ab2023-12-18 20:41:08 -08009850 const auto& [downSequenceNum, downEvent] = mWindow->receiveEvent();
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009851 ASSERT_TRUE(downSequenceNum);
Siarhei Vishniakoud3061ab2023-12-18 20:41:08 -08009852 const auto& [upSequenceNum, upEvent] = mWindow->receiveEvent();
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009853 ASSERT_TRUE(upSequenceNum);
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009854
Siarhei Vishniakouef2b4502023-12-28 11:51:47 -08009855 // Don't finish the events yet, and send a key
9856 mDispatcher->notifyKey(
9857 KeyArgsBuilder(AKEY_EVENT_ACTION_DOWN, AINPUT_SOURCE_KEYBOARD)
9858 .policyFlags(DEFAULT_POLICY_FLAGS | POLICY_FLAG_DISABLE_KEY_REPEAT)
9859 .build());
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009860 // Key will not be sent to the window, yet, because the window is still processing events
9861 // and the key remains pending, waiting for the touch events to be processed
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07009862 // Make sure that `assertNoEvents` doesn't wait too long, because it could cause an ANR.
Siarhei Vishniakouef2b4502023-12-28 11:51:47 -08009863 mWindow->assertNoEvents(100ms);
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009864
Siarhei Vishniakouef2b4502023-12-28 11:51:47 -08009865 std::this_thread::sleep_for(400ms);
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009866 // if we wait long enough though, dispatcher will give up, and still send the key
9867 // to the focused window, even though we have not yet finished the motion event
9868 mWindow->consumeKeyDown(ADISPLAY_ID_DEFAULT);
9869 mWindow->finishEvent(*downSequenceNum);
9870 mWindow->finishEvent(*upSequenceNum);
9871}
9872
9873/**
9874 * If a window is processing a motion event, and then a key event comes in, the key event should
9875 * not go to the focused window until the motion is processed.
9876 * If then a new motion comes in, then the pending key event should be going to the currently
9877 * focused window right away.
9878 */
9879TEST_F(InputDispatcherSingleWindowAnr,
Siarhei Vishniakouef2b4502023-12-28 11:51:47 -08009880 PendingKey_IsDeliveredWhileMotionIsProcessingAndNewTouchComesIn) {
9881 // The timeouts in this test are established by relying on the fact that the "key waiting for
9882 // events timeout" is equal to 500ms.
9883 ASSERT_EQ(mFakePolicy->getKeyWaitingForEventsTimeout(), 500ms);
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009884 mWindow->setDispatchingTimeout(2s); // Set a long ANR timeout to prevent it from triggering
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07009885 mDispatcher->onWindowInfosChanged({{*mWindow->getInfo()}, {}, 0, 0});
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009886
9887 tapOnWindow();
Siarhei Vishniakoud3061ab2023-12-18 20:41:08 -08009888 const auto& [downSequenceNum, _] = mWindow->receiveEvent();
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009889 ASSERT_TRUE(downSequenceNum);
Siarhei Vishniakoud3061ab2023-12-18 20:41:08 -08009890 const auto& [upSequenceNum, upEvent] = mWindow->receiveEvent();
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009891 ASSERT_TRUE(upSequenceNum);
9892 // Don't finish the events yet, and send a key
Siarhei Vishniakou67bf2162023-11-16 13:29:50 -08009893 mDispatcher->notifyKey(
9894 KeyArgsBuilder(AKEY_EVENT_ACTION_DOWN, AINPUT_SOURCE_KEYBOARD)
9895 .policyFlags(DEFAULT_POLICY_FLAGS | POLICY_FLAG_DISABLE_KEY_REPEAT)
9896 .build());
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009897 // At this point, key is still pending, and should not be sent to the application yet.
Siarhei Vishniakouef2b4502023-12-28 11:51:47 -08009898 mWindow->assertNoEvents(100ms);
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009899
9900 // Now tap down again. It should cause the pending key to go to the focused window right away.
9901 tapOnWindow();
Siarhei Vishniakouef2b4502023-12-28 11:51:47 -08009902 // Now that we tapped, we should receive the key immediately.
9903 // Since there's still room for slowness, we use 200ms, which is much less than
9904 // the "key waiting for events' timeout of 500ms minus the already waited 100ms duration.
9905 std::unique_ptr<InputEvent> keyEvent = mWindow->consume(200ms);
9906 ASSERT_NE(nullptr, keyEvent);
9907 ASSERT_EQ(InputEventType::KEY, keyEvent->getType());
9908 ASSERT_THAT(static_cast<KeyEvent&>(*keyEvent), WithKeyAction(AKEY_EVENT_ACTION_DOWN));
9909 // it doesn't matter that we haven't ack'd the other events yet. We can finish events in any
9910 // order.
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009911 mWindow->finishEvent(*downSequenceNum); // first tap's ACTION_DOWN
9912 mWindow->finishEvent(*upSequenceNum); // first tap's ACTION_UP
Siarhei Vishniakou67bf2162023-11-16 13:29:50 -08009913 mWindow->consumeMotionEvent(WithMotionAction(ACTION_DOWN));
9914 mWindow->consumeMotionEvent(WithMotionAction(ACTION_UP));
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009915 mWindow->assertNoEvents();
9916}
9917
Siarhei Vishniakouadb9fc92023-05-26 10:46:09 -07009918/**
9919 * Send an event to the app and have the app not respond right away.
9920 * When ANR is raised, policy will tell the dispatcher to cancel the events for that window.
9921 * So InputDispatcher will enqueue ACTION_CANCEL event as well.
9922 * At some point, the window becomes responsive again.
9923 * Ensure that subsequent events get dropped, and the next gesture is delivered.
9924 */
9925TEST_F(InputDispatcherSingleWindowAnr, TwoGesturesWithAnr) {
9926 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
9927 .pointer(PointerBuilder(0, ToolType::FINGER).x(10).y(10))
9928 .build());
9929
Siarhei Vishniakoud3061ab2023-12-18 20:41:08 -08009930 const auto [sequenceNum, _] = mWindow->receiveEvent(); // ACTION_DOWN
Siarhei Vishniakouadb9fc92023-05-26 10:46:09 -07009931 ASSERT_TRUE(sequenceNum);
9932 const std::chrono::duration timeout = mWindow->getDispatchingTimeout(DISPATCHING_TIMEOUT);
9933 mFakePolicy->assertNotifyWindowUnresponsiveWasCalled(timeout, mWindow);
9934
9935 mWindow->finishEvent(*sequenceNum);
9936 mWindow->consumeMotionEvent(WithMotionAction(ACTION_CANCEL));
9937 ASSERT_TRUE(mDispatcher->waitForIdle());
9938 mFakePolicy->assertNotifyWindowResponsiveWasCalled(mWindow->getToken(), mWindow->getPid());
9939
9940 // Now that the window is responsive, let's continue the gesture.
9941 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN)
9942 .pointer(PointerBuilder(0, ToolType::FINGER).x(11).y(11))
9943 .build());
9944
9945 mDispatcher->notifyMotion(MotionArgsBuilder(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
9946 .pointer(PointerBuilder(0, ToolType::FINGER).x(11).y(11))
9947 .pointer(PointerBuilder(1, ToolType::FINGER).x(3).y(3))
9948 .build());
9949
9950 mDispatcher->notifyMotion(MotionArgsBuilder(POINTER_1_UP, AINPUT_SOURCE_TOUCHSCREEN)
9951 .pointer(PointerBuilder(0, ToolType::FINGER).x(11).y(11))
9952 .pointer(PointerBuilder(1, ToolType::FINGER).x(3).y(3))
9953 .build());
9954 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN)
9955 .pointer(PointerBuilder(0, ToolType::FINGER).x(11).y(11))
9956 .build());
9957 // We already canceled this pointer, so the window shouldn't get any new events.
9958 mWindow->assertNoEvents();
9959
9960 // Start another one.
9961 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
9962 .pointer(PointerBuilder(0, ToolType::FINGER).x(15).y(15))
9963 .build());
9964 mWindow->consumeMotionEvent(WithMotionAction(ACTION_DOWN));
9965}
9966
Prabir Pradhanfc364722024-02-08 17:51:20 +00009967// Send an event to the app and have the app not respond right away. Then remove the app window.
9968// When the window is removed, the dispatcher will cancel the events for that window.
9969// So InputDispatcher will enqueue ACTION_CANCEL event as well.
9970TEST_F(InputDispatcherSingleWindowAnr, AnrAfterWindowRemoval) {
9971 mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_DOWN,
9972 AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
9973 {WINDOW_LOCATION}));
9974
9975 const auto [sequenceNum, _] = mWindow->receiveEvent(); // ACTION_DOWN
9976 ASSERT_TRUE(sequenceNum);
9977
9978 // Remove the window, but the input channel should remain alive.
9979 mDispatcher->onWindowInfosChanged({{}, {}, 0, 0});
9980
9981 const std::chrono::duration timeout = mWindow->getDispatchingTimeout(DISPATCHING_TIMEOUT);
9982 // Since the window was removed, Dispatcher does not know the PID associated with the window
9983 // anymore, so the policy is notified without the PID.
9984 mFakePolicy->assertNotifyWindowUnresponsiveWasCalled(timeout, mWindow->getToken(),
9985 /*pid=*/std::nullopt);
9986
9987 mWindow->finishEvent(*sequenceNum);
9988 // The cancellation was generated when the window was removed, along with the focus event.
9989 mWindow->consumeMotionEvent(
9990 AllOf(WithMotionAction(ACTION_CANCEL), WithDisplayId(ADISPLAY_ID_DEFAULT)));
9991 mWindow->consumeFocusEvent(false);
9992 ASSERT_TRUE(mDispatcher->waitForIdle());
9993 mFakePolicy->assertNotifyWindowResponsiveWasCalled(mWindow->getToken(), /*pid=*/std::nullopt);
9994}
9995
9996// Send an event to the app and have the app not respond right away. Wait for the policy to be
9997// notified of the unresponsive window, then remove the app window.
9998TEST_F(InputDispatcherSingleWindowAnr, AnrFollowedByWindowRemoval) {
9999 mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_DOWN,
10000 AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
10001 {WINDOW_LOCATION}));
10002
10003 const auto [sequenceNum, _] = mWindow->receiveEvent(); // ACTION_DOWN
10004 ASSERT_TRUE(sequenceNum);
10005 const std::chrono::duration timeout = mWindow->getDispatchingTimeout(DISPATCHING_TIMEOUT);
10006 mFakePolicy->assertNotifyWindowUnresponsiveWasCalled(timeout, mWindow);
10007
10008 // Remove the window, but the input channel should remain alive.
10009 mDispatcher->onWindowInfosChanged({{}, {}, 0, 0});
10010
10011 mWindow->finishEvent(*sequenceNum);
10012 // The cancellation was generated during the ANR, and the window lost focus when it was removed.
10013 mWindow->consumeMotionEvent(
10014 AllOf(WithMotionAction(ACTION_CANCEL), WithDisplayId(ADISPLAY_ID_DEFAULT)));
10015 mWindow->consumeFocusEvent(false);
10016 ASSERT_TRUE(mDispatcher->waitForIdle());
10017 // Since the window was removed, Dispatcher does not know the PID associated with the window
10018 // becoming responsive, so the policy is notified without the PID.
10019 mFakePolicy->assertNotifyWindowResponsiveWasCalled(mWindow->getToken(), /*pid=*/std::nullopt);
10020}
10021
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -070010022class InputDispatcherMultiWindowAnr : public InputDispatcherTest {
10023 virtual void SetUp() override {
10024 InputDispatcherTest::SetUp();
10025
Chris Yea209fde2020-07-22 13:54:51 -070010026 mApplication = std::make_shared<FakeApplicationHandle>();
Siarhei Vishniakouf83c6932023-07-07 17:48:10 -070010027 mApplication->setDispatchingTimeout(100ms);
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -070010028 mUnfocusedWindow = sp<FakeWindowHandle>::make(mApplication, mDispatcher, "Unfocused",
10029 ADISPLAY_ID_DEFAULT);
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -070010030 mUnfocusedWindow->setFrame(Rect(0, 0, 30, 30));
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -070010031 // Adding FLAG_WATCH_OUTSIDE_TOUCH to receive ACTION_OUTSIDE when another window is tapped
Prabir Pradhan4d5c52f2022-01-31 08:52:10 -080010032 mUnfocusedWindow->setWatchOutsideTouch(true);
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -070010033
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -070010034 mFocusedWindow = sp<FakeWindowHandle>::make(mApplication, mDispatcher, "Focused",
10035 ADISPLAY_ID_DEFAULT);
Siarhei Vishniakouf83c6932023-07-07 17:48:10 -070010036 mFocusedWindow->setDispatchingTimeout(100ms);
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -070010037 mFocusedWindow->setFrame(Rect(50, 50, 100, 100));
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -070010038
10039 // Set focused application.
10040 mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, mApplication);
Vishnu Nair47074b82020-08-14 11:54:47 -070010041 mFocusedWindow->setFocusable(true);
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -070010042
10043 // Expect one focus window exist in display.
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070010044 mDispatcher->onWindowInfosChanged(
10045 {{*mUnfocusedWindow->getInfo(), *mFocusedWindow->getInfo()}, {}, 0, 0});
Vishnu Nair958da932020-08-21 17:12:37 -070010046 setFocusedWindow(mFocusedWindow);
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -070010047 mFocusedWindow->consumeFocusEvent(true);
10048 }
10049
10050 virtual void TearDown() override {
10051 InputDispatcherTest::TearDown();
10052
10053 mUnfocusedWindow.clear();
10054 mFocusedWindow.clear();
10055 }
10056
10057protected:
Chris Yea209fde2020-07-22 13:54:51 -070010058 std::shared_ptr<FakeApplicationHandle> mApplication;
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -070010059 sp<FakeWindowHandle> mUnfocusedWindow;
10060 sp<FakeWindowHandle> mFocusedWindow;
10061 static constexpr PointF UNFOCUSED_WINDOW_LOCATION = {20, 20};
10062 static constexpr PointF FOCUSED_WINDOW_LOCATION = {75, 75};
10063 static constexpr PointF LOCATION_OUTSIDE_ALL_WINDOWS = {40, 40};
10064
10065 void tapOnFocusedWindow() { tap(FOCUSED_WINDOW_LOCATION); }
10066
10067 void tapOnUnfocusedWindow() { tap(UNFOCUSED_WINDOW_LOCATION); }
10068
10069private:
10070 void tap(const PointF& location) {
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -080010071 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070010072 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -070010073 location));
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -080010074 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070010075 injectMotionUp(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -070010076 location));
10077 }
10078};
10079
10080// If we have 2 windows that are both unresponsive, the one with the shortest timeout
10081// should be ANR'd first.
10082TEST_F(InputDispatcherMultiWindowAnr, TwoWindows_BothUnresponsive) {
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -080010083 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakou2899c552023-07-10 18:20:46 -070010084 injectMotionEvent(*mDispatcher,
10085 MotionEventBuilder(AMOTION_EVENT_ACTION_DOWN,
10086 AINPUT_SOURCE_TOUCHSCREEN)
10087 .pointer(PointerBuilder(0, ToolType::FINGER)
10088 .x(FOCUSED_WINDOW_LOCATION.x)
10089 .y(FOCUSED_WINDOW_LOCATION.y))
10090 .build()));
10091 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
10092 injectMotionEvent(*mDispatcher,
10093 MotionEventBuilder(AMOTION_EVENT_ACTION_UP,
10094 AINPUT_SOURCE_TOUCHSCREEN)
10095 .pointer(PointerBuilder(0, ToolType::FINGER)
10096 .x(FOCUSED_WINDOW_LOCATION.x)
10097 .y(FOCUSED_WINDOW_LOCATION.y))
10098 .build()));
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -070010099 mFocusedWindow->consumeMotionDown();
Siarhei Vishniakou2899c552023-07-10 18:20:46 -070010100 mFocusedWindow->consumeMotionUp();
Prabir Pradhan7662a8d2023-12-15 01:58:14 +000010101 mUnfocusedWindow->consumeMotionOutside(ADISPLAY_ID_DEFAULT, /*flags=*/0);
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -070010102 // We consumed all events, so no ANR
10103 ASSERT_TRUE(mDispatcher->waitForIdle());
10104 mFakePolicy->assertNotifyAnrWasNotCalled();
10105
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -080010106 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakou2899c552023-07-10 18:20:46 -070010107 injectMotionEvent(*mDispatcher,
10108 MotionEventBuilder(AMOTION_EVENT_ACTION_DOWN,
10109 AINPUT_SOURCE_TOUCHSCREEN)
10110 .pointer(PointerBuilder(0, ToolType::FINGER)
10111 .x(FOCUSED_WINDOW_LOCATION.x)
10112 .y(FOCUSED_WINDOW_LOCATION.y))
10113 .build()));
Siarhei Vishniakoud3061ab2023-12-18 20:41:08 -080010114 const auto [unfocusedSequenceNum, _] = mUnfocusedWindow->receiveEvent();
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -070010115 ASSERT_TRUE(unfocusedSequenceNum);
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -070010116
10117 const std::chrono::duration timeout =
10118 mFocusedWindow->getDispatchingTimeout(DISPATCHING_TIMEOUT);
Prabir Pradhanedd96402022-02-15 01:46:16 -080010119 mFakePolicy->assertNotifyWindowUnresponsiveWasCalled(timeout, mFocusedWindow);
Siarhei Vishniakou2899c552023-07-10 18:20:46 -070010120
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -070010121 mUnfocusedWindow->finishEvent(*unfocusedSequenceNum);
Siarhei Vishniakou234129c2020-10-22 22:28:12 -050010122 mFocusedWindow->consumeMotionDown();
10123 // This cancel is generated because the connection was unresponsive
10124 mFocusedWindow->consumeMotionCancel();
10125 mFocusedWindow->assertNoEvents();
10126 mUnfocusedWindow->assertNoEvents();
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -070010127 ASSERT_TRUE(mDispatcher->waitForIdle());
Prabir Pradhanedd96402022-02-15 01:46:16 -080010128 mFakePolicy->assertNotifyWindowResponsiveWasCalled(mFocusedWindow->getToken(),
10129 mFocusedWindow->getPid());
Siarhei Vishniakou234129c2020-10-22 22:28:12 -050010130 mFakePolicy->assertNotifyAnrWasNotCalled();
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -070010131}
10132
10133// If we have 2 windows with identical timeouts that are both unresponsive,
10134// it doesn't matter which order they should have ANR.
10135// But we should receive ANR for both.
10136TEST_F(InputDispatcherMultiWindowAnr, TwoWindows_BothUnresponsiveWithSameTimeout) {
10137 // Set the timeout for unfocused window to match the focused window
Siarhei Vishniakouf83c6932023-07-07 17:48:10 -070010138 mUnfocusedWindow->setDispatchingTimeout(
10139 mFocusedWindow->getDispatchingTimeout(DISPATCHING_TIMEOUT));
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070010140 mDispatcher->onWindowInfosChanged(
10141 {{*mUnfocusedWindow->getInfo(), *mFocusedWindow->getInfo()}, {}, 0, 0});
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -070010142
10143 tapOnFocusedWindow();
10144 // we should have ACTION_DOWN/ACTION_UP on focused window and ACTION_OUTSIDE on unfocused window
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -070010145 // We don't know which window will ANR first. But both of them should happen eventually.
Siarhei Vishniakouf83c6932023-07-07 17:48:10 -070010146 std::array<sp<IBinder>, 2> anrConnectionTokens = {mFakePolicy->getUnresponsiveWindowToken(
10147 mFocusedWindow->getDispatchingTimeout(
10148 DISPATCHING_TIMEOUT)),
10149 mFakePolicy->getUnresponsiveWindowToken(0ms)};
10150
10151 ASSERT_THAT(anrConnectionTokens,
10152 ::testing::UnorderedElementsAre(testing::Eq(mFocusedWindow->getToken()),
10153 testing::Eq(mUnfocusedWindow->getToken())));
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -070010154
10155 ASSERT_TRUE(mDispatcher->waitForIdle());
10156 mFakePolicy->assertNotifyAnrWasNotCalled();
Siarhei Vishniakou234129c2020-10-22 22:28:12 -050010157
10158 mFocusedWindow->consumeMotionDown();
10159 mFocusedWindow->consumeMotionUp();
10160 mUnfocusedWindow->consumeMotionOutside();
10161
Siarhei Vishniakouf83c6932023-07-07 17:48:10 -070010162 std::array<sp<IBinder>, 2> responsiveTokens = {mFakePolicy->getResponsiveWindowToken(),
10163 mFakePolicy->getResponsiveWindowToken()};
Siarhei Vishniakou234129c2020-10-22 22:28:12 -050010164
10165 // Both applications should be marked as responsive, in any order
Siarhei Vishniakouf83c6932023-07-07 17:48:10 -070010166 ASSERT_THAT(responsiveTokens,
10167 ::testing::UnorderedElementsAre(testing::Eq(mFocusedWindow->getToken()),
10168 testing::Eq(mUnfocusedWindow->getToken())));
Siarhei Vishniakou234129c2020-10-22 22:28:12 -050010169 mFakePolicy->assertNotifyAnrWasNotCalled();
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -070010170}
10171
10172// If a window is already not responding, the second tap on the same window should be ignored.
10173// We should also log an error to account for the dropped event (not tested here).
10174// At the same time, FLAG_WATCH_OUTSIDE_TOUCH targets should not receive any events.
10175TEST_F(InputDispatcherMultiWindowAnr, DuringAnr_SecondTapIsIgnored) {
10176 tapOnFocusedWindow();
Prabir Pradhan7662a8d2023-12-15 01:58:14 +000010177 mUnfocusedWindow->consumeMotionOutside(ADISPLAY_ID_DEFAULT, /*flags=*/0);
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -070010178 // Receive the events, but don't respond
Siarhei Vishniakoud3061ab2023-12-18 20:41:08 -080010179 const auto [downEventSequenceNum, downEvent] = mFocusedWindow->receiveEvent(); // ACTION_DOWN
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -070010180 ASSERT_TRUE(downEventSequenceNum);
Siarhei Vishniakoud3061ab2023-12-18 20:41:08 -080010181 const auto [upEventSequenceNum, upEvent] = mFocusedWindow->receiveEvent(); // ACTION_UP
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -070010182 ASSERT_TRUE(upEventSequenceNum);
10183 const std::chrono::duration timeout =
10184 mFocusedWindow->getDispatchingTimeout(DISPATCHING_TIMEOUT);
Prabir Pradhanedd96402022-02-15 01:46:16 -080010185 mFakePolicy->assertNotifyWindowUnresponsiveWasCalled(timeout, mFocusedWindow);
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -070010186
10187 // Tap once again
10188 // We cannot use "tapOnFocusedWindow" because it asserts the injection result to be success
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -080010189 ASSERT_EQ(InputEventInjectionResult::FAILED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070010190 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -070010191 FOCUSED_WINDOW_LOCATION));
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -080010192 ASSERT_EQ(InputEventInjectionResult::FAILED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070010193 injectMotionUp(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -070010194 FOCUSED_WINDOW_LOCATION));
10195 // Unfocused window does not receive ACTION_OUTSIDE because the tapped window is not a
10196 // valid touch target
10197 mUnfocusedWindow->assertNoEvents();
10198
10199 // Consume the first tap
10200 mFocusedWindow->finishEvent(*downEventSequenceNum);
10201 mFocusedWindow->finishEvent(*upEventSequenceNum);
10202 ASSERT_TRUE(mDispatcher->waitForIdle());
10203 // The second tap did not go to the focused window
10204 mFocusedWindow->assertNoEvents();
Siarhei Vishniakou234129c2020-10-22 22:28:12 -050010205 // Since all events are finished, connection should be deemed healthy again
Prabir Pradhanedd96402022-02-15 01:46:16 -080010206 mFakePolicy->assertNotifyWindowResponsiveWasCalled(mFocusedWindow->getToken(),
10207 mFocusedWindow->getPid());
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -070010208 mFakePolicy->assertNotifyAnrWasNotCalled();
10209}
10210
10211// If you tap outside of all windows, there will not be ANR
10212TEST_F(InputDispatcherMultiWindowAnr, TapOutsideAllWindows_DoesNotAnr) {
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -080010213 ASSERT_EQ(InputEventInjectionResult::FAILED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070010214 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -070010215 LOCATION_OUTSIDE_ALL_WINDOWS));
10216 ASSERT_TRUE(mDispatcher->waitForIdle());
10217 mFakePolicy->assertNotifyAnrWasNotCalled();
10218}
10219
10220// Since the focused window is paused, tapping on it should not produce any events
10221TEST_F(InputDispatcherMultiWindowAnr, Window_CanBePaused) {
10222 mFocusedWindow->setPaused(true);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070010223 mDispatcher->onWindowInfosChanged(
10224 {{*mUnfocusedWindow->getInfo(), *mFocusedWindow->getInfo()}, {}, 0, 0});
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -070010225
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -080010226 ASSERT_EQ(InputEventInjectionResult::FAILED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070010227 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -070010228 FOCUSED_WINDOW_LOCATION));
10229
10230 std::this_thread::sleep_for(mFocusedWindow->getDispatchingTimeout(DISPATCHING_TIMEOUT));
10231 ASSERT_TRUE(mDispatcher->waitForIdle());
10232 // Should not ANR because the window is paused, and touches shouldn't go to it
10233 mFakePolicy->assertNotifyAnrWasNotCalled();
10234
10235 mFocusedWindow->assertNoEvents();
10236 mUnfocusedWindow->assertNoEvents();
10237}
10238
10239/**
10240 * 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 -070010241 * not get delivered to the focused window until the motion is processed.
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -070010242 * If a different window becomes focused at this time, the key should go to that window instead.
10243 *
10244 * Warning!!!
10245 * This test depends on the value of android::inputdispatcher::KEY_WAITING_FOR_MOTION_TIMEOUT
10246 * and the injection timeout that we specify when injecting the key.
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070010247 * We must have the injection timeout (100ms) be smaller than
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -070010248 * KEY_WAITING_FOR_MOTION_TIMEOUT (currently 500ms).
10249 *
10250 * If that value changes, this test should also change.
10251 */
10252TEST_F(InputDispatcherMultiWindowAnr, PendingKey_GoesToNewlyFocusedWindow) {
10253 // Set a long ANR timeout to prevent it from triggering
10254 mFocusedWindow->setDispatchingTimeout(2s);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070010255 mDispatcher->onWindowInfosChanged(
10256 {{*mFocusedWindow->getInfo(), *mUnfocusedWindow->getInfo()}, {}, 0, 0});
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -070010257
10258 tapOnUnfocusedWindow();
Siarhei Vishniakoud3061ab2023-12-18 20:41:08 -080010259 const auto [downSequenceNum, downEvent] = mUnfocusedWindow->receiveEvent();
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -070010260 ASSERT_TRUE(downSequenceNum);
Siarhei Vishniakoud3061ab2023-12-18 20:41:08 -080010261 const auto [upSequenceNum, upEvent] = mUnfocusedWindow->receiveEvent();
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -070010262 ASSERT_TRUE(upSequenceNum);
10263 // Don't finish the events yet, and send a key
10264 // Injection will succeed because we will eventually give up and send the key to the focused
10265 // window even if motions are still being processed.
10266
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -080010267 InputEventInjectionResult result =
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070010268 injectKey(*mDispatcher, AKEY_EVENT_ACTION_DOWN, /*repeatCount=*/0, ADISPLAY_ID_DEFAULT,
Linnan Li13bf76a2024-05-05 19:18:02 +080010269 InputEventInjectionSync::NONE,
10270 /*injectionTimeout=*/100ms);
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -080010271 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, result);
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -070010272 // Key will not be sent to the window, yet, because the window is still processing events
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070010273 // and the key remains pending, waiting for the touch events to be processed.
10274 // Make sure `assertNoEvents` doesn't take too long. It uses CONSUME_TIMEOUT_NO_EVENT_EXPECTED
10275 // under the hood.
10276 static_assert(CONSUME_TIMEOUT_NO_EVENT_EXPECTED < 100ms);
10277 mFocusedWindow->assertNoEvents();
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -070010278
10279 // Switch the focus to the "unfocused" window that we tapped. Expect the key to go there
Vishnu Nair47074b82020-08-14 11:54:47 -070010280 mFocusedWindow->setFocusable(false);
10281 mUnfocusedWindow->setFocusable(true);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070010282 mDispatcher->onWindowInfosChanged(
10283 {{*mFocusedWindow->getInfo(), *mUnfocusedWindow->getInfo()}, {}, 0, 0});
Vishnu Nair958da932020-08-21 17:12:37 -070010284 setFocusedWindow(mUnfocusedWindow);
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -070010285
10286 // Focus events should precede the key events
10287 mUnfocusedWindow->consumeFocusEvent(true);
10288 mFocusedWindow->consumeFocusEvent(false);
10289
10290 // Finish the tap events, which should unblock dispatcher
10291 mUnfocusedWindow->finishEvent(*downSequenceNum);
10292 mUnfocusedWindow->finishEvent(*upSequenceNum);
10293
10294 // Now that all queues are cleared and no backlog in the connections, the key event
10295 // can finally go to the newly focused "mUnfocusedWindow".
10296 mUnfocusedWindow->consumeKeyDown(ADISPLAY_ID_DEFAULT);
10297 mFocusedWindow->assertNoEvents();
10298 mUnfocusedWindow->assertNoEvents();
Siarhei Vishniakou234129c2020-10-22 22:28:12 -050010299 mFakePolicy->assertNotifyAnrWasNotCalled();
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -070010300}
10301
10302// When the touch stream is split across 2 windows, and one of them does not respond,
10303// then ANR should be raised and the touch should be canceled for the unresponsive window.
10304// The other window should not be affected by that.
10305TEST_F(InputDispatcherMultiWindowAnr, SplitTouch_SingleWindowAnr) {
10306 // Touch Window 1
Prabir Pradhan678438e2023-04-13 19:32:51 +000010307 mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_DOWN,
10308 AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
10309 {FOCUSED_WINDOW_LOCATION}));
Prabir Pradhan7662a8d2023-12-15 01:58:14 +000010310 mUnfocusedWindow->consumeMotionOutside(ADISPLAY_ID_DEFAULT, /*flags=*/0);
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -070010311
10312 // Touch Window 2
Prabir Pradhan678438e2023-04-13 19:32:51 +000010313 mDispatcher->notifyMotion(
10314 generateMotionArgs(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
10315 {FOCUSED_WINDOW_LOCATION, UNFOCUSED_WINDOW_LOCATION}));
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -070010316
10317 const std::chrono::duration timeout =
10318 mFocusedWindow->getDispatchingTimeout(DISPATCHING_TIMEOUT);
Prabir Pradhanedd96402022-02-15 01:46:16 -080010319 mFakePolicy->assertNotifyWindowUnresponsiveWasCalled(timeout, mFocusedWindow);
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -070010320
10321 mUnfocusedWindow->consumeMotionDown();
10322 mFocusedWindow->consumeMotionDown();
10323 // Focused window may or may not receive ACTION_MOVE
10324 // But it should definitely receive ACTION_CANCEL due to the ANR
Siarhei Vishniakoud3061ab2023-12-18 20:41:08 -080010325 const auto [moveOrCancelSequenceNum, event] = mFocusedWindow->receiveEvent();
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -070010326 ASSERT_TRUE(moveOrCancelSequenceNum);
10327 mFocusedWindow->finishEvent(*moveOrCancelSequenceNum);
10328 ASSERT_NE(nullptr, event);
Siarhei Vishniakou63b63612023-04-12 11:00:23 -070010329 ASSERT_EQ(event->getType(), InputEventType::MOTION);
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -070010330 MotionEvent& motionEvent = static_cast<MotionEvent&>(*event);
10331 if (motionEvent.getAction() == AMOTION_EVENT_ACTION_MOVE) {
10332 mFocusedWindow->consumeMotionCancel();
10333 } else {
10334 ASSERT_EQ(AMOTION_EVENT_ACTION_CANCEL, motionEvent.getAction());
10335 }
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -070010336 ASSERT_TRUE(mDispatcher->waitForIdle());
Prabir Pradhanedd96402022-02-15 01:46:16 -080010337 mFakePolicy->assertNotifyWindowResponsiveWasCalled(mFocusedWindow->getToken(),
10338 mFocusedWindow->getPid());
Siarhei Vishniakou234129c2020-10-22 22:28:12 -050010339
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -070010340 mUnfocusedWindow->assertNoEvents();
10341 mFocusedWindow->assertNoEvents();
Siarhei Vishniakou234129c2020-10-22 22:28:12 -050010342 mFakePolicy->assertNotifyAnrWasNotCalled();
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -070010343}
10344
Siarhei Vishniakouf56b2692020-09-08 19:43:33 -050010345/**
10346 * If we have no focused window, and a key comes in, we start the ANR timer.
10347 * The focused application should add a focused window before the timer runs out to prevent ANR.
10348 *
10349 * If the user touches another application during this time, the key should be dropped.
10350 * Next, if a new focused window comes in, without toggling the focused application,
10351 * then no ANR should occur.
10352 *
10353 * Normally, we would expect the new focused window to be accompanied by 'setFocusedApplication',
10354 * but in some cases the policy may not update the focused application.
10355 */
10356TEST_F(InputDispatcherMultiWindowAnr, FocusedWindowWithoutSetFocusedApplication_NoAnr) {
10357 std::shared_ptr<FakeApplicationHandle> focusedApplication =
10358 std::make_shared<FakeApplicationHandle>();
Siarhei Vishniakouc033dfb2023-10-03 10:45:16 -070010359 focusedApplication->setDispatchingTimeout(300ms);
Siarhei Vishniakouf56b2692020-09-08 19:43:33 -050010360 mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, focusedApplication);
10361 // The application that owns 'mFocusedWindow' and 'mUnfocusedWindow' is not focused.
10362 mFocusedWindow->setFocusable(false);
10363
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070010364 mDispatcher->onWindowInfosChanged(
10365 {{*mFocusedWindow->getInfo(), *mUnfocusedWindow->getInfo()}, {}, 0, 0});
Siarhei Vishniakouf56b2692020-09-08 19:43:33 -050010366 mFocusedWindow->consumeFocusEvent(false);
10367
10368 // Send a key. The ANR timer should start because there is no focused window.
10369 // 'focusedApplication' will get blamed if this timer completes.
10370 // Key will not be sent anywhere because we have no focused window. It will remain pending.
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -080010371 InputEventInjectionResult result =
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070010372 injectKey(*mDispatcher, AKEY_EVENT_ACTION_DOWN, /*repeatCount=*/0, ADISPLAY_ID_DEFAULT,
Linnan Li13bf76a2024-05-05 19:18:02 +080010373 InputEventInjectionSync::NONE,
10374 /*injectionTimeout=*/100ms,
Harry Cutts33476232023-01-30 19:57:29 +000010375 /*allowKeyRepeat=*/false);
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -080010376 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, result);
Siarhei Vishniakouf56b2692020-09-08 19:43:33 -050010377
10378 // Wait until dispatcher starts the "no focused window" timer. If we don't wait here,
10379 // then the injected touches won't cause the focused event to get dropped.
10380 // The dispatcher only checks for whether the queue should be pruned upon queueing.
10381 // If we inject the touch right away and the ANR timer hasn't started, the touch event would
10382 // simply be added to the queue without 'shouldPruneInboundQueueLocked' returning 'true'.
10383 // For this test, it means that the key would get delivered to the window once it becomes
10384 // focused.
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070010385 std::this_thread::sleep_for(100ms);
Siarhei Vishniakouf56b2692020-09-08 19:43:33 -050010386
10387 // Touch unfocused window. This should force the pending key to get dropped.
Prabir Pradhan678438e2023-04-13 19:32:51 +000010388 mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_DOWN,
10389 AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
10390 {UNFOCUSED_WINDOW_LOCATION}));
Siarhei Vishniakouf56b2692020-09-08 19:43:33 -050010391
10392 // We do not consume the motion right away, because that would require dispatcher to first
10393 // process (== drop) the key event, and by that time, ANR will be raised.
10394 // Set the focused window first.
10395 mFocusedWindow->setFocusable(true);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070010396 mDispatcher->onWindowInfosChanged(
10397 {{*mFocusedWindow->getInfo(), *mUnfocusedWindow->getInfo()}, {}, 0, 0});
Siarhei Vishniakouf56b2692020-09-08 19:43:33 -050010398 setFocusedWindow(mFocusedWindow);
10399 mFocusedWindow->consumeFocusEvent(true);
10400 // We do not call "setFocusedApplication" here, even though the newly focused window belongs
10401 // to another application. This could be a bug / behaviour in the policy.
10402
10403 mUnfocusedWindow->consumeMotionDown();
10404
10405 ASSERT_TRUE(mDispatcher->waitForIdle());
10406 // Should not ANR because we actually have a focused window. It was just added too slowly.
10407 ASSERT_NO_FATAL_FAILURE(mFakePolicy->assertNotifyAnrWasNotCalled());
10408}
10409
Siarhei Vishniakou99e407b2023-12-26 18:09:32 -080010410/**
10411 * If we are pruning input queue, we should never drop pointer events. Otherwise, we risk having
10412 * an inconsistent event stream inside the dispatcher. In this test, we make sure that the
10413 * dispatcher doesn't prune pointer events incorrectly.
10414 *
10415 * This test reproduces a crash in InputDispatcher.
10416 * To reproduce the crash, we need to simulate the conditions for "pruning input queue" to occur.
10417 *
10418 * Keep the currently focused application (mApplication), and have no focused window.
10419 * We set up two additional windows:
10420 * 1) The navigation bar window. This simulates the system "NavigationBar", which is used in the
10421 * 3-button navigation mode. This window injects a BACK button when it's touched. 2) The application
10422 * window. This window is not focusable, but is touchable.
10423 *
10424 * We first touch the navigation bar, which causes it to inject a key. Since there's no focused
10425 * window, the dispatcher doesn't process this key, and all other events inside dispatcher are now
10426 * blocked. The dispatcher is waiting for 'mApplication' to add a focused window.
10427 *
10428 * Now, we touch "Another window". This window is owned by a different application than
10429 * 'mApplication'. This causes the dispatcher to stop waiting for 'mApplication' to add a focused
10430 * window. Now, the "pruning input queue" behaviour should kick in, and the dispatcher should start
10431 * dropping the events from its queue. Ensure that no crash occurs.
10432 *
10433 * In this test, we are setting long timeouts to prevent ANRs and events dropped due to being stale.
10434 * This does not affect the test running time.
10435 */
10436TEST_F(InputDispatcherMultiWindowAnr, PruningInputQueueShouldNotDropPointerEvents) {
10437 std::shared_ptr<FakeApplicationHandle> systemUiApplication =
10438 std::make_shared<FakeApplicationHandle>();
10439 systemUiApplication->setDispatchingTimeout(3000ms);
10440 mFakePolicy->setStaleEventTimeout(3000ms);
10441 sp<FakeWindowHandle> navigationBar =
10442 sp<FakeWindowHandle>::make(systemUiApplication, mDispatcher, "NavigationBar",
10443 ADISPLAY_ID_DEFAULT);
10444 navigationBar->setFocusable(false);
10445 navigationBar->setWatchOutsideTouch(true);
10446 navigationBar->setFrame(Rect(0, 0, 100, 100));
10447
10448 mApplication->setDispatchingTimeout(3000ms);
10449 // 'mApplication' is already focused, but we call it again here to make it explicit.
10450 mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, mApplication);
10451
10452 std::shared_ptr<FakeApplicationHandle> anotherApplication =
10453 std::make_shared<FakeApplicationHandle>();
10454 sp<FakeWindowHandle> appWindow =
10455 sp<FakeWindowHandle>::make(anotherApplication, mDispatcher, "Another window",
10456 ADISPLAY_ID_DEFAULT);
10457 appWindow->setFocusable(false);
10458 appWindow->setFrame(Rect(100, 100, 200, 200));
10459
10460 mDispatcher->onWindowInfosChanged(
10461 {{*navigationBar->getInfo(), *appWindow->getInfo()}, {}, 0, 0});
10462 // 'mFocusedWindow' is no longer in the dispatcher window list, and therefore loses focus
10463 mFocusedWindow->consumeFocusEvent(false);
10464
10465 // Touch down the navigation bar. It consumes the touch and injects a key into the dispatcher
10466 // in response.
10467 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
10468 .pointer(PointerBuilder(0, ToolType::FINGER).x(50).y(50))
10469 .build());
10470 navigationBar->consumeMotionEvent(WithMotionAction(ACTION_DOWN));
10471
10472 // Key will not be sent anywhere because we have no focused window. It will remain pending.
10473 // Pretend we are injecting KEYCODE_BACK, but it doesn't actually matter what key it is.
10474 InputEventInjectionResult result =
10475 injectKey(*mDispatcher, AKEY_EVENT_ACTION_DOWN, /*repeatCount=*/0, ADISPLAY_ID_DEFAULT,
Linnan Li13bf76a2024-05-05 19:18:02 +080010476 InputEventInjectionSync::NONE,
10477 /*injectionTimeout=*/100ms,
Siarhei Vishniakou99e407b2023-12-26 18:09:32 -080010478 /*allowKeyRepeat=*/false);
10479 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, result);
10480
10481 // Finish the gesture - lift up finger and inject ACTION_UP key event
10482 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN)
10483 .pointer(PointerBuilder(0, ToolType::FINGER).x(50).y(50))
10484 .build());
10485 result = injectKey(*mDispatcher, AKEY_EVENT_ACTION_UP, /*repeatCount=*/0, ADISPLAY_ID_DEFAULT,
Linnan Li13bf76a2024-05-05 19:18:02 +080010486 InputEventInjectionSync::NONE,
10487 /*injectionTimeout=*/100ms,
Siarhei Vishniakou99e407b2023-12-26 18:09:32 -080010488 /*allowKeyRepeat=*/false);
10489 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, result);
10490 // The key that was injected is blocking the dispatcher, so the navigation bar shouldn't be
10491 // getting any events yet.
10492 navigationBar->assertNoEvents();
10493
10494 // Now touch "Another window". This touch is going to a different application than the one we
10495 // are waiting for (which is 'mApplication').
10496 // This should cause the dispatcher to drop the pending focus-dispatched events (like the key
10497 // trying to be injected) and to continue processing the rest of the events in the original
10498 // order.
10499 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
10500 .pointer(PointerBuilder(0, ToolType::FINGER).x(150).y(150))
10501 .build());
10502 navigationBar->consumeMotionEvent(WithMotionAction(ACTION_UP));
10503 navigationBar->consumeMotionEvent(WithMotionAction(ACTION_OUTSIDE));
10504 appWindow->consumeMotionEvent(WithMotionAction(ACTION_DOWN));
10505
10506 appWindow->assertNoEvents();
10507 navigationBar->assertNoEvents();
10508}
10509
Siarhei Vishniakoua2862a02020-07-20 16:36:46 -050010510// These tests ensure we cannot send touch events to a window that's positioned behind a window
10511// that has feature NO_INPUT_CHANNEL.
10512// Layout:
10513// Top (closest to user)
10514// mNoInputWindow (above all windows)
10515// mBottomWindow
10516// Bottom (furthest from user)
10517class InputDispatcherMultiWindowOcclusionTests : public InputDispatcherTest {
10518 virtual void SetUp() override {
10519 InputDispatcherTest::SetUp();
10520
10521 mApplication = std::make_shared<FakeApplicationHandle>();
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -070010522 mNoInputWindow =
10523 sp<FakeWindowHandle>::make(mApplication, mDispatcher,
10524 "Window without input channel", ADISPLAY_ID_DEFAULT,
Prabir Pradhane7cc69c2024-01-05 21:35:28 +000010525 /*createInputChannel=*/false);
Prabir Pradhan51e7db02022-02-07 06:02:57 -080010526 mNoInputWindow->setNoInputChannel(true);
Siarhei Vishniakoua2862a02020-07-20 16:36:46 -050010527 mNoInputWindow->setFrame(Rect(0, 0, 100, 100));
10528 // It's perfectly valid for this window to not have an associated input channel
10529
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -070010530 mBottomWindow = sp<FakeWindowHandle>::make(mApplication, mDispatcher, "Bottom window",
10531 ADISPLAY_ID_DEFAULT);
Siarhei Vishniakoua2862a02020-07-20 16:36:46 -050010532 mBottomWindow->setFrame(Rect(0, 0, 100, 100));
10533
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070010534 mDispatcher->onWindowInfosChanged(
10535 {{*mNoInputWindow->getInfo(), *mBottomWindow->getInfo()}, {}, 0, 0});
Siarhei Vishniakoua2862a02020-07-20 16:36:46 -050010536 }
10537
10538protected:
10539 std::shared_ptr<FakeApplicationHandle> mApplication;
10540 sp<FakeWindowHandle> mNoInputWindow;
10541 sp<FakeWindowHandle> mBottomWindow;
10542};
10543
10544TEST_F(InputDispatcherMultiWindowOcclusionTests, NoInputChannelFeature_DropsTouches) {
10545 PointF touchedPoint = {10, 10};
10546
Prabir Pradhan678438e2023-04-13 19:32:51 +000010547 mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_DOWN,
10548 AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
10549 {touchedPoint}));
Siarhei Vishniakoua2862a02020-07-20 16:36:46 -050010550
10551 mNoInputWindow->assertNoEvents();
10552 // Even though the window 'mNoInputWindow' positioned above 'mBottomWindow' does not have
10553 // an input channel, it is not marked as FLAG_NOT_TOUCHABLE,
10554 // and therefore should prevent mBottomWindow from receiving touches
10555 mBottomWindow->assertNoEvents();
10556}
10557
10558/**
10559 * If a window has feature NO_INPUT_CHANNEL, and somehow (by mistake) still has an input channel,
10560 * ensure that this window does not receive any touches, and blocks touches to windows underneath.
10561 */
10562TEST_F(InputDispatcherMultiWindowOcclusionTests,
10563 NoInputChannelFeature_DropsTouchesWithValidChannel) {
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -070010564 mNoInputWindow = sp<FakeWindowHandle>::make(mApplication, mDispatcher,
10565 "Window with input channel and NO_INPUT_CHANNEL",
10566 ADISPLAY_ID_DEFAULT);
Siarhei Vishniakoua2862a02020-07-20 16:36:46 -050010567
Prabir Pradhan51e7db02022-02-07 06:02:57 -080010568 mNoInputWindow->setNoInputChannel(true);
Siarhei Vishniakoua2862a02020-07-20 16:36:46 -050010569 mNoInputWindow->setFrame(Rect(0, 0, 100, 100));
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070010570 mDispatcher->onWindowInfosChanged(
10571 {{*mNoInputWindow->getInfo(), *mBottomWindow->getInfo()}, {}, 0, 0});
Siarhei Vishniakoua2862a02020-07-20 16:36:46 -050010572
10573 PointF touchedPoint = {10, 10};
10574
Prabir Pradhan678438e2023-04-13 19:32:51 +000010575 mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_DOWN,
10576 AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
10577 {touchedPoint}));
Siarhei Vishniakoua2862a02020-07-20 16:36:46 -050010578
10579 mNoInputWindow->assertNoEvents();
10580 mBottomWindow->assertNoEvents();
10581}
10582
Vishnu Nair958da932020-08-21 17:12:37 -070010583class InputDispatcherMirrorWindowFocusTests : public InputDispatcherTest {
10584protected:
10585 std::shared_ptr<FakeApplicationHandle> mApp;
10586 sp<FakeWindowHandle> mWindow;
10587 sp<FakeWindowHandle> mMirror;
10588
10589 virtual void SetUp() override {
10590 InputDispatcherTest::SetUp();
10591 mApp = std::make_shared<FakeApplicationHandle>();
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -070010592 mWindow = sp<FakeWindowHandle>::make(mApp, mDispatcher, "TestWindow", ADISPLAY_ID_DEFAULT);
Prabir Pradhane7cc69c2024-01-05 21:35:28 +000010593 mMirror = mWindow->clone(ADISPLAY_ID_DEFAULT);
Vishnu Nair958da932020-08-21 17:12:37 -070010594 mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, mApp);
10595 mWindow->setFocusable(true);
10596 mMirror->setFocusable(true);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070010597 mDispatcher->onWindowInfosChanged({{*mWindow->getInfo(), *mMirror->getInfo()}, {}, 0, 0});
Vishnu Nair958da932020-08-21 17:12:37 -070010598 }
10599};
10600
10601TEST_F(InputDispatcherMirrorWindowFocusTests, CanGetFocus) {
10602 // Request focus on a mirrored window
10603 setFocusedWindow(mMirror);
10604
10605 // window gets focused
10606 mWindow->consumeFocusEvent(true);
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070010607 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectKeyDown(*mDispatcher))
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -080010608 << "Inject key event should return InputEventInjectionResult::SUCCEEDED";
Linnan Li13bf76a2024-05-05 19:18:02 +080010609 mWindow->consumeKeyDown(ui::ADISPLAY_ID_NONE);
Vishnu Nair958da932020-08-21 17:12:37 -070010610}
10611
10612// A focused & mirrored window remains focused only if the window and its mirror are both
10613// focusable.
10614TEST_F(InputDispatcherMirrorWindowFocusTests, FocusedIfAllWindowsFocusable) {
10615 setFocusedWindow(mMirror);
10616
Prabir Pradhanbb3f1c02024-01-04 20:17:14 +000010617 // window gets focused because it is above the mirror
Vishnu Nair958da932020-08-21 17:12:37 -070010618 mWindow->consumeFocusEvent(true);
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070010619 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectKeyDown(*mDispatcher))
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -080010620 << "Inject key event should return InputEventInjectionResult::SUCCEEDED";
Linnan Li13bf76a2024-05-05 19:18:02 +080010621 mWindow->consumeKeyDown(ui::ADISPLAY_ID_NONE);
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070010622 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectKeyUp(*mDispatcher))
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -080010623 << "Inject key event should return InputEventInjectionResult::SUCCEEDED";
Linnan Li13bf76a2024-05-05 19:18:02 +080010624 mWindow->consumeKeyUp(ui::ADISPLAY_ID_NONE);
Vishnu Nair958da932020-08-21 17:12:37 -070010625
10626 mMirror->setFocusable(false);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070010627 mDispatcher->onWindowInfosChanged({{*mWindow->getInfo(), *mMirror->getInfo()}, {}, 0, 0});
Vishnu Nair958da932020-08-21 17:12:37 -070010628
10629 // window loses focus since one of the windows associated with the token in not focusable
10630 mWindow->consumeFocusEvent(false);
10631
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070010632 ASSERT_EQ(InputEventInjectionResult::TIMED_OUT, injectKeyDown(*mDispatcher))
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -080010633 << "Inject key event should return InputEventInjectionResult::TIMED_OUT";
Vishnu Nair958da932020-08-21 17:12:37 -070010634 mWindow->assertNoEvents();
10635}
10636
10637// A focused & mirrored window remains focused until the window and its mirror both become
10638// invisible.
10639TEST_F(InputDispatcherMirrorWindowFocusTests, FocusedIfAnyWindowVisible) {
10640 setFocusedWindow(mMirror);
10641
10642 // window gets focused
10643 mWindow->consumeFocusEvent(true);
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070010644 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectKeyDown(*mDispatcher))
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -080010645 << "Inject key event should return InputEventInjectionResult::SUCCEEDED";
Linnan Li13bf76a2024-05-05 19:18:02 +080010646 mWindow->consumeKeyDown(ui::ADISPLAY_ID_NONE);
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070010647 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectKeyUp(*mDispatcher))
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -080010648 << "Inject key event should return InputEventInjectionResult::SUCCEEDED";
Linnan Li13bf76a2024-05-05 19:18:02 +080010649 mWindow->consumeKeyUp(ui::ADISPLAY_ID_NONE);
Vishnu Nair958da932020-08-21 17:12:37 -070010650
10651 mMirror->setVisible(false);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070010652 mDispatcher->onWindowInfosChanged({{*mWindow->getInfo(), *mMirror->getInfo()}, {}, 0, 0});
Vishnu Nair958da932020-08-21 17:12:37 -070010653
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070010654 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectKeyDown(*mDispatcher))
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -080010655 << "Inject key event should return InputEventInjectionResult::SUCCEEDED";
Linnan Li13bf76a2024-05-05 19:18:02 +080010656 mWindow->consumeKeyDown(ui::ADISPLAY_ID_NONE);
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070010657 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectKeyUp(*mDispatcher))
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -080010658 << "Inject key event should return InputEventInjectionResult::SUCCEEDED";
Linnan Li13bf76a2024-05-05 19:18:02 +080010659 mWindow->consumeKeyUp(ui::ADISPLAY_ID_NONE);
Vishnu Nair958da932020-08-21 17:12:37 -070010660
10661 mWindow->setVisible(false);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070010662 mDispatcher->onWindowInfosChanged({{*mWindow->getInfo(), *mMirror->getInfo()}, {}, 0, 0});
Vishnu Nair958da932020-08-21 17:12:37 -070010663
10664 // window loses focus only after all windows associated with the token become invisible.
10665 mWindow->consumeFocusEvent(false);
10666
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070010667 ASSERT_EQ(InputEventInjectionResult::TIMED_OUT, injectKeyDown(*mDispatcher))
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -080010668 << "Inject key event should return InputEventInjectionResult::TIMED_OUT";
Vishnu Nair958da932020-08-21 17:12:37 -070010669 mWindow->assertNoEvents();
10670}
10671
10672// A focused & mirrored window remains focused until both windows are removed.
10673TEST_F(InputDispatcherMirrorWindowFocusTests, FocusedWhileWindowsAlive) {
10674 setFocusedWindow(mMirror);
10675
10676 // window gets focused
10677 mWindow->consumeFocusEvent(true);
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070010678 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectKeyDown(*mDispatcher))
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -080010679 << "Inject key event should return InputEventInjectionResult::SUCCEEDED";
Linnan Li13bf76a2024-05-05 19:18:02 +080010680 mWindow->consumeKeyDown(ui::ADISPLAY_ID_NONE);
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070010681 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectKeyUp(*mDispatcher))
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -080010682 << "Inject key event should return InputEventInjectionResult::SUCCEEDED";
Linnan Li13bf76a2024-05-05 19:18:02 +080010683 mWindow->consumeKeyUp(ui::ADISPLAY_ID_NONE);
Vishnu Nair958da932020-08-21 17:12:37 -070010684
10685 // single window is removed but the window token remains focused
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070010686 mDispatcher->onWindowInfosChanged({{*mMirror->getInfo()}, {}, 0, 0});
Vishnu Nair958da932020-08-21 17:12:37 -070010687
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070010688 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectKeyDown(*mDispatcher))
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -080010689 << "Inject key event should return InputEventInjectionResult::SUCCEEDED";
Linnan Li13bf76a2024-05-05 19:18:02 +080010690 mMirror->consumeKeyDown(ui::ADISPLAY_ID_NONE);
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070010691 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectKeyUp(*mDispatcher))
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -080010692 << "Inject key event should return InputEventInjectionResult::SUCCEEDED";
Linnan Li13bf76a2024-05-05 19:18:02 +080010693 mMirror->consumeKeyUp(ui::ADISPLAY_ID_NONE);
Vishnu Nair958da932020-08-21 17:12:37 -070010694
10695 // Both windows are removed
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070010696 mDispatcher->onWindowInfosChanged({{}, {}, 0, 0});
Vishnu Nair958da932020-08-21 17:12:37 -070010697 mWindow->consumeFocusEvent(false);
10698
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070010699 ASSERT_EQ(InputEventInjectionResult::TIMED_OUT, injectKeyDown(*mDispatcher))
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -080010700 << "Inject key event should return InputEventInjectionResult::TIMED_OUT";
Vishnu Nair958da932020-08-21 17:12:37 -070010701 mWindow->assertNoEvents();
10702}
10703
10704// Focus request can be pending until one window becomes visible.
10705TEST_F(InputDispatcherMirrorWindowFocusTests, DeferFocusWhenInvisible) {
10706 // Request focus on an invisible mirror.
10707 mWindow->setVisible(false);
10708 mMirror->setVisible(false);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070010709 mDispatcher->onWindowInfosChanged({{*mWindow->getInfo(), *mMirror->getInfo()}, {}, 0, 0});
Vishnu Nair958da932020-08-21 17:12:37 -070010710 setFocusedWindow(mMirror);
10711
10712 // Injected key goes to pending queue.
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -080010713 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070010714 injectKey(*mDispatcher, AKEY_EVENT_ACTION_DOWN, /*repeatCount=*/0,
10715 ADISPLAY_ID_DEFAULT, InputEventInjectionSync::NONE));
Vishnu Nair958da932020-08-21 17:12:37 -070010716
10717 mMirror->setVisible(true);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070010718 mDispatcher->onWindowInfosChanged({{*mWindow->getInfo(), *mMirror->getInfo()}, {}, 0, 0});
Vishnu Nair958da932020-08-21 17:12:37 -070010719
10720 // window gets focused
10721 mWindow->consumeFocusEvent(true);
10722 // window gets the pending key event
10723 mWindow->consumeKeyDown(ADISPLAY_ID_DEFAULT);
10724}
Prabir Pradhan99987712020-11-10 18:43:05 -080010725
10726class InputDispatcherPointerCaptureTests : public InputDispatcherTest {
10727protected:
10728 std::shared_ptr<FakeApplicationHandle> mApp;
10729 sp<FakeWindowHandle> mWindow;
10730 sp<FakeWindowHandle> mSecondWindow;
10731
10732 void SetUp() override {
10733 InputDispatcherTest::SetUp();
10734 mApp = std::make_shared<FakeApplicationHandle>();
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -070010735 mWindow = sp<FakeWindowHandle>::make(mApp, mDispatcher, "TestWindow", ADISPLAY_ID_DEFAULT);
Prabir Pradhan99987712020-11-10 18:43:05 -080010736 mWindow->setFocusable(true);
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -070010737 mSecondWindow =
10738 sp<FakeWindowHandle>::make(mApp, mDispatcher, "TestWindow2", ADISPLAY_ID_DEFAULT);
Prabir Pradhan99987712020-11-10 18:43:05 -080010739 mSecondWindow->setFocusable(true);
10740
10741 mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, mApp);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070010742 mDispatcher->onWindowInfosChanged(
10743 {{*mWindow->getInfo(), *mSecondWindow->getInfo()}, {}, 0, 0});
Prabir Pradhan99987712020-11-10 18:43:05 -080010744
10745 setFocusedWindow(mWindow);
10746 mWindow->consumeFocusEvent(true);
10747 }
10748
Prabir Pradhan5cc1a692021-08-06 14:01:18 +000010749 void notifyPointerCaptureChanged(const PointerCaptureRequest& request) {
Prabir Pradhan678438e2023-04-13 19:32:51 +000010750 mDispatcher->notifyPointerCaptureChanged(generatePointerCaptureChangedArgs(request));
Prabir Pradhan99987712020-11-10 18:43:05 -080010751 }
10752
Prabir Pradhan5cc1a692021-08-06 14:01:18 +000010753 PointerCaptureRequest requestAndVerifyPointerCapture(const sp<FakeWindowHandle>& window,
10754 bool enabled) {
Prabir Pradhan99987712020-11-10 18:43:05 -080010755 mDispatcher->requestPointerCapture(window->getToken(), enabled);
Hiroki Sato25040232024-02-22 17:21:22 +090010756 auto request = mFakePolicy->assertSetPointerCaptureCalled(window, enabled);
Prabir Pradhan5cc1a692021-08-06 14:01:18 +000010757 notifyPointerCaptureChanged(request);
Prabir Pradhan99987712020-11-10 18:43:05 -080010758 window->consumeCaptureEvent(enabled);
Prabir Pradhan5cc1a692021-08-06 14:01:18 +000010759 return request;
Prabir Pradhan99987712020-11-10 18:43:05 -080010760 }
10761};
10762
10763TEST_F(InputDispatcherPointerCaptureTests, EnablePointerCaptureWhenFocused) {
10764 // Ensure that capture cannot be obtained for unfocused windows.
10765 mDispatcher->requestPointerCapture(mSecondWindow->getToken(), true);
10766 mFakePolicy->assertSetPointerCaptureNotCalled();
10767 mSecondWindow->assertNoEvents();
10768
10769 // Ensure that capture can be enabled from the focus window.
10770 requestAndVerifyPointerCapture(mWindow, true);
10771
10772 // Ensure that capture cannot be disabled from a window that does not have capture.
10773 mDispatcher->requestPointerCapture(mSecondWindow->getToken(), false);
10774 mFakePolicy->assertSetPointerCaptureNotCalled();
10775
10776 // Ensure that capture can be disabled from the window with capture.
10777 requestAndVerifyPointerCapture(mWindow, false);
10778}
10779
10780TEST_F(InputDispatcherPointerCaptureTests, DisablesPointerCaptureAfterWindowLosesFocus) {
Prabir Pradhan5cc1a692021-08-06 14:01:18 +000010781 auto request = requestAndVerifyPointerCapture(mWindow, true);
Prabir Pradhan99987712020-11-10 18:43:05 -080010782
10783 setFocusedWindow(mSecondWindow);
10784
10785 // Ensure that the capture disabled event was sent first.
10786 mWindow->consumeCaptureEvent(false);
10787 mWindow->consumeFocusEvent(false);
10788 mSecondWindow->consumeFocusEvent(true);
Hiroki Sato25040232024-02-22 17:21:22 +090010789 mFakePolicy->assertSetPointerCaptureCalled(mWindow, false);
Prabir Pradhan99987712020-11-10 18:43:05 -080010790
10791 // Ensure that additional state changes from InputReader are not sent to the window.
Prabir Pradhan5cc1a692021-08-06 14:01:18 +000010792 notifyPointerCaptureChanged({});
10793 notifyPointerCaptureChanged(request);
10794 notifyPointerCaptureChanged({});
Prabir Pradhan99987712020-11-10 18:43:05 -080010795 mWindow->assertNoEvents();
10796 mSecondWindow->assertNoEvents();
10797 mFakePolicy->assertSetPointerCaptureNotCalled();
10798}
10799
10800TEST_F(InputDispatcherPointerCaptureTests, UnexpectedStateChangeDisablesPointerCapture) {
Prabir Pradhan5cc1a692021-08-06 14:01:18 +000010801 auto request = requestAndVerifyPointerCapture(mWindow, true);
Prabir Pradhan99987712020-11-10 18:43:05 -080010802
10803 // InputReader unexpectedly disables and enables pointer capture.
Prabir Pradhan5cc1a692021-08-06 14:01:18 +000010804 notifyPointerCaptureChanged({});
10805 notifyPointerCaptureChanged(request);
Prabir Pradhan99987712020-11-10 18:43:05 -080010806
10807 // Ensure that Pointer Capture is disabled.
Hiroki Sato25040232024-02-22 17:21:22 +090010808 mFakePolicy->assertSetPointerCaptureCalled(mWindow, false);
Prabir Pradhan99987712020-11-10 18:43:05 -080010809 mWindow->consumeCaptureEvent(false);
10810 mWindow->assertNoEvents();
10811}
10812
Prabir Pradhan167e6d92021-02-04 16:18:17 -080010813TEST_F(InputDispatcherPointerCaptureTests, OutOfOrderRequests) {
10814 requestAndVerifyPointerCapture(mWindow, true);
10815
10816 // The first window loses focus.
10817 setFocusedWindow(mSecondWindow);
Hiroki Sato25040232024-02-22 17:21:22 +090010818 mFakePolicy->assertSetPointerCaptureCalled(mWindow, false);
Prabir Pradhan167e6d92021-02-04 16:18:17 -080010819 mWindow->consumeCaptureEvent(false);
10820
10821 // Request Pointer Capture from the second window before the notification from InputReader
10822 // arrives.
10823 mDispatcher->requestPointerCapture(mSecondWindow->getToken(), true);
Hiroki Sato25040232024-02-22 17:21:22 +090010824 auto request = mFakePolicy->assertSetPointerCaptureCalled(mSecondWindow, true);
Prabir Pradhan167e6d92021-02-04 16:18:17 -080010825
10826 // InputReader notifies Pointer Capture was disabled (because of the focus change).
Prabir Pradhan5cc1a692021-08-06 14:01:18 +000010827 notifyPointerCaptureChanged({});
Prabir Pradhan167e6d92021-02-04 16:18:17 -080010828
10829 // InputReader notifies Pointer Capture was enabled (because of mSecondWindow's request).
Prabir Pradhan5cc1a692021-08-06 14:01:18 +000010830 notifyPointerCaptureChanged(request);
Prabir Pradhan167e6d92021-02-04 16:18:17 -080010831
10832 mSecondWindow->consumeFocusEvent(true);
10833 mSecondWindow->consumeCaptureEvent(true);
10834}
10835
Prabir Pradhan5cc1a692021-08-06 14:01:18 +000010836TEST_F(InputDispatcherPointerCaptureTests, EnableRequestFollowsSequenceNumbers) {
10837 // App repeatedly enables and disables capture.
10838 mDispatcher->requestPointerCapture(mWindow->getToken(), true);
Hiroki Sato25040232024-02-22 17:21:22 +090010839 auto firstRequest = mFakePolicy->assertSetPointerCaptureCalled(mWindow, true);
Prabir Pradhan5cc1a692021-08-06 14:01:18 +000010840 mDispatcher->requestPointerCapture(mWindow->getToken(), false);
Hiroki Sato25040232024-02-22 17:21:22 +090010841 mFakePolicy->assertSetPointerCaptureCalled(mWindow, false);
Prabir Pradhan5cc1a692021-08-06 14:01:18 +000010842 mDispatcher->requestPointerCapture(mWindow->getToken(), true);
Hiroki Sato25040232024-02-22 17:21:22 +090010843 auto secondRequest = mFakePolicy->assertSetPointerCaptureCalled(mWindow, true);
Prabir Pradhan5cc1a692021-08-06 14:01:18 +000010844
10845 // InputReader notifies that PointerCapture has been enabled for the first request. Since the
10846 // first request is now stale, this should do nothing.
10847 notifyPointerCaptureChanged(firstRequest);
10848 mWindow->assertNoEvents();
10849
10850 // InputReader notifies that the second request was enabled.
10851 notifyPointerCaptureChanged(secondRequest);
10852 mWindow->consumeCaptureEvent(true);
10853}
10854
Prabir Pradhan7092e262022-05-03 16:51:09 +000010855TEST_F(InputDispatcherPointerCaptureTests, RapidToggleRequests) {
10856 requestAndVerifyPointerCapture(mWindow, true);
10857
10858 // App toggles pointer capture off and on.
10859 mDispatcher->requestPointerCapture(mWindow->getToken(), false);
Hiroki Sato25040232024-02-22 17:21:22 +090010860 mFakePolicy->assertSetPointerCaptureCalled(mWindow, false);
Prabir Pradhan7092e262022-05-03 16:51:09 +000010861
10862 mDispatcher->requestPointerCapture(mWindow->getToken(), true);
Hiroki Sato25040232024-02-22 17:21:22 +090010863 auto enableRequest = mFakePolicy->assertSetPointerCaptureCalled(mWindow, true);
Prabir Pradhan7092e262022-05-03 16:51:09 +000010864
10865 // InputReader notifies that the latest "enable" request was processed, while skipping over the
10866 // preceding "disable" request.
10867 notifyPointerCaptureChanged(enableRequest);
10868
10869 // Since pointer capture was never disabled during the rapid toggle, the window does not receive
10870 // any notifications.
10871 mWindow->assertNoEvents();
10872}
10873
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -070010874/**
10875 * One window. Hover mouse in the window, and then start capture. Make sure that the relative
10876 * mouse movements don't affect the previous mouse hovering state.
10877 * When pointer capture is enabled, the incoming events are always ACTION_MOVE (there are no
10878 * HOVER_MOVE events).
10879 */
10880TEST_F(InputDispatcherPointerCaptureTests, MouseHoverAndPointerCapture) {
10881 // Mouse hover on the window
10882 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_ENTER, AINPUT_SOURCE_MOUSE)
10883 .pointer(PointerBuilder(0, ToolType::MOUSE).x(100).y(110))
10884 .build());
10885 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_MOVE, AINPUT_SOURCE_MOUSE)
10886 .pointer(PointerBuilder(0, ToolType::MOUSE).x(100).y(110))
10887 .build());
10888
10889 mWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_HOVER_ENTER)));
10890 mWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_HOVER_MOVE)));
10891
10892 // Start pointer capture
10893 requestAndVerifyPointerCapture(mWindow, true);
10894
10895 // Send some relative mouse movements and receive them in the window.
10896 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_MOUSE_RELATIVE)
10897 .pointer(PointerBuilder(0, ToolType::MOUSE).x(10).y(11))
10898 .build());
10899 mWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_MOVE), WithCoords(10, 11),
10900 WithSource(AINPUT_SOURCE_MOUSE_RELATIVE)));
10901
10902 // Stop pointer capture
10903 requestAndVerifyPointerCapture(mWindow, false);
10904
10905 // Continue hovering on the window
10906 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_MOVE, AINPUT_SOURCE_MOUSE)
10907 .pointer(PointerBuilder(0, ToolType::MOUSE).x(105).y(115))
10908 .build());
10909 mWindow->consumeMotionEvent(
10910 AllOf(WithMotionAction(ACTION_HOVER_MOVE), WithSource(AINPUT_SOURCE_MOUSE)));
10911
10912 mWindow->assertNoEvents();
10913}
10914
Hiroki Sato25040232024-02-22 17:21:22 +090010915using InputDispatcherPointerCaptureDeathTest = InputDispatcherPointerCaptureTests;
10916
10917TEST_F(InputDispatcherPointerCaptureDeathTest,
10918 NotifyPointerCaptureChangedWithWrongTokenAbortsDispatcher) {
10919 testing::GTEST_FLAG(death_test_style) = "threadsafe";
10920 ScopedSilentDeath _silentDeath;
10921
10922 mDispatcher->requestPointerCapture(mWindow->getToken(), true);
10923 auto request = mFakePolicy->assertSetPointerCaptureCalled(mWindow, true);
10924
10925 // Dispatch a pointer changed event with a wrong token.
10926 request.window = mSecondWindow->getToken();
10927 ASSERT_DEATH(
10928 {
10929 notifyPointerCaptureChanged(request);
10930 mSecondWindow->consumeCaptureEvent(true);
10931 },
10932 "Unexpected requested window for Pointer Capture.");
10933}
10934
Bernardo Rufinoc3b7b8c2021-01-29 17:38:07 +000010935class InputDispatcherUntrustedTouchesTest : public InputDispatcherTest {
10936protected:
10937 constexpr static const float MAXIMUM_OBSCURING_OPACITY = 0.8;
Bernardo Rufino7393d172021-02-26 13:56:11 +000010938
10939 constexpr static const float OPACITY_ABOVE_THRESHOLD = 0.9;
10940 static_assert(OPACITY_ABOVE_THRESHOLD > MAXIMUM_OBSCURING_OPACITY);
10941
10942 constexpr static const float OPACITY_BELOW_THRESHOLD = 0.7;
10943 static_assert(OPACITY_BELOW_THRESHOLD < MAXIMUM_OBSCURING_OPACITY);
10944
10945 // When combined twice, ie 1 - (1 - 0.5)*(1 - 0.5) = 0.75 < 8, is still below the threshold
10946 constexpr static const float OPACITY_FAR_BELOW_THRESHOLD = 0.5;
10947 static_assert(OPACITY_FAR_BELOW_THRESHOLD < MAXIMUM_OBSCURING_OPACITY);
10948 static_assert(1 - (1 - OPACITY_FAR_BELOW_THRESHOLD) * (1 - OPACITY_FAR_BELOW_THRESHOLD) <
10949 MAXIMUM_OBSCURING_OPACITY);
10950
Prabir Pradhan8a5c41d2023-06-08 19:13:46 +000010951 static constexpr gui::Uid TOUCHED_APP_UID{10001};
10952 static constexpr gui::Uid APP_B_UID{10002};
10953 static constexpr gui::Uid APP_C_UID{10003};
Bernardo Rufinoc3b7b8c2021-01-29 17:38:07 +000010954
10955 sp<FakeWindowHandle> mTouchWindow;
10956
10957 virtual void SetUp() override {
10958 InputDispatcherTest::SetUp();
Bernardo Rufino6d52e542021-02-15 18:38:10 +000010959 mTouchWindow = getWindow(TOUCHED_APP_UID, "Touched");
Bernardo Rufinoc3b7b8c2021-01-29 17:38:07 +000010960 mDispatcher->setMaximumObscuringOpacityForTouch(MAXIMUM_OBSCURING_OPACITY);
10961 }
10962
10963 virtual void TearDown() override {
10964 InputDispatcherTest::TearDown();
10965 mTouchWindow.clear();
10966 }
10967
Prabir Pradhan8a5c41d2023-06-08 19:13:46 +000010968 sp<FakeWindowHandle> getOccludingWindow(gui::Uid uid, std::string name, TouchOcclusionMode mode,
chaviw3277faf2021-05-19 16:45:23 -050010969 float alpha = 1.0f) {
Bernardo Rufinoc3b7b8c2021-01-29 17:38:07 +000010970 sp<FakeWindowHandle> window = getWindow(uid, name);
Prabir Pradhan4d5c52f2022-01-31 08:52:10 -080010971 window->setTouchable(false);
Bernardo Rufinoc3b7b8c2021-01-29 17:38:07 +000010972 window->setTouchOcclusionMode(mode);
Bernardo Rufino1d0d1f22021-02-12 15:08:43 +000010973 window->setAlpha(alpha);
Bernardo Rufinoc3b7b8c2021-01-29 17:38:07 +000010974 return window;
10975 }
10976
Prabir Pradhan8a5c41d2023-06-08 19:13:46 +000010977 sp<FakeWindowHandle> getWindow(gui::Uid uid, std::string name) {
Bernardo Rufinoc3b7b8c2021-01-29 17:38:07 +000010978 std::shared_ptr<FakeApplicationHandle> app = std::make_shared<FakeApplicationHandle>();
10979 sp<FakeWindowHandle> window =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -070010980 sp<FakeWindowHandle>::make(app, mDispatcher, name, ADISPLAY_ID_DEFAULT);
Bernardo Rufinoc3b7b8c2021-01-29 17:38:07 +000010981 // Generate an arbitrary PID based on the UID
Prabir Pradhanaeebeb42023-06-13 19:53:03 +000010982 window->setOwnerInfo(gui::Pid{static_cast<pid_t>(1777 + (uid.val() % 10000))}, uid);
Bernardo Rufinoc3b7b8c2021-01-29 17:38:07 +000010983 return window;
10984 }
10985
10986 void touch(const std::vector<PointF>& points = {PointF{100, 200}}) {
Prabir Pradhan678438e2023-04-13 19:32:51 +000010987 mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_DOWN,
10988 AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
10989 points));
Bernardo Rufinoc3b7b8c2021-01-29 17:38:07 +000010990 }
10991};
10992
10993TEST_F(InputDispatcherUntrustedTouchesTest, WindowWithBlockUntrustedOcclusionMode_BlocksTouch) {
Bernardo Rufino1d0d1f22021-02-12 15:08:43 +000010994 const sp<FakeWindowHandle>& w =
Bernardo Rufinoc3b7b8c2021-01-29 17:38:07 +000010995 getOccludingWindow(APP_B_UID, "B", TouchOcclusionMode::BLOCK_UNTRUSTED);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070010996 mDispatcher->onWindowInfosChanged({{*w->getInfo(), *mTouchWindow->getInfo()}, {}, 0, 0});
Bernardo Rufinoc3b7b8c2021-01-29 17:38:07 +000010997
10998 touch();
10999
11000 mTouchWindow->assertNoEvents();
11001}
11002
Bernardo Rufinoa43a5a42021-02-17 12:21:14 +000011003TEST_F(InputDispatcherUntrustedTouchesTest,
Bernardo Rufino7393d172021-02-26 13:56:11 +000011004 WindowWithBlockUntrustedOcclusionModeWithOpacityBelowThreshold_BlocksTouch) {
11005 const sp<FakeWindowHandle>& w =
11006 getOccludingWindow(APP_B_UID, "B", TouchOcclusionMode::BLOCK_UNTRUSTED, 0.7f);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070011007 mDispatcher->onWindowInfosChanged({{*w->getInfo(), *mTouchWindow->getInfo()}, {}, 0, 0});
Bernardo Rufino7393d172021-02-26 13:56:11 +000011008
11009 touch();
11010
11011 mTouchWindow->assertNoEvents();
11012}
11013
11014TEST_F(InputDispatcherUntrustedTouchesTest,
Bernardo Rufinoa43a5a42021-02-17 12:21:14 +000011015 WindowWithBlockUntrustedOcclusionMode_DoesNotReceiveTouch) {
11016 const sp<FakeWindowHandle>& w =
11017 getOccludingWindow(APP_B_UID, "B", TouchOcclusionMode::BLOCK_UNTRUSTED);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070011018 mDispatcher->onWindowInfosChanged({{*w->getInfo(), *mTouchWindow->getInfo()}, {}, 0, 0});
Bernardo Rufinoa43a5a42021-02-17 12:21:14 +000011019
11020 touch();
11021
11022 w->assertNoEvents();
11023}
11024
Bernardo Rufinoc3b7b8c2021-01-29 17:38:07 +000011025TEST_F(InputDispatcherUntrustedTouchesTest, WindowWithAllowOcclusionMode_AllowsTouch) {
Bernardo Rufino1d0d1f22021-02-12 15:08:43 +000011026 const sp<FakeWindowHandle>& w = getOccludingWindow(APP_B_UID, "B", TouchOcclusionMode::ALLOW);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070011027 mDispatcher->onWindowInfosChanged({{*w->getInfo(), *mTouchWindow->getInfo()}, {}, 0, 0});
Bernardo Rufinoc3b7b8c2021-01-29 17:38:07 +000011028
11029 touch();
11030
11031 mTouchWindow->consumeAnyMotionDown();
11032}
11033
11034TEST_F(InputDispatcherUntrustedTouchesTest, TouchOutsideOccludingWindow_AllowsTouch) {
Bernardo Rufino1d0d1f22021-02-12 15:08:43 +000011035 const sp<FakeWindowHandle>& w =
Bernardo Rufinoc3b7b8c2021-01-29 17:38:07 +000011036 getOccludingWindow(APP_B_UID, "B", TouchOcclusionMode::BLOCK_UNTRUSTED);
Bernardo Rufino1d0d1f22021-02-12 15:08:43 +000011037 w->setFrame(Rect(0, 0, 50, 50));
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070011038 mDispatcher->onWindowInfosChanged({{*w->getInfo(), *mTouchWindow->getInfo()}, {}, 0, 0});
Bernardo Rufinoc3b7b8c2021-01-29 17:38:07 +000011039
11040 touch({PointF{100, 100}});
11041
11042 mTouchWindow->consumeAnyMotionDown();
11043}
11044
11045TEST_F(InputDispatcherUntrustedTouchesTest, WindowFromSameUid_AllowsTouch) {
Bernardo Rufino1d0d1f22021-02-12 15:08:43 +000011046 const sp<FakeWindowHandle>& w =
Bernardo Rufino6d52e542021-02-15 18:38:10 +000011047 getOccludingWindow(TOUCHED_APP_UID, "A", TouchOcclusionMode::BLOCK_UNTRUSTED);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070011048 mDispatcher->onWindowInfosChanged({{*w->getInfo(), *mTouchWindow->getInfo()}, {}, 0, 0});
Bernardo Rufino1d0d1f22021-02-12 15:08:43 +000011049
11050 touch();
11051
11052 mTouchWindow->consumeAnyMotionDown();
11053}
11054
11055TEST_F(InputDispatcherUntrustedTouchesTest, WindowWithZeroOpacity_AllowsTouch) {
11056 const sp<FakeWindowHandle>& w =
11057 getOccludingWindow(APP_B_UID, "B", TouchOcclusionMode::BLOCK_UNTRUSTED, 0.0f);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070011058 mDispatcher->onWindowInfosChanged({{*w->getInfo(), *mTouchWindow->getInfo()}, {}, 0, 0});
Bernardo Rufinoc3b7b8c2021-01-29 17:38:07 +000011059
11060 touch();
11061
11062 mTouchWindow->consumeAnyMotionDown();
11063}
11064
Bernardo Rufinoa43a5a42021-02-17 12:21:14 +000011065TEST_F(InputDispatcherUntrustedTouchesTest, WindowWithZeroOpacity_DoesNotReceiveTouch) {
11066 const sp<FakeWindowHandle>& w =
11067 getOccludingWindow(APP_B_UID, "B", TouchOcclusionMode::BLOCK_UNTRUSTED, 0.0f);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070011068 mDispatcher->onWindowInfosChanged({{*w->getInfo(), *mTouchWindow->getInfo()}, {}, 0, 0});
Bernardo Rufinoa43a5a42021-02-17 12:21:14 +000011069
11070 touch();
11071
11072 w->assertNoEvents();
11073}
11074
11075/**
11076 * This is important to make sure apps can't indirectly learn the position of touches (outside vs
11077 * inside) while letting them pass-through. Note that even though touch passes through the occluding
11078 * window, the occluding window will still receive ACTION_OUTSIDE event.
11079 */
11080TEST_F(InputDispatcherUntrustedTouchesTest,
11081 WindowWithZeroOpacityAndWatchOutside_ReceivesOutsideEvent) {
11082 const sp<FakeWindowHandle>& w =
11083 getOccludingWindow(APP_B_UID, "B", TouchOcclusionMode::BLOCK_UNTRUSTED, 0.0f);
Prabir Pradhan4d5c52f2022-01-31 08:52:10 -080011084 w->setWatchOutsideTouch(true);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070011085 mDispatcher->onWindowInfosChanged({{*w->getInfo(), *mTouchWindow->getInfo()}, {}, 0, 0});
Bernardo Rufinoa43a5a42021-02-17 12:21:14 +000011086
11087 touch();
11088
11089 w->consumeMotionOutside();
11090}
11091
11092TEST_F(InputDispatcherUntrustedTouchesTest, OutsideEvent_HasZeroCoordinates) {
11093 const sp<FakeWindowHandle>& w =
11094 getOccludingWindow(APP_B_UID, "B", TouchOcclusionMode::BLOCK_UNTRUSTED, 0.0f);
Prabir Pradhan4d5c52f2022-01-31 08:52:10 -080011095 w->setWatchOutsideTouch(true);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070011096 mDispatcher->onWindowInfosChanged({{*w->getInfo(), *mTouchWindow->getInfo()}, {}, 0, 0});
Bernardo Rufinoa43a5a42021-02-17 12:21:14 +000011097
11098 touch();
11099
Prabir Pradhandfabf8a2022-01-21 08:19:30 -080011100 w->consumeMotionOutsideWithZeroedCoords();
Bernardo Rufinoa43a5a42021-02-17 12:21:14 +000011101}
11102
Bernardo Rufinoc3b7b8c2021-01-29 17:38:07 +000011103TEST_F(InputDispatcherUntrustedTouchesTest, WindowWithOpacityBelowThreshold_AllowsTouch) {
Bernardo Rufino1d0d1f22021-02-12 15:08:43 +000011104 const sp<FakeWindowHandle>& w =
Bernardo Rufino7393d172021-02-26 13:56:11 +000011105 getOccludingWindow(APP_B_UID, "B", TouchOcclusionMode::USE_OPACITY,
11106 OPACITY_BELOW_THRESHOLD);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070011107 mDispatcher->onWindowInfosChanged({{*w->getInfo(), *mTouchWindow->getInfo()}, {}, 0, 0});
Bernardo Rufino1d0d1f22021-02-12 15:08:43 +000011108
11109 touch();
11110
11111 mTouchWindow->consumeAnyMotionDown();
11112}
11113
11114TEST_F(InputDispatcherUntrustedTouchesTest, WindowWithOpacityAtThreshold_AllowsTouch) {
11115 const sp<FakeWindowHandle>& w =
11116 getOccludingWindow(APP_B_UID, "B", TouchOcclusionMode::USE_OPACITY,
11117 MAXIMUM_OBSCURING_OPACITY);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070011118 mDispatcher->onWindowInfosChanged({{*w->getInfo(), *mTouchWindow->getInfo()}, {}, 0, 0});
Bernardo Rufinoc3b7b8c2021-01-29 17:38:07 +000011119
11120 touch();
11121
11122 mTouchWindow->consumeAnyMotionDown();
11123}
11124
11125TEST_F(InputDispatcherUntrustedTouchesTest, WindowWithOpacityAboveThreshold_BlocksTouch) {
Bernardo Rufino1d0d1f22021-02-12 15:08:43 +000011126 const sp<FakeWindowHandle>& w =
Bernardo Rufino7393d172021-02-26 13:56:11 +000011127 getOccludingWindow(APP_B_UID, "B", TouchOcclusionMode::USE_OPACITY,
11128 OPACITY_ABOVE_THRESHOLD);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070011129 mDispatcher->onWindowInfosChanged({{*w->getInfo(), *mTouchWindow->getInfo()}, {}, 0, 0});
Bernardo Rufino1d0d1f22021-02-12 15:08:43 +000011130
11131 touch();
11132
11133 mTouchWindow->assertNoEvents();
11134}
11135
11136TEST_F(InputDispatcherUntrustedTouchesTest, WindowsWithCombinedOpacityAboveThreshold_BlocksTouch) {
11137 // Resulting opacity = 1 - (1 - 0.7)*(1 - 0.7) = .91
11138 const sp<FakeWindowHandle>& w1 =
Bernardo Rufino7393d172021-02-26 13:56:11 +000011139 getOccludingWindow(APP_B_UID, "B1", TouchOcclusionMode::USE_OPACITY,
11140 OPACITY_BELOW_THRESHOLD);
Bernardo Rufino1d0d1f22021-02-12 15:08:43 +000011141 const sp<FakeWindowHandle>& w2 =
Bernardo Rufino7393d172021-02-26 13:56:11 +000011142 getOccludingWindow(APP_B_UID, "B2", TouchOcclusionMode::USE_OPACITY,
11143 OPACITY_BELOW_THRESHOLD);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070011144 mDispatcher->onWindowInfosChanged(
11145 {{*w1->getInfo(), *w2->getInfo(), *mTouchWindow->getInfo()}, {}, 0, 0});
Bernardo Rufino1d0d1f22021-02-12 15:08:43 +000011146
11147 touch();
11148
11149 mTouchWindow->assertNoEvents();
11150}
11151
11152TEST_F(InputDispatcherUntrustedTouchesTest, WindowsWithCombinedOpacityBelowThreshold_AllowsTouch) {
11153 // Resulting opacity = 1 - (1 - 0.5)*(1 - 0.5) = .75
11154 const sp<FakeWindowHandle>& w1 =
Bernardo Rufino7393d172021-02-26 13:56:11 +000011155 getOccludingWindow(APP_B_UID, "B1", TouchOcclusionMode::USE_OPACITY,
11156 OPACITY_FAR_BELOW_THRESHOLD);
Bernardo Rufino1d0d1f22021-02-12 15:08:43 +000011157 const sp<FakeWindowHandle>& w2 =
Bernardo Rufino7393d172021-02-26 13:56:11 +000011158 getOccludingWindow(APP_B_UID, "B2", TouchOcclusionMode::USE_OPACITY,
11159 OPACITY_FAR_BELOW_THRESHOLD);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070011160 mDispatcher->onWindowInfosChanged(
11161 {{*w1->getInfo(), *w2->getInfo(), *mTouchWindow->getInfo()}, {}, 0, 0});
Bernardo Rufino1d0d1f22021-02-12 15:08:43 +000011162
11163 touch();
11164
11165 mTouchWindow->consumeAnyMotionDown();
11166}
11167
11168TEST_F(InputDispatcherUntrustedTouchesTest,
11169 WindowsFromDifferentAppsEachBelowThreshold_AllowsTouch) {
11170 const sp<FakeWindowHandle>& wB =
Bernardo Rufino7393d172021-02-26 13:56:11 +000011171 getOccludingWindow(APP_B_UID, "B", TouchOcclusionMode::USE_OPACITY,
11172 OPACITY_BELOW_THRESHOLD);
Bernardo Rufino1d0d1f22021-02-12 15:08:43 +000011173 const sp<FakeWindowHandle>& wC =
Bernardo Rufino7393d172021-02-26 13:56:11 +000011174 getOccludingWindow(APP_C_UID, "C", TouchOcclusionMode::USE_OPACITY,
11175 OPACITY_BELOW_THRESHOLD);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070011176 mDispatcher->onWindowInfosChanged(
11177 {{*wB->getInfo(), *wC->getInfo(), *mTouchWindow->getInfo()}, {}, 0, 0});
Bernardo Rufino1d0d1f22021-02-12 15:08:43 +000011178
11179 touch();
11180
11181 mTouchWindow->consumeAnyMotionDown();
11182}
11183
11184TEST_F(InputDispatcherUntrustedTouchesTest, WindowsFromDifferentAppsOneAboveThreshold_BlocksTouch) {
11185 const sp<FakeWindowHandle>& wB =
Bernardo Rufino7393d172021-02-26 13:56:11 +000011186 getOccludingWindow(APP_B_UID, "B", TouchOcclusionMode::USE_OPACITY,
11187 OPACITY_BELOW_THRESHOLD);
Bernardo Rufino1d0d1f22021-02-12 15:08:43 +000011188 const sp<FakeWindowHandle>& wC =
Bernardo Rufino7393d172021-02-26 13:56:11 +000011189 getOccludingWindow(APP_C_UID, "C", TouchOcclusionMode::USE_OPACITY,
11190 OPACITY_ABOVE_THRESHOLD);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070011191 mDispatcher->onWindowInfosChanged(
11192 {{*wB->getInfo(), *wC->getInfo(), *mTouchWindow->getInfo()}, {}, 0, 0});
Bernardo Rufinoc3b7b8c2021-01-29 17:38:07 +000011193
11194 touch();
11195
11196 mTouchWindow->assertNoEvents();
11197}
11198
Bernardo Rufino6d52e542021-02-15 18:38:10 +000011199TEST_F(InputDispatcherUntrustedTouchesTest,
11200 WindowWithOpacityAboveThresholdAndSelfWindow_BlocksTouch) {
11201 const sp<FakeWindowHandle>& wA =
Bernardo Rufino7393d172021-02-26 13:56:11 +000011202 getOccludingWindow(TOUCHED_APP_UID, "T", TouchOcclusionMode::USE_OPACITY,
11203 OPACITY_BELOW_THRESHOLD);
Bernardo Rufino6d52e542021-02-15 18:38:10 +000011204 const sp<FakeWindowHandle>& wB =
Bernardo Rufino7393d172021-02-26 13:56:11 +000011205 getOccludingWindow(APP_B_UID, "B", TouchOcclusionMode::USE_OPACITY,
11206 OPACITY_ABOVE_THRESHOLD);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070011207 mDispatcher->onWindowInfosChanged(
11208 {{*wA->getInfo(), *wB->getInfo(), *mTouchWindow->getInfo()}, {}, 0, 0});
Bernardo Rufino6d52e542021-02-15 18:38:10 +000011209
11210 touch();
11211
11212 mTouchWindow->assertNoEvents();
11213}
11214
11215TEST_F(InputDispatcherUntrustedTouchesTest,
11216 WindowWithOpacityBelowThresholdAndSelfWindow_AllowsTouch) {
11217 const sp<FakeWindowHandle>& wA =
Bernardo Rufino7393d172021-02-26 13:56:11 +000011218 getOccludingWindow(TOUCHED_APP_UID, "T", TouchOcclusionMode::USE_OPACITY,
11219 OPACITY_ABOVE_THRESHOLD);
Bernardo Rufino6d52e542021-02-15 18:38:10 +000011220 const sp<FakeWindowHandle>& wB =
Bernardo Rufino7393d172021-02-26 13:56:11 +000011221 getOccludingWindow(APP_B_UID, "B", TouchOcclusionMode::USE_OPACITY,
11222 OPACITY_BELOW_THRESHOLD);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070011223 mDispatcher->onWindowInfosChanged(
11224 {{*wA->getInfo(), *wB->getInfo(), *mTouchWindow->getInfo()}, {}, 0, 0});
Bernardo Rufino6d52e542021-02-15 18:38:10 +000011225
11226 touch();
11227
11228 mTouchWindow->consumeAnyMotionDown();
11229}
11230
11231TEST_F(InputDispatcherUntrustedTouchesTest, SelfWindowWithOpacityAboveThreshold_AllowsTouch) {
11232 const sp<FakeWindowHandle>& w =
Bernardo Rufino7393d172021-02-26 13:56:11 +000011233 getOccludingWindow(TOUCHED_APP_UID, "T", TouchOcclusionMode::USE_OPACITY,
11234 OPACITY_ABOVE_THRESHOLD);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070011235 mDispatcher->onWindowInfosChanged({{*w->getInfo(), *mTouchWindow->getInfo()}, {}, 0, 0});
Bernardo Rufino6d52e542021-02-15 18:38:10 +000011236
11237 touch();
11238
11239 mTouchWindow->consumeAnyMotionDown();
11240}
11241
11242TEST_F(InputDispatcherUntrustedTouchesTest, SelfWindowWithBlockUntrustedMode_AllowsTouch) {
11243 const sp<FakeWindowHandle>& w =
11244 getOccludingWindow(TOUCHED_APP_UID, "T", TouchOcclusionMode::BLOCK_UNTRUSTED);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070011245 mDispatcher->onWindowInfosChanged({{*w->getInfo(), *mTouchWindow->getInfo()}, {}, 0, 0});
Bernardo Rufino6d52e542021-02-15 18:38:10 +000011246
11247 touch();
11248
11249 mTouchWindow->consumeAnyMotionDown();
11250}
11251
Bernardo Rufinoccd3dd62021-02-15 18:47:42 +000011252TEST_F(InputDispatcherUntrustedTouchesTest,
11253 OpacityThresholdIs0AndWindowAboveThreshold_BlocksTouch) {
11254 mDispatcher->setMaximumObscuringOpacityForTouch(0.0f);
11255 const sp<FakeWindowHandle>& w =
11256 getOccludingWindow(APP_B_UID, "B", TouchOcclusionMode::USE_OPACITY, 0.1f);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070011257 mDispatcher->onWindowInfosChanged({{*w->getInfo(), *mTouchWindow->getInfo()}, {}, 0, 0});
Bernardo Rufinoccd3dd62021-02-15 18:47:42 +000011258
11259 touch();
11260
11261 mTouchWindow->assertNoEvents();
11262}
11263
11264TEST_F(InputDispatcherUntrustedTouchesTest, OpacityThresholdIs0AndWindowAtThreshold_AllowsTouch) {
11265 mDispatcher->setMaximumObscuringOpacityForTouch(0.0f);
11266 const sp<FakeWindowHandle>& w =
11267 getOccludingWindow(APP_B_UID, "B", TouchOcclusionMode::USE_OPACITY, 0.0f);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070011268 mDispatcher->onWindowInfosChanged({{*w->getInfo(), *mTouchWindow->getInfo()}, {}, 0, 0});
Bernardo Rufinoccd3dd62021-02-15 18:47:42 +000011269
11270 touch();
11271
11272 mTouchWindow->consumeAnyMotionDown();
11273}
11274
11275TEST_F(InputDispatcherUntrustedTouchesTest,
11276 OpacityThresholdIs1AndWindowBelowThreshold_AllowsTouch) {
11277 mDispatcher->setMaximumObscuringOpacityForTouch(1.0f);
11278 const sp<FakeWindowHandle>& w =
Bernardo Rufino7393d172021-02-26 13:56:11 +000011279 getOccludingWindow(APP_B_UID, "B", TouchOcclusionMode::USE_OPACITY,
11280 OPACITY_ABOVE_THRESHOLD);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070011281 mDispatcher->onWindowInfosChanged({{*w->getInfo(), *mTouchWindow->getInfo()}, {}, 0, 0});
Bernardo Rufino7393d172021-02-26 13:56:11 +000011282
11283 touch();
11284
11285 mTouchWindow->consumeAnyMotionDown();
11286}
11287
11288TEST_F(InputDispatcherUntrustedTouchesTest,
11289 WindowWithBlockUntrustedModeAndWindowWithOpacityBelowFromSameApp_BlocksTouch) {
11290 const sp<FakeWindowHandle>& w1 =
11291 getOccludingWindow(APP_B_UID, "B", TouchOcclusionMode::BLOCK_UNTRUSTED,
11292 OPACITY_BELOW_THRESHOLD);
11293 const sp<FakeWindowHandle>& w2 =
11294 getOccludingWindow(APP_B_UID, "B", TouchOcclusionMode::USE_OPACITY,
11295 OPACITY_BELOW_THRESHOLD);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070011296 mDispatcher->onWindowInfosChanged(
11297 {{*w1->getInfo(), *w2->getInfo(), *mTouchWindow->getInfo()}, {}, 0, 0});
Bernardo Rufino7393d172021-02-26 13:56:11 +000011298
11299 touch();
11300
11301 mTouchWindow->assertNoEvents();
11302}
11303
11304/**
11305 * Window B of BLOCK_UNTRUSTED occlusion mode is enough to block the touch, we're testing that the
11306 * addition of another window (C) of USE_OPACITY occlusion mode and opacity below the threshold
11307 * (which alone would result in allowing touches) does not affect the blocking behavior.
11308 */
11309TEST_F(InputDispatcherUntrustedTouchesTest,
11310 WindowWithBlockUntrustedModeAndWindowWithOpacityBelowFromDifferentApps_BlocksTouch) {
11311 const sp<FakeWindowHandle>& wB =
11312 getOccludingWindow(APP_B_UID, "B", TouchOcclusionMode::BLOCK_UNTRUSTED,
11313 OPACITY_BELOW_THRESHOLD);
11314 const sp<FakeWindowHandle>& wC =
11315 getOccludingWindow(APP_C_UID, "C", TouchOcclusionMode::USE_OPACITY,
11316 OPACITY_BELOW_THRESHOLD);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070011317 mDispatcher->onWindowInfosChanged(
11318 {{*wB->getInfo(), *wC->getInfo(), *mTouchWindow->getInfo()}, {}, 0, 0});
Bernardo Rufino7393d172021-02-26 13:56:11 +000011319
11320 touch();
11321
11322 mTouchWindow->assertNoEvents();
11323}
11324
11325/**
11326 * This test is testing that a window from a different UID but with same application token doesn't
11327 * block the touch. Apps can share the application token for close UI collaboration for example.
11328 */
11329TEST_F(InputDispatcherUntrustedTouchesTest,
11330 WindowWithSameApplicationTokenFromDifferentApp_AllowsTouch) {
11331 const sp<FakeWindowHandle>& w =
11332 getOccludingWindow(APP_B_UID, "B", TouchOcclusionMode::BLOCK_UNTRUSTED);
11333 w->setApplicationToken(mTouchWindow->getApplicationToken());
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070011334 mDispatcher->onWindowInfosChanged({{*w->getInfo(), *mTouchWindow->getInfo()}, {}, 0, 0});
Bernardo Rufinoccd3dd62021-02-15 18:47:42 +000011335
11336 touch();
11337
11338 mTouchWindow->consumeAnyMotionDown();
11339}
11340
arthurhungb89ccb02020-12-30 16:19:01 +080011341class InputDispatcherDragTests : public InputDispatcherTest {
11342protected:
11343 std::shared_ptr<FakeApplicationHandle> mApp;
11344 sp<FakeWindowHandle> mWindow;
11345 sp<FakeWindowHandle> mSecondWindow;
11346 sp<FakeWindowHandle> mDragWindow;
Vaibhav Devmurari6abcf8f2022-06-06 10:08:05 +000011347 sp<FakeWindowHandle> mSpyWindow;
Arthur Hungb75c2aa2022-07-15 09:35:36 +000011348 // Mouse would force no-split, set the id as non-zero to verify if drag state could track it.
11349 static constexpr int32_t MOUSE_POINTER_ID = 1;
arthurhungb89ccb02020-12-30 16:19:01 +080011350
11351 void SetUp() override {
11352 InputDispatcherTest::SetUp();
11353 mApp = std::make_shared<FakeApplicationHandle>();
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -070011354 mWindow = sp<FakeWindowHandle>::make(mApp, mDispatcher, "TestWindow", ADISPLAY_ID_DEFAULT);
arthurhungb89ccb02020-12-30 16:19:01 +080011355 mWindow->setFrame(Rect(0, 0, 100, 100));
arthurhungb89ccb02020-12-30 16:19:01 +080011356
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -070011357 mSecondWindow =
11358 sp<FakeWindowHandle>::make(mApp, mDispatcher, "TestWindow2", ADISPLAY_ID_DEFAULT);
arthurhungb89ccb02020-12-30 16:19:01 +080011359 mSecondWindow->setFrame(Rect(100, 0, 200, 100));
arthurhungb89ccb02020-12-30 16:19:01 +080011360
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -070011361 mSpyWindow =
11362 sp<FakeWindowHandle>::make(mApp, mDispatcher, "SpyWindow", ADISPLAY_ID_DEFAULT);
Vaibhav Devmurari6abcf8f2022-06-06 10:08:05 +000011363 mSpyWindow->setSpy(true);
11364 mSpyWindow->setTrustedOverlay(true);
11365 mSpyWindow->setFrame(Rect(0, 0, 200, 100));
11366
arthurhungb89ccb02020-12-30 16:19:01 +080011367 mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, mApp);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070011368 mDispatcher->onWindowInfosChanged(
11369 {{*mSpyWindow->getInfo(), *mWindow->getInfo(), *mSecondWindow->getInfo()},
11370 {},
11371 0,
11372 0});
arthurhungb89ccb02020-12-30 16:19:01 +080011373 }
11374
Arthur Hungb75c2aa2022-07-15 09:35:36 +000011375 void injectDown(int fromSource = AINPUT_SOURCE_TOUCHSCREEN) {
11376 switch (fromSource) {
11377 case AINPUT_SOURCE_TOUCHSCREEN:
11378 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070011379 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN,
Arthur Hungb75c2aa2022-07-15 09:35:36 +000011380 ADISPLAY_ID_DEFAULT, {50, 50}))
11381 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
11382 break;
11383 case AINPUT_SOURCE_STYLUS:
11384 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070011385 injectMotionEvent(*mDispatcher,
11386 MotionEventBuilder(AMOTION_EVENT_ACTION_DOWN,
11387 AINPUT_SOURCE_STYLUS)
11388 .buttonState(
11389 AMOTION_EVENT_BUTTON_STYLUS_PRIMARY)
11390 .pointer(PointerBuilder(0, ToolType::STYLUS)
11391 .x(50)
11392 .y(50))
11393 .build()));
Arthur Hungb75c2aa2022-07-15 09:35:36 +000011394 break;
11395 case AINPUT_SOURCE_MOUSE:
11396 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070011397 injectMotionEvent(*mDispatcher,
11398 MotionEventBuilder(AMOTION_EVENT_ACTION_DOWN,
11399 AINPUT_SOURCE_MOUSE)
11400 .buttonState(AMOTION_EVENT_BUTTON_PRIMARY)
11401 .pointer(PointerBuilder(MOUSE_POINTER_ID,
11402 ToolType::MOUSE)
11403 .x(50)
11404 .y(50))
11405 .build()));
Arthur Hungb75c2aa2022-07-15 09:35:36 +000011406 break;
11407 default:
11408 FAIL() << "Source " << fromSource << " doesn't support drag and drop";
11409 }
arthurhungb89ccb02020-12-30 16:19:01 +080011410
11411 // Window should receive motion event.
11412 mWindow->consumeMotionDown(ADISPLAY_ID_DEFAULT);
Vaibhav Devmurari6abcf8f2022-06-06 10:08:05 +000011413 // Spy window should also receive motion event
11414 mSpyWindow->consumeMotionDown(ADISPLAY_ID_DEFAULT);
Arthur Hung54745652022-04-20 07:17:41 +000011415 }
11416
11417 // Start performing drag, we will create a drag window and transfer touch to it.
11418 // @param sendDown : if true, send a motion down on first window before perform drag and drop.
11419 // Returns true on success.
Arthur Hungb75c2aa2022-07-15 09:35:36 +000011420 bool startDrag(bool sendDown = true, int fromSource = AINPUT_SOURCE_TOUCHSCREEN) {
Arthur Hung54745652022-04-20 07:17:41 +000011421 if (sendDown) {
Arthur Hungb75c2aa2022-07-15 09:35:36 +000011422 injectDown(fromSource);
Arthur Hung54745652022-04-20 07:17:41 +000011423 }
arthurhungb89ccb02020-12-30 16:19:01 +080011424
11425 // The drag window covers the entire display
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -070011426 mDragWindow =
11427 sp<FakeWindowHandle>::make(mApp, mDispatcher, "DragWindow", ADISPLAY_ID_DEFAULT);
Vaibhav Devmurari6abcf8f2022-06-06 10:08:05 +000011428 mDragWindow->setTouchableRegion(Region{{0, 0, 0, 0}});
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070011429 mDispatcher->onWindowInfosChanged({{*mDragWindow->getInfo(), *mSpyWindow->getInfo(),
11430 *mWindow->getInfo(), *mSecondWindow->getInfo()},
11431 {},
11432 0,
11433 0});
arthurhungb89ccb02020-12-30 16:19:01 +080011434
11435 // Transfer touch focus to the drag window
Arthur Hung54745652022-04-20 07:17:41 +000011436 bool transferred =
Prabir Pradhan367f3432024-02-13 23:05:58 +000011437 mDispatcher->transferTouchGesture(mWindow->getToken(), mDragWindow->getToken(),
11438 /*isDragDrop=*/true);
Arthur Hung54745652022-04-20 07:17:41 +000011439 if (transferred) {
11440 mWindow->consumeMotionCancel();
Prabir Pradhan65455c72024-02-13 21:46:41 +000011441 mDragWindow->consumeMotionDown(ADISPLAY_ID_DEFAULT, AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
Arthur Hung54745652022-04-20 07:17:41 +000011442 }
11443 return transferred;
arthurhungb89ccb02020-12-30 16:19:01 +080011444 }
11445};
11446
11447TEST_F(InputDispatcherDragTests, DragEnterAndDragExit) {
Arthur Hungb75c2aa2022-07-15 09:35:36 +000011448 startDrag();
arthurhungb89ccb02020-12-30 16:19:01 +080011449
11450 // Move on window.
11451 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070011452 injectMotionEvent(*mDispatcher, AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN,
arthurhungb89ccb02020-12-30 16:19:01 +080011453 ADISPLAY_ID_DEFAULT, {50, 50}))
11454 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
Prabir Pradhan65455c72024-02-13 21:46:41 +000011455 mDragWindow->consumeMotionMove(ADISPLAY_ID_DEFAULT, AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
arthurhungb89ccb02020-12-30 16:19:01 +080011456 mWindow->consumeDragEvent(false, 50, 50);
11457 mSecondWindow->assertNoEvents();
11458
11459 // Move to another window.
11460 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070011461 injectMotionEvent(*mDispatcher, AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN,
arthurhungb89ccb02020-12-30 16:19:01 +080011462 ADISPLAY_ID_DEFAULT, {150, 50}))
11463 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
Prabir Pradhan65455c72024-02-13 21:46:41 +000011464 mDragWindow->consumeMotionMove(ADISPLAY_ID_DEFAULT, AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
arthurhungb89ccb02020-12-30 16:19:01 +080011465 mWindow->consumeDragEvent(true, 150, 50);
11466 mSecondWindow->consumeDragEvent(false, 50, 50);
11467
11468 // Move back to original window.
11469 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070011470 injectMotionEvent(*mDispatcher, AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN,
arthurhungb89ccb02020-12-30 16:19:01 +080011471 ADISPLAY_ID_DEFAULT, {50, 50}))
11472 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
Prabir Pradhan65455c72024-02-13 21:46:41 +000011473 mDragWindow->consumeMotionMove(ADISPLAY_ID_DEFAULT, AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
arthurhungb89ccb02020-12-30 16:19:01 +080011474 mWindow->consumeDragEvent(false, 50, 50);
11475 mSecondWindow->consumeDragEvent(true, -50, 50);
11476
11477 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070011478 injectMotionUp(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
11479 {50, 50}))
arthurhungb89ccb02020-12-30 16:19:01 +080011480 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
Prabir Pradhan65455c72024-02-13 21:46:41 +000011481 mDragWindow->consumeMotionUp(ADISPLAY_ID_DEFAULT, AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
arthurhungb89ccb02020-12-30 16:19:01 +080011482 mWindow->assertNoEvents();
11483 mSecondWindow->assertNoEvents();
11484}
11485
Vaibhav Devmurari6abcf8f2022-06-06 10:08:05 +000011486TEST_F(InputDispatcherDragTests, DragEnterAndPointerDownPilfersPointers) {
Arthur Hungb75c2aa2022-07-15 09:35:36 +000011487 startDrag();
Vaibhav Devmurari6abcf8f2022-06-06 10:08:05 +000011488
11489 // No cancel event after drag start
11490 mSpyWindow->assertNoEvents();
11491
11492 const MotionEvent secondFingerDownEvent =
11493 MotionEventBuilder(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
11494 .eventTime(systemTime(SYSTEM_TIME_MONOTONIC))
Siarhei Vishniakou6d73f832022-07-21 17:27:03 -070011495 .pointer(PointerBuilder(/*id=*/0, ToolType::FINGER).x(50).y(50))
11496 .pointer(PointerBuilder(/*id=*/1, ToolType::FINGER).x(60).y(60))
Vaibhav Devmurari6abcf8f2022-06-06 10:08:05 +000011497 .build();
11498 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070011499 injectMotionEvent(*mDispatcher, secondFingerDownEvent, INJECT_EVENT_TIMEOUT,
Vaibhav Devmurari6abcf8f2022-06-06 10:08:05 +000011500 InputEventInjectionSync::WAIT_FOR_RESULT))
11501 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
11502
11503 // Receives cancel for first pointer after next pointer down
11504 mSpyWindow->consumeMotionCancel();
11505 mSpyWindow->consumeMotionDown();
11506
11507 mSpyWindow->assertNoEvents();
11508}
11509
arthurhungf452d0b2021-01-06 00:19:52 +080011510TEST_F(InputDispatcherDragTests, DragAndDrop) {
Arthur Hungb75c2aa2022-07-15 09:35:36 +000011511 startDrag();
arthurhungf452d0b2021-01-06 00:19:52 +080011512
11513 // Move on window.
11514 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070011515 injectMotionEvent(*mDispatcher, AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN,
arthurhungf452d0b2021-01-06 00:19:52 +080011516 ADISPLAY_ID_DEFAULT, {50, 50}))
11517 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
Prabir Pradhan65455c72024-02-13 21:46:41 +000011518 mDragWindow->consumeMotionMove(ADISPLAY_ID_DEFAULT, AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
arthurhungf452d0b2021-01-06 00:19:52 +080011519 mWindow->consumeDragEvent(false, 50, 50);
11520 mSecondWindow->assertNoEvents();
11521
11522 // Move to another window.
11523 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070011524 injectMotionEvent(*mDispatcher, AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN,
arthurhungf452d0b2021-01-06 00:19:52 +080011525 ADISPLAY_ID_DEFAULT, {150, 50}))
11526 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
Prabir Pradhan65455c72024-02-13 21:46:41 +000011527 mDragWindow->consumeMotionMove(ADISPLAY_ID_DEFAULT, AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
arthurhungf452d0b2021-01-06 00:19:52 +080011528 mWindow->consumeDragEvent(true, 150, 50);
11529 mSecondWindow->consumeDragEvent(false, 50, 50);
11530
11531 // drop to another window.
11532 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070011533 injectMotionUp(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
arthurhungf452d0b2021-01-06 00:19:52 +080011534 {150, 50}))
11535 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
Prabir Pradhan65455c72024-02-13 21:46:41 +000011536 mDragWindow->consumeMotionUp(ADISPLAY_ID_DEFAULT, AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
Siarhei Vishniakoua66d65e2023-06-16 10:32:51 -070011537 mFakePolicy->assertDropTargetEquals(*mDispatcher, mSecondWindow->getToken());
arthurhungf452d0b2021-01-06 00:19:52 +080011538 mWindow->assertNoEvents();
11539 mSecondWindow->assertNoEvents();
11540}
11541
Vaibhav Devmurari110ba322023-11-17 10:47:16 +000011542TEST_F(InputDispatcherDragTests, DragAndDropNotCancelledIfSomeOtherPointerIsPilfered) {
11543 startDrag();
11544
11545 // No cancel event after drag start
11546 mSpyWindow->assertNoEvents();
11547
11548 const MotionEvent secondFingerDownEvent =
11549 MotionEventBuilder(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
11550 .eventTime(systemTime(SYSTEM_TIME_MONOTONIC))
11551 .pointer(PointerBuilder(/*id=*/0, ToolType::FINGER).x(50).y(50))
11552 .pointer(PointerBuilder(/*id=*/1, ToolType::FINGER).x(60).y(60))
11553 .build();
11554 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
11555 injectMotionEvent(*mDispatcher, secondFingerDownEvent, INJECT_EVENT_TIMEOUT,
11556 InputEventInjectionSync::WAIT_FOR_RESULT))
11557 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
11558
11559 // Receives cancel for first pointer after next pointer down
11560 mSpyWindow->consumeMotionEvent(WithMotionAction(ACTION_CANCEL));
Siarhei Vishniakou1ff00cc2023-12-13 16:12:13 -080011561 mSpyWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithPointerIds({1})));
Vaibhav Devmurari110ba322023-11-17 10:47:16 +000011562 mDragWindow->consumeMotionEvent(WithMotionAction(ACTION_MOVE));
11563
11564 mSpyWindow->assertNoEvents();
11565
11566 // Spy window calls pilfer pointers
11567 EXPECT_EQ(OK, mDispatcher->pilferPointers(mSpyWindow->getToken()));
11568 mDragWindow->assertNoEvents();
11569
11570 const MotionEvent firstFingerMoveEvent =
Siarhei Vishniakou96a15572023-12-18 10:47:52 -080011571 MotionEventBuilder(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN)
Vaibhav Devmurari110ba322023-11-17 10:47:16 +000011572 .eventTime(systemTime(SYSTEM_TIME_MONOTONIC))
11573 .pointer(PointerBuilder(/*id=*/0, ToolType::FINGER).x(60).y(60))
11574 .pointer(PointerBuilder(/*id=*/1, ToolType::FINGER).x(60).y(60))
11575 .build();
11576 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakou96a15572023-12-18 10:47:52 -080011577 injectMotionEvent(*mDispatcher, firstFingerMoveEvent, INJECT_EVENT_TIMEOUT,
Vaibhav Devmurari110ba322023-11-17 10:47:16 +000011578 InputEventInjectionSync::WAIT_FOR_RESULT))
11579 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
11580
11581 // Drag window should still receive the new event
Prabir Pradhan65455c72024-02-13 21:46:41 +000011582 mDragWindow->consumeMotionEvent(
11583 AllOf(WithMotionAction(ACTION_MOVE), WithFlags(AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE)));
Vaibhav Devmurari110ba322023-11-17 10:47:16 +000011584 mDragWindow->assertNoEvents();
11585}
11586
arthurhung6d4bed92021-03-17 11:59:33 +080011587TEST_F(InputDispatcherDragTests, StylusDragAndDrop) {
Arthur Hungb75c2aa2022-07-15 09:35:36 +000011588 startDrag(true, AINPUT_SOURCE_STYLUS);
arthurhung6d4bed92021-03-17 11:59:33 +080011589
11590 // Move on window and keep button pressed.
11591 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070011592 injectMotionEvent(*mDispatcher,
arthurhung6d4bed92021-03-17 11:59:33 +080011593 MotionEventBuilder(AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_STYLUS)
11594 .buttonState(AMOTION_EVENT_BUTTON_STYLUS_PRIMARY)
Siarhei Vishniakou6d73f832022-07-21 17:27:03 -070011595 .pointer(PointerBuilder(0, ToolType::STYLUS).x(50).y(50))
arthurhung6d4bed92021-03-17 11:59:33 +080011596 .build()))
11597 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
Prabir Pradhan65455c72024-02-13 21:46:41 +000011598 mDragWindow->consumeMotionMove(ADISPLAY_ID_DEFAULT, AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
arthurhung6d4bed92021-03-17 11:59:33 +080011599 mWindow->consumeDragEvent(false, 50, 50);
11600 mSecondWindow->assertNoEvents();
11601
11602 // Move to another window and release button, expect to drop item.
11603 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070011604 injectMotionEvent(*mDispatcher,
arthurhung6d4bed92021-03-17 11:59:33 +080011605 MotionEventBuilder(AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_STYLUS)
11606 .buttonState(0)
Siarhei Vishniakou6d73f832022-07-21 17:27:03 -070011607 .pointer(PointerBuilder(0, ToolType::STYLUS).x(150).y(50))
arthurhung6d4bed92021-03-17 11:59:33 +080011608 .build()))
11609 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
Prabir Pradhan65455c72024-02-13 21:46:41 +000011610 mDragWindow->consumeMotionMove(ADISPLAY_ID_DEFAULT, AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
arthurhung6d4bed92021-03-17 11:59:33 +080011611 mWindow->assertNoEvents();
11612 mSecondWindow->assertNoEvents();
Siarhei Vishniakoua66d65e2023-06-16 10:32:51 -070011613 mFakePolicy->assertDropTargetEquals(*mDispatcher, mSecondWindow->getToken());
arthurhung6d4bed92021-03-17 11:59:33 +080011614
11615 // nothing to the window.
11616 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070011617 injectMotionEvent(*mDispatcher,
arthurhung6d4bed92021-03-17 11:59:33 +080011618 MotionEventBuilder(AMOTION_EVENT_ACTION_UP, AINPUT_SOURCE_STYLUS)
11619 .buttonState(0)
Siarhei Vishniakou6d73f832022-07-21 17:27:03 -070011620 .pointer(PointerBuilder(0, ToolType::STYLUS).x(150).y(50))
arthurhung6d4bed92021-03-17 11:59:33 +080011621 .build()))
11622 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
Prabir Pradhan65455c72024-02-13 21:46:41 +000011623 mDragWindow->consumeMotionUp(ADISPLAY_ID_DEFAULT, AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
arthurhung6d4bed92021-03-17 11:59:33 +080011624 mWindow->assertNoEvents();
11625 mSecondWindow->assertNoEvents();
11626}
11627
Arthur Hung54745652022-04-20 07:17:41 +000011628TEST_F(InputDispatcherDragTests, DragAndDropOnInvalidWindow) {
Arthur Hungb75c2aa2022-07-15 09:35:36 +000011629 startDrag();
Arthur Hung6d0571e2021-04-09 20:18:16 +080011630
11631 // Set second window invisible.
11632 mSecondWindow->setVisible(false);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070011633 mDispatcher->onWindowInfosChanged(
11634 {{*mDragWindow->getInfo(), *mWindow->getInfo(), *mSecondWindow->getInfo()}, {}, 0, 0});
Arthur Hung6d0571e2021-04-09 20:18:16 +080011635
11636 // Move on window.
11637 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070011638 injectMotionEvent(*mDispatcher, AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN,
Arthur Hung6d0571e2021-04-09 20:18:16 +080011639 ADISPLAY_ID_DEFAULT, {50, 50}))
11640 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
Prabir Pradhan65455c72024-02-13 21:46:41 +000011641 mDragWindow->consumeMotionMove(ADISPLAY_ID_DEFAULT, AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
Arthur Hung6d0571e2021-04-09 20:18:16 +080011642 mWindow->consumeDragEvent(false, 50, 50);
11643 mSecondWindow->assertNoEvents();
11644
11645 // Move to another window.
11646 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070011647 injectMotionEvent(*mDispatcher, AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN,
Arthur Hung6d0571e2021-04-09 20:18:16 +080011648 ADISPLAY_ID_DEFAULT, {150, 50}))
11649 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
Prabir Pradhan65455c72024-02-13 21:46:41 +000011650 mDragWindow->consumeMotionMove(ADISPLAY_ID_DEFAULT, AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
Arthur Hung6d0571e2021-04-09 20:18:16 +080011651 mWindow->consumeDragEvent(true, 150, 50);
11652 mSecondWindow->assertNoEvents();
11653
11654 // drop to another window.
11655 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070011656 injectMotionUp(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
Arthur Hung6d0571e2021-04-09 20:18:16 +080011657 {150, 50}))
11658 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
Prabir Pradhan65455c72024-02-13 21:46:41 +000011659 mDragWindow->consumeMotionUp(ADISPLAY_ID_DEFAULT, AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
Siarhei Vishniakoua66d65e2023-06-16 10:32:51 -070011660 mFakePolicy->assertDropTargetEquals(*mDispatcher, nullptr);
Arthur Hung6d0571e2021-04-09 20:18:16 +080011661 mWindow->assertNoEvents();
11662 mSecondWindow->assertNoEvents();
11663}
11664
Arthur Hung54745652022-04-20 07:17:41 +000011665TEST_F(InputDispatcherDragTests, NoDragAndDropWhenMultiFingers) {
Arthur Hungb75c2aa2022-07-15 09:35:36 +000011666 // Ensure window could track pointerIds if it didn't support split touch.
11667 mWindow->setPreventSplitting(true);
11668
Arthur Hung54745652022-04-20 07:17:41 +000011669 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070011670 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
Arthur Hung54745652022-04-20 07:17:41 +000011671 {50, 50}))
11672 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
11673 mWindow->consumeMotionDown(ADISPLAY_ID_DEFAULT);
11674
11675 const MotionEvent secondFingerDownEvent =
11676 MotionEventBuilder(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
11677 .displayId(ADISPLAY_ID_DEFAULT)
11678 .eventTime(systemTime(SYSTEM_TIME_MONOTONIC))
Siarhei Vishniakou6d73f832022-07-21 17:27:03 -070011679 .pointer(PointerBuilder(/*id=*/0, ToolType::FINGER).x(50).y(50))
11680 .pointer(PointerBuilder(/*id=*/1, ToolType::FINGER).x(75).y(50))
Arthur Hung54745652022-04-20 07:17:41 +000011681 .build();
11682 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070011683 injectMotionEvent(*mDispatcher, secondFingerDownEvent, INJECT_EVENT_TIMEOUT,
Arthur Hung54745652022-04-20 07:17:41 +000011684 InputEventInjectionSync::WAIT_FOR_RESULT))
11685 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
Harry Cutts33476232023-01-30 19:57:29 +000011686 mWindow->consumeMotionPointerDown(/*pointerIndex=*/1);
Arthur Hung54745652022-04-20 07:17:41 +000011687
11688 // Should not perform drag and drop when window has multi fingers.
Arthur Hungb75c2aa2022-07-15 09:35:36 +000011689 ASSERT_FALSE(startDrag(false));
Arthur Hung54745652022-04-20 07:17:41 +000011690}
11691
11692TEST_F(InputDispatcherDragTests, DragAndDropWhenSplitTouch) {
11693 // First down on second window.
11694 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070011695 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
Arthur Hung54745652022-04-20 07:17:41 +000011696 {150, 50}))
11697 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
11698
11699 mSecondWindow->consumeMotionDown(ADISPLAY_ID_DEFAULT);
11700
11701 // Second down on first window.
11702 const MotionEvent secondFingerDownEvent =
11703 MotionEventBuilder(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
11704 .displayId(ADISPLAY_ID_DEFAULT)
11705 .eventTime(systemTime(SYSTEM_TIME_MONOTONIC))
Siarhei Vishniakou6d73f832022-07-21 17:27:03 -070011706 .pointer(PointerBuilder(/*id=*/0, ToolType::FINGER).x(150).y(50))
11707 .pointer(PointerBuilder(/*id=*/1, ToolType::FINGER).x(50).y(50))
Arthur Hung54745652022-04-20 07:17:41 +000011708 .build();
11709 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070011710 injectMotionEvent(*mDispatcher, secondFingerDownEvent, INJECT_EVENT_TIMEOUT,
Arthur Hung54745652022-04-20 07:17:41 +000011711 InputEventInjectionSync::WAIT_FOR_RESULT))
11712 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
11713 mWindow->consumeMotionDown(ADISPLAY_ID_DEFAULT);
Prabir Pradhan9d5f9ce2024-01-24 00:03:41 +000011714 mSecondWindow->consumeMotionMove(ADISPLAY_ID_DEFAULT);
Arthur Hung54745652022-04-20 07:17:41 +000011715
11716 // Perform drag and drop from first window.
Arthur Hungb75c2aa2022-07-15 09:35:36 +000011717 ASSERT_TRUE(startDrag(false));
Arthur Hung54745652022-04-20 07:17:41 +000011718
11719 // Move on window.
11720 const MotionEvent secondFingerMoveEvent =
11721 MotionEventBuilder(AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN)
11722 .eventTime(systemTime(SYSTEM_TIME_MONOTONIC))
Siarhei Vishniakou6d73f832022-07-21 17:27:03 -070011723 .pointer(PointerBuilder(/*id=*/0, ToolType::FINGER).x(150).y(50))
11724 .pointer(PointerBuilder(/*id=*/1, ToolType::FINGER).x(50).y(50))
Arthur Hung54745652022-04-20 07:17:41 +000011725 .build();
11726 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070011727 injectMotionEvent(*mDispatcher, secondFingerMoveEvent, INJECT_EVENT_TIMEOUT,
Arthur Hung54745652022-04-20 07:17:41 +000011728 InputEventInjectionSync::WAIT_FOR_RESULT));
Prabir Pradhan65455c72024-02-13 21:46:41 +000011729 mDragWindow->consumeMotionMove(ADISPLAY_ID_DEFAULT, AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
Arthur Hung54745652022-04-20 07:17:41 +000011730 mWindow->consumeDragEvent(false, 50, 50);
11731 mSecondWindow->consumeMotionMove();
11732
11733 // Release the drag pointer should perform drop.
11734 const MotionEvent secondFingerUpEvent =
11735 MotionEventBuilder(POINTER_1_UP, AINPUT_SOURCE_TOUCHSCREEN)
11736 .eventTime(systemTime(SYSTEM_TIME_MONOTONIC))
Siarhei Vishniakou6d73f832022-07-21 17:27:03 -070011737 .pointer(PointerBuilder(/*id=*/0, ToolType::FINGER).x(150).y(50))
11738 .pointer(PointerBuilder(/*id=*/1, ToolType::FINGER).x(50).y(50))
Arthur Hung54745652022-04-20 07:17:41 +000011739 .build();
11740 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070011741 injectMotionEvent(*mDispatcher, secondFingerUpEvent, INJECT_EVENT_TIMEOUT,
Arthur Hung54745652022-04-20 07:17:41 +000011742 InputEventInjectionSync::WAIT_FOR_RESULT));
Prabir Pradhan65455c72024-02-13 21:46:41 +000011743 mDragWindow->consumeMotionUp(ADISPLAY_ID_DEFAULT, AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
Siarhei Vishniakoua66d65e2023-06-16 10:32:51 -070011744 mFakePolicy->assertDropTargetEquals(*mDispatcher, mWindow->getToken());
Arthur Hung54745652022-04-20 07:17:41 +000011745 mWindow->assertNoEvents();
11746 mSecondWindow->consumeMotionMove();
11747}
11748
Arthur Hung3915c1f2022-05-31 07:17:17 +000011749TEST_F(InputDispatcherDragTests, DragAndDropWhenMultiDisplays) {
Arthur Hungb75c2aa2022-07-15 09:35:36 +000011750 startDrag();
Arthur Hung3915c1f2022-05-31 07:17:17 +000011751
11752 // Update window of second display.
11753 sp<FakeWindowHandle> windowInSecondary =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -070011754 sp<FakeWindowHandle>::make(mApp, mDispatcher, "D_2", SECOND_DISPLAY_ID);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070011755 mDispatcher->onWindowInfosChanged(
11756 {{*mDragWindow->getInfo(), *mSpyWindow->getInfo(), *mWindow->getInfo(),
11757 *mSecondWindow->getInfo(), *windowInSecondary->getInfo()},
11758 {},
11759 0,
11760 0});
Arthur Hung3915c1f2022-05-31 07:17:17 +000011761
11762 // Let second display has a touch state.
11763 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070011764 injectMotionEvent(*mDispatcher,
Arthur Hung3915c1f2022-05-31 07:17:17 +000011765 MotionEventBuilder(AMOTION_EVENT_ACTION_DOWN,
11766 AINPUT_SOURCE_TOUCHSCREEN)
11767 .displayId(SECOND_DISPLAY_ID)
Siarhei Vishniakou6d73f832022-07-21 17:27:03 -070011768 .pointer(PointerBuilder(0, ToolType::FINGER).x(100).y(100))
Arthur Hung3915c1f2022-05-31 07:17:17 +000011769 .build()));
Prabir Pradhan7662a8d2023-12-15 01:58:14 +000011770 windowInSecondary->consumeMotionDown(SECOND_DISPLAY_ID, /*expectedFlag=*/0);
Arthur Hung3915c1f2022-05-31 07:17:17 +000011771 // Update window again.
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070011772 mDispatcher->onWindowInfosChanged(
11773 {{*mDragWindow->getInfo(), *mSpyWindow->getInfo(), *mWindow->getInfo(),
11774 *mSecondWindow->getInfo(), *windowInSecondary->getInfo()},
11775 {},
11776 0,
11777 0});
Arthur Hung3915c1f2022-05-31 07:17:17 +000011778
11779 // Move on window.
11780 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070011781 injectMotionEvent(*mDispatcher, AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN,
Arthur Hung3915c1f2022-05-31 07:17:17 +000011782 ADISPLAY_ID_DEFAULT, {50, 50}))
11783 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
Prabir Pradhan65455c72024-02-13 21:46:41 +000011784 mDragWindow->consumeMotionMove(ADISPLAY_ID_DEFAULT, AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
Arthur Hung3915c1f2022-05-31 07:17:17 +000011785 mWindow->consumeDragEvent(false, 50, 50);
11786 mSecondWindow->assertNoEvents();
11787
11788 // Move to another window.
11789 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070011790 injectMotionEvent(*mDispatcher, AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN,
Arthur Hung3915c1f2022-05-31 07:17:17 +000011791 ADISPLAY_ID_DEFAULT, {150, 50}))
11792 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
Prabir Pradhan65455c72024-02-13 21:46:41 +000011793 mDragWindow->consumeMotionMove(ADISPLAY_ID_DEFAULT, AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
Arthur Hung3915c1f2022-05-31 07:17:17 +000011794 mWindow->consumeDragEvent(true, 150, 50);
11795 mSecondWindow->consumeDragEvent(false, 50, 50);
11796
11797 // drop to another window.
11798 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070011799 injectMotionUp(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
Arthur Hung3915c1f2022-05-31 07:17:17 +000011800 {150, 50}))
11801 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
Prabir Pradhan65455c72024-02-13 21:46:41 +000011802 mDragWindow->consumeMotionUp(ADISPLAY_ID_DEFAULT, AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
Siarhei Vishniakoua66d65e2023-06-16 10:32:51 -070011803 mFakePolicy->assertDropTargetEquals(*mDispatcher, mSecondWindow->getToken());
Arthur Hung3915c1f2022-05-31 07:17:17 +000011804 mWindow->assertNoEvents();
11805 mSecondWindow->assertNoEvents();
11806}
11807
Arthur Hungb75c2aa2022-07-15 09:35:36 +000011808TEST_F(InputDispatcherDragTests, MouseDragAndDrop) {
11809 startDrag(true, AINPUT_SOURCE_MOUSE);
11810 // Move on window.
11811 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070011812 injectMotionEvent(*mDispatcher,
Arthur Hungb75c2aa2022-07-15 09:35:36 +000011813 MotionEventBuilder(AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_MOUSE)
11814 .buttonState(AMOTION_EVENT_BUTTON_PRIMARY)
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070011815 .pointer(PointerBuilder(MOUSE_POINTER_ID, ToolType::MOUSE)
Arthur Hungb75c2aa2022-07-15 09:35:36 +000011816 .x(50)
11817 .y(50))
11818 .build()))
11819 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
Prabir Pradhan65455c72024-02-13 21:46:41 +000011820 mDragWindow->consumeMotionMove(ADISPLAY_ID_DEFAULT, AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
Arthur Hungb75c2aa2022-07-15 09:35:36 +000011821 mWindow->consumeDragEvent(false, 50, 50);
11822 mSecondWindow->assertNoEvents();
11823
11824 // Move to another window.
11825 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070011826 injectMotionEvent(*mDispatcher,
Arthur Hungb75c2aa2022-07-15 09:35:36 +000011827 MotionEventBuilder(AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_MOUSE)
11828 .buttonState(AMOTION_EVENT_BUTTON_PRIMARY)
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070011829 .pointer(PointerBuilder(MOUSE_POINTER_ID, ToolType::MOUSE)
Arthur Hungb75c2aa2022-07-15 09:35:36 +000011830 .x(150)
11831 .y(50))
11832 .build()))
11833 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
Prabir Pradhan65455c72024-02-13 21:46:41 +000011834 mDragWindow->consumeMotionMove(ADISPLAY_ID_DEFAULT, AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
Arthur Hungb75c2aa2022-07-15 09:35:36 +000011835 mWindow->consumeDragEvent(true, 150, 50);
11836 mSecondWindow->consumeDragEvent(false, 50, 50);
11837
11838 // drop to another window.
11839 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070011840 injectMotionEvent(*mDispatcher,
Arthur Hungb75c2aa2022-07-15 09:35:36 +000011841 MotionEventBuilder(AMOTION_EVENT_ACTION_UP, AINPUT_SOURCE_MOUSE)
11842 .buttonState(0)
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070011843 .pointer(PointerBuilder(MOUSE_POINTER_ID, ToolType::MOUSE)
Arthur Hungb75c2aa2022-07-15 09:35:36 +000011844 .x(150)
11845 .y(50))
11846 .build()))
11847 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
Prabir Pradhan65455c72024-02-13 21:46:41 +000011848 mDragWindow->consumeMotionUp(ADISPLAY_ID_DEFAULT, AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
Siarhei Vishniakoua66d65e2023-06-16 10:32:51 -070011849 mFakePolicy->assertDropTargetEquals(*mDispatcher, mSecondWindow->getToken());
Arthur Hungb75c2aa2022-07-15 09:35:36 +000011850 mWindow->assertNoEvents();
11851 mSecondWindow->assertNoEvents();
11852}
11853
Linnan Li5af92f92023-07-14 14:36:22 +080011854/**
11855 * Start drag and drop with a pointer whose id is not 0, cancel the current touch, and ensure drag
11856 * and drop is also canceled. Then inject a simple gesture, and ensure dispatcher does not crash.
11857 */
11858TEST_F(InputDispatcherDragTests, DragAndDropFinishedWhenCancelCurrentTouch) {
11859 // Down on second window
11860 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
11861 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
11862 {150, 50}))
11863 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
11864
11865 ASSERT_NO_FATAL_FAILURE(mSecondWindow->consumeMotionDown());
11866 ASSERT_NO_FATAL_FAILURE(mSpyWindow->consumeMotionDown());
11867
11868 // Down on first window
11869 const MotionEvent secondFingerDownEvent =
11870 MotionEventBuilder(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
11871 .displayId(ADISPLAY_ID_DEFAULT)
11872 .pointer(PointerBuilder(/*id=*/0, ToolType::FINGER).x(150).y(50))
11873 .pointer(PointerBuilder(/*id=*/1, ToolType::FINGER).x(50).y(50))
11874 .build();
11875 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
11876 injectMotionEvent(*mDispatcher, secondFingerDownEvent, INJECT_EVENT_TIMEOUT,
11877 InputEventInjectionSync::WAIT_FOR_RESULT))
11878 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
11879 ASSERT_NO_FATAL_FAILURE(mWindow->consumeMotionDown());
11880 ASSERT_NO_FATAL_FAILURE(mSecondWindow->consumeMotionMove());
11881 ASSERT_NO_FATAL_FAILURE(mSpyWindow->consumeMotionPointerDown(1));
11882
11883 // Start drag on first window
11884 ASSERT_TRUE(startDrag(/*sendDown=*/false, AINPUT_SOURCE_TOUCHSCREEN));
11885
11886 // Trigger cancel
11887 mDispatcher->cancelCurrentTouch();
11888 ASSERT_NO_FATAL_FAILURE(mSecondWindow->consumeMotionCancel());
Prabir Pradhan65455c72024-02-13 21:46:41 +000011889 ASSERT_NO_FATAL_FAILURE(mDragWindow->consumeMotionCancel(ADISPLAY_ID_DEFAULT,
11890 AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE));
Linnan Li5af92f92023-07-14 14:36:22 +080011891 ASSERT_NO_FATAL_FAILURE(mSpyWindow->consumeMotionCancel());
11892
11893 ASSERT_TRUE(mDispatcher->waitForIdle());
11894 // The D&D finished with nullptr
11895 mFakePolicy->assertDropTargetEquals(*mDispatcher, nullptr);
11896
11897 // Remove drag window
11898 mDispatcher->onWindowInfosChanged({{*mWindow->getInfo(), *mSecondWindow->getInfo()}, {}, 0, 0});
11899
11900 // Inject a simple gesture, ensure dispatcher not crashed
11901 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
11902 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
11903 PointF{50, 50}))
11904 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
11905 ASSERT_NO_FATAL_FAILURE(mWindow->consumeMotionDown());
11906
11907 const MotionEvent moveEvent =
11908 MotionEventBuilder(AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN)
11909 .displayId(ADISPLAY_ID_DEFAULT)
11910 .pointer(PointerBuilder(/*id=*/0, ToolType::FINGER).x(50).y(50))
11911 .build();
11912 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
11913 injectMotionEvent(*mDispatcher, moveEvent, INJECT_EVENT_TIMEOUT,
11914 InputEventInjectionSync::WAIT_FOR_RESULT))
11915 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
11916 ASSERT_NO_FATAL_FAILURE(mWindow->consumeMotionMove());
11917
11918 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
11919 injectMotionUp(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
11920 {50, 50}))
11921 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
11922 ASSERT_NO_FATAL_FAILURE(mWindow->consumeMotionUp());
11923}
11924
Prabir Pradhan9cd9eb62023-11-22 17:58:06 +000011925TEST_F(InputDispatcherDragTests, NoDragAndDropWithHoveringPointer) {
11926 // Start hovering over the window.
11927 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
11928 injectMotionEvent(*mDispatcher, ACTION_HOVER_ENTER, AINPUT_SOURCE_MOUSE,
11929 ADISPLAY_ID_DEFAULT, {50, 50}));
11930
11931 ASSERT_NO_FATAL_FAILURE(mWindow->consumeMotionEvent(WithMotionAction(ACTION_HOVER_ENTER)));
11932 ASSERT_NO_FATAL_FAILURE(mSpyWindow->consumeMotionEvent(WithMotionAction(ACTION_HOVER_ENTER)));
11933
11934 ASSERT_FALSE(startDrag(/*sendDown=*/false))
11935 << "Drag and drop should not work with a hovering pointer";
11936}
11937
Vishnu Nair062a8672021-09-03 16:07:44 -070011938class InputDispatcherDropInputFeatureTest : public InputDispatcherTest {};
11939
11940TEST_F(InputDispatcherDropInputFeatureTest, WindowDropsInput) {
11941 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -070011942 sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher,
11943 "Test window", ADISPLAY_ID_DEFAULT);
Prabir Pradhan51e7db02022-02-07 06:02:57 -080011944 window->setDropInput(true);
Vishnu Nair062a8672021-09-03 16:07:44 -070011945 mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application);
11946 window->setFocusable(true);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070011947 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Vishnu Nair062a8672021-09-03 16:07:44 -070011948 setFocusedWindow(window);
Harry Cutts33476232023-01-30 19:57:29 +000011949 window->consumeFocusEvent(/*hasFocus=*/true, /*inTouchMode=*/true);
Vishnu Nair062a8672021-09-03 16:07:44 -070011950
11951 // With the flag set, window should not get any input
Prabir Pradhan678438e2023-04-13 19:32:51 +000011952 mDispatcher->notifyKey(generateKeyArgs(AKEY_EVENT_ACTION_DOWN, ADISPLAY_ID_DEFAULT));
Vishnu Nair062a8672021-09-03 16:07:44 -070011953 window->assertNoEvents();
11954
Prabir Pradhan678438e2023-04-13 19:32:51 +000011955 mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_DOWN,
11956 AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT));
Siarhei Vishniakou5c02a712023-05-15 15:45:02 -070011957 mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN,
11958 ADISPLAY_ID_DEFAULT));
Siarhei Vishniakoud908f5a2023-11-16 10:25:12 -080011959 mDispatcher->waitForIdle();
Vishnu Nair062a8672021-09-03 16:07:44 -070011960 window->assertNoEvents();
11961
11962 // With the flag cleared, the window should get input
Prabir Pradhan51e7db02022-02-07 06:02:57 -080011963 window->setDropInput(false);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070011964 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Vishnu Nair062a8672021-09-03 16:07:44 -070011965
Prabir Pradhan678438e2023-04-13 19:32:51 +000011966 mDispatcher->notifyKey(generateKeyArgs(AKEY_EVENT_ACTION_UP, ADISPLAY_ID_DEFAULT));
Vishnu Nair062a8672021-09-03 16:07:44 -070011967 window->consumeKeyUp(ADISPLAY_ID_DEFAULT);
11968
Prabir Pradhan678438e2023-04-13 19:32:51 +000011969 mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_DOWN,
11970 AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT));
Vishnu Nair062a8672021-09-03 16:07:44 -070011971 window->consumeMotionDown(ADISPLAY_ID_DEFAULT);
11972 window->assertNoEvents();
11973}
11974
11975TEST_F(InputDispatcherDropInputFeatureTest, ObscuredWindowDropsInput) {
11976 std::shared_ptr<FakeApplicationHandle> obscuringApplication =
11977 std::make_shared<FakeApplicationHandle>();
11978 sp<FakeWindowHandle> obscuringWindow =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -070011979 sp<FakeWindowHandle>::make(obscuringApplication, mDispatcher, "obscuringWindow",
11980 ADISPLAY_ID_DEFAULT);
Vishnu Nair062a8672021-09-03 16:07:44 -070011981 obscuringWindow->setFrame(Rect(0, 0, 50, 50));
Prabir Pradhanaeebeb42023-06-13 19:53:03 +000011982 obscuringWindow->setOwnerInfo(gui::Pid{111}, gui::Uid{111});
Prabir Pradhan4d5c52f2022-01-31 08:52:10 -080011983 obscuringWindow->setTouchable(false);
Vishnu Nair062a8672021-09-03 16:07:44 -070011984 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -070011985 sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher,
11986 "Test window", ADISPLAY_ID_DEFAULT);
Prabir Pradhan51e7db02022-02-07 06:02:57 -080011987 window->setDropInputIfObscured(true);
Prabir Pradhanaeebeb42023-06-13 19:53:03 +000011988 window->setOwnerInfo(gui::Pid{222}, gui::Uid{222});
Vishnu Nair062a8672021-09-03 16:07:44 -070011989 mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application);
11990 window->setFocusable(true);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070011991 mDispatcher->onWindowInfosChanged(
11992 {{*obscuringWindow->getInfo(), *window->getInfo()}, {}, 0, 0});
Vishnu Nair062a8672021-09-03 16:07:44 -070011993 setFocusedWindow(window);
Harry Cutts33476232023-01-30 19:57:29 +000011994 window->consumeFocusEvent(/*hasFocus=*/true, /*inTouchMode=*/true);
Vishnu Nair062a8672021-09-03 16:07:44 -070011995
11996 // With the flag set, window should not get any input
Prabir Pradhan678438e2023-04-13 19:32:51 +000011997 mDispatcher->notifyKey(generateKeyArgs(AKEY_EVENT_ACTION_DOWN, ADISPLAY_ID_DEFAULT));
Vishnu Nair062a8672021-09-03 16:07:44 -070011998 window->assertNoEvents();
11999
Prabir Pradhan678438e2023-04-13 19:32:51 +000012000 mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_DOWN,
12001 AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT));
Siarhei Vishniakou5c02a712023-05-15 15:45:02 -070012002 mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN,
12003 ADISPLAY_ID_DEFAULT));
Vishnu Nair062a8672021-09-03 16:07:44 -070012004 window->assertNoEvents();
12005
12006 // With the flag cleared, the window should get input
Prabir Pradhan51e7db02022-02-07 06:02:57 -080012007 window->setDropInputIfObscured(false);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070012008 mDispatcher->onWindowInfosChanged(
12009 {{*obscuringWindow->getInfo(), *window->getInfo()}, {}, 0, 0});
Vishnu Nair062a8672021-09-03 16:07:44 -070012010
Prabir Pradhan678438e2023-04-13 19:32:51 +000012011 mDispatcher->notifyKey(generateKeyArgs(AKEY_EVENT_ACTION_UP, ADISPLAY_ID_DEFAULT));
Vishnu Nair062a8672021-09-03 16:07:44 -070012012 window->consumeKeyUp(ADISPLAY_ID_DEFAULT);
12013
Prabir Pradhan678438e2023-04-13 19:32:51 +000012014 mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_DOWN,
12015 AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT));
Vishnu Nair062a8672021-09-03 16:07:44 -070012016 window->consumeMotionDown(ADISPLAY_ID_DEFAULT, AMOTION_EVENT_FLAG_WINDOW_IS_PARTIALLY_OBSCURED);
12017 window->assertNoEvents();
12018}
12019
12020TEST_F(InputDispatcherDropInputFeatureTest, UnobscuredWindowGetsInput) {
12021 std::shared_ptr<FakeApplicationHandle> obscuringApplication =
12022 std::make_shared<FakeApplicationHandle>();
12023 sp<FakeWindowHandle> obscuringWindow =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -070012024 sp<FakeWindowHandle>::make(obscuringApplication, mDispatcher, "obscuringWindow",
12025 ADISPLAY_ID_DEFAULT);
Vishnu Nair062a8672021-09-03 16:07:44 -070012026 obscuringWindow->setFrame(Rect(0, 0, 50, 50));
Prabir Pradhanaeebeb42023-06-13 19:53:03 +000012027 obscuringWindow->setOwnerInfo(gui::Pid{111}, gui::Uid{111});
Prabir Pradhan4d5c52f2022-01-31 08:52:10 -080012028 obscuringWindow->setTouchable(false);
Vishnu Nair062a8672021-09-03 16:07:44 -070012029 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -070012030 sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher,
12031 "Test window", ADISPLAY_ID_DEFAULT);
Prabir Pradhan51e7db02022-02-07 06:02:57 -080012032 window->setDropInputIfObscured(true);
Prabir Pradhanaeebeb42023-06-13 19:53:03 +000012033 window->setOwnerInfo(gui::Pid{222}, gui::Uid{222});
Vishnu Nair062a8672021-09-03 16:07:44 -070012034 mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application);
12035 window->setFocusable(true);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070012036 mDispatcher->onWindowInfosChanged(
12037 {{*obscuringWindow->getInfo(), *window->getInfo()}, {}, 0, 0});
Vishnu Nair062a8672021-09-03 16:07:44 -070012038 setFocusedWindow(window);
Harry Cutts33476232023-01-30 19:57:29 +000012039 window->consumeFocusEvent(/*hasFocus=*/true, /*inTouchMode=*/true);
Vishnu Nair062a8672021-09-03 16:07:44 -070012040
12041 // With the flag set, window should not get any input
Prabir Pradhan678438e2023-04-13 19:32:51 +000012042 mDispatcher->notifyKey(generateKeyArgs(AKEY_EVENT_ACTION_DOWN, ADISPLAY_ID_DEFAULT));
Vishnu Nair062a8672021-09-03 16:07:44 -070012043 window->assertNoEvents();
12044
Prabir Pradhan678438e2023-04-13 19:32:51 +000012045 mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_DOWN,
12046 AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT));
Siarhei Vishniakou5c02a712023-05-15 15:45:02 -070012047 mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN,
12048 ADISPLAY_ID_DEFAULT));
Vishnu Nair062a8672021-09-03 16:07:44 -070012049 window->assertNoEvents();
12050
12051 // When the window is no longer obscured because it went on top, it should get input
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070012052 mDispatcher->onWindowInfosChanged(
12053 {{*window->getInfo(), *obscuringWindow->getInfo()}, {}, 0, 0});
Vishnu Nair062a8672021-09-03 16:07:44 -070012054
Prabir Pradhan678438e2023-04-13 19:32:51 +000012055 mDispatcher->notifyKey(generateKeyArgs(AKEY_EVENT_ACTION_UP, ADISPLAY_ID_DEFAULT));
Vishnu Nair062a8672021-09-03 16:07:44 -070012056 window->consumeKeyUp(ADISPLAY_ID_DEFAULT);
12057
Prabir Pradhan678438e2023-04-13 19:32:51 +000012058 mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_DOWN,
12059 AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT));
Vishnu Nair062a8672021-09-03 16:07:44 -070012060 window->consumeMotionDown(ADISPLAY_ID_DEFAULT);
12061 window->assertNoEvents();
12062}
12063
Antonio Kantekf16f2832021-09-28 04:39:20 +000012064class InputDispatcherTouchModeChangedTests : public InputDispatcherTest {
12065protected:
12066 std::shared_ptr<FakeApplicationHandle> mApp;
Antonio Kantek15beb512022-06-13 22:35:41 +000012067 std::shared_ptr<FakeApplicationHandle> mSecondaryApp;
Antonio Kantekf16f2832021-09-28 04:39:20 +000012068 sp<FakeWindowHandle> mWindow;
12069 sp<FakeWindowHandle> mSecondWindow;
Antonio Kantek15beb512022-06-13 22:35:41 +000012070 sp<FakeWindowHandle> mThirdWindow;
Antonio Kantekf16f2832021-09-28 04:39:20 +000012071
12072 void SetUp() override {
12073 InputDispatcherTest::SetUp();
12074
12075 mApp = std::make_shared<FakeApplicationHandle>();
Antonio Kantek15beb512022-06-13 22:35:41 +000012076 mSecondaryApp = std::make_shared<FakeApplicationHandle>();
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -070012077 mWindow = sp<FakeWindowHandle>::make(mApp, mDispatcher, "TestWindow", ADISPLAY_ID_DEFAULT);
Antonio Kantekf16f2832021-09-28 04:39:20 +000012078 mWindow->setFocusable(true);
Antonio Kantek26defcf2022-02-08 01:12:27 +000012079 setFocusedWindow(mWindow);
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -070012080 mSecondWindow =
12081 sp<FakeWindowHandle>::make(mApp, mDispatcher, "TestWindow2", ADISPLAY_ID_DEFAULT);
Antonio Kantekf16f2832021-09-28 04:39:20 +000012082 mSecondWindow->setFocusable(true);
Antonio Kantek15beb512022-06-13 22:35:41 +000012083 mThirdWindow =
12084 sp<FakeWindowHandle>::make(mSecondaryApp, mDispatcher,
12085 "TestWindow3_SecondaryDisplay", SECOND_DISPLAY_ID);
12086 mThirdWindow->setFocusable(true);
Antonio Kantekf16f2832021-09-28 04:39:20 +000012087
12088 mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, mApp);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070012089 mDispatcher->onWindowInfosChanged(
12090 {{*mWindow->getInfo(), *mSecondWindow->getInfo(), *mThirdWindow->getInfo()},
12091 {},
12092 0,
12093 0});
Antonio Kantek15beb512022-06-13 22:35:41 +000012094 mThirdWindow->setOwnerInfo(SECONDARY_WINDOW_PID, SECONDARY_WINDOW_UID);
Antonio Kantekf16f2832021-09-28 04:39:20 +000012095 mWindow->consumeFocusEvent(true);
Antonio Kantek26defcf2022-02-08 01:12:27 +000012096
Antonio Kantek15beb512022-06-13 22:35:41 +000012097 // Set main display initial touch mode to InputDispatcher::kDefaultInTouchMode.
Prabir Pradhan5735a322022-04-11 17:23:34 +000012098 if (mDispatcher->setInTouchMode(InputDispatcher::kDefaultInTouchMode, WINDOW_PID,
Harry Cutts33476232023-01-30 19:57:29 +000012099 WINDOW_UID, /*hasPermission=*/true, ADISPLAY_ID_DEFAULT)) {
Antonio Kantek48710e42022-03-24 14:19:30 -070012100 mWindow->consumeTouchModeEvent(InputDispatcher::kDefaultInTouchMode);
12101 mSecondWindow->consumeTouchModeEvent(InputDispatcher::kDefaultInTouchMode);
Antonio Kantek15beb512022-06-13 22:35:41 +000012102 mThirdWindow->assertNoEvents();
12103 }
12104
12105 // Set secondary display initial touch mode to InputDispatcher::kDefaultInTouchMode.
12106 if (mDispatcher->setInTouchMode(InputDispatcher::kDefaultInTouchMode, SECONDARY_WINDOW_PID,
Harry Cutts33476232023-01-30 19:57:29 +000012107 SECONDARY_WINDOW_UID, /*hasPermission=*/true,
Antonio Kantek15beb512022-06-13 22:35:41 +000012108 SECOND_DISPLAY_ID)) {
12109 mWindow->assertNoEvents();
12110 mSecondWindow->assertNoEvents();
12111 mThirdWindow->consumeTouchModeEvent(InputDispatcher::kDefaultInTouchMode);
Antonio Kantek48710e42022-03-24 14:19:30 -070012112 }
Antonio Kantekf16f2832021-09-28 04:39:20 +000012113 }
12114
Prabir Pradhanaeebeb42023-06-13 19:53:03 +000012115 void changeAndVerifyTouchModeInMainDisplayOnly(bool inTouchMode, gui::Pid pid, gui::Uid uid,
Antonio Kantek15beb512022-06-13 22:35:41 +000012116 bool hasPermission) {
Antonio Kanteka042c022022-07-06 16:51:07 -070012117 ASSERT_TRUE(mDispatcher->setInTouchMode(inTouchMode, pid, uid, hasPermission,
12118 ADISPLAY_ID_DEFAULT));
Antonio Kantekf16f2832021-09-28 04:39:20 +000012119 mWindow->consumeTouchModeEvent(inTouchMode);
12120 mSecondWindow->consumeTouchModeEvent(inTouchMode);
Antonio Kantek15beb512022-06-13 22:35:41 +000012121 mThirdWindow->assertNoEvents();
Antonio Kantekf16f2832021-09-28 04:39:20 +000012122 }
12123};
12124
Antonio Kantek26defcf2022-02-08 01:12:27 +000012125TEST_F(InputDispatcherTouchModeChangedTests, FocusedWindowCanChangeTouchMode) {
Antonio Kantekea47acb2021-12-23 12:41:25 -080012126 const WindowInfo& windowInfo = *mWindow->getInfo();
Antonio Kantek15beb512022-06-13 22:35:41 +000012127 changeAndVerifyTouchModeInMainDisplayOnly(!InputDispatcher::kDefaultInTouchMode,
12128 windowInfo.ownerPid, windowInfo.ownerUid,
Harry Cutts33476232023-01-30 19:57:29 +000012129 /* hasPermission=*/false);
Antonio Kantekf16f2832021-09-28 04:39:20 +000012130}
12131
Antonio Kantek26defcf2022-02-08 01:12:27 +000012132TEST_F(InputDispatcherTouchModeChangedTests, NonFocusedWindowOwnerCannotChangeTouchMode) {
12133 const WindowInfo& windowInfo = *mWindow->getInfo();
Prabir Pradhanaeebeb42023-06-13 19:53:03 +000012134 gui::Pid ownerPid = windowInfo.ownerPid;
Prabir Pradhan8a5c41d2023-06-08 19:13:46 +000012135 gui::Uid ownerUid = windowInfo.ownerUid;
Prabir Pradhanaeebeb42023-06-13 19:53:03 +000012136 mWindow->setOwnerInfo(gui::Pid::INVALID, gui::Uid::INVALID);
Antonio Kantek26defcf2022-02-08 01:12:27 +000012137 ASSERT_FALSE(mDispatcher->setInTouchMode(InputDispatcher::kDefaultInTouchMode, ownerPid,
Harry Cutts33476232023-01-30 19:57:29 +000012138 ownerUid, /*hasPermission=*/false,
Antonio Kanteka042c022022-07-06 16:51:07 -070012139 ADISPLAY_ID_DEFAULT));
Antonio Kantek26defcf2022-02-08 01:12:27 +000012140 mWindow->assertNoEvents();
12141 mSecondWindow->assertNoEvents();
12142}
12143
12144TEST_F(InputDispatcherTouchModeChangedTests, NonWindowOwnerMayChangeTouchModeOnPermissionGranted) {
12145 const WindowInfo& windowInfo = *mWindow->getInfo();
Prabir Pradhanaeebeb42023-06-13 19:53:03 +000012146 gui::Pid ownerPid = windowInfo.ownerPid;
Prabir Pradhan8a5c41d2023-06-08 19:13:46 +000012147 gui::Uid ownerUid = windowInfo.ownerUid;
Prabir Pradhanaeebeb42023-06-13 19:53:03 +000012148 mWindow->setOwnerInfo(gui::Pid::INVALID, gui::Uid::INVALID);
Antonio Kantek15beb512022-06-13 22:35:41 +000012149 changeAndVerifyTouchModeInMainDisplayOnly(!InputDispatcher::kDefaultInTouchMode, ownerPid,
Harry Cutts33476232023-01-30 19:57:29 +000012150 ownerUid, /*hasPermission=*/true);
Antonio Kantek26defcf2022-02-08 01:12:27 +000012151}
12152
Antonio Kantekf16f2832021-09-28 04:39:20 +000012153TEST_F(InputDispatcherTouchModeChangedTests, EventIsNotGeneratedIfNotChangingTouchMode) {
Antonio Kantekea47acb2021-12-23 12:41:25 -080012154 const WindowInfo& windowInfo = *mWindow->getInfo();
Antonio Kantek26defcf2022-02-08 01:12:27 +000012155 ASSERT_FALSE(mDispatcher->setInTouchMode(InputDispatcher::kDefaultInTouchMode,
12156 windowInfo.ownerPid, windowInfo.ownerUid,
Harry Cutts33476232023-01-30 19:57:29 +000012157 /*hasPermission=*/true, ADISPLAY_ID_DEFAULT));
Antonio Kantekf16f2832021-09-28 04:39:20 +000012158 mWindow->assertNoEvents();
12159 mSecondWindow->assertNoEvents();
12160}
12161
Antonio Kantek15beb512022-06-13 22:35:41 +000012162TEST_F(InputDispatcherTouchModeChangedTests, ChangeTouchOnSecondaryDisplayOnly) {
12163 const WindowInfo& windowInfo = *mThirdWindow->getInfo();
12164 ASSERT_TRUE(mDispatcher->setInTouchMode(!InputDispatcher::kDefaultInTouchMode,
12165 windowInfo.ownerPid, windowInfo.ownerUid,
Harry Cutts33476232023-01-30 19:57:29 +000012166 /*hasPermission=*/true, SECOND_DISPLAY_ID));
Antonio Kantek15beb512022-06-13 22:35:41 +000012167 mWindow->assertNoEvents();
12168 mSecondWindow->assertNoEvents();
12169 mThirdWindow->consumeTouchModeEvent(!InputDispatcher::kDefaultInTouchMode);
12170}
12171
Antonio Kantek48710e42022-03-24 14:19:30 -070012172TEST_F(InputDispatcherTouchModeChangedTests, CanChangeTouchModeWhenOwningLastInteractedWindow) {
12173 // Interact with the window first.
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070012174 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
12175 injectKeyDown(*mDispatcher, ADISPLAY_ID_DEFAULT))
Antonio Kantek48710e42022-03-24 14:19:30 -070012176 << "Inject key event should return InputEventInjectionResult::SUCCEEDED";
12177 mWindow->consumeKeyDown(ADISPLAY_ID_DEFAULT);
12178
12179 // Then remove focus.
12180 mWindow->setFocusable(false);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070012181 mDispatcher->onWindowInfosChanged({{*mWindow->getInfo()}, {}, 0, 0});
Antonio Kantek48710e42022-03-24 14:19:30 -070012182
12183 // Assert that caller can switch touch mode by owning one of the last interacted window.
12184 const WindowInfo& windowInfo = *mWindow->getInfo();
12185 ASSERT_TRUE(mDispatcher->setInTouchMode(!InputDispatcher::kDefaultInTouchMode,
12186 windowInfo.ownerPid, windowInfo.ownerUid,
Harry Cutts33476232023-01-30 19:57:29 +000012187 /*hasPermission=*/false, ADISPLAY_ID_DEFAULT));
Antonio Kantek48710e42022-03-24 14:19:30 -070012188}
12189
Prabir Pradhan07e05b62021-11-19 03:57:24 -080012190class InputDispatcherSpyWindowTest : public InputDispatcherTest {
12191public:
Prabir Pradhan4d5c52f2022-01-31 08:52:10 -080012192 sp<FakeWindowHandle> createSpy() {
Prabir Pradhan07e05b62021-11-19 03:57:24 -080012193 std::shared_ptr<FakeApplicationHandle> application =
12194 std::make_shared<FakeApplicationHandle>();
12195 std::string name = "Fake Spy ";
12196 name += std::to_string(mSpyCount++);
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -070012197 sp<FakeWindowHandle> spy = sp<FakeWindowHandle>::make(application, mDispatcher,
12198 name.c_str(), ADISPLAY_ID_DEFAULT);
Prabir Pradhan51e7db02022-02-07 06:02:57 -080012199 spy->setSpy(true);
Prabir Pradhan5c85e052021-12-22 02:27:12 -080012200 spy->setTrustedOverlay(true);
Prabir Pradhan07e05b62021-11-19 03:57:24 -080012201 return spy;
12202 }
12203
12204 sp<FakeWindowHandle> createForeground() {
12205 std::shared_ptr<FakeApplicationHandle> application =
12206 std::make_shared<FakeApplicationHandle>();
12207 sp<FakeWindowHandle> window =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -070012208 sp<FakeWindowHandle>::make(application, mDispatcher, "Fake Window",
12209 ADISPLAY_ID_DEFAULT);
Prabir Pradhan1376fcd2022-01-21 09:56:35 -080012210 window->setFocusable(true);
Prabir Pradhan07e05b62021-11-19 03:57:24 -080012211 return window;
12212 }
12213
12214private:
12215 int mSpyCount{0};
12216};
12217
Prabir Pradhana3ab87a2022-01-27 10:00:21 -080012218using InputDispatcherSpyWindowDeathTest = InputDispatcherSpyWindowTest;
Prabir Pradhan07e05b62021-11-19 03:57:24 -080012219/**
Prabir Pradhan5c85e052021-12-22 02:27:12 -080012220 * Adding a spy window that is not a trusted overlay causes Dispatcher to abort.
12221 */
Prabir Pradhana3ab87a2022-01-27 10:00:21 -080012222TEST_F(InputDispatcherSpyWindowDeathTest, UntrustedSpy_AbortsDispatcher) {
Siarhei Vishniakou21f77bd2023-07-18 17:51:35 -070012223 testing::GTEST_FLAG(death_test_style) = "threadsafe";
Prabir Pradhana3ab87a2022-01-27 10:00:21 -080012224 ScopedSilentDeath _silentDeath;
12225
Prabir Pradhan4d5c52f2022-01-31 08:52:10 -080012226 auto spy = createSpy();
Prabir Pradhan5c85e052021-12-22 02:27:12 -080012227 spy->setTrustedOverlay(false);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070012228 ASSERT_DEATH(mDispatcher->onWindowInfosChanged({{*spy->getInfo()}, {}, 0, 0}),
Prabir Pradhan5c85e052021-12-22 02:27:12 -080012229 ".* not a trusted overlay");
12230}
12231
12232/**
Prabir Pradhan07e05b62021-11-19 03:57:24 -080012233 * Input injection into a display with a spy window but no foreground windows should succeed.
12234 */
12235TEST_F(InputDispatcherSpyWindowTest, NoForegroundWindow) {
Prabir Pradhan4d5c52f2022-01-31 08:52:10 -080012236 auto spy = createSpy();
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070012237 mDispatcher->onWindowInfosChanged({{*spy->getInfo()}, {}, 0, 0});
Prabir Pradhan07e05b62021-11-19 03:57:24 -080012238
12239 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070012240 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT))
Prabir Pradhan07e05b62021-11-19 03:57:24 -080012241 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
12242 spy->consumeMotionDown(ADISPLAY_ID_DEFAULT);
12243}
12244
12245/**
12246 * Verify the order in which different input windows receive events. The touched foreground window
12247 * (if there is one) should always receive the event first. When there are multiple spy windows, the
12248 * spy windows will receive the event according to their Z-order, where the top-most spy window will
12249 * receive events before ones belows it.
12250 *
12251 * Here, we set up a scenario with four windows in the following Z order from the top:
12252 * spy1, spy2, window, spy3.
12253 * We then inject an event and verify that the foreground "window" receives it first, followed by
12254 * "spy1" and "spy2". The "spy3" does not receive the event because it is underneath the foreground
12255 * window.
12256 */
12257TEST_F(InputDispatcherSpyWindowTest, ReceivesInputInOrder) {
12258 auto window = createForeground();
Prabir Pradhan4d5c52f2022-01-31 08:52:10 -080012259 auto spy1 = createSpy();
12260 auto spy2 = createSpy();
12261 auto spy3 = createSpy();
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070012262 mDispatcher->onWindowInfosChanged(
12263 {{*spy1->getInfo(), *spy2->getInfo(), *window->getInfo(), *spy3->getInfo()}, {}, 0, 0});
Prabir Pradhan07e05b62021-11-19 03:57:24 -080012264 const std::vector<sp<FakeWindowHandle>> channels{spy1, spy2, window, spy3};
12265 const size_t numChannels = channels.size();
12266
Michael Wright8e9a8562022-02-09 13:44:29 +000012267 base::unique_fd epollFd(epoll_create1(EPOLL_CLOEXEC));
Prabir Pradhan07e05b62021-11-19 03:57:24 -080012268 if (!epollFd.ok()) {
12269 FAIL() << "Failed to create epoll fd";
12270 }
12271
12272 for (size_t i = 0; i < numChannels; i++) {
12273 struct epoll_event event = {.events = EPOLLIN, .data.u64 = i};
12274 if (epoll_ctl(epollFd.get(), EPOLL_CTL_ADD, channels[i]->getChannelFd(), &event) < 0) {
12275 FAIL() << "Failed to add fd to epoll";
12276 }
12277 }
12278
12279 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070012280 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT))
Prabir Pradhan07e05b62021-11-19 03:57:24 -080012281 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
12282
12283 std::vector<size_t> eventOrder;
12284 std::vector<struct epoll_event> events(numChannels);
12285 for (;;) {
12286 const int nFds = epoll_wait(epollFd.get(), events.data(), static_cast<int>(numChannels),
12287 (100ms).count());
12288 if (nFds < 0) {
12289 FAIL() << "Failed to call epoll_wait";
12290 }
12291 if (nFds == 0) {
12292 break; // epoll_wait timed out
12293 }
12294 for (int i = 0; i < nFds; i++) {
Colin Cross5b799302022-10-18 21:52:41 -070012295 ASSERT_EQ(static_cast<uint32_t>(EPOLLIN), events[i].events);
Siarhei Vishniakou31977182022-09-30 08:51:23 -070012296 eventOrder.push_back(static_cast<size_t>(events[i].data.u64));
Prabir Pradhan07e05b62021-11-19 03:57:24 -080012297 channels[i]->consumeMotionDown();
12298 }
12299 }
12300
12301 // Verify the order in which the events were received.
12302 EXPECT_EQ(3u, eventOrder.size());
12303 EXPECT_EQ(2u, eventOrder[0]); // index 2: window
12304 EXPECT_EQ(0u, eventOrder[1]); // index 0: spy1
12305 EXPECT_EQ(1u, eventOrder[2]); // index 1: spy2
12306}
12307
12308/**
12309 * A spy window using the NOT_TOUCHABLE flag does not receive events.
12310 */
12311TEST_F(InputDispatcherSpyWindowTest, NotTouchable) {
12312 auto window = createForeground();
Prabir Pradhan4d5c52f2022-01-31 08:52:10 -080012313 auto spy = createSpy();
12314 spy->setTouchable(false);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070012315 mDispatcher->onWindowInfosChanged({{*spy->getInfo(), *window->getInfo()}, {}, 0, 0});
Prabir Pradhan07e05b62021-11-19 03:57:24 -080012316
12317 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070012318 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT))
Prabir Pradhan07e05b62021-11-19 03:57:24 -080012319 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
12320 window->consumeMotionDown(ADISPLAY_ID_DEFAULT);
12321 spy->assertNoEvents();
12322}
12323
12324/**
12325 * A spy window will only receive gestures that originate within its touchable region. Gestures that
12326 * have their ACTION_DOWN outside of the touchable region of the spy window will not be dispatched
12327 * to the window.
12328 */
12329TEST_F(InputDispatcherSpyWindowTest, TouchableRegion) {
12330 auto window = createForeground();
Prabir Pradhan4d5c52f2022-01-31 08:52:10 -080012331 auto spy = createSpy();
Prabir Pradhan07e05b62021-11-19 03:57:24 -080012332 spy->setTouchableRegion(Region{{0, 0, 20, 20}});
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070012333 mDispatcher->onWindowInfosChanged({{*spy->getInfo(), *window->getInfo()}, {}, 0, 0});
Prabir Pradhan07e05b62021-11-19 03:57:24 -080012334
12335 // Inject an event outside the spy window's touchable region.
12336 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070012337 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT))
Prabir Pradhan07e05b62021-11-19 03:57:24 -080012338 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
12339 window->consumeMotionDown();
12340 spy->assertNoEvents();
12341 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070012342 injectMotionUp(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT))
Prabir Pradhan07e05b62021-11-19 03:57:24 -080012343 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
12344 window->consumeMotionUp();
12345 spy->assertNoEvents();
12346
12347 // Inject an event inside the spy window's touchable region.
12348 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070012349 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
Prabir Pradhan07e05b62021-11-19 03:57:24 -080012350 {5, 10}))
12351 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
12352 window->consumeMotionDown();
12353 spy->consumeMotionDown();
12354}
12355
12356/**
Prabir Pradhan07e05b62021-11-19 03:57:24 -080012357 * A spy window can listen for touches outside its touchable region using the WATCH_OUTSIDE_TOUCHES
Prabir Pradhandfabf8a2022-01-21 08:19:30 -080012358 * flag, but it will get zero-ed out coordinates if the foreground has a different owner.
Prabir Pradhan07e05b62021-11-19 03:57:24 -080012359 */
12360TEST_F(InputDispatcherSpyWindowTest, WatchOutsideTouches) {
12361 auto window = createForeground();
Prabir Pradhanaeebeb42023-06-13 19:53:03 +000012362 window->setOwnerInfo(gui::Pid{12}, gui::Uid{34});
Prabir Pradhan4d5c52f2022-01-31 08:52:10 -080012363 auto spy = createSpy();
12364 spy->setWatchOutsideTouch(true);
Prabir Pradhanaeebeb42023-06-13 19:53:03 +000012365 spy->setOwnerInfo(gui::Pid{56}, gui::Uid{78});
Prabir Pradhan07e05b62021-11-19 03:57:24 -080012366 spy->setFrame(Rect{0, 0, 20, 20});
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070012367 mDispatcher->onWindowInfosChanged({{*spy->getInfo(), *window->getInfo()}, {}, 0, 0});
Prabir Pradhan07e05b62021-11-19 03:57:24 -080012368
12369 // Inject an event outside the spy window's frame and touchable region.
12370 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070012371 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
Prabir Pradhandfabf8a2022-01-21 08:19:30 -080012372 {100, 200}))
Prabir Pradhan07e05b62021-11-19 03:57:24 -080012373 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
12374 window->consumeMotionDown();
Prabir Pradhandfabf8a2022-01-21 08:19:30 -080012375 spy->consumeMotionOutsideWithZeroedCoords();
Prabir Pradhan07e05b62021-11-19 03:57:24 -080012376}
12377
12378/**
Prabir Pradhan07e05b62021-11-19 03:57:24 -080012379 * Even when a spy window spans over multiple foreground windows, the spy should receive all
12380 * pointers that are down within its bounds.
12381 */
12382TEST_F(InputDispatcherSpyWindowTest, ReceivesMultiplePointers) {
12383 auto windowLeft = createForeground();
12384 windowLeft->setFrame({0, 0, 100, 200});
12385 auto windowRight = createForeground();
12386 windowRight->setFrame({100, 0, 200, 200});
Prabir Pradhan4d5c52f2022-01-31 08:52:10 -080012387 auto spy = createSpy();
Prabir Pradhan07e05b62021-11-19 03:57:24 -080012388 spy->setFrame({0, 0, 200, 200});
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070012389 mDispatcher->onWindowInfosChanged(
12390 {{*spy->getInfo(), *windowLeft->getInfo(), *windowRight->getInfo()}, {}, 0, 0});
Prabir Pradhan07e05b62021-11-19 03:57:24 -080012391
12392 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070012393 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
Prabir Pradhan07e05b62021-11-19 03:57:24 -080012394 {50, 50}))
12395 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
12396 windowLeft->consumeMotionDown();
12397 spy->consumeMotionDown();
12398
12399 const MotionEvent secondFingerDownEvent =
Siarhei Vishniakoua16e3a22022-03-02 15:26:40 -080012400 MotionEventBuilder(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
Prabir Pradhan07e05b62021-11-19 03:57:24 -080012401 .eventTime(systemTime(SYSTEM_TIME_MONOTONIC))
Siarhei Vishniakou6d73f832022-07-21 17:27:03 -070012402 .pointer(PointerBuilder(/*id=*/0, ToolType::FINGER).x(50).y(50))
12403 .pointer(PointerBuilder(/*id=*/1, ToolType::FINGER).x(150).y(50))
Prabir Pradhan07e05b62021-11-19 03:57:24 -080012404 .build();
12405 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070012406 injectMotionEvent(*mDispatcher, secondFingerDownEvent, INJECT_EVENT_TIMEOUT,
Prabir Pradhan07e05b62021-11-19 03:57:24 -080012407 InputEventInjectionSync::WAIT_FOR_RESULT))
12408 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
12409 windowRight->consumeMotionDown();
Harry Cutts33476232023-01-30 19:57:29 +000012410 spy->consumeMotionPointerDown(/*pointerIndex=*/1);
Prabir Pradhan07e05b62021-11-19 03:57:24 -080012411}
12412
12413/**
12414 * When the first pointer lands outside the spy window and the second pointer lands inside it, the
12415 * the spy should receive the second pointer with ACTION_DOWN.
12416 */
12417TEST_F(InputDispatcherSpyWindowTest, ReceivesSecondPointerAsDown) {
12418 auto window = createForeground();
12419 window->setFrame({0, 0, 200, 200});
Prabir Pradhan4d5c52f2022-01-31 08:52:10 -080012420 auto spyRight = createSpy();
Prabir Pradhan07e05b62021-11-19 03:57:24 -080012421 spyRight->setFrame({100, 0, 200, 200});
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070012422 mDispatcher->onWindowInfosChanged({{*spyRight->getInfo(), *window->getInfo()}, {}, 0, 0});
Prabir Pradhan07e05b62021-11-19 03:57:24 -080012423
12424 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070012425 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
Prabir Pradhan07e05b62021-11-19 03:57:24 -080012426 {50, 50}))
12427 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
12428 window->consumeMotionDown();
12429 spyRight->assertNoEvents();
12430
12431 const MotionEvent secondFingerDownEvent =
Siarhei Vishniakoua16e3a22022-03-02 15:26:40 -080012432 MotionEventBuilder(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
Prabir Pradhan07e05b62021-11-19 03:57:24 -080012433 .eventTime(systemTime(SYSTEM_TIME_MONOTONIC))
Siarhei Vishniakou6d73f832022-07-21 17:27:03 -070012434 .pointer(PointerBuilder(/*id=*/0, ToolType::FINGER).x(50).y(50))
12435 .pointer(PointerBuilder(/*id=*/1, ToolType::FINGER).x(150).y(50))
Prabir Pradhan07e05b62021-11-19 03:57:24 -080012436 .build();
12437 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070012438 injectMotionEvent(*mDispatcher, secondFingerDownEvent, INJECT_EVENT_TIMEOUT,
Prabir Pradhan07e05b62021-11-19 03:57:24 -080012439 InputEventInjectionSync::WAIT_FOR_RESULT))
12440 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
Harry Cutts33476232023-01-30 19:57:29 +000012441 window->consumeMotionPointerDown(/*pointerIndex=*/1);
Prabir Pradhan07e05b62021-11-19 03:57:24 -080012442 spyRight->consumeMotionDown();
12443}
12444
Prabir Pradhan1376fcd2022-01-21 09:56:35 -080012445/**
12446 * The spy window should not be able to affect whether or not touches are split. Only the foreground
12447 * windows should be allowed to control split touch.
12448 */
12449TEST_F(InputDispatcherSpyWindowTest, SplitIfNoForegroundWindowTouched) {
Prabir Pradhan76bdecb2022-01-31 11:14:15 -080012450 // This spy window prevents touch splitting. However, we still expect to split touches
Prabir Pradhan1376fcd2022-01-21 09:56:35 -080012451 // because a foreground window has not disabled splitting.
Prabir Pradhan4d5c52f2022-01-31 08:52:10 -080012452 auto spy = createSpy();
Prabir Pradhan76bdecb2022-01-31 11:14:15 -080012453 spy->setPreventSplitting(true);
Prabir Pradhan1376fcd2022-01-21 09:56:35 -080012454
Prabir Pradhan1376fcd2022-01-21 09:56:35 -080012455 auto window = createForeground();
12456 window->setFrame(Rect(0, 0, 100, 100));
Prabir Pradhan1376fcd2022-01-21 09:56:35 -080012457
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070012458 mDispatcher->onWindowInfosChanged({{*spy->getInfo(), *window->getInfo()}, {}, 0, 0});
Prabir Pradhan1376fcd2022-01-21 09:56:35 -080012459
12460 // First finger down, no window touched.
12461 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070012462 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
Prabir Pradhan1376fcd2022-01-21 09:56:35 -080012463 {100, 200}))
12464 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
12465 spy->consumeMotionDown(ADISPLAY_ID_DEFAULT);
12466 window->assertNoEvents();
12467
12468 // Second finger down on window, the window should receive touch down.
12469 const MotionEvent secondFingerDownEvent =
Siarhei Vishniakoua16e3a22022-03-02 15:26:40 -080012470 MotionEventBuilder(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
Prabir Pradhan1376fcd2022-01-21 09:56:35 -080012471 .displayId(ADISPLAY_ID_DEFAULT)
12472 .eventTime(systemTime(SYSTEM_TIME_MONOTONIC))
Siarhei Vishniakou6d73f832022-07-21 17:27:03 -070012473 .pointer(PointerBuilder(/*id=*/0, ToolType::FINGER).x(100).y(200))
12474 .pointer(PointerBuilder(/*id=*/1, ToolType::FINGER).x(50).y(50))
Prabir Pradhan1376fcd2022-01-21 09:56:35 -080012475 .build();
12476 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070012477 injectMotionEvent(*mDispatcher, secondFingerDownEvent, INJECT_EVENT_TIMEOUT,
Prabir Pradhan1376fcd2022-01-21 09:56:35 -080012478 InputEventInjectionSync::WAIT_FOR_RESULT))
12479 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
12480
12481 window->consumeMotionDown(ADISPLAY_ID_DEFAULT);
Harry Cutts33476232023-01-30 19:57:29 +000012482 spy->consumeMotionPointerDown(/*pointerIndex=*/1);
Prabir Pradhan1376fcd2022-01-21 09:56:35 -080012483}
12484
12485/**
12486 * A spy window will usually be implemented as an un-focusable window. Verify that these windows
12487 * do not receive key events.
12488 */
12489TEST_F(InputDispatcherSpyWindowTest, UnfocusableSpyDoesNotReceiveKeyEvents) {
Prabir Pradhan4d5c52f2022-01-31 08:52:10 -080012490 auto spy = createSpy();
Prabir Pradhan1376fcd2022-01-21 09:56:35 -080012491 spy->setFocusable(false);
12492
12493 auto window = createForeground();
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070012494 mDispatcher->onWindowInfosChanged({{*spy->getInfo(), *window->getInfo()}, {}, 0, 0});
Prabir Pradhan1376fcd2022-01-21 09:56:35 -080012495 setFocusedWindow(window);
12496 window->consumeFocusEvent(true);
12497
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070012498 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectKeyDown(*mDispatcher))
Prabir Pradhan1376fcd2022-01-21 09:56:35 -080012499 << "Inject key event should return InputEventInjectionResult::SUCCEEDED";
Linnan Li13bf76a2024-05-05 19:18:02 +080012500 window->consumeKeyDown(ui::ADISPLAY_ID_NONE);
Prabir Pradhan1376fcd2022-01-21 09:56:35 -080012501
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070012502 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectKeyUp(*mDispatcher))
Prabir Pradhan1376fcd2022-01-21 09:56:35 -080012503 << "Inject key event should return InputEventInjectionResult::SUCCEEDED";
Linnan Li13bf76a2024-05-05 19:18:02 +080012504 window->consumeKeyUp(ui::ADISPLAY_ID_NONE);
Prabir Pradhan1376fcd2022-01-21 09:56:35 -080012505
12506 spy->assertNoEvents();
12507}
12508
Vaibhav Devmurariff798f32022-05-09 23:45:04 +000012509using InputDispatcherPilferPointersTest = InputDispatcherSpyWindowTest;
12510
12511/**
12512 * A spy window can pilfer pointers. When this happens, touch gestures used by the spy window that
12513 * are currently sent to any other windows - including other spy windows - will also be cancelled.
12514 */
12515TEST_F(InputDispatcherPilferPointersTest, PilferPointers) {
12516 auto window = createForeground();
12517 auto spy1 = createSpy();
12518 auto spy2 = createSpy();
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070012519 mDispatcher->onWindowInfosChanged(
12520 {{*spy1->getInfo(), *spy2->getInfo(), *window->getInfo()}, {}, 0, 0});
Vaibhav Devmurariff798f32022-05-09 23:45:04 +000012521
12522 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070012523 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT))
Vaibhav Devmurariff798f32022-05-09 23:45:04 +000012524 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
12525 window->consumeMotionDown();
12526 spy1->consumeMotionDown();
12527 spy2->consumeMotionDown();
12528
12529 // Pilfer pointers from the second spy window.
12530 EXPECT_EQ(OK, mDispatcher->pilferPointers(spy2->getToken()));
12531 spy2->assertNoEvents();
12532 spy1->consumeMotionCancel();
12533 window->consumeMotionCancel();
12534
12535 // The rest of the gesture should only be sent to the second spy window.
12536 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070012537 injectMotionEvent(*mDispatcher, AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN,
Vaibhav Devmurariff798f32022-05-09 23:45:04 +000012538 ADISPLAY_ID_DEFAULT))
12539 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
12540 spy2->consumeMotionMove();
12541 spy1->assertNoEvents();
12542 window->assertNoEvents();
12543}
12544
12545/**
12546 * A spy window can pilfer pointers for a gesture even after the foreground window has been removed
12547 * in the middle of the gesture.
12548 */
12549TEST_F(InputDispatcherPilferPointersTest, CanPilferAfterWindowIsRemovedMidStream) {
12550 auto window = createForeground();
12551 auto spy = createSpy();
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070012552 mDispatcher->onWindowInfosChanged({{*spy->getInfo(), *window->getInfo()}, {}, 0, 0});
Vaibhav Devmurariff798f32022-05-09 23:45:04 +000012553
12554 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070012555 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT))
Vaibhav Devmurariff798f32022-05-09 23:45:04 +000012556 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
12557 window->consumeMotionDown(ADISPLAY_ID_DEFAULT);
12558 spy->consumeMotionDown(ADISPLAY_ID_DEFAULT);
12559
12560 window->releaseChannel();
12561
12562 EXPECT_EQ(OK, mDispatcher->pilferPointers(spy->getToken()));
12563
12564 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070012565 injectMotionUp(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT))
Vaibhav Devmurariff798f32022-05-09 23:45:04 +000012566 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
12567 spy->consumeMotionUp(ADISPLAY_ID_DEFAULT);
12568}
12569
12570/**
12571 * After a spy window pilfers pointers, new pointers that go down in its bounds should be sent to
12572 * the spy, but not to any other windows.
12573 */
12574TEST_F(InputDispatcherPilferPointersTest, ContinuesToReceiveGestureAfterPilfer) {
12575 auto spy = createSpy();
12576 auto window = createForeground();
12577
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070012578 mDispatcher->onWindowInfosChanged({{*spy->getInfo(), *window->getInfo()}, {}, 0, 0});
Vaibhav Devmurariff798f32022-05-09 23:45:04 +000012579
12580 // First finger down on the window and the spy.
12581 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070012582 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
Vaibhav Devmurariff798f32022-05-09 23:45:04 +000012583 {100, 200}))
12584 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
12585 spy->consumeMotionDown();
12586 window->consumeMotionDown();
12587
12588 // Spy window pilfers the pointers.
12589 EXPECT_EQ(OK, mDispatcher->pilferPointers(spy->getToken()));
12590 window->consumeMotionCancel();
12591
12592 // Second finger down on the window and spy, but the window should not receive the pointer down.
12593 const MotionEvent secondFingerDownEvent =
12594 MotionEventBuilder(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
12595 .displayId(ADISPLAY_ID_DEFAULT)
12596 .eventTime(systemTime(SYSTEM_TIME_MONOTONIC))
Siarhei Vishniakou6d73f832022-07-21 17:27:03 -070012597 .pointer(PointerBuilder(/*id=*/0, ToolType::FINGER).x(100).y(200))
12598 .pointer(PointerBuilder(/*id=*/1, ToolType::FINGER).x(50).y(50))
Vaibhav Devmurariff798f32022-05-09 23:45:04 +000012599 .build();
12600 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070012601 injectMotionEvent(*mDispatcher, secondFingerDownEvent, INJECT_EVENT_TIMEOUT,
Vaibhav Devmurariff798f32022-05-09 23:45:04 +000012602 InputEventInjectionSync::WAIT_FOR_RESULT))
12603 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
12604
Harry Cutts33476232023-01-30 19:57:29 +000012605 spy->consumeMotionPointerDown(/*pointerIndex=*/1);
Vaibhav Devmurariff798f32022-05-09 23:45:04 +000012606
12607 // Third finger goes down outside all windows, so injection should fail.
12608 const MotionEvent thirdFingerDownEvent =
12609 MotionEventBuilder(POINTER_2_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
12610 .displayId(ADISPLAY_ID_DEFAULT)
12611 .eventTime(systemTime(SYSTEM_TIME_MONOTONIC))
Siarhei Vishniakou6d73f832022-07-21 17:27:03 -070012612 .pointer(PointerBuilder(/*id=*/0, ToolType::FINGER).x(100).y(200))
12613 .pointer(PointerBuilder(/*id=*/1, ToolType::FINGER).x(50).y(50))
12614 .pointer(PointerBuilder(/*id=*/2, ToolType::FINGER).x(-5).y(-5))
Vaibhav Devmurariff798f32022-05-09 23:45:04 +000012615 .build();
12616 ASSERT_EQ(InputEventInjectionResult::FAILED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070012617 injectMotionEvent(*mDispatcher, thirdFingerDownEvent, INJECT_EVENT_TIMEOUT,
Vaibhav Devmurariff798f32022-05-09 23:45:04 +000012618 InputEventInjectionSync::WAIT_FOR_RESULT))
Siarhei Vishniakou1ae72f12023-01-29 12:55:30 -080012619 << "Inject motion event should return InputEventInjectionResult::FAILED";
Vaibhav Devmurariff798f32022-05-09 23:45:04 +000012620
12621 spy->assertNoEvents();
12622 window->assertNoEvents();
12623}
12624
12625/**
12626 * After a spy window pilfers pointers, only the pointers used by the spy should be canceled
12627 */
12628TEST_F(InputDispatcherPilferPointersTest, PartiallyPilferRequiredPointers) {
12629 auto spy = createSpy();
12630 spy->setFrame(Rect(0, 0, 100, 100));
12631 auto window = createForeground();
12632 window->setFrame(Rect(0, 0, 200, 200));
12633
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070012634 mDispatcher->onWindowInfosChanged({{*spy->getInfo(), *window->getInfo()}, {}, 0, 0});
Vaibhav Devmurariff798f32022-05-09 23:45:04 +000012635
12636 // First finger down on the window only
12637 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070012638 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
Vaibhav Devmurariff798f32022-05-09 23:45:04 +000012639 {150, 150}))
12640 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
12641 window->consumeMotionDown();
12642
12643 // Second finger down on the spy and window
12644 const MotionEvent secondFingerDownEvent =
12645 MotionEventBuilder(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
12646 .displayId(ADISPLAY_ID_DEFAULT)
12647 .eventTime(systemTime(SYSTEM_TIME_MONOTONIC))
Siarhei Vishniakou6d73f832022-07-21 17:27:03 -070012648 .pointer(PointerBuilder(/*id=*/0, ToolType::FINGER).x(150).y(150))
12649 .pointer(PointerBuilder(/*id=*/1, ToolType::FINGER).x(10).y(10))
Vaibhav Devmurariff798f32022-05-09 23:45:04 +000012650 .build();
12651 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070012652 injectMotionEvent(*mDispatcher, secondFingerDownEvent, INJECT_EVENT_TIMEOUT,
Vaibhav Devmurariff798f32022-05-09 23:45:04 +000012653 InputEventInjectionSync::WAIT_FOR_RESULT))
12654 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
12655 spy->consumeMotionDown();
12656 window->consumeMotionPointerDown(1);
12657
12658 // Third finger down on the spy and window
12659 const MotionEvent thirdFingerDownEvent =
12660 MotionEventBuilder(POINTER_2_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
12661 .displayId(ADISPLAY_ID_DEFAULT)
12662 .eventTime(systemTime(SYSTEM_TIME_MONOTONIC))
Siarhei Vishniakou6d73f832022-07-21 17:27:03 -070012663 .pointer(PointerBuilder(/*id=*/0, ToolType::FINGER).x(150).y(150))
12664 .pointer(PointerBuilder(/*id=*/1, ToolType::FINGER).x(10).y(10))
12665 .pointer(PointerBuilder(/*id=*/2, ToolType::FINGER).x(50).y(50))
Vaibhav Devmurariff798f32022-05-09 23:45:04 +000012666 .build();
12667 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070012668 injectMotionEvent(*mDispatcher, thirdFingerDownEvent, INJECT_EVENT_TIMEOUT,
Vaibhav Devmurariff798f32022-05-09 23:45:04 +000012669 InputEventInjectionSync::WAIT_FOR_RESULT))
12670 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
12671 spy->consumeMotionPointerDown(1);
12672 window->consumeMotionPointerDown(2);
12673
12674 // Spy window pilfers the pointers.
12675 EXPECT_EQ(OK, mDispatcher->pilferPointers(spy->getToken()));
Harry Cutts101ee9b2023-07-06 18:04:14 +000012676 window->consumeMotionPointerUp(/*idx=*/2, ADISPLAY_ID_DEFAULT, AMOTION_EVENT_FLAG_CANCELED);
12677 window->consumeMotionPointerUp(/*idx=*/1, ADISPLAY_ID_DEFAULT, AMOTION_EVENT_FLAG_CANCELED);
Vaibhav Devmurariff798f32022-05-09 23:45:04 +000012678
12679 spy->assertNoEvents();
12680 window->assertNoEvents();
12681}
12682
12683/**
12684 * After a spy window pilfers pointers, all pilfered pointers that have already been dispatched to
12685 * other windows should be canceled. If this results in the cancellation of all pointers for some
12686 * window, then that window should receive ACTION_CANCEL.
12687 */
12688TEST_F(InputDispatcherPilferPointersTest, PilferAllRequiredPointers) {
12689 auto spy = createSpy();
12690 spy->setFrame(Rect(0, 0, 100, 100));
12691 auto window = createForeground();
12692 window->setFrame(Rect(0, 0, 200, 200));
12693
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070012694 mDispatcher->onWindowInfosChanged({{*spy->getInfo(), *window->getInfo()}, {}, 0, 0});
Vaibhav Devmurariff798f32022-05-09 23:45:04 +000012695
12696 // First finger down on both spy and window
12697 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070012698 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
Vaibhav Devmurariff798f32022-05-09 23:45:04 +000012699 {10, 10}))
12700 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
12701 window->consumeMotionDown();
12702 spy->consumeMotionDown();
12703
12704 // Second finger down on the spy and window
12705 const MotionEvent secondFingerDownEvent =
12706 MotionEventBuilder(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
12707 .displayId(ADISPLAY_ID_DEFAULT)
12708 .eventTime(systemTime(SYSTEM_TIME_MONOTONIC))
Siarhei Vishniakou6d73f832022-07-21 17:27:03 -070012709 .pointer(PointerBuilder(/*id=*/0, ToolType::FINGER).x(10).y(10))
12710 .pointer(PointerBuilder(/*id=*/1, ToolType::FINGER).x(50).y(50))
Vaibhav Devmurariff798f32022-05-09 23:45:04 +000012711 .build();
12712 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070012713 injectMotionEvent(*mDispatcher, secondFingerDownEvent, INJECT_EVENT_TIMEOUT,
Vaibhav Devmurariff798f32022-05-09 23:45:04 +000012714 InputEventInjectionSync::WAIT_FOR_RESULT))
12715 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
12716 spy->consumeMotionPointerDown(1);
12717 window->consumeMotionPointerDown(1);
12718
12719 // Spy window pilfers the pointers.
12720 EXPECT_EQ(OK, mDispatcher->pilferPointers(spy->getToken()));
12721 window->consumeMotionCancel();
12722
12723 spy->assertNoEvents();
12724 window->assertNoEvents();
12725}
12726
12727/**
12728 * After a spy window pilfers pointers, new pointers that are not touching the spy window can still
12729 * be sent to other windows
12730 */
12731TEST_F(InputDispatcherPilferPointersTest, CanReceivePointersAfterPilfer) {
12732 auto spy = createSpy();
12733 spy->setFrame(Rect(0, 0, 100, 100));
12734 auto window = createForeground();
12735 window->setFrame(Rect(0, 0, 200, 200));
12736
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070012737 mDispatcher->onWindowInfosChanged({{*spy->getInfo(), *window->getInfo()}, {}, 0, 0});
Vaibhav Devmurariff798f32022-05-09 23:45:04 +000012738
12739 // First finger down on both window and spy
12740 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070012741 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
Vaibhav Devmurariff798f32022-05-09 23:45:04 +000012742 {10, 10}))
12743 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
12744 window->consumeMotionDown();
12745 spy->consumeMotionDown();
12746
12747 // Spy window pilfers the pointers.
12748 EXPECT_EQ(OK, mDispatcher->pilferPointers(spy->getToken()));
12749 window->consumeMotionCancel();
12750
12751 // Second finger down on the window only
12752 const MotionEvent secondFingerDownEvent =
12753 MotionEventBuilder(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
12754 .displayId(ADISPLAY_ID_DEFAULT)
12755 .eventTime(systemTime(SYSTEM_TIME_MONOTONIC))
Siarhei Vishniakou6d73f832022-07-21 17:27:03 -070012756 .pointer(PointerBuilder(/*id=*/0, ToolType::FINGER).x(10).y(10))
12757 .pointer(PointerBuilder(/*id=*/1, ToolType::FINGER).x(150).y(150))
Vaibhav Devmurariff798f32022-05-09 23:45:04 +000012758 .build();
12759 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070012760 injectMotionEvent(*mDispatcher, secondFingerDownEvent, INJECT_EVENT_TIMEOUT,
Vaibhav Devmurariff798f32022-05-09 23:45:04 +000012761 InputEventInjectionSync::WAIT_FOR_RESULT))
12762 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
12763 window->consumeMotionDown();
12764 window->assertNoEvents();
12765
12766 // TODO(b/232530217): do not send the unnecessary MOVE event and delete the next line
12767 spy->consumeMotionMove();
12768 spy->assertNoEvents();
12769}
12770
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -070012771/**
12772 * A window on the left and a window on the right. Also, a spy window that's above all of the
12773 * windows, and spanning both left and right windows.
12774 * Send simultaneous motion streams from two different devices, one to the left window, and another
12775 * to the right window.
12776 * Pilfer from spy window.
12777 * Check that the pilfering only affects the pointers that are actually being received by the spy.
12778 */
Siarhei Vishniakoued89cbb2023-10-13 10:42:44 -070012779TEST_F(InputDispatcherPilferPointersTest, MultiDevicePilfer_legacy) {
12780 SCOPED_FLAG_OVERRIDE(enable_multi_device_same_window_stream, false);
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -070012781 sp<FakeWindowHandle> spy = createSpy();
12782 spy->setFrame(Rect(0, 0, 200, 200));
12783 sp<FakeWindowHandle> leftWindow = createForeground();
12784 leftWindow->setFrame(Rect(0, 0, 100, 100));
12785
12786 sp<FakeWindowHandle> rightWindow = createForeground();
12787 rightWindow->setFrame(Rect(100, 0, 200, 100));
12788
12789 constexpr int32_t stylusDeviceId = 1;
12790 constexpr int32_t touchDeviceId = 2;
12791
12792 mDispatcher->onWindowInfosChanged(
12793 {{*spy->getInfo(), *leftWindow->getInfo(), *rightWindow->getInfo()}, {}, 0, 0});
12794
12795 // Stylus down on left window and spy
12796 mDispatcher->notifyMotion(MotionArgsBuilder(AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_STYLUS)
12797 .deviceId(stylusDeviceId)
12798 .pointer(PointerBuilder(0, ToolType::STYLUS).x(50).y(50))
12799 .build());
12800 leftWindow->consumeMotionEvent(
12801 AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(stylusDeviceId)));
12802 spy->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(stylusDeviceId)));
12803
12804 // Finger down on right window and spy - but spy already has stylus
12805 mDispatcher->notifyMotion(
12806 MotionArgsBuilder(AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
12807 .deviceId(touchDeviceId)
12808 .pointer(PointerBuilder(0, ToolType::FINGER).x(150).y(50))
12809 .build());
12810 rightWindow->consumeMotionEvent(
12811 AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(touchDeviceId)));
Siarhei Vishniakou2899c552023-07-10 18:20:46 -070012812 spy->assertNoEvents();
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -070012813
12814 // Act: pilfer from spy. Spy is currently receiving touch events.
12815 EXPECT_EQ(OK, mDispatcher->pilferPointers(spy->getToken()));
Siarhei Vishniakou2899c552023-07-10 18:20:46 -070012816 leftWindow->consumeMotionEvent(
12817 AllOf(WithMotionAction(ACTION_CANCEL), WithDeviceId(stylusDeviceId)));
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -070012818 rightWindow->consumeMotionEvent(
12819 AllOf(WithMotionAction(ACTION_CANCEL), WithDeviceId(touchDeviceId)));
12820
12821 // Continue movements from both stylus and touch. Touch will be delivered to spy, but not stylus
12822 mDispatcher->notifyMotion(MotionArgsBuilder(AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_STYLUS)
12823 .deviceId(stylusDeviceId)
12824 .pointer(PointerBuilder(0, ToolType::STYLUS).x(51).y(52))
12825 .build());
12826 mDispatcher->notifyMotion(
12827 MotionArgsBuilder(AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN)
12828 .deviceId(touchDeviceId)
12829 .pointer(PointerBuilder(0, ToolType::FINGER).x(151).y(52))
12830 .build());
Siarhei Vishniakou2899c552023-07-10 18:20:46 -070012831 spy->consumeMotionEvent(AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(stylusDeviceId)));
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -070012832
12833 spy->assertNoEvents();
12834 leftWindow->assertNoEvents();
12835 rightWindow->assertNoEvents();
12836}
12837
Siarhei Vishniakoued89cbb2023-10-13 10:42:44 -070012838/**
12839 * A window on the left and a window on the right. Also, a spy window that's above all of the
12840 * windows, and spanning both left and right windows.
12841 * Send simultaneous motion streams from two different devices, one to the left window, and another
12842 * to the right window.
12843 * Pilfer from spy window.
12844 * Check that the pilfering affects all of the pointers that are actually being received by the spy.
12845 * The spy should receive both the touch and the stylus events after pilfer.
12846 */
12847TEST_F(InputDispatcherPilferPointersTest, MultiDevicePilfer) {
12848 SCOPED_FLAG_OVERRIDE(enable_multi_device_same_window_stream, true);
12849 sp<FakeWindowHandle> spy = createSpy();
12850 spy->setFrame(Rect(0, 0, 200, 200));
12851 sp<FakeWindowHandle> leftWindow = createForeground();
12852 leftWindow->setFrame(Rect(0, 0, 100, 100));
12853
12854 sp<FakeWindowHandle> rightWindow = createForeground();
12855 rightWindow->setFrame(Rect(100, 0, 200, 100));
12856
12857 constexpr int32_t stylusDeviceId = 1;
12858 constexpr int32_t touchDeviceId = 2;
12859
12860 mDispatcher->onWindowInfosChanged(
12861 {{*spy->getInfo(), *leftWindow->getInfo(), *rightWindow->getInfo()}, {}, 0, 0});
12862
12863 // Stylus down on left window and spy
12864 mDispatcher->notifyMotion(MotionArgsBuilder(AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_STYLUS)
12865 .deviceId(stylusDeviceId)
12866 .pointer(PointerBuilder(0, ToolType::STYLUS).x(50).y(50))
12867 .build());
12868 leftWindow->consumeMotionEvent(
12869 AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(stylusDeviceId)));
12870 spy->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(stylusDeviceId)));
12871
12872 // Finger down on right window and spy
12873 mDispatcher->notifyMotion(
12874 MotionArgsBuilder(AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
12875 .deviceId(touchDeviceId)
12876 .pointer(PointerBuilder(0, ToolType::FINGER).x(150).y(50))
12877 .build());
12878 rightWindow->consumeMotionEvent(
12879 AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(touchDeviceId)));
12880 spy->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(touchDeviceId)));
12881
12882 // Act: pilfer from spy. Spy is currently receiving touch events.
12883 EXPECT_EQ(OK, mDispatcher->pilferPointers(spy->getToken()));
12884 leftWindow->consumeMotionEvent(
12885 AllOf(WithMotionAction(ACTION_CANCEL), WithDeviceId(stylusDeviceId)));
12886 rightWindow->consumeMotionEvent(
12887 AllOf(WithMotionAction(ACTION_CANCEL), WithDeviceId(touchDeviceId)));
12888
12889 // Continue movements from both stylus and touch. Touch and stylus will be delivered to spy
Siarhei Vishniakou92bca1c2024-04-01 14:06:59 -070012890 // Instead of sending the two MOVE events for each input device together, and then receiving
12891 // them both, process them one at at time. InputConsumer is always in the batching mode, which
12892 // means that the two MOVE events will be initially put into a batch. Once the events are
12893 // batched, the 'consume' call may result in any of the MOVE events to be sent first (depending
12894 // on the implementation of InputConsumer), which would mean that the order of the received
12895 // events could be different depending on whether there are 1 or 2 events pending in the
12896 // InputChannel at the time the test calls 'consume'. To make assertions simpler here, and to
12897 // avoid this confusing behaviour, send and receive each MOVE event separately.
Siarhei Vishniakoued89cbb2023-10-13 10:42:44 -070012898 mDispatcher->notifyMotion(MotionArgsBuilder(AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_STYLUS)
12899 .deviceId(stylusDeviceId)
12900 .pointer(PointerBuilder(0, ToolType::STYLUS).x(51).y(52))
12901 .build());
Siarhei Vishniakou92bca1c2024-04-01 14:06:59 -070012902 spy->consumeMotionEvent(AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(stylusDeviceId)));
Siarhei Vishniakoued89cbb2023-10-13 10:42:44 -070012903 mDispatcher->notifyMotion(
12904 MotionArgsBuilder(AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN)
12905 .deviceId(touchDeviceId)
12906 .pointer(PointerBuilder(0, ToolType::FINGER).x(151).y(52))
12907 .build());
Siarhei Vishniakou92bca1c2024-04-01 14:06:59 -070012908 spy->consumeMotionEvent(AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(touchDeviceId)));
Siarhei Vishniakoued89cbb2023-10-13 10:42:44 -070012909
12910 spy->assertNoEvents();
12911 leftWindow->assertNoEvents();
12912 rightWindow->assertNoEvents();
12913}
12914
Prabir Pradhan9cd9eb62023-11-22 17:58:06 +000012915TEST_F(InputDispatcherPilferPointersTest, NoPilferingWithHoveringPointers) {
12916 auto window = createForeground();
12917 auto spy = createSpy();
12918 mDispatcher->onWindowInfosChanged({{*spy->getInfo(), *window->getInfo()}, {}, 0, 0});
12919
12920 mDispatcher->notifyMotion(
12921 MotionArgsBuilder(ACTION_HOVER_ENTER, AINPUT_SOURCE_MOUSE)
12922 .deviceId(1)
12923 .pointer(PointerBuilder(/*id=*/0, ToolType::MOUSE).x(100).y(200))
12924 .build());
12925 window->consumeMotionEvent(WithMotionAction(ACTION_HOVER_ENTER));
12926 spy->consumeMotionEvent(WithMotionAction(ACTION_HOVER_ENTER));
12927
12928 // Pilfer pointers from the spy window should fail.
12929 EXPECT_NE(OK, mDispatcher->pilferPointers(spy->getToken()));
12930 spy->assertNoEvents();
12931 window->assertNoEvents();
12932}
12933
Prabir Pradhand65552b2021-10-07 11:23:50 -070012934class InputDispatcherStylusInterceptorTest : public InputDispatcherTest {
12935public:
12936 std::pair<sp<FakeWindowHandle>, sp<FakeWindowHandle>> setupStylusOverlayScenario() {
12937 std::shared_ptr<FakeApplicationHandle> overlayApplication =
12938 std::make_shared<FakeApplicationHandle>();
12939 sp<FakeWindowHandle> overlay =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -070012940 sp<FakeWindowHandle>::make(overlayApplication, mDispatcher,
12941 "Stylus interceptor window", ADISPLAY_ID_DEFAULT);
Prabir Pradhand65552b2021-10-07 11:23:50 -070012942 overlay->setFocusable(false);
Prabir Pradhanaeebeb42023-06-13 19:53:03 +000012943 overlay->setOwnerInfo(gui::Pid{111}, gui::Uid{111});
Prabir Pradhan4d5c52f2022-01-31 08:52:10 -080012944 overlay->setTouchable(false);
Prabir Pradhan51e7db02022-02-07 06:02:57 -080012945 overlay->setInterceptsStylus(true);
Prabir Pradhand65552b2021-10-07 11:23:50 -070012946 overlay->setTrustedOverlay(true);
12947
12948 std::shared_ptr<FakeApplicationHandle> application =
12949 std::make_shared<FakeApplicationHandle>();
12950 sp<FakeWindowHandle> window =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -070012951 sp<FakeWindowHandle>::make(application, mDispatcher, "Application window",
12952 ADISPLAY_ID_DEFAULT);
Prabir Pradhand65552b2021-10-07 11:23:50 -070012953 window->setFocusable(true);
Prabir Pradhanaeebeb42023-06-13 19:53:03 +000012954 window->setOwnerInfo(gui::Pid{222}, gui::Uid{222});
Prabir Pradhand65552b2021-10-07 11:23:50 -070012955
12956 mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070012957 mDispatcher->onWindowInfosChanged({{*overlay->getInfo(), *window->getInfo()}, {}, 0, 0});
Prabir Pradhand65552b2021-10-07 11:23:50 -070012958 setFocusedWindow(window);
Harry Cutts33476232023-01-30 19:57:29 +000012959 window->consumeFocusEvent(/*hasFocus=*/true, /*inTouchMode=*/true);
Prabir Pradhand65552b2021-10-07 11:23:50 -070012960 return {std::move(overlay), std::move(window)};
12961 }
12962
12963 void sendFingerEvent(int32_t action) {
Prabir Pradhan678438e2023-04-13 19:32:51 +000012964 mDispatcher->notifyMotion(
Prabir Pradhand65552b2021-10-07 11:23:50 -070012965 generateMotionArgs(action, AINPUT_SOURCE_TOUCHSCREEN | AINPUT_SOURCE_STYLUS,
Prabir Pradhan678438e2023-04-13 19:32:51 +000012966 ADISPLAY_ID_DEFAULT, {PointF{20, 20}}));
Prabir Pradhand65552b2021-10-07 11:23:50 -070012967 }
12968
12969 void sendStylusEvent(int32_t action) {
12970 NotifyMotionArgs motionArgs =
12971 generateMotionArgs(action, AINPUT_SOURCE_TOUCHSCREEN | AINPUT_SOURCE_STYLUS,
12972 ADISPLAY_ID_DEFAULT, {PointF{30, 40}});
Siarhei Vishniakou6d73f832022-07-21 17:27:03 -070012973 motionArgs.pointerProperties[0].toolType = ToolType::STYLUS;
Prabir Pradhan678438e2023-04-13 19:32:51 +000012974 mDispatcher->notifyMotion(motionArgs);
Prabir Pradhand65552b2021-10-07 11:23:50 -070012975 }
12976};
12977
Prabir Pradhana3ab87a2022-01-27 10:00:21 -080012978using InputDispatcherStylusInterceptorDeathTest = InputDispatcherStylusInterceptorTest;
12979
12980TEST_F(InputDispatcherStylusInterceptorDeathTest, UntrustedOverlay_AbortsDispatcher) {
Siarhei Vishniakouad3b6822023-06-22 14:17:35 -070012981 testing::GTEST_FLAG(death_test_style) = "threadsafe";
Prabir Pradhana3ab87a2022-01-27 10:00:21 -080012982 ScopedSilentDeath _silentDeath;
12983
Prabir Pradhand65552b2021-10-07 11:23:50 -070012984 auto [overlay, window] = setupStylusOverlayScenario();
12985 overlay->setTrustedOverlay(false);
12986 // Configuring an untrusted overlay as a stylus interceptor should cause Dispatcher to abort.
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070012987 ASSERT_DEATH(mDispatcher->onWindowInfosChanged(
12988 {{*overlay->getInfo(), *window->getInfo()}, {}, 0, 0}),
Prabir Pradhand65552b2021-10-07 11:23:50 -070012989 ".* not a trusted overlay");
12990}
12991
12992TEST_F(InputDispatcherStylusInterceptorTest, ConsmesOnlyStylusEvents) {
12993 auto [overlay, window] = setupStylusOverlayScenario();
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070012994 mDispatcher->onWindowInfosChanged({{*overlay->getInfo(), *window->getInfo()}, {}, 0, 0});
Prabir Pradhand65552b2021-10-07 11:23:50 -070012995
12996 sendStylusEvent(AMOTION_EVENT_ACTION_DOWN);
12997 overlay->consumeMotionDown();
12998 sendStylusEvent(AMOTION_EVENT_ACTION_UP);
12999 overlay->consumeMotionUp();
13000
13001 sendFingerEvent(AMOTION_EVENT_ACTION_DOWN);
13002 window->consumeMotionDown();
13003 sendFingerEvent(AMOTION_EVENT_ACTION_UP);
13004 window->consumeMotionUp();
13005
13006 overlay->assertNoEvents();
13007 window->assertNoEvents();
13008}
13009
13010TEST_F(InputDispatcherStylusInterceptorTest, SpyWindowStylusInterceptor) {
13011 auto [overlay, window] = setupStylusOverlayScenario();
Prabir Pradhan51e7db02022-02-07 06:02:57 -080013012 overlay->setSpy(true);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070013013 mDispatcher->onWindowInfosChanged({{*overlay->getInfo(), *window->getInfo()}, {}, 0, 0});
Prabir Pradhand65552b2021-10-07 11:23:50 -070013014
13015 sendStylusEvent(AMOTION_EVENT_ACTION_DOWN);
13016 overlay->consumeMotionDown();
13017 window->consumeMotionDown();
13018 sendStylusEvent(AMOTION_EVENT_ACTION_UP);
13019 overlay->consumeMotionUp();
13020 window->consumeMotionUp();
13021
13022 sendFingerEvent(AMOTION_EVENT_ACTION_DOWN);
13023 window->consumeMotionDown();
13024 sendFingerEvent(AMOTION_EVENT_ACTION_UP);
13025 window->consumeMotionUp();
13026
13027 overlay->assertNoEvents();
13028 window->assertNoEvents();
13029}
13030
Prabir Pradhan6dfbf262022-03-14 15:24:30 +000013031/**
13032 * Set up a scenario to test the behavior used by the stylus handwriting detection feature.
13033 * The scenario is as follows:
13034 * - The stylus interceptor overlay is configured as a spy window.
13035 * - The stylus interceptor spy receives the start of a new stylus gesture.
13036 * - It pilfers pointers and then configures itself to no longer be a spy.
13037 * - The stylus interceptor continues to receive the rest of the gesture.
13038 */
13039TEST_F(InputDispatcherStylusInterceptorTest, StylusHandwritingScenario) {
13040 auto [overlay, window] = setupStylusOverlayScenario();
13041 overlay->setSpy(true);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070013042 mDispatcher->onWindowInfosChanged({{*overlay->getInfo(), *window->getInfo()}, {}, 0, 0});
Prabir Pradhan6dfbf262022-03-14 15:24:30 +000013043
13044 sendStylusEvent(AMOTION_EVENT_ACTION_DOWN);
13045 overlay->consumeMotionDown();
13046 window->consumeMotionDown();
13047
13048 // The interceptor pilfers the pointers.
13049 EXPECT_EQ(OK, mDispatcher->pilferPointers(overlay->getToken()));
13050 window->consumeMotionCancel();
13051
13052 // The interceptor configures itself so that it is no longer a spy.
13053 overlay->setSpy(false);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070013054 mDispatcher->onWindowInfosChanged({{*overlay->getInfo(), *window->getInfo()}, {}, 0, 0});
Prabir Pradhan6dfbf262022-03-14 15:24:30 +000013055
13056 // It continues to receive the rest of the stylus gesture.
13057 sendStylusEvent(AMOTION_EVENT_ACTION_MOVE);
13058 overlay->consumeMotionMove();
13059 sendStylusEvent(AMOTION_EVENT_ACTION_UP);
13060 overlay->consumeMotionUp();
13061
13062 window->assertNoEvents();
13063}
13064
Prabir Pradhan5735a322022-04-11 17:23:34 +000013065struct User {
Prabir Pradhanaeebeb42023-06-13 19:53:03 +000013066 gui::Pid mPid;
Prabir Pradhan8a5c41d2023-06-08 19:13:46 +000013067 gui::Uid mUid;
Prabir Pradhan5735a322022-04-11 17:23:34 +000013068 uint32_t mPolicyFlags{DEFAULT_POLICY_FLAGS};
13069 std::unique_ptr<InputDispatcher>& mDispatcher;
13070
Prabir Pradhanaeebeb42023-06-13 19:53:03 +000013071 User(std::unique_ptr<InputDispatcher>& dispatcher, gui::Pid pid, gui::Uid uid)
Prabir Pradhan5735a322022-04-11 17:23:34 +000013072 : mPid(pid), mUid(uid), mDispatcher(dispatcher) {}
13073
13074 InputEventInjectionResult injectTargetedMotion(int32_t action) const {
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070013075 return injectMotionEvent(*mDispatcher, action, AINPUT_SOURCE_TOUCHSCREEN,
Prabir Pradhan5735a322022-04-11 17:23:34 +000013076 ADISPLAY_ID_DEFAULT, {100, 200},
13077 {AMOTION_EVENT_INVALID_CURSOR_POSITION,
13078 AMOTION_EVENT_INVALID_CURSOR_POSITION},
13079 INJECT_EVENT_TIMEOUT, InputEventInjectionSync::WAIT_FOR_RESULT,
13080 systemTime(SYSTEM_TIME_MONOTONIC), {mUid}, mPolicyFlags);
13081 }
13082
13083 InputEventInjectionResult injectTargetedKey(int32_t action) const {
Linnan Li13bf76a2024-05-05 19:18:02 +080013084 return inputdispatcher::injectKey(*mDispatcher, action, /*repeatCount=*/0,
13085 ui::ADISPLAY_ID_NONE,
Prabir Pradhan5735a322022-04-11 17:23:34 +000013086 InputEventInjectionSync::WAIT_FOR_RESULT,
Harry Cutts33476232023-01-30 19:57:29 +000013087 INJECT_EVENT_TIMEOUT, /*allowKeyRepeat=*/false, {mUid},
Prabir Pradhan5735a322022-04-11 17:23:34 +000013088 mPolicyFlags);
13089 }
13090
Siarhei Vishniakoue3ce4122023-08-23 10:26:46 -070013091 sp<FakeWindowHandle> createWindow(const char* name) const {
Prabir Pradhan5735a322022-04-11 17:23:34 +000013092 std::shared_ptr<FakeApplicationHandle> overlayApplication =
13093 std::make_shared<FakeApplicationHandle>();
Siarhei Vishniakoue3ce4122023-08-23 10:26:46 -070013094 sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(overlayApplication, mDispatcher,
13095 name, ADISPLAY_ID_DEFAULT);
Prabir Pradhan5735a322022-04-11 17:23:34 +000013096 window->setOwnerInfo(mPid, mUid);
13097 return window;
13098 }
13099};
13100
13101using InputDispatcherTargetedInjectionTest = InputDispatcherTest;
13102
13103TEST_F(InputDispatcherTargetedInjectionTest, CanInjectIntoOwnedWindow) {
Prabir Pradhanaeebeb42023-06-13 19:53:03 +000013104 auto owner = User(mDispatcher, gui::Pid{10}, gui::Uid{11});
Siarhei Vishniakoue3ce4122023-08-23 10:26:46 -070013105 auto window = owner.createWindow("Owned window");
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070013106 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Prabir Pradhan5735a322022-04-11 17:23:34 +000013107
13108 EXPECT_EQ(InputEventInjectionResult::SUCCEEDED,
13109 owner.injectTargetedMotion(AMOTION_EVENT_ACTION_DOWN));
13110 window->consumeMotionDown();
13111
13112 setFocusedWindow(window);
13113 window->consumeFocusEvent(true);
13114
13115 EXPECT_EQ(InputEventInjectionResult::SUCCEEDED,
13116 owner.injectTargetedKey(AKEY_EVENT_ACTION_DOWN));
Linnan Li13bf76a2024-05-05 19:18:02 +080013117 window->consumeKeyDown(ui::ADISPLAY_ID_NONE);
Prabir Pradhan5735a322022-04-11 17:23:34 +000013118}
13119
13120TEST_F(InputDispatcherTargetedInjectionTest, CannotInjectIntoUnownedWindow) {
Prabir Pradhanaeebeb42023-06-13 19:53:03 +000013121 auto owner = User(mDispatcher, gui::Pid{10}, gui::Uid{11});
Siarhei Vishniakoue3ce4122023-08-23 10:26:46 -070013122 auto window = owner.createWindow("Owned window");
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070013123 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Prabir Pradhan5735a322022-04-11 17:23:34 +000013124
Prabir Pradhanaeebeb42023-06-13 19:53:03 +000013125 auto rando = User(mDispatcher, gui::Pid{20}, gui::Uid{21});
Prabir Pradhan5735a322022-04-11 17:23:34 +000013126 EXPECT_EQ(InputEventInjectionResult::TARGET_MISMATCH,
13127 rando.injectTargetedMotion(AMOTION_EVENT_ACTION_DOWN));
13128
13129 setFocusedWindow(window);
13130 window->consumeFocusEvent(true);
13131
13132 EXPECT_EQ(InputEventInjectionResult::TARGET_MISMATCH,
13133 rando.injectTargetedKey(AKEY_EVENT_ACTION_DOWN));
13134 window->assertNoEvents();
13135}
13136
13137TEST_F(InputDispatcherTargetedInjectionTest, CanInjectIntoOwnedSpyWindow) {
Prabir Pradhanaeebeb42023-06-13 19:53:03 +000013138 auto owner = User(mDispatcher, gui::Pid{10}, gui::Uid{11});
Siarhei Vishniakoue3ce4122023-08-23 10:26:46 -070013139 auto window = owner.createWindow("Owned window");
13140 auto spy = owner.createWindow("Owned spy");
Prabir Pradhan5735a322022-04-11 17:23:34 +000013141 spy->setSpy(true);
13142 spy->setTrustedOverlay(true);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070013143 mDispatcher->onWindowInfosChanged({{*spy->getInfo(), *window->getInfo()}, {}, 0, 0});
Prabir Pradhan5735a322022-04-11 17:23:34 +000013144
13145 EXPECT_EQ(InputEventInjectionResult::SUCCEEDED,
13146 owner.injectTargetedMotion(AMOTION_EVENT_ACTION_DOWN));
13147 spy->consumeMotionDown();
13148 window->consumeMotionDown();
13149}
13150
13151TEST_F(InputDispatcherTargetedInjectionTest, CannotInjectIntoUnownedSpyWindow) {
Prabir Pradhanaeebeb42023-06-13 19:53:03 +000013152 auto owner = User(mDispatcher, gui::Pid{10}, gui::Uid{11});
Siarhei Vishniakoue3ce4122023-08-23 10:26:46 -070013153 auto window = owner.createWindow("Owned window");
Prabir Pradhan5735a322022-04-11 17:23:34 +000013154
Prabir Pradhanaeebeb42023-06-13 19:53:03 +000013155 auto rando = User(mDispatcher, gui::Pid{20}, gui::Uid{21});
Siarhei Vishniakoue3ce4122023-08-23 10:26:46 -070013156 auto randosSpy = rando.createWindow("Rando's spy");
Prabir Pradhan5735a322022-04-11 17:23:34 +000013157 randosSpy->setSpy(true);
13158 randosSpy->setTrustedOverlay(true);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070013159 mDispatcher->onWindowInfosChanged({{*randosSpy->getInfo(), *window->getInfo()}, {}, 0, 0});
Prabir Pradhan5735a322022-04-11 17:23:34 +000013160
13161 // The event is targeted at owner's window, so injection should succeed, but the spy should
13162 // not receive the event.
13163 EXPECT_EQ(InputEventInjectionResult::SUCCEEDED,
13164 owner.injectTargetedMotion(AMOTION_EVENT_ACTION_DOWN));
13165 randosSpy->assertNoEvents();
13166 window->consumeMotionDown();
13167}
13168
13169TEST_F(InputDispatcherTargetedInjectionTest, CanInjectIntoAnyWindowWhenNotTargeting) {
Prabir Pradhanaeebeb42023-06-13 19:53:03 +000013170 auto owner = User(mDispatcher, gui::Pid{10}, gui::Uid{11});
Siarhei Vishniakoue3ce4122023-08-23 10:26:46 -070013171 auto window = owner.createWindow("Owned window");
Prabir Pradhan5735a322022-04-11 17:23:34 +000013172
Prabir Pradhanaeebeb42023-06-13 19:53:03 +000013173 auto rando = User(mDispatcher, gui::Pid{20}, gui::Uid{21});
Siarhei Vishniakoue3ce4122023-08-23 10:26:46 -070013174 auto randosSpy = rando.createWindow("Rando's spy");
Prabir Pradhan5735a322022-04-11 17:23:34 +000013175 randosSpy->setSpy(true);
13176 randosSpy->setTrustedOverlay(true);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070013177 mDispatcher->onWindowInfosChanged({{*randosSpy->getInfo(), *window->getInfo()}, {}, 0, 0});
Prabir Pradhan5735a322022-04-11 17:23:34 +000013178
13179 // A user that has injection permission can inject into any window.
13180 EXPECT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070013181 injectMotionEvent(*mDispatcher, AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN,
Prabir Pradhan5735a322022-04-11 17:23:34 +000013182 ADISPLAY_ID_DEFAULT));
13183 randosSpy->consumeMotionDown();
13184 window->consumeMotionDown();
13185
13186 setFocusedWindow(randosSpy);
13187 randosSpy->consumeFocusEvent(true);
13188
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070013189 EXPECT_EQ(InputEventInjectionResult::SUCCEEDED, injectKeyDown(*mDispatcher));
Linnan Li13bf76a2024-05-05 19:18:02 +080013190 randosSpy->consumeKeyDown(ui::ADISPLAY_ID_NONE);
Prabir Pradhan5735a322022-04-11 17:23:34 +000013191 window->assertNoEvents();
13192}
13193
Siarhei Vishniakou580fb3a2023-05-05 15:02:20 -070013194TEST_F(InputDispatcherTargetedInjectionTest, CannotGenerateActionOutsideToOtherUids) {
Prabir Pradhanaeebeb42023-06-13 19:53:03 +000013195 auto owner = User(mDispatcher, gui::Pid{10}, gui::Uid{11});
Siarhei Vishniakoue3ce4122023-08-23 10:26:46 -070013196 auto window = owner.createWindow("Owned window");
Prabir Pradhan5735a322022-04-11 17:23:34 +000013197
Prabir Pradhanaeebeb42023-06-13 19:53:03 +000013198 auto rando = User(mDispatcher, gui::Pid{20}, gui::Uid{21});
Siarhei Vishniakoue3ce4122023-08-23 10:26:46 -070013199 auto randosWindow = rando.createWindow("Rando's window");
Prabir Pradhan5735a322022-04-11 17:23:34 +000013200 randosWindow->setFrame(Rect{-10, -10, -5, -5});
13201 randosWindow->setWatchOutsideTouch(true);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070013202 mDispatcher->onWindowInfosChanged({{*randosWindow->getInfo(), *window->getInfo()}, {}, 0, 0});
Prabir Pradhan5735a322022-04-11 17:23:34 +000013203
Siarhei Vishniakou580fb3a2023-05-05 15:02:20 -070013204 // Do not allow generation of ACTION_OUTSIDE events into windows owned by different uids.
Prabir Pradhan5735a322022-04-11 17:23:34 +000013205 EXPECT_EQ(InputEventInjectionResult::SUCCEEDED,
13206 owner.injectTargetedMotion(AMOTION_EVENT_ACTION_DOWN));
13207 window->consumeMotionDown();
Siarhei Vishniakou580fb3a2023-05-05 15:02:20 -070013208 randosWindow->assertNoEvents();
Prabir Pradhan5735a322022-04-11 17:23:34 +000013209}
13210
Prabir Pradhan64f21d22023-11-28 21:19:42 +000013211using InputDispatcherPointerInWindowTest = InputDispatcherTest;
13212
13213TEST_F(InputDispatcherPointerInWindowTest, PointerInWindowWhenHovering) {
13214 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
13215
13216 sp<FakeWindowHandle> left = sp<FakeWindowHandle>::make(application, mDispatcher, "Left Window",
13217 ADISPLAY_ID_DEFAULT);
13218 left->setFrame(Rect(0, 0, 100, 100));
13219 sp<FakeWindowHandle> right = sp<FakeWindowHandle>::make(application, mDispatcher,
13220 "Right Window", ADISPLAY_ID_DEFAULT);
13221 right->setFrame(Rect(100, 0, 200, 100));
13222 sp<FakeWindowHandle> spy =
13223 sp<FakeWindowHandle>::make(application, mDispatcher, "Spy Window", ADISPLAY_ID_DEFAULT);
13224 spy->setFrame(Rect(0, 0, 200, 100));
13225 spy->setTrustedOverlay(true);
13226 spy->setSpy(true);
13227
13228 mDispatcher->onWindowInfosChanged(
13229 {{*spy->getInfo(), *left->getInfo(), *right->getInfo()}, {}, 0, 0});
13230
13231 // Hover into the left window.
13232 mDispatcher->notifyMotion(
13233 MotionArgsBuilder(ACTION_HOVER_ENTER, AINPUT_SOURCE_STYLUS)
13234 .pointer(PointerBuilder(/*id=*/0, ToolType::STYLUS).x(50).y(50))
13235 .build());
13236
13237 left->consumeMotionEvent(WithMotionAction(ACTION_HOVER_ENTER));
13238 spy->consumeMotionEvent(WithMotionAction(ACTION_HOVER_ENTER));
13239
13240 ASSERT_TRUE(mDispatcher->isPointerInWindow(left->getToken(), ADISPLAY_ID_DEFAULT, DEVICE_ID,
13241 /*pointerId=*/0));
13242 ASSERT_TRUE(mDispatcher->isPointerInWindow(spy->getToken(), ADISPLAY_ID_DEFAULT, DEVICE_ID,
13243 /*pointerId=*/0));
13244 ASSERT_FALSE(mDispatcher->isPointerInWindow(right->getToken(), ADISPLAY_ID_DEFAULT, DEVICE_ID,
13245 /*pointerId=*/0));
13246
13247 // Hover move to the right window.
13248 mDispatcher->notifyMotion(
13249 MotionArgsBuilder(ACTION_HOVER_MOVE, AINPUT_SOURCE_STYLUS)
13250 .pointer(PointerBuilder(/*id=*/0, ToolType::STYLUS).x(150).y(50))
13251 .build());
13252
13253 left->consumeMotionEvent(WithMotionAction(ACTION_HOVER_EXIT));
13254 right->consumeMotionEvent(WithMotionAction(ACTION_HOVER_ENTER));
13255 spy->consumeMotionEvent(WithMotionAction(ACTION_HOVER_MOVE));
13256
13257 ASSERT_FALSE(mDispatcher->isPointerInWindow(left->getToken(), ADISPLAY_ID_DEFAULT, DEVICE_ID,
13258 /*pointerId=*/0));
13259 ASSERT_TRUE(mDispatcher->isPointerInWindow(spy->getToken(), ADISPLAY_ID_DEFAULT, DEVICE_ID,
13260 /*pointerId=*/0));
13261 ASSERT_TRUE(mDispatcher->isPointerInWindow(right->getToken(), ADISPLAY_ID_DEFAULT, DEVICE_ID,
13262 /*pointerId=*/0));
13263
13264 // Stop hovering.
13265 mDispatcher->notifyMotion(
13266 MotionArgsBuilder(ACTION_HOVER_EXIT, AINPUT_SOURCE_STYLUS)
13267 .pointer(PointerBuilder(/*id=*/0, ToolType::STYLUS).x(150).y(50))
13268 .build());
13269
13270 right->consumeMotionEvent(WithMotionAction(ACTION_HOVER_EXIT));
13271 spy->consumeMotionEvent(WithMotionAction(ACTION_HOVER_EXIT));
13272
13273 ASSERT_FALSE(mDispatcher->isPointerInWindow(left->getToken(), ADISPLAY_ID_DEFAULT, DEVICE_ID,
13274 /*pointerId=*/0));
13275 ASSERT_FALSE(mDispatcher->isPointerInWindow(spy->getToken(), ADISPLAY_ID_DEFAULT, DEVICE_ID,
13276 /*pointerId=*/0));
13277 ASSERT_FALSE(mDispatcher->isPointerInWindow(right->getToken(), ADISPLAY_ID_DEFAULT, DEVICE_ID,
13278 /*pointerId=*/0));
13279}
13280
13281TEST_F(InputDispatcherPointerInWindowTest, PointerInWindowWithSplitTouch) {
13282 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
13283
13284 sp<FakeWindowHandle> left = sp<FakeWindowHandle>::make(application, mDispatcher, "Left Window",
13285 ADISPLAY_ID_DEFAULT);
13286 left->setFrame(Rect(0, 0, 100, 100));
13287 sp<FakeWindowHandle> right = sp<FakeWindowHandle>::make(application, mDispatcher,
13288 "Right Window", ADISPLAY_ID_DEFAULT);
13289 right->setFrame(Rect(100, 0, 200, 100));
13290 sp<FakeWindowHandle> spy =
13291 sp<FakeWindowHandle>::make(application, mDispatcher, "Spy Window", ADISPLAY_ID_DEFAULT);
13292 spy->setFrame(Rect(0, 0, 200, 100));
13293 spy->setTrustedOverlay(true);
13294 spy->setSpy(true);
13295
13296 mDispatcher->onWindowInfosChanged(
13297 {{*spy->getInfo(), *left->getInfo(), *right->getInfo()}, {}, 0, 0});
13298
13299 // First pointer down on left window.
13300 mDispatcher->notifyMotion(
13301 MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
13302 .pointer(PointerBuilder(/*id=*/0, ToolType::FINGER).x(50).y(50))
13303 .build());
13304
13305 left->consumeMotionDown();
13306 spy->consumeMotionDown();
13307
13308 ASSERT_TRUE(mDispatcher->isPointerInWindow(left->getToken(), ADISPLAY_ID_DEFAULT, DEVICE_ID,
13309 /*pointerId=*/0));
13310 ASSERT_TRUE(mDispatcher->isPointerInWindow(spy->getToken(), ADISPLAY_ID_DEFAULT, DEVICE_ID,
13311 /*pointerId=*/0));
13312 ASSERT_FALSE(mDispatcher->isPointerInWindow(right->getToken(), ADISPLAY_ID_DEFAULT, DEVICE_ID,
13313 /*pointerId=*/0));
13314
13315 // Second pointer down on right window.
13316 mDispatcher->notifyMotion(
13317 MotionArgsBuilder(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
13318 .pointer(PointerBuilder(/*id=*/0, ToolType::FINGER).x(50).y(50))
13319 .pointer(PointerBuilder(/*id=*/1, ToolType::FINGER).x(150).y(50))
13320 .build());
13321
13322 left->consumeMotionMove();
13323 right->consumeMotionDown();
13324 spy->consumeMotionEvent(WithMotionAction(POINTER_1_DOWN));
13325
13326 ASSERT_TRUE(mDispatcher->isPointerInWindow(left->getToken(), ADISPLAY_ID_DEFAULT, DEVICE_ID,
13327 /*pointerId=*/0));
13328 ASSERT_TRUE(mDispatcher->isPointerInWindow(spy->getToken(), ADISPLAY_ID_DEFAULT, DEVICE_ID,
13329 /*pointerId=*/0));
13330 ASSERT_FALSE(mDispatcher->isPointerInWindow(right->getToken(), ADISPLAY_ID_DEFAULT, DEVICE_ID,
13331 /*pointerId=*/0));
13332 ASSERT_FALSE(mDispatcher->isPointerInWindow(left->getToken(), ADISPLAY_ID_DEFAULT, DEVICE_ID,
13333 /*pointerId=*/1));
13334 ASSERT_TRUE(mDispatcher->isPointerInWindow(spy->getToken(), ADISPLAY_ID_DEFAULT, DEVICE_ID,
13335 /*pointerId=*/1));
13336 ASSERT_TRUE(mDispatcher->isPointerInWindow(right->getToken(), ADISPLAY_ID_DEFAULT, DEVICE_ID,
13337 /*pointerId=*/1));
13338
13339 // Second pointer up.
13340 mDispatcher->notifyMotion(
13341 MotionArgsBuilder(POINTER_1_UP, AINPUT_SOURCE_TOUCHSCREEN)
13342 .pointer(PointerBuilder(/*id=*/0, ToolType::FINGER).x(50).y(50))
13343 .pointer(PointerBuilder(/*id=*/1, ToolType::FINGER).x(150).y(50))
13344 .build());
13345
13346 left->consumeMotionMove();
13347 right->consumeMotionUp();
13348 spy->consumeMotionEvent(WithMotionAction(POINTER_1_UP));
13349
13350 ASSERT_TRUE(mDispatcher->isPointerInWindow(left->getToken(), ADISPLAY_ID_DEFAULT, DEVICE_ID,
13351 /*pointerId=*/0));
13352 ASSERT_TRUE(mDispatcher->isPointerInWindow(spy->getToken(), ADISPLAY_ID_DEFAULT, DEVICE_ID,
13353 /*pointerId=*/0));
13354 ASSERT_FALSE(mDispatcher->isPointerInWindow(right->getToken(), ADISPLAY_ID_DEFAULT, DEVICE_ID,
13355 /*pointerId=*/0));
13356 ASSERT_FALSE(mDispatcher->isPointerInWindow(left->getToken(), ADISPLAY_ID_DEFAULT, DEVICE_ID,
13357 /*pointerId=*/1));
13358 ASSERT_FALSE(mDispatcher->isPointerInWindow(spy->getToken(), ADISPLAY_ID_DEFAULT, DEVICE_ID,
13359 /*pointerId=*/1));
13360 ASSERT_FALSE(mDispatcher->isPointerInWindow(right->getToken(), ADISPLAY_ID_DEFAULT, DEVICE_ID,
13361 /*pointerId=*/1));
13362
13363 // First pointer up.
13364 mDispatcher->notifyMotion(
13365 MotionArgsBuilder(ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN)
13366 .pointer(PointerBuilder(/*id=*/0, ToolType::FINGER).x(50).y(50))
13367 .build());
13368
13369 left->consumeMotionUp();
13370 spy->consumeMotionUp();
13371
13372 ASSERT_FALSE(mDispatcher->isPointerInWindow(left->getToken(), ADISPLAY_ID_DEFAULT, DEVICE_ID,
13373 /*pointerId=*/0));
13374 ASSERT_FALSE(mDispatcher->isPointerInWindow(spy->getToken(), ADISPLAY_ID_DEFAULT, DEVICE_ID,
13375 /*pointerId=*/0));
13376 ASSERT_FALSE(mDispatcher->isPointerInWindow(right->getToken(), ADISPLAY_ID_DEFAULT, DEVICE_ID,
13377 /*pointerId=*/0));
13378}
13379
Siarhei Vishniakoued89cbb2023-10-13 10:42:44 -070013380TEST_F(InputDispatcherPointerInWindowTest, MultipleDevicesControllingOneMouse_legacy) {
13381 SCOPED_FLAG_OVERRIDE(enable_multi_device_same_window_stream, false);
Prabir Pradhan64f21d22023-11-28 21:19:42 +000013382 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
13383
13384 sp<FakeWindowHandle> left = sp<FakeWindowHandle>::make(application, mDispatcher, "Left Window",
13385 ADISPLAY_ID_DEFAULT);
13386 left->setFrame(Rect(0, 0, 100, 100));
13387 sp<FakeWindowHandle> right = sp<FakeWindowHandle>::make(application, mDispatcher,
13388 "Right Window", ADISPLAY_ID_DEFAULT);
13389 right->setFrame(Rect(100, 0, 200, 100));
13390
13391 mDispatcher->onWindowInfosChanged({{*left->getInfo(), *right->getInfo()}, {}, 0, 0});
13392
13393 ASSERT_FALSE(mDispatcher->isPointerInWindow(left->getToken(), ADISPLAY_ID_DEFAULT, DEVICE_ID,
13394 /*pointerId=*/0));
13395 ASSERT_FALSE(mDispatcher->isPointerInWindow(right->getToken(), ADISPLAY_ID_DEFAULT, DEVICE_ID,
13396 /*pointerId=*/0));
13397
13398 // Hover move into the window.
13399 mDispatcher->notifyMotion(
13400 MotionArgsBuilder(ACTION_HOVER_MOVE, AINPUT_SOURCE_MOUSE)
13401 .pointer(PointerBuilder(/*id=*/0, ToolType::MOUSE).x(50).y(50))
13402 .rawXCursorPosition(50)
13403 .rawYCursorPosition(50)
13404 .deviceId(DEVICE_ID)
13405 .build());
13406
13407 left->consumeMotionEvent(WithMotionAction(ACTION_HOVER_ENTER));
13408
13409 ASSERT_TRUE(mDispatcher->isPointerInWindow(left->getToken(), ADISPLAY_ID_DEFAULT, DEVICE_ID,
13410 /*pointerId=*/0));
13411
13412 // Move the mouse with another device. This cancels the hovering pointer from the first device.
13413 mDispatcher->notifyMotion(
13414 MotionArgsBuilder(ACTION_HOVER_MOVE, AINPUT_SOURCE_MOUSE)
13415 .pointer(PointerBuilder(/*id=*/0, ToolType::MOUSE).x(51).y(50))
13416 .rawXCursorPosition(51)
13417 .rawYCursorPosition(50)
13418 .deviceId(SECOND_DEVICE_ID)
13419 .build());
13420
13421 left->consumeMotionEvent(WithMotionAction(ACTION_HOVER_EXIT));
13422 left->consumeMotionEvent(WithMotionAction(ACTION_HOVER_ENTER));
13423
13424 // TODO(b/313689709): InputDispatcher's touch state is not updated, even though the window gets
13425 // a HOVER_EXIT from the first device.
13426 ASSERT_TRUE(mDispatcher->isPointerInWindow(left->getToken(), ADISPLAY_ID_DEFAULT, DEVICE_ID,
13427 /*pointerId=*/0));
13428 ASSERT_TRUE(mDispatcher->isPointerInWindow(left->getToken(), ADISPLAY_ID_DEFAULT,
13429 SECOND_DEVICE_ID,
13430 /*pointerId=*/0));
13431
13432 // Move the mouse outside the window. Document the current behavior, where the window does not
13433 // receive HOVER_EXIT even though the mouse left the window.
13434 mDispatcher->notifyMotion(
13435 MotionArgsBuilder(ACTION_HOVER_MOVE, AINPUT_SOURCE_MOUSE)
13436 .pointer(PointerBuilder(/*id=*/0, ToolType::MOUSE).x(150).y(50))
13437 .rawXCursorPosition(150)
13438 .rawYCursorPosition(50)
13439 .deviceId(SECOND_DEVICE_ID)
13440 .build());
13441
13442 left->consumeMotionEvent(WithMotionAction(ACTION_HOVER_EXIT));
13443 right->consumeMotionEvent(WithMotionAction(ACTION_HOVER_ENTER));
13444 ASSERT_TRUE(mDispatcher->isPointerInWindow(left->getToken(), ADISPLAY_ID_DEFAULT, DEVICE_ID,
13445 /*pointerId=*/0));
13446 ASSERT_FALSE(mDispatcher->isPointerInWindow(left->getToken(), ADISPLAY_ID_DEFAULT,
13447 SECOND_DEVICE_ID,
13448 /*pointerId=*/0));
13449}
13450
Siarhei Vishniakoued89cbb2023-10-13 10:42:44 -070013451/**
13452 * TODO(b/313689709) - correctly support multiple mouse devices, because they should be controlling
13453 * the same cursor, and therefore have a shared motion event stream.
13454 */
13455TEST_F(InputDispatcherPointerInWindowTest, MultipleDevicesControllingOneMouse) {
13456 SCOPED_FLAG_OVERRIDE(enable_multi_device_same_window_stream, true);
13457 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
13458
13459 sp<FakeWindowHandle> left = sp<FakeWindowHandle>::make(application, mDispatcher, "Left Window",
13460 ADISPLAY_ID_DEFAULT);
13461 left->setFrame(Rect(0, 0, 100, 100));
13462 sp<FakeWindowHandle> right = sp<FakeWindowHandle>::make(application, mDispatcher,
13463 "Right Window", ADISPLAY_ID_DEFAULT);
13464 right->setFrame(Rect(100, 0, 200, 100));
13465
13466 mDispatcher->onWindowInfosChanged({{*left->getInfo(), *right->getInfo()}, {}, 0, 0});
13467
13468 ASSERT_FALSE(mDispatcher->isPointerInWindow(left->getToken(), ADISPLAY_ID_DEFAULT, DEVICE_ID,
13469 /*pointerId=*/0));
13470 ASSERT_FALSE(mDispatcher->isPointerInWindow(right->getToken(), ADISPLAY_ID_DEFAULT, DEVICE_ID,
13471 /*pointerId=*/0));
13472
13473 // Hover move into the window.
13474 mDispatcher->notifyMotion(
13475 MotionArgsBuilder(ACTION_HOVER_MOVE, AINPUT_SOURCE_MOUSE)
13476 .pointer(PointerBuilder(/*id=*/0, ToolType::MOUSE).x(50).y(50))
13477 .rawXCursorPosition(50)
13478 .rawYCursorPosition(50)
13479 .deviceId(DEVICE_ID)
13480 .build());
13481
13482 left->consumeMotionEvent(WithMotionAction(ACTION_HOVER_ENTER));
13483
13484 ASSERT_TRUE(mDispatcher->isPointerInWindow(left->getToken(), ADISPLAY_ID_DEFAULT, DEVICE_ID,
13485 /*pointerId=*/0));
13486
13487 // Move the mouse with another device
13488 mDispatcher->notifyMotion(
13489 MotionArgsBuilder(ACTION_HOVER_MOVE, AINPUT_SOURCE_MOUSE)
13490 .pointer(PointerBuilder(/*id=*/0, ToolType::MOUSE).x(51).y(50))
13491 .rawXCursorPosition(51)
13492 .rawYCursorPosition(50)
13493 .deviceId(SECOND_DEVICE_ID)
13494 .build());
13495 left->consumeMotionEvent(WithMotionAction(ACTION_HOVER_ENTER));
13496
13497 // TODO(b/313689709): InputDispatcher's touch state is not updated, even though the window gets
13498 // a HOVER_EXIT from the first device.
13499 ASSERT_TRUE(mDispatcher->isPointerInWindow(left->getToken(), ADISPLAY_ID_DEFAULT, DEVICE_ID,
13500 /*pointerId=*/0));
13501 ASSERT_TRUE(mDispatcher->isPointerInWindow(left->getToken(), ADISPLAY_ID_DEFAULT,
13502 SECOND_DEVICE_ID,
13503 /*pointerId=*/0));
13504
13505 // Move the mouse outside the window. Document the current behavior, where the window does not
13506 // receive HOVER_EXIT even though the mouse left the window.
13507 mDispatcher->notifyMotion(
13508 MotionArgsBuilder(ACTION_HOVER_MOVE, AINPUT_SOURCE_MOUSE)
13509 .pointer(PointerBuilder(/*id=*/0, ToolType::MOUSE).x(150).y(50))
13510 .rawXCursorPosition(150)
13511 .rawYCursorPosition(50)
13512 .deviceId(SECOND_DEVICE_ID)
13513 .build());
13514
13515 right->consumeMotionEvent(WithMotionAction(ACTION_HOVER_ENTER));
13516 ASSERT_TRUE(mDispatcher->isPointerInWindow(left->getToken(), ADISPLAY_ID_DEFAULT, DEVICE_ID,
13517 /*pointerId=*/0));
13518 ASSERT_FALSE(mDispatcher->isPointerInWindow(left->getToken(), ADISPLAY_ID_DEFAULT,
13519 SECOND_DEVICE_ID,
13520 /*pointerId=*/0));
13521}
13522
Garfield Tane84e6f92019-08-29 17:28:41 -070013523} // namespace android::inputdispatcher