blob: 9375e92eac766b651bddfbf93a11b9cebd072b6f [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 Pradhandc3a2ad2024-02-05 19:03:51 +000019#include "FakeInputTracingBackend.h"
Prabir Pradhane3b28dd2023-10-06 04:19:29 +000020#include "TestEventMatchers.h"
Michael Wrightd02c5b62014-02-10 15:10:22 -080021
Cody Heiner166a5af2023-07-07 12:25:00 -070022#include <NotifyArgsBuilders.h>
Prabir Pradhan5893d362023-11-17 04:30:40 +000023#include <android-base/logging.h>
Siarhei Vishniakou1c494c52021-08-11 20:25:01 -070024#include <android-base/properties.h>
Prabir Pradhana3ab87a2022-01-27 10:00:21 -080025#include <android-base/silent_death_test.h>
Garfield Tan1c7bc862020-01-28 13:24:04 -080026#include <android-base/stringprintf.h>
Siarhei Vishniakou4cb50ca2020-05-26 21:43:02 -070027#include <android-base/thread_annotations.h>
Robert Carr803535b2018-08-02 16:38:15 -070028#include <binder/Binder.h>
Ameer Armalycff4fa52023-10-04 23:45:11 +000029#include <com_android_input_flags.h>
Michael Wright8e9a8562022-02-09 13:44:29 +000030#include <fcntl.h>
Ameer Armalycff4fa52023-10-04 23:45:11 +000031#include <flag_macros.h>
Siarhei Vishniakou0b0374d2022-11-17 17:40:53 -080032#include <gmock/gmock.h>
Michael Wrightd02c5b62014-02-10 15:10:22 -080033#include <gtest/gtest.h>
Siarhei Vishniakou3782af62024-03-07 21:56:39 -080034#include <input/BlockingQueue.h>
Siarhei Vishniakou870ecec2020-12-09 08:07:46 -100035#include <input/Input.h>
Siarhei Vishniakou0438ca82024-03-12 14:27:25 -070036#include <input/InputConsumer.h>
Siarhei Vishniakouf4043212023-09-18 19:33:03 -070037#include <input/PrintTools.h>
Michael Wrightd02c5b62014-02-10 15:10:22 -080038#include <linux/input.h>
Prabir Pradhan07e05b62021-11-19 03:57:24 -080039#include <sys/epoll.h>
Siarhei Vishniakou870ecec2020-12-09 08:07:46 -100040
Garfield Tan1c7bc862020-01-28 13:24:04 -080041#include <cinttypes>
Siarhei Vishniakou487c49b2022-12-02 15:48:57 -080042#include <compare>
Siarhei Vishniakou4cb50ca2020-05-26 21:43:02 -070043#include <thread>
Garfield Tan1c7bc862020-01-28 13:24:04 -080044#include <unordered_set>
chaviwd1c23182019-12-20 18:44:56 -080045#include <vector>
Michael Wrightd02c5b62014-02-10 15:10:22 -080046
Garfield Tan1c7bc862020-01-28 13:24:04 -080047using android::base::StringPrintf;
chaviw3277faf2021-05-19 16:45:23 -050048using android::gui::FocusRequest;
49using android::gui::TouchOcclusionMode;
50using android::gui::WindowInfo;
51using android::gui::WindowInfoHandle;
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -080052using android::os::InputEventInjectionResult;
53using android::os::InputEventInjectionSync;
Garfield Tan1c7bc862020-01-28 13:24:04 -080054
Garfield Tane84e6f92019-08-29 17:28:41 -070055namespace android::inputdispatcher {
Michael Wrightd02c5b62014-02-10 15:10:22 -080056
Dominik Laskowski2f01d772022-03-23 16:01:29 -070057using namespace ftl::flag_operators;
Siarhei Vishniakou0b0374d2022-11-17 17:40:53 -080058using testing::AllOf;
Prabir Pradhan5893d362023-11-17 04:30:40 +000059using testing::Not;
Dominik Laskowski2f01d772022-03-23 16:01:29 -070060
Siarhei Vishniakouf4043212023-09-18 19:33:03 -070061namespace {
62
Michael Wrightd02c5b62014-02-10 15:10:22 -080063// An arbitrary time value.
Prabir Pradhan5735a322022-04-11 17:23:34 +000064static constexpr nsecs_t ARBITRARY_TIME = 1234;
Michael Wrightd02c5b62014-02-10 15:10:22 -080065
66// An arbitrary device id.
Prabir Pradhan9205e422023-05-16 20:06:13 +000067static constexpr int32_t DEVICE_ID = DEFAULT_DEVICE_ID;
Siarhei Vishniakou060f82b2023-01-27 06:39:14 -080068static constexpr int32_t SECOND_DEVICE_ID = 2;
Michael Wrightd02c5b62014-02-10 15:10:22 -080069
Jeff Brownf086ddb2014-02-11 14:28:48 -080070// An arbitrary display id.
Arthur Hungabbb9d82021-09-01 14:52:30 +000071static constexpr int32_t DISPLAY_ID = ADISPLAY_ID_DEFAULT;
72static constexpr int32_t SECOND_DISPLAY_ID = 1;
Jeff Brownf086ddb2014-02-11 14:28:48 -080073
Prabir Pradhan8ede1d12023-05-08 19:37:44 +000074// Ensure common actions are interchangeable between keys and motions for convenience.
75static_assert(AMOTION_EVENT_ACTION_DOWN == AKEY_EVENT_ACTION_DOWN);
76static_assert(AMOTION_EVENT_ACTION_UP == AKEY_EVENT_ACTION_UP);
Siarhei Vishniakouf372b812023-02-14 18:06:51 -080077static constexpr int32_t ACTION_DOWN = AMOTION_EVENT_ACTION_DOWN;
78static constexpr int32_t ACTION_MOVE = AMOTION_EVENT_ACTION_MOVE;
79static constexpr int32_t ACTION_UP = AMOTION_EVENT_ACTION_UP;
80static constexpr int32_t ACTION_HOVER_ENTER = AMOTION_EVENT_ACTION_HOVER_ENTER;
Siarhei Vishniakoua235c042023-05-02 09:59:09 -070081static constexpr int32_t ACTION_HOVER_MOVE = AMOTION_EVENT_ACTION_HOVER_MOVE;
Siarhei Vishniakouf372b812023-02-14 18:06:51 -080082static constexpr int32_t ACTION_HOVER_EXIT = AMOTION_EVENT_ACTION_HOVER_EXIT;
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -070083static constexpr int32_t ACTION_SCROLL = AMOTION_EVENT_ACTION_SCROLL;
Siarhei Vishniakou487c49b2022-12-02 15:48:57 -080084static constexpr int32_t ACTION_OUTSIDE = AMOTION_EVENT_ACTION_OUTSIDE;
Siarhei Vishniakou1ae72f12023-01-29 12:55:30 -080085static constexpr int32_t ACTION_CANCEL = AMOTION_EVENT_ACTION_CANCEL;
Siarhei Vishniakouf372b812023-02-14 18:06:51 -080086/**
87 * The POINTER_DOWN(0) is an unusual, but valid, action. It just means that the new pointer in the
88 * MotionEvent is at the index 0 rather than 1 (or later). That is, the pointer id=0 (which is at
89 * index 0) is the new pointer going down. The same pointer could have been placed at a different
90 * index, and the action would become POINTER_1_DOWN, 2, etc..; these would all be valid. In
91 * general, we try to place pointer id = 0 at the index 0. Of course, this is not possible if
92 * pointer id=0 leaves but the pointer id=1 remains.
93 */
94static constexpr int32_t POINTER_0_DOWN =
95 AMOTION_EVENT_ACTION_POINTER_DOWN | (0 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT);
Siarhei Vishniakoua16e3a22022-03-02 15:26:40 -080096static constexpr int32_t POINTER_1_DOWN =
97 AMOTION_EVENT_ACTION_POINTER_DOWN | (1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT);
Prabir Pradhanb60b1dc2022-03-15 14:02:35 +000098static constexpr int32_t POINTER_2_DOWN =
99 AMOTION_EVENT_ACTION_POINTER_DOWN | (2 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT);
Vaibhav Devmurari882bd9b2022-06-23 14:54:54 +0000100static constexpr int32_t POINTER_3_DOWN =
101 AMOTION_EVENT_ACTION_POINTER_DOWN | (3 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT);
Arthur Hungc539dbb2022-12-08 07:45:36 +0000102static constexpr int32_t POINTER_0_UP =
103 AMOTION_EVENT_ACTION_POINTER_UP | (0 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT);
Siarhei Vishniakoua16e3a22022-03-02 15:26:40 -0800104static constexpr int32_t POINTER_1_UP =
105 AMOTION_EVENT_ACTION_POINTER_UP | (1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT);
Harry Cuttsb166c002023-05-09 13:06:05 +0000106static constexpr int32_t POINTER_2_UP =
107 AMOTION_EVENT_ACTION_POINTER_UP | (2 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT);
Siarhei Vishniakoua16e3a22022-03-02 15:26:40 -0800108
Antonio Kantek15beb512022-06-13 22:35:41 +0000109// The default pid and uid for windows created on the primary display by the test.
Prabir Pradhanaeebeb42023-06-13 19:53:03 +0000110static constexpr gui::Pid WINDOW_PID{999};
Prabir Pradhan8a5c41d2023-06-08 19:13:46 +0000111static constexpr gui::Uid WINDOW_UID{1001};
Prabir Pradhan5735a322022-04-11 17:23:34 +0000112
Antonio Kantek15beb512022-06-13 22:35:41 +0000113// The default pid and uid for the windows created on the secondary display by the test.
Prabir Pradhanaeebeb42023-06-13 19:53:03 +0000114static constexpr gui::Pid SECONDARY_WINDOW_PID{1010};
Prabir Pradhan8a5c41d2023-06-08 19:13:46 +0000115static constexpr gui::Uid SECONDARY_WINDOW_UID{1012};
Antonio Kantek15beb512022-06-13 22:35:41 +0000116
Siarhei Vishniakou58cfc602020-12-14 23:21:30 +0000117// An arbitrary pid of the gesture monitor window
Prabir Pradhanaeebeb42023-06-13 19:53:03 +0000118static constexpr gui::Pid MONITOR_PID{2001};
Siarhei Vishniakou58cfc602020-12-14 23:21:30 +0000119
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -0700120/**
121 * If we expect to receive the event, the timeout can be made very long. When the test are running
122 * correctly, we will actually never wait until the end of the timeout because the wait will end
123 * when the event comes in. Still, this value shouldn't be infinite. During development, a local
124 * change may cause the test to fail. This timeout should be short enough to not annoy so that the
125 * developer can see the failure quickly (on human scale).
126 */
127static constexpr std::chrono::duration CONSUME_TIMEOUT_EVENT_EXPECTED = 1000ms;
128/**
129 * When no event is expected, we can have a very short timeout. A large value here would slow down
130 * the tests. In the unlikely event of system being too slow, the event may still be present but the
131 * timeout would complete before it is consumed. This would result in test flakiness. If this
132 * occurs, the flakiness rate would be high. Since the flakes are treated with high priority, this
133 * would get noticed and addressed quickly.
134 */
135static constexpr std::chrono::duration CONSUME_TIMEOUT_NO_EVENT_EXPECTED = 10ms;
136
Arthur Hungc539dbb2022-12-08 07:45:36 +0000137static constexpr int expectedWallpaperFlags =
138 AMOTION_EVENT_FLAG_WINDOW_IS_OBSCURED | AMOTION_EVENT_FLAG_WINDOW_IS_PARTIALLY_OBSCURED;
139
Siarhei Vishniakou56e79092023-02-21 19:13:16 -0800140using ReservedInputDeviceId::VIRTUAL_KEYBOARD_ID;
141
Gang Wang342c9272020-01-13 13:15:04 -0500142/**
143 * Return a DOWN key event with KEYCODE_A.
144 */
145static KeyEvent getTestKeyEvent() {
146 KeyEvent event;
147
Garfield Tanfbe732e2020-01-24 11:26:14 -0800148 event.initialize(InputEvent::nextId(), DEVICE_ID, AINPUT_SOURCE_KEYBOARD, ADISPLAY_ID_NONE,
149 INVALID_HMAC, AKEY_EVENT_ACTION_DOWN, 0, AKEYCODE_A, KEY_A, AMETA_NONE, 0,
150 ARBITRARY_TIME, ARBITRARY_TIME);
Gang Wang342c9272020-01-13 13:15:04 -0500151 return event;
152}
153
Michael Wrightd02c5b62014-02-10 15:10:22 -0800154// --- FakeInputDispatcherPolicy ---
155
156class FakeInputDispatcherPolicy : public InputDispatcherPolicyInterface {
Prabir Pradhanaeebeb42023-06-13 19:53:03 +0000157 struct AnrResult {
158 sp<IBinder> token{};
Prabir Pradhanfc364722024-02-08 17:51:20 +0000159 std::optional<gui::Pid> pid{};
Prabir Pradhanaeebeb42023-06-13 19:53:03 +0000160 };
Yeabkal Wubshitb8aadfa2024-01-17 17:03:42 -0800161 /* Stores data about a user-activity-poke event from the dispatcher. */
162 struct UserActivityPokeEvent {
163 nsecs_t eventTime;
164 int32_t eventType;
165 int32_t displayId;
166
167 bool operator==(const UserActivityPokeEvent& rhs) const = default;
168
169 friend std::ostream& operator<<(std::ostream& os, const UserActivityPokeEvent& ev) {
170 os << "UserActivityPokeEvent[time=" << ev.eventTime << ", eventType=" << ev.eventType
171 << ", displayId=" << ev.displayId << "]";
172 return os;
173 }
174 };
Prabir Pradhanedd96402022-02-15 01:46:16 -0800175
Michael Wrightd02c5b62014-02-10 15:10:22 -0800176public:
Prabir Pradhana41d2442023-04-20 21:30:40 +0000177 FakeInputDispatcherPolicy() = default;
178 virtual ~FakeInputDispatcherPolicy() = default;
Jackal Guof9696682018-10-05 12:23:23 +0800179
Siarhei Vishniakou8935a802019-11-15 16:41:44 -0800180 void assertFilterInputEventWasCalled(const NotifyKeyArgs& args) {
Prabir Pradhan81420cc2021-09-06 10:28:50 -0700181 assertFilterInputEventWasCalledInternal([&args](const InputEvent& event) {
Siarhei Vishniakou63b63612023-04-12 11:00:23 -0700182 ASSERT_EQ(event.getType(), InputEventType::KEY);
Prabir Pradhan81420cc2021-09-06 10:28:50 -0700183 EXPECT_EQ(event.getDisplayId(), args.displayId);
184
185 const auto& keyEvent = static_cast<const KeyEvent&>(event);
186 EXPECT_EQ(keyEvent.getEventTime(), args.eventTime);
187 EXPECT_EQ(keyEvent.getAction(), args.action);
188 });
Jackal Guof9696682018-10-05 12:23:23 +0800189 }
190
Prabir Pradhan81420cc2021-09-06 10:28:50 -0700191 void assertFilterInputEventWasCalled(const NotifyMotionArgs& args, vec2 point) {
192 assertFilterInputEventWasCalledInternal([&](const InputEvent& event) {
Siarhei Vishniakou63b63612023-04-12 11:00:23 -0700193 ASSERT_EQ(event.getType(), InputEventType::MOTION);
Prabir Pradhan81420cc2021-09-06 10:28:50 -0700194 EXPECT_EQ(event.getDisplayId(), args.displayId);
195
196 const auto& motionEvent = static_cast<const MotionEvent&>(event);
197 EXPECT_EQ(motionEvent.getEventTime(), args.eventTime);
198 EXPECT_EQ(motionEvent.getAction(), args.action);
Prabir Pradhan00e029d2023-03-09 20:11:09 +0000199 EXPECT_NEAR(motionEvent.getX(0), point.x, MotionEvent::ROUNDING_PRECISION);
200 EXPECT_NEAR(motionEvent.getY(0), point.y, MotionEvent::ROUNDING_PRECISION);
201 EXPECT_NEAR(motionEvent.getRawX(0), point.x, MotionEvent::ROUNDING_PRECISION);
202 EXPECT_NEAR(motionEvent.getRawY(0), point.y, MotionEvent::ROUNDING_PRECISION);
Prabir Pradhan81420cc2021-09-06 10:28:50 -0700203 });
Jackal Guof9696682018-10-05 12:23:23 +0800204 }
205
Siarhei Vishniakoucd899e82020-05-08 09:24:29 -0700206 void assertFilterInputEventWasNotCalled() {
207 std::scoped_lock lock(mLock);
208 ASSERT_EQ(nullptr, mFilteredEvent);
209 }
Michael Wrightd02c5b62014-02-10 15:10:22 -0800210
Siarhei Vishniakou2bfa9052019-11-21 18:10:54 -0800211 void assertNotifyConfigurationChangedWasCalled(nsecs_t when) {
Siarhei Vishniakoucd899e82020-05-08 09:24:29 -0700212 std::scoped_lock lock(mLock);
Siarhei Vishniakou2bfa9052019-11-21 18:10:54 -0800213 ASSERT_TRUE(mConfigurationChangedTime)
214 << "Timed out waiting for configuration changed call";
215 ASSERT_EQ(*mConfigurationChangedTime, when);
216 mConfigurationChangedTime = std::nullopt;
217 }
218
219 void assertNotifySwitchWasCalled(const NotifySwitchArgs& args) {
Siarhei Vishniakoucd899e82020-05-08 09:24:29 -0700220 std::scoped_lock lock(mLock);
Siarhei Vishniakou2bfa9052019-11-21 18:10:54 -0800221 ASSERT_TRUE(mLastNotifySwitch);
Garfield Tanc51d1ba2020-01-28 13:24:04 -0800222 // We do not check id because it is not exposed to the policy
Siarhei Vishniakou2bfa9052019-11-21 18:10:54 -0800223 EXPECT_EQ(args.eventTime, mLastNotifySwitch->eventTime);
224 EXPECT_EQ(args.policyFlags, mLastNotifySwitch->policyFlags);
225 EXPECT_EQ(args.switchValues, mLastNotifySwitch->switchValues);
226 EXPECT_EQ(args.switchMask, mLastNotifySwitch->switchMask);
227 mLastNotifySwitch = std::nullopt;
228 }
229
chaviwfd6d3512019-03-25 13:23:49 -0700230 void assertOnPointerDownEquals(const sp<IBinder>& touchedToken) {
Siarhei Vishniakoucd899e82020-05-08 09:24:29 -0700231 std::scoped_lock lock(mLock);
Siarhei Vishniakou2bfa9052019-11-21 18:10:54 -0800232 ASSERT_EQ(touchedToken, mOnPointerDownToken);
233 mOnPointerDownToken.clear();
234 }
235
236 void assertOnPointerDownWasNotCalled() {
Siarhei Vishniakoucd899e82020-05-08 09:24:29 -0700237 std::scoped_lock lock(mLock);
Siarhei Vishniakou2bfa9052019-11-21 18:10:54 -0800238 ASSERT_TRUE(mOnPointerDownToken == nullptr)
239 << "Expected onPointerDownOutsideFocus to not have been called";
chaviwfd6d3512019-03-25 13:23:49 -0700240 }
241
Siarhei Vishniakou4cb50ca2020-05-26 21:43:02 -0700242 // This function must be called soon after the expected ANR timer starts,
243 // because we are also checking how much time has passed.
Siarhei Vishniakou234129c2020-10-22 22:28:12 -0500244 void assertNotifyNoFocusedWindowAnrWasCalled(
Chris Yea209fde2020-07-22 13:54:51 -0700245 std::chrono::nanoseconds timeout,
Siarhei Vishniakou234129c2020-10-22 22:28:12 -0500246 const std::shared_ptr<InputApplicationHandle>& expectedApplication) {
Prabir Pradhanedd96402022-02-15 01:46:16 -0800247 std::unique_lock lock(mLock);
248 android::base::ScopedLockAssertion assumeLocked(mLock);
Siarhei Vishniakou234129c2020-10-22 22:28:12 -0500249 std::shared_ptr<InputApplicationHandle> application;
Prabir Pradhanedd96402022-02-15 01:46:16 -0800250 ASSERT_NO_FATAL_FAILURE(
251 application = getAnrTokenLockedInterruptible(timeout, mAnrApplications, lock));
Siarhei Vishniakou234129c2020-10-22 22:28:12 -0500252 ASSERT_EQ(expectedApplication, application);
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -0700253 }
254
Siarhei Vishniakou3c63fa42020-12-15 02:59:54 +0000255 void assertNotifyWindowUnresponsiveWasCalled(std::chrono::nanoseconds timeout,
Prabir Pradhanedd96402022-02-15 01:46:16 -0800256 const sp<WindowInfoHandle>& window) {
257 LOG_ALWAYS_FATAL_IF(window == nullptr, "window should not be null");
258 assertNotifyWindowUnresponsiveWasCalled(timeout, window->getToken(),
259 window->getInfo()->ownerPid);
Siarhei Vishniakou234129c2020-10-22 22:28:12 -0500260 }
261
Prabir Pradhanedd96402022-02-15 01:46:16 -0800262 void assertNotifyWindowUnresponsiveWasCalled(std::chrono::nanoseconds timeout,
263 const sp<IBinder>& expectedToken,
Prabir Pradhanfc364722024-02-08 17:51:20 +0000264 std::optional<gui::Pid> expectedPid) {
Prabir Pradhanedd96402022-02-15 01:46:16 -0800265 std::unique_lock lock(mLock);
266 android::base::ScopedLockAssertion assumeLocked(mLock);
267 AnrResult result;
268 ASSERT_NO_FATAL_FAILURE(result =
269 getAnrTokenLockedInterruptible(timeout, mAnrWindows, lock));
Prabir Pradhanaeebeb42023-06-13 19:53:03 +0000270 ASSERT_EQ(expectedToken, result.token);
271 ASSERT_EQ(expectedPid, result.pid);
Siarhei Vishniakou234129c2020-10-22 22:28:12 -0500272 }
273
Prabir Pradhanedd96402022-02-15 01:46:16 -0800274 /** Wrap call with ASSERT_NO_FATAL_FAILURE() to ensure the return value is valid. */
Siarhei Vishniakou3c63fa42020-12-15 02:59:54 +0000275 sp<IBinder> getUnresponsiveWindowToken(std::chrono::nanoseconds timeout) {
Siarhei Vishniakou234129c2020-10-22 22:28:12 -0500276 std::unique_lock lock(mLock);
277 android::base::ScopedLockAssertion assumeLocked(mLock);
Prabir Pradhanedd96402022-02-15 01:46:16 -0800278 AnrResult result = getAnrTokenLockedInterruptible(timeout, mAnrWindows, lock);
279 const auto& [token, _] = result;
280 return token;
Siarhei Vishniakou3c63fa42020-12-15 02:59:54 +0000281 }
282
Prabir Pradhanedd96402022-02-15 01:46:16 -0800283 void assertNotifyWindowResponsiveWasCalled(const sp<IBinder>& expectedToken,
Prabir Pradhanfc364722024-02-08 17:51:20 +0000284 std::optional<gui::Pid> expectedPid) {
Prabir Pradhanedd96402022-02-15 01:46:16 -0800285 std::unique_lock lock(mLock);
286 android::base::ScopedLockAssertion assumeLocked(mLock);
287 AnrResult result;
288 ASSERT_NO_FATAL_FAILURE(
289 result = getAnrTokenLockedInterruptible(0s, mResponsiveWindows, lock));
Prabir Pradhanaeebeb42023-06-13 19:53:03 +0000290 ASSERT_EQ(expectedToken, result.token);
291 ASSERT_EQ(expectedPid, result.pid);
Prabir Pradhanedd96402022-02-15 01:46:16 -0800292 }
293
294 /** Wrap call with ASSERT_NO_FATAL_FAILURE() to ensure the return value is valid. */
Siarhei Vishniakou3c63fa42020-12-15 02:59:54 +0000295 sp<IBinder> getResponsiveWindowToken() {
296 std::unique_lock lock(mLock);
297 android::base::ScopedLockAssertion assumeLocked(mLock);
Prabir Pradhanedd96402022-02-15 01:46:16 -0800298 AnrResult result = getAnrTokenLockedInterruptible(0s, mResponsiveWindows, lock);
299 const auto& [token, _] = result;
300 return token;
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -0700301 }
302
303 void assertNotifyAnrWasNotCalled() {
304 std::scoped_lock lock(mLock);
305 ASSERT_TRUE(mAnrApplications.empty());
Prabir Pradhanedd96402022-02-15 01:46:16 -0800306 ASSERT_TRUE(mAnrWindows.empty());
307 ASSERT_TRUE(mResponsiveWindows.empty())
Siarhei Vishniakou234129c2020-10-22 22:28:12 -0500308 << "ANR was not called, but please also consume the 'connection is responsive' "
309 "signal";
Siarhei Vishniakou4cb50ca2020-05-26 21:43:02 -0700310 }
311
Hiroki Sato25040232024-02-22 17:21:22 +0900312 PointerCaptureRequest assertSetPointerCaptureCalled(const sp<WindowInfoHandle>& window,
313 bool enabled) {
Prabir Pradhan99987712020-11-10 18:43:05 -0800314 std::unique_lock lock(mLock);
315 base::ScopedLockAssertion assumeLocked(mLock);
316
Hiroki Sato25040232024-02-22 17:21:22 +0900317 if (!mPointerCaptureChangedCondition
318 .wait_for(lock, 100ms, [this, enabled, window]() REQUIRES(mLock) {
319 if (enabled) {
320 return mPointerCaptureRequest->isEnable() &&
321 mPointerCaptureRequest->window == window->getToken();
322 } else {
323 return !mPointerCaptureRequest->isEnable();
324 }
325 })) {
326 ADD_FAILURE() << "Timed out waiting for setPointerCapture(" << window->getName() << ", "
327 << enabled << ") to be called.";
Prabir Pradhan5cc1a692021-08-06 14:01:18 +0000328 return {};
Prabir Pradhan99987712020-11-10 18:43:05 -0800329 }
Prabir Pradhan5cc1a692021-08-06 14:01:18 +0000330 auto request = *mPointerCaptureRequest;
331 mPointerCaptureRequest.reset();
332 return request;
Prabir Pradhan99987712020-11-10 18:43:05 -0800333 }
334
335 void assertSetPointerCaptureNotCalled() {
336 std::unique_lock lock(mLock);
337 base::ScopedLockAssertion assumeLocked(mLock);
338
339 if (mPointerCaptureChangedCondition.wait_for(lock, 100ms) != std::cv_status::timeout) {
Prabir Pradhan5cc1a692021-08-06 14:01:18 +0000340 FAIL() << "Expected setPointerCapture(request) to not be called, but was called. "
Prabir Pradhan99987712020-11-10 18:43:05 -0800341 "enabled = "
Hiroki Sato25040232024-02-22 17:21:22 +0900342 << std::to_string(mPointerCaptureRequest->isEnable());
Prabir Pradhan99987712020-11-10 18:43:05 -0800343 }
Prabir Pradhan5cc1a692021-08-06 14:01:18 +0000344 mPointerCaptureRequest.reset();
Prabir Pradhan99987712020-11-10 18:43:05 -0800345 }
346
Siarhei Vishniakoua66d65e2023-06-16 10:32:51 -0700347 void assertDropTargetEquals(const InputDispatcherInterface& dispatcher,
348 const sp<IBinder>& targetToken) {
349 dispatcher.waitForIdle();
arthurhungf452d0b2021-01-06 00:19:52 +0800350 std::scoped_lock lock(mLock);
Arthur Hung6d0571e2021-04-09 20:18:16 +0800351 ASSERT_TRUE(mNotifyDropWindowWasCalled);
arthurhungf452d0b2021-01-06 00:19:52 +0800352 ASSERT_EQ(targetToken, mDropTargetWindowToken);
Arthur Hung6d0571e2021-04-09 20:18:16 +0800353 mNotifyDropWindowWasCalled = false;
arthurhungf452d0b2021-01-06 00:19:52 +0800354 }
355
Siarhei Vishniakou7aa3e942021-11-18 09:49:11 -0800356 void assertNotifyInputChannelBrokenWasCalled(const sp<IBinder>& token) {
357 std::unique_lock lock(mLock);
358 base::ScopedLockAssertion assumeLocked(mLock);
359 std::optional<sp<IBinder>> receivedToken =
360 getItemFromStorageLockedInterruptible(100ms, mBrokenInputChannels, lock,
361 mNotifyInputChannelBroken);
Prabir Pradhanb0dad3a2023-11-02 20:52:47 +0000362 ASSERT_TRUE(receivedToken.has_value()) << "Did not receive the broken channel token";
Siarhei Vishniakou7aa3e942021-11-18 09:49:11 -0800363 ASSERT_EQ(token, *receivedToken);
364 }
365
Arthur Hung2ee6d0b2022-03-03 20:19:38 +0800366 /**
367 * Set policy timeout. A value of zero means next key will not be intercepted.
368 */
369 void setInterceptKeyTimeout(std::chrono::milliseconds timeout) {
370 mInterceptKeyTimeout = timeout;
371 }
372
Siarhei Vishniakouef2b4502023-12-28 11:51:47 -0800373 std::chrono::nanoseconds getKeyWaitingForEventsTimeout() override { return 500ms; }
374
Siarhei Vishniakoua7333112023-10-27 13:33:29 -0700375 void setStaleEventTimeout(std::chrono::nanoseconds timeout) { mStaleEventTimeout = timeout; }
376
Yeabkal Wubshitb8aadfa2024-01-17 17:03:42 -0800377 void assertUserActivityNotPoked() {
378 std::unique_lock lock(mLock);
379 base::ScopedLockAssertion assumeLocked(mLock);
380
381 std::optional<UserActivityPokeEvent> pokeEvent =
382 getItemFromStorageLockedInterruptible(500ms, mUserActivityPokeEvents, lock,
383 mNotifyUserActivity);
384
385 ASSERT_FALSE(pokeEvent) << "Expected user activity not to have been poked";
Josep del Riob3981622023-04-18 15:49:45 +0000386 }
387
Yeabkal Wubshitb8aadfa2024-01-17 17:03:42 -0800388 /**
389 * Asserts that a user activity poke has happened. The earliest recorded poke event will be
390 * cleared after this call.
391 *
392 * If an expected UserActivityPokeEvent is provided, asserts that the given event is the
393 * earliest recorded poke event.
394 */
395 void assertUserActivityPoked(std::optional<UserActivityPokeEvent> expectedPokeEvent = {}) {
396 std::unique_lock lock(mLock);
397 base::ScopedLockAssertion assumeLocked(mLock);
398
399 std::optional<UserActivityPokeEvent> pokeEvent =
400 getItemFromStorageLockedInterruptible(500ms, mUserActivityPokeEvents, lock,
401 mNotifyUserActivity);
402 ASSERT_TRUE(pokeEvent) << "Expected a user poke event";
403
404 if (expectedPokeEvent) {
405 ASSERT_EQ(expectedPokeEvent, *pokeEvent);
406 }
Josep del Riob3981622023-04-18 15:49:45 +0000407 }
408
Prabir Pradhan8a5c41d2023-06-08 19:13:46 +0000409 void assertNotifyDeviceInteractionWasCalled(int32_t deviceId, std::set<gui::Uid> uids) {
Prabir Pradhan8ede1d12023-05-08 19:37:44 +0000410 ASSERT_EQ(std::make_pair(deviceId, uids), mNotifiedInteractions.popWithTimeout(100ms));
411 }
412
413 void assertNotifyDeviceInteractionWasNotCalled() {
414 ASSERT_FALSE(mNotifiedInteractions.popWithTimeout(10ms));
415 }
416
Prabir Pradhanb0dad3a2023-11-02 20:52:47 +0000417 void setUnhandledKeyHandler(std::function<std::optional<KeyEvent>(const KeyEvent&)> handler) {
418 std::scoped_lock lock(mLock);
419 mUnhandledKeyHandler = handler;
420 }
421
422 void assertUnhandledKeyReported(int32_t keycode) {
423 std::unique_lock lock(mLock);
424 base::ScopedLockAssertion assumeLocked(mLock);
425 std::optional<int32_t> unhandledKeycode =
426 getItemFromStorageLockedInterruptible(100ms, mReportedUnhandledKeycodes, lock,
427 mNotifyUnhandledKey);
428 ASSERT_TRUE(unhandledKeycode) << "Expected unhandled key to be reported";
429 ASSERT_EQ(unhandledKeycode, keycode);
430 }
431
432 void assertUnhandledKeyNotReported() {
433 std::unique_lock lock(mLock);
434 base::ScopedLockAssertion assumeLocked(mLock);
435 std::optional<int32_t> unhandledKeycode =
436 getItemFromStorageLockedInterruptible(10ms, mReportedUnhandledKeycodes, lock,
437 mNotifyUnhandledKey);
438 ASSERT_FALSE(unhandledKeycode) << "Expected unhandled key NOT to be reported";
439 }
440
Michael Wrightd02c5b62014-02-10 15:10:22 -0800441private:
Siarhei Vishniakoucd899e82020-05-08 09:24:29 -0700442 std::mutex mLock;
443 std::unique_ptr<InputEvent> mFilteredEvent GUARDED_BY(mLock);
444 std::optional<nsecs_t> mConfigurationChangedTime GUARDED_BY(mLock);
445 sp<IBinder> mOnPointerDownToken GUARDED_BY(mLock);
446 std::optional<NotifySwitchArgs> mLastNotifySwitch GUARDED_BY(mLock);
Jackal Guof9696682018-10-05 12:23:23 +0800447
Prabir Pradhan99987712020-11-10 18:43:05 -0800448 std::condition_variable mPointerCaptureChangedCondition;
Prabir Pradhan5cc1a692021-08-06 14:01:18 +0000449
450 std::optional<PointerCaptureRequest> mPointerCaptureRequest GUARDED_BY(mLock);
Prabir Pradhan99987712020-11-10 18:43:05 -0800451
Siarhei Vishniakou4cb50ca2020-05-26 21:43:02 -0700452 // ANR handling
Chris Yea209fde2020-07-22 13:54:51 -0700453 std::queue<std::shared_ptr<InputApplicationHandle>> mAnrApplications GUARDED_BY(mLock);
Prabir Pradhanedd96402022-02-15 01:46:16 -0800454 std::queue<AnrResult> mAnrWindows GUARDED_BY(mLock);
455 std::queue<AnrResult> mResponsiveWindows GUARDED_BY(mLock);
Siarhei Vishniakou4cb50ca2020-05-26 21:43:02 -0700456 std::condition_variable mNotifyAnr;
Siarhei Vishniakou7aa3e942021-11-18 09:49:11 -0800457 std::queue<sp<IBinder>> mBrokenInputChannels GUARDED_BY(mLock);
458 std::condition_variable mNotifyInputChannelBroken;
Siarhei Vishniakou4cb50ca2020-05-26 21:43:02 -0700459
arthurhungf452d0b2021-01-06 00:19:52 +0800460 sp<IBinder> mDropTargetWindowToken GUARDED_BY(mLock);
Arthur Hung6d0571e2021-04-09 20:18:16 +0800461 bool mNotifyDropWindowWasCalled GUARDED_BY(mLock) = false;
Yeabkal Wubshitb8aadfa2024-01-17 17:03:42 -0800462
463 std::condition_variable mNotifyUserActivity;
464 std::queue<UserActivityPokeEvent> mUserActivityPokeEvents;
arthurhungf452d0b2021-01-06 00:19:52 +0800465
Arthur Hung2ee6d0b2022-03-03 20:19:38 +0800466 std::chrono::milliseconds mInterceptKeyTimeout = 0ms;
467
Siarhei Vishniakoua7333112023-10-27 13:33:29 -0700468 std::chrono::nanoseconds mStaleEventTimeout = 1000ms;
469
Prabir Pradhan8a5c41d2023-06-08 19:13:46 +0000470 BlockingQueue<std::pair<int32_t /*deviceId*/, std::set<gui::Uid>>> mNotifiedInteractions;
Prabir Pradhan8ede1d12023-05-08 19:37:44 +0000471
Prabir Pradhanb0dad3a2023-11-02 20:52:47 +0000472 std::condition_variable mNotifyUnhandledKey;
473 std::queue<int32_t> mReportedUnhandledKeycodes GUARDED_BY(mLock);
474 std::function<std::optional<KeyEvent>(const KeyEvent&)> mUnhandledKeyHandler GUARDED_BY(mLock);
475
Prabir Pradhanedd96402022-02-15 01:46:16 -0800476 // All three ANR-related callbacks behave the same way, so we use this generic function to wait
477 // for a specific container to become non-empty. When the container is non-empty, return the
478 // first entry from the container and erase it.
479 template <class T>
480 T getAnrTokenLockedInterruptible(std::chrono::nanoseconds timeout, std::queue<T>& storage,
481 std::unique_lock<std::mutex>& lock) REQUIRES(mLock) {
482 // If there is an ANR, Dispatcher won't be idle because there are still events
483 // in the waitQueue that we need to check on. So we can't wait for dispatcher to be idle
484 // before checking if ANR was called.
485 // Since dispatcher is not guaranteed to call notifyNoFocusedWindowAnr right away, we need
486 // to provide it some time to act. 100ms seems reasonable.
487 std::chrono::duration timeToWait = timeout + 100ms; // provide some slack
488 const std::chrono::time_point start = std::chrono::steady_clock::now();
489 std::optional<T> token =
490 getItemFromStorageLockedInterruptible(timeToWait, storage, lock, mNotifyAnr);
491 if (!token.has_value()) {
492 ADD_FAILURE() << "Did not receive the ANR callback";
493 return {};
494 }
495
496 const std::chrono::duration waited = std::chrono::steady_clock::now() - start;
497 // Ensure that the ANR didn't get raised too early. We can't be too strict here because
498 // the dispatcher started counting before this function was called
499 if (std::chrono::abs(timeout - waited) > 100ms) {
500 ADD_FAILURE() << "ANR was raised too early or too late. Expected "
501 << std::chrono::duration_cast<std::chrono::milliseconds>(timeout).count()
502 << "ms, but waited "
503 << std::chrono::duration_cast<std::chrono::milliseconds>(waited).count()
504 << "ms instead";
505 }
506 return *token;
507 }
508
509 template <class T>
510 std::optional<T> getItemFromStorageLockedInterruptible(std::chrono::nanoseconds timeout,
511 std::queue<T>& storage,
512 std::unique_lock<std::mutex>& lock,
513 std::condition_variable& condition)
514 REQUIRES(mLock) {
515 condition.wait_for(lock, timeout,
516 [&storage]() REQUIRES(mLock) { return !storage.empty(); });
517 if (storage.empty()) {
Prabir Pradhanedd96402022-02-15 01:46:16 -0800518 return std::nullopt;
519 }
520 T item = storage.front();
521 storage.pop();
522 return std::make_optional(item);
523 }
524
Siarhei Vishniakou2b4782c2020-11-07 01:51:18 -0600525 void notifyConfigurationChanged(nsecs_t when) override {
Siarhei Vishniakoucd899e82020-05-08 09:24:29 -0700526 std::scoped_lock lock(mLock);
Siarhei Vishniakou2bfa9052019-11-21 18:10:54 -0800527 mConfigurationChangedTime = when;
Michael Wrightd02c5b62014-02-10 15:10:22 -0800528 }
529
Prabir Pradhanaeebeb42023-06-13 19:53:03 +0000530 void notifyWindowUnresponsive(const sp<IBinder>& connectionToken, std::optional<gui::Pid> pid,
Prabir Pradhanedd96402022-02-15 01:46:16 -0800531 const std::string&) override {
Siarhei Vishniakou4cb50ca2020-05-26 21:43:02 -0700532 std::scoped_lock lock(mLock);
Prabir Pradhanfc364722024-02-08 17:51:20 +0000533 mAnrWindows.push({connectionToken, pid});
Siarhei Vishniakou4cb50ca2020-05-26 21:43:02 -0700534 mNotifyAnr.notify_all();
Siarhei Vishniakou234129c2020-10-22 22:28:12 -0500535 }
536
Prabir Pradhanedd96402022-02-15 01:46:16 -0800537 void notifyWindowResponsive(const sp<IBinder>& connectionToken,
Prabir Pradhanaeebeb42023-06-13 19:53:03 +0000538 std::optional<gui::Pid> pid) override {
Siarhei Vishniakou234129c2020-10-22 22:28:12 -0500539 std::scoped_lock lock(mLock);
Prabir Pradhanfc364722024-02-08 17:51:20 +0000540 mResponsiveWindows.push({connectionToken, pid});
Siarhei Vishniakou234129c2020-10-22 22:28:12 -0500541 mNotifyAnr.notify_all();
542 }
543
544 void notifyNoFocusedWindowAnr(
545 const std::shared_ptr<InputApplicationHandle>& applicationHandle) override {
546 std::scoped_lock lock(mLock);
547 mAnrApplications.push(applicationHandle);
548 mNotifyAnr.notify_all();
Michael Wrightd02c5b62014-02-10 15:10:22 -0800549 }
550
Siarhei Vishniakou7aa3e942021-11-18 09:49:11 -0800551 void notifyInputChannelBroken(const sp<IBinder>& connectionToken) override {
552 std::scoped_lock lock(mLock);
553 mBrokenInputChannels.push(connectionToken);
554 mNotifyInputChannelBroken.notify_all();
555 }
Michael Wrightd02c5b62014-02-10 15:10:22 -0800556
Siarhei Vishniakou2b4782c2020-11-07 01:51:18 -0600557 void notifyFocusChanged(const sp<IBinder>&, const sp<IBinder>&) override {}
Robert Carr740167f2018-10-11 19:03:41 -0700558
Chris Yef59a2f42020-10-16 12:55:26 -0700559 void notifySensorEvent(int32_t deviceId, InputDeviceSensorType sensorType,
560 InputDeviceSensorAccuracy accuracy, nsecs_t timestamp,
561 const std::vector<float>& values) override {}
562
563 void notifySensorAccuracy(int deviceId, InputDeviceSensorType sensorType,
564 InputDeviceSensorAccuracy accuracy) override {}
Bernardo Rufino2e1f6512020-10-08 13:42:07 +0000565
Chris Yefb552902021-02-03 17:18:37 -0800566 void notifyVibratorState(int32_t deviceId, bool isOn) override {}
567
Prabir Pradhana41d2442023-04-20 21:30:40 +0000568 bool filterInputEvent(const InputEvent& inputEvent, uint32_t policyFlags) override {
Siarhei Vishniakoucd899e82020-05-08 09:24:29 -0700569 std::scoped_lock lock(mLock);
Prabir Pradhana41d2442023-04-20 21:30:40 +0000570 switch (inputEvent.getType()) {
Siarhei Vishniakou63b63612023-04-12 11:00:23 -0700571 case InputEventType::KEY: {
Prabir Pradhana41d2442023-04-20 21:30:40 +0000572 const KeyEvent& keyEvent = static_cast<const KeyEvent&>(inputEvent);
573 mFilteredEvent = std::make_unique<KeyEvent>(keyEvent);
Jackal Guof9696682018-10-05 12:23:23 +0800574 break;
575 }
576
Siarhei Vishniakou63b63612023-04-12 11:00:23 -0700577 case InputEventType::MOTION: {
Prabir Pradhana41d2442023-04-20 21:30:40 +0000578 const MotionEvent& motionEvent = static_cast<const MotionEvent&>(inputEvent);
579 mFilteredEvent = std::make_unique<MotionEvent>(motionEvent);
Jackal Guof9696682018-10-05 12:23:23 +0800580 break;
581 }
Siarhei Vishniakou63b63612023-04-12 11:00:23 -0700582 default: {
583 ADD_FAILURE() << "Should only filter keys or motions";
584 break;
585 }
Jackal Guof9696682018-10-05 12:23:23 +0800586 }
Michael Wrightd02c5b62014-02-10 15:10:22 -0800587 return true;
588 }
589
Prabir Pradhana41d2442023-04-20 21:30:40 +0000590 void interceptKeyBeforeQueueing(const KeyEvent& inputEvent, uint32_t&) override {
591 if (inputEvent.getAction() == AKEY_EVENT_ACTION_UP) {
Arthur Hung2ee6d0b2022-03-03 20:19:38 +0800592 // Clear intercept state when we handled the event.
593 mInterceptKeyTimeout = 0ms;
594 }
595 }
Michael Wrightd02c5b62014-02-10 15:10:22 -0800596
Yeabkal Wubshit88a90412023-12-21 18:23:04 -0800597 void interceptMotionBeforeQueueing(int32_t, uint32_t, int32_t, nsecs_t, uint32_t&) override {}
Michael Wrightd02c5b62014-02-10 15:10:22 -0800598
Prabir Pradhana41d2442023-04-20 21:30:40 +0000599 nsecs_t interceptKeyBeforeDispatching(const sp<IBinder>&, const KeyEvent&, uint32_t) override {
Arthur Hung2ee6d0b2022-03-03 20:19:38 +0800600 nsecs_t delay = std::chrono::nanoseconds(mInterceptKeyTimeout).count();
601 // Clear intercept state so we could dispatch the event in next wake.
602 mInterceptKeyTimeout = 0ms;
603 return delay;
Michael Wrightd02c5b62014-02-10 15:10:22 -0800604 }
605
Prabir Pradhanb0dad3a2023-11-02 20:52:47 +0000606 std::optional<KeyEvent> dispatchUnhandledKey(const sp<IBinder>&, const KeyEvent& event,
Prabir Pradhana41d2442023-04-20 21:30:40 +0000607 uint32_t) override {
Prabir Pradhanb0dad3a2023-11-02 20:52:47 +0000608 std::scoped_lock lock(mLock);
609 mReportedUnhandledKeycodes.emplace(event.getKeyCode());
610 mNotifyUnhandledKey.notify_all();
611 return mUnhandledKeyHandler != nullptr ? mUnhandledKeyHandler(event) : std::nullopt;
Michael Wrightd02c5b62014-02-10 15:10:22 -0800612 }
613
Siarhei Vishniakou2b4782c2020-11-07 01:51:18 -0600614 void notifySwitch(nsecs_t when, uint32_t switchValues, uint32_t switchMask,
615 uint32_t policyFlags) override {
Siarhei Vishniakoucd899e82020-05-08 09:24:29 -0700616 std::scoped_lock lock(mLock);
Siarhei Vishniakou2bfa9052019-11-21 18:10:54 -0800617 /** We simply reconstruct NotifySwitchArgs in policy because InputDispatcher is
618 * essentially a passthrough for notifySwitch.
619 */
Prabir Pradhana8fe7c52023-12-14 22:07:23 +0000620 mLastNotifySwitch =
621 NotifySwitchArgs(InputEvent::nextId(), when, policyFlags, switchValues, switchMask);
Michael Wrightd02c5b62014-02-10 15:10:22 -0800622 }
623
Yeabkal Wubshitb8aadfa2024-01-17 17:03:42 -0800624 void pokeUserActivity(nsecs_t eventTime, int32_t eventType, int32_t displayId) override {
Josep del Riob3981622023-04-18 15:49:45 +0000625 std::scoped_lock lock(mLock);
Yeabkal Wubshitb8aadfa2024-01-17 17:03:42 -0800626 mNotifyUserActivity.notify_all();
627 mUserActivityPokeEvents.push({eventTime, eventType, displayId});
Josep del Riob3981622023-04-18 15:49:45 +0000628 }
Michael Wrightd02c5b62014-02-10 15:10:22 -0800629
Siarhei Vishniakoua7333112023-10-27 13:33:29 -0700630 bool isStaleEvent(nsecs_t currentTime, nsecs_t eventTime) override {
631 return std::chrono::nanoseconds(currentTime - eventTime) >= mStaleEventTimeout;
632 }
633
Siarhei Vishniakou2b4782c2020-11-07 01:51:18 -0600634 void onPointerDownOutsideFocus(const sp<IBinder>& newToken) override {
Siarhei Vishniakoucd899e82020-05-08 09:24:29 -0700635 std::scoped_lock lock(mLock);
chaviwfd6d3512019-03-25 13:23:49 -0700636 mOnPointerDownToken = newToken;
637 }
638
Prabir Pradhan5cc1a692021-08-06 14:01:18 +0000639 void setPointerCapture(const PointerCaptureRequest& request) override {
Prabir Pradhan99987712020-11-10 18:43:05 -0800640 std::scoped_lock lock(mLock);
Prabir Pradhan5cc1a692021-08-06 14:01:18 +0000641 mPointerCaptureRequest = {request};
Prabir Pradhan99987712020-11-10 18:43:05 -0800642 mPointerCaptureChangedCondition.notify_all();
643 }
644
arthurhungf452d0b2021-01-06 00:19:52 +0800645 void notifyDropWindow(const sp<IBinder>& token, float x, float y) override {
646 std::scoped_lock lock(mLock);
Arthur Hung6d0571e2021-04-09 20:18:16 +0800647 mNotifyDropWindowWasCalled = true;
arthurhungf452d0b2021-01-06 00:19:52 +0800648 mDropTargetWindowToken = token;
649 }
650
Prabir Pradhan8ede1d12023-05-08 19:37:44 +0000651 void notifyDeviceInteraction(int32_t deviceId, nsecs_t timestamp,
Prabir Pradhan8a5c41d2023-06-08 19:13:46 +0000652 const std::set<gui::Uid>& uids) override {
Prabir Pradhan8ede1d12023-05-08 19:37:44 +0000653 ASSERT_TRUE(mNotifiedInteractions.emplace(deviceId, uids));
654 }
655
Prabir Pradhan81420cc2021-09-06 10:28:50 -0700656 void assertFilterInputEventWasCalledInternal(
657 const std::function<void(const InputEvent&)>& verify) {
Siarhei Vishniakoucd899e82020-05-08 09:24:29 -0700658 std::scoped_lock lock(mLock);
Siarhei Vishniakoud99e1b62019-11-26 11:01:06 -0800659 ASSERT_NE(nullptr, mFilteredEvent) << "Expected filterInputEvent() to have been called.";
Prabir Pradhan81420cc2021-09-06 10:28:50 -0700660 verify(*mFilteredEvent);
Siarhei Vishniakou8935a802019-11-15 16:41:44 -0800661 mFilteredEvent = nullptr;
Jackal Guof9696682018-10-05 12:23:23 +0800662 }
Michael Wrightd02c5b62014-02-10 15:10:22 -0800663};
Siarhei Vishniakouf4043212023-09-18 19:33:03 -0700664} // namespace
Michael Wrightd02c5b62014-02-10 15:10:22 -0800665
Michael Wrightd02c5b62014-02-10 15:10:22 -0800666// --- InputDispatcherTest ---
667
Prabir Pradhandc3a2ad2024-02-05 19:03:51 +0000668// The trace is a global variable for now, to avoid having to pass it into all of the
669// FakeWindowHandles created throughout the tests.
670// TODO(b/210460522): Update the tests to avoid the need to have the trace be a global variable.
671static std::shared_ptr<VerifyingTrace> gVerifyingTrace = std::make_shared<VerifyingTrace>();
672
Michael Wrightd02c5b62014-02-10 15:10:22 -0800673class InputDispatcherTest : public testing::Test {
674protected:
Prabir Pradhana41d2442023-04-20 21:30:40 +0000675 std::unique_ptr<FakeInputDispatcherPolicy> mFakePolicy;
Siarhei Vishniakou18050092021-09-01 13:32:49 -0700676 std::unique_ptr<InputDispatcher> mDispatcher;
Michael Wrightd02c5b62014-02-10 15:10:22 -0800677
Siarhei Vishniakouf2652122021-03-05 21:39:46 +0000678 void SetUp() override {
Prabir Pradhandc3a2ad2024-02-05 19:03:51 +0000679 gVerifyingTrace->reset();
Prabir Pradhana41d2442023-04-20 21:30:40 +0000680 mFakePolicy = std::make_unique<FakeInputDispatcherPolicy>();
Prabir Pradhandc3a2ad2024-02-05 19:03:51 +0000681 mDispatcher = std::make_unique<InputDispatcher>(*mFakePolicy,
682 std::make_unique<FakeInputTracingBackend>(
683 gVerifyingTrace));
Siarhei Vishniakoua7333112023-10-27 13:33:29 -0700684
Harry Cutts101ee9b2023-07-06 18:04:14 +0000685 mDispatcher->setInputDispatchMode(/*enabled=*/true, /*frozen=*/false);
Siarhei Vishniakou870ecec2020-12-09 08:07:46 -1000686 // Start InputDispatcher thread
Prabir Pradhan3608aad2019-10-02 17:08:26 -0700687 ASSERT_EQ(OK, mDispatcher->start());
Michael Wrightd02c5b62014-02-10 15:10:22 -0800688 }
689
Siarhei Vishniakouf2652122021-03-05 21:39:46 +0000690 void TearDown() override {
Prabir Pradhan0eaf1402024-02-05 22:43:04 +0000691 ASSERT_NO_FATAL_FAILURE(gVerifyingTrace->verifyExpectedEventsTraced());
Prabir Pradhan3608aad2019-10-02 17:08:26 -0700692 ASSERT_EQ(OK, mDispatcher->stop());
Prabir Pradhana41d2442023-04-20 21:30:40 +0000693 mFakePolicy.reset();
Siarhei Vishniakou18050092021-09-01 13:32:49 -0700694 mDispatcher.reset();
Michael Wrightd02c5b62014-02-10 15:10:22 -0800695 }
Siarhei Vishniakou4cb50ca2020-05-26 21:43:02 -0700696
697 /**
698 * Used for debugging when writing the test
699 */
700 void dumpDispatcherState() {
701 std::string dump;
702 mDispatcher->dump(dump);
703 std::stringstream ss(dump);
704 std::string to;
705
706 while (std::getline(ss, to, '\n')) {
707 ALOGE("%s", to.c_str());
708 }
709 }
Vishnu Nair958da932020-08-21 17:12:37 -0700710
Chavi Weingarten847e8512023-03-29 00:26:09 +0000711 void setFocusedWindow(const sp<WindowInfoHandle>& window) {
Vishnu Nair958da932020-08-21 17:12:37 -0700712 FocusRequest request;
713 request.token = window->getToken();
Siarhei Vishniakou5d552c42021-05-21 05:02:22 +0000714 request.windowName = window->getName();
Vishnu Nair958da932020-08-21 17:12:37 -0700715 request.timestamp = systemTime(SYSTEM_TIME_MONOTONIC);
716 request.displayId = window->getInfo()->displayId;
717 mDispatcher->setFocusedWindow(request);
718 }
Michael Wrightd02c5b62014-02-10 15:10:22 -0800719};
720
Michael Wrightd02c5b62014-02-10 15:10:22 -0800721TEST_F(InputDispatcherTest, InjectInputEvent_ValidatesKeyEvents) {
722 KeyEvent event;
723
724 // Rejects undefined key actions.
Garfield Tanfbe732e2020-01-24 11:26:14 -0800725 event.initialize(InputEvent::nextId(), DEVICE_ID, AINPUT_SOURCE_KEYBOARD, ADISPLAY_ID_NONE,
726 INVALID_HMAC,
Harry Cutts101ee9b2023-07-06 18:04:14 +0000727 /*action=*/-1, 0, AKEYCODE_A, KEY_A, AMETA_NONE, 0, ARBITRARY_TIME,
Siarhei Vishniakou9c858ac2020-01-23 14:20:11 -0600728 ARBITRARY_TIME);
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -0800729 ASSERT_EQ(InputEventInjectionResult::FAILED,
Harry Cutts33476232023-01-30 19:57:29 +0000730 mDispatcher->injectInputEvent(&event, /*targetUid=*/{}, InputEventInjectionSync::NONE,
Prabir Pradhan5735a322022-04-11 17:23:34 +0000731 0ms, 0))
Michael Wrightd02c5b62014-02-10 15:10:22 -0800732 << "Should reject key events with undefined action.";
733
734 // Rejects ACTION_MULTIPLE since it is not supported despite being defined in the API.
Garfield Tanfbe732e2020-01-24 11:26:14 -0800735 event.initialize(InputEvent::nextId(), DEVICE_ID, AINPUT_SOURCE_KEYBOARD, ADISPLAY_ID_NONE,
736 INVALID_HMAC, AKEY_EVENT_ACTION_MULTIPLE, 0, AKEYCODE_A, KEY_A, AMETA_NONE, 0,
Siarhei Vishniakou9c858ac2020-01-23 14:20:11 -0600737 ARBITRARY_TIME, ARBITRARY_TIME);
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -0800738 ASSERT_EQ(InputEventInjectionResult::FAILED,
Harry Cutts33476232023-01-30 19:57:29 +0000739 mDispatcher->injectInputEvent(&event, /*targetUid=*/{}, InputEventInjectionSync::NONE,
Prabir Pradhan5735a322022-04-11 17:23:34 +0000740 0ms, 0))
Michael Wrightd02c5b62014-02-10 15:10:22 -0800741 << "Should reject key events with ACTION_MULTIPLE.";
742}
743
744TEST_F(InputDispatcherTest, InjectInputEvent_ValidatesMotionEvents) {
745 MotionEvent event;
746 PointerProperties pointerProperties[MAX_POINTERS + 1];
747 PointerCoords pointerCoords[MAX_POINTERS + 1];
Siarhei Vishniakou01747382022-01-20 13:23:27 -0800748 for (size_t i = 0; i <= MAX_POINTERS; i++) {
Michael Wrightd02c5b62014-02-10 15:10:22 -0800749 pointerProperties[i].clear();
750 pointerProperties[i].id = i;
751 pointerCoords[i].clear();
752 }
753
Siarhei Vishniakou49e59222018-12-28 18:17:15 -0800754 // Some constants commonly used below
755 constexpr int32_t source = AINPUT_SOURCE_TOUCHSCREEN;
756 constexpr int32_t edgeFlags = AMOTION_EVENT_EDGE_FLAG_NONE;
757 constexpr int32_t metaState = AMETA_NONE;
758 constexpr MotionClassification classification = MotionClassification::NONE;
759
chaviw9eaa22c2020-07-01 16:21:27 -0700760 ui::Transform identityTransform;
Michael Wrightd02c5b62014-02-10 15:10:22 -0800761 // Rejects undefined motion actions.
Garfield Tanfbe732e2020-01-24 11:26:14 -0800762 event.initialize(InputEvent::nextId(), DEVICE_ID, source, DISPLAY_ID, INVALID_HMAC,
Harry Cutts101ee9b2023-07-06 18:04:14 +0000763 /*action=*/-1, 0, 0, edgeFlags, metaState, 0, classification,
chaviw9eaa22c2020-07-01 16:21:27 -0700764 identityTransform, 0, 0, AMOTION_EVENT_INVALID_CURSOR_POSITION,
Prabir Pradhanb9b18502021-08-26 12:30:32 -0700765 AMOTION_EVENT_INVALID_CURSOR_POSITION, identityTransform, ARBITRARY_TIME,
766 ARBITRARY_TIME,
Harry Cutts101ee9b2023-07-06 18:04:14 +0000767 /*pointerCount=*/1, pointerProperties, pointerCoords);
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -0800768 ASSERT_EQ(InputEventInjectionResult::FAILED,
Harry Cutts33476232023-01-30 19:57:29 +0000769 mDispatcher->injectInputEvent(&event, /*targetUid=*/{}, InputEventInjectionSync::NONE,
Prabir Pradhan5735a322022-04-11 17:23:34 +0000770 0ms, 0))
Michael Wrightd02c5b62014-02-10 15:10:22 -0800771 << "Should reject motion events with undefined action.";
772
773 // Rejects pointer down with invalid index.
Garfield Tanfbe732e2020-01-24 11:26:14 -0800774 event.initialize(InputEvent::nextId(), DEVICE_ID, source, DISPLAY_ID, INVALID_HMAC,
Siarhei Vishniakoua16e3a22022-03-02 15:26:40 -0800775 POINTER_1_DOWN, 0, 0, edgeFlags, metaState, 0, classification,
776 identityTransform, 0, 0, AMOTION_EVENT_INVALID_CURSOR_POSITION,
777 AMOTION_EVENT_INVALID_CURSOR_POSITION, identityTransform, ARBITRARY_TIME,
778 ARBITRARY_TIME,
Harry Cutts101ee9b2023-07-06 18:04:14 +0000779 /*pointerCount=*/1, pointerProperties, pointerCoords);
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -0800780 ASSERT_EQ(InputEventInjectionResult::FAILED,
Harry Cutts33476232023-01-30 19:57:29 +0000781 mDispatcher->injectInputEvent(&event, /*targetUid=*/{}, InputEventInjectionSync::NONE,
Prabir Pradhan5735a322022-04-11 17:23:34 +0000782 0ms, 0))
Michael Wrightd02c5b62014-02-10 15:10:22 -0800783 << "Should reject motion events with pointer down index too large.";
784
Garfield Tanfbe732e2020-01-24 11:26:14 -0800785 event.initialize(InputEvent::nextId(), DEVICE_ID, source, DISPLAY_ID, INVALID_HMAC,
Garfield Tan00f511d2019-06-12 16:55:40 -0700786 AMOTION_EVENT_ACTION_POINTER_DOWN |
787 (~0U << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT),
chaviw9eaa22c2020-07-01 16:21:27 -0700788 0, 0, edgeFlags, metaState, 0, classification, identityTransform, 0, 0,
789 AMOTION_EVENT_INVALID_CURSOR_POSITION, AMOTION_EVENT_INVALID_CURSOR_POSITION,
Prabir Pradhanb9b18502021-08-26 12:30:32 -0700790 identityTransform, ARBITRARY_TIME, ARBITRARY_TIME,
Harry Cutts101ee9b2023-07-06 18:04:14 +0000791 /*pointerCount=*/1, pointerProperties, pointerCoords);
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -0800792 ASSERT_EQ(InputEventInjectionResult::FAILED,
Harry Cutts33476232023-01-30 19:57:29 +0000793 mDispatcher->injectInputEvent(&event, /*targetUid=*/{}, InputEventInjectionSync::NONE,
Prabir Pradhan5735a322022-04-11 17:23:34 +0000794 0ms, 0))
Michael Wrightd02c5b62014-02-10 15:10:22 -0800795 << "Should reject motion events with pointer down index too small.";
796
797 // Rejects pointer up with invalid index.
Garfield Tanfbe732e2020-01-24 11:26:14 -0800798 event.initialize(InputEvent::nextId(), DEVICE_ID, source, DISPLAY_ID, INVALID_HMAC,
Siarhei Vishniakoua16e3a22022-03-02 15:26:40 -0800799 POINTER_1_UP, 0, 0, edgeFlags, metaState, 0, classification, identityTransform,
800 0, 0, AMOTION_EVENT_INVALID_CURSOR_POSITION,
801 AMOTION_EVENT_INVALID_CURSOR_POSITION, identityTransform, ARBITRARY_TIME,
802 ARBITRARY_TIME,
Harry Cutts101ee9b2023-07-06 18:04:14 +0000803 /*pointerCount=*/1, pointerProperties, pointerCoords);
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -0800804 ASSERT_EQ(InputEventInjectionResult::FAILED,
Harry Cutts33476232023-01-30 19:57:29 +0000805 mDispatcher->injectInputEvent(&event, /*targetUid=*/{}, InputEventInjectionSync::NONE,
Prabir Pradhan5735a322022-04-11 17:23:34 +0000806 0ms, 0))
Michael Wrightd02c5b62014-02-10 15:10:22 -0800807 << "Should reject motion events with pointer up index too large.";
808
Garfield Tanfbe732e2020-01-24 11:26:14 -0800809 event.initialize(InputEvent::nextId(), DEVICE_ID, source, DISPLAY_ID, INVALID_HMAC,
Garfield Tan00f511d2019-06-12 16:55:40 -0700810 AMOTION_EVENT_ACTION_POINTER_UP |
811 (~0U << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT),
chaviw9eaa22c2020-07-01 16:21:27 -0700812 0, 0, edgeFlags, metaState, 0, classification, identityTransform, 0, 0,
813 AMOTION_EVENT_INVALID_CURSOR_POSITION, AMOTION_EVENT_INVALID_CURSOR_POSITION,
Prabir Pradhanb9b18502021-08-26 12:30:32 -0700814 identityTransform, ARBITRARY_TIME, ARBITRARY_TIME,
Harry Cutts101ee9b2023-07-06 18:04:14 +0000815 /*pointerCount=*/1, pointerProperties, pointerCoords);
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -0800816 ASSERT_EQ(InputEventInjectionResult::FAILED,
Harry Cutts33476232023-01-30 19:57:29 +0000817 mDispatcher->injectInputEvent(&event, /*targetUid=*/{}, InputEventInjectionSync::NONE,
Prabir Pradhan5735a322022-04-11 17:23:34 +0000818 0ms, 0))
Michael Wrightd02c5b62014-02-10 15:10:22 -0800819 << "Should reject motion events with pointer up index too small.";
820
821 // Rejects motion events with invalid number of pointers.
Garfield Tanfbe732e2020-01-24 11:26:14 -0800822 event.initialize(InputEvent::nextId(), DEVICE_ID, source, DISPLAY_ID, INVALID_HMAC,
823 AMOTION_EVENT_ACTION_DOWN, 0, 0, edgeFlags, metaState, 0, classification,
chaviw9eaa22c2020-07-01 16:21:27 -0700824 identityTransform, 0, 0, AMOTION_EVENT_INVALID_CURSOR_POSITION,
Prabir Pradhanb9b18502021-08-26 12:30:32 -0700825 AMOTION_EVENT_INVALID_CURSOR_POSITION, identityTransform, ARBITRARY_TIME,
826 ARBITRARY_TIME,
Harry Cutts101ee9b2023-07-06 18:04:14 +0000827 /*pointerCount=*/0, pointerProperties, pointerCoords);
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -0800828 ASSERT_EQ(InputEventInjectionResult::FAILED,
Harry Cutts33476232023-01-30 19:57:29 +0000829 mDispatcher->injectInputEvent(&event, /*targetUid=*/{}, InputEventInjectionSync::NONE,
Prabir Pradhan5735a322022-04-11 17:23:34 +0000830 0ms, 0))
Michael Wrightd02c5b62014-02-10 15:10:22 -0800831 << "Should reject motion events with 0 pointers.";
832
Garfield Tanfbe732e2020-01-24 11:26:14 -0800833 event.initialize(InputEvent::nextId(), DEVICE_ID, source, DISPLAY_ID, INVALID_HMAC,
834 AMOTION_EVENT_ACTION_DOWN, 0, 0, edgeFlags, metaState, 0, classification,
chaviw9eaa22c2020-07-01 16:21:27 -0700835 identityTransform, 0, 0, AMOTION_EVENT_INVALID_CURSOR_POSITION,
Prabir Pradhanb9b18502021-08-26 12:30:32 -0700836 AMOTION_EVENT_INVALID_CURSOR_POSITION, identityTransform, ARBITRARY_TIME,
837 ARBITRARY_TIME,
Harry Cutts101ee9b2023-07-06 18:04:14 +0000838 /*pointerCount=*/MAX_POINTERS + 1, pointerProperties, pointerCoords);
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -0800839 ASSERT_EQ(InputEventInjectionResult::FAILED,
Harry Cutts33476232023-01-30 19:57:29 +0000840 mDispatcher->injectInputEvent(&event, /*targetUid=*/{}, InputEventInjectionSync::NONE,
Prabir Pradhan5735a322022-04-11 17:23:34 +0000841 0ms, 0))
Michael Wrightd02c5b62014-02-10 15:10:22 -0800842 << "Should reject motion events with more than MAX_POINTERS pointers.";
843
844 // Rejects motion events with invalid pointer ids.
845 pointerProperties[0].id = -1;
Garfield Tanfbe732e2020-01-24 11:26:14 -0800846 event.initialize(InputEvent::nextId(), DEVICE_ID, source, DISPLAY_ID, INVALID_HMAC,
847 AMOTION_EVENT_ACTION_DOWN, 0, 0, edgeFlags, metaState, 0, classification,
chaviw9eaa22c2020-07-01 16:21:27 -0700848 identityTransform, 0, 0, AMOTION_EVENT_INVALID_CURSOR_POSITION,
Prabir Pradhanb9b18502021-08-26 12:30:32 -0700849 AMOTION_EVENT_INVALID_CURSOR_POSITION, identityTransform, ARBITRARY_TIME,
850 ARBITRARY_TIME,
Harry Cutts101ee9b2023-07-06 18:04:14 +0000851 /*pointerCount=*/1, pointerProperties, pointerCoords);
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -0800852 ASSERT_EQ(InputEventInjectionResult::FAILED,
Harry Cutts33476232023-01-30 19:57:29 +0000853 mDispatcher->injectInputEvent(&event, /*targetUid=*/{}, InputEventInjectionSync::NONE,
Prabir Pradhan5735a322022-04-11 17:23:34 +0000854 0ms, 0))
Michael Wrightd02c5b62014-02-10 15:10:22 -0800855 << "Should reject motion events with pointer ids less than 0.";
856
857 pointerProperties[0].id = MAX_POINTER_ID + 1;
Garfield Tanfbe732e2020-01-24 11:26:14 -0800858 event.initialize(InputEvent::nextId(), DEVICE_ID, source, DISPLAY_ID, INVALID_HMAC,
859 AMOTION_EVENT_ACTION_DOWN, 0, 0, edgeFlags, metaState, 0, classification,
chaviw9eaa22c2020-07-01 16:21:27 -0700860 identityTransform, 0, 0, AMOTION_EVENT_INVALID_CURSOR_POSITION,
Prabir Pradhanb9b18502021-08-26 12:30:32 -0700861 AMOTION_EVENT_INVALID_CURSOR_POSITION, identityTransform, ARBITRARY_TIME,
862 ARBITRARY_TIME,
Harry Cutts101ee9b2023-07-06 18:04:14 +0000863 /*pointerCount=*/1, pointerProperties, pointerCoords);
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -0800864 ASSERT_EQ(InputEventInjectionResult::FAILED,
Harry Cutts33476232023-01-30 19:57:29 +0000865 mDispatcher->injectInputEvent(&event, /*targetUid=*/{}, InputEventInjectionSync::NONE,
Prabir Pradhan5735a322022-04-11 17:23:34 +0000866 0ms, 0))
Michael Wrightd02c5b62014-02-10 15:10:22 -0800867 << "Should reject motion events with pointer ids greater than MAX_POINTER_ID.";
868
869 // Rejects motion events with duplicate pointer ids.
870 pointerProperties[0].id = 1;
871 pointerProperties[1].id = 1;
Garfield Tanfbe732e2020-01-24 11:26:14 -0800872 event.initialize(InputEvent::nextId(), DEVICE_ID, source, DISPLAY_ID, INVALID_HMAC,
873 AMOTION_EVENT_ACTION_DOWN, 0, 0, edgeFlags, metaState, 0, classification,
chaviw9eaa22c2020-07-01 16:21:27 -0700874 identityTransform, 0, 0, AMOTION_EVENT_INVALID_CURSOR_POSITION,
Prabir Pradhanb9b18502021-08-26 12:30:32 -0700875 AMOTION_EVENT_INVALID_CURSOR_POSITION, identityTransform, ARBITRARY_TIME,
876 ARBITRARY_TIME,
Harry Cutts101ee9b2023-07-06 18:04:14 +0000877 /*pointerCount=*/2, pointerProperties, pointerCoords);
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -0800878 ASSERT_EQ(InputEventInjectionResult::FAILED,
Harry Cutts33476232023-01-30 19:57:29 +0000879 mDispatcher->injectInputEvent(&event, /*targetUid=*/{}, InputEventInjectionSync::NONE,
Prabir Pradhan5735a322022-04-11 17:23:34 +0000880 0ms, 0))
Michael Wrightd02c5b62014-02-10 15:10:22 -0800881 << "Should reject motion events with duplicate pointer ids.";
882}
883
Siarhei Vishniakou2bfa9052019-11-21 18:10:54 -0800884/* Test InputDispatcher for notifyConfigurationChanged and notifySwitch events */
885
886TEST_F(InputDispatcherTest, NotifyConfigurationChanged_CallsPolicy) {
887 constexpr nsecs_t eventTime = 20;
Prabir Pradhan678438e2023-04-13 19:32:51 +0000888 mDispatcher->notifyConfigurationChanged({/*id=*/10, eventTime});
Siarhei Vishniakou2bfa9052019-11-21 18:10:54 -0800889 ASSERT_TRUE(mDispatcher->waitForIdle());
890
891 mFakePolicy->assertNotifyConfigurationChangedWasCalled(eventTime);
892}
893
894TEST_F(InputDispatcherTest, NotifySwitch_CallsPolicy) {
Prabir Pradhana8fe7c52023-12-14 22:07:23 +0000895 NotifySwitchArgs args(InputEvent::nextId(), /*eventTime=*/20, /*policyFlags=*/0,
896 /*switchValues=*/1,
Harry Cutts33476232023-01-30 19:57:29 +0000897 /*switchMask=*/2);
Prabir Pradhan678438e2023-04-13 19:32:51 +0000898 mDispatcher->notifySwitch(args);
Siarhei Vishniakou2bfa9052019-11-21 18:10:54 -0800899
900 // InputDispatcher adds POLICY_FLAG_TRUSTED because the event went through InputListener
901 args.policyFlags |= POLICY_FLAG_TRUSTED;
902 mFakePolicy->assertNotifySwitchWasCalled(args);
903}
904
Siarhei Vishniakouadeb6fa2023-05-26 09:11:06 -0700905namespace {
906
Siarhei Vishniakou097c3db2020-05-06 14:18:38 -0700907static constexpr std::chrono::duration INJECT_EVENT_TIMEOUT = 500ms;
Siarhei Vishniakou1c494c52021-08-11 20:25:01 -0700908// Default input dispatching timeout if there is no focused application or paused window
909// from which to determine an appropriate dispatching timeout.
910static const std::chrono::duration DISPATCHING_TIMEOUT = std::chrono::milliseconds(
911 android::os::IInputConstants::UNMULTIPLIED_DEFAULT_DISPATCHING_TIMEOUT_MILLIS *
912 android::base::HwTimeoutMultiplier());
Arthur Hungb92218b2018-08-14 12:00:21 +0800913
Arthur Hung2fbf37f2018-09-13 18:16:41 +0800914class FakeInputReceiver {
Arthur Hungb92218b2018-08-14 12:00:21 +0800915public:
Garfield Tan15601662020-09-22 15:32:38 -0700916 explicit FakeInputReceiver(std::unique_ptr<InputChannel> clientChannel, const std::string name)
Siarhei Vishniakou2defec02023-06-08 17:24:44 -0700917 : mConsumer(std::move(clientChannel)), mName(name) {}
chaviwd1c23182019-12-20 18:44:56 -0800918
Siarhei Vishniakoud3061ab2023-12-18 20:41:08 -0800919 std::unique_ptr<InputEvent> consume(std::chrono::milliseconds timeout, bool handled = false) {
920 auto [consumeSeq, event] = receiveEvent(timeout);
Siarhei Vishniakou4cb50ca2020-05-26 21:43:02 -0700921 if (!consumeSeq) {
922 return nullptr;
923 }
Prabir Pradhanb0dad3a2023-11-02 20:52:47 +0000924 finishEvent(*consumeSeq, handled);
Siarhei Vishniakoud3061ab2023-12-18 20:41:08 -0800925 return std::move(event);
Siarhei Vishniakou4cb50ca2020-05-26 21:43:02 -0700926 }
927
928 /**
929 * Receive an event without acknowledging it.
930 * Return the sequence number that could later be used to send finished signal.
931 */
Siarhei Vishniakoud3061ab2023-12-18 20:41:08 -0800932 std::pair<std::optional<uint32_t>, std::unique_ptr<InputEvent>> receiveEvent(
933 std::chrono::milliseconds timeout) {
Arthur Hungb92218b2018-08-14 12:00:21 +0800934 uint32_t consumeSeq;
Siarhei Vishniakoud3061ab2023-12-18 20:41:08 -0800935 std::unique_ptr<InputEvent> event;
Arthur Hungb92218b2018-08-14 12:00:21 +0800936
Siarhei Vishniakou08b574f2019-11-15 18:05:52 -0800937 std::chrono::time_point start = std::chrono::steady_clock::now();
938 status_t status = WOULD_BLOCK;
939 while (status == WOULD_BLOCK) {
Siarhei Vishniakoud3061ab2023-12-18 20:41:08 -0800940 InputEvent* rawEventPtr = nullptr;
Siarhei Vishniakou2defec02023-06-08 17:24:44 -0700941 status = mConsumer.consume(&mEventFactory, /*consumeBatches=*/true, -1, &consumeSeq,
Siarhei Vishniakoud3061ab2023-12-18 20:41:08 -0800942 &rawEventPtr);
943 event = std::unique_ptr<InputEvent>(rawEventPtr);
Siarhei Vishniakou08b574f2019-11-15 18:05:52 -0800944 std::chrono::duration elapsed = std::chrono::steady_clock::now() - start;
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -0700945 if (elapsed > timeout) {
Siarhei Vishniakou08b574f2019-11-15 18:05:52 -0800946 break;
947 }
948 }
949
950 if (status == WOULD_BLOCK) {
951 // Just means there's no event available.
Siarhei Vishniakoud3061ab2023-12-18 20:41:08 -0800952 return std::make_pair(std::nullopt, nullptr);
Siarhei Vishniakou08b574f2019-11-15 18:05:52 -0800953 }
954
955 if (status != OK) {
956 ADD_FAILURE() << mName.c_str() << ": consumer consume should return OK.";
Siarhei Vishniakoud3061ab2023-12-18 20:41:08 -0800957 return std::make_pair(std::nullopt, nullptr);
Siarhei Vishniakou08b574f2019-11-15 18:05:52 -0800958 }
959 if (event == nullptr) {
960 ADD_FAILURE() << "Consumed correctly, but received NULL event from consumer";
Siarhei Vishniakou08b574f2019-11-15 18:05:52 -0800961 }
Siarhei Vishniakoud3061ab2023-12-18 20:41:08 -0800962 return std::make_pair(consumeSeq, std::move(event));
Siarhei Vishniakou4cb50ca2020-05-26 21:43:02 -0700963 }
Siarhei Vishniakou08b574f2019-11-15 18:05:52 -0800964
Siarhei Vishniakou4cb50ca2020-05-26 21:43:02 -0700965 /**
966 * To be used together with "receiveEvent" to complete the consumption of an event.
967 */
Prabir Pradhanb0dad3a2023-11-02 20:52:47 +0000968 void finishEvent(uint32_t consumeSeq, bool handled = true) {
Siarhei Vishniakou2defec02023-06-08 17:24:44 -0700969 const status_t status = mConsumer.sendFinishedSignal(consumeSeq, handled);
Siarhei Vishniakou4cb50ca2020-05-26 21:43:02 -0700970 ASSERT_EQ(OK, status) << mName.c_str() << ": consumer sendFinishedSignal should return OK.";
Siarhei Vishniakou08b574f2019-11-15 18:05:52 -0800971 }
972
Siarhei Vishniakouf94ae022021-02-04 01:23:17 +0000973 void sendTimeline(int32_t inputEventId, std::array<nsecs_t, GraphicsTimeline::SIZE> timeline) {
Siarhei Vishniakou2defec02023-06-08 17:24:44 -0700974 const status_t status = mConsumer.sendTimeline(inputEventId, timeline);
Siarhei Vishniakouf94ae022021-02-04 01:23:17 +0000975 ASSERT_EQ(OK, status);
976 }
977
Siarhei Vishniakou63b63612023-04-12 11:00:23 -0700978 void consumeEvent(InputEventType expectedEventType, int32_t expectedAction,
Bernardo Rufinoc3b7b8c2021-01-29 17:38:07 +0000979 std::optional<int32_t> expectedDisplayId,
980 std::optional<int32_t> expectedFlags) {
Siarhei Vishniakoud3061ab2023-12-18 20:41:08 -0800981 std::unique_ptr<InputEvent> event = consume(CONSUME_TIMEOUT_EVENT_EXPECTED);
Siarhei Vishniakou08b574f2019-11-15 18:05:52 -0800982
983 ASSERT_NE(nullptr, event) << mName.c_str()
984 << ": consumer should have returned non-NULL event.";
Arthur Hungb92218b2018-08-14 12:00:21 +0800985 ASSERT_EQ(expectedEventType, event->getType())
Siarhei Vishniakou63b63612023-04-12 11:00:23 -0700986 << mName.c_str() << " expected " << ftl::enum_string(expectedEventType)
987 << " event, got " << *event;
Arthur Hungb92218b2018-08-14 12:00:21 +0800988
Bernardo Rufinoc3b7b8c2021-01-29 17:38:07 +0000989 if (expectedDisplayId.has_value()) {
990 EXPECT_EQ(expectedDisplayId, event->getDisplayId());
991 }
Tiger Huang8664f8c2018-10-11 19:14:35 +0800992
Tiger Huang8664f8c2018-10-11 19:14:35 +0800993 switch (expectedEventType) {
Siarhei Vishniakou63b63612023-04-12 11:00:23 -0700994 case InputEventType::KEY: {
Siarhei Vishniakouc5ca85c2019-11-15 17:20:00 -0800995 const KeyEvent& keyEvent = static_cast<const KeyEvent&>(*event);
Siarhei Vishniakouf4043212023-09-18 19:33:03 -0700996 ASSERT_THAT(keyEvent, WithKeyAction(expectedAction));
Bernardo Rufinoc3b7b8c2021-01-29 17:38:07 +0000997 if (expectedFlags.has_value()) {
998 EXPECT_EQ(expectedFlags.value(), keyEvent.getFlags());
999 }
Tiger Huang8664f8c2018-10-11 19:14:35 +08001000 break;
1001 }
Siarhei Vishniakou63b63612023-04-12 11:00:23 -07001002 case InputEventType::MOTION: {
Siarhei Vishniakouc5ca85c2019-11-15 17:20:00 -08001003 const MotionEvent& motionEvent = static_cast<const MotionEvent&>(*event);
Siarhei Vishniakouf4043212023-09-18 19:33:03 -07001004 ASSERT_THAT(motionEvent, WithMotionAction(expectedAction));
Bernardo Rufinoc3b7b8c2021-01-29 17:38:07 +00001005 if (expectedFlags.has_value()) {
1006 EXPECT_EQ(expectedFlags.value(), motionEvent.getFlags());
1007 }
Tiger Huang8664f8c2018-10-11 19:14:35 +08001008 break;
1009 }
Siarhei Vishniakou63b63612023-04-12 11:00:23 -07001010 case InputEventType::FOCUS: {
Siarhei Vishniakouf1035d42019-09-20 16:32:01 +01001011 FAIL() << "Use 'consumeFocusEvent' for FOCUS events";
1012 }
Siarhei Vishniakou63b63612023-04-12 11:00:23 -07001013 case InputEventType::CAPTURE: {
Prabir Pradhan99987712020-11-10 18:43:05 -08001014 FAIL() << "Use 'consumeCaptureEvent' for CAPTURE events";
1015 }
Siarhei Vishniakou63b63612023-04-12 11:00:23 -07001016 case InputEventType::TOUCH_MODE: {
Antonio Kantekf16f2832021-09-28 04:39:20 +00001017 FAIL() << "Use 'consumeTouchModeEvent' for TOUCH_MODE events";
1018 }
Siarhei Vishniakou63b63612023-04-12 11:00:23 -07001019 case InputEventType::DRAG: {
arthurhungb89ccb02020-12-30 16:19:01 +08001020 FAIL() << "Use 'consumeDragEvent' for DRAG events";
1021 }
Tiger Huang8664f8c2018-10-11 19:14:35 +08001022 }
Arthur Hungb92218b2018-08-14 12:00:21 +08001023 }
1024
Siarhei Vishniakoud3061ab2023-12-18 20:41:08 -08001025 std::unique_ptr<MotionEvent> consumeMotion() {
1026 std::unique_ptr<InputEvent> event = consume(CONSUME_TIMEOUT_EVENT_EXPECTED);
Siarhei Vishniakou1ae72f12023-01-29 12:55:30 -08001027
1028 if (event == nullptr) {
1029 ADD_FAILURE() << mName << ": expected a MotionEvent, but didn't get one.";
1030 return nullptr;
1031 }
1032
Siarhei Vishniakou63b63612023-04-12 11:00:23 -07001033 if (event->getType() != InputEventType::MOTION) {
1034 ADD_FAILURE() << mName << " expected a MotionEvent, got " << *event;
Siarhei Vishniakou1ae72f12023-01-29 12:55:30 -08001035 return nullptr;
1036 }
Siarhei Vishniakoud3061ab2023-12-18 20:41:08 -08001037 return std::unique_ptr<MotionEvent>(static_cast<MotionEvent*>(event.release()));
Siarhei Vishniakou1ae72f12023-01-29 12:55:30 -08001038 }
1039
1040 void consumeMotionEvent(const ::testing::Matcher<MotionEvent>& matcher) {
Siarhei Vishniakoud3061ab2023-12-18 20:41:08 -08001041 std::unique_ptr<MotionEvent> motionEvent = consumeMotion();
Siarhei Vishniakou1ae72f12023-01-29 12:55:30 -08001042 ASSERT_NE(nullptr, motionEvent) << "Did not get a motion event, but expected " << matcher;
1043 ASSERT_THAT(*motionEvent, matcher);
1044 }
1045
Siarhei Vishniakouf1035d42019-09-20 16:32:01 +01001046 void consumeFocusEvent(bool hasFocus, bool inTouchMode) {
Siarhei Vishniakoud3061ab2023-12-18 20:41:08 -08001047 std::unique_ptr<InputEvent> event = consume(CONSUME_TIMEOUT_EVENT_EXPECTED);
Siarhei Vishniakouf1035d42019-09-20 16:32:01 +01001048 ASSERT_NE(nullptr, event) << mName.c_str()
1049 << ": consumer should have returned non-NULL event.";
Siarhei Vishniakou63b63612023-04-12 11:00:23 -07001050 ASSERT_EQ(InputEventType::FOCUS, event->getType())
1051 << "Instead of FocusEvent, got " << *event;
Siarhei Vishniakouf1035d42019-09-20 16:32:01 +01001052
1053 ASSERT_EQ(ADISPLAY_ID_NONE, event->getDisplayId())
1054 << mName.c_str() << ": event displayId should always be NONE.";
1055
Siarhei Vishniakoud3061ab2023-12-18 20:41:08 -08001056 FocusEvent& focusEvent = static_cast<FocusEvent&>(*event);
1057 EXPECT_EQ(hasFocus, focusEvent.getHasFocus());
Siarhei Vishniakouf1035d42019-09-20 16:32:01 +01001058 }
1059
Prabir Pradhan99987712020-11-10 18:43:05 -08001060 void consumeCaptureEvent(bool hasCapture) {
Siarhei Vishniakoud3061ab2023-12-18 20:41:08 -08001061 std::unique_ptr<InputEvent> event = consume(CONSUME_TIMEOUT_EVENT_EXPECTED);
Prabir Pradhan99987712020-11-10 18:43:05 -08001062 ASSERT_NE(nullptr, event) << mName.c_str()
1063 << ": consumer should have returned non-NULL event.";
Siarhei Vishniakou63b63612023-04-12 11:00:23 -07001064 ASSERT_EQ(InputEventType::CAPTURE, event->getType())
1065 << "Instead of CaptureEvent, got " << *event;
Prabir Pradhan99987712020-11-10 18:43:05 -08001066
1067 ASSERT_EQ(ADISPLAY_ID_NONE, event->getDisplayId())
1068 << mName.c_str() << ": event displayId should always be NONE.";
1069
1070 const auto& captureEvent = static_cast<const CaptureEvent&>(*event);
1071 EXPECT_EQ(hasCapture, captureEvent.getPointerCaptureEnabled());
1072 }
1073
arthurhungb89ccb02020-12-30 16:19:01 +08001074 void consumeDragEvent(bool isExiting, float x, float y) {
Siarhei Vishniakoud3061ab2023-12-18 20:41:08 -08001075 std::unique_ptr<InputEvent> event = consume(CONSUME_TIMEOUT_EVENT_EXPECTED);
arthurhungb89ccb02020-12-30 16:19:01 +08001076 ASSERT_NE(nullptr, event) << mName.c_str()
1077 << ": consumer should have returned non-NULL event.";
Siarhei Vishniakou63b63612023-04-12 11:00:23 -07001078 ASSERT_EQ(InputEventType::DRAG, event->getType()) << "Instead of DragEvent, got " << *event;
arthurhungb89ccb02020-12-30 16:19:01 +08001079
1080 EXPECT_EQ(ADISPLAY_ID_NONE, event->getDisplayId())
1081 << mName.c_str() << ": event displayId should always be NONE.";
1082
1083 const auto& dragEvent = static_cast<const DragEvent&>(*event);
1084 EXPECT_EQ(isExiting, dragEvent.isExiting());
1085 EXPECT_EQ(x, dragEvent.getX());
1086 EXPECT_EQ(y, dragEvent.getY());
1087 }
1088
Antonio Kantekf16f2832021-09-28 04:39:20 +00001089 void consumeTouchModeEvent(bool inTouchMode) {
Siarhei Vishniakoud3061ab2023-12-18 20:41:08 -08001090 std::unique_ptr<InputEvent> event = consume(CONSUME_TIMEOUT_EVENT_EXPECTED);
Antonio Kantekf16f2832021-09-28 04:39:20 +00001091 ASSERT_NE(nullptr, event) << mName.c_str()
1092 << ": consumer should have returned non-NULL event.";
Siarhei Vishniakou63b63612023-04-12 11:00:23 -07001093 ASSERT_EQ(InputEventType::TOUCH_MODE, event->getType())
1094 << "Instead of TouchModeEvent, got " << *event;
Antonio Kantekf16f2832021-09-28 04:39:20 +00001095
1096 ASSERT_EQ(ADISPLAY_ID_NONE, event->getDisplayId())
1097 << mName.c_str() << ": event displayId should always be NONE.";
1098 const auto& touchModeEvent = static_cast<const TouchModeEvent&>(*event);
1099 EXPECT_EQ(inTouchMode, touchModeEvent.isInTouchMode());
1100 }
1101
Siarhei Vishniakouef2b4502023-12-28 11:51:47 -08001102 void assertNoEvents(std::chrono::milliseconds timeout) {
1103 std::unique_ptr<InputEvent> event = consume(timeout);
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07001104 if (event == nullptr) {
1105 return;
1106 }
Siarhei Vishniakou63b63612023-04-12 11:00:23 -07001107 if (event->getType() == InputEventType::KEY) {
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07001108 KeyEvent& keyEvent = static_cast<KeyEvent&>(*event);
Siarhei Vishniakoud908f5a2023-11-16 10:25:12 -08001109 ADD_FAILURE() << "Received key event " << keyEvent;
Siarhei Vishniakou63b63612023-04-12 11:00:23 -07001110 } else if (event->getType() == InputEventType::MOTION) {
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07001111 MotionEvent& motionEvent = static_cast<MotionEvent&>(*event);
Siarhei Vishniakoud908f5a2023-11-16 10:25:12 -08001112 ADD_FAILURE() << "Received motion event " << motionEvent;
Siarhei Vishniakou63b63612023-04-12 11:00:23 -07001113 } else if (event->getType() == InputEventType::FOCUS) {
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07001114 FocusEvent& focusEvent = static_cast<FocusEvent&>(*event);
1115 ADD_FAILURE() << "Received focus event, hasFocus = "
1116 << (focusEvent.getHasFocus() ? "true" : "false");
Siarhei Vishniakou63b63612023-04-12 11:00:23 -07001117 } else if (event->getType() == InputEventType::CAPTURE) {
Prabir Pradhan99987712020-11-10 18:43:05 -08001118 const auto& captureEvent = static_cast<CaptureEvent&>(*event);
1119 ADD_FAILURE() << "Received capture event, pointerCaptureEnabled = "
1120 << (captureEvent.getPointerCaptureEnabled() ? "true" : "false");
Siarhei Vishniakou63b63612023-04-12 11:00:23 -07001121 } else if (event->getType() == InputEventType::TOUCH_MODE) {
Antonio Kantekf16f2832021-09-28 04:39:20 +00001122 const auto& touchModeEvent = static_cast<TouchModeEvent&>(*event);
1123 ADD_FAILURE() << "Received touch mode event, inTouchMode = "
1124 << (touchModeEvent.isInTouchMode() ? "true" : "false");
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07001125 }
1126 FAIL() << mName.c_str()
1127 << ": should not have received any events, so consume() should return NULL";
chaviwd1c23182019-12-20 18:44:56 -08001128 }
1129
Siarhei Vishniakou2defec02023-06-08 17:24:44 -07001130 sp<IBinder> getToken() { return mConsumer.getChannel()->getConnectionToken(); }
chaviwd1c23182019-12-20 18:44:56 -08001131
Siarhei Vishniakou8d660132024-01-11 16:48:44 -08001132 int getChannelFd() { return mConsumer.getChannel()->getFd(); }
Prabir Pradhan07e05b62021-11-19 03:57:24 -08001133
Siarhei Vishniakou2defec02023-06-08 17:24:44 -07001134private:
1135 InputConsumer mConsumer;
Siarhei Vishniakoud3061ab2023-12-18 20:41:08 -08001136 DynamicInputEventFactory mEventFactory;
chaviwd1c23182019-12-20 18:44:56 -08001137
1138 std::string mName;
1139};
1140
chaviw3277faf2021-05-19 16:45:23 -05001141class FakeWindowHandle : public WindowInfoHandle {
chaviwd1c23182019-12-20 18:44:56 -08001142public:
1143 static const int32_t WIDTH = 600;
1144 static const int32_t HEIGHT = 800;
chaviwd1c23182019-12-20 18:44:56 -08001145
Chris Yea209fde2020-07-22 13:54:51 -07001146 FakeWindowHandle(const std::shared_ptr<InputApplicationHandle>& inputApplicationHandle,
Siarhei Vishniakou18050092021-09-01 13:32:49 -07001147 const std::unique_ptr<InputDispatcher>& dispatcher, const std::string name,
Prabir Pradhane7cc69c2024-01-05 21:35:28 +00001148 int32_t displayId, bool createInputChannel = true)
chaviwd1c23182019-12-20 18:44:56 -08001149 : mName(name) {
Prabir Pradhane7cc69c2024-01-05 21:35:28 +00001150 sp<IBinder> token;
1151 if (createInputChannel) {
Garfield Tan15601662020-09-22 15:32:38 -07001152 base::Result<std::unique_ptr<InputChannel>> channel =
1153 dispatcher->createInputChannel(name);
1154 token = (*channel)->getConnectionToken();
1155 mInputReceiver = std::make_unique<FakeInputReceiver>(std::move(*channel), name);
chaviwd1c23182019-12-20 18:44:56 -08001156 }
1157
1158 inputApplicationHandle->updateInfo();
1159 mInfo.applicationInfo = *inputApplicationHandle->getInfo();
1160
Prabir Pradhane7cc69c2024-01-05 21:35:28 +00001161 mInfo.token = token;
Siarhei Vishniakou540dbae2020-05-05 18:17:17 -07001162 mInfo.id = sId++;
chaviwd1c23182019-12-20 18:44:56 -08001163 mInfo.name = name;
Siarhei Vishniakouc1ae5562020-06-30 14:22:57 -05001164 mInfo.dispatchingTimeout = DISPATCHING_TIMEOUT;
Bernardo Rufinoc3b7b8c2021-01-29 17:38:07 +00001165 mInfo.alpha = 1.0;
Chavi Weingarten7f019192023-08-08 20:39:01 +00001166 mInfo.frame = Rect(0, 0, WIDTH, HEIGHT);
chaviw1ff3d1e2020-07-01 15:53:47 -07001167 mInfo.transform.set(0, 0);
chaviwd1c23182019-12-20 18:44:56 -08001168 mInfo.globalScaleFactor = 1.0;
1169 mInfo.touchableRegion.clear();
1170 mInfo.addTouchableRegion(Rect(0, 0, WIDTH, HEIGHT));
Prabir Pradhan5735a322022-04-11 17:23:34 +00001171 mInfo.ownerPid = WINDOW_PID;
1172 mInfo.ownerUid = WINDOW_UID;
chaviwd1c23182019-12-20 18:44:56 -08001173 mInfo.displayId = displayId;
Prabir Pradhan51e7db02022-02-07 06:02:57 -08001174 mInfo.inputConfig = WindowInfo::InputConfig::DEFAULT;
chaviwd1c23182019-12-20 18:44:56 -08001175 }
1176
Siarhei Vishniakouadb9fc92023-05-26 10:46:09 -07001177 sp<FakeWindowHandle> clone(int32_t displayId) {
1178 sp<FakeWindowHandle> handle = sp<FakeWindowHandle>::make(mInfo.name + "(Mirror)");
1179 handle->mInfo = mInfo;
1180 handle->mInfo.displayId = displayId;
1181 handle->mInfo.id = sId++;
1182 handle->mInputReceiver = mInputReceiver;
1183 return handle;
1184 }
1185
Prabir Pradhan4d5c52f2022-01-31 08:52:10 -08001186 void setTouchable(bool touchable) {
1187 mInfo.setInputConfig(WindowInfo::InputConfig::NOT_TOUCHABLE, !touchable);
1188 }
chaviwd1c23182019-12-20 18:44:56 -08001189
Prabir Pradhan4d5c52f2022-01-31 08:52:10 -08001190 void setFocusable(bool focusable) {
1191 mInfo.setInputConfig(WindowInfo::InputConfig::NOT_FOCUSABLE, !focusable);
1192 }
1193
1194 void setVisible(bool visible) {
1195 mInfo.setInputConfig(WindowInfo::InputConfig::NOT_VISIBLE, !visible);
1196 }
Vishnu Nair958da932020-08-21 17:12:37 -07001197
Siarhei Vishniakou4cb50ca2020-05-26 21:43:02 -07001198 void setDispatchingTimeout(std::chrono::nanoseconds timeout) {
Siarhei Vishniakouc1ae5562020-06-30 14:22:57 -05001199 mInfo.dispatchingTimeout = timeout;
Siarhei Vishniakou4cb50ca2020-05-26 21:43:02 -07001200 }
1201
Prabir Pradhan4d5c52f2022-01-31 08:52:10 -08001202 void setPaused(bool paused) {
1203 mInfo.setInputConfig(WindowInfo::InputConfig::PAUSE_DISPATCHING, paused);
1204 }
1205
Prabir Pradhan76bdecb2022-01-31 11:14:15 -08001206 void setPreventSplitting(bool preventSplitting) {
1207 mInfo.setInputConfig(WindowInfo::InputConfig::PREVENT_SPLITTING, preventSplitting);
Prabir Pradhan4d5c52f2022-01-31 08:52:10 -08001208 }
1209
1210 void setSlippery(bool slippery) {
1211 mInfo.setInputConfig(WindowInfo::InputConfig::SLIPPERY, slippery);
1212 }
1213
1214 void setWatchOutsideTouch(bool watchOutside) {
1215 mInfo.setInputConfig(WindowInfo::InputConfig::WATCH_OUTSIDE_TOUCH, watchOutside);
1216 }
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07001217
Prabir Pradhan51e7db02022-02-07 06:02:57 -08001218 void setSpy(bool spy) { mInfo.setInputConfig(WindowInfo::InputConfig::SPY, spy); }
1219
1220 void setInterceptsStylus(bool interceptsStylus) {
1221 mInfo.setInputConfig(WindowInfo::InputConfig::INTERCEPTS_STYLUS, interceptsStylus);
1222 }
1223
1224 void setDropInput(bool dropInput) {
1225 mInfo.setInputConfig(WindowInfo::InputConfig::DROP_INPUT, dropInput);
1226 }
1227
1228 void setDropInputIfObscured(bool dropInputIfObscured) {
1229 mInfo.setInputConfig(WindowInfo::InputConfig::DROP_INPUT_IF_OBSCURED, dropInputIfObscured);
1230 }
1231
1232 void setNoInputChannel(bool noInputChannel) {
1233 mInfo.setInputConfig(WindowInfo::InputConfig::NO_INPUT_CHANNEL, noInputChannel);
1234 }
1235
Josep del Riob3981622023-04-18 15:49:45 +00001236 void setDisableUserActivity(bool disableUserActivity) {
1237 mInfo.setInputConfig(WindowInfo::InputConfig::DISABLE_USER_ACTIVITY, disableUserActivity);
1238 }
1239
Siarhei Vishniakouf77f60a2023-10-23 17:26:05 -07001240 void setGlobalStylusBlocksTouch(bool shouldGlobalStylusBlockTouch) {
1241 mInfo.setInputConfig(WindowInfo::InputConfig::GLOBAL_STYLUS_BLOCKS_TOUCH,
1242 shouldGlobalStylusBlockTouch);
1243 }
1244
Bernardo Rufinoc3b7b8c2021-01-29 17:38:07 +00001245 void setAlpha(float alpha) { mInfo.alpha = alpha; }
1246
chaviw3277faf2021-05-19 16:45:23 -05001247 void setTouchOcclusionMode(TouchOcclusionMode mode) { mInfo.touchOcclusionMode = mode; }
Bernardo Rufinoc3b7b8c2021-01-29 17:38:07 +00001248
Bernardo Rufino7393d172021-02-26 13:56:11 +00001249 void setApplicationToken(sp<IBinder> token) { mInfo.applicationInfo.token = token; }
1250
Prabir Pradhanc44ce4d2021-10-05 05:26:29 -07001251 void setFrame(const Rect& frame, const ui::Transform& displayTransform = ui::Transform()) {
Chavi Weingarten7f019192023-08-08 20:39:01 +00001252 mInfo.frame = frame;
chaviwd1c23182019-12-20 18:44:56 -08001253 mInfo.touchableRegion.clear();
1254 mInfo.addTouchableRegion(frame);
Prabir Pradhanc44ce4d2021-10-05 05:26:29 -07001255
1256 const Rect logicalDisplayFrame = displayTransform.transform(frame);
1257 ui::Transform translate;
1258 translate.set(-logicalDisplayFrame.left, -logicalDisplayFrame.top);
1259 mInfo.transform = translate * displayTransform;
chaviwd1c23182019-12-20 18:44:56 -08001260 }
1261
Prabir Pradhan07e05b62021-11-19 03:57:24 -08001262 void setTouchableRegion(const Region& region) { mInfo.touchableRegion = region; }
1263
Prabir Pradhan4d5c52f2022-01-31 08:52:10 -08001264 void setIsWallpaper(bool isWallpaper) {
1265 mInfo.setInputConfig(WindowInfo::InputConfig::IS_WALLPAPER, isWallpaper);
1266 }
Siarhei Vishniakouca205502021-07-16 21:31:58 +00001267
Prabir Pradhan4d5c52f2022-01-31 08:52:10 -08001268 void setDupTouchToWallpaper(bool hasWallpaper) {
1269 mInfo.setInputConfig(WindowInfo::InputConfig::DUPLICATE_TOUCH_TO_WALLPAPER, hasWallpaper);
1270 }
chaviwd1c23182019-12-20 18:44:56 -08001271
Prabir Pradhan4d5c52f2022-01-31 08:52:10 -08001272 void setTrustedOverlay(bool trustedOverlay) {
1273 mInfo.setInputConfig(WindowInfo::InputConfig::TRUSTED_OVERLAY, trustedOverlay);
1274 }
Siarhei Vishniakoua2862a02020-07-20 16:36:46 -05001275
chaviw9eaa22c2020-07-01 16:21:27 -07001276 void setWindowTransform(float dsdx, float dtdx, float dtdy, float dsdy) {
1277 mInfo.transform.set(dsdx, dtdx, dtdy, dsdy);
1278 }
1279
1280 void setWindowScale(float xScale, float yScale) { setWindowTransform(xScale, 0, 0, yScale); }
chaviwaf87b3e2019-10-01 16:59:28 -07001281
yunho.shinf4a80b82020-11-16 21:13:57 +09001282 void setWindowOffset(float offsetX, float offsetY) { mInfo.transform.set(offsetX, offsetY); }
1283
Siarhei Vishniakoud3061ab2023-12-18 20:41:08 -08001284 std::unique_ptr<KeyEvent> consumeKey(bool handled = true) {
1285 std::unique_ptr<InputEvent> event = consume(CONSUME_TIMEOUT_EVENT_EXPECTED, handled);
1286 if (event == nullptr) {
1287 ADD_FAILURE() << "No event";
1288 return nullptr;
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07001289 }
Siarhei Vishniakoud3061ab2023-12-18 20:41:08 -08001290 if (event->getType() != InputEventType::KEY) {
1291 ADD_FAILURE() << "Instead of key event, got " << event;
1292 return nullptr;
1293 }
1294 return std::unique_ptr<KeyEvent>(static_cast<KeyEvent*>(event.release()));
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07001295 }
1296
1297 void consumeKeyEvent(const ::testing::Matcher<KeyEvent>& matcher) {
Siarhei Vishniakoud3061ab2023-12-18 20:41:08 -08001298 std::unique_ptr<KeyEvent> keyEvent = consumeKey();
1299 ASSERT_NE(nullptr, keyEvent);
1300 ASSERT_THAT(*keyEvent, matcher);
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07001301 }
1302
Siarhei Vishniakouc5ca85c2019-11-15 17:20:00 -08001303 void consumeKeyDown(int32_t expectedDisplayId, int32_t expectedFlags = 0) {
Prabir Pradhan7662a8d2023-12-15 01:58:14 +00001304 consumeKeyEvent(AllOf(WithKeyAction(ACTION_DOWN), WithDisplayId(expectedDisplayId),
1305 WithFlags(expectedFlags)));
Siarhei Vishniakouc5ca85c2019-11-15 17:20:00 -08001306 }
1307
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07001308 void consumeKeyUp(int32_t expectedDisplayId, int32_t expectedFlags = 0) {
Prabir Pradhan7662a8d2023-12-15 01:58:14 +00001309 consumeKeyEvent(AllOf(WithKeyAction(ACTION_UP), WithDisplayId(expectedDisplayId),
1310 WithFlags(expectedFlags)));
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07001311 }
1312
Svet Ganov5d3bc372020-01-26 23:11:07 -08001313 void consumeMotionCancel(int32_t expectedDisplayId = ADISPLAY_ID_DEFAULT,
Siarhei Vishniakou870ecec2020-12-09 08:07:46 -10001314 int32_t expectedFlags = 0) {
Siarhei Vishniakou1ae72f12023-01-29 12:55:30 -08001315 consumeMotionEvent(AllOf(WithMotionAction(ACTION_CANCEL), WithDisplayId(expectedDisplayId),
1316 WithFlags(expectedFlags | AMOTION_EVENT_FLAG_CANCELED)));
Svet Ganov5d3bc372020-01-26 23:11:07 -08001317 }
1318
1319 void consumeMotionMove(int32_t expectedDisplayId = ADISPLAY_ID_DEFAULT,
Siarhei Vishniakou870ecec2020-12-09 08:07:46 -10001320 int32_t expectedFlags = 0) {
Siarhei Vishniakou1ae72f12023-01-29 12:55:30 -08001321 consumeMotionEvent(AllOf(WithMotionAction(AMOTION_EVENT_ACTION_MOVE),
1322 WithDisplayId(expectedDisplayId), WithFlags(expectedFlags)));
Svet Ganov5d3bc372020-01-26 23:11:07 -08001323 }
1324
1325 void consumeMotionDown(int32_t expectedDisplayId = ADISPLAY_ID_DEFAULT,
Siarhei Vishniakou870ecec2020-12-09 08:07:46 -10001326 int32_t expectedFlags = 0) {
Bernardo Rufinoc3b7b8c2021-01-29 17:38:07 +00001327 consumeAnyMotionDown(expectedDisplayId, expectedFlags);
1328 }
1329
1330 void consumeAnyMotionDown(std::optional<int32_t> expectedDisplayId = std::nullopt,
1331 std::optional<int32_t> expectedFlags = std::nullopt) {
Prabir Pradhan7662a8d2023-12-15 01:58:14 +00001332 consumeMotionEvent(
1333 AllOf(WithMotionAction(ACTION_DOWN),
1334 testing::Conditional(expectedDisplayId.has_value(),
1335 WithDisplayId(*expectedDisplayId), testing::_),
1336 testing::Conditional(expectedFlags.has_value(), WithFlags(*expectedFlags),
1337 testing::_)));
Siarhei Vishniakouc5ca85c2019-11-15 17:20:00 -08001338 }
1339
Svet Ganov5d3bc372020-01-26 23:11:07 -08001340 void consumeMotionPointerDown(int32_t pointerIdx,
Siarhei Vishniakou870ecec2020-12-09 08:07:46 -10001341 int32_t expectedDisplayId = ADISPLAY_ID_DEFAULT,
1342 int32_t expectedFlags = 0) {
Prabir Pradhan7662a8d2023-12-15 01:58:14 +00001343 const int32_t action = AMOTION_EVENT_ACTION_POINTER_DOWN |
Siarhei Vishniakou870ecec2020-12-09 08:07:46 -10001344 (pointerIdx << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT);
Prabir Pradhan7662a8d2023-12-15 01:58:14 +00001345 consumeMotionEvent(AllOf(WithMotionAction(action), WithDisplayId(expectedDisplayId),
1346 WithFlags(expectedFlags)));
Svet Ganov5d3bc372020-01-26 23:11:07 -08001347 }
1348
1349 void consumeMotionPointerUp(int32_t pointerIdx, int32_t expectedDisplayId = ADISPLAY_ID_DEFAULT,
Siarhei Vishniakou870ecec2020-12-09 08:07:46 -10001350 int32_t expectedFlags = 0) {
Prabir Pradhan7662a8d2023-12-15 01:58:14 +00001351 const int32_t action = AMOTION_EVENT_ACTION_POINTER_UP |
Siarhei Vishniakou870ecec2020-12-09 08:07:46 -10001352 (pointerIdx << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT);
Prabir Pradhan7662a8d2023-12-15 01:58:14 +00001353 consumeMotionEvent(AllOf(WithMotionAction(action), WithDisplayId(expectedDisplayId),
1354 WithFlags(expectedFlags)));
Svet Ganov5d3bc372020-01-26 23:11:07 -08001355 }
1356
1357 void consumeMotionUp(int32_t expectedDisplayId = ADISPLAY_ID_DEFAULT,
Siarhei Vishniakou870ecec2020-12-09 08:07:46 -10001358 int32_t expectedFlags = 0) {
Prabir Pradhan7662a8d2023-12-15 01:58:14 +00001359 consumeMotionEvent(AllOf(WithMotionAction(ACTION_UP), WithDisplayId(expectedDisplayId),
1360 WithFlags(expectedFlags)));
Michael Wright3a240c42019-12-10 20:53:41 +00001361 }
1362
Siarhei Vishniakou234129c2020-10-22 22:28:12 -05001363 void consumeMotionOutside(int32_t expectedDisplayId = ADISPLAY_ID_DEFAULT,
1364 int32_t expectedFlags = 0) {
Prabir Pradhan7662a8d2023-12-15 01:58:14 +00001365 consumeMotionEvent(AllOf(WithMotionAction(AMOTION_EVENT_ACTION_OUTSIDE),
1366 WithDisplayId(expectedDisplayId), WithFlags(expectedFlags)));
Siarhei Vishniakou234129c2020-10-22 22:28:12 -05001367 }
1368
Prabir Pradhan7662a8d2023-12-15 01:58:14 +00001369 void consumeMotionOutsideWithZeroedCoords() {
1370 consumeMotionEvent(
1371 AllOf(WithMotionAction(AMOTION_EVENT_ACTION_OUTSIDE), WithRawCoords(0, 0)));
Prabir Pradhandfabf8a2022-01-21 08:19:30 -08001372 }
1373
Siarhei Vishniakouf1035d42019-09-20 16:32:01 +01001374 void consumeFocusEvent(bool hasFocus, bool inTouchMode = true) {
1375 ASSERT_NE(mInputReceiver, nullptr)
1376 << "Cannot consume events from a window with no receiver";
1377 mInputReceiver->consumeFocusEvent(hasFocus, inTouchMode);
1378 }
1379
Prabir Pradhan99987712020-11-10 18:43:05 -08001380 void consumeCaptureEvent(bool hasCapture) {
1381 ASSERT_NE(mInputReceiver, nullptr)
1382 << "Cannot consume events from a window with no receiver";
1383 mInputReceiver->consumeCaptureEvent(hasCapture);
1384 }
1385
Siarhei Vishniakoud3061ab2023-12-18 20:41:08 -08001386 std::unique_ptr<MotionEvent> consumeMotionEvent(
Prabir Pradhan7662a8d2023-12-15 01:58:14 +00001387 const ::testing::Matcher<MotionEvent>& matcher = testing::_) {
Siarhei Vishniakoud3061ab2023-12-18 20:41:08 -08001388 std::unique_ptr<InputEvent> event = consume(CONSUME_TIMEOUT_EVENT_EXPECTED);
1389 if (event == nullptr) {
1390 ADD_FAILURE() << "No event";
1391 return nullptr;
Prabir Pradhan5893d362023-11-17 04:30:40 +00001392 }
Siarhei Vishniakoud3061ab2023-12-18 20:41:08 -08001393 if (event->getType() != InputEventType::MOTION) {
1394 ADD_FAILURE() << "Instead of motion event, got " << *event;
1395 return nullptr;
1396 }
1397 std::unique_ptr<MotionEvent> motionEvent =
1398 std::unique_ptr<MotionEvent>(static_cast<MotionEvent*>(event.release()));
1399 EXPECT_THAT(*motionEvent, matcher);
Prabir Pradhan7662a8d2023-12-15 01:58:14 +00001400 return motionEvent;
chaviwd1c23182019-12-20 18:44:56 -08001401 }
1402
arthurhungb89ccb02020-12-30 16:19:01 +08001403 void consumeDragEvent(bool isExiting, float x, float y) {
1404 mInputReceiver->consumeDragEvent(isExiting, x, y);
1405 }
1406
Antonio Kantekf16f2832021-09-28 04:39:20 +00001407 void consumeTouchModeEvent(bool inTouchMode) {
1408 ASSERT_NE(mInputReceiver, nullptr)
1409 << "Cannot consume events from a window with no receiver";
1410 mInputReceiver->consumeTouchModeEvent(inTouchMode);
1411 }
1412
Siarhei Vishniakoud3061ab2023-12-18 20:41:08 -08001413 std::pair<std::optional<uint32_t>, std::unique_ptr<InputEvent>> receiveEvent() {
Prabir Pradhandc3a2ad2024-02-05 19:03:51 +00001414 return receive();
Siarhei Vishniakou4cb50ca2020-05-26 21:43:02 -07001415 }
1416
1417 void finishEvent(uint32_t sequenceNum) {
1418 ASSERT_NE(mInputReceiver, nullptr) << "Invalid receive event on window with no receiver";
1419 mInputReceiver->finishEvent(sequenceNum);
1420 }
1421
Siarhei Vishniakouf94ae022021-02-04 01:23:17 +00001422 void sendTimeline(int32_t inputEventId, std::array<nsecs_t, GraphicsTimeline::SIZE> timeline) {
1423 ASSERT_NE(mInputReceiver, nullptr) << "Invalid receive event on window with no receiver";
1424 mInputReceiver->sendTimeline(inputEventId, timeline);
1425 }
1426
Siarhei Vishniakouef2b4502023-12-28 11:51:47 -08001427 void assertNoEvents(std::chrono::milliseconds timeout = CONSUME_TIMEOUT_NO_EVENT_EXPECTED) {
Siarhei Vishniakoua2862a02020-07-20 16:36:46 -05001428 if (mInputReceiver == nullptr &&
Prabir Pradhan51e7db02022-02-07 06:02:57 -08001429 mInfo.inputConfig.test(WindowInfo::InputConfig::NO_INPUT_CHANNEL)) {
Siarhei Vishniakoua2862a02020-07-20 16:36:46 -05001430 return; // Can't receive events if the window does not have input channel
1431 }
1432 ASSERT_NE(nullptr, mInputReceiver)
1433 << "Window without InputReceiver must specify feature NO_INPUT_CHANNEL";
Siarhei Vishniakouef2b4502023-12-28 11:51:47 -08001434 mInputReceiver->assertNoEvents(timeout);
Arthur Hungb92218b2018-08-14 12:00:21 +08001435 }
1436
chaviwaf87b3e2019-10-01 16:59:28 -07001437 sp<IBinder> getToken() { return mInfo.token; }
1438
Siarhei Vishniakouf1035d42019-09-20 16:32:01 +01001439 const std::string& getName() { return mName; }
1440
Prabir Pradhanaeebeb42023-06-13 19:53:03 +00001441 void setOwnerInfo(gui::Pid ownerPid, gui::Uid ownerUid) {
Siarhei Vishniakou870ecec2020-12-09 08:07:46 -10001442 mInfo.ownerPid = ownerPid;
1443 mInfo.ownerUid = ownerUid;
1444 }
1445
Prabir Pradhanaeebeb42023-06-13 19:53:03 +00001446 gui::Pid getPid() const { return mInfo.ownerPid; }
Prabir Pradhanedd96402022-02-15 01:46:16 -08001447
Siarhei Vishniakou7aa3e942021-11-18 09:49:11 -08001448 void destroyReceiver() { mInputReceiver = nullptr; }
1449
Prabir Pradhan07e05b62021-11-19 03:57:24 -08001450 int getChannelFd() { return mInputReceiver->getChannelFd(); }
1451
Prabir Pradhandc3a2ad2024-02-05 19:03:51 +00001452 // FakeWindowHandle uses this consume method to ensure received events are added to the trace.
Siarhei Vishniakoud3061ab2023-12-18 20:41:08 -08001453 std::unique_ptr<InputEvent> consume(std::chrono::milliseconds timeout, bool handled = true) {
Prabir Pradhan7662a8d2023-12-15 01:58:14 +00001454 if (mInputReceiver == nullptr) {
1455 LOG(FATAL) << "Cannot consume event from a window with no input event receiver";
1456 }
Siarhei Vishniakoud3061ab2023-12-18 20:41:08 -08001457 std::unique_ptr<InputEvent> event = mInputReceiver->consume(timeout, handled);
Prabir Pradhan7662a8d2023-12-15 01:58:14 +00001458 if (event == nullptr) {
Siarhei Vishniakoud3061ab2023-12-18 20:41:08 -08001459 ADD_FAILURE() << "Consume failed: no event";
Prabir Pradhan7662a8d2023-12-15 01:58:14 +00001460 }
Prabir Pradhandc3a2ad2024-02-05 19:03:51 +00001461 expectReceivedEventTraced(event);
Siarhei Vishniakoud3061ab2023-12-18 20:41:08 -08001462 return event;
Prabir Pradhan7662a8d2023-12-15 01:58:14 +00001463 }
Siarhei Vishniakouef2b4502023-12-28 11:51:47 -08001464
1465private:
1466 FakeWindowHandle(std::string name) : mName(name){};
1467 const std::string mName;
1468 std::shared_ptr<FakeInputReceiver> mInputReceiver;
1469 static std::atomic<int32_t> sId; // each window gets a unique id, like in surfaceflinger
1470 friend class sp<FakeWindowHandle>;
Prabir Pradhandc3a2ad2024-02-05 19:03:51 +00001471
1472 // FakeWindowHandle uses this receive method to ensure received events are added to the trace.
1473 std::pair<std::optional<uint32_t /*seq*/>, std::unique_ptr<InputEvent>> receive() {
1474 if (mInputReceiver == nullptr) {
1475 ADD_FAILURE() << "Invalid receive event on window with no receiver";
1476 return std::make_pair(std::nullopt, nullptr);
1477 }
1478 auto out = mInputReceiver->receiveEvent(CONSUME_TIMEOUT_EVENT_EXPECTED);
1479 const auto& [_, event] = out;
1480 expectReceivedEventTraced(event);
1481 return std::move(out);
1482 }
1483
1484 void expectReceivedEventTraced(const std::unique_ptr<InputEvent>& event) {
1485 if (!event) {
1486 return;
1487 }
1488
1489 switch (event->getType()) {
1490 case InputEventType::KEY: {
Prabir Pradhan4497c862023-12-15 07:13:30 +00001491 gVerifyingTrace->expectKeyDispatchTraced(static_cast<KeyEvent&>(*event), mInfo.id);
Prabir Pradhandc3a2ad2024-02-05 19:03:51 +00001492 break;
1493 }
1494 case InputEventType::MOTION: {
Prabir Pradhan4497c862023-12-15 07:13:30 +00001495 gVerifyingTrace->expectMotionDispatchTraced(static_cast<MotionEvent&>(*event),
1496 mInfo.id);
Prabir Pradhandc3a2ad2024-02-05 19:03:51 +00001497 break;
1498 }
1499 default:
1500 break;
1501 }
1502 }
Arthur Hung2fbf37f2018-09-13 18:16:41 +08001503};
1504
Siarhei Vishniakou540dbae2020-05-05 18:17:17 -07001505std::atomic<int32_t> FakeWindowHandle::sId{1};
1506
Prabir Pradhan112b1ad2023-09-21 09:53:53 +00001507class FakeMonitorReceiver {
1508public:
Siarhei Vishniakou2defec02023-06-08 17:24:44 -07001509 FakeMonitorReceiver(InputDispatcher& dispatcher, const std::string name, int32_t displayId)
1510 : mInputReceiver(*dispatcher.createInputMonitor(displayId, name, MONITOR_PID), name) {}
Prabir Pradhan112b1ad2023-09-21 09:53:53 +00001511
Siarhei Vishniakou2defec02023-06-08 17:24:44 -07001512 sp<IBinder> getToken() { return mInputReceiver.getToken(); }
Prabir Pradhan112b1ad2023-09-21 09:53:53 +00001513
1514 void consumeKeyDown(int32_t expectedDisplayId, int32_t expectedFlags = 0) {
Siarhei Vishniakou2defec02023-06-08 17:24:44 -07001515 mInputReceiver.consumeEvent(InputEventType::KEY, AKEY_EVENT_ACTION_DOWN, expectedDisplayId,
1516 expectedFlags);
Prabir Pradhan112b1ad2023-09-21 09:53:53 +00001517 }
1518
1519 std::optional<int32_t> receiveEvent() {
Siarhei Vishniakoud3061ab2023-12-18 20:41:08 -08001520 const auto [sequenceNum, _] = mInputReceiver.receiveEvent(CONSUME_TIMEOUT_EVENT_EXPECTED);
1521 return sequenceNum;
Prabir Pradhan112b1ad2023-09-21 09:53:53 +00001522 }
1523
Siarhei Vishniakou2defec02023-06-08 17:24:44 -07001524 void finishEvent(uint32_t consumeSeq) { return mInputReceiver.finishEvent(consumeSeq); }
Prabir Pradhan112b1ad2023-09-21 09:53:53 +00001525
1526 void consumeMotionDown(int32_t expectedDisplayId, int32_t expectedFlags = 0) {
Siarhei Vishniakou2defec02023-06-08 17:24:44 -07001527 mInputReceiver.consumeEvent(InputEventType::MOTION, AMOTION_EVENT_ACTION_DOWN,
1528 expectedDisplayId, expectedFlags);
Prabir Pradhan112b1ad2023-09-21 09:53:53 +00001529 }
1530
1531 void consumeMotionMove(int32_t expectedDisplayId, int32_t expectedFlags = 0) {
Siarhei Vishniakou2defec02023-06-08 17:24:44 -07001532 mInputReceiver.consumeEvent(InputEventType::MOTION, AMOTION_EVENT_ACTION_MOVE,
1533 expectedDisplayId, expectedFlags);
Prabir Pradhan112b1ad2023-09-21 09:53:53 +00001534 }
1535
1536 void consumeMotionUp(int32_t expectedDisplayId, int32_t expectedFlags = 0) {
Siarhei Vishniakou2defec02023-06-08 17:24:44 -07001537 mInputReceiver.consumeEvent(InputEventType::MOTION, AMOTION_EVENT_ACTION_UP,
1538 expectedDisplayId, expectedFlags);
Prabir Pradhan112b1ad2023-09-21 09:53:53 +00001539 }
1540
1541 void consumeMotionCancel(int32_t expectedDisplayId, int32_t expectedFlags = 0) {
Siarhei Vishniakou2defec02023-06-08 17:24:44 -07001542 mInputReceiver.consumeMotionEvent(
Prabir Pradhan112b1ad2023-09-21 09:53:53 +00001543 AllOf(WithMotionAction(AMOTION_EVENT_ACTION_CANCEL),
1544 WithDisplayId(expectedDisplayId),
1545 WithFlags(expectedFlags | AMOTION_EVENT_FLAG_CANCELED)));
1546 }
1547
1548 void consumeMotionPointerDown(int32_t pointerIdx) {
1549 int32_t action = AMOTION_EVENT_ACTION_POINTER_DOWN |
1550 (pointerIdx << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT);
Siarhei Vishniakou2defec02023-06-08 17:24:44 -07001551 mInputReceiver.consumeEvent(InputEventType::MOTION, action, ADISPLAY_ID_DEFAULT,
1552 /*expectedFlags=*/0);
Prabir Pradhan112b1ad2023-09-21 09:53:53 +00001553 }
1554
1555 void consumeMotionEvent(const ::testing::Matcher<MotionEvent>& matcher) {
Siarhei Vishniakou2defec02023-06-08 17:24:44 -07001556 mInputReceiver.consumeMotionEvent(matcher);
Prabir Pradhan112b1ad2023-09-21 09:53:53 +00001557 }
1558
Siarhei Vishniakoud3061ab2023-12-18 20:41:08 -08001559 std::unique_ptr<MotionEvent> consumeMotion() { return mInputReceiver.consumeMotion(); }
Prabir Pradhan112b1ad2023-09-21 09:53:53 +00001560
Siarhei Vishniakouef2b4502023-12-28 11:51:47 -08001561 void assertNoEvents() { mInputReceiver.assertNoEvents(CONSUME_TIMEOUT_NO_EVENT_EXPECTED); }
Prabir Pradhan112b1ad2023-09-21 09:53:53 +00001562
1563private:
Siarhei Vishniakou2defec02023-06-08 17:24:44 -07001564 FakeInputReceiver mInputReceiver;
Prabir Pradhan112b1ad2023-09-21 09:53:53 +00001565};
1566
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08001567static InputEventInjectionResult injectKey(
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07001568 InputDispatcher& dispatcher, int32_t action, int32_t repeatCount,
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08001569 int32_t displayId = ADISPLAY_ID_NONE,
1570 InputEventInjectionSync syncMode = InputEventInjectionSync::WAIT_FOR_RESULT,
Prabir Pradhan93f342c2021-03-11 15:05:30 -08001571 std::chrono::milliseconds injectionTimeout = INJECT_EVENT_TIMEOUT,
Prabir Pradhan8a5c41d2023-06-08 19:13:46 +00001572 bool allowKeyRepeat = true, std::optional<gui::Uid> targetUid = {},
Prabir Pradhan5735a322022-04-11 17:23:34 +00001573 uint32_t policyFlags = DEFAULT_POLICY_FLAGS) {
Arthur Hungb92218b2018-08-14 12:00:21 +08001574 KeyEvent event;
1575 nsecs_t currentTime = systemTime(SYSTEM_TIME_MONOTONIC);
1576
1577 // Define a valid key down event.
Garfield Tanfbe732e2020-01-24 11:26:14 -08001578 event.initialize(InputEvent::nextId(), DEVICE_ID, AINPUT_SOURCE_KEYBOARD, displayId,
Harry Cutts33476232023-01-30 19:57:29 +00001579 INVALID_HMAC, action, /*flags=*/0, AKEYCODE_A, KEY_A, AMETA_NONE, repeatCount,
1580 currentTime, currentTime);
Arthur Hungb92218b2018-08-14 12:00:21 +08001581
Prabir Pradhan93f342c2021-03-11 15:05:30 -08001582 if (!allowKeyRepeat) {
1583 policyFlags |= POLICY_FLAG_DISABLE_KEY_REPEAT;
1584 }
Arthur Hungb92218b2018-08-14 12:00:21 +08001585 // Inject event until dispatch out.
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07001586 return dispatcher.injectInputEvent(&event, targetUid, syncMode, injectionTimeout, policyFlags);
Arthur Hungb92218b2018-08-14 12:00:21 +08001587}
1588
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07001589static void assertInjectedKeyTimesOut(InputDispatcher& dispatcher) {
1590 InputEventInjectionResult result =
1591 injectKey(dispatcher, AKEY_EVENT_ACTION_DOWN, /*repeatCount=*/0, ADISPLAY_ID_NONE,
1592 InputEventInjectionSync::WAIT_FOR_RESULT, CONSUME_TIMEOUT_NO_EVENT_EXPECTED);
1593 if (result != InputEventInjectionResult::TIMED_OUT) {
1594 FAIL() << "Injection should have timed out, but got " << ftl::enum_string(result);
1595 }
1596}
1597
1598static InputEventInjectionResult injectKeyDown(InputDispatcher& dispatcher,
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08001599 int32_t displayId = ADISPLAY_ID_NONE) {
Harry Cutts33476232023-01-30 19:57:29 +00001600 return injectKey(dispatcher, AKEY_EVENT_ACTION_DOWN, /*repeatCount=*/0, displayId);
Siarhei Vishniakou4cb50ca2020-05-26 21:43:02 -07001601}
1602
Prabir Pradhan93f342c2021-03-11 15:05:30 -08001603// Inject a down event that has key repeat disabled. This allows InputDispatcher to idle without
1604// sending a subsequent key up. When key repeat is enabled, the dispatcher cannot idle because it
1605// has to be woken up to process the repeating key.
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07001606static InputEventInjectionResult injectKeyDownNoRepeat(InputDispatcher& dispatcher,
1607 int32_t displayId = ADISPLAY_ID_NONE) {
Harry Cutts33476232023-01-30 19:57:29 +00001608 return injectKey(dispatcher, AKEY_EVENT_ACTION_DOWN, /*repeatCount=*/0, displayId,
Prabir Pradhan93f342c2021-03-11 15:05:30 -08001609 InputEventInjectionSync::WAIT_FOR_RESULT, INJECT_EVENT_TIMEOUT,
Harry Cutts33476232023-01-30 19:57:29 +00001610 /*allowKeyRepeat=*/false);
Prabir Pradhan93f342c2021-03-11 15:05:30 -08001611}
1612
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07001613static InputEventInjectionResult injectKeyUp(InputDispatcher& dispatcher,
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08001614 int32_t displayId = ADISPLAY_ID_NONE) {
Harry Cutts33476232023-01-30 19:57:29 +00001615 return injectKey(dispatcher, AKEY_EVENT_ACTION_UP, /*repeatCount=*/0, displayId);
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07001616}
1617
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08001618static InputEventInjectionResult injectMotionEvent(
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07001619 InputDispatcher& dispatcher, const MotionEvent& event,
Garfield Tandf26e862020-07-01 20:18:19 -07001620 std::chrono::milliseconds injectionTimeout = INJECT_EVENT_TIMEOUT,
Prabir Pradhan5735a322022-04-11 17:23:34 +00001621 InputEventInjectionSync injectionMode = InputEventInjectionSync::WAIT_FOR_RESULT,
Prabir Pradhan8a5c41d2023-06-08 19:13:46 +00001622 std::optional<gui::Uid> targetUid = {}, uint32_t policyFlags = DEFAULT_POLICY_FLAGS) {
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07001623 return dispatcher.injectInputEvent(&event, targetUid, injectionMode, injectionTimeout,
1624 policyFlags);
Garfield Tandf26e862020-07-01 20:18:19 -07001625}
1626
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08001627static InputEventInjectionResult injectMotionEvent(
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07001628 InputDispatcher& dispatcher, int32_t action, int32_t source, int32_t displayId,
1629 const PointF& position = {100, 200},
Siarhei Vishniakou4cb50ca2020-05-26 21:43:02 -07001630 const PointF& cursorPosition = {AMOTION_EVENT_INVALID_CURSOR_POSITION,
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07001631 AMOTION_EVENT_INVALID_CURSOR_POSITION},
1632 std::chrono::milliseconds injectionTimeout = INJECT_EVENT_TIMEOUT,
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08001633 InputEventInjectionSync injectionMode = InputEventInjectionSync::WAIT_FOR_RESULT,
Prabir Pradhan5735a322022-04-11 17:23:34 +00001634 nsecs_t eventTime = systemTime(SYSTEM_TIME_MONOTONIC),
Prabir Pradhan8a5c41d2023-06-08 19:13:46 +00001635 std::optional<gui::Uid> targetUid = {}, uint32_t policyFlags = DEFAULT_POLICY_FLAGS) {
Siarhei Vishniakou90ee4782023-05-08 11:57:24 -07001636 MotionEventBuilder motionBuilder =
1637 MotionEventBuilder(action, source)
1638 .displayId(displayId)
1639 .eventTime(eventTime)
1640 .rawXCursorPosition(cursorPosition.x)
1641 .rawYCursorPosition(cursorPosition.y)
1642 .pointer(
1643 PointerBuilder(/*id=*/0, ToolType::FINGER).x(position.x).y(position.y));
1644 if (MotionEvent::getActionMasked(action) == ACTION_DOWN) {
1645 motionBuilder.downTime(eventTime);
1646 }
Arthur Hungb92218b2018-08-14 12:00:21 +08001647
1648 // Inject event until dispatch out.
Siarhei Vishniakou90ee4782023-05-08 11:57:24 -07001649 return injectMotionEvent(dispatcher, motionBuilder.build(), injectionTimeout, injectionMode,
1650 targetUid, policyFlags);
Arthur Hungb92218b2018-08-14 12:00:21 +08001651}
1652
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07001653static InputEventInjectionResult injectMotionDown(InputDispatcher& dispatcher, int32_t source,
1654 int32_t displayId,
1655 const PointF& location = {100, 200}) {
Siarhei Vishniakou4cb50ca2020-05-26 21:43:02 -07001656 return injectMotionEvent(dispatcher, AMOTION_EVENT_ACTION_DOWN, source, displayId, location);
Garfield Tan00f511d2019-06-12 16:55:40 -07001657}
1658
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07001659static InputEventInjectionResult injectMotionUp(InputDispatcher& dispatcher, int32_t source,
1660 int32_t displayId,
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08001661 const PointF& location = {100, 200}) {
Siarhei Vishniakou4cb50ca2020-05-26 21:43:02 -07001662 return injectMotionEvent(dispatcher, AMOTION_EVENT_ACTION_UP, source, displayId, location);
Michael Wright3a240c42019-12-10 20:53:41 +00001663}
1664
Jackal Guof9696682018-10-05 12:23:23 +08001665static NotifyKeyArgs generateKeyArgs(int32_t action, int32_t displayId = ADISPLAY_ID_NONE) {
1666 nsecs_t currentTime = systemTime(SYSTEM_TIME_MONOTONIC);
1667 // Define a valid key event.
Prabir Pradhana8fe7c52023-12-14 22:07:23 +00001668 NotifyKeyArgs args(InputEvent::nextId(), currentTime, /*readTime=*/0, DEVICE_ID,
1669 AINPUT_SOURCE_KEYBOARD, displayId, POLICY_FLAG_PASS_TO_USER, action,
1670 /*flags=*/0, AKEYCODE_A, KEY_A, AMETA_NONE, currentTime);
Jackal Guof9696682018-10-05 12:23:23 +08001671
1672 return args;
1673}
1674
Josep del Riob3981622023-04-18 15:49:45 +00001675static NotifyKeyArgs generateSystemShortcutArgs(int32_t action,
1676 int32_t displayId = ADISPLAY_ID_NONE) {
1677 nsecs_t currentTime = systemTime(SYSTEM_TIME_MONOTONIC);
1678 // Define a valid key event.
Prabir Pradhana8fe7c52023-12-14 22:07:23 +00001679 NotifyKeyArgs args(InputEvent::nextId(), currentTime, /*readTime=*/0, DEVICE_ID,
1680 AINPUT_SOURCE_KEYBOARD, displayId, 0, action, /*flags=*/0, AKEYCODE_C, KEY_C,
1681 AMETA_META_ON, currentTime);
Josep del Riob3981622023-04-18 15:49:45 +00001682
1683 return args;
1684}
1685
1686static NotifyKeyArgs generateAssistantKeyArgs(int32_t action,
1687 int32_t displayId = ADISPLAY_ID_NONE) {
1688 nsecs_t currentTime = systemTime(SYSTEM_TIME_MONOTONIC);
1689 // Define a valid key event.
Prabir Pradhana8fe7c52023-12-14 22:07:23 +00001690 NotifyKeyArgs args(InputEvent::nextId(), currentTime, /*readTime=*/0, DEVICE_ID,
1691 AINPUT_SOURCE_KEYBOARD, displayId, 0, action, /*flags=*/0, AKEYCODE_ASSIST,
1692 KEY_ASSISTANT, AMETA_NONE, currentTime);
Josep del Riob3981622023-04-18 15:49:45 +00001693
1694 return args;
1695}
1696
Prabir Pradhan678438e2023-04-13 19:32:51 +00001697[[nodiscard]] static NotifyMotionArgs generateMotionArgs(int32_t action, int32_t source,
1698 int32_t displayId,
1699 const std::vector<PointF>& points) {
chaviwd1c23182019-12-20 18:44:56 -08001700 size_t pointerCount = points.size();
chaviwaf87b3e2019-10-01 16:59:28 -07001701 if (action == AMOTION_EVENT_ACTION_DOWN || action == AMOTION_EVENT_ACTION_UP) {
1702 EXPECT_EQ(1U, pointerCount) << "Actions DOWN and UP can only contain a single pointer";
1703 }
1704
chaviwd1c23182019-12-20 18:44:56 -08001705 PointerProperties pointerProperties[pointerCount];
1706 PointerCoords pointerCoords[pointerCount];
Jackal Guof9696682018-10-05 12:23:23 +08001707
chaviwd1c23182019-12-20 18:44:56 -08001708 for (size_t i = 0; i < pointerCount; i++) {
1709 pointerProperties[i].clear();
1710 pointerProperties[i].id = i;
Siarhei Vishniakou6d73f832022-07-21 17:27:03 -07001711 pointerProperties[i].toolType = ToolType::FINGER;
Jackal Guof9696682018-10-05 12:23:23 +08001712
chaviwd1c23182019-12-20 18:44:56 -08001713 pointerCoords[i].clear();
1714 pointerCoords[i].setAxisValue(AMOTION_EVENT_AXIS_X, points[i].x);
1715 pointerCoords[i].setAxisValue(AMOTION_EVENT_AXIS_Y, points[i].y);
1716 }
Jackal Guof9696682018-10-05 12:23:23 +08001717
1718 nsecs_t currentTime = systemTime(SYSTEM_TIME_MONOTONIC);
1719 // Define a valid motion event.
Prabir Pradhana8fe7c52023-12-14 22:07:23 +00001720 NotifyMotionArgs args(InputEvent::nextId(), currentTime, /*readTime=*/0, DEVICE_ID, source,
1721 displayId, POLICY_FLAG_PASS_TO_USER, action, /*actionButton=*/0,
1722 /*flags=*/0, AMETA_NONE, /*buttonState=*/0, MotionClassification::NONE,
chaviwd1c23182019-12-20 18:44:56 -08001723 AMOTION_EVENT_EDGE_FLAG_NONE, pointerCount, pointerProperties,
Harry Cutts101ee9b2023-07-06 18:04:14 +00001724 pointerCoords, /*xPrecision=*/0, /*yPrecision=*/0,
Garfield Tan00f511d2019-06-12 16:55:40 -07001725 AMOTION_EVENT_INVALID_CURSOR_POSITION,
Harry Cutts101ee9b2023-07-06 18:04:14 +00001726 AMOTION_EVENT_INVALID_CURSOR_POSITION, currentTime, /*videoFrames=*/{});
Jackal Guof9696682018-10-05 12:23:23 +08001727
1728 return args;
1729}
1730
Siarhei Vishniakoua16e3a22022-03-02 15:26:40 -08001731static NotifyMotionArgs generateTouchArgs(int32_t action, const std::vector<PointF>& points) {
1732 return generateMotionArgs(action, AINPUT_SOURCE_TOUCHSCREEN, DISPLAY_ID, points);
1733}
1734
chaviwd1c23182019-12-20 18:44:56 -08001735static NotifyMotionArgs generateMotionArgs(int32_t action, int32_t source, int32_t displayId) {
1736 return generateMotionArgs(action, source, displayId, {PointF{100, 200}});
1737}
1738
Prabir Pradhan5cc1a692021-08-06 14:01:18 +00001739static NotifyPointerCaptureChangedArgs generatePointerCaptureChangedArgs(
1740 const PointerCaptureRequest& request) {
Prabir Pradhana8fe7c52023-12-14 22:07:23 +00001741 return NotifyPointerCaptureChangedArgs(InputEvent::nextId(), systemTime(SYSTEM_TIME_MONOTONIC),
1742 request);
Prabir Pradhan99987712020-11-10 18:43:05 -08001743}
1744
Siarhei Vishniakouadeb6fa2023-05-26 09:11:06 -07001745} // namespace
1746
Siarhei Vishniakou7aa3e942021-11-18 09:49:11 -08001747/**
1748 * When a window unexpectedly disposes of its input channel, policy should be notified about the
1749 * broken channel.
1750 */
1751TEST_F(InputDispatcherTest, WhenInputChannelBreaks_PolicyIsNotified) {
1752 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
1753 sp<FakeWindowHandle> window =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07001754 sp<FakeWindowHandle>::make(application, mDispatcher,
1755 "Window that breaks its input channel", ADISPLAY_ID_DEFAULT);
Siarhei Vishniakou7aa3e942021-11-18 09:49:11 -08001756
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07001757 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Siarhei Vishniakou7aa3e942021-11-18 09:49:11 -08001758
1759 // Window closes its channel, but the window remains.
1760 window->destroyReceiver();
1761 mFakePolicy->assertNotifyInputChannelBrokenWasCalled(window->getInfo()->token);
1762}
1763
Arthur Hungb92218b2018-08-14 12:00:21 +08001764TEST_F(InputDispatcherTest, SetInputWindow_SingleWindowTouch) {
Chris Yea209fde2020-07-22 13:54:51 -07001765 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07001766 sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher,
1767 "Fake Window", ADISPLAY_ID_DEFAULT);
Arthur Hungb92218b2018-08-14 12:00:21 +08001768
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07001769 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08001770 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07001771 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT))
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08001772 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
Arthur Hungb92218b2018-08-14 12:00:21 +08001773
1774 // Window should receive motion event.
Siarhei Vishniakouc5ca85c2019-11-15 17:20:00 -08001775 window->consumeMotionDown(ADISPLAY_ID_DEFAULT);
Arthur Hungb92218b2018-08-14 12:00:21 +08001776}
1777
Siarhei Vishniakouaeed0da2024-01-09 08:57:13 -08001778using InputDispatcherDeathTest = InputDispatcherTest;
1779
1780/**
1781 * When 'onWindowInfosChanged' arguments contain a duplicate entry for the same window, dispatcher
1782 * should crash.
1783 */
1784TEST_F(InputDispatcherDeathTest, DuplicateWindowInfosAbortDispatcher) {
1785 testing::GTEST_FLAG(death_test_style) = "threadsafe";
1786 ScopedSilentDeath _silentDeath;
1787
1788 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
1789 sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher,
1790 "Fake Window", ADISPLAY_ID_DEFAULT);
1791 ASSERT_DEATH(mDispatcher->onWindowInfosChanged(
1792 {{*window->getInfo(), *window->getInfo()}, {}, 0, 0}),
1793 "Incorrect WindowInfosUpdate provided");
1794}
1795
Prabir Pradhanc44ce4d2021-10-05 05:26:29 -07001796TEST_F(InputDispatcherTest, WhenDisplayNotSpecified_InjectMotionToDefaultDisplay) {
1797 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07001798 sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher,
1799 "Fake Window", ADISPLAY_ID_DEFAULT);
Prabir Pradhanc44ce4d2021-10-05 05:26:29 -07001800
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07001801 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Prabir Pradhanc44ce4d2021-10-05 05:26:29 -07001802 // Inject a MotionEvent to an unknown display.
1803 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07001804 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_NONE))
Prabir Pradhanc44ce4d2021-10-05 05:26:29 -07001805 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
1806
1807 // Window should receive motion event.
1808 window->consumeMotionDown(ADISPLAY_ID_DEFAULT);
1809}
1810
Siarhei Vishniakoufb9fcda2020-05-04 14:59:19 -07001811/**
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07001812 * Calling onWindowInfosChanged once should not cause any issues.
1813 * This test serves as a sanity check for the next test, where onWindowInfosChanged is
Siarhei Vishniakoufb9fcda2020-05-04 14:59:19 -07001814 * called twice.
1815 */
Prabir Pradhan76bdecb2022-01-31 11:14:15 -08001816TEST_F(InputDispatcherTest, SetInputWindowOnceWithSingleTouchWindow) {
Chris Yea209fde2020-07-22 13:54:51 -07001817 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07001818 sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher,
1819 "Fake Window", ADISPLAY_ID_DEFAULT);
Siarhei Vishniakoufb9fcda2020-05-04 14:59:19 -07001820 window->setFrame(Rect(0, 0, 100, 100));
Siarhei Vishniakoufb9fcda2020-05-04 14:59:19 -07001821
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07001822 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08001823 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07001824 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
Siarhei Vishniakoufb9fcda2020-05-04 14:59:19 -07001825 {50, 50}))
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08001826 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
Siarhei Vishniakoufb9fcda2020-05-04 14:59:19 -07001827
1828 // Window should receive motion event.
1829 window->consumeMotionDown(ADISPLAY_ID_DEFAULT);
1830}
1831
1832/**
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07001833 * Calling onWindowInfosChanged twice, with the same info, should not cause any issues.
Siarhei Vishniakoufb9fcda2020-05-04 14:59:19 -07001834 */
1835TEST_F(InputDispatcherTest, SetInputWindowTwice_SingleWindowTouch) {
Chris Yea209fde2020-07-22 13:54:51 -07001836 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07001837 sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher,
1838 "Fake Window", ADISPLAY_ID_DEFAULT);
Siarhei Vishniakoufb9fcda2020-05-04 14:59:19 -07001839 window->setFrame(Rect(0, 0, 100, 100));
Siarhei Vishniakoufb9fcda2020-05-04 14:59:19 -07001840
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07001841 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
1842 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08001843 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07001844 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
Siarhei Vishniakoufb9fcda2020-05-04 14:59:19 -07001845 {50, 50}))
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08001846 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
Siarhei Vishniakoufb9fcda2020-05-04 14:59:19 -07001847
1848 // Window should receive motion event.
1849 window->consumeMotionDown(ADISPLAY_ID_DEFAULT);
1850}
1851
Arthur Hungb92218b2018-08-14 12:00:21 +08001852// The foreground window should receive the first touch down event.
1853TEST_F(InputDispatcherTest, SetInputWindow_MultiWindowsTouch) {
Chris Yea209fde2020-07-22 13:54:51 -07001854 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
Siarhei Vishniakou870ecec2020-12-09 08:07:46 -10001855 sp<FakeWindowHandle> windowTop =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07001856 sp<FakeWindowHandle>::make(application, mDispatcher, "Top", ADISPLAY_ID_DEFAULT);
Siarhei Vishniakou870ecec2020-12-09 08:07:46 -10001857 sp<FakeWindowHandle> windowSecond =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07001858 sp<FakeWindowHandle>::make(application, mDispatcher, "Second", ADISPLAY_ID_DEFAULT);
Arthur Hungb92218b2018-08-14 12:00:21 +08001859
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07001860 mDispatcher->onWindowInfosChanged(
1861 {{*windowTop->getInfo(), *windowSecond->getInfo()}, {}, 0, 0});
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08001862 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07001863 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT))
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08001864 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
Arthur Hungb92218b2018-08-14 12:00:21 +08001865
1866 // Top window should receive the touch down event. Second window should not receive anything.
Siarhei Vishniakouc5ca85c2019-11-15 17:20:00 -08001867 windowTop->consumeMotionDown(ADISPLAY_ID_DEFAULT);
Arthur Hungb92218b2018-08-14 12:00:21 +08001868 windowSecond->assertNoEvents();
1869}
1870
Siarhei Vishniakouca205502021-07-16 21:31:58 +00001871/**
1872 * Two windows: A top window, and a wallpaper behind the window.
1873 * Touch goes to the top window, and then top window disappears. Ensure that wallpaper window
1874 * gets ACTION_CANCEL.
Prabir Pradhan4d5c52f2022-01-31 08:52:10 -08001875 * 1. foregroundWindow <-- dup touch to wallpaper
1876 * 2. wallpaperWindow <-- is wallpaper
Siarhei Vishniakouca205502021-07-16 21:31:58 +00001877 */
1878TEST_F(InputDispatcherTest, WhenForegroundWindowDisappears_WallpaperTouchIsCanceled) {
1879 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
1880 sp<FakeWindowHandle> foregroundWindow =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07001881 sp<FakeWindowHandle>::make(application, mDispatcher, "Foreground", ADISPLAY_ID_DEFAULT);
Prabir Pradhan4d5c52f2022-01-31 08:52:10 -08001882 foregroundWindow->setDupTouchToWallpaper(true);
Siarhei Vishniakouca205502021-07-16 21:31:58 +00001883 sp<FakeWindowHandle> wallpaperWindow =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07001884 sp<FakeWindowHandle>::make(application, mDispatcher, "Wallpaper", ADISPLAY_ID_DEFAULT);
Prabir Pradhan4d5c52f2022-01-31 08:52:10 -08001885 wallpaperWindow->setIsWallpaper(true);
Siarhei Vishniakouca205502021-07-16 21:31:58 +00001886
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07001887 mDispatcher->onWindowInfosChanged(
1888 {{*foregroundWindow->getInfo(), *wallpaperWindow->getInfo()}, {}, 0, 0});
Siarhei Vishniakouca205502021-07-16 21:31:58 +00001889 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoud908f5a2023-11-16 10:25:12 -08001890 injectMotionEvent(*mDispatcher,
1891 MotionEventBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
1892 .pointer(PointerBuilder(0, ToolType::FINGER).x(100).y(200))
1893 .build()))
Siarhei Vishniakouca205502021-07-16 21:31:58 +00001894 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
1895
1896 // Both foreground window and its wallpaper should receive the touch down
1897 foregroundWindow->consumeMotionDown();
1898 wallpaperWindow->consumeMotionDown(ADISPLAY_ID_DEFAULT, expectedWallpaperFlags);
1899
1900 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoud908f5a2023-11-16 10:25:12 -08001901 injectMotionEvent(*mDispatcher,
1902 MotionEventBuilder(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN)
1903 .pointer(PointerBuilder(0, ToolType::FINGER).x(110).y(200))
1904 .build()))
Siarhei Vishniakouca205502021-07-16 21:31:58 +00001905 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
1906
Siarhei Vishniakoud908f5a2023-11-16 10:25:12 -08001907 foregroundWindow->consumeMotionEvent(WithMotionAction(ACTION_MOVE));
Siarhei Vishniakouca205502021-07-16 21:31:58 +00001908 wallpaperWindow->consumeMotionMove(ADISPLAY_ID_DEFAULT, expectedWallpaperFlags);
1909
1910 // Now the foreground window goes away, but the wallpaper stays
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07001911 mDispatcher->onWindowInfosChanged({{*wallpaperWindow->getInfo()}, {}, 0, 0});
Siarhei Vishniakouca205502021-07-16 21:31:58 +00001912 foregroundWindow->consumeMotionCancel();
1913 // Since the "parent" window of the wallpaper is gone, wallpaper should receive cancel, too.
1914 wallpaperWindow->consumeMotionCancel(ADISPLAY_ID_DEFAULT, expectedWallpaperFlags);
1915}
1916
1917/**
Siarhei Vishniakou82dc0422023-02-17 23:12:52 -08001918 * Two fingers down on the window, and lift off the first finger.
1919 * Next, cancel the gesture to the window by removing the window. Make sure that the CANCEL event
1920 * contains a single pointer.
1921 */
1922TEST_F(InputDispatcherTest, CancelAfterPointer0Up) {
1923 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
1924 sp<FakeWindowHandle> window =
1925 sp<FakeWindowHandle>::make(application, mDispatcher, "Window", ADISPLAY_ID_DEFAULT);
1926
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07001927 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Siarhei Vishniakou82dc0422023-02-17 23:12:52 -08001928 // First touch pointer down on right window
Prabir Pradhan678438e2023-04-13 19:32:51 +00001929 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
1930 .pointer(PointerBuilder(0, ToolType::FINGER).x(100).y(100))
1931 .build());
Siarhei Vishniakou82dc0422023-02-17 23:12:52 -08001932 // Second touch pointer down
Prabir Pradhan678438e2023-04-13 19:32:51 +00001933 mDispatcher->notifyMotion(MotionArgsBuilder(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
1934 .pointer(PointerBuilder(0, ToolType::FINGER).x(100).y(100))
1935 .pointer(PointerBuilder(1, ToolType::FINGER).x(110).y(100))
1936 .build());
Siarhei Vishniakou82dc0422023-02-17 23:12:52 -08001937 // First touch pointer lifts. The second one remains down
Prabir Pradhan678438e2023-04-13 19:32:51 +00001938 mDispatcher->notifyMotion(MotionArgsBuilder(POINTER_0_UP, AINPUT_SOURCE_TOUCHSCREEN)
1939 .pointer(PointerBuilder(0, ToolType::FINGER).x(100).y(100))
1940 .pointer(PointerBuilder(1, ToolType::FINGER).x(110).y(100))
1941 .build());
Siarhei Vishniakou82dc0422023-02-17 23:12:52 -08001942 window->consumeMotionEvent(WithMotionAction(ACTION_DOWN));
1943 window->consumeMotionEvent(WithMotionAction(POINTER_1_DOWN));
1944 window->consumeMotionEvent(WithMotionAction(POINTER_0_UP));
1945
1946 // Remove the window. The gesture should be canceled
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07001947 mDispatcher->onWindowInfosChanged({{}, {}, 0, 0});
Siarhei Vishniakou82dc0422023-02-17 23:12:52 -08001948 const std::map<int32_t, PointF> expectedPointers{{1, PointF{110, 100}}};
1949 window->consumeMotionEvent(
1950 AllOf(WithMotionAction(ACTION_CANCEL), WithPointers(expectedPointers)));
1951}
1952
1953/**
Siarhei Vishniakou2b030972021-11-18 10:01:27 -08001954 * Same test as WhenForegroundWindowDisappears_WallpaperTouchIsCanceled above,
1955 * with the following differences:
1956 * After ACTION_DOWN, Wallpaper window hangs up its channel, which forces the dispatcher to
1957 * clean up the connection.
1958 * This later may crash dispatcher during ACTION_CANCEL synthesis, if the dispatcher is not careful.
1959 * Ensure that there's no crash in the dispatcher.
1960 */
1961TEST_F(InputDispatcherTest, WhenWallpaperDisappears_NoCrash) {
1962 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
1963 sp<FakeWindowHandle> foregroundWindow =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07001964 sp<FakeWindowHandle>::make(application, mDispatcher, "Foreground", ADISPLAY_ID_DEFAULT);
Prabir Pradhan4d5c52f2022-01-31 08:52:10 -08001965 foregroundWindow->setDupTouchToWallpaper(true);
Siarhei Vishniakou2b030972021-11-18 10:01:27 -08001966 sp<FakeWindowHandle> wallpaperWindow =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07001967 sp<FakeWindowHandle>::make(application, mDispatcher, "Wallpaper", ADISPLAY_ID_DEFAULT);
Prabir Pradhan4d5c52f2022-01-31 08:52:10 -08001968 wallpaperWindow->setIsWallpaper(true);
Siarhei Vishniakou2b030972021-11-18 10:01:27 -08001969
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07001970 mDispatcher->onWindowInfosChanged(
1971 {{*foregroundWindow->getInfo(), *wallpaperWindow->getInfo()}, {}, 0, 0});
Siarhei Vishniakou2b030972021-11-18 10:01:27 -08001972 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07001973 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
Siarhei Vishniakou2b030972021-11-18 10:01:27 -08001974 {100, 200}))
1975 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
1976
1977 // Both foreground window and its wallpaper should receive the touch down
1978 foregroundWindow->consumeMotionDown();
1979 wallpaperWindow->consumeMotionDown(ADISPLAY_ID_DEFAULT, expectedWallpaperFlags);
1980
1981 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07001982 injectMotionEvent(*mDispatcher, AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN,
Siarhei Vishniakou2b030972021-11-18 10:01:27 -08001983 ADISPLAY_ID_DEFAULT, {110, 200}))
1984 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
1985
1986 foregroundWindow->consumeMotionMove();
1987 wallpaperWindow->consumeMotionMove(ADISPLAY_ID_DEFAULT, expectedWallpaperFlags);
1988
1989 // Wallpaper closes its channel, but the window remains.
1990 wallpaperWindow->destroyReceiver();
1991 mFakePolicy->assertNotifyInputChannelBrokenWasCalled(wallpaperWindow->getInfo()->token);
1992
1993 // Now the foreground window goes away, but the wallpaper stays, even though its channel
1994 // is no longer valid.
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07001995 mDispatcher->onWindowInfosChanged({{*wallpaperWindow->getInfo()}, {}, 0, 0});
Siarhei Vishniakou2b030972021-11-18 10:01:27 -08001996 foregroundWindow->consumeMotionCancel();
1997}
1998
Arthur Hungc539dbb2022-12-08 07:45:36 +00001999class ShouldSplitTouchFixture : public InputDispatcherTest,
2000 public ::testing::WithParamInterface<bool> {};
2001INSTANTIATE_TEST_SUITE_P(InputDispatcherTest, ShouldSplitTouchFixture,
2002 ::testing::Values(true, false));
Siarhei Vishniakou2b030972021-11-18 10:01:27 -08002003/**
Siarhei Vishniakouca205502021-07-16 21:31:58 +00002004 * A single window that receives touch (on top), and a wallpaper window underneath it.
2005 * The top window gets a multitouch gesture.
2006 * Ensure that wallpaper gets the same gesture.
2007 */
Arthur Hungc539dbb2022-12-08 07:45:36 +00002008TEST_P(ShouldSplitTouchFixture, WallpaperWindowReceivesMultiTouch) {
Siarhei Vishniakouca205502021-07-16 21:31:58 +00002009 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
Arthur Hungc539dbb2022-12-08 07:45:36 +00002010 sp<FakeWindowHandle> foregroundWindow =
2011 sp<FakeWindowHandle>::make(application, mDispatcher, "Foreground", ADISPLAY_ID_DEFAULT);
2012 foregroundWindow->setDupTouchToWallpaper(true);
2013 foregroundWindow->setPreventSplitting(GetParam());
Siarhei Vishniakouca205502021-07-16 21:31:58 +00002014
2015 sp<FakeWindowHandle> wallpaperWindow =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07002016 sp<FakeWindowHandle>::make(application, mDispatcher, "Wallpaper", ADISPLAY_ID_DEFAULT);
Prabir Pradhan4d5c52f2022-01-31 08:52:10 -08002017 wallpaperWindow->setIsWallpaper(true);
Siarhei Vishniakouca205502021-07-16 21:31:58 +00002018
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07002019 mDispatcher->onWindowInfosChanged(
2020 {{*foregroundWindow->getInfo(), *wallpaperWindow->getInfo()}, {}, 0, 0});
Siarhei Vishniakouca205502021-07-16 21:31:58 +00002021
2022 // Touch down on top window
2023 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07002024 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
Siarhei Vishniakouca205502021-07-16 21:31:58 +00002025 {100, 100}))
2026 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
2027
2028 // Both top window and its wallpaper should receive the touch down
Arthur Hungc539dbb2022-12-08 07:45:36 +00002029 foregroundWindow->consumeMotionDown();
Siarhei Vishniakouca205502021-07-16 21:31:58 +00002030 wallpaperWindow->consumeMotionDown(ADISPLAY_ID_DEFAULT, expectedWallpaperFlags);
2031
2032 // Second finger down on the top window
2033 const MotionEvent secondFingerDownEvent =
Siarhei Vishniakoua16e3a22022-03-02 15:26:40 -08002034 MotionEventBuilder(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
Siarhei Vishniakouca205502021-07-16 21:31:58 +00002035 .eventTime(systemTime(SYSTEM_TIME_MONOTONIC))
Siarhei Vishniakou6d73f832022-07-21 17:27:03 -07002036 .pointer(PointerBuilder(/*id=*/0, ToolType::FINGER).x(100).y(100))
2037 .pointer(PointerBuilder(/*id=*/1, ToolType::FINGER).x(150).y(150))
Siarhei Vishniakouca205502021-07-16 21:31:58 +00002038 .build();
2039 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07002040 injectMotionEvent(*mDispatcher, secondFingerDownEvent, INJECT_EVENT_TIMEOUT,
Siarhei Vishniakouca205502021-07-16 21:31:58 +00002041 InputEventInjectionSync::WAIT_FOR_RESULT))
2042 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
2043
Harry Cutts33476232023-01-30 19:57:29 +00002044 foregroundWindow->consumeMotionPointerDown(/*pointerIndex=*/1);
2045 wallpaperWindow->consumeMotionPointerDown(/*pointerIndex=*/1, ADISPLAY_ID_DEFAULT,
Siarhei Vishniakouca205502021-07-16 21:31:58 +00002046 expectedWallpaperFlags);
Arthur Hungc539dbb2022-12-08 07:45:36 +00002047
2048 const MotionEvent secondFingerUpEvent =
2049 MotionEventBuilder(POINTER_0_UP, AINPUT_SOURCE_TOUCHSCREEN)
2050 .displayId(ADISPLAY_ID_DEFAULT)
2051 .eventTime(systemTime(SYSTEM_TIME_MONOTONIC))
Siarhei Vishniakou6d73f832022-07-21 17:27:03 -07002052 .pointer(PointerBuilder(/*id=*/0, ToolType::FINGER).x(100).y(100))
2053 .pointer(PointerBuilder(/*id=*/1, ToolType::FINGER).x(150).y(150))
Arthur Hungc539dbb2022-12-08 07:45:36 +00002054 .build();
2055 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07002056 injectMotionEvent(*mDispatcher, secondFingerUpEvent, INJECT_EVENT_TIMEOUT,
Arthur Hungc539dbb2022-12-08 07:45:36 +00002057 InputEventInjectionSync::WAIT_FOR_RESULT))
2058 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
2059 foregroundWindow->consumeMotionPointerUp(0);
2060 wallpaperWindow->consumeMotionPointerUp(0, ADISPLAY_ID_DEFAULT, expectedWallpaperFlags);
2061
2062 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07002063 injectMotionEvent(*mDispatcher,
Siarhei Vishniakou92c8fd52023-01-29 14:57:43 -08002064 MotionEventBuilder(AMOTION_EVENT_ACTION_UP,
2065 AINPUT_SOURCE_TOUCHSCREEN)
2066 .displayId(ADISPLAY_ID_DEFAULT)
2067 .eventTime(systemTime(SYSTEM_TIME_MONOTONIC))
Harry Cutts101ee9b2023-07-06 18:04:14 +00002068 .pointer(PointerBuilder(/*id=*/1, ToolType::FINGER)
Siarhei Vishniakou92c8fd52023-01-29 14:57:43 -08002069 .x(100)
2070 .y(100))
2071 .build(),
2072 INJECT_EVENT_TIMEOUT, InputEventInjectionSync::WAIT_FOR_RESULT))
Arthur Hungc539dbb2022-12-08 07:45:36 +00002073 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
2074 foregroundWindow->consumeMotionUp(ADISPLAY_ID_DEFAULT);
2075 wallpaperWindow->consumeMotionUp(ADISPLAY_ID_DEFAULT, expectedWallpaperFlags);
Siarhei Vishniakouca205502021-07-16 21:31:58 +00002076}
2077
2078/**
2079 * Two windows: a window on the left and window on the right.
2080 * A third window, wallpaper, is behind both windows, and spans both top windows.
2081 * The first touch down goes to the left window. A second pointer touches down on the right window.
2082 * The touch is split, so both left and right windows should receive ACTION_DOWN.
2083 * The wallpaper will get the full event, so it should receive ACTION_DOWN followed by
2084 * ACTION_POINTER_DOWN(1).
2085 */
2086TEST_F(InputDispatcherTest, TwoWindows_SplitWallpaperTouch) {
2087 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
2088 sp<FakeWindowHandle> leftWindow =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07002089 sp<FakeWindowHandle>::make(application, mDispatcher, "Left", ADISPLAY_ID_DEFAULT);
Siarhei Vishniakouca205502021-07-16 21:31:58 +00002090 leftWindow->setFrame(Rect(0, 0, 200, 200));
Prabir Pradhan4d5c52f2022-01-31 08:52:10 -08002091 leftWindow->setDupTouchToWallpaper(true);
Siarhei Vishniakouca205502021-07-16 21:31:58 +00002092
2093 sp<FakeWindowHandle> rightWindow =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07002094 sp<FakeWindowHandle>::make(application, mDispatcher, "Right", ADISPLAY_ID_DEFAULT);
Siarhei Vishniakouca205502021-07-16 21:31:58 +00002095 rightWindow->setFrame(Rect(200, 0, 400, 200));
Prabir Pradhan4d5c52f2022-01-31 08:52:10 -08002096 rightWindow->setDupTouchToWallpaper(true);
Siarhei Vishniakouca205502021-07-16 21:31:58 +00002097
2098 sp<FakeWindowHandle> wallpaperWindow =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07002099 sp<FakeWindowHandle>::make(application, mDispatcher, "Wallpaper", ADISPLAY_ID_DEFAULT);
Siarhei Vishniakouca205502021-07-16 21:31:58 +00002100 wallpaperWindow->setFrame(Rect(0, 0, 400, 200));
Prabir Pradhan4d5c52f2022-01-31 08:52:10 -08002101 wallpaperWindow->setIsWallpaper(true);
Siarhei Vishniakouca205502021-07-16 21:31:58 +00002102
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07002103 mDispatcher->onWindowInfosChanged(
2104 {{*leftWindow->getInfo(), *rightWindow->getInfo(), *wallpaperWindow->getInfo()},
2105 {},
2106 0,
2107 0});
Siarhei Vishniakouca205502021-07-16 21:31:58 +00002108
2109 // Touch down on left window
2110 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07002111 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
Siarhei Vishniakouca205502021-07-16 21:31:58 +00002112 {100, 100}))
2113 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
2114
2115 // Both foreground window and its wallpaper should receive the touch down
2116 leftWindow->consumeMotionDown();
2117 wallpaperWindow->consumeMotionDown(ADISPLAY_ID_DEFAULT, expectedWallpaperFlags);
2118
2119 // Second finger down on the right window
2120 const MotionEvent secondFingerDownEvent =
Siarhei Vishniakoua16e3a22022-03-02 15:26:40 -08002121 MotionEventBuilder(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
Siarhei Vishniakouca205502021-07-16 21:31:58 +00002122 .eventTime(systemTime(SYSTEM_TIME_MONOTONIC))
Siarhei Vishniakou6d73f832022-07-21 17:27:03 -07002123 .pointer(PointerBuilder(/*id=*/0, ToolType::FINGER).x(100).y(100))
2124 .pointer(PointerBuilder(/*id=*/1, ToolType::FINGER).x(300).y(100))
Siarhei Vishniakouca205502021-07-16 21:31:58 +00002125 .build();
2126 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07002127 injectMotionEvent(*mDispatcher, secondFingerDownEvent, INJECT_EVENT_TIMEOUT,
Siarhei Vishniakouca205502021-07-16 21:31:58 +00002128 InputEventInjectionSync::WAIT_FOR_RESULT))
2129 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
2130
2131 leftWindow->consumeMotionMove();
2132 // Since the touch is split, right window gets ACTION_DOWN
2133 rightWindow->consumeMotionDown(ADISPLAY_ID_DEFAULT);
Harry Cutts33476232023-01-30 19:57:29 +00002134 wallpaperWindow->consumeMotionPointerDown(/*pointerIndex=*/1, ADISPLAY_ID_DEFAULT,
Siarhei Vishniakouca205502021-07-16 21:31:58 +00002135 expectedWallpaperFlags);
2136
2137 // Now, leftWindow, which received the first finger, disappears.
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07002138 mDispatcher->onWindowInfosChanged(
2139 {{*rightWindow->getInfo(), *wallpaperWindow->getInfo()}, {}, 0, 0});
Siarhei Vishniakouca205502021-07-16 21:31:58 +00002140 leftWindow->consumeMotionCancel();
2141 // Since a "parent" window of the wallpaper is gone, wallpaper should receive cancel, too.
2142 wallpaperWindow->consumeMotionCancel(ADISPLAY_ID_DEFAULT, expectedWallpaperFlags);
2143
2144 // The pointer that's still down on the right window moves, and goes to the right window only.
2145 // As far as the dispatcher's concerned though, both pointers are still present.
2146 const MotionEvent secondFingerMoveEvent =
2147 MotionEventBuilder(AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN)
2148 .eventTime(systemTime(SYSTEM_TIME_MONOTONIC))
Siarhei Vishniakou6d73f832022-07-21 17:27:03 -07002149 .pointer(PointerBuilder(/*id=*/0, ToolType::FINGER).x(100).y(100))
2150 .pointer(PointerBuilder(/*id=*/1, ToolType::FINGER).x(310).y(110))
Siarhei Vishniakouca205502021-07-16 21:31:58 +00002151 .build();
2152 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07002153 injectMotionEvent(*mDispatcher, secondFingerMoveEvent, INJECT_EVENT_TIMEOUT,
Siarhei Vishniakouca205502021-07-16 21:31:58 +00002154 InputEventInjectionSync::WAIT_FOR_RESULT));
2155 rightWindow->consumeMotionMove();
2156
2157 leftWindow->assertNoEvents();
2158 rightWindow->assertNoEvents();
2159 wallpaperWindow->assertNoEvents();
2160}
2161
Arthur Hungc539dbb2022-12-08 07:45:36 +00002162/**
2163 * Two windows: a window on the left with dup touch to wallpaper and window on the right without it.
2164 * The touch slips to the right window. so left window and wallpaper should receive ACTION_CANCEL
2165 * The right window should receive ACTION_DOWN.
2166 */
2167TEST_F(InputDispatcherTest, WallpaperWindowWhenSlippery) {
Arthur Hung74c248d2022-11-23 07:09:59 +00002168 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
Arthur Hungc539dbb2022-12-08 07:45:36 +00002169 sp<FakeWindowHandle> leftWindow =
2170 sp<FakeWindowHandle>::make(application, mDispatcher, "Left", ADISPLAY_ID_DEFAULT);
2171 leftWindow->setFrame(Rect(0, 0, 200, 200));
2172 leftWindow->setDupTouchToWallpaper(true);
2173 leftWindow->setSlippery(true);
2174
2175 sp<FakeWindowHandle> rightWindow =
2176 sp<FakeWindowHandle>::make(application, mDispatcher, "Right", ADISPLAY_ID_DEFAULT);
2177 rightWindow->setFrame(Rect(200, 0, 400, 200));
Arthur Hung74c248d2022-11-23 07:09:59 +00002178
2179 sp<FakeWindowHandle> wallpaperWindow =
2180 sp<FakeWindowHandle>::make(application, mDispatcher, "Wallpaper", ADISPLAY_ID_DEFAULT);
2181 wallpaperWindow->setIsWallpaper(true);
Arthur Hung74c248d2022-11-23 07:09:59 +00002182
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07002183 mDispatcher->onWindowInfosChanged(
2184 {{*leftWindow->getInfo(), *rightWindow->getInfo(), *wallpaperWindow->getInfo()},
2185 {},
2186 0,
2187 0});
Arthur Hung74c248d2022-11-23 07:09:59 +00002188
Arthur Hungc539dbb2022-12-08 07:45:36 +00002189 // Touch down on left window
Arthur Hung74c248d2022-11-23 07:09:59 +00002190 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07002191 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
Arthur Hungc539dbb2022-12-08 07:45:36 +00002192 {100, 100}))
Arthur Hung74c248d2022-11-23 07:09:59 +00002193 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
Arthur Hungc539dbb2022-12-08 07:45:36 +00002194
2195 // Both foreground window and its wallpaper should receive the touch down
2196 leftWindow->consumeMotionDown();
Arthur Hung74c248d2022-11-23 07:09:59 +00002197 wallpaperWindow->consumeMotionDown(ADISPLAY_ID_DEFAULT, expectedWallpaperFlags);
2198
Arthur Hungc539dbb2022-12-08 07:45:36 +00002199 // Move to right window, the left window should receive cancel.
Arthur Hung74c248d2022-11-23 07:09:59 +00002200 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07002201 injectMotionEvent(*mDispatcher, AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN,
Arthur Hungc539dbb2022-12-08 07:45:36 +00002202 ADISPLAY_ID_DEFAULT, {201, 100}))
Arthur Hung74c248d2022-11-23 07:09:59 +00002203 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
2204
Arthur Hungc539dbb2022-12-08 07:45:36 +00002205 leftWindow->consumeMotionCancel();
2206 rightWindow->consumeMotionDown(ADISPLAY_ID_DEFAULT);
2207 wallpaperWindow->consumeMotionCancel(ADISPLAY_ID_DEFAULT, expectedWallpaperFlags);
Arthur Hung74c248d2022-11-23 07:09:59 +00002208}
2209
Siarhei Vishniakoua16e3a22022-03-02 15:26:40 -08002210/**
Siarhei Vishniakou5bf25d92023-02-08 15:43:38 -08002211 * The policy typically sets POLICY_FLAG_PASS_TO_USER to the events. But when the display is not
2212 * interactive, it might stop sending this flag.
2213 * In this test, we check that if the policy stops sending this flag mid-gesture, we still ensure
2214 * to have a consistent input stream.
2215 *
2216 * Test procedure:
2217 * DOWN -> POINTER_DOWN -> (stop sending POLICY_FLAG_PASS_TO_USER) -> CANCEL.
2218 * DOWN (new gesture).
2219 *
2220 * In the bad implementation, we could potentially drop the CANCEL event, and get an inconsistent
2221 * state in the dispatcher. This would cause the final DOWN event to not be delivered to the app.
2222 *
2223 * We technically just need a single window here, but we are using two windows (spy on top and a
2224 * regular window below) to emulate the actual situation where it happens on the device.
2225 */
2226TEST_F(InputDispatcherTest, TwoPointerCancelInconsistentPolicy) {
2227 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
2228 sp<FakeWindowHandle> spyWindow =
2229 sp<FakeWindowHandle>::make(application, mDispatcher, "Spy", ADISPLAY_ID_DEFAULT);
2230 spyWindow->setFrame(Rect(0, 0, 200, 200));
2231 spyWindow->setTrustedOverlay(true);
2232 spyWindow->setSpy(true);
2233
2234 sp<FakeWindowHandle> window =
2235 sp<FakeWindowHandle>::make(application, mDispatcher, "Window", ADISPLAY_ID_DEFAULT);
2236 window->setFrame(Rect(0, 0, 200, 200));
2237
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07002238 mDispatcher->onWindowInfosChanged({{*spyWindow->getInfo(), *window->getInfo()}, {}, 0, 0});
Siarhei Vishniakou5bf25d92023-02-08 15:43:38 -08002239 const int32_t touchDeviceId = 4;
Siarhei Vishniakou5bf25d92023-02-08 15:43:38 -08002240
2241 // Two pointers down
Prabir Pradhan678438e2023-04-13 19:32:51 +00002242 mDispatcher->notifyMotion(
2243 MotionArgsBuilder(AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
2244 .deviceId(touchDeviceId)
2245 .policyFlags(DEFAULT_POLICY_FLAGS)
2246 .pointer(PointerBuilder(0, ToolType::FINGER).x(100).y(100))
2247 .build());
Siarhei Vishniakou5bf25d92023-02-08 15:43:38 -08002248
Prabir Pradhan678438e2023-04-13 19:32:51 +00002249 mDispatcher->notifyMotion(MotionArgsBuilder(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
2250 .deviceId(touchDeviceId)
2251 .policyFlags(DEFAULT_POLICY_FLAGS)
2252 .pointer(PointerBuilder(0, ToolType::FINGER).x(100).y(100))
2253 .pointer(PointerBuilder(1, ToolType::FINGER).x(120).y(120))
2254 .build());
Siarhei Vishniakou5bf25d92023-02-08 15:43:38 -08002255 spyWindow->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_DOWN));
2256 spyWindow->consumeMotionEvent(WithMotionAction(POINTER_1_DOWN));
2257 window->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_DOWN));
2258 window->consumeMotionEvent(WithMotionAction(POINTER_1_DOWN));
2259
2260 // Cancel the current gesture. Send the cancel without the default policy flags.
Prabir Pradhan678438e2023-04-13 19:32:51 +00002261 mDispatcher->notifyMotion(
2262 MotionArgsBuilder(AMOTION_EVENT_ACTION_CANCEL, AINPUT_SOURCE_TOUCHSCREEN)
2263 .deviceId(touchDeviceId)
2264 .policyFlags(0)
2265 .pointer(PointerBuilder(0, ToolType::FINGER).x(100).y(100))
2266 .pointer(PointerBuilder(1, ToolType::FINGER).x(120).y(120))
2267 .build());
Siarhei Vishniakou5bf25d92023-02-08 15:43:38 -08002268 spyWindow->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_CANCEL));
2269 window->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_CANCEL));
2270
2271 // We don't need to reset the device to reproduce the issue, but the reset event typically
2272 // follows, so we keep it here to model the actual listener behaviour more closely.
Prabir Pradhan678438e2023-04-13 19:32:51 +00002273 mDispatcher->notifyDeviceReset({/*id=*/1, systemTime(SYSTEM_TIME_MONOTONIC), touchDeviceId});
Siarhei Vishniakou5bf25d92023-02-08 15:43:38 -08002274
2275 // Start new gesture
Prabir Pradhan678438e2023-04-13 19:32:51 +00002276 mDispatcher->notifyMotion(
2277 MotionArgsBuilder(AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
2278 .deviceId(touchDeviceId)
2279 .policyFlags(DEFAULT_POLICY_FLAGS)
2280 .pointer(PointerBuilder(0, ToolType::FINGER).x(100).y(100))
2281 .build());
Siarhei Vishniakou5bf25d92023-02-08 15:43:38 -08002282 spyWindow->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_DOWN));
2283 window->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_DOWN));
2284
2285 // No more events
2286 spyWindow->assertNoEvents();
2287 window->assertNoEvents();
2288}
2289
2290/**
Linnan Li907ae732023-09-05 17:14:21 +08002291 * Same as the above 'TwoPointerCancelInconsistentPolicy' test, but for hovers.
2292 * The policy typically sets POLICY_FLAG_PASS_TO_USER to the events. But when the display is not
2293 * interactive, it might stop sending this flag.
2294 * We've already ensured the consistency of the touch event in this case, and we should also ensure
2295 * the consistency of the hover event in this case.
2296 *
2297 * Test procedure:
2298 * HOVER_ENTER -> HOVER_MOVE -> (stop sending POLICY_FLAG_PASS_TO_USER) -> HOVER_EXIT
2299 * HOVER_ENTER -> HOVER_MOVE -> HOVER_EXIT
2300 *
2301 * We expect to receive two full streams of hover events.
2302 */
2303TEST_F(InputDispatcherTest, HoverEventInconsistentPolicy) {
2304 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
2305
2306 sp<FakeWindowHandle> window =
2307 sp<FakeWindowHandle>::make(application, mDispatcher, "Window", ADISPLAY_ID_DEFAULT);
2308 window->setFrame(Rect(0, 0, 300, 300));
2309
2310 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
2311
2312 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_ENTER, AINPUT_SOURCE_STYLUS)
2313 .policyFlags(DEFAULT_POLICY_FLAGS)
2314 .pointer(PointerBuilder(0, ToolType::STYLUS).x(100).y(101))
2315 .build());
2316 window->consumeMotionEvent(WithMotionAction(ACTION_HOVER_ENTER));
2317
2318 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_MOVE, AINPUT_SOURCE_STYLUS)
2319 .policyFlags(DEFAULT_POLICY_FLAGS)
2320 .pointer(PointerBuilder(0, ToolType::STYLUS).x(101).y(102))
2321 .build());
2322 window->consumeMotionEvent(WithMotionAction(ACTION_HOVER_MOVE));
2323
2324 // Send hover exit without the default policy flags.
2325 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_EXIT, AINPUT_SOURCE_STYLUS)
2326 .policyFlags(0)
2327 .pointer(PointerBuilder(0, ToolType::STYLUS).x(101).y(102))
2328 .build());
2329
2330 window->consumeMotionEvent(WithMotionAction(ACTION_HOVER_EXIT));
2331
2332 // Send a simple hover event stream, ensure dispatcher not crashed and window can receive
2333 // right event.
2334 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_ENTER, AINPUT_SOURCE_STYLUS)
2335 .policyFlags(DEFAULT_POLICY_FLAGS)
2336 .pointer(PointerBuilder(0, ToolType::STYLUS).x(200).y(201))
2337 .build());
2338 window->consumeMotionEvent(WithMotionAction(ACTION_HOVER_ENTER));
2339
2340 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_MOVE, AINPUT_SOURCE_STYLUS)
2341 .policyFlags(DEFAULT_POLICY_FLAGS)
2342 .pointer(PointerBuilder(0, ToolType::STYLUS).x(201).y(202))
2343 .build());
2344 window->consumeMotionEvent(WithMotionAction(ACTION_HOVER_MOVE));
2345
2346 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_EXIT, AINPUT_SOURCE_STYLUS)
2347 .policyFlags(DEFAULT_POLICY_FLAGS)
2348 .pointer(PointerBuilder(0, ToolType::STYLUS).x(201).y(202))
2349 .build());
2350 window->consumeMotionEvent(WithMotionAction(ACTION_HOVER_EXIT));
2351}
2352
2353/**
Siarhei Vishniakoue0431e42023-01-28 17:01:39 -08002354 * Two windows: a window on the left and a window on the right.
2355 * Mouse is hovered from the right window into the left window.
2356 * Next, we tap on the left window, where the cursor was last seen.
2357 * The second tap is done onto the right window.
2358 * The mouse and tap are from two different devices.
2359 * We technically don't need to set the downtime / eventtime for these events, but setting these
2360 * explicitly helps during debugging.
2361 * This test reproduces a crash where there is a mismatch between the downTime and eventTime.
2362 * In the buggy implementation, a tap on the right window would cause a crash.
2363 */
2364TEST_F(InputDispatcherTest, HoverFromLeftToRightAndTap) {
2365 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
2366 sp<FakeWindowHandle> leftWindow =
2367 sp<FakeWindowHandle>::make(application, mDispatcher, "Left", ADISPLAY_ID_DEFAULT);
2368 leftWindow->setFrame(Rect(0, 0, 200, 200));
2369
2370 sp<FakeWindowHandle> rightWindow =
2371 sp<FakeWindowHandle>::make(application, mDispatcher, "Right", ADISPLAY_ID_DEFAULT);
2372 rightWindow->setFrame(Rect(200, 0, 400, 200));
2373
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07002374 mDispatcher->onWindowInfosChanged(
2375 {{*leftWindow->getInfo(), *rightWindow->getInfo()}, {}, 0, 0});
Siarhei Vishniakoue0431e42023-01-28 17:01:39 -08002376 // All times need to start at the current time, otherwise the dispatcher will drop the events as
2377 // stale.
2378 const nsecs_t baseTime = systemTime(SYSTEM_TIME_MONOTONIC);
2379 const int32_t mouseDeviceId = 6;
2380 const int32_t touchDeviceId = 4;
2381 // Move the cursor from right
2382 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07002383 injectMotionEvent(*mDispatcher,
Siarhei Vishniakoue0431e42023-01-28 17:01:39 -08002384 MotionEventBuilder(AMOTION_EVENT_ACTION_HOVER_MOVE,
2385 AINPUT_SOURCE_MOUSE)
2386 .deviceId(mouseDeviceId)
2387 .downTime(baseTime + 10)
2388 .eventTime(baseTime + 20)
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07002389 .pointer(PointerBuilder(0, ToolType::MOUSE).x(300).y(100))
Siarhei Vishniakoue0431e42023-01-28 17:01:39 -08002390 .build()));
2391 rightWindow->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_ENTER));
2392
2393 // .. to the left window
2394 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07002395 injectMotionEvent(*mDispatcher,
Siarhei Vishniakoue0431e42023-01-28 17:01:39 -08002396 MotionEventBuilder(AMOTION_EVENT_ACTION_HOVER_MOVE,
2397 AINPUT_SOURCE_MOUSE)
2398 .deviceId(mouseDeviceId)
2399 .downTime(baseTime + 10)
2400 .eventTime(baseTime + 30)
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07002401 .pointer(PointerBuilder(0, ToolType::MOUSE).x(110).y(100))
Siarhei Vishniakoue0431e42023-01-28 17:01:39 -08002402 .build()));
2403 rightWindow->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_EXIT));
2404 leftWindow->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_ENTER));
2405 // Now tap the left window
2406 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07002407 injectMotionEvent(*mDispatcher,
Siarhei Vishniakoue0431e42023-01-28 17:01:39 -08002408 MotionEventBuilder(AMOTION_EVENT_ACTION_DOWN,
2409 AINPUT_SOURCE_TOUCHSCREEN)
2410 .deviceId(touchDeviceId)
2411 .downTime(baseTime + 40)
2412 .eventTime(baseTime + 40)
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07002413 .pointer(PointerBuilder(0, ToolType::FINGER).x(100).y(100))
Siarhei Vishniakoue0431e42023-01-28 17:01:39 -08002414 .build()));
2415 leftWindow->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_EXIT));
2416 leftWindow->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_DOWN));
2417
2418 // release tap
2419 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07002420 injectMotionEvent(*mDispatcher,
Siarhei Vishniakoue0431e42023-01-28 17:01:39 -08002421 MotionEventBuilder(AMOTION_EVENT_ACTION_UP,
2422 AINPUT_SOURCE_TOUCHSCREEN)
2423 .deviceId(touchDeviceId)
2424 .downTime(baseTime + 40)
2425 .eventTime(baseTime + 50)
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07002426 .pointer(PointerBuilder(0, ToolType::FINGER).x(100).y(100))
Siarhei Vishniakoue0431e42023-01-28 17:01:39 -08002427 .build()));
2428 leftWindow->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_UP));
2429
2430 // Tap the window on the right
2431 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07002432 injectMotionEvent(*mDispatcher,
Siarhei Vishniakoue0431e42023-01-28 17:01:39 -08002433 MotionEventBuilder(AMOTION_EVENT_ACTION_DOWN,
2434 AINPUT_SOURCE_TOUCHSCREEN)
2435 .deviceId(touchDeviceId)
2436 .downTime(baseTime + 60)
2437 .eventTime(baseTime + 60)
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07002438 .pointer(PointerBuilder(0, ToolType::FINGER).x(300).y(100))
Siarhei Vishniakoue0431e42023-01-28 17:01:39 -08002439 .build()));
2440 rightWindow->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_DOWN));
2441
2442 // release tap
2443 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07002444 injectMotionEvent(*mDispatcher,
Siarhei Vishniakoue0431e42023-01-28 17:01:39 -08002445 MotionEventBuilder(AMOTION_EVENT_ACTION_UP,
2446 AINPUT_SOURCE_TOUCHSCREEN)
2447 .deviceId(touchDeviceId)
2448 .downTime(baseTime + 60)
2449 .eventTime(baseTime + 70)
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07002450 .pointer(PointerBuilder(0, ToolType::FINGER).x(300).y(100))
Siarhei Vishniakoue0431e42023-01-28 17:01:39 -08002451 .build()));
2452 rightWindow->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_UP));
2453
2454 // No more events
2455 leftWindow->assertNoEvents();
2456 rightWindow->assertNoEvents();
2457}
2458
2459/**
Siarhei Vishniakoua235c042023-05-02 09:59:09 -07002460 * Start hovering in a window. While this hover is still active, make another window appear on top.
2461 * The top, obstructing window has no input channel, so it's not supposed to receive input.
2462 * While the top window is present, the hovering is stopped.
2463 * Later, hovering gets resumed again.
2464 * Ensure that new hover gesture is handled correctly.
2465 * This test reproduces a crash where the HOVER_EXIT event wasn't getting dispatched correctly
2466 * to the window that's currently being hovered over.
2467 */
2468TEST_F(InputDispatcherTest, HoverWhileWindowAppears) {
2469 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
2470 sp<FakeWindowHandle> window =
2471 sp<FakeWindowHandle>::make(application, mDispatcher, "Window", ADISPLAY_ID_DEFAULT);
2472 window->setFrame(Rect(0, 0, 200, 200));
2473
2474 // Only a single window is present at first
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07002475 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Siarhei Vishniakoua235c042023-05-02 09:59:09 -07002476
2477 // Start hovering in the window
2478 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_ENTER, AINPUT_SOURCE_STYLUS)
2479 .pointer(PointerBuilder(0, ToolType::STYLUS).x(100).y(100))
2480 .build());
2481 window->consumeMotionEvent(WithMotionAction(ACTION_HOVER_ENTER));
2482
2483 // Now, an obscuring window appears!
2484 sp<FakeWindowHandle> obscuringWindow =
2485 sp<FakeWindowHandle>::make(application, mDispatcher, "Obscuring window",
2486 ADISPLAY_ID_DEFAULT,
Prabir Pradhane7cc69c2024-01-05 21:35:28 +00002487 /*createInputChannel=*/false);
Siarhei Vishniakoua235c042023-05-02 09:59:09 -07002488 obscuringWindow->setFrame(Rect(0, 0, 200, 200));
2489 obscuringWindow->setTouchOcclusionMode(TouchOcclusionMode::BLOCK_UNTRUSTED);
2490 obscuringWindow->setOwnerInfo(SECONDARY_WINDOW_PID, SECONDARY_WINDOW_UID);
2491 obscuringWindow->setNoInputChannel(true);
2492 obscuringWindow->setFocusable(false);
2493 obscuringWindow->setAlpha(1.0);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07002494 mDispatcher->onWindowInfosChanged(
2495 {{*obscuringWindow->getInfo(), *window->getInfo()}, {}, 0, 0});
Siarhei Vishniakoua235c042023-05-02 09:59:09 -07002496
2497 // While this new obscuring window is present, the hovering is stopped
2498 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_EXIT, AINPUT_SOURCE_STYLUS)
2499 .pointer(PointerBuilder(0, ToolType::STYLUS).x(100).y(100))
2500 .build());
2501 window->consumeMotionEvent(WithMotionAction(ACTION_HOVER_EXIT));
2502
2503 // Now the obscuring window goes away.
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07002504 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Siarhei Vishniakoua235c042023-05-02 09:59:09 -07002505
2506 // And a new hover gesture starts.
2507 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_ENTER, AINPUT_SOURCE_STYLUS)
2508 .pointer(PointerBuilder(0, ToolType::STYLUS).x(100).y(100))
2509 .build());
2510 window->consumeMotionEvent(WithMotionAction(ACTION_HOVER_ENTER));
2511}
2512
2513/**
2514 * Same test as 'HoverWhileWindowAppears' above, but here, we also send some HOVER_MOVE events to
2515 * the obscuring window.
2516 */
2517TEST_F(InputDispatcherTest, HoverMoveWhileWindowAppears) {
2518 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
2519 sp<FakeWindowHandle> window =
2520 sp<FakeWindowHandle>::make(application, mDispatcher, "Window", ADISPLAY_ID_DEFAULT);
2521 window->setFrame(Rect(0, 0, 200, 200));
2522
2523 // Only a single window is present at first
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07002524 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Siarhei Vishniakoua235c042023-05-02 09:59:09 -07002525
2526 // Start hovering in the window
2527 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_ENTER, AINPUT_SOURCE_STYLUS)
2528 .pointer(PointerBuilder(0, ToolType::STYLUS).x(100).y(100))
2529 .build());
2530 window->consumeMotionEvent(WithMotionAction(ACTION_HOVER_ENTER));
2531
2532 // Now, an obscuring window appears!
2533 sp<FakeWindowHandle> obscuringWindow =
2534 sp<FakeWindowHandle>::make(application, mDispatcher, "Obscuring window",
2535 ADISPLAY_ID_DEFAULT,
Prabir Pradhane7cc69c2024-01-05 21:35:28 +00002536 /*createInputChannel=*/false);
Siarhei Vishniakoua235c042023-05-02 09:59:09 -07002537 obscuringWindow->setFrame(Rect(0, 0, 200, 200));
2538 obscuringWindow->setTouchOcclusionMode(TouchOcclusionMode::BLOCK_UNTRUSTED);
2539 obscuringWindow->setOwnerInfo(SECONDARY_WINDOW_PID, SECONDARY_WINDOW_UID);
2540 obscuringWindow->setNoInputChannel(true);
2541 obscuringWindow->setFocusable(false);
2542 obscuringWindow->setAlpha(1.0);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07002543 mDispatcher->onWindowInfosChanged(
2544 {{*obscuringWindow->getInfo(), *window->getInfo()}, {}, 0, 0});
Siarhei Vishniakoua235c042023-05-02 09:59:09 -07002545
2546 // While this new obscuring window is present, the hovering continues. The event can't go to the
2547 // bottom window due to obstructed touches, so it should generate HOVER_EXIT for that window.
2548 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_MOVE, AINPUT_SOURCE_STYLUS)
2549 .pointer(PointerBuilder(0, ToolType::STYLUS).x(100).y(100))
2550 .build());
2551 obscuringWindow->assertNoEvents();
2552 window->consumeMotionEvent(WithMotionAction(ACTION_HOVER_EXIT));
2553
2554 // Now the obscuring window goes away.
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07002555 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Siarhei Vishniakoua235c042023-05-02 09:59:09 -07002556
2557 // Hovering continues in the same position. The hovering pointer re-enters the bottom window,
2558 // so it should generate a HOVER_ENTER
2559 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_MOVE, AINPUT_SOURCE_STYLUS)
2560 .pointer(PointerBuilder(0, ToolType::STYLUS).x(100).y(100))
2561 .build());
2562 window->consumeMotionEvent(WithMotionAction(ACTION_HOVER_ENTER));
2563
2564 // Now the MOVE should be getting dispatched normally
2565 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_MOVE, AINPUT_SOURCE_STYLUS)
2566 .pointer(PointerBuilder(0, ToolType::STYLUS).x(110).y(110))
2567 .build());
2568 window->consumeMotionEvent(WithMotionAction(ACTION_HOVER_MOVE));
2569}
2570
2571/**
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -07002572 * Hover mouse over a window, and then send ACTION_SCROLL. Ensure both the hover and the scroll
2573 * events are delivered to the window.
2574 */
2575TEST_F(InputDispatcherTest, HoverMoveAndScroll) {
2576 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
2577 sp<FakeWindowHandle> window =
2578 sp<FakeWindowHandle>::make(application, mDispatcher, "Window", ADISPLAY_ID_DEFAULT);
2579 window->setFrame(Rect(0, 0, 200, 200));
2580 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
2581
2582 // Start hovering in the window
2583 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_ENTER, AINPUT_SOURCE_MOUSE)
2584 .pointer(PointerBuilder(0, ToolType::MOUSE).x(100).y(110))
2585 .build());
2586 window->consumeMotionEvent(WithMotionAction(ACTION_HOVER_ENTER));
2587
2588 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_MOVE, AINPUT_SOURCE_MOUSE)
2589 .pointer(PointerBuilder(0, ToolType::MOUSE).x(110).y(120))
2590 .build());
2591 window->consumeMotionEvent(WithMotionAction(ACTION_HOVER_MOVE));
2592
2593 // Scroll with the mouse
2594 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_SCROLL, AINPUT_SOURCE_MOUSE)
2595 .pointer(PointerBuilder(0, ToolType::MOUSE).x(110).y(120))
2596 .build());
2597 window->consumeMotionEvent(WithMotionAction(ACTION_SCROLL));
2598}
2599
2600using InputDispatcherMultiDeviceTest = InputDispatcherTest;
2601
2602/**
Siarhei Vishniakou2899c552023-07-10 18:20:46 -07002603 * One window. Stylus down on the window. Next, touch from another device goes down. Ensure that
2604 * touch is dropped, because stylus should be preferred over touch.
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -07002605 */
Siarhei Vishniakou2899c552023-07-10 18:20:46 -07002606TEST_F(InputDispatcherMultiDeviceTest, StylusDownBlocksTouchDown) {
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -07002607 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
2608 sp<FakeWindowHandle> window =
2609 sp<FakeWindowHandle>::make(application, mDispatcher, "Window", ADISPLAY_ID_DEFAULT);
2610 window->setFrame(Rect(0, 0, 200, 200));
2611
2612 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
2613
2614 constexpr int32_t touchDeviceId = 4;
2615 constexpr int32_t stylusDeviceId = 2;
2616
2617 // Stylus down
2618 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_STYLUS)
2619 .deviceId(stylusDeviceId)
2620 .pointer(PointerBuilder(0, ToolType::STYLUS).x(100).y(110))
2621 .build());
2622 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(stylusDeviceId)));
2623
2624 // Touch down
2625 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
2626 .deviceId(touchDeviceId)
2627 .pointer(PointerBuilder(0, ToolType::FINGER).x(140).y(145))
2628 .build());
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -07002629
2630 // Touch move
2631 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN)
2632 .deviceId(touchDeviceId)
2633 .pointer(PointerBuilder(0, ToolType::FINGER).x(141).y(146))
2634 .build());
Siarhei Vishniakou2899c552023-07-10 18:20:46 -07002635 // Touch is ignored because stylus is already down
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -07002636
Siarhei Vishniakou2899c552023-07-10 18:20:46 -07002637 // Subsequent stylus movements are delivered correctly
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -07002638 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_STYLUS)
2639 .deviceId(stylusDeviceId)
2640 .pointer(PointerBuilder(0, ToolType::STYLUS).x(101).y(111))
2641 .build());
Siarhei Vishniakou2899c552023-07-10 18:20:46 -07002642 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(stylusDeviceId),
2643 WithCoords(101, 111)));
2644
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -07002645 window->assertNoEvents();
2646}
2647
2648/**
2649 * One window and one spy window. Stylus down on the window. Next, touch from another device goes
Siarhei Vishniakou2899c552023-07-10 18:20:46 -07002650 * down. Ensure that touch is dropped, because stylus should be preferred over touch.
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -07002651 * Similar test as above, but with added SPY window.
2652 */
Siarhei Vishniakou2899c552023-07-10 18:20:46 -07002653TEST_F(InputDispatcherMultiDeviceTest, StylusDownWithSpyBlocksTouchDown) {
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -07002654 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
2655 sp<FakeWindowHandle> window =
2656 sp<FakeWindowHandle>::make(application, mDispatcher, "Window", ADISPLAY_ID_DEFAULT);
2657 sp<FakeWindowHandle> spyWindow =
2658 sp<FakeWindowHandle>::make(application, mDispatcher, "Spy", ADISPLAY_ID_DEFAULT);
2659 spyWindow->setFrame(Rect(0, 0, 200, 200));
2660 spyWindow->setTrustedOverlay(true);
2661 spyWindow->setSpy(true);
2662 window->setFrame(Rect(0, 0, 200, 200));
2663
2664 mDispatcher->onWindowInfosChanged({{*spyWindow->getInfo(), *window->getInfo()}, {}, 0, 0});
2665
2666 constexpr int32_t touchDeviceId = 4;
2667 constexpr int32_t stylusDeviceId = 2;
2668
2669 // Stylus down
2670 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_STYLUS)
2671 .deviceId(stylusDeviceId)
2672 .pointer(PointerBuilder(0, ToolType::STYLUS).x(100).y(110))
2673 .build());
2674 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(stylusDeviceId)));
2675 spyWindow->consumeMotionEvent(
2676 AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(stylusDeviceId)));
2677
2678 // Touch down
2679 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
2680 .deviceId(touchDeviceId)
2681 .pointer(PointerBuilder(0, ToolType::FINGER).x(140).y(145))
2682 .build());
2683
2684 // Touch move
2685 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN)
2686 .deviceId(touchDeviceId)
2687 .pointer(PointerBuilder(0, ToolType::FINGER).x(141).y(146))
2688 .build());
Siarhei Vishniakou2899c552023-07-10 18:20:46 -07002689
2690 // Touch is ignored because stylus is already down
2691
2692 // Subsequent stylus movements are delivered correctly
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -07002693 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_STYLUS)
2694 .deviceId(stylusDeviceId)
2695 .pointer(PointerBuilder(0, ToolType::STYLUS).x(101).y(111))
2696 .build());
Siarhei Vishniakou2899c552023-07-10 18:20:46 -07002697 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(stylusDeviceId),
2698 WithCoords(101, 111)));
2699 spyWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(stylusDeviceId),
2700 WithCoords(101, 111)));
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -07002701
2702 window->assertNoEvents();
2703 spyWindow->assertNoEvents();
2704}
2705
2706/**
Siarhei Vishniakou2899c552023-07-10 18:20:46 -07002707 * One window. Stylus hover on the window. Next, touch from another device goes down. Ensure that
Siarhei Vishniakou3ad54f52023-11-02 16:54:40 -07002708 * touch is dropped, because stylus hover takes precedence.
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -07002709 */
Siarhei Vishniakou3ad54f52023-11-02 16:54:40 -07002710TEST_F(InputDispatcherMultiDeviceTest, StylusHoverBlocksTouchDown) {
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -07002711 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
2712 sp<FakeWindowHandle> window =
2713 sp<FakeWindowHandle>::make(application, mDispatcher, "Window", ADISPLAY_ID_DEFAULT);
2714 window->setFrame(Rect(0, 0, 200, 200));
2715
2716 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
2717
2718 constexpr int32_t touchDeviceId = 4;
2719 constexpr int32_t stylusDeviceId = 2;
2720
2721 // Stylus down on the window
2722 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_ENTER, AINPUT_SOURCE_STYLUS)
2723 .deviceId(stylusDeviceId)
2724 .pointer(PointerBuilder(0, ToolType::STYLUS).x(100).y(110))
2725 .build());
2726 window->consumeMotionEvent(
2727 AllOf(WithMotionAction(ACTION_HOVER_ENTER), WithDeviceId(stylusDeviceId)));
2728
2729 // Touch down on window
2730 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
2731 .deviceId(touchDeviceId)
2732 .pointer(PointerBuilder(0, ToolType::FINGER).x(140).y(145))
2733 .build());
2734 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN)
2735 .deviceId(touchDeviceId)
2736 .pointer(PointerBuilder(0, ToolType::FINGER).x(141).y(146))
2737 .build());
Siarhei Vishniakou2899c552023-07-10 18:20:46 -07002738
Siarhei Vishniakou3ad54f52023-11-02 16:54:40 -07002739 // Touch is ignored because stylus is hovering
Siarhei Vishniakou2899c552023-07-10 18:20:46 -07002740
Siarhei Vishniakou3ad54f52023-11-02 16:54:40 -07002741 // Subsequent stylus movements are delivered correctly
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -07002742 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_MOVE, AINPUT_SOURCE_STYLUS)
2743 .deviceId(stylusDeviceId)
2744 .pointer(PointerBuilder(0, ToolType::STYLUS).x(101).y(111))
2745 .build());
Siarhei Vishniakou3ad54f52023-11-02 16:54:40 -07002746 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_HOVER_MOVE),
2747 WithDeviceId(stylusDeviceId), WithCoords(101, 111)));
Siarhei Vishniakou2899c552023-07-10 18:20:46 -07002748
Siarhei Vishniakou3ad54f52023-11-02 16:54:40 -07002749 // and subsequent touches continue to be ignored
Siarhei Vishniakou2899c552023-07-10 18:20:46 -07002750 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN)
2751 .deviceId(touchDeviceId)
2752 .pointer(PointerBuilder(0, ToolType::FINGER).x(142).y(147))
2753 .build());
Siarhei Vishniakou3ad54f52023-11-02 16:54:40 -07002754 window->assertNoEvents();
Siarhei Vishniakou2899c552023-07-10 18:20:46 -07002755}
2756
2757/**
2758 * One window. Touch down on the window. Then, stylus hover on the window from another device.
Siarhei Vishniakou3ad54f52023-11-02 16:54:40 -07002759 * Ensure that touch is canceled, because stylus hover should take precedence.
Siarhei Vishniakou2899c552023-07-10 18:20:46 -07002760 */
Siarhei Vishniakou3ad54f52023-11-02 16:54:40 -07002761TEST_F(InputDispatcherMultiDeviceTest, TouchIsCanceledByStylusHover) {
Siarhei Vishniakou2899c552023-07-10 18:20:46 -07002762 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
2763 sp<FakeWindowHandle> window =
2764 sp<FakeWindowHandle>::make(application, mDispatcher, "Window", ADISPLAY_ID_DEFAULT);
2765 window->setFrame(Rect(0, 0, 200, 200));
2766
2767 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
2768
2769 constexpr int32_t touchDeviceId = 4;
2770 constexpr int32_t stylusDeviceId = 2;
2771
2772 // Touch down on window
2773 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
2774 .deviceId(touchDeviceId)
2775 .pointer(PointerBuilder(0, ToolType::FINGER).x(140).y(145))
2776 .build());
2777 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN)
2778 .deviceId(touchDeviceId)
2779 .pointer(PointerBuilder(0, ToolType::FINGER).x(141).y(146))
2780 .build());
2781 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(touchDeviceId)));
2782 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(touchDeviceId)));
2783
2784 // Stylus hover on the window
2785 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_ENTER, AINPUT_SOURCE_STYLUS)
2786 .deviceId(stylusDeviceId)
2787 .pointer(PointerBuilder(0, ToolType::STYLUS).x(100).y(110))
2788 .build());
2789 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_MOVE, AINPUT_SOURCE_STYLUS)
2790 .deviceId(stylusDeviceId)
2791 .pointer(PointerBuilder(0, ToolType::STYLUS).x(101).y(111))
2792 .build());
Siarhei Vishniakou3ad54f52023-11-02 16:54:40 -07002793 // Stylus hover movement causes touch to be canceled
2794 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_CANCEL), WithDeviceId(touchDeviceId),
2795 WithCoords(141, 146)));
2796 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_HOVER_ENTER),
2797 WithDeviceId(stylusDeviceId), WithCoords(100, 110)));
2798 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_HOVER_MOVE),
2799 WithDeviceId(stylusDeviceId), WithCoords(101, 111)));
Siarhei Vishniakou2899c552023-07-10 18:20:46 -07002800
Siarhei Vishniakou3ad54f52023-11-02 16:54:40 -07002801 // Subsequent touch movements are ignored
Siarhei Vishniakou2899c552023-07-10 18:20:46 -07002802 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN)
2803 .deviceId(touchDeviceId)
2804 .pointer(PointerBuilder(0, ToolType::FINGER).x(142).y(147))
2805 .build());
Siarhei Vishniakou3ad54f52023-11-02 16:54:40 -07002806
2807 window->assertNoEvents();
Siarhei Vishniakou2899c552023-07-10 18:20:46 -07002808}
2809
2810/**
2811 * One window. Stylus down on the window. Then, stylus from another device goes down. Ensure that
2812 * the latest stylus takes over. That is, old stylus should be canceled and the new stylus should
2813 * become active.
2814 */
2815TEST_F(InputDispatcherMultiDeviceTest, LatestStylusWins) {
2816 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
2817 sp<FakeWindowHandle> window =
2818 sp<FakeWindowHandle>::make(application, mDispatcher, "Window", ADISPLAY_ID_DEFAULT);
2819 window->setFrame(Rect(0, 0, 200, 200));
2820
2821 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
2822
2823 constexpr int32_t stylusDeviceId1 = 3;
2824 constexpr int32_t stylusDeviceId2 = 5;
2825
2826 // Touch down on window
2827 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_STYLUS)
2828 .deviceId(stylusDeviceId1)
2829 .pointer(PointerBuilder(0, ToolType::STYLUS).x(99).y(100))
2830 .build());
2831 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_STYLUS)
2832 .deviceId(stylusDeviceId1)
2833 .pointer(PointerBuilder(0, ToolType::STYLUS).x(100).y(101))
2834 .build());
2835 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(stylusDeviceId1)));
2836 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(stylusDeviceId1)));
2837
2838 // Second stylus down
2839 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_STYLUS)
2840 .deviceId(stylusDeviceId2)
2841 .pointer(PointerBuilder(0, ToolType::STYLUS).x(9).y(10))
2842 .build());
2843 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_STYLUS)
2844 .deviceId(stylusDeviceId2)
2845 .pointer(PointerBuilder(0, ToolType::STYLUS).x(10).y(11))
2846 .build());
2847
2848 // First stylus is canceled, second one takes over.
2849 window->consumeMotionEvent(
2850 AllOf(WithMotionAction(ACTION_CANCEL), WithDeviceId(stylusDeviceId1)));
2851 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(stylusDeviceId2)));
2852 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(stylusDeviceId2)));
2853
2854 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_STYLUS)
2855 .deviceId(stylusDeviceId1)
2856 .pointer(PointerBuilder(0, ToolType::STYLUS).x(101).y(102))
2857 .build());
2858 // Subsequent stylus movements are delivered correctly
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -07002859 window->assertNoEvents();
2860}
2861
2862/**
Siarhei Vishniakou2899c552023-07-10 18:20:46 -07002863 * One window. Touch down on the window. Then, stylus down on the window from another device.
2864 * Ensure that is canceled, because stylus down should be preferred over touch.
2865 */
2866TEST_F(InputDispatcherMultiDeviceTest, TouchIsCanceledByStylusDown) {
2867 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
2868 sp<FakeWindowHandle> window =
2869 sp<FakeWindowHandle>::make(application, mDispatcher, "Window", ADISPLAY_ID_DEFAULT);
2870 window->setFrame(Rect(0, 0, 200, 200));
2871
2872 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
2873
2874 constexpr int32_t touchDeviceId = 4;
2875 constexpr int32_t stylusDeviceId = 2;
2876
2877 // Touch down on window
2878 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
2879 .deviceId(touchDeviceId)
2880 .pointer(PointerBuilder(0, ToolType::FINGER).x(140).y(145))
2881 .build());
2882 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN)
2883 .deviceId(touchDeviceId)
2884 .pointer(PointerBuilder(0, ToolType::FINGER).x(141).y(146))
2885 .build());
2886 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(touchDeviceId)));
2887 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(touchDeviceId)));
2888
2889 // Stylus down on the window
2890 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_STYLUS)
2891 .deviceId(stylusDeviceId)
2892 .pointer(PointerBuilder(0, ToolType::STYLUS).x(100).y(110))
2893 .build());
2894 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_CANCEL), WithDeviceId(touchDeviceId)));
2895 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(stylusDeviceId)));
2896
2897 // Subsequent stylus movements are delivered correctly
2898 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_STYLUS)
2899 .deviceId(stylusDeviceId)
2900 .pointer(PointerBuilder(0, ToolType::STYLUS).x(101).y(111))
2901 .build());
2902 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(stylusDeviceId),
2903 WithCoords(101, 111)));
2904}
2905
2906/**
Siarhei Vishniakouf372b812023-02-14 18:06:51 -08002907 * Two windows: a window on the left and a window on the right.
2908 * Mouse is clicked on the left window and remains down. Touch is touched on the right and remains
2909 * down. Then, on the left window, also place second touch pointer down.
2910 * This test tries to reproduce a crash.
2911 * In the buggy implementation, second pointer down on the left window would cause a crash.
2912 */
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -07002913TEST_F(InputDispatcherMultiDeviceTest, MultiDeviceSplitTouch) {
Siarhei Vishniakouf372b812023-02-14 18:06:51 -08002914 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
2915 sp<FakeWindowHandle> leftWindow =
2916 sp<FakeWindowHandle>::make(application, mDispatcher, "Left", ADISPLAY_ID_DEFAULT);
2917 leftWindow->setFrame(Rect(0, 0, 200, 200));
2918
2919 sp<FakeWindowHandle> rightWindow =
2920 sp<FakeWindowHandle>::make(application, mDispatcher, "Right", ADISPLAY_ID_DEFAULT);
2921 rightWindow->setFrame(Rect(200, 0, 400, 200));
2922
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07002923 mDispatcher->onWindowInfosChanged(
2924 {{*leftWindow->getInfo(), *rightWindow->getInfo()}, {}, 0, 0});
Siarhei Vishniakouf372b812023-02-14 18:06:51 -08002925
2926 const int32_t touchDeviceId = 4;
2927 const int32_t mouseDeviceId = 6;
Siarhei Vishniakouf372b812023-02-14 18:06:51 -08002928
2929 // Start hovering over the left window
Prabir Pradhan678438e2023-04-13 19:32:51 +00002930 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_ENTER, AINPUT_SOURCE_MOUSE)
2931 .deviceId(mouseDeviceId)
2932 .pointer(PointerBuilder(0, ToolType::MOUSE).x(100).y(100))
2933 .build());
Siarhei Vishniakouf372b812023-02-14 18:06:51 -08002934 leftWindow->consumeMotionEvent(
2935 AllOf(WithMotionAction(ACTION_HOVER_ENTER), WithDeviceId(mouseDeviceId)));
2936
2937 // Mouse down on left window
Prabir Pradhan678438e2023-04-13 19:32:51 +00002938 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_MOUSE)
2939 .deviceId(mouseDeviceId)
2940 .buttonState(AMOTION_EVENT_BUTTON_PRIMARY)
2941 .pointer(PointerBuilder(0, ToolType::MOUSE).x(100).y(100))
2942 .build());
Siarhei Vishniakouf372b812023-02-14 18:06:51 -08002943
2944 leftWindow->consumeMotionEvent(
2945 AllOf(WithMotionAction(ACTION_HOVER_EXIT), WithDeviceId(mouseDeviceId)));
2946 leftWindow->consumeMotionEvent(
2947 AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(mouseDeviceId)));
2948
Prabir Pradhan678438e2023-04-13 19:32:51 +00002949 mDispatcher->notifyMotion(
2950 MotionArgsBuilder(AMOTION_EVENT_ACTION_BUTTON_PRESS, AINPUT_SOURCE_MOUSE)
2951 .deviceId(mouseDeviceId)
2952 .buttonState(AMOTION_EVENT_BUTTON_PRIMARY)
2953 .actionButton(AMOTION_EVENT_BUTTON_PRIMARY)
2954 .pointer(PointerBuilder(0, ToolType::MOUSE).x(100).y(100))
2955 .build());
Siarhei Vishniakouf372b812023-02-14 18:06:51 -08002956 leftWindow->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_BUTTON_PRESS));
2957
2958 // First touch pointer down on right window
Prabir Pradhan678438e2023-04-13 19:32:51 +00002959 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
2960 .deviceId(touchDeviceId)
2961 .pointer(PointerBuilder(0, ToolType::FINGER).x(300).y(100))
2962 .build());
Siarhei Vishniakou2899c552023-07-10 18:20:46 -07002963 leftWindow->assertNoEvents();
2964
Siarhei Vishniakouf372b812023-02-14 18:06:51 -08002965 rightWindow->consumeMotionEvent(WithMotionAction(ACTION_DOWN));
2966
2967 // Second touch pointer down on left window
Prabir Pradhan678438e2023-04-13 19:32:51 +00002968 mDispatcher->notifyMotion(MotionArgsBuilder(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
2969 .deviceId(touchDeviceId)
2970 .pointer(PointerBuilder(0, ToolType::FINGER).x(300).y(100))
2971 .pointer(PointerBuilder(1, ToolType::FINGER).x(100).y(100))
2972 .build());
Siarhei Vishniakou2899c552023-07-10 18:20:46 -07002973 // Since this is now a new splittable pointer going down on the left window, and it's coming
2974 // from a different device, the current gesture in the left window (pointer down) should first
2975 // be canceled.
2976 leftWindow->consumeMotionEvent(
2977 AllOf(WithMotionAction(ACTION_CANCEL), WithDeviceId(mouseDeviceId)));
Siarhei Vishniakouf372b812023-02-14 18:06:51 -08002978 leftWindow->consumeMotionEvent(
2979 AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(touchDeviceId)));
2980 // This MOVE event is not necessary (doesn't carry any new information), but it's there in the
2981 // current implementation.
2982 const std::map<int32_t, PointF> expectedPointers{{0, PointF{100, 100}}};
2983 rightWindow->consumeMotionEvent(
2984 AllOf(WithMotionAction(ACTION_MOVE), WithPointers(expectedPointers)));
2985
2986 leftWindow->assertNoEvents();
2987 rightWindow->assertNoEvents();
2988}
2989
2990/**
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -07002991 * Two windows: a window on the left and a window on the right.
2992 * Mouse is hovered on the left window and stylus is hovered on the right window.
2993 */
2994TEST_F(InputDispatcherMultiDeviceTest, MultiDeviceHover) {
2995 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
2996 sp<FakeWindowHandle> leftWindow =
2997 sp<FakeWindowHandle>::make(application, mDispatcher, "Left", ADISPLAY_ID_DEFAULT);
2998 leftWindow->setFrame(Rect(0, 0, 200, 200));
2999
3000 sp<FakeWindowHandle> rightWindow =
3001 sp<FakeWindowHandle>::make(application, mDispatcher, "Right", ADISPLAY_ID_DEFAULT);
3002 rightWindow->setFrame(Rect(200, 0, 400, 200));
3003
3004 mDispatcher->onWindowInfosChanged(
3005 {{*leftWindow->getInfo(), *rightWindow->getInfo()}, {}, 0, 0});
3006
3007 const int32_t stylusDeviceId = 3;
3008 const int32_t mouseDeviceId = 6;
3009
3010 // Start hovering over the left window
3011 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_ENTER, AINPUT_SOURCE_MOUSE)
3012 .deviceId(mouseDeviceId)
3013 .pointer(PointerBuilder(0, ToolType::MOUSE).x(100).y(110))
3014 .build());
3015 leftWindow->consumeMotionEvent(
3016 AllOf(WithMotionAction(ACTION_HOVER_ENTER), WithDeviceId(mouseDeviceId)));
3017
3018 // Stylus hovered on right window
3019 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_ENTER, AINPUT_SOURCE_STYLUS)
3020 .deviceId(stylusDeviceId)
3021 .pointer(PointerBuilder(0, ToolType::STYLUS).x(300).y(100))
3022 .build());
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -07003023 rightWindow->consumeMotionEvent(
3024 AllOf(WithMotionAction(ACTION_HOVER_ENTER), WithDeviceId(stylusDeviceId)));
3025
3026 // Subsequent HOVER_MOVE events are dispatched correctly.
3027 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_MOVE, AINPUT_SOURCE_MOUSE)
3028 .deviceId(mouseDeviceId)
3029 .pointer(PointerBuilder(0, ToolType::MOUSE).x(110).y(120))
3030 .build());
3031 leftWindow->consumeMotionEvent(
Siarhei Vishniakou2899c552023-07-10 18:20:46 -07003032 AllOf(WithMotionAction(ACTION_HOVER_MOVE), WithDeviceId(mouseDeviceId)));
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -07003033
3034 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_MOVE, AINPUT_SOURCE_STYLUS)
3035 .deviceId(stylusDeviceId)
3036 .pointer(PointerBuilder(0, ToolType::STYLUS).x(310).y(110))
3037 .build());
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -07003038 rightWindow->consumeMotionEvent(
Siarhei Vishniakou2899c552023-07-10 18:20:46 -07003039 AllOf(WithMotionAction(ACTION_HOVER_MOVE), WithDeviceId(stylusDeviceId)));
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -07003040
3041 leftWindow->assertNoEvents();
3042 rightWindow->assertNoEvents();
3043}
3044
3045/**
3046 * Three windows: a window on the left and a window on the right.
3047 * And a spy window that's positioned above all of them.
3048 * Stylus down on the left window and remains down. Touch goes down on the right and remains down.
3049 * Check the stream that's received by the spy.
3050 */
3051TEST_F(InputDispatcherMultiDeviceTest, MultiDeviceWithSpy) {
3052 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
3053
3054 sp<FakeWindowHandle> spyWindow =
3055 sp<FakeWindowHandle>::make(application, mDispatcher, "Spy", ADISPLAY_ID_DEFAULT);
3056 spyWindow->setFrame(Rect(0, 0, 400, 400));
3057 spyWindow->setTrustedOverlay(true);
3058 spyWindow->setSpy(true);
3059
3060 sp<FakeWindowHandle> leftWindow =
3061 sp<FakeWindowHandle>::make(application, mDispatcher, "Left", ADISPLAY_ID_DEFAULT);
3062 leftWindow->setFrame(Rect(0, 0, 200, 200));
3063
3064 sp<FakeWindowHandle> rightWindow =
3065 sp<FakeWindowHandle>::make(application, mDispatcher, "Right", ADISPLAY_ID_DEFAULT);
3066
3067 rightWindow->setFrame(Rect(200, 0, 400, 200));
3068
3069 mDispatcher->onWindowInfosChanged(
3070 {{*spyWindow->getInfo(), *leftWindow->getInfo(), *rightWindow->getInfo()}, {}, 0, 0});
3071
3072 const int32_t stylusDeviceId = 1;
3073 const int32_t touchDeviceId = 2;
3074
3075 // Stylus down on the left window
3076 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_STYLUS)
3077 .deviceId(stylusDeviceId)
3078 .pointer(PointerBuilder(0, ToolType::STYLUS).x(100).y(100))
3079 .build());
3080 leftWindow->consumeMotionEvent(
3081 AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(stylusDeviceId)));
3082 spyWindow->consumeMotionEvent(
3083 AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(stylusDeviceId)));
3084
3085 // Touch down on the right window
3086 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
3087 .deviceId(touchDeviceId)
3088 .pointer(PointerBuilder(0, ToolType::FINGER).x(300).y(100))
3089 .build());
Siarhei Vishniakou2899c552023-07-10 18:20:46 -07003090 leftWindow->assertNoEvents();
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -07003091 rightWindow->consumeMotionEvent(
3092 AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(touchDeviceId)));
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -07003093
Siarhei Vishniakou2899c552023-07-10 18:20:46 -07003094 // Spy window does not receive touch events, because stylus events take precedence, and it
3095 // already has an active stylus gesture.
3096
3097 // Stylus movements continue. They should be delivered to the left window and to the spy window
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -07003098 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_STYLUS)
3099 .deviceId(stylusDeviceId)
3100 .pointer(PointerBuilder(0, ToolType::STYLUS).x(110).y(110))
3101 .build());
Siarhei Vishniakou2899c552023-07-10 18:20:46 -07003102 leftWindow->consumeMotionEvent(
3103 AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(stylusDeviceId)));
3104 spyWindow->consumeMotionEvent(
3105 AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(stylusDeviceId)));
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -07003106
Siarhei Vishniakou2899c552023-07-10 18:20:46 -07003107 // Further MOVE events keep going to the right window only
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -07003108 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN)
3109 .deviceId(touchDeviceId)
3110 .pointer(PointerBuilder(0, ToolType::FINGER).x(310).y(110))
3111 .build());
3112 rightWindow->consumeMotionEvent(
3113 AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(touchDeviceId)));
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -07003114
3115 spyWindow->assertNoEvents();
3116 leftWindow->assertNoEvents();
3117 rightWindow->assertNoEvents();
3118}
3119
3120/**
3121 * Three windows: a window on the left, a window on the right, and a spy window positioned above
3122 * both.
3123 * Check hover in left window and touch down in the right window.
Siarhei Vishniakou3ad54f52023-11-02 16:54:40 -07003124 * At first, spy should receive hover. Spy shouldn't receive touch while stylus is hovering.
Siarhei Vishniakou2899c552023-07-10 18:20:46 -07003125 * At the same time, left and right should be getting independent streams of hovering and touch,
3126 * respectively.
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -07003127 */
Siarhei Vishniakou3ad54f52023-11-02 16:54:40 -07003128TEST_F(InputDispatcherMultiDeviceTest, MultiDeviceHoverBlocksTouchWithSpy) {
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -07003129 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
3130
3131 sp<FakeWindowHandle> spyWindow =
3132 sp<FakeWindowHandle>::make(application, mDispatcher, "Spy", ADISPLAY_ID_DEFAULT);
3133 spyWindow->setFrame(Rect(0, 0, 400, 400));
3134 spyWindow->setTrustedOverlay(true);
3135 spyWindow->setSpy(true);
3136
3137 sp<FakeWindowHandle> leftWindow =
3138 sp<FakeWindowHandle>::make(application, mDispatcher, "Left", ADISPLAY_ID_DEFAULT);
3139 leftWindow->setFrame(Rect(0, 0, 200, 200));
3140
3141 sp<FakeWindowHandle> rightWindow =
3142 sp<FakeWindowHandle>::make(application, mDispatcher, "Right", ADISPLAY_ID_DEFAULT);
3143 rightWindow->setFrame(Rect(200, 0, 400, 200));
3144
3145 mDispatcher->onWindowInfosChanged(
3146 {{*spyWindow->getInfo(), *leftWindow->getInfo(), *rightWindow->getInfo()}, {}, 0, 0});
3147
3148 const int32_t stylusDeviceId = 1;
3149 const int32_t touchDeviceId = 2;
3150
3151 // Stylus hover on the left window
3152 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_ENTER, AINPUT_SOURCE_STYLUS)
3153 .deviceId(stylusDeviceId)
3154 .pointer(PointerBuilder(0, ToolType::STYLUS).x(100).y(100))
3155 .build());
3156 leftWindow->consumeMotionEvent(
3157 AllOf(WithMotionAction(ACTION_HOVER_ENTER), WithDeviceId(stylusDeviceId)));
3158 spyWindow->consumeMotionEvent(
3159 AllOf(WithMotionAction(ACTION_HOVER_ENTER), WithDeviceId(stylusDeviceId)));
3160
Siarhei Vishniakou2899c552023-07-10 18:20:46 -07003161 // Touch down on the right window. Spy doesn't receive this touch because it already has
3162 // stylus hovering there.
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -07003163 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
3164 .deviceId(touchDeviceId)
3165 .pointer(PointerBuilder(0, ToolType::FINGER).x(300).y(100))
3166 .build());
Siarhei Vishniakou2899c552023-07-10 18:20:46 -07003167 leftWindow->assertNoEvents();
Siarhei Vishniakou3ad54f52023-11-02 16:54:40 -07003168 spyWindow->assertNoEvents();
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -07003169 rightWindow->consumeMotionEvent(
3170 AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(touchDeviceId)));
3171
Siarhei Vishniakou3ad54f52023-11-02 16:54:40 -07003172 // Stylus movements continue. They should be delivered to the left window and the spy.
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -07003173 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_MOVE, AINPUT_SOURCE_STYLUS)
3174 .deviceId(stylusDeviceId)
3175 .pointer(PointerBuilder(0, ToolType::STYLUS).x(110).y(110))
3176 .build());
Siarhei Vishniakou2899c552023-07-10 18:20:46 -07003177 leftWindow->consumeMotionEvent(
3178 AllOf(WithMotionAction(ACTION_HOVER_MOVE), WithDeviceId(stylusDeviceId)));
Siarhei Vishniakou3ad54f52023-11-02 16:54:40 -07003179 spyWindow->consumeMotionEvent(
3180 AllOf(WithMotionAction(ACTION_HOVER_MOVE), WithDeviceId(stylusDeviceId)));
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -07003181
Siarhei Vishniakou3ad54f52023-11-02 16:54:40 -07003182 // Touch movements continue. They should be delivered to the right window only
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -07003183 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN)
3184 .deviceId(touchDeviceId)
3185 .pointer(PointerBuilder(0, ToolType::FINGER).x(301).y(101))
3186 .build());
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -07003187 rightWindow->consumeMotionEvent(
3188 AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(touchDeviceId)));
3189
3190 spyWindow->assertNoEvents();
3191 leftWindow->assertNoEvents();
3192 rightWindow->assertNoEvents();
3193}
3194
3195/**
Siarhei Vishniakouf372b812023-02-14 18:06:51 -08003196 * On a single window, use two different devices: mouse and touch.
3197 * Touch happens first, with two pointers going down, and then the first pointer leaving.
3198 * Mouse is clicked next, which causes the touch stream to be aborted with ACTION_CANCEL.
3199 * Finally, a second touch pointer goes down again. Ensure the second touch pointer is ignored,
3200 * because the mouse is currently down, and a POINTER_DOWN event from the touchscreen does not
3201 * represent a new gesture.
3202 */
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -07003203TEST_F(InputDispatcherMultiDeviceTest, MixedTouchAndMouseWithPointerDown) {
Siarhei Vishniakouf372b812023-02-14 18:06:51 -08003204 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
3205 sp<FakeWindowHandle> window =
3206 sp<FakeWindowHandle>::make(application, mDispatcher, "Window", ADISPLAY_ID_DEFAULT);
3207 window->setFrame(Rect(0, 0, 400, 400));
3208
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07003209 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Siarhei Vishniakouf372b812023-02-14 18:06:51 -08003210
3211 const int32_t touchDeviceId = 4;
3212 const int32_t mouseDeviceId = 6;
Siarhei Vishniakouf372b812023-02-14 18:06:51 -08003213
Siarhei Vishniakou4e1ffa52023-02-21 11:50:34 -08003214 // First touch pointer down
Prabir Pradhan678438e2023-04-13 19:32:51 +00003215 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
3216 .deviceId(touchDeviceId)
3217 .pointer(PointerBuilder(0, ToolType::FINGER).x(300).y(100))
3218 .build());
Siarhei Vishniakouf372b812023-02-14 18:06:51 -08003219 // Second touch pointer down
Prabir Pradhan678438e2023-04-13 19:32:51 +00003220 mDispatcher->notifyMotion(MotionArgsBuilder(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
3221 .deviceId(touchDeviceId)
3222 .pointer(PointerBuilder(0, ToolType::FINGER).x(300).y(100))
3223 .pointer(PointerBuilder(1, ToolType::FINGER).x(350).y(100))
3224 .build());
Siarhei Vishniakouf372b812023-02-14 18:06:51 -08003225 // First touch pointer lifts. The second one remains down
Prabir Pradhan678438e2023-04-13 19:32:51 +00003226 mDispatcher->notifyMotion(MotionArgsBuilder(POINTER_0_UP, AINPUT_SOURCE_TOUCHSCREEN)
3227 .deviceId(touchDeviceId)
3228 .pointer(PointerBuilder(0, ToolType::FINGER).x(300).y(100))
3229 .pointer(PointerBuilder(1, ToolType::FINGER).x(350).y(100))
3230 .build());
Siarhei Vishniakouf372b812023-02-14 18:06:51 -08003231 window->consumeMotionEvent(WithMotionAction(ACTION_DOWN));
3232 window->consumeMotionEvent(WithMotionAction(POINTER_1_DOWN));
3233 window->consumeMotionEvent(WithMotionAction(POINTER_0_UP));
3234
3235 // Mouse down. The touch should be canceled
Prabir Pradhan678438e2023-04-13 19:32:51 +00003236 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_MOUSE)
3237 .deviceId(mouseDeviceId)
3238 .buttonState(AMOTION_EVENT_BUTTON_PRIMARY)
3239 .pointer(PointerBuilder(0, ToolType::MOUSE).x(320).y(100))
3240 .build());
Siarhei Vishniakouf372b812023-02-14 18:06:51 -08003241
3242 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_CANCEL), WithDeviceId(touchDeviceId),
Siarhei Vishniakou82dc0422023-02-17 23:12:52 -08003243 WithPointerCount(1u)));
Siarhei Vishniakouf372b812023-02-14 18:06:51 -08003244 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(mouseDeviceId)));
3245
Prabir Pradhan678438e2023-04-13 19:32:51 +00003246 mDispatcher->notifyMotion(
3247 MotionArgsBuilder(AMOTION_EVENT_ACTION_BUTTON_PRESS, AINPUT_SOURCE_MOUSE)
3248 .deviceId(mouseDeviceId)
3249 .buttonState(AMOTION_EVENT_BUTTON_PRIMARY)
3250 .actionButton(AMOTION_EVENT_BUTTON_PRIMARY)
3251 .pointer(PointerBuilder(0, ToolType::MOUSE).x(320).y(100))
3252 .build());
Siarhei Vishniakouf372b812023-02-14 18:06:51 -08003253 window->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_BUTTON_PRESS));
3254
3255 // Second touch pointer down.
Prabir Pradhan678438e2023-04-13 19:32:51 +00003256 mDispatcher->notifyMotion(MotionArgsBuilder(POINTER_0_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
3257 .deviceId(touchDeviceId)
3258 .pointer(PointerBuilder(0, ToolType::FINGER).x(300).y(100))
3259 .pointer(PointerBuilder(1, ToolType::FINGER).x(350).y(100))
3260 .build());
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -07003261 // Since we already canceled this touch gesture, it will be ignored until a completely new
3262 // gesture is started. This is easier to implement than trying to keep track of the new pointer
3263 // and generating an ACTION_DOWN instead of ACTION_POINTER_DOWN.
3264 // However, mouse movements should continue to work.
3265 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_MOUSE)
3266 .deviceId(mouseDeviceId)
3267 .buttonState(AMOTION_EVENT_BUTTON_PRIMARY)
3268 .pointer(PointerBuilder(0, ToolType::MOUSE).x(330).y(110))
3269 .build());
3270 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(mouseDeviceId)));
3271
Siarhei Vishniakouf372b812023-02-14 18:06:51 -08003272 window->assertNoEvents();
3273}
3274
3275/**
Siarhei Vishniakou56e79092023-02-21 19:13:16 -08003276 * Inject a touch down and then send a new event via 'notifyMotion'. Ensure the new event cancels
3277 * the injected event.
3278 */
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -07003279TEST_F(InputDispatcherMultiDeviceTest, UnfinishedInjectedEvent) {
Siarhei Vishniakou56e79092023-02-21 19:13:16 -08003280 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
3281 sp<FakeWindowHandle> window =
3282 sp<FakeWindowHandle>::make(application, mDispatcher, "Window", ADISPLAY_ID_DEFAULT);
3283 window->setFrame(Rect(0, 0, 400, 400));
3284
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07003285 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Siarhei Vishniakou56e79092023-02-21 19:13:16 -08003286
3287 const int32_t touchDeviceId = 4;
Siarhei Vishniakou56e79092023-02-21 19:13:16 -08003288 // Pretend a test injects an ACTION_DOWN mouse event, but forgets to lift up the touch after
3289 // completion.
3290 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07003291 injectMotionEvent(*mDispatcher,
Siarhei Vishniakou56e79092023-02-21 19:13:16 -08003292 MotionEventBuilder(ACTION_DOWN, AINPUT_SOURCE_MOUSE)
3293 .deviceId(ReservedInputDeviceId::VIRTUAL_KEYBOARD_ID)
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07003294 .pointer(PointerBuilder(0, ToolType::MOUSE).x(50).y(50))
Siarhei Vishniakou56e79092023-02-21 19:13:16 -08003295 .build()));
3296 window->consumeMotionEvent(
3297 AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(VIRTUAL_KEYBOARD_ID)));
3298
3299 // Now a real touch comes. Rather than crashing or dropping the real event, the injected pointer
3300 // should be canceled and the new gesture should take over.
Prabir Pradhan678438e2023-04-13 19:32:51 +00003301 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
3302 .deviceId(touchDeviceId)
3303 .pointer(PointerBuilder(0, ToolType::FINGER).x(300).y(100))
3304 .build());
Siarhei Vishniakou56e79092023-02-21 19:13:16 -08003305
3306 window->consumeMotionEvent(
3307 AllOf(WithMotionAction(ACTION_CANCEL), WithDeviceId(VIRTUAL_KEYBOARD_ID)));
3308 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(touchDeviceId)));
3309}
3310
3311/**
Siarhei Vishniakou6464e462023-02-06 18:57:59 -08003312 * This test is similar to the test above, but the sequence of injected events is different.
3313 *
3314 * Two windows: a window on the left and a window on the right.
3315 * Mouse is hovered over the left window.
3316 * Next, we tap on the left window, where the cursor was last seen.
3317 *
3318 * After that, we inject one finger down onto the right window, and then a second finger down onto
3319 * the left window.
3320 * The touch is split, so this last gesture should cause 2 ACTION_DOWN events, one in the right
3321 * window (first), and then another on the left window (second).
3322 * This test reproduces a crash where there is a mismatch between the downTime and eventTime.
3323 * In the buggy implementation, second finger down on the left window would cause a crash.
3324 */
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -07003325TEST_F(InputDispatcherMultiDeviceTest, HoverTapAndSplitTouch) {
Siarhei Vishniakou6464e462023-02-06 18:57:59 -08003326 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
3327 sp<FakeWindowHandle> leftWindow =
3328 sp<FakeWindowHandle>::make(application, mDispatcher, "Left", ADISPLAY_ID_DEFAULT);
3329 leftWindow->setFrame(Rect(0, 0, 200, 200));
3330
3331 sp<FakeWindowHandle> rightWindow =
3332 sp<FakeWindowHandle>::make(application, mDispatcher, "Right", ADISPLAY_ID_DEFAULT);
3333 rightWindow->setFrame(Rect(200, 0, 400, 200));
3334
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07003335 mDispatcher->onWindowInfosChanged(
3336 {{*leftWindow->getInfo(), *rightWindow->getInfo()}, {}, 0, 0});
Siarhei Vishniakou6464e462023-02-06 18:57:59 -08003337
3338 const int32_t mouseDeviceId = 6;
3339 const int32_t touchDeviceId = 4;
3340 // Hover over the left window. Keep the cursor there.
3341 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07003342 injectMotionEvent(*mDispatcher,
Siarhei Vishniakou6464e462023-02-06 18:57:59 -08003343 MotionEventBuilder(AMOTION_EVENT_ACTION_HOVER_ENTER,
3344 AINPUT_SOURCE_MOUSE)
3345 .deviceId(mouseDeviceId)
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07003346 .pointer(PointerBuilder(0, ToolType::MOUSE).x(50).y(50))
Siarhei Vishniakou6464e462023-02-06 18:57:59 -08003347 .build()));
3348 leftWindow->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_ENTER));
3349
3350 // Tap on left window
3351 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07003352 injectMotionEvent(*mDispatcher,
Siarhei Vishniakou6464e462023-02-06 18:57:59 -08003353 MotionEventBuilder(AMOTION_EVENT_ACTION_DOWN,
3354 AINPUT_SOURCE_TOUCHSCREEN)
3355 .deviceId(touchDeviceId)
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07003356 .pointer(PointerBuilder(0, ToolType::FINGER).x(100).y(100))
Siarhei Vishniakou6464e462023-02-06 18:57:59 -08003357 .build()));
3358
3359 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07003360 injectMotionEvent(*mDispatcher,
Siarhei Vishniakou6464e462023-02-06 18:57:59 -08003361 MotionEventBuilder(AMOTION_EVENT_ACTION_UP,
3362 AINPUT_SOURCE_TOUCHSCREEN)
3363 .deviceId(touchDeviceId)
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07003364 .pointer(PointerBuilder(0, ToolType::FINGER).x(100).y(100))
Siarhei Vishniakou6464e462023-02-06 18:57:59 -08003365 .build()));
3366 leftWindow->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_EXIT));
3367 leftWindow->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_DOWN));
3368 leftWindow->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_UP));
3369
3370 // First finger down on right window
3371 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07003372 injectMotionEvent(*mDispatcher,
Siarhei Vishniakou6464e462023-02-06 18:57:59 -08003373 MotionEventBuilder(AMOTION_EVENT_ACTION_DOWN,
3374 AINPUT_SOURCE_TOUCHSCREEN)
3375 .deviceId(touchDeviceId)
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07003376 .pointer(PointerBuilder(0, ToolType::FINGER).x(300).y(100))
Siarhei Vishniakou6464e462023-02-06 18:57:59 -08003377 .build()));
3378 rightWindow->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_DOWN));
3379
3380 // Second finger down on the left window
3381 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07003382 injectMotionEvent(*mDispatcher,
Siarhei Vishniakou6464e462023-02-06 18:57:59 -08003383 MotionEventBuilder(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
3384 .deviceId(touchDeviceId)
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07003385 .pointer(PointerBuilder(0, ToolType::FINGER).x(300).y(100))
3386 .pointer(PointerBuilder(1, ToolType::FINGER).x(100).y(100))
Siarhei Vishniakou6464e462023-02-06 18:57:59 -08003387 .build()));
3388 leftWindow->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_DOWN));
3389 rightWindow->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_MOVE));
3390
3391 // No more events
3392 leftWindow->assertNoEvents();
3393 rightWindow->assertNoEvents();
3394}
3395
3396/**
Siarhei Vishniakou2e3e4432023-02-09 18:34:11 -08003397 * Start hovering with a stylus device, and then tap with a touch device. Ensure no crash occurs.
3398 * While the touch is down, new hover events from the stylus device should be ignored. After the
3399 * touch is gone, stylus hovering should start working again.
3400 */
Siarhei Vishniakou3ad54f52023-11-02 16:54:40 -07003401TEST_F(InputDispatcherMultiDeviceTest, StylusHoverIgnoresTouchTap) {
Siarhei Vishniakou2e3e4432023-02-09 18:34:11 -08003402 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
3403 sp<FakeWindowHandle> window =
3404 sp<FakeWindowHandle>::make(application, mDispatcher, "Window", ADISPLAY_ID_DEFAULT);
3405 window->setFrame(Rect(0, 0, 200, 200));
3406
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07003407 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Siarhei Vishniakou2e3e4432023-02-09 18:34:11 -08003408
3409 const int32_t stylusDeviceId = 5;
3410 const int32_t touchDeviceId = 4;
3411 // Start hovering with stylus
3412 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07003413 injectMotionEvent(*mDispatcher,
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -07003414 MotionEventBuilder(ACTION_HOVER_ENTER, AINPUT_SOURCE_STYLUS)
Siarhei Vishniakou2e3e4432023-02-09 18:34:11 -08003415 .deviceId(stylusDeviceId)
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07003416 .pointer(PointerBuilder(0, ToolType::STYLUS).x(50).y(50))
Siarhei Vishniakou2e3e4432023-02-09 18:34:11 -08003417 .build()));
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -07003418 window->consumeMotionEvent(WithMotionAction(ACTION_HOVER_ENTER));
Siarhei Vishniakou2e3e4432023-02-09 18:34:11 -08003419
3420 // Finger down on the window
3421 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07003422 injectMotionEvent(*mDispatcher,
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -07003423 MotionEventBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
Siarhei Vishniakou2e3e4432023-02-09 18:34:11 -08003424 .deviceId(touchDeviceId)
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07003425 .pointer(PointerBuilder(0, ToolType::FINGER).x(100).y(100))
Siarhei Vishniakou2e3e4432023-02-09 18:34:11 -08003426 .build()));
Siarhei Vishniakou3ad54f52023-11-02 16:54:40 -07003427 // The touch device should be ignored!
Siarhei Vishniakou2e3e4432023-02-09 18:34:11 -08003428
Siarhei Vishniakou2899c552023-07-10 18:20:46 -07003429 // Continue hovering with stylus.
3430 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07003431 injectMotionEvent(*mDispatcher,
Siarhei Vishniakou2e3e4432023-02-09 18:34:11 -08003432 MotionEventBuilder(AMOTION_EVENT_ACTION_HOVER_MOVE,
3433 AINPUT_SOURCE_STYLUS)
3434 .deviceId(stylusDeviceId)
Siarhei Vishniakou25537f82023-07-18 14:35:47 -07003435 .pointer(PointerBuilder(0, ToolType::STYLUS).x(60).y(60))
Siarhei Vishniakou2e3e4432023-02-09 18:34:11 -08003436 .build()));
Siarhei Vishniakou3ad54f52023-11-02 16:54:40 -07003437 // Hovers continue to work
3438 window->consumeMotionEvent(
3439 AllOf(WithMotionAction(ACTION_HOVER_MOVE), WithDeviceId(stylusDeviceId)));
Siarhei Vishniakou2e3e4432023-02-09 18:34:11 -08003440
3441 // Lift up the finger
3442 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07003443 injectMotionEvent(*mDispatcher,
Siarhei Vishniakou2e3e4432023-02-09 18:34:11 -08003444 MotionEventBuilder(AMOTION_EVENT_ACTION_UP,
3445 AINPUT_SOURCE_TOUCHSCREEN)
3446 .deviceId(touchDeviceId)
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07003447 .pointer(PointerBuilder(0, ToolType::FINGER).x(100).y(100))
Siarhei Vishniakou2e3e4432023-02-09 18:34:11 -08003448 .build()));
Siarhei Vishniakou2e3e4432023-02-09 18:34:11 -08003449
Siarhei Vishniakou2e3e4432023-02-09 18:34:11 -08003450 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07003451 injectMotionEvent(*mDispatcher,
Siarhei Vishniakou2e3e4432023-02-09 18:34:11 -08003452 MotionEventBuilder(AMOTION_EVENT_ACTION_HOVER_MOVE,
3453 AINPUT_SOURCE_STYLUS)
3454 .deviceId(stylusDeviceId)
Siarhei Vishniakou25537f82023-07-18 14:35:47 -07003455 .pointer(PointerBuilder(0, ToolType::STYLUS).x(70).y(70))
Siarhei Vishniakou2e3e4432023-02-09 18:34:11 -08003456 .build()));
Siarhei Vishniakou3ad54f52023-11-02 16:54:40 -07003457 window->consumeMotionEvent(
3458 AllOf(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_MOVE), WithDeviceId(stylusDeviceId)));
Siarhei Vishniakou2e3e4432023-02-09 18:34:11 -08003459 window->assertNoEvents();
3460}
3461
3462/**
Siarhei Vishniakouf77f60a2023-10-23 17:26:05 -07003463 * If stylus is down anywhere on the screen, then touches should not be delivered to windows that
3464 * have InputConfig::GLOBAL_STYLUS_BLOCKS_TOUCH.
3465 *
3466 * Two windows: one on the left and one on the right.
3467 * The window on the right has GLOBAL_STYLUS_BLOCKS_TOUCH config.
3468 * Stylus down on the left window, and then touch down on the right window.
3469 * Check that the right window doesn't get touches while the stylus is down on the left window.
3470 */
3471TEST_F(InputDispatcherMultiDeviceTest, GlobalStylusDownBlocksTouch) {
3472 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
3473 sp<FakeWindowHandle> leftWindow =
3474 sp<FakeWindowHandle>::make(application, mDispatcher, "Left window",
3475 ADISPLAY_ID_DEFAULT);
3476 leftWindow->setFrame(Rect(0, 0, 100, 100));
3477
3478 sp<FakeWindowHandle> sbtRightWindow =
3479 sp<FakeWindowHandle>::make(application, mDispatcher,
3480 "Stylus blocks touch (right) window", ADISPLAY_ID_DEFAULT);
3481 sbtRightWindow->setFrame(Rect(100, 100, 200, 200));
3482 sbtRightWindow->setGlobalStylusBlocksTouch(true);
3483
3484 mDispatcher->onWindowInfosChanged(
3485 {{*leftWindow->getInfo(), *sbtRightWindow->getInfo()}, {}, 0, 0});
3486
3487 const int32_t stylusDeviceId = 5;
3488 const int32_t touchDeviceId = 4;
3489
3490 // Stylus down in the left window
3491 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_STYLUS)
3492 .pointer(PointerBuilder(0, ToolType::STYLUS).x(50).y(52))
3493 .deviceId(stylusDeviceId)
3494 .build());
3495 leftWindow->consumeMotionEvent(
3496 AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(stylusDeviceId)));
3497
3498 // Finger tap on the right window
3499 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
3500 .pointer(PointerBuilder(0, ToolType::FINGER).x(150).y(151))
3501 .deviceId(touchDeviceId)
3502 .build());
3503 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN)
3504 .pointer(PointerBuilder(0, ToolType::FINGER).x(150).y(151))
3505 .deviceId(touchDeviceId)
3506 .build());
3507
3508 // The touch should be blocked, because stylus is down somewhere else on screen!
3509 sbtRightWindow->assertNoEvents();
3510
3511 // Continue stylus motion, and ensure it's not impacted.
3512 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_STYLUS)
3513 .pointer(PointerBuilder(0, ToolType::STYLUS).x(51).y(53))
3514 .deviceId(stylusDeviceId)
3515 .build());
3516 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_UP, AINPUT_SOURCE_STYLUS)
3517 .pointer(PointerBuilder(0, ToolType::STYLUS).x(51).y(53))
3518 .deviceId(stylusDeviceId)
3519 .build());
3520 leftWindow->consumeMotionEvent(
3521 AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(stylusDeviceId)));
3522 leftWindow->consumeMotionEvent(
3523 AllOf(WithMotionAction(ACTION_UP), WithDeviceId(stylusDeviceId)));
3524
3525 // Now that the stylus gesture is done, touches should be getting delivered correctly.
3526 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
3527 .pointer(PointerBuilder(0, ToolType::FINGER).x(151).y(153))
3528 .deviceId(touchDeviceId)
3529 .build());
3530 sbtRightWindow->consumeMotionEvent(
3531 AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(touchDeviceId)));
3532}
3533
3534/**
3535 * If stylus is hovering anywhere on the screen, then touches should not be delivered to windows
3536 * that have InputConfig::GLOBAL_STYLUS_BLOCKS_TOUCH.
3537 *
3538 * Two windows: one on the left and one on the right.
3539 * The window on the right has GLOBAL_STYLUS_BLOCKS_TOUCH config.
3540 * Stylus hover on the left window, and then touch down on the right window.
3541 * Check that the right window doesn't get touches while the stylus is hovering on the left window.
3542 */
3543TEST_F(InputDispatcherMultiDeviceTest, GlobalStylusHoverBlocksTouch) {
3544 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
3545 sp<FakeWindowHandle> leftWindow =
3546 sp<FakeWindowHandle>::make(application, mDispatcher, "Left window",
3547 ADISPLAY_ID_DEFAULT);
3548 leftWindow->setFrame(Rect(0, 0, 100, 100));
3549
3550 sp<FakeWindowHandle> sbtRightWindow =
3551 sp<FakeWindowHandle>::make(application, mDispatcher,
3552 "Stylus blocks touch (right) window", ADISPLAY_ID_DEFAULT);
3553 sbtRightWindow->setFrame(Rect(100, 100, 200, 200));
3554 sbtRightWindow->setGlobalStylusBlocksTouch(true);
3555
3556 mDispatcher->onWindowInfosChanged(
3557 {{*leftWindow->getInfo(), *sbtRightWindow->getInfo()}, {}, 0, 0});
3558
3559 const int32_t stylusDeviceId = 5;
3560 const int32_t touchDeviceId = 4;
3561
3562 // Stylus hover in the left window
3563 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_ENTER, AINPUT_SOURCE_STYLUS)
3564 .pointer(PointerBuilder(0, ToolType::STYLUS).x(50).y(52))
3565 .deviceId(stylusDeviceId)
3566 .build());
3567 leftWindow->consumeMotionEvent(
3568 AllOf(WithMotionAction(ACTION_HOVER_ENTER), WithDeviceId(stylusDeviceId)));
3569
3570 // Finger tap on the right window
3571 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
3572 .pointer(PointerBuilder(0, ToolType::FINGER).x(150).y(151))
3573 .deviceId(touchDeviceId)
3574 .build());
3575 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN)
3576 .pointer(PointerBuilder(0, ToolType::FINGER).x(150).y(151))
3577 .deviceId(touchDeviceId)
3578 .build());
3579
3580 // The touch should be blocked, because stylus is hovering somewhere else on screen!
3581 sbtRightWindow->assertNoEvents();
3582
3583 // Continue stylus motion, and ensure it's not impacted.
3584 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_MOVE, AINPUT_SOURCE_STYLUS)
3585 .pointer(PointerBuilder(0, ToolType::STYLUS).x(51).y(53))
3586 .deviceId(stylusDeviceId)
3587 .build());
3588 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_EXIT, AINPUT_SOURCE_STYLUS)
3589 .pointer(PointerBuilder(0, ToolType::STYLUS).x(51).y(53))
3590 .deviceId(stylusDeviceId)
3591 .build());
3592 leftWindow->consumeMotionEvent(
3593 AllOf(WithMotionAction(ACTION_HOVER_MOVE), WithDeviceId(stylusDeviceId)));
3594 leftWindow->consumeMotionEvent(
3595 AllOf(WithMotionAction(ACTION_HOVER_EXIT), WithDeviceId(stylusDeviceId)));
3596
3597 // Now that the stylus gesture is done, touches should be getting delivered correctly.
3598 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
3599 .pointer(PointerBuilder(0, ToolType::FINGER).x(151).y(153))
3600 .deviceId(touchDeviceId)
3601 .build());
3602 sbtRightWindow->consumeMotionEvent(
3603 AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(touchDeviceId)));
3604}
3605
3606/**
Siarhei Vishniakouf372b812023-02-14 18:06:51 -08003607 * A spy window above a window with no input channel.
3608 * Start hovering with a stylus device, and then tap with it.
3609 * Ensure spy window receives the entire sequence.
3610 */
3611TEST_F(InputDispatcherTest, StylusHoverAndDownNoInputChannel) {
3612 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
3613 sp<FakeWindowHandle> spyWindow =
3614 sp<FakeWindowHandle>::make(application, mDispatcher, "Spy", ADISPLAY_ID_DEFAULT);
3615 spyWindow->setFrame(Rect(0, 0, 200, 200));
3616 spyWindow->setTrustedOverlay(true);
3617 spyWindow->setSpy(true);
3618 sp<FakeWindowHandle> window =
3619 sp<FakeWindowHandle>::make(application, mDispatcher, "Window", ADISPLAY_ID_DEFAULT);
3620 window->setNoInputChannel(true);
3621 window->setFrame(Rect(0, 0, 200, 200));
3622
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07003623 mDispatcher->onWindowInfosChanged({{*spyWindow->getInfo(), *window->getInfo()}, {}, 0, 0});
Siarhei Vishniakouf372b812023-02-14 18:06:51 -08003624
Siarhei Vishniakouf372b812023-02-14 18:06:51 -08003625 // Start hovering with stylus
Prabir Pradhan678438e2023-04-13 19:32:51 +00003626 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_ENTER, AINPUT_SOURCE_STYLUS)
3627 .pointer(PointerBuilder(0, ToolType::STYLUS).x(50).y(50))
3628 .build());
Siarhei Vishniakouf372b812023-02-14 18:06:51 -08003629 spyWindow->consumeMotionEvent(WithMotionAction(ACTION_HOVER_ENTER));
3630 // Stop hovering
Prabir Pradhan678438e2023-04-13 19:32:51 +00003631 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_EXIT, AINPUT_SOURCE_STYLUS)
3632 .pointer(PointerBuilder(0, ToolType::STYLUS).x(50).y(50))
3633 .build());
Siarhei Vishniakouf372b812023-02-14 18:06:51 -08003634 spyWindow->consumeMotionEvent(WithMotionAction(ACTION_HOVER_EXIT));
3635
3636 // Stylus touches down
Prabir Pradhan678438e2023-04-13 19:32:51 +00003637 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_STYLUS)
3638 .pointer(PointerBuilder(0, ToolType::STYLUS).x(50).y(50))
3639 .build());
Siarhei Vishniakouf372b812023-02-14 18:06:51 -08003640 spyWindow->consumeMotionEvent(WithMotionAction(ACTION_DOWN));
3641
3642 // Stylus goes up
Prabir Pradhan678438e2023-04-13 19:32:51 +00003643 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_UP, AINPUT_SOURCE_STYLUS)
3644 .pointer(PointerBuilder(0, ToolType::STYLUS).x(50).y(50))
3645 .build());
Siarhei Vishniakouf372b812023-02-14 18:06:51 -08003646 spyWindow->consumeMotionEvent(WithMotionAction(ACTION_UP));
3647
3648 // Again hover
Prabir Pradhan678438e2023-04-13 19:32:51 +00003649 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_ENTER, AINPUT_SOURCE_STYLUS)
3650 .pointer(PointerBuilder(0, ToolType::STYLUS).x(50).y(50))
3651 .build());
Siarhei Vishniakouf372b812023-02-14 18:06:51 -08003652 spyWindow->consumeMotionEvent(WithMotionAction(ACTION_HOVER_ENTER));
3653 // Stop hovering
Prabir Pradhan678438e2023-04-13 19:32:51 +00003654 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_EXIT, AINPUT_SOURCE_STYLUS)
3655 .pointer(PointerBuilder(0, ToolType::STYLUS).x(50).y(50))
3656 .build());
Siarhei Vishniakouf372b812023-02-14 18:06:51 -08003657 spyWindow->consumeMotionEvent(WithMotionAction(ACTION_HOVER_EXIT));
3658
3659 // No more events
3660 spyWindow->assertNoEvents();
3661 window->assertNoEvents();
3662}
3663
3664/**
Siarhei Vishniakou6b71b632023-10-27 21:34:46 -07003665 * A stale stylus HOVER_EXIT event is injected. Since it's a stale event, it should generally be
3666 * rejected. But since we already have an ongoing gesture, this event should be processed.
3667 * This prevents inconsistent events being handled inside the dispatcher.
3668 */
3669TEST_F(InputDispatcherTest, StaleStylusHoverGestureIsComplete) {
3670 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
3671
3672 sp<FakeWindowHandle> window =
3673 sp<FakeWindowHandle>::make(application, mDispatcher, "Window", ADISPLAY_ID_DEFAULT);
3674 window->setFrame(Rect(0, 0, 200, 200));
3675
3676 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
3677
3678 // Start hovering with stylus
3679 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_ENTER, AINPUT_SOURCE_STYLUS)
3680 .pointer(PointerBuilder(0, ToolType::STYLUS).x(50).y(50))
3681 .build());
3682 window->consumeMotionEvent(WithMotionAction(ACTION_HOVER_ENTER));
3683
3684 NotifyMotionArgs hoverExit = MotionArgsBuilder(ACTION_HOVER_EXIT, AINPUT_SOURCE_STYLUS)
3685 .pointer(PointerBuilder(0, ToolType::STYLUS).x(50).y(50))
3686 .build();
3687 // Make this 'hoverExit' event stale
3688 mFakePolicy->setStaleEventTimeout(100ms);
3689 std::this_thread::sleep_for(100ms);
3690
3691 // It shouldn't be dropped by the dispatcher, even though it's stale.
3692 mDispatcher->notifyMotion(hoverExit);
3693 window->consumeMotionEvent(WithMotionAction(ACTION_HOVER_EXIT));
3694
3695 // Stylus starts hovering again! There should be no crash.
3696 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_ENTER, AINPUT_SOURCE_STYLUS)
3697 .pointer(PointerBuilder(0, ToolType::STYLUS).x(51).y(51))
3698 .build());
3699 window->consumeMotionEvent(WithMotionAction(ACTION_HOVER_ENTER));
3700}
3701
3702/**
Siarhei Vishniakouf372b812023-02-14 18:06:51 -08003703 * Start hovering with a mouse, and then tap with a touch device. Pilfer the touch stream.
3704 * Next, click with the mouse device. Both windows (spy and regular) should receive the new mouse
3705 * ACTION_DOWN event because that's a new gesture, and pilfering should no longer be active.
3706 * While the mouse is down, new move events from the touch device should be ignored.
3707 */
3708TEST_F(InputDispatcherTest, TouchPilferAndMouseMove) {
3709 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
3710 sp<FakeWindowHandle> spyWindow =
3711 sp<FakeWindowHandle>::make(application, mDispatcher, "Spy", ADISPLAY_ID_DEFAULT);
3712 spyWindow->setFrame(Rect(0, 0, 200, 200));
3713 spyWindow->setTrustedOverlay(true);
3714 spyWindow->setSpy(true);
3715 sp<FakeWindowHandle> window =
3716 sp<FakeWindowHandle>::make(application, mDispatcher, "Window", ADISPLAY_ID_DEFAULT);
3717 window->setFrame(Rect(0, 0, 200, 200));
3718
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07003719 mDispatcher->onWindowInfosChanged({{*spyWindow->getInfo(), *window->getInfo()}, {}, 0, 0});
Siarhei Vishniakouf372b812023-02-14 18:06:51 -08003720
3721 const int32_t mouseDeviceId = 7;
3722 const int32_t touchDeviceId = 4;
Siarhei Vishniakouf372b812023-02-14 18:06:51 -08003723
3724 // Hover a bit with mouse first
Prabir Pradhan678438e2023-04-13 19:32:51 +00003725 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_ENTER, AINPUT_SOURCE_MOUSE)
3726 .deviceId(mouseDeviceId)
3727 .pointer(PointerBuilder(0, ToolType::MOUSE).x(100).y(100))
3728 .build());
Siarhei Vishniakouf372b812023-02-14 18:06:51 -08003729 spyWindow->consumeMotionEvent(
3730 AllOf(WithMotionAction(ACTION_HOVER_ENTER), WithDeviceId(mouseDeviceId)));
3731 window->consumeMotionEvent(
3732 AllOf(WithMotionAction(ACTION_HOVER_ENTER), WithDeviceId(mouseDeviceId)));
3733
3734 // Start touching
Prabir Pradhan678438e2023-04-13 19:32:51 +00003735 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
3736 .deviceId(touchDeviceId)
3737 .pointer(PointerBuilder(0, ToolType::FINGER).x(50).y(50))
3738 .build());
Siarhei Vishniakouf372b812023-02-14 18:06:51 -08003739 spyWindow->consumeMotionEvent(WithMotionAction(ACTION_HOVER_EXIT));
3740 window->consumeMotionEvent(WithMotionAction(ACTION_HOVER_EXIT));
3741 spyWindow->consumeMotionEvent(WithMotionAction(ACTION_DOWN));
3742 window->consumeMotionEvent(WithMotionAction(ACTION_DOWN));
3743
Prabir Pradhan678438e2023-04-13 19:32:51 +00003744 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN)
3745 .deviceId(touchDeviceId)
3746 .pointer(PointerBuilder(0, ToolType::FINGER).x(55).y(55))
3747 .build());
Siarhei Vishniakouf372b812023-02-14 18:06:51 -08003748 spyWindow->consumeMotionEvent(WithMotionAction(ACTION_MOVE));
3749 window->consumeMotionEvent(WithMotionAction(ACTION_MOVE));
3750
3751 // Pilfer the stream
3752 EXPECT_EQ(OK, mDispatcher->pilferPointers(spyWindow->getToken()));
3753 window->consumeMotionEvent(WithMotionAction(ACTION_CANCEL));
3754
Prabir Pradhan678438e2023-04-13 19:32:51 +00003755 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN)
3756 .deviceId(touchDeviceId)
3757 .pointer(PointerBuilder(0, ToolType::FINGER).x(60).y(60))
3758 .build());
Siarhei Vishniakouf372b812023-02-14 18:06:51 -08003759 spyWindow->consumeMotionEvent(WithMotionAction(ACTION_MOVE));
3760
3761 // Mouse down
Prabir Pradhan678438e2023-04-13 19:32:51 +00003762 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_MOUSE)
3763 .deviceId(mouseDeviceId)
3764 .buttonState(AMOTION_EVENT_BUTTON_PRIMARY)
3765 .pointer(PointerBuilder(0, ToolType::MOUSE).x(100).y(100))
3766 .build());
Siarhei Vishniakouf372b812023-02-14 18:06:51 -08003767
3768 spyWindow->consumeMotionEvent(
3769 AllOf(WithMotionAction(ACTION_CANCEL), WithDeviceId(touchDeviceId)));
3770 spyWindow->consumeMotionEvent(
3771 AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(mouseDeviceId)));
3772 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(mouseDeviceId)));
3773
Prabir Pradhan678438e2023-04-13 19:32:51 +00003774 mDispatcher->notifyMotion(
3775 MotionArgsBuilder(AMOTION_EVENT_ACTION_BUTTON_PRESS, AINPUT_SOURCE_MOUSE)
3776 .deviceId(mouseDeviceId)
3777 .buttonState(AMOTION_EVENT_BUTTON_PRIMARY)
3778 .actionButton(AMOTION_EVENT_BUTTON_PRIMARY)
3779 .pointer(PointerBuilder(0, ToolType::MOUSE).x(100).y(100))
3780 .build());
Siarhei Vishniakouf372b812023-02-14 18:06:51 -08003781 spyWindow->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_BUTTON_PRESS));
3782 window->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_BUTTON_PRESS));
3783
3784 // Mouse move!
Prabir Pradhan678438e2023-04-13 19:32:51 +00003785 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_MOUSE)
3786 .deviceId(mouseDeviceId)
3787 .buttonState(AMOTION_EVENT_BUTTON_PRIMARY)
3788 .pointer(PointerBuilder(0, ToolType::MOUSE).x(110).y(110))
3789 .build());
Siarhei Vishniakouf372b812023-02-14 18:06:51 -08003790 spyWindow->consumeMotionEvent(WithMotionAction(ACTION_MOVE));
3791 window->consumeMotionEvent(WithMotionAction(ACTION_MOVE));
3792
3793 // Touch move!
Prabir Pradhan678438e2023-04-13 19:32:51 +00003794 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN)
3795 .deviceId(touchDeviceId)
3796 .pointer(PointerBuilder(0, ToolType::FINGER).x(65).y(65))
3797 .build());
Siarhei Vishniakouf372b812023-02-14 18:06:51 -08003798
3799 // No more events
3800 spyWindow->assertNoEvents();
3801 window->assertNoEvents();
3802}
3803
3804/**
Siarhei Vishniakoua16e3a22022-03-02 15:26:40 -08003805 * On the display, have a single window, and also an area where there's no window.
3806 * First pointer touches the "no window" area of the screen. Second pointer touches the window.
3807 * Make sure that the window receives the second pointer, and first pointer is simply ignored.
3808 */
3809TEST_F(InputDispatcherTest, SplitWorksWhenEmptyAreaIsTouched) {
3810 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
3811 sp<FakeWindowHandle> window =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07003812 sp<FakeWindowHandle>::make(application, mDispatcher, "Window", DISPLAY_ID);
Siarhei Vishniakoua16e3a22022-03-02 15:26:40 -08003813
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07003814 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Siarhei Vishniakoua16e3a22022-03-02 15:26:40 -08003815
3816 // Touch down on the empty space
Prabir Pradhan678438e2023-04-13 19:32:51 +00003817 mDispatcher->notifyMotion(generateTouchArgs(AMOTION_EVENT_ACTION_DOWN, {{-1, -1}}));
Siarhei Vishniakoua16e3a22022-03-02 15:26:40 -08003818
3819 mDispatcher->waitForIdle();
3820 window->assertNoEvents();
3821
3822 // Now touch down on the window with another pointer
Prabir Pradhan678438e2023-04-13 19:32:51 +00003823 mDispatcher->notifyMotion(generateTouchArgs(POINTER_1_DOWN, {{-1, -1}, {10, 10}}));
Siarhei Vishniakoua16e3a22022-03-02 15:26:40 -08003824 mDispatcher->waitForIdle();
3825 window->consumeMotionDown();
3826}
3827
3828/**
3829 * Same test as above, but instead of touching the empty space, the first touch goes to
3830 * non-touchable window.
3831 */
3832TEST_F(InputDispatcherTest, SplitWorksWhenNonTouchableWindowIsTouched) {
3833 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
3834 sp<FakeWindowHandle> window1 =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07003835 sp<FakeWindowHandle>::make(application, mDispatcher, "Window1", DISPLAY_ID);
Siarhei Vishniakoua16e3a22022-03-02 15:26:40 -08003836 window1->setTouchableRegion(Region{{0, 0, 100, 100}});
3837 window1->setTouchable(false);
3838 sp<FakeWindowHandle> window2 =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07003839 sp<FakeWindowHandle>::make(application, mDispatcher, "Window2", DISPLAY_ID);
Siarhei Vishniakoua16e3a22022-03-02 15:26:40 -08003840 window2->setTouchableRegion(Region{{100, 0, 200, 100}});
3841
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07003842 mDispatcher->onWindowInfosChanged({{*window1->getInfo(), *window2->getInfo()}, {}, 0, 0});
Siarhei Vishniakoua16e3a22022-03-02 15:26:40 -08003843
Siarhei Vishniakoua16e3a22022-03-02 15:26:40 -08003844 // Touch down on the non-touchable window
Prabir Pradhan678438e2023-04-13 19:32:51 +00003845 mDispatcher->notifyMotion(generateTouchArgs(AMOTION_EVENT_ACTION_DOWN, {{50, 50}}));
Siarhei Vishniakoua16e3a22022-03-02 15:26:40 -08003846
3847 mDispatcher->waitForIdle();
3848 window1->assertNoEvents();
3849 window2->assertNoEvents();
3850
3851 // Now touch down on the window with another pointer
Prabir Pradhan678438e2023-04-13 19:32:51 +00003852 mDispatcher->notifyMotion(generateTouchArgs(POINTER_1_DOWN, {{50, 50}, {150, 50}}));
Siarhei Vishniakoua16e3a22022-03-02 15:26:40 -08003853 mDispatcher->waitForIdle();
3854 window2->consumeMotionDown();
3855}
3856
Vaibhav Devmurari882bd9b2022-06-23 14:54:54 +00003857/**
3858 * When splitting touch events the downTime should be adjusted such that the downTime corresponds
3859 * to the event time of the first ACTION_DOWN sent to the particular window.
3860 */
3861TEST_F(InputDispatcherTest, SplitTouchesSendCorrectActionDownTime) {
3862 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
3863 sp<FakeWindowHandle> window1 =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07003864 sp<FakeWindowHandle>::make(application, mDispatcher, "Window1", DISPLAY_ID);
Vaibhav Devmurari882bd9b2022-06-23 14:54:54 +00003865 window1->setTouchableRegion(Region{{0, 0, 100, 100}});
3866 sp<FakeWindowHandle> window2 =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07003867 sp<FakeWindowHandle>::make(application, mDispatcher, "Window2", DISPLAY_ID);
Vaibhav Devmurari882bd9b2022-06-23 14:54:54 +00003868 window2->setTouchableRegion(Region{{100, 0, 200, 100}});
3869
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07003870 mDispatcher->onWindowInfosChanged({{*window1->getInfo(), *window2->getInfo()}, {}, 0, 0});
Vaibhav Devmurari882bd9b2022-06-23 14:54:54 +00003871
Vaibhav Devmurari882bd9b2022-06-23 14:54:54 +00003872 // Touch down on the first window
Prabir Pradhan678438e2023-04-13 19:32:51 +00003873 mDispatcher->notifyMotion(generateTouchArgs(AMOTION_EVENT_ACTION_DOWN, {{50, 50}}));
Vaibhav Devmurari882bd9b2022-06-23 14:54:54 +00003874 mDispatcher->waitForIdle();
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07003875
Prabir Pradhan9d5f9ce2024-01-24 00:03:41 +00003876 const std::unique_ptr<MotionEvent> firstDown =
3877 window1->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN)));
3878 ASSERT_EQ(firstDown->getDownTime(), firstDown->getEventTime());
Vaibhav Devmurari882bd9b2022-06-23 14:54:54 +00003879 window2->assertNoEvents();
Vaibhav Devmurari882bd9b2022-06-23 14:54:54 +00003880
3881 // Now touch down on the window with another pointer
Prabir Pradhan678438e2023-04-13 19:32:51 +00003882 mDispatcher->notifyMotion(generateTouchArgs(POINTER_1_DOWN, {{50, 50}, {150, 50}}));
Vaibhav Devmurari882bd9b2022-06-23 14:54:54 +00003883 mDispatcher->waitForIdle();
Prabir Pradhan9d5f9ce2024-01-24 00:03:41 +00003884
3885 const std::unique_ptr<MotionEvent> secondDown =
3886 window2->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN)));
3887 ASSERT_EQ(secondDown->getDownTime(), secondDown->getEventTime());
3888 ASSERT_NE(firstDown->getDownTime(), secondDown->getDownTime());
3889 // We currently send MOVE events to all windows receiving a split touch when there is any change
3890 // in the touch state, even when none of the pointers in the split window actually moved.
3891 // Document this behavior in the test.
3892 window1->consumeMotionMove();
Vaibhav Devmurari882bd9b2022-06-23 14:54:54 +00003893
3894 // Now move the pointer on the second window
Prabir Pradhan678438e2023-04-13 19:32:51 +00003895 mDispatcher->notifyMotion(generateTouchArgs(AMOTION_EVENT_ACTION_MOVE, {{50, 50}, {151, 51}}));
Vaibhav Devmurari882bd9b2022-06-23 14:54:54 +00003896 mDispatcher->waitForIdle();
Prabir Pradhan9d5f9ce2024-01-24 00:03:41 +00003897
3898 window2->consumeMotionEvent(WithDownTime(secondDown->getDownTime()));
3899 window1->consumeMotionEvent(WithDownTime(firstDown->getDownTime()));
Vaibhav Devmurari882bd9b2022-06-23 14:54:54 +00003900
3901 // Now add new touch down on the second window
Prabir Pradhan678438e2023-04-13 19:32:51 +00003902 mDispatcher->notifyMotion(generateTouchArgs(POINTER_2_DOWN, {{50, 50}, {151, 51}, {150, 50}}));
Vaibhav Devmurari882bd9b2022-06-23 14:54:54 +00003903 mDispatcher->waitForIdle();
Vaibhav Devmurari882bd9b2022-06-23 14:54:54 +00003904
Prabir Pradhan9d5f9ce2024-01-24 00:03:41 +00003905 window2->consumeMotionEvent(
3906 AllOf(WithMotionAction(POINTER_1_DOWN), WithDownTime(secondDown->getDownTime())));
3907 window1->consumeMotionEvent(WithDownTime(firstDown->getDownTime()));
Vaibhav Devmurari882bd9b2022-06-23 14:54:54 +00003908
3909 // Now move the pointer on the first window
Prabir Pradhan678438e2023-04-13 19:32:51 +00003910 mDispatcher->notifyMotion(
3911 generateTouchArgs(AMOTION_EVENT_ACTION_MOVE, {{51, 51}, {151, 51}, {150, 50}}));
Vaibhav Devmurari882bd9b2022-06-23 14:54:54 +00003912 mDispatcher->waitForIdle();
Vaibhav Devmurari882bd9b2022-06-23 14:54:54 +00003913
Prabir Pradhan9d5f9ce2024-01-24 00:03:41 +00003914 window1->consumeMotionEvent(WithDownTime(firstDown->getDownTime()));
3915 window2->consumeMotionEvent(WithDownTime(secondDown->getDownTime()));
3916
3917 // Now add new touch down on the first window
Prabir Pradhan678438e2023-04-13 19:32:51 +00003918 mDispatcher->notifyMotion(
3919 generateTouchArgs(POINTER_3_DOWN, {{51, 51}, {151, 51}, {150, 50}, {50, 50}}));
Vaibhav Devmurari882bd9b2022-06-23 14:54:54 +00003920 mDispatcher->waitForIdle();
Prabir Pradhan9d5f9ce2024-01-24 00:03:41 +00003921
3922 window1->consumeMotionEvent(
3923 AllOf(WithMotionAction(POINTER_1_DOWN), WithDownTime(firstDown->getDownTime())));
3924 window2->consumeMotionEvent(WithDownTime(secondDown->getDownTime()));
Vaibhav Devmurari882bd9b2022-06-23 14:54:54 +00003925}
3926
Garfield Tandf26e862020-07-01 20:18:19 -07003927TEST_F(InputDispatcherTest, HoverMoveEnterMouseClickAndHoverMoveExit) {
Chris Yea209fde2020-07-22 13:54:51 -07003928 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
Garfield Tandf26e862020-07-01 20:18:19 -07003929 sp<FakeWindowHandle> windowLeft =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07003930 sp<FakeWindowHandle>::make(application, mDispatcher, "Left", ADISPLAY_ID_DEFAULT);
Garfield Tandf26e862020-07-01 20:18:19 -07003931 windowLeft->setFrame(Rect(0, 0, 600, 800));
Garfield Tandf26e862020-07-01 20:18:19 -07003932 sp<FakeWindowHandle> windowRight =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07003933 sp<FakeWindowHandle>::make(application, mDispatcher, "Right", ADISPLAY_ID_DEFAULT);
Garfield Tandf26e862020-07-01 20:18:19 -07003934 windowRight->setFrame(Rect(600, 0, 1200, 800));
Garfield Tandf26e862020-07-01 20:18:19 -07003935
3936 mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application);
3937
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07003938 mDispatcher->onWindowInfosChanged(
3939 {{*windowLeft->getInfo(), *windowRight->getInfo()}, {}, 0, 0});
Garfield Tandf26e862020-07-01 20:18:19 -07003940
3941 // Start cursor position in right window so that we can move the cursor to left window.
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08003942 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07003943 injectMotionEvent(*mDispatcher,
Garfield Tandf26e862020-07-01 20:18:19 -07003944 MotionEventBuilder(AMOTION_EVENT_ACTION_HOVER_MOVE,
3945 AINPUT_SOURCE_MOUSE)
Siarhei Vishniakou6d73f832022-07-21 17:27:03 -07003946 .pointer(PointerBuilder(0, ToolType::MOUSE).x(900).y(400))
Garfield Tandf26e862020-07-01 20:18:19 -07003947 .build()));
Siarhei Vishniakou5cee1e32022-11-29 12:35:39 -08003948 windowRight->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_ENTER));
Garfield Tandf26e862020-07-01 20:18:19 -07003949
3950 // Move cursor into left window
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08003951 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07003952 injectMotionEvent(*mDispatcher,
Garfield Tandf26e862020-07-01 20:18:19 -07003953 MotionEventBuilder(AMOTION_EVENT_ACTION_HOVER_MOVE,
3954 AINPUT_SOURCE_MOUSE)
Siarhei Vishniakou6d73f832022-07-21 17:27:03 -07003955 .pointer(PointerBuilder(0, ToolType::MOUSE).x(300).y(400))
Garfield Tandf26e862020-07-01 20:18:19 -07003956 .build()));
Siarhei Vishniakou5cee1e32022-11-29 12:35:39 -08003957 windowRight->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_EXIT));
3958 windowLeft->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_ENTER));
Garfield Tandf26e862020-07-01 20:18:19 -07003959
3960 // Inject a series of mouse events for a mouse click
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08003961 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07003962 injectMotionEvent(*mDispatcher,
Garfield Tandf26e862020-07-01 20:18:19 -07003963 MotionEventBuilder(AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_MOUSE)
3964 .buttonState(AMOTION_EVENT_BUTTON_PRIMARY)
Siarhei Vishniakou6d73f832022-07-21 17:27:03 -07003965 .pointer(PointerBuilder(0, ToolType::MOUSE).x(300).y(400))
Garfield Tandf26e862020-07-01 20:18:19 -07003966 .build()));
Siarhei Vishniakouf372b812023-02-14 18:06:51 -08003967 windowLeft->consumeMotionEvent(WithMotionAction(ACTION_HOVER_EXIT));
3968 windowLeft->consumeMotionEvent(WithMotionAction(ACTION_DOWN));
Garfield Tandf26e862020-07-01 20:18:19 -07003969
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08003970 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07003971 injectMotionEvent(*mDispatcher,
Garfield Tandf26e862020-07-01 20:18:19 -07003972 MotionEventBuilder(AMOTION_EVENT_ACTION_BUTTON_PRESS,
3973 AINPUT_SOURCE_MOUSE)
3974 .buttonState(AMOTION_EVENT_BUTTON_PRIMARY)
3975 .actionButton(AMOTION_EVENT_BUTTON_PRIMARY)
Siarhei Vishniakou6d73f832022-07-21 17:27:03 -07003976 .pointer(PointerBuilder(0, ToolType::MOUSE).x(300).y(400))
Garfield Tandf26e862020-07-01 20:18:19 -07003977 .build()));
Siarhei Vishniakou5cee1e32022-11-29 12:35:39 -08003978 windowLeft->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_BUTTON_PRESS));
Garfield Tandf26e862020-07-01 20:18:19 -07003979
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08003980 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07003981 injectMotionEvent(*mDispatcher,
Garfield Tandf26e862020-07-01 20:18:19 -07003982 MotionEventBuilder(AMOTION_EVENT_ACTION_BUTTON_RELEASE,
3983 AINPUT_SOURCE_MOUSE)
3984 .buttonState(0)
3985 .actionButton(AMOTION_EVENT_BUTTON_PRIMARY)
Siarhei Vishniakou6d73f832022-07-21 17:27:03 -07003986 .pointer(PointerBuilder(0, ToolType::MOUSE).x(300).y(400))
Garfield Tandf26e862020-07-01 20:18:19 -07003987 .build()));
Siarhei Vishniakou5cee1e32022-11-29 12:35:39 -08003988 windowLeft->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_BUTTON_RELEASE));
Garfield Tandf26e862020-07-01 20:18:19 -07003989
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08003990 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07003991 injectMotionEvent(*mDispatcher,
Garfield Tandf26e862020-07-01 20:18:19 -07003992 MotionEventBuilder(AMOTION_EVENT_ACTION_UP, AINPUT_SOURCE_MOUSE)
3993 .buttonState(0)
Siarhei Vishniakou6d73f832022-07-21 17:27:03 -07003994 .pointer(PointerBuilder(0, ToolType::MOUSE).x(300).y(400))
Garfield Tandf26e862020-07-01 20:18:19 -07003995 .build()));
3996 windowLeft->consumeMotionUp(ADISPLAY_ID_DEFAULT);
3997
3998 // Move mouse cursor back to right window
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08003999 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07004000 injectMotionEvent(*mDispatcher,
Garfield Tandf26e862020-07-01 20:18:19 -07004001 MotionEventBuilder(AMOTION_EVENT_ACTION_HOVER_MOVE,
4002 AINPUT_SOURCE_MOUSE)
Siarhei Vishniakou6d73f832022-07-21 17:27:03 -07004003 .pointer(PointerBuilder(0, ToolType::MOUSE).x(900).y(400))
Garfield Tandf26e862020-07-01 20:18:19 -07004004 .build()));
Siarhei Vishniakou5cee1e32022-11-29 12:35:39 -08004005 windowRight->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_ENTER));
Siarhei Vishniakou5cee1e32022-11-29 12:35:39 -08004006
4007 // No more events
4008 windowLeft->assertNoEvents();
4009 windowRight->assertNoEvents();
4010}
4011
Siarhei Vishniakouf372b812023-02-14 18:06:51 -08004012/**
4013 * Put two fingers down (and don't release them) and click the mouse button.
4014 * The clicking of mouse is a new ACTION_DOWN event. Since it's from a different device, the
4015 * currently active gesture should be canceled, and the new one should proceed.
4016 */
4017TEST_F(InputDispatcherTest, TwoPointersDownMouseClick) {
4018 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
4019 sp<FakeWindowHandle> window =
4020 sp<FakeWindowHandle>::make(application, mDispatcher, "Window", ADISPLAY_ID_DEFAULT);
4021 window->setFrame(Rect(0, 0, 600, 800));
4022
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07004023 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Siarhei Vishniakouf372b812023-02-14 18:06:51 -08004024
4025 const int32_t touchDeviceId = 4;
4026 const int32_t mouseDeviceId = 6;
Siarhei Vishniakouf372b812023-02-14 18:06:51 -08004027
4028 // Two pointers down
Prabir Pradhan678438e2023-04-13 19:32:51 +00004029 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
4030 .deviceId(touchDeviceId)
4031 .pointer(PointerBuilder(0, ToolType::FINGER).x(100).y(100))
4032 .build());
Siarhei Vishniakouf372b812023-02-14 18:06:51 -08004033
Prabir Pradhan678438e2023-04-13 19:32:51 +00004034 mDispatcher->notifyMotion(MotionArgsBuilder(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
4035 .deviceId(touchDeviceId)
4036 .pointer(PointerBuilder(0, ToolType::FINGER).x(100).y(100))
4037 .pointer(PointerBuilder(1, ToolType::FINGER).x(120).y(120))
4038 .build());
Siarhei Vishniakouf372b812023-02-14 18:06:51 -08004039 window->consumeMotionEvent(WithMotionAction(ACTION_DOWN));
4040 window->consumeMotionEvent(WithMotionAction(POINTER_1_DOWN));
4041
4042 // Inject a series of mouse events for a mouse click
Prabir Pradhan678438e2023-04-13 19:32:51 +00004043 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_MOUSE)
4044 .deviceId(mouseDeviceId)
4045 .buttonState(AMOTION_EVENT_BUTTON_PRIMARY)
4046 .pointer(PointerBuilder(0, ToolType::MOUSE).x(300).y(400))
4047 .build());
Siarhei Vishniakouf372b812023-02-14 18:06:51 -08004048 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_CANCEL), WithDeviceId(touchDeviceId),
4049 WithPointerCount(2u)));
4050 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(mouseDeviceId)));
4051
Prabir Pradhan678438e2023-04-13 19:32:51 +00004052 mDispatcher->notifyMotion(
4053 MotionArgsBuilder(AMOTION_EVENT_ACTION_BUTTON_PRESS, AINPUT_SOURCE_MOUSE)
4054 .deviceId(mouseDeviceId)
4055 .buttonState(AMOTION_EVENT_BUTTON_PRIMARY)
4056 .actionButton(AMOTION_EVENT_BUTTON_PRIMARY)
4057 .pointer(PointerBuilder(0, ToolType::MOUSE).x(300).y(400))
4058 .build());
Siarhei Vishniakouf372b812023-02-14 18:06:51 -08004059 window->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_BUTTON_PRESS));
4060
4061 // Try to send more touch events while the mouse is down. Since it's a continuation of an
4062 // already canceled gesture, it should be ignored.
Prabir Pradhan678438e2023-04-13 19:32:51 +00004063 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN)
4064 .deviceId(touchDeviceId)
4065 .pointer(PointerBuilder(0, ToolType::FINGER).x(101).y(101))
4066 .pointer(PointerBuilder(1, ToolType::FINGER).x(121).y(121))
4067 .build());
Siarhei Vishniakouf372b812023-02-14 18:06:51 -08004068 window->assertNoEvents();
4069}
4070
Siarhei Vishniakou5cee1e32022-11-29 12:35:39 -08004071TEST_F(InputDispatcherTest, HoverWithSpyWindows) {
4072 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
4073
4074 sp<FakeWindowHandle> spyWindow =
4075 sp<FakeWindowHandle>::make(application, mDispatcher, "Spy", ADISPLAY_ID_DEFAULT);
4076 spyWindow->setFrame(Rect(0, 0, 600, 800));
4077 spyWindow->setTrustedOverlay(true);
4078 spyWindow->setSpy(true);
4079 sp<FakeWindowHandle> window =
4080 sp<FakeWindowHandle>::make(application, mDispatcher, "Window", ADISPLAY_ID_DEFAULT);
4081 window->setFrame(Rect(0, 0, 600, 800));
4082
4083 mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07004084 mDispatcher->onWindowInfosChanged({{*spyWindow->getInfo(), *window->getInfo()}, {}, 0, 0});
Siarhei Vishniakou5cee1e32022-11-29 12:35:39 -08004085
4086 // Send mouse cursor to the window
4087 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07004088 injectMotionEvent(*mDispatcher,
Siarhei Vishniakou5cee1e32022-11-29 12:35:39 -08004089 MotionEventBuilder(AMOTION_EVENT_ACTION_HOVER_ENTER,
4090 AINPUT_SOURCE_MOUSE)
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07004091 .pointer(PointerBuilder(0, ToolType::MOUSE).x(100).y(100))
Siarhei Vishniakou5cee1e32022-11-29 12:35:39 -08004092 .build()));
4093
4094 window->consumeMotionEvent(AllOf(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_ENTER),
4095 WithSource(AINPUT_SOURCE_MOUSE)));
4096 spyWindow->consumeMotionEvent(AllOf(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_ENTER),
4097 WithSource(AINPUT_SOURCE_MOUSE)));
4098
4099 window->assertNoEvents();
4100 spyWindow->assertNoEvents();
Garfield Tandf26e862020-07-01 20:18:19 -07004101}
4102
Siarhei Vishniakou060f82b2023-01-27 06:39:14 -08004103TEST_F(InputDispatcherTest, MouseAndTouchWithSpyWindows) {
4104 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
4105
4106 sp<FakeWindowHandle> spyWindow =
4107 sp<FakeWindowHandle>::make(application, mDispatcher, "Spy", ADISPLAY_ID_DEFAULT);
4108 spyWindow->setFrame(Rect(0, 0, 600, 800));
4109 spyWindow->setTrustedOverlay(true);
4110 spyWindow->setSpy(true);
4111 sp<FakeWindowHandle> window =
4112 sp<FakeWindowHandle>::make(application, mDispatcher, "Window", ADISPLAY_ID_DEFAULT);
4113 window->setFrame(Rect(0, 0, 600, 800));
4114
4115 mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07004116 mDispatcher->onWindowInfosChanged({{*spyWindow->getInfo(), *window->getInfo()}, {}, 0, 0});
Siarhei Vishniakou060f82b2023-01-27 06:39:14 -08004117
4118 // Send mouse cursor to the window
4119 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07004120 injectMotionEvent(*mDispatcher,
Siarhei Vishniakou060f82b2023-01-27 06:39:14 -08004121 MotionEventBuilder(AMOTION_EVENT_ACTION_HOVER_ENTER,
4122 AINPUT_SOURCE_MOUSE)
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07004123 .pointer(PointerBuilder(0, ToolType::MOUSE).x(100).y(100))
Siarhei Vishniakou060f82b2023-01-27 06:39:14 -08004124 .build()));
4125
4126 // Move mouse cursor
4127 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07004128 injectMotionEvent(*mDispatcher,
Siarhei Vishniakou060f82b2023-01-27 06:39:14 -08004129 MotionEventBuilder(AMOTION_EVENT_ACTION_HOVER_MOVE,
4130 AINPUT_SOURCE_MOUSE)
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07004131 .pointer(PointerBuilder(0, ToolType::MOUSE).x(110).y(110))
Siarhei Vishniakou060f82b2023-01-27 06:39:14 -08004132 .build()));
4133
4134 window->consumeMotionEvent(AllOf(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_ENTER),
4135 WithSource(AINPUT_SOURCE_MOUSE)));
4136 spyWindow->consumeMotionEvent(AllOf(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_ENTER),
4137 WithSource(AINPUT_SOURCE_MOUSE)));
4138 window->consumeMotionEvent(AllOf(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_MOVE),
4139 WithSource(AINPUT_SOURCE_MOUSE)));
4140 spyWindow->consumeMotionEvent(AllOf(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_MOVE),
4141 WithSource(AINPUT_SOURCE_MOUSE)));
4142 // Touch down on the window
4143 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07004144 injectMotionEvent(*mDispatcher,
Siarhei Vishniakou060f82b2023-01-27 06:39:14 -08004145 MotionEventBuilder(AMOTION_EVENT_ACTION_DOWN,
4146 AINPUT_SOURCE_TOUCHSCREEN)
4147 .deviceId(SECOND_DEVICE_ID)
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07004148 .pointer(PointerBuilder(0, ToolType::FINGER).x(200).y(200))
Siarhei Vishniakou060f82b2023-01-27 06:39:14 -08004149 .build()));
4150 window->consumeMotionEvent(AllOf(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_EXIT),
4151 WithSource(AINPUT_SOURCE_MOUSE)));
4152 spyWindow->consumeMotionEvent(AllOf(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_EXIT),
4153 WithSource(AINPUT_SOURCE_MOUSE)));
4154 window->consumeMotionEvent(AllOf(WithMotionAction(AMOTION_EVENT_ACTION_DOWN),
4155 WithSource(AINPUT_SOURCE_TOUCHSCREEN)));
4156 spyWindow->consumeMotionEvent(AllOf(WithMotionAction(AMOTION_EVENT_ACTION_DOWN),
4157 WithSource(AINPUT_SOURCE_TOUCHSCREEN)));
4158
4159 // pilfer the motion, retaining the gesture on the spy window.
4160 EXPECT_EQ(OK, mDispatcher->pilferPointers(spyWindow->getToken()));
4161 window->consumeMotionEvent(AllOf(WithMotionAction(AMOTION_EVENT_ACTION_CANCEL),
4162 WithSource(AINPUT_SOURCE_TOUCHSCREEN)));
4163
4164 // Touch UP on the window
4165 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07004166 injectMotionEvent(*mDispatcher,
Siarhei Vishniakou060f82b2023-01-27 06:39:14 -08004167 MotionEventBuilder(AMOTION_EVENT_ACTION_UP,
4168 AINPUT_SOURCE_TOUCHSCREEN)
4169 .deviceId(SECOND_DEVICE_ID)
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07004170 .pointer(PointerBuilder(0, ToolType::FINGER).x(200).y(200))
Siarhei Vishniakou060f82b2023-01-27 06:39:14 -08004171 .build()));
4172 spyWindow->consumeMotionEvent(AllOf(WithMotionAction(AMOTION_EVENT_ACTION_UP),
4173 WithSource(AINPUT_SOURCE_TOUCHSCREEN)));
4174
4175 // Previously, a touch was pilfered. However, that gesture was just finished. Now, we are going
4176 // to send a new gesture. It should again go to both windows (spy and the window below), just
4177 // like the first gesture did, before pilfering. The window configuration has not changed.
4178
4179 // One more tap - DOWN
4180 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07004181 injectMotionEvent(*mDispatcher,
Siarhei Vishniakou060f82b2023-01-27 06:39:14 -08004182 MotionEventBuilder(AMOTION_EVENT_ACTION_DOWN,
4183 AINPUT_SOURCE_TOUCHSCREEN)
4184 .deviceId(SECOND_DEVICE_ID)
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07004185 .pointer(PointerBuilder(0, ToolType::FINGER).x(250).y(250))
Siarhei Vishniakou060f82b2023-01-27 06:39:14 -08004186 .build()));
4187 window->consumeMotionEvent(AllOf(WithMotionAction(AMOTION_EVENT_ACTION_DOWN),
4188 WithSource(AINPUT_SOURCE_TOUCHSCREEN)));
4189 spyWindow->consumeMotionEvent(AllOf(WithMotionAction(AMOTION_EVENT_ACTION_DOWN),
4190 WithSource(AINPUT_SOURCE_TOUCHSCREEN)));
4191
4192 // Touch UP on the window
4193 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07004194 injectMotionEvent(*mDispatcher,
Siarhei Vishniakou060f82b2023-01-27 06:39:14 -08004195 MotionEventBuilder(AMOTION_EVENT_ACTION_UP,
4196 AINPUT_SOURCE_TOUCHSCREEN)
4197 .deviceId(SECOND_DEVICE_ID)
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07004198 .pointer(PointerBuilder(0, ToolType::FINGER).x(250).y(250))
Siarhei Vishniakou060f82b2023-01-27 06:39:14 -08004199 .build()));
4200 window->consumeMotionEvent(AllOf(WithMotionAction(AMOTION_EVENT_ACTION_UP),
4201 WithSource(AINPUT_SOURCE_TOUCHSCREEN)));
4202 spyWindow->consumeMotionEvent(AllOf(WithMotionAction(AMOTION_EVENT_ACTION_UP),
4203 WithSource(AINPUT_SOURCE_TOUCHSCREEN)));
4204
4205 window->assertNoEvents();
4206 spyWindow->assertNoEvents();
4207}
4208
Garfield Tandf26e862020-07-01 20:18:19 -07004209// This test is different from the test above that HOVER_ENTER and HOVER_EXIT events are injected
4210// directly in this test.
4211TEST_F(InputDispatcherTest, HoverEnterMouseClickAndHoverExit) {
Chris Yea209fde2020-07-22 13:54:51 -07004212 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
Garfield Tandf26e862020-07-01 20:18:19 -07004213 sp<FakeWindowHandle> window =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07004214 sp<FakeWindowHandle>::make(application, mDispatcher, "Window", ADISPLAY_ID_DEFAULT);
Garfield Tandf26e862020-07-01 20:18:19 -07004215 window->setFrame(Rect(0, 0, 1200, 800));
Garfield Tandf26e862020-07-01 20:18:19 -07004216
4217 mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application);
4218
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07004219 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Garfield Tandf26e862020-07-01 20:18:19 -07004220
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08004221 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07004222 injectMotionEvent(*mDispatcher,
Garfield Tandf26e862020-07-01 20:18:19 -07004223 MotionEventBuilder(AMOTION_EVENT_ACTION_HOVER_ENTER,
4224 AINPUT_SOURCE_MOUSE)
Siarhei Vishniakou6d73f832022-07-21 17:27:03 -07004225 .pointer(PointerBuilder(0, ToolType::MOUSE).x(300).y(400))
Garfield Tandf26e862020-07-01 20:18:19 -07004226 .build()));
Siarhei Vishniakou5cee1e32022-11-29 12:35:39 -08004227 window->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_ENTER));
Garfield Tandf26e862020-07-01 20:18:19 -07004228 // Inject a series of mouse events for a mouse click
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08004229 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07004230 injectMotionEvent(*mDispatcher,
Garfield Tandf26e862020-07-01 20:18:19 -07004231 MotionEventBuilder(AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_MOUSE)
4232 .buttonState(AMOTION_EVENT_BUTTON_PRIMARY)
Siarhei Vishniakou6d73f832022-07-21 17:27:03 -07004233 .pointer(PointerBuilder(0, ToolType::MOUSE).x(300).y(400))
Garfield Tandf26e862020-07-01 20:18:19 -07004234 .build()));
Siarhei Vishniakouf372b812023-02-14 18:06:51 -08004235 window->consumeMotionEvent(WithMotionAction(ACTION_HOVER_EXIT));
4236 window->consumeMotionEvent(WithMotionAction(ACTION_DOWN));
Garfield Tandf26e862020-07-01 20:18:19 -07004237
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08004238 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07004239 injectMotionEvent(*mDispatcher,
Garfield Tandf26e862020-07-01 20:18:19 -07004240 MotionEventBuilder(AMOTION_EVENT_ACTION_BUTTON_PRESS,
4241 AINPUT_SOURCE_MOUSE)
4242 .buttonState(AMOTION_EVENT_BUTTON_PRIMARY)
4243 .actionButton(AMOTION_EVENT_BUTTON_PRIMARY)
Siarhei Vishniakou6d73f832022-07-21 17:27:03 -07004244 .pointer(PointerBuilder(0, ToolType::MOUSE).x(300).y(400))
Garfield Tandf26e862020-07-01 20:18:19 -07004245 .build()));
Siarhei Vishniakou5cee1e32022-11-29 12:35:39 -08004246 window->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_BUTTON_PRESS));
Garfield Tandf26e862020-07-01 20:18:19 -07004247
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08004248 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07004249 injectMotionEvent(*mDispatcher,
Garfield Tandf26e862020-07-01 20:18:19 -07004250 MotionEventBuilder(AMOTION_EVENT_ACTION_BUTTON_RELEASE,
4251 AINPUT_SOURCE_MOUSE)
4252 .buttonState(0)
4253 .actionButton(AMOTION_EVENT_BUTTON_PRIMARY)
Siarhei Vishniakou6d73f832022-07-21 17:27:03 -07004254 .pointer(PointerBuilder(0, ToolType::MOUSE).x(300).y(400))
Garfield Tandf26e862020-07-01 20:18:19 -07004255 .build()));
Siarhei Vishniakou5cee1e32022-11-29 12:35:39 -08004256 window->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_BUTTON_RELEASE));
Garfield Tandf26e862020-07-01 20:18:19 -07004257
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08004258 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07004259 injectMotionEvent(*mDispatcher,
Garfield Tandf26e862020-07-01 20:18:19 -07004260 MotionEventBuilder(AMOTION_EVENT_ACTION_UP, AINPUT_SOURCE_MOUSE)
4261 .buttonState(0)
Siarhei Vishniakou6d73f832022-07-21 17:27:03 -07004262 .pointer(PointerBuilder(0, ToolType::MOUSE).x(300).y(400))
Garfield Tandf26e862020-07-01 20:18:19 -07004263 .build()));
4264 window->consumeMotionUp(ADISPLAY_ID_DEFAULT);
4265
Siarhei Vishniakoua235c042023-05-02 09:59:09 -07004266 // We already canceled the hovering implicitly by injecting the "DOWN" event without lifting the
4267 // hover first. Therefore, injection of HOVER_EXIT is inconsistent, and should fail.
4268 ASSERT_EQ(InputEventInjectionResult::FAILED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07004269 injectMotionEvent(*mDispatcher,
Garfield Tandf26e862020-07-01 20:18:19 -07004270 MotionEventBuilder(AMOTION_EVENT_ACTION_HOVER_EXIT,
4271 AINPUT_SOURCE_MOUSE)
Siarhei Vishniakou6d73f832022-07-21 17:27:03 -07004272 .pointer(PointerBuilder(0, ToolType::MOUSE).x(300).y(400))
Garfield Tandf26e862020-07-01 20:18:19 -07004273 .build()));
Siarhei Vishniakouf372b812023-02-14 18:06:51 -08004274 window->assertNoEvents();
Garfield Tandf26e862020-07-01 20:18:19 -07004275}
4276
Siarhei Vishniakou0b0374d2022-11-17 17:40:53 -08004277/**
Siarhei Vishniakoub581f7f2022-12-07 20:23:06 +00004278 * Hover over a window, and then remove that window. Make sure that HOVER_EXIT for that event
4279 * is generated.
4280 */
4281TEST_F(InputDispatcherTest, HoverExitIsSentToRemovedWindow) {
4282 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
4283 sp<FakeWindowHandle> window =
4284 sp<FakeWindowHandle>::make(application, mDispatcher, "Window", ADISPLAY_ID_DEFAULT);
4285 window->setFrame(Rect(0, 0, 1200, 800));
4286
4287 mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application);
4288
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07004289 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Siarhei Vishniakoub581f7f2022-12-07 20:23:06 +00004290
4291 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07004292 injectMotionEvent(*mDispatcher,
Siarhei Vishniakoub581f7f2022-12-07 20:23:06 +00004293 MotionEventBuilder(AMOTION_EVENT_ACTION_HOVER_ENTER,
4294 AINPUT_SOURCE_MOUSE)
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07004295 .pointer(PointerBuilder(0, ToolType::MOUSE).x(300).y(400))
Siarhei Vishniakoub581f7f2022-12-07 20:23:06 +00004296 .build()));
4297 window->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_ENTER));
4298
4299 // Remove the window, but keep the channel.
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07004300 mDispatcher->onWindowInfosChanged({{}, {}, 0, 0});
Siarhei Vishniakoub581f7f2022-12-07 20:23:06 +00004301 window->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_EXIT));
4302}
4303
4304/**
Daniel Norman7487dfa2023-08-02 16:39:45 -07004305 * Test that invalid HOVER events sent by accessibility do not cause a fatal crash.
4306 */
Ameer Armalycff4fa52023-10-04 23:45:11 +00004307TEST_F_WITH_FLAGS(InputDispatcherTest, InvalidA11yHoverStreamDoesNotCrash,
4308 REQUIRES_FLAGS_DISABLED(ACONFIG_FLAG(com::android::input::flags,
4309 a11y_crash_on_inconsistent_event_stream))) {
Daniel Norman7487dfa2023-08-02 16:39:45 -07004310 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
4311 sp<FakeWindowHandle> window =
4312 sp<FakeWindowHandle>::make(application, mDispatcher, "Window", ADISPLAY_ID_DEFAULT);
4313 window->setFrame(Rect(0, 0, 1200, 800));
4314
4315 mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application);
4316
4317 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
4318
4319 MotionEventBuilder hoverEnterBuilder =
4320 MotionEventBuilder(AMOTION_EVENT_ACTION_HOVER_ENTER, AINPUT_SOURCE_MOUSE)
4321 .pointer(PointerBuilder(0, ToolType::MOUSE).x(300).y(400))
4322 .addFlag(AMOTION_EVENT_FLAG_IS_ACCESSIBILITY_EVENT);
4323 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
4324 injectMotionEvent(*mDispatcher, hoverEnterBuilder.build()));
4325 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
4326 injectMotionEvent(*mDispatcher, hoverEnterBuilder.build()));
4327 window->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_ENTER));
4328 window->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_ENTER));
4329}
4330
4331/**
Siarhei Vishniakou4e1ffa52023-02-21 11:50:34 -08004332 * If mouse is hovering when the touch goes down, the hovering should be stopped via HOVER_EXIT.
4333 */
4334TEST_F(InputDispatcherTest, TouchDownAfterMouseHover) {
4335 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
4336 sp<FakeWindowHandle> window =
4337 sp<FakeWindowHandle>::make(application, mDispatcher, "Window", ADISPLAY_ID_DEFAULT);
4338 window->setFrame(Rect(0, 0, 100, 100));
4339
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07004340 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Siarhei Vishniakou4e1ffa52023-02-21 11:50:34 -08004341
4342 const int32_t mouseDeviceId = 7;
4343 const int32_t touchDeviceId = 4;
Siarhei Vishniakou4e1ffa52023-02-21 11:50:34 -08004344
4345 // Start hovering with the mouse
Prabir Pradhan678438e2023-04-13 19:32:51 +00004346 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_ENTER, AINPUT_SOURCE_MOUSE)
4347 .deviceId(mouseDeviceId)
4348 .pointer(PointerBuilder(0, ToolType::MOUSE).x(10).y(10))
4349 .build());
Siarhei Vishniakou4e1ffa52023-02-21 11:50:34 -08004350 window->consumeMotionEvent(
4351 AllOf(WithMotionAction(ACTION_HOVER_ENTER), WithDeviceId(mouseDeviceId)));
4352
4353 // Touch goes down
Prabir Pradhan678438e2023-04-13 19:32:51 +00004354 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
4355 .deviceId(touchDeviceId)
4356 .pointer(PointerBuilder(0, ToolType::FINGER).x(50).y(50))
4357 .build());
Siarhei Vishniakou4e1ffa52023-02-21 11:50:34 -08004358
4359 window->consumeMotionEvent(
4360 AllOf(WithMotionAction(ACTION_HOVER_EXIT), WithDeviceId(mouseDeviceId)));
4361 window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(touchDeviceId)));
4362}
4363
4364/**
Siarhei Vishniakou0b0374d2022-11-17 17:40:53 -08004365 * Inject a mouse hover event followed by a tap from touchscreen.
Siarhei Vishniakoub581f7f2022-12-07 20:23:06 +00004366 * The tap causes a HOVER_EXIT event to be generated because the current event
4367 * stream's source has been switched.
Siarhei Vishniakou0b0374d2022-11-17 17:40:53 -08004368 */
4369TEST_F(InputDispatcherTest, MouseHoverAndTouchTap) {
4370 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
4371 sp<FakeWindowHandle> window =
4372 sp<FakeWindowHandle>::make(application, mDispatcher, "Window", ADISPLAY_ID_DEFAULT);
4373 window->setFrame(Rect(0, 0, 100, 100));
4374
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07004375 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -07004376 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_MOVE, AINPUT_SOURCE_MOUSE)
4377 .pointer(PointerBuilder(0, ToolType::MOUSE).x(50).y(50))
4378 .build());
Siarhei Vishniakou0b0374d2022-11-17 17:40:53 -08004379 ASSERT_NO_FATAL_FAILURE(
4380 window->consumeMotionEvent(AllOf(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_ENTER),
4381 WithSource(AINPUT_SOURCE_MOUSE))));
Siarhei Vishniakou0b0374d2022-11-17 17:40:53 -08004382
4383 // Tap on the window
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -07004384 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
4385 .pointer(PointerBuilder(0, ToolType::FINGER).x(10).y(10))
4386 .build());
Siarhei Vishniakou0b0374d2022-11-17 17:40:53 -08004387 ASSERT_NO_FATAL_FAILURE(
Siarhei Vishniakoub581f7f2022-12-07 20:23:06 +00004388 window->consumeMotionEvent(AllOf(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_EXIT),
4389 WithSource(AINPUT_SOURCE_MOUSE))));
4390
4391 ASSERT_NO_FATAL_FAILURE(
Siarhei Vishniakou0b0374d2022-11-17 17:40:53 -08004392 window->consumeMotionEvent(AllOf(WithMotionAction(AMOTION_EVENT_ACTION_DOWN),
4393 WithSource(AINPUT_SOURCE_TOUCHSCREEN))));
4394
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -07004395 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN)
4396 .pointer(PointerBuilder(0, ToolType::FINGER).x(10).y(10))
4397 .build());
Siarhei Vishniakou0b0374d2022-11-17 17:40:53 -08004398 ASSERT_NO_FATAL_FAILURE(
4399 window->consumeMotionEvent(AllOf(WithMotionAction(AMOTION_EVENT_ACTION_UP),
4400 WithSource(AINPUT_SOURCE_TOUCHSCREEN))));
4401}
4402
Tommy Nordgrendae9dfc2022-10-13 11:25:57 +02004403TEST_F(InputDispatcherTest, HoverEnterMoveRemoveWindowsInSecondDisplay) {
4404 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
4405 sp<FakeWindowHandle> windowDefaultDisplay =
4406 sp<FakeWindowHandle>::make(application, mDispatcher, "DefaultDisplay",
4407 ADISPLAY_ID_DEFAULT);
4408 windowDefaultDisplay->setFrame(Rect(0, 0, 600, 800));
4409 sp<FakeWindowHandle> windowSecondDisplay =
4410 sp<FakeWindowHandle>::make(application, mDispatcher, "SecondDisplay",
4411 SECOND_DISPLAY_ID);
4412 windowSecondDisplay->setFrame(Rect(0, 0, 600, 800));
4413
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07004414 mDispatcher->onWindowInfosChanged(
4415 {{*windowDefaultDisplay->getInfo(), *windowSecondDisplay->getInfo()}, {}, 0, 0});
Tommy Nordgrendae9dfc2022-10-13 11:25:57 +02004416
4417 // Set cursor position in window in default display and check that hover enter and move
4418 // events are generated.
4419 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07004420 injectMotionEvent(*mDispatcher,
Tommy Nordgrendae9dfc2022-10-13 11:25:57 +02004421 MotionEventBuilder(AMOTION_EVENT_ACTION_HOVER_MOVE,
4422 AINPUT_SOURCE_MOUSE)
4423 .displayId(ADISPLAY_ID_DEFAULT)
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07004424 .pointer(PointerBuilder(0, ToolType::MOUSE).x(300).y(600))
Tommy Nordgrendae9dfc2022-10-13 11:25:57 +02004425 .build()));
Siarhei Vishniakou5cee1e32022-11-29 12:35:39 -08004426 windowDefaultDisplay->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_ENTER));
Tommy Nordgrendae9dfc2022-10-13 11:25:57 +02004427
4428 // Remove all windows in secondary display and check that no event happens on window in
4429 // primary display.
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07004430 mDispatcher->onWindowInfosChanged({{*windowDefaultDisplay->getInfo()}, {}, 0, 0});
4431
Tommy Nordgrendae9dfc2022-10-13 11:25:57 +02004432 windowDefaultDisplay->assertNoEvents();
4433
4434 // Move cursor position in window in default display and check that only hover move
4435 // event is generated and not hover enter event.
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07004436 mDispatcher->onWindowInfosChanged(
4437 {{*windowDefaultDisplay->getInfo(), *windowSecondDisplay->getInfo()}, {}, 0, 0});
Tommy Nordgrendae9dfc2022-10-13 11:25:57 +02004438 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07004439 injectMotionEvent(*mDispatcher,
Tommy Nordgrendae9dfc2022-10-13 11:25:57 +02004440 MotionEventBuilder(AMOTION_EVENT_ACTION_HOVER_MOVE,
4441 AINPUT_SOURCE_MOUSE)
4442 .displayId(ADISPLAY_ID_DEFAULT)
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07004443 .pointer(PointerBuilder(0, ToolType::MOUSE).x(400).y(700))
Tommy Nordgrendae9dfc2022-10-13 11:25:57 +02004444 .build()));
Siarhei Vishniakou5cee1e32022-11-29 12:35:39 -08004445 windowDefaultDisplay->consumeMotionEvent(
4446 AllOf(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_MOVE),
4447 WithSource(AINPUT_SOURCE_MOUSE)));
Tommy Nordgrendae9dfc2022-10-13 11:25:57 +02004448 windowDefaultDisplay->assertNoEvents();
4449}
4450
Garfield Tan00f511d2019-06-12 16:55:40 -07004451TEST_F(InputDispatcherTest, DispatchMouseEventsUnderCursor) {
Chris Yea209fde2020-07-22 13:54:51 -07004452 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
Garfield Tan00f511d2019-06-12 16:55:40 -07004453
4454 sp<FakeWindowHandle> windowLeft =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07004455 sp<FakeWindowHandle>::make(application, mDispatcher, "Left", ADISPLAY_ID_DEFAULT);
Garfield Tan00f511d2019-06-12 16:55:40 -07004456 windowLeft->setFrame(Rect(0, 0, 600, 800));
Garfield Tan00f511d2019-06-12 16:55:40 -07004457 sp<FakeWindowHandle> windowRight =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07004458 sp<FakeWindowHandle>::make(application, mDispatcher, "Right", ADISPLAY_ID_DEFAULT);
Garfield Tan00f511d2019-06-12 16:55:40 -07004459 windowRight->setFrame(Rect(600, 0, 1200, 800));
Garfield Tan00f511d2019-06-12 16:55:40 -07004460
4461 mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application);
4462
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07004463 mDispatcher->onWindowInfosChanged(
4464 {{*windowLeft->getInfo(), *windowRight->getInfo()}, {}, 0, 0});
Garfield Tan00f511d2019-06-12 16:55:40 -07004465
4466 // Inject an event with coordinate in the area of right window, with mouse cursor in the area of
4467 // left window. This event should be dispatched to the left window.
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08004468 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07004469 injectMotionEvent(*mDispatcher, AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_MOUSE,
Siarhei Vishniakou4cb50ca2020-05-26 21:43:02 -07004470 ADISPLAY_ID_DEFAULT, {610, 400}, {599, 400}));
Siarhei Vishniakouc5ca85c2019-11-15 17:20:00 -08004471 windowLeft->consumeMotionDown(ADISPLAY_ID_DEFAULT);
Garfield Tan00f511d2019-06-12 16:55:40 -07004472 windowRight->assertNoEvents();
4473}
4474
Siarhei Vishniakou2bfa9052019-11-21 18:10:54 -08004475TEST_F(InputDispatcherTest, NotifyDeviceReset_CancelsKeyStream) {
Chris Yea209fde2020-07-22 13:54:51 -07004476 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07004477 sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher,
4478 "Fake Window", ADISPLAY_ID_DEFAULT);
Vishnu Nair47074b82020-08-14 11:54:47 -07004479 window->setFocusable(true);
Siarhei Vishniakou2bfa9052019-11-21 18:10:54 -08004480
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07004481 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Vishnu Nair958da932020-08-21 17:12:37 -07004482 setFocusedWindow(window);
4483
Siarhei Vishniakouf1035d42019-09-20 16:32:01 +01004484 window->consumeFocusEvent(true);
Siarhei Vishniakou2bfa9052019-11-21 18:10:54 -08004485
Prabir Pradhan678438e2023-04-13 19:32:51 +00004486 mDispatcher->notifyKey(generateKeyArgs(AKEY_EVENT_ACTION_DOWN, ADISPLAY_ID_DEFAULT));
Siarhei Vishniakou2bfa9052019-11-21 18:10:54 -08004487
4488 // Window should receive key down event.
4489 window->consumeKeyDown(ADISPLAY_ID_DEFAULT);
4490
4491 // When device reset happens, that key stream should be terminated with FLAG_CANCELED
4492 // on the app side.
Prabir Pradhan678438e2023-04-13 19:32:51 +00004493 mDispatcher->notifyDeviceReset({/*id=*/10, /*eventTime=*/20, DEVICE_ID});
Prabir Pradhan7662a8d2023-12-15 01:58:14 +00004494 window->consumeKeyUp(ADISPLAY_ID_DEFAULT, AKEY_EVENT_FLAG_CANCELED);
Siarhei Vishniakou2bfa9052019-11-21 18:10:54 -08004495}
4496
4497TEST_F(InputDispatcherTest, NotifyDeviceReset_CancelsMotionStream) {
Chris Yea209fde2020-07-22 13:54:51 -07004498 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07004499 sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher,
4500 "Fake Window", ADISPLAY_ID_DEFAULT);
Siarhei Vishniakou2bfa9052019-11-21 18:10:54 -08004501
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07004502 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Siarhei Vishniakou2bfa9052019-11-21 18:10:54 -08004503
Prabir Pradhan678438e2023-04-13 19:32:51 +00004504 mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_DOWN,
4505 AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT));
Siarhei Vishniakou2bfa9052019-11-21 18:10:54 -08004506
4507 // Window should receive motion down event.
4508 window->consumeMotionDown(ADISPLAY_ID_DEFAULT);
4509
4510 // When device reset happens, that motion stream should be terminated with ACTION_CANCEL
4511 // on the app side.
Prabir Pradhan678438e2023-04-13 19:32:51 +00004512 mDispatcher->notifyDeviceReset({/*id=*/10, /*eventTime=*/20, DEVICE_ID});
Siarhei Vishniakou1ae72f12023-01-29 12:55:30 -08004513 window->consumeMotionEvent(
4514 AllOf(WithMotionAction(ACTION_CANCEL), WithDisplayId(ADISPLAY_ID_DEFAULT)));
Siarhei Vishniakou2bfa9052019-11-21 18:10:54 -08004515}
4516
Siarhei Vishniakou0686f0c2023-05-02 11:56:15 -07004517TEST_F(InputDispatcherTest, NotifyDeviceResetCancelsHoveringStream) {
4518 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
4519 sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher,
4520 "Fake Window", ADISPLAY_ID_DEFAULT);
4521
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07004522 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Siarhei Vishniakou0686f0c2023-05-02 11:56:15 -07004523
4524 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_ENTER, AINPUT_SOURCE_STYLUS)
4525 .pointer(PointerBuilder(0, ToolType::STYLUS).x(10).y(10))
4526 .build());
4527
4528 window->consumeMotionEvent(WithMotionAction(ACTION_HOVER_ENTER));
4529
4530 // When device reset happens, that hover stream should be terminated with ACTION_HOVER_EXIT
4531 mDispatcher->notifyDeviceReset({/*id=*/10, /*eventTime=*/20, DEVICE_ID});
4532 window->consumeMotionEvent(WithMotionAction(ACTION_HOVER_EXIT));
4533
4534 // After the device has been reset, a new hovering stream can be sent to the window
4535 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_ENTER, AINPUT_SOURCE_STYLUS)
4536 .pointer(PointerBuilder(0, ToolType::STYLUS).x(15).y(15))
4537 .build());
4538 window->consumeMotionEvent(WithMotionAction(ACTION_HOVER_ENTER));
4539}
4540
Arthur Hung2ee6d0b2022-03-03 20:19:38 +08004541TEST_F(InputDispatcherTest, InterceptKeyByPolicy) {
4542 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07004543 sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher,
4544 "Fake Window", ADISPLAY_ID_DEFAULT);
Arthur Hung2ee6d0b2022-03-03 20:19:38 +08004545 window->setFocusable(true);
4546
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07004547 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Arthur Hung2ee6d0b2022-03-03 20:19:38 +08004548 setFocusedWindow(window);
4549
4550 window->consumeFocusEvent(true);
4551
Prabir Pradhan678438e2023-04-13 19:32:51 +00004552 const NotifyKeyArgs keyArgs = generateKeyArgs(AKEY_EVENT_ACTION_DOWN, ADISPLAY_ID_DEFAULT);
Arthur Hung2ee6d0b2022-03-03 20:19:38 +08004553 const std::chrono::milliseconds interceptKeyTimeout = 50ms;
4554 const nsecs_t injectTime = keyArgs.eventTime;
4555 mFakePolicy->setInterceptKeyTimeout(interceptKeyTimeout);
Prabir Pradhan678438e2023-04-13 19:32:51 +00004556 mDispatcher->notifyKey(keyArgs);
Arthur Hung2ee6d0b2022-03-03 20:19:38 +08004557 // The dispatching time should be always greater than or equal to intercept key timeout.
4558 window->consumeKeyDown(ADISPLAY_ID_DEFAULT);
4559 ASSERT_TRUE((systemTime(SYSTEM_TIME_MONOTONIC) - injectTime) >=
4560 std::chrono::nanoseconds(interceptKeyTimeout).count());
4561}
4562
Siarhei Vishniakouf54d2ab2023-06-09 13:23:53 -07004563/**
4564 * Keys with ACTION_UP are delivered immediately, even if a long 'intercept key timeout' is set.
4565 */
Arthur Hung2ee6d0b2022-03-03 20:19:38 +08004566TEST_F(InputDispatcherTest, InterceptKeyIfKeyUp) {
4567 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07004568 sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher,
4569 "Fake Window", ADISPLAY_ID_DEFAULT);
Arthur Hung2ee6d0b2022-03-03 20:19:38 +08004570 window->setFocusable(true);
4571
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07004572 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Arthur Hung2ee6d0b2022-03-03 20:19:38 +08004573 setFocusedWindow(window);
4574
4575 window->consumeFocusEvent(true);
4576
Prabir Pradhan678438e2023-04-13 19:32:51 +00004577 mDispatcher->notifyKey(generateKeyArgs(AKEY_EVENT_ACTION_DOWN, ADISPLAY_ID_DEFAULT));
Arthur Hung2ee6d0b2022-03-03 20:19:38 +08004578 window->consumeKeyDown(ADISPLAY_ID_DEFAULT);
Siarhei Vishniakouf54d2ab2023-06-09 13:23:53 -07004579
4580 // Set a value that's significantly larger than the default consumption timeout. If the
4581 // implementation is correct, the actual value doesn't matter; it won't slow down the test.
4582 mFakePolicy->setInterceptKeyTimeout(600ms);
4583 mDispatcher->notifyKey(generateKeyArgs(AKEY_EVENT_ACTION_UP, ADISPLAY_ID_DEFAULT));
4584 // Window should receive key event immediately when same key up.
Arthur Hung2ee6d0b2022-03-03 20:19:38 +08004585 window->consumeKeyUp(ADISPLAY_ID_DEFAULT);
4586}
4587
Prabir Pradhanc44ce4d2021-10-05 05:26:29 -07004588/**
Siarhei Vishniakou487c49b2022-12-02 15:48:57 -08004589 * Two windows. First is a regular window. Second does not overlap with the first, and has
4590 * WATCH_OUTSIDE_TOUCH.
4591 * Both windows are owned by the same UID.
4592 * Tap first window. Make sure that the second window receives ACTION_OUTSIDE with correct, non-zero
4593 * coordinates. The coordinates are not zeroed out because both windows are owned by the same UID.
4594 */
4595TEST_F(InputDispatcherTest, ActionOutsideForOwnedWindowHasValidCoordinates) {
4596 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -07004597 sp<FakeWindowHandle> window =
4598 sp<FakeWindowHandle>::make(application, mDispatcher, "Window", ADISPLAY_ID_DEFAULT);
Siarhei Vishniakou487c49b2022-12-02 15:48:57 -08004599 window->setFrame(Rect{0, 0, 100, 100});
4600
4601 sp<FakeWindowHandle> outsideWindow =
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -07004602 sp<FakeWindowHandle>::make(application, mDispatcher, "Outside Window",
Siarhei Vishniakou487c49b2022-12-02 15:48:57 -08004603 ADISPLAY_ID_DEFAULT);
4604 outsideWindow->setFrame(Rect{100, 100, 200, 200});
4605 outsideWindow->setWatchOutsideTouch(true);
4606 // outsideWindow must be above 'window' to receive ACTION_OUTSIDE events when 'window' is tapped
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07004607 mDispatcher->onWindowInfosChanged({{*outsideWindow->getInfo(), *window->getInfo()}, {}, 0, 0});
Siarhei Vishniakou487c49b2022-12-02 15:48:57 -08004608
4609 // Tap on first window.
Prabir Pradhan678438e2023-04-13 19:32:51 +00004610 mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_DOWN,
4611 AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
4612 {PointF{50, 50}}));
Siarhei Vishniakou487c49b2022-12-02 15:48:57 -08004613 window->consumeMotionDown();
4614 // The coordinates of the tap in 'outsideWindow' are relative to its top left corner.
4615 // Therefore, we should offset them by (100, 100) relative to the screen's top left corner.
4616 outsideWindow->consumeMotionEvent(
4617 AllOf(WithMotionAction(ACTION_OUTSIDE), WithCoords(-50, -50)));
Prabir Pradhan502a7252023-12-01 16:11:24 +00004618
4619 // Ensure outsideWindow doesn't get any more events for the gesture.
4620 mDispatcher->notifyMotion(generateMotionArgs(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN,
4621 ADISPLAY_ID_DEFAULT, {PointF{51, 51}}));
4622 window->consumeMotionMove();
4623 outsideWindow->assertNoEvents();
Siarhei Vishniakou487c49b2022-12-02 15:48:57 -08004624}
4625
4626/**
Prabir Pradhanb60b1dc2022-03-15 14:02:35 +00004627 * This test documents the behavior of WATCH_OUTSIDE_TOUCH. The window will get ACTION_OUTSIDE when
4628 * a another pointer causes ACTION_DOWN to be sent to another window for the first time. Only one
4629 * ACTION_OUTSIDE event is sent per gesture.
4630 */
4631TEST_F(InputDispatcherTest, ActionOutsideSentOnlyWhenAWindowIsTouched) {
4632 // There are three windows that do not overlap. `window` wants to WATCH_OUTSIDE_TOUCH.
4633 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07004634 sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher,
4635 "First Window", ADISPLAY_ID_DEFAULT);
Prabir Pradhanb60b1dc2022-03-15 14:02:35 +00004636 window->setWatchOutsideTouch(true);
4637 window->setFrame(Rect{0, 0, 100, 100});
4638 sp<FakeWindowHandle> secondWindow =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07004639 sp<FakeWindowHandle>::make(application, mDispatcher, "Second Window",
4640 ADISPLAY_ID_DEFAULT);
Prabir Pradhanb60b1dc2022-03-15 14:02:35 +00004641 secondWindow->setFrame(Rect{100, 100, 200, 200});
4642 sp<FakeWindowHandle> thirdWindow =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07004643 sp<FakeWindowHandle>::make(application, mDispatcher, "Third Window",
4644 ADISPLAY_ID_DEFAULT);
Prabir Pradhanb60b1dc2022-03-15 14:02:35 +00004645 thirdWindow->setFrame(Rect{200, 200, 300, 300});
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07004646 mDispatcher->onWindowInfosChanged(
4647 {{*window->getInfo(), *secondWindow->getInfo(), *thirdWindow->getInfo()}, {}, 0, 0});
Prabir Pradhanb60b1dc2022-03-15 14:02:35 +00004648
4649 // First pointer lands outside all windows. `window` does not get ACTION_OUTSIDE.
Prabir Pradhan678438e2023-04-13 19:32:51 +00004650 mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_DOWN,
4651 AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
4652 {PointF{-10, -10}}));
Prabir Pradhanb60b1dc2022-03-15 14:02:35 +00004653 window->assertNoEvents();
4654 secondWindow->assertNoEvents();
4655
4656 // The second pointer lands inside `secondWindow`, which should receive a DOWN event.
4657 // Now, `window` should get ACTION_OUTSIDE.
Prabir Pradhan678438e2023-04-13 19:32:51 +00004658 mDispatcher->notifyMotion(generateMotionArgs(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN,
4659 ADISPLAY_ID_DEFAULT,
4660 {PointF{-10, -10}, PointF{105, 105}}));
Siarhei Vishniakou487c49b2022-12-02 15:48:57 -08004661 const std::map<int32_t, PointF> expectedPointers{{0, PointF{-10, -10}}, {1, PointF{105, 105}}};
4662 window->consumeMotionEvent(
4663 AllOf(WithMotionAction(ACTION_OUTSIDE), WithPointers(expectedPointers)));
Prabir Pradhanb60b1dc2022-03-15 14:02:35 +00004664 secondWindow->consumeMotionDown();
4665 thirdWindow->assertNoEvents();
4666
4667 // The third pointer lands inside `thirdWindow`, which should receive a DOWN event. There is
4668 // no ACTION_OUTSIDE sent to `window` because one has already been sent for this gesture.
Prabir Pradhan678438e2023-04-13 19:32:51 +00004669 mDispatcher->notifyMotion(
4670 generateMotionArgs(POINTER_2_DOWN, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
4671 {PointF{-10, -10}, PointF{105, 105}, PointF{205, 205}}));
Prabir Pradhanb60b1dc2022-03-15 14:02:35 +00004672 window->assertNoEvents();
4673 secondWindow->consumeMotionMove();
4674 thirdWindow->consumeMotionDown();
4675}
4676
Prabir Pradhan814fe082022-07-22 20:22:18 +00004677TEST_F(InputDispatcherTest, OnWindowInfosChanged_RemoveAllWindowsOnDisplay) {
4678 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07004679 sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher,
4680 "Fake Window", ADISPLAY_ID_DEFAULT);
Prabir Pradhan814fe082022-07-22 20:22:18 +00004681 window->setFocusable(true);
4682
Patrick Williamsd828f302023-04-28 17:52:08 -05004683 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Prabir Pradhan814fe082022-07-22 20:22:18 +00004684 setFocusedWindow(window);
4685
4686 window->consumeFocusEvent(true);
4687
Prabir Pradhan678438e2023-04-13 19:32:51 +00004688 const NotifyKeyArgs keyDown = generateKeyArgs(AKEY_EVENT_ACTION_DOWN, ADISPLAY_ID_DEFAULT);
4689 const NotifyKeyArgs keyUp = generateKeyArgs(AKEY_EVENT_ACTION_UP, ADISPLAY_ID_DEFAULT);
4690 mDispatcher->notifyKey(keyDown);
4691 mDispatcher->notifyKey(keyUp);
Prabir Pradhan814fe082022-07-22 20:22:18 +00004692
4693 window->consumeKeyDown(ADISPLAY_ID_DEFAULT);
4694 window->consumeKeyUp(ADISPLAY_ID_DEFAULT);
4695
4696 // All windows are removed from the display. Ensure that we can no longer dispatch to it.
Patrick Williamsd828f302023-04-28 17:52:08 -05004697 mDispatcher->onWindowInfosChanged({{}, {}, 0, 0});
Prabir Pradhan814fe082022-07-22 20:22:18 +00004698
4699 window->consumeFocusEvent(false);
4700
Prabir Pradhan678438e2023-04-13 19:32:51 +00004701 mDispatcher->notifyKey(keyDown);
4702 mDispatcher->notifyKey(keyUp);
Prabir Pradhan814fe082022-07-22 20:22:18 +00004703 window->assertNoEvents();
4704}
4705
Arthur Hung96483742022-11-15 03:30:48 +00004706TEST_F(InputDispatcherTest, NonSplitTouchableWindowReceivesMultiTouch) {
4707 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
4708 sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher,
4709 "Fake Window", ADISPLAY_ID_DEFAULT);
4710 // Ensure window is non-split and have some transform.
4711 window->setPreventSplitting(true);
4712 window->setWindowOffset(20, 40);
Patrick Williamsd828f302023-04-28 17:52:08 -05004713 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Arthur Hung96483742022-11-15 03:30:48 +00004714
4715 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07004716 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
Arthur Hung96483742022-11-15 03:30:48 +00004717 {50, 50}))
4718 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
4719 window->consumeMotionDown(ADISPLAY_ID_DEFAULT);
4720
4721 const MotionEvent secondFingerDownEvent =
4722 MotionEventBuilder(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
4723 .displayId(ADISPLAY_ID_DEFAULT)
4724 .eventTime(systemTime(SYSTEM_TIME_MONOTONIC))
Siarhei Vishniakou6d73f832022-07-21 17:27:03 -07004725 .pointer(PointerBuilder(/*id=*/0, ToolType::FINGER).x(50).y(50))
4726 .pointer(PointerBuilder(/*id=*/1, ToolType::FINGER).x(-30).y(-50))
Arthur Hung96483742022-11-15 03:30:48 +00004727 .build();
4728 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07004729 injectMotionEvent(*mDispatcher, secondFingerDownEvent, INJECT_EVENT_TIMEOUT,
Arthur Hung96483742022-11-15 03:30:48 +00004730 InputEventInjectionSync::WAIT_FOR_RESULT))
4731 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
4732
Siarhei Vishniakoud3061ab2023-12-18 20:41:08 -08004733 std::unique_ptr<MotionEvent> event = window->consumeMotionEvent();
4734 ASSERT_NE(nullptr, event);
4735 EXPECT_EQ(POINTER_1_DOWN, event->getAction());
4736 EXPECT_EQ(70, event->getX(0)); // 50 + 20
4737 EXPECT_EQ(90, event->getY(0)); // 50 + 40
4738 EXPECT_EQ(-10, event->getX(1)); // -30 + 20
4739 EXPECT_EQ(-10, event->getY(1)); // -50 + 40
Arthur Hung96483742022-11-15 03:30:48 +00004740}
4741
Siarhei Vishniakou25537f82023-07-18 14:35:47 -07004742/**
4743 * Two windows: a splittable and a non-splittable.
4744 * The non-splittable window shouldn't receive any "incomplete" gestures.
4745 * Send the first pointer to the splittable window, and then touch the non-splittable window.
4746 * The second pointer should be dropped because the initial window is splittable, so it won't get
4747 * any pointers outside of it, and the second window is non-splittable, so it shouldn't get any
4748 * "incomplete" gestures.
4749 */
4750TEST_F(InputDispatcherTest, SplittableAndNonSplittableWindows) {
4751 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
4752 sp<FakeWindowHandle> leftWindow =
4753 sp<FakeWindowHandle>::make(application, mDispatcher, "Left splittable Window",
4754 ADISPLAY_ID_DEFAULT);
4755 leftWindow->setPreventSplitting(false);
4756 leftWindow->setFrame(Rect(0, 0, 100, 100));
4757 sp<FakeWindowHandle> rightWindow =
4758 sp<FakeWindowHandle>::make(application, mDispatcher, "Right non-splittable Window",
4759 ADISPLAY_ID_DEFAULT);
4760 rightWindow->setPreventSplitting(true);
4761 rightWindow->setFrame(Rect(100, 100, 200, 200));
4762 mDispatcher->onWindowInfosChanged(
4763 {{*leftWindow->getInfo(), *rightWindow->getInfo()}, {}, 0, 0});
4764
4765 // Touch down on left, splittable window
4766 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
4767 .pointer(PointerBuilder(0, ToolType::FINGER).x(50).y(50))
4768 .build());
4769 leftWindow->consumeMotionEvent(WithMotionAction(ACTION_DOWN));
4770
4771 mDispatcher->notifyMotion(
4772 MotionArgsBuilder(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
4773 .pointer(PointerBuilder(/*id=*/0, ToolType::FINGER).x(50).y(50))
4774 .pointer(PointerBuilder(/*id=*/1, ToolType::FINGER).x(150).y(150))
4775 .build());
4776 leftWindow->assertNoEvents();
4777 rightWindow->assertNoEvents();
4778}
4779
Harry Cuttsb166c002023-05-09 13:06:05 +00004780TEST_F(InputDispatcherTest, TouchpadThreeFingerSwipeOnlySentToTrustedOverlays) {
4781 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
4782 sp<FakeWindowHandle> window =
4783 sp<FakeWindowHandle>::make(application, mDispatcher, "Window", ADISPLAY_ID_DEFAULT);
4784 window->setFrame(Rect(0, 0, 400, 400));
4785 sp<FakeWindowHandle> trustedOverlay =
4786 sp<FakeWindowHandle>::make(application, mDispatcher, "Trusted Overlay",
4787 ADISPLAY_ID_DEFAULT);
4788 trustedOverlay->setSpy(true);
4789 trustedOverlay->setTrustedOverlay(true);
4790
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07004791 mDispatcher->onWindowInfosChanged({{*trustedOverlay->getInfo(), *window->getInfo()}, {}, 0, 0});
Harry Cuttsb166c002023-05-09 13:06:05 +00004792
4793 // Start a three-finger touchpad swipe
4794 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_MOUSE)
4795 .pointer(PointerBuilder(0, ToolType::FINGER).x(200).y(100))
4796 .classification(MotionClassification::MULTI_FINGER_SWIPE)
4797 .build());
4798 mDispatcher->notifyMotion(MotionArgsBuilder(POINTER_1_DOWN, AINPUT_SOURCE_MOUSE)
4799 .pointer(PointerBuilder(0, ToolType::FINGER).x(200).y(100))
4800 .pointer(PointerBuilder(1, ToolType::FINGER).x(250).y(100))
4801 .classification(MotionClassification::MULTI_FINGER_SWIPE)
4802 .build());
4803 mDispatcher->notifyMotion(MotionArgsBuilder(POINTER_2_DOWN, AINPUT_SOURCE_MOUSE)
4804 .pointer(PointerBuilder(0, ToolType::FINGER).x(200).y(100))
4805 .pointer(PointerBuilder(1, ToolType::FINGER).x(250).y(100))
4806 .pointer(PointerBuilder(2, ToolType::FINGER).x(300).y(100))
4807 .classification(MotionClassification::MULTI_FINGER_SWIPE)
4808 .build());
4809
4810 trustedOverlay->consumeMotionEvent(WithMotionAction(ACTION_DOWN));
4811 trustedOverlay->consumeMotionEvent(WithMotionAction(POINTER_1_DOWN));
4812 trustedOverlay->consumeMotionEvent(WithMotionAction(POINTER_2_DOWN));
4813
4814 // Move the swipe a bit
4815 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_MOUSE)
4816 .pointer(PointerBuilder(0, ToolType::FINGER).x(200).y(105))
4817 .pointer(PointerBuilder(1, ToolType::FINGER).x(250).y(105))
4818 .pointer(PointerBuilder(2, ToolType::FINGER).x(300).y(105))
4819 .classification(MotionClassification::MULTI_FINGER_SWIPE)
4820 .build());
4821
4822 trustedOverlay->consumeMotionEvent(WithMotionAction(ACTION_MOVE));
4823
4824 // End the swipe
4825 mDispatcher->notifyMotion(MotionArgsBuilder(POINTER_2_UP, AINPUT_SOURCE_MOUSE)
4826 .pointer(PointerBuilder(0, ToolType::FINGER).x(200).y(105))
4827 .pointer(PointerBuilder(1, ToolType::FINGER).x(250).y(105))
4828 .pointer(PointerBuilder(2, ToolType::FINGER).x(300).y(105))
4829 .classification(MotionClassification::MULTI_FINGER_SWIPE)
4830 .build());
4831 mDispatcher->notifyMotion(MotionArgsBuilder(POINTER_1_UP, AINPUT_SOURCE_MOUSE)
4832 .pointer(PointerBuilder(0, ToolType::FINGER).x(200).y(105))
4833 .pointer(PointerBuilder(1, ToolType::FINGER).x(250).y(105))
4834 .classification(MotionClassification::MULTI_FINGER_SWIPE)
4835 .build());
4836 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_UP, AINPUT_SOURCE_MOUSE)
4837 .pointer(PointerBuilder(0, ToolType::FINGER).x(200).y(105))
4838 .classification(MotionClassification::MULTI_FINGER_SWIPE)
4839 .build());
4840
4841 trustedOverlay->consumeMotionEvent(WithMotionAction(POINTER_2_UP));
4842 trustedOverlay->consumeMotionEvent(WithMotionAction(POINTER_1_UP));
4843 trustedOverlay->consumeMotionEvent(WithMotionAction(ACTION_UP));
4844
4845 window->assertNoEvents();
4846}
4847
4848TEST_F(InputDispatcherTest, TouchpadThreeFingerSwipeNotSentToSingleWindow) {
4849 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
4850 sp<FakeWindowHandle> window =
4851 sp<FakeWindowHandle>::make(application, mDispatcher, "Window", ADISPLAY_ID_DEFAULT);
4852 window->setFrame(Rect(0, 0, 400, 400));
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07004853 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Harry Cuttsb166c002023-05-09 13:06:05 +00004854
4855 // Start a three-finger touchpad swipe
4856 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_MOUSE)
4857 .pointer(PointerBuilder(0, ToolType::FINGER).x(200).y(100))
4858 .classification(MotionClassification::MULTI_FINGER_SWIPE)
4859 .build());
4860 mDispatcher->notifyMotion(MotionArgsBuilder(POINTER_1_DOWN, AINPUT_SOURCE_MOUSE)
4861 .pointer(PointerBuilder(0, ToolType::FINGER).x(200).y(100))
4862 .pointer(PointerBuilder(1, ToolType::FINGER).x(250).y(100))
4863 .classification(MotionClassification::MULTI_FINGER_SWIPE)
4864 .build());
4865 mDispatcher->notifyMotion(MotionArgsBuilder(POINTER_2_DOWN, AINPUT_SOURCE_MOUSE)
4866 .pointer(PointerBuilder(0, ToolType::FINGER).x(200).y(100))
4867 .pointer(PointerBuilder(1, ToolType::FINGER).x(250).y(100))
4868 .pointer(PointerBuilder(2, ToolType::FINGER).x(300).y(100))
4869 .classification(MotionClassification::MULTI_FINGER_SWIPE)
4870 .build());
4871
4872 // Move the swipe a bit
4873 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_MOUSE)
4874 .pointer(PointerBuilder(0, ToolType::FINGER).x(200).y(105))
4875 .pointer(PointerBuilder(1, ToolType::FINGER).x(250).y(105))
4876 .pointer(PointerBuilder(2, ToolType::FINGER).x(300).y(105))
4877 .classification(MotionClassification::MULTI_FINGER_SWIPE)
4878 .build());
4879
4880 // End the swipe
4881 mDispatcher->notifyMotion(MotionArgsBuilder(POINTER_2_UP, AINPUT_SOURCE_MOUSE)
4882 .pointer(PointerBuilder(0, ToolType::FINGER).x(200).y(105))
4883 .pointer(PointerBuilder(1, ToolType::FINGER).x(250).y(105))
4884 .pointer(PointerBuilder(2, ToolType::FINGER).x(300).y(105))
4885 .classification(MotionClassification::MULTI_FINGER_SWIPE)
4886 .build());
4887 mDispatcher->notifyMotion(MotionArgsBuilder(POINTER_1_UP, AINPUT_SOURCE_MOUSE)
4888 .pointer(PointerBuilder(0, ToolType::FINGER).x(200).y(105))
4889 .pointer(PointerBuilder(1, ToolType::FINGER).x(250).y(105))
4890 .classification(MotionClassification::MULTI_FINGER_SWIPE)
4891 .build());
4892 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_UP, AINPUT_SOURCE_MOUSE)
4893 .pointer(PointerBuilder(0, ToolType::FINGER).x(200).y(105))
4894 .classification(MotionClassification::MULTI_FINGER_SWIPE)
4895 .build());
4896
4897 window->assertNoEvents();
4898}
4899
Prabir Pradhanb60b1dc2022-03-15 14:02:35 +00004900/**
Siarhei Vishniakouadb9fc92023-05-26 10:46:09 -07004901 * Send a two-pointer gesture to a single window. The window's orientation changes in response to
4902 * the first pointer.
Prabir Pradhan69d00bf2023-06-23 19:55:18 +00004903 * Ensure that the second pointer and the subsequent gesture is correctly delivered to the window.
Siarhei Vishniakouadb9fc92023-05-26 10:46:09 -07004904 */
4905TEST_F(InputDispatcherTest, MultiplePointersWithRotatingWindow) {
4906 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
4907 sp<FakeWindowHandle> window =
4908 sp<FakeWindowHandle>::make(application, mDispatcher, "Window", ADISPLAY_ID_DEFAULT);
4909 window->setFrame(Rect(0, 0, 400, 400));
Siarhei Vishniakou700424c2023-07-18 17:18:42 -07004910 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Siarhei Vishniakouadb9fc92023-05-26 10:46:09 -07004911
4912 const nsecs_t baseTime = systemTime(SYSTEM_TIME_MONOTONIC);
4913 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
4914 .downTime(baseTime + 10)
4915 .eventTime(baseTime + 10)
4916 .pointer(PointerBuilder(0, ToolType::FINGER).x(100).y(100))
4917 .build());
4918
4919 window->consumeMotionEvent(WithMotionAction(ACTION_DOWN));
4920
Siarhei Vishniakouadb9fc92023-05-26 10:46:09 -07004921 // Change the transform so that the orientation is now different from original.
Siarhei Vishniakou700424c2023-07-18 17:18:42 -07004922 window->setWindowTransform(0, -1, 1, 0);
Siarhei Vishniakouadb9fc92023-05-26 10:46:09 -07004923
Siarhei Vishniakou700424c2023-07-18 17:18:42 -07004924 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Siarhei Vishniakouadb9fc92023-05-26 10:46:09 -07004925
Siarhei Vishniakouadb9fc92023-05-26 10:46:09 -07004926 mDispatcher->notifyMotion(MotionArgsBuilder(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
4927 .downTime(baseTime + 10)
4928 .eventTime(baseTime + 30)
4929 .pointer(PointerBuilder(0, ToolType::FINGER).x(100).y(100))
4930 .pointer(PointerBuilder(1, ToolType::FINGER).x(200).y(200))
4931 .build());
4932
Prabir Pradhan69d00bf2023-06-23 19:55:18 +00004933 window->consumeMotionEvent(WithMotionAction(POINTER_1_DOWN));
4934
4935 // Finish the gesture and start a new one. Ensure all events are sent to the window.
Siarhei Vishniakouadb9fc92023-05-26 10:46:09 -07004936 mDispatcher->notifyMotion(MotionArgsBuilder(POINTER_1_UP, AINPUT_SOURCE_TOUCHSCREEN)
4937 .downTime(baseTime + 10)
4938 .eventTime(baseTime + 40)
4939 .pointer(PointerBuilder(0, ToolType::FINGER).x(100).y(100))
4940 .pointer(PointerBuilder(1, ToolType::FINGER).x(200).y(200))
4941 .build());
Prabir Pradhan69d00bf2023-06-23 19:55:18 +00004942
4943 window->consumeMotionEvent(WithMotionAction(POINTER_1_UP));
4944
Siarhei Vishniakouadb9fc92023-05-26 10:46:09 -07004945 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN)
4946 .downTime(baseTime + 10)
4947 .eventTime(baseTime + 50)
4948 .pointer(PointerBuilder(0, ToolType::FINGER).x(100).y(100))
4949 .build());
4950
Prabir Pradhan69d00bf2023-06-23 19:55:18 +00004951 window->consumeMotionEvent(WithMotionAction(ACTION_UP));
4952
Siarhei Vishniakouadb9fc92023-05-26 10:46:09 -07004953 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
4954 .downTime(baseTime + 60)
4955 .eventTime(baseTime + 60)
4956 .pointer(PointerBuilder(0, ToolType::FINGER).x(40).y(40))
4957 .build());
4958
Siarhei Vishniakou700424c2023-07-18 17:18:42 -07004959 window->consumeMotionEvent(WithMotionAction(ACTION_DOWN));
Siarhei Vishniakouadb9fc92023-05-26 10:46:09 -07004960}
4961
4962/**
Hu Guo771a7692023-09-17 20:51:08 +08004963 * When there are multiple screens, such as screen projection to TV or screen recording, if the
4964 * cancel event occurs, the coordinates of the cancel event should be sent to the target screen, and
4965 * its coordinates should be converted by the transform of the windows of target screen.
4966 */
4967TEST_F(InputDispatcherTest, WhenMultiDisplayWindowSameToken_DispatchCancelToTargetDisplay) {
4968 // This case will create a window and a spy window on the default display and mirror
4969 // window on the second display. cancel event is sent through spy window pilferPointers
4970 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
4971
4972 sp<FakeWindowHandle> spyWindowDefaultDisplay =
4973 sp<FakeWindowHandle>::make(application, mDispatcher, "Spy", ADISPLAY_ID_DEFAULT);
4974 spyWindowDefaultDisplay->setTrustedOverlay(true);
4975 spyWindowDefaultDisplay->setSpy(true);
4976
4977 sp<FakeWindowHandle> windowDefaultDisplay =
4978 sp<FakeWindowHandle>::make(application, mDispatcher, "DefaultDisplay",
4979 ADISPLAY_ID_DEFAULT);
4980 windowDefaultDisplay->setWindowTransform(1, 0, 0, 1);
4981
4982 sp<FakeWindowHandle> windowSecondDisplay = windowDefaultDisplay->clone(SECOND_DISPLAY_ID);
4983 windowSecondDisplay->setWindowTransform(2, 0, 0, 2);
4984
4985 // Add the windows to the dispatcher
4986 mDispatcher->onWindowInfosChanged(
4987 {{*spyWindowDefaultDisplay->getInfo(), *windowDefaultDisplay->getInfo(),
4988 *windowSecondDisplay->getInfo()},
4989 {},
4990 0,
4991 0});
4992
4993 // Send down to ADISPLAY_ID_DEFAULT
4994 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
4995 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
4996 {100, 100}))
4997 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
4998
4999 spyWindowDefaultDisplay->consumeMotionDown();
5000 windowDefaultDisplay->consumeMotionDown();
5001
5002 EXPECT_EQ(OK, mDispatcher->pilferPointers(spyWindowDefaultDisplay->getToken()));
5003
5004 // windowDefaultDisplay gets cancel
Siarhei Vishniakoud3061ab2023-12-18 20:41:08 -08005005 std::unique_ptr<MotionEvent> event = windowDefaultDisplay->consumeMotionEvent();
5006 ASSERT_NE(nullptr, event);
5007 EXPECT_EQ(AMOTION_EVENT_ACTION_CANCEL, event->getAction());
Hu Guo771a7692023-09-17 20:51:08 +08005008
5009 // The cancel event is sent to windowDefaultDisplay of the ADISPLAY_ID_DEFAULT display, so the
5010 // coordinates of the cancel are converted by windowDefaultDisplay's transform, the x and y
5011 // coordinates are both 100, otherwise if the cancel event is sent to windowSecondDisplay of
5012 // SECOND_DISPLAY_ID, the x and y coordinates are 200
Siarhei Vishniakoud3061ab2023-12-18 20:41:08 -08005013 EXPECT_EQ(100, event->getX(0));
5014 EXPECT_EQ(100, event->getY(0));
Hu Guo771a7692023-09-17 20:51:08 +08005015}
5016
5017/**
Prabir Pradhanc44ce4d2021-10-05 05:26:29 -07005018 * Ensure the correct coordinate spaces are used by InputDispatcher.
5019 *
5020 * InputDispatcher works in the display space, so its coordinate system is relative to the display
5021 * panel. Windows get events in the window space, and get raw coordinates in the logical display
5022 * space.
5023 */
5024class InputDispatcherDisplayProjectionTest : public InputDispatcherTest {
5025public:
5026 void SetUp() override {
5027 InputDispatcherTest::SetUp();
Prabir Pradhan33e3baa2022-12-06 20:30:22 +00005028 removeAllWindowsAndDisplays();
Prabir Pradhanc44ce4d2021-10-05 05:26:29 -07005029 }
5030
5031 void addDisplayInfo(int displayId, const ui::Transform& transform) {
5032 gui::DisplayInfo info;
5033 info.displayId = displayId;
5034 info.transform = transform;
5035 mDisplayInfos.push_back(std::move(info));
Patrick Williamsd828f302023-04-28 17:52:08 -05005036 mDispatcher->onWindowInfosChanged({mWindowInfos, mDisplayInfos, 0, 0});
Prabir Pradhanc44ce4d2021-10-05 05:26:29 -07005037 }
5038
5039 void addWindow(const sp<WindowInfoHandle>& windowHandle) {
5040 mWindowInfos.push_back(*windowHandle->getInfo());
Patrick Williamsd828f302023-04-28 17:52:08 -05005041 mDispatcher->onWindowInfosChanged({mWindowInfos, mDisplayInfos, 0, 0});
Prabir Pradhanc44ce4d2021-10-05 05:26:29 -07005042 }
5043
Prabir Pradhan33e3baa2022-12-06 20:30:22 +00005044 void removeAllWindowsAndDisplays() {
5045 mDisplayInfos.clear();
5046 mWindowInfos.clear();
5047 }
5048
Prabir Pradhanc44ce4d2021-10-05 05:26:29 -07005049 // Set up a test scenario where the display has a scaled projection and there are two windows
5050 // on the display.
5051 std::pair<sp<FakeWindowHandle>, sp<FakeWindowHandle>> setupScaledDisplayScenario() {
5052 // The display has a projection that has a scale factor of 2 and 4 in the x and y directions
5053 // respectively.
5054 ui::Transform displayTransform;
5055 displayTransform.set(2, 0, 0, 4);
5056 addDisplayInfo(ADISPLAY_ID_DEFAULT, displayTransform);
5057
5058 std::shared_ptr<FakeApplicationHandle> application =
5059 std::make_shared<FakeApplicationHandle>();
5060
5061 // Add two windows to the display. Their frames are represented in the display space.
5062 sp<FakeWindowHandle> firstWindow =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07005063 sp<FakeWindowHandle>::make(application, mDispatcher, "First Window",
5064 ADISPLAY_ID_DEFAULT);
Prabir Pradhanc44ce4d2021-10-05 05:26:29 -07005065 firstWindow->setFrame(Rect(0, 0, 100, 200), displayTransform);
5066 addWindow(firstWindow);
5067
5068 sp<FakeWindowHandle> secondWindow =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07005069 sp<FakeWindowHandle>::make(application, mDispatcher, "Second Window",
5070 ADISPLAY_ID_DEFAULT);
Prabir Pradhanc44ce4d2021-10-05 05:26:29 -07005071 secondWindow->setFrame(Rect(100, 200, 200, 400), displayTransform);
5072 addWindow(secondWindow);
5073 return {std::move(firstWindow), std::move(secondWindow)};
5074 }
5075
5076private:
5077 std::vector<gui::DisplayInfo> mDisplayInfos;
5078 std::vector<gui::WindowInfo> mWindowInfos;
5079};
5080
Prabir Pradhan33e3baa2022-12-06 20:30:22 +00005081TEST_F(InputDispatcherDisplayProjectionTest, HitTestCoordinateSpaceConsistency) {
Prabir Pradhanc44ce4d2021-10-05 05:26:29 -07005082 auto [firstWindow, secondWindow] = setupScaledDisplayScenario();
5083 // Send down to the first window. The point is represented in the display space. The point is
Prabir Pradhan33e3baa2022-12-06 20:30:22 +00005084 // selected so that if the hit test was performed with the point and the bounds being in
5085 // different coordinate spaces, the event would end up in the incorrect window.
Prabir Pradhan678438e2023-04-13 19:32:51 +00005086 mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_DOWN,
5087 AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
5088 {PointF{75, 55}}));
Prabir Pradhanc44ce4d2021-10-05 05:26:29 -07005089
5090 firstWindow->consumeMotionDown();
5091 secondWindow->assertNoEvents();
5092}
5093
5094// Ensure that when a MotionEvent is injected through the InputDispatcher::injectInputEvent() API,
5095// the event should be treated as being in the logical display space.
5096TEST_F(InputDispatcherDisplayProjectionTest, InjectionInLogicalDisplaySpace) {
5097 auto [firstWindow, secondWindow] = setupScaledDisplayScenario();
5098 // Send down to the first window. The point is represented in the logical display space. The
5099 // point is selected so that if the hit test was done in logical display space, then it would
5100 // end up in the incorrect window.
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07005101 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
Prabir Pradhanc44ce4d2021-10-05 05:26:29 -07005102 PointF{75 * 2, 55 * 4});
5103
5104 firstWindow->consumeMotionDown();
5105 secondWindow->assertNoEvents();
5106}
5107
Prabir Pradhandaa2f142021-12-10 09:30:08 +00005108// Ensure that when a MotionEvent that has a custom transform is injected, the post-transformed
5109// event should be treated as being in the logical display space.
5110TEST_F(InputDispatcherDisplayProjectionTest, InjectionWithTransformInLogicalDisplaySpace) {
5111 auto [firstWindow, secondWindow] = setupScaledDisplayScenario();
5112
5113 const std::array<float, 9> matrix = {1.1, 2.2, 3.3, 4.4, 5.5, 6.6, 0.0, 0.0, 1.0};
5114 ui::Transform injectedEventTransform;
5115 injectedEventTransform.set(matrix);
5116 const vec2 expectedPoint{75, 55}; // The injected point in the logical display space.
5117 const vec2 untransformedPoint = injectedEventTransform.inverse().transform(expectedPoint);
5118
5119 MotionEvent event = MotionEventBuilder(AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
5120 .displayId(ADISPLAY_ID_DEFAULT)
5121 .eventTime(systemTime(SYSTEM_TIME_MONOTONIC))
Siarhei Vishniakou6d73f832022-07-21 17:27:03 -07005122 .pointer(PointerBuilder(/*id=*/0, ToolType::FINGER)
Prabir Pradhandaa2f142021-12-10 09:30:08 +00005123 .x(untransformedPoint.x)
5124 .y(untransformedPoint.y))
5125 .build();
5126 event.transform(matrix);
5127
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07005128 injectMotionEvent(*mDispatcher, event, INJECT_EVENT_TIMEOUT,
Prabir Pradhandaa2f142021-12-10 09:30:08 +00005129 InputEventInjectionSync::WAIT_FOR_RESULT);
5130
5131 firstWindow->consumeMotionDown();
5132 secondWindow->assertNoEvents();
5133}
5134
Prabir Pradhanc44ce4d2021-10-05 05:26:29 -07005135TEST_F(InputDispatcherDisplayProjectionTest, WindowGetsEventsInCorrectCoordinateSpace) {
5136 auto [firstWindow, secondWindow] = setupScaledDisplayScenario();
5137
5138 // Send down to the second window.
Prabir Pradhan678438e2023-04-13 19:32:51 +00005139 mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_DOWN,
5140 AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
5141 {PointF{150, 220}}));
Prabir Pradhanc44ce4d2021-10-05 05:26:29 -07005142
5143 firstWindow->assertNoEvents();
Siarhei Vishniakoud3061ab2023-12-18 20:41:08 -08005144 std::unique_ptr<MotionEvent> event = secondWindow->consumeMotionEvent();
5145 ASSERT_NE(nullptr, event);
5146 EXPECT_EQ(AMOTION_EVENT_ACTION_DOWN, event->getAction());
Prabir Pradhanc44ce4d2021-10-05 05:26:29 -07005147
5148 // Ensure that the events from the "getRaw" API are in logical display coordinates.
Siarhei Vishniakoud3061ab2023-12-18 20:41:08 -08005149 EXPECT_EQ(300, event->getRawX(0));
5150 EXPECT_EQ(880, event->getRawY(0));
Prabir Pradhanc44ce4d2021-10-05 05:26:29 -07005151
5152 // Ensure that the x and y values are in the window's coordinate space.
5153 // The left-top of the second window is at (100, 200) in display space, which is (200, 800) in
5154 // the logical display space. This will be the origin of the window space.
Siarhei Vishniakoud3061ab2023-12-18 20:41:08 -08005155 EXPECT_EQ(100, event->getX(0));
5156 EXPECT_EQ(80, event->getY(0));
Prabir Pradhanc44ce4d2021-10-05 05:26:29 -07005157}
5158
Prabir Pradhan112b1ad2023-09-21 09:53:53 +00005159TEST_F(InputDispatcherDisplayProjectionTest, CancelMotionWithCorrectCoordinates) {
5160 auto [firstWindow, secondWindow] = setupScaledDisplayScenario();
5161 // The monitor will always receive events in the logical display's coordinate space, because
5162 // it does not have a window.
Prabir Pradhanfb549072023-10-05 19:17:36 +00005163 FakeMonitorReceiver monitor{*mDispatcher, "Monitor", ADISPLAY_ID_DEFAULT};
Prabir Pradhan112b1ad2023-09-21 09:53:53 +00005164
5165 // Send down to the first window.
5166 mDispatcher->notifyMotion(generateMotionArgs(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN,
5167 ADISPLAY_ID_DEFAULT, {PointF{50, 100}}));
5168 firstWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithCoords(100, 400)));
5169 monitor.consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithCoords(100, 400)));
5170
5171 // Second pointer goes down on second window.
5172 mDispatcher->notifyMotion(generateMotionArgs(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN,
5173 ADISPLAY_ID_DEFAULT,
5174 {PointF{50, 100}, PointF{150, 220}}));
5175 secondWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithCoords(100, 80)));
5176 const std::map<int32_t, PointF> expectedMonitorPointers{{0, PointF{100, 400}},
5177 {1, PointF{300, 880}}};
5178 monitor.consumeMotionEvent(
5179 AllOf(WithMotionAction(POINTER_1_DOWN), WithPointers(expectedMonitorPointers)));
5180
5181 mDispatcher->cancelCurrentTouch();
5182
5183 firstWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_CANCEL), WithCoords(100, 400)));
5184 secondWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_CANCEL), WithCoords(100, 80)));
5185 monitor.consumeMotionEvent(
5186 AllOf(WithMotionAction(ACTION_CANCEL), WithPointers(expectedMonitorPointers)));
5187}
5188
Prabir Pradhan1c29a092023-09-21 10:29:29 +00005189TEST_F(InputDispatcherDisplayProjectionTest, SynthesizeDownWithCorrectCoordinates) {
5190 auto [firstWindow, secondWindow] = setupScaledDisplayScenario();
5191
5192 // Send down to the first window.
5193 mDispatcher->notifyMotion(generateMotionArgs(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN,
5194 ADISPLAY_ID_DEFAULT, {PointF{50, 100}}));
5195 firstWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithCoords(100, 400)));
5196
5197 // The pointer is transferred to the second window, and the second window receives it in the
5198 // correct coordinate space.
Prabir Pradhan367f3432024-02-13 23:05:58 +00005199 mDispatcher->transferTouchGesture(firstWindow->getToken(), secondWindow->getToken());
Prabir Pradhan1c29a092023-09-21 10:29:29 +00005200 firstWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_CANCEL), WithCoords(100, 400)));
5201 secondWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithCoords(-100, -400)));
5202}
5203
Prabir Pradhan0dfcac72023-10-05 20:04:21 +00005204TEST_F(InputDispatcherDisplayProjectionTest, SynthesizeHoverEnterExitWithCorrectCoordinates) {
5205 auto [firstWindow, secondWindow] = setupScaledDisplayScenario();
5206
5207 // Send hover move to the second window, and ensure it shows up as hover enter.
5208 mDispatcher->notifyMotion(generateMotionArgs(ACTION_HOVER_MOVE, AINPUT_SOURCE_STYLUS,
5209 ADISPLAY_ID_DEFAULT, {PointF{150, 220}}));
5210 secondWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_HOVER_ENTER),
5211 WithCoords(100, 80), WithRawCoords(300, 880)));
5212
5213 // Touch down at the same location and ensure a hover exit is synthesized.
5214 mDispatcher->notifyMotion(generateMotionArgs(ACTION_DOWN, AINPUT_SOURCE_STYLUS,
5215 ADISPLAY_ID_DEFAULT, {PointF{150, 220}}));
5216 secondWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_HOVER_EXIT), WithCoords(100, 80),
5217 WithRawCoords(300, 880)));
5218 secondWindow->consumeMotionEvent(
5219 AllOf(WithMotionAction(ACTION_DOWN), WithCoords(100, 80), WithRawCoords(300, 880)));
5220 secondWindow->assertNoEvents();
5221 firstWindow->assertNoEvents();
5222}
5223
Prabir Pradhan453ae732023-10-13 14:30:14 +00005224// Same as above, but while the window is being mirrored.
5225TEST_F(InputDispatcherDisplayProjectionTest,
5226 SynthesizeHoverEnterExitWithCorrectCoordinatesWhenMirrored) {
5227 auto [firstWindow, secondWindow] = setupScaledDisplayScenario();
5228
5229 const std::array<float, 9> matrix = {1.1, 2.2, 3.3, 4.4, 5.5, 6.6, 0.0, 0.0, 1.0};
5230 ui::Transform secondDisplayTransform;
5231 secondDisplayTransform.set(matrix);
5232 addDisplayInfo(SECOND_DISPLAY_ID, secondDisplayTransform);
5233
5234 sp<FakeWindowHandle> secondWindowClone = secondWindow->clone(SECOND_DISPLAY_ID);
5235 secondWindowClone->setWindowTransform(1.1, 2.2, 3.3, 4.4);
5236 addWindow(secondWindowClone);
5237
5238 // Send hover move to the second window, and ensure it shows up as hover enter.
5239 mDispatcher->notifyMotion(generateMotionArgs(ACTION_HOVER_MOVE, AINPUT_SOURCE_STYLUS,
5240 ADISPLAY_ID_DEFAULT, {PointF{150, 220}}));
5241 secondWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_HOVER_ENTER),
5242 WithCoords(100, 80), WithRawCoords(300, 880)));
5243
5244 // Touch down at the same location and ensure a hover exit is synthesized for the correct
5245 // display.
5246 mDispatcher->notifyMotion(generateMotionArgs(ACTION_DOWN, AINPUT_SOURCE_STYLUS,
5247 ADISPLAY_ID_DEFAULT, {PointF{150, 220}}));
5248 secondWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_HOVER_EXIT), WithCoords(100, 80),
5249 WithRawCoords(300, 880)));
5250 secondWindow->consumeMotionEvent(
5251 AllOf(WithMotionAction(ACTION_DOWN), WithCoords(100, 80), WithRawCoords(300, 880)));
5252 secondWindow->assertNoEvents();
5253 firstWindow->assertNoEvents();
5254}
5255
Prabir Pradhan0dfcac72023-10-05 20:04:21 +00005256TEST_F(InputDispatcherDisplayProjectionTest, SynthesizeHoverCancelationWithCorrectCoordinates) {
5257 auto [firstWindow, secondWindow] = setupScaledDisplayScenario();
5258
5259 // Send hover enter to second window
5260 mDispatcher->notifyMotion(generateMotionArgs(ACTION_HOVER_ENTER, AINPUT_SOURCE_STYLUS,
5261 ADISPLAY_ID_DEFAULT, {PointF{150, 220}}));
5262 secondWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_HOVER_ENTER),
5263 WithCoords(100, 80), WithRawCoords(300, 880)));
5264
5265 mDispatcher->cancelCurrentTouch();
5266
5267 secondWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_HOVER_EXIT), WithCoords(100, 80),
5268 WithRawCoords(300, 880)));
5269 secondWindow->assertNoEvents();
5270 firstWindow->assertNoEvents();
5271}
5272
Prabir Pradhan453ae732023-10-13 14:30:14 +00005273// Same as above, but while the window is being mirrored.
Prabir Pradhan16463382023-10-12 23:03:19 +00005274TEST_F(InputDispatcherDisplayProjectionTest,
5275 SynthesizeHoverCancelationWithCorrectCoordinatesWhenMirrored) {
5276 auto [firstWindow, secondWindow] = setupScaledDisplayScenario();
5277
5278 const std::array<float, 9> matrix = {1.1, 2.2, 3.3, 4.4, 5.5, 6.6, 0.0, 0.0, 1.0};
5279 ui::Transform secondDisplayTransform;
5280 secondDisplayTransform.set(matrix);
5281 addDisplayInfo(SECOND_DISPLAY_ID, secondDisplayTransform);
5282
5283 sp<FakeWindowHandle> secondWindowClone = secondWindow->clone(SECOND_DISPLAY_ID);
5284 secondWindowClone->setWindowTransform(1.1, 2.2, 3.3, 4.4);
5285 addWindow(secondWindowClone);
5286
5287 // Send hover enter to second window
5288 mDispatcher->notifyMotion(generateMotionArgs(ACTION_HOVER_ENTER, AINPUT_SOURCE_STYLUS,
5289 ADISPLAY_ID_DEFAULT, {PointF{150, 220}}));
5290 secondWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_HOVER_ENTER),
5291 WithCoords(100, 80), WithRawCoords(300, 880),
5292 WithDisplayId(ADISPLAY_ID_DEFAULT)));
5293
5294 mDispatcher->cancelCurrentTouch();
5295
5296 // Ensure the cancelation happens with the correct displayId and the correct coordinates.
5297 secondWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_HOVER_EXIT), WithCoords(100, 80),
5298 WithRawCoords(300, 880),
5299 WithDisplayId(ADISPLAY_ID_DEFAULT)));
5300 secondWindow->assertNoEvents();
5301 firstWindow->assertNoEvents();
5302}
5303
Prabir Pradhan33e3baa2022-12-06 20:30:22 +00005304/** Ensure consistent behavior of InputDispatcher in all orientations. */
5305class InputDispatcherDisplayOrientationFixture
5306 : public InputDispatcherDisplayProjectionTest,
5307 public ::testing::WithParamInterface<ui::Rotation> {};
5308
5309// This test verifies the touchable region of a window for all rotations of the display by tapping
5310// in different locations on the display, specifically points close to the four corners of a
5311// window.
5312TEST_P(InputDispatcherDisplayOrientationFixture, HitTestInDifferentOrientations) {
5313 constexpr static int32_t displayWidth = 400;
5314 constexpr static int32_t displayHeight = 800;
5315
5316 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
5317
5318 const auto rotation = GetParam();
5319
5320 // Set up the display with the specified rotation.
5321 const bool isRotated = rotation == ui::ROTATION_90 || rotation == ui::ROTATION_270;
5322 const int32_t logicalDisplayWidth = isRotated ? displayHeight : displayWidth;
5323 const int32_t logicalDisplayHeight = isRotated ? displayWidth : displayHeight;
5324 const ui::Transform displayTransform(ui::Transform::toRotationFlags(rotation),
5325 logicalDisplayWidth, logicalDisplayHeight);
5326 addDisplayInfo(ADISPLAY_ID_DEFAULT, displayTransform);
5327
5328 // Create a window with its bounds determined in the logical display.
5329 const Rect frameInLogicalDisplay(100, 100, 200, 300);
5330 const Rect frameInDisplay = displayTransform.inverse().transform(frameInLogicalDisplay);
5331 sp<FakeWindowHandle> window =
5332 sp<FakeWindowHandle>::make(application, mDispatcher, "Window", ADISPLAY_ID_DEFAULT);
5333 window->setFrame(frameInDisplay, displayTransform);
5334 addWindow(window);
5335
5336 // The following points in logical display space should be inside the window.
5337 static const std::array<vec2, 4> insidePoints{
5338 {{100, 100}, {199.99, 100}, {100, 299.99}, {199.99, 299.99}}};
5339 for (const auto pointInsideWindow : insidePoints) {
5340 const vec2 p = displayTransform.inverse().transform(pointInsideWindow);
5341 const PointF pointInDisplaySpace{p.x, p.y};
Prabir Pradhan678438e2023-04-13 19:32:51 +00005342 mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_DOWN,
5343 AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
5344 {pointInDisplaySpace}));
Prabir Pradhan33e3baa2022-12-06 20:30:22 +00005345 window->consumeMotionDown();
5346
Prabir Pradhan678438e2023-04-13 19:32:51 +00005347 mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_UP,
5348 AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
5349 {pointInDisplaySpace}));
Prabir Pradhan33e3baa2022-12-06 20:30:22 +00005350 window->consumeMotionUp();
5351 }
5352
5353 // The following points in logical display space should be outside the window.
5354 static const std::array<vec2, 5> outsidePoints{
5355 {{200, 100}, {100, 300}, {200, 300}, {100, 99.99}, {99.99, 100}}};
5356 for (const auto pointOutsideWindow : outsidePoints) {
5357 const vec2 p = displayTransform.inverse().transform(pointOutsideWindow);
5358 const PointF pointInDisplaySpace{p.x, p.y};
Prabir Pradhan678438e2023-04-13 19:32:51 +00005359 mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_DOWN,
5360 AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
5361 {pointInDisplaySpace}));
Prabir Pradhan33e3baa2022-12-06 20:30:22 +00005362
Prabir Pradhan678438e2023-04-13 19:32:51 +00005363 mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_UP,
5364 AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
5365 {pointInDisplaySpace}));
Prabir Pradhan33e3baa2022-12-06 20:30:22 +00005366 }
5367 window->assertNoEvents();
5368}
5369
5370// Run the precision tests for all rotations.
5371INSTANTIATE_TEST_SUITE_P(InputDispatcherDisplayOrientationTests,
5372 InputDispatcherDisplayOrientationFixture,
5373 ::testing::Values(ui::ROTATION_0, ui::ROTATION_90, ui::ROTATION_180,
5374 ui::ROTATION_270),
5375 [](const testing::TestParamInfo<ui::Rotation>& testParamInfo) {
5376 return ftl::enum_string(testParamInfo.param);
5377 });
5378
Siarhei Vishniakou18050092021-09-01 13:32:49 -07005379using TransferFunction = std::function<bool(const std::unique_ptr<InputDispatcher>& dispatcher,
5380 sp<IBinder>, sp<IBinder>)>;
Siarhei Vishniakoud0c6bc82021-03-13 03:14:52 +00005381
5382class TransferTouchFixture : public InputDispatcherTest,
5383 public ::testing::WithParamInterface<TransferFunction> {};
5384
5385TEST_P(TransferTouchFixture, TransferTouch_OnePointer) {
Chris Yea209fde2020-07-22 13:54:51 -07005386 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
Svet Ganov5d3bc372020-01-26 23:11:07 -08005387
5388 // Create a couple of windows
Siarhei Vishniakou870ecec2020-12-09 08:07:46 -10005389 sp<FakeWindowHandle> firstWindow =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07005390 sp<FakeWindowHandle>::make(application, mDispatcher, "First Window",
5391 ADISPLAY_ID_DEFAULT);
Arthur Hungc539dbb2022-12-08 07:45:36 +00005392 firstWindow->setDupTouchToWallpaper(true);
Siarhei Vishniakou870ecec2020-12-09 08:07:46 -10005393 sp<FakeWindowHandle> secondWindow =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07005394 sp<FakeWindowHandle>::make(application, mDispatcher, "Second Window",
5395 ADISPLAY_ID_DEFAULT);
Arthur Hungc539dbb2022-12-08 07:45:36 +00005396 sp<FakeWindowHandle> wallpaper =
5397 sp<FakeWindowHandle>::make(application, mDispatcher, "Wallpaper", ADISPLAY_ID_DEFAULT);
5398 wallpaper->setIsWallpaper(true);
Prabir Pradhan65455c72024-02-13 21:46:41 +00005399 // Add the windows to the dispatcher, and ensure the first window is focused
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07005400 mDispatcher->onWindowInfosChanged(
5401 {{*firstWindow->getInfo(), *secondWindow->getInfo(), *wallpaper->getInfo()}, {}, 0, 0});
Prabir Pradhan65455c72024-02-13 21:46:41 +00005402 setFocusedWindow(firstWindow);
5403 firstWindow->consumeFocusEvent(true);
Svet Ganov5d3bc372020-01-26 23:11:07 -08005404
5405 // Send down to the first window
Prabir Pradhan678438e2023-04-13 19:32:51 +00005406 mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_DOWN,
5407 AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT));
Arthur Hungc539dbb2022-12-08 07:45:36 +00005408
Svet Ganov5d3bc372020-01-26 23:11:07 -08005409 // Only the first window should get the down event
5410 firstWindow->consumeMotionDown();
5411 secondWindow->assertNoEvents();
Arthur Hungc539dbb2022-12-08 07:45:36 +00005412 wallpaper->consumeMotionDown(ADISPLAY_ID_DEFAULT, expectedWallpaperFlags);
Prabir Pradhan65455c72024-02-13 21:46:41 +00005413 // Dispatcher reports pointer down outside focus for the wallpaper
5414 mFakePolicy->assertOnPointerDownEquals(wallpaper->getToken());
Svet Ganov5d3bc372020-01-26 23:11:07 -08005415
Siarhei Vishniakoud0c6bc82021-03-13 03:14:52 +00005416 // Transfer touch to the second window
5417 TransferFunction f = GetParam();
5418 const bool success = f(mDispatcher, firstWindow->getToken(), secondWindow->getToken());
5419 ASSERT_TRUE(success);
Svet Ganov5d3bc372020-01-26 23:11:07 -08005420 // The first window gets cancel and the second gets down
5421 firstWindow->consumeMotionCancel();
Prabir Pradhan65455c72024-02-13 21:46:41 +00005422 secondWindow->consumeMotionDown(ADISPLAY_ID_DEFAULT, AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
Arthur Hungc539dbb2022-12-08 07:45:36 +00005423 wallpaper->consumeMotionCancel(ADISPLAY_ID_DEFAULT, expectedWallpaperFlags);
Prabir Pradhan65455c72024-02-13 21:46:41 +00005424 // There should not be any changes to the focused window when transferring touch
5425 ASSERT_NO_FATAL_FAILURE(mFakePolicy->assertOnPointerDownWasNotCalled());
Svet Ganov5d3bc372020-01-26 23:11:07 -08005426
5427 // Send up event to the second window
Prabir Pradhan678438e2023-04-13 19:32:51 +00005428 mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN,
5429 ADISPLAY_ID_DEFAULT));
Prabir Pradhan65455c72024-02-13 21:46:41 +00005430 // The first window gets no events and the second gets up
Svet Ganov5d3bc372020-01-26 23:11:07 -08005431 firstWindow->assertNoEvents();
Prabir Pradhan65455c72024-02-13 21:46:41 +00005432 secondWindow->consumeMotionUp(ADISPLAY_ID_DEFAULT, AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
Arthur Hungc539dbb2022-12-08 07:45:36 +00005433 wallpaper->assertNoEvents();
Svet Ganov5d3bc372020-01-26 23:11:07 -08005434}
5435
Siarhei Vishniakou7ae7afd2022-03-31 15:26:13 -07005436/**
Prabir Pradhan367f3432024-02-13 23:05:58 +00005437 * When 'transferTouchGesture' API is invoked, dispatcher needs to find the "best" window to take
5438 * touch from. When we have spy windows, there are several windows to choose from: either spy, or
5439 * the 'real' (non-spy) window. Always prefer the 'real' window because that's what would be most
Siarhei Vishniakou7ae7afd2022-03-31 15:26:13 -07005440 * natural to the user.
5441 * In this test, we are sending a pointer to both spy window and first window. We then try to
5442 * transfer touch to the second window. The dispatcher should identify the first window as the
5443 * one that should lose the gesture, and therefore the action should be to move the gesture from
5444 * the first window to the second.
Prabir Pradhan367f3432024-02-13 23:05:58 +00005445 * The main goal here is to test the behaviour of 'transferTouchGesture' API, but it's still valid
5446 * to test the other API, as well.
Siarhei Vishniakou7ae7afd2022-03-31 15:26:13 -07005447 */
5448TEST_P(TransferTouchFixture, TransferTouch_MultipleWindowsWithSpy) {
5449 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
5450
5451 // Create a couple of windows + a spy window
5452 sp<FakeWindowHandle> spyWindow =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07005453 sp<FakeWindowHandle>::make(application, mDispatcher, "Spy", ADISPLAY_ID_DEFAULT);
Siarhei Vishniakou7ae7afd2022-03-31 15:26:13 -07005454 spyWindow->setTrustedOverlay(true);
5455 spyWindow->setSpy(true);
5456 sp<FakeWindowHandle> firstWindow =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07005457 sp<FakeWindowHandle>::make(application, mDispatcher, "First", ADISPLAY_ID_DEFAULT);
Siarhei Vishniakou7ae7afd2022-03-31 15:26:13 -07005458 sp<FakeWindowHandle> secondWindow =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07005459 sp<FakeWindowHandle>::make(application, mDispatcher, "Second", ADISPLAY_ID_DEFAULT);
Siarhei Vishniakou7ae7afd2022-03-31 15:26:13 -07005460
5461 // Add the windows to the dispatcher
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07005462 mDispatcher->onWindowInfosChanged(
5463 {{*spyWindow->getInfo(), *firstWindow->getInfo(), *secondWindow->getInfo()}, {}, 0, 0});
Siarhei Vishniakou7ae7afd2022-03-31 15:26:13 -07005464
5465 // Send down to the first window
Prabir Pradhan678438e2023-04-13 19:32:51 +00005466 mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_DOWN,
5467 AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT));
Siarhei Vishniakou7ae7afd2022-03-31 15:26:13 -07005468 // Only the first window and spy should get the down event
5469 spyWindow->consumeMotionDown();
5470 firstWindow->consumeMotionDown();
5471
5472 // Transfer touch to the second window. Non-spy window should be preferred over the spy window
Prabir Pradhan367f3432024-02-13 23:05:58 +00005473 // if f === 'transferTouchGesture'.
Siarhei Vishniakou7ae7afd2022-03-31 15:26:13 -07005474 TransferFunction f = GetParam();
5475 const bool success = f(mDispatcher, firstWindow->getToken(), secondWindow->getToken());
5476 ASSERT_TRUE(success);
5477 // The first window gets cancel and the second gets down
5478 firstWindow->consumeMotionCancel();
Prabir Pradhan65455c72024-02-13 21:46:41 +00005479 secondWindow->consumeMotionDown(ADISPLAY_ID_DEFAULT, AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
Siarhei Vishniakou7ae7afd2022-03-31 15:26:13 -07005480
5481 // Send up event to the second window
Prabir Pradhan678438e2023-04-13 19:32:51 +00005482 mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN,
5483 ADISPLAY_ID_DEFAULT));
Siarhei Vishniakou7ae7afd2022-03-31 15:26:13 -07005484 // The first window gets no events and the second+spy get up
5485 firstWindow->assertNoEvents();
5486 spyWindow->consumeMotionUp();
Prabir Pradhan65455c72024-02-13 21:46:41 +00005487 secondWindow->consumeMotionUp(ADISPLAY_ID_DEFAULT, AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
Siarhei Vishniakou7ae7afd2022-03-31 15:26:13 -07005488}
5489
Siarhei Vishniakoud0c6bc82021-03-13 03:14:52 +00005490TEST_P(TransferTouchFixture, TransferTouch_TwoPointersNonSplitTouch) {
Chris Yea209fde2020-07-22 13:54:51 -07005491 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
Svet Ganov5d3bc372020-01-26 23:11:07 -08005492
5493 PointF touchPoint = {10, 10};
5494
5495 // Create a couple of windows
Siarhei Vishniakou870ecec2020-12-09 08:07:46 -10005496 sp<FakeWindowHandle> firstWindow =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07005497 sp<FakeWindowHandle>::make(application, mDispatcher, "First Window",
5498 ADISPLAY_ID_DEFAULT);
Prabir Pradhan76bdecb2022-01-31 11:14:15 -08005499 firstWindow->setPreventSplitting(true);
Siarhei Vishniakou870ecec2020-12-09 08:07:46 -10005500 sp<FakeWindowHandle> secondWindow =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07005501 sp<FakeWindowHandle>::make(application, mDispatcher, "Second Window",
5502 ADISPLAY_ID_DEFAULT);
Prabir Pradhan76bdecb2022-01-31 11:14:15 -08005503 secondWindow->setPreventSplitting(true);
Svet Ganov5d3bc372020-01-26 23:11:07 -08005504
5505 // Add the windows to the dispatcher
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07005506 mDispatcher->onWindowInfosChanged(
5507 {{*firstWindow->getInfo(), *secondWindow->getInfo()}, {}, 0, 0});
Svet Ganov5d3bc372020-01-26 23:11:07 -08005508
5509 // Send down to the first window
Prabir Pradhan678438e2023-04-13 19:32:51 +00005510 mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_DOWN,
5511 AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
5512 {touchPoint}));
Svet Ganov5d3bc372020-01-26 23:11:07 -08005513 // Only the first window should get the down event
5514 firstWindow->consumeMotionDown();
5515 secondWindow->assertNoEvents();
5516
5517 // Send pointer down to the first window
Prabir Pradhan678438e2023-04-13 19:32:51 +00005518 mDispatcher->notifyMotion(generateMotionArgs(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN,
5519 ADISPLAY_ID_DEFAULT, {touchPoint, touchPoint}));
Svet Ganov5d3bc372020-01-26 23:11:07 -08005520 // Only the first window should get the pointer down event
5521 firstWindow->consumeMotionPointerDown(1);
5522 secondWindow->assertNoEvents();
5523
5524 // Transfer touch focus to the second window
Siarhei Vishniakoud0c6bc82021-03-13 03:14:52 +00005525 TransferFunction f = GetParam();
5526 bool success = f(mDispatcher, firstWindow->getToken(), secondWindow->getToken());
5527 ASSERT_TRUE(success);
Svet Ganov5d3bc372020-01-26 23:11:07 -08005528 // The first window gets cancel and the second gets down and pointer down
5529 firstWindow->consumeMotionCancel();
Prabir Pradhan65455c72024-02-13 21:46:41 +00005530 secondWindow->consumeMotionDown(ADISPLAY_ID_DEFAULT, AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
5531 secondWindow->consumeMotionPointerDown(1, ADISPLAY_ID_DEFAULT,
5532 AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
Svet Ganov5d3bc372020-01-26 23:11:07 -08005533
5534 // Send pointer up to the second window
Prabir Pradhan678438e2023-04-13 19:32:51 +00005535 mDispatcher->notifyMotion(generateMotionArgs(POINTER_1_UP, AINPUT_SOURCE_TOUCHSCREEN,
5536 ADISPLAY_ID_DEFAULT, {touchPoint, touchPoint}));
Svet Ganov5d3bc372020-01-26 23:11:07 -08005537 // The first window gets nothing and the second gets pointer up
5538 firstWindow->assertNoEvents();
Prabir Pradhan65455c72024-02-13 21:46:41 +00005539 secondWindow->consumeMotionPointerUp(1, ADISPLAY_ID_DEFAULT,
5540 AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
Svet Ganov5d3bc372020-01-26 23:11:07 -08005541
5542 // Send up event to the second window
Prabir Pradhan678438e2023-04-13 19:32:51 +00005543 mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN,
5544 ADISPLAY_ID_DEFAULT));
Svet Ganov5d3bc372020-01-26 23:11:07 -08005545 // The first window gets nothing and the second gets up
5546 firstWindow->assertNoEvents();
Prabir Pradhan65455c72024-02-13 21:46:41 +00005547 secondWindow->consumeMotionUp(ADISPLAY_ID_DEFAULT, AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
Svet Ganov5d3bc372020-01-26 23:11:07 -08005548}
5549
Arthur Hungc539dbb2022-12-08 07:45:36 +00005550TEST_P(TransferTouchFixture, TransferTouch_MultipleWallpapers) {
5551 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
5552
5553 // Create a couple of windows
5554 sp<FakeWindowHandle> firstWindow =
5555 sp<FakeWindowHandle>::make(application, mDispatcher, "First Window",
5556 ADISPLAY_ID_DEFAULT);
5557 firstWindow->setDupTouchToWallpaper(true);
5558 sp<FakeWindowHandle> secondWindow =
5559 sp<FakeWindowHandle>::make(application, mDispatcher, "Second Window",
5560 ADISPLAY_ID_DEFAULT);
5561 secondWindow->setDupTouchToWallpaper(true);
5562
5563 sp<FakeWindowHandle> wallpaper1 =
5564 sp<FakeWindowHandle>::make(application, mDispatcher, "Wallpaper1", ADISPLAY_ID_DEFAULT);
5565 wallpaper1->setIsWallpaper(true);
5566
5567 sp<FakeWindowHandle> wallpaper2 =
5568 sp<FakeWindowHandle>::make(application, mDispatcher, "Wallpaper2", ADISPLAY_ID_DEFAULT);
5569 wallpaper2->setIsWallpaper(true);
5570 // Add the windows to the dispatcher
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07005571 mDispatcher->onWindowInfosChanged({{*firstWindow->getInfo(), *wallpaper1->getInfo(),
5572 *secondWindow->getInfo(), *wallpaper2->getInfo()},
5573 {},
5574 0,
5575 0});
Arthur Hungc539dbb2022-12-08 07:45:36 +00005576
5577 // Send down to the first window
Prabir Pradhan678438e2023-04-13 19:32:51 +00005578 mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_DOWN,
5579 AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT));
Arthur Hungc539dbb2022-12-08 07:45:36 +00005580
5581 // Only the first window should get the down event
5582 firstWindow->consumeMotionDown();
5583 secondWindow->assertNoEvents();
5584 wallpaper1->consumeMotionDown(ADISPLAY_ID_DEFAULT, expectedWallpaperFlags);
5585 wallpaper2->assertNoEvents();
5586
5587 // Transfer touch focus to the second window
5588 TransferFunction f = GetParam();
5589 bool success = f(mDispatcher, firstWindow->getToken(), secondWindow->getToken());
5590 ASSERT_TRUE(success);
5591
5592 // The first window gets cancel and the second gets down
5593 firstWindow->consumeMotionCancel();
Prabir Pradhan65455c72024-02-13 21:46:41 +00005594 secondWindow->consumeMotionDown(ADISPLAY_ID_DEFAULT, AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
Arthur Hungc539dbb2022-12-08 07:45:36 +00005595 wallpaper1->consumeMotionCancel(ADISPLAY_ID_DEFAULT, expectedWallpaperFlags);
Prabir Pradhan65455c72024-02-13 21:46:41 +00005596 wallpaper2->consumeMotionDown(ADISPLAY_ID_DEFAULT,
5597 expectedWallpaperFlags | AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
Arthur Hungc539dbb2022-12-08 07:45:36 +00005598
5599 // Send up event to the second window
Prabir Pradhan678438e2023-04-13 19:32:51 +00005600 mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN,
5601 ADISPLAY_ID_DEFAULT));
Arthur Hungc539dbb2022-12-08 07:45:36 +00005602 // The first window gets no events and the second gets up
5603 firstWindow->assertNoEvents();
Prabir Pradhan65455c72024-02-13 21:46:41 +00005604 secondWindow->consumeMotionUp(ADISPLAY_ID_DEFAULT, AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
Arthur Hungc539dbb2022-12-08 07:45:36 +00005605 wallpaper1->assertNoEvents();
Prabir Pradhan65455c72024-02-13 21:46:41 +00005606 wallpaper2->consumeMotionUp(ADISPLAY_ID_DEFAULT,
5607 expectedWallpaperFlags | AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
Arthur Hungc539dbb2022-12-08 07:45:36 +00005608}
5609
Siarhei Vishniakoud0c6bc82021-03-13 03:14:52 +00005610// For the cases of single pointer touch and two pointers non-split touch, the api's
Prabir Pradhan367f3432024-02-13 23:05:58 +00005611// 'transferTouchGesture' and 'transferTouchOnDisplay' are equivalent in behaviour. They only differ
Siarhei Vishniakoud0c6bc82021-03-13 03:14:52 +00005612// for the case where there are multiple pointers split across several windows.
Prabir Pradhan367f3432024-02-13 23:05:58 +00005613INSTANTIATE_TEST_SUITE_P(
5614 InputDispatcherTransferFunctionTests, TransferTouchFixture,
5615 ::testing::Values(
5616 [&](const std::unique_ptr<InputDispatcher>& dispatcher, sp<IBinder> /*ignored*/,
5617 sp<IBinder> destChannelToken) {
5618 return dispatcher->transferTouchOnDisplay(destChannelToken,
5619 ADISPLAY_ID_DEFAULT);
5620 },
5621 [&](const std::unique_ptr<InputDispatcher>& dispatcher, sp<IBinder> from,
5622 sp<IBinder> to) {
5623 return dispatcher->transferTouchGesture(from, to,
5624 /*isDragAndDrop=*/false);
5625 }));
Siarhei Vishniakoud0c6bc82021-03-13 03:14:52 +00005626
Prabir Pradhan367f3432024-02-13 23:05:58 +00005627TEST_F(InputDispatcherTest, TransferTouch_TwoPointersSplitTouch) {
Chris Yea209fde2020-07-22 13:54:51 -07005628 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
Svet Ganov5d3bc372020-01-26 23:11:07 -08005629
Siarhei Vishniakou870ecec2020-12-09 08:07:46 -10005630 sp<FakeWindowHandle> firstWindow =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07005631 sp<FakeWindowHandle>::make(application, mDispatcher, "First Window",
5632 ADISPLAY_ID_DEFAULT);
Svet Ganov5d3bc372020-01-26 23:11:07 -08005633 firstWindow->setFrame(Rect(0, 0, 600, 400));
Svet Ganov5d3bc372020-01-26 23:11:07 -08005634
Siarhei Vishniakou870ecec2020-12-09 08:07:46 -10005635 sp<FakeWindowHandle> secondWindow =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07005636 sp<FakeWindowHandle>::make(application, mDispatcher, "Second Window",
5637 ADISPLAY_ID_DEFAULT);
Svet Ganov5d3bc372020-01-26 23:11:07 -08005638 secondWindow->setFrame(Rect(0, 400, 600, 800));
Svet Ganov5d3bc372020-01-26 23:11:07 -08005639
5640 // Add the windows to the dispatcher
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07005641 mDispatcher->onWindowInfosChanged(
5642 {{*firstWindow->getInfo(), *secondWindow->getInfo()}, {}, 0, 0});
Svet Ganov5d3bc372020-01-26 23:11:07 -08005643
5644 PointF pointInFirst = {300, 200};
5645 PointF pointInSecond = {300, 600};
5646
5647 // Send down to the first window
Prabir Pradhan678438e2023-04-13 19:32:51 +00005648 mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_DOWN,
5649 AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
5650 {pointInFirst}));
Svet Ganov5d3bc372020-01-26 23:11:07 -08005651 // Only the first window should get the down event
5652 firstWindow->consumeMotionDown();
5653 secondWindow->assertNoEvents();
5654
5655 // Send down to the second window
Prabir Pradhan678438e2023-04-13 19:32:51 +00005656 mDispatcher->notifyMotion(generateMotionArgs(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN,
5657 ADISPLAY_ID_DEFAULT,
5658 {pointInFirst, pointInSecond}));
Svet Ganov5d3bc372020-01-26 23:11:07 -08005659 // The first window gets a move and the second a down
5660 firstWindow->consumeMotionMove();
5661 secondWindow->consumeMotionDown();
5662
Prabir Pradhan367f3432024-02-13 23:05:58 +00005663 // Transfer touch to the second window
5664 mDispatcher->transferTouchGesture(firstWindow->getToken(), secondWindow->getToken());
Svet Ganov5d3bc372020-01-26 23:11:07 -08005665 // The first window gets cancel and the new gets pointer down (it already saw down)
5666 firstWindow->consumeMotionCancel();
Prabir Pradhan65455c72024-02-13 21:46:41 +00005667 secondWindow->consumeMotionPointerDown(1, ADISPLAY_ID_DEFAULT,
5668 AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
Svet Ganov5d3bc372020-01-26 23:11:07 -08005669
5670 // Send pointer up to the second window
Prabir Pradhan678438e2023-04-13 19:32:51 +00005671 mDispatcher->notifyMotion(generateMotionArgs(POINTER_1_UP, AINPUT_SOURCE_TOUCHSCREEN,
5672 ADISPLAY_ID_DEFAULT,
5673 {pointInFirst, pointInSecond}));
Svet Ganov5d3bc372020-01-26 23:11:07 -08005674 // The first window gets nothing and the second gets pointer up
5675 firstWindow->assertNoEvents();
Prabir Pradhan65455c72024-02-13 21:46:41 +00005676 secondWindow->consumeMotionPointerUp(1, ADISPLAY_ID_DEFAULT,
5677 AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
Svet Ganov5d3bc372020-01-26 23:11:07 -08005678
5679 // Send up event to the second window
Prabir Pradhan678438e2023-04-13 19:32:51 +00005680 mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN,
5681 ADISPLAY_ID_DEFAULT));
Svet Ganov5d3bc372020-01-26 23:11:07 -08005682 // The first window gets nothing and the second gets up
5683 firstWindow->assertNoEvents();
Prabir Pradhan65455c72024-02-13 21:46:41 +00005684 secondWindow->consumeMotionUp(ADISPLAY_ID_DEFAULT, AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
Svet Ganov5d3bc372020-01-26 23:11:07 -08005685}
5686
Prabir Pradhan367f3432024-02-13 23:05:58 +00005687// Same as TransferTouch_TwoPointersSplitTouch, but using 'transferTouchOnDisplay' api.
5688// Unlike 'transferTouchGesture', calling 'transferTouchOnDisplay' when there are two windows
5689// receiving touch is not supported, so the touch should continue on those windows and the
5690// transferred-to window should get nothing.
5691TEST_F(InputDispatcherTest, TransferTouchOnDisplay_TwoPointersSplitTouch) {
Siarhei Vishniakoud0c6bc82021-03-13 03:14:52 +00005692 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
5693
Siarhei Vishniakoud0c6bc82021-03-13 03:14:52 +00005694 sp<FakeWindowHandle> firstWindow =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07005695 sp<FakeWindowHandle>::make(application, mDispatcher, "First Window",
5696 ADISPLAY_ID_DEFAULT);
Siarhei Vishniakoud0c6bc82021-03-13 03:14:52 +00005697 firstWindow->setFrame(Rect(0, 0, 600, 400));
Siarhei Vishniakoud0c6bc82021-03-13 03:14:52 +00005698
Siarhei Vishniakoud0c6bc82021-03-13 03:14:52 +00005699 sp<FakeWindowHandle> secondWindow =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07005700 sp<FakeWindowHandle>::make(application, mDispatcher, "Second Window",
5701 ADISPLAY_ID_DEFAULT);
Siarhei Vishniakoud0c6bc82021-03-13 03:14:52 +00005702 secondWindow->setFrame(Rect(0, 400, 600, 800));
Siarhei Vishniakoud0c6bc82021-03-13 03:14:52 +00005703
5704 // Add the windows to the dispatcher
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07005705 mDispatcher->onWindowInfosChanged(
5706 {{*firstWindow->getInfo(), *secondWindow->getInfo()}, {}, 0, 0});
Siarhei Vishniakoud0c6bc82021-03-13 03:14:52 +00005707
5708 PointF pointInFirst = {300, 200};
5709 PointF pointInSecond = {300, 600};
5710
5711 // Send down to the first window
Prabir Pradhan678438e2023-04-13 19:32:51 +00005712 mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_DOWN,
5713 AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
5714 {pointInFirst}));
Siarhei Vishniakoud0c6bc82021-03-13 03:14:52 +00005715 // Only the first window should get the down event
5716 firstWindow->consumeMotionDown();
5717 secondWindow->assertNoEvents();
5718
5719 // Send down to the second window
Prabir Pradhan678438e2023-04-13 19:32:51 +00005720 mDispatcher->notifyMotion(generateMotionArgs(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN,
5721 ADISPLAY_ID_DEFAULT,
5722 {pointInFirst, pointInSecond}));
Siarhei Vishniakoud0c6bc82021-03-13 03:14:52 +00005723 // The first window gets a move and the second a down
5724 firstWindow->consumeMotionMove();
5725 secondWindow->consumeMotionDown();
5726
5727 // Transfer touch focus to the second window
Siarhei Vishniakou7ae7afd2022-03-31 15:26:13 -07005728 const bool transferred =
Prabir Pradhan367f3432024-02-13 23:05:58 +00005729 mDispatcher->transferTouchOnDisplay(secondWindow->getToken(), ADISPLAY_ID_DEFAULT);
5730 // The 'transferTouchOnDisplay' call should not succeed, because there are 2 touched windows
Siarhei Vishniakoud0c6bc82021-03-13 03:14:52 +00005731 ASSERT_FALSE(transferred);
5732 firstWindow->assertNoEvents();
5733 secondWindow->assertNoEvents();
5734
5735 // The rest of the dispatch should proceed as normal
5736 // Send pointer up to the second window
Prabir Pradhan678438e2023-04-13 19:32:51 +00005737 mDispatcher->notifyMotion(generateMotionArgs(POINTER_1_UP, AINPUT_SOURCE_TOUCHSCREEN,
5738 ADISPLAY_ID_DEFAULT,
5739 {pointInFirst, pointInSecond}));
Siarhei Vishniakoud0c6bc82021-03-13 03:14:52 +00005740 // The first window gets MOVE and the second gets pointer up
5741 firstWindow->consumeMotionMove();
5742 secondWindow->consumeMotionUp();
5743
5744 // Send up event to the first window
Prabir Pradhan678438e2023-04-13 19:32:51 +00005745 mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN,
5746 ADISPLAY_ID_DEFAULT));
Siarhei Vishniakoud0c6bc82021-03-13 03:14:52 +00005747 // The first window gets nothing and the second gets up
5748 firstWindow->consumeMotionUp();
5749 secondWindow->assertNoEvents();
5750}
5751
Arthur Hungabbb9d82021-09-01 14:52:30 +00005752// This case will create two windows and one mirrored window on the default display and mirror
Prabir Pradhan367f3432024-02-13 23:05:58 +00005753// two windows on the second display. It will test if 'transferTouchGesture' works fine if we put
Arthur Hungabbb9d82021-09-01 14:52:30 +00005754// the windows info of second display before default display.
Prabir Pradhan367f3432024-02-13 23:05:58 +00005755TEST_F(InputDispatcherTest, TransferTouch_CloneSurface) {
Arthur Hungabbb9d82021-09-01 14:52:30 +00005756 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
5757 sp<FakeWindowHandle> firstWindowInPrimary =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07005758 sp<FakeWindowHandle>::make(application, mDispatcher, "D_1_W1", ADISPLAY_ID_DEFAULT);
Arthur Hungabbb9d82021-09-01 14:52:30 +00005759 firstWindowInPrimary->setFrame(Rect(0, 0, 100, 100));
Arthur Hungabbb9d82021-09-01 14:52:30 +00005760 sp<FakeWindowHandle> secondWindowInPrimary =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07005761 sp<FakeWindowHandle>::make(application, mDispatcher, "D_1_W2", ADISPLAY_ID_DEFAULT);
Arthur Hungabbb9d82021-09-01 14:52:30 +00005762 secondWindowInPrimary->setFrame(Rect(100, 0, 200, 100));
Arthur Hungabbb9d82021-09-01 14:52:30 +00005763
Siarhei Vishniakouadb9fc92023-05-26 10:46:09 -07005764 sp<FakeWindowHandle> mirrorWindowInPrimary = firstWindowInPrimary->clone(ADISPLAY_ID_DEFAULT);
Arthur Hungabbb9d82021-09-01 14:52:30 +00005765 mirrorWindowInPrimary->setFrame(Rect(0, 100, 100, 200));
Arthur Hungabbb9d82021-09-01 14:52:30 +00005766
Siarhei Vishniakouadb9fc92023-05-26 10:46:09 -07005767 sp<FakeWindowHandle> firstWindowInSecondary = firstWindowInPrimary->clone(SECOND_DISPLAY_ID);
Arthur Hungabbb9d82021-09-01 14:52:30 +00005768 firstWindowInSecondary->setFrame(Rect(0, 0, 100, 100));
Arthur Hungabbb9d82021-09-01 14:52:30 +00005769
Siarhei Vishniakouadb9fc92023-05-26 10:46:09 -07005770 sp<FakeWindowHandle> secondWindowInSecondary = secondWindowInPrimary->clone(SECOND_DISPLAY_ID);
Arthur Hungabbb9d82021-09-01 14:52:30 +00005771 secondWindowInPrimary->setFrame(Rect(100, 0, 200, 100));
Arthur Hungabbb9d82021-09-01 14:52:30 +00005772
5773 // Update window info, let it find window handle of second display first.
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07005774 mDispatcher->onWindowInfosChanged(
5775 {{*firstWindowInSecondary->getInfo(), *secondWindowInSecondary->getInfo(),
5776 *mirrorWindowInPrimary->getInfo(), *firstWindowInPrimary->getInfo(),
5777 *secondWindowInPrimary->getInfo()},
5778 {},
5779 0,
5780 0});
Arthur Hungabbb9d82021-09-01 14:52:30 +00005781
5782 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07005783 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
Arthur Hungabbb9d82021-09-01 14:52:30 +00005784 {50, 50}))
5785 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
5786
5787 // Window should receive motion event.
5788 firstWindowInPrimary->consumeMotionDown(ADISPLAY_ID_DEFAULT);
5789
Prabir Pradhan367f3432024-02-13 23:05:58 +00005790 // Transfer touch
5791 ASSERT_TRUE(mDispatcher->transferTouchGesture(firstWindowInPrimary->getToken(),
5792 secondWindowInPrimary->getToken()));
Arthur Hungabbb9d82021-09-01 14:52:30 +00005793 // The first window gets cancel.
5794 firstWindowInPrimary->consumeMotionCancel();
Prabir Pradhan65455c72024-02-13 21:46:41 +00005795 secondWindowInPrimary->consumeMotionDown(ADISPLAY_ID_DEFAULT,
5796 AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
Arthur Hungabbb9d82021-09-01 14:52:30 +00005797
5798 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07005799 injectMotionEvent(*mDispatcher, AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN,
Arthur Hungabbb9d82021-09-01 14:52:30 +00005800 ADISPLAY_ID_DEFAULT, {150, 50}))
5801 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
5802 firstWindowInPrimary->assertNoEvents();
Prabir Pradhan65455c72024-02-13 21:46:41 +00005803 secondWindowInPrimary->consumeMotionMove(ADISPLAY_ID_DEFAULT,
5804 AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
Arthur Hungabbb9d82021-09-01 14:52:30 +00005805
5806 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07005807 injectMotionUp(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
Arthur Hungabbb9d82021-09-01 14:52:30 +00005808 {150, 50}))
5809 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
5810 firstWindowInPrimary->assertNoEvents();
Prabir Pradhan65455c72024-02-13 21:46:41 +00005811 secondWindowInPrimary->consumeMotionUp(ADISPLAY_ID_DEFAULT, AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
Arthur Hungabbb9d82021-09-01 14:52:30 +00005812}
5813
Prabir Pradhan367f3432024-02-13 23:05:58 +00005814// Same as TransferTouch_CloneSurface, but this touch on the secondary display and use
5815// 'transferTouchOnDisplay' api.
5816TEST_F(InputDispatcherTest, TransferTouchOnDisplay_CloneSurface) {
Arthur Hungabbb9d82021-09-01 14:52:30 +00005817 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
5818 sp<FakeWindowHandle> firstWindowInPrimary =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07005819 sp<FakeWindowHandle>::make(application, mDispatcher, "D_1_W1", ADISPLAY_ID_DEFAULT);
Arthur Hungabbb9d82021-09-01 14:52:30 +00005820 firstWindowInPrimary->setFrame(Rect(0, 0, 100, 100));
Arthur Hungabbb9d82021-09-01 14:52:30 +00005821 sp<FakeWindowHandle> secondWindowInPrimary =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07005822 sp<FakeWindowHandle>::make(application, mDispatcher, "D_1_W2", ADISPLAY_ID_DEFAULT);
Arthur Hungabbb9d82021-09-01 14:52:30 +00005823 secondWindowInPrimary->setFrame(Rect(100, 0, 200, 100));
Arthur Hungabbb9d82021-09-01 14:52:30 +00005824
Siarhei Vishniakouadb9fc92023-05-26 10:46:09 -07005825 sp<FakeWindowHandle> mirrorWindowInPrimary = firstWindowInPrimary->clone(ADISPLAY_ID_DEFAULT);
Arthur Hungabbb9d82021-09-01 14:52:30 +00005826 mirrorWindowInPrimary->setFrame(Rect(0, 100, 100, 200));
Arthur Hungabbb9d82021-09-01 14:52:30 +00005827
Siarhei Vishniakouadb9fc92023-05-26 10:46:09 -07005828 sp<FakeWindowHandle> firstWindowInSecondary = firstWindowInPrimary->clone(SECOND_DISPLAY_ID);
Arthur Hungabbb9d82021-09-01 14:52:30 +00005829 firstWindowInSecondary->setFrame(Rect(0, 0, 100, 100));
Arthur Hungabbb9d82021-09-01 14:52:30 +00005830
Siarhei Vishniakouadb9fc92023-05-26 10:46:09 -07005831 sp<FakeWindowHandle> secondWindowInSecondary = secondWindowInPrimary->clone(SECOND_DISPLAY_ID);
Arthur Hungabbb9d82021-09-01 14:52:30 +00005832 secondWindowInPrimary->setFrame(Rect(100, 0, 200, 100));
Arthur Hungabbb9d82021-09-01 14:52:30 +00005833
5834 // Update window info, let it find window handle of second display first.
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07005835 mDispatcher->onWindowInfosChanged(
5836 {{*firstWindowInSecondary->getInfo(), *secondWindowInSecondary->getInfo(),
5837 *mirrorWindowInPrimary->getInfo(), *firstWindowInPrimary->getInfo(),
5838 *secondWindowInPrimary->getInfo()},
5839 {},
5840 0,
5841 0});
Arthur Hungabbb9d82021-09-01 14:52:30 +00005842
5843 // Touch on second display.
5844 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07005845 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, SECOND_DISPLAY_ID,
5846 {50, 50}))
Arthur Hungabbb9d82021-09-01 14:52:30 +00005847 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
5848
5849 // Window should receive motion event.
Prabir Pradhanbb3f1c02024-01-04 20:17:14 +00005850 firstWindowInSecondary->consumeMotionDown(SECOND_DISPLAY_ID);
Arthur Hungabbb9d82021-09-01 14:52:30 +00005851
5852 // Transfer touch focus
Prabir Pradhan367f3432024-02-13 23:05:58 +00005853 ASSERT_TRUE(mDispatcher->transferTouchOnDisplay(secondWindowInSecondary->getToken(),
5854 SECOND_DISPLAY_ID));
Arthur Hungabbb9d82021-09-01 14:52:30 +00005855
5856 // The first window gets cancel.
Prabir Pradhanbb3f1c02024-01-04 20:17:14 +00005857 firstWindowInSecondary->consumeMotionCancel(SECOND_DISPLAY_ID);
Prabir Pradhan65455c72024-02-13 21:46:41 +00005858 secondWindowInSecondary->consumeMotionDown(SECOND_DISPLAY_ID,
5859 AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
Arthur Hungabbb9d82021-09-01 14:52:30 +00005860
5861 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07005862 injectMotionEvent(*mDispatcher, AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN,
Arthur Hungabbb9d82021-09-01 14:52:30 +00005863 SECOND_DISPLAY_ID, {150, 50}))
5864 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
Prabir Pradhanbb3f1c02024-01-04 20:17:14 +00005865 firstWindowInSecondary->assertNoEvents();
Prabir Pradhan65455c72024-02-13 21:46:41 +00005866 secondWindowInSecondary->consumeMotionMove(SECOND_DISPLAY_ID,
5867 AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
Arthur Hungabbb9d82021-09-01 14:52:30 +00005868
5869 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07005870 injectMotionUp(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, SECOND_DISPLAY_ID, {150, 50}))
Arthur Hungabbb9d82021-09-01 14:52:30 +00005871 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
Prabir Pradhanbb3f1c02024-01-04 20:17:14 +00005872 firstWindowInSecondary->assertNoEvents();
Prabir Pradhan65455c72024-02-13 21:46:41 +00005873 secondWindowInSecondary->consumeMotionUp(SECOND_DISPLAY_ID, AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
Arthur Hungabbb9d82021-09-01 14:52:30 +00005874}
5875
Siarhei Vishniakouf1035d42019-09-20 16:32:01 +01005876TEST_F(InputDispatcherTest, FocusedWindow_ReceivesFocusEventAndKeyEvent) {
Chris Yea209fde2020-07-22 13:54:51 -07005877 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07005878 sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher,
5879 "Fake Window", ADISPLAY_ID_DEFAULT);
Siarhei Vishniakouf1035d42019-09-20 16:32:01 +01005880
Vishnu Nair47074b82020-08-14 11:54:47 -07005881 window->setFocusable(true);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07005882 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Vishnu Nair958da932020-08-21 17:12:37 -07005883 setFocusedWindow(window);
Siarhei Vishniakouf1035d42019-09-20 16:32:01 +01005884
5885 window->consumeFocusEvent(true);
5886
Prabir Pradhan678438e2023-04-13 19:32:51 +00005887 mDispatcher->notifyKey(generateKeyArgs(AKEY_EVENT_ACTION_DOWN, ADISPLAY_ID_DEFAULT));
Siarhei Vishniakouf1035d42019-09-20 16:32:01 +01005888
5889 // Window should receive key down event.
5890 window->consumeKeyDown(ADISPLAY_ID_DEFAULT);
Josep del Riob3981622023-04-18 15:49:45 +00005891
5892 // Should have poked user activity
Siarhei Vishniakou4fd86732023-05-24 17:33:01 +00005893 mDispatcher->waitForIdle();
Josep del Riob3981622023-04-18 15:49:45 +00005894 mFakePolicy->assertUserActivityPoked();
5895}
5896
5897TEST_F(InputDispatcherTest, FocusedWindow_DisableUserActivity) {
5898 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
5899 sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher,
5900 "Fake Window", ADISPLAY_ID_DEFAULT);
5901
5902 window->setDisableUserActivity(true);
5903 window->setFocusable(true);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07005904 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Josep del Riob3981622023-04-18 15:49:45 +00005905 setFocusedWindow(window);
5906
5907 window->consumeFocusEvent(true);
5908
5909 mDispatcher->notifyKey(generateKeyArgs(AKEY_EVENT_ACTION_DOWN, ADISPLAY_ID_DEFAULT));
5910
5911 // Window should receive key down event.
5912 window->consumeKeyDown(ADISPLAY_ID_DEFAULT);
5913
5914 // Should have poked user activity
Siarhei Vishniakou4fd86732023-05-24 17:33:01 +00005915 mDispatcher->waitForIdle();
Josep del Riob3981622023-04-18 15:49:45 +00005916 mFakePolicy->assertUserActivityNotPoked();
5917}
5918
5919TEST_F(InputDispatcherTest, FocusedWindow_DoesNotReceiveSystemShortcut) {
5920 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
5921 sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher,
5922 "Fake Window", ADISPLAY_ID_DEFAULT);
5923
5924 window->setFocusable(true);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07005925 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Josep del Riob3981622023-04-18 15:49:45 +00005926 setFocusedWindow(window);
5927
5928 window->consumeFocusEvent(true);
5929
5930 mDispatcher->notifyKey(generateSystemShortcutArgs(AKEY_EVENT_ACTION_DOWN, ADISPLAY_ID_DEFAULT));
5931 mDispatcher->waitForIdle();
5932
5933 // System key is not passed down
5934 window->assertNoEvents();
5935
5936 // Should have poked user activity
5937 mFakePolicy->assertUserActivityPoked();
5938}
5939
5940TEST_F(InputDispatcherTest, FocusedWindow_DoesNotReceiveAssistantKey) {
5941 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
5942 sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher,
5943 "Fake Window", ADISPLAY_ID_DEFAULT);
5944
5945 window->setFocusable(true);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07005946 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Josep del Riob3981622023-04-18 15:49:45 +00005947 setFocusedWindow(window);
5948
5949 window->consumeFocusEvent(true);
5950
5951 mDispatcher->notifyKey(generateAssistantKeyArgs(AKEY_EVENT_ACTION_DOWN, ADISPLAY_ID_DEFAULT));
5952 mDispatcher->waitForIdle();
5953
5954 // System key is not passed down
5955 window->assertNoEvents();
5956
5957 // Should have poked user activity
5958 mFakePolicy->assertUserActivityPoked();
5959}
5960
5961TEST_F(InputDispatcherTest, FocusedWindow_SystemKeyIgnoresDisableUserActivity) {
5962 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
5963 sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher,
5964 "Fake Window", ADISPLAY_ID_DEFAULT);
5965
5966 window->setDisableUserActivity(true);
5967 window->setFocusable(true);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07005968 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Josep del Riob3981622023-04-18 15:49:45 +00005969 setFocusedWindow(window);
5970
5971 window->consumeFocusEvent(true);
5972
5973 mDispatcher->notifyKey(generateSystemShortcutArgs(AKEY_EVENT_ACTION_DOWN, ADISPLAY_ID_DEFAULT));
5974 mDispatcher->waitForIdle();
5975
5976 // System key is not passed down
5977 window->assertNoEvents();
5978
5979 // Should have poked user activity
5980 mFakePolicy->assertUserActivityPoked();
Siarhei Vishniakouf1035d42019-09-20 16:32:01 +01005981}
5982
Siarhei Vishniakou90ee4782023-05-08 11:57:24 -07005983TEST_F(InputDispatcherTest, InjectedTouchesPokeUserActivity) {
5984 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
5985 sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher,
5986 "Fake Window", ADISPLAY_ID_DEFAULT);
5987
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07005988 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Siarhei Vishniakou90ee4782023-05-08 11:57:24 -07005989
5990 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07005991 injectMotionEvent(*mDispatcher, AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN,
Siarhei Vishniakou90ee4782023-05-08 11:57:24 -07005992 ADISPLAY_ID_DEFAULT, {100, 100}))
5993 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
5994
5995 window->consumeMotionEvent(
5996 AllOf(WithMotionAction(ACTION_DOWN), WithDisplayId(ADISPLAY_ID_DEFAULT)));
5997
5998 // Should have poked user activity
Siarhei Vishniakou4fd86732023-05-24 17:33:01 +00005999 mDispatcher->waitForIdle();
Siarhei Vishniakou90ee4782023-05-08 11:57:24 -07006000 mFakePolicy->assertUserActivityPoked();
6001}
6002
Siarhei Vishniakouf1035d42019-09-20 16:32:01 +01006003TEST_F(InputDispatcherTest, UnfocusedWindow_DoesNotReceiveFocusEventOrKeyEvent) {
Chris Yea209fde2020-07-22 13:54:51 -07006004 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07006005 sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher,
6006 "Fake Window", ADISPLAY_ID_DEFAULT);
Siarhei Vishniakouf1035d42019-09-20 16:32:01 +01006007
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07006008 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Siarhei Vishniakouf1035d42019-09-20 16:32:01 +01006009
Prabir Pradhan678438e2023-04-13 19:32:51 +00006010 mDispatcher->notifyKey(generateKeyArgs(AKEY_EVENT_ACTION_DOWN, ADISPLAY_ID_DEFAULT));
Siarhei Vishniakouf1035d42019-09-20 16:32:01 +01006011 mDispatcher->waitForIdle();
6012
6013 window->assertNoEvents();
6014}
6015
6016// If a window is touchable, but does not have focus, it should receive motion events, but not keys
6017TEST_F(InputDispatcherTest, UnfocusedWindow_ReceivesMotionsButNotKeys) {
Chris Yea209fde2020-07-22 13:54:51 -07006018 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07006019 sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher,
6020 "Fake Window", ADISPLAY_ID_DEFAULT);
Siarhei Vishniakouf1035d42019-09-20 16:32:01 +01006021
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07006022 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Siarhei Vishniakouf1035d42019-09-20 16:32:01 +01006023
6024 // Send key
Prabir Pradhan678438e2023-04-13 19:32:51 +00006025 mDispatcher->notifyKey(generateKeyArgs(AKEY_EVENT_ACTION_DOWN, ADISPLAY_ID_DEFAULT));
Siarhei Vishniakouf1035d42019-09-20 16:32:01 +01006026 // Send motion
Prabir Pradhan678438e2023-04-13 19:32:51 +00006027 mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_DOWN,
6028 AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT));
Siarhei Vishniakouf1035d42019-09-20 16:32:01 +01006029
6030 // Window should receive only the motion event
6031 window->consumeMotionDown(ADISPLAY_ID_DEFAULT);
6032 window->assertNoEvents(); // Key event or focus event will not be received
6033}
6034
arthurhungea3f4fc2020-12-21 23:18:53 +08006035TEST_F(InputDispatcherTest, PointerCancel_SendCancelWhenSplitTouch) {
6036 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
6037
arthurhungea3f4fc2020-12-21 23:18:53 +08006038 sp<FakeWindowHandle> firstWindow =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07006039 sp<FakeWindowHandle>::make(application, mDispatcher, "First Window",
6040 ADISPLAY_ID_DEFAULT);
arthurhungea3f4fc2020-12-21 23:18:53 +08006041 firstWindow->setFrame(Rect(0, 0, 600, 400));
arthurhungea3f4fc2020-12-21 23:18:53 +08006042
arthurhungea3f4fc2020-12-21 23:18:53 +08006043 sp<FakeWindowHandle> secondWindow =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07006044 sp<FakeWindowHandle>::make(application, mDispatcher, "Second Window",
6045 ADISPLAY_ID_DEFAULT);
arthurhungea3f4fc2020-12-21 23:18:53 +08006046 secondWindow->setFrame(Rect(0, 400, 600, 800));
arthurhungea3f4fc2020-12-21 23:18:53 +08006047
6048 // Add the windows to the dispatcher
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07006049 mDispatcher->onWindowInfosChanged(
6050 {{*firstWindow->getInfo(), *secondWindow->getInfo()}, {}, 0, 0});
arthurhungea3f4fc2020-12-21 23:18:53 +08006051
6052 PointF pointInFirst = {300, 200};
6053 PointF pointInSecond = {300, 600};
6054
6055 // Send down to the first window
Prabir Pradhan678438e2023-04-13 19:32:51 +00006056 mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_DOWN,
6057 AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
6058 {pointInFirst}));
arthurhungea3f4fc2020-12-21 23:18:53 +08006059 // Only the first window should get the down event
6060 firstWindow->consumeMotionDown();
6061 secondWindow->assertNoEvents();
6062
6063 // Send down to the second window
Prabir Pradhan678438e2023-04-13 19:32:51 +00006064 mDispatcher->notifyMotion(generateMotionArgs(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN,
6065 ADISPLAY_ID_DEFAULT,
6066 {pointInFirst, pointInSecond}));
arthurhungea3f4fc2020-12-21 23:18:53 +08006067 // The first window gets a move and the second a down
6068 firstWindow->consumeMotionMove();
6069 secondWindow->consumeMotionDown();
6070
6071 // Send pointer cancel to the second window
6072 NotifyMotionArgs pointerUpMotionArgs =
Siarhei Vishniakoua16e3a22022-03-02 15:26:40 -08006073 generateMotionArgs(POINTER_1_UP, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
arthurhungea3f4fc2020-12-21 23:18:53 +08006074 {pointInFirst, pointInSecond});
6075 pointerUpMotionArgs.flags |= AMOTION_EVENT_FLAG_CANCELED;
Prabir Pradhan678438e2023-04-13 19:32:51 +00006076 mDispatcher->notifyMotion(pointerUpMotionArgs);
arthurhungea3f4fc2020-12-21 23:18:53 +08006077 // The first window gets move and the second gets cancel.
6078 firstWindow->consumeMotionMove(ADISPLAY_ID_DEFAULT, AMOTION_EVENT_FLAG_CANCELED);
6079 secondWindow->consumeMotionCancel(ADISPLAY_ID_DEFAULT, AMOTION_EVENT_FLAG_CANCELED);
6080
6081 // Send up event.
Prabir Pradhan678438e2023-04-13 19:32:51 +00006082 mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN,
6083 ADISPLAY_ID_DEFAULT));
arthurhungea3f4fc2020-12-21 23:18:53 +08006084 // The first window gets up and the second gets nothing.
6085 firstWindow->consumeMotionUp();
6086 secondWindow->assertNoEvents();
6087}
6088
Siarhei Vishniakouf94ae022021-02-04 01:23:17 +00006089TEST_F(InputDispatcherTest, SendTimeline_DoesNotCrashDispatcher) {
6090 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
6091
6092 sp<FakeWindowHandle> window =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07006093 sp<FakeWindowHandle>::make(application, mDispatcher, "Window", ADISPLAY_ID_DEFAULT);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07006094 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Siarhei Vishniakouf94ae022021-02-04 01:23:17 +00006095 std::array<nsecs_t, GraphicsTimeline::SIZE> graphicsTimeline;
6096 graphicsTimeline[GraphicsTimeline::GPU_COMPLETED_TIME] = 2;
6097 graphicsTimeline[GraphicsTimeline::PRESENT_TIME] = 3;
6098
Harry Cutts33476232023-01-30 19:57:29 +00006099 window->sendTimeline(/*inputEventId=*/1, graphicsTimeline);
Siarhei Vishniakouf94ae022021-02-04 01:23:17 +00006100 window->assertNoEvents();
6101 mDispatcher->waitForIdle();
6102}
6103
Prabir Pradhan1376fcd2022-01-21 09:56:35 -08006104using InputDispatcherMonitorTest = InputDispatcherTest;
6105
Siarhei Vishniakouca205502021-07-16 21:31:58 +00006106/**
6107 * Two entities that receive touch: A window, and a global monitor.
6108 * The touch goes to the window, and then the window disappears.
6109 * The monitor does not get cancel right away. But if more events come in, the touch gets canceled
6110 * for the monitor, as well.
6111 * 1. foregroundWindow
6112 * 2. monitor <-- global monitor (doesn't observe z order, receives all events)
6113 */
Prabir Pradhan1376fcd2022-01-21 09:56:35 -08006114TEST_F(InputDispatcherMonitorTest, MonitorTouchIsCanceledWhenForegroundWindowDisappears) {
Siarhei Vishniakouca205502021-07-16 21:31:58 +00006115 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
6116 sp<FakeWindowHandle> window =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07006117 sp<FakeWindowHandle>::make(application, mDispatcher, "Foreground", ADISPLAY_ID_DEFAULT);
Siarhei Vishniakouca205502021-07-16 21:31:58 +00006118
Prabir Pradhanfb549072023-10-05 19:17:36 +00006119 FakeMonitorReceiver monitor = FakeMonitorReceiver(*mDispatcher, "M_1", ADISPLAY_ID_DEFAULT);
Siarhei Vishniakouca205502021-07-16 21:31:58 +00006120
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07006121 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Siarhei Vishniakouca205502021-07-16 21:31:58 +00006122 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07006123 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
Siarhei Vishniakouca205502021-07-16 21:31:58 +00006124 {100, 200}))
6125 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
6126
6127 // Both the foreground window and the global monitor should receive the touch down
6128 window->consumeMotionDown();
6129 monitor.consumeMotionDown(ADISPLAY_ID_DEFAULT);
6130
6131 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07006132 injectMotionEvent(*mDispatcher, AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN,
Siarhei Vishniakouca205502021-07-16 21:31:58 +00006133 ADISPLAY_ID_DEFAULT, {110, 200}))
6134 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
6135
6136 window->consumeMotionMove();
6137 monitor.consumeMotionMove(ADISPLAY_ID_DEFAULT);
6138
6139 // Now the foreground window goes away
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07006140 mDispatcher->onWindowInfosChanged({{}, {}, 0, 0});
Siarhei Vishniakouca205502021-07-16 21:31:58 +00006141 window->consumeMotionCancel();
6142 monitor.assertNoEvents(); // Global monitor does not get a cancel yet
6143
6144 // If more events come in, there will be no more foreground window to send them to. This will
6145 // cause a cancel for the monitor, as well.
6146 ASSERT_EQ(InputEventInjectionResult::FAILED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07006147 injectMotionEvent(*mDispatcher, AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN,
Siarhei Vishniakouca205502021-07-16 21:31:58 +00006148 ADISPLAY_ID_DEFAULT, {120, 200}))
6149 << "Injection should fail because the window was removed";
6150 window->assertNoEvents();
6151 // Global monitor now gets the cancel
6152 monitor.consumeMotionCancel(ADISPLAY_ID_DEFAULT);
6153}
6154
Prabir Pradhan1376fcd2022-01-21 09:56:35 -08006155TEST_F(InputDispatcherMonitorTest, ReceivesMotionEvents) {
Chris Yea209fde2020-07-22 13:54:51 -07006156 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07006157 sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher,
6158 "Fake Window", ADISPLAY_ID_DEFAULT);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07006159 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Michael Wright3a240c42019-12-10 20:53:41 +00006160
Prabir Pradhanfb549072023-10-05 19:17:36 +00006161 FakeMonitorReceiver monitor = FakeMonitorReceiver(*mDispatcher, "M_1", ADISPLAY_ID_DEFAULT);
Michael Wright3a240c42019-12-10 20:53:41 +00006162
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08006163 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07006164 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT))
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08006165 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
Michael Wright3a240c42019-12-10 20:53:41 +00006166 window->consumeMotionDown(ADISPLAY_ID_DEFAULT);
chaviwd1c23182019-12-20 18:44:56 -08006167 monitor.consumeMotionDown(ADISPLAY_ID_DEFAULT);
Michael Wright3a240c42019-12-10 20:53:41 +00006168}
6169
Prabir Pradhan1376fcd2022-01-21 09:56:35 -08006170TEST_F(InputDispatcherMonitorTest, MonitorCannotPilferPointers) {
Prabir Pradhanfb549072023-10-05 19:17:36 +00006171 FakeMonitorReceiver monitor = FakeMonitorReceiver(*mDispatcher, "M_1", ADISPLAY_ID_DEFAULT);
Michael Wright3a240c42019-12-10 20:53:41 +00006172
Chris Yea209fde2020-07-22 13:54:51 -07006173 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07006174 sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher,
6175 "Fake Window", ADISPLAY_ID_DEFAULT);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07006176 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Michael Wright3a240c42019-12-10 20:53:41 +00006177
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08006178 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07006179 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT))
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08006180 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
chaviwd1c23182019-12-20 18:44:56 -08006181 monitor.consumeMotionDown(ADISPLAY_ID_DEFAULT);
Prabir Pradhan1376fcd2022-01-21 09:56:35 -08006182 window->consumeMotionDown(ADISPLAY_ID_DEFAULT);
Michael Wright3a240c42019-12-10 20:53:41 +00006183
Prabir Pradhan1376fcd2022-01-21 09:56:35 -08006184 // Pilfer pointers from the monitor.
6185 // This should not do anything and the window should continue to receive events.
6186 EXPECT_NE(OK, mDispatcher->pilferPointers(monitor.getToken()));
Michael Wright3a240c42019-12-10 20:53:41 +00006187
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08006188 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07006189 injectMotionEvent(*mDispatcher, AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN,
Prabir Pradhan1376fcd2022-01-21 09:56:35 -08006190 ADISPLAY_ID_DEFAULT))
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08006191 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
Prabir Pradhan1376fcd2022-01-21 09:56:35 -08006192
6193 monitor.consumeMotionMove(ADISPLAY_ID_DEFAULT);
6194 window->consumeMotionMove(ADISPLAY_ID_DEFAULT);
Michael Wright3a240c42019-12-10 20:53:41 +00006195}
6196
Prabir Pradhan1376fcd2022-01-21 09:56:35 -08006197TEST_F(InputDispatcherMonitorTest, NoWindowTransform) {
Evan Rosky84f07f02021-04-16 10:42:42 -07006198 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07006199 sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher,
6200 "Fake Window", ADISPLAY_ID_DEFAULT);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07006201 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Evan Rosky84f07f02021-04-16 10:42:42 -07006202 window->setWindowOffset(20, 40);
6203 window->setWindowTransform(0, 1, -1, 0);
6204
Prabir Pradhanfb549072023-10-05 19:17:36 +00006205 FakeMonitorReceiver monitor = FakeMonitorReceiver(*mDispatcher, "M_1", ADISPLAY_ID_DEFAULT);
Evan Rosky84f07f02021-04-16 10:42:42 -07006206
6207 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07006208 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT))
Evan Rosky84f07f02021-04-16 10:42:42 -07006209 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
6210 window->consumeMotionDown(ADISPLAY_ID_DEFAULT);
Siarhei Vishniakoud3061ab2023-12-18 20:41:08 -08006211 std::unique_ptr<MotionEvent> event = monitor.consumeMotion();
6212 ASSERT_NE(nullptr, event);
Evan Rosky84f07f02021-04-16 10:42:42 -07006213 // Even though window has transform, gesture monitor must not.
6214 ASSERT_EQ(ui::Transform(), event->getTransform());
6215}
6216
Prabir Pradhan1376fcd2022-01-21 09:56:35 -08006217TEST_F(InputDispatcherMonitorTest, InjectionFailsWithNoWindow) {
Arthur Hungb3307ee2021-10-14 10:57:37 +00006218 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
Prabir Pradhanfb549072023-10-05 19:17:36 +00006219 FakeMonitorReceiver monitor = FakeMonitorReceiver(*mDispatcher, "M_1", ADISPLAY_ID_DEFAULT);
Arthur Hungb3307ee2021-10-14 10:57:37 +00006220
Prabir Pradhan1376fcd2022-01-21 09:56:35 -08006221 ASSERT_EQ(InputEventInjectionResult::FAILED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07006222 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT))
Prabir Pradhan1376fcd2022-01-21 09:56:35 -08006223 << "Injection should fail if there is a monitor, but no touchable window";
6224 monitor.assertNoEvents();
Arthur Hungb3307ee2021-10-14 10:57:37 +00006225}
6226
Linnan Lid8150952024-01-26 18:07:17 +00006227/**
6228 * Two displays
6229 * The first monitor has a foreground window, a monitor
6230 * The second window has only one monitor.
6231 * We first inject a Down event into the first display, this injection should succeed and both
6232 * the foreground window and monitor should receive a down event, then inject a Down event into
6233 * the second display as well, this injection should fail, at this point, the first display
6234 * window and monitor should not receive a cancel or any other event.
6235 * Continue to inject Move and UP events to the first display, the events should be received
6236 * normally by the foreground window and monitor.
6237 */
6238TEST_F(InputDispatcherMonitorTest, MonitorTouchIsNotCanceledWhenAnotherEmptyDisplayReceiveEvents) {
6239 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
6240 sp<FakeWindowHandle> window =
6241 sp<FakeWindowHandle>::make(application, mDispatcher, "Foreground", ADISPLAY_ID_DEFAULT);
6242
6243 FakeMonitorReceiver monitor = FakeMonitorReceiver(*mDispatcher, "M_1", ADISPLAY_ID_DEFAULT);
6244 FakeMonitorReceiver secondMonitor = FakeMonitorReceiver(*mDispatcher, "M_2", SECOND_DISPLAY_ID);
6245
6246 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
6247 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
6248 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
6249 {100, 200}))
6250 << "The down event injected into the first display should succeed";
6251
6252 window->consumeMotionDown();
6253 monitor.consumeMotionDown(ADISPLAY_ID_DEFAULT);
Linnan Lid8150952024-01-26 18:07:17 +00006254
6255 ASSERT_EQ(InputEventInjectionResult::FAILED,
6256 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, SECOND_DISPLAY_ID,
6257 {100, 200}))
Prabir Pradhana0d43d42024-01-30 00:27:08 +00006258 << "The down event injected into the second display should fail since there's no "
6259 "touchable window";
Linnan Lid8150952024-01-26 18:07:17 +00006260
6261 // Continue to inject event to first display.
6262 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
6263 injectMotionEvent(*mDispatcher, AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN,
6264 ADISPLAY_ID_DEFAULT, {110, 220}))
6265 << "The move event injected into the first display should succeed";
6266
6267 window->consumeMotionMove();
6268 monitor.consumeMotionMove(ADISPLAY_ID_DEFAULT);
Linnan Lid8150952024-01-26 18:07:17 +00006269
6270 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
6271 injectMotionUp(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
6272 {110, 220}))
6273 << "The up event injected into the first display should succeed";
6274
6275 window->consumeMotionUp();
6276 monitor.consumeMotionUp(ADISPLAY_ID_DEFAULT);
Prabir Pradhana0d43d42024-01-30 00:27:08 +00006277
6278 window->assertNoEvents();
6279 monitor.assertNoEvents();
Linnan Lid8150952024-01-26 18:07:17 +00006280 secondMonitor.assertNoEvents();
6281}
6282
6283/**
6284 * Two displays
6285 * There is a monitor and foreground window on each display.
6286 * First, we inject down events into each of the two displays, at this point, the foreground windows
6287 * and monitors on both displays should receive down events.
6288 * At this point, the foreground window of the second display goes away, the gone window should
6289 * receive the cancel event, and the other windows and monitors should not receive any events.
6290 * Inject a move event into the second display. At this point, the injection should fail because
6291 * the second display no longer has a foreground window. At this point, the monitor on the second
6292 * display should receive a cancel event, and any windows or monitors on the first display should
6293 * not receive any events, and any subsequent injection of events into the second display should
6294 * also fail.
6295 * Continue to inject events into the first display, and the events should all be injected
6296 * successfully and received normally.
6297 */
6298TEST_F(InputDispatcherMonitorTest, MonitorTouchIsNotCancelWhenAnotherDisplayMonitorTouchCanceled) {
6299 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
6300 sp<FakeWindowHandle> window =
6301 sp<FakeWindowHandle>::make(application, mDispatcher, "Foreground", ADISPLAY_ID_DEFAULT);
6302 sp<FakeWindowHandle> secondWindow =
6303 sp<FakeWindowHandle>::make(application, mDispatcher, "SecondForeground",
6304 SECOND_DISPLAY_ID);
6305
6306 FakeMonitorReceiver monitor = FakeMonitorReceiver(*mDispatcher, "M_1", ADISPLAY_ID_DEFAULT);
6307 FakeMonitorReceiver secondMonitor = FakeMonitorReceiver(*mDispatcher, "M_2", SECOND_DISPLAY_ID);
6308
6309 // There is a foreground window on both displays.
6310 mDispatcher->onWindowInfosChanged({{*window->getInfo(), *secondWindow->getInfo()}, {}, 0, 0});
6311 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
6312 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
6313 {100, 200}))
6314 << "The down event injected into the first display should succeed";
6315
6316 window->consumeMotionDown(ADISPLAY_ID_DEFAULT);
6317 monitor.consumeMotionDown(ADISPLAY_ID_DEFAULT);
Linnan Lid8150952024-01-26 18:07:17 +00006318
6319 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
6320 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, SECOND_DISPLAY_ID,
6321 {100, 200}))
6322 << "The down event injected into the second display should succeed";
6323
Linnan Lid8150952024-01-26 18:07:17 +00006324 secondWindow->consumeMotionDown(SECOND_DISPLAY_ID);
6325 secondMonitor.consumeMotionDown(SECOND_DISPLAY_ID);
6326
6327 // Now second window is gone away.
6328 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
6329
6330 // The gone window should receive a cancel, and the monitor on the second display should not
6331 // receive any events.
Linnan Lid8150952024-01-26 18:07:17 +00006332 secondWindow->consumeMotionCancel(SECOND_DISPLAY_ID);
6333 secondMonitor.assertNoEvents();
6334
6335 ASSERT_EQ(InputEventInjectionResult::FAILED,
6336 injectMotionEvent(*mDispatcher, AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN,
6337 SECOND_DISPLAY_ID, {110, 220}))
Prabir Pradhana0d43d42024-01-30 00:27:08 +00006338 << "The move event injected into the second display should fail because there's no "
6339 "touchable window";
Linnan Lid8150952024-01-26 18:07:17 +00006340 // Now the monitor on the second display should receive a cancel event.
6341 secondMonitor.consumeMotionCancel(SECOND_DISPLAY_ID);
Linnan Lid8150952024-01-26 18:07:17 +00006342
6343 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
6344 injectMotionEvent(*mDispatcher, AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN,
6345 ADISPLAY_ID_DEFAULT, {110, 200}))
6346 << "The move event injected into the first display should succeed";
6347
6348 window->consumeMotionMove();
6349 monitor.consumeMotionMove(ADISPLAY_ID_DEFAULT);
Linnan Lid8150952024-01-26 18:07:17 +00006350
6351 ASSERT_EQ(InputEventInjectionResult::FAILED,
Prabir Pradhana0d43d42024-01-30 00:27:08 +00006352 injectMotionUp(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, SECOND_DISPLAY_ID,
6353 {110, 220}))
6354 << "The up event injected into the second display should fail because there's no "
6355 "touchable window";
Linnan Lid8150952024-01-26 18:07:17 +00006356
6357 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
6358 injectMotionUp(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
6359 {110, 220}))
6360 << "The up event injected into the first display should succeed";
6361
6362 window->consumeMotionUp(ADISPLAY_ID_DEFAULT);
6363 monitor.consumeMotionUp(ADISPLAY_ID_DEFAULT);
Prabir Pradhana0d43d42024-01-30 00:27:08 +00006364
Linnan Lid8150952024-01-26 18:07:17 +00006365 window->assertNoEvents();
6366 monitor.assertNoEvents();
Prabir Pradhana0d43d42024-01-30 00:27:08 +00006367 secondWindow->assertNoEvents();
6368 secondMonitor.assertNoEvents();
Linnan Lid8150952024-01-26 18:07:17 +00006369}
6370
6371/**
6372 * One display with transform
6373 * There is a foreground window and a monitor on the display
6374 * Inject down event and move event sequentially, the foreground window and monitor can receive down
6375 * event and move event, then let the foreground window go away, the foreground window receives
6376 * cancel event, inject move event again, the monitor receives cancel event, all the events received
6377 * by the monitor should be with the same transform as the display
6378 */
6379TEST_F(InputDispatcherMonitorTest, MonitorTouchCancelEventWithDisplayTransform) {
6380 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
6381 sp<FakeWindowHandle> window =
6382 sp<FakeWindowHandle>::make(application, mDispatcher, "Foreground", ADISPLAY_ID_DEFAULT);
6383 FakeMonitorReceiver monitor = FakeMonitorReceiver(*mDispatcher, "M_1", ADISPLAY_ID_DEFAULT);
6384
6385 ui::Transform transform;
6386 transform.set({1.1, 2.2, 3.3, 4.4, 5.5, 6.6, 0, 0, 1});
6387
6388 gui::DisplayInfo displayInfo;
6389 displayInfo.displayId = ADISPLAY_ID_DEFAULT;
6390 displayInfo.transform = transform;
6391
6392 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {displayInfo}, 0, 0});
6393
6394 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
6395 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
6396 {100, 200}))
6397 << "The down event injected should succeed";
6398
6399 window->consumeMotionDown();
6400 std::unique_ptr<MotionEvent> downMotionEvent = monitor.consumeMotion();
6401 EXPECT_EQ(transform, downMotionEvent->getTransform());
6402 EXPECT_EQ(AMOTION_EVENT_ACTION_DOWN, downMotionEvent->getAction());
6403
6404 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
6405 injectMotionEvent(*mDispatcher, AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN,
6406 ADISPLAY_ID_DEFAULT, {110, 220}))
6407 << "The move event injected should succeed";
6408
6409 window->consumeMotionMove();
6410 std::unique_ptr<MotionEvent> moveMotionEvent = monitor.consumeMotion();
6411 EXPECT_EQ(transform, moveMotionEvent->getTransform());
6412 EXPECT_EQ(AMOTION_EVENT_ACTION_MOVE, moveMotionEvent->getAction());
6413
6414 // Let foreground window gone
6415 mDispatcher->onWindowInfosChanged({{}, {displayInfo}, 0, 0});
6416
Prabir Pradhana0d43d42024-01-30 00:27:08 +00006417 // Foreground window should receive a cancel event, but not the monitor.
Linnan Lid8150952024-01-26 18:07:17 +00006418 window->consumeMotionCancel();
Linnan Lid8150952024-01-26 18:07:17 +00006419
6420 ASSERT_EQ(InputEventInjectionResult::FAILED,
6421 injectMotionEvent(*mDispatcher, AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN,
6422 ADISPLAY_ID_DEFAULT, {110, 220}))
6423 << "The move event injected should failed";
6424 // Now foreground should not receive any events, but monitor should receive a cancel event
6425 // with transform that same as display's display.
Linnan Lid8150952024-01-26 18:07:17 +00006426 std::unique_ptr<MotionEvent> cancelMotionEvent = monitor.consumeMotion();
6427 EXPECT_EQ(transform, cancelMotionEvent->getTransform());
6428 EXPECT_EQ(ADISPLAY_ID_DEFAULT, cancelMotionEvent->getDisplayId());
6429 EXPECT_EQ(AMOTION_EVENT_ACTION_CANCEL, cancelMotionEvent->getAction());
6430
6431 // Other event inject to this display should fail.
6432 ASSERT_EQ(InputEventInjectionResult::FAILED,
6433 injectMotionEvent(*mDispatcher, AMOTION_EVENT_ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN,
6434 ADISPLAY_ID_DEFAULT, {110, 220}))
Prabir Pradhana0d43d42024-01-30 00:27:08 +00006435 << "The up event injected should fail because the touched window was removed";
Linnan Lid8150952024-01-26 18:07:17 +00006436 window->assertNoEvents();
6437 monitor.assertNoEvents();
6438}
6439
chaviw81e2bb92019-12-18 15:03:51 -08006440TEST_F(InputDispatcherTest, TestMoveEvent) {
Chris Yea209fde2020-07-22 13:54:51 -07006441 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07006442 sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher,
6443 "Fake Window", ADISPLAY_ID_DEFAULT);
chaviw81e2bb92019-12-18 15:03:51 -08006444
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07006445 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
chaviw81e2bb92019-12-18 15:03:51 -08006446
6447 NotifyMotionArgs motionArgs =
6448 generateMotionArgs(AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN,
6449 ADISPLAY_ID_DEFAULT);
6450
Prabir Pradhan678438e2023-04-13 19:32:51 +00006451 mDispatcher->notifyMotion(motionArgs);
chaviw81e2bb92019-12-18 15:03:51 -08006452 // Window should receive motion down event.
6453 window->consumeMotionDown(ADISPLAY_ID_DEFAULT);
6454
6455 motionArgs.action = AMOTION_EVENT_ACTION_MOVE;
Garfield Tanc51d1ba2020-01-28 13:24:04 -08006456 motionArgs.id += 1;
chaviw81e2bb92019-12-18 15:03:51 -08006457 motionArgs.eventTime = systemTime(SYSTEM_TIME_MONOTONIC);
6458 motionArgs.pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_X,
6459 motionArgs.pointerCoords[0].getX() - 10);
6460
Prabir Pradhan678438e2023-04-13 19:32:51 +00006461 mDispatcher->notifyMotion(motionArgs);
Prabir Pradhan7662a8d2023-12-15 01:58:14 +00006462 window->consumeMotionMove(ADISPLAY_ID_DEFAULT, /*expectedFlags=*/0);
chaviw81e2bb92019-12-18 15:03:51 -08006463}
6464
Siarhei Vishniakouf1035d42019-09-20 16:32:01 +01006465/**
6466 * Dispatcher has touch mode enabled by default. Typically, the policy overrides that value to
6467 * the device default right away. In the test scenario, we check both the default value,
6468 * and the action of enabling / disabling.
6469 */
6470TEST_F(InputDispatcherTest, TouchModeState_IsSentToApps) {
Chris Yea209fde2020-07-22 13:54:51 -07006471 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07006472 sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher,
6473 "Test window", ADISPLAY_ID_DEFAULT);
Antonio Kantekea47acb2021-12-23 12:41:25 -08006474 const WindowInfo& windowInfo = *window->getInfo();
Siarhei Vishniakouf1035d42019-09-20 16:32:01 +01006475
6476 // Set focused application.
6477 mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application);
Vishnu Nair47074b82020-08-14 11:54:47 -07006478 window->setFocusable(true);
Siarhei Vishniakouf1035d42019-09-20 16:32:01 +01006479
6480 SCOPED_TRACE("Check default value of touch mode");
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07006481 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Vishnu Nair958da932020-08-21 17:12:37 -07006482 setFocusedWindow(window);
Harry Cutts33476232023-01-30 19:57:29 +00006483 window->consumeFocusEvent(/*hasFocus=*/true, /*inTouchMode=*/true);
Siarhei Vishniakouf1035d42019-09-20 16:32:01 +01006484
6485 SCOPED_TRACE("Remove the window to trigger focus loss");
Vishnu Nair47074b82020-08-14 11:54:47 -07006486 window->setFocusable(false);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07006487 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Harry Cutts33476232023-01-30 19:57:29 +00006488 window->consumeFocusEvent(/*hasFocus=*/false, /*inTouchMode=*/true);
Siarhei Vishniakouf1035d42019-09-20 16:32:01 +01006489
6490 SCOPED_TRACE("Disable touch mode");
Antonio Kantekea47acb2021-12-23 12:41:25 -08006491 mDispatcher->setInTouchMode(false, windowInfo.ownerPid, windowInfo.ownerUid,
Harry Cutts33476232023-01-30 19:57:29 +00006492 /*hasPermission=*/true, ADISPLAY_ID_DEFAULT);
Antonio Kantekf16f2832021-09-28 04:39:20 +00006493 window->consumeTouchModeEvent(false);
Vishnu Nair47074b82020-08-14 11:54:47 -07006494 window->setFocusable(true);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07006495 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Vishnu Nair958da932020-08-21 17:12:37 -07006496 setFocusedWindow(window);
Harry Cutts33476232023-01-30 19:57:29 +00006497 window->consumeFocusEvent(/*hasFocus=*/true, /*inTouchMode=*/false);
Siarhei Vishniakouf1035d42019-09-20 16:32:01 +01006498
6499 SCOPED_TRACE("Remove the window to trigger focus loss");
Vishnu Nair47074b82020-08-14 11:54:47 -07006500 window->setFocusable(false);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07006501 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Harry Cutts33476232023-01-30 19:57:29 +00006502 window->consumeFocusEvent(/*hasFocus=*/false, /*inTouchMode=*/false);
Siarhei Vishniakouf1035d42019-09-20 16:32:01 +01006503
6504 SCOPED_TRACE("Enable touch mode again");
Antonio Kantekea47acb2021-12-23 12:41:25 -08006505 mDispatcher->setInTouchMode(true, windowInfo.ownerPid, windowInfo.ownerUid,
Harry Cutts33476232023-01-30 19:57:29 +00006506 /*hasPermission=*/true, ADISPLAY_ID_DEFAULT);
Antonio Kantekf16f2832021-09-28 04:39:20 +00006507 window->consumeTouchModeEvent(true);
Vishnu Nair47074b82020-08-14 11:54:47 -07006508 window->setFocusable(true);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07006509 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Vishnu Nair958da932020-08-21 17:12:37 -07006510 setFocusedWindow(window);
Harry Cutts33476232023-01-30 19:57:29 +00006511 window->consumeFocusEvent(/*hasFocus=*/true, /*inTouchMode=*/true);
Siarhei Vishniakouf1035d42019-09-20 16:32:01 +01006512
6513 window->assertNoEvents();
6514}
6515
Gang Wange9087892020-01-07 12:17:14 -05006516TEST_F(InputDispatcherTest, VerifyInputEvent_KeyEvent) {
Chris Yea209fde2020-07-22 13:54:51 -07006517 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07006518 sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher,
6519 "Test window", ADISPLAY_ID_DEFAULT);
Gang Wange9087892020-01-07 12:17:14 -05006520
6521 mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application);
Vishnu Nair47074b82020-08-14 11:54:47 -07006522 window->setFocusable(true);
Gang Wange9087892020-01-07 12:17:14 -05006523
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07006524 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Vishnu Nair958da932020-08-21 17:12:37 -07006525 setFocusedWindow(window);
6526
Harry Cutts33476232023-01-30 19:57:29 +00006527 window->consumeFocusEvent(/*hasFocus=*/true, /*inTouchMode=*/true);
Gang Wange9087892020-01-07 12:17:14 -05006528
Prabir Pradhan678438e2023-04-13 19:32:51 +00006529 const NotifyKeyArgs keyArgs = generateKeyArgs(AKEY_EVENT_ACTION_DOWN);
6530 mDispatcher->notifyKey(keyArgs);
Gang Wange9087892020-01-07 12:17:14 -05006531
Siarhei Vishniakoud3061ab2023-12-18 20:41:08 -08006532 std::unique_ptr<KeyEvent> event = window->consumeKey();
6533 ASSERT_NE(event, nullptr);
6534 std::unique_ptr<VerifiedInputEvent> verified = mDispatcher->verifyInputEvent(*event);
Gang Wange9087892020-01-07 12:17:14 -05006535 ASSERT_NE(verified, nullptr);
6536 ASSERT_EQ(verified->type, VerifiedInputEvent::Type::KEY);
6537
6538 ASSERT_EQ(keyArgs.eventTime, verified->eventTimeNanos);
6539 ASSERT_EQ(keyArgs.deviceId, verified->deviceId);
6540 ASSERT_EQ(keyArgs.source, verified->source);
6541 ASSERT_EQ(keyArgs.displayId, verified->displayId);
6542
6543 const VerifiedKeyEvent& verifiedKey = static_cast<const VerifiedKeyEvent&>(*verified);
6544
6545 ASSERT_EQ(keyArgs.action, verifiedKey.action);
Gang Wange9087892020-01-07 12:17:14 -05006546 ASSERT_EQ(keyArgs.flags & VERIFIED_KEY_EVENT_FLAGS, verifiedKey.flags);
Siarhei Vishniakouf355bf92021-12-09 10:43:21 -08006547 ASSERT_EQ(keyArgs.downTime, verifiedKey.downTimeNanos);
Gang Wange9087892020-01-07 12:17:14 -05006548 ASSERT_EQ(keyArgs.keyCode, verifiedKey.keyCode);
6549 ASSERT_EQ(keyArgs.scanCode, verifiedKey.scanCode);
6550 ASSERT_EQ(keyArgs.metaState, verifiedKey.metaState);
6551 ASSERT_EQ(0, verifiedKey.repeatCount);
6552}
6553
Siarhei Vishniakou47040bf2020-02-28 15:03:13 -08006554TEST_F(InputDispatcherTest, VerifyInputEvent_MotionEvent) {
Chris Yea209fde2020-07-22 13:54:51 -07006555 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07006556 sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher,
6557 "Test window", ADISPLAY_ID_DEFAULT);
Siarhei Vishniakou47040bf2020-02-28 15:03:13 -08006558
6559 mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application);
6560
Prabir Pradhanb5cb9572021-09-24 06:35:16 -07006561 ui::Transform transform;
6562 transform.set({1.1, 2.2, 3.3, 4.4, 5.5, 6.6, 0, 0, 1});
6563
6564 gui::DisplayInfo displayInfo;
6565 displayInfo.displayId = ADISPLAY_ID_DEFAULT;
6566 displayInfo.transform = transform;
6567
Patrick Williamsd828f302023-04-28 17:52:08 -05006568 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {displayInfo}, 0, 0});
Siarhei Vishniakou47040bf2020-02-28 15:03:13 -08006569
Prabir Pradhan678438e2023-04-13 19:32:51 +00006570 const NotifyMotionArgs motionArgs =
Siarhei Vishniakou47040bf2020-02-28 15:03:13 -08006571 generateMotionArgs(AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN,
6572 ADISPLAY_ID_DEFAULT);
Prabir Pradhan678438e2023-04-13 19:32:51 +00006573 mDispatcher->notifyMotion(motionArgs);
Siarhei Vishniakou47040bf2020-02-28 15:03:13 -08006574
Siarhei Vishniakoud3061ab2023-12-18 20:41:08 -08006575 std::unique_ptr<MotionEvent> event = window->consumeMotionEvent();
6576 ASSERT_NE(nullptr, event);
6577 std::unique_ptr<VerifiedInputEvent> verified = mDispatcher->verifyInputEvent(*event);
Siarhei Vishniakou47040bf2020-02-28 15:03:13 -08006578 ASSERT_NE(verified, nullptr);
6579 ASSERT_EQ(verified->type, VerifiedInputEvent::Type::MOTION);
6580
6581 EXPECT_EQ(motionArgs.eventTime, verified->eventTimeNanos);
6582 EXPECT_EQ(motionArgs.deviceId, verified->deviceId);
6583 EXPECT_EQ(motionArgs.source, verified->source);
6584 EXPECT_EQ(motionArgs.displayId, verified->displayId);
6585
6586 const VerifiedMotionEvent& verifiedMotion = static_cast<const VerifiedMotionEvent&>(*verified);
6587
Prabir Pradhanb5cb9572021-09-24 06:35:16 -07006588 const vec2 rawXY =
6589 MotionEvent::calculateTransformedXY(motionArgs.source, transform,
6590 motionArgs.pointerCoords[0].getXYValue());
6591 EXPECT_EQ(rawXY.x, verifiedMotion.rawX);
6592 EXPECT_EQ(rawXY.y, verifiedMotion.rawY);
Siarhei Vishniakou47040bf2020-02-28 15:03:13 -08006593 EXPECT_EQ(motionArgs.action & AMOTION_EVENT_ACTION_MASK, verifiedMotion.actionMasked);
Siarhei Vishniakou47040bf2020-02-28 15:03:13 -08006594 EXPECT_EQ(motionArgs.flags & VERIFIED_MOTION_EVENT_FLAGS, verifiedMotion.flags);
Siarhei Vishniakouf355bf92021-12-09 10:43:21 -08006595 EXPECT_EQ(motionArgs.downTime, verifiedMotion.downTimeNanos);
Siarhei Vishniakou47040bf2020-02-28 15:03:13 -08006596 EXPECT_EQ(motionArgs.metaState, verifiedMotion.metaState);
6597 EXPECT_EQ(motionArgs.buttonState, verifiedMotion.buttonState);
6598}
6599
chaviw09c8d2d2020-08-24 15:48:26 -07006600/**
6601 * Ensure that separate calls to sign the same data are generating the same key.
6602 * We avoid asserting against INVALID_HMAC. Since the key is random, there is a non-zero chance
6603 * that a specific key and data combination would produce INVALID_HMAC, which would cause flaky
6604 * tests.
6605 */
6606TEST_F(InputDispatcherTest, GeneratedHmac_IsConsistent) {
6607 KeyEvent event = getTestKeyEvent();
6608 VerifiedKeyEvent verifiedEvent = verifiedKeyEventFromKeyEvent(event);
6609
6610 std::array<uint8_t, 32> hmac1 = mDispatcher->sign(verifiedEvent);
6611 std::array<uint8_t, 32> hmac2 = mDispatcher->sign(verifiedEvent);
6612 ASSERT_EQ(hmac1, hmac2);
6613}
6614
6615/**
6616 * Ensure that changes in VerifiedKeyEvent produce a different hmac.
6617 */
6618TEST_F(InputDispatcherTest, GeneratedHmac_ChangesWhenFieldsChange) {
6619 KeyEvent event = getTestKeyEvent();
6620 VerifiedKeyEvent verifiedEvent = verifiedKeyEventFromKeyEvent(event);
6621 std::array<uint8_t, 32> initialHmac = mDispatcher->sign(verifiedEvent);
6622
6623 verifiedEvent.deviceId += 1;
6624 ASSERT_NE(initialHmac, mDispatcher->sign(verifiedEvent));
6625
6626 verifiedEvent.source += 1;
6627 ASSERT_NE(initialHmac, mDispatcher->sign(verifiedEvent));
6628
6629 verifiedEvent.eventTimeNanos += 1;
6630 ASSERT_NE(initialHmac, mDispatcher->sign(verifiedEvent));
6631
6632 verifiedEvent.displayId += 1;
6633 ASSERT_NE(initialHmac, mDispatcher->sign(verifiedEvent));
6634
6635 verifiedEvent.action += 1;
6636 ASSERT_NE(initialHmac, mDispatcher->sign(verifiedEvent));
6637
6638 verifiedEvent.downTimeNanos += 1;
6639 ASSERT_NE(initialHmac, mDispatcher->sign(verifiedEvent));
6640
6641 verifiedEvent.flags += 1;
6642 ASSERT_NE(initialHmac, mDispatcher->sign(verifiedEvent));
6643
6644 verifiedEvent.keyCode += 1;
6645 ASSERT_NE(initialHmac, mDispatcher->sign(verifiedEvent));
6646
6647 verifiedEvent.scanCode += 1;
6648 ASSERT_NE(initialHmac, mDispatcher->sign(verifiedEvent));
6649
6650 verifiedEvent.metaState += 1;
6651 ASSERT_NE(initialHmac, mDispatcher->sign(verifiedEvent));
6652
6653 verifiedEvent.repeatCount += 1;
6654 ASSERT_NE(initialHmac, mDispatcher->sign(verifiedEvent));
6655}
6656
Vishnu Nair958da932020-08-21 17:12:37 -07006657TEST_F(InputDispatcherTest, SetFocusedWindow) {
6658 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
6659 sp<FakeWindowHandle> windowTop =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07006660 sp<FakeWindowHandle>::make(application, mDispatcher, "Top", ADISPLAY_ID_DEFAULT);
Vishnu Nair958da932020-08-21 17:12:37 -07006661 sp<FakeWindowHandle> windowSecond =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07006662 sp<FakeWindowHandle>::make(application, mDispatcher, "Second", ADISPLAY_ID_DEFAULT);
Vishnu Nair958da932020-08-21 17:12:37 -07006663 mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application);
6664
6665 // Top window is also focusable but is not granted focus.
6666 windowTop->setFocusable(true);
6667 windowSecond->setFocusable(true);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07006668 mDispatcher->onWindowInfosChanged(
6669 {{*windowTop->getInfo(), *windowSecond->getInfo()}, {}, 0, 0});
Vishnu Nair958da932020-08-21 17:12:37 -07006670 setFocusedWindow(windowSecond);
6671
6672 windowSecond->consumeFocusEvent(true);
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07006673 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectKeyDown(*mDispatcher))
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08006674 << "Inject key event should return InputEventInjectionResult::SUCCEEDED";
Vishnu Nair958da932020-08-21 17:12:37 -07006675
6676 // Focused window should receive event.
6677 windowSecond->consumeKeyDown(ADISPLAY_ID_NONE);
6678 windowTop->assertNoEvents();
6679}
6680
6681TEST_F(InputDispatcherTest, SetFocusedWindow_DropRequestInvalidChannel) {
6682 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
6683 sp<FakeWindowHandle> window =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07006684 sp<FakeWindowHandle>::make(application, mDispatcher, "TestWindow", ADISPLAY_ID_DEFAULT);
Vishnu Nair958da932020-08-21 17:12:37 -07006685 mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application);
6686
6687 window->setFocusable(true);
6688 // Release channel for window is no longer valid.
6689 window->releaseChannel();
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07006690 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Vishnu Nair958da932020-08-21 17:12:37 -07006691 setFocusedWindow(window);
6692
6693 // Test inject a key down, should timeout.
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07006694 ASSERT_NO_FATAL_FAILURE(assertInjectedKeyTimesOut(*mDispatcher));
Vishnu Nair958da932020-08-21 17:12:37 -07006695
6696 // window channel is invalid, so it should not receive any input event.
6697 window->assertNoEvents();
6698}
6699
6700TEST_F(InputDispatcherTest, SetFocusedWindow_DropRequestNoFocusableWindow) {
6701 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
6702 sp<FakeWindowHandle> window =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07006703 sp<FakeWindowHandle>::make(application, mDispatcher, "TestWindow", ADISPLAY_ID_DEFAULT);
Prabir Pradhan76bdecb2022-01-31 11:14:15 -08006704 window->setFocusable(false);
Vishnu Nair958da932020-08-21 17:12:37 -07006705 mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application);
6706
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07006707 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Vishnu Nair958da932020-08-21 17:12:37 -07006708 setFocusedWindow(window);
6709
6710 // Test inject a key down, should timeout.
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07006711 ASSERT_NO_FATAL_FAILURE(assertInjectedKeyTimesOut(*mDispatcher));
Vishnu Nair958da932020-08-21 17:12:37 -07006712
Prabir Pradhan76bdecb2022-01-31 11:14:15 -08006713 // window is not focusable, so it should not receive any input event.
Vishnu Nair958da932020-08-21 17:12:37 -07006714 window->assertNoEvents();
6715}
6716
6717TEST_F(InputDispatcherTest, SetFocusedWindow_CheckFocusedToken) {
6718 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
6719 sp<FakeWindowHandle> windowTop =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07006720 sp<FakeWindowHandle>::make(application, mDispatcher, "Top", ADISPLAY_ID_DEFAULT);
Vishnu Nair958da932020-08-21 17:12:37 -07006721 sp<FakeWindowHandle> windowSecond =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07006722 sp<FakeWindowHandle>::make(application, mDispatcher, "Second", ADISPLAY_ID_DEFAULT);
Vishnu Nair958da932020-08-21 17:12:37 -07006723 mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application);
6724
6725 windowTop->setFocusable(true);
6726 windowSecond->setFocusable(true);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07006727 mDispatcher->onWindowInfosChanged(
6728 {{*windowTop->getInfo(), *windowSecond->getInfo()}, {}, 0, 0});
Vishnu Nair958da932020-08-21 17:12:37 -07006729 setFocusedWindow(windowTop);
6730 windowTop->consumeFocusEvent(true);
6731
Chavi Weingarten847e8512023-03-29 00:26:09 +00006732 windowTop->editInfo()->focusTransferTarget = windowSecond->getToken();
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07006733 mDispatcher->onWindowInfosChanged(
6734 {{*windowTop->getInfo(), *windowSecond->getInfo()}, {}, 0, 0});
Vishnu Nair958da932020-08-21 17:12:37 -07006735 windowSecond->consumeFocusEvent(true);
6736 windowTop->consumeFocusEvent(false);
6737
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07006738 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectKeyDown(*mDispatcher))
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08006739 << "Inject key event should return InputEventInjectionResult::SUCCEEDED";
Vishnu Nair958da932020-08-21 17:12:37 -07006740
6741 // Focused window should receive event.
6742 windowSecond->consumeKeyDown(ADISPLAY_ID_NONE);
6743}
6744
Chavi Weingarten847e8512023-03-29 00:26:09 +00006745TEST_F(InputDispatcherTest, SetFocusedWindow_TransferFocusTokenNotFocusable) {
Vishnu Nair958da932020-08-21 17:12:37 -07006746 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
6747 sp<FakeWindowHandle> windowTop =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07006748 sp<FakeWindowHandle>::make(application, mDispatcher, "Top", ADISPLAY_ID_DEFAULT);
Vishnu Nair958da932020-08-21 17:12:37 -07006749 sp<FakeWindowHandle> windowSecond =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07006750 sp<FakeWindowHandle>::make(application, mDispatcher, "Second", ADISPLAY_ID_DEFAULT);
Vishnu Nair958da932020-08-21 17:12:37 -07006751 mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application);
6752
6753 windowTop->setFocusable(true);
Chavi Weingarten847e8512023-03-29 00:26:09 +00006754 windowSecond->setFocusable(false);
6755 windowTop->editInfo()->focusTransferTarget = windowSecond->getToken();
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07006756 mDispatcher->onWindowInfosChanged(
6757 {{*windowTop->getInfo(), *windowSecond->getInfo()}, {}, 0, 0});
Chavi Weingarten847e8512023-03-29 00:26:09 +00006758 setFocusedWindow(windowTop);
6759 windowTop->consumeFocusEvent(true);
Vishnu Nair958da932020-08-21 17:12:37 -07006760
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07006761 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectKeyDown(*mDispatcher))
Chavi Weingarten847e8512023-03-29 00:26:09 +00006762 << "Inject key event should return InputEventInjectionResult::SUCCEEDED";
Vishnu Nair958da932020-08-21 17:12:37 -07006763
6764 // Event should be dropped.
Chavi Weingarten847e8512023-03-29 00:26:09 +00006765 windowTop->consumeKeyDown(ADISPLAY_ID_NONE);
Vishnu Nair958da932020-08-21 17:12:37 -07006766 windowSecond->assertNoEvents();
6767}
6768
6769TEST_F(InputDispatcherTest, SetFocusedWindow_DeferInvisibleWindow) {
6770 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
6771 sp<FakeWindowHandle> window =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07006772 sp<FakeWindowHandle>::make(application, mDispatcher, "TestWindow", ADISPLAY_ID_DEFAULT);
Vishnu Nair958da932020-08-21 17:12:37 -07006773 sp<FakeWindowHandle> previousFocusedWindow =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07006774 sp<FakeWindowHandle>::make(application, mDispatcher, "previousFocusedWindow",
6775 ADISPLAY_ID_DEFAULT);
Vishnu Nair958da932020-08-21 17:12:37 -07006776 mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application);
6777
6778 window->setFocusable(true);
6779 previousFocusedWindow->setFocusable(true);
6780 window->setVisible(false);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07006781 mDispatcher->onWindowInfosChanged(
6782 {{*window->getInfo(), *previousFocusedWindow->getInfo()}, {}, 0, 0});
Vishnu Nair958da932020-08-21 17:12:37 -07006783 setFocusedWindow(previousFocusedWindow);
6784 previousFocusedWindow->consumeFocusEvent(true);
6785
6786 // Requesting focus on invisible window takes focus from currently focused window.
6787 setFocusedWindow(window);
6788 previousFocusedWindow->consumeFocusEvent(false);
6789
6790 // Injected key goes to pending queue.
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08006791 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07006792 injectKey(*mDispatcher, AKEY_EVENT_ACTION_DOWN, /*repeatCount=*/0,
6793 ADISPLAY_ID_DEFAULT, InputEventInjectionSync::NONE));
Vishnu Nair958da932020-08-21 17:12:37 -07006794
6795 // Window does not get focus event or key down.
6796 window->assertNoEvents();
6797
6798 // Window becomes visible.
6799 window->setVisible(true);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07006800 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Vishnu Nair958da932020-08-21 17:12:37 -07006801
6802 // Window receives focus event.
6803 window->consumeFocusEvent(true);
6804 // Focused window receives key down.
6805 window->consumeKeyDown(ADISPLAY_ID_DEFAULT);
6806}
6807
Vishnu Nair599f1412021-06-21 10:39:58 -07006808TEST_F(InputDispatcherTest, DisplayRemoved) {
6809 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
6810 sp<FakeWindowHandle> window =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07006811 sp<FakeWindowHandle>::make(application, mDispatcher, "window", ADISPLAY_ID_DEFAULT);
Vishnu Nair599f1412021-06-21 10:39:58 -07006812 mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application);
6813
6814 // window is granted focus.
6815 window->setFocusable(true);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07006816 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Vishnu Nair599f1412021-06-21 10:39:58 -07006817 setFocusedWindow(window);
6818 window->consumeFocusEvent(true);
6819
6820 // When a display is removed window loses focus.
6821 mDispatcher->displayRemoved(ADISPLAY_ID_DEFAULT);
6822 window->consumeFocusEvent(false);
6823}
6824
Siarhei Vishniakou870ecec2020-12-09 08:07:46 -10006825/**
6826 * Launch two windows, with different owners. One window (slipperyExitWindow) has Flag::SLIPPERY,
6827 * and overlaps the other window, slipperyEnterWindow. The window 'slipperyExitWindow' is on top
6828 * of the 'slipperyEnterWindow'.
6829 *
6830 * Inject touch down into the top window. Upon receipt of the DOWN event, move the window in such
6831 * a way so that the touched location is no longer covered by the top window.
6832 *
6833 * Next, inject a MOVE event. Because the top window already moved earlier, this event is now
6834 * positioned over the bottom (slipperyEnterWindow) only. And because the top window had
6835 * Flag::SLIPPERY, this will cause the top window to lose the touch event (it will receive
6836 * ACTION_CANCEL instead), and the bottom window will receive a newly generated gesture (starting
6837 * with ACTION_DOWN).
6838 * Thus, the touch has been transferred from the top window into the bottom window, because the top
6839 * window moved itself away from the touched location and had Flag::SLIPPERY.
6840 *
6841 * Even though the top window moved away from the touched location, it is still obscuring the bottom
6842 * window. It's just not obscuring it at the touched location. That means, FLAG_WINDOW_IS_PARTIALLY_
6843 * OBSCURED should be set for the MotionEvent that reaches the bottom window.
6844 *
6845 * In this test, we ensure that the event received by the bottom window has
6846 * FLAG_WINDOW_IS_PARTIALLY_OBSCURED.
6847 */
6848TEST_F(InputDispatcherTest, SlipperyWindow_SetsFlagPartiallyObscured) {
Prabir Pradhanaeebeb42023-06-13 19:53:03 +00006849 constexpr gui::Pid SLIPPERY_PID{WINDOW_PID.val() + 1};
Prabir Pradhan8a5c41d2023-06-08 19:13:46 +00006850 constexpr gui::Uid SLIPPERY_UID{WINDOW_UID.val() + 1};
Siarhei Vishniakou870ecec2020-12-09 08:07:46 -10006851
6852 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
6853 mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application);
6854
6855 sp<FakeWindowHandle> slipperyExitWindow =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07006856 sp<FakeWindowHandle>::make(application, mDispatcher, "Top", ADISPLAY_ID_DEFAULT);
Prabir Pradhan4d5c52f2022-01-31 08:52:10 -08006857 slipperyExitWindow->setSlippery(true);
Siarhei Vishniakou870ecec2020-12-09 08:07:46 -10006858 // Make sure this one overlaps the bottom window
6859 slipperyExitWindow->setFrame(Rect(25, 25, 75, 75));
6860 // Change the owner uid/pid of the window so that it is considered to be occluding the bottom
6861 // one. Windows with the same owner are not considered to be occluding each other.
6862 slipperyExitWindow->setOwnerInfo(SLIPPERY_PID, SLIPPERY_UID);
6863
6864 sp<FakeWindowHandle> slipperyEnterWindow =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07006865 sp<FakeWindowHandle>::make(application, mDispatcher, "Second", ADISPLAY_ID_DEFAULT);
Siarhei Vishniakou870ecec2020-12-09 08:07:46 -10006866 slipperyExitWindow->setFrame(Rect(0, 0, 100, 100));
6867
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07006868 mDispatcher->onWindowInfosChanged(
6869 {{*slipperyExitWindow->getInfo(), *slipperyEnterWindow->getInfo()}, {}, 0, 0});
Siarhei Vishniakou870ecec2020-12-09 08:07:46 -10006870
6871 // Use notifyMotion instead of injecting to avoid dealing with injection permissions
Prabir Pradhan678438e2023-04-13 19:32:51 +00006872 mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_DOWN,
6873 AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
6874 {{50, 50}}));
Siarhei Vishniakou870ecec2020-12-09 08:07:46 -10006875 slipperyExitWindow->consumeMotionDown();
6876 slipperyExitWindow->setFrame(Rect(70, 70, 100, 100));
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07006877 mDispatcher->onWindowInfosChanged(
6878 {{*slipperyExitWindow->getInfo(), *slipperyEnterWindow->getInfo()}, {}, 0, 0});
Siarhei Vishniakou870ecec2020-12-09 08:07:46 -10006879
Prabir Pradhan678438e2023-04-13 19:32:51 +00006880 mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_MOVE,
6881 AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
6882 {{51, 51}}));
Siarhei Vishniakou870ecec2020-12-09 08:07:46 -10006883
6884 slipperyExitWindow->consumeMotionCancel();
6885
6886 slipperyEnterWindow->consumeMotionDown(ADISPLAY_ID_DEFAULT,
6887 AMOTION_EVENT_FLAG_WINDOW_IS_PARTIALLY_OBSCURED);
6888}
6889
Siarhei Vishniakouafa08cc2023-05-08 22:35:50 -07006890/**
6891 * Two windows, one on the left and another on the right. The left window is slippery. The right
6892 * window isn't eligible to receive touch because it specifies InputConfig::DROP_INPUT. When the
6893 * touch moves from the left window into the right window, the gesture should continue to go to the
6894 * left window. Touch shouldn't slip because the right window can't receive touches. This test
6895 * reproduces a crash.
6896 */
6897TEST_F(InputDispatcherTest, TouchSlippingIntoWindowThatDropsTouches) {
6898 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
6899
6900 sp<FakeWindowHandle> leftSlipperyWindow =
6901 sp<FakeWindowHandle>::make(application, mDispatcher, "Left", ADISPLAY_ID_DEFAULT);
6902 leftSlipperyWindow->setSlippery(true);
6903 leftSlipperyWindow->setFrame(Rect(0, 0, 100, 100));
6904
6905 sp<FakeWindowHandle> rightDropTouchesWindow =
6906 sp<FakeWindowHandle>::make(application, mDispatcher, "Right", ADISPLAY_ID_DEFAULT);
6907 rightDropTouchesWindow->setFrame(Rect(100, 0, 200, 100));
6908 rightDropTouchesWindow->setDropInput(true);
6909
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07006910 mDispatcher->onWindowInfosChanged(
6911 {{*leftSlipperyWindow->getInfo(), *rightDropTouchesWindow->getInfo()}, {}, 0, 0});
Siarhei Vishniakouafa08cc2023-05-08 22:35:50 -07006912
6913 // Start touch in the left window
6914 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
6915 .pointer(PointerBuilder(0, ToolType::FINGER).x(50).y(50))
6916 .build());
6917 leftSlipperyWindow->consumeMotionDown();
6918
6919 // And move it into the right window
6920 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN)
6921 .pointer(PointerBuilder(0, ToolType::FINGER).x(150).y(50))
6922 .build());
6923
6924 // Since the right window isn't eligible to receive input, touch does not slip.
6925 // The left window continues to receive the gesture.
6926 leftSlipperyWindow->consumeMotionEvent(WithMotionAction(ACTION_MOVE));
6927 rightDropTouchesWindow->assertNoEvents();
6928}
6929
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -07006930/**
6931 * A single window is on screen first. Touch is injected into that window. Next, a second window
6932 * appears. Since the first window is slippery, touch will move from the first window to the second.
6933 */
6934TEST_F(InputDispatcherTest, InjectedTouchSlips) {
6935 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
6936 sp<FakeWindowHandle> originalWindow =
6937 sp<FakeWindowHandle>::make(application, mDispatcher, "Original", ADISPLAY_ID_DEFAULT);
6938 originalWindow->setFrame(Rect(0, 0, 200, 200));
6939 originalWindow->setSlippery(true);
6940
6941 sp<FakeWindowHandle> appearingWindow =
6942 sp<FakeWindowHandle>::make(application, mDispatcher, "Appearing", ADISPLAY_ID_DEFAULT);
6943 appearingWindow->setFrame(Rect(0, 0, 200, 200));
6944
6945 mDispatcher->onWindowInfosChanged({{*originalWindow->getInfo()}, {}, 0, 0});
6946
6947 // Touch down on the original window
6948 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
6949 injectMotionEvent(*mDispatcher,
6950 MotionEventBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
6951 .pointer(PointerBuilder(1, ToolType::FINGER).x(100).y(100))
6952 .build()));
6953 originalWindow->consumeMotionEvent(WithMotionAction(ACTION_DOWN));
6954
6955 // Now, a new window appears. This could be, for example, a notification shade that appears
6956 // after user starts to drag down on the launcher window.
6957 mDispatcher->onWindowInfosChanged(
6958 {{*appearingWindow->getInfo(), *originalWindow->getInfo()}, {}, 0, 0});
6959 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
6960 injectMotionEvent(*mDispatcher,
6961 MotionEventBuilder(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN)
6962 .pointer(PointerBuilder(1, ToolType::FINGER).x(110).y(110))
6963 .build()));
6964 originalWindow->consumeMotionEvent(WithMotionAction(ACTION_CANCEL));
6965 appearingWindow->consumeMotionEvent(WithMotionAction(ACTION_DOWN));
6966 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
6967 injectMotionEvent(*mDispatcher,
6968 MotionEventBuilder(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN)
6969 .pointer(PointerBuilder(1, ToolType::FINGER).x(120).y(120))
6970 .build()));
6971 appearingWindow->consumeMotionEvent(WithMotionAction(ACTION_MOVE));
6972
6973 originalWindow->assertNoEvents();
6974 appearingWindow->assertNoEvents();
6975}
6976
Prabir Pradhan8ede1d12023-05-08 19:37:44 +00006977TEST_F(InputDispatcherTest, NotifiesDeviceInteractionsWithMotions) {
Prabir Pradhan8a5c41d2023-06-08 19:13:46 +00006978 using Uid = gui::Uid;
Prabir Pradhan8ede1d12023-05-08 19:37:44 +00006979 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
6980
6981 sp<FakeWindowHandle> leftWindow =
6982 sp<FakeWindowHandle>::make(application, mDispatcher, "Left", ADISPLAY_ID_DEFAULT);
6983 leftWindow->setFrame(Rect(0, 0, 100, 100));
Prabir Pradhanaeebeb42023-06-13 19:53:03 +00006984 leftWindow->setOwnerInfo(gui::Pid{1}, Uid{101});
Prabir Pradhan8ede1d12023-05-08 19:37:44 +00006985
6986 sp<FakeWindowHandle> rightSpy =
6987 sp<FakeWindowHandle>::make(application, mDispatcher, "Right spy", ADISPLAY_ID_DEFAULT);
6988 rightSpy->setFrame(Rect(100, 0, 200, 100));
Prabir Pradhanaeebeb42023-06-13 19:53:03 +00006989 rightSpy->setOwnerInfo(gui::Pid{2}, Uid{102});
Prabir Pradhan8ede1d12023-05-08 19:37:44 +00006990 rightSpy->setSpy(true);
6991 rightSpy->setTrustedOverlay(true);
6992
6993 sp<FakeWindowHandle> rightWindow =
6994 sp<FakeWindowHandle>::make(application, mDispatcher, "Right", ADISPLAY_ID_DEFAULT);
6995 rightWindow->setFrame(Rect(100, 0, 200, 100));
Prabir Pradhanaeebeb42023-06-13 19:53:03 +00006996 rightWindow->setOwnerInfo(gui::Pid{3}, Uid{103});
Prabir Pradhan8ede1d12023-05-08 19:37:44 +00006997
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07006998 mDispatcher->onWindowInfosChanged(
6999 {{*rightSpy->getInfo(), *rightWindow->getInfo(), *leftWindow->getInfo()}, {}, 0, 0});
Prabir Pradhan8ede1d12023-05-08 19:37:44 +00007000
7001 // Touch in the left window
7002 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
7003 .pointer(PointerBuilder(0, ToolType::FINGER).x(50).y(50))
7004 .build());
7005 ASSERT_NO_FATAL_FAILURE(leftWindow->consumeMotionDown());
7006 mDispatcher->waitForIdle();
Prabir Pradhan8a5c41d2023-06-08 19:13:46 +00007007 ASSERT_NO_FATAL_FAILURE(
7008 mFakePolicy->assertNotifyDeviceInteractionWasCalled(DEVICE_ID, {Uid{101}}));
Prabir Pradhan8ede1d12023-05-08 19:37:44 +00007009
7010 // Touch another finger over the right windows
7011 mDispatcher->notifyMotion(MotionArgsBuilder(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
7012 .pointer(PointerBuilder(0, ToolType::FINGER).x(50).y(50))
7013 .pointer(PointerBuilder(1, ToolType::FINGER).x(150).y(50))
7014 .build());
7015 ASSERT_NO_FATAL_FAILURE(rightSpy->consumeMotionDown());
7016 ASSERT_NO_FATAL_FAILURE(rightWindow->consumeMotionDown());
7017 ASSERT_NO_FATAL_FAILURE(leftWindow->consumeMotionMove());
7018 mDispatcher->waitForIdle();
7019 ASSERT_NO_FATAL_FAILURE(
Prabir Pradhan8a5c41d2023-06-08 19:13:46 +00007020 mFakePolicy->assertNotifyDeviceInteractionWasCalled(DEVICE_ID,
7021 {Uid{101}, Uid{102}, Uid{103}}));
Prabir Pradhan8ede1d12023-05-08 19:37:44 +00007022
7023 // Release finger over left window. The UP actions are not treated as device interaction.
7024 // The windows that did not receive the UP pointer will receive MOVE events, but since this
7025 // is part of the UP action, we do not treat this as device interaction.
7026 mDispatcher->notifyMotion(MotionArgsBuilder(POINTER_0_UP, AINPUT_SOURCE_TOUCHSCREEN)
7027 .pointer(PointerBuilder(0, ToolType::FINGER).x(50).y(50))
7028 .pointer(PointerBuilder(1, ToolType::FINGER).x(150).y(50))
7029 .build());
7030 ASSERT_NO_FATAL_FAILURE(leftWindow->consumeMotionUp());
7031 ASSERT_NO_FATAL_FAILURE(rightSpy->consumeMotionMove());
7032 ASSERT_NO_FATAL_FAILURE(rightWindow->consumeMotionMove());
7033 mDispatcher->waitForIdle();
7034 ASSERT_NO_FATAL_FAILURE(mFakePolicy->assertNotifyDeviceInteractionWasNotCalled());
7035
7036 // Move remaining finger
7037 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN)
7038 .pointer(PointerBuilder(1, ToolType::FINGER).x(150).y(50))
7039 .build());
7040 ASSERT_NO_FATAL_FAILURE(rightSpy->consumeMotionMove());
7041 ASSERT_NO_FATAL_FAILURE(rightWindow->consumeMotionMove());
7042 mDispatcher->waitForIdle();
7043 ASSERT_NO_FATAL_FAILURE(
Prabir Pradhan8a5c41d2023-06-08 19:13:46 +00007044 mFakePolicy->assertNotifyDeviceInteractionWasCalled(DEVICE_ID, {Uid{102}, Uid{103}}));
Prabir Pradhan8ede1d12023-05-08 19:37:44 +00007045
7046 // Release all fingers
7047 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN)
7048 .pointer(PointerBuilder(1, ToolType::FINGER).x(150).y(50))
7049 .build());
7050 ASSERT_NO_FATAL_FAILURE(rightSpy->consumeMotionUp());
7051 ASSERT_NO_FATAL_FAILURE(rightWindow->consumeMotionUp());
7052 mDispatcher->waitForIdle();
7053 ASSERT_NO_FATAL_FAILURE(mFakePolicy->assertNotifyDeviceInteractionWasNotCalled());
7054}
7055
7056TEST_F(InputDispatcherTest, NotifiesDeviceInteractionsWithKeys) {
7057 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
7058
7059 sp<FakeWindowHandle> window =
7060 sp<FakeWindowHandle>::make(application, mDispatcher, "Window", ADISPLAY_ID_DEFAULT);
7061 window->setFrame(Rect(0, 0, 100, 100));
Prabir Pradhanaeebeb42023-06-13 19:53:03 +00007062 window->setOwnerInfo(gui::Pid{1}, gui::Uid{101});
Prabir Pradhan8ede1d12023-05-08 19:37:44 +00007063
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07007064 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Prabir Pradhan8ede1d12023-05-08 19:37:44 +00007065 setFocusedWindow(window);
7066 ASSERT_NO_FATAL_FAILURE(window->consumeFocusEvent(true));
7067
7068 mDispatcher->notifyKey(KeyArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_KEYBOARD).build());
7069 ASSERT_NO_FATAL_FAILURE(window->consumeKeyDown(ADISPLAY_ID_DEFAULT));
7070 mDispatcher->waitForIdle();
Prabir Pradhan8a5c41d2023-06-08 19:13:46 +00007071 ASSERT_NO_FATAL_FAILURE(
7072 mFakePolicy->assertNotifyDeviceInteractionWasCalled(DEVICE_ID, {gui::Uid{101}}));
Prabir Pradhan8ede1d12023-05-08 19:37:44 +00007073
7074 // The UP actions are not treated as device interaction.
7075 mDispatcher->notifyKey(KeyArgsBuilder(ACTION_UP, AINPUT_SOURCE_KEYBOARD).build());
7076 ASSERT_NO_FATAL_FAILURE(window->consumeKeyUp(ADISPLAY_ID_DEFAULT));
7077 mDispatcher->waitForIdle();
7078 ASSERT_NO_FATAL_FAILURE(mFakePolicy->assertNotifyDeviceInteractionWasNotCalled());
7079}
7080
Prabir Pradhan5893d362023-11-17 04:30:40 +00007081TEST_F(InputDispatcherTest, HoverEnterExitSynthesisUsesNewEventId) {
7082 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
7083
7084 sp<FakeWindowHandle> left = sp<FakeWindowHandle>::make(application, mDispatcher, "Left Window",
7085 ADISPLAY_ID_DEFAULT);
7086 left->setFrame(Rect(0, 0, 100, 100));
7087 sp<FakeWindowHandle> right = sp<FakeWindowHandle>::make(application, mDispatcher,
7088 "Right Window", ADISPLAY_ID_DEFAULT);
7089 right->setFrame(Rect(100, 0, 200, 100));
7090 sp<FakeWindowHandle> spy =
7091 sp<FakeWindowHandle>::make(application, mDispatcher, "Spy Window", ADISPLAY_ID_DEFAULT);
7092 spy->setFrame(Rect(0, 0, 200, 100));
7093 spy->setTrustedOverlay(true);
7094 spy->setSpy(true);
7095
7096 mDispatcher->onWindowInfosChanged(
7097 {{*spy->getInfo(), *left->getInfo(), *right->getInfo()}, {}, 0, 0});
7098
7099 // Send hover move to the left window, and ensure hover enter is synthesized with a new eventId.
7100 NotifyMotionArgs notifyArgs = generateMotionArgs(ACTION_HOVER_MOVE, AINPUT_SOURCE_STYLUS,
7101 ADISPLAY_ID_DEFAULT, {PointF{50, 50}});
7102 mDispatcher->notifyMotion(notifyArgs);
7103
Siarhei Vishniakoud3061ab2023-12-18 20:41:08 -08007104 std::unique_ptr<MotionEvent> leftEnter = left->consumeMotionEvent(
Prabir Pradhan5893d362023-11-17 04:30:40 +00007105 AllOf(WithMotionAction(ACTION_HOVER_ENTER), Not(WithEventId(notifyArgs.id)),
7106 WithEventIdSource(IdGenerator::Source::INPUT_DISPATCHER)));
Siarhei Vishniakoud3061ab2023-12-18 20:41:08 -08007107 ASSERT_NE(nullptr, leftEnter);
Prabir Pradhan5893d362023-11-17 04:30:40 +00007108 spy->consumeMotionEvent(AllOf(WithMotionAction(ACTION_HOVER_ENTER),
7109 Not(WithEventId(notifyArgs.id)),
Siarhei Vishniakoud3061ab2023-12-18 20:41:08 -08007110 Not(WithEventId(leftEnter->getId())),
Prabir Pradhan5893d362023-11-17 04:30:40 +00007111 WithEventIdSource(IdGenerator::Source::INPUT_DISPATCHER)));
7112
7113 // Send move to the right window, and ensure hover exit and enter are synthesized with new ids.
7114 notifyArgs = generateMotionArgs(ACTION_HOVER_MOVE, AINPUT_SOURCE_STYLUS, ADISPLAY_ID_DEFAULT,
7115 {PointF{150, 50}});
7116 mDispatcher->notifyMotion(notifyArgs);
7117
Siarhei Vishniakoud3061ab2023-12-18 20:41:08 -08007118 std::unique_ptr<MotionEvent> leftExit = left->consumeMotionEvent(
Prabir Pradhan5893d362023-11-17 04:30:40 +00007119 AllOf(WithMotionAction(ACTION_HOVER_EXIT), Not(WithEventId(notifyArgs.id)),
7120 WithEventIdSource(IdGenerator::Source::INPUT_DISPATCHER)));
Siarhei Vishniakoud3061ab2023-12-18 20:41:08 -08007121 ASSERT_NE(nullptr, leftExit);
Prabir Pradhan5893d362023-11-17 04:30:40 +00007122 right->consumeMotionEvent(AllOf(WithMotionAction(ACTION_HOVER_ENTER),
7123 Not(WithEventId(notifyArgs.id)),
Siarhei Vishniakoud3061ab2023-12-18 20:41:08 -08007124 Not(WithEventId(leftExit->getId())),
Prabir Pradhan5893d362023-11-17 04:30:40 +00007125 WithEventIdSource(IdGenerator::Source::INPUT_DISPATCHER)));
7126
7127 spy->consumeMotionEvent(AllOf(WithMotionAction(ACTION_HOVER_MOVE), WithEventId(notifyArgs.id)));
7128}
7129
Prabir Pradhanb0dad3a2023-11-02 20:52:47 +00007130class InputDispatcherFallbackKeyTest : public InputDispatcherTest {
7131protected:
7132 std::shared_ptr<FakeApplicationHandle> mApp;
7133 sp<FakeWindowHandle> mWindow;
7134
7135 virtual void SetUp() override {
7136 InputDispatcherTest::SetUp();
7137
7138 mApp = std::make_shared<FakeApplicationHandle>();
7139
7140 mWindow = sp<FakeWindowHandle>::make(mApp, mDispatcher, "Window", ADISPLAY_ID_DEFAULT);
7141 mWindow->setFrame(Rect(0, 0, 100, 100));
7142
7143 mDispatcher->onWindowInfosChanged({{*mWindow->getInfo()}, {}, 0, 0});
7144 setFocusedWindow(mWindow);
7145 ASSERT_NO_FATAL_FAILURE(mWindow->consumeFocusEvent(/*hasFocus=*/true));
7146 }
7147
7148 void setFallback(int32_t keycode) {
7149 mFakePolicy->setUnhandledKeyHandler([keycode](const KeyEvent& event) {
7150 return KeyEventBuilder(event).keyCode(keycode).build();
7151 });
7152 }
7153
7154 void consumeKey(bool handled, const ::testing::Matcher<KeyEvent>& matcher) {
Siarhei Vishniakoud3061ab2023-12-18 20:41:08 -08007155 std::unique_ptr<KeyEvent> event = mWindow->consumeKey(handled);
7156 ASSERT_NE(nullptr, event);
7157 ASSERT_THAT(*event, matcher);
Prabir Pradhanb0dad3a2023-11-02 20:52:47 +00007158 }
7159};
7160
7161TEST_F(InputDispatcherFallbackKeyTest, PolicyNotNotifiedForHandledKey) {
7162 mDispatcher->notifyKey(
7163 KeyArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_KEYBOARD).keyCode(AKEYCODE_A).build());
7164 consumeKey(/*handled=*/true, AllOf(WithKeyAction(ACTION_DOWN), WithKeyCode(AKEYCODE_A)));
7165 ASSERT_NO_FATAL_FAILURE(mFakePolicy->assertUnhandledKeyNotReported());
7166}
7167
7168TEST_F(InputDispatcherFallbackKeyTest, PolicyNotifiedForUnhandledKey) {
7169 mDispatcher->notifyKey(
7170 KeyArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_KEYBOARD).keyCode(AKEYCODE_A).build());
7171 consumeKey(/*handled=*/false, AllOf(WithKeyAction(ACTION_DOWN), WithKeyCode(AKEYCODE_A)));
7172 ASSERT_NO_FATAL_FAILURE(mFakePolicy->assertUnhandledKeyReported(AKEYCODE_A));
7173}
7174
7175TEST_F(InputDispatcherFallbackKeyTest, NoFallbackRequestedByPolicy) {
7176 mDispatcher->notifyKey(
7177 KeyArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_KEYBOARD).keyCode(AKEYCODE_A).build());
7178
7179 // Do not handle this key event.
7180 consumeKey(/*handled=*/false,
7181 AllOf(WithKeyAction(ACTION_DOWN), WithKeyCode(AKEYCODE_A), WithFlags(0)));
7182 ASSERT_NO_FATAL_FAILURE(mFakePolicy->assertUnhandledKeyReported(AKEYCODE_A));
7183
7184 // Since the policy did not request any fallback to be generated, ensure there are no events.
7185 ASSERT_NO_FATAL_FAILURE(mFakePolicy->assertUnhandledKeyNotReported());
7186}
7187
7188TEST_F(InputDispatcherFallbackKeyTest, FallbackDispatchForUnhandledKey) {
7189 setFallback(AKEYCODE_B);
7190 mDispatcher->notifyKey(
7191 KeyArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_KEYBOARD).keyCode(AKEYCODE_A).build());
7192
7193 // Do not handle this key event.
7194 consumeKey(/*handled=*/false,
7195 AllOf(WithKeyAction(ACTION_DOWN), WithKeyCode(AKEYCODE_A), WithFlags(0)));
7196
7197 // Since the key was not handled, ensure the fallback event was dispatched instead.
7198 ASSERT_NO_FATAL_FAILURE(mFakePolicy->assertUnhandledKeyReported(AKEYCODE_A));
7199 consumeKey(/*handled=*/true,
7200 AllOf(WithKeyAction(ACTION_DOWN), WithKeyCode(AKEYCODE_B),
7201 WithFlags(AKEY_EVENT_FLAG_FALLBACK)));
7202
7203 // Release the original key, and ensure the fallback key is also released.
7204 mDispatcher->notifyKey(
7205 KeyArgsBuilder(ACTION_UP, AINPUT_SOURCE_KEYBOARD).keyCode(AKEYCODE_A).build());
7206 consumeKey(/*handled=*/false,
7207 AllOf(WithKeyAction(ACTION_UP), WithKeyCode(AKEYCODE_A), WithFlags(0)));
7208 ASSERT_NO_FATAL_FAILURE(mFakePolicy->assertUnhandledKeyReported(AKEYCODE_A));
7209 consumeKey(/*handled=*/true,
7210 AllOf(WithKeyAction(ACTION_UP), WithKeyCode(AKEYCODE_B),
7211 WithFlags(AKEY_EVENT_FLAG_FALLBACK)));
7212
7213 ASSERT_NO_FATAL_FAILURE(mFakePolicy->assertUnhandledKeyNotReported());
7214 mWindow->assertNoEvents();
7215}
7216
7217TEST_F(InputDispatcherFallbackKeyTest, AppHandlesPreviouslyUnhandledKey) {
7218 setFallback(AKEYCODE_B);
7219 mDispatcher->notifyKey(
7220 KeyArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_KEYBOARD).keyCode(AKEYCODE_A).build());
7221
7222 // Do not handle this key event, but handle the fallback.
7223 consumeKey(/*handled=*/false,
7224 AllOf(WithKeyAction(ACTION_DOWN), WithKeyCode(AKEYCODE_A), WithFlags(0)));
7225 ASSERT_NO_FATAL_FAILURE(mFakePolicy->assertUnhandledKeyReported(AKEYCODE_A));
7226 consumeKey(/*handled=*/true,
7227 AllOf(WithKeyAction(ACTION_DOWN), WithKeyCode(AKEYCODE_B),
7228 WithFlags(AKEY_EVENT_FLAG_FALLBACK)));
7229
7230 // Release the original key, and ensure the fallback key is also released.
7231 mDispatcher->notifyKey(
7232 KeyArgsBuilder(ACTION_UP, AINPUT_SOURCE_KEYBOARD).keyCode(AKEYCODE_A).build());
7233 // But this time, the app handles the original key.
7234 consumeKey(/*handled=*/true,
7235 AllOf(WithKeyAction(ACTION_UP), WithKeyCode(AKEYCODE_A), WithFlags(0)));
7236 ASSERT_NO_FATAL_FAILURE(mFakePolicy->assertUnhandledKeyReported(AKEYCODE_A));
7237 // Ensure the fallback key is canceled.
7238 consumeKey(/*handled=*/true,
7239 AllOf(WithKeyAction(ACTION_UP), WithKeyCode(AKEYCODE_B),
7240 WithFlags(AKEY_EVENT_FLAG_FALLBACK | AKEY_EVENT_FLAG_CANCELED)));
7241
7242 ASSERT_NO_FATAL_FAILURE(mFakePolicy->assertUnhandledKeyNotReported());
7243 mWindow->assertNoEvents();
7244}
7245
7246TEST_F(InputDispatcherFallbackKeyTest, AppDoesNotHandleFallback) {
7247 setFallback(AKEYCODE_B);
7248 mDispatcher->notifyKey(
7249 KeyArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_KEYBOARD).keyCode(AKEYCODE_A).build());
7250
7251 // Do not handle this key event.
7252 consumeKey(/*handled=*/false,
7253 AllOf(WithKeyAction(ACTION_DOWN), WithKeyCode(AKEYCODE_A), WithFlags(0)));
7254 ASSERT_NO_FATAL_FAILURE(mFakePolicy->assertUnhandledKeyReported(AKEYCODE_A));
7255 // App does not handle the fallback either, so ensure another fallback is not generated.
7256 setFallback(AKEYCODE_C);
7257 consumeKey(/*handled=*/false,
7258 AllOf(WithKeyAction(ACTION_DOWN), WithKeyCode(AKEYCODE_B),
7259 WithFlags(AKEY_EVENT_FLAG_FALLBACK)));
7260
7261 // Release the original key, and ensure the fallback key is also released.
7262 setFallback(AKEYCODE_B);
7263 mDispatcher->notifyKey(
7264 KeyArgsBuilder(ACTION_UP, AINPUT_SOURCE_KEYBOARD).keyCode(AKEYCODE_A).build());
7265 consumeKey(/*handled=*/false,
7266 AllOf(WithKeyAction(ACTION_UP), WithKeyCode(AKEYCODE_A), WithFlags(0)));
7267 ASSERT_NO_FATAL_FAILURE(mFakePolicy->assertUnhandledKeyReported(AKEYCODE_A));
7268 consumeKey(/*handled=*/false,
7269 AllOf(WithKeyAction(ACTION_UP), WithKeyCode(AKEYCODE_B),
7270 WithFlags(AKEY_EVENT_FLAG_FALLBACK)));
7271
7272 ASSERT_NO_FATAL_FAILURE(mFakePolicy->assertUnhandledKeyNotReported());
7273 mWindow->assertNoEvents();
7274}
7275
7276TEST_F(InputDispatcherFallbackKeyTest, InconsistentPolicyCancelsFallback) {
7277 setFallback(AKEYCODE_B);
7278 mDispatcher->notifyKey(
7279 KeyArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_KEYBOARD).keyCode(AKEYCODE_A).build());
7280
7281 // Do not handle this key event, so fallback is generated.
7282 consumeKey(/*handled=*/false,
7283 AllOf(WithKeyAction(ACTION_DOWN), WithKeyCode(AKEYCODE_A), WithFlags(0)));
7284 ASSERT_NO_FATAL_FAILURE(mFakePolicy->assertUnhandledKeyReported(AKEYCODE_A));
7285 consumeKey(/*handled=*/true,
7286 AllOf(WithKeyAction(ACTION_DOWN), WithKeyCode(AKEYCODE_B),
7287 WithFlags(AKEY_EVENT_FLAG_FALLBACK)));
7288
7289 // Release the original key, but assume the policy is misbehaving and it
7290 // generates an inconsistent fallback to the one from the DOWN event.
7291 setFallback(AKEYCODE_C);
7292 mDispatcher->notifyKey(
7293 KeyArgsBuilder(ACTION_UP, AINPUT_SOURCE_KEYBOARD).keyCode(AKEYCODE_A).build());
7294 consumeKey(/*handled=*/false,
7295 AllOf(WithKeyAction(ACTION_UP), WithKeyCode(AKEYCODE_A), WithFlags(0)));
7296 ASSERT_NO_FATAL_FAILURE(mFakePolicy->assertUnhandledKeyReported(AKEYCODE_A));
7297 // Ensure the fallback key reported before as DOWN is canceled due to the inconsistency.
7298 consumeKey(/*handled=*/true,
7299 AllOf(WithKeyAction(ACTION_UP), WithKeyCode(AKEYCODE_B),
7300 WithFlags(AKEY_EVENT_FLAG_FALLBACK | AKEY_EVENT_FLAG_CANCELED)));
7301
7302 ASSERT_NO_FATAL_FAILURE(mFakePolicy->assertUnhandledKeyNotReported());
7303 mWindow->assertNoEvents();
7304}
7305
7306TEST_F(InputDispatcherFallbackKeyTest, CanceledKeyCancelsFallback) {
7307 setFallback(AKEYCODE_B);
7308 mDispatcher->notifyKey(
7309 KeyArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_KEYBOARD).keyCode(AKEYCODE_A).build());
7310
7311 // Do not handle this key event, so fallback is generated.
7312 consumeKey(/*handled=*/false,
7313 AllOf(WithKeyAction(ACTION_DOWN), WithKeyCode(AKEYCODE_A), WithFlags(0)));
7314 ASSERT_NO_FATAL_FAILURE(mFakePolicy->assertUnhandledKeyReported(AKEYCODE_A));
7315 consumeKey(/*handled=*/true,
7316 AllOf(WithKeyAction(ACTION_DOWN), WithKeyCode(AKEYCODE_B),
7317 WithFlags(AKEY_EVENT_FLAG_FALLBACK)));
7318
7319 // The original key is canceled.
7320 mDispatcher->notifyKey(KeyArgsBuilder(ACTION_UP, AINPUT_SOURCE_KEYBOARD)
7321 .keyCode(AKEYCODE_A)
7322 .addFlag(AKEY_EVENT_FLAG_CANCELED)
7323 .build());
7324 consumeKey(/*handled=*/false,
7325 AllOf(WithKeyAction(ACTION_UP), WithKeyCode(AKEYCODE_A),
7326 WithFlags(AKEY_EVENT_FLAG_CANCELED)));
7327 ASSERT_NO_FATAL_FAILURE(mFakePolicy->assertUnhandledKeyReported(AKEYCODE_A));
7328 // Ensure the fallback key is also canceled due to the original key being canceled.
7329 consumeKey(/*handled=*/true,
7330 AllOf(WithKeyAction(ACTION_UP), WithKeyCode(AKEYCODE_B),
7331 WithFlags(AKEY_EVENT_FLAG_FALLBACK | AKEY_EVENT_FLAG_CANCELED)));
7332
7333 ASSERT_NO_FATAL_FAILURE(mFakePolicy->assertUnhandledKeyNotReported());
7334 mWindow->assertNoEvents();
7335}
7336
Prabir Pradhanfa2c69f2024-02-01 20:31:34 +00007337TEST_F(InputDispatcherFallbackKeyTest, InputChannelRemovedDuringPolicyCall) {
Prabir Pradhanb13da8f2024-01-09 23:10:13 +00007338 setFallback(AKEYCODE_B);
7339 mDispatcher->notifyKey(
7340 KeyArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_KEYBOARD).keyCode(AKEYCODE_A).build());
7341
7342 // Do not handle this key event.
7343 consumeKey(/*handled=*/false,
7344 AllOf(WithKeyAction(ACTION_DOWN), WithKeyCode(AKEYCODE_A), WithFlags(0)));
7345 ASSERT_NO_FATAL_FAILURE(mFakePolicy->assertUnhandledKeyReported(AKEYCODE_A));
7346 consumeKey(/*handled=*/true,
7347 AllOf(WithKeyAction(ACTION_DOWN), WithKeyCode(AKEYCODE_B),
7348 WithFlags(AKEY_EVENT_FLAG_FALLBACK)));
7349
7350 mFakePolicy->setUnhandledKeyHandler([&](const KeyEvent& event) {
7351 // When the unhandled key is reported to the policy next, remove the input channel.
7352 mDispatcher->removeInputChannel(mWindow->getToken());
7353 return KeyEventBuilder(event).keyCode(AKEYCODE_B).build();
7354 });
7355 // Release the original key, and let the app now handle the previously unhandled key.
7356 // This should result in the previously generated fallback key to be cancelled.
7357 // Since the policy was notified of the unhandled DOWN event earlier, it will also be notified
7358 // of the UP event for consistency. The Dispatcher calls into the policy from its own thread
7359 // without holding the lock, because it need to synchronously fetch the fallback key. While in
7360 // the policy call, we will now remove the input channel. Once the policy call returns, the
7361 // Dispatcher will no longer have a channel to send cancellation events to. Ensure this does
7362 // not cause any crashes.
7363 mDispatcher->notifyKey(
7364 KeyArgsBuilder(ACTION_UP, AINPUT_SOURCE_KEYBOARD).keyCode(AKEYCODE_A).build());
7365 consumeKey(/*handled=*/true,
7366 AllOf(WithKeyAction(ACTION_UP), WithKeyCode(AKEYCODE_A), WithFlags(0)));
7367 ASSERT_NO_FATAL_FAILURE(mFakePolicy->assertUnhandledKeyReported(AKEYCODE_A));
7368}
7369
Prabir Pradhanfa2c69f2024-02-01 20:31:34 +00007370TEST_F(InputDispatcherFallbackKeyTest, WindowRemovedDuringPolicyCall) {
7371 setFallback(AKEYCODE_B);
7372 mDispatcher->notifyKey(
7373 KeyArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_KEYBOARD).keyCode(AKEYCODE_A).build());
7374
7375 // Do not handle this key event.
7376 consumeKey(/*handled=*/false,
7377 AllOf(WithKeyAction(ACTION_DOWN), WithKeyCode(AKEYCODE_A), WithFlags(0)));
7378 ASSERT_NO_FATAL_FAILURE(mFakePolicy->assertUnhandledKeyReported(AKEYCODE_A));
7379 consumeKey(/*handled=*/true,
7380 AllOf(WithKeyAction(ACTION_DOWN), WithKeyCode(AKEYCODE_B),
7381 WithFlags(AKEY_EVENT_FLAG_FALLBACK)));
7382
7383 mFakePolicy->setUnhandledKeyHandler([&](const KeyEvent& event) {
7384 // When the unhandled key is reported to the policy next, remove the window.
7385 mDispatcher->onWindowInfosChanged({{}, {}, 0, 0});
7386 return KeyEventBuilder(event).keyCode(AKEYCODE_B).build();
7387 });
7388 // Release the original key, which the app will not handle. When this unhandled key is reported
7389 // to the policy, the window will be removed.
7390 mDispatcher->notifyKey(
7391 KeyArgsBuilder(ACTION_UP, AINPUT_SOURCE_KEYBOARD).keyCode(AKEYCODE_A).build());
7392 consumeKey(/*handled=*/false,
7393 AllOf(WithKeyAction(ACTION_UP), WithKeyCode(AKEYCODE_A), WithFlags(0)));
7394 ASSERT_NO_FATAL_FAILURE(mFakePolicy->assertUnhandledKeyReported(AKEYCODE_A));
7395
7396 // Since the window was removed, it loses focus, and the channel state will be reset.
7397 consumeKey(/*handled=*/true,
7398 AllOf(WithKeyAction(ACTION_UP), WithKeyCode(AKEYCODE_B),
7399 WithFlags(AKEY_EVENT_FLAG_FALLBACK | AKEY_EVENT_FLAG_CANCELED)));
7400 mWindow->consumeFocusEvent(false);
7401 mWindow->assertNoEvents();
7402}
7403
7404TEST_F(InputDispatcherFallbackKeyTest, WindowRemovedWhileAwaitingFinishedSignal) {
7405 setFallback(AKEYCODE_B);
7406 mDispatcher->notifyKey(
7407 KeyArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_KEYBOARD).keyCode(AKEYCODE_A).build());
7408
7409 // Do not handle this key event.
7410 consumeKey(/*handled=*/false,
7411 AllOf(WithKeyAction(ACTION_DOWN), WithKeyCode(AKEYCODE_A), WithFlags(0)));
7412 ASSERT_NO_FATAL_FAILURE(mFakePolicy->assertUnhandledKeyReported(AKEYCODE_A));
7413 const auto [seq, event] = mWindow->receiveEvent();
7414 ASSERT_TRUE(seq.has_value() && event != nullptr) << "Failed to receive fallback event";
7415 ASSERT_EQ(event->getType(), InputEventType::KEY);
7416 ASSERT_THAT(static_cast<const KeyEvent&>(*event),
7417 AllOf(WithKeyAction(ACTION_DOWN), WithKeyCode(AKEYCODE_B),
7418 WithFlags(AKEY_EVENT_FLAG_FALLBACK)));
7419
7420 // Remove the window now, which should generate a cancellations and make the window lose focus.
7421 mDispatcher->onWindowInfosChanged({{}, {}, 0, 0});
7422 consumeKey(/*handled=*/true,
7423 AllOf(WithKeyAction(ACTION_UP), WithKeyCode(AKEYCODE_A),
7424 WithFlags(AKEY_EVENT_FLAG_CANCELED)));
7425 consumeKey(/*handled=*/true,
7426 AllOf(WithKeyAction(ACTION_UP), WithKeyCode(AKEYCODE_B),
7427 WithFlags(AKEY_EVENT_FLAG_FALLBACK | AKEY_EVENT_FLAG_CANCELED)));
7428 mWindow->consumeFocusEvent(false);
7429
7430 // Finish the event by reporting it as handled.
7431 mWindow->finishEvent(*seq);
7432 mWindow->assertNoEvents();
7433}
7434
Garfield Tan1c7bc862020-01-28 13:24:04 -08007435class InputDispatcherKeyRepeatTest : public InputDispatcherTest {
7436protected:
Siarhei Vishniakoufa2a0492023-11-14 13:13:18 -08007437 static constexpr std::chrono::nanoseconds KEY_REPEAT_TIMEOUT = 40ms;
7438 static constexpr std::chrono::nanoseconds KEY_REPEAT_DELAY = 40ms;
Garfield Tan1c7bc862020-01-28 13:24:04 -08007439
Chris Yea209fde2020-07-22 13:54:51 -07007440 std::shared_ptr<FakeApplicationHandle> mApp;
Garfield Tan1c7bc862020-01-28 13:24:04 -08007441 sp<FakeWindowHandle> mWindow;
7442
7443 virtual void SetUp() override {
Prabir Pradhandae52792023-12-15 07:36:40 +00007444 InputDispatcherTest::SetUp();
Garfield Tan1c7bc862020-01-28 13:24:04 -08007445
Prabir Pradhandae52792023-12-15 07:36:40 +00007446 mDispatcher->setKeyRepeatConfiguration(KEY_REPEAT_TIMEOUT, KEY_REPEAT_DELAY);
Garfield Tan1c7bc862020-01-28 13:24:04 -08007447 setUpWindow();
7448 }
7449
7450 void setUpWindow() {
Chris Yea209fde2020-07-22 13:54:51 -07007451 mApp = std::make_shared<FakeApplicationHandle>();
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07007452 mWindow = sp<FakeWindowHandle>::make(mApp, mDispatcher, "Fake Window", ADISPLAY_ID_DEFAULT);
Garfield Tan1c7bc862020-01-28 13:24:04 -08007453
Vishnu Nair47074b82020-08-14 11:54:47 -07007454 mWindow->setFocusable(true);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07007455 mDispatcher->onWindowInfosChanged({{*mWindow->getInfo()}, {}, 0, 0});
Vishnu Nair958da932020-08-21 17:12:37 -07007456 setFocusedWindow(mWindow);
Garfield Tan1c7bc862020-01-28 13:24:04 -08007457 mWindow->consumeFocusEvent(true);
7458 }
7459
Chris Ye2ad95392020-09-01 13:44:44 -07007460 void sendAndConsumeKeyDown(int32_t deviceId) {
Garfield Tan1c7bc862020-01-28 13:24:04 -08007461 NotifyKeyArgs keyArgs = generateKeyArgs(AKEY_EVENT_ACTION_DOWN, ADISPLAY_ID_DEFAULT);
Chris Ye2ad95392020-09-01 13:44:44 -07007462 keyArgs.deviceId = deviceId;
Garfield Tan1c7bc862020-01-28 13:24:04 -08007463 keyArgs.policyFlags |= POLICY_FLAG_TRUSTED; // Otherwise it won't generate repeat event
Prabir Pradhan678438e2023-04-13 19:32:51 +00007464 mDispatcher->notifyKey(keyArgs);
Garfield Tan1c7bc862020-01-28 13:24:04 -08007465
7466 // Window should receive key down event.
7467 mWindow->consumeKeyDown(ADISPLAY_ID_DEFAULT);
7468 }
7469
7470 void expectKeyRepeatOnce(int32_t repeatCount) {
7471 SCOPED_TRACE(StringPrintf("Checking event with repeat count %" PRId32, repeatCount));
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07007472 mWindow->consumeKeyEvent(
7473 AllOf(WithKeyAction(AKEY_EVENT_ACTION_DOWN), WithRepeatCount(repeatCount)));
Garfield Tan1c7bc862020-01-28 13:24:04 -08007474 }
7475
Chris Ye2ad95392020-09-01 13:44:44 -07007476 void sendAndConsumeKeyUp(int32_t deviceId) {
Garfield Tan1c7bc862020-01-28 13:24:04 -08007477 NotifyKeyArgs keyArgs = generateKeyArgs(AKEY_EVENT_ACTION_UP, ADISPLAY_ID_DEFAULT);
Chris Ye2ad95392020-09-01 13:44:44 -07007478 keyArgs.deviceId = deviceId;
Garfield Tan1c7bc862020-01-28 13:24:04 -08007479 keyArgs.policyFlags |= POLICY_FLAG_TRUSTED; // Unless it won't generate repeat event
Prabir Pradhan678438e2023-04-13 19:32:51 +00007480 mDispatcher->notifyKey(keyArgs);
Garfield Tan1c7bc862020-01-28 13:24:04 -08007481
7482 // Window should receive key down event.
Prabir Pradhan7662a8d2023-12-15 01:58:14 +00007483 mWindow->consumeKeyUp(ADISPLAY_ID_DEFAULT,
Harry Cutts33476232023-01-30 19:57:29 +00007484 /*expectedFlags=*/0);
Garfield Tan1c7bc862020-01-28 13:24:04 -08007485 }
Hu Guofe3c8f12023-09-22 17:20:15 +08007486
7487 void injectKeyRepeat(int32_t repeatCount) {
7488 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
7489 injectKey(*mDispatcher, AKEY_EVENT_ACTION_DOWN, repeatCount, ADISPLAY_ID_DEFAULT))
7490 << "Inject key event should return InputEventInjectionResult::SUCCEEDED";
7491 }
Garfield Tan1c7bc862020-01-28 13:24:04 -08007492};
7493
7494TEST_F(InputDispatcherKeyRepeatTest, FocusedWindow_ReceivesKeyRepeat) {
Harry Cutts33476232023-01-30 19:57:29 +00007495 sendAndConsumeKeyDown(/*deviceId=*/1);
Chris Ye2ad95392020-09-01 13:44:44 -07007496 for (int32_t repeatCount = 1; repeatCount <= 10; ++repeatCount) {
7497 expectKeyRepeatOnce(repeatCount);
7498 }
7499}
7500
7501TEST_F(InputDispatcherKeyRepeatTest, FocusedWindow_ReceivesKeyRepeatFromTwoDevices) {
Harry Cutts33476232023-01-30 19:57:29 +00007502 sendAndConsumeKeyDown(/*deviceId=*/1);
Chris Ye2ad95392020-09-01 13:44:44 -07007503 for (int32_t repeatCount = 1; repeatCount <= 10; ++repeatCount) {
7504 expectKeyRepeatOnce(repeatCount);
7505 }
Harry Cutts33476232023-01-30 19:57:29 +00007506 sendAndConsumeKeyDown(/*deviceId=*/2);
Chris Ye2ad95392020-09-01 13:44:44 -07007507 /* repeatCount will start from 1 for deviceId 2 */
Garfield Tan1c7bc862020-01-28 13:24:04 -08007508 for (int32_t repeatCount = 1; repeatCount <= 10; ++repeatCount) {
7509 expectKeyRepeatOnce(repeatCount);
7510 }
7511}
7512
7513TEST_F(InputDispatcherKeyRepeatTest, FocusedWindow_StopsKeyRepeatAfterUp) {
Harry Cutts33476232023-01-30 19:57:29 +00007514 sendAndConsumeKeyDown(/*deviceId=*/1);
7515 expectKeyRepeatOnce(/*repeatCount=*/1);
7516 sendAndConsumeKeyUp(/*deviceId=*/1);
Chris Ye2ad95392020-09-01 13:44:44 -07007517 mWindow->assertNoEvents();
7518}
7519
7520TEST_F(InputDispatcherKeyRepeatTest, FocusedWindow_KeyRepeatAfterStaleDeviceKeyUp) {
Harry Cutts33476232023-01-30 19:57:29 +00007521 sendAndConsumeKeyDown(/*deviceId=*/1);
7522 expectKeyRepeatOnce(/*repeatCount=*/1);
7523 sendAndConsumeKeyDown(/*deviceId=*/2);
7524 expectKeyRepeatOnce(/*repeatCount=*/1);
Chris Ye2ad95392020-09-01 13:44:44 -07007525 // Stale key up from device 1.
Harry Cutts33476232023-01-30 19:57:29 +00007526 sendAndConsumeKeyUp(/*deviceId=*/1);
Chris Ye2ad95392020-09-01 13:44:44 -07007527 // Device 2 is still down, keep repeating
Harry Cutts33476232023-01-30 19:57:29 +00007528 expectKeyRepeatOnce(/*repeatCount=*/2);
7529 expectKeyRepeatOnce(/*repeatCount=*/3);
Chris Ye2ad95392020-09-01 13:44:44 -07007530 // Device 2 key up
Harry Cutts33476232023-01-30 19:57:29 +00007531 sendAndConsumeKeyUp(/*deviceId=*/2);
Chris Ye2ad95392020-09-01 13:44:44 -07007532 mWindow->assertNoEvents();
7533}
7534
7535TEST_F(InputDispatcherKeyRepeatTest, FocusedWindow_KeyRepeatStopsAfterRepeatingKeyUp) {
Harry Cutts33476232023-01-30 19:57:29 +00007536 sendAndConsumeKeyDown(/*deviceId=*/1);
7537 expectKeyRepeatOnce(/*repeatCount=*/1);
7538 sendAndConsumeKeyDown(/*deviceId=*/2);
7539 expectKeyRepeatOnce(/*repeatCount=*/1);
Chris Ye2ad95392020-09-01 13:44:44 -07007540 // Device 2 which holds the key repeating goes up, expect the repeating to stop.
Harry Cutts33476232023-01-30 19:57:29 +00007541 sendAndConsumeKeyUp(/*deviceId=*/2);
Chris Ye2ad95392020-09-01 13:44:44 -07007542 // Device 1 still holds key down, but the repeating was already stopped
Garfield Tan1c7bc862020-01-28 13:24:04 -08007543 mWindow->assertNoEvents();
7544}
7545
liushenxiang42232912021-05-21 20:24:09 +08007546TEST_F(InputDispatcherKeyRepeatTest, FocusedWindow_StopsKeyRepeatAfterDisableInputDevice) {
7547 sendAndConsumeKeyDown(DEVICE_ID);
Harry Cutts33476232023-01-30 19:57:29 +00007548 expectKeyRepeatOnce(/*repeatCount=*/1);
Prabir Pradhan678438e2023-04-13 19:32:51 +00007549 mDispatcher->notifyDeviceReset({/*id=*/10, /*eventTime=*/20, DEVICE_ID});
liushenxiang42232912021-05-21 20:24:09 +08007550 mWindow->consumeKeyUp(ADISPLAY_ID_DEFAULT,
7551 AKEY_EVENT_FLAG_CANCELED | AKEY_EVENT_FLAG_LONG_PRESS);
7552 mWindow->assertNoEvents();
7553}
7554
Garfield Tan1c7bc862020-01-28 13:24:04 -08007555TEST_F(InputDispatcherKeyRepeatTest, FocusedWindow_RepeatKeyEventsUseEventIdFromInputDispatcher) {
Michael Wrighte1cbbd62023-02-22 19:32:13 +00007556 GTEST_SKIP() << "Flaky test (b/270393106)";
Harry Cutts33476232023-01-30 19:57:29 +00007557 sendAndConsumeKeyDown(/*deviceId=*/1);
Garfield Tan1c7bc862020-01-28 13:24:04 -08007558 for (int32_t repeatCount = 1; repeatCount <= 10; ++repeatCount) {
Siarhei Vishniakoud3061ab2023-12-18 20:41:08 -08007559 std::unique_ptr<KeyEvent> repeatEvent = mWindow->consumeKey();
7560 ASSERT_NE(nullptr, repeatEvent);
Garfield Tan1c7bc862020-01-28 13:24:04 -08007561 EXPECT_EQ(IdGenerator::Source::INPUT_DISPATCHER,
Siarhei Vishniakoud3061ab2023-12-18 20:41:08 -08007562 IdGenerator::getSource(repeatEvent->getId()));
Garfield Tan1c7bc862020-01-28 13:24:04 -08007563 }
7564}
7565
7566TEST_F(InputDispatcherKeyRepeatTest, FocusedWindow_RepeatKeyEventsUseUniqueEventId) {
Michael Wrighte1cbbd62023-02-22 19:32:13 +00007567 GTEST_SKIP() << "Flaky test (b/270393106)";
Harry Cutts33476232023-01-30 19:57:29 +00007568 sendAndConsumeKeyDown(/*deviceId=*/1);
Garfield Tan1c7bc862020-01-28 13:24:04 -08007569
7570 std::unordered_set<int32_t> idSet;
7571 for (int32_t repeatCount = 1; repeatCount <= 10; ++repeatCount) {
Siarhei Vishniakoud3061ab2023-12-18 20:41:08 -08007572 std::unique_ptr<KeyEvent> repeatEvent = mWindow->consumeKey();
7573 ASSERT_NE(nullptr, repeatEvent);
7574 int32_t id = repeatEvent->getId();
Garfield Tan1c7bc862020-01-28 13:24:04 -08007575 EXPECT_EQ(idSet.end(), idSet.find(id));
7576 idSet.insert(id);
7577 }
7578}
7579
Hu Guofe3c8f12023-09-22 17:20:15 +08007580TEST_F(InputDispatcherKeyRepeatTest, FocusedWindow_CorrectRepeatCountWhenInjectKeyRepeat) {
7581 injectKeyRepeat(0);
7582 mWindow->consumeKeyDown(ADISPLAY_ID_DEFAULT);
7583 for (int32_t repeatCount = 1; repeatCount <= 2; ++repeatCount) {
7584 expectKeyRepeatOnce(repeatCount);
7585 }
7586 injectKeyRepeat(1);
7587 // Expect repeatCount to be 3 instead of 1
7588 expectKeyRepeatOnce(3);
7589}
7590
Arthur Hung2fbf37f2018-09-13 18:16:41 +08007591/* Test InputDispatcher for MultiDisplay */
7592class InputDispatcherFocusOnTwoDisplaysTest : public InputDispatcherTest {
7593public:
Prabir Pradhan3608aad2019-10-02 17:08:26 -07007594 virtual void SetUp() override {
Arthur Hung2fbf37f2018-09-13 18:16:41 +08007595 InputDispatcherTest::SetUp();
Arthur Hungb92218b2018-08-14 12:00:21 +08007596
Chris Yea209fde2020-07-22 13:54:51 -07007597 application1 = std::make_shared<FakeApplicationHandle>();
Siarhei Vishniakou870ecec2020-12-09 08:07:46 -10007598 windowInPrimary =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07007599 sp<FakeWindowHandle>::make(application1, mDispatcher, "D_1", ADISPLAY_ID_DEFAULT);
Siarhei Vishniakoub9b15352019-11-26 13:19:26 -08007600
Arthur Hung2fbf37f2018-09-13 18:16:41 +08007601 // Set focus window for primary display, but focused display would be second one.
7602 mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application1);
Vishnu Nair47074b82020-08-14 11:54:47 -07007603 windowInPrimary->setFocusable(true);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07007604 mDispatcher->onWindowInfosChanged({{*windowInPrimary->getInfo()}, {}, 0, 0});
7605
Vishnu Nair958da932020-08-21 17:12:37 -07007606 setFocusedWindow(windowInPrimary);
Siarhei Vishniakouf1035d42019-09-20 16:32:01 +01007607 windowInPrimary->consumeFocusEvent(true);
Arthur Hungb92218b2018-08-14 12:00:21 +08007608
Chris Yea209fde2020-07-22 13:54:51 -07007609 application2 = std::make_shared<FakeApplicationHandle>();
Siarhei Vishniakou870ecec2020-12-09 08:07:46 -10007610 windowInSecondary =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07007611 sp<FakeWindowHandle>::make(application2, mDispatcher, "D_2", SECOND_DISPLAY_ID);
Arthur Hung2fbf37f2018-09-13 18:16:41 +08007612 // Set focus to second display window.
Arthur Hung2fbf37f2018-09-13 18:16:41 +08007613 // Set focus display to second one.
7614 mDispatcher->setFocusedDisplay(SECOND_DISPLAY_ID);
7615 // Set focus window for second display.
7616 mDispatcher->setFocusedApplication(SECOND_DISPLAY_ID, application2);
Vishnu Nair47074b82020-08-14 11:54:47 -07007617 windowInSecondary->setFocusable(true);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07007618 mDispatcher->onWindowInfosChanged(
7619 {{*windowInPrimary->getInfo(), *windowInSecondary->getInfo()}, {}, 0, 0});
Vishnu Nair958da932020-08-21 17:12:37 -07007620 setFocusedWindow(windowInSecondary);
Siarhei Vishniakouf1035d42019-09-20 16:32:01 +01007621 windowInSecondary->consumeFocusEvent(true);
Arthur Hung2fbf37f2018-09-13 18:16:41 +08007622 }
7623
Prabir Pradhan3608aad2019-10-02 17:08:26 -07007624 virtual void TearDown() override {
Arthur Hung2fbf37f2018-09-13 18:16:41 +08007625 InputDispatcherTest::TearDown();
7626
Chris Yea209fde2020-07-22 13:54:51 -07007627 application1.reset();
Arthur Hung2fbf37f2018-09-13 18:16:41 +08007628 windowInPrimary.clear();
Chris Yea209fde2020-07-22 13:54:51 -07007629 application2.reset();
Arthur Hung2fbf37f2018-09-13 18:16:41 +08007630 windowInSecondary.clear();
7631 }
7632
7633protected:
Chris Yea209fde2020-07-22 13:54:51 -07007634 std::shared_ptr<FakeApplicationHandle> application1;
Arthur Hung2fbf37f2018-09-13 18:16:41 +08007635 sp<FakeWindowHandle> windowInPrimary;
Chris Yea209fde2020-07-22 13:54:51 -07007636 std::shared_ptr<FakeApplicationHandle> application2;
Arthur Hung2fbf37f2018-09-13 18:16:41 +08007637 sp<FakeWindowHandle> windowInSecondary;
7638};
7639
7640TEST_F(InputDispatcherFocusOnTwoDisplaysTest, SetInputWindow_MultiDisplayTouch) {
7641 // Test touch down on primary display.
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08007642 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07007643 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT))
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08007644 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
Siarhei Vishniakouc5ca85c2019-11-15 17:20:00 -08007645 windowInPrimary->consumeMotionDown(ADISPLAY_ID_DEFAULT);
Arthur Hungb92218b2018-08-14 12:00:21 +08007646 windowInSecondary->assertNoEvents();
7647
Arthur Hung2fbf37f2018-09-13 18:16:41 +08007648 // Test touch down on second display.
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08007649 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07007650 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, SECOND_DISPLAY_ID))
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08007651 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
Arthur Hungb92218b2018-08-14 12:00:21 +08007652 windowInPrimary->assertNoEvents();
Siarhei Vishniakouc5ca85c2019-11-15 17:20:00 -08007653 windowInSecondary->consumeMotionDown(SECOND_DISPLAY_ID);
Arthur Hungb92218b2018-08-14 12:00:21 +08007654}
7655
Arthur Hung2fbf37f2018-09-13 18:16:41 +08007656TEST_F(InputDispatcherFocusOnTwoDisplaysTest, SetInputWindow_MultiDisplayFocus) {
Tiger Huang721e26f2018-07-24 22:26:19 +08007657 // Test inject a key down with display id specified.
Prabir Pradhan93f342c2021-03-11 15:05:30 -08007658 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07007659 injectKeyDownNoRepeat(*mDispatcher, ADISPLAY_ID_DEFAULT))
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08007660 << "Inject key event should return InputEventInjectionResult::SUCCEEDED";
Siarhei Vishniakouc5ca85c2019-11-15 17:20:00 -08007661 windowInPrimary->consumeKeyDown(ADISPLAY_ID_DEFAULT);
Tiger Huang721e26f2018-07-24 22:26:19 +08007662 windowInSecondary->assertNoEvents();
7663
7664 // Test inject a key down without display id specified.
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07007665 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectKeyDownNoRepeat(*mDispatcher))
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08007666 << "Inject key event should return InputEventInjectionResult::SUCCEEDED";
Arthur Hungb92218b2018-08-14 12:00:21 +08007667 windowInPrimary->assertNoEvents();
Siarhei Vishniakouc5ca85c2019-11-15 17:20:00 -08007668 windowInSecondary->consumeKeyDown(ADISPLAY_ID_NONE);
Arthur Hungb92218b2018-08-14 12:00:21 +08007669
Siarhei Vishniakoub9b15352019-11-26 13:19:26 -08007670 // Remove all windows in secondary display.
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07007671 mDispatcher->onWindowInfosChanged({{*windowInPrimary->getInfo()}, {}, 0, 0});
Arthur Hungb92218b2018-08-14 12:00:21 +08007672
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08007673 // Old focus should receive a cancel event.
Prabir Pradhan7662a8d2023-12-15 01:58:14 +00007674 windowInSecondary->consumeKeyUp(ADISPLAY_ID_NONE, AKEY_EVENT_FLAG_CANCELED);
Arthur Hungb92218b2018-08-14 12:00:21 +08007675
7676 // Test inject a key down, should timeout because of no target window.
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07007677 ASSERT_NO_FATAL_FAILURE(assertInjectedKeyTimesOut(*mDispatcher));
Arthur Hungb92218b2018-08-14 12:00:21 +08007678 windowInPrimary->assertNoEvents();
Siarhei Vishniakouf1035d42019-09-20 16:32:01 +01007679 windowInSecondary->consumeFocusEvent(false);
Arthur Hungb92218b2018-08-14 12:00:21 +08007680 windowInSecondary->assertNoEvents();
7681}
7682
Arthur Hung2fbf37f2018-09-13 18:16:41 +08007683// Test per-display input monitors for motion event.
7684TEST_F(InputDispatcherFocusOnTwoDisplaysTest, MonitorMotionEvent_MultiDisplay) {
chaviwd1c23182019-12-20 18:44:56 -08007685 FakeMonitorReceiver monitorInPrimary =
Prabir Pradhanfb549072023-10-05 19:17:36 +00007686 FakeMonitorReceiver(*mDispatcher, "M_1", ADISPLAY_ID_DEFAULT);
chaviwd1c23182019-12-20 18:44:56 -08007687 FakeMonitorReceiver monitorInSecondary =
Prabir Pradhanfb549072023-10-05 19:17:36 +00007688 FakeMonitorReceiver(*mDispatcher, "M_2", SECOND_DISPLAY_ID);
Arthur Hung2fbf37f2018-09-13 18:16:41 +08007689
7690 // Test touch down on primary display.
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08007691 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07007692 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT))
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08007693 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
Siarhei Vishniakouc5ca85c2019-11-15 17:20:00 -08007694 windowInPrimary->consumeMotionDown(ADISPLAY_ID_DEFAULT);
chaviwd1c23182019-12-20 18:44:56 -08007695 monitorInPrimary.consumeMotionDown(ADISPLAY_ID_DEFAULT);
Arthur Hung2fbf37f2018-09-13 18:16:41 +08007696 windowInSecondary->assertNoEvents();
chaviwd1c23182019-12-20 18:44:56 -08007697 monitorInSecondary.assertNoEvents();
Arthur Hung2fbf37f2018-09-13 18:16:41 +08007698
7699 // Test touch down on second display.
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08007700 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07007701 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, SECOND_DISPLAY_ID))
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08007702 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
Arthur Hung2fbf37f2018-09-13 18:16:41 +08007703 windowInPrimary->assertNoEvents();
chaviwd1c23182019-12-20 18:44:56 -08007704 monitorInPrimary.assertNoEvents();
Siarhei Vishniakouc5ca85c2019-11-15 17:20:00 -08007705 windowInSecondary->consumeMotionDown(SECOND_DISPLAY_ID);
chaviwd1c23182019-12-20 18:44:56 -08007706 monitorInSecondary.consumeMotionDown(SECOND_DISPLAY_ID);
Arthur Hung2fbf37f2018-09-13 18:16:41 +08007707
Siarhei Vishniakou92c8fd52023-01-29 14:57:43 -08007708 // Lift up the touch from the second display
7709 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07007710 injectMotionUp(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, SECOND_DISPLAY_ID))
Siarhei Vishniakou92c8fd52023-01-29 14:57:43 -08007711 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
7712 windowInSecondary->consumeMotionUp(SECOND_DISPLAY_ID);
7713 monitorInSecondary.consumeMotionUp(SECOND_DISPLAY_ID);
7714
Arthur Hung2fbf37f2018-09-13 18:16:41 +08007715 // Test inject a non-pointer motion event.
7716 // If specific a display, it will dispatch to the focused window of particular display,
7717 // or it will dispatch to the focused window of focused display.
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08007718 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07007719 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TRACKBALL, ADISPLAY_ID_NONE))
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08007720 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
Arthur Hung2fbf37f2018-09-13 18:16:41 +08007721 windowInPrimary->assertNoEvents();
chaviwd1c23182019-12-20 18:44:56 -08007722 monitorInPrimary.assertNoEvents();
Siarhei Vishniakouc5ca85c2019-11-15 17:20:00 -08007723 windowInSecondary->consumeMotionDown(ADISPLAY_ID_NONE);
chaviwd1c23182019-12-20 18:44:56 -08007724 monitorInSecondary.consumeMotionDown(ADISPLAY_ID_NONE);
Arthur Hung2fbf37f2018-09-13 18:16:41 +08007725}
7726
7727// Test per-display input monitors for key event.
7728TEST_F(InputDispatcherFocusOnTwoDisplaysTest, MonitorKeyEvent_MultiDisplay) {
Siarhei Vishniakou870ecec2020-12-09 08:07:46 -10007729 // Input monitor per display.
chaviwd1c23182019-12-20 18:44:56 -08007730 FakeMonitorReceiver monitorInPrimary =
Prabir Pradhanfb549072023-10-05 19:17:36 +00007731 FakeMonitorReceiver(*mDispatcher, "M_1", ADISPLAY_ID_DEFAULT);
chaviwd1c23182019-12-20 18:44:56 -08007732 FakeMonitorReceiver monitorInSecondary =
Prabir Pradhanfb549072023-10-05 19:17:36 +00007733 FakeMonitorReceiver(*mDispatcher, "M_2", SECOND_DISPLAY_ID);
Arthur Hung2fbf37f2018-09-13 18:16:41 +08007734
7735 // Test inject a key down.
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07007736 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectKeyDown(*mDispatcher))
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08007737 << "Inject key event should return InputEventInjectionResult::SUCCEEDED";
Arthur Hung2fbf37f2018-09-13 18:16:41 +08007738 windowInPrimary->assertNoEvents();
chaviwd1c23182019-12-20 18:44:56 -08007739 monitorInPrimary.assertNoEvents();
Siarhei Vishniakouc5ca85c2019-11-15 17:20:00 -08007740 windowInSecondary->consumeKeyDown(ADISPLAY_ID_NONE);
chaviwd1c23182019-12-20 18:44:56 -08007741 monitorInSecondary.consumeKeyDown(ADISPLAY_ID_NONE);
Arthur Hung2fbf37f2018-09-13 18:16:41 +08007742}
7743
Vishnu Nair958da932020-08-21 17:12:37 -07007744TEST_F(InputDispatcherFocusOnTwoDisplaysTest, CanFocusWindowOnUnfocusedDisplay) {
7745 sp<FakeWindowHandle> secondWindowInPrimary =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07007746 sp<FakeWindowHandle>::make(application1, mDispatcher, "D_1_W2", ADISPLAY_ID_DEFAULT);
Vishnu Nair958da932020-08-21 17:12:37 -07007747 secondWindowInPrimary->setFocusable(true);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07007748 mDispatcher->onWindowInfosChanged(
7749 {{*windowInPrimary->getInfo(), *secondWindowInPrimary->getInfo(),
7750 *windowInSecondary->getInfo()},
7751 {},
7752 0,
7753 0});
Vishnu Nair958da932020-08-21 17:12:37 -07007754 setFocusedWindow(secondWindowInPrimary);
7755 windowInPrimary->consumeFocusEvent(false);
7756 secondWindowInPrimary->consumeFocusEvent(true);
7757
7758 // Test inject a key down.
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07007759 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
7760 injectKeyDown(*mDispatcher, ADISPLAY_ID_DEFAULT))
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08007761 << "Inject key event should return InputEventInjectionResult::SUCCEEDED";
Vishnu Nair958da932020-08-21 17:12:37 -07007762 windowInPrimary->assertNoEvents();
7763 windowInSecondary->assertNoEvents();
7764 secondWindowInPrimary->consumeKeyDown(ADISPLAY_ID_DEFAULT);
7765}
7766
Arthur Hungdfd528e2021-12-08 13:23:04 +00007767TEST_F(InputDispatcherFocusOnTwoDisplaysTest, CancelTouch_MultiDisplay) {
7768 FakeMonitorReceiver monitorInPrimary =
Prabir Pradhanfb549072023-10-05 19:17:36 +00007769 FakeMonitorReceiver(*mDispatcher, "M_1", ADISPLAY_ID_DEFAULT);
Arthur Hungdfd528e2021-12-08 13:23:04 +00007770 FakeMonitorReceiver monitorInSecondary =
Prabir Pradhanfb549072023-10-05 19:17:36 +00007771 FakeMonitorReceiver(*mDispatcher, "M_2", SECOND_DISPLAY_ID);
Arthur Hungdfd528e2021-12-08 13:23:04 +00007772
7773 // Test touch down on primary display.
7774 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07007775 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT))
Arthur Hungdfd528e2021-12-08 13:23:04 +00007776 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
7777 windowInPrimary->consumeMotionDown(ADISPLAY_ID_DEFAULT);
7778 monitorInPrimary.consumeMotionDown(ADISPLAY_ID_DEFAULT);
7779
7780 // Test touch down on second display.
7781 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07007782 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, SECOND_DISPLAY_ID))
Arthur Hungdfd528e2021-12-08 13:23:04 +00007783 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
7784 windowInSecondary->consumeMotionDown(SECOND_DISPLAY_ID);
7785 monitorInSecondary.consumeMotionDown(SECOND_DISPLAY_ID);
7786
7787 // Trigger cancel touch.
7788 mDispatcher->cancelCurrentTouch();
7789 windowInPrimary->consumeMotionCancel(ADISPLAY_ID_DEFAULT);
7790 monitorInPrimary.consumeMotionCancel(ADISPLAY_ID_DEFAULT);
7791 windowInSecondary->consumeMotionCancel(SECOND_DISPLAY_ID);
7792 monitorInSecondary.consumeMotionCancel(SECOND_DISPLAY_ID);
7793
7794 // Test inject a move motion event, no window/monitor should receive the event.
7795 ASSERT_EQ(InputEventInjectionResult::FAILED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07007796 injectMotionEvent(*mDispatcher, AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN,
Arthur Hungdfd528e2021-12-08 13:23:04 +00007797 ADISPLAY_ID_DEFAULT, {110, 200}))
7798 << "Inject motion event should return InputEventInjectionResult::FAILED";
7799 windowInPrimary->assertNoEvents();
7800 monitorInPrimary.assertNoEvents();
7801
7802 ASSERT_EQ(InputEventInjectionResult::FAILED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07007803 injectMotionEvent(*mDispatcher, AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN,
Arthur Hungdfd528e2021-12-08 13:23:04 +00007804 SECOND_DISPLAY_ID, {110, 200}))
7805 << "Inject motion event should return InputEventInjectionResult::FAILED";
7806 windowInSecondary->assertNoEvents();
7807 monitorInSecondary.assertNoEvents();
7808}
7809
Hu Guocb134f12023-12-23 13:42:44 +00007810/**
7811 * Send a key to the primary display and to the secondary display.
7812 * Then cause the key on the primary display to be canceled by sending in a stale key.
7813 * Ensure that the key on the primary display is canceled, and that the key on the secondary display
7814 * does not get canceled.
7815 */
7816TEST_F(InputDispatcherFocusOnTwoDisplaysTest, WhenDropKeyEvent_OnlyCancelCorrespondingKeyGesture) {
7817 // Send a key down on primary display
7818 mDispatcher->notifyKey(
7819 KeyArgsBuilder(AKEY_EVENT_ACTION_DOWN, AINPUT_SOURCE_KEYBOARD)
7820 .displayId(ADISPLAY_ID_DEFAULT)
7821 .policyFlags(DEFAULT_POLICY_FLAGS | POLICY_FLAG_DISABLE_KEY_REPEAT)
7822 .build());
7823 windowInPrimary->consumeKeyEvent(
7824 AllOf(WithKeyAction(AKEY_EVENT_ACTION_DOWN), WithDisplayId(ADISPLAY_ID_DEFAULT)));
7825 windowInSecondary->assertNoEvents();
7826
7827 // Send a key down on second display
7828 mDispatcher->notifyKey(
7829 KeyArgsBuilder(AKEY_EVENT_ACTION_DOWN, AINPUT_SOURCE_KEYBOARD)
7830 .displayId(SECOND_DISPLAY_ID)
7831 .policyFlags(DEFAULT_POLICY_FLAGS | POLICY_FLAG_DISABLE_KEY_REPEAT)
7832 .build());
7833 windowInSecondary->consumeKeyEvent(
7834 AllOf(WithKeyAction(AKEY_EVENT_ACTION_DOWN), WithDisplayId(SECOND_DISPLAY_ID)));
7835 windowInPrimary->assertNoEvents();
7836
7837 // Send a valid key up event on primary display that will be dropped because it is stale
7838 NotifyKeyArgs staleKeyUp =
7839 KeyArgsBuilder(AKEY_EVENT_ACTION_UP, AINPUT_SOURCE_KEYBOARD)
7840 .displayId(ADISPLAY_ID_DEFAULT)
7841 .policyFlags(DEFAULT_POLICY_FLAGS | POLICY_FLAG_DISABLE_KEY_REPEAT)
7842 .build();
7843 static constexpr std::chrono::duration STALE_EVENT_TIMEOUT = 10ms;
7844 mFakePolicy->setStaleEventTimeout(STALE_EVENT_TIMEOUT);
7845 std::this_thread::sleep_for(STALE_EVENT_TIMEOUT);
7846 mDispatcher->notifyKey(staleKeyUp);
7847
7848 // Only the key gesture corresponding to the dropped event should receive the cancel event.
7849 // Therefore, windowInPrimary should get the cancel event and windowInSecondary should not
7850 // receive any events.
7851 windowInPrimary->consumeKeyEvent(AllOf(WithKeyAction(AKEY_EVENT_ACTION_UP),
7852 WithDisplayId(ADISPLAY_ID_DEFAULT),
7853 WithFlags(AKEY_EVENT_FLAG_CANCELED)));
7854 windowInSecondary->assertNoEvents();
7855}
7856
7857/**
7858 * Similar to 'WhenDropKeyEvent_OnlyCancelCorrespondingKeyGesture' but for motion events.
7859 */
7860TEST_F(InputDispatcherFocusOnTwoDisplaysTest, WhenDropMotionEvent_OnlyCancelCorrespondingGesture) {
7861 // Send touch down on primary display.
7862 mDispatcher->notifyMotion(
7863 MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
7864 .pointer(PointerBuilder(/*id=*/0, ToolType::FINGER).x(100).y(200))
7865 .displayId(ADISPLAY_ID_DEFAULT)
7866 .build());
7867 windowInPrimary->consumeMotionEvent(
7868 AllOf(WithMotionAction(ACTION_DOWN), WithDisplayId(ADISPLAY_ID_DEFAULT)));
7869 windowInSecondary->assertNoEvents();
7870
7871 // Send touch down on second display.
7872 mDispatcher->notifyMotion(
7873 MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
7874 .pointer(PointerBuilder(/*id=*/0, ToolType::FINGER).x(100).y(200))
7875 .displayId(SECOND_DISPLAY_ID)
7876 .build());
7877 windowInPrimary->assertNoEvents();
7878 windowInSecondary->consumeMotionEvent(
7879 AllOf(WithMotionAction(ACTION_DOWN), WithDisplayId(SECOND_DISPLAY_ID)));
7880
7881 // inject a valid MotionEvent on primary display that will be stale when it arrives.
7882 NotifyMotionArgs staleMotionUp =
7883 MotionArgsBuilder(ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN)
7884 .displayId(ADISPLAY_ID_DEFAULT)
7885 .pointer(PointerBuilder(/*id=*/0, ToolType::FINGER).x(100).y(200))
7886 .build();
7887 static constexpr std::chrono::duration STALE_EVENT_TIMEOUT = 10ms;
7888 mFakePolicy->setStaleEventTimeout(STALE_EVENT_TIMEOUT);
7889 std::this_thread::sleep_for(STALE_EVENT_TIMEOUT);
7890 mDispatcher->notifyMotion(staleMotionUp);
7891
7892 // For stale motion events, we let the gesture to complete. This behaviour is different from key
7893 // events, where we would cancel the current keys instead.
7894 windowInPrimary->consumeMotionEvent(WithMotionAction(ACTION_UP));
7895 windowInSecondary->assertNoEvents();
7896}
7897
Jackal Guof9696682018-10-05 12:23:23 +08007898class InputFilterTest : public InputDispatcherTest {
7899protected:
Prabir Pradhan81420cc2021-09-06 10:28:50 -07007900 void testNotifyMotion(int32_t displayId, bool expectToBeFiltered,
7901 const ui::Transform& transform = ui::Transform()) {
Jackal Guof9696682018-10-05 12:23:23 +08007902 NotifyMotionArgs motionArgs;
7903
Siarhei Vishniakou870ecec2020-12-09 08:07:46 -10007904 motionArgs =
7905 generateMotionArgs(AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN, displayId);
Prabir Pradhan678438e2023-04-13 19:32:51 +00007906 mDispatcher->notifyMotion(motionArgs);
Siarhei Vishniakou870ecec2020-12-09 08:07:46 -10007907 motionArgs =
7908 generateMotionArgs(AMOTION_EVENT_ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN, displayId);
Prabir Pradhan678438e2023-04-13 19:32:51 +00007909 mDispatcher->notifyMotion(motionArgs);
Siarhei Vishniakou2bfa9052019-11-21 18:10:54 -08007910 ASSERT_TRUE(mDispatcher->waitForIdle());
Jackal Guof9696682018-10-05 12:23:23 +08007911 if (expectToBeFiltered) {
Siarhei Vishniakou3218fc02023-06-15 20:41:02 -07007912 const auto xy = transform.transform(motionArgs.pointerCoords[0].getXYValue());
Prabir Pradhan81420cc2021-09-06 10:28:50 -07007913 mFakePolicy->assertFilterInputEventWasCalled(motionArgs, xy);
Jackal Guof9696682018-10-05 12:23:23 +08007914 } else {
7915 mFakePolicy->assertFilterInputEventWasNotCalled();
7916 }
7917 }
7918
7919 void testNotifyKey(bool expectToBeFiltered) {
7920 NotifyKeyArgs keyArgs;
7921
7922 keyArgs = generateKeyArgs(AKEY_EVENT_ACTION_DOWN);
Prabir Pradhan678438e2023-04-13 19:32:51 +00007923 mDispatcher->notifyKey(keyArgs);
Jackal Guof9696682018-10-05 12:23:23 +08007924 keyArgs = generateKeyArgs(AKEY_EVENT_ACTION_UP);
Prabir Pradhan678438e2023-04-13 19:32:51 +00007925 mDispatcher->notifyKey(keyArgs);
Siarhei Vishniakou2bfa9052019-11-21 18:10:54 -08007926 ASSERT_TRUE(mDispatcher->waitForIdle());
Jackal Guof9696682018-10-05 12:23:23 +08007927
7928 if (expectToBeFiltered) {
Siarhei Vishniakou8935a802019-11-15 16:41:44 -08007929 mFakePolicy->assertFilterInputEventWasCalled(keyArgs);
Jackal Guof9696682018-10-05 12:23:23 +08007930 } else {
7931 mFakePolicy->assertFilterInputEventWasNotCalled();
7932 }
7933 }
7934};
7935
7936// Test InputFilter for MotionEvent
7937TEST_F(InputFilterTest, MotionEvent_InputFilter) {
7938 // Since the InputFilter is disabled by default, check if touch events aren't filtered.
Harry Cutts101ee9b2023-07-06 18:04:14 +00007939 testNotifyMotion(ADISPLAY_ID_DEFAULT, /*expectToBeFiltered=*/false);
7940 testNotifyMotion(SECOND_DISPLAY_ID, /*expectToBeFiltered=*/false);
Jackal Guof9696682018-10-05 12:23:23 +08007941
7942 // Enable InputFilter
7943 mDispatcher->setInputFilterEnabled(true);
7944 // Test touch on both primary and second display, and check if both events are filtered.
Harry Cutts101ee9b2023-07-06 18:04:14 +00007945 testNotifyMotion(ADISPLAY_ID_DEFAULT, /*expectToBeFiltered=*/true);
7946 testNotifyMotion(SECOND_DISPLAY_ID, /*expectToBeFiltered=*/true);
Jackal Guof9696682018-10-05 12:23:23 +08007947
7948 // Disable InputFilter
7949 mDispatcher->setInputFilterEnabled(false);
7950 // Test touch on both primary and second display, and check if both events aren't filtered.
Harry Cutts101ee9b2023-07-06 18:04:14 +00007951 testNotifyMotion(ADISPLAY_ID_DEFAULT, /*expectToBeFiltered=*/false);
7952 testNotifyMotion(SECOND_DISPLAY_ID, /*expectToBeFiltered=*/false);
Jackal Guof9696682018-10-05 12:23:23 +08007953}
7954
7955// Test InputFilter for KeyEvent
7956TEST_F(InputFilterTest, KeyEvent_InputFilter) {
7957 // Since the InputFilter is disabled by default, check if key event aren't filtered.
Harry Cutts101ee9b2023-07-06 18:04:14 +00007958 testNotifyKey(/*expectToBeFiltered=*/false);
Jackal Guof9696682018-10-05 12:23:23 +08007959
7960 // Enable InputFilter
7961 mDispatcher->setInputFilterEnabled(true);
7962 // Send a key event, and check if it is filtered.
Harry Cutts101ee9b2023-07-06 18:04:14 +00007963 testNotifyKey(/*expectToBeFiltered=*/true);
Jackal Guof9696682018-10-05 12:23:23 +08007964
7965 // Disable InputFilter
7966 mDispatcher->setInputFilterEnabled(false);
7967 // Send a key event, and check if it isn't filtered.
Harry Cutts101ee9b2023-07-06 18:04:14 +00007968 testNotifyKey(/*expectToBeFiltered=*/false);
Jackal Guof9696682018-10-05 12:23:23 +08007969}
7970
Prabir Pradhan81420cc2021-09-06 10:28:50 -07007971// Ensure that MotionEvents sent to the InputFilter through InputListener are converted to the
7972// logical display coordinate space.
7973TEST_F(InputFilterTest, MotionEvent_UsesLogicalDisplayCoordinates_notifyMotion) {
7974 ui::Transform firstDisplayTransform;
7975 firstDisplayTransform.set({1.1, 2.2, 3.3, 4.4, 5.5, 6.6, 0, 0, 1});
7976 ui::Transform secondDisplayTransform;
7977 secondDisplayTransform.set({-6.6, -5.5, -4.4, -3.3, -2.2, -1.1, 0, 0, 1});
7978
7979 std::vector<gui::DisplayInfo> displayInfos(2);
7980 displayInfos[0].displayId = ADISPLAY_ID_DEFAULT;
7981 displayInfos[0].transform = firstDisplayTransform;
7982 displayInfos[1].displayId = SECOND_DISPLAY_ID;
7983 displayInfos[1].transform = secondDisplayTransform;
7984
Patrick Williamsd828f302023-04-28 17:52:08 -05007985 mDispatcher->onWindowInfosChanged({{}, displayInfos, 0, 0});
Prabir Pradhan81420cc2021-09-06 10:28:50 -07007986
7987 // Enable InputFilter
7988 mDispatcher->setInputFilterEnabled(true);
7989
7990 // Ensure the correct transforms are used for the displays.
Harry Cutts101ee9b2023-07-06 18:04:14 +00007991 testNotifyMotion(ADISPLAY_ID_DEFAULT, /*expectToBeFiltered=*/true, firstDisplayTransform);
7992 testNotifyMotion(SECOND_DISPLAY_ID, /*expectToBeFiltered=*/true, secondDisplayTransform);
Prabir Pradhan81420cc2021-09-06 10:28:50 -07007993}
7994
Siarhei Vishniakou5d552c42021-05-21 05:02:22 +00007995class InputFilterInjectionPolicyTest : public InputDispatcherTest {
7996protected:
7997 virtual void SetUp() override {
7998 InputDispatcherTest::SetUp();
7999
8000 /**
8001 * We don't need to enable input filter to test the injected event policy, but we enabled it
8002 * here to make the tests more realistic, since this policy only matters when inputfilter is
8003 * on.
8004 */
8005 mDispatcher->setInputFilterEnabled(true);
8006
8007 std::shared_ptr<InputApplicationHandle> application =
8008 std::make_shared<FakeApplicationHandle>();
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07008009 mWindow = sp<FakeWindowHandle>::make(application, mDispatcher, "Test Window",
8010 ADISPLAY_ID_DEFAULT);
Siarhei Vishniakou5d552c42021-05-21 05:02:22 +00008011
8012 mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application);
8013 mWindow->setFocusable(true);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07008014 mDispatcher->onWindowInfosChanged({{*mWindow->getInfo()}, {}, 0, 0});
Siarhei Vishniakou5d552c42021-05-21 05:02:22 +00008015 setFocusedWindow(mWindow);
8016 mWindow->consumeFocusEvent(true);
8017 }
8018
Siarhei Vishniakouf00a4ec2021-06-16 03:55:32 +00008019 void testInjectedKey(int32_t policyFlags, int32_t injectedDeviceId, int32_t resolvedDeviceId,
8020 int32_t flags) {
Siarhei Vishniakou5d552c42021-05-21 05:02:22 +00008021 KeyEvent event;
8022
8023 const nsecs_t eventTime = systemTime(SYSTEM_TIME_MONOTONIC);
8024 event.initialize(InputEvent::nextId(), injectedDeviceId, AINPUT_SOURCE_KEYBOARD,
8025 ADISPLAY_ID_NONE, INVALID_HMAC, AKEY_EVENT_ACTION_DOWN, 0, AKEYCODE_A,
Harry Cutts33476232023-01-30 19:57:29 +00008026 KEY_A, AMETA_NONE, /*repeatCount=*/0, eventTime, eventTime);
Siarhei Vishniakou5d552c42021-05-21 05:02:22 +00008027 const int32_t additionalPolicyFlags =
8028 POLICY_FLAG_PASS_TO_USER | POLICY_FLAG_DISABLE_KEY_REPEAT;
8029 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Harry Cutts33476232023-01-30 19:57:29 +00008030 mDispatcher->injectInputEvent(&event, /*targetUid=*/{},
Siarhei Vishniakou4648fea2023-06-27 01:00:12 +00008031 InputEventInjectionSync::WAIT_FOR_RESULT, 100ms,
Siarhei Vishniakou5d552c42021-05-21 05:02:22 +00008032 policyFlags | additionalPolicyFlags));
8033
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07008034 mWindow->consumeKeyEvent(AllOf(WithDeviceId(resolvedDeviceId), WithFlags(flags)));
Siarhei Vishniakouf00a4ec2021-06-16 03:55:32 +00008035 }
8036
8037 void testInjectedMotion(int32_t policyFlags, int32_t injectedDeviceId, int32_t resolvedDeviceId,
8038 int32_t flags) {
8039 MotionEvent event;
8040 PointerProperties pointerProperties[1];
8041 PointerCoords pointerCoords[1];
8042 pointerProperties[0].clear();
8043 pointerProperties[0].id = 0;
8044 pointerCoords[0].clear();
8045 pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_X, 300);
8046 pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_Y, 400);
8047
8048 ui::Transform identityTransform;
8049 const nsecs_t eventTime = systemTime(SYSTEM_TIME_MONOTONIC);
8050 event.initialize(InputEvent::nextId(), injectedDeviceId, AINPUT_SOURCE_TOUCHSCREEN,
8051 DISPLAY_ID, INVALID_HMAC, AMOTION_EVENT_ACTION_DOWN, 0, 0,
8052 AMOTION_EVENT_EDGE_FLAG_NONE, AMETA_NONE, 0, MotionClassification::NONE,
8053 identityTransform, 0, 0, AMOTION_EVENT_INVALID_CURSOR_POSITION,
Prabir Pradhanb9b18502021-08-26 12:30:32 -07008054 AMOTION_EVENT_INVALID_CURSOR_POSITION, identityTransform, eventTime,
Evan Rosky09576692021-07-01 12:22:09 -07008055 eventTime,
Harry Cutts101ee9b2023-07-06 18:04:14 +00008056 /*pointerCount=*/1, pointerProperties, pointerCoords);
Siarhei Vishniakouf00a4ec2021-06-16 03:55:32 +00008057
8058 const int32_t additionalPolicyFlags = POLICY_FLAG_PASS_TO_USER;
8059 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Harry Cutts33476232023-01-30 19:57:29 +00008060 mDispatcher->injectInputEvent(&event, /*targetUid=*/{},
Siarhei Vishniakou4648fea2023-06-27 01:00:12 +00008061 InputEventInjectionSync::WAIT_FOR_RESULT, 100ms,
Siarhei Vishniakouf00a4ec2021-06-16 03:55:32 +00008062 policyFlags | additionalPolicyFlags));
8063
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07008064 mWindow->consumeMotionEvent(AllOf(WithFlags(flags), WithDeviceId(resolvedDeviceId)));
Siarhei Vishniakou5d552c42021-05-21 05:02:22 +00008065 }
8066
8067private:
8068 sp<FakeWindowHandle> mWindow;
8069};
8070
8071TEST_F(InputFilterInjectionPolicyTest, TrustedFilteredEvents_KeepOriginalDeviceId) {
Siarhei Vishniakouf00a4ec2021-06-16 03:55:32 +00008072 // Must have POLICY_FLAG_FILTERED here to indicate that the event has gone through the input
8073 // filter. Without it, the event will no different from a regularly injected event, and the
8074 // injected device id will be overwritten.
Harry Cutts33476232023-01-30 19:57:29 +00008075 testInjectedKey(POLICY_FLAG_FILTERED, /*injectedDeviceId=*/3, /*resolvedDeviceId=*/3,
8076 /*flags=*/0);
Siarhei Vishniakou5d552c42021-05-21 05:02:22 +00008077}
8078
Siarhei Vishniakouf00a4ec2021-06-16 03:55:32 +00008079TEST_F(InputFilterInjectionPolicyTest, KeyEventsInjectedFromAccessibility_HaveAccessibilityFlag) {
Siarhei Vishniakou5d552c42021-05-21 05:02:22 +00008080 testInjectedKey(POLICY_FLAG_FILTERED | POLICY_FLAG_INJECTED_FROM_ACCESSIBILITY,
Harry Cutts33476232023-01-30 19:57:29 +00008081 /*injectedDeviceId=*/3, /*resolvedDeviceId=*/3,
Siarhei Vishniakouf00a4ec2021-06-16 03:55:32 +00008082 AKEY_EVENT_FLAG_IS_ACCESSIBILITY_EVENT);
8083}
8084
8085TEST_F(InputFilterInjectionPolicyTest,
8086 MotionEventsInjectedFromAccessibility_HaveAccessibilityFlag) {
8087 testInjectedMotion(POLICY_FLAG_FILTERED | POLICY_FLAG_INJECTED_FROM_ACCESSIBILITY,
Harry Cutts33476232023-01-30 19:57:29 +00008088 /*injectedDeviceId=*/3, /*resolvedDeviceId=*/3,
Siarhei Vishniakouf00a4ec2021-06-16 03:55:32 +00008089 AMOTION_EVENT_FLAG_IS_ACCESSIBILITY_EVENT);
Siarhei Vishniakou5d552c42021-05-21 05:02:22 +00008090}
8091
8092TEST_F(InputFilterInjectionPolicyTest, RegularInjectedEvents_ReceiveVirtualDeviceId) {
Harry Cutts33476232023-01-30 19:57:29 +00008093 testInjectedKey(/*policyFlags=*/0, /*injectedDeviceId=*/3,
8094 /*resolvedDeviceId=*/VIRTUAL_KEYBOARD_ID, /*flags=*/0);
Siarhei Vishniakou5d552c42021-05-21 05:02:22 +00008095}
8096
Yeabkal Wubshitb8aadfa2024-01-17 17:03:42 -08008097class InputDispatcherUserActivityPokeTests : public InputDispatcherTest {
8098protected:
8099 virtual void SetUp() override {
8100 InputDispatcherTest::SetUp();
8101
8102 std::shared_ptr<FakeApplicationHandle> application =
8103 std::make_shared<FakeApplicationHandle>();
8104 application->setDispatchingTimeout(100ms);
8105 mWindow = sp<FakeWindowHandle>::make(application, mDispatcher, "TestWindow",
8106 ADISPLAY_ID_DEFAULT);
Yeabkal Wubshit222d83d2024-01-24 18:00:09 +00008107 mWindow->setFrame(Rect(0, 0, 100, 100));
Yeabkal Wubshitb8aadfa2024-01-17 17:03:42 -08008108 mWindow->setDispatchingTimeout(100ms);
8109 mWindow->setFocusable(true);
8110
8111 // Set focused application.
8112 mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application);
8113
8114 mDispatcher->onWindowInfosChanged({{*mWindow->getInfo()}, {}, 0, 0});
8115 setFocusedWindow(mWindow);
8116 mWindow->consumeFocusEvent(true);
8117 }
8118
8119 void notifyAndConsumeMotion(int32_t action, uint32_t source, int32_t displayId,
8120 nsecs_t eventTime) {
8121 mDispatcher->notifyMotion(MotionArgsBuilder(action, source)
8122 .displayId(displayId)
8123 .eventTime(eventTime)
8124 .pointer(PointerBuilder(0, ToolType::FINGER).x(50).y(50))
8125 .build());
8126 mWindow->consumeMotionEvent(WithMotionAction(action));
8127 }
8128
8129private:
8130 sp<FakeWindowHandle> mWindow;
8131};
8132
8133TEST_F_WITH_FLAGS(
8134 InputDispatcherUserActivityPokeTests, MinPokeTimeObserved,
8135 REQUIRES_FLAGS_ENABLED(ACONFIG_FLAG(com::android::input::flags,
8136 rate_limit_user_activity_poke_in_dispatcher))) {
8137 mDispatcher->setMinTimeBetweenUserActivityPokes(50ms);
8138
8139 // First event of type TOUCH. Should poke.
8140 notifyAndConsumeMotion(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
8141 milliseconds_to_nanoseconds(50));
8142 mFakePolicy->assertUserActivityPoked(
8143 {{milliseconds_to_nanoseconds(50), USER_ACTIVITY_EVENT_TOUCH, ADISPLAY_ID_DEFAULT}});
8144
8145 // 80ns > 50ns has passed since previous TOUCH event. Should poke.
8146 notifyAndConsumeMotion(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
8147 milliseconds_to_nanoseconds(130));
8148 mFakePolicy->assertUserActivityPoked(
8149 {{milliseconds_to_nanoseconds(130), USER_ACTIVITY_EVENT_TOUCH, ADISPLAY_ID_DEFAULT}});
8150
8151 // First event of type OTHER. Should poke (despite being within 50ns of previous TOUCH event).
8152 notifyAndConsumeMotion(ACTION_SCROLL, AINPUT_SOURCE_ROTARY_ENCODER, ADISPLAY_ID_DEFAULT,
8153 milliseconds_to_nanoseconds(135));
8154 mFakePolicy->assertUserActivityPoked(
8155 {{milliseconds_to_nanoseconds(135), USER_ACTIVITY_EVENT_OTHER, ADISPLAY_ID_DEFAULT}});
8156
8157 // Within 50ns of previous TOUCH event. Should NOT poke.
8158 notifyAndConsumeMotion(ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
8159 milliseconds_to_nanoseconds(140));
8160 mFakePolicy->assertUserActivityNotPoked();
8161
8162 // Within 50ns of previous OTHER event. Should NOT poke.
8163 notifyAndConsumeMotion(ACTION_SCROLL, AINPUT_SOURCE_ROTARY_ENCODER, ADISPLAY_ID_DEFAULT,
8164 milliseconds_to_nanoseconds(150));
8165 mFakePolicy->assertUserActivityNotPoked();
8166
8167 // Within 50ns of previous TOUCH event (which was at time 130). Should NOT poke.
8168 // Note that STYLUS is mapped to TOUCH user activity, since it's a pointer-type source.
8169 notifyAndConsumeMotion(ACTION_DOWN, AINPUT_SOURCE_STYLUS, ADISPLAY_ID_DEFAULT,
8170 milliseconds_to_nanoseconds(160));
8171 mFakePolicy->assertUserActivityNotPoked();
8172
8173 // 65ns > 50ns has passed since previous OTHER event. Should poke.
8174 notifyAndConsumeMotion(ACTION_SCROLL, AINPUT_SOURCE_ROTARY_ENCODER, ADISPLAY_ID_DEFAULT,
8175 milliseconds_to_nanoseconds(200));
8176 mFakePolicy->assertUserActivityPoked(
8177 {{milliseconds_to_nanoseconds(200), USER_ACTIVITY_EVENT_OTHER, ADISPLAY_ID_DEFAULT}});
8178
8179 // 170ns > 50ns has passed since previous TOUCH event. Should poke.
8180 notifyAndConsumeMotion(ACTION_UP, AINPUT_SOURCE_STYLUS, ADISPLAY_ID_DEFAULT,
8181 milliseconds_to_nanoseconds(300));
8182 mFakePolicy->assertUserActivityPoked(
8183 {{milliseconds_to_nanoseconds(300), USER_ACTIVITY_EVENT_TOUCH, ADISPLAY_ID_DEFAULT}});
8184
8185 // Assert that there's no more user activity poke event.
8186 mFakePolicy->assertUserActivityNotPoked();
8187}
8188
8189TEST_F_WITH_FLAGS(
8190 InputDispatcherUserActivityPokeTests, DefaultMinPokeTimeOf100MsUsed,
8191 REQUIRES_FLAGS_ENABLED(ACONFIG_FLAG(com::android::input::flags,
8192 rate_limit_user_activity_poke_in_dispatcher))) {
8193 notifyAndConsumeMotion(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
8194 milliseconds_to_nanoseconds(200));
8195 mFakePolicy->assertUserActivityPoked(
8196 {{milliseconds_to_nanoseconds(200), USER_ACTIVITY_EVENT_TOUCH, ADISPLAY_ID_DEFAULT}});
8197
8198 notifyAndConsumeMotion(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
8199 milliseconds_to_nanoseconds(280));
8200 mFakePolicy->assertUserActivityNotPoked();
8201
8202 notifyAndConsumeMotion(ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
8203 milliseconds_to_nanoseconds(340));
8204 mFakePolicy->assertUserActivityPoked(
8205 {{milliseconds_to_nanoseconds(340), USER_ACTIVITY_EVENT_TOUCH, ADISPLAY_ID_DEFAULT}});
8206}
8207
8208TEST_F_WITH_FLAGS(
8209 InputDispatcherUserActivityPokeTests, ZeroMinPokeTimeDisablesRateLimiting,
8210 REQUIRES_FLAGS_ENABLED(ACONFIG_FLAG(com::android::input::flags,
8211 rate_limit_user_activity_poke_in_dispatcher))) {
8212 mDispatcher->setMinTimeBetweenUserActivityPokes(0ms);
8213
8214 notifyAndConsumeMotion(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, 20);
8215 mFakePolicy->assertUserActivityPoked();
8216
8217 notifyAndConsumeMotion(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, 30);
8218 mFakePolicy->assertUserActivityPoked();
8219}
8220
chaviwfd6d3512019-03-25 13:23:49 -07008221class InputDispatcherOnPointerDownOutsideFocus : public InputDispatcherTest {
Prabir Pradhan3608aad2019-10-02 17:08:26 -07008222 virtual void SetUp() override {
chaviwfd6d3512019-03-25 13:23:49 -07008223 InputDispatcherTest::SetUp();
8224
Chris Yea209fde2020-07-22 13:54:51 -07008225 std::shared_ptr<FakeApplicationHandle> application =
8226 std::make_shared<FakeApplicationHandle>();
Siarhei Vishniakou870ecec2020-12-09 08:07:46 -10008227 mUnfocusedWindow =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07008228 sp<FakeWindowHandle>::make(application, mDispatcher, "Top", ADISPLAY_ID_DEFAULT);
chaviwfd6d3512019-03-25 13:23:49 -07008229 mUnfocusedWindow->setFrame(Rect(0, 0, 30, 30));
chaviwfd6d3512019-03-25 13:23:49 -07008230
Siarhei Vishniakoub9b15352019-11-26 13:19:26 -08008231 mFocusedWindow =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07008232 sp<FakeWindowHandle>::make(application, mDispatcher, "Second", ADISPLAY_ID_DEFAULT);
Siarhei Vishniakoub9b15352019-11-26 13:19:26 -08008233 mFocusedWindow->setFrame(Rect(50, 50, 100, 100));
chaviwfd6d3512019-03-25 13:23:49 -07008234
8235 // Set focused application.
8236 mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application);
Vishnu Nair47074b82020-08-14 11:54:47 -07008237 mFocusedWindow->setFocusable(true);
chaviwfd6d3512019-03-25 13:23:49 -07008238
8239 // Expect one focus window exist in display.
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07008240 mDispatcher->onWindowInfosChanged(
8241 {{*mUnfocusedWindow->getInfo(), *mFocusedWindow->getInfo()}, {}, 0, 0});
Vishnu Nair958da932020-08-21 17:12:37 -07008242 setFocusedWindow(mFocusedWindow);
Siarhei Vishniakouf1035d42019-09-20 16:32:01 +01008243 mFocusedWindow->consumeFocusEvent(true);
chaviwfd6d3512019-03-25 13:23:49 -07008244 }
8245
Prabir Pradhan3608aad2019-10-02 17:08:26 -07008246 virtual void TearDown() override {
chaviwfd6d3512019-03-25 13:23:49 -07008247 InputDispatcherTest::TearDown();
8248
8249 mUnfocusedWindow.clear();
Siarhei Vishniakoub9b15352019-11-26 13:19:26 -08008250 mFocusedWindow.clear();
chaviwfd6d3512019-03-25 13:23:49 -07008251 }
8252
8253protected:
8254 sp<FakeWindowHandle> mUnfocusedWindow;
Siarhei Vishniakoub9b15352019-11-26 13:19:26 -08008255 sp<FakeWindowHandle> mFocusedWindow;
Siarhei Vishniakoufb9fcda2020-05-04 14:59:19 -07008256 static constexpr PointF FOCUSED_WINDOW_TOUCH_POINT = {60, 60};
chaviwfd6d3512019-03-25 13:23:49 -07008257};
8258
8259// Have two windows, one with focus. Inject MotionEvent with source TOUCHSCREEN and action
8260// DOWN on the window that doesn't have focus. Ensure the window that didn't have focus received
8261// the onPointerDownOutsideFocus callback.
8262TEST_F(InputDispatcherOnPointerDownOutsideFocus, OnPointerDownOutsideFocus_Success) {
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08008263 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07008264 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
Siarhei Vishniakoufb9fcda2020-05-04 14:59:19 -07008265 {20, 20}))
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08008266 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
Siarhei Vishniakou03aee2a2020-04-13 20:44:54 -07008267 mUnfocusedWindow->consumeMotionDown();
chaviwfd6d3512019-03-25 13:23:49 -07008268
Siarhei Vishniakou2bfa9052019-11-21 18:10:54 -08008269 ASSERT_TRUE(mDispatcher->waitForIdle());
chaviwfd6d3512019-03-25 13:23:49 -07008270 mFakePolicy->assertOnPointerDownEquals(mUnfocusedWindow->getToken());
8271}
8272
8273// Have two windows, one with focus. Inject MotionEvent with source TRACKBALL and action
8274// DOWN on the window that doesn't have focus. Ensure no window received the
8275// onPointerDownOutsideFocus callback.
8276TEST_F(InputDispatcherOnPointerDownOutsideFocus, OnPointerDownOutsideFocus_NonPointerSource) {
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08008277 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07008278 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TRACKBALL, ADISPLAY_ID_DEFAULT,
8279 {20, 20}))
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08008280 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
Siarhei Vishniakou03aee2a2020-04-13 20:44:54 -07008281 mFocusedWindow->consumeMotionDown();
chaviwfd6d3512019-03-25 13:23:49 -07008282
Siarhei Vishniakou2bfa9052019-11-21 18:10:54 -08008283 ASSERT_TRUE(mDispatcher->waitForIdle());
8284 mFakePolicy->assertOnPointerDownWasNotCalled();
chaviwfd6d3512019-03-25 13:23:49 -07008285}
8286
8287// Have two windows, one with focus. Inject KeyEvent with action DOWN on the window that doesn't
8288// have focus. Ensure no window received the onPointerDownOutsideFocus callback.
8289TEST_F(InputDispatcherOnPointerDownOutsideFocus, OnPointerDownOutsideFocus_NonMotionFailure) {
Prabir Pradhan93f342c2021-03-11 15:05:30 -08008290 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07008291 injectKeyDownNoRepeat(*mDispatcher, ADISPLAY_ID_DEFAULT))
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08008292 << "Inject key event should return InputEventInjectionResult::SUCCEEDED";
Siarhei Vishniakou03aee2a2020-04-13 20:44:54 -07008293 mFocusedWindow->consumeKeyDown(ADISPLAY_ID_DEFAULT);
chaviwfd6d3512019-03-25 13:23:49 -07008294
Siarhei Vishniakou2bfa9052019-11-21 18:10:54 -08008295 ASSERT_TRUE(mDispatcher->waitForIdle());
8296 mFakePolicy->assertOnPointerDownWasNotCalled();
chaviwfd6d3512019-03-25 13:23:49 -07008297}
8298
8299// Have two windows, one with focus. Inject MotionEvent with source TOUCHSCREEN and action
8300// DOWN on the window that already has focus. Ensure no window received the
8301// onPointerDownOutsideFocus callback.
Siarhei Vishniakou870ecec2020-12-09 08:07:46 -10008302TEST_F(InputDispatcherOnPointerDownOutsideFocus, OnPointerDownOutsideFocus_OnAlreadyFocusedWindow) {
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08008303 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07008304 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
Siarhei Vishniakoufb9fcda2020-05-04 14:59:19 -07008305 FOCUSED_WINDOW_TOUCH_POINT))
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08008306 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
Siarhei Vishniakou03aee2a2020-04-13 20:44:54 -07008307 mFocusedWindow->consumeMotionDown();
chaviwfd6d3512019-03-25 13:23:49 -07008308
Siarhei Vishniakou2bfa9052019-11-21 18:10:54 -08008309 ASSERT_TRUE(mDispatcher->waitForIdle());
8310 mFakePolicy->assertOnPointerDownWasNotCalled();
chaviwfd6d3512019-03-25 13:23:49 -07008311}
8312
Prabir Pradhan47cf0a02021-03-11 20:30:57 -08008313// Have two windows, one with focus. Injecting a trusted DOWN MotionEvent with the flag
8314// NO_FOCUS_CHANGE on the unfocused window should not call the onPointerDownOutsideFocus callback.
8315TEST_F(InputDispatcherOnPointerDownOutsideFocus, NoFocusChangeFlag) {
8316 const MotionEvent event =
8317 MotionEventBuilder(AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_MOUSE)
8318 .eventTime(systemTime(SYSTEM_TIME_MONOTONIC))
Siarhei Vishniakou6d73f832022-07-21 17:27:03 -07008319 .pointer(PointerBuilder(/*id=*/0, ToolType::FINGER).x(20).y(20))
Prabir Pradhan47cf0a02021-03-11 20:30:57 -08008320 .addFlag(AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE)
8321 .build();
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07008322 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectMotionEvent(*mDispatcher, event))
Prabir Pradhan47cf0a02021-03-11 20:30:57 -08008323 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
8324 mUnfocusedWindow->consumeAnyMotionDown(ADISPLAY_ID_DEFAULT, AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
8325
8326 ASSERT_TRUE(mDispatcher->waitForIdle());
8327 mFakePolicy->assertOnPointerDownWasNotCalled();
8328 // Ensure that the unfocused window did not receive any FOCUS events.
8329 mUnfocusedWindow->assertNoEvents();
8330}
8331
chaviwaf87b3e2019-10-01 16:59:28 -07008332// These tests ensures we can send touch events to a single client when there are multiple input
8333// windows that point to the same client token.
8334class InputDispatcherMultiWindowSameTokenTests : public InputDispatcherTest {
8335 virtual void SetUp() override {
8336 InputDispatcherTest::SetUp();
8337
Chris Yea209fde2020-07-22 13:54:51 -07008338 std::shared_ptr<FakeApplicationHandle> application =
8339 std::make_shared<FakeApplicationHandle>();
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07008340 mWindow1 = sp<FakeWindowHandle>::make(application, mDispatcher, "Fake Window 1",
8341 ADISPLAY_ID_DEFAULT);
chaviwaf87b3e2019-10-01 16:59:28 -07008342 mWindow1->setFrame(Rect(0, 0, 100, 100));
8343
Prabir Pradhane7cc69c2024-01-05 21:35:28 +00008344 mWindow2 = mWindow1->clone(ADISPLAY_ID_DEFAULT);
chaviwaf87b3e2019-10-01 16:59:28 -07008345 mWindow2->setFrame(Rect(100, 100, 200, 200));
8346
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07008347 mDispatcher->onWindowInfosChanged({{*mWindow1->getInfo(), *mWindow2->getInfo()}, {}, 0, 0});
chaviwaf87b3e2019-10-01 16:59:28 -07008348 }
8349
8350protected:
8351 sp<FakeWindowHandle> mWindow1;
8352 sp<FakeWindowHandle> mWindow2;
8353
8354 // Helper function to convert the point from screen coordinates into the window's space
chaviw3277faf2021-05-19 16:45:23 -05008355 static PointF getPointInWindow(const WindowInfo* windowInfo, const PointF& point) {
chaviw1ff3d1e2020-07-01 15:53:47 -07008356 vec2 vals = windowInfo->transform.transform(point.x, point.y);
8357 return {vals.x, vals.y};
chaviwaf87b3e2019-10-01 16:59:28 -07008358 }
8359
8360 void consumeMotionEvent(const sp<FakeWindowHandle>& window, int32_t expectedAction,
8361 const std::vector<PointF>& points) {
Siarhei Vishniakouf1035d42019-09-20 16:32:01 +01008362 const std::string name = window->getName();
Siarhei Vishniakoud3061ab2023-12-18 20:41:08 -08008363 std::unique_ptr<MotionEvent> motionEvent =
Prabir Pradhan7662a8d2023-12-15 01:58:14 +00008364 window->consumeMotionEvent(WithMotionAction(expectedAction));
Siarhei Vishniakoud3061ab2023-12-18 20:41:08 -08008365 ASSERT_NE(nullptr, motionEvent);
8366 ASSERT_EQ(points.size(), motionEvent->getPointerCount());
chaviwaf87b3e2019-10-01 16:59:28 -07008367
8368 for (size_t i = 0; i < points.size(); i++) {
8369 float expectedX = points[i].x;
8370 float expectedY = points[i].y;
8371
Siarhei Vishniakoud3061ab2023-12-18 20:41:08 -08008372 EXPECT_EQ(expectedX, motionEvent->getX(i))
chaviwaf87b3e2019-10-01 16:59:28 -07008373 << "expected " << expectedX << " for x[" << i << "] coord of " << name.c_str()
Siarhei Vishniakoud3061ab2023-12-18 20:41:08 -08008374 << ", got " << motionEvent->getX(i);
8375 EXPECT_EQ(expectedY, motionEvent->getY(i))
chaviwaf87b3e2019-10-01 16:59:28 -07008376 << "expected " << expectedY << " for y[" << i << "] coord of " << name.c_str()
Siarhei Vishniakoud3061ab2023-12-18 20:41:08 -08008377 << ", got " << motionEvent->getY(i);
chaviwaf87b3e2019-10-01 16:59:28 -07008378 }
8379 }
chaviw9eaa22c2020-07-01 16:21:27 -07008380
Prabir Pradhanbb3f1c02024-01-04 20:17:14 +00008381 void touchAndAssertPositions(sp<FakeWindowHandle> touchedWindow, int32_t action,
8382 const std::vector<PointF>& touchedPoints,
chaviw9eaa22c2020-07-01 16:21:27 -07008383 std::vector<PointF> expectedPoints) {
Prabir Pradhan678438e2023-04-13 19:32:51 +00008384 mDispatcher->notifyMotion(generateMotionArgs(action, AINPUT_SOURCE_TOUCHSCREEN,
8385 ADISPLAY_ID_DEFAULT, touchedPoints));
chaviw9eaa22c2020-07-01 16:21:27 -07008386
Prabir Pradhanbb3f1c02024-01-04 20:17:14 +00008387 consumeMotionEvent(touchedWindow, action, expectedPoints);
chaviw9eaa22c2020-07-01 16:21:27 -07008388 }
chaviwaf87b3e2019-10-01 16:59:28 -07008389};
8390
8391TEST_F(InputDispatcherMultiWindowSameTokenTests, SingleTouchSameScale) {
8392 // Touch Window 1
8393 PointF touchedPoint = {10, 10};
8394 PointF expectedPoint = getPointInWindow(mWindow1->getInfo(), touchedPoint);
Prabir Pradhanbb3f1c02024-01-04 20:17:14 +00008395 touchAndAssertPositions(mWindow1, AMOTION_EVENT_ACTION_DOWN, {touchedPoint}, {expectedPoint});
chaviwaf87b3e2019-10-01 16:59:28 -07008396
8397 // Release touch on Window 1
Prabir Pradhanbb3f1c02024-01-04 20:17:14 +00008398 touchAndAssertPositions(mWindow1, AMOTION_EVENT_ACTION_UP, {touchedPoint}, {expectedPoint});
chaviwaf87b3e2019-10-01 16:59:28 -07008399
8400 // Touch Window 2
8401 touchedPoint = {150, 150};
8402 expectedPoint = getPointInWindow(mWindow2->getInfo(), touchedPoint);
Prabir Pradhanbb3f1c02024-01-04 20:17:14 +00008403 touchAndAssertPositions(mWindow2, AMOTION_EVENT_ACTION_DOWN, {touchedPoint}, {expectedPoint});
chaviwaf87b3e2019-10-01 16:59:28 -07008404}
8405
chaviw9eaa22c2020-07-01 16:21:27 -07008406TEST_F(InputDispatcherMultiWindowSameTokenTests, SingleTouchDifferentTransform) {
8407 // Set scale value for window2
chaviwaf87b3e2019-10-01 16:59:28 -07008408 mWindow2->setWindowScale(0.5f, 0.5f);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07008409 mDispatcher->onWindowInfosChanged({{*mWindow1->getInfo(), *mWindow2->getInfo()}, {}, 0, 0});
chaviwaf87b3e2019-10-01 16:59:28 -07008410
8411 // Touch Window 1
8412 PointF touchedPoint = {10, 10};
8413 PointF expectedPoint = getPointInWindow(mWindow1->getInfo(), touchedPoint);
Prabir Pradhanbb3f1c02024-01-04 20:17:14 +00008414 touchAndAssertPositions(mWindow1, AMOTION_EVENT_ACTION_DOWN, {touchedPoint}, {expectedPoint});
chaviwaf87b3e2019-10-01 16:59:28 -07008415 // Release touch on Window 1
Prabir Pradhanbb3f1c02024-01-04 20:17:14 +00008416 touchAndAssertPositions(mWindow1, AMOTION_EVENT_ACTION_UP, {touchedPoint}, {expectedPoint});
chaviwaf87b3e2019-10-01 16:59:28 -07008417
8418 // Touch Window 2
8419 touchedPoint = {150, 150};
8420 expectedPoint = getPointInWindow(mWindow2->getInfo(), touchedPoint);
Prabir Pradhanbb3f1c02024-01-04 20:17:14 +00008421 touchAndAssertPositions(mWindow2, AMOTION_EVENT_ACTION_DOWN, {touchedPoint}, {expectedPoint});
8422 touchAndAssertPositions(mWindow2, AMOTION_EVENT_ACTION_UP, {touchedPoint}, {expectedPoint});
chaviwaf87b3e2019-10-01 16:59:28 -07008423
chaviw9eaa22c2020-07-01 16:21:27 -07008424 // Update the transform so rotation is set
8425 mWindow2->setWindowTransform(0, -1, 1, 0);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07008426 mDispatcher->onWindowInfosChanged({{*mWindow1->getInfo(), *mWindow2->getInfo()}, {}, 0, 0});
chaviw9eaa22c2020-07-01 16:21:27 -07008427 expectedPoint = getPointInWindow(mWindow2->getInfo(), touchedPoint);
Prabir Pradhanbb3f1c02024-01-04 20:17:14 +00008428 touchAndAssertPositions(mWindow2, AMOTION_EVENT_ACTION_DOWN, {touchedPoint}, {expectedPoint});
chaviwaf87b3e2019-10-01 16:59:28 -07008429}
8430
chaviw9eaa22c2020-07-01 16:21:27 -07008431TEST_F(InputDispatcherMultiWindowSameTokenTests, MultipleTouchDifferentTransform) {
Chavi Weingarten65f98b82020-01-16 18:56:50 +00008432 mWindow2->setWindowScale(0.5f, 0.5f);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07008433 mDispatcher->onWindowInfosChanged({{*mWindow1->getInfo(), *mWindow2->getInfo()}, {}, 0, 0});
Chavi Weingarten65f98b82020-01-16 18:56:50 +00008434
8435 // Touch Window 1
8436 std::vector<PointF> touchedPoints = {PointF{10, 10}};
8437 std::vector<PointF> expectedPoints = {getPointInWindow(mWindow1->getInfo(), touchedPoints[0])};
Prabir Pradhanbb3f1c02024-01-04 20:17:14 +00008438 touchAndAssertPositions(mWindow1, AMOTION_EVENT_ACTION_DOWN, touchedPoints, expectedPoints);
Chavi Weingarten65f98b82020-01-16 18:56:50 +00008439
8440 // Touch Window 2
Prabir Pradhanbb3f1c02024-01-04 20:17:14 +00008441 // Since this is part of the same touch gesture that has already been dispatched to Window 1,
8442 // the touch stream from Window 2 will be merged with the stream in Window 1. The merged stream
8443 // will continue to be dispatched through Window 1.
chaviw9eaa22c2020-07-01 16:21:27 -07008444 touchedPoints.push_back(PointF{150, 150});
8445 expectedPoints.push_back(getPointInWindow(mWindow2->getInfo(), touchedPoints[1]));
Prabir Pradhanbb3f1c02024-01-04 20:17:14 +00008446 touchAndAssertPositions(mWindow1, POINTER_1_DOWN, touchedPoints, expectedPoints);
Chavi Weingarten65f98b82020-01-16 18:56:50 +00008447
chaviw9eaa22c2020-07-01 16:21:27 -07008448 // Release Window 2
Prabir Pradhanbb3f1c02024-01-04 20:17:14 +00008449 touchAndAssertPositions(mWindow1, POINTER_1_UP, touchedPoints, expectedPoints);
chaviw9eaa22c2020-07-01 16:21:27 -07008450 expectedPoints.pop_back();
Chavi Weingarten65f98b82020-01-16 18:56:50 +00008451
chaviw9eaa22c2020-07-01 16:21:27 -07008452 // Update the transform so rotation is set for Window 2
8453 mWindow2->setWindowTransform(0, -1, 1, 0);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07008454 mDispatcher->onWindowInfosChanged({{*mWindow1->getInfo(), *mWindow2->getInfo()}, {}, 0, 0});
chaviw9eaa22c2020-07-01 16:21:27 -07008455 expectedPoints.push_back(getPointInWindow(mWindow2->getInfo(), touchedPoints[1]));
Prabir Pradhanbb3f1c02024-01-04 20:17:14 +00008456 touchAndAssertPositions(mWindow1, POINTER_1_DOWN, touchedPoints, expectedPoints);
Chavi Weingarten65f98b82020-01-16 18:56:50 +00008457}
8458
chaviw9eaa22c2020-07-01 16:21:27 -07008459TEST_F(InputDispatcherMultiWindowSameTokenTests, MultipleTouchMoveDifferentTransform) {
Chavi Weingarten65f98b82020-01-16 18:56:50 +00008460 mWindow2->setWindowScale(0.5f, 0.5f);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07008461 mDispatcher->onWindowInfosChanged({{*mWindow1->getInfo(), *mWindow2->getInfo()}, {}, 0, 0});
Chavi Weingarten65f98b82020-01-16 18:56:50 +00008462
8463 // Touch Window 1
8464 std::vector<PointF> touchedPoints = {PointF{10, 10}};
8465 std::vector<PointF> expectedPoints = {getPointInWindow(mWindow1->getInfo(), touchedPoints[0])};
Prabir Pradhanbb3f1c02024-01-04 20:17:14 +00008466 touchAndAssertPositions(mWindow1, AMOTION_EVENT_ACTION_DOWN, touchedPoints, expectedPoints);
Chavi Weingarten65f98b82020-01-16 18:56:50 +00008467
8468 // Touch Window 2
chaviw9eaa22c2020-07-01 16:21:27 -07008469 touchedPoints.push_back(PointF{150, 150});
8470 expectedPoints.push_back(getPointInWindow(mWindow2->getInfo(), touchedPoints[1]));
Chavi Weingarten65f98b82020-01-16 18:56:50 +00008471
Prabir Pradhanbb3f1c02024-01-04 20:17:14 +00008472 touchAndAssertPositions(mWindow1, POINTER_1_DOWN, touchedPoints, expectedPoints);
Chavi Weingarten65f98b82020-01-16 18:56:50 +00008473
8474 // Move both windows
8475 touchedPoints = {{20, 20}, {175, 175}};
8476 expectedPoints = {getPointInWindow(mWindow1->getInfo(), touchedPoints[0]),
8477 getPointInWindow(mWindow2->getInfo(), touchedPoints[1])};
8478
Prabir Pradhanbb3f1c02024-01-04 20:17:14 +00008479 touchAndAssertPositions(mWindow1, AMOTION_EVENT_ACTION_MOVE, touchedPoints, expectedPoints);
Chavi Weingarten65f98b82020-01-16 18:56:50 +00008480
chaviw9eaa22c2020-07-01 16:21:27 -07008481 // Release Window 2
Prabir Pradhanbb3f1c02024-01-04 20:17:14 +00008482 touchAndAssertPositions(mWindow1, POINTER_1_UP, touchedPoints, expectedPoints);
chaviw9eaa22c2020-07-01 16:21:27 -07008483 expectedPoints.pop_back();
8484
8485 // Touch Window 2
8486 mWindow2->setWindowTransform(0, -1, 1, 0);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07008487 mDispatcher->onWindowInfosChanged({{*mWindow1->getInfo(), *mWindow2->getInfo()}, {}, 0, 0});
chaviw9eaa22c2020-07-01 16:21:27 -07008488 expectedPoints.push_back(getPointInWindow(mWindow2->getInfo(), touchedPoints[1]));
Prabir Pradhanbb3f1c02024-01-04 20:17:14 +00008489 touchAndAssertPositions(mWindow1, POINTER_1_DOWN, touchedPoints, expectedPoints);
chaviw9eaa22c2020-07-01 16:21:27 -07008490
8491 // Move both windows
8492 touchedPoints = {{20, 20}, {175, 175}};
8493 expectedPoints = {getPointInWindow(mWindow1->getInfo(), touchedPoints[0]),
8494 getPointInWindow(mWindow2->getInfo(), touchedPoints[1])};
8495
Prabir Pradhanbb3f1c02024-01-04 20:17:14 +00008496 touchAndAssertPositions(mWindow1, AMOTION_EVENT_ACTION_MOVE, touchedPoints, expectedPoints);
Chavi Weingarten65f98b82020-01-16 18:56:50 +00008497}
8498
8499TEST_F(InputDispatcherMultiWindowSameTokenTests, MultipleWindowsFirstTouchWithScale) {
8500 mWindow1->setWindowScale(0.5f, 0.5f);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07008501 mDispatcher->onWindowInfosChanged({{*mWindow1->getInfo(), *mWindow2->getInfo()}, {}, 0, 0});
Chavi Weingarten65f98b82020-01-16 18:56:50 +00008502
8503 // Touch Window 1
8504 std::vector<PointF> touchedPoints = {PointF{10, 10}};
8505 std::vector<PointF> expectedPoints = {getPointInWindow(mWindow1->getInfo(), touchedPoints[0])};
Prabir Pradhanbb3f1c02024-01-04 20:17:14 +00008506 touchAndAssertPositions(mWindow1, AMOTION_EVENT_ACTION_DOWN, touchedPoints, expectedPoints);
Chavi Weingarten65f98b82020-01-16 18:56:50 +00008507
8508 // Touch Window 2
chaviw9eaa22c2020-07-01 16:21:27 -07008509 touchedPoints.push_back(PointF{150, 150});
8510 expectedPoints.push_back(getPointInWindow(mWindow2->getInfo(), touchedPoints[1]));
Chavi Weingarten65f98b82020-01-16 18:56:50 +00008511
Prabir Pradhanbb3f1c02024-01-04 20:17:14 +00008512 touchAndAssertPositions(mWindow1, POINTER_1_DOWN, touchedPoints, expectedPoints);
Chavi Weingarten65f98b82020-01-16 18:56:50 +00008513
8514 // Move both windows
8515 touchedPoints = {{20, 20}, {175, 175}};
8516 expectedPoints = {getPointInWindow(mWindow1->getInfo(), touchedPoints[0]),
8517 getPointInWindow(mWindow2->getInfo(), touchedPoints[1])};
8518
Prabir Pradhanbb3f1c02024-01-04 20:17:14 +00008519 touchAndAssertPositions(mWindow1, AMOTION_EVENT_ACTION_MOVE, touchedPoints, expectedPoints);
Chavi Weingarten65f98b82020-01-16 18:56:50 +00008520}
8521
Siarhei Vishniakou0f6558d2023-04-21 12:05:13 -07008522/**
8523 * When one of the windows is slippery, the touch should not slip into the other window with the
8524 * same input channel.
8525 */
8526TEST_F(InputDispatcherMultiWindowSameTokenTests, TouchDoesNotSlipEvenIfSlippery) {
8527 mWindow1->setSlippery(true);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07008528 mDispatcher->onWindowInfosChanged({{*mWindow1->getInfo(), *mWindow2->getInfo()}, {}, 0, 0});
Siarhei Vishniakou0f6558d2023-04-21 12:05:13 -07008529
8530 // Touch down in window 1
8531 mDispatcher->notifyMotion(generateMotionArgs(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN,
8532 ADISPLAY_ID_DEFAULT, {{50, 50}}));
8533 consumeMotionEvent(mWindow1, ACTION_DOWN, {{50, 50}});
8534
8535 // Move touch to be above window 2. Even though window 1 is slippery, touch should not slip.
8536 // That means the gesture should continue normally, without any ACTION_CANCEL or ACTION_DOWN
8537 // getting generated.
8538 mDispatcher->notifyMotion(generateMotionArgs(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN,
8539 ADISPLAY_ID_DEFAULT, {{150, 150}}));
8540
8541 consumeMotionEvent(mWindow1, ACTION_MOVE, {{150, 150}});
8542}
8543
Siarhei Vishniakoud5876ba2023-05-15 17:58:34 -07008544/**
8545 * When hover starts in one window and continues into the other, there should be a HOVER_EXIT and
8546 * a HOVER_ENTER generated, even if the windows have the same token. This is because the new window
8547 * that the pointer is hovering over may have a different transform.
8548 */
8549TEST_F(InputDispatcherMultiWindowSameTokenTests, HoverIntoClone) {
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07008550 mDispatcher->onWindowInfosChanged({{*mWindow1->getInfo(), *mWindow2->getInfo()}, {}, 0, 0});
Siarhei Vishniakoud5876ba2023-05-15 17:58:34 -07008551
8552 // Start hover in window 1
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -07008553 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_ENTER, AINPUT_SOURCE_TOUCHSCREEN)
8554 .pointer(PointerBuilder(0, ToolType::FINGER).x(50).y(50))
8555 .build());
Siarhei Vishniakoud5876ba2023-05-15 17:58:34 -07008556 consumeMotionEvent(mWindow1, ACTION_HOVER_ENTER,
8557 {getPointInWindow(mWindow1->getInfo(), PointF{50, 50})});
Siarhei Vishniakoud5876ba2023-05-15 17:58:34 -07008558 // Move hover to window 2.
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -07008559 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_MOVE, AINPUT_SOURCE_TOUCHSCREEN)
8560 .pointer(PointerBuilder(0, ToolType::FINGER).x(150).y(150))
8561 .build());
Siarhei Vishniakoud5876ba2023-05-15 17:58:34 -07008562 consumeMotionEvent(mWindow1, ACTION_HOVER_EXIT, {{50, 50}});
Prabir Pradhanbb3f1c02024-01-04 20:17:14 +00008563 consumeMotionEvent(mWindow2, ACTION_HOVER_ENTER,
Siarhei Vishniakoud5876ba2023-05-15 17:58:34 -07008564 {getPointInWindow(mWindow2->getInfo(), PointF{150, 150})});
8565}
8566
Siarhei Vishniakou4cb50ca2020-05-26 21:43:02 -07008567class InputDispatcherSingleWindowAnr : public InputDispatcherTest {
8568 virtual void SetUp() override {
8569 InputDispatcherTest::SetUp();
8570
Chris Yea209fde2020-07-22 13:54:51 -07008571 mApplication = std::make_shared<FakeApplicationHandle>();
Siarhei Vishniakouf83c6932023-07-07 17:48:10 -07008572 mApplication->setDispatchingTimeout(100ms);
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07008573 mWindow = sp<FakeWindowHandle>::make(mApplication, mDispatcher, "TestWindow",
8574 ADISPLAY_ID_DEFAULT);
Siarhei Vishniakou4cb50ca2020-05-26 21:43:02 -07008575 mWindow->setFrame(Rect(0, 0, 30, 30));
Siarhei Vishniakouf83c6932023-07-07 17:48:10 -07008576 mWindow->setDispatchingTimeout(100ms);
Vishnu Nair47074b82020-08-14 11:54:47 -07008577 mWindow->setFocusable(true);
Siarhei Vishniakou4cb50ca2020-05-26 21:43:02 -07008578
8579 // Set focused application.
8580 mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, mApplication);
8581
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07008582 mDispatcher->onWindowInfosChanged({{*mWindow->getInfo()}, {}, 0, 0});
Vishnu Nair958da932020-08-21 17:12:37 -07008583 setFocusedWindow(mWindow);
Siarhei Vishniakou4cb50ca2020-05-26 21:43:02 -07008584 mWindow->consumeFocusEvent(true);
8585 }
8586
8587 virtual void TearDown() override {
8588 InputDispatcherTest::TearDown();
8589 mWindow.clear();
8590 }
8591
8592protected:
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07008593 static constexpr std::chrono::duration SPY_TIMEOUT = 200ms;
Chris Yea209fde2020-07-22 13:54:51 -07008594 std::shared_ptr<FakeApplicationHandle> mApplication;
Siarhei Vishniakou4cb50ca2020-05-26 21:43:02 -07008595 sp<FakeWindowHandle> mWindow;
8596 static constexpr PointF WINDOW_LOCATION = {20, 20};
8597
8598 void tapOnWindow() {
Siarhei Vishniakou67bf2162023-11-16 13:29:50 -08008599 const auto touchingPointer = PointerBuilder(/*id=*/0, ToolType::FINGER)
8600 .x(WINDOW_LOCATION.x)
8601 .y(WINDOW_LOCATION.y);
8602 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
8603 .pointer(touchingPointer)
8604 .build());
8605 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN)
8606 .pointer(touchingPointer)
8607 .build());
Siarhei Vishniakou4cb50ca2020-05-26 21:43:02 -07008608 }
Prabir Pradhan1376fcd2022-01-21 09:56:35 -08008609
8610 sp<FakeWindowHandle> addSpyWindow() {
8611 sp<FakeWindowHandle> spy =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07008612 sp<FakeWindowHandle>::make(mApplication, mDispatcher, "Spy", ADISPLAY_ID_DEFAULT);
Prabir Pradhan1376fcd2022-01-21 09:56:35 -08008613 spy->setTrustedOverlay(true);
8614 spy->setFocusable(false);
Prabir Pradhan51e7db02022-02-07 06:02:57 -08008615 spy->setSpy(true);
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07008616 spy->setDispatchingTimeout(SPY_TIMEOUT);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07008617 mDispatcher->onWindowInfosChanged({{*spy->getInfo(), *mWindow->getInfo()}, {}, 0, 0});
Prabir Pradhan1376fcd2022-01-21 09:56:35 -08008618 return spy;
8619 }
Siarhei Vishniakou4cb50ca2020-05-26 21:43:02 -07008620};
8621
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07008622// Send a tap and respond, which should not cause an ANR.
8623TEST_F(InputDispatcherSingleWindowAnr, WhenTouchIsConsumed_NoAnr) {
8624 tapOnWindow();
8625 mWindow->consumeMotionDown();
8626 mWindow->consumeMotionUp();
8627 ASSERT_TRUE(mDispatcher->waitForIdle());
8628 mFakePolicy->assertNotifyAnrWasNotCalled();
8629}
8630
8631// Send a regular key and respond, which should not cause an ANR.
8632TEST_F(InputDispatcherSingleWindowAnr, WhenKeyIsConsumed_NoAnr) {
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07008633 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectKeyDownNoRepeat(*mDispatcher));
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07008634 mWindow->consumeKeyDown(ADISPLAY_ID_NONE);
8635 ASSERT_TRUE(mDispatcher->waitForIdle());
8636 mFakePolicy->assertNotifyAnrWasNotCalled();
8637}
8638
Siarhei Vishniakoue41c4512020-09-08 19:35:58 -05008639TEST_F(InputDispatcherSingleWindowAnr, WhenFocusedApplicationChanges_NoAnr) {
8640 mWindow->setFocusable(false);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07008641 mDispatcher->onWindowInfosChanged({{*mWindow->getInfo()}, {}, 0, 0});
Siarhei Vishniakoue41c4512020-09-08 19:35:58 -05008642 mWindow->consumeFocusEvent(false);
8643
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08008644 InputEventInjectionResult result =
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07008645 injectKey(*mDispatcher, AKEY_EVENT_ACTION_DOWN, /*repeatCount=*/0, ADISPLAY_ID_DEFAULT,
8646 InputEventInjectionSync::NONE, CONSUME_TIMEOUT_EVENT_EXPECTED,
Harry Cutts33476232023-01-30 19:57:29 +00008647 /*allowKeyRepeat=*/false);
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08008648 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, result);
Siarhei Vishniakoue41c4512020-09-08 19:35:58 -05008649 // Key will not go to window because we have no focused window.
8650 // The 'no focused window' ANR timer should start instead.
8651
8652 // Now, the focused application goes away.
8653 mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, nullptr);
8654 // The key should get dropped and there should be no ANR.
8655
8656 ASSERT_TRUE(mDispatcher->waitForIdle());
8657 mFakePolicy->assertNotifyAnrWasNotCalled();
8658}
8659
Siarhei Vishniakou4cb50ca2020-05-26 21:43:02 -07008660// Send an event to the app and have the app not respond right away.
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07008661// When ANR is raised, policy will tell the dispatcher to cancel the events for that window.
8662// So InputDispatcher will enqueue ACTION_CANCEL event as well.
Siarhei Vishniakou4cb50ca2020-05-26 21:43:02 -07008663TEST_F(InputDispatcherSingleWindowAnr, OnPointerDown_BasicAnr) {
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08008664 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07008665 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
Siarhei Vishniakou4cb50ca2020-05-26 21:43:02 -07008666 WINDOW_LOCATION));
8667
Siarhei Vishniakoud3061ab2023-12-18 20:41:08 -08008668 const auto [sequenceNum, _] = mWindow->receiveEvent(); // ACTION_DOWN
Siarhei Vishniakou4cb50ca2020-05-26 21:43:02 -07008669 ASSERT_TRUE(sequenceNum);
8670 const std::chrono::duration timeout = mWindow->getDispatchingTimeout(DISPATCHING_TIMEOUT);
Prabir Pradhanedd96402022-02-15 01:46:16 -08008671 mFakePolicy->assertNotifyWindowUnresponsiveWasCalled(timeout, mWindow);
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07008672
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07008673 mWindow->finishEvent(*sequenceNum);
Siarhei Vishniakou1ae72f12023-01-29 12:55:30 -08008674 mWindow->consumeMotionEvent(
8675 AllOf(WithMotionAction(ACTION_CANCEL), WithDisplayId(ADISPLAY_ID_DEFAULT)));
Siarhei Vishniakou4cb50ca2020-05-26 21:43:02 -07008676 ASSERT_TRUE(mDispatcher->waitForIdle());
Prabir Pradhanedd96402022-02-15 01:46:16 -08008677 mFakePolicy->assertNotifyWindowResponsiveWasCalled(mWindow->getToken(), mWindow->getPid());
Siarhei Vishniakou4cb50ca2020-05-26 21:43:02 -07008678}
8679
8680// Send a key to the app and have the app not respond right away.
8681TEST_F(InputDispatcherSingleWindowAnr, OnKeyDown_BasicAnr) {
8682 // Inject a key, and don't respond - expect that ANR is called.
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07008683 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectKeyDownNoRepeat(*mDispatcher));
Siarhei Vishniakoud3061ab2023-12-18 20:41:08 -08008684 const auto [sequenceNum, _] = mWindow->receiveEvent();
Siarhei Vishniakou4cb50ca2020-05-26 21:43:02 -07008685 ASSERT_TRUE(sequenceNum);
Siarhei Vishniakou4cb50ca2020-05-26 21:43:02 -07008686 const std::chrono::duration timeout = mWindow->getDispatchingTimeout(DISPATCHING_TIMEOUT);
Prabir Pradhanedd96402022-02-15 01:46:16 -08008687 mFakePolicy->assertNotifyWindowUnresponsiveWasCalled(timeout, mWindow);
Siarhei Vishniakou4cb50ca2020-05-26 21:43:02 -07008688 ASSERT_TRUE(mDispatcher->waitForIdle());
8689}
8690
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07008691// We have a focused application, but no focused window
8692TEST_F(InputDispatcherSingleWindowAnr, FocusedApplication_NoFocusedWindow) {
Vishnu Nair47074b82020-08-14 11:54:47 -07008693 mWindow->setFocusable(false);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07008694 mDispatcher->onWindowInfosChanged({{*mWindow->getInfo()}, {}, 0, 0});
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07008695 mWindow->consumeFocusEvent(false);
8696
8697 // taps on the window work as normal
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08008698 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07008699 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07008700 WINDOW_LOCATION));
8701 ASSERT_NO_FATAL_FAILURE(mWindow->consumeMotionDown());
8702 mDispatcher->waitForIdle();
8703 mFakePolicy->assertNotifyAnrWasNotCalled();
8704
8705 // Once a focused event arrives, we get an ANR for this application
8706 // We specify the injection timeout to be smaller than the application timeout, to ensure that
8707 // injection times out (instead of failing).
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08008708 const InputEventInjectionResult result =
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07008709 injectKey(*mDispatcher, AKEY_EVENT_ACTION_DOWN, /*repeatCount=*/0, ADISPLAY_ID_DEFAULT,
Siarhei Vishniakouf83c6932023-07-07 17:48:10 -07008710 InputEventInjectionSync::WAIT_FOR_RESULT, 50ms, /*allowKeyRepeat=*/false);
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08008711 ASSERT_EQ(InputEventInjectionResult::TIMED_OUT, result);
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07008712 const std::chrono::duration timeout = mApplication->getDispatchingTimeout(DISPATCHING_TIMEOUT);
Vishnu Naire4df8752022-09-08 09:17:55 -07008713 mFakePolicy->assertNotifyNoFocusedWindowAnrWasCalled(timeout, mApplication);
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07008714 ASSERT_TRUE(mDispatcher->waitForIdle());
8715}
8716
Siarhei Vishniakou289e9242022-02-15 14:50:16 -08008717/**
8718 * Make sure the stale key is dropped before causing an ANR. So even if there's no focused window,
8719 * there will not be an ANR.
8720 */
8721TEST_F(InputDispatcherSingleWindowAnr, StaleKeyEventDoesNotAnr) {
8722 mWindow->setFocusable(false);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07008723 mDispatcher->onWindowInfosChanged({{*mWindow->getInfo()}, {}, 0, 0});
Siarhei Vishniakou289e9242022-02-15 14:50:16 -08008724 mWindow->consumeFocusEvent(false);
8725
8726 KeyEvent event;
Siarhei Vishniakoua7333112023-10-27 13:33:29 -07008727 static constexpr std::chrono::duration STALE_EVENT_TIMEOUT = 1000ms;
8728 mFakePolicy->setStaleEventTimeout(STALE_EVENT_TIMEOUT);
Siarhei Vishniakou289e9242022-02-15 14:50:16 -08008729 const nsecs_t eventTime = systemTime(SYSTEM_TIME_MONOTONIC) -
8730 std::chrono::nanoseconds(STALE_EVENT_TIMEOUT).count();
8731
8732 // Define a valid key down event that is stale (too old).
8733 event.initialize(InputEvent::nextId(), DEVICE_ID, AINPUT_SOURCE_KEYBOARD, ADISPLAY_ID_NONE,
Harry Cutts101ee9b2023-07-06 18:04:14 +00008734 INVALID_HMAC, AKEY_EVENT_ACTION_DOWN, /*flags=*/0, AKEYCODE_A, KEY_A,
Hu Guofe3c8f12023-09-22 17:20:15 +08008735 AMETA_NONE, /*repeatCount=*/0, eventTime, eventTime);
Siarhei Vishniakou289e9242022-02-15 14:50:16 -08008736
Hu Guofe3c8f12023-09-22 17:20:15 +08008737 const int32_t policyFlags =
8738 POLICY_FLAG_FILTERED | POLICY_FLAG_PASS_TO_USER | POLICY_FLAG_DISABLE_KEY_REPEAT;
Siarhei Vishniakou289e9242022-02-15 14:50:16 -08008739
8740 InputEventInjectionResult result =
Harry Cutts33476232023-01-30 19:57:29 +00008741 mDispatcher->injectInputEvent(&event, /*targetUid=*/{},
Siarhei Vishniakou289e9242022-02-15 14:50:16 -08008742 InputEventInjectionSync::WAIT_FOR_RESULT,
8743 INJECT_EVENT_TIMEOUT, policyFlags);
8744 ASSERT_EQ(InputEventInjectionResult::FAILED, result)
8745 << "Injection should fail because the event is stale";
8746
8747 ASSERT_TRUE(mDispatcher->waitForIdle());
8748 mFakePolicy->assertNotifyAnrWasNotCalled();
8749 mWindow->assertNoEvents();
8750}
8751
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07008752// We have a focused application, but no focused window
Siarhei Vishniakou234129c2020-10-22 22:28:12 -05008753// Make sure that we don't notify policy twice about the same ANR.
8754TEST_F(InputDispatcherSingleWindowAnr, NoFocusedWindow_DoesNotSendDuplicateAnr) {
Siarhei Vishniakou06405fc2023-09-22 13:40:51 -07008755 const std::chrono::duration appTimeout = 400ms;
8756 mApplication->setDispatchingTimeout(appTimeout);
8757 mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, mApplication);
8758
Vishnu Nair47074b82020-08-14 11:54:47 -07008759 mWindow->setFocusable(false);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07008760 mDispatcher->onWindowInfosChanged({{*mWindow->getInfo()}, {}, 0, 0});
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07008761 mWindow->consumeFocusEvent(false);
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07008762
8763 // Once a focused event arrives, we get an ANR for this application
8764 // We specify the injection timeout to be smaller than the application timeout, to ensure that
8765 // injection times out (instead of failing).
Siarhei Vishniakou06405fc2023-09-22 13:40:51 -07008766 const std::chrono::duration eventInjectionTimeout = 100ms;
8767 ASSERT_LT(eventInjectionTimeout, appTimeout);
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08008768 const InputEventInjectionResult result =
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07008769 injectKey(*mDispatcher, AKEY_EVENT_ACTION_DOWN, /*repeatCount=*/0, ADISPLAY_ID_DEFAULT,
Siarhei Vishniakou06405fc2023-09-22 13:40:51 -07008770 InputEventInjectionSync::WAIT_FOR_RESULT, eventInjectionTimeout,
8771 /*allowKeyRepeat=*/false);
8772 ASSERT_EQ(InputEventInjectionResult::TIMED_OUT, result)
8773 << "result=" << ftl::enum_string(result);
8774 // We already waited for 'eventInjectionTimeout`, because the countdown started when the event
8775 // was first injected. So now we have (appTimeout - eventInjectionTimeout) left to wait.
8776 std::chrono::duration remainingWaitTime = appTimeout - eventInjectionTimeout;
8777 mFakePolicy->assertNotifyNoFocusedWindowAnrWasCalled(remainingWaitTime, mApplication);
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07008778
Vishnu Naire4df8752022-09-08 09:17:55 -07008779 std::this_thread::sleep_for(appTimeout);
Siarhei Vishniakou234129c2020-10-22 22:28:12 -05008780 // ANR should not be raised again. It is up to policy to do that if it desires.
8781 mFakePolicy->assertNotifyAnrWasNotCalled();
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07008782
Siarhei Vishniakou234129c2020-10-22 22:28:12 -05008783 // If we now get a focused window, the ANR should stop, but the policy handles that via
8784 // 'notifyFocusChanged' callback. This is implemented in the policy so we can't test it here.
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07008785 ASSERT_TRUE(mDispatcher->waitForIdle());
8786}
8787
8788// We have a focused application, but no focused window
8789TEST_F(InputDispatcherSingleWindowAnr, NoFocusedWindow_DropsFocusedEvents) {
Vishnu Nair47074b82020-08-14 11:54:47 -07008790 mWindow->setFocusable(false);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07008791 mDispatcher->onWindowInfosChanged({{*mWindow->getInfo()}, {}, 0, 0});
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07008792 mWindow->consumeFocusEvent(false);
8793
8794 // Once a focused event arrives, we get an ANR for this application
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07008795 ASSERT_NO_FATAL_FAILURE(assertInjectedKeyTimesOut(*mDispatcher));
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07008796
Vishnu Naire4df8752022-09-08 09:17:55 -07008797 const std::chrono::duration timeout = mApplication->getDispatchingTimeout(DISPATCHING_TIMEOUT);
8798 mFakePolicy->assertNotifyNoFocusedWindowAnrWasCalled(timeout, mApplication);
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07008799
8800 // Future focused events get dropped right away
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07008801 ASSERT_EQ(InputEventInjectionResult::FAILED, injectKeyDown(*mDispatcher));
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07008802 ASSERT_TRUE(mDispatcher->waitForIdle());
8803 mWindow->assertNoEvents();
8804}
8805
8806/**
8807 * Ensure that the implementation is valid. Since we are using multiset to keep track of the
8808 * ANR timeouts, we are allowing entries with identical timestamps in the same connection.
8809 * If we process 1 of the events, but ANR on the second event with the same timestamp,
8810 * the ANR mechanism should still work.
8811 *
8812 * In this test, we are injecting DOWN and UP events with the same timestamps, and acknowledging the
8813 * DOWN event, while not responding on the second one.
8814 */
8815TEST_F(InputDispatcherSingleWindowAnr, Anr_HandlesEventsWithIdenticalTimestamps) {
8816 nsecs_t currentTime = systemTime(SYSTEM_TIME_MONOTONIC);
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07008817 injectMotionEvent(*mDispatcher, AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN,
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07008818 ADISPLAY_ID_DEFAULT, WINDOW_LOCATION,
8819 {AMOTION_EVENT_INVALID_CURSOR_POSITION,
8820 AMOTION_EVENT_INVALID_CURSOR_POSITION},
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08008821 500ms, InputEventInjectionSync::WAIT_FOR_RESULT, currentTime);
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07008822
8823 // Now send ACTION_UP, with identical timestamp
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07008824 injectMotionEvent(*mDispatcher, AMOTION_EVENT_ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN,
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07008825 ADISPLAY_ID_DEFAULT, WINDOW_LOCATION,
8826 {AMOTION_EVENT_INVALID_CURSOR_POSITION,
8827 AMOTION_EVENT_INVALID_CURSOR_POSITION},
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08008828 500ms, InputEventInjectionSync::WAIT_FOR_RESULT, currentTime);
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07008829
8830 // We have now sent down and up. Let's consume first event and then ANR on the second.
8831 mWindow->consumeMotionDown(ADISPLAY_ID_DEFAULT);
8832 const std::chrono::duration timeout = mWindow->getDispatchingTimeout(DISPATCHING_TIMEOUT);
Prabir Pradhanedd96402022-02-15 01:46:16 -08008833 mFakePolicy->assertNotifyWindowUnresponsiveWasCalled(timeout, mWindow);
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07008834}
8835
Prabir Pradhan1376fcd2022-01-21 09:56:35 -08008836// A spy window can receive an ANR
8837TEST_F(InputDispatcherSingleWindowAnr, SpyWindowAnr) {
8838 sp<FakeWindowHandle> spy = addSpyWindow();
8839
8840 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07008841 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
Prabir Pradhan1376fcd2022-01-21 09:56:35 -08008842 WINDOW_LOCATION));
8843 mWindow->consumeMotionDown();
8844
Siarhei Vishniakoud3061ab2023-12-18 20:41:08 -08008845 const auto [sequenceNum, _] = spy->receiveEvent(); // ACTION_DOWN
Prabir Pradhan1376fcd2022-01-21 09:56:35 -08008846 ASSERT_TRUE(sequenceNum);
8847 const std::chrono::duration timeout = spy->getDispatchingTimeout(DISPATCHING_TIMEOUT);
Prabir Pradhanedd96402022-02-15 01:46:16 -08008848 mFakePolicy->assertNotifyWindowUnresponsiveWasCalled(timeout, spy);
Prabir Pradhan1376fcd2022-01-21 09:56:35 -08008849
8850 spy->finishEvent(*sequenceNum);
Siarhei Vishniakou1ae72f12023-01-29 12:55:30 -08008851 spy->consumeMotionEvent(
8852 AllOf(WithMotionAction(ACTION_CANCEL), WithDisplayId(ADISPLAY_ID_DEFAULT)));
Prabir Pradhan1376fcd2022-01-21 09:56:35 -08008853 ASSERT_TRUE(mDispatcher->waitForIdle());
Prabir Pradhanedd96402022-02-15 01:46:16 -08008854 mFakePolicy->assertNotifyWindowResponsiveWasCalled(spy->getToken(), mWindow->getPid());
Prabir Pradhan1376fcd2022-01-21 09:56:35 -08008855}
8856
8857// If an app is not responding to a key event, spy windows should continue to receive
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07008858// new motion events
Prabir Pradhan1376fcd2022-01-21 09:56:35 -08008859TEST_F(InputDispatcherSingleWindowAnr, SpyWindowReceivesEventsDuringAppAnrOnKey) {
8860 sp<FakeWindowHandle> spy = addSpyWindow();
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07008861
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08008862 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07008863 injectKeyDown(*mDispatcher, ADISPLAY_ID_DEFAULT));
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07008864 mWindow->consumeKeyDown(ADISPLAY_ID_DEFAULT);
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07008865 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectKeyUp(*mDispatcher, ADISPLAY_ID_DEFAULT));
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07008866
8867 // Stuck on the ACTION_UP
8868 const std::chrono::duration timeout = mWindow->getDispatchingTimeout(DISPATCHING_TIMEOUT);
Prabir Pradhanedd96402022-02-15 01:46:16 -08008869 mFakePolicy->assertNotifyWindowUnresponsiveWasCalled(timeout, mWindow);
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07008870
Prabir Pradhan1376fcd2022-01-21 09:56:35 -08008871 // New tap will go to the spy window, but not to the window
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07008872 tapOnWindow();
Prabir Pradhan1376fcd2022-01-21 09:56:35 -08008873 spy->consumeMotionDown(ADISPLAY_ID_DEFAULT);
8874 spy->consumeMotionUp(ADISPLAY_ID_DEFAULT);
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07008875
8876 mWindow->consumeKeyUp(ADISPLAY_ID_DEFAULT); // still the previous motion
8877 mDispatcher->waitForIdle();
Prabir Pradhanedd96402022-02-15 01:46:16 -08008878 mFakePolicy->assertNotifyWindowResponsiveWasCalled(mWindow->getToken(), mWindow->getPid());
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07008879 mWindow->assertNoEvents();
Prabir Pradhan1376fcd2022-01-21 09:56:35 -08008880 spy->assertNoEvents();
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07008881}
8882
Prabir Pradhan1376fcd2022-01-21 09:56:35 -08008883// If an app is not responding to a motion event, spy windows should continue to receive
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07008884// new motion events
Prabir Pradhan1376fcd2022-01-21 09:56:35 -08008885TEST_F(InputDispatcherSingleWindowAnr, SpyWindowReceivesEventsDuringAppAnrOnMotion) {
8886 sp<FakeWindowHandle> spy = addSpyWindow();
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07008887
8888 tapOnWindow();
Prabir Pradhan1376fcd2022-01-21 09:56:35 -08008889 spy->consumeMotionDown(ADISPLAY_ID_DEFAULT);
8890 spy->consumeMotionUp(ADISPLAY_ID_DEFAULT);
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07008891
8892 mWindow->consumeMotionDown();
8893 // Stuck on the ACTION_UP
8894 const std::chrono::duration timeout = mWindow->getDispatchingTimeout(DISPATCHING_TIMEOUT);
Prabir Pradhanedd96402022-02-15 01:46:16 -08008895 mFakePolicy->assertNotifyWindowUnresponsiveWasCalled(timeout, mWindow);
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07008896
Prabir Pradhan1376fcd2022-01-21 09:56:35 -08008897 // New tap will go to the spy window, but not to the window
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07008898 tapOnWindow();
Prabir Pradhan1376fcd2022-01-21 09:56:35 -08008899 spy->consumeMotionDown(ADISPLAY_ID_DEFAULT);
8900 spy->consumeMotionUp(ADISPLAY_ID_DEFAULT);
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07008901
8902 mWindow->consumeMotionUp(ADISPLAY_ID_DEFAULT); // still the previous motion
8903 mDispatcher->waitForIdle();
Prabir Pradhanedd96402022-02-15 01:46:16 -08008904 mFakePolicy->assertNotifyWindowResponsiveWasCalled(mWindow->getToken(), mWindow->getPid());
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07008905 mWindow->assertNoEvents();
Prabir Pradhan1376fcd2022-01-21 09:56:35 -08008906 spy->assertNoEvents();
8907}
8908
8909TEST_F(InputDispatcherSingleWindowAnr, UnresponsiveMonitorAnr) {
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07008910 mDispatcher->setMonitorDispatchingTimeoutForTest(SPY_TIMEOUT);
Prabir Pradhan1376fcd2022-01-21 09:56:35 -08008911
Prabir Pradhanfb549072023-10-05 19:17:36 +00008912 FakeMonitorReceiver monitor = FakeMonitorReceiver(*mDispatcher, "M_1", ADISPLAY_ID_DEFAULT);
Prabir Pradhan1376fcd2022-01-21 09:56:35 -08008913
8914 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07008915 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
Prabir Pradhan1376fcd2022-01-21 09:56:35 -08008916 WINDOW_LOCATION));
8917
8918 mWindow->consumeMotionDown(ADISPLAY_ID_DEFAULT);
8919 const std::optional<uint32_t> consumeSeq = monitor.receiveEvent();
8920 ASSERT_TRUE(consumeSeq);
8921
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07008922 mFakePolicy->assertNotifyWindowUnresponsiveWasCalled(SPY_TIMEOUT, monitor.getToken(),
8923 MONITOR_PID);
Prabir Pradhan1376fcd2022-01-21 09:56:35 -08008924
8925 monitor.finishEvent(*consumeSeq);
8926 monitor.consumeMotionCancel(ADISPLAY_ID_DEFAULT);
8927
8928 ASSERT_TRUE(mDispatcher->waitForIdle());
Prabir Pradhanedd96402022-02-15 01:46:16 -08008929 mFakePolicy->assertNotifyWindowResponsiveWasCalled(monitor.getToken(), MONITOR_PID);
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07008930}
8931
8932// If a window is unresponsive, then you get anr. if the window later catches up and starts to
8933// process events, you don't get an anr. When the window later becomes unresponsive again, you
8934// get an ANR again.
8935// 1. tap -> block on ACTION_UP -> receive ANR
8936// 2. consume all pending events (= queue becomes healthy again)
8937// 3. tap again -> block on ACTION_UP again -> receive ANR second time
8938TEST_F(InputDispatcherSingleWindowAnr, SameWindow_CanReceiveAnrTwice) {
8939 tapOnWindow();
8940
8941 mWindow->consumeMotionDown();
8942 // Block on ACTION_UP
8943 const std::chrono::duration timeout = mWindow->getDispatchingTimeout(DISPATCHING_TIMEOUT);
Prabir Pradhanedd96402022-02-15 01:46:16 -08008944 mFakePolicy->assertNotifyWindowUnresponsiveWasCalled(timeout, mWindow);
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07008945 mWindow->consumeMotionUp(); // Now the connection should be healthy again
8946 mDispatcher->waitForIdle();
Prabir Pradhanedd96402022-02-15 01:46:16 -08008947 mFakePolicy->assertNotifyWindowResponsiveWasCalled(mWindow->getToken(), mWindow->getPid());
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07008948 mWindow->assertNoEvents();
8949
8950 tapOnWindow();
8951 mWindow->consumeMotionDown();
Prabir Pradhanedd96402022-02-15 01:46:16 -08008952 mFakePolicy->assertNotifyWindowUnresponsiveWasCalled(timeout, mWindow);
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07008953 mWindow->consumeMotionUp();
8954
8955 mDispatcher->waitForIdle();
Prabir Pradhanedd96402022-02-15 01:46:16 -08008956 mFakePolicy->assertNotifyWindowResponsiveWasCalled(mWindow->getToken(), mWindow->getPid());
Siarhei Vishniakou234129c2020-10-22 22:28:12 -05008957 mFakePolicy->assertNotifyAnrWasNotCalled();
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07008958 mWindow->assertNoEvents();
8959}
8960
Siarhei Vishniakou234129c2020-10-22 22:28:12 -05008961// If a connection remains unresponsive for a while, make sure policy is only notified once about
8962// it.
8963TEST_F(InputDispatcherSingleWindowAnr, Policy_DoesNotGetDuplicateAnr) {
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08008964 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07008965 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07008966 WINDOW_LOCATION));
8967
8968 const std::chrono::duration windowTimeout = mWindow->getDispatchingTimeout(DISPATCHING_TIMEOUT);
Prabir Pradhanedd96402022-02-15 01:46:16 -08008969 mFakePolicy->assertNotifyWindowUnresponsiveWasCalled(windowTimeout, mWindow);
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07008970 std::this_thread::sleep_for(windowTimeout);
Siarhei Vishniakou234129c2020-10-22 22:28:12 -05008971 // 'notifyConnectionUnresponsive' should only be called once per connection
8972 mFakePolicy->assertNotifyAnrWasNotCalled();
8973 // When the ANR happened, dispatcher should abort the current event stream via ACTION_CANCEL
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07008974 mWindow->consumeMotionDown();
Siarhei Vishniakou1ae72f12023-01-29 12:55:30 -08008975 mWindow->consumeMotionEvent(
8976 AllOf(WithMotionAction(ACTION_CANCEL), WithDisplayId(ADISPLAY_ID_DEFAULT)));
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07008977 mWindow->assertNoEvents();
Siarhei Vishniakou234129c2020-10-22 22:28:12 -05008978 mDispatcher->waitForIdle();
Prabir Pradhanedd96402022-02-15 01:46:16 -08008979 mFakePolicy->assertNotifyWindowResponsiveWasCalled(mWindow->getToken(), mWindow->getPid());
Siarhei Vishniakou234129c2020-10-22 22:28:12 -05008980 mFakePolicy->assertNotifyAnrWasNotCalled();
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07008981}
8982
8983/**
8984 * 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 -07008985 * not get delivered to the focused window until the motion is processed.
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07008986 */
8987TEST_F(InputDispatcherSingleWindowAnr, Key_StaysPendingWhileMotionIsProcessed) {
Siarhei Vishniakouef2b4502023-12-28 11:51:47 -08008988 // The timeouts in this test are established by relying on the fact that the "key waiting for
8989 // events timeout" is equal to 500ms.
8990 ASSERT_EQ(mFakePolicy->getKeyWaitingForEventsTimeout(), 500ms);
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07008991 mWindow->setDispatchingTimeout(2s); // Set a long ANR timeout to prevent it from triggering
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07008992 mDispatcher->onWindowInfosChanged({{*mWindow->getInfo()}, {}, 0, 0});
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07008993
8994 tapOnWindow();
Siarhei Vishniakoud3061ab2023-12-18 20:41:08 -08008995 const auto& [downSequenceNum, downEvent] = mWindow->receiveEvent();
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07008996 ASSERT_TRUE(downSequenceNum);
Siarhei Vishniakoud3061ab2023-12-18 20:41:08 -08008997 const auto& [upSequenceNum, upEvent] = mWindow->receiveEvent();
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07008998 ASSERT_TRUE(upSequenceNum);
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07008999
Siarhei Vishniakouef2b4502023-12-28 11:51:47 -08009000 // Don't finish the events yet, and send a key
9001 mDispatcher->notifyKey(
9002 KeyArgsBuilder(AKEY_EVENT_ACTION_DOWN, AINPUT_SOURCE_KEYBOARD)
9003 .policyFlags(DEFAULT_POLICY_FLAGS | POLICY_FLAG_DISABLE_KEY_REPEAT)
9004 .build());
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009005 // Key will not be sent to the window, yet, because the window is still processing events
9006 // and the key remains pending, waiting for the touch events to be processed
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07009007 // Make sure that `assertNoEvents` doesn't wait too long, because it could cause an ANR.
Siarhei Vishniakouef2b4502023-12-28 11:51:47 -08009008 mWindow->assertNoEvents(100ms);
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009009
Siarhei Vishniakouef2b4502023-12-28 11:51:47 -08009010 std::this_thread::sleep_for(400ms);
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009011 // if we wait long enough though, dispatcher will give up, and still send the key
9012 // to the focused window, even though we have not yet finished the motion event
9013 mWindow->consumeKeyDown(ADISPLAY_ID_DEFAULT);
9014 mWindow->finishEvent(*downSequenceNum);
9015 mWindow->finishEvent(*upSequenceNum);
9016}
9017
9018/**
9019 * If a window is processing a motion event, and then a key event comes in, the key event should
9020 * not go to the focused window until the motion is processed.
9021 * If then a new motion comes in, then the pending key event should be going to the currently
9022 * focused window right away.
9023 */
9024TEST_F(InputDispatcherSingleWindowAnr,
Siarhei Vishniakouef2b4502023-12-28 11:51:47 -08009025 PendingKey_IsDeliveredWhileMotionIsProcessingAndNewTouchComesIn) {
9026 // The timeouts in this test are established by relying on the fact that the "key waiting for
9027 // events timeout" is equal to 500ms.
9028 ASSERT_EQ(mFakePolicy->getKeyWaitingForEventsTimeout(), 500ms);
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009029 mWindow->setDispatchingTimeout(2s); // Set a long ANR timeout to prevent it from triggering
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07009030 mDispatcher->onWindowInfosChanged({{*mWindow->getInfo()}, {}, 0, 0});
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009031
9032 tapOnWindow();
Siarhei Vishniakoud3061ab2023-12-18 20:41:08 -08009033 const auto& [downSequenceNum, _] = mWindow->receiveEvent();
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009034 ASSERT_TRUE(downSequenceNum);
Siarhei Vishniakoud3061ab2023-12-18 20:41:08 -08009035 const auto& [upSequenceNum, upEvent] = mWindow->receiveEvent();
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009036 ASSERT_TRUE(upSequenceNum);
9037 // Don't finish the events yet, and send a key
Siarhei Vishniakou67bf2162023-11-16 13:29:50 -08009038 mDispatcher->notifyKey(
9039 KeyArgsBuilder(AKEY_EVENT_ACTION_DOWN, AINPUT_SOURCE_KEYBOARD)
9040 .policyFlags(DEFAULT_POLICY_FLAGS | POLICY_FLAG_DISABLE_KEY_REPEAT)
9041 .build());
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009042 // At this point, key is still pending, and should not be sent to the application yet.
Siarhei Vishniakouef2b4502023-12-28 11:51:47 -08009043 mWindow->assertNoEvents(100ms);
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009044
9045 // Now tap down again. It should cause the pending key to go to the focused window right away.
9046 tapOnWindow();
Siarhei Vishniakouef2b4502023-12-28 11:51:47 -08009047 // Now that we tapped, we should receive the key immediately.
9048 // Since there's still room for slowness, we use 200ms, which is much less than
9049 // the "key waiting for events' timeout of 500ms minus the already waited 100ms duration.
9050 std::unique_ptr<InputEvent> keyEvent = mWindow->consume(200ms);
9051 ASSERT_NE(nullptr, keyEvent);
9052 ASSERT_EQ(InputEventType::KEY, keyEvent->getType());
9053 ASSERT_THAT(static_cast<KeyEvent&>(*keyEvent), WithKeyAction(AKEY_EVENT_ACTION_DOWN));
9054 // it doesn't matter that we haven't ack'd the other events yet. We can finish events in any
9055 // order.
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009056 mWindow->finishEvent(*downSequenceNum); // first tap's ACTION_DOWN
9057 mWindow->finishEvent(*upSequenceNum); // first tap's ACTION_UP
Siarhei Vishniakou67bf2162023-11-16 13:29:50 -08009058 mWindow->consumeMotionEvent(WithMotionAction(ACTION_DOWN));
9059 mWindow->consumeMotionEvent(WithMotionAction(ACTION_UP));
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009060 mWindow->assertNoEvents();
9061}
9062
Siarhei Vishniakouadb9fc92023-05-26 10:46:09 -07009063/**
9064 * Send an event to the app and have the app not respond right away.
9065 * When ANR is raised, policy will tell the dispatcher to cancel the events for that window.
9066 * So InputDispatcher will enqueue ACTION_CANCEL event as well.
9067 * At some point, the window becomes responsive again.
9068 * Ensure that subsequent events get dropped, and the next gesture is delivered.
9069 */
9070TEST_F(InputDispatcherSingleWindowAnr, TwoGesturesWithAnr) {
9071 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
9072 .pointer(PointerBuilder(0, ToolType::FINGER).x(10).y(10))
9073 .build());
9074
Siarhei Vishniakoud3061ab2023-12-18 20:41:08 -08009075 const auto [sequenceNum, _] = mWindow->receiveEvent(); // ACTION_DOWN
Siarhei Vishniakouadb9fc92023-05-26 10:46:09 -07009076 ASSERT_TRUE(sequenceNum);
9077 const std::chrono::duration timeout = mWindow->getDispatchingTimeout(DISPATCHING_TIMEOUT);
9078 mFakePolicy->assertNotifyWindowUnresponsiveWasCalled(timeout, mWindow);
9079
9080 mWindow->finishEvent(*sequenceNum);
9081 mWindow->consumeMotionEvent(WithMotionAction(ACTION_CANCEL));
9082 ASSERT_TRUE(mDispatcher->waitForIdle());
9083 mFakePolicy->assertNotifyWindowResponsiveWasCalled(mWindow->getToken(), mWindow->getPid());
9084
9085 // Now that the window is responsive, let's continue the gesture.
9086 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN)
9087 .pointer(PointerBuilder(0, ToolType::FINGER).x(11).y(11))
9088 .build());
9089
9090 mDispatcher->notifyMotion(MotionArgsBuilder(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
9091 .pointer(PointerBuilder(0, ToolType::FINGER).x(11).y(11))
9092 .pointer(PointerBuilder(1, ToolType::FINGER).x(3).y(3))
9093 .build());
9094
9095 mDispatcher->notifyMotion(MotionArgsBuilder(POINTER_1_UP, AINPUT_SOURCE_TOUCHSCREEN)
9096 .pointer(PointerBuilder(0, ToolType::FINGER).x(11).y(11))
9097 .pointer(PointerBuilder(1, ToolType::FINGER).x(3).y(3))
9098 .build());
9099 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN)
9100 .pointer(PointerBuilder(0, ToolType::FINGER).x(11).y(11))
9101 .build());
9102 // We already canceled this pointer, so the window shouldn't get any new events.
9103 mWindow->assertNoEvents();
9104
9105 // Start another one.
9106 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
9107 .pointer(PointerBuilder(0, ToolType::FINGER).x(15).y(15))
9108 .build());
9109 mWindow->consumeMotionEvent(WithMotionAction(ACTION_DOWN));
9110}
9111
Prabir Pradhanfc364722024-02-08 17:51:20 +00009112// Send an event to the app and have the app not respond right away. Then remove the app window.
9113// When the window is removed, the dispatcher will cancel the events for that window.
9114// So InputDispatcher will enqueue ACTION_CANCEL event as well.
9115TEST_F(InputDispatcherSingleWindowAnr, AnrAfterWindowRemoval) {
9116 mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_DOWN,
9117 AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
9118 {WINDOW_LOCATION}));
9119
9120 const auto [sequenceNum, _] = mWindow->receiveEvent(); // ACTION_DOWN
9121 ASSERT_TRUE(sequenceNum);
9122
9123 // Remove the window, but the input channel should remain alive.
9124 mDispatcher->onWindowInfosChanged({{}, {}, 0, 0});
9125
9126 const std::chrono::duration timeout = mWindow->getDispatchingTimeout(DISPATCHING_TIMEOUT);
9127 // Since the window was removed, Dispatcher does not know the PID associated with the window
9128 // anymore, so the policy is notified without the PID.
9129 mFakePolicy->assertNotifyWindowUnresponsiveWasCalled(timeout, mWindow->getToken(),
9130 /*pid=*/std::nullopt);
9131
9132 mWindow->finishEvent(*sequenceNum);
9133 // The cancellation was generated when the window was removed, along with the focus event.
9134 mWindow->consumeMotionEvent(
9135 AllOf(WithMotionAction(ACTION_CANCEL), WithDisplayId(ADISPLAY_ID_DEFAULT)));
9136 mWindow->consumeFocusEvent(false);
9137 ASSERT_TRUE(mDispatcher->waitForIdle());
9138 mFakePolicy->assertNotifyWindowResponsiveWasCalled(mWindow->getToken(), /*pid=*/std::nullopt);
9139}
9140
9141// Send an event to the app and have the app not respond right away. Wait for the policy to be
9142// notified of the unresponsive window, then remove the app window.
9143TEST_F(InputDispatcherSingleWindowAnr, AnrFollowedByWindowRemoval) {
9144 mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_DOWN,
9145 AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
9146 {WINDOW_LOCATION}));
9147
9148 const auto [sequenceNum, _] = mWindow->receiveEvent(); // ACTION_DOWN
9149 ASSERT_TRUE(sequenceNum);
9150 const std::chrono::duration timeout = mWindow->getDispatchingTimeout(DISPATCHING_TIMEOUT);
9151 mFakePolicy->assertNotifyWindowUnresponsiveWasCalled(timeout, mWindow);
9152
9153 // Remove the window, but the input channel should remain alive.
9154 mDispatcher->onWindowInfosChanged({{}, {}, 0, 0});
9155
9156 mWindow->finishEvent(*sequenceNum);
9157 // The cancellation was generated during the ANR, and the window lost focus when it was removed.
9158 mWindow->consumeMotionEvent(
9159 AllOf(WithMotionAction(ACTION_CANCEL), WithDisplayId(ADISPLAY_ID_DEFAULT)));
9160 mWindow->consumeFocusEvent(false);
9161 ASSERT_TRUE(mDispatcher->waitForIdle());
9162 // Since the window was removed, Dispatcher does not know the PID associated with the window
9163 // becoming responsive, so the policy is notified without the PID.
9164 mFakePolicy->assertNotifyWindowResponsiveWasCalled(mWindow->getToken(), /*pid=*/std::nullopt);
9165}
9166
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009167class InputDispatcherMultiWindowAnr : public InputDispatcherTest {
9168 virtual void SetUp() override {
9169 InputDispatcherTest::SetUp();
9170
Chris Yea209fde2020-07-22 13:54:51 -07009171 mApplication = std::make_shared<FakeApplicationHandle>();
Siarhei Vishniakouf83c6932023-07-07 17:48:10 -07009172 mApplication->setDispatchingTimeout(100ms);
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07009173 mUnfocusedWindow = sp<FakeWindowHandle>::make(mApplication, mDispatcher, "Unfocused",
9174 ADISPLAY_ID_DEFAULT);
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009175 mUnfocusedWindow->setFrame(Rect(0, 0, 30, 30));
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009176 // Adding FLAG_WATCH_OUTSIDE_TOUCH to receive ACTION_OUTSIDE when another window is tapped
Prabir Pradhan4d5c52f2022-01-31 08:52:10 -08009177 mUnfocusedWindow->setWatchOutsideTouch(true);
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009178
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07009179 mFocusedWindow = sp<FakeWindowHandle>::make(mApplication, mDispatcher, "Focused",
9180 ADISPLAY_ID_DEFAULT);
Siarhei Vishniakouf83c6932023-07-07 17:48:10 -07009181 mFocusedWindow->setDispatchingTimeout(100ms);
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009182 mFocusedWindow->setFrame(Rect(50, 50, 100, 100));
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009183
9184 // Set focused application.
9185 mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, mApplication);
Vishnu Nair47074b82020-08-14 11:54:47 -07009186 mFocusedWindow->setFocusable(true);
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009187
9188 // Expect one focus window exist in display.
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07009189 mDispatcher->onWindowInfosChanged(
9190 {{*mUnfocusedWindow->getInfo(), *mFocusedWindow->getInfo()}, {}, 0, 0});
Vishnu Nair958da932020-08-21 17:12:37 -07009191 setFocusedWindow(mFocusedWindow);
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009192 mFocusedWindow->consumeFocusEvent(true);
9193 }
9194
9195 virtual void TearDown() override {
9196 InputDispatcherTest::TearDown();
9197
9198 mUnfocusedWindow.clear();
9199 mFocusedWindow.clear();
9200 }
9201
9202protected:
Chris Yea209fde2020-07-22 13:54:51 -07009203 std::shared_ptr<FakeApplicationHandle> mApplication;
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009204 sp<FakeWindowHandle> mUnfocusedWindow;
9205 sp<FakeWindowHandle> mFocusedWindow;
9206 static constexpr PointF UNFOCUSED_WINDOW_LOCATION = {20, 20};
9207 static constexpr PointF FOCUSED_WINDOW_LOCATION = {75, 75};
9208 static constexpr PointF LOCATION_OUTSIDE_ALL_WINDOWS = {40, 40};
9209
9210 void tapOnFocusedWindow() { tap(FOCUSED_WINDOW_LOCATION); }
9211
9212 void tapOnUnfocusedWindow() { tap(UNFOCUSED_WINDOW_LOCATION); }
9213
9214private:
9215 void tap(const PointF& location) {
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08009216 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07009217 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009218 location));
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08009219 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07009220 injectMotionUp(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009221 location));
9222 }
9223};
9224
9225// If we have 2 windows that are both unresponsive, the one with the shortest timeout
9226// should be ANR'd first.
9227TEST_F(InputDispatcherMultiWindowAnr, TwoWindows_BothUnresponsive) {
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08009228 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakou2899c552023-07-10 18:20:46 -07009229 injectMotionEvent(*mDispatcher,
9230 MotionEventBuilder(AMOTION_EVENT_ACTION_DOWN,
9231 AINPUT_SOURCE_TOUCHSCREEN)
9232 .pointer(PointerBuilder(0, ToolType::FINGER)
9233 .x(FOCUSED_WINDOW_LOCATION.x)
9234 .y(FOCUSED_WINDOW_LOCATION.y))
9235 .build()));
9236 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
9237 injectMotionEvent(*mDispatcher,
9238 MotionEventBuilder(AMOTION_EVENT_ACTION_UP,
9239 AINPUT_SOURCE_TOUCHSCREEN)
9240 .pointer(PointerBuilder(0, ToolType::FINGER)
9241 .x(FOCUSED_WINDOW_LOCATION.x)
9242 .y(FOCUSED_WINDOW_LOCATION.y))
9243 .build()));
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009244 mFocusedWindow->consumeMotionDown();
Siarhei Vishniakou2899c552023-07-10 18:20:46 -07009245 mFocusedWindow->consumeMotionUp();
Prabir Pradhan7662a8d2023-12-15 01:58:14 +00009246 mUnfocusedWindow->consumeMotionOutside(ADISPLAY_ID_DEFAULT, /*flags=*/0);
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009247 // We consumed all events, so no ANR
9248 ASSERT_TRUE(mDispatcher->waitForIdle());
9249 mFakePolicy->assertNotifyAnrWasNotCalled();
9250
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08009251 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakou2899c552023-07-10 18:20:46 -07009252 injectMotionEvent(*mDispatcher,
9253 MotionEventBuilder(AMOTION_EVENT_ACTION_DOWN,
9254 AINPUT_SOURCE_TOUCHSCREEN)
9255 .pointer(PointerBuilder(0, ToolType::FINGER)
9256 .x(FOCUSED_WINDOW_LOCATION.x)
9257 .y(FOCUSED_WINDOW_LOCATION.y))
9258 .build()));
Siarhei Vishniakoud3061ab2023-12-18 20:41:08 -08009259 const auto [unfocusedSequenceNum, _] = mUnfocusedWindow->receiveEvent();
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009260 ASSERT_TRUE(unfocusedSequenceNum);
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009261
9262 const std::chrono::duration timeout =
9263 mFocusedWindow->getDispatchingTimeout(DISPATCHING_TIMEOUT);
Prabir Pradhanedd96402022-02-15 01:46:16 -08009264 mFakePolicy->assertNotifyWindowUnresponsiveWasCalled(timeout, mFocusedWindow);
Siarhei Vishniakou2899c552023-07-10 18:20:46 -07009265
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009266 mUnfocusedWindow->finishEvent(*unfocusedSequenceNum);
Siarhei Vishniakou234129c2020-10-22 22:28:12 -05009267 mFocusedWindow->consumeMotionDown();
9268 // This cancel is generated because the connection was unresponsive
9269 mFocusedWindow->consumeMotionCancel();
9270 mFocusedWindow->assertNoEvents();
9271 mUnfocusedWindow->assertNoEvents();
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009272 ASSERT_TRUE(mDispatcher->waitForIdle());
Prabir Pradhanedd96402022-02-15 01:46:16 -08009273 mFakePolicy->assertNotifyWindowResponsiveWasCalled(mFocusedWindow->getToken(),
9274 mFocusedWindow->getPid());
Siarhei Vishniakou234129c2020-10-22 22:28:12 -05009275 mFakePolicy->assertNotifyAnrWasNotCalled();
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009276}
9277
9278// If we have 2 windows with identical timeouts that are both unresponsive,
9279// it doesn't matter which order they should have ANR.
9280// But we should receive ANR for both.
9281TEST_F(InputDispatcherMultiWindowAnr, TwoWindows_BothUnresponsiveWithSameTimeout) {
9282 // Set the timeout for unfocused window to match the focused window
Siarhei Vishniakouf83c6932023-07-07 17:48:10 -07009283 mUnfocusedWindow->setDispatchingTimeout(
9284 mFocusedWindow->getDispatchingTimeout(DISPATCHING_TIMEOUT));
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07009285 mDispatcher->onWindowInfosChanged(
9286 {{*mUnfocusedWindow->getInfo(), *mFocusedWindow->getInfo()}, {}, 0, 0});
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009287
9288 tapOnFocusedWindow();
9289 // we should have ACTION_DOWN/ACTION_UP on focused window and ACTION_OUTSIDE on unfocused window
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009290 // We don't know which window will ANR first. But both of them should happen eventually.
Siarhei Vishniakouf83c6932023-07-07 17:48:10 -07009291 std::array<sp<IBinder>, 2> anrConnectionTokens = {mFakePolicy->getUnresponsiveWindowToken(
9292 mFocusedWindow->getDispatchingTimeout(
9293 DISPATCHING_TIMEOUT)),
9294 mFakePolicy->getUnresponsiveWindowToken(0ms)};
9295
9296 ASSERT_THAT(anrConnectionTokens,
9297 ::testing::UnorderedElementsAre(testing::Eq(mFocusedWindow->getToken()),
9298 testing::Eq(mUnfocusedWindow->getToken())));
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009299
9300 ASSERT_TRUE(mDispatcher->waitForIdle());
9301 mFakePolicy->assertNotifyAnrWasNotCalled();
Siarhei Vishniakou234129c2020-10-22 22:28:12 -05009302
9303 mFocusedWindow->consumeMotionDown();
9304 mFocusedWindow->consumeMotionUp();
9305 mUnfocusedWindow->consumeMotionOutside();
9306
Siarhei Vishniakouf83c6932023-07-07 17:48:10 -07009307 std::array<sp<IBinder>, 2> responsiveTokens = {mFakePolicy->getResponsiveWindowToken(),
9308 mFakePolicy->getResponsiveWindowToken()};
Siarhei Vishniakou234129c2020-10-22 22:28:12 -05009309
9310 // Both applications should be marked as responsive, in any order
Siarhei Vishniakouf83c6932023-07-07 17:48:10 -07009311 ASSERT_THAT(responsiveTokens,
9312 ::testing::UnorderedElementsAre(testing::Eq(mFocusedWindow->getToken()),
9313 testing::Eq(mUnfocusedWindow->getToken())));
Siarhei Vishniakou234129c2020-10-22 22:28:12 -05009314 mFakePolicy->assertNotifyAnrWasNotCalled();
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009315}
9316
9317// If a window is already not responding, the second tap on the same window should be ignored.
9318// We should also log an error to account for the dropped event (not tested here).
9319// At the same time, FLAG_WATCH_OUTSIDE_TOUCH targets should not receive any events.
9320TEST_F(InputDispatcherMultiWindowAnr, DuringAnr_SecondTapIsIgnored) {
9321 tapOnFocusedWindow();
Prabir Pradhan7662a8d2023-12-15 01:58:14 +00009322 mUnfocusedWindow->consumeMotionOutside(ADISPLAY_ID_DEFAULT, /*flags=*/0);
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009323 // Receive the events, but don't respond
Siarhei Vishniakoud3061ab2023-12-18 20:41:08 -08009324 const auto [downEventSequenceNum, downEvent] = mFocusedWindow->receiveEvent(); // ACTION_DOWN
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009325 ASSERT_TRUE(downEventSequenceNum);
Siarhei Vishniakoud3061ab2023-12-18 20:41:08 -08009326 const auto [upEventSequenceNum, upEvent] = mFocusedWindow->receiveEvent(); // ACTION_UP
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009327 ASSERT_TRUE(upEventSequenceNum);
9328 const std::chrono::duration timeout =
9329 mFocusedWindow->getDispatchingTimeout(DISPATCHING_TIMEOUT);
Prabir Pradhanedd96402022-02-15 01:46:16 -08009330 mFakePolicy->assertNotifyWindowUnresponsiveWasCalled(timeout, mFocusedWindow);
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009331
9332 // Tap once again
9333 // We cannot use "tapOnFocusedWindow" because it asserts the injection result to be success
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08009334 ASSERT_EQ(InputEventInjectionResult::FAILED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07009335 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009336 FOCUSED_WINDOW_LOCATION));
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08009337 ASSERT_EQ(InputEventInjectionResult::FAILED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07009338 injectMotionUp(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009339 FOCUSED_WINDOW_LOCATION));
9340 // Unfocused window does not receive ACTION_OUTSIDE because the tapped window is not a
9341 // valid touch target
9342 mUnfocusedWindow->assertNoEvents();
9343
9344 // Consume the first tap
9345 mFocusedWindow->finishEvent(*downEventSequenceNum);
9346 mFocusedWindow->finishEvent(*upEventSequenceNum);
9347 ASSERT_TRUE(mDispatcher->waitForIdle());
9348 // The second tap did not go to the focused window
9349 mFocusedWindow->assertNoEvents();
Siarhei Vishniakou234129c2020-10-22 22:28:12 -05009350 // Since all events are finished, connection should be deemed healthy again
Prabir Pradhanedd96402022-02-15 01:46:16 -08009351 mFakePolicy->assertNotifyWindowResponsiveWasCalled(mFocusedWindow->getToken(),
9352 mFocusedWindow->getPid());
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009353 mFakePolicy->assertNotifyAnrWasNotCalled();
9354}
9355
9356// If you tap outside of all windows, there will not be ANR
9357TEST_F(InputDispatcherMultiWindowAnr, TapOutsideAllWindows_DoesNotAnr) {
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08009358 ASSERT_EQ(InputEventInjectionResult::FAILED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07009359 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009360 LOCATION_OUTSIDE_ALL_WINDOWS));
9361 ASSERT_TRUE(mDispatcher->waitForIdle());
9362 mFakePolicy->assertNotifyAnrWasNotCalled();
9363}
9364
9365// Since the focused window is paused, tapping on it should not produce any events
9366TEST_F(InputDispatcherMultiWindowAnr, Window_CanBePaused) {
9367 mFocusedWindow->setPaused(true);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07009368 mDispatcher->onWindowInfosChanged(
9369 {{*mUnfocusedWindow->getInfo(), *mFocusedWindow->getInfo()}, {}, 0, 0});
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009370
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08009371 ASSERT_EQ(InputEventInjectionResult::FAILED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07009372 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009373 FOCUSED_WINDOW_LOCATION));
9374
9375 std::this_thread::sleep_for(mFocusedWindow->getDispatchingTimeout(DISPATCHING_TIMEOUT));
9376 ASSERT_TRUE(mDispatcher->waitForIdle());
9377 // Should not ANR because the window is paused, and touches shouldn't go to it
9378 mFakePolicy->assertNotifyAnrWasNotCalled();
9379
9380 mFocusedWindow->assertNoEvents();
9381 mUnfocusedWindow->assertNoEvents();
9382}
9383
9384/**
9385 * 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 -07009386 * not get delivered to the focused window until the motion is processed.
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009387 * If a different window becomes focused at this time, the key should go to that window instead.
9388 *
9389 * Warning!!!
9390 * This test depends on the value of android::inputdispatcher::KEY_WAITING_FOR_MOTION_TIMEOUT
9391 * and the injection timeout that we specify when injecting the key.
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07009392 * We must have the injection timeout (100ms) be smaller than
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009393 * KEY_WAITING_FOR_MOTION_TIMEOUT (currently 500ms).
9394 *
9395 * If that value changes, this test should also change.
9396 */
9397TEST_F(InputDispatcherMultiWindowAnr, PendingKey_GoesToNewlyFocusedWindow) {
9398 // Set a long ANR timeout to prevent it from triggering
9399 mFocusedWindow->setDispatchingTimeout(2s);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07009400 mDispatcher->onWindowInfosChanged(
9401 {{*mFocusedWindow->getInfo(), *mUnfocusedWindow->getInfo()}, {}, 0, 0});
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009402
9403 tapOnUnfocusedWindow();
Siarhei Vishniakoud3061ab2023-12-18 20:41:08 -08009404 const auto [downSequenceNum, downEvent] = mUnfocusedWindow->receiveEvent();
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009405 ASSERT_TRUE(downSequenceNum);
Siarhei Vishniakoud3061ab2023-12-18 20:41:08 -08009406 const auto [upSequenceNum, upEvent] = mUnfocusedWindow->receiveEvent();
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009407 ASSERT_TRUE(upSequenceNum);
9408 // Don't finish the events yet, and send a key
9409 // Injection will succeed because we will eventually give up and send the key to the focused
9410 // window even if motions are still being processed.
9411
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08009412 InputEventInjectionResult result =
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07009413 injectKey(*mDispatcher, AKEY_EVENT_ACTION_DOWN, /*repeatCount=*/0, ADISPLAY_ID_DEFAULT,
9414 InputEventInjectionSync::NONE, /*injectionTimeout=*/100ms);
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08009415 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, result);
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009416 // Key will not be sent to the window, yet, because the window is still processing events
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07009417 // and the key remains pending, waiting for the touch events to be processed.
9418 // Make sure `assertNoEvents` doesn't take too long. It uses CONSUME_TIMEOUT_NO_EVENT_EXPECTED
9419 // under the hood.
9420 static_assert(CONSUME_TIMEOUT_NO_EVENT_EXPECTED < 100ms);
9421 mFocusedWindow->assertNoEvents();
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009422
9423 // Switch the focus to the "unfocused" window that we tapped. Expect the key to go there
Vishnu Nair47074b82020-08-14 11:54:47 -07009424 mFocusedWindow->setFocusable(false);
9425 mUnfocusedWindow->setFocusable(true);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07009426 mDispatcher->onWindowInfosChanged(
9427 {{*mFocusedWindow->getInfo(), *mUnfocusedWindow->getInfo()}, {}, 0, 0});
Vishnu Nair958da932020-08-21 17:12:37 -07009428 setFocusedWindow(mUnfocusedWindow);
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009429
9430 // Focus events should precede the key events
9431 mUnfocusedWindow->consumeFocusEvent(true);
9432 mFocusedWindow->consumeFocusEvent(false);
9433
9434 // Finish the tap events, which should unblock dispatcher
9435 mUnfocusedWindow->finishEvent(*downSequenceNum);
9436 mUnfocusedWindow->finishEvent(*upSequenceNum);
9437
9438 // Now that all queues are cleared and no backlog in the connections, the key event
9439 // can finally go to the newly focused "mUnfocusedWindow".
9440 mUnfocusedWindow->consumeKeyDown(ADISPLAY_ID_DEFAULT);
9441 mFocusedWindow->assertNoEvents();
9442 mUnfocusedWindow->assertNoEvents();
Siarhei Vishniakou234129c2020-10-22 22:28:12 -05009443 mFakePolicy->assertNotifyAnrWasNotCalled();
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009444}
9445
9446// When the touch stream is split across 2 windows, and one of them does not respond,
9447// then ANR should be raised and the touch should be canceled for the unresponsive window.
9448// The other window should not be affected by that.
9449TEST_F(InputDispatcherMultiWindowAnr, SplitTouch_SingleWindowAnr) {
9450 // Touch Window 1
Prabir Pradhan678438e2023-04-13 19:32:51 +00009451 mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_DOWN,
9452 AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
9453 {FOCUSED_WINDOW_LOCATION}));
Prabir Pradhan7662a8d2023-12-15 01:58:14 +00009454 mUnfocusedWindow->consumeMotionOutside(ADISPLAY_ID_DEFAULT, /*flags=*/0);
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009455
9456 // Touch Window 2
Prabir Pradhan678438e2023-04-13 19:32:51 +00009457 mDispatcher->notifyMotion(
9458 generateMotionArgs(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
9459 {FOCUSED_WINDOW_LOCATION, UNFOCUSED_WINDOW_LOCATION}));
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009460
9461 const std::chrono::duration timeout =
9462 mFocusedWindow->getDispatchingTimeout(DISPATCHING_TIMEOUT);
Prabir Pradhanedd96402022-02-15 01:46:16 -08009463 mFakePolicy->assertNotifyWindowUnresponsiveWasCalled(timeout, mFocusedWindow);
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009464
9465 mUnfocusedWindow->consumeMotionDown();
9466 mFocusedWindow->consumeMotionDown();
9467 // Focused window may or may not receive ACTION_MOVE
9468 // But it should definitely receive ACTION_CANCEL due to the ANR
Siarhei Vishniakoud3061ab2023-12-18 20:41:08 -08009469 const auto [moveOrCancelSequenceNum, event] = mFocusedWindow->receiveEvent();
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009470 ASSERT_TRUE(moveOrCancelSequenceNum);
9471 mFocusedWindow->finishEvent(*moveOrCancelSequenceNum);
9472 ASSERT_NE(nullptr, event);
Siarhei Vishniakou63b63612023-04-12 11:00:23 -07009473 ASSERT_EQ(event->getType(), InputEventType::MOTION);
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009474 MotionEvent& motionEvent = static_cast<MotionEvent&>(*event);
9475 if (motionEvent.getAction() == AMOTION_EVENT_ACTION_MOVE) {
9476 mFocusedWindow->consumeMotionCancel();
9477 } else {
9478 ASSERT_EQ(AMOTION_EVENT_ACTION_CANCEL, motionEvent.getAction());
9479 }
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009480 ASSERT_TRUE(mDispatcher->waitForIdle());
Prabir Pradhanedd96402022-02-15 01:46:16 -08009481 mFakePolicy->assertNotifyWindowResponsiveWasCalled(mFocusedWindow->getToken(),
9482 mFocusedWindow->getPid());
Siarhei Vishniakou234129c2020-10-22 22:28:12 -05009483
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009484 mUnfocusedWindow->assertNoEvents();
9485 mFocusedWindow->assertNoEvents();
Siarhei Vishniakou234129c2020-10-22 22:28:12 -05009486 mFakePolicy->assertNotifyAnrWasNotCalled();
Siarhei Vishniakoud44dddf2020-03-25 16:16:40 -07009487}
9488
Siarhei Vishniakouf56b2692020-09-08 19:43:33 -05009489/**
9490 * If we have no focused window, and a key comes in, we start the ANR timer.
9491 * The focused application should add a focused window before the timer runs out to prevent ANR.
9492 *
9493 * If the user touches another application during this time, the key should be dropped.
9494 * Next, if a new focused window comes in, without toggling the focused application,
9495 * then no ANR should occur.
9496 *
9497 * Normally, we would expect the new focused window to be accompanied by 'setFocusedApplication',
9498 * but in some cases the policy may not update the focused application.
9499 */
9500TEST_F(InputDispatcherMultiWindowAnr, FocusedWindowWithoutSetFocusedApplication_NoAnr) {
9501 std::shared_ptr<FakeApplicationHandle> focusedApplication =
9502 std::make_shared<FakeApplicationHandle>();
Siarhei Vishniakouc033dfb2023-10-03 10:45:16 -07009503 focusedApplication->setDispatchingTimeout(300ms);
Siarhei Vishniakouf56b2692020-09-08 19:43:33 -05009504 mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, focusedApplication);
9505 // The application that owns 'mFocusedWindow' and 'mUnfocusedWindow' is not focused.
9506 mFocusedWindow->setFocusable(false);
9507
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07009508 mDispatcher->onWindowInfosChanged(
9509 {{*mFocusedWindow->getInfo(), *mUnfocusedWindow->getInfo()}, {}, 0, 0});
Siarhei Vishniakouf56b2692020-09-08 19:43:33 -05009510 mFocusedWindow->consumeFocusEvent(false);
9511
9512 // Send a key. The ANR timer should start because there is no focused window.
9513 // 'focusedApplication' will get blamed if this timer completes.
9514 // Key will not be sent anywhere because we have no focused window. It will remain pending.
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08009515 InputEventInjectionResult result =
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07009516 injectKey(*mDispatcher, AKEY_EVENT_ACTION_DOWN, /*repeatCount=*/0, ADISPLAY_ID_DEFAULT,
9517 InputEventInjectionSync::NONE, /*injectionTimeout=*/100ms,
Harry Cutts33476232023-01-30 19:57:29 +00009518 /*allowKeyRepeat=*/false);
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08009519 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, result);
Siarhei Vishniakouf56b2692020-09-08 19:43:33 -05009520
9521 // Wait until dispatcher starts the "no focused window" timer. If we don't wait here,
9522 // then the injected touches won't cause the focused event to get dropped.
9523 // The dispatcher only checks for whether the queue should be pruned upon queueing.
9524 // If we inject the touch right away and the ANR timer hasn't started, the touch event would
9525 // simply be added to the queue without 'shouldPruneInboundQueueLocked' returning 'true'.
9526 // For this test, it means that the key would get delivered to the window once it becomes
9527 // focused.
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07009528 std::this_thread::sleep_for(100ms);
Siarhei Vishniakouf56b2692020-09-08 19:43:33 -05009529
9530 // Touch unfocused window. This should force the pending key to get dropped.
Prabir Pradhan678438e2023-04-13 19:32:51 +00009531 mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_DOWN,
9532 AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
9533 {UNFOCUSED_WINDOW_LOCATION}));
Siarhei Vishniakouf56b2692020-09-08 19:43:33 -05009534
9535 // We do not consume the motion right away, because that would require dispatcher to first
9536 // process (== drop) the key event, and by that time, ANR will be raised.
9537 // Set the focused window first.
9538 mFocusedWindow->setFocusable(true);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07009539 mDispatcher->onWindowInfosChanged(
9540 {{*mFocusedWindow->getInfo(), *mUnfocusedWindow->getInfo()}, {}, 0, 0});
Siarhei Vishniakouf56b2692020-09-08 19:43:33 -05009541 setFocusedWindow(mFocusedWindow);
9542 mFocusedWindow->consumeFocusEvent(true);
9543 // We do not call "setFocusedApplication" here, even though the newly focused window belongs
9544 // to another application. This could be a bug / behaviour in the policy.
9545
9546 mUnfocusedWindow->consumeMotionDown();
9547
9548 ASSERT_TRUE(mDispatcher->waitForIdle());
9549 // Should not ANR because we actually have a focused window. It was just added too slowly.
9550 ASSERT_NO_FATAL_FAILURE(mFakePolicy->assertNotifyAnrWasNotCalled());
9551}
9552
Siarhei Vishniakou99e407b2023-12-26 18:09:32 -08009553/**
9554 * If we are pruning input queue, we should never drop pointer events. Otherwise, we risk having
9555 * an inconsistent event stream inside the dispatcher. In this test, we make sure that the
9556 * dispatcher doesn't prune pointer events incorrectly.
9557 *
9558 * This test reproduces a crash in InputDispatcher.
9559 * To reproduce the crash, we need to simulate the conditions for "pruning input queue" to occur.
9560 *
9561 * Keep the currently focused application (mApplication), and have no focused window.
9562 * We set up two additional windows:
9563 * 1) The navigation bar window. This simulates the system "NavigationBar", which is used in the
9564 * 3-button navigation mode. This window injects a BACK button when it's touched. 2) The application
9565 * window. This window is not focusable, but is touchable.
9566 *
9567 * We first touch the navigation bar, which causes it to inject a key. Since there's no focused
9568 * window, the dispatcher doesn't process this key, and all other events inside dispatcher are now
9569 * blocked. The dispatcher is waiting for 'mApplication' to add a focused window.
9570 *
9571 * Now, we touch "Another window". This window is owned by a different application than
9572 * 'mApplication'. This causes the dispatcher to stop waiting for 'mApplication' to add a focused
9573 * window. Now, the "pruning input queue" behaviour should kick in, and the dispatcher should start
9574 * dropping the events from its queue. Ensure that no crash occurs.
9575 *
9576 * In this test, we are setting long timeouts to prevent ANRs and events dropped due to being stale.
9577 * This does not affect the test running time.
9578 */
9579TEST_F(InputDispatcherMultiWindowAnr, PruningInputQueueShouldNotDropPointerEvents) {
9580 std::shared_ptr<FakeApplicationHandle> systemUiApplication =
9581 std::make_shared<FakeApplicationHandle>();
9582 systemUiApplication->setDispatchingTimeout(3000ms);
9583 mFakePolicy->setStaleEventTimeout(3000ms);
9584 sp<FakeWindowHandle> navigationBar =
9585 sp<FakeWindowHandle>::make(systemUiApplication, mDispatcher, "NavigationBar",
9586 ADISPLAY_ID_DEFAULT);
9587 navigationBar->setFocusable(false);
9588 navigationBar->setWatchOutsideTouch(true);
9589 navigationBar->setFrame(Rect(0, 0, 100, 100));
9590
9591 mApplication->setDispatchingTimeout(3000ms);
9592 // 'mApplication' is already focused, but we call it again here to make it explicit.
9593 mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, mApplication);
9594
9595 std::shared_ptr<FakeApplicationHandle> anotherApplication =
9596 std::make_shared<FakeApplicationHandle>();
9597 sp<FakeWindowHandle> appWindow =
9598 sp<FakeWindowHandle>::make(anotherApplication, mDispatcher, "Another window",
9599 ADISPLAY_ID_DEFAULT);
9600 appWindow->setFocusable(false);
9601 appWindow->setFrame(Rect(100, 100, 200, 200));
9602
9603 mDispatcher->onWindowInfosChanged(
9604 {{*navigationBar->getInfo(), *appWindow->getInfo()}, {}, 0, 0});
9605 // 'mFocusedWindow' is no longer in the dispatcher window list, and therefore loses focus
9606 mFocusedWindow->consumeFocusEvent(false);
9607
9608 // Touch down the navigation bar. It consumes the touch and injects a key into the dispatcher
9609 // in response.
9610 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
9611 .pointer(PointerBuilder(0, ToolType::FINGER).x(50).y(50))
9612 .build());
9613 navigationBar->consumeMotionEvent(WithMotionAction(ACTION_DOWN));
9614
9615 // Key will not be sent anywhere because we have no focused window. It will remain pending.
9616 // Pretend we are injecting KEYCODE_BACK, but it doesn't actually matter what key it is.
9617 InputEventInjectionResult result =
9618 injectKey(*mDispatcher, AKEY_EVENT_ACTION_DOWN, /*repeatCount=*/0, ADISPLAY_ID_DEFAULT,
9619 InputEventInjectionSync::NONE, /*injectionTimeout=*/100ms,
9620 /*allowKeyRepeat=*/false);
9621 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, result);
9622
9623 // Finish the gesture - lift up finger and inject ACTION_UP key event
9624 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN)
9625 .pointer(PointerBuilder(0, ToolType::FINGER).x(50).y(50))
9626 .build());
9627 result = injectKey(*mDispatcher, AKEY_EVENT_ACTION_UP, /*repeatCount=*/0, ADISPLAY_ID_DEFAULT,
9628 InputEventInjectionSync::NONE, /*injectionTimeout=*/100ms,
9629 /*allowKeyRepeat=*/false);
9630 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, result);
9631 // The key that was injected is blocking the dispatcher, so the navigation bar shouldn't be
9632 // getting any events yet.
9633 navigationBar->assertNoEvents();
9634
9635 // Now touch "Another window". This touch is going to a different application than the one we
9636 // are waiting for (which is 'mApplication').
9637 // This should cause the dispatcher to drop the pending focus-dispatched events (like the key
9638 // trying to be injected) and to continue processing the rest of the events in the original
9639 // order.
9640 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
9641 .pointer(PointerBuilder(0, ToolType::FINGER).x(150).y(150))
9642 .build());
9643 navigationBar->consumeMotionEvent(WithMotionAction(ACTION_UP));
9644 navigationBar->consumeMotionEvent(WithMotionAction(ACTION_OUTSIDE));
9645 appWindow->consumeMotionEvent(WithMotionAction(ACTION_DOWN));
9646
9647 appWindow->assertNoEvents();
9648 navigationBar->assertNoEvents();
9649}
9650
Siarhei Vishniakoua2862a02020-07-20 16:36:46 -05009651// These tests ensure we cannot send touch events to a window that's positioned behind a window
9652// that has feature NO_INPUT_CHANNEL.
9653// Layout:
9654// Top (closest to user)
9655// mNoInputWindow (above all windows)
9656// mBottomWindow
9657// Bottom (furthest from user)
9658class InputDispatcherMultiWindowOcclusionTests : public InputDispatcherTest {
9659 virtual void SetUp() override {
9660 InputDispatcherTest::SetUp();
9661
9662 mApplication = std::make_shared<FakeApplicationHandle>();
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07009663 mNoInputWindow =
9664 sp<FakeWindowHandle>::make(mApplication, mDispatcher,
9665 "Window without input channel", ADISPLAY_ID_DEFAULT,
Prabir Pradhane7cc69c2024-01-05 21:35:28 +00009666 /*createInputChannel=*/false);
Prabir Pradhan51e7db02022-02-07 06:02:57 -08009667 mNoInputWindow->setNoInputChannel(true);
Siarhei Vishniakoua2862a02020-07-20 16:36:46 -05009668 mNoInputWindow->setFrame(Rect(0, 0, 100, 100));
9669 // It's perfectly valid for this window to not have an associated input channel
9670
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07009671 mBottomWindow = sp<FakeWindowHandle>::make(mApplication, mDispatcher, "Bottom window",
9672 ADISPLAY_ID_DEFAULT);
Siarhei Vishniakoua2862a02020-07-20 16:36:46 -05009673 mBottomWindow->setFrame(Rect(0, 0, 100, 100));
9674
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07009675 mDispatcher->onWindowInfosChanged(
9676 {{*mNoInputWindow->getInfo(), *mBottomWindow->getInfo()}, {}, 0, 0});
Siarhei Vishniakoua2862a02020-07-20 16:36:46 -05009677 }
9678
9679protected:
9680 std::shared_ptr<FakeApplicationHandle> mApplication;
9681 sp<FakeWindowHandle> mNoInputWindow;
9682 sp<FakeWindowHandle> mBottomWindow;
9683};
9684
9685TEST_F(InputDispatcherMultiWindowOcclusionTests, NoInputChannelFeature_DropsTouches) {
9686 PointF touchedPoint = {10, 10};
9687
Prabir Pradhan678438e2023-04-13 19:32:51 +00009688 mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_DOWN,
9689 AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
9690 {touchedPoint}));
Siarhei Vishniakoua2862a02020-07-20 16:36:46 -05009691
9692 mNoInputWindow->assertNoEvents();
9693 // Even though the window 'mNoInputWindow' positioned above 'mBottomWindow' does not have
9694 // an input channel, it is not marked as FLAG_NOT_TOUCHABLE,
9695 // and therefore should prevent mBottomWindow from receiving touches
9696 mBottomWindow->assertNoEvents();
9697}
9698
9699/**
9700 * If a window has feature NO_INPUT_CHANNEL, and somehow (by mistake) still has an input channel,
9701 * ensure that this window does not receive any touches, and blocks touches to windows underneath.
9702 */
9703TEST_F(InputDispatcherMultiWindowOcclusionTests,
9704 NoInputChannelFeature_DropsTouchesWithValidChannel) {
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07009705 mNoInputWindow = sp<FakeWindowHandle>::make(mApplication, mDispatcher,
9706 "Window with input channel and NO_INPUT_CHANNEL",
9707 ADISPLAY_ID_DEFAULT);
Siarhei Vishniakoua2862a02020-07-20 16:36:46 -05009708
Prabir Pradhan51e7db02022-02-07 06:02:57 -08009709 mNoInputWindow->setNoInputChannel(true);
Siarhei Vishniakoua2862a02020-07-20 16:36:46 -05009710 mNoInputWindow->setFrame(Rect(0, 0, 100, 100));
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07009711 mDispatcher->onWindowInfosChanged(
9712 {{*mNoInputWindow->getInfo(), *mBottomWindow->getInfo()}, {}, 0, 0});
Siarhei Vishniakoua2862a02020-07-20 16:36:46 -05009713
9714 PointF touchedPoint = {10, 10};
9715
Prabir Pradhan678438e2023-04-13 19:32:51 +00009716 mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_DOWN,
9717 AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
9718 {touchedPoint}));
Siarhei Vishniakoua2862a02020-07-20 16:36:46 -05009719
9720 mNoInputWindow->assertNoEvents();
9721 mBottomWindow->assertNoEvents();
9722}
9723
Vishnu Nair958da932020-08-21 17:12:37 -07009724class InputDispatcherMirrorWindowFocusTests : public InputDispatcherTest {
9725protected:
9726 std::shared_ptr<FakeApplicationHandle> mApp;
9727 sp<FakeWindowHandle> mWindow;
9728 sp<FakeWindowHandle> mMirror;
9729
9730 virtual void SetUp() override {
9731 InputDispatcherTest::SetUp();
9732 mApp = std::make_shared<FakeApplicationHandle>();
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07009733 mWindow = sp<FakeWindowHandle>::make(mApp, mDispatcher, "TestWindow", ADISPLAY_ID_DEFAULT);
Prabir Pradhane7cc69c2024-01-05 21:35:28 +00009734 mMirror = mWindow->clone(ADISPLAY_ID_DEFAULT);
Vishnu Nair958da932020-08-21 17:12:37 -07009735 mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, mApp);
9736 mWindow->setFocusable(true);
9737 mMirror->setFocusable(true);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07009738 mDispatcher->onWindowInfosChanged({{*mWindow->getInfo(), *mMirror->getInfo()}, {}, 0, 0});
Vishnu Nair958da932020-08-21 17:12:37 -07009739 }
9740};
9741
9742TEST_F(InputDispatcherMirrorWindowFocusTests, CanGetFocus) {
9743 // Request focus on a mirrored window
9744 setFocusedWindow(mMirror);
9745
9746 // window gets focused
9747 mWindow->consumeFocusEvent(true);
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07009748 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectKeyDown(*mDispatcher))
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08009749 << "Inject key event should return InputEventInjectionResult::SUCCEEDED";
Vishnu Nair958da932020-08-21 17:12:37 -07009750 mWindow->consumeKeyDown(ADISPLAY_ID_NONE);
9751}
9752
9753// A focused & mirrored window remains focused only if the window and its mirror are both
9754// focusable.
9755TEST_F(InputDispatcherMirrorWindowFocusTests, FocusedIfAllWindowsFocusable) {
9756 setFocusedWindow(mMirror);
9757
Prabir Pradhanbb3f1c02024-01-04 20:17:14 +00009758 // window gets focused because it is above the mirror
Vishnu Nair958da932020-08-21 17:12:37 -07009759 mWindow->consumeFocusEvent(true);
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07009760 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectKeyDown(*mDispatcher))
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08009761 << "Inject key event should return InputEventInjectionResult::SUCCEEDED";
Vishnu Nair958da932020-08-21 17:12:37 -07009762 mWindow->consumeKeyDown(ADISPLAY_ID_NONE);
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07009763 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectKeyUp(*mDispatcher))
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08009764 << "Inject key event should return InputEventInjectionResult::SUCCEEDED";
Vishnu Nair958da932020-08-21 17:12:37 -07009765 mWindow->consumeKeyUp(ADISPLAY_ID_NONE);
9766
9767 mMirror->setFocusable(false);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07009768 mDispatcher->onWindowInfosChanged({{*mWindow->getInfo(), *mMirror->getInfo()}, {}, 0, 0});
Vishnu Nair958da932020-08-21 17:12:37 -07009769
9770 // window loses focus since one of the windows associated with the token in not focusable
9771 mWindow->consumeFocusEvent(false);
9772
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07009773 ASSERT_EQ(InputEventInjectionResult::TIMED_OUT, injectKeyDown(*mDispatcher))
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08009774 << "Inject key event should return InputEventInjectionResult::TIMED_OUT";
Vishnu Nair958da932020-08-21 17:12:37 -07009775 mWindow->assertNoEvents();
9776}
9777
9778// A focused & mirrored window remains focused until the window and its mirror both become
9779// invisible.
9780TEST_F(InputDispatcherMirrorWindowFocusTests, FocusedIfAnyWindowVisible) {
9781 setFocusedWindow(mMirror);
9782
9783 // window gets focused
9784 mWindow->consumeFocusEvent(true);
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07009785 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectKeyDown(*mDispatcher))
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08009786 << "Inject key event should return InputEventInjectionResult::SUCCEEDED";
Vishnu Nair958da932020-08-21 17:12:37 -07009787 mWindow->consumeKeyDown(ADISPLAY_ID_NONE);
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07009788 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectKeyUp(*mDispatcher))
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08009789 << "Inject key event should return InputEventInjectionResult::SUCCEEDED";
Vishnu Nair958da932020-08-21 17:12:37 -07009790 mWindow->consumeKeyUp(ADISPLAY_ID_NONE);
9791
9792 mMirror->setVisible(false);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07009793 mDispatcher->onWindowInfosChanged({{*mWindow->getInfo(), *mMirror->getInfo()}, {}, 0, 0});
Vishnu Nair958da932020-08-21 17:12:37 -07009794
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07009795 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectKeyDown(*mDispatcher))
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08009796 << "Inject key event should return InputEventInjectionResult::SUCCEEDED";
Vishnu Nair958da932020-08-21 17:12:37 -07009797 mWindow->consumeKeyDown(ADISPLAY_ID_NONE);
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07009798 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectKeyUp(*mDispatcher))
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08009799 << "Inject key event should return InputEventInjectionResult::SUCCEEDED";
Vishnu Nair958da932020-08-21 17:12:37 -07009800 mWindow->consumeKeyUp(ADISPLAY_ID_NONE);
9801
9802 mWindow->setVisible(false);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07009803 mDispatcher->onWindowInfosChanged({{*mWindow->getInfo(), *mMirror->getInfo()}, {}, 0, 0});
Vishnu Nair958da932020-08-21 17:12:37 -07009804
9805 // window loses focus only after all windows associated with the token become invisible.
9806 mWindow->consumeFocusEvent(false);
9807
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07009808 ASSERT_EQ(InputEventInjectionResult::TIMED_OUT, injectKeyDown(*mDispatcher))
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08009809 << "Inject key event should return InputEventInjectionResult::TIMED_OUT";
Vishnu Nair958da932020-08-21 17:12:37 -07009810 mWindow->assertNoEvents();
9811}
9812
9813// A focused & mirrored window remains focused until both windows are removed.
9814TEST_F(InputDispatcherMirrorWindowFocusTests, FocusedWhileWindowsAlive) {
9815 setFocusedWindow(mMirror);
9816
9817 // window gets focused
9818 mWindow->consumeFocusEvent(true);
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07009819 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectKeyDown(*mDispatcher))
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08009820 << "Inject key event should return InputEventInjectionResult::SUCCEEDED";
Vishnu Nair958da932020-08-21 17:12:37 -07009821 mWindow->consumeKeyDown(ADISPLAY_ID_NONE);
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07009822 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectKeyUp(*mDispatcher))
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08009823 << "Inject key event should return InputEventInjectionResult::SUCCEEDED";
Vishnu Nair958da932020-08-21 17:12:37 -07009824 mWindow->consumeKeyUp(ADISPLAY_ID_NONE);
9825
9826 // single window is removed but the window token remains focused
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07009827 mDispatcher->onWindowInfosChanged({{*mMirror->getInfo()}, {}, 0, 0});
Vishnu Nair958da932020-08-21 17:12:37 -07009828
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07009829 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectKeyDown(*mDispatcher))
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08009830 << "Inject key event should return InputEventInjectionResult::SUCCEEDED";
Prabir Pradhanbb3f1c02024-01-04 20:17:14 +00009831 mMirror->consumeKeyDown(ADISPLAY_ID_NONE);
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07009832 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectKeyUp(*mDispatcher))
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08009833 << "Inject key event should return InputEventInjectionResult::SUCCEEDED";
Prabir Pradhanbb3f1c02024-01-04 20:17:14 +00009834 mMirror->consumeKeyUp(ADISPLAY_ID_NONE);
Vishnu Nair958da932020-08-21 17:12:37 -07009835
9836 // Both windows are removed
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07009837 mDispatcher->onWindowInfosChanged({{}, {}, 0, 0});
Vishnu Nair958da932020-08-21 17:12:37 -07009838 mWindow->consumeFocusEvent(false);
9839
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07009840 ASSERT_EQ(InputEventInjectionResult::TIMED_OUT, injectKeyDown(*mDispatcher))
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08009841 << "Inject key event should return InputEventInjectionResult::TIMED_OUT";
Vishnu Nair958da932020-08-21 17:12:37 -07009842 mWindow->assertNoEvents();
9843}
9844
9845// Focus request can be pending until one window becomes visible.
9846TEST_F(InputDispatcherMirrorWindowFocusTests, DeferFocusWhenInvisible) {
9847 // Request focus on an invisible mirror.
9848 mWindow->setVisible(false);
9849 mMirror->setVisible(false);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07009850 mDispatcher->onWindowInfosChanged({{*mWindow->getInfo(), *mMirror->getInfo()}, {}, 0, 0});
Vishnu Nair958da932020-08-21 17:12:37 -07009851 setFocusedWindow(mMirror);
9852
9853 // Injected key goes to pending queue.
Siarhei Vishniakouae6229e2019-12-30 16:23:19 -08009854 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -07009855 injectKey(*mDispatcher, AKEY_EVENT_ACTION_DOWN, /*repeatCount=*/0,
9856 ADISPLAY_ID_DEFAULT, InputEventInjectionSync::NONE));
Vishnu Nair958da932020-08-21 17:12:37 -07009857
9858 mMirror->setVisible(true);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07009859 mDispatcher->onWindowInfosChanged({{*mWindow->getInfo(), *mMirror->getInfo()}, {}, 0, 0});
Vishnu Nair958da932020-08-21 17:12:37 -07009860
9861 // window gets focused
9862 mWindow->consumeFocusEvent(true);
9863 // window gets the pending key event
9864 mWindow->consumeKeyDown(ADISPLAY_ID_DEFAULT);
9865}
Prabir Pradhan99987712020-11-10 18:43:05 -08009866
9867class InputDispatcherPointerCaptureTests : public InputDispatcherTest {
9868protected:
9869 std::shared_ptr<FakeApplicationHandle> mApp;
9870 sp<FakeWindowHandle> mWindow;
9871 sp<FakeWindowHandle> mSecondWindow;
9872
9873 void SetUp() override {
9874 InputDispatcherTest::SetUp();
9875 mApp = std::make_shared<FakeApplicationHandle>();
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07009876 mWindow = sp<FakeWindowHandle>::make(mApp, mDispatcher, "TestWindow", ADISPLAY_ID_DEFAULT);
Prabir Pradhan99987712020-11-10 18:43:05 -08009877 mWindow->setFocusable(true);
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -07009878 mSecondWindow =
9879 sp<FakeWindowHandle>::make(mApp, mDispatcher, "TestWindow2", ADISPLAY_ID_DEFAULT);
Prabir Pradhan99987712020-11-10 18:43:05 -08009880 mSecondWindow->setFocusable(true);
9881
9882 mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, mApp);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -07009883 mDispatcher->onWindowInfosChanged(
9884 {{*mWindow->getInfo(), *mSecondWindow->getInfo()}, {}, 0, 0});
Prabir Pradhan99987712020-11-10 18:43:05 -08009885
9886 setFocusedWindow(mWindow);
9887 mWindow->consumeFocusEvent(true);
9888 }
9889
Prabir Pradhan5cc1a692021-08-06 14:01:18 +00009890 void notifyPointerCaptureChanged(const PointerCaptureRequest& request) {
Prabir Pradhan678438e2023-04-13 19:32:51 +00009891 mDispatcher->notifyPointerCaptureChanged(generatePointerCaptureChangedArgs(request));
Prabir Pradhan99987712020-11-10 18:43:05 -08009892 }
9893
Prabir Pradhan5cc1a692021-08-06 14:01:18 +00009894 PointerCaptureRequest requestAndVerifyPointerCapture(const sp<FakeWindowHandle>& window,
9895 bool enabled) {
Prabir Pradhan99987712020-11-10 18:43:05 -08009896 mDispatcher->requestPointerCapture(window->getToken(), enabled);
Hiroki Sato25040232024-02-22 17:21:22 +09009897 auto request = mFakePolicy->assertSetPointerCaptureCalled(window, enabled);
Prabir Pradhan5cc1a692021-08-06 14:01:18 +00009898 notifyPointerCaptureChanged(request);
Prabir Pradhan99987712020-11-10 18:43:05 -08009899 window->consumeCaptureEvent(enabled);
Prabir Pradhan5cc1a692021-08-06 14:01:18 +00009900 return request;
Prabir Pradhan99987712020-11-10 18:43:05 -08009901 }
9902};
9903
9904TEST_F(InputDispatcherPointerCaptureTests, EnablePointerCaptureWhenFocused) {
9905 // Ensure that capture cannot be obtained for unfocused windows.
9906 mDispatcher->requestPointerCapture(mSecondWindow->getToken(), true);
9907 mFakePolicy->assertSetPointerCaptureNotCalled();
9908 mSecondWindow->assertNoEvents();
9909
9910 // Ensure that capture can be enabled from the focus window.
9911 requestAndVerifyPointerCapture(mWindow, true);
9912
9913 // Ensure that capture cannot be disabled from a window that does not have capture.
9914 mDispatcher->requestPointerCapture(mSecondWindow->getToken(), false);
9915 mFakePolicy->assertSetPointerCaptureNotCalled();
9916
9917 // Ensure that capture can be disabled from the window with capture.
9918 requestAndVerifyPointerCapture(mWindow, false);
9919}
9920
9921TEST_F(InputDispatcherPointerCaptureTests, DisablesPointerCaptureAfterWindowLosesFocus) {
Prabir Pradhan5cc1a692021-08-06 14:01:18 +00009922 auto request = requestAndVerifyPointerCapture(mWindow, true);
Prabir Pradhan99987712020-11-10 18:43:05 -08009923
9924 setFocusedWindow(mSecondWindow);
9925
9926 // Ensure that the capture disabled event was sent first.
9927 mWindow->consumeCaptureEvent(false);
9928 mWindow->consumeFocusEvent(false);
9929 mSecondWindow->consumeFocusEvent(true);
Hiroki Sato25040232024-02-22 17:21:22 +09009930 mFakePolicy->assertSetPointerCaptureCalled(mWindow, false);
Prabir Pradhan99987712020-11-10 18:43:05 -08009931
9932 // Ensure that additional state changes from InputReader are not sent to the window.
Prabir Pradhan5cc1a692021-08-06 14:01:18 +00009933 notifyPointerCaptureChanged({});
9934 notifyPointerCaptureChanged(request);
9935 notifyPointerCaptureChanged({});
Prabir Pradhan99987712020-11-10 18:43:05 -08009936 mWindow->assertNoEvents();
9937 mSecondWindow->assertNoEvents();
9938 mFakePolicy->assertSetPointerCaptureNotCalled();
9939}
9940
9941TEST_F(InputDispatcherPointerCaptureTests, UnexpectedStateChangeDisablesPointerCapture) {
Prabir Pradhan5cc1a692021-08-06 14:01:18 +00009942 auto request = requestAndVerifyPointerCapture(mWindow, true);
Prabir Pradhan99987712020-11-10 18:43:05 -08009943
9944 // InputReader unexpectedly disables and enables pointer capture.
Prabir Pradhan5cc1a692021-08-06 14:01:18 +00009945 notifyPointerCaptureChanged({});
9946 notifyPointerCaptureChanged(request);
Prabir Pradhan99987712020-11-10 18:43:05 -08009947
9948 // Ensure that Pointer Capture is disabled.
Hiroki Sato25040232024-02-22 17:21:22 +09009949 mFakePolicy->assertSetPointerCaptureCalled(mWindow, false);
Prabir Pradhan99987712020-11-10 18:43:05 -08009950 mWindow->consumeCaptureEvent(false);
9951 mWindow->assertNoEvents();
9952}
9953
Prabir Pradhan167e6d92021-02-04 16:18:17 -08009954TEST_F(InputDispatcherPointerCaptureTests, OutOfOrderRequests) {
9955 requestAndVerifyPointerCapture(mWindow, true);
9956
9957 // The first window loses focus.
9958 setFocusedWindow(mSecondWindow);
Hiroki Sato25040232024-02-22 17:21:22 +09009959 mFakePolicy->assertSetPointerCaptureCalled(mWindow, false);
Prabir Pradhan167e6d92021-02-04 16:18:17 -08009960 mWindow->consumeCaptureEvent(false);
9961
9962 // Request Pointer Capture from the second window before the notification from InputReader
9963 // arrives.
9964 mDispatcher->requestPointerCapture(mSecondWindow->getToken(), true);
Hiroki Sato25040232024-02-22 17:21:22 +09009965 auto request = mFakePolicy->assertSetPointerCaptureCalled(mSecondWindow, true);
Prabir Pradhan167e6d92021-02-04 16:18:17 -08009966
9967 // InputReader notifies Pointer Capture was disabled (because of the focus change).
Prabir Pradhan5cc1a692021-08-06 14:01:18 +00009968 notifyPointerCaptureChanged({});
Prabir Pradhan167e6d92021-02-04 16:18:17 -08009969
9970 // InputReader notifies Pointer Capture was enabled (because of mSecondWindow's request).
Prabir Pradhan5cc1a692021-08-06 14:01:18 +00009971 notifyPointerCaptureChanged(request);
Prabir Pradhan167e6d92021-02-04 16:18:17 -08009972
9973 mSecondWindow->consumeFocusEvent(true);
9974 mSecondWindow->consumeCaptureEvent(true);
9975}
9976
Prabir Pradhan5cc1a692021-08-06 14:01:18 +00009977TEST_F(InputDispatcherPointerCaptureTests, EnableRequestFollowsSequenceNumbers) {
9978 // App repeatedly enables and disables capture.
9979 mDispatcher->requestPointerCapture(mWindow->getToken(), true);
Hiroki Sato25040232024-02-22 17:21:22 +09009980 auto firstRequest = mFakePolicy->assertSetPointerCaptureCalled(mWindow, true);
Prabir Pradhan5cc1a692021-08-06 14:01:18 +00009981 mDispatcher->requestPointerCapture(mWindow->getToken(), false);
Hiroki Sato25040232024-02-22 17:21:22 +09009982 mFakePolicy->assertSetPointerCaptureCalled(mWindow, false);
Prabir Pradhan5cc1a692021-08-06 14:01:18 +00009983 mDispatcher->requestPointerCapture(mWindow->getToken(), true);
Hiroki Sato25040232024-02-22 17:21:22 +09009984 auto secondRequest = mFakePolicy->assertSetPointerCaptureCalled(mWindow, true);
Prabir Pradhan5cc1a692021-08-06 14:01:18 +00009985
9986 // InputReader notifies that PointerCapture has been enabled for the first request. Since the
9987 // first request is now stale, this should do nothing.
9988 notifyPointerCaptureChanged(firstRequest);
9989 mWindow->assertNoEvents();
9990
9991 // InputReader notifies that the second request was enabled.
9992 notifyPointerCaptureChanged(secondRequest);
9993 mWindow->consumeCaptureEvent(true);
9994}
9995
Prabir Pradhan7092e262022-05-03 16:51:09 +00009996TEST_F(InputDispatcherPointerCaptureTests, RapidToggleRequests) {
9997 requestAndVerifyPointerCapture(mWindow, true);
9998
9999 // App toggles pointer capture off and on.
10000 mDispatcher->requestPointerCapture(mWindow->getToken(), false);
Hiroki Sato25040232024-02-22 17:21:22 +090010001 mFakePolicy->assertSetPointerCaptureCalled(mWindow, false);
Prabir Pradhan7092e262022-05-03 16:51:09 +000010002
10003 mDispatcher->requestPointerCapture(mWindow->getToken(), true);
Hiroki Sato25040232024-02-22 17:21:22 +090010004 auto enableRequest = mFakePolicy->assertSetPointerCaptureCalled(mWindow, true);
Prabir Pradhan7092e262022-05-03 16:51:09 +000010005
10006 // InputReader notifies that the latest "enable" request was processed, while skipping over the
10007 // preceding "disable" request.
10008 notifyPointerCaptureChanged(enableRequest);
10009
10010 // Since pointer capture was never disabled during the rapid toggle, the window does not receive
10011 // any notifications.
10012 mWindow->assertNoEvents();
10013}
10014
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -070010015/**
10016 * One window. Hover mouse in the window, and then start capture. Make sure that the relative
10017 * mouse movements don't affect the previous mouse hovering state.
10018 * When pointer capture is enabled, the incoming events are always ACTION_MOVE (there are no
10019 * HOVER_MOVE events).
10020 */
10021TEST_F(InputDispatcherPointerCaptureTests, MouseHoverAndPointerCapture) {
10022 // Mouse hover on the window
10023 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_ENTER, AINPUT_SOURCE_MOUSE)
10024 .pointer(PointerBuilder(0, ToolType::MOUSE).x(100).y(110))
10025 .build());
10026 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_MOVE, AINPUT_SOURCE_MOUSE)
10027 .pointer(PointerBuilder(0, ToolType::MOUSE).x(100).y(110))
10028 .build());
10029
10030 mWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_HOVER_ENTER)));
10031 mWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_HOVER_MOVE)));
10032
10033 // Start pointer capture
10034 requestAndVerifyPointerCapture(mWindow, true);
10035
10036 // Send some relative mouse movements and receive them in the window.
10037 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_MOUSE_RELATIVE)
10038 .pointer(PointerBuilder(0, ToolType::MOUSE).x(10).y(11))
10039 .build());
10040 mWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_MOVE), WithCoords(10, 11),
10041 WithSource(AINPUT_SOURCE_MOUSE_RELATIVE)));
10042
10043 // Stop pointer capture
10044 requestAndVerifyPointerCapture(mWindow, false);
10045
10046 // Continue hovering on the window
10047 mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_MOVE, AINPUT_SOURCE_MOUSE)
10048 .pointer(PointerBuilder(0, ToolType::MOUSE).x(105).y(115))
10049 .build());
10050 mWindow->consumeMotionEvent(
10051 AllOf(WithMotionAction(ACTION_HOVER_MOVE), WithSource(AINPUT_SOURCE_MOUSE)));
10052
10053 mWindow->assertNoEvents();
10054}
10055
Hiroki Sato25040232024-02-22 17:21:22 +090010056using InputDispatcherPointerCaptureDeathTest = InputDispatcherPointerCaptureTests;
10057
10058TEST_F(InputDispatcherPointerCaptureDeathTest,
10059 NotifyPointerCaptureChangedWithWrongTokenAbortsDispatcher) {
10060 testing::GTEST_FLAG(death_test_style) = "threadsafe";
10061 ScopedSilentDeath _silentDeath;
10062
10063 mDispatcher->requestPointerCapture(mWindow->getToken(), true);
10064 auto request = mFakePolicy->assertSetPointerCaptureCalled(mWindow, true);
10065
10066 // Dispatch a pointer changed event with a wrong token.
10067 request.window = mSecondWindow->getToken();
10068 ASSERT_DEATH(
10069 {
10070 notifyPointerCaptureChanged(request);
10071 mSecondWindow->consumeCaptureEvent(true);
10072 },
10073 "Unexpected requested window for Pointer Capture.");
10074}
10075
Bernardo Rufinoc3b7b8c2021-01-29 17:38:07 +000010076class InputDispatcherUntrustedTouchesTest : public InputDispatcherTest {
10077protected:
10078 constexpr static const float MAXIMUM_OBSCURING_OPACITY = 0.8;
Bernardo Rufino7393d172021-02-26 13:56:11 +000010079
10080 constexpr static const float OPACITY_ABOVE_THRESHOLD = 0.9;
10081 static_assert(OPACITY_ABOVE_THRESHOLD > MAXIMUM_OBSCURING_OPACITY);
10082
10083 constexpr static const float OPACITY_BELOW_THRESHOLD = 0.7;
10084 static_assert(OPACITY_BELOW_THRESHOLD < MAXIMUM_OBSCURING_OPACITY);
10085
10086 // When combined twice, ie 1 - (1 - 0.5)*(1 - 0.5) = 0.75 < 8, is still below the threshold
10087 constexpr static const float OPACITY_FAR_BELOW_THRESHOLD = 0.5;
10088 static_assert(OPACITY_FAR_BELOW_THRESHOLD < MAXIMUM_OBSCURING_OPACITY);
10089 static_assert(1 - (1 - OPACITY_FAR_BELOW_THRESHOLD) * (1 - OPACITY_FAR_BELOW_THRESHOLD) <
10090 MAXIMUM_OBSCURING_OPACITY);
10091
Prabir Pradhan8a5c41d2023-06-08 19:13:46 +000010092 static constexpr gui::Uid TOUCHED_APP_UID{10001};
10093 static constexpr gui::Uid APP_B_UID{10002};
10094 static constexpr gui::Uid APP_C_UID{10003};
Bernardo Rufinoc3b7b8c2021-01-29 17:38:07 +000010095
10096 sp<FakeWindowHandle> mTouchWindow;
10097
10098 virtual void SetUp() override {
10099 InputDispatcherTest::SetUp();
Bernardo Rufino6d52e542021-02-15 18:38:10 +000010100 mTouchWindow = getWindow(TOUCHED_APP_UID, "Touched");
Bernardo Rufinoc3b7b8c2021-01-29 17:38:07 +000010101 mDispatcher->setMaximumObscuringOpacityForTouch(MAXIMUM_OBSCURING_OPACITY);
10102 }
10103
10104 virtual void TearDown() override {
10105 InputDispatcherTest::TearDown();
10106 mTouchWindow.clear();
10107 }
10108
Prabir Pradhan8a5c41d2023-06-08 19:13:46 +000010109 sp<FakeWindowHandle> getOccludingWindow(gui::Uid uid, std::string name, TouchOcclusionMode mode,
chaviw3277faf2021-05-19 16:45:23 -050010110 float alpha = 1.0f) {
Bernardo Rufinoc3b7b8c2021-01-29 17:38:07 +000010111 sp<FakeWindowHandle> window = getWindow(uid, name);
Prabir Pradhan4d5c52f2022-01-31 08:52:10 -080010112 window->setTouchable(false);
Bernardo Rufinoc3b7b8c2021-01-29 17:38:07 +000010113 window->setTouchOcclusionMode(mode);
Bernardo Rufino1d0d1f22021-02-12 15:08:43 +000010114 window->setAlpha(alpha);
Bernardo Rufinoc3b7b8c2021-01-29 17:38:07 +000010115 return window;
10116 }
10117
Prabir Pradhan8a5c41d2023-06-08 19:13:46 +000010118 sp<FakeWindowHandle> getWindow(gui::Uid uid, std::string name) {
Bernardo Rufinoc3b7b8c2021-01-29 17:38:07 +000010119 std::shared_ptr<FakeApplicationHandle> app = std::make_shared<FakeApplicationHandle>();
10120 sp<FakeWindowHandle> window =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -070010121 sp<FakeWindowHandle>::make(app, mDispatcher, name, ADISPLAY_ID_DEFAULT);
Bernardo Rufinoc3b7b8c2021-01-29 17:38:07 +000010122 // Generate an arbitrary PID based on the UID
Prabir Pradhanaeebeb42023-06-13 19:53:03 +000010123 window->setOwnerInfo(gui::Pid{static_cast<pid_t>(1777 + (uid.val() % 10000))}, uid);
Bernardo Rufinoc3b7b8c2021-01-29 17:38:07 +000010124 return window;
10125 }
10126
10127 void touch(const std::vector<PointF>& points = {PointF{100, 200}}) {
Prabir Pradhan678438e2023-04-13 19:32:51 +000010128 mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_DOWN,
10129 AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
10130 points));
Bernardo Rufinoc3b7b8c2021-01-29 17:38:07 +000010131 }
10132};
10133
10134TEST_F(InputDispatcherUntrustedTouchesTest, WindowWithBlockUntrustedOcclusionMode_BlocksTouch) {
Bernardo Rufino1d0d1f22021-02-12 15:08:43 +000010135 const sp<FakeWindowHandle>& w =
Bernardo Rufinoc3b7b8c2021-01-29 17:38:07 +000010136 getOccludingWindow(APP_B_UID, "B", TouchOcclusionMode::BLOCK_UNTRUSTED);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070010137 mDispatcher->onWindowInfosChanged({{*w->getInfo(), *mTouchWindow->getInfo()}, {}, 0, 0});
Bernardo Rufinoc3b7b8c2021-01-29 17:38:07 +000010138
10139 touch();
10140
10141 mTouchWindow->assertNoEvents();
10142}
10143
Bernardo Rufinoa43a5a42021-02-17 12:21:14 +000010144TEST_F(InputDispatcherUntrustedTouchesTest,
Bernardo Rufino7393d172021-02-26 13:56:11 +000010145 WindowWithBlockUntrustedOcclusionModeWithOpacityBelowThreshold_BlocksTouch) {
10146 const sp<FakeWindowHandle>& w =
10147 getOccludingWindow(APP_B_UID, "B", TouchOcclusionMode::BLOCK_UNTRUSTED, 0.7f);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070010148 mDispatcher->onWindowInfosChanged({{*w->getInfo(), *mTouchWindow->getInfo()}, {}, 0, 0});
Bernardo Rufino7393d172021-02-26 13:56:11 +000010149
10150 touch();
10151
10152 mTouchWindow->assertNoEvents();
10153}
10154
10155TEST_F(InputDispatcherUntrustedTouchesTest,
Bernardo Rufinoa43a5a42021-02-17 12:21:14 +000010156 WindowWithBlockUntrustedOcclusionMode_DoesNotReceiveTouch) {
10157 const sp<FakeWindowHandle>& w =
10158 getOccludingWindow(APP_B_UID, "B", TouchOcclusionMode::BLOCK_UNTRUSTED);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070010159 mDispatcher->onWindowInfosChanged({{*w->getInfo(), *mTouchWindow->getInfo()}, {}, 0, 0});
Bernardo Rufinoa43a5a42021-02-17 12:21:14 +000010160
10161 touch();
10162
10163 w->assertNoEvents();
10164}
10165
Bernardo Rufinoc3b7b8c2021-01-29 17:38:07 +000010166TEST_F(InputDispatcherUntrustedTouchesTest, WindowWithAllowOcclusionMode_AllowsTouch) {
Bernardo Rufino1d0d1f22021-02-12 15:08:43 +000010167 const sp<FakeWindowHandle>& w = getOccludingWindow(APP_B_UID, "B", TouchOcclusionMode::ALLOW);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070010168 mDispatcher->onWindowInfosChanged({{*w->getInfo(), *mTouchWindow->getInfo()}, {}, 0, 0});
Bernardo Rufinoc3b7b8c2021-01-29 17:38:07 +000010169
10170 touch();
10171
10172 mTouchWindow->consumeAnyMotionDown();
10173}
10174
10175TEST_F(InputDispatcherUntrustedTouchesTest, TouchOutsideOccludingWindow_AllowsTouch) {
Bernardo Rufino1d0d1f22021-02-12 15:08:43 +000010176 const sp<FakeWindowHandle>& w =
Bernardo Rufinoc3b7b8c2021-01-29 17:38:07 +000010177 getOccludingWindow(APP_B_UID, "B", TouchOcclusionMode::BLOCK_UNTRUSTED);
Bernardo Rufino1d0d1f22021-02-12 15:08:43 +000010178 w->setFrame(Rect(0, 0, 50, 50));
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070010179 mDispatcher->onWindowInfosChanged({{*w->getInfo(), *mTouchWindow->getInfo()}, {}, 0, 0});
Bernardo Rufinoc3b7b8c2021-01-29 17:38:07 +000010180
10181 touch({PointF{100, 100}});
10182
10183 mTouchWindow->consumeAnyMotionDown();
10184}
10185
10186TEST_F(InputDispatcherUntrustedTouchesTest, WindowFromSameUid_AllowsTouch) {
Bernardo Rufino1d0d1f22021-02-12 15:08:43 +000010187 const sp<FakeWindowHandle>& w =
Bernardo Rufino6d52e542021-02-15 18:38:10 +000010188 getOccludingWindow(TOUCHED_APP_UID, "A", TouchOcclusionMode::BLOCK_UNTRUSTED);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070010189 mDispatcher->onWindowInfosChanged({{*w->getInfo(), *mTouchWindow->getInfo()}, {}, 0, 0});
Bernardo Rufino1d0d1f22021-02-12 15:08:43 +000010190
10191 touch();
10192
10193 mTouchWindow->consumeAnyMotionDown();
10194}
10195
10196TEST_F(InputDispatcherUntrustedTouchesTest, WindowWithZeroOpacity_AllowsTouch) {
10197 const sp<FakeWindowHandle>& w =
10198 getOccludingWindow(APP_B_UID, "B", TouchOcclusionMode::BLOCK_UNTRUSTED, 0.0f);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070010199 mDispatcher->onWindowInfosChanged({{*w->getInfo(), *mTouchWindow->getInfo()}, {}, 0, 0});
Bernardo Rufinoc3b7b8c2021-01-29 17:38:07 +000010200
10201 touch();
10202
10203 mTouchWindow->consumeAnyMotionDown();
10204}
10205
Bernardo Rufinoa43a5a42021-02-17 12:21:14 +000010206TEST_F(InputDispatcherUntrustedTouchesTest, WindowWithZeroOpacity_DoesNotReceiveTouch) {
10207 const sp<FakeWindowHandle>& w =
10208 getOccludingWindow(APP_B_UID, "B", TouchOcclusionMode::BLOCK_UNTRUSTED, 0.0f);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070010209 mDispatcher->onWindowInfosChanged({{*w->getInfo(), *mTouchWindow->getInfo()}, {}, 0, 0});
Bernardo Rufinoa43a5a42021-02-17 12:21:14 +000010210
10211 touch();
10212
10213 w->assertNoEvents();
10214}
10215
10216/**
10217 * This is important to make sure apps can't indirectly learn the position of touches (outside vs
10218 * inside) while letting them pass-through. Note that even though touch passes through the occluding
10219 * window, the occluding window will still receive ACTION_OUTSIDE event.
10220 */
10221TEST_F(InputDispatcherUntrustedTouchesTest,
10222 WindowWithZeroOpacityAndWatchOutside_ReceivesOutsideEvent) {
10223 const sp<FakeWindowHandle>& w =
10224 getOccludingWindow(APP_B_UID, "B", TouchOcclusionMode::BLOCK_UNTRUSTED, 0.0f);
Prabir Pradhan4d5c52f2022-01-31 08:52:10 -080010225 w->setWatchOutsideTouch(true);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070010226 mDispatcher->onWindowInfosChanged({{*w->getInfo(), *mTouchWindow->getInfo()}, {}, 0, 0});
Bernardo Rufinoa43a5a42021-02-17 12:21:14 +000010227
10228 touch();
10229
10230 w->consumeMotionOutside();
10231}
10232
10233TEST_F(InputDispatcherUntrustedTouchesTest, OutsideEvent_HasZeroCoordinates) {
10234 const sp<FakeWindowHandle>& w =
10235 getOccludingWindow(APP_B_UID, "B", TouchOcclusionMode::BLOCK_UNTRUSTED, 0.0f);
Prabir Pradhan4d5c52f2022-01-31 08:52:10 -080010236 w->setWatchOutsideTouch(true);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070010237 mDispatcher->onWindowInfosChanged({{*w->getInfo(), *mTouchWindow->getInfo()}, {}, 0, 0});
Bernardo Rufinoa43a5a42021-02-17 12:21:14 +000010238
10239 touch();
10240
Prabir Pradhandfabf8a2022-01-21 08:19:30 -080010241 w->consumeMotionOutsideWithZeroedCoords();
Bernardo Rufinoa43a5a42021-02-17 12:21:14 +000010242}
10243
Bernardo Rufinoc3b7b8c2021-01-29 17:38:07 +000010244TEST_F(InputDispatcherUntrustedTouchesTest, WindowWithOpacityBelowThreshold_AllowsTouch) {
Bernardo Rufino1d0d1f22021-02-12 15:08:43 +000010245 const sp<FakeWindowHandle>& w =
Bernardo Rufino7393d172021-02-26 13:56:11 +000010246 getOccludingWindow(APP_B_UID, "B", TouchOcclusionMode::USE_OPACITY,
10247 OPACITY_BELOW_THRESHOLD);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070010248 mDispatcher->onWindowInfosChanged({{*w->getInfo(), *mTouchWindow->getInfo()}, {}, 0, 0});
Bernardo Rufino1d0d1f22021-02-12 15:08:43 +000010249
10250 touch();
10251
10252 mTouchWindow->consumeAnyMotionDown();
10253}
10254
10255TEST_F(InputDispatcherUntrustedTouchesTest, WindowWithOpacityAtThreshold_AllowsTouch) {
10256 const sp<FakeWindowHandle>& w =
10257 getOccludingWindow(APP_B_UID, "B", TouchOcclusionMode::USE_OPACITY,
10258 MAXIMUM_OBSCURING_OPACITY);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070010259 mDispatcher->onWindowInfosChanged({{*w->getInfo(), *mTouchWindow->getInfo()}, {}, 0, 0});
Bernardo Rufinoc3b7b8c2021-01-29 17:38:07 +000010260
10261 touch();
10262
10263 mTouchWindow->consumeAnyMotionDown();
10264}
10265
10266TEST_F(InputDispatcherUntrustedTouchesTest, WindowWithOpacityAboveThreshold_BlocksTouch) {
Bernardo Rufino1d0d1f22021-02-12 15:08:43 +000010267 const sp<FakeWindowHandle>& w =
Bernardo Rufino7393d172021-02-26 13:56:11 +000010268 getOccludingWindow(APP_B_UID, "B", TouchOcclusionMode::USE_OPACITY,
10269 OPACITY_ABOVE_THRESHOLD);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070010270 mDispatcher->onWindowInfosChanged({{*w->getInfo(), *mTouchWindow->getInfo()}, {}, 0, 0});
Bernardo Rufino1d0d1f22021-02-12 15:08:43 +000010271
10272 touch();
10273
10274 mTouchWindow->assertNoEvents();
10275}
10276
10277TEST_F(InputDispatcherUntrustedTouchesTest, WindowsWithCombinedOpacityAboveThreshold_BlocksTouch) {
10278 // Resulting opacity = 1 - (1 - 0.7)*(1 - 0.7) = .91
10279 const sp<FakeWindowHandle>& w1 =
Bernardo Rufino7393d172021-02-26 13:56:11 +000010280 getOccludingWindow(APP_B_UID, "B1", TouchOcclusionMode::USE_OPACITY,
10281 OPACITY_BELOW_THRESHOLD);
Bernardo Rufino1d0d1f22021-02-12 15:08:43 +000010282 const sp<FakeWindowHandle>& w2 =
Bernardo Rufino7393d172021-02-26 13:56:11 +000010283 getOccludingWindow(APP_B_UID, "B2", TouchOcclusionMode::USE_OPACITY,
10284 OPACITY_BELOW_THRESHOLD);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070010285 mDispatcher->onWindowInfosChanged(
10286 {{*w1->getInfo(), *w2->getInfo(), *mTouchWindow->getInfo()}, {}, 0, 0});
Bernardo Rufino1d0d1f22021-02-12 15:08:43 +000010287
10288 touch();
10289
10290 mTouchWindow->assertNoEvents();
10291}
10292
10293TEST_F(InputDispatcherUntrustedTouchesTest, WindowsWithCombinedOpacityBelowThreshold_AllowsTouch) {
10294 // Resulting opacity = 1 - (1 - 0.5)*(1 - 0.5) = .75
10295 const sp<FakeWindowHandle>& w1 =
Bernardo Rufino7393d172021-02-26 13:56:11 +000010296 getOccludingWindow(APP_B_UID, "B1", TouchOcclusionMode::USE_OPACITY,
10297 OPACITY_FAR_BELOW_THRESHOLD);
Bernardo Rufino1d0d1f22021-02-12 15:08:43 +000010298 const sp<FakeWindowHandle>& w2 =
Bernardo Rufino7393d172021-02-26 13:56:11 +000010299 getOccludingWindow(APP_B_UID, "B2", TouchOcclusionMode::USE_OPACITY,
10300 OPACITY_FAR_BELOW_THRESHOLD);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070010301 mDispatcher->onWindowInfosChanged(
10302 {{*w1->getInfo(), *w2->getInfo(), *mTouchWindow->getInfo()}, {}, 0, 0});
Bernardo Rufino1d0d1f22021-02-12 15:08:43 +000010303
10304 touch();
10305
10306 mTouchWindow->consumeAnyMotionDown();
10307}
10308
10309TEST_F(InputDispatcherUntrustedTouchesTest,
10310 WindowsFromDifferentAppsEachBelowThreshold_AllowsTouch) {
10311 const sp<FakeWindowHandle>& wB =
Bernardo Rufino7393d172021-02-26 13:56:11 +000010312 getOccludingWindow(APP_B_UID, "B", TouchOcclusionMode::USE_OPACITY,
10313 OPACITY_BELOW_THRESHOLD);
Bernardo Rufino1d0d1f22021-02-12 15:08:43 +000010314 const sp<FakeWindowHandle>& wC =
Bernardo Rufino7393d172021-02-26 13:56:11 +000010315 getOccludingWindow(APP_C_UID, "C", TouchOcclusionMode::USE_OPACITY,
10316 OPACITY_BELOW_THRESHOLD);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070010317 mDispatcher->onWindowInfosChanged(
10318 {{*wB->getInfo(), *wC->getInfo(), *mTouchWindow->getInfo()}, {}, 0, 0});
Bernardo Rufino1d0d1f22021-02-12 15:08:43 +000010319
10320 touch();
10321
10322 mTouchWindow->consumeAnyMotionDown();
10323}
10324
10325TEST_F(InputDispatcherUntrustedTouchesTest, WindowsFromDifferentAppsOneAboveThreshold_BlocksTouch) {
10326 const sp<FakeWindowHandle>& wB =
Bernardo Rufino7393d172021-02-26 13:56:11 +000010327 getOccludingWindow(APP_B_UID, "B", TouchOcclusionMode::USE_OPACITY,
10328 OPACITY_BELOW_THRESHOLD);
Bernardo Rufino1d0d1f22021-02-12 15:08:43 +000010329 const sp<FakeWindowHandle>& wC =
Bernardo Rufino7393d172021-02-26 13:56:11 +000010330 getOccludingWindow(APP_C_UID, "C", TouchOcclusionMode::USE_OPACITY,
10331 OPACITY_ABOVE_THRESHOLD);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070010332 mDispatcher->onWindowInfosChanged(
10333 {{*wB->getInfo(), *wC->getInfo(), *mTouchWindow->getInfo()}, {}, 0, 0});
Bernardo Rufinoc3b7b8c2021-01-29 17:38:07 +000010334
10335 touch();
10336
10337 mTouchWindow->assertNoEvents();
10338}
10339
Bernardo Rufino6d52e542021-02-15 18:38:10 +000010340TEST_F(InputDispatcherUntrustedTouchesTest,
10341 WindowWithOpacityAboveThresholdAndSelfWindow_BlocksTouch) {
10342 const sp<FakeWindowHandle>& wA =
Bernardo Rufino7393d172021-02-26 13:56:11 +000010343 getOccludingWindow(TOUCHED_APP_UID, "T", TouchOcclusionMode::USE_OPACITY,
10344 OPACITY_BELOW_THRESHOLD);
Bernardo Rufino6d52e542021-02-15 18:38:10 +000010345 const sp<FakeWindowHandle>& wB =
Bernardo Rufino7393d172021-02-26 13:56:11 +000010346 getOccludingWindow(APP_B_UID, "B", TouchOcclusionMode::USE_OPACITY,
10347 OPACITY_ABOVE_THRESHOLD);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070010348 mDispatcher->onWindowInfosChanged(
10349 {{*wA->getInfo(), *wB->getInfo(), *mTouchWindow->getInfo()}, {}, 0, 0});
Bernardo Rufino6d52e542021-02-15 18:38:10 +000010350
10351 touch();
10352
10353 mTouchWindow->assertNoEvents();
10354}
10355
10356TEST_F(InputDispatcherUntrustedTouchesTest,
10357 WindowWithOpacityBelowThresholdAndSelfWindow_AllowsTouch) {
10358 const sp<FakeWindowHandle>& wA =
Bernardo Rufino7393d172021-02-26 13:56:11 +000010359 getOccludingWindow(TOUCHED_APP_UID, "T", TouchOcclusionMode::USE_OPACITY,
10360 OPACITY_ABOVE_THRESHOLD);
Bernardo Rufino6d52e542021-02-15 18:38:10 +000010361 const sp<FakeWindowHandle>& wB =
Bernardo Rufino7393d172021-02-26 13:56:11 +000010362 getOccludingWindow(APP_B_UID, "B", TouchOcclusionMode::USE_OPACITY,
10363 OPACITY_BELOW_THRESHOLD);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070010364 mDispatcher->onWindowInfosChanged(
10365 {{*wA->getInfo(), *wB->getInfo(), *mTouchWindow->getInfo()}, {}, 0, 0});
Bernardo Rufino6d52e542021-02-15 18:38:10 +000010366
10367 touch();
10368
10369 mTouchWindow->consumeAnyMotionDown();
10370}
10371
10372TEST_F(InputDispatcherUntrustedTouchesTest, SelfWindowWithOpacityAboveThreshold_AllowsTouch) {
10373 const sp<FakeWindowHandle>& w =
Bernardo Rufino7393d172021-02-26 13:56:11 +000010374 getOccludingWindow(TOUCHED_APP_UID, "T", TouchOcclusionMode::USE_OPACITY,
10375 OPACITY_ABOVE_THRESHOLD);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070010376 mDispatcher->onWindowInfosChanged({{*w->getInfo(), *mTouchWindow->getInfo()}, {}, 0, 0});
Bernardo Rufino6d52e542021-02-15 18:38:10 +000010377
10378 touch();
10379
10380 mTouchWindow->consumeAnyMotionDown();
10381}
10382
10383TEST_F(InputDispatcherUntrustedTouchesTest, SelfWindowWithBlockUntrustedMode_AllowsTouch) {
10384 const sp<FakeWindowHandle>& w =
10385 getOccludingWindow(TOUCHED_APP_UID, "T", TouchOcclusionMode::BLOCK_UNTRUSTED);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070010386 mDispatcher->onWindowInfosChanged({{*w->getInfo(), *mTouchWindow->getInfo()}, {}, 0, 0});
Bernardo Rufino6d52e542021-02-15 18:38:10 +000010387
10388 touch();
10389
10390 mTouchWindow->consumeAnyMotionDown();
10391}
10392
Bernardo Rufinoccd3dd62021-02-15 18:47:42 +000010393TEST_F(InputDispatcherUntrustedTouchesTest,
10394 OpacityThresholdIs0AndWindowAboveThreshold_BlocksTouch) {
10395 mDispatcher->setMaximumObscuringOpacityForTouch(0.0f);
10396 const sp<FakeWindowHandle>& w =
10397 getOccludingWindow(APP_B_UID, "B", TouchOcclusionMode::USE_OPACITY, 0.1f);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070010398 mDispatcher->onWindowInfosChanged({{*w->getInfo(), *mTouchWindow->getInfo()}, {}, 0, 0});
Bernardo Rufinoccd3dd62021-02-15 18:47:42 +000010399
10400 touch();
10401
10402 mTouchWindow->assertNoEvents();
10403}
10404
10405TEST_F(InputDispatcherUntrustedTouchesTest, OpacityThresholdIs0AndWindowAtThreshold_AllowsTouch) {
10406 mDispatcher->setMaximumObscuringOpacityForTouch(0.0f);
10407 const sp<FakeWindowHandle>& w =
10408 getOccludingWindow(APP_B_UID, "B", TouchOcclusionMode::USE_OPACITY, 0.0f);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070010409 mDispatcher->onWindowInfosChanged({{*w->getInfo(), *mTouchWindow->getInfo()}, {}, 0, 0});
Bernardo Rufinoccd3dd62021-02-15 18:47:42 +000010410
10411 touch();
10412
10413 mTouchWindow->consumeAnyMotionDown();
10414}
10415
10416TEST_F(InputDispatcherUntrustedTouchesTest,
10417 OpacityThresholdIs1AndWindowBelowThreshold_AllowsTouch) {
10418 mDispatcher->setMaximumObscuringOpacityForTouch(1.0f);
10419 const sp<FakeWindowHandle>& w =
Bernardo Rufino7393d172021-02-26 13:56:11 +000010420 getOccludingWindow(APP_B_UID, "B", TouchOcclusionMode::USE_OPACITY,
10421 OPACITY_ABOVE_THRESHOLD);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070010422 mDispatcher->onWindowInfosChanged({{*w->getInfo(), *mTouchWindow->getInfo()}, {}, 0, 0});
Bernardo Rufino7393d172021-02-26 13:56:11 +000010423
10424 touch();
10425
10426 mTouchWindow->consumeAnyMotionDown();
10427}
10428
10429TEST_F(InputDispatcherUntrustedTouchesTest,
10430 WindowWithBlockUntrustedModeAndWindowWithOpacityBelowFromSameApp_BlocksTouch) {
10431 const sp<FakeWindowHandle>& w1 =
10432 getOccludingWindow(APP_B_UID, "B", TouchOcclusionMode::BLOCK_UNTRUSTED,
10433 OPACITY_BELOW_THRESHOLD);
10434 const sp<FakeWindowHandle>& w2 =
10435 getOccludingWindow(APP_B_UID, "B", TouchOcclusionMode::USE_OPACITY,
10436 OPACITY_BELOW_THRESHOLD);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070010437 mDispatcher->onWindowInfosChanged(
10438 {{*w1->getInfo(), *w2->getInfo(), *mTouchWindow->getInfo()}, {}, 0, 0});
Bernardo Rufino7393d172021-02-26 13:56:11 +000010439
10440 touch();
10441
10442 mTouchWindow->assertNoEvents();
10443}
10444
10445/**
10446 * Window B of BLOCK_UNTRUSTED occlusion mode is enough to block the touch, we're testing that the
10447 * addition of another window (C) of USE_OPACITY occlusion mode and opacity below the threshold
10448 * (which alone would result in allowing touches) does not affect the blocking behavior.
10449 */
10450TEST_F(InputDispatcherUntrustedTouchesTest,
10451 WindowWithBlockUntrustedModeAndWindowWithOpacityBelowFromDifferentApps_BlocksTouch) {
10452 const sp<FakeWindowHandle>& wB =
10453 getOccludingWindow(APP_B_UID, "B", TouchOcclusionMode::BLOCK_UNTRUSTED,
10454 OPACITY_BELOW_THRESHOLD);
10455 const sp<FakeWindowHandle>& wC =
10456 getOccludingWindow(APP_C_UID, "C", TouchOcclusionMode::USE_OPACITY,
10457 OPACITY_BELOW_THRESHOLD);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070010458 mDispatcher->onWindowInfosChanged(
10459 {{*wB->getInfo(), *wC->getInfo(), *mTouchWindow->getInfo()}, {}, 0, 0});
Bernardo Rufino7393d172021-02-26 13:56:11 +000010460
10461 touch();
10462
10463 mTouchWindow->assertNoEvents();
10464}
10465
10466/**
10467 * This test is testing that a window from a different UID but with same application token doesn't
10468 * block the touch. Apps can share the application token for close UI collaboration for example.
10469 */
10470TEST_F(InputDispatcherUntrustedTouchesTest,
10471 WindowWithSameApplicationTokenFromDifferentApp_AllowsTouch) {
10472 const sp<FakeWindowHandle>& w =
10473 getOccludingWindow(APP_B_UID, "B", TouchOcclusionMode::BLOCK_UNTRUSTED);
10474 w->setApplicationToken(mTouchWindow->getApplicationToken());
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070010475 mDispatcher->onWindowInfosChanged({{*w->getInfo(), *mTouchWindow->getInfo()}, {}, 0, 0});
Bernardo Rufinoccd3dd62021-02-15 18:47:42 +000010476
10477 touch();
10478
10479 mTouchWindow->consumeAnyMotionDown();
10480}
10481
arthurhungb89ccb02020-12-30 16:19:01 +080010482class InputDispatcherDragTests : public InputDispatcherTest {
10483protected:
10484 std::shared_ptr<FakeApplicationHandle> mApp;
10485 sp<FakeWindowHandle> mWindow;
10486 sp<FakeWindowHandle> mSecondWindow;
10487 sp<FakeWindowHandle> mDragWindow;
Vaibhav Devmurari6abcf8f2022-06-06 10:08:05 +000010488 sp<FakeWindowHandle> mSpyWindow;
Arthur Hungb75c2aa2022-07-15 09:35:36 +000010489 // Mouse would force no-split, set the id as non-zero to verify if drag state could track it.
10490 static constexpr int32_t MOUSE_POINTER_ID = 1;
arthurhungb89ccb02020-12-30 16:19:01 +080010491
10492 void SetUp() override {
10493 InputDispatcherTest::SetUp();
10494 mApp = std::make_shared<FakeApplicationHandle>();
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -070010495 mWindow = sp<FakeWindowHandle>::make(mApp, mDispatcher, "TestWindow", ADISPLAY_ID_DEFAULT);
arthurhungb89ccb02020-12-30 16:19:01 +080010496 mWindow->setFrame(Rect(0, 0, 100, 100));
arthurhungb89ccb02020-12-30 16:19:01 +080010497
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -070010498 mSecondWindow =
10499 sp<FakeWindowHandle>::make(mApp, mDispatcher, "TestWindow2", ADISPLAY_ID_DEFAULT);
arthurhungb89ccb02020-12-30 16:19:01 +080010500 mSecondWindow->setFrame(Rect(100, 0, 200, 100));
arthurhungb89ccb02020-12-30 16:19:01 +080010501
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -070010502 mSpyWindow =
10503 sp<FakeWindowHandle>::make(mApp, mDispatcher, "SpyWindow", ADISPLAY_ID_DEFAULT);
Vaibhav Devmurari6abcf8f2022-06-06 10:08:05 +000010504 mSpyWindow->setSpy(true);
10505 mSpyWindow->setTrustedOverlay(true);
10506 mSpyWindow->setFrame(Rect(0, 0, 200, 100));
10507
arthurhungb89ccb02020-12-30 16:19:01 +080010508 mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, mApp);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070010509 mDispatcher->onWindowInfosChanged(
10510 {{*mSpyWindow->getInfo(), *mWindow->getInfo(), *mSecondWindow->getInfo()},
10511 {},
10512 0,
10513 0});
arthurhungb89ccb02020-12-30 16:19:01 +080010514 }
10515
Arthur Hungb75c2aa2022-07-15 09:35:36 +000010516 void injectDown(int fromSource = AINPUT_SOURCE_TOUCHSCREEN) {
10517 switch (fromSource) {
10518 case AINPUT_SOURCE_TOUCHSCREEN:
10519 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070010520 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN,
Arthur Hungb75c2aa2022-07-15 09:35:36 +000010521 ADISPLAY_ID_DEFAULT, {50, 50}))
10522 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
10523 break;
10524 case AINPUT_SOURCE_STYLUS:
10525 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070010526 injectMotionEvent(*mDispatcher,
10527 MotionEventBuilder(AMOTION_EVENT_ACTION_DOWN,
10528 AINPUT_SOURCE_STYLUS)
10529 .buttonState(
10530 AMOTION_EVENT_BUTTON_STYLUS_PRIMARY)
10531 .pointer(PointerBuilder(0, ToolType::STYLUS)
10532 .x(50)
10533 .y(50))
10534 .build()));
Arthur Hungb75c2aa2022-07-15 09:35:36 +000010535 break;
10536 case AINPUT_SOURCE_MOUSE:
10537 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070010538 injectMotionEvent(*mDispatcher,
10539 MotionEventBuilder(AMOTION_EVENT_ACTION_DOWN,
10540 AINPUT_SOURCE_MOUSE)
10541 .buttonState(AMOTION_EVENT_BUTTON_PRIMARY)
10542 .pointer(PointerBuilder(MOUSE_POINTER_ID,
10543 ToolType::MOUSE)
10544 .x(50)
10545 .y(50))
10546 .build()));
Arthur Hungb75c2aa2022-07-15 09:35:36 +000010547 break;
10548 default:
10549 FAIL() << "Source " << fromSource << " doesn't support drag and drop";
10550 }
arthurhungb89ccb02020-12-30 16:19:01 +080010551
10552 // Window should receive motion event.
10553 mWindow->consumeMotionDown(ADISPLAY_ID_DEFAULT);
Vaibhav Devmurari6abcf8f2022-06-06 10:08:05 +000010554 // Spy window should also receive motion event
10555 mSpyWindow->consumeMotionDown(ADISPLAY_ID_DEFAULT);
Arthur Hung54745652022-04-20 07:17:41 +000010556 }
10557
10558 // Start performing drag, we will create a drag window and transfer touch to it.
10559 // @param sendDown : if true, send a motion down on first window before perform drag and drop.
10560 // Returns true on success.
Arthur Hungb75c2aa2022-07-15 09:35:36 +000010561 bool startDrag(bool sendDown = true, int fromSource = AINPUT_SOURCE_TOUCHSCREEN) {
Arthur Hung54745652022-04-20 07:17:41 +000010562 if (sendDown) {
Arthur Hungb75c2aa2022-07-15 09:35:36 +000010563 injectDown(fromSource);
Arthur Hung54745652022-04-20 07:17:41 +000010564 }
arthurhungb89ccb02020-12-30 16:19:01 +080010565
10566 // The drag window covers the entire display
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -070010567 mDragWindow =
10568 sp<FakeWindowHandle>::make(mApp, mDispatcher, "DragWindow", ADISPLAY_ID_DEFAULT);
Vaibhav Devmurari6abcf8f2022-06-06 10:08:05 +000010569 mDragWindow->setTouchableRegion(Region{{0, 0, 0, 0}});
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070010570 mDispatcher->onWindowInfosChanged({{*mDragWindow->getInfo(), *mSpyWindow->getInfo(),
10571 *mWindow->getInfo(), *mSecondWindow->getInfo()},
10572 {},
10573 0,
10574 0});
arthurhungb89ccb02020-12-30 16:19:01 +080010575
10576 // Transfer touch focus to the drag window
Arthur Hung54745652022-04-20 07:17:41 +000010577 bool transferred =
Prabir Pradhan367f3432024-02-13 23:05:58 +000010578 mDispatcher->transferTouchGesture(mWindow->getToken(), mDragWindow->getToken(),
10579 /*isDragDrop=*/true);
Arthur Hung54745652022-04-20 07:17:41 +000010580 if (transferred) {
10581 mWindow->consumeMotionCancel();
Prabir Pradhan65455c72024-02-13 21:46:41 +000010582 mDragWindow->consumeMotionDown(ADISPLAY_ID_DEFAULT, AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
Arthur Hung54745652022-04-20 07:17:41 +000010583 }
10584 return transferred;
arthurhungb89ccb02020-12-30 16:19:01 +080010585 }
10586};
10587
10588TEST_F(InputDispatcherDragTests, DragEnterAndDragExit) {
Arthur Hungb75c2aa2022-07-15 09:35:36 +000010589 startDrag();
arthurhungb89ccb02020-12-30 16:19:01 +080010590
10591 // Move on window.
10592 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070010593 injectMotionEvent(*mDispatcher, AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN,
arthurhungb89ccb02020-12-30 16:19:01 +080010594 ADISPLAY_ID_DEFAULT, {50, 50}))
10595 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
Prabir Pradhan65455c72024-02-13 21:46:41 +000010596 mDragWindow->consumeMotionMove(ADISPLAY_ID_DEFAULT, AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
arthurhungb89ccb02020-12-30 16:19:01 +080010597 mWindow->consumeDragEvent(false, 50, 50);
10598 mSecondWindow->assertNoEvents();
10599
10600 // Move to another window.
10601 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070010602 injectMotionEvent(*mDispatcher, AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN,
arthurhungb89ccb02020-12-30 16:19:01 +080010603 ADISPLAY_ID_DEFAULT, {150, 50}))
10604 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
Prabir Pradhan65455c72024-02-13 21:46:41 +000010605 mDragWindow->consumeMotionMove(ADISPLAY_ID_DEFAULT, AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
arthurhungb89ccb02020-12-30 16:19:01 +080010606 mWindow->consumeDragEvent(true, 150, 50);
10607 mSecondWindow->consumeDragEvent(false, 50, 50);
10608
10609 // Move back to original window.
10610 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070010611 injectMotionEvent(*mDispatcher, AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN,
arthurhungb89ccb02020-12-30 16:19:01 +080010612 ADISPLAY_ID_DEFAULT, {50, 50}))
10613 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
Prabir Pradhan65455c72024-02-13 21:46:41 +000010614 mDragWindow->consumeMotionMove(ADISPLAY_ID_DEFAULT, AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
arthurhungb89ccb02020-12-30 16:19:01 +080010615 mWindow->consumeDragEvent(false, 50, 50);
10616 mSecondWindow->consumeDragEvent(true, -50, 50);
10617
10618 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070010619 injectMotionUp(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
10620 {50, 50}))
arthurhungb89ccb02020-12-30 16:19:01 +080010621 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
Prabir Pradhan65455c72024-02-13 21:46:41 +000010622 mDragWindow->consumeMotionUp(ADISPLAY_ID_DEFAULT, AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
arthurhungb89ccb02020-12-30 16:19:01 +080010623 mWindow->assertNoEvents();
10624 mSecondWindow->assertNoEvents();
10625}
10626
Vaibhav Devmurari6abcf8f2022-06-06 10:08:05 +000010627TEST_F(InputDispatcherDragTests, DragEnterAndPointerDownPilfersPointers) {
Arthur Hungb75c2aa2022-07-15 09:35:36 +000010628 startDrag();
Vaibhav Devmurari6abcf8f2022-06-06 10:08:05 +000010629
10630 // No cancel event after drag start
10631 mSpyWindow->assertNoEvents();
10632
10633 const MotionEvent secondFingerDownEvent =
10634 MotionEventBuilder(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
10635 .eventTime(systemTime(SYSTEM_TIME_MONOTONIC))
Siarhei Vishniakou6d73f832022-07-21 17:27:03 -070010636 .pointer(PointerBuilder(/*id=*/0, ToolType::FINGER).x(50).y(50))
10637 .pointer(PointerBuilder(/*id=*/1, ToolType::FINGER).x(60).y(60))
Vaibhav Devmurari6abcf8f2022-06-06 10:08:05 +000010638 .build();
10639 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070010640 injectMotionEvent(*mDispatcher, secondFingerDownEvent, INJECT_EVENT_TIMEOUT,
Vaibhav Devmurari6abcf8f2022-06-06 10:08:05 +000010641 InputEventInjectionSync::WAIT_FOR_RESULT))
10642 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
10643
10644 // Receives cancel for first pointer after next pointer down
10645 mSpyWindow->consumeMotionCancel();
10646 mSpyWindow->consumeMotionDown();
10647
10648 mSpyWindow->assertNoEvents();
10649}
10650
arthurhungf452d0b2021-01-06 00:19:52 +080010651TEST_F(InputDispatcherDragTests, DragAndDrop) {
Arthur Hungb75c2aa2022-07-15 09:35:36 +000010652 startDrag();
arthurhungf452d0b2021-01-06 00:19:52 +080010653
10654 // Move on window.
10655 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070010656 injectMotionEvent(*mDispatcher, AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN,
arthurhungf452d0b2021-01-06 00:19:52 +080010657 ADISPLAY_ID_DEFAULT, {50, 50}))
10658 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
Prabir Pradhan65455c72024-02-13 21:46:41 +000010659 mDragWindow->consumeMotionMove(ADISPLAY_ID_DEFAULT, AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
arthurhungf452d0b2021-01-06 00:19:52 +080010660 mWindow->consumeDragEvent(false, 50, 50);
10661 mSecondWindow->assertNoEvents();
10662
10663 // Move to another window.
10664 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070010665 injectMotionEvent(*mDispatcher, AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN,
arthurhungf452d0b2021-01-06 00:19:52 +080010666 ADISPLAY_ID_DEFAULT, {150, 50}))
10667 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
Prabir Pradhan65455c72024-02-13 21:46:41 +000010668 mDragWindow->consumeMotionMove(ADISPLAY_ID_DEFAULT, AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
arthurhungf452d0b2021-01-06 00:19:52 +080010669 mWindow->consumeDragEvent(true, 150, 50);
10670 mSecondWindow->consumeDragEvent(false, 50, 50);
10671
10672 // drop to another window.
10673 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070010674 injectMotionUp(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
arthurhungf452d0b2021-01-06 00:19:52 +080010675 {150, 50}))
10676 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
Prabir Pradhan65455c72024-02-13 21:46:41 +000010677 mDragWindow->consumeMotionUp(ADISPLAY_ID_DEFAULT, AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
Siarhei Vishniakoua66d65e2023-06-16 10:32:51 -070010678 mFakePolicy->assertDropTargetEquals(*mDispatcher, mSecondWindow->getToken());
arthurhungf452d0b2021-01-06 00:19:52 +080010679 mWindow->assertNoEvents();
10680 mSecondWindow->assertNoEvents();
10681}
10682
Vaibhav Devmurari110ba322023-11-17 10:47:16 +000010683TEST_F(InputDispatcherDragTests, DragAndDropNotCancelledIfSomeOtherPointerIsPilfered) {
10684 startDrag();
10685
10686 // No cancel event after drag start
10687 mSpyWindow->assertNoEvents();
10688
10689 const MotionEvent secondFingerDownEvent =
10690 MotionEventBuilder(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
10691 .eventTime(systemTime(SYSTEM_TIME_MONOTONIC))
10692 .pointer(PointerBuilder(/*id=*/0, ToolType::FINGER).x(50).y(50))
10693 .pointer(PointerBuilder(/*id=*/1, ToolType::FINGER).x(60).y(60))
10694 .build();
10695 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
10696 injectMotionEvent(*mDispatcher, secondFingerDownEvent, INJECT_EVENT_TIMEOUT,
10697 InputEventInjectionSync::WAIT_FOR_RESULT))
10698 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
10699
10700 // Receives cancel for first pointer after next pointer down
10701 mSpyWindow->consumeMotionEvent(WithMotionAction(ACTION_CANCEL));
Siarhei Vishniakou1ff00cc2023-12-13 16:12:13 -080010702 mSpyWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithPointerIds({1})));
Vaibhav Devmurari110ba322023-11-17 10:47:16 +000010703 mDragWindow->consumeMotionEvent(WithMotionAction(ACTION_MOVE));
10704
10705 mSpyWindow->assertNoEvents();
10706
10707 // Spy window calls pilfer pointers
10708 EXPECT_EQ(OK, mDispatcher->pilferPointers(mSpyWindow->getToken()));
10709 mDragWindow->assertNoEvents();
10710
10711 const MotionEvent firstFingerMoveEvent =
Siarhei Vishniakou96a15572023-12-18 10:47:52 -080010712 MotionEventBuilder(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN)
Vaibhav Devmurari110ba322023-11-17 10:47:16 +000010713 .eventTime(systemTime(SYSTEM_TIME_MONOTONIC))
10714 .pointer(PointerBuilder(/*id=*/0, ToolType::FINGER).x(60).y(60))
10715 .pointer(PointerBuilder(/*id=*/1, ToolType::FINGER).x(60).y(60))
10716 .build();
10717 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakou96a15572023-12-18 10:47:52 -080010718 injectMotionEvent(*mDispatcher, firstFingerMoveEvent, INJECT_EVENT_TIMEOUT,
Vaibhav Devmurari110ba322023-11-17 10:47:16 +000010719 InputEventInjectionSync::WAIT_FOR_RESULT))
10720 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
10721
10722 // Drag window should still receive the new event
Prabir Pradhan65455c72024-02-13 21:46:41 +000010723 mDragWindow->consumeMotionEvent(
10724 AllOf(WithMotionAction(ACTION_MOVE), WithFlags(AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE)));
Vaibhav Devmurari110ba322023-11-17 10:47:16 +000010725 mDragWindow->assertNoEvents();
10726}
10727
arthurhung6d4bed92021-03-17 11:59:33 +080010728TEST_F(InputDispatcherDragTests, StylusDragAndDrop) {
Arthur Hungb75c2aa2022-07-15 09:35:36 +000010729 startDrag(true, AINPUT_SOURCE_STYLUS);
arthurhung6d4bed92021-03-17 11:59:33 +080010730
10731 // Move on window and keep button pressed.
10732 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070010733 injectMotionEvent(*mDispatcher,
arthurhung6d4bed92021-03-17 11:59:33 +080010734 MotionEventBuilder(AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_STYLUS)
10735 .buttonState(AMOTION_EVENT_BUTTON_STYLUS_PRIMARY)
Siarhei Vishniakou6d73f832022-07-21 17:27:03 -070010736 .pointer(PointerBuilder(0, ToolType::STYLUS).x(50).y(50))
arthurhung6d4bed92021-03-17 11:59:33 +080010737 .build()))
10738 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
Prabir Pradhan65455c72024-02-13 21:46:41 +000010739 mDragWindow->consumeMotionMove(ADISPLAY_ID_DEFAULT, AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
arthurhung6d4bed92021-03-17 11:59:33 +080010740 mWindow->consumeDragEvent(false, 50, 50);
10741 mSecondWindow->assertNoEvents();
10742
10743 // Move to another window and release button, expect to drop item.
10744 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070010745 injectMotionEvent(*mDispatcher,
arthurhung6d4bed92021-03-17 11:59:33 +080010746 MotionEventBuilder(AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_STYLUS)
10747 .buttonState(0)
Siarhei Vishniakou6d73f832022-07-21 17:27:03 -070010748 .pointer(PointerBuilder(0, ToolType::STYLUS).x(150).y(50))
arthurhung6d4bed92021-03-17 11:59:33 +080010749 .build()))
10750 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
Prabir Pradhan65455c72024-02-13 21:46:41 +000010751 mDragWindow->consumeMotionMove(ADISPLAY_ID_DEFAULT, AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
arthurhung6d4bed92021-03-17 11:59:33 +080010752 mWindow->assertNoEvents();
10753 mSecondWindow->assertNoEvents();
Siarhei Vishniakoua66d65e2023-06-16 10:32:51 -070010754 mFakePolicy->assertDropTargetEquals(*mDispatcher, mSecondWindow->getToken());
arthurhung6d4bed92021-03-17 11:59:33 +080010755
10756 // nothing to the window.
10757 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070010758 injectMotionEvent(*mDispatcher,
arthurhung6d4bed92021-03-17 11:59:33 +080010759 MotionEventBuilder(AMOTION_EVENT_ACTION_UP, AINPUT_SOURCE_STYLUS)
10760 .buttonState(0)
Siarhei Vishniakou6d73f832022-07-21 17:27:03 -070010761 .pointer(PointerBuilder(0, ToolType::STYLUS).x(150).y(50))
arthurhung6d4bed92021-03-17 11:59:33 +080010762 .build()))
10763 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
Prabir Pradhan65455c72024-02-13 21:46:41 +000010764 mDragWindow->consumeMotionUp(ADISPLAY_ID_DEFAULT, AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
arthurhung6d4bed92021-03-17 11:59:33 +080010765 mWindow->assertNoEvents();
10766 mSecondWindow->assertNoEvents();
10767}
10768
Arthur Hung54745652022-04-20 07:17:41 +000010769TEST_F(InputDispatcherDragTests, DragAndDropOnInvalidWindow) {
Arthur Hungb75c2aa2022-07-15 09:35:36 +000010770 startDrag();
Arthur Hung6d0571e2021-04-09 20:18:16 +080010771
10772 // Set second window invisible.
10773 mSecondWindow->setVisible(false);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070010774 mDispatcher->onWindowInfosChanged(
10775 {{*mDragWindow->getInfo(), *mWindow->getInfo(), *mSecondWindow->getInfo()}, {}, 0, 0});
Arthur Hung6d0571e2021-04-09 20:18:16 +080010776
10777 // Move on window.
10778 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070010779 injectMotionEvent(*mDispatcher, AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN,
Arthur Hung6d0571e2021-04-09 20:18:16 +080010780 ADISPLAY_ID_DEFAULT, {50, 50}))
10781 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
Prabir Pradhan65455c72024-02-13 21:46:41 +000010782 mDragWindow->consumeMotionMove(ADISPLAY_ID_DEFAULT, AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
Arthur Hung6d0571e2021-04-09 20:18:16 +080010783 mWindow->consumeDragEvent(false, 50, 50);
10784 mSecondWindow->assertNoEvents();
10785
10786 // Move to another window.
10787 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070010788 injectMotionEvent(*mDispatcher, AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN,
Arthur Hung6d0571e2021-04-09 20:18:16 +080010789 ADISPLAY_ID_DEFAULT, {150, 50}))
10790 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
Prabir Pradhan65455c72024-02-13 21:46:41 +000010791 mDragWindow->consumeMotionMove(ADISPLAY_ID_DEFAULT, AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
Arthur Hung6d0571e2021-04-09 20:18:16 +080010792 mWindow->consumeDragEvent(true, 150, 50);
10793 mSecondWindow->assertNoEvents();
10794
10795 // drop to another window.
10796 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070010797 injectMotionUp(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
Arthur Hung6d0571e2021-04-09 20:18:16 +080010798 {150, 50}))
10799 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
Prabir Pradhan65455c72024-02-13 21:46:41 +000010800 mDragWindow->consumeMotionUp(ADISPLAY_ID_DEFAULT, AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
Siarhei Vishniakoua66d65e2023-06-16 10:32:51 -070010801 mFakePolicy->assertDropTargetEquals(*mDispatcher, nullptr);
Arthur Hung6d0571e2021-04-09 20:18:16 +080010802 mWindow->assertNoEvents();
10803 mSecondWindow->assertNoEvents();
10804}
10805
Arthur Hung54745652022-04-20 07:17:41 +000010806TEST_F(InputDispatcherDragTests, NoDragAndDropWhenMultiFingers) {
Arthur Hungb75c2aa2022-07-15 09:35:36 +000010807 // Ensure window could track pointerIds if it didn't support split touch.
10808 mWindow->setPreventSplitting(true);
10809
Arthur Hung54745652022-04-20 07:17:41 +000010810 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070010811 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
Arthur Hung54745652022-04-20 07:17:41 +000010812 {50, 50}))
10813 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
10814 mWindow->consumeMotionDown(ADISPLAY_ID_DEFAULT);
10815
10816 const MotionEvent secondFingerDownEvent =
10817 MotionEventBuilder(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
10818 .displayId(ADISPLAY_ID_DEFAULT)
10819 .eventTime(systemTime(SYSTEM_TIME_MONOTONIC))
Siarhei Vishniakou6d73f832022-07-21 17:27:03 -070010820 .pointer(PointerBuilder(/*id=*/0, ToolType::FINGER).x(50).y(50))
10821 .pointer(PointerBuilder(/*id=*/1, ToolType::FINGER).x(75).y(50))
Arthur Hung54745652022-04-20 07:17:41 +000010822 .build();
10823 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070010824 injectMotionEvent(*mDispatcher, secondFingerDownEvent, INJECT_EVENT_TIMEOUT,
Arthur Hung54745652022-04-20 07:17:41 +000010825 InputEventInjectionSync::WAIT_FOR_RESULT))
10826 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
Harry Cutts33476232023-01-30 19:57:29 +000010827 mWindow->consumeMotionPointerDown(/*pointerIndex=*/1);
Arthur Hung54745652022-04-20 07:17:41 +000010828
10829 // Should not perform drag and drop when window has multi fingers.
Arthur Hungb75c2aa2022-07-15 09:35:36 +000010830 ASSERT_FALSE(startDrag(false));
Arthur Hung54745652022-04-20 07:17:41 +000010831}
10832
10833TEST_F(InputDispatcherDragTests, DragAndDropWhenSplitTouch) {
10834 // First down on second window.
10835 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070010836 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
Arthur Hung54745652022-04-20 07:17:41 +000010837 {150, 50}))
10838 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
10839
10840 mSecondWindow->consumeMotionDown(ADISPLAY_ID_DEFAULT);
10841
10842 // Second down on first window.
10843 const MotionEvent secondFingerDownEvent =
10844 MotionEventBuilder(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
10845 .displayId(ADISPLAY_ID_DEFAULT)
10846 .eventTime(systemTime(SYSTEM_TIME_MONOTONIC))
Siarhei Vishniakou6d73f832022-07-21 17:27:03 -070010847 .pointer(PointerBuilder(/*id=*/0, ToolType::FINGER).x(150).y(50))
10848 .pointer(PointerBuilder(/*id=*/1, ToolType::FINGER).x(50).y(50))
Arthur Hung54745652022-04-20 07:17:41 +000010849 .build();
10850 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070010851 injectMotionEvent(*mDispatcher, secondFingerDownEvent, INJECT_EVENT_TIMEOUT,
Arthur Hung54745652022-04-20 07:17:41 +000010852 InputEventInjectionSync::WAIT_FOR_RESULT))
10853 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
10854 mWindow->consumeMotionDown(ADISPLAY_ID_DEFAULT);
Prabir Pradhan9d5f9ce2024-01-24 00:03:41 +000010855 mSecondWindow->consumeMotionMove(ADISPLAY_ID_DEFAULT);
Arthur Hung54745652022-04-20 07:17:41 +000010856
10857 // Perform drag and drop from first window.
Arthur Hungb75c2aa2022-07-15 09:35:36 +000010858 ASSERT_TRUE(startDrag(false));
Arthur Hung54745652022-04-20 07:17:41 +000010859
10860 // Move on window.
10861 const MotionEvent secondFingerMoveEvent =
10862 MotionEventBuilder(AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN)
10863 .eventTime(systemTime(SYSTEM_TIME_MONOTONIC))
Siarhei Vishniakou6d73f832022-07-21 17:27:03 -070010864 .pointer(PointerBuilder(/*id=*/0, ToolType::FINGER).x(150).y(50))
10865 .pointer(PointerBuilder(/*id=*/1, ToolType::FINGER).x(50).y(50))
Arthur Hung54745652022-04-20 07:17:41 +000010866 .build();
10867 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070010868 injectMotionEvent(*mDispatcher, secondFingerMoveEvent, INJECT_EVENT_TIMEOUT,
Arthur Hung54745652022-04-20 07:17:41 +000010869 InputEventInjectionSync::WAIT_FOR_RESULT));
Prabir Pradhan65455c72024-02-13 21:46:41 +000010870 mDragWindow->consumeMotionMove(ADISPLAY_ID_DEFAULT, AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
Arthur Hung54745652022-04-20 07:17:41 +000010871 mWindow->consumeDragEvent(false, 50, 50);
10872 mSecondWindow->consumeMotionMove();
10873
10874 // Release the drag pointer should perform drop.
10875 const MotionEvent secondFingerUpEvent =
10876 MotionEventBuilder(POINTER_1_UP, AINPUT_SOURCE_TOUCHSCREEN)
10877 .eventTime(systemTime(SYSTEM_TIME_MONOTONIC))
Siarhei Vishniakou6d73f832022-07-21 17:27:03 -070010878 .pointer(PointerBuilder(/*id=*/0, ToolType::FINGER).x(150).y(50))
10879 .pointer(PointerBuilder(/*id=*/1, ToolType::FINGER).x(50).y(50))
Arthur Hung54745652022-04-20 07:17:41 +000010880 .build();
10881 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070010882 injectMotionEvent(*mDispatcher, secondFingerUpEvent, INJECT_EVENT_TIMEOUT,
Arthur Hung54745652022-04-20 07:17:41 +000010883 InputEventInjectionSync::WAIT_FOR_RESULT));
Prabir Pradhan65455c72024-02-13 21:46:41 +000010884 mDragWindow->consumeMotionUp(ADISPLAY_ID_DEFAULT, AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
Siarhei Vishniakoua66d65e2023-06-16 10:32:51 -070010885 mFakePolicy->assertDropTargetEquals(*mDispatcher, mWindow->getToken());
Arthur Hung54745652022-04-20 07:17:41 +000010886 mWindow->assertNoEvents();
10887 mSecondWindow->consumeMotionMove();
10888}
10889
Arthur Hung3915c1f2022-05-31 07:17:17 +000010890TEST_F(InputDispatcherDragTests, DragAndDropWhenMultiDisplays) {
Arthur Hungb75c2aa2022-07-15 09:35:36 +000010891 startDrag();
Arthur Hung3915c1f2022-05-31 07:17:17 +000010892
10893 // Update window of second display.
10894 sp<FakeWindowHandle> windowInSecondary =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -070010895 sp<FakeWindowHandle>::make(mApp, mDispatcher, "D_2", SECOND_DISPLAY_ID);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070010896 mDispatcher->onWindowInfosChanged(
10897 {{*mDragWindow->getInfo(), *mSpyWindow->getInfo(), *mWindow->getInfo(),
10898 *mSecondWindow->getInfo(), *windowInSecondary->getInfo()},
10899 {},
10900 0,
10901 0});
Arthur Hung3915c1f2022-05-31 07:17:17 +000010902
10903 // Let second display has a touch state.
10904 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070010905 injectMotionEvent(*mDispatcher,
Arthur Hung3915c1f2022-05-31 07:17:17 +000010906 MotionEventBuilder(AMOTION_EVENT_ACTION_DOWN,
10907 AINPUT_SOURCE_TOUCHSCREEN)
10908 .displayId(SECOND_DISPLAY_ID)
Siarhei Vishniakou6d73f832022-07-21 17:27:03 -070010909 .pointer(PointerBuilder(0, ToolType::FINGER).x(100).y(100))
Arthur Hung3915c1f2022-05-31 07:17:17 +000010910 .build()));
Prabir Pradhan7662a8d2023-12-15 01:58:14 +000010911 windowInSecondary->consumeMotionDown(SECOND_DISPLAY_ID, /*expectedFlag=*/0);
Arthur Hung3915c1f2022-05-31 07:17:17 +000010912 // Update window again.
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070010913 mDispatcher->onWindowInfosChanged(
10914 {{*mDragWindow->getInfo(), *mSpyWindow->getInfo(), *mWindow->getInfo(),
10915 *mSecondWindow->getInfo(), *windowInSecondary->getInfo()},
10916 {},
10917 0,
10918 0});
Arthur Hung3915c1f2022-05-31 07:17:17 +000010919
10920 // Move on window.
10921 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070010922 injectMotionEvent(*mDispatcher, AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN,
Arthur Hung3915c1f2022-05-31 07:17:17 +000010923 ADISPLAY_ID_DEFAULT, {50, 50}))
10924 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
Prabir Pradhan65455c72024-02-13 21:46:41 +000010925 mDragWindow->consumeMotionMove(ADISPLAY_ID_DEFAULT, AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
Arthur Hung3915c1f2022-05-31 07:17:17 +000010926 mWindow->consumeDragEvent(false, 50, 50);
10927 mSecondWindow->assertNoEvents();
10928
10929 // Move to another window.
10930 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070010931 injectMotionEvent(*mDispatcher, AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN,
Arthur Hung3915c1f2022-05-31 07:17:17 +000010932 ADISPLAY_ID_DEFAULT, {150, 50}))
10933 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
Prabir Pradhan65455c72024-02-13 21:46:41 +000010934 mDragWindow->consumeMotionMove(ADISPLAY_ID_DEFAULT, AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
Arthur Hung3915c1f2022-05-31 07:17:17 +000010935 mWindow->consumeDragEvent(true, 150, 50);
10936 mSecondWindow->consumeDragEvent(false, 50, 50);
10937
10938 // drop to another window.
10939 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070010940 injectMotionUp(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
Arthur Hung3915c1f2022-05-31 07:17:17 +000010941 {150, 50}))
10942 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
Prabir Pradhan65455c72024-02-13 21:46:41 +000010943 mDragWindow->consumeMotionUp(ADISPLAY_ID_DEFAULT, AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
Siarhei Vishniakoua66d65e2023-06-16 10:32:51 -070010944 mFakePolicy->assertDropTargetEquals(*mDispatcher, mSecondWindow->getToken());
Arthur Hung3915c1f2022-05-31 07:17:17 +000010945 mWindow->assertNoEvents();
10946 mSecondWindow->assertNoEvents();
10947}
10948
Arthur Hungb75c2aa2022-07-15 09:35:36 +000010949TEST_F(InputDispatcherDragTests, MouseDragAndDrop) {
10950 startDrag(true, AINPUT_SOURCE_MOUSE);
10951 // Move on window.
10952 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070010953 injectMotionEvent(*mDispatcher,
Arthur Hungb75c2aa2022-07-15 09:35:36 +000010954 MotionEventBuilder(AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_MOUSE)
10955 .buttonState(AMOTION_EVENT_BUTTON_PRIMARY)
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070010956 .pointer(PointerBuilder(MOUSE_POINTER_ID, ToolType::MOUSE)
Arthur Hungb75c2aa2022-07-15 09:35:36 +000010957 .x(50)
10958 .y(50))
10959 .build()))
10960 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
Prabir Pradhan65455c72024-02-13 21:46:41 +000010961 mDragWindow->consumeMotionMove(ADISPLAY_ID_DEFAULT, AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
Arthur Hungb75c2aa2022-07-15 09:35:36 +000010962 mWindow->consumeDragEvent(false, 50, 50);
10963 mSecondWindow->assertNoEvents();
10964
10965 // Move to another window.
10966 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070010967 injectMotionEvent(*mDispatcher,
Arthur Hungb75c2aa2022-07-15 09:35:36 +000010968 MotionEventBuilder(AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_MOUSE)
10969 .buttonState(AMOTION_EVENT_BUTTON_PRIMARY)
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070010970 .pointer(PointerBuilder(MOUSE_POINTER_ID, ToolType::MOUSE)
Arthur Hungb75c2aa2022-07-15 09:35:36 +000010971 .x(150)
10972 .y(50))
10973 .build()))
10974 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
Prabir Pradhan65455c72024-02-13 21:46:41 +000010975 mDragWindow->consumeMotionMove(ADISPLAY_ID_DEFAULT, AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
Arthur Hungb75c2aa2022-07-15 09:35:36 +000010976 mWindow->consumeDragEvent(true, 150, 50);
10977 mSecondWindow->consumeDragEvent(false, 50, 50);
10978
10979 // drop to another window.
10980 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070010981 injectMotionEvent(*mDispatcher,
Arthur Hungb75c2aa2022-07-15 09:35:36 +000010982 MotionEventBuilder(AMOTION_EVENT_ACTION_UP, AINPUT_SOURCE_MOUSE)
10983 .buttonState(0)
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070010984 .pointer(PointerBuilder(MOUSE_POINTER_ID, ToolType::MOUSE)
Arthur Hungb75c2aa2022-07-15 09:35:36 +000010985 .x(150)
10986 .y(50))
10987 .build()))
10988 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
Prabir Pradhan65455c72024-02-13 21:46:41 +000010989 mDragWindow->consumeMotionUp(ADISPLAY_ID_DEFAULT, AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
Siarhei Vishniakoua66d65e2023-06-16 10:32:51 -070010990 mFakePolicy->assertDropTargetEquals(*mDispatcher, mSecondWindow->getToken());
Arthur Hungb75c2aa2022-07-15 09:35:36 +000010991 mWindow->assertNoEvents();
10992 mSecondWindow->assertNoEvents();
10993}
10994
Linnan Li5af92f92023-07-14 14:36:22 +080010995/**
10996 * Start drag and drop with a pointer whose id is not 0, cancel the current touch, and ensure drag
10997 * and drop is also canceled. Then inject a simple gesture, and ensure dispatcher does not crash.
10998 */
10999TEST_F(InputDispatcherDragTests, DragAndDropFinishedWhenCancelCurrentTouch) {
11000 // Down on second window
11001 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
11002 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
11003 {150, 50}))
11004 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
11005
11006 ASSERT_NO_FATAL_FAILURE(mSecondWindow->consumeMotionDown());
11007 ASSERT_NO_FATAL_FAILURE(mSpyWindow->consumeMotionDown());
11008
11009 // Down on first window
11010 const MotionEvent secondFingerDownEvent =
11011 MotionEventBuilder(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
11012 .displayId(ADISPLAY_ID_DEFAULT)
11013 .pointer(PointerBuilder(/*id=*/0, ToolType::FINGER).x(150).y(50))
11014 .pointer(PointerBuilder(/*id=*/1, ToolType::FINGER).x(50).y(50))
11015 .build();
11016 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
11017 injectMotionEvent(*mDispatcher, secondFingerDownEvent, INJECT_EVENT_TIMEOUT,
11018 InputEventInjectionSync::WAIT_FOR_RESULT))
11019 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
11020 ASSERT_NO_FATAL_FAILURE(mWindow->consumeMotionDown());
11021 ASSERT_NO_FATAL_FAILURE(mSecondWindow->consumeMotionMove());
11022 ASSERT_NO_FATAL_FAILURE(mSpyWindow->consumeMotionPointerDown(1));
11023
11024 // Start drag on first window
11025 ASSERT_TRUE(startDrag(/*sendDown=*/false, AINPUT_SOURCE_TOUCHSCREEN));
11026
11027 // Trigger cancel
11028 mDispatcher->cancelCurrentTouch();
11029 ASSERT_NO_FATAL_FAILURE(mSecondWindow->consumeMotionCancel());
Prabir Pradhan65455c72024-02-13 21:46:41 +000011030 ASSERT_NO_FATAL_FAILURE(mDragWindow->consumeMotionCancel(ADISPLAY_ID_DEFAULT,
11031 AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE));
Linnan Li5af92f92023-07-14 14:36:22 +080011032 ASSERT_NO_FATAL_FAILURE(mSpyWindow->consumeMotionCancel());
11033
11034 ASSERT_TRUE(mDispatcher->waitForIdle());
11035 // The D&D finished with nullptr
11036 mFakePolicy->assertDropTargetEquals(*mDispatcher, nullptr);
11037
11038 // Remove drag window
11039 mDispatcher->onWindowInfosChanged({{*mWindow->getInfo(), *mSecondWindow->getInfo()}, {}, 0, 0});
11040
11041 // Inject a simple gesture, ensure dispatcher not crashed
11042 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
11043 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
11044 PointF{50, 50}))
11045 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
11046 ASSERT_NO_FATAL_FAILURE(mWindow->consumeMotionDown());
11047
11048 const MotionEvent moveEvent =
11049 MotionEventBuilder(AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN)
11050 .displayId(ADISPLAY_ID_DEFAULT)
11051 .pointer(PointerBuilder(/*id=*/0, ToolType::FINGER).x(50).y(50))
11052 .build();
11053 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
11054 injectMotionEvent(*mDispatcher, moveEvent, INJECT_EVENT_TIMEOUT,
11055 InputEventInjectionSync::WAIT_FOR_RESULT))
11056 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
11057 ASSERT_NO_FATAL_FAILURE(mWindow->consumeMotionMove());
11058
11059 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
11060 injectMotionUp(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
11061 {50, 50}))
11062 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
11063 ASSERT_NO_FATAL_FAILURE(mWindow->consumeMotionUp());
11064}
11065
Prabir Pradhan9cd9eb62023-11-22 17:58:06 +000011066TEST_F(InputDispatcherDragTests, NoDragAndDropWithHoveringPointer) {
11067 // Start hovering over the window.
11068 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
11069 injectMotionEvent(*mDispatcher, ACTION_HOVER_ENTER, AINPUT_SOURCE_MOUSE,
11070 ADISPLAY_ID_DEFAULT, {50, 50}));
11071
11072 ASSERT_NO_FATAL_FAILURE(mWindow->consumeMotionEvent(WithMotionAction(ACTION_HOVER_ENTER)));
11073 ASSERT_NO_FATAL_FAILURE(mSpyWindow->consumeMotionEvent(WithMotionAction(ACTION_HOVER_ENTER)));
11074
11075 ASSERT_FALSE(startDrag(/*sendDown=*/false))
11076 << "Drag and drop should not work with a hovering pointer";
11077}
11078
Vishnu Nair062a8672021-09-03 16:07:44 -070011079class InputDispatcherDropInputFeatureTest : public InputDispatcherTest {};
11080
11081TEST_F(InputDispatcherDropInputFeatureTest, WindowDropsInput) {
11082 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -070011083 sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher,
11084 "Test window", ADISPLAY_ID_DEFAULT);
Prabir Pradhan51e7db02022-02-07 06:02:57 -080011085 window->setDropInput(true);
Vishnu Nair062a8672021-09-03 16:07:44 -070011086 mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application);
11087 window->setFocusable(true);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070011088 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Vishnu Nair062a8672021-09-03 16:07:44 -070011089 setFocusedWindow(window);
Harry Cutts33476232023-01-30 19:57:29 +000011090 window->consumeFocusEvent(/*hasFocus=*/true, /*inTouchMode=*/true);
Vishnu Nair062a8672021-09-03 16:07:44 -070011091
11092 // With the flag set, window should not get any input
Prabir Pradhan678438e2023-04-13 19:32:51 +000011093 mDispatcher->notifyKey(generateKeyArgs(AKEY_EVENT_ACTION_DOWN, ADISPLAY_ID_DEFAULT));
Vishnu Nair062a8672021-09-03 16:07:44 -070011094 window->assertNoEvents();
11095
Prabir Pradhan678438e2023-04-13 19:32:51 +000011096 mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_DOWN,
11097 AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT));
Siarhei Vishniakou5c02a712023-05-15 15:45:02 -070011098 mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN,
11099 ADISPLAY_ID_DEFAULT));
Siarhei Vishniakoud908f5a2023-11-16 10:25:12 -080011100 mDispatcher->waitForIdle();
Vishnu Nair062a8672021-09-03 16:07:44 -070011101 window->assertNoEvents();
11102
11103 // With the flag cleared, the window should get input
Prabir Pradhan51e7db02022-02-07 06:02:57 -080011104 window->setDropInput(false);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070011105 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Vishnu Nair062a8672021-09-03 16:07:44 -070011106
Prabir Pradhan678438e2023-04-13 19:32:51 +000011107 mDispatcher->notifyKey(generateKeyArgs(AKEY_EVENT_ACTION_UP, ADISPLAY_ID_DEFAULT));
Vishnu Nair062a8672021-09-03 16:07:44 -070011108 window->consumeKeyUp(ADISPLAY_ID_DEFAULT);
11109
Prabir Pradhan678438e2023-04-13 19:32:51 +000011110 mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_DOWN,
11111 AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT));
Vishnu Nair062a8672021-09-03 16:07:44 -070011112 window->consumeMotionDown(ADISPLAY_ID_DEFAULT);
11113 window->assertNoEvents();
11114}
11115
11116TEST_F(InputDispatcherDropInputFeatureTest, ObscuredWindowDropsInput) {
11117 std::shared_ptr<FakeApplicationHandle> obscuringApplication =
11118 std::make_shared<FakeApplicationHandle>();
11119 sp<FakeWindowHandle> obscuringWindow =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -070011120 sp<FakeWindowHandle>::make(obscuringApplication, mDispatcher, "obscuringWindow",
11121 ADISPLAY_ID_DEFAULT);
Vishnu Nair062a8672021-09-03 16:07:44 -070011122 obscuringWindow->setFrame(Rect(0, 0, 50, 50));
Prabir Pradhanaeebeb42023-06-13 19:53:03 +000011123 obscuringWindow->setOwnerInfo(gui::Pid{111}, gui::Uid{111});
Prabir Pradhan4d5c52f2022-01-31 08:52:10 -080011124 obscuringWindow->setTouchable(false);
Vishnu Nair062a8672021-09-03 16:07:44 -070011125 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -070011126 sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher,
11127 "Test window", ADISPLAY_ID_DEFAULT);
Prabir Pradhan51e7db02022-02-07 06:02:57 -080011128 window->setDropInputIfObscured(true);
Prabir Pradhanaeebeb42023-06-13 19:53:03 +000011129 window->setOwnerInfo(gui::Pid{222}, gui::Uid{222});
Vishnu Nair062a8672021-09-03 16:07:44 -070011130 mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application);
11131 window->setFocusable(true);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070011132 mDispatcher->onWindowInfosChanged(
11133 {{*obscuringWindow->getInfo(), *window->getInfo()}, {}, 0, 0});
Vishnu Nair062a8672021-09-03 16:07:44 -070011134 setFocusedWindow(window);
Harry Cutts33476232023-01-30 19:57:29 +000011135 window->consumeFocusEvent(/*hasFocus=*/true, /*inTouchMode=*/true);
Vishnu Nair062a8672021-09-03 16:07:44 -070011136
11137 // With the flag set, window should not get any input
Prabir Pradhan678438e2023-04-13 19:32:51 +000011138 mDispatcher->notifyKey(generateKeyArgs(AKEY_EVENT_ACTION_DOWN, ADISPLAY_ID_DEFAULT));
Vishnu Nair062a8672021-09-03 16:07:44 -070011139 window->assertNoEvents();
11140
Prabir Pradhan678438e2023-04-13 19:32:51 +000011141 mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_DOWN,
11142 AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT));
Siarhei Vishniakou5c02a712023-05-15 15:45:02 -070011143 mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN,
11144 ADISPLAY_ID_DEFAULT));
Vishnu Nair062a8672021-09-03 16:07:44 -070011145 window->assertNoEvents();
11146
11147 // With the flag cleared, the window should get input
Prabir Pradhan51e7db02022-02-07 06:02:57 -080011148 window->setDropInputIfObscured(false);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070011149 mDispatcher->onWindowInfosChanged(
11150 {{*obscuringWindow->getInfo(), *window->getInfo()}, {}, 0, 0});
Vishnu Nair062a8672021-09-03 16:07:44 -070011151
Prabir Pradhan678438e2023-04-13 19:32:51 +000011152 mDispatcher->notifyKey(generateKeyArgs(AKEY_EVENT_ACTION_UP, ADISPLAY_ID_DEFAULT));
Vishnu Nair062a8672021-09-03 16:07:44 -070011153 window->consumeKeyUp(ADISPLAY_ID_DEFAULT);
11154
Prabir Pradhan678438e2023-04-13 19:32:51 +000011155 mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_DOWN,
11156 AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT));
Vishnu Nair062a8672021-09-03 16:07:44 -070011157 window->consumeMotionDown(ADISPLAY_ID_DEFAULT, AMOTION_EVENT_FLAG_WINDOW_IS_PARTIALLY_OBSCURED);
11158 window->assertNoEvents();
11159}
11160
11161TEST_F(InputDispatcherDropInputFeatureTest, UnobscuredWindowGetsInput) {
11162 std::shared_ptr<FakeApplicationHandle> obscuringApplication =
11163 std::make_shared<FakeApplicationHandle>();
11164 sp<FakeWindowHandle> obscuringWindow =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -070011165 sp<FakeWindowHandle>::make(obscuringApplication, mDispatcher, "obscuringWindow",
11166 ADISPLAY_ID_DEFAULT);
Vishnu Nair062a8672021-09-03 16:07:44 -070011167 obscuringWindow->setFrame(Rect(0, 0, 50, 50));
Prabir Pradhanaeebeb42023-06-13 19:53:03 +000011168 obscuringWindow->setOwnerInfo(gui::Pid{111}, gui::Uid{111});
Prabir Pradhan4d5c52f2022-01-31 08:52:10 -080011169 obscuringWindow->setTouchable(false);
Vishnu Nair062a8672021-09-03 16:07:44 -070011170 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -070011171 sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher,
11172 "Test window", ADISPLAY_ID_DEFAULT);
Prabir Pradhan51e7db02022-02-07 06:02:57 -080011173 window->setDropInputIfObscured(true);
Prabir Pradhanaeebeb42023-06-13 19:53:03 +000011174 window->setOwnerInfo(gui::Pid{222}, gui::Uid{222});
Vishnu Nair062a8672021-09-03 16:07:44 -070011175 mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application);
11176 window->setFocusable(true);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070011177 mDispatcher->onWindowInfosChanged(
11178 {{*obscuringWindow->getInfo(), *window->getInfo()}, {}, 0, 0});
Vishnu Nair062a8672021-09-03 16:07:44 -070011179 setFocusedWindow(window);
Harry Cutts33476232023-01-30 19:57:29 +000011180 window->consumeFocusEvent(/*hasFocus=*/true, /*inTouchMode=*/true);
Vishnu Nair062a8672021-09-03 16:07:44 -070011181
11182 // With the flag set, window should not get any input
Prabir Pradhan678438e2023-04-13 19:32:51 +000011183 mDispatcher->notifyKey(generateKeyArgs(AKEY_EVENT_ACTION_DOWN, ADISPLAY_ID_DEFAULT));
Vishnu Nair062a8672021-09-03 16:07:44 -070011184 window->assertNoEvents();
11185
Prabir Pradhan678438e2023-04-13 19:32:51 +000011186 mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_DOWN,
11187 AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT));
Siarhei Vishniakou5c02a712023-05-15 15:45:02 -070011188 mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN,
11189 ADISPLAY_ID_DEFAULT));
Vishnu Nair062a8672021-09-03 16:07:44 -070011190 window->assertNoEvents();
11191
11192 // When the window is no longer obscured because it went on top, it should get input
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070011193 mDispatcher->onWindowInfosChanged(
11194 {{*window->getInfo(), *obscuringWindow->getInfo()}, {}, 0, 0});
Vishnu Nair062a8672021-09-03 16:07:44 -070011195
Prabir Pradhan678438e2023-04-13 19:32:51 +000011196 mDispatcher->notifyKey(generateKeyArgs(AKEY_EVENT_ACTION_UP, ADISPLAY_ID_DEFAULT));
Vishnu Nair062a8672021-09-03 16:07:44 -070011197 window->consumeKeyUp(ADISPLAY_ID_DEFAULT);
11198
Prabir Pradhan678438e2023-04-13 19:32:51 +000011199 mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_DOWN,
11200 AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT));
Vishnu Nair062a8672021-09-03 16:07:44 -070011201 window->consumeMotionDown(ADISPLAY_ID_DEFAULT);
11202 window->assertNoEvents();
11203}
11204
Antonio Kantekf16f2832021-09-28 04:39:20 +000011205class InputDispatcherTouchModeChangedTests : public InputDispatcherTest {
11206protected:
11207 std::shared_ptr<FakeApplicationHandle> mApp;
Antonio Kantek15beb512022-06-13 22:35:41 +000011208 std::shared_ptr<FakeApplicationHandle> mSecondaryApp;
Antonio Kantekf16f2832021-09-28 04:39:20 +000011209 sp<FakeWindowHandle> mWindow;
11210 sp<FakeWindowHandle> mSecondWindow;
Antonio Kantek15beb512022-06-13 22:35:41 +000011211 sp<FakeWindowHandle> mThirdWindow;
Antonio Kantekf16f2832021-09-28 04:39:20 +000011212
11213 void SetUp() override {
11214 InputDispatcherTest::SetUp();
11215
11216 mApp = std::make_shared<FakeApplicationHandle>();
Antonio Kantek15beb512022-06-13 22:35:41 +000011217 mSecondaryApp = std::make_shared<FakeApplicationHandle>();
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -070011218 mWindow = sp<FakeWindowHandle>::make(mApp, mDispatcher, "TestWindow", ADISPLAY_ID_DEFAULT);
Antonio Kantekf16f2832021-09-28 04:39:20 +000011219 mWindow->setFocusable(true);
Antonio Kantek26defcf2022-02-08 01:12:27 +000011220 setFocusedWindow(mWindow);
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -070011221 mSecondWindow =
11222 sp<FakeWindowHandle>::make(mApp, mDispatcher, "TestWindow2", ADISPLAY_ID_DEFAULT);
Antonio Kantekf16f2832021-09-28 04:39:20 +000011223 mSecondWindow->setFocusable(true);
Antonio Kantek15beb512022-06-13 22:35:41 +000011224 mThirdWindow =
11225 sp<FakeWindowHandle>::make(mSecondaryApp, mDispatcher,
11226 "TestWindow3_SecondaryDisplay", SECOND_DISPLAY_ID);
11227 mThirdWindow->setFocusable(true);
Antonio Kantekf16f2832021-09-28 04:39:20 +000011228
11229 mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, mApp);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070011230 mDispatcher->onWindowInfosChanged(
11231 {{*mWindow->getInfo(), *mSecondWindow->getInfo(), *mThirdWindow->getInfo()},
11232 {},
11233 0,
11234 0});
Antonio Kantek15beb512022-06-13 22:35:41 +000011235 mThirdWindow->setOwnerInfo(SECONDARY_WINDOW_PID, SECONDARY_WINDOW_UID);
Antonio Kantekf16f2832021-09-28 04:39:20 +000011236 mWindow->consumeFocusEvent(true);
Antonio Kantek26defcf2022-02-08 01:12:27 +000011237
Antonio Kantek15beb512022-06-13 22:35:41 +000011238 // Set main display initial touch mode to InputDispatcher::kDefaultInTouchMode.
Prabir Pradhan5735a322022-04-11 17:23:34 +000011239 if (mDispatcher->setInTouchMode(InputDispatcher::kDefaultInTouchMode, WINDOW_PID,
Harry Cutts33476232023-01-30 19:57:29 +000011240 WINDOW_UID, /*hasPermission=*/true, ADISPLAY_ID_DEFAULT)) {
Antonio Kantek48710e42022-03-24 14:19:30 -070011241 mWindow->consumeTouchModeEvent(InputDispatcher::kDefaultInTouchMode);
11242 mSecondWindow->consumeTouchModeEvent(InputDispatcher::kDefaultInTouchMode);
Antonio Kantek15beb512022-06-13 22:35:41 +000011243 mThirdWindow->assertNoEvents();
11244 }
11245
11246 // Set secondary display initial touch mode to InputDispatcher::kDefaultInTouchMode.
11247 if (mDispatcher->setInTouchMode(InputDispatcher::kDefaultInTouchMode, SECONDARY_WINDOW_PID,
Harry Cutts33476232023-01-30 19:57:29 +000011248 SECONDARY_WINDOW_UID, /*hasPermission=*/true,
Antonio Kantek15beb512022-06-13 22:35:41 +000011249 SECOND_DISPLAY_ID)) {
11250 mWindow->assertNoEvents();
11251 mSecondWindow->assertNoEvents();
11252 mThirdWindow->consumeTouchModeEvent(InputDispatcher::kDefaultInTouchMode);
Antonio Kantek48710e42022-03-24 14:19:30 -070011253 }
Antonio Kantekf16f2832021-09-28 04:39:20 +000011254 }
11255
Prabir Pradhanaeebeb42023-06-13 19:53:03 +000011256 void changeAndVerifyTouchModeInMainDisplayOnly(bool inTouchMode, gui::Pid pid, gui::Uid uid,
Antonio Kantek15beb512022-06-13 22:35:41 +000011257 bool hasPermission) {
Antonio Kanteka042c022022-07-06 16:51:07 -070011258 ASSERT_TRUE(mDispatcher->setInTouchMode(inTouchMode, pid, uid, hasPermission,
11259 ADISPLAY_ID_DEFAULT));
Antonio Kantekf16f2832021-09-28 04:39:20 +000011260 mWindow->consumeTouchModeEvent(inTouchMode);
11261 mSecondWindow->consumeTouchModeEvent(inTouchMode);
Antonio Kantek15beb512022-06-13 22:35:41 +000011262 mThirdWindow->assertNoEvents();
Antonio Kantekf16f2832021-09-28 04:39:20 +000011263 }
11264};
11265
Antonio Kantek26defcf2022-02-08 01:12:27 +000011266TEST_F(InputDispatcherTouchModeChangedTests, FocusedWindowCanChangeTouchMode) {
Antonio Kantekea47acb2021-12-23 12:41:25 -080011267 const WindowInfo& windowInfo = *mWindow->getInfo();
Antonio Kantek15beb512022-06-13 22:35:41 +000011268 changeAndVerifyTouchModeInMainDisplayOnly(!InputDispatcher::kDefaultInTouchMode,
11269 windowInfo.ownerPid, windowInfo.ownerUid,
Harry Cutts33476232023-01-30 19:57:29 +000011270 /* hasPermission=*/false);
Antonio Kantekf16f2832021-09-28 04:39:20 +000011271}
11272
Antonio Kantek26defcf2022-02-08 01:12:27 +000011273TEST_F(InputDispatcherTouchModeChangedTests, NonFocusedWindowOwnerCannotChangeTouchMode) {
11274 const WindowInfo& windowInfo = *mWindow->getInfo();
Prabir Pradhanaeebeb42023-06-13 19:53:03 +000011275 gui::Pid ownerPid = windowInfo.ownerPid;
Prabir Pradhan8a5c41d2023-06-08 19:13:46 +000011276 gui::Uid ownerUid = windowInfo.ownerUid;
Prabir Pradhanaeebeb42023-06-13 19:53:03 +000011277 mWindow->setOwnerInfo(gui::Pid::INVALID, gui::Uid::INVALID);
Antonio Kantek26defcf2022-02-08 01:12:27 +000011278 ASSERT_FALSE(mDispatcher->setInTouchMode(InputDispatcher::kDefaultInTouchMode, ownerPid,
Harry Cutts33476232023-01-30 19:57:29 +000011279 ownerUid, /*hasPermission=*/false,
Antonio Kanteka042c022022-07-06 16:51:07 -070011280 ADISPLAY_ID_DEFAULT));
Antonio Kantek26defcf2022-02-08 01:12:27 +000011281 mWindow->assertNoEvents();
11282 mSecondWindow->assertNoEvents();
11283}
11284
11285TEST_F(InputDispatcherTouchModeChangedTests, NonWindowOwnerMayChangeTouchModeOnPermissionGranted) {
11286 const WindowInfo& windowInfo = *mWindow->getInfo();
Prabir Pradhanaeebeb42023-06-13 19:53:03 +000011287 gui::Pid ownerPid = windowInfo.ownerPid;
Prabir Pradhan8a5c41d2023-06-08 19:13:46 +000011288 gui::Uid ownerUid = windowInfo.ownerUid;
Prabir Pradhanaeebeb42023-06-13 19:53:03 +000011289 mWindow->setOwnerInfo(gui::Pid::INVALID, gui::Uid::INVALID);
Antonio Kantek15beb512022-06-13 22:35:41 +000011290 changeAndVerifyTouchModeInMainDisplayOnly(!InputDispatcher::kDefaultInTouchMode, ownerPid,
Harry Cutts33476232023-01-30 19:57:29 +000011291 ownerUid, /*hasPermission=*/true);
Antonio Kantek26defcf2022-02-08 01:12:27 +000011292}
11293
Antonio Kantekf16f2832021-09-28 04:39:20 +000011294TEST_F(InputDispatcherTouchModeChangedTests, EventIsNotGeneratedIfNotChangingTouchMode) {
Antonio Kantekea47acb2021-12-23 12:41:25 -080011295 const WindowInfo& windowInfo = *mWindow->getInfo();
Antonio Kantek26defcf2022-02-08 01:12:27 +000011296 ASSERT_FALSE(mDispatcher->setInTouchMode(InputDispatcher::kDefaultInTouchMode,
11297 windowInfo.ownerPid, windowInfo.ownerUid,
Harry Cutts33476232023-01-30 19:57:29 +000011298 /*hasPermission=*/true, ADISPLAY_ID_DEFAULT));
Antonio Kantekf16f2832021-09-28 04:39:20 +000011299 mWindow->assertNoEvents();
11300 mSecondWindow->assertNoEvents();
11301}
11302
Antonio Kantek15beb512022-06-13 22:35:41 +000011303TEST_F(InputDispatcherTouchModeChangedTests, ChangeTouchOnSecondaryDisplayOnly) {
11304 const WindowInfo& windowInfo = *mThirdWindow->getInfo();
11305 ASSERT_TRUE(mDispatcher->setInTouchMode(!InputDispatcher::kDefaultInTouchMode,
11306 windowInfo.ownerPid, windowInfo.ownerUid,
Harry Cutts33476232023-01-30 19:57:29 +000011307 /*hasPermission=*/true, SECOND_DISPLAY_ID));
Antonio Kantek15beb512022-06-13 22:35:41 +000011308 mWindow->assertNoEvents();
11309 mSecondWindow->assertNoEvents();
11310 mThirdWindow->consumeTouchModeEvent(!InputDispatcher::kDefaultInTouchMode);
11311}
11312
Antonio Kantek48710e42022-03-24 14:19:30 -070011313TEST_F(InputDispatcherTouchModeChangedTests, CanChangeTouchModeWhenOwningLastInteractedWindow) {
11314 // Interact with the window first.
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070011315 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
11316 injectKeyDown(*mDispatcher, ADISPLAY_ID_DEFAULT))
Antonio Kantek48710e42022-03-24 14:19:30 -070011317 << "Inject key event should return InputEventInjectionResult::SUCCEEDED";
11318 mWindow->consumeKeyDown(ADISPLAY_ID_DEFAULT);
11319
11320 // Then remove focus.
11321 mWindow->setFocusable(false);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070011322 mDispatcher->onWindowInfosChanged({{*mWindow->getInfo()}, {}, 0, 0});
Antonio Kantek48710e42022-03-24 14:19:30 -070011323
11324 // Assert that caller can switch touch mode by owning one of the last interacted window.
11325 const WindowInfo& windowInfo = *mWindow->getInfo();
11326 ASSERT_TRUE(mDispatcher->setInTouchMode(!InputDispatcher::kDefaultInTouchMode,
11327 windowInfo.ownerPid, windowInfo.ownerUid,
Harry Cutts33476232023-01-30 19:57:29 +000011328 /*hasPermission=*/false, ADISPLAY_ID_DEFAULT));
Antonio Kantek48710e42022-03-24 14:19:30 -070011329}
11330
Prabir Pradhan07e05b62021-11-19 03:57:24 -080011331class InputDispatcherSpyWindowTest : public InputDispatcherTest {
11332public:
Prabir Pradhan4d5c52f2022-01-31 08:52:10 -080011333 sp<FakeWindowHandle> createSpy() {
Prabir Pradhan07e05b62021-11-19 03:57:24 -080011334 std::shared_ptr<FakeApplicationHandle> application =
11335 std::make_shared<FakeApplicationHandle>();
11336 std::string name = "Fake Spy ";
11337 name += std::to_string(mSpyCount++);
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -070011338 sp<FakeWindowHandle> spy = sp<FakeWindowHandle>::make(application, mDispatcher,
11339 name.c_str(), ADISPLAY_ID_DEFAULT);
Prabir Pradhan51e7db02022-02-07 06:02:57 -080011340 spy->setSpy(true);
Prabir Pradhan5c85e052021-12-22 02:27:12 -080011341 spy->setTrustedOverlay(true);
Prabir Pradhan07e05b62021-11-19 03:57:24 -080011342 return spy;
11343 }
11344
11345 sp<FakeWindowHandle> createForeground() {
11346 std::shared_ptr<FakeApplicationHandle> application =
11347 std::make_shared<FakeApplicationHandle>();
11348 sp<FakeWindowHandle> window =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -070011349 sp<FakeWindowHandle>::make(application, mDispatcher, "Fake Window",
11350 ADISPLAY_ID_DEFAULT);
Prabir Pradhan1376fcd2022-01-21 09:56:35 -080011351 window->setFocusable(true);
Prabir Pradhan07e05b62021-11-19 03:57:24 -080011352 return window;
11353 }
11354
11355private:
11356 int mSpyCount{0};
11357};
11358
Prabir Pradhana3ab87a2022-01-27 10:00:21 -080011359using InputDispatcherSpyWindowDeathTest = InputDispatcherSpyWindowTest;
Prabir Pradhan07e05b62021-11-19 03:57:24 -080011360/**
Prabir Pradhan5c85e052021-12-22 02:27:12 -080011361 * Adding a spy window that is not a trusted overlay causes Dispatcher to abort.
11362 */
Prabir Pradhana3ab87a2022-01-27 10:00:21 -080011363TEST_F(InputDispatcherSpyWindowDeathTest, UntrustedSpy_AbortsDispatcher) {
Siarhei Vishniakou21f77bd2023-07-18 17:51:35 -070011364 testing::GTEST_FLAG(death_test_style) = "threadsafe";
Prabir Pradhana3ab87a2022-01-27 10:00:21 -080011365 ScopedSilentDeath _silentDeath;
11366
Prabir Pradhan4d5c52f2022-01-31 08:52:10 -080011367 auto spy = createSpy();
Prabir Pradhan5c85e052021-12-22 02:27:12 -080011368 spy->setTrustedOverlay(false);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070011369 ASSERT_DEATH(mDispatcher->onWindowInfosChanged({{*spy->getInfo()}, {}, 0, 0}),
Prabir Pradhan5c85e052021-12-22 02:27:12 -080011370 ".* not a trusted overlay");
11371}
11372
11373/**
Prabir Pradhan07e05b62021-11-19 03:57:24 -080011374 * Input injection into a display with a spy window but no foreground windows should succeed.
11375 */
11376TEST_F(InputDispatcherSpyWindowTest, NoForegroundWindow) {
Prabir Pradhan4d5c52f2022-01-31 08:52:10 -080011377 auto spy = createSpy();
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070011378 mDispatcher->onWindowInfosChanged({{*spy->getInfo()}, {}, 0, 0});
Prabir Pradhan07e05b62021-11-19 03:57:24 -080011379
11380 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070011381 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT))
Prabir Pradhan07e05b62021-11-19 03:57:24 -080011382 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
11383 spy->consumeMotionDown(ADISPLAY_ID_DEFAULT);
11384}
11385
11386/**
11387 * Verify the order in which different input windows receive events. The touched foreground window
11388 * (if there is one) should always receive the event first. When there are multiple spy windows, the
11389 * spy windows will receive the event according to their Z-order, where the top-most spy window will
11390 * receive events before ones belows it.
11391 *
11392 * Here, we set up a scenario with four windows in the following Z order from the top:
11393 * spy1, spy2, window, spy3.
11394 * We then inject an event and verify that the foreground "window" receives it first, followed by
11395 * "spy1" and "spy2". The "spy3" does not receive the event because it is underneath the foreground
11396 * window.
11397 */
11398TEST_F(InputDispatcherSpyWindowTest, ReceivesInputInOrder) {
11399 auto window = createForeground();
Prabir Pradhan4d5c52f2022-01-31 08:52:10 -080011400 auto spy1 = createSpy();
11401 auto spy2 = createSpy();
11402 auto spy3 = createSpy();
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070011403 mDispatcher->onWindowInfosChanged(
11404 {{*spy1->getInfo(), *spy2->getInfo(), *window->getInfo(), *spy3->getInfo()}, {}, 0, 0});
Prabir Pradhan07e05b62021-11-19 03:57:24 -080011405 const std::vector<sp<FakeWindowHandle>> channels{spy1, spy2, window, spy3};
11406 const size_t numChannels = channels.size();
11407
Michael Wright8e9a8562022-02-09 13:44:29 +000011408 base::unique_fd epollFd(epoll_create1(EPOLL_CLOEXEC));
Prabir Pradhan07e05b62021-11-19 03:57:24 -080011409 if (!epollFd.ok()) {
11410 FAIL() << "Failed to create epoll fd";
11411 }
11412
11413 for (size_t i = 0; i < numChannels; i++) {
11414 struct epoll_event event = {.events = EPOLLIN, .data.u64 = i};
11415 if (epoll_ctl(epollFd.get(), EPOLL_CTL_ADD, channels[i]->getChannelFd(), &event) < 0) {
11416 FAIL() << "Failed to add fd to epoll";
11417 }
11418 }
11419
11420 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070011421 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT))
Prabir Pradhan07e05b62021-11-19 03:57:24 -080011422 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
11423
11424 std::vector<size_t> eventOrder;
11425 std::vector<struct epoll_event> events(numChannels);
11426 for (;;) {
11427 const int nFds = epoll_wait(epollFd.get(), events.data(), static_cast<int>(numChannels),
11428 (100ms).count());
11429 if (nFds < 0) {
11430 FAIL() << "Failed to call epoll_wait";
11431 }
11432 if (nFds == 0) {
11433 break; // epoll_wait timed out
11434 }
11435 for (int i = 0; i < nFds; i++) {
Colin Cross5b799302022-10-18 21:52:41 -070011436 ASSERT_EQ(static_cast<uint32_t>(EPOLLIN), events[i].events);
Siarhei Vishniakou31977182022-09-30 08:51:23 -070011437 eventOrder.push_back(static_cast<size_t>(events[i].data.u64));
Prabir Pradhan07e05b62021-11-19 03:57:24 -080011438 channels[i]->consumeMotionDown();
11439 }
11440 }
11441
11442 // Verify the order in which the events were received.
11443 EXPECT_EQ(3u, eventOrder.size());
11444 EXPECT_EQ(2u, eventOrder[0]); // index 2: window
11445 EXPECT_EQ(0u, eventOrder[1]); // index 0: spy1
11446 EXPECT_EQ(1u, eventOrder[2]); // index 1: spy2
11447}
11448
11449/**
11450 * A spy window using the NOT_TOUCHABLE flag does not receive events.
11451 */
11452TEST_F(InputDispatcherSpyWindowTest, NotTouchable) {
11453 auto window = createForeground();
Prabir Pradhan4d5c52f2022-01-31 08:52:10 -080011454 auto spy = createSpy();
11455 spy->setTouchable(false);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070011456 mDispatcher->onWindowInfosChanged({{*spy->getInfo(), *window->getInfo()}, {}, 0, 0});
Prabir Pradhan07e05b62021-11-19 03:57:24 -080011457
11458 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070011459 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT))
Prabir Pradhan07e05b62021-11-19 03:57:24 -080011460 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
11461 window->consumeMotionDown(ADISPLAY_ID_DEFAULT);
11462 spy->assertNoEvents();
11463}
11464
11465/**
11466 * A spy window will only receive gestures that originate within its touchable region. Gestures that
11467 * have their ACTION_DOWN outside of the touchable region of the spy window will not be dispatched
11468 * to the window.
11469 */
11470TEST_F(InputDispatcherSpyWindowTest, TouchableRegion) {
11471 auto window = createForeground();
Prabir Pradhan4d5c52f2022-01-31 08:52:10 -080011472 auto spy = createSpy();
Prabir Pradhan07e05b62021-11-19 03:57:24 -080011473 spy->setTouchableRegion(Region{{0, 0, 20, 20}});
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070011474 mDispatcher->onWindowInfosChanged({{*spy->getInfo(), *window->getInfo()}, {}, 0, 0});
Prabir Pradhan07e05b62021-11-19 03:57:24 -080011475
11476 // Inject an event outside the spy window's touchable region.
11477 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070011478 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT))
Prabir Pradhan07e05b62021-11-19 03:57:24 -080011479 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
11480 window->consumeMotionDown();
11481 spy->assertNoEvents();
11482 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070011483 injectMotionUp(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT))
Prabir Pradhan07e05b62021-11-19 03:57:24 -080011484 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
11485 window->consumeMotionUp();
11486 spy->assertNoEvents();
11487
11488 // Inject an event inside the spy window's touchable region.
11489 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070011490 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
Prabir Pradhan07e05b62021-11-19 03:57:24 -080011491 {5, 10}))
11492 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
11493 window->consumeMotionDown();
11494 spy->consumeMotionDown();
11495}
11496
11497/**
Prabir Pradhan07e05b62021-11-19 03:57:24 -080011498 * A spy window can listen for touches outside its touchable region using the WATCH_OUTSIDE_TOUCHES
Prabir Pradhandfabf8a2022-01-21 08:19:30 -080011499 * flag, but it will get zero-ed out coordinates if the foreground has a different owner.
Prabir Pradhan07e05b62021-11-19 03:57:24 -080011500 */
11501TEST_F(InputDispatcherSpyWindowTest, WatchOutsideTouches) {
11502 auto window = createForeground();
Prabir Pradhanaeebeb42023-06-13 19:53:03 +000011503 window->setOwnerInfo(gui::Pid{12}, gui::Uid{34});
Prabir Pradhan4d5c52f2022-01-31 08:52:10 -080011504 auto spy = createSpy();
11505 spy->setWatchOutsideTouch(true);
Prabir Pradhanaeebeb42023-06-13 19:53:03 +000011506 spy->setOwnerInfo(gui::Pid{56}, gui::Uid{78});
Prabir Pradhan07e05b62021-11-19 03:57:24 -080011507 spy->setFrame(Rect{0, 0, 20, 20});
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070011508 mDispatcher->onWindowInfosChanged({{*spy->getInfo(), *window->getInfo()}, {}, 0, 0});
Prabir Pradhan07e05b62021-11-19 03:57:24 -080011509
11510 // Inject an event outside the spy window's frame and touchable region.
11511 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070011512 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
Prabir Pradhandfabf8a2022-01-21 08:19:30 -080011513 {100, 200}))
Prabir Pradhan07e05b62021-11-19 03:57:24 -080011514 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
11515 window->consumeMotionDown();
Prabir Pradhandfabf8a2022-01-21 08:19:30 -080011516 spy->consumeMotionOutsideWithZeroedCoords();
Prabir Pradhan07e05b62021-11-19 03:57:24 -080011517}
11518
11519/**
Prabir Pradhan07e05b62021-11-19 03:57:24 -080011520 * Even when a spy window spans over multiple foreground windows, the spy should receive all
11521 * pointers that are down within its bounds.
11522 */
11523TEST_F(InputDispatcherSpyWindowTest, ReceivesMultiplePointers) {
11524 auto windowLeft = createForeground();
11525 windowLeft->setFrame({0, 0, 100, 200});
11526 auto windowRight = createForeground();
11527 windowRight->setFrame({100, 0, 200, 200});
Prabir Pradhan4d5c52f2022-01-31 08:52:10 -080011528 auto spy = createSpy();
Prabir Pradhan07e05b62021-11-19 03:57:24 -080011529 spy->setFrame({0, 0, 200, 200});
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070011530 mDispatcher->onWindowInfosChanged(
11531 {{*spy->getInfo(), *windowLeft->getInfo(), *windowRight->getInfo()}, {}, 0, 0});
Prabir Pradhan07e05b62021-11-19 03:57:24 -080011532
11533 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070011534 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
Prabir Pradhan07e05b62021-11-19 03:57:24 -080011535 {50, 50}))
11536 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
11537 windowLeft->consumeMotionDown();
11538 spy->consumeMotionDown();
11539
11540 const MotionEvent secondFingerDownEvent =
Siarhei Vishniakoua16e3a22022-03-02 15:26:40 -080011541 MotionEventBuilder(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
Prabir Pradhan07e05b62021-11-19 03:57:24 -080011542 .eventTime(systemTime(SYSTEM_TIME_MONOTONIC))
Siarhei Vishniakou6d73f832022-07-21 17:27:03 -070011543 .pointer(PointerBuilder(/*id=*/0, ToolType::FINGER).x(50).y(50))
11544 .pointer(PointerBuilder(/*id=*/1, ToolType::FINGER).x(150).y(50))
Prabir Pradhan07e05b62021-11-19 03:57:24 -080011545 .build();
11546 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070011547 injectMotionEvent(*mDispatcher, secondFingerDownEvent, INJECT_EVENT_TIMEOUT,
Prabir Pradhan07e05b62021-11-19 03:57:24 -080011548 InputEventInjectionSync::WAIT_FOR_RESULT))
11549 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
11550 windowRight->consumeMotionDown();
Harry Cutts33476232023-01-30 19:57:29 +000011551 spy->consumeMotionPointerDown(/*pointerIndex=*/1);
Prabir Pradhan07e05b62021-11-19 03:57:24 -080011552}
11553
11554/**
11555 * When the first pointer lands outside the spy window and the second pointer lands inside it, the
11556 * the spy should receive the second pointer with ACTION_DOWN.
11557 */
11558TEST_F(InputDispatcherSpyWindowTest, ReceivesSecondPointerAsDown) {
11559 auto window = createForeground();
11560 window->setFrame({0, 0, 200, 200});
Prabir Pradhan4d5c52f2022-01-31 08:52:10 -080011561 auto spyRight = createSpy();
Prabir Pradhan07e05b62021-11-19 03:57:24 -080011562 spyRight->setFrame({100, 0, 200, 200});
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070011563 mDispatcher->onWindowInfosChanged({{*spyRight->getInfo(), *window->getInfo()}, {}, 0, 0});
Prabir Pradhan07e05b62021-11-19 03:57:24 -080011564
11565 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070011566 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
Prabir Pradhan07e05b62021-11-19 03:57:24 -080011567 {50, 50}))
11568 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
11569 window->consumeMotionDown();
11570 spyRight->assertNoEvents();
11571
11572 const MotionEvent secondFingerDownEvent =
Siarhei Vishniakoua16e3a22022-03-02 15:26:40 -080011573 MotionEventBuilder(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
Prabir Pradhan07e05b62021-11-19 03:57:24 -080011574 .eventTime(systemTime(SYSTEM_TIME_MONOTONIC))
Siarhei Vishniakou6d73f832022-07-21 17:27:03 -070011575 .pointer(PointerBuilder(/*id=*/0, ToolType::FINGER).x(50).y(50))
11576 .pointer(PointerBuilder(/*id=*/1, ToolType::FINGER).x(150).y(50))
Prabir Pradhan07e05b62021-11-19 03:57:24 -080011577 .build();
11578 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070011579 injectMotionEvent(*mDispatcher, secondFingerDownEvent, INJECT_EVENT_TIMEOUT,
Prabir Pradhan07e05b62021-11-19 03:57:24 -080011580 InputEventInjectionSync::WAIT_FOR_RESULT))
11581 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
Harry Cutts33476232023-01-30 19:57:29 +000011582 window->consumeMotionPointerDown(/*pointerIndex=*/1);
Prabir Pradhan07e05b62021-11-19 03:57:24 -080011583 spyRight->consumeMotionDown();
11584}
11585
Prabir Pradhan1376fcd2022-01-21 09:56:35 -080011586/**
11587 * The spy window should not be able to affect whether or not touches are split. Only the foreground
11588 * windows should be allowed to control split touch.
11589 */
11590TEST_F(InputDispatcherSpyWindowTest, SplitIfNoForegroundWindowTouched) {
Prabir Pradhan76bdecb2022-01-31 11:14:15 -080011591 // This spy window prevents touch splitting. However, we still expect to split touches
Prabir Pradhan1376fcd2022-01-21 09:56:35 -080011592 // because a foreground window has not disabled splitting.
Prabir Pradhan4d5c52f2022-01-31 08:52:10 -080011593 auto spy = createSpy();
Prabir Pradhan76bdecb2022-01-31 11:14:15 -080011594 spy->setPreventSplitting(true);
Prabir Pradhan1376fcd2022-01-21 09:56:35 -080011595
Prabir Pradhan1376fcd2022-01-21 09:56:35 -080011596 auto window = createForeground();
11597 window->setFrame(Rect(0, 0, 100, 100));
Prabir Pradhan1376fcd2022-01-21 09:56:35 -080011598
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070011599 mDispatcher->onWindowInfosChanged({{*spy->getInfo(), *window->getInfo()}, {}, 0, 0});
Prabir Pradhan1376fcd2022-01-21 09:56:35 -080011600
11601 // First finger down, no window touched.
11602 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070011603 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
Prabir Pradhan1376fcd2022-01-21 09:56:35 -080011604 {100, 200}))
11605 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
11606 spy->consumeMotionDown(ADISPLAY_ID_DEFAULT);
11607 window->assertNoEvents();
11608
11609 // Second finger down on window, the window should receive touch down.
11610 const MotionEvent secondFingerDownEvent =
Siarhei Vishniakoua16e3a22022-03-02 15:26:40 -080011611 MotionEventBuilder(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
Prabir Pradhan1376fcd2022-01-21 09:56:35 -080011612 .displayId(ADISPLAY_ID_DEFAULT)
11613 .eventTime(systemTime(SYSTEM_TIME_MONOTONIC))
Siarhei Vishniakou6d73f832022-07-21 17:27:03 -070011614 .pointer(PointerBuilder(/*id=*/0, ToolType::FINGER).x(100).y(200))
11615 .pointer(PointerBuilder(/*id=*/1, ToolType::FINGER).x(50).y(50))
Prabir Pradhan1376fcd2022-01-21 09:56:35 -080011616 .build();
11617 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070011618 injectMotionEvent(*mDispatcher, secondFingerDownEvent, INJECT_EVENT_TIMEOUT,
Prabir Pradhan1376fcd2022-01-21 09:56:35 -080011619 InputEventInjectionSync::WAIT_FOR_RESULT))
11620 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
11621
11622 window->consumeMotionDown(ADISPLAY_ID_DEFAULT);
Harry Cutts33476232023-01-30 19:57:29 +000011623 spy->consumeMotionPointerDown(/*pointerIndex=*/1);
Prabir Pradhan1376fcd2022-01-21 09:56:35 -080011624}
11625
11626/**
11627 * A spy window will usually be implemented as an un-focusable window. Verify that these windows
11628 * do not receive key events.
11629 */
11630TEST_F(InputDispatcherSpyWindowTest, UnfocusableSpyDoesNotReceiveKeyEvents) {
Prabir Pradhan4d5c52f2022-01-31 08:52:10 -080011631 auto spy = createSpy();
Prabir Pradhan1376fcd2022-01-21 09:56:35 -080011632 spy->setFocusable(false);
11633
11634 auto window = createForeground();
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070011635 mDispatcher->onWindowInfosChanged({{*spy->getInfo(), *window->getInfo()}, {}, 0, 0});
Prabir Pradhan1376fcd2022-01-21 09:56:35 -080011636 setFocusedWindow(window);
11637 window->consumeFocusEvent(true);
11638
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070011639 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectKeyDown(*mDispatcher))
Prabir Pradhan1376fcd2022-01-21 09:56:35 -080011640 << "Inject key event should return InputEventInjectionResult::SUCCEEDED";
11641 window->consumeKeyDown(ADISPLAY_ID_NONE);
11642
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070011643 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectKeyUp(*mDispatcher))
Prabir Pradhan1376fcd2022-01-21 09:56:35 -080011644 << "Inject key event should return InputEventInjectionResult::SUCCEEDED";
11645 window->consumeKeyUp(ADISPLAY_ID_NONE);
11646
11647 spy->assertNoEvents();
11648}
11649
Vaibhav Devmurariff798f32022-05-09 23:45:04 +000011650using InputDispatcherPilferPointersTest = InputDispatcherSpyWindowTest;
11651
11652/**
11653 * A spy window can pilfer pointers. When this happens, touch gestures used by the spy window that
11654 * are currently sent to any other windows - including other spy windows - will also be cancelled.
11655 */
11656TEST_F(InputDispatcherPilferPointersTest, PilferPointers) {
11657 auto window = createForeground();
11658 auto spy1 = createSpy();
11659 auto spy2 = createSpy();
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070011660 mDispatcher->onWindowInfosChanged(
11661 {{*spy1->getInfo(), *spy2->getInfo(), *window->getInfo()}, {}, 0, 0});
Vaibhav Devmurariff798f32022-05-09 23:45:04 +000011662
11663 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070011664 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT))
Vaibhav Devmurariff798f32022-05-09 23:45:04 +000011665 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
11666 window->consumeMotionDown();
11667 spy1->consumeMotionDown();
11668 spy2->consumeMotionDown();
11669
11670 // Pilfer pointers from the second spy window.
11671 EXPECT_EQ(OK, mDispatcher->pilferPointers(spy2->getToken()));
11672 spy2->assertNoEvents();
11673 spy1->consumeMotionCancel();
11674 window->consumeMotionCancel();
11675
11676 // The rest of the gesture should only be sent to the second spy window.
11677 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070011678 injectMotionEvent(*mDispatcher, AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN,
Vaibhav Devmurariff798f32022-05-09 23:45:04 +000011679 ADISPLAY_ID_DEFAULT))
11680 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
11681 spy2->consumeMotionMove();
11682 spy1->assertNoEvents();
11683 window->assertNoEvents();
11684}
11685
11686/**
11687 * A spy window can pilfer pointers for a gesture even after the foreground window has been removed
11688 * in the middle of the gesture.
11689 */
11690TEST_F(InputDispatcherPilferPointersTest, CanPilferAfterWindowIsRemovedMidStream) {
11691 auto window = createForeground();
11692 auto spy = createSpy();
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070011693 mDispatcher->onWindowInfosChanged({{*spy->getInfo(), *window->getInfo()}, {}, 0, 0});
Vaibhav Devmurariff798f32022-05-09 23:45:04 +000011694
11695 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070011696 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT))
Vaibhav Devmurariff798f32022-05-09 23:45:04 +000011697 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
11698 window->consumeMotionDown(ADISPLAY_ID_DEFAULT);
11699 spy->consumeMotionDown(ADISPLAY_ID_DEFAULT);
11700
11701 window->releaseChannel();
11702
11703 EXPECT_EQ(OK, mDispatcher->pilferPointers(spy->getToken()));
11704
11705 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070011706 injectMotionUp(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT))
Vaibhav Devmurariff798f32022-05-09 23:45:04 +000011707 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
11708 spy->consumeMotionUp(ADISPLAY_ID_DEFAULT);
11709}
11710
11711/**
11712 * After a spy window pilfers pointers, new pointers that go down in its bounds should be sent to
11713 * the spy, but not to any other windows.
11714 */
11715TEST_F(InputDispatcherPilferPointersTest, ContinuesToReceiveGestureAfterPilfer) {
11716 auto spy = createSpy();
11717 auto window = createForeground();
11718
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070011719 mDispatcher->onWindowInfosChanged({{*spy->getInfo(), *window->getInfo()}, {}, 0, 0});
Vaibhav Devmurariff798f32022-05-09 23:45:04 +000011720
11721 // First finger down on the window and the spy.
11722 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070011723 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
Vaibhav Devmurariff798f32022-05-09 23:45:04 +000011724 {100, 200}))
11725 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
11726 spy->consumeMotionDown();
11727 window->consumeMotionDown();
11728
11729 // Spy window pilfers the pointers.
11730 EXPECT_EQ(OK, mDispatcher->pilferPointers(spy->getToken()));
11731 window->consumeMotionCancel();
11732
11733 // Second finger down on the window and spy, but the window should not receive the pointer down.
11734 const MotionEvent secondFingerDownEvent =
11735 MotionEventBuilder(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
11736 .displayId(ADISPLAY_ID_DEFAULT)
11737 .eventTime(systemTime(SYSTEM_TIME_MONOTONIC))
Siarhei Vishniakou6d73f832022-07-21 17:27:03 -070011738 .pointer(PointerBuilder(/*id=*/0, ToolType::FINGER).x(100).y(200))
11739 .pointer(PointerBuilder(/*id=*/1, ToolType::FINGER).x(50).y(50))
Vaibhav Devmurariff798f32022-05-09 23:45:04 +000011740 .build();
11741 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070011742 injectMotionEvent(*mDispatcher, secondFingerDownEvent, INJECT_EVENT_TIMEOUT,
Vaibhav Devmurariff798f32022-05-09 23:45:04 +000011743 InputEventInjectionSync::WAIT_FOR_RESULT))
11744 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
11745
Harry Cutts33476232023-01-30 19:57:29 +000011746 spy->consumeMotionPointerDown(/*pointerIndex=*/1);
Vaibhav Devmurariff798f32022-05-09 23:45:04 +000011747
11748 // Third finger goes down outside all windows, so injection should fail.
11749 const MotionEvent thirdFingerDownEvent =
11750 MotionEventBuilder(POINTER_2_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
11751 .displayId(ADISPLAY_ID_DEFAULT)
11752 .eventTime(systemTime(SYSTEM_TIME_MONOTONIC))
Siarhei Vishniakou6d73f832022-07-21 17:27:03 -070011753 .pointer(PointerBuilder(/*id=*/0, ToolType::FINGER).x(100).y(200))
11754 .pointer(PointerBuilder(/*id=*/1, ToolType::FINGER).x(50).y(50))
11755 .pointer(PointerBuilder(/*id=*/2, ToolType::FINGER).x(-5).y(-5))
Vaibhav Devmurariff798f32022-05-09 23:45:04 +000011756 .build();
11757 ASSERT_EQ(InputEventInjectionResult::FAILED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070011758 injectMotionEvent(*mDispatcher, thirdFingerDownEvent, INJECT_EVENT_TIMEOUT,
Vaibhav Devmurariff798f32022-05-09 23:45:04 +000011759 InputEventInjectionSync::WAIT_FOR_RESULT))
Siarhei Vishniakou1ae72f12023-01-29 12:55:30 -080011760 << "Inject motion event should return InputEventInjectionResult::FAILED";
Vaibhav Devmurariff798f32022-05-09 23:45:04 +000011761
11762 spy->assertNoEvents();
11763 window->assertNoEvents();
11764}
11765
11766/**
11767 * After a spy window pilfers pointers, only the pointers used by the spy should be canceled
11768 */
11769TEST_F(InputDispatcherPilferPointersTest, PartiallyPilferRequiredPointers) {
11770 auto spy = createSpy();
11771 spy->setFrame(Rect(0, 0, 100, 100));
11772 auto window = createForeground();
11773 window->setFrame(Rect(0, 0, 200, 200));
11774
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070011775 mDispatcher->onWindowInfosChanged({{*spy->getInfo(), *window->getInfo()}, {}, 0, 0});
Vaibhav Devmurariff798f32022-05-09 23:45:04 +000011776
11777 // First finger down on the window only
11778 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070011779 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
Vaibhav Devmurariff798f32022-05-09 23:45:04 +000011780 {150, 150}))
11781 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
11782 window->consumeMotionDown();
11783
11784 // Second finger down on the spy and window
11785 const MotionEvent secondFingerDownEvent =
11786 MotionEventBuilder(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
11787 .displayId(ADISPLAY_ID_DEFAULT)
11788 .eventTime(systemTime(SYSTEM_TIME_MONOTONIC))
Siarhei Vishniakou6d73f832022-07-21 17:27:03 -070011789 .pointer(PointerBuilder(/*id=*/0, ToolType::FINGER).x(150).y(150))
11790 .pointer(PointerBuilder(/*id=*/1, ToolType::FINGER).x(10).y(10))
Vaibhav Devmurariff798f32022-05-09 23:45:04 +000011791 .build();
11792 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070011793 injectMotionEvent(*mDispatcher, secondFingerDownEvent, INJECT_EVENT_TIMEOUT,
Vaibhav Devmurariff798f32022-05-09 23:45:04 +000011794 InputEventInjectionSync::WAIT_FOR_RESULT))
11795 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
11796 spy->consumeMotionDown();
11797 window->consumeMotionPointerDown(1);
11798
11799 // Third finger down on the spy and window
11800 const MotionEvent thirdFingerDownEvent =
11801 MotionEventBuilder(POINTER_2_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
11802 .displayId(ADISPLAY_ID_DEFAULT)
11803 .eventTime(systemTime(SYSTEM_TIME_MONOTONIC))
Siarhei Vishniakou6d73f832022-07-21 17:27:03 -070011804 .pointer(PointerBuilder(/*id=*/0, ToolType::FINGER).x(150).y(150))
11805 .pointer(PointerBuilder(/*id=*/1, ToolType::FINGER).x(10).y(10))
11806 .pointer(PointerBuilder(/*id=*/2, ToolType::FINGER).x(50).y(50))
Vaibhav Devmurariff798f32022-05-09 23:45:04 +000011807 .build();
11808 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070011809 injectMotionEvent(*mDispatcher, thirdFingerDownEvent, INJECT_EVENT_TIMEOUT,
Vaibhav Devmurariff798f32022-05-09 23:45:04 +000011810 InputEventInjectionSync::WAIT_FOR_RESULT))
11811 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
11812 spy->consumeMotionPointerDown(1);
11813 window->consumeMotionPointerDown(2);
11814
11815 // Spy window pilfers the pointers.
11816 EXPECT_EQ(OK, mDispatcher->pilferPointers(spy->getToken()));
Harry Cutts101ee9b2023-07-06 18:04:14 +000011817 window->consumeMotionPointerUp(/*idx=*/2, ADISPLAY_ID_DEFAULT, AMOTION_EVENT_FLAG_CANCELED);
11818 window->consumeMotionPointerUp(/*idx=*/1, ADISPLAY_ID_DEFAULT, AMOTION_EVENT_FLAG_CANCELED);
Vaibhav Devmurariff798f32022-05-09 23:45:04 +000011819
11820 spy->assertNoEvents();
11821 window->assertNoEvents();
11822}
11823
11824/**
11825 * After a spy window pilfers pointers, all pilfered pointers that have already been dispatched to
11826 * other windows should be canceled. If this results in the cancellation of all pointers for some
11827 * window, then that window should receive ACTION_CANCEL.
11828 */
11829TEST_F(InputDispatcherPilferPointersTest, PilferAllRequiredPointers) {
11830 auto spy = createSpy();
11831 spy->setFrame(Rect(0, 0, 100, 100));
11832 auto window = createForeground();
11833 window->setFrame(Rect(0, 0, 200, 200));
11834
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070011835 mDispatcher->onWindowInfosChanged({{*spy->getInfo(), *window->getInfo()}, {}, 0, 0});
Vaibhav Devmurariff798f32022-05-09 23:45:04 +000011836
11837 // First finger down on both spy and window
11838 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070011839 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
Vaibhav Devmurariff798f32022-05-09 23:45:04 +000011840 {10, 10}))
11841 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
11842 window->consumeMotionDown();
11843 spy->consumeMotionDown();
11844
11845 // Second finger down on the spy and window
11846 const MotionEvent secondFingerDownEvent =
11847 MotionEventBuilder(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
11848 .displayId(ADISPLAY_ID_DEFAULT)
11849 .eventTime(systemTime(SYSTEM_TIME_MONOTONIC))
Siarhei Vishniakou6d73f832022-07-21 17:27:03 -070011850 .pointer(PointerBuilder(/*id=*/0, ToolType::FINGER).x(10).y(10))
11851 .pointer(PointerBuilder(/*id=*/1, ToolType::FINGER).x(50).y(50))
Vaibhav Devmurariff798f32022-05-09 23:45:04 +000011852 .build();
11853 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070011854 injectMotionEvent(*mDispatcher, secondFingerDownEvent, INJECT_EVENT_TIMEOUT,
Vaibhav Devmurariff798f32022-05-09 23:45:04 +000011855 InputEventInjectionSync::WAIT_FOR_RESULT))
11856 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
11857 spy->consumeMotionPointerDown(1);
11858 window->consumeMotionPointerDown(1);
11859
11860 // Spy window pilfers the pointers.
11861 EXPECT_EQ(OK, mDispatcher->pilferPointers(spy->getToken()));
11862 window->consumeMotionCancel();
11863
11864 spy->assertNoEvents();
11865 window->assertNoEvents();
11866}
11867
11868/**
11869 * After a spy window pilfers pointers, new pointers that are not touching the spy window can still
11870 * be sent to other windows
11871 */
11872TEST_F(InputDispatcherPilferPointersTest, CanReceivePointersAfterPilfer) {
11873 auto spy = createSpy();
11874 spy->setFrame(Rect(0, 0, 100, 100));
11875 auto window = createForeground();
11876 window->setFrame(Rect(0, 0, 200, 200));
11877
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070011878 mDispatcher->onWindowInfosChanged({{*spy->getInfo(), *window->getInfo()}, {}, 0, 0});
Vaibhav Devmurariff798f32022-05-09 23:45:04 +000011879
11880 // First finger down on both window and spy
11881 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070011882 injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
Vaibhav Devmurariff798f32022-05-09 23:45:04 +000011883 {10, 10}))
11884 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
11885 window->consumeMotionDown();
11886 spy->consumeMotionDown();
11887
11888 // Spy window pilfers the pointers.
11889 EXPECT_EQ(OK, mDispatcher->pilferPointers(spy->getToken()));
11890 window->consumeMotionCancel();
11891
11892 // Second finger down on the window only
11893 const MotionEvent secondFingerDownEvent =
11894 MotionEventBuilder(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
11895 .displayId(ADISPLAY_ID_DEFAULT)
11896 .eventTime(systemTime(SYSTEM_TIME_MONOTONIC))
Siarhei Vishniakou6d73f832022-07-21 17:27:03 -070011897 .pointer(PointerBuilder(/*id=*/0, ToolType::FINGER).x(10).y(10))
11898 .pointer(PointerBuilder(/*id=*/1, ToolType::FINGER).x(150).y(150))
Vaibhav Devmurariff798f32022-05-09 23:45:04 +000011899 .build();
11900 ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070011901 injectMotionEvent(*mDispatcher, secondFingerDownEvent, INJECT_EVENT_TIMEOUT,
Vaibhav Devmurariff798f32022-05-09 23:45:04 +000011902 InputEventInjectionSync::WAIT_FOR_RESULT))
11903 << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
11904 window->consumeMotionDown();
11905 window->assertNoEvents();
11906
11907 // TODO(b/232530217): do not send the unnecessary MOVE event and delete the next line
11908 spy->consumeMotionMove();
11909 spy->assertNoEvents();
11910}
11911
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -070011912/**
11913 * A window on the left and a window on the right. Also, a spy window that's above all of the
11914 * windows, and spanning both left and right windows.
11915 * Send simultaneous motion streams from two different devices, one to the left window, and another
11916 * to the right window.
11917 * Pilfer from spy window.
11918 * Check that the pilfering only affects the pointers that are actually being received by the spy.
11919 */
11920TEST_F(InputDispatcherPilferPointersTest, MultiDevicePilfer) {
11921 sp<FakeWindowHandle> spy = createSpy();
11922 spy->setFrame(Rect(0, 0, 200, 200));
11923 sp<FakeWindowHandle> leftWindow = createForeground();
11924 leftWindow->setFrame(Rect(0, 0, 100, 100));
11925
11926 sp<FakeWindowHandle> rightWindow = createForeground();
11927 rightWindow->setFrame(Rect(100, 0, 200, 100));
11928
11929 constexpr int32_t stylusDeviceId = 1;
11930 constexpr int32_t touchDeviceId = 2;
11931
11932 mDispatcher->onWindowInfosChanged(
11933 {{*spy->getInfo(), *leftWindow->getInfo(), *rightWindow->getInfo()}, {}, 0, 0});
11934
11935 // Stylus down on left window and spy
11936 mDispatcher->notifyMotion(MotionArgsBuilder(AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_STYLUS)
11937 .deviceId(stylusDeviceId)
11938 .pointer(PointerBuilder(0, ToolType::STYLUS).x(50).y(50))
11939 .build());
11940 leftWindow->consumeMotionEvent(
11941 AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(stylusDeviceId)));
11942 spy->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(stylusDeviceId)));
11943
11944 // Finger down on right window and spy - but spy already has stylus
11945 mDispatcher->notifyMotion(
11946 MotionArgsBuilder(AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
11947 .deviceId(touchDeviceId)
11948 .pointer(PointerBuilder(0, ToolType::FINGER).x(150).y(50))
11949 .build());
11950 rightWindow->consumeMotionEvent(
11951 AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(touchDeviceId)));
Siarhei Vishniakou2899c552023-07-10 18:20:46 -070011952 spy->assertNoEvents();
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -070011953
11954 // Act: pilfer from spy. Spy is currently receiving touch events.
11955 EXPECT_EQ(OK, mDispatcher->pilferPointers(spy->getToken()));
Siarhei Vishniakou2899c552023-07-10 18:20:46 -070011956 leftWindow->consumeMotionEvent(
11957 AllOf(WithMotionAction(ACTION_CANCEL), WithDeviceId(stylusDeviceId)));
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -070011958 rightWindow->consumeMotionEvent(
11959 AllOf(WithMotionAction(ACTION_CANCEL), WithDeviceId(touchDeviceId)));
11960
11961 // Continue movements from both stylus and touch. Touch will be delivered to spy, but not stylus
11962 mDispatcher->notifyMotion(MotionArgsBuilder(AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_STYLUS)
11963 .deviceId(stylusDeviceId)
11964 .pointer(PointerBuilder(0, ToolType::STYLUS).x(51).y(52))
11965 .build());
11966 mDispatcher->notifyMotion(
11967 MotionArgsBuilder(AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN)
11968 .deviceId(touchDeviceId)
11969 .pointer(PointerBuilder(0, ToolType::FINGER).x(151).y(52))
11970 .build());
Siarhei Vishniakou2899c552023-07-10 18:20:46 -070011971 spy->consumeMotionEvent(AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(stylusDeviceId)));
Siarhei Vishniakou0b251a32023-09-20 16:24:42 -070011972
11973 spy->assertNoEvents();
11974 leftWindow->assertNoEvents();
11975 rightWindow->assertNoEvents();
11976}
11977
Prabir Pradhan9cd9eb62023-11-22 17:58:06 +000011978TEST_F(InputDispatcherPilferPointersTest, NoPilferingWithHoveringPointers) {
11979 auto window = createForeground();
11980 auto spy = createSpy();
11981 mDispatcher->onWindowInfosChanged({{*spy->getInfo(), *window->getInfo()}, {}, 0, 0});
11982
11983 mDispatcher->notifyMotion(
11984 MotionArgsBuilder(ACTION_HOVER_ENTER, AINPUT_SOURCE_MOUSE)
11985 .deviceId(1)
11986 .pointer(PointerBuilder(/*id=*/0, ToolType::MOUSE).x(100).y(200))
11987 .build());
11988 window->consumeMotionEvent(WithMotionAction(ACTION_HOVER_ENTER));
11989 spy->consumeMotionEvent(WithMotionAction(ACTION_HOVER_ENTER));
11990
11991 // Pilfer pointers from the spy window should fail.
11992 EXPECT_NE(OK, mDispatcher->pilferPointers(spy->getToken()));
11993 spy->assertNoEvents();
11994 window->assertNoEvents();
11995}
11996
Prabir Pradhand65552b2021-10-07 11:23:50 -070011997class InputDispatcherStylusInterceptorTest : public InputDispatcherTest {
11998public:
11999 std::pair<sp<FakeWindowHandle>, sp<FakeWindowHandle>> setupStylusOverlayScenario() {
12000 std::shared_ptr<FakeApplicationHandle> overlayApplication =
12001 std::make_shared<FakeApplicationHandle>();
12002 sp<FakeWindowHandle> overlay =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -070012003 sp<FakeWindowHandle>::make(overlayApplication, mDispatcher,
12004 "Stylus interceptor window", ADISPLAY_ID_DEFAULT);
Prabir Pradhand65552b2021-10-07 11:23:50 -070012005 overlay->setFocusable(false);
Prabir Pradhanaeebeb42023-06-13 19:53:03 +000012006 overlay->setOwnerInfo(gui::Pid{111}, gui::Uid{111});
Prabir Pradhan4d5c52f2022-01-31 08:52:10 -080012007 overlay->setTouchable(false);
Prabir Pradhan51e7db02022-02-07 06:02:57 -080012008 overlay->setInterceptsStylus(true);
Prabir Pradhand65552b2021-10-07 11:23:50 -070012009 overlay->setTrustedOverlay(true);
12010
12011 std::shared_ptr<FakeApplicationHandle> application =
12012 std::make_shared<FakeApplicationHandle>();
12013 sp<FakeWindowHandle> window =
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -070012014 sp<FakeWindowHandle>::make(application, mDispatcher, "Application window",
12015 ADISPLAY_ID_DEFAULT);
Prabir Pradhand65552b2021-10-07 11:23:50 -070012016 window->setFocusable(true);
Prabir Pradhanaeebeb42023-06-13 19:53:03 +000012017 window->setOwnerInfo(gui::Pid{222}, gui::Uid{222});
Prabir Pradhand65552b2021-10-07 11:23:50 -070012018
12019 mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070012020 mDispatcher->onWindowInfosChanged({{*overlay->getInfo(), *window->getInfo()}, {}, 0, 0});
Prabir Pradhand65552b2021-10-07 11:23:50 -070012021 setFocusedWindow(window);
Harry Cutts33476232023-01-30 19:57:29 +000012022 window->consumeFocusEvent(/*hasFocus=*/true, /*inTouchMode=*/true);
Prabir Pradhand65552b2021-10-07 11:23:50 -070012023 return {std::move(overlay), std::move(window)};
12024 }
12025
12026 void sendFingerEvent(int32_t action) {
Prabir Pradhan678438e2023-04-13 19:32:51 +000012027 mDispatcher->notifyMotion(
Prabir Pradhand65552b2021-10-07 11:23:50 -070012028 generateMotionArgs(action, AINPUT_SOURCE_TOUCHSCREEN | AINPUT_SOURCE_STYLUS,
Prabir Pradhan678438e2023-04-13 19:32:51 +000012029 ADISPLAY_ID_DEFAULT, {PointF{20, 20}}));
Prabir Pradhand65552b2021-10-07 11:23:50 -070012030 }
12031
12032 void sendStylusEvent(int32_t action) {
12033 NotifyMotionArgs motionArgs =
12034 generateMotionArgs(action, AINPUT_SOURCE_TOUCHSCREEN | AINPUT_SOURCE_STYLUS,
12035 ADISPLAY_ID_DEFAULT, {PointF{30, 40}});
Siarhei Vishniakou6d73f832022-07-21 17:27:03 -070012036 motionArgs.pointerProperties[0].toolType = ToolType::STYLUS;
Prabir Pradhan678438e2023-04-13 19:32:51 +000012037 mDispatcher->notifyMotion(motionArgs);
Prabir Pradhand65552b2021-10-07 11:23:50 -070012038 }
12039};
12040
Prabir Pradhana3ab87a2022-01-27 10:00:21 -080012041using InputDispatcherStylusInterceptorDeathTest = InputDispatcherStylusInterceptorTest;
12042
12043TEST_F(InputDispatcherStylusInterceptorDeathTest, UntrustedOverlay_AbortsDispatcher) {
Siarhei Vishniakouad3b6822023-06-22 14:17:35 -070012044 testing::GTEST_FLAG(death_test_style) = "threadsafe";
Prabir Pradhana3ab87a2022-01-27 10:00:21 -080012045 ScopedSilentDeath _silentDeath;
12046
Prabir Pradhand65552b2021-10-07 11:23:50 -070012047 auto [overlay, window] = setupStylusOverlayScenario();
12048 overlay->setTrustedOverlay(false);
12049 // Configuring an untrusted overlay as a stylus interceptor should cause Dispatcher to abort.
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070012050 ASSERT_DEATH(mDispatcher->onWindowInfosChanged(
12051 {{*overlay->getInfo(), *window->getInfo()}, {}, 0, 0}),
Prabir Pradhand65552b2021-10-07 11:23:50 -070012052 ".* not a trusted overlay");
12053}
12054
12055TEST_F(InputDispatcherStylusInterceptorTest, ConsmesOnlyStylusEvents) {
12056 auto [overlay, window] = setupStylusOverlayScenario();
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070012057 mDispatcher->onWindowInfosChanged({{*overlay->getInfo(), *window->getInfo()}, {}, 0, 0});
Prabir Pradhand65552b2021-10-07 11:23:50 -070012058
12059 sendStylusEvent(AMOTION_EVENT_ACTION_DOWN);
12060 overlay->consumeMotionDown();
12061 sendStylusEvent(AMOTION_EVENT_ACTION_UP);
12062 overlay->consumeMotionUp();
12063
12064 sendFingerEvent(AMOTION_EVENT_ACTION_DOWN);
12065 window->consumeMotionDown();
12066 sendFingerEvent(AMOTION_EVENT_ACTION_UP);
12067 window->consumeMotionUp();
12068
12069 overlay->assertNoEvents();
12070 window->assertNoEvents();
12071}
12072
12073TEST_F(InputDispatcherStylusInterceptorTest, SpyWindowStylusInterceptor) {
12074 auto [overlay, window] = setupStylusOverlayScenario();
Prabir Pradhan51e7db02022-02-07 06:02:57 -080012075 overlay->setSpy(true);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070012076 mDispatcher->onWindowInfosChanged({{*overlay->getInfo(), *window->getInfo()}, {}, 0, 0});
Prabir Pradhand65552b2021-10-07 11:23:50 -070012077
12078 sendStylusEvent(AMOTION_EVENT_ACTION_DOWN);
12079 overlay->consumeMotionDown();
12080 window->consumeMotionDown();
12081 sendStylusEvent(AMOTION_EVENT_ACTION_UP);
12082 overlay->consumeMotionUp();
12083 window->consumeMotionUp();
12084
12085 sendFingerEvent(AMOTION_EVENT_ACTION_DOWN);
12086 window->consumeMotionDown();
12087 sendFingerEvent(AMOTION_EVENT_ACTION_UP);
12088 window->consumeMotionUp();
12089
12090 overlay->assertNoEvents();
12091 window->assertNoEvents();
12092}
12093
Prabir Pradhan6dfbf262022-03-14 15:24:30 +000012094/**
12095 * Set up a scenario to test the behavior used by the stylus handwriting detection feature.
12096 * The scenario is as follows:
12097 * - The stylus interceptor overlay is configured as a spy window.
12098 * - The stylus interceptor spy receives the start of a new stylus gesture.
12099 * - It pilfers pointers and then configures itself to no longer be a spy.
12100 * - The stylus interceptor continues to receive the rest of the gesture.
12101 */
12102TEST_F(InputDispatcherStylusInterceptorTest, StylusHandwritingScenario) {
12103 auto [overlay, window] = setupStylusOverlayScenario();
12104 overlay->setSpy(true);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070012105 mDispatcher->onWindowInfosChanged({{*overlay->getInfo(), *window->getInfo()}, {}, 0, 0});
Prabir Pradhan6dfbf262022-03-14 15:24:30 +000012106
12107 sendStylusEvent(AMOTION_EVENT_ACTION_DOWN);
12108 overlay->consumeMotionDown();
12109 window->consumeMotionDown();
12110
12111 // The interceptor pilfers the pointers.
12112 EXPECT_EQ(OK, mDispatcher->pilferPointers(overlay->getToken()));
12113 window->consumeMotionCancel();
12114
12115 // The interceptor configures itself so that it is no longer a spy.
12116 overlay->setSpy(false);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070012117 mDispatcher->onWindowInfosChanged({{*overlay->getInfo(), *window->getInfo()}, {}, 0, 0});
Prabir Pradhan6dfbf262022-03-14 15:24:30 +000012118
12119 // It continues to receive the rest of the stylus gesture.
12120 sendStylusEvent(AMOTION_EVENT_ACTION_MOVE);
12121 overlay->consumeMotionMove();
12122 sendStylusEvent(AMOTION_EVENT_ACTION_UP);
12123 overlay->consumeMotionUp();
12124
12125 window->assertNoEvents();
12126}
12127
Prabir Pradhan5735a322022-04-11 17:23:34 +000012128struct User {
Prabir Pradhanaeebeb42023-06-13 19:53:03 +000012129 gui::Pid mPid;
Prabir Pradhan8a5c41d2023-06-08 19:13:46 +000012130 gui::Uid mUid;
Prabir Pradhan5735a322022-04-11 17:23:34 +000012131 uint32_t mPolicyFlags{DEFAULT_POLICY_FLAGS};
12132 std::unique_ptr<InputDispatcher>& mDispatcher;
12133
Prabir Pradhanaeebeb42023-06-13 19:53:03 +000012134 User(std::unique_ptr<InputDispatcher>& dispatcher, gui::Pid pid, gui::Uid uid)
Prabir Pradhan5735a322022-04-11 17:23:34 +000012135 : mPid(pid), mUid(uid), mDispatcher(dispatcher) {}
12136
12137 InputEventInjectionResult injectTargetedMotion(int32_t action) const {
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070012138 return injectMotionEvent(*mDispatcher, action, AINPUT_SOURCE_TOUCHSCREEN,
Prabir Pradhan5735a322022-04-11 17:23:34 +000012139 ADISPLAY_ID_DEFAULT, {100, 200},
12140 {AMOTION_EVENT_INVALID_CURSOR_POSITION,
12141 AMOTION_EVENT_INVALID_CURSOR_POSITION},
12142 INJECT_EVENT_TIMEOUT, InputEventInjectionSync::WAIT_FOR_RESULT,
12143 systemTime(SYSTEM_TIME_MONOTONIC), {mUid}, mPolicyFlags);
12144 }
12145
12146 InputEventInjectionResult injectTargetedKey(int32_t action) const {
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070012147 return inputdispatcher::injectKey(*mDispatcher, action, /*repeatCount=*/0, ADISPLAY_ID_NONE,
Prabir Pradhan5735a322022-04-11 17:23:34 +000012148 InputEventInjectionSync::WAIT_FOR_RESULT,
Harry Cutts33476232023-01-30 19:57:29 +000012149 INJECT_EVENT_TIMEOUT, /*allowKeyRepeat=*/false, {mUid},
Prabir Pradhan5735a322022-04-11 17:23:34 +000012150 mPolicyFlags);
12151 }
12152
Siarhei Vishniakoue3ce4122023-08-23 10:26:46 -070012153 sp<FakeWindowHandle> createWindow(const char* name) const {
Prabir Pradhan5735a322022-04-11 17:23:34 +000012154 std::shared_ptr<FakeApplicationHandle> overlayApplication =
12155 std::make_shared<FakeApplicationHandle>();
Siarhei Vishniakoue3ce4122023-08-23 10:26:46 -070012156 sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(overlayApplication, mDispatcher,
12157 name, ADISPLAY_ID_DEFAULT);
Prabir Pradhan5735a322022-04-11 17:23:34 +000012158 window->setOwnerInfo(mPid, mUid);
12159 return window;
12160 }
12161};
12162
12163using InputDispatcherTargetedInjectionTest = InputDispatcherTest;
12164
12165TEST_F(InputDispatcherTargetedInjectionTest, CanInjectIntoOwnedWindow) {
Prabir Pradhanaeebeb42023-06-13 19:53:03 +000012166 auto owner = User(mDispatcher, gui::Pid{10}, gui::Uid{11});
Siarhei Vishniakoue3ce4122023-08-23 10:26:46 -070012167 auto window = owner.createWindow("Owned window");
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070012168 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Prabir Pradhan5735a322022-04-11 17:23:34 +000012169
12170 EXPECT_EQ(InputEventInjectionResult::SUCCEEDED,
12171 owner.injectTargetedMotion(AMOTION_EVENT_ACTION_DOWN));
12172 window->consumeMotionDown();
12173
12174 setFocusedWindow(window);
12175 window->consumeFocusEvent(true);
12176
12177 EXPECT_EQ(InputEventInjectionResult::SUCCEEDED,
12178 owner.injectTargetedKey(AKEY_EVENT_ACTION_DOWN));
12179 window->consumeKeyDown(ADISPLAY_ID_NONE);
12180}
12181
12182TEST_F(InputDispatcherTargetedInjectionTest, CannotInjectIntoUnownedWindow) {
Prabir Pradhanaeebeb42023-06-13 19:53:03 +000012183 auto owner = User(mDispatcher, gui::Pid{10}, gui::Uid{11});
Siarhei Vishniakoue3ce4122023-08-23 10:26:46 -070012184 auto window = owner.createWindow("Owned window");
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070012185 mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
Prabir Pradhan5735a322022-04-11 17:23:34 +000012186
Prabir Pradhanaeebeb42023-06-13 19:53:03 +000012187 auto rando = User(mDispatcher, gui::Pid{20}, gui::Uid{21});
Prabir Pradhan5735a322022-04-11 17:23:34 +000012188 EXPECT_EQ(InputEventInjectionResult::TARGET_MISMATCH,
12189 rando.injectTargetedMotion(AMOTION_EVENT_ACTION_DOWN));
12190
12191 setFocusedWindow(window);
12192 window->consumeFocusEvent(true);
12193
12194 EXPECT_EQ(InputEventInjectionResult::TARGET_MISMATCH,
12195 rando.injectTargetedKey(AKEY_EVENT_ACTION_DOWN));
12196 window->assertNoEvents();
12197}
12198
12199TEST_F(InputDispatcherTargetedInjectionTest, CanInjectIntoOwnedSpyWindow) {
Prabir Pradhanaeebeb42023-06-13 19:53:03 +000012200 auto owner = User(mDispatcher, gui::Pid{10}, gui::Uid{11});
Siarhei Vishniakoue3ce4122023-08-23 10:26:46 -070012201 auto window = owner.createWindow("Owned window");
12202 auto spy = owner.createWindow("Owned spy");
Prabir Pradhan5735a322022-04-11 17:23:34 +000012203 spy->setSpy(true);
12204 spy->setTrustedOverlay(true);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070012205 mDispatcher->onWindowInfosChanged({{*spy->getInfo(), *window->getInfo()}, {}, 0, 0});
Prabir Pradhan5735a322022-04-11 17:23:34 +000012206
12207 EXPECT_EQ(InputEventInjectionResult::SUCCEEDED,
12208 owner.injectTargetedMotion(AMOTION_EVENT_ACTION_DOWN));
12209 spy->consumeMotionDown();
12210 window->consumeMotionDown();
12211}
12212
12213TEST_F(InputDispatcherTargetedInjectionTest, CannotInjectIntoUnownedSpyWindow) {
Prabir Pradhanaeebeb42023-06-13 19:53:03 +000012214 auto owner = User(mDispatcher, gui::Pid{10}, gui::Uid{11});
Siarhei Vishniakoue3ce4122023-08-23 10:26:46 -070012215 auto window = owner.createWindow("Owned window");
Prabir Pradhan5735a322022-04-11 17:23:34 +000012216
Prabir Pradhanaeebeb42023-06-13 19:53:03 +000012217 auto rando = User(mDispatcher, gui::Pid{20}, gui::Uid{21});
Siarhei Vishniakoue3ce4122023-08-23 10:26:46 -070012218 auto randosSpy = rando.createWindow("Rando's spy");
Prabir Pradhan5735a322022-04-11 17:23:34 +000012219 randosSpy->setSpy(true);
12220 randosSpy->setTrustedOverlay(true);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070012221 mDispatcher->onWindowInfosChanged({{*randosSpy->getInfo(), *window->getInfo()}, {}, 0, 0});
Prabir Pradhan5735a322022-04-11 17:23:34 +000012222
12223 // The event is targeted at owner's window, so injection should succeed, but the spy should
12224 // not receive the event.
12225 EXPECT_EQ(InputEventInjectionResult::SUCCEEDED,
12226 owner.injectTargetedMotion(AMOTION_EVENT_ACTION_DOWN));
12227 randosSpy->assertNoEvents();
12228 window->consumeMotionDown();
12229}
12230
12231TEST_F(InputDispatcherTargetedInjectionTest, CanInjectIntoAnyWindowWhenNotTargeting) {
Prabir Pradhanaeebeb42023-06-13 19:53:03 +000012232 auto owner = User(mDispatcher, gui::Pid{10}, gui::Uid{11});
Siarhei Vishniakoue3ce4122023-08-23 10:26:46 -070012233 auto window = owner.createWindow("Owned window");
Prabir Pradhan5735a322022-04-11 17:23:34 +000012234
Prabir Pradhanaeebeb42023-06-13 19:53:03 +000012235 auto rando = User(mDispatcher, gui::Pid{20}, gui::Uid{21});
Siarhei Vishniakoue3ce4122023-08-23 10:26:46 -070012236 auto randosSpy = rando.createWindow("Rando's spy");
Prabir Pradhan5735a322022-04-11 17:23:34 +000012237 randosSpy->setSpy(true);
12238 randosSpy->setTrustedOverlay(true);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070012239 mDispatcher->onWindowInfosChanged({{*randosSpy->getInfo(), *window->getInfo()}, {}, 0, 0});
Prabir Pradhan5735a322022-04-11 17:23:34 +000012240
12241 // A user that has injection permission can inject into any window.
12242 EXPECT_EQ(InputEventInjectionResult::SUCCEEDED,
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070012243 injectMotionEvent(*mDispatcher, AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN,
Prabir Pradhan5735a322022-04-11 17:23:34 +000012244 ADISPLAY_ID_DEFAULT));
12245 randosSpy->consumeMotionDown();
12246 window->consumeMotionDown();
12247
12248 setFocusedWindow(randosSpy);
12249 randosSpy->consumeFocusEvent(true);
12250
Siarhei Vishniakoub237f9e2023-07-21 16:42:23 -070012251 EXPECT_EQ(InputEventInjectionResult::SUCCEEDED, injectKeyDown(*mDispatcher));
Prabir Pradhan5735a322022-04-11 17:23:34 +000012252 randosSpy->consumeKeyDown(ADISPLAY_ID_NONE);
12253 window->assertNoEvents();
12254}
12255
Siarhei Vishniakou580fb3a2023-05-05 15:02:20 -070012256TEST_F(InputDispatcherTargetedInjectionTest, CannotGenerateActionOutsideToOtherUids) {
Prabir Pradhanaeebeb42023-06-13 19:53:03 +000012257 auto owner = User(mDispatcher, gui::Pid{10}, gui::Uid{11});
Siarhei Vishniakoue3ce4122023-08-23 10:26:46 -070012258 auto window = owner.createWindow("Owned window");
Prabir Pradhan5735a322022-04-11 17:23:34 +000012259
Prabir Pradhanaeebeb42023-06-13 19:53:03 +000012260 auto rando = User(mDispatcher, gui::Pid{20}, gui::Uid{21});
Siarhei Vishniakoue3ce4122023-08-23 10:26:46 -070012261 auto randosWindow = rando.createWindow("Rando's window");
Prabir Pradhan5735a322022-04-11 17:23:34 +000012262 randosWindow->setFrame(Rect{-10, -10, -5, -5});
12263 randosWindow->setWatchOutsideTouch(true);
Siarhei Vishniakouc41de372023-07-20 13:14:26 -070012264 mDispatcher->onWindowInfosChanged({{*randosWindow->getInfo(), *window->getInfo()}, {}, 0, 0});
Prabir Pradhan5735a322022-04-11 17:23:34 +000012265
Siarhei Vishniakou580fb3a2023-05-05 15:02:20 -070012266 // Do not allow generation of ACTION_OUTSIDE events into windows owned by different uids.
Prabir Pradhan5735a322022-04-11 17:23:34 +000012267 EXPECT_EQ(InputEventInjectionResult::SUCCEEDED,
12268 owner.injectTargetedMotion(AMOTION_EVENT_ACTION_DOWN));
12269 window->consumeMotionDown();
Siarhei Vishniakou580fb3a2023-05-05 15:02:20 -070012270 randosWindow->assertNoEvents();
Prabir Pradhan5735a322022-04-11 17:23:34 +000012271}
12272
Prabir Pradhan64f21d22023-11-28 21:19:42 +000012273using InputDispatcherPointerInWindowTest = InputDispatcherTest;
12274
12275TEST_F(InputDispatcherPointerInWindowTest, PointerInWindowWhenHovering) {
12276 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
12277
12278 sp<FakeWindowHandle> left = sp<FakeWindowHandle>::make(application, mDispatcher, "Left Window",
12279 ADISPLAY_ID_DEFAULT);
12280 left->setFrame(Rect(0, 0, 100, 100));
12281 sp<FakeWindowHandle> right = sp<FakeWindowHandle>::make(application, mDispatcher,
12282 "Right Window", ADISPLAY_ID_DEFAULT);
12283 right->setFrame(Rect(100, 0, 200, 100));
12284 sp<FakeWindowHandle> spy =
12285 sp<FakeWindowHandle>::make(application, mDispatcher, "Spy Window", ADISPLAY_ID_DEFAULT);
12286 spy->setFrame(Rect(0, 0, 200, 100));
12287 spy->setTrustedOverlay(true);
12288 spy->setSpy(true);
12289
12290 mDispatcher->onWindowInfosChanged(
12291 {{*spy->getInfo(), *left->getInfo(), *right->getInfo()}, {}, 0, 0});
12292
12293 // Hover into the left window.
12294 mDispatcher->notifyMotion(
12295 MotionArgsBuilder(ACTION_HOVER_ENTER, AINPUT_SOURCE_STYLUS)
12296 .pointer(PointerBuilder(/*id=*/0, ToolType::STYLUS).x(50).y(50))
12297 .build());
12298
12299 left->consumeMotionEvent(WithMotionAction(ACTION_HOVER_ENTER));
12300 spy->consumeMotionEvent(WithMotionAction(ACTION_HOVER_ENTER));
12301
12302 ASSERT_TRUE(mDispatcher->isPointerInWindow(left->getToken(), ADISPLAY_ID_DEFAULT, DEVICE_ID,
12303 /*pointerId=*/0));
12304 ASSERT_TRUE(mDispatcher->isPointerInWindow(spy->getToken(), ADISPLAY_ID_DEFAULT, DEVICE_ID,
12305 /*pointerId=*/0));
12306 ASSERT_FALSE(mDispatcher->isPointerInWindow(right->getToken(), ADISPLAY_ID_DEFAULT, DEVICE_ID,
12307 /*pointerId=*/0));
12308
12309 // Hover move to the right window.
12310 mDispatcher->notifyMotion(
12311 MotionArgsBuilder(ACTION_HOVER_MOVE, AINPUT_SOURCE_STYLUS)
12312 .pointer(PointerBuilder(/*id=*/0, ToolType::STYLUS).x(150).y(50))
12313 .build());
12314
12315 left->consumeMotionEvent(WithMotionAction(ACTION_HOVER_EXIT));
12316 right->consumeMotionEvent(WithMotionAction(ACTION_HOVER_ENTER));
12317 spy->consumeMotionEvent(WithMotionAction(ACTION_HOVER_MOVE));
12318
12319 ASSERT_FALSE(mDispatcher->isPointerInWindow(left->getToken(), ADISPLAY_ID_DEFAULT, DEVICE_ID,
12320 /*pointerId=*/0));
12321 ASSERT_TRUE(mDispatcher->isPointerInWindow(spy->getToken(), ADISPLAY_ID_DEFAULT, DEVICE_ID,
12322 /*pointerId=*/0));
12323 ASSERT_TRUE(mDispatcher->isPointerInWindow(right->getToken(), ADISPLAY_ID_DEFAULT, DEVICE_ID,
12324 /*pointerId=*/0));
12325
12326 // Stop hovering.
12327 mDispatcher->notifyMotion(
12328 MotionArgsBuilder(ACTION_HOVER_EXIT, AINPUT_SOURCE_STYLUS)
12329 .pointer(PointerBuilder(/*id=*/0, ToolType::STYLUS).x(150).y(50))
12330 .build());
12331
12332 right->consumeMotionEvent(WithMotionAction(ACTION_HOVER_EXIT));
12333 spy->consumeMotionEvent(WithMotionAction(ACTION_HOVER_EXIT));
12334
12335 ASSERT_FALSE(mDispatcher->isPointerInWindow(left->getToken(), ADISPLAY_ID_DEFAULT, DEVICE_ID,
12336 /*pointerId=*/0));
12337 ASSERT_FALSE(mDispatcher->isPointerInWindow(spy->getToken(), ADISPLAY_ID_DEFAULT, DEVICE_ID,
12338 /*pointerId=*/0));
12339 ASSERT_FALSE(mDispatcher->isPointerInWindow(right->getToken(), ADISPLAY_ID_DEFAULT, DEVICE_ID,
12340 /*pointerId=*/0));
12341}
12342
12343TEST_F(InputDispatcherPointerInWindowTest, PointerInWindowWithSplitTouch) {
12344 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
12345
12346 sp<FakeWindowHandle> left = sp<FakeWindowHandle>::make(application, mDispatcher, "Left Window",
12347 ADISPLAY_ID_DEFAULT);
12348 left->setFrame(Rect(0, 0, 100, 100));
12349 sp<FakeWindowHandle> right = sp<FakeWindowHandle>::make(application, mDispatcher,
12350 "Right Window", ADISPLAY_ID_DEFAULT);
12351 right->setFrame(Rect(100, 0, 200, 100));
12352 sp<FakeWindowHandle> spy =
12353 sp<FakeWindowHandle>::make(application, mDispatcher, "Spy Window", ADISPLAY_ID_DEFAULT);
12354 spy->setFrame(Rect(0, 0, 200, 100));
12355 spy->setTrustedOverlay(true);
12356 spy->setSpy(true);
12357
12358 mDispatcher->onWindowInfosChanged(
12359 {{*spy->getInfo(), *left->getInfo(), *right->getInfo()}, {}, 0, 0});
12360
12361 // First pointer down on left window.
12362 mDispatcher->notifyMotion(
12363 MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
12364 .pointer(PointerBuilder(/*id=*/0, ToolType::FINGER).x(50).y(50))
12365 .build());
12366
12367 left->consumeMotionDown();
12368 spy->consumeMotionDown();
12369
12370 ASSERT_TRUE(mDispatcher->isPointerInWindow(left->getToken(), ADISPLAY_ID_DEFAULT, DEVICE_ID,
12371 /*pointerId=*/0));
12372 ASSERT_TRUE(mDispatcher->isPointerInWindow(spy->getToken(), ADISPLAY_ID_DEFAULT, DEVICE_ID,
12373 /*pointerId=*/0));
12374 ASSERT_FALSE(mDispatcher->isPointerInWindow(right->getToken(), ADISPLAY_ID_DEFAULT, DEVICE_ID,
12375 /*pointerId=*/0));
12376
12377 // Second pointer down on right window.
12378 mDispatcher->notifyMotion(
12379 MotionArgsBuilder(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
12380 .pointer(PointerBuilder(/*id=*/0, ToolType::FINGER).x(50).y(50))
12381 .pointer(PointerBuilder(/*id=*/1, ToolType::FINGER).x(150).y(50))
12382 .build());
12383
12384 left->consumeMotionMove();
12385 right->consumeMotionDown();
12386 spy->consumeMotionEvent(WithMotionAction(POINTER_1_DOWN));
12387
12388 ASSERT_TRUE(mDispatcher->isPointerInWindow(left->getToken(), ADISPLAY_ID_DEFAULT, DEVICE_ID,
12389 /*pointerId=*/0));
12390 ASSERT_TRUE(mDispatcher->isPointerInWindow(spy->getToken(), ADISPLAY_ID_DEFAULT, DEVICE_ID,
12391 /*pointerId=*/0));
12392 ASSERT_FALSE(mDispatcher->isPointerInWindow(right->getToken(), ADISPLAY_ID_DEFAULT, DEVICE_ID,
12393 /*pointerId=*/0));
12394 ASSERT_FALSE(mDispatcher->isPointerInWindow(left->getToken(), ADISPLAY_ID_DEFAULT, DEVICE_ID,
12395 /*pointerId=*/1));
12396 ASSERT_TRUE(mDispatcher->isPointerInWindow(spy->getToken(), ADISPLAY_ID_DEFAULT, DEVICE_ID,
12397 /*pointerId=*/1));
12398 ASSERT_TRUE(mDispatcher->isPointerInWindow(right->getToken(), ADISPLAY_ID_DEFAULT, DEVICE_ID,
12399 /*pointerId=*/1));
12400
12401 // Second pointer up.
12402 mDispatcher->notifyMotion(
12403 MotionArgsBuilder(POINTER_1_UP, AINPUT_SOURCE_TOUCHSCREEN)
12404 .pointer(PointerBuilder(/*id=*/0, ToolType::FINGER).x(50).y(50))
12405 .pointer(PointerBuilder(/*id=*/1, ToolType::FINGER).x(150).y(50))
12406 .build());
12407
12408 left->consumeMotionMove();
12409 right->consumeMotionUp();
12410 spy->consumeMotionEvent(WithMotionAction(POINTER_1_UP));
12411
12412 ASSERT_TRUE(mDispatcher->isPointerInWindow(left->getToken(), ADISPLAY_ID_DEFAULT, DEVICE_ID,
12413 /*pointerId=*/0));
12414 ASSERT_TRUE(mDispatcher->isPointerInWindow(spy->getToken(), ADISPLAY_ID_DEFAULT, DEVICE_ID,
12415 /*pointerId=*/0));
12416 ASSERT_FALSE(mDispatcher->isPointerInWindow(right->getToken(), ADISPLAY_ID_DEFAULT, DEVICE_ID,
12417 /*pointerId=*/0));
12418 ASSERT_FALSE(mDispatcher->isPointerInWindow(left->getToken(), ADISPLAY_ID_DEFAULT, DEVICE_ID,
12419 /*pointerId=*/1));
12420 ASSERT_FALSE(mDispatcher->isPointerInWindow(spy->getToken(), ADISPLAY_ID_DEFAULT, DEVICE_ID,
12421 /*pointerId=*/1));
12422 ASSERT_FALSE(mDispatcher->isPointerInWindow(right->getToken(), ADISPLAY_ID_DEFAULT, DEVICE_ID,
12423 /*pointerId=*/1));
12424
12425 // First pointer up.
12426 mDispatcher->notifyMotion(
12427 MotionArgsBuilder(ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN)
12428 .pointer(PointerBuilder(/*id=*/0, ToolType::FINGER).x(50).y(50))
12429 .build());
12430
12431 left->consumeMotionUp();
12432 spy->consumeMotionUp();
12433
12434 ASSERT_FALSE(mDispatcher->isPointerInWindow(left->getToken(), ADISPLAY_ID_DEFAULT, DEVICE_ID,
12435 /*pointerId=*/0));
12436 ASSERT_FALSE(mDispatcher->isPointerInWindow(spy->getToken(), ADISPLAY_ID_DEFAULT, DEVICE_ID,
12437 /*pointerId=*/0));
12438 ASSERT_FALSE(mDispatcher->isPointerInWindow(right->getToken(), ADISPLAY_ID_DEFAULT, DEVICE_ID,
12439 /*pointerId=*/0));
12440}
12441
12442TEST_F(InputDispatcherPointerInWindowTest, MultipleDevicesControllingOneMouse) {
12443 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
12444
12445 sp<FakeWindowHandle> left = sp<FakeWindowHandle>::make(application, mDispatcher, "Left Window",
12446 ADISPLAY_ID_DEFAULT);
12447 left->setFrame(Rect(0, 0, 100, 100));
12448 sp<FakeWindowHandle> right = sp<FakeWindowHandle>::make(application, mDispatcher,
12449 "Right Window", ADISPLAY_ID_DEFAULT);
12450 right->setFrame(Rect(100, 0, 200, 100));
12451
12452 mDispatcher->onWindowInfosChanged({{*left->getInfo(), *right->getInfo()}, {}, 0, 0});
12453
12454 ASSERT_FALSE(mDispatcher->isPointerInWindow(left->getToken(), ADISPLAY_ID_DEFAULT, DEVICE_ID,
12455 /*pointerId=*/0));
12456 ASSERT_FALSE(mDispatcher->isPointerInWindow(right->getToken(), ADISPLAY_ID_DEFAULT, DEVICE_ID,
12457 /*pointerId=*/0));
12458
12459 // Hover move into the window.
12460 mDispatcher->notifyMotion(
12461 MotionArgsBuilder(ACTION_HOVER_MOVE, AINPUT_SOURCE_MOUSE)
12462 .pointer(PointerBuilder(/*id=*/0, ToolType::MOUSE).x(50).y(50))
12463 .rawXCursorPosition(50)
12464 .rawYCursorPosition(50)
12465 .deviceId(DEVICE_ID)
12466 .build());
12467
12468 left->consumeMotionEvent(WithMotionAction(ACTION_HOVER_ENTER));
12469
12470 ASSERT_TRUE(mDispatcher->isPointerInWindow(left->getToken(), ADISPLAY_ID_DEFAULT, DEVICE_ID,
12471 /*pointerId=*/0));
12472
12473 // Move the mouse with another device. This cancels the hovering pointer from the first device.
12474 mDispatcher->notifyMotion(
12475 MotionArgsBuilder(ACTION_HOVER_MOVE, AINPUT_SOURCE_MOUSE)
12476 .pointer(PointerBuilder(/*id=*/0, ToolType::MOUSE).x(51).y(50))
12477 .rawXCursorPosition(51)
12478 .rawYCursorPosition(50)
12479 .deviceId(SECOND_DEVICE_ID)
12480 .build());
12481
12482 left->consumeMotionEvent(WithMotionAction(ACTION_HOVER_EXIT));
12483 left->consumeMotionEvent(WithMotionAction(ACTION_HOVER_ENTER));
12484
12485 // TODO(b/313689709): InputDispatcher's touch state is not updated, even though the window gets
12486 // a HOVER_EXIT from the first device.
12487 ASSERT_TRUE(mDispatcher->isPointerInWindow(left->getToken(), ADISPLAY_ID_DEFAULT, DEVICE_ID,
12488 /*pointerId=*/0));
12489 ASSERT_TRUE(mDispatcher->isPointerInWindow(left->getToken(), ADISPLAY_ID_DEFAULT,
12490 SECOND_DEVICE_ID,
12491 /*pointerId=*/0));
12492
12493 // Move the mouse outside the window. Document the current behavior, where the window does not
12494 // receive HOVER_EXIT even though the mouse left the window.
12495 mDispatcher->notifyMotion(
12496 MotionArgsBuilder(ACTION_HOVER_MOVE, AINPUT_SOURCE_MOUSE)
12497 .pointer(PointerBuilder(/*id=*/0, ToolType::MOUSE).x(150).y(50))
12498 .rawXCursorPosition(150)
12499 .rawYCursorPosition(50)
12500 .deviceId(SECOND_DEVICE_ID)
12501 .build());
12502
12503 left->consumeMotionEvent(WithMotionAction(ACTION_HOVER_EXIT));
12504 right->consumeMotionEvent(WithMotionAction(ACTION_HOVER_ENTER));
12505 ASSERT_TRUE(mDispatcher->isPointerInWindow(left->getToken(), ADISPLAY_ID_DEFAULT, DEVICE_ID,
12506 /*pointerId=*/0));
12507 ASSERT_FALSE(mDispatcher->isPointerInWindow(left->getToken(), ADISPLAY_ID_DEFAULT,
12508 SECOND_DEVICE_ID,
12509 /*pointerId=*/0));
12510}
12511
Garfield Tane84e6f92019-08-29 17:28:41 -070012512} // namespace android::inputdispatcher